/*
 * The participant screen.
 *
 * The visual language is the event design template's - bands, one card at a
 * time, the stamp motif, the type scale. The STRUCTURE is this app's, and the
 * information hierarchy is the one the owner specified on 2026-08-24: identity
 * and clock, then people met and countries explored, then the two rankings,
 * then questions, then the passport, then everyone you met.
 *
 * Depends on tokens.css for every colour, radius and font. Nothing here
 * hard-codes a colour, so branding repaints the whole screen by rewriting
 * seven custom properties.
 */

/* --------------------------------------------------------------- frame */

/* Capped, not fixed. Real phones run from about 360 to 430 CSS pixels, and a
   fixed width puts a horizontal scrollbar on the narrow ones. */
body {
  max-width: var(--frame-w);
  margin: 0 auto;
  padding: 0 var(--pad) var(--safe-area);
  min-height: 100vh;
  min-height: 100dvh;
}

/* ------------------------------------------------------------ logo band */

/* Keeps its height whether or not logos are set, so the screen does not jump
   between one event and the next. */
#logobar {
  height: var(--band-logo);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gap);
}

#logobar .logo-slot {
  width: 96px;
  height: 40px;
  flex: 0 0 auto;
}

#logobar .logo-slot[data-empty="true"] { visibility: hidden; }

/* --------------------------------------------------------- event title */

#game-name {
  font-size: 21px;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -0.01em;
  margin: 2px 0 2px;
}

#game-sub,
.sub {
  font-size: 12px;
  color: var(--text-dim);
  margin-bottom: 14px;
  line-height: 1.45;
}

/* ------------------------------------------------------------- identity */

/* Player number and home country on one row, the clock beneath the country.
   One compact status area rather than four equally-weighted boxes. */
/* Player number, home country and the clock stay on screen while the rest of
   the page scrolls. On a phone this is the part you look up to check - your own
   number, to read it out, and how long is left - and before this it scrolled
   away the moment anybody opened a question.

   Three details make it work rather than merely stick:
   - an opaque background, or the content scrolls visibly through it;
   - negative side margins with matching padding, so it spans the full width
     instead of leaving two gutters where text slides past its edges;
   - `top: 0` against the document scroller. Nothing between here and <body>
     sets `overflow` or `transform`, both of which silently disable sticky. If
     a wrapper ever gains one, this stops working with no error - check that
     first. */
#status {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--bg);
  margin: 0 calc(var(--pad) * -1) 16px;
  padding: 14px var(--pad) 12px;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  border-bottom: 1px solid var(--border);
}

#status .who {
  font-size: 34px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.02em;
}

#status .session {
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-top: 5px;
}

#status .right { text-align: right; flex: 0 0 auto; }

#status .home {
  font-size: 15px;
  font-weight: 650;
  line-height: 1.2;
  /* Country names run long - "United Kingdom", "Korea, Republic of" - so they
     wrap rather than truncate. Losing half a country name is worse than a
     second line. */
  max-width: 9rem;
  overflow-wrap: break-word;
}

#status .clock {
  font-size: 26px;
  font-weight: 600;
  line-height: 1;
  margin-top: 6px;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

#status .clock[data-state="expired"] { color: var(--stamp); }
#status .clock[data-state="paused"] { color: var(--warn); }

#status .clocklabel {
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin-top: 3px;
}

/* -------------------------------------------------------------- metrics */

/* People met and countries explored lead; questions is deliberately smaller.
   Rendered by the client from the server's metric view, in its order. */
#progress {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--gap);
  margin-bottom: 12px;
}

.stat {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 11px 12px;
  min-height: var(--tile-h);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

.stat .k {
  font-size: 10px;
  line-height: 1.25;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-dim);
}

