/*
 * The game (game.js): the BETA label, the no-game sign, the answer boxes of each style, the "Close!" line, the
 * dial's colours, blue arc and red pulse, a wrong answer's shake, the reveal, the example card, the end screen with
 * its golden 7-for-7 row and its review, and the fireworks. Everything
 * sits in start.css's sky-glass question box and reuses its unit --u, its colours and its glossy yellow .go pill.
 */

:root {
  --right: #1f9d55;
  --wrong: #d64534;
  --close: #e08a00;
  --extra-time: #4aa8ff;
  --time-go: #3fd07a;
  --time-warn: #ffb13b;
  --time-hot: #ff3b30;
  --chip: rgb(255 255 255 / 92%);
  --chip-rim: rgb(31 42 77 / 18%);
  --zone: rgb(255 255 255 / 38%);
  --zone-rim: rgb(31 42 77 / 22%);
  --tile-font: max(calc(1.45 * var(--u)), 14px);
  --tile-gap: max(calc(0.7 * var(--u)), 6px);
  --tile-h: calc(3.3 * var(--tile-font) + 4px); /* two lines (1.2 each), 0.45em padding twice, a 2px rim twice */
}

/* Wide boxes fit a title on one line, so a tile is one line tall (with a little more air). */
@media (min-width: 700px) {
  :root {
    --tile-h: calc(2.5 * var(--tile-font) + 4px);
  }
}

/* ---- BETA: a stamp on the title, on beta days (game.js unhides it) ---- */

.beta {
  display: block;
  margin: calc(-0.8 * var(--u)) 0 0;
  padding: 0.15em 0.7em;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: max(calc(2.4 * var(--u)), 18px);
  letter-spacing: 0.2em;
  color: #fff;
  background: linear-gradient(#ff8a5c, #e8553a);
  border-radius: 999px;
  box-shadow: 0 0.12em 0 #b23d25;
  transform: rotate(-4deg);
}

/* ---- No game today: a small glass sign in LIFTOFF's place, centred on the 0 m line like it ---- */

.no-game {
  position: absolute;
  top: calc(100% + var(--blades-px));
  left: 50%;
  translate: -50% -50%;
  width: max-content;
  max-width: var(--strip);
  margin: 0;
  padding: 0.5em 1.2em;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: max(calc(2.2 * var(--u)), 15px);
  line-height: 1.2;
  text-align: center;
  text-wrap: balance;
  color: var(--ink);
  background: var(--glass-card);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: max(calc(0.3 * var(--u)), 2px) solid var(--glass-rim);
  border-radius: 1em;
}

/* Phones: the box takes the room up to the screen's right edge, past the sprites' gutter. */
@media (max-width: 560px) {
  .q-slot {
    right: 10px;
  }
}

/* ---- Answer boxes ---- */

.qplay,
.qfeedback,
.qreveal,
.qexample,
.qend {
  justify-self: stretch;
}

.qplay {
  display: grid;
  gap: max(calc(0.9 * var(--u)), 10px);
  justify-items: center;
}

.qrow,
.qfields {
  justify-self: stretch;
  display: flex;
  gap: max(calc(1 * var(--u)), 8px);
}

.qfields {
  flex-direction: column;
}

/* Labelled boxes ("each of these" lists): a row per part, the item the question names ("Chanel") beside its field,
   so labels add no height. The label column takes what its longest label needs, up to 40%; longer ones wrap. */
.qfields.qlabels {
  display: grid;
  grid-template-columns: fit-content(40%) minmax(0, 1fr);
  align-items: center;
  column-gap: max(calc(1 * var(--u)), 8px);
}

.qlabelled {
  display: contents;
}

.qlabel {
  font-weight: 700;
  font-size: max(calc(1.5 * var(--u)), 14px);
  text-align: right;
  overflow-wrap: anywhere;
}

/* 16px minimum so phones don't zoom in on focus. */
.qfield {
  flex: 1;
  min-width: 0;
  width: 100%;
  font: inherit;
  font-weight: 700;
  font-size: max(calc(1.8 * var(--u)), 16px);
  padding: 0.5em 0.75em;
  color: var(--ink);
  background: var(--field);
  border: max(calc(0.25 * var(--u)), 2px) solid rgb(255 255 255 / 95%);
  border-radius: max(calc(1 * var(--u)), 10px);
}

.qpic .qfield {
  padding: 0.45em 0.5em;
  text-align: center;
}

.qfield.is-close {
  border-color: var(--close);
  box-shadow: 0 0 0 2px rgb(224 138 0 / 35%);
}

.qbox .qfield:focus-visible,
.qbox button:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 3px;
}

