Tokens

Every value the components are built from, read from the package's dist/tokens.json when this site is built, with the description each token carries in its source.

Application code uses the semantic layer: every token there names a job, not a colour, so the same markup works in both themes and a rebrand touches one file. In CSS each one is a custom property prefixed --ds-, for example var(--ds-surface); in Tailwind it is a utility named after the job, bg-surface, text-fg-muted, rounded-control. Dark values live beside their light counterpart in the same source token, so the two cannot drift apart, and the token tests fail if a semantic token defines only one theme.

Semantic colours

TokenLightDarkUsed for
surface#ffffffoklch(21% 0.006 285.885)The page card — what content sits on.
surface-sunkenoklch(96.7% 0.001 286.375)oklch(14.1% 0.005 285.823)The ground behind the card and sidebar.
surface-subtleoklch(98.5% 0 0)oklch(27.4% 0.006 286.033)Table heads and row hover. 259 uses.
surface-inverseoklch(14.1% 0.005 285.823)oklch(98.5% 0 0)Primary buttons and the mobile FAB. Flips in dark — light-on-dark becomes dark-on-light.
surface-inverse-hoveroklch(27.4% 0.006 286.033)oklch(92% 0.004 286.32)Primary button hover. Light lifts zinc-950 to zinc-800; dark drops zinc-50 to zinc-200 — both move AWAY from the page, which is what reads as a press-ready state.
on-inverse#ffffffoklch(14.1% 0.005 285.823)Text and icons on surface-inverse.
scrimoklch(0% 0 0 / 0.4)oklch(0% 0 0 / 0.6)The dimmed layer behind a modal, drawer or sheet. Stays dark in BOTH themes — deriving it from `fg` would make it white in dark, which lights the page up instead of pushing it back.
borderoklch(14.1% 0.005 285.823 / 0.1)oklch(100% 0 0 / 0.1)The default hairline. zinc-950 at 10% (white at 10% in dark) rather than a solid step, so it reads correctly over any surface. 212 uses.
divideroklch(14.1% 0.005 285.823 / 0.05)oklch(100% 0 0 / 0.06)A rule BETWEEN items inside a container, as opposed to the container's own edge. Deliberately lighter than `border` (zinc-950 at 5% vs 10%) — a divider that matches the outer border makes a panel read as a table.
border-strongoklch(92% 0.004 286.32)oklch(37% 0.013 285.805)Cards that must read as raised — stat tiles, the active nav item.
fgoklch(14.1% 0.005 285.823)#ffffffHeadings and emphasis. 748 uses.
fg-bodyoklch(37% 0.013 285.805)oklch(87.1% 0.006 286.286)Running copy in rows and cells. 309 uses.
fg-mutedoklch(55.2% 0.016 285.938)oklch(70.5% 0.015 286.067)Labels, meta, subtitles. 850 uses — the single most-used class in the app.
fg-subtleoklch(70.5% 0.015 286.067)oklch(55.2% 0.016 285.938)Resting icon colour and timestamps. 438 uses.
accentoklch(54.6% 0.245 262.881)oklch(70.7% 0.165 254.624)Links and informational emphasis. Settles the blue-409 vs indigo-438 split.
accent-hoveroklch(48.8% 0.243 264.376)oklch(80.9% 0.105 251.813)
on-accent#ffffffoklch(14.1% 0.005 285.823)
focus-ringoklch(62.3% 0.214 259.815)oklch(62.3% 0.214 259.815)Kept identical in both themes — it must read against every surface, and blue-500 already was the Catalyst focus colour.
successoklch(59.6% 0.145 163.225)oklch(76.5% 0.177 163.223)
success-tintoklch(95% 0.052 163.051)oklch(76.5% 0.177 163.223 / 0.15)Badge and alert background. Light uses the fixed 100 step; dark uses 15% of the base over the surface, so one rule covers both themes without a second hand-tuned ramp.
success-washoklch(97.9% 0.021 166.113)oklch(76.5% 0.177 163.223 / 0.08)Large-surface fill for the success tone — alert strips, banners. Deliberately lighter than `success-tint`: the same hue needs more saturation to register in a badge than it does across a whole alert, so a tint used at panel size reads as shouting.
on-success-tintoklch(50.8% 0.118 165.612)oklch(84.5% 0.143 164.978)
warningoklch(66.6% 0.179 58.318)oklch(82.8% 0.189 84.429)
warning-tintoklch(96.2% 0.059 95.617)oklch(82.8% 0.189 84.429 / 0.15)
warning-washoklch(98.7% 0.022 95.277)oklch(82.8% 0.189 84.429 / 0.08)Large-surface fill for the warning tone — alert strips, banners. Deliberately lighter than `warning-tint`: the same hue needs more saturation to register in a badge than it does across a whole alert, so a tint used at panel size reads as shouting.
on-warning-tintoklch(55.5% 0.163 48.998)oklch(87.9% 0.169 91.605)
dangeroklch(57.7% 0.245 27.325)oklch(70.4% 0.191 22.216)
danger-hoveroklch(50.5% 0.213 27.518)oklch(80.8% 0.114 19.571)
danger-tintoklch(93.6% 0.032 17.717)oklch(70.4% 0.191 22.216 / 0.15)
danger-washoklch(97.1% 0.013 17.38)oklch(70.4% 0.191 22.216 / 0.08)Large-surface fill for the danger tone — alert strips, banners. Deliberately lighter than `danger-tint`: the same hue needs more saturation to register in a badge than it does across a whole alert, so a tint used at panel size reads as shouting.
on-danger-tintoklch(50.5% 0.213 27.518)oklch(80.8% 0.114 19.571)
on-danger#ffffffoklch(14.1% 0.005 285.823)Text on a filled danger surface. Dark flips to a near-black because `danger` lightens to red-400 there — white on red-400 is 2.87:1 and fails AA. Mirrors how on-accent is handled.
accent-tintoklch(93.2% 0.032 255.585)oklch(70.7% 0.165 254.624 / 0.15)
accent-washoklch(97% 0.014 254.604)oklch(70.7% 0.165 254.624 / 0.08)Large-surface fill for the accent tone — alert strips, banners. Deliberately lighter than `accent-tint`: the same hue needs more saturation to register in a badge than it does across a whole alert, so a tint used at panel size reads as shouting.
on-accent-tintoklch(48.8% 0.243 264.376)oklch(80.9% 0.105 251.813)
neutral-tintoklch(92% 0.004 286.32)oklch(100% 0 0 / 0.1)The default badge, for states with no semantic charge.
on-neutral-tintoklch(37% 0.013 285.805)oklch(87.1% 0.006 286.286)

