diff --git a/backend/Cargo.lock b/backend/Cargo.lock index f5a232a..6f0b008 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -1033,7 +1033,7 @@ checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "mangalord" -version = "0.11.0" +version = "0.13.0" dependencies = [ "anyhow", "argon2", diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 32ed364..c9d7962 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mangalord" -version = "0.12.0" +version = "0.13.0" edition = "2021" [lib] diff --git a/docs/design-system.md b/docs/design-system.md new file mode 100644 index 0000000..de74545 --- /dev/null +++ b/docs/design-system.md @@ -0,0 +1,162 @@ +# 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 ` diff --git a/frontend/src/routes/login/+page.svelte b/frontend/src/routes/login/+page.svelte index 682885c..21f3394 100644 --- a/frontend/src/routes/login/+page.svelte +++ b/frontend/src/routes/login/+page.svelte @@ -26,8 +26,8 @@

Log in

-