/* stage.css — True Highlights tile-grid player stage (P2). Loaded only behind `?ui=tiles`
 * (docs/design/tile-grid/PLAN.md §1/§3), after tiles.css. Everything here is namespaced
 * `.th-stage…`; the few rules that re-skin a REUSED classic element (`.player-controls`,
 * `.cut-seg-btn`, `.title-note`, `.end-note`, `.up-next`, `.player-date`, `.team-hub-*`) are scoped under
 * `.th-stage` so classic is never touched — mirrors the same light-on-dark treatment
 * `.player-panel.is-fullscreen` already uses in styles.css, because the stage backdrop, like
 * fullscreen, is always dark regardless of the site theme.
 *
 * TOS / spoiler-safety (docs/SPOILER-SAFETY.md): no rule in THIS FILE sets `overflow:hidden`,
 * `border-radius` or an overlay on the frame, or (on any ANCESTOR of `.player-panel`) `transform`,
 * `filter`, `contain` or `clip-path` — any of those would either clip/overlay the YouTube frame
 * (forbidden by YouTube's terms) or break iOS pseudo-fullscreen, which needs every ancestor up to
 * `.th-stage` free of a new containing block. That's a claim about this file, not the frame's
 * total styling: classic's `.player-frame` (styles.css, reused here unmodified) keeps its own
 * pre-existing `overflow:hidden` + 8px `border-radius` — accepted long before the stage existed,
 * and inert either way since the iframe is sized to fill that box exactly (`inset:0`), so nothing
 * of it is actually clipped (Opus-review fix, 2026-09-15 — this comment used to read as though
 * NOTHING clipped the frame anywhere, which wasn't true). The backdrop halves may use
 * transform/clip-path freely because they are siblings of `.st-inner`, never ancestors of the
 * frame; the entrance animation (below) is scoped the same way, to `.st-box`'s children OTHER
 * than `.st-player` — never `.st-player` itself or anything inside it.
 */

html.stage-open { overflow: hidden; scrollbar-gutter: stable; }

.th-stage {
  position: fixed; inset: 0; z-index: 980; /* below .modal-overlay/toasts/install-hint/explorer (1000-1301) */
  overflow-y: auto; overscroll-behavior: contain;
  background: #0c0c0a; color: #f4f1ea;
  -webkit-text-size-adjust: 100%;
}

