/* Atkinson Hyperlegible draws zero with a slash, which can confuse children who are still learning
   numerals. Its digits are swapped for Fredoka's (already self-hosted), which have a plain zero and a
   similar weight. */
@font-face {
  font-family: 'Starbit Digits';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('/fonts/fredoka-latin-500-normal.woff2') format('woff2');
  unicode-range: U+0030-0039;
}
@font-face {
  font-family: 'Starbit Digits';
  font-style: normal;
  font-weight: 700 900;
  font-display: swap;
  src: url('/fonts/fredoka-latin-600-normal.woff2') format('woff2');
  unicode-range: U+0030-0039;
}
@font-face {
  font-family: 'Starbit Sans';
  font-style: normal;
  font-weight: 500 900;
  font-display: swap;
  src: url('/fonts/StarbitSans-Bold.woff2') format('woff2');
}
@font-face {
  font-family: 'Fredoka';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/fonts/fredoka-latin-500-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Fredoka';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/fonts/fredoka-latin-600-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Fredoka';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/fonts/fredoka-latin-700-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Atkinson Hyperlegible';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/atkinson-hyperlegible-latin-400-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Atkinson Hyperlegible';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/fonts/atkinson-hyperlegible-latin-700-normal.woff2') format('woff2');
}
*,
*::before,
*::after {
  box-sizing: border-box;
}
:root {
  padding-top: env(safe-area-inset-top, 0px);
  padding-bottom: env(safe-area-inset-bottom, 0px);
}
body {
  margin: 0;
}
img {
  max-width: 100%;
}
[hidden] {
  display: none !important;
}
/* Layout: sticker-book toy shelf. Chunky ink outlines, hard drop shadows, big tap targets for small fingers on an iPad. Single bright theme by choice. */
:root {
  /* Fresh mint ground with warm white cards, matching the teal-to-mint logo. Deep ocean teal is the brand's dark (the Watch Time night sky). */
  --ground: #dff2e8;
  --paper: #fffdf7;
  --ink: #1f2a44;
  --night: #164d53;
  --ink-soft: #55607b;
  --tomato: #ff6a4d;
  --sun: #ffc93c;
  --grape: #6e5bff;
  --leaf: #1fae6b; /* fills only: too pale for text on cream (2.8:1) */
  --leaf-text: var(--go);
  --sky: #3ba2e3;
  --pink: #ff8fb8;
  --orange: #ff9f45;
  --plus: #117a49;
  --go: #117a49;
  --minus: #d2372a;
  --wash-sun: #fff3cf;
  --wash-leaf: #d3f5e3;
  --wash-tomato: #ffe1da;
  /* Star effects: about twice as slow as before, with a soft ease, so they feel calm (issue #15). */
  --star-pop: 0.8s;
  --star-bump: 0.9s;
  --ease-soft: cubic-bezier(0.37, 0, 0.63, 1);
  --display: 'Starbit Sans', 'Fredoka', 'Arial Rounded MT Bold', 'Trebuchet MS', system-ui, sans-serif;
  --body: 'Starbit Digits', 'Atkinson Hyperlegible', 'Verdana', system-ui, sans-serif;
  --r: 22px;
  color-scheme: light;
}
html,
body {
  font-variant-ligatures: none;
  height: 100%;
}
body {
  background: var(--ground);
  color: var(--ink);
  font-family: var(--body);
  font-size: 18px;
  line-height: 1.45;
  padding-left: max(16px, env(safe-area-inset-left, 0px));
  padding-right: max(16px, env(safe-area-inset-right, 0px));
  -webkit-tap-highlight-color: transparent;
  -webkit-user-select: none;
  user-select: none;
  background-image: radial-gradient(circle at 1px 1px, rgba(31, 42, 68, 0.06) 1.5px, transparent 0);
  background-size: 26px 26px;
}
button,
input,
select {
  font: inherit;
  color: inherit;
}
button {
  cursor: pointer;
  touch-action: manipulation;
}
:focus-visible {
  outline: 4px solid var(--grape);
  outline-offset: 3px;
}
h1,
h2,
h3 {
  font-family: var(--display);
  font-weight: 700;
  line-height: 1.1;
  margin: 0;
  text-wrap: balance;
}
.wrap {
  max-width: 1040px;
  margin: 0 auto;
  padding-block: 18px 40px;
  display: flex;
  flex-direction: column;
  gap: 22px;
}

/* top bar */
.top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}
.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  background: none;
  border: 0;
  padding: 0;
}
.brand h1 {
  margin: 0;
  line-height: 0;
}
.brand .logo {
  display: block;
  height: clamp(34px, 5vw, 46px);
  width: auto;
  max-width: 100%;
}
.top-right,
.who {
  display: flex;
  /* On the narrowest phones (320px) the buttons wrap instead of pushing the page sideways. */
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 10px;
  align-items: center;
  flex-wrap: wrap;
  min-width: 0;
}
/* The header never squeezes its words: "Player 1" and "Grown-ups" stay on one line (issue #74). A very
   long name may still wrap inside its pill rather than push the header off the screen. */
#open-parent {
  white-space: nowrap;
  min-height: 44px;
}
.pill.kid {
  min-width: 0;
  min-height: 44px;
}
#kid-name {
  min-width: 0;
  overflow-wrap: anywhere;
}
/* Phones: the logo and Grown-ups share the first row (the logo gets a little smaller if it must), and the
   player and stars get their own row under them, so it all fits at 320px wide with bigger text. */
@media (max-width: 480px) {
  .top {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 12px;
  }
  .top-right {
    display: contents;
  }
  .brand {
    min-width: 0;
    width: 100%;
  }
  .brand h1 {
    min-width: 0;
    width: 100%;
  }
  .brand .logo {
    width: 100%;
    max-width: 152px;
    height: auto;
  }
  #open-parent {
    grid-column: 2;
    grid-row: 1;
  }
  .who {
    grid-column: 1 / -1;
    flex-wrap: nowrap;
  }
}
.pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: var(--paper);
  border: 3px solid var(--ink);
  border-radius: 999px;
  padding: 6px 14px 6px 8px;
  font-family: var(--display);
  font-weight: 700;
  font-size: 22px;
  box-shadow: 0 4px 0 var(--ink);
}
.pill svg {
  width: 30px;
  height: 30px;
}
.btn {
  border: 3px solid var(--ink);
  border-radius: 16px;
  background: var(--paper);
  padding: 12px 20px;
  font-family: var(--display);
  font-weight: 600;
  font-size: 20px;
  box-shadow: 0 5px 0 var(--ink);
  transition:
    transform 0.08s,
    box-shadow 0.08s;
}
.btn:active {
  transform: translateY(4px);
  box-shadow: 0 1px 0 var(--ink);
}
.btn.small {
  font-size: 16px;
  padding: 8px 14px;
  border-radius: 12px;
  box-shadow: 0 4px 0 var(--ink);
}
.btn.go {
  background: var(--go);
  color: #fff;
}
.btn.warm {
  background: var(--sun);
}
.btn.grape {
  background: var(--grape);
  color: #fff;
}
.btn.ghost {
  background: transparent;
  box-shadow: none;
  border-style: dashed;
}

