Site Token Contract (`--site-*`)

No Leed component reads a color directly. Every one of them reads a --component-* custom property, and each of those resolves through a three-deep var() fallback chain. One rung of that chain belongs to you: --site-*. Set the names you care about in your own :root, leave the rest alone, and every component that reads them follows.

The resolution chain

The shape is identical for every color Leed paints:

--component-primary-color: var(
  --docs-primary-color,                 /* set by the active documentation color theme */
  var(--site-primary-color,             /* set by YOU, in your own :root */
      var(--default-primary-color))     /* Leed's floor, in defaults.css */
);

Three rungs, resolved left to right, first defined value wins:

RungWho sets itWhereShould you?
--docs-*The color-theme-* utility on <html>docs/themes/<name>.css, or your own custom themeOnly by writing a documentation theme
--site-*Youa :root block in your own tailwind/ CSSYes — this is the supported surface
--default-*Leeddefaults.css, with its own dark overrideNo

Because --docs-* sits above --site-*, a documentation page with a color theme applied overrides your site palette inside the docs — which is the point of a theme. Everywhere else on the site, --site-* is the top of the chain.

flowchart LR
  C["--component-X<br/><i>read by every Leed component</i>"]
  D["--docs-X<br/>set by the color-theme utility<br/><i>docs pages only</i>"]
  S["--site-X<br/>set by YOU, in :root<br/><i>your supported surface</i>"]
  F["--default-X<br/>defaults.css<br/><i>light + dark floor</i>"]
  C -->|"first choice"| D
  D -.->|"undefined ⇒ fall through"| S
  S -.->|"undefined ⇒ fall through"| F
  D --> OUT["painted value"]
  S --> OUT
  F --> OUT

A handful of --component-* names read a differently named --docs-* token as their first choice — --component-anchor-text-color reads --docs-body-link-color, and both --component-current-location-text-color and --component-copied-content-bg-color read --docs-primary-color. That only matters if you are writing a documentation theme; from the --site-* rung the mapping is name-for-name.

Setting tokens

Tokens go in an ordinary :root block in a file under tailwind/, imported from tailwind/site.config.css. They are custom-property declarations, so they do not need to win a cascade fight — leave the file unlayered or put it in layer(base), whichever your entry file already does. Copy only the lines you care about.

/* tailwind/site/theme.css */
:root {
  color-scheme: light dark;

  --site-primary-color: var(--color-pink-700);
  --site-primary-color-hover: var(--color-pink-800);
  --site-text-color: var(--color-neutral-600);
  --site-bg-color: var(--color-white);
  --site-border-color: var(--color-neutral-300);
  --site-header-1-color: var(--color-neutral-900);

  @media (prefers-color-scheme: dark) {
    --site-text-color: var(--color-neutral-300);
    --site-bg-color: var(--color-neutral-950);
    --site-border-color: var(--color-neutral-700);
    --site-header-1-color: var(--color-neutral-50);
  }
}

The 45 tokens

Defaults are written as the Tailwind color names defaults.css uses. A — in the dark column means the light value carries into dark unchanged. Where a default is another token, the chain is given.

Brand and primary

TokenWhat it colorsLight defaultDark default
--site-primary-colorThe accent: buttons, active states, the copy-confirmation groundblue-500blue-400
--site-primary-color-hoverThe accent under the pointerblue-600blue-500
--site-primary-lightA lighter accent; the sidebar hover wash is mixed from itblue-400blue-300

Page surface and text

TokenWhat it colorsLight defaultDark default
--site-bg-colorThe page ground — and the diagram zoom stagewhiteslate-950
--site-text-colorBody textgray-700slate-400
--site-fixed-body-bg-colorThe ground behind fixed/overlay body contentslate-950—
--site-border-colorGeneric borders and rulesslate-300slate-500
--site-card-bg-colorThe ground behind an API reference cardtransparent—
--site-step-light-colorThe connector between numbered stepsgray-200slate-800

Headings

TokenWhat it colorsLight defaultDark default
--site-header-1-colorh1gray-900gray-200
--site-header-2-colorh2gray-900gray-200
--site-header-3-colorh3gray-800gray-100
--site-header-4-colorh4gray-800gray-100
--site-header-5-colorh5gray-800slate-100
--site-header-6-colorh6gray-800slate-100

