/* The fight's HUD on the web stage, in the TV's language (FightHUDKit,
   EnemyStageView): dark translucent capsules, lit pills, clock-hand timer
   discs, white type with a soft shadow. Everything is in --u, about 1% of
   the screen's height, as on the TV (externalStageUnit). */
/* (woff2 where it's to be had — the site; the phone's own server carries
   only the .ttf, and a browser goes on to that.) */
@font-face { font-family: "Onest"; src: url("assets/fonts/Onest-Bold.woff2") format("woff2"), url("assets/fonts/Onest-Bold.ttf") format("truetype"); font-weight: 700; font-display: swap; }
@font-face { font-family: "Onest"; src: url("assets/fonts/Onest-Black.woff2") format("woff2"), url("assets/fonts/Onest-Black.ttf") format("truetype"); font-weight: 900; font-display: swap; }
@font-face { font-family: "Zagadka"; src: url("assets/fonts/Zagadka-Regular.woff2") format("woff2"), url("assets/fonts/Zagadka-Regular.ttf") format("truetype"); font-weight: 400; font-display: swap; }

.hud {
  --u: min(1vh, 0.75vw);
  --enemy-health: rgb(235, 92, 51);
  --health: rgb(255, 77, 23);
  --stamina: rgb(148, 224, 107);
  --block: rgb(128, 214, 255);
  --taken: rgb(255, 59, 48);
  --strike: rgb(50, 173, 230);
  position: fixed;
  inset: 0;
  pointer-events: none;
  font-family: "Onest", -apple-system, system-ui, sans-serif;
  color: #fff;
  opacity: 1;
  transition: opacity 0.4s ease;
}
.hud.idle .fight-only { opacity: 0; }
/* The fight decided (the phone's screen): only the verdict stays. */
.hud.verdict .fight-only, .hud.verdict .hud-title { opacity: 0; }
.hud-title { transition: opacity 0.4s ease; }
.fight-only { transition: opacity 0.4s ease; }
.hud .shadowed { text-shadow: 0 0 calc(var(--u) * 0.6) rgba(0, 0, 0, 0.8); }

/* ── A lit tube on a dark capsule, its number inside the far end ── */
.pill {
  position: relative;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.62);
  box-shadow: inset 0 0 0 calc(var(--u) * 0.22) rgba(255, 255, 255, 0.14);
}
.pill > i {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: calc(var(--f, 1) * 100%);
  min-width: var(--h);
  border-radius: inherit;
  background: linear-gradient(90deg, color-mix(in srgb, var(--c) 80%, transparent), var(--c));
  box-shadow: 0 0 calc(var(--u) * 0.7) color-mix(in srgb, var(--c) 55%, transparent);
  transition: width 0.25s ease-out;
}
.pill[data-empty] > i { min-width: 0; width: 0; }
.pill > i::after {
  content: "";
  position: absolute;
  left: calc(var(--h) * 0.35);
  right: calc(var(--h) * 0.35);
  top: calc(var(--h) * 0.14);
  height: calc(var(--h) * 0.28);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.28);
}
.pill > b {
  position: absolute;
  right: calc(var(--h) * 0.42);
  top: 50%;
  translate: 0 -50%;
  font-size: calc(var(--h) * 0.66);
  font-weight: 900;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  text-shadow: 0 0 calc(var(--u) * 0.3) rgba(0, 0, 0, 0.55);
}

/* ── Who you're fighting, top left ── */
.hud-title {
  position: absolute;
  left: calc(var(--u) * 3.5);
  top: calc(var(--u) * 3.5);
  display: flex;
  align-items: baseline;
  gap: calc(var(--u) * 1.2);
  white-space: nowrap;
  text-shadow: 0 0 calc(var(--u) * 0.6) rgba(0, 0, 0, 0.75);
}
.hud-title .name {
  font-family: "Zagadka", serif;
  font-size: calc(var(--u) * 5.4);
  letter-spacing: calc(var(--u) * 0.15);
}
.hud-title .level {
  font-size: calc(var(--u) * 1.9);
  font-weight: 700;
  letter-spacing: calc(var(--u) * 0.3);
  color: rgba(255, 255, 255, 0.7);
  text-transform: uppercase;
}

/* ── His health, just over his head ── */
.hud-enemy-hp {
  --h: calc(var(--u) * 2.6);
  --c: var(--enemy-health);
  position: absolute;
  width: calc(var(--u) * 24);
  height: var(--h);
  translate: -50% -50%;
  filter: drop-shadow(0 calc(var(--u) * 0.3) var(--u) rgba(0, 0, 0, 0.45));
  opacity: 0;
  transition: opacity 0.3s ease-out;
}

/* ── His open blows: discs beside him, the clock hand running out ── */
.hud-attacks {
  position: absolute;
  width: calc(var(--u) * 8);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(var(--u) * 1.2);
  translate: -50% -50%;
}
.disc {
  --s: calc(var(--u) * 7.2);
  --p: 0;
  --a: rgb(255, 107, 87);
  position: relative;
  width: var(--s);
  height: var(--s);
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.6);
  box-shadow: 0 0 calc(var(--u) * (0.6 + 1.2 * var(--p))) color-mix(in srgb, var(--a) calc(40% + 50% * var(--p)), transparent);
  animation: disc-in 0.3s cubic-bezier(0.3, 1.4, 0.6, 1);
}
.disc.small { --s: calc(var(--u) * 5.2); }
.disc::before {
  content: "";
  position: absolute;
  inset: 12%;
  border-radius: 50%;
  background: conic-gradient(var(--a) calc(var(--p) * 1turn), transparent 0);
}
.disc::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  box-shadow: inset 0 0 0 max(1px, calc(var(--s) * 0.07)) rgba(255, 255, 255, 0.85);
}
.disc svg {
  position: absolute;
  inset: 32%;
  width: 36%;
  height: 36%;
  margin: auto;
  z-index: 1;
  fill: #fff;
  filter: drop-shadow(0 0 calc(var(--u) * 0.3) rgba(0, 0, 0, 0.6));
}
.disc .label {
  position: absolute;
  right: calc(100% + var(--u) * 1.2);
  top: 50%;
  translate: 0 -50%;
  font-size: calc(var(--u) * 2.5);
  font-weight: 900;
  letter-spacing: calc(var(--u) * 0.2);
  white-space: nowrap;
  text-transform: uppercase;
  text-shadow: 0 0 calc(var(--u) * 0.5) rgba(0, 0, 0, 0.85);
}
.disc.small .label { font-size: calc(var(--u) * 2); color: rgba(255, 255, 255, 0.75); }
/* Stopped: the block's blue, the disc full and lit (FightHUDKit: blockTint,
   the glow at 0.95 over a radius of 2.4). */
.disc.blocked {
  --a: var(--block);
  --p: 1;
  box-shadow: 0 0 calc(var(--u) * 2.4) color-mix(in srgb, var(--block) 95%, transparent);
}
.disc.blocked .label { color: var(--block); }
.disc.blocked svg { animation: shield-punch 0.4s ease-out forwards; }
.disc .ring {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  box-shadow: inset 0 0 0 max(1px, calc(var(--s) * 0.08)) var(--block);
  opacity: 0;
}
.disc.blocked .ring { animation: ring-out 0.45s ease-out; }
.disc.gone { animation: disc-out 0.3s ease-in forwards; }
@keyframes disc-in { from { scale: 0.3; opacity: 0; } }
@keyframes disc-out { to { scale: 1.6; opacity: 0; } }
@keyframes ring-out { from { opacity: 0.95; scale: 1; } to { opacity: 0; scale: 2.3; } }
@keyframes shield-punch { 25% { scale: 1.55; } 100% { scale: 1.2; } }

/* ── The room's event, top centre ── */
.hud-event {
  position: absolute;
  left: 50%;
  top: calc(var(--u) * 3.5);
  translate: -50% 0;
  display: flex;
  align-items: center;
  gap: calc(var(--u) * 1.2);
  padding: calc(var(--u) * 0.7) calc(var(--u) * 2.4) calc(var(--u) * 0.7) calc(var(--u) * 0.7);
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.4);
  white-space: nowrap;
  transition: opacity 0.3s ease, translate 0.34s cubic-bezier(0.3, 1.3, 0.6, 1);
}
.hud-event[hidden] { display: flex; opacity: 0; translate: -50% calc(var(--u) * -6); }
.hud-event .disc { --s: calc(var(--u) * 6.4); animation: none; }
.hud-event .disc svg { inset: 26%; width: 48%; height: 48%; }
.hud-event .title {
  font-size: calc(var(--u) * 2);
  font-weight: 900;
  letter-spacing: calc(var(--u) * 0.2);
  text-transform: uppercase;
  color: var(--a);
}
.hud-event .text { font-size: calc(var(--u) * 2.6); font-weight: 700; }
.hud-event .title, .hud-event .text { text-shadow: 0 0 calc(var(--u) * 0.5) rgba(0, 0, 0, 0.85); }

