room Sig Select: unify with the my_sign card-stage apparatus (DRY stat-block, per-card stage image, --duoUser felt)
The in-room SIG_SELECT stage diverged from the polished GAME SIGN page:
a fixed dark-Gaussian modal over the hex, a stale label-only stat-block,
and no card imagery. This brings it in line with my_sign / my_sea.
A — Stat-block DRY: _sig_select_overlay.html now renders the shared
core/_partials/_stat_face.html (rank-chip + title + arcana + keywords)
instead of a reduced label-only copy; sig-select.js's updateStage() now
calls StageCard.populateStatExtras (the missing call that left those
fields blank). data-arcana-key added per card for title color-keying.
B — Per-card stage image: the stage card gains a .sig-stage-card-img
slot + data-image-url per thumbnail, so an image-equipped seat deck
(RWS / Minchiate) shows real card art on the preview. Thumbnails stay
glyph-only (rank + suit) at every deck — only the stage shows the image.
Keyed off each card's OWN deck_variant, so it auto-upgrades to mixed art
when the dubbodeck assembly lands. No backend change (cards already
carry a deck_variant via _room_deck_variant).
C — Felt-in-aperture: the stage renders INSIDE .room-hex-pane on edge-to-
edge green --duoUser felt (my_sea-style), replacing the hex content; the
old .sig-backdrop blur is gone. .sig-overlay absolute-fills the pane
(.room-hex-pane.has-sig-stage = positioning context); dismissing it
reveals the hex + waiting message behind. Scroll-down still reaches the
reelhouse carousel (untouched scroll pane).
Polishes:
- Image-mode bg escape: the levity 0,3,0 polarity rule
(.sig-overlay/.my-sign-page[data-polarity="levity"] .sig-stage-card)
hard-set a --secUser background that re-clothed image cards behind the
transparent PNG. Added the &.sig-stage-card--image { background:
transparent; border:0; overflow:visible } escape (parity w. the base +
my-sea rules). Latent my_sign bug too. Monodeck-era assumption.
- FLIP .btn-reveal: non-polarized image decks get a FLIP that turns the
preview to the deck card-back (my_sign parity) — back-img + reused
.my-sign-flip-btn (shared positioning/hide/counter-position rules
already cover .sig-stage-card) + a frozen-gated reveal scoped to
.sig-overlay + sig-select.js _flipToBack (500ms Y-rotate, midpoint
swap). SPIN now sets data-spinning so the btn hides mid-rotate.
- Reserved thumbs-up / hover cursors portal to a body-root fixed
container, so they hung over the reelhouse on scroll. sig-select.js now
toggles .cursors-hidden off the aperture scrollTop: instant hide the
moment the scroll leaves the hex, 0.5s opacity ease-in on the full
return. Tray intentionally kept.
TDD: SigSelectUnifiedStageTest (6 ITs) — DRY stat-face present, per-card
data-image-url + data-arcana-key, .sig-stage-card-img slot, image deck
non-empty face URL / text deck empty, has-sig-stage felt + overlay inside
the hex pane. 319 epic test_views ITs green; user-verified live on an RWS
room (no rect, FLIP works, thumb timing). Jasmine for the JS wiring +
the dubbodeck cross-deck assembly (per-seat segment cards, CARTE-solo
both-polarity case, per-card backs) are the tracked follow-on.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -98,6 +98,11 @@ var SigSelect = (function () {
|
||||
uprightSel: '#id_stat_keywords_upright',
|
||||
reversedSel: '#id_stat_keywords_reversed',
|
||||
});
|
||||
// Fill the rank-chip + title + arcana of the DRY _stat_face.html block
|
||||
// (unified w. my_sign 2026-06-03) — previously the sig stat-block was a
|
||||
// reduced label-only copy, so this call was absent and those fields
|
||||
// stayed blank.
|
||||
StageCard.populateStatExtras(statBlock, card);
|
||||
|
||||
stageCard.style.display = '';
|
||||
stage.classList.add('sig-stage--active');
|
||||
@@ -113,6 +118,32 @@ var SigSelect = (function () {
|
||||
updateStage(cardEl);
|
||||
}
|
||||
|
||||
// ── FLIP — reveal the deck card-back (non-polarized image decks) ──────
|
||||
//
|
||||
// my_sign parity (its `_flipToBackAnimated`): a 500ms Y-axis half-rotation
|
||||
// that swaps the front face for the deck's card-back at the midpoint. The
|
||||
// back-img + .sig-flip-btn render only for non-polarized image decks
|
||||
// (template gate), so this no-ops on Earthman/text decks. SPIN orientation
|
||||
// (.stage-card--reversed) is preserved through the flip. `data-flipping`
|
||||
// hides the in-card FLIP btn mid-rotate (shared SCSS rule).
|
||||
function _flipToBack() {
|
||||
if (!stageCard || stageCard.dataset.flipping) return;
|
||||
stageCard.dataset.flipping = '1';
|
||||
var spin = stageCard.classList.contains('stage-card--reversed')
|
||||
? ' rotate(180deg)' : '';
|
||||
var rest = 'translateX(0px) rotateY(0deg) scale(1)' + spin;
|
||||
var mid = rest + ' rotateY(90deg)';
|
||||
stageCard.animate([
|
||||
{ transform: rest },
|
||||
{ transform: mid, offset: 0.5 },
|
||||
{ transform: rest },
|
||||
], { duration: 500, easing: 'ease' });
|
||||
setTimeout(function () {
|
||||
stageCard.classList.toggle('is-flipped-to-back');
|
||||
}, 250);
|
||||
setTimeout(function () { delete stageCard.dataset.flipping; }, 500);
|
||||
}
|
||||
|
||||
// ── Hover events ──────────────────────────────────────────────────────
|
||||
|
||||
function onCardEnter(e) {
|
||||
@@ -482,8 +513,9 @@ var SigSelect = (function () {
|
||||
function _dismissSigOverlay() {
|
||||
_hideCountdown();
|
||||
_hideTakeSigBtn();
|
||||
var backdrop = document.querySelector('.sig-backdrop');
|
||||
if (backdrop) backdrop.remove();
|
||||
// Removing the felt overlay reveals the hex + waiting message that sit
|
||||
// behind it in the pane (no separate dark backdrop element anymore —
|
||||
// the felt lives on .sig-overlay itself since the 2026-06-03 unify).
|
||||
if (overlay) { overlay.remove(); overlay = null; }
|
||||
// Remove all floating cursors (hover + thumbs-up) from the portal
|
||||
Object.keys(_reservedFloats).forEach(function (role) {
|
||||
@@ -594,9 +626,38 @@ var SigSelect = (function () {
|
||||
_flipBtn.addEventListener('click', function () {
|
||||
if (_flipBtn.classList.contains('btn-disabled')) return;
|
||||
statBlock.classList.toggle('is-reversed');
|
||||
// data-spinning hides the in-card FLIP btn for the 0.4s CSS rotate
|
||||
// (shared `.sig-stage-card[data-spinning] .my-sign-flip-btn` rule)
|
||||
// so it doesn't ride the spin between bottom-left + top-right.
|
||||
stageCard.dataset.spinning = '1';
|
||||
stageCard.classList.toggle('stage-card--reversed');
|
||||
setTimeout(function () { delete stageCard.dataset.spinning; }, 400);
|
||||
});
|
||||
|
||||
// FLIP-to-back (non-polarized image decks only — btn renders just then).
|
||||
var sigFlipBtn = stageCard.querySelector('.sig-flip-btn');
|
||||
if (sigFlipBtn) {
|
||||
sigFlipBtn.addEventListener('click', _flipToBack);
|
||||
}
|
||||
|
||||
// Reserved thumbs-up + hover cursors portal to a body-root fixed
|
||||
// container, so they'd hang over the reelhouse when the aperture scroll-
|
||||
// snaps down to it. Drive their visibility straight off the aperture's
|
||||
// scrollTop: 0 == snapped on the hex (show); any non-zero == the user
|
||||
// has begun scrolling toward the reelhouse (hide). This vanishes them
|
||||
// the INSTANT the scroll starts and restores them only once it lands
|
||||
// fully back on the hex — user-spec timing 2026-06-03.
|
||||
var _aperture = document.getElementById('id_room_aperture');
|
||||
if (_aperture) {
|
||||
_aperture.addEventListener('scroll', function () {
|
||||
var portal = document.getElementById('id_sig_cursor_portal');
|
||||
// .cursors-hidden hides INSTANTLY (transition:none) at scroll
|
||||
// start; removing it on the return eases opacity 0→1 over 0.5s
|
||||
// via the portal's base transition.
|
||||
if (portal) portal.classList.toggle('cursors-hidden', _aperture.scrollTop > 0);
|
||||
}, { passive: true });
|
||||
}
|
||||
|
||||
cautionEl = stage.querySelector('.sig-info');
|
||||
cautionEffect = cautionEl.querySelector('.sig-info-effect');
|
||||
cautionTitle = cautionEl.querySelector('.sig-info-title');
|
||||
|
||||
@@ -1494,6 +1494,69 @@ class SigSelectRenderingTest(TestCase):
|
||||
self.assertContains(response, "fyi-next")
|
||||
|
||||
|
||||
class SigSelectUnifiedStageTest(TestCase):
|
||||
"""Sig Select stage unified with the my_sign card-stage apparatus:
|
||||
the shared DRY _stat_face.html stat-block (rank-chip + title + arcana,
|
||||
not just keywords), per-card face-image plumbing, and the green
|
||||
--duoUser felt that replaces the hex-pane content (my_sea-style) instead
|
||||
of the old fixed dark-Gaussian modal. Founder is PC (levity), mid-pick."""
|
||||
|
||||
def setUp(self):
|
||||
self.room, self.gamers, self.earthman, _ = _full_sig_setUp(self)
|
||||
self.url = reverse("epic:room", kwargs={"room_id": self.room.id})
|
||||
|
||||
# ── Workstream A — DRY stat-block ───────────────────────────────────────
|
||||
def test_stat_block_uses_dry_stat_face_partial(self):
|
||||
# The overlay must render the SHARED _stat_face.html (rank-chip +
|
||||
# title + arcana), not the old reduced label-only stat-face.
|
||||
content = self.client.get(self.url).content.decode()
|
||||
self.assertIn("stat-face-title", content)
|
||||
self.assertIn("stat-chip-rank", content)
|
||||
self.assertIn("stat-face-arcana", content)
|
||||
# Keyword <ul> IDs preserved so sig-select.js's selectors still resolve.
|
||||
self.assertIn('id="id_stat_keywords_upright"', content)
|
||||
self.assertIn('id="id_stat_keywords_reversed"', content)
|
||||
|
||||
# ── Workstream B — per-card face-image plumbing ─────────────────────────
|
||||
def test_sig_cards_carry_image_url_and_arcana_key(self):
|
||||
content = self.client.get(self.url).content.decode()
|
||||
self.assertIn("data-image-url=", content)
|
||||
self.assertIn("data-arcana-key=", content)
|
||||
|
||||
def test_stage_card_has_image_slot(self):
|
||||
content = self.client.get(self.url).content.decode()
|
||||
self.assertIn("sig-stage-card-img", content)
|
||||
|
||||
def test_image_deck_renders_nonempty_face_url(self):
|
||||
# Image-equipped seat deck → each sig card carries a real static path.
|
||||
self.earthman.has_card_images = True
|
||||
self.earthman.save(update_fields=["has_card_images"])
|
||||
content = self.client.get(self.url).content.decode()
|
||||
self.assertIn('data-image-url="/static', content)
|
||||
|
||||
def test_textonly_deck_renders_empty_face_url(self):
|
||||
# Glyph-only deck (Earthman as seeded) → empty data-image-url, glyph
|
||||
# fallback. The attribute still renders (plumbing present).
|
||||
self.earthman.has_card_images = False
|
||||
self.earthman.save(update_fields=["has_card_images"])
|
||||
content = self.client.get(self.url).content.decode()
|
||||
self.assertIn('data-image-url=""', content)
|
||||
|
||||
# ── Workstream C — felt replaces hex-pane content (my_sea-style) ────────
|
||||
def test_sig_stage_on_felt_in_hex_pane_no_dark_backdrop(self):
|
||||
content = self.client.get(self.url).content.decode()
|
||||
# Felt modifier on the hex pane; the old dark Gaussian backdrop is gone.
|
||||
self.assertIn("has-sig-stage", content)
|
||||
self.assertNotIn("sig-backdrop", content)
|
||||
# The overlay lives INSIDE the hex pane (before the scroll/views pane).
|
||||
hex_pos = content.find("room-hex-pane")
|
||||
overlay_pos = content.find("sig-overlay")
|
||||
scroll_pos = content.find("room-scroll-pane")
|
||||
self.assertNotEqual(overlay_pos, -1)
|
||||
self.assertLess(hex_pos, overlay_pos)
|
||||
self.assertLess(overlay_pos, scroll_pos)
|
||||
|
||||
|
||||
class SelectSigCardViewTest(TestCase):
|
||||
"""select_sig view — records choice, enforces turn order, rejects bad input."""
|
||||
|
||||
|
||||
@@ -609,33 +609,33 @@
|
||||
&--next { right: 1rem; }
|
||||
}
|
||||
|
||||
// ─── Sig Select overlay (SIG_SELECT phase) ────────────────────────────────────
|
||||
// ─── Sig Select stage (SIG_SELECT phase) ──────────────────────────────────────
|
||||
//
|
||||
// Two overlays (levity / gravity) run in parallel, one per polarity group.
|
||||
// Layout mirrors the gatekeeper: dark Gaussian backdrop + centred modal.
|
||||
// Inside the modal: upper stage (card preview) + lower mini card grid (no scroll).
|
||||
// Two stages (levity / gravity) run in parallel, one per polarity group.
|
||||
// Unified w. my_sign / my_sea 2026-06-03: renders INSIDE .room-hex-pane on
|
||||
// edge-to-edge green --duoUser felt (no dark Gaussian backdrop), replacing the
|
||||
// hex content my_sea-style. Inside the modal: upper stage (card preview) +
|
||||
// lower mini card grid (no scroll).
|
||||
|
||||
html:has(.sig-backdrop) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sig-backdrop {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.75);
|
||||
backdrop-filter: blur(5px);
|
||||
z-index: 100;
|
||||
pointer-events: none;
|
||||
// The hex pane becomes a positioning context only while the felt stage shows,
|
||||
// so the absolute-filling overlay scopes to the pane (not the viewport) and
|
||||
// the position-strip's root stacking stays untouched in every other phase.
|
||||
.room-hex-pane.has-sig-stage {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.sig-overlay {
|
||||
position: fixed;
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
justify-content: center;
|
||||
z-index: 120;
|
||||
pointer-events: none;
|
||||
z-index: 5;
|
||||
// Edge-to-edge non-Gaussian green felt — an opaque surface that covers the
|
||||
// hex/seats behind it; sig-select.js's _dismissSigOverlay removes the whole
|
||||
// overlay (this gamer's sigs done) to reveal the hex + waiting message.
|
||||
background: rgba(var(--duoUser), 1);
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.sig-modal {
|
||||
@@ -1077,6 +1077,15 @@ body.deck-family-english {
|
||||
@extend %flip-btn-revealed;
|
||||
}
|
||||
|
||||
// Room sig-select stage: same frozen-gated hover-reveal as my_sign, scoped to
|
||||
// .sig-overlay (the FLIP btn renders only for non-polarized image seat decks).
|
||||
// The FLIP appears once a card is OK-locked (.sig-stage--frozen), matching the
|
||||
// my_sign-main rule above.
|
||||
.sig-overlay .sig-stage--frozen .sig-stage-card:hover .my-sign-flip-btn,
|
||||
.sig-overlay .sig-stage--frozen .sig-stage-card:has(.my-sign-flip-btn:hover) .my-sign-flip-btn {
|
||||
@extend %flip-btn-revealed;
|
||||
}
|
||||
|
||||
// Unified mid-flip-hide across all 4 surfaces. `[data-flipping]="1"` is set on
|
||||
// the card by each surface's FLIP handler for the 500ms rotation duration;
|
||||
// `%flip-btn-mid-flip`'s `display: none` makes the btn vanish INSTANTLY (per
|
||||
@@ -1232,8 +1241,26 @@ body.deck-family-english {
|
||||
pointer-events: none;
|
||||
z-index: 200; // above sig-overlay (120), below tray (310)
|
||||
overflow: visible;
|
||||
opacity: 1;
|
||||
transition: opacity 0.25s ease; // eases the cursors back in on scroll-return
|
||||
}
|
||||
|
||||
// sig-select.js toggles this off the aperture scrollTop. `transition: none`
|
||||
// makes the hide at scroll-start INSTANT (user-spec); removing the class on the
|
||||
// return falls back to the base 0.5s opacity ease above — fade in, snap out.
|
||||
#id_sig_cursor_portal.cursors-hidden {
|
||||
opacity: 0;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
// The reserved-sig thumbs-up + hover hand-pointers portal to this body-root
|
||||
// fixed container (escaping the deck-grid clip), so when the table-hex aperture
|
||||
// scroll-snaps DOWN to the reelhouse they'd otherwise hang over that view at
|
||||
// their stale coords. sig-select.js toggles their visibility off an
|
||||
// IntersectionObserver on the scroll pane (threshold 0) — hidden the instant
|
||||
// the reelhouse begins to enter, restored only once it has fully left. (The
|
||||
// tray is intentionally NOT hidden — user wants to keep it.)
|
||||
|
||||
.sig-cursor-float {
|
||||
position: absolute;
|
||||
font-size: 1.5rem;
|
||||
@@ -1324,6 +1351,16 @@ body.deck-family-english {
|
||||
.fan-card-name-group{ color: rgba(var(--priUser), 1); }
|
||||
.fan-card-name { color: rgba(var(--quiUser), 1); }
|
||||
.fan-card-arcana { color: rgba(var(--priUser), 1); }
|
||||
// Image-mode parity w. the base (`.sig-stage-card--image` ~L795) + the
|
||||
// my-sea sea-sig-card override below: this 0,3,0 levity bg/border must
|
||||
// NOT re-clothe an image card — its transparent shell + contour-stroke
|
||||
// PNG has to show through (else a solid --secUser rect sits behind the
|
||||
// card). Was the missing escape that left the rect on RWS/Minchiate.
|
||||
&.sig-stage-card--image {
|
||||
background: transparent;
|
||||
border: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
}
|
||||
// Polarity title + qualifier text: --quiUser for levity (paired w. gravity's --terUser).
|
||||
// All five selectors prefixed w. .sig-stage-card to match (or beat) the 0,4,0 specificity
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
{% load i18n %}{% comment %}
|
||||
Sig Select overlay — dark Gaussian modal over the dormant table hex.
|
||||
Rendered for the current user's polarity group only.
|
||||
Sig Select stage — unified with the my_sign / my_sea card-stage apparatus
|
||||
(2026-06-03). Renders INSIDE .room-hex-pane on edge-to-edge green --duoUser
|
||||
felt (no dark Gaussian backdrop), replacing the hex content my_sea-style;
|
||||
sig-select.js bootstraps off `.sig-overlay`'s data-* payload. Rendered for
|
||||
the current user's polarity group only.
|
||||
Context: sig_cards, user_polarity, user_seat, sig_reserve_url, sig_reservations_json
|
||||
{% endcomment %}
|
||||
<div class="sig-backdrop"></div>
|
||||
<div class="sig-overlay"
|
||||
data-polarity="{{ user_polarity }}"
|
||||
data-user-role="{{ user_seat.role }}"
|
||||
@@ -18,6 +20,24 @@ Context: sig_cards, user_polarity, user_seat, sig_reserve_url, sig_reservations_
|
||||
<div class="sig-stage" id="id_sig_stage">
|
||||
|
||||
<div class="sig-stage-card" style="display:none">
|
||||
{# Image-mode slot — stage-card.js _setImageMode shows this <img> #}
|
||||
{# + adds .sig-stage-card--image when the focused card's #}
|
||||
{# data-image-url is non-empty (image-equipped seat deck per #}
|
||||
{# DeckVariant.has_card_images); else the text fan-card-* scaffold #}
|
||||
{# below takes over. Per-card src — works for mixed-deck piles #}
|
||||
{# once the dubbodeck assembly lands (each card keeps its deck). #}
|
||||
<img class="sig-stage-card-img" alt="" style="display:none">
|
||||
{# Non-polarized image decks (RWS / Minchiate): a FLIP .btn-reveal #}
|
||||
{# turns the preview to the deck's card-back (my_sign parity). The #}
|
||||
{# back-img defaults display:none via SCSS; .is-flipped-to-back #}
|
||||
{# (toggled by sig-select.js) reveals it. The shared #}
|
||||
{# .my-sign-flip-btn rules already anchor/hide/counter-position on #}
|
||||
{# any .sig-stage-card. Gated on the SEAT deck for now — per-card #}
|
||||
{# backs arrive with the dubbodeck assembly (mixed-deck piles). #}
|
||||
{% if user_seat.deck_variant.has_card_images and not user_seat.deck_variant.is_polarized %}
|
||||
<img class="sig-stage-card-back-img" alt="" src="{{ user_seat.deck_variant.back_image_url }}">
|
||||
<button class="btn btn-reveal my-sign-flip-btn sig-flip-btn" type="button">FLIP</button>
|
||||
{% endif %}
|
||||
<div class="fan-card-corner fan-card-corner--tl">
|
||||
<span class="fan-corner-rank"></span>
|
||||
<i class="fa-solid stage-suit-icon" style="display:none"></i>
|
||||
@@ -48,14 +68,13 @@ Context: sig_cards, user_polarity, user_seat, sig_reserve_url, sig_reservations_
|
||||
<div class="sig-stat-block">
|
||||
<button class="btn btn-reverse spin-btn" type="button">SPIN</button>
|
||||
<button class="btn btn-info fyi-btn" type="button">FYI</button>
|
||||
<div class="stat-face stat-face--upright">
|
||||
<p class="stat-face-label">Emanation</p>
|
||||
<ul class="stat-keywords" id="id_stat_keywords_upright"></ul>
|
||||
</div>
|
||||
<div class="stat-face stat-face--reversed">
|
||||
<p class="stat-face-label">Reversal</p>
|
||||
<ul class="stat-keywords" id="id_stat_keywords_reversed"></ul>
|
||||
</div>
|
||||
{# DRY stat-face (rank-chip + title + arcana + keywords) — the #}
|
||||
{# same shared partial my_sign / sea_stage / fan use. No `card` #}
|
||||
{# arg → JS-populated by sig-select.js (populateStatExtras + #}
|
||||
{# populateKeywords). keywords_ul_id keeps the <ul> ids sig- #}
|
||||
{# select.js's #id_stat_keywords_* selectors target. #}
|
||||
{% include "core/_partials/_stat_face.html" with face_modifier="upright" label_text="Emanation" keywords_ul_id="id_stat_keywords_upright" %}
|
||||
{% include "core/_partials/_stat_face.html" with face_modifier="reversed" label_text="Reversal" keywords_ul_id="id_stat_keywords_reversed" %}
|
||||
{% include "apps/gameboard/_partials/_sig_fyi_panel.html" with panel_id="id_sig_tooltip" %}
|
||||
</div>
|
||||
</div>
|
||||
@@ -69,6 +88,8 @@ Context: sig_cards, user_polarity, user_seat, sig_reserve_url, sig_reservations_
|
||||
data-name-group="{{ card.name_group }}"
|
||||
data-name-title="{{ card.name_title }}"
|
||||
data-arcana="{{ card.get_arcana_display }}"
|
||||
data-arcana-key="{{ card.arcana }}"
|
||||
data-image-url="{{ card.image_url }}"
|
||||
data-correspondence="{{ card.correspondence|default:'' }}"
|
||||
data-keywords-upright="{{ card.keywords_upright|join:',' }}"
|
||||
data-keywords-reversed="{{ card.keywords_reversed|join:',' }}"
|
||||
@@ -83,6 +104,9 @@ Context: sig_cards, user_polarity, user_seat, sig_reserve_url, sig_reservations_
|
||||
data-levity-reversal="{{ card.levity_reversal }}"
|
||||
data-gravity-reversal="{{ card.gravity_reversal }}"
|
||||
data-italic-word="{{ card.italic_word }}">
|
||||
{# Thumbnails stay glyph-only (rank + suit symbol) at every deck #}
|
||||
{# — `data-image-url` above feeds the STAGE preview's image only #}
|
||||
{# (stage-card.js _setImageMode), never the thumbnail face. #}
|
||||
<div class="fan-card-corner fan-card-corner--tl">
|
||||
<span class="fan-corner-rank">{{ card.corner_rank }}</span>
|
||||
{% if card.suit_icon %}<i class="fa-solid {{ card.suit_icon }}"></i>{% endif %}
|
||||
|
||||
@@ -31,7 +31,11 @@
|
||||
{# the hex content is replaced entirely by the Scroll (no partial scroll #}
|
||||
{# — `scroll-snap-stop: always`). DRY seam: my_sea reuses _room_scroll. #}
|
||||
<div id="id_room_aperture" class="room-aperture{% if room.table_status %} is-scrollable{% endif %}">
|
||||
<div class="room-pane room-hex-pane">
|
||||
{# `has-sig-stage` (active sig pick) makes the pane a positioning context #}
|
||||
{# so the green-felt _sig_select_overlay fills it (my_sea-style), covering #}
|
||||
{# the hex/seats behind. Dismissing the overlay (this gamer's sigs done) #}
|
||||
{# reveals the hex + waiting message underneath. #}
|
||||
<div class="room-pane room-hex-pane{% if room.table_status == "SIG_SELECT" and user_polarity and not polarity_done and viewer_cost_current %} has-sig-stage{% endif %}">
|
||||
<div class="room-shell">
|
||||
<div id="id_game_table" class="room-table">
|
||||
{# SCAN SIGS advances the whole table past role-select — gated on #}
|
||||
@@ -109,6 +113,13 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>{# /.room-shell #}
|
||||
{# Sig Select stage — green-felt card stage + thumbnail grid, rendered #}
|
||||
{# INSIDE the hex pane (absolute-fills it on --duoUser felt, my_sea- #}
|
||||
{# style) for this gamer's polarity group. Suppressed once their polarity #}
|
||||
{# sigs are assigned (then the hex/waiting-msg shows through). #}
|
||||
{% if room.table_status == "SIG_SELECT" and user_polarity and not polarity_done and viewer_cost_current %}
|
||||
{% include "apps/gameboard/_partials/_sig_select_overlay.html" %}
|
||||
{% endif %}
|
||||
{# Position circles scroll away WITH the hex (they live inside the hex #}
|
||||
{# pane, not at room-page root). Neither the aperture nor the pane sets #}
|
||||
{# z-index/transform, so the strip's z-130 still resolves in the root #}
|
||||
@@ -134,12 +145,9 @@
|
||||
{% endif %}
|
||||
|
||||
{# Phase overlays are gated on `viewer_cost_current` too: a lapsed gamer #}
|
||||
{# gets GATE VIEW in the center, so the SIG/SKY/SEA modals (which embed #}
|
||||
{# their trigger-btn ids in JS) must not render alongside it. #}
|
||||
{# Sig Select overlay — suppressed once this gamer's polarity sigs are assigned #}
|
||||
{% if room.table_status == "SIG_SELECT" and user_polarity and not polarity_done and viewer_cost_current %}
|
||||
{% include "apps/gameboard/_partials/_sig_select_overlay.html" %}
|
||||
{% endif %}
|
||||
{# gets GATE VIEW in the center, so the SKY/SEA modals (which embed #}
|
||||
{# their trigger-btn ids in JS) must not render alongside it. (The Sig #}
|
||||
{# Select stage now lives INSIDE the hex pane above — my_sea-style felt.) #}
|
||||
|
||||
{# Sky (Pick Sky) overlay — natal chart entry #}
|
||||
{% if room.table_status == "SKY_SELECT" and not sky_confirmed and viewer_cost_current %}
|
||||
|
||||
Reference in New Issue
Block a user