/* ==========================================================================
   Hands of the Unbound — presentation
   ==========================================================================
   Colour carries meaning here rather than decoration. The four suits are the
   four combat affinities, so every card, pip and particle that refers to a suit
   uses the same hue as the affinity it grants; a player learns "orange means
   Strength" once and it holds everywhere.
   ========================================================================== */

:root {
  --bg-0: #080918;
  --bg-1: #151333;
  --bg-2: #202452;
  --panel: rgba(25, 28, 66, 0.82);
  --panel-solid: #1b1e48;
  --edge: rgba(170, 190, 255, 0.13);
  --edge-bright: rgba(205, 216, 255, 0.25);

  --ink: #eef1ff;
  --ink-dim: #9aa2cc;
  --ink-faint: #626a96;

  --gold: #ffd36e;
  --gold-deep: #d99a2b;
  --danger: #ff4d6d;
  --good: #8bffb0;
  --ice: #7ee6ff;
  --violet: #9d7bff;
  --teal: #45e0c1;

  /* Suit = combat affinity */
  --strength: #ff8a3d;   /* Clubs   */
  --agility: #46d66f;    /* Spades  */
  --elemental: #ff5fa2;  /* Hearts  */
  --arcane: #b07cff;     /* Diamonds*/

  --chips: #6fb3ff;
  --mult: #ff6b6b;

  --r-sm: 8px;
  --r-md: 14px;
  --r-lg: 22px;

  --shadow-1: 0 2px 8px rgba(0, 0, 0, .4);
  --shadow-2: 0 10px 30px rgba(0, 0, 0, .5);
  --shadow-3: 0 24px 60px rgba(0, 0, 0, .6);

  --font: ui-rounded, "SF Pro Rounded", "Segoe UI", Inter, system-ui, -apple-system, sans-serif;
  --font-num: "SF Mono", ui-monospace, "Cascadia Mono", Menlo, Consolas, monospace;
}

*, *::before, *::after { box-sizing: border-box; }

html, body {
  height: 100%;
  margin: 0;
}

body {
  font-family: var(--font);
  color: var(--ink);
  background: var(--bg-0);
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
  opacity: 0;
  transition: opacity .5s ease;
}
body.ready { opacity: 1; }

/* Slow drifting nebula, so a static screen still breathes. */
body::before {
  content: "";
  position: fixed;
  inset: -30%;
  z-index: -2;
  background:
    radial-gradient(50% 45% at 16% 22%, rgba(126, 82, 255, .3), transparent 65%),
    radial-gradient(45% 40% at 84% 72%, rgba(255, 80, 156, .22), transparent 65%),
    radial-gradient(60% 50% at 55% 12%, rgba(55, 205, 255, .19), transparent 70%),
    radial-gradient(42% 38% at 18% 82%, rgba(45, 224, 177, .12), transparent 70%),
    linear-gradient(160deg, var(--bg-1), var(--bg-0) 60%);
  animation: drift 42s ease-in-out infinite alternate;
}
@keyframes drift {
  from { transform: translate3d(-2%, -1%, 0) scale(1.05) rotate(0deg); }
  to   { transform: translate3d(3%, 2%, 0) scale(1.15) rotate(6deg); }
}

/* Faint felt weave over everything. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: .35;
  background-image:
    repeating-linear-gradient(45deg, rgba(255,255,255,.014) 0 2px, transparent 2px 4px),
    repeating-linear-gradient(-45deg, rgba(0,0,0,.05) 0 2px, transparent 2px 4px);
}

#app {
  position: relative;
  height: 100%;
  /* Size queries ask the app, not the window: on the landscape stage the app
     is laid out at least 1280 wide however small the window it is scaled into. */
  container: app / size;
  display: flex;
  flex-direction: column;
  will-change: transform;
}

.screen {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  padding: 14px clamp(12px, 3vw, 34px) 16px;
  gap: 12px;
  overflow: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--edge-bright) transparent;
}
.screen::-webkit-scrollbar { width: 8px; }
.screen::-webkit-scrollbar-thumb { background: var(--edge-bright); border-radius: 99px; }

/* ==========================================================================
   Buttons
   ========================================================================== */

button {
  font-family: inherit;
  font-size: 15px;
  font-weight: 700;
  color: var(--ink);
  background:
    radial-gradient(130% 100% at 20% 0%, rgba(157,123,255,.13), transparent 58%),
    linear-gradient(180deg, rgba(255,255,255,.11), rgba(255,255,255,.035));
  border: 1px solid var(--edge-bright);
  border-radius: var(--r-md);
  padding: 10px 18px;
  cursor: pointer;
  letter-spacing: .02em;
  box-shadow: var(--shadow-1), inset 0 1px 0 rgba(255,255,255,.14);
  transition: transform .12s cubic-bezier(.3,1.4,.4,1), filter .16s, box-shadow .16s, opacity .16s, translate .12s cubic-bezier(.3,1.4,.4,1), scale .12s cubic-bezier(.3,1.4,.4,1);
}
button:hover:not(:disabled) { translate: 0 -2px; filter: brightness(1.16); box-shadow: var(--shadow-2), inset 0 1px 0 rgba(255,255,255,.2); }
button:active:not(:disabled) { translate: 0 1px; scale: .98; filter: brightness(.94); }
button:disabled { opacity: .34; cursor: not-allowed; filter: grayscale(.6); }
button:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }

.primary {
  background: linear-gradient(180deg, #ffe19a, var(--gold) 45%, var(--gold-deep));
  color: #241a05;
  border-color: rgba(255, 230, 160, .8);
  text-shadow: 0 1px 0 rgba(255,255,255,.35);
}
.primary.big { font-size: 19px; padding: 15px 40px; border-radius: var(--r-lg); }
.ghost { background: rgba(255,255,255,.05); }
.buy {
  background: linear-gradient(180deg, #7be495, #35a95c);
  color: #052312;
  border-color: rgba(180,255,200,.6);
  padding: 8px 16px;
  width: 100%;
  margin-top: auto;
}

/* ==========================================================================
   Top bar
   ========================================================================== */

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 10px 18px;
  background:
    radial-gradient(110% 160% at 0% 0%, rgba(85,214,255,.13), transparent 56%),
    radial-gradient(90% 160% at 100% 100%, rgba(176,124,255,.13), transparent 58%),
    var(--panel);
  backdrop-filter: blur(14px);
  border: 1px solid var(--edge);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-1);
  flex-wrap: wrap;
}
.topbar-left, .topbar-right, .topbar-budget { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }

.stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-width: 68px;
  padding: 4px 12px;
  border-radius: var(--r-sm);
  background: linear-gradient(180deg, rgba(17,19,49,.82), rgba(7,8,25,.58));
  border: 1px solid var(--edge);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.055);
}
.stat-label { font-size: 9px; letter-spacing: .16em; color: var(--ink-faint); text-transform: uppercase; }
.stat-value { font-family: var(--font-num); font-size: 18px; font-weight: 700; }
.stat.floor { border-color: rgba(176,124,255,.34); background: linear-gradient(180deg, rgba(98,65,173,.3), rgba(17,14,48,.72)); }
.stat.floor .stat-value { color: #d6c3ff; text-shadow: 0 0 13px rgba(176,124,255,.55); }
.stat.encounter-stat { border-color: rgba(255,95,162,.3); background: linear-gradient(180deg, rgba(139,44,88,.26), rgba(42,13,35,.66)); }
.stat.encounter-stat .stat-value { color: #ffb4d4; }
.stat.money .stat-value { color: var(--gold); }
.stat.hands .stat-value { color: var(--ice); }
.stat.hands { border-color: rgba(85,214,255,.3); background: linear-gradient(180deg, rgba(31,108,143,.26), rgba(11,36,58,.68)); }
.stat.hands.warning {
  border-color: rgba(255,166,72,.7);
  background: linear-gradient(180deg, rgba(157,82,21,.72), rgba(69,31,8,.88));
  box-shadow:
    0 0 0 1px rgba(255,184,92,.12),
    0 0 20px rgba(255,132,48,.24),
    inset 0 1px 0 rgba(255,230,190,.16);
}
.stat.hands.warning .stat-label { color: #ffd0a0; }
.stat.hands.warning .stat-value {
  color: #ffb15f;
  text-shadow: 0 0 15px rgba(255,135,54,.76);
}
.stat.hands.critical {
  border-color: rgba(255,77,109,.92);
  background: linear-gradient(180deg, rgba(164,27,59,.88), rgba(75,8,27,.95));
  animation: handsCritical .82s ease-in-out infinite;
}
.stat.hands.critical .stat-label { color: #ffd6df; }
.stat.hands.critical .stat-value {
  color: #fff;
  text-shadow: 0 0 10px #fff, 0 0 22px rgba(255,77,109,1);
}
@keyframes handsCritical {
  0%, 100% {
    transform: scale(1);
    filter: brightness(1);
    box-shadow:
      0 0 0 1px rgba(255,77,109,.22),
      0 0 16px rgba(255,30,76,.32),
      inset 0 1px 0 rgba(255,255,255,.16);
  }
  50% {
    transform: scale(1.055);
    filter: brightness(1.36);
    box-shadow:
      0 0 0 2px rgba(255,128,150,.48),
      0 0 34px 5px rgba(255,30,76,.68),
      inset 0 1px 0 rgba(255,255,255,.28);
  }
}
.stat.discards { border-color: rgba(69,224,193,.28); background: linear-gradient(180deg, rgba(25,119,103,.24), rgba(9,48,46,.65)); }
.stat.discards .stat-value { color: #91f4df; }
.stat.money { border-color: rgba(255,211,110,.32); background: linear-gradient(180deg, rgba(137,96,22,.25), rgba(52,36,6,.66)); }

/* Hearts were cut along with the Break stance - see combat/encounter.ts. The
   hand budget is the only clock now, so there is no second health bar to draw. */

/* ==========================================================================
   Encounter
   ========================================================================== */

.encounter { display: flex; flex-direction: column; gap: 10px; }

.intent {
  align-self: center;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 20px;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: .04em;
  color: #ffe6b0;
  background: linear-gradient(90deg, transparent, rgba(255,180,60,.2), transparent);
  border-top: 1px solid rgba(255,190,90,.35);
  border-bottom: 1px solid rgba(255,190,90,.35);
  text-align: center;
}
.intent-icon { filter: drop-shadow(0 0 6px rgba(255,190,90,.9)); }

.enemy-row {
  display: flex;
  gap: clamp(10px, 2vw, 24px);
  /* Bottom-aligned so the size difference between tiers reads as height on a
     shared ground line rather than as arbitrary boxes floating at centre. */
  align-items: flex-end;
  justify-content: center;
  flex-wrap: wrap;
  padding: 6px 0;
}

.enemy {
  position: relative;
  width: clamp(120px, 15vw, 172px);
  padding: 12px 12px 14px;
  text-align: center;
  overflow: hidden;
  background:
    radial-gradient(110% 90% at 50% 0%, rgba(255,92,136,.18), transparent 58%),
    linear-gradient(180deg, rgba(64,28,61,.94), rgba(27,16,43,.95));
  border: 1px solid rgba(255,120,176,.32);
  border-radius: var(--r-md);
  box-shadow: 0 12px 30px rgba(3,4,14,.54), 0 0 24px rgba(255,77,109,.08), inset 0 1px 0 rgba(255,255,255,.1);
  transition: transform .2s, filter .2s, opacity .3s, translate .2s, scale .2s;
}
.enemy::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 3px;
  background: linear-gradient(90deg, transparent, #ff6caa, #9d7bff, transparent);
  opacity: .72;
}
.enemy.pending { opacity: .4; filter: grayscale(.8); }
.enemy.dead { opacity: .22; filter: grayscale(1); }
.enemy.struck { animation: enemyStruck .28s cubic-bezier(.3,1.4,.4,1); }
@keyframes enemyStruck {
  0% { transform: translateX(0) scale(1); filter: brightness(1); }
  25% { transform: translateX(-10px) scale(1.06); filter: brightness(3) saturate(0); }
  60% { transform: translateX(6px) scale(1.02); filter: brightness(1.4); }
  100% { transform: translateX(0) scale(1); filter: brightness(1); }
}
.enemy.dying { pointer-events: none; }

.enemy-art {
  font-size: clamp(38px, 5vw, 54px);
  line-height: 1.1;
  filter: drop-shadow(0 6px 12px rgba(0,0,0,.6));
  animation: idleBob 3.4s ease-in-out infinite;
}
.enemy:nth-child(2n) .enemy-art { animation-delay: -1.1s; }
.enemy:nth-child(3n) .enemy-art { animation-delay: -2.2s; }

/* Creature portraits ------------------------------------------------------
   Height is the whole point of this block. A Patrol creature is drawn small, an
   Elite noticeably larger, and the Warden larger than both, so the tier of the
   fight is legible from the silhouettes alone. `--portrait` carries the height
   so the responsive blocks below can retune one number per breakpoint instead
   of restating every rule. */
.enemy-portrait {
  --portrait: 96px;
  display: block;
  width: 100%;
  height: var(--portrait);
  object-fit: contain;
  /* The art ships on an opaque plate; a mask feathers the edge into the card so
     the portraits sit in the scene instead of on stickers. */
  -webkit-mask-image: radial-gradient(72% 78% at 50% 46%, #000 62%, transparent 100%);
  mask-image: radial-gradient(72% 78% at 50% 46%, #000 62%, transparent 100%);
}
.enemy-row.tier-patrol .enemy-portrait { --portrait: clamp(74px, 8vw, 96px); }
.enemy-row.tier-elite  .enemy-portrait { --portrait: clamp(94px, 10.5vw, 126px); }
.enemy-row.tier-warden .enemy-portrait { --portrait: clamp(104px, 11.5vw, 138px); }

/* The Warden itself, not its escorts. */
.enemy.boss { width: clamp(150px, 19vw, 216px); }
.enemy.boss .enemy-portrait { --portrait: clamp(150px, 17vw, 210px); }
.enemy.boss .enemy-name { font-size: 13px; color: #ffd9a0; letter-spacing: .07em; }
.enemy.boss::before {
  background: linear-gradient(90deg, transparent, #ffce6a, #ff6caa, transparent);
  opacity: 1;
  height: 4px;
}
.enemy.boss {
  border-color: rgba(255,206,106,.5);
  box-shadow: 0 16px 40px rgba(3,4,14,.62), 0 0 34px rgba(255,180,80,.2), inset 0 1px 0 rgba(255,255,255,.14);
}
@keyframes idleBob {
  0%, 100% { transform: translateY(0) rotate(-1.5deg); }
  50% { transform: translateY(-7px) rotate(1.5deg); }
}

/* ==========================================================================
   Hero combat rig
   ==========================================================================
   The player's own portrait, beside the hand rather than the enemy line - the
   swing fires off the cards being played, so the hero stands where the cards
   are. Lives inside .hand-with-piles, which every layout already places, so
   this needs no new grid-template-areas of its own. */
.hero-rig {
  position: relative;
  flex: 0 0 auto;
  width: clamp(84px, 9vw, 130px);
  aspect-ratio: 1;
  display: grid;
  place-items: center;
}
.hero-rig-body {
  position: relative;
  width: 100%;
  height: 100%;
  animation: heroBob 2.8s ease-in-out infinite;
}
.hero-rig-art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  filter: drop-shadow(0 8px 12px rgba(0,0,0,.55));
  user-select: none;
  -webkit-user-drag: none;
}
.hero-rig-plate {
  position: absolute;
  inset: 8%;
  display: grid;
  place-items: center;
  font-size: 28px;
  font-weight: 700;
  border-radius: 50%;
  background: radial-gradient(60% 60% at 50% 40%, rgba(176,124,255,.5), rgba(0,0,0,.3) 70%);
  color: #fff;
  text-shadow: 0 2px 8px rgba(0,0,0,.7);
}

@keyframes heroBob {
  0%, 100% { transform: translateY(0) scale(1, 1); }
  50% { transform: translateY(-1.9%) scale(.988, 1.016); }
}

/* Victory: a double hop on overshoot easing - lands heavier than it left, so
   the second hop reads as a smaller echo of the first rather than a repeat.
   The `.win` rule outranks the idle bob on specificity, so the bob pauses for
   the hop's 1.6s and resumes the instant `.win` is removed. */
.hero-rig.win .hero-rig-body { animation: heroVictoryHop 1.6s cubic-bezier(.3, 1.2, .4, 1) 1; }
@keyframes heroVictoryHop {
  0% { transform: none; }
  18% { transform: translateY(-12%) scale(.93, 1.09); }
  34% { transform: translateY(0) scale(1.08, .91); }
  50% { transform: translateY(-7%) scale(.97, 1.05); }
  66% { transform: translateY(0) scale(1.05, .95); }
  82% { transform: translateY(-2%) scale(.99, 1.02); }
  100% { transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .hero-rig-body { animation: none; }
  .hero-rig.win .hero-rig-body { animation: none; }
}

.enemy-name {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: #ffc9c9;
  margin: 4px 0 7px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.hp-bar {
  position: relative;
  height: 17px;
  border-radius: 99px;
  background: rgba(0,0,0,.55);
  border: 1px solid rgba(255,255,255,.13);
  overflow: hidden;
}
.hp-fill {
  position: absolute;
  inset: 0 auto 0 0;
  background: linear-gradient(90deg, #ff6b6b, #ffa25c);
  box-shadow: 0 0 14px rgba(255,110,110,.6);
  transition: width .45s cubic-bezier(.2,.9,.3,1);
}
.hp-fill.low { background: linear-gradient(90deg, #ff2d55, #ff6b6b); animation: hpPulse .9s ease-in-out infinite; }
@keyframes hpPulse { 0%,100% { filter: brightness(1); } 50% { filter: brightness(1.5); } }
.hp-text {
  position: relative;
  font-family: var(--font-num);
  font-size: 10px;
  font-weight: 700;
  line-height: 15px;
  text-shadow: 0 1px 3px #000;
}

.enemy-slain {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: 13px;
  font-weight: 800;
  letter-spacing: .16em;
  color: #ff8f8f;
  background: rgba(0,0,0,.45);
  border-radius: var(--r-md);
}

/* Meters ------------------------------------------------------------------ */

.meters { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }

.meter {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 8px 15px;
  background: var(--panel);
  border: 1px solid var(--edge);
  border-radius: 99px;
  box-shadow: var(--shadow-1);
}
.meter-icon { font-size: 19px; }
.meter-title { font-size: 12px; font-weight: 700; letter-spacing: .04em; }
.meter-body { display: flex; flex-direction: column; gap: 5px; }

.meter.shield { border-color: rgba(126,230,255,.42); background: linear-gradient(180deg, rgba(30,70,100,.6), rgba(20,40,66,.7)); }
.meter.shield.broken { border-color: rgba(255,190,90,.4); opacity: .8; }
.meter.charge { border-color: rgba(255,150,90,.34); }
/* The standing retaliation warning. It is armed from turn one and never
   counts down, so it reads as a rule of the room rather than as a timer. */
.meter.retaliate {
  border-color: rgba(255,120,90,.42);
  background: linear-gradient(180deg, rgba(88,28,30,.6), rgba(48,16,22,.72));
}
.meter.retaliate .meter-title { color: #ffbca8; }
/* Flares on the turn the player steps on it, then the next render clears it. */
.meter.retaliate.provoked {
  border-color: var(--danger);
  animation: alarm 1s ease-in-out 2;
}
@keyframes alarm {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255,77,109,.5); }
  50% { box-shadow: 0 0 26px 5px rgba(255,77,109,.55); }
}
@keyframes alarm {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255,77,109,.5); }
  50% { box-shadow: 0 0 26px 5px rgba(255,77,109,.55); }
}
.meter.stun-ready {
  border-color: var(--gold);
  background: linear-gradient(180deg, rgba(120,90,20,.7), rgba(70,50,10,.8));
  animation: stunGlow 1.3s ease-in-out infinite;
}
@keyframes stunGlow {
  0%, 100% { box-shadow: 0 0 12px rgba(255,211,110,.4); }
  50% { box-shadow: 0 0 34px 6px rgba(255,211,110,.75); }
}

/* The shield plate. Colour is the tier (red Warden, blue Elite) and the crack
   pattern is the progress, so the meter answers "how bad" and "how close"
   without either being read as text. */
.shield-art {
  width: 42px;
  height: 42px;
  object-fit: contain;
  filter: drop-shadow(0 3px 8px rgba(0,0,0,.6));
  flex: 0 0 auto;
}
.shield-art.shield-cracked { animation: shieldStrain 2.2s ease-in-out infinite; }
@keyframes shieldStrain {
  0%, 100% { transform: rotate(0deg) scale(1); }
  45% { transform: rotate(-3deg) scale(1.04); }
  70% { transform: rotate(2deg) scale(1.01); }
}
.meter.shield.broken .shield-art { opacity: .85; filter: drop-shadow(0 0 12px rgba(255,150,90,.55)); }

.shield-pips, .charge-pips { display: flex; gap: 5px; }
.pip {
  width: 24px;
  height: 7px;
  border-radius: 99px;
  background: rgba(255,255,255,.14);
  border: 1px solid rgba(255,255,255,.16);
  transition: background .25s, box-shadow .25s;
}
.shield-pips .pip.lit { background: var(--ice); box-shadow: 0 0 12px var(--ice); }
.charge-pips .pip.lit { background: #ff9a5c; box-shadow: 0 0 12px #ff9a5c; }

.armour-badge {
  font-family: var(--font-num);
  font-size: 11px;
  font-weight: 700;
  padding: 3px 9px;
  border-radius: 99px;
  background: rgba(0,0,0,.42);
  color: var(--ice);
  white-space: nowrap;
}
.meter.charge .armour-badge { color: #ffb98a; }

/* ==========================================================================
   Scoreboard
   ========================================================================== */

.scoreboard {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 12px;
  background:
    radial-gradient(80% 150% at 18% 50%, rgba(85,214,255,.1), transparent 58%),
    radial-gradient(80% 150% at 82% 50%, rgba(255,95,162,.1), transparent 58%),
    linear-gradient(180deg, rgba(31,35,82,.9), rgba(20,22,56,.86));
  border: 1px solid rgba(152,169,255,.18);
  border-radius: var(--r-lg);
  backdrop-filter: blur(12px);
}

.hand-name {
  font-size: 15px;
  font-weight: 800;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--gold);
  text-shadow: 0 0 22px rgba(255,211,110,.55);
  min-height: 20px;
}
.hand-name.slam { animation: nameSlam .34s cubic-bezier(.2,1.6,.4,1); }
@keyframes nameSlam {
  0% { transform: scale(1.7); opacity: 0; letter-spacing: .6em; }
  100% { transform: scale(1); opacity: 1; letter-spacing: .2em; }
}

.score-row { display: flex; align-items: center; gap: 12px; }

.chips-box, .mult-box {
  min-width: 116px;
  padding: 7px 18px;
  text-align: center;
  border-radius: var(--r-md);
  border: 1px solid var(--edge-bright);
}
.chips-box { background: linear-gradient(180deg, rgba(60,110,190,.55), rgba(24,48,96,.7)); }
.mult-box { background: linear-gradient(180deg, rgba(190,60,60,.55), rgba(96,24,24,.7)); }
.box-label { font-size: 9px; letter-spacing: .18em; color: rgba(255,255,255,.6); }

/* Banked Elemental charge. Sits under the Mult value it will be added to, so
   the relationship needs no explaining, and only exists while there is one. */
.elemental-charge {
  margin-top: 4px;
  display: inline-block;
  padding: 1px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .06em;
  color: #ffd7e8;
  background: rgba(255,95,162,.22);
  border: 1px solid rgba(255,95,162,.55);
  box-shadow: 0 0 14px rgba(255,95,162,.35);
  cursor: help;
}
.chips-value, .mult-value { font-family: var(--font-num); font-size: 27px; font-weight: 800; line-height: 1.15; }
.chips-value { color: #bcdcff; text-shadow: 0 0 18px rgba(110,180,255,.7); }
.mult-value { color: #ffbdbd; text-shadow: 0 0 18px rgba(255,110,110,.7); }
.chips-value.counting, .mult-value.counting, .total-value.counting {
  animation: numberRollBounce .14s ease-in-out infinite alternate;
  transform-origin: 50% 75%;
}
@keyframes numberRollBounce {
  from { transform: translateY(1px) scale(.99); filter: brightness(1); }
  to { transform: translateY(-2px) scale(1.035); filter: brightness(1.28); }
}
.times, .equals { font-size: 24px; font-weight: 800; color: var(--ink-dim); }

.total-box {
  min-width: 170px;
  padding: 7px 22px;
  text-align: center;
  border-radius: var(--r-md);
  background: linear-gradient(180deg, rgba(255,211,110,.24), rgba(140,100,20,.34));
  border: 1px solid rgba(255,211,110,.5);
}
.total-value {
  font-family: var(--font-num);
  font-size: 34px;
  font-weight: 800;
  color: var(--gold);
  text-shadow: 0 0 26px rgba(255,211,110,.8);
  line-height: 1.1;
}
.total-value.slam { animation: totalSlam .42s cubic-bezier(.2,1.7,.35,1); }
@keyframes totalSlam {
  0% { transform: scale(2.3); filter: brightness(2.6); }
  55% { transform: scale(.92); }
  100% { transform: scale(1); filter: brightness(1); }
}

.goal { width: min(100%, 560px); }
.goal-bar {
  position: relative;
  height: 9px;
  border-radius: 99px;
  background: rgba(0,0,0,.5);
  border: 1px solid var(--edge);
  overflow: hidden;
}
.goal-fill {
  height: 100%;
  border-radius: 99px;
  background: linear-gradient(90deg, var(--gold-deep), var(--gold), #fff3cf);
  box-shadow: 0 0 16px rgba(255,211,110,.75);
  transition: width .6s cubic-bezier(.2,.9,.3,1);
}
.goal-text { text-align: center; font-family: var(--font-num); font-size: 11px; color: var(--ink-dim); margin-top: 4px; }

/* The chest is a first-class objective, so it gets a real panel in the top bar
   rather than a 34px marker crammed onto the damage track. The earlier version
   was reported as "teenee tiny and so hard to read". */
.chest-art { object-fit: contain; display: block; }
.chest-badge {
  display: flex; align-items: center; gap: 12px;
  padding: 8px 16px 8px 10px;
  border-radius: var(--r-lg);
  cursor: help;
  background: radial-gradient(120% 140% at 12% 50%, rgba(255,211,110,.20), transparent 70%), rgba(0,0,0,.32);
  box-shadow: inset 0 0 0 1px rgba(255,211,110,.35);
  min-width: 260px;
}
.chest-badge-art { width: 52px; height: 52px; filter: drop-shadow(0 3px 7px rgba(0,0,0,.65)); }
.chest-badge:not(.open) .chest-badge-art { animation: chest-breathe 2.4s ease-in-out infinite; }
@keyframes chest-breathe { 50% { transform: scale(1.08); filter: brightness(1.18); } }
.chest-badge.open .chest-badge-art { filter: brightness(1.3) drop-shadow(0 0 12px rgba(255,211,110,.9)); }
.chest-badge-body { display: flex; flex-direction: column; gap: 5px; flex: 1 1 auto; min-width: 0; }
.chest-badge-title {
  font-size: 12px; font-weight: 800; letter-spacing: .08em; color: var(--gold);
  text-transform: uppercase; white-space: nowrap;
}
.chest-badge.open .chest-badge-title { color: var(--good); }
.chest-track {
  height: 7px; border-radius: 99px; overflow: hidden;
  background: rgba(0,0,0,.55); box-shadow: inset 0 0 0 1px var(--edge);
}
.chest-track-fill {
  height: 100%; border-radius: 99px;
  background: linear-gradient(90deg, var(--gold-deep), var(--gold), #fff3cf);
  box-shadow: 0 0 12px rgba(255,211,110,.7);
  transition: width .45s cubic-bezier(.2,.9,.3,1);
}
.chest-badge-sub { font-family: var(--font-num); font-size: 10px; color: var(--ink-dim); white-space: nowrap; }

.coin-bit { position: absolute; transform: translate(-50%,-50%); pointer-events: none; line-height: 1; }

/* Chest preview on a blind card, so the skip decision names its own price. */
.blind-chest {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  cursor: help;
  background: rgba(255,211,110,.08);
  border-color: rgba(255,211,110,.28);
}
.blind-chest-art { width: 26px; height: 26px; }
.blind-chest-value {
  font-family: var(--font-num); font-size: 14px; font-weight: 800; color: var(--gold);
}
.blind-card.skipped .blind-chest, .blind-card.locked .blind-chest { opacity: .55; }

/* ==========================================================================
   Tableau (gems | play area | consumables)
   ========================================================================== */

.tableau {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.tableau-lower {
  display: grid;
  grid-template-columns: minmax(280px, 2.1fr) minmax(140px, 1fr);
  gap: 12px;
  align-items: start;
}

.rail-block {
  padding: 9px;
  background:
    radial-gradient(120% 150% at 0% 0%, rgba(176,124,255,.09), transparent 52%),
    rgba(5,7,25,.35);
  border: 1px solid rgba(176,190,255,.14);
  border-radius: var(--r-md);
}
.rail-title {
  font-size: 9px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: 7px;
}
.rail-title-split { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.rail-capacity { letter-spacing: .08em; text-transform: none; opacity: .8; }
.rail-empty { font-size: 11px; color: var(--ink-faint); font-style: italic; padding: 5px 2px; }

/* An empty socket is drawn, not described. The dashed box says "this is space
   you own", which is the fact that decides whether a gem in the shop is even
   affordable in slot terms. */
.inv-socket-empty {
  display: grid;
  place-items: center;
  width: 104px;
  min-height: 96px;
  border-radius: var(--r-md);
  border: 1px dashed var(--edge-bright);
  background: rgba(255,255,255,.02);
  color: var(--ink-faint);
  font-size: 20px;
  font-weight: 300;
  cursor: help;
}

.gem-rail, .consumable-rail { display: flex; flex-wrap: wrap; gap: 8px; }

.gem {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  width: clamp(104px, 10vw, 138px);
  min-height: clamp(96px, 9vw, 124px);
  padding: 10px 8px;
  text-align: center;
  font-size: clamp(11px, 1.05vw, 13px);
  font-weight: 700;
  line-height: 1.2;
  border-radius: var(--r-md);
  background:
    radial-gradient(110% 90% at 50% 0%, rgba(85,214,255,.2), transparent 52%),
    linear-gradient(180deg, rgba(101,73,183,.8), rgba(50,34,105,.9));
  border: 1px solid rgba(190,163,255,.45);
  box-shadow: var(--shadow-1), 0 0 18px rgba(157,123,255,.09), inset 0 1px 0 rgba(255,255,255,.1);
  cursor: help;
  transition: transform .18s, box-shadow .18s, translate .18s, scale .18s;
}
.gem:hover { translate: 0 -4px; box-shadow: var(--shadow-2); }
.gem.debuffed { filter: grayscale(1); opacity: .5; }
.gem.firing { animation: gemFire .32s cubic-bezier(.3,1.5,.4,1); z-index: 5; }
@keyframes gemFire {
  0% { transform: translateY(0) scale(1); box-shadow: var(--shadow-1); }
  40% { transform: translateY(-14px) scale(1.22) rotate(-5deg); box-shadow: 0 0 34px 8px rgba(255,211,110,.9); }
  100% { transform: translateY(0) scale(1); box-shadow: var(--shadow-1); }
}
.gem-counter {
  position: absolute;
  top: -7px; right: -7px;
  min-width: 20px;
  padding: 1px 5px;
  font-family: var(--font-num);
  font-size: 10px;
  text-align: center;
  border-radius: 99px;
  background: var(--gold);
  color: #241a05;
  box-shadow: 0 0 10px rgba(255,211,110,.8);
}

.consumable {
  font-size: 11px;
  padding: 7px 10px;
}
.consumable.kind-TAROT { background: linear-gradient(180deg, rgba(150,80,190,.7), rgba(80,36,110,.85)); }
.consumable.kind-PLANET { background: linear-gradient(180deg, rgba(70,120,200,.7), rgba(28,60,120,.85)); }
.consumable.kind-SPECTRAL { background: linear-gradient(180deg, rgba(120,200,190,.6), rgba(40,90,90,.85)); }
/* With a card face the tile becomes a picture with a caption. The padding drops
   because the art now supplies the tile's body. */
.consumable.has-art { padding: 5px 6px 6px; }
.consumable-body { display: flex; flex-direction: column; align-items: center; gap: 4px; }
.consumable-art { width: 52px; border-radius: 7px; }
.consumable-name { font-size: 10px; font-weight: 700; line-height: 1.2; }

.play-area {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 8px;
  min-height: 128px;
  padding: 10px;
  border-radius: var(--r-md);
  background:
    radial-gradient(ellipse at 50% 40%, rgba(80,200,140,.1), transparent 70%),
    rgba(0,0,0,.26);
  border: 1px dashed var(--edge);
}

/* ==========================================================================
   Cards
   ========================================================================== */

.card {
  --card-rgb: 255, 211, 110;
  --card-float-duration: 6.2s;
  --card-float-delay: -1s;
  position: relative;
  width: clamp(96px, 10vw, 140px);
  aspect-ratio: .705;
  flex: 0 0 auto;
  border-radius: 10px;
  background:
    radial-gradient(130% 90% at 14% 0%, rgba(var(--card-rgb),.13), transparent 48%),
    linear-gradient(160deg, #fffef8, #e6dfca);
  border: 1px solid rgba(0,0,0,.35);
  box-shadow:
    0 2px 0 rgba(56,39,24,.34),
    0 9px 18px rgba(2,3,12,.56),
    0 22px 42px rgba(2,3,12,.36),
    0 0 18px rgba(var(--card-rgb),.1);
  color: #17182b;
  user-select: none;
  isolation: isolate;
  will-change: transform, translate, box-shadow;
  transition:
    transform .2s cubic-bezier(.2,1.35,.35,1),
    translate .2s cubic-bezier(.2,1.2,.35,1),
    box-shadow .2s ease,
    filter .16s;
}
/* Matched to the delivered frame art (hammer=red, swords=green, flame=gold,
   gem=purple), so the selection glow and the border it's glowing around agree. */
.card.suit-C { --card-rgb: 179, 49, 44; }
.card.suit-S { --card-rgb: 47, 143, 82; }
.card.suit-H { --card-rgb: 217, 154, 43; }
.card.suit-D { --card-rgb: 122, 79, 209; }
.card.small { width: 54px; aspect-ratio: .692; }
.card.clickable { cursor: pointer; }
.card.clickable:hover {
  transform: translateY(-16px) scale(1.055) rotate(-.6deg);
  box-shadow:
    0 3px 0 rgba(56,39,24,.28),
    0 18px 30px rgba(2,3,12,.62),
    0 34px 62px rgba(2,3,12,.42),
    0 0 30px rgba(var(--card-rgb),.28);
  filter: saturate(1.08) brightness(1.03);
  z-index: 4;
}
.card.selected {
  transform: translateY(-26px) scale(1.06);
  box-shadow:
    0 0 0 2px #fff7d4,
    0 0 0 5px var(--gold),
    0 16px 32px rgba(2,3,12,.62),
    0 30px 62px rgba(2,3,12,.42),
    0 0 34px rgba(var(--card-rgb),.36);
  z-index: 5;
}
.card.debuffed { filter: grayscale(1) brightness(.62); }
.card.scoring { animation: cardScore .3s cubic-bezier(.3,1.5,.4,1); z-index: 6; }
@keyframes cardScore {
  0% { transform: translateY(0) scale(1); filter: brightness(1); }
  45% { transform: translateY(-22px) scale(1.16); filter: brightness(1.7) drop-shadow(0 0 18px var(--gold)); }
  100% { transform: translateY(0) scale(1); filter: brightness(1); }
}

.card-face {
  position: absolute;
  inset: 0;
  padding: 5px 6px;
  overflow: hidden;
  border-radius: inherit;
  background:
    linear-gradient(145deg, rgba(var(--card-rgb),.075), transparent 34%),
    radial-gradient(90% 70% at 100% 100%, rgba(var(--card-rgb),.055), transparent 68%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.92), inset 0 -1px 0 rgba(74,52,26,.08);
}
.card.face-down {
  --card-rgb: 255, 211, 110;
  background: #171b42;
  border-color: rgba(255,211,110,.52);
}
.card-back {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: inherit;
  background:
    linear-gradient(145deg, rgba(255,255,255,.08), rgba(8,10,31,.16)),
    url("./assets/images/hotu_back_006_default-card-back_v01_512x768.webp") center / cover no-repeat,
    #1b204b;
  box-shadow:
    inset 0 0 0 3px rgba(18,21,55,.74),
    inset 0 0 0 5px rgba(255,211,110,.32),
    inset 0 1px 0 rgba(255,255,255,.34);
}
.card-back::after {
  content: "";
  position: absolute;
  inset: 8%;
  border: 1px solid rgba(255,226,145,.36);
  border-radius: 7px;
  box-shadow: inset 0 0 18px rgba(255,211,110,.12);
}
.card-back-mark {
  position: absolute;
  z-index: 1;
  left: 50%;
  top: 50%;
  translate: -50% -50%;
  width: 35%;
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  border-radius: 50%;
  color: #fff1bd;
  background: rgba(15,17,49,.72);
  border: 1px solid rgba(255,226,145,.55);
  box-shadow: 0 0 20px rgba(255,211,110,.32);
  font-family: var(--font-num);
  font-size: clamp(20px, 2.6vw, 34px);
  font-weight: 900;
  text-shadow: 0 0 12px rgba(255,211,110,.72);
}
.card.small .card-back-mark { font-size: 15px; }
.card-corner { position: absolute; display: flex; flex-direction: column; align-items: center; line-height: .95; }
.card-corner.tl { top: 8%; left: 8%; }
.card-corner.br { bottom: 8%; right: 8%; transform: rotate(180deg); }
.card-rank { font-size: clamp(18px, 2.1vw, 25px); font-weight: 800; }
.card-pip {
  width: clamp(11px, 1.35vw, 16px);
  height: clamp(11px, 1.35vw, 16px);
  object-fit: contain;
  filter: drop-shadow(0 1px 1px rgba(0,0,0,.3));
}
.card-centre {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: 40px;
  opacity: .95;
}
.card.small .card-centre { font-size: 28px; }
.card.small .card-rank { font-size: 12px; }
.card.small .card-pip { width: 9px; height: 9px; }

/* Matched to the frame art per suit - hammer=red, swords=green, flame=gold,
   gem=purple. Only the rank numeral (and the unused fallback diamond, for
   Stone cards) still needs an ink colour; the pip and corner glyphs are the
   real icon art now and carry their own colour. */
.suit-H .card-rank, .suit-H .card-centre { color: #d99a2b; }
.suit-D .card-rank, .suit-D .card-centre { color: #7a4fd1; }
.suit-C .card-rank, .suit-C .card-centre { color: #b3312c; }
.suit-S .card-rank, .suit-S .card-centre { color: #2f8f52; }

/* Affinity strip — the suit's meaning, always visible. */
.card-aff {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  font-size: 8px;
  font-weight: 800;
  letter-spacing: .14em;
  text-align: center;
  padding: 2px 0;
  color: #fff;
  text-shadow: 0 1px 2px rgba(0,0,0,.7);
}
.aff-STRENGTH .card-aff { background: linear-gradient(90deg, transparent, var(--strength), transparent); }
.aff-AGILITY .card-aff { background: linear-gradient(90deg, transparent, var(--agility), transparent); }
.aff-ELEMENTAL .card-aff { background: linear-gradient(90deg, transparent, var(--elemental), transparent); }
.aff-ARCANE .card-aff { background: linear-gradient(90deg, transparent, var(--arcane), transparent); }

.card-enh {
  position: absolute;
  top: 4px; right: 5px;
  width: 15px; height: 15px;
  display: grid; place-items: center;
  font-size: 9px; font-weight: 800;
  border-radius: 4px;
  background: rgba(0,0,0,.7);
  color: #fff;
}
.card-seal { position: absolute; bottom: 15px; left: 6px; width: 11px; height: 11px; border-radius: 50%; box-shadow: 0 0 6px currentColor; }
.seal-GOLD { background: var(--gold); color: var(--gold); }
.seal-RED { background: #ff4d4d; color: #ff4d4d; }
.seal-BLUE { background: #4db8ff; color: #4db8ff; }
.seal-PURPLE { background: #b07cff; color: #b07cff; }

.enh-BONUS .card-face { background: linear-gradient(160deg, #dbeaff, #b9d3f7); }
.enh-MULT .card-face { background: linear-gradient(160deg, #ffdcdc, #f8b6b6); }
.enh-GLASS .card-face { background: linear-gradient(160deg, rgba(255,255,255,.95), rgba(200,235,255,.75)); }
.enh-STEEL .card-face { background: linear-gradient(160deg, #dfe3ea, #a9b2c4); }
.enh-GOLD .card-face { background: linear-gradient(160deg, #ffe9a8, #e5be4f); }
.enh-STONE .card-face { background: linear-gradient(160deg, #b4b7c2, #7f8494); }
.enh-WILD .card-face { background: linear-gradient(160deg, #ffe6ff, #d9c2f5); }
.enh-LUCKY .card-face { background: linear-gradient(160deg, #d6ffe0, #a5e8b8); }

.card-shine {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  mix-blend-mode: screen;
}
.ed-FOIL .card-shine { background: linear-gradient(120deg, transparent 30%, rgba(120,190,255,.65), transparent 70%); }
.ed-HOLOGRAPHIC .card-shine { background: linear-gradient(120deg, rgba(255,80,180,.5), rgba(80,255,220,.5), rgba(255,220,80,.5)); }
.ed-POLYCHROME .card-shine {
  background: linear-gradient(120deg, #ff5f6d, #ffc371, #47e6b1, #6a8dff, #ff5f6d);
  background-size: 300% 300%;
  opacity: .62;
  animation: rainbow 3.4s linear infinite;
}
@keyframes rainbow { to { background-position: 300% 0; } }
.ed-NEGATIVE .card-face { filter: invert(1) hue-rotate(180deg); }

/* ==========================================================================
   Hand panel
   ========================================================================== */

.hand-panel {
  margin-top: auto;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 12px;
  background:
    radial-gradient(70% 150% at 0% 100%, rgba(85,214,255,.12), transparent 62%),
    radial-gradient(72% 150% at 100% 100%, rgba(255,95,162,.12), transparent 62%),
    radial-gradient(85% 90% at 50% 0%, rgba(176,124,255,.1), transparent 64%),
    rgba(22,25,62,.9);
  border: 1px solid rgba(172,188,255,.19);
  border-radius: var(--r-lg);
  backdrop-filter: blur(12px);
  box-shadow: var(--shadow-2);
}

.hand-tools {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 12px;
  flex-wrap: wrap;
  min-height: 30px;
}
/* Centred over the hand rail regardless of what the preview/forecast side
   is showing - those two grow and shrink with selection, and letting them
   push the sort control around would mean "centered" only held true when
   the hand was empty. */
.sort-group {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  align-items: center;
  gap: 6px;
}
.tools-label { font-size: 9px; letter-spacing: .16em; text-transform: uppercase; color: var(--ink-faint); }
.sort-btn { padding: 5px 14px; font-size: 12px; border-radius: 99px; }
.sort-btn.active { background: linear-gradient(180deg, var(--gold), var(--gold-deep)); color: #241a05; border-color: rgba(255,230,160,.8); }
.deck-count { font-family: var(--font-num); font-size: 11px; color: var(--ink-faint); }

.preview { display: flex; align-items: center; gap: 9px; font-size: 12px; }
.preview-hand { font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: var(--gold); }
.preview-lvl { font-family: var(--font-num); color: var(--ink-dim); }
.preview-shield { padding: 2px 10px; border-radius: 99px; font-weight: 700; font-size: 11px; }
.preview-shield.yes { background: rgba(126,230,255,.2); color: var(--ice); border: 1px solid rgba(126,230,255,.5); }
.preview-shield.no { background: rgba(255,120,120,.14); color: #ffa0a0; border: 1px solid rgba(255,120,120,.35); }

.hand-rail {
  display: flex;
  justify-content: center;
  gap: 7px;
  flex-wrap: wrap;
  padding: 26px 4px 6px;
  min-height: 138px;
}

.actions { display: flex; justify-content: center; gap: 12px; flex-wrap: wrap; }
.action {
  min-width: 150px;
  padding: 11px 22px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
}
.action strong { font-size: 16px; letter-spacing: .1em; }
.action small { font-size: 10px; opacity: .72; font-weight: 500; }
.action.strike { background: linear-gradient(180deg, #ff9d6b, #d94d24); color: #2b0d02; border-color: rgba(255,190,150,.6); }
/* Break is gold, not blue: it is the treasure action, and colouring it like the
   chest is what makes the two read as the same system at a glance. */
.action.break-chest { background: linear-gradient(180deg, #ffd98a, #d69a2e); color: #2b1c00; border-color: rgba(255,215,130,.65); }
.action.break-chest:disabled { background: linear-gradient(180deg, #4a4636, #35322a); color: var(--ink-faint); }
.action.discard {
  background: linear-gradient(180deg, rgba(132,111,226,.72), rgba(63,55,135,.84));
  border-color: rgba(183,165,255,.45);
}
.action.strike:hover:not(:disabled) { box-shadow: 0 12px 30px rgba(255,90,54,.38), inset 0 1px 0 rgba(255,255,255,.3); }
.action.break-chest:hover:not(:disabled) { box-shadow: 0 12px 30px rgba(255,196,60,.36), inset 0 1px 0 rgba(255,255,255,.34); }
.action.discard:hover:not(:disabled) { box-shadow: 0 12px 30px rgba(157,123,255,.34), inset 0 1px 0 rgba(255,255,255,.24); }

/* ==========================================================================
   Title
   ========================================================================== */

.title {
  position: relative;
  isolation: isolate;
  align-items: center;
  justify-content: flex-start;
  text-align: center;
  gap: 12px;
  padding-top: clamp(22px, 4vh, 54px);
}
.title::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    linear-gradient(180deg, rgba(5,7,22,.42), rgba(5,7,22,.68) 54%, rgba(5,7,22,.9)),
    radial-gradient(70% 65% at 50% 42%, transparent 20%, rgba(6,8,27,.6) 100%),
    url("./assets/images/hotu_screen_002_run-selection-hall_v01_source.png") center / cover no-repeat;
  filter: saturate(1.08);
}
.title > * { position: relative; z-index: 1; }
.title-mark { font-size: 74px; filter: drop-shadow(0 10px 26px rgba(255,211,110,.5)); animation: idleBob 4s ease-in-out infinite; }
.title-mark .gem-art { width: 96px; height: 96px; }
.title-name {
  margin: 0;
  font-size: clamp(42px, 8vw, 84px);
  font-weight: 900;
  letter-spacing: .1em;
  background: linear-gradient(180deg, #fff6d8, var(--gold) 55%, var(--gold-deep));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  filter: drop-shadow(0 6px 24px rgba(255,211,110,.45));
}
.title-accent { -webkit-text-fill-color: var(--elemental); filter: drop-shadow(0 0 20px rgba(255,95,162,.7)); }
.title-tag { margin: 0; color: var(--ink-dim); font-size: 15px; }

.title-panel {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 20px 26px;
  width: min(1020px, 96vw);
  min-width: 0;
  background:
    radial-gradient(80% 150% at 0% 0%, rgba(85,214,255,.13), transparent 62%),
    radial-gradient(80% 150% at 100% 100%, rgba(176,124,255,.15), transparent 62%),
    rgba(17,20,50,.88);
  border: 1px solid rgba(190,204,255,.2);
  border-radius: var(--r-lg);
  backdrop-filter: blur(14px);
  box-shadow: 0 24px 70px rgba(0,0,0,.58), inset 0 1px 0 rgba(255,255,255,.08);
}
.field { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.field-label { font-size: 10px; letter-spacing: .16em; text-transform: uppercase; color: var(--ink-faint); min-width: 52px; text-align: left; }
.seed-input {
  flex: 1;
  min-width: 160px;
  padding: 9px 14px;
  font-family: var(--font-num);
  font-size: 16px;
  letter-spacing: .18em;
  color: var(--gold);
  background: rgba(0,0,0,.42);
  border: 1px solid var(--edge-bright);
  border-radius: var(--r-sm);
  text-transform: uppercase;
}
.seed-input:focus { outline: 2px solid var(--gold); outline-offset: 1px; }

.chip-row { display: flex; gap: 5px; flex-wrap: wrap; }
.chip { padding: 5px 12px; font-size: 11px; font-weight: 600; border-radius: 99px; }
.chip.active { background: linear-gradient(180deg, var(--gold), var(--gold-deep)); color: #241a05; }

.title-actions { display: flex; gap: 12px; flex-wrap: wrap; justify-content: center; }
.title-foot { font-size: 11px; color: var(--ink-faint); }

/* ==========================================================================
   Deck picker and permanent unlock vault
   ========================================================================== */

.deck-field { display: flex; flex-direction: column; gap: 9px; text-align: left; }
.deck-field-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.unlocks-button { padding: 5px 12px; font-size: 11px; border-radius: 99px; }

.deck-picker {
  display: flex;
  gap: 9px;
  padding: 10px 8px 13px;
  overflow-x: auto;
  overscroll-behavior-inline: contain;
  scrollbar-width: thin;
  scrollbar-color: rgba(176,124,255,.55) rgba(0,0,0,.22);
  border-radius: var(--r-md);
  background:
    linear-gradient(90deg, rgba(85,214,255,.05), rgba(176,124,255,.08), rgba(255,95,162,.05)),
    rgba(0,0,0,.28);
  border: 1px solid rgba(175,191,255,.12);
}
.deck-picker::-webkit-scrollbar { height: 7px; }
.deck-picker::-webkit-scrollbar-thumb { background: rgba(176,124,255,.55); border-radius: 99px; }

button.deck-choice {
  flex: 0 0 clamp(240px, 30vw, 360px);
  width: clamp(240px, 30vw, 360px);
  padding: 10px 10px 9px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: center;
  border-radius: 18px;
  background: rgba(7,9,27,.78);
  border-color: rgba(var(--deck-rgb, 176, 124, 255),.16);
  box-shadow: 0 8px 20px rgba(0,0,0,.35);
  opacity: .82;
}
button.deck-choice:hover {
  translate: 0 -5px;
  opacity: 1;
  border-color: rgba(var(--deck-rgb, 176, 124, 255),.62);
  box-shadow: 0 13px 28px rgba(0,0,0,.5), 0 0 24px rgba(var(--deck-rgb, 176, 124, 255),.24);
}
button.deck-choice.active {
  opacity: 1;
  border-color: rgb(var(--deck-rgb, 176, 124, 255));
  box-shadow:
    0 0 0 2px rgba(255,255,255,.72),
    0 0 0 5px rgba(var(--deck-rgb, 176, 124, 255),.68),
    0 14px 32px rgba(0,0,0,.52),
    0 0 28px rgba(var(--deck-rgb, 176, 124, 255),.3);
}
button.deck-choice.locked { opacity: .5; }
button.deck-choice.locked:hover { opacity: .76; }
.deck-choice-name {
  width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: 13px;
  letter-spacing: .08em;
  text-transform: uppercase;
  white-space: nowrap;
}

.deck-back {
  --deck-rgb: 176, 124, 255;
  --deck-hue: 0deg;
  position: relative;
  width: 100%;
  aspect-ratio: 2 / 3;
  overflow: hidden;
  flex: 0 0 auto;
  border-radius: 8px;
  background: #11152e;
  border: 1px solid rgba(var(--deck-rgb),.55);
  box-shadow:
    0 7px 15px rgba(0,0,0,.58),
    0 0 18px rgba(var(--deck-rgb),.18),
    inset 0 0 0 1px rgba(255,255,255,.12);
}
.deck-back::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(circle at 50% 48%, rgba(var(--deck-rgb),.26), transparent 38%),
    linear-gradient(145deg, rgba(var(--deck-rgb),.16), transparent 45%);
  mix-blend-mode: screen;
}
.deck-back-art {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
  filter: hue-rotate(var(--deck-hue)) saturate(1.18) contrast(1.05);
}
.deck-back-emblem {
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 2;
  transform: translate(-50%, -50%);
  width: 38%;
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  border-radius: 50%;
  font-size: clamp(16px, 2vw, 24px);
  background: radial-gradient(circle, rgba(8,11,29,.94), rgba(8,11,29,.58));
  border: 1px solid rgba(var(--deck-rgb),.72);
  box-shadow: 0 0 19px rgba(var(--deck-rgb),.52), inset 0 0 10px rgba(var(--deck-rgb),.2);
  text-shadow: 0 2px 6px #000;
}
.deck-back.locked .deck-back-art {
  filter: grayscale(1) brightness(.33) contrast(1.15);
}
.deck-back.locked::after { background: rgba(4,5,14,.42); mix-blend-mode: normal; }
.deck-back.locked .deck-back-emblem {
  border-color: rgba(255,255,255,.24);
  box-shadow: 0 4px 14px rgba(0,0,0,.55);
  filter: grayscale(1);
}

.deck-picker-detail {
  min-height: 72px;
  display: grid;
  grid-template-columns: minmax(150px, .7fr) minmax(240px, 1.8fr) minmax(190px, 1fr);
  gap: 12px;
  align-items: center;
  padding: 9px 12px;
  border-radius: var(--r-md);
  background: rgba(0,0,0,.31);
  border: 1px solid rgba(180,196,255,.12);
}
.deck-detail-head { display: flex; align-items: center; gap: 8px; }
.deck-detail-head strong { font-size: 14px; }
.deck-status, .vault-deck-status {
  padding: 2px 7px;
  border-radius: 99px;
  font-size: 8px;
  font-weight: 900;
  letter-spacing: .12em;
}
.deck-status.unlocked, .vault-deck.unlocked .vault-deck-status {
  color: #062111;
  background: var(--good);
}
.deck-status.locked, .vault-deck.locked .vault-deck-status {
  color: #ffd0da;
  background: rgba(255,77,109,.22);
  border: 1px solid rgba(255,77,109,.35);
}
.deck-detail-text { color: var(--ink); font-size: 12px; line-height: 1.4; }
.deck-detail-hint { color: var(--ink-faint); font-size: 10px; text-align: right; }

.unlock-progress { display: flex; flex-direction: column; gap: 4px; min-width: 150px; }
.unlock-progress-track {
  height: 7px;
  overflow: hidden;
  border-radius: 99px;
  background: rgba(0,0,0,.52);
  border: 1px solid rgba(255,255,255,.1);
}
.unlock-progress-fill {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, var(--arcane), var(--ice), var(--good));
  box-shadow: 0 0 13px rgba(126,230,255,.65);
}
.unlock-progress-copy {
  color: var(--ink-dim);
  font-family: var(--font-num);
  font-size: 9px;
  text-align: right;
}

.deck-vault-overlay {
  background:
    linear-gradient(180deg, rgba(4,5,18,.68), rgba(4,5,18,.9)),
    url("./assets/images/hotu_screen_002_run-selection-hall_v01_source.png") center / cover no-repeat;
}
.overlay-card.deck-vault {
  width: min(1120px, 96vw);
  max-width: none;
  padding: 22px 24px 26px;
  background:
    radial-gradient(90% 80% at 50% 0%, rgba(176,124,255,.14), transparent 64%),
    rgba(15,18,45,.96);
}
.vault-kicker {
  color: var(--ice);
  font-size: 9px;
  font-weight: 900;
  letter-spacing: .22em;
}
.vault-intro {
  max-width: 780px;
  margin: -4px auto 17px;
  color: var(--ink-dim);
  font-size: 12px;
  line-height: 1.55;
  text-align: center;
}
.vault-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 11px;
}
.vault-deck {
  --deck-rgb: 176, 124, 255;
  min-width: 0;
  display: grid;
  grid-template-columns: 82px minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  padding: 11px;
  border-radius: var(--r-md);
  background:
    radial-gradient(120% 100% at 0% 50%, rgba(var(--deck-rgb),.11), transparent 50%),
    rgba(3,5,20,.46);
  border: 1px solid rgba(var(--deck-rgb),.18);
}
.vault-deck > .deck-back { grid-row: 1; width: 82px; }
.vault-deck-copy { min-width: 0; }
.vault-deck h3 { margin: 4px 0 3px; font-size: 14px; }
.vault-deck p { margin: 0; }
.vault-deck-effect {
  min-height: 29px;
  color: var(--ink);
  font-size: 10px;
  line-height: 1.4;
}
.vault-deck-requirement {
  min-height: 28px;
  margin-top: 5px !important;
  color: var(--ink-dim);
  font-size: 9px;
  line-height: 1.35;
}
.vault-deck .unlock-progress { margin-top: 6px; min-width: 0; }
.vault-deck.locked { opacity: .72; }
.vault-deck.unlocked {
  border-color: rgba(139,255,176,.24);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.05);
}

.unlock-notice {
  display: flex;
  align-items: center;
  gap: 13px;
  width: min(620px, 92vw);
  padding: 10px 16px;
  border-radius: var(--r-lg);
  background:
    radial-gradient(120% 180% at 0% 50%, rgba(126,230,255,.18), transparent 55%),
    linear-gradient(120deg, rgba(55,40,105,.95), rgba(24,28,67,.96));
  border: 1px solid rgba(255,211,110,.5);
  box-shadow: 0 0 34px rgba(255,211,110,.18), var(--shadow-2);
}
.unlock-notice-kicker {
  color: var(--gold);
  font-size: 9px;
  font-weight: 900;
  letter-spacing: .18em;
}
.unlock-notice-backs { display: flex; }
.unlock-notice-backs .deck-back { width: 42px; margin-left: -8px; }
.unlock-notice-backs .deck-back:first-child { margin-left: 0; }
.unlock-notice-backs .deck-back-emblem { font-size: 12px; }
.unlock-notice-copy { display: flex; flex-direction: column; gap: 2px; text-align: left; }
.unlock-notice-copy strong { color: #fff2be; }
.unlock-notice-copy span { color: var(--ink-dim); font-size: 11px; }

@container app (max-width: 820px) {
  .vault-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .deck-picker-detail { grid-template-columns: 1fr 1.5fr; }
  .deck-picker-detail > :last-child { grid-column: 1 / -1; }
}

@container app (max-width: 560px) {
  .title { padding-top: 16px; }
  .title-mark { font-size: 48px; }
  .title-mark .gem-art { width: 64px; height: 64px; }
  .title-name { font-size: 38px; }
  .title-panel { padding: 14px 12px; }
  button.deck-choice { flex-basis: 130px; width: 130px; }
  .hero-portrait.xl { width: 110px; border-radius: 16px; }
  .hero-portrait.xl .hero-portrait-art { font-size: 32px; }
  .hero-portrait.xl .hero-portrait-lock { font-size: 18px; bottom: 6px; }
  .hero-portrait.xl .hero-portrait-chain-bar { height: 8px; margin-top: -4px; }
  .deck-picker-detail { grid-template-columns: 1fr; }
  .deck-picker-detail > :last-child { grid-column: auto; }
  .deck-detail-hint { text-align: left; }
  .vault-grid { grid-template-columns: 1fr; }
  .vault-deck { grid-template-columns: 68px minmax(0, 1fr); }
  .vault-deck > .deck-back { width: 68px; }
  .unlock-notice { align-items: flex-start; flex-wrap: wrap; }
}

/* ==========================================================================
   Blind select / shop / pack / over
   ========================================================================== */

.screen-title { margin: 0; font-size: clamp(26px, 4vw, 40px); font-weight: 900; letter-spacing: .06em; text-align: center; }
.screen-sub { margin: 0 0 6px; text-align: center; color: var(--ink-dim); font-size: 14px; }

.blind-row {
  display: flex;
  gap: 18px;
  justify-content: center;
  /* Stretch, not centre: the three cards are meant to be the same height so
     their fact boxes and footers line up across the row. */
  align-items: stretch;
  flex-wrap: wrap;
  padding: 10px 0;
}

/* The header is one banded strip: who and where on the left, the floor in the
   middle, money on the right. */
.blind-select-head {
  width: min(1240px, 97vw);
  /* Clears the fixed chrome buttons in the top-right corner. A full-width
     header reaches under them at every viewport size, so the band is pushed
     below them rather than padded away from one edge. */
  margin: 34px auto 0;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 24px;
  padding: 12px 16px;
  border-radius: var(--r-lg);
  background: rgba(6,10,26,.42);
  border: 1px solid var(--edge);
}
.blind-select-ident { justify-self: start; }
.blind-select-title { grid-column: 2; }
.blind-select-head .screen-title { grid-column: auto; }
.blind-select-head .screen-sub { margin: 2px 0 0; }
.floor-name {
  display: inline-block;
  padding: 5px 12px;
  border-radius: 99px;
  border: 1px solid rgba(255,211,110,.34);
  background: rgba(255,211,110,.08);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--gold);
}
.floor-progress { margin-top: 6px; padding-left: 4px; font-size: 12px; color: var(--ink-dim); }
.floor-progress strong { color: var(--ink); font-weight: 800; }
.blind-wallet {
  grid-column: 3;
  justify-self: end;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 16px 8px 12px;
  border-radius: var(--r-md);
  background: rgba(4,8,22,.55);
  border: 1px solid rgba(255,211,110,.3);
}
.blind-wallet-coin { font-size: 20px; filter: drop-shadow(0 0 8px rgba(255,211,110,.5)); }
.blind-wallet-body { display: flex; flex-direction: column; }
.blind-wallet-label {
  color: var(--ink-faint);
  font-size: 8px;
  font-weight: 800;
  letter-spacing: .15em;
  text-transform: uppercase;
}
/* Banked tags -------------------------------------------------------------
   A skipped blind's reward almost never pays out on pickup, so it has to stay
   on screen until it does. Green matches the skip button and the SKIP REWARD
   ribbon in the shop, so the whole chain reads as one colour. */
.tag-strip {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  justify-content: center;
  width: min(940px, 96vw);
  margin: 0 auto;
  padding: 8px 14px;
  border-radius: var(--r-md);
  background:
    radial-gradient(120% 160% at 0% 0%, rgba(139,255,176,.12), transparent 62%),
    rgba(4,8,22,.46);
  border: 1px solid rgba(139,255,176,.24);
}
.tag-strip-label {
  font-size: 9px;
  font-weight: 800;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: rgba(139,255,176,.8);
}
.tag-rail { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; }
.tag-chip {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 5px 11px 5px 8px;
  border-radius: 99px;
  background: rgba(139,255,176,.1);
  border: 1px solid rgba(139,255,176,.3);
  cursor: default;
}
.tag-chip-icon { font-size: 14px; }
.tag-chip-body { display: flex; flex-direction: column; line-height: 1.2; }
.tag-chip-name { font-size: 12px; font-weight: 800; color: #d8ffe6; }
.tag-chip-when {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: rgba(139,255,176,.72);
}

/* The combat top bar has no room for names, so it carries a count and a
   tooltip. It still pulses, because the point is that it be noticed. */
.tag-badge {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 3px 10px;
  border-radius: 99px;
  background: rgba(139,255,176,.12);
  border: 1px solid rgba(139,255,176,.34);
  cursor: default;
  animation: tagBadgePulse 3.4s ease-in-out infinite;
}
.tag-badge-icon { font-size: 13px; }
.tag-badge-count { font-family: var(--font-num); font-size: 14px; font-weight: 800; color: #d8ffe6; }
@keyframes tagBadgePulse {
  0%, 100% { box-shadow: 0 0 0 rgba(139,255,176,0); }
  50% { box-shadow: 0 0 14px rgba(139,255,176,.35); }
}

/* Blind cards ------------------------------------------------------------
   Three columns of equal height whose rows line up: head, fact boxes, footer.
   The alignment is the point - this screen is a comparison, and a comparison
   you have to scan diagonally is a comparison you do not make. */
.blind-card {
  position: relative;
  display: flex;
  flex-direction: column;
  width: min(340px, 92vw);
  padding: 16px;
  text-align: left;
  background: var(--panel);
  border: 1px solid var(--edge);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-2);
  transition: transform .2s, box-shadow .2s, opacity .2s, translate .2s, scale .2s;
}
.blind-card.locked { opacity: .55; }
.blind-card.done, .blind-card.skipped { opacity: .5; }
.blind-card.current { border-color: var(--gold); box-shadow: 0 0 34px rgba(255,211,110,.32), var(--shadow-2); }
.blind-card.tier-BOSS { background: linear-gradient(180deg, rgba(90,20,50,.7), rgba(40,12,30,.8)); border-color: rgba(255,100,140,.4); }
.blind-card.tier-BOSS.current { border-color: var(--gold); }

.blind-head { display: flex; align-items: center; gap: 14px; }
/* A framed tile rather than a free-floating sprite: at this size the portrait
   is an identifier, and an identifier needs a consistent footprint or the three
   headers stop lining up. */
.blind-portrait-tile {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 78px;
  height: 78px;
  border-radius: var(--r-md);
  background: radial-gradient(85% 85% at 50% 35%, rgba(255,255,255,.09), rgba(0,0,0,.34));
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.08);
  overflow: hidden;
}
.blind-portrait {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.blind-head-body { min-width: 0; }
.blind-tier { font-size: 11px; letter-spacing: .22em; text-transform: uppercase; color: var(--ink-dim); }
.blind-req {
  font-family: var(--font-num);
  font-size: clamp(34px, 4vw, 46px);
  font-weight: 800;
  line-height: 1.05;
  color: var(--ink);
}
.blind-card.current .blind-req { color: var(--gold); }
.blind-req-label { font-size: 9px; letter-spacing: .14em; color: var(--ink-faint); text-transform: uppercase; }
.blind-reward { margin-top: 6px; font-size: 14px; color: var(--good); font-weight: 800; }

/* The dossier ------------------------------------------------------------
   Who is in the room and what they carry, shown before you commit. Two tiers
   of density on purpose: the roster is glanceable (silhouette, HP, a symbol)
   and the notes name names, because "one of them hits back" is trivia while
   "Root Snare hits back at Flushes" is a plan. */
.blind-dossier {
  margin-top: 14px;
  padding: 10px;
  border-radius: var(--r-md);
  background: rgba(4,8,22,.42);
  border: 1px solid var(--edge);
}
.blind-roster { display: flex; gap: 6px; align-items: flex-end; }
.roster-slot {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 6px 2px 4px;
  border-radius: var(--r-sm);
  background: radial-gradient(80% 80% at 50% 30%, rgba(255,255,255,.06), rgba(0,0,0,.28));
  cursor: help;
}
/* The Warden reads as the centre of the line here exactly as it does in the
   fight, so the shape of the room is recognisable before you enter it. */
.roster-slot.boss { padding-top: 2px; background: radial-gradient(80% 80% at 50% 30%, rgba(255,140,170,.14), rgba(0,0,0,.34)); }
.roster-art { width: 100%; height: 46px; object-fit: contain; display: block; }
.roster-slot.boss .roster-art { height: 56px; }
.roster-hp {
  font-family: var(--font-num);
  font-size: 11px;
  font-weight: 700;
  color: var(--ink-dim);
  line-height: 1;
}
.roster-marks { display: flex; gap: 2px; }
.roster-mark { font-size: 10px; line-height: 1; }
.roster-mark.ward { filter: drop-shadow(0 0 4px rgba(120,180,255,.8)); }
.roster-mark.weak { filter: drop-shadow(0 0 4px rgba(120,255,160,.8)); }
.roster-mark.volatile { filter: drop-shadow(0 0 4px rgba(255,120,120,.8)); }

.dossier-notes { display: flex; flex-direction: column; gap: 4px; margin-top: 8px; }
.dossier-note {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  font-size: 11px;
  line-height: 1.35;
  color: var(--ink-dim);
}
.dossier-icon { flex: 0 0 auto; font-size: 10px; line-height: 1.5; }
.dossier-note.ward { color: #b6d4ff; cursor: help; }
.dossier-note.weak { color: #a6f0bd; }
.dossier-note.volatile { color: #ffb3b3; }
.dossier-note.plain { color: var(--ink-faint); }

.blind-boss-redraw { color: #ffd98a; }

/* The fact stack. `flex: 1` is what pins the footer to the bottom of every
   card regardless of how many boxes a given blind happens to have. */
/* ---------------------------------------------------------------------------
   The floor fork

   Two lanes, drawn as near-identically as possible on purpose: the encounters
   are the same encounters, and the eye should land on the only cells that
   differ - the waystations. Everything converges on one Warden tile because
   both roads genuinely do.
--------------------------------------------------------------------------- */
.route-fork {
  background:
    radial-gradient(circle at 50% 46%, rgba(93,58,144,.2), transparent 48%),
    linear-gradient(120deg, rgba(20,25,61,.18), rgba(63,25,83,.18) 54%, rgba(11,40,57,.16));
}
.route-fork .blind-select-head {
  width: min(1480px, 98vw);
  margin-top: 18px;
  padding: 12px 22px;
  border-width: 0 0 1px;
  border-radius: 0;
  background: transparent;
}
.route-fork .blind-select-ident { min-width: 230px; }
.route-fork .blind-select-title { min-width: min(620px, 55vw); }
.route-fork .screen-title {
  font-family: Georgia, serif;
  font-size: clamp(27px, 3vw, 42px);
  letter-spacing: .035em;
}
.route-fork .screen-sub { margin-top: 4px; font-size: 12px; }
.route-fork .blind-wallet {
  border-radius: 999px;
  padding: 7px 20px 7px 13px;
  margin-right: 70px;
  background: rgba(20,16,44,.78);
  border-color: rgba(255,211,110,.75);
}

.fork-truth {
  width: min(920px, 92vw);
  margin: -2px auto 0;
  padding: 13px 24px;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px 24px;
  border: 1px solid rgba(125,144,224,.52);
  border-radius: 999px;
  background: rgba(8,13,34,.62);
  font-family: Georgia, serif;
  font-size: 11px;
  font-weight: 900;
  letter-spacing: .16em;
  text-transform: uppercase;
}
.fork-truth-same { color: #7ee6ff; }
.fork-truth-different { color: var(--gold); }
.fork-truth-divider { color: rgba(255,255,255,.72); font-size: 8px; }

.fork-diagram {
  width: min(1280px, 96vw);
  margin: 0 auto;
}
.fork-common {
  min-height: 52px;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 14px;
  color: var(--ink-dim);
}
.fork-start { display: flex; align-items: center; gap: 10px; }
.fork-start-pip {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border: 1px solid rgba(255,211,110,.78);
  border-radius: 50%;
  color: var(--gold);
  font-size: 12px;
  background: rgba(43,32,68,.9);
  box-shadow: 0 0 16px rgba(255,211,110,.2);
}
.fork-start-label,
.fork-common-path {
  font-family: Georgia, serif;
  font-size: 10px;
  font-weight: 900;
  letter-spacing: .18em;
  text-transform: uppercase;
}
.fork-common-path { display: flex; align-items: center; gap: 9px; }
.fork-common-path span { color: rgba(255,255,255,.64); }

.fork-lanes { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 38px; }

.fork-lane {
  --route: var(--gold);
  position: relative;
  min-height: 560px;
  display: grid;
  grid-template-rows: 168px 108px 1fr auto;
  grid-template-areas: "head" "path" "stocks" "take";
  gap: 14px;
  padding: 26px 38px 28px;
  border-radius: 42% 42% 20px 20px / 13% 13% 20px 20px;
  border: 1px solid var(--route);
  background:
    radial-gradient(circle at 50% 9%, color-mix(in srgb, var(--route) 22%, transparent), transparent 42%),
    linear-gradient(145deg, color-mix(in srgb, var(--route) 9%, rgba(20,17,48,.96)), rgba(8,12,30,.95) 72%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.04),
    0 22px 50px rgba(0,0,0,.34);
  overflow: hidden;
  transition: border-color .2s ease, box-shadow .2s ease, transform .2s ease, opacity .2s ease, translate .2s ease, scale .2s ease;
}
.fork-lane::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(115deg, transparent 0 47%, color-mix(in srgb, var(--route) 5%, transparent) 48% 49%, transparent 50%),
    repeating-linear-gradient(145deg, transparent 0 48px, rgba(255,255,255,.015) 49px 50px);
}
.fork-lane:hover {
  border-color: color-mix(in srgb, var(--route) 86%, white);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--route) 28%, transparent),
              0 25px 60px color-mix(in srgb, var(--route) 18%, rgba(0,0,0,.6));
  translate: 0 -4px;
}
/* Hovering one lane fades the other. With two rows this deliberately similar,
   isolation is the fastest way to answer "what is actually different here". */
.fork-diagram.hovering .fork-lane:not(:hover) { opacity: .42; }

.fork-lane-head {
  position: relative;
  z-index: 1;
  grid-area: head;
  display: flex;
  gap: 20px;
  align-items: center;
}
.fork-lane-badge {
  width: 142px;
  height: 142px;
  border: 0;
  border-radius: 0;
  object-fit: contain;
  flex: none;
  filter: drop-shadow(0 12px 18px rgba(0,0,0,.55));
}
.fork-lane-badge.glyph-badge {
  display: grid;
  place-items: center;
  font-size: 62px;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 40%, color-mix(in srgb, var(--route) 34%, transparent), transparent 70%);
  filter: drop-shadow(0 0 18px color-mix(in srgb, var(--route) 44%, transparent));
}
.fork-lane-name {
  font-family: Georgia, serif;
  font-size: clamp(22px, 2vw, 31px);
  font-weight: 900;
  color: var(--route);
  letter-spacing: .025em;
}
.fork-lane-keeper { font-size: 11px; letter-spacing: .16em; text-transform: uppercase; color: var(--ink-dim); }
.fork-lane-pitch {
  max-width: 390px;
  margin-top: 8px;
  font-family: Georgia, serif;
  font-size: 12px;
  font-style: italic;
  line-height: 1.45;
  color: var(--ink-soft, #c9c2dd);
}

.fork-path {
  position: relative;
  z-index: 1;
  grid-area: path;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0;
}
.fork-link {
  flex: 1 1 90px;
  min-width: 55px;
  max-width: 210px;
  height: 2px;
  background: linear-gradient(90deg, color-mix(in srgb, var(--route) 15%, transparent), var(--route), color-mix(in srgb, var(--route) 15%, transparent));
}
.fork-node {
  flex: none;
  width: 138px;
  min-height: 90px;
  padding: 12px 8px 9px;
  border-radius: 50%;
  text-align: center;
  border: 1px solid rgba(255,255,255,.08);
  background: rgba(8,7,18,.78);
}
.fork-node-art { width: 54px; height: 54px; object-fit: contain; display: block; margin: 0 auto; }
.fork-node-glyph { font-size: 30px; line-height: 34px; }
.fork-node-label {
  font-size: 9px; font-weight: 900; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-dim);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.fork-node-stop { margin-top: 3px; font-size: 9px; color: var(--route); opacity: .8; }
.fork-node-req { font-size: 12px; font-weight: 800; color: var(--danger); font-variant-numeric: tabular-nums; }
.fork-node-marks { display: flex; justify-content: center; gap: 3px; margin-top: 2px; font-size: 10px; }
.fork-node.station {
  border-color: var(--route);
  background: radial-gradient(circle at 50% 32%, color-mix(in srgb, var(--route) 24%, transparent), rgba(8,7,18,.88) 72%);
}
.fork-node.station .fork-node-label { color: var(--route); }

.fork-stocks {
  position: relative;
  z-index: 1;
  grid-area: stocks;
  align-self: stretch;
  margin: 0;
  padding: 17px 24px 17px 42px;
  display: grid;
  align-content: center;
  gap: 10px;
  border: 1px solid color-mix(in srgb, var(--route) 27%, transparent);
  background: rgba(5,8,24,.62);
  font-size: 11px;
  line-height: 1.4;
  color: var(--ink);
}
.fork-stocks li::marker { color: var(--route); }
.fork-take {
  position: relative;
  z-index: 1;
  grid-area: take;
  width: 76%;
  justify-self: center;
  align-self: end;
  padding: 12px 18px;
  border-radius: 999px;
  border-color: var(--route);
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--route) 48%, rgba(255,255,255,.12)),
    color-mix(in srgb, var(--route) 42%, rgba(10,12,32,.94)));
  box-shadow: 0 10px 22px color-mix(in srgb, var(--route) 13%, rgba(0,0,0,.45));
  color: #fff;
  text-shadow: 0 1px 3px rgba(0,0,0,.72);
  white-space: nowrap;
}
.fork-take-copy { display: flex; flex-direction: column; gap: 2px; align-items: center; }
.fork-take-copy strong { font-family: Georgia, serif; letter-spacing: .05em; }
.fork-take-copy small { color: rgba(255,255,255,.78); font-size: 10px; opacity: 1; text-transform: none; letter-spacing: .02em; }

.fork-join { margin-top: 8px; display: flex; flex-direction: column; align-items: center; gap: 2px; }
.fork-join-rule {
  width: 54%; height: 2px;
  background: linear-gradient(90deg, transparent, rgba(255,211,110,.5), transparent);
}
.fork-warden {
  display: grid;
  grid-template-columns: auto auto;
  grid-template-areas: "label label" "node name";
  align-items: center;
  column-gap: 10px;
  padding: 6px 22px 7px;
}
.fork-warden-label {
  grid-area: label;
  text-align: center;
  font-size: 8px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: #ff9ac4;
}
.fork-warden .fork-node {
  grid-area: node;
  width: 70px;
  min-height: 54px;
  padding: 2px;
  border: 0;
  background: transparent;
}
.fork-warden .fork-node-art { width: 52px; height: 52px; }
.fork-warden .fork-node-label,
.fork-warden .fork-node-req,
.fork-warden .fork-node-marks { display: none; }
.fork-warden-name {
  grid-area: name;
  font-family: Georgia, serif;
  font-size: 15px;
  font-weight: 900;
  color: var(--ink);
  letter-spacing: .04em;
}
.fork-footer-notes {
  display: flex;
  justify-content: center;
  gap: 30px;
  margin-top: 1px;
  color: var(--ink-faint);
  font-size: 8px;
  font-weight: 800;
  letter-spacing: .18em;
  text-transform: uppercase;
}

/* The committed route, carried through the rest of the floor. */
.route-badge {
  --route: var(--gold);
  display: inline-flex; align-items: center; gap: 6px; margin-top: 8px;
  padding: 4px 10px; border-radius: 999px;
  font-size: 11px; font-weight: 700; letter-spacing: .06em; color: var(--route);
  border: 1px solid color-mix(in srgb, var(--route) 45%, transparent);
  background: color-mix(in srgb, var(--route) 12%, transparent);
}
.route-badge-glyph { font-size: 13px; }

@container app (max-width: 900px) {
  .route-fork .blind-select-head { margin-top: 34px; }
  .fork-truth { border-radius: 18px; }
  .fork-lanes { grid-template-columns: 1fr; gap: 18px; }
  .fork-lane { min-height: 510px; }
  .fork-take { width: 100%; }
}
@container app (max-width: 560px) {
  .route-fork .blind-select-title { min-width: 0; }
  .route-fork .blind-wallet { margin-right: 0; }
  .fork-truth { gap: 8px 12px; font-size: 9px; }
  .fork-common { flex-direction: column; padding: 8px 0; }
  .fork-lane { padding: 22px 18px; border-radius: 28px; grid-template-rows: auto auto auto auto; }
  .fork-lane-head { flex-direction: column; text-align: center; }
  .fork-lane-badge { width: 112px; height: 112px; }
  .fork-lane-pitch { max-width: none; }
  .fork-node { width: 112px; }
  .fork-footer-notes { flex-direction: column; align-items: center; gap: 5px; }
}

/* ---------------------------------------------------------------------------
   Forge commissions
--------------------------------------------------------------------------- */
.forge-row { display: flex; gap: 12px; flex-wrap: wrap; }
.forge-slot {
  position: relative; width: 150px; padding: 12px; border-radius: 14px; text-align: center;
  border: 1px solid rgba(255,138,61,.32);
  background: linear-gradient(160deg, rgba(48,26,14,.75), rgba(14,10,22,.85));
}
.forge-slot-glyph {
  font-size: 30px; line-height: 1.3;
  filter: drop-shadow(0 0 14px rgba(255,138,61,.75));
}
.forge-slot.taken { opacity: .45; filter: saturate(.4); }
.forge-slot-done {
  margin-top: 8px; font-size: 10px; letter-spacing: .18em; text-transform: uppercase;
  color: var(--good);
}

.forge-deck {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(62px, 1fr));
  gap: 10px; max-height: 52vh; overflow-y: auto; padding: 4px;
}
.forge-cell { display: flex; flex-direction: column; align-items: center; gap: 3px; }
.forge-cell-note {
  font-size: 9px; letter-spacing: .06em; text-align: center; color: var(--ink-dim);
  line-height: 1.2;
}
.forge-cell-note.warn { color: #ffb37a; }
.forge-cell.already { opacity: .5; }

.specialist-service {
  display: grid; grid-template-columns: 54px minmax(0, 1fr) auto; align-items: center; gap: 14px;
  padding: 14px; border-radius: 15px; border: 1px solid color-mix(in srgb, var(--route) 48%, transparent);
  background: linear-gradient(135deg, color-mix(in srgb, var(--route) 13%, transparent), rgba(6,9,20,.72));
}
.specialist-service.used { opacity: .55; filter: saturate(.55); }
.specialist-glyph {
  display: grid; place-items: center; width: 50px; height: 50px; border-radius: 14px;
  font-size: 27px; background: rgba(4,7,17,.66); box-shadow: inset 0 0 0 1px var(--edge);
}
.specialist-copy { min-width: 0; }
.specialist-copy .item-kind { margin-bottom: 3px; }
.specialist-copy .item-text { max-width: 54ch; }

.study-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 10px; }
.study-choice, .polish-choice {
  appearance: none; color: var(--ink); text-align: left; cursor: pointer;
  border: 1px solid var(--edge); background: rgba(7,11,25,.86); border-radius: 13px; padding: 12px;
  transition: transform .14s ease, border-color .14s ease, background .14s ease, translate .14s ease, scale .14s ease;
}
.study-choice:hover, .polish-choice:hover:not(:disabled) {
  translate: 0 -2px; border-color: var(--gold); background: rgba(22,23,42,.94);
}
.study-hand, .study-level, .study-times { display: block; }
.study-hand { font-family: var(--display); font-size: 15px; }
.study-level { margin-top: 5px; color: var(--gold); font-weight: 700; }
.study-times { margin-top: 2px; color: var(--ink-dim); font-size: 10px; }

.polish-grid { display: grid; gap: 9px; max-height: 52vh; overflow-y: auto; }
.polish-choice { display: grid; grid-template-columns: 48px minmax(0, 1fr) auto; align-items: center; gap: 12px; }
.polish-choice .gem-art { width: 48px; height: 48px; }
.polish-copy, .polish-step { display: block; }
.polish-step { margin-top: 4px; color: var(--ink-dim); font-size: 11px; }
.polish-price { color: var(--gold); font-weight: 800; }
.polish-choice:disabled { opacity: .45; cursor: not-allowed; }

.keeper-stocks {
  margin: 10px 0 0; padding-left: 16px; text-align: left;
  font-size: 11px; line-height: 1.6; color: var(--ink-dim);
}

.blind-facts { flex: 1; display: flex; flex-direction: column; gap: 10px; margin-top: 14px; }
.blind-box {
  padding: 10px 12px;
  border-radius: var(--r-md);
  background: rgba(4,8,22,.5);
  border: 1px solid var(--edge);
}
.blind-boss {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-size: 12px;
  color: #ffc0c0;
  line-height: 1.4;
  text-align: center;
}
.blind-boss-icon { opacity: .8; }
.blind-actions { margin-top: 14px; display: flex; gap: 8px; }
.blind-actions > * { flex: 1; }
/* A locked card keeps a footer of the same height so the row does not resize
   as blinds are cleared. */
.blind-locked-note {
  display: grid;
  place-items: center;
  padding: 11px;
  border-radius: var(--r-md);
  border: 1px dashed var(--edge-bright);
  font-size: 10px;
  font-weight: 800;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.blind-tag-preview {
  background:
    radial-gradient(100% 120% at 0% 0%, rgba(139,255,176,.13), transparent 60%),
    rgba(4,8,22,.5);
  border-color: rgba(139,255,176,.26);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.04);
}
.blind-tag-head { display: flex; align-items: center; gap: 6px; }
.blind-tag-icon { font-size: 14px; filter: drop-shadow(0 0 6px rgba(139,255,176,.55)); }
.blind-tag-name {
  color: var(--good);
  font-size: 10px;
  font-weight: 900;
  letter-spacing: .08em;
  text-transform: uppercase;
}
.blind-tag-effect { margin-top: 5px; color: var(--ink); font-size: 10px; line-height: 1.42; }
.blind-tag-timing {
  margin-top: 6px;
  color: var(--gold);
  font-size: 8px;
  font-weight: 800;
  letter-spacing: .1em;
  text-transform: uppercase;
}
.skip-button-copy { display: flex; flex-direction: column; align-items: center; gap: 1px; }
.skip-button-copy strong { font-size: 12px; letter-spacing: .08em; }
.skip-button-copy small { color: var(--good); font-size: 9px; font-weight: 700; }
.skip-blind {
  border-color: rgba(139,255,176,.3);
  background: linear-gradient(180deg, rgba(70,135,102,.3), rgba(20,55,45,.38));
}
.skip-blind:hover:not(:disabled) {
  box-shadow: 0 12px 28px rgba(80,220,145,.2), inset 0 1px 0 rgba(255,255,255,.15);
}
.blind-stamp {
  position: absolute; top: 40%; left: 50%;
  transform: translate(-50%, -50%) rotate(-16deg);
  font-size: 22px; font-weight: 900; letter-spacing: .12em;
  color: var(--good); border: 3px solid var(--good); border-radius: 8px; padding: 4px 14px;
  opacity: .85;
}
.blind-stamp.skip { color: var(--ink-dim); border-color: var(--ink-dim); }

/* Shop --------------------------------------------------------------------
   Three columns: who is selling, what is for sale, what you already own. The
   rails never move between visits, so the eye learns one place per question
   and only the middle changes. */
.shop-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  flex-wrap: wrap;
  width: min(1440px, 97vw);
  margin: 34px auto 0;
  padding: 0 4px 14px;
  border-bottom: 1px solid var(--edge);
}
.shop-head-left { display: flex; align-items: baseline; gap: 18px; flex-wrap: wrap; }
.shop-head-left .screen-title { text-align: left; font-size: clamp(22px, 3vw, 34px); }
.shop-kicker {
  flex-basis: 100%;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: .26em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
/* Inline beside the title: the shop is where most tags actually redeem, so
   this is the screen where the player checks that one did. */
.shop-head-left .tag-strip {
  width: auto;
  margin: 0;
  padding: 5px 12px;
  background: none;
  border-color: rgba(139,255,176,.22);
}
.shop-wallet { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; }

.shop-body {
  display: grid;
  grid-template-columns: minmax(190px, 250px) minmax(0, 1fr) minmax(230px, 320px);
  align-items: start;
  gap: 16px;
  width: min(1440px, 97vw);
  margin: 0 auto;
}
.shop-centre, .shop-rail { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.shop-panel {
  padding: 14px;
  border-radius: var(--r-lg);
  background: rgba(6,10,26,.44);
  border: 1px solid var(--edge);
}
.shop-panel .section-title { text-align: left; margin-bottom: 10px; }
.shop-panel .section-title::before, .shop-panel .section-title::after { display: none; }

.keeper-panel { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 6px; }
.shopkeeper-art {
  width: 100%;
  max-width: 190px;
  aspect-ratio: 1;
  object-fit: contain;
  filter: drop-shadow(0 10px 22px rgba(0,0,0,.6));
  animation: idleBob 5.2s ease-in-out infinite;
}
.shopkeeper-name {
  font-size: 15px;
  font-weight: 900;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink);
  line-height: 1.25;
}
.shopkeeper-quote {
  margin: 0;
  padding-top: 10px;
  border-top: 1px solid var(--edge);
  width: 100%;
  font-size: 11px;
  font-style: italic;
  color: var(--ink-dim);
  line-height: 1.5;
}

/* In the rail the inventory is a compact sell list, not the wide strip the
   blind-select screen uses. */
/* Capped and scrolled rather than shrunk further. A player holding five gems
   and two consumables will always outgrow whatever fixed height we pick, and
   the failure mode of guessing wrong is that the Permanent Upgrade and the
   Next Encounter button slide off the bottom of the screen. */
.inventory-panel .inventory {
  flex-direction: column;
  gap: 10px;
  max-height: min(46vh, 400px);
  overflow-y: auto;
  padding-right: 4px;
}
.inventory-panel .inv-block { width: 100%; }
.inventory-panel .inv-rail { gap: 6px; }
/* Compact enough that the Permanent Upgrade below it stays above the fold.
   The rail is a reference list, not a display case - full-size tiles pushed the
   one purchase that outlives the run off the bottom of the screen. */
.inventory-panel .inv-gem { width: 64px; padding: 6px 4px 8px; gap: 2px; }
.inventory-panel .inv-gem .gem-art { width: 30px; height: 30px; }
.inventory-panel .inv-gem-name { font-size: 9px; line-height: 1.15; }
.inventory-panel .inv-gem-text { display: none; }
.inventory-panel .inv-gem-sell { font-size: 8px; padding: 1px 5px; }
.inventory-panel .inv-socket-empty { width: 64px; min-height: 52px; font-size: 15px; }
.inventory-panel .inv-consumable { width: 64px; padding: 6px 4px 8px; }
.inventory-panel .inv-consumable-art { width: 30px; }
.inventory-panel .inv-consumable-name { font-size: 9px; line-height: 1.15; }
.inventory-panel .inv-sell { font-size: 8px; padding: 1px 5px; }
.inventory-panel .rail-title { font-size: 8px; margin-bottom: 5px; }
.voucher-panel .voucher-row { justify-content: center; }
.voucher-panel .voucher-card { width: 100%; }
.purse {
  font-family: var(--font-num); font-size: 26px; font-weight: 800; color: var(--gold);
  padding: 5px 20px; border-radius: 99px;
  background: rgba(0,0,0,.4); border: 1px solid rgba(255,211,110,.4);
  text-shadow: 0 0 18px rgba(255,211,110,.6);
}
.shop-section { display: flex; flex-direction: column; gap: 10px; }
.section-title {
  font-size: 11px; letter-spacing: .24em; text-transform: uppercase; color: var(--ink-dim);
  display: flex; align-items: center; gap: 10px; justify-content: center;
}
.section-title::before, .section-title::after {
  content: ""; flex: 1 1 60px; max-width: 90px; height: 1px;
  background: linear-gradient(90deg, transparent, var(--edge-bright), transparent);
}

.shop-grid, .pack-grid, .voucher-row, .pack-options {
  display: flex; gap: 20px; flex-wrap: wrap; justify-content: center;
}

/* Type/family colour: a left-to-right story (glow, icon plate, name) instead
   of a flat card with a tinted border was the whole ask - "lackluster" meant
   every item read the same regardless of what it was. */
.shop-item, .pack-card, .voucher-card, .pack-option {
  --tint: 170, 175, 210;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 9px;
  width: 196px;
  padding: 20px 14px 14px;
  text-align: center;
  background:
    radial-gradient(120% 90% at 50% -10%, rgba(var(--tint), .22), transparent 65%),
    var(--panel);
  border: 1px solid rgba(var(--tint), .38);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-1), inset 0 1px 0 rgba(255,255,255,.05);
  transition: transform .18s cubic-bezier(.3,1.3,.4,1), box-shadow .18s, border-color .18s, translate .18s cubic-bezier(.3,1.3,.4,1), scale .18s cubic-bezier(.3,1.3,.4,1);
  overflow: hidden;
}
.shop-item::before, .pack-card::before, .voucher-card::before, .pack-option::before {
  content: "";
  position: absolute; top: 0; left: 0; right: 0; height: 3px;
  background: linear-gradient(90deg, transparent, rgb(var(--tint)), transparent);
  opacity: .9;
}
.shop-item:hover, .pack-card:hover, .voucher-card:hover, .pack-option:hover {
  translate: 0 -7px;
  box-shadow: 0 14px 34px rgba(var(--tint), .22), var(--shadow-2);
  border-color: rgba(var(--tint), .7);
}
.pack-option.clickable { cursor: pointer; }
.voucher-card { --tint: 255, 211, 110; width: 280px; }
.item-kind { font-size: 8px; letter-spacing: .18em; color: var(--ink-faint); text-transform: uppercase; }
.item-glyph, .pack-glyph {
  display: grid; place-items: center;
  width: 76px; height: 76px;
  font-size: 40px; line-height: 1;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, rgba(var(--tint), .5), rgba(var(--tint), .12) 70%);
  box-shadow: inset 0 0 0 1px rgba(var(--tint), .4);
}
/* A gem badge shows art instead of an emoji, so it drops the tinted disc and
   lets the artwork itself carry the shape. */
.item-glyph.gem-glyph {
  background: radial-gradient(circle at 50% 55%, rgba(var(--tint), .3), transparent 70%);
  box-shadow: none;
}
.item-glyph.gem-glyph .gem-art { width: 72px; height: 72px; }
.inv-gem .gem-art { width: 40px; height: 40px; }

/* Tarots and Planets are illustrated cards, not badges, so they get a card
   rectangle rather than the circular disc the emoji glyphs sit in. */
.item-glyph.arcana-glyph {
  width: auto; height: auto;
  background: none;
  box-shadow: none;
  border-radius: 0;
}

/* A booster is a wrapped package, not a floating emoji. Delivered family art
   gets the full portrait silhouette; the seal remains only for fallback art. */
.pack-glyph { position: relative; overflow: visible; }
.pack-glyph.family-art {
  width: 96px;
  height: 128px;
  border-radius: 0;
  background: none;
  box-shadow: none;
}
.pack-wrapper {
  width: 76px;
  height: 76px;
  object-fit: contain;
  filter: drop-shadow(0 6px 14px rgba(0,0,0,.55));
}
.pack-wrapper.pack-family-art { width: 96px; height: 128px; }
.pack-seal {
  position: absolute;
  right: -4px;
  bottom: -2px;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  font-size: 16px;
  border-radius: 50%;
  background: rgba(8,10,26,.9);
  box-shadow: 0 0 0 1px rgba(var(--tint), .6), 0 4px 10px rgba(0,0,0,.5);
}

/* Vouchers are one-off permanent upgrades. Each two-tier family shares a
   delivered ticket motif; tier two gets a brighter procedural presentation. */
.voucher-ticket {
  display: grid;
  place-items: center;
  width: 100%;
  aspect-ratio: 3 / 2;
  padding: 0;
  filter: drop-shadow(0 6px 14px rgba(0,0,0,.5));
}
.voucher-art { display: block; width: 100%; height: 100%; object-fit: contain; }
.voucher-ticket-fallback {
  background: url("./assets/images/hotu_voucher_009_ticket-frame_v01_768x512.webp") center / contain no-repeat;
}
.voucher-card.tier-two .voucher-art {
  filter: brightness(1.08) saturate(1.12) drop-shadow(0 0 12px rgba(255,211,110,.35));
}
.voucher-card .voucher-name { margin-top: -3px; }
.voucher-card .voucher-text { font-size: 11px; line-height: 1.35; text-wrap: balance; }
.arcana-art {
  display: block;
  width: 76px;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: var(--r-md);
  box-shadow: 0 6px 16px rgba(0,0,0,.5), inset 0 0 0 1px rgba(255,255,255,.14);
}
.pack-option .arcana-art { width: 96px; }
/* Tarot art is a full illustration, not an icon: below about 56px the figure
   stops being recognisable and the tile is just a coloured square. */
.inv-consumable-art { width: 58px; border-radius: 8px; }

.item-name, .pack-name, .voucher-name { font-size: 14px; font-weight: 800; line-height: 1.3; }

/* Effect text on the tile itself. Deciding what to buy means comparing
   effects, and you cannot compare things you have to hover one at a time. */
.item-text {
  font-size: 11px; line-height: 1.4; color: var(--ink-dim);
  font-weight: 500; text-wrap: balance;
}

/* A free item is nearly always a skip reward paying out. It used to render as
   a "$0" button, which was indistinguishable from a broken one - the reported
   "I skipped for a pack and got nothing". */
.shop-item.free, .pack-card.free {
  border-color: rgba(139,255,176,.75);
  box-shadow: 0 0 0 1px rgba(139,255,176,.35), 0 10px 30px rgba(139,255,176,.18), var(--shadow-1);
  animation: free-pulse 2.2s ease-in-out infinite;
}
@keyframes free-pulse {
  50% { box-shadow: 0 0 0 2px rgba(139,255,176,.5), 0 12px 36px rgba(139,255,176,.3), var(--shadow-2); }
}
/* A flat badge rather than the corner ribbon it used to be: rotated 38 degrees
   the band ran off the top of the card and the tile's own overflow clipped it,
   so it read "IP REWARD". A label the player cannot finish reading is worse
   than no label at all. */
.free-ribbon {
  position: absolute; top: 8px; right: 8px;
  background: var(--good); color: #06210f;
  font-size: 8px; font-weight: 900; letter-spacing: .12em;
  padding: 3px 8px;
  border-radius: 99px;
  box-shadow: 0 2px 8px rgba(0,0,0,.45);
}
.btn.buy.free {
  background: linear-gradient(180deg, #8bffb0, #4bd07c);
  color: #06210f; font-weight: 900;
}
.item-stickers { font-size: 9px; color: var(--gold); letter-spacing: .06em; }
.pack-meta, .voucher-text { font-size: 10px; color: var(--ink-dim); line-height: 1.35; }
.shop-item.type-GEM, .pack-card.family-GEM_PACK { --tint: 255, 195, 90; }
.shop-item.type-PLANET, .pack-card.family-CELESTIAL { --tint: 120, 175, 255; }
.shop-item.type-TAROT, .pack-card.family-ARCANA { --tint: 205, 130, 255; }
.shop-item.type-SPECTRAL, .pack-card.family-SPECTRAL { --tint: 120, 225, 215; }
.shop-item.type-PLAYING_CARD, .pack-card.family-STANDARD { --tint: 150, 220, 165; }

.shop-controls { display: flex; gap: 12px; justify-content: center; padding: 8px 0 4px; flex-wrap: wrap; }
.pack-inventory-label {
  margin-top: 8px;
  color: var(--good);
  font-size: 9px;
  font-weight: 900;
  letter-spacing: .16em;
  text-align: center;
  text-transform: uppercase;
}
.pack .inventory { width: min(940px, 96vw); margin: 0 auto; }

/* The inventory dock: leads the shop screen rather than trailing it, because
   selling only works if you can see it without scrolling past everything
   else first. */
.inventory { display: flex; gap: 14px; flex-wrap: wrap; justify-content: center; }
.inv-block {
  flex: 1 1 300px;
  padding: 12px 14px;
  background: rgba(0,0,0,.28);
  border: 1px solid var(--edge);
  border-radius: var(--r-lg);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.04);
}
.inv-rail { display: flex; gap: 8px; flex-wrap: wrap; }
.inv-gem, .inv-consumable {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  width: clamp(104px, 9.5vw, 132px);
  min-height: 96px;
  padding: 10px 8px;
  text-align: center;
  font-size: 12px;
  font-weight: 700;
  line-height: 1.2;
  border-radius: var(--r-md);
  background: linear-gradient(180deg, rgba(90,70,160,.7), rgba(48,36,92,.8));
  border: 1px solid rgba(180,150,255,.3);
  transition: transform .16s, box-shadow .16s, border-color .16s, translate .16s, scale .16s;
}
.inv-gem.clickable, .inv-consumable.clickable { cursor: pointer; }
.inv-gem.clickable:hover, .inv-consumable.clickable:hover {
  translate: 0 -4px;
  box-shadow: var(--shadow-2);
}
.inv-gem-name, .inv-consumable-name { font-size: 12px; font-weight: 800; }
.inv-gem-sell {
  font-size: 10px; font-weight: 700; letter-spacing: .03em;
  color: var(--good);
  padding: 2px 8px;
  border-radius: 99px;
  background: rgba(120, 220, 150, .15);
}
.inv-gem:not(.clickable) .inv-gem-sell { color: var(--ink-faint); background: rgba(255,255,255,.06); }
.inv-gem.clickable:hover .inv-gem-sell { background: var(--good); color: #052312; }

.inv-sell {
  margin-top: 2px;
  font-size: 9px; font-weight: 700;
  padding: 3px 9px;
  border-radius: 99px;
  background: rgba(120, 220, 150, .15);
  border: 1px solid rgba(120, 220, 150, .3);
  color: var(--good);
}
.inv-sell:hover:not(:disabled) { background: var(--good); color: #052312; }

.over { align-items: center; justify-content: center; text-align: center; gap: 14px; }
.over-glyph { font-size: 84px; filter: drop-shadow(0 10px 30px rgba(0,0,0,.7)); animation: idleBob 3.4s ease-in-out infinite; }
.over.win .screen-title { color: var(--gold); }
.over.loss .screen-title { color: var(--danger); }
.over-stats { display: flex; gap: 14px; flex-wrap: wrap; justify-content: center; }
.over-stat { min-width: 116px; padding: 12px 16px; background: var(--panel); border: 1px solid var(--edge); border-radius: var(--r-md); }
.over-stat-value { font-family: var(--font-num); font-size: 25px; font-weight: 800; color: var(--gold); }
.over-stat-label { font-size: 10px; letter-spacing: .12em; text-transform: uppercase; color: var(--ink-faint); }
.over-seed { font-family: var(--font-num); font-size: 12px; color: var(--ink-faint); }

/* Run-over screens get their own plates instead of the global nebula. Both
   images keep the middle of the frame empty (the breach's flagstone ring, the
   ruined table's dark felt), which is where the centred title and stats land,
   so the scrim only has to tame the bright edges rather than hide the art. */
.screen.over.win,
.screen.over.loss { position: relative; background-color: #0b0814; }
.screen.over.win {
  background:
    radial-gradient(70% 60% at 50% 62%, rgba(7,6,16,.62), rgba(7,6,16,.18) 70%, transparent),
    linear-gradient(180deg, rgba(8,6,18,.18), rgba(8,6,18,.5)),
    url("./assets/images/hotu_screen_008_victory-breach_v01_source.png") center / cover fixed no-repeat,
    #0b0814;
}
.screen.over.loss {
  background:
    radial-gradient(70% 60% at 50% 60%, rgba(5,4,12,.5), rgba(5,4,12,.1) 70%, transparent),
    linear-gradient(180deg, rgba(5,4,12,.2), rgba(5,4,12,.55)),
    url("./assets/images/hotu_screen_009_defeat-table_v02_source.png") center / cover fixed no-repeat,
    #0b0814;
}
.screen.over .over-stat { background: rgba(10,9,24,.84); backdrop-filter: blur(3px); }
.screen.over .screen-title,
.screen.over .screen-sub { text-shadow: 0 2px 18px rgba(0,0,0,.85); }
.screen.over .screen-sub,
.screen.over .over-seed {
  color: #e6dfcf;
  text-shadow: 0 1px 3px rgba(0,0,0,.95), 0 0 14px rgba(0,0,0,.8);
}

/* ==========================================================================
   Effect layers
   ========================================================================== */

#fx, #flash, #vignette, #transition {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 60;
}
#flash { z-index: 62; opacity: 0; }
#vignette { z-index: 61; opacity: 0; }

.float {
  position: absolute;
  font-family: var(--font-num);
  font-size: 21px;
  font-weight: 800;
  white-space: nowrap;
  transform: translate(-50%, -50%);
  text-shadow: 0 2px 10px rgba(0,0,0,.9);
}
.chip-float { color: #9fd0ff; }
.mult-float { color: #ff9d9d; }
.coin-float { color: var(--gold); }
.dmg-float { color: #ffb27a; font-size: 26px; }
.dmg-float.big { color: var(--gold); font-size: 40px; text-shadow: 0 0 26px rgba(255,211,110,.95); }
.spill-float { color: var(--ice); font-size: 15px; }
.shield-float { color: var(--ice); font-size: 22px; letter-spacing: .12em; }
.shatter-float { color: var(--ice); font-size: 34px; font-weight: 900; letter-spacing: .18em; text-shadow: 0 0 34px rgba(126,230,255,.95); }
.stun-float { color: var(--gold); font-size: 40px; font-weight: 900; letter-spacing: .2em; text-shadow: 0 0 40px rgba(255,211,110,1); }
.hit-float { color: var(--danger); font-size: 40px; font-weight: 900; letter-spacing: .2em; text-shadow: 0 0 30px rgba(255,77,109,.95); }
.block-float { color: var(--good); font-size: 24px; letter-spacing: .14em; }
.fail-float { color: #ff9a9a; font-size: 22px; letter-spacing: .12em; }
.clear-float { color: var(--good); font-size: 38px; font-weight: 900; letter-spacing: .18em; text-shadow: 0 0 36px rgba(139,255,176,.9); }

.particle { position: absolute; border-radius: 50%; transform: translate(-50%, -50%); }
.projectile { position: absolute; border-radius: 50%; transform: translate(-50%, -50%); }
.strike-icon { position: absolute; object-fit: contain; transform: translate(-50%, -50%); pointer-events: none; }
.beam { position: absolute; height: 5px; border-radius: 99px; filter: blur(.4px); }
.shockwave { position: absolute; transform: translate(-50%, -50%); border-style: solid; border-radius: 50%; }

/* Transition ------------------------------------------------------------- */

#transition { z-index: 70; display: none; }
#transition.active { display: block; }
.wipe-panel {
  position: absolute;
  top: 0; bottom: 0;
  width: 20.5%;
  background: linear-gradient(180deg, var(--bg-2), var(--bg-0));
  border-left: 1px solid rgba(255,211,110,.16);
  transform: scaleY(0);
  transform-origin: top;
}
.wipe-panel:nth-child(1) { left: 0; }
.wipe-panel:nth-child(2) { left: 20%; transform-origin: bottom; }
.wipe-panel:nth-child(3) { left: 40%; }
.wipe-panel:nth-child(4) { left: 60%; transform-origin: bottom; }
.wipe-panel:nth-child(5) { left: 80%; }
.wipe-label {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  font-size: clamp(24px, 5vw, 46px);
  font-weight: 900;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--gold);
  text-shadow: 0 0 40px rgba(255,211,110,.7);
  opacity: 0;
  white-space: nowrap;
}

/* ==========================================================================
   Chrome, tooltips, toasts, overlay
   ========================================================================== */

.chrome { position: fixed; top: 12px; right: 14px; display: flex; gap: 6px; z-index: 50; }
.chrome-btn { width: 36px; height: 36px; padding: 0; font-size: 15px; border-radius: 50%; }

#tooltip {
  position: fixed;
  z-index: 80;
  max-width: 300px;
  padding: 10px 13px;
  background: rgba(12, 14, 30, .97);
  border: 1px solid rgba(255,211,110,.32);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-3);
  font-size: 12px;
  line-height: 1.5;
  pointer-events: none;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity .14s, transform .14s, translate .14s, scale .14s;
}
#tooltip.visible { opacity: 1; transform: translateY(0); }
.tip-title { font-weight: 800; color: var(--gold); margin-bottom: 4px; letter-spacing: .04em; }
.tip-body { color: var(--ink); white-space: pre-line; }
.tip-meta { margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--edge); color: var(--ink-dim); font-size: 11px; white-space: pre-line; }

.toast-rail { position: fixed; top: 60px; right: 14px; z-index: 75; display: flex; flex-direction: column; gap: 8px; align-items: flex-end; }
.toast {
  padding: 9px 15px;
  font-size: 13px;
  font-weight: 700;
  border-radius: var(--r-md);
  background: rgba(12,14,30,.95);
  border: 1px solid var(--edge-bright);
  box-shadow: var(--shadow-2);
}
.toast.good { border-color: rgba(139,255,176,.5); color: var(--good); }
.toast.bad { border-color: rgba(255,77,109,.5); color: #ffa8b8; }

.overlay {
  position: fixed; inset: 0; z-index: 85;
  display: grid; place-items: center;
  padding: 20px;
  background: rgba(4,5,14,.82);
  backdrop-filter: blur(8px);
  animation: fadeIn .2s ease;
}
@keyframes fadeIn { from { opacity: 0; } }
.overlay-card {
  max-width: 620px;
  max-height: 86vh;
  overflow: auto;
  padding: 26px 30px;
  background: var(--panel-solid);
  border: 1px solid rgba(255,211,110,.3);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-3);
  animation: cardIn .3s cubic-bezier(.2,1.2,.35,1);
}
@keyframes cardIn { from { transform: scale(.9) translateY(20px); opacity: 0; } }
.overlay-card h2 { margin: 0 0 16px; color: var(--gold); letter-spacing: .06em; }
.help-section { margin-bottom: 16px; }
.help-section h3 { margin: 0 0 5px; font-size: 13px; letter-spacing: .12em; text-transform: uppercase; color: var(--ice); }
.help-section p { margin: 0 0 6px; font-size: 13px; line-height: 1.55; color: var(--ink-dim); }

/* ==========================================================================
   Responsive
   ========================================================================== */

@container app (max-width: 900px) {
  .tableau-lower { grid-template-columns: 1fr; }
  .play-area { min-height: 100px; order: -1; }
  .card { width: clamp(64px, 9vw, 84px); height: auto; }
  .card-centre { font-size: 32px; }
  .score-row { gap: 7px; }
  .chips-box, .mult-box { min-width: 84px; padding: 5px 10px; }
  .chips-value, .mult-value { font-size: 21px; }
  .total-value { font-size: 27px; }
  .action { min-width: 116px; padding: 9px 14px; }
}

@container app (max-width: 560px) {
  /* Narrow: the three header bands stack, title first. */
  .blind-select-head { grid-template-columns: 1fr; justify-items: center; gap: 10px; text-align: center; }
  .blind-select-title { grid-column: 1; grid-row: 1; }
  .blind-select-ident { justify-self: center; grid-row: 2; }
  .blind-wallet { grid-column: 1; grid-row: 3; justify-self: center; }
  .floor-progress { padding-left: 0; }
  .blind-card { width: min(340px, 92vw); }
  .blind-actions { flex-direction: column; }
  .card { width: clamp(54px, 12vw, 68px); height: auto; }
  .card-centre { font-size: 25px; }
  .card-rank { font-size: 13px; }
  .enemy { width: 104px; }
  .enemy.boss, .combat .enemy.boss { width: 132px; }
  .topbar { padding: 8px 10px; gap: 8px; }
  .stat { min-width: 54px; padding: 3px 8px; }
  .stat-value { font-size: 15px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}

/* ==========================================================================
   Combat density
   ==========================================================================
   The encounter screen is the one view that must fit without scrolling: a
   player deciding between Strike and Break needs the enemy line, the readout
   and their own hand visible at the same time. Everything below trades padding
   for that guarantee at a 1280x720 floor.
   ========================================================================== */

.screen.combat {
  /* Prefer a scrollbar to silently clipping something interactive: a fixed
     `hidden` here is what let the gem row collapse to zero height and
     disappear behind the hand panel once cards got bigger, with no visible
     sign anything was wrong. auto only appears when content truly outgrows
     the viewport. */
  overflow-y: auto;
  overflow-x: hidden;
  gap: 8px;
  padding: 10px clamp(10px, 2.4vw, 26px) 12px;
}

/* Keep the top bar clear of the fixed corner controls. */
.topbar { padding: 7px 128px 7px 14px; }
.stat { min-width: 60px; padding: 3px 10px; }
.stat-value { font-size: 16px; }

.combat .encounter { flex: 0 0 auto; gap: 7px; }
.combat .enemy { padding: 11px 13px 13px; width: clamp(132px, 14.5vw, 184px); }
.combat .enemy-art { font-size: clamp(42px, 4.8vw, 58px); }
.combat .enemy-name { font-size: 11px; margin: 3px 0 6px; }
/* Restated inside .combat because the width rule above outranks `.enemy.boss`
   on specificity; without these the Warden would shrink to escort size. */
.combat .enemy.boss { width: clamp(158px, 18.5vw, 210px); }
.combat .enemy-row.tier-patrol .enemy-portrait { --portrait: clamp(70px, 7.4vw, 90px); }
.combat .enemy-row.tier-elite  .enemy-portrait { --portrait: clamp(88px, 9.6vw, 116px); }
.combat .enemy-row.tier-warden .enemy-portrait { --portrait: clamp(96px, 10.4vw, 124px); }
.combat .enemy.boss .enemy-portrait { --portrait: clamp(138px, 15.5vw, 190px); }
.combat .hp-bar { height: 15px; }
.combat .hp-text { line-height: 13px; }
.combat .intent { padding: 5px 16px; font-size: 12px; }
.combat .meter { padding: 5px 12px; }
.combat .meter-title { font-size: 11px; }

.combat .scoreboard { flex: 0 0 auto; padding: 8px 12px; gap: 5px; }
.combat .hand-name { font-size: 13px; min-height: 17px; }
.combat .chips-box, .combat .mult-box { padding: 4px 14px; min-width: 100px; }
.combat .chips-value, .combat .mult-value { font-size: 22px; }
.combat .total-box { padding: 4px 18px; min-width: 148px; }
.combat .total-value { font-size: 28px; }
.combat .goal-text { font-size: 10px; margin-top: 2px; }

/* The tableau absorbs whatever space is left over rather than demanding its own.
   The gem row is the one part of it that must never collapse to zero - it is
   the only place gems can be seen, reordered or (in the shop) sold, so it
   keeps its natural size and the play area/consumables below it shrink first. */
.combat .tableau { flex: 1 1 auto; min-height: 84px; }
.combat .gem-block { flex: 0 0 auto; }
.combat .tableau-lower { flex: 1 1 auto; min-height: 0; }
.combat .play-area { min-height: 0; height: 100%; padding: 6px; }
.combat .rail-block { padding: 8px 9px; }

.combat .hand-panel { flex: 0 0 auto; padding: 8px 12px 10px; gap: 6px; }
.combat .hand-rail { padding: 22px 4px 2px; min-height: 0; gap: 6px; }
.combat .card { width: clamp(76px, 8.4vw, 104px); height: auto; }
.combat .card-centre { font-size: 33px; }
.combat .card-rank { font-size: 14px; }
.combat .action { padding: 8px 18px; min-width: 138px; }
.combat .action strong { font-size: 15px; }

@container app (min-height: 860px) {
  .combat .card { width: clamp(92px, 9.6vw, 128px); height: auto; }
  .combat .card-centre { font-size: 40px; }
  .combat .hand-rail { padding: 26px 4px 6px; }
}

/* The action label is wrapped in a span, so the column lives there. */
.action > span { display: flex; flex-direction: column; align-items: center; gap: 1px; }

/* Empty play area reads as a slot rather than a void. */
.play-area:empty::after {
  content: "played cards land here";
  font-size: 11px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-faint);
  opacity: .5;
}

/* Shop sections read as one centred column rather than orphaned left labels. */
.shop-section { width: 100%; max-width: 940px; margin: 0 auto; }
.section-title { text-align: center; }
.shop .inventory { max-width: 940px; margin-left: auto; margin-right: auto; }

/* ==========================================================================
   Build 2
   ========================================================================== */

/* Gems: order is a rule, so the rail shows position and affords dragging. */
.gem { cursor: grab; touch-action: none; }
.gem-order {
  position: absolute; left: 6px; top: 6px;
  font-family: var(--font-num); font-size: 10px; font-weight: 800;
  color: var(--gold); opacity: .75;
}
.gem-name { padding: 0 2px; }
/* A socketed gem's effect is reasoned about every hand, so it is never hidden
   behind a hover. */
.gem-text {
  font-size: 9px; line-height: 1.3; font-weight: 500;
  color: var(--ink-dim); padding: 0 2px; text-wrap: balance;
}
.inv-gem-text {
  font-size: 9px; line-height: 1.3; font-weight: 500;
  color: var(--ink-dim); text-wrap: balance;
}

/* Gem art. Sized off the tile so it scales with the gem rail rather than
   pinning to a fixed pixel size at every breakpoint. */
.gem-art {
  width: clamp(34px, 3.6vw, 50px);
  height: clamp(34px, 3.6vw, 50px);
  object-fit: contain;
  display: block;
  pointer-events: none;
  filter: drop-shadow(0 2px 5px rgba(0,0,0,.55));
}
.gem-art-fallback {
  display: grid; place-items: center;
  font-size: clamp(26px, 2.8vw, 36px);
  line-height: 1;
}
.gem.debuffed .gem-art { filter: grayscale(1) brightness(.6); }
.gem.dragging {
  cursor: grabbing; z-index: 30; opacity: .92;
  transform: translateY(-6px) scale(1.08) rotate(-3deg);
  box-shadow: 0 18px 44px rgba(0,0,0,.65), 0 0 0 2px var(--gold);
}
.gem-rail { position: relative; }

/* Damage forecast */
.forecast { display: flex; align-items: center; gap: 8px; font-family: var(--font-num); font-size: 12px; }
.forecast-hint { color: var(--ink-faint); }
.forecast-base { color: var(--ink-dim); }
.forecast-exact {
  color: #ffe6a8; font-weight: 700; padding: 3px 12px; border-radius: 99px;
  background: rgba(255,211,110,.14); border: 1px solid rgba(255,211,110,.42);
}

/* Draw / discard piles.
   Named distinctly from `.hand-row`, which the hand-levels table uses - the
   collision turned the hand rail into a single vertical column. */
.hand-with-piles { display: flex; align-items: center; gap: 12px; }
.hand-with-piles .hand-rail { flex: 1 1 auto; min-width: 0; }
.pile {
  position: relative; width: 58px; flex: 0 0 auto; text-align: center;
  padding-top: 6px; user-select: none;
}
.pile-content, .pile-stack, .pile-count, .pile-label { display: block; }
.pile.draw {
  padding: 6px 0 0;
  color: inherit;
  background: transparent;
  border: 0;
  border-radius: 10px;
  box-shadow: none;
}
.pile.draw:hover:not(:disabled) {
  translate: 0 -3px;
  filter: brightness(1.18);
  box-shadow: none;
}
.pile.draw:active:not(:disabled) { translate: 0 0; scale: .97; }
.pile.draw:focus-visible { outline-offset: 4px; }
.pile-stack {
  height: 52px; border-radius: 8px; margin: 0 6px;
  background: linear-gradient(160deg, #2b2f52, #191c39);
  border: 1px solid var(--edge-bright);
  box-shadow: 0 3px 0 -1px #1b1e38, 0 6px 0 -2px #14162c, var(--shadow-1);
}
.pile.discard .pile-stack { background: linear-gradient(160deg, #3a2436, #241624); }
.pile-count { font-family: var(--font-num); font-size: 15px; font-weight: 800; margin-top: 5px; }
.pile.draw .pile-count { color: var(--ice); }
.pile.discard .pile-count { color: var(--ink-dim); }
.pile-label { font-size: 8px; letter-spacing: .16em; text-transform: uppercase; color: var(--ink-faint); }

/* Suit affinity reactions */
.card.affinity-fired {
  box-shadow: 0 0 0 3px var(--aff-glow, #fff), 0 0 26px 6px var(--aff-glow, #fff), var(--shadow-2);
}
.crit-float {
  color: var(--agility); font-size: 22px; font-weight: 900; letter-spacing: .18em;
  text-shadow: 0 0 22px rgba(70,214,111,.95);
}

/* The banked Elemental charge cashing in. Deliberately reads like CRIT! - both
   are moments the score moves for a reason the cards on the table do not
   explain, and both need naming rather than a silent bump. */
.elemental-float {
  color: var(--elemental); font-size: 20px; font-weight: 900; letter-spacing: .14em;
  text-shadow: 0 0 22px rgba(255,95,162,.95);
}

/* ---------------------------------------------------------------------------
   Hand-mastery ceremony (Tomes)

   A Tome's whole effect is a number behind a panel, so it gets the one moment
   in the shop that takes the screen. The veil dims rather than blacks out - the
   shop stays legible underneath, which keeps this reading as something that
   happened in the room instead of a cutaway.
--------------------------------------------------------------------------- */
.mastery-veil {
  position: fixed; inset: 0; z-index: 90;
  display: flex; justify-content: center; align-items: flex-start;
  padding-top: clamp(40px, 9vh, 110px);
  background: radial-gradient(120% 80% at 50% 0%, rgba(30,22,52,.62), rgba(6,5,14,.86));
  backdrop-filter: blur(3px) saturate(.75);
  pointer-events: none;
}
.mastery-scroll {
  width: min(560px, 92vw); text-align: center;
}
.mastery-whisper {
  font-size: 15px; letter-spacing: .1em; font-style: italic;
  color: rgba(233,222,255,.7);
  opacity: 0; transform: translateY(6px);
  transition: opacity .34s ease, transform .34s ease, translate .34s ease, scale .34s ease;
  text-shadow: 0 0 24px rgba(176,124,255,.55);
}
.mastery-whisper.in { opacity: 1; transform: none; }
.mastery-headline {
  margin-top: 8px;
  font-size: clamp(19px, 3.4vw, 30px); font-weight: 900; letter-spacing: .16em;
  color: var(--gold);
  text-shadow: 0 0 40px rgba(255,211,110,.85), 0 2px 0 rgba(0,0,0,.45);
  -webkit-text-stroke: 1px rgba(0,0,0,.3);
  opacity: 0; transform: scale(.86);
  transition: opacity .3s cubic-bezier(.2,1.5,.4,1), transform .3s cubic-bezier(.2,1.5,.4,1), translate .3s cubic-bezier(.2,1.5,.4,1), scale .3s cubic-bezier(.2,1.5,.4,1);
}
.mastery-headline.in { opacity: 1; transform: none; }

.mastery-list {
  margin-top: 18px; display: flex; flex-direction: column; gap: 3px;
  padding: 12px; border-radius: 16px;
  background: rgba(12,10,26,.72);
  border: 1px solid rgba(176,124,255,.22);
  box-shadow: 0 24px 70px rgba(0,0,0,.6), inset 0 1px 0 rgba(255,255,255,.06);
}
/* Every untouched rung sits grey and half-lit. The contrast between these and
   the single gold row is the entire message, so the dimming is heavy. */
.mastery-row {
  display: grid; grid-template-columns: 1fr auto 64px; gap: 12px; align-items: center;
  padding: 7px 12px; border-radius: 9px;
  font-size: 13px; letter-spacing: .04em;
  color: rgba(206,200,224,.45); filter: grayscale(1); opacity: .5;
  transition: color .32s ease, filter .32s ease, opacity .32s ease,
              background .32s ease, transform .32s cubic-bezier(.2,1.3,.4,1),
              box-shadow .32s ease, translate .32s cubic-bezier(.2,1.3,.4,1), scale .32s cubic-bezier(.2,1.3,.4,1);
}
.mastery-row-name { text-align: left; font-weight: 600; }
.mastery-row-base { font-variant-numeric: tabular-nums; opacity: .75; }
.mastery-row-lv {
  text-align: right; font-weight: 800; font-variant-numeric: tabular-nums;
}
.mastery-row.lit {
  color: #fff3d0; filter: none; opacity: 1; transform: scale(1.045);
  background: linear-gradient(90deg, rgba(255,211,110,.05), rgba(255,211,110,.2), rgba(255,211,110,.05));
  box-shadow: 0 0 0 1px rgba(255,211,110,.5), 0 0 34px rgba(255,211,110,.4),
              inset 0 0 22px rgba(255,211,110,.14);
}
.mastery-row.lit .mastery-row-lv { color: var(--gold); text-shadow: 0 0 18px rgba(255,211,110,.95); }
.mastery-row.lit .mastery-row-base { opacity: 1; color: rgba(255,232,178,.9); }

.mastery-rune {
  position: fixed; z-index: 91; pointer-events: none;
  font-size: 20px; color: var(--gold);
  text-shadow: 0 0 16px rgba(255,211,110,.95), 0 0 34px rgba(255,170,60,.6);
}

/* ---------------------------------------------------------------------------
   The tome itself (single-hand mastery ceremony)

   Ported from prototypes/mastery-ascension/. The house rule carried over
   unchanged: the artwork supplies the realism. Nothing here paints paper,
   pages or lettering over the illustrations - every rule below is either
   structural (position/size, set once by JS layout) or light and shadow
   (glow, gutter shade, cast shadow), consuming per-frame values JS writes as
   custom properties. `--tome-*` throughout so nothing here collides with the
   scroll-ceremony rules above, which stay untouched for the multi-raise path.
--------------------------------------------------------------------------- */

.tome-root {
  --tome-accent: #f76d3b;
  --tome-accent-dim: #853214;
  position: relative;
  margin-top: 18px;
}

/* Reserves the SCALED footprint in normal flow (JS sets height directly) -
   the stage inside is authored at a literal 700x560px and only ever changes
   size via `transform: scale()`, which does not affect layout on its own. */
.tome-frame {
  position: relative;
  width: 100%;
  pointer-events: none;
}

.tome-stage {
  --tome-fit: 1;
  position: absolute;
  left: 50%;
  top: 0;
  width: 700px;
  height: 560px;
  transform: translateX(-50%) scale(var(--tome-fit));
  transform-origin: top center;
  perspective: 1600px;
  perspective-origin: 50% 50%;
}

.tome-bloom-floor {
  position: absolute;
  left: 50%; top: 62%;
  width: 620px; height: 330px;
  margin: -165px 0 0 -310px;
  border-radius: 50%;
  background: radial-gradient(closest-side, color-mix(in srgb, var(--tome-accent) 62%, #fff 12%), transparent 72%);
  filter: blur(26px);
  mix-blend-mode: screen;
  opacity: 0;
}

.tome-rays {
  position: absolute;
  inset: -30%;
  opacity: 0;
  mix-blend-mode: screen;
  background: repeating-conic-gradient(from 0deg,
    color-mix(in srgb, var(--tome-accent) 55%, #ffeec2) 0deg 1.6deg, transparent 1.6deg 9deg);
  -webkit-mask-image: radial-gradient(closest-side, transparent 18%, #000 42%, transparent 76%);
  mask-image: radial-gradient(closest-side, transparent 18%, #000 42%, transparent 76%);
  filter: blur(2px);
}

.tome-shaft {
  position: absolute;
  left: 50%; bottom: 48%;
  width: 300px; height: 62%;
  margin-left: -150px;
  background: linear-gradient(0deg,
    color-mix(in srgb, var(--tome-accent) 40%, #ffe9bd 22%), transparent 82%);
  clip-path: polygon(38% 100%, 62% 100%, 96% 0, 4% 0);
  filter: blur(36px);
  mix-blend-mode: screen;
  opacity: 0;
}

.tome-rig {
  position: absolute;
  left: 100px; top: 30px;
  width: 500px; height: 500px;
  transform-style: preserve-3d;
  will-change: transform;
}

.tome-rig img { display: block; }

.tome-base-right, .tome-open-final, .tome-open-bloom {
  position: absolute; left: 0; top: 0;
  width: 500px; height: 500px;
  filter: drop-shadow(0 24px 30px rgba(0,0,0,.55));
}
.tome-open-final { opacity: 0; }
/* A bloom struck from the artwork's own pixels: same shape, same silhouette,
   so the glow belongs to the book instead of sitting in front of it. */
.tome-open-bloom {
  opacity: 0;
  filter: blur(11px) brightness(1.45) saturate(.7);
  mix-blend-mode: screen;
}

.tome-pivot {
  position: absolute; top: 0;
  width: 0; height: 0;
  transform-origin: 0 0;
  transform-style: preserve-3d;
}
.tome-face { position: absolute; left: 0; backface-visibility: hidden; }
.tome-face img {
  position: absolute; left: 0; top: 0;
  width: 500px; height: 500px;
  transform-origin: 0 0;
}
.tome-cover-front img { filter: drop-shadow(0 20px 26px rgba(0,0,0,.6)); }
.tome-cover-back { transform: rotateY(180deg); }

.tome-gutter {
  position: absolute;
  background: radial-gradient(50% 60% at 50% 50%, rgba(20,10,4,.40), transparent 72%);
  opacity: 0;
}
.tome-cover-shadow {
  --tome-lean: 0;
  position: absolute;
  transform-origin: left center;
  background: linear-gradient(90deg, rgba(6,3,10,.62), rgba(6,3,10,.18) 42%, transparent 78%);
  opacity: 0;
  filter: blur(7px);
}

.tome-sigil {
  position: absolute;
  width: 230px; height: 230px;
  margin: 0;
  opacity: 0;
  mix-blend-mode: screen;
  background:
    radial-gradient(closest-side, transparent 63%, color-mix(in srgb, var(--tome-accent) 85%, #ffdca0) 65%, transparent 68%),
    radial-gradient(closest-side, transparent 84%, color-mix(in srgb, var(--tome-accent) 70%, #ffdca0) 85%, transparent 88%);
  filter: blur(1.2px);
}

.tome-clasp {
  position: absolute;
  width: 96px; height: 96px;
  margin: -48px 0 0 -48px;
  border-radius: 50%;
  background: radial-gradient(closest-side, #fff6de, color-mix(in srgb, var(--tome-accent) 70%, transparent) 42%, transparent 70%);
  mix-blend-mode: screen;
  opacity: 0;
}

.tome-ring {
  position: absolute;
  border-radius: 50%;
  border: 2px solid color-mix(in srgb, var(--tome-accent) 65%, #fff 35%);
  opacity: 0;
  mix-blend-mode: screen;
  transform: translate(-50%,-50%);
  filter: blur(1px);
}

.tome-flash {
  position: absolute;
  inset: -20%;
  opacity: 0;
  mix-blend-mode: screen;
  background: radial-gradient(38% 44% at 50% 50%,
    #fff8ea, color-mix(in srgb, var(--tome-accent) 70%, #fff3d8) 38%, transparent 72%);
}

/* the message on the open pages */
.tome-page-text {
  --tome-l1: 0; --tome-l2: 0; --tome-l3: 0; --tome-l4: 0; --tome-l5: 0;
  --tome-glow: 1;
  position: absolute;
  transform: translate(-50%,-50%) translateZ(2px);
  text-align: center;
  opacity: 0;
  color: #2a1a12;
}
.tome-pt-eyebrow {
  font-size: 15px; letter-spacing: calc(.42em - var(--tome-l1) * .16em);
  text-transform: uppercase;
  color: color-mix(in srgb, var(--tome-accent-dim) 72%, #4a2f1c);
  opacity: var(--tome-l1);
  transform: translateY(calc((1 - var(--tome-l1)) * 10px));
  filter: blur(calc((1 - var(--tome-l1)) * 3px));
}
.tome-pt-flourish {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  margin: 7px 0 4px;
  opacity: var(--tome-l2);
  color: color-mix(in srgb, var(--tome-accent-dim) 80%, #6b4a2c);
}
.tome-pt-flourish i {
  height: 1px; width: calc(var(--tome-l2) * 84px);
  background: linear-gradient(90deg, transparent, currentColor, transparent);
}
.tome-pt-flourish b { font-size: 8px; }
.tome-pt-name {
  --tome-name-size: 52px;
  --tome-name-shift: 0px;
  display: inline-block;
  white-space: nowrap;
  font-size: var(--tome-name-size);
  line-height: 1.02;
  font-weight: 600;
  letter-spacing: .035em;
  text-transform: uppercase;
  color: #3b2116;
  opacity: var(--tome-l3);
  transform:
    translateX(var(--tome-name-shift))
    translateY(calc((1 - var(--tome-l3)) * 14px))
    scale(calc(.94 + var(--tome-l3) * .06));
  filter: blur(calc((1 - var(--tome-l3)) * 5px));
  text-shadow:
    0 1px 0 rgba(255,250,236,.55),
    0 0 calc(var(--tome-l3) * 26px) color-mix(in srgb, var(--tome-accent) 45%, transparent);
}
.tome-pt-level {
  display: flex; align-items: baseline; justify-content: center; gap: .3em;
  position: relative;
  margin-top: 12px;
  font-size: 19px;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--tome-accent-dim) 70%, #4a2f1c);
  transform: translateX(-.34em);
}
.tome-pl-label {
  letter-spacing: .28em; margin-right: .1em;
  opacity: var(--tome-l4);
  transform: translateY(calc((1 - var(--tome-l4)) * 8px));
}
.tome-pl-from {
  font-size: 1.25em;
  font-variant-numeric: tabular-nums;
  opacity: calc(var(--tome-l4) * .62);
  transform: translateY(calc((1 - var(--tome-l4)) * 8px));
}
.tome-pl-arrow {
  font-size: 1.05em;
  opacity: calc(var(--tome-l4) * .55);
  transform: translateX(calc((1 - var(--tome-l5)) * -6px));
}
.tome-pl-to {
  position: relative;
  font-size: 1.42em; font-weight: 700; line-height: .8;
  font-variant-numeric: tabular-nums;
  color: #46220f;
  opacity: var(--tome-l5);
  transform: translateY(calc((1 - var(--tome-l5)) * 12px)) scale(calc(.62 + var(--tome-l5) * .38));
  text-shadow:
    0 1px 0 rgba(255,250,236,.65),
    0 0 calc(3px + var(--tome-l5) * 12px) color-mix(in srgb, var(--tome-accent) 95%, transparent),
    0 0 calc(var(--tome-l5) * 28px) color-mix(in srgb, var(--tome-accent) 70%, transparent),
    0 0 calc(var(--tome-l5) * 56px) color-mix(in srgb, var(--tome-accent) 40%, transparent);
}
/* the halo behind the new level, breathing slowly once it has landed */
.tome-pl-to::before {
  content: "";
  position: absolute; inset: -55% -70%;
  z-index: -1;
  border-radius: 50%;
  background: radial-gradient(closest-side,
    color-mix(in srgb, var(--tome-accent) 60%, #fff6de) 0%,
    color-mix(in srgb, var(--tome-accent) 34%, transparent) 45%, transparent 72%);
  opacity: calc(var(--tome-l5) * var(--tome-glow) * .9);
  mix-blend-mode: screen;
}

/* transfer: the charge travelling from the tome to the mastery row it raised */
.tome-fx {
  position: fixed;
  inset: 0;
  z-index: 92;
  pointer-events: none;
}
.tome-orb, .tome-spark, .tome-hit-ring {
  position: absolute; left: 0; top: 0;
  opacity: 0;
  mix-blend-mode: screen;
  will-change: transform, opacity;
}
/* a pip rather than a bead - reads as the suit leaving the page */
.tome-orb {
  width: 10px; height: 10px;
  border-radius: 2px 8px 2px 8px;
  background: radial-gradient(closest-side, #fffaf0, color-mix(in srgb, var(--tome-accent) 92%, transparent) 55%, transparent);
  filter: blur(.3px);
}
.tome-spark {
  width: 4px; height: 4px;
  border-radius: 50%;
  background: #fff3d6;
  box-shadow: 0 0 8px color-mix(in srgb, var(--tome-accent) 80%, transparent);
}
.tome-hit-ring {
  border-radius: 8px;
  border: 2px solid color-mix(in srgb, var(--tome-accent) 60%, #fff 40%);
  filter: blur(1.5px);
}

@container app (max-width: 480px) {
  .tome-root { margin-top: 12px; }
}

/* Milestone callouts */
.milestone {
  position: absolute; left: 50%; top: 38%;
  transform: translate(-50%,-50%); text-align: center; white-space: nowrap;
}
.milestone-text {
  font-size: clamp(30px, 6vw, 62px); font-weight: 900; letter-spacing: .16em;
  -webkit-text-stroke: 1px rgba(0,0,0,.35);
}
.milestone-sub { margin-top: 6px; font-size: 13px; letter-spacing: .18em; text-transform: uppercase; color: var(--ink-dim); }
.tone-gold .milestone-text { color: var(--gold); text-shadow: 0 0 46px rgba(255,211,110,.95); }
.tone-ice .milestone-text { color: var(--ice); text-shadow: 0 0 46px rgba(126,230,255,.95); }
.tone-red .milestone-text { color: var(--danger); text-shadow: 0 0 46px rgba(255,77,109,.95); }
.tone-green .milestone-text { color: var(--good); text-shadow: 0 0 46px rgba(139,255,176,.9); }

/* Epic milestone (OVERKILL, etc.) - bigger text plus a spinning ray burst
   behind it, in the spirit of a slot machine's own big-win flourishes. */
.milestone-epic .milestone-text {
  font-size: clamp(38px, 8vw, 84px);
  -webkit-text-stroke: 1.5px rgba(0,0,0,.4);
}
.milestone-epic .milestone-sub { font-size: 15px; margin-top: 10px; color: var(--gold); opacity: .85; }
.milestone-rays {
  position: absolute; left: 50%; top: 50%; width: 900px; height: 900px;
  transform: translate(-50%, -50%);
  background: repeating-conic-gradient(
    rgba(255,211,110,.28) 0deg 8deg,
    rgba(255,211,110,0) 8deg 22deg
  );
  border-radius: 50%;
  z-index: -1;
  animation: rays-spin 6s linear infinite;
  filter: blur(1px);
}
@keyframes rays-spin { to { transform: translate(-50%, -50%) rotate(360deg); } }

.flyer { position: absolute; font-size: 26px; transform: translate(-50%,-50%); }
.confetto { position: absolute; border-radius: 2px; }

/* Floor map */
.floor-map { display: flex; align-items: center; justify-content: center; gap: 3px; margin: 4px 0 14px; flex-wrap: wrap; }
.map-floor {
  position: relative; width: 40px; height: 40px; border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(0,0,0,.35); border: 1px solid var(--edge);
  font-family: var(--font-num); font-weight: 800; font-size: 14px; color: var(--ink-faint);
}
.map-floor.done { border-color: rgba(139,255,176,.5); color: var(--good); background: rgba(60,140,90,.22); }
.map-floor.current {
  border-color: var(--gold); color: var(--gold); background: rgba(255,211,110,.16);
  box-shadow: 0 0 22px rgba(255,211,110,.45); transform: scale(1.18);
}
.map-link { width: 22px; height: 2px; background: var(--edge-bright); }
.map-link.done { background: rgba(139,255,176,.55); }
.map-pips { position: absolute; bottom: -11px; display: flex; gap: 3px; }
.map-pip { width: 7px; height: 4px; border-radius: 99px; background: rgba(255,255,255,.2); }
.map-pip.done { background: var(--good); }
.map-pip.here { background: var(--gold); box-shadow: 0 0 8px var(--gold); }
.map-pip.skipped { background: var(--ink-faint); }

/* Panels */
.panel-card { width: min(760px, 94vw); }
.panel-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 14px; }
.panel-head h2 { margin: 0; }
.panel-sub { font-size: 12px; color: var(--ink-dim); margin-top: 2px; }
.panel-body { display: flex; flex-direction: column; gap: 14px; }
.panel-note { font-size: 12px; line-height: 1.55; color: var(--ink-dim); }
.panel-note.dim { color: var(--ink-faint); }
.panel-list { display: flex; flex-direction: column; gap: 6px; }
.chip.static { cursor: default; background: rgba(255,255,255,.06); }
.ghost.small { padding: 5px 12px; font-size: 12px; }

.seed-row { display: flex; align-items: center; gap: 10px; }
.seed-code {
  font-family: var(--font-num); font-size: 16px; letter-spacing: .2em; color: var(--gold);
  padding: 7px 14px; border-radius: var(--r-sm);
  background: rgba(0,0,0,.42); border: 1px solid var(--edge-bright);
}

.deck-summary { display: flex; gap: 10px; flex-wrap: wrap; }
.deck-suit {
  flex: 1 1 120px; padding: 10px; text-align: center; border-radius: var(--r-md);
  background: rgba(0,0,0,.3); border: 1px solid var(--edge);
}
.deck-suit-glyph { font-size: 24px; line-height: 1; }
.deck-suit-name { font-size: 10px; letter-spacing: .12em; text-transform: uppercase; color: var(--ink-dim); margin-top: 2px; }
.deck-suit-count { font-family: var(--font-num); font-size: 24px; font-weight: 800; }
.deck-suit-total { font-size: 10px; color: var(--ink-faint); }
.deck-suit.aff-STRENGTH { border-color: rgba(255,138,61,.45); } .deck-suit.aff-STRENGTH .deck-suit-count { color: var(--strength); }
.deck-suit.aff-AGILITY { border-color: rgba(70,214,111,.45); } .deck-suit.aff-AGILITY .deck-suit-count { color: var(--agility); }
.deck-suit.aff-ELEMENTAL { border-color: rgba(255,95,162,.45); } .deck-suit.aff-ELEMENTAL .deck-suit-count { color: var(--elemental); }
.deck-suit.aff-ARCANE { border-color: rgba(176,124,255,.45); } .deck-suit.aff-ARCANE .deck-suit-count { color: var(--arcane); }

.deck-counts { display: flex; gap: 10px; flex-wrap: wrap; }
.deck-count-stat {
  flex: 1 1 100px; padding: 8px; text-align: center; border-radius: var(--r-sm);
  background: rgba(0,0,0,.26); border: 1px solid var(--edge);
}
.deck-count-stat strong { display: block; font-family: var(--font-num); font-size: 19px; }
.deck-count-stat span { font-size: 10px; color: var(--ink-faint); }
.deck-count-stat.bad strong { color: var(--danger); }

.deck-group { display: flex; flex-direction: column; gap: 6px; }
.deck-group-title { font-size: 10px; letter-spacing: .16em; text-transform: uppercase; color: var(--ink-faint); }
.deck-rail { display: flex; flex-wrap: wrap; gap: 4px; }
.deck-rail .card { cursor: default; }
.deck-rail .at-hand { outline: 2px solid var(--gold); outline-offset: 1px; }
.deck-rail .at-discard, .deck-rail .at-destroyed { opacity: .3; filter: grayscale(.7); }

.hand-table { display: flex; flex-direction: column; gap: 2px; }
.hand-row {
  display: grid; grid-template-columns: 2fr .6fr .9fr .7fr 1fr .8fr;
  gap: 8px; align-items: center; padding: 6px 10px; border-radius: var(--r-sm);
  font-family: var(--font-num); font-size: 13px;
}
.hand-row.head { font-family: var(--font); font-size: 9px; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-faint); }
.hand-row:not(.head) { background: rgba(0,0,0,.24); }
.hand-row.levelled { background: rgba(255,211,110,.1); border: 1px solid rgba(255,211,110,.25); }
.hand-row-name { font-family: var(--font); font-weight: 700; }
.hand-row-lv { color: var(--gold); font-weight: 800; }
.hand-row-base { color: var(--ice); font-weight: 700; }
.hand-row-plays { color: var(--ink-faint); }

@container app (max-width: 620px) {
  .hand-table .hand-row { grid-template-columns: 1.6fr .5fr .8fr .6fr 1fr; }
  .hand-row-plays, .hand-row.head span:last-child { display: none; }
  .pile { display: none; }
}

/* Seven chrome buttons need more clearance than Build 1's three, and must stay
   on one row - a second row would sit on top of the enemy line. */
.chrome { flex-wrap: nowrap; gap: 5px; }
.chrome-btn { width: 29px; height: 29px; font-size: 13px; flex: 0 0 auto; }
.combat .topbar { padding-right: 250px; }
@container app (max-width: 860px) {
  .chrome { top: auto; bottom: 10px; right: 10px; }
  .combat .topbar { padding-right: 14px; }
}

/* A selected card must never fall when hovered.
   `.card.clickable:hover` carries a pseudo-class and so outranks
   `.card.selected`, which meant pointing at a card you had already picked
   animated it *down* from -26px to -14px. Selection is the stronger state, so
   hovering one lifts further rather than overriding it. */
.card.clickable.selected:hover {
  transform: translateY(-34px) scale(1.1) rotate(-1deg);
  box-shadow:
    0 0 0 2px #fff7d4,
    0 0 0 5px var(--gold),
    0 20px 38px rgba(2,3,12,.66),
    0 36px 70px rgba(2,3,12,.45),
    0 0 38px rgba(var(--card-rgb),.45);
  z-index: 6;
}

/* ==========================================================================
   Card faces
   ========================================================================== */

.card-art {
  position: absolute;
  inset: 15% 12% 15% 12%;
  pointer-events: none;
}

/* Single-glyph fallback: stone cards and small renders. */
.card-art.solo {
  display: grid;
  place-items: center;
  font-size: clamp(38px, 4.4vw, 52px);
  line-height: 1;
}
.card.small .card-art.solo { font-size: 26px; }

/* Numbered cards use a real pip count and a familiar playing-card layout.
   Each pip is the combat identity emoji rather than a traditional suit. */
.card-art.pip-field { inset: 17% 11% 16%; }
.face-pip {
  position: absolute;
  width: clamp(13px, 1.45vw, 19px);
  transform: translate(-50%, -50%);
  filter: drop-shadow(0 1px 2px rgba(0,0,0,.3));
}
.face-pip-icon { display: block; width: 100%; height: auto; }
.face-pip.flipped { transform: translate(-50%, -50%) rotate(180deg); }
.card.small .card-art.pip-field { inset: 21% 14% 20%; }
.card.small .face-pip { width: 9px; }

/* Court cards: a single full-height portrait, suit worn as a chest emblem.
   Top/bottom inset is generous (16%) so the crown and the hem clear the
   frame art's own medallions instead of sitting on top of them. */
.card-art.court { inset: 16% 10%; }
.card-art.court svg { width: 100%; height: 100%; display: block; }
.court-emblem {
  position: absolute;
  left: 50%;
  top: 77%;
  transform: translate(-50%, -50%);
  width: clamp(25px, 2.6vw, 34px);
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: rgba(255,255,255,.92);
  border: 1px solid rgba(0,0,0,.16);
  box-shadow: 0 2px 6px rgba(0,0,0,.22);
}
.court-emblem-icon { width: 65%; height: 65%; object-fit: contain; }
.card.small .court-emblem { width: 18px; }

/* The ace takes the whole face. */
.card-art.ace { display: grid; place-items: center; }
.ace-glyph { width: clamp(40px, 5vw, 58px); height: auto; filter: drop-shadow(0 2px 4px rgba(0,0,0,.3)); }
.ace-ring {
  position: absolute;
  width: 76%; aspect-ratio: 1;
  border: 2px solid currentColor;
  border-radius: 50%;
  opacity: .3;
}
.ace-ring::after {
  content: "";
  position: absolute; inset: 5px;
  border: 1px solid currentColor;
  border-radius: 50%;
  opacity: .55;
}

/* Suit colour reaches the court figure's SVG through currentColor - the pips,
   corner and ace glyphs are the real icon art now and carry their own colour. */
.suit-H .card-art, .suit-D .card-art, .suit-C .card-art, .suit-S .card-art { color: inherit; }
.suit-H .card-art { color: #d99a2b; }
.suit-D .card-art { color: #7a4fd1; }
.suit-C .card-art { color: #b3312c; }
.suit-S .card-art { color: #2f8f52; }

/* Faint linen so the face is not flat white. */
.card-face::before {
  content: "";
  position: absolute; inset: 0;
  border-radius: inherit;
  pointer-events: none;
  opacity: .5;
  background-image:
    repeating-linear-gradient(90deg, rgba(0,0,0,.022) 0 1px, transparent 1px 3px),
    repeating-linear-gradient(0deg, rgba(0,0,0,.022) 0 1px, transparent 1px 3px);
}

/* A specular highlight that follows the cursor. */
.card-gloss {
  position: absolute; inset: 0;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  transition: opacity .18s;
  background: radial-gradient(
    150px circle at var(--mx, 50%) var(--my, 50%),
    rgba(255,255,255,.85), rgba(255,255,255,.18) 42%, transparent 66%);
  mix-blend-mode: overlay;
}
.card.clickable:hover .card-gloss { opacity: 1; }

/* Draw pile shows a patterned back rather than a blank slab. */
.pile.draw .pile-stack {
  background:
    repeating-linear-gradient(45deg, rgba(255,211,110,.16) 0 3px, transparent 3px 7px),
    repeating-linear-gradient(-45deg, rgba(126,230,255,.14) 0 3px, transparent 3px 7px),
    linear-gradient(160deg, #34386b, #1d2044);
  border-color: rgba(255,211,110,.34);
}
.pile.draw .pile-stack::after {
  content: "";
  position: absolute; inset: 6px;
  border: 1px solid rgba(255,255,255,.16);
  border-radius: 4px;
}
.pile-stack { position: relative; }

/* Selection reads as committed rather than merely hovered. */
.card.selected .card-face {
  box-shadow:
    inset 0 0 0 2px rgba(255,211,110,.74),
    inset 0 1px 0 rgba(255,255,255,.96);
}
.card.selected .card-gloss {
  opacity: .28;
  background:
    linear-gradient(125deg, transparent 20%, rgba(255,255,255,.55) 43%, transparent 64%),
    radial-gradient(160px circle at var(--mx, 50%) var(--my, 50%), rgba(255,255,255,.7), transparent 62%);
}
.hand-rail .card[data-selection-order]::after {
  content: attr(data-selection-order);
  position: absolute;
  top: -9px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 30;
  width: 25px;
  height: 25px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  color: #241a05;
  background: linear-gradient(180deg, #fff1bc, var(--gold));
  border: 2px solid #fff8dc;
  box-shadow: 0 4px 12px rgba(0,0,0,.48), 0 0 18px rgba(255,211,110,.48);
  font-family: var(--font-num);
  font-size: 12px;
  font-weight: 900;
}

/* ==========================================================================
   Fanned hand
   ==========================================================================
   The arc is expressed through --rot and --lift so every interactive state can
   build on it. Writing the fan straight into `transform` would mean hover and
   selection had to restate it, and any state that forgot would snap the card
   out of the arc - which is the same class of bug as the selected-hover drop.
   ========================================================================== */

.hand-rail .card {
  transform: translateY(var(--lift, 0px)) rotate(var(--rot, 0deg));
  transform-origin: bottom center;
}
.hand-rail .card.clickable:not(.selected) {
  animation: cardIdleFloat var(--card-float-duration) ease-in-out var(--card-float-delay) infinite both;
}
@keyframes cardIdleFloat {
  0%, 100% { translate: 0 0; }
  23% { translate: 0 -1px; }
  51% { translate: 0 .5px; }
  76% { translate: 0 -2px; }
}
.hand-rail .card.clickable:hover {
  animation: none;
  translate: 0 -1px;
  transform: translateY(calc(var(--lift, 0px) - 18px)) rotate(0deg) scale(1.075);
  box-shadow:
    0 3px 0 rgba(56,39,24,.25),
    0 20px 34px rgba(2,3,12,.66),
    0 38px 72px rgba(2,3,12,.46),
    0 0 34px rgba(var(--card-rgb),.34);
  z-index: 20 !important;
}
.hand-rail .card.selected {
  animation: none;
  translate: 0 -1px;
  transform: translateY(calc(var(--lift, 0px) - 28px)) rotate(0deg) scale(1.06);
  z-index: 21 !important;
}
.hand-rail .card.clickable.selected:hover {
  translate: 0 -2px;
  transform: translateY(calc(var(--lift, 0px) - 37px)) rotate(0deg) scale(1.1);
  z-index: 22 !important;
}
.hand-rail .card.clickable:active {
  animation: none;
  translate: 0 1px;
  transform: translateY(calc(var(--lift, 0px) - 11px)) rotate(0deg) scale(.99);
  box-shadow:
    0 2px 0 rgba(56,39,24,.22),
    0 9px 18px rgba(2,3,12,.58),
    0 0 22px rgba(var(--card-rgb),.28);
  transition-duration: .06s;
}
.hand-rail .card.clickable.selected:active {
  transform: translateY(calc(var(--lift, 0px) - 24px)) rotate(0deg) scale(1.015);
}
.card.clickable:focus-visible {
  outline: 3px solid var(--ice);
  outline-offset: 5px;
  box-shadow:
    0 0 0 2px rgba(8,9,24,.9),
    0 0 0 6px rgba(126,230,255,.5),
    0 20px 44px rgba(2,3,12,.62);
}

/* Overlap slightly so the fan reads as one hand rather than a row of tiles.
   The rail reserves padding for the lift above and the sag below: transforms do
   not affect layout, so without it a raised card climbs into the tools bar and a
   sagging one sits on top of the action buttons. */
.combat .hand-rail { gap: 0; padding: 36px 6px 26px; align-items: flex-start; }
.combat .hand-rail .card { margin: 0 -3px; }

/* Selection readout: hand type sits above the leftmost card, sort remains
   centred, and the forecast holds the right edge. This keeps the three pieces
   stable instead of letting changing copy push Rank/Suit around. */
.hand-tools {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  padding-inline: 70px;
}
.hand-tools .preview {
  grid-column: 1;
  grid-row: 1;
  justify-self: start;
  flex-wrap: wrap;
}
.hand-tools .sort-group {
  position: static;
  grid-column: 2;
  grid-row: 1;
  justify-self: center;
  transform: none;
}
.hand-tools .forecast {
  grid-column: 3;
  grid-row: 1;
  justify-self: end;
  text-align: right;
}
.preview-empty { color: var(--ink-faint); font-size: 11px; }
.selection-count {
  padding: 2px 7px;
  border-radius: 99px;
  color: var(--ink-dim);
  background: rgba(255,255,255,.06);
  border: 1px solid var(--edge);
  font-family: var(--font-num);
  font-size: 10px;
  font-weight: 800;
}
button.selection-clear {
  padding: 2px 7px;
  border-radius: 99px;
  color: var(--ink-dim);
  background: transparent;
  border-color: var(--edge);
  box-shadow: none;
  font-size: 10px;
}

@container app (max-width: 760px) {
  .hand-tools {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    row-gap: 5px;
    padding-inline: 0;
  }
  .hand-tools .preview { grid-column: 1; grid-row: 1; }
  .hand-tools .forecast { grid-column: 2; grid-row: 1; }
  .hand-tools .sort-group { grid-column: 1 / -1; grid-row: 2; }
}

@container app (max-width: 560px) {
  .combat .enemy { width: clamp(104px, 29vw, 128px); padding: 8px 9px 10px; }
  .combat .enemy-art { font-size: clamp(34px, 10vw, 46px); }
  .combat .enemy.boss { width: clamp(132px, 38vw, 168px); }
  .combat .enemy-row.tier-patrol .enemy-portrait { --portrait: clamp(56px, 16vw, 74px); }
  .combat .enemy-row.tier-elite  .enemy-portrait { --portrait: clamp(68px, 20vw, 92px); }
  .combat .enemy-row.tier-warden .enemy-portrait { --portrait: clamp(72px, 21vw, 96px); }
  .combat .enemy.boss .enemy-portrait { --portrait: clamp(104px, 30vw, 138px); }
}

/* ==========================================================================
   Combat layout variants
   --------------------------------------------------------------------------
   Three arrangements of the same markup, switched with F1-F3. Everything above
   this block is the Classic layout; the two below re-place the *same* nodes
   with CSS grid, using `display: contents` on the wrappers so their children
   can be positioned individually. No variant may add or reorder DOM - see the
   header of `web2/layouts.ts` for why.
   ========================================================================== */

.layout-pill {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 4px 12px 4px 6px;
  border-radius: 99px;
  background: linear-gradient(90deg, rgba(126,120,255,.35), rgba(126,120,255,.12));
  border: 1px solid rgba(150,140,255,.4);
  color: var(--ink);
  cursor: pointer;
  font: inherit;
  white-space: nowrap;
}
.layout-pill:hover { border-color: rgba(180,170,255,.75); }
.layout-pill-key {
  padding: 1px 6px;
  border-radius: 99px;
  background: rgba(0,0,0,.42);
  font-family: var(--font-num);
  font-size: 10px;
  font-weight: 800;
  color: #cfc7ff;
}
.layout-pill-name {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: .16em;
  text-transform: uppercase;
}

/* The room's name. Classic keeps it to a quiet line; the wide layouts promote
   it to a masthead over the enemy arcade. */
/* Classic is the tightest of the three for vertical space, so the room's name
   is one quiet line there. The wide layouts promote it to a masthead. */
.encounter-title {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 10px;
  text-align: center;
}
.layout-cathedral .encounter-title,
.layout-command .encounter-title { display: block; }
.layout-command .encounter-title { text-align: left; }
.encounter-place {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: .34em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.encounter-name {
  margin: 0;
  font-size: 13px;
  font-weight: 900;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink);
}

/* An unfilled socket, drawn rather than described.
   In the stacked layout it is a narrow marker: it exists to say "this space is
   yours", and giving it a full gem tile's footprint would let five empty
   sockets eat the row that the actual gems need. The rail layouts below widen
   it back out and reveal the label, because a vertical rail has the room. */
.gem-empty {
  width: clamp(50px, 4.6vw, 66px);
  min-height: 0;
  height: auto;
  padding: 22px 6px;
  justify-content: center;
  gap: 6px;
  border-style: dashed;
  border-color: var(--edge-bright);
  background: rgba(255,255,255,.02);
  box-shadow: none;
  cursor: help;
}
.gem-empty-mark { font-size: 15px; color: var(--ink-faint); }
.gem-empty-label {
  display: none;
  font-size: 9px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.layout-cathedral .gem-empty-label,
.layout-command .gem-empty-label { display: block; }
.rail-note { color: var(--ink-faint); font-weight: 400; text-transform: none; letter-spacing: .04em; }
.rail-title { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }

/* --------------------------------------------------------------------------
   F2 — Crystal Cathedral
   Two resource rails flank a lit arcade. The left rail is what you spend, the
   right is what you hold, and neither ever moves; the centre column carries
   everything that changes during a hand. The point is that your eyes track one
   region while playing and glance sideways only to plan.

   Only `.topbar` and `.tableau` are dissolved with `display: contents`. The
   encounter and scoreboard stay intact blocks that stack internally, which is
   what keeps this from becoming a pile of margin offsets.
   -------------------------------------------------------------------------- */

.combat.layout-cathedral {
  --rail-bg: linear-gradient(180deg, rgba(10,20,48,.72), rgba(6,12,32,.5));
  --rail-edge: 1px solid rgba(120,190,255,.22);
  display: grid;
  grid-template-columns: minmax(190px, 232px) minmax(0, 1fr) minmax(190px, 232px);
  grid-template-rows: auto auto auto auto 1fr;
  grid-template-areas:
    "ident   foes   money"
    "budget  foes   chest"
    "gems    score  cons"
    "gems    play   cons"
    "gems    hand   cons";
  align-content: start;
  gap: 10px 16px;
  /* Clears the fixed chrome buttons. Classic reserves that space inside the
     top bar, but here the bar is dissolved and the money mount would sit
     underneath them. */
  padding-top: 32px;
}

.layout-cathedral .topbar,
.layout-cathedral .tableau,
.layout-cathedral .tableau-lower { display: contents; }

.layout-cathedral .topbar-left {
  grid-area: ident;
  flex-direction: column;
  align-items: stretch;
  gap: 7px;
}
/* Every rail mount pins to the top of its area. Without this they stretch to
   the height of the enemy arcade beside them and become empty slabs. */
.layout-cathedral .topbar-left,
.layout-cathedral .topbar-budget,
.layout-cathedral .topbar-right,
.layout-cathedral .topbar-mid { align-self: start; }
.layout-cathedral .topbar-budget { grid-area: budget; align-items: stretch; }
.layout-cathedral .topbar-budget .stat { flex: 1; flex-direction: column; gap: 1px; padding: 8px 6px; }
.layout-cathedral .topbar-right { grid-area: money; align-items: stretch; }
.layout-cathedral .topbar-right .stat {
  flex: 1;
  flex-direction: column;
  align-items: flex-start;
  gap: 0;
  padding: 8px 14px;
}
.layout-cathedral .topbar-right .stat-value { font-size: 28px; }
.layout-cathedral .topbar-mid { grid-area: chest; }

/* One border treatment for everything mounted on a rail. */
.layout-cathedral .topbar-left .stat,
.layout-cathedral .topbar-budget .stat,
.layout-cathedral .topbar-right .stat,
.layout-cathedral .chest-badge,
.layout-cathedral .gem-block,
.layout-cathedral .consumable-block {
  background: var(--rail-bg);
  border: var(--rail-edge);
  border-radius: var(--r-md);
}
.layout-cathedral .layout-pill { align-self: start; }

.layout-cathedral .gem-block { grid-area: gems; align-self: start; padding: 10px; }
.layout-cathedral .gem-rail { flex-direction: column; }
.layout-cathedral .gem,
.layout-cathedral .gem-empty {
  width: 100%;
  flex-direction: row;
  justify-content: flex-start;
  gap: 8px;
  padding: 7px 9px;
}
/* Effect text does not fit a narrow rail; the tooltip still carries it. */
.layout-cathedral .gem .gem-text { display: none; }
.layout-cathedral .gem .gem-art { width: 30px; height: 30px; }
.layout-cathedral .gem-order { position: static; }

.layout-cathedral .chest-badge {
  flex-direction: column;
  text-align: center;
  gap: 8px;
  min-width: 0;
  padding: 12px;
}
.layout-cathedral .chest-badge-art { width: 68px; height: 68px; }
.layout-cathedral .consumable-block { grid-area: cons; align-self: start; padding: 10px; }
.layout-cathedral .consumable-rail { flex-direction: column; }
.layout-cathedral .consumable { width: 100%; }

/* The arcade: each enemy stands in a lit alcove under the room's name. */
.layout-cathedral .encounter { grid-area: foes; }
.layout-cathedral .encounter-place { font-size: 11px; letter-spacing: .42em; color: var(--ice); }
.layout-cathedral .encounter-name { font-size: clamp(19px, 2.2vw, 28px); letter-spacing: .16em; }
.layout-cathedral .enemy {
  background:
    radial-gradient(120% 80% at 50% 0%, rgba(120,190,255,.2), transparent 62%),
    linear-gradient(180deg, rgba(16,32,68,.9), rgba(8,14,36,.92));
  border: 1px solid rgba(140,200,255,.34);
  border-radius: 120px 120px var(--r-md) var(--r-md);
  padding-top: 18px;
}
.layout-cathedral .enemy::before {
  background: linear-gradient(90deg, transparent, #9fd6ff, #c7b3ff, transparent);
}
.layout-cathedral .enemy.boss { border-color: rgba(255,206,106,.55); }

.layout-cathedral .scoreboard { grid-area: score; }
.layout-cathedral .play-area { grid-area: play; background: none; border-color: transparent; min-height: 64px; }
.layout-cathedral .gem-empty { padding: 9px; }
.combat.layout-cathedral .gem,
.combat.layout-cathedral .gem-empty { min-height: 0; height: auto; }
.layout-cathedral .hand-panel { grid-area: hand; }

/* Hexagonal readouts: the numbers stop being boxes and start being cut stones. */
.layout-cathedral .chips-box,
.layout-cathedral .mult-box,
.layout-cathedral .total-box {
  clip-path: polygon(13% 0, 87% 0, 100% 50%, 87% 100%, 13% 100%, 0 50%);
  border-radius: 0;
  padding-left: 24px;
  padding-right: 24px;
}

/* --------------------------------------------------------------------------
   F3 — Command Deck
   The enemy line becomes a target list: one row each, art left, full-width
   health bar right, read top to bottom. It is the densest of the three and the
   only one that holds up when a room is crowded, because rows stack where
   tiles wrap. The whole right half is then free for the hand.
   -------------------------------------------------------------------------- */

.combat.layout-command {
  display: grid;
  /* The left side is two sub-columns, not one stack. Giving the sockets and
     the consumables their own rows made the left column taller than the right
     on its own, and since grid rows are shared that pushed the action buttons
     below the fold no matter how much the right column was trimmed. Sitting
     them side by side removes a whole row. */
  grid-template-columns: minmax(170px, 17%) minmax(140px, 14%) minmax(0, 1fr);
  grid-template-areas:
    "bar   bar   bar"
    "foes  foes  score"
    "foes  foes  play"
    "gems  cons  hand";
  /* Every row is content-sized and every item pins to the top of its row. A
     `1fr` row anywhere here lets one column's spare height inflate the other's
     block into a giant empty slab and push the hand off screen. */
  grid-auto-rows: auto;
  align-content: start;
  align-items: start;
  gap: 10px 16px;
}

.layout-command .tableau,
.layout-command .tableau-lower { display: contents; }

.layout-command .topbar { grid-area: bar; }
.layout-command .encounter { grid-area: foes; align-self: start; }
.layout-command .encounter-title { text-align: left; }
.layout-command .enemy-row {
  flex-direction: column;
  align-items: stretch;
  gap: 8px;
}
/* A target row, not a portrait tile. This is the arrangement that does not
   degrade as enemies are added: rows stack, tiles wrap. */
.combat.layout-command .enemy { padding: 7px 12px; }
.combat.layout-command .enemy {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  grid-template-rows: auto auto;
  align-items: center;
  column-gap: 12px;
  width: 100%;
  padding: 10px 14px;
  text-align: left;
}
.layout-command .enemy-art { grid-row: 1 / span 2; }
/* Out-specifies `.combat .enemy-row.tier-elite .enemy-portrait` in the base
   sheet, which would otherwise keep the tier sizing and make every target row
   twice as tall as it needs to be. */
.combat.layout-command .enemy-row .enemy-portrait { --portrait: 46px; width: 46px; }
.combat.layout-command .enemy-row .enemy.boss .enemy-portrait { --portrait: 66px; width: 66px; }
.layout-command .enemy.boss { width: 100%; }
.layout-command .enemy-name { margin: 0 0 5px; align-self: end; }
.layout-command .hp-bar { align-self: start; height: 17px; }
.layout-command .hp-text { line-height: 18px; font-size: 11px; }
.layout-command .enemy-slain { border-radius: var(--r-md); }
.layout-command .meters { flex-direction: column; align-items: stretch; }
.layout-command .meter { width: 100%; }

.layout-command .gem-block { grid-area: gems; align-self: start; }
.layout-command .consumable-block { grid-area: cons; align-self: start; }
.layout-command .gem-rail { flex-direction: column; }
.layout-command .gem,
.layout-command .gem-empty {
  width: 100%;
  flex-direction: row;
  justify-content: flex-start;
  gap: 9px;
  padding: 7px 9px;
  text-align: left;
}
/* The base tile is a portrait card with a min-height sized for its effect
   text. Stacked in a narrow rail that becomes 115px per socket, so the block
   grows past the viewport and pushes the hand off screen. */
.combat.layout-command .gem,
.combat.layout-command .gem-empty { min-height: 0; height: auto; }
/* The left column is the binding constraint on total height here - it stacks
   the target list, the sockets and the consumables while the right column only
   has to fit the hand. Everything in it is trimmed so the action row stays
   above the fold on a 1280x800 screen. */
.combat.layout-command .gem-empty { padding: 3px 9px; }
.combat.layout-command .gem { padding: 6px 9px; }
.combat.layout-command .gem .gem-text {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.combat.layout-command .consumable-rail { gap: 6px; }
.combat.layout-command .meters { gap: 6px; }
.combat.layout-command .meter { padding: 5px 10px; }
.layout-command .gem .gem-art { width: 32px; height: 32px; }
.layout-command .gem .gem-text { font-size: 9px; }
.layout-command .gem-order { position: static; }

.layout-command .scoreboard { grid-area: score; }
 /* Stretches to fill the height the target list forces on its row, so the
    landing zone uses the space instead of leaving a hole. */
.layout-command .play-area { grid-area: play; min-height: 88px; align-self: stretch; }
.layout-command .hand-panel { grid-area: hand; }

/* --------------------------------------------------------------------------
   Both wide layouts give the hand a narrower column than Classic does, so the
   cards shrink to keep the fan on one row. A wrapped hand is the one failure
   that makes a layout unusable: it pushes the action buttons off screen.
   -------------------------------------------------------------------------- */
.layout-cathedral .card { width: clamp(58px, 6.2vw, 84px); }
.layout-command .card { width: clamp(64px, 6.6vw, 92px); }
.layout-cathedral .hand-rail,
.layout-command .hand-rail { flex-wrap: nowrap; }
.layout-cathedral .hand-with-piles,
.layout-command .hand-with-piles { gap: 8px; }

/* Below this width a three-column split leaves every rail too narrow to read,
   so both wide layouts fall back to the Classic column. */
@container app (max-width: 1120px) {
  .combat.layout-cathedral,
  .combat.layout-command {
    display: flex;
    flex-direction: column;
  }
  .layout-cathedral .topbar,
  .layout-cathedral .tableau,
  .layout-cathedral .tableau-lower,
  .layout-command .tableau,
  .layout-command .tableau-lower { display: flex; }
  .layout-cathedral .topbar { justify-content: space-between; }
  .layout-cathedral .topbar-left { flex-direction: row; }
  .layout-cathedral .gem-rail,
  .layout-cathedral .consumable-rail,
  .layout-command .gem-rail,
  .layout-command .enemy-row,
  .layout-command .meters { flex-direction: row; flex-wrap: wrap; }
  .layout-cathedral .gem,
  .layout-cathedral .gem-empty,
  .layout-cathedral .consumable,
  .layout-command .gem,
  .layout-command .gem-empty,
  .layout-command .enemy { width: auto; }
  .layout-command .enemy { display: flex; flex-direction: column; text-align: center; }
  .layout-cathedral .hand-rail,
  .layout-command .hand-rail { flex-wrap: wrap; }
  .layout-cathedral .card,
  .layout-command .card { width: clamp(76px, 8.4vw, 104px); }
}

/* ==========================================================================
   Enemy arrivals and per-enemy shields
   ========================================================================== */

/* The room slides in once per encounter, driven from `stageEntrance`.
   `--enter-delay` staggers the escorts; the Warden lands last and from above,
   so the eye is pulled to the centre exactly as the screen shake hits. */
.enemy.entering { animation-duration: .58s; animation-fill-mode: both; animation-timing-function: cubic-bezier(.16,.9,.3,1.25); animation-delay: var(--enter-delay, 0s); }
.enemy.enter-quick { animation-duration: .34s; animation-timing-function: cubic-bezier(.2,.9,.35,1.08); }
.enemy.enter-grand { animation-duration: .62s; }

.enemy.enter-left  { animation-name: enemyEnterLeft; }
.enemy.enter-right { animation-name: enemyEnterRight; }
.enemy.enter-top   { animation-name: enemyEnterTop; }
/* A warm-up steps in from just off its own slot rather than off the screen. */
.enemy.enter-quick.enter-left  { animation-name: enemyStepLeft; }
.enemy.enter-quick.enter-right { animation-name: enemyStepRight; }
.enemy.enter-quick.enter-top   { animation-name: enemyStepLeft; }

@keyframes enemyEnterLeft {
  0%   { opacity: 0; transform: translateX(-95vw) rotate(-9deg); }
  72%  { opacity: 1; transform: translateX(10px) rotate(2deg); }
  86%  { transform: translateX(-4px) rotate(-1deg) scaleY(.94); }
  100% { opacity: 1; transform: none; }
}
@keyframes enemyEnterRight {
  0%   { opacity: 0; transform: translateX(95vw) rotate(9deg); }
  72%  { opacity: 1; transform: translateX(-10px) rotate(-2deg); }
  86%  { transform: translateX(4px) rotate(1deg) scaleY(.94); }
  100% { opacity: 1; transform: none; }
}
/* Drops from above and squashes on landing - the impact is the whole point. */
@keyframes enemyEnterTop {
  0%   { opacity: 0; transform: translateY(-78vh) scale(1.14); }
  62%  { opacity: 1; transform: translateY(0) scale(1.06); }
  74%  { transform: translateY(0) scaleY(.82) scaleX(1.14); }
  88%  { transform: translateY(-12px) scaleY(1.05) scaleX(.97); }
  100% { opacity: 1; transform: none; }
}
@keyframes enemyStepLeft {
  0%   { opacity: 0; transform: translateX(-46px); }
  100% { opacity: 1; transform: none; }
}
@keyframes enemyStepRight {
  0%   { opacity: 0; transform: translateX(46px); }
  100% { opacity: 1; transform: none; }
}

/* A shielded enemy wears its plate. Which enemies carry one is decided by the
   engine, so this is a readout, not decoration - see `Enemy.shielded`. */
.enemy.shielded {
  border-color: rgba(126,230,255,.5);
  box-shadow: 0 12px 30px rgba(3,4,14,.54), 0 0 26px rgba(120,200,255,.24), inset 0 1px 0 rgba(255,255,255,.1);
}
.enemy.shielded::after {
  content: "";
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  pointer-events: none;
  background: linear-gradient(150deg, rgba(140,220,255,.16), transparent 46%, rgba(140,220,255,.1));
  box-shadow: inset 0 0 22px rgba(120,200,255,.28);
  animation: wardShimmer 3.4s ease-in-out infinite;
}
@keyframes wardShimmer {
  0%, 100% { opacity: .55; }
  50% { opacity: 1; }
}
.enemy-ward {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 26px;
  height: 26px;
  object-fit: contain;
  filter: drop-shadow(0 2px 6px rgba(0,0,0,.6));
  z-index: 2;
}
.enemy.shielded.ward-down::after { animation: none; opacity: .28; }

/* ==========================================================================
   Targeting and enemy traits
   --------------------------------------------------------------------------
   A target picks where a hand *starts*; spillover still chains outward from
   there. The ring says "damage lands here first", not "damage stops here".
   ========================================================================== */

.enemy.clickable { cursor: pointer; }
.enemy.clickable:hover { translate: 0 -4px; filter: brightness(1.1); }

.enemy.targeted {
  border-color: rgba(255,211,110,.8);
  box-shadow:
    0 0 0 2px rgba(255,211,110,.55),
    0 14px 34px rgba(3,4,14,.6),
    0 0 30px rgba(255,180,80,.24);
}
/* A crosshair pinned to the tile rather than an outline on it: an outline reads
   as "selected", and this is an aiming decision. */
.enemy.targeted::after {
  content: "◎";
  position: absolute;
  top: 4px;
  left: 8px;
  font-size: 16px;
  line-height: 1;
  color: var(--gold);
  text-shadow: 0 0 10px rgba(255,211,110,.8);
  animation: targetPulse 1.8s ease-in-out infinite;
  z-index: 3;
  pointer-events: none;
}
@keyframes targetPulse {
  0%, 100% { opacity: .75; transform: scale(1); }
  50% { opacity: 1; transform: scale(1.16); }
}
/* The ward plate already owns ::after on a shielded enemy, so a shielded target
   gets its crosshair from a shifted position instead of losing it. */
.enemy.shielded.targeted::after {
  content: "";
  background: linear-gradient(150deg, rgba(140,220,255,.16), transparent 46%, rgba(140,220,255,.1));
}
.enemy.shielded.targeted { outline: 2px solid rgba(255,211,110,.7); outline-offset: -1px; }

/* Traits, stated on the creature. These are the reason to aim at one enemy
   over another, so they must be readable in the same glance that picks it. */
.enemy-traits { display: flex; flex-direction: column; gap: 4px; margin-top: 7px; }
.enemy-trait {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  padding: 3px 7px;
  border-radius: 6px;
  font-size: 9px;
  font-weight: 800;
  letter-spacing: .04em;
  text-transform: uppercase;
  line-height: 1.2;
}
.enemy-trait.weak {
  background: rgba(139,255,176,.14);
  border: 1px solid rgba(139,255,176,.4);
  color: #b6ffd0;
}
.enemy-trait.volatile {
  background: rgba(255,90,110,.14);
  border: 1px solid rgba(255,90,110,.42);
  color: #ffb3bd;
}
.trait-icon { font-size: 11px; }

/* The creature that just swung back. Cleared by the next render. */
.enemy.provoked { animation: enemyProvoked .5s ease-out 2; }
@keyframes enemyProvoked {
  0%, 100% { box-shadow: 0 12px 30px rgba(3,4,14,.54); }
  40% { box-shadow: 0 0 30px 6px rgba(255,77,109,.7); }
}

/* Command Deck lays traits out beside the health bar instead of under it. */
.layout-command .enemy-traits { flex-direction: row; flex-wrap: wrap; margin-top: 5px; grid-column: 2; }
.layout-command .enemy { grid-template-rows: auto auto auto; }

/* ---------------------------------------------------------------------------
   Heroes and the Soul ladder
   ---------------------------------------------------------------------------
   The LOST state is one CSS rule, not a second art asset: brightness(0) reduces
   any portrait to its own silhouette. That is what lets a hero read as Lost
   before their artwork exists at all - the fallback plate has a silhouette too.
   --------------------------------------------------------------------------- */

.hero-portrait {
  position: relative;
  width: 76px;
  aspect-ratio: 1;
  border-radius: 16px;
  overflow: hidden;
  flex: 0 0 auto;
  background:
    radial-gradient(70% 70% at 50% 30%, rgba(var(--deck-rgb), .28), transparent 70%),
    linear-gradient(165deg, rgba(20, 22, 44, .95), rgba(9, 10, 20, .98));
  border: 1px solid rgba(var(--deck-rgb), .42);
  box-shadow: 0 6px 18px rgba(0, 0, 0, .45), inset 0 1px 0 rgba(255, 255, 255, .06);
}
.hero-portrait.small { width: 58px; border-radius: 13px; }
/* The title screen's own hero pick - big enough that the character reads as a
   character, not a thumbnail you take on faith. */
.hero-portrait.xl { width: 340px; border-radius: 26px; }
.hero-portrait.xl .hero-portrait-art { font-size: 96px; }
.hero-portrait.xl .hero-portrait-lock { font-size: 40px; bottom: 14px; }
.hero-portrait.xl .hero-portrait-chain-bar { height: 16px; margin-top: -8px; }

.hero-portrait-art {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: grid;
  place-items: center;
  font-size: 26px;
  line-height: 1;
}
.hero-portrait.small .hero-portrait-art { font-size: 20px; }

/* The stand-in until artwork lands. Deliberately a solid shape rather than a
   dashed "missing asset" box, because it has to silhouette convincingly. */
.hero-portrait-plate {
  background: radial-gradient(60% 60% at 50% 40%, rgba(var(--deck-rgb), .5), rgba(var(--deck-rgb), .14) 70%, transparent);
  text-shadow: 0 2px 8px rgba(0, 0, 0, .7);
}

/* Rank 0. Fully collapsed to shadow, with the outline still flickering, and a
   brief flash of the restored form on a long cycle - 150ms out of 7.3s, per the
   restoration bible. The flash is the hook: it is the only glimpse of who this
   is, and it is over before you can study it. */
.hero-portrait.lost { border-color: rgba(var(--deck-rgb), .22); }
.hero-portrait.lost .hero-portrait-art {
  filter: brightness(0) contrast(1.4);
  opacity: .88;
  animation: lost-flash 7.3s steps(1, end) infinite;
}
.hero-portrait.lost::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(180deg, transparent 40%, rgba(var(--deck-rgb), .16) 50%, transparent 60%);
  animation: lost-scan 4.1s linear infinite;
}

@keyframes lost-flash {
  0%, 96.9% { filter: brightness(0) contrast(1.4); opacity: .88; }
  97%, 98.9% { filter: none; opacity: 1; }
  99%, 100% { filter: brightness(0) contrast(1.4); opacity: .88; }
}
@keyframes lost-scan {
  0% { transform: translateY(-100%); }
  100% { transform: translateY(100%); }
}

/* A flickering silhouette is exactly the effect a motion-sensitive player asked
   to be spared. The state still reads: it is still a black silhouette. */
@media (prefers-reduced-motion: reduce) {
  .hero-portrait.lost .hero-portrait-art { animation: none; }
  .hero-portrait.lost::after { animation: none; opacity: 0; }
}

/* The chained read: two crossed iron bars and a padlock glyph, laid over the
   flickering silhouette every LOST portrait already has. Texture carries the
   mood; the glyph carries the meaning, so it still reads at 58px. */
.hero-portrait-chain-bar {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 145%;
  height: 8px;
  margin: -4px 0 0 -72.5%;
  background: repeating-linear-gradient(
    90deg,
    rgba(222, 226, 238, .88) 0 5px,
    rgba(96, 101, 126, .65) 5px 7px,
    transparent 7px 10px
  );
  box-shadow: 0 1px 2px rgba(0, 0, 0, .65);
  opacity: .85;
  pointer-events: none;
}
.hero-portrait-chain-bar.chain-a { transform: rotate(33deg); }
.hero-portrait-chain-bar.chain-b { transform: rotate(-33deg); }
.hero-portrait-lock {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 5px;
  text-align: center;
  font-size: 15px;
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, .75));
  pointer-events: none;
}
.hero-portrait.small .hero-portrait-lock { font-size: 11px; bottom: 3px; }
.hero-portrait.small .hero-portrait-chain-bar { height: 6px; }

/* Rank 1: AWAKENING. Real beginner-tier art, still unsettled - it glitches in
   once when the portrait first mounts (the moment the chains break) and is
   left with a slow, faint residual flicker rather than the LOST state's heavy
   black-out. "Eyes illuminate. Silhouette stabilizes slightly." */
.hero-portrait.awakening .hero-portrait-art {
  filter: saturate(.4) brightness(.82) contrast(1.12);
  animation:
    hero-awaken-in 900ms cubic-bezier(.2, .85, .25, 1) both,
    hero-awaken-idle 3.6s ease-in-out 900ms infinite;
}
@keyframes hero-awaken-in {
  0% { filter: brightness(0) contrast(1.4); opacity: .85; }
  9% { filter: none; opacity: 1; }
  16% { filter: brightness(0) contrast(1.4); opacity: .85; }
  24% { filter: none; opacity: 1; }
  38% { filter: saturate(.25) brightness(.7); opacity: .92; }
  100% { filter: saturate(.4) brightness(.82) contrast(1.12); opacity: 1; }
}
@keyframes hero-awaken-idle {
  0%, 100% { filter: saturate(.4) brightness(.82) contrast(1.12); }
  50% { filter: saturate(.55) brightness(.92) contrast(1.04); }
}
@media (prefers-reduced-motion: reduce) {
  .hero-portrait.awakening .hero-portrait-art {
    animation: none;
    filter: saturate(.4) brightness(.82) contrast(1.12);
  }
}

/* Ranks 7+: a soul-glow the flat art tiers alone don't carry. Legendary adds a
   steady rim light; Ascendant (rank 10 only - see heroArtTier) intensifies it
   into a slow breathing shimmer, the one CSS cue marking the climb's actual
   endpoint. */
.hero-portrait.revealed.tier-legendary {
  box-shadow: 0 6px 18px rgba(0, 0, 0, .45), inset 0 1px 0 rgba(255, 255, 255, .06),
    0 0 16px rgba(var(--deck-rgb), .38);
  border-color: rgba(var(--deck-rgb), .75);
}
.hero-portrait.revealed.tier-ascendant {
  border-color: rgba(var(--deck-rgb), .95);
  animation: hero-ascendant-glow 3.2s ease-in-out infinite;
}
@keyframes hero-ascendant-glow {
  0%, 100% { box-shadow: 0 6px 18px rgba(0, 0, 0, .45), inset 0 1px 0 rgba(255, 255, 255, .06), 0 0 18px rgba(var(--deck-rgb), .5); }
  50% { box-shadow: 0 6px 22px rgba(0, 0, 0, .45), inset 0 1px 0 rgba(255, 255, 255, .1), 0 0 30px rgba(var(--deck-rgb), .85); }
}
@media (prefers-reduced-motion: reduce) {
  .hero-portrait.revealed.tier-ascendant { animation: none; box-shadow: 0 6px 18px rgba(0, 0, 0, .45), inset 0 1px 0 rgba(255, 255, 255, .06), 0 0 22px rgba(var(--deck-rgb), .65); }
}

.hero-portrait-clickable { cursor: zoom-in; }
.hero-portrait-clickable:hover,
.hero-portrait-clickable:focus-visible { border-color: rgb(var(--deck-rgb)); outline: none; }
.hero-portrait-clickable:focus-visible { box-shadow: 0 0 0 2px rgba(var(--deck-rgb), .5); }

.hero-lightbox-body { align-items: center; }
.hero-lightbox-art {
  width: min(420px, 100%);
  aspect-ratio: 1;
  object-fit: contain;
  border-radius: 18px;
  background: radial-gradient(70% 70% at 50% 30%, rgba(255, 255, 255, .05), transparent 70%);
  align-self: center;
}
.hero-lightbox-desc {
  margin: 0;
  text-align: center;
  color: var(--muted);
  font-style: italic;
}

.soul-meter { display: grid; gap: 5px; margin-top: 8px; }
.soul-meter-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  font-size: 11px;
  letter-spacing: .16em;
  text-transform: uppercase;
}
.soul-title { color: rgb(var(--deck-rgb)); font-weight: 800; }
.soul-rank { color: var(--muted); font-variant-numeric: tabular-nums; }

.soul-pips { display: flex; gap: 3px; }
.soul-pip {
  flex: 1 1 0;
  height: 4px;
  border-radius: 99px;
  background: rgba(255, 255, 255, .09);
}
.soul-pip.lit {
  background: rgb(var(--deck-rgb));
  box-shadow: 0 0 8px rgba(var(--deck-rgb), .65);
}

.vault-deck-next {
  margin: 6px 0 0;
  font-size: 12px;
  color: var(--muted);
  font-style: italic;
}
.hidden { display: none; }

/* The Hall's cards lead with the portrait, so the layout that suited a card
   back needs a wider first column. */
.hero-card .hero-portrait { width: 96px; }
button.deck-choice.hero-choice { gap: 7px; }

/* ==========================================================================
   Fantasy combat cohesion
   ==========================================================================
   The encounter used to sit on the global nebula and read like a dashboard.
   This treatment makes it a physical enchanted table: stone and brass frame
   the persistent controls, while the score and played cards occupy one central
   ritual surface. The rules and layout variants are unchanged.
   ========================================================================== */

.screen.combat {
  position: relative;
  background:
    linear-gradient(180deg, rgba(5,9,24,.34), rgba(5,7,19,.5)),
    url("./assets/images/hotu_screen_005_main-combat-playmat_v01_source.png") center / cover fixed no-repeat,
    #080d1c;
}

.combat .topbar,
.combat .scoreboard,
.combat .rail-block,
.combat .hand-panel {
  border-color: rgba(190,151,78,.34);
  box-shadow:
    0 14px 34px rgba(1,3,12,.48),
    inset 0 1px 0 rgba(255,240,190,.08),
    inset 0 0 0 1px rgba(4,8,22,.62);
}

.combat .topbar {
  border-radius: 6px 6px 18px 18px;
  background:
    linear-gradient(90deg, rgba(20,35,68,.94), rgba(31,25,61,.95) 52%, rgba(20,35,68,.94)),
    rgba(8,13,31,.94);
}

.combat .layout-pill {
  border-color: rgba(231,190,101,.4);
  background:
    linear-gradient(180deg, rgba(94,75,139,.5), rgba(32,31,68,.86));
}
.combat .layout-pill-key {
  color: var(--gold);
  border: 1px solid rgba(255,211,110,.22);
}

.combat .scoreboard {
  position: relative;
  overflow: visible;
  border-radius: 4px 4px 20px 20px;
  background:
    radial-gradient(60% 170% at 50% -30%, rgba(115,91,188,.3), transparent 66%),
    linear-gradient(180deg, rgba(17,27,60,.96), rgba(9,14,36,.94));
}
.combat .scoreboard::before,
.combat .hand-panel::before {
  content: "◆";
  position: absolute;
  z-index: 2;
  left: 50%;
  top: -8px;
  transform: translateX(-50%);
  width: 34px;
  height: 16px;
  display: grid;
  place-items: center;
  color: var(--gold);
  font-size: 9px;
  background: #111936;
  border: 1px solid rgba(255,211,110,.42);
  clip-path: polygon(18% 0, 82% 0, 100% 50%, 82% 100%, 18% 100%, 0 50%);
  text-shadow: 0 0 9px rgba(255,211,110,.7);
}

.combat .chips-box,
.combat .mult-box,
.combat .total-box {
  border-radius: 0;
  clip-path: polygon(11% 0, 89% 0, 100% 50%, 89% 100%, 11% 100%, 0 50%);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.12);
}
.combat .chips-box {
  background:
    radial-gradient(circle at 50% 15%, rgba(126,230,255,.22), transparent 54%),
    linear-gradient(180deg, rgba(32,76,131,.82), rgba(15,31,71,.94));
}
.combat .mult-box {
  background:
    radial-gradient(circle at 50% 15%, rgba(255,116,130,.22), transparent 54%),
    linear-gradient(180deg, rgba(126,46,67,.84), rgba(62,22,47,.95));
}
.combat .total-box {
  background:
    radial-gradient(circle at 50% 10%, rgba(255,226,142,.24), transparent 58%),
    linear-gradient(180deg, rgba(118,77,30,.78), rgba(55,36,23,.94));
}

/* The visible scoring story: Hand → Base → Cards → Affinity → Gems → Final. */
.resolution-ribbon {
  min-height: 31px;
  max-width: min(100%, 860px);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 5px;
  padding: 3px 10px;
}
.resolution-empty {
  color: rgba(228,218,194,.46);
  font-family: Georgia, "Times New Roman", serif;
  font-size: 11px;
  font-style: italic;
}
.resolution-arrow {
  color: rgba(255,211,110,.44);
  font-family: Georgia, serif;
  font-size: 18px;
  line-height: 1;
}
.resolution-step {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  min-height: 25px;
  padding: 4px 9px;
  border: 1px solid rgba(255,255,255,.12);
  border-radius: 4px 10px;
  background: rgba(5,9,24,.7);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.05);
}
.resolution-label {
  color: var(--ink-faint);
  font-size: 8px;
  font-weight: 900;
  letter-spacing: .15em;
  text-transform: uppercase;
}
.resolution-value {
  color: #eee8dc;
  font-family: var(--font-num);
  font-size: 10px;
  white-space: nowrap;
}
.resolution-step.hand { border-color: rgba(176,124,255,.34); }
.resolution-step.base { border-color: rgba(126,230,255,.28); }
.resolution-step.cards { border-color: rgba(255,255,255,.2); }
.resolution-step.gems { border-color: rgba(255,211,110,.44); }
.resolution-step.total {
  border-color: rgba(255,211,110,.78);
  background: linear-gradient(180deg, rgba(118,77,30,.72), rgba(47,29,19,.88));
  box-shadow: 0 0 16px rgba(255,211,110,.14);
}
.resolution-step.total .resolution-value { color: var(--gold); font-size: 12px; }
.resolution-step.affinity-strength { border-color: rgba(255,138,61,.58); }
.resolution-step.affinity-agility { border-color: rgba(70,214,111,.58); }
.resolution-step.affinity-elemental { border-color: rgba(255,95,162,.58); }
.resolution-step.affinity-arcane { border-color: rgba(176,124,255,.62); }

/* A permanent hand altar gives the played-card area a job even while empty. */
.combat .play-area {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  min-height: 104px;
  height: auto;
  border-style: solid;
  border-color: rgba(190,151,78,.3);
  border-radius: 18px 5px 18px 5px;
  background:
    radial-gradient(ellipse at 50% 48%, rgba(104,78,180,.24), transparent 52%),
    radial-gradient(ellipse at 50% 55%, rgba(45,170,180,.1), transparent 68%),
    linear-gradient(180deg, rgba(7,14,34,.78), rgba(4,8,22,.9));
  box-shadow:
    inset 0 0 46px rgba(3,5,17,.82),
    inset 0 0 0 1px rgba(255,228,160,.04),
    0 12px 30px rgba(1,3,12,.34);
}
.combat .tableau {
  flex: 0 0 auto;
  min-height: 0;
}
.combat .tableau-lower {
  flex: 0 0 auto;
  min-height: 104px;
}
.combat .play-area::before,
.combat .play-area::after {
  content: "";
  position: absolute;
  z-index: -1;
  pointer-events: none;
}
.combat .play-area::before {
  inset: 8px;
  border: 1px solid rgba(220,178,94,.16);
  border-radius: 13px 3px 13px 3px;
}
.combat .play-area::after {
  left: 12%;
  right: 12%;
  top: 50%;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(126,230,255,.25), rgba(255,211,110,.28), transparent);
}
.altar-backdrop {
  position: absolute;
  z-index: -1;
  inset: 0;
  display: grid;
  place-items: center;
  pointer-events: none;
}
.altar-ring {
  position: absolute;
  border-radius: 50%;
  border: 1px solid rgba(126,230,255,.19);
  box-shadow: 0 0 28px rgba(126,230,255,.05);
}
.altar-ring.outer {
  width: min(260px, 38%);
  aspect-ratio: 1;
  border-style: dashed;
  animation: altarTurn 30s linear infinite;
}
.altar-ring.inner {
  width: min(172px, 25%);
  aspect-ratio: 1;
  border-color: rgba(255,211,110,.2);
  animation: altarTurn 22s linear infinite reverse;
}
.altar-rune {
  color: rgba(255,211,110,.16);
  font-family: Georgia, serif;
  font-size: 34px;
  text-shadow: 0 0 24px rgba(255,211,110,.18);
}
.altar-prompt {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  color: rgba(221,213,198,.46);
  white-space: nowrap;
}
.altar-prompt strong {
  font-family: Georgia, "Times New Roman", serif;
  font-size: 11px;
  letter-spacing: .26em;
}
.altar-prompt small {
  font-size: 9px;
  letter-spacing: .08em;
}
@keyframes altarTurn { to { transform: rotate(360deg); } }
.play-area .card { z-index: 2; }

.combat .rail-block {
  background:
    linear-gradient(180deg, rgba(14,24,52,.88), rgba(6,11,29,.9));
}
.combat .hand-panel {
  position: relative;
  border-radius: 18px 5px 18px 5px;
  background:
    radial-gradient(70% 110% at 50% 110%, rgba(105,63,154,.25), transparent 68%),
    linear-gradient(180deg, rgba(22,27,67,.95), rgba(9,13,36,.96));
}
.combat .action {
  border-radius: 4px 12px;
  clip-path: polygon(7% 0, 93% 0, 100% 22%, 100% 78%, 93% 100%, 7% 100%, 0 78%, 0 22%);
}
.combat .action.strike {
  background:
    linear-gradient(180deg, #ffd884, #e49735 58%, #9b571e);
  color: #261504;
  border-color: #ffdc8c;
  text-shadow: 0 1px rgba(255,255,255,.32);
}

/* The parchment face asset is already part of the game. Using it here gives
   every card the same tactile material without sacrificing the bright pips. */
.card-face {
  background:
    linear-gradient(145deg, rgba(var(--card-rgb),.075), transparent 34%),
    radial-gradient(90% 70% at 100% 100%, rgba(var(--card-rgb),.055), transparent 68%),
    url("./assets/images/hotu_material_005_neutral-card-face_v01_512x768.webp") center / cover no-repeat;
}
/* The delivered frame art, full bleed - it carries its own parchment centre,
   so it replaces the neutral material above outright rather than layering on
   it. Specificity (two classes) wins over the plain .card-face rules above
   regardless of source order. */
.suit-C .card-face { background: url("./assets/suits/frame-strength.webp") center / 100% 100% no-repeat; }
.suit-S .card-face { background: url("./assets/suits/frame-agility.webp") center / 100% 100% no-repeat; }
.suit-H .card-face { background: url("./assets/suits/frame-elemental.webp") center / 100% 100% no-repeat; }
.suit-D .card-face { background: url("./assets/suits/frame-arcane.webp") center / 100% 100% no-repeat; }
.card {
  border-color: rgba(69,44,20,.58);
  box-shadow:
    0 2px 0 rgba(56,39,24,.46),
    0 10px 22px rgba(2,3,12,.62),
    0 24px 44px rgba(2,3,12,.4),
    0 0 18px rgba(var(--card-rgb),.11);
}
.card-art.court {
  inset: 16% 10%;
  border-radius: 45% 45% 16% 16%;
  background:
    radial-gradient(circle at 50% 40%, rgba(var(--card-rgb),.16), transparent 58%),
    linear-gradient(180deg, rgba(255,255,255,.22), transparent 65%);
  box-shadow:
    inset 0 0 0 1px rgba(var(--card-rgb),.2),
    0 2px 8px rgba(0,0,0,.08);
}
.card-art.court svg {
  overflow: visible;
  filter: drop-shadow(0 2px 1px rgba(255,255,255,.38)) drop-shadow(0 3px 3px rgba(0,0,0,.2));
}
.court-aura { opacity: .58; }
.court-emblem {
  top: 79%;
  width: clamp(23px, 2.4vw, 31px);
  color: #fff8e5;
  background:
    radial-gradient(circle at 35% 25%, rgba(255,255,255,.3), transparent 36%),
    rgb(var(--card-rgb));
  border: 2px solid rgba(93,62,24,.72);
  box-shadow:
    0 2px 7px rgba(0,0,0,.34),
    inset 0 0 0 1px rgba(255,255,255,.45);
  filter: saturate(.84);
}
.card.small .court-emblem { width: 16px; }

/* Build-aware route notes connect the strategic fork to the current run. */
.fork-build-context {
  grid-area: context;
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 12px 7% 2px;
  padding: 8px 12px;
  color: var(--ink);
  background:
    linear-gradient(90deg, color-mix(in srgb, var(--route) 14%, rgba(6,9,25,.82)), rgba(6,9,25,.72));
  border: 1px solid color-mix(in srgb, var(--route) 42%, transparent);
  border-radius: 4px 12px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.04);
}
.fork-lane {
  min-height: 610px;
  grid-template-rows: 154px 50px 104px 1fr auto;
  grid-template-areas: "head" "context" "path" "stocks" "take";
}
.fork-build-glyph {
  width: 27px;
  height: 27px;
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  color: var(--route);
  border: 1px solid color-mix(in srgb, var(--route) 55%, transparent);
  border-radius: 50%;
  background: rgba(0,0,0,.28);
  text-shadow: 0 0 10px var(--route);
}
.fork-build-copy {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.fork-build-label {
  color: color-mix(in srgb, var(--route) 76%, white);
  font-size: 8px;
  font-weight: 900;
  letter-spacing: .16em;
  text-transform: uppercase;
}
.fork-build-value {
  overflow: hidden;
  color: #e9e6ee;
  font-size: 10px;
  font-weight: 650;
  line-height: 1.25;
  text-overflow: ellipsis;
  white-space: nowrap;
}

@container app (max-width: 900px) {
  .resolution-ribbon { display: none; }
  .combat .play-area { min-height: 92px; }
  .altar-prompt small { display: none; }
}

@container app (max-width: 560px) {
  .fork-build-context { margin-inline: 3%; }
  .fork-build-value { white-space: normal; }
  .altar-ring.outer { width: 46%; }
  .altar-ring.inner { width: 30%; }
}

@media (prefers-reduced-motion: reduce) {
  .altar-ring { animation: none !important; }
}

/* The shop now inhabits the same world as the combat table instead of falling
   back to the global nebula. Panels remain opaque enough for long effect text,
   while the shelves and warm lanterns supply place and atmosphere. */
.screen.shop {
  position: relative;
  background:
    linear-gradient(180deg, rgba(6,8,20,.42), rgba(6,5,16,.66)),
    url("./assets/images/hotu_screen_010_waystation-shop_v02_source.png") center / cover fixed no-repeat,
    #100b18;
}
.shop .shop-head {
  padding: 12px 18px 14px;
  border: 1px solid rgba(215,165,83,.36);
  border-radius: 4px 4px 18px 18px;
  background: linear-gradient(180deg, rgba(22,16,37,.92), rgba(12,10,27,.88));
  box-shadow: 0 14px 34px rgba(0,0,0,.42), inset 0 1px 0 rgba(255,240,190,.08);
}
.shop .shop-panel {
  border-color: color-mix(in srgb, var(--route, #d5a653) 34%, transparent);
  border-radius: 5px 18px;
  background:
    radial-gradient(100% 90% at 50% 0%, color-mix(in srgb, var(--route, #d5a653) 8%, transparent), transparent 64%),
    rgba(8,8,22,.86);
  box-shadow:
    0 14px 34px rgba(0,0,0,.38),
    inset 0 1px 0 rgba(255,240,190,.06);
  backdrop-filter: blur(7px);
}
.shop .section-title {
  color: color-mix(in srgb, var(--route, #d5a653) 70%, white);
  font-family: Georgia, "Times New Roman", serif;
  font-size: 12px;
  letter-spacing: .2em;
}
.shop .shop-item,
.shop .pack-card,
.shop .voucher-card {
  border-radius: 4px 16px;
  background:
    radial-gradient(120% 90% at 50% -10%, rgba(var(--tint), .2), transparent 65%),
    linear-gradient(180deg, rgba(31,23,45,.94), rgba(12,10,25,.96));
  box-shadow:
    0 12px 28px rgba(0,0,0,.44),
    inset 0 1px 0 rgba(255,240,190,.06);
}
.shop .shop-item::after,
.shop .pack-card::after,
.shop .voucher-card::after {
  content: "◆";
  position: absolute;
  left: 50%;
  top: -1px;
  transform: translate(-50%, -50%);
  color: rgb(var(--tint));
  font-size: 10px;
  text-shadow: 0 0 9px rgba(var(--tint),.7);
}
.shop .item-kind,
.shop .rail-title {
  font-size: 9px;
  letter-spacing: .15em;
}

/* ==========================================================================
   Menus — pause, settings, statistics, credits
   ==========================================================================
   These screens are read rather than played, so they drop the game's density
   and lean on the same panel chrome everywhere. The one rule they add: any
   control that destroys something is red and never adjacent to a control that
   starts something.
   ========================================================================== */

/* Title screen secondary menu -------------------------------------------- */

.title-menu {
  display: flex;
  gap: 22px;
  justify-content: center;
  flex-wrap: wrap;
  margin-top: 18px;
}

button.link {
  background: none;
  box-shadow: none;
  border: 0;
  padding: 4px 2px;
  font-size: 12px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-faint);
  border-bottom: 1px solid transparent;
  border-radius: 0;
}

button.link:hover:not(:disabled) {
  color: var(--gold);
  border-bottom-color: rgba(255, 211, 110, .45);
  translate: none; scale: none;
  box-shadow: none;
  filter: none;
}

/* Tabs -------------------------------------------------------------------- */

.tab-strip {
  display: flex;
  gap: 4px;
  flex-wrap: wrap;
  margin: 0 0 18px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--edge);
}

button.tab {
  background: none;
  box-shadow: none;
  padding: 7px 14px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-faint);
  border-radius: var(--r-sm);
}

button.tab:hover:not(:disabled) {
  color: var(--ink);
  background: rgba(255, 255, 255, .05);
  translate: none; scale: none;
  box-shadow: none;
  filter: none;
}

button.tab.active {
  color: #241a05;
  background: linear-gradient(180deg, var(--gold), var(--gold-deep));
}

.tab-section {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

/* Setting rows ------------------------------------------------------------ */

.setting-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 20px;
  padding: 13px 0;
  border-bottom: 1px solid rgba(170, 190, 255, .07);
}

.setting-row:last-child { border-bottom: 0; }

.setting-copy { flex: 1; min-width: 0; }

.setting-name {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 3px;
}

.setting-hint {
  font-size: 12px;
  line-height: 1.5;
  color: var(--ink-dim);
}

.setting-control { flex: 0 0 auto; padding-top: 2px; }

/* Switch ------------------------------------------------------------------ */

button.switch {
  width: 46px;
  height: 26px;
  padding: 0;
  border-radius: 99px;
  background: rgba(255, 255, 255, .09);
  box-shadow: inset 0 1px 3px rgba(0, 0, 0, .5);
  position: relative;
  transition: background .18s ease;
}

button.switch:hover:not(:disabled) { translate: none; scale: none; filter: brightness(1.2); }

button.switch.on { background: linear-gradient(180deg, var(--gold), var(--gold-deep)); }

.switch-knob {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--ink);
  box-shadow: 0 1px 4px rgba(0, 0, 0, .55);
  transition: transform .18s cubic-bezier(.3, .8, .4, 1), translate .18s cubic-bezier(.3, .8, .4, 1), scale .18s cubic-bezier(.3, .8, .4, 1);
}

button.switch.on .switch-knob { transform: translateX(20px); background: #2b1d04; }

/* Slider ------------------------------------------------------------------ */

.slider { display: flex; align-items: center; gap: 12px; }

.slider-input {
  width: 150px;
  accent-color: var(--gold);
  cursor: pointer;
}

.slider-value {
  font-variant-numeric: tabular-nums;
  font-size: 12px;
  font-weight: 700;
  color: var(--gold);
  min-width: 40px;
  text-align: right;
}

/* Destructive ------------------------------------------------------------- */

.danger {
  background: linear-gradient(180deg, #ff5f7c, #c22343);
  color: #fff;
}

/* Confirm dialog ---------------------------------------------------------- */

.confirm-overlay { z-index: 90; }

.overlay-card.confirm-card {
  max-width: 440px;
  text-align: left;
}

.overlay-card.confirm-card.wide { max-width: 560px; }

.confirm-body {
  font-size: 13px;
  line-height: 1.6;
  color: var(--ink-dim);
  margin: 0 0 20px;
}

.confirm-actions {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
  flex-wrap: wrap;
}

.import-box {
  width: 100%;
  margin-bottom: 16px;
  padding: 10px 12px;
  border-radius: var(--r-sm);
  border: 1px solid var(--edge);
  background: rgba(0, 0, 0, .32);
  color: var(--ink);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px;
  line-height: 1.5;
  resize: vertical;
}

/* Pause menu -------------------------------------------------------------- */

.menu-list { display: flex; flex-direction: column; gap: 8px; }

button.menu-item {
  display: block;
  width: 100%;
  text-align: left;
  padding: 14px 18px;
  border-radius: var(--r-md);
  background: rgba(255, 255, 255, .05);
}

/* Both need the element+class specificity of `button.menu-item` above to win. */
button.menu-item.primary { background: linear-gradient(180deg, var(--gold), var(--gold-deep)); }
button.menu-item.danger { background: linear-gradient(180deg, #ff5f7c, #c22343); }

.menu-item-copy { display: flex; flex-direction: column; gap: 3px; }

.menu-item-copy strong {
  font-size: 15px;
  letter-spacing: .04em;
}

.menu-item-copy small {
  font-size: 11.5px;
  font-weight: 400;
  color: var(--ink-dim);
}

button.menu-item.primary .menu-item-copy small { color: rgba(36, 26, 5, .72); }
button.menu-item.danger .menu-item-copy small { color: rgba(255, 255, 255, .75); }

/* Theme picker (settings) ------------------------------------------------- */

.theme-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 8px;
  width: 100%;
}

button.theme-pick {
  text-align: left;
  padding: 11px 13px;
  border-radius: var(--r-sm);
  background: rgba(255, 255, 255, .05);
  border: 1px solid transparent;
}

button.theme-pick.active {
  border-color: var(--gold);
  background: rgba(255, 211, 110, .12);
}

.theme-pick-copy { display: flex; flex-direction: column; gap: 3px; }
.theme-pick-copy strong { font-size: 13px; }
.theme-pick-copy small { font-size: 10.5px; font-weight: 400; color: var(--ink-dim); line-height: 1.45; }

/* Statistics -------------------------------------------------------------- */

.stat-group-title {
  font-size: 10px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-top: 6px;
}

.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
  gap: 8px;
}

.stat-card {
  padding: 14px 12px;
  border-radius: var(--r-md);
  background: rgba(255, 255, 255, .04);
  border: 1px solid var(--edge);
  text-align: center;
}

.stat-card.good { border-color: rgba(139, 255, 176, .3); }

.stat-value {
  font-size: 22px;
  font-weight: 800;
  color: var(--gold);
  font-variant-numeric: tabular-nums;
  line-height: 1.15;
  word-break: break-word;
}

.stat-card.good .stat-value { color: var(--good); }

.stat-label {
  margin-top: 5px;
  font-size: 10px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* Tables. Wide content scrolls inside the panel rather than the page.
   The scrollbar is styled rather than hidden: this platform reserves and paints
   a gutter for `overflow-x: auto` even when the content fits, and the default
   is a bright white bar across the bottom of the table. */

.stat-table {
  display: block;
  overflow-x: auto;
  border-radius: var(--r-md);
  border: 1px solid var(--edge);
  scrollbar-width: thin;
  scrollbar-color: rgba(170, 190, 255, .28) transparent;
}

.stat-table::-webkit-scrollbar { height: 8px; }
.stat-table::-webkit-scrollbar-track { background: transparent; }

.stat-table::-webkit-scrollbar-thumb {
  background: rgba(170, 190, 255, .28);
  border-radius: 99px;
}

.stat-table::-webkit-scrollbar-thumb:hover { background: rgba(170, 190, 255, .45); }

.stat-row {
  display: grid;
  align-items: center;
  gap: 10px;
  padding: 9px 13px;
  font-size: 12.5px;
  min-width: max-content;
  border-bottom: 1px solid rgba(170, 190, 255, .06);
}

.stat-row:last-child { border-bottom: 0; }

.hero-table .stat-row { grid-template-columns: minmax(110px, 1.4fr) minmax(140px, 1.5fr) 54px 54px 78px 92px; }
.history-table .stat-row { grid-template-columns: 84px minmax(100px, 1fr) 92px 56px 92px 92px 84px; }

.stat-row.head {
  font-size: 9.5px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-faint);
  background: rgba(0, 0, 0, .25);
  position: sticky;
  top: 0;
}

.stat-row.lost { color: var(--ink-faint); font-style: italic; }
.stat-row.restored { background: rgba(255, 211, 110, .07); }

.stat-hero { font-weight: 600; color: var(--ink); }
.stat-soul { color: var(--ink-dim); font-size: 11.5px; }

.stat-outcome { font-weight: 700; font-size: 11px; letter-spacing: .06em; }
.outcome-win .stat-outcome { color: var(--good); }
.outcome-loss .stat-outcome { color: var(--danger); }
.outcome-overflow .stat-outcome { color: var(--ice); }

.stat-seed {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px;
  color: var(--ink-dim);
}

.stat-when { color: var(--ink-faint); font-size: 11px; }

/* Credits ----------------------------------------------------------------- */

.credit-scroll { display: flex; flex-direction: column; gap: 20px; margin-bottom: 18px; }

.credit-title {
  font-size: 10px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: 6px;
}

.credit-line { font-size: 13px; line-height: 1.6; color: var(--ink-dim); }

/* Narrow screens ---------------------------------------------------------- */

@container app (max-width: 620px) {
  .setting-row { flex-direction: column; align-items: stretch; gap: 10px; }
  .setting-control { align-self: flex-start; }
  .slider-input { width: 100%; min-width: 180px; }
  .title-menu { gap: 14px; }
}

/* The menus are wider than the reference readers: settings rows are two
   columns and the run history is seven. */
.overlay-card.menu-wide { max-width: 900px; }

/* Panels scroll their own body. Same reasoning as `.stat-table`: the default
   gutter paints as a solid white bar against these dark cards. */
.overlay-card {
  scrollbar-width: thin;
  scrollbar-color: rgba(170, 190, 255, .28) transparent;
}

.overlay-card::-webkit-scrollbar { width: 9px; }
.overlay-card::-webkit-scrollbar-track { background: transparent; }

.overlay-card::-webkit-scrollbar-thumb {
  background: rgba(170, 190, 255, .28);
  border-radius: 99px;
}

.overlay-card::-webkit-scrollbar-thumb:hover { background: rgba(170, 190, 255, .45); }

/* =========================================================================
   Versions 2 and 3: the floor map (expedition-ui.ts)
   ========================================================================= */
/* Landscape, one screen: header, board (every spare pixel), footer. Nothing
   scrolls and nothing changes size after the screen appears, so the map can
   never shift while its art loads. */
.screen.expedition {
  display: grid; grid-template-rows: auto minmax(0, 1fr) auto; gap: 10px;
  overflow: hidden; padding: 12px clamp(14px, 2.4vw, 36px) 10px clamp(44px, 3.4vw, 52px);
}
.exp-head {
  display: grid; grid-template-columns: minmax(0, 1fr) auto auto; align-items: center; gap: 18px;
  padding: 8px 14px; margin-right: clamp(0px, 22cqw, 300px); /* clear the chrome buttons, top right */
  border-radius: var(--r-lg); background: rgba(6,10,26,.42); border: 1px solid var(--edge);
}
.exp-ident { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.exp-ident .floor-name { align-self: flex-start; font-size: 10px; padding: 3px 10px; }
.exp-title-row { display: flex; align-items: baseline; gap: 14px; min-width: 0; }
.exp-title { margin: 0; font-size: clamp(20px, 2.2vw, 30px); font-weight: 900; letter-spacing: .04em; white-space: nowrap; }
.exp-layout { display: flex; flex-direction: column; min-width: 0; font-size: 12px; color: var(--ink-dim); line-height: 1.3; }
.exp-layout strong { color: var(--ink); font-size: 13px; }
.exp-layout span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.exp-head .floor-map { margin: 0; transform: none; }
.exp-head .map-floor { width: 30px; height: 30px; }
.exp-head .map-floor-num { font-size: 13px; }
.exp-head .map-link { width: 12px; }
.exp-head .blind-wallet { padding: 6px 12px; }
.exp-head .purse { font-size: 22px; }

.expedition-board { position: relative; min-height: 0; }
.expedition-canvas {
  position: absolute; inset: 0; border-radius: var(--r-lg); overflow: hidden;
  container-type: size; container-name: board;
  /* One unit of map scale: a hundredth of the board's width, held back on
     short boards so cards never outgrow the rows they sit in. */
  --u: min(1.05cqw, 2.05cqh);
  border: 1px solid var(--edge-bright);
  background:
    radial-gradient(60% 70% at 18% 30%, hsl(calc(var(--biome-hue) + 0deg) 70% 45% / .14), transparent 70%),
    radial-gradient(50% 60% at 82% 72%, hsl(calc(var(--biome-hue) + 60deg) 70% 50% / .12), transparent 70%),
    repeating-linear-gradient(0deg, rgba(255,255,255,.025) 0 1px, transparent 1px 46px),
    repeating-linear-gradient(90deg, rgba(255,255,255,.025) 0 1px, transparent 1px 46px),
    linear-gradient(160deg, #10132d, #0a0c1d 70%);
  box-shadow: inset 0 0 80px rgba(0,0,0,.55), var(--shadow-2);
}
.expedition-canvas::before {
  content: attr(data-watermark); position: absolute; left: 50%; top: 50%; translate: -50% -50%;
  font: 900 calc(var(--u) * 6.5)/1 var(--font-display, serif); letter-spacing: .14em; color: rgba(255,255,255,.035);
  white-space: nowrap; pointer-events: none;
}
.expedition-roads { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; overflow: visible; }
.expedition-roads path { fill: none; stroke: rgba(205, 216, 255, .22); stroke-width: 3; stroke-linecap: round; stroke-dasharray: 2 9; vector-effect: non-scaling-stroke; }
.expedition-roads path.walked { stroke: var(--gold); stroke-dasharray: none; stroke-width: 3.5; opacity: .85; }
.expedition-roads path.open { stroke: #9ff3ff; stroke-dasharray: 10 8; stroke-width: 3.5; animation: road-march 1.1s linear infinite; filter: drop-shadow(0 0 4px rgba(126,230,255,.7)); }
.expedition-roads path.gone { opacity: .07; }
.expedition-roads path.fog { opacity: .35; stroke-dasharray: 1 10; }
.expedition-roads path.hidden { display: none; }
@keyframes road-march { to { stroke-dashoffset: -36; } }

/* Cards are centred with the `translate` property, not `transform`, so an
   entrance or hover animation (which writes `transform`) can never knock them
   off their spot. Every size is in board units, so the map is the same
   picture at any window size and cards never collide. */
.map-node {
  position: absolute; left: calc(7% + var(--x) * .86%); top: calc(12% + var(--y) * .76%); translate: -50% -50%;
  width: calc(var(--u) * 10.4); padding: calc(var(--u) * .5) calc(var(--u) * .5) calc(var(--u) * .6);
  display: flex; flex-direction: column; align-items: center; gap: calc(var(--u) * .1);
  border-radius: calc(var(--u) * 1.2); border: 1px solid var(--edge-bright); background: rgba(16, 19, 44, .94); color: var(--ink);
  cursor: pointer; text-align: center; font: inherit; box-shadow: var(--shadow-1);
  transition: scale .18s cubic-bezier(.3,1.3,.4,1), box-shadow .18s, border-color .18s, opacity .25s, filter .25s;
  --tone: #aab6ff;
}
.map-node:hover { scale: 1.06; z-index: 3; }
.map-node .map-node-plate { width: calc(var(--u) * 5.6); height: calc(var(--u) * 4.6); display: grid; place-items: center; }
.map-node .map-node-art { max-width: 100%; max-height: 100%; object-fit: contain; filter: drop-shadow(0 4px 8px rgba(0,0,0,.6)); }
.map-node .map-node-kind { font-size: max(8px, calc(var(--u) * .8)); font-weight: 800; letter-spacing: .14em; text-transform: uppercase; color: var(--tone); }
.map-node .map-node-name { font-size: max(10px, calc(var(--u) * 1.1)); line-height: 1.15; }
.map-node .map-node-sub { font-size: max(9px, calc(var(--u) * .95)); color: var(--ink-dim); }
.map-node .map-node-stamp { position: absolute; top: 6px; right: 6px; font-size: 8.5px; font-weight: 900; letter-spacing: .12em; color: var(--good); }
.map-node.kind-patrol { --tone: #ffb36b; } .map-node.kind-elite { --tone: #ff8a5c; } .map-node.kind-warden { --tone: #ff5d73; }
.map-node.kind-challenge { --tone: #c79bff; } .map-node.kind-cache, .map-node.kind-vault { --tone: var(--gold); }
.map-node.kind-shrine { --tone: var(--ice); } .map-node.kind-trail { --tone: var(--good); } .map-node.kind-camp { --tone: var(--teal); }
.map-node.kind-start, .map-node.kind-rest { --tone: #c9d2ff; }
.map-node.kind-warden { width: calc(var(--u) * 11.4); border-color: rgba(255, 93, 115, .45); }
.map-node.st-available { border-color: var(--tone); box-shadow: 0 0 0 1px var(--tone), 0 0 22px color-mix(in srgb, var(--tone) 45%, transparent), var(--shadow-1); animation: node-ready 2.2s ease-in-out infinite; }
@keyframes node-ready { 50% { box-shadow: 0 0 0 1px var(--tone), 0 0 34px color-mix(in srgb, var(--tone) 65%, transparent), var(--shadow-1); } }
.map-node.st-current { border-color: var(--gold); box-shadow: 0 0 0 2px var(--gold), 0 0 26px rgba(255,211,110,.45); }
.map-node.st-visited { opacity: .72; }
.map-node.st-blocked { opacity: .6; }
.map-node.st-ahead { opacity: .88; }
.map-node.st-near-fog { opacity: .5; filter: blur(1.2px) grayscale(.8); }
.map-node.st-near-fog .map-node-art { filter: brightness(.25); }
.map-node.st-deep-fog { width: calc(var(--u) * 5.6); height: calc(var(--u) * 5.6); padding: 0; justify-content: center; border-style: dashed; background: rgba(10,12,28,.6); opacity: .45; cursor: default; }
.map-node.st-deep-fog .map-node-fog { font-size: calc(var(--u) * 2); color: var(--ink-faint); }
.map-node.st-bypassed { opacity: .14; filter: grayscale(1); }
.map-node.secret { border-style: dashed; }
.map-node.selected { outline: 2px solid #fff; outline-offset: 3px; z-index: 4; }
/* A short board (a phone held sideways) keeps the art and the name. */
@container board (max-height: 330px) {
  .map-node .map-node-kind, .map-node .map-node-sub { display: none; }
}
.expedition-party {
  position: absolute; left: calc(7% + var(--x) * .86%); top: calc(12% + var(--y) * .76%);
  width: 26px; height: 26px; translate: -50% calc(var(--u) * -6.2 - 50%);
  display: grid; place-items: center; border-radius: 50%; background: radial-gradient(circle, #fff6d8, var(--gold) 55%, var(--gold-deep));
  color: #3a2600; font-size: 13px; box-shadow: 0 0 0 3px rgba(255,211,110,.25), 0 0 18px rgba(255,211,110,.8); z-index: 5;
  transition: left .4s cubic-bezier(.45,.05,.3,1), top .4s cubic-bezier(.45,.05,.3,1); pointer-events: auto;
  animation: party-bob 1.8s ease-in-out infinite;
}
@keyframes party-bob { 50% { transform: translateY(-4px); } }
.expedition-wound {
  position: absolute; left: 12px; bottom: 12px; z-index: 6; max-width: 46%; padding: 7px 12px; border-radius: var(--r-md);
  background: rgba(40, 8, 18, .88); border: 1px solid rgba(255, 77, 109, .5); color: #ffc2cc; font-size: 12.5px;
}

/* The popup: a card over the board, on the side away from the room it is
   about, so that room stays visible next to it. */
.map-pop {
  position: absolute; top: 10px; bottom: 10px; right: 10px; width: min(380px, 42%); z-index: 8;
  display: none; pointer-events: none;
}
.map-pop.on-left { right: auto; left: 10px; }
.map-pop.open { display: flex; flex-direction: column; justify-content: center; pointer-events: auto; animation: pop-in .2s cubic-bezier(.2,1,.35,1); }
@keyframes pop-in { from { opacity: 0; scale: .97; } }
.map-pop .expedition-inspector { position: relative; max-height: 100%; }
.map-pop-close {
  position: absolute; top: 8px; right: 8px; z-index: 2; width: 30px; height: 30px; border-radius: 50%;
  border: 1px solid var(--edge-bright); background: rgba(6,10,26,.8); color: var(--ink-dim); cursor: pointer; font-size: 13px;
}
.map-pop-close:hover { color: var(--ink); border-color: var(--gold); }
.expedition-inspector {
  border-radius: var(--r-lg); border: 1px solid var(--edge-bright); background: rgba(14, 17, 40, .97); padding: 16px; display: flex; flex-direction: column; gap: 10px;
  overflow: auto; box-shadow: 0 18px 50px rgba(0,0,0,.6);
}
.insp-kicker { font-size: 10px; font-weight: 800; letter-spacing: .18em; color: var(--gold); padding-right: 30px; }
.insp-title { margin: 0; font-size: 21px; }
.insp-text { margin: 0; color: var(--ink-dim); font-size: 13px; line-height: 1.45; }
.insp-terms { padding: 8px 10px; border-radius: 10px; background: rgba(255, 138, 92, .12); border: 1px solid rgba(255, 138, 92, .35); font-size: 13px; }
.insp-numbers { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; }
.insp-numbers > div { display: flex; flex-direction: column; padding: 8px; border-radius: 10px; background: rgba(4,8,22,.5); border: 1px solid var(--edge); }
.insp-numbers span { font-size: 9px; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-faint); font-weight: 800; }
.insp-numbers strong { font-size: 16px; font-family: var(--font-num, inherit); }
.insp-rule, .insp-note, .insp-blocked { padding: 8px 10px; border-radius: 10px; background: rgba(4,8,22,.5); border: 1px solid var(--edge); font-size: 12.5px; color: var(--ink-dim); }
.insp-blocked { color: #ffc2cc; }
.insp-tag { display: flex; flex-direction: column; gap: 3px; padding: 8px 10px; border-radius: 10px; background: rgba(139,255,176,.08); border: 1px solid rgba(139,255,176,.3); font-size: 12.5px; }
.insp-tag small { color: var(--ink-faint); }
.insp-rewards-head { font-size: 10px; font-weight: 800; letter-spacing: .16em; text-transform: uppercase; color: var(--ink-faint); margin-top: 2px; }
.insp-list { margin: 0; padding-left: 18px; font-size: 13px; color: var(--ink); }
.insp-choices { display: flex; flex-direction: column; gap: 6px; }
.insp-choice { text-align: left; padding: 10px 12px; border-radius: 12px; border: 1px solid rgba(255,211,110,.35); background: rgba(255,211,110,.07); color: var(--ink); cursor: pointer; }
.insp-choice:hover { border-color: var(--gold); background: rgba(255,211,110,.14); }
.insp-choice span { display: flex; flex-direction: column; gap: 2px; }
.insp-choice small { color: var(--ink-dim); font-size: 11.5px; }
.insp-go { margin-top: 4px; }
.expedition-inspector .blind-dossier { margin: 0; }
.insp-route { display: flex; flex-direction: column; gap: 10px; }
.insp-stations { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.insp-station {
  padding: 12px 10px; border-radius: 14px; cursor: pointer; color: var(--ink); font: inherit; text-align: center;
  border: 1px solid color-mix(in srgb, var(--route) 55%, transparent); background: color-mix(in srgb, var(--route) 10%, rgba(6,10,26,.6));
  transition: border-color .15s, background .15s, translate .15s;
}
.insp-station:hover { border-color: var(--route); background: color-mix(in srgb, var(--route) 20%, rgba(6,10,26,.6)); translate: 0 -2px; }
.insp-station-inner { display: flex; flex-direction: column; align-items: center; gap: 3px; }
.insp-station-inner strong { font-size: 15px; }
.insp-station-inner small { color: var(--ink-dim); font-size: 11.5px; }
.insp-station-pitch { font-size: 11.5px; color: var(--ink-dim); line-height: 1.35; margin-top: 2px; }
.insp-station-more { margin-top: 6px; font-size: 11px; font-weight: 800; letter-spacing: .04em; color: var(--route); }
.insp-station-art { width: 72px; height: 72px; object-fit: contain; flex: none; }

/* One specialist, full size. */
.station-overlay .station-card {
  position: relative; display: grid; grid-template-columns: minmax(180px, 34%) 1fr; gap: 22px; align-items: center;
  width: min(820px, 92vw); max-height: 90vh; padding: 22px 24px; overflow: auto;
  border: 1px solid color-mix(in srgb, var(--route) 60%, transparent);
  background: radial-gradient(80% 90% at 15% 40%, color-mix(in srgb, var(--route) 20%, transparent), transparent 70%), rgba(12, 15, 36, .98);
}
.station-portrait { display: grid; place-items: center; }
.station-portrait-art { width: 100%; max-height: 62vh; object-fit: contain; filter: drop-shadow(0 14px 26px rgba(0,0,0,.6)); }
.station-portrait .glyph-badge { font-size: 96px; }
.station-body { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.station-name { margin: 0; font-size: 30px; color: var(--route); }
.station-keeper { color: var(--ink-dim); font-weight: 700; margin-top: -4px; }
.station-quote { margin: 2px 0; font-style: italic; color: var(--ink); }
.station-pitch { margin: 0; color: var(--ink-dim); font-size: 13.5px; line-height: 1.45; }
.station-stocks { margin: 0; padding-left: 18px; font-size: 13px; line-height: 1.5; }
.station-service { display: flex; flex-direction: column; gap: 2px; padding: 8px 10px; border-radius: 10px; background: rgba(4,8,22,.5); border: 1px solid var(--edge); font-size: 12.5px; color: var(--ink-dim); }
.station-service strong { color: var(--ink); }
.station-actions { display: flex; gap: 10px; justify-content: flex-end; margin-top: 6px; flex-wrap: wrap; }
.station-take { min-width: 200px; }

.exp-foot { display: flex; align-items: center; gap: 16px; min-width: 0; }
.expedition-legend { display: flex; flex-direction: column; gap: 3px; font-size: 11px; color: var(--ink-dim); flex: none; }
.expedition-legend .lg { display: inline-block; width: 18px; height: 3px; border-radius: 2px; margin-right: 6px; vertical-align: middle; background: rgba(205,216,255,.3); }
.expedition-legend .lg-open { background: #9ff3ff; } .expedition-legend .lg-ahead { background: var(--gold); }
.expedition-legend .lg-fog { background: rgba(205,216,255,.12); } .expedition-legend .lg-gone { background: rgba(205,216,255,.05); }
.expedition-legend-note { color: var(--ink-faint); }
.exp-foot .tag-rail { flex: none; }
/* What you carry, as one compact row. */
.exp-foot .inventory { flex: 1; min-width: 0; flex-wrap: nowrap; justify-content: flex-end; gap: 10px; }
.exp-foot .inv-block { padding: 6px 10px; min-width: 0; }
.exp-foot .inv-rail { flex-wrap: nowrap; gap: 6px; overflow-x: auto; }
.exp-foot .rail-title { font-size: 9px; margin-bottom: 4px; }
.exp-foot .inv-gem, .exp-foot .inv-consumable { width: 66px; padding: 5px 4px 6px; gap: 2px; flex: none; }
.exp-foot .inv-gem .gem-art { width: 28px; height: 28px; }
.exp-foot .inv-consumable-art { width: 28px; }
.exp-foot .inv-gem-name, .exp-foot .inv-consumable-name { font-size: 9px; line-height: 1.15; }
.exp-foot .inv-gem-text, .exp-foot .inv-consumable-text { display: none; }
.exp-foot .inv-gem-sell, .exp-foot .inv-sell { font-size: 8px; padding: 1px 5px; }
.exp-foot .inv-socket-empty { width: 66px; min-height: 0; height: 62px; font-size: 14px; flex: none; }
@container app (max-height: 520px) {
  .screen.expedition { gap: 6px; padding-top: 6px; padding-bottom: 6px; }
  .exp-head { padding: 4px 10px; }
  .exp-layout span, .exp-ident .floor-name, .blind-wallet-label, .expedition-legend { display: none; }
  .exp-foot .inv-gem-name, .exp-foot .inv-consumable-name, .exp-foot .inv-gem-sell, .exp-foot .inv-sell, .exp-foot .rail-title { display: none; }
  .exp-foot .inv-gem, .exp-foot .inv-consumable, .exp-foot .inv-socket-empty { width: 40px; height: 40px; }
  .map-pop { width: min(340px, 48%); }
}

/* =========================================================================
   Versions 2 and 3: the Soul Tree (soul-tree.ts)
   ========================================================================= */
.soul-tree-btn-copy { display: inline-flex; flex-direction: column; align-items: center; line-height: 1.15; }
.ember-badge { font-size: 11px; font-weight: 700; color: #ffb36b; letter-spacing: .02em; }
.ember-notice {
  display: flex; flex-direction: column; align-items: center; gap: 4px; margin: 10px auto; padding: 14px 20px; width: min(520px, 92vw);
  border-radius: var(--r-lg); background: rgba(255, 138, 61, .1); border: 1px solid rgba(255, 138, 61, .4); text-align: center;
}
.ember-notice-kicker { font-size: 10px; font-weight: 800; letter-spacing: .2em; color: #ffb36b; }
.ember-notice strong { font-size: 26px; color: #ffd0a0; }
.ember-notice span { font-size: 12.5px; color: var(--ink-dim); }
.soul-tree-overlay { z-index: 700; }
.tree-card {
  width: min(1380px, 97vw); height: min(880px, 94vh); display: grid; grid-template-rows: auto 1fr; gap: 12px; padding: 16px;
  border-radius: var(--r-lg); background: rgba(10, 12, 28, .97); border: 1px solid rgba(255, 179, 107, .3); box-shadow: 0 30px 80px rgba(0,0,0,.7);
}
.tree-head { display: flex; align-items: center; gap: 16px; }
.tree-head h2 { margin: 2px 0; }
.tree-embers { margin-left: auto; display: flex; align-items: baseline; gap: 6px; padding: 8px 14px; border-radius: 14px; background: rgba(255,138,61,.12); border: 1px solid rgba(255,138,61,.4); }
.tree-embers strong { font-size: 24px; color: #ffd0a0; }
.tree-embers small { color: var(--ink-dim); }
.tree-body { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: 12px; min-height: 0; }
.tree-stage {
  position: relative; overflow: hidden; border-radius: 16px; border: 1px solid var(--edge); cursor: grab; touch-action: none;
  background: radial-gradient(70% 60% at 50% 100%, rgba(255, 179, 107, .12), transparent 70%), radial-gradient(60% 50% at 50% 20%, rgba(157, 123, 255, .12), transparent 70%), #080a18;
}
.tree-stage.dragging { cursor: grabbing; }
.tree-world { position: absolute; left: 0; top: 0; transform-origin: 0 0; }
.tree-links { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.tree-links line { stroke: rgba(205, 216, 255, .14); stroke-width: 4; stroke-linecap: round; }
.tree-links line.open { stroke: rgba(255, 211, 110, .4); stroke-dasharray: 8 8; }
.tree-links line.lit { stroke: #ffd36e; filter: drop-shadow(0 0 6px rgba(255, 211, 110, .7)); }
.tree-links line.cross { stroke-dasharray: 3 9; }
.tree-links line.cross.lit { stroke: #c79bff; stroke-dasharray: none; filter: drop-shadow(0 0 6px rgba(199, 155, 255, .7)); }
.tree-node {
  position: absolute; transform: translate(-50%, -50%); width: 184px; padding: 10px 10px 11px; display: flex; flex-direction: column; align-items: center; gap: 3px;
  border-radius: 16px; border: 1px solid var(--edge-bright); background: rgba(16, 19, 44, .95); color: var(--ink); font: inherit; cursor: pointer; text-align: center;
  transition: transform .15s, box-shadow .2s, opacity .2s, translate .15s, scale .15s;
}
.tree-node:hover { transform: translate(-50%, -50%) scale(1.05); }
.tree-node .tree-node-gem { width: 84px; height: 84px; display: grid; place-items: center; border-radius: 50%; background: radial-gradient(circle, color-mix(in srgb, var(--bough) 30%, transparent), transparent 70%); }
.tree-node img { width: 74px; height: 74px; object-fit: contain; }
.tree-node strong { font-size: 19px; line-height: 1.15; }
.tree-node small { font-size: 15px; color: var(--ink-dim); }
.tree-node.capstone { width: 200px; border-width: 2px; }
.tree-node.st-locked { opacity: .42; }
.tree-node.st-locked img { filter: grayscale(1) brightness(.6); }
.tree-node.st-open { border-color: color-mix(in srgb, var(--bough) 50%, transparent); }
.tree-node.st-ready { border-color: var(--bough); box-shadow: 0 0 0 1px var(--bough), 0 0 24px color-mix(in srgb, var(--bough) 45%, transparent); animation: node-ready 2.4s ease-in-out infinite; --tone: var(--bough); }
.tree-node.st-restored { border-color: var(--bough); background: color-mix(in srgb, var(--bough) 16%, rgba(16,19,44,.95)); box-shadow: 0 0 30px color-mix(in srgb, var(--bough) 40%, transparent); }
.tree-node.st-restored small { color: var(--bough); font-weight: 700; }
.tree-node.selected { outline: 2px solid #fff; outline-offset: 3px; }
.tree-node-plan { position: absolute; top: -12px; right: -12px; width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center; background: #ffb36b; color: #2a1400; font-size: 16px; font-weight: 900; }
.tree-zoom { position: absolute; right: 10px; bottom: 10px; display: flex; gap: 6px; }
.tree-zoom .tree-fit { width: auto; padding: 0 10px; }
.tree-side { overflow: auto; }
.tree-detail { display: flex; flex-direction: column; gap: 10px; padding: 14px; border-radius: 16px; background: var(--panel); border: 1px solid var(--edge); }
.tree-detail h3 { margin: 0; font-size: 20px; }
.tree-detail-bough { font-size: 10px; font-weight: 800; letter-spacing: .18em; color: #ffb36b; }
.tree-detail-effect { margin: 0; font-size: 13.5px; line-height: 1.45; }
.tree-detail-story { margin: 0; font-size: 12.5px; color: var(--ink-dim); font-style: italic; }
.tree-detail-names { font-size: 12px; color: var(--ink-faint); }
.tree-detail-state { font-size: 12.5px; color: var(--ink-dim); padding: 8px 10px; border-radius: 10px; background: rgba(4,8,22,.5); border: 1px solid var(--edge); }
.tree-auto { display: flex; flex-direction: column; gap: 8px; margin-top: 6px; padding-top: 10px; border-top: 1px solid var(--edge); }
.tree-strategies { display: flex; flex-wrap: wrap; gap: 5px; }
.tree-auto-note { margin: 0; font-size: 12px; color: var(--ink-dim); }
.tree-auto-row { display: flex; gap: 8px; align-items: center; }
@container app (max-width: 1000px) { .tree-body { grid-template-columns: 1fr; grid-template-rows: 1fr auto; } }

/* =========================================================================
   Version 3: screen changes (ui.ts cinematic). Version 1 and 2 keep the wipe.
   ========================================================================= */
::view-transition-old(root), ::view-transition-new(root) {
  animation-duration: .36s;
  animation-timing-function: cubic-bezier(.2, .8, .2, 1);
  mix-blend-mode: normal;
}
html[data-vt="fight"]::view-transition-old(root),
html[data-vt="challenge"]::view-transition-old(root) { animation: vt-push-old .34s cubic-bezier(.5, 0, .7, .4) both; }
html[data-vt="fight"]::view-transition-new(root),
html[data-vt="challenge"]::view-transition-new(root) { animation: vt-push-new .42s cubic-bezier(.2, .8, .2, 1) .06s both; }
html[data-vt="challenge"]::view-transition-new(root) { animation-name: vt-push-new-violet; }
html[data-vt="spoils"]::view-transition-old(root) { animation: vt-fade-old .24s ease-in both; }
html[data-vt="spoils"]::view-transition-new(root) { animation: vt-rise-new .42s cubic-bezier(.2, .8, .2, 1) .04s both; }
html[data-vt="return"]::view-transition-old(root) { animation: vt-sink-old .26s ease-in both; }
html[data-vt="return"]::view-transition-new(root) { animation: vt-settle-new .4s cubic-bezier(.2, .8, .2, 1) both; }
html[data-vt="finale"]::view-transition-old(root) { animation: vt-fade-old .7s ease-in both; }
html[data-vt="finale"]::view-transition-new(root) { animation: vt-fade-new 1s ease-out .2s both; }
html[data-vt="soft"]::view-transition-old(root) { animation: vt-fade-old .2s ease-in both; }
html[data-vt="soft"]::view-transition-new(root) { animation: vt-fade-new .28s ease-out both; }

@keyframes vt-push-old { to { opacity: 0; transform: scale(1.07); filter: blur(5px) brightness(1.3); } }
@keyframes vt-push-new { from { opacity: 0; transform: scale(.965); filter: brightness(1.6); } }
@keyframes vt-push-new-violet { from { opacity: 0; transform: scale(.965); filter: hue-rotate(40deg) brightness(1.5); } }
@keyframes vt-rise-new { from { opacity: 0; transform: translateY(26px); } }
@keyframes vt-sink-old { to { opacity: 0; transform: translateY(14px) scale(.99); } }
@keyframes vt-settle-new { from { opacity: 0; transform: scale(1.02); } }
@keyframes vt-fade-old { to { opacity: 0; } }
@keyframes vt-fade-new { from { opacity: 0; } }

.cine-plate { position: fixed; inset: 0; z-index: 800; overflow: hidden; background: #05060d; pointer-events: none; }
.cine-plate img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.cine-shade { position: absolute; inset: 0; background: radial-gradient(70% 60% at 50% 55%, transparent 20%, rgba(4, 5, 14, .78) 100%), linear-gradient(180deg, rgba(4,5,14,.2), rgba(4,5,14,.75)); }
.cine-text { position: absolute; left: 50%; bottom: 16%; transform: translateX(-50%); display: flex; flex-direction: column; align-items: center; gap: 8px; text-align: center; width: min(900px, 92vw); }
.cine-text small { font-size: 13px; font-weight: 800; letter-spacing: .34em; color: var(--gold); animation: cine-in .7s cubic-bezier(.2, .8, .2, 1) both; }
.cine-text strong { font: 900 clamp(34px, 6vw, 72px)/1.02 var(--font-display, serif); letter-spacing: .04em; color: #fff4dc; text-shadow: 0 6px 30px rgba(0,0,0,.8);
  animation: cine-in .8s cubic-bezier(.2, .8, .2, 1) .08s both; }
.cine-text span { font-size: 15px; color: #d6dbff; max-width: 640px; animation: cine-in .8s cubic-bezier(.2, .8, .2, 1) .18s both; }
.cine-warden .cine-text strong { color: #ffd0d6; text-shadow: 0 0 40px rgba(255, 77, 109, .55), 0 6px 30px rgba(0,0,0,.8); }
.cine-warden .cine-text small { color: #ff8b9b; }
@keyframes cine-in { from { opacity: 0; transform: translateY(14px); letter-spacing: .5em; } }
@media (prefers-reduced-motion: reduce) { .cine-plate { display: none; } }

/* A face-down card turned over on the altar: a brief glint so the eye finds it. */
.card.played.revealed { animation: reveal-glint .9s ease-out; }
@keyframes reveal-glint { from { box-shadow: 0 0 0 2px #fff, 0 0 30px rgba(255,255,255,.7); } }

/* =========================================================================
   Version 3: the landscape stage (stage.ts)
   ========================================================================= */
.landscape-stage #app { transform-origin: 0 0; }
.turn-device { display: none; }
@media (orientation: portrait) and (max-width: 900px) {
  .landscape-stage .turn-device {
    position: fixed; inset: 0; z-index: 10000; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px;
    padding: 24px; text-align: center; background: radial-gradient(circle at 50% 40%, #1b1d48, #07081a 70%); color: var(--ink);
  }
  .turn-device-icon { font-size: 54px; animation: turn-hint 2.4s ease-in-out infinite; }
  .turn-device strong { font-size: 20px; }
  .turn-device span { color: var(--ink-dim); font-size: 14px; }
}
@keyframes turn-hint { 0%, 30% { rotate: 0deg; } 55%, 85% { rotate: -90deg; } 100% { rotate: 0deg; } }

/* Both landscape fight layouts fill exactly one screen: the hand row takes
   what is left, and cards size from the screen's height as well as its width. */
.landscape-stage .combat.layout-cathedral,
.landscape-stage .combat.layout-command { overflow: hidden; }
.landscape-stage .combat.layout-cathedral { gap: 8px 14px; padding-bottom: 8px; }
.landscape-stage .layout-cathedral .play-area { min-height: 50px; }
.landscape-stage .layout-cathedral .card,
.landscape-stage .layout-command .card { width: clamp(64px, min(6.4cqw, 11.5cqh), 104px); }
/* Command Deck on the stage: the bar, then the target list down the left
   beside the score and the altar, which takes whatever height is spare, then
   sockets, consumables and the hand along the bottom. The target list scrolls
   inside its own column if a crowded room outgrows it. */
.landscape-stage .combat.layout-command {
  grid-template-rows: auto auto minmax(0, 1fr) auto; align-content: stretch; gap: 8px 14px; padding-bottom: 8px;
}
.landscape-stage .layout-command .encounter { align-self: stretch; min-height: 0; overflow-y: auto; scrollbar-width: thin; }
.landscape-stage .layout-command .play-area { min-height: 56px; }
.landscape-stage .layout-command .gem-block,
.landscape-stage .layout-command .consumable-block { align-self: stretch; min-height: 0; overflow-y: auto; scrollbar-width: thin; }
.landscape-stage .layout-command .hand-panel { align-self: end; }

/* The title screen on the stage: name and buttons on the left, the run setup
   on the right, both in one screen. */
.screen.title.landscape {
  display: grid; grid-template-columns: minmax(300px, 36%) minmax(0, 1fr); align-items: center; gap: 28px;
  padding: 44px clamp(28px, 4cqw, 64px) 24px clamp(52px, 5cqw, 80px); overflow: hidden; text-align: center;
}
.title.landscape .title-brand { display: flex; flex-direction: column; align-items: center; gap: 12px; min-width: 0; }
.title.landscape .title-name { font-size: clamp(38px, 4.6cqw, 74px); line-height: 1.02; }
.title.landscape .title-actions { flex-direction: column; align-items: stretch; width: min(320px, 100%); gap: 9px; margin-top: 8px; }
.title.landscape .title-actions .big { padding-top: 14px; padding-bottom: 14px; }
.title.landscape .title-panel { width: auto; max-height: 100%; min-height: 0; padding: 16px 20px; gap: 10px; overflow: hidden; }
.title.landscape button.deck-choice { flex: 0 0 clamp(160px, 27cqh, 290px); width: clamp(160px, 27cqh, 290px); }
.title.landscape .deck-picker-detail { padding-top: 8px; padding-bottom: 8px; }

/* A hero card's portrait is as wide as the card. Fixed at 340px it spilled out
   of any card narrower than that and painted over its neighbours. */
button.deck-choice .hero-portrait.xl { width: 100%; }

/* The shop on the stage: header, three columns that each scroll on their own
   if a visit stocks more than fits, and the way out always on screen. */
.landscape-stage .screen.shop { display: grid; grid-template-rows: auto minmax(0, 1fr) auto; gap: 10px; overflow: hidden; padding-top: 10px; padding-bottom: 8px; }
.landscape-stage .shop .shop-head { margin: 0 clamp(0px, 22cqw, 300px) 0 0; width: auto; max-width: none; padding: 8px 16px 10px; align-self: stretch; }
.landscape-stage .shop-body { width: 100%; height: 100%; min-height: 0; align-items: stretch; }
.landscape-stage .shop-body > * { min-height: 0; overflow-y: auto; scrollbar-width: thin; }
.landscape-stage .shop-rail .inventory-panel .inventory { max-height: none; }
.landscape-stage .shop-controls { padding: 0; }

/* The fixed widgets outside the app (version tab, developer panel, toasts)
   shrink with the stage so they keep their size relative to the screen. */
.landscape-stage #hotu-corner,
.landscape-stage #hotu-versions,
.landscape-stage #dev-panel,
.landscape-stage .toast-rail { zoom: var(--stage-zoom, 1); }

/* =========================================================================
   Version 4 · The Lamplighter: dialled in
   ========================================================================= */

/* Cards draw everything inside them from their own width, so a card reads the
   same at any size: in the hand, on the altar, in the shop. Small cards keep
   their own fixed sizes (they out-specify these). */
.card { container-type: inline-size; }
.card .card-rank { font-size: max(13px, 21cqw); }
.card .card-pip { width: max(10px, 13cqw); height: max(10px, 13cqw); }
.card .face-pip { width: max(9px, 15.5cqw); }
.card .court-emblem { width: max(18px, 28cqw); }
.card .ace-glyph { width: max(30px, 46cqw); }
.card .card-aff { font-size: max(7px, 7.2cqw); padding: 1.6cqw 0; letter-spacing: .16em; }
.card .card-enh { width: max(14px, 13cqw); height: max(14px, 13cqw); font-size: max(8px, 7.5cqw); }
.card .card-seal { width: max(9px, 9cqw); height: max(9px, 9cqw); bottom: 14cqw; }
.card .card-back-mark { font-size: max(15px, 26cqw); }

/* Registered so it resolves where it is set (against the app), not inside
   each card (where `cqw` would mean the hand row). */
@property --cw { syntax: "<length>"; inherits: true; initial-value: 100px; }

/* --- Fights: the hand comes first ---------------------------------------
   One card size for the whole fight (`--cw`), from the stage's width and
   height. When a hand is wider than its row the cards overlap into a fan
   instead of shrinking; hovering one lifts it clear of its neighbours. */
html.landscape-stage .combat { --cw: clamp(84px, min(9.2cqw, 16.4cqh), 140px); }
html.landscape-stage .combat:not(.layout-classic) .card { width: var(--cw); }
/* The altar is a size container, so played cards fit whatever height it ends
   up with (a wrapped score line or a tall boss never clips them). */
html.landscape-stage .combat:not(.layout-classic) .play-area { container-type: size; }
html.landscape-stage .combat:not(.layout-classic) .play-area .card {
  width: min(calc(var(--cw) * .92), calc((100cqh - 10px) * .705));
}
html.landscape-stage .combat:not(.layout-classic) .hand-tools { flex-wrap: nowrap; white-space: nowrap; }
html.landscape-stage .combat .hand-with-piles { gap: 10px; align-items: flex-end; }
html.landscape-stage .combat:not(.layout-classic) .hand-rail {
  container-type: inline-size;
  flex: 1 1 0; min-width: 0; min-height: 0;
  flex-wrap: nowrap; justify-content: center; gap: 0;
  padding: 36px 6px 16px;
}
/* In the hand a card is the fight's size unless that would bury more than
   about a third of each card; then the whole hand shrinks a little instead. */
@property --hw { syntax: "<length>"; inherits: false; initial-value: 100px; }
html.landscape-stage .combat:not(.layout-classic) .hand-rail > .card {
  --hw: min(var(--cw), calc(100cqw / (var(--n, 8) * .64 + .36)));
  width: var(--hw);
}
html.landscape-stage .combat .hand-rail > .card + .card {
  margin-left: min(10px, calc((100cqw - var(--n, 8) * var(--hw)) / max(1, var(--n, 8) - 1)));
}
/* A chosen card rises but keeps its place in the stack, so it never hides
   the corner of the card beside it. */
html.landscape-stage .combat .hand-rail > .card.selected { z-index: var(--z) !important; }
html.landscape-stage .combat .hero-rig { width: calc(var(--cw) * .82); }
html.landscape-stage .combat .pile { flex: 0 0 auto; }

/* Command Deck: a wider target list, the altar trimmed to what a played hand
   needs, and the hand row (cards, piles, actions) given the rest. */
html.landscape-stage .combat.layout-command {
  grid-template-columns: minmax(220px, 18.5%) minmax(150px, 12.5%) minmax(0, 1fr);
  gap: 10px 14px; padding-bottom: 10px;
}
/* The foes run the full height of the first column, so an Elite's three
   targets and its shield are all in view; sockets and consumables stack in
   the second column beside them. */
html.landscape-stage .combat.layout-command .encounter { grid-area: 2 / 1 / 5 / 2; }
html.landscape-stage .combat.layout-command .gem-block { grid-area: 2 / 2 / 4 / 3; }
html.landscape-stage .combat.layout-command .consumable-block { grid-area: 4 / 2 / 5 / 3; }
html.landscape-stage .combat.layout-command .hand-panel { display: flex; flex-direction: column; gap: 6px; padding-top: 8px; padding-bottom: 10px; }
html.landscape-stage .combat.layout-command .play-area { min-height: calc(var(--cw) * 1.42 + 24px); }
html.landscape-stage .combat.layout-command .enemy-row .enemy-portrait { --portrait: 58px; width: 58px; }
html.landscape-stage .combat.layout-command .enemy-row .enemy.boss .enemy-portrait { --portrait: 80px; width: 80px; }
html.landscape-stage .combat.layout-command .enemy { padding: 10px 14px; border-radius: 14px; }
html.landscape-stage .combat.layout-command .enemy-name { font-size: 13px; }
html.landscape-stage .combat.layout-command .hp-bar { height: 19px; }

/* The action row: equal buttons, one weight, always the same place. */
html.landscape-stage .combat:not(.layout-classic) .actions { gap: 10px; flex-wrap: nowrap; }
html.landscape-stage .combat:not(.layout-classic) .action { min-width: 0; flex: 0 1 190px; padding: 9px 18px; border-radius: 12px; }
html.landscape-stage .combat:not(.layout-classic) .action strong { font-size: 15px; }

/* Crystal Cathedral: the altar takes the spare height between the score and
   the hand, and the cards are a size smaller than Command Deck's because the
   foes sit above the altar rather than beside it. */
html.landscape-stage .combat.layout-cathedral {
  --cw: clamp(74px, min(8cqw, 12.4cqh), 124px);
  grid-template-rows: auto auto auto minmax(84px, 1fr) auto;
  gap: 8px 16px;
  padding-top: 40px;
}
html.landscape-stage .combat.layout-cathedral .encounter-name { font-size: clamp(18px, 2.6cqh, 26px); margin-bottom: 2px; }
html.landscape-stage .combat.layout-cathedral .enemy-row { gap: 10px; }
/* The shield and any other meters stand beside the foes, not under them:
   that row of height is what the altar needs. */
html.landscape-stage .combat.layout-cathedral .encounter {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; column-gap: 14px;
}
html.landscape-stage .combat.layout-cathedral .encounter > * { grid-column: 1 / -1; }
html.landscape-stage .combat.layout-cathedral .encounter > .encounter-title { grid-row: 1; }
html.landscape-stage .combat.layout-cathedral .encounter > .intent { grid-row: 2; }
html.landscape-stage .combat.layout-cathedral .encounter > .enemy-row { grid-row: 3; grid-column: 1; }
html.landscape-stage .combat.layout-cathedral .encounter > .meters { grid-row: 3; grid-column: 2; flex-direction: column; align-items: stretch; max-width: 220px; }
html.landscape-stage .combat.layout-cathedral .enemy-row[class] .enemy-portrait { --portrait: 60px; }
html.landscape-stage .combat.layout-cathedral .enemy-row[class] .enemy.boss .enemy-portrait { --portrait: 80px; }
html.landscape-stage .combat.layout-cathedral .play-area { min-height: 0; align-self: stretch; }

html.landscape-stage .combat.layout-cathedral .hand-panel { align-self: end; }
html.landscape-stage .combat.layout-cathedral .hand-rail { padding-top: 26px; padding-bottom: 8px; }
html.landscape-stage .combat.layout-cathedral .play-area { padding: 4px; }

/* --- Title: every hero at once -------------------------------------------
   Fifteen heroes in a side-scrolling strip hid most of them behind a cut-off
   card. On the stage they are a grid of portraits: all visible, one click. */
.title.landscape .deck-picker {
  display: grid; grid-template-columns: repeat(8, minmax(0, 1fr)); gap: 7px;
  overflow: visible; padding: 10px;
}
.title.landscape button.deck-choice { flex: none; width: auto; min-width: 0; padding: 6px 6px 7px; gap: 5px; border-radius: 14px; }
.title.landscape button.deck-choice:hover { translate: 0 -3px; }
.title.landscape button.deck-choice .hero-portrait.xl { border-radius: 11px; }
.title.landscape button.deck-choice .hero-portrait.xl .hero-portrait-art { font-size: 34px; }
.title.landscape button.deck-choice .hero-portrait.xl .hero-portrait-lock { font-size: 18px; bottom: 6px; }
.title.landscape button.deck-choice .hero-portrait.xl .hero-portrait-chain-bar { height: 7px; margin-top: -3px; }
.title.landscape .deck-choice-name { font-size: 9px; letter-spacing: 0; }
.title.landscape .title-panel { gap: 12px; padding: 18px 22px; }

/* --- The map ------------------------------------------------------------
   The room popup docks on the right and the board slides left to make room,
   so the whole floor stays in view while you read a room. The floor's name
   sits small in a corner instead of behind the rooms. */
html.landscape-stage .expedition-board { --dock: min(370px, 36%); }
html.landscape-stage .expedition-canvas { transition: right .28s cubic-bezier(.2, .9, .3, 1); }
html.landscape-stage .expedition-board.docked .expedition-canvas { right: calc(var(--dock) + 12px); }
html.landscape-stage .map-pop,
html.landscape-stage .map-pop.on-left { top: 0; bottom: 0; right: 0; left: auto; width: var(--dock); }
html.landscape-stage .map-pop.open { justify-content: flex-start; }
html.landscape-stage .map-pop .expedition-inspector { max-height: 100%; overflow-y: auto; scrollbar-width: thin; }
@keyframes pop-in { from { opacity: 0; translate: 24px 0; } }
html.landscape-stage .expedition-canvas::before {
  left: auto; top: auto; right: 18px; bottom: 12px; translate: none;
  font-size: calc(var(--u) * 2.2); letter-spacing: .3em; color: rgba(255, 255, 255, .07);
}
html.landscape-stage .exp-layout span { white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
@media (prefers-reduced-motion: reduce) { html.landscape-stage .expedition-canvas { transition: none; } }
html.landscape-stage .expedition-canvas { --u: min(1.28cqw, 2.1cqh); }

/* --- The shop -------------------------------------------------------------
   Wares and packs side by side, the specialist's service underneath, so a
   whole visit reads at a glance without the middle column scrolling. The
   keeper's column is narrower; it only holds a portrait and a few lines. */
html.landscape-stage .shop-body { grid-template-columns: minmax(180px, 17%) minmax(0, 1fr) minmax(260px, 25%); gap: 12px; }
html.landscape-stage .shop-centre { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); align-content: start; gap: 12px; }
html.landscape-stage .shop-centre > .specialist-panel { grid-column: 1 / -1; }
html.landscape-stage .shop-centre > .shop-section { margin: 0; min-width: 0; }
html.landscape-stage .shop-centre .shop-grid,
html.landscape-stage .shop-centre .pack-grid { flex-wrap: wrap; justify-content: center; gap: 10px; }
html.landscape-stage .shop-centre :is(.shop-grid, .pack-grid) > * { width: calc(50% - 5px); max-width: 196px; min-width: 0; }
html.landscape-stage .shop-centre .shop-section { padding-left: 12px; padding-right: 12px; }

/* The selection readout is always one line, however much it has to say; a
   wrapped readout pushed the action row off the bottom of the screen. */
html.landscape-stage .combat:not(.layout-classic) .hand-tools { padding-inline: 12px; column-gap: 12px; }
html.landscape-stage .combat:not(.layout-classic) .hand-tools .preview { flex-wrap: nowrap; min-width: 0; overflow: hidden; }
html.landscape-stage .combat:not(.layout-classic) .hand-tools .preview > * { flex-shrink: 0; }
html.landscape-stage .combat:not(.layout-classic) .hand-tools .preview > :last-child:not(:first-child) {
  flex-shrink: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* The side boxes stay short so they never set the height of the top rows:
   floor and encounter share a line, and the chest lies on its side. */
html.landscape-stage .combat.layout-cathedral .topbar-left { display: grid; grid-template-columns: 1fr 1fr; gap: 7px; }
html.landscape-stage .combat.layout-cathedral .topbar-left > .layout-pill { grid-column: 1 / -1; justify-self: start; }
html.landscape-stage .combat.layout-cathedral .topbar-left .stat { min-width: 0; padding: 6px 8px; }
html.landscape-stage .combat.layout-cathedral .chest-badge { flex-direction: row; align-items: center; text-align: left; gap: 10px; padding: 8px 12px; }
html.landscape-stage .combat.layout-cathedral .chest-badge-art { width: 46px; height: 46px; flex: none; }

/* =========================================================================
   Version 4 · the docked fight layouts (Center Stage, War Table, Throne Hall)
   The foes stand centred at the top, the altar in the middle, and everything
   you play with (sockets, consumables, your hero, the score) sits in one dock
   around the hand. The wrappers dissolve (`display: contents`) so each piece
   is placed on the fight's own grid; the dock's panel is the grid's ::before.
   ========================================================================= */
html.landscape-stage .combat.layout-docked {
  --side: minmax(236px, 19%);
  display: grid; position: relative; overflow: hidden;
  grid-template-columns: var(--side) 62px minmax(0, 1fr) 62px var(--side);
  gap: 8px 12px; padding: 10px 16px 12px; align-content: stretch;
}
html.landscape-stage .combat.layout-docked :is(.tableau, .tableau-lower, .hand-panel, .hand-with-piles) { display: contents; }
html.landscape-stage .combat.layout-docked > * { min-width: 0; min-height: 0; }
html.landscape-stage .combat.layout-docked .topbar { grid-area: bar; }
html.landscape-stage .combat.layout-docked .encounter { grid-area: foes; }
html.landscape-stage .combat.layout-docked .scoreboard { grid-area: score; }
html.landscape-stage .combat.layout-docked .play-area { grid-area: play; }
html.landscape-stage .combat.layout-docked .gem-block { grid-area: gems; }
html.landscape-stage .combat.layout-docked .consumable-block { grid-area: cons; }
html.landscape-stage .combat.layout-docked .hand-tools { grid-area: tools; }
html.landscape-stage .combat.layout-docked .hero-rig { grid-area: hero; }
html.landscape-stage .combat.layout-docked .pile.draw { grid-area: draw; }
html.landscape-stage .combat.layout-docked .hand-rail { grid-area: rail; }
html.landscape-stage .combat.layout-docked .pile.discard { grid-area: spent; }
html.landscape-stage .combat.layout-docked .actions { grid-area: acts; }

/* The dock: one panel behind the hand and everything that belongs to it. */
html.landscape-stage .combat.layout-docked::before {
  content: ""; grid-column: 1 / -1; grid-row: -4 / -1; margin: -6px -8px -4px;
  border-radius: 20px; pointer-events: none;
  background:
    radial-gradient(60% 120% at 50% 100%, rgba(255, 211, 110, .07), transparent 70%),
    linear-gradient(180deg, rgba(22, 25, 62, .82), rgba(10, 12, 32, .92));
  border: 1px solid rgba(176, 190, 255, .16);
  box-shadow: 0 -10px 40px rgba(0, 0, 0, .35), inset 0 1px 0 rgba(255, 255, 255, .06);
}

/* The foes: name and order on the left, the line centred, the shield right. */
html.landscape-stage .combat.layout-docked .encounter-title { display: block; }
html.landscape-stage .combat.layout-docked .encounter {
  display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  grid-template-rows: auto 1fr; align-items: center; column-gap: 18px; row-gap: 4px; padding: 0;
}
html.landscape-stage .combat.layout-docked .encounter > .encounter-title { grid-area: 1 / 1; align-self: end; text-align: left; }
html.landscape-stage .combat.layout-docked .encounter > .intent { grid-area: 2 / 1; align-self: start; justify-self: start; max-width: 100%; }
html.landscape-stage .combat.layout-docked .encounter > .enemy-row { grid-area: 1 / 2 / 3 / 3; justify-content: center; flex-wrap: nowrap; gap: 12px; }
html.landscape-stage .combat.layout-docked .encounter > .meters {
  grid-area: 1 / 3 / 3 / 4; justify-self: end; align-self: center; flex-direction: column; align-items: stretch; gap: 6px; width: min(100%, 250px);
}
html.landscape-stage .combat.layout-docked .encounter-name { font-size: clamp(18px, 2.6cqh, 26px); margin: 0; }
html.landscape-stage .combat.layout-docked .enemy { width: clamp(150px, 13.5cqw, 196px); padding: 10px 12px 12px; border-radius: 16px; }
html.landscape-stage .combat.layout-docked .enemy-row[class] .enemy-portrait { --portrait: clamp(58px, 9.6cqh, 84px); }
html.landscape-stage .combat.layout-docked .enemy-row[class] .enemy.boss .enemy-portrait { --portrait: clamp(76px, 12.6cqh, 110px); }
html.landscape-stage .combat.layout-docked .enemy.boss { width: clamp(186px, 17cqw, 240px); }
html.landscape-stage .combat.layout-docked .enemy-name { font-size: 12.5px; }
html.landscape-stage .combat.layout-docked .hp-bar { height: 18px; }
html.landscape-stage .combat.layout-docked .meter { padding: 6px 10px; }

/* The altar takes whatever height is left; played cards fit it. */
html.landscape-stage .combat.layout-docked .play-area { min-height: 0; align-self: stretch; padding: 4px; }

/* The hand row: piles hug the fan, the rail lifts hovered cards clear. */
html.landscape-stage .combat.layout-docked .hand-rail { padding: 26px 4px 16px; align-self: end; }
html.landscape-stage .combat.layout-docked .pile { align-self: end; margin-bottom: 8px; justify-self: center; }
html.landscape-stage .combat.layout-docked .hand-tools { align-self: end; padding-inline: 4px; background: none; border: 0; box-shadow: none; }
/* The readout keeps to its own column, so a long one ends in an ellipsis
   instead of running under the sort buttons. */
html.landscape-stage .combat.layout-docked .hand-tools .preview { max-width: 100%; }
html.landscape-stage .combat.layout-docked .actions { align-self: center; justify-content: center; }
html.landscape-stage .combat.layout-docked .hero-rig { width: auto; height: 100%; max-height: 210px; max-width: 100%; aspect-ratio: 1; justify-self: center; align-self: center; }

/* Sockets as a compact list: art, name, a line of what they do. */
html.landscape-stage .combat.layout-docked .gem-empty-label { display: block; }
html.landscape-stage .combat.layout-docked :is(.gem-block, .consumable-block) {
  align-self: stretch; overflow-y: auto; scrollbar-width: thin; background: rgba(5, 7, 25, .35); margin: 4px 0;
}
html.landscape-stage .combat.layout-docked .gem-rail { flex-direction: column; flex-wrap: nowrap; gap: 5px; }
html.landscape-stage .combat.layout-docked :is(.gem, .gem-empty) {
  width: 100%; min-height: 0; height: auto; flex-direction: row; justify-content: flex-start; gap: 9px; padding: 5px 9px; text-align: left;
}
html.landscape-stage .combat.layout-docked .gem-empty { padding: 3px 9px; }
html.landscape-stage .combat.layout-docked .gem .gem-art { width: 30px; height: 30px; flex: none; }
html.landscape-stage .combat.layout-docked .gem .gem-text { font-size: 9px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
html.landscape-stage .combat.layout-docked .gem-order { position: static; }
html.landscape-stage .combat.layout-docked .consumable-rail { gap: 6px; }

/* The score, compact: hand name above, one line of chips × mult = total,
   the damage track under it. */
html.landscape-stage .combat.layout-docked .scoreboard { gap: 4px; padding: 8px 12px; }
html.landscape-stage .combat.layout-docked .score-row { gap: 8px; }
html.landscape-stage .combat.layout-docked :is(.chips-box, .mult-box) { min-width: 84px; padding: 4px 12px; }
html.landscape-stage .combat.layout-docked .resolution-ribbon { min-height: 0; }
html.landscape-stage .combat.layout-docked .resolution-ribbon:has(.resolution-empty) { display: none; }
html.landscape-stage .combat.layout-docked .hand-name { font-size: 13px; min-height: 17px; }

/* --- Center Stage ----------------------------------------------------------
   The score sits on the altar it is scored on; sockets on the dock's left,
   your hero and the consumables on its right. */
html.landscape-stage .combat.layout-stage {
  grid-template-rows: auto auto minmax(96px, 1fr) auto auto auto;
  grid-template-areas:
    "bar   bar   bar   bar   bar"
    "foes  foes  foes  foes  foes"
    "play  play  play  play  play"
    "gems  tools tools tools hero"
    "gems  draw  rail  spent hero"
    "gems  acts  acts  acts  cons";
}
html.landscape-stage .combat.layout-stage .scoreboard {
  grid-area: play; align-self: center; justify-self: start; width: calc(var(--side-w) - 8px); z-index: 2; position: relative; margin-left: 4px;
}
html.landscape-stage .combat.layout-stage { --side-w: max(236px, 19cqw); }
html.landscape-stage .combat.layout-stage .play-area { padding-inline: var(--side-w); }
html.landscape-stage .combat.layout-stage .consumable-block { align-self: end; }
/* Smaller portraits here than in Throne Hall: the score tower shares the
   altar's row, so the altar needs the height. */
html.landscape-stage .combat.layout-stage .enemy-row[class] .enemy-portrait { --portrait: clamp(46px, 7.4cqh, 64px); }
html.landscape-stage .combat.layout-stage .enemy-row[class] .enemy.boss .enemy-portrait { --portrait: clamp(60px, 10cqh, 86px); }
html.landscape-stage .combat.layout-stage .enemy { padding: 8px 10px 9px; }
html.landscape-stage .combat.layout-stage .enemy-traits { margin-top: 5px; }
html.landscape-stage .combat.layout-stage .scoreboard { gap: 4px; padding: 7px 9px; }

html.landscape-stage .combat.layout-stage .play-area { min-height: 140px; }

/* --- War Table -------------------------------------------------------------
   One belt above the hand (sockets, score, consumables); your hero stands at
   the left of the cards and the three actions stack on the right. */
html.landscape-stage .combat.layout-table {
  grid-template-rows: auto auto minmax(96px, 1fr) auto auto auto;
  grid-template-areas:
    "bar   bar   bar   bar   bar"
    "foes  foes  foes  foes  foes"
    "play  play  play  play  play"
    "gems  gems  score cons  cons"
    "hero  tools tools tools acts"
    "hero  draw  rail  spent acts";
}
html.landscape-stage .combat.layout-table .gem-rail { flex-direction: row; gap: 6px; }
html.landscape-stage .combat.layout-table :is(.gem, .gem-empty) { flex: 1 1 0; width: auto; flex-direction: column; justify-content: center; text-align: center; padding: 4px; gap: 2px; }
html.landscape-stage .combat.layout-table .gem :is(.gem-text, .gem-order) { display: none; }
html.landscape-stage .combat.layout-table .gem .gem-name { font-size: 9px; line-height: 1.1; }
html.landscape-stage .combat.layout-table .gem-empty-label { display: none; }
html.landscape-stage .combat.layout-table .gem-empty { min-height: 44px; }
html.landscape-stage .combat.layout-table .consumable-rail { flex-wrap: nowrap; }
html.landscape-stage .combat.layout-table :is(.gem-block, .consumable-block) { overflow: hidden; }
/* The score in the belt is one line: the hand's name, then chips × mult = total. */
html.landscape-stage .combat.layout-table .scoreboard {
  align-self: stretch; display: grid; grid-template-columns: auto auto; align-content: center; justify-content: center; align-items: center; column-gap: 14px; row-gap: 4px;
}
html.landscape-stage .combat.layout-table .scoreboard > :is(.goal, .resolution-ribbon) { grid-column: 1 / -1; justify-self: center; }
html.landscape-stage .combat.layout-table .hand-name { max-width: 150px; font-size: 12px; line-height: 1.2; text-align: right; }
/* The foes as banners across the table: portrait left, name and health right,
   so the line is short and the altar keeps its height. */
html.landscape-stage .combat.layout-table .enemy {
  display: grid; grid-template-columns: auto minmax(0, 1fr); grid-template-rows: auto auto; align-items: center; column-gap: 12px;
  width: clamp(168px, 14cqw, 220px); padding: 9px 12px; text-align: left;
}
html.landscape-stage .combat.layout-table .enemy.boss { width: clamp(220px, 19cqw, 280px); }
html.landscape-stage .combat.layout-table .enemy-art { grid-row: 1 / span 2; }
html.landscape-stage .combat.layout-table .enemy > :is(.enemy-traits, .enemy-slain) { grid-column: 1 / -1; }
html.landscape-stage .combat.layout-table .enemy-traits { justify-content: flex-start; margin-top: 6px; }
html.landscape-stage .combat.layout-table .enemy-name { margin: 0 0 5px; align-self: end; }
html.landscape-stage .combat.layout-table .hp-bar { align-self: start; }
html.landscape-stage .combat.layout-table .enemy-row[class] .enemy-portrait { --portrait: 58px; width: 58px; }
html.landscape-stage .combat.layout-table .enemy-row[class] .enemy.boss .enemy-portrait { --portrait: 78px; width: 78px; }
html.landscape-stage .combat.layout-table .actions { flex-direction: column; align-items: stretch; align-self: stretch; justify-content: center; gap: 8px; }
html.landscape-stage .combat.layout-table .action { flex: 0 0 auto; padding: 10px 12px; }
html.landscape-stage .combat.layout-table .hero-rig { max-height: 200px; align-self: end; }

/* --- Throne Hall -----------------------------------------------------------
   Your hero stands tall on the left, facing the foes; the score has its own
   tower on the right; sockets and consumables flank the hand. */
html.landscape-stage .combat.layout-throne {
  --side: minmax(220px, 17.5%);
  /* A size smaller than the other layouts' cards: the foes share their row
     with the hero and the score, so the altar needs the height. */
  --cw: clamp(80px, min(8.4cqw, 14.6cqh), 128px);
  grid-template-rows: auto auto minmax(96px, 1fr) auto auto auto;
  grid-template-areas:
    "bar   bar   bar   bar   bar"
    "hero  foes  foes  foes  score"
    "hero  play  play  play  score"
    "gems  tools tools tools cons"
    "gems  draw  rail  spent cons"
    "gems  acts  acts  acts  cons";
}
html.landscape-stage .combat.layout-throne .hero-rig {
  max-height: none; height: auto; width: 100%; aspect-ratio: auto; align-self: stretch; border-radius: 20px;
  background: radial-gradient(60% 50% at 50% 70%, rgba(255, 211, 110, .16), transparent 70%), linear-gradient(180deg, rgba(22, 25, 62, .5), rgba(10, 12, 32, .7));
  border: 1px solid rgba(255, 211, 110, .2);
}
html.landscape-stage .combat.layout-throne .hero-rig-body { width: 92%; height: 92%; }
/* The foes' column is narrow here, so everything shares rows: the room's
   name with its rule, then the line with the shield beside it. */
html.landscape-stage .combat.layout-throne .encounter {
  grid-template-columns: minmax(0, 1fr) auto; grid-template-rows: auto auto; align-items: center; column-gap: 12px; row-gap: 6px;
}
html.landscape-stage .combat.layout-throne .encounter > .encounter-title { grid-area: 1 / 1 / 2 / 3; justify-self: center; text-align: center; }
html.landscape-stage .combat.layout-throne .encounter:has(> .intent) > .encounter-title { grid-area: 1 / 1; }
html.landscape-stage .combat.layout-throne .encounter-place { display: none; }
html.landscape-stage .combat.layout-throne .encounter > .intent { grid-area: 1 / 2; justify-self: end; max-width: 240px; font-size: 11px; line-height: 1.25; }
html.landscape-stage .combat.layout-throne .encounter > .enemy-row { grid-area: 2 / 1; justify-self: center; gap: 10px; }
html.landscape-stage .combat.layout-throne .encounter > .meters { grid-area: 2 / 2; justify-self: end; flex-direction: column; width: auto; max-width: 200px; }
html.landscape-stage .combat.layout-throne .encounter:not(:has(> .meters .meter)) > .enemy-row { grid-column: 1 / 3; }
html.landscape-stage .combat.layout-throne .enemy-row[class] .enemy-portrait { --portrait: clamp(40px, 6.6cqh, 58px); }
html.landscape-stage .combat.layout-throne .enemy-row[class] .enemy.boss .enemy-portrait { --portrait: clamp(54px, 8.8cqh, 76px); }
html.landscape-stage .combat.layout-throne .enemy { width: clamp(132px, 11.4cqw, 170px); padding: 8px 9px 9px; }
html.landscape-stage .combat.layout-throne .enemy.boss { width: clamp(160px, 14cqw, 210px); }
html.landscape-stage .combat.layout-throne .enemy-traits { margin-top: 5px; }
html.landscape-stage .combat.layout-throne .scoreboard { align-self: stretch; justify-content: center; gap: 8px; }
/* The score as a tower (Throne Hall's right column, Center Stage's altar side):
   chips × mult on one line, the total under it. */
html.landscape-stage .combat:is(.layout-throne, .layout-stage) .score-row { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; justify-items: stretch; gap: 3px 6px; width: 100%; }
html.landscape-stage .combat:is(.layout-throne, .layout-stage) .score-row > .equals { display: none; }
html.landscape-stage .combat:is(.layout-throne, .layout-stage) .score-row > .total-box { grid-column: 1 / -1; justify-self: center; }
html.landscape-stage .combat:is(.layout-throne, .layout-stage) :is(.chips-box, .mult-box) { min-width: 0; padding: 4px 6px; }
html.landscape-stage .combat:is(.layout-throne, .layout-stage) .hand-name { text-align: center; letter-spacing: .12em; }
html.landscape-stage .combat:is(.layout-throne, .layout-stage) .goal { width: 100%; }
/* One line in the tower here: chips × mult = total. */
html.landscape-stage .combat.layout-stage .score-row { grid-template-columns: 1fr auto 1fr auto 1.25fr; gap: 4px; }
html.landscape-stage .combat.layout-stage .score-row > .equals { display: block; }
html.landscape-stage .combat.layout-stage .score-row > .total-box { grid-column: auto; justify-self: stretch; min-width: 0; padding: 4px 6px; }
html.landscape-stage .combat.layout-stage :is(.chips-value, .mult-value, .total-value) { font-size: 20px; }
html.landscape-stage .combat.layout-stage :is(.times, .equals) { font-size: 16px; }

/* =========================================================================
   Version 4 · the start menu
   The name and one column of choices on the left over the threshold art; a
   card for the saved run on the right. Keyboard: arrows walk, Enter picks.
   ========================================================================= */
.screen.front-menu {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 26px;
  padding: 36px 56px 44px; overflow: hidden; text-align: left;
}
html .screen.title.front-menu::before {
  background:
    linear-gradient(90deg, rgba(4, 5, 16, .92) 0%, rgba(4, 5, 16, .7) 36%, rgba(4, 5, 16, .2) 70%, rgba(4, 5, 16, .45) 100%),
    linear-gradient(180deg, rgba(4, 5, 16, .2), rgba(4, 5, 16, .65)),
    url("./assets/images/hotu_screen_001_title-threshold_v01_source.png") center 30% / cover no-repeat;
  filter: none;
}
.front-head { display: flex; flex-direction: column; align-items: center; gap: 8px; text-align: center; }
.front-head .title-mark { margin-bottom: -4px; }
.front-head .title-mark .gem-art { width: 64px; height: 64px; }
.front-head .title-name { font-size: clamp(40px, 4.4cqw, 66px); line-height: 1; text-align: center; white-space: nowrap; }
.front-main { display: flex; align-items: center; justify-content: center; gap: 56px; }
.front-body { display: flex; flex-direction: column; min-width: 0; }
.front-items { display: flex; flex-direction: column; gap: 4px; width: 380px; max-width: 100%; }
button.front-item {
  position: relative; display: flex; align-items: center; width: 100%; padding: 10px 18px 10px 22px; text-align: left;
  background: linear-gradient(90deg, rgba(255, 255, 255, .03), transparent 80%); border: 0; border-radius: 10px; box-shadow: none;
  color: var(--ink); transition: background .18s, translate .18s, color .18s;
}
button.front-item::before {
  content: ""; position: absolute; left: 6px; top: 22%; bottom: 22%; width: 3px; border-radius: 3px; background: var(--gold);
  opacity: 0; scale: 1 .4; transition: opacity .18s, scale .18s;
}
button.front-item:hover:not(:disabled), button.front-item:focus-visible {
  translate: 6px 0; background: linear-gradient(90deg, rgba(255, 211, 110, .16), transparent 85%); filter: none; box-shadow: none; outline: none;
}
button.front-item:hover::before, button.front-item:focus-visible::before { opacity: 1; scale: 1; }
.front-item-copy { display: flex; flex-direction: column; gap: 1px; }
.front-item-copy strong { font-size: 21px; font-weight: 800; letter-spacing: .04em; }
.front-item-copy small { font-size: 12px; color: var(--ink-dim); font-weight: 500; letter-spacing: .02em; }
.front-item-copy .ember-badge { font-size: 12px; }
button.front-item.primary-item strong { font-size: 27px; color: var(--gold); text-shadow: 0 0 24px rgba(255, 211, 110, .45); }
.front-minor { display: flex; gap: 22px; margin-top: 16px; padding-left: 22px; }
.front-minor button.link { font-size: 12px; letter-spacing: .16em; text-transform: uppercase; }
.front-continue {
  cursor: pointer; width: 290px; display: flex; flex-direction: column; align-items: center; gap: 10px;
  padding: 20px; border-radius: 22px; text-align: center;
  background: linear-gradient(180deg, rgba(18, 21, 52, .82), rgba(8, 10, 26, .9)); border: 1px solid rgba(255, 211, 110, .28);
  box-shadow: 0 30px 60px rgba(0, 0, 0, .5), inset 0 1px 0 rgba(255, 255, 255, .06); backdrop-filter: blur(10px);
}
.front-continue-kicker { font-size: 10px; font-weight: 800; letter-spacing: .24em; color: var(--gold); }
.front-continue .hero-portrait.xl { width: 100%; border-radius: 16px; }
.front-continue > strong { font-size: 22px; }
.front-continue-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; width: 100%; }
.front-continue-stats span { display: flex; flex-direction: column; padding: 6px 4px; border-radius: 10px; background: rgba(255, 255, 255, .05); font-size: 10px; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-faint); }
.front-continue-stats b { font-size: 15px; letter-spacing: 0; text-transform: none; color: var(--ink); }
.front-continue-seed { font-family: var(--font-num); font-size: 11px; color: var(--ink-faint); letter-spacing: .1em; }
.front-switcher {
  position: absolute; left: 50%; bottom: 12px; translate: -50% 0;
  display: flex; align-items: center; gap: 4px; padding: 4px 6px; border-radius: 999px;
  background: rgba(0, 0, 0, .35); border: 1px solid rgba(255, 255, 255, .1);
}
.front-switch-label { font-size: 9px; letter-spacing: .2em; text-transform: uppercase; color: var(--ink-faint); margin: 0 6px; }
button.front-switch { min-height: 0; padding: 4px 11px; font-size: 12px; border-radius: 999px; background: transparent; border: 1px solid transparent; box-shadow: none; color: var(--ink-dim); }
button.front-switch.on { background: var(--gold); color: #1a1205; border-color: var(--gold); }

/* Centered: the name over a centred pair, the menu and the saved run. */
html .screen.title.front-menu.menu-centered::before,
html .screen.title.front-menu.menu-duo::before,
html .screen.title.front-menu.menu-pillar::before {
  background:
    radial-gradient(60% 70% at 50% 48%, rgba(4, 5, 16, .55), rgba(4, 5, 16, .2) 70%),
    linear-gradient(180deg, rgba(4, 5, 16, .55), rgba(4, 5, 16, .35) 40%, rgba(4, 5, 16, .8)),
    url("./assets/images/hotu_screen_001_title-threshold_v01_source.png") center 30% / cover no-repeat;
}

/* Duo: the name and menu stacked on the left, the run card beside them; the pair centred. */
.front-menu.menu-duo { display: grid; grid-template-columns: auto auto; grid-template-areas: "head card" "body card"; justify-content: center; align-content: center; column-gap: 72px; row-gap: 22px; }
.menu-duo .front-main { display: contents; }
.menu-duo .front-head { grid-area: head; align-items: flex-start; text-align: left; }
.menu-duo .front-head .title-name { text-align: left; white-space: normal; }
.menu-duo .front-body { grid-area: body; }
.menu-duo .front-continue { grid-area: card; align-self: center; }

/* Pillar: one centred column like a console menu; the run card becomes a strip. */
.front-menu.menu-pillar { gap: 18px; }
.menu-pillar .front-head .title-mark .gem-art { width: 52px; height: 52px; }
.menu-pillar .front-head .title-name { font-size: clamp(36px, 3.8cqw, 56px); }
.menu-pillar .front-main { flex-direction: column; gap: 14px; }
.menu-pillar .front-continue {
  order: -1; width: 400px; display: grid; grid-template-columns: 76px 1fr; grid-template-areas: "art kicker" "art name" "art stats";
  align-items: center; gap: 2px 16px; padding: 12px 16px; text-align: left;
}
.menu-pillar .front-continue .hero-portrait.xl { grid-area: art; width: 76px; height: 76px; border-radius: 12px; }
.menu-pillar .front-continue-kicker { grid-area: kicker; }
.menu-pillar .front-continue > strong { grid-area: name; font-size: 18px; }
.menu-pillar .front-continue-stats { grid-area: stats; }
.menu-pillar .front-continue-stats span { padding: 3px 4px; }
.menu-pillar .front-continue-seed { display: none; }
.menu-pillar .front-items { width: 400px; }
.menu-pillar button.front-item { justify-content: center; text-align: center; padding: 7px 18px; background: transparent; }
.menu-pillar .front-item-copy { align-items: center; }
.menu-pillar .front-item-copy small { display: none; }
.menu-pillar button.front-item:hover:not(:disabled), .menu-pillar button.front-item:focus-visible { translate: none; background: radial-gradient(closest-side, rgba(255, 211, 110, .18), transparent); }
.menu-pillar button.front-item::before { display: none; }
.menu-pillar .front-minor { justify-content: center; padding-left: 0; }

.front-foot { position: absolute; right: 24px; bottom: 14px; font-size: 10px; letter-spacing: .14em; color: rgba(255, 255, 255, .35); }

/* =========================================================================
   Version 4 · the hero select
   The same three pieces (roster, chosen hero, run setup) in three layouts and
   four colourways. The palette sets the accent and the light behind the art;
   the chosen hero's own colour (`--deck-rgb`) tints the glow around them.
   ========================================================================= */
.screen.hero-select {
  --hs-a: #ffd36e; --hs-b: #b07cff; --hs-deep: #0b0820; --hs-panel: rgba(20, 16, 46, .82);
  display: grid; grid-template-rows: auto minmax(0, 1fr); gap: 14px; padding: 18px clamp(28px, 3.4cqw, 52px) 18px clamp(48px, 4.6cqw, 72px);
  overflow: hidden; text-align: left; align-items: stretch; outline: none;
}
.hero-select.palette-ember { --hs-a: #ffb347; --hs-b: #ff5f6d; --hs-deep: #1c0a0c; --hs-panel: rgba(42, 16, 18, .82); }
.hero-select.palette-frost { --hs-a: #bff3ff; --hs-b: #6f97ff; --hs-deep: #06101f; --hs-panel: rgba(12, 26, 48, .82); }
.hero-select.palette-verdant { --hs-a: #c6f28a; --hs-b: #33b67a; --hs-deep: #06140e; --hs-panel: rgba(12, 34, 26, .82); }
html .screen.title.hero-select::before {
  background:
    radial-gradient(55% 70% at 28% 55%, rgba(var(--deck-rgb, 255, 211, 110), .2), transparent 70%),
    radial-gradient(60% 60% at 85% 10%, color-mix(in srgb, var(--hs-b) 26%, transparent), transparent 70%),
    linear-gradient(180deg, color-mix(in srgb, var(--hs-deep) 70%, transparent), color-mix(in srgb, var(--hs-deep) 94%, transparent)),
    url("./assets/images/hotu_screen_002_run-selection-hall_v01_source.png") center / cover no-repeat;
  filter: none; transition: background .4s;
}
.hs-head { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 18px; padding-right: 176px; }
.hs-title h1 { margin: 0; font-size: clamp(24px, 3cqw, 34px); letter-spacing: .04em; }
.hs-kicker { font-size: 10px; font-weight: 800; letter-spacing: .26em; color: var(--hs-a); }
.hs-switcher { display: flex; align-items: center; gap: 8px; padding: 6px 10px; border-radius: 999px; background: rgba(0, 0, 0, .35); border: 1px solid rgba(255, 255, 255, .1); }
.hs-switch-label { font-size: 9px; letter-spacing: .2em; text-transform: uppercase; color: var(--ink-faint); margin-left: 6px; }
.hs-switch-row { display: flex; gap: 4px; }
button.hs-switch { padding: 5px 11px; font-size: 12px; border-radius: 999px; background: transparent; border: 1px solid transparent; box-shadow: none; color: var(--ink-dim); }
button.hs-switch.on { background: var(--hs-a); color: #1a1205; border-color: var(--hs-a); }
button.hs-swatch { width: 22px; height: 22px; padding: 0; border-radius: 50%; border: 2px solid rgba(255, 255, 255, .25); box-shadow: none; }
button.hs-swatch.on { border-color: #fff; box-shadow: 0 0 0 2px rgba(0, 0, 0, .6), 0 0 12px rgba(255, 255, 255, .4); }

.hs-body { display: grid; gap: 16px; min-height: 0; }
.hs-roster-wrap { position: relative; min-height: 0; min-width: 0; display: flex; align-items: center; gap: 8px; }
.hs-roster { flex: 1; min-width: 0; min-height: 0; height: 100%; }
button.hs-arrow { display: none; flex: none; width: 40px; height: 64px; padding: 0; font-size: 30px; line-height: 1; border-radius: 12px; background: rgba(0, 0, 0, .4); border: 1px solid rgba(255, 255, 255, .14); color: var(--hs-a); }
button.hs-hero {
  display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 6px 6px 8px; min-width: 0; border-radius: 14px;
  background: var(--hs-panel); border: 1px solid rgba(255, 255, 255, .08); box-shadow: none; color: var(--ink);
}
button.hs-hero .hero-portrait.xl { width: 100%; border-radius: 10px; }
button.hs-hero .hero-portrait.xl .hero-portrait-art { font-size: 34px; }
button.hs-hero .hero-portrait.xl .hero-portrait-lock { font-size: 18px; bottom: 6px; }
button.hs-hero .hero-portrait.xl .hero-portrait-chain-bar { height: 7px; margin-top: -3px; }
.hs-hero-name { font-size: 11px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hs-hero-rank { font-size: 9px; letter-spacing: .12em; color: var(--ink-faint); text-transform: uppercase; }
button.hs-hero.locked .hs-hero-name { color: var(--ink-faint); }
button.hs-hero.active { border-color: var(--hs-a); box-shadow: 0 0 0 1px var(--hs-a), 0 0 22px color-mix(in srgb, var(--hs-a) 40%, transparent); }
button.hs-hero.viewing:not(.active) { border-color: rgba(255, 255, 255, .4); }
button.hs-hero.active .hs-hero-name { color: var(--hs-a); }

.hs-detail { display: flex; min-width: 0; min-height: 0; gap: 18px; padding: 16px; border-radius: 20px; background: var(--hs-panel); border: 1px solid color-mix(in srgb, var(--hs-a) 26%, transparent); }
.hs-detail-art .hero-portrait.xl { width: 100%; border-radius: 16px; box-shadow: 0 0 40px rgba(var(--deck-rgb), .35), 0 16px 34px rgba(0, 0, 0, .5); }
.hs-detail-copy { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.hs-name { margin: 0; font-size: clamp(24px, 2.6cqw, 36px); line-height: 1.05; color: #fff; }
.hs-power { margin: 4px 0 0; font-size: 15px; line-height: 1.45; color: var(--ink); }
.hs-hint { margin: 2px 0 0; font-size: 12px; color: var(--ink-dim); line-height: 1.4; }
.hs-detail .soul-title { color: var(--hs-a); }
.hs-detail .soul-pip.lit { background: var(--hs-a); box-shadow: 0 0 8px var(--hs-a); }

.hs-setup { display: flex; flex-direction: column; gap: 12px; padding: 16px; border-radius: 20px; background: var(--hs-panel); border: 1px solid rgba(255, 255, 255, .08); min-width: 0; }
.hs-setup .seed-input { width: 100%; }
.hs-stakes { flex-wrap: wrap; gap: 5px; }
.hs-stakes .chip { padding: 5px 10px; font-size: 11.5px; }
.hs-stakes .chip.active { background: var(--hs-a); color: #1a1205; border-color: var(--hs-a); }
button.hs-begin { margin-top: auto; display: flex; justify-content: center; padding: 14px 18px; background: linear-gradient(180deg, color-mix(in srgb, var(--hs-a) 100%, white 20%), color-mix(in srgb, var(--hs-a) 80%, black)); color: #1a1205; border: 0; }
button.hs-begin > span { display: flex; flex-direction: column; align-items: center; line-height: 1.1; }
button.hs-begin strong { font-size: 20px; letter-spacing: .06em; }
button.hs-begin small { font-size: 10px; letter-spacing: .2em; opacity: .65; text-transform: uppercase; }

/* --- Gallery: every hero in a grid, the chosen one in full beside it ---- */
.hero-select.design-gallery .hs-body { grid-template-columns: minmax(0, 1fr) minmax(340px, 32%); grid-template-rows: minmax(0, 1fr) auto; grid-template-areas: "roster detail" "roster setup"; }
.hero-select.design-gallery .hs-roster-wrap { grid-area: roster; }
.hero-select.design-gallery .hs-detail { grid-area: detail; flex-direction: column; align-items: center; text-align: center; overflow: hidden; gap: 10px; }
.hero-select.design-gallery .hs-detail-art { width: auto; height: 100%; min-height: 0; flex: 1 1 0; aspect-ratio: 1; max-width: 100%; }
.hero-select.design-gallery .hs-detail-art .hero-portrait.xl { width: auto; height: 100%; }
.hero-select.design-gallery .hs-detail-copy { align-items: center; flex: none; }
.hero-select.design-gallery .hs-name { font-size: 28px; }
.hero-select.design-gallery .hs-power { margin: 0; font-size: 14px; }
.hero-select.design-gallery .hs-setup { grid-area: setup; }
.hero-select.design-gallery .hs-track { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 10px; align-content: start; height: 100%; }
.hero-select.design-gallery button.hs-hero .hero-portrait.xl { aspect-ratio: 1; }

/* --- Spotlight: the chosen hero fills the stage, the roster along the bottom - */
.hero-select.design-spotlight .hs-body { grid-template-columns: minmax(0, 1fr) minmax(300px, 27%); grid-template-rows: minmax(0, 1fr) auto; grid-template-areas: "detail setup" "roster roster"; }
.hero-select.design-spotlight .hs-detail { grid-area: detail; align-items: center; gap: 28px; padding: 20px 28px; background: linear-gradient(90deg, var(--hs-panel), transparent); border: 0; }
.hero-select.design-spotlight .hs-detail { container-type: size; }
.hero-select.design-spotlight .hs-detail-art { flex: none; width: min(48cqw, 100cqh - 40px); }
.hero-select.design-spotlight .hs-detail-art .hero-portrait.xl { width: 100%; }
.hero-select.design-spotlight .hs-name { font-size: clamp(34px, 4cqw, 56px); }
.hero-select.design-spotlight .hs-power { font-size: 17px; max-width: 46ch; }
.hero-select.design-spotlight .hs-setup { grid-area: setup; }
.hero-select.design-spotlight .hs-roster-wrap { grid-area: roster; }
.hero-select.design-spotlight .hs-track { display: grid; grid-template-columns: repeat(15, minmax(0, 1fr)); gap: 6px; }
.hero-select.design-spotlight button.hs-hero { padding: 4px 4px 5px; gap: 2px; border-radius: 10px; }
.hero-select.design-spotlight .hs-hero-rank { display: none; }
.hero-select.design-spotlight .hs-hero-name { font-size: 8.5px; letter-spacing: 0; }
.hero-select.design-spotlight button.hs-hero.active { translate: 0 -6px; }
.hero-select.design-spotlight button.hs-arrow { display: block; height: 52px; width: 32px; font-size: 24px; }

/* --- Banners: tall banners in a row, the chosen one raised in the middle -- */
.hero-select.design-banners .hs-body { grid-template-columns: minmax(0, 1fr) minmax(320px, 30%); grid-template-rows: minmax(0, 1fr) auto; grid-template-areas: "roster roster" "detail setup"; }
.hero-select.design-banners .hs-roster-wrap { grid-area: roster; }
.hero-select.design-banners .hs-roster { position: relative; overflow: hidden; mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent); }
.hero-select.design-banners .hs-track {
  --bw: clamp(150px, 26cqh, 210px); --bgap: 18px;
  position: absolute; left: 50%; top: 0; bottom: 0; display: flex; align-items: center; gap: var(--bgap);
  translate: calc(-1 * (var(--i, 0) * (var(--bw) + var(--bgap)) + var(--bw) / 2)) 0; transition: translate .45s cubic-bezier(.2, .9, .3, 1);
}
.hero-select.design-banners button.hs-hero {
  flex: 0 0 var(--bw); width: var(--bw); padding: 8px 8px 14px; border-radius: 18px 18px 60px 60px / 18px 18px 30px 30px;
  background: linear-gradient(180deg, color-mix(in srgb, var(--hs-b) 30%, var(--hs-deep)), var(--hs-deep)); opacity: .55; scale: .88; transition: scale .35s, opacity .35s, box-shadow .35s;
}
.hero-select.design-banners button.hs-hero .hero-portrait.xl { aspect-ratio: 3 / 4; border-radius: 12px 12px 40px 40px / 12px 12px 22px 22px; }
.hero-select.design-banners button.hs-hero .hero-portrait-art { object-fit: cover; }
.hero-select.design-banners button.hs-hero.viewing { opacity: 1; scale: 1.06; }
.hero-select.design-banners button.hs-hero:hover:not(.viewing) { opacity: .85; }
.hero-select.design-banners .hs-hero-name { font-size: 13px; }
.hero-select.design-banners button.hs-arrow { display: block; z-index: 2; }
.hero-select.design-banners .hs-detail { grid-area: detail; padding: 14px 18px; }
.hero-select.design-banners .hs-detail-art { display: none; }
.hero-select.design-banners .hs-setup { grid-area: setup; }
.hero-select.design-banners .hs-setup { display: grid; grid-template-columns: 1fr; gap: 8px; padding: 12px 14px; }

/* =========================================================================
   Version 4 · "Show me around": the screen dims, one part is lit, a small
   card beside it explains it (see guide.ts).
   ========================================================================= */
.tour { position: fixed; inset: 0; z-index: 9000; }
.tour-hole {
  position: fixed; border-radius: 14px; box-shadow: 0 0 0 200vmax rgba(4, 5, 16, .72); outline: 3px solid #ffd36e; outline-offset: 2px; pointer-events: none;
  transition: left .35s cubic-bezier(.3, .8, .3, 1), top .35s cubic-bezier(.3, .8, .3, 1), width .35s cubic-bezier(.3, .8, .3, 1), height .35s cubic-bezier(.3, .8, .3, 1);
  animation: tour-glow 1.6s ease-in-out infinite;
}
.tour-hole.none { left: 50% !important; top: 50% !important; width: 0 !important; height: 0 !important; outline: 0; animation: none; }
@keyframes tour-glow { 50% { outline-color: #fff3c4; outline-offset: 5px; } }
.tour-card {
  position: fixed; z-index: 2; padding: 14px 16px 12px; border-radius: 18px; color: var(--ink);
  background: linear-gradient(180deg, #232650, #14163a); border: 2px solid #ffd36e; box-shadow: 0 22px 60px rgba(0, 0, 0, .8);
  transition: left .35s cubic-bezier(.3, .8, .3, 1), top .35s cubic-bezier(.3, .8, .3, 1);
}
.tour-card h3 { margin: 4px 0 6px; font-size: 22px; color: #fff4cf; }
.tour-card p { margin: 0 0 10px; font-size: 14.5px; line-height: 1.45; color: #e3e6ff; }
.tour-head { display: flex; justify-content: space-between; align-items: center; }
.tour-count { font-size: 11px; font-weight: 800; letter-spacing: .14em; color: #ffd36e; }
button.tour-skip, button.tour-more { padding: 2px; background: none; border: 0; box-shadow: none; color: #aab0dd; font-size: 12.5px; font-weight: 500; text-decoration: underline; }
button.tour-more { display: block; margin: -2px 0 10px; color: #9ee7ff; }
.tour-btns { display: flex; justify-content: space-between; gap: 10px; align-items: center; }
button.tour-back { padding: 9px 16px; background: rgba(255, 255, 255, .07); border: 1px solid rgba(255, 255, 255, .2); }
button.tour-next { min-width: 120px; padding: 9px 18px; background: linear-gradient(180deg, #ffe38a, #f4b63e); color: #3a2600; border: 0; box-shadow: 0 4px 0 #a8741c; }
.tour-dots { display: flex; gap: 5px; justify-content: center; margin-top: 10px; }
.tour-dots i { width: 7px; height: 7px; border-radius: 50%; background: rgba(255, 255, 255, .16); }
.tour-dots i.done { background: rgba(255, 211, 110, .5); }
.tour-dots i.on { background: #ffd36e; scale: 1.25; }
.tour-arrow { position: absolute; width: 16px; height: 16px; margin: -9px; background: #232650; border: 2px solid #ffd36e; rotate: 45deg; }
.tour-arrow.below { top: 0; border-right: 0; border-bottom: 0; }
.tour-arrow.above { top: 100%; border-left: 0; border-top: 0; background: #14163a; }
.tour-arrow.right { left: 0; border-top: 0; border-right: 0; }
.tour-arrow.left { left: 100%; border-bottom: 0; border-left: 0; }
.tour-arrow.inside, .tour-arrow.none { display: none; }
@media (prefers-reduced-motion: reduce) { .tour-hole, .tour-card { transition: none; animation: none; } }

/* =========================================================================
   Version 4 · the illustrated guide: five landscape pages with tabs, the
   game's own art, and Back / Next / Let's play always on screen.
   ========================================================================= */
.guide-overlay { z-index: 800; }
.guide-overlay .guide-card {
  width: min(1060px, 94vw); max-width: none; height: min(640px, 90vh); max-height: none; padding: 0; overflow: hidden; display: grid; grid-template-rows: auto auto minmax(0, 1fr) auto;
  border-radius: 22px; text-align: left;
}
.gd-banner {
  position: relative; display: flex; align-items: flex-end; justify-content: space-between; min-height: 112px; padding: 18px 26px 14px;
  background:
    linear-gradient(90deg, rgba(6, 7, 22, .92), rgba(6, 7, 22, .45) 55%, rgba(6, 7, 22, .2)),
    url("./assets/images/hotu_screen_004_encounter-intro-arena_v01_source.png") center 40% / cover no-repeat;
}
.gd-kicker { font-size: 10px; font-weight: 800; letter-spacing: .26em; color: var(--gold); }
.gd-banner h2 { margin: 2px 0 0; font-size: 34px; }
button.gd-close { position: absolute; top: 12px; right: 14px; width: 34px; height: 34px; padding: 0; border-radius: 50%; }
.gd-tabs { display: flex; gap: 4px; padding: 10px 22px 0; border-bottom: 1px solid rgba(255, 255, 255, .08); }
button.gd-tab { padding: 9px 16px; font-size: 13.5px; border-radius: 10px 10px 0 0; background: transparent; border: 0; box-shadow: none; color: var(--ink-dim); }
button.gd-tab:hover:not(:disabled) { translate: none; color: var(--ink); }
button.gd-tab.on { background: rgba(255, 211, 110, .12); color: var(--gold); box-shadow: inset 0 -2px 0 var(--gold); }
.gd-holder { min-height: 0; overflow: hidden; padding: 18px 26px; }
.gd-page { height: 100%; display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr); gap: 26px; align-items: center; }
.gd-copy { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.gd-lead { margin: 0; font-size: 17px; line-height: 1.55; color: var(--ink); }
.gd-steps { margin: 0; padding-left: 22px; display: flex; flex-direction: column; gap: 11px; font-size: 15px; line-height: 1.45; color: var(--ink-dim); }
.gd-steps b { color: var(--ink); }
.gd-tip { display: grid; grid-template-columns: 46px minmax(0, 1fr); gap: 12px; align-items: center; padding: 9px 12px; border-radius: 14px; background: rgba(255, 255, 255, .04); border: 1px solid rgba(255, 255, 255, .07); }
.gd-tip b { display: block; font-size: 14px; }
.gd-tip p { margin: 2px 0 0; font-size: 12.5px; line-height: 1.45; color: var(--ink-dim); }
.gd-tip-icon { display: grid; place-items: center; width: 46px; height: 46px; font-size: 26px; }
.gd-tip-icon > :is(img, .gem-art, .shield-art) { width: 44px; height: 44px; object-fit: contain; }
.gd-art { display: flex; align-items: center; justify-content: center; min-width: 0; height: 100%; border-radius: 18px; background: radial-gradient(70% 70% at 50% 40%, rgba(176, 124, 255, .14), transparent 70%), rgba(0, 0, 0, .22); border: 1px solid rgba(255, 255, 255, .06); }

/* the demo: a hand, a readout and a foe */
.gd-demo { width: 100%; display: flex; flex-direction: column; align-items: center; gap: 14px; padding: 14px; }
.gd-demo-foe { display: flex; align-items: center; gap: 12px; padding: 8px 14px; border-radius: 14px; background: rgba(0, 0, 0, .35); border: 1px solid rgba(255, 255, 255, .1); }
.gd-demo-foe-art { width: 56px; height: 56px; object-fit: contain; }
.gd-demo-foe-copy strong { font-size: 13px; text-transform: uppercase; letter-spacing: .08em; }
.gd-demo-hp { position: relative; width: 170px; height: 16px; margin-top: 4px; border-radius: 99px; overflow: hidden; background: rgba(255, 255, 255, .1); }
.gd-demo-fill { position: absolute; inset: 0 auto 0 0; width: 100%; background: linear-gradient(90deg, #ff6b6b, #ffb36b); transition: width .7s cubic-bezier(.2, .9, .3, 1); }
.gd-demo-hp span { position: relative; display: block; text-align: center; font-family: var(--font-num); font-size: 10px; line-height: 16px; }
.gd-demo-score { display: flex; flex-direction: column; align-items: center; gap: 6px; }
.gd-demo-name { font-size: 13px; font-weight: 800; letter-spacing: .16em; text-transform: uppercase; color: var(--gold); min-height: 18px; }
.gd-demo-math { display: flex; align-items: center; gap: 10px; font-size: 18px; color: var(--ink-faint); }
.gd-demo-math span { display: flex; flex-direction: column; align-items: center; min-width: 62px; padding: 4px 10px; border-radius: 10px; background: rgba(255, 255, 255, .06); }
.gd-demo-math b { font-family: var(--font-num); font-size: 20px; color: var(--ink); }
.gd-demo-math small { font-size: 9px; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-faint); }
.gd-demo-chips { color: var(--chips) !important; } .gd-demo-mult { color: var(--mult) !important; } .gd-demo-total { color: var(--gold) !important; }
.gd-demo-hand { display: flex; justify-content: center; margin-top: 28px; }
.gd-demo-hand .card.card { width: 82px; transform: none; transition: translate .3s, box-shadow .3s; pointer-events: none; }
.gd-demo-hand .card + .card { margin-left: -12px; }
.gd-demo-hand .card.gd-pick { translate: 0 -16px; box-shadow: 0 0 0 2px rgba(255, 211, 110, .7); }
.gd-demo-hand .card.gd-played { translate: 0 -30px; box-shadow: 0 0 0 2px var(--gold), 0 0 24px rgba(255, 211, 110, .7); }

/* shields and foes */
.gd-foe-art { gap: 14px; padding: 14px; align-items: center; }
.gd-tier { position: relative; display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 10px; border-radius: 14px; background: rgba(0, 0, 0, .3); border: 1px solid rgba(255, 255, 255, .08); text-align: center; }
.gd-tier > img:first-child { width: 96px; height: 96px; object-fit: contain; }
.gd-tier.boss > img:first-child { width: 150px; height: 150px; }
.gd-tier .shield-art { position: absolute; top: 6px; right: 6px; width: 34px; height: 34px; object-fit: contain; }
.gd-tier small { font-size: 11px; color: var(--ink-faint); }
.gd-chest { width: 44px; height: 44px; object-fit: contain; }

/* affinities */
.gd-aff { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; padding: 16px; align-content: center; }
.gd-aff-card { display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 14px 10px; border-radius: 16px; background: rgba(0, 0, 0, .3); border: 1px solid; text-align: center; }
.gd-aff-card img { width: 64px; height: 64px; object-fit: contain; }
.gd-aff-card b { font-size: 15px; } .gd-aff-card small { font-size: 12px; color: var(--ink-dim); }
.gd-aff-card.aff-strength { border-color: color-mix(in srgb, var(--strength) 55%, transparent); } .gd-aff-card.aff-strength b { color: var(--strength); }
.gd-aff-card.aff-agility { border-color: color-mix(in srgb, var(--agility) 55%, transparent); } .gd-aff-card.aff-agility b { color: var(--agility); }
.gd-aff-card.aff-elemental { border-color: color-mix(in srgb, var(--elemental) 55%, transparent); } .gd-aff-card.aff-elemental b { color: var(--elemental); }
.gd-aff-card.aff-arcane { border-color: color-mix(in srgb, var(--arcane) 55%, transparent); } .gd-aff-card.aff-arcane b { color: var(--arcane); }

/* the run: a tiny floor map */
.gd-map { flex-direction: column; gap: 22px; }
.gd-map-row { display: flex; align-items: center; gap: 6px; }
.gd-map-row i { width: 22px; height: 3px; border-radius: 3px; background: linear-gradient(90deg, #ffd36e, #ffb36b); }
.gd-map-row.side { gap: 10px; }
.gd-room { padding: 10px 12px; border-radius: 12px; font-size: 12px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; background: rgba(255, 255, 255, .06); border: 1px solid rgba(255, 255, 255, .16); }
.gd-room.elite { border-color: #ffd36e; color: #ffd36e; }
.gd-room.boss { border-color: #ff6b8a; color: #ff9db2; }
.gd-room.camp { color: var(--ink-dim); }
.gd-room.opt { border-style: dashed; color: #9ee7ff; border-color: rgba(158, 231, 255, .5); }

/* keys */
.gd-keys { grid-template-columns: repeat(3, minmax(0, 1fr)); align-content: center; gap: 10px 18px; }
.gd-key { display: flex; align-items: center; gap: 12px; padding: 10px 12px; border-radius: 12px; background: rgba(255, 255, 255, .04); }
.gd-key kbd { min-width: 64px; padding: 6px 8px; border-radius: 8px; text-align: center; font-family: var(--font-num); font-size: 13px; background: #1c1f44; border: 1px solid rgba(255, 255, 255, .2); box-shadow: 0 3px 0 rgba(0, 0, 0, .5); color: var(--gold); }
.gd-key span { font-size: 13.5px; color: var(--ink-dim); }

.gd-foot { display: flex; align-items: center; gap: 10px; padding: 12px 22px 16px; border-top: 1px solid rgba(255, 255, 255, .08); }
.gd-spacer { flex: 1; }
button.gd-next { min-width: 140px; }

/* ===========================================================================
   Prologue: the opening cinematic (prologue.ts). Two styles share the frame,
   captions and controls: Storybook (one painted plate per beat) and Tableau
   (one continuous scene around the threshold table, driven by .s1-.s6).
   =========================================================================== */
.prologue {
  position: fixed; inset: 0; z-index: 9000;
  display: grid; place-items: center;
  background: #030208;
  color: #f4ead2;
  animation: pro-in .8s ease-out both;
}
.prologue.closing { animation: pro-out .6s ease-in both; }
@keyframes pro-in { from { opacity: 0; } }
@keyframes pro-out { to { opacity: 0; filter: blur(4px); } }

.pro-frame { position: relative; width: min(100vw, 177.78vh); aspect-ratio: 16 / 9; }
.pro-stage {
  position: absolute; inset: 0; overflow: hidden;
  container-type: size;
  background: #000;
  cursor: pointer;
}
.pro-stage.instant, .pro-stage.instant * { transition: none !important; }
.pro-stage img { pointer-events: none; user-select: none; }

/* Captions sit low in the frame, a word at a time. */
.pro-caption {
  position: absolute; left: 0; right: 0; bottom: 6.5%;
  display: grid; justify-items: center; gap: .5em;
  padding: 0 8%;
  pointer-events: none; text-align: center;
  font-family: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  opacity: 0; transition: opacity .25s;
  z-index: 5;
}
.pro-frame::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 26%;
  background: linear-gradient(transparent, rgba(0, 0, 0, .72));
  pointer-events: none; z-index: 4;
}
.pro-caption.on { opacity: 1; }
.pro-cap-line {
  font-size: clamp(18px, 2.6vw, 38px); line-height: 1.25;
  text-shadow: 0 2px 18px #000, 0 0 4px #000;
}
.pro-cap-line span { display: inline-block; white-space: pre; }
.pro-caption.on .pro-cap-line span { animation: pro-word .9s calc(.3s + var(--d, 0s) + var(--w) * 120ms) both cubic-bezier(.2, .7, .2, 1); }
@keyframes pro-word { from { opacity: 0; translate: 0 .35em; filter: blur(6px); } }

.pro-controls {
  position: fixed; top: 14px; right: 16px; z-index: 2;
  display: flex; gap: 10px; align-items: center;
}
.pro-switch {
  display: flex; align-items: center; gap: 2px; padding: 3px;
  border: 1px solid rgba(233, 196, 106, .3); border-radius: 999px;
  background: rgba(10, 8, 20, .7); backdrop-filter: blur(6px);
}
.pro-switch-label { font-size: 11px; letter-spacing: .14em; text-transform: uppercase; color: rgba(244, 234, 210, .55); padding: 0 8px 0 10px; }
button.pro-style, button.pro-skip {
  min-height: 0; padding: 6px 14px; border-radius: 999px;
  font-size: 13px; font-weight: 700;
  background: transparent; border: 0; box-shadow: none; color: rgba(244, 234, 210, .7);
}
button.pro-style.active { background: linear-gradient(135deg, #f4d27a, #c08a2e); color: #1b1206; }
button.pro-skip { border: 1px solid rgba(244, 234, 210, .25); background: rgba(10, 8, 20, .7); color: #f4ead2; }
.pro-foot {
  position: fixed; bottom: 12px; left: 0; right: 0; z-index: 2;
  display: flex; justify-content: center; align-items: center; gap: 18px;
  pointer-events: none;
}
.pro-dots { display: flex; gap: 8px; pointer-events: auto; }
button.pro-dot {
  width: 10px; height: 10px; min-height: 0; padding: 0; border-radius: 50%;
  border: 1px solid rgba(233, 196, 106, .6); background: transparent; box-shadow: none;
}
button.pro-dot.active { background: #e9c46a; box-shadow: 0 0 10px #e9c46a; }
.pro-hint { font-size: 11px; letter-spacing: .06em; color: rgba(244, 234, 210, .4); }
.prologue.at-end .pro-hint { visibility: hidden; }

/* --- Shared pieces ------------------------------------------------------- */
.pro-chain {
  position: absolute; height: 1.6cqh; width: 100%;
  background:
    radial-gradient(ellipse 50% 40% at 50% 50%, transparent 46%, #e2ccff 50%, #8c5cff 66%, transparent 72%) 0 50% / 2.6cqh 100% repeat-x;
  filter: drop-shadow(0 0 .6cqh #a77bff) drop-shadow(0 0 1.6cqh rgba(130, 80, 255, .7));
  transform-origin: left center;
  scale: 0 1;
}
.pro-embers { position: absolute; inset: 0; pointer-events: none; }
.pro-embers i {
  position: absolute; left: var(--x); bottom: -2%;
  width: .55cqh; height: .55cqh; border-radius: 50%;
  background: #ffcf6e; box-shadow: 0 0 1cqh #ffb347;
  opacity: 0;
  animation: pro-ember var(--s) var(--d) linear infinite;
}
@keyframes pro-ember {
  0% { opacity: 0; translate: 0 0; }
  15% { opacity: .9; }
  100% { opacity: 0; translate: 3cqw -70cqh; }
}

.pro-titlecard {
  position: absolute; inset: 0;
  display: grid; justify-items: center; align-content: start;
  padding-top: 13cqh; gap: 1.6cqh;
  text-align: center;
  background: radial-gradient(ellipse 60% 45% at 50% 28%, rgba(0, 0, 0, .55), transparent 70%);
}
.pro-title-kicker {
  font-size: 1.9cqh; letter-spacing: .38em; text-transform: uppercase; color: #e9c46a;
  opacity: 0; animation: pro-rise 1.6s .9s both;
}
.pro-title { margin: 0; display: grid; line-height: .95; font-family: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif; }
.pro-title span { font-size: 4.6cqh; font-weight: 400; letter-spacing: .3em; text-transform: uppercase; opacity: 0; animation: pro-rise 1.6s .3s both; }
.pro-title strong {
  font-size: 15cqh; letter-spacing: .08em; text-transform: uppercase;
  background: linear-gradient(180deg, #fff3cf 10%, #f2c55c 48%, #a4691c 92%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
  filter: drop-shadow(0 .4cqh 0 #2a1704) drop-shadow(0 0 4cqh rgba(255, 190, 90, .45));
  animation: pro-title 2.4s .5s both cubic-bezier(.2, .7, .2, 1);
}
.pro-press {
  position: absolute; bottom: 9cqh; left: 0; right: 0;
  font-size: 2.1cqh; letter-spacing: .3em; text-transform: uppercase; color: #f4ead2;
  animation: pro-press 2.2s 3s infinite both;
}
@keyframes pro-rise { from { opacity: 0; translate: 0 1.5cqh; } to { opacity: 1; translate: 0 0; } }
@keyframes pro-title { from { opacity: 0; letter-spacing: .5em; filter: blur(12px); } to { opacity: 1; } }
@keyframes pro-press { 0%, 100% { opacity: .15; } 50% { opacity: .85; } }

/* --- Storybook ----------------------------------------------------------- */
.sb-plate { position: absolute; inset: 0; opacity: 0; transition: opacity 1.2s ease; }
.sb-plate.on { opacity: 1; }
.sb-plate.out { opacity: 0; transition-duration: 1.3s; }
.sb-plate > * { position: absolute; }
.sb-bg { inset: 0; width: 100%; height: 100%; object-fit: cover; }
.sb-plate.on .sb-bg { animation: sb-push 10s ease-out both; }
@keyframes sb-push { from { scale: 1.14; } to { scale: 1; } }

.sb-row { left: 3%; right: 3%; bottom: 5%; height: 40cqh; display: flex; justify-content: center; align-items: flex-end; }
.sb-hero {
  position: relative; flex: none; width: 13cqh; height: calc(19cqh + var(--k) * 1.6cqh);
  margin-inline: -1.2cqh;
  translate: 0 calc((7 - var(--k)) * -1.1cqh);
  z-index: var(--k);
  opacity: 0;
}
.sb-hero img { position: absolute; inset: auto -40% 0; width: 180%; height: auto; max-height: 100%; object-fit: contain; object-position: bottom; filter: drop-shadow(0 .8cqh 1cqh rgba(0, 0, 0, .6)); }
.sb-plate.on .sb-hero { animation: sb-appear 1.1s calc(.3s + var(--k) * 110ms) both; }
@keyframes sb-appear { from { opacity: 0; translate: 0 calc((7 - var(--k)) * -1.1cqh + 3cqh); } to { opacity: 1; } }
.sb-1.on .sb-hero img { animation: sb-lend 1.4s calc(2.2s + var(--i) * 70ms) both; }
@keyframes sb-lend { 50% { filter: drop-shadow(0 0 1.4cqh #ffd36e) brightness(1.35); } }
.sb-glow { inset: 0; background: radial-gradient(ellipse 30% 30% at 50% 36%, rgba(255, 214, 120, .55), transparent 70%); opacity: 0; }
.sb-1.on .sb-glow { animation: sb-fadein 2s 3.2s both; }
.sb-deck { left: 50%; top: 18%; width: 9cqh; translate: -50% 0; opacity: 0; }
.sb-deck img { width: 100%; border-radius: .8cqh; box-shadow: 0 0 3cqh #ffd36e, 0 0 9cqh rgba(255, 179, 71, .6); }
.sb-1.on .sb-deck { animation: sb-deck 2s 3.6s both cubic-bezier(.2, .9, .2, 1.2); }
@keyframes sb-deck { from { opacity: 0; scale: .2; rotate: -20deg; } to { opacity: 1; scale: 1; rotate: 0deg; } }
.sb-flare { position: absolute; inset: -150%; background: radial-gradient(circle, rgba(255, 240, 200, .9), rgba(255, 200, 100, .3) 25%, transparent 55%); opacity: 0; }
.sb-1.on .sb-flare { animation: sb-flare 1.6s 3.7s both; }
@keyframes sb-flare { 30% { opacity: 1; scale: 1.2; } to { opacity: 0; scale: .6; } }
@keyframes sb-fadein { from { opacity: 0; } to { opacity: 1; } }

.sb-dark { inset: 0; background: radial-gradient(ellipse at 50% 40%, rgba(20, 0, 40, .3), rgba(0, 0, 0, .85)); opacity: 0; }
.sb-2.on .sb-dark { animation: sb-fadein 5s .4s both; }
.sb-3 .sb-dark { opacity: .8; }
.sb-vaelos { left: 50%; bottom: -6%; height: 96cqh; translate: -50% 18%; opacity: 0; filter: brightness(.3) drop-shadow(0 0 4cqh #6a3cff); }
.sb-2.on .sb-vaelos { animation: sb-vaelos 5.5s 1.2s both cubic-bezier(.3, .6, .2, 1); }
@keyframes sb-vaelos { to { translate: -50% 0; opacity: 1; filter: brightness(1) drop-shadow(0 0 4cqh #6a3cff); } }
.sb-lamps { left: 6%; right: 6%; top: 58%; display: flex; justify-content: space-between; }
.sb-lamps i { width: 1cqh; height: 1.6cqh; border-radius: 50% 50% 45% 45%; background: #ffd36e; box-shadow: 0 0 1.2cqh #ffb347, 0 0 3cqh #ff9a2a; }
.sb-2.on .sb-lamps i { animation: sb-out .5s calc(.2s + var(--i) * 260ms) both; }
@keyframes sb-out { 40% { scale: 1.4; } to { opacity: .05; scale: .3; box-shadow: none; } }

.sb-3 .sb-row .sb-hero { opacity: 1; animation: none !important; }
.sb-3.on .sb-hero:not(.escaped) img { animation: sb-bind 1.4s calc(1s + var(--k) * 140ms) both; }
@keyframes sb-bind { to { filter: brightness(0) drop-shadow(0 0 .6cqh #9b6bff) drop-shadow(0 0 1.6cqh rgba(110, 60, 255, .6)); opacity: .9; } }
.sb-3 .sb-hero.escaped img { filter: drop-shadow(0 0 1.6cqh #ffb347); }
.sb-chains { inset: 0; }
.sb-chains .a { top: 60%; rotate: -7deg; left: -5%; width: 110%; }
.sb-chains .b { top: 72%; rotate: 4deg; left: -5%; width: 110%; }
.sb-chains .c { top: 84%; rotate: -2deg; left: -5%; width: 110%; }
.sb-3.on .pro-chain { animation: pro-draw 1.2s cubic-bezier(.6, 0, .2, 1) both; }
.sb-3.on .pro-chain.a { animation-delay: .5s; }
.sb-3.on .pro-chain.b { animation-delay: .8s; }
.sb-3.on .pro-chain.c { animation-delay: 1.1s; }
@keyframes pro-draw { to { scale: 1 1; } }
.sb-names { inset: 0; }
.sb-names span, .tb-names span {
  position: absolute; left: var(--x); top: var(--y);
  font: italic 3cqh "Iowan Old Style", Palatino, Georgia, serif; color: #f3e6c4;
  text-shadow: 0 0 1cqh rgba(255, 220, 160, .6);
  opacity: 0;
}
.sb-3.on .sb-names span { animation: pro-forget 3s calc(3s + var(--i) * 230ms) both; }
@keyframes pro-forget {
  0% { opacity: 0; translate: 0 1cqh; filter: blur(4px); }
  25% { opacity: .9; filter: blur(0); }
  100% { opacity: 0; translate: 0 -6cqh; filter: blur(8px); letter-spacing: .4em; }
}

.sb-4.on .sb-bg { animation: sb-rush 8s ease-in both; }
@keyframes sb-rush { from { scale: 1; } to { scale: 1.5; } }
.sb-closing { inset: 0; box-shadow: inset 0 0 0 0 rgba(60, 20, 120, .9); }
.sb-4.on .sb-closing { animation: sb-close 6.5s .5s both ease-in; }
@keyframes sb-close { to { box-shadow: inset 0 0 22cqh 8cqh rgba(40, 10, 90, .95); } }
.sb-closing .l { top: 14%; left: -10%; width: 60%; rotate: 12deg; }
.sb-closing .r { top: 80%; left: 50%; width: 60%; rotate: -168deg; transform-origin: left center; }
.sb-4.on .sb-closing .pro-chain { animation: pro-draw 2.4s 3s both cubic-bezier(.6, 0, .2, 1); }
.sb-runner { left: 50%; bottom: -4%; height: 72cqh; aspect-ratio: 1; translate: -50% 0; }
.sb-runner img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; object-position: bottom; }
.sb-4.on .sb-runner { animation: sb-run 7s both cubic-bezier(.3, .5, .3, 1); }
@keyframes sb-run { from { scale: .55; translate: -50% -8%; opacity: 0; } 12% { opacity: 1; } to { scale: 1.08; translate: -50% 4%; } }
.sb-runner .weak { opacity: 0; filter: saturate(.5) brightness(.8); }
.sb-4.on .sb-runner .full { animation: sb-dim 2.6s 3.2s both steps(6, end); }
.sb-4.on .sb-runner .weak { animation: sb-fadein 2.6s 3.2s both; }
@keyframes sb-dim { 0%, 30%, 60% { opacity: 1; } 15%, 45%, 75%, 100% { opacity: 0; } }
.sb-carried { left: 67%; top: 40%; width: 8cqh; rotate: 10deg; z-index: 2; }
.sb-carried::before, .tb-deck::before { content: ""; position: absolute; inset: -90%; border-radius: 50%; background: radial-gradient(closest-side, rgba(255, 214, 120, .55), rgba(255, 170, 60, .18) 55%, transparent); z-index: -1; }
.sb-carried img { position: relative; }
.sb-carried img { width: 100%; border-radius: .6cqh; box-shadow: 0 0 2cqh #ffd36e; }
.sb-4.on .sb-carried { animation: sb-carry 7s both cubic-bezier(.3, .5, .3, 1); }
.sb-4.on .sb-carried img { animation: pro-power 1.8s 3.6s both; }
@keyframes pro-power { 40% { box-shadow: 0 0 4cqh #fff1c4, 0 0 12cqh #ffb347; filter: brightness(1.6); } to { box-shadow: 0 0 2.6cqh #ffd36e, 0 0 6cqh rgba(255, 179, 71, .7); } }
@keyframes sb-carry { from { opacity: 0; scale: .5; translate: -4cqw -4cqh; } 15% { opacity: 1; } to { scale: 1.15; translate: 0 2cqh; } }

.sb-night { inset: 0; background: radial-gradient(ellipse 60% 70% at 50% 70%, rgba(10, 10, 30, .35), rgba(2, 2, 10, .88)); }
@keyframes pro-pulse { 50% { scale: 1.35; filter: drop-shadow(0 0 5px #ffd36e) drop-shadow(0 0 16px #ffb347); } }
.sb-fallen, .tb-fallen { left: 31%; bottom: 3%; height: 46cqh; aspect-ratio: 1; filter: brightness(.55) saturate(.6) drop-shadow(0 0 2cqh rgba(0, 0, 0, .8)); opacity: 0; }
.sb-fallen img, .tb-fallen img { width: 100%; height: 100%; object-fit: contain; object-position: bottom; }
.sb-5.on .sb-fallen { animation: sb-fall 2.4s .6s both; }
@keyframes sb-fall { from { opacity: 0; translate: -3cqw 0; } to { opacity: 1; rotate: -4deg; } }
.sb-ember-deck, .tb-campdeck { left: 55%; bottom: 7%; width: 6cqh; rotate: 74deg; opacity: 0; filter: drop-shadow(0 0 1cqh #ffb347); }
.sb-ember-deck img, .tb-campdeck img { width: 100%; border-radius: .5cqh; }
.sb-5.on .sb-ember-deck { animation: sb-fadein 1.4s 2.6s both, pro-deckglow 2.4s 4s infinite; }
@keyframes pro-deckglow { 50% { filter: drop-shadow(0 0 1.6cqh #ffd36e) brightness(1.4); } }
.sb-5 .pro-embers { opacity: 0; }
.pro-motes { position: absolute; left: 57%; bottom: 12%; width: 0; height: 0; }
.pro-motes i {
  position: absolute; width: .9cqh; height: .9cqh; border-radius: 50%;
  background: #fff1c4; box-shadow: 0 0 1cqh #ffd36e, 0 0 3cqh rgba(255, 179, 71, .8);
  opacity: 0;
}
.sb-5.on .pro-motes i { animation: pro-mote 3.6s calc(4.2s + var(--i) * 140ms) both cubic-bezier(.3, .6, .3, 1); }
.s5 .tb-camp .pro-motes i { animation: pro-mote 3.6s calc(4.6s + var(--i) * 140ms) both cubic-bezier(.3, .6, .3, 1); }
@keyframes pro-mote {
  0% { opacity: 0; translate: 0 0; scale: .4; }
  15% { opacity: 1; scale: 1.2; }
  100% { opacity: .85; translate: var(--tx) var(--ty); scale: .45; }
}
.sb-5.on .pro-embers { animation: sb-fadein 2s 4s both; }

/* --- Tableau: the threshold table, one continuous scene ------------------- */
.tb-world, .tb-camp, .tb-title { position: absolute; inset: 0; }
.tb-world { transform-origin: 50% 70%; scale: 1.28; transition: scale 9s cubic-bezier(.2, .6, .2, 1), translate 2.4s ease, opacity 1.6s ease, filter 2s; }
.tb-world > * { position: absolute; }
.tb-bg { inset: 0; width: 100%; height: 100%; object-fit: cover; }
.tb-dim { inset: 0; background: radial-gradient(ellipse at 50% 45%, rgba(25, 0, 50, .35), rgba(0, 0, 0, .88)); opacity: .25; transition: opacity 4s ease 1s; }
.tb-vaelos { left: 50%; top: 2%; height: 64cqh; translate: -50% 25%; opacity: 0; filter: brightness(.2) drop-shadow(0 0 3cqh #6a3cff); transition: translate 4.5s cubic-bezier(.3, .6, .2, 1) 1.4s, opacity 3s ease 1.4s, filter 4s ease 1.4s, scale 2s ease; }
.tb-gatechains { inset: 0; }
.tb-gatechains .pro-chain { left: 30%; width: 40%; }
.tb-gatechains .g1 { top: 22%; rotate: 8deg; }
.tb-gatechains .g2 { top: 36%; rotate: -6deg; }
.tb-gatechains .g3 { top: 50%; rotate: 3deg; }
.tb-ring { inset: 0; }
.tb-hero {
  position: absolute; left: var(--x); top: var(--y);
  width: 24cqh; height: 24cqh;
  translate: -50% -100%; scale: var(--sc); transform-origin: 50% 100%;
  z-index: var(--z);
  opacity: 0;
  transition: opacity 1.2s ease calc(.4s + var(--k) * 120ms), left 1.8s cubic-bezier(.5, 0, .2, 1), top 1.8s cubic-bezier(.5, 0, .2, 1), scale 1.8s cubic-bezier(.5, 0, .2, 1), filter 1.6s;
}
.tb-hero img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; object-position: bottom; transition: filter 1.4s ease calc(1.2s + var(--k) * 150ms), opacity 1.2s ease; }
.tb-hero .weak { opacity: 0; }
.tb-halo { position: absolute; left: 20%; right: 20%; top: 0; bottom: 10%; border-radius: 50%; background: radial-gradient(closest-side, rgba(255, 210, 120, .55), transparent); opacity: 0; transition: opacity 1s ease calc(var(--i) * 230ms); }
.tb-bonds { position: absolute; inset: 20% 10% 25%; }
.tb-bonds .pro-chain { height: 2.6cqh; background-size: 4cqh 100%; width: 120%; left: -10%; }
.tb-bonds .x1 { top: 30%; rotate: 28deg; }
.tb-bonds .x2 { top: 62%; rotate: -24deg; }
.tb-cards { inset: 0; }
.tb-card { position: absolute; left: var(--fx); top: var(--fy); width: 5cqh; translate: -50% -50%; opacity: 0; }
.tb-card img { width: 100%; border-radius: .5cqh; box-shadow: 0 0 1.4cqh #ffd36e; }
.tb-deck { left: 50%; top: 79%; width: 6cqh; translate: -50% -50%; opacity: 0; scale: .3; transition: opacity .8s ease 3.9s, scale .9s cubic-bezier(.2, .9, .2, 1.3) 3.9s, left 1.6s ease, top 1.6s ease; z-index: 30; }
.tb-deck img { position: relative; width: 100%; border-radius: .6cqh; box-shadow: 0 0 2cqh #ffd36e, 0 0 6cqh rgba(255, 179, 71, .7); }
.tb-flare { position: absolute; inset: -200%; background: radial-gradient(circle, rgba(255, 240, 200, .9), rgba(255, 200, 100, .3) 22%, transparent 50%); opacity: 0; }
.tb-names { inset: 0; z-index: 40; }
.tb-camp { opacity: 0; transition: opacity 1.8s ease; }
.tb-camp > * { position: absolute; }
.tb-campbg { inset: 0; width: 100%; height: 100%; object-fit: cover; }
.tb-camp .pro-embers { opacity: 0; transition: opacity 2s 4s; }
.tb-title { opacity: 0; pointer-events: none; }
.tb-title .pro-titlecard * { animation-play-state: paused; }

/* I. Fifteen: the heroes gather, each throws a card, one deck forms. */
.s1 .tb-world { scale: 1.02; }
.s1 .tb-hero { opacity: 1; }
.s1 .tb-halo { opacity: 1; }
.s1 .tb-card { animation: tb-throw 1.2s calc(1.8s + var(--i) * 110ms) both cubic-bezier(.5, 0, .3, 1); }
@keyframes tb-throw {
  0% { opacity: 0; scale: .6; }
  20% { opacity: 1; scale: 1; }
  100% { opacity: .9; left: 50%; top: 79%; scale: .9; rotate: var(--r); }
}
.s1 .tb-deck { opacity: 1; scale: 1; }
.s1 .tb-flare { animation: sb-flare 1.6s 4s both; }

/* II. The lamps go out; Vaelos comes up through the arch. */
.s2 .tb-card { animation: none; opacity: 0; }
.s2 .tb-world { scale: 1.08; translate: 0 3%; }
.s2 .tb-halo { opacity: 0; }
.s2 .tb-dim { opacity: .82; }
.s2 .tb-vaelos { translate: -50% 0; opacity: 1; filter: brightness(1) drop-shadow(0 0 3cqh #6a3cff); }

/* III. The binding: chains, silhouettes, names forgotten. */
.s3 .tb-world { scale: 1.12; translate: 0 5%; }
.s3 .tb-bonds .pro-chain { scale: 1 1; transition: scale 1s cubic-bezier(.6, 0, .2, 1) calc(.4s + var(--k) * 140ms); }
.s3 .tb-hero:not(.escaped) img { filter: brightness(0) drop-shadow(0 0 .6cqh #9b6bff) drop-shadow(0 0 1.4cqh rgba(110, 60, 255, .6)); }
.s3 .tb-hero.escaped .tb-halo { opacity: 1; transition-delay: 2s; }
.s3 .tb-gatechains .pro-chain { scale: 1 1; transition: scale 1.4s cubic-bezier(.6, 0, .2, 1) 2.2s; }
.s3 .tb-names span { animation: pro-forget 3s calc(3.2s + var(--i) * 230ms) both; }

/* IV. The escape: the deck leaps to the last hero, who runs and dims. */
.s4 .tb-names span { animation: none; opacity: 0; }
.s4 .tb-world { scale: 1.2; translate: 4% 2%; }
.s4 .tb-hero:not(.escaped) { filter: blur(.4cqh); opacity: .5; transition-delay: 0s; }
.s4 .tb-hero.escaped { left: 26%; top: 104%; scale: 2.9; z-index: 50; transition-delay: .6s; }
.s4 .tb-hero.escaped .full { opacity: 0; transition: opacity 2s ease 3.4s; }
.s4 .tb-hero.escaped .weak { opacity: 1; filter: saturate(.55) brightness(.85); transition: opacity 2s ease 3.4s; }
.s4 .tb-deck { left: 39%; top: 50%; z-index: 60; transition-delay: 0s, 0s, .2s, .2s; }
.s4 .tb-deck img { animation: pro-power 1.8s 3.8s both; }
.s4 .tb-vaelos { scale: 1.18; }
.s4 .tb-dim { opacity: .92; transition-delay: 0s; }

/* V. The Lantern Camp: everything else falls away. */
.s5 .tb-world { opacity: 0; filter: blur(1cqh); }
.s5 .tb-camp { opacity: 1; transition-delay: .6s; }
.s5 .tb-fallen { opacity: 1; rotate: -4deg; transition: opacity 2s 1.2s; }
.s5 .tb-campdeck { opacity: 1; transition: opacity 1.4s 3s; animation: pro-deckglow 2.4s 4s infinite; }
.s5 .tb-camp .pro-embers { opacity: 1; }

/* VI. Back to the threshold: an empty table, one deck, the name. */
.s6 .tb-camp { opacity: 0; transition-delay: 0s; }
.s6 .tb-world { opacity: 1; filter: none; scale: 1; translate: 0 0; transition: opacity 2s ease .4s, scale 6s ease, translate 6s ease; }
.s6 .tb-ring, .s6 .tb-vaelos, .s6 .tb-gatechains { opacity: 0; transition: none; }
.s6 .tb-dim { opacity: .3; }
.s6 .tb-deck { left: 50%; top: 79%; }
.s6 .tb-title { opacity: 1; transition: opacity 1s 1s; }
.s6 .tb-title .pro-titlecard * { animation-play-state: running; }

@media (prefers-reduced-motion: reduce) {
  .prologue *, .prologue *::before, .prologue *::after { animation-duration: .01s !important; animation-delay: 0s !important; transition-duration: .01s !important; transition-delay: 0s !important; }
}

/* ===========================================================================
   The first-hand coach (coach.ts): the hero talks the player through their
   first fight. Everything under it stays clickable; only the bubble is not.
   =========================================================================== */
.coach { position: fixed; inset: 0; z-index: 8800; pointer-events: none; }
.coach-hole { box-shadow: 0 0 0 200vmax rgba(4, 5, 16, .55); }
.coach.busy .coach-hole, .coach.busy .coach-bubble { opacity: 0; transition: opacity .2s; }
.coach-bubble {
  position: fixed; pointer-events: auto;
  display: grid; grid-template-columns: 96px minmax(0, 1fr); gap: 14px; align-items: end;
  padding: 14px 18px 14px 12px; border-radius: 20px;
  background: linear-gradient(180deg, #232650, #14163a); border: 2px solid #ffd36e;
  box-shadow: 0 22px 60px rgba(0, 0, 0, .8);
  transition: left .35s cubic-bezier(.3, .8, .3, 1), top .35s cubic-bezier(.3, .8, .3, 1), opacity .2s;
}
.coach-avatar {
  width: 96px; height: 96px; margin: -34px 0 -6px; border-radius: 18px;
  background: radial-gradient(circle at 50% 70%, rgba(255, 211, 110, .35), transparent 70%);
}
.coach-avatar img { width: 100%; height: 100%; object-fit: contain; object-position: bottom; filter: drop-shadow(0 6px 10px rgba(0, 0, 0, .6)); animation: coach-bob 3s ease-in-out infinite; }
@keyframes coach-bob { 50% { translate: 0 -3px; } }
.coach-name { font-size: 11px; font-weight: 800; letter-spacing: .18em; text-transform: uppercase; color: #ffd36e; }
.coach-words { margin: 4px 0 10px; font-size: 15px; line-height: 1.45; color: #eef0ff; }
.coach-words.in { animation: coach-in .35s ease-out both; }
@keyframes coach-in { from { opacity: 0; translate: 0 4px; } }
.coach-actions { display: flex; justify-content: space-between; align-items: center; gap: 10px; }
button.coach-skip { padding: 2px; background: none; border: 0; box-shadow: none; color: #aab0dd; font-size: 12.5px; font-weight: 500; text-decoration: underline; }
button.coach-next { min-width: 120px; padding: 8px 18px; background: linear-gradient(180deg, #ffe38a, #f4b63e); color: #3a2600; border: 0; box-shadow: 0 4px 0 #a8741c; }
.coach-wait { font-size: 12px; font-weight: 800; letter-spacing: .14em; text-transform: uppercase; color: #9ee7ff; animation: tour-glow-text 1.4s ease-in-out infinite; }
@keyframes tour-glow-text { 50% { opacity: .45; } }
/* The cards to pick: lifted a touch and ringed, without fighting the hand's own transforms. */
.hand-rail .coach-pick:not(.selected) { outline: 3px solid #ffd36e; outline-offset: 3px; border-radius: 10px; filter: drop-shadow(0 0 10px #ffd36e) drop-shadow(0 0 3px #fff3c4); animation: coach-pick 1.2s ease-in-out infinite; }
@keyframes coach-pick { 50% { filter: drop-shadow(0 0 18px #ffd36e) drop-shadow(0 0 4px #fff3c4); } }
@media (prefers-reduced-motion: reduce) { .coach-bubble, .coach-avatar img, .coach-pick { transition: none; animation: none; } }

/* ===========================================================================
   Card styles (card-style.ts). html[data-cards] picks the frame set,
   html[data-elemental] whether Elemental cards wear Flame or Lightning.
   Classic keeps every rule above untouched.
   =========================================================================== */
html[data-elemental="lightning"] .card.suit-H { --card-rgb: 70, 140, 235; }
html[data-elemental="lightning"] .suit-H .card-rank,
html[data-elemental="lightning"] .suit-H .card-art { color: #2f6fd6; }
/* Classic has no Lightning frame: its Elemental frame is recoloured. */
html[data-cards="classic"][data-elemental="lightning"] .suit-H .card-face { filter: hue-rotate(185deg) saturate(1.1); }

html[data-cards="royal"] .card.suit-C .card-face { background: url("./assets/cards/royal/frame-strength.webp") center / 100% 100% no-repeat; }
html[data-cards="royal"] .card.suit-S .card-face { background: url("./assets/cards/royal/frame-agility.webp") center / 100% 100% no-repeat; }
html[data-cards="royal"] .card.suit-D .card-face { background: url("./assets/cards/royal/frame-arcane.webp") center / 100% 100% no-repeat; }
html[data-cards="royal"][data-elemental="flame"] .card.suit-H .card-face { background: url("./assets/cards/royal/frame-flame.webp") center / 100% 100% no-repeat; }
html[data-cards="royal"][data-elemental="lightning"] .card.suit-H .card-face { background: url("./assets/cards/royal/frame-lightning.webp") center / 100% 100% no-repeat; }
html[data-cards="high"] .card.suit-C .card-face { background: url("./assets/cards/high/frame-strength.webp") center / 100% 100% no-repeat; }
html[data-cards="high"] .card.suit-S .card-face { background: url("./assets/cards/high/frame-agility.webp") center / 100% 100% no-repeat; }
html[data-cards="high"] .card.suit-D .card-face { background: url("./assets/cards/high/frame-arcane.webp") center / 100% 100% no-repeat; }
html[data-cards="high"][data-elemental="flame"] .card.suit-H .card-face { background: url("./assets/cards/high/frame-flame.webp") center / 100% 100% no-repeat; }
html[data-cards="high"][data-elemental="lightning"] .card.suit-H .card-face { background: url("./assets/cards/high/frame-lightning.webp") center / 100% 100% no-repeat; }

/* Lettering: Cinzel in the affinity colour, sat inside the frame's corner. */
html:not([data-cards="classic"]) .card-rank { font-family: "Cinzel", "Iowan Old Style", Georgia, serif; font-weight: 700; letter-spacing: -.02em; text-shadow: 0 1px 0 rgba(255, 255, 255, .55); }
html[data-cards="royal"] .card-corner.tl { top: 10%; left: 11%; }
html[data-cards="royal"] .card-corner.br { bottom: 10%; right: 11%; }
html[data-cards="high"] .card-corner.tl { top: 8.5%; left: 10%; }
html[data-cards="high"] .card-corner.br { bottom: 8.5%; right: 10%; }
/* The frames are already rich: the old affinity tint and inner highlight would muddy them. */
html:not([data-cards="classic"]) .card-face { box-shadow: none; }
html:not([data-cards="classic"]) .card { border-color: rgba(20, 14, 6, .7); }

/* Painted court characters, with the faint glow from the Card Lab behind them. */
.card-art.court.painted {
  inset: 13% 15% 10%;
  border-radius: 0; background: none; box-shadow: none;
}
.court-glow {
  position: absolute; left: 50%; top: 52%; width: 120%; aspect-ratio: 1; translate: -50% -50%;
  background: radial-gradient(closest-side, rgba(var(--card-rgb), .34), transparent);
  pointer-events: none;
}
.court-hero {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: contain; object-position: 50% 100%;
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, .28));
}
html[data-cards="high"] .card-art.court.painted { inset: 12% 13% 9%; }
.card.small .card-art.court.painted { inset: 15% 14% 9%; }
/* Pips sit a little further inside the heavier frames. */
html:not([data-cards="classic"]) .card-art.pip-field { inset: 21% 19% 20%; }
html:not([data-cards="classic"]) .card.small .card-art.pip-field { inset: 23% 20% 22%; }
html:not([data-cards="classic"]) .face-pip { width: 15cqw; }
/* Corner lettering scales with the card; the corner icon is big enough to read. */
html:not([data-cards="classic"]) .card .card-rank { font-size: 17cqw; }
html:not([data-cards="classic"]) .card .card-pip { width: 10cqw; height: 10cqw; }
/* The affinity strip takes the frame's own colour instead of a bright band of its own. */
html:not([data-cards="classic"]) .card .card-aff { background: linear-gradient(90deg, transparent, rgba(var(--card-rgb), .82) 25%, rgba(var(--card-rgb), .82) 75%, transparent); text-shadow: 0 1px 1px rgba(0, 0, 0, .5); }
/* The fight screen's card-style pill sits beside the layout pill. */
.card-style-pill .layout-pill-key { font-size: 14px; }


/* ===========================================================================
   Version 5 · The Chainbreaker: effects (fx.ts) and the story (story.ts)
   =========================================================================== */
.fx5-layer { position: fixed; inset: 0; z-index: 9500; pointer-events: none; overflow: hidden; }
.fx5-link {
  position: absolute; border-radius: 40%; border: 3px solid var(--c);
  box-shadow: 0 0 8px var(--c), inset 0 0 4px var(--c); background: transparent;
}
.fx5-ring {
  position: absolute; width: 20px; height: 20px; border-radius: 50%; translate: -50% -50%;
  border: 3px solid var(--c); box-shadow: 0 0 24px var(--c);
  animation: fx5-ring .6s ease-out forwards;
}
@keyframes fx5-ring { to { width: 260px; height: 260px; opacity: 0; border-width: 1px; } }
.fx5-ember { position: absolute; border-radius: 50%; background: var(--c); box-shadow: 0 0 8px var(--c), 0 0 2px #fff; }
.fx5-banner {
  position: absolute; left: 50%; top: 40%; translate: -50% -50%;
  display: grid; place-items: center; pointer-events: none;
  animation: fx5-banner 1.45s cubic-bezier(.2, 1.4, .4, 1) forwards;
}
.fx5-banner strong {
  position: relative; font: 900 clamp(34px, 6vw, 86px) / 1 "Cinzel", "Iowan Old Style", Georgia, serif; letter-spacing: .08em; white-space: nowrap;
  background: linear-gradient(180deg, #fff6d8 10%, var(--c) 55%, color-mix(in srgb, var(--c) 60%, #5a3000) 95%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
  filter: drop-shadow(0 4px 0 rgba(40, 20, 0, .7)) drop-shadow(0 0 28px color-mix(in srgb, var(--c) 70%, transparent));
}
.fx5-banner-rays {
  position: absolute; width: 140%; aspect-ratio: 3 / 1;
  background: radial-gradient(ellipse closest-side, color-mix(in srgb, var(--c) 45%, transparent), transparent),
    repeating-conic-gradient(from 0deg, color-mix(in srgb, var(--c) 35%, transparent) 0 4deg, transparent 4deg 14deg);
  -webkit-mask: radial-gradient(ellipse closest-side, #000 30%, transparent); mask: radial-gradient(ellipse closest-side, #000 30%, transparent);
}
.fx5-banner.p6 strong, .fx5-banner.p7 strong, .fx5-banner.p8 strong, .fx5-banner.p9 strong { font-size: clamp(40px, 7.4vw, 104px); }
@keyframes fx5-banner {
  0% { opacity: 0; scale: 2.2; filter: blur(8px); }
  18% { opacity: 1; scale: .94; filter: blur(0); }
  28% { scale: 1.03; }
  75% { opacity: 1; scale: 1; }
  100% { opacity: 0; scale: 1.08; translate: -50% -62%; }
}
.fx5-ambient { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 0; }

/* --- Story scenes ---------------------------------------------------------- */
.story5 {
  position: fixed; inset: 0; z-index: 9200; overflow: hidden; cursor: pointer;
  background: #04030a; color: #f4ead2; --st: #ffd36e;
  animation: st-in .38s ease-out both;
}
.story5.closing { animation: st-out .5s ease-in both; }
@keyframes st-in { from { opacity: 0; } }
@keyframes st-out { to { opacity: 0; filter: blur(6px); } }
.story5 > * { position: absolute; }
.story5 .st-bg { inset: 0; width: 100%; height: 100%; object-fit: cover; animation: st-push 4.6s ease-out both; }
@keyframes st-push { from { scale: 1.16; } to { scale: 1.02; } }
.story5 .st-shade { inset: 0; background: linear-gradient(90deg, rgba(4, 3, 10, .94) 0%, rgba(4, 3, 10, .72) 45%, rgba(4, 3, 10, .3) 100%), radial-gradient(ellipse at 70% 50%, color-mix(in srgb, var(--st) 22%, transparent), transparent 60%); }
.story5 .st-copy { left: 7%; top: 50%; translate: 0 -50%; width: min(620px, 52%); display: grid; gap: 14px; }
.story5 .st-kicker { font: 800 clamp(11px, 1.1vw, 14px) / 1 var(--font); letter-spacing: .32em; color: var(--st); animation: st-rise .8s .15s both; }
.story5 .st-title {
  margin: 0; font: 900 clamp(38px, 5.6vw, 84px) / .98 "Cinzel", "Iowan Old Style", Georgia, serif; letter-spacing: .02em;
  background: linear-gradient(180deg, #fff6dc 15%, color-mix(in srgb, var(--st) 70%, #ffd36e) 60%, color-mix(in srgb, var(--st) 50%, #4a2a00) 100%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
  filter: drop-shadow(0 3px 0 rgba(0, 0, 0, .6)) drop-shadow(0 0 30px color-mix(in srgb, var(--st) 40%, transparent));
  animation: st-title 1.1s .25s cubic-bezier(.2, .8, .2, 1) both;
}
@keyframes st-title { from { opacity: 0; letter-spacing: .3em; filter: blur(10px); } }
@keyframes st-rise { from { opacity: 0; translate: 0 14px; } }
.story5 .st-rule { width: 180px; height: 2px; background: linear-gradient(90deg, var(--st), transparent); animation: st-rule .9s .6s both; transform-origin: left; }
@keyframes st-rule { from { scale: 0 1; } }
.story5 .st-line, .story5 .st-taunt { margin: 0; font: italic clamp(16px, 1.7vw, 23px) / 1.45 "Iowan Old Style", "Palatino Linotype", Georgia, serif; color: #efe3c8; text-shadow: 0 2px 10px #000; }
.story5 .st-line span, .story5 .st-taunt span { display: inline-block; white-space: pre; animation: pro-word .8s calc(var(--d) + var(--w) * 70ms) both; }
.story5 .st-foot { display: flex; gap: 10px; align-items: baseline; font-size: 13px; color: rgba(244, 234, 210, .7); letter-spacing: .14em; text-transform: uppercase; animation: st-rise .8s 2s both; }
.story5 .st-foot strong { color: var(--st); letter-spacing: .06em; font-size: 15px; }
.story5 .st-skip { right: 22px; bottom: 16px; font-size: 11px; letter-spacing: .2em; text-transform: uppercase; color: rgba(255, 255, 255, .35); animation: st-rise 1s 1.5s both; }
/* The Warden's silhouette looms behind the chapter title. */
.story5.chapter .st-warden {
  right: 4%; bottom: -4%; height: 92%; max-width: 50%; object-fit: contain;
  filter: brightness(0) drop-shadow(0 0 18px color-mix(in srgb, var(--st) 80%, transparent)) drop-shadow(0 0 60px color-mix(in srgb, var(--st) 40%, transparent));
  opacity: .9; animation: st-loom 4s ease-out both;
}
@keyframes st-loom { from { opacity: 0; translate: 6% 4%; scale: .92; } }
.story5.chapter .st-chains { left: -5%; right: -5%; bottom: 13%; height: 60px; }
.story5.chapter .st-chains .pro-chain { left: 0; width: 100%; height: 22px; background-size: 36px 100%; scale: 1 1; animation: st-chain 1s .2s cubic-bezier(.6, 0, .2, 1) both; }
.story5.chapter .st-chains .c1 { top: 0; rotate: -2deg; }
.story5.chapter .st-chains .c2 { top: 30px; rotate: 1.5deg; animation-delay: .4s; }
@keyframes st-chain { from { scale: 0 1; } }
.story5 .st-chains.broken .pro-chain, .story5.freed.broken .st-hero-chains .pro-chain { opacity: 0; transition: opacity .15s; }
/* The Warden rises out of its gate. */
.story5.warden .st-shade { background: linear-gradient(270deg, rgba(4, 3, 10, .95) 0%, rgba(4, 3, 10, .7) 42%, rgba(30, 0, 10, .25) 100%), radial-gradient(ellipse at 30% 60%, color-mix(in srgb, var(--st) 35%, transparent), transparent 55%); }
.story5.warden .st-boss {
  left: 3%; bottom: -6%; height: 104%; max-width: 56%; object-fit: contain;
  filter: drop-shadow(0 0 30px color-mix(in srgb, var(--st) 70%, transparent)) drop-shadow(0 20px 40px #000);
  animation: st-boss 1.4s cubic-bezier(.15, .9, .25, 1.05) both;
}
@keyframes st-boss { from { translate: 0 30%; filter: brightness(0) drop-shadow(0 0 30px var(--st)); opacity: 0; } 55% { opacity: 1; } }
.story5.warden .st-copy { left: auto; right: 6%; text-align: right; justify-items: end; }
.story5.warden .st-title { background: none; color: #fff2d9; -webkit-text-fill-color: currentColor; }
.story5.warden .st-title .st-word { display: inline-block; white-space: nowrap; margin-left: .28em; }
.story5.warden .st-title .st-word:first-child { margin-left: 0; }
.story5.warden .st-title .st-word span { display: inline-block; animation: st-letter .5s calc(.35s + var(--i) * 35ms) cubic-bezier(.2, 1.6, .4, 1) both; text-shadow: 0 0 22px color-mix(in srgb, var(--st) 70%, transparent), 0 3px 0 #000; }
@keyframes st-letter { from { opacity: 0; translate: 0 -40px; scale: 1.6; } }
.story5.warden .st-rule-text { margin: 0; font-size: 14px; color: rgba(244, 234, 210, .75); max-width: 420px; animation: st-rise .8s 1s both; }
.story5.warden .st-taunt { color: color-mix(in srgb, var(--st) 40%, #fff); max-width: 520px; }
/* A hero walks free. */
.story5.freed { cursor: default; background: radial-gradient(ellipse at 50% 45%, #2a1c4a, #06040e 70%); }
.story5.freed .st-rays { inset: -20%; background: repeating-conic-gradient(from 0deg at 38% 50%, rgba(255, 196, 110, .08) 0 5deg, transparent 5deg 15deg); -webkit-mask: radial-gradient(circle at 38% 50%, #000 10%, transparent 60%); mask: radial-gradient(circle at 38% 50%, #000 10%, transparent 60%); opacity: 0; transition: opacity 1.2s; }
.story5.freed.broken .st-rays { opacity: 1; }
.story5.freed .st-hero { left: 34%; top: 50%; translate: -50% -50%; width: min(46vh, 40vw); aspect-ratio: 1; }
.story5.freed .st-hero > img { width: 100%; height: 100%; object-fit: contain; filter: brightness(0) drop-shadow(0 0 16px #a77bff); transition: filter 1.2s ease; }
.story5.freed.broken .st-hero > img { filter: brightness(1) drop-shadow(0 0 30px rgba(255, 214, 140, .8)); }
.story5.freed .st-hero-chains { position: absolute; inset: 15% 0; }
.story5.freed .st-hero-chains .pro-chain { left: -10%; width: 120%; height: 18px; background-size: 30px 100%; scale: 1 1; }
.story5.freed .st-hero-chains .h1 { top: 25%; rotate: 24deg; }
.story5.freed .st-hero-chains .h2 { top: 55%; rotate: -20deg; }
.story5.freed .st-hero-chains .h3 { top: 75%; rotate: 8deg; }
.story5.freed .st-copy { left: 56%; width: min(520px, 38%); }
.story5.freed .st-copy > * { animation: st-rise .8s both; }
.story5.freed .st-copy > :nth-child(2) { animation-delay: 1.3s; }
.story5.freed .st-copy > :nth-child(n+3) { animation-delay: 1.7s; }
.story5.freed .st-hand { margin: 0; font: italic 22px/1.4 "Iowan Old Style", Georgia, serif; color: #ffe7b0; }
.story5.freed .st-power { margin: 0; font-size: 14px; color: rgba(244, 234, 210, .8); }
.story5.freed .st-line-small { margin: 0; font-size: 13px; letter-spacing: .04em; color: rgba(244, 234, 210, .6); }
.story5.freed .st-continue { justify-self: start; min-width: 160px; }

/* --- The end of a run ------------------------------------------------------ */
.st-end { position: relative; z-index: 1; max-width: 560px; margin: 4px auto 14px; padding: 14px 20px; border-radius: 14px; text-align: center; background: rgba(8, 6, 20, .6); border: 1px solid rgba(255, 211, 110, .2); }
.st-end p { margin: 6px 0 0; font: italic 17px/1.45 "Iowan Old Style", Georgia, serif; color: #f1e5c9; }
.st-end .st-end-sub { font-size: 14px; color: rgba(241, 229, 201, .7); }
.st-end-kicker { font-size: 11px; font-weight: 800; letter-spacing: .26em; color: var(--gold); }
.st-end.loss { border-color: rgba(176, 124, 255, .3); }
.st-end.loss .st-end-kicker { color: #c9a6ff; }
.screen.over { position: relative; }
.screen.over > *:not(.fx5-ambient) { position: relative; z-index: 1; }

/* --- The Chronicle --------------------------------------------------------- */
.chronicle-overlay { z-index: 820; }
.overlay-card.chronicle {
  width: min(1040px, 94vw); max-width: none; height: min(660px, 90vh); max-height: none; padding: 0; overflow: hidden;
  display: grid; grid-template-rows: auto minmax(0, 1fr); position: relative; z-index: 1;
  background: linear-gradient(180deg, #1c1630, #110d1f); border: 1px solid rgba(255, 211, 110, .3);
}
.chron-head { display: flex; justify-content: space-between; align-items: center; padding: 16px 22px; border-bottom: 1px solid rgba(255, 211, 110, .15); }
.chron-head h2 { margin: 2px 0 0; font: 900 28px/1 "Cinzel", Georgia, serif; color: #fff1cf; }
.chron-kicker { font-size: 11px; font-weight: 800; letter-spacing: .26em; color: var(--gold); }
.chron-body { display: grid; grid-template-columns: 260px minmax(0, 1fr); min-height: 0; }
.chron-nav { overflow-y: auto; padding: 10px; border-right: 1px solid rgba(255, 211, 110, .12); display: grid; gap: 3px; align-content: start; }
button.chron-nav-item { justify-content: flex-start; text-align: left; padding: 8px 12px; background: transparent; border: 1px solid transparent; box-shadow: none; border-radius: 10px; }
button.chron-nav-item.active { background: rgba(255, 211, 110, .1); border-color: rgba(255, 211, 110, .45); }
button.chron-nav-item.locked { opacity: .45; }
.chron-nav-copy { display: grid; gap: 1px; }
.chron-nav-copy small { font-size: 10px; letter-spacing: .2em; color: var(--ink-faint); }
.chron-nav-copy strong { font-size: 15px; }
.chron-page {
  overflow-y: auto; padding: 26px 34px; color: #eee3c9;
  background: radial-gradient(ellipse at 50% 0%, rgba(255, 211, 110, .06), transparent 60%);
}
.chron-page.turn { animation: chron-turn .45s ease-out both; }
@keyframes chron-turn { from { opacity: 0; translate: 18px 0; } }
.chron-title { margin: 6px 0 14px; font: 900 34px/1.05 "Cinzel", Georgia, serif; color: #fff1cf; }
.chron-page p { font: 17px/1.6 "Iowan Old Style", "Palatino Linotype", Georgia, serif; max-width: 62ch; }
.chron-page .chron-epigraph { font-style: italic; font-size: 19px; }
.chron-meta { display: flex; gap: 10px; align-items: baseline; font-family: var(--font) !important; font-size: 13px !important; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-dim); }
.chron-meta strong { color: var(--gold); letter-spacing: .04em; }
.chron-fall { color: #ffe7b0; }
.chron-pending, .chron-locked { color: var(--ink-dim); font-style: italic; }
.chron-warden { float: right; width: 220px; max-height: 260px; object-fit: contain; margin: 0 0 12px 18px; filter: drop-shadow(0 10px 20px rgba(0, 0, 0, .6)); }
.chron-warden.unseen { filter: brightness(0) drop-shadow(0 0 12px #a77bff); opacity: .8; }
.chron-heroes { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; margin-top: 14px; }
.chron-hero { display: grid; justify-items: center; gap: 4px; padding: 10px; border-radius: 12px; background: rgba(255, 255, 255, .04); border: 1px solid rgba(255, 255, 255, .08); text-align: center; }
.chron-hero img { width: 90px; height: 90px; object-fit: contain; }
.chron-hero.bound img { filter: brightness(0) drop-shadow(0 0 8px #a77bff); opacity: .7; }
.chron-hero strong { font-size: 14px; }
.chron-hero small { font-size: 12px; color: var(--ink-dim); line-height: 1.35; }
.chron-quote { margin: 18px 0; padding: 18px 24px; border-left: 3px solid var(--gold); font: italic 24px/1.4 "Iowan Old Style", Georgia, serif; color: #ffe7b0; }

/* Center Stage's score tower is narrow: the resolution steps sit two to a row
   (no arrows) and the tower never grows past the altar's row. */
html.landscape-stage .combat.layout-stage .scoreboard { max-height: 100%; overflow: hidden; }
html.landscape-stage .combat.layout-stage .resolution-ribbon { display: grid; grid-template-columns: 1fr 1fr; gap: 3px; padding: 2px 0; justify-content: stretch; }
html.landscape-stage .combat.layout-stage .resolution-arrow { display: none; }
html.landscape-stage .combat.layout-stage .resolution-step { min-height: 0; padding: 2px 6px; gap: 4px; justify-content: space-between; min-width: 0; }
html.landscape-stage .combat.layout-stage .resolution-step .resolution-value { overflow: hidden; text-overflow: ellipsis; }
html.landscape-stage .combat.layout-stage .resolution-step.total { grid-column: 1 / -1; }

/* ===========================================================================
   Version 6 · The Hearthsong: the Music Room (music.ts)
   =========================================================================== */
.music-room-overlay { z-index: 830; }
.overlay-card.music-room {
  width: min(1080px, 94vw); max-width: none; max-height: 92vh; padding: 0; overflow: auto;
  display: grid; grid-template-rows: auto auto 1fr auto;
  background: linear-gradient(180deg, #1a1630, #0f0c1d); border: 1px solid rgba(255, 211, 110, .3);
}
.mr-head { display: flex; justify-content: space-between; align-items: center; padding: 16px 22px 10px; }
.mr-head h2 { margin: 2px 0 0; font: 900 28px/1 "Cinzel", Georgia, serif; color: #fff1cf; }
.mr-kicker { font-size: 11px; font-weight: 800; letter-spacing: .26em; color: var(--gold); }
.mr-now {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(160px, 320px) auto; align-items: center; gap: 16px;
  margin: 0 22px; padding: 12px 16px; border-radius: 14px; background: rgba(0, 0, 0, .3); border: 1px solid rgba(255, 255, 255, .08);
}
.mr-now-copy { display: grid; gap: 2px; min-width: 0; }
.mr-now-copy small { font-size: 10px; letter-spacing: .24em; color: var(--ink-faint); }
.mr-now-copy strong { font-size: 18px; color: #fff1cf; }
.mr-now-copy span { font-size: 12px; color: var(--ink-dim); }
.mr-viz { width: 100%; height: 46px; }
.mr-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 12px; padding: 16px 22px; }
.mr-track {
  --mr: #ffd36e;
  display: flex; flex-direction: column; gap: 8px; padding: 14px; border-radius: 14px;
  background: linear-gradient(180deg, color-mix(in srgb, var(--mr) 10%, rgba(20, 16, 40, .9)), rgba(12, 10, 24, .92));
  border: 1px solid color-mix(in srgb, var(--mr) 30%, transparent);
}
.mr-track.chosen { border-color: var(--mr); box-shadow: 0 0 0 1px var(--mr), 0 0 24px color-mix(in srgb, var(--mr) 30%, transparent); }
.mr-track.silence { --mr: #8890b8; }
.mr-track-head { display: flex; justify-content: space-between; align-items: center; }
.mr-track-head strong { font: 800 18px/1.1 "Cinzel", Georgia, serif; color: color-mix(in srgb, var(--mr) 55%, #fff); }
.mr-badge { font-size: 9px; font-weight: 900; letter-spacing: .18em; padding: 3px 7px; border-radius: 999px; background: var(--mr); color: #1a1205; }
.mr-track p { margin: 0; font-size: 12.5px; line-height: 1.4; color: var(--ink-dim); }
.mr-moods { display: grid; grid-template-columns: 1fr 1fr; gap: 5px; }
button.mr-mood { min-height: 0; padding: 6px 8px; font-size: 12px; justify-content: flex-start; background: rgba(255, 255, 255, .05); border: 1px solid rgba(255, 255, 255, .1); box-shadow: none; }
button.mr-mood.on { background: color-mix(in srgb, var(--mr) 28%, transparent); border-color: var(--mr); color: #fff; }
.mr-track > button.primary, .mr-track > button.ghost, .mr-chosen-note { margin-top: auto; }
.mr-chosen-note { font-size: 12px; color: color-mix(in srgb, var(--mr) 60%, #fff); text-align: center; padding: 6px; }
.mr-foot { margin: 0; padding: 0 22px 16px; font-size: 12px; color: var(--ink-faint); }

/* ===========================================================================
   Version 6: characters and Wardens that move
   =========================================================================== */
/* Foes breathe instead of bobbing: a slow squash-and-stretch from the feet. */
.enemy-art.enemy-portrait { transform-origin: 50% 92%; animation: foeBreathe 3.2s ease-in-out infinite; }
.enemy-row.tier-elite .enemy-art.enemy-portrait { animation-duration: 3.8s; }
.enemy.boss .enemy-art.enemy-portrait { animation: wardenBreathe 4.6s ease-in-out infinite; }
@keyframes foeBreathe {
  0%, 100% { transform: translateY(0) scale(1, 1) rotate(-1deg); }
  45% { transform: translateY(-4px) scale(.985, 1.035) rotate(1deg); }
  60% { transform: translateY(-5px) scale(.99, 1.04) rotate(1deg); }
}
@keyframes wardenBreathe {
  0%, 100% { transform: translateY(0) scale(1, 1); filter: drop-shadow(0 0 0 rgba(255, 120, 80, 0)); }
  40% { transform: translateY(-6px) scale(1.015, 1.05); filter: drop-shadow(0 0 14px rgba(255, 140, 90, .55)); }
  55% { transform: translateY(-6px) scale(1.02, 1.05); filter: drop-shadow(0 0 18px rgba(255, 140, 90, .6)); }
}
/* A Warden's presence: a slow pulse of light behind it. */
.enemy.boss { isolation: isolate; }
.enemy.boss::after {
  content: ""; position: absolute; left: 50%; top: 42%; width: 120%; aspect-ratio: 1; translate: -50% -50%; z-index: -1;
  background: radial-gradient(closest-side, rgba(255, 130, 80, .28), rgba(160, 80, 255, .12) 55%, transparent);
  animation: wardenAura 4.6s ease-in-out infinite; pointer-events: none;
}
@keyframes wardenAura { 0%, 100% { opacity: .55; scale: .92; } 50% { opacity: 1; scale: 1.06; } }
/* Badly hurt: trembling, reddening. */
.enemy.wounded .enemy-art.enemy-portrait { animation: foeWounded .9s ease-in-out infinite; }
@keyframes foeWounded {
  0%, 100% { transform: translate(0, 0); filter: sepia(.3) saturate(1.6) hue-rotate(-20deg); }
  25% { transform: translate(-1.5px, 1px); }
  50% { transform: translate(1.5px, 0); filter: sepia(.5) saturate(2) hue-rotate(-25deg) brightness(.92); }
  75% { transform: translate(-1px, -1px); }
}
.enemy.boss.wounded::after { animation-duration: 1.4s; background: radial-gradient(closest-side, rgba(255, 60, 60, .38), rgba(160, 40, 80, .14) 55%, transparent); }

/* Your hero breathes too (it only bobbed). */
.hero-rig-art { transform-origin: 50% 95%; animation: heroBreathe 3.6s ease-in-out infinite; }
@keyframes heroBreathe { 0%, 100% { scale: 1 1; } 50% { scale: .99 1.025; } }

/* Court characters step forward on a hovered card. */
.court-hero { transition: scale .25s cubic-bezier(.2, 1.4, .4, 1), translate .25s ease, filter .25s; transform-origin: 50% 100%; }
.card.clickable:hover .court-hero, .card.selected .court-hero { scale: 1.07; translate: 0 -3%; filter: drop-shadow(0 4px 6px rgba(0, 0, 0, .35)) drop-shadow(0 0 8px rgba(var(--card-rgb), .55)); }
.card.clickable:hover .court-glow, .card.selected .court-glow { background: radial-gradient(closest-side, rgba(var(--card-rgb), .55), transparent); }

@media (prefers-reduced-motion: reduce) {
  .enemy-art.enemy-portrait, .enemy.boss::after, .hero-rig-art, .enemy.wounded .enemy-art.enemy-portrait { animation: none; }
}

/* ===========================================================================
   Version 6: the Daily Chest (daily.ts), from the dailies chest art
   =========================================================================== */
button.daily-chest {
  position: absolute; top: 16px; left: 22px; z-index: 3;
  padding: 6px 14px 6px 6px; border-radius: 16px; min-height: 0;
  background: linear-gradient(180deg, rgba(40, 30, 64, .85), rgba(16, 12, 30, .9)); border: 1px solid rgba(255, 211, 110, .25);
  box-shadow: 0 8px 22px rgba(0, 0, 0, .45);
}
.dc-wrap { display: flex; align-items: center; gap: 10px; }
.dc-art { width: 54px; height: 54px; object-fit: contain; filter: drop-shadow(0 4px 6px rgba(0, 0, 0, .5)); }
.dc-copy { display: grid; text-align: left; line-height: 1.15; }
.dc-copy small { font-size: 9px; font-weight: 900; letter-spacing: .2em; color: var(--gold); }
.dc-copy strong { font-size: 15px; color: #fff1cf; }
.dc-copy span { font-size: 11px; color: var(--ink-dim); }
button.daily-chest:not(.ready) { opacity: .75; }
button.daily-chest:not(.ready) .dc-art { filter: grayscale(.6) brightness(.8); }
button.daily-chest.ready { border-color: rgba(255, 211, 110, .7); animation: dcCall 2.4s ease-in-out infinite; }
button.daily-chest.ready .dc-art { animation: dcBounce 2.4s ease-in-out infinite; }
button.daily-chest.ready .dc-copy span { color: #ffe08a; font-weight: 700; }
@keyframes dcCall { 0%, 100% { box-shadow: 0 8px 22px rgba(0, 0, 0, .45), 0 0 0 rgba(255, 211, 110, 0); } 50% { box-shadow: 0 8px 22px rgba(0, 0, 0, .45), 0 0 22px rgba(255, 211, 110, .45); } }
@keyframes dcBounce { 0%, 70%, 100% { transform: translateY(0) rotate(0); } 78% { transform: translateY(-5px) rotate(-5deg); } 86% { transform: translateY(0) rotate(4deg); } 92% { transform: translateY(-2px) rotate(-2deg); } }

.daily-open {
  position: fixed; inset: 0; z-index: 9300; display: grid; grid-template-columns: 1fr 1fr; align-items: center; gap: 3vw; padding: 0 6vw;
  background: radial-gradient(ellipse at 32% 50%, #2c1f4a, #07050f 72%); color: #f4ead2; overflow: hidden;
  animation: st-in .35s ease-out both;
}
.daily-open.closing { animation: st-out .4s ease-in both; }
.daily-open > * { position: relative; z-index: 1; }
.dc-rays { position: absolute !important; inset: -30%; z-index: 0 !important; background: repeating-conic-gradient(from 0deg at 41% 50%, rgba(255, 210, 120, .1) 0 5deg, transparent 5deg 14deg); -webkit-mask: radial-gradient(circle at 41% 50%, #000 8%, transparent 50%); mask: radial-gradient(circle at 41% 50%, #000 8%, transparent 50%); opacity: 0; transition: opacity 1s; }
.daily-open.open .dc-rays { opacity: 1; animation: dcSpin 40s linear infinite; }
@keyframes dcSpin { to { rotate: 360deg; } }
.dc-chest { justify-self: end; width: min(44vh, 34vw); aspect-ratio: 1; display: grid; place-items: center; }
.dc-big { width: 100%; height: 100%; object-fit: contain; filter: drop-shadow(0 18px 30px rgba(0, 0, 0, .6)); transition: filter .6s, scale .6s cubic-bezier(.2, 1.6, .4, 1); }
.daily-open.open .dc-big { scale: 1.08; filter: drop-shadow(0 0 40px rgba(255, 214, 140, .8)) brightness(1.15); }
.dc-glow { position: absolute; inset: 10%; border-radius: 50%; background: radial-gradient(closest-side, rgba(255, 220, 150, .7), transparent); opacity: 0; transition: opacity .5s; }
.daily-open.open .dc-glow { opacity: 1; }
.dc-reveal { display: grid; gap: 12px; max-width: 460px; opacity: 0; translate: 0 14px; transition: opacity .6s .2s, translate .6s .2s; }
.daily-open.open .dc-reveal { opacity: 1; translate: 0 0; }
.dc-kicker { font-size: 12px; font-weight: 900; letter-spacing: .26em; color: var(--gold); }
.dc-title { margin: 0; font: 900 clamp(40px, 5vw, 64px)/1 "Cinzel", Georgia, serif; background: linear-gradient(180deg, #fff6d8, #ffd36e 55%, #b07020); -webkit-background-clip: text; background-clip: text; color: transparent; }
.dc-reveal p { margin: 0; font-size: 14px; line-height: 1.5; color: rgba(244, 234, 210, .8); }
.dc-ladder { display: flex; gap: 8px; margin-top: 6px; }
.dc-step { display: grid; justify-items: center; gap: 2px; padding: 6px; border-radius: 10px; background: rgba(255, 255, 255, .04); border: 1px solid rgba(255, 255, 255, .08); }
.dc-step img { width: 46px; height: 46px; object-fit: contain; }
.dc-step:not(.now) img { filter: grayscale(.4) brightness(.75); }
.dc-step.now { border-color: rgba(255, 211, 110, .6); background: rgba(255, 211, 110, .1); }
.dc-step small { font-size: 10px; color: var(--ink-dim); }
.dc-done { justify-self: start; min-width: 160px; }
.daily-open > .fx5-ambient, .story5 > .fx5-ambient { position: absolute; inset: 0; z-index: 0; grid-area: 1 / 1 / -1 / -1; }

/* Short screens (phones turned sideways): the overlays drawn outside the
   scaled stage tighten up instead of scrolling a few big rows. */
@media (max-height: 520px) {
  .chron-head, .mr-head { padding: 8px 14px; }
  .chron-head h2, .mr-head h2 { font-size: 20px; }
  .chron-body { grid-template-columns: 190px minmax(0, 1fr); }
  button.chron-nav-item { padding: 5px 9px; }
  .chron-nav-copy strong { font-size: 13px; }
  .chron-page { padding: 14px 18px; }
  .chron-title { font-size: 22px; margin: 2px 0 8px; }
  .chron-page p { font-size: 14px; line-height: 1.5; }
  .chron-page .chron-epigraph { font-size: 15px; }
  .chron-warden { width: 130px; max-height: 150px; }
  .mr-now { margin: 0 14px; padding: 6px 10px; }
  .mr-now-copy strong { font-size: 14px; }
  .mr-viz { height: 30px; }
  .mr-grid { padding: 10px 14px; gap: 8px; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); }
  .mr-track { padding: 10px; gap: 6px; }
  .mr-track p { display: none; }
  button.mr-mood { padding: 4px 6px; font-size: 11px; }
  .story5 .st-title { font-size: clamp(28px, 5vw, 44px); }
  .story5 .st-line, .story5 .st-taunt { font-size: 14px; }
  .story5 .st-copy { gap: 8px; }
  .daily-open { gap: 2vw; padding: 0 4vw; }
  .dc-title { font-size: 34px; }
  .dc-reveal { gap: 8px; }
  .dc-reveal p { font-size: 12px; }
  .dc-step img { width: 32px; height: 32px; }
  button.daily-chest { top: 8px; left: 12px; padding: 4px 10px 4px 4px; }
  .dc-art { width: 38px; height: 38px; }
}

/* --- The map, version 6 (also patched into version 5) --------------------
   Calm and readable: the room panel is always docked, so the board never
   slides under the pointer; hover lights a room up without moving it; the
   current room wears a "You are here" flag; open roads glow and say Next;
   and a bar across the top says what to do. */
.map-node { transition: box-shadow .16s ease, border-color .16s ease, background-color .16s ease, opacity .25s, filter .25s; }
.map-node:hover { scale: none; z-index: 3; }
.map-node:not(:disabled):hover { background-color: rgba(30, 36, 78, .97); border-color: color-mix(in srgb, var(--tone) 80%, #fff); }
.map-node.st-available:hover, .map-node.st-available.hint { box-shadow: 0 0 0 2px var(--tone), 0 0 30px color-mix(in srgb, var(--tone) 70%, transparent), var(--shadow-1); animation: none; }
.map-node.st-available { animation-duration: 2.8s; }
.map-node.st-current { border-color: var(--gold); border-width: 2px; background-color: rgba(42, 34, 16, .96); box-shadow: 0 0 0 3px rgba(255,211,110,.28), 0 0 30px rgba(255,211,110,.5); opacity: 1; z-index: 2; }
.map-node.st-visited { opacity: .5; }
.map-node.st-ahead, .map-node.st-blocked { opacity: .62; }
.map-node.selected { outline: 2px solid rgba(255,255,255,.9); outline-offset: 4px; z-index: 4; }
.map-node .map-node-go {
  position: absolute; bottom: 0; left: 50%; translate: -50% 55%; padding: 2px 9px; border-radius: 99px;
  background: var(--tone); color: #1a1206; font-size: max(8px, calc(var(--u) * .78)); font-weight: 900; letter-spacing: .14em; text-transform: uppercase;
  box-shadow: 0 2px 10px rgba(0,0,0,.5); pointer-events: none;
}
.expedition-party {
  width: auto; height: auto; padding: 3px 10px; border-radius: 99px; white-space: nowrap;
  translate: -50% calc(var(--u) * -4.9 - 50%); pointer-events: none; z-index: 6;
  font-size: max(9px, calc(var(--u) * .8)); font-weight: 900; letter-spacing: .1em; text-transform: uppercase;
  box-shadow: 0 0 0 2px rgba(255,211,110,.3), 0 0 16px rgba(255,211,110,.7);
  animation: none;
}
.expedition-party.walking { animation: party-bob .4s ease-in-out infinite; }
/* The panel never closes now, so the board stays where it is. */
html.landscape-stage .expedition-canvas { transition: none; }
.map-pop.open { animation: none; }
.map-pop-close { display: none; }
.insp-here { color: var(--gold); border-color: rgba(255,211,110,.35); }

.exp-next {
  position: absolute; top: 10px; left: 12px; right: 12px; z-index: 7;
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  pointer-events: none;
}
.exp-next-say {
  padding: 6px 12px; border-radius: 99px; background: rgba(8, 10, 26, .88); border: 1px solid rgba(255,211,110,.35);
  color: var(--gold); font-weight: 800; font-size: 13px; letter-spacing: .02em;
}
.exp-next-road {
  pointer-events: auto; display: inline-flex; align-items: center; padding: 5px 12px; border-radius: 99px; cursor: pointer;
  border: 1px solid #9ff3ff; background: rgba(12, 40, 56, .9); color: var(--ink); font: inherit; font-weight: 800; font-size: 13px;
  transition: background-color .15s, box-shadow .15s;
}
.exp-next-road span { display: inline-flex; align-items: baseline; gap: 6px; }
.exp-next-road small { font-size: 9.5px; letter-spacing: .14em; text-transform: uppercase; color: #9ff3ff; }
.exp-next-road:hover { background: rgba(24, 70, 92, .95); box-shadow: 0 0 14px rgba(126,230,255,.5); }
.exp-next-road.kind-fight { border-color: #ffb36b; background: rgba(60, 30, 10, .92); }

/* Tours on a phone turned sideways: a smaller card, so the thing it points at
   stays in view. Overlays live on <body> and are not scaled with the stage. */
@media (max-height: 520px) {
  .tour-card { padding: 9px 12px 8px; border-radius: 14px; max-width: min(300px, 46vw); }
  .tour-card h3 { font-size: 16px; margin: 2px 0 4px; }
  .tour-card p { font-size: 12px; line-height: 1.35; margin-bottom: 7px; }
  button.tour-next { min-width: 84px; padding: 6px 12px; box-shadow: 0 3px 0 #a8741c; }
  button.tour-back { padding: 6px 12px; }
  .tour-dots { margin-top: 6px; }
}
