Colour
Primitives are raw and theme-agnostic; themes map them to meaning. Nothing on this page is referenced by a component — components only ever see the semantic layer.
Hierarchy comes from the ramp
Eleven steps per theme, and no pure grey anywhere — each ramp carries a hue bias so the neutrals read as chosen rather than inherited. This is the load-bearing decision on the page: with a real ramp, hierarchy is built from tone, and borders can drop to a hairline. With three greys you end up outlining everything, which is exactly what makes an interface look amateur.
Warm — Horizon Sunrise
Paper rather than white. Biased warm so first light reads as light rather than as office.
Cool — Stormy Clouds
The classic Swiss grey, pulled very slightly blue so it reads as weather and not as newsprint.
Night — Night Aurora
Blue-black, so the cold green accent has something to sit against.
One accent per theme
Each is earned by its theme's name rather than picked for variety. A Swiss interface spends roughly two percent of its pixels on colour, so there is exactly one accent in play at a time — three steps of it, for rest, hover, and the lifted variant a dark ground needs.
Terracotta
Horizon SunriseSteel
Stormy CloudsAurora
Night AuroraStatus is not decoration
Four status hues, shared across themes and shifted per theme for legibility. They never stand in for the accent, and they never appear because a layout looked plain. In the UI they land as a tint plus theme ink rather than a saturated fill — quiet enough to annotate without shouting, and contrast-checked composited over the surface beneath.
red
Destructiveamber
Needs attentiongreen
Completeblue
In progressThe naming rule
Primitives are always namespaced — --color-cool-600, --space-4. Semantic tokens never are — --ink, --line, --accent. A --color-* reference inside a component is a tier violation you can spot in review without knowing the token list, and the Tailwind bridge enforces the same rule mechanically: bg-ground exists as a utility and bg-cool-600 does not.