/*
 * Dial It In.
 *
 * Deliberately not sharing feud.css. That sheet is built around a board that is
 * a grid of answer cards on a laptop screen in a meeting; this one is built
 * around a single horizontal bar that has to be legible on a phone held at
 * arm's length, on a projector at the back of a room, and inside a 1080x1920
 * video frame with a streamer's camera over one corner of it. The two sets of
 * constraints disagree often enough that one sheet serving both would be a
 * sheet of exceptions.
 *
 * Everything sizes off --unit, which the board sets from the viewport. That is
 * what lets the same markup be a phone page, a projector slide and a vertical
 * video frame without a second layout.
 */

:root {
  --unit: 1vw;
  --bg: #0b1020;
  --panel: #151c33;
  --ink: #f2f5ff;
  --dim: #97a3c4;
  --line: #2a3556;
  --cold: #3aa0ff;
  --warm: #ff7a3d;
  --hit: #ffd23f;
  --good: #38d39f;
  --bad: #ff5d73;
  --crowd: #c07dff;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  -webkit-text-size-adjust: 100%;
}

/* OBS browser sources composite over the scene, so a transparent page lets the
   board sit on top of a camera or a background loop instead of covering it.
   The panels keep a translucent fill of their own -- text over live video is
   unreadable without something behind it. */
body.transparent { background: transparent; }
body.transparent .panel { background: rgba(21, 28, 51, 0.82); }

h1, h2, h3 { margin: 0 0 0.4em; line-height: 1.1; font-weight: 800; }
p { margin: 0 0 0.6em; line-height: 1.45; }
a { color: var(--cold); text-decoration: none; }
a:hover { text-decoration: underline; }

.wrap {
  max-width: 720px;
  margin: 0 auto;
  padding: 20px 16px 48px;
}

.panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 16px;
  margin: 0 0 14px;
}

.hint { color: var(--dim); font-size: 14px; }
.err { color: var(--bad); font-weight: 700; }
.ok { color: var(--good); font-weight: 700; }

label { display: block; font-size: 13px; color: var(--dim); margin: 10px 0 4px; text-transform: uppercase; letter-spacing: 0.06em; }

input[type="text"], input[type="password"], input[type="number"], select {
  width: 100%;
  font: inherit;
  font-size: 17px;               /* 16px or larger, or iOS zooms the page on focus */
  padding: 12px;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: #0e1428;
  color: var(--ink);
}

