/* HUD APPEARANCE — colour, plate, border, shadow and type. No geometry.
 *
 * The counterpart to hud-layout.css. If you find yourself reaching for a
 * position, a width or a margin in this file, it belongs in that one.
 *
 * PALETTE — the Grey Lantern containment dossier (v0.14 audit §5). The field
 * HUD is a battered containment instrument, not an arcade cabinet: signal
 * amber carries interactability and direction, cold cyan carries power and
 * radio, and danger red is reserved for damage and failure so that it still
 * means something when it appears.
 *
 * CONTRAST — plates are gone. Ink carries its own two-part shadow so values
 * stay readable on a blown-out wall without a filled rectangle behind them.
 * Optional corner scrims (peak ~.32, faded by ~72%) are a gradient with no
 * detectable edge; `html.hud-no-scrim` drops them entirely.
 */

:root {
  --soot: var(--tone-07090a);
  --bunker: var(--steel-800);
  --paper-hud: var(--cream-700);
  --amber: var(--amber-hot);
  --cyan: var(--tone-78a8ad);
  --danger: var(--tone-c94a3a);

  --hud-plate: transparent;
  --hud-plate-soft: transparent;
  --hud-edge: rgba(216, 208, 186, .10);
  --hud-ink: var(--cream-200);          /* values */
  --hud-key: #e6dfcc;                   /* labels — was #d8d0ba */

  --hud-sink: none;
  --hud-lift: none;
  --hud-text-shadow: 0 1px 2px rgba(0, 0, 0, .95), 0 0 10px rgba(0, 0, 0, .7);
  --hud-radius: 2px;
  --hud-scrim-bl: radial-gradient(130% 150% at 8% 60%, rgba(7, 9, 10, .32), rgba(7, 9, 10, 0) 74%);
  --hud-scrim-br: radial-gradient(120% 140% at 85% 80%, rgba(7, 9, 10, .34), rgba(7, 9, 10, 0) 72%);
  --hud-scrim-tr: radial-gradient(120% 150% at 95% 50%, rgba(7, 9, 10, .32), rgba(7, 9, 10, 0) 72%);
  --hud-scrim-tl: linear-gradient(96deg, rgba(7, 9, 10, .30), rgba(7, 9, 10, 0) 70%);
}

/* Shared plate corners — vitals, ammo, mission, and kill feed agree. */
#hud #mission,
#hud #zcount,
#hud #hp-box,
#hud #points-box,
#hud #round-box,
#hud #stam-box,
#hud #ammo-box,
#hud #nade-box,
#hud .kfeed {
  border-radius: var(--hud-radius);
}

/* Shared readout chrome. */
#hud .hud-key,
#hud #hp-num,
#hud #points,
#hud #ammo-mag,
#hud #ammo-res,
#hud #wpn-name,
#hud #z-rem,
#hud #mission-title,
#hud #mission-detail,
#hud #nade-count,
#hud .kfeed {
  text-shadow: 0 1px 2px rgba(0, 0, 0, .95), 0 0 10px rgba(0, 0, 0, .75);
}
#hud #hud-fps,
#pause-fps {
  color: var(--hud-key);
  font: 700 calc(11 * var(--u))/1 var(--font-mono);
  letter-spacing: .16em;
  text-transform: uppercase;
  opacity: .52;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .95);
}
#pause-fps { font-size: 11px; }
/* TYPE HIERARCHY (v0.21 audit §6). Three bands at 1080p, --hud-scale 1:
 *   IMMEDIATE SURVIVAL  26-38px / 700 — magazine, health, enemy count
 *   CURRENT DECISION    20px / 700    — prompt, its cost, the objective verb
 *   BACKGROUND          <=18px / 500-600 — reserve, points, frags, weapon
 *                       name, and every field label
 * Size and weight together: the self-hosted faces stop at 700 (Oswald) and
 * 600 (Plex Mono), so 800/900 render AS 700 and the only real weight step is
 * below it. Values are read under fire; labels are read once, so they are the
 * lightest thing here. --hud-scale multiplies all of it (Settings). */
#hud .hud-key {
  color: var(--hud-key);
  font: 500 calc(12 * var(--u))/1.1 var(--font-mono);
  letter-spacing: .16em;
  text-transform: uppercase;
}

