From 3410f073f067cf55bbc9372339ad95688e9b77cd Mon Sep 17 00:00:00 2001 From: Disco DeDisco Date: Fri, 1 May 2026 02:06:55 -0400 Subject: [PATCH] =?UTF-8?q?fan-card=20title=20symmetry;=20pips=20=E2=86=92?= =?UTF-8?q?=20Minor;=20tray=20Sig=20card?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - title slot:

; font-size 0.1 → 0.087 (deck) / 0.093 → 0.08 (sig/sea); text-wrap: balance — kills upright/reversal asymmetry & all per-card squeeze hacks - trump 8 hyphen → U+2011, trump 9 space → U+00A0 (mig 0021) so titles wrap as intended - pips (Earthman 1–10) → MINOR arcana (mig 0022); StageCard._arcanaDisplay() picks the right label - PICK SEA: re-clicking a deposited slot now restores the server-rolled reversed state (sea.js _populate toggle) - tray Sig card: render same .sig-stage-card.sea-sig-card (rank + icon, -5deg) as Sea center; --sig-card-w sized off --tray-cell-size - title_squeeze_class kept as no-op for template compat - 0020 (Self-Unimportance rename) included from prior turn Code architected by Disco DeDisco Git commit message Co-Authored-By: Claude Opus 4.7 (1M context) --- .../epic/migrations/0020_self_unimportance.py | 41 +++++++++++++ src/apps/epic/migrations/0021_trump9_nbsp.py | 61 +++++++++++++++++++ .../migrations/0022_pips_to_minor_arcana.py | 42 +++++++++++++ src/apps/epic/models.py | 12 +++- src/apps/epic/static/apps/epic/sea.js | 16 ++--- src/apps/epic/static/apps/epic/stage-card.js | 11 +++- .../static/apps/gameboard/gameboard.js | 30 ++++++--- src/static_src/scss/_card-deck.scss | 32 +++++++--- src/static_src/scss/_tray.scss | 18 +++--- .../gameboard/_partials/_sea_overlay.html | 4 +- .../_partials/_sig_select_overlay.html | 2 +- .../apps/gameboard/_partials/_tarot_fan.html | 10 +-- src/templates/apps/gameboard/room.html | 2 +- 13 files changed, 233 insertions(+), 48 deletions(-) create mode 100644 src/apps/epic/migrations/0020_self_unimportance.py create mode 100644 src/apps/epic/migrations/0021_trump9_nbsp.py create mode 100644 src/apps/epic/migrations/0022_pips_to_minor_arcana.py diff --git a/src/apps/epic/migrations/0020_self_unimportance.py b/src/apps/epic/migrations/0020_self_unimportance.py new file mode 100644 index 0000000..1e7b7fc --- /dev/null +++ b/src/apps/epic/migrations/0020_self_unimportance.py @@ -0,0 +1,41 @@ +"""Trump 8 rename: Losing Self-Importance → Self-Unimportance. + +The renamed form fits on one fan-card line above the Sublimating/Sedimentary +qualifier without a scaleX squeeze. +""" +from django.db import migrations + + +def forward(apps, schema_editor): + TarotCard = apps.get_model("epic", "TarotCard") + DeckVariant = apps.get_model("epic", "DeckVariant") + try: + earthman = DeckVariant.objects.get(slug="earthman") + except DeckVariant.DoesNotExist: + return + TarotCard.objects.filter( + deck_variant=earthman, arcana="MAJOR", number=8, + ).update(name="Self-Unimportance", slug="self-unimportance") + + +def reverse(apps, schema_editor): + TarotCard = apps.get_model("epic", "TarotCard") + DeckVariant = apps.get_model("epic", "DeckVariant") + try: + earthman = DeckVariant.objects.get(slug="earthman") + except DeckVariant.DoesNotExist: + return + TarotCard.objects.filter( + deck_variant=earthman, arcana="MAJOR", number=8, + ).update(name="Losing Self-Importance", slug="losing-self-importance") + + +class Migration(migrations.Migration): + + dependencies = [ + ("epic", "0019_explicit_virtues_italic_word"), + ] + + operations = [ + migrations.RunPython(forward, reverse_code=reverse), + ] diff --git a/src/apps/epic/migrations/0021_trump9_nbsp.py b/src/apps/epic/migrations/0021_trump9_nbsp.py new file mode 100644 index 0000000..14cec28 --- /dev/null +++ b/src/apps/epic/migrations/0021_trump9_nbsp.py @@ -0,0 +1,61 @@ +"""Long-title wrap fixes for trumps 8 and 9. + + Trump 8 "Self-Unimportance" → swap the hyphen for U+2011 (non-breaking + hyphen) so it stays glued and the title sits on one line above + Sublimating / Sedimentary. + + Trump 9 "Erasing Personal History" → insert U+00A0 (non-breaking space) + between "Personal" and "History" so the browser keeps them together, + forcing "Erasing" alone on line 1 and "Personal History," on line 2. +""" +from django.db import migrations + + +# Trump 8 +OLD_8 = "Self-Unimportance" +NEW_8 = "Self‑Unimportance" + +# Trump 9 +OLD_9 = "Erasing Personal History" +NEW_9 = "Erasing Personal History" + + +def forward(apps, schema_editor): + TarotCard = apps.get_model("epic", "TarotCard") + DeckVariant = apps.get_model("epic", "DeckVariant") + try: + earthman = DeckVariant.objects.get(slug="earthman") + except DeckVariant.DoesNotExist: + return + TarotCard.objects.filter( + deck_variant=earthman, arcana="MAJOR", number=8, + ).update(name=NEW_8) + TarotCard.objects.filter( + deck_variant=earthman, arcana="MAJOR", number=9, + ).update(name=NEW_9) + + +def reverse(apps, schema_editor): + TarotCard = apps.get_model("epic", "TarotCard") + DeckVariant = apps.get_model("epic", "DeckVariant") + try: + earthman = DeckVariant.objects.get(slug="earthman") + except DeckVariant.DoesNotExist: + return + TarotCard.objects.filter( + deck_variant=earthman, arcana="MAJOR", number=8, + ).update(name=OLD_8) + TarotCard.objects.filter( + deck_variant=earthman, arcana="MAJOR", number=9, + ).update(name=OLD_9) + + +class Migration(migrations.Migration): + + dependencies = [ + ("epic", "0020_self_unimportance"), + ] + + operations = [ + migrations.RunPython(forward, reverse_code=reverse), + ] diff --git a/src/apps/epic/migrations/0022_pips_to_minor_arcana.py b/src/apps/epic/migrations/0022_pips_to_minor_arcana.py new file mode 100644 index 0000000..fc2fe61 --- /dev/null +++ b/src/apps/epic/migrations/0022_pips_to_minor_arcana.py @@ -0,0 +1,42 @@ +"""Reclassify Earthman pip cards (number 1-10) from MIDDLE to MINOR arcana. + +The 0004 reseed initially lumped pips + court cards under MIDDLE; pips +should be MINOR arcana, with MIDDLE reserved for the Earthman court +cards (Maid/Jack/Queen/King at numbers 11-14). +""" +from django.db import migrations + + +def forward(apps, schema_editor): + TarotCard = apps.get_model("epic", "TarotCard") + DeckVariant = apps.get_model("epic", "DeckVariant") + try: + earthman = DeckVariant.objects.get(slug="earthman") + except DeckVariant.DoesNotExist: + return + TarotCard.objects.filter( + deck_variant=earthman, arcana="MIDDLE", number__lte=10, + ).update(arcana="MINOR") + + +def reverse(apps, schema_editor): + TarotCard = apps.get_model("epic", "TarotCard") + DeckVariant = apps.get_model("epic", "DeckVariant") + try: + earthman = DeckVariant.objects.get(slug="earthman") + except DeckVariant.DoesNotExist: + return + TarotCard.objects.filter( + deck_variant=earthman, arcana="MINOR", number__lte=10, + ).update(arcana="MIDDLE") + + +class Migration(migrations.Migration): + + dependencies = [ + ("epic", "0021_trump9_nbsp"), + ] + + operations = [ + migrations.RunPython(forward, reverse_code=reverse), + ] diff --git a/src/apps/epic/models.py b/src/apps/epic/models.py index ab789c5..5537f69 100644 --- a/src/apps/epic/models.py +++ b/src/apps/epic/models.py @@ -211,8 +211,8 @@ class DeckVariant(models.Model): class TarotCard(models.Model): MAJOR = "MAJOR" - MINOR = "MINOR" - MIDDLE = "MIDDLE" # Earthman court cards (M/J/Q/K) + MINOR = "MINOR" # pip cards (numbers 1-10) + MIDDLE = "MIDDLE" # Earthman court cards (M/J/Q/K, numbers 11-14) ARCANA_CHOICES = [ (MAJOR, "Major Arcana"), (MINOR, "Minor Arcana"), @@ -323,6 +323,14 @@ class TarotCard(models.Model): return self.name.split(': ', 1)[1] return self.name + @property + def title_squeeze_class(self): + """No-op kept for template compatibility. Title fit is now handled by + a smaller base `font-size` on `.fan-card-name`/`.fan-card-reversal-*` + plus `text-wrap: balance` (see `_card-deck.scss`) — every long-title + card fits naturally without per-card CSS hacks.""" + return '' + @property def suit_icon(self): if self.icon: diff --git a/src/apps/epic/static/apps/epic/sea.js b/src/apps/epic/static/apps/epic/sea.js index 9f00a0a..4921375 100644 --- a/src/apps/epic/static/apps/epic/sea.js +++ b/src/apps/epic/static/apps/epic/sea.js @@ -25,9 +25,12 @@ var SeaDeal = (function () { _infoData = StageCard.buildInfoData(card); _infoIdx = 0; - // Reset SPIN - stageCard.classList.remove('stage-card--reversed'); - statBlock.classList.remove('is-reversed'); + // Sync SPIN state to the card's reversal axis — `card.reversed` is set + // server-side at deck-fetch time (apps.epic.utils.stack_reversal_probability) + // and persisted in `_seaHand`, so re-clicking a deposited slot must + // restore that state, not reset to upright. + stageCard.classList.toggle('stage-card--reversed', !!card.reversed); + statBlock.classList.toggle('is-reversed', !!card.reversed); _closeInfo(); } @@ -105,13 +108,6 @@ var SeaDeal = (function () { _viewingPos = posSelector; _seaHand[posSelector] = { card: card, isLevity: isLevity }; _populate(card, isLevity); - // Server pre-rolled the reversal axis at deck-fetch time - // (apps.epic.utils.stack_reversal_probability). Honor it here so the - // card lands face-reversed if rolled. - if (card.reversed) { - statBlock.classList.add('is-reversed'); - stageCard.classList.add('stage-card--reversed'); - } _fillSlot(posSelector, card, isLevity); _showStage(isLevity); } diff --git a/src/apps/epic/static/apps/epic/stage-card.js b/src/apps/epic/static/apps/epic/stage-card.js index b113737..a3b5ca8 100644 --- a/src/apps/epic/static/apps/epic/stage-card.js +++ b/src/apps/epic/static/apps/epic/stage-card.js @@ -84,6 +84,15 @@ var StageCard = (function () { return a === 'MAJOR' || a === 'MAJOR ARCANA'; } + // Map either form (model code or display) to the rendered label. + function _arcanaDisplay(card) { + var a = (card.arcana || '').toUpperCase(); + if (a === 'MAJOR' || a === 'MAJOR ARCANA') return 'Major Arcana'; + if (a === 'MINOR' || a === 'MINOR ARCANA') return 'Minor Arcana'; + if (a === 'MIDDLE' || a === 'MIDDLE ARCANA') return 'Middle Arcana'; + return ''; + } + // Paint the stage-card's upright + reversal faces from a normalized card // object + the active polarity ('levity' | 'gravity'). Reversal-qualifier // falls back to the current polarity's qualifier when blank (6F behavior). @@ -117,7 +126,7 @@ var StageCard = (function () { if (nameGroupEl) nameGroupEl.textContent = emanationOverride ? '' : (card.name_group || ''); var arcanaEl = stageCard.querySelector('.fan-card-arcana'); - if (arcanaEl) arcanaEl.textContent = isMajor ? 'Major Arcana' : 'Middle Arcana'; + if (arcanaEl) arcanaEl.textContent = _arcanaDisplay(card); var nameEl = stageCard.querySelector('.fan-card-name'); var qAbove = stageCard.querySelector('.sig-qualifier-above'); diff --git a/src/apps/gameboard/static/apps/gameboard/gameboard.js b/src/apps/gameboard/static/apps/gameboard/gameboard.js index 135513c..57d7a84 100644 --- a/src/apps/gameboard/static/apps/gameboard/gameboard.js +++ b/src/apps/gameboard/static/apps/gameboard/gameboard.js @@ -33,14 +33,14 @@ function initGameKitTooltips() { if (portal.classList.contains('active') && activeToken) { const tokenRect = activeToken.getBoundingClientRect(); const portalRect = portal.getBoundingClientRect(); - // Expand left to cover button overflow outside portal edge - const expandedPortalRect = { - left: portalRect.left - 24, - top: portalRect.top, - right: portalRect.right, - bottom: portalRect.bottom, - }; - const rects = [tokenRect, expandedPortalRect]; + const rects = [tokenRect, portalRect]; + // Include the DON/DOFF button group's actual bounding rect so the + // portions of those buttons that hang past the portal's left edge + // (and above its top edge) stay inside the hover-tolerance region. + // Was previously a hardcoded 24px left expansion which didn't + // cover top overhang and underestimated wider button labels. + const equipBtns = portal.querySelector('.tt-equip-btns'); + if (equipBtns) rects.push(equipBtns.getBoundingClientRect()); if (miniPortal.classList.contains('active')) rects.push(miniPortal.getBoundingClientRect()); const left = Math.min(...rects.map(r => r.left)); const top = Math.min(...rects.map(r => r.top)); @@ -244,7 +244,19 @@ function initGameKitTooltips() { const tokenRect = token.getBoundingClientRect(); const halfW = portal.offsetWidth / 2; const rawLeft = tokenRect.left + tokenRect.width / 2; - const clampedLeft = Math.max(halfW + 8, Math.min(rawLeft, window.innerWidth - halfW - 8)); + // Extra left clearance — the DON/DOFF button group is absolute- + // positioned with `left: -1rem` inside the portal and spills further + // left by its own width. Measure the actual overhang so the clamp + // keeps the buttons inside the viewport rather than just the portal. + let leftOverhang = 0; + const equipBtns = portal.querySelector('.tt-equip-btns'); + if (equipBtns) { + const portalRect = portal.getBoundingClientRect(); + const btnsRect = equipBtns.getBoundingClientRect(); + leftOverhang = Math.max(0, portalRect.left - btnsRect.left); + } + const minLeft = halfW + 8 + leftOverhang; + const clampedLeft = Math.max(minLeft, Math.min(rawLeft, window.innerWidth - halfW - 8)); portal.style.left = Math.round(clampedLeft) + 'px'; // Show above when token is in lower viewport half; below when in upper half diff --git a/src/static_src/scss/_card-deck.scss b/src/static_src/scss/_card-deck.scss index 7f84935..a999079 100644 --- a/src/static_src/scss/_card-deck.scss +++ b/src/static_src/scss/_card-deck.scss @@ -350,21 +350,34 @@ display: flex; flex-direction: column; align-items: center; + justify-content: center; gap: calc(var(--fan-card-w) * 0.007); + // Ghost-line: reserve at least two title-line-heights of vertical space + // on each face so emanation + reversal stay symmetric even when one + // side has a single-line title (e.g. trumps 6–9 reversal "Indulged + // Folly" vs upright "Losing Self-Importance, / Sublimating"). + min-height: calc(var(--fan-card-w) * 0.21); } // Qualifier shares the name's typography — same line, different content. // Sizes scale with --fan-card-w so they stay proportional on mobile. + // `text-wrap: balance` distributes lines evenly so a borderline-long title + // breaks at the natural midpoint instead of greedy first-fit (e.g. trump + // 9 wraps as "Erasing / Personal History," instead of "Erasing Personal / + // History,"). Base size lowered from 0.1 → 0.087 (~13%) so all the long + // titles (trumps 8/9/18/36/41 + Queen of Crowns) fit without per-card + // hacks and without asymmetry between upright (h3) and reversal (p). .sig-qualifier-above, .sig-qualifier-below, .fan-card-reversal-qualifier, .fan-card-reversal-name, .fan-card-name { - font-size: calc(var(--fan-card-w) * 0.1); + font-size: calc(var(--fan-card-w) * 0.087); font-weight: bold; margin: 0; color: rgba(var(--terUser), 1); transition: opacity 0.2s; + text-wrap: balance; } // Reversal-face spans pre-rotated so they read forward once the card spins @@ -547,12 +560,14 @@ html:has(.sig-backdrop) { .fan-card-face-upright { display: flex; flex-direction: column; align-items: center; gap: 0.15rem; } .fan-card-face-reversal { display: flex; flex-direction: column; align-items: center; gap: 0.15rem; padding-top: 0.1rem; } .fan-card-name-group { font-size: calc(var(--sig-card-w, 120px) * 0.073); opacity: 0.6; } - // Upright qualifier + name share sizing/weight/color with their reversed counterparts + // Upright qualifier + name share sizing/weight/color with their reversed counterparts. + // text-wrap: balance distributes lines evenly so longer titles wrap symmetrically; + // base size 0.08 (was 0.093) gives long titles room to fit without per-card hacks. .sig-qualifier-above, .sig-qualifier-below, - .fan-card-reversal-qualifier { font-size: calc(var(--sig-card-w, 120px) * 0.093); font-weight: 600; color: rgba(var(--quiUser), 1); transition: opacity 0.2s; } + .fan-card-reversal-qualifier { font-size: calc(var(--sig-card-w, 120px) * 0.08); font-weight: 600; color: rgba(var(--quiUser), 1); transition: opacity 0.2s; text-wrap: balance; } .fan-card-name, - .fan-card-reversal-name { font-size: calc(var(--sig-card-w, 120px) * 0.093); font-weight: 600; color: rgba(var(--quiUser), 1); transition: opacity 0.2s; } + .fan-card-reversal-name { font-size: calc(var(--sig-card-w, 120px) * 0.08); font-weight: 600; color: rgba(var(--quiUser), 1); transition: opacity 0.2s; text-wrap: balance; } .fan-card-arcana { font-size: calc(var(--sig-card-w, 120px) * 0.067); text-transform: uppercase; letter-spacing: 0.06em; opacity: 0.5; } .fan-card-correspondence{ display: none; } // Minchiate equivalence shown in game-kit only // Reversed face elements — pre-rotated so they read forward after card spins @@ -1148,8 +1163,9 @@ $sea-card-h: 6.5rem; } // .sig-stage-card is normally scoped inside .sig-stage — re-apply the card shell -// here so it renders correctly outside that context. -.sea-cross .sig-stage-card { +// here so it renders correctly outside that context. Class-based selector so it +// also applies in the tray (.tray-sig-card .sig-stage-card.sea-sig-card). +.sig-stage-card.sea-sig-card { flex-shrink: 0; width: var(--sig-card-w, #{$sea-card-w}); height: auto; @@ -1498,9 +1514,9 @@ $_glow-gravity: 0 0 0.8rem 0.15rem rgba(var(--quaUser), 0.6); .fan-card-name-group { font-size: calc(var(--sig-card-w, 140px) * 0.073); opacity: 0.6; } .sig-qualifier-above, .sig-qualifier-below, - .fan-card-reversal-qualifier { font-size: calc(var(--sig-card-w, 140px) * 0.093); font-weight: 600; color: rgba(var(--quiUser), 1); transition: opacity 0.2s; } + .fan-card-reversal-qualifier { font-size: calc(var(--sig-card-w, 140px) * 0.08); font-weight: 600; color: rgba(var(--quiUser), 1); transition: opacity 0.2s; text-wrap: balance; } .fan-card-name, - .fan-card-reversal-name { font-size: calc(var(--sig-card-w, 140px) * 0.093); font-weight: 600; color: rgba(var(--quiUser), 1); transition: opacity 0.2s; } + .fan-card-reversal-name { font-size: calc(var(--sig-card-w, 140px) * 0.08); font-weight: 600; color: rgba(var(--quiUser), 1); transition: opacity 0.2s; text-wrap: balance; } .fan-card-arcana { font-size: calc(var(--sig-card-w, 140px) * 0.067); text-transform: uppercase; letter-spacing: 0.06em; opacity: 0.5; } .fan-card-reversal-qualifier, .fan-card-reversal-name { transform: rotate(180deg); opacity: 0.25; } diff --git a/src/static_src/scss/_tray.scss b/src/static_src/scss/_tray.scss index 7bc640a..30faabc 100644 --- a/src/static_src/scss/_tray.scss +++ b/src/static_src/scss/_tray.scss @@ -147,18 +147,18 @@ $handle-r: 1rem; } } +// Hosts the same compact rank-+-icon Sig card used in the Sea Select center +// (.sig-stage-card.sea-sig-card). Width is sized so the 5:8-aspect card +// height ≈ tray cell height. .tray-sig-card { - padding: 0; - overflow: hidden; + padding: 0; background: transparent; + display: flex; + align-items: center; + justify-content: center; - img { - display: block; - width: 100%; - height: 100%; - object-fit: cover; - object-position: center; - transform: scale(1.4); // crop SVG's internal margins + .sig-stage-card.sea-sig-card { + --sig-card-w: calc(var(--tray-cell-size, 48px) * 5 / 8); } } diff --git a/src/templates/apps/gameboard/_partials/_sea_overlay.html b/src/templates/apps/gameboard/_partials/_sea_overlay.html index 553e32d..4e53c55 100644 --- a/src/templates/apps/gameboard/_partials/_sea_overlay.html +++ b/src/templates/apps/gameboard/_partials/_sea_overlay.html @@ -13,7 +13,7 @@

