/* Darkpool battle stage (M20) — cinematic 8-phase round playback.
 * Layout: ambient grid floor + 3-column arena (side / central matchup / side)
 *         + accumulating combat log + fixed bottom bar.
 */

/* ============== STAGE SHELL ============== */
body.stage-page { padding: 0; margin: 0; max-width: none; }

.stage {
  position: relative;
  min-height: 100vh;
  padding: 14px 22px 100px;
  display: grid;
  grid-template-rows: auto auto 1fr auto;
  gap: 14px;
}
.stage > * { position: relative; z-index: 2; }
.stage > .grid-floor,
.stage > .glitch-overlay { z-index: 0; }
.stage--xfade { filter: hue-rotate(40deg) saturate(1.4); }
.stage.shake { animation: stage-shake 320ms cubic-bezier(.36,.07,.19,.97) both; }

@keyframes stage-shake {
  10%, 90% { transform: translate3d(-1px, 0, 0); }
  20%, 80% { transform: translate3d(2px, 0, 0); }
  30%, 50%, 70% { transform: translate3d(-3px, 0, 0); }
  40%, 60% { transform: translate3d(3px, 0, 0); }
}

/* ============== Grid floor (perspective horizon) ============== */
.grid-floor {
  position: fixed; inset: 0; pointer-events: none; z-index: 0;
  overflow: hidden;
}
.grid-floor__inner {
  position: absolute;
  left: -50%; right: -50%;
  bottom: -8%;
  height: 60%;
  background:
    linear-gradient(rgba(92,242,255,0.09) 1px, transparent 1px) 0 0/40px 40px,
    linear-gradient(90deg, rgba(255,79,216,0.09) 1px, transparent 1px) 0 0/40px 40px;
  transform: perspective(420px) rotateX(62deg);
  transform-origin: 50% 0%;
  -webkit-mask-image: linear-gradient(to top, rgba(0,0,0,1) 0%, rgba(0,0,0,0) 90%);
          mask-image: linear-gradient(to top, rgba(0,0,0,1) 0%, rgba(0,0,0,0) 90%);
}
.grid-floor__horizon {
  position: absolute;
  left: 0; right: 0;
  bottom: 38%;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--magenta) 30%, var(--cyan) 70%, transparent);
  filter: blur(0.5px);
  box-shadow: 0 0 18px var(--cyan-glow), 0 0 32px var(--magenta-glow);
  opacity: 0.6;
}

