diff --git a/.planning/phases/16-multi-signer-ui/16-UI-SPEC.md b/.planning/phases/16-multi-signer-ui/16-UI-SPEC.md
new file mode 100644
index 0000000..43938c4
--- /dev/null
+++ b/.planning/phases/16-multi-signer-ui/16-UI-SPEC.md
@@ -0,0 +1,323 @@
+---
+phase: 16
+slug: multi-signer-ui
+status: draft
+shadcn_initialized: false
+preset: none
+created: 2026-04-03
+---
+
+# Phase 16 — UI Design Contract
+
+> Visual and interaction contract for Phase 16: Multi-Signer UI.
+> Generated by gsd-ui-researcher, verified by gsd-ui-checker.
+
+---
+
+## Design System
+
+| Property | Value |
+|----------|-------|
+| Tool | none — fully manual Tailwind CSS |
+| Preset | not applicable |
+| Component library | none (custom components only) |
+| Icon library | none (inline SVG or Unicode characters only, per existing patterns) |
+| Font | Geist Sans (sans-serif body), Cormorant Garamond (display, marketing only) |
+
+Source: `globals.css` CSS custom properties + existing component inspection.
+
+No shadcn gate required: `components.json` is absent. Stack is Next.js 15 App Router + Tailwind CSS v4 (`@tailwindcss/postcss`). All existing portal components are hand-crafted with Tailwind utility classes and inline `style={}` objects. This phase continues that pattern.
+
+---
+
+## Spacing Scale
+
+Declared values (must be multiples of 4):
+
+| Token | Value | Usage |
+|-------|-------|-------|
+| xs | 4px | Icon gaps, dot-to-label gap in signer rows, badge inner padding |
+| sm | 8px | Compact element spacing, signer row internal gap, input padding |
+| md | 16px | Default element spacing, panel section gaps, field box padding |
+| lg | 24px | Section padding within PreparePanel, table cell padding |
+| xl | 32px | Layout gaps between major panel sections |
+| 2xl | 48px | Major section breaks (not used within PreparePanel) |
+| 3xl | 64px | Page-level spacing (not applicable to portal panels) |
+
+Exceptions:
+- Colored signer dot: 8px × 8px circle (sm × sm) — consistent with existing badge geometry
+- Active signer dropdown height: 32px (matches existing PreparePanel button height convention of `py-1.5` = 6px top + 6px bottom + 20px line ≈ 32px)
+- Signer list email input height: 32px (`py-1.5 px-2`) to match textarea style in existing PreparePanel
+- Touch targets for remove (×) buttons: minimum 28px × 28px (compact panel context, not primary CTA)
+
+Source: measured from existing `PreparePanel.tsx` button styles (`py-2 px-4` = 8px + 8px vertical, matching `md` token) and `DocumentsTable.tsx` cell padding (`0.875rem 1.5rem`).
+
+---
+
+## Typography
+
+| Role | Size | Weight | Line Height |
+|------|------|--------|-------------|
+| Body | 14px (0.875rem) | 400 (regular) | 1.5 |
+| Label | 12px (0.75rem) | 500 (medium) | 1.4 |
+| Heading | 16px (1rem) | 600 (semibold) | 1.3 |
+| Badge / caption | 12px (0.75rem) | 500 (medium) | 1.0 |
+
+Source: extracted directly from existing components.
+- PreparePanel `
`: `font-semibold` (600) — maps to Heading
+- PreparePanel body labels: `text-sm` = 14px regular — maps to Body
+- PreparePanel secondary labels (`text-xs text-gray-400`): 12px medium — maps to Label
+- DocumentsTable `| `: `0.75rem font-weight:600 uppercase letter-spacing:0.05em` — maps to Label (uppercase table headers are an established portal pattern)
+- StatusBadge: `text-xs font-medium` = 12px 500 — maps to Badge
+
+Only 2 weights used throughout the portal: 400 (regular) and 600 (semibold). Weight 500 is used for table data cells and badge text — treat as part of the semibold family for this contract (no additional weight token needed).
+
+---
+
+## Color
+
+| Role | Value | Usage |
+|------|-------|-------|
+| Dominant (60%) | `#FAF9F7` (cream) | Page background, panel backgrounds |
+| Secondary (30%) | `#F9FAFB` / `#F3F4F6` | Card surfaces, table rows, input backgrounds, panel wrapper (`bg-gray-100`) |
+| Accent (10%) | `#1B2B4B` (navy) | Primary interactive text, document links, Download button, section headings |
+| Destructive | `#DC2626` (red-600) | Remove signer (×) button, send-block validation error text, unassigned field outline |
+
+Accent reserved for: document link hover, primary heading text, Download Signed PDF button background. NOT used for signer colors or type-palette colors.
+
+### Signer Color Palette (locked — source: CONTEXT.md D-01)
+
+Auto-assigned in order when signers are added. Stored in `documents.signers[].color`.
+
+| Signer Index | Color | Hex |
+|-------------|-------|-----|
+| 0 (first) | Indigo | `#6366f1` |
+| 1 (second) | Rose | `#f43f5e` |
+| 2 (third) | Emerald | `#10b981` |
+| 3 (fourth) | Amber | `#f59e0b` |
+| 4+ | Cycles back | same order |
+
+### Field Type Color Palette (existing — source: `FieldPlacer.tsx` `PALETTE_TOKENS`)
+
+These colors are UNCHANGED. They apply only when a field has no `signerEmail`.
+
+| Field Type | Color | Hex |
+|------------|-------|-----|
+| client-signature | Blue | `#2563eb` |
+| initials | Purple | `#7c3aed` |
+| checkbox | Green | `#059669` |
+| date | Amber | `#d97706` |
+| text | Slate | `#64748b` |
+| agent-signature | Red | `#dc2626` |
+| agent-initials | Orange | `#ea580c` |
+
+### Color Override Rule (locked — source: CONTEXT.md D-06, D-07)
+
+When `field.signerEmail` is set: field box border, background tint, and drag ghost use the **signer color** from `documents.signers`. When `field.signerEmail` is absent (agent-owned fields or untagged fields): use existing **type color** from `PALETTE_TOKENS`.
+
+### Validation State Color
+
+- Unassigned client-facing field outline: `2px solid #ef4444` (red-500, slightly lighter than destructive `#dc2626` to distinguish validation from permanent agent-red fields)
+- Error message text below Send button: `text-red-600` (`#dc2626`), consistent with existing `result.ok === false` style in PreparePanel
+
+Source: CONTEXT.md D-09, D-10; existing PreparePanel error pattern.
+
+---
+
+## Component Inventory
+
+This section catalogs the new and modified UI elements for Phase 16.
+
+### 1. PreparePanel — Signer List Section (NEW)
+
+**Location:** Between the "Text field fill" section and the "AI Auto-place Fields" button. Only visible when `currentStatus === 'Draft'`.
+
+**Structure:**
+
+```
+[ Prepare Document heading ]
+[ Recipients section — existing ]
+[ Text field fill — existing ]
+──────────────────────────────
+[ Signers section — NEW ]
+ label: "Signers"
+ [ email input ] [ Add button ]
+ helper: "Each signer receives their own signing link."
+ [ signer list ]
+ signer row: ● indigo dot email@example.com [×]
+ signer row: ● rose dot email@example.com [×]
+──────────────────────────────
+[ AI Auto-place Fields — existing ]
+[ Preview — existing ]
+[ Prepare and Send — existing ]
+[ error/result message — existing ]
+```
+
+**Signer Row spec:**
+- Colored dot: 8px × 8px circle, `background: signerColor`, `border-radius: 50%`, `flex-shrink: 0`
+- Email text: 14px regular, `color: #374151` (gray-700), `flex: 1`, `truncate`
+- Remove button (×): 16px text, `color: #9CA3AF`, hover `color: #DC2626`, no border, cursor pointer, minimum 28px touch target via padding
+- Row gap: 6px between dot, email, and × button (`gap-1.5` ≈ 6px)
+- Row background: white with 1px `#E5E7EB` border, `border-radius: 0.375rem`, padding `6px 8px`
+
+**Email input spec:**
+- Full-width text input, `border: 1px solid #D1D5DB`, `border-radius: 0.375rem`, `padding: 6px 8px`, `font-size: 0.875rem`
+- Placeholder: `"signer@example.com"`
+- Inline with "Add" button: flex row, `gap: 8px`
+
+**Add button spec:**
+- Label: "Add"
+- Style: `bg-gray-700 text-white` hover `bg-gray-800`, `px-3 py-1.5`, `border-radius: 0.375rem`, `font-size: 0.875rem font-weight: 500`
+- Disabled when input is empty or contains an already-added email
+
+**Section label:** `text-sm font-medium text-gray-700 mb-1` — matches existing label pattern
+
+### 2. FieldPlacer — Active Signer Selector (NEW)
+
+**Location:** Top of FieldPlacer, above the field type palette. Visible ONLY when `signers.length > 0`.
+
+**Structure:**
+
+```
+[ Active signer: ▼ ● indigo first@example.com ]
+[ palette tokens — existing ]
+[ PDF canvas drop zone — existing ]
+```
+
+**Dropdown spec:**
+- Native ` |