Gemini redesign
docs: add design doc for high-contrast UI upgrade style: implement high-contrast header and navigation style: remove redundant gap class from nav style: implement high-contrast commit list style: implement high-contrast commit detail view style: address feedback on high-contrast UI style: move repository description back to header under title style: render active nav menu item as span with active indicator docs: add plan for recent commit activity indicator feat: add humanize time helper and update models for recent commit indicator feat: populate recent commit data for summary page feat: display recent commit activity indicator on summary page
12 files changed,  +2727, -70
A docs/plans/2025-04-07-design-enhancement.md
+639, -0
  1@@ -0,0 +1,639 @@
  2+# Git Static Site Design Enhancement
  3+
  4+## Overview
  5+
  6+This document outlines the visual design enhancements for the pgit static site generator. The goal is to create a bold, developer-focused aesthetic with improved typography, visual hierarchy, and CSS-only interactions.
  7+
  8+## Typography System
  9+
 10+### Font Stack (Option A: Tech Bold)
 11+
 12+| Element | Font | Weights | Usage |
 13+|---------|------|---------|-------|
 14+| Headers/Display | Space Grotesk | 500, 600, 700, 800 | Repo names, section titles, navigation |
 15+| Body | Inter | 400, 500, 600, 700 | Paragraphs, labels, metadata |
 16+| Code/Mono | JetBrains Mono | 400, 500, 600, 700 | Commit hashes, code blocks, file paths |
 17+
 18+### Google Fonts URL
 19+
 20+```html
 21+<link rel="preconnect" href="https://fonts.googleapis.com">
 22+<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
 23+<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&family=Space+Grotesk:wght@500;600;700;800&display=swap" rel="stylesheet">
 24+```
 25+
 26+### Type Scale
 27+
 28+| Element | Size | Weight | Line-Height | Letter-Spacing | Notes |
 29+|---------|------|--------|-------------|----------------|-------|
 30+| H1 (Repo Name) | 2rem | 800 | 1.2 | -0.02em | Space Grotesk |
 31+| H2 (Section) | 1.25rem | 700 | 1.3 | 0.05em | Space Grotesk, uppercase |
 32+| H3 (Subsection) | 1rem | 600 | 1.4 | 0 | Space Grotesk |
 33+| Body | 1rem | 400 | 1.6 | 0 | Inter |
 34+| Body Bold | 1rem | 600 | 1.6 | 0 | Inter |
 35+| Small | 0.875rem | 500 | 1.4 | 0.01em | Inter, metadata |
 36+| Code | 0.9rem | 500 | 1.5 | 0.02em | JetBrains Mono |
 37+| Code Bold | 0.9rem | 700 | 1.5 | 0.02em | JetBrains Mono, hashes |
 38+
 39+## Color Scheme
 40+
 41+**Note:** Colors are defined at build time using the Chroma library. Design works with any theme.
 42+
 43+### Existing Variables (Preserve)
 44+- `--bg-color`: Background
 45+- `--text-color`: Primary text
 46+- `--link-color`: Links and accents
 47+- `--hover`: Hover states
 48+- `--visited`: Visited links
 49+- `--border`: Borders and dividers
 50+- `--grey-light`: Muted text
 51+
 52+### New Variables to Add
 53+```css
 54+--font-display: 'Space Grotesk', system-ui, sans-serif;
 55+--font-body: 'Inter', system-ui, sans-serif;
 56+--font-mono: 'JetBrains Mono', 'Fira Code', monospace;
 57+
 58+--transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);
 59+--transition-base: 200ms cubic-bezier(0.4, 0, 0.2, 1);
 60+
 61+--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.1);
 62+--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.15);
 63+```
 64+
 65+## Layout & Spacing
 66+
 67+### Spacing Scale
 68+```css
 69+--space-1: 0.25rem;   /* 4px */
 70+--space-2: 0.5rem;    /* 8px */
 71+--space-3: 0.75rem;   /* 12px */
 72+--space-4: 1rem;      /* 16px */
 73+--space-5: 1.5rem;    /* 24px */
 74+--space-6: 2rem;      /* 32px */
 75+--space-8: 2.5rem;    /* 40px */
 76+```
 77+
 78+### Section Spacing
 79+- **Header**: 2.5rem padding, border-bottom separator
 80+- **Main content**: 2rem gap between major sections
 81+- **Footer**: 2rem top padding, smaller text, top border
 82+
 83+## Components
 84+
 85+### Navigation (Desktop)
 86+
 87+**Layout:** Horizontal pill buttons
 88+
 89+**Structure:**
 90+```
 91+[summary] [refs] [main] [code] [commits]
 92+```
 93+
 94+**Styles:**
 95+```css
 96+nav {
 97+  display: flex;
 98+  gap: var(--space-2);
 99+  flex-wrap: wrap;
100+}
101+
102+nav a {
103+  font-family: var(--font-display);
104+  font-weight: 600;
105+  font-size: 0.9rem;
106+  padding: var(--space-2) var(--space-4);
107+  border: 1px solid var(--border);
108+  border-radius: 4px;
109+  text-decoration: none;
110+  transition: all var(--transition-base);
111+}
112+
113+nav a:hover {
114+  background: var(--link-color);
115+  color: var(--bg-color);
116+  transform: translateY(-2px);
117+  box-shadow: 0 4px 12px rgba(139, 233, 253, 0.15);
118+  text-decoration: none;
119+}
120+
121+nav a:active {
122+  transform: translateY(0);
123+}
124+
125+nav .current {
126+  background: var(--link-color);
127+  color: var(--bg-color);
128+  font-weight: 700;
129+}
130+```
131+
132+### Navigation (Mobile)
133+
134+**Layout:** 2-column grid, responsive stacking
135+
136+**Structure:**
137+```
138+┌─────────────┬─────────────┐
139+│  summary    │    refs     │
140+├─────────────┼─────────────┤
141+│    main     │    code     │
142+├─────────────┴─────────────┤
143+│         commits           │
144+└───────────────────────────┘
145+```
146+
147+**Styles:**
148+```css
149+@media (max-width: 600px) {
150+  nav {
151+    display: grid;
152+    grid-template-columns: 1fr 1fr;
153+    gap: var(--space-2);
154+  }
155+  
156+  nav a {
157+    text-align: center;
158+    min-height: 44px;
159+    display: flex;
160+    align-items: center;
161+    justify-content: center;
162+  }
163+  
164+  /* Full width for commits */
165+  nav a[href*="commits"] {
166+    grid-column: 1 / -1;
167+  }
168+}
169+```
170+
171+### Commit List
172+
173+**Structure:**
174+```
175+┌─────────────────────────────────────────────────────────────┐
176+│ ●  a7f3d9e  Add user authentication feature          (main) │
177+│    Author Name · 2 hours ago                                │
178+│    Full commit message with proper typography...            │
179+└─────────────────────────────────────────────────────────────┘
180+```
181+
182+**Styles:**
183+```css
184+.commit-row {
185+  border-left: 2px solid transparent;
186+  padding-left: var(--space-3);
187+  margin-bottom: var(--space-4);
188+  transition: border-color var(--transition-fast), 
189+              background var(--transition-fast);
190+}
191+
192+.commit-row:hover {
193+  border-left-color: var(--link-color);
194+  background: rgba(139, 233, 253, 0.03);
195+}
196+
197+.commit-hash {
198+  font-family: var(--font-mono);
199+  font-weight: 600;
200+  font-size: 0.9rem;
201+  color: var(--link-color);
202+}
203+
204+.commit-message {
205+  font-family: var(--font-body);
206+  font-size: 1.05rem;
207+  font-weight: 500;
208+  line-height: 1.5;
209+  margin: var(--space-2) 0;
210+}
211+
212+.commit-meta {
213+  font-size: 0.875rem;
214+  color: var(--grey-light);
215+  font-weight: 500;
216+}
217+
218+.commit-meta span + span::before {
219+  content: "·";
220+  margin: 0 var(--space-2);
221+  opacity: 0.6;
222+}
223+
224+.commit-refs {
225+  display: inline-flex;
226+  gap: var(--space-1);
227+}
228+
229+.commit-ref {
230+  font-size: 0.8rem;
231+  padding: 0.1rem var(--space-2);
232+  border: 1px solid var(--link-color);
233+  border-radius: 3px;
234+  color: var(--link-color);
235+  font-weight: 600;
236+}
237+```
238+
239+### Commit Graph (Simple)
240+
241+**Visual:** Vertical line with commit dots
242+
243+```
244+│ ●─── 3a7f2e9  Latest commit message
245+│
246+│ ●─── 8c4d1a2  Previous commit
247+│
248+│ ●─── 9e1b3c4  Older commit
249+```
250+
251+**Implementation:** CSS pseudo-elements
252+```css
253+.commit-graph {
254+  position: relative;
255+  padding-left: 1.5rem;
256+}
257+
258+.commit-graph::before {
259+  content: "";
260+  position: absolute;
261+  left: 0;
262+  top: 0;
263+  bottom: 0;
264+  width: 2px;
265+  background: var(--border);
266+}
267+
268+.commit-dot {
269+  position: absolute;
270+  left: -5px;
271+  width: 12px;
272+  height: 12px;
273+  border-radius: 50%;
274+  background: var(--link-color);
275+  border: 2px solid var(--bg-color);
276+}
277+
278+/* On mobile: hide graph, keep simple list */
279+@media (max-width: 600px) {
280+  .commit-graph {
281+    padding-left: 0;
282+  }
283+  .commit-graph::before,
284+  .commit-dot {
285+    display: none;
286+  }
287+}
288+```
289+
290+### Tree View (Desktop - Compact)
291+
292+**Structure:**
293+```
294+┌─────────────────────────────────────────────────────────────┐
295+│ 📁 src/                          3 commits ago    ───      │
296+│ 📄 main.go                       2 hours ago      245 L    │
297+│ 📄 utils.go                      1 day ago        128 L    │
298+│ 📁 internal/                     5 days ago       ───      │
299+└─────────────────────────────────────────────────────────────┘
300+```
301+
302+**Styles:**
303+```css
304+.tree-row {
305+  display: flex;
306+  align-items: center;
307+  justify-content: space-between;
308+  padding: var(--space-2) var(--space-3);
309+  border-bottom: 1px solid rgba(98, 114, 164, 0.2);
310+  transition: background var(--transition-fast);
311+}
312+
313+.tree-row:hover {
314+  background: rgba(255, 255, 255, 0.03);
315+}
316+
317+.tree-row:last-child {
318+  border-bottom: none;
319+}
320+
321+.tree-icon {
322+  width: 16px;
323+  height: 16px;
324+  margin-right: var(--space-2);
325+  opacity: 0.8;
326+  transition: opacity var(--transition-fast);
327+}
328+
329+.tree-row:hover .tree-icon {
330+  opacity: 1;
331+}
332+
333+.tree-name {
334+  font-family: var(--font-mono);
335+  font-weight: 500;
336+  flex: 1;
337+}
338+
339+.tree-commit {
340+  font-size: 0.875rem;
341+  color: var(--grey-light);
342+  flex: 1;
343+  text-align: right;
344+  margin-right: var(--space-4);
345+}
346+
347+.tree-size {
348+  font-family: var(--font-mono);
349+  font-size: 0.8rem;
350+  color: var(--grey-light);
351+  min-width: 60px;
352+  text-align: right;
353+}
354+```
355+
356+### Tree View (Mobile - Touch Optimized)
357+
358+**Structure:**
359+```
360+┌────────────────────────────┐
361+│ 📄 main.go                 │
362+│    Updated 2 hours ago     │
363+├────────────────────────────┤
364+│ 📄 utils.go                │
365+│    Updated 1 day ago       │
366+└────────────────────────────┘
367+```
368+
369+**Mobile Styles:**
370+```css
371+@media (max-width: 768px) {
372+  .tree-row {
373+    flex-direction: column;
374+    align-items: flex-start;
375+    padding: var(--space-3);
376+    min-height: 60px; /* Touch target */
377+  }
378+  
379+  .tree-name {
380+    font-size: 1.05rem;
381+    font-weight: 600;
382+    margin-bottom: var(--space-1);
383+  }
384+  
385+  .tree-commit {
386+    display: none; /* Hidden on mobile */
387+  }
388+  
389+  .tree-size {
390+    display: none; /* Hidden on mobile */
391+  }
392+  
393+  .tree-meta-mobile {
394+    display: block;
395+    font-size: 0.875rem;
396+    color: var(--grey-light);
397+  }
398+}
399+```
400+
401+### Header Component
402+
403+**Structure:**
404+```
405+┌─────────────────────────────────────────────────────────────┐
406+│                                                             │
407+│   REPOSITORY NAME                    [nav pills...]         │
408+│   Repository description text                               │
409+│   git clone https://...                                     │
410+│                                                             │
411+└─────────────────────────────────────────────────────────────┘
412+```
413+
414+**Styles:**
415+```css
416+.site-header {
417+  padding: var(--space-6) 0;
418+  border-bottom: 1px solid var(--border);
419+  margin-bottom: var(--space-6);
420+}
421+
422+.repo-name {
423+  font-family: var(--font-display);
424+  font-size: 2rem;
425+  font-weight: 800;
426+  letter-spacing: -0.02em;
427+  margin: 0 0 var(--space-2) 0;
428+}
429+
430+.repo-name a {
431+  color: var(--text-color);
432+  text-decoration: none;
433+}
434+
435+.repo-desc {
436+  font-family: var(--font-body);
437+  font-size: 1rem;
438+  color: var(--grey-light);
439+  margin: var(--space-2) 0;
440+}
441+
442+.clone-cmd {
443+  font-family: var(--font-mono);
444+  font-size: 0.875rem;
445+  background: rgba(98, 114, 164, 0.15);
446+  padding: var(--space-2) var(--space-3);
447+  border-radius: 4px;
448+  margin-top: var(--space-3);
449+}
450+
451+/* Mobile header */
452+@media (max-width: 768px) {
453+  .site-header {
454+    padding: var(--space-4) 0;
455+  }
456+  
457+  .repo-name {
458+    font-size: 1.5rem;
459+  }
460+  
461+  .header-content {
462+    flex-direction: column;
463+    gap: var(--space-4);
464+  }
465+}
466+```
467+
468+### Breadcrumbs
469+
470+**Structure:**
471+```
472+src / components / Button.tsx
473+```
474+
475+**Styles:**
476+```css
477+.breadcrumbs {
478+  font-family: var(--font-mono);
479+  font-size: 0.9rem;
480+  margin-bottom: var(--space-4);
481+}
482+
483+.breadcrumbs a {
484+  color: var(--link-color);
485+  text-decoration: none;
486+}
487+
488+.breadcrumbs a:hover {
489+  text-decoration: underline;
490+}
491+
492+.breadcrumbs .current {
493+  font-weight: 600;
494+  color: var(--text-color);
495+}
496+
497+.breadcrumbs .separator {
498+  margin: 0 var(--space-2);
499+  opacity: 0.5;
500+}
501+```
502+
503+## Animations & Transitions
504+
505+### Global Transitions
506+```css
507+* {
508+  transition: background-color var(--transition-fast),
509+              border-color var(--transition-fast);
510+}
511+
512+a {
513+  transition: color var(--transition-fast),
514+              background var(--transition-fast),
515+              transform var(--transition-base),
516+              box-shadow var(--transition-base);
517+}
518+```
519+
520+### Hover Effects
521+
522+**Links:**
523+```css
524+a:hover {
525+  text-decoration: underline;
526+  text-decoration-thickness: 2px;
527+  text-underline-offset: 2px;
528+}
529+```
530+
531+**Buttons/Nav:**
532+```css
533+.btn:hover,
534+nav a:hover {
535+  transform: translateY(-2px);
536+  box-shadow: 0 4px 12px rgba(139, 233, 253, 0.15);
537+}
538+
539+.btn:active,
540+nav a:active {
541+  transform: translateY(0);
542+  box-shadow: none;
543+}
544+```
545+
546+**Commit Rows:**
547+```css
548+.commit-row {
549+  border-left: 2px solid transparent;
550+  transition: border-color var(--transition-fast),
551+              background var(--transition-fast),
552+              padding-left var(--transition-fast);
553+}
554+
555+.commit-row:hover {
556+  border-left-color: var(--link-color);
557+  background: rgba(139, 233, 253, 0.03);
558+  padding-left: calc(var(--space-3) + 2px);
559+}
560+```
561+
562+### Focus States (Accessibility)
563+```css
564+:focus-visible {
565+  outline: 2px solid var(--link-color);
566+  outline-offset: 2px;
567+}
568+
569+:focus:not(:focus-visible) {
570+  outline: none;
571+}
572+```
573+
574+## Responsive Breakpoints
575+
576+| Breakpoint | Width | Target |
577+|------------|-------|--------|
578+| sm | < 600px | Mobile |
579+| md | 600-900px | Tablet |
580+| lg | > 900px | Desktop |
581+
582+## Template Changes Required
583+
584+### base.layout.tmpl
585+- Add Google Fonts link in `<head>`
586+- Add `font-display` class to body or root
587+
588+### header.partial.tmpl
589+- Add `site-header` wrapper class
590+- Add `repo-name` class to h1
591+- Update navigation structure (remove pipes, add pill classes)
592+- Add mobile-friendly nav classes
593+
594+### log.page.tmpl
595+- Add `commit-graph` wrapper
596+- Add `commit-row` class to each commit
597+- Add `commit-dot` elements
598+- Add `commit-hash`, `commit-message`, `commit-meta` classes
599+
600+### tree.page.tmpl
601+- Add `tree-row` classes
602+- Add mobile-specific meta elements (conditionally hidden)
603+
604+### commit.page.tmpl
605+- Add typography classes to definition list
606+- Enhance diff file headers
607+
608+## Performance Considerations
609+
610+1. **Font Loading**: Use `display=swap` for Google Fonts to prevent FOIT
611+2. **CSS Variables**: All theme colors use CSS variables for instant theme switching
612+3. **No JavaScript**: All interactions are CSS-only for maximum performance
613+4. **Touch Targets**: Minimum 44px on mobile for accessibility
614+5. **Will-change**: Consider adding `will-change: transform` on frequently animated elements
615+
616+## Accessibility
617+
618+1. **Focus indicators**: Visible outline on all interactive elements
619+2. **Color contrast**: Works with existing Chroma themes (assume compliant)
620+3. **Touch targets**: Minimum 44x44px on mobile
621+4. **Reduced motion**: Respect `prefers-reduced-motion` media query
622+
623+```css
624+@media (prefers-reduced-motion: reduce) {
625+  *,
626+  *::before,
627+  *::after {
628+    animation-duration: 0.01ms !important;
629+    animation-iteration-count: 1 !important;
630+    transition-duration: 0.01ms !important;
631+  }
632+}
633+```
634+
635+## Future Enhancements (Out of Scope)
636+
637+- Dark/light mode toggle (requires JavaScript or CSS-only checkbox hack)
638+- Search functionality
639+- File preview modals
640+- Copy-to-clipboard buttons
A docs/plans/2025-04-07-design-implementation.md
+1385, -0
   1@@ -0,0 +1,1385 @@
   2+# Git Static Site Design Enhancement Implementation Plan
   3+
   4+> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
   5+
   6+**Goal:** Implement bold typography, visual hierarchy, CSS-only navigation with hover states, simple commit graph, and responsive tree view for the pgit static site generator.
   7+
   8+**Architecture:** Enhance existing CSS files (vars.css, smol.css, main.css) and minimal template updates to add Google Fonts, new component classes, and responsive design without JavaScript. The build system generates static HTML which uses these enhanced styles.
   9+
  10+**Tech Stack:** Go templates, CSS3 (variables, flexbox, grid, transitions), Google Fonts (Space Grotesk, Inter, JetBrains Mono)
  11+
  12+---
  13+
  14+## Testing Strategy
  15+
  16+Before and after each major change, use Playwright CLI to capture screenshots:
  17+
  18+```bash
  19+# Start test server
  20+python3 -m http.server 8888 --directory /home/btburke/projects/pgit/testdata.site &
  21+
  22+# Take screenshot of page
  23+playwright-cli open http://localhost:8888
  24+playwright-cli screenshot --filename=screenshot-index.png
  25+playwright-cli goto http://localhost:8888/logs/main/index.html
  26+playwright-cli screenshot --filename=screenshot-commits.png
  27+playwright-cli goto http://localhost:8888/tree/main/index.html
  28+playwright-cli screenshot --filename=screenshot-tree.png
  29+playwright-cli close
  30+```
  31+
  32+Compare screenshots to verify visual changes.
  33+
  34+---
  35+
  36+### Task 1: Update vars.css with Font Variables and Design Tokens
  37+
  38+**Files:**
  39+- Modify: `/home/btburke/projects/pgit/static/vars.css` (entire file)
  40+
  41+**Step 1: Add Google Fonts and CSS variables**
  42+
  43+The vars.css is copied to each generated site. Add the design tokens here.
  44+
  45+```css
  46+:root {
  47+  /* Existing theme colors (preserve) */
  48+  --bg-color: #282a36;
  49+  --text-color: #f8f8f2;
  50+  --border: #6272a4;
  51+  --link-color: #8be9fd;
  52+  --hover: #ff79c6;
  53+  --visited: #bd93f9;
  54+
  55+  /* Typography - Fonts */
  56+  --font-display: 'Space Grotesk', system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
  57+  --font-body: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
  58+  --font-mono: 'JetBrains Mono', 'Fira Code', 'Consolas', monospace;
  59+
  60+  /* Typography - Scale */
  61+  --text-xs: 0.75rem;
  62+  --text-sm: 0.875rem;
  63+  --text-base: 1rem;
  64+  --text-lg: 1.125rem;
  65+  --text-xl: 1.25rem;
  66+  --text-2xl: 1.5rem;
  67+  --text-3xl: 2rem;
  68+
  69+  /* Typography - Weights */
  70+  --font-normal: 400;
  71+  --font-medium: 500;
  72+  --font-semibold: 600;
  73+  --font-bold: 700;
  74+  --font-extrabold: 800;
  75+
  76+  /* Spacing */
  77+  --space-1: 0.25rem;
  78+  --space-2: 0.5rem;
  79+  --space-3: 0.75rem;
  80+  --space-4: 1rem;
  81+  --space-5: 1.5rem;
  82+  --space-6: 2rem;
  83+  --space-8: 2.5rem;
  84+
  85+  /* Transitions */
  86+  --transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);
  87+  --transition-base: 200ms cubic-bezier(0.4, 0, 0.2, 1);
  88+
  89+  /* Shadows */
  90+  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.1);
  91+  --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.15);
  92+
  93+  /* Layout */
  94+  --max-width: 900px;
  95+  --touch-target: 44px;
  96+}
  97+```
  98+
  99+**Step 2: Verify file exists and test site regeneration**
 100+
 101+Run: `make test-site`
 102+Expected: Site regenerates without errors
 103+
 104+**Step 3: Commit**
 105+
 106+```bash
 107+jj commit -m "design: add typography and design tokens to vars.css"
 108+```
 109+
 110+---
 111+
 112+### Task 2: Update smol.css with Typography and Base Styles
 113+
 114+**Files:**
 115+- Modify: `/home/btburke/projects/pgit/static/smol.css` (multiple sections)
 116+
 117+**Step 1: Update font-family definitions**
 118+
 119+Replace the html font-family block (lines 61-86):
 120+
 121+```css
 122+html {
 123+  background-color: var(--bg-color);
 124+  color: var(--text-color);
 125+  font-size: 16px;
 126+  line-height: 1.6;
 127+  font-family: var(--font-body);
 128+  -webkit-text-size-adjust: 100%;
 129+  -moz-tab-size: 4;
 130+  -o-tab-size: 4;
 131+  tab-size: 4;
 132+}
 133+```
 134+
 135+**Step 2: Update heading styles (lines 155-166)**
 136+
 137+Replace with:
 138+
 139+```css
 140+h1, h2, h3, h4 {
 141+  margin: 0;
 142+  padding: 0;
 143+  font-family: var(--font-display);
 144+  font-weight: var(--font-bold);
 145+  line-height: 1.2;
 146+}
 147+
 148+h1 {
 149+  font-size: var(--text-3xl);
 150+  font-weight: var(--font-extrabold);
 151+  letter-spacing: -0.02em;
 152+}
 153+
 154+h2 {
 155+  font-size: var(--text-xl);
 156+  font-weight: var(--font-bold);
 157+  letter-spacing: 0.05em;
 158+  text-transform: uppercase;
 159+}
 160+
 161+h3 {
 162+  font-size: var(--text-lg);
 163+  font-weight: var(--font-semibold);
 164+}
 165+
 166+h4 {
 167+  font-size: var(--text-base);
 168+  font-weight: var(--font-semibold);
 169+}
 170+```
 171+
 172+**Step 3: Update code/pre styles (lines 102-134)**
 173+
 174+Update font-family references:
 175+
 176+```css
 177+code, kbd, samp, pre {
 178+  font-family: var(--font-mono);
 179+}
 180+
 181+code, kbd, samp {
 182+  border: 2px solid var(--code);
 183+  font-size: 0.9rem;
 184+  font-weight: var(--font-medium);
 185+}
 186+
 187+pre {
 188+  font-size: 0.85rem;
 189+  line-height: 1.5;
 190+}
 191+```
 192+
 193+**Step 4: Add reduced motion support at end of file**
 194+
 195+Add to end of smol.css:
 196+
 197+```css
 198+/* Reduced motion support */
 199+@media (prefers-reduced-motion: reduce) {
 200+  *,
 201+  *::before,
 202+  *::after {
 203+    animation-duration: 0.01ms !important;
 204+    animation-iteration-count: 1 !important;
 205+    transition-duration: 0.01ms !important;
 206+    scroll-behavior: auto !important;
 207+  }
 208+}
 209+
 210+/* Focus visibility for accessibility */
 211+:focus-visible {
 212+  outline: 2px solid var(--link-color);
 213+  outline-offset: 2px;
 214+}
 215+
 216+:focus:not(:focus-visible) {
 217+  outline: none;
 218+}
 219+```
 220+
 221+**Step 5: Regenerate test site and verify**
 222+
 223+Run: `make test-site`
 224+Expected: No errors, fonts should be referenced (but not loaded yet without Google Fonts link)
 225+
 226+**Step 6: Commit**
 227+
 228+```bash
 229+jj commit -m "design: update smol.css with new typography system"
 230+```
 231+
 232+---
 233+
 234+### Task 3: Update base.layout.tmpl with Google Fonts
 235+
 236+**Files:**
 237+- Modify: `/home/btburke/projects/pgit/html/base.layout.tmpl`
 238+
 239+**Step 1: Add Google Fonts link**
 240+
 241+Insert after `<meta name="keywords"...>` and before `{{template "meta" .}}`:
 242+
 243+```html
 244+    <link rel="preconnect" href="https://fonts.googleapis.com">
 245+    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
 246+    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&family=Space+Grotesk:wght@500;600;700;800&display=swap" rel="stylesheet">
 247+```
 248+
 249+**Step 2: Add body font class**
 250+
 251+Update body tag:
 252+
 253+```html
 254+  <body class="font-body">
 255+```
 256+
 257+Full template should be:
 258+
 259+```html
 260+{{define "base"}}
 261+<!doctype html>
 262+<html lang="en">
 263+  <head>
 264+    <meta charset='utf-8'>
 265+    <meta name="viewport" content="width=device-width, initial-scale=1" />
 266+    <title>{{template "title" .}}</title>
 267+
 268+    <meta name="keywords" content="git code forge repo repository" />
 269+
 270+    <link rel="preconnect" href="https://fonts.googleapis.com">
 271+    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
 272+    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&family=Space+Grotesk:wght@500;600;700;800&display=swap" rel="stylesheet">
 273+
 274+    {{template "meta" .}}
 275+
 276+    <link rel="stylesheet" href="{{.Repo.RootRelative}}vars.css" />
 277+    <link rel="stylesheet" href="{{.Repo.RootRelative}}smol.css" />
 278+    <link rel="stylesheet" href="{{.Repo.RootRelative}}main.css" />
 279+  </head>
 280+  <body class="font-body">
 281+    <header class="site-header box">{{template "header" .}}</header>
 282+    <hr class="my" />
 283+    <main>{{template "content" .}}</main>
 284+    <hr class="my" />
 285+    <footer>{{template "footer" .}}</footer>
 286+  </body>
 287+</html>
 288+{{end}}
 289+```
 290+
 291+**Step 3: Regenerate test site**
 292+
 293+Run: `make test-site`
 294+Expected: No template errors
 295+
 296+**Step 4: Verify fonts load in browser**
 297+
 298+Open test site in browser, inspect element, verify Space Grotesk/Inter/JetBrains Mono are applied.
 299+
 300+**Step 5: Commit**
 301+
 302+```bash
 303+jj commit -m "design: add Google Fonts to base layout"
 304+```
 305+
 306+---
 307+
 308+### Task 4: Create Enhanced main.css with Component Styles
 309+
 310+**Files:**
 311+- Modify: `/home/btburke/projects/pgit/static/main.css` (rewrite with new styles)
 312+
 313+**Step 1: Write complete main.css**
 314+
 315+```css
 316+/* ========================================
 317+   PGIT DESIGN SYSTEM - COMPONENT STYLES
 318+   ======================================== */
 319+
 320+/* ---- Base ---- */
 321+body {
 322+  max-width: var(--max-width);
 323+  font-family: var(--font-body);
 324+}
 325+
 326+pre {
 327+  border: 1px solid var(--border);
 328+  padding: var(--grid-height);
 329+  background-color: var(--pre) !important;
 330+  font-family: var(--font-mono);
 331+  font-size: 0.85rem;
 332+  line-height: 1.5;
 333+}
 334+
 335+/* ---- Typography Utilities ---- */
 336+.font-display {
 337+  font-family: var(--font-display);
 338+}
 339+
 340+.font-body {
 341+  font-family: var(--font-body);
 342+}
 343+
 344+.font-mono {
 345+  font-family: var(--font-mono);
 346+}
 347+
 348+/* ---- Header ---- */
 349+.site-header {
 350+  padding: var(--space-6) 0;
 351+  border-bottom: 1px solid var(--border);
 352+  margin-bottom: var(--space-6);
 353+}
 354+
 355+.repo-name {
 356+  font-family: var(--font-display);
 357+  font-size: var(--text-3xl);
 358+  font-weight: var(--font-extrabold);
 359+  letter-spacing: -0.02em;
 360+  margin: 0 0 var(--space-2) 0;
 361+}
 362+
 363+.repo-name a {
 364+  color: var(--text-color);
 365+  text-decoration: none;
 366+  transition: color var(--transition-fast);
 367+}
 368+
 369+.repo-name a:hover {
 370+  color: var(--link-color);
 371+}
 372+
 373+.repo-desc {
 374+  font-family: var(--font-body);
 375+  font-size: var(--text-base);
 376+  color: var(--grey-light);
 377+  margin: var(--space-2) 0;
 378+}
 379+
 380+.clone-cmd {
 381+  font-family: var(--font-mono);
 382+  font-size: var(--text-sm);
 383+  background: rgba(98, 114, 164, 0.15);
 384+  padding: var(--space-2) var(--space-3);
 385+  border-radius: 4px;
 386+  margin-top: var(--space-3);
 387+}
 388+
 389+/* ---- Navigation (Desktop) ---- */
 390+.site-nav {
 391+  display: flex;
 392+  gap: var(--space-2);
 393+  flex-wrap: wrap;
 394+  margin: var(--space-4) 0;
 395+}
 396+
 397+.site-nav a {
 398+  font-family: var(--font-display);
 399+  font-weight: var(--font-semibold);
 400+  font-size: 0.9rem;
 401+  padding: var(--space-2) var(--space-4);
 402+  border: 1px solid var(--border);
 403+  border-radius: 4px;
 404+  text-decoration: none;
 405+  color: var(--link-color);
 406+  transition: all var(--transition-base);
 407+  display: inline-flex;
 408+  align-items: center;
 409+  justify-content: center;
 410+  min-height: 36px;
 411+}
 412+
 413+.site-nav a:hover {
 414+  background: var(--link-color);
 415+  color: var(--bg-color);
 416+  transform: translateY(-2px);
 417+  box-shadow: 0 4px 12px rgba(139, 233, 253, 0.15);
 418+  text-decoration: none;
 419+}
 420+
 421+.site-nav a:active {
 422+  transform: translateY(0);
 423+  box-shadow: none;
 424+}
 425+
 426+.site-nav .nav-current {
 427+  background: var(--link-color);
 428+  color: var(--bg-color);
 429+  font-weight: var(--font-bold);
 430+}
 431+
 432+/* ---- Navigation (Mobile) ---- */
 433+@media (max-width: 600px) {
 434+  .site-nav {
 435+    display: grid;
 436+    grid-template-columns: 1fr 1fr;
 437+  }
 438+  
 439+  .site-nav a {
 440+    text-align: center;
 441+    min-height: var(--touch-target);
 442+  }
 443+  
 444+  /* Full width for commits link */
 445+  .site-nav a[href*="commits"],
 446+  .site-nav a[href*="logs"] {
 447+    grid-column: 1 / -1;
 448+  }
 449+}
 450+
 451+/* ---- Commit List ---- */
 452+.commit-list {
 453+  display: flex;
 454+  flex-direction: column;
 455+  gap: var(--space-4);
 456+}
 457+
 458+.commit-row {
 459+  position: relative;
 460+  border-left: 2px solid transparent;
 461+  padding-left: var(--space-4);
 462+  transition: border-color var(--transition-fast),
 463+              background var(--transition-fast);
 464+}
 465+
 466+.commit-row:hover {
 467+  border-left-color: var(--link-color);
 468+  background: rgba(139, 233, 253, 0.03);
 469+}
 470+
 471+/* ---- Commit Graph ---- */
 472+.commit-graph {
 473+  position: relative;
 474+  padding-left: 1.75rem;
 475+}
 476+
 477+.commit-graph::before {
 478+  content: "";
 479+  position: absolute;
 480+  left: 0;
 481+  top: 0.5rem;
 482+  bottom: 0.5rem;
 483+  width: 2px;
 484+  background: var(--border);
 485+}
 486+
 487+.commit-dot {
 488+  position: absolute;
 489+  left: -5px;
 490+  top: 0.25rem;
 491+  width: 12px;
 492+  height: 12px;
 493+  border-radius: 50%;
 494+  background: var(--link-color);
 495+  border: 2px solid var(--bg-color);
 496+  box-shadow: 0 0 0 1px var(--border);
 497+}
 498+
 499+.commit-row:hover .commit-dot {
 500+  background: var(--hover);
 501+  transform: scale(1.1);
 502+  transition: transform var(--transition-fast);
 503+}
 504+
 505+/* Hide graph on mobile */
 506+@media (max-width: 600px) {
 507+  .commit-graph {
 508+    padding-left: 0;
 509+  }
 510+  
 511+  .commit-graph::before,
 512+  .commit-dot {
 513+    display: none;
 514+  }
 515+}
 516+
 517+/* ---- Commit Content ---- */
 518+.commit-header {
 519+  display: flex;
 520+  justify-content: space-between;
 521+  align-items: center;
 522+  gap: var(--space-3);
 523+  flex-wrap: wrap;
 524+}
 525+
 526+.commit-hash {
 527+  font-family: var(--font-mono);
 528+  font-weight: var(--font-semibold);
 529+  font-size: 0.9rem;
 530+  color: var(--link-color);
 531+  letter-spacing: 0.02em;
 532+}
 533+
 534+.commit-hash:hover {
 535+  color: var(--hover);
 536+}
 537+
 538+.commit-message {
 539+  font-family: var(--font-body);
 540+  font-size: 1.05rem;
 541+  font-weight: var(--font-medium);
 542+  line-height: 1.5;
 543+  margin: var(--space-2) 0;
 544+  color: var(--text-color);
 545+}
 546+
 547+.commit-meta {
 548+  font-size: var(--text-sm);
 549+  color: var(--grey-light);
 550+  font-weight: var(--font-medium);
 551+  display: flex;
 552+  align-items: center;
 553+  gap: var(--space-2);
 554+}
 555+
 556+.commit-meta-separator {
 557+  opacity: 0.5;
 558+}
 559+
 560+.commit-refs {
 561+  display: inline-flex;
 562+  gap: var(--space-1);
 563+}
 564+
 565+.commit-ref {
 566+  font-family: var(--font-mono);
 567+  font-size: 0.8rem;
 568+  padding: 0.15rem var(--space-2);
 569+  border: 1px solid var(--link-color);
 570+  border-radius: 3px;
 571+  color: var(--link-color);
 572+  font-weight: var(--font-semibold);
 573+}
 574+
 575+/* ---- Tree View ---- */
 576+.tree-list {
 577+  border: 1px solid var(--border);
 578+  border-radius: 4px;
 579+  overflow: hidden;
 580+}
 581+
 582+.tree-row {
 583+  display: flex;
 584+  align-items: center;
 585+  justify-content: space-between;
 586+  padding: var(--space-2) var(--space-3);
 587+  border-bottom: 1px solid rgba(98, 114, 164, 0.2);
 588+  transition: background var(--transition-fast);
 589+}
 590+
 591+.tree-row:hover {
 592+  background: rgba(255, 255, 255, 0.03);
 593+}
 594+
 595+.tree-row:last-child {
 596+  border-bottom: none;
 597+}
 598+
 599+.tree-icon {
 600+  width: 16px;
 601+  height: 16px;
 602+  margin-right: var(--space-2);
 603+  opacity: 0.8;
 604+  transition: opacity var(--transition-fast);
 605+  flex-shrink: 0;
 606+}
 607+
 608+.tree-row:hover .tree-icon {
 609+  opacity: 1;
 610+}
 611+
 612+.tree-name {
 613+  font-family: var(--font-mono);
 614+  font-weight: var(--font-medium);
 615+  flex: 1;
 616+  display: flex;
 617+  align-items: center;
 618+}
 619+
 620+.tree-name a {
 621+  color: var(--link-color);
 622+  text-decoration: none;
 623+}
 624+
 625+.tree-name a:hover {
 626+  text-decoration: underline;
 627+  text-decoration-thickness: 2px;
 628+  text-underline-offset: 2px;
 629+}
 630+
 631+.tree-commit {
 632+  font-size: var(--text-sm);
 633+  color: var(--grey-light);
 634+  flex: 1;
 635+  text-align: right;
 636+  margin-right: var(--space-4);
 637+  white-space: nowrap;
 638+  overflow: hidden;
 639+  text-overflow: ellipsis;
 640+}
 641+
 642+.tree-commit a {
 643+  color: var(--grey-light);
 644+  text-decoration: none;
 645+}
 646+
 647+.tree-commit a:hover {
 648+  color: var(--link-color);
 649+}
 650+
 651+.tree-size {
 652+  font-family: var(--font-mono);
 653+  font-size: 0.8rem;
 654+  color: var(--grey-light);
 655+  min-width: 60px;
 656+  text-align: right;
 657+  flex-shrink: 0;
 658+}
 659+
 660+.tree-meta-mobile {
 661+  display: none;
 662+  font-size: var(--text-sm);
 663+  color: var(--grey-light);
 664+  margin-top: var(--space-1);
 665+}
 666+
 667+/* Tree View Mobile */
 668+@media (max-width: 768px) {
 669+  .tree-row {
 670+    flex-direction: column;
 671+    align-items: flex-start;
 672+    padding: var(--space-3);
 673+    min-height: 60px;
 674+  }
 675+  
 676+  .tree-name {
 677+    font-size: 1.05rem;
 678+    font-weight: var(--font-semibold);
 679+    margin-bottom: var(--space-1);
 680+  }
 681+  
 682+  .tree-commit {
 683+    display: none;
 684+  }
 685+  
 686+  .tree-size {
 687+    display: none;
 688+  }
 689+  
 690+  .tree-meta-mobile {
 691+    display: block;
 692+  }
 693+}
 694+
 695+/* ---- Breadcrumbs ---- */
 696+.breadcrumbs {
 697+  font-family: var(--font-mono);
 698+  font-size: 0.95rem;
 699+  margin-bottom: var(--space-4);
 700+  display: flex;
 701+  align-items: center;
 702+  flex-wrap: wrap;
 703+  gap: var(--space-2);
 704+}
 705+
 706+.breadcrumbs a {
 707+  color: var(--link-color);
 708+  text-decoration: none;
 709+  font-weight: var(--font-medium);
 710+}
 711+
 712+.breadcrumbs a:hover {
 713+  text-decoration: underline;
 714+  text-decoration-thickness: 2px;
 715+}
 716+
 717+.breadcrumbs .current {
 718+  font-weight: var(--font-bold);
 719+  color: var(--text-color);
 720+}
 721+
 722+.breadcrumbs .separator {
 723+  opacity: 0.5;
 724+  color: var(--grey-light);
 725+}
 726+
 727+/* ---- Diff View ---- */
 728+.diff-file {
 729+  align-items: center;
 730+  height: 62px;
 731+  position: sticky;
 732+  top: 0;
 733+  left: 0;
 734+  background-color: var(--bg-color);
 735+  border-bottom: 1px solid var(--border);
 736+  padding: var(--space-2) var(--space-3);
 737+  font-family: var(--font-mono);
 738+  font-size: 0.9rem;
 739+}
 740+
 741+.diff-file a {
 742+  color: var(--link-color);
 743+  font-weight: var(--font-semibold);
 744+}
 745+
 746+.color-green {
 747+  color: #50fa7b;
 748+  font-weight: var(--font-semibold);
 749+}
 750+
 751+.color-red {
 752+  color: #ff5555;
 753+  font-weight: var(--font-semibold);
 754+}
 755+
 756+/* ---- Utility Classes ---- */
 757+.border-b {
 758+  border-bottom: 1px solid var(--border);
 759+}
 760+
 761+.border-b:last-child {
 762+  border-bottom: 0;
 763+}
 764+
 765+.box {
 766+  margin: 1rem 0;
 767+  padding: var(--grid-height);
 768+  border: 1px solid var(--border);
 769+  border-radius: 4px;
 770+}
 771+
 772+.white-space-bs {
 773+  white-space: break-spaces;
 774+}
 775+
 776+.mb-0 {
 777+  margin-bottom: 0;
 778+}
 779+
 780+/* ---- Section Headers ---- */
 781+.section-title {
 782+  font-family: var(--font-display);
 783+  font-size: var(--text-xl);
 784+  font-weight: var(--font-bold);
 785+  letter-spacing: 0.05em;
 786+  text-transform: uppercase;
 787+  margin-bottom: var(--space-4);
 788+  color: var(--text-color);
 789+}
 790+
 791+/* ---- Footer ---- */
 792+.site-footer {
 793+  text-align: center;
 794+  padding-top: var(--space-4);
 795+  border-top: 1px solid var(--border);
 796+  margin-top: var(--space-6);
 797+  font-size: var(--text-sm);
 798+  color: var(--grey-light);
 799+}
 800+
 801+.site-footer a {
 802+  color: var(--link-color);
 803+  font-weight: var(--font-medium);
 804+}
 805+
 806+/* ---- Mobile Header ---- */
 807+@media (max-width: 768px) {
 808+  .site-header {
 809+    padding: var(--space-4) 0;
 810+  }
 811+  
 812+  .repo-name {
 813+    font-size: var(--text-2xl);
 814+  }
 815+  
 816+  .header-content {
 817+    flex-direction: column;
 818+    gap: var(--space-4);
 819+  }
 820+  
 821+  .clone-cmd {
 822+    font-size: 0.75rem;
 823+    overflow-x: auto;
 824+  }
 825+}
 826+
 827+/* ---- Definition Lists (Commit Details) ---- */
 828+dl {
 829+  margin: var(--space-4) 0;
 830+}
 831+
 832+dt {
 833+  font-family: var(--font-display);
 834+  font-weight: var(--font-semibold);
 835+  font-size: var(--text-sm);
 836+  text-transform: uppercase;
 837+  letter-spacing: 0.05em;
 838+  color: var(--grey-light);
 839+  margin-top: var(--space-3);
 840+}
 841+
 842+dd {
 843+  margin-left: 0;
 844+  font-family: var(--font-body);
 845+  margin-top: var(--space-1);
 846+}
 847+
 848+dd a {
 849+  font-family: var(--font-mono);
 850+  color: var(--link-color);
 851+}
 852+
 853+/* ---- Links Enhancement ---- */
 854+a {
 855+  transition: color var(--transition-fast),
 856+              background var(--transition-fast),
 857+              transform var(--transition-base),
 858+              box-shadow var(--transition-base);
 859+}
 860+
 861+a:hover {
 862+  text-decoration-thickness: 2px;
 863+  text-underline-offset: 2px;
 864+}
 865+
 866+/* ---- Existing responsive rules (preserve) ---- */
 867+@media only screen and (max-width: 900px) {
 868+  .tree-commit {
 869+    display: none;
 870+  }
 871+}
 872+```
 873+
 874+**Step 2: Regenerate test site**
 875+
 876+Run: `make test-site`
 877+Expected: CSS file copied successfully
 878+
 879+**Step 3: Take screenshot and verify styles applied**
 880+
 881+```bash
 882+playwright-cli open http://localhost:8888
 883+playwright-cli screenshot --filename=main-css-applied.png
 884+```
 885+
 886+**Step 4: Commit**
 887+
 888+```bash
 889+jj commit -m "design: add complete component styles to main.css"
 890+```
 891+
 892+---
 893+
 894+### Task 5: Update header.partial.tmpl with New Structure
 895+
 896+**Files:**
 897+- Modify: `/home/btburke/projects/pgit/html/header.partial.tmpl`
 898+
 899+**Step 1: Rewrite template with new classes**
 900+
 901+```html
 902+{{define "header"}}
 903+<div class="header-content flex flex-col">
 904+  <h1 class="repo-name p-0">
 905+    {{if .SiteURLs.HomeURL}}
 906+      <a href="{{.SiteURLs.HomeURL}}">repos</a>
 907+      <span>/</span>
 908+    {{end}}
 909+    <span>{{.Repo.RepoName}}</span>
 910+  </h1>
 911+
 912+  <nav class="site-nav">
 913+    <a href="{{.SiteURLs.SummaryURL}}">summary</a>
 914+    <a href="{{.SiteURLs.RefsURL}}">refs</a>
 915+    <span class="nav-current">{{.RevData.Name}}</span>
 916+    <a href="{{.RevData.TreeURL}}">code</a>
 917+    <a href="{{.RevData.LogURL}}">commits</a>
 918+  </nav>
 919+
 920+  <div>
 921+    <div class="repo-desc">{{.Repo.Desc}}</div>
 922+    {{if .SiteURLs.CloneURL}}<pre class="clone-cmd mb-0">git clone {{.SiteURLs.CloneURL}}</pre>{{end}}
 923+  </div>
 924+</div>
 925+{{end}}
 926+```
 927+
 928+**Step 2: Regenerate test site**
 929+
 930+Run: `make test-site`
 931+Expected: No template errors
 932+
 933+**Step 3: Verify navigation renders as pills**
 934+
 935+Check that pipes are removed and each nav item is a separate element.
 936+
 937+**Step 4: Commit**
 938+
 939+```bash
 940+jj commit -m "design: update header template with new navigation structure"
 941+```
 942+
 943+---
 944+
 945+### Task 6: Update log.page.tmpl with Commit Graph
 946+
 947+**Files:**
 948+- Modify: `/home/btburke/projects/pgit/html/log.page.tmpl`
 949+
 950+**Step 1: Rewrite with commit graph and new classes**
 951+
 952+```html
 953+{{template "base" .}}
 954+
 955+{{define "title"}}commits - {{.Repo.RepoName}}@{{.RevData.Name}}{{end}}
 956+{{define "meta"}}{{end}}
 957+
 958+{{define "content"}}
 959+  <h2 class="section-title">{{.NumCommits}} commits</h2>
 960+  
 961+  <div class="commit-graph">
 962+    {{range .Logs}}
 963+      <div class="commit-row">
 964+        <div class="commit-dot"></div>
 965+        
 966+        <div class="commit-header">
 967+          <a href="{{.URL}}" class="commit-hash">{{.ShortID}}</a>
 968+
 969+          <div class="commit-refs">
 970+            {{range .Refs}}
 971+              {{if .URL}}
 972+                <a href="{{.URL}}" class="commit-ref">{{.Refspec}}</a>
 973+              {{else}}
 974+                <span class="commit-ref">{{.Refspec}}</span>
 975+              {{end}}
 976+            {{end}}
 977+          </div>
 978+        </div>
 979+
 980+        <div class="commit-message">
 981+          <pre class="m-0 white-space-bs">{{.Message}}</pre>
 982+        </div>
 983+
 984+        <div class="commit-meta">
 985+          <span>{{.AuthorStr}}</span>
 986+          <span class="commit-meta-separator">·</span>
 987+          <span>{{.WhenStr}}</span>
 988+        </div>
 989+      </div>
 990+    {{end}}
 991+  </div>
 992+{{end}}
 993+```
 994+
 995+**Step 2: Regenerate test site**
 996+
 997+Run: `make test-site`
 998+Expected: Template renders successfully
 999+
