Skip to content

Theming

Colour is one of the two orthogonal axes (the other is density). A scheme is just a block of token overrides — no CSS fork.

Schemedata-themeSurfaceAccent
Dark Knight (canonical)dark-knight (alias dark)deep navyteal
Désert Dunesdesert-dunes (alias light)warm creamcoral
<html data-theme="dark-knight"> <!-- force dark -->
<html data-theme="desert-dunes"> <!-- force light -->
<html> <!-- unset → follows OS via prefers-color-scheme -->

The tokens set color-scheme for you, so native form controls and scrollbars match. A [data-theme-toggle] button cycles the schemes.

Every solid fill has an --on-* text token (--on-primary, --on-danger, …), so contrast is guaranteed rather than lucky. Use them whenever you fill with a brand colour:

.badge-primary { background: var(--primary); color: var(--on-primary); }

Each colour also ships an -rgb channel triple. Build soft fills, rings and hover states from it so they re-tint with the brand:

background: rgb(var(--primary-rgb) / .12); /* soft fill */
box-shadow: 0 0 0 3px rgb(var(--primary-rgb) / .22); /* focus ring */

Never write a literal rgba(45, 212, 191, …) — it won’t follow a brand override.

Override the brand/semantic tokens after the foundation. One block re-skins everything:

:root {
--primary: #ff6b4a;
--primary-rgb: 255 107 74;
--on-primary: #ffffff;
}

Neutral lines and borders flow through --border-rgb, so they flip with the scheme automatically. See Brand a product for the full recipe.

Each consuming product owns its theme.css — a single :root{} override shipped in the product’s own repo, not published with the kit. The pattern is demonstrated with fictional example brands:

Example themeBrandType
qazana (umbrella)coralFraunces · Space Grotesk
aurorapolar mintSpace Grotesk
vermeilvermilionFraunces
nocturneindigoBricolage Grotesque

Try them in the live theme switcher — picking a theme swaps a real override file onto the page.

The tokens and kits live in the qazana cascade layer; theme files and your app’s CSS are unlayered. Unlayered CSS beats layered CSS regardless of selector specificity, so a plain :root{} theme outranks even the tokens’ higher-specificity scheme blocks (:root[data-theme=…]) — in both schemes, with no !important and no selector games.