// Aperture foundation (html/body/.container overflow + flex-column) lives // universally in _base.scss. Gameboard's only divergence: `overflow: clip` // on .container instead of `hidden` — `clip` prevents the seat tooltip // scroll-anchoring quirk Firefox triggers under overflow:hidden. The // `.row { margin-bottom: -1rem }` pull mirrors the billboard/dashboard // h2-row tightening. body.page-gameboard { .container { overflow: clip; } .row { margin-bottom: -1rem; } } .gameboard-page { flex: 1; min-width: 425px; overflow: hidden; display: flex; flex-direction: column; position: relative; } @media (max-width: 550px) { .gameboard-page { min-width: 0; overflow: hidden; } } @media (min-width: 738px) { .gameboard-page { min-width: 666px; } body.page-gameboard .container { overflow: visible; } } @media (orientation: landscape) { // Restore clip in landscape — overrides the >738px overflow:visible above, // preventing the gameboard applets from bleeding into the footer sidebar. body.page-gameboard .container { overflow: clip; } // Reset the 666px min-width so gameboard-page shrinks to fit within the // sidebar-bounded container rather than overflowing into the footer sidebar. .gameboard-page { min-width: 0; } } #id_applet_game_kit { display: flex; flex-direction: column; #id_game_kit { flex: 1; position: relative; display: flex; flex-direction: row; flex-wrap: wrap; align-items: center; justify-content: space-evenly; overflow-x: visible; scrollbar-width: none; &::-webkit-scrollbar { display: none; } .token { position: static; } .token:hover .token-tooltip, .token:hover .tt { display: none; } // JS portal handles show/hide .token, .kit-item { font-size: 1.5rem; } .kit-item { opacity: 0.6; } } } // Sprint A.4 — card-deck stack icon (.deck-stack-icon) replaces the // fa-regular fa-id-badge wherever a deck appears in icon form: gameboard's // .token.deck-variant, kit-bag dialog's .kit-bag-deck, future room.html pile // + deck-bag. Lifted out of the #id_applet_game_kit nest so the base sizing // + rest-state SCSS applies in any deck-icon context. 3 stacked card-back // rects, 5° CW rest tilt; see [[project-card-deck-icon]] for the design rules. // When the deck has card-images, the rect fills are overridden inline w. an // SVG referencing the deck's -back.png; otherwise the // placeholder `fill: rgba(--priUser, 1)` shows through. .deck-stack-icon { display: inline-block; // 2026-05-25 PM user spec: 1.5× the prior fa-id-badge visual weight // since the icon is no longer constrained to placeholder-icon dimensions // (now a meaningful first-class deck visualization). width: 2.25rem; // 1.5rem × 1.5 height: 3.6rem; // 1.5× while preserving 5:8 tarot card aspect color: rgba(var(--terUser), 1); // stroke color via currentColor overflow: visible; // fan-out exceeds the viewBox bounds filter: drop-shadow(0.08rem 0.08rem 0.15rem rgba(0, 0, 0, 0.6)); .deck-stack-icon__stack { transform: rotate(5deg); transform-origin: 50% 50%; transform-box: fill-box; transition: transform 0.25s ease; } .deck-stack-icon__card { fill: rgba(var(--priUser), 1); stroke: currentColor; stroke-width: 1; transform-origin: 50% 50%; transform-box: fill-box; transition: transform 0.25s ease; } // Rest: tightly stacked w. tiny vertical offsets (suggests stack // depth without separating the cards visually). .deck-stack-icon__card--1 { transform: translateY(-0.4px); } .deck-stack-icon__card--3 { transform: translateY( 0.4px); } } // Sprint A.4 — fan-out trigger lives at the icon level (not nested in // #id_applet_game_kit) so the same `.deck-stack-icon` works wherever it's // dropped: gameboard's .token.deck-variant, kit-bag dialog's .kit-bag-deck, // future room.html pile + deck-bag. Hover/active/focus on the icon itself // OR any of its known wrappers triggers the splay; cards 2 + 3 fan out from // under card 1, card 1 stays put. Tooltip portal is wired to the same // `.token:hover` / `.kit-bag-deck:hover` triggers via JS so the splay + // tooltip-appearance co-activate. .deck-stack-icon:hover, .deck-stack-icon:active, .token.deck-variant:hover .deck-stack-icon, .token.deck-variant:active .deck-stack-icon, .token.deck-variant:focus .deck-stack-icon, .kit-bag-deck:hover .deck-stack-icon, .kit-bag-deck:active .deck-stack-icon, .kit-bag-deck:focus .deck-stack-icon { .deck-stack-icon__card--2 { transform: translate(-5px, -2px) rotate(-12deg); } .deck-stack-icon__card--3 { transform: translate( 5px, -2px) rotate( 12deg); } } #id_applet_new_game { display: flex; flex-direction: column; } #id_applet_my_games { display: flex; flex-direction: column; .applet-list { flex: 1; padding-top: 0.25rem; } } #id_tooltip_portal { position: fixed; z-index: 9999; padding: 0.75rem 1.5rem; @extend %tt-token-fields; .tt-equip-btns { position: absolute; left: -1rem; top: -1rem; display: flex; flex-direction: column; gap: 0.25rem; z-index: 1; .btn { margin: 0; } } // Tray sig-card tooltip (Phase 2) — PRV / NXT btns pinned to the bottom // corners of the portal, 1rem outside the panel so the btn centres land // exactly on the corners. The shared @stat-block-shared mixin in // _card-deck.scss already does this for fan / sig / sea contexts; the // portal isn't covered by that mixin so we re-state the rules here. .fyi-prev, .fyi-next { display: inline-flex; position: absolute; bottom: -1rem; margin: 0; z-index: 70; } .fyi-prev { left: -1rem; } .fyi-next { right: -1rem; } &.active { display: block; } } #id_mini_tooltip_portal { position: fixed; z-index: 9999; font-size: 0.8em; font-style: italic; width: fit-content; white-space: nowrap; text-align: right; &.active { display: block; } } @media (max-height: 500px) { body.page-gameboard { .container { .row { padding: 0.25rem 0; .col-lg-6 h2 { margin-bottom: 0.5rem; } } } } } // ─── My Sea sign-gate ──────────────────────────────────────────────────────── // 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 // significator (gate passed), /gameboard/my-sea/ renders this landing // screen: DRY table hex w. 6 chair seats labeled 1C-6C + central DRAW // SEA btn. Mirrors my-sign's `.my-sign-page` + `.my-sign-landing` // structure — same room-shell chain so room.js's scaleTable() can size // the hex; same flex setup so the container chain propagates real // height down for the scale calc. .my-sea-page { flex: 1; min-height: 0; display: flex; flex-direction: column; position: relative; } .my-sea-landing { flex: 1; min-height: 0; display: flex; // FREE DRAW btn — centered in the hex, mirrors SCAN SIGN's 2-line // font sizing so "FREE/DRAW" sits cleanly inside the 4rem circle. #id_draw_sea_btn { white-space: normal; } // Chair-position labels (1C-6C). Mirrors the room's `.seat-role- // label` grid placement (col 2, row 1 by default; flips to col 1 // for left-side seats 3/4/5 so the label sits closest to the hex) // but uses a role-free class name — my-sea is the solo draw flow, // no role-pick phase, so the room's role-grammar doesn't apply. .table-seat .seat-position-label { grid-column: 2; grid-row: 1; font-size: 0.8rem; font-weight: 600; letter-spacing: 0.05em; color: rgba(var(--secUser), 1); } .table-seat[data-slot="3"] .seat-position-label, .table-seat[data-slot="4"] .seat-position-label, .table-seat[data-slot="5"] .seat-position-label { grid-column: 1; } // Seated chair (post-FREE DRAW). Visual transition mirrors // `.table-seat.active .fa-chair` from _room.scss line 626 — // --terUser color + --ninUser drop-shadow glow — but uses a stable // `.seated` class (semantically distinct from `.active`: active = // current turn in a multi-user room; seated = draw-locked occupant // in this solo-flow). _room.scss line 596 makes the colour change // a 0.6s ease transition so the chair animates rather than snaps. // Status icon (.position-status-icon) colour swap fa-ban red → // fa-circle-check green is handled by _room.scss lines 615-616. .table-seat.seated .fa-chair { color: rgba(var(--terUser), 1); filter: drop-shadow(0 0 4px rgba(var(--ninUser), 1)); } } // Picker phase bg — `--duoUser` matches the table hex's interior so // the landing→picker swap reads as a continuous surface (parallels // `.my-sign-page[data-phase="picker"]` in _card-deck.scss line 704). .my-sea-page[data-phase="picker"] { background: rgba(var(--duoUser), 1); } // Landing phase bg — explicit `--priUser` revert per user spec // (2026-05-20). The hex INTERIOR is `--duoUser` (set on `.table-hex` // in _room.scss); the aperture AROUND the hex should be the default // body color. Defensive override so any bf-cache / stale-CSS state // can't leak the picker-phase green bg onto a landing render. .my-sea-page[data-phase="landing"] { background: rgba(var(--priUser), 1); } // Sprint 6 iter 6a — gatekeeper page bg + modal chrome. The page bg // is uniform `--duoUser` (matches the hex interior on landing / // picker so the visual transitions read as a continuous surface); // the `.gate-overlay`/`.gate-modal` rules in `_room.scss` already // give us the darkened Gaussian-glass modal centered over it. No hex // or chair-seats on this page — the gatekeeper is a transient in- // flight UI per user spec 2026-05-20. .my-sea-page[data-phase="gate"] { background: rgba(var(--duoUser), 1); flex: 1; min-height: 0; } .my-sea-picker { flex: 1; min-height: 0; display: flex; align-items: center; justify-content: center; gap: 1rem; // Portrait — stack the cross spread above the form col (mirrors the // gameroom SEA SELECT modal's `@media (max-width: 600px)` stack // pattern in `_card-deck.scss`). Landscape keeps the side-by-side // layout since horizontal real-estate is the abundant axis there. // User-spec 2026-05-20. @media (orientation: portrait) { flex-direction: column; } } // .my-sea-cross renders all 6 surrounding positions (crown/leave/lay/ // loom + cover/cross overlaid on core) unconditionally. The SPREAD // dropdown sets `data-spread=""` on this element; per-spread // rules below hide the positions each spread doesn't use. Inherits // the 3×3 `grid-template-areas` from _card-deck.scss line 1189-1200 // so visible cells land in their canonical positions; hidden cells // just leave their grid slots empty. // // Per-spread position subsets — user-locked 2026-05-19: // PPF: leave (1) cover (2) loom (3) — horizontal middle row // SAO: lay (1) cover (2) crown (3) — vertical center column // MBS: crown (1) lay (2) loom (3) — T-shape (crown + lay vertical, loom right) // DOS: loom (1) cross (2) crown (3) — loom right · cross overlay · crown above // CC variants: all 6 positions (Waite-Smith / Escape Velocity differ in DRAW ORDER only, // not in position visibility). // Bump grid gap on my-sea (gameroom .sea-cross stays at 0.5rem since // gameroom slots have no per-position labels). The vertical leave/loom // labels need ~1.5rem of horizontal clearance from adjacent cells, and // the horizontal crown/cover/lay/cross labels need ~1rem of vertical // clearance so they don't overlap into the next row. .my-sea-cross { gap: 1rem !important; } .my-sea-cross[data-spread="past-present-future"] { .sea-pos-crown, .sea-pos-cross, .sea-pos-lay { display: none; } } .my-sea-cross[data-spread="situation-action-outcome"] { .sea-pos-leave, .sea-pos-loom, .sea-pos-cross { display: none; } } .my-sea-cross[data-spread="mind-body-spirit"] { .sea-pos-leave, .sea-pos-cover, .sea-pos-cross { display: none; } } .my-sea-cross[data-spread="desire-obstacle-solution"] { .sea-pos-leave, .sea-pos-cover, .sea-pos-lay { display: none; } } // Celtic Cross variants (waite-smith / escape-velocity) — all positions // visible by default. No `display: none` overrides needed. // Position-name caption — re-appropriates the GRAVITY/LEVITY // `.sea-stack-name` typographic look (_card-deck.scss line 1557): // small uppercase letter-spaced w. a subtle scaleY stretch, // --terUser ink at 0.6 opacity. No polarity coloring — these are // spread-position labels, not deck identifiers. // // Labels live OUTSIDE the .sea-card-slot (sibling, inside the crucifix // cell or the cover/cross wrapper) so they survive SeaDeal._fillSlot's // `slot.innerHTML = …` clobber on draw. Each label is absolute- // positioned to nearly touch the slot's nearest border per the user- // locked spec: // crown / cover — above top border // lay / cross — below bottom border // leave — left of left border, rotated 90° CCW // loom — right of right border, rotated 90° CW .sea-pos-label { font-size: 0.65rem; letter-spacing: 0.08em; text-transform: uppercase; font-weight: 600; opacity: 1; color: rgba(var(--seciUser), 1); text-align: center; pointer-events: none; white-space: nowrap; position: absolute; z-index: 2; } // Cells need `position: relative` so absolute label children anchor // to them. `.sea-pos-core` already has `position: relative` per the // existing rule in _card-deck.scss line 1311; the other crucifix // cells need it added. .my-sea-cross .sea-crucifix-cell { position: relative; } // Above top border — overlaps slot's top edge by 0.1rem (per the // `.sea-stack-name` "tuck under" treatment in _card-deck.scss:1564). .sea-pos-crown > .sea-pos-label, .sea-pos-cover > .sea-pos-label { bottom: 100%; left: 50%; transform: translate(-50%, 0.1rem) scaleY(1.2); } // Cover + cross labels dim w. their slots — they sit on top of the // sig card so a vivid label would compete w. the sig at idle. Default // 0.25 opacity matches the slot's faint dotted-outline at idle; the // parent's :hover state (propagated up when the inside `.sea-card- // slot:hover` fires per CSS hover-ancestor rules) boosts to the // `.sea-pos-label` baseline 0.6, matching the slot's `--duoUser` mask // reveal. .sea-pos-cover > .sea-pos-label, .sea-pos-cross > .sea-pos-label { opacity: 0.5; transition: opacity 0.15s ease; } .sea-pos-cover:hover > .sea-pos-label, .sea-pos-cross:hover > .sea-pos-label { opacity: 1; } // Below bottom border — same `0.1rem` overlap but downward. .sea-pos-lay > .sea-pos-label, .sea-pos-cross > .sea-pos-label { top: 100%; left: 50%; transform: translate(-50%, -0.1rem) scaleY(1.2); } // Left of left border, rotated 90° CCW — text reads bottom-to-top. // `writing-mode: vertical-rl` puts text top-to-bottom (CW); a 180° // rotation flips it to read bottom-to-top (CCW), satisfying the user- // locked "Leave: counterclockwise" spec. // // `scaleX(1.2)` (instead of the horizontal labels' scaleY) widens the // character column (perpendicular to text-flow) — for vertical-rl // labels, that's the visible "width" the user noticed had been lost // at this angle. Without it, the rotated labels look squat. .sea-pos-leave > .sea-pos-label { right: 100%; top: 50%; writing-mode: vertical-rl; transform: translate(0.1rem, -50%) rotate(180deg) scaleX(1.2); } // Right of right border, rotated 90° CW — text reads top-to-bottom. // Native `writing-mode: vertical-rl` direction; no extra rotation. .sea-pos-loom > .sea-pos-label { left: 100%; top: 50%; writing-mode: vertical-rl; transform: translate(-0.1rem, -50%) scaleX(1.2); } // Section dividers inside the SPREAD combobox — labels "3-card spreads" // / "6-card spreads" separating the option groups. Styled to echo the // `.kit-bag-label` treatment (small uppercase underlined letter-spaced // --quaUser) but horizontal rather than vertical (kit-bag uses writing- // mode: vertical-rl; this is a flat dropdown). .sea-select-list .sea-select-divider { font-size: 0.55rem; text-transform: uppercase; text-decoration: underline; letter-spacing: 0.12em; color: rgba(var(--quaUser), 0.75); padding: 0.4rem 0.6rem 0.2rem; pointer-events: none; // not selectable; combobox.js skips it // (no role=option), but belt-and-braces // against accidental hover/click styles. list-style: none; } // Form col on my-sea — same DRY treatment as the gameroom sea-overlay // `.sea-form-col` (handled in _card-deck.scss) but sits next to the // picker's cross on a `--duoUser` page. Just constrain the width so it // doesn't fight the cross for horizontal space. .my-sea-form-col { flex: 0 0 16rem; max-width: 16rem; // Portal the SPREAD dropdown out of `.sea-form-main`'s overflow // clip — by default the gameroom's `.sea-form-main { overflow-y: // auto }` (from _card-deck.scss:1424) keeps the modal contents // scrollable, but for my-sea's much shorter form the dropdown gets // clipped instead of overlaying the LOCK HAND / DEL btns below. // Setting overflow visible here lets the absolute-positioned // `.sea-select-list` extend past the form area + sit "above // everything else" via its existing z-index: 100. .sea-form-main { overflow: visible; } // Portrait — split the form into two columns. LEFT carries the // SPREAD field (label + reversal hint + combobox) above the action // btns (AUTO DRAW / GATE VIEW + DEL); RIGHT carries the DECKS // section (label + GRAVITY/LEVITY stacks) spanning both rows. // Without this rearrange, on a phone-portrait viewport the stacked // form col runs off the bottom of the viewport — DECKS lives above // the action btns + everything below the fold (user-spec // 2026-05-21). `.sea-form-main` uses `display: contents` so its // `.sea-field` + `.sea-stacks` children act as direct grid items of // the form col despite the intermediate wrapper in the DOM. // // Selector chains `.sea-form-col.my-sea-form-col` to win against // `_card-deck.scss`'s base `.sea-form-col { display: flex; flex- // direction: column }` (same 1-class specificity; card-deck loads // AFTER gameboard in `core.scss`, so source order would otherwise // overrule my-sea's grid). Chained 2-class selector pulls // specificity ahead regardless of source order. @media (orientation: portrait) { &.sea-form-col { flex: 0 0 auto; max-width: none; width: 100%; display: grid; grid-template-columns: 1fr 1fr; grid-template-areas: "field stacks" "actions stacks"; column-gap: 1rem; row-gap: 0.5rem; align-items: start; .sea-form-main { display: contents; } .sea-field { grid-area: field; margin-bottom: 0; } .sea-stacks { grid-area: stacks; margin: 0; justify-content: center; } .sea-form-actions { grid-area: actions; align-self: end; padding-top: 0; } } } // Bump the dropdown z-index well above the picker's stacking ints // (cover z:3, cross z:4, modal stage z:9999 only opens on draw // anyway). 1000 sits above any in-page layer the user might be // interacting w. when they open the SPREAD picker. .sea-select-list { z-index: 1000; } // Portrait — open the SPREAD dropdown UPWARD instead of downward. // The portrait form col sits at the bottom of the viewport (below // the cross spread) w. the navbar/footer pinned beneath it, so the // default `top: 100%` dropdown extends BELOW the visible aperture // + the user can't scroll to it. Flipping to `bottom: 100%` makes // the list grow upward into the abundant green aperture above. // Chained `&.sea-form-col` to beat card-deck's later-loaded base // (per [[feedback-scss-import-order-specificity]]). @media (orientation: portrait) { &.sea-form-col .sea-select .sea-select-list { top: auto; bottom: 100%; margin: 0 0 0.2rem; } } } // LOCK HAND post-commit visual-lock: dim everything that mutates the // hand. `.btn-disabled` is the project's existing soft-disabled // treatment per [[feedback_btn_disabled_pointer_events]] — pointer- // events:none + opacity reduction. The deck stacks aren't buttons // themselves so we apply the class manually + the rule below ensures // they stop responding to clicks. .my-sea-picker--locked { .sea-deck-stack.btn-disabled { pointer-events: none; opacity: 0.5; cursor: default; } } // SPREAD combobox lock — applied after the first deposit so the user // can't switch spread mid-draw + scramble the in-progress hand's // position-to-card mapping. DEL releases the lock by removing this // class. Same `pointer-events: none` treatment as `.btn-disabled` per // [[feedback_btn_disabled_pointer_events]]. .sea-select.sea-select--locked { pointer-events: none; opacity: 0.5; cursor: default; } // ── Iter 4b: Brief banner + DEL guard portal ───────────────────────────────── // Both reuse shared chrome: the Brief is `.note-banner` from note.js // (portaled atop h2 w. Gaussian glass); the DEL guard is `#id_guard_portal` // from base.html (the same one the room gear-menu DEL uses, positioned // 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); } // `gap: 0` so qualifier sits directly above the title at the // title's own line-height (no flex gap between them); `.fan-card- // arcana` carries its own margin-top to restore breathing room // between title block and arcana label. .fan-card-face { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0; text-align: center; padding: 0 0.2rem; } // Qualifier + title share the same typography (per `_card-deck.scss` // convention at lines 568-572 / 1821-1823) — both bold, same size, // same wrap, same line-height. Color inherits from the slot's // polarity-driven `color:` (set on `--gravity` / `--levity`). .fan-card-qualifier, .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-qualifier:empty { display: none; } .fan-card-arcana { margin: calc(var(--slot-w) * 0.05) 0 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). `.fan-card-name`, // `.fan-card-qualifier`, `.fan-card-corner` + `.fan-card-arcana` all // pin `color: inherit` so they pick up the slot's polarity color // uniformly — the global `.fan-card-face .fan-card-name { color: // --terUser }` rule in `_card-deck.scss:376-383` loads AFTER gameboard // (per `core.scss` import order) and otherwise wins at matching 0,2,0 // specificity, stranding the title at --terUser while the qualifier // inherits the slot color. Explicit `inherit` here at 0,3,0 beats it. .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); .fan-card-corner { color: inherit; } .fan-card-qualifier { color: inherit; } .fan-card-name { color: inherit; } .fan-card-arcana { color: inherit; opacity: 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 { color: inherit; } .fan-card-qualifier { color: inherit; } .fan-card-name { color: inherit; } .fan-card-arcana { color: inherit; opacity: 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 — sibling of the slot inside the wrap, sits BELOW the slot // box (mirrors the my_sea.html picker's `.sea-pos-label` placement). // `margin-top: -0.15rem` crosses the slot's bottom border so the // label's top edge sits flush against it; `position: relative; // z-index: 2` keeps the label text rendering ATOP the slot's bottom // border (dotted for empty slots, solid for filled). .my-sea-slot-label { position: relative; z-index: 2; 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.3); 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; } }