⚠️ Design system CSS not found. Check the path in cms/docs.config.js → designSystemPath, then re-run npm run docgen.

Tokens

The primitive layer everything else resolves through

Website / Tokens
Download .md file
Open .md in new tab
On this page
  • Why the split exists
  • The unit scale
  • Type scale
  • Line height
  • Weight
  • Letter spacing
  • Alpha
  • Where the rest is documented
  • Declared but unread

Tokens come in two layers. Primitives are raw values with no opinion about where they are used — --l is 16px, --font-m is 18px, and neither knows what it is for. Semantic tokens name an intent and resolve through a primitive, so --text-primary is the colour body text takes, whatever that colour turns out to be. Page and component code uses the semantic layer; this page documents the primitive layer beneath it.

Why the split exists

Reaching past a semantic token to a primitive is the mistake this architecture is built to prevent. --neutral-800 is a grey; --text-secondary is the colour supporting text takes, which today happens to be that grey. Write the primitive and the element stops following the theme — it will not invert in dark mode, and a palette change leaves it behind.

  • Use a semantic token in page and component code. If no semantic token fits, the semantic layer is missing one, and the fix is to add it rather than to reach past it.
  • Use a primitive only when defining a semantic token. That is the one place the raw value belongs.

The unit scale

Every spacing and sizing token resolves through this scale, so the whole system moves together if it is re-stepped. Values are rem, which means they track the reader's browser zoom and root font-size preference rather than pinning to device pixels.

Token Value Token Value
0 3.5rem · 56px
0.125rem · 2px 4rem · 64px
0.25rem · 4px 4.5rem · 72px
0.5rem · 8px 5rem · 80px
0.75rem · 12px 5.5rem · 88px
1rem · 16px 6rem · 96px
1.5rem · 24px 6.5rem · 104px
2rem · 32px 7rem · 112px
2.5rem · 40px 7.5rem · 120px
3rem · 48px 10rem · 160px

The --space-* tokens are aliases onto this scale — --space-l is — and they are what layout code actually uses. The Spacing page covers them and the utilities that apply them.

Type scale

Font sizes are primitives. Nothing here says which element takes which step; that mapping is the web hierarchy on the Typography page.

Token Value Token Value
0.625rem · 10px 1.75rem · 28px
0.75rem · 12px 2rem · 32px
0.875rem · 14px 2.25rem · 36px
1rem · 16px 2.5rem · 40px
1.125rem · 18px 3rem · 48px
1.25rem · 20px 3.5rem · 56px
1.375rem · 22px 4rem · 64px
1.5rem · 24px 4.5rem · 72px

--font-10xl · 72px

Where Culture Meets Care

--font-9xl · 64px

Where Culture Meets Care

--font-8xl · 56px

Where Culture Meets Care

--font-7xl · 48px

Where Culture Meets Care

--font-6xl · 40px

Where Culture Meets Care

--font-5xl · 36px

Where Culture Meets Care

--font-4xl · 32px

Where Culture Meets Care

--font-3xl · 28px

Where Culture Meets Care

--font-2xl · 24px

Where Culture Meets Care

--font-xl · 22px

Where Culture Meets Care

--font-l · 20px

Where Culture Meets Care

--font-m · 18px

Where Culture Meets Care

--font-s · 16px

Where Culture Meets Care

--font-xs · 14px

Where Culture Meets Care

--font-2xs · 12px

Where Culture Meets Care

--font-3xs · 10px

Where Culture Meets Care

Line height

Token Value Use
0.7 Tight display settings where the leading would otherwise open the line up
1 Single-line controls — buttons, badges, anything that never wraps
1.2 Headings, where the type is large enough that generous leading reads as a gap
1.4 Sub-headings and short passages
1.6 Body copy, which is the one place leading does the most work for readability
1.8 A long measure that needs more air than body copy

Weight

The tokens span 300 to 900, but the loaded faces do not. Erode is a variable font covering 300–700; Inter is loaded at 400–700. So 400 to 700 is the range both faces render natively, 300 is available in Erode only, and nothing on the site provides 800 or 900 — a browser asked for those will clamp to 700 or synthesise a heavier face.

Token Value Token Value
300 600
400 700
450 800
500 900
  • Stay between 400 and 700. Those are the weights both faces actually ship; 800 and 900 are declared tokens with no loaded face behind them.

Letter spacing

Token Value Use
-0.03em Large headings, where default tracking looks loose
0.03em A slight opening, for small text set in caps
0.06em Labels
0.12em Eyebrows and badges — the widest setting in regular use
0.24em Reserved for display settings at large sizes

Alpha

The alpha tokens are color-mix operands, not colours. --alpha-10 expands to transparent 90%, so color-mix(in srgb, var(--text-primary), var(--alpha-10)) is the text colour at 10 % strength. They step in fives from --alpha-5 to --alpha-95.

background: color-mix(in srgb, var(--text-primary), var(--alpha-10));

This is how the faded surfaces and hairlines are built, and it is why they follow the theme: mixing against a semantic token inverts when that token does.

Where the rest is documented

No family is listed twice, so each one has a single page that owns its values.

Family Documented on
Colour — semantic tokens, light and dark Colour
Colour — the neutral and gold primitive ramps Brand Book → Colour
Font slots, and which element takes which size Typography
--space-* and the spacing utilities Spacing
, the 44px floor for anything pressable Spacing
The four --safe-area-* insets Spacing
Border widths and radius Border
Containers and max-widths Layout
Easing and duration Motion
Component tokens Each component's own page, as those pages land

Declared but unread

Some role tokens ship in the engine — four of them re-stepped at the breakpoints — but no rule reads them: --headline-size, --headline-weight, --headline-leading, --headline-tracking, --headline-width, --subline-size, --subline-weight, --title-size, --label-weight, --label-leading and --label-tracking.

  • Do not build against them. Setting one changes nothing today, and a display class has to set font-family itself because --title-family is the only role family token that exists.

This is recorded as an engine gap in docs/figma-mapping.md. The fix belongs upstream — either ship the classes that read them, or drop the tokens.

On this page
  • Why the split exists
  • The unit scale
  • Type scale
  • Line height
  • Weight
  • Letter spacing
  • Alpha
  • Where the rest is documented
  • Declared but unread
Previous Typography
Next Classes

© 2026 BlackDoctor