diff --git a/.gitignore b/.gitignore
index 075cbda..1a37262 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,3 +15,4 @@ docs/build
memory/
TASKS.md
dashboard.html
+.gstack/
diff --git a/CLAUDE.md b/CLAUDE.md
index 8ece4c2..4a2b03a 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -39,3 +39,15 @@ Xianpeng Shen (shenxianpeng), DevOps engineer. Maintains the gitstats open sourc
- Branch for PRs: `main`
- Always run `nox -s lint` before committing
- **Language**: Always reply in the same language the user writes in. If the user writes in Chinese, respond in Chinese.
+
+## Design System
+Always read `DESIGN.md` before making any visual or UI decisions.
+All font choices, colors, spacing, and aesthetic direction are defined there.
+Do not deviate without explicit user approval.
+In QA mode, flag any code that doesn't match `DESIGN.md`.
+
+Key rules (never violate without checking DESIGN.md first):
+- `font-family` must be `var(--font-mono)` on body — no fallback to sans-serif
+- Accent color is warm amber (`#D97706` light / `#F59E0B` dark) — not steel blue
+- Border-radius: zero everywhere
+- No cards, no box-shadow elevation, no grain textures
diff --git a/DESIGN.md b/DESIGN.md
new file mode 100644
index 0000000..91dd711
--- /dev/null
+++ b/DESIGN.md
@@ -0,0 +1,304 @@
+# Design System — GitStats
+
+## Product Context
+- **What this is:** A Python CLI tool that generates self-contained HTML/JSON reports with statistics from Git repositories
+- **Who it's for:** Developers and DevOps engineers analyzing their own repositories
+- **Space/industry:** Developer tooling / repository analytics
+- **Project type:** Data report — static HTML output, not a web app or SaaS product
+
+## Aesthetic Direction
+- **Direction:** Terminal-Native / Developer-First
+- **Decoration level:** Minimal — typography, spacing, and contrast do all the work
+- **Mood:** Feels like high-quality CLI tool output rendered as HTML. Not a SaaS product trying to appeal to developers — a developer tool that reflects developer values. The user should think "this tool knows what it is."
+- **Key differentiator:** Warm grayscale palette + zero border-radius + full monospace typeface. Most git analytics tools (GitHub, GitLab, Sourcegraph) use cool-gray, rounded-corner SaaS aesthetics. GitStats owns the developer-native space.
+
+## Typography
+- **All text — IBM Plex Mono** (one typeface for everything, including body)
+ - This is a deliberate commitment, not an omission. The gitstats user is a developer. There are no non-technical users to protect from monospace body text.
+ - `font-family: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace`
+- **Loading:** Google Fonts CDN (`https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,300;0,400;0,500;0,600;1,400&display=swap`)
+- **Type scale:**
+
+| Role | Size | Weight | Notes |
+|------|------|--------|-------|
+| Hero / page title | 22–28px | 600 | letter-spacing: -0.03em |
+| Section heading h2 | 18px | 500 | prefixed with `// ` in amber |
+| Sub-heading h3 | 15px | 500 | — |
+| Body / paragraphs | 13px | 400 | line-height: 1.7 |
+| UI labels / table headers | 11px | 500 | uppercase, letter-spacing: 0.05em |
+| Tabular data | 12px | 400 | font-feature-settings: "tnum" |
+| Code / commands | 12px | 400 | background surface, border |
+
+## Color
+
+### Light mode
+| Token | Value | Usage |
+|-------|-------|-------|
+| `--bg` | `#ffffff` | Page background |
+| `--surface` | `#f5f5f4` | Table headers, code blocks, surface elements |
+| `--surface-2` | `#ebeaea` | Hover states |
+| `--text` | `#211e1e` | Primary text (warm near-black) |
+| `--text-2` | `#4b4646` | Secondary text, nav links |
+| `--text-muted` | `#9e9a9a` | Placeholder, metadata |
+| `--border` | `#cfcecd` | Default borders |
+| `--border-strong` | `#9e9a9a` | Table borders, strong dividers |
+| `--amber` | `#D97706` | **Accent** — links, bar charts, interactive hover, `//` heading prefix |
+| `--amber-hover` | `#b45309` | Amber on hover |
+| `--amber-light` | `#fef3c7` | Alert/badge backgrounds |
+| `--green` | `#2d6a3f` | Health score, success states |
+| `--red` | `#8b2323` | Danger/error states |
+| `--yellow` | `#d4a017` | Warning states |
+
+### Dark mode
+| Token | Value | Usage |
+|-------|-------|-------|
+| `--bg` | `#211e1e` | Page background (warm near-black) |
+| `--surface` | `#2d2929` | Surface elements |
+| `--surface-2` | `#352f2f` | Hover states |
+| `--text` | `#f1ecec` | Primary text (warm near-white) |
+| `--text-2` | `#b7b1b1` | Secondary text |
+| `--text-muted` | `#656363` | Muted text |
+| `--border` | `#3d3838` | Default borders |
+| `--border-strong` | `#656363` | Strong borders |
+| `--amber` | `#F59E0B` | Accent (one stop brighter for dark contrast) |
+| `--amber-hover` | `#fbbf24` | Amber on hover |
+| `--green` | `#4ade80` | Health/success |
+| `--red` | `#f87171` | Danger/error |
+| `--yellow` | `#e3b341` | Warning |
+
+### Color role rules
+- **Amber** = interaction, state emphasis, links, bar charts, active indicators
+- **Green** = heatmap density (GitHub green scale), health scores, success states — never use for interaction
+- These two color families must not overlap. Amber is for "you can click/interact with this." Green is for "this is a data density or health signal."
+
+### Heatmap scale
+GitHub green — colorblind-safe, universally recognizable for contribution graphs:
+- Level 0: `#ebedf0` (light) / `#1c2128` (dark)
+- Level 1: `#9be9a8` / `#0e4429`
+- Level 2: `#40c463` / `#006d32`
+- Level 3: `#30a14e` / `#26a641`
+- Level 4: `#216e39` / `#39d353`
+
+## Spacing
+- **Base unit:** 4px
+- **Scale:** `--sp-1: 4px` `--sp-2: 8px` `--sp-3: 12px` `--sp-4: 16px` `--sp-5: 24px` `--sp-6: 32px` `--sp-7: 48px` `--sp-8: 64px`
+- **Density:** Compact-to-comfortable. Table cell padding: 8px 12px. Reports are data-dense — don't waste vertical space.
+- **Max content width:** 1280px
+
+## Layout
+- **Approach:** Section-based, not card-based. Sections separated by `
` headings and `` dividers. Tables, chart regions, and stat blocks are the primitives — not cards.
+- **Border radius:** Zero everywhere (`border-radius: 0`). This is the terminal/angular identity. Never introduce rounded corners.
+- **Grid:** No explicit CSS grid. Section content flows naturally with max-width constraint.
+- **Nav:** Sticky top bar, min-height 44px (WCAG 2.5.5 touch target).
+
+### Section heading convention
+All `h2` elements get a `//` prefix in amber, applied via CSS:
+```css
+h2::before { content: '// '; color: var(--amber); }
+```
+
+### Generation command block
+On the general/index page, directly below `
`, show the command used to generate the report:
+```
+$ gitstats /path/to/repo ./output ▊
+```
+Styled with surface background, 1px border, amber prompt character, blinking cursor. This is the single strongest "this is a CLI tool" signal and requires ~4 lines of Python to implement.
+
+## Motion
+
+### Tokens
+| Token | Duration | Easing | Usage |
+|-------|----------|--------|-------|
+| `--transition-fast` | `120ms ease-out` | ease-out | hover color/background shifts |
+| `--transition-base` | `150ms ease-out` | ease-out | border-color, nav state |
+| `--transition-theme` | `200ms ease` | ease | theme toggle — bg + color on body |
+| `--transition-cursor` | `1.2s step-end infinite` | step-end | blinking cursor (blink keyframe) |
+
+### Rules
+- **Standard:** `transition: background-color 120ms ease-out, color 120ms ease-out, border-color 120ms ease-out`
+- **Theme switch:** `transition: background-color 0.2s ease, color 0.2s ease` on `body`
+- **Never animate layout properties** (`width`, `height`, `top`, `left`) — transform + opacity only
+- **No animations on data load** — reports are static; entrance animations would feel wrong
+- **`prefers-reduced-motion`:** Cursor blink animation (`@keyframes blink`) is disabled via `@media (prefers-reduced-motion: reduce)`. All other transitions are safe (sub-200ms, no layout shifts).
+
+## Interactive States
+
+### Focus
+- **`:focus-visible`:** `outline: 2px solid var(--amber); outline-offset: 2px`
+- Never use `outline: none` without a visible replacement
+- All nav links, the theme toggle, and table header sort anchors must show focus ring on keyboard nav
+
+### Hover
+- **Links:** color shifts to `var(--amber)`, underline appears
+- **Nav links:** color → `var(--amber)`, background → `var(--surface-color)`
+- **Table rows:** `tr:hover td` → background `var(--table-hover-bg)`
+- **Bar charts:** `.bar` opacity 0.85 → 1.0 on parent hover
+- **Theme toggle / nav-github:** color → `var(--amber)` or `var(--text-color)`
+
+### Active / Current page
+- Nav link for the current page should visually indicate active state (bold weight or amber color)
+- (not yet implemented — future enhancement)
+
+## Responsive Design
+
+### Strategy
+GitStats reports are primarily desktop tools (run via CLI, opened in a browser). Mobile is secondary but should not be broken. The goal is "readable and usable on mobile" not "designed for mobile."
+
+### Breakpoints
+| Name | Width | Behavior |
+|------|-------|----------|
+| desktop | ≥ 768px | Full layout, sticky nav, side-by-side columns |
+| mobile | < 768px | Stacked layout, scrollable tables, wrapped nav |
+
+### Nav on mobile
+**Current state:** Nav items wrap into multiple rows (deferred — FINDING-003).
+**Target:** Implement horizontal scrollable nav with `overflow-x: auto; white-space: nowrap` on `.nav ul`. No hamburger menu — developer tool users expect dense, direct access. A horizontally scrolling list of 6 links is appropriate for this audience.
+
+**Implementation plan (when prioritized):**
+```css
+@media (max-width: 768px) {
+ .nav ul {
+ overflow-x: auto;
+ white-space: nowrap;
+ flex-wrap: nowrap;
+ -webkit-overflow-scrolling: touch;
+ }
+ .nav li a {
+ min-height: 44px; /* already set */
+ }
+}
+```
+
+### Tables on mobile
+Tables use `display: block; overflow-x: auto` on all viewports (implemented). Wide tables scroll horizontally within the viewport — correct behavior for data reports.
+
+### Charts on mobile
+Chart.js canvases are responsive by default (`responsive: true`). Charts reflow to container width automatically.
+
+## Component Library
+
+### Navigation (`.nav`)
+```
+[GitStats] [General | Activity | Authors | Files | Lines | Tags] [GitHub ⬡] [🌙]
+```
+- Sticky top bar, `min-height: 44px`, `z-index: 100`
+- Brand: `16px 700 monospace`, left
+- Links: `12px 500 monospace`, separated by `1px border-left`, vertical dividers
+- Right side: GitHub icon link + theme toggle button, separated from links by `border-left`
+- Active hover: color → amber, background → surface
+- All interactive elements: `min-height: 44px`, `min-width: 44px` (WCAG 2.5.5)
+
+### Generation Command Block (`.cmd-block`)
+```
+$ gitstats . ./output ▊
+```
+- Surface background, `1px border`, monospace 12px, amber `$` prompt, blinking cursor `▊`
+- `@media (prefers-reduced-motion: reduce)` disables blink
+- Placed directly below `
` on the index/general page only
+
+### Tables
+- `border-collapse: collapse`, `font-size: 12px`
+- `th`: surface background, uppercase, `11px`, `letter-spacing: 0.08em`, strong border
+- `td`: white/table-bg background, `8px 12px` padding, light border
+- `tr:hover`: table-hover-bg background
+- `table.noborders`: bar chart tables — no borders, transparent background
+- Responsive: `display: block; overflow-x: auto` on all viewports
+
+### Bar Charts (`.bar` + `.noborders`)
+- Plain `
` with `
` cells containing a `
`
+- `.bar` background: `var(--bar-color)` = `var(--amber)`, opacity 0.85
+- On row hover: opacity → 1.0
+- Bar height/width set inline by Python based on value percentage
+
+### Heatmap (`.heat0`–`.heat4`)
+- Used on the Activity page for commit frequency calendars
+- GitHub green scale (5 levels, colorblind-safe)
+- Level 0 = no activity, Level 4 = peak activity
+- Text color inverts to white at levels 3–4 for contrast
+- See Color section for exact hex values
+
+### Section Headings (`h2`)
+```html
+