diff --git a/docs/superpowers/specs/2026-05-12-pdf-stack-overhaul-design.md b/docs/superpowers/specs/2026-05-12-pdf-stack-overhaul-design.md
new file mode 100644
index 00000000..35053d2a
--- /dev/null
+++ b/docs/superpowers/specs/2026-05-12-pdf-stack-overhaul-design.md
@@ -0,0 +1,491 @@
+# PDF Stack Overhaul — Design
+
+**Date:** 2026-05-12
+**Branch:** `feat/documents-folders`
+**Status:** Design approved; pending user review of spec; implementation planned via writing-plans skill.
+
+## Goal
+
+Replace `pdfme` (3 deps, 8 hand-coded coordinate templates, 571-line TipTap-to-pdfme bridge) with `@react-pdf/renderer` (JSX components, real layout primitives). Add `unpdf` for berth-PDF tier-2 rasterization. Add port-level logo upload with quality safeguards. Migrate only the internal-only PDF surfaces; remove invoice and admin-TipTap PDF generation entirely (they violate the new "no client-facing CRM-generated PDFs" rule).
+
+## Scope (locked)
+
+### KEEP & migrate to `@react-pdf/renderer` (internal-only)
+
+| Surface | Current location | Caller |
+| ----------------------- | --------------------------------------------------------------------------------------------------- | ------------------------------------- |
+| Activity report | `src/lib/pdf/templates/reports/activity-report.ts` | `src/lib/services/reports.service.ts` |
+| Revenue report | `src/lib/pdf/templates/reports/revenue-report.ts` | same |
+| Pipeline report | `src/lib/pdf/templates/reports/pipeline-report.ts` | same |
+| Occupancy report | `src/lib/pdf/templates/reports/occupancy-report.ts` | same |
+| Client summary export | `src/lib/pdf/templates/client-summary-template.ts` | `src/lib/services/record-export.ts` |
+| Berth spec export | `src/lib/pdf/templates/berth-spec-template.ts` | same |
+| Interest summary export | `src/lib/pdf/templates/interest-summary-template.ts` | same |
+| Expense sheet | `src/lib/services/expense-pdf.service.ts` (currently uses pdfme indirectly via `expense-export.ts`) | same |
+
+### REMOVE entirely
+
+| Removal | Reason |
+| ----------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `src/lib/pdf/templates/invoice-template.ts` + `generatePdf` call in `invoices.ts:604` + API route `/api/v1/invoices/[id]/generate-pdf` | Invoices are client-facing; no CRM-generated client-facing PDFs. Future invoice rendering will use the deferred AcroForm-fill admin-template feature. |
+| `src/lib/pdf/tiptap-to-pdfme.ts` (571 lines) + API route `/api/v1/admin/templates/preview` + `generatePdf` block in `document-templates.ts:516` | TipTap document templates are Documenso seed bodies; CRM does not render them to PDF anymore. |
+| `src/lib/pdf/templates/eoi-standard-inapp.ts` (337 lines, HTML seed) + seed-data references | Only used as the seed `bodyHtml` text on a `document_templates` row. The in-app EOI is rendered by `fill-eoi-form.ts` (pdf-lib), not from this HTML. Safe to drop. |
+| `src/lib/pdf/generate.ts` (24 lines) | Pdfme wrapper; replaced by `src/lib/pdf/render.ts`. |
+| Deps: `@pdfme/common`, `@pdfme/generator`, `@pdfme/schemas` | Replaced by `@react-pdf/renderer`. |
+
+### STAYS UNTOUCHED
+
+- `src/lib/pdf/fill-eoi-form.ts` (pdf-lib AcroForm fill on `assets/eoi-template.pdf`) — the in-app EOI pathway.
+- `src/lib/services/berth-pdf-parser.ts` tier-1 (pdf-lib AcroForm read) and tier-3 (AI fallback). Tier-2 (Tesseract OCR) gets `unpdf` for PDF→image rasterization.
+- `pdf-lib` dep (still needed by `fill-eoi-form.ts` and `berth-pdf-parser.ts`).
+- All Documenso integration code.
+
+## Architecture
+
+Three orthogonal PDF paths post-migration, each with a single owner:
+
+```
+┌──────────────────────────┐ ┌──────────────────────────┐ ┌────────────────────────┐
+│ react-pdf (this phase) │ │ pdf-lib AcroForm fill │ │ Documenso (external) │
+│ Internal only │ │ Standardized + signing │ │ Client-facing signed │
+│ │ │ │ │ docs │
+│ • Reports (×4) │ │ • In-app EOI │ │ │
+│ • Expenses │ │ • Future admin-upload │ │ (handled outside our │
+│ • Record exports (×3) │ │ invoice templates │ │ system) │
+│ • Future internal lists │ │ (deferred) │ │ │
+└────────────┬─────────────┘ └────────────┬─────────────┘ └────────────────────────┘
+ │ │
+ ▼ ▼
+ src/lib/pdf/render.ts src/lib/pdf/fill-eoi-form.ts
+ (renderToBuffer + (unchanged this phase)
+ renderToStream)
+ │
+ ▼
+ src/lib/pdf/brand-kit/
+ ├─ DocumentShell.tsx
+ ├─ Header.tsx
+ ├─ Footer.tsx
+ ├─ DataTable.tsx
+ ├─ KeyValueGrid.tsx
+ ├─ Section.tsx
+ ├─ Badge.tsx
+ ├─ charts/{Bar,Line,Pie,Funnel}Chart.tsx
+ ├─ tokens.ts
+ └─ logo.ts
+```
+
+### Module boundaries
+
+- **`brand-kit/`** — pure presentation primitives. No DB access, no CRM domain knowledge. Each component has typed props and renders react-pdf elements.
+- **`templates/`** — one `.tsx` per document type. Imports brand-kit primitives + receives typed data props. No DB access; data fetching stays in the calling service.
+- **`render.ts`** — the only module that touches `@react-pdf/renderer`'s `renderToBuffer` / `renderToStream`. Services call `renderPdf()` or `renderPdfStream()`.
+- **`logo.ts`** — `resolvePortLogo(portId)` reads `system_settings.port_logo_file_id` and returns `{ source, buffer, mimeType }`. Cached per request via React `cache()`.
+- **Chart rendering** — pure SVG components emitting react-pdf's native `