PICK SEA

-

Draw +6 cards to describe your character's influences and seed the game-map.

+

Draw +6 cards to describe your character's influences and seed the map.

@@ -151,7 +151,7 @@

-

+

diff --git a/src/templates/apps/gameboard/_partials/_sig_select_overlay.html b/src/templates/apps/gameboard/_partials/_sig_select_overlay.html index 6c97915..ed9b260 100644 --- a/src/templates/apps/gameboard/_partials/_sig_select_overlay.html +++ b/src/templates/apps/gameboard/_partials/_sig_select_overlay.html @@ -26,7 +26,7 @@ Context: sig_cards, user_polarity, user_seat, sig_reserve_url, sig_reservations_

-

+

diff --git a/src/templates/apps/gameboard/_partials/_tarot_fan.html b/src/templates/apps/gameboard/_partials/_tarot_fan.html index a50969e..be681ad 100644 --- a/src/templates/apps/gameboard/_partials/_tarot_fan.html +++ b/src/templates/apps/gameboard/_partials/_tarot_fan.html @@ -28,13 +28,13 @@
{% if card.levity_emanation %} {# Polarity-split title (cards 48-49 + trumps 19-21); no qualifier slots — qualifier is baked into the title between "The" and the proper noun #} -

{{ card.levity_emanation|italicize:card.italic_word }}

+

{{ card.levity_emanation|italicize:card.italic_word }}

{% else %} {% if card.name_group %}

{{ card.name_group }}

{% endif %} {% if card.arcana != "MAJOR" and card.levity_qualifier %}

{{ card.levity_qualifier }}

{% endif %} -

{{ card.name_title|italicize:card.italic_word }}{% if card.arcana == "MAJOR" and card.levity_qualifier %},{% endif %}

+

{{ card.name_title|italicize:card.italic_word }}{% if card.arcana == "MAJOR" and card.levity_qualifier %},{% endif %}

{% if card.arcana == "MAJOR" and card.levity_qualifier %}

{{ card.levity_qualifier }}

{% endif %} @@ -49,12 +49,12 @@ {% if card.levity_reversal %} {# Polarity-split reversal title — single line, qualifier slot empty. Title goes in the qualifier slot so it visually lands on top after spin. #}

-

{{ card.levity_reversal|italicize:card.italic_word }}

+

{{ card.levity_reversal|italicize:card.italic_word }}

{% elif card.arcana == "MAJOR" %}

{{ card.levity_qualifier|default:card.gravity_qualifier }}

-

{{ card.name_title|italicize:card.italic_word }}{% if card.levity_qualifier %},{% endif %}

+

{{ card.name_title|italicize:card.italic_word }}{% if card.levity_qualifier %},{% endif %}

{% else %} -

{{ card.name_title|italicize:card.italic_word }}

+

{{ card.name_title|italicize:card.italic_word }}

{{ card.reversal_qualifier|default:card.gravity_qualifier }}

{% endif %}
diff --git a/src/templates/apps/gameboard/room.html b/src/templates/apps/gameboard/room.html index 6b2d186..27ef08a 100644 --- a/src/templates/apps/gameboard/room.html +++ b/src/templates/apps/gameboard/room.html @@ -101,7 +101,7 @@
- + {% endif %} {% include "apps/gameboard/_partials/_room_gear.html" %}