fan-card title symmetry; pips → Minor; tray Sig card
- title slot: <h3> → <p>; 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 <discodedisco@outlook.com> Git commit message Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
41
src/apps/epic/migrations/0020_self_unimportance.py
Normal file
41
src/apps/epic/migrations/0020_self_unimportance.py
Normal file
@@ -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),
|
||||||
|
]
|
||||||
61
src/apps/epic/migrations/0021_trump9_nbsp.py
Normal file
61
src/apps/epic/migrations/0021_trump9_nbsp.py
Normal file
@@ -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),
|
||||||
|
]
|
||||||
42
src/apps/epic/migrations/0022_pips_to_minor_arcana.py
Normal file
42
src/apps/epic/migrations/0022_pips_to_minor_arcana.py
Normal file
@@ -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),
|
||||||
|
]
|
||||||
@@ -211,8 +211,8 @@ class DeckVariant(models.Model):
|
|||||||
|
|
||||||
class TarotCard(models.Model):
|
class TarotCard(models.Model):
|
||||||
MAJOR = "MAJOR"
|
MAJOR = "MAJOR"
|
||||||
MINOR = "MINOR"
|
MINOR = "MINOR" # pip cards (numbers 1-10)
|
||||||
MIDDLE = "MIDDLE" # Earthman court cards (M/J/Q/K)
|
MIDDLE = "MIDDLE" # Earthman court cards (M/J/Q/K, numbers 11-14)
|
||||||
ARCANA_CHOICES = [
|
ARCANA_CHOICES = [
|
||||||
(MAJOR, "Major Arcana"),
|
(MAJOR, "Major Arcana"),
|
||||||
(MINOR, "Minor Arcana"),
|
(MINOR, "Minor Arcana"),
|
||||||
@@ -323,6 +323,14 @@ class TarotCard(models.Model):
|
|||||||
return self.name.split(': ', 1)[1]
|
return self.name.split(': ', 1)[1]
|
||||||
return self.name
|
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
|
@property
|
||||||
def suit_icon(self):
|
def suit_icon(self):
|
||||||
if self.icon:
|
if self.icon:
|
||||||
|
|||||||
@@ -25,9 +25,12 @@ var SeaDeal = (function () {
|
|||||||
_infoData = StageCard.buildInfoData(card);
|
_infoData = StageCard.buildInfoData(card);
|
||||||
_infoIdx = 0;
|
_infoIdx = 0;
|
||||||
|
|
||||||
// Reset SPIN
|
// Sync SPIN state to the card's reversal axis — `card.reversed` is set
|
||||||
stageCard.classList.remove('stage-card--reversed');
|
// server-side at deck-fetch time (apps.epic.utils.stack_reversal_probability)
|
||||||
statBlock.classList.remove('is-reversed');
|
// 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();
|
_closeInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,13 +108,6 @@ var SeaDeal = (function () {
|
|||||||
_viewingPos = posSelector;
|
_viewingPos = posSelector;
|
||||||
_seaHand[posSelector] = { card: card, isLevity: isLevity };
|
_seaHand[posSelector] = { card: card, isLevity: isLevity };
|
||||||
_populate(card, 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);
|
_fillSlot(posSelector, card, isLevity);
|
||||||
_showStage(isLevity);
|
_showStage(isLevity);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,6 +84,15 @@ var StageCard = (function () {
|
|||||||
return a === 'MAJOR' || a === 'MAJOR ARCANA';
|
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
|
// Paint the stage-card's upright + reversal faces from a normalized card
|
||||||
// object + the active polarity ('levity' | 'gravity'). Reversal-qualifier
|
// object + the active polarity ('levity' | 'gravity'). Reversal-qualifier
|
||||||
// falls back to the current polarity's qualifier when blank (6F behavior).
|
// 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 || '');
|
if (nameGroupEl) nameGroupEl.textContent = emanationOverride ? '' : (card.name_group || '');
|
||||||
|
|
||||||
var arcanaEl = stageCard.querySelector('.fan-card-arcana');
|
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 nameEl = stageCard.querySelector('.fan-card-name');
|
||||||
var qAbove = stageCard.querySelector('.sig-qualifier-above');
|
var qAbove = stageCard.querySelector('.sig-qualifier-above');
|
||||||
|
|||||||
@@ -33,14 +33,14 @@ function initGameKitTooltips() {
|
|||||||
if (portal.classList.contains('active') && activeToken) {
|
if (portal.classList.contains('active') && activeToken) {
|
||||||
const tokenRect = activeToken.getBoundingClientRect();
|
const tokenRect = activeToken.getBoundingClientRect();
|
||||||
const portalRect = portal.getBoundingClientRect();
|
const portalRect = portal.getBoundingClientRect();
|
||||||
// Expand left to cover button overflow outside portal edge
|
const rects = [tokenRect, portalRect];
|
||||||
const expandedPortalRect = {
|
// Include the DON/DOFF button group's actual bounding rect so the
|
||||||
left: portalRect.left - 24,
|
// portions of those buttons that hang past the portal's left edge
|
||||||
top: portalRect.top,
|
// (and above its top edge) stay inside the hover-tolerance region.
|
||||||
right: portalRect.right,
|
// Was previously a hardcoded 24px left expansion which didn't
|
||||||
bottom: portalRect.bottom,
|
// cover top overhang and underestimated wider button labels.
|
||||||
};
|
const equipBtns = portal.querySelector('.tt-equip-btns');
|
||||||
const rects = [tokenRect, expandedPortalRect];
|
if (equipBtns) rects.push(equipBtns.getBoundingClientRect());
|
||||||
if (miniPortal.classList.contains('active')) rects.push(miniPortal.getBoundingClientRect());
|
if (miniPortal.classList.contains('active')) rects.push(miniPortal.getBoundingClientRect());
|
||||||
const left = Math.min(...rects.map(r => r.left));
|
const left = Math.min(...rects.map(r => r.left));
|
||||||
const top = Math.min(...rects.map(r => r.top));
|
const top = Math.min(...rects.map(r => r.top));
|
||||||
@@ -244,7 +244,19 @@ function initGameKitTooltips() {
|
|||||||
const tokenRect = token.getBoundingClientRect();
|
const tokenRect = token.getBoundingClientRect();
|
||||||
const halfW = portal.offsetWidth / 2;
|
const halfW = portal.offsetWidth / 2;
|
||||||
const rawLeft = tokenRect.left + tokenRect.width / 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';
|
portal.style.left = Math.round(clampedLeft) + 'px';
|
||||||
|
|
||||||
// Show above when token is in lower viewport half; below when in upper half
|
// Show above when token is in lower viewport half; below when in upper half
|
||||||
|
|||||||
@@ -350,21 +350,34 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
gap: calc(var(--fan-card-w) * 0.007);
|
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.
|
// Qualifier shares the name's typography — same line, different content.
|
||||||
// Sizes scale with --fan-card-w so they stay proportional on mobile.
|
// 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-above,
|
||||||
.sig-qualifier-below,
|
.sig-qualifier-below,
|
||||||
.fan-card-reversal-qualifier,
|
.fan-card-reversal-qualifier,
|
||||||
.fan-card-reversal-name,
|
.fan-card-reversal-name,
|
||||||
.fan-card-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;
|
font-weight: bold;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: rgba(var(--terUser), 1);
|
color: rgba(var(--terUser), 1);
|
||||||
transition: opacity 0.2s;
|
transition: opacity 0.2s;
|
||||||
|
text-wrap: balance;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reversal-face spans pre-rotated so they read forward once the card spins
|
// 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-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-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; }
|
.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-above,
|
||||||
.sig-qualifier-below,
|
.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-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-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
|
.fan-card-correspondence{ display: none; } // Minchiate equivalence shown in game-kit only
|
||||||
// Reversed face elements — pre-rotated so they read forward after card spins
|
// 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
|
// .sig-stage-card is normally scoped inside .sig-stage — re-apply the card shell
|
||||||
// here so it renders correctly outside that context.
|
// here so it renders correctly outside that context. Class-based selector so it
|
||||||
.sea-cross .sig-stage-card {
|
// also applies in the tray (.tray-sig-card .sig-stage-card.sea-sig-card).
|
||||||
|
.sig-stage-card.sea-sig-card {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
width: var(--sig-card-w, #{$sea-card-w});
|
width: var(--sig-card-w, #{$sea-card-w});
|
||||||
height: auto;
|
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; }
|
.fan-card-name-group { font-size: calc(var(--sig-card-w, 140px) * 0.073); opacity: 0.6; }
|
||||||
.sig-qualifier-above,
|
.sig-qualifier-above,
|
||||||
.sig-qualifier-below,
|
.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-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-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-qualifier,
|
||||||
.fan-card-reversal-name { transform: rotate(180deg); opacity: 0.25; }
|
.fan-card-reversal-name { transform: rotate(180deg); opacity: 0.25; }
|
||||||
|
|||||||
@@ -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 {
|
.tray-sig-card {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
overflow: hidden;
|
|
||||||
background: transparent;
|
background: transparent;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
img {
|
.sig-stage-card.sea-sig-card {
|
||||||
display: block;
|
--sig-card-w: calc(var(--tray-cell-size, 48px) * 5 / 8);
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
object-fit: cover;
|
|
||||||
object-position: center;
|
|
||||||
transform: scale(1.4); // crop SVG's internal margins
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
<header class="sea-modal-header">
|
<header class="sea-modal-header">
|
||||||
<h2>PICK <span>SEA</span></h2>
|
<h2>PICK <span>SEA</span></h2>
|
||||||
<p>Draw +6 cards to describe your character's influences and seed the game-map.</p>
|
<p>Draw +6 cards to describe your character's influences and seed the map.</p>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div class="sea-modal-body">
|
<div class="sea-modal-body">
|
||||||
@@ -151,7 +151,7 @@
|
|||||||
<div class="fan-card-face-upright">
|
<div class="fan-card-face-upright">
|
||||||
<p class="fan-card-name-group"></p>
|
<p class="fan-card-name-group"></p>
|
||||||
<p class="sig-qualifier-above"></p>
|
<p class="sig-qualifier-above"></p>
|
||||||
<h3 class="fan-card-name"></h3>
|
<p class="fan-card-name"></p>
|
||||||
<p class="sig-qualifier-below"></p>
|
<p class="sig-qualifier-below"></p>
|
||||||
</div>
|
</div>
|
||||||
<p class="fan-card-arcana"></p>
|
<p class="fan-card-arcana"></p>
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ Context: sig_cards, user_polarity, user_seat, sig_reserve_url, sig_reservations_
|
|||||||
<div class="fan-card-face-upright">
|
<div class="fan-card-face-upright">
|
||||||
<p class="fan-card-name-group"></p>
|
<p class="fan-card-name-group"></p>
|
||||||
<p class="sig-qualifier-above"></p>
|
<p class="sig-qualifier-above"></p>
|
||||||
<h3 class="fan-card-name"></h3>
|
<p class="fan-card-name"></p>
|
||||||
<p class="sig-qualifier-below"></p>
|
<p class="sig-qualifier-below"></p>
|
||||||
</div>
|
</div>
|
||||||
<p class="fan-card-arcana"></p>
|
<p class="fan-card-arcana"></p>
|
||||||
|
|||||||
@@ -28,13 +28,13 @@
|
|||||||
<div class="fan-card-face-upright">
|
<div class="fan-card-face-upright">
|
||||||
{% if card.levity_emanation %}
|
{% 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 #}
|
{# Polarity-split title (cards 48-49 + trumps 19-21); no qualifier slots — qualifier is baked into the title between "The" and the proper noun #}
|
||||||
<h3 class="fan-card-name">{{ card.levity_emanation|italicize:card.italic_word }}</h3>
|
<p class="fan-card-name {{ card.title_squeeze_class }}">{{ card.levity_emanation|italicize:card.italic_word }}</p>
|
||||||
{% else %}
|
{% else %}
|
||||||
{% if card.name_group %}<p class="fan-card-name-group">{{ card.name_group }}</p>{% endif %}
|
{% if card.name_group %}<p class="fan-card-name-group">{{ card.name_group }}</p>{% endif %}
|
||||||
{% if card.arcana != "MAJOR" and card.levity_qualifier %}
|
{% if card.arcana != "MAJOR" and card.levity_qualifier %}
|
||||||
<p class="sig-qualifier-above">{{ card.levity_qualifier }}</p>
|
<p class="sig-qualifier-above">{{ card.levity_qualifier }}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<h3 class="fan-card-name">{{ card.name_title|italicize:card.italic_word }}{% if card.arcana == "MAJOR" and card.levity_qualifier %},{% endif %}</h3>
|
<p class="fan-card-name {{ card.title_squeeze_class }}">{{ card.name_title|italicize:card.italic_word }}{% if card.arcana == "MAJOR" and card.levity_qualifier %},{% endif %}</p>
|
||||||
{% if card.arcana == "MAJOR" and card.levity_qualifier %}
|
{% if card.arcana == "MAJOR" and card.levity_qualifier %}
|
||||||
<p class="sig-qualifier-below">{{ card.levity_qualifier }}</p>
|
<p class="sig-qualifier-below">{{ card.levity_qualifier }}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -49,12 +49,12 @@
|
|||||||
{% if card.levity_reversal %}
|
{% 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. #}
|
{# Polarity-split reversal title — single line, qualifier slot empty. Title goes in the qualifier slot so it visually lands on top after spin. #}
|
||||||
<p class="fan-card-reversal-name"></p>
|
<p class="fan-card-reversal-name"></p>
|
||||||
<p class="fan-card-reversal-qualifier">{{ card.levity_reversal|italicize:card.italic_word }}</p>
|
<p class="fan-card-reversal-qualifier {{ card.title_squeeze_class }}">{{ card.levity_reversal|italicize:card.italic_word }}</p>
|
||||||
{% elif card.arcana == "MAJOR" %}
|
{% elif card.arcana == "MAJOR" %}
|
||||||
<p class="fan-card-reversal-name">{{ card.levity_qualifier|default:card.gravity_qualifier }}</p>
|
<p class="fan-card-reversal-name">{{ card.levity_qualifier|default:card.gravity_qualifier }}</p>
|
||||||
<p class="fan-card-reversal-qualifier">{{ card.name_title|italicize:card.italic_word }}{% if card.levity_qualifier %},{% endif %}</p>
|
<p class="fan-card-reversal-qualifier {{ card.title_squeeze_class }}">{{ card.name_title|italicize:card.italic_word }}{% if card.levity_qualifier %},{% endif %}</p>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p class="fan-card-reversal-name">{{ card.name_title|italicize:card.italic_word }}</p>
|
<p class="fan-card-reversal-name {{ card.title_squeeze_class }}">{{ card.name_title|italicize:card.italic_word }}</p>
|
||||||
<p class="fan-card-reversal-qualifier">{{ card.reversal_qualifier|default:card.gravity_qualifier }}</p>
|
<p class="fan-card-reversal-qualifier">{{ card.reversal_qualifier|default:card.gravity_qualifier }}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -101,7 +101,7 @@
|
|||||||
<i class="fa-solid fa-dice-d20"></i>
|
<i class="fa-solid fa-dice-d20"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div id="id_tray" style="display:none"><div id="id_tray_grid" data-role-icons-url="{% static 'apps/epic/icons/cards-roles/' %}">{% if my_tray_role %}<div class="tray-cell tray-role-card" data-role="{{ my_tray_role }}"><img src="{% static my_tray_scrawl_static_path %}" alt="{{ my_tray_role }}"></div>{% else %}<div class="tray-cell"></div>{% endif %}{% if my_tray_sig %}<div class="tray-cell tray-sig-card"><img src="{% static 'apps/epic/icons/cards-sigs/Blank.svg' %}" alt="{{ my_tray_sig.name }}"></div>{% else %}<div class="tray-cell"></div>{% endif %}{% for i in "345678" %}<div class="tray-cell"></div>{% endfor %}</div></div>
|
<div id="id_tray" style="display:none"><div id="id_tray_grid" data-role-icons-url="{% static 'apps/epic/icons/cards-roles/' %}">{% if my_tray_role %}<div class="tray-cell tray-role-card" data-role="{{ my_tray_role }}"><img src="{% static my_tray_scrawl_static_path %}" alt="{{ my_tray_role }}"></div>{% else %}<div class="tray-cell"></div>{% endif %}{% if my_tray_sig %}<div class="tray-cell tray-sig-card"><div class="sig-stage-card sea-sig-card" aria-label="{{ my_tray_sig.name }}"><span class="fan-corner-rank">{{ my_tray_sig.corner_rank }}</span>{% if my_tray_sig.suit_icon %}<i class="fa-solid {{ my_tray_sig.suit_icon }}"></i>{% endif %}</div></div>{% else %}<div class="tray-cell"></div>{% endif %}{% for i in "345678" %}<div class="tray-cell"></div>{% endfor %}</div></div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% include "apps/gameboard/_partials/_room_gear.html" %}
|
{% include "apps/gameboard/_partials/_room_gear.html" %}
|
||||||
|
|||||||
Reference in New Issue
Block a user