/* ============== Boot overlay (one-shot) ============== */
.boot {
  position: fixed;
  top: 0; left: 0; right: 0; bottom: 0;
  width: 100vw; height: 100vh;
  z-index: 2000;
  background: var(--bg);
  display: flex; align-items: center; justify-content: center;
  animation: boot-out 600ms ease-in 1800ms forwards;
  pointer-events: none;
  overflow: hidden;
}
.boot__inner { padding: 24px 32px; max-width: 100%; }
.boot__banner {
  font-family: var(--font-body);
  color: var(--cyan);
  text-shadow: 0 0 8px var(--cyan-glow);
  font-size: 18px;
  line-height: 1.05;
  margin: 0 0 18px;
  white-space: pre;
}
.boot__line {
  font-family: var(--font-body);
  font-size: 14px;
  color: var(--bone-dim);
  margin: 2px 0;
  opacity: 0;
  animation: boot-in 200ms ease-out forwards;
}
.boot__line:nth-child(1) { animation-delay:  60ms; }
.boot__line:nth-child(2) { animation-delay: 220ms; }
.boot__line:nth-child(3) { animation-delay: 380ms; }
.boot__line:nth-child(4) { animation-delay: 540ms; }
.boot__line:nth-child(5) { animation-delay: 700ms; }
.boot__line:nth-child(6) { animation-delay: 860ms; }
.boot__line .ok   { color: var(--acid); }
.boot__line .mag  { color: var(--magenta); text-shadow: 0 0 6px var(--magenta-glow); }
.boot__line .blink { animation: boot-blink 600ms steps(1) infinite; }
@keyframes boot-blink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }
@keyframes boot-in {
  from { opacity: 0; transform: translateY(2px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes boot-out { to { opacity: 0; visibility: hidden; } }

/* ============== HUD (top status line) ============== */
.hud {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  border: 1px solid var(--void-line);
  background: linear-gradient(180deg, rgba(255,79,216,0.04), rgba(92,242,255,0.04));
  padding: 8px 16px;
  font-family: var(--font-body);
}
.hud__left  { font-family: var(--font-body); }
.hud__right { text-align: right; }
.hud__center { display: flex; gap: 28px; justify-content: center; }
.hud__round  { display: inline-flex; align-items: baseline; gap: 6px; }
.hud__round-mark {
  font-family: var(--font-display);
  font-size: 18px;
  color: var(--ash);
  transition: color 200ms;
}
.hud__round--active .hud__round-mark {
  color: var(--magenta);
  text-shadow: 0 0 8px var(--magenta-glow);
}
.hud__round--win  .hud__round-mark { color: var(--acid); }
.hud__round--loss .hud__round-mark { color: var(--rust); }
.blink { animation: hud-blink 800ms steps(1) infinite; }
@keyframes hud-blink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }

/* ============== Arena (3 columns) ============== */
.arena {
  display: grid;
  grid-template-columns: minmax(260px, 1fr) minmax(420px, 540px) minmax(260px, 1fr);
  gap: 22px;
  align-items: start;
  position: relative;
  z-index: 2;
}

/* ============== Side panels ============== */
.side {
  display: flex; flex-direction: column; gap: 14px;
  align-items: stretch;
  transition: filter 220ms linear, opacity 220ms linear;
}
.side__nameplate {
  padding: 8px 12px 10px;
  border: 1px solid var(--void-line);
  background:
    linear-gradient(180deg, rgba(255,255,255,0.02), transparent),
    var(--bg-panel);
  text-align: center;
}
.side--attacker .side__nameplate { border-color: var(--magenta-deep); }
.side--defender .side__nameplate { border-color: var(--cyan-deep); }
.side__role {
  font-family: var(--font-display);
  font-size: 12px;
  color: var(--ash);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.side__name {
  font-family: var(--font-display);
  font-size: 24px;
  line-height: 1; margin: 4px 0 2px;
}
.side--attacker .side__name { color: var(--magenta); text-shadow: 0 0 8px var(--magenta-glow); }
.side--defender .side__name { color: var(--cyan); text-shadow: 0 0 8px var(--cyan-glow); }
.side__rank {
  font-family: var(--font-body);
  font-size: 14px;
  color: var(--bone-dim);
}

/* slide-in on intro */
@keyframes side-in-left {
  from { transform: translate(-50px, 0); opacity: 0; }
  to   { transform: translate(0, 0); opacity: 1; }
}
@keyframes side-in-right {
  from { transform: translate(50px, 0); opacity: 0; }
  to   { transform: translate(0, 0); opacity: 1; }
}
.side--attacker { animation: side-in-left  600ms cubic-bezier(.2,.8,.2,1) both; }
.side--defender { animation: side-in-right 600ms cubic-bezier(.2,.8,.2,1) both; }

/* loser flicker */
@keyframes flicker-loser {
  0%, 100% { opacity: 1; filter: hue-rotate(0); }
  20%, 60% { opacity: 0.3; filter: hue-rotate(40deg) saturate(2); transform: translateX(-3px); }
  40%      { opacity: 0.7; filter: hue-rotate(-30deg); transform: translateX(2px); }
}
.side.is-loser  { animation: flicker-loser 360ms steps(8); }

/* winner pulse */
@keyframes winner-pulse {
  0%, 100% { filter: drop-shadow(0 0 0 currentColor); }
  50%      { filter: drop-shadow(0 0 18px var(--acid)); }
}
.side.is-winner .side__actor svg { animation: winner-pulse 1200ms ease-in-out infinite; }

.side__actor {
  display: flex; justify-content: center;
  padding: 14px 0;
}

/* ============== Actor reactions (idle / anticipation / damage / verdict / glitch) ============== */

/* idle: gentle bob always running. Lives on the SVG so reaction transforms
   on .side__actor compose cleanly above it. */
@keyframes actor-bob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-2px); }
}
/* The bob and ambient filter live on .rig (which wraps the actor svg + the
   monitor screen overlay) so both elements move together. */
.side__actor > .rig { animation: actor-bob 2.4s ease-in-out infinite; }

/* per-side ambient glow (defender pulses, attacker steady) */
@keyframes def-glow-pulse {
  0%, 100% { filter: drop-shadow(0 0 6px var(--cyan-glow)); }
  50%      { filter: drop-shadow(0 0 14px var(--cyan-glow)); }
}
.side--attacker .side__actor > .rig {
  filter: drop-shadow(0 0 8px var(--magenta-glow));
}
.side--defender .side__actor > .rig {
  animation: actor-bob 2.4s ease-in-out infinite, def-glow-pulse 3s ease-in-out infinite;
}

/* anticipation: attacker leans toward defender during acc_roll/crit_roll */
@keyframes anticipate-atk {
  from { transform: translateX(0); }
  to   { transform: translateX(8px) translateY(-1px); }
}
.side--attacker.is-anticipating .side__actor {
  animation: anticipate-atk 500ms cubic-bezier(.2,.8,.2,1) forwards;
}

