/* ------------------------------------------------------------------------------------------------
   Qualifying broadcast: one machine, for a stream overlay.

   The page's home is an OBS browser source — a panel a few hundred pixels tall in a corner of the
   stream layout, read off a viewer's screen at whatever size the stream lands on. So two things drive
   everything below. Nothing scrolls: the page is one screen, and broadcast.js trims the ladder to
   whatever height there is. And the type is big and sized to the window, not to a phone: the previous
   arrangement put the whole queue board in that panel, and its 14px rows were too small to read on
   the stream.

   Same tokens and row tints as the board (styles.css), restated rather than shared so the two
   stylesheets stay independent — this one is a different shape of page, not a theme of the other.
   ------------------------------------------------------------------------------------------------ */

:root {
  color-scheme: light dark;
  --bg: #ffffff;
  --text: #111827;
  --border: #d0d0d8;
  --muted: #6b7280;
  --warning: #b45309;
  --on-game: #059669;
  --panel-bg: rgba(127, 127, 127, 0.07);
  --mine-bg: rgba(5, 150, 105, 0.12);
  --queue-0: rgba(245, 158, 11, 0.18);
  --queue-1: rgba(139, 92, 246, 0.16);
  --queue-2: rgba(16, 185, 129, 0.16);
  --queue-3: rgba(244, 114, 182, 0.16);
}

/* Dark by default — broadcast.js stamps <html data-theme="dark"> unless the URL says ?theme=light —
   because the page's home is OBS's browser, which can't state a colour-scheme preference and would
   render light, on a stream layout that is dark. The preference block below is for a page opened in
   an ordinary browser with no data-theme at all. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #0f1117;
    --text: #f3f4f6;
    --border: #3f3f46;
    --muted: #9ca3af;
    --warning: #fbbf24;
    --on-game: #34d399;
    --panel-bg: rgba(255, 255, 255, 0.06);
    --mine-bg: rgba(52, 211, 153, 0.18);
    --queue-0: rgba(251, 191, 36, 0.30);
    --queue-1: rgba(167, 139, 250, 0.30);
    --queue-2: rgba(52, 211, 153, 0.28);
    --queue-3: rgba(244, 114, 182, 0.30);
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --bg: #0f1117;
  --text: #f3f4f6;
  --border: #3f3f46;
  --muted: #9ca3af;
  --warning: #fbbf24;
  --on-game: #34d399;
  --panel-bg: rgba(255, 255, 255, 0.06);
  --mine-bg: rgba(52, 211, 153, 0.18);
  --queue-0: rgba(251, 191, 36, 0.30);
  --queue-1: rgba(167, 139, 250, 0.30);
  --queue-2: rgba(52, 211, 153, 0.28);
  --queue-3: rgba(244, 114, 182, 0.30);
}

:root[data-theme="light"] {
  color-scheme: light;
}

/* One knob for every size on the page. Width AND height, taking the smaller: the panel is usually
   wide and short, and a size picked from width alone would run off the bottom. At a 680x270 source
   this lands around 19px, which puts the player's name near 35px and the rows near 19px. The width
   term is set by the ladder rows — a name beside a thirteen-character score — and the height term by
   the left column's stack: machine, name, time, two up next, and a two-game ladder is what a 270px
   window just holds. */
html {
  font-size: clamp(13px, min(2.85vw, 7.6vh), 44px);
}

body {
  font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
  margin: 0;
  /* A little more above than below: the top edge is the one the stream layout crops closest to. */
  padding: 0.6rem 0.6rem 0.35rem;
  background: var(--bg);
  color: var(--text);
  line-height: 1.25;
  /* Nothing scrolls, by design: the page fits itself to the window (see fitStage in broadcast.js). */
  overflow: hidden;
  height: 100vh;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
}

/* The stage, the picker and the chip all set their own display, which would otherwise beat the
   hidden attribute's UA rule; broadcast.js toggles visibility through that attribute. */
[hidden] { display: none !important; }

/* ---- Header ------------------------------------------------------------------------------------ */

.top {
  grid-area: head;
  min-width: 0;
}

/* Shrunk to fit a long machine name by fitText (broadcast.js), like the player's name below it.

   This and every other one-line text below clips sideways only ("clip visible"), not "hidden": the
   line boxes are tight (1.15–1.25) and Segoe UI's descenders reach below them, so a hidden overflow
   took the bottom off every y and g. The ellipsis only needs the inline axis clipped, and a descender
   painting a few pixels into the row gap beneath is fine. */
h1 {
  font-size: 1.4rem;
  font-weight: 700;
  line-height: 1.15;
  margin: 0;
  white-space: nowrap;
  overflow: clip visible;
  text-overflow: ellipsis;
  min-width: 0;
}