/* ------------------------------------------------------------- objective */
#hud #mission {
  color: var(--hud-key);
  background: var(--hud-scrim-tl);
  border: 0;
  border-left: 3px solid var(--amber);
  box-shadow: none;
  opacity: 0;
  transition: opacity .25s;
}
#hud #mission.show { opacity: 1; }
#hud #mission-kicker {
  color: var(--amber);
  font: 500 calc(12 * var(--u))/1.1 var(--font-mono);
  letter-spacing: .2em; text-transform: uppercase;
  text-shadow: var(--hud-text-shadow);
}
#hud #mission-title {
  color: var(--hud-ink);
  font: 700 calc(20 * var(--u))/1.16 var(--font-display);
  letter-spacing: .05em; text-transform: uppercase;
  text-shadow: 0 2px 5px var(--ink), 0 0 12px rgba(0, 0, 0, .8);
}
#hud #mission-detail {
  color: var(--hud-key);
  font: 500 calc(13 * var(--u))/1.4 var(--font-mono);
  letter-spacing: .04em;
  text-shadow: var(--hud-text-shadow);
}
#hud #mission-meta {
  border-top: 1px solid rgba(216, 208, 186, .18);
  color: var(--amber);
  font: 600 calc(12 * var(--u))/1.1 var(--font-mono);
  letter-spacing: .1em; text-transform: uppercase;
  text-shadow: var(--hud-text-shadow);
}
#hud #mission-distance { color: var(--hud-key); }
#hud #objective-marker {
  color: var(--amber);
  font: 700 calc(13 * var(--u))/1 var(--font-mono);
  letter-spacing: .12em;
  text-shadow: 0 2px 5px var(--ink), 0 0 12px var(--ink);
}
#hud #objective-marker:before {
  content: "";
  border: 1px solid var(--amber);
  background: rgba(118, 76, 30, .24);
  transform: rotate(45deg);
  box-shadow: 0 0 13px rgba(231, 184, 115, .46);
  animation: signalMarker 1.1s ease-in-out infinite;
}
@keyframes signalMarker { 50% { transform: rotate(45deg) scale(1.35); opacity: .55; } }

/* Downed mate: Second Wind blue, not amber — the objective is a place, this
   is a person. Pulse is the only motion; geometry stays in hud-layout. */
#hud #mate-down {
  color: #7fb2e8;
  font: 700 calc(13 * var(--u))/1.25 var(--font-mono);
  letter-spacing: .1em;
  text-shadow: 0 2px 5px var(--ink), 0 0 12px var(--ink);
  text-align: center;
}
#hud #mate-down .md-arrow { filter: drop-shadow(0 0 6px rgba(127, 178, 232, .5)); animation: mateDownPulse 1.4s ease-in-out infinite; }
#hud #mate-down-dist { color: rgba(127, 178, 232, .82); font-weight: 400; }
@keyframes mateDownPulse { 50% { opacity: .5; } }
@media (prefers-reduced-motion: reduce) {
  #hud #mate-down .md-arrow { animation: none; }
}

/* Side objectives: cyan is power and radio, so a live row is cyan; amber
   marks a finished one, danger red a relay about to fall. */
#hud #side-ops .so {
  background: var(--hud-scrim-tl);
  border-left: 2px solid var(--cyan);
  color: var(--hud-key);
  font: 500 calc(11 * var(--u))/1.35 var(--font-mono);
  letter-spacing: .06em; text-transform: uppercase;
  text-shadow: var(--hud-text-shadow);
  transition: opacity .3s;
}
#hud #side-ops .so b {
  color: var(--hud-ink);
  font: 700 calc(13 * var(--u))/1.15 var(--font-display);
  letter-spacing: .06em;
}
#hud #side-ops .bar { background: rgba(216, 208, 186, .12); }
#hud #side-ops .bar i { background: var(--cyan); }
#hud #side-ops .so.urgent { border-left-color: var(--danger); }
#hud #side-ops .so.urgent .bar i { background: var(--danger); }
#hud #side-ops .so.done { border-left-color: var(--amber); opacity: .85; }
#hud #side-ops .so.done .bar i { background: var(--amber); }