/* ── Feed lines: a small dark capsule with a coloured dot ── */
.feed-pill {
  display: inline-flex;
  align-items: center;
  gap: calc(var(--u) * 1.1);
  padding: calc(var(--u) * 0.8) calc(var(--u) * 1.5);
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.42);
  font-size: calc(var(--u) * 2.4);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  animation: feed-in 0.2s ease-out;
}
.feed-pill::before {
  content: "";
  width: calc(var(--u) * 1.2);
  height: calc(var(--u) * 1.2);
  border-radius: 50%;
  background: var(--dot, var(--strike));
}
.feed-pill.notice { flex-direction: row-reverse; box-shadow: inset 0 0 0 max(1px, calc(var(--u) * 0.15)) rgba(255, 115, 102, 0.5); }
@keyframes feed-in { from { opacity: 0; translate: 0 calc(var(--u) * 2); } }
.hud-notices {
  position: absolute;
  right: calc(var(--u) * 3.5);
  top: calc(var(--u) * 3.5);
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: calc(var(--u) * 0.8);
}
.hud-notices .feed-pill { animation-name: notice-in; }
@keyframes notice-in { from { opacity: 0; translate: 0 calc(var(--u) * -2); } }

/* ── The player's corner, bottom left: feed, name, the badge ── */
.hud-player {
  position: absolute;
  left: calc(var(--u) * 3.5);
  bottom: calc(var(--u) * 3.5);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: calc(var(--u) * 1.6);
}
.hud-feed { display: flex; flex-direction: column; align-items: flex-start; gap: calc(var(--u) * 0.8); }
.player-name {
  font-size: calc(var(--u) * 2.6);
  font-weight: 900;
  letter-spacing: calc(var(--u) * 0.2);
  margin: 0 0 calc(var(--u) * -0.6) calc(var(--u) * 1.2);
  text-shadow: 0 0 calc(var(--u) * 0.5) rgba(0, 0, 0, 0.75);
}
.badge {
  position: relative;
  display: flex;
  align-items: center;
  filter: drop-shadow(0 calc(var(--u) * 0.4) calc(var(--u) * 1.2) rgba(0, 0, 0, 0.45));
}
.badge .pills {
  display: flex;
  flex-direction: column;
  gap: calc(var(--u) * 0.9);
  padding-left: calc(var(--u) * 10.5 * 0.62);
  translate: 0 calc(var(--u) * 0.2);
}
.badge .hp { --h: calc(var(--u) * 4.2); --c: var(--health); width: calc(var(--u) * 34); height: var(--h); }
.badge .stamina { --h: calc(var(--u) * 2.3); --c: var(--stamina); width: calc(var(--u) * 25); height: var(--h); }
.badge .stamina.low { --c: orange; }
.badge .stamina.out { --c: red; }
.avatar {
  position: absolute;
  left: 0;
  top: 50%;
  translate: 0 -50%;
  width: calc(var(--u) * 10.5);
  height: calc(var(--u) * 10.5);
  border-radius: 50%;
  overflow: hidden;
  /* The race's colour (PlayerAvatar.Race.tint, set on #hud) under the head. */
  background: radial-gradient(circle at 50% 35%, rgba(var(--tint, 52, 77, 117), 0.95), rgba(var(--tint, 52, 77, 117), 0.5));
  display: grid;
  place-items: center;
}
/* The dark bezel, then the thin light rim — over the head, as in the game. */
.avatar::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  box-shadow: inset 0 0 0 calc(var(--u) * 0.9) rgb(20, 20, 20), inset 0 0 0 calc(var(--u) * 1.25) rgba(255, 255, 255, 0.85);
}
.avatar svg { width: 52%; height: 52%; fill: #fff; filter: drop-shadow(0 0 calc(var(--u) * 0.3) rgba(0, 0, 0, 0.5)); }
.avatar canvas { position: absolute; inset: 0; width: 100%; height: 100%; }
/* The 3D head once it's in (AvatarHeads); the sword glyph until then. */
.has-head .avatar svg { display: none; }

/* ── Damage flying out of him ── */
.damage {
  position: absolute;
  translate: -50% -50%;
  font-size: calc(var(--u) * 6);
  font-weight: 900;
  color: #fff;
  -webkit-text-stroke: calc(var(--u) * 0.25) rgba(120, 20, 10, 0.85);
  paint-order: stroke fill;
  text-shadow: 0 calc(var(--u) * 0.4) calc(var(--u) * 1.2) rgba(0, 0, 0, 0.5);
  animation: damage-fly 0.95s cubic-bezier(0.2, 0.8, 0.3, 1) forwards;
}
.damage.weak { color: rgb(255, 214, 10); font-size: calc(var(--u) * 7.4); }
.damage.resist { color: rgba(255, 255, 255, 0.75); font-size: calc(var(--u) * 4.8); }
/* (--w: the hit's weight — stage-fight.js damageNumber.) */
@keyframes damage-fly {
  0% { opacity: 0; scale: calc(var(--w, 1) * 0.5); }
  15% { opacity: 1; scale: calc(var(--w, 1) * 1.15); }
  30% { scale: var(--w, 1); }
  100% { opacity: 0; scale: var(--w, 1); translate: -50% calc(-50% - var(--u) * 9); }
}

/* ── Low capsules at the bottom: the countdown, the verdict ── */
.hud-bottom {
  position: absolute;
  left: 50%;
  bottom: calc(var(--u) * 3.5);
  translate: -50% 0;
}
.panel-capsule {
  display: flex;
  align-items: center;
  gap: calc(var(--u) * 2.2);
  padding: calc(var(--u) * 1.4) calc(var(--u) * 4) calc(var(--u) * 1.4) calc(var(--u) * 1.4);
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.5);
  box-shadow: inset 0 0 0 max(1px, calc(var(--u) * 0.18)) color-mix(in srgb, var(--a) 50%, transparent),
    0 0 calc(var(--u) * 2.4) color-mix(in srgb, var(--a) 30%, transparent);
  white-space: nowrap;
  animation: panel-in 0.45s cubic-bezier(0.3, 1.2, 0.6, 1);
}
@keyframes panel-in { from { opacity: 0; translate: 0 calc(var(--u) * 6); } }
.panel-capsule .sign {
  position: relative;
  width: calc(var(--u) * 8.4);
  height: calc(var(--u) * 8.4);
  border-radius: 50%;
  background: color-mix(in srgb, var(--a) 90%, transparent);
  box-shadow: inset 0 0 0 max(1px, calc(var(--u) * 0.5)) rgba(255, 255, 255, 0.85), 0 0 calc(var(--u) * 1.6) color-mix(in srgb, var(--a) 55%, transparent);
  display: grid;
  place-items: center;
  font-size: calc(var(--u) * 4.2);
  font-weight: 900;
}
.panel-capsule .sign svg { width: 46%; height: 46%; fill: #fff; }
.panel-capsule.countdown .sign { background: rgba(0, 0, 0, 0.55); }
.panel-capsule.countdown .sign::before {
  content: "";
  position: absolute;
  inset: 8%;
  border-radius: 50%;
  background: conic-gradient(var(--a) calc(var(--p, 1) * 1turn), transparent 0);
  -webkit-mask: radial-gradient(circle, transparent 62%, #000 63%);
  mask: radial-gradient(circle, transparent 62%, #000 63%);
}
.panel-capsule .word {
  font-size: calc(var(--u) * 5.2);
  font-weight: 900;
  letter-spacing: calc(var(--u) * 0.25);
  color: var(--a);
  text-transform: uppercase;
  line-height: 1.05;
}
.panel-capsule.countdown .word { font-size: calc(var(--u) * 3.6); color: #fff; }
.panel-capsule .who { display: flex; align-items: baseline; gap: calc(var(--u) * 1); color: rgba(255, 255, 255, 0.78); }
.panel-capsule .who .name { font-family: "Zagadka", serif; font-size: calc(var(--u) * 3.8); }
.panel-capsule .who .level { font-size: calc(var(--u) * 2.4); font-weight: 700; }
.panel-capsule .word, .panel-capsule .who { text-shadow: 0 0 calc(var(--u) * 0.4) rgba(0, 0, 0, 0.6); }

/* ── Beaten: a red glow closes in round the edges; hurt: a red flash ── */
.hud-edge {
  position: absolute;
  inset: 0;
  opacity: 0;
  background: radial-gradient(ellipse at center, transparent 55%, rgba(255, 40, 30, 0.55));
  transition: opacity 0.6s ease-out;
}
.hud-edge.on { opacity: 1; }
.hud-edge.flash { animation: hurt 0.45s ease-out; }
@keyframes hurt { 0% { opacity: 0.9; } 100% { opacity: 0; } }

/* ── The rooms' rules on the HUD ── */
/* Darkness (RoomRule.darkness): the blows' warnings are gone — block by the
   vibration and his yell — and the stage sinks into shadow. */
.hud-dark {
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse at 50% 55%, rgba(0, 0, 0, 0.35), rgba(0, 0, 0, 0.82) 70%);
  opacity: 0;
  transition: opacity 0.6s ease;
  pointer-events: none;
  z-index: -1;
}
.hud.dark .hud-dark { opacity: 1; }
.hud.dark .hud-attacks { opacity: 0; }
.hud-attacks { transition: opacity 0.4s ease; }
/* Sandstorm: sand piles on the warnings until the phone is turned. */
.hud-attacks .sand {
  position: absolute;
  inset: calc(var(--u) * -3) calc(var(--u) * -18) calc(var(--u) * -3) calc(var(--u) * -3);
  z-index: 2;
  border-radius: calc(var(--u) * 3);
  opacity: 0;
  background:
    radial-gradient(circle at 20% 30%, rgba(140, 105, 60, 0.6) 0 1.5px, transparent 2px) 0 0 / 9px 9px,
    radial-gradient(circle at 70% 60%, rgba(120, 90, 50, 0.55) 0 1.2px, transparent 1.8px) 0 0 / 7px 7px,
    rgba(199, 158, 97, 0.92);
  filter: blur(0.3px);
  pointer-events: none;
}

/* ── His trick (EnemyTrait): a disc heading his attack column, what it is
   and what to do beside it, away from him (EnemyStageView.enemyTrickDisc) ── */
.hud-trick {
  position: absolute;
  width: calc(var(--u) * 7.2);
  height: calc(var(--u) * 7.2);
  translate: -50% -50%;
}
.trick-item { position: absolute; inset: 0; }
.trick-item .disc { --a: rgb(255, 107, 140); }
.trick-item .glyph {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(var(--u) * 0.15);
}
.trick-item .glyph svg {
  position: static;
  width: 34%;
  height: 34%;
  margin: 0;
  filter: drop-shadow(0 0 calc(var(--u) * 0.3) rgba(0, 0, 0, 0.6));
}
.trick-item .glyph.pair svg { width: 30%; height: 30%; }
.trick-item .glyph.pair svg + svg { width: 22%; height: 22%; }
.trick-item .words {
  position: absolute;
  right: calc(100% + var(--u) * 1.2);
  top: 50%;
  translate: 0 -50%;
  width: calc(var(--u) * 24);
  text-align: right;
  text-shadow: 0 0 calc(var(--u) * 0.5) rgba(0, 0, 0, 0.85);
  animation: feed-in 0.25s ease-out;
}
.trick-item .title {
  font-size: calc(var(--u) * 2);
  font-weight: 900;
  letter-spacing: calc(var(--u) * 0.2);
  text-transform: uppercase;
  color: var(--a);
}
.trick-item .text {
  font-size: calc(var(--u) * 2.3);
  font-weight: 700;
  line-height: 1.15;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.trick-item.gone { animation: disc-out 0.3s ease-in forwards; }

/* A trick answered: the notice in green (web-only; the TV acts it out). */
.feed-pill.notice.good { box-shadow: inset 0 0 0 max(1px, calc(var(--u) * 0.15)) rgba(148, 224, 107, 0.55); }

/* The dragon's sky, the soul's thread, the sleeping dust, the spores. */
.hud-trick-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

/* Кактус's needles in the glass — here the page is the glass: click them out. */
.hud-needles { position: absolute; inset: 0; pointer-events: none; }
.hud-needle {
  position: absolute;
  width: calc(var(--u) * 10);
  height: calc(var(--u) * 10);
  translate: -50% -50%;
  pointer-events: auto;
  cursor: pointer;
  border-radius: 50%;
  animation: needle-in 0.35s cubic-bezier(0.3, 1.3, 0.6, 1);
  transition: translate 0.35s ease-in, opacity 0.35s ease-in;
}
.hud-needle svg { width: 100%; height: 100%; overflow: visible; filter: drop-shadow(0.12em 0.12em 0.2em rgba(0, 0, 0, 0.5)); }
.hud-needle .cracks line { stroke: rgba(255, 255, 255, 0.55); stroke-width: 1; }
.hud-needle:hover svg { filter: drop-shadow(0 0 calc(var(--u) * 0.8) rgba(255, 240, 200, 0.8)); }
.hud-needle.out { pointer-events: none; translate: -50% calc(-50% - var(--u) * 8); opacity: 0; }
@keyframes needle-in { from { scale: 2.4; opacity: 0; } }

/* The ghost detector (GhostDetectorView), low in the middle. */
.hud-detector {
  position: absolute;
  left: 50%;
  bottom: calc(var(--u) * 3.5);
  translate: -50% 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(var(--u) * 0.8);
  padding: calc(var(--u) * 1.4) calc(var(--u) * 1.8);
  border-radius: calc(var(--u) * 2.4);
  background: rgba(0, 0, 0, 0.55);
  box-shadow: inset 0 0 0 1px rgba(140, 217, 255, 0.35);
  --cold: rgb(140, 217, 255);
}
.hud-detector[hidden] { display: none; }
.hud-detector.caught { box-shadow: inset 0 0 0 max(2px, calc(var(--u) * 0.25)) rgb(115, 255, 140); }
.hud-detector .meter { width: calc(var(--u) * 15); height: calc(var(--u) * 8.4); overflow: visible; }
.hud-detector .track { fill: none; stroke: rgba(255, 255, 255, 0.25); stroke-width: 6; stroke-linecap: round; }
.hud-detector .level { fill: none; stroke: var(--cold); stroke-width: 6; stroke-linecap: round; }
.hud-detector .needle { stroke: #fff; stroke-width: 3; stroke-linecap: round; }
.hud-detector circle { fill: #fff; }
.hud-detector .lamps { display: flex; gap: calc(var(--u) * 0.5); }
.hud-detector .lamps i { width: calc(var(--u) * 1.2); height: calc(var(--u) * 0.7); border-radius: 99px; background: rgba(255, 255, 255, 0.14); }
.hud-detector .lamps i.lit { background: var(--cold); box-shadow: 0 0 calc(var(--u) * 0.4) var(--cold); }
.hud-detector .lamps i.hot { background: #fff; box-shadow: 0 0 calc(var(--u) * 0.4) var(--cold); }
.hud-detector .label { font-size: calc(var(--u) * 1.1); font-weight: 900; letter-spacing: calc(var(--u) * 0.1); color: rgba(140, 217, 255, 0.9); }
.hud-detector .prompt { font-size: calc(var(--u) * 1.4); font-weight: 900; letter-spacing: calc(var(--u) * 0.08); }
.hud-detector.caught .prompt { color: rgb(115, 255, 140); }

/* The gnomes' shuffle, drawn flat while the 3D stage has none of its own. */
.hud-shuffle {
  position: absolute;
  left: 50%;
  bottom: calc(var(--u) * 3.5);
  translate: -50% 0;
  width: calc(var(--u) * 32);
  height: calc(var(--u) * 14);
  padding: calc(var(--u) * 0.6) 0;
  border-radius: calc(var(--u) * 2.4);
  background: rgba(0, 0, 0, 0.5);
}
.hud-shuffle[hidden] { display: none; }
.hud-shuffle svg { width: 100%; height: 100%; }

/* How to answer it here, with no phone in hand (web-only). */
.hud-trick-hint {
  position: absolute;
  left: 50%;
  bottom: calc(var(--u) * 20);
  translate: -50% 0;
  padding: calc(var(--u) * 0.7) calc(var(--u) * 1.6);
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.45);
  font-size: calc(var(--u) * 1.9);
  font-weight: 700;
  color: rgba(255, 255, 255, 0.85);
  white-space: nowrap;
  text-shadow: 0 0 calc(var(--u) * 0.4) rgba(0, 0, 0, 0.7);
}
.hud-trick-hint[hidden] { display: none; }

/* ── The left hand ──
   The sword rests in the bottom corner of the hand that holds it, so for a
   left-handed player everything of theirs crosses to the right, as on the TV
   (EnemyStageView: the player's corner opposite the sword, the blows' column
   on the enemy's other side). The class is set from the phone's own setting
   (stage-fight.js setHand). */
.hud.left .hud-player { left: auto; right: calc(var(--u) * 3.5); align-items: flex-end; }
.hud.left .hud-feed { align-items: flex-end; }
.hud.left .hud-feed .feed-pill { flex-direction: row-reverse; }
.hud.left .player-name { margin: 0 calc(var(--u) * 1.2) calc(var(--u) * -0.6) 0; }
.hud.left .badge .pills { align-items: flex-end; padding-left: 0; padding-right: calc(var(--u) * 10.5 * 0.62); }
.hud.left .avatar { left: auto; right: 0; }
/* The pills grow toward the middle of the screen: from the right, leftwards. */
.hud.left .badge .pill > i { left: auto; right: 0;
  background: linear-gradient(270deg, color-mix(in srgb, var(--c) 80%, transparent), var(--c)); }
.hud.left .badge .pill > b { right: auto; left: calc(var(--h) * 0.42); }
/* His blows and his trick: named on the side away from him. */
.hud.left .disc .label { right: auto; left: calc(100% + var(--u) * 1.2); }
.hud.left .trick-item .words { right: auto; left: calc(100% + var(--u) * 1.2); text-align: left; }

/* ── The lite picture (a TV box, an old phone — enemy3d.js QUALITY) ──
   Nothing in the HUD that has to be drawn over again with a blur every
   frame: the discs' glow follows their timer (a new shadow each frame), and
   a drop-shadow filter re-rasters whatever moves under it. */
body.lite .hud .disc { box-shadow: none; }
body.lite .hud *, body.lite .hud { filter: none !important; }

/* ── A friend's screen (Батон, Оппи): nobody to fight ── */
.hud.friend .hud-enemy-hp { display: none; }
/* Hearts off him for a pet (stage-fight.js remotePet). */
.heart { position: absolute; translate: -50% -50%; font: 900 var(--size, 30px) / 1 system-ui, sans-serif; color: #ff5d8f;
  text-shadow: 0 0 calc(var(--u) * 1.2) rgba(255, 93, 143, 0.55); pointer-events: none; opacity: 0;
  animation: heart-rise 1.25s cubic-bezier(0.2, 0.7, 0.3, 1) forwards; }
@keyframes heart-rise {
  0% { opacity: 0; transform: translate(0, 0) scale(0.4); }
  18% { opacity: 1; transform: translate(calc(var(--drift, 0px) * 0.3), calc(var(--u) * -3)) scale(1.1); }
  100% { opacity: 0; transform: translate(var(--drift, 0px), calc(var(--u) * -17)) scale(0.9); }
}

/* ── The gates (stage-gate.js) ──
   Shut over the stage while the phone is on its training page or the
   dungeon's; open — the leaves swung in and the view gone through the arch —
   when the fight starts. The gates themselves are a 3D scene on one canvas
   (see-through where the way is: the arena is the fight's own canvas under
   it); the page adds only the line along the bottom, a vignette, and — for
   the lite picture, which draws no frames while it stands shut — the flames
   of the two torches. */
@font-face { font-family: "Kablammo"; src: url("assets/fonts/Kablammo-sign.woff2") format("woff2"); font-display: swap; }

#gate {
  --u: min(1vh, calc(100vw / 170));
  --flame-0: #fff3c4; --flame-1: #ffb23e; --flame-2: #ff6a1a;
  position: fixed;
  inset: 0;
  z-index: 3;
  overflow: hidden;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.45s ease 0.2s, visibility 0s 0.65s;
}
#gate[data-door="dungeon"] { --flame-0: #f6e6ff; --flame-1: #c07bff; --flame-2: #7a2bd6; }
#gate.on { opacity: 1; visibility: visible; transition: opacity 0.35s ease, visibility 0s; }
#gate.away { visibility: hidden; }

/* The scene: a 16:9 frame, covering the screen as the fight's does. */
.gate-3d { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }

/* Darker towards the edges, the eye on the doors. Gone as they open — the
   arena behind has its own. */
#gate::after { content: ""; position: absolute; inset: 0; transition: opacity 0.5s ease 0.5s;
  background: radial-gradient(ellipse 80% 86% at 50% 50%, rgba(0, 0, 0, 0) 56%, rgba(0, 0, 0, 0.46)); }
#gate.open::after { opacity: 0; transition: opacity 0.5s ease 0.15s; }

.gate-hint { position: absolute; left: 50%; bottom: 6.4%; translate: -50% 0; max-width: 78%; text-align: center; z-index: 1;
  font: 700 calc(var(--u) * 2.3) / 1.3 "Onest", system-ui, sans-serif; color: rgba(255, 255, 255, 0.86);
  text-shadow: 0 calc(var(--u) * 0.15) calc(var(--u) * 0.9) rgba(0, 0, 0, 0.95), 0 0 calc(var(--u) * 2.4) rgba(0, 0, 0, 0.7);
  transition: opacity 0.45s ease 0.9s, translate 0.45s ease 0.9s; }
#gate.open .gate-hint { opacity: 0; translate: -50% calc(var(--u) * 3); transition: opacity 0.3s ease, translate 0.3s ease; }

/* Raised out of the ground (a floor of the dungeon run — StageGate.close
   with `rise`): the scene does that itself, the run's map showing round and
   over it until the wall fills the frame. There at once, then — it's what's
   drawn that grows — with no hint to read, and the dark towards the edges
   coming on as the wall does. */
#gate.risen { transition: none; }
#gate.risen .gate-hint { display: none; }
#gate.risen:not(.open)::after { animation: gate-shade 1.1s ease-in both; }
@keyframes gate-shade { from { opacity: 0; } }

/* The lite picture's flames while it stands shut (stage-gate.js puts each
   on its torch and gives the scene's scale there, --m: a metre). They are
   the scene's own three tongues, drawn by the page — moving, and with the
   full picture, the scene draws them. */
.gate-torch { display: none; position: absolute; width: calc(var(--m, 100px) * 0.62); height: calc(var(--m, 100px) * 0.9); translate: -50% -74.4%; }
#gate.stands .gate-torch { display: block; }
.gate-torch i { position: absolute; left: 50%; bottom: 0; width: 100%; height: 100%; translate: -50% 0; transform-origin: 50% 72%;
  border-radius: 50%; opacity: 0.7; background: radial-gradient(closest-side, var(--flame-2), transparent);
  animation: gate-flame 0.62s ease-in-out infinite alternate; }
.gate-torch i:nth-child(2) { width: 64.5%; height: 73.3%; bottom: 4.4%; opacity: 0.9; animation-duration: 0.47s; animation-delay: -0.2s;
  background: radial-gradient(closest-side, var(--flame-1), transparent); }
.gate-torch i:nth-child(3) { width: 32.3%; height: 42.2%; bottom: 11.1%; opacity: 1; animation-duration: 0.36s; animation-delay: -0.1s;
  background: radial-gradient(closest-side, var(--flame-0), transparent); }
.gate-torch + .gate-torch i { animation-delay: -0.31s; }

@keyframes gate-flame {
  from { transform: scale(1.06, 0.94); }
  to { transform: scale(0.92, 1.12); }
}

/* ── The mini-games (stage-mini.js) ──
   What the TV shows of a mini-game while the phone plays it: its own scene
   on its own canvas, over everything the fight has, and one HUD for all
   seven — MiniGameHUDView on the web. It is made of the fight HUD's own
   pieces above (.pill, .disc, .feed-pill, .panel-capsule): the mode's name
   in the display face where the fight has the enemy's, its clock a lit
   tube, what just happened a notice pill, the countdown and the verdict the
   same low capsules. Laid out as the TV's stage lays it: what it is and
   what's been won along the top; along the bottom — how many it takes on
   the left, the time in the middle, the lives on the right, all three
   larger than the rest (they're read from a couch). The strike a game asks
   for is the fight's disc for an open blow, standing over the thing to
   strike (.mh-mark). The phone composes it — `hud` in its `mini` message, a
   MiniHUD — in its own language. */
#mini {
  position: fixed;
  inset: 0;
  z-index: 3;
  background: #060706;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.35s ease, visibility 0s 0.35s;
}
body.mini #mini { opacity: 1; visibility: visible; transition: opacity 0.35s ease, visibility 0s; }
/* A run's mini-game comes up behind the gates like a fight (stage.html
   mini.arrive): under the map — which is cut through where they open —
   until they're out of the way. */
body.arriving #mini { z-index: 1; }
/* A mini-game's HUD keeps BOTH bottom corners (how many it takes, the lives):
   the page's own tools stand over its bottom row, clear of either. */
body.mini #corner, body.mini.left-hand:not(.idle) #corner { left: auto; right: 16px; align-items: flex-end;
  bottom: calc(min(1vh, 0.75vw) * 16); }
.mini-canvas { object-fit: cover; transition: opacity 0.5s ease; }
.mini-canvas.is-loading { opacity: 0; }

.mini-hud {
  --gold: rgb(255, 209, 89);
  --danger: rgb(255, 115, 102);
  --ac: rgb(255, 204, 102);
  display: flex;
  flex-direction: column;
  padding: calc(var(--u) * 3.5) calc(var(--u) * 4);
  /* Only as much scrim as the type needs. */
  background: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0) 33%, rgba(0, 0, 0, 0) 66%, rgba(0, 0, 0, 0.55));
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}
.mh-icon { width: 1.05em; height: 1.05em; flex: none; fill: currentColor; }
.mh-icon .s { fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }
.mh-icon .k { fill: none; stroke: rgba(0, 0, 0, 0.72); stroke-width: 2.8; stroke-linecap: round; }
.mh-coin .k { stroke-width: 2.6; }
.mini-hud .pill > i { transition: width 0.12s linear; }
.mini-hud .hud-edge { z-index: -1; }

