/* ---------------------------------------------------------------------------
 * ZoodleSwap - teacher and projector styling.
 *
 * Two very different distances. The lobby and the scoreboard are read from the
 * back of a classroom, so they are enormous. The roster is read at arm's
 * length on a phone, so it is dense and tappable. Both live here because they
 * are the same person's screens minutes apart.
 * ------------------------------------------------------------------------- */

.leader .page-title {
  margin: 8px 0 0;
  font-size: 1.8rem;
  color: var(--cyan);
}

.leader .page-title.small { font-size: 1.3rem; }

/* --- setup ---------------------------------------------------------------- */

.setup { justify-content: center; }

.setup-card {
  width: min(460px, 100%);
  background: var(--panel);
  border: 1px solid #14465f;
  border-radius: 20px;
  padding: 24px;
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.select {
  font-family: inherit;
  font-size: 1.05rem;
  padding: 13px;
  min-height: 52px;
  border-radius: 12px;
  border: 2px solid #1d5a78;
  background: #061e2e;
  color: var(--paper);
}

.select:focus { outline: 3px solid var(--cyan); }

/* --- the lobby, on the projector ------------------------------------------
 * Two jobs at once, and they want opposite things. Joining needs a code big
 * enough to read from the back row. Waiting needs the names, because the only
 * interesting thing happening in the two minutes before a game starts is
 * watching your own name appear.
 *
 * So the joining half is squeezed into one strip along the top and the rest of
 * the screen is names, sized to hold a class of forty without scrolling.
 */

.lobby { justify-content: flex-start; gap: 16px; padding: 14px 18px 20px; }

.lobby-bar {
  width: 100%;
  display: flex;
  align-items: center;
  gap: clamp(10px, 1.6vw, 40px);
  flex-wrap: wrap;
  justify-content: center;
  background: var(--panel);
  border: 1px solid #14465f;
  border-radius: 20px;
  padding: 14px 22px;
}

.lobby-logo {
  width: clamp(140px, 15vw, 260px);
  height: auto;
  flex: none;
}

.lobby-join { text-align: left; }

.lobby-label {
  margin: 0;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: .1em;
  font-size: .72rem;
}

.lobby-url {
  margin: 0 0 6px;
  font-size: clamp(1rem, 2vw, 1.5rem);
  color: var(--paper);
}

.lobby-code {
  margin: 0;
  font-size: clamp(2.4rem, 5.6vw, 5rem);
  line-height: 1;
  letter-spacing: .1em;
  color: var(--gold);
  font-weight: 700;
}

.lobby-qr { display: flex; flex-direction: column; align-items: center; gap: 6px; }

.qr {
  background: #fff;
  padding: 8px;
  border-radius: 12px;
  line-height: 0;
}

.qr.small { padding: 7px; }
.qr img, .qr canvas { display: block; }

.qr-caption {
  margin: 0;
  color: var(--muted);
  font-size: .72rem;
  text-align: center;
  line-height: 1.25;
  text-transform: uppercase;
  letter-spacing: .06em;
}

.qr-fallback {
  display: block;
  padding: 8px;
  color: var(--navy);
  font-size: .62rem;
  word-break: break-all;
  max-width: 150px;
  line-height: 1.3;
}

/* --- the names ------------------------------------------------------------ */

.lobby-body {
  flex: 1;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  min-height: 0;
}

.lobby-count { margin: 0; color: var(--cyan); font-size: 1.1rem; font-weight: 600; }
.lobby-count b { font-size: 1.5rem; }

.name-cards {
  list-style: none;
  margin: 0;
  padding: 0;
  width: 100%;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(clamp(120px, 12vw, 190px), 1fr));
  gap: 8px;
  align-content: start;
  overflow-y: auto;
  flex: 1;
  min-height: 0;
}

/* One name, sized so forty of them still fit on a projector and each is
 * readable from a desk. */
.name-card {
  background: rgba(39, 207, 228, .1);
  border: 1px solid #1b5f7a;
  border-radius: 12px;
  padding: 10px 12px;
  text-align: center;
  font-size: clamp(.95rem, 1.3vw, 1.3rem);
  font-weight: 600;
  color: var(--paper);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  animation: name-in .35s ease-out;
}

@keyframes name-in {
  from { transform: scale(.85); opacity: 0; }
  to   { transform: scale(1);   opacity: 1; }
}

.lobby-waiting { color: var(--muted); margin: 0; }

.lobby-actions { display: flex; gap: 14px; flex-wrap: wrap; justify-content: center; }

/* --- running, on the projector -------------------------------------------- */

.running { justify-content: flex-start; gap: 18px; padding-top: 22px; }

.run-head {
  display: flex;
  align-items: baseline;
  gap: 26px;
  flex-wrap: wrap;
  justify-content: center;
}

.run-clock {
  font-size: clamp(3.5rem, 14vw, 7rem);
  line-height: 1;
  color: var(--cyan);
  font-variant-numeric: tabular-nums;
  font-weight: 700;
}

.run-clock.low { color: var(--bad); }
.run-code { color: var(--muted); font-size: 1.1rem; }
.run-code b { color: var(--gold); font-size: 1.5rem; letter-spacing: .1em; }

.scoreboard {
  list-style: none;
  counter-reset: rank;
  margin: 0;
  padding: 0;
  width: min(760px, 100%);
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 8px;
}

.scoreboard li {
  counter-increment: rank;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  padding: 12px 16px;
  border-radius: 12px;
  background: rgba(10, 46, 67, .75);
  font-size: 1.2rem;
}

.scoreboard li::before {
  content: counter(rank);
  color: var(--muted);
  font-size: .9rem;
  min-width: 1.6em;
}

.scoreboard li:nth-child(1) { background: rgba(255, 194, 71, .18); }
.scoreboard li b { color: var(--gold); font-size: 1.4rem; }

.run-actions { display: flex; gap: 12px; flex-wrap: wrap; justify-content: center; }

/* --- the teacher's phone -------------------------------------------------- */

.phone-view { justify-content: flex-start; padding-top: 20px; }
.phone-note { color: var(--muted); font-size: .85rem; margin: 0; text-align: center; }
.roster.wide { width: min(520px, 100%); max-height: none; }