/* Boss health. Red is damage; the pale strip over it is the iron plating. */
#hud #boss-bar .bb-name {
  color: var(--hud-ink);
  font: 700 calc(13 * var(--u))/1 var(--font-display);
  letter-spacing: .3em; text-transform: uppercase;
  text-shadow: var(--hud-text-shadow);
}
#hud #boss-bar .bb-track {
  border: 1px solid rgba(216, 208, 186, .4);
  background: rgba(7, 9, 10, .72);
  box-shadow: 0 2px 10px rgba(0, 0, 0, .6);
}
#hud #boss-bar .bb-fill { background: linear-gradient(180deg, #d8301c, #7d130b); }
#hud #boss-bar .bb-armor { background: #bfd3e0; box-shadow: 0 0 6px #bfd3e0; }
#hud #boss-bar.enraged .bb-fill { background: linear-gradient(180deg, #ff8a2a, #b0280c); animation: bossRage .5s ease-in-out infinite; }
@keyframes bossRage { 50% { filter: brightness(1.5); } }
@media (prefers-reduced-motion: reduce) {
  #hud #boss-bar.enraged .bb-fill { animation: none; }
}

/* ------------------------------------------------------ map, enemies, squad */
#hud #minimap {
  background: rgba(7, 9, 10, .34);
  border-radius: 50%;
  box-shadow: 0 0 0 1px rgba(205, 191, 160, .18);
}
#hud #zcount {
  background: var(--hud-scrim-tr);
  border-right: 1px solid rgba(201, 74, 58, .45);
  box-shadow: none;
  font-size: calc(12 * var(--u));
}
#hud #zcount.rising { border-right-color: var(--danger); }
/* Incoming danger is immediate survival: a first-band number. */
#hud #zcount b {
  color: var(--hud-ink);
  font: 700 calc(26 * var(--u))/1 var(--font-display);
  text-shadow: var(--hud-text-shadow);
}
#hud .squad-row {
  font: 500 calc(12 * var(--u))/1.5 var(--font-mono);
  letter-spacing: .08em;
  color: var(--cyan);
  text-shadow: var(--hud-text-shadow);
}
#hud .squad-row.me { color: var(--hud-ink); }
#hud .squad-row.host:after { content: " ★"; color: var(--amber); }
@keyframes squadIn { from { opacity: 0; transform: translateX(14px); } }
#hud .squad-row { animation: squadIn .28s ease-out; }
#hud .kfeed {
  color: var(--hud-key);
  background: none;
  border-left: 2px solid var(--copper);
  font-size: calc(12 * var(--u));
  letter-spacing: .08em; text-transform: uppercase;
  animation: kfeed 3.2s ease forwards;
}
#hud .kfeed.hs { border-left-color: var(--danger); color: var(--tone-ffd6cc); }
@keyframes kfeed { 0% { opacity: 0; transform: translateX(12px); } 8% { opacity: 1; transform: none; } 70% { opacity: 1; } 100% { opacity: 0; } }

/* The map switch is a key hint, not a boxed web button: same voice as the
   ENEMIES label beside it, and it only brightens under the cursor. */
#map-toggle {
  /* A persistent readout: the HUD contract wants a plate and >= .75 opacity,
     and at .62 on bare night sky it was the one unreadable key in the corner. */
  border: 1px solid rgba(216, 208, 186, .14);
  border-radius: 3px;
  background: rgba(10, 11, 13, .5);
  color: var(--hud-key);
  font: 600 12px/1 var(--font-mono);
  letter-spacing: .16em; text-transform: uppercase;
  text-shadow: var(--hud-text-shadow);
  opacity: .82;
  cursor: pointer;
  transition: opacity .15s, color .15s;
  -webkit-tap-highlight-color: transparent;
}
#map-toggle:hover, #map-toggle:focus-visible { color: var(--tone-fff4dd); opacity: 1; border-right-color: var(--copper); }
#map-toggle[aria-pressed="false"] { opacity: .78; color: var(--tone-6d6a62); }
#map-toggle[aria-pressed="false"]:hover { opacity: 1; }
html.is-touch #map-toggle { border: 1px solid rgba(216, 208, 186, .16); border-radius: 3px; opacity: .8; }

/* ------------------------------------------------------------------ vitals */
#hud #hp-box,
#hud #points-box,
#hud #round-box,
#hud #stam-box {
  background: var(--hud-scrim-bl);
  box-shadow: none;
}
#hud #hp-box { border-left: 3px solid var(--danger); }
/* Mirrored for a left-handed pad (see hud-layout.css); the accent stays with
   the readout, it just changes which edge it marks. */
