diff --git a/docs/superpowers/plans/2026-05-30-ui-normalization.md b/docs/superpowers/plans/2026-05-30-ui-normalization.md
new file mode 100644
index 0000000..010e6a0
--- /dev/null
+++ b/docs/superpowers/plans/2026-05-30-ui-normalization.md
@@ -0,0 +1,473 @@
+# UI Normalization Implementation Plan
+
+> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
+
+**Goal:** Make the design tokens the single source of truth for every visual value in the Avalonia UI, remove duplicated styles, and add a reusable `ModalShell` control for the copy-pasted modal chrome.
+
+**Architecture:** Establish global control defaults in `App.axaml`, expand/repoint brushes in `Tokens.axaml`, promote shared styles into `IslandStyles.axaml`, then mechanically migrate every view to reference tokens (snapping stray values to the nearest token per "lane B"). Off-palette colors fold into the existing palette. A new `ModalShell` templated control replaces the per-modal titlebar/border/footer markup.
+
+**Tech Stack:** .NET 8, Avalonia 12 (Fluent theme, dark variant), compiled XAML (`x:DataType`), CommunityToolkit.Mvvm.
+
+**Verification model:** There are no unit tests for XAML. The "test" for every task is a clean build:
+- `dotnet build src/ClaudeDo.App/ClaudeDo.App.csproj` (compiles Ui + Data; validates all StaticResource keys and compiled bindings)
+
+Build with the `.csproj` directly — `.slnx` requires .NET 9 and will fail on this machine (.NET 8).
+
+**Normalization rules (apply everywhere unless a task says otherwise):**
+
+Font sizes — replace every `FontSize="N"` literal with the token whose value it snaps to:
+| literal | token |
+|---|---|
+| 9 | `{StaticResource FontSizeEyebrow}` (10) |
+| 10 | `{StaticResource FontSizeEyebrow}` (10) |
+| 11 | `{StaticResource FontSizeMono}` (11) |
+| 12 | `{StaticResource FontSizeBody}` (13) |
+| 13 | `{StaticResource FontSizeBody}` (13) |
+| 14 | `{StaticResource FontSizeTaskTitle}` (14) |
+| 16 | `{StaticResource FontSizeH3}` (18) |
+| 18 | `{StaticResource FontSizeH3}` (18) |
+| 24 | `{StaticResource FontSizeH2}` (24) |
+| 32 | `{StaticResource FontSizeH1}` (32) |
+
+Spacing — modal body padding literals `16` and `20` snap to `18`; keep other axis values mapped to the nearest of SpaceXs=4/SpaceSm=8/SpaceMd=12/SpaceLg=14/SpaceXl=18/Space2Xl=24. Leave values that already equal a token as plain numbers (do **not** churn every margin into a resource ref — only modal body padding is standardized).
+
+Corner radius — `4` → `6`; TextBox inputs use `8`.
+
+Colors — fold off-palette to palette:
+| literal / named | replacement |
+|---|---|
+| `#4CAF50` (online dot) | `{DynamicResource StatusRunningBrush}` |
+| `#FFA726` (reconnecting dot) | `{DynamicResource StatusReviewBrush}` |
+| `#EF5350` (offline / phantom) | `{DynamicResource StatusErrorBrush}` |
+| `OrangeRed`, `Orange` | `{DynamicResource BloodBrush}` |
+| `White` (badge / danger text) | `{DynamicResource TextBrush}` |
+| `White` (on accent primary button) | `{DynamicResource DeepBrush}` |
+| `#FF080C0B` (terminal bg) | `{DynamicResource VoidBrush}` |
+| `#0DFFFFFF` (island hairline) | `{DynamicResource HairlineOverlayBrush}` |
+
+---
+
+## Phase 1 — Foundation
+
+### Task 1: Add new brushes & repoint badges in Tokens.axaml
+
+**Files:**
+- Modify: `src/ClaudeDo.Ui/Design/Tokens.axaml`
+
+- [ ] **Step 1: Add named tint, hairline brushes**
+
+In the BRUSHES section (after the Status*Brush block ending ~line 85), add:
+
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+- [ ] **Step 2: Build to verify tokens parse**
+
+Run: `dotnet build src/ClaudeDo.App/ClaudeDo.App.csproj`
+Expected: PASS (no errors).
+
+- [ ] **Step 3: Commit**
+
+```bash
+git add src/ClaudeDo.Ui/Design/Tokens.axaml
+git commit -m "feat(ui): add named tint and hairline overlay brush tokens"
+```
+
+---
+
+### Task 2: Global control defaults in App.axaml
+
+**Files:**
+- Modify: `src/ClaudeDo.App/App.axaml`
+
+- [ ] **Step 1: Add Window default style**
+
+Inside ``, after `` and before the ListBoxItem styles, add:
+
+```xml
+
+
+```
+
+(FontFamily/FontSize/Foreground are inherited properties in Avalonia, so setting them on the Window root propagates to all descendant text controls.)
+
+- [ ] **Step 2: Build**
+
+Run: `dotnet build src/ClaudeDo.App/ClaudeDo.App.csproj`
+Expected: PASS.
+
+- [ ] **Step 3: Commit**
+
+```bash
+git add src/ClaudeDo.App/App.axaml
+git commit -m "feat(ui): set global Inter Tight font default on all windows"
+```
+
+---
+
+### Task 3: Promote shared styles into IslandStyles.axaml
+
+**Files:**
+- Modify: `src/ClaudeDo.Ui/Design/IslandStyles.axaml`
+
+- [ ] **Step 1: Add shared modal styles**
+
+At the end of the `` element (before the closing `` at line ~901), add:
+
+```xml
+
+
+
+
+
+
+
+
+
+
+```
+
+Note: `TextBlock.section-label` already exists at line ~864 — do NOT re-add it.
+
+- [ ] **Step 2: Replace hardcoded values inside existing IslandStyles rules**
+
+Apply the normalization rules to the existing style setters in this file:
+- Every `FontSize="N"` setter → the snapped token ref (table above). Specific lines: 149 (10→FontSizeEyebrow), 206 (11→FontSizeMono), 252 (13→FontSizeBody), 397 (11→FontSizeMono), 453 (9→FontSizeEyebrow), 475 (10→FontSizeEyebrow), 483 (10→FontSizeEyebrow), 556 (12→FontSizeBody), 573 (9→FontSizeEyebrow), 597 (12→FontSizeBody), 622 (10→FontSizeEyebrow), 638 (12→FontSizeBody), 697 (14→FontSizeTaskTitle), 771 (10→FontSizeEyebrow), 783 (10→FontSizeEyebrow), 788 (10→FontSizeEyebrow), 819 (11→FontSizeMono), 867 (10→FontSizeEyebrow), 884 (9→FontSizeEyebrow).
+- Chip tint backgrounds/borders → named brushes:
+ - line 155/156 `#1F7C9166`/`#4C7C9166` → `{StaticResource RunningTintBrush}`/`{StaticResource RunningTintBorderBrush}`
+ - 163/164 review tints → `ReviewTintBrush`/`ReviewTintBorderBrush`
+ - 171/172 error tints → `ErrorTintBrush`/`ErrorTintBorderBrush`
+ - 179/180 queued tints → `QueuedTintBrush`/`QueuedTintBorderBrush`
+ - agent-strip tints at 361/362 (`#147C9166`/`#4C7C9166`), 365/366, 368/369, 374/375 → the matching `*TintBrush`/`*TintBorderBrush` (snap the `#14` alpha to the shared `#1F` tint).
+- line 123 `#0DFFFFFF` → `{StaticResource HairlineOverlayBrush}`.
+- line 389 & 810 `#FF080C0B` → `{StaticResource VoidBrush}`.
+- line 887 badge `White` → `{StaticResource TextBrush}`.
+- Badge brushes at lines 88-90: replace the three `` definitions with palette refs:
+```xml
+
+
+
+```
+- Corner radius `4` setters (447 live-chip, 813 task-live-tail `5`→leave, badges 878 `3`→leave) → only snap `4`→`6` where it appears as `CornerRadius="4"` on live-chip (447) and kbd (614) and badge tints. Leave `3` and `5` as-is (no nearby token; they're intentional micro-radii). NOTE: if unsure, leave radius alone — radius churn is lowest priority.
+
+- [ ] **Step 3: Build**
+
+Run: `dotnet build src/ClaudeDo.App/ClaudeDo.App.csproj`
+Expected: PASS.
+
+- [ ] **Step 4: Commit**
+
+```bash
+git add src/ClaudeDo.Ui/Design/IslandStyles.axaml
+git commit -m "refactor(ui): tokenize IslandStyles values and add shared modal styles"
+```
+
+---
+
+## Phase 2 — Per-view token migration (independent; parallelizable)
+
+For each task: open the file, apply the **normalization rules** (font/color/spacing/radius tables at top). Remove any local `Window.Styles` block that only redefines `section-label`, `field-label`, `path-mono`, `Button.primary`, or `Button.danger` (now shared from IslandStyles). Keep local styles that are genuinely unique to that view. After each file, build and commit.
+
+Each task ends with:
+- Build: `dotnet build src/ClaudeDo.App/ClaudeDo.App.csproj` → PASS
+- Commit: `git add && git commit -m "refactor(ui): tokenize "`
+
+### Task 4: MainWindow.axaml
+- Snap all `FontSize` literals (lines ~46,52,59,67,112,136,209,222,231).
+- Status dots: `#4CAF50`→`StatusRunningBrush`, `#FFA726`→`StatusReviewBrush`, `#EF5350`→`StatusErrorBrush` (lines ~200,203,205).
+
+### Task 5: Islands — ListsIslandView.axaml, TasksIslandView.axaml
+- ListsIslandView: snap FontSize (18,10,12 at lines ~18,49,57,58,59); username TextBlock (~57) gets no explicit FontFamily (inherits SansFont now — correct, leave it).
+- TasksIslandView: snap FontSize (24,11 at ~15,19).
+
+### Task 6: DetailsIslandView.axaml
+- Snap all FontSize (10,14,11,10,13,12 at lines ~54,57,92,114,138,142,199,269).
+- `OrangeRed`→`BloodBrush` (~154).
+- TextBox `CornerRadius="6"`→`8` (~172,274). TextBox `Padding="8"` leave.
+- Remove any redundant inline label styles superseded by shared `field-label`.
+
+### Task 7: TaskRowView.axaml (includes the BorderBrush bug fix)
+- Snap FontSize (10,14 at ~85,103).
+- **Bug fix:** `BorderBrush="{DynamicResource BorderBrush}"` → `{DynamicResource LineBrush}` (the schedule-flyout border, ~line 188/222). `BorderBrush` is not a defined key.
+- Schedule flyout: title/labels inherit SansFont now (leave unset).
+
+### Task 8: AgentStripView.axaml, SessionTerminalView.axaml
+- AgentStrip: snap FontSize (10,9 at ~22,29,73,78); commit chip radius `4`→`6` (~102).
+- SessionTerminal: snap FontSize (10,11 at ~17,69).
+
+### Task 9: ThemedDatePicker.axaml
+- Snap any FontSize literals; popup border `CornerRadius="10"` → leave (10 = ChipCornerRadius value, acceptable) OR `{StaticResource ChipCornerRadius}`. Tokenize colors if any literals present.
+
+---
+
+## Phase 3 — ModalShell control
+
+### Task 10: Create ModalShell control
+
+**Files:**
+- Create: `src/ClaudeDo.Ui/Views/Controls/ModalShell.axaml.cs`
+- Create: `src/ClaudeDo.Ui/Views/Controls/ModalShell.axaml`
+
+- [ ] **Step 1: Write the code-behind (templated control)**
+
+`ModalShell.axaml.cs`:
+```csharp
+using System;
+using System.Windows.Input;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Controls.Primitives;
+using Avalonia.Input;
+
+namespace ClaudeDo.Ui.Views.Controls;
+
+/// Reusable modal chrome: titlebar (drag + close) wrapping a body and optional footer.
+public class ModalShell : ContentControl
+{
+ public static readonly StyledProperty TitleProperty =
+ AvaloniaProperty.Register(nameof(Title));
+
+ public static readonly StyledProperty