src/types/ that defines reusable role, state, mode, and semantic-map patterns. Components inherit one with extends: and then override or delete what differs — badge extends the action archetype and deletes its interaction states; button extends the same archetype and keeps them. Types are portable source, not platform adapters: the same archetype feeds every output target.
Five archetypes exist:
Anatomy of a type config
Every type config shares the same top-level shape —type:, an effect: channel (backdrop-filter for all archetypes except text, which uses filter), a meta: block, and then roles:, modes:, and semantic-map:. The meta: block states a system-wide invariant, annotated identically in all five files:
semantic-map is the named-to-numeric lookup: a component (or author) writing border: thin gets 1 through this table rather than a magic number. The other archetypes vary the same vocabulary — feedback’s auxiliary role authors border-x-start-width: 3, the logical-property spelling that produces the classic left-accent alert bar and mirrors correctly in right-to-left scripts; input adds an indeterminate mode alongside selected.
Chart is the structural outlier: it has no roles: or modes: at all, defining instead series: (named palettes composed of intent + contrast stops — solo, comparison, percentile, categorical), overlays: (threshold bands and target lines), states: (default/selected/dimmed for series elements), and axis: styling. Everything still references intents by name, so chart colors go through the same solver as everything else.
The text archetype: where typography meets contrast
types/text/config.yaml defines the six text roles. Each role carries a font family variable, a font-scale step exponent, weight, line height, letter spacing, and a fluid: envelope:
The
fluid: envelope per role (floor, ceiling, min, max, reference: container) feeds a second generated rule gated by [data-mode~="fluid"] — fluid typography is opt-in per element via that mode token, exactly as the markup contract describes.
How text roles drive per-role APCA foregrounds
This file is also the source of the role-specific solved foregrounds you see in the color token reference — the chain runs from YAML to solver to CSS:- Baseline election. The generator elects the baseline role as the one whose
font-scaleis closest to zero (ties broken alphabetically) — with the shipped config,body. This is derived, not hard-coded: reshape the scale and the baseline can move. - Per-role solve. For every other role, the role’s step exponent and the brand’s ratio yield a rendered pixel size; size and weight index into Substrate’s size/weight-aware Lc floor table (its own construction — see the APCA Solver reference); and that target is solved against the actual surface. Larger, bolder text legitimately needs less contrast, so each role earns its own solved lightness instead of sharing one global foreground.
- Emission. The solver writes
--ucs-{intent}-fg-l-{role}per intent × non-baseline role; the generated CSS narrows it to--intent-fg-l-{role}inside each intent’s scope; and a text element carryingdata-mode~="heading"picks it up with a fallback to the base foreground. The baseline role uses the plain--intent-fg-ldirectly, and where a parent already declaredcontrast: auto, the spatial foreground is suppressed with an explanatory comment in the output rather than silently fighting it.
Authoring with archetypes
Reach for a type config when a pattern recurs across components — roles, states, or semantic maps that would otherwise be copy-pasted. The inheritance mechanics are the same cascade as everywhere else (see the resolution cascade): objects deep-merge,null deletes, and a brand can override at the type level so the change reaches every component that extends it. Parts can tap an archetype directly with uses: — a part named after a text role inherits that role’s tokens without the component extending the whole type.
Component Config Overview
The full config.yaml schema — channels, parts, validation, and the cascade.
Type Tokens
The generated typography variables the text roles resolve into.