Expand description
Serialise ThemeTokens into a tokens.css string.
Output is plain hex — all color-mix() math has already been done
by the engine. A static file is faster than nested color-mix()
at parse time and has zero browser-support risk.
Dark mode is emitted as two blocks that mirror the framework’s
own guards: an explicit :root[data-theme="dark"] block and a
@media (prefers-color-scheme: dark) { :root { … } } auto block.
Because the generated file is appended after the framework bundle,
a :root-only override would tie [data-theme="dark"] on
specificity and win by source order — leaking light into dark. The
dual structure prevents that for both the explicit toggle and OS
auto-dark. The dark values come from DarkPolicy (auto-derived,
light-only, or explicit). See docs/design/TOKENS-EMIT-SPEC.md.
The output has two sections inside the same :root block:
-
Canonical brand- tokens* — the engine’s primary output per §11 of the implementation brief. These are the names the decision layer reasons in:
--rio-brand-light,-dark,-adaptive,-surface,-accent,-hover,-active,-tint,-text. -
Drop-in compatibility tokens — the names the live admin templates already consume (
--rio-accent*, the surface ladder, the text ladder, the border ladder, semantic backgrounds). Without this block the generated file would not actually drop into the framework’s CSS bundle. Brand-derived tokens (--rio-accent,--rio-accent-hover,--rio-accent-soft,--rio-accent-border,--rio-bg,--rio-border,--rio-info-bg) come from the resolvedThemeTokens; the slate scaffold (--rio-surface-*,--rio-text-*,--rio-border-soft,--rio-border-strong) is brand-agnostic by design — mirrors the livecolors.cssso a brand swap does not move the chrome ladder out from under existing components.
Enums§
- Dark
Policy - How the emitted
tokens.cssshould handle dark mode.
Functions§
- emit
- Render a drop-in
tokens.cssfrom a fully resolvedThemeTokens. - emit_
with - Render a drop-in
tokens.csswith an explicitDarkPolicy.