/* ═══════════════════════════════════════════════════════════════════════════
   In-game HUD (the screen you see WHILE PLAYING — the menu, dashboards and results screen keep the
   comic style in index.html). Owner request: no hard "shadow box" effect, a Street-Fighter-style
   Spirit bar with the label inside it, a Might plate that matches, a leaderboard that can shrink to
   the top 2 + you, and Twitch-style messages that slide in at the top right.

   Rules for this file (server/test/ui.test.js enforces the first):
     • No hard offset shadows (a "Npx Npx 0 colour" box-shadow). Glows and soft ambient shadows only.
     • Motion is decoration: every animation has a calm fallback under prefers-reduced-motion.
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
  --h-glass: rgba(14, 10, 34, .66);
  --h-glass-strong: rgba(14, 10, 34, .82);
  --h-line: rgba(255, 255, 255, .17);
  --h-dim: rgba(255, 255, 255, .62);
  --h-gold: #ffd23f;
  --h-cyan: #37e2ff;
  --h-ink: var(--ink, #1a0f2e); /* the comic outline colour of the rest of the game */
  --h-outline: 2.5px; /* the thin black comic outline drawn around gradient-bordered buttons */
  --h-safe-top: env(safe-area-inset-top, 0px);
  --h-safe-right: env(safe-area-inset-right, 0px);
  --h-safe-left: env(safe-area-inset-left, 0px);
  --h-safe-bottom: env(safe-area-inset-bottom, 0px);
  --feed-top: 12px;
}

#hud {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 10;
  opacity: 0;
  transition: opacity .45s;
  font-family: 'Quicksand', 'Fredoka', sans-serif;
  color: #fff;
}

#hud.show {
  opacity: 1;
}

/* ───────────── Survival: countdown / zone bar (top centre) + the red edge when you stand outside the zone ───────────── */

#survBar {
  position: absolute;
  top: calc(12px + var(--h-safe-top));
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 6px 16px;
  background: var(--h-glass);
  border: 1px solid var(--h-line);
  border-radius: 999px;
  font-weight: 800;
  font-size: 13px;
  letter-spacing: .06em;
  white-space: nowrap;
}
#survBar.hidden { display: none; }
#survBar span:nth-child(2) { color: var(--h-gold); }
#survBar span:empty { display: none; }
#survBar.danger #survPhase { color: #ff6b7a; }

/* ───────────── Team: the 4-squad scoreboard (top centre, in place of #survBar) ───────────── */

#teamBar {
  position: absolute;
  top: calc(12px + var(--h-safe-top));
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 6px 14px;
  background: var(--h-glass);
  border: 1px solid var(--h-line);
  border-radius: 999px;
  font-weight: 800;
  font-size: 12px;
  letter-spacing: .04em;
  white-space: nowrap;
}
#teamBar.hidden { display: none; }
#teamBar .tm { display: flex; align-items: center; gap: 5px; opacity: .78; }
#teamBar .tm.mine { opacity: 1; }
#teamBar .tm i { width: 9px; height: 9px; border-radius: 50%; display: inline-block; box-shadow: 0 0 5px currentColor; }
@media (max-width: 700px) {
  /* A narrow-width flex-wrap squeezed the 4 squads into one cramped column (the max-width left
     barely enough room for one item per row). A fixed 2x2 grid — there are always exactly 4
     squads — keeps it balanced instead. */
  #teamBar { left: calc(12px + var(--h-safe-left)); transform: none; top: calc(84px + var(--h-safe-top)); max-width: min(190px, calc(100vw - 190px)); display: grid; grid-template-columns: repeat(2, auto); gap: 6px 14px; padding: 5px 12px; border-radius: 14px; font-size: 11px; white-space: nowrap; }
}

#dangerVig {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity .25s;
  background: radial-gradient(ellipse at center, rgba(255, 30, 60, 0) 42%, rgba(255, 30, 60, .5) 100%);
}
#dangerVig.on { opacity: 1; animation: dangerPulse 1s ease-in-out infinite; }
@keyframes dangerPulse { 50% { opacity: .55; } }
@media (prefers-reduced-motion: reduce) { #dangerVig.on { animation: none; } }
/* phones: the board owns the top right, so the bar sits under the Spirit bar, on two short lines */
@media (max-width: 700px) {
  #survBar { left: calc(12px + var(--h-safe-left)); transform: none; top: calc(84px + var(--h-safe-top)); max-width: min(172px, calc(100vw - 230px)); flex-wrap: wrap; gap: 2px 10px; padding: 5px 12px; border-radius: 14px; font-size: 12px; }
}

/* ───────────── Survival: watching the rest of the round after you died ───────────── */

#watchBar {
  position: absolute;
  bottom: calc(18px + var(--h-safe-bottom));
  left: 50%;
  transform: translateX(-50%);
  display: none;
  align-items: center;
  gap: 10px;
  padding: 6px 8px 6px 16px;
  background: var(--h-glass-strong);
  border: 1px solid var(--h-line);
  border-radius: 999px;
  font-weight: 800;
  font-size: 13px;
  letter-spacing: .06em;
  white-space: nowrap;
  pointer-events: auto;
}
#watchBar button {
  font: inherit;
  color: #fff;
  cursor: var(--cur-pointer);
  padding: 6px 14px;
  border-radius: 999px;
  border: 1px solid var(--h-line);
  background: rgba(255, 255, 255, .12);
}
#watchBar button:hover { background: rgba(255, 255, 255, .22); }
#watchBar #watchLeave { background: rgba(255, 59, 78, .35); }
body.watching #watchBar { display: flex; }
/* a spectator has no dragon: hide the player's own bars and touch buttons (the board, minimap and zone bar stay) */
body.watching #hudTop, body.watching #actionBar, body.watching #breathWrap { display: none !important; }
@media (max-width: 700px) { #watchBar { bottom: calc(150px + var(--h-safe-bottom)); } }

/* ───────────── top left: Might plate + Spirit bar ───────────── */

#hudTop {
  position: absolute;
  top: calc(12px + var(--h-safe-top));
  left: calc(12px + var(--h-safe-left));
  width: min(340px, 44vw);
  display: flex;
  flex-direction: column;
  gap: 7px;
}

