The header ✕ sat under the iPhone status bar/notch (overlay had no safe-area
padding), so there was no reachable way out without saving. Add a labeled Cancel
button next to Save, and pad the header/footer for the notch + home indicator.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The tap picker wasn't working in practice. Replace it with simple text inputs for
hero/board/shown cards: case-insensitive, accepts 'ah kh' / 'AhKh' / '7d2c5h' /
'10h'. parseCards() tokenizes; the server's normalize_structured() canonicalizes
(case, 10->T, completeness). Also adds per-action remove (✕) in the street log.
Picker UI + bottom-sheet CSS removed; tap picker deferred to V2 (docs/RECORDER.md).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Tap-to-build hand recorder per docs/RECORDER.md. Correctness by construction: every
tap writes a known value into a known slot, emitting the canonical structured contract
(server normalize_structured() is the shape authority, so the client is best-effort).
- recorder.js: mount-agnostic module (mounts into any container -> overlay now,
standalone later, zero logic change). Pure buildStructured(state)->contract dict.
Card picker: sticky-suit-or-rank-first + x (unknown suit) + unknown-card; lock resets
per slot so it never bleeds between cards. Pre-fills from /session/data (stakes->blinds,
stack->hero, villains->seated). Per-street action entry, manual street advance.
- recorder.css: full-screen overlay using app theme tokens; floating launcher.
- index.html: overlay div + script + launcher (chat/session stays mounted underneath).
Validated end-to-end: JS core builds a hand (sticky/rainbow/unknown cards all correct)
-> POST /hands -> normalized -> /hand/{id} replay round-trips identically.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>