Palette

The primitives the semantic layer points at. Application code should not use these directly; they exist so a semantic token can be changed in one place.

HueSteps
white#ffffff
black#000000
zinc
blue
emerald
amber
red

Radius

TokenValueUsed for
rounded-chip0.375remChips, delta pills, tight icon buttons.
rounded-control0.5remThe default: buttons, inputs, cards. 827 uses.
rounded-panel0.75remPanels, modals, the sidebar nav card. 161 uses.
rounded-sheet1remTop corners of the mobile bottom sheet.
rounded-full9999pxAvatars, badges, pills. 9999px rather than v4's calc(infinity * 1px) — same render, but only the finite value is portable outside Tailwind.

Shadow

TokenValueUsed for
shadow-raised0 1px 2px 0 rgb(0 0 0 / 0.05)Resting cards and the active nav item. 195 uses — the only elevation most screens need.
shadow-float0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)Things that float over the page on demand — dropdowns, popovers, drawers.
shadow-overlay0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)Modal panels only — the one surface that blocks the page behind it.

Controls

TokenHeightUsed for
h-control-sm2rem32px — inside table rows and card footers.
h-control-md2.25rem36px — the default, at sm and up.
h-control-lg2.75rem44px — below sm, and the studio action bar.
h-control-fab3.5rem56px — the mobile floating action button. Larger than lg on purpose: it is the one control a thumb reaches for without looking, and it overlaps the bar rather than sitting in it.

Space

TokenValueUsed for
base0.25rem
gutter1remGrid gap between cards.
section1.5remGap between stacked panels.
page2.5remContent card padding at lg and up.

Type

FamilyStack
font-sansInter, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"
font-monoui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace
WeightValueUsed for
font-regular400Body copy only. Rarely written — it is the default.
font-medium500Labels, nav items, table cells. 1,144 uses — the most-written weight.
font-semibold600Headings, buttons, stat values. 818 uses.
StyleSize / line heightWeightUsed for
text-display1.875rem / 2rem600Stat tile values. 30/32.
text-heading1.25rem / 2rem600Every page title in the dashboard. 20/32.
text-title1.125rem / 1.75rem600Overlay and section titles — sheet headers, modal headings, empty-state headings. 18/28. Added after the fact: the app uses 18px 99 times, three times more than 20px, so leaving it out was a gap rather than a simplification and rounding those up would have been a change disguised as a migration.
text-section0.875rem / 1.25rem600Panel headers and card titles. 14/20.
text-body0.875rem / 1.5rem400The workhorse. 1,705 uses — if a size is unspecified, it is this one. 14/24.
text-body-touch1rem / 1.5rem400Inputs below the sm breakpoint. 16px stops iOS zooming the page on focus. 16/24.
text-meta0.75rem / 1rem400Timestamps, counts, helper text, badge copy. 989 uses. 12/16.
text-overline0.75rem / 1rem500Table column headers.

Was this page helpful?