/* Might: a slanted plate in the same language as the Spirit bar */
#mightPlate {
  position: relative;
  align-self: flex-start;
  min-width: 158px;
  padding: 5px 26px 8px 14px;
  display: flex;
  align-items: baseline;
  gap: 9px;
  background: linear-gradient(100deg, rgba(240, 130, 20, .96), rgba(226, 52, 78, .94) 70%, rgba(226, 52, 78, .5));
  clip-path: polygon(0 0, 100% 0, calc(100% - 14px) 100%, 0 100%);
  transition: filter .25s;
}

#mightPlate .lbl {
  font-family: 'Bangers', 'Fredoka', sans-serif;
  font-size: 13px;
  letter-spacing: 2.4px;
  color: rgba(26, 8, 40, .78);
  text-transform: uppercase;
}

#plVal {
  font-family: 'Bangers', 'Fredoka', sans-serif;
  font-size: 32px;
  line-height: 1;
  letter-spacing: 1px;
  color: #fff;
  font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 3px rgba(70, 0, 25, .85), 0 0 10px rgba(255, 255, 255, .35);
  transition: color .3s, transform .3s;
}

#mightPlate.gain #plVal {
  color: #eaffc8;
  transform: scale(1.08);
}

#mightPlate.loss #plVal {
  color: #fff;
  text-shadow: 0 0 12px rgba(255, 60, 60, .95), 0 1px 3px rgba(70, 0, 25, .85);
  transform: scale(.94);
}

/* thin progress line along the bottom: how close the Might is to what Ascension needs */
#mightProg {
  position: absolute;
  left: 0;
  right: 14px;
  bottom: 0;
  height: 3px;
  background: rgba(20, 6, 36, .55);
}

#mightProgFill {
  display: block;
  height: 100%;
  width: 0;
  background: linear-gradient(90deg, #fff2a8, #fff);
  transition: width .25s ease-out;
}

#mightPlate.full #mightProgFill {
  animation: h-glint 1.2s ease-in-out infinite;
}

/* Spirit: the fighting-game bar. Structure: #spiritBar > .sf (border) > .sf-track > lag / fill / ticks / shine, + the text on top. */
#spiritBar {
  position: relative;
  width: 100%;
  height: 27px;
  --glow: rgba(55, 226, 255, .5);
  filter: drop-shadow(0 0 6px var(--glow));
  transition: filter .3s;
}

#spiritBar .sf {
  position: absolute;
  inset: 0;
  padding: 2px 3px;
  background: linear-gradient(180deg, #ffffff, #93a5c4 55%, #566a8f);
  clip-path: polygon(13px 0, 100% 0, calc(100% - 13px) 100%, 0 100%);
}

#spiritBar .sf-track {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: linear-gradient(180deg, #0a0520, #1a1040);
  clip-path: polygon(11px 0, 100% 0, calc(100% - 11px) 100%, 0 100%);
}

#spiritBar .sf-fill,
#spiritBar .sf-lag {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 100%;
}

#spiritBar .sf-fill {
  background:
    linear-gradient(180deg, rgba(255, 255, 255, .55) 0 42%, rgba(255, 255, 255, 0) 43%),
    linear-gradient(180deg, #7ff3ff, #1fc4ff 50%, #0a7bff);
  transition: width .12s linear;
}

/* the "damage" trail: when Spirit is spent it drains slowly behind the bar, like a fighting-game health bar */
#spiritBar .sf-lag {
  background: linear-gradient(180deg, #fff, #ffc76a);
  transition: width .9s cubic-bezier(.2, .7, .2, 1) .22s;
}

/* One tick per full-charge shot (docs/COMBAT-V2.md "Spirit economy") — the segment width is set as
   --spirit-seg (a %) by client/main.mjs from the server's cfg (KI_MAX / full-shot cost), never hardcoded
   here. Falls back to thirds if JS hasn't set it yet. */
#spiritBar .sf-ticks {
  position: absolute;
  inset: 0;
  --spirit-seg: 33.333%;
  background: repeating-linear-gradient(90deg, transparent 0 calc(var(--spirit-seg) - 1px), rgba(6, 3, 24, .5) calc(var(--spirit-seg) - 1px) var(--spirit-seg));
  pointer-events: none;
}

#spiritBar .sf-shine {
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg, transparent 38%, rgba(255, 255, 255, .5) 50%, transparent 62%) 0 0 / 260% 100%;
  animation: h-sweep 3.6s linear infinite;
  mix-blend-mode: overlay;
  pointer-events: none;
}

#spiritBar .sf-text {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  font-family: 'Bangers', 'Fredoka', sans-serif;
  font-size: 14px;
  letter-spacing: 1.6px;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .85), 0 0 8px rgba(0, 0, 0, .5);
  white-space: nowrap;
}

#spiritBar .sf-text .k {
  color: rgba(255, 255, 255, .78);
}

#spiritBar .sf-text .v {
  color: #fff;
  font-variant-numeric: tabular-nums;
}

#spiritBar .sf-text .t {
  color: var(--h-gold);
  letter-spacing: 1.4px;
}

#spiritBar .sf-text .t:empty {
  display: none;
}

/* states */
#spiritBar.low {
  --glow: rgba(255, 70, 70, .6);
  animation: h-throb .7s ease-in-out infinite;
}

#spiritBar.low .sf-fill {
  background:
    linear-gradient(180deg, rgba(255, 255, 255, .5) 0 42%, rgba(255, 255, 255, 0) 43%),
    linear-gradient(180deg, #ff9a7a, #ff4b3e 50%, #c81e2e);
}

#spiritBar.ready {
  --glow: rgba(255, 210, 63, .85);
}

#spiritBar.ready .sf-fill,
#spiritBar.asc .sf-fill {
  background:
    linear-gradient(180deg, rgba(255, 255, 255, .6) 0 42%, rgba(255, 255, 255, 0) 43%),
    linear-gradient(180deg, #fff3a0, #ffd23f 50%, #ff9d1c);
}

