Complete rewrite of presenter mode. Two-part solution:
1. Single-slide preview mode in runtime.js
- Detect ?preview=N query param on page load
- When present: show only slide N, hide all chrome (progress-bar,
notes-overlay, overview), skip key handlers, skip hash/broadcast
- This lets the presenter window load the deck file in iframes with
specific slides — CSS/theme/colors 100% identical to audience view
2. Magnetic-card presenter window
- 4 independent cards (CURRENT / NEXT / SCRIPT / TIMER)
- Each card is position:absolute, draggable by header, resizable by
bottom-right corner handle
- Cards have colored indicator dots matching their role
- Dragging shows blue outline; resizing shows green
- Layout persists to localStorage per-deck, with 'Reset layout' button
- Default layout: CURRENT big top-left, NEXT top-right, SCRIPT
bottom-right, TIMER bottom-left
Previews use iframe.src = deckUrl + '?preview=N':
- iframe loads THE SAME HTML file as the audience
- runtime.js detects ?preview=N and renders only that slide
- CSS transform:scale() fits 1920x1080 into card body, centered
- Zero style injection / zero HTML escaping — can't break
Sync: BroadcastChannel keeps audience ↔ presenter in lockstep.
Verified with headless Chrome: tokyo-night theme, gradient headlines,
speaker avatars, agenda rows — all render identically between windows.