html.left-handed #hud #hp-box { border-right-color: var(--danger); }
html.left-handed #hud #points-box { border-right-color: var(--amber); }
html.left-handed #hud #round-box { border-right-color: var(--copper); }
html.left-handed #hud #stam-box { border-right-color: var(--tone-6f8f3f); }
#hud #points-box {
  border-left: 3px solid var(--amber);
  background-image: var(--hud-scrim-bl);
  background-repeat: no-repeat;
  background-size: 100% 100%;
  background-color: transparent;
}
#hud #round-box { border-left: 3px solid var(--copper); }
#hud #stam-box { border-left: 3px solid var(--tone-6f8f3f); opacity: 0; transition: opacity .3s; }

/* At 28px the running total was louder than the health above it. The purchase
   decision is carried by the prompt, which names the cost and reddens it when
   it cannot be paid, so the total itself is background. */
#hud #points {
  color: var(--hud-ink);
  font: 600 calc(18 * var(--u))/1 var(--font-display);
  letter-spacing: .02em;
  text-shadow: 0 2px 4px var(--ink), 0 0 10px var(--ink);
}
#hud #points:after { content: none; }
#hud #hp-num {
  color: var(--hud-ink);
  font: 700 calc(30 * var(--u))/1 var(--font-display);
  text-shadow: var(--hud-text-shadow);
}
/* Critical health is a state like a dry magazine, and reads in the same red.
   .crit is set by updateHp at the 30% the bar already changes at. */
#hud #hp-box.crit #hp-num { color: var(--tone-ff8578); }
#hud #hp-bar {
  background: rgba(0, 0, 0, .72);
  border: 1px solid rgba(255, 255, 255, .18);
  border-radius: 2px;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .55);
}
#hud #hp-fill { background: linear-gradient(90deg, #5a1812, #b04538); transition: width .12s linear; }
#hud #hp-fill.mid { background: linear-gradient(90deg, #5a4012, #b09018); }
#hud #hp-fill.ok { background: linear-gradient(90deg, #16401e, #28a84e); }
#hud #stam-bar { background: rgba(0, 0, 0, .72); box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .55); }
#hud #stam-fill { background: linear-gradient(90deg, #3e5a24, #88b844); transition: width .08s linear; }

/* The round counter is a segmented containment seal — a mechanical exposure
   counter off a drum, painted by containmentSealCanvas(). It is a machined
   object, so it hangs straight rather than at the hand-daubed angle the chalk
   tally it replaced was drawn at. */
#hud #round-tally {
  background-repeat: no-repeat;
  background-size: contain;
  font-size: 0;
  filter: drop-shadow(0 3px 5px rgba(0, 0, 0, .8));
}
#hud #round-num {
  color: var(--hud-ink);
  font: 900 calc(46 * var(--u))/1 var(--font-display);
  font-style: italic;
  letter-spacing: -.02em;
  text-shadow: 3px 4px 0 rgba(0, 0, 0, .85), 0 0 18px rgba(0, 0, 0, .9);
  transform: skew(-7deg);
}
#hud .perk-chip {
  background: none; border: 0;
  filter: drop-shadow(0 2px 4px rgba(0, 0, 0, .7));
}

/* ------------------------------------------------------------------ weapon */
#hud #ammo-box {
  background: var(--hud-scrim-br);
  border-right: 2px solid rgba(216, 208, 186, .18);
  box-shadow: none;
}
#hud #wpn-name {
  color: var(--hud-ink);
  font: 600 calc(14 * var(--u))/1.1 var(--font-ui);
  letter-spacing: .04em;
  text-shadow: var(--hud-text-shadow);
}
#hud #wpn-name.pap { color: var(--cyan); }
#hud #ammo-line {
  color: var(--hud-ink);
  font-family:var(--font-display);
  text-shadow: 0 2px 4px var(--ink), 0 0 10px var(--ink);
}
/* Rounds in the gun is the first band, rounds in the bag the third: 36 and 22
   were near enough that both had to be read to find the one that decides
   whether to keep firing. Now it is better than 2:1. */