#spiritBar.ready .sf {
  animation: h-glint 1.1s ease-in-out infinite;
}

#spiritBar.asc {
  --glow: rgba(255, 150, 30, .9);
}

#spiritBar.asc .sf-fill {
  background-size: 100% 100%, 100% 100%;
  animation: h-flame .5s ease-in-out infinite alternate;
}

#spiritBar.exh {
  --glow: rgba(120, 140, 180, .3);
}

#spiritBar.exh .sf-fill {
  background:
    linear-gradient(180deg, rgba(255, 255, 255, .25) 0 42%, rgba(255, 255, 255, 0) 43%),
    linear-gradient(180deg, #8996b3, #5f6d8f 50%, #3f4b6b);
}

#spiritBar.exh .sf-shine {
  display: none;
}

/* ───────────── top right: leaderboard ───────────── */

#hudRight {
  position: absolute;
  top: calc(12px + var(--h-safe-top));
  right: calc(12px + var(--h-safe-right));
  width: var(--h-board-w, 214px);
  display: flex;
  flex-direction: column;
  align-items: stretch;
}

#board {
  background: var(--h-glass);
  border: 1px solid var(--h-line);
  border-radius: 10px;
  overflow: hidden;
}

#board .bd-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 4px 5px 4px 12px;
  background: linear-gradient(90deg, rgba(160, 110, 255, .55), rgba(160, 110, 255, .08));
}

#board .bd-title {
  font-family: 'Bangers', 'Fredoka', sans-serif;
  font-size: 14px;
  letter-spacing: 2.4px;
  color: var(--h-gold);
  text-transform: uppercase;
}

.bd-actions {
  display: flex;
  align-items: center;
  gap: 6px;
}

#lbToggle {
  pointer-events: auto;
  width: 26px;
  height: 22px;
  padding: 0;
  display: grid;
  place-items: center;
  color: #fff;
  background:
    linear-gradient(180deg, rgba(120, 90, 200, .75), rgba(60, 36, 130, .85)) padding-box,
    linear-gradient(160deg, #ffffff, #b48cff 50%, #5a2fc0) border-box;
  border: 2px solid transparent;
  outline: 2px solid var(--h-ink);
  border-radius: 7px;
  cursor: var(--cur-pointer);
  -webkit-tap-highlight-color: transparent;
  transition: background .15s;
}

/* Same look as #lbToggle (kept as its own rule, not a shared selector, so both stay simple standalone blocks) */
#inviteRoomBtn {
  pointer-events: auto;
  width: 26px;
  height: 22px;
  padding: 0;
  display: grid;
  place-items: center;
  color: #fff;
  font-size: 12px;
  line-height: 1;
  background:
    linear-gradient(180deg, rgba(120, 90, 200, .75), rgba(60, 36, 130, .85)) padding-box,
    linear-gradient(160deg, #ffffff, #b48cff 50%, #5a2fc0) border-box;
  border: 2px solid transparent;
  outline: 2px solid var(--h-ink);
  border-radius: 7px;
  cursor: var(--cur-pointer);
  -webkit-tap-highlight-color: transparent;
  transition: background .15s;
}

/* Same look again: the in-game menu button (Esc) */
#gameMenuBtn {
  pointer-events: auto;
  width: 26px;
  height: 22px;
  padding: 0;
  display: grid;
  place-items: center;
  color: #fff;
  background:
    linear-gradient(180deg, rgba(120, 90, 200, .75), rgba(60, 36, 130, .85)) padding-box,
    linear-gradient(160deg, #ffffff, #b48cff 50%, #5a2fc0) border-box;
  border: 2px solid transparent;
  outline: 2px solid var(--h-ink);
  border-radius: 7px;
  cursor: var(--cur-pointer);
  -webkit-tap-highlight-color: transparent;
  transition: background .15s;
}

#gameMenuBtn svg {
  width: 14px;
  height: 14px;
}

/* Same look again: back to full screen (touch-first screens only — main.mjs unhides it where the browser allows) */
#fullscreenBtn {
  pointer-events: auto;
  width: 26px;
  height: 22px;
  padding: 0;
  display: grid;
  place-items: center;
  color: #fff;
  background:
    linear-gradient(180deg, rgba(120, 90, 200, .75), rgba(60, 36, 130, .85)) padding-box,
    linear-gradient(160deg, #ffffff, #b48cff 50%, #5a2fc0) border-box;
  border: 2px solid transparent;
  outline: 2px solid var(--h-ink);
  border-radius: 7px;
  cursor: var(--cur-pointer);
  -webkit-tap-highlight-color: transparent;
  transition: background .15s;
}

#fullscreenBtn svg {
  width: 14px;
  height: 14px;
}

#fullscreenBtn[hidden] {
  display: none;
}

#lbToggle:hover,
#inviteRoomBtn:hover,
#gameMenuBtn:hover,
#fullscreenBtn:hover {
  filter: brightness(1.25);
}

/* Touch screens: the three header buttons get a finger-sized box (they were 26×22 px). The title gets its own
   line above them, so the narrow phone board never clips a button. */
@media (pointer: coarse) {
  #board .bd-head {
    flex-wrap: wrap;
    justify-content: center;
    row-gap: 4px;
    padding: 5px 6px 6px;
  }

  #board .bd-title {
    flex: 1 0 100%;
    text-align: center;
  }

  .bd-actions {
    gap: 8px;
  }

  #lbToggle,
  #inviteRoomBtn,
  #gameMenuBtn,
  #fullscreenBtn {
    width: 40px;
    height: 34px;
  }

  #lbToggle svg,
  #gameMenuBtn svg {
    width: 18px;
    height: 18px;
  }

  #inviteRoomBtn {
    font-size: 16px;
  }
}

#inviteRoomBtn[hidden] {
  display: none;
}

#lbToggle svg {
  width: 14px;
  height: 14px;
  transition: transform .25s;
}

