Files
SimpleFinanceDash/.planning/phases/05-design-system-token-rework/05-UI-SPEC.md

236 lines
10 KiB
Markdown

---
phase: 5
slug: design-system-token-rework
status: draft
shadcn_initialized: true
preset: new-york / neutral / lucide
created: 2026-04-20
---
# Phase 5 — UI Design Contract
> Visual and interaction contract for Phase 5: Design System Token Rework.
> Generated by gsd-ui-researcher, verified by gsd-ui-checker.
>
> This phase is a pure token and spacing rework — no new components, no new features.
> Every entry in this contract describes what must be TRUE after the change, not before.
---
## Design System
| Property | Value | Source |
|----------|-------|--------|
| Tool | shadcn/ui | components.json |
| Style | new-york | components.json |
| Preset | neutral base, cssVariables: true | components.json |
| Component library | Radix UI (via shadcn) | components.json |
| Icon library | lucide-react | components.json |
| Font | Inter (--font-sans) | src/index.css |
---
## Spacing Scale
Declared values (all multiples of 4):
| Token | px Value | Tailwind Class | Usage |
|-------|----------|----------------|-------|
| xs | 4px | gap-1 / p-1 | Icon gaps, inline tight spacing |
| sm | 8px | gap-2 / p-2 | Compact inline elements, badge padding |
| md | 16px | gap-4 / p-4 | Default inline element spacing |
| lg | 24px | gap-6 / p-6 | Card internal padding (upgraded from p-4) |
| xl | 32px | gap-8 | Section gaps between cards and sections (upgraded from gap-6) |
| 2xl | 48px | gap-12 | Major section breaks, page-level vertical rhythm |
| 3xl | 64px | py-16 | Auth page vertical centering, hero areas |
**Phase 5 spacing changes (from CONTEXT.md):**
- Card internal padding: `p-4``p-6` across all 9 pages
- Section gaps: `gap-4``gap-6`, `gap-6``gap-8` across all pages
- Page header bottom margin: standardize to `mb-6` everywhere
- Section-to-section gap: standardize to `gap-8`
Exceptions: none — 8-point scale applies without exception.
---
## Typography
| Role | Size | Tailwind | Weight | Weight Class | Line Height | Usage |
|------|------|----------|--------|--------------|-------------|-------|
| Caption | 12px | text-xs | 400 | font-normal | 1.5 | Subtitles, secondary metadata |
| Body / Label | 14px | text-sm | 500 | font-medium | 1.5 | Table cells, form labels, card labels, stat subtitles |
| Base | 16px | text-base | 500 | font-medium | 1.5 | Card titles (e.g. chart section headings) |
| Heading | 24px | text-2xl | 600 | font-semibold | 1.2 | Page titles (PageShell h1), auth card titles, template names |
Source: Existing usage in PageShell, StatCard, DashboardPage, LoginPage, RegisterPage confirmed these four sizes as the complete in-use set.
Weights used: exactly 2 — `font-medium` (500) for body/data, `font-semibold` (600) for headings. The rare `font-bold` (700) occurrences in StatCard value display are reclassified as `font-semibold` for consistency.
---
## Color
### Base UI Tokens (post-rework values)
| Role | OKLCH Value | Usage |
|------|-------------|-------|
| Background (dominant, 60%) | oklch(0.98 0.01 260) | Page background — chroma lifted 0.005→0.01 for subtle warmth |
| Card / Popover (secondary, 30%) | oklch(1 0 0) | Cards, modals, popovers, sidebar surface |
| Sidebar | oklch(0.97 0.008 260) | Sidebar background — no change |
| Primary accent (10%) | oklch(0.55 0.15 260) | Active nav items, primary buttons, focus rings |
| Secondary / Muted | oklch(0.93 0.02 260) | Secondary buttons, muted chip backgrounds |
| Border / Input | oklch(0.88 0.01 260) | All borders and input outlines |
| Destructive | oklch(0.6 0.2 25) | Delete actions, error alerts only |
Accent reserved for: primary action buttons, active sidebar navigation item, focus ring outlines, primary CTA buttons. No other elements may use the primary OKLCH(0.55 0.15 260) value.
### Category Text Colors (WCAG 4.5:1 contrast on white — no change to lightness/chroma)
| Token | OKLCH Value | Hue |
|-------|-------------|-----|
| --color-income | oklch(0.55 0.17 155) | Green |
| --color-bill | oklch(0.55 0.17 25) | Orange-red |
| --color-variable-expense | oklch(0.58 0.16 50) | Amber |
| --color-debt | oklch(0.52 0.18 355) | Red |
| --color-saving | oklch(0.55 0.16 220) | Blue |
| --color-investment | oklch(0.55 0.16 285) | Violet |
### Category Fill Colors (post-rework — chroma raised to 0.22+)
These replace the current fill tokens (C=0.18-0.20). Exact values are at Claude's discretion per CONTEXT.md as long as chroma >= 0.22 and the fills remain visually distinct from each other.
| Token | Target OKLCH | Constraint |
|-------|--------------|------------|
| --color-income-fill | oklch(0.72 0.22 155) | C >= 0.22, L ~0.70-0.75 |
| --color-bill-fill | oklch(0.70 0.22 25) | C >= 0.22, L ~0.68-0.73 |
| --color-variable-expense-fill | oklch(0.74 0.22 50) | C >= 0.22, L ~0.70-0.76 |
| --color-debt-fill | oklch(0.66 0.23 355) | C >= 0.22, L ~0.64-0.70 |
| --color-saving-fill | oklch(0.72 0.22 220) | C >= 0.22, L ~0.70-0.75 |
| --color-investment-fill | oklch(0.68 0.22 285) | C >= 0.22, L ~0.65-0.72 |
### Chart Colors (post-rework — aligned to fill tokens)
The `--color-chart-1` through `--color-chart-5` variables are REMOVED. Chart components reference `--color-*-fill` tokens directly. This eliminates the duplicate color system.
| Removed | Replaced by |
|---------|-------------|
| --color-chart-1 | --color-income-fill |
| --color-chart-2 | --color-bill-fill |
| --color-chart-3 | --color-variable-expense-fill |
| --color-chart-4 | --color-debt-fill |
| --color-chart-5 | --color-saving-fill |
### Corner Radius
| Token | Current Value | Post-Rework Value | Effect |
|-------|--------------|-------------------|--------|
| --radius | 0.625rem (10px) | 0rem (0px) | All shadcn components become sharp-cornered |
Third-party overrides required (applied via CSS selectors in src/index.css):
- Recharts bar elements: force `rx="0" ry="0"` or CSS `border-radius: 0`
- Sonner toast container: override `.sonner-toast` border-radius to 0
---
## Copywriting Contract
Phase 5 is a pure visual rework — no new user-facing copy is introduced. The following existing copy elements remain unchanged and are documented here as the confirmed contract.
| Element | Copy | Notes |
|---------|------|-------|
| Primary CTA (Budget List) | "New Budget" | Existing — unchanged |
| Primary CTA (Template) | "Add item" | Existing — unchanged |
| Primary CTA (Categories) | "New Category" | Existing — unchanged |
| Empty state (Dashboard) | Translation key: `dashboard.noBudgetForMonth` | Existing — no copy changes this phase |
| Error state (auth forms) | Translation key: `auth.error` + specific message | Existing — no copy changes this phase |
| Destructive actions | None introduced in this phase | Token rework only |
No new destructive actions are introduced. No new confirmation dialogs. No new empty states.
---
## Component Inventory
Components affected by token changes (no code changes required — token cascade handles it):
| Component | Location | Rounding Source | Change Required |
|-----------|----------|-----------------|-----------------|
| Button | src/components/ui/button.tsx | --radius token | Automatic via --radius: 0 |
| Card | src/components/ui/card.tsx | --radius token | Automatic; padding class updated to p-6 |
| Input | src/components/ui/input.tsx | --radius token | Automatic via --radius: 0 |
| Badge | src/components/ui/badge.tsx | --radius token | Automatic via --radius: 0 |
| Select | src/components/ui/select.tsx | --radius token | Automatic via --radius: 0 |
| Sheet | src/components/ui/sheet.tsx | --radius token | Automatic via --radius: 0 |
| Dialog | src/components/ui/dialog.tsx | --radius token | Automatic via --radius: 0 |
| Popover | src/components/ui/popover.tsx | --radius token | Automatic via --radius: 0 |
| Sidebar | src/components/ui/sidebar.tsx | --radius token | Automatic via --radius: 0 |
| Dropdown Menu | src/components/ui/dropdown-menu.tsx | --radius token | Automatic via --radius: 0 |
| Recharts bars | SpendBarChart, IncomeBarChart | SVG rx/ry attrs | Explicit CSS override needed |
| Sonner toasts | src/components/ui/sonner.tsx | Sonner inline styles | CSS selector override needed |
| Category swatches | CategoriesPage, CategorySection | Hardcoded rounded-* | Audit and remove rounded-* classes |
| Budget progress bars | BudgetDetailPage | Hardcoded rounded-* | Audit and remove rounded-* classes |
Pages to audit for inline `rounded-*` classes (must be zero after this phase):
1. DashboardPage — CategorySection swatches, StatCard
2. BudgetListPage — budget item rows
3. BudgetDetailPage — progress bars, budget row items
4. TemplatePage — template item rows, category group headers
5. CategoriesPage — category color swatches
6. QuickAddPage — picker items
7. SettingsPage — form elements
8. LoginPage — auth card
9. RegisterPage — auth card
---
## Registry Safety
| Registry | Blocks Used | Safety Gate |
|----------|-------------|-------------|
| shadcn official (new-york) | button, card, badge, input, label, select, sheet, dialog, popover, sidebar, dropdown-menu, separator, skeleton, table, tooltip, sonner, chart, collapsible | not required |
| Third-party | none | not applicable |
No third-party registries. No vetting gate required.
---
## Interaction Contract
Phase 5 introduces no new interaction patterns. Existing interactions are preserved. The following are confirmed unchanged:
- Collapsible sections: 200ms ease-out open/close animation (--animate-collapsible-open/close) — no change
- Sidebar navigation: active state uses primary color — no change to behavior
- Form validation: error states use `--color-destructive` — no change
- Chart tooltips: Recharts default — style override via chart.tsx config only
---
## Visual Regression Checklist
The executor must perform a manual visual pass after all token changes confirming:
- [ ] No pill buttons visible on any of the 9 pages
- [ ] No rounded cards visible on any of the 9 pages
- [ ] No rounded inputs visible on any of the 9 pages
- [ ] Category fill colors are visibly colorful against white (not grey-tinted)
- [ ] Category text colors still appear dark/readable (not washed out by chroma increase)
- [ ] Section gaps feel generous — no visual crowding between cards
- [ ] Card internal padding feels spacious — content not flush against card edges
- [ ] Page headers have consistent bottom margin before first content section
- [ ] Recharts bars are square-ended (no rounded caps)
- [ ] Sonner toasts have sharp corners
---
## Checker Sign-Off
- [ ] Dimension 1 Copywriting: PASS
- [ ] Dimension 2 Visuals: PASS
- [ ] Dimension 3 Color: PASS
- [ ] Dimension 4 Typography: PASS
- [ ] Dimension 5 Spacing: PASS
- [ ] Dimension 6 Registry Safety: PASS
**Approval:** pending