/* index.css — page styles for index.php (moved out of the page so browsers cache them). */
/* index.php page-specific extras */
ul { list-style: none; }
input, textarea { font-family: inherit; }

/* ─── LAYOUT ──────────────────────────────────────────────────────────────── */
.wrap  { max-width: 1120px; margin: 0 auto; padding: 0 28px; }
.wrap-sm { max-width: 820px; margin: 0 auto; padding: 0 28px; }
/* Keeps the gutter on a notched iPhone in landscape, where viewport-fit=cover
   lets the page run under the camera housing. Split from the rule above so a
   browser without env() still gets the plain 28px. */
.wrap, .wrap-sm {
  padding-left: max(28px, env(safe-area-inset-left));
  padding-right: max(28px, env(safe-area-inset-right));
}
section { padding: 96px 0; }

/* ─── GRID ────────────────────────────────────────────────────────────────── */
.grid { display: grid; gap: 16px; }
@media (min-width: 600px)  { .g2 { grid-template-columns: repeat(2,1fr); } }
@media (min-width: 900px)  { .g3 { grid-template-columns: repeat(3,1fr); } }
@media (min-width: 1000px) { .g4 { grid-template-columns: repeat(4,1fr); } }

/* ─── GLASS / CARD ────────────────────────────────────────────────────────── */
.glass {
  background: var(--glass);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.card { padding: 24px 26px; }
.glass-hover { transition: background .2s, border-color .2s, transform .2s, box-shadow .2s; }
.glass-hover:hover {
  background: var(--glass-hover);
  border-color: var(--border-brand);
  transform: translateY(-3px);
  box-shadow: 0 16px 48px rgba(0,0,0,.4), 0 0 0 1px var(--border-brand);
}

/* ─── BUTTONS ─────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; gap: .45rem;
  padding: .75rem 1.4rem; border-radius: var(--radius-sm);
  font-weight: 700; font-size: .9rem; border: none;
  text-decoration: none; white-space: nowrap; cursor: pointer;
  transition: filter .15s, transform .15s, box-shadow .15s;
}
.btn-primary {
  /* --brand-dim, not --brand: see shared.css for why (contrast) */
  background: var(--brand-dim); color: #fff;
  box-shadow: 0 4px 20px var(--brand-glow);
}
.btn-primary:hover { filter: brightness(1.1); transform: translateY(-2px); box-shadow: 0 8px 32px var(--brand-glow); }
.btn-discord {
  background: #5865f2; color: #fff;
  box-shadow: 0 4px 20px rgba(88,101,242,.3);
}
.btn-discord:hover { filter: brightness(1.1); transform: translateY(-2px); }
.btn-steam {
  background: #1b2838; color: #c6d4df;
  border: 1px solid #4a90d9;
  box-shadow: 0 4px 20px rgba(74,144,217,.2);
}
.btn-steam:hover { background: #2a475e; border-color: #6bb3f0; filter: brightness(1.08); transform: translateY(-2px); }
.btn-ghost {
  background: var(--glass); color: var(--fg2);
  border: 1px solid var(--border);
}
.btn-ghost:hover { background: var(--glass-hover); color: var(--fg); }
.btn-sm { padding: .5rem 1rem; font-size: .84rem; }
.btn:active { transform: translateY(0) !important; }

/* ─── PILL / BADGE ────────────────────────────────────────────────────────── */
.pill {
  display: inline-flex; align-items: center; gap: .3rem;
  font-size: .82rem; font-weight: 700; padding: .38rem .9rem;
  border-radius: 99px; border: 1px solid var(--border);
  background: var(--glass); color: var(--fg2); white-space: nowrap;
}
.pill-brand { border-color: var(--border-brand); color: var(--brand); background: rgba(50,167,235,.08); }
.pill-green { border-color: rgba(52,211,153,.3); color: var(--green); background: rgba(52,211,153,.06); }
.pill-red   { border-color: rgba(248,113,113,.3); color: #f87171;        background: rgba(248,113,113,.06); }
.pill-grey  { border-color: rgba(148,163,184,.3); color: #94a3b8;        background: rgba(148,163,184,.06); }

/* ─── SECTION LABEL ───────────────────────────────────────────────────────── */
.eyebrow {
  font-size: .71rem; font-weight: 800; letter-spacing: .14em;
  text-transform: uppercase; color: var(--brand); display: block; margin-bottom: .6rem;
}
h2.section-title {
  font-size: clamp(1.55rem, 2.8vw, 2.2rem); font-weight: 800;
  letter-spacing: -.025em; line-height: 1.15; color: var(--fg);
}
.section-sub { color: var(--fg2); margin-top: .5rem; font-size: 1rem; line-height: 1.7; max-width: 560px; }

/* ─── HERO ────────────────────────────────────────────────────────────────── */
/* min-height is the phone's here (auto — the content sets the height); the
   min-width:721px block gives desktop its 92dvh. It used to be 92vh on the base
   rule, "auto" under max-width:720px, and then 85vh again under max-width:600px,
   which came later in the file and quietly won — so the 720px rule was dead on
   every phone. dvh, not vh: vh is the tallest viewport, so a vh-sized hero sits
   partly under the mobile URL bar until you scroll. */
.hero {
  position: relative; overflow: hidden;
  padding: 0; min-height: auto;
  display: flex; align-items: center;
}

/* ── Tactical HUD background ────────────────────────────────────────────── */
.hero-hud {
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  overflow: hidden;
  /* Held in a custom property so the mobile block below can swap the file
     without restating the whole multi-layer background shorthand. */
  --hero-photo: url('/img/misc/pubg_playerunknowns_battlegrounds_4-bg.jpg');
  /* PUBG artwork as base, then dark brand tint so HUD stays readable */
  background:
    /* 1. Heavy tint — image is a subtle ghost behind the HUD */
    linear-gradient(180deg,
      rgba(6,16,28,0.82) 0%,
      rgba(6,16,28,0.72) 35%,
      rgba(6,16,28,0.76) 65%,
      rgba(5,11,20,0.90) 100%
    ),
    /* 2. PUBG artwork — the -bg derivative (q78 vs. the ~98 source): heavily
       tinted by the layer above (this file only ships as "a subtle ghost"),
       so the extra source fidelity was wasted bytes. */
    var(--hero-photo) center 20% / cover no-repeat;
}
/* This background is the LCP element, and the desktop file is 1920x1080 / 381KB
   — preloaded at fetchpriority=high and then buried under the 0.82-alpha tint
   above. A phone needs none of that resolution: the -mobile derivative is 840px
   wide and 76KB, the same picture once the tint is on it. index.php preloads
   whichever one this query will actually use (see its two media= preloads). */
@media (max-width: 720px) {
  .hero-hud { --hero-photo: url('/img/misc/pubg_playerunknowns_battlegrounds_4-mobile.jpg'); }
}

/* Mesh gradient blobs — tint the image with brand colours */
.hud-blob {
  position: absolute; border-radius: 50%;
  filter: blur(90px); will-change: transform;
}
.hud-blob-1 {
  width: 70vmin; height: 70vmin; opacity: 0.35;
  background: radial-gradient(circle, rgba(6,16,60,0.9) 0%, rgba(6,16,60,0) 70%);
  top: -15%; left: -15%;
  animation: hudBlob1 28s ease-in-out infinite;
}
.hud-blob-2 {
  width: 55vmin; height: 55vmin; opacity: 0.28;
  background: radial-gradient(circle, rgba(28,229,255,0.4) 0%, rgba(28,229,255,0) 70%);
  bottom: -20%; right: -10%;
  animation: hudBlob2 36s ease-in-out infinite;
}
.hud-blob-3 {
  width: 45vmin; height: 45vmin; opacity: 0.22;
  background: radial-gradient(circle, rgba(80,40,160,0.5) 0%, rgba(80,40,160,0) 70%);
  top: 20%; left: 35%;
  animation: hudBlob3 44s ease-in-out infinite;
}
/* Parked when the hero is off screen or the tab is hidden — see setAmbient().
   `paused` rather than `none` so the blobs hold position instead of snapping back
   to their start transform when you scroll up again. */
.wg-idle .hud-blob-1,
.wg-idle .hud-blob-2,
.wg-idle .hud-blob-3,
.wg-idle .hud-grid,
.wg-idle .hud-you,
.wg-idle .hud-next-zone { animation-play-state: paused; }

@keyframes hudBlob1 { 0%,100%{transform:translate(0,0) scale(1)} 50%{transform:translate(8vw,6vh) scale(1.1)} }
@keyframes hudBlob2 { 0%,100%{transform:translate(0,0) scale(1)} 50%{transform:translate(-6vw,-8vh) scale(0.9)} }
@keyframes hudBlob3 { 0%,100%{transform:translate(0,0) scale(1)} 50%{transform:translate(-10vw,4vh) scale(1.15)} }

/* Tron perspective grid — lower opacity so it sits behind the photo */
.hud-grid {
  position: absolute; left: -10%; right: -10%; bottom: -10%; height: 65%;
  background-image:
    linear-gradient(rgba(28,229,255,0.07) 1px, transparent 1px),
    linear-gradient(90deg, rgba(28,229,255,0.04) 1px, transparent 1px);
  background-size: 70px 70px;
  transform: perspective(800px) rotateX(62deg);
  transform-origin: 50% 100%;
  animation: hudGridScroll 6s linear infinite;
  mask-image: linear-gradient(180deg, transparent 0%, black 35%, black 75%, transparent 100%);
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, black 35%, black 75%, transparent 100%);
}
@keyframes hudGridScroll { from{background-position:0 0} to{background-position:0 70px} }

/* ── Corner bracket viewfinder frame ─────────────────────────────────────── */
.hud-corner {
  position: absolute; width: 28px; height: 28px;
  z-index: 9; pointer-events: none;
}
.hud-corner-tl { top: 14px; left: 14px;
  border-top: 2px solid rgba(28,229,255,0.7);
  border-left: 2px solid rgba(28,229,255,0.7); }
.hud-corner-tr { top: 14px; right: 14px;
  border-top: 2px solid rgba(28,229,255,0.7);
  border-right: 2px solid rgba(28,229,255,0.7); }
.hud-corner-bl { bottom: 14px; left: 14px;
  border-bottom: 2px solid rgba(28,229,255,0.7);
  border-left: 2px solid rgba(28,229,255,0.7); }
.hud-corner-br { bottom: 14px; right: 14px;
  border-bottom: 2px solid rgba(28,229,255,0.7);
  border-right: 2px solid rgba(28,229,255,0.7); }

/* ── Top bar: bot status + player search ─────────────────────────────────── */
.hud-top-bar {
  /* Sits at the top edge of the hero, not above it. A negative offset here used
     to pull the bar outside the hero box, where the sticky header (z-index 300)
     overlapped it and clipped the search field and status pill in half whenever
     the live-bar was hidden. */
  position: absolute; top: 0; left: 0; right: 0; z-index: 400;
  display: flex; align-items: center; justify-content: center; gap: 10px;
  background: linear-gradient(180deg, rgba(6,16,28,0.85) 0%, rgba(6,16,28,0) 100%);
  padding: 12px 20px 24px;
  pointer-events: none;
  overflow: visible;
}
.hud-top-bar .pill          { pointer-events: auto; }
.hud-top-bar .eyebrow-search { pointer-events: auto; }
.hud-strip-inner {
  display: flex; align-items: center; gap: 0;
  background: rgba(4,8,16,0.88);
  border: 1px solid rgba(28,229,255,0.25);
  border-radius: 6px;
  backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
  box-shadow: 0 2px 20px rgba(0,0,0,0.5);
  overflow: hidden;
}
.hud-strip-cell {
  display: flex; align-items: center; gap: 7px;
  padding: 7px 18px;
  border-right: 1px solid rgba(28,229,255,0.15);
  font: 700 12px/1 ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  letter-spacing: 0.12em; text-transform: uppercase; color: #8AA0B8;
}
.hud-strip-cell:last-child { border-right: none; }
.hud-strip-cell .sv       { color: var(--hud-fg); font-weight: 800; }
.hud-strip-cell .sv.white { color: var(--hud-fg-bright); }
.hud-strip-cell .sv.cyan  { color: var(--hud-cyan); }
.hud-strip-cell .sv.win   { color: var(--hud-green); }
.hud-strip-live {
  display: flex; align-items: center; gap: 7px;
  padding: 7px 16px;
  background: rgba(45,212,130,0.1);
  border-right: 1px solid rgba(28,229,255,0.15);
  font: 800 12px/1 ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  letter-spacing: 0.2em; text-transform: uppercase; color: #5DDF9C;
}
.hud-strip-live .hd {
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--hud-green); box-shadow: 0 0 5px var(--hud-green);
  flex-shrink: 0;
}
@keyframes hudPulse { 0%,100%{opacity:1} 50%{opacity:.35} }

/* ── The data beat ────────────────────────────────────────────────────────────
   DESIGN.md's Live-Glow Rule: a glow means the data behind it is real and
   current. These dots used to pulse on a 1.6s timer whether or not anything had
   arrived, which made the glow decoration rather than signal. Now `.wg-beat` is
   stamped on by JS the moment fresh data lands (see applyHudData) and removed
   when the beat finishes, so one synchronized pulse == one successful refresh.
   Between polls the dots rest, lit but still — which is itself accurate: the
   data is real, nothing new has happened yet.

   Cost: four infinite loops became four 900ms animations per 30s poll. */
.wg-beat { animation: wgBeat .9s cubic-bezier(0.16, 1, 0.3, 1); }
@keyframes wgBeat {
  0%   { transform: scale(1);    filter: brightness(1); }
  22%  { transform: scale(1.85); filter: brightness(1.7); }
  100% { transform: scale(1);    filter: brightness(1); }
}

/* ── Strip search row ────────────────────────────────────────────────────── */
.hud-strip-search {
  pointer-events: auto;
  display: flex; align-items: center;
}
.hud-strip-search-row {
  display: flex; gap: 0; align-items: center;
  background: rgba(4,8,16,0.88);
  border: 1px solid rgba(28,229,255,0.22);
  border-radius: 6px;
  backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
  box-shadow: 0 2px 20px rgba(0,0,0,0.5);
  overflow: hidden;
}
.hud-strip-search-wrap { position: relative; flex: 1; min-width: 0; }
.hud-strip-search-input {
  width: 280px; padding: 7px 14px;
  background: transparent; border: none; outline: none;
  font: 700 11px/1 ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  letter-spacing: 0.08em; color: var(--hud-fg);
  caret-color: var(--hud-cyan);
}
.hud-strip-search-input::placeholder { color: rgba(138,160,184,0.65); }
.hud-strip-search-input:focus { background: rgba(28,229,255,0.04); }
.hud-strip-search-btn {
  padding: 7px 16px;
  background: rgba(28,229,255,0.12); border: none; border-left: 1px solid rgba(28,229,255,0.22);
  font: 700 11px/1 ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--hud-cyan);
  cursor: pointer; transition: background .15s;
}
.hud-strip-search-btn:hover { background: rgba(28,229,255,0.22); }

