Typography

Six semantic text roles — display, heading, body, action, label, caption — 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.

Role (L2)
Family alias
Slot (L1) → font
display
typography.family.display
Slot 1 —
heading
typography.family.heading
Slot 1 —
body
typography.family.body
Slot 1 —
action
typography.family.action
Slot 2 —
label
typography.family.label
Slot 1 —
caption
typography.family.caption
Slot 1 —

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 shrink at S; body, action, label, caption 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.

display-xl
Display XL
display-l
Display L
display-m
Display M
display-s
Display S
display-xs
Display XS

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).

heading-xl
Heading XL
heading-l
Heading L
heading-m
Heading M
heading-s
Heading S

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.

body-xl
The quick brown fox jumps over the lazy dog
body-l
The quick brown fox jumps over the lazy dog
body-m
The quick brown fox jumps over the lazy dog
body-s
The quick brown fox jumps over the lazy dog
body-xs
The quick brown fox jumps over the lazy dog

Action

Interactive elements — buttons, tabs, links, breadcrumbs. Weight medium. Letter-spacing slightly-wide (action-s widens further at +0.02em). Action is the role designed to swap face. It's the only role pointing at font.family.2 by default — change slot 2 in the theme editor and every button/tab/link label switches typography while body stays unchanged.

Try it Only action specimens swap. Body stays Inter — proves per-role mapping works.
action-l
Action L — Buttons, Links, Tabs
action-m
Action M — Buttons, Links, Tabs
action-s
Action S — Buttons, Links, Tabs

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.

label-l
Form field label
label-m
Form field label
label-s
Form field label

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.

caption-m
Caption M — helper text, metadata
caption-s
Caption S — helper text, metadata

What's next — phase 2

Phase 1 (shipped 2026-05-13) added the architectural plumbing: numbered family slots, per-role family aliases, S/M/L responsive modes. Sizes stayed hand-tuned. Phase 2 will bring the editor UI: Google Fonts picker with lazy-load, per-mode base-size sliders, role-to-slot map editor, and (optionally) a formula-driven scale mode where sizes derive from base × ratio^n. Tracked in tokens/PLUGIN-HANDOFF.md.