/* ── Replay ──────────────────────────────────────────────────────────────────
   A video player for something that has no video. Two ideas shape it.

   THE STAGE IS A FRAME, NOT A PAGE. What is inside it is a real board being
   driven by a recording, and the recording's coordinates are fractions of the
   box the board was recorded in — so the frame holds the ASPECT RATIO that was
   recorded (--ar-a, set per segment from JS) and the board fills it exactly. A
   stage that simply took the space available would put every tap a few percent
   off, which on a 5×5 grid is a different cell.

   THE TWO SIDES KEEP THEIR COLOURS. The swap control at the top is the reason
   this screen exists — you watch the same instant from the other person's
   screen — so it reuses the arena's own --vs-mine / --vs-theirs pairing rather
   than inventing a selected state. Which side is lit IS which recording is
   playing.

   Composes: tokens.css → base.css → components.css → arena.css. No new values. */

/* Line icons outside a button need the app's stroke treatment; the two
   fill-based marks (avatars, game marques) are excluded, exactly as in
   arena.css. */
.ah-hgo svg, .ah-hempty-ic svg, .ar-draft-rdy svg, .ah-hempty .pill svg {
  fill: none; stroke: currentColor; stroke-width: var(--stroke);
  stroke-linecap: round; stroke-linejoin: round;
}

/* ══ past challenges ═════════════════════════════════════════════════════ */

.ah-hist { max-width: var(--wrap); margin: 0 auto; padding: var(--space-6); }
.ah-hist-load, .ah-hnote {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-label);
  color: var(--mute);
  margin-bottom: var(--space-6);
}

.ah-hrow {
  border: var(--hairline) solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  overflow: hidden;
}
.ah-hrow + .ah-hrow { margin-top: var(--space-4); }
/* A hairline down the left edge is the whole outcome badge — quieter than a
   coloured card, and it survives being read at a glance down a long list. */
.ah-hrow.won  { border-left: 2px solid var(--vs-win); }
.ah-hrow.lost { border-left: 2px solid var(--vs-lose); }
.ah-hrow.live { border-left: 2px solid var(--accent); }

.ah-hmain {
  width: 100%;
  display: flex;
  align-items: center;
  gap: var(--space-5);
  padding: var(--space-5);
  background: none;
  border: 0;
  color: var(--text);
  cursor: pointer;
  text-align: left;
}
.ah-hmain:hover { background: var(--surface-2); }
.ah-ht { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--space-1); }
.ah-ht strong { font-size: var(--text-lg); font-weight: 500; }
.ah-ht small {
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  letter-spacing: var(--tracking-label);
  color: var(--mute);
}
.ah-hscore { font-size: var(--text-xl); color: var(--text); }
.ah-hscore i { color: var(--mute); font-style: normal; padding: 0 var(--space-2); }
.ah-hgo { color: var(--mute); display: flex; }
.ah-hgo svg { width: var(--icon); height: var(--icon); }

.ah-hrounds {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  padding: 0 var(--space-5) var(--space-5);
}
.ah-hround {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-4) var(--space-2) var(--space-2);
  background: var(--surface-2);
  border: var(--hairline) solid var(--line);
  border-radius: var(--radius);
  color: var(--dim);
  cursor: pointer;
  transition: border-color var(--t), color var(--t);
}
.ah-hround:hover { border-color: var(--accent-line); color: var(--text); }
.ah-hround.won  { border-color: var(--success-line); }
.ah-hround.lost { border-color: var(--danger-line); }
.ah-hround-ic { display: flex; }
.ah-hround-ic svg { width: 22px; height: 22px; border-radius: var(--radius-sm); }
.ah-hround-n {
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  letter-spacing: var(--tracking-label);
}

