A.5-polish-2 FLIP-to-back bug fixes — TDD. Two user-reported bugs from the first FLIP-to-back commit (1963ad4): (1) FLIPping made the entire card disappear instead of showing the back; (2) the FLIP btn stayed visible during the animation when it should hide just like the tarot-fan view's flip btn does. Root cause of (1): the back-image element was rendered with inline style="display:none" in the template. Inline styles beat CSS class rules in the cascade — my .sig-stage-card.is-flipped-to-back .sig-stage-card-back-img { display: block } rule was the right specificity but couldn't override an inline style attribute. So the toggle hid the front (CSS-controlled, no inline override) but failed to show the back (CSS blocked by inline). Net: empty stage. Fix: removed the inline style on the back-img element; default .sig-stage-card-back-img { display: none } rule (already present in SCSS) handles the hidden default, and the .is-flipped-to-back toggle now flips visibility cleanly. Both rules are pure-CSS so they cascade as expected. Root cause of (2): the non-polarized FLIP handler was a bare class toggle (no animation, no data-flipping attr), so there was no SCSS hook to hide the btn. Plus there was no equivalent SCSS rule even for the polarized _flipPolarityAnimated flow which DID set data-flipping — the polarized flip just animated without hiding the btn either. Fix: (a) added _flipToBackAnimated() JS function mirroring _flipPolarityAnimated's shape — rotateY 0→90→0 at 500ms ease, swap visual content at the halfway point (here: class toggle instead of revInput/polarity flip), set stageCard.dataset.flipping = '1' for the duration so SCSS has a hook. (b) New SCSS rule .my-sign-stage:has(.sig-stage-card[data-flipping]) .my-sign-flip-btn { opacity: 0; pointer-events: none } mirrors the tarot-fan view's pattern (_card-deck.scss:459.tarot-fan-wrap:has(.fan-card[data-flipping]) .fan-flip-btn). The :has() selector covers BOTH the polarized animation (which already sets data-flipping) AND the new non-polarized animation, so the btn hide-during-flip behavior now lands consistently across both flip modes — fixes a latent polished-flow gap not just the new code path. No new tests — the existing 3 ITs from 1963ad4 already verify the template/scaffold contract (data-deck-polarized attr + back-img element conditional render); the bug fixes here are CSS/JS-level behavior best caught by visual verify (no automated test would have caught the inline-style cascade issue since the IT asserted on element presence, not display state). 1303/1303 IT+UT total green (71s, unchanged from 1963ad4 since no new tests in this commit)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Disco DeDisco
2026-05-25 01:35:47 -04:00
parent 1963ad4c71
commit bdf6a251f4
2 changed files with 44 additions and 12 deletions

View File

@@ -887,6 +887,18 @@ html:has(.sig-backdrop) {
display: inline-flex; display: inline-flex;
} }
// Sprint A.5 — hide FLIP btn during the flip animation. `data-flipping="1"`
// is set on .sig-stage-card by _flipPolarityAnimated (polarized) AND
// _flipToBackAnimated (non-polarized) for the 500ms animation duration; CSS
// :has() selects the parent .my-sign-stage when any child carries that attr
// and zeros the btn so it doesn't visually interfere w. the rotateY mid-spin.
// Mirrors the tarot-fan view's pattern (`_card-deck.scss:459` —
// `.tarot-fan-wrap:has(.fan-card[data-flipping]) .fan-flip-btn`).
.my-sign-stage:has(.sig-stage-card[data-flipping]) .my-sign-flip-btn {
opacity: 0;
pointer-events: none;
}
// ─── Mini card grid ─────────────────────────────────────────────────────────── // ─── Mini card grid ───────────────────────────────────────────────────────────
// flex: 0 0 auto — shrinks to card content; no background (backdrop blur). // flex: 0 0 auto — shrinks to card content; no background (backdrop blur).
// align-content: start prevents CSS grid from distributing extra height between rows. // align-content: start prevents CSS grid from distributing extra height between rows.

View File

@@ -42,9 +42,11 @@
{# non-polarized decks). Pre-rendered back-image element; CSS #} {# non-polarized decks). Pre-rendered back-image element; CSS #}
{# toggles visibility via `.sig-stage-card.is-flipped-to-back`. #} {# toggles visibility via `.sig-stage-card.is-flipped-to-back`. #}
{% if request.user.equipped_deck.has_card_images and not request.user.equipped_deck.is_polarized %} {% if request.user.equipped_deck.has_card_images and not request.user.equipped_deck.is_polarized %}
{# No inline style — `.sig-stage-card-back-img` defaults to #}
{# `display: none` via SCSS; `.sig-stage-card.is-flipped-to-back` #}
{# overrides to `display: block`. Inline would beat the toggle. #}
<img class="sig-stage-card-back-img" alt="" <img class="sig-stage-card-back-img" alt=""
src="{{ request.user.equipped_deck.back_image_url }}" src="{{ request.user.equipped_deck.back_image_url }}">
style="display:none">
{% endif %} {% endif %}
<div class="fan-card-corner fan-card-corner--tl"> <div class="fan-card-corner fan-card-corner--tl">
<span class="fan-corner-rank"></span> <span class="fan-corner-rank"></span>
@@ -359,20 +361,38 @@
}); });
} }
if (flipBtn) { // Sprint A.5 — non-polarized FLIP animation. Mirrors the polarized
flipBtn.addEventListener('click', function () { // `_flipPolarityAnimated` shape (rotateY-90 mid-spin + dataset.flipping
if (!_currentCard) return; // for the duration so SCSS can hide the btn) but swaps a class
// Sprint A.5 — non-polarized decks (Minchiate, RWS): FLIP // toggle for the polarity revInput-flip at the halfway point.
// shows the deck card-back instead of cycling polarity (no function _flipToBackAnimated() {
// gravity/levity to toggle on these decks). Stat block stays if (!stageCard || stageCard.dataset.flipping) return;
// unchanged — user spec 2026-05-25 PM. Polarized decks stageCard.dataset.flipping = '1';
// (Earthman) keep the existing polarity-flip animation. var rest = 'translateX(0px) rotateY(0deg) scale(1)';
if (pageEl.dataset.deckPolarized === 'false') { var mid = 'translateX(0px) rotateY(90deg) scale(1)';
stageCard.animate([
{ transform: rest },
{ transform: mid, offset: 0.5 },
{ transform: rest },
], { duration: 500, easing: 'ease' });
setTimeout(function () {
stageCard.classList.toggle('is-flipped-to-back'); stageCard.classList.toggle('is-flipped-to-back');
if (flipBtn) flipBtn.classList.toggle( if (flipBtn) flipBtn.classList.toggle(
'is-reversed', 'is-reversed',
stageCard.classList.contains('is-flipped-to-back') stageCard.classList.contains('is-flipped-to-back')
); );
}, 250);
setTimeout(function () { delete stageCard.dataset.flipping; }, 500);
}
if (flipBtn) {
flipBtn.addEventListener('click', function () {
if (!_currentCard) return;
// Non-polarized decks (Minchiate, RWS): FLIP shows the deck
// card-back; stat block stays unchanged — user spec 2026-05-25 PM.
// Polarized decks (Earthman) keep the existing polarity cycle.
if (pageEl.dataset.deckPolarized === 'false') {
_flipToBackAnimated();
} else { } else {
_flipPolarityAnimated(); _flipPolarityAnimated();
} }