FoundationsColor
Eight tokens, one palette, no exceptions.
The system is warm-neutral. Two surfaces, one ink, four supporting roles, two surfaces, two line tokens. The whole site lives in this set.
The eight core tokens
These are the only colors that should ever appear in a component. If you find yourself reaching for a value that isn't on this list, the right answer is to use the nearest token — not to add a new one.
Page surface
#F6F3EF
Body text, primary buttons, focus
#1A1816
Card surface (rarely used directly)
#FAF8F5
Inset surface, hover wash
#ECE8E2
Secondary text, labels, captions
#6F6860
Editorial accent, serif emphasis
#8A7D6E
Default 1 px borders
#DDD7CE
Errors, destructive actions
hsl(0 72% 51%)
Surfaces
Three surface tokens, used in this exact order: --background for the page, --surface-elevated for cards and dropdowns that should sit above the page, --surface-inset for recessed surfaces like code blocks and table rows. The depth is in the eye, not in the shadow.
Cards, dialogs, dropdowns
#FAF8F5
Code blocks, table rows, inset wells
#EDE9E3
Lines, not shadows
The system uses lines more than shadows. --line-subtle is the 8% ink divider, used inside cards and between table rows. --line-strong is the 16% ink divider, used to outline cards and to separate sections. Reach for a shadow only when a line won't do.
Inside-card dividers, table row borders
rgba(26,24,22,0.08)
Card borders, section dividers
rgba(26,24,22,0.16)
Color roles in components
How each token shows up in the live components.
| Role | Swatch | Where it appears | Token |
|---|---|---|---|
| Background | Body | --background | |
| Foreground | Body text, icon, button | --foreground | |
| Primary button | Button --primary | bg-foreground | |
| Secondary button | Button --secondary | bg-surface-elevated | |
| Muted text | Caption, helper | text-muted-foreground | |
| Destructive | Error, delete | text-destructive | |
| Accent | Serif italic emphasis | text-accent | |
| Focus ring | :focus-visible | ring-ring |
Dark mode, deliberately not shipped
The site does not have a dark mode. The decision is a trade-off, not a mistake: the warm-neutral palette is designed to read like printed paper, and a dark counterpart would change the editorial voice more than it would save battery.
Contrast
All foreground/background pairings clear WCAG AA at 4.5:1 for body text and 3:1 for large text. --muted-foreground on --background is the lowest pair at 5.84:1, used only for non-essential text (captions, helper text, metadata). It is never used for body copy.
| Foreground | Background | Ratio | Use |
|---|---|---|---|
--foreground | --background | 13.74:1 | Body text |
--foreground | --surface-elevated | 12.96:1 | Card text |
--muted-foreground | --background | 5.84:1 | Helper, caption, label |
--accent | --background | 4.62:1 | Editorial accent, italic emphasis |
--destructive | --background | 4.51:1 | Error text |
How to use these tokens
Use them through Tailwind's color utilities, which are bound to the@theme inline map in app/globals.css. Never hard-code a hex value in a component.
<div className="bg-background text-foreground">
<p className="text-muted-foreground">Helper text goes here</p>
<button className="bg-foreground text-background">Primary</button>
<button className="border border-border bg-surface-elevated text-foreground">
Secondary
</button>
</div>Why these values
The eight core tokens are warm-neutral because the site reads as editorial, not corporate. Cream and ink is the same pair the New York Times Magazine and Hermes have used for decades — it is well-trodden because it works.
--muted-foreground at #6F6860 is the lowest "safe" warm-gray in print; at 5.84:1 against cream it clears AA at every size, and it has enough chroma to feel like the same family as ink.
--accent is the one piece of color in the system. It is used sparingly, in serif italic emphasis, the way a designer would use a single colored ink on a printed page.