.ah-hempty { text-align: center; padding: var(--space-11) var(--space-6); }
.ah-hempty-ic { color: var(--mute); display: inline-flex; }
.ah-hempty-ic svg { width: 44px; height: 44px; }
.ah-hempty h2 { font-size: var(--text-xl); font-weight: 400; margin: var(--space-6) 0 var(--space-4); }
.ah-hempty p {
  color: var(--dim);
  font-size: var(--text-base);
  line-height: var(--leading-body);
  margin-bottom: var(--space-8);
}

/* ══ the replay screen ═══════════════════════════════════════════════════ */


/* ── the swap: two sides and a pivot ────────────────────────────────────── */

/* ── the segment picker ─────────────────────────────────────────────────── */

/* ── the stage ──────────────────────────────────────────────────────────── */


/* The frame carries the recorded aspect, and the WIDTH is what gives way when
   the height runs out — a `max-height` alone would cap the height while the
   width kept growing, quietly widening the box past the ratio. The ratio is the
   correctness guarantee here (normalised coordinates only land on the right
   cells inside a box of the recorded shape), so it is the one thing that must
   not bend. */
.ar-frame {
  position: relative;
  /* Fit the stage, whatever shape the recording was. The stage is the flex slack
     between the nav and the timeline, so the frame is bounded on BOTH axes and
     letterboxes to the recorded aspect — a fixed vh height was for the old
     scrolling layout and would now overflow a short screen.
     --ar-a is set per recording; the fallback keeps the box real if a stream
     arrives without a board/session event. */
  /* Let the ratio drive BOTH axes. `height: 100%` used to force a height, so
     aspect-ratio then computed a width wider than the stage and the board was
     clipped on the right — exactly the "video is cutting" report. With only max
     constraints the box letterboxes instead. */
  aspect-ratio: var(--ar-a, 3 / 4);
  width: 100%;
  max-width: 100%;
  max-height: 100%;
  background: var(--bg);
  border: var(--hairline) solid var(--line-2);
  border-radius: var(--radius);
  overflow: hidden;
  /* Nothing here scrolls any more, and nothing here is interactive — the shield
     absorbs every gesture, so the browser should not try to interpret any. */
  touch-action: none;
}
/* NOT inset:0 — scaleToFrame() gives the mount an explicit size (the width the
   game assumes) and scales it into the frame, so it must be free to be a
   different size from its parent. */
.ar-mount { position: absolute; left: 0; top: 0; display: flex; flex-direction: column; }
.ar-board { flex: 1; min-height: 0; }
.ar-miss {
  margin: auto;
  padding: var(--space-8);
  text-align: center;
  color: var(--mute);
  font-size: var(--text-base);
}

/* ── the ghost: the finger, drawn from the recording ─────────────────────── */

/* Both layers are inert. They sit over a live board, and the replay hit-tests
   through this exact point to find the element to dispatch into — a ghost that
   could be hit would swallow every synthesised tap. */
.ar-trail, .ar-ghost { pointer-events: none; }

.ar-trail {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  z-index: var(--z-panel);
}
.ar-trail polyline {
  fill: none;
  stroke: var(--accent);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0.55;
}

.ar-ghost {
  position: absolute;
  z-index: var(--z-panel);
  width: 22px; height: 22px;
  margin: -11px 0 0 -11px;
  border-radius: var(--radius-full);
  border: 2px solid var(--accent);
  background: var(--accent-dim);
  transition: transform var(--duration-1) var(--ease);
}
/* Pressed is smaller and filled — the same read as a fingertip landing. */
.ar-ghost.down { transform: scale(0.62); background: var(--accent); }

/* ── the draft reconstruction ───────────────────────────────────────────── */

.ar-draft {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  padding: var(--space-6);
  overflow: auto;
}
.ar-draft[hidden] { display: none; }
.ar-draft-h { display: flex; align-items: center; gap: var(--space-5); flex-wrap: wrap; }
.ar-draft-f {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-label);
  color: var(--accent);
}
.ar-draft-f.dim { color: var(--mute); }
.ar-draft-rdy {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-label);
  color: var(--vs-win);
}
.ar-draft-rdy svg { width: var(--icon-sm); height: var(--icon-sm); }

