diff --git a/docs/plans/2026-02-20-redaction-workflow-redesign-design.md b/docs/plans/2026-02-20-redaction-workflow-redesign-design.md
new file mode 100644
index 0000000..9a2c6e8
--- /dev/null
+++ b/docs/plans/2026-02-20-redaction-workflow-redesign-design.md
@@ -0,0 +1,142 @@
+# Redaction Workflow Redesign
+
+## Problem
+
+Two issues blocking release:
+
+1. Auto-detection runs on upload — it should be a separate action
+2. Double-click (spot) redactions are dead-ends — no analysis, no popover, no solver access
+
+Root cause: manually-created redactions skip the analysis pipeline entirely and arrive as `"unanalyzed"` with no `analysis` object or `overrides`. The popover, text edit bar, canvas rendering, and solver all require these to exist.
+
+## Design Decisions
+
+- **Primary workflow is manual**: users double-click redactions they want to investigate
+- **Auto-detect ("Scan for Redactions") is secondary**: a dev/AI tool for batch processing
+- **Inline editing on canvas**: left/right text editable directly on the document, not in a disconnected panel
+- **OCR runs at upload time**: cached and available for both manual and auto-detect flows
+- **Text cleaning replaces image masking**: filter OCR characters by overlap with redaction boxes instead of whiting out image regions
+
+## User Journey
+
+### 1. Upload
+- Clean upload screen, drop a PDF
+- PDF rasterizes, page image displays
+- OCR runs automatically in background (brief "Processing..." indicator)
+- When OCR completes, document is ready for interaction
+
+### 2. Mark & Analyze Redactions (Primary Flow)
+- User examines document (zoom, pan)
+- **Double-click on any black bar**:
+ - Brief loading indicator
+ - Backend finds bounding box (OpenCV connected components)
+ - Backend runs mini-pipeline: font detection, left/right text extraction from cached OCR, pixel alignment
+ - Returns fully analyzed redaction
+- Canvas zooms to center the redaction line
+- Inline editing activates:
+ - Left/right text render at detected positions on the canvas
+ - Editable `` overlays at text positions (feels like typing on the document)
+ - Gap (redaction box) highlighted with pixel width shown
+ - Small floating toolbar: font selector, size, offset fine-tune, gap width, **Solve** button
+
+### 3. Fine-Tune & Solve
+- Adjust left/right text by typing directly on the document
+- Ctrl+drag: fine-tune text offset (X/Y pixel alignment)
+- Shift+drag: adjust gap width
+- Drag box edges: resize the redaction bounding box (new)
+- Click **Solve**: solver streams results, matched against associates
+
+### 4. Navigate Between Redactions
+- Left panel lists all marked redactions for the page
+- Click one to pan and open inline editor
+- Each shows status: analyzed, solved, with solution preview
+
+### 5. Scan for Redactions (Secondary/Dev Flow)
+- Button at top of left panel, above redaction list
+- Disabled until OCR completes, then enabled
+- Runs full LLM pipeline (uses cached OCR): detection + analysis for all redactions on page
+- Each arrives analyzed and ready to solve
+- Same inline editing experience when clicked
+
+## Backend Changes
+
+### New endpoint: `GET /api/doc/{id}/ocr` (SSE)
+- Runs Tesseract on each page, caches `OcrLine[]` in document state
+- Emits `page_ocr_complete` events (lightweight metadata, not full OCR data)
+- Emits `ocr_complete` when all pages done
+- Returns cached results if already run
+
+### New function: `clean_ocr_chars(ocr_lines, redaction_bboxes)`
+- Filters OCR characters: excludes any whose bounding box overlaps a redaction bbox
+- Returns only clean characters
+- Replaces `detect_font_masked()` image-masking approach
+- Used by both auto-detect pipeline and spot pipeline
+
+### New function: `analyze_spot_redaction(doc_id, page, bbox)`
+- Takes known bounding box + cached OCR data
+- Runs: `clean_ocr_chars()` → font detection (on clean chars) → left/right text extraction → pixel alignment
+- Skips LLM detection (we already have the box)
+- Returns full redaction with `analysis` + `overrides` + `status: "analyzed"`
+
+### Modified: `POST /api/doc/{id}/page/{page}/spot`
+- After finding bbox via OpenCV, calls `analyze_spot_redaction()`
+- Returns fully populated redaction object
+
+### Modified: `analyze_page()`
+- Accepts pre-computed OCR data (no longer runs Tesseract internally)
+- Uses `clean_ocr_chars()` instead of `detect_font_masked()`
+
+### Modified: `GET /api/doc/{id}/analyze` (SSE)
+- No longer auto-triggered on upload
+- Uses cached OCR data from the `/ocr` endpoint
+- Otherwise same flow: LLM detection → region finding → analysis
+
+## Frontend Changes
+
+### Upload flow (`main.js`)
+- `uploadFile()` → `POST /api/upload` → page image loads
+- Automatically starts `GET /api/doc/{id}/ocr` SSE → shows "Running OCR..." status
+- When OCR completes: document ready, "Scan for Redactions" button enables
+- No auto-analysis
+
+### Inline editing (new)
+- When a redaction activates, HTML `` elements overlay the canvas at text positions
+- Inputs transform with viewport (zoom/pan) — positioned using the same coordinate system
+- Styled to blend with document (semi-transparent background, matched font size)
+- Typing updates `overrides.leftText`/`overrides.rightText` and redraws canvas
+- Floating toolbar anchors near the redaction with font/size/offset/gap/solve controls
+
+### Double-click spot (revised)
+- Response now includes full analysis data
+- Creates redaction with `status: "analyzed"`, populated `analysis`/`overrides`
+- Activates inline editor immediately
+
+### Detect Redactions button (new)
+- Top of left panel, above redaction list
+- Disabled until OCR completes
+- Click triggers `GET /api/doc/{id}/analyze` SSE
+- Progress indicator while running
+
+### Drag handles for bbox resize (new)
+- When a redaction is active, small handles at box edges
+- Drag to resize `x`, `y`, `w`, `h`
+
+## Interaction Summary
+
+| Interaction | Action |
+|---|---|
+| Double-click black bar | Create & analyze redaction, open inline editor |
+| Ctrl+drag | Fine-tune text offset (X/Y alignment) |
+| Shift+drag | Adjust gap width |
+| Drag box edges | Resize redaction bounding box |
+| Click redaction in list | Pan to it, open inline editor |
+| "Scan for Redactions" | Run full LLM auto-detect pipeline |
+
+## What Stays the Same
+
+- Canvas rendering for overlays (boxes, preview text, solutions)
+- Solver (Rust DFS, dictionary modes, SSE streaming)
+- Associate matching + tier badges
+- Viewport (zoom, pan, touch support)
+- Page navigation
+- Export (Ctrl+E)