Color
Roles, not a mood board. Every color has a job. Brand teal is a fill, not body text.
Signal #1AA68A is how a control is filled. It is not how a sentence is colored. Foundations split fill, text, and focus because the brand teal fails both 4.5:1 and 3:1 on paper.
Roles
| Role | Job |
|---|---|
| Canvas / surface / raised / inset | Where the instrument sits. Elevation is a surface token, not a mood. |
| Inverse | The opposite canvas. Buttons that must win, skip links. |
| Foreground / muted / subtle / disabled | Reading, secondary reading, inactive UI. |
| Border / border-strong | Hairlines. Solid, never alpha. |
| Signal fill | The one saturated fill on a surface. Action background, selected mark, large accent. |
Signal text (--fg-signal) | Links, signal words, the paper focus ring. |
| Status fill + status text | Critical, caution, positive, info. Fill for dots and large UI; text pair for words. |
| Action / action-fg | Primary control: signal fill, ink on the fill. Never white on signal. |
| Focus | 2px ring. Paper uses --fg-signal. Ink uses luminous signal. |
One saturated fill per surface. Never mix paper and ink tokens on one surface.
Accessibility
These ratios were measured. Do not round them into a different story.
| Pair | Ratio | Level |
|---|---|---|
--fg #0E141B on --bg-canvas paper #F6F3EE | 16.7:1 | AAA |
--fg-muted #5A6370 on paper | 5.5:1 | AA |
Signal fill #1AA68A on paper | 2.76:1 | FAIL text and FAIL non-text 3:1. Do not use as text or as the sole focus ring on paper. |
--fg-signal #0F6E5C on paper | 5.57:1 | AA — links, signal words, paper focus ring |
Signal luminous #3EE0C2 on ink #0E141B | 11.2:1 | AAA — fill + text + focus on ink |
Action: ink on signal fill #1AA68A | 6.05:1 | AA. Never white on signal (3.06, large-only). |
--fg-critical #B42318 on paper | 5.94:1 | AA. Fill #D64541 on paper is 3.96 (UI / large only, not small text). |
--fg-caution #8A5A00 on paper | 5.36:1 | AA. Fill on paper is #B57812 (3.35 UI), not brand #C4841D (2.85, FAIL even UI). |
--fg-positive #0F6B4C on paper | 5.88:1 | AA. Fill #1F8A65 is 3.89 UI / large only. |
Dark status text on ink: critical #E89B97 | 8.4:1 | AA |
Dark status text on ink: caution #E8C27A | 11.0:1 | AA |
Dark status text on ink: positive #8FCBB3 | 10.0:1 | AA |
Dark status text on ink: info #7EC8E3 | 9.9:1 | AA |
--fg-muted #9AA3AD on ink | 7.24:1 | AA |
Check the pair, not the swatch. A color that passes on ink can fail on paper.
--fg-disabled #9AA3AD on paper is inactive UI (WCAG 1.4.3 exempt). Keep it visible; do not fade it into the canvas.
Semantic tokens — paper
Default theme. Light canvas, ink reading, teal as a fill.
| Token | Paper | Role |
|---|---|---|
--bg-canvas | #F6F3EE | Page canvas |
--bg-surface | #FFFCF7 | Panel |
--bg-raised | #FFFCF7 | Sticky, dropdown |
--bg-inset | #EBE6DE | Recessed well |
--bg-inverse | #0E141B | Inverse fill |
--fg | #0E141B | Body text |
--fg-muted | #5A6370 | Secondary text |
--fg-subtle | #5A6370 | Tertiary; do not drop below 4.5:1 |
--fg-inverse | #F6F3EE | Text on inverse |
--fg-disabled | #9AA3AD | Inactive UI |
--border | #D6D0C7 | Hairline |
--border-strong | #B7B0A4 | Strong hairline |
--signal | #1AA68A | Fill only |
--fg-signal | #0F6E5C | Text, links, focus |
--signal-muted | #D5EFE8 | Quiet signal well |
--critical | #D64541 | Fill / dot |
--fg-critical | #B42318 | Critical words |
--critical-muted | #F8D6D4 | Quiet critical well |
--caution | #B57812 | Fill / dot (darkened vs brand #C4841D so UI hits 3:1) |
--fg-caution | #8A5A00 | Caution words |
--caution-muted | #F3E4C4 | Quiet caution well |
--positive | #1F8A65 | Fill / dot |
--fg-positive | #0F6B4C | Positive words |
--positive-muted | #D5EBE3 | Quiet positive well |
--info | #155E75 | Fill / dot |
--fg-info | #155E75 | Info words |
--info-muted | #D4EAF1 | Quiet info well |
--action | var(--signal) | Primary fill |
--action-fg | var(--fg) | Ink on teal |
--focus | var(--fg-signal) | 2px ring |
Semantic tokens — ink
Dark canvas. Elevation is a lighter surface, not a drop shadow. Luminous signal is fill, text, and focus.
| Token | Ink | Role |
|---|---|---|
--bg-canvas | #0E141B | Page canvas |
--bg-surface | #161E27 | Panel |
--bg-raised | #1C2630 | Sticky, dropdown |
--bg-inset | #121922 | Recessed well |
--bg-inverse | #F6F3EE | Inverse fill |
--fg | #F6F3EE | Body text |
--fg-muted | #9AA3AD | Secondary text (7.24:1) |
--fg-inverse | #0E141B | Text on inverse |
--fg-disabled | #6B7480 | Inactive UI |
--border | #2A333C | Hairline |
--border-strong | #3D4854 | Strong hairline |
--signal | #3EE0C2 | Fill |
--fg-signal | #3EE0C2 | Text, links, focus |
--signal-muted | #0F2A26 | Quiet signal well |
--critical | #D64541 | Fill / dot |
--fg-critical | #E89B97 | Critical words (8.4:1) |
--critical-muted | #3A1A1A | Quiet critical well |
--caution | #E8C27A | Fill / dot |
--fg-caution | #E8C27A | Caution words (11.0:1) |
--caution-muted | #33260E | Quiet caution well |
--positive | #1F8A65 | Fill / dot |
--fg-positive | #8FCBB3 | Positive words (10.0:1) |
--positive-muted | #0F2A22 | Quiet positive well |
--info | #7EC8E3 | Fill / dot |
--fg-info | #7EC8E3 | Info words (9.9:1) |
--info-muted | #0E2430 | Quiet info well |
--action | var(--signal) | Primary fill |
--action-fg | #0E141B | Ink on luminous teal |
--focus | var(--fg-signal) | 2px ring |
Dark mode
Follow prefers-color-scheme. The Paper / Ink toggle overrides.
- Elevation on ink is a lighter surface, not a drop shadow. Dark-on-dark shadow reads as dirt.
- Never mix themes on one surface. A paper panel on an ink canvas is a different product.
- One saturated fill per surface. Status color is a word + icon + hue, not a second fill competing with Signal.
Do / Don't
| Do | Don't |
|---|---|
| One filled action per region. | Type set in fill colors (#1AA68A as body, #D64541 as small text). |
Links and focus use --fg-signal on paper. | Color-only status. A delta is icon + word + color. |
Pills = muted well + --fg-* text. | Caution behind long copy. The fill is a dot, not a paragraph background. |
| Check the pair, not the swatch. | Signal-on-signal. Teal text on a teal well. |
| Ink on signal for action labels (6.05:1). | White on signal (3.06, large-only). |
Validation
We do not claim guaranteed compliance. Tokens make the floor constructible; they do not ship the receipt.
Validate with axe, Lighthouse, and real operators — both themes, keyboard-only, and under prefers-reduced-motion. See Accessibility.
Live tokens
These swatches use CSS variables. The Paper / Ink toggle in the header recolors them.
Dual preview below is independent of the toggle — both themes at once.
Paper
Ink
Contrast pairs
Measured ratios. Do not round them into a different story. Check the pair, not the swatch.
| Pair | Sample | Ratio |
|---|---|---|
| fg on paper | #0E141B on #F6F3EE | 16.7:1 AAA |
| fg-muted on paper | #5A6370 on paper | 5.5:1 AA |
| signal fill on paper | #1AA68A on paper | 2.76:1 FAIL text and FAIL 3:1 |
| fg-signal on paper | #0F6E5C on paper | 5.57:1 AA |
| signal luminous on ink | #3EE0C2 on #0E141B | 11.2:1 AAA |
| action: ink on signal | ink on #1AA68A | 6.05:1 AA |
| white on signal | white on #1AA68A | 3.06:1 large-only |
| fg-critical on paper | #B42318 on paper | 5.94:1 AA |
| critical fill on paper | #D64541 on paper | 3.96:1 UI / large only |
| fg-caution on paper | #8A5A00 on paper | 5.36:1 AA |
| caution fill #B57812 | #B57812 on paper | 3.35:1 UI |
| caution brand #C4841D | #C4841D on paper | 2.85:1 FAIL even UI |
| fg-positive on paper | #0F6B4C on paper | 5.88:1 AA |
| positive fill on paper | #1F8A65 on paper | 3.89:1 UI / large only |
| fg-muted on ink | #9AA3AD on ink | 7.24:1 AA |
| critical text on ink | #E89B97 on ink | 8.4:1 AA |
| caution text on ink | #E8C27A on ink | 11.0:1 AA |
| positive text on ink | #8FCBB3 on ink | 10.0:1 AA |
| info text on ink | #7EC8E3 on ink | 9.9:1 AA |