/* The strike asked for, over the thing that asks for it: the fight's disc,
   put by the scene where its anchor lands on the page (MiniStage.arrow). */
.mh-over { position: absolute; inset: 0; pointer-events: none; }
.mh-mark { position: absolute; left: 0; top: 0; margin: calc(var(--s) / -2) 0 0 calc(var(--s) / -2); color: #fff;
  box-shadow: 0 0 calc(var(--s) * 0.2) color-mix(in srgb, var(--a) calc(40% + 50% * var(--p)), transparent); }
.mh-mark svg { inset: 31%; width: 38%; height: 38%; }
.mh-mark.blocked { box-shadow: 0 0 calc(var(--s) * 0.33) color-mix(in srgb, var(--block) 95%, transparent); }
.mh-mark.blocked svg { animation: none; }
.mh-mark.away { animation: none; scale: 0.5; opacity: 0; transition: scale 0.16s ease-out, opacity 0.16s ease-out; }
.mini-hud.ended .mh-over { opacity: 0; transition: opacity 0.25s ease; }

/* The header: what it is, on the left; what's been won, on the right. */
.mh-top { display: grid; gap: calc(var(--u) * 1.1); }
.mh-head { display: flex; align-items: flex-start; gap: calc(var(--u) * 1.6); }
.mh-left { display: grid; justify-items: start; gap: calc(var(--u) * 0.9); min-width: 0; }
.mh-right { display: grid; justify-items: end; gap: calc(var(--u) * 0.9); margin-left: auto; }
.mh-title { display: flex; align-items: baseline; gap: calc(var(--u) * 1.2); white-space: nowrap;
  text-shadow: 0 0 calc(var(--u) * 0.6) rgba(0, 0, 0, 0.75); }