#board.compact #lbToggle svg {
  transform: rotate(180deg);
}

#lbList {
  padding: 3px 0 4px;
  max-height: 46vh;
  overflow: hidden;
}

.lb-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 3px 11px 3px 8px;
  font-size: 12.5px;
  font-weight: 800;
  line-height: 1.3;
  border-left: 3px solid transparent;
}

.lb-row .rk {
  flex: 0 0 auto;
  min-width: 20px;
  height: 18px;
  padding: 0 4px;
  display: grid;
  place-items: center;
  font-family: 'Bangers', 'Fredoka', sans-serif;
  font-size: 12px;
  letter-spacing: .5px;
  border-radius: 9px;
  color: var(--h-dim);
  background: rgba(255, 255, 255, .08);
}

.lb-row.r1 .rk {
  color: #3a2600;
  background: linear-gradient(180deg, #fff1a3, #ffc21a);
}

.lb-row.r2 .rk {
  color: #23303f;
  background: linear-gradient(180deg, #f4f8ff, #b3c1d6);
}

.lb-row.r3 .rk {
  color: #3a1c08;
  background: linear-gradient(180deg, #ffd0a0, #d9884a);
}

.lb-row .nm {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.lb-row .sc {
  flex: 0 0 auto;
  font-variant-numeric: tabular-nums;
  color: var(--h-dim);
}

.lb-row.r1 .nm {
  color: var(--h-gold);
}

.lb-row.me {
  background: linear-gradient(90deg, rgba(255, 210, 63, .22), rgba(255, 210, 63, .05));
  border-left-color: var(--h-gold);
}

.lb-row.me .sc {
  color: #fff;
}

.lb-gap {
  text-align: center;
  line-height: .7;
  font-size: 15px;
  letter-spacing: 3px;
  color: var(--h-dim);
}

/* ───────────── messages: Twitch-alert style feed ───────────── */

#feed {
  position: fixed;
  top: var(--feed-top);
  right: calc(12px + var(--h-safe-right));
  width: min(268px, 62vw);
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 6px;
  pointer-events: none;
  z-index: 60; /* above the results overlay (z-index 20): level-ups and achievements appear on the game-over screen */
}

.fd-item {
  position: relative;
  display: flex;
  align-items: center;
  gap: 8px;
  --fd-h: 44px;
  max-width: 100%;
  max-height: var(--fd-h);
  padding: 6px 12px 6px 14px;
  overflow: hidden;
  border-radius: 7px;
  background: linear-gradient(90deg, var(--h-glass-strong), rgba(14, 10, 34, .7));
  border: 1px solid var(--h-line);
  box-shadow: 0 0 0 0 transparent;
  will-change: transform, opacity;
}

.fd-bar {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 4px;
  background: var(--fd);
  box-shadow: 0 0 10px 1px var(--fd);
}

.fd-ico {
  flex: 0 0 auto;
  font-size: 15px;
  line-height: 1;
}

.fd-txt {
  min-width: 0;
  font-size: 12.5px;
  font-weight: 800;
  line-height: 1.25;
  letter-spacing: .2px;
  color: #fff;
  /* long messages (e.g. the daily reward) wrap to two lines instead of being cut off with "…" */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
  overflow-wrap: anywhere;
}

.fd-cnt {
  flex: 0 0 auto;
  font-family: 'Bangers', 'Fredoka', sans-serif;
  font-size: 14px;
  letter-spacing: .5px;
  color: var(--h-gold);
}

.fd-cnt:empty {
  display: none;
}

.fd-shine {
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg, transparent 30%, rgba(255, 255, 255, .55) 50%, transparent 70%);
  transform: translateX(-120%);
  pointer-events: none;
}

/* the moments that matter get a warmer, longer glow */
.fd-crown .fd-txt {
  color: var(--h-gold);
}

/* entering: slide in from the right with a little overshoot, flash, pop the icon, grow the bar */
.fd-in {
  animation: fd-in .55s cubic-bezier(.16, 1.25, .3, 1) both;
}

.fd-in.fd-crown,
.fd-in.fd-power {
  animation: fd-in .55s cubic-bezier(.16, 1.25, .3, 1) both, fd-halo 1.6s ease-out .1s both;
}

.fd-in .fd-shine {
  animation: fd-shine .95s ease-out .12s both;
}

.fd-in .fd-ico {
  animation: fd-pop .55s cubic-bezier(.2, 1.7, .4, 1) .12s both;
}

.fd-in .fd-bar {
  animation: fd-bar .45s ease-out both;
  transform-origin: center;
}

.fd-bump {
  animation: fd-bump .32s ease-out;
}

.fd-out {
  animation: fd-out .32s ease-in both;
}

@keyframes fd-in {
  0% { transform: translateX(115%) scale(.92); opacity: 0; }
  60% { opacity: 1; }
  100% { transform: none; opacity: 1; }
}

@keyframes fd-out {
  0% { transform: none; opacity: 1; max-height: var(--fd-h); margin-top: 0; }
  62% { transform: translateX(110%); opacity: 0; max-height: var(--fd-h); margin-top: 0; padding-top: 6px; padding-bottom: 6px; }
  100% { transform: translateX(110%); opacity: 0; max-height: 0; margin-top: -6px; padding-top: 0; padding-bottom: 0; }
}

@keyframes fd-shine {
  from { transform: translateX(-120%); }
  to { transform: translateX(120%); }
}

@keyframes fd-pop {
  0% { transform: scale(0) rotate(-40deg); }
  100% { transform: scale(1) rotate(0); }
}

@keyframes fd-bar {
  from { transform: scaleY(0); }
  to { transform: scaleY(1); }
}

@keyframes fd-bump {
  0% { transform: scale(1); }
  40% { transform: scale(1.07); }
  100% { transform: scale(1); }
}

@keyframes fd-halo {
  0% { box-shadow: 0 0 0 0 var(--fd); }
  35% { box-shadow: 0 0 20px 2px var(--fd); }
  100% { box-shadow: 0 0 0 0 transparent; }
}

/* ───────────── reward cards (achievements, level-ups) and the results count-up ───────────── */

.fd-card {
  --fd-h: 76px;
  gap: 12px;
  align-items: center;
  padding: 9px 16px 9px 18px;
  border: 2px solid transparent;
  border-radius: 12px;
  background:
    linear-gradient(90deg, rgba(14, 10, 34, .94), rgba(30, 20, 66, .9)) padding-box,
    linear-gradient(120deg, var(--fd), #ffffff 45%, var(--fd)) border-box;
}

.fd-card .fd-bar {
  display: none;
}

.fd-card .fd-ico {
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  font-size: 22px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, rgba(255, 255, 255, .38), rgba(255, 255, 255, .04) 70%);
  border: 2px solid var(--fd);
  box-shadow: 0 0 14px var(--fd);
}

.fd-card .fd-body {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}

.fd-card .fd-tag {
  font-family: 'Bangers', 'Fredoka', sans-serif;
  font-size: 11px;
  letter-spacing: 2.2px;
  color: var(--fd);
}

.fd-card .fd-txt {
  font-size: 15px;
  white-space: normal;
  line-height: 1.15;
  color: #fff;
}

.fd-card .fd-sub {
  font-size: 12px;
  font-weight: 800;
  color: var(--h-gold);
}

/* a burst of sparks when a reward card lands */
.fd-spark {
  position: absolute;
  left: 38px;
  top: 50%;
  width: 5px;
  height: 5px;
  margin: -2px 0 0 -2px;
  border-radius: 50%;
  background: var(--fd);
  box-shadow: 0 0 6px var(--fd);
  opacity: 0;
  pointer-events: none;
}

.fd-in .fd-spark {
  animation: fd-spark .8s ease-out .28s both;
}

.fd-in.fd-card {
  animation: fd-card-in .7s cubic-bezier(.16, 1.3, .3, 1) both, fd-halo 1.8s ease-out .15s both;
}

@keyframes fd-card-in {
  0% { transform: translateX(120%) rotate(6deg) scale(.85); opacity: 0; }
  55% { opacity: 1; }
  100% { transform: none; opacity: 1; }
}

@keyframes fd-spark {
  0% { transform: rotate(var(--a)) translateX(0) scale(1); opacity: 1; }
  100% { transform: rotate(var(--a)) translateX(var(--d)) scale(.2); opacity: 0; }
}

/* results screen numbers settle with a small pop once they finish counting */
.count-pop {
  animation: count-pop .45s cubic-bezier(.2, 1.6, .4, 1);
}

@keyframes count-pop {
  0% { transform: scale(1); }
  45% { transform: scale(1.18); }
  100% { transform: scale(1); }
}

/* ───────────── minimap ───────────── */

#miniWrap {
  position: absolute;
  right: calc(12px + var(--h-safe-right));
  bottom: calc(12px + var(--h-safe-bottom));
  padding: 6px;
  border-radius: 50%;
  background:
    radial-gradient(circle at 35% 30%, rgba(75, 42, 168, .92), rgba(23, 10, 69, .95)) padding-box,
    linear-gradient(160deg, #ffffff, #9a75ff 50%, #2b1670) border-box;
  border: 3px solid transparent;
  outline: var(--h-outline) solid var(--h-ink);
}

#minimap {
  display: block;
  width: 132px;
  height: 132px;
  border-radius: 50%;
}

/* ───────────── Breath indicator (desktop) ───────────── */

#breathWrap {
  position: absolute;
  right: calc(20px + var(--h-safe-right));
  bottom: calc(168px + var(--h-safe-bottom));
  width: 82px;
  padding: 8px 8px 7px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  background:
    linear-gradient(180deg, rgba(34, 22, 78, .88), rgba(14, 10, 34, .9)) padding-box,
    linear-gradient(160deg, #ffffff, #ffb02e 50%, #b8560a) border-box;
  border: 2px solid transparent;
  outline: var(--h-outline) solid var(--h-ink);
  border-radius: 13px;
}

#breathIcon {
  font-size: 26px;
  line-height: 1;
  transition: transform .2s;
}