/* home */
.watch-card {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 18px;
  align-items: center;
  /* Night sky: the brand's deep ocean teal with a few soft stars. White text on it is 9.5:1. */
  background:
    radial-gradient(circle at 78% 22%, rgba(255, 203, 61, 0.55) 0 2px, transparent 3px),
    radial-gradient(circle at 64% 70%, rgba(255, 255, 255, 0.35) 0 1.5px, transparent 2.5px),
    radial-gradient(circle at 90% 82%, rgba(255, 203, 61, 0.4) 0 1.5px, transparent 2.5px),
    radial-gradient(circle at 56% 18%, rgba(255, 255, 255, 0.3) 0 1px, transparent 2px), var(--night);
  color: #fff;
  border: 3px solid var(--ink);
  border-radius: 28px;
  padding: 22px 24px;
  box-shadow: 0 7px 0 var(--ink);
  text-align: left;
  width: 100%;
}
.watch-card h2 {
  font-size: clamp(28px, 4.4vw, 40px);
}
.watch-card p {
  margin: 6px 0 0;
  font-size: 18px;
  max-width: 46ch;
  opacity: 0.95;
}
.watch-card .tv {
  width: 110px;
  height: 90px;
}
.left-line {
  display: inline-flex !important;
  align-items: center;
  gap: 8px;
  margin-top: 12px !important;
  background: var(--sun);
  color: var(--ink);
  border-radius: 999px;
  padding: 6px 16px;
  font-family: var(--display);
  font-weight: 700;
  font-size: 21px !important;
  font-variant-numeric: tabular-nums;
}
/* Time bank and star meter: a bar that fills to the new total. The fill is a scaleX transform so it
   animates smoothly; calm mode and reduced motion switch the transition off, so it simply jumps. */
.bank {
  position: relative;
  height: 18px;
  width: min(100%, 360px);
  margin-top: 12px;
  border: 3px solid var(--ink);
  border-radius: 999px;
  background: var(--paper);
  overflow: hidden;
}
.watch-card .bank {
  border-color: #fff;
  background: rgba(255, 255, 255, 0.18);
}
.bank.big {
  height: 30px;
  width: min(100%, 420px);
  margin: 4px auto 0;
}
.bank.stars {
  margin: 0 auto;
}
.bank-fill {
  position: absolute;
  inset: 0;
  background: var(--sun);
  transform-origin: left center;
  transform: scaleX(0);
}
.bank-fill.filling {
  transition: transform 1.1s ease-out;
}
.bank-total {
  font-family: var(--display);
  font-weight: 700;
  font-size: 24px;
  color: var(--ink);
}
.today {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}
.today b {
  font-family: var(--display);
  font-size: 22px;
  font-variant-numeric: tabular-nums;
}
.earned {
  font-family: var(--display);
  font-weight: 700;
  font-size: 24px;
  /* --go, not --leaf: leaf green on cream is only 2.8:1, too pale for text. */
  color: var(--go);
}
.earned.level-line {
  color: var(--grape);
}
.section-label {
  font-family: var(--display);
  font-weight: 600;
  font-size: 15px;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.games {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 18px;
}
.game-tile {
  display: flex;
  flex-direction: column;
  gap: 10px;
  align-items: flex-start;
  text-align: left;
  border: 3px solid var(--ink);
  border-radius: var(--r);
  padding: 18px;
  box-shadow: 0 6px 0 var(--ink);
  background: var(--paper);
  min-height: 190px;
  transition:
    transform 0.08s,
    box-shadow 0.08s;
}
.game-tile:active {
  transform: translateY(5px);
  box-shadow: 0 1px 0 var(--ink);
}
.game-tile .art {
  width: 72px;
  height: 72px;
  border-radius: 18px;
  border: 3px solid var(--ink);
  display: grid;
  place-items: center;
}
.game-tile .art svg {
  width: 48px;
  height: 48px;
}
.game-tile h3 {
  font-size: 24px;
}
.game-tile p {
  margin: 0;
  color: var(--ink-soft);
  font-size: 16px;
}
.game-tile .best {
  margin-top: auto;
  font-family: var(--display);
  font-weight: 600;
  font-size: 15px;
  color: var(--ink-soft);
  display: flex;
  gap: 6px;
  align-items: center;
}
.game-tile .best svg {
  width: 18px;
  height: 18px;
}

/* play */
.play-head {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}
.play-head h2 {
  font-size: 30px;
  flex: 1;
  min-width: 0;
}
/* A game's title asks for its full width, so when the line is short of room the progress row moves under the
   title as one piece, instead of squeezing the title or splitting the marks. On a phone the title may wrap
   beside Back. */
#play-title {
  flex: 1 1 auto;
}
@media (max-width: 480px) {
  #play-title {
    flex-basis: 6em;
  }
}
/* Round progress: "1 of 5" in words, then one mark per question. Each kind has its own shape or symbol
   (see lib/marks.js), so colour only adds to it: tick in a solid circle = right, tick in a rounded square = right
   with a hint, tick in a dashed circle = right after another try (never a cross: getting there is good),
   big ring with a dot = this question, empty circle = still to come.
   The row never shrinks: it sits at the end of the title's line, or on its own line under it. */
.dots {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: none;
  max-width: 100%;
  margin-left: auto;
}
.dots-count {
  font-family: var(--display);
  font-weight: 600;
  font-size: 20px;
  line-height: 1;
  white-space: nowrap;
  color: var(--ink-soft);
}
.marks {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  min-width: 0;
}
/* On a phone a long round doesn't fit on one line, so its marks go in two even rows (5 and 5, or 4 and 4),
   read left to right, never one mark left alone on a second line. */