.stat .n {
  font-size: 26px;
  font-weight: 650;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.stat .n .of {
  font-size: 15px;
  font-weight: 500;
  color: var(--text-dim);
}

.stat .sub {
  font-size: 11px;
  color: var(--text-dim);
  margin-top: 3px;
}

/* A maxed metric earns a hairline of stamp ink. */
.stat[data-done="true"] {
  border-color: color-mix(in srgb, var(--stamp) 45%, var(--border));
  background: linear-gradient(var(--stamp-soft), var(--stamp-soft)), var(--surface);
}

/* Questions discovered sits below the two headline metrics and reads quieter. */
.stat.minor {
  grid-column: 1 / -1;
  min-height: 0;
  flex-direction: row;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  padding: 9px 12px;
}

.stat.minor .n { font-size: 17px; }

/* ------------------------------------------------------------- rankings */

#rankings {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--gap);
  margin-bottom: 16px;
}

.rank {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 11px 12px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.rank .place {
  font-size: 26px;
  font-weight: 700;
  line-height: 1;
  color: var(--primary-ink);
  font-variant-numeric: tabular-nums;
}

/* An unearned ranking reads as a neutral placeholder, never as "— / 4". */
.rank .place.none { color: var(--text-faint); }

.rank .detail { font-size: 11px; color: var(--text-dim); }

.rank .award {
  font-size: 10px;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-dim);
  line-height: 1.3;
}

/* ---------------------------------------------------------------- cards */

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 20px 18px;
  margin-bottom: 12px;
}

.card .label {
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin-bottom: 8px;
}

.card .value {
  font-size: 17px;
  font-weight: 600;
  line-height: 1.4;
}

.card .prompt {
  font-size: 19px;
  font-weight: 650;
  line-height: 1.35;
  letter-spacing: -0.01em;
  margin: 6px 0 16px;
}

.muted { color: var(--text-dim); font-size: 14px; line-height: 1.55; }

.hidden { display: none !important; }

/* ---------------------------------------------------------------- forms */

label {
  display: block;
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin-bottom: 6px;
}

/* The partner number: large, centred, unmistakably the thing to fill in. */
#partner-input {
  font-size: 40px;
  font-weight: 700;
  text-align: center;
  letter-spacing: 0.16em;
  padding: 14px 12px 14px 26px;   /* letter-spacing pads the right edge */
  font-variant-numeric: tabular-nums;
}

button[type="submit"],
#pair-button,
#answer-button,
#confirm-button,
#continue-button {
  width: 100%;
  padding: 15px 18px;
  margin-top: 14px;
  background: var(--primary);
  color: var(--primary-text);
  border: 1px solid var(--primary);
  border-radius: var(--radius-sm);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.04em;
}

button[type="submit"]:hover:not(:disabled),
#continue-button:hover:not(:disabled) { background: var(--primary-hover); }

/* A disabled primary stops being primary: dimming a saturated fill still
   leaves it the loudest thing on screen, which is the wrong signal. */
button:disabled {
  background: var(--surface-sunken);
  border-color: var(--border);
  color: var(--text-faint);
  cursor: default;
}

textarea { min-height: 104px; line-height: 1.5; }

#answer-count {
  text-align: right;
  font-size: 12px;
  color: var(--text-faint);
  margin-top: 6px;
}

/* --- choice buttons ----------------------------------------------------- */

.choice {
  display: block;
  width: 100%;
  text-align: left;
  padding: 15px 16px;
  margin-bottom: 8px;
  background: var(--field);
  color: var(--field-text);
  border: 1px solid var(--field-border);
  border-radius: var(--radius-sm);
  font-size: 15px;
  font-weight: 500;
  letter-spacing: 0;
}

.choice:has(input:checked) {
  border-color: var(--primary);
  background: color-mix(in srgb, var(--primary) 12%, var(--field));
  font-weight: 650;
}

/* --- the searchable country list ---------------------------------------
 * 249 ISO entries in a native picker is a spin-wheel with no type-ahead, and
 * on Android Chrome a <datalist> draws nothing at all. This is the list this
 * file owns, so every engine renders it the same way.
 */
.combo { position: relative; }