#breathIcon.ready {
  animation: h-bob 1.4s ease-in-out infinite;
}

#breathBar {
  width: 100%;
  height: 7px;
  overflow: hidden;
  border-radius: 4px;
  background: rgba(255, 255, 255, .14);
}

#breathFill {
  height: 100%;
  width: 100%;
  border-radius: 4px;
  background: linear-gradient(90deg, #ffd23f, #ff5a4a);
  transition: width .1s linear;
}

#breathLabel {
  font-family: 'Bangers', 'Fredoka', sans-serif;
  font-size: 12px;
  letter-spacing: 2px;
  color: var(--h-dim);
}

/* ───────────── touch controls ───────────── */

#actionBar {
  position: absolute;
  left: calc(16px + var(--h-safe-left));
  bottom: calc(134px + var(--h-safe-bottom));
  display: none;
  flex-direction: column;
  gap: 8px;
  pointer-events: auto;
}

body.touch #actionBar {
  display: flex;
}

.actionBtn {
  position: relative;
  width: 84px;
  height: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 13px;
  border: 3px solid transparent; /* the visible border is the gradient painted under it (border-box layer) */
  outline: var(--h-outline) solid var(--h-ink); /* + the thin black comic outline (an outline, not a shadow: no offset) */
  font-family: 'Bangers', 'Fredoka', sans-serif;
  font-size: 16px;
  letter-spacing: 1.4px;
  color: #fff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .7);
  cursor: var(--cur-pointer);
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  transition: transform .1s, filter .15s, opacity .2s;
}

.actionBtn:active,
.actionBtn.on {
  transform: scale(.94);
  filter: brightness(1.2);
}

#ascendBtn {
  background:
    linear-gradient(180deg, #ffd766, #f08a13) padding-box,
    linear-gradient(160deg, #fff7c9, #ffb02e 45%, #b8560a) border-box;
}

#ascendBtn.off {
  opacity: .38;
  filter: grayscale(.7);
}