/* --- the level picker ----------------------------------------------------- */

.sheet {
  position: fixed;
  inset: 0;
  background: rgba(2, 12, 23, .78);
  display: grid;
  place-items: end center;
  z-index: 40;
  padding: 0;
}

.sheet-card {
  background: var(--panel);
  border-radius: 22px 22px 0 0;
  padding: 22px;
  width: min(520px, 100%);
  max-height: 84vh;
  overflow-y: auto;
  position: relative;
  border: 1px solid #14465f;
}

.sheet-card h3 { margin: 0 0 14px; color: var(--cyan); font-size: 1.3rem; }

.sheet-close {
  position: absolute;
  top: 12px;
  right: 14px;
  background: none;
  border: 0;
  color: var(--muted);
  font-size: 1.8rem;
  line-height: 1;
  cursor: pointer;
  padding: 4px 10px;
}

.level-list { display: flex; flex-direction: column; gap: 5px; }

.level-band {
  margin: 12px 0 2px;
  color: var(--muted);
  font-size: .75rem;
  text-transform: uppercase;
  letter-spacing: .1em;
}

.level-option {
  font-family: inherit;
  font-size: 1rem;
  text-align: left;
  padding: 13px 15px;
  min-height: 48px;
  border-radius: 10px;
  border: 2px solid transparent;
  background: rgba(255, 255, 255, .05);
  color: var(--paper);
  cursor: pointer;
}

.level-option:hover { background: rgba(39, 207, 228, .12); }
.level-option.current { border-color: var(--gold); color: var(--gold); }

@media (min-width: 900px) {
  .lobby-code { font-size: 6rem; }
}

/* The redeal button while it is waiting to be confirmed. */
.ghost-btn.arming {
  border-color: var(--gold);
  color: var(--gold);
  background: rgba(255, 194, 71, .1);
}

/* --- the leader-only page -------------------------------------------------
 * Read at arm's length on a phone while standing in a noisy room, so it is
 * dense, tappable, and says what it is for at the top.
 */

.levels-page { justify-content: flex-start; padding: 18px 16px 30px; gap: 12px; }

.levels-head {
  width: min(560px, 100%);
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 14px;
}

.levels-intro {
  margin: 6px 0 0;
  color: var(--muted);
  font-size: .88rem;
  line-height: 1.45;
  max-width: 40ch;
}

.levels-code { color: var(--muted); font-size: .8rem; white-space: nowrap; }
.levels-code b { color: var(--gold); font-size: 1.1rem; letter-spacing: .08em; }

.levels-status {
  margin: 0;
  min-height: 1.2em;
  color: var(--gold);
  font-size: .88rem;
  width: min(560px, 100%);
}

.levels-empty { color: var(--muted); font-size: .9rem; text-align: center; }

.roster li.locked { opacity: .6; cursor: default; }

/* --- the teacher's own QR -------------------------------------------------
 * In the header, on the far left, half the size of the class's join code.
 * It used to sit in the bottom-left corner of the screen, where it covered
 * the name of whichever child landed there. Small and away from the big code
 * so children scan the right one.
 */
.leader-corner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  flex: none;
  opacity: .82;
}

.leader-corner:hover { opacity: 1; }
.leader-corner .qr { padding: 5px; border-radius: 8px; }
.leader-corner .qr-caption { font-size: .56rem; }

/* --- the leader-only roster, on a phone -----------------------------------
 * Read and tapped one-handed, standing up, in a room that is not quiet. The
 * earlier version was a tight two-column list: fine on a laptop, and on a
 * phone close enough that a thumb aimed at one child could hand a different
 * child a new puzzle with nothing on screen to say so. Scrolling is cheaper
 * than that mistake.
 */

.player-cards {
  list-style: none;
  margin: 0;
  padding: 0;
  width: min(560px, 100%);
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 12px;
}

.player-card {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 14px 16px;
  min-height: 66px;
  justify-content: center;
  border-radius: 14px;
  border: 1px solid #1b5f7a;
  background: rgba(39, 207, 228, .08);
  cursor: pointer;
  transition: background .12s ease, border-color .12s ease;
  -webkit-tap-highlight-color: transparent;
}

.player-card:hover,
.player-card:focus-visible {
  background: rgba(39, 207, 228, .18);
  border-color: var(--cyan);
  outline: none;
}

.player-card:active { background: rgba(39, 207, 228, .26); }

