Typography

Families, scale, weights, and complete ds-text-* recipes. Use a semantic text utility when authoring page typography so family, size, line height, weight, and tracking move together; do not reassemble a size token by hand.

Font families

Family slots are available ingredients; family roles are what consumers use. Rebrand by changing which slot a role points to, not by making agents infer usage from a family name.

Family roles

Use roles in components and application surfaces. A serif-led system can point body, heading, and display at font.family.serif; a mono-led system can point them at font.family.mono. The role name stays stable.

RoleDefault mappingUsage
font.role.bodyDocument and long-form body text
font.role.headingSection and content headings
font.role.displayLarge display text
font.role.uiControls, labels, navigation, compact UI
font.role.codeCode-like values, token names, technical text

Scale

The shared primitive ladder below. Base ("md") is fixed at 1rem — the browser's own normal size — steps above compound by a ratio, steps below drop by a flat amount. Change either in build_font_scale() (scripts/scaffold_design_system.py) and every role that references it moves with it.

Aa4xl
Aa3xl
Aa2xl
Aaxl
Aalg
Aamd
Aasm
Aaxs
Aa2xs

Grouped by role below. Each role aliases the ladder above rather than being consumed directly, so any one role can be resized on its own — button-sm and label start at the same value today, but changing one won't move the other.

Headings

Size and weight compound so hierarchy still reads if color changes. Map these to whichever heading tag is right for the document outline, not necessarily h1/h2/h3 literally.

ExampleTokenSizeLine heightWeightTrackingUsage
Heading textds-text-displayfont.weight.display tighterHero headlines, above any heading
Heading textds-text-heading-3xlfont.weight.heading-3xl tighterLarge marketing headlines
Heading textds-text-heading-2xlfont.weight.heading-2xl tightMain page heading
Heading textds-text-heading-xlfont.weight.heading-xl tightSection headings
Heading textds-text-heading-lgfont.weight.heading-lg tightSubsection headings

Body copy

Normal to relaxed line height since paragraphs wrap across multiple lines, unlike headings or controls. copy-md is the browser's own default (1rem) — call it normal, not large.

ExampleTokenSizeLine heightWeightTrackingUsage
Copy textds-text-copy-lgfont.weight.copy-lg normalLead paragraphs, dialogs
Copy textds-text-copy-mdfont.weight.copy-md normalDefault body text, the browser's own baseline
Copy textds-text-copy-smfont.weight.copy-sm normalSecondary or dense body text
Copy textds-text-captionfont.weight.caption normalHelper text, metadata, field help/error

Buttons

Own semantic tokens, not reused from Body copy — resizing buttons never moves paragraph text. The roles follow the Button size names: button-sm and button-md intentionally share 14px, while button-lg steps to 16px. Line height is always none, since control text never wraps.

ExampleTokenSizeLine heightWeightTrackingUsage
Button textds-text-button-lgfont.weight.button-lg normalLarge Button · 40px; large control labels
Button textds-text-button-mdfont.weight.button-md normalDefault Button, Input, and Select trigger; Command Menu search · 14px
Button textds-text-button-smfont.weight.button-sm normalSmall Button · 32px; compact control labels

Labels

Short single-line naming text, medium weight, and wide tracking. ds-text-label serves field labels; ds-text-label-sm serves compact group labels; ds-text-eyebrow shares the small recipe without forcing uppercase. A brand may add an uppercase transform, but the complete recipe remains intact.

ExampleTokenSizeLine heightWeightTrackingUsage
Label textds-text-labelfont.weight.label wideField labels
Label textds-text-label-smfont.weight.label-sm wideGroup labels — sidebar nav, menu, and command-list sections

Weights

ExampleTokenValueUsage
Aalight Optional display treatment; not assigned to a semantic recipe
Aaregular Body's own default
Aamedium Buttons, labels, tabs, table headers
Aasemibold Headings, card/dialog titles
Aabold Not currently used

Tracking

Bands guide, semantic recipes decide. Display and heading roles take their band's tighter/tight tracking; body copy and controls pin normal; label and eyebrow recipes pin wide. The wider step is reserved for compact symbolic chords such as Menu keyboard shortcuts, where normal tracking visually fuses adjacent symbols.

ExampleTokenValueSize rangeUsage
Trackingtighter2.5rem and upDisplay and heading-3xl
Trackingtight1.25–2remHeadings
Trackingnormal1rem and downBody text and all smaller UI text
Trackingwide0.875remNot currently used — available for label-size text
⇧⌘Ewider0.875remCompact symbolic chords — Menu keyboard shortcuts