@media (max-width: 480px) {
  .marks[data-n='8'],
  .marks[data-n='10'] {
    display: grid;
    grid-template-columns: repeat(var(--cols), auto);
    justify-items: center;
  }
  .marks[data-n='8'] {
    --cols: 4;
  }
  .marks[data-n='10'] {
    --cols: 5;
  }
}
.dot {
  flex: none;
  display: inline-grid;
  place-items: center;
  box-sizing: border-box;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  border: 2.5px solid var(--ink);
  background: var(--paper);
  color: var(--ink);
}
.dot svg {
  width: 100%;
  height: 100%;
  fill: none;
  stroke: currentColor;
  stroke-width: 3;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.dot svg .fill {
  fill: currentColor;
  stroke: none;
}
.dot.todo {
  width: 16px;
  height: 16px;
  margin: 0 4px;
  border-width: 2.5px;
}
.dot.ok {
  background: var(--sun);
}
.dot.miss {
  border-style: dashed;
  background: var(--pink);
}
.dot.help {
  border-radius: 6px;
  background: var(--sky);
}
.dot.now {
  width: 28px;
  height: 28px;
  border-width: 4px;
}
.stage {
  background: var(--paper);
  border: 3px solid var(--ink);
  border-radius: 30px;
  box-shadow: 0 7px 0 var(--ink);
  padding: clamp(18px, 4vw, 34px);
  display: flex;
  flex-direction: column;
  gap: 24px;
  align-items: center;
  text-align: center;
}
.prompt {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  width: 100%;
}
.ask {
  font-family: var(--display);
  font-weight: 600;
  font-size: 24px;
  color: var(--ink-soft);
}
.big {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(54px, 10vw, 92px);
  line-height: 1;
  font-variant-numeric: tabular-nums;
  letter-spacing: 1px;
}
.sentence {
  font-size: clamp(24px, 3.6vw, 32px);
  font-weight: 700;
  max-width: 28ch;
}
.blank {
  display: inline-block;
  min-width: 3.2em;
  border-bottom: 5px solid var(--grape);
  margin: 0 0.2em;
}
.choices {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 16px;
  width: 100%;
  max-width: 760px;
}
/* For a moment after a question appears, taps pass through the choices (see READY_MS in app.js). Nothing looks different. */
.choices.wait .choice {
  pointer-events: none;
}
.choice {
  border: 3px solid var(--ink);
  border-radius: 20px;
  background: var(--wash-sun);
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(28px, 4.6vw, 40px);
  padding: 18px 10px;
  min-height: 96px;
  box-shadow: 0 6px 0 var(--ink);
  font-variant-numeric: tabular-nums;
  transition:
    transform 0.08s,
    box-shadow 0.08s,
    background 0.15s;
}
.choice small {
  display: block;
  font-size: 16px;
  font-weight: 600;
  color: var(--ink-soft);
}
.choice:active {
  transform: translateY(5px);
  box-shadow: 0 1px 0 var(--ink);
}
.choice.right {
  background: var(--go);
  color: #fff;
}
.choice.right small {
  color: #fff;
}
/* A wrong choice keeps its gentle 0.35s shake (off in calm mode and with reduced motion); the X badge moves with it. */
.choice.wrong {
  position: relative;
  background: var(--wash-tomato);
  border-color: var(--minus);
  color: var(--ink-soft);
  animation: shake 0.35s;
}
/* The X on a wrong choice (issue #17): a round badge sitting over the button's top corner, so the X is clear in every
   mode and the child can still read what they picked. It never flashes. White on --minus passes AA. */
.choice.wrong small {
  color: var(--ink-soft);
}
.choice .x-mark {
  position: absolute;
  top: -14px;
  right: -14px;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: var(--minus);
  border: 3px solid var(--ink);
  box-sizing: border-box;
  pointer-events: none;
}
.choice .x-mark svg {
  display: block;
  width: 100%;
  height: 100%;
  fill: none;
  stroke: #fff;
  stroke-width: 4;
  stroke-linecap: round;
}
.choice.right {
  animation: pop var(--star-pop) var(--ease-soft);
}
@keyframes pop {
  50% {
    transform: scale(1.1);
  }
}
@keyframes bump {
  40% {
    transform: scale(1.3) rotate(-6deg);
  }
}
@keyframes shake {
  25% {
    transform: translateX(-8px);
  }
  50% {
    transform: translateX(8px);
  }
  75% {
    transform: translateX(-4px);
  }
}
.coins {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: center;
  align-items: center;
  max-width: 560px;
}
.coins svg {
  flex: none;
}
.coins.coin-row {
  /* Coin Count's coins are drawn at near-real relative sizes, so give them a wider row (seven fit
     in one row on an iPad in landscape), and line them up along the bottom like coins on a table
     (their value pills line up too). Coins come in two groups, so when the row has to wrap it
     breaks into two even rows. One gap everywhere keeps the spacing even. */
  --coin-gap: 14px 12px;
  max-width: 820px;
  align-items: flex-end;
  gap: var(--coin-gap);
}
.coin-group {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: flex-end;
  gap: var(--coin-gap);
}
/* Two coins that stay together when a group wraps (see coinRow), so a group of four on a phone
   breaks 2 and 2, never 3 and 1. */
.coin-pair {
  display: flex;
  flex: none;
  align-items: flex-end;
  gap: var(--coin-gap);
}
.coin-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  flex: none;
}
.coin-val {
  /* The value pill overlaps the rim a little, so it reads as belonging to that coin. */
  position: relative;
  margin-top: -5px;
  padding: 0 0.55em;
  min-width: 2.6em;
  border: 2.5px solid var(--ink);
  border-radius: 999px;
  background: #fffdf7;
  color: var(--ink);
  font-family: Fredoka, sans-serif;
  font-weight: 700;
  font-size: 22px;
  line-height: 1.3;
  text-align: center;
}
/* Coin Count's bills (levels 8 to 10, issue #49): small play cards, laid out like a coin row, in two
   even groups so a narrow screen never leaves one bill alone. A question with bills and coins
   stacks the bills above the coins. */
.bills.bill-row,
.bill-group {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 14px 12px;
}
.bills.bill-row {
  max-width: 820px;
}
.bill-wrap {
  display: flex;
  flex: none;
}
.bill {
  flex: none;
  max-width: 100%;
  height: auto;
  /* Each bill puts its drawn width in --bill-w; bigger text enlarges it by --bill-scale (see
     BILL_BIG_SCALE in lib/bill-art.js). The outline grows with it (3px to about 3.5px), like the
     thicker borders bigger text gives the answer buttons. Coins are not scaled. */
  width: calc(var(--bill-w) * var(--bill-scale, 1) * 1px);
}
.money {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
}
.seq {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  justify-content: center;
}
.seq span {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(30px, 5vw, 46px);
  border: 3px solid var(--ink);
  border-radius: 16px;
  padding: 6px 14px;
  min-width: 2.2em;
  background: var(--wash-leaf);
  font-variant-numeric: tabular-nums;
}
.seq span.q {
  background: var(--sun);
}
.versus {
  display: flex;
  align-items: center;
  gap: clamp(14px, 4vw, 40px);
}
.versus .big {
  min-width: 2.2em;
}
.versus .mark {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  border: 4px dashed var(--ink-soft);
}
.cheer {
  font-family: var(--display);
  font-weight: 700;
  font-size: 26px;
  color: var(--leaf-text);
  min-height: 1.3em;
}
.result {
  display: flex;
  flex-direction: column;
  align-items: center;
  /* Tight enough that "Play again" and "All games" stay on screen on an iPad in landscape. */
  gap: 10px;
}
/* Bigger text: a little tighter still, so the whole result screen fits an iPad in landscape without scrolling. */
html.a11y-big .result {
  gap: 8px;
}
.result p {
  margin: 0;
}
.result .small-line {
  font-size: 19px;
  max-width: 640px;
}
.result .starrow {
  display: flex;
  gap: 4px;
  flex-wrap: wrap;
  justify-content: center;
}
.result .starrow svg {
  width: 44px;
  height: 44px;
}
.row {
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
  justify-content: center;
}

