/* Defined Marketing scavenger hunt.
   Palette is deliberately three colours: brand red, pure white, pure black.
   Green appears in exactly one place -- the approved thumbs-up -- because a
   verdict has to read instantly and red is already spoken for. */

:root {
  --red: #ED2E35;
  --red-dark: #C41F26;
  --red-tint: #FDECED;
  --black: #000000;
  --white: #FFFFFF;

  --ink-60: rgba(0, 0, 0, 0.60);
  --ink-40: rgba(0, 0, 0, 0.40);
  --ink-12: rgba(0, 0, 0, 0.12);
  --ink-06: rgba(0, 0, 0, 0.06);

  --ok: #128A46;
  --ok-tint: #E7F5ED;

  --radius: 10px;
  --radius-lg: 16px;
  --shadow: 0 1px 2px rgba(0,0,0,.08), 0 8px 24px rgba(0,0,0,.06);

  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--white);
  color: var(--black);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.45;
  -webkit-text-size-adjust: 100%;
  overscroll-behavior-y: contain;
}

button, input, select, textarea { font: inherit; color: inherit; }

/* ---------- Wordmark -------------------------------------------------------
   The Defined Marketing logo uses a turned "e" (U+01DD). The real character is
   drawn on the baseline by the type designer, so it needs no transform -- and
   no transform means it cannot drift off the line. */

.wordmark {
  display: inline-flex;
  align-items: baseline;
  font-weight: 800;
  letter-spacing: -0.02em;
  text-transform: lowercase;
  white-space: nowrap;
}
.wordmark .turned-e { color: var(--red); }
.wordmark .mark-light { font-weight: 500; margin-left: .35em; }

/* Fallback only, for a system font with no U+01DD: rotate a normal "e".
   An "e" occupies the band from the baseline up to the x-height, so rotating
   about the box centre lands it in the upper half and leaves it hanging above
   the line. translateY puts it back down where it belongs. */
:root.no-turned-e .wordmark .turned-e {
  display: inline-block;
  line-height: 1;
  transform: rotate(180deg) translateY(-0.09em);
}

/* ---------- Layout --------------------------------------------------------- */

.app { min-height: 100dvh; display: flex; flex-direction: column; }

.topbar {
  position: sticky; top: 0; z-index: 40;
  background: var(--black); color: var(--white);
  padding: calc(var(--safe-top) + 10px) 14px 10px;
  display: flex; align-items: center; gap: 12px;
}
.topbar .team-name { font-weight: 800; font-size: 17px; letter-spacing: -.01em; }
.topbar .route { font-size: 12px; color: rgba(255,255,255,.65); text-transform: uppercase; letter-spacing: .08em; }
.topbar .spacer { flex: 1; }

