Azalea
Azalea

Colour

Nine semantic tokens and three brand colours. Every value below is read live from the stylesheet, so this page cannot drift from the tokens — a colour chart that lies is worse than no chart.

Semantic tokens

Name things by role, never by colour. `--primary` can be re-tuned for contrast; `--teal-500` cannot, without a find-and-replace across four repos. Click any swatch to copy its var() reference.

Brand

Sampled from the Averoa mark. These are for identity — a logo, a gradient accent, a hero number. They are not UI colours: none of them is guaranteed to carry text at an accessible contrast, so never put copy on one without checking.

brand-text

In both themes

The same tokens, two sets of values. Nothing below hardcodes a colour.

light

Surface

Secondary text on a card, above a hairline.

dark

Surface

Secondary text on a card, above a hairline.

Contrast, measured live

Computed from the values your browser actually resolved, in the theme you are actually in — switch the theme and watch them change. A design system that publishes a colour chart without these is asking to be trusted on a claim it never checked.

Body text on the pageAA 4.5:1
Body text on a cardAA 4.5:1
Secondary text on the pageAA 4.5:1
Primary button labelAA 4.5:1
Primary button label, hoveredAA 4.5:1
Primary as link textAA 4.5:1
Focus ring against the pageAA 3:1

The border token is deliberately not listed. WCAG's 3:1 rule covers non-text content needed to understand the interface; a hairline between rows is decoration, and pushing it to 3:1 would make every list look caged.

One place the palette was wrong

This is what the table above caught, and it is the reason it exists.

The light theme's --primary was #0db39e. White label text on it measured 2.64:1 against a 4.5:1 requirement — on the most-used control in the platform. As link text it was 2.51:1, and as the focus ring 2.51:1 against a 3:1 bar.

It is now #098071: the same hue and saturation, dropped in lightness until both pass. It reads as the same teal. --muted moved for the same reason, from 4.47:1 to 4.65:1.

That means Hana looks very slightly deeper than before — a deliberate exception to the “tokens lifted verbatim” rule. A design system that preserves an accessibility defect to preserve an appearance has the priorities backwards. The dark theme already passed everything and is untouched.

Rules

  • Never hardcode a hex in a component. If you need a colour that is not here, the answer is usually a token that does not exist yet.
  • Define every colour on bare :root first, then redefine it in the dark blocks. A colour whose only definition lives inside a media query is invisible in the other theme — the most common way a themed component breaks.
  • Status colours are not in this palette on purpose. They live in StatusBadge, where meaning and colour are decided together.