/* ---------- backdrop: team-colour diagonal halves + watermark crests ---------- */
.st-bg { position: fixed; inset: 0; z-index: -1; background: #0c0c0a; }
.st-half { position: absolute; inset: 0; overflow: hidden; }
.st-half.h { background-color: color-mix(in oklab, var(--hc, #3a372e) 70%, #000); clip-path: polygon(0 0, 58% 0, 42% 100%, 0 100%); }
.st-half.a { background-color: color-mix(in oklab, var(--ac, #3a372e) 70%, #000); clip-path: polygon(calc(58% + 8px) 0, 100% 0, 100% 100%, calc(42% + 8px) 100%); }
.st-wm {
  position: absolute; top: 50%; width: 46vw; height: 84vh; transform: translate(-50%, -50%) rotate(-7deg);
  background-position: center; background-size: contain; background-repeat: no-repeat;
  opacity: .14; filter: grayscale(1) contrast(1.4) blur(1.5px);
}
.st-half.h .st-wm { left: 22%; }
.st-half.a .st-wm { left: 79%; }

/* Fade only, and never on `.st-player` (Opus-review fix, TRU-20): it's an ANCESTOR of the mounted
 * `.player-panel`/iframe, and a safe title's autoplay iframe is created at t=0 — iOS muted
 * autoplay needs it visible from the first frame, not faded in over the next .5s (see the file
 * header, and docs/SPOILER-SAFETY.md / PLAN §7 "iOS"). The old rule animated `.st-box` itself,
 * which animated the player right along with everything else; these are `.st-box`'s OTHER
 * children — every part of the stage chrome except the player mount. */
.th-stage.th-enter .st-top,
.th-stage.th-enter .st-meta,
.th-stage.th-enter .st-next,
.th-stage.th-enter .st-squads { animation: th-st-rise .5s .1s ease both; }
@keyframes th-st-rise { from { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .th-stage.th-enter .st-top,
  .th-stage.th-enter .st-meta,
  .th-stage.th-enter .st-next,
  .th-stage.th-enter .st-squads { animation: none; }
}

/* The pinned footer (tiles.css) sits above the stage at every width, so the stage's own content
 * has to be able to scroll out from under it. */
.st-inner { position: relative; min-height: 100%; padding: clamp(14px, 4vh, 44px) clamp(12px, 4vw, 56px) calc(40px + var(--th-foot-h, 0px)); }
/* grid-template-columns is explicit (minmax(0,1fr), not the implicit auto-sized single column a
 * bare `display:grid` would create) so the track itself is capped at the available width — an
 * `auto` track sizes to CONTENT first and only THEN yields, which let the reused classic
 * `.player-controls` (flex-wrap:wrap) push every row (and the whole stage) wider than the
 * viewport at narrow widths before it ever got a box narrow enough to wrap into. Sizing only. */
/* Width is set by the HEIGHT that's free, not a fixed cap (owner, 2026-09-15: "if the stage is
 * full viewport width then we don't need theater mode toggle" — so no toggle; the stage simply
 * takes what the viewport can give). The old flat `min(1080px, 100%)` was both too narrow on a
 * large monitor and too WIDE on a short one: measured at 1024x768 the controls ran 9px behind the
 * pinned footer. 255px is the chrome this has to clear — the stage's top padding and title block
 * (~106), the gap and controls row (~70), the pinned footer (63) and a little slack — so the 16:9
 * frame plus everything under it always lands inside the viewport. The 520px floor keeps a very
 * short window from collapsing the box, and min(100%) means phones stay full-bleed exactly as
 * before. */
.st-box {
  position: relative;
  width: min(100%, max(520px, calc((100vh - 255px) * 16 / 9)));
  width: min(100%, max(520px, calc((100dvh - 255px) * 16 / 9)));
  margin-inline: auto; display: grid; grid-template-columns: minmax(0, 1fr); gap: 14px;
}

/* ---------- header: back control (leading), competition/round line + title (trailing) ---------- */
/* Owner request 2026-09-15: the back arrow sits top-left and the label block is right-aligned
 * against it, so the header reads the way a phone screen does — leading control, trailing title —
 * at every width instead of only on desktop. The button is FIRST in the DOM too, so it's also the
 * first thing the focus trap lands on. */
.st-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.st-label { min-width: 0; margin-left: auto; text-align: right; }
.st-comp { display: block; font: 600 12px/1.3 var(--label, inherit); letter-spacing: .1em; text-transform: uppercase; color: rgba(244, 241, 234, .78); }
.st-title { margin: 6px 0 0; font-size: clamp(20px, 3vw, 32px); line-height: 1.08; font-weight: 700; letter-spacing: .01em; color: #fff; }
.st-title i { font-style: normal; opacity: .55; padding-inline: .18em; font-weight: 500; }
.st-back {
  flex: none; width: 44px; height: 44px; display: grid; place-items: center;
  border: 0; border-radius: 50%; background: rgba(0, 0, 0, .42); color: #f4f1ea; cursor: pointer;
}
.st-back:hover { background: rgba(0, 0, 0, .66); }
/* The chevron's own mass sits right of its centre, so nudge it back to look optically centred. */
.st-back svg { width: 20px; height: 20px; margin-right: 2px; }

/* ---------- player mount: app.js appends the real .player-panel here, unmodified ---------- */
/* min-width:0 defeats CSS Grid's automatic minimum size: `.st-box` is a grid container, and a
 * grid item's default auto-min-width is its content's MIN-CONTENT size — which for the reused
 * classic `.player-controls` (flex-wrap:wrap) is small on its own, but without this the grid item
 * itself refuses to shrink below it, so the wrap never gets a narrow enough box to trigger and
 * the whole row (and the stage) overflows horizontally. Sizing only — no overflow/transform on
 * anything upstream of the frame, so this doesn't touch the pseudo-fullscreen containing-block
 * rule (docs/SPOILER-SAFETY.md). Measured: 390px and 280px both wrap cleanly with this in place. */
.st-player { min-width: 0; }
/* The stage is a dark surface in EVERY theme — .th-stage paints #0c0c0a and the backdrop puts the
 * team colours over black — and the reused classic controls further down this file are re-skinned
 * light-on-dark to match it. The classic panel brings its own `background: var(--card)` and accent
 * border, which in the LIGHT theme is paper: that is what put near-white controls on a near-white
 * slab (owner, 2026-09-15, "what happened to the player control?"). Inside the stage the panel is
 * only a container for the frame and the controls row, so it keeps none of its own chrome, and
 * `color` is pinned so anything inheriting it (the time readouts) stays legible on the backdrop.
 * Fullscreen and the mini player are separate surfaces that paint their own backgrounds — both are
 * excluded here rather than having this rule out-specify them. */
.st-player .player-panel:not(.is-fullscreen):not(.mini) {
  margin: 0; padding: 0; background: none; border: 0; border-radius: 0; color: #f4f1ea;
}
/* …and it must not keep the CLASSIC wide-player sizing. From 1000px up, styles.css gives the
 * inline panel `width: var(--player-wide-w); left: 50%; margin-left: -half` to let an open card
 * grow past the 780px column — a viewport-centering trick that makes the panel ignore whatever
 * box it's in. Inside the stage that meant the frame escaped `.st-box` entirely: measured 960px
 * of frame in a 912px box at 1024x768, and 1180px of frame in a 649px box at 1280x620, with the
 * controls landing behind the pinned footer. The selector has to out-specify that rule's four
 * :not()s, hence the three here on top of two classes. */
.th-stage .st-player .player-panel:not(.is-fullscreen):not(.mini):not(.is-pseudo-fs) {
  width: auto; left: auto; margin-left: 0;
}
/* .player-date is redundant in the stage — round/date live in .st-comp instead (PLAN §3). */
.th-stage .player-date { display: none; }

/* ---------- meta row: queue toggle (stage.js) + cut chooser (app.js's buildCutChooser renders
   into #th-st-meta) + hint ---------- */
.st-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 16px; }
/* With the add-to-queue control gated out of the UI (stage.js QUEUE_BTN_IN_UI, owner 2026-09-16)
   this row is empty for any match with a single cut, and an empty flex box still takes a slot in
   its parent's gap. Collapse it until app.js appends a cut chooser into it. */
.st-meta:empty { display: none; }
.st-meta .cut-seg { flex-basis: auto; margin-top: 0; }
.st-hint { font-size: 13px; line-height: 1.3; color: rgba(244, 241, 234, .68); }
/* "Add to queue" (PLAN.md §8 Q1, owner 2026-09-15) — same dark-translucent/accent-on-toggle
   treatment as the reused `.ctrl`/`.cut-seg-btn` further down this file, so it reads as one
   family of stage controls rather than a one-off. Text label, not just an icon, per the brief
   ("Add to queue" / "In queue") — this is the ONLY place a match can be queued (never a tile). */
.st-queue-btn {
  display: inline-flex; align-items: center; gap: 6px;
  height: 34px; padding: 0 14px; border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, .22); background: rgba(255, 255, 255, .08); color: #f4f1ea;
  font: 600 12.5px/1 var(--label, inherit); letter-spacing: .02em; cursor: pointer;
}
.st-queue-btn:hover { background: rgba(255, 255, 255, .16); border-color: rgba(255, 255, 255, .34); }
.st-queue-btn.on { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
.st-queue-icon { font-weight: 700; }

/* ---------- up next ---------- */
.st-next h3 { margin: 0 0 2px; font: 600 12px/1 var(--label, inherit); letter-spacing: .12em; text-transform: uppercase; color: rgba(244, 241, 234, .8); }
.st-next-list { list-style: none; margin: 0; padding: 2px 2px 8px; display: flex; gap: 10px; overflow-x: auto; scrollbar-width: thin; }
.st-next-list li { flex: none; }
.st-next-list .th-tile { --th-tw: 128px; --th-th: 64px; --th-tile: #2a2923; }

/* ---------- squads: renderTeamHubLinks() renders directly into #th-st-squads ---------- */
.st-squads .team-hub-section { margin-top: 0; }
/* Same fix as `.st-box` above, scoped to this container only: styles.css's `.team-hub-rosters`
 * (classic, unedited) is `grid-template-columns:1fr 1fr` with no minmax floor, so at very narrow
 * widths a long player/team name can push this SECOND grid past the stage's own edge exactly the
 * way `.player-controls` did before the `.st-box` fix. */
.st-squads .team-hub-rosters { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
.st-squads .team-hub-section-label,
.st-squads .team-hub-roster-heading,
.st-squads .team-hub-roster-player,
.st-squads .team-hub-roster-num,
.st-squads .team-hub-roster-empty { color: rgba(244, 241, 234, .86); }
.st-squads .team-hub-roster-heading:hover,
.st-squads .team-hub-roster-heading:focus-visible,
.st-squads .team-hub-roster-player:hover,
.st-squads .team-hub-roster-player:focus-visible { color: #fff; }
.st-squads .team-hub-roster-num,
.st-squads .team-hub-roster-empty { color: rgba(244, 241, 234, .55); }

/* Keep a full screen of spare room under the content while a protected video is scrolled up —
 * ensureScrollRoom (app.js) sizes this; the floor guarantees it can never be clamped short of the
 * crop target however the content above reflows (late fonts, a narrow phone). Not an overlay. */
.st-room { height: 0; }

/* ---------- reused classic controls, re-skinned dark (mirrors .player-panel.is-fullscreen) ---------- */
/* The stage's backdrop is two saturated team colours, and the controls' own translucent white
 * fill had to fight whatever those clubs happen to be — the row read as ghost buttons on a red and
 * blue field (owner, 2026-09-15: "give the player controls their own background opacity so the
 * buttons show nicely"). One dark plate behind the whole row gives every control the same ground
 * no matter the fixture. It's a SIBLING of `.player-frame`, never an ancestor, so it can't create
 * a containing block for the frame (see this file's header) and it paints nothing over the video.
 * Fullscreen keeps its own gradient scrim — that rule out-specifies this one. */
.th-stage .player-controls {
  padding: 8px 10px;
  border: 1px solid rgba(255, 255, 255, .08);
  border-radius: 12px;
  background: rgba(10, 10, 8, .55);
}
.th-stage .ctrl {
  background: rgba(255, 255, 255, .08); color: #f4f1ea; border-color: rgba(255, 255, 255, .18);
}
.th-stage .ctrl:hover { background: rgba(255, 255, 255, .16); border-color: rgba(255, 255, 255, .3); }
/* The sound control belongs with pp/cc-on, not with the outlined rest: this file's `.th-stage
 * .ctrl` re-skin has the same specificity as `.ctrl.sound-pill` and loads later, so without this
 * it quietly lost its accent fill in the stage and read as an ordinary button. */
.th-stage .ctrl.pp,
.th-stage .ctrl.sound-pill,
.th-stage .ctrl.cc.on { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
.th-stage .time { color: rgba(244, 241, 234, .8); }
.th-stage .seek { background: rgba(255, 255, 255, .22); }
.th-stage .cut-seg-btn {
  background: rgba(255, 255, 255, .1); color: #ddd; border-color: rgba(255, 255, 255, .2);
}
.th-stage .cut-seg-btn:hover { background: rgba(255, 255, 255, .18); color: #fff; border-color: rgba(255, 255, 255, .32); }
.th-stage .cut-seg-btn.on { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
.th-stage .title-note { background: rgba(0, 0, 0, .5); color: rgba(244, 241, 234, .92); border-color: #ffb199; box-shadow: inset 3px 0 0 #ffb199; }
.th-stage .end-note { background: rgba(255, 255, 255, .1); color: #f4f1ea; }
/* The classic watch-queue's own auto-advance strip (app.js's queueShowUpNext/queueUpNextPlace,
   reused as-is per PLAN §8 Q1) now reaches the stage too — it inserts itself in-flow right after
   `.player-controls`/`.end-note`, same as classic, so Constraint 1 (nothing over the frame) holds
   unchanged. Its base rule paints `var(--card2)`/`var(--ink)`, which in the LIGHT theme is a pale
   card — the same near-invisible-on-dark problem `.player-panel` itself had (see that fix above).
   NOT `.up-next-inbar` (fullscreen) — that variant already pins its own dark colours inline in
   styles.css regardless of theme, so it needs no help here. */
.th-stage .up-next { background: rgba(255, 255, 255, .1); color: #f4f1ea; }
.th-stage .up-next-count { color: rgba(244, 241, 234, .7); }

/* Mini and theater are dropped in the stage — the stage is already full size, and a fixed mini
 * has no page scroll to crop the title strip with (PLAN §3). Hidden, never disabled, so Tab skips
 * them without any extra focus-trap bookkeeping. */
.th-stage .theater,
.th-stage .mini-placeholder { display: none; }

/* While the mounted panel is fullscreen, the stage's own chrome (Squads/cuts/Up next) sits behind
 * the fullscreen top-layer/pseudo-fs overlay either way — also drop it from the tab order. Purely
 * a focus/tidiness concern, never a spoiler-safety one (§3, "Fullscreen"). */
.th-stage:has(.player-panel.is-fullscreen) .st-meta,
.th-stage:has(.player-panel.is-fullscreen) .st-next,
.th-stage:has(.player-panel.is-fullscreen) .st-squads { display: none; }

@media (max-width: 680px) {
  .st-inner { padding: 10px 10px calc(28px + var(--th-foot-h, 0px)); }
  .st-hint { display: none; }
  .st-back { width: 40px; height: 40px; }
}
@media (max-width: 340px) {
  .st-box { gap: 10px; }
}

/* ---------- classic watch-queue pill, reused as-is in tiles mode (PLAN §8 Q1) ----------
   The pill/sheet are styles.css's own — untouched, not this file's to restyle — but their bottom
   offset is `calc(16px + var(--utilbar-h, 52px) + …)`, keyed to the CLASSIC fixed footer's live-
   measured height. `html[data-ui="tiles"] .site-footer{display:none}` (tiles.css) means that
   measurement (wireUtilBar) reads 0 there, so the pill collapses to ~16px above the true viewport
   bottom — UNDER tiles' own pinned footer (`.th-foot`, tiles.css, z-index 990, opaque, its real
   height published as `--th-foot-h`), not clear of it. Two fixed-bottom bars at the same z-index
   ordering don't matter here since they don't need to OVERLAP at all — clearing `.th-foot`'s own
   height puts the pill above it with room to spare, the same way every other fixed-bottom element
   in this codebase (`.a2hs-hint`, the mini player) clears whatever bar is under IT. z-index is
   untouched on purpose: the pill still sits below the stage (980) while a match plays full-screen
   — the in-stage "Add to queue" toggle above is the queue entry point there, and re-appearing atop
   an already-full stage would be one more thing to Tab past for no reason. Scoped here (not
   tiles.css, which is claimed by another lane right now) per this file's own `html[data-ui="tiles"]`
   allowance for the pill. */
html[data-ui="tiles"] .queue-pill {
  bottom: calc(16px + var(--th-foot-h, 0px) + env(safe-area-inset-bottom, 0px));
}
