# Design Visual system for Quantum. Register: product. Personality: calm precision — ink on good paper, composed and legible. All colors OKLCH. ## Theme Scene: a couple reviews the month on a laptop at the kitchen table under evening lamplight; each also glances at balances on a phone in daylight. Both themes are first-class: **light is the canonical "paper statement" reading, dark is the evening companion**. Default follows `prefers-color-scheme`, with a `data-theme` override on `` persisted per user. Identity holds across themes: warm ink on warm paper (light), warm chalk on warm charcoal (dark). Never pure black or white. ## Color Strategy: **Restrained.** Tinted warm neutrals carry the interface; one spruce accent under 10% of any surface; semantic and chart colors appear only where data demands them. ### Neutrals (warm, hue ≈ 85) | Token | Light | Dark | | ----------------- | ----------------------- | ----------------------- | | `--bg` | `oklch(0.975 0.004 85)` | `oklch(0.19 0.006 85)` | | `--bg-raised` | `oklch(0.99 0.003 85)` | `oklch(0.225 0.007 85)` | | `--bg-sunken` | `oklch(0.955 0.005 85)` | `oklch(0.165 0.006 85)` | | `--text` | `oklch(0.245 0.012 85)` | `oklch(0.92 0.008 85)` | | `--text-muted` | `oklch(0.49 0.012 85)` | `oklch(0.70 0.01 85)` | | `--text-faint` | `oklch(0.62 0.01 85)` | `oklch(0.55 0.01 85)` | | `--border` | `oklch(0.90 0.006 85)` | `oklch(0.30 0.008 85)` | | `--border-strong` | `oklch(0.82 0.008 85)` | `oklch(0.38 0.01 85)` | ### Accent — spruce (hue ≈ 190, deliberately not money-green, not fintech navy) | Token | Light | Dark | | ---------------- | ----------------------- | ----------------------- | | `--accent` | `oklch(0.46 0.07 190)` | `oklch(0.80 0.08 185)` | | `--accent-hover` | `oklch(0.40 0.075 190)` | `oklch(0.85 0.075 185)` | | `--accent-bg` | `oklch(0.94 0.02 190)` | `oklch(0.27 0.03 190)` | | `--on-accent` | `oklch(0.98 0.005 190)` | `oklch(0.20 0.02 190)` | ### Semantic (paired with sign/shape, never hue alone) | Token | Light | Dark | Use | | ----------- | ---------------------- | ---------------------- | ----------------------------- | | `--pos` | `oklch(0.52 0.10 175)` | `oklch(0.78 0.11 170)` | income, inflow | | `--neg` | `oklch(0.53 0.13 30)` | `oklch(0.74 0.13 30)` | expense, outflow, destructive | | `--warn` | `oklch(0.60 0.11 75)` | `oklch(0.80 0.11 80)` | staleness, needs-attention | | `--warn-bg` | `oklch(0.95 0.03 85)` | `oklch(0.26 0.03 80)` | banner fills | Red (`--neg`) appears in chrome only when money or data is at risk; an expense figure in a table is plain ink, not red. ### Chart colors - `--chart-1` `oklch(0.55 0.13 180)` light / `oklch(0.65 0.12 190)` dark — the single-series mark color (net worth line). Validated ≥0.1 chroma and 3:1 contrast per surface. (`--chart-2…7` remain as spare series tokens.) - **Per-category palette** `--cat-0` … `--cat-11`: each category owns a stable palette index (`categories.color_index`, assigned at creation, never recomputed from position). Generated with [poline](https://github.com/meodai/poline) via `scripts/generate-category-palette.ts` — a closed-loop hue journey anchored at spruce/amber/plum, normalized into OKLCH L 0.54–0.62, C ≥ 0.10 so one set passes the lightness band, chroma floor, and 3:1 contrast on BOTH surfaces (no dark override). Neighboring slots are interleaved to maximize hue distance; charts additionally separate fills with 2px surface gaps and always carry a legend, so identity never rests on hue alone. Neutral (`--text-faint`) is reserved for "Other" and "Uncategorized" — never a category. ## Typography - **UI + numerals**: Inter Variable (bundled via `@fontsource-variable/inter`, self-hosted, no CDN). Fallback `system-ui`. - **Monospace** (DIDs, rule patterns, tokens): `ui-monospace, 'Cascadia Mono', Consolas, monospace`. - **Tabular figures are law**: any column of money or dates sets `font-variant-numeric: tabular-nums`. - Scale (1.25 ratio): 13 / 14 (body) / 16 / 20 / 25 / 31 px as `--text-xs/-sm/-md/-lg/-xl/-2xl`. Weights: 400 body, 500 emphasis & nav, 600 headings & figures. Line height 1.5 body, 1.2 headings. - Body measure ≤ 70ch. Money aligns right; descriptions align left. ## Spacing, shape, elevation - 4px base: `--space-1..8` = 4, 8, 12, 16, 24, 32, 48, 64. - Radius: `--radius-sm` 5px (inputs, chips), `--radius-md` 8px (surfaces, menus), full for provenance badges. - Elevation by border first: 1px `--border` + `--bg-raised`. Shadows only on overlays (menus, dialogs): `0 4px 16px oklch(0 0 0 / 0.10)` light, `/ 0.35` dark. No decorative shadows on static content. ## Motion 120ms (micro: hover, check, chip) and 180ms (panels, menus), both `cubic-bezier(0.22, 1, 0.36, 1)`. Nothing bounces, nothing floats, no layout property animation. `prefers-reduced-motion: reduce` collapses all to 0ms. ## App shell - **Desktop (≥880px)**: fixed left sidebar, 216px. Wordmark "Quantum" top; nav: Dashboard, Ledger, Reports, Accounts, Settings; footer shows sync status line ("Synced 6:02 AM") and the signed-in user's handle. Content area scrolls independently; reports/forms cap at 1040px, the ledger runs fluid. - **Mobile (<880px)**: bottom tab bar with the same five destinations; page title in a slim top bar. No hamburger menus. - Login is shell-less: a centered column on `--bg`, wordmark, one input, one button. ## Component conventions - **Provenance badge**: pill, `--bg-sunken` fill, 12px text: `⚙ rule` / `person's handle` / `↻ carried`. Click opens event history. - **Banners** (connection health): full-width strip under the top of content, `--warn-bg` fill, 1px `--warn` border (all four sides), plain sentence + one link out. No icons larger than the text. - **Tables**: row hover `--bg-sunken`, 1px hairline row separators, header 13px/500/`--text-muted`, uppercase avoided. - **Empty states**: one sentence + one action, set in `--text-muted`. No illustrations. - **Focus**: 2px `--accent` outline, 2px offset, on every interactive element.