# Design Visual system for the app0 web UI. Register: product (see PRODUCT.md). Palette: **gruvbox** (morhetz/gruvbox, MIT) — published, warm, proven for long reading, canonical dark+light pair. Restrained use: neutrals + ONE amber accent. All text pairings below verified WCAG AA (≥4.5:1). ## Theme switching - `data-theme="light|dark"` on ``; default follows `prefers-color-scheme`; manual toggle in the account menu, persisted in localStorage (`linji-theme`). No flash: inline script in index.html applies the stored choice before first paint. ## Color ### Dark (`data-theme="dark"`, default for system-dark) | Token | Gruvbox source | Value | Contrast on `--bg` | |---|---|---|---| | `--bg` | dark0 | `#282828` | — | | `--bg-raised` | dark1 | `#3c3836` | — | | `--bg-inset` | dark0_hard | `#1d2021` | — | | `--text` | light1 | `#ebdbb2` | 10.75 | | `--text-dim` | light4 (`#a89984`) on bg; light3 (`#bdae93`) on raised | `#a89984` | 5.30 / 5.32 | | `--accent` | bright yellow | `#fabd2f` | 8.69 | | `--accent-text` | bright yellow | `#fabd2f` | 8.69 | | `--on-accent` | dark0 | `#282828` | 8.69 | | `--danger` | bright red | `#fb4934` | 4.29 (large/bold only; body-danger uses `--text`) | ### Light (`data-theme="light"`) | Token | Gruvbox source | Value | Contrast on `--bg` | |---|---|---|---| | `--bg` | light0 | `#fbf1c7` | — | | `--bg-raised` | light0_hard | `#f9f5d7` | — | | `--bg-inset` | light0_soft | `#f2e5bc` | — | | `--text` | dark1 | `#3c3836` | 10.22 | | `--text-dim` | dark3 | `#665c54` | 5.74 | | `--accent` | bright yellow | `#fabd2f` | fill only | | `--accent-text` | faded orange | `#af3a03` | 5.40 | | `--on-accent` | dark1 | `#3c3836` | 6.84 | | `--danger` | neutral red | `#cc241d` | 4.82 | Rules: `--accent` fills primary buttons (`--on-accent` label) and selection; text-colored accent always `--accent-text`. Danger as small text only in light; in dark use bold or larger size (4.29 = AA-large). Borders: 1px `color-mix(in oklab, var(--text) 14%, transparent)`. No shadow+border combos; shadows optional ≤8px blur. ## Typography - One family, all sans: `system-ui, -apple-system, "PingFang SC", "Microsoft YaHei", "Noto Sans CJK SC", sans-serif`. - Fixed rem scale (ratio ~1.2): 0.78 / 0.92 / 1 / 1.2 / 1.44. Base 16px; `line-height: 1.65` for message text, 1.4 for chrome. - Thread titles: weight 600, same family. No display fonts. ## Radius & spacing - `--radius: 10px` panels, 8px buttons/inputs; concentric (inner = outer − padding). Nothing >12px. - 4px spacing grid; 0.9rem between stream messages; dense chrome. ## Components - **Buttons**: primary (accent fill), ghost (transparent, dim → text on hover), danger variants. 8px radius, `active { scale: 0.96 }`, `:focus-visible` outline `--accent`. - **Dialogs**: native `` (Add space, Invite, Members, Account menu actions); `::backdrop` 60% dim. No custom overlay machinery, escapes overflow clipping for free. - **Skeletons**: shimmering `--bg-inset` rows while spaces/stream load; never mid-content spinners. - **Empty states**: one sentence + one action. ## Layout - Desktop: 240px sidebar (spaces, Add space, account) + stream column max 52rem. - Mobile ≤700px: sidebar → top bar with slide-over; composer sticky bottom; 44px touch targets. ## Motion - 150–200ms ease-out hover/press/dialog; dialog fade+rise 12px. - No choreography on SSE stream refresh — silent state. - `@media (prefers-reduced-motion: reduce)`: instant. ## Register bans (product) No gradient text, glassmorphism, eyebrow kickers, side-stripe borders, >12px radii on surfaces, card grids, hero metrics.