/* ============================================================================
   GAMESWA — /players
   Session C · 2026-08-11
   ----------------------------------------------------------------------------
   Page-scoped. Loaded only by /players/, linked outside the canonical GW:HEAD
   block so the shared chrome stays byte-identical across pages.

   Nothing here is a fork of a shared component. The RUSH radar (media slot M8)
   is the only thing on the site that needs this CSS, and it is genuinely one
   page's art, not a component other pages will want.

   NO HEX IN THIS FILE. Every colour is a token from tokens.css.
   ========================================================================== */

/* ── SHARED SMALL BITS ───────────────────────────────────────────────────*/

/* Lead paragraphs read better narrower than the 62ch body default at the
   display sizes this page uses. */
.gw-players-lead { max-width: 40ch; margin-top: var(--gw-s-5); }
.gw-players-body { margin-top: var(--gw-s-5); }
.gw-players-cta  { margin: var(--gw-s-6) 0 0; }

/* ── RUSH SECTION LAYOUT ─────────────────────────────────────────────────
   Mobile first: copy, then radar, one column. Desktop is the adaptation. */
.gw-rush {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--gw-s-7);
  align-items: center;
}
@media (min-width: 900px) {
  .gw-rush { grid-template-columns: 1fr 1fr; gap: var(--gw-s-8); }
}
.gw-rush__copy > .gw-body { margin-top: var(--gw-s-5); }

/* ── RUSH RADAR CARD · MEDIA SLOT M8 ─────────────────────────────────────
   A broadcast graphics panel, not a chart. The box is reserved by the SVG's
   own aspect ratio, so nothing shifts: there is no asset to arrive.         */
.gw-radar-card {
  margin: 0;
  padding: var(--gw-s-5);
  background: var(--gw-surface-2);
  border: 1px solid var(--gw-rule);
  border-radius: var(--gw-r-md);
}
.gw-radar-card__head {
  display: flex;
  align-items: baseline;
  gap: var(--gw-s-3);
  border-bottom: 1px solid var(--gw-rule);
  padding-bottom: var(--gw-s-3);
}
/* The score. Sanctioned tease: score, radar, name. Nothing behind it. */
.gw-radar-card__score {
  margin-inline-start: auto;
  font-family: var(--gw-font-display);
  font-weight: 900;
  font-size: var(--gw-t-xl);
  line-height: 1;
  letter-spacing: var(--gw-track-display);
  font-variant-numeric: tabular-nums;
  color: var(--gw-text);
}
/* Said twice on purpose: here, and in the screen-reader description. */
.gw-radar-card__note {
  margin: var(--gw-s-3) 0 0;
  text-align: center;
  text-transform: none;
  letter-spacing: 0.08em;
}

.gw-radar {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 440 / 300;   /* matches the viewBox. Zero layout shift. */
  margin-top: var(--gw-s-3);
  overflow: visible;
}

/* ── RADAR · STATIC APPEARANCE ───────────────────────────────────────────*/
.gw-radar__ring {
  fill: none;
  stroke: var(--gw-rule-strong);
  stroke-width: 1;
}
.gw-radar__ring--4 { stroke: var(--gw-rule-strong); }
.gw-radar__spokes line {
  stroke: var(--gw-rule);
  stroke-width: 1;
}
/* Blue is the working accent in both themes. --gw-accent-text is the
   text-safe blue per theme, which is exactly the contrast a 2px stroke wants:
   #4A70F0 on ink, #0E2A8C on off-white. */
.gw-radar__poly {
  fill: var(--gw-accent);
  fill-opacity: 0.16;
  stroke: var(--gw-accent-text);
  stroke-width: 2;
  stroke-linejoin: round;
}
/* Lime as punctuation, and as a FILL, never as type. Six dots is sparing. */
.gw-radar__dots circle {
  fill: var(--gw-punct-fill);
  stroke: var(--gw-surface-2);
  stroke-width: 1.5;
}
/* Axis labels are TYPE, so they take a text token, never lime. */
.gw-radar__labels text {
  font-family: var(--gw-font-data);
  font-size: 13px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  fill: var(--gw-text-faint);
}

