diff --git a/CLAUDE.md b/CLAUDE.md
index 1abb98e..d16e96d 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -409,6 +409,9 @@ Colors are defined as raw CSS custom properties in `:root` (light) and `[data-th
| `--accent-hover` | `#ea580c` | `#f97316` | `bg-accent-hover`, `hover:bg-accent-hover` |
| `--accent-subtle` | `#fff7ed` (orange-50) | `rgba(234,88,12,0.1)` | `bg-accent-subtle` |
| `--accent-text` | `#ffffff` | `#ffffff` | `text-accent-text` |
+| `--text` | `#1c1917` (stone-900) | `#e7e5e4` (stone-200) | `text-text` |
+| `--text-secondary` | `#57534e` (stone-600) | `#d6d3d1` (stone-300) | `text-text-secondary` |
+| `--text-muted` | `#78716c` (stone-500) | `#a8a29e` (stone-400) | `text-text-muted` |
A base layer rule sets the default border color so bare `border` / `divide-y` classes use the theme:
@@ -420,7 +423,7 @@ A base layer rule sets the default border color so bare `border` / `divide-y` cl
}
```
-Neutral text colors (`text-stone-800`, `text-stone-500`, etc.) are used directly — they are not tokenised since they're static in both themes.
+Neutral text colors use the tokenised utilities (`text-text`, `text-text-secondary`, `text-text-muted`) which adapt automatically between light and dark themes. Do not use hardcoded `text-stone-*` classes for neutral text — always use the token-based classes.
#### Dark Mode
@@ -459,11 +462,11 @@ Extra utilities (e.g., `w-28 justify-center whitespace-nowrap`) can be added alo
| Level | Classes | Use |
|-------|---------|-----|
| Page title | `text-3xl font-semibold` | Top-level `
` on each page |
-| Section title | `text-lg font-semibold text-stone-800` | `
` / `
` for form card titles |
-| Subsection title | `text-base font-semibold text-stone-800` | `
` within cards (e.g. "Confirm cafe details") |
-| Form section label | `text-xs font-semibold text-stone-500 uppercase tracking-wide` | `
` grouping related fields (e.g. "Coffee", "Grinder", "Water") |
-| Body / description | `text-sm text-stone-600` | Paragraph text below headings |
-| Muted secondary | `text-xs text-stone-500` | Subtext in option lists, metadata |
+| Section title | `text-lg font-semibold text-text` | `
` / `
` for form card titles |
+| Subsection title | `text-base font-semibold text-text` | `
` within cards (e.g. "Confirm cafe details") |
+| Form section label | `text-xs font-semibold text-text-muted uppercase tracking-wide` | `
` grouping related fields (e.g. "Coffee", "Grinder", "Water") |
+| Body / description | `text-sm text-text-secondary` | Paragraph text below headings |
+| Muted secondary | `text-xs text-text-muted` | Subtext in option lists, metadata |
| Accent title | `text-2xl font-semibold text-accent` | Login / register page headers |
Page headers follow a consistent structure — title + constrained description:
@@ -471,7 +474,7 @@ Page headers follow a consistent structure — title + constrained description:
```html
Page Title
-
Short description of what the page does.
+
Short description of what the page does.
```
@@ -485,17 +488,17 @@ Use `w-full` for full-width CTAs. Use `py-3` for larger touch targets on final s
**Secondary** — cancel, back, alternative actions:
```html
-