#blastBtn {
  flex-direction: column;
  gap: 1px;
  line-height: 1;
  overflow: hidden;
  background:
    linear-gradient(180deg, #58e6ff, #1a86d8) padding-box,
    linear-gradient(160deg, #eaffff, #37e2ff 45%, #0a4fb3) border-box;
}

#blastBtn.on {
  background:
    linear-gradient(180deg, #fff2a0, #ffb31a) padding-box,
    linear-gradient(160deg, #ffffff, #ffd23f 45%, #c47a00) border-box;
  color: #2a1400;
  text-shadow: none;
}

#blastIcon {
  font-size: 18px;
  text-shadow: none;
}

#blastName {
  font-size: 12px;
  letter-spacing: 1px;
}

#blastBar {
  position: absolute;
  left: 8px;
  right: 8px;
  bottom: 4px;
  height: 5px;
  overflow: hidden;
  border-radius: 3px;
  background: rgba(10, 4, 40, .5);
}

#blastFill {
  display: block;
  height: 100%;
  width: 100%;
  background: linear-gradient(90deg, #ffd23f, #ff5a4a);
  transition: width .1s linear;
}

/* On touch screens the Breath button carries the element icon, name and gauge, so the separate
   round indicator would just be a confusing fourth "button". */
body.touch #breathWrap {
  display: none;
}

#boostBtn {
  position: absolute;
  left: calc(16px + var(--h-safe-left));
  bottom: calc(22px + var(--h-safe-bottom));
  width: 92px;
  height: 92px;
  border-radius: 50%;
  display: none;
  align-items: center;
  justify-content: center;
  pointer-events: auto;
  font-family: 'Bangers', 'Fredoka', sans-serif;
  font-size: 22px;
  letter-spacing: 2px;
  color: #fff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .7);
  background:
    radial-gradient(circle at 35% 28%, #ff9f86, #ff4a3e 55%, #c81e2e) padding-box,
    linear-gradient(160deg, #fff0ea, #ff7a6a 45%, #9c1024) border-box;
  border: 4px solid transparent;
  outline: var(--h-outline) solid var(--h-ink);
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  transition: transform .1s, filter .15s;
}

#boostBtn.on {
  transform: scale(.94);
  filter: brightness(1.2);
}

body.touch #boostBtn {
  display: flex;
}

/* ───────────── first-flight hint + rebirth banner ───────────── */

#tutorial {
  position: fixed;
  left: 50%;
  bottom: 5%;
  width: min(92vw, 440px);
  padding: 11px 18px 12px;
  text-align: center;
  background: var(--h-glass-strong);
  border: 1px solid var(--h-line);
  border-radius: 12px;
  opacity: 0;
  pointer-events: none;
  transform: translate(-50%, 14px);
  transition: opacity .4s, transform .4s cubic-bezier(.2, 1.2, .3, 1);
  z-index: 14;
}

#tutorial.show {
  opacity: 1;
  transform: translate(-50%, 0);
}

#tutorial .tt {
  font-family: 'Bangers', 'Fredoka', sans-serif;
  font-size: 17px;
  letter-spacing: 2.4px;
  color: var(--h-gold);
  margin-bottom: 4px;
}

#tutorial p {
  margin: 3px 0;
  font-size: 13px;
  font-weight: 700;
  line-height: 1.38;
  color: rgba(255, 255, 255, .92);
}

#tutorial .touch-only-text {
  display: none;
}

body.touch #tutorial {
  bottom: auto;
  top: 26%;
  width: min(88vw, 420px);
}

body.touch #tutorial .touch-only-text {
  display: block;
}

body.touch #tutorial .desk-only-text {
  display: none;
}

#respawnOverlay {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  opacity: 0;
  transition: opacity .25s;
  z-index: 14;
}

#respawnOverlay.show {
  opacity: 1;
}

#respawnOverlay .msg {
  padding: 16px 40px;
  text-align: center;
  font-family: 'Bangers', 'Fredoka', sans-serif;
  font-size: clamp(24px, 4.4vw, 38px);
  letter-spacing: 3px;
  color: var(--h-gold);
  background: var(--h-glass-strong);
  border: 1px solid var(--h-line);
  border-radius: 14px;
  text-shadow: 0 0 14px rgba(255, 210, 63, .55);
}

#respawnOverlay .msg small {
  display: block;
  margin-top: 5px;
  font-family: 'Quicksand', sans-serif;
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 2.5px;
  text-transform: uppercase;
  color: var(--h-dim);
  text-shadow: none;
}

/* ───────────── keyframes shared by the bars ───────────── */

@keyframes h-sweep {
  from { background-position: 130% 0; }
  to { background-position: -130% 0; }
}

@keyframes h-throb {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.03); }
}

@keyframes h-glint {
  0%, 100% { filter: brightness(1); }
  50% { filter: brightness(1.35); }
}

@keyframes h-flame {
  from { filter: brightness(1) saturate(1); }
  to { filter: brightness(1.25) saturate(1.3); }
}

@keyframes h-bob {
  0%, 100% { transform: translateY(0) rotate(-3deg); }
  50% { transform: translateY(-2px) rotate(3deg) scale(1.1); }
}

/* ───────────── small screens ───────────── */

