/* Wastelanday — sun-bleached sand and rust over dark ash, toxic-green glow. */
:root {
  --bg: #12100e;
  --panel: #1c1916;
  --panel-edge: #2e2822;
  --ground: #6f6248;
  --ground-alt: #5d5340;
  --wall: #2a241d;
  --board-bg: #0a0908;
  --text: #e2dbcd;
  --dim: #9a8f7c;
  --amber: #e8a33c;
  --rust: #b4552d;
  --toxic: #7ee06a;
  --hp: #d9533c;
  --hp-track: #35201c;
  --steel: #8a8f96;

  --r-common: #cfd6dd;
  --r-uncommon: #6ecf5f;
  --r-rare: #4fa3e8;
  --r-epic: #b07ae8;
  --r-valuable: #e8a33c;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  min-height: 100%;
  background: var(--bg);
  color: var(--text);
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

/* ---------- top bar ---------- */
#topbar {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  flex-wrap: wrap;
  padding: 12px 16px;
  border-bottom: 1px solid var(--panel-edge);
  position: relative;
}
#topbar-meta { display: flex; align-items: center; gap: 8px; }
#logo { width: 34px; height: 34px; flex: none; }
#topbar h1 {
  margin: 0;
  font-family: Georgia, "Palatino Linotype", "Times New Roman", serif;
  font-size: 28px;
  letter-spacing: 5px;
  text-transform: uppercase;
  color: var(--amber);
  text-shadow: 0 0 18px rgba(232, 163, 60, .3);
}
#date-label { color: var(--dim); font-size: 13px; }
#mode-label {
  font-size: 11px; letter-spacing: 1px; text-transform: uppercase;
  color: var(--rust); border: 1px solid var(--rust); border-radius: 4px; padding: 1px 6px;
}
#mode-label:empty { display: none; }
#share-btn {
  position: absolute; right: 16px;
  background: var(--panel); color: var(--amber);
  border: 1px solid var(--panel-edge); border-radius: 6px;
  padding: 5px 13px; font-size: 12px; letter-spacing: 1px;
  text-transform: uppercase; cursor: pointer;
}
#share-btn:hover { background: var(--panel-edge); }

/* The absolutely-positioned Share and Sound buttons sat on top of the centred
   title and date on any narrow window — a landscape phone at 740px showed
   "2026-" disappearing under Sound. Below 900px the bar becomes honest rows. */
@media (max-width: 900px) {
  #topbar { gap: 8px 10px; padding: 10px 12px 12px; }
  #topbar h1 { font-size: 20px; letter-spacing: 3px; }
  #logo { width: 26px; height: 26px; }
  #share-btn { position: static; order: 3; }
  /* the date and mode badge always get their own line, so nothing can collide */
  #topbar-meta { order: 4; flex-basis: 100%; justify-content: center; }
  #topbar h1 { flex: 1 1 auto; text-align: left; }
}
@media (max-width: 380px) {
  #topbar h1 { font-size: 17px; letter-spacing: 2px; }
}

/* ---------- layout ---------- */
#layout {
  display: flex;
  gap: 18px;
  align-items: flex-start;
  justify-content: center;
  padding: 18px;
  flex-wrap: wrap;
  max-width: 1400px;
  margin: 0 auto;
}
#board-wrap { flex: 1 1 420px; max-width: 620px; }
@media (orientation: landscape) and (max-height: 620px) {
  #board-wrap { max-width: min(620px, 66vh); }
}
#side { flex: 1 1 300px; max-width: 400px; }

#game {
  width: 100%;
  aspect-ratio: 1 / 1;
  display: block;
  background: var(--board-bg);
  border: 1px solid var(--panel-edge);
  border-radius: 8px;
}

/* the hard boundary of the zone — a quiet rust line, not a hazard barricade */
.map-edge {
  fill: none;
  stroke: var(--rust);
  stroke-width: 2.5;
  opacity: .45;
  pointer-events: none;
}
.map-edge-glow {
  fill: none;
  stroke: var(--rust);
  stroke-width: 9;
  opacity: .07;
  pointer-events: none;
}