1000+**Step 3: Verify commit graph appears**
1001+
1002+Check for vertical line and commit dots on desktop.
1003+
1004+**Step 4: Commit**
1005+
1006+```bash
1007+jj commit -m "design: add commit graph and enhanced commit list styling"
1008+```
1009+
1010+---
1011+
1012+### Task 7: Update tree.page.tmpl with Mobile-Optimized Layout
1013+
1014+**Files:**
1015+- Modify: `/home/btburke/projects/pgit/html/tree.page.tmpl`
1016+
1017+**Step 1: Rewrite with enhanced tree styling and mobile meta**
1018+
1019+```html
1020+{{template "base" .}}
1021+
1022+{{define "title"}}files - {{.Repo.RepoName}}@{{.RevData.Name}}{{end}}
1023+{{define "meta"}}{{end}}
1024+
1025+{{define "content"}}
1026+  <nav class="breadcrumbs">
1027+    {{range .Tree.Crumbs}}
1028+      {{if .IsLast}}
1029+        <span class="current">{{.Text}}</span>
1030+      {{else}}
1031+        <a href="{{.URL}}">{{.Text}}</a>
1032+        {{if not .IsLast}}<span class="separator">/</span>{{end}}
1033+      {{end}}
1034+    {{end}}
1035+  </nav>
1036+
1037+  <div class="tree-list">
1038+    {{range .Tree.Items}}
1039+      <div class="tree-row">
1040+        <div class="tree-name">
1041+          {{if .IsDir}}
1042+            <svg class="tree-icon" xmlns="http://www.w3.org/2000/svg" fill="currentColor" height="16" width="16" viewBox="0 0 512 512">
1043+              <path d="M0 96C0 60.7 28.7 32 64 32H196.1c19.1 0 37.4 7.6 50.9 21.1L289.9 96H448c35.3 0 64 28.7 64 64V416c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V96zM64 80c-8.8 0-16 7.2-16 16V416c0 8.8 7.2 16 16 16H448c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16H286.6c-10.6 0-20.8-4.2-28.3-11.7L213.1 87c-4.5-4.5-10.6-7-17-7H64z"/>
1044+            </svg>
1045+          {{else}}
1046+            <svg class="tree-icon" xmlns="http://www.w3.org/2000/svg" fill="currentColor" height="16" width="16" viewBox="0 0 384 512">
1047+              <path d="M320 464c8.8 0 16-7.2 16-16V160H256c-17.7 0-32-14.3-32-32V48H64c-8.8 0-16 7.2-16 16V448c0 8.8 7.2 16 16 16H320zM0 64C0 28.7 28.7 0 64 0H229.5c17 0 33.3 6.7 45.3 18.7l90.5 90.5c12 12 18.7 28.3 18.7 45.3V448c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V64z"/>
1048+            </svg>
1049+          {{end}}
1050+
1051+          <a href="{{.URL}}">{{.Name}}</a>
1052+        </div>
1053+
1054+        {{if not $.Repo.HideTreeLastCommit}}
1055+        <div class="tree-commit">
1056+          <a href="{{.CommitURL}}" title="{{.Summary}}">{{.When}}</a>
1057+        </div>
1058+        {{end}}
1059+        
1060+        <div class="tree-size">
1061+          {{if .IsDir}}
1062+          {{else}}
1063+            {{if .IsTextFile}}{{.NumLines}} L{{else}}{{.Size}}{{end}}
1064+          {{end}}
1065+        </div>
1066+        
1067+        <!-- Mobile-only meta -->
1068+        {{if not $.Repo.HideTreeLastCommit}}
1069+        <div class="tree-meta-mobile">
1070+          {{.When}}
1071+        </div>
1072+        {{end}}
1073+      </div>
1074+    {{end}}
1075+  </div>
1076+{{end}}
1077+```
1078+
1079+**Step 2: Regenerate test site**
1080+
1081+Run: `make test-site`
1082+Expected: Template renders successfully
1083+
1084+**Step 3: Test mobile view**
1085+
1086+Use Playwright to resize and verify mobile layout hides commit info properly.
1087+
1088+```bash
1089+playwright-cli open http://localhost:8888/tree/main/index.html
1090+playwright-cli resize 375 812
1091+playwright-cli screenshot --filename=tree-mobile.png
1092+```
1093+
1094+**Step 4: Commit**
1095+
1096+```bash
1097+jj commit -m "design: update tree view with mobile-optimized layout"
1098+```
1099+
1100+---
1101+
1102+### Task 8: Update commit.page.tmpl with Enhanced Styles
1103+
1104+**Files:**
1105+- Modify: `/home/btburke/projects/pgit/html/commit.page.tmpl`
1106+
1107+**Step 1: Add classes to enhance commit detail page**
1108+
1109+```html
1110+{{template "base" .}}
1111+{{define "title"}}{{.Commit.Summary}} - {{.Repo.RepoName}}@{{.CommitID}}{{end}}
1112+{{define "meta"}}
1113+<link rel="stylesheet" href="{{.Repo.RootRelative}}syntax.css" />
1114+{{end}}
1115+
1116+{{define "content"}}
1117+  <dl>
1118+    <dt>commit</dt>
1119+    <dd><a href="{{.CommitURL}}" class="commit-hash">{{.CommitID}}</a></dd>
1120+
1121+    <dt>parent</dt>
1122+    <dd><a href="{{.ParentURL}}" class="commit-hash">{{.Parent}}</a></dd>
1123+
1124+    <dt>author</dt>
1125+    <dd>{{.Commit.Author.Name}}</dd>
1126+
1127+    <dt>date</dt>
1128+    <dd>{{.Commit.Author.When}}</dd>
1129+  </dl>
1130+
1131+  <pre class="commit-message white-space-bs">{{.Commit.Message}}</pre>
1132+
1133+  <div class="box mono">
1134+    <div>
1135+      <strong>{{.Diff.NumFiles}}</strong> files changed,&nbsp;
1136+      <span class="color-green">+{{.Diff.TotalAdditions}}</span>,
1137+      <span class="color-red">-{{.Diff.TotalDeletions}}</span>
1138+    </div>
1139+
1140+    <div class="mt">
1141+    {{range .Diff.Files}}
1142+      <div class="my-sm">
1143+        <span>{{.FileType}}</span>
1144+        <a href="#diff-{{.Name}}">{{.Name}}</a>
1145+      </div>
1146+    {{end}}
1147+    </div>
1148+  </div>
1149+
1150+  {{range .Diff.Files}}
1151+    <div id="diff-{{.Name}}" class="diff-file flex justify-between">
1152+      <div>
1153+        <span>{{.FileType}} {{if eq .FileType "R"}}{{.OldName}} => {{end}}</span>
1154+        <a href="#diff-{{.Name}}">{{.Name}}</a>
1155+      </div>
1156+
1157+      <div>
1158+        <span class="color-green">+{{.NumAdditions}}</span>,
1159+        <span class="color-red">-{{.NumDeletions}}</span>
1160+      </div>
1161+    </div>
1162+
1163+    {{.Content}}
1164+  {{end}}
1165+{{end}}
1166+```
1167+
1168+**Step 2: Regenerate test site**
1169+
1170+Run: `make test-site`
1171+
1172+**Step 3: Commit**
1173+
1174+```bash
1175+jj commit -m "design: enhance commit detail page with typography classes"
1176+```
1177+
1178+---
1179+
1180+### Task 9: Update refs.page.tmpl with Section Title
1181+
1182+**Files:**
1183+- Modify: `/home/btburke/projects/pgit/html/refs.page.tmpl`
1184+
1185+**Step 1: Add section title class**
1186+
1187+```html
1188+{{template "base" .}}
1189+
1190+{{define "title"}}refs - {{.Repo.RepoName}}{{end}}
1191+{{define "meta"}}{{end}}
1192+
1193+{{define "content"}}
1194+  <h2 class="section-title">refs</h2>
1195+
1196+  <ul class="tree-list">
1197+  {{range .Refs}}
1198+    {{if .URL}}
1199+      <li class="tree-row"><a href="{{.URL}}">{{.Refspec}}</a></li>
1200+    {{else}}
1201+      <li class="tree-row">{{.Refspec}}</li>
1202+    {{end}}
1203+  {{end}}
1204+  </ul>
1205+{{end}}
1206+```
1207+
1208+**Step 2: Regenerate and commit**
1209+
1210+Run: `make test-site`
1211+
1212+```bash
1213+jj commit -m "design: update refs page with section styling"
1214+```
1215+
1216+---
1217+
1218+### Task 10: Update footer.partial.tmpl with Site Footer Class
1219+
1220+**Files:**
1221+- Modify: `/home/btburke/projects/pgit/html/footer.partial.tmpl`
1222+
1223+**Step 1: Add site-footer class**
1224+
1225+```html
1226+{{define "footer"}}
1227+<div class="site-footer">
1228+  <div>
1229+    built with <a href="https://pgit.pico.sh">pgit</a>
1230+  </div>
1231+</div>
1232+{{end}}
1233+```
1234+
1235+**Step 2: Regenerate and commit**
1236+
1237+Run: `make test-site`
1238+
1239+```bash
1240+jj commit -m "design: add site-footer class to footer template"
1241+```
1242+
1243+---
1244+
1245+### Task 11: Update file.page.tmpl with Breadcrumbs
1246+
1247+**Files:**
1248+- Modify: `/home/btburke/projects/pgit/html/file.page.tmpl`
1249+
1250+**Step 1: Add breadcrumbs class and section title**
1251+
1252+```html
1253+{{template "base" .}}
1254+{{define "title"}}{{.Item.Path}}@{{.RevData.Name}}{{end}}
1255+{{define "meta"}}
1256+<link rel="stylesheet" href="{{.Repo.RootRelative}}syntax.css" />
1257+{{end}}
1258+
1259+{{define "content"}}
1260+  <nav class="breadcrumbs">
1261+    {{range .Item.Crumbs}}
1262+      <a href="{{.URL}}">{{.Text}}</a>
1263+      {{if not .IsLast}}<span class="separator">/</span>{{end}}
1264+    {{end}}
1265+  </nav>
1266+
1267+  {{if not .Repo.HideTreeLastCommit}}
1268+  <div class="box">
1269+    <div class="flex items-center justify-between">
1270+      <div class="flex-1">
1271+        <a href="{{.Item.CommitURL}}">{{.Item.Summary}}</a>
1272+      </div>
1273+      <div class="mono">
1274+        <a href="{{.Item.CommitURL}}" class="commit-hash">{{.Item.CommitID}}</a>
1275+      </div>
1276+    </div>
1277+
1278+    <div class="commit-meta mt">
1279+      <span>{{.Item.Author.Name}}</span>
1280+      <span class="commit-meta-separator">·</span>
1281+      <span>{{.Item.When}}</span>
1282+    </div>
1283+  </div>
1284+  {{end}}
1285+
1286+  <h2 class="section-title">{{.Item.Name}}</h2>
1287+
1288+  {{.Contents}}
1289+{{end}}
1290+```
1291+
1292+**Step 2: Regenerate and commit**
1293+
1294+Run: `make test-site`
1295+
1296+```bash
1297+jj commit -m "design: update file page with breadcrumbs and styling"
1298+```
1299+
1300+---
1301+
1302+### Task 12: Final Testing and Screenshot Comparison
1303+
1304+**Files:** None (verification only)
1305+
1306+**Step 1: Regenerate complete test site**
1307+
1308+```bash
1309+make test-site
1310+```
1311+
1312+**Step 2: Start server and capture screenshots**
1313+
1314+```bash
1315+python3 -m http.server 8888 --directory /home/btburke/projects/pgit/testdata.site &
1316+```
1317+
1318+**Step 3: Capture desktop screenshots**
1319+
1320+```bash
1321+playwright-cli open http://localhost:8888
1322+playwright-cli screenshot --filename=final-desktop-home.png
1323+playwright-cli goto http://localhost:8888/logs/main/index.html
1324+playwright-cli screenshot --filename=final-desktop-commits.png
1325+playwright-cli goto http://localhost:8888/tree/main/index.html
1326+playwright-cli screenshot --filename=final-desktop-tree.png
1327+playwright-cli goto http://localhost:8888/commits/93ec21917415ae74afec3fab3e734145b75019fc.html
1328+playwright-cli screenshot --filename=final-desktop-commit.png
1329+```
1330+
1331+**Step 4: Capture mobile screenshots**
1332+
1333+```bash
1334+playwright-cli resize 375 812
1335+playwright-cli goto http://localhost:8888
1336+playwright-cli screenshot --filename=final-mobile-home.png
1337+playwright-cli goto http://localhost:8888/logs/main/index.html
1338+playwright-cli screenshot --filename=final-mobile-commits.png
1339+playwright-cli goto http://localhost:8888/tree/main/index.html
1340+playwright-cli screenshot --filename=final-mobile-tree.png
1341+```
1342+
1343+**Step 5: Verify all screenshots show:**
1344+- Google Fonts loaded (Space Grotesk, Inter, JetBrains Mono visible)
1345+- Navigation as pill buttons
1346+- Commit graph visible on desktop (vertical line with dots)
1347+- Tree view compact on desktop, stacked on mobile
1348+- Proper spacing and typography hierarchy
1349+- Hover states work (test manually)
1350+
1351+**Step 6: Final commit**
1352+
1353+```bash
1354+jj commit -m "design: complete visual enhancement implementation"
1355+```
1356+
1357+---
1358+
1359+## Summary of Changes
1360+
1361+### Files Modified
1362+
1363+1. `/home/btburke/projects/pgit/static/vars.css` - Added design tokens
1364+2. `/home/btburke/projects/pgit/static/smol.css` - Updated typography base
1365+3. `/home/btburke/projects/pgit/static/main.css` - Complete component styles
1366+4. `/home/btburke/projects/pgit/html/base.layout.tmpl` - Added Google Fonts
1367+5. `/home/btburke/projects/pgit/html/header.partial.tmpl` - New nav structure
1368+6. `/home/btburke/projects/pgit/html/log.page.tmpl` - Commit graph
1369+7. `/home/btburke/projects/pgit/html/tree.page.tmpl` - Mobile tree view
1370+8. `/home/btburke/projects/pgit/html/commit.page.tmpl` - Enhanced styling
1371+9. `/home/btburke/projects/pgit/html/refs.page.tmpl` - Section styling
1372+10. `/home/btburke/projects/pgit/html/file.page.tmpl` - Breadcrumbs
1373+11. `/home/btburke/projects/pgit/html/footer.partial.tmpl` - Footer class
1374+
1375+### Key Features Implemented
1376+
1377+- ✅ Bold typography (Space Grotesk headers, Inter body, JetBrains Mono code)
1378+- ✅ Visual hierarchy with proper font weights and sizes
1379+- ✅ CSS-only pill navigation with hover effects
1380+- ✅ Mobile-optimized navigation (2-column grid, touch targets)
1381+- ✅ Simple commit graph (vertical line with dots)
1382+- ✅ Compact tree view on desktop
1383+- ✅ Mobile tree view (hidden commit/size info, larger touch targets)
1384+- ✅ Smooth transitions (150-200ms)
1385+- ✅ Accessible focus states
1386+- ✅ Respects color scheme from Chroma
A docs/plans/2026-04-07-design-update-design.md
+29, -0
 1@@ -0,0 +1,29 @@
 2+# High-Contrast Technical Design Upgrade
 3+
 4+## Goal
 5+Improve the design of the Git hosting static site by applying a "High-Contrast Technical" aesthetic. This involves bold typography, strong visual hierarchy, denser spacing, and CSS-only interactive elements to make the interface more readable and visually appealing.
 6+
 7+## Architecture & Aesthetics
 8+- **Typography:** Mix of a clean sans-serif for UI/menus and monospace for code/commits.
 9+- **Visual Hierarchy:** Heavy font weights (e.g., 800) for primary information (commit messages, active states), muted colors (`var(--grey-light)`) for secondary metadata (author, date).
