DESIGN_SYSTEM.md
Rama main · réplica de lectura del repositorio original.
# Lyriks — Design System
Reverse-engineered from the Step 01 mockup, codified as **Tailwind v4 design tokens** in
[`src/app.css`](src/app.css) and a small set of headless-ish **primitives** in
[`src/lib/ui/design-system/`](src/lib/ui/design-system/).
> **One rule:** components compose **tokens only** (`bg-surface`, `text-ink-900`, `rounded-card`,
> `shadow-card`…). No raw hex in components. Re-theming = editing `@theme` in `app.css`, nothing else.
---
## 1. Visual anatomy of the screen
```
┌──────────────────────────────────────────────────────────────────────┐
│ TOP BAR — full width, brand gradient, h-14 │ ← chrome
├───────────────┬────────────────────────────────────────────────────-─┤
│ SIDEBAR │ MAIN (canvas, scrolls) │
│ dark rail │ eyebrow · H1 · subtitle │
│ w-64 │ ┌── SectionCard (surface, rounded-card, shadow) ──┐ │
│ │ │ field label · control │ │
│ · project │ └─────────────────────────────────────────────────┘ │
│ · nav items │ …more section cards… │
│ · readiness │ │
│ ├────────────────────────────────────────────────────-─┤
│ │ BOTTOM BAR — surface, sticky: nav · coherence · save │ ← chrome
└───────────────┴────────────────────────────────────────────────────-─┘
```
Three regions: **chrome** (top bar + sidebar + bottom bar) frames a single scrolling **canvas** of
stacked **section cards**. Step 01 has 6 content sections (see the feature spec).
---
## 2. Color tokens
All colors live under `@theme` and generate `bg-*`, `text-*`, `border-*` utilities.
### Brand — violet→pink (identity, primary actions, active state)
Aligned to the the v3 mockup palette (the Tailwind violet/pink family).
| Token | Hex | Used for |
|---|---|---|
| `brand-50…300` | `#f5f3ff`→`#c4b5fd` | chips, soft fills, focus ring |
| `brand-400` | `#a78bfa` | soft accents on dark |
| `brand-500` | `#7c3aed` | **the violet** — gradient start, primary solid |
| `brand-600` | `#6d28d9` | hover |
| `brand-700` | `#5b21b6` | pressed |
| `magenta-500` | `#ec4899` | **the pink** — gradient end |
`bg-brand-gradient` → the signature **`linear-gradient(135deg, #7C3AED 0% → #EC4899 100%)`**
(via `brand-500 → magenta-500`). Applied to the **top bar**, the **active sidebar item**, the
**avatar**, and the **primary button** (which also carries `shadow-brand`, the violet glow).
`gradient-warm` (amber→pink) and `glass` (dark blur panel) mirror the mockup's secondary utilities.
### Accent — blue (selection affordance)
The Form-Factor tiles select with **blue** (`#3b82f6`, mockup blue-500), deliberately distinct from
brand violet so "selected" never reads as "primary action". `accent-50` fill + `accent-400` border
+ `accent-500` dot/text.
### Surfaces
| Token | Hex | Role |
|---|---|---|
| `canvas` | `#f8fafc` | app background (mockup lightmode) |
| `surface` | `#ffffff` | cards, top of bottom bar |
| `surface-sunken` | `#f1f5f9` | inset/secondary fields |
| `sidebar` | `#0b0b14` | left rail (mockup ink-900) |
| `sidebar-soft` | `#16161f` | hovered rail item (mockup ink-800) |
| `sidebar-line` | `#1f1f2c` | rail dividers (mockup ink-700) |
Ink text and lines use the **slate** ramp (`ink-900 #0f172a` … `ink-400 #94a3b8`,
`line #e2e8f0`), matching the mockup's lightmode content colors.
### Ink (text) — a 4-step ramp + 2 on-dark
`ink-900` headings · `ink-700` body · `ink-500` muted · `ink-400` labels/hints ·
`ink-on-dark` / `ink-on-dark-muted` for the sidebar.
### Lines
`line` (`#e9e9ee`) default borders · `line-strong` (`#d7d7df`) emphasized / hovered.
### Semantic (status) — each ships a `-500` ink and a `-50` soft background
| Token | Meaning in the UI |
|---|---|
| `success-500` / `success-50` | "Auto-saved", success criteria, readiness "Strong" |
| `warning-500` / `warning-50` | coherence "At risk", project label accent |
| `danger-500` / `danger-50` | failure criteria, coherence "Critical" |
**Score → color** mapping (coherence ring, readiness ring) is centralized in
[`scoreTone()`](src/lib/ui/design-system/tone.ts): `<34` danger · `34–66` warning · `≥67` success.
---
## 3. Typography
Font: **Inter** with a system fallback (`--font-sans`). Roles used across the screen:
| Role | Tailwind | Notes |
|---|---|---|
| Eyebrow (`STEP 01 · INITIALIZATION`) | `text-xs font-semibold uppercase tracking-[0.14em] text-brand-500` | |
| Page title (H1) | `text-3xl font-bold text-ink-900 tracking-tight` | |
| Subtitle | `text-sm text-ink-500` | |
| Field label | `text-[11px] font-semibold uppercase tracking-[0.12em] text-ink-400` | |
| Card value / section title | `text-lg font-semibold text-ink-900` | |
| Body | `text-sm text-ink-700` | |
| Help / hint | `text-xs text-ink-500` | |
---
## 4. Shape, elevation, spacing
- **Radii:** `rounded-field` (`0.625rem`) inputs & tiles · `rounded-card` (`1rem`) section cards ·
`rounded-pill` chips/buttons-as-pills.
- **Elevation:** `shadow-card` (cards: hairline + soft ambient) · `shadow-pop` (menus/dialogs).
- **Focus:** every interactive element gets `shadow-focus` (3px `brand-200` halo) via a base rule —
no per-component focus styling needed.
- **Spacing rhythm:** cards `p-6`→`p-7`, `gap-4` grids, `space-y-6` between section cards, content
column maxed at `max-w-5xl`.
---
## 5. Primitives (`src/lib/ui/design-system/`)
Small, composable Svelte 5 components. Each is a thin, typed wrapper over tokens.
| Component | Purpose |
|---|---|
| `Button.svelte` | `variant: primary \| ghost \| outline \| danger`, `size`, gradient primary |
| `Card.svelte` | surface + `rounded-card` + `shadow-card` + border |
| `SectionCard.svelte` | `Card` with eyebrow icon, title, subtitle slot + content |
| `Field.svelte` | label + control wrapper + optional counter/error |
| `TextInput.svelte` / `Textarea.svelte` | tokenized inputs with char counters |
| `Select.svelte` | native select styled as the mockup dropdown |
| `Chip.svelte` | pill; `tone: brand \| neutral \| success \| warning \| danger` |
| `TagInput.svelte` | add/remove string tags (pain points, criteria) |
| `ToggleTile.svelte` | multi-select tile w/ accent-blue selected state (form factors, sizes) |
| `ScoreRing.svelte` | SVG ring for coherence / readiness, colored by `scoreTone()` |
| `Icon.svelte` | inline SVG set used by chrome + sections |
Primitives are **presentation only** — no data fetching, no domain logic. They receive props and
emit callbacks, keeping the dependency arrow pointing inward (UI → application → domain).
---
## 6. How to extend / re-theme
1. **New color or scale:** add a `--color-*` token in `@theme`. Utilities are generated instantly.
2. **New status:** add `--color-x-500` + `--color-x-50`, extend `Chip` tone + `scoreTone()`.
3. **Brand refresh:** change `brand-*` / `magenta-*` — the gradient, buttons, active nav, focus ring,
and avatar all follow because they reference the tokens, not literals.
4. **New control:** build it from existing primitives/tokens; never reach for raw hex.