/* The "Updated …" clock and its controls, on the top-scores heading line. */
.status {
  margin: 0;
  color: var(--muted);
  font-size: 0.8rem;
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  flex: none;
}

/* The status dot, as on the board: pulses on each read, pauses the feed when clicked. */
.snapshot-status {
  font: inherit;
  color: var(--muted);
  background: transparent;
  border: 0;
  padding: 0 0 0 0.45rem;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}

.snapshot-dot {
  width: 0.55rem;
  height: 0.55rem;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.35;
}

.snapshot-status.pulse .snapshot-dot { animation: snapshot-pulse 0.9s ease-out; }

@keyframes snapshot-pulse {
  0% { opacity: 1; transform: scale(1.6); }
  100% { opacity: 0.35; transform: scale(1); }
}

.snapshot-status[aria-pressed="true"] .snapshot-dot { opacity: 1; }

/* The machine picker's button: the same size and colour as the dot, so it reads as part of the status
   line rather than as a control the stream's viewers are meant to notice. Big enough to hit in OBS's
   interact window all the same — the padding is the target, the icon is the hint. */
.pick-arena {
  font: inherit;
  color: var(--muted);
  background: transparent;
  border: 0;
  padding: 0.15rem 0 0.15rem 0.55rem;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
}

.pick-arena svg {
  width: 0.8rem;
  height: 0.8rem;
  fill: currentColor;
  opacity: 0.55;
}

.pick-arena:hover svg,
.pick-arena:focus-visible svg { opacity: 1; }

/* The status line is chrome — hidden unless the page was asked for it (?chrome=1), and shown while
   the pointer is moving, which is the operator in OBS's interact window. broadcast.js sets both
   attributes. */
:root[data-chrome="0"] .status {
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s;
}

:root[data-chrome="0"][data-pointer="active"] .status {
  opacity: 1;
  pointer-events: auto;
}

@media (prefers-reduced-motion: reduce) {
  .snapshot-status.pulse .snapshot-dot { animation: none; }
}

/* ---- The view ---------------------------------------------------------------------------------- */

/* Two columns: the player's column on the left, the top-scores ladder on the right with the whole
   height. The right column is the wider, since its rows carry a name AND a score and the name is
   what gives way; the left column's lines are shorter. The player's own ladder takes whatever height
   the lines above it leave; the top ladder clips, and fitStage trims it to what fits. */
.stage {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.3fr);
  grid-template-rows: auto auto auto minmax(0, 1fr);
  grid-template-areas:
    "head top"
    "now  top"
    "next top"
    "mine top";
  column-gap: 0.7rem;
  row-gap: 0.2rem;
  flex: 1;
  min-height: 0;
}

/* A tall, narrow source stacks everything instead. */
@media (max-aspect-ratio: 5/4) {
  .stage {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto auto auto auto minmax(0, 1fr);
    grid-template-areas: "head" "now" "next" "mine" "top";
  }
}

.now { grid-area: now; }
.next { grid-area: next; }
.panel.own-games { grid-area: mine; }
.panel.top-scores { grid-area: top; }

.now-line {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  min-width: 0;
}

.now-marker {
  color: var(--on-game);
  font-size: 1.2rem;
  flex: none;
}

/* The biggest thing on the page: the name a viewer came to read. A name too long for the column is
   shrunk to fit by fitText (broadcast.js) rather than cut short, and only ellipsizes past its floor. */
.now-name {
  font-size: 1.8rem;
  font-weight: 700;
  line-height: 1.15;
  white-space: nowrap;
  overflow: clip visible;
  text-overflow: ellipsis;
  min-width: 0;
}

/* Nobody on the machine: "Machine is free", "Queue is empty", "Blocked for repair". */
.now-name.idle {
  font-weight: 500;
  color: var(--muted);
}

/* Under the name, on one line: the column is narrow and the name's indent is width this line needs. */
.now-time {
  font-size: 0.92rem;
  color: var(--muted);
  white-space: nowrap;
  overflow: clip visible;
  text-overflow: ellipsis;
}

/* The queue label, tinted like the board's rows so a two-tournament stream still says whose turn it is. */
.chip {
  font-size: 0.75rem;
  font-weight: 600;
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  white-space: nowrap;
  flex: none;
}

[data-queue="0"] { background: var(--queue-0); }
[data-queue="1"] { background: var(--queue-1); }
[data-queue="2"] { background: var(--queue-2); }
[data-queue="3"] { background: var(--queue-3); }

/* The label beside the first name, the second name under the first: the column is too narrow for
   two names on one line, and has the height to spare. */
.next {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  font-size: 0.95rem;
  min-width: 0;
}

.label {
  color: var(--muted);
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  flex: none;
}

.next-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0;
  min-width: 0;
  overflow: clip visible;
}