10+- **Density:** Tightly packed related information with generous whitespace between distinct blocks (e.g., between individual commits).
11+- **Interactivity:** Pure CSS hover states (color changes, borders) on menus and commit lists.
12+
13+## Components
14+
15+### Header and Navigation
16+- **Header (`header.partial.tmpl`):** Repository name in bold sans-serif.
17+- **Menu Layout:** Replace inline `|` separators with a flex container (`gap: 1rem`).
18+- **Links (`nav a`):** Styled as tabs. Default: muted (`var(--grey-light)`), bold. Hover: bright (`var(--text-color)`), crisp bottom border (using `border-bottom` or `::after`).
19+- **Active State (`nav span.font-bold`):** Matches hover style (bright text, bottom border).
20+
21+### Commit List (`log.page.tmpl`)
22+- **Typography:** Commit message (subject) is bold and larger. Metadata (author, date, short hash) is smaller (`var(--text-sm)`) and muted (`var(--grey-light)`).
23+- **Spacing:** Tight packing within a commit block, but larger margin (`margin-bottom: 1.5rem`) between commits.
24+- **Refs (`.Refspec`):** High-contrast pill shape (solid background/bright border).
25+- **Hover State:** Subtle background color change on the entire commit block (`div.group-2 > div:hover`).
26+
27+### Commit Detail (`commit.page.tmpl`)
28+- **Typography:** Main commit message treated as a major heading (large, bold, high contrast).
29+- **Metadata (`dl`):** Styled as a dense, two-column grid (`display: grid; grid-template-columns: max-content 1fr; gap: 0.5rem 1rem;`). Labels (`dt`) right-aligned and muted; values (`dd`) bold.
30+- **Diff Headers (`.diff-file`):** Enhanced sticky headers with a distinct, slightly darker background color and a bottom border.
A docs/plans/2026-04-07-high-contrast-ui-design-plan.md
+269, -0
  1@@ -0,0 +1,269 @@
  2+# High-Contrast Technical UI Upgrade Implementation Plan
  3+
  4+> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
  5+
  6+**Goal:** Implement a "High-Contrast Technical" aesthetic to improve typography, visual hierarchy, density, and CSS-only interactive elements across the Git hosting site templates.
  7+
  8+**Architecture:** We will modify the CSS (`static/main.css`, `static/smol.css`) and HTML templates (`html/header.partial.tmpl`, `html/log.page.tmpl`, `html/commit.page.tmpl`). We will rely purely on CSS for hover effects, spacing, and typography without adding any JavaScript.
  9+
 10+**Tech Stack:** Go HTML Templates, CSS
 11+
 12+---
 13+
 14+### Task 1: Header and Navigation Menu Redesign
 15+
 16+**Files:**
 17+- Modify: `html/header.partial.tmpl`
 18+- Modify: `static/main.css`
 19+
 20+**Step 1: Update the Navigation HTML**
 21+Remove the `|` separators from the `<nav>` element and structure it to easily support flexbox gaps.
 22+
 23+```html
 24+<!-- html/header.partial.tmpl -->
 25+<!-- REPLACE existing <nav> block with: -->
 26+<nav class="flex gap items-center nav-menu">
 27+  <a href="{{.SiteURLs.SummaryURL}}">summary</a>
 28+  <a href="{{.SiteURLs.RefsURL}}">refs</a>
 29+  <span class="active">{{.RevData.Name}}</span>
 30+  <a href="{{.RevData.TreeURL}}">code</a>
 31+  <a href="{{.RevData.LogURL}}">commits</a>
 32+</nav>
 33+```
 34+
 35+**Step 2: Add CSS for the new Header/Nav**
 36+Update `static/main.css` to add the new navigation styling.
 37+
 38+```css
 39+/* static/main.css */
 40+/* APPEND TO END OF FILE */
 41+
 42+/* --- High-Contrast UI Updates --- */
 43+
 44+/* Header & Nav */
 45+.nav-menu {
 46+  gap: 1.5rem;
 47+  margin: 1rem 0;
 48+  border-bottom: 1px solid var(--border);
 49+  padding-bottom: 0.5rem;
 50+}
 51+
 52+.nav-menu a, .nav-menu span.active {
 53+  color: var(--grey-light);
 54+  font-weight: 600;
 55+  text-transform: uppercase;
 56+  font-size: 0.9rem;
 57+  text-decoration: none;
 58+  padding-bottom: 0.4rem;
 59+  border-bottom: 2px solid transparent;
 60+  transition: all 0.2s ease;
 61+}
 62+
 63+.nav-menu a:hover, .nav-menu span.active {
 64+  color: var(--text-color);
 65+  border-bottom: 2px solid var(--link-color);
 66+}
 67+```
 68+
 69+**Step 3: Render and Verify**
 70+Run: `make test-site && npx playwright-cli open file:///home/btburke/projects/pgit/testdata.site/index.html`
 71+Expected: The header menu is a flex row. No pipe separators. Links are grey but turn bright with a bottom border on hover.
 72+
 73+**Step 4: Commit**
 74+```bash
 75+jj commit -m "style: implement high-contrast header and navigation"
 76+```
 77+
 78+---
 79+
 80+### Task 2: Commit List (log.page.tmpl) Upgrade
 81+
 82+**Files:**
 83+- Modify: `html/log.page.tmpl`
 84+- Modify: `static/main.css`
 85+
 86+**Step 1: Update HTML Structure**
 87+Refactor the loop inside `log.page.tmpl` to use semantic classes for the new design.
 88+
 89+```html
 90+<!-- html/log.page.tmpl -->
 91+<!-- REPLACE the content inside {{range .Logs}} with: -->
 92+<div class="commit-row py">
 93+  <div class="flex justify-between items-start mb">
 94+    <div class="flex-1">
 95+      <pre class="m-0 white-space-bs font-bold text-md text-transform-none">{{.Message}}</pre>
 96+      <div class="flex items-center gap-xs text-sm font-grey-light mt-2">
 97+        <span class="font-bold">{{.AuthorStr}}</span>
 98+        <span>&nbsp;&centerdot;&nbsp;</span>
 99+        <span>{{.WhenStr}}</span>
100+      </div>
101+    </div>
102+    
103+    <div class="flex flex-col items-end gap-xs">
104+      <a href="{{.URL}}" class="mono text-sm font-bold commit-hash">{{.ShortID}}</a>
105+      {{if .Refs}}
106+      <div class="flex gap-xs flex-wrap justify-end mt-2">
107+        {{range .Refs}}
108+          <span class="ref-pill mono text-sm">
109+            {{if .URL}}
110+              <a href="{{.URL}}">{{.Refspec}}</a>
111+            {{else}}
112+              {{.Refspec}}
113+            {{end}}
114+          </span>
115+        {{end}}
116+      </div>
117+      {{end}}
118+    </div>
119+  </div>
120+</div>
121+```
122+
123+**Step 2: Add CSS for Commit List**
124+Append the new styles to `static/main.css`.
125+
126+```css
127+/* static/main.css */
128+/* APPEND TO END OF FILE */
129+
130+/* Commit List */
131+.commit-row {
132+  border-bottom: 1px solid var(--grey);
133+  transition: background-color 0.2s ease;
134+  padding: 1rem 0.5rem;
135+  margin: 0 -0.5rem; /* pull out to allow hover background to extend */
136+  border-radius: 4px;
137+}
138+
139+.commit-row:hover {
140+  background-color: var(--pre);
141+}
142+
143+.commit-row:last-child {
144+  border-bottom: none;
145+}
146+
147+.commit-hash {
148+  background-color: var(--pre);
149+  padding: 0.2rem 0.5rem;
150+  border-radius: 4px;
151+  border: 1px solid var(--grey);
152+}
153+
154+.ref-pill {
155+  background-color: var(--link-color);
156+  color: var(--bg-color);
157+  padding: 0.1rem 0.4rem;
158+  border-radius: 12px;
159+  font-weight: bold;
160+}
161+.ref-pill a {
162+  color: inherit;
163+  text-decoration: none;
164+}
165+.ref-pill a:hover {
166+  text-decoration: underline;
167+}
168+```
169+
170+**Step 3: Render and Verify**
171+Run: `make test-site && npx playwright-cli open file:///home/btburke/projects/pgit/testdata.site/commits/main.html`
172+Expected: Commit lists have generous spacing. Hovering over a row adds a subtle background. Hashes look like buttons. Refs look like solid pills. Messages are bold and larger than the author/date metadata.
173+
174+**Step 4: Commit**
175+```bash
176+jj commit -m "style: implement high-contrast commit list"
177+```
178+
179+---
180+
181+### Task 3: Commit Detail (commit.page.tmpl) Upgrade
182+
183+**Files:**
184+- Modify: `html/commit.page.tmpl`
185+- Modify: `static/main.css`
186+
187+**Step 1: Update HTML Structure**
188+Convert the `<dl>` to use our new grid class and enhance the layout.
189+
190+```html
191+<!-- html/commit.page.tmpl -->
192+<!-- REPLACE the top section (above the diff) with: -->
193+<div class="mb-4">
194+  <pre class="white-space-bs font-bold text-lg mb-4 text-transform-none">{{.Commit.Message}}</pre>
195+
196+  <div class="metadata-grid text-sm mb-4">
197+    <div class="meta-label">commit</div>
198+    <div class="meta-value mono"><a href="{{.CommitURL}}">{{.CommitID}}</a></div>
199+
200+    <div class="meta-label">parent</div>
201+    <div class="meta-value mono"><a href="{{.ParentURL}}">{{.Parent}}</a></div>
202+
203+    <div class="meta-label">author</div>
204+    <div class="meta-value font-bold">{{.Commit.Author.Name}}</div>
205+
206+    <div class="meta-label">date</div>
207+    <div class="meta-value">{{.Commit.Author.When}}</div>
208+  </div>
209+</div>
210+
211+<div class="box mono mb-4">
212+<!-- ... keep existing diff summary box content ... -->
213+```
214+
215+**Step 2: Add CSS for Commit Detail**
216+Append the new styles to `static/main.css`.
217+
218+```css
219+/* static/main.css */
220+/* APPEND TO END OF FILE */
221+
222+/* Commit Detail */
223+.metadata-grid {
224+  display: grid;
225+  grid-template-columns: max-content 1fr;
226+  gap: 0.5rem 1.5rem;
227+  align-items: center;
228+  background-color: var(--pre);
229+  padding: 1rem;
230+  border-radius: 4px;
231+  border: 1px solid var(--grey);
232+}
233+
234+.meta-label {
235+  color: var(--grey-light);
236+  text-align: right;
237+  font-weight: 600;
238+  text-transform: uppercase;
239+  font-size: 0.8rem;
240+}
241+
242+.meta-value {
243+  color: var(--text-color);
244+}
245+
246+/* Update existing .diff-file to be more distinct */
247+.diff-file {
248+  align-items: center;
249+  height: 48px; /* Slightly slimmer */
250+  position: sticky;
251+  top: 0;
252+  left: 0;
253+  background-color: var(--bg-color);
254+  border-bottom: 2px solid var(--grey);
255+  border-top: 1px solid var(--grey);
256+  padding: 0 1rem;
257+  margin: 2rem 0 0 0;
258+  z-index: 10;
259+  font-weight: bold;
260+}
261+```
262+
263+**Step 3: Render and Verify**
264+Run: `make test-site && npx playwright-cli open file:///home/btburke/projects/pgit/testdata.site/commits/93ec21917415ae74afec3fab3e734145b75019fc.html`
265+Expected: The commit message is large and bold. Metadata is in a neat, boxed grid. Diff file headers have a clear top/bottom border separating them from the code.
266+
267+**Step 4: Commit**
268+```bash
269+jj commit -m "style: implement high-contrast commit detail view"
270+```
A docs/plans/2026-04-07-recent-commit-indicator-plan.md
+196, -0
  1@@ -0,0 +1,196 @@
  2+# Recent Commit Activity Indicator Plan
  3+
  4+> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
  5+
  6+**Goal:** Add a subtle, tight block to the summary page showing the most recent commit and a humanized relative date to indicate development activity.
  7+
  8+**Architecture:** Use `github.com/dustin/go-humanize` to format the relative time of the latest commit. Expose this via a new `HumanWhenStr` field on `CommitData`. Update the generator (`main.go`) to capture this data and pass it to the `SummaryPageData`. Finally, render it in `html/summary.page.tmpl` using a tight `.box-sm` layout.
  9+
 10+**Tech Stack:** Go, Go HTML Templates
 11+
 12+---
 13+
 14+### Task 1: Implement `humanizeTime` Helper and Update Models
 15+
 16+**Files:**
 17+- Modify: `main.go`
 18+
 19+**Step 1: Add `humanizeTime` function**
 20+Add a new helper function to `main.go` (near `toPretty` or similar helpers) that formats the time. If older than a year, fallback to `Month Year`.
 21+
 22+```go
 23+// in main.go
 24+func humanizeTime(t time.Time) string {
 25+	if time.Since(t).Hours() > 365*24 {
 26+		return t.Format("Jan 2006")
 27+	}
 28+	return humanize.Time(t)
 29+}
 30+```
 31+
 32+**Step 2: Update `CommitData`**
 33+Add `HumanWhenStr string` to `CommitData`.
 34+
 35+```go
 36+// in main.go
 37+type CommitData struct {
 38+	SummaryStr   string
 39+	URL          template.URL
 40+	WhenStr      string
 41+	HumanWhenStr string // <-- NEW
 42+	AuthorStr    string
 43+	ShortID      string
 44+	ParentID     string
 45+	Refs         []*RefInfo
 46+	*git.Commit
 47+}
 48+```
 49+
 50+**Step 3: Update `SummaryPageData`**
 51+Add `LastCommit *CommitData` to `SummaryPageData`.
 52+
 53+```go
 54+// in main.go
 55+type SummaryPageData struct {
 56+	*PageData
 57+	Readme     template.HTML
 58+	LastCommit *CommitData // <-- NEW
 59+}
 60+```
 61+
 62+**Step 4: Build to Verify Syntax**
 63+Run: `go build`
 64+Expected: Clean build. No template or logical errors yet.
 65+
 66+**Step 5: Commit**
 67+```bash
 68+jj commit -m "feat: add humanize time helper and update models for recent commit indicator"
 69+```
 70+
 71+---
 72+
 73+### Task 2: Populate Data in Generator
 74+
 75+**Files:**
 76+- Modify: `main.go`
 77+
 78+**Step 1: Update `writeRevision`**
 79+In `main.go`'s `writeRevision` method (around line 966), `output.LastCommit = commit` is currently capturing the raw `*git.Commit`. Change `BranchOutput.LastCommit` type to `*CommitData`.
 80+
 81+First, update `BranchOutput`:
 82+```go
 83+// in main.go
 84+type BranchOutput struct {
 85+	Readme     string
 86+	LastCommit *CommitData // <-- CHANGED from *git.Commit
 87+}
 88+```
 89+
 90+Next, update the commit loop in `writeRevision` (around line 983) to populate the new field and capture the enriched struct:
 91+
 92+```go
 93+// in main.go inside writeRevision loop
 94+			cd := &CommitData{
 95+				ParentID:     parentID,
 96+				URL:          c.getCommitURL(commit.ID.String()),
 97+				ShortID:      getShortID(commit.ID.String()),
 98+				SummaryStr:   commit.Summary(),
 99+				AuthorStr:    commit.Author.Name,
100+				WhenStr:      commit.Author.When.Format(time.DateOnly),
101+				HumanWhenStr: humanizeTime(commit.Author.When), // <-- NEW
102+				Commit:       commit,
103+				Refs:         tags,
104+			}
105+			
106+			if i == 0 {
107+				output.LastCommit = cd // <-- Captures the enriched CommitData
108+			}
109+			logs = append(logs, cd)
110+```
111+
112+**Step 2: Update `writeRootSummary` Method Signature**
113+Update `writeRootSummary` to accept the `LastCommit`.
114+
115+```go
116+// in main.go
117+func (c *Config) writeRootSummary(data *PageData, readme template.HTML, lastCommit *CommitData) { // <-- Add parameter
118+	c.Logger.Info("writing root html", "repoPath", c.RepoPath)
119+	c.writeHtml(&WriteData{
120+		Filename: "index.html",
121+		Template: "html/summary.page.tmpl",
122+		Data: &SummaryPageData{
123+			PageData:   data,
124+			Readme:     readme,
125+			LastCommit: lastCommit, // <-- Set it here
126+		},
127+	})
128+}
129+```
130+
131+**Step 3: Update `writeRootSummary` Invocation**
132+In `writeRepo()` (around line 738), pass `mainOutput.LastCommit`.
133+
134+```go
135+// in main.go
136+	c.writeRootSummary(data, readmeHTML, mainOutput.LastCommit)
137+```
138+
139+**Step 4: Build to Verify Logic**
140+Run: `go build`
141+Expected: Clean build.
142+
143+**Step 5: Commit**
144+```bash
145+jj commit -m "feat: populate recent commit data for summary page"
146+```
147+
148+---
149+
150+### Task 3: Render Activity Indicator in Template
151+
152+**Files:**
153+- Modify: `html/summary.page.tmpl`
154+
155+**Step 1: Update the Template**
156+Add the `.box-sm` block right below the `{{define "content"}}` directive, before the clone URL logic.
157+
158+```html
159+<!-- html/summary.page.tmpl -->
160+{{define "content"}}
161+  {{if .LastCommit}}
162+  <div class="box-sm flex justify-between items-center mb text-sm font-grey-light">
163+    <div class="flex items-center gap-xs truncate">
164+      <span class="font-bold">{{.LastCommit.AuthorStr}}</span>
165+      <span>&nbsp;&centerdot;&nbsp;</span>
166+      <a href="{{.LastCommit.URL}}" class="link-alt-hover text-transform-none">{{.LastCommit.SummaryStr}}</a>
167+    </div>
168+    <div class="mono" title="{{.LastCommit.WhenStr}}">
169+      {{.LastCommit.HumanWhenStr}}
170+    </div>
171+  </div>
172+  {{end}}
173+
174+  {{if .SiteURLs.CloneURL}}
175+...
176+```
177+
178+**Step 2: Add CSS Truncation Helper (if missing)**
179+Verify `static/main.css` or `static/smol.css` has a `.truncate` class. If not, add it to `static/main.css`:
180+
181+```css
182+/* in static/main.css */
183+.truncate {
184+  overflow: hidden;
185+  text-overflow: ellipsis;
186+  white-space: nowrap;
187+}
188+```
189+
190+**Step 3: Render and Verify**
191+Run: `make test-site && npx playwright-cli open file:///home/btburke/projects/pgit/testdata.site/index.html`
192+Expected: A small box immediately above the clone URL block displaying the author, commit message, and relative date (e.g., "2 years ago" or "Oct 2024").
193+
194+**Step 4: Commit**
195+```bash
196+jj commit -m "feat: display recent commit activity indicator on summary page"
197+```
M html/base.layout.tmpl
+1, -1
1@@ -15,7 +15,7 @@
2     <link rel="stylesheet" href="{{.Repo.RootRelative}}main.css" />
3   </head>
4   <body>
5-    <header class="box">{{template "header" .}}</header>
6+    <header>{{template "header" .}}</header>
7     <hr class="my" />
8     <main>{{template "content" .}}</main>
9     <hr class="my" />
M html/commit.page.tmpl
+13, -11
 1@@ -5,21 +5,23 @@
 2 {{end}}
 3 
 4 {{define "content"}}
 5-  <dl>
 6-    <dt>commit</dt>
 7-    <dd><a href="{{.CommitURL}}">{{.CommitID}}</a></dd>
 8+  <div class="mb-4">
 9+    <pre class="white-space-bs font-bold text-lg mb-4 text-transform-none">{{.Commit.Message}}</pre>
