feat: My Sea applet dynamic population + lay/leave POSITION_LABELS swap fix + My Sign applet stat-block + Brief-fied sign-gate + --duoUser olive on all four personal-data surfaces. Six visual+structural items batched across the dashboard/billboard/gameboard.
(1) **My Sea applet dynamic population.** Applet at `_applet-my-sea.html` was referencing an undefined `latest_draw_cards` template var — fell through to "No draws yet" even when the user had an active draw. New helpers in `apps/gameboard/models.py`: `DRAW_ORDER` + `POSITION_LABELS` constants (Python mirrors of the JS dicts in `my_sea.html:274-293`) + `latest_draw_slots(user)` builder that pairs each spread position w. its drawn card + display label + polarity. Wired through `gameboard()` + `toggle_game_applets()` views as `my_sea_slots`. Applet now renders all spread slots in DRAW_ORDER: filled = `.my-sea-slot--filled.my-sea-slot--{gravity,levity}` w. corner-tl + face (name + arcana) + corner-br (mirror) markup (same shape language as my_sign.html `.sig-stage-card`), empty = `.my-sea-slot--empty` w. `0.15rem dashed rgba(var(--terUser), 1)` border (matches the picker's `.sea-card-slot` style exactly so the applet reads as a true scaled-down twin). Container queries (`container-type: size` on `.my-sea-scroll`) lift `--slot-w` to fill the applet's vertical aperture (`min(100cqi, calc((100cqh - 1rem) * 5 / 8))` carves the label row). Position labels pulled tight against the slot's bottom border (`margin-top: -0.15rem` crosses the border line) + vertically stretched (`transform: scaleY(1.4)` mirroring `.sea-pos-label` in `_card-deck.scss:1671-1684`) — empty-slot labels keep the same `--secUser` ink as filled-slot labels for title cohesion across the row. Horizontal-scroll on multi-card spreads via mousewheel — `bindMySeaWheel()` in `gameboard.js` translates vertical wheel events to `scrollLeft += deltaY` (lifted verbatim from `bindPaletteWheel` in `dashboard.js:7-14`).
(2) **lay/leave POSITION_LABELS swap fix.** User caught in the Escape Velocity picker that LEFT slot read "Lay" + BOTTOM slot read "Leave" — opposite of traditional Celtic Cross semantics (LEFT = Behind/past, BOTTOM = Beneath/root). Root cause: POSITION_LABELS for both Waite-Smith + Escape Velocity had `lay`/`leave` slug→label assignments inverted vs the CSS grid's spatial mapping (`_card-deck.scss:1276-1279` puts slug `lay` at BOTTOM, slug `leave` at LEFT). Fix in 5 places: `my_sea.html:287,292` JS POSITION_LABELS (WS: lay→"Beneath", leave→"Behind"; EV: lay→"Lay", leave→"Leave"), `gameboard/models.py:44-47` Python mirror, `test_game_my_sea.py:618-619` FT label-assertion table, `_sea_overlay.html:28,53` annotated comments (`sea-pos-leave` → "Behind (past) — CC pos 6 / EV pos 4"; `sea-pos-lay` → "Beneath (root) — CC pos 4 / EV pos 3"). Slug-to-CSS mapping, DRAW_ORDER, + DB persistence unchanged → no migrations, no data invalidation. **Crucial for Voronoi mapping correctness** per user spec.
(3) **My Sign applet — stage-card layout + stat-block beside.** Applet card markup upgraded to mirror my_sign.html `.sig-stage-card`: corner-tl + face (name + arcana centred) + corner-br (mirror, rotated 180°). Sized to fill applet height via container queries (`--applet-card-w: min(48cqi, 62.5cqh)` — 48cqi caps the card at half the row to leave room for the stat-block). Sibling `.my-sign-applet-stat-block` partial added — emanation/reversal face label + keyword list (from `card.keywords_upright` / `keywords_reversed` keyed off `significator_reversed`), no SPIN/FYI buttons (applet is read-only). Styling cribbed from `.sig-stat-block` in `_card-deck.scss:595-607` — priUser-translucent bg + terUser border + matching `--applet-card-w` sizing.
(4) **My Sea sign-gate refactored to Brief banner.** Was an inline `.my-sea-sign-gate` div w. its own SCSS — broke from the project's `Brief.showBanner` portal pattern. Refactored to a shared `_my_sea_sign_gate_brief.html` partial that fires `Brief.showBanner` w. title="Sign required" + line_text="Look!—pick your sign before drawing the Sea." + post_url=`/billboard/my-sign/`. Brief portals to the page-level h2 anchor via `note.js`'s `_alignToH2` (gaussian-glass `.note-banner` shell, FYI button → my-sign picker, NVM dismisses). Modifier class `.my-sea-sign-gate-brief` added post-render for FT selector disambiguation. note.js load hoisted to gameboard.html `{% block scripts %}` + the top of `my_sea.html {% block content %}` (single load per page — note.js declares `const Brief = ...` at global scope, second load = SyntaxError). All `.my-sea-sign-gate{,--applet,__line,__actions,__back,__fyi}` SCSS deleted. FTs (`test_no_sig_renders_lookline_gate_on_standalone_page` + 5 siblings) + ITs (`test_my_sea_applet_fires_sign_gate_brief_for_user_without_sig` etc.) updated to assert `.note-banner.my-sea-sign-gate-brief` + the JS-rendered FYI/NVM buttons inside the Brief shell.
(5) **Levity card text invisibility fix.** My-sea applet levity slots (--secUser bg) rendered their corner-rank + suit-icon invisible because `.fan-card-corner` carries a global `color: rgba(var(--secUser), 0.75)` rule at `_card-deck.scss:312-319` (specificity 0,1,0) that out-specifics the slot's inherited `color: --priUser`. Same trap as the `.fan-card-name { color: --quiUser }` global. Fix at `_gameboard.scss` inside the levity rule: explicit `.fan-card-corner { color: rgba(var(--priUser), 1) }` + `.fan-card-name { color: rgba(var(--priUser), 1) }` + `.fan-card-arcana { color: rgba(var(--priUser), 0.7) }` overrides at (1,3,1) specificity — beats the globals without `!important`. **Trap captured in memory** — pattern repeats across game-kit, my-sign, my-sea so worth pinning.
(6) **--duoUser olive on all five personal-data surfaces.** Per user spec, the four "personal" applets (My Sign on billboard, My Sea on gameboard, My Sky on dashboard) + the standalone Dashsky page + the standalone My Sign page got `background-color: rgba(var(--duoUser), 1)` so they read as a unified olive-bg group across navigation surfaces. For Dashsky specifically, the form column also got the override (`.sky-page .sky-form-col { background: --duoUser }`) — the base `.sky-form-col { background: --priUser }` (`_sky.scss:137`, shared w. the in-room CAST SKY modal) was leaving the dashsky form column purple inside the otherwise-olive page. Scoped to `.sky-page` so the in-room modal's purple form-col stays intact (sits over --secUser room bg, needs that contrast). One detour caught: tried `body.page-sky { background-color: --duoUser }` to fill the gap below .sky-page's content-sized aperture but it bled to navbar + footer (which sit outside .container) — reverted.
**TDD coverage**: 3 new ITs in `apps/gameboard/tests/integrated/test_views.py` — `test_my_sea_applet_renders_drawn_cards_in_draw_order` (SAO 1-of-3 fills `lay` slot, cover/crown render as empty placeholders), `test_my_sea_applet_labels_match_locked_spread` (SAO labels exactly Situation/Action/Outcome), `test_my_sea_applet_waite_smith_labels_post_fix` (regression pin for the WS Cover/Cross/Crown/**Beneath**/Before/**Behind** sequence post-swap-fix). Existing my-sea applet ITs updated to match the new selector vocabulary (`.my-sea-slot--filled` instead of `.my-sea-card`, Brief script substring instead of `.my-sea-sign-gate--applet`). 6 my-sea FTs updated to the Brief-banner contract. 1214/1214 IT/UT green.
**.gitignore**: temporary entry for `src/apps/epic/static/apps/epic/images/cards-faces/minchiate-fiorentine/` until images get renamed — flagged for removal once the rename lands. (Per user's wget download of the Minchiate faces into the gameboard cards/ tree this session.)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -433,73 +433,165 @@ body.page-billposts {
|
||||
// `.applet-list-page .applet-scroll`). Old `.scroll-list` styling removed.
|
||||
|
||||
// ── My Sign applet (billboard) ────────────────────────────────────────────
|
||||
// Saved-sig preview thumbnail. Same 5:8 card shell + corner/name layout as
|
||||
// `.sig-stage-card` (see `_card-deck.scss`) but scaled down to fit the 4×6
|
||||
// applet aperture. Without these rules the markup collapses bg-less to the
|
||||
// applet's top-left corner. `--applet-card-w` drives all child font sizing
|
||||
// off a single knob (same calc-fractions as `.sig-stage-card` w. --sig-card-w).
|
||||
// Saved-sig preview — mirrors the `.sig-stage-card` layout (corner top-
|
||||
// left + face w. name + arcana + mirror corner bottom-right) but sized
|
||||
// to fill the applet's vertical aperture rather than a fixed 5rem.
|
||||
// Container queries on `.my-sign-applet-body` lift `--applet-card-w` to
|
||||
// `min(100cqi, 62.5cqh)` — the card grows to fill whichever axis is
|
||||
// constraining (62.5cqh = `100cqh * 5/8` keeps the 5:8 aspect inside
|
||||
// the container height). All child font sizes calc off --applet-card-w
|
||||
// so the typography scales w. the card without per-applet tuning.
|
||||
#id_applet_my_sign {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
// Anchor for #id_applet_sky_delete_btn's absolute centering.
|
||||
position: relative;
|
||||
background-color: rgba(var(--duoUser), 1) !important;
|
||||
|
||||
.my-sign-applet-empty {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
h2 {
|
||||
flex-shrink: 0;
|
||||
background-color: rgba(var(--priUser), 1);
|
||||
box-shadow: rgba(0, 0, 0, 1) !important;
|
||||
}
|
||||
|
||||
.my-sign-applet-body {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0.5rem;
|
||||
gap: 0.5rem;
|
||||
padding: 0.3rem;
|
||||
container-type: size;
|
||||
}
|
||||
|
||||
.my-sign-applet-card {
|
||||
--applet-card-w: 5rem;
|
||||
// Width-cap shrinks by half the row (card + gap + stat-block) so the
|
||||
// pair centres without horizontal overflow. `1.0cqi` keeps the
|
||||
// gap/padding allowance — anything left after the stat-block grows
|
||||
// to fill, capped by the card's natural 5:8 aspect.
|
||||
--applet-card-w: min(48cqi, 62.5cqh);
|
||||
width: var(--applet-card-w);
|
||||
aspect-ratio: 5 / 8;
|
||||
border-radius: 0.4rem;
|
||||
background: rgba(var(--priUser), 1);
|
||||
border: 0.12rem solid rgba(var(--secUser), 0.6);
|
||||
color: rgba(var(--secUser), 1);
|
||||
padding: 0.25rem;
|
||||
padding: 0.35rem;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
transition: transform 0.4s ease;
|
||||
|
||||
.fan-card-corner--tl {
|
||||
// Top-left + bottom-right corners — rank + suit icon stacked.
|
||||
// br is rotated 180° (mirror) so the card reads as "completed"
|
||||
// from both edges, matching the stage card pattern.
|
||||
.fan-card-corner--tl,
|
||||
.fan-card-corner--br {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
line-height: 1.1;
|
||||
line-height: 1.05;
|
||||
gap: 0.05rem;
|
||||
position: absolute;
|
||||
top: 0.2rem;
|
||||
left: 0.2rem;
|
||||
|
||||
.fan-corner-rank {
|
||||
font-size: calc(var(--applet-card-w) * 0.18);
|
||||
font-size: calc(var(--applet-card-w) * 0.16);
|
||||
font-weight: 700;
|
||||
}
|
||||
i { font-size: calc(var(--applet-card-w) * 0.14); }
|
||||
i { font-size: calc(var(--applet-card-w) * 0.13); }
|
||||
}
|
||||
.fan-card-corner--tl { top: 0.25rem; left: 0.3rem; }
|
||||
.fan-card-corner--br {
|
||||
bottom: 0.25rem; right: 0.3rem;
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
// Card face — name + arcana stacked, centred in the remaining
|
||||
// vertical space between the two corners. `flex: 1` lets the
|
||||
// face absorb whatever's left after the absolute-positioned
|
||||
// corners.
|
||||
.fan-card-face {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.2rem;
|
||||
text-align: center;
|
||||
padding: 0 0.2rem;
|
||||
}
|
||||
|
||||
.fan-card-name {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
font-size: calc(var(--applet-card-w) * 0.13);
|
||||
font-weight: 600;
|
||||
font-size: calc(var(--applet-card-w) * 0.11);
|
||||
font-weight: 700;
|
||||
line-height: 1.15;
|
||||
text-wrap: balance;
|
||||
padding: 0 0.15rem;
|
||||
color: rgba(var(--quiUser), 1);
|
||||
}
|
||||
|
||||
.fan-card-arcana {
|
||||
margin: 0;
|
||||
font-size: calc(var(--applet-card-w) * 0.075);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
&.stage-card--reversed { transform: rotate(180deg); }
|
||||
}
|
||||
|
||||
// Stat block — mirrors the stage card's footprint (same 5:8 aspect +
|
||||
// height) so the pair reads as a balanced 2-tile composition centred
|
||||
// in the applet aperture. Styling cribbed from `.sig-stat-block` in
|
||||
// `_card-deck.scss:595-607` (priUser-translucent bg + terUser border)
|
||||
// minus the SPIN/FYI button apparatus — applet is read-only, no
|
||||
// interaction needed. `--applet-card-w` is reused as the sizing knob
|
||||
// so stat-face-label + stat-keywords typography scales w. the card.
|
||||
.my-sign-applet-stat-block {
|
||||
--applet-card-w: min(48cqi, 62.5cqh);
|
||||
width: var(--applet-card-w);
|
||||
aspect-ratio: 5 / 8;
|
||||
align-self: center;
|
||||
background: rgba(var(--priUser), 0.8);
|
||||
border-radius: 0.4rem;
|
||||
border: 0.1rem solid rgba(var(--terUser), 0.15);
|
||||
padding: calc(var(--applet-card-w) * 0.08);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
|
||||
.stat-face-label {
|
||||
font-size: calc(var(--applet-card-w) * 0.08);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.09em;
|
||||
opacity: 0.7;
|
||||
color: rgba(var(--terUser), 1);
|
||||
margin: 0 0 calc(var(--applet-card-w) * 0.06);
|
||||
}
|
||||
|
||||
.stat-keywords {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
li {
|
||||
font-size: calc(var(--applet-card-w) * 0.1);
|
||||
padding: calc(var(--applet-card-w) * 0.04) 0;
|
||||
color: rgba(var(--quiUser), 1);
|
||||
border-bottom: 0.05rem solid rgba(var(--terUser), 0.18);
|
||||
&:last-child { border-bottom: none; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.my-sign-applet-empty {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
|
||||
@@ -60,6 +60,8 @@
|
||||
.stat-face--upright { display: block; }
|
||||
|
||||
&.is-reversed {
|
||||
opacity: 1;
|
||||
|
||||
.stat-face--upright { display: none; }
|
||||
.stat-face--reversed { display: block; }
|
||||
}
|
||||
|
||||
@@ -162,48 +162,13 @@ body.page-gameboard {
|
||||
}
|
||||
|
||||
// ─── My Sea sign-gate ────────────────────────────────────────────────────────
|
||||
// Sprint 4b of [[project-my-sea-roadmap]]. Renders when User.significator
|
||||
// is None, on both the standalone /gameboard/my-sea/ page AND the
|
||||
// /gameboard/ My Sea applet. Look!-formatted Brief-style line w. FYI
|
||||
// (→ /billboard/my-sign/) + BACK (→ /gameboard/) action buttons. Inline
|
||||
// content (not portaled like .note-banner) — it IS the page content
|
||||
// until a sig is picked, not a transient nudge.
|
||||
.my-sea-sign-gate {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 1rem;
|
||||
padding: 1.5rem;
|
||||
color: rgba(var(--terUser), 1);
|
||||
|
||||
.my-sea-sign-gate__line {
|
||||
text-align: center;
|
||||
font-size: 1.1rem;
|
||||
line-height: 1.4;
|
||||
margin: 0;
|
||||
// --terUser ink mirrors the gate's accent + signals "do this
|
||||
// first" visually distinct from the body's standard --secUser.
|
||||
color: rgba(var(--terUser), 1);
|
||||
}
|
||||
|
||||
.my-sea-sign-gate__actions {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
// Applet variant — denser layout, omits NVM (the user is already on
|
||||
// the gameboard). Smaller line + just the FYI action surviving.
|
||||
&.my-sea-sign-gate--applet {
|
||||
padding: 0.5rem;
|
||||
gap: 0.5rem;
|
||||
|
||||
.my-sea-sign-gate__line {
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
// REMOVED 2026-05-22 — refactored to a Brief banner. The no-sig nudge now
|
||||
// fires via `Brief.showBanner` from `_my_sea_sign_gate_brief.html`, which
|
||||
// portals a `.note-banner.my-sea-sign-gate-brief` to the page h2 (gaussian-
|
||||
// glass shell, FYI → /billboard/my-sign/, NVM dismisses). All the inline
|
||||
// `.my-sea-sign-gate{,--applet,__line,__actions,__back,__fyi}` styling
|
||||
// dropped — `.note-banner` rules in `_note.scss:11` cover positioning,
|
||||
// shell, + button placement DRYly.
|
||||
|
||||
// ─── My Sea DRAW SEA landing ─────────────────────────────────────────────────
|
||||
// Sprint 5 iter 1 of [[project-my-sea-roadmap]]. When a user has a saved
|
||||
@@ -596,3 +561,214 @@ body.page-gameboard {
|
||||
// above the anchor button w. Gaussian glass + no backdrop). The picker IIFE
|
||||
// invokes it via `window.showGuard(delBtn, "Are you sure?", confirmFn,
|
||||
// null, {yesLabel: "DEL"})`. No my-sea-specific SCSS needed.
|
||||
|
||||
|
||||
// ── My Sea applet (billboard-style gameboard applet) ─────────────────────────
|
||||
// The applet at `_applet-my-sea.html` lists the active draw's slots in
|
||||
// DRAW_ORDER — drawn cards filled + empty slots placeholder'd, each
|
||||
// w. a label caption tucked tight against the slot's bottom edge.
|
||||
// Horizontal-scroll mirrors the Palettes applet (`.palette` in
|
||||
// `_palette-picker.scss:1`): row of fixed-size items + `overflow-x:
|
||||
// auto`, so 6-card spreads scroll while 3-card spreads fit. Slots use
|
||||
// the same `.sig-stage-card` layout language as the my_sign.html stage
|
||||
// card (corner-tl + face w. name + corner-br) at applet scale —
|
||||
// container queries on `.my-sea-scroll` lift `--slot-w` to fill the
|
||||
// scroll's vertical aperture (minus label) so cards span the whole
|
||||
// applet height per user spec 2026-05-22.
|
||||
#id_applet_my_sea {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
// Anchor for #id_applet_sky_delete_btn's absolute centering.
|
||||
position: relative;
|
||||
background-color: rgba(var(--duoUser), 1) !important;
|
||||
|
||||
h2 {
|
||||
flex-shrink: 0;
|
||||
background-color: rgba(var(--priUser), 1);
|
||||
box-shadow: rgba(0, 0, 0, 1) !important;
|
||||
}
|
||||
|
||||
.my-sea-scroll {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: stretch;
|
||||
gap: 0.75rem;
|
||||
padding: 0.25rem 0.5rem 0.5rem;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
scroll-snap-type: x mandatory;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
container-type: size;
|
||||
}
|
||||
|
||||
.my-sea-slot-wrap {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
scroll-snap-align: start;
|
||||
height: 100%;
|
||||
// No gap — the label sits directly against the slot's bottom
|
||||
// border per user spec ("tighter [...] practically overlapping").
|
||||
// Slight negative margin pulls the label baseline up into the
|
||||
// slot's border line so the two visually merge.
|
||||
}
|
||||
|
||||
// Slot shell — 5:8 card, sized to fill the wrap's height minus the
|
||||
// label row. `--slot-w` resolves via container queries: 100cqi-cap
|
||||
// when the scroll is wide-but-shallow, 100cqh*5/8 = 62.5cqh - tiny-
|
||||
// label-reservation otherwise. The `- 1rem` carves out the label
|
||||
// row + tight gap so the card doesn't overshoot the applet floor.
|
||||
.my-sea-slot {
|
||||
--slot-w: min(100cqi, calc((100cqh - 1rem) * 5 / 8));
|
||||
width: var(--slot-w);
|
||||
aspect-ratio: 5 / 8;
|
||||
border-radius: 0.4rem;
|
||||
border: 0.12rem solid rgba(var(--secUser), 0.6);
|
||||
padding: 0.35rem;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
flex: 0 0 auto;
|
||||
|
||||
.fan-card-corner--tl,
|
||||
.fan-card-corner--br {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
line-height: 1.05;
|
||||
gap: 0.05rem;
|
||||
position: absolute;
|
||||
|
||||
.fan-corner-rank {
|
||||
font-size: calc(var(--slot-w) * 0.16);
|
||||
font-weight: 700;
|
||||
}
|
||||
i { font-size: calc(var(--slot-w) * 0.13); }
|
||||
}
|
||||
.fan-card-corner--tl { top: 0.25rem; left: 0.3rem; }
|
||||
.fan-card-corner--br {
|
||||
bottom: 0.25rem; right: 0.3rem;
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.fan-card-face {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.2rem;
|
||||
text-align: center;
|
||||
padding: 0 0.2rem;
|
||||
}
|
||||
|
||||
.fan-card-name {
|
||||
margin: 0;
|
||||
font-size: calc(var(--slot-w) * 0.105);
|
||||
font-weight: 700;
|
||||
line-height: 1.15;
|
||||
text-wrap: balance;
|
||||
}
|
||||
|
||||
.fan-card-arcana {
|
||||
margin: 0;
|
||||
font-size: calc(var(--slot-w) * 0.07);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
// Filled slot polarity — mirrors `.sea-card-slot--gravity` / `--levity`
|
||||
// in `_card-deck.scss:1332-1341`. Gravity = priUser bg + quiUser text;
|
||||
// levity = inverted (secUser bg + priUser text). Explicit
|
||||
// `.fan-card-name { color: ... }` override is required: the global
|
||||
// `.fan-card-name` rule in `_card-deck.scss:569-570` hardcodes
|
||||
// --quiUser, which is invisible on the levity --secUser bg (both
|
||||
// light variants). Setting it back to --priUser here restores
|
||||
// contrast. Corner-rank + arcana inherit from the slot's `color`
|
||||
// (no global override) so they follow polarity automatically.
|
||||
.my-sea-slot--filled.my-sea-slot--gravity {
|
||||
background: rgba(var(--priUser), 1);
|
||||
color: rgba(var(--quiUser), 1);
|
||||
border-color: rgba(var(--secUser), 0.6);
|
||||
}
|
||||
.my-sea-slot--filled.my-sea-slot--levity {
|
||||
background: rgba(var(--secUser), 1);
|
||||
color: rgba(var(--priUser), 1);
|
||||
border-color: rgba(var(--priUser), 1);
|
||||
// `.fan-card-corner` carries a global `color: rgba(var(--secUser),
|
||||
// 0.75)` rule in `_card-deck.scss:312-319` that out-specifics the
|
||||
// slot's inherited color (specificity 0,1,0 wins over inheritance).
|
||||
// On the levity --secUser bg this paints the corner-rank + suit-
|
||||
// icon in the same color as the background → invisible. Same trap
|
||||
// bit my-sign + game-kit earlier — fix is an explicit override at
|
||||
// matching/higher specificity inside the polarity rule.
|
||||
// `.fan-card-name` has its own `color: --quiUser` global rule
|
||||
// (`_card-deck.scss:569-570`); `.fan-card-arcana` inherits but pin
|
||||
// explicitly so a future global tweak can't silently re-break it.
|
||||
.fan-card-corner { color: rgba(var(--priUser), 1); }
|
||||
.fan-card-name { color: rgba(var(--priUser), 1); }
|
||||
.fan-card-arcana { color: rgba(var(--priUser), 0.7); }
|
||||
}
|
||||
.my-sea-slot--filled.my-sea-slot--reversed { transform: rotate(180deg); }
|
||||
|
||||
// Empty slot — matches the my_sea.html picker's empty `.sea-card-
|
||||
// slot` style (`_card-deck.scss:1299-1303`): 0.15rem DASHED border in
|
||||
// --terUser at full opacity, --duoUser fill. Same width + dash
|
||||
// frequency as the picker so the applet reads as a true "miniature"
|
||||
// of the picker rather than a cousin w. different dotting cadence.
|
||||
// `!important` on the three border properties: the base `.my-sea-
|
||||
// slot` border shorthand sits at the same (1,1,0) specificity, so
|
||||
// belt-and-suspenders the override.
|
||||
.my-sea-slot--empty {
|
||||
background-color: rgba(var(--duoUser), 1);
|
||||
border-style: dashed !important;
|
||||
border-color: rgba(var(--terUser), 1) !important;
|
||||
border-width: 0.15rem !important;
|
||||
}
|
||||
|
||||
// Label — pulled tight against the slot's bottom border + vertically
|
||||
// stretched via `scaleY(1.2)` to match the my_sea.html picker's
|
||||
// `.sea-pos-label` typography (re-appropriated from `.sea-stack-name`
|
||||
// in `_card-deck.scss:1671-1684`). Negative margin-top crosses the
|
||||
// 0.12rem border so the label's top edge overlaps the bottom edge of
|
||||
// the slot, per the user-locked spec ("practically overlapping").
|
||||
.my-sea-slot-label {
|
||||
margin-top: -0.15rem;
|
||||
padding: 0 0.2rem;
|
||||
font-size: 0.65rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
color: rgba(var(--secUser), 0.85);
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
line-height: 1.1;
|
||||
transform: scaleY(1.4);
|
||||
transform-origin: top center;
|
||||
}
|
||||
// `.my-sea-slot-label--empty` intentionally has NO per-state recolor
|
||||
// — the empty-state label keeps the same `--secUser` ink as the
|
||||
// filled-slot label per user spec 2026-05-22 (pins position identity
|
||||
// Cover/Cross/etc. across the row regardless of fill state).
|
||||
// Previously dimmed to --terUser to echo the dashed border tone —
|
||||
// but that broke title cohesion when most slots were empty.
|
||||
|
||||
// No-draws empty state — centred italic, mirrors the Brief / applet-
|
||||
// list-entry--empty pattern in `_billboard.scss:29-38`.
|
||||
.my-sea-empty {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
font-style: italic;
|
||||
opacity: 0.6;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -906,8 +906,13 @@ body[class*="-light"] #id_sky_tooltip_2 {
|
||||
flex-direction: column;
|
||||
// Anchor for #id_applet_sky_delete_btn's absolute centering.
|
||||
position: relative;
|
||||
background-color: rgba(var(--duoUser), 1) !important;
|
||||
|
||||
h2 { flex-shrink: 0; }
|
||||
h2 {
|
||||
flex-shrink: 0;
|
||||
background-color: rgba(var(--priUser), 1);
|
||||
box-shadow: rgba(0, 0, 0, 1) !important;
|
||||
}
|
||||
|
||||
.sky-svg {
|
||||
flex: 1;
|
||||
@@ -953,8 +958,20 @@ body[class*="-light"] #id_sky_tooltip_2 {
|
||||
flex-direction: column;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
// --duoUser aperture bg — matches the My Sky / My Sea / My Sign
|
||||
// applet shells (`_sky.scss:909`, `_gameboard.scss:583`,
|
||||
// `_billboard.scss:449`) so all four personal-data surfaces read
|
||||
// as a unified olive-bg group across the dashboard/billboard/
|
||||
// gameboard navigation.
|
||||
background-color: rgba(var(--duoUser), 1);
|
||||
}
|
||||
|
||||
// Note: tried `body.page-sky { background-color: --duoUser }` to fill
|
||||
// any gap below the .sky-page aperture but it bled to navbar + footer
|
||||
// (which sit OUTSIDE .container) — reverted 2026-05-22. The real fix
|
||||
// is the scoped `.sky-page .sky-form-col` rule below, which puts the
|
||||
// olive on the form column where the purple was leaking through.
|
||||
|
||||
// DEL btn pinned at the wheel center — appears wherever a wheel is shown
|
||||
// (Dashsky form#id_sky_delete_form, CAST SKY overlay #id_sky_delete_btn,
|
||||
// My Sky applet #id_applet_sky_delete_btn). Anchored to .sky-wheel-col /
|
||||
@@ -1021,6 +1038,16 @@ body[class*="-light"] #id_sky_tooltip_2 {
|
||||
overflow-y: visible;
|
||||
}
|
||||
|
||||
// Override the base `.sky-form-col { background: --priUser }` (line 137,
|
||||
// shared w. the in-room CAST SKY modal) so the dashsky form column sits
|
||||
// on the same --duoUser olive as the rest of the .sky-page aperture.
|
||||
// Scoped to `.sky-page` so the in-room modal's purple form-col stays
|
||||
// intact (it sits over the room's --secUser bg + needs the contrast).
|
||||
.sky-page .sky-form-col {
|
||||
background: rgba(var(--duoUser), 1);
|
||||
border-right-color: transparent;
|
||||
}
|
||||
|
||||
// The (max-width:600px) block (written for the in-room CAST SKY modal where
|
||||
// form-col is flex-row) sets align-self:flex-end on the btn — that's "right"
|
||||
// once we flip to flex-column. Reset.
|
||||
|
||||
Reference in New Issue
Block a user