#hud #ammo-mag { font-size: calc(38 * var(--u)); font-weight: 700; }
#hud #ammo-res { color: var(--hud-key); font-size: calc(17 * var(--u)); font-weight: 600; }
#hud #ammo-key { opacity: .92; }
#hud #nade-pips { color: var(--hud-key); font-size: calc(12 * var(--u)); letter-spacing: 3px; }
#hud #nade-pips .monkey { color: var(--copper); }
#hud #nade-box {
  background: var(--hud-scrim-br);
  border-right: 2px solid rgba(216, 208, 186, .16);
  box-shadow: none;
}
#hud #nade-icon { opacity: 1; filter: brightness(1.4) contrast(1.14) drop-shadow(0 2px 2px var(--ink)); }
#hud #nade-count {
  color: var(--hud-ink);
  font: 600 calc(16 * var(--u))/1 var(--font-display);
  text-shadow: var(--hud-text-shadow);
}
#hud .alt-wpn {
  color: #a39c8c;   /* was 6d6a62: ~2.3:1 on the plate, under the legibility floor (AAA audit) */
  font: 500 calc(12 * var(--u))/1.5 var(--font-mono);
  letter-spacing: .13em; text-shadow: 0 1px 0 var(--ink);
}
#hud .alt-wpn b { color: #d8d0ba; }
#hud .alt-wpn.pap { color: var(--tone-4d7b93); }
#hud .alt-wpn.pap b { color: var(--cyan); }

/* Reload belongs to the weapon block, not to a lone word floating over the
   crosshair at 58% screen height. */
#hud #ammo-box.reloading {
  border-right-color: var(--amber);
  animation: ammoReload .9s ease-in-out infinite;
}
#hud #ammo-box.dry #ammo-mag { color: var(--tone-ff8578); }
#hud #ammo-box.spent {
  border-right-color: var(--danger);
  animation: ammoSpent 1s ease-in-out infinite;
}
#hud #ammo-box.spent #ammo-mag,
#hud #ammo-box.spent #ammo-res { color: var(--tone-ff8578); }
@keyframes ammoReload { 50% { box-shadow: 0 0 16px rgba(231, 184, 115, .35); } }
@keyframes ammoSpent { 50% { box-shadow: 0 0 16px rgba(201, 74, 58, .4); } }

/* ------------------------------------------------------------------ centre */
#hud #xhair i { background: rgba(255, 252, 239, .96); box-shadow: 0 0 2px var(--ink), 0 0 5px rgba(0, 0, 0, .9); }
#hud #hitmark { opacity: 0; }
#hud #hitmark i { background: var(--paper); box-shadow: 0 0 4px var(--ink); }
#hud #hitmark.red i { background: var(--danger); box-shadow: 0 0 6px rgba(201, 74, 58, .9); }