.mh-title .name { font-family: "Zagadka", serif; font-weight: 400; font-size: calc(var(--u) * 5.4); letter-spacing: calc(var(--u) * 0.15);
  line-height: 1; color: var(--ac); }
.mh-title .cap { font-size: calc(var(--u) * 1.9); font-weight: 700; letter-spacing: calc(var(--u) * 0.3); text-transform: uppercase;
  color: rgba(255, 255, 255, 0.7); }
/* The bottom row every game shares: how many it takes on the left, the time
   in the middle (of the whole row, whatever the corners weigh), the lives on
   the right — in their own, larger units: the middle's and the corners'. */
.mh-bottom { --bu: calc(var(--u) * 1.6); --cu: calc(var(--u) * 2); display: grid; grid-template-columns: 1fr auto 1fr; align-items: end;
  gap: calc(var(--u) * 2); width: 100%; }
.mh-reps { display: grid; justify-items: start; gap: calc(var(--cu) * 0.9); }
.mh-time { display: grid; justify-items: center; gap: calc(var(--bu) * 0.9); }
.mh-lives { display: grid; justify-items: end; gap: calc(var(--cu) * 0.9); }
.mh-bar { --h: calc(var(--bu) * 3.4); --c: var(--ac); width: calc(var(--bu) * 32); height: var(--h);
  filter: drop-shadow(0 calc(var(--u) * 0.3) calc(var(--u) * 1) rgba(0, 0, 0, 0.45)); }