/* ── Bottom HUD bar ──────────────────────────────────────────────────────── */
.hud-bar {
  position: absolute; bottom: 0; left: 0; right: 0; z-index: 5;
  display: grid;
  grid-template-columns: 280px 1fr 290px;
  /* solid frosted panel — no fade, all content always visible */
  background: rgba(4,8,18,0.82);
  border-top: 1px solid rgba(28,229,255,0.18);
  backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px);
  padding: 0 0 14px 0;
  pointer-events: none;
}

/* ── Left panel: telemetry stats ─────────────────────────────────────────── */
.hud-telemetry {
  padding: 12px 18px 10px 20px;
  display: grid; grid-template-columns: auto auto; gap: 2px 14px;
  align-content: start;
  font: 600 12px/1.35 ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  color: var(--hud-fg); letter-spacing: 0.03em;
}
.hud-telemetry .hk {
  color: var(--hud-muted);
  text-transform: uppercase; letter-spacing: 0.09em; white-space: nowrap;
}
.hud-telemetry .hv       { color: var(--hud-fg); text-align: right; white-space: nowrap; font-weight: 700; }
.hud-telemetry .hv.white { color: var(--hud-fg-bright); }
.hud-telemetry .hv.cyan  { color: var(--hud-cyan); }
.hud-telemetry .hv.win   { color: var(--hud-green); }
.hud-telemetry .hk-section {
  grid-column: 1 / -1;
  color: rgba(28,229,255,0.55); text-transform: uppercase;
  letter-spacing: 0.16em; font-size: 10px; font-weight: 700;
  border-top: 1px solid rgba(28,229,255,0.15);
  padding-top: 5px; margin-top: 3px;
}
.hud-telemetry .hk-section:first-child { border-top: none; padding-top: 0; margin-top: 0; }
/* Sub-rows: indented detail line under a record entry */
.hud-telemetry .hk-sub          { color: rgba(124,144,168,0.55); padding-left: 8px; font-size: 11px; }
.hud-telemetry .hv-sub          { color: rgba(182,199,220,0.6);  font-size: 11px; font-weight: 600; text-align: right; }
.hud-telemetry .hv-sub.cyan     { color: rgba(28,229,255,0.65); }
.hud-telemetry .hv-sub.win      { color: rgba(45,212,130,0.75); }

