Colors
Semantic color tokens read live from the active theme, with WCAG contrast checks.
Semantic tokens
All 48 color tokens from globals.css, read live from the preview theme. Switch Light and Dark in the header and the values and ratios update.
Surfaces 8
Layers from the desk to the sheet. Most screens use only canvas, background, subtle and muted.
Text and ink 10
Four steps of ink. Primary is the ink button, so it matches foreground.
Brand 5
Iris violet marks selection, focus, the first chart series and AI. It is never the default button.
Status 8
Kept apart from brand so a selected row never reads as a success.
Lines 3
Hairlines do the work shadows usually do. Sheet edge is translucent so it reads on any surface.
Chart palette 6
Six series colors in a fixed order. Rated as graphics against the sheet (3:1).
Sidebar 8
The shell sidebar sits on the canvas, so it has its own set.
Contrast
The pairs the product actually ships, measured in the preview theme. Translucent soft fills are composited over the sheet first, the same way the browser paints them.
Measuring…
Ratios use the WCAG 2.x relative luminance formula and are truncated, never rounded up. Text needs 4.5:1 (AA) or 7:1 (AAA); 3:1 passes only for text at 18px, or 14px bold, and for icons, focus rings and chart marks (WCAG 1.4.11).
Status colors
Four status hues, each with a soft fill. StatusDot carries state in lists; soft badges carry it in tables and headers.
successPaidPaidwarningPendingPendinginfoIn reviewIn reviewdestructiveOverdueOverdue
- Never color alone. Pair every status hue with a word, an icon or a dot label so the meaning survives color blindness and grayscale.
- Small labels use ink. Where a tinted label measures below 4.5:1 (see the ratios above), use the ink label with a colored dot, or keep tinted text to icons and 14px semibold.
- Assign in order. Series 1 is always the subject of the chart, so it gets brand iris. Keep a series on the same color across every chart on a page.
- Six at most. Group the tail into “Other” on chart-6. More categories than that belong in a table or a ranked bar list.
- Label what is light. Series under 3:1 on the sheet (see the badges) need direct labels or a legend with values, never color alone.
Light and dark
Key tokens in both themes at once, read from explicit .theme-light and .theme-dark scopes. Dark soft fills are translucent so they tint whatever surface they sit on.
.theme-light--canvas…--background…--foreground…--ink-2…--muted-foreground…--border…--brand…--brand-soft…--brand-ink…--success…--warning…--destructive…
.theme-dark--canvas…--background…--foreground…--ink-2…--muted-foreground…--border…--brand…--brand-soft…--brand-ink…--success…--warning…--destructive…
1// 1. Tailwind classes (preferred): tokens are mapped in @theme inline2<div className="rounded-xl border bg-background text-foreground">3 <p className="text-ink-2">Secondary text</p>4 <span className="bg-brand-soft text-brand-ink">Selected</span>5</div>67// 2. Arbitrary values when a utility doesn't exist8<div className="shadow-[0_0_0_1px_var(--sheet-edge)]" />910// 3. Inline styles, SVG and Recharts11<Bar dataKey="revenue" fill="var(--chart-1)" />12<CartesianGrid vertical={false} stroke="var(--border)" />1314// 4. Force a theme inside a preview15<div className="theme-dark bg-background text-foreground">…</div>