SIG SELECT: FLIP→SPIN rename; stage-card reversal JS — TDD

- Template: FLIP btn label → SPIN; .btn-reverse class + .sig-flip-btn kept
- _button-pad.scss: .btn-reverse restyled w. cyan (--priCy/--terCy); .btn-tip
  removed; button section comments added (BIG, BYE, FYI, OK, SPIN etc.)
- sig-select.js: SPIN/FLIP handler also toggles .stage-card--reversed on
  stageCard; updateStage() populates .fan-card-reversal-name (data-reversal)
  + .fan-card-reversal-qualifier (polarity qualifier); resets .stage-card--reversed
  on each new hover — TDD
- SigSelectSpec.js: SPIN card animation describe block (7 specs); spec
  descriptions updated FLIP→SPIN; fixture gains reversal elements +
  data-reversal attr; 235 Jasmine specs green

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-28 16:51:53 -04:00
parent 759ce8d3e4
commit 0522b5c126
5 changed files with 196 additions and 32 deletions

View File

@@ -127,8 +127,13 @@ var SigSelect = (function () {
stageCard.querySelector('.sig-qualifier-above').textContent = isMajor ? '' : qualifier; stageCard.querySelector('.sig-qualifier-above').textContent = isMajor ? '' : qualifier;
stageCard.querySelector('.sig-qualifier-below').textContent = isMajor ? qualifier : ''; stageCard.querySelector('.sig-qualifier-below').textContent = isMajor ? qualifier : '';
// Reversed face — same qualifier, polarity-resolved reversal title
stageCard.querySelector('.fan-card-reversal-qualifier').textContent = qualifier;
stageCard.querySelector('.fan-card-reversal-name').textContent = cardEl.dataset.reversal || '';
// Populate stat block keyword faces and reset to upright // Populate stat block keyword faces and reset to upright
statBlock.classList.remove('is-reversed'); statBlock.classList.remove('is-reversed');
stageCard.classList.remove('stage-card--reversed');
_populateKeywordList( _populateKeywordList(
statBlock.querySelector('#id_stat_keywords_upright'), statBlock.querySelector('#id_stat_keywords_upright'),
cardEl.dataset.keywordsUpright cardEl.dataset.keywordsUpright
@@ -613,6 +618,7 @@ var SigSelect = (function () {
_flipBtn.addEventListener('click', function () { _flipBtn.addEventListener('click', function () {
if (_flipBtn.classList.contains('btn-disabled')) return; if (_flipBtn.classList.contains('btn-disabled')) return;
statBlock.classList.toggle('is-reversed'); statBlock.classList.toggle('is-reversed');
stageCard.classList.toggle('stage-card--reversed');
}); });
cautionEl = stage.querySelector('.sig-caution-tooltip'); cautionEl = stage.querySelector('.sig-caution-tooltip');

View File

@@ -22,9 +22,11 @@ describe("SigSelect", () => {
<p class="sig-qualifier-below"></p> <p class="sig-qualifier-below"></p>
<p class="fan-card-arcana"></p> <p class="fan-card-arcana"></p>
<p class="fan-card-correspondence"></p> <p class="fan-card-correspondence"></p>
<p class="fan-card-reversal-qualifier"></p>
<p class="fan-card-reversal-name"></p>
</div> </div>
<div class="sig-stat-block"> <div class="sig-stat-block">
<button class="btn btn-reverse sig-flip-btn" type="button">FLIP</button> <button class="btn btn-reverse sig-flip-btn" type="button">SPIN</button>
<button class="btn btn-caution sig-caution-btn" type="button">!!</button> <button class="btn btn-caution sig-caution-btn" type="button">!!</button>
<div class="stat-face stat-face--upright"> <div class="stat-face stat-face--upright">
<p class="stat-face-label">Upright</p> <p class="stat-face-label">Upright</p>
@@ -60,7 +62,8 @@ describe("SigSelect", () => {
data-keywords-reversed="no direction,disregard for consequences" data-keywords-reversed="no direction,disregard for consequences"
data-cautions="${cardCautions.replace(/"/g, '&quot;')}" data-cautions="${cardCautions.replace(/"/g, '&quot;')}"
data-levity-qualifier="Elevated" data-levity-qualifier="Elevated"
data-gravity-qualifier="Graven"> data-gravity-qualifier="Graven"
data-reversal="Territoriality">
<div class="fan-card-corner fan-card-corner--tl"> <div class="fan-card-corner fan-card-corner--tl">
<span class="fan-corner-rank">K</span> <span class="fan-corner-rank">K</span>
</div> </div>
@@ -321,7 +324,7 @@ describe("SigSelect", () => {
expect(cautionEffect.innerHTML).toContain("First"); expect(cautionEffect.innerHTML).toContain("First");
}); });
it("opening caution adds .btn-disabled and swaps labels to ×", () => { it("opening caution adds .btn-disabled and swaps SPIN/FYI labels to ×", () => {
openCaution(); openCaution();
var flipBtn = testDiv.querySelector(".sig-flip-btn"); var flipBtn = testDiv.querySelector(".sig-flip-btn");
expect(flipBtn.classList.contains("btn-disabled")).toBe(true); expect(flipBtn.classList.contains("btn-disabled")).toBe(true);
@@ -330,7 +333,7 @@ describe("SigSelect", () => {
expect(cautionBtn.textContent).toBe("\u00D7"); expect(cautionBtn.textContent).toBe("\u00D7");
}); });
it("closing caution removes .btn-disabled and restores original labels", () => { it("closing caution removes .btn-disabled and restores SPIN/FYI labels", () => {
var flipBtn = testDiv.querySelector(".sig-flip-btn"); var flipBtn = testDiv.querySelector(".sig-flip-btn");
var origFlip = flipBtn.textContent; var origFlip = flipBtn.textContent;
var origCaution = cautionBtn.textContent; var origCaution = cautionBtn.textContent;
@@ -348,7 +351,7 @@ describe("SigSelect", () => {
expect(testDiv.querySelector(".sig-stage").classList.contains("sig-caution-open")).toBe(false); expect(testDiv.querySelector(".sig-stage").classList.contains("sig-caution-open")).toBe(false);
}); });
it("FLIP click when caution open (btn-disabled) does nothing", () => { it("SPIN click when caution open (btn-disabled) does nothing", () => {
openCaution(); openCaution();
var flipBtn = testDiv.querySelector(".sig-flip-btn"); var flipBtn = testDiv.querySelector(".sig-flip-btn");
flipBtn.dispatchEvent(new MouseEvent("click", { bubbles: true })); flipBtn.dispatchEvent(new MouseEvent("click", { bubbles: true }));
@@ -357,9 +360,9 @@ describe("SigSelect", () => {
}); });
}); });
// ── Stat block: keyword population and FLIP toggle ────────────────── // // ── Stat block: keyword population and SPIN toggle ────────────────── //
describe("stat block and FLIP", () => { describe("stat block and SPIN", () => {
beforeEach(() => makeFixture()); beforeEach(() => makeFixture());
it("populates upright keywords when a card is hovered", () => { it("populates upright keywords when a card is hovered", () => {
@@ -379,14 +382,14 @@ describe("SigSelect", () => {
expect(items[1].textContent).toBe("disregard for consequences"); expect(items[1].textContent).toBe("disregard for consequences");
}); });
it("FLIP click adds .is-reversed to the stat block", () => { it("SPIN click adds .is-reversed to the stat block", () => {
card.dispatchEvent(new MouseEvent("mouseenter", { bubbles: true })); card.dispatchEvent(new MouseEvent("mouseenter", { bubbles: true }));
var flipBtn = statBlock.querySelector(".sig-flip-btn"); var flipBtn = statBlock.querySelector(".sig-flip-btn");
flipBtn.dispatchEvent(new MouseEvent("click", { bubbles: true })); flipBtn.dispatchEvent(new MouseEvent("click", { bubbles: true }));
expect(statBlock.classList.contains("is-reversed")).toBe(true); expect(statBlock.classList.contains("is-reversed")).toBe(true);
}); });
it("second FLIP click removes .is-reversed", () => { it("second SPIN click removes .is-reversed", () => {
card.dispatchEvent(new MouseEvent("mouseenter", { bubbles: true })); card.dispatchEvent(new MouseEvent("mouseenter", { bubbles: true }));
var flipBtn = statBlock.querySelector(".sig-flip-btn"); var flipBtn = statBlock.querySelector(".sig-flip-btn");
flipBtn.dispatchEvent(new MouseEvent("click", { bubbles: true })); flipBtn.dispatchEvent(new MouseEvent("click", { bubbles: true }));
@@ -416,6 +419,76 @@ describe("SigSelect", () => {
}); });
}); });
// ── SPIN card animation — stage-card reversed state ──────────────────── //
describe("SPIN card animation", () => {
function hover() {
card.dispatchEvent(new MouseEvent("mouseenter", { bubbles: true }));
}
it("SPIN click adds .stage-card--reversed to the stage card", () => {
makeFixture();
hover();
statBlock.querySelector(".sig-flip-btn")
.dispatchEvent(new MouseEvent("click", { bubbles: true }));
expect(stageCard.classList.contains("stage-card--reversed")).toBe(true);
});
it("second SPIN click removes .stage-card--reversed", () => {
makeFixture();
hover();
var flipBtn = statBlock.querySelector(".sig-flip-btn");
flipBtn.dispatchEvent(new MouseEvent("click", { bubbles: true }));
flipBtn.dispatchEvent(new MouseEvent("click", { bubbles: true }));
expect(stageCard.classList.contains("stage-card--reversed")).toBe(false);
});
it("hovering a new card resets .stage-card--reversed", () => {
makeFixture();
hover();
statBlock.querySelector(".sig-flip-btn")
.dispatchEvent(new MouseEvent("click", { bubbles: true }));
expect(stageCard.classList.contains("stage-card--reversed")).toBe(true);
card.dispatchEvent(new MouseEvent("mouseleave", { bubbles: true }));
card.dispatchEvent(new MouseEvent("mouseenter", { bubbles: true }));
expect(stageCard.classList.contains("stage-card--reversed")).toBe(false);
});
it("updateStage() populates fan-card-reversal-name from data-reversal", () => {
makeFixture();
card.dataset.reversal = "Territoriality";
hover();
expect(stageCard.querySelector(".fan-card-reversal-name").textContent)
.toBe("Territoriality");
});
it("updateStage() populates fan-card-reversal-qualifier with levity qualifier", () => {
makeFixture({ polarity: "levity", userRole: "PC" });
hover();
expect(stageCard.querySelector(".fan-card-reversal-qualifier").textContent)
.toBe("Elevated");
});
it("updateStage() populates fan-card-reversal-qualifier with gravity qualifier", () => {
makeFixture({ polarity: "gravity", userRole: "BC" });
hover();
expect(stageCard.querySelector(".fan-card-reversal-qualifier").textContent)
.toBe("Graven");
});
it("hovering a card without data-reversal clears the reversal name", () => {
makeFixture();
card.dataset.reversal = "Territoriality";
hover();
card.dispatchEvent(new MouseEvent("mouseleave", { bubbles: true }));
delete card.dataset.reversal;
card.dispatchEvent(new MouseEvent("mouseenter", { bubbles: true }));
// reversal-name clears because data-reversal is gone;
// reversal-qualifier stays (it always mirrors the polarity qualifier)
expect(stageCard.querySelector(".fan-card-reversal-name").textContent).toBe("");
});
});
// ── WS cursor hover (applyHover) ──────────────────────────────────────── // // ── WS cursor hover (applyHover) ──────────────────────────────────────── //
// //
// Fixture polarity = levity, userRole = PC. // Fixture polarity = levity, userRole = PC.

View File

@@ -24,6 +24,7 @@
border: 0.18rem solid rgba(var(--priUser), 1); border: 0.18rem solid rgba(var(--priUser), 1);
} }
// BIG btn
&.btn-primary { &.btn-primary {
width: 4rem; width: 4rem;
height: 4rem; height: 4rem;
@@ -70,6 +71,7 @@
} }
} }
// BYE btn
&.btn-abandon { &.btn-abandon {
color: rgba(var(--priBl), 1); color: rgba(var(--priBl), 1);
border-color: rgba(var(--priBl), 1); border-color: rgba(var(--priBl), 1);
@@ -105,6 +107,7 @@
} }
} }
// DEL btn
&.btn-cancel { &.btn-cancel {
color: rgba(var(--priOr), 1); color: rgba(var(--priOr), 1);
border-color: rgba(var(--priOr), 1); border-color: rgba(var(--priOr), 1);
@@ -139,6 +142,7 @@
} }
} }
// FYI btn
&.btn-caution { &.btn-caution {
color: rgba(var(--priYl), 1); color: rgba(var(--priYl), 1);
border-color: rgba(var(--priYl), 1); border-color: rgba(var(--priYl), 1);
@@ -174,6 +178,7 @@
} }
} }
// OK btn
&.btn-confirm { &.btn-confirm {
color: rgba(var(--priGn), 1); color: rgba(var(--priGn), 1);
border-color: rgba(var(--priGn), 1); border-color: rgba(var(--priGn), 1);
@@ -209,6 +214,7 @@
} }
} }
// DEL btn
&.btn-danger { &.btn-danger {
color: rgba(var(--priRd), 1); color: rgba(var(--priRd), 1);
background-color: rgba(var(--terRd), 1); background-color: rgba(var(--terRd), 1);
@@ -286,6 +292,7 @@
font-size: 0.75rem; // 0.63rem × 1.2 font-size: 0.75rem; // 0.63rem × 1.2
} }
// PRV btn
&.btn-nav-left { &.btn-nav-left {
color: rgba(var(--priFs), 1); color: rgba(var(--priFs), 1);
border-color: rgba(var(--priFs), 1); border-color: rgba(var(--priFs), 1);
@@ -321,6 +328,7 @@
} }
} }
// NXT btn
&.btn-nav-right { &.btn-nav-right {
color: rgba(var(--priLm), 1); color: rgba(var(--priLm), 1);
border-color: rgba(var(--priLm), 1); border-color: rgba(var(--priLm), 1);
@@ -356,6 +364,7 @@
} }
} }
// DON btn
&.btn-equip { &.btn-equip {
color: rgba(var(--priTk), 1); color: rgba(var(--priTk), 1);
border-color: rgba(var(--priTk), 1); border-color: rgba(var(--priTk), 1);
@@ -391,6 +400,7 @@
} }
} }
// DOFF btn
&.btn-unequip { &.btn-unequip {
color: rgba(var(--priMe), 1); color: rgba(var(--priMe), 1);
border-color: rgba(var(--priMe), 1); border-color: rgba(var(--priMe), 1);
@@ -426,7 +436,8 @@
} }
} }
&.btn-reverse { // FLIP btn
&.btn-reveal {
color: rgba(var(--priCy), 1); color: rgba(var(--priCy), 1);
border-color: rgba(var(--priCy), 1); border-color: rgba(var(--priCy), 1);
background-color: rgba(var(--terCy), 1); background-color: rgba(var(--terCy), 1);
@@ -461,37 +472,38 @@
} }
} }
&.btn-tip { // SPIN btn
color: rgba(var(--priLm), 1); &.btn-reverse {
border-color: rgba(var(--priLm), 1); color: rgba(var(--priCy), 1);
background-color: rgba(var(--terLm), 1); border-color: rgba(var(--priCy), 1);
background-color: rgba(var(--terCy), 1);
box-shadow: box-shadow:
0.1rem 0.1rem 0.12rem rgba(var(--terLm), 0.25), 0.1rem 0.1rem 0.12rem rgba(var(--terCy), 0.25),
0.12rem 0.12rem 0.25rem rgba(0, 0, 0, 0.25), 0.12rem 0.12rem 0.25rem rgba(0, 0, 0, 0.25),
0.25rem 0.25rem 0.25rem rgba(var(--terLm), 0.12) 0.25rem 0.25rem 0.25rem rgba(var(--terCy), 0.12)
; ;
&:hover { &:hover {
text-shadow: text-shadow:
0.1rem 0.1rem 0.1rem rgba(0, 0, 0, 0.25), 0.1rem 0.1rem 0.1rem rgba(0, 0, 0, 0.25),
0 0 1rem rgba(var(--priLm), 1) 0 0 1rem rgba(var(--priCy), 1)
; ;
box-shadow: box-shadow:
0.12rem 0.12rem 0.5rem rgba(0, 0, 0, 0.25), 0.12rem 0.12rem 0.5rem rgba(0, 0, 0, 0.25),
0 0 0.5rem rgba(var(--priLm), 0.12) 0 0 0.5rem rgba(var(--priCy), 0.12)
; ;
} }
&:active { &:active {
border: 0.18rem solid rgba(var(--priLm), 1); border: 0.18rem solid rgba(var(--priCy), 1);
text-shadow: text-shadow:
-0.1rem -0.1rem 0.25rem rgba(0, 0, 0, 0.25), -0.1rem -0.1rem 0.25rem rgba(0, 0, 0, 0.25),
0 0 0.12rem rgba(var(--priLm), 1) 0 0 0.12rem rgba(var(--priCy), 1)
; ;
box-shadow: box-shadow:
-0.1rem -0.1rem 0.12rem rgba(var(--terLm), 0.25), -0.1rem -0.1rem 0.12rem rgba(var(--terCy), 0.25),
-0.1rem -0.1rem 0.12rem rgba(0, 0, 0, 0.25), -0.1rem -0.1rem 0.12rem rgba(0, 0, 0, 0.25),
0 0 0.5rem rgba(var(--priLm), 0.12) 0 0 0.5rem rgba(var(--priCy), 0.12)
; ;
} }
} }

