From 82f4af9bccc9024b968e47d791cd66f8e87cb9ac Mon Sep 17 00:00:00 2001 From: Disco DeDisco Date: Mon, 8 Jun 2026 00:38:58 -0400 Subject: [PATCH] =?UTF-8?q?Sea=20Select=20glow:=20defer=20sea-btn=20reopen?= =?UTF-8?q?=20+=20glow=20handoff=20past=20parse=20time;=20pulse=20the=20gl?= =?UTF-8?q?ow-handoff=20=E2=80=94=20TDD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit room.html includes _sea_overlay.html (~L77) BEFORE _burger.html (~L167, which holds #id_burger_btn + #id_sea_btn), so the overlay's two inline scripts captured those btns at parse time → null → both bindings silently no-op'd: the sea btn (active post-completion) did nothing on click + the burger stayed stuck --priId because its glow-handoff transfer listener never bound. Defer both the sea-btn REOPEN binding (_bindSeaReopen) & the burger→sea_btn→.sea-select GLOW chain (_bindGlowHandoff) to DOMContentLoaded so the burger fan exists first. Also make the glow-handoff halo PULSE (quick ease-in swell, slow ease-out decay via per-segment timing fns + a lopsided 22/78 keystop split) instead of a flat glow — the burger, then the sea btn after the handoff click, keep cueing "click me to reopen your sea". Co-Authored-By: Claude Opus 4.8 (1M context) --- src/apps/epic/tests/integrated/test_views.py | 14 ++++ src/static_src/scss/_burger.scss | 32 +++++++- .../gameboard/_partials/_sea_overlay.html | 77 ++++++++++++------- 3 files changed, 92 insertions(+), 31 deletions(-) diff --git a/src/apps/epic/tests/integrated/test_views.py b/src/apps/epic/tests/integrated/test_views.py index 3a9f739..70f7987 100644 --- a/src/apps/epic/tests/integrated/test_views.py +++ b/src/apps/epic/tests/integrated/test_views.py @@ -4270,6 +4270,20 @@ class PickSeaUnifiedFeltTest(TestCase): [sea] = parsed.cssselect("#id_pick_sea_btn") self.assertIn("hex-phase-btn--out", sea.get("class", "")) + def test_sea_btn_and_glow_bindings_defer_past_parse_time(self): + """room.html includes _sea_overlay.html (~line 77) BEFORE _burger.html + (~line 167, which holds #id_burger_btn + #id_sea_btn). So the overlay's + inline scripts must NOT bind those btns at parse time — they don't exist + yet, and a parse-time `getElementById` returns null → the sea-btn REOPEN + binding + the burger→sea_btn GLOW handoff both silently no-op (sea btn + dead, burger stuck --priId until refresh). Both bindings must defer to + DOMContentLoaded. Regression guard for the 2026-06-08 include-order fix.""" + content = self.client.get(self.url).content.decode() + # Both deferred binders present + gated on DOMContentLoaded. + self.assertIn("_bindSeaReopen", content) + self.assertIn("_bindGlowHandoff", content) + self.assertIn("DOMContentLoaded", content) + class CarteSeatSwitchSkySeaTest(TestCase): """A CARTE owner (one gamer owns all 6 seats) must drive EACH seat through diff --git a/src/static_src/scss/_burger.scss b/src/static_src/scss/_burger.scss index 9c2f0e5..e879fcc 100644 --- a/src/static_src/scss/_burger.scss +++ b/src/static_src/scss/_burger.scss @@ -183,13 +183,39 @@ // the burger. AUTO DRAW's guard-OK ends the cycle permanently (the user // has actually drawn — they've found the path). Owner: my_sea.html + // _sea_overlay.html JS. +// The --priId border/color stays steady; the --ninUser halo PULSES — a quick +// ease-IN swell then a slow ease-OUT decay (user-spec 2026-06-08) so the burger +// (and, after the handoff click, the sea btn) keeps cueing "click me to reopen +// your sea" rather than sitting as a flat glow. Rides until the chain advances. #id_burger_btn.glow-handoff, #id_sea_btn.glow-handoff { color: rgba(var(--priId), 1); border-color: rgba(var(--priId), 1); - box-shadow: - 0 0 0.5rem 0.1rem rgba(var(--ninUser), 0.75), - 0 0 1.2rem 0.3rem rgba(var(--ninUser), 0.35); + animation: glow-handoff-pulse 1.8s infinite; +} + +// Quick ease-IN to the bright peak over the first ~22% of the cycle, then a slow +// ease-OUT fade back to the dim trough across the remaining ~78%. The per-segment +// timing fns set the in/out asymmetry; the lopsided keystop split makes the swell +// feel snappy and the decay linger. +@keyframes glow-handoff-pulse { + 0% { + box-shadow: + 0 0 0.35rem 0.05rem rgba(var(--ninUser), 0.25), + 0 0 0.7rem 0.1rem rgba(var(--ninUser), 0.12); + animation-timing-function: ease-in; + } + 22% { + box-shadow: + 0 0 0.6rem 0.15rem rgba(var(--ninUser), 0.95), + 0 0 1.4rem 0.4rem rgba(var(--ninUser), 0.55); + animation-timing-function: ease-out; + } + 100% { + box-shadow: + 0 0 0.35rem 0.05rem rgba(var(--ninUser), 0.25), + 0 0 0.7rem 0.1rem rgba(var(--ninUser), 0.12); + } } // ── Sky-saved glow (CAST SKY → SAVE SKY) ────────────────────────────── diff --git a/src/templates/apps/gameboard/_partials/_sea_overlay.html b/src/templates/apps/gameboard/_partials/_sea_overlay.html index 0631813..cb173c9 100644 --- a/src/templates/apps/gameboard/_partials/_sea_overlay.html +++ b/src/templates/apps/gameboard/_partials/_sea_overlay.html @@ -482,14 +482,23 @@ via epic:sea_save. `?seat` threads the CARTE-selected seat onto the action URLs. // ── Sea sub-btn = post-completion REOPEN (active only once the spread is // complete, like the sky btn). An ACTIVE click re-shows the felt to review the // saved spread (window.openSeaFelt); inactive clicks fall to burger-btn.js's - // --priRd flash. - var seaSubBtn = document.getElementById('id_sea_btn'); - if (seaSubBtn) { + // --priRd flash. DEFERRED to DOMContentLoaded: #id_sea_btn lives in + // _burger.html, which room.html includes AFTER this overlay — a parse-time + // getElementById returns null → the binding would silently no-op (sea btn + // dead). Bind once the burger fan exists. + function _bindSeaReopen() { + var seaSubBtn = document.getElementById('id_sea_btn'); + if (!seaSubBtn) return; seaSubBtn.addEventListener('click', function () { if (!seaSubBtn.classList.contains('active')) return; openSea(); }); } + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', _bindSeaReopen); + } else { + _bindSeaReopen(); + } // Re-seed SeaDeal's `_seaHand` from the server-rendered saved slots so they // stay clickable to RE-OPEN the stage after a refresh. @@ -528,32 +537,44 @@ via epic:sea_save. `?seat` threads the CARTE-selected seat onto the action URLs. {# .sea-select → end, so the user is led to reopen + review their sea. #}