#minimap-panel {
  background: var(--panel); border: 1px solid var(--panel-edge);
  border-radius: 8px; padding: 10px 12px 11px;
}
#minimap-panel h3 {
  margin: 0 0 8px; font-size: 11px; letter-spacing: 1.6px;
  text-transform: uppercase; color: var(--dim); font-weight: 600;
}
#minimap {
  display: block; margin: 0 auto; width: 100%; max-width: 190px; height: auto;
  background: #0a0908; border: 1px solid var(--panel-edge); border-radius: 5px;
}
#mini-key {
  display: flex; flex-wrap: wrap; justify-content: center; gap: 4px 12px;
  margin-top: 9px; font-size: 10px; color: var(--dim);
}
#mini-key span { display: inline-flex; align-items: center; gap: 4px; }
.mk { width: 7px; height: 7px; border-radius: 50%; display: inline-block; }
.mk.you { background: #fff0c4; }
.mk.goal { background: var(--toxic); }
.mk.entry { background: #7fd0e0; }
.mk.foe { background: #e0553c; }
.mk.loot { background: var(--amber); }
/* the crater, banded — even unexplored ground shows you how deep it goes */
.mm-cell { fill: #14120f; }
.mm-cell.r1 { fill: #17150f; }
.mm-cell.r2 { fill: #1c1a11; }
.mm-cell.r3 { fill: #221e12; }
.mm-cell.r4 { fill: #2a2313; }
.mm-cell.known { fill: #3b352a; }
.mm-cell.known.r2 { fill: #423a27; }
.mm-cell.known.r3 { fill: #4a3f25; }
.mm-cell.known.r4 { fill: #554521; }
.mm-cell.seen { fill: #6b5f4a; }
.mm-cell.seen.r3 { fill: #786845; }
.mm-cell.seen.r4 { fill: #86723f; }
.mm-cell.solid { fill: #211d18; }
.mm-cell.rad { fill: #4f6b3a; }
.mm-cell.seen.rad { fill: #5d8038; }
.mm-entry { fill: #7fd0e0; }
.mm-hero { fill: #fff0c4; stroke: #12100e; stroke-width: .18; }
.mm-goal { fill: var(--toxic); }
.mm-goal-ring { fill: none; stroke: var(--toxic); stroke-width: .22; opacity: .9; }
.mm-enemy { fill: #e0553c; }
.mm-loot { fill: var(--amber); }
.mm-view { fill: none; stroke: rgba(255, 255, 255, .5); stroke-width: .18; }

#board-actions { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
#board-actions button {
  flex: 1 1 auto; min-width: 0;
  background: var(--panel); color: var(--text);
  border: 1px solid var(--panel-edge); border-radius: 6px;
  padding: 7px 6px; font-size: 11px; letter-spacing: .5px;
  text-transform: uppercase; cursor: pointer; white-space: nowrap;
}
#board-actions button:hover { background: var(--panel-edge); color: var(--amber); }

/* ---------- board ---------- */
.tile { fill: var(--ground); }
.tile.alt { fill: var(--ground-alt); }
.tile.rad { fill: #4f6b3a; }
.tile.rad-hot { fill: #5d8038; }
.wall { fill: var(--wall); }
.route-hint { fill: none; stroke: var(--toxic); stroke-width: 2; stroke-dasharray: 3 5; opacity: .35; }

/* The board's legend, laid under the art: amber dashes mean take it, cyan
   dashes mean switch it on, red means danger, a solid slab blocks your line of
   sight and a dashed one does not. */
.pad { pointer-events: none; }
.pad-loot { fill: url(#glow-loot); animation: pad-pulse 2.4s ease-in-out infinite; }
.pad-tech { fill: url(#glow-tech); }
.pad-goal { fill: url(#glow-goal); animation: pad-pulse 2.4s ease-in-out infinite; }
.pad-danger { fill: url(#glow-danger); }
.pad-entry { fill: url(#glow-tech); opacity: .5; }

/* the flare, and then the ride */
.extract-ring {
  fill: none; stroke: var(--toxic); stroke-width: 2.5; stroke-dasharray: 7 5;
  animation: reticle-spin 5s linear infinite, pad-pulse 1.1s ease-in-out infinite;
  transform-box: fill-box; transform-origin: center;
}
.extract-count {
  font: 700 15px/1 system-ui, sans-serif; fill: var(--toxic);
  text-anchor: middle; paint-order: stroke; stroke: #0a0908; stroke-width: 3;
}
/* cover keeps a plate: it is ground you cannot cross, and a tall plate also
   means the sightline stops here */
.pad-solid { fill: #241f18; stroke: rgba(0, 0, 0, .5); stroke-width: 1.5; }
.pad-low { fill: rgba(28, 24, 18, .5); }
@keyframes pad-pulse { 0%, 100% { opacity: .72; } 50% { opacity: 1; } }

/* ---------- the zone is never quite still ----------
   All of it lives on the symbols in the sprite sheet, so every instance of a
   thing moves together — which for a handful of fires and barrels reads as one
   place breathing rather than a crowd out of step. */
.rad-glow { animation: rad-flicker 3.7s steps(1, end) infinite, rad-pulse 2.4s ease-in-out infinite; }
@keyframes rad-flicker {
  0%, 42%, 47%, 63%, 69%, 100% { opacity: 1; }
  44%, 66% { opacity: .68; }
}
.tile.rad, .tile.rad-hot { animation: rad-tile 5.2s ease-in-out infinite; }
@keyframes rad-tile { 0%, 100% { filter: brightness(1); } 50% { filter: brightness(1.13); } }

.fx-rad-mark { animation: rad-mark 2.6s ease-in-out infinite; transform-origin: 16px 20px; }
@keyframes rad-mark { 0%, 100% { opacity: .85; } 50% { opacity: 1; } }
.fx-drip { animation: rad-mark 3.1s ease-in-out infinite; }
.fx-ooze { animation: ooze 4.4s ease-in-out infinite; transform-box: fill-box; transform-origin: center; }
@keyframes ooze { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.11); } }
.fx-bubble { animation: bubble 2.8s ease-in-out infinite; transform-box: fill-box; transform-origin: center; }
.fx-bubble.b2 { animation-duration: 3.6s; animation-delay: -1.2s; }
@keyframes bubble {
  0%, 100% { opacity: 0; transform: translateY(0) scale(.6); }
  40% { opacity: .9; }
  100% { transform: translateY(-5px) scale(1.1); opacity: 0; }
}

.fx-flame { animation: flame 900ms ease-in-out infinite; transform-box: fill-box; transform-origin: 50% 100%; }
@keyframes flame {
  0%, 100% { transform: scaleY(1) scaleX(1) skewX(0deg); }
  30% { transform: scaleY(1.13) scaleX(.92) skewX(-4deg); }
  60% { transform: scaleY(.94) scaleX(1.06) skewX(3deg); }
}
.fx-flame-mid { animation: flame 700ms ease-in-out infinite reverse; transform-box: fill-box; transform-origin: 50% 100%; }
.fx-flame-core { animation: flame 520ms ease-in-out infinite; transform-box: fill-box; transform-origin: 50% 100%; }
.fx-ember { animation: ember 2.4s linear infinite; transform-box: fill-box; transform-origin: center; }
.fx-ember.e2 { animation-duration: 3.2s; animation-delay: -1.4s; }
@keyframes ember {
  0% { opacity: 0; transform: translate(0, 4px) scale(.6); }
  25% { opacity: .95; }
  100% { opacity: 0; transform: translate(-3px, -9px) scale(.3); }
}
.fx-bulb { animation: bulb 5.5s ease-in-out infinite; }
@keyframes bulb { 0%, 88%, 100% { opacity: 1; } 90% { opacity: .55; } 93% { opacity: 1; } 95% { opacity: .7; } }

.fx-beacon { animation: beacon 1.5s ease-in-out infinite; transform-box: fill-box; transform-origin: center; }
@keyframes beacon { 0%, 100% { opacity: .55; transform: scale(.86); } 50% { opacity: 1; transform: scale(1.12); } }
.fx-blink { animation: blink 1.4s steps(1, end) infinite; }
.fx-blink.slow { animation-duration: 2.6s; }
@keyframes blink { 0%, 55% { opacity: 1; } 56%, 100% { opacity: .28; } }
.fx-scan { animation: scan 2.2s ease-in-out infinite; }
@keyframes scan { 0%, 100% { opacity: .55; } 50% { opacity: 1; } }
.fx-glow-eyes { animation: eyeglow 2.9s ease-in-out infinite; }
@keyframes eyeglow { 0%, 100% { opacity: .82; } 50% { opacity: 1; } }

/* enemies breathe, each on its own beat (the delay is set per instance) */
.sprite.en { animation: idle-bob 2.6s ease-in-out infinite; }
@keyframes idle-bob { 0%, 100% { translate: 0 0; } 50% { translate: 0 -1.1px; } }

@media (prefers-reduced-motion: reduce) {
  .rad-glow, .tile.rad, .tile.rad-hot, .fx-rad-mark, .fx-drip, .fx-ooze, .fx-bubble,
  .fx-flame, .fx-flame-mid, .fx-flame-core, .fx-ember, .fx-bulb, .fx-beacon,
  .fx-blink, .fx-scan, .fx-glow-eyes, .sprite.en, .pad-loot, .pad-goal,
  #hero-aura, .evac, .vehicle, .reticle {
    animation: none !important;
  }
}

.pip-enemy { fill: #e0553c; stroke: #1a1512; stroke-width: 1; pointer-events: none; }
.pip-enemy.unaware { fill: #8a7a5f; }

.fog { fill: var(--board-bg); transition: opacity .25s ease; }
.fog.explored { opacity: .62; }
.fog.clear { opacity: 0; }

.sprite-sheet { position: absolute; width: 0; height: 0; overflow: hidden; }

.sprite { transition: x .12s ease, y .12s ease; }
.sprite.unaware { opacity: .5; }
.sprite.dying { opacity: 0; transition: opacity .2s ease; }
#hero-use { transition: x .12s ease, y .12s ease; }
#hero-weapon { pointer-events: none; }

#hero-aura {
  fill: url(#fire-grad);
  pointer-events: none;
  animation: aura-pulse 3s ease-in-out infinite;
}
@keyframes aura-pulse { 0%, 100% { opacity: .26; } 50% { opacity: .42; } }

.light-glow { fill: url(#fire-grad); pointer-events: none; }
.rad-glow { fill: url(#rad-grad); pointer-events: none; animation: rad-pulse 2.4s ease-in-out infinite; }
@keyframes rad-pulse { 0%, 100% { opacity: .65; } 50% { opacity: 1; } }

.vehicle { animation: vehicle-pulse 1.8s ease-in-out infinite; transform-origin: center; }
@keyframes vehicle-pulse { 0%, 100% { opacity: .8; } 50% { opacity: 1; } }

/* reticle over the enemy `F` would hit */
/* Static. It used to spin, and once the blocked-lane line was drawn inside the
   same group the whole thing swung round its bounding box like a compass
   needle. A crosshair is a crosshair. */
.reticle {
  fill: none; stroke: var(--rust); stroke-width: 2.2;
  pointer-events: none;
  animation: reticle-pulse 1.6s ease-in-out infinite;
}
@keyframes reticle-pulse { 0%, 100% { opacity: .85; } 50% { opacity: 1; } }
@keyframes reticle-spin { to { transform: rotate(360deg); } }

.tracer { stroke: #ffe3a0; stroke-width: 2; opacity: .9; animation: tracer-fade .22s ease-out forwards; }
.tracer.enemy { stroke: #ff8a6a; }
.tracer.sentry { stroke: #7fd0e0; }
@keyframes tracer-fade { to { opacity: 0; } }

.dmg-num {
  font: 700 15px/1 system-ui, sans-serif;
  fill: var(--amber); text-anchor: middle;
  animation: dmg-float 1s ease-out forwards; pointer-events: none;
}
.dmg-num.dmg-hero { fill: #ff6a52; }
.dmg-num.dmg-crit { font-size: 20px; fill: #ffd24a; }
.miss-num, .cover-num {
  font: 700 12px/1 system-ui, sans-serif; text-anchor: middle;
  fill: var(--dim); animation: dmg-float .9s ease-out forwards; pointer-events: none;
}
.cover-num { fill: #7fd0e0; }
@keyframes dmg-float {
  0% { opacity: 0; transform: translateY(4px); }
  20% { opacity: 1; }
  100% { opacity: 0; transform: translateY(-16px); }
}

.particle { pointer-events: none; }
.kill-ring {
  fill: none; stroke: #cfd6dd; stroke-width: 2;
  animation: ring-out .5s ease-out forwards; pointer-events: none;
  transform-box: fill-box; transform-origin: center;
}
@keyframes ring-out { to { transform: scale(2.1); opacity: 0; } }
.burst-ring {
  fill: none; stroke: var(--toxic); stroke-width: 3;
  animation: ring-out .6s ease-out forwards; pointer-events: none;
  transform-box: fill-box; transform-origin: center;
}

.sentry-life {
  font: 700 10px/1 system-ui, sans-serif; fill: #7fd0e0;
  text-anchor: middle; pointer-events: none;
}

#hero-use.hit { animation: hero-hit .3s ease; }
@keyframes hero-hit { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }
#board-wrap.shake { animation: board-shake .3s ease; }
@keyframes board-shake {
  0%, 100% { transform: translate(0, 0); }
  25% { transform: translate(-4px, 2px); }
  75% { transform: translate(4px, -2px); }
}

/* ---------- side panel ---------- */
#side { display: flex; flex-direction: column; gap: 12px; }

#class-box {
  background: var(--panel);
  border: 1px solid var(--panel-edge);
  border-radius: 8px;
  padding: 12px 14px;
}
#class-head { display: flex; gap: 10px; align-items: center; }
#class-icon { width: 40px; height: 40px; flex: none; }
#class-name {
  font-family: Georgia, serif; font-size: 18px;
  letter-spacing: 2px; text-transform: uppercase; color: var(--amber);
}
#class-power { font-size: 12px; color: var(--toxic); }
#class-blurb { font-size: 12.5px; line-height: 1.5; color: var(--dim); margin-top: 8px; }

#stats {
  width: 100%; border-collapse: collapse;
  background: var(--panel); border: 1px solid var(--panel-edge); border-radius: 8px;
  font-size: 12.5px; overflow: hidden;
}
#stats th {
  text-align: left; font-weight: 600; color: var(--dim);
  text-transform: uppercase; letter-spacing: .8px; font-size: 10.5px;
  padding: 6px 4px 6px 10px; width: 1%; white-space: nowrap;
}
#stats td {
  padding: 6px 10px 6px 0; color: var(--text);
  font-variant-numeric: tabular-nums;
}
#stats tr + tr th, #stats tr + tr td { border-top: 1px solid var(--panel-edge); }
#stats .warn { color: var(--rust); }
#stats .good { color: var(--toxic); }

#bars {
  background: var(--panel); border: 1px solid var(--panel-edge);
  border-radius: 8px; padding: 10px 12px;
  display: flex; flex-direction: column; gap: 8px;
}
.bar-row { display: flex; align-items: center; gap: 8px; }
.bar-label {
  width: 34px; font-size: 10.5px; letter-spacing: 1px;
  text-transform: uppercase; color: var(--dim);
}
#hp-track { flex: 1; display: flex; gap: 2px; height: 13px; }
.hp-seg { flex: 1; background: var(--hp-track); border-radius: 2px; }
.hp-seg.on { background: var(--hp); }
.hp-seg.lost { background: #241a18; opacity: .55; }
#rad-track {
  flex: 1; height: 13px; border-radius: 3px;
  background: #23261c; overflow: hidden;
}
#rad-fill { height: 100%; width: 0; background: var(--toxic); transition: width .25s ease; }
#hp-num, #rad-num {
  width: 56px; text-align: right; font-size: 12px;
  font-variant-numeric: tabular-nums; color: var(--dim);
}

#inventory {
  background: var(--panel); border: 1px solid var(--panel-edge);
  border-radius: 8px; padding: 10px 12px;
}
#inventory h3 {
  margin: 0 0 8px; font-size: 11px; letter-spacing: 1.6px;
  text-transform: uppercase; color: var(--dim); font-weight: 600;
}
.inv-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 6px; }
.inv-cell {
  position: relative; aspect-ratio: 1; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  background: #17150f; border: 2px solid #3a332a;
  border-radius: 6px; cursor: help;
}
.inv-cell svg { width: 22px; height: 22px; }
/* quality is a corner flash — the frame belongs to "you are holding this" */
.inv-rarity {
  position: absolute; top: 0; right: 0; width: 0; height: 0;
  border-left: 11px solid transparent; border-top: 11px solid var(--r-common);
}
.inv-rarity.common { border-top-color: var(--r-common); }
.inv-rarity.uncommon { border-top-color: var(--r-uncommon); }
.inv-rarity.rare { border-top-color: var(--r-rare); }
.inv-rarity.epic { border-top-color: var(--r-epic); }
.inv-rarity.valuable { border-top-color: var(--r-valuable); }
.inv-cell.held { border-color: var(--amber); background: #241f14; box-shadow: 0 0 8px rgba(232, 163, 60, .3); }
.inv-cell .inv-stat {
  position: absolute; top: -1px; left: 2px;
  font-size: 9px; color: var(--amber); font-weight: 700;
}
.inv-cell .inv-count {
  position: absolute; right: 2px; bottom: 0;
  font-size: 10px; color: var(--text); font-weight: 700;
}
.inv-cell.disabled { opacity: .5; }
.inv-cell.disabled svg { filter: grayscale(1); }
.inv-cell.disabled .inv-rarity { filter: grayscale(1); opacity: .5; }
.inv-cell.disabled::after {
  content: ''; position: absolute; inset: 5px;
  background: linear-gradient(to bottom right,
    transparent calc(50% - 0.6px), rgba(190, 185, 175, .55) calc(50% - 0.6px),
    rgba(190, 185, 175, .55) calc(50% + 0.6px), transparent calc(50% + 0.6px));
}

#rarity-key { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 9px; }
.rk {
  font-size: 9.5px; letter-spacing: .6px; text-transform: uppercase;
  padding: 1px 5px; border-radius: 3px; border: 1px solid;
}
.rk.common { color: var(--r-common); border-color: var(--r-common); }
.rk.uncommon { color: var(--r-uncommon); border-color: var(--r-uncommon); }
.rk.rare { color: var(--r-rare); border-color: var(--r-rare); }
.rk.epic { color: var(--r-epic); border-color: var(--r-epic); }
.rk.valuable { color: var(--r-valuable); border-color: var(--r-valuable); }

#log {
  background: var(--panel); border: 1px solid var(--panel-edge);
  border-radius: 8px; padding: 10px 12px;
  font-size: 12.5px; line-height: 1.6; color: var(--dim);
  min-height: 82px;
}
#log div:last-child { color: var(--text); }

/* ---------- the controller ----------
   Under the board on every screen, not only on a phone: the pad on the left,
   everything you can do on the right, and every button carries the key that
   does the same thing. Without it a desktop player had no hint of what the
   game can do or what the selected survivor's power is. */
#touch-controls {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 10px; margin-top: 10px;
  background: var(--panel); border: 1px solid var(--panel-edge);
  border-radius: 8px; padding: 10px;
}
#dpad {
  flex: none;
  display: grid; grid-template-columns: repeat(3, 46px); grid-template-rows: repeat(3, 46px);
  gap: 4px;
}
.dpad-btn:nth-child(1) { grid-column: 2; grid-row: 1; }
.dpad-btn:nth-child(2) { grid-column: 1; grid-row: 2; }
.dpad-btn:nth-child(3) { grid-column: 2; grid-row: 3; }
.dpad-btn:nth-child(4) { grid-column: 3; grid-row: 2; }
.dpad-btn {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px;
  background: #1c1a14; color: var(--text);
  border: 1px solid #3a362a; border-radius: 7px; cursor: pointer; padding: 0;
}
.dpad-btn b { font-size: 16px; line-height: 1; }
.dpad-btn i { font-style: normal; font-size: 9px; color: var(--dim); letter-spacing: .5px; }
.dpad-btn:active { background: #2e2a1e; border-color: #8a7f5c; }

#touch-actions {
  flex: 1 1 auto; display: grid; gap: 4px;
  grid-template-columns: repeat(4, 1fr);   /* two even rows of four */
}
@media (max-width: 720px) {
  #touch-actions { grid-template-columns: repeat(auto-fit, minmax(62px, 1fr)); }
}
.tbtn {
  position: relative;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px;
  min-height: 46px; padding: 4px 2px;
  background: #1c1a14; color: var(--text);
  border: 1px solid #3a362a; border-radius: 7px; cursor: pointer;
}
.tbtn:active { background: #2e2a1e; border-color: #8a7f5c; }
.tbtn:disabled { opacity: .38; }
.tbtn.call { border-color: #6a5a2e; }
/* the keyboard shortcut, so the two control schemes teach each other */
.tb-key {
  position: absolute; top: 2px; left: 3px;
  font-size: 8px; letter-spacing: .04em; color: var(--dim);
  border: 1px solid #3a362a; border-radius: 3px; padding: 0 3px; line-height: 1.3;
}
.tb-ico { font-size: 15px; line-height: 1; }
.tb-lab { font-size: 10px; letter-spacing: .04em; text-transform: uppercase; }
.tb-sub { font-size: 9px; color: var(--dim); max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* not possible right now — out of ammo, nothing in the reticle, already acted */
.tbtn.off { opacity: .38; }
.tbtn:hover:not(.off), .dpad-btn:hover { border-color: #8a7f5c; }

/* ---------- modals & overlay ---------- */
.modal {
  position: fixed; inset: 0; z-index: 20;
  background: rgba(8, 7, 6, .82);
  display: flex; align-items: center; justify-content: center; padding: 20px;
}
.modal.hidden, #overlay.hidden { display: none; }
.modal-card {
  position: relative;
  background: var(--panel); border: 1px solid var(--panel-edge);
  border-radius: 10px; padding: 20px 22px;
  max-width: 620px; width: 100%; max-height: 86vh; overflow: auto;
}
.modal-card h3 {
  margin: 0 0 6px; font-family: Georgia, serif; font-size: 19px;
  letter-spacing: 2px; text-transform: uppercase; color: var(--amber);
}
.modal-note { margin: 0 0 14px; font-size: 12px; color: var(--dim); }
.modal-close {
  position: absolute; top: 10px; right: 12px;
  background: none; border: none; color: var(--dim);
  font-size: 26px; line-height: 1; cursor: pointer;
}
.modal-close:hover { color: var(--text); }

.class-opt {
  display: flex; gap: 12px; width: 100%; text-align: left;
  background: #17150f; border: 1px solid var(--panel-edge);
  border-radius: 8px; padding: 11px 13px; margin-bottom: 8px;
  color: var(--text); cursor: pointer;
}
.class-opt:hover { border-color: var(--amber); background: #221d14; }
.class-opt > svg { width: 34px; height: 34px; flex: none; }
.class-opt-text { flex: 1; min-width: 0; }
.class-opt-name {
  display: block;
  font-family: Georgia, serif; letter-spacing: 1.4px;
  text-transform: uppercase; color: var(--amber); font-size: 14px;
}
.class-opt-stats { display: block; font-size: 11.5px; color: var(--toxic); margin: 3px 0; }
.class-opt-desc { display: block; font-size: 12px; color: var(--dim); line-height: 1.45; margin-top: 4px; }

.bestiary-row {
  display: flex; gap: 12px; padding: 9px 0;
  border-bottom: 1px solid var(--panel-edge);
}
.bestiary-row svg { width: 30px; height: 30px; flex: none; }
.bestiary-text { flex: 1; font-size: 12px; line-height: 1.45; }
.bestiary-name {
  font-family: Georgia, serif; letter-spacing: 1.2px;
  text-transform: uppercase; color: var(--text);
}
.bestiary-stats { color: var(--toxic); font-size: 11px; }
.bestiary-desc { color: var(--dim); margin-top: 3px; }

.help-body { font-size: 13px; line-height: 1.6; color: var(--dim); }
.help-body b { color: var(--text); }
.keys { width: 100%; border-collapse: collapse; margin: 12px 0; }
.keys th {
  text-align: left; padding: 4px 12px 4px 0; white-space: nowrap;
  color: var(--amber); font-size: 12px; font-weight: 600;
}
.keys td { padding: 4px 0; }
.legend-swatch {
  display: inline-block; width: 16px; height: 16px; border-radius: 4px;
  vertical-align: -3px; margin-right: 6px;
}
.legend-swatch.loot { background: rgba(232, 163, 60, .12); border: 2px dashed var(--amber); }
.legend-swatch.tech { background: rgba(127, 208, 224, .12); border: 2px dashed #7fd0e0; }
.legend-swatch.danger { background: rgba(217, 83, 60, .18); border: 2px solid #d9533c; }
.legend-swatch.solid { background: #221d17; border: 2px solid #100e0b; }
.legend-swatch.lowc { background: rgba(20, 17, 13, .4); border: 2px dashed #6b5f4a; }
.help-body ul { padding-left: 18px; margin: 10px 0 0; }
.help-body li { margin-bottom: 6px; }

#overlay {
  position: fixed; inset: 0; z-index: 30;
  background: rgba(8, 7, 6, .88);
  display: flex; align-items: center; justify-content: center; padding: 20px;
}
#overlay-card {
  background: var(--panel); border: 1px solid var(--panel-edge);
  border-radius: 10px; padding: 24px 26px;
  max-width: 460px; width: 100%; text-align: center; max-height: 90vh; overflow: auto;
}
#overlay-card h2 {
  margin: 0 0 12px; font-family: Georgia, serif; font-size: 24px;
  letter-spacing: 3px; text-transform: uppercase; color: var(--amber);
}
#overlay-body .big { font-size: 17px; margin: 6px 0; }
#overlay-body .best { color: var(--toxic); font-weight: 700; }
#overlay-body .hint { color: var(--dim); font-size: 12.5px; }
#share-snippet {
  background: #17150f; border: 1px solid var(--panel-edge);
  border-radius: 6px; padding: 10px; text-align: left;
  font-size: 12.5px; line-height: 1.5; white-space: pre-wrap;
  color: var(--text); margin: 14px 0 10px;
}
.hint-btn {
  background: var(--panel); color: var(--amber);
  border: 1px solid var(--panel-edge); border-radius: 6px;
  padding: 7px 14px; font-size: 12px; letter-spacing: 1px;
  text-transform: uppercase; cursor: pointer; margin: 0 4px;
}
.hint-btn:hover { background: var(--panel-edge); }

@media (max-width: 720px) {
  #layout { padding: 10px; gap: 12px; }
  #minimap { max-width: 150px; }
  #board-actions button { flex: 1 1 28%; padding: 9px 6px; font-size: 11px; }
}

#credits {
  border-top: 1px solid var(--panel-edge);
  padding: 14px 18px 22px; text-align: center;
  color: var(--dim); font-size: 11.5px; line-height: 1.6;
}
#credits a { color: var(--amber); text-decoration: none; }
#credits b { color: var(--text); }

/* ---------- the holdout ---------- */
.camp-yard { fill: #56503a; stroke: rgba(184, 164, 105, .35); stroke-width: 1.5; }
.camp-gap { fill: rgba(184, 164, 105, .07); stroke: #b8a469; stroke-width: 1.4; stroke-dasharray: 5 4; opacity: .6; }
.gen-glow { fill: url(#glow-goal); animation: pad-pulse 2.4s ease-in-out infinite; }

.deploy-wash { fill: rgba(127, 208, 224, .07); }
.deploy-edge { fill: none; stroke: rgba(127, 208, 224, .5); stroke-width: 1.6; stroke-dasharray: 7 5; }
.gate-pad { fill: rgba(224, 85, 60, .10); stroke: rgba(224, 85, 60, .35); stroke-width: 1.5; }
.gate-arrow { fill: rgba(224, 85, 60, .5); }
.gate.hot .gate-pad { fill: rgba(224, 85, 60, .26); stroke: #e0553c; animation: pad-pulse 1.2s ease-in-out infinite; }
.gate.hot .gate-arrow { fill: #ff8a6a; }

.sel-ring {
  fill: none; stroke: var(--amber); stroke-width: 2.5; stroke-dasharray: 6 4;
  animation: reticle-spin 5s linear infinite; transform-box: fill-box; transform-origin: center;
}
.sprite.spent, .held.spent { opacity: .45; }
.hp-track-mini { fill: rgba(0, 0, 0, .55); }
.hp-friend { fill: #6ecf5f; }
.hp-foe { fill: #d9533c; }

#camp-box, #squad-box {
  background: var(--panel); border: 1px solid var(--panel-edge);
  border-radius: 8px; padding: 11px 13px;
}
#camp-box h3, #squad-box h3 {
  margin: 0 0 9px; font-size: 11px; letter-spacing: 1.6px;
  text-transform: uppercase; color: var(--dim); font-weight: 600;
}
#core-track { flex: 1; height: 13px; border-radius: 3px; background: #35201c; overflow: hidden; }
#core-fill { height: 100%; width: 100%; background: var(--toxic); transition: width .25s ease; }
#core-num { width: 56px; text-align: right; font-size: 12px; color: var(--dim); font-variant-numeric: tabular-nums; }
#camp-box #stats { margin-top: 10px; border: none; background: none; }

#squad { display: flex; flex-direction: column; gap: 6px; }
.unit {
  display: flex; align-items: center; gap: 9px; width: 100%; text-align: left;
  background: #17150f; border: 1px solid var(--panel-edge); border-left: 3px solid var(--panel-edge);
  border-radius: 7px; padding: 7px 9px; color: var(--text); cursor: pointer;
}
.unit svg { width: 26px; height: 26px; flex: none; }
.unit-body { flex: 1; min-width: 0; }
.unit-name {
  display: block; font-family: Georgia, serif; font-size: 12.5px;
  letter-spacing: 1.2px; text-transform: uppercase; color: var(--amber);
}
.unit-bar { display: block; height: 4px; border-radius: 2px; background: #35201c; margin: 4px 0 3px; }
.unit-bar i { display: block; height: 100%; border-radius: 2px; background: #6ecf5f; }
.unit-line { display: block; font-size: 10.5px; color: var(--dim); }
.unit-tag {
  font-size: 9.5px; letter-spacing: 1px; text-transform: uppercase;
  color: var(--dim); flex: none;
}
.unit.ready { border-left-color: var(--toxic); }
.unit.ready .unit-tag { color: var(--toxic); }
.unit.sel { border-color: var(--amber); box-shadow: 0 0 8px rgba(232, 163, 60, .25); }
.unit.spent { opacity: .5; }
.unit.down { opacity: .4; }
.unit.down .unit-name { color: var(--dim); text-decoration: line-through; }
.unit.down .unit-bar i { background: #6b3a30; }

#hint { margin: 9px 0 0; font-size: 11.5px; line-height: 1.45; color: var(--dim); }
#phase-actions { display: flex; gap: 8px; margin-top: 9px; }
#phase-actions button {
  flex: 1; background: var(--panel-edge); color: var(--amber);
  border: 1px solid var(--panel-edge); border-radius: 6px; padding: 8px 10px;
  font-size: 12px; letter-spacing: 1px; text-transform: uppercase; cursor: pointer;
}
#phase-actions button:hover:not(:disabled) { background: #37301f; }
#phase-actions button:disabled { opacity: .4; cursor: default; }
#game { cursor: crosshair; }


/* ---- the camera --------------------------------------------------------
   The world group carries pan and zoom; easing it here keeps the follow
   smooth without a single frame of JavaScript animation. */
#world { transition: transform .18s ease-out; }
@media (prefers-reduced-motion: reduce) { #world { transition: none; } }

/* ---- ground ------------------------------------------------------------ */
.road { fill: #4a4133; stroke: #7d7259; stroke-width: 1.3; stroke-dasharray: 12 9; }
/* ---- autotiled terrain --------------------------------------------------
   Each tile is drawn against its neighbours: a capstone only where the ridge
   ends, a running bond that carries across a whole wall, rails only on the
   open side of a bridge. No sprite sheet — the variants are generated. */
.at { shape-rendering: crispEdges; }
.at-rock { fill: #46403a; }
.at-wall { fill: #56544c; }
.at-water { fill: #2b4a52; }
.at-bridge { fill: #55432c; }
.at-cap { fill: #77746a; }
.at-sky { fill: #625a4c; }
.at-lit { fill: rgba(255, 245, 220, .13); }
.at-foot { fill: rgba(0, 0, 0, .34); }
.at-seam { stroke: rgba(0, 0, 0, .38); stroke-width: 1.1; fill: none; }
.at-crack { stroke: rgba(0, 0, 0, .26); stroke-width: 1; fill: none; stroke-linecap: round; }
.at-facet { stroke: rgba(0, 0, 0, .22); stroke-width: 1.2; fill: none; stroke-linejoin: round; }
.at-rock + .at-facet { stroke: rgba(255, 246, 226, .07); }
.at-shore { fill: rgba(150, 205, 214, .22); }
.at-ripple { fill: none; stroke: rgba(160, 214, 224, .3); stroke-width: 1.1; animation: ripple 4.5s ease-in-out infinite; }
.at-ripple.slow { animation-duration: 7s; animation-delay: -2s; }
@keyframes ripple { 0%, 100% { opacity: .2; transform: translateX(0); } 50% { opacity: .6; transform: translateX(2px); } }
.at-plank { stroke: rgba(0, 0, 0, .38); stroke-width: 1.1; }
.at-rail { fill: #6b5436; }

/* ---- the minimap -------------------------------------------------------
   A corner overlay on the board rather than a standing panel in the sidebar:
   at eight tiles of thirty-three you consult it constantly, and it belongs
   where you are already looking. */
#board-frame { position: relative; line-height: 0; }
#map-toggle {
  position: absolute; top: 10px; right: 10px; z-index: 3;
  width: 32px; height: 32px; line-height: 1; padding: 0;
  background: rgba(20, 18, 13, .82); color: #a9a390;
  border: 1px solid #4a4535; border-radius: 6px;
  font-size: 16px; cursor: pointer;
}
#map-toggle:hover { background: rgba(30, 27, 19, .95); color: #ded7bf; }
#map-toggle.on { color: #d8c46a; border-color: #8a7f5c; }
#map-box {
  position: absolute; top: 50px; right: 10px; z-index: 3;
  /* See-through, so it never hides what is on the tiles underneath it. */
  opacity: .6; background: rgba(16, 15, 10, .82); border: 1px solid #3a362a;
  border-radius: 6px; padding: 8px; line-height: 1.4;
  box-shadow: 0 4px 14px rgba(0, 0, 0, .5);
}
#map-box.hidden { display: none; }
#map-box:hover { opacity: .95; }
/* Sized to the corner, not the board: it is an overlay on a square board, so
   a full-width panel would cover three quarters of what you are looking at. */
#minimap { width: 168px; height: 168px; display: block; border-radius: 4px; background: #16150f; }
@media (max-width: 560px) {
  #map-box { padding: 6px; }
  #minimap { width: 44vw; height: 44vw; max-width: 168px; max-height: 168px; }
  .map-key { font-size: 9px; gap: 5px; }
}
.mm-ground { fill: #201d16; }
.mm-road { fill: #3a3529; }
.mm-water { fill: #24404a; }
.mm-bridge { fill: #4a3a26; }
.mm-solid { fill: #4d4738; }
.mm-low { fill: #38332a; }
.mm-camp { fill: rgba(184, 164, 105, .16); stroke: #8a7f5c; stroke-width: 1; }
.mm-gen { fill: #d8c46a; }
.mm-gate { fill: none; stroke: #6a6350; stroke-width: 1.2; }
.mm-gate.hot { stroke: #e0603c; stroke-width: 2; animation: pad-pulse 1.6s ease-in-out infinite; }
.mm-foe { fill: #e0603c; }
.mm-friend { fill: #7fd0a8; }
.mm-friend.sel { stroke: #fff; stroke-width: 1.2; }
.mm-view { fill: none; stroke: rgba(255, 255, 255, .5); stroke-width: 1.2; }
.map-key { margin: 4px 0 0; font-size: 10px; color: #8b8574; display: flex; gap: 8px; flex-wrap: wrap; }
.map-key i { width: 8px; height: 8px; border-radius: 2px; display: inline-block; margin-right: 3px; vertical-align: -1px; }
.k-friend { background: #7fd0a8; } .k-foe { background: #e0603c; }
.k-gate { background: none; border: 1px solid #6a6350; } .k-gen { background: #d8c46a; }

/* ---- the kit ----------------------------------------------------------- */
#kit { margin: 8px 0; }
.kit-head { font-size: 12px; color: #c9c2ac; display: flex; justify-content: space-between; align-items: baseline; gap: 6px; margin-bottom: 4px; }
.kit-vitals { font-size: 10px; color: #8b8574; }
.kit-rows { display: grid; gap: 3px; }
.kit-row {
  display: flex; align-items: center; gap: 6px; width: 100%; text-align: left;
  background: #1c1a14; border: 1px solid #2e2b21; border-radius: 5px;
  padding: 3px 6px; color: #a9a390; font-size: 11px; cursor: pointer;
}
.kit-row svg { width: 18px; height: 18px; flex: none; }
.kit-ico { width: 18px; text-align: center; flex: none; font-size: 13px; }
.kit-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kit-num { color: #7d7766; font-variant-numeric: tabular-nums; }
.kit-row:hover:not(:disabled) { border-color: #6a6350; color: #ded7bf; }
.kit-row.on { border-color: #8a7f5c; background: #262218; color: #e2dbc2; }
.kit-row.dry { opacity: .45; }
.kit-row:disabled { cursor: default; opacity: .5; }
.traits { display: flex; flex-wrap: wrap; gap: 3px; margin-top: 5px; }
.trait {
  font-size: 10px; padding: 1px 5px; border-radius: 8px;
  background: rgba(138, 127, 92, .16); border: 1px solid rgba(138, 127, 92, .35);
  color: #b3aa8b; cursor: help;
}

/* Supply drops: a soft glow says "worth the walk". */
.cache-glow { fill: url(#glow-loot); animation: pad-pulse 2.4s ease-in-out infinite; }
.sprite.cache { opacity: .95; }
.mm-cache { fill: #d8c46a; opacity: .85; }
.help-body h4 { margin: 14px 0 4px; font-size: 13px; color: #d8c46a; letter-spacing: .04em; }

/* Start / Hold / End must stay reachable — the squad cards and the kit push
   them past the fold on a short screen. */
#phase-actions {
  position: sticky; bottom: 0; z-index: 2;
  padding-top: 6px; margin-top: 4px;
  background: linear-gradient(to top, var(--panel, #191710) 70%, transparent);
}
#minimap { max-width: 200px; margin: 0 auto; }


/* ---- ability badges -----------------------------------------------------
   What makes this survivor different, as a glyph and a number, so nobody has
   to read a paragraph to find out who has the armour. */
.badges { display: flex; flex-wrap: wrap; gap: 3px; }
.badge {
  display: inline-flex; align-items: center; gap: 2px;
  padding: 1px 4px 1px 3px; border-radius: 7px; cursor: help;
  background: rgba(138, 127, 92, .22); border: 1px solid rgba(138, 127, 92, .5);
  color: #d5cba6;
}
.badge svg { width: 12px; height: 12px; display: block; }
.badge b { font-size: 10px; font-weight: 700; font-variant-numeric: tabular-nums; }
.badge.b-medic { background: rgba(200, 64, 47, .2); border-color: rgba(200, 64, 47, .5); color: #e88b7a; }
.badge.b-armor { background: rgba(127, 168, 208, .2); border-color: rgba(127, 168, 208, .5); color: #b8d2ec; }
.badge.b-reach { background: rgba(127, 208, 168, .2); border-color: rgba(127, 208, 168, .5); color: #9fe4c0; }
.badge.b-swift { background: rgba(216, 196, 106, .2); border-color: rgba(216, 196, 106, .5); color: #e4d488; }

/* the badges drawn on the board, under the survivor */
.unit-badges { pointer-events: none; }
.unit-badge { color: #ded7bf; opacity: .95; }
.unit-badge-bg { fill: rgba(12, 11, 8, .8); }

/* ---- the squad's supplies ----------------------------------------------- */
#supply { display: flex; gap: 6px; margin-top: 8px; }
.supply {
  flex: 1; display: flex; align-items: center; gap: 5px;
  background: #14120d; border: 1px solid #2e2b21; border-radius: 5px; padding: 4px 6px;
}
.supply .s-ico { font-size: 13px; line-height: 1; }
.supply .s-num { font-size: 15px; font-weight: 700; color: #ded7bf; font-variant-numeric: tabular-nums; }
.supply .s-lab { font-size: 9px; color: #8b8574; letter-spacing: .06em; text-transform: uppercase; }
.supply.dry { border-color: #7a3227; background: #24120e; }
.supply.dry .s-num { color: #e0603c; }
.supply.low .s-num { color: #d8a04a; }

/* how many steps the selected survivor has left */
.pips { display: inline-flex; gap: 2px; vertical-align: -1px; }
.pip { width: 6px; height: 6px; border-radius: 50%; background: #d8c46a; }
.pip.spent { background: #3e3a2c; }

/* Slow enough to follow with your eye, and it starts a beat after the action
   so you see the shot before the camera leaves. */
#world { transition: transform .34s cubic-bezier(.33, .1, .25, 1); }
@media (prefers-reduced-motion: reduce) { #world { transition: none; } }

/* Something that shoots back, marked on the board. */
.foe-ranged { fill: rgba(224, 96, 60, .22); stroke: #e0603c; stroke-width: 1.2; }
.foe-range-num { fill: #ffcbb8; font-size: 8px; font-weight: 700; text-anchor: middle; }
.k-bdg { width: 13px; height: 13px; vertical-align: -2px; margin-right: 4px; color: #d8c46a; }

/* ---- action points and reach -------------------------------------------
   How far this survivor can still get, and how many actions they have to
   spend — both on the board, so neither is something you count in your head. */
.reach-cell { fill: rgba(127, 208, 224, .10); pointer-events: none; }
.reach-edge { fill: none; stroke: rgba(127, 208, 224, .55); stroke-width: 1.6; stroke-dasharray: 6 4; pointer-events: none; }
.ap { pointer-events: none; }
.ap-bg { fill: rgba(12, 11, 8, .8); }
.ap-pip { fill: #d8c46a; }
.ap-pip.spent { fill: none; stroke: #6a6350; stroke-width: 1.2; }

/* One of yours in the firing lane. There is no roll — the round hits them. */
.reticle.blocked circle, .reticle.blocked path { stroke: #e0603c; }
.lane-blocked { stroke: #e0603c; stroke-width: 2; stroke-dasharray: 4 3; opacity: .85; }
.in-the-way { fill: none; stroke: #e0603c; stroke-width: 2.5; animation: pad-pulse 1.1s ease-in-out infinite; }


/* Grit on the dirt. Without it the ground was a flat field with nothing in it
   to focus on — which is what "the game looks blurry" actually was; the render
   is vector-sharp at any zoom. */
.grit { fill: rgba(38, 31, 21, .34); }
.grit.pale { fill: rgba(214, 199, 168, .16); }
.grit-stone { fill: rgba(30, 25, 17, .26); }
.grit-crack { stroke: rgba(34, 28, 19, .3); stroke-width: 1; fill: none; stroke-linecap: round; }

/* ---- hit reporting ------------------------------------------------------
   Whatever took the hit blinks, and the number floats off it. Every outcome
   is reported — a hit, a miss, a round that buried itself in cover. */
.hit-flash { pointer-events: none; animation: hit-blink .46s ease-out forwards; }
.hit-flash.hurt-friend { fill: #e0603c; }
.hit-flash.hurt-foe { fill: #ffb85c; }
.hit-flash.hurt-none { fill: #c9c2ac; }
@keyframes hit-blink {
  0% { opacity: 0; }
  18% { opacity: .68; }
  100% { opacity: 0; }
}
/* the one whose beat is playing, so you can tell who is moving */
.sprite.en.acting { animation: acting-bob .5s ease-in-out infinite; }
@keyframes acting-bob { 0%, 100% { opacity: 1; } 50% { opacity: .72; } }
@media (prefers-reduced-motion: reduce) {
  .hit-flash, .sprite.en.acting { animation: none; }
}

/* While their turn plays out the board is theirs, not yours. */
#board-frame.busy { cursor: progress; }
#board-frame.busy #game { pointer-events: none; }
#board-frame.busy::after {
  content: ''; position: absolute; inset: 0; border-radius: 8px;
  box-shadow: inset 0 0 0 2px rgba(224, 96, 60, .45); pointer-events: none;
}

/* Half cover: chest-high, ground visible around it, obviously something you
   shoot over rather than through. Full cover keeps the tall capped look. */
.at-lowmass { fill: #5c5a4e; stroke: rgba(0, 0, 0, .4); stroke-width: 1; }
.at-lowcap { fill: #7c7869; }

/* ---- feel ---------------------------------------------------------------
   A hit you take kicks the board and washes it red; one you land just kicks. */
#board-wrap.shake { animation: board-shake .22s ease; }
#board-wrap.shake-hard { animation: board-shake-hard .32s ease; }
@keyframes board-shake-hard {
  0%, 100% { transform: translate(0, 0); }
  15% { transform: translate(-5px, 3px); }
  35% { transform: translate(5px, -3px); }
  55% { transform: translate(-4px, -2px); }
  80% { transform: translate(3px, 2px); }
}
#board-frame.bleeding::before {
  content: ''; position: absolute; inset: 0; border-radius: 8px; z-index: 4;
  pointer-events: none; animation: bleed .42s ease-out forwards;
  background: radial-gradient(ellipse at center, rgba(224, 40, 24, 0) 45%, rgba(200, 30, 18, .55) 100%);
}
@keyframes bleed { 0% { opacity: 0; } 22% { opacity: 1; } 100% { opacity: 0; } }

/* What a body was carrying: smaller and dimmer than a supply crate. */
.sprite.cache.scrap { opacity: .8; transform-box: fill-box; transform-origin: center; scale: .7; }

/* Picked-up supplies fly to the panel that counts them. */
.fly-chip {
  position: fixed; z-index: 60; pointer-events: none;
  font-size: 18px; line-height: 1; margin: -9px 0 0 -9px;
  transition: transform .46s cubic-bezier(.4, 0, .3, 1), opacity .46s ease-in;
}
.supply.took { animation: supply-pop .4s ease-out; }
@keyframes supply-pop {
  0%, 100% { transform: scale(1); }
  40% { transform: scale(1.12); border-color: #d8c46a; }
}
@media (prefers-reduced-motion: reduce) {
  #board-wrap.shake, #board-wrap.shake-hard, #board-frame.bleeding::before, .supply.took { animation: none; }
}

/* Sandbags: the ring a squad throws up outside the concrete. Burlap in a
   running bond — lit top, shadowed base, a seam — so it reads as stacked bags
   rather than a slab with dots on it. */
.at-bags { fill: #4f4530; }
.at-bag { fill: #8f7d52; stroke: rgba(30, 24, 12, .7); stroke-width: .9; stroke-linejoin: round; }
.at-bag-shade { fill: rgba(30, 24, 12, .32); }
.at-bag-seam { stroke: rgba(255, 240, 200, .18); stroke-width: .8; fill: none; }

/* ---- the archive --------------------------------------------------------
   Past nights only. The date is the seed, so a future date would be a future
   night — and every player must get the same night on the same day. */
.archive-note { font-size: 12px; color: var(--dim); line-height: 1.5; margin: 0 0 12px; }
#archive-list { display: grid; gap: 5px; max-height: 46vh; overflow-y: auto; }
.arch-row {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  background: #1c1a14; border: 1px solid #2e2b21; border-radius: 6px;
  padding: 7px 10px; color: var(--text); font-size: 13px; cursor: pointer;
}
.arch-row:hover { border-color: #6a6350; background: #262218; }
.arch-row.today { border-color: #8a7f5c; }
.arch-date { font-variant-numeric: tabular-nums; }
.arch-tag {
  margin-left: auto; font-size: 10px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--dim); border: 1px solid #3a362a; border-radius: 8px; padding: 1px 7px;
}
.arch-tag.held { color: var(--toxic); border-color: rgba(126, 224, 106, .45); }
.arch-tag.lost { color: var(--rust); border-color: rgba(180, 85, 45, .45); }
.arch-tag.now { color: var(--amber); border-color: rgba(232, 163, 60, .5); }

/* ---- the shot itself ---------------------------------------------------- */
.muzzle { fill: #ffe9a8; opacity: .95; animation: muzzle-out .15s ease-out forwards; }
.muzzle.enemy { fill: #ffb0a0; }
@keyframes muzzle-out { 0% { opacity: 1; } 100% { opacity: 0; } }
.slash {
  fill: none; stroke: #f2ead6; stroke-width: 3.5; stroke-linecap: round;
  animation: slash-out .26s ease-out forwards;
}
@keyframes slash-out {
  0% { opacity: 0; stroke-dasharray: 0 60; }
  30% { opacity: 1; }
  100% { opacity: 0; stroke-dasharray: 60 0; }
}
@media (prefers-reduced-motion: reduce) { .muzzle, .slash { animation: none; opacity: 0; } }
.sprite.corpse { opacity: .75; }
.sprite.wreck { animation: wreck-fade .7s ease-out forwards; pointer-events: none; }
@keyframes wreck-fade { 0% { opacity: 1; } 100% { opacity: 0; } }

/* Sound: one labelled control in the top bar, next to Share, where you look
   for it. It used to be an unlabelled 32px icon in the board's corner and
   nobody found it. */
#sound-toggle {
  position: absolute; right: 96px;
  background: var(--panel); color: var(--amber);
  border: 1px solid #8a7f5c; border-radius: 6px;
  padding: 5px 11px; font-size: 12px; letter-spacing: 1px;
  text-transform: uppercase; cursor: pointer; white-space: nowrap;
}
#sound-toggle:hover { background: var(--panel-edge); }
#sound-toggle.off { color: var(--dim); border-color: var(--panel-edge); }
@media (max-width: 900px) {
  #sound-toggle { position: static; order: 2; }
}

/* ---- the legend ----------------------------------------------------------
   One row a thing. Icon, name, a tag for what it does to you, one line. */
#legend-list { display: grid; gap: 6px; max-height: 60vh; overflow-y: auto; }
.legend-row { display: flex; gap: 10px; align-items: flex-start; padding: 7px 8px; background: #1c1a14; border: 1px solid #2e2b21; border-radius: 6px; }
.legend-row > svg, .legend-sw { width: 28px; height: 28px; flex: none; border-radius: 5px; }
.legend-sw { display: inline-block; border: 1px solid rgba(0, 0, 0, .4); }
.legend-text { min-width: 0; }
.legend-name { font-size: 13px; color: var(--text); margin-right: 8px; }
.legend-tag { font-size: 9px; letter-spacing: .08em; text-transform: uppercase; padding: 1px 6px; border-radius: 8px; border: 1px solid; vertical-align: 1px; }
.lg-block { color: #b8b3a3; border-color: #6a6350; }
.lg-cover { color: #d8c46a; border-color: #8a7f5c; }
.lg-loot { color: #e8a33c; border-color: rgba(232, 163, 60, .5); }
.lg-safe { color: #7fd0e0; border-color: rgba(127, 208, 224, .5); }
.lg-danger { color: #e0603c; border-color: rgba(224, 96, 60, .55); }
.legend-line { font-size: 12px; color: var(--dim); line-height: 1.45; margin-top: 3px; }

/* ---- edge definition ------------------------------------------------------
   Every board sprite gets a thin dark outline, drawn *under* the fill
   (paint-order) so it only shows outside the shape. This is what "the assets
   look blurry" actually was: soft shading with no edge against a mid-tone
   ground. The render is vector-sharp at any zoom — it lacked contrast at the
   silhouette, not resolution. Pure stroke, no filter, so nothing rasterises. */
#layer-dyn use, #layer-static use {
  stroke: rgba(14, 11, 8, .88); stroke-width: .85;
  paint-order: stroke fill markers; stroke-linejoin: round;
}
.bestiary-lead { font-size: 12.5px; color: var(--text); margin-top: 3px; }
.bestiary-lead + .bestiary-desc { color: var(--dim); font-size: 11.5px; }

/* Stances: a survivor on overwatch or braced shows it until they act again. */
.stance { fill: none; stroke-width: 2.2; pointer-events: none; }
.stance.overwatch { stroke: #7fd0e0; stroke-dasharray: 3 4; animation: reticle-spin 6s linear infinite; transform-box: fill-box; transform-origin: center; }
.stance.braced { stroke: #d8c46a; stroke-dasharray: 8 3; }
.sprite.mine { opacity: .9; }