.mh-bar.urgent { --c: var(--danger); }
.mh-progress { --h: calc(var(--bu) * 2.4); --c: var(--ac); width: calc(var(--bu) * 32); height: var(--h);
  filter: drop-shadow(0 calc(var(--u) * 0.3) calc(var(--u) * 1) rgba(0, 0, 0, 0.45)); }
.mh-steps { --h: calc(var(--cu) * 3.4); --c: var(--ac); width: calc(var(--cu) * 14); height: var(--h);
  filter: drop-shadow(0 calc(var(--u) * 0.3) calc(var(--u) * 1) rgba(0, 0, 0, 0.45)); }
.mh-dots, .mh-marks { display: flex; align-items: center; border-radius: 999px; background: rgba(0, 0, 0, 0.42); }
.mh-dots { gap: calc(var(--cu) * 0.8); padding: calc(var(--cu) * 1) calc(var(--cu) * 1.5); }
.mh-dots b { width: calc(var(--cu) * 1.5); height: calc(var(--cu) * 1.5); border-radius: 50%; background: rgba(255, 255, 255, 0.2);
  transition: background 0.2s ease, scale 0.3s cubic-bezier(0.3, 1.6, 0.6, 1), box-shadow 0.2s ease; }
.mh-dots.many { gap: calc(var(--cu) * 0.6); }
.mh-dots.many b { width: calc(var(--cu) * 1.2); height: calc(var(--cu) * 1.2); }
.mh-dots.count { gap: calc(var(--cu) * 0.9); font-size: calc(var(--cu) * 2.4); font-weight: 900; line-height: 1; }
.mh-dots b[style*="--on:1"], .mh-dots b[style*="--on: 1"] { background: var(--ac); scale: 1.12; box-shadow: 0 0 calc(var(--u) * 0.9) color-mix(in srgb, var(--ac) 70%, transparent); }
.mh-dots.gold b[style*="--on:1"], .mh-dots.gold b[style*="--on: 1"] { background: var(--gold); box-shadow: 0 0 calc(var(--u) * 0.9) color-mix(in srgb, var(--gold) 70%, transparent); }
.mh-marks { gap: calc(var(--cu) * 0.9); padding: calc(var(--cu) * 0.9) calc(var(--cu) * 1.5); font-size: calc(var(--cu) * 2.4); color: rgba(255, 255, 255, 0.32); }
.mh-marks .on { color: var(--danger); }
.mh-marks .on.new { animation: mh-pop 0.3s cubic-bezier(0.3, 1.8, 0.6, 1); }
.mh-marks.drop { color: rgba(255, 255, 255, 0.25); }
.mh-marks.drop .on { color: rgb(191, 51, 89); animation: none; }

.mh-score { display: flex; align-items: center; gap: calc(var(--u) * 0.9); padding: calc(var(--u) * 0.8) calc(var(--u) * 2); border-radius: 999px;
  background: rgba(0, 0, 0, 0.45); box-shadow: inset 0 0 0 max(1px, calc(var(--u) * 0.15)) rgba(255, 255, 255, 0.16);
  font-size: calc(var(--u) * 4); font-weight: 900; line-height: 1; white-space: nowrap; }
.mh-score.accent { color: var(--ac); }
.mh-score.gold { color: var(--gold); }
.mh-score b { font-weight: 900; animation: mh-tick 0.2s ease-out; }
.mh-score .mh-coin { font-size: calc(var(--u) * 2.8); }
.mh-counters { display: flex; align-items: center; gap: calc(var(--u) * 1); }
.mh-counters .feed-pill { animation: none; }
.mh-gap { flex: 1; }
.mh-streak { --dot: var(--ac); flex-direction: row-reverse; box-shadow: inset 0 0 0 max(1px, calc(var(--u) * 0.15)) color-mix(in srgb, var(--ac) 50%, transparent);
  animation: mh-pop 0.3s cubic-bezier(0.3, 1.8, 0.6, 1) !important; }

/* The scene shows through the middle. Three, two, one — the fight's own
   capsule — stands low, in the foot, as the stage fight's does. */
.mh-mid { flex: 1; min-height: 0; }
.mh-ready { display: grid; place-items: center; }
.mh-ready:empty { display: none; }
.mh-count { position: relative; }
.mh-count .mh-drain { position: absolute; inset: 8%; width: 84%; height: 84%; rotate: -90deg; overflow: visible; fill: none; }
.mh-drain circle { fill: none; stroke-width: 9; }
.mh-drain .track { stroke: rgba(255, 255, 255, 0.14); }
.mh-drain .arc { stroke: var(--a); stroke-linecap: round; stroke-dasharray: 276.5; animation: mh-drain 1s linear both; }
.mh-count b { position: relative; font-weight: 900; animation: mh-count 0.3s cubic-bezier(0.3, 1.7, 0.6, 1) both; }
/* How it ended: the fight's verdict capsule, low in the frame, the rest of
   the HUD gone — the scene's own finale plays out above it. A record rides
   over it as a notice; past a hairline, what the round paid. */