View File

@@ -22,9 +22,11 @@ describe("SigSelect", () => {
<p class="sig-qualifier-below"></p> <p class="sig-qualifier-below"></p>
<p class="fan-card-arcana"></p> <p class="fan-card-arcana"></p>
<p class="fan-card-correspondence"></p> <p class="fan-card-correspondence"></p>
<p class="fan-card-reversal-qualifier"></p>
<p class="fan-card-reversal-name"></p>
</div> </div>
<div class="sig-stat-block"> <div class="sig-stat-block">
<button class="btn btn-reverse sig-flip-btn" type="button">FLIP</button> <button class="btn btn-reverse sig-flip-btn" type="button">SPIN</button>
<button class="btn btn-caution sig-caution-btn" type="button">!!</button> <button class="btn btn-caution sig-caution-btn" type="button">!!</button>
<div class="stat-face stat-face--upright"> <div class="stat-face stat-face--upright">
<p class="stat-face-label">Upright</p> <p class="stat-face-label">Upright</p>
@@ -60,7 +62,8 @@ describe("SigSelect", () => {
data-keywords-reversed="no direction,disregard for consequences" data-keywords-reversed="no direction,disregard for consequences"
data-cautions="${cardCautions.replace(/"/g, '&quot;')}" data-cautions="${cardCautions.replace(/"/g, '&quot;')}"
data-levity-qualifier="Elevated" data-levity-qualifier="Elevated"
data-gravity-qualifier="Graven"> data-gravity-qualifier="Graven"
data-reversal="Territoriality">
<div class="fan-card-corner fan-card-corner--tl"> <div class="fan-card-corner fan-card-corner--tl">
<span class="fan-corner-rank">K</span> <span class="fan-corner-rank">K</span>
</div> </div>
@@ -321,7 +324,7 @@ describe("SigSelect", () => {
expect(cautionEffect.innerHTML).toContain("First"); expect(cautionEffect.innerHTML).toContain("First");
}); });
it("opening caution adds .btn-disabled and swaps labels to ×", () => { it("opening caution adds .btn-disabled and swaps SPIN/FYI labels to ×", () => {
openCaution(); openCaution();
var flipBtn = testDiv.querySelector(".sig-flip-btn"); var flipBtn = testDiv.querySelector(".sig-flip-btn");
expect(flipBtn.classList.contains("btn-disabled")).toBe(true); expect(flipBtn.classList.contains("btn-disabled")).toBe(true);
@@ -330,7 +333,7 @@ describe("SigSelect", () => {
expect(cautionBtn.textContent).toBe("\u00D7"); expect(cautionBtn.textContent).toBe("\u00D7");
}); });
it("closing caution removes .btn-disabled and restores original labels", () => { it("closing caution removes .btn-disabled and restores SPIN/FYI labels", () => {
var flipBtn = testDiv.querySelector(".sig-flip-btn"); var flipBtn = testDiv.querySelector(".sig-flip-btn");
var origFlip = flipBtn.textContent; var origFlip = flipBtn.textContent;
var origCaution = cautionBtn.textContent; var origCaution = cautionBtn.textContent;
@@ -348,7 +351,7 @@ describe("SigSelect", () => {
expect(testDiv.querySelector(".sig-stage").classList.contains("sig-caution-open")).toBe(false); expect(testDiv.querySelector(".sig-stage").classList.contains("sig-caution-open")).toBe(false);
}); });
it("FLIP click when caution open (btn-disabled) does nothing", () => { it("SPIN click when caution open (btn-disabled) does nothing", () => {
openCaution(); openCaution();
var flipBtn = testDiv.querySelector(".sig-flip-btn"); var flipBtn = testDiv.querySelector(".sig-flip-btn");
flipBtn.dispatchEvent(new MouseEvent("click", { bubbles: true })); flipBtn.dispatchEvent(new MouseEvent("click", { bubbles: true }));
@@ -357,9 +360,9 @@ describe("SigSelect", () => {
}); });
}); });
// ── Stat block: keyword population and FLIP toggle ────────────────── // // ── Stat block: keyword population and SPIN toggle ────────────────── //
describe("stat block and FLIP", () => { describe("stat block and SPIN", () => {
beforeEach(() => makeFixture()); beforeEach(() => makeFixture());
it("populates upright keywords when a card is hovered", () => { it("populates upright keywords when a card is hovered", () => {
@@ -379,14 +382,14 @@ describe("SigSelect", () => {
expect(items[1].textContent).toBe("disregard for consequences"); expect(items[1].textContent).toBe("disregard for consequences");
}); });
it("FLIP click adds .is-reversed to the stat block", () => { it("SPIN click adds .is-reversed to the stat block", () => {
card.dispatchEvent(new MouseEvent("mouseenter", { bubbles: true })); card.dispatchEvent(new MouseEvent("mouseenter", { bubbles: true }));
var flipBtn = statBlock.querySelector(".sig-flip-btn"); var flipBtn = statBlock.querySelector(".sig-flip-btn");
flipBtn.dispatchEvent(new MouseEvent("click", { bubbles: true })); flipBtn.dispatchEvent(new MouseEvent("click", { bubbles: true }));
expect(statBlock.classList.contains("is-reversed")).toBe(true); expect(statBlock.classList.contains("is-reversed")).toBe(true);
}); });
it("second FLIP click removes .is-reversed", () => { it("second SPIN click removes .is-reversed", () => {
card.dispatchEvent(new MouseEvent("mouseenter", { bubbles: true })); card.dispatchEvent(new MouseEvent("mouseenter", { bubbles: true }));
var flipBtn = statBlock.querySelector(".sig-flip-btn"); var flipBtn = statBlock.querySelector(".sig-flip-btn");
flipBtn.dispatchEvent(new MouseEvent("click", { bubbles: true })); flipBtn.dispatchEvent(new MouseEvent("click", { bubbles: true }));
@@ -416,6 +419,76 @@ describe("SigSelect", () => {
}); });
}); });
// ── SPIN card animation — stage-card reversed state ──────────────────── //
describe("SPIN card animation", () => {
function hover() {
card.dispatchEvent(new MouseEvent("mouseenter", { bubbles: true }));
}
it("SPIN click adds .stage-card--reversed to the stage card", () => {
makeFixture();
hover();
statBlock.querySelector(".sig-flip-btn")
.dispatchEvent(new MouseEvent("click", { bubbles: true }));
expect(stageCard.classList.contains("stage-card--reversed")).toBe(true);
});
it("second SPIN click removes .stage-card--reversed", () => {
makeFixture();
hover();
var flipBtn = statBlock.querySelector(".sig-flip-btn");
flipBtn.dispatchEvent(new MouseEvent("click", { bubbles: true }));
flipBtn.dispatchEvent(new MouseEvent("click", { bubbles: true }));
expect(stageCard.classList.contains("stage-card--reversed")).toBe(false);
});
it("hovering a new card resets .stage-card--reversed", () => {
makeFixture();
hover();
statBlock.querySelector(".sig-flip-btn")
.dispatchEvent(new MouseEvent("click", { bubbles: true }));
expect(stageCard.classList.contains("stage-card--reversed")).toBe(true);
card.dispatchEvent(new MouseEvent("mouseleave", { bubbles: true }));
card.dispatchEvent(new MouseEvent("mouseenter", { bubbles: true }));
expect(stageCard.classList.contains("stage-card--reversed")).toBe(false);
});
it("updateStage() populates fan-card-reversal-name from data-reversal", () => {
makeFixture();
card.dataset.reversal = "Territoriality";
hover();
expect(stageCard.querySelector(".fan-card-reversal-name").textContent)
.toBe("Territoriality");
});
it("updateStage() populates fan-card-reversal-qualifier with levity qualifier", () => {
makeFixture({ polarity: "levity", userRole: "PC" });
hover();
expect(stageCard.querySelector(".fan-card-reversal-qualifier").textContent)
.toBe("Elevated");
});
it("updateStage() populates fan-card-reversal-qualifier with gravity qualifier", () => {
makeFixture({ polarity: "gravity", userRole: "BC" });
hover();
expect(stageCard.querySelector(".fan-card-reversal-qualifier").textContent)
.toBe("Graven");
});
it("hovering a card without data-reversal clears the reversal name", () => {
makeFixture();
card.dataset.reversal = "Territoriality";
hover();
card.dispatchEvent(new MouseEvent("mouseleave", { bubbles: true }));
delete card.dataset.reversal;
card.dispatchEvent(new MouseEvent("mouseenter", { bubbles: true }));
// reversal-name clears because data-reversal is gone;
// reversal-qualifier stays (it always mirrors the polarity qualifier)
expect(stageCard.querySelector(".fan-card-reversal-name").textContent).toBe("");
});
});
// ── WS cursor hover (applyHover) ──────────────────────────────────────── // // ── WS cursor hover (applyHover) ──────────────────────────────────────── //
// //
// Fixture polarity = levity, userRole = PC. // Fixture polarity = levity, userRole = PC.

View File

@@ -36,7 +36,7 @@ Context: sig_cards, user_polarity, user_seat, sig_reserve_url, sig_reservations_
</div> </div>
</div> </div>
<div class="sig-stat-block"> <div class="sig-stat-block">
<button class="btn btn-reverse sig-flip-btn" type="button">FLIP</button> <button class="btn btn-reverse sig-flip-btn" type="button">SPIN</button>
<button class="btn btn-caution sig-caution-btn" type="button">FYI</button> <button class="btn btn-caution sig-caution-btn" type="button">FYI</button>
<div class="stat-face stat-face--upright"> <div class="stat-face stat-face--upright">
<p class="stat-face-label">Upright</p> <p class="stat-face-label">Upright</p>