/* bracing: defender squares up during def_acc_roll/def_crit_roll
   — slight lean back + scale-up to read as "preparing the wall" */
@keyframes brace-def {
  from { transform: translateX(0) scale(1); }
  to   { transform: translateX(-4px) scale(1.04); }
}
.side--defender.is-bracing .side__actor {
  animation: brace-def 500ms cubic-bezier(.2,.8,.2,1) forwards;
}

/* damage tick: micro-shake on the side losing HP this round */
@keyframes actor-tick {
  0%, 100% { transform: translateX(0); }
  50%      { transform: translateX(-1.5px); }
}
.side.is-taking-damage .side__actor {
  animation: actor-tick 80ms steps(2) infinite;
}

/* ----- verdict reactions ----- */

/* defender HIT: recoil + magenta wash */
@keyframes recoil-hit {
  0%   { transform: translateX(0) scale(1); }
  10%  { transform: translateX(8px) scale(0.96); filter: drop-shadow(0 0 10px var(--magenta)); }
  35%  { transform: translateX(-5px) scale(0.98); filter: drop-shadow(0 0 6px var(--magenta)); }
  60%  { transform: translateX(2px) scale(0.99); }
  100% { transform: translateX(0) scale(1); }
}
.side--defender.react-hit .side__actor { animation: recoil-hit 600ms; }

/* defender CRIT: bigger recoil, more flash, slight rotation */
@keyframes recoil-crit {
  0%   { transform: translateX(0) scale(1) rotate(0); }
  10%  { transform: translateX(14px) scale(0.92) rotate(2deg); filter: drop-shadow(0 0 18px var(--magenta)); }
  25%  { transform: translateX(-10px) scale(0.93) rotate(-2deg); filter: drop-shadow(0 0 14px var(--magenta)); }
  45%  { transform: translateX(7px) scale(0.96) rotate(1deg); filter: drop-shadow(0 0 10px var(--magenta)); }
  70%  { transform: translateX(-3px) scale(0.98); }
  100% { transform: translateX(0) scale(1) rotate(0); }
}
.side--defender.react-crit .side__actor { animation: recoil-crit 800ms; }

/* defender MISS: smug lean back with acid edge */
@keyframes smug-lean {
  0%   { transform: translateX(0) rotate(0); }
  35%  { transform: translateX(-3px) rotate(-3deg); filter: drop-shadow(0 0 8px var(--acid)); }
  100% { transform: translateX(0) rotate(0); }
}
.side--defender.react-miss .side__actor { animation: smug-lean 700ms ease-out; }

/* defender RESIST: confident upscale + cyan ring */
@keyframes confident-resist {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.06); filter: drop-shadow(0 0 16px var(--cyan)); }
  100% { transform: scale(1); }
}
.side--defender.react-resist .side__actor { animation: confident-resist 700ms; }

/* attacker HIT: lunge forward + magenta flash */
@keyframes lunge-hit {
  0%   { transform: translateX(0); }
  20%  { transform: translateX(12px); filter: drop-shadow(0 0 14px var(--magenta)); }
  60%  { transform: translateX(-3px); filter: drop-shadow(0 0 6px var(--magenta)); }
  100% { transform: translateX(0); }
}
.side--attacker.react-hit .side__actor { animation: lunge-hit 600ms; }

/* attacker CRIT: bigger lunge with scale */
@keyframes lunge-crit {
  0%   { transform: translateX(0) scale(1); }
  15%  { transform: translateX(20px) scale(1.08); filter: drop-shadow(0 0 22px var(--magenta)); }
  35%  { transform: translateX(-5px) scale(1.02); filter: drop-shadow(0 0 14px var(--magenta)); }
  60%  { transform: translateX(2px) scale(1); filter: drop-shadow(0 0 6px var(--magenta)); }
  100% { transform: translateX(0) scale(1); }
}
.side--attacker.react-crit .side__actor { animation: lunge-crit 800ms; }

/* attacker MISS / RESIST: dejected slump (desaturate + lean back) */
@keyframes dejected {
  0%   { transform: translateX(0) rotate(0); filter: brightness(1); }
  30%  { transform: translateX(-5px) rotate(2deg); filter: brightness(0.5) saturate(0.4); }
  65%  { transform: translateX(-2px) rotate(2deg); filter: brightness(0.6) saturate(0.5); }
  100% { transform: translateX(0) rotate(0); filter: brightness(1); }
}
.side--attacker.react-miss .side__actor,
.side--attacker.react-resist .side__actor { animation: dejected 800ms; }