@media (max-width: 640px) {
  #hudTop {
    width: calc(100vw - 24px - 166px - 8px);
    min-width: 168px;
  }

  #mightPlate {
    min-width: 132px;
    padding: 4px 22px 7px 11px;
  }

  #plVal {
    font-size: 26px;
  }

  #spiritBar {
    height: 24px;
  }

  #spiritBar .sf-text {
    font-size: 12px;
    gap: 5px;
    letter-spacing: 1.2px;
  }

  #hud {
    --h-board-w: 166px;
  }

  #hudRight {
    width: var(--h-board-w);
  }

  #board .bd-title {
    font-size: 12.5px;
    letter-spacing: 2px;
  }

  .lb-row {
    font-size: 11.5px;
    padding: 2px 9px 2px 6px;
    gap: 6px;
  }

  #feed {
    width: min(232px, 66vw);
  }

  .fd-txt {
    font-size: 11.5px;
  }

  #minimap {
    width: 96px;
    height: 96px;
  }

  #miniWrap {
    right: calc(10px + var(--h-safe-right));
    bottom: calc(10px + var(--h-safe-bottom));
    padding: 5px;
  }

  #breathWrap {
    right: calc(14px + var(--h-safe-right));
    bottom: calc(126px + var(--h-safe-bottom));
    width: 72px;
  }

  #actionBar {
    left: calc(14px + var(--h-safe-left));
    bottom: calc(124px + var(--h-safe-bottom));
  }

  #boostBtn {
    left: calc(14px + var(--h-safe-left));
    bottom: calc(16px + var(--h-safe-bottom));
    width: 88px;
    height: 88px;
  }
}

/* landscape phones: short screen, controls sit side by side */
@media (max-height: 520px) {
  #mightPlate {
    padding: 2px 20px 6px 10px;
  }

  #plVal {
    font-size: 22px;
  }

  #spiritBar {
    height: 21px;
  }

  #spiritBar .sf-text {
    font-size: 11px;
  }

  #minimap {
    width: 84px;
    height: 84px;
  }

  #lbList {
    max-height: 38vh;
  }

  #actionBar {
    flex-direction: row;
    left: calc(108px + var(--h-safe-left));
    bottom: calc(16px + var(--h-safe-bottom));
    gap: 8px;
  }

  #boostBtn {
    width: 80px;
    height: 80px;
    bottom: calc(14px + var(--h-safe-bottom));
  }

  #breathWrap {
    right: calc(104px + var(--h-safe-right));
    bottom: calc(10px + var(--h-safe-bottom));
    width: 64px;
  }

  body.touch #tutorial {
    top: 22%;
  }
}

/* ───────────── touch-first screens: phones AND tablets (owner 2026-10-12) ─────────────
   A mouse/trackpad desktop never matches (pointer: coarse), so none of this reaches it. The camera is zoomed out
   too (main.mjs ZOOM_SCALE). The minimap moves up, left of the board; the joystick takes its corner and is the only
   way to steer (a tap elsewhere is still the quick shot); a full-screen button joins the board's header. */
@media (pointer: coarse) {
  #miniWrap {
    top: calc(12px + var(--h-safe-top));
    right: calc(12px + var(--h-board-w, 214px) + 6px + var(--h-safe-right));
    bottom: auto;
    padding: 2px;
  }

  #hud #joystick { /* #hud: wins over the base rule below, which comes later in this file */
    display: block;
    width: 142px;
    height: 142px;
  }

  /* the Breath (attack) button a little bigger than ASCEND (owner 2026-10-13) */
  #hud #blastBtn {
    width: 96px;
    height: 56px;
  }

  #hud #blastIcon {
    font-size: 21px;
  }

  #hud #blastName {
    font-size: 13px;
  }
}

/* touch-first screens held upright (tablets, or a phone after "PLAY IN PORTRAIT"): a narrow screen has no room for the
   minimap beside the board, so it sits under the Might/Spirit block on the left */
@media (pointer: coarse) and (orientation: portrait) and (max-width: 700px) {
  #miniWrap {
    top: calc(96px + var(--h-safe-top));
    left: calc(12px + var(--h-safe-left));
    right: auto;
  }

  #minimap {
    width: 76px;
    height: 76px;
  }
}

/* the compact board (owner 2026-10-14): phones held sideways, and phones held upright — where the 166 px board could
   not fit its 4 header buttons (the full-screen one was cut) and, at 320 px, ran into Might/Spirit */
@media (pointer: coarse) and (orientation: landscape), (pointer: coarse) and (max-width: 640px) {
  #hud {
    --h-board-w: 150px;
  }

  #hudRight {
    width: var(--h-board-w);
  }

  #board .bd-head {
    row-gap: 3px;
    padding: 3px 4px 4px;
  }

  #board .bd-title {
    font-size: 10.5px;
    letter-spacing: 1.4px;
  }

  .bd-actions {
    gap: 4px;
  }

  #lbToggle,
  #inviteRoomBtn,
  #gameMenuBtn,
  #fullscreenBtn {
    width: 29px;
    height: 25px;
  }

  #lbToggle svg,
  #gameMenuBtn svg,
  #fullscreenBtn svg {
    width: 13px;
    height: 13px;
  }

  #inviteRoomBtn {
    font-size: 12px;
  }

  .lb-row {
    gap: 5px;
    padding: 2px 7px 2px 5px;
    font-size: 10.5px;
  }

  .lb-row .rk {
    min-width: 16px;
    height: 15px;
    font-size: 10px;
  }

}

/* upright phones: the Might/Spirit block takes the width the board leaves (it overlapped it at 320 px) */
@media (pointer: coarse) and (orientation: portrait) and (max-width: 640px) {
  #hudTop {
    width: calc(100vw - 24px - var(--h-board-w) - 10px);
    min-width: 0;
  }

  #mightPlate {
    min-width: 0;
  }
}

/* touch: the expanded board scrolls with a finger instead of cutting its last rows (steering is the joystick, so a
   swipe on the board steals nothing) */
@media (pointer: coarse) {
  #lbList {
    overflow-y: auto;
    pointer-events: auto;
    touch-action: pan-y;
    overscroll-behavior: contain;
    scrollbar-width: none;
  }

  #lbList::-webkit-scrollbar {
    display: none;
  }
}

/* touch-first screens held sideways: smaller Might/Spirit and board, ASCEND above FLY!, the Breath button right of
   FLY!, the joystick bottom right */