.stat { text-align: right; line-height: 1.15; }
.stat .value { font-size: 20px; font-weight: 800; font-variant-numeric: tabular-nums; }
.stat .label { font-size: 10px; text-transform: uppercase; letter-spacing: .1em; color: rgba(255,255,255,.6); }
.stat .value.warn { color: var(--red); }
.stat .value.caution { color: #E8A317; }

/* One unmissable prompt to start heading back. */
.time-banner {
  position: sticky; top: 0; z-index: 35;
  background: #E8A317; color: var(--black);
  padding: 10px 14px; font-weight: 800; font-size: 14px; text-align: center;
}
.time-banner.over { background: var(--red); color: var(--white); }
/* Checked in. Not a warning -- the run went fine, it is simply over -- so this
   is the calm one of the three rather than another orange or red stripe. */
.time-banner.done { background: var(--black); color: var(--white); }
.time-banner[hidden] { display: none; }

/* Bingo: grid is the pretty view, list is the one that works at night. */
.view-toggle { display: inline-flex; border: 1.5px solid var(--ink-12); border-radius: 999px; overflow: hidden; }
.view-toggle button {
  appearance: none; border: 0; background: var(--white); cursor: pointer;
  font: inherit; font-size: 11px; font-weight: 800; text-transform: uppercase;
  letter-spacing: .06em; padding: 5px 12px; color: var(--ink-40);
}
.view-toggle button[aria-pressed="true"] { background: var(--black); color: var(--white); }

.bingo-list { display: flex; flex-direction: column; gap: 8px; }
.bingo-row {
  display: flex; align-items: center; gap: 12px; width: 100%; text-align: left;
  border: 2px solid var(--black); border-radius: var(--radius-lg);
  background: var(--white); padding: 10px 12px; min-height: 62px;
  font: inherit; cursor: pointer;
}
.bingo-row.approved { border-color: var(--ok); background: var(--ok-tint); }
.bingo-row.rejected { border-color: var(--red); background: var(--red-tint); }
.bingo-row.pending { border-color: var(--ink-40); }
.bingo-row .row-icon,
.bingo-row .row-shot {
  flex: 0 0 44px; width: 44px; height: 44px; border-radius: 8px;
  display: grid; place-items: center; background: var(--ink-06) center/cover no-repeat;
}
.bingo-row .row-icon svg, .bingo-row .row-icon img { width: 32px; height: 32px; object-fit: contain; }
.bingo-row .row-body { flex: 1; min-width: 0; }
.bingo-row .row-label { display: block; font-size: 15px; font-weight: 700; line-height: 1.2; }
.bingo-row .row-meta { display: block; font-size: 11px; color: var(--ink-60); margin-top: 2px; }

/* Said out loud on a staff console when the screen is not showing everything.
   Amber rather than red: nothing is broken, but do not read this as the lot. */
.banner {
  border: 2px solid var(--black); border-radius: var(--radius);
  padding: 11px 14px; margin-bottom: 12px; font-size: 14px; font-weight: 600;
  background: var(--white);
}
.banner.warn { background: #FDF3DF; border-color: #E8A317; }
/* "3 still with a judge" beside a Check in button -- the thing worth noticing
   before ending a team's run, not after. */
.warn-note { color: #8A5A00; font-weight: 700; margin-top: 3px; }

/* The end of the night, on the judge's console: the button that puts the winner
   on the big screen. Only appears once every team is actually back. */
.reveal-box {
  border: 2px solid var(--red); border-radius: var(--radius);
  padding: 12px 14px; margin-bottom: 14px; background: var(--red-tint);
}
.reveal-box.on { border-color: var(--ok); background: var(--ok-tint); }

/* A judge's reason, shown before the retake rather than destroyed by the tap. */
.reject-reason {
  background: var(--red-tint); border: 1.5px solid var(--red); color: var(--red-dark);
  border-radius: var(--radius); padding: 12px 14px; font-weight: 700; margin-bottom: 10px;
}

/* Only ever rendered when the organiser has uploaded an example photo. */
.example-shot { margin: 0 0 14px; }
.example-shot img {
  width: 100%; border-radius: var(--radius); border: 2px solid var(--ok);
  display: block; max-height: 240px; object-fit: cover;
}
.example-shot figcaption {
  font-size: 13px; font-weight: 700; color: var(--ok); margin-top: 6px; text-align: center;
}

.link-btn {
  appearance: none; border: 0; background: none; padding: 0; font: inherit;
  font-size: 13px; font-weight: 700; color: var(--red); text-decoration: underline;
  cursor: pointer; text-align: left;
}

.failed-list { display: flex; flex-direction: column; gap: 8px; margin-bottom: 6px; }
.failed-row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  border: 1.5px solid var(--ink-12); border-radius: var(--radius); padding: 10px 12px;
}
.queue-pill.failed { background: var(--red); cursor: pointer; }

.tabs {
  position: sticky; top: 0; z-index: 30;
  /* minmax(0, 1fr), not 1fr. A bare 1fr column refuses to shrink below its own
     content, so one long label pushes the column out, the grid grows past the
     viewport and the WHOLE APP slides sideways under the thumb -- which is
     exactly what a fifth tab did at 320px until the labels below were made to
     fit. They fit now, so this is the guard rather than the fix: it is what
     stops the next tab, or a longer word, from doing it again silently. */
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr);
  background: var(--white); border-bottom: 2px solid var(--black);
}
/* The tab strip is the one place in the app that is NOT set in spaced capitals.
   Measured, at 13px bold: "LANDMARKS" needs 87px and its count another 27px,
   against a column of 82px on a 412px phone -- so in capitals, side by side,
   something always gets cut off. Sentence case brings the label to 66px and the
   count goes underneath, which fits every phone from 320px up with room spare.
   The alternatives were all worse: renaming a word the printed cards also use,
   type too small to read in a moving car, or hiding a whole tab. */
.tabs button {
  appearance: none; border: 0; background: none; cursor: pointer;
  padding: 9px 4px 8px; font-weight: 700; font-size: 13px;
  letter-spacing: -.01em; color: var(--ink-60);
  border-bottom: 3px solid transparent; margin-bottom: -2px;
  /* start, not center: with the count on a second row, centring would drop the
     three labels that have no count half a line below the two that do. */
  display: grid; justify-items: center; align-content: start; gap: 3px;
  line-height: 1.15;
  /* Second guard, independent of the first: clipping one letter is bad, a page
     that scrolls sideways under the thumb is worse. */
  overflow: hidden;
}
@media (max-width: 380px) {
  .tabs button { font-size: 12px; padding-left: 2px; padding-right: 2px; }
  .tabs .badge { padding: 0 4px; font-size: 10px; min-width: 15px; line-height: 15px; }
}
.tabs button[aria-selected="true"] { color: var(--black); border-bottom-color: var(--red); }
.tabs .badge {
  display: inline-block; min-width: 17px; padding: 0 4px;
  background: var(--red); color: var(--white); border-radius: 9px;
  font-size: 11px; line-height: 17px; letter-spacing: 0;
}

main { flex: 1; padding: 14px 14px calc(var(--safe-bottom) + 32px); }
.panel[hidden] { display: none; }

/* ---------- Shared bits ---------------------------------------------------- */

.section-title {
  font-size: 12px; font-weight: 800; text-transform: uppercase;
  letter-spacing: .1em; color: var(--ink-60); margin: 22px 0 8px;
}
.section-title:first-child { margin-top: 4px; }

.card {
  border: 2px solid var(--black); border-radius: var(--radius-lg);
  background: var(--white); overflow: hidden;
}

.btn {
  appearance: none; cursor: pointer; border: 2px solid var(--black);
  background: var(--white); color: var(--black);
  border-radius: var(--radius); padding: 12px 16px;
  font-weight: 700; font-size: 15px; letter-spacing: -.01em;
  min-height: 48px; /* thumb-sized: this gets used in a moving vehicle */
}
.btn:active { transform: translateY(1px); }
.btn.primary { background: var(--red); border-color: var(--red); color: var(--white); }
.btn.primary:disabled { background: var(--ink-12); border-color: var(--ink-12); color: var(--ink-40); }
.btn.dark { background: var(--black); color: var(--white); }
.btn.ghost { border-color: var(--ink-12); }
.btn.small { min-height: 38px; padding: 8px 12px; font-size: 13px; border-width: 1.5px; }
.btn:disabled { cursor: not-allowed; opacity: .55; }
.btn.block { width: 100%; }
/* Saving a photo has to be a real link -- a download needs an href -- and an
   anchor is INLINE, so it ignored the width, the padding stayed lopsided and it
   came out looking like underlined text overlapping the badge above it. */
a.btn { display: inline-flex; align-items: center; justify-content: center; text-decoration: none; }
a.btn.block { display: flex; }

.input {
  width: 100%; padding: 13px 14px; min-height: 48px;
  border: 2px solid var(--black); border-radius: var(--radius);
  background: var(--white); outline: none;
}
.input:focus { border-color: var(--red); }
.input::placeholder { color: var(--ink-40); }

.note { font-size: 13px; color: var(--ink-60); }
.error {
  background: var(--red-tint); border: 1.5px solid var(--red); color: var(--red-dark);
  border-radius: var(--radius); padding: 10px 12px; font-size: 14px; font-weight: 600;
}

/* ---------- Verdict badge --------------------------------------------------
   One component, used on landmark slots, bingo tiles and riddle rows. */

.verdict {
  display: inline-flex; align-items: center; justify-content: center; gap: 5px;
  border-radius: 999px; font-size: 12px; font-weight: 800;
  padding: 3px 9px; white-space: nowrap; border: 1.5px solid transparent;
}
.verdict.pending  { background: var(--white); color: var(--ink-60); border-color: var(--ink-12); }
.verdict.approved { background: var(--ok-tint); color: var(--ok); border-color: var(--ok); }
.verdict.rejected { background: var(--red-tint); color: var(--red-dark); border-color: var(--red); cursor: pointer; }
/* Approved, but a first-team-only item another team had already claimed.
   Deliberately neither green nor red: the submission was fine, it simply earns
   nothing, and a plain green tick worth zero points is how a team ends the
   night certain they were miscounted. */
.verdict.noscore { background: var(--black); color: var(--white); border-color: var(--black); }
.verdict svg { width: 13px; height: 13px; }

/* ---------- Where you stand ------------------------------------------------ */

.standing { padding: 16px; text-align: center; }
.standing .pos { font-size: 30px; font-weight: 800; letter-spacing: -.02em; line-height: 1.1; }
.standing .gap { font-size: 15px; font-weight: 700; margin-top: 3px; }
.standing .note { margin-top: 8px; }
.standing.leading { border-color: var(--red); }
.standing.leading .pos { color: var(--red); }

/* Full running order on the player's phone.
   The name column is minmax(0, 1fr) and truncates. A bare 1fr would take its
   automatic minimum from the longest team name and push the points column off
   the right edge of a 320px screen -- which is exactly how the bingo card came
   to be cut off on Android. */
.ranking { padding: 0; }
.rank-row {
  display: grid; grid-template-columns: 26px minmax(0, 1fr) auto;
  align-items: center; gap: 10px;
  padding: 10px 13px; border-top: 1px solid var(--ink-12);
}
.rank-row:first-child { border-top: 0; }
.rank-row .pos {
  font-size: 13px; font-weight: 800; color: var(--ink-60);
  font-variant-numeric: tabular-nums;
}
.rank-row .nm {
  font-weight: 700; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.rank-row .pts { font-weight: 800; font-variant-numeric: tabular-nums; }
.rank-row .pts small { font-weight: 700; color: var(--ink-40); margin-left: 3px; }
/* This team's own row, so it can be found without reading every name. */
.rank-row.me { background: var(--black); color: var(--white); }
.rank-row.me .pos { color: rgba(255,255,255,.65); }
.rank-row.me .pts small { color: rgba(255,255,255,.6); }
.rank-foot {
  padding: 11px 13px; border-top: 2px solid var(--black);
  font-size: 13px; font-weight: 700;
}
.rank-foot .note { margin: 3px 0 0; font-weight: 400; }

/* ---------- Photos: the team's own record of the night ---------------------
   Square tiles rather than rows: this tab is for looking at the night, and a
   list of 40 lines with 40px thumbnails is not looking at anything. */

.shots { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
@media (min-width: 520px) {
  .shots { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

.shot-tile {
  appearance: none; padding: 0; cursor: pointer; position: relative;
  border: 2px solid var(--black); border-radius: var(--radius);
  background: var(--white); overflow: hidden; text-align: left;
  display: flex; flex-direction: column; min-width: 0;
}
.shot-tile .shot-img {
  display: block; width: 100%; aspect-ratio: 1 / 1;
  background: var(--ink-12) center / cover no-repeat;
}
/* A video upload has no thumbnail -- the phone never decodes a frame from it. */
.shot-tile .shot-img.novideo {
  display: grid; place-items: center; font-size: 24px; color: var(--ink-40);
}
.shot-cap {
  padding: 5px 7px; font-size: 11px; font-weight: 700; line-height: 1.3;
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.shot-tile .corner-verdict {
  position: absolute; top: 4px; right: 4px; z-index: 3;
  width: 18px; height: 18px; border-radius: 50%;
  display: grid; place-items: center; color: var(--white);
}
.shot-tile .corner-verdict svg { width: 10px; height: 10px; }
.shot-tile .corner-verdict.approved { background: var(--ok); }
.shot-tile .corner-verdict.rejected { background: var(--red); }
.shot-tile .corner-verdict.pending { background: var(--black); }
.shot-tag {
  position: absolute; top: 4px; left: 4px; z-index: 3;
  background: var(--black); color: var(--white);
  font-size: 9px; font-weight: 800; text-transform: uppercase; letter-spacing: .06em;
  padding: 2px 6px; border-radius: 999px;
}
/* A replaced or retaken attempt is still their photo. Dimmed, never hidden. */
.shot-tile.past { border-color: var(--ink-12); }
.shot-tile.past .shot-img { opacity: .45; }

.shot-full {
  display: block; width: 100%; border-radius: var(--radius);
  border: 2px solid var(--black); background: var(--ink-12);
}

.answer-row {
  display: flex; gap: 10px; align-items: flex-start; justify-content: space-between;
  padding: 11px 13px; border-top: 1px solid var(--ink-12);
}
.answer-row:first-child { border-top: 0; }
.answer-row .answer-body { min-width: 0; }
.answer-row .note { margin: 2px 0 0; }
.answer-row.past { opacity: .55; }

/* ---------- Landmarks ------------------------------------------------------ */

.landmark {
  display: flex; gap: 12px; align-items: flex-start;
  border: 2px solid var(--black); border-radius: var(--radius-lg);
  padding: 12px; margin-bottom: 10px; background: var(--white);
}
.landmark.approved { border-color: var(--ok); background: var(--ok-tint); }
.landmark.rejected { border-color: var(--red); background: var(--red-tint); }
.landmark.pending { border-color: var(--ink-40); }
.landmark .thumb {
  width: 68px; height: 68px; flex: 0 0 68px; border-radius: 8px;
  background: var(--ink-06) center/cover no-repeat;
  border: 1.5px solid var(--ink-12);
  display: grid; place-items: center; font-size: 22px; font-weight: 800; color: var(--ink-40);
}
.landmark .body { flex: 1; min-width: 0; }
.landmark h3 { margin: 0 0 2px; font-size: 16px; font-weight: 800; letter-spacing: -.01em; }
.landmark .meta { font-size: 12px; color: var(--ink-60); }
.landmark .actions { margin-top: 9px; display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }

.distance { font-weight: 800; font-variant-numeric: tabular-nums; }
.distance.near { color: var(--ok); }
.distance.far { color: var(--red); }

/* ---------- Bingo grid -----------------------------------------------------
   Mirrors the printed card: 6x6, red outer rule, sponsor block in the centre. */

.bingo-wrap { border: 3px solid var(--red); border-radius: 6px; overflow: hidden; background: var(--black); }
.bingo {
  display: grid;
  /* minmax(0, 1fr), never a bare 1fr. A bare 1fr track is minmax(auto, 1fr),
     whose automatic minimum is the item's min-content width -- and that grows
     with the longest word in the label and with the intrinsic width of any
     uploaded icon. Six such tracks then total more than the phone is wide, and
     .bingo-wrap's overflow:hidden silently clips the right-hand columns off the
     card. Pinning the minimum to 0 makes that arithmetically impossible. */
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 1px;
  background: var(--black);
}
/* Cell height is the whole Android bug.
 *
 * The card is a fixed 6x6, so on a 360px phone each square is about 46px wide.
 * With a locked square aspect ratio, a label like "Purchase a Foam Souvenir and
 * Wear It" needs more lines than that height allows, and the overflow was
 * landing on top of the row above -- which reads exactly as "the bingo card
 * cuts off".
 *
 * So: no fixed ratio on a phone. Rows grow to whatever their longest label
 * needs, and nothing is ever clipped. The square proportions come back at
 * tablet width and up, where they fit without costing anything. */
.cell {
  position: relative; background: var(--white);
  display: flex; flex-direction: column; align-items: center; justify-content: flex-end;
  padding: 4px 2px; gap: 2px; cursor: pointer; border: 0;
  font-family: inherit; text-align: center;
  min-width: 0;      /* grid items default to min-width:auto -- see above */
  min-height: 66px;
}
@media (min-width: 560px) {
  .cell { aspect-ratio: 1 / 1.12; min-height: 0; }
}
.cell:disabled { cursor: default; }
/* On a phone the icon is a fixed band and the label takes everything left over,
   so a long label wins the space it needs. On a wide screen the icon grows back
   into the square. */
.cell .icon {
  flex: 0 0 auto; height: 26px;
  display: grid; place-items: center;
  width: 100%; min-width: 0; min-height: 0; padding: 1px;
}
@media (min-width: 560px) {
  .cell .icon { flex: 1; height: auto; padding: 2px; }
}
.cell .icon svg { width: 100%; height: 100%; max-width: 100%; max-height: 46px; }
/* Uploaded artwork. object-fit keeps any aspect ratio intact inside the square.
   max-width matters as much as width: a 512px PNG otherwise reports a 512px
   min-content width and blows the track open. */
.cell .icon .icon-art { width: 100%; height: 100%; max-width: 100%; max-height: 46px; object-fit: contain; }
.cell .cell-label { max-width: 100%; }
.cell .cell-label {
  font-size: 9.5px; line-height: 1.1; font-weight: 700; text-transform: uppercase;
  letter-spacing: .01em; hyphens: auto; overflow-wrap: anywhere;
}
.cell.highlight { background: var(--red-tint); }
.cell.sponsor { background: var(--white); padding: 6px; justify-content: center; }
.cell.approved { background: var(--ok-tint); }
.cell.approved .cell-label { color: var(--ok); }
.cell.rejected { background: var(--red-tint); }
.cell.pending::after {
  content: ''; position: absolute; inset: 0;
  border: 2px solid var(--ink-40); pointer-events: none;
}
.cell.approved::after { content: ''; position: absolute; inset: 0; border: 2px solid var(--ok); pointer-events: none; }
.cell.rejected::after { content: ''; position: absolute; inset: 0; border: 2px solid var(--red); pointer-events: none; }

/* The submitted photo lands in the cell's top-left corner. */
.cell .shot {
  position: absolute; top: 2px; left: 2px; z-index: 2;
  width: 38%; aspect-ratio: 1; border-radius: 3px;
  background: var(--ink-06) center/cover no-repeat;
  border: 1.5px solid var(--white);
  box-shadow: 0 1px 3px rgba(0,0,0,.35);
}
.cell .corner-verdict {
  position: absolute; top: 2px; right: 2px; z-index: 3;
  width: 15px; height: 15px; border-radius: 50%;
  display: grid; place-items: center; color: var(--white);
}
.cell .corner-verdict svg { width: 9px; height: 9px; }
.cell .corner-verdict.approved { background: var(--ok); }
.cell .corner-verdict.rejected { background: var(--red); }
.cell .corner-verdict.pending { background: var(--black); }

@media (min-width: 420px) {
  .cell .cell-label { font-size: 11px; }
  .cell .icon svg, .cell .icon .icon-art { max-height: 62px; }
}

.sponsor-mark { display: grid; place-items: center; gap: 3px; width: 100%; min-width: 0; }
/* The sponsor block is two columns wide -- about 95px on a small phone -- and
   "dǝfined marketing" on one line does not fit in that. Let the lockup stack
   instead of running out of the square. */
.sponsor-mark .wordmark {
  font-size: clamp(10px, 3vw, 20px);
  flex-wrap: wrap; justify-content: center; max-width: 100%;
}
.sponsor-mark .wordmark .mark-light { margin-left: .35em; }
@media (max-width: 419px) {
  .sponsor-mark .wordmark .mark-light { margin-left: 0; }
}
.sponsor-mark .url {
  font-size: clamp(6px, 1.7vw, 10px); color: var(--ink-60); letter-spacing: .02em;
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ---------- Riddles / rows ------------------------------------------------- */

.row {
  display: flex; align-items: center; gap: 12px;
  border: 2px solid var(--black); border-radius: var(--radius-lg);
  padding: 12px; margin-bottom: 10px; background: var(--white);
}
.row.approved { border-color: var(--ok); background: var(--ok-tint); }
.row.rejected { border-color: var(--red); background: var(--red-tint); }
.row .num {
  flex: 0 0 38px; height: 38px; border-radius: 50%;
  background: var(--black); color: var(--white);
  display: grid; place-items: center; font-weight: 800; font-size: 15px;
}
.row.approved .num { background: var(--ok); }
.row .body { flex: 1; min-width: 0; }
.row .prompt { font-size: 14px; font-weight: 600; margin-bottom: 6px; }

/* ---------- Upload queue indicator ----------------------------------------- */

.queue-pill {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(var(--safe-bottom) + 14px); z-index: 60;
  background: var(--black); color: var(--white);
  border-radius: 999px; padding: 9px 16px;
  font-size: 13px; font-weight: 700; box-shadow: var(--shadow);
  display: flex; align-items: center; gap: 8px;
}
.queue-pill.offline { background: var(--red); }
.queue-pill[hidden] { display: none; }
.spinner {
  width: 13px; height: 13px; border-radius: 50%;
  border: 2px solid rgba(255,255,255,.35); border-top-color: var(--white);
  animation: spin .8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ---------- Join screen ---------------------------------------------------- */

.join { max-width: 420px; margin: 0 auto; padding: 32px 20px calc(var(--safe-bottom) + 32px); }
.join .brand { text-align: center; margin-bottom: 28px; }
.join .brand .wordmark { font-size: 26px; }
.join h1 {
  font-size: 30px; font-weight: 800; line-height: 1.05;
  letter-spacing: -.02em; text-transform: uppercase; margin: 0 0 6px;
}
.join h1 .accent { color: var(--red); }
.join .code-input {
  text-transform: uppercase; letter-spacing: .35em; text-align: center;
  font-size: 26px; font-weight: 800; padding: 16px 10px;
}
.join label { display: block; font-size: 12px; font-weight: 800; text-transform: uppercase; letter-spacing: .1em; margin: 18px 0 6px; }

/* Shown when a scanned QR code already carried the team code. */
.code-chip {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  border: 2px solid var(--ok); background: var(--ok-tint);
  border-radius: var(--radius); padding: 12px 14px; min-height: 48px;
}
.code-chip span { font-size: 24px; font-weight: 800; letter-spacing: .18em; color: var(--ok); }

/* ---------- Modal / camera sheet ------------------------------------------- */

.sheet-backdrop {
  position: fixed; inset: 0; z-index: 80; background: rgba(0,0,0,.55);
  display: flex; align-items: flex-end; justify-content: center;
}
.sheet-backdrop[hidden] { display: none; }
.sheet {
  background: var(--white); width: 100%; max-width: 520px;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  padding: 18px 16px calc(var(--safe-bottom) + 18px);
  max-height: 92dvh; overflow-y: auto;
}
.sheet h2 { margin: 0 0 4px; font-size: 19px; font-weight: 800; letter-spacing: -.01em; }
.sheet .requirement {
  background: var(--black); color: var(--white); border-radius: var(--radius);
  padding: 10px 12px; font-size: 13px; font-weight: 600; margin: 12px 0;
}
.sheet .requirement strong { color: var(--red); }
.preview {
  width: 100%; aspect-ratio: 4/3; border-radius: var(--radius);
  background: var(--ink-06) center/contain no-repeat; margin: 12px 0;
  border: 1.5px solid var(--ink-12);
}
.sheet-actions { display: flex; gap: 8px; margin-top: 6px; }
.sheet-actions .btn { flex: 1; }

/* ---------- Staff consoles -------------------------------------------------- */

.staff-head {
  position: sticky; top: 0; z-index: 40; background: var(--black); color: var(--white);
  padding: 12px 16px; display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
}
.staff-head h1 { font-size: 16px; font-weight: 800; margin: 0; letter-spacing: -.01em; }
.staff-head .spacer { flex: 1; }
.staff-head .pill {
  background: rgba(255,255,255,.14); border-radius: 999px;
  padding: 4px 11px; font-size: 12px; font-weight: 700;
}
.staff-head .pill.live { background: var(--red); }
.staff-head a { color: var(--white); }

/* Form controls sitting in the black header. The global `select { color:
   inherit }` rule hands them the header's WHITE text, while .input keeps its
   white background -- so the judge console's two filter dropdowns rendered as
   blank white rectangles with invisible labels. State both explicitly here
   rather than relying on inheritance from whatever encloses them. */
/* `.input` is in this list because the team picker's trigger is a BUTTON styled
   as a form control, and buttons inherit `color` from the black header just as
   selects do -- so it came out white-on-white exactly like the dropdowns did.
   Matching on the class as well as the tag names covers whatever gets styled as
   a control in here next. */
.staff-head select,
.staff-head input,
.staff-head textarea,
.staff-head .input { color: var(--black); background: var(--white); }
.staff-head select option { color: var(--black); background: var(--white); }

/* Assigned / everything toggle. Two buttons rather than a dropdown: which one
   is active has to be readable at a glance, because it decides whether a judge
   is looking at the whole night or a third of it. */
.seg { display: flex; border-radius: 999px; overflow: hidden; background: rgba(255,255,255,.14); }
.seg button {
  appearance: none; border: 0; background: none; cursor: pointer;
  font-family: inherit; font-size: 12px; font-weight: 700;
  padding: 5px 12px; color: rgba(255,255,255,.72); white-space: nowrap;
}
.seg button.on { background: var(--white); color: var(--black); }

/* Team picker: a button that opens a checkbox list. */
.multi { position: relative; }
.multi-btn {
  width: auto; min-height: 36px; padding: 6px 26px 6px 10px; border-width: 1px;
  text-align: left; cursor: pointer; white-space: nowrap;
  font-weight: 700; font-size: 13px;
  background-image: linear-gradient(45deg, transparent 50%, var(--black) 50%),
                    linear-gradient(135deg, var(--black) 50%, transparent 50%);
  background-position: calc(100% - 14px) 16px, calc(100% - 9px) 16px;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
.multi-menu {
  position: absolute; top: calc(100% + 6px); right: 0; z-index: 60;
  min-width: 210px; max-height: 60vh; overflow-y: auto;
  background: var(--white); color: var(--black);
  border: 2px solid var(--black); border-radius: var(--radius-lg);
  box-shadow: 0 10px 30px rgba(0,0,0,.28); padding: 6px;
}
.multi-menu[hidden] { display: none; }
.multi-menu .multi-actions { display: flex; gap: 6px; padding: 4px 4px 8px; }
.multi-menu .multi-actions button {
  flex: 1; appearance: none; cursor: pointer; font-family: inherit;
  font-size: 12px; font-weight: 700; padding: 6px 8px;
  border: 1px solid var(--black); border-radius: 999px;
  background: var(--white); color: var(--black);
}
.multi-menu label {
  display: flex; align-items: center; gap: 9px; padding: 7px 8px;
  border-radius: 8px; cursor: pointer; font-size: 13px; font-weight: 600;
}
.multi-menu label:hover { background: var(--paper, #f2f2f2); }
.multi-menu label input { width: 16px; height: 16px; min-height: 0; flex: 0 0 auto; accent-color: var(--red); }
.multi-menu .note { padding: 6px 8px 2px; margin: 0; }

.staff-wrap { padding: 16px; max-width: 1500px; margin: 0 auto; }
.two-col { display: grid; grid-template-columns: 1fr; gap: 16px; }
@media (min-width: 1000px) { .two-col { grid-template-columns: minmax(0,1fr) 340px; } }

.queue-grid { display: grid; gap: 14px; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); }

.judge-card { border: 2px solid var(--black); border-radius: var(--radius-lg); overflow: hidden; background: var(--white); }
.judge-card .media { width: 100%; background: var(--black); display: block; }
.judge-card .media img, .judge-card .media video { width: 100%; display: block; max-height: 62vh; object-fit: contain; }
.judge-card .info { padding: 11px 13px; }
.judge-card .who { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--ink-60); margin-bottom: 3px; }
.judge-card .who .team { font-weight: 800; color: var(--black); font-size: 14px; }
.judge-card h3 { margin: 0 0 4px; font-size: 17px; font-weight: 800; letter-spacing: -.01em; }
/* Who on the team actually pressed the button. It was previously tucked in
   beside the route in 12px grey and was effectively invisible. */
.judge-card .sent-by { font-size: 12px; color: var(--ink-60); margin-bottom: 8px; }
.judge-card .sent-by strong { color: var(--black); }
.judge-card .facts { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }

/* Approving a first-team-only item somebody else already holds pays nobody.
   Placed directly above the buttons so it cannot be scrolled past. */
.claim-warning {
  background: var(--red-tint); border: 1.5px solid var(--red); color: var(--red-dark);
  border-radius: var(--radius); padding: 9px 11px; font-size: 13px;
  font-weight: 600; margin-bottom: 10px;
}

.answer-check { font-size: 13px; font-weight: 700; margin: 0 0 10px; }
.answer-check.ok { color: var(--ok); }
.answer-check.no { color: var(--red-dark); }
.fact {
  font-size: 11px; font-weight: 700; border-radius: 999px; padding: 3px 9px;
  background: var(--ink-06); border: 1px solid var(--ink-12);
}
.fact.good { background: var(--ok-tint); border-color: var(--ok); color: var(--ok); }
.fact.bad { background: var(--red-tint); border-color: var(--red); color: var(--red-dark); }
.fact.strong { background: var(--black); color: var(--white); border-color: var(--black); }
/* ---------- Where the photo was taken --------------------------------------
   A strip under the photo, built from map tiles. The schematic underneath
   shows immediately and stays visible if the tiles never load, so a judge on a
   bad connection still sees the photo's position relative to the landmark. */

.map-slot { position: relative; cursor: pointer; border-top: 1.5px solid var(--ink-12); }
.map-slot:hover .map-open { color: var(--red); }

.minimap {
  position: relative; overflow: hidden; background: #F2F2F2;
  max-width: 100%;
}
.minimap-fallback { position: absolute; inset: 0; line-height: 0; }
.minimap-fallback svg { width: 100%; height: 100%; }
.minimap.has-tiles .minimap-fallback { display: none; }

.minimap-tiles { position: absolute; inset: 0; }
.minimap-tiles img { position: absolute; display: block; max-width: none; }

.minimap-pin {
  position: absolute; transform: translate(-50%, -50%); z-index: 3; pointer-events: none;
}
.minimap-accuracy {
  position: absolute; transform: translate(-50%, -50%); z-index: 2; pointer-events: none;
  border-radius: 50%; background: rgba(237, 46, 53, .13); border: 1.5px solid rgba(237, 46, 53, .5);
}
.minimap-credit {
  position: absolute; right: 0; bottom: 0; z-index: 4;
  background: rgba(255, 255, 255, .82); color: var(--ink-60);
  font-size: 9px; padding: 1px 5px; text-decoration: none; border-top-left-radius: 4px;
}

.map-caption {
  display: flex; justify-content: space-between; align-items: center; gap: 10px;
  padding: 6px 13px; font-size: 12px; color: var(--ink-60);
  background: var(--ink-06);
}
.map-caption strong { color: var(--black); }
.map-open { font-weight: 700; white-space: nowrap; }

.map-legend {
  display: flex; flex-wrap: wrap; gap: 14px; align-items: center;
  margin-top: 10px; font-size: 12px; font-weight: 600;
}
.map-legend i {
  display: inline-block; width: 11px; height: 11px; border-radius: 50%;
  border: 2px solid #fff; box-shadow: 0 0 0 1px var(--ink-12); margin-right: 5px;
  vertical-align: -1px;
}
#map-sheet .minimap { border-radius: var(--radius); border: 1.5px solid var(--ink-12); }

.judge-card .verdict-actions { display: flex; gap: 8px; }
.judge-card .verdict-actions .btn { flex: 1; }
.btn.approve { background: var(--ok); border-color: var(--ok); color: var(--white); }
.btn.reject { background: var(--red); border-color: var(--red); color: var(--white); }

.answer-box {
  font-size: 27px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
  background: var(--ink-06); border-radius: var(--radius); padding: 16px;
  text-align: center; margin-bottom: 10px; overflow-wrap: anywhere;
}

table.grid { width: 100%; border-collapse: collapse; font-size: 14px; }
table.grid th, table.grid td { padding: 8px 9px; border-bottom: 1px solid var(--ink-12); text-align: left; }
table.grid th { font-size: 11px; text-transform: uppercase; letter-spacing: .07em; color: var(--ink-40); }
table.grid td.num, table.grid th.num { text-align: right; font-variant-numeric: tabular-nums; }
table.grid tr.done { background: var(--ok-tint); }

/* Correctable dispatch / check-in times. Remembering to dispatch late used to
   be unfixable, and it decides the tie-break. */
.time-edit {
  font: inherit; font-weight: 800; font-variant-numeric: tabular-nums;
  border: 1.5px solid var(--ink-12); border-radius: 6px; padding: 3px 5px;
  background: var(--white); width: 100%; max-width: 108px;
}
.time-edit:hover, .time-edit:focus { border-color: var(--red); outline: none; }

.empty { text-align: center; padding: 60px 20px; color: var(--ink-40); }
.empty .big { font-size: 44px; margin-bottom: 8px; }

/* ---------- Venue display --------------------------------------------------
   Dark, because it plays on a bar monitor. Same three colours inverted. */

body.display { background: var(--black); color: var(--white); overflow: hidden; }
.stage {
  display: grid; height: 100dvh;
  grid-template-columns: 1fr clamp(320px, 24vw, 640px);
  grid-template-rows: 100%;
}
@media (max-width: 900px) { .stage { grid-template-columns: 1fr; } }

/* Both panes are placed explicitly. The results board also sits in cell 1/1,
   on top of the slideshow, and an explicitly-placed third child throws off the
   auto-placement of everything after it -- which dropped the whole rail into a
   second row underneath, full width, at the exact moment the hunt ended. */
.slideshow { grid-column: 1; grid-row: 1; position: relative; overflow: hidden; background: var(--black); }
.rail { grid-column: 2; grid-row: 1; }
@media (max-width: 900px) {
  .slideshow, .rail { grid-column: 1; }
  .rail { grid-row: 2; }
}
.slideshow img, .slideshow video {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: contain; opacity: 0; transition: opacity .7s ease;
}
.slideshow .active { opacity: 1; }
.slide-caption {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 5;
  padding: 40px 34px 26px;
  background: linear-gradient(transparent, rgba(0,0,0,.9));
}
.slide-caption .team { font-size: clamp(30px, 2.6vw, 68px); font-weight: 800; letter-spacing: -.02em; }
.slide-caption .item { font-size: clamp(17px, 1.4vw, 36px); color: rgba(255,255,255,.75); }
.slide-caption .team .dot { color: var(--red); }

/* A photo a judge accepted seconds ago, going up while the team is still at the
   bar. Worth saying out loud rather than letting it slide past in rotation. */
.slide-caption .fresh {
  display: inline-block; margin-bottom: 8px;
  background: var(--red); color: var(--white);
  font-size: clamp(12px, .9vw, 22px); font-weight: 800;
  text-transform: uppercase; letter-spacing: .14em;
  padding: 5px 13px; border-radius: 999px;
}
.slide-caption .fresh[hidden] { display: none; }
.slide-caption .fresh.pop { animation: fresh-pop .5s ease-out; }
@keyframes fresh-pop {
  from { transform: scale(.7); opacity: 0; }
  60%  { transform: scale(1.08); opacity: 1; }
  to   { transform: scale(1); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .slide-caption .fresh.pop { animation: none; }
}

/* "TEAM 4 TAKES THE LEAD". Interrupts the photo, briefly, because a lead
   change is the only thing on this screen worth interrupting a room for. */
.lead-flash {
  position: absolute; left: 0; right: 0; top: 0; z-index: 8;
  padding: clamp(14px, 1.6vw, 34px) clamp(20px, 2.4vw, 50px);
  background: linear-gradient(rgba(237,46,53,.97), rgba(237,46,53,.86));
  color: var(--white);
}
.lead-flash[hidden] { display: none; }
.lead-flash .who {
  display: block; font-size: clamp(28px, 2.6vw, 66px); font-weight: 800;
  letter-spacing: -.02em; line-height: 1.05;
}
.lead-flash .what {
  display: block; font-size: clamp(14px, 1.1vw, 28px); font-weight: 800;
  text-transform: uppercase; letter-spacing: .16em; opacity: .85; margin-top: 2px;
}
.lead-flash.pop { animation: lead-in .45s ease-out; }
@keyframes lead-in {
  from { transform: translateY(-100%); }
  to   { transform: translateY(0); }
}

/* ---------- The finale ------------------------------------------------------
   Shown once every team that went out has come back. First place is held until
   a judge presses the button, so the room hears it from a person. */

.res-head {
  font-size: clamp(13px, 1vw, 26px); font-weight: 800; text-transform: uppercase;
  letter-spacing: .18em; color: var(--red); margin-bottom: clamp(10px, 1.4vw, 26px);
}
.res-row {
  display: grid; grid-template-columns: 2.2ch 6px minmax(0, 1fr) auto auto;
  align-items: center; gap: clamp(8px, 1vw, 20px);
  padding: clamp(6px, .7vw, 15px) 0; border-bottom: 1px solid rgba(255,255,255,.1);
}
.res-rank {
  font-size: clamp(18px, 1.5vw, 40px); font-weight: 800;
  color: rgba(255,255,255,.4); font-variant-numeric: tabular-nums;
}
.res-hue { width: 6px; height: 1.6em; border-radius: 3px; background: rgba(255,255,255,.18); }
.res-name {
  font-size: clamp(19px, 1.7vw, 46px); font-weight: 800; letter-spacing: -.02em;
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.res-time {
  font-size: clamp(12px, .9vw, 22px); color: rgba(255,255,255,.45);
  font-variant-numeric: tabular-nums;
}
.res-pts {
  font-size: clamp(20px, 1.6vw, 44px); font-weight: 800;
  font-variant-numeric: tabular-nums; min-width: 2.5ch; text-align: right;
}
.res-row.win { border-bottom-color: var(--red); }
.res-row.win .res-rank, .res-row.win .res-pts { color: var(--red); }
.res-row.win .res-name { font-size: clamp(24px, 2.3vw, 62px); }
/* Held back: the row is there, the name is not. */
.res-row.held-row .res-name {
  color: rgba(255,255,255,.35); font-style: italic; font-weight: 600;
  font-size: clamp(17px, 1.3vw, 34px);
}
.res-first.shown .res-row.win { animation: winner-in .6s ease-out; }
@keyframes winner-in {
  from { transform: scale(.94); opacity: 0; }
  to   { transform: scale(1); opacity: 1; }
}
.res-foot {
  margin-top: clamp(10px, 1.4vw, 26px); font-size: clamp(11px, .8vw, 20px);
  color: rgba(255,255,255,.35);
}
@media (prefers-reduced-motion: reduce) {
  .lead-flash.pop, .res-first.shown .res-row.win { animation: none; }
}

.rail { background: var(--black); border-left: 3px solid var(--red); padding: 22px 20px; overflow: hidden; }
.rail h2 {
  font-size: clamp(12px, .9vw, 22px); text-transform: uppercase; letter-spacing: .16em;
  color: rgba(255,255,255,.5); margin: 0 0 14px; font-weight: 800;
}
/* The state of the night, along the top of the rail. Somebody glancing up from
   a drink should get the time, the room and who is still out without reading. */
.info { margin-bottom: 16px; padding-bottom: 13px; border-bottom: 1px solid rgba(255,255,255,.12); }
.info-top { display: flex; align-items: baseline; gap: 12px; }
.info-clock {
  font-size: clamp(26px, 2vw, 54px); font-weight: 800; letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
}
.info-venue {
  font-size: clamp(11px, .8vw, 20px); text-transform: uppercase; letter-spacing: .12em;
  color: rgba(255,255,255,.45); min-width: 0; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap;
}
.info-stats { font-size: clamp(12px, .9vw, 22px); color: rgba(255,255,255,.6); margin-top: 3px; }
.info-stats b { color: var(--white); font-weight: 800; }

.lb-row { display: flex; align-items: center; gap: 11px; padding: 9px 0; border-bottom: 1px solid rgba(255,255,255,.1); }
/* Each team's own colour, which the database has always held and nothing has
   ever shown. From across a room it is how somebody finds their row. */
.lb-row .hue {
  flex: 0 0 5px; width: 5px; align-self: stretch; min-height: 2em;
  border-radius: 3px; background: rgba(255,255,255,.18);
}
.lb-row .rank { width: 2ch; font-size: clamp(19px, 1.5vw, 42px); font-weight: 800;
                color: rgba(255,255,255,.4); font-variant-numeric: tabular-nums; }
.lb-row.top .rank { color: var(--red); }
.lb-row .nm { flex: 1; font-weight: 700; font-size: clamp(17px, 1.3vw, 34px); min-width: 0;
               overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Each team's own clock, counting down from their own dispatch. The staggered
   start is exactly why these cannot be one shared timer. */
.lb-row .clock {
  text-align: right; line-height: 1.05; font-variant-numeric: tabular-nums;
  min-width: 5ch;
}
.lb-row .clock .t { display: block; font-size: clamp(15px, 1.1vw, 28px); font-weight: 800; }
.lb-row .clock .k {
  display: block; font-size: clamp(9px, .6vw, 15px); text-transform: uppercase;
  letter-spacing: .1em; color: rgba(255,255,255,.4);
}
.lb-row .clock.live .t { color: rgba(255,255,255,.9); }
.lb-row .clock.soon .t { color: #FFC24A; }          /* under 20 minutes left */
.lb-row .clock.over .t { color: var(--red); }        /* past their deadline */
.lb-row .clock.home .t { color: #4ED17F; }           /* back, inside the limit */
.lb-row .clock.idle .t { color: rgba(255,255,255,.3); font-size: clamp(11px, .8vw, 18px); }
/* The clipping has to be on the small itself. Its parent is what carries the
   ellipsis, and a block child inside an ellipsised parent is simply cut -- which
   read as "0/4 LANDMAR" on a projector. */
.lb-row .nm small { display: block; font-weight: 500; font-size: clamp(12px, .8vw, 20px);
                    color: rgba(255,255,255,.45); text-transform: uppercase; letter-spacing: .06em;
                    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lb-row .pts { font-size: clamp(22px, 1.7vw, 46px); font-weight: 800; font-variant-numeric: tabular-nums; }
.rail .foot { position: absolute; bottom: 18px; }
.display-brand { margin-top: 18px; padding-top: 14px; border-top: 1px solid rgba(255,255,255,.1); }
.display-brand .wordmark { font-size: clamp(19px, 1.3vw, 34px); color: var(--white); }

/* ---------- Print: team join sheets ---------------------------------------- */

@media print {
  .no-print { display: none !important; }
  .join-sheet { page-break-after: always; }
  body { background: var(--white); }
}
.join-sheet {
  width: 100%; max-width: 700px; margin: 0 auto 26px;
  border: 4px solid var(--red); border-radius: 10px;
  padding: 34px; text-align: center; background: var(--white);
}
.join-sheet .kicker { font-size: 13px; font-weight: 800; letter-spacing: .18em; text-transform: uppercase; color: var(--ink-40); }
.join-sheet .team-name { font-size: 46px; font-weight: 800; letter-spacing: -.03em; text-transform: uppercase; margin: 4px 0; }
.join-sheet .route { font-size: 17px; font-weight: 700; color: var(--red); text-transform: uppercase; letter-spacing: .1em; }
/* The printed team code. The border, padding and letter-spacing here are what
   draw the box around it -- only the size and margin were ever overridden
   further down, and those values are folded in here now. */
.join-sheet .code {
  font-size: 44px; font-weight: 800; letter-spacing: .16em;
  border: 4px solid var(--black); border-radius: 12px;
  padding: 14px 10px; margin: 10px 0 4px; font-variant-numeric: tabular-nums;
}
.join-sheet .steps { text-align: left; max-width: 430px; margin: 20px auto 0; font-size: 14px; }
.join-sheet .steps li { margin-bottom: 7px; }
.join-sheet .wordmark { font-size: 21px; margin-top: 18px; }
.join-sheet .qr-block { margin: 20px auto 6px; line-height: 0; }
.join-sheet .qr-block svg { width: 300px; height: 300px; max-width: 70vw; }
.join-sheet .scan-me {
  font-size: 17px; font-weight: 800; text-transform: uppercase; letter-spacing: .06em;
  color: var(--red); margin-bottom: 6px;
}
.join-sheet .url { font-size: 15px; font-weight: 600; color: var(--ink-60); }

/* Booth layout: every team on one page for a check-in desk. */
.booth-sheet { max-width: 900px; margin: 0 auto; }
.booth-head { display: flex; justify-content: space-between; align-items: flex-end;
              border-bottom: 3px solid var(--red); padding-bottom: 10px; margin-bottom: 18px; }
.booth-head .kicker { font-size: 12px; font-weight: 800; letter-spacing: .18em;
                      text-transform: uppercase; color: var(--ink-40); }
.booth-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; }
.booth-card { border: 2px solid var(--black); border-radius: 10px; padding: 10px;
              text-align: center; break-inside: avoid; }
.booth-card svg { width: 100%; height: auto; max-width: 150px; }
.booth-name { font-weight: 800; font-size: 15px; margin-top: 4px; }
.booth-code { font-weight: 800; font-size: 17px; letter-spacing: .12em; color: var(--red); }
.booth-foot { margin-top: 20px; padding-top: 12px; border-top: 1px solid var(--ink-12);
              font-size: 13px; text-align: center; color: var(--ink-60); }
@media print { .booth-grid { grid-template-columns: repeat(4, 1fr); } }
