Relationships
Branches 3
Context
Named scale ramps — value ladders keyed by sm/md/lg/xl (and friends) — underpin a large share of the attribute surface: spacing/inset, radius, elevation, frame-offset, substrate-size/-opacity, card height, bento row-height/content-height, the type scale, and (per ADR-014) the forthcoming media-height. They are the dimensional vocabulary the whole system speaks.
Today they are inconsistently sourced:
- Tokenized ramps —
--rf-radius-{sm,md,lg},--rf-spacing-{xs…2xl},--rf-shadow-{none…lg}are real design tokens inpackages/lumina/tokens/base.css. A project can already retune them throughtheme.tokens(the typed token contract,ThemeTokensConfig) andmodes— the same path that overrides colours. - Literal ramps — others are hard-coded values keyed by data-attribute, not tokens, and therefore cannot be retuned from config:
.rf-card[data-height="md"] { min-height: 18rem }.rf-bento[data-content-height="md"] { --cell-content-height: 10rem }.rf-bento[data-row-height="md"] { --bento-row-height: 24rem }(has a token hook,--rf-bento-row-height, but no per-step tokens)
So whether a project can tune a ramp is an accident of which ramps happened to be tokenized. The literal ramps also quietly violate the project's own convention ("reference design tokens — never hard-code values"). This surfaced from the ADR-014 discussion, where the same "named layer, fixed vocabulary, flexible value" shape recurred for the third time (after colours and tints/backgrounds/frames).
Decision
Ramps are token-backed, never literal. Tokenize the remaining hard-coded ramps as
--rf-{ramp}-{step}tokens (--rf-card-height-md,--rf-content-height-md, per-step--rf-bento-row-height-md, the ADR-014media-heightramp, …); rune CSS references the token, never a literal. This is a consistency/quality fix valuable on its own.Ramps live in the typed token contract and are overridden via
theme.tokens(option A). No new or parallel config mechanism. Override flows throughmodesfor dark exactly as colours do. The ramps are grouped within the contract (adimensions/scalessection) so a project can define a whole ladder at once.Fixed vocabulary, flexible values. Projects retune what each named step resolves to; they may not add steps, remove steps, or invent ramps. The step set per ramp is the stable contract — the same law as ADR-014's small fixed threshold set, one level down: the names are the contract, the values flex.
Structured and validated, no raw-CSS escape hatch. Ramp values are dimensions (or, post-ADR-014, clamp anchors), type-checked by the token contract — never raw CSS — so they stay portable and theme-swappable.
The general law (now explicit). refrakt has two override layers and they obey one policy:
- Presets — named bundles: tints, backgrounds, frames.
- Scales — named value ladders: spacing, radius, type, elevation, heights, offsets.
Both are theme-defaulted, project-overridable by value, with a fixed vocabulary, structured (no raw CSS), and validated. Colours already exemplify it; tints/backgrounds/frames obey it (ADR-014); this decision extends it to every dimension ramp by closing the tokenization gap.
Rationale
- Consistency over accident. Whether a ramp is tunable should be a deliberate policy, not a side effect of which ones were tokenized. Closing the gap makes the token system uniform and retires a standing violation of the "never hard-code values" convention.
- Reuse over a new surface.
theme.tokens+modesalready validate, cascade, and handle dark mode. Routing ramps through it adds zero new override concepts — the cheapest possible way to deliver the capability. - The fixed-vocabulary guardrail is what makes this safe. It preserves the CSS-coverage tests, cross-theme portability, and content portability that a free-form ramp vocabulary would shatter.
- It composes with ADR-014. Once ramps are
clamp()-based, a project-tuned value is simply the anchor (min/max) the theme's clamp formula consumes; the container thresholds remain a fixed count while their values become tunable too. The two decisions reinforce rather than conflict.
Consequences
- Enabling work (to be scoped, pairs with ADR-014 Phase 2): tokenize the literal ramps; extend the token-contract types with the grouped ramp section (builds on the token-contract typing work, WORK-185); update the CSS-coverage tests to derive ramp selectors from the fixed step set.
- The token contract grows (a deliberate, backward-compatible change — existing tokens are unchanged; new ramp groups are additive).
media-heightmust be token-backed from birth. Whatever ships it (ADR-014 Phase 2) should define--rf-media-height-*tokens, not literals, so it lands on the right side of this decision.- Tooling:
refrakt inspectand the structure contracts should treat ramps as fixed-vocabulary token sets; a project override changes values, never the selector set. - Docs: theme-authoring
config-api/tokens gains a "tuning scale ramps" section;runes/surfaces.mdnotes that the size scales are project-tunable. - Escape-hatch-free scales joins escape-hatch-free frames as an explicit invariant: dimension ramps must not gain a raw-CSS value form.