@media (pointer: coarse) and (orientation: landscape) {
  #hudTop {
    width: min(250px, 36vw);
    gap: 5px;
  }

  #mightPlate {
    min-width: 0;
    padding: 2px 18px 5px 9px;
    gap: 7px;
  }

  #mightPlate .lbl {
    font-size: 11px;
    letter-spacing: 2px;
  }

  #plVal {
    font-size: 20px;
  }

  #spiritBar {
    height: 18px;
  }

  #spiritBar .sf-text {
    font-size: 10px;
  }

  #minimap {
    width: 76px;
    height: 76px;
  }

  /* the expanded list ends above the joystick (18 + 138 px from the bottom) and scrolls the rest (see below) */
  #lbList {
    max-height: max(60px, calc(100vh - 240px));
  }

  /* the two action buttons leave their column and are placed one by one around FLY! (same markup) */
  body.touch #actionBar {
    display: contents;
  }

  #ascendBtn {
    position: absolute;
    left: calc(12px + var(--h-safe-left));
    bottom: calc(104px + var(--h-safe-bottom));
  }

  #blastBtn {
    position: absolute;
    left: calc(106px + var(--h-safe-left));
    bottom: calc(26px + var(--h-safe-bottom));
  }

  #boostBtn {
    left: calc(14px + var(--h-safe-left));
    width: 80px;
    height: 80px;
    bottom: calc(14px + var(--h-safe-bottom));
  }

  #hud #joystick {
    width: 138px;
    height: 138px;
  }

  body.touch #tutorial {
    top: 22%;
  }
}

/* ───────────── joystick (touch-first screens only, see above) ─────────────
   A round base and a knob that follows the thumb; main.mjs reads the knob's direction straight into the steering
   angle (same predicted path as before, no extra delay). Flat glass like the rest of the HUD. */
#joystick {
  display: none;
  position: absolute;
  right: calc(18px + var(--h-safe-right));
  bottom: calc(18px + var(--h-safe-bottom));
  width: 132px;
  height: 132px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 255, 255, .06) 0 30%, rgba(14, 10, 34, .42) 31% 100%);
  border: 2px solid var(--h-line);
  outline: var(--h-outline) solid var(--h-ink);
  pointer-events: auto;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
}

#joystick .js-knob {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 44%;
  height: 44%;
  margin: -22% 0 0 -22%;
  border-radius: 50%;
  background:
    radial-gradient(circle at 35% 30%, rgba(255, 255, 255, .95), rgba(190, 160, 255, .9) 45%, rgba(110, 70, 220, .92)) padding-box,
    linear-gradient(160deg, #ffffff, #b48cff 50%, #5a2fc0) border-box;
  border: 2px solid transparent;
  outline: var(--h-outline) solid var(--h-ink);
  will-change: transform;
}

#joystick.on {
  border-color: rgba(255, 255, 255, .35);
}

/* ───────────── portrait phones: "turn your phone sideways" (owner 2026-10-12) ─────────────
   Only while a game is on screen (#hud.show). Android usually never shows it (main.mjs locks landscape); iPhone can't
   be locked by a web page, so this covers it. Tablets in portrait (wider than 600px) keep playing as they are. */
#rotateHint {
  display: none;
}

@media (orientation: portrait) and (max-width: 600px) {
  body.touch #hud.show #rotateHint {
    position: fixed;
    inset: 0;
    z-index: 50;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 10px;
    padding: 24px;
    text-align: center;
    background: rgba(14, 6, 30, .93);
    pointer-events: auto;
  }
}

#rotateHint .rh-icon {
  font-size: 56px;
  line-height: 1;
  animation: rh-turn 1.8s ease-in-out infinite;
}

#rotateHint b {
  font-family: 'Bangers', 'Fredoka', sans-serif;
  font-weight: 400;
  font-size: 28px;
  letter-spacing: 1.6px;
  color: var(--h-gold);
}

#rotateHint .rh-sub {
  font-size: 13px;
  font-weight: 700;
  color: var(--h-dim);
}

/* the way out when the phone won't (or the player doesn't want to) turn: it appears after 3 s, then the portrait
   layout is used for the rest of the visit (main.mjs adds body.portrait-ok) */
#rotateSkip {
  margin-top: 14px;
  padding: 9px 18px;
  font-family: 'Bangers', 'Fredoka', sans-serif;
  font-size: 17px;
  letter-spacing: 1.4px;
  color: #fff;
  background: var(--h-glass);
  border: 1px solid var(--h-line);
  border-radius: 10px;
  outline: var(--h-outline) solid var(--h-ink);
  cursor: var(--cur-pointer);
  -webkit-tap-highlight-color: transparent;
  visibility: hidden;
  opacity: 0;
  animation: rh-skip-in .3s ease-out 3s forwards;
}

@keyframes rh-skip-in {
  to { visibility: visible; opacity: 1; }
}

body.portrait-ok #hud.show #rotateHint {
  display: none;
}

@keyframes rh-turn {
  0%, 25% { transform: rotate(0deg); }
  55%, 85% { transform: rotate(-90deg); }
  100% { transform: rotate(0deg); }
}

/* ───────────── reduced motion: same information, no movement ───────────── */

@media (prefers-reduced-motion: reduce) {
  #rotateHint .rh-icon,
  #spiritBar .sf-shine,
  #spiritBar.low,
  #spiritBar.ready .sf,
  #spiritBar.asc .sf-fill,
  #mightPlate.full #mightProgFill,
  #breathIcon.ready {
    animation: none;
  }

  #spiritBar .sf-lag {
    transition: none;
  }

  .fd-in,
  .fd-in.fd-crown,
  .fd-in.fd-power,
  .fd-in.fd-card {
    animation: fd-fade .2s ease-out both;
  }

  .fd-spark,
  .count-pop {
    animation: none;
    display: none;
  }

  .fd-in .fd-shine,
  .fd-in .fd-ico,
  .fd-in .fd-bar,
  .fd-bump {
    animation: none;
  }

  .fd-out {
    animation: fd-fade-out .2s ease-in both;
  }

  #tutorial {
    transition: opacity .2s;
  }

  @keyframes fd-fade {
    from { opacity: 0; }
    to { opacity: 1; }
  }

  @keyframes fd-fade-out {
    to { opacity: 0; max-height: 0; margin-top: -6px; padding-top: 0; padding-bottom: 0; }
  }
}