.optionlist {
  margin-top: 6px;
  max-height: 190px;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--field);
  -webkit-overflow-scrolling: touch;
}

.optionlist[hidden] { display: none; }

.optionlist button {
  display: block;
  width: 100%;
  text-align: left;
  padding: 12px 14px;
  background: var(--field);
  color: var(--field-text);
  border: 0;
  border-bottom: 1px solid var(--border);
  font-size: 15px;
  font-weight: 400;
  letter-spacing: 0;
  margin: 0;
}

.optionlist button:last-child { border-bottom: 0; }
.optionlist button:hover { background: var(--surface-sunken); }
.optionlist mark { background: transparent; color: var(--primary-ink); font-weight: 700; }

.combo-empty { padding: 12px 14px; font-size: 14px; color: var(--text-faint); }

/* -------------------------------------------------------------- success */

/* The stamp. Restrained on purpose: a second offset rule reads as an inked
   edge without becoming a graphic. */
.stamp-mark {
  width: 124px;
  height: 124px;
  margin: 4px auto 16px;
  display: grid;
  place-items: center;
  text-align: center;
  border: 2.5px solid var(--stamp);
  border-radius: 10px;
  color: var(--stamp);
  transform: rotate(-7deg);
  position: relative;
  background: var(--stamp-soft);
}

.stamp-mark::after {
  content: "";
  position: absolute;
  inset: 5px;
  border: 1px solid var(--stamp);
  border-radius: 6px;
  opacity: 0.5;
}

.stamp-tick { font-size: 32px; line-height: 1; }

.stamp-word {
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  margin-top: 6px;
  padding: 0 8px;
  line-height: 1.25;
}

.success-title {
  font-size: 17px;
  font-weight: 700;
  text-align: center;
  margin-bottom: 4px;
}

.success-detail {
  text-align: center;
  font-size: 16px;
  font-weight: 600;
  margin-bottom: 6px;
}

#panel-success .muted { text-align: center; }

/* -------------------------------------------------------------- waiting */

/* Nothing to act on, so it centres rather than hanging from the top. */
#panel-wait { text-align: center; }

.waiting-mark {
  width: 52px;
  height: 52px;
  margin: 4px auto 16px;
  border-radius: 50%;
  border: 2px solid var(--border-strong);
  border-top-color: var(--primary);
  animation: spin 1.6s linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  .waiting-mark { animation: none; border-top-color: var(--border-strong); }
}

/* ------------------------------------------------------------- passport */

.passport-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 10px;
}

.passport-count {
  font-size: 13px;
  font-weight: 650;
  color: var(--stamp);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.passport-countries {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 10px;
}

/* One stamp per country visited. Wraps rather than truncates. */
.passport-countries span {
  border: 1px solid color-mix(in srgb, var(--stamp) 55%, transparent);
  background: var(--stamp-soft);
  color: var(--stamp);
  border-radius: var(--radius-sm);
  padding: 6px 10px;
  font-size: 13px;
  font-weight: 600;
  line-height: 1.25;
}

/* ---------------------------------------------------------------- recap */

.recap-row {
  border-top: 1px solid var(--border);
  padding: 12px 0;
}

.recap-row:first-child { border-top: 0; padding-top: 2px; }

.recap-who {
  font-size: 15px;
  font-weight: 650;
  margin-bottom: 2px;
}

.recap-q {
  font-size: 13px;
  font-weight: 600;
  margin-bottom: 4px;
  line-height: 1.4;
}

.recap-a { font-size: 14px; line-height: 1.5; }
.recap-a + .recap-a { margin-top: 4px; }

/* ------------------------------------------------------- banner / error */

/* Applies to the whole screen, so it sits above the card and does not move
   when the card beneath it changes state (§52). */
#stage-error,
#problems {
  margin: 10px 0 0;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  background: var(--stamp-soft);
  border: 1px solid color-mix(in srgb, var(--danger) 35%, transparent);
  color: var(--danger);
  font-size: 13px;
  line-height: 1.5;
}