.ar-draft-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(74px, 1fr));
  gap: var(--space-3);
}
.ar-dtile {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-2);
  background: var(--surface);
  border: var(--hairline) solid var(--line);
  border-radius: var(--radius);
  transition: border-color var(--t), opacity var(--t);
}
.ar-dtile-ic { display: flex; }
.ar-dtile-ic svg { width: 30px; height: 30px; border-radius: var(--radius-sm); }
.ar-dtile-n {
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  letter-spacing: var(--tracking-label);
  color: var(--mute);
  text-align: center;
}
.ar-dtile.hover  { border-color: var(--accent-line); background: var(--surface-2); }
.ar-dtile.picked { border-color: var(--accent); }
.ar-dtile.picked .ar-dtile-n { color: var(--accent); }
.ar-dtile.banned { opacity: 0.35; border-color: var(--danger-line); }

/* ── caption + transport ────────────────────────────────────────────────── */

.ar-cap {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-label);
  color: var(--dim);
  text-align: center;
  min-height: var(--space-6);
}
.ar-pp { flex: none; }
.ar-time { flex: none; font-size: var(--text-xs); color: var(--mute); }

/* The move track. Every tick is a move the recording says was made, so the
   shape of the round — the long think, the burst at the end — is legible before
   you press play. */
.ar-marks { position: absolute; left: 0; right: 0; top: 4px; height: 6px; }
.ar-marks i {
  position: absolute;
  top: 0;
  width: 1px; height: 6px;
  background: var(--line-2);
}

.ar-note {
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  letter-spacing: var(--tracking-label);
  line-height: var(--leading-body);
  color: var(--over-text);
  text-align: center;
}
.ar-note[hidden] { display: none; }

/* A short screen puts the transport first: the board can shrink, the controls
   cannot be off the bottom of the page. */
@media (max-height: 620px) {
  .ar-frame { width: min(100%, calc(48vh * var(--ar-a))); }
  .ar { gap: var(--space-4); }
}


/* ── layout: three rows, no scroll ───────────────────────────────────────────
   The nav is fixed height, the bar is fixed height, and the stage takes whatever
   is left. Sized in dvh (not vh) so the mobile URL bar collapsing doesn't push
   the timeline under the fold — which is the one control a viewer always needs.
   `min-height: 0` on the stage is what actually lets it shrink inside the flex
   column; without it the board's intrinsic height wins and the page scrolls. */
.ar-screen { height: 100dvh; display: flex; flex-direction: column; overflow: hidden; }
.ar-screen .scroll { flex: 1; min-height: 0; overflow: hidden; padding: 0; }
.ar {
  height: 100%; display: flex; flex-direction: column; min-height: 0;
  max-width: var(--wrap); margin-inline: auto; width: 100%;
  padding: 0 var(--space-6) calc(var(--space-5) + var(--sab));
}
.ar-stage {
  flex: 1; min-height: 0; padding: var(--space-4) 0;
  /* minmax(0,1fr), not auto: an `auto` track is sized by its content, and the
     frame's `width:100%` then resolves against a track the frame itself defines —
     circular, and it collapsed the board to 2x3px. Definite tracks break the loop. */
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr);
  place-items: center;
}

/* Whose view — two small avatars in the nav, current one lit. */
.ar-who { display: inline-flex; align-items: center; gap: var(--space-2); }
.ar-side {
  display: grid; place-items: center; padding: 2px;
  background: none; border: var(--hairline) solid transparent; border-radius: var(--radius-full);
  cursor: pointer; opacity: 0.5; transition: opacity var(--t), border-color var(--t);
}
.ar-side.on { opacity: 1; }
.ar-side.mine.on   { border-color: var(--vs-mine); }
.ar-side.theirs.on { border-color: var(--vs-theirs); }
.ar-side:disabled { opacity: 0.2; cursor: default; }