.qfeedback {
  margin: 0;
  min-height: 1.3em;
  font-weight: 800;
  font-size: max(calc(1.7 * var(--u)), 15px);
  color: #9a5a00;
}

/* An empty live region stays rendered (screen readers only announce changes to a region already there), but takes
   no room. */
.qfeedback:empty {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}

/* Spelling: a round speaker button above the field. */
.qspeak {
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
  padding: 0.45em 1.1em 0.45em 0.8em;
  border: 0;
  border-radius: 999px;
  cursor: pointer;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: max(calc(1.8 * var(--u)), 16px);
  color: #fff;
  background: linear-gradient(#5aa9ff, #2f7fd1);
  box-shadow:
    inset 0 0.07em 0 rgb(255 255 255 / 45%),
    0 0.13em 0 #1d5ea3;
}

.qspeak svg {
  width: 1.4em;
  height: 1.4em;
}

.qspeak:active {
  transform: translateY(0.1em);
  box-shadow: 0 0.03em 0 #1d5ea3;
}

/* ---- Drag-to-match: equal tiles, two to a row in the "Not sorted" tray, one to a row in equal groups ---- */

.qmatch {
  justify-self: stretch;
  display: grid;
  gap: max(calc(0.8 * var(--u)), 8px);
}

.qmatch-hint {
  margin: 0;
  font-weight: 700;
  font-size: max(calc(1.4 * var(--u)), 13px);
  color: var(--ink-soft);
}

/* Short screens: no room for the hint. */
@media (max-height: 700px) {
  .qmatch-hint {
    display: none;
  }
}

/* A part of the box that scrolls inside it once the box would run off the screen (game.js --scroll-fit), so
   Submit under it stays in view. A touch on its background scrolls it (with momentum); a touch on a tile drags. */
.qscroll {
  max-height: max(120px, var(--scroll-fit, 100vh));
  overflow: hidden auto;
  overscroll-behavior: contain;
  touch-action: pan-y pinch-zoom;
  -webkit-overflow-scrolling: touch;
}

/* A soft fade at an edge with more to scroll to (game.js marks them); a mask, so nothing sits over the tiles. */
.qscroll.more-below {
  -webkit-mask-image: linear-gradient(to top, transparent, #000 28px);
  mask-image: linear-gradient(to top, transparent, #000 28px);
}

.qscroll.more-above {
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 28px);
  mask-image: linear-gradient(to bottom, transparent, #000 28px);
}

.qscroll.more-above.more-below {
  -webkit-mask-image: linear-gradient(transparent, #000 28px, #000 calc(100% - 28px), transparent);
  mask-image: linear-gradient(transparent, #000 28px, #000 calc(100% - 28px), transparent);
}

.qmatch-slot {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-content: start;
  gap: var(--tile-gap);
}

/* The unsorted list: its heading is quieter than the groups' and it has no frame until something is dragged. */
.qmatch-tray {
  display: grid;
  justify-items: center;
  gap: var(--tile-gap);
  padding: var(--tile-gap);
  border: 2px solid transparent;
  border-radius: max(calc(1.2 * var(--u)), 12px);
}

.qmatch-tray > .qmatch-name {
  font-size: max(calc(1.3 * var(--u)), 13px);
  color: var(--ink-soft);
  background: rgb(255 255 255 / 55%);
}

/* The list fits the tiles still in it (a dragged tile waits in place, so it only settles after the drop); once
   empty it gives way to a quiet "All sorted" line. Its heading stays, the keyboard's way to put one back. */
.qmatch-tray .qmatch-slot {
  justify-self: stretch;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

/* An odd tile out sits centred under the pair above it, as wide as they are. */
.qmatch-tray .qmatch-item:last-child:nth-child(odd) {
  grid-column: 1 / -1;
  justify-self: center;
  width: calc((100% - var(--tile-gap)) / 2);
}

.qmatch-tray .qmatch-slot:empty,
.qmatch-slot:not(:empty) + .qmatch-done {
  display: none;
}

.qmatch-done {
  margin: 0;
  font-weight: 700;
  font-size: max(calc(1.4 * var(--u)), 13px);
  color: var(--ink-soft);
}

/* Two groups side by side, equal widths; the grid row stretches both to the taller one. */
.qmatch-groups {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: max(calc(0.8 * var(--u)), 8px);
}

/* More than two (a "Match these" question: a group per item): one under another, each a row with its name beside its
   tiles, so a name or a title never has to break inside a word to fit a third of the width. */
.qmatch-groups.rows {
  grid-template-columns: minmax(0, 1fr);
}

.qmatch-groups.rows .qmatch-group {
  grid-template-columns: minmax(min-content, 2fr) minmax(0, 3fr);
  grid-template-rows: auto;
  align-items: center;
}

/* A name wraps only between words, and its column is at least its longest word wide. */
.qmatch-groups.rows .qmatch-name {
  overflow-wrap: normal;
}

/* A row's tiles and spot are wide: one line high (a longer title still wraps and grows its tile). */
.qmatch-groups.rows .qmatch-slot {
  --tile-h: calc(2.1 * var(--tile-font) + 4px);
}

/* A group's rim is solid, so its one dashed spot reads as the place to drop. */
.qmatch-group {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto 1fr;
  gap: var(--tile-gap);
  padding: var(--tile-gap);
  background: var(--zone);
  border: 2px solid var(--zone-rim);
  border-radius: max(calc(1.2 * var(--u)), 12px);
  cursor: pointer;
}

/* The one empty spot at the end of each group, the size of a tile (game.js puts each new tile in front of it). */
.qmatch-drop {
  display: grid;
  place-items: center;
  min-height: var(--tile-h);
  border: 2px dashed var(--zone-rim);
  border-radius: max(calc(1 * var(--u)), 10px);
  font-weight: 700;
  font-size: max(calc(1.3 * var(--u)), 13px);
  color: var(--ink-soft);
}

/* A one-each group (game-match.js) takes one tile: once it has it, its spot goes. */
.one-each .qmatch-item + .qmatch-drop {
  display: none;
}

.qmatch-tray.over,
.qmatch-group.over,
.choosing .qmatch-group {
  border-color: var(--focus);
  background: rgb(47 127 209 / 14%);
}

.qmatch-group.over .qmatch-drop,
.choosing .qmatch-drop {
  border-color: var(--focus);
  color: var(--focus);
}

.qmatch-name {
  min-width: 0;
  overflow-wrap: anywhere; /* a name too long for its half wraps rather than being cut */
  border: 0;
  border-radius: 999px;
  padding: 0.3em 0.6em;
  cursor: pointer;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: max(calc(1.7 * var(--u)), 15px);
  color: #fff;
  background: var(--ink-soft);
}

/* A tile fills its cell; long titles wrap inside it. -webkit-touch-callout: a long press on an iPhone must not
   open the callout, which would cancel the drag. */
.qmatch-item {
  box-sizing: border-box;
  width: 100%;
  min-height: var(--tile-h);
  margin: 0;
  padding: 0.45em 0.35em;
  border: 2px solid var(--chip-rim);
  border-radius: max(calc(1 * var(--u)), 10px);
  cursor: grab;
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  font: inherit;
  font-weight: 800;
  font-size: var(--tile-font);
  line-height: 1.2;
  text-align: center;
  overflow-wrap: break-word;
  color: var(--ink);
  background: var(--chip);
  box-shadow: 0 2px 4px rgb(30 70 130 / 18%);
}

.qmatch-item[aria-pressed="true"] {
  border-color: var(--focus);
  background: #e3f0ff;
  box-shadow: 0 0 0 3px rgb(47 127 209 / 35%);
}

/* While dragged, the tile stays where it was, faded, and the ghost (on the page, outside the box) follows. */
.qmatch-item.lifted {
  opacity: 0.35;
  box-shadow: none;
}

.qmatch-ghost {
  position: fixed;
  z-index: 1000;
  display: grid;
  place-items: center;
  min-height: 0;
  pointer-events: none;
  cursor: grabbing;
  font-family: var(--font-body);
  background: #fff; /* opaque, so the faded tile under it doesn't show through */
  box-shadow: 0 8px 18px rgb(30 70 130 / 35%);
}

/* ---- Drag-to-order: one column of match tiles, numbered down the left, the list's ends named above and below ---- */

.qorder {
  justify-self: stretch;
  display: grid;
  gap: var(--tile-gap);
}

.qorder-end {
  margin: 0;
  font-weight: 800;
  font-size: max(calc(1.2 * var(--u)), 12px);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* Numbers then tiles, flowing down two columns (game.js sets --rows), so each tile's row holds its place's number
   and a tile that wraps to two lines keeps its number beside it. */
.qorder-list,
.qorder-row {
  display: grid;
  grid-template-columns: max(calc(2.4 * var(--u)), 22px) minmax(0, 1fr);
  align-items: center;
  gap: var(--tile-gap) max(calc(0.6 * var(--u)), 6px);
}

.qorder-list {
  grid-template-rows: repeat(var(--rows), auto);
  grid-auto-flow: column;
}

.qorder-result {
  justify-self: stretch;
  display: grid;
  gap: var(--tile-gap);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Nothing is dragged on the reveal: a swipe on a tile scrolls the list (the drag tiles' `touch-action: none` would
   block it). */
.qorder-result .qmatch-item {
  touch-action: pan-y pinch-zoom;
}

.qorder-num {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: max(calc(1.8 * var(--u)), 16px);
  color: var(--ink-soft);
}

/* The grip says "drag me"; the name reads from the left, as a list does. */
.qorder-item,
.qorder-placed {
  display: flex;
  align-items: center;
  gap: 0.6em;
  padding-inline: 0.7em;
  text-align: left;
}

.qorder-grip {
  flex: none;
  font-size: 1.2em;
  line-height: 1;
  color: var(--ink-soft);
  opacity: 0.6;
}

.qorder-item.qmatch-ghost {
  display: flex;
  place-items: initial;
}

/* The reveal: each tile as it was checked, its rim and mark saying right or wrong. */
.qorder-placed {
  cursor: default;
  justify-content: space-between;
}

.qorder-placed.is-right {
  border-color: var(--right);
  background: #e3f4ea;
}

.qorder-placed.is-wrong {
  border-color: var(--wrong);
  background: #fbe6e3;
}

.qorder-mark {
  flex: none;
  font-size: 1.15em;
}

.is-right .qorder-mark {
  color: var(--right);
}

.is-wrong .qorder-mark {
  color: var(--wrong);
}

/* A match question's reveal: the right sort, each title marked by where the player put it, as above. No tile chrome,
   so the whole sort fits a phone: a column of plain lines under each underlined group name, each line led by its
   tick or cross (a wrong one in red). */
.qmatch-result {
  justify-self: stretch;
  display: grid;
  gap: 8px;
}

.qmatch-result .qmatch-group,
.qmatch-result .qmatch-name {
  cursor: default;
}

.qmatch-result .qmatch-groups {
  gap: 4px 14px;
}

.qmatch-result .qmatch-group {
  grid-template-rows: auto;
  align-content: start;
  gap: 3px;
  padding: 0;
  background: none;
  border: 0;
  border-radius: 0;
}

/* The names are <p>s: their default margins go. */
.qmatch-result .qmatch-name {
  justify-self: stretch;
  margin: 0;
  padding: 0 0 2px;
  border-radius: 0;
  text-align: left;
  font-size: max(calc(1.55 * var(--u)), 15px);
  color: var(--ink);
  background: none;
  border-bottom: 2px solid var(--zone-rim);
}

/* In rows, a gap between a name and its titles. */
.qmatch-result .qmatch-groups.rows .qmatch-group {
  column-gap: 10px;
}

.qmatch-result .qmatch-slot {
  gap: 3px;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* A line is only as tall as its title: nothing is dragged here; a swipe on one scrolls the result (the drag tiles'
   `touch-action: none` would block it). */
.qmatch-result .qmatch-item {
  min-height: 0;
  touch-action: pan-y pinch-zoom;
  justify-content: flex-start;
  align-items: baseline;
  gap: 0.35em;
  padding: 0;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  background: none;
  font-weight: 700;
  line-height: 1.25;
}

.qmatch-result .qorder-mark {
  order: -1;
  font-size: 1em;
  font-weight: 800;
}

.qmatch-result .qorder-placed.is-wrong {
  color: var(--wrong);
}

/* Phones, and phones on their side: on a match or order reveal (game.js "list-reveal" on the group) the dial and the
   verdict give their room to the sort or the tiles. */
@media (max-width: 560px), (max-height: 500px) and (min-aspect-ratio: 5/4) {
  .list-reveal .qbox,
  .list-reveal .qreveal {
    gap: 6px;
  }

  .list-reveal .qverdict {
    font-size: 18px;
  }

  .list-reveal .timer {
    width: 76px;
  }
}

/* Phones, upright or on their side: a match reveal's sort or an order reveal's tiles may scroll in less room than the
   usual 120px floor (about three lines), so Next stays on screen under a long question and answer. */
@media (max-width: 560px), (max-height: 500px) and (min-aspect-ratio: 5/4) {
  .list-reveal .qscroll {
    max-height: max(60px, var(--scroll-fit, 100vh));
  }
}

/* Read out after the name ("Lenin (wrong)"), not shown: the rim and the mark show it. The reveal's "You said:",
   "(wrong)" and "Answer:" are start.css .sr-only text. */
.qorder-said {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}

/* Very narrow boxes: one tile to a row in the tray too, and smaller headings, tiles and gaps so a group's
   heading and titles fit its half of the width. */
@media (max-width: 340px) {
  :root {
    --tile-font: 13px;
  }

  .qmatch-tray .qmatch-slot {
    grid-template-columns: minmax(0, 1fr);
  }

  .qmatch-tray .qmatch-item:last-child:nth-child(odd) {
    width: 100%;
  }

  .qmatch-groups {
    gap: 6px;
  }

  /* The reveal's groups one under the other, so a title keeps to one line. */
  .qmatch-result .qmatch-groups {
    grid-template-columns: minmax(0, 1fr);
    gap: 8px;
  }

  .qmatch-group {
    padding: 4px;
  }

  .qmatch-name {
    font-size: 12px;
    padding: 0.3em 0.25em;
  }

  .qmatch-item {
    padding: 0.45em 0.2em;
  }
}

/* ---- Phone keyboard (game.js puts "keyboard" on <html>): the box rests just above the keys ---- */

/* The slot is the visible part above the keyboard, as game.js measured it in the slot's layer (--vv-top down,
   --vv-h tall), and the box sits on its bottom; a box still too tall (its picture already at the smallest) runs
   off the top, the timer first, never over the field. */
.keyboard .q-slot {
  top: calc(var(--vv-top) + 8px);
  bottom: auto;
  height: calc(var(--vv-h) - 16px);
  justify-content: flex-end;
}

.keyboard .qgroup {
  margin: 0 auto;
}

/* The dial gives up some size to the room above the keys. */
.keyboard .timer {
  width: clamp(80px, calc(0.3 * var(--vv-h)), 140px);
}

/* Submit back beside the field: one row less to fit above the keys. */
.keyboard .qrow {
  flex-direction: row;
}

/* Question 1's goal reminder gives its row to the room above the keys. */
.keyboard .qgoal {
  display: none;
}

/* ---- Timer: the colour arc, the number, the blue arc of extra time and the red pulse of the last 5 seconds ---- */

/* game.js sets the dial's data-time: extra (blue time left), go (above 20 s), warn (20 s down to just above 10 s),
   hot (10 s and under). */
.dial-arc {
  stroke: var(--time-go);
}

.dial[data-time="warn"] .dial-arc {
  stroke: var(--time-warn);
}

.dial[data-time="hot"] .dial-arc {
  stroke: var(--time-hot);
}

.dial-num {
  fill: #f4f1e6;
}

.dial[data-time="extra"] .dial-num {
  fill: #7cc4ff;
}

.dial[data-time="hot"] .dial-num {
  fill: #ff6a5c;
}

.dial-extra {
  stroke: var(--extra-time);
}

.dial-ring {
  stroke: var(--time-hot);
  opacity: 0;
}

/* At 5 s and under (game.js "urgent" on the group), twice a second: the box's rim glows red, the dial's outer ring
   beats red and the number thumps. */
.qgroup.urgent .qbox {
  animation: glow 0.5s ease-in-out infinite;
}

.qgroup.urgent .dial-ring {
  animation: ringbeat 0.5s ease-in-out infinite;
}

.qgroup.urgent .dial-window {
  transform-box: fill-box;
  transform-origin: center;
  animation: thump 0.5s ease-in-out infinite;
}

/* ---- A wrong answer: the box gives a short shake (game.js "shake"); the height and the balloons stay ---- */

.qgroup .qbox.shake {
  animation: shake 0.45s ease-in-out;
}

/* ---- The question's words can't be selected or copied (game.js cancels a copy or cut that starts in them) ---- */

.qtext,
.qexample,
.qreview-text {
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

/* Question 1's reminder of the goal, a small pill between "Question 1 of 7" and the question. */
.qgoal {
  margin: 0;
  padding: 4px 10px;
  border-radius: 99px;
  background: rgb(255 255 255 / 45%);
  color: var(--ink-soft);
  font-weight: 700;
  font-size: max(calc(1.2 * var(--u)), 12px);
  line-height: 1.3;
}

/* Under 600px tall (the smallest phones, phones on their side) it says less, on one line. */
.qgoal-short {
  display: none;
}

@media (max-height: 599px) {
  .qgoal-long {
    display: none;
  }

  .qgoal-short {
    display: inline;
  }
}

/* A crossword's letter pattern (game.js): one piece, never split between its letters. */
.qpattern {
  white-space: nowrap;
}

/* ---- Reveal ---- */

.qreveal,
.qexample,
.qend {
  display: grid;
  justify-items: center;
  gap: max(calc(0.8 * var(--u)), 10px);
}

.qverdict {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: max(calc(2.3 * var(--u)), 20px);
  line-height: 1.2;
  /* Its line, kept while the verdict waits a frame for screen readers (game.js announce), so the reveal is laid out
     once instead of growing and moving up a frame later. */
  min-height: 1.2em;
}

.qverdict[data-verdict="right"] {
  color: var(--right);
}

.qverdict[data-verdict="wrong"] {
  color: var(--wrong);
}

/* On the reveal the question steps back: small and quiet above the verdict. */
.qbox[data-view="reveal"] > .qtext {
  font-size: max(calc(1.5 * var(--u)), 14px);
  color: var(--ink-soft);
}

/* The answer, the biggest line of a reveal or an example card (green on the card). */
.qright {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: max(calc(2.7 * var(--u)), 25px);
  line-height: 1.15;
  overflow-wrap: anywhere;
}

.qright b {
  font-weight: inherit;
}

/* A wrong reveal's line of what the player gave: the typed text struck through in the wrong colour, or each box's
   text, green with its ✓ when right, struck through when wrong. */
.qsaid {
  margin: 0;
  font-weight: 800;
  font-size: max(calc(1.8 * var(--u)), 17px);
  overflow-wrap: anywhere;
}

.qsaid-right {
  color: var(--right);
}

.qsaid-wrong {
  color: var(--wrong);
  text-decoration: line-through;
  text-decoration-thickness: 2px;
}

.qreveal-pics,
.qexample-pics {
  justify-self: stretch;
}

/* A free-licence photo's credit, under the reveal's pictures: small, quiet, wrapping long file names. */
.qcredits {
  justify-self: stretch;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: max(calc(1.1 * var(--u)), 12px);
  font-weight: 600;
  line-height: 1.3;
  color: var(--ink-soft);
  overflow-wrap: anywhere;
}

.qcredits a {
  color: inherit;
}

/* ---- Example card: "NEXT UP" small over the style's name and its rule, then a light frame tagged "EXAMPLE" with
   "Q: <clue>" (or the picture), "A: <answer>" big and green, and the trick small ---- */

.qexample-next,
.qexample-tag {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 600;
  text-transform: uppercase;
  line-height: 1.2;
  color: var(--ink-soft);
}

.qexample-next {
  letter-spacing: 0.1em;
  font-size: max(calc(1.3 * var(--u)), 12px);
}

.qexample-title {
  margin: -4px 0 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: max(calc(2.4 * var(--u)), 22px);
  line-height: 1.1;
}

.qexample-rule {
  margin: 0;
  text-wrap: balance;
  font-weight: 700;
  font-size: max(calc(1.75 * var(--u)), 16px);
  line-height: 1.3;
}

.qexample-box {
  justify-self: center;
  box-sizing: border-box;
  width: 100%;
  max-width: 520px;
  min-width: 0;
  margin-top: 2px;
  display: grid;
  justify-items: center;
  gap: max(calc(0.6 * var(--u)), 6px);
  padding: max(calc(0.9 * var(--u)), 9px) max(calc(1.4 * var(--u)), 12px) max(calc(1.1 * var(--u)), 11px);
  border-radius: max(calc(1.2 * var(--u)), 12px);
  background: rgb(255 255 255 / 62%);
  border: 1.5px solid rgb(255 255 255 / 90%);
}

.qexample-tag {
  letter-spacing: 0.12em;
  font-size: max(calc(1.15 * var(--u)), 11px);
  line-height: 1.1;
}

.qexample-text {
  text-wrap: balance;
  font-size: max(calc(1.9 * var(--u)), 17px);
  line-height: 1.25;
}

.qexample .qright {
  font-size: max(calc(2.4 * var(--u)), 22px);
  color: var(--right);
}

/* "Q:" and "A:" in the body font, quiet, the A: no bigger than the clue. */
.qexample-label {
  font-family: var(--font-body);
  font-weight: 800;
  color: var(--ink-soft);
}

.qexample .qright .qexample-label {
  font-size: max(calc(1.9 * var(--u)), 17px);
}

/* On the card a crossword's letter pattern sits on its own line under the clue (still one unbroken line). */
.qexample-text .qpattern {
  display: block;
}

.qexample-explain {
  margin: 0;
  font-weight: 700;
  font-size: max(calc(1.5 * var(--u)), 14px);
  line-height: 1.3;
  color: var(--ink-soft);
}

/* The narrowest phones: a little more room in the frame, and the crossword's pattern a size down so it fits it. */
@media (max-width: 360px) {
  .qexample-box {
    padding-left: 8px;
    padding-right: 8px;
  }

  .qexample-text .qpattern {
    font-size: 16px;
  }
}

/* Short screens (phones on their side): "Next up: Rebus" on one line and a tighter frame, so the picture keeps
   room. */
@media (max-height: 500px) {
  .qexample-next {
    display: none;
  }

  .qexample-title {
    margin: 0;
    font-size: max(calc(2 * var(--u)), 18px);
  }

  .qexample-title::before {
    content: "Next up: ";
    font-weight: 600;
    color: var(--ink-soft);
  }

  .qexample-box {
    gap: 3px;
    margin-top: 0;
    padding-top: 5px;
    padding-bottom: 6px;
  }
}

/* The smallest phones on their side (568x320): a tighter frame still (start.css tightens the box). */
@media (max-height: 339px) and (min-aspect-ratio: 5/4) {
  .qexample-box {
    gap: 2px;
    padding-top: 4px;
    padding-bottom: 4px;
  }
}

/* ---- End screen ---- */

.qend-title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: max(calc(3.2 * var(--u)), 25px);
  line-height: 1.15;
}

.qend-height {
  white-space: nowrap;
}

.qend-score {
  margin: calc(-0.4 * var(--u)) 0 0;
  font-weight: 800;
  font-size: max(calc(1.7 * var(--u)), 16px);
  color: var(--ink-soft);
}

.qend-row {
  margin: 0;
  font-size: max(calc(3.6 * var(--u)), 28px);
  letter-spacing: 0.02em;
  line-height: 1.2;
}

/* 7 for 7: the row glows gold and pulses (still and gold with reduced motion). No side padding, so it wraps no
   sooner than any other row. The glow holds still; only the size pulses (a transform, cheap to keep running). */
.qend-row.gold {
  border-radius: 999px;
  background: radial-gradient(closest-side, rgb(255 214 92 / 75%), rgb(255 196 40 / 25%) 70%, transparent);
  filter: drop-shadow(0 0 6px rgb(255 190 30 / 90%));
  animation: goldpulse 1.6s ease-in-out infinite;
}

.qend-share {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 10px 12px;
}

.qend-copied {
  font-weight: 800;
  color: var(--right);
}

.qend-text {
  justify-self: stretch;
  font: inherit;
  font-weight: 700;
  resize: none;
  border-radius: 10px;
}

/* The stats are a footnote to the height and the row: small boxes, not wider than they need. */
.qend-stats {
  justify-self: center;
  width: min(100%, 520px);
  margin: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 6px;
}

.qend-stats div {
  display: grid;
  gap: 0;
  padding: 4px;
  background: rgb(255 255 255 / 40%);
  border-radius: 8px;
}

.qend-stats dt {
  font-weight: 700;
  font-size: max(calc(1.1 * var(--u)), 12px);
  color: var(--ink-soft);
}

.qend-stats dd {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: max(calc(1.7 * var(--u)), 15px);
}

.qend-next {
  margin: 0;
  font-weight: 700;
  font-size: max(calc(1.5 * var(--u)), 14px);
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
}

/* ---- Review: the day's questions in the end screen's place, scrolling inside the box (Back stays under it) ---- */

.qreview {
  justify-self: stretch;
  display: grid;
  justify-items: center;
  gap: max(calc(0.8 * var(--u)), 10px);
}

.qreview-list {
  justify-self: stretch;
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 8px;
  text-align: left;
}

/* A row per question: its number and mark in a narrow column, then its text, what the player said on a wrong one,
   the answer and how many players got it. */
.qreview-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: baseline;
  column-gap: 8px;
  padding: 8px 10px;
  background: rgb(255 255 255 / 40%);
  border-radius: 10px;
}

.qreview-body {
  display: grid;
  gap: 2px;
}

.qreview-body p {
  margin: 0;
}

/* One width for every row's number and mark, so the texts line up whichever mark a row has. */
.qreview-tag {
  min-width: 2.1em;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: max(calc(1.5 * var(--u)), 15px);
  color: var(--ink-soft);
  white-space: nowrap;
}

.is-right .qreview-mark {
  color: var(--right);
}

.is-wrong .qreview-mark {
  color: var(--wrong);
}

.qreview-text {
  font-size: max(calc(1.4 * var(--u)), 14px);
  font-weight: 700;
  line-height: 1.3;
}

.qreview-body .qsaid {
  font-size: max(calc(1.3 * var(--u)), 13px);
}

.qreview-answer {
  font-size: max(calc(1.5 * var(--u)), 15px);
}

/* How many players got it: a line kept even while empty, so nothing moves when the numbers arrive. */
.qreview-share {
  min-height: 1.3em;
  font-size: max(calc(1.2 * var(--u)), 12px);
  font-weight: 700;
  line-height: 1.3;
  color: var(--ink-soft);
}

/* ---- 7 for 7: fireworks over the sky, under the question box (game-fireworks.js draws them) ---- */

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

@media (max-width: 560px) {
  .qrow {
    flex-direction: column;
  }

  .qend-stats {
    grid-template-columns: 1fr 1fr;
  }

  /* Copy and Review your game side by side on a 375px phone (they stack at 320px). */
  .qend-share .go {
    font-size: 16px;
    padding-inline: 0.85em;
  }
}

/* The narrowest phones (320px) keep the old sizes: the title stays on one line up to "You reached 1,500 m" (5,000 m
   and 10,000 m wrap, as they always have); a bigger one would wrap from 100 m. */
@media (max-width: 359px) {
  .qend-title {
    font-size: 22px;
  }

  .qend-row {
    font-size: 26px;
  }
}

/* The box's own shadow (start.css) stays under the red rim. */
@keyframes glow {
  0%,
  100% {
    box-shadow:
      0 0 0 0 rgb(255 59 48 / 0%),
      0 calc(1 * var(--u)) calc(2.4 * var(--u)) var(--glass-shadow);
  }

  50% {
    box-shadow:
      0 0 0 7px rgb(255 59 48 / 55%),
      0 calc(1 * var(--u)) calc(2.4 * var(--u)) var(--glass-shadow);
  }
}

@keyframes ringbeat {
  0%,
  100% {
    opacity: 0;
  }

  50% {
    opacity: 0.95;
  }
}

@keyframes thump {
  50% {
    transform: scale(1.14);
  }
}

@keyframes shake {
  0%,
  100% {
    transform: translateX(0);
  }

  20%,
  60% {
    transform: translateX(-8px);
  }

  40%,
  80% {
    transform: translateX(8px);
  }
}

@keyframes goldpulse {
  0%,
  100% {
    transform: scale(1);
  }

  50% {
    transform: scale(1.06);
  }
}

/* Reduced motion: at 5 s and under the rim and the ring are simply red (the number still counts), a wrong answer
   doesn't shake, and the 7-for-7 row is gold but still (and game-fireworks.js sets off none). */
@media (prefers-reduced-motion: reduce) {
  .qgroup.urgent .qbox,
  .qgroup.urgent .dial-ring,
  .qgroup.urgent .dial-window,
  .qgroup .qbox.shake,
  .qend-row.gold {
    animation: none;
  }

  .qgroup.urgent .qbox {
    box-shadow:
      0 0 0 5px rgb(255 59 48 / 55%),
      0 calc(1 * var(--u)) calc(2.4 * var(--u)) var(--glass-shadow);
  }

  .qgroup.urgent .dial-ring {
    opacity: 0.9;
  }
}