/* xfade glitch on both sprites — RGB-shift + flicker */
@keyframes sprite-glitch {
  0%   { transform: translateX(0); filter: hue-rotate(0); }
  20%  { transform: translateX(-3px); filter: hue-rotate(80deg) saturate(2); opacity: 0.7; }
  40%  { transform: translateX(3px) skewX(2deg); filter: hue-rotate(-60deg); opacity: 1; }
  60%  { transform: translateX(-2px); filter: hue-rotate(40deg); opacity: 0.85; }
  80%  { transform: translateX(1px); filter: hue-rotate(-20deg); opacity: 1; }
  100% { transform: translateX(0); filter: hue-rotate(0); }
}
.side.react-glitch .side__actor { animation: sprite-glitch 280ms steps(7); }

/* ============== HP bar ============== */
.hp { display: grid; grid-template-columns: 1fr auto; gap: 10px; align-items: center; }
.hp__cells {
  display: grid;
  grid-template-columns: repeat(20, 1fr);
  gap: 2px;
  height: 14px;
}
.hp__cell {
  border: 1px solid;
  transition: background 200ms linear, opacity 200ms linear;
  opacity: 0.3;
}
.hp__cell.is-on { opacity: 1; }
.hp.is-draining .hp__cell.is-on { animation: hp-pulse 240ms steps(6); }
@keyframes hp-pulse {
  0%, 100% { filter: brightness(1); }
  50%      { filter: brightness(1.6) saturate(1.6); }
}
.hp__numbers {
  font-family: var(--font-display);
  font-size: 16px;
  min-width: 80px;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.hp__numbers .ash { color: var(--ash); }
.hp__numbers .bone { color: var(--bone); }

/* ============== Program card (in-stage) ============== */
.prog-card {
  border: 1px solid var(--void-line);
  background:
    linear-gradient(180deg, rgba(255,255,255,0.02), transparent),
    var(--bg-panel);
  padding: 10px 12px 12px;
  position: relative;
}
.prog-card--attacker { border-color: var(--magenta-deep); box-shadow: inset 0 0 0 1px rgba(255,79,216,0.15); }
.prog-card--defender { border-color: var(--cyan-deep);    box-shadow: inset 0 0 0 1px rgba(92,242,255,0.15); }
.prog-card__head { display: flex; align-items: center; gap: 12px; }
.prog-card__head-text { line-height: 1.1; min-width: 0; }
.prog-card__name {
  font-family: var(--font-display);
  font-size: 16px;
  color: var(--bone);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.prog-card__meta {
  font-family: var(--font-body);
  color: var(--ash);
  font-size: 14px;
  margin-top: 2px;
}
.prog-card__stats {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px;
  margin-top: 10px;
}
.stat { border-top: 1px dashed var(--void-line); padding-top: 6px; }
.stat__label {
  font-family: var(--font-display);
  color: var(--ash);
  font-size: 11px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}
.stat__value {
  font-family: var(--font-display);
  font-size: 22px;
  line-height: 1;
  margin-top: 2px;
  font-variant-numeric: tabular-nums;
  color: var(--bone);
}
.stat__value--mag  { color: var(--magenta); text-shadow: 0 0 6px var(--magenta-glow); }
.stat__value--cyan { color: var(--cyan); text-shadow: 0 0 6px var(--cyan-glow); }

/* ============== Central matchup column ============== */
.central {
  display: flex; flex-direction: column;
  align-items: center;
  gap: 14px;
  padding: 8px 16px;
  position: relative;
}
.central__round {
  text-align: center;
  font-family: var(--font-body);
}
.central__round-lbl {
  font-family: var(--font-display);
  color: var(--ash);
  font-size: 14px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.central__round-num {
  font-family: var(--font-display);
  color: var(--bone);
  font-size: 64px;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.central__matchup {
  text-align: center;
  opacity: 0; transform: translateY(8px);
  transition: opacity 240ms linear, transform 240ms cubic-bezier(.2,.8,.2,1);
}
.central__matchup.is-on { opacity: 1; transform: translateY(0); }
.matchup__row {
  font-family: var(--font-display);
  font-size: 28px;
}
.matchup__mult {
  font-family: var(--font-display);
  font-size: 56px;
  line-height: 1;
  margin: 4px 0;
  text-shadow: 0 0 14px currentColor;
  font-variant-numeric: tabular-nums;
}
.matchup__mult--strong  { color: var(--acid); }
.matchup__mult--weak    { color: var(--rust); }
.matchup__mult--neutral { color: var(--bone-dim); }
.matchup__label {
  font-family: var(--font-display);
  color: var(--ash);
  font-size: 12px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
}
.matchup__vs { color: var(--ash); margin: 0 12px; font-family: var(--font-display); }

/* rolls box */
.rolls {
  display: flex; flex-direction: column; gap: 10px;
  align-self: stretch;
  padding: 12px 14px;
  border: 1px dashed var(--void-line);
  background: rgba(255,255,255,0.015);
}
.roll-line {
  display: grid;
  grid-template-columns: 80px 90px auto 60px auto;
  align-items: baseline;
  gap: 10px;
  opacity: 0;
  transform: translateX(-6px);
  transition: opacity 200ms linear, transform 200ms linear;
}
.roll-line.is-on { opacity: 1; transform: translateX(0); }
.roll-line__label {
  font-family: var(--font-display);
  color: var(--ash);
  font-size: 12px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}
.roll-line__value {
  font-family: var(--font-display);
  font-size: 22px;
  font-variant-numeric: tabular-nums;
  color: var(--bone);
}
.roll-line__value.is-hit  { color: var(--acid); text-shadow: 0 0 6px rgba(182,255,92,0.6); }
.roll-line__value.is-miss { color: var(--rust); text-shadow: 0 0 6px rgba(255,138,60,0.6); }
.roll-line__vs {
  font-family: var(--font-body);
  color: var(--ash);
  font-size: 13px;
}
.roll-line__threshold {
  font-family: var(--font-display);
  color: var(--bone-dim);
}
.roll-line__verdict {
  font-family: var(--font-display);
  font-size: 14px;
}
.roll-line__verdict.is-hit  { color: var(--acid); }
.roll-line__verdict.is-miss { color: var(--rust); }

/* Side-tinted roll labels: magenta = attacker, cyan = defender. */
.roll-line--atk .roll-line__label { color: var(--magenta); }
.roll-line--def .roll-line__label { color: var(--cyan); }
/* Defender's "fail = block halved" lands as a positive for the attacker, so
   it still uses the attacker-centric is-hit/is-miss verdict colors. */

/* damage / blocked readout */
.damage-readout {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  align-self: stretch;
  padding: 12px 16px;
  border: 1px solid var(--magenta-deep);
  background: linear-gradient(90deg, rgba(255,79,216,0.06), rgba(92,242,255,0.06));
  opacity: 0;
  transition: opacity 220ms linear;
}
.damage-readout.is-on { opacity: 1; }
.damage-readout__col {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
}
.damage-readout__lbl {
  font-family: var(--font-display);
  color: var(--ash);
  font-size: 13px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}
.damage-readout__val {
  font-family: var(--font-display);
  font-size: 30px;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--magenta);
  text-shadow: 0 0 8px var(--magenta-glow);
}
.damage-readout__val.is-crit { color: var(--rust); text-shadow: 0 0 12px rgba(255,138,60,0.6); font-size: 36px; }
.damage-readout__val--cyan { color: var(--cyan); text-shadow: 0 0 8px var(--cyan-glow); }
.damage-readout__vs {
  font-family: var(--font-display);
  color: var(--ash);
  font-size: 16px;
  letter-spacing: 0.06em;
}

/* verdict pop */
.verdict {
  text-align: center;
  margin-top: 4px;
  display: none;
}
.verdict.is-on {
  display: block;
  animation: verdict-pop 360ms cubic-bezier(.2,.8,.2,1) both;
}
@keyframes verdict-pop {
  from { transform: scale(0.85); opacity: 0; }
  to   { transform: scale(1); opacity: 1; }
}
.verdict__main {
  font-family: var(--font-display);
  font-size: 24px;
  letter-spacing: 0.08em;
}
.verdict.is-attacker .verdict__main { color: var(--acid); text-shadow: 0 0 14px rgba(182,255,92,0.7); }
.verdict.is-defender .verdict__main { color: var(--rust); text-shadow: 0 0 14px rgba(255,138,60,0.7); }
.verdict__flavor {
  font-family: var(--font-body);
  color: var(--ash);
  font-size: 14px;
  margin-top: 4px;
  max-width: 380px;
  margin-left: auto; margin-right: auto;
}

/* ============== Final verdict (replaces central when done) ============== */
.final {
  display: none;
  flex-direction: column; align-items: center;
  gap: 12px; padding: 18px 12px;
  text-align: center;
}
.final.is-on { display: flex; animation: verdict-pop 460ms cubic-bezier(.2,.8,.2,1) both; }
.final__title {
  font-family: var(--font-display);
  font-size: 88px;
  line-height: 1;
  text-shadow: 0 0 24px currentColor;
}
.final__title--win  { color: var(--acid); }
.final__title--loss { color: var(--rust); }
.final__score {
  font-family: var(--font-display);
  color: var(--bone);
  font-size: 56px;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.final__delta {
  font-family: var(--font-display);
  font-size: 18px;
}
.final__delta--up   { color: var(--acid); }
.final__delta--down { color: var(--rust); }
.final__reward {
  margin-top: 10px;
  padding: 10px 14px;
  border: 1px solid var(--acid);
  background: rgba(182,255,92,0.05);
  text-align: left;
  min-width: 240px;
}
.final__nav {
  margin-top: 14px;
  display: flex; gap: 12px; justify-content: center;
}
.final__nav a {
  font-family: var(--font-display);
  font-size: 13px;
  letter-spacing: 0.06em;
  padding: 8px 14px;
  background: transparent;
  color: var(--bone);
  border: 1px solid var(--cyan);
  text-decoration: none;
  text-transform: uppercase;
}
.final__nav a:hover { background: var(--cyan); color: var(--bg); }
.final__nav a.btn--mag { border-color: var(--magenta); color: var(--magenta); }
.final__nav a.btn--mag:hover { background: var(--magenta); color: var(--bg); }

/* ============== Combat log ============== */
.battle-log {
  margin-top: 8px;
  padding: 10px 14px 12px;
  border: 1px solid var(--void-line);
  background:
    linear-gradient(180deg, rgba(0,0,0,0.4), rgba(0,0,0,0.15)),
    var(--bg-panel);
}
.battle-log__head {
  display: flex; justify-content: space-between; align-items: center;
  border-bottom: 1px dashed var(--void-line);
  padding-bottom: 4px; margin-bottom: 8px;
  font-family: var(--font-display);
  font-size: 13px;
  color: var(--ash);
  letter-spacing: 0.05em;
  text-transform: uppercase;
}
.battle-log__body {
  display: flex; flex-direction: column; gap: 4px;
  min-height: 60px;
  font-family: var(--font-body);
  font-size: 14px;
}
.battle-log__entry {
  font-family: var(--font-body);
  font-size: 15px;
  animation: log-in 240ms cubic-bezier(.2,.8,.2,1) both;
}
@keyframes log-in {
  from { opacity: 0; transform: translateX(-6px); }
  to   { opacity: 1; transform: translateX(0); }
}
.battle-log__entry .r { color: var(--ash); }
.battle-log__entry .atk { color: var(--magenta); font-family: var(--font-display); }
.battle-log__entry .def { color: var(--cyan);    font-family: var(--font-display); }
.battle-log__entry .arrow { color: var(--ash); }
.battle-log__entry .num { color: var(--bone); font-family: var(--font-display); }
.battle-log__entry .crit { color: var(--rust); font-family: var(--font-display); margin-left: 6px; letter-spacing: 0.08em; }
.battle-log__entry .miss { color: var(--rust); font-family: var(--font-display); margin-left: 6px; letter-spacing: 0.08em; }
.battle-log__entry .win  { color: var(--acid); font-family: var(--font-display); margin-left: 8px; letter-spacing: 0.1em; }
.battle-log__entry .loss { color: var(--rust); font-family: var(--font-display); margin-left: 8px; letter-spacing: 0.1em; }
.battle-log__waiting {
  font-family: var(--font-body);
  color: var(--ash);
  font-size: 14px;
}

/* ============== Bottom bar (fixed) ============== */
.bottom-bar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  padding: 12px 28px;
  gap: 14px;
  background: linear-gradient(180deg, transparent, rgba(0,0,0,0.85));
  z-index: 50;
}
.bottom-bar__center { display: flex; gap: 10px; justify-content: center; }
.bottom-bar > :last-child { justify-self: end; }
.btn-st {
  font-family: var(--font-display);
  font-size: 13px;
  letter-spacing: 0.06em;
  padding: 6px 14px;
  background: transparent;
  color: var(--bone);
  border: 1px solid var(--cyan);
  cursor: pointer;
  text-transform: uppercase;
  text-decoration: none;
  display: inline-block;
}
.btn-st:hover { background: var(--cyan); color: var(--bg); }
.btn-st--mag { border-color: var(--magenta); color: var(--magenta); }
.btn-st--mag:hover { background: var(--magenta); color: var(--bg); }

/* ============== Glitch overlay ============== */
.glitch-overlay {
  position: fixed; inset: 0; pointer-events: none; z-index: 0;
  display: none;
}
.glitch-overlay.is-on {
  display: block;
  animation: glitch-fade 380ms ease-out forwards;
}
@keyframes glitch-fade {
  0%   { opacity: 1; }
  70%  { opacity: 1; }
  100% { opacity: 0; }
}
.glitch-overlay__bar {
  position: absolute; left: -10%; right: -10%; height: 20px;
  background: linear-gradient(90deg, transparent, var(--magenta), var(--cyan), transparent);
  mix-blend-mode: screen;
  animation: bar-slip 400ms steps(6);
  opacity: 0.7;
}
@keyframes bar-slip {
  from { transform: translateX(-30px); }
  to   { transform: translateX(30px); }
}
.glitch-overlay__noise {
  position: absolute; inset: 0;
  background:
    repeating-linear-gradient(0deg, rgba(255,79,216,0.06) 0 2px, transparent 2px 4px),
    repeating-linear-gradient(90deg, rgba(92,242,255,0.04) 0 2px, transparent 2px 4px);
  mix-blend-mode: screen;
}

/* ============== Ambient log (right edge) ============== */
.ambient-log {
  position: fixed;
  right: 12px; top: 100px;
  width: 240px;
  font-family: var(--font-body);
  font-size: 13px;
  z-index: 3;
  opacity: 0.45;
  pointer-events: none;
}
.ambient-log__line {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  color: var(--bone-dim);
  margin: 1px 0;
}
.ambient-log__line .prompt { color: var(--ash); }
.ambient-log__line.is-fresh { color: var(--cyan); }

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

/* Make all stage containers safe from overflow at any width. */
.stage, .stage * { box-sizing: border-box; }

/* Reserve space for fixed bottom bar so content doesn't sit underneath it. */
.stage { padding-bottom: 80px; }

/* When central matchup widgets are inactive (between phases or after final),
 * they should not take vertical space.  is-on triggers the visible state. */
.central__matchup,
.damage-readout {
  max-height: 0;
  overflow: hidden;
  padding-top: 0; padding-bottom: 0;
  margin: 0;
  border-width: 0;
  transition: opacity 240ms linear, max-height 240ms ease,
              padding 240ms ease, border-width 240ms ease;
}
.central__matchup.is-on {
  max-height: 200px;
  padding-top: 0; padding-bottom: 0;
}
.damage-readout.is-on {
  max-height: 120px;
  padding: 12px 16px;
  border-width: 1px;
}

/* Roll lines collapse vertical space when not yet fired. */
.roll-line {
  max-height: 0;
  margin: 0;
  overflow: hidden;
  transition: opacity 200ms linear, transform 200ms linear,
              max-height 240ms ease, margin 240ms ease;
}
.roll-line.is-on {
  max-height: 60px;
  margin: 0;
}

@media (max-width: 1280px) {
  .ambient-log { display: none; }
}
/* ---- Tablet & mobile: keep 1-on-1 face-off (atk LEFT, def RIGHT, central BELOW) ---- */
@media (max-width: 1100px) {
  .arena {
    grid-template-columns: 1fr 1fr;
    grid-template-areas:
      "atk def"
      "central central";
    gap: 14px;
  }
  .side--attacker { grid-area: atk; min-width: 0; }
  .side--defender { grid-area: def; min-width: 0; }
  .central { grid-area: central; padding: 6px 8px; }
  .central__round-num { font-size: 48px; }
  .matchup__row { font-size: 22px; }
  .matchup__mult { font-size: 42px; }
  .roll-line { grid-template-columns: 80px 90px auto auto; gap: 8px; }
  .roll-line__threshold, .roll-line__vs { display: none; }
  .final__title { font-size: 64px; }
  .final__score { font-size: 40px; }
}
@media (max-width: 700px) {
  .stage { padding: 12px 8px 140px; gap: 8px; }
  .hud { grid-template-columns: 1fr; gap: 4px; padding: 8px 12px; text-align: center; }
  .hud__left, .hud__right { text-align: center; }
  .hud__center { gap: 14px; }
  .arena { gap: 8px; }
  /* compress sides so they fit at half-width */
  .side { gap: 8px; }
  .side__nameplate { padding: 6px 6px 8px; }
  .side__role { font-size: 10px; }
  .side__name { font-size: 16px; margin: 2px 0 1px; }
  .side__rank { font-size: 11px; }
  .side__actor { padding: 4px 0; }
  /* sprite rig: cap at column width so it scales down. The rig is a
     positioning context for the screen overlay; we want it to be
     intrinsically sized to the svg so percentage overlay coords work. */
  .side__actor > .rig { max-width: 100%; }
  .side__actor .rig svg { max-width: 100%; height: auto; display: block; }
  .hp__cells { height: 8px; }
  .hp__numbers { font-size: 12px; }
  /* prog cards */
  .prog-card { padding: 6px; }
  .prog-card__head { gap: 6px; }
  .prog-card__name { font-size: 13px; }
  .prog-card__meta { font-size: 10px; }
  .prog-card__stats { gap: 4px; margin-top: 4px; }
  .stat__label { font-size: 9px; }
  .stat__value { font-size: 16px; }
  /* central */
  .central__round-num { font-size: 36px; }
  .matchup__row { font-size: 16px; }
  .matchup__mult { font-size: 34px; }
  .matchup__vs { margin: 0 6px; }
  .roll-line {
    grid-template-columns: 70px 1fr auto;
    column-gap: 8px;
  }
  .roll-line__label { font-size: 11px; }
  .roll-line__value { font-size: 18px; }
  .damage-readout__val { font-size: 24px; }
  .damage-readout__val.is-crit { font-size: 28px; }
  .final__title { font-size: 44px; }
  .final__score { font-size: 30px; }
  .bottom-bar {
    grid-template-columns: 1fr;
    padding: 10px 14px;
    gap: 8px;
    text-align: center;
  }
  .bottom-bar > :last-child { display: none; }
  .bottom-bar__center { flex-wrap: wrap; }
  .btn-st { font-size: 12px; padding: 6px 10px; }
  .battle-log__entry { font-size: 13px; }
}
@media (max-width: 460px) {
  .stage { padding: 10px 6px 140px; }
  .arena { gap: 6px; }
  .side__name { font-size: 14px; }
  .side__nameplate { padding: 4px 4px 6px; }
  .prog-card__name { font-size: 12px; }
  .stat__value { font-size: 14px; }
  .central__round-num { font-size: 30px; }
  .matchup__row { font-size: 14px; }
  .matchup__mult { font-size: 28px; }
  .final__title { font-size: 36px; }
  .final__score { font-size: 24px; }
}

/* ============== Actor monitor screen overlay ==============

   The actor sprite is a 24×32 pixel grid rendered at scale 6 (so 144×192 px).
   Inside it is a "screen" rectangle where the default eyes-and-mouth used
   to be drawn. With actor_sprite(blank_screen=True) those pixels are wiped
   to the screen-fill color, giving us a clean surface to overlay either:
     • a small emotion face SVG (idle / verdict / final state), or
     • the program art SVG (whichever program ran this round).

   Positions below are derived from app/pixel/actors.py SCREEN_RECTS:
     attacker  rows  9-15 cols 8-15  →  top 54  left 48  w 48  h 42
     defender  rows  8-16 cols 6-17  →  top 48  left 36  w 72  h 54
*/

.rig {
  position: relative;
  display: inline-block;
  line-height: 0;  /* prevent extra space under inline svg */
}
.rig__screen {
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  /* The blanked screen pixels behind us are palette[5] (a deep ink color);
     we let those show through and just float content on top. */
  overflow: hidden;
}
.rig__screen svg {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  /* crispEdges already set by pixel_sprite, just be explicit */
  image-rendering: pixelated;
  display: block;
}

/* Positions expressed as % of the unscaled 24×32 sprite so they hold
   regardless of how the rig is scaled (mobile shrinks via max-width:100%). */
.rig--attacker .rig__screen {
  /* attacker face area: rows 9-15, cols 8-15 */
  top: 28.125%;   /* 9 / 32 */
  left: 33.333%;  /* 8 / 24 */
  width: 33.333%; /* 8 / 24 */
  height: 21.875%;/* 7 / 32 */
}
.rig--defender .rig__screen {
  /* defender face area: rows 8-16, cols 6-17 */
  top: 25%;       /* 8 / 32 */
  left: 25%;      /* 6 / 24 */
  width: 50%;     /* 12 / 24 */
  height: 28.125%;/* 9 / 32 */
}

/* Faint scanline + flicker on the monitor surface so swaps feel like CRT
   re-syncs rather than instant DOM updates. Sits under the content. */
.rig__screen::before {
  content: "";
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(
    to bottom,
    rgba(255,255,255,0.04) 0,
    rgba(255,255,255,0.04) 1px,
    transparent 1px,
    transparent 3px
  );
  pointer-events: none;
  z-index: 1;
}
.rig__screen svg { position: relative; z-index: 2; }

/* When the sprite is reacting (winner pulse, glitch, etc) the screen rides
   along — it's positioned inside .rig which is inside .side__actor, so the
   reaction transforms applied to .side__actor compose cleanly. */

@keyframes screen-flicker {
  0%, 95%, 100% { opacity: 1; }
  96% { opacity: 0.5; }
  97% { opacity: 1; }
  98% { opacity: 0.7; }
}
.rig__screen { animation: screen-flicker 4.2s steps(1) infinite; }

/* Mobile: sprite scales down — keep overlay positions in proportion via
   transform-origin scaling. We use a per-side pct ratio: positions are
   relative to the 144×192 svg, so we just scale the .rig itself.
   (battle.css mobile media queries scale .side__actor svg via existing
   rules; nothing extra needed here as long as overlay positions stay in
   pixel coords matching the unscaled svg.) */
