diff --git a/flight-comparator/docs/DESIGN_SYSTEM.md b/flight-comparator/docs/DESIGN_SYSTEM.md
new file mode 100644
index 0000000..20f84b6
--- /dev/null
+++ b/flight-comparator/docs/DESIGN_SYSTEM.md
@@ -0,0 +1,1015 @@
+# Flight Radar — Design System
+
+**Version 1.0 · February 2026**
+
+This document is the authoritative reference for the visual design and UX of the Flight Radar web application. It covers the full design system: principles, tokens, components, and page-level specifications — ready for direct implementation in Tailwind CSS v4 + React.
+
+---
+
+## Table of Contents
+
+1. [Current State Audit](#1-current-state-audit)
+2. [Design Principles](#2-design-principles)
+3. [Color System](#3-color-system)
+4. [Typography](#4-typography)
+5. [Spacing & Layout Grid](#5-spacing--layout-grid)
+6. [Elevation & Shadow](#6-elevation--shadow)
+7. [Component Library](#7-component-library)
+8. [Page Specifications](#8-page-specifications)
+9. [Motion & Animation](#9-motion--animation)
+10. [Icons](#10-icons)
+11. [Implementation Checklist](#11-implementation-checklist)
+
+---
+
+## 1. Current State Audit
+
+### What's broken today
+
+| Area | Problem | Impact |
+|------|---------|--------|
+| **Navigation** | Nav links butted together with no gaps: renders as `DashboardScansAirportsLogs` | Unreadable, looks broken |
+| **Dashboard stats** | Five identical white boxes with no accent, icon, or trend | Zero visual hierarchy |
+| **Scan list items** | Status badge glued to destination: `BDS → FMM,DUScompleted` | Parsing required by user |
+| **Form** | Flat input fields, no grouping, no visual section breaks | Feels like a raw HTML form |
+| **Mode toggle** | Full-width button pair looks like a toggle switch gone wrong | Confusing affordance |
+| **Airports page** | Empty white canvas with an input box — no state, no branding | Dead end feeling |
+| **Logs page** | Wall of monospaced text with no log-level differentiation | No scanability |
+| **Mobile** | Nav links overflow and collapse poorly | Unusable on small screens |
+| **Loading states** | Plain text "Loading…" or invisible spinner | No feedback |
+| **Empty states** | Plain text only, no illustration or call to action | Abandoned feeling |
+| **Colors** | Two blues + basic status colours, no system | Incoherent palette |
+| **Typography** | Browser default font, no size scale | Low credibility |
+| **Branding** | ✈️ emoji as logo | Not scalable, not professional |
+
+### What's good and must be kept
+
+- Tailwind CSS v4 already installed — just needs design tokens
+- React Router working, page structure sound
+- Component boundaries (AirportSearch, Layout, pages) are clean
+- Status badge color logic is correct
+- Auto-refresh on running scans is a great UX feature
+- Expandable flight rows in the route table are the right pattern
+
+---
+
+## 2. Design Principles
+
+### 1. Data first, chrome second
+Flight data is complex (many numbers, dates, airports). The UI must recede and let data breathe. Avoid decorative elements that compete with content.
+
+### 2. Material Design 3 — adapted, not copied
+Use MD3's color system (tonal palettes, surface roles), elevation model (tonal elevation, not drop shadows), and component shapes (rounded corners). Ditch components that don't fit a desktop tool (FABs, bottom nav for desktop).
+
+### 3. Mobile-first, desktop-optimised
+Start every layout from 320 px. Desktop adds a sidebar and wider data tables — it doesn't redesign the page.
+
+### 4. Instant feedback everywhere
+Every async action shows a skeleton, spinner, or progress indicator. Every destructive or slow action is confirmed. Success and error are always communicated via toast.
+
+### 5. One primary action per view
+Each page has exactly one primary CTA (blue filled button). Everything else is secondary or ghost.
+
+---
+
+## 3. Color System
+
+### Brand palette (MD3 tonal palette — primary hue: blue 220°)
+
+```
+Primary #1A73E8 (Google Blue — familiar, trustworthy for a data tool)
+On Primary #FFFFFF
+Primary Cont. #D2E3FC (primary container — used for active nav, chips)
+On Primary Cont.#003E8C
+
+Secondary #0F9D58 (green — price / success / confirmed flights)
+On Secondary #FFFFFF
+Secondary Cont. #C8E6C9
+
+Tertiary #F4B400 (amber — warnings, pending states)
+On Tertiary #3B2A00
+Tertiary Cont. #FFF0C0
+
+Error #D93025 (red — failed, error)
+Error Cont. #FDECEA
+
+Surface #F8F9FA (page background — very light grey)
+Surface 1 #FFFFFF (card background — level 1)
+Surface 2 #F1F3F4 (table row alternate / subtle separators)
+Surface Variant #E8EAED (input backgrounds, chip backgrounds)
+On Surface #202124 (primary text)
+On Surface Var. #5F6368 (secondary text, labels, metadata)
+Outline #DADCE0 (borders, dividers)
+Outline Var. #F1F3F4 (very subtle separators)
+```
+
+### Semantic status colours
+
+| Status | Background | Text | Border | Usage |
+|--------|-----------|------|--------|-------|
+| `completed` | `#E6F4EA` | `#137333` | `#A8D5B5` | Scan finished, route confirmed |
+| `running` | `#E8F0FE` | `#1557B0` | `#A8C7FA` | Scan in progress |
+| `pending` | `#FEF7E0` | `#7A5200` | `#F9D659` | Queued, not started |
+| `failed` | `#FDECEA` | `#A50E0E` | `#F5C6C6` | Error state |
+
+### Dark mode (implement via CSS variables)
+
+```css
+/* light (default) */
+:root {
+ --color-bg: #F8F9FA;
+ --color-surface: #FFFFFF;
+ --color-surface-2: #F1F3F4;
+ --color-on-surface: #202124;
+ --color-on-surface-var: #5F6368;
+ --color-outline: #DADCE0;
+ --color-primary: #1A73E8;
+ --color-secondary: #0F9D58;
+}
+
+/* dark */
+@media (prefers-color-scheme: dark) {
+ :root {
+ --color-bg: #1C1B1F;
+ --color-surface: #2C2B30;
+ --color-surface-2: #36343B;
+ --color-on-surface: #E6E1E5;
+ --color-on-surface-var: #938F99;
+ --color-outline: #49454F;
+ --color-primary: #A8C7FA;
+ --color-secondary: #81C995;
+ }
+}
+```
+
+---
+
+## 4. Typography
+
+### Font stack
+
+```css
+font-family: 'Google Sans', 'Roboto', system-ui, -apple-system, sans-serif;
+font-family-mono: 'Roboto Mono', 'JetBrains Mono', monospace; /* logs, IATA codes */
+```
+
+> Load from Google Fonts: `Google Sans` (300, 400, 500) + `Roboto Mono` (400)
+
+### Type scale (MD3 aligned)
+
+| Token | Size | Weight | Line height | Usage |
+|-------|------|--------|-------------|-------|
+| `display-sm` | 36px / 2.25rem | 400 | 44px | Page hero (empty states) |
+| `headline-lg` | 32px / 2rem | 400 | 40px | — |
+| `headline-md` | 28px / 1.75rem | 400 | 36px | Page title |
+| `headline-sm` | 24px / 1.5rem | 400 | 32px | Section title |
+| `title-lg` | 22px / 1.375rem | 500 | 28px | Card title |
+| `title-md` | 16px / 1rem | 500 | 24px | List item title, form label |
+| `title-sm` | 14px / 0.875rem | 500 | 20px | Table header, tab label |
+| `body-lg` | 16px / 1rem | 400 | 24px | Body copy, descriptions |
+| `body-md` | 14px / 0.875rem | 400 | 20px | Secondary body, list metadata |
+| `body-sm` | 12px / 0.75rem | 400 | 16px | Captions, helper text |
+| `label-lg` | 14px / 0.875rem | 500 | 20px | Button labels |
+| `label-md` | 12px / 0.75rem | 500 | 16px | Badge labels, chip labels |
+| `label-sm` | 11px / 0.6875rem | 500 | 16px | Overlines, micro labels |
+| `mono-md` | 13px / 0.8125rem | 400 | 20px | IATA codes, log messages |
+
+---
+
+## 5. Spacing & Layout Grid
+
+### Spacing scale (4px base)
+
+```
+1 → 4px (tight gaps: icon-to-text, badge padding)
+2 → 8px (small gaps: form field helper text)
+3 → 12px (medium-small: list item inner padding)
+4 → 16px (base unit: card inner padding mobile)
+5 → 20px (—)
+6 → 24px (card inner padding desktop, section gaps)
+8 → 32px (between major sections)
+10 → 40px (—)
+12 → 48px (page top padding)
+16 → 64px (large empty state illustrations)
+```
+
+### Layout grid
+
+**Mobile (< 600px)**
+- 1 column, 16px margins, 16px gutters
+- Full-width cards
+- Bottom navigation bar (56px)
+
+**Tablet (600–1024px)**
+- 8 columns, 24px margins, 24px gutters
+- Side rail navigation (72px collapsed)
+- Cards: 2-column grid for stats
+
+**Desktop (> 1024px)**
+- 12 columns, 24px margins, 24px gutters
+- Fixed sidebar navigation (256px)
+- Max content width: 1280px
+- Cards: 3–5 column grid for stats
+
+### Sidebar layout (desktop)
+
+```
+┌──────────┬────────────────────────────────┐
+│ │ Top bar (64px, search + user) │
+│ Sidebar ├────────────────────────────────┤
+│ (256px) │ │
+│ │ Main content area │
+│ Logo │ max-w: 1024px, centered │
+│ Nav │ px: 24px │
+│ items │ │
+│ │ │
+│ ────── │ │
+│ Logs │ │
+└──────────┴────────────────────────────────┘
+```
+
+---
+
+## 6. Elevation & Shadow
+
+MD3 uses **tonal elevation** (surface tint) as primary depth cue, with subtle shadows for resting state only.
+
+| Level | Shadow | Tint overlay | Usage |
+|-------|--------|-------------|-------|
+| 0 | none | 0% | Page background |
+| 1 | `0 1px 2px rgba(0,0,0,.08)` | 5% primary | Cards (resting) |
+| 2 | `0 2px 6px rgba(0,0,0,.10)` | 8% primary | Dropdowns, popovers |
+| 3 | `0 4px 12px rgba(0,0,0,.12)` | 11% primary | Modals, dialogs |
+| 4 | `0 6px 20px rgba(0,0,0,.14)` | 12% primary | Navigation drawer |
+
+---
+
+## 7. Component Library
+
+### 7.1 Navigation
+
+#### Sidebar (desktop ≥ 1024px)
+
+```
+Width: 256px (expanded) / 72px (collapsed — future)
+Background: Surface (white)
+Border-right: 1px solid Outline (#DADCE0)
+
+Logo area (64px tall):
+ ✈ icon (24px, Primary blue) + "Flight Radar" (title-lg, On Surface)
+
+Nav item (48px tall, full width):
+ - Inactive: transparent bg, On Surface Var text, 16px side padding
+ - Active: Primary Container bg (#D2E3FC), On Primary Container text,
+ bold icon, rounded 28px pill shape (full bleed)
+ - Hover: Surface 2 bg, On Surface text
+ - Icon: 20px, left-aligned
+ - Label: body-md 500 weight, 12px left of icon
+
+Section divider:
+ Between main items and Logs: 1px divider + "Developer" label (label-sm, muted)
+
+Items (in order):
+ 🏠 Dashboard → /
+ 🔍 Scans → /scans
+ ✈ Airports → /airports
+ ── (divider)
+ 📋 Logs → /logs
+```
+
+#### Top app bar (desktop)
+
+```
+Height: 64px
+Background: Surface (white)
+Border-bottom: 1px solid Outline
+Shadow: Level 1 on scroll
+
+Left: (sidebar occupies)
+Center: Page title (headline-sm, On Surface) — OR breadcrumb
+Right: + New Scan button (filled, primary)
+```
+
+#### Bottom navigation (mobile < 600px)
+
+```
+Height: 80px (includes safe area)
+Background: Surface
+Border-top: 1px solid Outline
+Shadow: Level 2 (upward)
+
+4 items: Dashboard | Scans | Airports | Logs
+Each: icon (24px) + label (label-md) stacked
+Active: Primary colour icon + Primary Container indicator pill behind icon (56×32px)
+Inactive: On Surface Var colour
+```
+
+---
+
+### 7.2 Buttons
+
+#### Filled (primary action — one per page)
+
+```
+Background: Primary (#1A73E8)
+Text: On Primary (#FFFFFF)
+Height: 40px
+Padding: 0 24px
+Border-radius: 20px (fully rounded — MD3 style)
+Font: label-lg (14px/500)
+Shadow: Level 1
+Hover: darken 8% + Level 2 shadow
+Pressed: darken 12%, Level 1
+Disabled: 38% opacity
+
+Icons: optional leading icon at 18px
+```
+
+#### Outlined (secondary action)
+
+```
+Border: 1px solid Outline (#DADCE0)
+Text: Primary (#1A73E8)
+Background: transparent
+Same sizing/radius as filled
+Hover: Primary Container bg (#D2E3FC)
+```
+
+#### Text (tertiary / destructive link)
+
+```
+Text: Primary or Error
+No border, no background
+Hover: surface tint
+Padding: 0 12px
+```
+
+#### Icon button
+
+```
+Size: 40×40px
+Shape: circle
+Background: transparent → Surface 2 on hover
+Icon: 20px, On Surface Var → On Surface on hover
+```
+
+---
+
+### 7.3 Status Chip / Badge
+
+```
+Height: 24px
+Padding: 0 10px
+Border-radius: 12px (pill)
+Font: label-md (12px/500)
+Border: 1px solid (matching border column from §3)
+
+┌──────────────────────┐
+│ ● completed │ green bg, green text, green dot
+│ ↻ running │ blue bg, blue text, spinning dot (CSS animation)
+│ ⧖ pending │ amber bg, amber text, static dot
+│ ✕ failed │ red bg, red text, X icon
+└──────────────────────┘
+```
+
+Implementation: The colored dot/icon is a 6px circle or SVG icon on the left at 8px margin-right.
+
+---
+
+### 7.4 Stat Card
+
+Used on Dashboard (5 cards) and Scan Details (3 cards).
+
+```
+┌────────────────────────┐
+│ ┌──┐ │
+│ │ 🔍│ Total Scans │ ← icon in tinted circle (40px), label (body-sm, muted)
+│ └──┘ │
+│ │
+│ 54 │ ← number (display-sm or headline-md)
+│ │
+│ +3 today │ ← optional trend (body-sm, secondary/error)
+└────────────────────────┘
+
+Padding: 24px
+Border-radius: 16px (MD3 large shape)
+Background: Surface (white)
+Shadow: Level 1
+Width: fluid (grid cell)
+
+Icon circle: 40×40px, border-radius 20px
+ Total: #E8F0FE bg, Primary icon
+ Pending: #FEF7E0 bg, Tertiary icon
+ Running: #E8F0FE bg, Primary icon (animated pulse)
+ Completed: #E6F4EA bg, Secondary icon
+ Failed: #FDECEA bg, Error icon
+```
+
+---
+
+### 7.5 List / Scan Card
+
+Replaces the current flat `` row in the dashboard.
+
+```
+┌──────────────────────────────────────────────────────────┐
+│ BDS → FMM, DUS ● completed 25.2.2026 │
+│ 26 Feb 2026 – 27 May 2026 · 1 adult · Economy │
+│ │
+│ 182 routes · 50 flights found → │
+└──────────────────────────────────────────────────────────┘
+
+Padding: 16px 20px
+Border-radius: 12px (on hover, or always)
+Background: Surface
+Hover: Surface 2 bg + Level 2 shadow (lift effect)
+Divider: 1px inside, OR 8px gap between cards (prefer cards)
+Cursor: pointer
+
+Route arrow (→): On Surface Var, shifts right on hover (transform)
+
+Status chip: right-aligned in first row, always visible
+Date metadata: body-sm, On Surface Var
+Stats line: body-sm, On Surface Var, shown only when > 0
+```
+
+---
+
+### 7.6 Text Input & Form Field
+
+MD3 "Outlined" input variant.
+
+```
+Height: 56px
+Border: 1px solid Outline
+Border-radius: 4px (corners) — MD3 uses 4px for inputs (not pills)
+Background: transparent (on Surface bg it appears inset)
+Padding: 16px
+
+Labels: floating label (HTML standard — use