Skip to content
GitHub
Sections

Reference · Design Tokens

Predefined option sets

This is a spec: descriptive guidance, not a checkable rule. It carries no forbidden and instead pair, and no jig check detector applies to it directly.

The spec

Limited options, chosen once. The point is not the specific values — it is that there are few of them, so a decision is a selection rather than an invention.

Spacing — six options, 8pt base. Identical in every mode.

XSSMLXLXXL
81624324880

Modes select from these; they never define their own values. --spacing-card is M in editorial, M in product, S in operator — same option set, different selection. This is why there are no arbitrary numbers left in the mode files.

Type — the scale ratio varies by mode, because scale size should track interface complexity. A large ratio gives dramatic steps that suit content-led pages; a small ratio gives fine gradations that suit dense tools needing many levels in little space.

ModeRatioCaptionBody (UI)ProseLeadH3H2H1
editorial1.250 Major Third141618202424–3232–48
product1.200 Minor Third141618202020–2424–32
operator1.125 Major Second12141816161822

A range means the heading is fluid. 32–48 is not two values to choose between: --text-h1 interpolates continuously with viewport width, reaching its minimum at a 360px viewport and its maximum at 1024px, saturating outside that range. There is no breakpoint here, and the system defines none anywhere else — a clamp() has no threshold to place, which is exactly why it was chosen over a second -sm scale. Where a project's layout does switch, the project measures and records the width (T-04).

Editorial --text-h1 at a fixed 48px gives 13 characters per line on a 360px screen, so a 45-character headline sets as four lines and 211px of headline. At the 32px minimum the same headline is three lines and half the height. operator has no fluid headings because its largest is 22px, which already fits about 28 characters — the mechanism is absent because the problem is.

The bounds are in rem, and that is load-bearing. clamp(32px, 8vw, 48px) ignores a reader who has raised their default font size: page zoom scales vw, a font-size preference does not. Every term stays rem-based so the whole curve moves with the user's setting, which WCAG 1.4.4 requires.

Only headings are fluid. Body and prose are fixed at every width on purpose. Readability is absolute — set by the eye and viewing distance, not by screen width — while heading size is relative, existing to contrast with body, and that contrast can compress when less content competes for the view. A fluid --text-prose would also breach the 18px floor at narrow widths (B-75, T20). What responds for body text is the measure, via the container.

editorial omits the rung the ratio would put between H2 and H1 (a step near 40); the ratio names the ladder, not every adjacent step — its H2→H1 jump (32→48) is 1.5, not 1.25.

The columns are --text-caption, --text-body, --text-prose, --text-lead, --text-h3, --text-h2 and --text-h1 in that order.

--text-lead is the standfirst role — the one paragraph that introduces a page or section, set larger than body. It existed in all three mode files and was documented nowhere, which is how a token becomes invisible: present, usable, and never chosen because no one knows it is there. In operator it is 16px, *below* --text-prose, because that mode has no editorial standfirst — it is the size of a slightly emphasised label.

Line heights are per-mode too, which this section used to obscure by quoting one mode's values as though they were everyone's:

Tokeneditorialproductoperator
--leading-caption1.51.51.5
--leading-body1.51.51.5
--leading-prose1.61.61.6
--leading-lead1.51.51.5
--leading-h31.3331.41.5
--leading-h21.251.3331.4
--leading-h11.11.251.333

The heading rows are one ladder, read through a sliding window. The ladder is 1.1 · 1.25 · 1.333 · 1.4 · 1.5, and each mode takes three consecutive rungs, starting one lower as the mode gets denser. editorial opens at 1.1 because its H1 is 48px and a large heading needs proportionally less leading to sit at the same optical rhythm; operator's H1 is 22px, near body size, so it takes the body-ish end of the same ladder. That is why product's H1 leading equals editorial's H2 — they are the same rung, not a coincidence.

Body and reading roles do not vary: the floor is 1.5 everywhere, and prose sits at 1.6, inside the 1.5–2 band long-form reading wants. Within any mode, leading never increases as size increases.

--text-body and --text-prose are different roles, not two sizes of the same thing. Body is UI text — labels, controls, table cells, short strings read in glances. Prose is sustained reading, and never drops below 18px on a page anyone is expected to actually read (B-75).

Line heights are unitless and floor at 1.5 for body and prose, easing down as size rises. Raise it further when lines are long, when the typeface is heavy or dark, or when it simply looks large for its nominal size. Between 1.5 and 2 is the comfortable band for prose.

Measure: 40–80 characters. Below 40 the eye returns too often; above 80 it loses the line. --measure-prose sits mid-range in every mode.

The lower bound is a target, not a floor, and on a small phone it is unreachable. --measure-prose caps the upper end; nothing can raise the lower one on a narrow screen, because the only two levers both give out. Measured in the preview at 16px body — the size B-75 and WCAG 1.4.4 forbid going under:

viewportwith the 16px gutterwith a 12px gutterwith no gutter at all
320px343538
360px394043
375px414244
414px454649

At 375px and up the target is met as the gutters already stand. At 320px it cannot be met at any gutter, since 40 characters of 16px text need about 335px of width before margins exist. The two constraints are geometrically incompatible there, and the resolution is not to argue: the 16px body floor wins, and the measure target yields. Shrinking body text to buy characters is the one move that is never available.

So do not narrow the gutter chasing this number. It costs layout at every small width and buys one character at 360px, while changing nothing at 320px.

Weights: two. Regular (400) and bold (600). See B-77.

Letter spacing tightens as size grows — most text typefaces are spaced for small sizes and look loose when scaled up. --tracking-h1 is the most negative; body is 0.

Typeface. One sans serif by default: most legible small, neutral across brands, least likely to be the wrong choice. When picking one — prefer a popular face with many weights, a tall x-height and generous default spacing, with OpenType features and the language coverage the product needs. When in doubt, the platform system font is tried, tested and free to load. A second face is permitted for headings only (B-76).

Radius — four options, by element size: --radius-sm 8px (buttons, inputs), --radius-md 16px (cards, panels), --radius-lg 32px (hero media and full-bleed surfaces), and --radius-full for pills, badges, avatars and chips.

--radius-control selects sm in all three modes. --radius-surface selects md in editorial and product, but sm in operator — the selection is per-mode, not a fixed derivation. --radius-lg and --radius-full are brand-scale options; no mode currently selects either.

Shadow — three, two of which do anything: --shadow-raised sits above the page, --shadow-overlay floats over it, and --shadow-none is the explicit absence a mode selects when its elevation is stroke-led rather than shadow-led (every mode currently does, via --shadow-surface). A-08 still prefers a stroke; the other two exist for when depth is the point.

Kind
Spec
Section
Design Tokens

Read as plain text