  /* ═══════════ GAME SCREEN REDESIGN ═══════════ */
  #game {
    padding: 0;
    gap: 3px;
    /* Reserve only the HUD's real height plus a little air. The bottom controls keep their thumb-space;
       the board gains room mostly from the top, not by crowding the action buttons. */
    justify-content: flex-start;
    padding-top: calc(env(safe-area-inset-top,0px) + clamp(82px, 10.5vh, 98px));
    padding-bottom: calc(env(safe-area-inset-bottom,0px) + clamp(20px, 4vh, 40px));
    background: url('../../assets/stage/bg.webp') center / cover no-repeat;
    position: relative;
    overflow: hidden;
    isolation: isolate;   /* own stacking context → the bgVid (z-index:-1) paints ABOVE this webp bg, below content */
  }

  /* HUD: back+moves left, star+lives right */
  /* ── stage HUD: sliced sprites ── */
  #game #hud {
    justify-content: space-between;
    align-items: flex-start;
    max-width: none;
    width: 100%;
    padding: calc(env(safe-area-inset-top,0px) + 6px) clamp(6px,2.5vw,12px) 0;
    gap: clamp(4px,1.5vw,8px);
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    z-index: 10;
  }
  /* left bar = back + Moves + Stage as one sprite; values overlaid on slots */
  #game .hudLeft {
    position: relative; display: block;
    flex: 0 1 auto;
    width: clamp(210px, 58vw, 290px);
    aspect-ratio: 626 / 177;
    background: url('../../assets/stage/hud_left.webp') center / 100% 100% no-repeat;
    gap: 0;
  }
  /* in-game starlight / hearts HUD (right slot) — restored to show the economy during play */
  #game .hudRight {
    display: flex; flex-direction: column; align-items: flex-end;
    gap: clamp(2px, 1vw, 5px); flex: 0 0 auto;
  }

  /* back arrow: transparent click target over the sprite's arrow (left ~18% of bar) */
  #game #hudBack {
    position: absolute; left: 0; top: 50%; transform: translateY(-50%);
    width: 18%; height: 92%; min-width: 0 !important;
    background: transparent !important;
    border: none !important; box-shadow: none !important; padding: 0 !important;
    font-size: 0 !important; color: transparent !important; cursor: pointer; z-index: 2;
  }
  #game #hudBack svg { display: none; }

  /* Moves value: inside the Moves value box (center ~36% across, ~62% down) */
  #game #hudDrags {
    position: absolute; left: 37%; top: 57%; transform: translate(-50%, -50%);
    width: auto; height: auto; padding: 0;
    background: none !important; border: none !important; box-shadow: none !important;
    border-radius: 0;
    font: inherit; font-weight: 900; font-size: clamp(17px, 5.3vw, 22px); line-height: 1; color: #5a3510;
    text-shadow: none; white-space: nowrap; min-width: 0;
  }
  #game #hudDrags svg { display: none; }
  #game #hudDrags { cursor: pointer; }                       /* tappable → opens the refill menu */
  #game #hudDrags.low { color: #c0392b; }                    /* ≤2 strokes: warn early so the lock isn't a surprise */
  #game #hudDrags.locked { color: #c0392b; animation: drPulse 1.1s ease-in-out infinite; }   /* out → pulse "tap to refill" */
  @keyframes drPulse { 0%,100% { transform: translate(-50%,-50%) scale(1); } 50% { transform: translate(-50%,-50%) scale(1.16); } }
  html[data-motion="reduced"] { #game #hudDrags.locked { animation: none; } }
  /* refill confirm: the pill pops and stays GLOWING through the whole count-up roll (~480ms) so the rising
     number is visibly "hot" while it climbs, settling as the roll lands (owner 2026-07: old .55s pop was too
     shallow to notice after an ad). Keeps its centering transform. */
  #game #hudDrags.refilled { animation: drRefill .85s ease-out; }
  @keyframes drRefill {
    0%   { transform: translate(-50%,-50%) scale(1); }
    18%  { transform: translate(-50%,-50%) scale(1.42); filter: brightness(1.6) drop-shadow(0 0 10px rgba(255,230,140,1)); }
    62%  { transform: translate(-50%,-50%) scale(1.14); filter: brightness(1.35) drop-shadow(0 0 8px rgba(255,230,140,.85)); }
    100% { transform: translate(-50%,-50%) scale(1); }
  }
  /* "+N" floats up from the pill on a refill (positioned in JS at the pill center) — big enough to read
     while the eyes are still returning from the rewarded ad */
  .dragRefillFloat {
    position: fixed; z-index: 80; pointer-events: none; white-space: nowrap;
    display: flex; align-items: center; gap: 4px;
    color: var(--gold); font-family: 'Jua', system-ui, sans-serif; font-weight: 400; font-size: 27px;
    -webkit-text-stroke: 1.4px var(--gold-deep); paint-order: stroke fill; text-shadow: 0 2px 5px rgba(60,34,4,.55);
    animation: dragRefillRise 1.4s ease-out forwards;
  }
  .dragRefillFloat .ico { width: 22px; height: 22px; }
  @keyframes dragRefillRise {
    0%   { opacity: 0; transform: translate(-50%, 4px) scale(.7); }
    14%  { opacity: 1; transform: translate(-50%, -10px) scale(1.12); }
    72%  { opacity: 1; transform: translate(-50%, -30px) scale(1); }
    100% { opacity: 0; transform: translate(-50%, -48px) scale(.96); }
  }
  /* reduce-motion: the +N chip appears statically (JS removes it after ~1.3s) — meaning without motion */
  .dragRefillFloat.static { animation: none; opacity: 1; transform: translate(-50%, -26px); }
  /* arrival ring — a gold pulse expanding from the pill the frame the count-up LANDS (도착 충격) */
  .dragRefillRing {
    position: fixed; z-index: 79; pointer-events: none;
    width: 30px; height: 30px; margin: -15px 0 0 -15px; border-radius: 50%;
    border: 3px solid rgba(255,214,96,.95); box-shadow: 0 0 12px rgba(255,214,96,.8);
    animation: dragRingOut .55s cubic-bezier(.15,.7,.3,1) forwards;
  }
  @keyframes dragRingOut {
    0%   { opacity: .9; transform: scale(.4); }
    100% { opacity: 0; transform: scale(2.6); }
  }
  /* Stage value: inside the Stage value box (center ~70% across, ~57% down) */
  #game #puzzleName {
    position: absolute; left: 70.5%; top: 57%; transform: translate(-50%, -50%);
    max-width: 40%; text-align: center;
    overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
    font-weight: 900; font-size: clamp(14px, 4.4vw, 18px); line-height: 1;
    color: #5a3510; text-shadow: none;
  }

  /* star (coins) + heart (lives): reuse the map's combined stone HUD bar for tonal unity */
  #game .hudRight .gameHudCombo { margin-top: 2px; }

  /* time-seal countdown pill — the one place where fading light adds urgency */
  /* OVERLAY (not in-flow): the boss timer + coach must never consume column height — otherwise on short
     screens they push the bottom action bar (.controls) out of reach. Pinned just below the HUD, over the
     board's top margin. Centered via margin-inline:auto (NOT transform → leaves transform free for the
     pulse / coach-in animations). */
  /* .paletteZone wraps the palette + boss timer; it's the positioning context the timer anchors to. */
  #game .paletteZone { position: relative; }
  #game .bossTimer {
    position: absolute; left: 0; right: 0; margin-inline: auto; width: max-content;
    /* anchored to the palette's BOTTOM edge (top:100% of .paletteZone, whose height == the palette's,
       since the timer is out of flow) → tracks the shape-preview height at any resolution instead of a
       fixed offset that overlapped a 2-row palette. */
    top: 100%; margin-top: 4px;
    padding: 4px 16px 5px;
    display: flex; align-items: center; gap: 6px; z-index: 9;
    border-radius: 999px; border: 2px solid #f0c15a;
    background: linear-gradient(180deg, #6a2a26, #321617);
    color: #fff3e6; font-weight: 900; font-size: clamp(16px, 4.6vw, 21px); line-height: 1; letter-spacing: .5px;
    text-shadow: 0 1px 2px rgba(0,0,0,.5);
    box-shadow: 0 4px 12px rgba(70,18,12,.42), 0 0 9px rgba(255,110,80,.36), inset 0 1px 0 rgba(255,244,202,.28);
  }
  #game .bossTimer::before { content: "\231B"; font-size: .9em; filter: saturate(1.08) drop-shadow(0 1px 1px rgba(55,12,4,.55)); }
  #game .bossTimer.low {
    color: #fff0ec; border-color: #ff6a5a;
    background: linear-gradient(180deg, #5e2020, #3a1414);
    box-shadow: 0 4px 14px rgba(70,12,12,.5), inset 0 1px 0 rgba(255,255,255,.25);
    animation: bossTimerPulse 1s ease-in-out infinite;
  }
  @keyframes bossTimerPulse { 0%,100% { transform: scale(1); } 50% { transform: scale(1.09); } }
  html[data-motion="reduced"] { #game .bossTimer.low { animation: none; } }
  #game .timeSealCoach {
    position: absolute; left: 0; right: 0; margin-inline: auto; width: max-content; z-index: 10;
    top: auto; bottom: calc(env(safe-area-inset-bottom,0px) + clamp(120px, 17vh, 154px));
    max-width: min(320px, 86vw); padding: 6px 12px 6px 7px;
    border-radius: 13px; border: 1.5px solid rgba(255,221,142,.85);
    background:
      linear-gradient(180deg, rgba(255,232,168,.2), transparent 45%),
      linear-gradient(180deg, rgba(74,34,22,.94), rgba(39,20,15,.94));
    color: #fff4d2; font-size: clamp(12px, 3.4vw, 15px); font-weight: 850; line-height: 1.18;
    display: flex; align-items: center; justify-content: center; gap: 7px;
    text-align: left; text-shadow: 0 1px 2px rgba(24,8,3,.72);
    box-shadow: 0 4px 12px rgba(42,14,6,.38), 0 0 9px rgba(255,128,82,.28), inset 0 1px 0 rgba(255,245,205,.22);
    pointer-events: none;
  }
  #game .timeSealCoach .timeSealSha {
    flex: 0 0 auto; width: 42px; height: 42px; object-fit: contain;
    filter: drop-shadow(0 2px 3px rgba(18,8,2,.5)) drop-shadow(0 0 8px rgba(255,220,96,.38));
    transform-origin: 50% 90%;
    animation: timeSealShaPeek .72s cubic-bezier(.18,1.35,.35,1) both;
  }
  #game .timeSealCoach .timeSealCoachText { display: block; max-width: 220px; }
  #game .timeSealCoach::before {
    content: ""; position: absolute; left: 50%; top: -7px; transform: translateX(-50%);
    width: 0; height: 0; border-left: 7px solid transparent; border-right: 7px solid transparent;
    border-bottom: 8px solid rgba(74,34,22,.94);
    filter: drop-shadow(0 -1px 0 rgba(255,221,142,.75));
  }
  /* tail points UP toward the board — all coaches sit below the board now */
  #game .timeSealCoach.omenCoach {
    border-color: rgba(255,232,135,.9);
    background:
      linear-gradient(180deg, rgba(255,241,174,.24), transparent 45%),
      linear-gradient(180deg, rgba(56,62,28,.95), rgba(34,47,22,.95));
    box-shadow: 0 4px 12px rgba(23,38,12,.36), 0 0 12px rgba(255,220,92,.32), inset 0 1px 0 rgba(255,250,210,.24);
  }
  #game .timeSealCoach.omenCoach::before { border-bottom-color: rgba(56,62,28,.95); }
  #game .timeSealCoach.trailCoach {
    border-color: rgba(235,216,139,.82);
    background:
      linear-gradient(180deg, rgba(255,235,160,.18), transparent 45%),
      linear-gradient(180deg, rgba(50,48,30,.95), rgba(30,37,24,.95));
    box-shadow: 0 4px 12px rgba(21,31,13,.34), 0 0 9px rgba(255,218,92,.24), inset 0 1px 0 rgba(255,250,210,.2);
  }
  #game .timeSealCoach.trailCoach::before { border-bottom-color: rgba(50,48,30,.95); }
  /* elite intro coach — amethyst skin (matches the elite gem/socket/pill grammar) */
  #game .timeSealCoach.eliteCoach {
    border-color: rgba(214,178,248,.85);
    background:
      linear-gradient(180deg, rgba(230,210,255,.2), transparent 45%),
      linear-gradient(180deg, rgba(58,34,92,.95), rgba(36,20,58,.95));
    box-shadow: 0 4px 12px rgba(30,14,52,.4), 0 0 11px rgba(154,85,224,.34), inset 0 1px 0 rgba(235,215,255,.22);
  }
  #game .timeSealCoach.eliteCoach::before { border-bottom-color: rgba(58,34,92,.95); }
  #game .timeSealCoach.show { animation: timeSealCoachIn .22s ease-out both; }
  @keyframes timeSealCoachIn { from { opacity: 0; transform: translateY(6px) scale(.97); } to { opacity: 1; transform: translateY(0) scale(1); } }
  @keyframes timeSealShaPeek {
    0% { opacity: 0; transform: translateY(7px) rotate(-4deg) scale(.82); }
    64% { opacity: 1; transform: translateY(-2px) rotate(2deg) scale(1.06); }
    100% { opacity: 1; transform: translateY(0) rotate(0) scale(1); }
  }
  html[data-motion="reduced"] {
    #game .timeSealCoach.show,
    #game .timeSealCoach .timeSealSha { animation: none; }
  }

  /* Board area: centers the board+frame vertically */
  .gameBoardArea {
    flex: 0 1 auto;            /* natural height (= framed canvas); don't grow → content packs toward the top */
    display: flex;
    align-items: center;
    justify-content: center;
    position: relative;
    z-index: 5;
    width: 100%;
    min-height: 0;
    padding-top: 0;
  }
  /* Board placement polish — RESPONSIVE, board SIZE never changes (fitBoard owns it; owner 2026-06-30).
     Applied on screens with vertical headroom (≥760px tall: Fold cover, most modern phones) OR screens
     wide enough that they can't be a narrow phone (≥600px: Fold/tablet UNFOLDED — short but wide, e.g.
     ~808×720, so height alone wrongly excluded it and the board glued to the palette there — 2026-07-03):
       • flex:1 1 auto → the area GROWS to fill the space between the palette and the pinned bottom bar, and
         (it's display:flex + align/justify:center) CENTERS the board in it. This splits the leftover space
         ABOVE+BELOW the board instead of dumping it all below → the bottom action bar stays pinned
         (margin-top:auto) at a STABLE position and the board no longer glues to the palette.
       • margin-top → guarantees a MINIMUM palette↔board gap even for a large board that nearly fills the area
         (where centering alone would shrink the gap back toward 0).
     :not(.scrollY) → tall scroll boards keep their own rule (display:block + top-anchored overflow-y:auto),
     untouched. Small NARROW screens (SE 375×667, chrome already fills the column per boardFit's 320px
     reservation) fall outside both conditions → keep flex:0 1 auto, so the board can never be
     center-clipped there. CSS-only. */
  @media (min-height: 760px), (min-width: 600px) {
    #game .gameBoardArea:not(.scrollY) { flex: 1 1 auto; margin-top: clamp(8px, 1.6vh, 16px); }
  }

  /* Tall-board (rows > 9) vertical scroll: cells stay full-size, the board scrolls. Block + top-anchor so
     the top is reachable (flex `align-items:center` clips the top of an overflowing child); flex governs the
     height (no maxHeight). Long-press one finger OR a second finger scrolls it (input/paint.js); one finger drags = paint. */
  .gameBoardArea.scrollY {
    display: block;
    flex: 1 1 0;            /* take ALL remaining space between palette and the action bar … */
    min-height: 0;         /* … and be allowed to shrink below the board height so it scrolls internally */
    overflow-y: auto;
    overflow-x: hidden;
    -webkit-overflow-scrolling: touch;
  }
  .gameBoardArea.scrollY .gameBoardWrap { margin: 0 auto; }
  /* "↕ 스크롤" cue shown while the long-press scroll mode is active (sticky → stays at the top while scrolling) */
  .gameBoardArea.scrollOn::before {
    content: "↕ 스크롤"; position: sticky; top: 6px; z-index: 12;
    display: block; width: max-content; margin: 0 auto -34px;
    padding: 5px 14px; border-radius: 999px;
    background: rgba(40,20,8,.78); color: #ffe7bd; font-weight: 800; font-size: 13px;
    box-shadow: 0 2px 8px rgba(0,0,0,.35); pointer-events: none;
  }

  /* Board wrapper: creates positioning context for frame + puzzle name */
  .gameBoardWrap {
    position: relative;
    isolation: isolate;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  /* first-levels (사각형 1·2) drag tutorial: a touch dot + ripple + finger demoing a drag across the board.
     JS overlays #dragCoach exactly on #board and removes .on at the player's first touch. */
  #dragCoach { position: absolute; z-index: 9; pointer-events: none; opacity: 0; transition: opacity .3s ease; }
  #dragCoach.on { opacity: 1; }
  /* control-button guide: a pulsing ring on a bottom tool + a tooltip above it (one-time, tap to dismiss) */
  #controlCoach { position: fixed; inset: 0; z-index: 75; pointer-events: none; opacity: 0; transition: opacity .25s ease; }
  #controlCoach.on { opacity: 1; }
  #controlCoach .ccRing {
    position: fixed; transform: translate(-50%, -50%); border-radius: 50%; box-sizing: border-box;
    border: 3px solid rgba(255,224,122,.95);
    box-shadow: 0 0 0 4px rgba(255,224,122,.22), 0 0 16px rgba(255,224,122,.5);
    animation: ccRingPulse 1.2s ease-in-out infinite;
  }
  @keyframes ccRingPulse {
    0%,100% { transform: translate(-50%,-50%) scale(1);    opacity: .95; }
    50%     { transform: translate(-50%,-50%) scale(1.16); opacity: .55; }
  }
  #controlCoach .ccBubble {
    position: fixed; transform: translateX(-50%); max-width: 240px; word-break: keep-all;
    padding: 9px 14px; border-radius: 12px; text-align: center;
    background: rgba(40,28,14,.95); color: #fff3d6;
    font-family: system-ui, sans-serif; font-size: 14px; font-weight: 700; line-height: 1.35;
    box-shadow: 0 6px 18px rgba(20,12,4,.5);
    animation: ccBubbleIn .28s ease-out both;
  }
  #controlCoach .ccBubble::after {
    content: ""; position: absolute; left: 50%; bottom: -7px; transform: translateX(-50%);
    border: 7px solid transparent; border-bottom: 0; border-top-color: rgba(40,28,14,.95);
  }
  @keyframes ccBubbleIn { 0% { opacity: 0; transform: translateX(-50%) translateY(5px); } 100% { opacity: 1; transform: translateX(-50%) translateY(0); } }
  html[data-motion="reduced"] { #controlCoach .ccRing, #controlCoach .ccBubble { animation: none; } }
  #dragCoach .dcPoint { position: absolute; left: var(--x1, 25%); top: var(--y1, 25%); transform: translate(-50%, -50%);
    width: clamp(28px, 9vw, 40px); aspect-ratio: 1; border-radius: 50%;
    background: radial-gradient(circle at 38% 34%, rgba(255,255,255,.96), rgba(255,255,255,.34) 62%, transparent 74%);
    box-shadow: 0 0 0 3px rgba(255,255,255,.5), 0 3px 10px rgba(0,0,0,.4);
    animation: dcDrag 3.4s cubic-bezier(.5,0,.5,1) infinite; }
  #dragCoach .dcRipple { position: absolute; inset: 0; border-radius: 50%; border: 2px solid rgba(255,255,255,.9);
    animation: dcRipple 3.4s ease-out infinite; }
  #dragCoach .dcHand { position: absolute; left: 60%; top: 78%; font-size: clamp(24px, 8vw, 36px); line-height: 1;
    filter: drop-shadow(0 3px 4px rgba(0,0,0,.45)); }
  /* demo a full 2×2 square fill: press top-left, drag → top-right → bottom-right → bottom-left (all 4 cells). */
  @keyframes dcDrag {
    0%   { left: var(--x1,25%); top: var(--y1,25%); opacity: 0; }
    6%   { opacity: 1; }
    15%  { left: var(--x1,25%); top: var(--y1,25%); }    /* press the first cell */
    38%  { left: var(--x2,75%); top: var(--y2,25%); }    /* drag → top-right */
    60%  { left: var(--x3,75%); top: var(--y3,75%); }    /* drag ↓ bottom-right */
    82%  { left: var(--x4,25%); top: var(--y4,75%); }    /* drag ← bottom-left: square filled */
    88%  { left: var(--x4,25%); top: var(--y4,75%); opacity: 1; }
    95%  { opacity: 0; }
    100% { left: var(--x1,25%); top: var(--y1,25%); opacity: 0; }
  }
  @keyframes dcRipple { 0%,12% { transform: scale(.7); opacity: .9; } 26% { transform: scale(1.7); opacity: 0; } 100% { transform: scale(1.7); opacity: 0; } }
  html[data-motion="reduced"] { #dragCoach .dcPoint, #dragCoach .dcRipple { animation: none !important; } }  /* keep finger VISIBLE (static) — only drop motion, matches #startCoach (§8); battery-saver hid the whole tutorial before */

  /* 6x6+ idle "여기서 시작" pointer: a finger taps the forced start region (which also glows) so it
     clearly reads as a hint — not just a brighter tile. JS overlays #startCoach on #board + positions
     the point at the region centroid; removed on the player's first board input. */
  #startCoach { position: absolute; z-index: 9; pointer-events: none; opacity: 0; transition: opacity .3s ease; }
  #startCoach.on { opacity: 1; }
  #startCoach .scPoint { position: absolute; left: var(--cx, 30%); top: var(--cy, 30%); transform: translate(-50%, -50%);
    width: clamp(30px, 10vw, 44px); aspect-ratio: 1; border-radius: 50%;
    background: radial-gradient(circle at 38% 34%, rgba(255,238,188,.98), rgba(255,206,110,.42) 60%, transparent 74%);
    box-shadow: 0 0 0 3px rgba(255,214,120,.6), 0 3px 10px rgba(0,0,0,.42);
    animation: scTap 1.5s ease-in-out infinite; }
  #startCoach .scRipple { position: absolute; inset: 0; border-radius: 50%; border: 2px solid rgba(255,220,130,.95);
    animation: scRipple 1.5s ease-out infinite; }
  #startCoach .scHand { position: absolute; left: 62%; top: 72%; font-size: clamp(28px, 9vw, 42px); line-height: 1;
    filter: drop-shadow(0 3px 4px rgba(0,0,0,.5)); animation: scHandBob 1.5s ease-in-out infinite; }
  @keyframes scTap { 0%,100% { transform: translate(-50%,-50%) scale(1); } 50% { transform: translate(-50%,-50%) scale(.8); } }
  @keyframes scRipple { 0% { transform: scale(.55); opacity: .95; } 55% { transform: scale(1.95); opacity: 0; } 100% { transform: scale(1.95); opacity: 0; } }
  @keyframes scHandBob { 0%,100% { transform: translateY(-7px); } 50% { transform: translateY(0); } }
  html[data-motion="reduced"] { #startCoach .scPoint, #startCoach .scRipple, #startCoach .scHand { animation: none; } }

  /* The playfield frame is drawn dynamically from puzzle data. The title uses the map card header
     because it is a self-contained banner and does not add loose rails around irregular boards. */
  /* Stage title banner retired — the stage name now lives in the HUD bar's "Stage" slot */
  /* (legacy in-board stage-title CSS removed — the live stage name is #puzzleName in the HUD;
     the old .stageTitle / .stageTitle--legacy element + its map_card_header.webp are deleted.) */
  /* Board cells: remove standalone shadow/animation (frame provides the decoration) */
  #game #board {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    margin: 0;
    filter: none;
    animation: none;
    overflow: visible;
    background: transparent;
    box-shadow: none;
    z-index: 2;
  }
  #game .leadLayer {
    filter:
      drop-shadow(0 2px 1px rgba(35,18,8,.34))
      drop-shadow(0 0 2px rgba(207,163,82,.16));
  }
  #game .boardPlateLayer {
    position: absolute;
    left: 0;
    top: 0;
    overflow: visible;
    pointer-events: none;
    z-index: 0;
  }
  #game .boardFrameLayer {
    position: absolute;
    left: 0;
    top: 0;
    overflow: visible;
    pointer-events: none;
    z-index: 1;
  }
  #game .boardPlateCells {
    fill: #2f2818;   /* dark warm-stone recess behind cells (was red) → matches the temple canvas */
  }
  #game .cell {
    position: relative;
    z-index: 2;
    border-radius: 0;
    overflow: hidden;
    background: transparent;
  }
  #game .cell.void {
    background: transparent !important;
  }
  #game .cell.tex::before {
    opacity: .42;
    filter: saturate(.72) contrast(1.04) brightness(1.08);
  }
  /* empty cell = quiet idle glass, not a flat CSS fill: ivory/bronze transparency, shallow
     inner depth, and only a faint facet texture so the puzzle shape remains the main signal. */
  #game .cell.unfilled {
    /* light warm cream "empty slot" — clearly brighter than the tan board/void so players can read which
       cells to fill; sits on the dark #2f2818 plate grout, so the lit grid pops as the fill area. */
    background:
      linear-gradient(154deg, rgba(255,255,255,.42) 0%, rgba(255,250,232,.12) 44%, transparent 70%),
      radial-gradient(100% 96% at 50% 32%, #f6eed9 0%, #ecdfbf 70%, #d8c39a 100%);
    color: #5a4720;
    box-shadow:
      inset 0 2px 0 rgba(255,255,250,.7),
      inset 0 0 0 1px rgba(120,90,38,.28),
      inset 0 -6px 11px rgba(120,82,28,.26),
      inset 0 7px 12px rgba(255,248,222,.20);
  }
  /* "여기서 시작" idle-help glow (6x6+): the old warm-gold-on-warm-beige glow blended into the empty
     tiles. Lift the hinted region OFF the warm floor two ways so its SHAPE reads at a glance: a bright
     near-white fill (a clear LUMINANCE jump vs the #ecdfbf floor) + a crisp amber outline (--s2) that
     stays strong even at the swell's trough, so the silhouette never fades. Gentle swell, not a blink. */
  @keyframes startHereGlow {
    0%, 100% { box-shadow:
      inset 0 2px 0 rgba(255,255,250,.7), inset 0 0 0 1px rgba(120,90,38,.28),
      inset 0 -6px 11px rgba(120,82,28,.26), inset 0 7px 12px rgba(255,248,222,.20),
      inset 0 0 6px 1px rgba(245,160,35,.45), inset 0 0 0 2.5px rgba(220,130,18,.92); }
    50%      { box-shadow:
      inset 0 2px 0 rgba(255,255,250,.7), inset 0 0 0 1px rgba(120,90,38,.28),
      inset 0 -6px 11px rgba(120,82,28,.26), inset 0 7px 12px rgba(255,248,222,.20),
      inset 0 0 18px 5px rgba(255,165,40,.8), inset 0 0 0 2.5px rgba(235,140,20,1); }
  }
  #game .cell.unfilled.startHint {
    background:
      linear-gradient(154deg, rgba(255,255,255,.55) 0%, rgba(255,252,238,.16) 44%, transparent 70%),
      radial-gradient(100% 96% at 50% 32%, #fffef9 0%, #fff3cc 60%, #ffe2a0 100%);
    animation: startHereGlow 2.4s ease-in-out infinite;
  }
  html[data-motion="reduced"] {
    #game .cell.unfilled.startHint { animation: none; box-shadow:
      inset 0 2px 0 rgba(255,255,250,.7), inset 0 0 0 1px rgba(120,90,38,.28),
      inset 0 -6px 11px rgba(120,82,28,.26), inset 0 7px 12px rgba(255,248,222,.20),
      inset 0 0 12px 3px rgba(255,165,40,.6), inset 0 0 0 2.5px rgba(228,135,18,1); }
  }
  #game .cell.unfilled::before {
    content: "";
    opacity: .18;
    mix-blend-mode: soft-light;
    filter: saturate(.34) contrast(.92) brightness(1.18);
  }
  #game .cell.unfilled::after {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 1;
    background:
      linear-gradient(180deg, rgba(255,253,232,.16) 0%, rgba(255,253,232,.03) 13%, transparent 28%),
      linear-gradient(90deg, rgba(255,253,232,.09) 0%, transparent 12%);
    mix-blend-mode: screen;
  }
  #game .cell .omenGlyph {
    position: absolute; inset: 8%; z-index: 3; pointer-events: none;
    display: grid; place-items: center;
    opacity: 0; transform: scale(.92);
    color: rgba(133,84,17,.62); font-weight: 1000; font-size: calc(var(--cell-px) * .34); line-height: 1;
    text-shadow: 0 1px 0 rgba(255,255,230,.44), 0 0 8px rgba(255,225,104,.24);
    mix-blend-mode: multiply;
  }
  #game .cell.omenCell {
    box-shadow:
      inset 0 2px 0 rgba(255,255,250,.7),
      inset 0 0 0 1px rgba(120,90,38,.28),
      inset 0 -6px 11px rgba(120,82,28,.26),
      inset 0 7px 12px rgba(255,248,222,.20),
      inset 0 0 0 2px rgba(255,217,99,.26),
      0 0 9px rgba(255,216,92,.14);
  }
  #game .cell.omenCell .omenGlyph {
    opacity: .72;
    animation: omenGlyphPulse 2.8s ease-in-out infinite;
  }
  #game .cell.omenCell.paint .omenGlyph,
  #game .cell.omenCell.locked .omenGlyph { opacity: .34; mix-blend-mode: screen; }
  #game .cell.omen-heart .omenGlyph { color: rgba(150,39,33,.64); }
  #game .cell.omen-hint .omenGlyph { color: rgba(67,112,28,.64); }
  #game .cell.omen-jump .omenGlyph { color: rgba(30,98,143,.64); }
  @keyframes omenGlyphPulse {
    0%, 100% { transform: scale(.92); filter: brightness(.94); }
    50% { transform: scale(1.04); filter: brightness(1.18); }
  }
  html[data-motion="reduced"] {
    #game .cell.omenCell .omenGlyph { animation: none; transform: scale(1); }
  }
  /* in-progress paint = tactile placed glass. It is brighter and thicker than empty glass,
     but stays neutral so it cannot be mistaken for a sealed stained-glass reward. */
  /* in-progress painted region (not yet a valid/sealed shape) — a muted cool slate, deliberately
     OFF the warm palette so "I painted here, pending" reads at a glance, distinct from both the warm
     floor/void and the light empty cells, and clearly not a (saturated) sealed jewel. */
  #game .cell.paint {
    background:
      linear-gradient(152deg, rgba(255,255,255,.30) 0%, rgba(232,243,244,.10) 44%, transparent 70%),
      radial-gradient(96% 92% at 48% 32%, #a3b4b6 0%, #7d9193 74%, #5f7679 100%);
    color: #fff;
    box-shadow:
      inset 0 2px 0 rgba(255,255,255,.38),
      inset 0 -6px 10px rgba(26,40,41,.3),
      inset 0 0 0 1px rgba(48,68,70,.34);
  }
  #game .cell.paint::before {
    opacity: .34;
    filter: saturate(.48) contrast(1.02) brightness(1.10);
  }
  /* Shape mode: jewels render as flat --sN colour (no webp gem tiles) so the stained-glass texture
     (.cell.tex::before) + specular sheen (.cell.sN::after) + .locked lighting read as backlit glass.
     NB: must repeat at #game specificity — `#game .cell{background:transparent}` (an id selector) would
     otherwise beat the base `.cell.sN{background:var(--sN)}` and blank every jewel to the plate behind. */
  #game .cell.s1 { background: var(--s1); }
  #game .cell.s2 { background: var(--s2); }
  #game .cell.s3 { background: var(--s3); }
  #game .cell.s4 { background: var(--s4); }
  #game .cell.s5 { background: var(--s5); }
  #game .cell.sX { background: var(--sX); }
  #game .cell.locked {
    filter: brightness(1.08) saturate(1.48) contrast(1.03);
    box-shadow:
      inset 0 1px 0 rgba(255,255,255,.36),
      inset 0 -6px 12px rgba(0,0,0,.20),
      inset 0 0 14px rgba(255,232,158,.10);
  }
  #game .cell.locked::before {
    opacity: .92;
    filter: saturate(1.08) contrast(1.08) brightness(1.08);
  }
  #game .cell.locked::after {
    background:
      linear-gradient(180deg, rgba(255,255,255,.36) 0%, rgba(255,255,255,.07) 10%, transparent 18%),
      linear-gradient(90deg, rgba(255,255,255,.17) 0%, transparent 11%),
      radial-gradient(100% 70% at 50% 0%, rgba(255,247,204,.16), transparent 58%);
  }
  /* idle shimmer: when the player pauses (#game.idle, set after a few idle seconds), the sealed jewels
     softly + IRREGULARLY catch the light — a calm "stained-glass shine". Each cell uses its own random
     --wd (9–17s period) / --wdl (random negative delay) so they never pulse in unison. Off during play
     (any input clears .idle) and off the game screen. Subtle by design (Quiet Canvas). */
  /* not a blink — the glass rests at its normal brightness most of the cycle, then ONE slow gentle
     swell (+~8%) and an equally slow return. Low amplitude + long rest = a soft glow, not a pulse. */
  /* idle light-wave: a gentle warm swell travels L→R, each sealed jewel catching the light AS IT IS REACHED
     (delay = column × step + small per-cell jitter, so it reads as light caught BY the glass — organic,
     not a band on top). Replaces the old linear "shine sweep" overlay (2026-06-24). Rests at a soft boost. */
  @keyframes idleGlassWave {
    0%, 14%, 100% { filter: brightness(1.06) saturate(1.42) contrast(1.03); }
    7%            { filter: brightness(1.26) saturate(1.6) contrast(1.05); }
  }
  #game.idle .cell.locked { animation: idleGlassWave 9s calc(var(--col, 0) * 0.16s + var(--wj, 0s)) ease-in-out infinite; }
  html[data-motion="reduced"] { #game.idle .cell.locked { animation: none; } }

  /* ── idle ambient life: peripheral, calm, ONLY while the player pauses; suppressed during the win/reward
     sequence so it never competes with the celebration. Reading zone (clues/unfilled) stays untouched. ── */
  /* ① drifting light motes — warm, sparse, very slow (light = IP memory anchor) */
  .idleMotes { position: absolute; inset: 0; z-index: 6; pointer-events: none; opacity: 0; transition: opacity .8s ease; }
  body:not(.reward-sequence) #game.idle .idleMotes { opacity: 1; }
  .idleMotes i {
    position: absolute; width: 7px; height: 7px; border-radius: 50%; will-change: transform, opacity;
    background: radial-gradient(circle at 50% 40%, rgba(255,246,210,.95), rgba(255,214,120,.35) 55%, transparent 72%);
  }
  .idleMotes i:nth-child(1) { left: 16%; bottom: 10%; animation: moteDrift 13s ease-in-out infinite; }
  .idleMotes i:nth-child(2) { left: 74%; bottom: 16%; animation: moteDrift 17s ease-in-out -6s infinite; }
  .idleMotes i:nth-child(3) { left: 46%; bottom: 6%;  animation: moteDrift 21s ease-in-out -11s infinite; }
  @keyframes moteDrift {
    0%   { opacity: 0; transform: translate(0,0) scale(.7); }
    20%  { opacity: .85; }
    80%  { opacity: .6; }
    100% { opacity: 0; transform: translate(12px,-120px) scale(1.05); }
  }
  /* ② board light-wave — RETIRED (2026-06-24): the linear "shine sweep" band read as a cheap overlay.
     Replaced by idleGlassWave above (the sealed jewels themselves catch a L→R light wave). */
  /* ③ Sha companion — peeks from a bottom corner on a longer idle; small, calm, non-blocking */
  .stageBuddy {
    position: absolute; left: 1%; bottom: 1%; z-index: 7; width: clamp(76px, 22vw, 116px);
    pointer-events: none; opacity: 0; transform: translateY(42%) rotate(-4deg);
    transition: opacity .5s ease, transform .5s cubic-bezier(.34,1.4,.5,1);
    filter: var(--sha-tint, brightness(1)) drop-shadow(0 3px 5px rgba(20,30,12,.4));
  }
  body:not(.reward-sequence) #game.idleDeep .stageBuddy {
    opacity: 1; transform: translateY(0) rotate(-4deg); animation: buddyBob 3.2s ease-in-out infinite;
  }
  @keyframes buddyBob { 0%,100% { transform: translateY(0) rotate(-4deg); } 50% { transform: translateY(-5px) rotate(-2deg); } }
  html[data-motion="reduced"] {
    .idleMotes { display: none; }
    body:not(.reward-sequence) #game.idleDeep .stageBuddy { animation: none; opacity: 1; transform: rotate(-4deg); }
  }
  /* equipped Sha costume tint also rides the win-card mascot */
  #winMascot img { filter: var(--sha-tint, brightness(1)) drop-shadow(0 6px 9px rgba(40,20,8,.42)); }

  /* ── Wardrobe (Sha costumes) ── */
  #wardrobe {
    position: fixed;
    inset: 0;
    isolation: isolate;
    background:
      linear-gradient(180deg, rgba(3,8,7,.04), rgba(3,8,7,.18) 46%, rgba(3,8,7,.62) 100%),
      url('../../assets/wardrobe/fitting_room_bg.webp') center top / cover no-repeat;
    overflow: hidden;
  }
  #wardrobe::before {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    background:
      radial-gradient(circle at 50% 42%, rgba(255,225,119,.18), transparent 30%),
      radial-gradient(circle at 50% 68%, rgba(255,220,99,.24), transparent 22%),
      linear-gradient(90deg, rgba(0,0,0,.22), transparent 24% 76%, rgba(0,0,0,.22)),
      linear-gradient(180deg, rgba(1,5,4,.12), transparent 18% 60%, rgba(1,5,4,.66));
  }
  #wardrobe .mapBar {
    position: relative;
    z-index: 2;
    width: 100%;
    max-width: 560px;
    margin: 0 auto;
    padding: calc(8px + env(safe-area-inset-top, 0px)) 12px 6px;
    display: grid;
    grid-template-columns: 54px minmax(0, 1fr) minmax(72px, auto);
    gap: 8px;
    align-items: center;
    background: none;
  }
  #wardrobeBack {
    width: 50px;
    height: 50px;
    border: 0;
    border-radius: 0;
    background: url('../../assets/badge/back_round.png') center / contain no-repeat;
    box-shadow: none;
    filter: drop-shadow(0 4px 4px rgba(18,10,4,.38));
  }
  #wardrobeBack .ico { display: none; }
  #wardrobe .mapTitle {
    min-width: 0;
    height: 50px;
    padding: 0 18px;
    display: flex;
    justify-content: center;
    align-items: center;
    background: url('../../assets/badge/row_bar.png') center / 100% 100% no-repeat;
    color: #fff3c6;
    font-size: clamp(18px, 5vw, 25px);
    font-weight: 950;
    line-height: 1;
    text-shadow: 0 2px 0 #4a260d, 0 4px 6px rgba(0,0,0,.42);
  }
  #wardrobe .mapStars {
    min-width: 72px;
    height: 42px;
    padding: 0 14px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 5px;
    background: url('../../assets/badge/count_tab.png') center / 100% 100% no-repeat;
    color: #ffe38b;
    font-size: 16px;
    font-weight: 950;
    white-space: nowrap;
    text-shadow: 0 2px 0 #4e2b0f, 0 3px 5px rgba(0,0,0,.35);
  }
  #wardrobe .wardrobePreview {
    position: relative;
    z-index: 3;                    /* render Sha + its stage pool OVER the tray top → "standing on the shelf" */
    /* shrunk (was 40vh/300–470) so the tray frame + its bottom nameplate clear the fixed 121px bottom nav —
       the nameplate ("거울 가면") was being covered by the nav (2026-06-24). 30vh keeps it adaptive. */
    flex: 0 0 clamp(196px, 30vh, 280px);
    width: min(100%, 560px);
    min-height: 0;
    margin: -2px auto 0;
    padding: clamp(12px, 2.4vh, 22px) 0 clamp(18px, 3.2vh, 30px);
    display: flex;
    justify-content: center;
    align-items: flex-end;
  }
  /* STAGE: a wide warm glow straddling the seam (dips onto the tray top) so the two halves read as one
     room — Sha stands on a lit shelf/stage, not on a hard dividing line. */
  #wardrobe .wardrobePreview::before {
    content: "";
    position: absolute;
    left: 50%;
    bottom: clamp(-36px, -4.6vh, -24px);
    transform: translateX(-50%);
    width: min(99%, 580px);
    height: clamp(80px, 14vh, 130px);
    z-index: 0;
    pointer-events: none;
    background: radial-gradient(ellipse at 50% 42%, rgba(255,243,182,.42), rgba(150,108,40,.16) 47%, transparent 71%);
    border-radius: 50%;
  }
  /* contact pool — Sha's feet meet the shelf right at the seam */
  #wardrobe .wardrobePreview::after {
    content: "";
    position: absolute;
    left: 50%;
    bottom: clamp(-16px, -1.6vh, -7px);
    width: min(60vw, 320px);
    height: clamp(34px, 6vh, 58px);
    transform: translateX(-50%);
    z-index: 0;
    background:
      radial-gradient(ellipse at 50% 28%, rgba(255,246,168,.72), rgba(160,112,34,.22) 44%, transparent 67%),
      radial-gradient(ellipse at 50% 68%, rgba(46,32,14,.52), rgba(22,15,8,.18) 60%, transparent 74%);
    border-radius: 50%;
    box-shadow: 0 9px 17px rgba(5,8,4,.38);
    opacity: .92;
  }
  /* STAGE FX stack — all behind Sha (preview img is z-index 1), layered for a lavish living spotlight. */
  #wardrobe .stageFx { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
  /* rotating god-rays — a radiant halo of light wedges spinning slowly behind Sha, with a warm↔cool shimmer */
  #wardrobe .stageRays {
    position: absolute;
    left: 50%; bottom: 4%;
    transform: translateX(-50%);
    width: min(132%, 660px); height: min(132%, 660px);
    pointer-events: none;
    background: repeating-conic-gradient(from 0deg,
      rgba(255,243,182,.20) 0deg 6deg, transparent 6deg 25deg);
    -webkit-mask: radial-gradient(circle at 50% 50%, #000 8%, rgba(0,0,0,.55) 34%, transparent 70%);
            mask: radial-gradient(circle at 50% 50%, #000 8%, rgba(0,0,0,.55) 34%, transparent 70%);
    mix-blend-mode: screen;
    filter: blur(2px);
    opacity: .6;
    animation: raysSpin 22s linear infinite, fxHue 9s ease-in-out infinite;
  }
  @keyframes raysSpin {
    from { transform: translateX(-50%) rotate(0deg); }
    to   { transform: translateX(-50%) rotate(360deg); }
  }
  @keyframes fxHue {
    0%,100% { filter: blur(2px) hue-rotate(0deg)   brightness(1); }
    50%     { filter: blur(2px) hue-rotate(-22deg) brightness(1.12); }
  }
  /* slow horizontal sweep glint crossing the stage */
  /* curtain-like L→R light sweep (stageSweep) removed 2026-06-23 — kept the spinning rays + footlight beam. */
  /* STAGE SPOTLIGHT: a soft warm beam thrown UP from the shelf onto Sha (footlight cone — narrow at the
     stage base, widening toward the character). Behind Sha, screen-blended so it reads as light, not haze. */
  #wardrobe .stageBeam {
    position: absolute;
    left: 50%;
    bottom: clamp(-6px, -0.6vh, 2px);
    transform: translateX(-50%);
    width: min(82%, 430px);
    height: clamp(236px, 46vh, 430px);
    z-index: 0;
    pointer-events: none;
    clip-path: polygon(35% 100%, 65% 100%, 96% 0, 4% 0);   /* narrow at the shelf, wide toward Sha */
    background: linear-gradient(0deg,
      rgba(255,240,165,.36) 4%,
      rgba(255,233,150,.19) 38%,
      rgba(255,228,138,.07) 70%,
      transparent 92%);
    filter: blur(8px);
    mix-blend-mode: screen;
    opacity: .92;
    animation: beamBreathe 4.2s ease-in-out infinite;   /* the light is alive — slow breathe + gentle sway */
  }
  @keyframes beamBreathe {
    0%,100% { opacity: .72; transform: translateX(-50%) scaleX(.92) rotate(-1.4deg); }
    50%     { opacity: 1;   transform: translateX(-50%) scaleX(1.10) rotate(1.4deg); }
  }
  /* dust motes drifting UP through the beam (clipped to the cone) → a living spotlight */
  #wardrobe .stageBeam::before, #wardrobe .stageBeam::after {
    content: ""; position: absolute; inset: 0; pointer-events: none;
    background-repeat: no-repeat;
    background-image:
      radial-gradient(circle, rgba(255,249,206,.95) 0, transparent 62%),
      radial-gradient(circle, rgba(255,244,182,.70) 0, transparent 62%),
      radial-gradient(circle, rgba(255,250,214,.85) 0, transparent 62%);
    background-size: 7px 7px, 5px 5px, 6px 6px;
    background-position: 30% 92%, 62% 72%, 46% 52%;
    animation: moteRise 5.2s linear infinite;
  }
  #wardrobe .stageBeam::after {
    animation-delay: 2.6s;
    background-position: 66% 90%, 38% 66%, 55% 46%;
    background-size: 5px 5px, 6px 6px, 4px 4px;
  }
  @keyframes moteRise {
    0%   { transform: translateY(12%);  opacity: 0; }
    18%  { opacity: 1; }
    82%  { opacity: 1; }
    100% { transform: translateY(-44%); opacity: 0; }
  }
  html[data-motion="reduced"] {
    #wardrobe .stageBeam { animation: none; opacity: .9; transform: translateX(-50%); }
    #wardrobe .stageBeam::before, #wardrobe .stageBeam::after { animation: none; opacity: .5; }
    #wardrobe .stageRays { animation: none; }
    #wardrobe .stageFx::before { animation: none; opacity: 0; }
  }
  #wardrobe .wardrobePreview img {
    position: relative;
    z-index: 1;
    width: clamp(190px, 50vw, 300px);
    max-height: clamp(240px, 38vh, 370px);
    object-fit: contain;
    filter: var(--preview-tint, brightness(1)) drop-shadow(0 9px 10px rgba(18,12,6,.46));
    transition: filter .25s ease, transform .25s ease;
    transform: translateY(2px);
  }
  @keyframes equipPop {
    0%   { transform: translateY(2px) scale(1); }
    35%  { transform: translateY(-6px) scale(1.07); }
    65%  { transform: translateY(1px) scale(0.97); }
    100% { transform: translateY(2px) scale(1); }
  }
  #wardrobe .wardrobePreview img.equipPop {
    animation: equipPop 0.42s cubic-bezier(.22,.61,.36,1) both;
  }
  /* Outer ornate tray frame RETIRED (2026-06-27): each costume card already carries its own frame
     (.costumeCard::before) → the second wrapping frame made layout (border-image insets) hard to manage and
     read as frame-in-frame. Now a flat flex-column panel: tab bar on top, scrolling card grid below. */
  #wardrobe .mapScroll {
    position: relative;
    z-index: 1;
    box-sizing: border-box;
    flex: 0 0 clamp(346px, calc(56vh - 92px), 500px);
    height: clamp(346px, calc(56vh - 92px), 500px);
    min-height: 0;
    width: 100%;
    max-width: 560px;
    margin: 2px auto 0;
    padding:
      clamp(8px, 2vw, 12px)
      clamp(8px, 2.2vw, 14px)
      calc(env(safe-area-inset-bottom,0px) + clamp(10px, 2.6vw, 16px));
    display: flex;
    flex-direction: column;
    border-radius: 20px;
    border: 1px solid rgba(120,86,44,.42);
    background:
      radial-gradient(ellipse 120% 64% at 50% 0%, rgba(92,66,36,.32), transparent 64%),
      linear-gradient(180deg, rgba(34,24,14,.60), rgba(15,10,6,.70));
    box-shadow: inset 0 1px 0 rgba(255,231,176,.12), 0 6px 18px rgba(5,8,4,.3);
    overflow: hidden;
  }
  /* name plate retired with the frame plaque it sat on — costume name now reads from the hero preview +
     each card's own label, so a separate plate is redundant. Element/JS kept inert to minimise churn. */
  #wardrobe .wardrobePlate { display: none; }
  /* ── wardrobe tabs: Daily 탭과 동일한 row_bar 디자인 언어 ── */
  #wardrobe .wardrobeTabs {
    flex: 0 0 auto;
    display: flex;
    gap: 4px;
    margin: 0 0 clamp(8px, 2vw, 12px);
    padding: 5px 6px 8px;
    background: linear-gradient(180deg, rgba(128,103,59,.18), rgba(248,237,202,.18));
  }
  #wardrobe .wardrobeTab {
    position: relative;
    flex: 1 1 0;
    min-width: 0;
    min-height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 0 6px 3px;
    border: 0;
    border-radius: 0;
    background: url('../../assets/badge/row_bar.png') center / 100% 100% no-repeat;
    color: rgba(255,246,226,.62);
    font-size: clamp(12px, 3.4vw, 14px);
    font-weight: 900;
    letter-spacing: .2px;
    text-shadow: 0 2px 0 #4a3214, 0 2px 4px rgba(0,0,0,.46);
    filter: grayscale(.3) brightness(.78);
    opacity: .76;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition: transform .12s, filter .12s, opacity .12s;
  }
  #wardrobe .wardrobeTab .wtCount {
    font-size: .78em;
    font-weight: 800;
    padding: 1px 6px;
    border-radius: 999px;
    background: rgba(0,0,0,.28);
    color: rgba(255,241,168,.75);
  }
  #wardrobe .wardrobeTab.active {
    color: #fff6e2;
    text-shadow: 0 2px 0 #4a3214, -1px 0 0 #4a3214, 1px 0 0 #4a3214, 0 2px 6px rgba(0,0,0,.58);
    filter: none;
    opacity: 1;
    transform: translateY(-1px);
    z-index: 2;
  }
  #wardrobe .wardrobeTab.active::after {
    content: "";
    position: absolute;
    left: 18%; right: 18%; bottom: 6px;
    height: 3px;
    border-radius: 999px;
    background: linear-gradient(90deg, transparent, #ecd590 30%, #cda53a 50%, #ecd590 70%, transparent);
    box-shadow: 0 0 4px rgba(255,226,112,.28);
    pointer-events: none;
  }
  #wardrobe .wardrobeTab.active .wtCount { background: rgba(0,0,0,.34); color: #ffe7b0; }
  .wardrobeIntro {
    margin: 0 0 clamp(10px, 2.5vw, 14px);
    padding: clamp(9px, 2.2vw, 12px) clamp(14px, 3.5vw, 18px);
    background: var(--grad-card);
    border: 1px solid var(--line);
    border-radius: 12px;
    box-shadow: var(--lift-sm), var(--sheen);
    font-size: clamp(11px, 2.8vw, 12.5px);
    font-weight: 600;
    color: #5c3515;
    text-align: center;
    line-height: 1.5;
  }
  .wardrobeIntro::before {
    content: "✦ ";
    color: #c8921a;
    font-weight: 700;
  }
  .wardrobeGrid {
    position: relative;
    box-sizing: border-box;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-auto-rows: min-content;   /* rows size to cards, not stretched to fill the flex track */
    gap: clamp(9px, 2.6vw, 14px);
    flex: 1 1 auto;
    min-height: 0;
    margin: 0;
    padding: 2px 2px clamp(12px, 3vw, 20px);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }
  .costumeCard {
    position: relative;
    min-height: clamp(198px, 29vh, 238px);
    padding:
      clamp(23px, 5vw, 31px)
      clamp(16px, 4.1vw, 23px)
      clamp(29px, 6.4vw, 38px);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    gap: clamp(6px, 1.8vw, 10px);
    border: 0;
    border-radius: 0;
    background: transparent;
    isolation: isolate;
    overflow: visible;
    filter: drop-shadow(0 5px 5px rgba(12,14,8,.32));
  }
  .costumeCard::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background: url('../../assets/wardrobe/card_frame.webp') center / 100% 100% no-repeat;
    filter: saturate(.98);
  }
  .costumeCard.equipped::before {
    filter: brightness(1.08) saturate(1.18) drop-shadow(0 0 10px rgba(255,226,92,.70));
  }
  .costumeCard.equipped::after {
    content: "";
    position: absolute;
    inset:
      clamp(15px, 4.2vw, 22px)
      clamp(15px, 4.2vw, 22px)
      clamp(26px, 5.8vw, 34px);
    z-index: -1;
    border-radius: 13px;
    background:
      linear-gradient(180deg, rgba(255,232,90,.24), rgba(123,211,72,.13)),
      radial-gradient(circle at 50% 24%, rgba(255,247,151,.45), transparent 56%);
    pointer-events: none;
  }
  /* locked = veiled silhouette in a lit display case → reads as an empty collection slot to fill
     (수집욕 레버 ②). The card frame stays lit (museum case); only the figure inside is veiled, and
     full-colour desire is restored in the big preview pane on tap/hover. */
  .costumeCard.locked { filter: brightness(.985) drop-shadow(0 4px 5px rgba(12,14,8,.26)); }
  .costumeCard.locked .cSwatch { filter: grayscale(1) brightness(.2) drop-shadow(0 5px 6px rgba(10,8,3,.5)); }
  .costumeCard.locked::after {
    content: "";
    position: absolute;
    top: clamp(58px, 13.5vw, 82px);
    left: 50%;
    width: clamp(30px, 8vw, 40px);
    height: clamp(30px, 8vw, 40px);
    transform: translateX(-50%);
    background: url('../../assets/badge/padlock.png') center / contain no-repeat;
    filter: drop-shadow(0 2px 3px rgba(0,0,0,.5)) brightness(1.12);
    opacity: .92;
    z-index: 1;
    pointer-events: none;
  }
  .costumeCard .cSwatch {
    width: clamp(100px, 28vw, 140px);
    height: clamp(108px, 30vw, 150px);
    object-fit: contain;
    object-position: center center;
    filter: drop-shadow(0 5px 6px rgba(14,10,4,.42));
    transform: none;
  }
  .costumeCard .cName {
    min-height: 26px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: clamp(12px, 3.45vw, 14px);
    font-weight: 950;
    color: #6b3912;
    text-align: center;
    line-height: 1.1;
    text-shadow: 0 1px 0 rgba(255,246,205,.72);
  }
  .costumeCard .cBtn {
    width: 100%;
    min-width: 0;
    min-height: 31px;
    margin-top: auto;
    padding: 0 5px 2px;
    display: flex; align-items: center; justify-content: center; gap: 3px; overflow: hidden;   /* center icon+value, clip overflow */
    border: 0;
    border-radius: 0;
    background: url('../../assets/common/btn_green.png') center / 100% 100% no-repeat;
    color: #fffbe8;
    font-size: clamp(12px, 3.4vw, 14px);
    font-weight: 950;
    line-height: 1;
    white-space: nowrap;
    cursor: pointer;
    text-shadow: 0 2px 0 #25510e, 0 3px 4px rgba(0,0,0,.28);
    filter: drop-shadow(0 3px 3px rgba(14,10,4,.34));
  }
  .costumeCard .cBtn .starIco { width: 1em; height: 1em; vertical-align: 0; }   /* smaller star so icon+price fits the chip */
  .costumeCard .cBtn.cBuy {
    background: linear-gradient(180deg, #f0e0bf, #b8a07a);
    border: 2px solid rgba(113,79,35,.45);
    border-radius: 7px;
    color: #5a310c;
    text-shadow: 0 1px 0 rgba(255,246,198,.82);
  }
  .costumeCard .cBtn.cAd {
    background:
      linear-gradient(180deg, rgba(95,169,232,.95), rgba(36,89,151,.95)),
      url('../../assets/common/btn_green.png') center / 100% 100% no-repeat;
    background-blend-mode: multiply, normal;
    text-shadow: 0 2px 0 #173a67, 0 3px 4px rgba(0,0,0,.28);
  }
  .costumeCard .cBtn:disabled {
    cursor: default;
    filter: grayscale(.55) brightness(.74) drop-shadow(0 3px 3px rgba(14,10,4,.26));
    opacity: .72;
  }
  /* 창문 게이트 진행칩(미달) — 맵 창문칩과 같은 gallery 아이콘. 탭하면 맵으로 (창문 얻는 곳). */
  .costumeCard .cBtn.cWinGate {
    background: linear-gradient(180deg, #efe2c0, #c2a878); border: 2px solid rgba(113,79,35,.5); border-radius: 7px;
    color: #5a3410; text-shadow: 0 1px 0 rgba(255,246,198,.7); gap: 5px;
  }
  .costumeCard .cBtn.cWinGate .ico { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 2; flex: none; }
  .costumeCard .cBtnRow {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 5px;
    width: 100%;
    margin-top: auto;
  }
  .costumeCard .cOwned {
    min-width: 90px;
    min-height: 29px;
    margin-top: auto;
    padding: 6px 14px 0;
    background: url('../../assets/badge/count_tab.png') center / 100% 100% no-repeat;
    color: #cfff9b;
    font-size: 12px;
    font-weight: 950;
    text-align: center;
    text-shadow: 0 2px 0 #25510e, 0 3px 4px rgba(0,0,0,.30);
  }
  @media (max-height: 700px) {
    #wardrobe .wardrobePreview { flex-basis: clamp(150px, 24vh, 210px); padding-top: 4px; }   /* shorter screens: keep tray + nameplate above the bottom nav */
    #wardrobe .wardrobePreview img { width: clamp(158px, 43vw, 238px); max-height: clamp(190px, 34vh, 292px); }
    #wardrobe .mapScroll {
      flex-basis: clamp(340px, 50vh, 430px);
      height: clamp(340px, 50vh, 430px);
      margin-top: 2px;
    }
    .costumeCard { min-height: clamp(176px, 31vh, 214px); }
    .costumeCard .cSwatch { width: clamp(80px, 22vw, 104px); height: clamp(86px, 23vw, 110px); }
  }
  @media (min-width: 640px) {
    .wardrobeGrid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    /* iPad+: mascot image capped to fit inside the 228px inner content area → no HUD overlap */
    #wardrobe .wardrobePreview img {
      width: clamp(140px, 22vw, 210px);
      max-height: clamp(160px, 18vh, 216px);
    }
    /* iPad+: grid tray fills remaining space instead of fixed height → no dead space above nav.
       Reserve the fixed bottom nav's height (≈121px stone slab + safe-area) as bottom margin so the
       tray ends AT the nav top, not the viewport bottom — otherwise the last grid rows scroll behind
       the fixed nav (z-index 6) and their 구매 buttons become untappable (iPad, 3+ rows of items). */
    #wardrobe .mapScroll {
      flex: 1 1 auto;
      height: auto;
      max-height: none;
      margin-bottom: calc(env(safe-area-inset-bottom, 0px) + 124px);
    }
  }
  /* ④ gentle help: after a long pause (#game.idleHelp ≈30s), the Hint button softly breathes a warm glow —
     "stuck? a hint is here." No scale jump, no flash, no urgency (no-pressure pillar). */
  body:not(.reward-sequence) #game.idleHelp #solveBtn:not(:disabled) { animation: hintBreathe 2.4s ease-in-out infinite; }
  @keyframes hintBreathe {
    0%, 100% { filter: drop-shadow(0 4px 4px rgba(48,28,10,.34)); }
    50%      { filter: drop-shadow(0 4px 4px rgba(48,28,10,.34)) drop-shadow(0 0 9px rgba(255,210,120,.85)); }
  }
  html[data-motion="reduced"] {
    body:not(.reward-sequence) #game.idleHelp #solveBtn:not(:disabled) {
      animation: none; filter: drop-shadow(0 4px 4px rgba(48,28,10,.34)) drop-shadow(0 0 7px rgba(255,210,120,.6));
    }
  }
  #game .cell .clue {
    font-size: clamp(30px, calc(var(--cell-px, 70px) * .62), 48px);
    font-weight: 950;
    color: #fff;
    text-shadow:
      0 3px 0 #142437,
      2px 0 0 #142437,
      -2px 0 0 #142437,
      0 -2px 0 #142437,
      0 5px 7px rgba(0,0,0,.35);
  }

  /* Status & legend: white text on garden bg */
  #game #status {
    display: block;
    position: relative; z-index: 10;
    height: 30px;
    min-height: 30px;
    margin: -6px 0 -2px;
    color: #fff8ef;
    font-size: clamp(18px, 5.2vw, 28px);
    font-weight: 950;
    line-height: 1.1;
    visibility: hidden;
    white-space: nowrap;
    pointer-events: none;
    text-shadow:
      0 3px 0 #4b1b13,
      2px 0 0 #4b1b13,
      -2px 0 0 #4b1b13,
      0 -2px 0 #4b1b13,
      0 5px 7px rgba(46,11,2,.35);
  }
  #game #status.ok,
  #game #status.warn { visibility: visible; }
  /* hint banner: gold (distinct from green .ok / red .warn), plays a brief rise-hold-fade so it reads
     as a MOMENT — the "인정" beat naming what the hint just did. Ends hidden (fill: both → opacity 0). */
  #game #status.hint { visibility: visible; color: #ffe7a3; animation: hintBanner 2.1s ease-out both; }
  @keyframes hintBanner {
    0%   { opacity: 0; transform: translateY(5px) scale(.96); }
    14%  { opacity: 1; transform: translateY(0) scale(1); }
    78%  { opacity: 1; transform: translateY(0) scale(1); }
    100% { opacity: 0; transform: translateY(0) scale(1); }
  }
  html[data-motion="reduced"] { #game #status.hint { animation: none; opacity: 1; } }
  #gameGuide {
    position: relative;
    z-index: 10;
    color: #fff8ef;
    font-size: clamp(15px, 4vw, 19px);
    font-weight: 800;
    line-height: 1.15;
    text-align: center;
    letter-spacing: 0;
    max-width: 92vw;
    margin-left: auto;
    margin-right: auto;
    white-space: normal;
    text-shadow: 0 2px 4px rgba(46,11,2,.45);
  }
  /* (legacy #game .legend / .dot / swatch CSS removed — legend is display:none in shape mode,
     replaced by the shape palette in render(); the game_swatch_*.webp it used are deleted.) */

  /* Action buttons row: no card background */
  #game .controls {
    background: none;
    border: none;
    box-shadow: none;
    padding: 0;
    gap: clamp(14px, 5vw, 22px);
    /* flow right below the instruction (was absolute-bottom) so the whole stack packs toward the top;
       the leftover space falls to the bottom of the screen. */
    position: static;
    margin: clamp(4px, 1.2vh, 12px) auto 0;
    z-index: 10;
  }

  /* Bottom action bar: icon-only controls for localization-safe play. */
  #game .controls .gameActBtn {
    position: relative;
    display: grid;
    place-items: center;
    width: clamp(62px, 16vw, 80px) !important;
    height: clamp(62px, 16vw, 80px) !important;
    min-width: 0 !important;
    padding: 0 !important;
    border-radius: 50% !important;
    border: none !important;
    background-color: transparent !important;
    background-image: var(--act-bg) !important;
    background-position: center !important;
    background-size: contain !important;
    background-repeat: no-repeat !important;
    color: #fff3c8;
    box-shadow: none !important;
    filter: drop-shadow(0 4px 4px rgba(48,28,10,.34));
    -webkit-tap-highlight-color: transparent;
    transition: transform .12s ease, filter .12s ease, box-shadow .12s ease;
  }
  #game .controls .gameActBtn::before {
    content: none;
  }
  #game .controls .gameActBtn::after {
    content: none;
  }
  #game .controls .gameActBtn svg {
    display: none;
  }
  #game .controls .gameActBtn:active {
    transform: scale(0.9);
  }
  #undoBtn   { --act-bg: url('../../assets/stage/btn_action_undo.png');  }
  #restartBtn { --act-bg: url('../../assets/stage/btn_action_reset.png'); }
  #solveBtn  { --act-bg: url('../../assets/stage/btn_action_hint.png');  }
  #menuBtn   { --act-bg: url('../../assets/stage/btn_action_menu.png');  }
  /* per-attempt Undo budget: dim when spent (disabled), and show the remaining count as a small badge */
  #game .controls #undoBtn:disabled { filter: grayscale(.8) drop-shadow(0 4px 4px rgba(48,28,10,.34)); opacity: .42; cursor: default; }
  #game .controls #undoBtn:disabled:active { transform: none; }
  #undoBtn .undoCount {
    position: absolute; top: -2px; right: -2px; z-index: 3;
    min-width: 18px; height: 18px; padding: 0 3px; box-sizing: border-box;
    display: grid; place-items: center; border-radius: 999px;
    font-size: 11px; font-weight: 900; line-height: 1; color: #5a3c08;
    background: radial-gradient(circle at 50% 32%, #fff3c8, #ffce5e 52%, #f0a81f);
    border: 1.5px solid #fff6e0; box-shadow: 0 1px 3px rgba(8,50,90,.5); }
  #undoBtn:disabled .undoCount { background: #c9c2b4; border-color: #e8e3d8; color: #6b6658; }

  #gameMenu {
    position: fixed;
    inset: 0;
    z-index: 61;
    display: none;
    align-items: flex-end;
    justify-content: center;
    padding: 0 18px calc(env(safe-area-inset-bottom,0px) + 98px);
    background: rgba(20,29,18,.08);
  }
  #gameMenu.show { display: flex; }
  .gameMenuTray {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;   /* center the single actions row (wallet row removed → was top-pinned) */
    gap: 8px;
    box-sizing: border-box;
    width: min(88vw, 356px);
    min-height: 90px;
    padding: 0;
    /* 9-slice the statusbar STONE FRAME so its rounded corners stay crisp + even at the menu's size.
       (was: bg stretched to 100%×100% + border-radius:999px → the pill clipped the corners unevenly,
       and the wrong aspect distorted them.) Frame fixed; only the centre stretches to hold the buttons. */
    border-style: solid;
    border-width: 16px;
    border-image: url('../../assets/stage/statusbar.webp') 40 fill / 16px / 0 stretch;
    border-radius: 0;
    background: none;
    box-shadow: none;
    filter: drop-shadow(0 6px 8px rgba(36,22,8,.34));
  }
  .gameMenuActions {
    display: flex;
    justify-content: center;
    gap: 14px;
  }
  .gameMenuBtn {
    position: relative;
    display: grid;
    place-items: center;
    width: 50px;
    height: 50px;
    min-width: 0;
    padding: 0;
    border-radius: 50%;
    border: none;
    color: #fff4cf;
    background:
      radial-gradient(circle at 50% 51%, #637b67 0 43%, #334d3e 44% 56%, transparent 57%),
      radial-gradient(circle at 44% 39%, #fff0bc 0 8%, #bdae77 28%, #627056 58%, #273b2f 100%);
    box-shadow: inset 0 2px 0 rgba(255,255,224,.25), 0 2px 3px rgba(42,24,8,.22);
  }
  .gameMenuBtn[hidden] { display: none; }   /* .gameMenuBtn sets display:grid, which would override [hidden]'s UA display:none */
  .gameMenuBtn .ico { width: 24px; height: 24px; stroke-width: 2.2; }
  /* skip = » glyph (same mark as the skipped-node map badge) — clearer than a compass for "skip stage" */
  .gameMenuBtn.skipGlyph { font-size: 30px; font-weight: 900; line-height: 1; padding-bottom: 5px; }
  .heartNote {
    position: relative;
    width: fit-content;
    max-width: 100%;
    margin: 8px auto 14px;
    padding: 5px 12px 4px;
    border-radius: 999px;
    border: 1px solid rgba(150,90,30,.26);
    background: rgba(255,246,218,.52);
    color: #7d5130;
    font-size: 13px;
    font-weight: 900;
    line-height: 1.2;
    text-shadow: 0 1px 0 rgba(255,246,205,.58);
  }
  .heartNote .ico {
    width: 14px;
    height: 14px;
    margin-right: 4px;
    color: #e8475c;
    vertical-align: -2px;
  }
  #noDragsLifeBal.heartNote { margin: 10px auto 0; background: rgba(42,31,20,.72); color: #ffe6a2; border-color: rgba(255,218,127,.28); text-shadow: 0 2px 2px rgba(0,0,0,.45); }

  /* the green button graphic is baked into the frame image; #winNext is the transparent label + tap
     target sitting over it (width/height cover the baked button; top % set in the positioning block). */
  #win #winNext {
    width: 54%;
    height: 13%;
    white-space: nowrap;
    border: none;
    border-radius: 0;
    background: transparent;
    box-shadow: none;
    display: flex; align-items: center; justify-content: center;
    color: #fff6df;
    font-family: 'Jua', system-ui, sans-serif;
    font-size: clamp(19px, 5.4vw, 24px);
    font-weight: 400;
    text-shadow:
      0 2px 0 #1f7a27,
      0 3px 5px rgba(8,60,16,.45),
      1px 0 0 #1f7a27,
      -1px 0 0 #1f7a27;
  }
  #win #winNext:active {
    transform: translateY(3px) scale(.98);
    box-shadow: 0 3px 7px rgba(28,40,12,.3);
  }

  /* ── Scene Overlay ── */
  #sceneOverlay { position: fixed; inset: 0; z-index: 150; display: none; overflow: hidden; cursor: pointer; }
  #sceneOverlay.active { display: block; animation: scFadeIn .45s ease forwards; }
  #sceneBg { position: absolute; inset: 0; background-size: cover; background-position: center; }
  /* slow ken-burns so the scene keeps gentle life (never a dead freeze) while dialogue is read */
  #sceneOverlay.active #sceneBg { animation: scKenBurns 22s ease-out both; transform-origin: 50% 42%; }
  @keyframes scKenBurns { from { transform: scale(1.02); } to { transform: scale(1.13) translateY(-2%); } }
  #sceneVideo { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: none;
    transform-origin: 50% 42%; }
  /* one-shot video ends → HOLD the last frame with a gentle ken-burns (never rewind to the start poster,
     never a dead freeze). Role shapes the hold: payoff pushes IN (climax), preview drifts calmly (여운). */
  #sceneVideo.scHoldPayoff  { animation: scVideoPayoff 16s ease-out forwards; }
  #sceneVideo.scHoldPreview { animation: scVideoPreview 16s ease-out forwards; }
  @keyframes scVideoPayoff  { from { transform: scale(1); filter: brightness(1); } to { transform: scale(1.08) translateY(-2%); filter: brightness(1.06); } }
  @keyframes scVideoPreview { from { transform: scale(1); } to { transform: scale(1.04) translateY(-1%); } }
  #sceneChar { position: absolute; bottom: 148px; right: 12px;
               height: 52vh; max-height: 340px; object-fit: contain; pointer-events: none;
               animation: scCharIn .5s .1s ease both; }
  #scenePanel { position: absolute; bottom: 0; left: 0; right: 0;
                background: linear-gradient(transparent, rgba(0,0,0,.8) 40%);
                padding: 52px 22px 38px; min-height: 148px; }
  #sceneTitle { font-size: 11px; font-weight: 700; color: rgba(255,255,255,.55);
                letter-spacing: .1em; text-transform: uppercase; margin: 0 0 6px; }
  #sceneDialog { font-size: 17px; font-weight: 500; line-height: 1.6; color: #fff;
                 margin: 0; min-height: 54px; }
  #sceneProgress { display: flex; justify-content: center; gap: 6px; min-height: 8px; margin-top: 7px; }
  #sceneProgress i { width: 6px; height: 6px; border-radius: 50%; background: rgba(255,255,255,.28); box-shadow: 0 1px 2px rgba(0,0,0,.45); }
  #sceneProgress i.on { background: #ffe6a0; box-shadow: 0 0 8px rgba(255,218,110,.7); }
  #sceneContinue { display: block; text-align: right; font-size: 18px; color: rgba(255,255,255,.5);
                   margin-top: 6px; opacity: 0; transition: opacity .3s;
                   animation: scPulse 1.1s ease-in-out infinite; }
  #sceneSkipBtn { position: absolute; top: calc(env(safe-area-inset-top,0px) + 14px); right: 16px;
                  background: rgba(0,0,0,.38); color: rgba(255,255,255,.65);
                  border: 1px solid rgba(255,255,255,.22); border-radius: 20px;
                  padding: 5px 14px; font-size: 12px; font-weight: 600; letter-spacing: .04em;
                  cursor: pointer; z-index: 1; }
  @keyframes scFadeIn  { from { opacity: 0 } to { opacity: 1 } }
  @keyframes scCharIn  { from { opacity: 0; transform: translateY(28px) } to { opacity: 1; transform: translateY(0) } }
  @keyframes scPulse   { 0%,100% { opacity: .4 } 50% { opacity: .9 } }
  html[data-motion="reduced"] { #sceneContinue, #sceneVideo.scHoldPayoff, #sceneVideo.scHoldPreview { animation: none; } }

  /* ═══════════ TABLET / WIDE (≥640px: iPad 10", tablets) ═══════════ */
  @media (min-width: 640px) {
    /* top nav bar + game HUD */
    .mapBar, #hud         { max-width: 700px; }
    /* map / achievements scrollable content */
    .mapScroll            { max-width: 700px; }
    /* settings content column */
    #settings .mapScroll  { max-width: 660px; }
    /* shop top bar + content */
    #shop .mapBar         { max-width: 700px; }
    #shop .mapScroll      { max-width: 660px; }
    /* gallery: wider journey column */
    /* title nav bar — cap width AND CENTER it. Base sets left+right(!important); adding only `width`
       over-constrains the fixed box → it pins to the left. Switch to left:50% + translateX to center. */
    .titleNav { left: 50% !important; right: auto !important; transform: translateX(-50%); width: min(100%, 600px); }
  }