#hud #banner { opacity: 0; pointer-events: none; transition: opacity .45s; }
body.pause-open #hud #banner { opacity: 0; visibility: hidden; }
#hud #banner {
  background: var(--hud-scrim-tl);
  border-left: 2px solid var(--amber);
  text-shadow: var(--hud-text-shadow);
}
#hud #banner-main {
  color: var(--hud-ink);
  font: 700 calc(22 * var(--u))/1.15 var(--font-display);
  letter-spacing: .05em; text-transform: uppercase;
  overflow-wrap: anywhere;
}
#hud #banner-sub {
  color: var(--paper-mute);
  font: 600 calc(13 * var(--u))/1.4 var(--font-mono);
  letter-spacing: .02em;
  overflow-wrap: anywhere;
}
@media (max-width: 480px), (max-height: 430px) {
  #hud #banner-main { font-size: calc(18 * var(--u)); }
  #hud #banner-sub { font-size: calc(12 * var(--u)); }
}
#hud #mastery-callout {
  color: var(--hud-ink);
  background: var(--hud-scrim-bl);
  border-left: 2px solid var(--amber);
  font: 700 calc(13 * var(--u))/1.3 var(--font-mono);
  letter-spacing: .1em; text-transform: uppercase;
  text-shadow: var(--hud-text-shadow);
  text-wrap: pretty;
  opacity: 0;
  transition: opacity .18s ease;
}
#hud #mastery-callout.show { opacity: 1; }
#hud .pill {
  color: var(--hud-ink);
  background: var(--hud-scrim-bl);
  border: 0;
  box-shadow: inset 3px 0 var(--cyan);
  font: 700 calc(12 * var(--u))/1 var(--font-mono);
  letter-spacing: .1em; text-transform: uppercase;
}
#hud .pill.gold { box-shadow: inset 3px 0 var(--amber); }
#hud .pill.pink { box-shadow: inset 3px 0 var(--copper); }
#hud .pill.orange { box-shadow: inset 3px 0 var(--copper); }
#hud .pill.stim { box-shadow: inset 3px 0 #c9a06a; }
#hud .pill .bar { background: rgba(216, 208, 186, .8); }
#hud .ppop {
  color: var(--amber);
  font: 700 calc(18 * var(--u))/1 var(--font-mono);
  text-shadow: 2px 2px 3px rgba(0, 0, 0, .9);
  animation: ppop .9s ease-out forwards;
  pointer-events: none;
}
#hud .ppop.spent { color: var(--danger); }
@keyframes ppop {
  0% { opacity: 0; transform: translateY(6px) scale(.7); }
  15% { opacity: 1; transform: translateY(0) scale(1.1); }
  100% { opacity: 0; transform: translateY(-8px) scale(1); }
}
#hud #lowhp {
  opacity: 0; pointer-events: none;
  background: radial-gradient(ellipse at center, transparent 35%, rgba(140, 0, 0, .5) 100%);
}
#hud #revive-bar .lbl {
  color: var(--cream-400);
  font: 700 calc(11 * var(--u))/1 var(--font-mono);
  letter-spacing: .3em;
  text-shadow: 0 1px 0 var(--ink);
}
#hud #revive-track { background: rgba(6, 8, 12, .85); box-shadow: inset 0 0 5px var(--ink); }
#hud #revive-fill { background: linear-gradient(90deg, var(--blood-deep), var(--blood)); box-shadow: none; }
#hud #round-splat { opacity: 0; background-size: cover; background-position: center; pointer-events: none; }
#hud #round-splat.play { animation: splat 2.4s ease-out forwards; }
#hud #round-splat.play.dogs { animation: splat-dogs 2.4s ease-out forwards; }
@keyframes splat { 0% { opacity: 0; transform: scale(1.22); } 12% { opacity: .48; transform: scale(1); } 50% { opacity: .28; } 100% { opacity: 0; transform: scale(1.03); } }
@keyframes splat-dogs { 0% { opacity: 0; filter: hue-rotate(-25deg) saturate(1.8); transform: scale(1.28); } 10% { opacity: .8; transform: scale(1); } 50% { opacity: .55; } 100% { opacity: 0; } }

/* --------------------------------------------------- prompt and subtitle */
#hud #prompt { opacity: 0; transition: opacity .12s; }
#hud #prompt.show { opacity: 1; }
/* The current decision — what the key does, its cost, why it is refused.
   Second band, so every part of it clears the 18px floor. */
#hud #prompt-text {
  color: var(--hud-ink);
  font: 700 calc(20 * var(--u))/1.3 var(--font-ui);
  letter-spacing: .07em; text-transform: uppercase;
  background: var(--hud-scrim-bl);
  border: 1px solid var(--hud-edge);
  border-left: 3px solid var(--amber);
  box-shadow: none;
  text-shadow: var(--hud-text-shadow);
}
/* theme.css prefixed every prompt with `content:"[ " attr(data-key) " ]"`, and
   nothing has ever set data-key — so every prompt read "[ ] HOLD F TO …". */
#hud #prompt-text:before { content: none; }
#hud #prompt-text .cost-no { color: var(--tone-ff8578); font-weight: 800; }
/* The refusal reason is part of the decision, not a footnote to it: it takes
   the prompt's own size at every tier rather than a 13px gloss. */
#hud #prompt-text .cost-no-line {
  color: var(--tone-ff8578);
  letter-spacing: .14em;
}
#hud #prompt-bar { background: var(--amber); box-shadow: 0 0 8px rgba(231, 184, 115, .7); transition: width .05s linear; }

#signal-subtitle {
  color: var(--hud-ink);
  font: 700 calc(16 * var(--hud-sub-scale) * 1px)/1.45 var(--font-mono);
  letter-spacing: .04em;
  background: rgba(5, 7, 8, var(--hud-sub-plate));
  text-shadow: 0 2px 5px var(--ink);
  opacity: 0;
  transition: opacity .22s;
}
#signal-subtitle.show { opacity: 1; }
#signal-subtitle:empty { background: none; }
#signal-subtitle b { color: var(--amber); }
html.coaching #signal-subtitle { opacity: 0; }

