# Mangalord design system One screen. This is the contract the implementation reads — every value in code comes from a token defined here. ## Tokens All tokens live on `:root` in [frontend/src/lib/styles/tokens.css](../frontend/src/lib/styles/tokens.css). Dark values override under `:root[data-theme="dark"]`. Components consume tokens only — no raw hex, no raw px in scoped styles. ### Color Semantic, not literal. Tested with [WebAIM contrast checker](https://webaim.org/resources/contrastchecker/). | Token | Light | Dark | Use | |---|---|---|---| | `--bg` | `#ffffff` | `#0f1115` | page background | | `--surface` | `#f6f7f9` | `#161a21` | cards, inputs, drop zones | | `--surface-elevated` | `#ffffff` | `#1c2129` | hovered cards, focused inputs | | `--border` | `#e3e5ea` | `#2a2f37` | hairlines | | `--border-strong` | `#c8ccd4` | `#3a414d` | input borders | | `--text` | `#16181d` | `#e8eaed` | body | | `--text-muted` | `#5b6168` | `#9aa0a6` | meta, hints | | `--primary` | `#2563eb` | `#60a5fa` | links, primary button, focus | | `--primary-hover` | `#1d4ed8` | `#3b82f6` | primary hover | | `--primary-contrast` | `#ffffff` | `#0f1115` | text on primary fill | | `--danger` | `#b00020` | `#f87171` | errors, destructive | | `--danger-soft-bg` | `#fff5f5` | `#3a1620` | invalid page row | | `--success` | `#0a7d2c` | `#4ade80` | success text | | `--warning-soft-bg` | `#fff5d6` | `#3a2e10` | active bookmark fill | | `--warning-border` | `#d6a800` | `#a37800` | active bookmark border | | `--focus-ring` | `#2563eb` | `#60a5fa` | `:focus-visible` outline | | `--focus-ring-soft` | `rgb(37 99 235 / 0.25)` | `rgb(96 165 250 / 0.3)` | input focus halo (`box-shadow`) | | `--primary-soft-bg` | `rgb(37 99 235 / 0.08)` | `rgb(96 165 250 / 0.12)` | drop-zone drag-over, selected theme radio | Verified ratios (light theme, against `--bg`): `--text` 16.5:1 (AAA), `--text-muted` 6.4:1 (AA), `--primary` 5.2:1 (AA), `--danger` 7.6:1 (AAA). Dark theme: `--text` 13.8:1, `--text-muted` 4.7:1, `--primary` 5.3:1, `--danger` 5.1:1. All interactive elements clear 4.5:1; large UI clears 3:1. ### Typography System stack, zero FOUT cost: `system-ui, -apple-system, "Segoe UI", Roboto, sans-serif`. Monospace stack (for code-like elements, currently unused but reserved): `ui-monospace, "SF Mono", Menlo, monospace`. | Token | Value | Where | |---|---|---| | `--font-xs` | `0.75rem` / `1.4` | micro-meta (file sizes, "Bookmarked {date}") | | `--font-sm` | `0.875rem` / `1.5` | card meta, hints, inline errors | | `--font-base` | `1rem` / `1.55` | body, inputs, buttons | | `--font-lg` | `1.125rem` / `1.45` | card titles, h3 | | `--font-xl` | `1.5rem` / `1.3` | h2 | | `--font-2xl` | `2rem` / `1.2` | h1 page titles | Weights: `--weight-regular: 400`, `--weight-medium: 500`, `--weight-semibold: 600`. Headings use semibold. Body and inputs use regular. Card titles use semibold at `--font-sm` or `--font-lg`. ### Spacing One ladder (4 px base): `--space-1 0.25rem`, `--space-2 0.5rem`, `--space-3 0.75rem`, `--space-4 1rem`, `--space-5 1.25rem`, `--space-6 1.5rem`, `--space-8 2rem`. ### Radii, shadows, transitions `--radius-sm 4px`, `--radius-md 6px`, `--radius-lg 10px`, `--radius-pill 999px`. `--shadow-sm` (light: `0 1px 2px rgb(0 0 0 / 0.06)`; dark: `0 1px 2px rgb(0 0 0 / 0.4)`), `--shadow-md` (light: `0 2px 8px rgb(0 0 0 / 0.08)`; dark: `0 2px 8px rgb(0 0 0 / 0.5)`). `--transition: 120ms ease-out`. Disabled under `@media (prefers-reduced-motion: reduce)`. ### Z-index `--z-dropdown 10`, `--z-sticky 50`, `--z-modal 100`, `--z-toast 1000`. No raw `z-index` numbers in component CSS. ## Components All shapes are token-driven. Implementation lives in route-scoped `