PICK SEA Sprint C: sea stage card viewer — FLIP in, SPIN/FYI, deposit/re-expand — TDD

- sea.js: SeaDeal module — openStage() shows big card viewer w. flip-in animation;
  SPIN toggles stage-card--reversed; FYI shows energies/operations (Energy/Operation
  titles, PRV/NXT nav); backdrop click deposits card to slot; click deposited slot
  re-opens stage; resetHand() clears hand on DEL
- sea_deck view: adds name_group/name_title/reversal/keywords_upright/keywords_reversed/
  energies/operations to each card dict (full sig-select stage data set)
- _sea_overlay.html: data-sea-user-polarity attr; sea stage HTML (sig-stage-card shell
  + fan-card-face-upright/reversal structure + sea-stat-block w. SPIN/FYI/PRV/NXT);
  FLIP click calls SeaDeal.openStage(); _fillPos removed (sea.js handles slot fill);
  _reset calls SeaDeal.resetHand()
- room.html: sea.js included alongside sig-select.js
- _card-deck.scss: sea-stage layout (fixed overlay, backdrop, content row); sea-stage-card
  w. @keyframes sea-flip-in (3D rotateY perspective); sea-stat-block scoped styles
  incl. SPIN/FYI btns, stat faces, sig-info FYI panel
- SeaDealSpec.js: 20 Jasmine specs — openStage, SPIN, FYI, backdrop dismiss, slot re-expand

Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Disco DeDisco
2026-04-29 01:12:06 -04:00
parent 2af59b3a7f
commit 08aa4dc819
11 changed files with 1140 additions and 64 deletions

View File