10 
11-    <dt>parent</dt>
12-    <dd><a href="{{.ParentURL}}">{{.Parent}}</a></dd>
13+    <div class="metadata-grid text-sm mb-4">
14+      <div class="meta-label">commit</div>
15+      <div class="meta-value mono"><a href="{{.CommitURL}}">{{.CommitID}}</a></div>
16 
17-    <dt>author</dt>
18-    <dd>{{.Commit.Author.Name}}</dd>
19+      <div class="meta-label">parent</div>
20+      <div class="meta-value mono"><a href="{{.ParentURL}}">{{.Parent}}</a></div>
21 
22-    <dt>date</dt>
23-    <dd>{{.Commit.Author.When}}</dd>
24-  </dl>
25+      <div class="meta-label">author</div>
26+      <div class="meta-value font-bold">{{.Commit.Author.Name}}</div>
27 
28-  <pre class="white-space-bs">{{.Commit.Message}}</pre>
29+      <div class="meta-label">date</div>
30+      <div class="meta-value">{{.Commit.Author.When}}</div>
31+    </div>
32+  </div>
33 
34   <div class="box mono">
35     <div>
M html/header.partial.tmpl
+19, -10
 1@@ -1,24 +1,33 @@
 2 {{define "header"}}
 3 <div class="flex flex-col">
 4-  <h1 class="text-xl flex gap p-0">
 5+  <h1 class="text-xl flex gap p-0 mb-0">
 6     {{if .SiteURLs.HomeURL}}
 7       <a href="{{.SiteURLs.HomeURL}}">repos</a>
 8       <span>/</span>
 9     {{end}}