#problems:empty { display: none; }

/* Server-supplied §63 wording: information, not alarm. */
.banner {
  margin-bottom: 10px;
  padding: 10px 14px;
  border-radius: var(--radius-sm);
  background: var(--warn-soft);
  border: 1px solid color-mix(in srgb, var(--warn) 40%, transparent);
  color: var(--warn);
  font-size: 13px;
  font-weight: 650;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-align: center;
}

/* ------------------------------------------------------------ connection */

.dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-right: 7px;
  background: var(--text-faint);
}

.dot.up { background: var(--ok); }
.dot.down { background: var(--warn); }

#foot {
  font-size: 11px;
  color: var(--text-faint);
  line-height: 1.5;
  padding: 6px 0 0;
}

/* ------------------------------------------------------------ wide view */

/* A laptop or Surface running as a participant. The frame stays capped -
   stretching a phone layout across 1400px reads as a broken page rather than
   a spacious one - but the two grids can breathe. */
@media (min-width: 480px) {
  #progress { grid-template-columns: 1fr 1fr; }
}

/* ------------------------------------------------------- header strip

 * The template's own metric chips, drawn by the client from the HEADER
 * region. `.placeholder` is a clock that has not been earned - dead, not
 * missing, so it stays visible at 30% rather than vanishing and reflowing
 * the row.
 */
.chip {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 8px 11px;
}

.chip .label {
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin-bottom: 3px;
}

.chip .value { font-size: 16px; font-weight: 650; line-height: 1; }
.chip .value.placeholder { color: var(--text-faint); }

.tabular {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

#header-strip {
  display: flex;
  flex-wrap: wrap;
  gap: var(--gap);
  margin-bottom: 12px;
}

#header-strip:empty { display: none; }

/* Choice rows are an input and a label, not a button. */
.choice {
  display: flex;
  align-items: center;
  gap: 10px;
}

.choice input { width: auto; margin: 0; flex: 0 0 auto; }

.choice label {
  margin: 0;
  font-size: 15px;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--text);
  cursor: pointer;
}

.problem { margin: 0; }

/* ------------------------------------------------------------ interests */

/* Three quick taps, not a multi-select list no thumb can operate. */
.chipgroup { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 6px; }

.chip-choice {
  width: auto;
  margin: 0;
  padding: 10px 14px;
  background: var(--field);
  color: var(--field-text);
  border: 1px solid var(--field-border);
  border-radius: var(--radius-sm);
  font-size: 15px;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
}

.chip-choice[aria-pressed="true"] {
  border-color: var(--primary);
  background: color-mix(in srgb, var(--primary) 14%, var(--field));
  font-weight: 650;
}

/* "2 of 3 chosen", so a disabled Join button is never a mystery. */
.chipcount { font-size: 12px; margin-bottom: 14px; }

/* --------------------------------------------------------------- consent */

/* Beside its box, the way a consent line looks everywhere - not a label
   stacked above a field. */
.tick-line {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  text-transform: none;
  letter-spacing: 0;
  font-size: 14px;
  color: var(--text);
  margin-bottom: 14px;
}

/* appearance: auto because tokens.css strips it from inputs; a checkbox
   without its native tick is a grey bar that never visibly changes. */
.tickbox {
  appearance: auto;
  -webkit-appearance: checkbox;
  width: 1.15rem;
  height: 1.15rem;
  min-width: 1.15rem;
  padding: 0;
  margin: 0;
  border: 0;
  background: initial;
  accent-color: var(--primary);
  flex: 0 0 auto;
}

/* A chosen interest is a label, not a button - it is showing what they picked,
   not offering a choice. Same shape as the sign-in chips so the two read as
   the same thing. */
.interest-chip {
  cursor: default;
  border-color: color-mix(in srgb, var(--primary) 45%, var(--border));
  background: color-mix(in srgb, var(--primary) 10%, var(--surface));
  font-weight: 600;
}