/* ── Centre panel: kill feed ─────────────────────────────────────────────── */
.hud-feed-wrap {
  display: flex; flex-direction: column;
  pointer-events: auto;
  padding: 12px 16px 12px;
  gap: 0;
  border-left: 1px solid rgba(28,229,255,0.18);
  border-right: 1px solid rgba(28,229,255,0.18);
  justify-content: flex-start;
  background: rgba(4,10,20,0.45);
}
.hud-feed-header {
  display: flex; align-items: center; gap: 8px;
  padding: 0 0 6px 0;
  border-bottom: 1px solid rgba(28,229,255,0.2);
  margin-bottom: 5px;
  font: 700 11px/1 ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  letter-spacing: 0.2em; color: var(--hud-cyan); text-transform: uppercase;
}
.hud-feed-header::before {
  content: ''; width: 6px; height: 6px; border-radius: 50%;
  background: var(--hud-green); box-shadow: 0 0 5px var(--hud-green);
}
/* Pseudo-element can't take a class, so the beat rides the parent. */
.hud-feed-header.wg-beat { animation: none; }
.hud-feed-header.wg-beat::before { animation: wgBeat .9s cubic-bezier(0.16, 1, 0.3, 1); }
.hud-feed {
  display: flex; flex-direction: column; gap: 3px;
}
.hud-feed-row {
  display: grid;
  grid-template-columns: 110px 62px 1fr auto;
  align-items: center; gap: 8px;
  padding: 5px 10px;
  border-radius: 3px;
  background: rgba(6,14,26,0.6);
  border: 1px solid rgba(28,229,255,0.08);
  font: 600 13px/1 ui-sans-serif, system-ui, sans-serif; color: var(--hud-fg);
  /* Staggered by --i (set in renderHudFeed) so a page of kills arrives as a feed
     rather than a block swap. Capped at 8 steps × 28ms = 224ms total so the last
     row is never perceptibly late — the whole page turns inside a quarter second. */
  opacity: 0;
  animation: hudFeedIn 0.34s cubic-bezier(0.16, 1, 0.3, 1) forwards;
  animation-delay: calc(min(var(--i, 0), 8) * 28ms);
}
.hud-feed-row.win {
  background: rgba(6,26,16,0.7);
  border-color: rgba(45,212,130,0.25);
}
@keyframes hudFeedIn {
  from { opacity:0; transform:translateY(6px); }
  to   { opacity:1; transform:translateY(0); }
}
.hud-feed-row .hw  { color: var(--hud-fg-bright); font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; pointer-events: auto; }
.hud-feed-row .hvb { color: var(--hud-muted); white-space: nowrap; font-size: 12px; }
.hud-feed-row .hwtarget { color: #F87171; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; pointer-events: auto; }
.hud-feed-row .hwtarget a.hud-feed-link { color: #F87171; pointer-events: auto; }
.hud-feed-row .hwtarget a.hud-feed-link:hover { color: #FCA5A5; }
.hud-feed-row .hwp { color: var(--hud-cyan); font-family: ui-monospace, monospace; font-size: 12px; white-space: nowrap; text-align: right; }
.hud-feed-row.win .hw,
.hud-feed-row.win .hwtarget { color: var(--hud-green); }

/* ── Right panel: minimap ────────────────────────────────────────────────── */
.hud-minimap-wrap {
  padding: 10px 18px 10px 12px;
  display: flex; flex-direction: column; align-items: center; justify-content: flex-end;
  border-left: 1px solid rgba(28,229,255,0.15);
  gap: 6px;
}
.hud-dinner-badge {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  width: 100%; max-width: 258px;
  padding: 5px 10px;
  background: rgba(242,201,76,0.08);
  border: 1px solid rgba(242,201,76,0.28);
  border-radius: 4px;
  font: 700 9px/1 ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--hud-muted); white-space: nowrap;
}
.hud-dinner-badge .hdb-trophy { color: #F2C94C; font-size: 11px; }
.hud-dinner-badge .hdb-map { color: var(--hud-fg-bright); font-weight: 800; }
.hud-dinner-badge .hdb-idx { color: var(--hud-cyan); }
.hud-minimap {
  position: relative;
  width: 100%; aspect-ratio: 1;
  max-width: 258px;
  border-radius: 8px;
  border: 1px solid rgba(28,229,255,0.35);
  /* -bg.jpg derivatives, not the source PNGs data.php's heatmap canvas uses —
     this thumbnail is capped at 258px and sits under a dark tint (::before
     below), so the heavily-compressed JPEG is indistinguishable here. */
  --minimap-bg: url('/img/maps/Erangel-bg.jpg');
  background: var(--minimap-bg, url('/img/maps/Erangel-bg.jpg')) center/cover no-repeat;
  box-shadow: 0 0 30px rgba(3,175,229,0.15), inset 0 0 30px rgba(0,0,0,0.4);
  overflow: hidden;
  flex-shrink: 0;
}
/* Dark tint + vignette over the map image */
.hud-minimap::before {
  content: ''; position: absolute; inset: 0; z-index: 0;
  background:
    rgba(6,16,28,0.4),
    radial-gradient(ellipse at center, transparent 40%, rgba(0,0,0,0.55) 100%);
  border-radius: inherit;
}
.hud-minimap-grid {
  position: absolute; inset: 0; z-index: 1;
  background-image:
    linear-gradient(rgba(255,255,255,0.04) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,0.04) 1px, transparent 1px);
  background-size: 48px 48px;
}
.hud-play-zone {
  position: absolute; top: 18%; left: 22%; width: 64%; height: 64%;
  border-radius: 50%; border: 1.5px solid rgba(255,255,255,0.6);
  box-shadow: 0 0 12px rgba(255,255,255,0.1); z-index: 2;
}
/* The next-zone ring keeps its slow loop: in PUBG the next circle genuinely is a
   pending countdown, so a breathing dashed ring is literal, not decorative. It is
   4s and opacity-only, and it pauses with the rest of the hero when scrolled off. */
.hud-next-zone {
  position: absolute; top: 32%; left: 38%; width: 36%; height: 36%;
  border-radius: 50%; border: 1.5px dashed rgba(255,255,255,0.45);
  animation: hudZonePulse 4s ease-in-out infinite; z-index: 2;
}
@keyframes hudZonePulse { 0%,100%{opacity:.55} 50%{opacity:1} }
.hud-blue-zone {
  position: absolute; inset: 0; z-index: 1;
  background: radial-gradient(circle at 50% 50%, transparent 55%, rgba(28,229,255,0.1) 70%, rgba(28,229,255,0.22) 100%);
}
.hud-you {
  position: absolute; top: 52%; left: 48%;
  width: 0; height: 0;
  border-left: 7px solid transparent; border-right: 7px solid transparent;
  border-bottom: 14px solid #FFFFFF;
  transform: translate(-50%,-50%) rotate(28deg);
  filter: drop-shadow(0 0 4px rgba(255,255,255,0.85));
  overflow: visible; z-index: 4;
  animation: hudYouRotate 22s linear infinite;
}
@keyframes hudYouRotate { from{transform:translate(-50%,-50%) rotate(0deg)} to{transform:translate(-50%,-50%) rotate(360deg)} }
.hud-squad-dot {
  position: absolute; width: 10px; height: 10px; border-radius: 50%;
  border: 2px solid rgba(0,0,0,0.65);
  box-shadow: 0 0 5px rgba(0,0,0,0.5); z-index: 3;
}
.hud-squad-1 { top:42%; left:38%; background:var(--hud-green); }
.hud-squad-2 { top:58%; left:62%; background:#FFB547; }
.hud-squad-3 { top:36%; left:56%; background:#6B7BFF; }
.hud-squad-dot .hud-dot-name,
.hud-you .hud-dot-name {
  position: absolute; bottom: calc(100% + 4px); left: 50%; transform: translateX(-50%);
  white-space: nowrap;
  font: 700 7px/1 ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  letter-spacing: 0.06em; color: var(--hud-fg-bright);
  background: rgba(6,16,28,0.85); border-radius: 3px; padding: 2px 5px;
  pointer-events: auto; text-shadow: 0 1px 2px rgba(0,0,0,0.9); z-index: 5;
}
a.hud-dot-link,
a.hud-strip-player-link,
a.hud-feed-link {
  color: #5B9CF6; text-decoration: none;
}
a.hud-dot-link:hover,
a.hud-strip-player-link:hover,
a.hud-feed-link:hover { color: #93C5FD; text-decoration: underline; }
.hud-strip-dot { opacity: 0.5; }
.hud-minimap-badge {
  position: absolute; bottom: 6px; left: 7px; z-index: 4;
  font: 800 7px/1 ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  letter-spacing: 0.2em; color: rgba(28,229,255,0.45);
  text-transform: uppercase; pointer-events: none;
}
.hud-minimap-label {
  position: absolute; top: 7px; left: 9px; z-index: 4;
  font: 800 10px/1 ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  letter-spacing: 0.18em; color: var(--hud-cyan); text-transform: uppercase;
  text-shadow: 0 0 8px rgba(28,229,255,0.6), 0 1px 4px rgba(0,0,0,0.9);
}
.hud-minimap-coords {
  position: absolute; bottom: 7px; right: 9px; z-index: 4;
  font: 600 9px/1 ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  letter-spacing: 0.05em; color: rgba(255,255,255,0.6);
  text-shadow: 0 1px 3px rgba(0,0,0,0.9);
}
.hud-minimap-north {
  position: absolute; top: 7px; left: 50%; transform: translateX(-50%);
  font: 800 11px/1 ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  letter-spacing: 0.1em; color: rgba(255,255,255,0.8); z-index: 3;
  text-shadow: 0 1px 3px rgba(0,0,0,0.9);
}
.hud-kill-skull {
  position: absolute; z-index: 3;
  font-size: 9px; line-height: 1;
  transform: translate(-50%, -50%);
  filter: drop-shadow(0 0 3px rgba(248,113,113,0.9));
  opacity: 0.85;
  pointer-events: none;
  animation: skullFadeIn 0.4s ease-out both;
}
@keyframes skullFadeIn {
  from { opacity: 0; transform: translate(-50%, -50%) scale(0.4); }
  to   { opacity: 0.85; transform: translate(-50%, -50%) scale(1); }
}

/* Scanlines overlay — subtle */
.hud-scanlines {
  position: absolute; inset: 0; pointer-events: none; z-index: 8;
  background-image: repeating-linear-gradient(0deg, rgba(255,255,255,0.007) 0, rgba(255,255,255,0.007) 1px, transparent 1px, transparent 4px);
  mix-blend-mode: overlay;
}

/* Vignette — soft edges only, bottom handled by the solid HUD bar */
.hud-vignette {
  position: absolute; inset: 0; z-index: 7; pointer-events: none;
  background: radial-gradient(130% 90% at 50% 35%, transparent 30%, rgba(5,12,22,0.35) 100%);
}

/* Bottom fade — blends hero into page bg, sits above HUD bar */
.hero-fade-b {
  position: absolute; bottom: 0; left: 0; right: 0; height: 120px; z-index: 4;
  background: linear-gradient(to bottom, transparent, var(--bg)); pointer-events: none;
}
/* Bottom padding reserves space for HUD bar + match strip above it */
/* Top padding clears the absolutely-positioned .hud-top-bar (search + status pill)
   that now sits at the hero's top edge. */
.hero-content { position: relative; z-index: 2; width: 100%; padding: 96px 0 290px; pointer-events: none; }
/* Re-enable pointer events for everything interactive inside hero-content */
.hero-content a,
.hero-content button,
.hero-content input,
.hero-content form,
.hero-content .pill,
.hero-content .hero-mobile-search,
.hero-content .hero-match-strip { pointer-events: auto; }
.hero-inner {
  max-width: 680px;
  margin: 0 auto;
  text-align: center;
}
.hero-inner .hero-eyebrow { justify-content: center; }
.hero-inner .hero-btns    { justify-content: center; }
.hero-inner .hero-pills   { justify-content: center; }
.hero-inner .hero-sub     { margin-left: auto; margin-right: auto; }
.hero-inner .hero-cta-note{ margin-left: auto; margin-right: auto; }
.hero-inner .hero-search  { max-width: 520px; margin: 0 auto; }
/* Responsive */
@media (max-width: 1200px) {
  .hud-bar { grid-template-columns: 260px 1fr 250px; }
}
@media (max-width: 1000px) {
  .hud-bar { grid-template-columns: 230px 1fr 220px; }
}
@media (max-width: 900px) {
  .hud-bar { grid-template-columns: 1fr 200px; }
  .hud-telemetry { display: none; }
}
@media (max-width: 720px) {
  /* The full HUD bar, corner brackets and breakout strip need desktop width.
     They are swapped for .hero-mini-hud, which carries the same live data, so
     the phone still gets the proof rather than a hero with nothing in it.
     Those three swaps are NOT driven from this block — see "MOBILE/DESKTOP
     SWAP" below for why. */
  .hud-bar { display: none; }
  .hud-top-bar { display: none; }
  .hud-corner { display: none; }
  /* 18px sides, not 0. The base rule zeroes the horizontal padding because on a
     wide screen .hero-inner's max-width:680px does the insetting — but between
     601px and 680px that max-width no longer bites, so the hero copy ran into
     both screen edges. Below 601px .wrap supplies the same 18px and the block at
     the foot of this file re-states the vertical values; see the note there. */
  .hero-content { padding: 52px 18px 56px; }

  /* Ambient layers off on phones. Three 90px-blur blobs, a background-position
     loop on a layer that is simultaneously mask-image'd and perspective-rotated
     (so it repaints rather than composites), and a full-viewport
     mix-blend-mode:overlay is a lot of per-frame work for a decorative wash —
     and it ran at full desktop cost on a phone GPU the whole time the hero was
     on screen. The photo and its tint stay; only the moving parts go. */
  .hud-blob, .hud-grid, .hud-scanlines { display: none; }

  /* The one conversion action gets the full row and is allowed to wrap. .btn is
     white-space:nowrap and this label needs ~346px inside the 339px a 375px
     phone actually has, so it used to run across the gutter (and, with no
     overflow-x guard on the page, widen the document). */
  .hero-btns { flex-direction: column; align-items: stretch; }
  .hero-btns .btn { justify-content: center; }
  .btn-hero { width: 100%; white-space: normal; padding: .9rem 1.1rem; }

  /* 16px is the floor: iOS Safari zooms the page in when you focus anything
     smaller and does not zoom back out. Covers the hero search, the newsletter
     field and every contact-form input. */
  .hero-mobile-search-input,
  .hero-search-input,
  .form-input { font-size: 16px; }
  .hero-mobile-search-input { padding: 12px 14px; }
  .hero-mobile-search-btn { min-width: 52px; min-height: 48px; }
}

/* ── MOBILE/DESKTOP SWAP ──────────────────────────────────────────────────────
   These three blocks are either/or: .hero-match-strip and the desktop HUD on a
   wide screen, .hero-mobile-search + .hero-mini-hud on a phone. Each one's
   mobile state is its BASE rule and the desktop state is a min-width query, so
   the visible state never depends on which rule happens to sit lower in the file.

   It was the other way round, and it silently broke: the max-width:720px block
   above set .hero-mini-hud{display:block}, then the component's own base rule
   ~40 lines later set display:none. Equal specificity, later in the file, no
   !important — so the phone's entire live readout (Players / Total kills /
   Headshot % / Longest shot) was display:none on every viewport and nobody could
   see it. Its two neighbours only worked because someone had already hit this
   and patched them with !important, which is the symptom, not the fix.

   Note the selectors: `.hero .hero-mini-hud`, not `.hero-mini-hud`, and
   `section.hero`, not `.hero`. A media query adds NO specificity, so a bare
   `.hero-mini-hud` in here would still be decided by source order against the
   component's own base rule below — the exact trap described above, just facing
   the other way. One extra step of specificity makes these win wherever they
   sit, so moving or reordering blocks in this file cannot resurrect the bug. */
@media (min-width: 721px) {
  .hero .hero-mini-hud      { display: none; }
  .hero .hero-mobile-search { display: none; }
  .hero .hero-match-strip   { display: flex; }
  section.hero              { min-height: 92vh; min-height: 92dvh; }
}
/* ── MOBILE LIVE READOUT ──────────────────────────────────────────────────
   Desktop shows the full HUD bar; below 720px it cannot fit, so this condensed
   readout carries the same proof. Hidden by default and switched on in the
   720px block, so only one of the two is ever rendered. Values follow the
   value-over-micro-label pairing used by the stat pills elsewhere. */
/* display:block is the BASE state — the phone's. Desktop hides it in the
   min-width:721px block above. Do not move this to display:none. */
.hero-mini-hud { display: block; margin-top: 22px; }
.hero-mini-hud__head {
  display: flex; align-items: center; gap: 7px;
  font-size: .68rem; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: var(--muted); margin-bottom: 10px;
}
.hero-mini-hud__dot {
  width: 6px; height: 6px; border-radius: 50%; background: var(--green);
  box-shadow: 0 0 5px var(--green); flex-shrink: 0;
}
.hero-mini-hud__grid {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 1px;
  background: var(--border); border: 1px solid var(--border);
  border-radius: var(--radius-sm); overflow: hidden; margin: 0;
}
.hero-mini-hud__cell { background: rgba(4,8,16,.88); padding: 12px 14px; min-width: 0; }
.hero-mini-hud__cell dt {
  font-size: .64rem; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: var(--muted); margin-bottom: 3px;
}
.hero-mini-hud__val {
  margin: 0; font-size: 1.15rem; font-weight: 800; line-height: 1.15; color: var(--fg);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.hero-mini-hud__val--cyan { color: var(--brand); }
@media (prefers-reduced-motion: reduce) { .hero-mini-hud__dot { box-shadow: none; } }
/* Mobile carries the same data beat as the desktop HUD dots. */

/* Visible on mobile (the base state); desktop hides it in the min-width:721px
   block above, where .hud-top-bar carries the same search instead. */
.hero-mobile-search { display: block; margin-bottom: 20px; }
.hero-mobile-search-row {
  display: flex; gap: 0; align-items: center;
  background: rgba(4,8,16,0.82);
  border: 1px solid rgba(28,229,255,0.28);
  border-radius: 10px;
  overflow: visible;
}
.hero-mobile-search-wrap { position: relative; flex: 1; min-width: 0; }
.hero-mobile-search-input {
  width: 100%; padding: 10px 14px;
  background: transparent; border: none; outline: none;
  font-size: .9rem; font-weight: 600; color: var(--hud-fg);
  caret-color: var(--hud-cyan); box-sizing: border-box;
}
.hero-mobile-search-input::placeholder { color: rgba(138,160,184,0.6); }
.hero-mobile-search-btn {
  padding: 10px 18px;
  background: rgba(28,229,255,0.12); border: none;
  border-left: 1px solid rgba(28,229,255,0.2);
  font-size: .9rem; color: var(--hud-cyan); cursor: pointer;
  border-radius: 0 10px 10px 0;
}
.hero-mobile-search-wrap .hero-ac-list { z-index: 300; }

/* Reduced motion: disable blob / grid animations */
/* Reduced motion: kill every ambient loop and every entrance, keep every state
   change. Previously this covered only the blobs, the grid and the you-marker —
   the zone ring, both live dots, the feed-row entrance, the kill skulls and the
   live-bar slide all kept animating for users who asked them not to.

   The data beat is included: a user who suppresses motion still gets the fresh
   value, just without the pulse. The text is the signal; the pulse is emphasis. */
@media (prefers-reduced-motion: reduce) {
  .hud-blob-1, .hud-blob-2, .hud-blob-3,
  .hud-grid,
  .hud-you,
  .hud-next-zone,
  .hud-feed-row,
  .hud-kill-skull,
  .live-dot,
  #live-bar.live-bar--visible,
  .wg-beat,
  .hud-feed-header.wg-beat::before {
    animation: none !important;
  }
  /* These two start at opacity:0 and are made visible by their own keyframes —
     without the animation they would never appear at all. */
  .hud-feed-row   { opacity: 1; }
  .hud-kill-skull { opacity: .85; }
}
.hero-eyebrow { display: flex; align-items: center; gap: 10px; margin-bottom: 20px; flex-wrap: wrap; }

/* Eyebrow inline player search */
.eyebrow-search {
  display: flex; align-items: center; gap: 0;
  background: rgba(4,8,16,0.75);
  border: 1px solid rgba(28,229,255,0.28);
  border-radius: 20px;
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  overflow: visible;
}
.eyebrow-search-wrap { position: relative; }
.eyebrow-search-input {
  width: 380px; padding: 10px 12px 10px 16px;
  background: transparent; border: none; outline: none;
  font-size: .88rem; font-weight: 600; color: var(--hud-fg);
  caret-color: var(--hud-cyan); letter-spacing: .02em;
}
.eyebrow-search-input::placeholder { color: rgba(138,160,184,0.6); }
.eyebrow-search-input:focus { background: rgba(28,229,255,0.04); border-radius: 20px 0 0 20px; }
.eyebrow-search-btn {
  padding: 10px 16px 10px 12px;
  background: transparent; border: none; border-left: 1px solid rgba(28,229,255,0.2);
  font-size: .85rem; color: var(--hud-cyan); cursor: pointer;
  transition: color .15s;
}
.eyebrow-search-btn:hover { color: #fff; }
/* Autocomplete dropdown — needs higher z-index since it's inside hero-content */
.eyebrow-search-wrap .hero-ac-list { z-index: 300; min-width: 220px; }

h1.hero-title {
  font-size: clamp(2.2rem, 5vw, 3.6rem); font-weight: 900;
  line-height: 1.06; letter-spacing: -.03em; color: var(--fg);
  margin-bottom: 20px;
  text-shadow: 0 2px 20px rgba(0,0,0,0.8);
}
.hero-title .accent {
  /* Solid bright cyan — no gradient clip, no transparency issues over photo */
  color: var(--hud-cyan);
  -webkit-text-fill-color: var(--hud-cyan);
  text-shadow: 0 0 30px rgba(28,229,255,0.5), 0 2px 20px rgba(0,0,0,0.8);
}
.hero-sub { font-size: 1.05rem; color: var(--fg2); line-height: 1.7; max-width: 480px; margin-bottom: 28px; text-shadow: 0 1px 8px rgba(0,0,0,0.85); }
.hero-btns { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 12px; }
/* One heavy element in the hero. The install button is the only conversion action,
   so it carries the size, the glyph, and the glow; everything else steps down to text. */
.btn-hero { font-size: 1rem; padding: .9rem 2rem; }
.hero-cta-note {
  font-size: .82rem; line-height: 1.6; color: var(--muted);
  max-width: 480px; margin-bottom: 24px; text-shadow: 0 1px 8px rgba(0,0,0,.85);
}
.hero-cta-alt { display: inline-block; color: var(--fg2); text-decoration: none; border-bottom: 1px solid var(--border-brand); }
.hero-cta-alt:hover { color: var(--brand); border-bottom-color: var(--brand); }
.hero-cta-alt:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.hero-pills { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 0; }
/* Match strip sits below the pills, breaks out of hero-inner max-width.
   display:none is the BASE state — it needs desktop width; the min-width:721px
   block above turns it back on. */
.hero-match-strip {
  display: none; justify-content: center; margin-top: 22px;
  /* Break out of hero-inner's max-width: 680px */
  width: 100vw; position: relative; left: 50%; transform: translateX(-50%);
}

/* search widget */
.hero-search {
  margin-top: 16px; padding-top: 16px;
  border-top: 1px solid var(--border);
}
.hero-search-label { font-size: .72rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); margin-bottom: 8px; }
.hero-search-row { display: flex; gap: 8px; }
.hero-search-wrap { position: relative; flex: 1; min-width: 0; }
.hero-search-input {
  width: 100%; min-width: 0; padding: .7rem 1rem;
  border-radius: var(--radius-sm); border: 1px solid var(--border);
  background: rgba(10,17,32,.9); color: var(--fg); font-size: .9rem;
  outline: none; transition: border-color .15s; box-sizing: border-box;
}
.hero-search-input:focus { border-color: var(--border-brand); }
.hero-search-input::placeholder { color: var(--muted); }
/* Same dropdown as stats.php's .search-ac-list — keep the two in step */
.hero-ac-list {
  display: none; position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 200;
  background: #0d1520; border: 1px solid rgba(50,167,235,.5); border-radius: var(--radius-sm);
  max-height: 220px; overflow-y: auto; box-shadow: 0 8px 24px rgba(0,0,0,.5);
  list-style: none; margin: 0; padding: 0;
}
.hero-ac-list.open { display: block; }
.hero-ac-item {
  padding: .55rem 1rem; font-size: .9rem; color: var(--fg); cursor: pointer;
  border-bottom: 1px solid rgba(255,255,255,.04);
}
.hero-ac-item:last-child { border-bottom: none; }
.hero-ac-item:hover, .hero-ac-item.active { background: rgba(50,167,235,.15); color: #fff; }
.hero-ac-item mark { background: none; color: var(--brand); font-weight: 700; }
.hero-ac-empty { padding: .6rem 1rem; font-size: .82rem; color: var(--muted); font-style: italic; }

/* carousel removed — hero is full-width over the tactical HUD */


/* ─── EDITORIAL DENSITY ───────────────────────────────────────────────────────
   The page used to run ten sections through one identical block (eyebrow +
   title + sub + equal-weight card grid) on a flat `section{padding:96px 0}`, so
   every section argued at the same volume and none of them landed.

   Three tiers replace that. They differ in spacing, width and type scale, so the
   cadence itself tells you what matters:

     .tier-lead     a feature argued at scale — generous, asymmetric
     .tier-index    the scannable remainder — tight rows, no containers
     .tier-utility  changelog / newsletter / contact — compressed, recessive

   Rhythm now comes from the contrast between these, which is why the tier
   paddings are deliberately far apart rather than one step on a scale. */

/* Section head: asymmetric. Title left, supporting copy right on wide screens,
   so the two stop reading as one centered stack. */
.sec-head { display: grid; gap: 10px; margin-bottom: 34px; }
@media (min-width: 820px) {
  .sec-head { grid-template-columns: 1.15fr .85fr; gap: 40px; align-items: end; }
  .sec-head .section-sub { margin-top: 0; max-width: none; }
}

/* ── Tier 1: the lead ─────────────────────────────────────────────────────── */
.lead-pair { display: grid; gap: 18px; margin-bottom: 30px; }
@media (min-width: 820px) { .lead-pair { grid-template-columns: 1fr 1fr; gap: 22px; } }
.lead-card {
  padding: 30px 28px; border-radius: var(--radius);
  background: linear-gradient(155deg, rgba(50,167,235,.07), rgba(255,255,255,.02));
  border: 1px solid var(--border-brand);
  display: flex; flex-direction: column; gap: 10px;
}
/* The differentiator card is tinted purple to separate the two claims: one is
   "the reason you'd add any PUBG bot", the other is "the reason you'd add this
   one". Purple is the rank/identity accent, used here for standing, not decor. */
.lead-card--alt {
  background: linear-gradient(155deg, rgba(167,139,250,.08), rgba(255,255,255,.02));
  border-color: rgba(167,139,250,.3);
}
.lead-tag {
  font-size: .64rem; font-weight: 800; letter-spacing: .12em; text-transform: uppercase;
  color: var(--brand);
}
.lead-card--alt .lead-tag { color: var(--purple); }
.lead-title { font-size: 1.45rem; font-weight: 800; letter-spacing: -.02em; line-height: 1.15; color: var(--fg); margin: 0; }
.lead-desc  { font-size: .95rem; color: var(--fg2); line-height: 1.6; margin: 0; }

/* ── Tier 2: the index ────────────────────────────────────────────────────── */
/* Rows, not cards. Proximity and a hairline rule do the grouping that ten
   bordered boxes were doing before, which is what lets the eye move down the
   list instead of stopping at every container. */
.index-list { border-top: 1px solid var(--border); }
.index-row {
  display: grid; gap: 3px;
  padding: 15px 4px;
  border-bottom: 1px solid var(--border);
  /* transform, not padding-left: shifting padding on hover relayouts the row and
     everything below it on every frame. The translate is visually identical and
     stays on the compositor. */
  transition: background .15s, transform .15s cubic-bezier(0.16, 1, 0.3, 1);
}
@media (min-width: 700px) {
  .index-row { grid-template-columns: 210px 1fr; gap: 26px; align-items: baseline; padding: 14px 4px; }
}
.index-row:hover { background: rgba(255,255,255,.02); transform: translateX(6px); }
@media (prefers-reduced-motion: reduce) {
  .index-row { transition: background .15s; }
  .index-row:hover { transform: none; }
}
.index-t { font-weight: 700; font-size: .95rem; color: var(--fg); }
.index-d { font-size: .88rem; color: var(--fg2); line-height: 1.55; }

/* ── Tier 3: utility ──────────────────────────────────────────────────────── */
/* Changelog, newsletter and contact are real but not persuasive. They get less
   room and a quieter head so they stop competing with the pitch above them. */
.tier-utility { padding: 52px 0; }
.tier-utility .section-title { font-size: 1.15rem; }
.tier-utility .sec-head { margin-bottom: 22px; }

/* ─── WOLF REPORTS REEL ───────────────────────────────────────────────────────
   The page's one authored moment. Every other section is a claim; this is the
   claim being demonstrated, so it gets the widest measure, the darkest stage,
   and the only sustained motion on the page.

   Structure: a stage (plays the selected kill) beside a rail of real recent
   kills. Nothing here is illustrated — each entry is a row out of wolf_reports
   with a timestamped Twitch VOD behind it. The iframe is created only on click
   (see mountReel), so the section costs nothing until someone asks to watch. */
#reel {
  position: relative;
  background: #070b11;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  overflow: hidden;
}
/* Backdrop: a recon field, not a second copy of the hero photo. Reusing the hero
   artwork here made the page read as one long image; this builds the surface out
   of the section's own material instead — the terrain of an actual PUBG map, held
   far enough back to be texture rather than picture.

   Layer order (top to bottom): tint → sector grid → contour sweep → map terrain. */
#reel::before {
  content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  /* Longhand throughout: the layer lists stay index-aligned and nothing silently
     overrides the shorthand's per-layer sizing. Order is top layer first.

     The tint matches the hero's own wash (rgba(6,16,28,...)) rather than a new
     near-black, so scrolling from hero to reel reads as one continuous field. */
  background-color: #070b11;
  background-image:
    /* 1. Deep tint, heavier at the edges so the stage sits in a pool of light.
       The dimming lives here rather than in a filter, so the map is darkened
       without putting a containing block on the pseudo-element. */
    radial-gradient(125% 85% at 50% 40%, rgba(6,16,28,.80) 0%, rgba(5,12,22,.95) 58%, rgba(5,11,20,.99) 100%),
    /* 2. Sector grid — same 70px module and cyan values as the hero's .hud-grid. */
    linear-gradient(rgba(28,229,255,.05) 1px, transparent 1px),
    linear-gradient(90deg, rgba(28,229,255,.035) 1px, transparent 1px),
    /* 3. The terrain itself — texture, not subject matter. A separate
       heavily-compressed JPEG derivative, not the PNG data.php's heatmap
       canvas uses — that one has to stay lossless-sharp, this is buried
       under the tint above and doesn't need to be. */
    url('/img/maps/Miramar-bg.jpg');
  background-size:     auto,      70px 70px, 70px 70px, cover;
  background-position: center,    center,    center,    center 35%;
  background-repeat:   no-repeat, repeat,    repeat,    no-repeat;
}
/* Scanlines + vignette + horizon fade — the hero runs .hud-scanlines and
   .hud-vignette as real elements; the reel gets the same treatment from one
   pseudo-element so both sections sit under the same glass. */
#reel::after {
  content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background:
    /* Top/bottom fade into the page canvas */
    linear-gradient(180deg, var(--bg) 0%, transparent 15%, transparent 85%, var(--bg) 100%),
    /* Vignette, matching .hud-vignette's shape */
    radial-gradient(130% 90% at 50% 35%, transparent 30%, rgba(5,12,22,.35) 100%),
    /* Scanlines, matching .hud-scanlines' 4px pitch */
    repeating-linear-gradient(0deg, rgba(255,255,255,.007) 0, rgba(255,255,255,.007) 1px, transparent 1px, transparent 4px);
}
#reel > .wrap { position: relative; z-index: 1; }

/* Accent word — the same device as the hero's .hero-title .accent: solid HUD cyan
   with a soft bloom, never a gradient clip. Repeating it here is what makes the
   two sections read as the same voice rather than two different pages. */
.reel-accent {
  color: var(--hud-cyan);
  text-shadow: 0 0 30px rgba(28,229,255,.45);
}
/* The section head sits over terrain here, not flat canvas, so its type needs the
   same shadow the hero gives its copy or it loses its edge against the map. */
#reel .section-title { text-shadow: 0 2px 20px rgba(0,0,0,.8); }
#reel .section-sub   { text-shadow: 0 1px 8px rgba(0,0,0,.85); }
#reel .eyebrow       { color: var(--hud-cyan); text-shadow: 0 0 16px rgba(28,229,255,.35); }

.reel-layout { display: grid; gap: 18px; }
@media (min-width: 960px) {
  .reel-layout { grid-template-columns: minmax(0,1.62fr) minmax(300px,.92fr); gap: 20px; align-items: start; }
}

/* ── Stage ─────────────────────────────────────────────────────────────────── */
.reel-stage {
  position: relative; min-width: 0;
  border: 1px solid rgba(28,229,255,.22);
  border-radius: var(--radius);
  background: #04080f;
  overflow: hidden;
  /* Live-Glow Rule: this frame holds real footage, so it earns the cyan lift. */
  box-shadow: 0 18px 60px rgba(0,0,0,.6), 0 0 0 1px rgba(28,229,255,.05), 0 0 46px rgba(28,229,235,.07);
}

/* Corner viewfinder brackets — the hero frames the whole viewport with these
   (.hud-corner); here they frame the thing you are actually looking at. Same
   28px arm, same 2px weight, same cyan. Drawn on a wrapper rather than the
   stage itself so `overflow: hidden` cannot clip them. */
.reel-frame { position: relative; }
.reel-frame::before,
.reel-frame::after {
  content: ''; position: absolute; width: 22px; height: 22px;
  z-index: 3; pointer-events: none;
}
.reel-frame::before {
  top: -7px; left: -7px;
  border-top: 2px solid rgba(28,229,255,.6);
  border-left: 2px solid rgba(28,229,255,.6);
}
.reel-frame::after {
  bottom: -7px; right: -7px;
  border-bottom: 2px solid rgba(28,229,255,.6);
  border-right: 2px solid rgba(28,229,255,.6);
}
@media (max-width: 720px) { .reel-frame::before, .reel-frame::after { display: none; } }
.reel-screen { position: relative; aspect-ratio: 16/9; width: 100%; background: #04080f; }
.reel-screen iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* Poster: what you see before you press play. The map art is the real map the
   kill happened on, so even the resting state is telling the truth. */
.reel-poster {
  position: absolute; inset: 0; z-index: 2;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px;
  cursor: pointer; border: 0; width: 100%; padding: 0;
  /* Longhand rather than the shorthand: if --reel-map ever resolves to something
     the parser rejects, only background-image is dropped and the base color and
     sizing survive. The shorthand would take the whole declaration down with it. */
  background-color: #060c14;
  background-image: var(--reel-map, none);
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
  text-align: center;
  transition: opacity .32s cubic-bezier(0.16,1,0.3,1);
}
.reel-poster::after {
  content: ''; position: absolute; inset: 0;
  background:
    linear-gradient(180deg, rgba(4,8,15,.42) 0%, rgba(4,8,15,.72) 62%, rgba(4,8,15,.93) 100%),
    radial-gradient(115% 82% at 50% 42%, transparent 24%, rgba(4,8,15,.6) 100%);
}
.reel-poster > * { position: relative; z-index: 1; }
.reel-stage.is-playing .reel-poster { opacity: 0; pointer-events: none; }

/* Play control — a reticle, not a rounded triangle in a circle. It is the one
   place the HUD's viewfinder language becomes an affordance you actually press. */
.reel-play {
  width: 74px; height: 74px; position: relative;
  display: grid; place-items: center;
  border-radius: 50%;
  background: rgba(4,10,18,.62);
  border: 1.5px solid rgba(28,229,255,.55);
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
  box-shadow: 0 0 26px rgba(28,229,255,.24), inset 0 0 22px rgba(28,229,255,.09);
  transition: transform .28s cubic-bezier(0.16,1,0.3,1), box-shadow .28s, border-color .28s;
}
.reel-play::before,
.reel-play::after {
  content: ''; position: absolute; background: rgba(28,229,255,.75);
}
/* Reticle ticks at 12 and 6 o'clock */
.reel-play::before { top: -7px; left: 50%; width: 1.5px; height: 11px; transform: translateX(-50%); }
.reel-play::after  { bottom: -7px; left: 50%; width: 1.5px; height: 11px; transform: translateX(-50%); }
.reel-play span {
  width: 0; height: 0; margin-left: 5px;
  border-left: 19px solid var(--hud-fg-bright);
  border-top: 12px solid transparent; border-bottom: 12px solid transparent;
  filter: drop-shadow(0 0 7px rgba(28,229,255,.5));
}
.reel-poster:hover .reel-play,
.reel-poster:focus-visible .reel-play {
  transform: scale(1.075);
  border-color: rgba(28,229,255,.95);
  box-shadow: 0 0 40px rgba(28,229,255,.42), inset 0 0 26px rgba(28,229,255,.16);
}
.reel-poster:focus-visible { outline: 2px solid var(--hud-cyan); outline-offset: -4px; }
.reel-poster:active .reel-play { transform: scale(.97); }

.reel-poster-cap {
  font: 700 10px/1 ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  letter-spacing: .22em; text-transform: uppercase; color: rgba(28,229,255,.85);
  text-shadow: 0 1px 8px rgba(0,0,0,.95);
}

/* Caption bar under the stage — the kill's own metadata, value-over-label. */
.reel-meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 18px;
  padding: 13px 18px;
  border-top: 1px solid rgba(28,229,255,.16);
  background: rgba(4,10,20,.72);
}
.reel-meta-headline {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  min-width: 0; margin-right: auto;
  font-size: 1.02rem; font-weight: 800; letter-spacing: -.01em; color: var(--hud-fg-bright);
}
.reel-meta-headline .rk { color: var(--hud-fg-bright); }
.reel-meta-headline .rv { color: #F87171; }
.reel-meta-headline .rarrow { color: var(--hud-muted); font-weight: 600; font-size: .85rem; }
/* The three cells are real dt/dd pairs, so they're wrapped in their own inner
   <dl> for valid markup — display:contents keeps it out of the flex layout
   so .reel-meta's flex row still sees the cells directly. */
.reel-meta-terms { display: contents; }
.reel-meta-cell {
  display: flex; flex-direction: column; gap: 3px; white-space: nowrap;
}
.reel-meta-cell dt {
  font: 700 .6rem/1 ui-sans-serif, system-ui, sans-serif;
  letter-spacing: .13em; text-transform: uppercase; color: var(--hud-muted);
}
.reel-meta-cell dd {
  margin: 0; font: 700 .82rem/1 ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  color: var(--hud-fg);
}
.reel-meta-cell dd.cyan { color: var(--hud-cyan); }
.reel-dual {
  display: inline-flex; align-items: center; gap: .35rem;
  padding: .48rem .95rem; border-radius: var(--radius-xs);
  background: rgba(28,229,255,.1); border: 1px solid rgba(28,229,255,.32);
  font: 800 .72rem/1 ui-sans-serif, system-ui, sans-serif;
  letter-spacing: .07em; text-transform: uppercase; color: var(--hud-cyan);
  text-decoration: none; white-space: nowrap;
  transition: background .15s, border-color .15s, transform .15s;
}
.reel-dual:hover { background: rgba(28,229,255,.2); border-color: rgba(28,229,255,.6); transform: translateY(-1px); }
.reel-dual:active { transform: translateY(0); }
/* The display above beats the UA's [hidden] rule, so the JS toggle was a no-op
   and every report showed a dead "Dual POV" link. */
.reel-dual[hidden] { display: none; }

/* ── Rail ──────────────────────────────────────────────────────────────────── */
.reel-rail { display: flex; flex-direction: column; min-width: 0; }
.reel-rail-head {
  display: flex; align-items: center; gap: 8px;
  padding: 0 2px 9px;
  font: 700 .66rem/1 ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  letter-spacing: .2em; text-transform: uppercase; color: var(--hud-cyan);
}
.reel-rail-head .rdot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--hud-green); box-shadow: 0 0 6px var(--hud-green);
}
.reel-rail-head .rcount { margin-left: auto; color: var(--hud-muted); letter-spacing: .1em; }
.reel-list {
  display: flex; flex-direction: column; gap: 5px;
  max-height: 452px; overflow-y: auto; padding-right: 4px;
  scrollbar-width: thin; scrollbar-color: rgba(28,229,255,.25) transparent;
}
.reel-list::-webkit-scrollbar { width: 5px; }
.reel-list::-webkit-scrollbar-thumb { background: rgba(28,229,255,.25); border-radius: 3px; }
/* Below 960px the layout is a single column, so a capped, independently
   scrolling list inside a scrolling page is a trap on touch: a swipe that starts
   on a row scrolls the list, not the page, and the page appears stuck. The rail
   flows with the page instead, clipped to REEL_MOBILE_VISIBLE rows with a
   "show more" button (see index.php) rather than a hidden scrollbar. */
@media (max-width: 959px) {
  .reel-list { max-height: none; overflow-y: visible; padding-right: 0; }
}
/* Visibility of both the clipped rows and the button is driven by the `hidden`
   attribute alone, set in index.php — never by a display rule in a media query.
   `[hidden]` is only a UA `display:none`, so ANY author `display` on the same
   element beats it: a `.reel-more{display:flex}` inside the mobile query would
   have made the button permanently visible and a `.reel-item{display:grid}`
   already outranks `hidden` on the rows. Hence :not([hidden]) here and an
   explicit [hidden] rule for the rows — one source of truth, no fighting. */
.reel-item[hidden] { display: none; }
.reel-more[hidden] { display: none; }
.reel-more:not([hidden]) {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; min-height: 48px; margin-top: 6px; padding: 12px 18px;
  background: var(--glass); color: var(--fg2);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  font-size: .9rem; font-weight: 700; font-family: inherit; line-height: 1.2;
  cursor: pointer;
  transition: background .2s, border-color .2s, color .2s;
}
.reel-more:hover { background: var(--glass-hover); border-color: var(--border-brand); color: var(--fg); }
.reel-more:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.reel-more .chev { color: var(--brand); flex-shrink: 0; }

.reel-item {
  display: grid; grid-template-columns: 3px 1fr auto; align-items: center; gap: 11px;
  width: 100%; text-align: left; min-height: 56px;
  padding: 11px 12px 11px 0;
  border: 1px solid rgba(255,255,255,.06);
  border-radius: var(--radius-xs);
  background: rgba(255,255,255,.022);
  color: var(--hud-fg); cursor: pointer;
  font: inherit;
  transition: background .16s, border-color .16s, transform .16s cubic-bezier(0.16,1,0.3,1);
}
/* The 3px stripe is a grid column, not a border-left — it is the selection
   indicator for a list, which is the one thing a stripe legitimately is. */
.reel-item::before {
  content: ''; grid-column: 1; align-self: stretch;
  border-radius: 2px; background: transparent; transition: background .16s;
}
.reel-item:hover { background: rgba(255,255,255,.05); border-color: rgba(28,229,255,.22); transform: translateX(3px); }
.reel-item:focus-visible { outline: 2px solid var(--hud-cyan); outline-offset: 1px; }
.reel-item[aria-current="true"] {
  background: rgba(28,229,255,.085);
  border-color: rgba(28,229,255,.4);
}
.reel-item[aria-current="true"]::before { background: var(--hud-cyan); box-shadow: 0 0 9px rgba(28,229,255,.75); }
.reel-item-main { min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.reel-item-names {
  display: flex; align-items: baseline; gap: 6px; min-width: 0;
  font-size: .84rem; font-weight: 700; color: var(--hud-fg-bright);
}
.reel-item-names .rn { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.reel-item-names .rv { color: #F87171; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.reel-item-names .rarrow { color: var(--hud-muted); font-size: .72rem; flex-shrink: 0; }
.reel-item-sub {
  font: 600 .69rem/1 ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  letter-spacing: .04em; color: var(--hud-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.reel-item-sub .rsep { opacity: .45; }
.reel-item-badge {
  font: 800 .58rem/1 ui-sans-serif, system-ui, sans-serif;
  letter-spacing: .1em; text-transform: uppercase;
  padding: .3rem .5rem; border-radius: 3px; white-space: nowrap;
  background: rgba(255,255,255,.05); color: var(--hud-muted);
}
.reel-item-badge.dual { background: rgba(28,229,255,.14); color: var(--hud-cyan); }
.reel-item-badge.win  { background: rgba(45,212,130,.14); color: var(--hud-green); }

/* Empty state — real, because a fresh guild genuinely has no reports yet. */
.reel-empty {
  padding: 30px 26px; text-align: center;
  border: 1px dashed rgba(255,255,255,.12); border-radius: var(--radius);
  background: rgba(255,255,255,.02);
}
.reel-empty h3 { margin: 0 0 7px; font-size: 1rem; font-weight: 800; color: var(--fg); }
.reel-empty p  { margin: 0 auto; max-width: 46ch; font-size: .9rem; line-height: 1.6; color: var(--fg2); }

@media (prefers-reduced-motion: reduce) {
  .reel-item, .reel-play, .reel-poster, .reel-dual { transition: none; }
  .reel-item:hover { transform: none; }
  .reel-poster:hover .reel-play { transform: none; }
}

/* ─── COMMANDS ────────────────────────────────────────────────────────────── */
.cmd-card {
  display: flex; align-items: flex-start; gap: 16px; padding: 16px 20px;
  border-radius: var(--radius-sm); border: 1px solid var(--border);
  background: var(--glass); transition: border-color .2s, background .2s;
}
.cmd-card:hover { border-color: var(--border-brand); background: var(--glass-hover); }
.kbd {
  font-family: ui-monospace, "SFMono-Regular", Menlo, Monaco, Consolas, monospace;
  background: rgba(50,167,235,.1); border: 1px solid rgba(50,167,235,.2);
  padding: .18rem .5rem; border-radius: var(--radius-xs);
  font-size: .82rem; color: var(--brand); white-space: nowrap; flex-shrink: 0;
}
.cmd-desc { font-size: .87rem; color: var(--fg2); line-height: 1.5; }

/* ─── SCREENS ─────────────────────────────────────────────────────────────── */
/* No forced aspect-ratio: these are Discord embed screenshots, and the previous
   16/9 cover-crop discarded ~29% of imgs/4.png (618x488, a 1.27:1 image) — cutting
   off the embed fields and footer, which are the actual proof. Intrinsic sizing via
   width/height attributes reserves the right space and prevents layout shift. */
.screen-img {
  width: 100%; height: auto; display: block;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--bg3);
}
.screen-cap {
  display: block; margin-top: 10px;
  font-size: .7rem; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: var(--muted);
}

/* ─── DUAL VIEW ───────────────────────────────────────────────────────────── */
.dual-mock {
  display: grid; grid-template-columns: 1fr 1fr; gap: 3px;
  border-radius: var(--radius); overflow: hidden;
  border: 1px solid var(--border);
  box-shadow: 0 24px 72px rgba(0,0,0,.5);
  max-width: 560px;
}
.dual-pov {
  aspect-ratio: 16/9;
  display: flex; align-items: center; justify-content: center;
  font-size: .78rem; color: var(--muted); font-weight: 700; letter-spacing: .06em;
}
.dual-pov:first-child { background: linear-gradient(135deg, #091520 0%, #0d2035 100%); }
.dual-pov:last-child  { background: linear-gradient(135deg, #12091f 0%, #1d0f30 100%); }
.dual-info { display: flex; flex-direction: column; gap: 24px; justify-content: center; }
/* Was an inline grid-template-columns:1fr 1fr, which no media query could override.
   As a class it can collapse to one column before the two ~130px columns force the
   nowrap spec pills to overflow horizontally. */
.dual-split { display: grid; gap: 48px; grid-template-columns: 1fr 1fr; align-items: center; }
@media (max-width: 820px) {
  .dual-split { grid-template-columns: 1fr; gap: 32px; }
  .dual-mock { max-width: 100%; }
}
.dual-stat { display: flex; align-items: center; gap: 12px; }
.dual-stat-icon { font-size: 1.5rem; line-height: 1; }
.dual-stat-label { font-size: .75rem; color: var(--muted); font-weight: 600; text-transform: uppercase; letter-spacing: .08em; }
.dual-stat-val { font-size: 1.1rem; color: var(--fg); font-weight: 700; }

/* ─── ROADMAP ─────────────────────────────────────────────────────────────── */
.roadmap-card { position: relative; overflow: hidden; }
.roadmap-card::before {
  content: ''; position: absolute; top: 0; left: 0; right: 0; height: 2px;
}
.roadmap-card.now::before  { background: var(--green); }
.roadmap-card.next::before { background: var(--brand); }
.roadmap-card.later::before { background: var(--purple); }
.roadmap-tag { font-size: .7rem; font-weight: 800; text-transform: uppercase; letter-spacing: .12em; margin-bottom: 14px; }
.roadmap-card.now   .roadmap-tag { color: var(--green); }
.roadmap-card.next  .roadmap-tag { color: var(--brand); }
.roadmap-card.later .roadmap-tag { color: var(--purple); }
.roadmap-list { display: flex; flex-direction: column; gap: 10px; }
.roadmap-item { display: flex; align-items: flex-start; gap: 10px; font-size: .9rem; color: var(--fg2); }
.roadmap-item::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: var(--border); flex-shrink: 0; margin-top: .45rem; }
.roadmap-card.now   .roadmap-item::before { background: var(--green); }
.roadmap-card.next  .roadmap-item::before { background: var(--brand); }
.roadmap-card.later .roadmap-item::before { background: var(--purple); }

/* ─── CHANGELOG ───────────────────────────────────────────────────────────── */
/* Spacing between entries lives on the stack, not on the card. The card itself
   carries no margin (the global reset zeroes it), so before this existed a
   second News Day would have rendered flush against the first, hairline borders
   doubling into a seam. The home page shows two entries and stops; the rest are
   on changelog.php, so this section's height no longer grows week by week. */
.changelog-stack { display: flex; flex-direction: column; gap: 14px; }
.changelog-entry {
  padding: 24px 28px;
  /* Hairline brand edge, per DESIGN.md Shapes: "Borders are hairlines, never heavy."
     The version label above already carries the brand colour, so the entry reads as
     brand-affiliated without a heavy side tab. */
  border-left: 1px solid var(--border-brand);
  border-radius: 0 var(--radius) var(--radius) 0;
}
/* The next entry, clipped to a sliver and faded out: it says "there is more"
   without a second interaction idiom. The gradient's transparent end is
   interpolated in premultiplied alpha, so `transparent` fades to --bg2 cleanly
   rather than through grey — and tracks the section if it's ever re-themed,
   which a hardcoded rgba() stop would not. Its markup is aria-hidden: the
   clipped text is decoration, and the link below is the real affordance. */
.changelog-peek { position: relative; height: 96px; overflow: hidden; }
.changelog-peek::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 72px;
  background: linear-gradient(to bottom, transparent, var(--bg2));
  pointer-events: none;
}
.changelog-more {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 48px; margin-top: -4px; padding: 14px 22px;
  background: var(--glass); color: var(--fg2);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  font-size: .9rem; font-weight: 700; text-decoration: none;
  transition: background .2s, border-color .2s, color .2s;
}
.changelog-more:hover { background: var(--glass-hover); border-color: var(--border-brand); color: var(--fg); }
.changelog-more:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.changelog-more .arrow { color: var(--brand); font-size: .85rem; }
.changelog-version { font-size: .72rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--brand); margin-bottom: 4px; }
.changelog-list { display: flex; flex-direction: column; gap: 8px; margin-top: 12px; }
.changelog-item { display: flex; align-items: flex-start; gap: 10px; font-size: .9rem; color: var(--fg2); }
.changelog-item::before { content: '→'; color: var(--brand); font-size: .8rem; flex-shrink: 0; margin-top: .1rem; }

/* ─── CTA BAND ────────────────────────────────────────────────────────────── */
.cta-band {
  position: relative; overflow: hidden;
  background: linear-gradient(135deg, rgba(50,167,235,.12) 0%, rgba(50,167,235,.04) 100%);
  border-top: 1px solid var(--border-brand); border-bottom: 1px solid var(--border-brand);
  padding: 72px 0;
}
.cta-band::before {
  content: ''; position: absolute; inset: 0;
  background: radial-gradient(ellipse 70% 80% at 80% 50%, rgba(50,167,235,.12) 0%, transparent 60%);
  pointer-events: none;
}

/* ─── FAQ ─────────────────────────────────────────────────────────────────── */
.faq-item { border-bottom: 1px solid var(--border); }
.faq-q {
  width: 100%; display: flex; align-items: center; justify-content: space-between;
  padding: 18px 0; background: none; border: none; color: var(--fg);
  font-size: .97rem; font-weight: 600; text-align: left; gap: 12px; cursor: pointer;
}
.faq-q svg { flex-shrink: 0; transition: transform .25s; color: var(--muted); }
.faq-item.open .faq-q svg { transform: rotate(45deg); color: var(--brand); }
/* Height animates via grid-template-rows rather than max-height: the row track
   resolves to the content's real height at any width, so an open answer reflows
   correctly on resize/rotate instead of clipping at a stale measured pixel value. */
.faq-a { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .3s ease; }
.faq-item.open .faq-a { grid-template-rows: 1fr; }
/* The grid item must carry no padding, border or margin. A 0fr track is floored
   at the item's *minimum contribution*, and that measurement includes padding —
   a static `padding-bottom: 18px` here left an 18px strip of every closed answer
   on screen, clipped mid-line. So the bottom spacing only exists while open, and
   rides the same .3s so it grows and shrinks with the row instead of snapping. */
.faq-a > .faq-a-inner { overflow: hidden; min-height: 0; }
.faq-a-inner {
  padding: 0; color: var(--fg2); font-size: .93rem; line-height: 1.7;
  transition: padding-bottom .3s ease;
}
.faq-item.open .faq-a-inner { padding-bottom: 18px; }
@media (prefers-reduced-motion: reduce) {
  .faq-a, .faq-a-inner { transition: none; }
}

/* ─── FORMS ───────────────────────────────────────────────────────────────── */
.form-input {
  width: 100%; padding: .8rem 1rem; border-radius: var(--radius-sm);
  border: 1px solid var(--border); background: rgba(10,17,32,.9);
  color: var(--fg); font-size: .93rem; outline: none;
  transition: border-color .15s;
}
.form-input:focus { border-color: var(--border-brand); }
.form-input::placeholder { color: var(--muted); }
textarea.form-input { resize: vertical; min-height: 100px; }
.form-grid { display: grid; gap: 10px; }

/* ─── NEWSLETTER ──────────────────────────────────────────────────────────── */
.newsletter-band {
  background: var(--bg2); border-top: 1px solid var(--border); border-bottom: 1px solid var(--border);
  padding: 64px 0;
}
/* Form posts redirect back to #newsletter / #contact; clear the sticky header. */
#newsletter, #contact { scroll-margin-top: 72px; }
.form-flash { flex-basis: 100%; margin: 12px 0 0; font-size: .88rem; font-weight: 600; color: var(--green); }
.form-flash.is-error { color: #F87171; }
.newsletter-band .form-flash { margin-top: -10px; } /* the card's 24px flex gap already spaces it */
/* Was an inline style="…min-width:260px…", which no media query could reach. The
   card has 52px of its own padding inside an 18px wrap, so 260px overflowed the
   card below a ~355px viewport, and above that the email field was left ~156px —
   too narrow to see what you typed. Stacks on phones, sits inline from 480px. */
.newsletter-form { display: flex; gap: 8px; flex: 1; min-width: 0; align-items: center; flex-wrap: wrap; }
.newsletter-form .form-input { flex: 1 1 100%; min-width: 0; }
.newsletter-form .btn { flex: 1 1 100%; justify-content: center; }
@media (min-width: 480px) {
  .newsletter-form .form-input { flex: 1 1 auto; }
  .newsletter-form .btn { flex: 0 0 auto; }
}

/* ─── CONTACT ─────────────────────────────────────────────────────────────── */
.contact-grid { display: grid; gap: 40px; }
@media (min-width: 700px) { .contact-grid { grid-template-columns: 1fr 1.3fr; } }
.contact-link { display: flex; align-items: center; gap: 10px; color: var(--fg2); font-size: .92rem; padding: 12px 0; border-bottom: 1px solid var(--border); }
.contact-link:last-child { border-bottom: none; }
.contact-link:hover { color: var(--fg); }
.contact-link-icon { width: 32px; height: 32px; border-radius: 8px; display: flex; align-items: center; justify-content: center; background: var(--glass); border: 1px solid var(--border); font-size: .95rem; flex-shrink: 0; }

/* ─── SCROLL REVEAL ───────────────────────────────────────────────────────── */
/* Content is visible by default. Only once JS confirms IntersectionObserver is
   running does `.reveal-armed` on <html> arm the hidden start state — otherwise a
   script error or an unsupported browser would leave nine sections permanently
   invisible. Exponential ease-out (not linear `ease`) so sections settle rather
   than drift to a stop. */
.reveal { transition: opacity .5s cubic-bezier(0.16, 1, 0.3, 1), transform .5s cubic-bezier(0.16, 1, 0.3, 1); }
.reveal-armed .reveal { opacity: 0; transform: translateY(18px); }
.reveal-armed .reveal.visible { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .reveal-armed .reveal { opacity: 1; transform: none; transition: none; }
}

/* ─── DIVIDER ─────────────────────────────────────────────────────────────── */
.divider { height: 1px; background: var(--border); }

/* ─── MOBILE TWEAKS ───────────────────────────────────────────────────────── */
@media (max-width: 600px) {
  section { padding: 64px 0; }
  /* Longhand, not `padding: 0 18px`. The hero is <div class="wrap hero-content">
     — one element carrying both classes at the same specificity — so a shorthand
     here also wrote padding-top/bottom: 0, and because this block sits lower in
     the file than the 720px one it beat .hero-content's `52px 0 56px`. Result:
     on every phone 600px and under the hero had NO vertical padding, and the Bot
     Online pill sat hard against the live-streamers bar with only that bar's own
     10px beneath it. .wrap owns the side gutters; it must not touch the rest. */
  .wrap, .wrap-sm { padding-left: 18px; padding-right: 18px; }
  .wrap, .wrap-sm {
    padding-left: max(18px, env(safe-area-inset-left));
    padding-right: max(18px, env(safe-area-inset-right));
  }
  /* Restated after .wrap above so source order can never strip it again. These
     are the values the 720px block always intended; tune them here, not there. */
  .hero-content { padding-top: 52px; padding-bottom: 56px; }
  /* .hero's min-height deliberately lives on the base rule and the
     min-width:721px block only — a third value here is what broke it before. */
}

/* ─── LIVE BUBBLE BAR + TWITCH MODAL ──────────────────────────────────────────
   Deliberately NOT defined here. shared.css owns #live-bar, .live-bubble and
   #live-modal for every page that renders them. This file used to carry a
   second, full copy of that block, loaded after shared.css and therefore
   winning — and the two had already drifted: .live-dot pulsed at 3.4s here and
   2s there, so the same component breathed at two different rates depending on
   which page you were on. The 3.4s version was the intended one and now lives
   in shared.css. Page-specific tweaks go here as overrides, never as a copy. */