Links and heading anchors

TokenWhat it colorsLight defaultDark default
--site-body-link-colorLinks in the article body--component-primary-color—
--site-body-link-hover-colorBody link, hover--component-primary-color-hover—
--site-body-link-active-colorBody link, :active--component-primary-color-hover—
--site-anchor-text-colorThe # anchor beside a headingsky-600—
--site-anchor-text-color-hoverHeading anchor, hoversky-700sky-400
--site-anchor-text-color-activeHeading anchor, :activesky-900—

Navigation and current location

TokenWhat it colorsLight defaultDark default
--site-current-location-text-colorThe text of the page you are on, in the sidebar and TOCsky-800sky-500
--site-current-location-bg-colorThe ground of the current TOC entryslate-50slate-800
--site-sidebar-link-bg-colorThe resting ground of every sidebar rowtransparent—
--site-sidebar-link-hover-bg-colorA sidebar row under the pointera 7% wash of --component-primary-light—
--site-sidebar-link-current-bg-colorThe sidebar row for the current pagefalls through to the hover token—
--site-menu-bg-colorMenu and dropdown groundswhiteslate-900
--site-header-bg-colorThe site header bandgray-100slate-900
--site-header-border-colorThe rule under the headergray-500slate-200

Code and math

TokenWhat it colorsLight defaultDark default
--site-code-bg-colorThe outer code-block wellgray-100slate-900
--site-code-inner-bg-colorThe inner <code> surfacewhiteslate-950
--site-code-border-colorThe code-block border (used at 10% alpha)gray-950white
--site-code-bg-color-selectionSelected text inside a code blockblue-100blue-800
--site-code-math-text-colorRendered block and inline mathgray-700slate-400

Search

TokenWhat it colorsLight defaultDark default
--site-search-button-bg-colorThe search trigger in the headerwhiteslate-950
--site-search-modal-bg-colorThe search dialog groundwhiteslate-950
--site-search-result-bg-colorThe resting ground of one result rowtransparent—

Buttons, pagination, footer, copy

TokenWhat it colorsLight defaultDark default
--site-button-secondary-bg-colorSecondary button groundgray-100gray-600
--site-button-secondary-bg-hover-colorSecondary button, hovergray-200gray-700
--site-pagination-icon-colorPrevious/next arrowsgray-500gray-400
--site-pagination-icon-color-hoverPrevious/next arrows, hovergray-700gray-200
--site-footer-social-icons-colorFooter social icons--component-text-color—
--site-footer-social-icons-hover-colorFooter social icons, hovergray-500gray-400
--site-copied-content-bg-colorThe “Copied” confirmation groundpink-800—
--site-copied-content-text-colorThe “Copied” confirmation textwhite—
All 45 names as one copy-pasteable :root block

Paste this into a file under tailwind/, delete every line you do not want, and give the survivors real values. Anything you delete falls through to Leed’s default, which already has a dark twin.

:root {
  color-scheme: light dark;

  /* brand */
  --site-primary-color: ;
  --site-primary-color-hover: ;
  --site-primary-light: ;

  /* surface */
  --site-bg-color: ;
  --site-text-color: ;
  --site-fixed-body-bg-color: ;
  --site-border-color: ;
  --site-card-bg-color: ;
  --site-step-light-color: ;

  /* headings */
  --site-header-1-color: ;
  --site-header-2-color: ;
  --site-header-3-color: ;
  --site-header-4-color: ;
  --site-header-5-color: ;
  --site-header-6-color: ;

  /* links and heading anchors */
  --site-body-link-color: ;
  --site-body-link-hover-color: ;
  --site-body-link-active-color: ;
  --site-anchor-text-color: ;
  --site-anchor-text-color-hover: ;
  --site-anchor-text-color-active: ;

  /* navigation */
  --site-current-location-text-color: ;
  --site-current-location-bg-color: ;
  --site-sidebar-link-bg-color: ;
  --site-sidebar-link-hover-bg-color: ;
  --site-sidebar-link-current-bg-color: ;
  --site-menu-bg-color: ;
  --site-header-bg-color: ;
  --site-header-border-color: ;

  /* code and math */
  --site-code-bg-color: ;
  --site-code-inner-bg-color: ;
  --site-code-border-color: ;
  --site-code-bg-color-selection: ;
  --site-code-math-text-color: ;

  /* search */
  --site-search-button-bg-color: ;
  --site-search-modal-bg-color: ;
  --site-search-result-bg-color: ;

  /* buttons, pagination, footer, copy */
  --site-button-secondary-bg-color: ;
  --site-button-secondary-bg-hover-color: ;
  --site-pagination-icon-color: ;
  --site-pagination-icon-color-hover: ;
  --site-footer-social-icons-color: ;
  --site-footer-social-icons-hover-color: ;
  --site-copied-content-bg-color: ;
  --site-copied-content-text-color: ;

  /* layout — not a color */
  --site-header-height: ;

  @media (prefers-color-scheme: dark) {
    /* re-declare only the ones that differ */
  }
}