10     <span>{{.Repo.RepoName}}</span>
11   </h1>
12+  {{if .Repo.Desc}}<div class="font-italic font-grey-light mt">{{.Repo.Desc}}</div>{{end}}
13 
14-  <nav>
15-    <a href="{{.SiteURLs.SummaryURL}}">summary</a> |
16-    <a href="{{.SiteURLs.RefsURL}}">refs</a> |
17-    <span class="font-bold">{{.RevData.Name}}</span> |
18-    <a href="{{.RevData.TreeURL}}">code</a> |
19-    <a href="{{.RevData.LogURL}}">commits</a>
20+  <nav class="flex items-center nav-menu">
21+    {{if eq .Active "summary"}}<span class="active">summary</span>{{else}}<a href="{{.SiteURLs.SummaryURL}}">summary</a>{{end}}
22+    {{if eq .Active "refs"}}<span class="active">refs</span>{{else}}<a href="{{.SiteURLs.RefsURL}}">refs</a>{{end}}
23+    <span class="font-bold">{{.RevData.Name}}</span>
24+    {{if eq .Active "code"}}<span class="active">code</span>{{else}}<a href="{{.RevData.TreeURL}}">code</a>{{end}}
25+    {{if eq .Active "commits"}}<span class="active">commits</span>{{else}}<a href="{{.RevData.LogURL}}">commits</a>{{end}}
26   </nav>
27 
28-  <div>
29-    <div>{{.Repo.Desc}}</div>
30-    {{if .SiteURLs.CloneURL}}<pre class="mb-0">git clone {{.SiteURLs.CloneURL}}</pre>{{end}}
31+  {{if and (eq .Active "summary") .LastCommit}}
32+  <div class="flex justify-between items-center mt mb text-sm font-grey-light">
33+    <div class="flex items-center gap-xs truncate">
34+      <span class="font-bold">{{.LastCommit.AuthorStr}}</span>
35+      <span>&nbsp;&centerdot;&nbsp;</span>
36+      <a href="{{.LastCommit.URL}}" class="link-alt-hover text-transform-none">{{.LastCommit.SummaryStr}}</a>
37+    </div>
38+    <div class="mono" title="{{.LastCommit.WhenStr}}">
39+      {{.LastCommit.HumanWhenStr}}
40+    </div>
41   </div>
42+  {{end}}
43 </div>
44 {{end}}
M html/log.page.tmpl
+24, -20
 1@@ -7,30 +7,34 @@
 2   <div class="group-2">
 3     <div><span class="font-bold">({{.NumCommits}})</span> commits</div>
 4     {{range .Logs}}
 5-      <div>
 6-        <div class="flex justify-between items-center">
 7-          <a href="{{.URL}}" class="mono">{{.ShortID}}</a>
 8-
 9-          <div class="mono">