@@ -402,6 +402,42 @@
// DOFF btn
&.btn-unequip {
color: rgba(var(--priId), 1);
border-color: rgba(var(--priId), 1);
background-color: rgba(var(--terId), 1);
box-shadow:
0.1rem 0.1rem 0.12rem rgba(var(--terId), 0.25),
0.12rem 0.12rem 0.25rem rgba(0, 0, 0, 0.25),
0.25rem 0.25rem 0.25rem rgba(var(--terId), 0.12)
;
&:hover {
text-shadow:
0.1rem 0.1rem 0.1rem rgba(0, 0, 0, 0.25),
0 0 1rem rgba(var(--priId), 1)
;
box-shadow:
0.12rem 0.12rem 0.5rem rgba(0, 0, 0, 0.25),
0 0 0.5rem rgba(var(--priId), 0.12)
;
}
&:active {
border: 0.18rem solid rgba(var(--priId), 1);
text-shadow:
-0.1rem -0.1rem 0.25rem rgba(0, 0, 0, 0.25),
0 0 0.12rem rgba(var(--priId), 1)
;
box-shadow:
-0.1rem -0.1rem 0.12rem rgba(var(--terId), 0.25),
-0.1rem -0.1rem 0.12rem rgba(0, 0, 0, 0.25),
0 0 0.5rem rgba(var(--priId), 0.12)
;
}
}
// FLIP btn
&.btn-reveal {
color: rgba(var(--priMe), 1);
border-color: rgba(var(--priMe), 1);
background-color: rgba(var(--terMe), 1);
@@ -436,42 +472,6 @@
}
}
// FLIP btn
&.btn-reveal {
color: rgba(var(--priCy), 1);
border-color: rgba(var(--priCy), 1);
background-color: rgba(var(--terCy), 1);
box-shadow:
0.1rem 0.1rem 0.12rem rgba(var(--terCy), 0.25),
0.12rem 0.12rem 0.25rem rgba(0, 0, 0, 0.25),
0.25rem 0.25rem 0.25rem rgba(var(--terCy), 0.12)
;
&:hover {
text-shadow:
0.1rem 0.1rem 0.1rem rgba(0, 0, 0, 0.25),
0 0 1rem rgba(var(--priCy), 1)
;
box-shadow:
0.12rem 0.12rem 0.5rem rgba(0, 0, 0, 0.25),
0 0 0.5rem rgba(var(--priCy), 0.12)
;
}
&:active {
border: 0.18rem solid rgba(var(--priCy), 1);
text-shadow:
-0.1rem -0.1rem 0.25rem rgba(0, 0, 0, 0.25),
0 0 0.12rem rgba(var(--priCy), 1)
;
box-shadow:
-0.1rem -0.1rem 0.12rem rgba(var(--terCy), 0.25),
-0.1rem -0.1rem 0.12rem rgba(0, 0, 0, 0.25),
0 0 0.5rem rgba(var(--priCy), 0.12)
;
}
}
// SPIN btn
&.btn-reverse {
color: rgba(var(--priCy), 1);

View File

@@ -606,6 +606,14 @@ html:has(.sig-backdrop) {
// Polarity qualifier: same colour as the card title in this context
.sig-qualifier-above,
.sig-qualifier-below { color: rgba(var(--quiUser), 1); }
// Upright + reversal title glow — levity
.sig-stage-card .fan-card-name,
.sig-stage-card .sig-qualifier-above,
.sig-stage-card .sig-qualifier-below,
.sig-stage-card .fan-card-reversal-name,
.sig-stage-card .fan-card-reversal-qualifier {
text-shadow: 0 1px 1px rgba(0,0,0,0.55), 0 0 0.55rem rgba(var(--ninUser), 0.7);
}
// card-ref spans inside the caution tooltip — must match the base rule's
// .sig-stat-block .sig-info-effect .card-ref specificity (0,3,0) to win.
.sig-info-effect .card-ref { color: rgba(var(--quiUser), 1); }
@@ -624,6 +632,14 @@ html:has(.sig-backdrop) {
// Polarity qualifier: terUser for gravity (quiUser is levity's equivalent)
.sig-qualifier-above,
.sig-qualifier-below { color: rgba(var(--terUser), 1); }
// Upright + reversal title glow — gravity
.sig-stage-card .fan-card-name,
.sig-stage-card .sig-qualifier-above,
.sig-stage-card .sig-qualifier-below,
.sig-stage-card .fan-card-reversal-name,
.sig-stage-card .fan-card-reversal-qualifier {
text-shadow: 1px 1px 0 rgba(0,0,0,1), 0 0 0.25rem rgba(var(--ninUser), 0.25);
}
// Cursor colours live in .sig-cursor-float[data-role] rules (portal elements)
}
@@ -785,7 +801,9 @@ $sea-card-h: 6.5rem;
.sea-card-slot {
width: $sea-card-w;
height: $sea-card-h;
border: 0.15rem dashed rgba(var(--terUser), 0.45);
background-color: rgba(var(--duoUser), 1);
border: 0.15rem dashed rgba(var(--terUser), 1);
box-shadow: 0 0 2px rgba(var(--priUser), 0.5);
border-radius: 0.3rem;
display: flex;
align-items: center;
@@ -843,13 +861,16 @@ $sea-card-h: 6.5rem;
.sea-pos-cross .sea-card-slot { transform: rotate(90deg); }
// Sig card in center slot — compact rank + icon display
// Sig card in center slot — compact rank + icon display; tilted CCW so Cover slot peeks through
.sea-sig-card {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 0.2rem;
transform: rotate(-5deg);
position: relative;
z-index: 2;
.fan-corner-rank {
font-size: 1.2rem;
@@ -975,8 +996,10 @@ $sea-card-h: 6.5rem;
.sea-stack-ok {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
left: 0;
right: 0;
margin: 0 auto;
transform: translateY(-50%);
z-index: 5;
}
@@ -1033,11 +1056,154 @@ $_glow-gravity: 0 0 0.8rem 0.15rem rgba(var(--quaUser), 0.6);
// NVM button — same positioning as .natus-modal-wrap > .btn-cancel
.sea-modal-wrap > .btn-cancel {
position: absolute;
top: -0.75rem;
right: -0.75rem;
top: -1rem;
right: -1rem;
z-index: 10;
}
// ── Sea stage — big card viewer ───────────────────────────────────────────────
.sea-stage {
position: fixed;
inset: 0;
z-index: 200;
display: flex;
align-items: center;
justify-content: center;
}
.sea-stage-backdrop {
position: absolute;
inset: 0;
cursor: pointer;
}
.sea-stage-content {
position: relative;
z-index: 1;
display: flex;
flex-direction: row;
align-items: flex-end;
gap: 0.75rem;
padding: 1.5rem;
}
// Stage card — size matches sig-select stage (--sig-card-w driven by inline style)
.sea-stage-card {
flex-shrink: 0;
width: var(--sig-card-w, 140px);
height: auto;
aspect-ratio: 5 / 8;
border-radius: 0.5rem;
background: rgba(var(--priUser), 1);
border: 0.15rem solid rgba(var(--secUser), 0.6);
display: flex;
flex-direction: column;
position: relative;
padding: 0.25rem;
overflow: hidden;
transform-style: preserve-3d;
// Flip-in animation when stage opens
&--shown {
animation: sea-flip-in 0.35s ease forwards;
}
.fan-card-corner--tl,
.fan-card-corner--br {
display: flex;
flex-direction: column;
align-items: center;
line-height: 1.1;
gap: 0.1rem;
.fan-corner-rank { font-size: calc(var(--sig-card-w, 140px) * 0.133); font-weight: 700; }
i { font-size: calc(var(--sig-card-w, 140px) * 0.1); }
}
.fan-card-face {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
padding: 0.25rem 0.15rem;
gap: 0.2rem;
.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, 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-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-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; }
}
&.stage-card--reversed {
transform: rotate(180deg);
.fan-card-reversal-qualifier,
.fan-card-reversal-name { opacity: 1; }
.fan-card-name,
.sig-qualifier-above,
.sig-qualifier-below { opacity: 0.25; }
}
}
@keyframes sea-flip-in {
0% { transform: perspective(600px) rotateY(-90deg) scale(0.4); opacity: 0; }
60% { transform: perspective(600px) rotateY(8deg) scale(1.03); opacity: 1; }
100% { transform: perspective(600px) rotateY(0deg) scale(1); opacity: 1; }
}
// Sea stat block — reuses sig-select stat-block sizing, scoped to sea-stage
.sea-stage-content .sea-stat-block {
flex: 0 0 auto;
width: var(--sig-card-w, 140px);
height: calc(var(--sig-card-w, 140px) * 8 / 5);
background: rgba(var(--priUser), 0.85);
border-radius: 0.4rem;
border: 0.1rem solid rgba(var(--terUser), 0.15);
position: relative;
display: block;
.sea-spin-btn { position: absolute; top: -1rem; right: -1rem; margin: 0; z-index: 50; }
.sea-fyi-btn { position: absolute; top: 1.25rem; right: -1rem; margin: 0; z-index: 50; }
.stat-face { display: none; padding: calc(var(--sig-card-w, 140px) * 0.37) calc(var(--sig-card-w, 140px) * 0.1) calc(var(--sig-card-w, 140px) * 0.08); }
.stat-face--upright { display: block; }
&.is-reversed { .stat-face--upright { display: none; } .stat-face--reversed { display: block; } }
.stat-face-label { font-size: calc(var(--sig-card-w, 140px) * 0.063); text-transform: uppercase; letter-spacing: 0.09em; opacity: 0.4; margin: 0 0 calc(var(--sig-card-w, 140px) * 0.07); }
.stat-keywords { list-style: none; padding: 0; margin: 0;
li { font-size: calc(var(--sig-card-w, 140px) * 0.083); padding: calc(var(--sig-card-w, 140px) * 0.042) 0; opacity: 0.85; border-bottom: 0.05rem solid rgba(var(--terUser), 0.12); &:last-child { border-bottom: none; } }
}
.sig-info {
position: absolute;
inset: 0;
z-index: 60;
background-color: rgba(var(--tooltip-bg), 0.6);
backdrop-filter: blur(6px);
border-radius: 0.4rem;
border: 0.1rem solid rgba(var(--priYl), 0.35);
padding: 0.75rem;
flex-direction: column;
gap: 0.4rem;
overflow-y: auto;
display: none;
&[style*="display"]:not([style*="none"]) { display: flex; }
}
.sea-fyi-prev,
.sea-fyi-next { display: inline-flex; position: absolute; bottom: -1rem; margin: 0; z-index: 70; }
.sea-fyi-prev { left: -1rem; }
.sea-fyi-next { right: -1rem; }
}
@media (orientation: landscape) {
html.sea-open body .container .navbar,
html.sea-open body #id_footer {

View File

@@ -57,7 +57,8 @@ html:has(.gate-backdrop) {
html:has(.gate-backdrop) #id_aperture_fill,
html:has(.sig-backdrop) #id_aperture_fill,
html:has(.role-select-backdrop) #id_aperture_fill {
html:has(.role-select-backdrop) #id_aperture_fill,
html.sea-open #id_aperture_fill {
opacity: 1;
}

View File

@@ -0,0 +1,292 @@
describe("SeaDeal", () => {
let testDiv, overlay, stage, stageCard, statBlock;
const CARD = {
id: 99, name: "Queen of Crowns",
arcana: "MIDDLE", suit: "CROWNS", number: 13,
corner_rank: "Q", suit_icon: "fa-crown",
name_group: "", name_title: "Queen of Crowns",
levity_qualifier: "Elevated", gravity_qualifier: "Graven",
reversal: "Vacant",
keywords_upright: ["nurturing", "practical", "abundance"],
keywords_reversed: ["financial dependence", "smothering"],
energies: [{ type: "LIBIDO", effect: "Energy entry." }],
operations: [{ type: "COVER", effect: "Operation entry." }],
};
function makeFixture({ polarity = "levity" } = {}) {
testDiv = document.createElement("div");
testDiv.innerHTML = `
<div id="id_sea_overlay" data-sea-user-polarity="${polarity}">
<!-- Cross grid (simplified) -->
<div class="sea-cross">
<div class="sea-cross-cell sea-pos-crown">
<div class="sea-card-slot sea-card-slot--empty"></div>
</div>
<div class="sea-cross-cell sea-pos-past">
<div class="sea-card-slot sea-card-slot--empty"></div>
</div>
<div class="sea-cross-cell sea-pos-center">
<div class="sea-sig-card"></div>
<div class="sea-pos-cover">
<div class="sea-card-slot sea-card-slot--empty"></div>
</div>
<div class="sea-pos-cross">
<div class="sea-card-slot sea-card-slot--empty"></div>
</div>
</div>
<div class="sea-cross-cell sea-pos-future">
<div class="sea-card-slot sea-card-slot--empty"></div>
</div>
<div class="sea-cross-cell sea-pos-root">
<div class="sea-card-slot sea-card-slot--empty"></div>
</div>
</div>
<!-- Sea stage (big card viewer) -->
<div class="sea-stage" id="id_sea_stage" style="display:none">
<div class="sea-stage-backdrop"></div>
<div class="sea-stage-content">
<div class="sig-stage-card sea-stage-card" style="--sig-card-w:140px">
<div class="fan-card-corner fan-card-corner--tl">
<span class="fan-corner-rank"></span>
<i class="fa-solid stage-suit-icon" style="display:none"></i>
</div>
<div class="fan-card-face">
<div class="fan-card-face-upright">
<p class="fan-card-name-group"></p>
<p class="sig-qualifier-above"></p>
<h3 class="fan-card-name"></h3>
<p class="sig-qualifier-below"></p>
</div>
<p class="fan-card-arcana"></p>
<div class="fan-card-face-reversal">
<p class="fan-card-reversal-name"></p>
<p class="fan-card-reversal-qualifier"></p>
</div>
</div>
<div class="fan-card-corner fan-card-corner--br">
<span class="fan-corner-rank"></span>
<i class="fa-solid stage-suit-icon" style="display:none"></i>
</div>
</div>
<div class="sig-stat-block sea-stat-block">
<button class="btn btn-reverse sea-spin-btn" type="button">SPIN</button>
<button class="btn btn-info sea-fyi-btn" type="button">FYI</button>
<div class="stat-face stat-face--upright">
<p class="stat-face-label">Emanation</p>
<ul class="stat-keywords" id="id_sea_stat_upright"></ul>
</div>
<div class="stat-face stat-face--reversed">
<p class="stat-face-label">Reversal</p>
<ul class="stat-keywords" id="id_sea_stat_reversed"></ul>
</div>
<div class="sig-info" id="id_sea_fyi_panel" style="display:none">
<div class="sig-info-header">
<h4 class="sig-info-title"></h4>
<p class="sig-info-type"></p>
</div>
<p class="sig-info-effect"></p>
<span class="sig-info-index"></span>
</div>
<button class="btn btn-nav-left sea-fyi-prev" type="button">PRV</button>
<button class="btn btn-nav-right sea-fyi-next" type="button">NXT</button>
</div>
</div>
</div>
</div>
`;
document.body.appendChild(testDiv);
overlay = testDiv.querySelector("#id_sea_overlay");
stage = testDiv.querySelector("#id_sea_stage");
stageCard = testDiv.querySelector(".sea-stage-card");
statBlock = testDiv.querySelector(".sea-stat-block");
SeaDeal._testInit();
}
afterEach(() => {
if (testDiv) testDiv.remove();
// Purge any stale overlays left by tests that called makeFixture() twice
document.querySelectorAll('#id_sea_overlay').forEach(el => el.remove());
});
// ── openStage ────────────────────────────────────────────────────────── //
describe("openStage()", () => {
beforeEach(() => makeFixture());
it("makes #id_sea_stage visible", () => {
SeaDeal.openStage(CARD, ".sea-pos-cover", true);
expect(stage.style.display).not.toBe("none");
});
it("populates corner rank on stage card", () => {
SeaDeal.openStage(CARD, ".sea-pos-cover", true);
const rank = stageCard.querySelector(".fan-card-corner--tl .fan-corner-rank");
expect(rank.textContent).toBe("Q");
});
it("shows suit icon on stage card", () => {
SeaDeal.openStage(CARD, ".sea-pos-cover", true);
const icon = stageCard.querySelector(".fan-card-corner--tl .stage-suit-icon");
expect(icon.style.display).not.toBe("none");
expect(icon.classList.contains("fa-crown")).toBe(true);
});
it("populates upright card name for non-major", () => {
SeaDeal.openStage(CARD, ".sea-pos-cover", true);
expect(stageCard.querySelector(".fan-card-name").textContent).toBe("Queen of Crowns");
});
it("puts levity qualifier in qualifier-above for non-major", () => {
SeaDeal.openStage(CARD, ".sea-pos-cover", true);
expect(stageCard.querySelector(".sig-qualifier-above").textContent).toBe("Elevated");
});
it("puts gravity qualifier in qualifier-above for non-major gravity", () => {
// Re-init with gravity polarity (no double-append; beforeEach already ran)
overlay.dataset.seaUserPolarity = "gravity";
SeaDeal._testInit();
stageCard = testDiv.querySelector(".sea-stage-card");
SeaDeal.openStage(CARD, ".sea-pos-cover", false);
expect(stageCard.querySelector(".sig-qualifier-above").textContent).toBe("Graven");
});
it("puts reversal word in reversal-qualifier slot", () => {
SeaDeal.openStage(CARD, ".sea-pos-cover", true);
expect(stageCard.querySelector(".fan-card-reversal-qualifier").textContent).toBe("Vacant");
});
it("populates upright keywords in stat block", () => {
SeaDeal.openStage(CARD, ".sea-pos-cover", true);
const items = testDiv.querySelectorAll("#id_sea_stat_upright li");
expect(items.length).toBe(3);
expect(items[0].textContent).toBe("nurturing");
});
it("populates reversed keywords in stat block", () => {
SeaDeal.openStage(CARD, ".sea-pos-cover", true);
const items = testDiv.querySelectorAll("#id_sea_stat_reversed li");
expect(items.length).toBe(2);
});
it("fills the target position slot", () => {
SeaDeal.openStage(CARD, ".sea-pos-cover", true);
const slot = testDiv.querySelector(".sea-pos-cover .sea-card-slot");
expect(slot.classList.contains("sea-card-slot--filled")).toBe(true);
});
it("resets SPIN to upright when opening a new card", () => {
SeaDeal.openStage(CARD, ".sea-pos-cover", true);
stageCard.classList.add("stage-card--reversed");
statBlock.classList.add("is-reversed");
SeaDeal.openStage(CARD, ".sea-pos-cross", true);
expect(stageCard.classList.contains("stage-card--reversed")).toBe(false);
expect(statBlock.classList.contains("is-reversed")).toBe(false);
});
});
// ── SPIN in sea stage ─────────────────────────────────────────────────── //
describe("SPIN btn in sea stage", () => {
beforeEach(() => {
makeFixture();
SeaDeal.openStage(CARD, ".sea-pos-cover", true);
});
it("toggles is-reversed on stat block", () => {
testDiv.querySelector(".sea-spin-btn").dispatchEvent(new MouseEvent("click", { bubbles: true }));
expect(statBlock.classList.contains("is-reversed")).toBe(true);
});
it("toggles stage-card--reversed on stage card", () => {
testDiv.querySelector(".sea-spin-btn").dispatchEvent(new MouseEvent("click", { bubbles: true }));
expect(stageCard.classList.contains("stage-card--reversed")).toBe(true);
});
it("second SPIN click restores upright", () => {
const btn = testDiv.querySelector(".sea-spin-btn");
btn.dispatchEvent(new MouseEvent("click", { bubbles: true }));
btn.dispatchEvent(new MouseEvent("click", { bubbles: true }));
expect(statBlock.classList.contains("is-reversed")).toBe(false);
});
});
// ── FYI in sea stage ──────────────────────────────────────────────────── //
describe("FYI btn in sea stage", () => {
beforeEach(() => {
makeFixture();
SeaDeal.openStage(CARD, ".sea-pos-cover", true);
});
it("FYI click shows the info panel", () => {
testDiv.querySelector(".sea-fyi-btn").dispatchEvent(new MouseEvent("click", { bubbles: true }));
expect(testDiv.querySelector("#id_sea_fyi_panel").style.display).not.toBe("none");
});
it("shows first energy entry title as 'Energy'", () => {
testDiv.querySelector(".sea-fyi-btn").dispatchEvent(new MouseEvent("click", { bubbles: true }));
expect(testDiv.querySelector(".sig-info-title").textContent).toBe("Energy");
});
it("shows first entry type", () => {
testDiv.querySelector(".sea-fyi-btn").dispatchEvent(new MouseEvent("click", { bubbles: true }));
expect(testDiv.querySelector(".sig-info-type").textContent).toBe("LIBIDO");
});
it("NXT advances to operation entry", () => {
testDiv.querySelector(".sea-fyi-btn").dispatchEvent(new MouseEvent("click", { bubbles: true }));
testDiv.querySelector(".sea-fyi-next").dispatchEvent(new MouseEvent("click", { bubbles: true }));
expect(testDiv.querySelector(".sig-info-title").textContent).toBe("Operation");
expect(testDiv.querySelector(".sig-info-type").textContent).toBe("COVER");
});
});
// ── Backdrop dismiss ──────────────────────────────────────────────────── //
describe("stage backdrop click", () => {
beforeEach(() => {
makeFixture();
SeaDeal.openStage(CARD, ".sea-pos-cover", true);
});
it("hides the sea stage", () => {
testDiv.querySelector(".sea-stage-backdrop").dispatchEvent(new MouseEvent("click", { bubbles: true }));
expect(stage.style.display).toBe("none");
});
it("leaves the slot filled after dismiss", () => {
testDiv.querySelector(".sea-stage-backdrop").dispatchEvent(new MouseEvent("click", { bubbles: true }));
const slot = testDiv.querySelector(".sea-pos-cover .sea-card-slot");
expect(slot.classList.contains("sea-card-slot--filled")).toBe(true);
});
});
// ── Re-open from deposited slot ───────────────────────────────────────── //
describe("clicking a deposited slot", () => {
beforeEach(() => {
makeFixture();
SeaDeal.openStage(CARD, ".sea-pos-cover", true);
// Dismiss first
testDiv.querySelector(".sea-stage-backdrop").dispatchEvent(new MouseEvent("click", { bubbles: true }));
});
it("re-opens the sea stage", () => {
expect(stage.style.display).toBe("none");
const slot = testDiv.querySelector(".sea-pos-cover .sea-card-slot");
slot.dispatchEvent(new MouseEvent("click", { bubbles: true }));
expect(stage.style.display).not.toBe("none");
});
it("re-populates stage with the same card rank", () => {
const slot = testDiv.querySelector(".sea-pos-cover .sea-card-slot");
slot.dispatchEvent(new MouseEvent("click", { bubbles: true }));
const rank = stageCard.querySelector(".fan-card-corner--tl .fan-corner-rank");
expect(rank.textContent).toBe("Q");
});
});
});

View File

@@ -22,6 +22,7 @@
<script src="RoleSelectSpec.js"></script>
<script src="TraySpec.js"></script>
<script src="SigSelectSpec.js"></script>
<script src="SeaDealSpec.js"></script>
<script src="NatusWheelSpec.js"></script>
<script src="NoteSpec.js"></script>
<script src="NotePageSpec.js"></script>
@@ -32,6 +33,7 @@
<script src="/static/apps/epic/role-select.js"></script>
<script src="/static/apps/epic/tray.js"></script>
<script src="/static/apps/epic/sig-select.js"></script>
<script src="/static/apps/epic/sea.js"></script>
<script src="/static/apps/gameboard/d3.min.js"></script>
<script src="/static/apps/gameboard/natus-wheel.js"></script>
<!-- Jasmine env config (optional) -->