Every token above has a separate dark default, applied by the single media query described in Dark Mode. The 17 built-in color themes that supply the --docs-* rung above these are cataloged in Themes, Fonts and Code Themes.

Five tokens that bypass the chain and are read raw

A small set of properties is read without a --component-* wrapper. Two consequences: their names carry no --site- prefix, and leaving them unset leaves them undefined rather than inherited — an undefined custom property in a color position makes the whole declaration invalid at computed-value time, so the element gets no paint at all rather than a fallback.

TokenRead byWhat happens if unset
--api-snippets-bg-colordocs/api.css — the small mono chips beside endpoints, parameters and enum valuesThe chip renders with no ground; text sits directly on the page
--api-select-list-item-bg-color-hoverdocs/api.css — the server/language select list in the API referenceNo hover feedback on the list rows
--menu-footer-header-text-colordocs/docs.css — the bold column headings in the documentation footer menuThe heading falls back to inherited color
--form-border-color / --form-border-color-hoverOccupies the middle rung of --component-form-border-color, but unprefixedNothing breaks — there is a --default-form-border-color floor (gray-300 light, white dark). Listed because the name surprises people
--form-download-spinner-textutils/utilities.css — the spinner icon inside a form download buttonThe spinner falls back to inherited color

--site-header-height

The one non-color token in the contract, and the token that makes in-page anchors land correctly.

TokenTypeDefaultWhat reads it
--site-header-heightlength0pxhtml { scroll-padding-top } in defaults.css
html {
  scroll-padding-top: calc(
    var(--height-header, var(--site-header-height, 0px)) + var(--height-toc, 0px)
  );
}

--height-header and --height-toc are published at runtime by documentation.js, on documentation pages only. Everywhere else both are undefined — which is exactly why the fallback exists, and why a non-documentation site with a fixed header has to declare the value itself:

:root {
  --site-header-height: 68px;
}

Measure it; do not guess. Open a page, select the header element, and read its rendered height including its border. If the number is wrong, every in-page anchor lands off by the difference — which is a quiet, permanent papercut across an entire documentation set, since deep links to a heading are how most readers arrive at a section.

--component-bg-color and the diagram zoom stage

One paragraph, because the failure only appears after a click and only in one scheme.

Every Mermaid diagram is click-to-zoom. The full-screen viewer paints its stage var(--component-bg-color, #ffffff) and clones the diagram into it — so the diagram resolves its own var() colors there, against whatever the page’s tokens say. A diagram themed for ink-on-parchment, dropped onto a hard white stage on a dark page, is dark-on-dark and close to unreadable.

Setting --site-bg-color in both schemes is enough to make --component-bg-color resolve correctly and the stage carry the same ground the diagram had in the document. The rest of diagram theming — the palette file, which keys accept a var(), and why — is in Theming Diagrams.

Tokens versus overrides

The dividing line is short. If what you want to change is a color, set a token. If it is structure — spacing, radius, geometry, layout — write a rule in a layer(components) file, as described in Cascade Layers and Overriding Leed. And if the thing you are fighting is painted by a theme utility, neither an override nor a --site-* token reaches it: set the --docs-* token instead, because the utility is unlayered and outranks anything layered you could write.

Readers arriving here because an anchor scrolled its heading under the header want the --site-header-height section above; the reading side of that behavior is described in Documentation Reading Experience.

ESC