.player-name {
  font-size: 1.15rem;
  font-weight: 600;
  color: var(--paper);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Small, and underneath - it is the answer to "what will they get", not a
 * label anybody should read first. */
.player-level {
  font-size: .78rem;
  color: var(--cyan);
  opacity: .85;
  line-height: 1.3;
}

.player-card.locked {
  cursor: default;
  border-color: #17506d;
  background: rgba(255, 255, 255, .04);
}

.player-card.locked:hover { background: rgba(255, 255, 255, .04); border-color: #17506d; }

/* Shown in place of the scoreboard when the teacher chose to keep scores off
 * the projector, so the space reads as deliberate rather than broken. */
.scoreboard .board-hidden {
  justify-content: center;
  opacity: .6;
  font-style: italic;
}

/* --- teams -----------------------------------------------------------------
 * The colour is carried on --team, set per card from the same list the server
 * uses, so a team is recognisable at a glance from the back of a room.
 */
.teams-area { width: 100%; display: flex; flex-direction: column; gap: 14px; }

.team-pool {
  border: 2px dashed rgba(39, 207, 228, .35);
  border-radius: 14px;
  padding: 10px 12px;
  transition: background .12s ease, border-color .12s ease;
}
.team-pool.empty { opacity: .55; }
.team-pool.over { background: rgba(39, 207, 228, .12); border-color: var(--cyan); }

.pool-label {
  margin: 0 0 8px;
  font-size: .82rem;
  opacity: .75;
  text-align: center;
}

.team-cards {
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
}

.team-card {
  border: 3px solid var(--team, var(--cyan));
  border-radius: 16px;
  padding: 10px 10px 12px;
  background: color-mix(in srgb, var(--team) 12%, transparent);
  min-height: 120px;
  transition: background .12s ease, transform .12s ease;
}
.team-card.over {
  background: color-mix(in srgb, var(--team) 28%, transparent);
  transform: translateY(-2px);
}

.team-name {
  margin: 0;
  text-align: center;
  font-weight: 800;
  color: var(--team);
  font-size: 1.05rem;
}

.team-tally { margin: 2px 0 8px; text-align: center; font-size: .78rem; opacity: .7; }

.team-list { margin: 0; }

/* A name you can pick up. `held` is the tap-to-move state - the teacher has
 * this child in hand and the next tap on a team drops them there. */
.name-card.draggable { cursor: grab; }
.name-card.dragging { opacity: .45; }
.name-card.held {
  outline: 3px solid var(--gold);
  outline-offset: 2px;
  transform: scale(1.04);
}

.scoreboard .team-score { border-left: 6px solid var(--team); }
.scoreboard .team-score small { display: block; font-size: .72rem; opacity: .65; font-weight: 400; }

/* --- the finale ------------------------------------------------------------
 * A projector screen at the end of a lesson. Everything here is sized to be
 * read from the back of a classroom, and the winner is deliberately several
 * times the size of everybody else.
 */
.screen.finale {
  position: relative;
  justify-content: flex-start;
  overflow: hidden;
  background:
    radial-gradient(1200px 700px at 50% -10%, rgba(255, 194, 71, .16), transparent 70%),
    var(--bg, #081826);
}

/* The house lights, on for the winner and then off again. */
.screen.finale.lit::before {
  content: '';
  position: absolute;
  inset: -20%;
  pointer-events: none;
  background:
    conic-gradient(from 0deg,
      rgba(255, 194, 71, .16) 0deg, transparent 25deg,
      rgba(58, 169, 255, .16) 60deg, transparent 90deg,
      rgba(63, 217, 138, .16) 140deg, transparent 170deg,
      rgba(255, 107, 107, .16) 220deg, transparent 250deg,
      rgba(255, 194, 71, .16) 320deg, transparent 360deg);
  animation: sweep 7s linear infinite;
}
@keyframes sweep { to { transform: rotate(360deg); } }

.fireworks { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }

.finale-inner {
  position: relative;
  z-index: 2;
  width: min(980px, 100%);
  max-height: 100dvh;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 6px 14px 12px;
}

.finale-banner {
  margin: 0;
  font-size: clamp(1.6rem, 4.6vw, 3rem);
  font-weight: 900;
  letter-spacing: .5px;
  color: var(--gold);
  text-align: center;
  text-shadow: 0 0 28px rgba(255, 194, 71, .35);
}

/* --- a place -------------------------------------------------------------- */

.place-card {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 14px;
  width: 100%;
  padding: 8px 16px;
  border-radius: 14px;
  border-left: 8px solid var(--team, var(--cyan));
  background: rgba(10, 46, 67, .72);
  animation: slide-in .45s cubic-bezier(.2, .9, .3, 1.3) both;
}
@keyframes slide-in {
  from { opacity: 0; transform: translateY(26px) scale(.96); }
  to   { opacity: 1; transform: none; }
}

.place-no { font-weight: 900; opacity: .75; font-size: 1.05rem; min-width: 2.6em; }
.place-name { font-weight: 700; font-size: 1.2rem; text-align: left; }
.place-name small { display: block; font-size: .72rem; opacity: .6; font-weight: 400; }
.place-score { font-size: 1.5rem; color: var(--gold); }

.places { width: 100%; display: flex; flex-direction: column; gap: 8px; }

/* --- the winner ----------------------------------------------------------- */

.crown { width: 100%; }

.crown .place-card.winner {
  grid-template-columns: 1fr;
  justify-items: center;
  text-align: center;
  gap: 4px;
  padding: clamp(10px, 2.4vh, 20px) 18px;
  border: 4px solid var(--team, var(--gold));
  border-left-width: 4px;
  border-radius: 22px;
  background:
    linear-gradient(180deg, rgba(255, 194, 71, .18), rgba(10, 46, 67, .85));
  box-shadow: 0 0 60px rgba(255, 194, 71, .3);
}
.crown .place-card.winner .place-no {
  font-size: clamp(1rem, 2.4vw, 1.4rem);
  color: var(--gold);
  opacity: 1;
  letter-spacing: 2px;
}
.crown .place-card.winner .place-name {
  font-size: clamp(2rem, 7vw, 4.4rem);
  line-height: 1.05;
  text-align: center;
}
.crown .place-card.winner .place-score { font-size: clamp(1.6rem, 4vw, 2.6rem); }

.crown.land { animation: crash-in .7s cubic-bezier(.2, 1.1, .3, 1.2) both; }
@keyframes crash-in {
  0%   { opacity: 0; transform: scale(.3) rotate(-6deg); }
  60%  { opacity: 1; transform: scale(1.08) rotate(2deg); }
  100% { transform: none; }
}

/* --- the mascot ----------------------------------------------------------- */

.finale-actions { display: flex; gap: 12px; margin-top: 6px; }

@media (prefers-reduced-motion: reduce) {
  .screen.finale.lit::before,
  .crown.land,
  .place-card { animation: none !important; }
}

/* --- the mascot's routine --------------------------------------------------
 *
 * One flat picture, so his arms and legs cannot move independently - they are
 * folded across his chest in the artwork and cutting them out leaves holes.
 * What sells a dance without a rig is squash and stretch, a change of move
 * every couple of beats, and a shadow that reacts: an audience reads weight
 * and rhythm long before it notices that an elbow never bends.
 *
 * Eight beats, roughly two seconds: bounce, bounce, spin, land, lean, lean,
 * jump, land. Enough variety that it does not read as a loop straight away.
 */
.mascot-stage {
  position: relative;
  /* Sized off the screen's HEIGHT, not its width. He is the tallest thing on
   * this screen after the winner's card, and at 300px he pushed second and
   * third place off the bottom of a classroom Chromebook. */
  height: clamp(70px, 22vh, 200px);
  width: auto;
  aspect-ratio: 300 / 469;
  opacity: 0;
  transition: opacity .3s ease;
  display: flex;
  align-items: flex-end;
  justify-content: center;
}
.mascot-stage.dancing { opacity: 1; }

.mascot-stage .mascot {
  width: 100%;
  height: auto;
  transform-origin: 50% 100%;      /* he pivots on his feet, like a person */
  will-change: transform;
}

.mascot-stage.dancing .mascot { animation: routine 2.1s steps(1, end) infinite; }

/* Each beat is its own little animation so the moves have different feels -
 * a spin should whip round, a landing should thump. */
@keyframes routine {
  0%    { transform: translateY(0) rotate(-6deg) scale(1, 1); }
  6%    { transform: translateY(-16%) rotate(4deg) scale(.94, 1.08); }
  12%   { transform: translateY(0) rotate(-3deg) scale(1.08, .92); }
  18%   { transform: translateY(-14%) rotate(6deg) scale(.95, 1.06); }
  25%   { transform: translateY(0) rotate(0deg) scale(1.06, .94); }

  /* the spin */
  31%   { transform: translateY(-10%) rotateY(180deg) rotate(4deg) scale(1, 1); }
  37%   { transform: translateY(-4%) rotateY(360deg) rotate(-4deg) scale(1.02, .98); }
  43%   { transform: translateY(0) rotate(0deg) scale(1.1, .9); }

  /* the lean, side to side */
  50%   { transform: translateY(-6%) rotate(-14deg) scale(1, 1); }
  57%   { transform: translateY(-6%) rotate(14deg) scale(1, 1); }
  64%   { transform: translateY(-6%) rotate(-12deg) scale(1, 1); }
  70%   { transform: translateY(0) rotate(0deg) scale(1.08, .92); }

  /* the big jump */
  78%   { transform: translateY(-34%) rotate(8deg) scale(.9, 1.14); }
  86%   { transform: translateY(-30%) rotate(-8deg) scale(.92, 1.1); }
  93%   { transform: translateY(0) rotate(0deg) scale(1.14, .86); }
  100%  { transform: translateY(0) rotate(-6deg) scale(1, 1); }
}

/* The shadow is what makes the jumps read as height rather than as the
 * picture getting smaller. */
.mascot-shadow {
  position: absolute;
  bottom: -2%;
  width: 62%;
  height: 8%;
  border-radius: 50%;
  background: radial-gradient(ellipse at center, rgba(0, 0, 0, .5), transparent 70%);
  filter: blur(1px);
}
.mascot-stage.dancing .mascot-shadow { animation: shadow 2.1s steps(1, end) infinite; }

@keyframes shadow {
  0%, 12%, 25%, 43%, 70%, 93%, 100% { transform: scale(1); opacity: .5; }
  6%, 18%   { transform: scale(.82); opacity: .34; }
  31%, 37%  { transform: scale(.88); opacity: .38; }
  50%, 57%, 64% { transform: scale(.92); opacity: .42; }
  78%, 86%  { transform: scale(.6); opacity: .22; }
}

@media (prefers-reduced-motion: reduce) {
  .mascot-stage.dancing .mascot,
  .mascot-stage.dancing .mascot-shadow { animation: none; }
}

/* With a big class the runners-up would run off the bottom, so the reveal
 * shows the top few and counts the rest. Everybody's score is on the board
 * during the game; this screen is for the podium. */
.places-more {
  margin: 2px 0 0;
  font-size: .82rem;
  opacity: .6;
  text-align: center;
}

/* --- word-length checkboxes -------------------------------------------------
 * Five big square buttons rather than five tiny ticks: this is set up on a
 * teacher's laptop in a hurry, and a tile-shaped target also shows at a glance
 * which board the class is about to get. */
.field.lengths { border: 0; padding: 0; margin: 0; }
.length-boxes { display: flex; gap: 8px; margin-top: 6px; }
.length-box { position: relative; cursor: pointer; }
.length-box input { position: absolute; opacity: 0; pointer-events: none; }
.length-box span {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  border-radius: 10px;
  border: 2px solid rgba(39, 207, 228, .45);
  font-weight: 800;
  font-size: 1.15rem;
  color: rgba(255, 255, 255, .55);
  transition: background .12s ease, color .12s ease, border-color .12s ease;
}
.length-box input:checked + span {
  background: linear-gradient(180deg, var(--tile-top, #fffdf0), var(--tile-bottom, #ffe5a8));
  border-color: var(--gold-deep, #d9a02a);
  color: var(--ink, #16222e);
}
.length-box input:focus-visible + span { outline: 3px solid var(--cyan); outline-offset: 2px; }

/* A link dressed as a button (ZoodleBug Home) - same size and shape as the
 * real buttons beside it, and no underline. */
a.ghost-btn, a.big-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
}

.done-actions { flex-wrap: wrap; justify-content: center; }

/* --- the pencil on each name ------------------------------------------------
 * Small and quiet: the projector is showing these names to the class, so the
 * pencil is there for the teacher without competing with the name itself. */
.name-card {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}
.name-card .name-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
.rename-btn {
  flex: none;
  width: 30px;
  height: 30px;
  padding: 0;
  border-radius: 8px;
  border: 1px solid #1b5f7a;
  background: rgba(255, 255, 255, .04);
  color: var(--muted, #8fb2c4);
  font-size: .95rem;
  line-height: 1;
  cursor: pointer;
  touch-action: manipulation;
}
.rename-btn:hover, .rename-btn:focus-visible { color: var(--gold, #ffc247); border-color: var(--gold, #ffc247); }

/* --- the logo, on every teacher screen ---------------------------------------
 * The game's own artwork, not a header bar: the setup page and the phone page
 * wear it modestly, and the projector during a game wears it big. */
.setup-logo {
  width: clamp(170px, 34vw, 300px);
  height: auto;
  filter: drop-shadow(0 10px 22px rgba(0, 0, 0, .45));
}

.levels-logo {
  width: clamp(140px, 42vw, 220px);
  height: auto;
  filter: drop-shadow(0 8px 18px rgba(0, 0, 0, .4));
}

/* --- the projector during a game ---------------------------------------------
 * A projector is wide, and the scores rarely fill it. The logo takes the left
 * half at full size; the clock, the scores and the buttons take the right.
 * On a tall or narrow screen the logo sits on top instead. */
.running { justify-content: flex-start; gap: 18px; padding-top: 18px; }

.run-layout {
  flex: 1;
  width: min(1500px, 100%);
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
  align-items: center;
  gap: clamp(18px, 4vw, 60px);
}

.run-brand { display: flex; justify-content: center; align-items: center; min-height: 0; }

.run-logo {
  width: 100%;
  max-width: 960px;
  max-height: 78vh;
  height: auto;
  object-fit: contain;
  filter: drop-shadow(0 16px 34px rgba(0, 0, 0, .5));
}

.run-main {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
  min-width: 0;
}

.run-main .scoreboard { width: 100%; }

@media (max-aspect-ratio: 1/1), (max-width: 760px) {
  .run-layout { grid-template-columns: 1fr; align-content: start; }
  .run-logo { width: min(78vw, 520px); max-height: 34vh; }
}

/* --- the setup page on a computer --------------------------------------------
 * It used to be one narrow column down the middle of a wide screen, long
 * enough to scroll. On a computer it is now the logo, big, on the left and
 * the choices in two columns on the right - all of it on one screen. */
@media (min-width: 1000px) {
  .setup {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr);
    grid-template-areas:
      "logo title"
      "logo form"
      "home form";
    align-content: center;
    align-items: center;
    column-gap: clamp(24px, 4vw, 64px);
    row-gap: 12px;
    max-width: 1500px;
    margin: 0 auto;
    padding: 12px 32px;
  }

  .setup-logo {
    grid-area: logo;
    width: 100%;
    max-width: 640px;
    max-height: 80vh;
    object-fit: contain;
    justify-self: center;
  }

  .setup .page-title { grid-area: title; margin: 0; }

  .setup-card {
    grid-area: form;
    width: 100%;
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-items: start;
    gap: 10px 22px;
    padding: 16px 22px;
  }

  .setup-card .join-msg { min-height: 0; }
  .setup-card .join-msg:empty { display: none; }

  .setup-card .field.lengths,
  .setup-card .join-msg,
  .setup-card #setupBtn { grid-column: 1 / -1; }

  .setup-card .select { min-height: 46px; padding: 10px 12px; }
  .setup-card .field-note { font-size: .74rem; line-height: 1.3; }

  .setup > .ghost-btn.quiet { grid-area: home; justify-self: center; align-self: end; margin: 0; }
}

.howto-inline {
  margin-left: 12px;
  font-size: .95rem;
  color: var(--muted);
  text-decoration: underline;
  vertical-align: middle;
  white-space: nowrap;
}
#lobbyHowTo { text-decoration: none; }

.remove-btn:hover, .remove-btn:focus-visible { color: var(--bad, #ff8b7a); border-color: var(--bad, #ff8b7a); }

/* --- the Leader Only page: tiles and removing ------------------------------- */
.player-card { display: flex; align-items: center; gap: 10px; }
.player-card .player-main { flex: 1; min-width: 0; display: flex; flex-direction: column; cursor: pointer; }
.player-card.locked .player-main { cursor: default; }
.player-tools { display: flex; align-items: center; gap: 6px; flex: none; }
.tile-step, .remove-player {
  width: 40px;
  height: 40px;
  border-radius: 10px;
  border: 2px solid #17506d;
  background: var(--panel-soft, #0e3b55);
  color: var(--cyan, #27cfe4);
  font-family: inherit;
  font-size: 1.3rem;
  font-weight: 700;
  cursor: pointer;
  touch-action: manipulation;
}
.tile-step:disabled, .remove-player:disabled { opacity: .35; cursor: default; }
.tile-count { display: flex; flex-direction: column; align-items: center; min-width: 46px; line-height: 1.05; }
.tile-count small { font-size: .62rem; color: var(--muted, #8fb2c4); text-transform: uppercase; letter-spacing: .06em; }
.tile-count b { font-size: 1.3rem; color: var(--gold, #ffc247); }
.remove-player { margin-left: 6px; color: var(--muted, #8fb2c4); font-size: 1rem; }
.remove-player:hover, .remove-player:focus-visible { color: var(--bad, #ff8b7a); border-color: var(--bad, #ff8b7a); }

/* --- the final screen: places, top scores and the logo -------------------------
 * One column normally. With the teacher's "top scores" list switched on it is
 * two: the places (and the winner) on the left, the best words or equations on
 * the right. The logo sits at the bottom, in the middle, either way. */
.finale-grid {
  position: relative;
  z-index: 2;
  width: min(1500px, 100%);
  flex: 1;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: 1fr auto;
  justify-items: center;
  gap: 8px 32px;
}
.finale-grid .finale-inner { grid-column: 1; }
.finale-grid.with-top { grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr); }
.finale-grid.with-top .finale-inner { width: 100%; }

.finale-top {
  width: 100%;
  align-self: start;
  margin-top: 8px;
  background: rgba(10, 46, 67, .72);
  border: 2px solid #17506d;
  border-radius: 22px;
  padding: 16px 18px;
}
.finale-top-title {
  margin: 0 0 12px;
  text-align: center;
  color: var(--cyan);
  font-size: clamp(1.3rem, 2.6vw, 2rem);
}
.finale-top-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.top-row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  border-radius: 14px;
  background: rgba(255, 255, 255, .05);
  opacity: 0;
  transform: translateY(8px);
  transition: opacity .35s ease, transform .35s ease;
}
.top-row.shown { opacity: 1; transform: none; }
.top-row:first-child { background: rgba(255, 194, 71, .16); }
.top-rank { color: var(--muted); font-weight: 700; font-size: clamp(1rem, 1.8vw, 1.4rem); min-width: 1.4em; text-align: center; }
.top-who { display: flex; flex-direction: column; min-width: 0; }
.top-who b { font-size: clamp(1.05rem, 2vw, 1.6rem); color: var(--paper); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.top-who small { font-size: clamp(.9rem, 1.6vw, 1.25rem); color: var(--cyan); letter-spacing: .04em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.top-points { font-size: clamp(1.3rem, 2.6vw, 2.1rem); font-weight: 800; color: var(--gold); font-variant-numeric: tabular-nums; }

.finale-logo {
  grid-column: 1 / -1;
  align-self: end;
  height: clamp(60px, 13vh, 150px);
  width: auto;
  pointer-events: none;
  filter: drop-shadow(0 10px 22px rgba(0, 0, 0, .45));
}

@media (max-width: 800px) {
  .finale-grid.with-top { grid-template-columns: minmax(0, 1fr); }
}
@media (prefers-reduced-motion: reduce) {
  .top-row { transition: none; }
}

/* Locked only means the puzzle level can't change; the tile buttons and the
 * remove button still work, so only the level text is dimmed. */
.player-card.locked .player-main { opacity: .65; }

/* --- three columns when the top-scores list is on ------------------------------
 * Places on the left, the logo big in the middle, the best words or equations
 * on the right. All sized from the screen, for a classroom computer or
 * projector at any resolution. */
.finale-grid.with-top {
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  width: min(1800px, 100%);
  column-gap: clamp(16px, 2.5vw, 48px);
}
.finale-grid.with-top .finale-inner { grid-column: 1; grid-row: 1; }
.finale-grid.with-top .finale-top { grid-column: 3; grid-row: 1; }
.finale-grid.with-top .finale-logo {
  grid-column: 2;
  grid-row: 1;
  align-self: start;
  margin-top: clamp(20px, 6vh, 80px);
  height: auto;
  width: clamp(200px, 24vw, 460px);
}
@media (max-width: 800px) {
  .finale-grid.with-top { grid-template-columns: minmax(0, 1fr); }
  .finale-grid.with-top .finale-logo,
  .finale-grid.with-top .finale-top { grid-column: 1; grid-row: auto; }
}
/* The buttons under the places wrap rather than run off the edge when the
 * column is narrow. */
.finale-actions { flex-wrap: wrap; justify-content: center; }

/* --- team play (Oct 2026) ---------------------------------------------------- */
.field-static { margin: 0; font-size: .95rem; line-height: 1.4; color: var(--paper); }
.field-static b { color: var(--gold); }
.team-card.new-team { border-style: dashed; opacity: .75; display: flex; flex-direction: column; justify-content: center; }
.team-card.new-team.over { opacity: 1; }

/* --- the next round (Tim, Oct 2026): keep the teams or shuffle them ---------
 * Two big choices at the top of the round's settings. */
.field.next-teams { border: 0; padding: 0; margin: 0; }
.next-team-choices { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 6px; }
.next-team-choice { position: relative; cursor: pointer; }
.next-team-choice input { position: absolute; opacity: 0; pointer-events: none; }
.next-team-choice span {
  display: flex;
  flex-direction: column;
  gap: 4px;
  height: 100%;
  padding: 14px 16px;
  border-radius: 14px;
  border: 2px solid rgba(39, 207, 228, .45);
  color: var(--paper);
  transition: background .12s ease, border-color .12s ease, color .12s ease;
}
.next-team-choice b { font-size: 1.1rem; }
.next-team-choice small { font-size: .85rem; color: var(--muted); }
.next-team-choice input:checked + span {
  background: linear-gradient(180deg, var(--gold), var(--gold-deep));
  border-color: var(--gold);
  color: var(--ink);
}
.next-team-choice input:checked + span small { color: rgba(22, 34, 46, .8); }
.next-team-choice input:focus-visible + span { outline: 3px solid var(--cyan); outline-offset: 2px; }
#nextBackBtn { width: 100%; grid-column: 1 / -1; }
@media (max-width: 480px) {
  .next-team-choices { grid-template-columns: 1fr; }
}

/* --- the live team scoreboard (Tim, Oct 2026) --------------------------------
 * One row per team, best first: rank (a crown for the leader), the team in its
 * colour, a bar in proportion to the leader's points, and the points. Rows
 * slide when teams change places; a team that climbs glows for a moment and
 * its points pop when they go up. Read from the back of a classroom. */
.scoreboard.team-board { grid-template-columns: 1fr; gap: 10px; counter-reset: none; }
.scoreboard.team-board li.team-row {
  counter-increment: none;
  display: grid;
  grid-template-columns: 3.2rem 1fr auto;
  align-items: center;
  gap: 16px;
  padding: 14px 20px;
  border-radius: 16px;
  background: linear-gradient(90deg, color-mix(in srgb, var(--team) 22%, rgba(10, 46, 67, .85)), rgba(10, 46, 67, .8));
  border-left: 8px solid var(--team);
  transition: transform .6s cubic-bezier(.2, .8, .2, 1), box-shadow .3s ease;
}
.scoreboard.team-board li.team-row::before { content: none; }
.team-row .tr-rank {
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  border-radius: 50%;
  background: rgba(255, 255, 255, .1);
  font-size: 1.5rem;
  font-weight: 800;
  color: var(--paper);
}
.team-row.leader .tr-rank { background: rgba(255, 194, 71, .25); font-size: 1.8rem; }
.team-row .tr-main { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.team-row .tr-name { font-size: 1.5rem; font-weight: 700; color: var(--paper); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.team-row .tr-name small { margin-left: 10px; font-size: .85rem; font-weight: 400; opacity: .65; }
.team-row .tr-bar { height: 16px; border-radius: 999px; background: rgba(255, 255, 255, .08); overflow: hidden; }
.team-row .tr-bar i {
  display: block;
  height: 100%;
  width: 0;
  border-radius: inherit;
  background: linear-gradient(90deg, var(--team), color-mix(in srgb, var(--team) 60%, #fff));
  box-shadow: 0 0 12px color-mix(in srgb, var(--team) 70%, transparent);
  transition: width .8s cubic-bezier(.2, .8, .2, 1);
}
.team-row .tr-points {
  font-size: 2.2rem;
  font-weight: 800;
  color: var(--gold);
  font-variant-numeric: tabular-nums;
  min-width: 3ch;
  text-align: right;
}
.team-row.leader { box-shadow: 0 0 0 2px rgba(255, 194, 71, .55), 0 8px 26px rgba(255, 194, 71, .18); }
.team-row .tr-points.bump { animation: tr-bump .5s ease; }
.team-row.climb { animation: tr-climb 1.2s ease; }
@keyframes tr-bump { 0% { transform: scale(1); } 40% { transform: scale(1.3); color: #fff; } 100% { transform: scale(1); } }
@keyframes tr-climb { 0% { box-shadow: 0 0 0 0 var(--team); } 30% { box-shadow: 0 0 0 4px var(--team), 0 0 30px var(--team); } 100% { box-shadow: 0 0 0 0 transparent; } }
@media (prefers-reduced-motion: reduce) {
  .scoreboard.team-board li.team-row, .team-row .tr-bar i { transition: none; }
  .team-row .tr-points.bump, .team-row.climb { animation: none; }
}

/* --- one screen, always (Tim, Oct 2026) -------------------------------------
 * The join screen, the game and the results each fit the projector with no
 * scrolling, however many children there are: the screen is exactly one
 * viewport tall, and leader.js shrinks the names, teams and scores
 * (--ls / --rs, 1 = full size) until everything fits.
 *
 * The join screen's header is compact: a smaller code and QR in one strip,
 * so the room's names get the space. */
.leader .screen.lobby,
.leader .screen.running {
  height: 100dvh;
  min-height: 0;
  overflow: hidden;
  box-sizing: border-box;
}
.lobby { gap: 10px; padding: 10px 16px 12px; padding-top: max(10px, var(--zb-home-top, 0px)); }
.lobby-bar {
  flex: none;
  padding: 8px 18px;
  gap: clamp(10px, 2vw, 32px);
  border-radius: 16px;
  flex-wrap: nowrap;
}
.lobby-logo { width: auto; height: clamp(54px, 9vh, 92px); }
.lobby-join { display: grid; grid-template-columns: auto auto; column-gap: 18px; align-items: baseline; }
.lobby-join .lobby-label { grid-column: 1; }
.lobby-url { margin: 0; font-size: clamp(1rem, 2.6vh, 1.5rem); }
.lobby-code { font-size: clamp(1.8rem, 6vh, 3.4rem); letter-spacing: .08em; }
@media (min-width: 900px) { .lobby-code { font-size: clamp(1.8rem, 6vh, 3.4rem); } }
.lobby-qr { flex-direction: row; gap: 8px; }
.lobby-qr .qr { padding: 5px; border-radius: 8px; }
.lobby-qr .qr img, .lobby-qr .qr canvas { width: clamp(64px, 11vh, 104px) !important; height: auto !important; }
.leader-corner .qr img, .leader-corner .qr canvas { width: clamp(40px, 6vh, 56px) !important; height: auto !important; }
.lobby-body { gap: calc(8px * var(--ls, 1)); overflow: hidden; }
.lobby-count { font-size: calc(1.05rem * var(--ls, 1)); }
.teams-area { flex: 1; min-height: 0; overflow-y: auto; gap: calc(12px * var(--ls, 1)); }
.lobby-actions { flex: none; gap: 10px; }
.lobby-actions .big-btn, .lobby-actions .ghost-btn { padding-top: 10px; padding-bottom: 10px; }
.name-card {
  font-size: calc(clamp(.95rem, 1.3vw, 1.3rem) * var(--ls, 1));
  padding: calc(9px * var(--ls, 1)) calc(11px * var(--ls, 1));
}
.name-cards { gap: calc(8px * var(--ls, 1)); grid-template-columns: repeat(auto-fill, minmax(calc(clamp(120px, 12vw, 190px) * var(--ls, 1)), 1fr)); }
.team-cards { gap: calc(12px * var(--ls, 1)); grid-template-columns: repeat(auto-fit, minmax(calc(190px * var(--ls, 1)), 1fr)); }
.team-card { padding: calc(8px * var(--ls, 1)); min-height: 0; border-width: calc(3px * var(--ls, 1)); }
.team-name { font-size: calc(1.05rem * var(--ls, 1)); }
.team-tally { margin: 0 0 calc(6px * var(--ls, 1)); font-size: calc(.78rem * var(--ls, 1)); }
.team-pool { padding: calc(8px * var(--ls, 1)) calc(12px * var(--ls, 1)); }
.team-pool.empty { display: none; }
.pool-label { font-size: calc(.82rem * var(--ls, 1)); margin-bottom: calc(6px * var(--ls, 1)); }
.rename-btn, .remove-btn { width: calc(30px * var(--ls, 1)); height: calc(30px * var(--ls, 1)); font-size: calc(.95rem * var(--ls, 1)); }

/* The game on the projector: the scoreboard and clock shrink to fit. */
.running { gap: 10px; padding-top: max(10px, var(--zb-home-top, 0px)); padding-bottom: 10px; }
.run-layout { min-height: 0; }
.run-logo { max-height: min(78vh, calc(78vh * var(--rs, 1) + 10vh)); }
.run-main { gap: calc(14px * var(--rs, 1)); }
.run-head { align-items: center; gap: calc(22px * var(--rs, 1)); }
.run-clock { font-size: calc(clamp(3.5rem, 14vw, 7rem) * var(--rs, 1)); }
.scoreboard.team-board { gap: calc(10px * var(--rs, 1)); }
.scoreboard.team-board li.team-row { padding: calc(14px * var(--rs, 1)) calc(20px * var(--rs, 1)); gap: calc(16px * var(--rs, 1)); }
.team-row .tr-rank { width: calc(3rem * var(--rs, 1)); height: calc(3rem * var(--rs, 1)); font-size: calc(1.5rem * var(--rs, 1)); }
.team-row.leader .tr-rank { font-size: calc(1.8rem * var(--rs, 1)); }
.team-row .tr-main { gap: calc(8px * var(--rs, 1)); }
.team-row .tr-name { font-size: calc(1.5rem * var(--rs, 1)); }
.team-row .tr-bar { height: calc(16px * var(--rs, 1)); }
.team-row .tr-points { font-size: calc(2.2rem * var(--rs, 1)); }
.scoreboard.team-board { grid-template-columns: 1fr; }

/* Join late: small, beside the clock. */
.run-join { display: flex; align-items: center; gap: 10px; }
.run-join .qr { padding: 4px; border-radius: 8px; }
.run-join .qr img, .run-join .qr canvas { width: calc(84px * var(--rs, 1)) !important; height: auto !important; }
.run-join-text p { margin: 0; }
.run-url { color: var(--paper); font-size: calc(1.05rem * var(--rs, 1)); }
.run-join .run-code { color: var(--muted); font-size: calc(1rem * var(--rs, 1)); }
.run-join .run-code b { color: var(--gold); font-size: calc(1.6rem * var(--rs, 1)); letter-spacing: .1em; }
.run-full { margin: 0; color: var(--muted); font-size: 1rem; }

/* Names first: on a computer the ✎ and ✕ on each name appear when the mouse
 * is over it (or it is picked up), so the projector shows whole names. On a
 * touch screen they stay visible. */
@media (hover: hover) and (pointer: fine) {
  .lobby .name-card .rename-btn,
  .lobby .name-card .remove-btn { display: none; }
  .lobby .name-card:hover .rename-btn,
  .lobby .name-card:hover .remove-btn,
  .lobby .name-card:focus-within .rename-btn,
  .lobby .name-card:focus-within .remove-btn,
  .lobby .name-card.held .rename-btn,
  .lobby .name-card.held .remove-btn { display: inline-grid; place-items: center; }
}
.team-cards { grid-template-columns: repeat(auto-fit, minmax(calc(210px * var(--ls, 1)), 1fr)); }

/* The one next step, at the top of the join screen. */
.lobby-step { display: flex; align-items: center; justify-content: center; gap: 18px; flex-wrap: wrap; flex: none; width: 100%; }
.lobby-step .big-btn { font-size: 1.25rem; padding: 12px 34px; }
.lobby-step .lobby-step-msg { margin: 0; flex-basis: 100%; text-align: center; min-height: 0; }
.lobby-step .lobby-step-msg:empty { display: none; }

/* The results fit one screen too (--fs, set by leader.js as places arrive).
 * Runners-up sit two to a row; the mascot keeps clear of the winner's card
 * when he jumps. */
.leader .screen.finale { height: 100dvh; min-height: 0; box-sizing: border-box; padding-top: max(8px, var(--zb-home-top, 0px)); }
.finale-inner { gap: calc(8px * var(--fs, 1)); }
.finale-banner { font-size: calc(clamp(1.6rem, 4.6vw, 3rem) * var(--fs, 1)); }
.crown .place-card.winner { padding: calc(clamp(10px, 2.4vh, 20px) * var(--fs, 1)) 18px; }
.crown .place-card.winner .place-name { font-size: calc(clamp(2rem, 7vw, 4.4rem) * var(--fs, 1)); }
.crown .place-card.winner .place-score { font-size: calc(clamp(1.6rem, 4vw, 2.6rem) * var(--fs, 1)); }
.mascot-stage { height: calc(clamp(70px, 22vh, 200px) * var(--fs, 1)); margin-top: calc(clamp(70px, 22vh, 200px) * var(--fs, 1) * .32); }
.places { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 360px), 1fr)); gap: calc(8px * var(--fs, 1)); }
.places .places-more { grid-column: 1 / -1; }
.place-card { padding: calc(8px * var(--fs, 1)) 16px; }
.place-name { font-size: calc(1.2rem * var(--fs, 1)); }
.place-score { font-size: calc(1.5rem * var(--fs, 1)); }
.finale-logo { height: calc(clamp(60px, 13vh, 150px) * var(--fs, 1)); }

/* --- rounds and the Top Players (Tim, Oct 2026) ------------------------------ */
.finale-banner[data-round]:not([data-round=""])::before {
  content: attr(data-round);
  display: block;
  font-size: .42em;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--cyan);
  margin-bottom: 2px;
}
.run-round {
  font-size: calc(1.3rem * var(--rs, 1));
  font-weight: 800;
  color: var(--gold);
  letter-spacing: .06em;
  text-transform: uppercase;
}
.finale-actions { flex-wrap: wrap; justify-content: center; }

.leader .screen.champions {
  height: 100dvh;
  min-height: 0;
  overflow: hidden;
  box-sizing: border-box;
  justify-content: flex-start;
  gap: calc(12px * var(--cs, 1));
  padding-top: max(12px, var(--zb-home-top, 0px));
  background:
    radial-gradient(1100px 600px at 50% -10%, rgba(255, 194, 71, .2), transparent 70%),
    var(--bg, #081826);
}
.champions .finale-banner { font-size: calc(clamp(2rem, 6vw, 3.6rem) * var(--cs, 1)); }
.champ-sub { margin: 0; color: var(--muted); font-size: calc(1.1rem * var(--cs, 1)); text-align: center; }
.champ-none { color: var(--paper); font-size: 1.3rem; }
.champ-list {
  list-style: none;
  margin: 0;
  padding: 0;
  width: min(1100px, 100%);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 440px), 1fr));
  gap: calc(10px * var(--cs, 1));
}
.champ-row {
  display: grid;
  grid-template-columns: calc(3rem * var(--cs, 1)) 1fr auto;
  align-items: center;
  gap: calc(14px * var(--cs, 1));
  padding: calc(12px * var(--cs, 1)) calc(18px * var(--cs, 1));
  border-radius: 16px;
  border-left: 8px solid var(--team);
  background: linear-gradient(90deg, color-mix(in srgb, var(--team) 20%, rgba(10, 46, 67, .85)), rgba(10, 46, 67, .8));
  animation: slide-in .5s cubic-bezier(.2, .9, .3, 1.3) both;
}
.champ-row.first {
  grid-column: 1 / -1;
  box-shadow: 0 0 0 2px rgba(255, 194, 71, .6), 0 10px 30px rgba(255, 194, 71, .22);
}
.champ-place { font-size: calc(1.8rem * var(--cs, 1)); font-weight: 900; color: var(--paper); text-align: center; }
.champ-name { font-size: calc(1.6rem * var(--cs, 1)); font-weight: 800; color: var(--paper); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.champ-row.first .champ-name { font-size: calc(2.2rem * var(--cs, 1)); }
.champ-wins { font-size: calc(1.2rem * var(--cs, 1)); white-space: nowrap; }
.champ-wins b { color: var(--gold); font-size: 1.5em; }
.champ-wins small { color: var(--muted); }
@media (prefers-reduced-motion: reduce) { .champ-row { animation: none; } }
#practiceBtn { width: 100%; }
.practice-note { text-align: center; margin-top: -8px; }
