my-sea deck-stack + spread-card glow: unify hover-reveal / click-persist + --ninUser halo — TDD
Unify the glow/FLIP interaction across the owner picker (my_sea) + the read-only spectator (my_sea_visit), then carry the same selection halo onto the spread cards + deck-stack faces. DECK STACK (user-spec 2026-05-30) — the owner revealed the FLIP only on click (persisted) but never on hover; the spectator revealed it on hover but never persisted. Now BOTH do both: - `.sea-stack-ok` reveal is a single shared rule in _card-deck.scss — opacity fades in on hover/focus (ephemeral) OR via the JS-set `.sea-deck-stack--active` class (click-persist, same class the face-glow rides). The owner's inline `display` toggling is gone (`_showOk`/`_hideOk` just flip `--active`); the spectator's hover-only override in _gameboard.scss is removed. - Interactivity stays gated on `--active`, NOT hover: hover is a purely VISUAL preview (matching the spectator's disabled FLIP). This preserves the owner's two-step deal — were the FLIP click-through on hover, a single stack-click would land on the centred FLIP + deal early (caught by the draw FT). - Spectator persist wired in my_sea_visit.html (click a stack → `--active`, click elsewhere clears); its FLIP stays `.btn-disabled` (read-only). SPREAD CARDS — the same hover-glow + active-persist now on EVERY spread card, building on the cover/cross rules. The prior `.sea-card-slot--focused` glow (0-1-0) was silently overridden by the filled-card drop-shadow ladder (up to 0-4-0) and never rendered (verified live); `!important` (consistent w. the existing `opacity:1 !important` there) makes the halo win on hover + focus. The halo is symmetric (rotation-invariant). No colour change — box-shadow only. DECK FACE HALO — the levity + gravity stack glows now mirror the card halo's tuned geometry (0.5rem blur / 0.5rem spread / 0.3 alpha), each in its own polarity colour (--ninUser / --quaUser); single keeps its own tone. Verified live in Firefox: deck FLIP persists on click + fades on hover; the card halo wins over the drop-shadow on hover/focus across crown/cover/(reversed-)cross; levity/gravity deck glows match the card halo. Draw FTs green (single-draw, hand- completion, AUTO DRAW, auto-drawn-slot reopen) — the two-step deal + card focus survive the display→opacity switch. Code architected by Disco DeDisco <discodedisco@outlook.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -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-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; }
|
.sea-pos-cross .sea-card-slot--visible { opacity: 0.15; animation: sea-cross-appear 2s ease; }
|
||||||
|
|
||||||
// Hover: reveal fully (snappy)
|
// ── Spread-card hover-glow + active-persist (user-spec 2026-05-30) ──────────
|
||||||
.sea-pos-cover .sea-card-slot--visible:hover,
|
// Mirror the deck-stack's hover / `--active` glow onto EACH spread card: the
|
||||||
.sea-pos-cross .sea-card-slot--visible:hover { opacity: 1; transition: opacity 0.15s ease; }
|
// 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 {
|
.sea-card-slot--focused {
|
||||||
opacity: 1 !important;
|
opacity: 1 !important;
|
||||||
transition: opacity 0.15s ease, box-shadow 0.15s ease;
|
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
|
// Cover + Cross — absolutely overlaid on the Sig card in .sea-pos-core
|
||||||
@@ -2000,7 +2020,27 @@ $sea-card-h: 6.5rem;
|
|||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
z-index: 5;
|
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
|
.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
|
// 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);
|
$_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);
|
// Levity + gravity stack glows mirror the spread-card halo's tuned geometry
|
||||||
$_glow-gravity: 0 0 0.8rem 0.15rem rgba(var(--quaUser), 0.6);
|
// ($_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 {
|
.sea-deck-stack--levity .sea-stack-face {
|
||||||
background: rgba(var(--terUser), 0.88);
|
background: rgba(var(--terUser), 0.88);
|
||||||
|
|||||||
@@ -808,20 +808,11 @@ body.page-gameboard {
|
|||||||
transform-origin: center;
|
transform-origin: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read-only FLIP (disabled ×) — hidden until its stack is hovered/focused,
|
// FLIP reveal (hover-fade + click-persist) is now the SHARED `.sea-stack-ok`
|
||||||
// then eases in: same reveal shape as the shared `flip-btn-base` mixin
|
// behaviour in _card-deck.scss — unified with the owner picker per user-spec
|
||||||
// (opacity 0→1 over 0.3s ease), inlined here because _gameboard.scss is
|
// 2026-05-30, so the visitor's prior hover-only override is gone. The
|
||||||
// imported before _card-deck.scss (where the mixin lives). Stays non-
|
// spectator's click-persist (`.sea-deck-stack--active`) is wired in
|
||||||
// interactive — `.btn-disabled` keeps pointer-events:none. The base
|
// my_sea_visit.html (the read-only FLIP stays disabled throughout).
|
||||||
// `.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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Iter 4b: Brief banner + DEL guard portal ─────────────────────────────────
|
// ── Iter 4b: Brief banner + DEL guard portal ─────────────────────────────────
|
||||||
|
|||||||
@@ -357,10 +357,12 @@
|
|||||||
return DRAW_ORDER[hidden.value] || [];
|
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() {
|
function _hideOk() {
|
||||||
if (_activeStack) {
|
if (_activeStack) {
|
||||||
var ok = _activeStack.querySelector('.sea-stack-ok');
|
|
||||||
if (ok) ok.style.display = 'none';
|
|
||||||
_activeStack.classList.remove('sea-deck-stack--active');
|
_activeStack.classList.remove('sea-deck-stack--active');
|
||||||
_activeStack = null;
|
_activeStack = null;
|
||||||
}
|
}
|
||||||
@@ -369,8 +371,6 @@
|
|||||||
_hideOk();
|
_hideOk();
|
||||||
_activeStack = stack;
|
_activeStack = stack;
|
||||||
stack.classList.add('sea-deck-stack--active');
|
stack.classList.add('sea-deck-stack--active');
|
||||||
var ok = stack.querySelector('.sea-stack-ok');
|
|
||||||
if (ok) ok.style.display = '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function _fillSlot(positionName, card, isLevity) {
|
function _fillSlot(positionName, card, isLevity) {
|
||||||
@@ -529,7 +529,6 @@
|
|||||||
});
|
});
|
||||||
var ok = stack.querySelector('.sea-stack-ok');
|
var ok = stack.querySelector('.sea-stack-ok');
|
||||||
if (ok) {
|
if (ok) {
|
||||||
ok.style.display = 'none';
|
|
||||||
ok.addEventListener('click', function (e) {
|
ok.addEventListener('click', function (e) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
// Hand complete → FLIP is disabled. No draw.
|
// Hand complete → FLIP is disabled. No draw.
|
||||||
|
|||||||
@@ -137,6 +137,34 @@
|
|||||||
}
|
}
|
||||||
}());
|
}());
|
||||||
</script>
|
</script>
|
||||||
|
{# 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. #}
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
var overlay = document.getElementById('id_sea_overlay');
|
||||||
|
if (!overlay) return;
|
||||||
|
var stacks = overlay.querySelectorAll('.sea-deck-stack');
|
||||||
|
if (!stacks.length) return;
|
||||||
|
function clearAll(except) {
|
||||||
|
stacks.forEach(function (s) {
|
||||||
|
if (s !== except) s.classList.remove('sea-deck-stack--active');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
stacks.forEach(function (stack) {
|
||||||
|
stack.addEventListener('click', function (e) {
|
||||||
|
e.stopPropagation(); // don't let the overlay handler clear it
|
||||||
|
var on = stack.classList.contains('sea-deck-stack--active');
|
||||||
|
clearAll(stack);
|
||||||
|
stack.classList.toggle('sea-deck-stack--active', !on);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// A click anywhere else on the cross drops the persisted reveal.
|
||||||
|
overlay.addEventListener('click', function () { clearAll(null); });
|
||||||
|
}());
|
||||||
|
</script>
|
||||||
{# Async witness — a WS to `mysea_<owner>` pushes the owner's hand as each #}
|
{# Async witness — a WS to `mysea_<owner>` pushes the owner's hand as each #}
|
||||||
{# card lands; SeaDeal.register fills the cross slot (+ seeds it clickable) #}
|
{# card lands; SeaDeal.register fills the cross slot (+ seeds it clickable) #}
|
||||||
{# live, no refresh. A DEL (empty hand) re-empties the cleared slots. #}
|
{# live, no refresh. A DEL (empty hand) re-empties the cleared slots. #}
|
||||||
|
|||||||
Reference in New Issue
Block a user