Typography
Seven semantic text roles — display, heading, body, action, label, caption, code — composed from a three-link token chain across L1 and L2. L1 font-family slots (numbered 1/2/3) hold the actual face. L2 family aliases (one per role) map each role to a slot. L2 composite tokens bake font-family + size + weight + line-height + letter-spacing into a single style. The brand swaps a slot's value and every role bound to it changes face — without touching any composite.
Architecture
Three layers move together. Edit a slot at L1, every L2 role bound to it changes. Edit a role's family alias at L2, only that role swaps. Edit a composite directly only when a one-off needs to deviate (it shouldn't — that's an L3 component concern). The slot each role points at is set by the L2 family aliases in tokens/source-tokens.json; the map below shows the shipped mapping.
Overline has no family alias of its own — it follows label. The code role also styles monospace micro-UI (timestamps, hex inputs, calendar times), so remapping it moves those too.
Responsive modes — S / M / L
Every L2 typography token declares three modes: S (mobile, ≤600px), M (tablet, 601–1023px), L (desktop, ≥1024px). Display and heading (xl/l/m) shrink at S; body, action, label, caption, overline and code stay constant across all three. Empty $modes blocks mean "inherit base" — they exist in the JSON so the Figma plugin can build variable modes from them.
Preview a mode without resizing: open the Theme editor (cog icon in the header) — the Viewport switcher at the top has Auto / S / M / L buttons. Auto follows your real viewport; the others force a specific mode for visual review.
Display
The biggest type in the system — for hero sections, marketing moments, and impactful brand statements. Five sizes from xl (largest) to xs. Weight bold. All five shrink at S to keep mobile readable.
Heading
UI hierarchy headings for sections, cards, modals. Four sizes xl to s. Weight semibold (one step less weight than display). Heading-xl, l, and m shrink at S; heading-s stays fixed (already small enough for mobile).
Body
Running text for paragraphs and prose. Five sizes xl to xs. Weight regular. Letter-spacing normal. Same values at every breakpoint — body never shrinks below readable.
Action
Interactive elements — buttons, tabs, links, breadcrumbs. Weight medium. Letter-spacing slightly-wide (action-s widens further at +0.02em). Action shares the text face (font.family.1) with body by default — the norm across brands and platforms, where buttons follow the body font and differentiate by weight and spacing. A brand that wants a distinct UI voice remaps the action role to its own slot in the theme editor's role map; the demo below previews what an action-only face swap looks like.
Label
Static UI labels — form field labels, tags, chip text, badges. Same metrics as action (weight medium, slightly-wide letter-spacing) but semantically different: labels aren't interactive. Bound to slot 1 by default.
Caption
Helper text, metadata, fine print, image captions, timestamps. Two sizes m and s. Weight regular. Smaller than body-xs (caption-s = 11px) so it reads as supplementary, not primary.
Overline
Uppercase eyebrow above a heading — section markers, kickers, card categories. One size. Family follows the label role.
Code
Monospace text — code blocks, inline code, and the monospace micro-UI (timestamps, hex inputs, calendar times). Three sizes. The only role bound to slot 3 by default.
Retune it live
Everything on this page is editable in the Theme Editor (header button) → Typo: a Google Fonts picker per family slot, the role map that decides which slot each role wears (the slot captions update live as you remap), and per-mode base-size sliders that scale the whole ramp. Export carries the result as standard DTCG JSON; the letbe tokens plugin registers the same slots, roles and modes as Figma variables.