Skip to content

Colors and the CSS cascade

Six color keys, and the four layers your styles land in.

colors is required and takes exactly six keys, no more and no fewer:

json
{
"colors": {
"accent-primary": { "light": "#4E7D4A", "dark": "#7FAE79" },
"background": { "light": "#FBFAF7", "dark": "#14130F" },
"border": { "light": "#E4E0D8", "dark": "#2E2C26" },
"sidebar-background": { "light": "#F6F4EE", "dark": "#1C1B17" },
"header-background": { "light": "#FFFFFF", "dark": "#0B0A08" },
"card-background": { "light": "#FFFFFF", "dark": "#1C1B17" }
}
}

Every key needs both light and dark. Six-digit hex only — three-digit shorthand and eight-digit alpha forms are rejected rather than silently losing their alpha channel.

Six keys is deliberately few. They seed a much larger derived palette rather than being the palette themselves.

Reed assembles one stylesheet from four layers, concatenated in a fixed order so later layers win:

  1. L0 — component token contract

    Declares every custom property the shared components read, for every template. Lowest precedence, and it exists so components never resolve a property to nothing on a template that did not declare it.

  2. L1 — template baseline

    The chosen template’s own stylesheet. mint re-declares the L0 properties in its own baseline and therefore wins over them.

  3. L2 — generated design tokens

    The variables derived from your colors, typography and explicitly-set layout values.

  4. L3 — customCss

    The contents of your customCss files, in docs.json array order. Highest precedence.

Each layer is emitted with a marker comment — /* reed:L0 … */ through /* reed:L3 … */ — so you can read the built stylesheet and see exactly which layer a declaration came from. When an override does not take effect, that comment tells you whether you are fighting L1 or L2.

Your colors reach L2, above both the contract and the template baseline. customCss reaches L3, above everything. Reed emits around 185 --reed-* custom properties plus the underlying --sl-* variables, so overriding a token is usually better than overriding a selector: tokens are the supported surface, selectors are an implementation detail that can move.