Restyle the code-drawn UI toward the candy look — colours, corner-rounding
and glossy feel only; no rect geometry moves.
- HUD: grape candy card with a glossy top sheen, a bright rounded rim and
warm cream text on a soft purple shadow (was a flat dark translucent panel).
- Banner panel: grape candy fill under a sheen + bright rim, rounder corners.
- Titles: celebratory candy gold YOU WIN! / punchy coral OUT OF MOVES, each
on a tinted drop shadow for pop.
- PLAY AGAIN: bubblegum candy button with a glossy sheen, bright rim and a
darker bevel lip for a 3D candy edge.
BannerLayout rects (panel/title/button) and the restart hit-test are
untouched, so tests/banner_layout still passes. Refresh the p4_hud / p7_win /
p7_lose goldens.
Polish pass before final acceptance. The 8x8 grid was rendering flush to the
left/right screen edges (gems ~4pt from the bezel on iPhone 17). Add a content
margin (BOARD_INSET_X = 16pt) layered on top of the platform safe-area insets so
the grid is framed by the background, while the HUD keeps using the bare safe
insets so it still hugs the top below the Dynamic Island. The grid is
width-constrained in portrait, so this inset is what sizes it; vertical
centering inside the safe area is unchanged, and the win/lose banner (derived
from the grid) stays centered over the framed board.
Safe-area verified on a current iPhone simulator (iPhone 17, iOS 26): HUD below
the Dynamic Island, board far above the home indicator, forced win/lose banners
centered and unclipped.
The headless geometry tests (hit_test, banner_layout) call compute() with a
zero inset directly, so they are unaffected; full logic gate stays green (18/18).
Goldens: add p9_polish.png (resting board, M3TE_ANIM_TIME=0) as the canonical
polished layout. Re-capture the README-documented deterministic goldens whose
board position shifts by the 16pt margin (p4_board, p4_hud, p6_idle_t0,
p6_idle_mid, p6_select, p7_win, p7_lose, p7_restart). The in-flight move-timeline
goldens (p5_swap_*, p6_anim_*, p6_fx_*, p6_inputlock_board) and the p0 quad
goldens are not reproducible via the documented env pins (which pin only the idle
clock + level state), so they are left as-is.
Tap a gem to select it: BoardView hit-tests the touch to a grid cell and
draws a bright rim + translucent fill over it; tapping the same cell clears
the selection, tapping another moves it, tapping off-board clears it.
Selection only — no swap (that's P5). The HUD renders the live score and
remaining moves (out of the move limit) in the Lato font on a translucent
card above the grid.
The touch→cell geometry is factored into a pure BoardLayout (no GL/stb
imports) that BoardView composes and P5 will reuse for swap endpoints.
tests/hit_test.sx locks point_to_cell as the exact inverse of cell_frame
(every cell center round-trips; off-board taps reject) — headless because
BoardLayout pulls no C imports. goldens/p4_hud.png captures the scene after
a real idb tap at (201,437)pt: the HUD plus a yellow selection rim on the
red gem at cell (col 4, row 3).