.mini-hud .mh-top, .mini-hud .mh-foot { transition: opacity 0.35s ease-out; }
.mini-hud.ended .mh-top, .mini-hud.ended .mh-foot { opacity: 0; }
.mh-end { position: absolute; left: 50%; bottom: calc(var(--u) * 3.5); translate: -50% 0; display: grid; justify-items: center;
  gap: calc(var(--u) * 1.2); }
.mh-record { box-shadow: inset 0 0 0 max(1px, calc(var(--u) * 0.15)) color-mix(in srgb, var(--dot) 50%, transparent);
  animation: mh-pop 0.3s cubic-bezier(0.3, 1.5, 0.6, 1) 0.25s both; }
.mh-rule { flex: none; width: max(1px, calc(var(--u) * 0.2)); height: calc(var(--u) * 5.6); border-radius: 999px; background: rgba(255, 255, 255, 0.2); }
.mh-paid { display: flex; align-items: center; gap: calc(var(--u) * 1); font-size: calc(var(--u) * 4.4); font-weight: 900; color: var(--gold);
  text-shadow: 0 0 calc(var(--u) * 0.4) rgba(0, 0, 0, 0.6); }
.mh-paid .mh-coin { font-size: calc(var(--u) * 3.4); }

/* The foot: the last word — a notice pill — what the game says to do now,
   then the bottom row. */
.mh-foot { display: grid; justify-items: center; gap: calc(var(--u) * 1.4); }
.mh-flash { height: calc(var(--u) * 4.6); display: grid; place-items: center; }
.mh-flash .feed-pill.notice { animation: mh-word 2.4s ease both; }
.mh-rows { display: flex; align-items: flex-end; justify-content: center; gap: calc(var(--u) * 3); width: 100%; }
.mh-stack { display: grid; justify-items: center; gap: calc(var(--u) * 1.2); min-width: 0; }
.mh-stack:empty { display: none; }
.mh-chips { display: flex; align-items: center; justify-content: center; gap: calc(var(--u) * 1.4); }
/* A strike asked for, as the fight draws an open blow or the room's event:
   a disc with its arrow, the clock hand filling as its window runs out (a
   demand with no window is simply lit), its name beside it. */
.mh-chip { display: flex; align-items: center; gap: calc(var(--u) * 1.2); padding: calc(var(--u) * 0.7) calc(var(--u) * 2.4) calc(var(--u) * 0.7) calc(var(--u) * 0.7);
  border-radius: 999px; background: rgba(0, 0, 0, 0.4); white-space: nowrap; font-size: calc(var(--u) * 2.6); font-weight: 700; text-transform: uppercase;
  text-shadow: 0 0 calc(var(--u) * 0.5) rgba(0, 0, 0, 0.85); animation: mh-pop 0.28s cubic-bezier(0.3, 1.5, 0.6, 1) both; }
.mh-chip .disc { --s: calc(var(--u) * 6.4); flex: none; color: #fff; animation: none; }
.mh-chip .disc svg { inset: 26%; width: 48%; height: 48%; }
.mh-turn { --dot: var(--ac); flex-direction: row; box-shadow: inset 0 0 0 max(1px, calc(var(--u) * 0.15)) color-mix(in srgb, var(--ac) 50%, transparent) !important;
  animation: mh-pop 0.28s cubic-bezier(0.3, 1.5, 0.6, 1) both !important; }
.mh-sub { font-size: calc(var(--u) * 2.8); font-weight: 900; text-shadow: 0 0 calc(var(--u) * 0.5) rgba(0, 0, 0, 0.85); }
.mh-text { font-size: calc(var(--u) * var(--s, 3)); font-weight: 900; color: #bfbfbf; text-align: center; text-shadow: 0 0 calc(var(--u) * 0.5) rgba(0, 0, 0, 0.85);
  animation: mh-fade 0.25s ease both; }
.mh-text.accent { color: var(--ac); }
.mh-text.gold { color: var(--gold); animation: mh-pop 0.28s cubic-bezier(0.3, 1.5, 0.6, 1) both; }
.mh-text.danger { color: var(--danger); letter-spacing: calc(var(--u) * 0.4); animation: mh-pop 0.28s cubic-bezier(0.3, 1.5, 0.6, 1) both; }
.mh-meter { --c: var(--ac); width: calc(var(--bu) * var(--w, 26)); height: var(--h); }
.mh-meter.danger { --c: var(--danger); }
.mh-meter.gold { --c: var(--gold); }
.mh-meter.dim { --c: rgba(255, 255, 255, 0.6); }
/* The lives as one bar (the corridor's health): a heart, and a pill that
   empties toward it — its number at the near end. */
.mh-hp { display: flex; align-items: center; gap: calc(var(--cu) * 1);
  filter: drop-shadow(0 calc(var(--u) * 0.4) calc(var(--u) * 1.2) rgba(0, 0, 0, 0.45)); }
.mh-hp > .mh-icon { font-size: calc(var(--cu) * 2.4); color: var(--health); }
.mh-hp .pill { --h: calc(var(--cu) * 3.4); --c: var(--health); width: calc(var(--cu) * 14); height: var(--h); }
.mh-hp .pill > i { left: auto; right: 0; background: linear-gradient(270deg, color-mix(in srgb, var(--c) 80%, transparent), var(--c));
  transition: width 0.25s ease-out; }
.mh-hp .pill > b { right: auto; left: calc(var(--h) * 0.42); }
/* The goblet's spirit level, as one of the discs: the rim warms as a spill
   nears, the dot is where the wine leans. */
.mh-level { --ring: rgba(255, 255, 255, 0.85); position: relative; flex: none; width: calc(var(--u) * 13); height: calc(var(--u) * 13); border-radius: 50%;
  background: rgba(0, 0, 0, 0.6); box-shadow: inset 0 0 0 calc(var(--u) * 0.65) var(--ring), 0 0 calc(var(--u) * 1.2) rgba(0, 0, 0, 0.4);
  transition: box-shadow 0.2s ease; }
.mh-level.gold { --ring: var(--gold); box-shadow: inset 0 0 0 calc(var(--u) * 0.65) var(--ring), 0 0 calc(var(--u) * 1.2) color-mix(in srgb, var(--gold) 60%, transparent); }
.mh-level.danger { --ring: var(--danger); box-shadow: inset 0 0 0 calc(var(--u) * 0.65) var(--ring), 0 0 calc(var(--u) * 1.2) color-mix(in srgb, var(--danger) 60%, transparent); }
.mh-level::before { content: ""; position: absolute; inset: 20%; border-radius: 50%; box-shadow: inset 0 0 0 max(1px, calc(var(--u) * 0.15)) rgba(255, 255, 255, 0.15); }
.mh-level i { position: absolute; left: 50%; top: 50%; width: calc(var(--u) * 2.6); height: calc(var(--u) * 2.6); margin: calc(var(--u) * -1.3);
  border-radius: 50%; background: rgb(191, 51, 89); box-shadow: 0 0 calc(var(--u) * 0.9) rgba(191, 51, 89, 0.8);
  translate: calc(var(--x, 0) * var(--u) * 4.8) calc(var(--y, 0) * var(--u) * -4.8); transition: translate 0.07s linear; }

@keyframes mh-pop { from { opacity: 0; scale: 0.82; } }
@keyframes mh-fade { from { opacity: 0; } }
@keyframes mh-tick { from { scale: 1.14; } }
@keyframes mh-count { from { opacity: 0; scale: 0.5; } }
@keyframes mh-drain { from { stroke-dashoffset: 0; } to { stroke-dashoffset: 276.5; } }
@keyframes mh-word { 0% { opacity: 0; scale: 0.85; } 8% { opacity: 1; scale: 1; } 78% { opacity: 1; } 100% { opacity: 0; } }

/* ── The dungeon run's map (stage-map.js) ──
   Between a run's floors: the game's board of it, the phone's own run laid
   on it — under the gates, which rise over it when a floor's fight starts.
   Its labels ride one layer, moved and scaled with the board's camera
   (--m: a unit of the board in pixels, at the map's own distance). */
#map {
  --u: min(1vh, 0.75vw);
  position: fixed;
  inset: 0;
  z-index: 2;
  overflow: hidden;
  pointer-events: none;
  background: #08070a;
  font-family: "Onest", -apple-system, system-ui, sans-serif;
  color: #fff;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.5s ease, visibility 0s 0.5s;
}
#map.on { opacity: 1; visibility: visible; transition: opacity 0.5s ease, visibility 0s; }
.map-3d { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
/* Darker towards the edges, and under the plaque. */
#map::after { content: ""; position: absolute; inset: 0;
  background: radial-gradient(ellipse 84% 90% at 50% 46%, rgba(0, 0, 0, 0) 55%, rgba(0, 0, 0, 0.5)),
    linear-gradient(to top, rgba(0, 0, 0, 0.55), rgba(0, 0, 0, 0) 26%); }