button {
  font: inherit;
  font-weight: 700;
  font-size: 16px;
  padding: 13px 16px;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: #222d4f;
  color: var(--ink);
  cursor: pointer;
  min-height: 46px;              /* thumb-sized; the host is on a phone too */
}
button:hover { background: #2b3860; }
button:disabled { opacity: 0.4; cursor: default; }
button.primary { background: var(--cold); border-color: var(--cold); color: #04101f; }
button.warn { background: var(--warm); border-color: var(--warm); color: #1c0a02; }
button.ghost { background: transparent; }

/* The phone's mute. Small on purpose: it is an escape hatch, not a control, and
   it sits directly above the clue, which is what the eye should land on. The
   override is because .row stretches its children and this one must not grow to
   the width of the panel. */
button.soundtoggle {
  flex: 0 0 auto;
  font-size: 13px;
  font-weight: 700;
  padding: 6px 12px;
  min-height: 0;
  color: var(--dim);
}
button.soundtoggle:hover { background: transparent; color: var(--ink); }

.row { display: flex; gap: 8px; flex-wrap: wrap; }
.row > * { flex: 1 1 140px; }

/* ------------------------------------------------------------------ dial */

/* The meter itself. One element, sized in --unit, reused at every scale:
   the phone's draggable dial, the board's swarm chart and the reveal are all
   this bar with different children on top of it. */
.dial {
  position: relative;
  height: calc(var(--unit) * 7);
  min-height: 54px;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--cold), #6d7bd6 45%, var(--warm));
  margin: 10px 0;
}

.dial .tick {
  position: absolute;
  top: -6px;
  bottom: -6px;
  width: 3px;
  margin-left: -1.5px;
  background: rgba(255, 255, 255, 0.25);
  border-radius: 2px;
}

/* Where the player's own dial sits. Wide enough to be grabbable with a thumb
   and tall enough to read over the swarm behind it. */
.dial .me {
  position: absolute;
  top: -10px;
  bottom: -10px;
  width: calc(var(--unit) * 1.2);
  min-width: 10px;
  margin-left: calc(var(--unit) * -0.6);
  background: var(--ink);
  border-radius: 6px;
  box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.45);
}

.dial .target {
  position: absolute;
  top: calc(var(--unit) * -2.2);
  bottom: calc(var(--unit) * -2.2);
  width: calc(var(--unit) * 0.9);
  min-width: 8px;
  margin-left: calc(var(--unit) * -0.45);
  background: var(--hit);
  border-radius: 4px;
  box-shadow: 0 0 calc(var(--unit) * 1.4) var(--hit);
}

.dial .crowd {
  position: absolute;
  top: -10px;
  bottom: -10px;
  width: calc(var(--unit) * 0.8);
  min-width: 7px;
  margin-left: calc(var(--unit) * -0.4);
  background: var(--crowd);
  border-radius: 4px;
}

/* The scoring rings, drawn only at the reveal. Painting them earlier would
   hand the target away -- their centre is the answer. */
.dial .band {
  position: absolute;
  top: 0; bottom: 0;
  background: rgba(255, 210, 63, 0.16);
  border-left: 1px solid rgba(255, 210, 63, 0.45);
  border-right: 1px solid rgba(255, 210, 63, 0.45);
}

.ends {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  font-weight: 800;
  color: var(--ink);
  /* The target marker overhangs the dial at both ends. On the host page the
     labels sit above it, so they need clearance or the glow lands on the word. */
  margin-bottom: 20px;
}
.ends span { max-width: 45%; }
.ends span:last-child { text-align: right; }

/* --------------------------------------------------------------- the swarm */

/* One column per whole percent. Fixed at 101 columns whether twelve people are
   playing or twelve thousand, which is what keeps the board's cost flat. */
.swarm {
  display: flex;
  align-items: flex-end;
  gap: 1px;
  height: calc(var(--unit) * 10);
  min-height: 60px;
  margin-bottom: 2px;
}
.swarm i {
  flex: 1 1 0;
  min-width: 0;
  background: var(--good);
  border-radius: 2px 2px 0 0;
  transition: height 220ms ease-out;
  display: block;
}

/* ------------------------------------------------------------------ board */

.board {
  --unit: 1.1vw;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: calc(var(--unit) * 1.6);
  padding: calc(var(--unit) * 3);
}

.board .clue {
  font-size: calc(var(--unit) * 5.4);
  font-weight: 900;
  text-align: center;
  line-height: 1.12;
  text-wrap: balance;
}
.board .ends { font-size: calc(var(--unit) * 2.4); }
.board .meta {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: calc(var(--unit) * 2);
  font-size: calc(var(--unit) * 1.9);
  color: var(--dim);
}
.board .clock {
  font-variant-numeric: tabular-nums;
  font-weight: 900;
  font-size: calc(var(--unit) * 4.6);
  color: var(--ink);
}
.board .clock.low { color: var(--bad); }
.board .dial { height: calc(var(--unit) * 6); }
.board .swarm { height: calc(var(--unit) * 14); }

/* The join card. Big enough to read off a projector from the back row and off a
   phone screen watching a stream, which is the smaller of the two. */
.joinbox {
  text-align: center;
  font-size: calc(var(--unit) * 2.4);
}
/* The address is the one thing on this card that has to be readable, and its
   length is not ours to choose -- it is whatever host the game is deployed
   behind. So it is capped against the viewport as well as the unit, and allowed
   to wrap rather than run off the side of the screen. */
.joinbox .code {
  font-size: min(calc(var(--unit) * 4), 6vw);
  font-weight: 900;
  letter-spacing: 0.03em;
  line-height: 1.15;
}
/* The code is drawn as SVG, so it is resolution-independent: the same markup
   is crisp on a 1080-wide capture and on a projector. The white padding around
   it is the quiet zone -- a QR pressed up against a dark panel does not scan,
   and this board is mostly dark. */
.joinbox .qr {
  width: min(calc(var(--unit) * 20), 38vw);
  margin: calc(var(--unit) * 1.2) auto 0;
}
.joinbox .qr svg { display: block; width: 100%; height: auto; border-radius: 8px; }

/* The always-on join line. Quiet enough to ignore while the round is the point,
   legible enough to type from a phone held at arm's length. */
.joinstrip {
  margin-top: auto;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(var(--unit) * 1.2);
  text-align: center;
  font-size: min(calc(var(--unit) * 1.9), 3vw);
  color: var(--dim);
  letter-spacing: 0.02em;
}
.joinstrip b { color: var(--ink); letter-spacing: 0.08em; }

/* The board's sound toggle.
 *
 * Fixed and small, and the only thing on this page that is not the round. It
 * cannot be sized in --unit like everything else: --unit follows the viewport so
 * that a projector and a 1080x1920 frame get the same layout, and a control that
 * has to stay clickable wants a size in pixels rather than one that shrinks with
 * the frame it is composited into.
 *
 * It fades back once sound is on, rather than disappearing. Disappearing would
 * mean a host who wants silence -- an ad break, someone talking over the stream
 * -- has nothing to press; at this opacity it is out of the way of the shot and
 * still findable by anyone who goes looking, which is the same treatment the
 * Feud board gives its own. */
.soundbtn {
  position: fixed;
  top: 10px;
  left: 12px;
  z-index: 60;
  font: inherit;
  font-size: 13px;
  font-weight: 700;
  min-height: 0;
  padding: 5px 12px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: rgba(0, 0, 0, 0.45);
  color: var(--dim);
  backdrop-filter: blur(4px);
  white-space: nowrap;
  opacity: 0.72;
  transition: opacity 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}
.soundbtn:hover, .soundbtn:focus-visible {
  background: rgba(0, 0, 0, 0.45);
  opacity: 1;
  color: var(--ink);
  border-color: var(--cold);
}
.soundbtn.on { opacity: 0.25; }
.soundbtn.on:hover, .soundbtn.on:focus-visible { opacity: 1; }
/* Small, because the round is the point and this line is not. Still large
   enough to scan: a phone camera wants roughly two modules per pixel of
   capture, and at this size a version 5 symbol clears that on a 1080 frame. */
.joinstrip .qr { flex: none; width: calc(var(--unit) * 8); }
.joinstrip .qr svg { display: block; width: 100%; height: auto; border-radius: 4px; }

/* The guess slider. Left as a native range on purpose -- it already handles
   drag, tap-to-jump, keyboard and VoiceOver -- but sized for a thumb and made
   visibly dead when the window is shut, because a control that looks live and
   does nothing is the worst thing a phone screen can do mid-round. */
input[type="range"] {
  width: 100%;
  height: 44px;
  accent-color: var(--good);
  cursor: pointer;
}
input[type="range"]:disabled { opacity: 0.35; cursor: default; }

/* The call to action on a card. The whole card is the link, so this is the part
   that has to look like one. */
.go { color: var(--cold); font-weight: 800; font-size: 18px; margin-bottom: 0.4em; }
a:hover .go { text-decoration: underline; }

/* A reference table, not a scoreboard -- the option is the emphasis and the
   description is prose, so it reads left to right like documentation. */
.opts { width: 100%; border-collapse: collapse; font-size: 14px; }
.opts td { padding: 8px 10px 8px 0; border-bottom: 1px solid var(--line); vertical-align: top; }
.opts td:first-child { width: 12em; white-space: nowrap; }
.opts td:last-child { color: var(--dim); }
.opts code { color: var(--ink); font-weight: 700; }

.lb { width: 100%; border-collapse: collapse; font-size: calc(var(--unit) * 1.9); }
.lb td { padding: calc(var(--unit) * 0.5) calc(var(--unit) * 0.8); border-bottom: 1px solid var(--line); }
.lb td:first-child { color: var(--dim); width: 3em; }
.lb td:last-child { text-align: right; font-weight: 800; font-variant-numeric: tabular-nums; }

/* Vertical: a 9:16 video frame, not a page. The safe areas are the parts of a
   phone screen the app's own chrome sits over -- comments up the bottom left,
   the button rail down the right -- so the game keeps out of both rather than
   trusting them to stay put. */
.board.vertical {
  --unit: 1.9vw;
  padding: 6vh 14vw 22vh 6vw;
  justify-content: flex-start;
  padding-top: 8vh;
}
.board.vertical .clue { font-size: calc(var(--unit) * 4.4); }
.board.vertical .swarm { height: calc(var(--unit) * 11); }

@media (max-width: 900px) {
  .board { --unit: 3.4vw; padding: 16px; }
  .board.vertical { --unit: 3.4vw; padding: 16px; }
}
