Themes
The system has one palette and two readings of it. The dark theme changes which palette colours the semantic tokens point at, and nothing else; the palette itself never changes.
How it works
Section titled “How it works”tokens.css writes the light values on :root and on [data-theme="light"], and the dark theme as one [data-theme="dark"] block that holds only the tokens it changes. The light block on the attribute lets a light section sit inside a dark page. In the token files, the dark theme is theme-dark.tokens.json, applied by the resolver’s theme modifier.
Two rules keep the dark theme coherent:
- The dark surface stays emphasis. In the dark theme
--surface-darkis one step above the canvas rather than equal to it, so a dark card, a dark band and everytone="dark"component still stand apart from the page. - Coral does not move.
--color-primary,--color-on-primaryand--focus-ringare the same in both themes. The brand colour is the one thing a theme may not reinterpret.
Theme and tone
Section titled “Theme and tone”They are separate. A component’s tone names a surface within the page, such as a dark card; the theme names the page’s own floor. A component never takes a theme prop: it reads the tokens, and the tokens follow the theme.
Switching
Section titled “Switching”The CSS reads only the data-theme attribute; there is no prefers-color-scheme query. A page sets data-theme="light" or data-theme="dark" on <html> with a short script in <head>, before the first paint, so a page never flashes the wrong theme. “Follow the system” is a stored preference that the script turns into light or dark with matchMedia, which is what lets a page force light against a dark operating system. The switch itself has no transition: a crossfade would put every surface in motion at once.
What the dark theme changes
Section titled “What the dark theme changes”| Token | Light | Dark | Description |
|---|---|---|---|
--color-primary-disabledcolor.primary-disabled | #e6dfd8Points to --cream-500 | #3a3833 | Primary fill when disabled. |
--text-inktext.ink | #141413Points to --ink-900 | #faf9f5Points to --cream-50 | Headlines and the strongest text. |
--text-body-strongtext.body-strong | #252523Points to --ink-800 | #f5f0e8Points to --cream-100 | Emphasized body text. |
--text-bodytext.body | #3d3d3aPoints to --ink-700 | #e8e0d2Points to --cream-300 | Running text. |
--text-mutedtext.muted | #6c6a64Points to --ink-500 | #a09d96Points to --ink-300 | Secondary text such as dates and metadata. |
--text-muted-softtext.muted-soft | #8e8b82Points to --ink-400 | #7f7c74 | The quietest text: hints and micro-labels. |
--surface-canvassurface.canvas | #faf9f5Points to --cream-50 | #181715Points to --night-900 | The page floor. |
--surface-softsurface.soft | #f5f0e8Points to --cream-100 | #1f1e1bPoints to --night-850 | A soft band one step above the canvas. |
--surface-cardsurface.card | #efe9dePoints to --cream-200 | #252320Points to --night-800 | Cards on the canvas. |
--surface-cream-strongsurface.cream-strong | #e8e0d2Points to --cream-300 | #2b2925 | The strongest cream, for emphasis inside cards. |
--surface-darksurface.dark | #181715Points to --night-900 | #2b2925 | The emphasis surface: dark cards, code windows, the footer. |
--surface-dark-softsurface.dark-soft | #1f1e1bPoints to --night-850 | #322f2a | One step above the dark surface, such as code inside a dark card. |
--surface-dark-elevatedsurface.dark-elevated | #252320Points to --night-800 | #393631 | Raised elements on dark surfaces. |
--surface-blur-creamsurface.blur-cream | rgb(250 249 245 / 72%) | rgb(24 23 21 / 72%) | Translucent cream behind a 12px backdrop blur, such as the scrolled top bar. |
--surface-blur-cream-opaquesurface.blur-cream-opaque | rgb(250 249 245 / 94%) | rgb(24 23 21 / 94%) | Near-opaque cream for when the blur is not supported. |
--hairlinehairline | #e6dfd8Points to --cream-500 | #35332f | Borders. They read as one elevation step, not as ink lines. |
--hairline-softhairline-soft | #ebe6dfPoints to --cream-400 | #2a2823 | Fainter borders inside cards. |
--hairline-on-darkhairline-on-dark | #31302c | #43413b | Borders on dark surfaces. |
--marker-coralmarker.coral | #f4e2d9 | #4d352bPoints to --marker-coral-on-dark | |
--marker-tealmarker.teal | #deede7 | #2e453fPoints to --marker-teal-on-dark | |
--marker-ambermarker.amber | #f7ead9 | #52412cPoints to --marker-amber-on-dark | |
--marker-redmarker.red | #f1d9d5 | #492826Points to --marker-red-on-dark | |
--marker-coral-on-darkmarker.coral-on-dark | #422c24 | #4d352b | |
--marker-teal-on-darkmarker.teal-on-dark | #273a35 | #2e453f | |
--marker-amber-on-darkmarker.amber-on-dark | #463624 | #52412c | |
--marker-red-on-darkmarker.red-on-dark | #3e2120 | #492826 | |
--border-hairlineborder.hairline | 1px solid #e6dfd8 | 1px solid #35332f | Dividers and card outlines. |
--border-hairline-softborder.hairline-soft | 1px solid #ebe6df | 1px solid #2a2823 | Fainter dividers inside cards. |
--border-hairline-darkborder.hairline-dark | 1px solid #31302c | 1px solid #43413b | Borders on dark surfaces. |