/* The shield: an invisible plate over the board so a real finger can never reach
   it. Playback steps over it with elementsFromPoint. */
.ar-shield { position: absolute; inset: 0; z-index: 3; background: transparent; touch-action: none; }

/* ── one timeline, broken into the match's sections ──────────────────────── */
/* The scrubber rides ON the active part, so position and section read as one. */
.ar-marks { position: absolute; left: 0; right: 0; bottom: 0; height: 3px; z-index: 1; pointer-events: none; }
.ar-time { flex: none; font-size: var(--text-xs); color: var(--mute); }
.ar-pp { flex: none; }


/* ── whose view, in words ────────────────────────────────────────────────────
   Two small avatars cannot tell you which run you are watching. */
.ar-title { color: var(--mute); }
.ar-whose { margin-left: var(--space-3); font-weight: 500; }
.ar-whose.mine   { color: var(--vs-mine); }
.ar-whose.theirs { color: var(--vs-theirs); }

/* ── the transport: two lines, nothing else ──────────────────────────────── */
.ar-bar {
  flex: none; display: flex; flex-direction: column; align-items: stretch;
  gap: var(--space-3); padding-top: var(--space-4);
}

/* Line 1 — the match as chapters, widths proportional to duration. */
.ar-line { position: relative; height: 26px; display: flex; align-items: center; cursor: pointer; touch-action: none; }
.ar-chaps { display: flex; gap: 2px; width: 100%; height: 6px; }
.ar-chap {
  position: relative; min-width: 6px; height: 100%; overflow: hidden;
  background: var(--line-2); border-radius: var(--radius-sm);
  transition: height var(--t);
}
.ar-line:hover .ar-chap, .ar-chap.on { height: 100%; }
.ar-chap-fill { display: block; height: 100%; width: 0; background: var(--accent); }
.ar-chap.on .ar-chap-fill { background: var(--accent); }
.ar-marks { position: absolute; left: 0; right: 0; bottom: 0; height: 3px; pointer-events: none; }

/* Line 2 — every control. */
.ar-ctrls { display: flex; align-items: center; gap: var(--space-4); }
.ar-spacer { flex: 1; }
.ar-time { font-size: var(--text-xs); color: var(--mute); }
.ar-rate { padding: var(--space-2) var(--space-4); font-size: var(--text-xs); }

/* ── gesture feedback ───────────────────────────────────────────────────── */
.ar-skip {
  position: absolute; top: 50%; transform: translateY(-50%);
  padding: var(--space-4) var(--space-6);
  background: var(--surface-2); border-radius: var(--radius);
  font-family: var(--font-mono); font-size: var(--text-lg); color: var(--text);
  pointer-events: none; animation: ar-skip-fade 0.5s var(--ease) forwards; z-index: 4;
}
.ar-skip.back { left: var(--space-7); }
.ar-skip.fwd  { right: var(--space-7); }
@keyframes ar-skip-fade { from { opacity: 0; } 30% { opacity: 1; } to { opacity: 0; } }

/* Held for 2×: say so, or the sudden speed reads as a bug. */
.ar-fast .ar-frame::after {
  content: '2\00D7'; position: absolute; top: var(--space-5); right: var(--space-5); z-index: 4;
  padding: var(--space-2) var(--space-4); border-radius: var(--radius);
  background: var(--surface-2); color: var(--text);
  font-family: var(--font-mono); font-size: var(--text-xs);
}


/* A replay is a recording, not a game. The mounted board still carries its own
   live chrome — restart, the hint/settings row, the mode toggles — which is both
   meaningless here and misleading, since none of it is what the player pressed.
   The board itself stays; only the furniture goes. */
.ar-board .q-chrome, .ar-board .gh-actions, .ar-board .pz-acts,
.ar-board [data-restart], .ar-board [data-settings], .ar-board .icon-btn,
.ar-board .pill { display: none !important; }
