Foundations
Colour that can be reasoned about.
The palette is authored in OKLCH, organised semantically, and measured on every change. Each of those three choices exists to make a different mistake harder — mixing by feel, naming by appearance, and shipping text nobody can read.
Why OKLCH
In hex and HSL, lightness is a lie. Two colours with the same nominal lightness can differ enormously in how bright they appear, because the notation describes the signal sent to the display rather than the impression made on a person. Yellow at 50% reads far lighter than blue at 50%.
OKLCH is perceptual: its lightness channel tracks apparent brightness. That single property is what makes everything else on this page possible. A hue can be changed without silently changing how light it reads, a whole family can be darkened by a known amount, and a contrast budget becomes arithmetic instead of trial and error.
A worked example
The system's warm chart hue is too light to serve as a line on a light card — it misses the 3:1 floor for non-text marks. The fix was not to pick a new colour by eye: the same hue and chroma were kept and only lightness was lowered, giving a stroke token that clears the floor while remaining recognisably the same colour. In a non-perceptual space that edit is guesswork.
The semantic layer
Components never name a hue. They ask for a role — the surface a card sits on, the text colour for secondary information, the accent that means "act here" — and the token layer answers with a value appropriate to the active theme.
The gain is not tidiness. It is that a role can be re-measured, and a hue cannot. When every foreground names the surface it belongs to, the set of pairs that must clear a contrast floor is derivable rather than remembered, which is exactly how the evidence page builds itself.
The elevation ladder
Depth is a short, named ladder rather than a continuum of shadows — four steps, enough to express hierarchy and few enough to stay consistent across two products.
- --surface-sunken
oklch(0.98 0.005 60) - --surface-base
oklch(0.97 0.008 60) - --surface-raised
oklch(1 0 0) - --surface-overlay
oklch(1 0 0)
Text on its own tint
The badge idiom — coloured text on a soft wash of the same hue — hides a trap. The wash moves the background toward the text, so a colour that comfortably clears the contrast floor on a plain card can fall below it on a 12% tint of itself. The pairing looks correct in isolation and fails in composition.
The system's answer is a parallel set of tokens for exactly this case. Where a hue is used
as a badge, its text takes the -on-tint variant — the same colour pulled far enough
away from its own wash to clear the floor over the composite.
Measure the composite, not the token
A single foreground-and-background pair cannot express this: the effective background is the wash composited over the surface beneath it. Any audit that measures the text against the bare card will report a comfortable ratio for something that is not comfortable at all.
The system currently defines 4 of these:
--credit-on-tint , --destructive-on-tint , --primary-on-tint , --warning-on-tint . Every one of them is measured over its own tint, in both themes, on the
contrast page.
What colour is not allowed to do
Carry meaning on its own
Every state is legible from its text. Colour reinforces; it never encodes. This is not only a colour-blindness accommodation — it is also what keeps a state readable in a screenshot, a printout, or a high-contrast mode that discards the palette entirely.
Cross between data and status
Chart series and status indicators draw from separate sets. The warm hue in the data palette is never allowed to imply caution, because a series that happens to be amber would then be making a claim the data does not support.
Appear outside the token layer
A colour written directly into a component is invisible to every mechanism described here. It will not be audited, it will not respond to a theme, and it will not be found when the palette moves.
19 pairs currently answer to these rules, and 19 of them clear the floor in both themes. The token reference lists every value the system defines.