Themes
Two themes built from one token file. Dark may override colour and nothing else, and every contrast pair is checked in both.
How it is built
tokens/core.tokens.json holds the light theme plus everything that is not colour. tokens/themes/dark.tokens.json overrides the colour group only, and a loader throws if it tries to touch type, space or layout. Type that changed between themes would be a different design, not a theme.
:root { /* light */ }
.dark,
[data-theme="dark"] { /* dark */ }
Which file to import
tokens.css is class-driven and never reads the operating system preference. That is deliberate: a reader who picked light has to get light on a dark laptop. The app owns the choice.
tokens-auto.css adds a prefers-color-scheme block guarded by :root:not(.light):not([data-theme="light"]). Use it only on a standalone page with no toggle, like this documentation.
Every colour must be themed
A colour that keeps its light value in dark is almost always a bug, so a test fails on any colour the dark theme does not define. Exceptions have to be named explicitly in the test, and there is currently one: focus, where the amber is correct on both grounds.
Both themes are checked
Forty-four pairs, two themes, 88 checks. Two of the three failures on the first build were dark-only, which is exactly the class of bug that ships when dark mode is eyeballed:
dark: color.ink-inverse on color.paper-dark is 1.05:1, needs 4.5:1 (footer text)
dark: color.focus on color.ink is 1.44:1, needs 3:1 (focus ring)
The first was a semantic error. In dark the footer is still a dark surface, so text on it stays light; text on the brand colour is on-brand, which is the dark value. The second changed the rule rather than the colour, because the focus indicator is two colours working together. See Focus.
Check your work in both
Every example on this site renders in whichever theme is active. Use the toggle in the masthead on any page; the choice is remembered and applied before first paint, so there is no white flash.
The same card, in whichever theme is active
HTML
<a class="p234-story p234-story--secondary" href="#">
<span class="p234-kicker" data-section="politics">Politics</span>
<h3 class="p234-story__headline">Senate passes the 2027 appropriation bill at second reading</h3>
<p class="p234-story__standfirst">The chamber moved the bill after ninety minutes of debate on the capital component.</p>
<div class="p234-meta">
<span class="p234-meta__source">Channels Television</span>
<span class="p234-meta__dot">·</span>
<span>4 hours ago</span>
<span class="p234-coverage">3 sources</span>
</div>
</a>