The gate check ran during SSR where navigator is undefined,
rendering the 'Unsupported browser' div into the initial HTML.
Now gated on browser (client-only) so SSR renders the app
and the gate evaluates in the browser.
1. drawOverlay: checkerboard mask overlay now drawn in axis + measure
states (mask carry-forward — slab is isolated)
2. Removed the separate red axis line + arrowhead — the rect's long
side IS the axis
3. Rect rotates: uses axisState.rect.angle (from UAT-8a)
4. Replace three rotate buttons with slider (-180..180, step 1) +
minus/plus nudge buttons (same pattern as Sensitivity slider)
587 lines, 109/109 tests, build OK.
Spec CAPTURE.md §Browsers: Phone iOS Safari / Android Chrome, PC
Chrome / Edge / Firefox, others hard stop.
- browserGate.js: UA detection + allowlist (pure, DOM-free)
- +layout.svelte: renders hard-stop panel when unsupported
- iPadOS 13+ reports as Macintosh — added Safari rule (Version/ +
Safari/ without Chrome/) so iPad Safari is not blocked
- 27 unit tests incl. iPad Safari regression
- 107/107 full suite green
Spec CAPTURE.md §Mask lists exactly two controls: Sheet and Sensitivity. Edge offset and feather nudge buttons were extra. Removed from the UI; core params (edgeOffset, feather) remain in maskState.js, still unit-tested.