/* ------------------------------------------------------------- viewmodel */
#vm { filter: sepia(.06) saturate(.86) contrast(1.05); }
#vm-img { filter: drop-shadow(0 18px 22px rgba(0, 0, 0, .72)); }
#vm.upgraded #vm-img {
  filter: saturate(1.18) contrast(1.06) sepia(.12) hue-rotate(155deg)
    drop-shadow(0 0 8px rgba(120, 168, 173, .25)) drop-shadow(0 18px 22px rgba(0, 0, 0, .74));
}
#vm-fallback {
  background: linear-gradient(160deg, var(--tone-3a3f45), var(--tone-181b1e));
  border: 1px solid var(--ink); border-radius: 6px 22px 4px 4px;
  box-shadow: inset 0 2px 0 rgba(255, 255, 255, .12), 0 10px 30px rgba(0, 0, 0, .8);
}
#muzzle {
  opacity: 0;
  background: radial-gradient(circle, rgba(255, 240, 190, .95) 0%, rgba(255, 160, 60, .75) 26%, rgba(255, 90, 20, .28) 52%, transparent 72%);
}
#slash {
  opacity: 0;
  background: linear-gradient(90deg, transparent 8%, rgba(255, 255, 255, .92) 44%, rgba(190, 220, 255, .34) 58%, transparent 76%);
  filter: blur(7px);
}
#slash.rev { --d: -1; }
#slash.play { animation: slashA .3s cubic-bezier(.16, .84, .3, 1); }
@keyframes slashA {
  0% { opacity: 0; transform: translate(-50%, -50%) rotate(calc(38deg * var(--d))) scaleX(.1); }
  16% { opacity: .95; }
  100% { opacity: 0; transform: translate(-50%, -50%) rotate(calc(-14deg * var(--d))) scaleX(1); }
}
/* The weapon cache is a frequency-requisition console: a signal readout, not a
   toy box. Copper for the carrier, amber for the item it settles on. Cache
   Clearance (fire sale) flips the plate to emergency rust so the 10-point
   window is unmissable without arcade magenta. */
#box-cycle {
  border: 1px solid rgba(184, 115, 69, .55);
  border-left: 3px solid var(--copper);
  background: linear-gradient(104deg, rgba(7, 9, 10, .92), rgba(28, 22, 14, .82));
  box-shadow: 0 10px 35px var(--ink), inset 0 0 22px rgba(184, 115, 69, .12);
  opacity: 0; transition: opacity .1s, box-shadow .2s, border-color .2s;
  clip-path: polygon(0 5%, 96% 0, 100% 91%, 94% 100%, 3% 96%);
}
#box-cycle.visible { opacity: 1; }
#box-cycle.offer {
  box-shadow: 0 10px 35px var(--ink), 0 0 22px rgba(232, 166, 75, .32), inset 0 0 22px rgba(184, 115, 69, .16);
}
#box-cycle.sale {
  border-color: rgba(184, 115, 69, .82);
  border-left-color: var(--blood);
  background: linear-gradient(104deg, rgba(18, 8, 6, .94), rgba(42, 22, 12, .84));
  box-shadow: 0 10px 40px #000, 0 0 18px rgba(141, 18, 12, .35), inset 0 0 22px rgba(184, 115, 69, .18);
}
#box-cycle-state {
  color: var(--copper);
  font: 700 9px/1.2 var(--font-mono);
  letter-spacing: .19em; text-transform: uppercase;
}
#box-cycle.sale #box-cycle-state { color: var(--amber-hot); }
#box-cycle img { filter: sepia(.12) drop-shadow(0 0 16px rgba(231, 184, 115, .8)); }
#box-cycle.sale img { filter: sepia(.2) saturate(1.05) drop-shadow(0 0 12px rgba(184, 115, 69, .7)); }
#box-cycle-name {
  overflow: hidden;
  color: var(--paper-hud);
  font: 800 12px/1.25 var(--font-display);
  letter-spacing: .11em; text-align: center; text-overflow: ellipsis;
  text-transform: uppercase; white-space: nowrap; text-shadow: 1px 2px var(--ink);
}
#fade { background: var(--ink); opacity: 1; transition: opacity .8s; }