.map-tags { position: absolute; left: 0; top: 0; transform-origin: 0 0; will-change: transform; transition: opacity 0.25s ease; }
/* A floor's number, on its piece's near corner. */
.map-tag {
  position: absolute;
  left: calc((var(--x) + var(--dx, 0)) * var(--m));
  top: calc((var(--y) + var(--dy, 1.02)) * var(--m));
  translate: -50% -50%;
  display: inline-flex;
  align-items: center;
  gap: calc(var(--u) * 0.7);
  height: calc(var(--u) * 3.6);
  padding: 0 calc(var(--u) * 1.3);
  border-radius: 999px;
  background: rgba(19, 16, 23, 0.94);
  box-shadow: inset 0 0 0 1px rgba(240, 226, 255, 0.18);
  font-size: calc(var(--u) * 2);
  font-weight: 800;
  color: rgba(246, 232, 200, 0.6);
  white-space: nowrap;
}
.map-tag b { font-weight: 800; }
.map-tag i { font: 400 calc(var(--u) * 2.1) / 1 "Zagadka", "Onest", serif; color: #fff; padding: calc(var(--u) * 0.35) calc(var(--u) * 0.9);
  border-radius: 999px; background: #2a2638; }
.map-tag.is-ahead { height: calc(var(--u) * 4.6); font-size: calc(var(--u) * 2.5); color: #fff;
  background: rgb(94, 54, 160); box-shadow: inset 0 0 0 1px rgba(240, 226, 255, 0.4), 0 0 calc(var(--u) * 2.2) rgba(184, 121, 255, 0.55); }
.map-tag.is-boss { color: #ffd98a; }
.map-tag.is-boss.is-ahead { background: rgb(150, 104, 22); box-shadow: inset 0 0 0 1px rgba(255, 236, 190, 0.5), 0 0 calc(var(--u) * 2.2) rgba(255, 204, 92, 0.6); }
.map-tag.is-mini.is-ahead { background: rgb(170, 88, 28); box-shadow: inset 0 0 0 1px rgba(255, 226, 200, 0.45), 0 0 calc(var(--u) * 2.2) rgba(255, 150, 70, 0.55); }
/* The merchant's stall: his sign — grey where he has been, gold and named
   where he is. */
.map-tag svg { width: 1.05em; height: 1.05em; flex: none; }
.map-tag.is-stall { padding: 0 calc(var(--u) * 0.9); color: rgba(246, 232, 200, 0.42); }
/* (Over his awning — the piece's near corner is under the plaque when it's
   the one before the floor ahead, which is when he's open.) */
.map-tag.is-stall.is-open { --dx: -0.59; --dy: -1.74; height: calc(var(--u) * 4.6); padding: 0 calc(var(--u) * 1.5) 0 calc(var(--u) * 1.2); font-size: calc(var(--u) * 2.3);
  color: #2b1a02; background: linear-gradient(180deg, rgb(255, 214, 110), rgb(236, 170, 52));
  box-shadow: inset 0 0 0 1px rgba(255, 244, 210, 0.6), 0 0 calc(var(--u) * 2.2) rgba(255, 204, 92, 0.55); }
/* The floor ahead, along the bottom: «Этаж N», who holds it. */
.map-plaque { position: absolute; left: 50%; bottom: calc(var(--u) * 3.5); translate: -50% 0; z-index: 1; transition: opacity 0.25s ease, translate 0.3s ease; }
.map-plaque .sign { font-size: calc(var(--u) * 3.8); }
/* A run won (StageMap.finale): its title over the summit — the game's own
   victory title — and along the bottom, in the plaque's place, how it
   ended: the ascension it was won at and, opened by it, the next. Both
   wait for the crystal. */
.map-title { position: absolute; left: 50%; top: calc(var(--u) * 6.5); z-index: 1; translate: -50% 0; white-space: nowrap;
  font: 400 calc(var(--u) * 9.5) / 1.1 "Zagadka", "Onest", serif;
  background: linear-gradient(180deg, #fff, rgb(204, 178, 255)); -webkit-background-clip: text; background-clip: text; color: transparent;
  filter: drop-shadow(0 0 calc(var(--u) * 1.8) rgba(118, 66, 238, 0.9));
  opacity: 0; scale: 0.82; transition: opacity 0.6s ease, scale 0.7s cubic-bezier(0.3, 1.4, 0.6, 1); }
#map.is-top .map-title { background-image: linear-gradient(180deg, rgb(255, 245, 209), rgb(255, 199, 92));
  filter: drop-shadow(0 0 calc(var(--u) * 1.8) rgba(255, 150, 20, 0.75)); }
#map.finale.told .map-title { opacity: 1; scale: 1; }
#map.finale .map-plaque { opacity: 0; translate: -50% calc(var(--u) * 5); }
#map.finale.carded .map-plaque { opacity: 1; translate: -50% 0; }
.map-done { gap: calc(var(--u) * 1.6); }
.map-done .sign b { font-weight: 900; }
.map-done .sign svg { position: absolute; left: 50%; top: 0; width: 48%; height: auto; translate: -50% -72%; color: rgb(255, 222, 140);
  filter: drop-shadow(0 calc(var(--u) * 0.2) calc(var(--u) * 0.4) rgba(0, 0, 0, 0.5)); }
.map-done .sign.is-was { background: rgba(255, 255, 255, 0.14); box-shadow: inset 0 0 0 max(1px, calc(var(--u) * 0.3)) rgba(255, 255, 255, 0.3);
  color: rgba(255, 255, 255, 0.7); }
.map-done .step { display: grid; place-items: center; width: calc(var(--u) * 3.6); color: rgba(255, 255, 255, 0.55); }
.map-done .step svg { width: 100%; height: auto; }
.map-done .word { font-size: calc(var(--u) * 3.9); letter-spacing: calc(var(--u) * 0.12); margin-left: calc(var(--u) * 0.8); }
.map-done .who { margin-left: calc(var(--u) * 0.8); }
.map-done .note { font-size: calc(var(--u) * 2.5); font-weight: 600; }
.map-done .note:empty { display: none; }
/* The gates on the board (StageMap.dive): where they open the board's
   picture is cut through to the fight's own canvas under it — nothing of
   this layer's own behind the picture, nor over it. */
#map.hosting { background: none; }
#map::after { transition: opacity 0.6s ease; }
#map.hosting::after { opacity: 0; }
/* The camera on its way down to a room: nothing to read on the way. */
#map.flying .map-tags, #map.flying .map-plaque { opacity: 0; }
#map.flying .map-plaque { translate: -50% calc(var(--u) * 5); }

/* ── The loader ──
   Something the screen is waiting for is still being read in — a fight's
   room and enemy, the run's map, a mini-game's stage, the title's yard —
   which on a first visit, with nothing kept by the browser yet, is seconds
   (stage.html `loader`: up only when it takes more than a moment). The
   game's own way in, as its launch has it: a portal turning in its stone
   ring, light wound into its dark middle and sparks drawn in after it —
   and round it, in gold, how much has come. All of it the stylesheet's:
   the GPU is busy with what's being loaded. */
#loader {
  --u: min(1vh, 0.75vw);
  position: fixed;
  inset: 0;
  z-index: 7;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: calc(var(--u) * 3);
  background: radial-gradient(ellipse 75% 75% at 50% 46%, rgba(38, 24, 66, 0.9), rgba(7, 6, 10, 0.97) 72%);
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.45s ease, visibility 0s 0.45s;
}
#loader.on { opacity: 1; visibility: visible; transition: opacity 0.3s ease, visibility 0s; }
.portal { position: relative; width: calc(var(--u) * 30); aspect-ratio: 1; }
.portal > i, .portal > span, .portal > svg { position: absolute; inset: 0; border-radius: 50%; }
/* Its light on the dark round it, breathing. */
.portal .glow { inset: -26%; background: radial-gradient(closest-side, rgba(170, 110, 255, 0.5), rgba(120, 62, 220, 0.16) 56%, rgba(0, 0, 0, 0)); }
/* The ring: cut stones, a dark joint between each, turning slowly. */
.portal .ring { inset: 3%;
  background: repeating-conic-gradient(from 3deg, #474260 0deg 19deg, #1c192b 19deg 22.5deg);
  -webkit-mask: radial-gradient(closest-side, rgba(0, 0, 0, 0) 76%, #000 77.5%, #000 98%, rgba(0, 0, 0, 0) 100%);
  mask: radial-gradient(closest-side, rgba(0, 0, 0, 0) 76%, #000 77.5%, #000 98%, rgba(0, 0, 0, 0) 100%);
  box-shadow: inset 0 0 calc(var(--u) * 2) rgba(0, 0, 0, 0.6); }
/* The whirl: three arms of light winding into the middle, a second set
   under them turning the other way. */
.portal .whirl { inset: 15%;
  background: conic-gradient(from 0deg, rgba(0, 0, 0, 0) 0 6%, rgba(222, 184, 255, 0.95) 20%, rgba(0, 0, 0, 0) 33%,
    rgba(150, 92, 255, 0.9) 53%, rgba(0, 0, 0, 0) 66%, rgba(244, 226, 255, 0.92) 86%, rgba(0, 0, 0, 0) 96%);
  -webkit-mask: radial-gradient(closest-side, #000 30%, rgba(0, 0, 0, 0.8) 70%, rgba(0, 0, 0, 0) 100%);
  mask: radial-gradient(closest-side, #000 30%, rgba(0, 0, 0, 0.8) 70%, rgba(0, 0, 0, 0) 100%);
  filter: blur(calc(var(--u) * 0.55)); }
.portal .whirl.under { inset: 21%; opacity: 0.6; }
/* The dark it all goes into. */
.portal .eye { inset: 37%; background: radial-gradient(closest-side, #05030a 58%, rgba(64, 32, 128, 0.92) 84%, rgba(0, 0, 0, 0));
  box-shadow: 0 0 calc(var(--u) * 2.6) rgba(198, 154, 255, 0.85); }
/* Sparks, each on its own turn of the spiral inwards. */
.portal .sparks i { position: absolute; left: 50%; top: 50%; width: calc(var(--u) * 0.8); height: calc(var(--u) * 0.8);
  margin: calc(var(--u) * -0.4); border-radius: 50%; background: #f6eaff; opacity: 0;
  box-shadow: 0 0 calc(var(--u) * 1.1) calc(var(--u) * 0.2) rgba(200, 150, 255, 0.9); }
/* How much has come: a gold line round the ring, from the top. */
.portal svg { inset: -7%; rotate: -90deg; overflow: visible; }
.portal circle { fill: none; stroke: rgba(255, 255, 255, 0.09); stroke-width: 1.6; }
.portal circle.come { stroke: #ffd98a; stroke-width: 2.2; stroke-linecap: round; stroke-dasharray: 100;
  stroke-dashoffset: calc(100 - var(--p, 0) * 100); transition: stroke-dashoffset 0.35s ease, opacity 0.3s ease;
  filter: drop-shadow(0 0 calc(var(--u) * 0.5) rgba(255, 196, 96, 0.9)); }
#loader:not(.counts) .portal circle.come { opacity: 0; }
.loader-word { font: 400 calc(var(--u) * 6.2) / 1 "Zagadka", "Onest", serif; color: #efe3ff; white-space: nowrap;
  text-shadow: 0 calc(var(--u) * 0.45) 0 #2b1d4d, 0 0 calc(var(--u) * 2.4) rgba(180, 120, 255, 0.75); }
/* What it's waiting for: the scene's name (stage.html `loader.begin`). */
.loader-what { min-height: 1.2em; margin-top: calc(var(--u) * -1.2); font: 700 calc(var(--u) * 2.5) / 1.2 "Onest", system-ui, sans-serif;
  letter-spacing: 0.01em; color: rgba(232, 216, 255, 0.78); text-align: center; white-space: nowrap; }
.loader-share { min-height: 1em; font: 800 calc(var(--u) * 2.1) / 1 "Onest", system-ui, sans-serif; letter-spacing: 0.08em;
  color: rgba(255, 226, 180, 0.82); font-variant-numeric: tabular-nums; }
#loader.on .portal .glow { animation: portal-breathe 2.6s ease-in-out infinite; }
#loader.on .portal .ring { animation: portal-turn 26s linear infinite; }
#loader.on .portal .whirl { animation: portal-turn 2.3s linear infinite; }
#loader.on .portal .whirl.under { animation: portal-turn 3.7s linear infinite reverse; }
#loader.on .portal .sparks i { animation: portal-spark 1.9s cubic-bezier(0.5, 0, 0.9, 0.6) calc(var(--i) * -0.2375s) infinite; }
@keyframes portal-turn { to { rotate: 360deg; } }
@keyframes portal-breathe { 50% { scale: 1.08; opacity: 0.78; } }
@keyframes portal-spark {
  0% { transform: rotate(calc(var(--i) * 45deg)) translateX(calc(var(--u) * 18)) scale(1); opacity: 0; }
  14% { opacity: 1; }
  100% { transform: rotate(calc(var(--i) * 45deg + 230deg)) translateX(calc(var(--u) * 3.4)) scale(0.25); opacity: 0; }
}
/* The weak machine's: no blur to draw every frame, half the sparks. */
body.lite .portal .whirl { filter: none; }
body.lite .portal .sparks i:nth-child(even) { display: none; }
@media (prefers-reduced-motion: reduce) {
  #loader.on .portal .whirl, #loader.on .portal .whirl.under { animation-duration: 14s; }
  #loader.on .portal .sparks i, #loader.on .portal .glow { animation: none; }
}

/* ── A browser a few years behind: a TV's own (Chromium 94–110) ───────────
   The page runs there, and two things it's written with didn't: the bars'
   colours and where everything stands (audit 2026-10-10). Both said again
   here in older words, for such a browser only — one that knows the newer
   ones never reads these.

   color-mix(): with a var() in it a declaration isn't thrown out as it's
   read but when it's worked out — so nothing written before it steps in,
   and the bars had no fill at all. Here the fill is the plain colour, and
   the glows (which were only glows) are gone. */
@supports not (color: color-mix(in srgb, red, blue)) {
  .pill > i, .hud.left .badge .pill > i, .mh-hp .pill > i { background: var(--c); box-shadow: none; }
  .panel-capsule .sign { background: var(--a); box-shadow: inset 0 0 0 max(1px, calc(var(--u) * 0.5)) rgba(255, 255, 255, 0.85); }
  .mh-level.gold, .mh-level.danger { box-shadow: inset 0 0 0 calc(var(--u) * 0.65) var(--ring); }
}
/* translate / rotate / scale as properties of their own (Chromium 104): what
   is centred on its point with them hung off it instead — the enemy's
   health, the attacks, the capsule at the foot, every mark of the map. The
   same places as one `transform` each. (What's ANIMATED with those
   properties simply doesn't move there; where it stands is right.) */
@supports not (translate: 0px) {
  .pill > b { transform: translate(0, -50%); }
  .hud-enemy-hp { transform: translate(-50%, -50%); }
  .hud-attacks { transform: translate(-50%, -50%); }
  .disc .label { transform: translate(0, -50%); }
  .hud-event { transform: translate(-50%, 0); }
  .hud-event[hidden] { transform: translate(-50%, calc(var(--u) * -6)); }
  .badge .pills { transform: translate(0, calc(var(--u) * 0.2)); }
  .avatar { transform: translate(0, -50%); }
  .damage { transform: translate(-50%, -50%); }
  .hud-bottom { transform: translate(-50%, 0); }
  .hud-trick { transform: translate(-50%, -50%); }
  .trick-item .words { transform: translate(0, -50%); }
  .hud-needle { transform: translate(-50%, -50%); }
  .hud-needle.out { transform: translate(-50%, calc(-50% - var(--u) * 8)); }
  .hud-detector { transform: translate(-50%, 0); }
  .hud-shuffle { transform: translate(-50%, 0); }
  .hud-trick-hint { transform: translate(-50%, 0); }
  .heart { transform: translate(-50%, -50%); }
  .gate-hint { transform: translate(-50%, 0); }
  #gate.open .gate-hint { transform: translate(-50%, calc(var(--u) * 3)); }
  .gate-torch { transform: translate(-50%, -74.4%); }
  .gate-torch i { transform: translate(-50%, 0); }
  .mh-dots b[style*="--on:1"], .mh-dots b[style*="--on: 1"] { transform: scale(1.12); }
  .mh-count .mh-drain { transform: rotate(-90deg); }
  .mh-end { transform: translate(-50%, 0); }
  .mh-level i { transform: translate(calc(var(--x, 0) * var(--u) * 4.8), calc(var(--y, 0) * var(--u) * -4.8)); }
  .map-tag { transform: translate(-50%, -50%); }
  .map-plaque { transform: translate(-50%, 0); }
  .map-title { transform: translate(-50%, 0) scale(0.82); }
  #map.finale.told .map-title { transform: translate(-50%, 0) scale(1); }
  #map.finale .map-plaque { transform: translate(-50%, calc(var(--u) * 5)); }
  #map.finale.carded .map-plaque { transform: translate(-50%, 0); }
  .map-done .sign svg { transform: translate(-50%, -72%); }
  #map.flying .map-plaque { transform: translate(-50%, calc(var(--u) * 5)); }
  .portal svg { transform: rotate(-90deg); }
}
