Primitive scales feed semantic roles; components consume roles only. Ratios are computed live. Click any swatch to copy its variable name.
Primitive ramps from tokens.json, exported as --ds-color-* for reference and debugging. Never consume primitives in components. Neutral, brand, and accent use the 25–950 tonal shape when a step must keep one lightness identity across modes. Functional status colours use paired light/dark 1–12 scales when each step is designed for the mode it renders in and carries use rather than identity: 1–2 are app/subtle backgrounds, 3–5 component backgrounds, 6–8 borders, 9–10 solid fills, and 11–12 text. Only the active theme's status ramps are shown here; the theme toggle swaps them in place. Alpha ramps reproduce the neutral ramp as transparency — alpha.dark.N on white matches neutral.N, alpha.light.N on black does the same — and always use the current darkest/lightest neutral endpoints as their rgba bases.
Click a swatch to copy its variable. Values can coincide in one brand — page and panel are both white here — but the roles stay distinct so a rebrand can pull them apart without touching consumers.
| Example | Token | Value | Usage |
|---|---|---|---|
surface.canvas | App background; the base everything sits on | ||
surface.page | Primary content areas and forms | ||
surface.panel | Cards, grouped content, navigation shells | ||
surface.raised | Elevated elements: popovers, menus, sticky bars | ||
surface.overlay | Scrim behind modals and drawers |
A non-neutral surface is a complete context, not one background token. Map on-surface.primary, secondary, muted, hover, and active to that hue, then put ds-on-surface on the host. Topbar links, Ghost buttons, and Avatar consume the local aliases with neutral-canvas fallbacks.
Emphasis grades static hierarchy — primary / secondary / muted are fixed levels, not interaction states. muted sits below AA contrast by design: placeholder-grade, never for content someone must read. link sits apart from that grading: it marks a destination rather than a level, and it is the one role here a brand is expected to re-point.
| Example | Token | Usage |
|---|---|---|
| Primary carries the message. | text.primary | Headings, body copy |
| Secondary supports it. | text.secondary | Supporting copy, labels, helper text, table headers |
| Muted whispers metadata. | text.muted | Placeholders, decorative metadata — never essential text |
| Link takes you somewhere. | text.link | Optional branded link ink, applied through --ds-link-color only on a contrast-gated page or canvas; base Link inherits its parent |
subtle / default / strong grade static emphasis, like text. The same family also answers interaction through border.hover / border.active — shown in the Interaction table below. Every token belongs to exactly one axis.
| Example | Token | Usage |
|---|---|---|
border.subtle | Dividers, table row separators | |
border.default | Control and card outlines | |
border.strong | High-emphasis outlines |
Each intent ships two emphases, both designed as bg + text pairs consumed whole, never one half — and the tier follows the feedback's lifetime: subtle (status.*.bg / .text) tints persistent in-flow state read in place (Alert, Badge), solid (status.*.solid-bg / .solid-text) carries transient or glanced feedback that must register instantly (Toast, solid Badge). Both pairs are mode-tuned from the matching functional scale; dark mode does not reuse an opaque deep light-theme swatch. Status stays functional even in a colorful brand: its ramps never double as the brand accent.
| Example | Token | Usage |
|---|---|---|
| SolidSubtle | status.success.* | Positive confirmation: saved, completed, online |
| SolidSubtle | status.warning.* | Reversible caution: pending, degraded, expiring |
| SolidSubtle | status.error.* | Failures and destructive outcomes |
| SolidSubtle | status.info.* | Neutral information and hints |
Rest / hover / active answer input — a separate axis from emphasis. control.*, border.*, and action.primary.* carry full triads for filled controls. The monochrome Primary and Danger buttons answer hover structurally by dropping to text-grade outlines, while secondary strengthens its outline and ghost derives a quiet translucent plate.
| Family | Rest | Hover | Active | Usage |
|---|---|---|---|---|
control.* | Fills for menu items, tabs, list rows, ghost buttons | |||
border.* | Inputs and selectable cards answer interaction | |||
action.primary | The view's main action — one per view | |||
secondary/currentColor | Supporting actions inherit the surface pair; outline presence carries state | |||
action.danger | Destructive actions |
The approved text-on-surface combinations. The validator enforces these same pairs at build time; here they are computed live from the loaded theme, in both modes — each Example cell renders in its own pair, so what you read is the proof. When a pair fails after a palette change, adjust the ramp, not the role mapping: re-tune the derived step's color value (e.g. darken this brand's neutral.500) so the fix propagates to every consumer — never re-point the role to a different step, which silently breaks the hierarchy the roles encode.
| Example | Ratio | Usage |
|---|---|---|
| text.primary on surface.page | Body, headings | |
| text.secondary on surface.page | Supporting text, labels | |
| text.link on surface.page | Links in prose | |
| action.primary text on bg | Primary buttons | |
| action.primary fg on surface.canvas | Text and border when a project deliberately outlines a primary state | |
| action.danger text on bg | Danger buttons | |
| action.danger fg on bg-subtle | Destructive menu rows, highlighted | |
| text.primary on control.bg-active | Pressed fills, selected controls | |
| status.success text on bg | Success badges, alerts | |
| status.warning text on bg | Warning badges, alerts | |
| status.error text on bg | Error badges, alerts | |
| status.error.fg on surface.page | Field error messages, error icons, invalid values | |
| status.info text on bg | Info badges, alerts | |
| status.success solid text on bg | Solid success badges, toasts | |
| status.warning solid text on bg | Solid warning badges, toasts | |
| status.error solid text on bg | Solid error badges, toasts | |
| status.info solid text on bg | Solid info badges, toasts | |
| focus.ring on surface.page | Keyboard focus indicator — non-text, min 3:1 | |
| status.error.border on surface.page | Invalid control borders — non-text, min 3:1 |