@media (prefers-reduced-motion: reduce) {
  #hud #mission, #hud #mastery-callout, #signal-subtitle { transition: none; }
  #hud #ammo-box.reloading, #hud #ammo-box.spent, #hud #objective-marker:before, #hud .squad-row { animation: none; }
}

/* COMPACT TYPE. The v0.13 audit set a 14px floor for essential HUD text and a
   22px floor for values; this keeps both while taking the numbers down to the
   smallest size that still clears them, because on a 320px screen every pixel
   of readout is a pixel of the fort the player cannot see. The 18px floor is
   a 1080p rule; what carries over is the ORDER — magazine, health, enemies,
   then the rest. */
@media (max-width: 480px), (max-height: 430px) {
  #hud #mission-title { font-size: calc(14 * var(--u)); }
  #hud #mission-meta { font-size: calc(12 * var(--u)); }
  #hud #ammo-mag { font-size: calc(24 * var(--u)); }
  #hud #ammo-res { font-size: calc(15 * var(--u)); }
  #hud #wpn-name { font-size: calc(12 * var(--u)); }
  #hud #points { font-size: calc(18 * var(--u)); }
  #hud #hp-num { font-size: calc(21 * var(--u)); }
  #hud #zcount b { font-size: calc(19 * var(--u)); }
  #hud #round-num { font-size: calc(24 * var(--u)); }
  #hud #prompt-text { font-size: calc(19 * var(--u)); }
  #hud .hud-key { font-size: calc(11 * var(--u)); font-weight: 500; }
}

html.hud-no-scrim #hud #mission,
html.hud-no-scrim #hud #zcount,
html.hud-no-scrim #hud #hp-box,
html.hud-no-scrim #hud #points-box,
html.hud-no-scrim #hud #round-box,
html.hud-no-scrim #hud #stam-box,
html.hud-no-scrim #hud #ammo-box,
html.hud-no-scrim #hud #nade-box,
html.hud-no-scrim #hud #mastery-callout,
html.hud-no-scrim #hud .pill,
html.hud-no-scrim #hud #prompt-text,
html.hud-no-scrim #map-toggle {
  background: none;
  background-image: none;
  box-shadow: none;
}

#vm-debug {
  color: #e6dfcc;
  font: 700 11px/1.4 var(--font-mono);
  text-shadow: 0 1px 2px rgba(0, 0, 0, .95), 0 0 10px rgba(0, 0, 0, .75);
  white-space: pre;
}

/* Colourblind: remap HUD state + objective colours only — not a full-screen filter. */
html[data-cb="protanopia"] {
  --danger: #c9a24a;
  --danger-hot: #d8b45a;
  --denied: #b8963a;
  --blood: #a87828;
  --blood-hot: #c09038;
  --cyan: #5a9ec8;
  --rot-cyan: #5a9ec8;
  --copper: #c4a050;
  --amber: #d4c060;
  --amber-hot: #e8d878;
}
html[data-cb="deuteranopia"] {
  --danger: #d4a040;
  --danger-hot: #e0b050;
  --denied: #c09038;
  --blood: #b07a28;
  --blood-hot: #c89038;
  --cyan: #6a8ad0;
  --rot-cyan: #6a8ad0;
  --copper: #c8a848;
  --amber: #dcc868;
  --amber-hot: #eee080;
}
html[data-cb="tritanopia"] {
  --danger: #d06060;
  --danger-hot: #e07070;
  --denied: #c05050;
  --cyan: #6a9e70;
  --rot-cyan: #6a9e70;
  --copper: #c07070;
  --amber: #e09090;
  --amber-hot: #f0a8a8;
}

html.hud-hi-contrast {
  --hud-ink: #fff8ee;
  --hud-key: #fff4e0;
  --hud-text-shadow: 0 1px 2px #000, 0 0 4px #000, 0 0 12px #000;
}
html.hud-hi-contrast #hud #hp-fill,
html.hud-hi-contrast #hud #stam-fill,
html.hud-hi-contrast #hud #prompt-bar {
  filter: contrast(1.35) saturate(1.1);
}
html.hud-hi-contrast #hud .hud-key,
html.hud-hi-contrast #hud #mission,
html.hud-hi-contrast #hud #ammo-mag {
  color: #fff8ee;
}
