1fcd032b0a
The replay viewer's renderer used to wipe and rebuild every card from scratch on every step (`board.replaceChildren()`). Each step was a discrete redraw — fine for correctness, abrupt for the eye. Restructured to a persistent card-element model: - `#board` is now a positioned context (relative) instead of a CSS grid. The dashed empty-pile placeholders are absolutely- positioned `.slot` elements painted once at bootstrap. - Each card lives as a sibling of the slots, absolutely-positioned with `transform: translate(x, y)`. The CSS transition on `transform` (280 ms cubic-bezier) runs every move as a flight rather than a redraw. - `cardEls: Map<id, HTMLElement>` persists across renders. Cards unchanged between steps don't re-create their DOM at all. - Z-index is set per-render from the card's pile index so a card flying out from the bottom of a tableau passes behind the cards above it. - Newly-spawned cards (rare — only on Restart) fade in at their target position via a `requestAnimationFrame` opacity flip; cards that disappear (also rare) fade out and despawn after the 220 ms fade. - `will-change: transform` lets the browser composite the animation, keeping it smooth on low-spec hardware. Restart now drops every existing card before resetting so the fresh deal looks like a new game, not a continuation. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>