Theming#
The site’s colors are a small set of semantic token pairs with light and dark variants. You edit them in the GUI’s Theme tab; 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 full set covers page, primary, accent, success,
warning, and error — twelve tokens per mode. You only set the ones you want to
change; the rest come from the base palette.
The Theme tab lays them out as a grid of hex values, light beside dark:
Token |
Light |
Dark |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Contrast validation#
The design rule is stricter than it first looks: within a mode, every -fg
must be legible on every -bg — not just on the background it’s paired with.
Components separate surfaces with borders and shadows rather than background
contrast, so a text color can land on any surface and has to stay readable
everywhere.
“Legible” means the WCAG AA ratio for normal text, 4.5:1. The merged palette is checked at build time, so a low-contrast override fails the build rather than shipping an unreadable site, and the error names every pair that fell short with its actual ratio.
In practice: keep all six -bg values in one lightness band and all six -fg
values in the opposite band. A primary-fg that only looks good on
primary-bg will fail against page-bg.
Custom CSS#
For anything the tokens don’t reach, the Theme tab has Edit custom CSS…,
which opens a user.css that overrides every style the site ships — no
!important needed. Show in folder opens its location. This is an escape
hatch, not the first stop: colors set through the tokens stay contrast-checked,
and CSS written here does not.
Light / dark at runtime#
Viewers get a color-mode selector (auto / light / dark) in the header. Their choice is remembered in their own browser — which is why every token is defined for both modes.
The values above are the example theme that ships with the repo’s development config — a starting point, not a requirement.