10-            {{range .Refs}}
11-              {{if .URL}}
12-                <a href="{{.URL}}">({{.Refspec}})</a>
13-              {{else}}
14-                ({{.Refspec}})
15+      <div class="commit-row py">
16+        <div class="flex justify-between items-start mb">
17+          <div class="flex-1 mr-4">
18+            <pre class="m-0 white-space-bs font-bold text-md text-transform-none">{{.Message}}</pre>
19+            <div class="flex items-center gap-xs text-sm font-grey-light mt">
20+              <span class="font-bold">{{.AuthorStr}}</span>
21+              <span>&nbsp;&centerdot;&nbsp;</span>
22+              <span>{{.WhenStr}}</span>
23+            </div>
24+          </div>
25+          
26+          <div class="flex flex-col items-end gap-xs">
27+            <a href="{{.URL}}" class="mono text-sm font-bold commit-hash">{{.ShortID}}</a>
28+            {{if .Refs}}
29+            <div class="flex gap-xs flex-wrap justify-end mt">
30+              {{range .Refs}}
31+                <span class="commit-hash mono text-sm">
32+                  {{if .URL}}
33+                    <a href="{{.URL}}">{{.Refspec}}</a>
34+                  {{else}}
35+                    {{.Refspec}}
36+                  {{end}}
37+                </span>
38               {{end}}
39+            </div>
40             {{end}}
41           </div>
42         </div>
43-
44-        <div class="flex items-center gap-xs text-sm">
45-          <span>{{.AuthorStr}}</span>
46-          <span>&nbsp;&centerdot;&nbsp;</span>
47-          <span>{{.WhenStr}}</span>
48-        </div>
49-
50-        <div>
51-          <pre class="m-0 white-space-bs">{{.Message}}</pre>
52-        </div>
53       </div>
54     {{end}}
55   </div>
M html/summary.page.tmpl
+5, -0
 1@@ -6,5 +6,10 @@
 2 {{end}}
 3 
 4 {{define "content"}}
 5+  {{if .SiteURLs.CloneURL}}
 6+  <div class="mb-4">
 7+    <pre class="mt-2 mb-0">git clone {{.SiteURLs.CloneURL}}</pre>
 8+  </div>
 9+  {{end}}