/* watch */
.tabs {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}
.tab {
  border: 3px solid var(--ink);
  border-radius: 999px;
  padding: 10px 20px;
  background: var(--paper);
  font-family: var(--display);
  font-weight: 600;
  font-size: 19px;
}
.tab[aria-selected='true'] {
  background: var(--ink);
  color: #fff;
}
.vid-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}
.vid {
  border: 3px solid var(--ink);
  border-radius: 18px;
  background: var(--paper);
  box-shadow: 0 5px 0 var(--ink);
  padding: 0;
  overflow: hidden;
  text-align: left;
  display: flex;
  flex-direction: column;
}
.vid .thumb {
  aspect-ratio: 16/9;
  max-width: 100%;
  background: var(--grape);
  display: grid;
  place-items: center;
  position: relative;
  overflow: hidden;
}
.vid .thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  position: absolute;
  inset: 0;
}
.vid .thumb svg {
  width: 56px;
  height: 56px;
  position: relative;
}
.vid .name {
  padding: 10px 14px;
  font-family: var(--display);
  font-weight: 600;
  font-size: 19px;
}
.empty {
  background: var(--paper);
  border: 3px dashed var(--ink-soft);
  border-radius: 22px;
  padding: 26px;
  text-align: center;
  color: var(--ink-soft);
  display: flex;
  flex-direction: column;
  gap: 12px;
  align-items: center;
}
.empty h3 {
  color: var(--ink);
  font-size: 24px;
}
.player-box {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.player-frame {
  position: relative;
  aspect-ratio: 16/9;
  max-width: 100%;
  width: 100%;
  background: #000;
  border: 3px solid var(--ink);
  border-radius: 20px;
  overflow: hidden;
}
.player-frame > div,
.player-frame iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.meter {
  display: flex;
  align-items: center;
  gap: 12px;
  background: var(--paper);
  border: 3px solid var(--ink);
  border-radius: 16px;
  padding: 10px 14px;
  flex-wrap: wrap;
}
.meter .bar {
  flex: 1;
  min-width: 140px;
  height: 18px;
  border: 3px solid var(--ink);
  border-radius: 999px;
  overflow: hidden;
  background: var(--wash-sun);
}
.meter .fill {
  height: 100%;
  background: var(--sun);
  width: 0%;
  transition: width 0.9s linear;
}
.meter .lbl {
  font-family: var(--display);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.notice {
  background: var(--wash-tomato);
  border: 3px solid var(--ink);
  border-radius: 18px;
  padding: 16px 18px;
  font-size: 17px;
}
.notice b {
  font-family: var(--display);
}
.timer-stage {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
  text-align: center;
}
.ring {
  width: min(300px, 70vw);
  height: min(300px, 70vw);
  max-width: 100%;
  position: relative;
}
.ring svg {
  width: 100%;
  height: 100%;
  transform: rotate(-90deg);
}
.ring .center {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
.ring .t {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(48px, 9vw, 72px);
  font-variant-numeric: tabular-nums;
  line-height: 1;
}
.ring .s {
  color: var(--ink-soft);
  font-size: 16px;
}
.hint {
  color: var(--ink-soft);
  max-width: 52ch;
  font-size: 17px;
}

/* overlays */
.overlay {
  position: fixed;
  inset: 0;
  z-index: 50;
  background: rgba(31, 42, 68, 0.72);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: max(16px, env(safe-area-inset-top, 0px)) max(16px, env(safe-area-inset-right, 0px))
    max(16px, env(safe-area-inset-bottom, 0px)) max(16px, env(safe-area-inset-left, 0px));
}
.sheet {
  background: var(--paper);
  border: 4px solid var(--ink);
  border-radius: 32px;
  box-shadow: 0 10px 0 var(--ink);
  width: min(640px, 100%);
  max-height: 100%;
  overflow: auto;
  padding: clamp(20px, 4vw, 34px);
  display: flex;
  flex-direction: column;
  gap: 20px;
  align-items: center;
  text-align: center;
}
.sheet h2 {
  font-size: clamp(30px, 5vw, 42px);
}
.sheet p {
  margin: 0;
  font-size: 19px;
  color: var(--ink-soft);
}
.glass {
  width: 120px;
  height: 150px;
}
.hold {
  position: relative;
  overflow: hidden;
  border: 4px solid var(--ink);
  border-radius: 999px;
  background: var(--wash-leaf);
  font-family: var(--display);
  font-weight: 700;
  font-size: 24px;
  padding: 18px 34px;
  box-shadow: 0 6px 0 var(--ink);
  touch-action: none;
  -webkit-touch-callout: none;
}
.hold .p {
  position: absolute;
  inset: 0;
  background: var(--leaf);
  transform-origin: left;
  transform: scaleX(0);
}
.hold span {
  position: relative;
}
/* Grown-ups lock: pattern pad, PIN field and the quiet "Forgot it?" link */
.ppad {
  display: grid;
  grid-template-columns: repeat(3, 64px);
  gap: 22px;
  justify-content: center;
  padding: 12px;
  margin: 0 auto;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}
.ppad-dot {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  border: 3px solid var(--ink);
  background: var(--paper);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  cursor: pointer;
}
.ppad-dot span {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--ink-soft);
  color: var(--paper);
  font-family: var(--display);
  font-weight: 700;
  font-size: 15px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.ppad-dot[aria-pressed='true'] {
  background: var(--ink);
}
.ppad-dot[aria-pressed='true'] span {
  width: 30px;
  height: 30px;
  background: var(--sun);
  color: var(--ink);
}
/* Messages on the lock screen are read by kids: plain navy, not alarm red. */
#gate-err {
  color: var(--ink);
}
#lock-type button {
  white-space: nowrap;
}
@media (max-width: 480px) {
  .lock-setup .row {
    flex-direction: column;
    align-items: stretch;
  }
  .lock-setup .row .btn.go {
    order: -1;
  }
}
.lock-setup {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.lock-setup .lab {
  font-weight: 700;
}
.txt.lock-pin {
  width: 7ch;
  font-size: 28px;
  letter-spacing: 0.3em;
  text-align: center;
}
.btn.linkish {
  align-self: center;
  min-height: 44px;
  border: none;
  box-shadow: none;
  background: none;
  text-decoration: underline;
  color: var(--ink-soft);
}
.gate-input.code {
  width: 8ch;
}
.gate-input {
  font-family: var(--display);
  font-weight: 700;
  font-size: 40px;
  width: 5ch;
  text-align: center;
  border: 3px solid var(--ink);
  border-radius: 16px;
  padding: 6px;
  -webkit-user-select: text;
  user-select: text;
}
.err {
  color: var(--tomato);
  font-weight: 700;
  min-height: 1.4em;
}
.err.ok {
  color: var(--go);
}

/* parent */
.panel {
  background: var(--paper);
  border: 3px solid var(--ink);
  border-radius: 24px;
  padding: 22px;
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.panel h2 {
  font-size: 28px;
}
/* Collapsible Grown-ups sections (native <details>, see folds.js) */
.panel.fold {
  display: block;
}
.fold > summary {
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: 44px;
  cursor: pointer;
  border-radius: 12px;
}
.fold > summary::-webkit-details-marker {
  display: none;
}
.fold > summary::after {
  content: '';
  flex: none;
  width: 14px;
  height: 14px;
  margin-right: 6px;
  border-right: 4px solid var(--ink);
  border-bottom: 4px solid var(--ink);
  transform: rotate(45deg);
}
.fold[open] > summary::after {
  transform: rotate(225deg);
}
.fold-body {
  display: flex;
  flex-direction: column;
  gap: 18px;
  margin-top: 18px;
}
.field {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.field > label,
.field > .lab {
  font-weight: 700;
}
.seg {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
.seg button {
  border: 3px solid var(--ink);
  border-radius: 12px;
  background: var(--paper);
  padding: 8px 14px;
  font-weight: 700;
  min-height: 44px;
  min-width: 44px;
}
.seg button[aria-pressed='true'] {
  background: var(--sun);
}
.txt {
  border: 3px solid var(--ink);
  border-radius: 12px;
  padding: 10px 12px;
  font-size: 17px;
  min-width: 0;
  width: 100%;
  -webkit-user-select: text;
  user-select: text;
  background: var(--paper);
}
.addrow {
  display: grid;
  grid-template-columns: 1fr 1.4fr auto;
  gap: 10px;
}
.vlist {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.vlist li {
  display: flex;
  align-items: center;
  gap: 10px;
  border: 2px solid var(--ink);
  border-radius: 12px;
  padding: 8px 12px;
}
.addrow.kidrow {
  grid-template-columns: 1fr 160px auto;
}
select.txt.grade,
.vlist li select.txt.grade {
  flex: 0 0 160px;
  width: 160px;
}
/* On phones, a kid's name gets its own line, with the grade and Remove underneath. */
@media (max-width: 640px) {
  #k-list li {
    flex-wrap: wrap;
  }
  #k-list li .txt[data-kn] {
    flex: 1 1 calc(100% - 60px);
    min-width: 10ch;
  }
  #k-list li select.txt.grade {
    flex: 1 1 auto;
    width: auto;
  }
  .addrow.kidrow {
    grid-template-columns: 1fr auto;
  }
  .addrow.kidrow #k-name {
    grid-column: 1 / -1;
  }
  .addrow.kidrow select.txt.grade {
    width: 100%;
  }
}
.vlist li span {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.vlist code {
  color: var(--ink-soft);
  font-size: 14px;
}
.setup {
  color: var(--ink-soft);
  font-size: 16px;
}
.setup ol {
  margin: 6px 0 0;
  padding-left: 22px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.setup b {
  color: var(--ink);
}

.shop {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}
.prize {
  display: flex;
  flex-direction: column;
  gap: 6px;
  align-items: flex-start;
  text-align: left;
  border: 3px dashed var(--ink);
  border-radius: 18px;
  padding: 14px 16px;
  background: var(--paper);
}
.prize.can {
  border-style: solid;
  background: var(--wash-sun);
  box-shadow: 0 5px 0 var(--ink);
}
.prize .cost {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--display);
  font-weight: 700;
  font-size: 22px;
  font-variant-numeric: tabular-nums;
}
.prize .cost svg {
  width: 26px;
  height: 26px;
}
.prize .pn {
  font-family: var(--display);
  font-weight: 600;
  font-size: 20px;
}
.prize .pn .clock-ico {
  width: 22px;
  height: 22px;
  vertical-align: -4px;
  margin-right: 6px;
}
.time-item {
  flex-direction: column;
  align-items: stretch !important;
  gap: 8px !important;
}
.time-item > .lab {
  flex: none;
}
.time-item .ti-head {
  display: flex;
  align-items: center;
  gap: 10px;
}
.time-item .ti-head span {
  flex: 1;
  white-space: normal;
}
.vlist li .cost-in {
  flex: 0 0 96px;
  width: 96px;
  min-height: 44px;
}
/* Prize names wrap instead of being cut off ("Pick th..."). */
.vlist li .prize-name {
  white-space: normal;
  overflow-wrap: anywhere;
}
@media (max-width: 600px) {
  /* On a phone the name gets its own line, with the price and Remove under it. */
  .vlist li.prize-item {
    flex-wrap: wrap;
  }
  .vlist li .prize-name {
    flex: 1 1 100%;
  }
}
.prize .need {
  font-size: 15px;
  color: var(--ink-soft);
}
.lvl {
  background: var(--ink);
  color: #fff;
  border-radius: 999px;
  padding: 2px 10px;
  font-size: 13px;
  letter-spacing: 0.5px;
  margin-right: 4px;
}
.toast {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  bottom: calc(20px + env(safe-area-inset-bottom, 0px));
  z-index: 60;
  background: var(--ink);
  color: #fff;
  font-family: var(--display);
  font-weight: 600;
  font-size: 20px;
  padding: 14px 22px;
  border-radius: 18px;
  width: max-content;
  max-width: calc(100% - 32px);
  text-align: center;
  box-shadow: 0 6px 0 rgba(31, 42, 68, 0.3);
}
.tbl {
  overflow-x: auto;
}
.report {
  width: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}
.report th,
.report td {
  text-align: left;
  padding: 8px 10px;
  border-bottom: 2px solid var(--wash-sun);
}
.report th {
  font-family: var(--display);
  font-size: 14px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.offline {
  font-family: var(--display);
  font-weight: 600;
  font-size: 20px;
  color: var(--ink) !important;
  background: var(--wash-leaf);
  border-radius: 14px;
  padding: 10px 16px;
}
.pill.kid {
  font-size: 19px;
  padding: 5px 14px 5px 6px;
}
.kface {
  display: inline-grid;
  place-items: center;
  width: 64px;
  height: 64px;
  border-radius: 50%;
  border: 3px solid var(--ink);
  font-family: var(--display);
  font-weight: 700;
  font-size: 30px;
  color: var(--ink);
}
.kface.sm {
  width: 32px;
  height: 32px;
  font-size: 16px;
  border-width: 2px;
  flex: none;
}
.kids {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  justify-content: center;
}
.kidpick {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  border: 3px solid var(--ink);
  border-radius: 20px;
  background: var(--wash-sun);
  padding: 16px 20px;
  font-family: var(--display);
  font-weight: 600;
  font-size: 22px;
  box-shadow: 0 5px 0 var(--ink);
  min-width: 130px;
}
.vlist li .txt {
  flex: 1;
  padding: 6px 10px;
}
/* The axolotl guide, just above the games it points at. A still picture: it never moves on its own
   (brand/BRAND.md). The bubble has no hard shadow on purpose, so it never looks like a button. */
/* One row: the guide on the left, the Games label on the right, so the tiles stay in view on iPad. */
.games-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px 18px;
  margin: -6px 0 -8px;
}
.guide {
  display: flex;
  align-items: center;
  gap: 14px;
}
.guide-mascot {
  flex: none;
  width: 64px;
  height: 64px;
}
.guide-line {
  position: relative;
  margin: 0;
  background: var(--paper);
  border: 3px solid var(--ink);
  border-radius: 18px;
  padding: 8px 16px;
  font-family: var(--display);
  font-size: 20px;
  color: var(--ink);
}
/* Speech tail pointing at the mascot. */
.guide-line::before {
  content: '';
  position: absolute;
  left: -11px;
  top: 50%;
  width: 16px;
  height: 16px;
  background: var(--paper);
  border-left: 3px solid var(--ink);
  border-bottom: 3px solid var(--ink);
  transform: translateY(-50%) rotate(45deg);
}
.water-strip {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  background: var(--paper);
  border: 3px solid var(--ink);
  border-radius: 20px;
  padding: 12px 18px;
}
.water-strip > div {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}
.cups {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  align-items: center;
  font-family: var(--display);
  font-weight: 700;
  font-size: 18px;
}
.hintline {
  /* When a hint is scrolled into view (showHint in app.js), leave a little room under it. */
  scroll-margin-bottom: 12px;
  background: var(--wash-leaf);
  border: 2px dashed var(--leaf);
  border-radius: 14px;
  padding: 10px 16px;
  font-size: 18px;
  max-width: 52ch;
}
.hintline .hint-text {
  margin: 0;
}
/* Picture hints (shared by every game that sets hintArt; see lib/hint.js).
   Markup: .hintline > .hint-art (the picture, aria-hidden) + .hint-text (the sentence).
   The box is as wide as its picture, so a picture never wraps, and the sentence wraps under it.
   showHint in app.js puts .art-hint on the stage while a picture hint is open (a class, because
   WebKit did not restyle :has() rules when the hint was filled in).
   Bigger text: one rule in the html.a11y-big block. iPad landscape: the hint moves beside the
   question (the media query after the html.a11y-big block). */
.stage.art-hint > .hintline {
  max-width: 100%;
}
.stage.art-hint > .hintline .hint-text {
  max-width: 46ch;
  margin-inline: auto;
}
.hint-art {
  --art-scale: 1;
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 8px;
}
.hint-art svg {
  max-width: 100%;
  height: auto;
}
/* A picture that puts its width in --w on each svg (style="--w:120") is drawn at --w times
   --art-scale pixels, so bigger text can enlarge it without CSS zoom (WebKit and Chromium lay out
   zoom differently). Narrow screens still shrink it with max-width. */
.hint-art svg[style*='--w'] {
  width: calc(var(--w) * var(--art-scale) * 1px);
}
/* Width rules keyed by each game's picture. Add one per picture class, next to this one:
   .hint-art:has(> .hop-art) + .hint-text     Number Hop ten frames and tens rods
   .hint-art:has(> .coin-steps) + .hint-text  Coin Count running totals (lib/coin-art.js)
   .hint-art:has(> .clock-hint) + .hint-text  Clock Check minute ring (lib/draw.js)
   (These :has() rules are safe: the picture and the sentence are added together.) */
.stage.art-hint > .hintline .hint-art:has(> .hop-art) + .hint-text {
  max-width: 40ch;
}
.stage.art-hint > .hintline .hint-art:has(> .coin-steps) + .hint-text {
  max-width: 38ch;
}
.stage.art-hint > .hintline .hint-art:has(> .clock-hint) + .hint-text {
  max-width: 30ch;
}

/* Coin Count hint (lib/coin-art.js): the child's coins biggest first, the running total above each,
   and "+5¢ = ?" above the last coin, so the child sees one more coin is still to add. Rows are
   balanced (never 6 and 1): seven coins come as two rows (4 and 3), and on a phone each row breaks
   in half again (3 over 2, 2 over 2). The coins sit
   along the bottom, like the question, each with its white value pill under it (issue #67). Running
   totals are plain numbers on a soft sun band above, with square corners and no outline, unlike the
   round outlined pills, so a total never looks like the value of the coin under it. */
.coin-steps {
  display: flex;
  flex-direction: column;
  align-items: center;
  /* A wide gap between two rows, so each running total sits closer to its own coin than to the
     row of coins above it. */
  gap: 24px;
}
/* A row is two halves (see coinStepsHTML). They sit side by side when they fit; on a phone the row
   breaks between them into two even lines (issue #82), with the same wide gap as between rows. A
   half only wraps inside itself as a last resort, so the hint never runs off the side. */
.coin-steps-row,
.coin-steps-half {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: stretch;
  gap: 24px 10px;
  max-width: 100%;
}
.coin-step {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: center;
  gap: 6px;
  flex: none;
}
.coin-step .coin-wrap {
  flex: none;
}
/* Hint coins are drawn smaller, so their pills are a little smaller too, and quieter than the
   running totals above, which are what the hint is about. */
.coin-step .coin-val {
  margin-top: -4px;
  border-width: 2px;
  font-size: 15px;
}
.coin-total,
.coin-next {
  font-family: var(--display);
  font-weight: 700;
  font-size: 22px;
  line-height: 1.2;
  color: var(--ink);
  white-space: nowrap;
}
.coin-total {
  padding: 2px 6px;
  border-radius: 6px;
  background: var(--wash-sun);
  border-bottom: 3px solid var(--sun);
}
.coin-next {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 4px 3px 8px;
  border: 2.5px dashed var(--ink-soft);
  border-radius: 10px;
}
/* The "?" is the strongest thing in the row: the answer is the child's to find. */
.coin-ask {
  display: inline-grid;
  place-items: center;
  min-width: 1.5em;
  padding: 0 4px;
  background: var(--sun);
  border: 3px solid var(--ink);
  border-radius: 8px;
}
/* The totals appear one at a time, in counting order, the first time the hint opens for a question.
   Tapping Hint again (.again) shows them all at once. Off in calm mode and with reduced motion. */
@media (prefers-reduced-motion: no-preference) {
  .hintline:not(.again) .coin-step > :first-child {
    animation: count-on 0.35s ease-out both;
    animation-delay: calc(var(--i, 0) * 0.5s);
  }
}
@keyframes count-on {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
}
.review-tag {
  font-family: var(--display);
  font-weight: 600;
  font-size: 15px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  background: var(--grape);
  color: #fff;
  border-radius: 999px;
  padding: 4px 14px;
}
.slot {
  display: inline-grid;
  place-items: center;
  width: 54px;
  height: 54px;
  border: 3px dashed var(--ink-soft);
  border-radius: 12px;
  font-family: var(--display);
  font-weight: 700;
  font-size: 28px;
  color: var(--ink-soft);
  flex: none;
}
/* Pattern Party: after a right answer the found piece sits in the gap and does one small, slow jiggle,
   then rests (issue #85). Calm mode and reduced motion switch it off, so the piece just appears. */
.pattern-row .fill {
  display: inline-grid;
  place-items: center;
  flex: none;
}
@media (prefers-reduced-motion: no-preference) {
  .pattern-row .fill {
    animation: jiggle 0.6s var(--ease-soft) 1;
  }
}
@keyframes jiggle {
  25% {
    transform: rotate(-7deg);
  }
  60% {
    transform: rotate(5deg);
  }
  85% {
    transform: rotate(-2deg);
  }
}
.btn:disabled {
  opacity: 0.45;
  box-shadow: none;
  cursor: default;
  transform: none;
}
.eq {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(12px, 3vw, 28px);
  flex-wrap: wrap;
}
/* The sign is just the symbol, bold and as big as the numbers, coloured green (+) or red (−) (issue #66).
   No box, no word: the words "add" and "take away" are heard (read-aloud, VoiceOver), not shown.
   The shapes differ, so colour is extra. Both colours pass 3:1 as large text on the card, and high contrast
   swaps in the darker --plus and --minus. */
.op {
  font-family: var(--display);
  font-weight: 700;
  /* The font's + and − are drawn smaller and thinner than its digits, so the sign is set a little bigger and
     given a thin outline in its own colour, to match the numbers' size and weight. */
  font-size: clamp(66px, 12vw, 112px);
  line-height: 0.8;
  -webkit-text-stroke: 0.035em currentColor;
}
.op.plus {
  color: var(--plus);
}
.op.minus {
  color: var(--minus);
}
html.a11y-big .op {
  font-size: clamp(78px, 14.5vw, 132px);
}
/* The end of the number sentence: "= ?", kept together on one line. The box is where the answer goes;
   its thin dashed outline is the same as the answer slots in other games, so it is not mistaken for a button. */
.eq-end {
  display: inline-flex;
  align-items: center;
  gap: clamp(12px, 3vw, 28px);
  white-space: nowrap;
}
.eq-sign {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(54px, 10vw, 92px);
  line-height: 1;
}
.eq-ask {
  display: inline-grid;
  place-items: center;
  min-width: clamp(76px, 12vw, 108px);
  height: clamp(76px, 12vw, 108px);
  border: 3px dashed var(--ink-soft);
  border-radius: 20px;
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(44px, 8vw, 72px);
  line-height: 1;
  color: var(--ink-soft);
}
html.a11y-big .eq-sign {
  font-size: clamp(64px, 12vw, 108px);
}

/* Maths hint pictures (lib/tenframe.js). Solid dot: you have it. Dot with a plus: you add it.
   Hollow crossed-out dot: you take it away. Shape carries the meaning; colour only helps.
   The parts never wrap onto two lines (the arrow must point at the frames); on a narrow
   screen the columns shrink together instead. */
.hop-art {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  gap: 14px;
  flex-wrap: nowrap;
}
.hop-art svg {
  display: block;
  max-width: 100%;
  height: auto;
}
.hop-art .pv-col {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  flex: 0 1 auto;
  min-width: 0;
}
.hop-art .pv-head {
  font-family: var(--display);
  font-weight: 700;
  font-size: 20px;
  line-height: 1.3;
  min-height: 1.3em;
}
.hop-art .tf-box {
  fill: var(--paper);
  stroke: var(--ink);
  stroke-width: 2.5;
}
.hop-art .tf-ten .tf-box {
  stroke-width: 5;
}
.hop-art .tf-traded .tf-box {
  stroke-width: 3;
  stroke-dasharray: 7 5;
}
.hop-art .tf-line {
  fill: none;
  stroke: var(--ink-soft);
  stroke-width: 1.5;
}
.hop-art .d-have {
  fill: var(--ink);
}
.hop-art .d-add circle {
  fill: var(--plus);
  stroke: var(--ink);
  stroke-width: 1.5;
}
.hop-art .d-add path {
  stroke: #fff;
  stroke-width: 3;
  stroke-linecap: round;
}
.hop-art .d-take circle {
  fill: var(--paper);
  stroke: var(--ink);
  stroke-width: 2;
}
.hop-art .d-take path {
  stroke: var(--minus);
  stroke-width: 3;
  stroke-linecap: round;
}
.hop-art .rod rect {
  stroke: var(--ink);
  stroke-width: 2;
}
.hop-art .rod path {
  fill: none;
  stroke: var(--paper);
  stroke-width: 1.5;
}
.hop-art .rod-have rect {
  fill: var(--ink);
}
.hop-art .rod-add rect {
  fill: var(--plus);
}
.hop-art .rod .rod-plus {
  stroke: #fff;
  stroke-width: 3;
  stroke-linecap: round;
}
.hop-art .rod-take rect {
  fill: var(--paper);
}
.hop-art .rod-take path {
  stroke: var(--ink-soft);
}
.hop-art .rod .slash {
  stroke: var(--minus);
  stroke-width: 3.5;
  stroke-linecap: round;
}
.hop-art .rod-traded {
  fill: none;
  stroke: var(--ink);
  stroke-width: 2.5;
  stroke-dasharray: 6 4;
}
.hop-art .mark-plus,
.hop-art .arrow {
  fill: none;
  stroke: var(--ink);
  stroke-width: 4;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* The answer message with the mascot beside it. The mascot has a fixed slot (it never slides with the length of
   the message) and the slot's size is always reserved, so nothing jumps when it appears. The text sits beside it. */
.buddy {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  column-gap: 12px;
  width: min(100%, 460px);
  min-height: 56px;
  text-align: left;
}
/* The buddy's slot is exactly the buddy's size (--bs), so the message or title beside it never moves. */
.buddy-slot {
  --bs: 56px;
  flex: none;
  width: var(--bs);
  height: var(--bs);
}
.buddy-slot[data-buddy-size='44'] {
  --bs: 44px;
}
.buddy-slot[data-buddy-size='76'] {
  --bs: 76px;
}
.buddy-mascot {
  display: block;
  width: var(--bs);
  height: var(--bs);
  visibility: hidden;
}
.buddy-mascot.on {
  visibility: visible;
}
/* The result screen and the math break: the title stays centred, with the buddy in the equal space to its
   left. The title comes first in the page, so VoiceOver reads it first; the grid puts the buddy on the left. */
.result-head,
.break-buddy {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  column-gap: 14px;
  width: 100%;
}
:is(.result-head, .break-buddy) > h2 {
  grid-row: 1;
  grid-column: 2;
}
:is(.result-head, .break-buddy) > .buddy-slot {
  grid-row: 1;
  grid-column: 1;
  justify-self: end;
}
/* The bigger result-screen buddy reaches into the gaps above and below, so the title row is no taller than the
   title alone and the buttons below never move. */
.result-head > .buddy-slot {
  margin-block: -12px;
}
/* Phones: the mascot sits above the message, so "Not quite. Try again!" keeps its one line. Room for both is
   always reserved. */
@media (max-width: 420px) {
  .buddy {
    grid-template-columns: minmax(0, 1fr);
    justify-items: center;
    row-gap: 4px;
    /* 44px mascot + 4px gap + one line of the 26px message, with room to spare. */
    min-height: 90px;
    text-align: center;
  }
  .buddy-slot,
  .buddy-slot[data-buddy-size='44'] {
    --bs: 44px;
  }
  .buddy-slot[data-buddy-size='76'] {
    --bs: 52px;
  }
  /* No room for equal space beside the title: the buddy goes centred above it. */
  .result-head,
  .break-buddy {
    grid-template-columns: minmax(0, 1fr);
    row-gap: 6px;
  }
  :is(.result-head, .break-buddy) > h2 {
    grid-row: 2;
    grid-column: 1;
  }
  :is(.result-head, .break-buddy) > .buddy-slot {
    grid-column: 1;
    justify-self: center;
  }
  .result-head > .buddy-slot {
    margin-block: 0;
  }
}
.cheer.pop {
  animation: pop var(--star-pop) var(--ease-soft);
}
.cheer.bad {
  color: var(--minus);
}
.pill.bump {
  animation: bump var(--star-bump) var(--ease-soft);
}
.spark {
  position: fixed;
  z-index: 70;
  pointer-events: none;
  left: 0;
  top: 0;
}
.summary {
  margin: 0;
  font-size: 18px;
  line-height: 1.5;
}
.signin {
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-width: 440px;
  margin-top: 14px;
}
.sso {
  width: 100%;
  text-align: center;
}
.or {
  color: var(--ink-soft);
  font-size: 15px;
}
.sso ~ .or {
  text-align: center;
}
.emailrow {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}
.emailrow .txt {
  flex: 1 1 220px;
  min-width: 0;
}
.acct-card {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px 16px;
  border: 2px solid var(--ink);
  border-radius: 16px;
  padding: 14px 16px;
}
.acct-who {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
  overflow-wrap: anywhere;
}
.acct-group {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 18px;
  padding-top: 18px;
  border-top: 2px dashed var(--ink-soft);
}
.acct-group .lab {
  font-weight: 700;
}
.acct-group .setup {
  margin: 0;
}
.acct-btns {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 10px;
}
.btn.danger {
  border-color: var(--minus);
  color: var(--minus);
}
.fold-body > .err:empty {
  display: none;
}
.acct-status {
  color: var(--ink-soft);
  font-size: 15px;
}
.acct-status.bad {
  color: var(--minus);
}
.addbreak {
  display: flex;
  flex-direction: column;
  gap: 10px;
  border: 2px dashed var(--ink-soft);
  border-radius: 16px;
  padding: 14px;
  margin-top: 6px;
}
.seg .ico {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 6px 10px;
}
.seg .ico svg {
  width: 30px;
  height: 30px;
}
.seg button .x {
  margin-left: 8px;
  font-weight: 700;
  color: var(--minus);
}
.a11y-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}
.a11y-item {
  display: flex;
  flex-direction: column;
  gap: 6px;
  border: 2px solid var(--wash-sun);
  border-radius: 14px;
  padding: 12px 14px;
}
.a11y-item .lab {
  font-weight: 700;
}
.a11y-item p {
  margin: 0;
  color: var(--ink-soft);
  font-size: 15px;
}
.voice-item {
  grid-column: 1 / -1;
}
.voice-item .sub {
  font-weight: 700;
  font-size: 15px;
}
.voice-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.voice-field select {
  max-width: 420px;
}
.voice-item [data-try-voice] {
  align-self: flex-start;
  margin: 4px 0 6px;
}
.breakline {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(26px, 4vw, 34px);
  color: var(--ink) !important;
  max-width: 24ch;
}
.breakicon svg {
  width: 110px;
  height: 110px;
}
html.a11y-big body {
  font-size: 21px;
}
html.a11y-big .choice {
  min-height: 132px;
  font-size: clamp(34px, 5.6vw, 50px);
  border-width: 4px;
}
html.a11y-big .btn {
  font-size: 23px;
  padding: 16px 24px;
}
html.a11y-big .btn.small {
  font-size: 19px;
  padding: 12px 18px;
}
html.a11y-big .big {
  font-size: clamp(64px, 12vw, 108px);
}
html.a11y-big .ask {
  font-size: 28px;
}
html.a11y-big .guide-line {
  font-size: 26px;
}
html.a11y-big .coin-val {
  font-size: 29px;
  border-width: 3px;
}
html.a11y-big .sentence {
  font-size: clamp(28px, 4.4vw, 38px);
}
html.a11y-big .game-tile h3 {
  font-size: 28px;
}
/* Bigger text makes the round progress marks bigger too. */
html.a11y-big .dot {
  width: 32px;
  height: 32px;
  border-width: 3px;
}
html.a11y-big .dot.help {
  border-radius: 8px;
}
html.a11y-big .dot.now {
  width: 36px;
  height: 36px;
  border-width: 5px;
}
html.a11y-big .dot.todo {
  width: 20px;
  height: 20px;
  border-width: 3px;
}
html.a11y-big .dots-count {
  font-size: 24px;
}
/* Bigger text makes every picture hint bigger too (one rule for all games' hintArt). The scale
   applies to pictures that set --w; their column names get bigger text with the rest of the page. */
html.a11y-big .hint-art {
  --art-scale: 1.2;
}
html.a11y-big {
  --bill-scale: 1.15;
}
html.a11y-big .hop-art .pv-head {
  font-size: 24px;
}
html.a11y-big :is(.coin-total, .coin-next) {
  font-size: 26px;
}
html.a11y-big .coin-step .coin-val {
  border-width: 2.5px;
  font-size: 18px;
}
/* Phones (issue #82): a half row of three hint coins, with their totals, fits across even at 320px
   wide, with default or bigger text, so a row breaks 3 over 2 and never leaves a coin alone. The
   coins are drawn a little smaller (a loonie is still about 62px across, 68px with bigger text),
   the gaps and the panel's side padding are a little tighter, the step still to do stacks its "?"
   under it, and with bigger text the totals stay a size up from default. Pills keep their size, so every value stays easy to read. */
@media (max-width: 400px) {
  .hintline:has(.coin-steps) {
    padding-inline: 8px;
  }
  .hint-art:has(> .coin-steps) {
    --art-scale: 0.82;
  }
  html.a11y-big .hint-art:has(> .coin-steps) {
    --art-scale: 0.9;
  }
  .coin-steps-row,
  .coin-steps-half {
    column-gap: 6px;
  }
  html.a11y-big .coin-total {
    font-size: 23px;
  }
  /* Each total sits just above its own coin, even next to the taller "+10¢ = ?" box. */
  .coin-step {
    justify-content: flex-end;
  }
  /* "+10¢ =" sits over its "?", so the step still to do is no wider than a coin with its total. */
  .coin-next,
  html.a11y-big .coin-next {
    flex-direction: column;
    gap: 4px;
    padding: 3px 4px 6px;
    font-size: 20px;
  }
}
/* iPad landscape: an open picture hint sits beside the choices, under the number sentence, so the
   sentence stays where it was, and the choices and the whole hint fit on one screen. Shared by every
   game with hintArt. Dense flow puts the hint in the first free rows of the right column. */
@media (orientation: landscape) and (min-width: 1000px) {
  .stage.art-hint {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-auto-flow: dense;
    column-gap: 28px;
    row-gap: 18px;
    align-content: start;
    justify-items: center;
  }
  .stage.art-hint > * {
    grid-column: 1;
  }
  .stage.art-hint > :is(.prompt, .review-tag) {
    grid-column: 1 / -1;
  }
  /* Even rows beside the hint: two rows of two, or one row of three (renderQ sets data-n). */
  .stage.art-hint > .choices {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .stage.art-hint > .choices[data-n='3'] {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
  .stage.art-hint > .hintline {
    grid-column: 2;
    grid-row: span 3;
    align-self: start;
    max-width: 52vw;
  }
  /* Clock Check: the question clock is tall, so the hint clock starts beside it (renderQ sets
     data-game) instead of under it. Back, the question clock and the whole hint then fit on one
     iPad screen, with bigger text too. */
  .stage.art-hint[data-game='clock'] > .prompt {
    grid-column: 1;
  }
  .stage.art-hint[data-game='clock'] > .hintline {
    grid-row: span 2;
  }
  /* "Not quite. Try again!" (with the mascot beside it) goes under the hint panel, beside the Hint button, where there is room,
     not below the fold under the buttons. order only changes where the grid places it (after the
     hint), not the reading order. */
  .stage.art-hint[data-game='clock'] > .buddy {
    grid-column: 2;
    order: 1;
    align-self: start;
  }
  /* Bigger text: the number sentence, two rows of choices, the buttons and the hint must still
     fit on one iPad screen with room to spare, so the choices and gaps are a little tighter here
     (the numbers stay just as big). */
  html.a11y-big .stage.art-hint {
    row-gap: 12px;
    padding-block: 22px;
  }
  html.a11y-big .stage.art-hint > .prompt {
    gap: 10px;
  }
  html.a11y-big .stage.art-hint .choice {
    min-height: 104px;
  }
}
html.a11y-contrast {
  --ground: #ffffff;
  --ink-soft: #1f2a44;
  --wash-sun: #ffffff;
  --wash-leaf: #ffffff;
  --wash-tomato: #ffffff;
  --plus: #0b6b3d;
  --minus: #b3261e;
  --leaf-text: var(--plus);
}
/* High contrast: the logo's teal-to-mint letters are too pale, so the wordmark turns solid ink. The star and its
   deep teal outline stay as they are (the outline already gives gold on white a strong edge). */
html.a11y-contrast .brand .logo .wordmark path {
  fill: var(--ink);
}
html.a11y-contrast body {
  background-image: none;
}
html.a11y-contrast .choice,
html.a11y-contrast .btn,
html.a11y-contrast .game-tile,
html.a11y-contrast .stage,
html.a11y-contrast .sheet,
html.a11y-contrast .panel,
html.a11y-contrast .acct-card,
html.a11y-contrast .guide-line,
html.a11y-contrast .guide-line::before {
  border-width: 4px;
}
html.a11y-contrast .acct-group {
  border-top-color: var(--ink);
}
html.a11y-contrast .choice.right {
  background: #0b6b3d;
}
/* High contrast: coin animals turn solid navy so they stand out from the metal. */
html.a11y-contrast .coin .coin-art {
  fill: var(--ink);
}
html.a11y-contrast .coin .coin-line {
  stroke: var(--ink);
}
/* High contrast: bill symbols turn solid navy, and the inner border darkens, like the coins. */
html.a11y-contrast .bill .bill-art {
  fill: var(--ink);
  stroke: var(--ink);
}
html.a11y-contrast .bill .bill-art-light {
  stroke: #fff;
  fill: none;
}
html.a11y-contrast .bill .bill-edge {
  stroke: var(--ink);
}
html.a11y-contrast .hintline {
  border: 3px solid var(--ink);
}
/* High contrast: plain white quarters on the hint clock (the ink marks still show each quarter), and
   running totals with a solid ink line under them instead of the soft band. */
html.a11y-contrast .clock-hint .qtr {
  fill: #fff;
}
html.a11y-contrast .coin-total {
  border-bottom-color: var(--ink);
}
html.a11y-contrast .coin-next {
  border-color: var(--ink);
}
/* High contrast: progress marks are black on white; their shapes already say what each one means. */
html.a11y-contrast .dot.ok,
html.a11y-contrast .dot.help,
html.a11y-contrast .dot.miss {
  background: var(--paper);
}
html.a11y-calm body {
  background-image: none;
}
html.a11y-calm *,
html.a11y-calm *::before,
html.a11y-calm *::after {
  animation: none !important;
  transition: none !important;
}
.choice.kbd-focus {
  outline: 5px solid var(--grape);
  outline-offset: 4px;
}
@media (max-width: 640px) {
  .a11y-grid {
    grid-template-columns: 1fr;
  }
}
.ft {
  display: flex;
  align-items: stretch;
  gap: 10px;
  flex-wrap: wrap;
  justify-content: center;
  margin-bottom: 14px;
}
.ft-step {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  min-width: 150px;
  padding: 10px 16px;
  border: 3px solid var(--ink);
  border-radius: 16px;
  background: var(--paper);
  text-align: center;
}
.ft-step span {
  font-family: var(--display);
  font-weight: 600;
  font-size: 14px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.ft-step b {
  font-family: var(--display);
  font-weight: 700;
  font-size: 21px;
}
.ft-step small {
  color: var(--ink-soft);
  font-size: 15px;
  font-variant-numeric: tabular-nums;
}
.ft-step.now {
  background: var(--sun);
}
.ft-arrow {
  align-self: center;
  font-family: var(--display);
  font-weight: 700;
  font-size: 28px;
}
@media (max-width: 900px) {
  .games {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (max-width: 760px) {
  .games,
  .vid-grid,
  .shop {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .watch-card .tv {
    width: 80px;
    height: 66px;
  }
}
@media (max-width: 480px) {
  .games,
  .vid-grid,
  .shop {
    grid-template-columns: 1fr;
  }
  .watch-card {
    grid-template-columns: 1fr;
  }
  .watch-card .tv {
    display: none;
  }
  .addrow {
    grid-template-columns: 1fr;
  }
  .game-tile {
    min-height: 0;
  }
}
@media (prefers-reduced-motion: reduce) {
  * {
    animation: none !important;
    transition: none !important;
  }
}

/* feedback form (Grown-ups) */
.fb {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.fb textarea {
  resize: vertical;
  min-height: 110px;
  font-family: var(--body);
  -webkit-user-select: text;
  user-select: text;
}
.fb-hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  opacity: 0;
}
.fb-more summary {
  cursor: pointer;
  font-weight: 700;
  min-height: 44px;
  display: flex;
  align-items: center;
}
.fb-more dl {
  display: grid;
  gap: 4px;
  margin: 4px 0 10px;
  font-size: 15px;
}
.fb-more dl div {
  display: grid;
  grid-template-columns: minmax(130px, 34%) 1fr;
  gap: 10px;
}
.fb-more dt {
  color: var(--ink-soft);
}
.fb-more dd {
  margin: 0;
  overflow-wrap: anywhere;
}
.fb-status {
  font-weight: 700;
}
.fb-status[data-tone='good'] {
  color: var(--go);
}
.fb-status[data-tone='bad'] {
  color: var(--minus);
}