/* ── RADAR · DRAW ON ─────────────────────────────────────────────────────
   transform/opacity and stroke-dashoffset only. The polygon carries
   pathLength="100", so the dash maths is exact and needs no JS to measure it.

   reveal.js puts .is-visible on the .gw-reveal card when it scrolls in. The
   radar rides that one observer rather than adding a second. */
.gw-radar__ring,
.gw-radar__spokes,
.gw-radar__dots {
  opacity: 0;
  transition: opacity var(--gw-dur-slow) var(--gw-ease);
}
.gw-radar__ring {
  transform: scale(0.82);
  transform-box: view-box;
  transform-origin: 220px 150px;
  transition: opacity var(--gw-dur-slow) var(--gw-ease),
              transform var(--gw-dur-slow) var(--gw-ease);
}
.gw-radar__ring--1 { transition-delay: 0.00s; }
.gw-radar__ring--2 { transition-delay: 0.06s; }
.gw-radar__ring--3 { transition-delay: 0.12s; }
.gw-radar__ring--4 { transition-delay: 0.18s; }
.gw-radar__spokes  { transition-delay: 0.20s; }

.gw-radar__poly {
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
  fill-opacity: 0;
  transition: stroke-dashoffset 1.1s var(--gw-ease) 0.28s,
              fill-opacity var(--gw-dur-slow) var(--gw-ease) 0.9s;
}
.gw-radar__dots { transition-delay: 1.0s; }

.is-visible .gw-radar__ring   { opacity: 1; transform: scale(1); }
.is-visible .gw-radar__spokes { opacity: 1; }
.is-visible .gw-radar__poly   { stroke-dashoffset: 0; fill-opacity: 0.16; }
.is-visible .gw-radar__dots   { opacity: 1; }

/* Quality floor. Two ways the radar must be simply PRESENT, not animating:
   no JS at all, and a visitor who asked for no motion. Neither may depend on
   .is-visible ever being added. */
html.no-js .gw-radar__ring,
html.no-js .gw-radar__spokes,
html.no-js .gw-radar__dots {
  opacity: 1;
  transform: none;
}
html.no-js .gw-radar__poly { stroke-dashoffset: 0; fill-opacity: 0.16; }

@media (prefers-reduced-motion: reduce) {
  .gw-radar__ring,
  .gw-radar__spokes,
  .gw-radar__dots {
    opacity: 1;
    transform: none;
    transition: none;
    transition-delay: 0s;
  }
  .gw-radar__poly {
    stroke-dashoffset: 0;
    fill-opacity: 0.16;
    transition: none;
  }
}

/* ── THE APP SECTION ─────────────────────────────────────────────────────
   .gw-invert already holds this block at ink in both themes.               */
.gw-app .gw-eyebrow { flex-wrap: wrap; }
.gw-app .gw-body { margin-top: var(--gw-s-5); }

.gw-app__release {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--gw-s-5);
  margin-top: var(--gw-s-6);
}
@media (min-width: 768px) {
  .gw-app__release { flex-direction: row; align-items: center; gap: var(--gw-s-6); }
  .gw-app__release .gw-body { margin-top: 0; }
}

/* State B only. The badge box is sized before the asset exists, and reads as
   a deliberate slot rather than a broken image if the flag is ever flipped
   ahead of the asset drop. */
.gw-appstore {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 140px;
  min-height: 47px;
  padding: 0 var(--gw-s-4);
  border: 1px solid var(--gw-rule-strong);
  border-radius: var(--gw-r-md);
  font-family: var(--gw-font-data);
  font-size: var(--gw-t-data);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gw-text-muted);
}
.gw-appstore[aria-disabled='true'] { opacity: 0.55; cursor: not-allowed; }
.gw-appstore img { width: 140px; height: 47px; object-fit: contain; }