.next-list li {
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
  white-space: nowrap;
  min-width: 0;
}

.next-list .position {
  color: var(--muted);
  font-weight: 600;
}

.next-list .name {
  font-weight: 600;
  overflow: clip visible;
  text-overflow: ellipsis;
}

.next-list .waited {
  color: var(--muted);
  font-size: 0.8rem;
}

.next-list .nobody {
  color: var(--muted);
}

/* ---- The two ladders ---------------------------------------------------------------------------- */

.panel {
  background: var(--panel-bg);
  border-radius: 0.5rem;
  padding: 0.25rem 0.4rem 0.3rem;
  min-width: 0;
  min-height: 0;
  /* Clipped both ways, unlike the one-line texts: rows that run past the panel (a source shorter
     than the fitter was given, an OBS scale) must stop at its rounded bottom edge, not paint over it. */
  overflow: clip;
}

h2 {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin: 0 0 0.1rem;
  white-space: nowrap;
  overflow: clip visible;
  text-overflow: ellipsis;
  min-width: 0;
}

/* The top-scores heading with the status clock at its right end; the heading is what gives way. */
.panel-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
}

.rows {
  display: flex;
  flex-direction: column;
}

/* rank | name | score | points, the score right-aligned so a column of them compares at a glance.
   The name column is the one that gives way. */
.row {
  display: grid;
  grid-template-columns: 1.4rem minmax(0, 1fr) auto auto;
  align-items: baseline;
  gap: 0 0.3rem;
  font-size: 1rem;
  padding: 0.06rem 0.15rem;
  border-radius: 0.3rem;
  line-height: 1.25;
}

/* The player on the machine's own rows on the top-scores ladder, and every row on their own ladder. */
.row.mine { background: var(--mine-bg); }

.row .rank {
  color: var(--muted);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.row .name {
  white-space: nowrap;
  overflow: clip visible;
  text-overflow: ellipsis;
}

.row .score {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.row .points {
  color: var(--muted);
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
  text-align: right;
}

/* The tint sits on the rank cell rather than the whole row so it doesn't fight the "mine" highlight. */
.row .rank[data-queue] {
  border-radius: 0.25rem;
  text-align: center;
  padding: 0 0.2rem;
}

/* The player's own ladder ranks read "#3", which wants its own width rather than the top ladder's
   two-digit column; the "of 24" beside it is context, in the small print's size and colour. */
.rows.own .row { grid-template-columns: auto minmax(0, 1fr) auto auto; }

.rows.own .row .name {
  color: var(--muted);
  font-size: 0.85rem;
}

.rows .none {
  color: var(--muted);
  font-size: 0.95rem;
  padding: 0.1rem 0.25rem;
}

/* ---- The picker -------------------------------------------------------------------------------- */

.picker {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.picker-hint {
  margin: 0;
  color: var(--muted);
  font-size: 0.95rem;
}

/* Every machine on one screen: as many columns as fit, each button tall enough to hit from OBS's
   interact window and no taller. Scrolls only on a board with more machines than the window has room
   for, which is the one place the page allows it. */
.picker-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
  gap: 0.35rem;
  overflow-y: auto;
  min-height: 0;
  align-content: start;
}

.arena-button {
  font: inherit;
  font-size: 0.95rem;
  font-weight: 600;
  color: inherit;
  background: var(--panel-bg);
  border: 1px solid var(--border);
  border-radius: 0.45rem;
  padding: 0.3rem 0.6rem 0.35rem;
  text-align: left;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  gap: 0.05rem;
  min-width: 0;
  line-height: 1.2;
}

.arena-button:hover,
.arena-button:focus-visible { border-color: var(--text); }

.arena-button[aria-selected="true"] { border-color: var(--on-game); box-shadow: inset 0 0 0 1px var(--on-game); }

/* The name wraps rather than truncating: the operator picking a machine needs the whole name, and a
   line more on a button costs nothing here. overflow-wrap covers a name with no space to break at,
   and the clip on the button is the backstop should a browser disagree about any of it. */
.arena-button {
  overflow: hidden;
}

.arena-button .arena-label {
  white-space: normal;
  overflow-wrap: anywhere;
  min-width: 0;
  max-width: 100%;
}

.arena-button .arena-count {
  color: var(--muted);
  font-size: 0.8rem;
  font-weight: 500;
  flex: none;
}

.picker-foot {
  display: flex;
  gap: 0.4rem;
  flex: none;
}

.pill {
  font: inherit;
  font-size: 0.85rem;
  color: inherit;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 0.25rem 0.8rem;
  cursor: pointer;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  line-height: 1.2;
}

.pill:hover,
.pill:focus-visible { border-color: var(--text); }

.warning {
  margin: 0.2rem 0 0;
  color: var(--warning);
  font-size: 0.85rem;
}
