03 // Register Palettes

The Material
Spectrum.

Approved Backgrounds

Environmental backgrounds.

Seven approved bases — four dark, three light — now attributed to the register that uses each. Never use an off-palette value as a page or card background. Warm Paper is Commons-only (S-08).

Universal baseline: Systems Blue #007FFF and Forged Steel #475569 are the only two colours approved across every register without restriction. Universal is the default for a mixed or unknown audience, not a fallback of last resort.

Core Deep

#0A0C10

Commons base

Data Midnight

#020617

Bedrock base

Deck Base

#0C1424

Catalyst base

Industrial Surface

#121418

Commons surface

Laboratory Clean v2

#EEF2F6

Bedrock base

White

#FFFFFF

Catalyst base — light

Warm Paper

#FAF7F2

Commons base — S-08

Register Palettes

Three registers, each in both modes. Every ratio is the measured contrast against that register's own base. A value is only approved at the size class it was measured at.

System Tokens

Available in every register. Status colours are reserved and never double as a chart series.

Every value in this table is half of a pair. Ship the token, not the hex. Each status colour has a dark value and a light value, and var(--sem-error) / var(--sem-warning) resolve to the right one automatically. Copying a hex out of this table pins it to one mode.

The failure is not subtle, and it runs in the direction people expect least. Warning light is #5B4708, chosen because it clears 7.94 on the light base. Carried onto a dark panel it measures 2.00 — roughly half the contrast of the retired value it replaced. A colour picked to fix contrast makes it worse the moment it crosses modes, because “darker” only helps against light grounds.

So a token carrying two values is not a defect or a duplicate — it is the mechanism. If you find a stylesheet declaring one name twice in different blocks, check whether the blocks are the dark and light scopes before calling it drift.

The exception, and it is not rare: an element that carries its own fixed ground. A callout card with an inline cream background stays cream in both themes. Its text is measured against that card, not against the page — so the literal matched to the card is correct, and a mode-switching token is the wrong answer there. It would flip to the dark-mode value on a ground that never went dark.

The rule is not “always use the token.” It is match the value to the ground the element actually sits on, and use a token exactly when that ground follows the theme. Read the ancestor chain before deciding which case you are in — the background is often several elements up, and a snippet of the element’s own style attribute will not show it.

A related trap when converting: var(--x) where --x is undefined is not a fallback to anything. The declaration is invalid at computed-value time and the element inherits past it. On a page that does not load tokens.css that means silently unstyled text, which is worse than the marginal ratio you were trying to fix. Either supply var(--x, <literal>) or confirm the stylesheet is actually loaded there.

Inversion islands: use the ground-keyed tokens. --sem-* keys off the theme. A contrast requirement keys off the ground. Those are the same thing almost everywhere — which is why the theme-keyed token works, and why the exception is easy to miss.

They come apart at an inversion island: a dark panel pinned inside a light page, or a pale card pinned inside a dark page. There the theme-keyed token resolves to the value chosen for the opposite ground. Measured on a panel pinned to #0f1117 while the theme is light:

var(--sem-warning)  → #5B4708 → 2.11  wrong
var(--sem-warning-on-dark) → #FBBF24 → 11.30

It fails in both directions and for all four semantics. So the set now carries --sem-{error,warning,success,info}-on-{dark,light}, defined once outside every theme block so they never switch. Same hexes — these add names, not colours.

Choosing between them: if the surface follows the theme, use the theme-keyed token. If the surface pins its own ground, use the ground-keyed one. The question is never “what mode is the page in” — it is “what is this text actually sitting on.”

Chart Series

A data palette, deliberately separate from the brand palette. The order is load-bearing. Three pairs converge under deuteranopia — blue/violet, olive/orange, pink/teal — and this order keeps them non-adjacent. Assign in order, never cycle. A seventh series folds into “Other”, small multiples, or composite encoding.