Theming
Theming
The site's colors are a small set of semantic token pairs with light and dark
variants. A deployment overrides them with an optional theme.json; the result
is merged onto the base palette and contrast-validated at build time.
Tokens
Each semantic role has a background (-bg) and foreground (-fg) token, in both
light and dark modes. The theme.json keys are the token names without the
leading --:
{
"light": {
"page-bg": "#faf7ff",
"page-fg": "#1e1b2e",
"primary-bg": "#ede9fe",
"primary-fg": "#5b21b6",
"accent-bg": "#fff3e0",
"accent-fg": "#8a4b00"
},
"dark": {
"page-bg": "#14121f",
"page-fg": "#ece9f6",
"primary-bg": "#2a2140",
"primary-fg": "#c9b6ff",
"accent-bg": "#3a2b08",
"accent-fg": "#f3c968"
}
} The full semantic set covers page, primary, accent, success, warning, and
error — each with a -bg/-fg pair. theme.json only needs to include the
tokens you want to change; the rest come from the base palette.
Contrast validation
The design rule is simple: every -fg must be legible on its -bg. The
merged palette is checked at build time, so a low-contrast override fails the
build rather than shipping an unreadable site. Tokens are emitted as CSS custom
properties and consumed throughout the app.
Light / dark at runtime
Viewers get a color-mode selector (auto / light / dark) in the header, persisted in a cookie — which is why every token is defined for both modes.
The palette above is the example theme that ships in the repo's
dev-config, and it's also the source of this docs site's violet + amber accents.