diff --git a/docs/superpowers/specs/2026-07-12-frontend-design-system.md b/docs/superpowers/specs/2026-07-12-frontend-design-system.md new file mode 100644 index 0000000..4f1bd66 --- /dev/null +++ b/docs/superpowers/specs/2026-07-12-frontend-design-system.md @@ -0,0 +1,128 @@ +# Lyra frontend: the "Pressing Plant" design system + +**Date:** 2026-07-12 +**Status:** approved (design comp signed off), implementing +**Comp:** https://claude.ai/code/artifact/af6f9654-619d-4245-b3dd-602a6427934a + +## Intent + +Give Lyra a real visual identity instead of unstyled raw HTML. Direction: +**Liner Notes / "Pressing Plant"** — the app presented as *a record label's internal +catalog for an audience of one*. The acquisition pipeline reads as a pressing plant. +The metaphor lives in the **chrome only** (masthead, section names, catalog/matrix +numbers, deadwax etch styling); **functional labels stay literal and legible** +(Downloading, Verifying, Needs attention) so nothing is obscured. Single-user homelab +tool → license to be bold. + +This is a **tool, not a document**: information design first (summary before detail, +state encoded as form — severity stripe + chip — not just prose), editorial typography +second. + +## Design language (the reusable reference) + +### Color — deliberately off the AI-editorial cliché (no cream, no vermilion) +Two-color-print feel: manila/kraft paper + warm ink + one bold **deep spruce** accent. +Tokens are CSS custom properties on `:root`; both themes get equal care. Semantic status +colors are **separate from the accent**. + +| Token | Day (light) | Night (dark) | Use | +|---|---|---|---| +| `--paper` | `#E7DFCC` | `#14130F` | ground | +| `--paper-2` | `#DED5BE` | `#1D1B16` | recessed panel | +| `--ink` | `#1B1A17` | `#E9E1CD` | primary text | +| `--graphite` | `#726D5F` | `#938C7B` | secondary text / mono meta | +| `--rule` | `rgba(ink,.16)` | `rgba(ink,.16)` | hairlines | +| `--rule-2` | `rgba(ink,.30)` | `rgba(ink,.28)` | stronger rules | +| `--accent` | `#1F5138` | `#5BB487` | the one bold move; links, active nav, "pressed" | +| `--accent-ink` | `#F3EEDF` | `#10120F` | text on accent | +| `--live` (semantic) | `#9A6B1E` amber | `#D2A24E` | work in progress | +| `--alert` (semantic) | `#99392B` clay | `#D8695A` | needs attention (errors only) | + +Theme mechanics: define tokens on `:root`; redefine under +`@media (prefers-color-scheme: dark)`; **also** redefine under +`:root[data-theme="light"]` and `:root[data-theme="dark"]` so an explicit in-app toggle +wins in both directions. Style components through tokens only, never inside the media +query. Faint paper grain via a tiled radial-gradient. **Sharp corners** (radius 0–2px) — +letterpress/label feel, and it dodges the `rounded-lg` cliché. + +### Type — serif/mono tension is the concept +- **Display + editorial:** **Fraunces** (OFL variable serif; soft, optical, warm), + self-hosted via `next/font/local` (woff2 vendored under `web/src/fonts/`, subset to + latin). The comp used a Palatino system stack as a stand-in; the real app ships Fraunces. +- **Machine voice (all metadata, labels, data, progress):** a system **mono** stack + (`ui-monospace, "SF Mono", "Cascadia Code", Menlo, Consolas, monospace`) — zero weight, + reliable. Uppercase mono labels get `letter-spacing: 0.12–0.22em`. +- Scale (rem): masthead `clamp(2.6, 6vw, 3.7)`, job title `1.42`, tile value `2.5`, + body `1.0`, section head `0.78` mono, meta/labels `0.62–0.72` mono. `text-wrap: balance` + on headings; running text ~65ch; `font-variant-numeric: tabular-nums` on all aligned digits. + +### Motifs +Masthead wordmark + tagline + live worker dot + "Pressing № NNNN" catalog mark; +contents-bar nav (hairline top/bottom, active item underlined in accent); summary tiles +(hairline grid); dept section headers (mono small-caps + rule fill + count); tracklist +job rows with a left **severity stripe**; mono **status chip**; thin ruled **progress bar** +(indeterminate variant for search); **deadwax matrix** etch line for pressed items +(`Lyra·A0430 — FLAC 24/48`); colophon footer. + +### Motion (restrained) +Live-dot pulse; indeterminate progress slide; hover underlines. All gated by +`@media (prefers-reduced-motion: reduce)`. No scattered effects. + +## Architecture + +Hand-rolled CSS, no framework (matches the lightweight Next 15 / React 19 stack). + +- **`web/src/app/globals.css`** (new) — token definitions (both themes), base/reset, + paper grain, focus-visible, reduced-motion. Imported once in the root layout. +- **`web/src/app/design.css`** (new, or co-located module) — the component classes + (masthead, contents nav, tiles, dept header, job row, chip, bar, pressed list, buttons, + inputs). Plain global classes keep it simple and shared across pages. +- **Fonts:** `web/src/fonts/` vendored Fraunces woff2 + `next/font/local` wiring, exposed + as a CSS variable on `
`. +- **App shell:** `web/src/app/layout.tsx` gains the shared chrome — a `