diff --git a/src/static_src/scss/_card-deck.scss b/src/static_src/scss/_card-deck.scss index 85fd280..e6f5857 100644 --- a/src/static_src/scss/_card-deck.scss +++ b/src/static_src/scss/_card-deck.scss @@ -1696,15 +1696,35 @@ $sea-card-h: 6.5rem; .sea-pos-cover .sea-card-slot--visible { opacity: 0.3; animation: sea-cover-appear 2s ease; } .sea-pos-cross .sea-card-slot--visible { opacity: 0.15; animation: sea-cross-appear 2s ease; } -// Hover: reveal fully (snappy) -.sea-pos-cover .sea-card-slot--visible:hover, -.sea-pos-cross .sea-card-slot--visible:hover { opacity: 1; transition: opacity 0.15s ease; } +// ── Spread-card hover-glow + active-persist (user-spec 2026-05-30) ────────── +// Mirror the deck-stack's hover / `--active` glow onto EACH spread card: the +// customary --ninUser selection halo appears on HOVER + PERSISTS on the active +// (`.sea-card-slot--focused`) two-tap selection sea.js sets. Builds on the +// cover/cross opacity-reveal rules above. +// +// `!important`: the filled-card drop-shadow ladder (lines ~498-542) climbs to +// 0-4-0, so on a hovered/focused rotated card it out-specifies a plain +// `.sea-card-slot--focused` box-shadow (0-1-0) — exactly why the PRIOR focused +// glow silently never rendered (verified 2026-05-30). The halo is symmetric so +// it's rotation-invariant; it replaces the tiny directional drop (the +// established focused intent). No colour change — box-shadow only. +$_sea-card-glow: 0 0 0.5rem 0.5rem rgba(var(--ninUser), 0.3), 0 0 0.4rem rgba(0, 0, 0, 0.85); -// Focused (first tap): persist at opacity 1 + selection glow until modal opens +// Hover: Cover/Cross bump opacity to full (they overlay the semi-transparent +// sig); every position then gains the halo. +.sea-pos-cover .sea-card-slot--visible:hover, +.sea-pos-cross .sea-card-slot--visible:hover { opacity: 1; } +.my-sea-cross .sea-card-slot--visible:hover { + box-shadow: $_sea-card-glow !important; + transition: opacity 0.15s ease, box-shadow 0.15s ease; +} + +// Active/persist (first tap): hold full opacity + the halo until the second tap +// opens the stage (sea.js two-tap pattern, all positions). .sea-card-slot--focused { opacity: 1 !important; transition: opacity 0.15s ease, box-shadow 0.15s ease; - box-shadow: 0 0 0.5rem 0.25rem rgba(var(--ninUser), 0.35), 0 0 0.4rem rgba(0, 0, 0, 0.85); + box-shadow: $_sea-card-glow !important; } // Cover + Cross — absolutely overlaid on the Sig card in .sea-pos-core @@ -2000,7 +2020,27 @@ $sea-card-h: 6.5rem; margin: 0 auto; transform: translateY(-50%); z-index: 5; + // FLIP reveal — UNIFIED across the owner picker (my_sea) + the read-only + // spectator (my_sea_visit), user-spec 2026-05-30. Hidden + non-interactive + // by default; HOVER / focus fades it in ephemerally; a CLICK PERSISTS it via + // the JS-set `.sea-deck-stack--active` class (the same class the face-glow + // rules below persist on). Was split: the owner toggled `display` on click + // only (no hover); the spectator faded on hover only (no persist). + opacity: 0; + pointer-events: none; + transition: opacity 0.3s ease; } +.sea-deck-stack:hover .sea-stack-ok, +.sea-deck-stack:focus-within .sea-stack-ok, +.sea-deck-stack--active .sea-stack-ok { opacity: 1; } +// Interactivity is gated on the PERSIST state (`--active`), NOT hover. Hover is +// a purely VISUAL preview — same as the spectator's disabled FLIP, whose "hover +// effect" is just the reveal. Keeping the FLIP click-through on hover preserves +// the owner's two-step deal: click the stack (→ `--active`) THEN click the FLIP. +// Were it clickable on hover, a single stack-click would land on the centred +// FLIP itself + deal early. The spectator's FLIP stays `.btn-disabled` (read- +// only) so it never becomes interactive even while persisted. +.sea-deck-stack--active .sea-stack-ok:not(.btn-disabled) { pointer-events: auto; } .sea-deck-stack { gap: 0; } // remove gap so name slides under the face @@ -2021,8 +2061,13 @@ $sea-card-h: 6.5rem; // Deck backs — face-down pile colour identifies polarity $_sea-shadow: 1px 2px 0 rgba(0,0,0,0.7), 0 4px 0 rgba(0,0,0,0.18), 2px 5px 5px rgba(0,0,0,0.5); -$_glow-levity: 0 0 0.8rem 0.15rem rgba(var(--ninUser), 0.6); -$_glow-gravity: 0 0 0.8rem 0.15rem rgba(var(--quaUser), 0.6); +// Levity + gravity stack glows mirror the spread-card halo's tuned geometry +// ($_sea-card-glow, user-tuned 2026-05-30: 0.5rem blur / 0.5rem spread / 0.3 +// alpha) so the deck glows read identically to the card halo — each keeps its +// own polarity colour (--ninUser / --quaUser). Duplicated literally (not +// shared) so each stays independently tunable. (single keeps its own tone.) +$_glow-levity: 0 0 0.5rem 0.5rem rgba(var(--ninUser), 0.3); +$_glow-gravity: 0 0 0.5rem 0.5rem rgba(var(--ninUser), 0.3); .sea-deck-stack--levity .sea-stack-face { background: rgba(var(--terUser), 0.88); diff --git a/src/static_src/scss/_gameboard.scss b/src/static_src/scss/_gameboard.scss index e89ddfe..e26d483 100644 --- a/src/static_src/scss/_gameboard.scss +++ b/src/static_src/scss/_gameboard.scss @@ -808,20 +808,11 @@ body.page-gameboard { transform-origin: center; } - // Read-only FLIP (disabled ×) — hidden until its stack is hovered/focused, - // then eases in: same reveal shape as the shared `flip-btn-base` mixin - // (opacity 0→1 over 0.3s ease), inlined here because _gameboard.scss is - // imported before _card-deck.scss (where the mixin lives). Stays non- - // interactive — `.btn-disabled` keeps pointer-events:none. The base - // `.sea-stack-ok` positioning is untouched (we only add the fade). - .sea-stack-ok { - opacity: 0; - transition: opacity 0.3s ease; - } - .sea-deck-stack:hover .sea-stack-ok, - .sea-deck-stack:focus-within .sea-stack-ok { - opacity: 1; - } + // FLIP reveal (hover-fade + click-persist) is now the SHARED `.sea-stack-ok` + // behaviour in _card-deck.scss — unified with the owner picker per user-spec + // 2026-05-30, so the visitor's prior hover-only override is gone. The + // spectator's click-persist (`.sea-deck-stack--active`) is wired in + // my_sea_visit.html (the read-only FLIP stays disabled throughout). } // ── Iter 4b: Brief banner + DEL guard portal ───────────────────────────────── diff --git a/src/templates/apps/gameboard/my_sea.html b/src/templates/apps/gameboard/my_sea.html index 8cdc045..5fa9424 100644 --- a/src/templates/apps/gameboard/my_sea.html +++ b/src/templates/apps/gameboard/my_sea.html @@ -357,10 +357,12 @@ return DRAW_ORDER[hidden.value] || []; } + // FLIP visibility is now CSS-driven (opacity on hover/focus + + // the `.sea-deck-stack--active` persist class — unified w. the + // spectator page, user-spec 2026-05-30). `_showOk`/`_hideOk` just + // toggle `--active`; no more inline `display` juggling. function _hideOk() { if (_activeStack) { - var ok = _activeStack.querySelector('.sea-stack-ok'); - if (ok) ok.style.display = 'none'; _activeStack.classList.remove('sea-deck-stack--active'); _activeStack = null; } @@ -369,8 +371,6 @@ _hideOk(); _activeStack = stack; stack.classList.add('sea-deck-stack--active'); - var ok = stack.querySelector('.sea-stack-ok'); - if (ok) ok.style.display = ''; } function _fillSlot(positionName, card, isLevity) { @@ -529,7 +529,6 @@ }); var ok = stack.querySelector('.sea-stack-ok'); if (ok) { - ok.style.display = 'none'; ok.addEventListener('click', function (e) { e.stopPropagation(); // Hand complete → FLIP is disabled. No draw. diff --git a/src/templates/apps/gameboard/my_sea_visit.html b/src/templates/apps/gameboard/my_sea_visit.html index 7799689..594110d 100644 --- a/src/templates/apps/gameboard/my_sea_visit.html +++ b/src/templates/apps/gameboard/my_sea_visit.html @@ -137,6 +137,34 @@ } }()); + {# Deck-stack persist — the spectator's FLIP is disabled (read-only), but #} + {# clicking a stack PERSISTS its glow + the revealed × via the shared #} + {# `.sea-deck-stack--active` class (same persist the owner picker uses, #} + {# user-spec 2026-05-30). Hover-reveal + the fade are the shared CSS; this #} + {# only adds the click-to-lock. Clicking another stack / elsewhere clears. #} + {# Async witness — a WS to `mysea_` pushes the owner's hand as each #} {# card lands; SeaDeal.register fills the cross slot (+ seeds it clickable) #} {# live, no refresh. A DEL (empty hand) re-empties the cleared slots. #}