10   {{.Readme}}
11 {{end}}
M main.go
+45, -27
  1@@ -106,13 +106,14 @@ type TagData struct {
  2 }
  3 
  4 type CommitData struct {
  5-	SummaryStr string
  6-	URL        template.URL
  7-	WhenStr    string
  8-	AuthorStr  string
  9-	ShortID    string
 10-	ParentID   string
 11-	Refs       []*RefInfo
 12+	SummaryStr   string
 13+	URL          template.URL
 14+	WhenStr      string
 15+	HumanWhenStr string
 16+	AuthorStr    string
 17+	ShortID      string
 18+	ParentID     string
 19+	Refs         []*RefInfo
 20 	*git.Commit
 21 }
 22 
 23@@ -160,7 +161,7 @@ type RefInfo struct {
 24 
 25 type BranchOutput struct {
 26 	Readme     string
 27-	LastCommit *git.Commit
 28+	LastCommit *CommitData
 29 }
 30 
 31 type SiteURLs struct {
 32@@ -178,7 +179,8 @@ type PageData struct {
 33 
 34 type SummaryPageData struct {
 35 	*PageData
 36-	Readme template.HTML
 37+	Readme     template.HTML
 38+	LastCommit *CommitData
 39 }
 40 
 41 type TreePageData struct {
 42@@ -214,6 +216,13 @@ type RefPageData struct {
 43 	Refs []*RefInfo
 44 }
 45 
 46+func (s *SummaryPageData) Active() string { return "summary" }
 47+func (s *TreePageData) Active() string    { return "code" }
 48+func (s *FilePageData) Active() string    { return "code" }
 49+func (s *LogPageData) Active() string     { return "commits" }
 50+func (s *CommitPageData) Active() string  { return "commits" }
 51+func (s *RefPageData) Active() string     { return "refs" }
 52+
 53 type WriteData struct {
 54 	Template string
 55 	Filename string
 56@@ -309,6 +318,13 @@ func toPretty(b int64) string {
 57 	return humanize.Bytes(uint64(b))
 58 }
 59 
 60+func humanizeTime(t time.Time) string {
 61+	if time.Since(t).Hours() > 365*24 {
 62+		return t.Format("Jan 2006")
 63+	}
 64+	return humanize.Time(t)
 65+}
 66+
 67 func repoName(root string) string {
 68 	_, file := filepath.Split(root)
 69 	return file
 70@@ -367,14 +383,15 @@ func (c *Config) copyStatic(dir string) error {
 71 	return nil
 72 }
 73 
 74-func (c *Config) writeRootSummary(data *PageData, readme template.HTML) {
 75+func (c *Config) writeRootSummary(data *PageData, readme template.HTML, lastCommit *CommitData) {
 76 	c.Logger.Info("writing root html", "repoPath", c.RepoPath)
 77 	c.writeHtml(&WriteData{
 78 		Filename: "index.html",
 79 		Template: "html/summary.page.tmpl",
 80 		Data: &SummaryPageData{
 81-			PageData: data,
 82-			Readme:   readme,
 83+			PageData:   data,
 84+			Readme:     readme,
 85+			LastCommit: lastCommit,
 86 		},
 87 	})
 88 }
 89@@ -728,7 +745,7 @@ func (c *Config) writeRepo() *BranchOutput {
 90 	}
 91 	// Wrap README in a div with class for CSS styling
 92 	readmeHTML = template.HTML(`<div class="readme">` + string(readmeHTML) + `</div>`)
 93-	c.writeRootSummary(data, readmeHTML)
 94+	c.writeRootSummary(data, readmeHTML, mainOutput.LastCommit)
 95 	return mainOutput
 96 }
 97 
 98@@ -955,10 +972,6 @@ func (c *Config) writeRevision(repo *git.Repository, pageData *PageData, refs []
 99 
100 		logs := []*CommitData{}
101 		for i, commit := range commits {
102-			if i == 0 {
103-				output.LastCommit = commit
104-			}
105-
106 			tags := []*RefInfo{}
107 			for _, ref := range refs {
108 				if commit.ID.String() == ref.ID {
109@@ -973,16 +986,21 @@ func (c *Config) writeRevision(repo *git.Repository, pageData *PageData, refs []
110 			} else {
111 				parentID = parentSha.String()
112 			}
113-			logs = append(logs, &CommitData{
114-				ParentID:   parentID,
115-				URL:        c.getCommitURL(commit.ID.String()),
116-				ShortID:    getShortID(commit.ID.String()),
117-				SummaryStr: commit.Summary(),
118-				AuthorStr:  commit.Author.Name,
119-				WhenStr:    commit.Author.When.Format(time.DateOnly),
120-				Commit:     commit,
121-				Refs:       tags,
122-			})
123+			cd := &CommitData{
124+				ParentID:     parentID,
125+				URL:          c.getCommitURL(commit.ID.String()),
126+				ShortID:      getShortID(commit.ID.String()),
127+				SummaryStr:   commit.Summary(),
128+				AuthorStr:    commit.Author.Name,
129+				WhenStr:      commit.Author.When.Format(time.DateOnly),
130+				HumanWhenStr: humanizeTime(commit.Author.When),
131+				Commit:       commit,
132+				Refs:         tags,
133+			}
134+			logs = append(logs, cd)
135+			if i == 0 {
136+				output.LastCommit = cd
137+			}
138 		}
139 
140 		c.writeLog(pageData, logs)
M static/main.css
+102, -1
  1@@ -30,13 +30,44 @@ body {
  2   text-wrap: wrap;
  3 }
  4 
  5+/* Commit Detail */
  6+.metadata-grid {
  7+  display: grid;
  8+  grid-template-columns: max-content 1fr;
  9+  gap: 0.5rem 1.5rem;
 10+  align-items: center;
 11+  background-color: var(--pre);
 12+  padding: 1rem;
 13+  border-radius: 4px;
 14+  border: 1px solid var(--grey);
 15+}
 16+
 17+.meta-label {
 18+  color: var(--grey-light);
 19+  text-align: right;
 20+  font-weight: 600;
 21+  text-transform: uppercase;
 22+  font-size: 0.8rem;
 23+}
 24+
 25+.meta-value {
 26+  color: var(--text-color);
 27+}
 28+
 29+/* Update existing .diff-file to be more distinct */
 30 .diff-file {
 31   align-items: center;
 32-  height: 62px;
 33+  height: 48px; /* Slightly slimmer */
 34   position: sticky;
 35   top: 0;
 36   left: 0;
 37   background-color: var(--bg-color);
 38+  border-bottom: 2px solid var(--grey);
 39+  border-top: 1px solid var(--grey);
 40+  padding: 0 1rem;
 41+  margin: 2rem 0 0 0;
 42+  z-index: 10;
 43+  font-weight: bold;
 44 }
 45 
 46 .white-space-bs {
 47@@ -52,3 +83,73 @@ body {
 48     display: none;
 49   }
 50 }
 51+
 52+/* --- High-Contrast UI Updates --- */
 53+
 54+/* Header & Nav */
 55+.nav-menu {
 56+  gap: 1.5rem;
 57+  margin: 1rem 0;
 58+  border-bottom: 1px solid var(--border);
 59+  padding-bottom: 0.5rem;
 60+}
 61+
 62+.nav-menu a, .nav-menu span.active {
 63+  color: var(--grey-light);
 64+  font-weight: 600;
 65+  text-transform: uppercase;
 66+  font-size: 0.9rem;
 67+  text-decoration: none;
 68+  padding-bottom: 0.4rem;
 69+  border-bottom: 2px solid transparent;
 70+  transition: all 0.2s ease;
 71+}
 72+
 73+.nav-menu span.font-bold {
 74+  color: var(--text-color);
 75+  font-weight: 600;
 76+  text-transform: uppercase;
 77+  font-size: 0.9rem;
 78+  padding-bottom: 0.4rem;
 79+  border-bottom: 2px solid transparent;
 80+}
 81+
 82+.nav-menu a:hover, .nav-menu span.active {
 83+  color: var(--text-color);
 84+  border-bottom: 2px solid var(--link-color);
 85+}
 86+
 87+/* Commit List */
 88+.commit-row {
 89+  border-bottom: 1px solid var(--grey);
 90+  transition: background-color 0.2s ease;
 91+  padding: 1rem 0.5rem;
 92+  margin: 0 -0.5rem; /* pull out to allow hover background to extend */
 93+  border-radius: 4px;
 94+}
 95+
 96+.commit-row:hover {
 97+  background-color: var(--pre);
 98+}
 99+
100+.commit-row:last-child {
101+  border-bottom: none;
102+}
103+
104+.commit-hash {
105+  color: var(--text-color);
106+}
107+.commit-hash a {
108+  color: inherit;
109+  text-decoration: none;
110+}
111+.commit-hash a:hover {
112+  text-decoration: underline;
113+}
114+
115+.truncate {
116+  overflow: hidden;
117+  text-overflow: ellipsis;
118+  white-space: nowrap;
119+}
120+