/* ─────────── Shared bits ─────────── */

.hint {
  font-size: var(--text-sm);
  color: var(--ink-soft);
  max-width: 60ch;
}

.piece--chosen {
  outline: 4px solid var(--good);
  outline-offset: 3px;
}

/* ─────────── Writing: letters ─────────── */

.letter-slots,
.letter-tiles {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: center;
}

.letter-tiles {
  background: var(--paper-deep);
}

.slot--letter {
  width: clamp(46px, 6vw, 64px);
  height: clamp(54px, 7vw, 72px);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.3rem, 3.4vw, 2rem);
}

.piece--letter {
  width: clamp(46px, 6vw, 64px);
  height: clamp(54px, 7vw, 72px);
  flex-direction: column;
  gap: 0;
  line-height: 1;
  background: linear-gradient(180deg, #fff 0%, #fff4e2 100%);
}

.piece__upper {
  font-size: clamp(1.15rem, 3vw, 1.7rem);
}

.piece__lower {
  font-size: clamp(0.75rem, 1.8vw, 1rem);
  color: var(--write-deep);
}

/* ─────────── English: colours ─────────── */

.word-area {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 130px;
  background: var(--paper-deep);
}

.word-card {
  font-size: clamp(1.8rem, 6vw, 2.8rem);
  padding: 0.5rem 1.5rem;
  background: var(--card);
}

.buckets {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: var(--gap);
}

.bucket {
  position: relative;
  min-height: 130px;
  flex-direction: column;
  gap: 0.4rem;
  padding: 0.85rem;
  background: var(--card);
  border: var(--line);
  box-shadow: var(--lift-sm);
  overflow: hidden;
}

.bucket__paint {
  width: 100%;
  flex: 1;
  min-height: 60px;
  border-radius: 12px;
  background: var(--bucket);
  border: var(--line-thin);
}

/* The name is read by the speaker button, never printed on the bucket:
   a printed word would turn the lesson into text matching. */
.bucket__label {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ─────────── Maths: arithmetic ─────────── */

/* Held sideways, an iPad stretched the sum into a wide empty bar above a
   620px pad, with the score and the level chips stranded at the left edge.
   One centred column keeps the whole game together. The bar stays full width.
*/
.board--sum > :not(.topbar) {
  width: 100%;
  max-width: 760px;
  margin-inline: auto;
}

.sum-play {
  display: grid;
  gap: var(--space-block);
}

/* Wide and short — an iPad on its side, or a laptop. The sum takes the left,
   the keys the right, and the screen stops being half empty. */
@media (min-width: 900px) and (min-aspect-ratio: 13 / 10) {
  .board--sum > :not(.topbar) {
    max-width: none;
  }

  .sum-play {
    grid-template-columns: minmax(0, 1fr) minmax(330px, 0.62fr);
    align-items: center;
  }

  .sum-play .pad {
    max-width: 520px;
    margin-inline: 0;
  }

  /* The row takes the height the bar and the chips leave, so the board does
     not sit in the top half with a band of empty paper below it. */
  .sum-play {
    min-height: 52vh;
    align-items: stretch;
  }

  .sum-play .pad {
    align-self: center;
  }
}

.sum-card {
  display: grid;
  place-items: center;
  padding-block: clamp(1.25rem, 4vw, 2.5rem);
  background: linear-gradient(180deg, #fff 0%, #eefaf2 100%);
}

.sum {
  display: flex;
  align-items: center;
  gap: clamp(0.5rem, 2vw, 1.25rem);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(2.4rem, 9vw, 4.5rem);
  font-variant-numeric: tabular-nums;
  flex-wrap: wrap;
  justify-content: center;
}

.sum__op {
  color: var(--maths-deep);
}

.sum__answer {
  min-width: clamp(90px, 18vw, 150px);
  padding: 0.1em 0.3em;
  text-align: center;
  border: 4px dashed var(--maths-deep);
  border-radius: var(--radius);
  background: #fff;
}

.sum__answer--good {
  border-style: solid;
  background: rgba(47, 182, 115, 0.2);
}

.sum__answer--retry {
  border-color: var(--retry);
  border-style: solid;
  background: rgba(255, 201, 60, 0.22);
  font-size: 0.6em;
}

.pad {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: var(--gap);
  max-width: 620px;
  width: 100%;
  margin-inline: auto;
}

.pad__key {
  height: clamp(64px, 11vw, 82px);
  font-size: clamp(1.5rem, 4vw, 2rem);
  /* The grid sets the width; the button minimum would push the row off screen. */
  min-width: 0;
  padding-inline: 0;
}

.pad__key--wide {
  grid-column: span 2;
}

/* ─────────── Maths: geometry ─────────── */

.geometry {
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) minmax(220px, 1fr);
  gap: var(--space-block);
  align-items: start;
}

@media (max-width: 820px) {
  .geometry {
    grid-template-columns: 1fr;
  }
}

.stage-card {
  padding: 0.5rem;
  background: #fff;
}

.stage {
  width: 100%;
  height: auto;
  display: block;
  touch-action: none;
}

.stage__grid line {
  stroke: rgba(35, 32, 28, 0.12);
  stroke-width: 1;
}

.stage__shape {
  fill: rgba(168, 85, 247, 0.22);
  stroke: var(--shape-deep);
  stroke-width: 5;
  stroke-linejoin: round;
}

.stage__shape--triangle {
  fill: rgba(56, 193, 114, 0.22);
  stroke: var(--maths-deep);
}

.stage__handle {
  fill: var(--star);
  stroke: var(--ink);
  stroke-width: 4;
  cursor: grab;
}

.stage__handle:active {
  cursor: grabbing;
}

.stage__label {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 20px;
  fill: var(--ink);
  paint-order: stroke;
  stroke: #fff;
  stroke-width: 5px;
}

.readout {
  background: linear-gradient(180deg, #fff 0%, #f5edff 100%);
}

.readout__name {
  font-size: var(--text-lg);
  margin-bottom: 0.5rem;
}

.readout__list {
  list-style: none;
  display: grid;
  gap: 0.35rem;
  font-variant-numeric: tabular-nums;
}

.readout__list li {
  padding: 0.35rem 0.6rem;
  background: rgba(255, 255, 255, 0.8);
  border: var(--line-thin);
  border-radius: 12px;
}

.readout__badge {
  margin-top: 0.75rem;
  font-family: var(--font-display);
  font-weight: 600;
  background: var(--star);
  border: var(--line-thin);
  border-radius: 999px;
  padding: 0.3rem 0.8rem;
  display: inline-block;
}

/* ─────────── Subgame menu ─────────── */

.menu--games {
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
}

.tile--game {
  min-height: 150px;
}

/* ─────────── Writing: keyboard games ─────────── */

.letter-stage {
  display: grid;
  place-items: center;
  padding-block: clamp(1rem, 3vw, 2rem);
  background: linear-gradient(180deg, #fff 0%, #fff1e0 100%);
}

.big-letter {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1;
}

.big-letter__upper {
  font-size: clamp(4rem, 16vw, 8rem);
}

.big-letter__lower {
  font-size: clamp(2.5rem, 10vw, 5rem);
  color: var(--write-deep);
}

.keyboard {
  display: grid;
  gap: 8px;
  justify-items: center;
  max-width: 780px;
  width: 100%;
  margin-inline: auto;
}

.keyboard__row {
  display: flex;
  gap: 8px;
  justify-content: center;
  width: 100%;
}

.key {
  flex: 1 1 0;
  max-width: 68px;
  min-width: 0;
  height: clamp(52px, 8vw, 66px);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1rem, 2.6vw, 1.5rem);
  background: var(--card);
  border: var(--line-thin);
  border-radius: 12px;
  box-shadow: 0 3px 0 var(--ink);
  transition:
    transform var(--fast) ease,
    background var(--fast) ease;
}

.key--left {
  background: #fff6ee;
}

.key--right {
  background: #eef6ff;
}

.key:active {
  transform: translateY(3px);
  box-shadow: none;
}

.key--space {
  flex: 3 1 0;
  max-width: 260px;
  font-size: var(--text-sm);
}

.key--back {
  max-width: 100px;
}

/* Drawn in its real place, but this game's answers are single words. A
   key that does nothing is what a child expects from a key that is not
   part of the word; a key that types a space they did not want is a wrong
   answer the keyboard gave them. */
.key--off {
  opacity: 0.4;
  cursor: default;
  box-shadow: none;
}

.key--off:active {
  transform: none;
}

.key--target {
  background: var(--star);
  transform: translateY(-3px);
  box-shadow: 0 6px 0 var(--ink);
}

.key--good {
  background: var(--good);
  color: #fff;
}

.key--bad {
  background: var(--retry);
}

/* Copy a word or a sentence */

.copy {
  display: grid;
  gap: 0.5rem;
  background: linear-gradient(180deg, #fff 0%, #fff1e0 100%);
}

.copy__label {
  font-size: var(--text-sm);
  color: var(--ink-soft);
}

.copy__model,
.copy__typed {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  min-height: 64px;
  align-items: center;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.8rem, 6vw, 3rem);
  line-height: 1;
}

.copy__typed {
  border-top: 2px dashed var(--rule, rgba(35, 32, 28, 0.25));
  padding-top: 0.5rem;
}

.glyph {
  min-width: 0.7em;
  text-align: center;
  padding: 0.1em 0.12em;
  border-radius: 8px;
}

.glyph--good {
  color: var(--maths-deep);
  background: rgba(56, 193, 114, 0.16);
}

.glyph--bad {
  color: #b3261e;
  background: rgba(255, 201, 60, 0.35);
}

.glyph--next {
  box-shadow: inset 0 -6px 0 var(--star);
}

.caret {
  width: 3px;
  height: 1em;
  background: var(--ink);
  animation: blink 1s steps(2, start) infinite;
}

@keyframes blink {
  to {
    visibility: hidden;
  }
}

/* ─────────── English: picture choices ─────────── */

.choices {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--gap);
}

.choice {
  min-height: 130px;
  font-size: clamp(3rem, 9vw, 4.5rem);
  background: var(--card);
  border: var(--line);
  box-shadow: var(--lift-sm);
}

/*
  Right and wrong may never be told apart by colour alone.

  Around one boy in twelve cannot separate this green from a red, and the
  quiz used nothing else. The shake already marks a wrong answer; this marks
  a right one, so both carry a shape as well as a colour.
*/
.choice--show,
.choice--right {
  position: relative;
  border-color: var(--good);
  background: rgba(47, 182, 115, 0.18);
}

.choice--show::after,
.choice--right::after {
  content: '✓';
  position: absolute;
  top: 4px;
  right: 8px;
  font-family: var(--font-display);
  font-size: 1.1rem;
  line-height: 1;
  color: var(--good);
}

/* ─────────── Maths: help pictures ─────────── */

.help-area {
  display: grid;
  gap: 0.6rem;
  justify-items: center;
  margin-top: 0.75rem;
  min-height: 1.5rem;
}

.hint--help {
  font-size: var(--text-base);
  text-align: center;
  color: var(--ink);
}

.hint--answer {
  font-family: var(--font-display);
  font-weight: 600;
  background: var(--star);
  border: var(--line-thin);
  border-radius: 999px;
  padding: 0.25rem 0.9rem;
}

.dots-help {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
  justify-content: center;
}

.dots-help__group {
  display: grid;
  grid-template-columns: repeat(5, auto);
  gap: 6px;
  padding: 8px;
  border: var(--line-thin);
  border-radius: 12px;
  background: #fff;
}

.dots-help__sign {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.5rem;
}

.dot-mark {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--maths);
  border: 2px solid var(--ink);
}

.dot-mark--new {
  background: var(--star);
}

.dot-mark--off {
  background: #fff;
  opacity: 0.45;
}

.pad__key--ok {
  grid-column: span 4;
}

/* ─────────── Geometry: angles ─────────── */

.stage__arc {
  fill: none;
  stroke: var(--shape-deep);
  stroke-width: 4;
  opacity: 0.8;
}

.stage__arc--right {
  stroke: var(--write-deep);
  stroke-width: 6;
}

.stage__angle {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 19px;
  fill: var(--shape-deep);
  paint-order: stroke;
  stroke: #fff;
  stroke-width: 5px;
}

/* ─────────── Reward: sticker on the end screen ─────────── */

.prize {
  display: grid;
  justify-items: center;
  gap: 0.2rem;
  padding: 1rem 1.6rem;
  border: var(--line);
  border-radius: var(--radius-lg);
  background: var(--paper-deep);
  box-shadow: var(--lift-sm);
  animation: pop-in 320ms var(--ease-pop);
}

.prize--rare {
  background: linear-gradient(140deg, #e8f1ff 0%, #d7e8ff 100%);
}

.prize--legendary {
  background: linear-gradient(140deg, #fff3c4 0%, #ffd97a 60%, #ffe9a8 100%);
  box-shadow:
    var(--lift-sm),
    0 0 0 6px rgba(255, 183, 3, 0.25);
}

.prize__label {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-sm);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-soft);
}

.prize__emoji {
  font-size: clamp(3rem, 12vw, 4.5rem);
  line-height: 1.1;
}

.prize--legendary .prize__emoji {
  animation: wiggle 900ms var(--ease-pop) infinite;
}

.prize__name {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-base);
}

.prize__count {
  font-size: var(--text-sm);
  color: var(--ink-soft);
}

@keyframes wiggle {
  0%, 100% { transform: rotate(-5deg); }
  50% { transform: rotate(5deg); }
}

/* ─────────── Album ─────────── */

.home-foot {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: clamp(0.75rem, 0.5rem + 1.5vw, 1.5rem);
  padding-top: 0.5rem;
}

.home-foot .btn {
  flex: 1 1 220px;
  max-width: 320px;
}

@media (max-width: 680px) {
  .home-foot .btn {
    flex-basis: 100%;
    max-width: none;
  }
}

.album {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
  gap: var(--gap);
}

.album__slot {
  display: grid;
  justify-items: center;
  gap: 0.15rem;
  padding: 0.9rem 0.5rem;
  min-height: 118px;
  background: var(--card);
  border: var(--line);
  border-radius: var(--radius);
  box-shadow: var(--lift-sm);
  position: relative;
}

.album__slot--empty {
  background: rgba(255, 255, 255, 0.45);
  border-style: dashed;
  box-shadow: none;
  opacity: 0.75;
}

.album__slot--rare {
  border-color: var(--english-deep);
}

.album__slot--legendary {
  border-color: var(--star);
  background: linear-gradient(140deg, #fffaf0 0%, #ffeec2 100%);
}

.album__slot--unique {
  border-color: #7c4dff;
  background: linear-gradient(140deg, #f6f1ff 0%, #e6d9ff 55%, #fbe9ff 100%);
  box-shadow: 0 0 0 1px rgba(124, 77, 255, 0.25), var(--lift-sm);
}

.album__slot--empty.album__slot--rare,
.album__slot--empty.album__slot--legendary,
.album__slot--empty.album__slot--unique {
  background: rgba(255, 255, 255, 0.45);
  box-shadow: none;
}

.album__emoji {
  font-size: 2.6rem;
  line-height: 1;
}

.album__name {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-sm);
}

.album__count {
  position: absolute;
  top: 6px;
  right: 8px;
  font-size: 0.8rem;
  font-family: var(--font-display);
  font-weight: 600;
  background: var(--star);
  border: var(--line-thin);
  border-radius: 999px;
  padding: 0 0.35rem;
}

.album__bar {
  height: 18px;
  border: var(--line-thin);
  border-radius: 999px;
  background: #fff;
  overflow: hidden;
}

.album__fill {
  height: 100%;
  background: repeating-linear-gradient(
    45deg,
    var(--maths) 0 10px,
    var(--maths-deep) 10px 20px
  );
  transition: width var(--normal) ease;
}

/* ─────────── Buddy ─────────── */

.buddy {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}

.buddy--pop .buddy__face {
  animation: pop-in 260ms var(--ease-pop);
}

.buddy__face {
  font-size: 2rem;
  line-height: 1;
}

.buddy__bubble {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-sm);
  background: var(--card);
  border: var(--line-thin);
  border-radius: 999px;
  padding: 0.1rem 0.7rem;
  opacity: 0;
  transform: translateX(-6px);
  transition:
    opacity var(--fast) ease,
    transform var(--fast) ease;
}

.buddy__bubble--on {
  opacity: 1;
  transform: translateX(0);
}

/* ─────────── Secrets (nothing here is announced) ─────────── */

.secret-star {
  position: fixed;
  right: calc(6px + env(safe-area-inset-right, 0px));
  bottom: calc(6px + env(safe-area-inset-bottom, 0px));
  width: 34px;
  height: 34px;
  font-size: 14px;
  color: rgba(35, 32, 28, 0.18);
  background: none;
  border: none;
  z-index: 30;
}

.critter {
  position: fixed;
  font-size: clamp(2.4rem, 8vw, 3.4rem);
  line-height: 1;
  background: none;
  border: none;
  padding: 10px;
  z-index: 55;
  filter: drop-shadow(0 3px 4px rgba(35, 32, 28, 0.25));
}

.critter--caught {
  animation: caught 420ms var(--ease-pop) forwards;
}

/* Walks slowly along the floor, and turns to face the way it goes. */
.critter--walk {
  left: -80px;
  animation: critter-walk var(--seconds) linear forwards;
}

/* Comes down on a thread, hangs about, then climbs back up. */
.critter--drop {
  top: -60px;
  animation: critter-drop var(--seconds) ease-in-out forwards;
}

.critter--drop::before {
  content: '';
  position: absolute;
  left: 50%;
  bottom: 100%;
  width: 2px;
  height: 100vh;
  background: rgba(35, 32, 28, 0.35);
}

/* Drifts upward, swaying. */
.critter--float {
  bottom: -60px;
  animation: critter-float var(--seconds) ease-in-out forwards;
}

/* Hops across in arcs. */
.critter--hop {
  left: -80px;
  animation:
    critter-walk var(--seconds) linear forwards,
    critter-hop 1.4s ease-in-out infinite;
}

/* Leans in from the side, looks around, and goes back. */
.critter--peek {
  left: -30px;
  animation: critter-peek var(--seconds) ease-in-out forwards;
}

.critter--peek-right {
  left: auto;
  right: -30px;
  animation-name: critter-peek-right;
}

@keyframes critter-walk {
  to {
    left: calc(100vw + 60px);
  }
}

@keyframes critter-drop {
  0% {
    transform: translateY(0);
  }
  30% {
    transform: translateY(45vh);
  }
  65% {
    transform: translateY(38vh);
  }
  100% {
    transform: translateY(-10vh);
  }
}

@keyframes critter-float {
  0% {
    transform: translate(0, 0) rotate(-8deg);
  }
  25% {
    transform: translate(9vw, -25vh) rotate(8deg);
  }
  50% {
    transform: translate(-4vw, -50vh) rotate(-6deg);
  }
  75% {
    transform: translate(7vw, -75vh) rotate(6deg);
  }
  100% {
    transform: translate(0, -105vh) rotate(0deg);
  }
}

@keyframes critter-hop {
  0%,
  100% {
    transform: translateY(0) rotate(0deg);
  }
  45% {
    transform: translateY(-34px) rotate(-8deg);
  }
}

@keyframes critter-peek {
  0%,
  100% {
    transform: translateX(-100%);
  }
  20%,
  80% {
    transform: translateX(30%);
  }
}

@keyframes critter-peek-right {
  0%,
  100% {
    transform: translateX(100%) scaleX(-1);
  }
  20%,
  80% {
    transform: translateX(-30%) scaleX(-1);
  }
}

@keyframes caught {
  to {
    transform: scale(1.8);
    opacity: 0;
  }
}

/* A child who asked for less motion still gets the visitor, just calmer. */
@media (prefers-reduced-motion: reduce) {
  .critter--walk,
  .critter--hop {
    left: 40vw;
  }

  .critter--drop {
    top: 30vh;
  }

  .critter--float {
    bottom: 30vh;
  }

  .critter--peek {
    transform: translateX(20%);
  }
}

.confetti {
  position: fixed;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
  z-index: 58;
}

.confetti span {
  position: absolute;
  top: -40px;
  animation: fall 3.4s linear forwards;
}

@keyframes fall {
  to {
    transform: translateY(105vh) rotate(320deg);
  }
}

.golden {
  filter: sepia(1) saturate(4) hue-rotate(-18deg) brightness(1.1);
  animation: wiggle 1.1s var(--ease-pop) infinite;
}

/* The buddy sleeps when the game waits too long. */
.is-idle .buddy__face::after {
  content: ' 💤';
  font-size: 1rem;
}

/* Night colours: the reward for finding the corner star. */
.theme-night {
  --paper: #1b1f2a;
  --paper-deep: #232838;
  --card: #2b3042;
  --ink: #f3f1ec;
  --ink-soft: #b9bdc9;
  --line: 3px solid #0d0f16;
  --line-thin: 2px solid #0d0f16;
  --lift: 0 6px 0 #0d0f16;
  --lift-sm: 0 4px 0 #0d0f16;
  color: var(--ink);
}

.theme-night .slot {
  background: rgba(255, 255, 255, 0.08);
}

.theme-night .key--left {
  background: #333a4f;
}

.theme-night .key--right {
  background: #2c3550;
}

/* ─────────── Clock ─────────── */

.clock-card {
  display: grid;
  place-items: center;
  background: linear-gradient(180deg, #fff 0%, #eefaf2 100%);
}

.clock {
  width: min(70vw, 300px);
  height: auto;
  touch-action: none;
}

.clock--live {
  cursor: grab;
}

.clock__face {
  fill: #fff;
  stroke: var(--ink);
  stroke-width: 5;
}

.clock__tick {
  stroke: rgba(35, 32, 28, 0.35);
  stroke-width: 2;
}

.clock__tick--hour {
  stroke: var(--ink);
  stroke-width: 4;
}

.clock__number {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 26px;
  fill: var(--ink);
}

.clock__hand {
  stroke-linecap: round;
}

.clock__hand--hour {
  stroke: var(--maths-deep);
  stroke-width: 12;
}

.clock__hand--minute {
  stroke: var(--write-deep);
  stroke-width: 7;
}

.clock__pin {
  fill: var(--ink);
}

.clock-prompt {
  display: grid;
  justify-items: center;
}

.choices--time .choice--time,
.choices--letters .choice--letter {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.5rem, 5vw, 2.2rem);
  min-height: 76px;
}

/* ─────────── Money ─────────── */

.shop {
  display: flex;
  align-items: center;
  gap: 1.2rem;
  flex-wrap: wrap;
  background: linear-gradient(180deg, #fff 0%, #fff6e6 100%);
}

.shop__icon {
  font-size: clamp(3rem, 10vw, 4.5rem);
}

.shop__name {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-lg);
}

.shop__price {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.6rem, 6vw, 2.4rem);
  color: var(--maths-deep);
}

.shop__note {
  font-size: var(--text-sm);
  color: var(--ink-soft);
}

.tray-card {
  background: #fffdf7;
}

.tray {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  min-height: 76px;
}

.tray--wrong {
  animation: shake 340ms ease;
}

.tray__total {
  margin-left: auto;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-lg);
}

.coins {
  display: flex;
  flex-wrap: wrap;
  gap: var(--gap);
  justify-content: center;
}

.coin {
  min-width: 78px;
  height: 78px;
  border-radius: 50%;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.95rem;
  background: radial-gradient(circle at 34% 30%, #ffe9a8 0%, #f5c542 55%, #d9a520 100%);
  border: var(--line-thin);
  box-shadow: var(--lift-sm);
}

.coin--picked {
  background: radial-gradient(circle at 34% 30%, #d8f5e3 0%, #8ad9ae 60%, #4aa87a 100%);
  height: 62px;
  min-width: 62px;
}

/* ─────────── Maze ─────────── */

.maze-card {
  position: relative;
  display: grid;
  justify-items: center;
  width: 100%;
  min-width: 0;
  background: #fffdf7;
}

.maze {
  position: relative;
  display: grid;
  grid-template-columns: repeat(var(--cols), minmax(0, 1fr));
  gap: 6px;
  /* The cells must follow the grid, not the other way round: their own
     size once pushed the card wider than the screen. */
  width: 100%;
  max-width: 420px;
}

.maze__cell {
  position: relative;
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  min-width: 0;
  font-size: clamp(1.1rem, 5vw, 1.8rem);
  background: #f1f5ef;
  border: var(--line-thin);
  border-radius: 10px;
}

.maze__cell--wall {
  background: repeating-linear-gradient(45deg, #6b5b4a 0 8px, #5b4d3f 8px 16px);
  border-color: #3d332a;
}

.maze__cell--goal {
  background: #fff3c4;
}

/* A battery the robot has not reached yet. It sits off the straight route
   on purpose, so fetching it is a decision the child has to plan for. */
.maze__cell--battery {
  background: #e8f7ff;
}

/* Collected. The cell keeps its place so the child can see where the
   battery was, which is what makes a shorter second plan possible. */
.maze__cell--taken {
  background: #f1f5ef;
  opacity: 0.55;
}

/* Where the robot has been on this run. A program that goes wrong is much
   easier to read when the path it took is still on the board. */
.maze__cell--trail {
  box-shadow: inset 0 0 0 3px rgba(58, 160, 255, 0.35);
}

/* Three facts, in the order they matter: how short the answer can be, how
   many batteries are left, and how long the plan is so far. */
.maze-status {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.4rem 0.9rem;
  font-family: var(--font-display);
  font-size: var(--text-sm);
  color: var(--ink-soft);
}

.maze-status__item {
  padding: 0.25rem 0.7rem;
  background: #fff;
  border: var(--line-thin);
  border-radius: 999px;
}

/* The plan has gone past the perfect answer. Not wrong — the robot may
   still find the star — so this warns rather than scolds. */
.maze-status__item--over {
  background: #fff3c4;
}

.robot {
  position: absolute;
  top: 0;
  left: 0;
  line-height: 1;
  font-size: clamp(1.6rem, 6vw, 2.4rem);
  display: grid;
  place-items: center;
  transition: transform 380ms var(--ease-pop);
  pointer-events: none;
  z-index: 2;
}

.robot--bump {
  animation: shake 380ms ease;
}

.program-card {
  background: #fff;
}

.program {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  min-height: 60px;
  align-items: center;
}

.program__empty {
  font-size: var(--text-sm);
  color: var(--ink-soft);
}

.blocks {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--gap);
  width: 100%;
  max-width: 460px;
  margin-inline: auto;
}

.block {
  min-width: 0;
  height: 78px;
  display: grid;
  place-items: center;
  gap: 1px;
  font-size: 1.7rem;
  background: var(--card);
  border: var(--line);
  border-radius: var(--radius);
  box-shadow: var(--lift-sm);
}

.block__label {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.72rem;
  color: var(--ink-soft);
}

.block--placed {
  min-width: 52px;
  height: 52px;
  font-size: 1.4rem;
  background: #eef6ff;
}

/* The step that walked into a wall. It stays marked after the robot goes
   back to the start, because it is the answer to "what went wrong?". */
.block--failed {
  position: relative;
  background: #ffe1e1;
  border-color: #c0392b;
  animation: shake 380ms ease;
}

.block--failed::after {
  content: '✗';
  position: absolute;
  top: 1px;
  right: 4px;
  font-family: var(--font-display);
  font-size: 0.85rem;
  line-height: 1;
  color: #c0392b;
}

/* ─────────── Polish spelling ─────────── */

.gap-card {
  display: grid;
  justify-items: center;
  gap: 0.6rem;
  background: linear-gradient(180deg, #fff 0%, #ffeef0 100%);
}

.gap-word {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(2.4rem, 11vw, 4.5rem);
  letter-spacing: 0.04em;
}

/* ─────────── Levels ─────────── */

.levels {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}

.levels__label {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-sm);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink-soft);
}

.levels__name {
  font-size: var(--text-sm);
  color: var(--ink-soft);
}

.level {
  min-width: 46px;
  height: 46px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.1rem;
  background: var(--card);
  border: var(--line-thin);
  border-radius: 12px;
}

.level--on {
  background: var(--star);
  box-shadow: var(--lift-sm);
}

/* ─────────── Fractions and signs ─────────── */

.fraction {
  display: inline-grid;
  justify-items: center;
  line-height: 1;
  font-size: 0.8em;
}

.fraction__bar {
  width: 1.4em;
  height: 4px;
  background: var(--ink);
  margin: 0.12em 0;
  border-radius: 2px;
}

.choices--signs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
  gap: var(--gap);
}

.choice--sign {
  min-height: 84px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.6rem, 6vw, 2.4rem);
  background: var(--card);
  border: var(--line);
  box-shadow: var(--lift-sm);
}

/* ─────────── Patterns ─────────── */

.pattern-card {
  display: grid;
  gap: 0.75rem;
  justify-items: center;
  background: linear-gradient(180deg, #fff 0%, #eef4ff 100%);
}

.pattern {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: center;
}

.pattern__cell {
  min-width: 68px;
  height: 68px;
  display: grid;
  place-items: center;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.3rem, 4vw, 1.9rem);
  background: #fff;
  border: var(--line-thin);
  border-radius: 14px;
}

.pattern__cell--gap {
  border-style: dashed;
  background: rgba(255, 201, 60, 0.25);
}

/* ─────────── Settings ─────────── */

.setup {
  display: grid;
  gap: 0.6rem;
  max-width: 680px;
}

.setup__label {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-base);
}

.field {
  font: inherit;
  font-size: var(--text-base);
  padding: 0.7rem 0.9rem;
  border: var(--line-thin);
  border-radius: 12px;
  background: #fff;
  color: var(--ink);
  width: 100%;
}

.field--area {
  resize: vertical;
  min-height: 130px;
}

/* ─────────── Shared quiz screen ─────────── */

.quiz__prompt {
  display: grid;
  justify-items: center;
  gap: 0.4rem;
  padding-block: clamp(1rem, 3vw, 2rem);
  background: linear-gradient(180deg, #fff 0%, #f2f7ff 100%);
}

.quiz__face {
  font-size: clamp(4rem, 16vw, 7rem);
  line-height: 1.05;
}

.quiz__prompt--flag .quiz__face {
  font-size: clamp(4.5rem, 20vw, 8rem);
}

.quiz__label {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-lg);
  text-align: center;
}

.choice--text {
  min-height: 78px;
  padding: 0.5rem 0.75rem;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1rem, 2.6vw, 1.35rem);
  text-align: center;
  background: var(--card);
  border: var(--line);
  box-shadow: var(--lift-sm);
}

/* A long silence quietly fades two wrong answers. Nobody is told. */
.choice--dim {
  opacity: 0.35;
  transition: opacity 600ms ease;
}

/* ─────────── Story problems ─────────── */

.story {
  display: flex;
  align-items: center;
  gap: 1rem;
  max-width: 44ch;
  text-align: left;
}

.story__icon {
  font-size: clamp(2.5rem, 8vw, 3.5rem);
  flex-shrink: 0;
}

.story__text {
  font-family: var(--font-body);
  font-size: clamp(1.05rem, 3vw, 1.4rem);
  line-height: 1.45;
}

/* ─────────── Daily review and parent screen ─────────── */

.tile--review {
  min-height: 0;
  flex-direction: row;
  align-items: center;
  gap: 1rem;
  background: linear-gradient(120deg, #fff 0%, #eef6ff 100%);
  transform: none;
}

.tile--review:hover {
  transform: translateY(-4px);
}

.tile--due {
  background: linear-gradient(120deg, #fff8e4 0%, #ffeaa8 100%);
}

.quiz__prompt--daily .quiz__face {
  font-size: clamp(2.2rem, 8vw, 3.4rem);
}

.table {
  display: grid;
  gap: 2px;
  margin-top: 0.5rem;
}

.table__head,
.table__row {
  display: grid;
  grid-template-columns: 1fr 70px 70px 60px;
  gap: 8px;
  align-items: center;
  padding: 0.45rem 0.5rem;
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
}

.table__head {
  font-family: var(--font-display);
  font-weight: 600;
  color: var(--ink-soft);
  border-bottom: var(--line-thin);
}

.table__row:nth-child(odd) {
  background: rgba(255, 255, 255, 0.6);
  border-radius: 8px;
}

.light {
  display: inline-block;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  border: 2px solid var(--ink);
  vertical-align: -2px;
}

/* Colour is never the only signal: the numbers next to it say the same. */
.light--green {
  background: #2fb673;
}
.light--amber {
  background: #ffc93c;
}
.light--red {
  background: #e4495c;
}
.light--grey {
  background: #d4d4d4;
}

/* Patterns, so the colour game works without colour vision too. */
.bucket__paint--stripes {
  background-image: repeating-linear-gradient(45deg, rgba(255,255,255,0.55) 0 8px, transparent 8px 16px);
}
.bucket__paint--dots {
  background-image: radial-gradient(rgba(255,255,255,0.7) 3px, transparent 4px);
  background-size: 16px 16px;
}
.bucket__paint--checks {
  background-image:
    linear-gradient(45deg, rgba(0,0,0,0.18) 25%, transparent 25% 75%, rgba(0,0,0,0.18) 75%),
    linear-gradient(45deg, rgba(0,0,0,0.18) 25%, transparent 25% 75%, rgba(0,0,0,0.18) 75%);
  background-size: 18px 18px;
  background-position: 0 0, 9px 9px;
}
.bucket__paint--waves {
  background-image: repeating-radial-gradient(circle at 0 100%, transparent 0 8px, rgba(255,255,255,0.5) 8px 10px);
}
.bucket__paint--grid {
  background-image:
    linear-gradient(rgba(0,0,0,0.2) 2px, transparent 2px),
    linear-gradient(90deg, rgba(0,0,0,0.2) 2px, transparent 2px);
  background-size: 16px 16px;
}
.bucket__paint--zigzag {
  background-image: repeating-linear-gradient(135deg, rgba(255,255,255,0.5) 0 6px, transparent 6px 14px);
}
.bucket__paint--diamonds {
  background-image:
    repeating-linear-gradient(45deg, rgba(255,255,255,0.45) 0 2px, transparent 2px 12px),
    repeating-linear-gradient(-45deg, rgba(255,255,255,0.45) 0 2px, transparent 2px 12px);
}
/* The only dark-on-light pattern: white paint needs a mark that shows. */
.bucket__paint--weave {
  background-image:
    repeating-linear-gradient(0deg, rgba(0,0,0,0.22) 0 3px, transparent 3px 11px),
    repeating-linear-gradient(90deg, rgba(0,0,0,0.22) 0 3px, transparent 3px 11px);
}

/* ─────────── Today's goals ─────────── */

.goals {
  padding: clamp(1rem, 0.7rem + 1vw, 1.5rem);
  background: var(--card);
  border: var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--lift-sm);
}

.goals--done {
  background: linear-gradient(120deg, #fff8e4 0%, #ffeaa8 100%);
}

.goals__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.7rem;
}

.goals__title {
  font-size: var(--text-base);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--ink-soft);
}

.goals__count {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-base);
}

.goals__row {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.goal {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.45rem 0.9rem 0.45rem 0.65rem;
  font-size: var(--text-sm);
  background: var(--paper-deep);
  border: var(--line-thin);
  border-radius: 999px;
  opacity: 0.75;
}

.goal--done {
  background: rgba(47, 182, 115, 0.2);
  border-color: var(--good);
  opacity: 1;
}

.goal__icon {
  font-size: 1.1rem;
  line-height: 1;
}

.goal-done {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-base);
  background: var(--star);
  border: var(--line-thin);
  border-radius: 999px;
  padding: 0.3rem 1rem;
}

/* ─────────── Parent screen: room to breathe ─────────── */

.parents {
  display: grid;
  gap: clamp(1rem, 0.7rem + 1vw, 1.6rem);
}

.parents .card {
  display: grid;
  gap: 0.8rem;
  padding: clamp(1.15rem, 0.8rem + 1.5vw, 1.75rem);
}

.parents .readout__name {
  font-size: var(--text-lg);
  margin-bottom: 0;
}

.parents .readout__list {
  gap: 0.5rem;
}

.parents .readout__list li {
  padding: 0.6rem 0.8rem;
  line-height: 1.4;
}

/* Settings or Progress. Two visits, not one screen: a parent changing a
   setting is not the same parent checking how the week went, and showing
   both at once meant scrolling past one to reach the other. */
.parents__tabs {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.4rem;
  padding: 0.4rem;
  background: var(--paper-deep);
  border: var(--line-thin);
  border-radius: 999px;
}

.parents__tab {
  padding: 0.7rem 0.9rem;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-base);
  color: var(--ink-soft);
  background: transparent;
  border: 2px solid transparent;
  border-radius: 999px;
  cursor: pointer;
  transition: background 160ms ease, color 160ms ease;
}

.parents__tab:hover {
  color: var(--ink);
  background: rgba(255, 255, 255, 0.6);
}

.parents__tab--on {
  color: var(--ink);
  background: var(--card);
  border-color: var(--ink);
  box-shadow: var(--lift-sm);
}

.parents__tab:focus-visible {
  outline: 3px solid var(--focus, #1f5fa8);
  outline-offset: 2px;
}

.parents__panel {
  display: grid;
  gap: clamp(1rem, 0.7rem + 1vw, 1.6rem);
}

/* Said once, above the greyed cards, instead of a padlock on every one. */
.parents__shut {
  display: flex;
  align-items: flex-start;
  gap: 0.8rem;
  line-height: 1.5;
}

.parents__shut-mark {
  font-size: 1.4rem;
  line-height: 1.2;
}

.parents .hud {
  gap: 0.75rem;
}

.table {
  gap: 4px;
  margin-top: 0.25rem;
}

.table__head,
.table__row {
  grid-template-columns: minmax(0, 1fr) 62px 62px 56px;
  gap: 10px;
  padding: 0.6rem 0.7rem;
  font-size: var(--text-base);
}

.table__head {
  font-size: var(--text-sm);
  padding-bottom: 0.4rem;
}

.table__row span:not(:first-child) {
  text-align: right;
}

.table__row span:first-child {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
  overflow-wrap: anywhere;
}

.table__row:nth-child(odd) {
  background: rgba(255, 255, 255, 0.75);
}

@media (max-width: 560px) {
  .table__head {
    display: none;
  }

  .table__row {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: 'name counts';
    row-gap: 2px;
  }

  .table__row span:nth-child(2)::after {
    content: ' facts';
  }

  .table__row span:nth-child(3)::after {
    content: ' strong';
  }

  .table__row span:nth-child(4)::after {
    content: ' due';
  }

  .table__row span:not(:first-child) {
    font-size: var(--text-sm);
    color: var(--ink-soft);
    text-align: left;
  }
}

/* The review card reads left to right, like a sentence. */
.tile--review {
  justify-content: flex-start;
}

.tile--review .tile__icon {
  font-size: 2.6rem;
}

/* ─────────── Screen sizes, per game ─────────── */

@media (max-width: 680px) {
  /* The keyboard is the widest thing in the game: let it use the full width. */
  .keyboard {
    gap: 6px;
  }

  .keyboard__row {
    gap: 6px;
  }

  .key {
    height: clamp(46px, 11vw, 58px);
    border-radius: 10px;
  }

  .pad {
    gap: 10px;
  }

  .pad__key {
    height: clamp(58px, 13vw, 72px);
  }

  .sum {
    gap: 0.4rem;
  }

  .choices {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
  }

  .choice {
    min-height: 104px;
  }

  .choice--text {
    min-height: 68px;
    font-size: 1rem;
  }

  .buckets {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .bucket {
    min-height: 104px;
  }

  .coins {
    gap: 8px;
  }

  .coin {
    min-width: 66px;
    height: 66px;
    font-size: 0.85rem;
  }

  .letter-slots,
  .letter-tiles {
    gap: 5px;
  }

  .goals__row {
    gap: 6px;
  }

  .goal {
    padding: 0.3rem 0.6rem;
    font-size: 0.85rem;
  }

  .quiz__face {
    font-size: clamp(3.2rem, 22vw, 5rem);
  }

  .maze {
    max-width: 100%;
  }
}

/* Landscape phone: put the prompt beside the answers instead of above. */
@media (orientation: landscape) and (max-height: 560px) {
  .quiz__prompt {
    padding-block: 0.4rem;
  }

  .quiz__face {
    font-size: clamp(2.4rem, 12vh, 4rem);
  }

  .key {
    height: clamp(38px, 9vh, 52px);
  }

  .pad__key {
    height: clamp(44px, 10vh, 62px);
  }

  .big-letter__upper {
    font-size: clamp(3rem, 22vh, 6rem);
  }

  .clock {
    width: min(42vh, 260px);
  }

  .geometry {
    grid-template-columns: minmax(0, 1.4fr) minmax(180px, 1fr);
  }
}

/* ─────────── Home header ─────────── */

.hero__row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}

/* The wordmark, with the same line under it as the public site. The word
   starts at x=140 of a 520x120 artwork, which is 1.167 of the height. */
/* The same size as the public header: one brand, one size. */
.hero__brand {
  --logo-h: 50px;
  display: block;
  text-decoration: none;
  /* The brand and the big title are two different things. Without this they
     read as one stacked block. */
  margin-bottom: 0.5rem;
}

.hero__brand .logo__mark {
  height: var(--logo-h);
  width: auto;
  display: block;
}

.logo__word {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 92px;
  letter-spacing: -0.02em;
  fill: var(--ink);
}

.logo__sweet {
  stroke: var(--ink);
  stroke-width: 5;
}

.logo__line {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 20px;
  text-transform: uppercase;
  fill: #8d8478;
}

@media (max-width: 560px) {
  .hero__row {
    gap: 0.5rem;
  }

  .hero__brand {
    --logo-h: 36px;
    margin-bottom: 0.25rem;
  }

  .hero h1 {
    font-size: clamp(2.3rem, 1.2rem + 6vw, 3rem);
  }
}

/* The switch and the parents button share the right of the brand row. */
.hero__tools {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-shrink: 0;
}

/* EN | PL. One pill split in two, the language on show filled in ink so it
   reads as "you are here" and the other reads as the way across. */
.lang-switch {
  display: inline-flex;
  flex-shrink: 0;
  height: 48px;
  border: var(--line-thin);
  border-radius: 999px;
  background: var(--card);
  overflow: hidden;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.95rem;
  letter-spacing: 0.04em;
}

.lang-switch__on,
.lang-switch__go {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 48px;
  padding: 0 0.7rem;
  text-decoration: none;
}

.lang-switch__on {
  background: var(--ink);
  color: var(--paper);
}

.lang-switch__go {
  color: var(--ink-soft);
  transition: background var(--fast) ease, color var(--fast) ease;
}

.lang-switch__go:hover {
  background: var(--paper-deep);
  color: var(--ink);
}

.lang-switch__go:focus-visible {
  outline: 3px solid var(--english);
  outline-offset: -3px;
}

@media (max-width: 680px) {
  .lang-switch {
    height: 42px;
  }

  .lang-switch__on,
  .lang-switch__go {
    min-width: 44px;
    padding: 0 0.55rem;
  }
}

.hero__parents {
  flex-shrink: 0;
  min-height: 48px;
  font-size: 0.95rem;
  padding: 0 0.9rem;
  color: var(--ink-soft);
}

/* On a phone the button sits beside a headline that is already wrapping.
   A pill reads as a small secondary control instead of a second card. */
@media (max-width: 680px) {
  .hero__parents {
    min-height: 42px;
    font-size: 0.9rem;
    padding: 0 1rem;
    border-radius: 999px;
    border-style: solid;
    background: var(--card);
    box-shadow: var(--lift-sm);
  }
}

/* The alphabet strip: a hint he opens himself, not one that is pushed at him. */
.alphabet-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  justify-content: center;
  padding: 0.6rem;
  background: var(--paper-deep);
  border: var(--line-thin);
  border-radius: var(--radius);
}

.alphabet-strip__letter {
  min-width: 26px;
  text-align: center;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1rem;
  color: var(--ink-soft);
}

/* ─────────── Encouragement ─────────── */

.toast {
  position: fixed;
  left: 50%;
  /* Below the header: a message must never cover the way back. */
  top: calc(76px + env(safe-area-inset-top, 0px));
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 0.5rem;
  max-width: min(92vw, 420px);
  padding: 0.6rem 1.1rem;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-base);
  background: var(--card);
  border: var(--line);
  border-radius: 999px;
  box-shadow: var(--lift-sm);
  z-index: 70;
  animation: toast-in 320ms var(--ease-pop);
}

.toast--out {
  animation: toast-out 380ms ease forwards;
}

.toast__icon {
  font-size: 1.3rem;
}

@keyframes toast-in {
  from {
    transform: translate(-50%, -24px);
    opacity: 0;
  }
}

@keyframes toast-out {
  to {
    transform: translate(-50%, -24px);
    opacity: 0;
  }
}

/* ─────────── Reward goal ─────────── */

.quest {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: clamp(0.85rem, 0.6rem + 1vw, 1.25rem);
  background: linear-gradient(120deg, #fff 0%, #ffeef7 100%);
  border: var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--lift-sm);
}

.quest--done {
  background: linear-gradient(120deg, #fff8e4 0%, #ffe29a 100%);
}

.quest__icon {
  font-size: clamp(2rem, 7vw, 2.8rem);
  flex-shrink: 0;
}

.quest__body {
  display: grid;
  gap: 0.25rem;
  min-width: 0;
}

.quest__title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-lg);
  line-height: 1.15;
  overflow-wrap: anywhere;
}

.quest__note {
  font-size: var(--text-sm);
  color: var(--ink-soft);
}

.quest__dots {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 0.3rem;
}

.quest__dot {
  width: 18px;
  height: 18px;
  border: var(--line-thin);
  border-radius: 6px;
  background: #fff;
}

.quest__dot--done {
  background: var(--good);
}

.quest-fields {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 0.75rem;
}

.quest-fields .setup__label {
  display: grid;
  gap: 0.3rem;
  font-size: var(--text-sm);
}

.field--small {
  max-width: 140px;
}

/* ─────────── Sign-in hint ─────────── */

.sign-in-hint {
  justify-self: center;
  align-self: center;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 48px;
  max-width: 100%;
  padding: 0.6rem 1.35rem;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-sm);
  line-height: 1.3;
  text-align: center;
  color: var(--ink);
  background: var(--card);
  border: var(--line-thin);
  border-radius: 999px;
  box-shadow: var(--lift-sm);
}

.sign-in-hint:hover {
  transform: translateY(-2px);
}

.code-line code {
  display: inline-block;
  margin-top: 0.25rem;
  padding: 0.15rem 0.5rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.85em;
  background: var(--paper-deep);
  border: var(--line-thin);
  border-radius: 8px;
  overflow-wrap: anywhere;
  -webkit-user-select: text;
  user-select: text;
}

/* ─────────── Did you know? ─────────── */

.tile--discover {
  display: grid;
  gap: 0.6rem;
  padding: clamp(1rem, 0.7rem + 1vw, 1.5rem);
  min-height: 0;
  transform: none;
  background: linear-gradient(120deg, #fff 0%, #eef6ff 100%);
}

.tile--discover:hover {
  transform: translateY(-4px);
}

.discover {
  display: flex;
  align-items: center;
  gap: 1rem;
  text-align: left;
  background: none;
  border: none;
  padding: 0;
  color: inherit;
  min-width: 0;
}

.discover__icon {
  font-size: clamp(2.2rem, 8vw, 3rem);
  flex-shrink: 0;
}

.discover__body {
  display: grid;
  gap: 0.3rem;
  min-width: 0;
}

.discover__label {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-sm);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--english-deep);
}

.discover__text {
  font-size: var(--text-base);
  line-height: 1.35;
  overflow-wrap: anywhere;
}

.discover__review {
  justify-self: start;
  padding: 0.35rem 0.85rem;
  font-size: var(--text-sm);
  color: var(--ink-soft);
  background: rgba(255, 255, 255, 0.8);
  border: 2px dashed rgba(35, 32, 28, 0.25);
  border-radius: 999px;
}

.fact-card {
  display: grid;
  justify-items: center;
  gap: 0.8rem;
  text-align: center;
  padding-block: clamp(1.25rem, 1rem + 2vw, 2.5rem);
  background: linear-gradient(180deg, #fff 0%, #eef6ff 100%);
}

.fact__icon {
  font-size: clamp(3.5rem, 15vw, 5.5rem);
  line-height: 1;
}

.fact__text {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.2rem, 4.5vw, 1.8rem);
  line-height: 1.35;
  max-width: 28ch;
}

.fact__topic {
  font-size: var(--text-sm);
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--ink-soft);
}

.fact-review {
  justify-self: center;
}

/* ─────────── Shapes: tasks and new shapes ─────────── */

.task-line {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  background: linear-gradient(120deg, #fff 0%, #f3eaff 100%);
}

.task-line--done {
  background: linear-gradient(120deg, #eafff2 0%, #bdf0d2 100%);
}

.task-line__icon {
  font-size: 2rem;
  flex-shrink: 0;
}

.task-line__text {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-base);
  line-height: 1.3;
}

.level--wide {
  min-width: 0;
  padding-inline: 0.7rem;
  font-size: 0.95rem;
}

.stage--refused {
  animation: shake 200ms ease;
}

.stage__shape--trapezium {
  fill: rgba(255, 183, 3, 0.25);
  stroke: var(--write-deep);
}

.stage__shape--circle,
.stage__shape--ellipse {
  fill: rgba(58, 160, 255, 0.22);
  stroke: var(--english-deep);
}

.stage__radius {
  stroke: var(--english-deep);
  stroke-width: 4;
  stroke-dasharray: 8 6;
}

.stage__pin {
  fill: var(--ink);
}

/* ─────────── Who is playing ─────────── */

.hero__hello {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
}

.hero__avatar {
  font-size: 2rem;
  line-height: 1;
}

.home-foot--quiet {
  padding-top: 0.25rem;
}

.site-link {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-sm);
  color: var(--ink-soft);
  text-decoration: none;
  padding: 0.35rem 1rem;
  background: var(--card);
  border: var(--line-thin);
  border-radius: 999px;
}

.site-link__mark {
  width: 26px;
  height: 26px;
  display: block;
}

.site-link__back {
  font-size: 1.1rem;
  line-height: 1;
  color: var(--ink);
}

/* ─────────── Parent screen: profile, account, locks ─────────── */

.profile {
  display: grid;
  gap: 0.7rem;
}

.profile__row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 1rem;
  align-items: center;
}

.avatar {
  display: grid;
  justify-items: center;
  gap: 2px;
  width: 96px;
  padding: 0.55rem 0.3rem 0.45rem;
  background: var(--paper-deep);
  border: var(--line);
  border-radius: var(--radius);
  box-shadow: var(--lift-sm);
}

.avatar__face {
  font-size: 2.4rem;
  line-height: 1;
}

.avatar__label {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-soft);
}

.field--name {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-lg);
  max-width: 360px;
}

/* A display rule beats the hidden attribute, so say it again here. */
.avatar-picker[hidden] {
  display: none;
}

.avatar-picker {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(58px, 1fr));
  gap: 8px;
  padding-top: 0.5rem;
}

.avatar-pick {
  height: 58px;
  font-size: 1.8rem;
  background: var(--card);
  border: var(--line-thin);
  border-radius: 14px;
}

.avatar-pick--on {
  background: var(--star);
  box-shadow: var(--lift-sm);
}

.account .btn {
  font-size: var(--text-base);
}

/* Locked: visible, so a parent can see what an account is for. */
.is-locked {
  position: relative;
  opacity: 0.72;
  filter: grayscale(0.9);
}

.is-locked::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: rgba(255, 255, 255, 0.1);
}

.lock-badge {
  justify-self: start;
  grid-column: 1 / -1;
  position: relative;
  z-index: 1;
  margin-bottom: 0.3rem;
  padding: 0.35rem 0.9rem;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-sm);
  background: var(--paper-deep);
  border: var(--line-thin);
  border-radius: 999px;
}

.sign-in-hint--on {
  border-style: solid;
  border-color: var(--good);
  background: rgba(47, 182, 115, 0.14);
  color: var(--ink);
}

/* ─────────── A visitor is caught ─────────── */

/* The page brightens for a second behind the card. Bright, not dark: this is
   a reward, and the whole game is set on warm paper. */
.catch {
  position: fixed;
  inset: 0;
  z-index: 70;
  display: grid;
  place-items: center;
  pointer-events: none;
  background: radial-gradient(circle at 50% 45%, rgba(255, 255, 255, 0.92), rgba(255, 248, 236, 0.55) 60%, rgba(255, 248, 236, 0) 78%);
  animation: catch-wash 1400ms ease-out forwards;
}

.catch__card {
  display: grid;
  justify-items: center;
  gap: 0.2rem;
  padding: 1.2rem 2rem 1.1rem;
  text-align: center;
  background: var(--card);
  border: var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--lift);
  animation: catch-pop 1400ms var(--ease-pop) forwards;
}

.catch__icon {
  font-size: clamp(3.5rem, 16vw, 6rem);
  line-height: 1;
}

.catch__name {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-lg);
}

.catch__note {
  font-size: var(--text-sm);
  color: var(--ink-soft);
}

@keyframes catch-wash {
  0% { opacity: 0; }
  12% { opacity: 1; }
  72% { opacity: 1; }
  100% { opacity: 0; }
}

@keyframes catch-pop {
  0% { transform: scale(0.5) rotate(-6deg); opacity: 0; }
  18% { transform: scale(1.08) rotate(2deg); opacity: 1; }
  30% { transform: scale(1) rotate(0deg); }
  78% { transform: scale(1); opacity: 1; }
  100% { transform: scale(0.94); opacity: 0; }
}

/* With motion turned down the global rule cuts every animation to 0.01ms and
   the card would land on its final frame — invisible. Show it plainly. */
@media (prefers-reduced-motion: reduce) {
  .catch,
  .catch__card {
    animation: none !important;
    opacity: 1;
    transform: none;
  }
}


/* ─────────── The sweet divider ─────────── */

/* Four sweets from the logo on a dashed line: it closes the subject grid
   without shouting, and it is the same mark the public pages use. */
.sweet-rule {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  padding-block: 0.4rem;
  position: relative;
}

.sweet-rule::before,
.sweet-rule::after {
  content: '';
  flex: 1;
  height: 0;
  border-top: 2px dashed rgba(35, 32, 28, 0.16);
}

.sweet-rule span {
  width: 16px;
  height: 16px;
  border: var(--line-thin);
  border-radius: 50%;
  flex-shrink: 0;
}


/* ─────────── The hairline under the brand row ─────────── */

/* A whisper of the four colours, fading out at both ends. It closes the bar
   without drawing a box around it. */
.hero__row {
  position: relative;
  padding-bottom: 1rem;
}

.hero__row::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  border-radius: 2px;
  opacity: 0.45;
  background: linear-gradient(
    90deg,
    transparent,
    var(--write) 18%,
    var(--english) 42%,
    var(--maths) 66%,
    var(--star) 86%,
    transparent
  );
}


/* ─────────── Home hero: the title, and what to do next ─────────── */

.hero__main {
  display: grid;
  gap: clamp(1.1rem, 0.6rem + 2vw, 2rem);
  align-items: center;
  /* The title was sitting on the hairline under the brand row. */
  padding-top: clamp(1.25rem, 0.8rem + 1.6vw, 2.25rem);
}

/* The three lines under the title are one block, not three strays. */
.hero__main > div {
  display: grid;
  gap: 0.55rem;
}

@media (min-width: 760px) {
  .hero__main {
    grid-template-columns: minmax(0, 1fr) minmax(280px, 360px);
  }
}

/* Beside the title the fact is a card, not a banner: the drop stacks over
   the text instead of sitting beside it, and the review button runs the
   full width underneath. On a phone the grid is one column and it goes back
   to the wide shape it has always had. */
@media (min-width: 760px) {
  .hero__main .tile--discover {
    align-self: stretch;
    padding: 1.4rem 1.5rem 1.5rem;
  }

  .hero__main .discover {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.6rem;
  }

  .hero__main .discover__icon {
    font-size: 3rem;
  }

  .hero__main .discover__text {
    font-size: var(--text-base);
    line-height: 1.4;
  }

  .hero__main .discover__review {
    width: 100%;
  }
}

/* Three facts, each one a chip with the number carrying the weight. */
.hero__facts {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-top: 0.3rem;
}

.fact {
  display: inline-flex;
  align-items: baseline;
  gap: 0.4rem;
  padding: 0.4rem 0.9rem 0.45rem;
  font-size: var(--text-sm);
  color: var(--ink);
  background: var(--card);
  border: var(--line-thin);
  border-radius: 999px;
  box-shadow: var(--lift-sm);
}

.fact strong {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.4rem;
  line-height: 1;
}

.fact--subjects { background: linear-gradient(140deg, #fff 55%, rgba(58, 160, 255, 0.24)); }
.fact--games { background: linear-gradient(140deg, #fff 55%, rgba(56, 193, 114, 0.24)); }
.fact--time { background: linear-gradient(140deg, #fff 55%, rgba(255, 183, 3, 0.3)); }








/* Each subject tints its own card, the same colour the tile uses. */



/* A reading question is a sentence, not a picture, so it is set as text. */
.quiz__prompt--read .quiz__face {
  font-size: clamp(1.3rem, 1rem + 2vw, 2rem);
  line-height: 1.3;
  text-align: center;
  max-width: 24ch;
}

.quiz__prompt--word .quiz__face {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(2rem, 1.4rem + 3vw, 3.5rem);
}

.quiz__prompt--mix .quiz__face {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.5rem, 1.1rem + 2vw, 2.4rem);
}

/* A colour name is not a colour, so the colours are shown as well. */
.quiz__swatches {
  display: flex;
  gap: 0.7rem;
  margin-top: 0.9rem;
}

.quiz__swatch {
  width: clamp(44px, 12vw, 64px);
  height: clamp(44px, 12vw, 64px);
  border: var(--line);
  border-radius: 50%;
  box-shadow: var(--lift-sm);
}

/* The pitch game has nothing to look at: the note is the question. */
.quiz__prompt--arts .quiz__face {
  font-size: clamp(3rem, 12vw, 5rem);
}

/* What a child did here last time, on the tile, before the game opens. */
.tile__record {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem 0.55rem;
}

.tile__stars {
  font-size: 0.95rem;
  letter-spacing: 0.05em;
}

.tile__rounds {
  font-size: 0.85rem;
  color: var(--ink-soft);
}

.tile__best--new {
  background: transparent;
  border-style: dashed;
  color: var(--ink-soft);
}



/* ─────────── The exam ─────────── */

/* The one thing here that promises a reward before the work, so it says on
   its face exactly what that costs. */
.exam-tile {
  display: flex;
  align-items: center;
  gap: 1rem;
  width: 100%;
  padding: 1.1rem 1.3rem;
  text-align: left;
  color: var(--ink);
  background: linear-gradient(135deg, #fff6d8 0%, #ffe08a 60%, #ffd45e 100%);
  border: var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--lift);
  transition:
    transform var(--normal) var(--ease-pop),
    box-shadow var(--normal) ease;
}

.exam-tile:hover {
  transform: translateY(-4px);
  box-shadow: 0 12px 0 var(--ink);
}

.exam-tile--done {
  background: linear-gradient(135deg, #fff 0%, #ffe9a8 100%);
}

.exam-tile__icon {
  font-size: 2.4rem;
  line-height: 1;
  flex-shrink: 0;
}

.exam-tile__body {
  display: grid;
  gap: 0.15rem;
  min-width: 0;
  flex: 1;
}

.exam-tile__name {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-lg);
}

.exam-tile__note {
  font-size: var(--text-sm);
  line-height: 1.35;
  color: var(--ink-soft);
}

.exam-tile__score {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-sm);
  padding: 0.25rem 0.8rem;
  background: rgba(255, 255, 255, 0.75);
  border: var(--line-thin);
  border-radius: 999px;
  flex-shrink: 0;
}

/* The page before it starts: what it is, and what it is worth. */
.exam-card {
  display: grid;
  justify-items: center;
  gap: 0.6rem;
  text-align: center;
  background: linear-gradient(160deg, #fff 55%, rgba(255, 183, 3, 0.26));
}

.exam-card__icon {
  font-size: 3.4rem;
  line-height: 1;
}

.exam-card__note {
  max-width: 44ch;
  color: var(--ink-soft);
  line-height: 1.5;
}

.exam-card__rule {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  margin-top: 0.4rem;
  padding: 0.75rem 1.2rem;
  text-align: left;
  background: var(--card);
  border: var(--line-thin);
  border-radius: var(--radius);
  max-width: 34ch;
}

.exam-card__target {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 2rem;
  line-height: 1;
  color: var(--maths-deep);
}

.exam-card__gold {
  font-size: var(--text-sm);
  color: var(--ink-soft);
}

.exam-card .btn--big {
  margin-top: 0.8rem;
  min-height: 68px;
  font-size: var(--text-lg);
  padding-inline: 2rem;
}

/* During the paper: which question, and how many are left. */
.exam-progress {
  display: grid;
  gap: 0.5rem;
  justify-items: center;
}

.exam-progress__count {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-sm);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.exam-progress__dots {
  display: flex;
  gap: 8px;
}

.exam-dot {
  width: 14px;
  height: 14px;
  border: var(--line-thin);
  border-radius: 50%;
  background: var(--card);
}

.exam-dot--done {
  background: var(--star);
}

.exam-prompt {
  display: grid;
  justify-items: center;
  gap: 0.5rem;
}

/* The question itself. It is not the caption under the picture — the caption
   says what the thing is, this says what to do about it — so it is set apart
   and it is the biggest text in the card after the picture. */
.exam-prompt__ask {
  margin-top: 0.5rem;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.15rem, 1rem + 0.8vw, 1.6rem);
  line-height: 1.25;
  text-align: center;
  max-width: 24ch;
  color: var(--ink);
}

/* Which subject the question came from: a mixed paper should say. */
.exam-prompt__subject {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.8rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-soft);
  padding: 0.2rem 0.8rem;
  background: var(--paper-deep);
  border: var(--line-thin);
  border-radius: 999px;
}

.exam-score {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-lg);
}

/* The answer a child got right. The tick that goes with it is set beside
   .choice--show, so both places are marked the same way. */
.choice--right {
  background: rgba(47, 182, 115, 0.25);
}

/* ─────────── Golden stickers ─────────── */

.prize--golden {
  background: linear-gradient(135deg, #fff6d8 0%, #ffd45e 55%, #f5a623 100%);
  border: var(--line);
  box-shadow: var(--lift);
}

.album__slot--golden {
  background: linear-gradient(140deg, #fff8e0 0%, #ffd965 100%);
  border-color: var(--ink);
}

.album__slot--golden.album__slot--empty {
  background: repeating-linear-gradient(
    -45deg,
    #f4efe4 0 8px,
    #efe6d2 8px 16px
  );
}

/* The golden row in the album: locked slots and all, because the gap is the
   point — a child can see how many there are and exactly how to get one. */
.album__heading {
  margin-top: 1.6rem;
  font-size: var(--text-lg);
}

/* One block per rarity. Its own count and its own bar, so the everyday row
   reads as nearly finished rather than being averaged away by the rare
   ones nobody is expected to complete. */
.album__tier {
  display: grid;
  gap: 0.5rem;
}

.album__tier .album__heading {
  margin-top: 0.4rem;
}

.album__tier .album__bar {
  margin-bottom: 0.3rem;
}

.album--golden {
  grid-template-columns: repeat(auto-fill, minmax(92px, 1fr));
}

/* A clean round. It cannot be ground out — it is all or none — so it gets
   the only shouting banner in the game. */
.perfect {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-lg);
  letter-spacing: 0.08em;
  padding: 0.5rem 1.2rem;
  background: linear-gradient(135deg, #fff6d8 0%, #ffd45e 55%, #ffb703 100%);
  border: var(--line-thin);
  border-radius: 999px;
  animation: perfect-pop 500ms var(--ease-pop);
}

@keyframes perfect-pop {
  0% { transform: scale(0.7) rotate(-4deg); opacity: 0; }
  60% { transform: scale(1.08) rotate(2deg); opacity: 1; }
  100% { transform: scale(1) rotate(0deg); }
}

/* ─────────── How strict ─────────── */

/* The one setting that changes the rules of every game, so it shows what
   each choice does rather than leaving a parent to find out by watching. */
.strict-card {
  display: grid;
  gap: 0.7rem;
}

.strict-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: 0.6rem;
}

.strict {
  display: grid;
  justify-items: center;
  gap: 0.15rem;
  padding: 0.85rem 0.6rem 0.9rem;
  color: var(--ink);
  background: var(--card);
  border: var(--line-thin);
  border-radius: var(--radius);
  transition: transform var(--fast) ease;
}

.strict:hover {
  transform: translateY(-2px);
}

.strict--on {
  background: var(--star);
  border: var(--line);
  box-shadow: var(--lift-sm);
}

.strict__icon {
  font-size: 1.8rem;
  line-height: 1;
}

.strict__name {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-sm);
}

.strict__allowed {
  font-size: 0.8rem;
  color: var(--ink-soft);
}

.strict--on .strict__allowed {
  color: var(--ink);
}

.strict__detail {
  padding: 0.85rem 1rem;
  font-size: var(--text-sm);
  line-height: 1.5;
  background: var(--paper-deep);
  border-radius: var(--radius);
}

/* ─────────── How it went ─────────── */

/* A record of the round, not a reward: a question answered right after a
   miss is amber, not a clean tick. */
.recap {
  width: 100%;
  text-align: left;
  padding: 0.7rem 0.9rem;
  background: var(--card);
  border: var(--line-thin);
  border-radius: var(--radius);
}

.recap__summary {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-sm);
  cursor: pointer;
}

.recap__list {
  display: grid;
  gap: 0.3rem;
  margin-top: 0.7rem;
  padding: 0;
  list-style: none;
}

.recap__row {
  display: grid;
  grid-template-columns: 1.6rem minmax(0, 1fr);
  align-items: baseline;
  gap: 0.1rem 0.5rem;
  padding: 0.45rem 0.55rem;
  border-radius: 10px;
  font-size: 0.95rem;
  line-height: 1.35;
}

.recap__row--clean { background: rgba(47, 182, 115, 0.12); }
.recap__row--late { background: rgba(255, 201, 60, 0.18); }
.recap__row--missed { background: rgba(228, 73, 92, 0.12); }

.recap__mark {
  grid-row: span 2;
  font-size: 1rem;
  line-height: 1.35;
}

.recap__asked {
  font-family: var(--font-display);
  font-weight: 600;
  overflow-wrap: anywhere;
}

.recap__answer {
  grid-column: 2;
  color: var(--ink-soft);
  overflow-wrap: anywhere;
}

/* ─────────── Map of Europe ─────────── */

/*
  Two games share this: one names a country and waits for a tap, the other
  lights a country and offers names. The map is the same either way, and so
  are the colours — a country a child has just got right looks the same in
  both, which is the point of having two games over one map.
*/

.map-ask {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.2rem, 4.5vw, 1.7rem);
  text-align: center;
  margin: 0;
}

.map-card {
  display: grid;
  justify-items: center;
  padding: var(--gap-sm);
  background: #dff0f8;
  overflow: hidden;
}

/* The drawing is 1000 by 1008, and the box has to be that shape too.
   "height: auto, max-height" let the box stay wide while the map shrank
   inside it, which put a band of nothing down one side. */
.map {
  --map-ratio: 1000 / 1008;
  display: block;
  width: 100%;
  max-width: min(100%, calc(62vh * 1000 / 1008));
  aspect-ratio: var(--map-ratio);
  margin-inline: auto;
  border-radius: 12px;
  touch-action: manipulation;
}

.map__sea {
  fill: #dff0f8;
}

.map__land {
  stroke: #6f6355;
  stroke-width: 1.4;
  stroke-linejoin: round;
  transition: fill 160ms ease;
}

/* The countries this level does not ask about. They are there so that
   Europe looks like Europe, and they never answer anything. */
.map__land--rest {
  fill: #eee7d9;
  pointer-events: none;
}

.map__land--play {
  fill: #ffe3b3;
  cursor: pointer;
}

/* A hover that only a mouse gets. On a touch screen every tap would leave
   a country looking chosen. */
@media (hover: hover) {
  .map__land--play:hover {
    fill: #ffd48a;
  }
}

/* Montenegro is about three pixels across on a phone. These rings are a
   target a thumb can hit, and they say "there is a country here" — which is
   half of what the map is for. */
.map__ring {
  fill: transparent;
  stroke: #6f6355;
  stroke-width: 2;
  stroke-dasharray: 5 4;
  cursor: pointer;
}

.map__land--right {
  fill: #7fd39b;
  stroke: #1f7a46;
  stroke-width: 2.4;
}

.map__ring.map__land--right {
  fill: rgba(127, 211, 155, 0.75);
}

.map__land--wrong {
  fill: #f8a8a8;
  stroke: #b03030;
  stroke-width: 2.4;
}

.map__ring.map__land--wrong {
  fill: rgba(248, 168, 168, 0.8);
}

/* The country the second game is asking about. */
.map__land--ask {
  fill: var(--star);
  stroke: #8a5a00;
  stroke-width: 2.6;
  animation: map-pulse 1.6s ease-in-out infinite;
}

@keyframes map-pulse {
  50% {
    fill: #ffdf8a;
  }
}

@media (prefers-reduced-motion: reduce) {
  .map__land--ask {
    animation: none;
  }
}

/* ─────────── Line them up ─────────── */

/*
  A row of towers, sorted by swapping neighbours. The height is the answer
  and the number on top is the same answer written down — a five-year-old
  reads the heights, an eight-year-old reads the numbers, and both are
  looking at the same row.
*/

.sort-card {
  display: grid;
  justify-items: center;
  padding: var(--gap-sm);
  background: #fffdf7;
}

.sort-line {
  display: grid;
  grid-template-columns: repeat(var(--slots), minmax(0, 1fr));
  align-items: end;
  gap: clamp(4px, 1.5vw, 10px);
  width: 100%;
  max-width: 520px;
  height: clamp(180px, 34vh, 280px);
}

/* Two rows: the bar's room, then the number under it. The bar's height is
   a percentage, and a percentage needs a row with a real size — packing the
   rows to the bottom instead gave every bar a height of nothing. */
.sort-tower {
  display: grid;
  grid-template-rows: 1fr auto;
  justify-items: center;
  gap: 4px;
  min-width: 0;
  height: 100%;
  padding: 0;
  background: none;
  border: none;
  cursor: pointer;
}

/* The bar is what the child compares. It grows from the ground, so a row
   of them reads as a staircase once it is sorted — which is the moment
   the game is played for. */
.sort-tower__bar {
  align-self: end;
  width: 100%;
  height: var(--height);
  border: var(--line-thin);
  border-radius: 10px 10px 4px 4px;
  background: linear-gradient(180deg, #ffd79a, #ffb454);
  transition: height 220ms var(--ease-pop), background 160ms ease;
}

.sort-tower__value {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(0.85rem, 3vw, 1.1rem);
}

@media (hover: hover) {
  .sort-tower:hover .sort-tower__bar {
    background: linear-gradient(180deg, #ffe6bd, #ffc477);
  }
}

.sort-tower--picked .sort-tower__bar {
  background: linear-gradient(180deg, #bfe3ff, #6cb8ff);
  box-shadow: var(--lift-sm);
}

/* The pair the demonstration is looking at, and the pair it decided to
   swap. Two different colours on purpose: looking is not swapping, and
   that difference is the algorithm. */
.sort-tower--look .sort-tower__bar {
  background: linear-gradient(180deg, #e4e0ff, #b5aaff);
}

.sort-tower--swap .sort-tower__bar {
  background: linear-gradient(180deg, #b9ecc9, #6fd694);
}

.sort-note {
  min-height: 1.6em;
  text-align: center;
}

/* ─────────── Move the tower ─────────── */

.tower-card {
  display: grid;
  justify-items: center;
  padding: var(--gap-sm);
  background: #fffdf7;
}

.tower-yard {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(6px, 2vw, 16px);
  width: 100%;
  max-width: 540px;
}

.tower-peg {
  position: relative;
  display: grid;
  align-content: end;
  justify-items: center;
  min-width: 0;
  height: clamp(170px, 32vh, 260px);
  padding: 0;
  background: none;
  border: none;
  border-radius: 14px;
  cursor: pointer;
}

.tower-peg__post {
  position: absolute;
  bottom: 14px;
  width: 10px;
  height: 78%;
  border-radius: 6px;
  background: #cbb99f;
}

.tower-peg__base {
  width: 100%;
  height: 12px;
  border: var(--line-thin);
  border-radius: 6px;
  background: #b08f6a;
}

.tower-peg__stack {
  position: relative;
  display: grid;
  justify-items: center;
  align-content: end;
  gap: 3px;
  width: 100%;
  z-index: 1;
}

/* A disc's width is its number, so the order is visible without reading. */
.tower-disc {
  display: grid;
  place-items: center;
  width: calc(26% + 66% * (var(--size) / var(--of)));
  height: clamp(20px, 4.2vh, 30px);
  border: var(--line-thin);
  border-radius: 999px;
  background: linear-gradient(180deg, #ffd79a, #ff9f45);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.8rem;
  transition: transform 200ms var(--ease-pop);
}

/* Picked up: the disc rises off the stack and waits to be told where to go. */
.tower-disc--up {
  transform: translateY(-14px) scale(1.06);
  background: linear-gradient(180deg, #bfe3ff, #6cb8ff);
}

.tower-peg--lifted .tower-peg__base {
  background: #6cb8ff;
}

.tower-peg--no {
  animation: shake 380ms ease;
}

.tower-peg--done .tower-peg__base {
  background: #6fd694;
}

/* The map cannot use a pseudo-element, so the tick and the cross are drawn
   into the map itself. Same rule as the quiz: never colour alone. */
.map__mark {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 46px;
  text-anchor: middle;
  dominant-baseline: central;
  paint-order: stroke;
  stroke: #fff;
  stroke-width: 6px;
  pointer-events: none;
}

.map__mark--right {
  fill: #1f7a46;
}

.map__mark--wrong {
  fill: #b03030;
}

/* ─────────── Chess ─────────── */

/*
  A real board: eight by eight, a1 dark, the files lettered and the ranks
  numbered down the side. Those are the things that have to become familiar
  before a real board stops being confusing, and a simplified one teaches a
  child to read a board that does not exist.
*/

.chess-ask {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.1rem, 4.2vw, 1.5rem);
  text-align: center;
  margin: 0;
  min-height: 1.4em;
}

.chess-card {
  display: grid;
  justify-items: center;
  padding: var(--gap-sm);
  background: #fffdf7;
}

/* The board, its rank numbers and its file letters, held together so the
   labels cannot drift away from the squares they belong to. */
.chess-frame {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr) auto;
  gap: 4px;
  width: 100%;
  max-width: min(100%, 58vh);
}

/*
  Eight equal rows as well as eight equal columns.
  
  Without the rows the grid sized each one to its contents, so a rank
  holding pieces was taller than an empty one — and because the board has a
  fixed aspect ratio, the empty ranks were squeezed to make room. The board
  was not square, and it changed shape as the pieces moved.
*/
.chess-board {
  display: grid;
  grid-template-columns: repeat(8, minmax(0, 1fr));
  grid-template-rows: repeat(8, minmax(0, 1fr));
  aspect-ratio: 1;
  width: 100%;
  border: var(--line-thin);
  border-radius: 8px;
  overflow: hidden;
}

.chess-ranks,
.chess-files {
  display: grid;
  font-family: var(--font-display);
  font-size: clamp(0.6rem, 2vw, 0.8rem);
  color: var(--ink-soft);
}

.chess-ranks {
  grid-template-rows: repeat(8, minmax(0, 1fr));
  align-items: center;
  justify-items: center;
  width: 1.2em;
}

.chess-files {
  grid-column: 2;
  grid-template-columns: repeat(8, minmax(0, 1fr));
  justify-items: center;
}

.chess-square {
  display: grid;
  place-items: center;
  min-width: 0;
  padding: 0;
  border: none;
  border-radius: 0;
  cursor: pointer;
  transition: background 140ms ease;
}

.chess-square--light {
  background: #f1e4c9;
}

.chess-square--dark {
  background: #b58863;
}

/* The piece being asked about. Not green and not red: it is the subject of
   the question, not an answer to it. */
.chess-square--from {
  box-shadow: inset 0 0 0 4px var(--star);
}

/* A square the child found. The dot is what makes it legible without
   relying on the colour, which is the rule everywhere in these games. */
.chess-square--found {
  background: #7fd39b;
}

.chess-square--found::after {
  content: '•';
  position: absolute;
  font-size: 1.6rem;
  line-height: 0;
  color: #1f7a46;
}

.chess-square--wrong {
  background: #f8a8a8;
  animation: shake 380ms ease;
}

.chess-square--wrong::after {
  content: '✗';
  position: absolute;
  font-size: 1rem;
  line-height: 1;
  color: #b03030;
}

.chess-square--found,
.chess-square--wrong {
  position: relative;
}

/* The glyphs are outlined rather than solid, so a black piece on a dark
   square is still a piece. */
.chess-man {
  font-size: clamp(1.1rem, 5.2vw, 2.4rem);
  line-height: 1;
  pointer-events: none;
  /* A glyph taller than its square used to stretch the whole rank. */
  max-height: 100%;
  overflow: hidden;
}

.chess-man--white {
  color: #fffdf7;
  text-shadow:
    0 0 2px #23201c,
    0 1px 0 #23201c,
    1px 0 0 #23201c,
    -1px 0 0 #23201c,
    0 -1px 0 #23201c;
}

.chess-man--black {
  color: #23201c;
  text-shadow: 0 0 2px rgba(255, 253, 247, 0.85);
}

.choices--wide {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

/* The squares a picked piece may move to, and the pieces it could take.
   A dot for an empty square and a ring for an occupied one: the difference
   between "you may go here" and "you may take this" is worth seeing. */
.chess-square--picked {
  box-shadow: inset 0 0 0 4px #3aa0ff;
}

.chess-square--legal {
  position: relative;
}

.chess-square--legal::before {
  content: '';
  position: absolute;
  width: 26%;
  height: 26%;
  border-radius: 50%;
  background: rgba(31, 122, 70, 0.55);
}

.chess-square--takeable::before {
  width: 82%;
  height: 82%;
  background: none;
  border: 4px solid rgba(176, 48, 48, 0.7);
}

/* What each side has lost, and who is ahead. */
.chess-taken {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 0.6rem;
  width: 100%;
  max-width: min(100%, 58vh);
  margin-inline: auto;
  font-size: 1.2rem;
  line-height: 1.2;
}

.chess-taken__row:last-of-type {
  text-align: right;
}

.chess-taken__edge {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-sm);
  padding: 0.2rem 0.7rem;
  background: #fff;
  border: var(--line-thin);
  border-radius: 999px;
  white-space: nowrap;
}

.chess-promote {
  font-size: 1rem;
}

/* Three more bucket patterns, for the nine-colour level. Colour is never
   the only signal a bucket gives. */
.bucket__paint--crosses {
  background-image:
    repeating-linear-gradient(45deg, rgba(255,255,255,0.6) 0 3px, transparent 3px 12px),
    repeating-linear-gradient(-45deg, rgba(255,255,255,0.6) 0 3px, transparent 3px 12px);
}
.bucket__paint--bricks {
  background-image:
    repeating-linear-gradient(0deg, rgba(255,255,255,0.55) 0 2px, transparent 2px 14px),
    repeating-linear-gradient(90deg, rgba(255,255,255,0.55) 0 2px, transparent 2px 28px);
}
.bucket__paint--rings {
  background-image: radial-gradient(circle, transparent 5px, rgba(255,255,255,0.65) 5px 7px, transparent 7px);
  background-size: 20px 20px;
}

/* The card between two puzzles of a run. Short on purpose: a full end
   screen here would read as though the round had finished. */
.done--step {
  gap: 0.6rem;
}

.run-dots {
  display: flex;
  justify-content: center;
  gap: 0.5rem;
}

.run-dot {
  width: 14px;
  height: 14px;
  border: var(--line-thin);
  border-radius: 50%;
  background: var(--card);
}

.run-dot--done {
  background: var(--good);
}

/* ─────────── IT: using a computer ─────────── */

/*
  The keyboard these games draw is the whole one: a number row, a shift key
  that really works, and the symbols that live above the digits. Shift is
  the first key a child meets that changes what the other keys do, and
  nobody ever explains it — they are told "hold shift for a capital" and
  left to find the rest by accident.
*/
.keyboard--full .keyboard__row--digits {
  margin-bottom: 4px;
}

.key--shift {
  min-width: 72px;
  font-size: 0.7rem;
  background: #eef6ff;
}

.key--on {
  background: var(--star);
  box-shadow: var(--lift-press);
  transform: translateY(2px);
}

.type-card,
.login-card {
  display: grid;
  justify-items: center;
  gap: 0.6rem;
  background: #fffdf7;
}

.type-target__label {
  font-family: var(--font-display);
  font-size: var(--text-sm);
  color: var(--ink-soft);
  margin: 0;
}

/* One box per character, so a child can see exactly where they are. */
.type-target {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 4px;
  margin: 0;
}

.type-char {
  display: grid;
  place-items: center;
  min-width: 1.5em;
  padding: 0.2rem 0.35rem;
  font-family: var(--font-display);
  font-size: clamp(1.4rem, 6vw, 2.2rem);
  border: var(--line-thin);
  border-radius: 8px;
  background: var(--card);
}

.type-char--done {
  background: #d7f0e1;
  border-color: var(--good);
}

.type-char--next {
  background: var(--star);
  transform: translateY(-2px);
  box-shadow: var(--lift-sm);
}

.type-typed {
  font-family: var(--font-display);
  font-size: var(--text-sm);
  color: var(--ink-soft);
  letter-spacing: 0.1em;
  min-height: 1.4em;
  margin: 0;
}

.type-note {
  min-height: 1.5em;
  text-align: center;
}

/* The card a login is copied from. Deliberately looks like a sticky note:
   this is the thing a grown-up writes a password on, and the game is about
   copying it correctly rather than about remembering it. */
.login-card__site {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-lg);
  margin: 0;
}

.login-note {
  width: 100%;
  max-width: 320px;
  padding: 0.8rem 1rem;
  background: #fff8cc;
  border: var(--line-thin);
  border-radius: 10px;
  transform: rotate(-1deg);
}

.login-note__label {
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 0 0 0.4rem;
}

.login-note__line {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  margin: 0.2rem 0;
  font-family: var(--font-display);
}

.login-note__key {
  color: var(--ink-soft);
}

.login-note__value {
  font-weight: 600;
}

.login-form {
  display: grid;
  gap: 0.6rem;
  width: 100%;
  max-width: 320px;
}

.login-field {
  display: grid;
  gap: 0.2rem;
}

.login-field__label {
  font-family: var(--font-display);
  font-size: 0.8rem;
  color: var(--ink-soft);
}

.login-field__box {
  min-height: 2.4em;
  padding: 0.35rem 0.6rem;
  font-family: var(--font-display);
  font-size: 1.1rem;
  background: var(--card);
  border: var(--line-thin);
  border-radius: 8px;
  word-break: break-all;
}

/* The box being typed into. The one that matters is the password, because
   it shows dots and cannot be checked by reading it back. */
.login-field--on .login-field__box {
  border-color: var(--english);
  box-shadow: 0 0 0 3px rgba(58, 160, 255, 0.25);
}

.login-field__box--secret {
  letter-spacing: 0.25em;
}

/* ─────────── Mirror it ─────────── */

/*
  Half a picture and the half that is missing. No dragging, no reading and
  no sound: a child picks a colour and taps squares, which makes it the game
  here that works for the youngest players and on the worst phone.
*/
.mirror-card {
  display: grid;
  justify-items: center;
  padding: var(--gap-sm);
  background: #fffdf7;
}

.mirror {
  position: relative;
  display: grid;
  grid-template-columns: repeat(var(--cols), minmax(0, 1fr));
  gap: 2px;
  width: 100%;
  max-width: min(100%, 56vh);
  aspect-ratio: 1;
  padding: 2px;
  background: rgba(35, 32, 28, 0.12);
  border: var(--line-thin);
  border-radius: 10px;
}

/* The line the picture folds along, so a child can see the fold. */
.mirror::after {
  content: '';
  position: absolute;
  inset: 0;
  border-left: 2px dashed rgba(35, 32, 28, 0.45);
  width: 50%;
  pointer-events: none;
  left: 50%;
  border-left-width: 2px;
}

.mirror--across::after {
  border-left: none;
  border-top: 2px dashed rgba(35, 32, 28, 0.45);
  width: 100%;
  left: 0;
  top: 50%;
  height: 50%;
}

.mirror-cell {
  min-width: 0;
  padding: 0;
  border: none;
  border-radius: 3px;
  background: #fffdf7;
  cursor: pointer;
}

.mirror-cell--given {
  cursor: default;
}

/* A painted square. The colour is the whole content, so it fills the cell. */
.mirror-cell--on {
  background: var(--paint);
}

.mirror-cell--free:not(.mirror-cell--on) {
  background: #f3efe6;
}

@media (hover: hover) {
  .mirror-cell--free:hover {
    outline: 2px solid var(--ink);
    outline-offset: -2px;
  }
}

.mirror-palette {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 0.6rem;
}

.mirror-paint {
  width: 44px;
  height: 44px;
  padding: 0;
  background: var(--paint);
  border: var(--line-thin);
  border-radius: 50%;
  box-shadow: var(--lift-sm);
  cursor: pointer;
}

.mirror-paint--on {
  transform: translateY(2px);
  box-shadow: var(--lift-press);
  outline: 3px solid var(--ink);
  outline-offset: 2px;
}

.mirror-rubber {
  font-size: 0.85rem;
}

/* "Add it to the home screen", offered once and never in the middle of a
   round. The game already works offline; almost nobody finds that out. */
.install {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.8rem 1rem;
  background: #eef6ff;
}

.install__icon {
  font-size: 2rem;
  line-height: 1;
}

.install__words {
  display: grid;
  gap: 0.3rem;
  justify-items: start;
}

.install__title {
  font-family: var(--font-display);
  font-weight: 600;
  margin: 0;
}

.install__note {
  font-size: var(--text-sm);
  color: var(--ink-soft);
  margin: 0;
}

/* iOS has no install prompt to call, so the three words a parent needs are
   written out instead. Not mentioning it at all would be worse. */
.install__how {
  font-size: var(--text-sm);
  margin: 0.2rem 0 0;
}

.install__no {
  font-size: 0.8rem;
  align-self: start;
}

@media (max-width: 520px) {
  .install {
    grid-template-columns: auto minmax(0, 1fr);
  }

  .install__no {
    grid-column: 2;
    justify-self: end;
  }
}

/* ─────────── Trace the letter ─────────── */

/*
  A page of an exercise book, and the only screen here a child draws on.

  The guide is grey and thin so that the child's own line is the one they
  see, the baseline is darker than the other three because it is the line a
  letter actually sits on, and the start dot is the loudest thing on the
  page — where to begin is the single most common thing to get wrong.
*/
.trace {
  display: grid;
  justify-items: center;
  gap: var(--gap-sm);
}

.trace__letter {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(2rem, 1.4rem + 3vw, 3.2rem);
  line-height: 1;
  color: var(--ink);
}

.trace__sheet {
  width: min(78vw, 22rem);
  aspect-ratio: 1;
  padding: 0.5rem;
  background: var(--card, #fff);
  border: var(--line, 3px solid #23201c);
  border-radius: var(--radius-lg, 22px);
  box-shadow: var(--lift-sm, 5px 5px 0 rgba(35, 32, 28, 0.12));
}

.trace__paper {
  display: block;
  width: 100%;
  height: 100%;
  touch-action: none; /* the finger draws; it must not scroll the page */
  cursor: crosshair;
}

.trace__rule {
  stroke: rgba(35, 32, 28, 0.18);
  stroke-width: 0.6;
  stroke-dasharray: 3 3;
}

.trace__rule--strong {
  stroke: rgba(35, 32, 28, 0.42);
  stroke-dasharray: none;
  stroke-width: 0.9;
}

.trace__guide {
  fill: none;
  stroke: rgba(35, 32, 28, 0.16);
  stroke-width: 9;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.trace__guide--dot {
  fill: rgba(35, 32, 28, 0.16);
  stroke: none;
}

/* The stroke being asked for now, and the ones still to come. */
.trace__guide--now {
  stroke: rgba(35, 32, 28, 0.3);
}

.trace__guide--later {
  stroke: rgba(35, 32, 28, 0.07);
}

.trace__done {
  fill: none;
  stroke: var(--write, #f0a202);
  stroke-width: 7;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0;
}

.trace__done--dot {
  fill: var(--write, #f0a202);
  stroke: none;
}

.trace__done--on {
  opacity: 1;
}

.trace__ink {
  fill: none;
  stroke: var(--ink);
  stroke-width: 6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.trace__start {
  fill: #1e8449;
  opacity: 0;
}

.trace__start--on {
  opacity: 1;
  animation: trace-beat 1.6s ease-in-out infinite;
}

.trace__pencil {
  fill: var(--ink);
  opacity: 0;
}

.trace__pencil--on {
  opacity: 1;
}

@keyframes trace-beat {
  0%, 100% { r: 5; }
  50% { r: 6.6; }
}

@media (prefers-reduced-motion: reduce) {
  .trace__start--on {
    animation: none;
  }
}

.trace__arrow {
  fill: #1e8449;
  opacity: 0;
}

.trace__arrow--on {
  opacity: 1;
}

/* ─────────── Wielka litera, sylaby, interpunkcja ─────────── */

/*
  Three questions of different shapes on one card: a sentence with a gap, a
  single word to clap out, and a sentence missing its last mark. The line
  sets in a reading size rather than the huge single-word size the spelling
  games use, because here the child has to read a whole sentence.
*/
.usage__line {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.15rem, 0.95rem + 2vw, 1.75rem);
  line-height: 1.45;
  text-align: center;
  text-wrap: balance;
}

/* One word to clap: that one is the big one. */
.gap-card--word .usage__line {
  font-size: clamp(2rem, 9vw, 3.6rem);
  letter-spacing: 0.04em;
}

.choices .choice--letter {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.3rem, 4.5vw, 1.9rem);
  min-height: 72px;
  padding-inline: 1.1rem;
}

/* A whole sentence on a button: it wraps, and the two sit one above the
   other rather than being squeezed side by side. */
.choices .choice--line {
  flex: 1 1 100%;
  max-width: 34rem;
  padding: 0.85rem 1.1rem;
  font-size: clamp(0.98rem, 0.9rem + 0.6vw, 1.15rem);
  line-height: 1.4;
  text-align: left;
  white-space: normal;
}

/* ─────────── Head to head ─────────── */

/*
  The tablet lies flat on the table and a child sits at each end, so the top
  half is turned through 180 degrees and each of them reads their own half
  the right way up.

  The two halves are equal on purpose. Making the losing half smaller, or
  the winning half brighter, would do the one thing this game must not do,
  which is make the slower child feel slower than they already do.
*/
.board--duel {
  max-width: 46rem;
}

.duel {
  display: grid;
  grid-template-rows: 1fr auto 1fr;
  gap: 0.6rem;
  min-height: min(76vh, 46rem);
}

.duel__half {
  display: grid;
  align-content: center;
  justify-items: center;
  gap: 0.7rem;
  padding: 0.9rem;
  background: var(--card, #fff);
  border: var(--line, 3px solid #23201c);
  border-radius: var(--radius-lg, 22px);
  box-shadow: var(--lift-sm, 5px 5px 0 rgba(35, 32, 28, 0.12));
  transition: opacity 180ms ease;
}

.duel__half--two {
  transform: rotate(180deg);
  background: linear-gradient(180deg, #fff 0%, #fff0e2 100%);
  border-color: #c2621a;
}

.duel__half--one {
  background: linear-gradient(180deg, #fff 0%, #e9f1ff 100%);
  border-color: #1f5fa8;
}

/* Out of this question. Dimmed rather than hidden, so the child can still
   see the answer when it arrives. */
.duel__half--out {
  opacity: 0.55;
}

.duel__sum {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.9rem, 7vw, 3rem);
  letter-spacing: 0.02em;
}

.duel__options {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.55rem;
  width: min(100%, 24rem);
}

.duel__option {
  min-height: 62px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.3rem, 4.5vw, 1.9rem);
  color: var(--ink);
  background: #fff;
  border: var(--line, 3px solid #23201c);
  border-radius: var(--radius, 14px);
  cursor: pointer;
}

.duel__option:active {
  transform: translateY(2px);
}

/* Never colour alone: the tick and the cross say it too. */
.duel__option--right {
  background: #cdeccd;
}

.duel__option--right::after {
  content: ' ✓';
}

.duel__option--wrong {
  background: #f6d3d3;
}

.duel__option--wrong::after {
  content: ' ✕';
}

.duel__middle {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
  padding: 0.4rem 0.8rem;
}

.duel__score {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.4rem, 5vw, 2rem);
}

.duel__levels {
  display: flex;
  gap: 0.35rem;
}

.duel__note {
  margin: 0;
  font-size: 0.85rem;
  color: var(--ink-soft, #6b655c);
}

/**
 * On a computer, side by side.
 *
 * The stacked layout above is for a tablet lying flat on a table with a
 * child on each side, which is why player two is printed upside down. A
 * monitor stands up and nobody sits behind it, so that same layout gives
 * one player a screen they have to read on their head. The test is
 * whether there is a mouse, not how wide the window is: a tablet in
 * landscape is as wide as a laptop, and it still lies flat.
 */
@media (min-width: 58rem) and (hover: hover) and (pointer: fine) {
  .board--duel {
    max-width: 64rem;
  }

  .duel {
    grid-template-rows: 1fr;
    /* A bounded middle. Left to grow it takes a fifth of the board away
       from the two players; pinned too narrow the level buttons spill out
       over player two's card. */
    grid-template-columns: 1fr minmax(9rem, 12rem) 1fr;
    gap: 1rem;
    min-height: min(68vh, 34rem);
  }

  /* Player one on the left, so the screen reads in the same order as the
     score above it. The markup keeps player two first for the flat case. */
  .duel__half--one {
    order: 1;
  }

  .duel__middle {
    order: 2;
    flex-direction: column;
    gap: 0.8rem;
    padding: 0.4rem 0;
  }

  /* Two by two. Left as a row they spill over player two's card, and
     left to wrap on their own they break three and one. */
  .duel__levels {
    display: grid;
    grid-template-columns: repeat(2, auto);
    justify-content: center;
  }

  .duel__half--two {
    order: 3;
    transform: none;
    background: linear-gradient(180deg, #fff 0%, #fff0e2 100%);
  }

  .duel__note {
    text-align: center;
  }
}

.duel__over {
  display: grid;
  justify-items: center;
  gap: 0.5rem;
}

.duel__shout {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.5rem, 6vw, 2.2rem);
}

.duel__final {
  margin: 0;
  font-size: 1.2rem;
  color: var(--ink-soft, #6b655c);
}

/* ─────────── The head of a subject menu ─────────── */

/*
  A subject screen used to be a title and then tiles, with nothing said
  about the subject and nothing under it. This is the one line a parent
  reads before handing the tablet over, and the count is what a child
  checks.
*/
.menu-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.35rem 1.2rem;
  margin-top: calc(var(--space-block) * -0.45);
}

.menu-head__note {
  font-size: var(--text-base);
  color: var(--ink-soft);
}

.menu-head__count {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-sm);
  color: var(--ink-soft);
  padding: 0.25rem 0.9rem;
  background: var(--card);
  border: var(--line-thin);
  border-radius: 999px;
}

/* ─────────── The age switch ─────────── */

/*
  "Showing the 34 games for age 7" and a way out of it.

  It has to be plain rather than pretty: a child who has just noticed that
  a game they played last week is not on the screen needs to find this in
  one glance, and press it without asking anybody.
*/
.age-switch {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.5rem 0.9rem;
  padding: 0.6rem 1rem;
  background: var(--card);
  border: var(--line-thin);
  border-radius: 999px;
}

.age-switch__label {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-sm);
  color: var(--ink-soft);
}

.age-switch__btn {
  min-height: 42px;
  padding: 0 1rem;
  font-size: var(--text-sm);
}

/* ─────────── The age slider ─────────── */

/*
  One control for the whole job. The leftmost stop is "—", which means no
  age set and every game offered, so taking the age back off is the same
  gesture as putting it on rather than a separate little puzzle.

  The numbers sit under the track and the current one goes dark, because a
  slider with no labels is a guess and a parent should not have to drag it
  to find out where it is.
*/
.age-slider {
  margin-top: 0.6rem;
  max-width: 22rem;
}

.age-slider__input {
  width: 100%;
  height: 2.4rem;
  margin: 0;
  background: transparent;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}

.age-slider__input:focus-visible {
  outline: 4px solid var(--english-deep);
  outline-offset: 3px;
  border-radius: var(--radius);
}

/* The track and the thumb have to be styled per engine; there is no shared
   selector for either, and leaving one out gives that browser the default
   grey slider next to a drawn one. */
.age-slider__input::-webkit-slider-runnable-track {
  height: 12px;
  background: var(--paper-deep, #fff3dc);
  border: var(--line-thin);
  border-radius: 999px;
}

.age-slider__input::-moz-range-track {
  height: 12px;
  background: var(--paper-deep, #fff3dc);
  border: var(--line-thin);
  border-radius: 999px;
}

.age-slider__input::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 30px;
  height: 30px;
  margin-top: -11px;
  background: var(--star);
  border: var(--line);
  border-radius: 50%;
  box-shadow: var(--lift-sm);
}

.age-slider__input::-moz-range-thumb {
  width: 30px;
  height: 30px;
  background: var(--star);
  border: var(--line);
  border-radius: 50%;
  box-shadow: var(--lift-sm);
}

.age-slider__ticks {
  display: flex;
  justify-content: space-between;
  margin-top: 0.1rem;
  padding: 0 0.3rem;
}

.age-slider__tick {
  flex: 1;
  text-align: center;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-sm);
  color: var(--ink-soft);
}

.age-slider__tick--on {
  color: var(--ink);
  font-size: var(--text-base);
}

/* ─────────── The pickers in the Parents Area ─────────── */

.pick-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: 0.5rem;
}

.pick {
  min-height: 48px;
  min-width: 48px;
  padding: 0 0.9rem;
  font-family: var(--font-display);
  font-weight: 600;
  color: var(--ink);
  background: var(--card);
  border: var(--line-thin);
  border-radius: var(--radius);
  transition: transform var(--fast) var(--ease-pop), background var(--fast) ease;
}

.pick:hover {
  transform: translateY(-2px);
}

.pick--on {
  background: var(--star);
  border: var(--line);
  box-shadow: var(--lift-sm);
}

/* ─────────── The daily review, on the parent screen ─────────── */

/*
  The most useful thing on this screen was a grey chip and a plain button
  in a row of three, between two cards, where it read as a footnote. A
  parent with four minutes should see what to do from the doorway.
*/
.review-panel {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.9rem 1.2rem;
  background: linear-gradient(140deg, #fff 45%, color-mix(in oklab, var(--star) 36%, #fff));
  border: var(--line);
}

.review-panel__count {
  flex: none;
  display: grid;
  place-items: center;
  width: 3.6rem;
  height: 3.6rem;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.7rem;
  font-variant-numeric: tabular-nums;
  background: var(--card);
  border: var(--line);
  border-radius: 50%;
  box-shadow: var(--lift-sm);
}

.review-panel__words {
  flex: 1 1 16rem;
  min-width: 0;
}

.review-panel__title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-lg);
  margin-bottom: 0.2rem;
}

.review-panel__go {
  flex: none;
}

/* Nothing due is good news, not a gap. It says so and takes the star off. */
.review-panel--clear {
  background: linear-gradient(140deg, #fff 45%, color-mix(in oklab, var(--good, #38c172) 22%, #fff));
}

.review-panel--clear .review-panel__count {
  color: #2f9e44;
}

/* ─────────── The moment a thing becomes known ─────────── */

/*
  Small, and it does not stop the game. A child who has just answered
  correctly is already moving to the next question; a box in the middle of
  the screen saying WELL DONE takes that away rather than adds to it.

  It names what was learned rather than praising the child, because "you
  know 7 × 8 now" is still true after the tablet is put down.
*/
.learned {
  position: fixed;
  left: 50%;
  bottom: calc(1.5rem + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  z-index: 60;
  display: flex;
  align-items: center;
  gap: 0.7rem;
  max-width: min(92vw, 26rem);
  padding: 0.7rem 1.1rem;
  background: var(--card);
  border: var(--line);
  border-radius: 999px;
  box-shadow: var(--lift);
  animation: learned-in 2.6s ease both;
  pointer-events: none;
}

.learned__mark {
  font-size: 1.5rem;
  line-height: 1;
}

.learned__words {
  display: grid;
  min-width: 0;
}

.learned__what {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-base);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.learned__said {
  font-size: var(--text-sm);
  color: var(--ink-soft);
}

/* For good is the rarer one — months of getting it right — so it is the
   one that carries the colour. */
.learned--for-good {
  background: linear-gradient(140deg, #fff 40%, color-mix(in oklab, var(--star) 45%, #fff));
}

@keyframes learned-in {
  0% { opacity: 0; transform: translate(-50%, 1rem); }
  8%, 88% { opacity: 1; transform: translate(-50%, 0); }
  100% { opacity: 0; transform: translate(-50%, 0.5rem); }
}

@media (prefers-reduced-motion: reduce) {
  .learned {
    animation: none;
  }
}

/* ─────────── Things I know ─────────── */

/*
  Nothing on this screen is red, and nothing is a bar left half empty.
  A thing is known, nearly known, or simply not mentioned yet — because the
  point of it is to show a child what they have, not what they are missing.
*/
.known-head {
  display: flex;
  align-items: center;
  gap: 1.1rem;
  background: linear-gradient(140deg, #fff 45%, color-mix(in oklab, var(--good, #38c172) 22%, #fff));
}

.known-head__count {
  flex: none;
  display: grid;
  place-items: center;
  width: 4.6rem;
  height: 4.6rem;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 2.1rem;
  font-variant-numeric: tabular-nums;
  background: var(--card);
  border: var(--line);
  border-radius: 50%;
  box-shadow: var(--lift-sm);
}

.known-head__words {
  min-width: 0;
}

.known-head__title {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  margin-bottom: 0.2rem;
}

.known-sub {
  font-family: var(--font-display);
  font-size: var(--text-sm);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* One game per row, and tapping it opens it — the list that says
   "practise these" has to be a list you can act on. */
.known-group {
  display: grid;
  gap: 0.35rem;
}

.known-group__title {
  font-family: var(--font-display);
  font-size: var(--text-base);
  letter-spacing: 0.02em;
}

.known-group__note {
  margin: 0 0 0.3rem;
}

.known-rows {
  display: grid;
  gap: 0.5rem;
}

.known-row {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  width: 100%;
  padding: 0.65rem 0.9rem;
  text-align: left;
  background: var(--card);
  border: var(--line-thin);
  border-radius: var(--radius);
  cursor: pointer;
  transition: transform var(--fast) var(--ease-pop), box-shadow var(--fast) ease;
}

.known-row:hover {
  transform: translateY(-2px);
  box-shadow: var(--lift-sm);
}

.known-row__icon {
  font-size: 1.6rem;
  line-height: 1;
}

.known-row__body {
  display: grid;
  flex: 1;
  min-width: 0;
}

.known-row__name {
  font-family: var(--font-display);
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.known-row__detail {
  font-size: var(--text-sm);
  color: var(--ink-soft);
}

.known-row__score {
  flex: none;
  font-family: var(--font-display);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* Gold for the finished ones, green for the good ones, and the third is
   left plain: it is a list of what to play next, not a telling-off. */
.known-row--mastered {
  border: var(--line);
  background: linear-gradient(140deg, #fff 50%, color-mix(in oklab, var(--star) 34%, #fff));
}

.known-row--going-well {
  background: linear-gradient(140deg, #fff 55%, color-mix(in oklab, var(--good, #38c172) 22%, #fff));
}

.known-row--mastered .known-row__score {
  color: #8a6400;
}

.known-nearly {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-sm);
  color: var(--ink-soft);
}

.known-subjects {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem;
}

.known-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.35rem 0.85rem;
  font-size: var(--text-sm);
  background: var(--card);
  border: var(--line-thin);
  border-radius: 999px;
}

.known-chip__name {
  font-family: var(--font-display);
  font-weight: 600;
}

.known-chip__count {
  font-variant-numeric: tabular-nums;
  color: var(--ink-soft);
}

.known-foot {
  margin-top: 0.4rem;
}

/* Day one. Not a failure, and it says what will fill it. */
.known-empty {
  display: grid;
  justify-items: center;
  gap: 0.6rem;
  text-align: center;
}

.known-empty__mark {
  font-size: 3.4rem;
  line-height: 1;
}

.known-empty p {
  max-width: 44ch;
}

/* ─────────── What is waiting ─────────── */

/*
  One line, and it says nothing at all when there is nothing. No day
  count, no chain, and no sentence that is worse for having been away: a
  child who has not played for a month reads the same words as one who
  played this morning, only with more in them.
*/
.waiting {
  display: grid;
  gap: 0.6rem;
  margin: 0;
  padding: clamp(1rem, 0.7rem + 1vw, 1.5rem);
  background: var(--card);
  border: var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--lift-sm);
}

.waiting__label {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-sm);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* Each one is a chip, the same shape as today's goals directly above it.
   It used to be a run of underlined words inside a stretched pill, which
   matched nothing else on the screen and looked worse the more it had to
   say — two lines of it inside a shape meant for one. */
.waiting__row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem;
}

.waiting__go,
.waiting__what {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.45rem 0.9rem;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-sm);
  color: var(--ink);
  background: var(--paper-deep);
  border: var(--line-thin);
  border-radius: 999px;
}

.waiting__go {
  cursor: pointer;
  transition: background 150ms ease, transform 150ms ease;
}

.waiting__go:hover {
  background: var(--star);
}

.waiting__go:active {
  transform: translateY(2px);
}

.waiting__go:focus-visible {
  outline: 3px solid var(--focus, #1f5fa8);
  outline-offset: 2px;
}

/* Nothing to go and do, so it does not pretend to be a button. */
.waiting__what {
  color: var(--ink-soft);
  background: transparent;
}

/* ─────────── Picking today's three ─────────── */

.goals--choosing .goals__ask {
  margin: 0.2rem 0 0.6rem;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-base);
}

/* A goal that can be tapped has to look like it can be tapped, or it
   reads as a list of what has been decided for you. */
.goal--pick {
  cursor: pointer;
  background: var(--card);
  border: 2px dashed rgba(35, 32, 28, 0.35);
  transition: transform var(--fast) var(--ease-pop), background var(--fast) ease;
}

.goal--pick:hover {
  transform: translateY(-2px);
}

.goal--picked {
  background: var(--star);
  border: var(--line-thin);
  border-style: solid;
  box-shadow: var(--lift-sm);
}

.goals__done {
  justify-self: start;
  margin-top: 0.7rem;
}

.goals__done:disabled {
  opacity: 0.55;
  cursor: default;
  transform: none;
  box-shadow: var(--lift-sm);
}


/* ─────────── What this page is, under the game ───────────

   Every game has its own address, so every address has to say what it
   is. The difficulty is tone: it must look made, without looking
   playable, and it must stay out of the way of the game above it.

   What it does with the space:

   The subject's own colour runs down the left edge and marks the section
   headings. Every other surface on this site is keyed to its subject —
   the tiles, the cards, the menus — so the panel reading as "the world
   one" or "the maths one" costs nothing and ties it to the page.

   Two columns where there is room. The writing about the game goes left
   and reads as prose; what is in it and how to play go right, short and
   scannable. A single column of five stacked sections was a wall, and
   the two halves are wanted by two different people — the paragraph by a
   parent deciding, the steps by a child starting.

   Headings are small caps against the subject colour rather than more
   bold text, so five of them in a row still read as signposts.

   And no shadow, no rounded-22px cards, no filled chips: those are the
   game's own language, and this is text about the game. */

.has-about .shell {
  min-height: 0;
  padding-bottom: 0;
}

.play-about[hidden] {
  display: none;
}

.play-about {
  display: block;
  margin-block: clamp(1.5rem, 1rem + 2vw, 2.5rem) 0;
  padding-block: 0 calc(2.5rem + env(safe-area-inset-bottom, 0px));
}

.play-about__card {
  --about: var(--logic, #64748b);
  display: grid;
  gap: 0.9rem;
  padding: clamp(1.2rem, 1rem + 1vw, 1.9rem) clamp(1.1rem, 0.9rem + 1vw, 1.8rem);
  color: var(--ink-soft);
  font-size: var(--text-xs, 0.82rem);
  line-height: 1.6;
  background: rgba(255, 255, 255, 0.5);
  border: 1px solid rgba(35, 32, 28, 0.14);
  border-left: 4px solid var(--about);
  border-radius: 4px 12px 12px 4px;
}

.play-about__card--write { --about: var(--write); }
.play-about__card--english { --about: var(--english); }
.play-about__card--maths { --about: var(--maths); }
.play-about__card--polish { --about: var(--polish); }
.play-about__card--world { --about: var(--world); }
.play-about__card--logic { --about: var(--logic); }
.play-about__card--chess { --about: var(--chess); }
.play-about__card--it { --about: var(--it); }
.play-about__card--science { --about: var(--science); }
.play-about__card--reading { --about: var(--reading); }
.play-about__card--arts { --about: var(--arts); }

/* ── the head ── */

.play-about__head {
  display: block;
}

.play-about__icon {
  display: none;
}

.play-about__title {
  margin: 0 0 0.25rem;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--text-base);
  line-height: 1.2;
  color: var(--ink);
  text-wrap: balance;
}

.play-about__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  margin: 0;
  font-size: 0.74rem;
}

.play-about__chip {
  padding: 0;
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  white-space: nowrap;
}

.play-about__chip + .play-about__chip::before {
  content: '·';
  margin-right: 0.3rem;
}

a.play-about__chip {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-color: var(--about);
  text-decoration-thickness: 2px;
}

/* The one sentence that carries the page: a size up, in the ink colour. */
.play-about__lead {
  margin: 0;
  max-width: 62ch;
  font-size: var(--text-sm);
  line-height: 1.5;
  color: var(--ink);
  text-wrap: pretty;
}

/* ── two columns where there is room ── */

.play-about__cols {
  display: grid;
  gap: 1rem 2.2rem;
}

.play-about__main,


.play-about__main p {
  margin: 0;
  max-width: 62ch;
}

.play-about__main p + p {
  margin-top: 0.6rem;
}

/* Small caps in the subject's colour: five bold headings in a row stop
   being signposts and become noise. */
.play-about__sub {
  margin: 0.3rem 0 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--about);
  filter: saturate(0.9) brightness(0.82);
}

.play-about__main > .play-about__sub:first-child,
.play-about__side > .play-about__sub:first-child {
  margin-top: 0;
}

/* What is in it, counted from the game itself. */
.play-about__inside {
  margin: 0;
  color: var(--ink);
}

.play-about__inside-label {
  font-family: var(--font-display);
  font-weight: 700;
  color: var(--about);
  filter: saturate(0.9) brightness(0.82);
}

/* ── the other games ── */

.play-about__games {
  display: grid;
  gap: 0.25rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.play-about__games a {
  display: block;
  padding: 0.1rem 0;
  color: inherit;
  text-decoration: none;
}

.play-about__games strong {
  font-family: var(--font-display);
  font-weight: 600;
  color: var(--ink);
  border-bottom: 2px solid var(--about);
}

.play-about__games a:hover strong {
  border-bottom-color: var(--ink);
}

/* ── the way out ── */

.play-about__back {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0.4rem 0 0;
  padding-top: 0.9rem;
  border-top: 1px solid rgba(35, 32, 28, 0.12);
}

.play-about__btn {
  display: inline-block;
  min-height: 0;
  min-width: 0;
  width: auto;
  padding: 0.5rem 1rem;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-xs, 0.82rem);
  color: var(--ink);
  background: rgba(255, 255, 255, 0.7);
  border: 1px solid rgba(35, 32, 28, 0.28);
  border-radius: 999px;
  box-shadow: none;
  text-decoration: none;
  cursor: pointer;
  transition: background 150ms ease, border-color 150ms ease, transform 150ms ease;
}

.play-about__btn:hover {
  border-color: var(--ink);
  background: #fff;
}

.play-about__btn:active {
  transform: translateY(1px);
}

/* Back to the game is where a child wants to go, so it is the loud one. */
.play-about__btn--go {
  color: var(--ink);
  background: var(--star);
  border-color: var(--ink);
}

.play-about__btn--go:hover {
  background: var(--star);
  filter: brightness(1.06);
}

.play-about__btn:focus-visible {
  outline: 3px solid var(--focus, #1f5fa8);
  outline-offset: 2px;
}

.play-about__more {
  display: flex;
  flex-wrap: wrap;
  gap: 0.2rem 1rem;
  margin: 0;
  font-size: 0.74rem;
}

.play-about__more a {
  color: inherit;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
  text-decoration-color: rgba(35, 32, 28, 0.3);
}

.play-about__more a:hover {
  color: var(--ink);
  text-decoration-color: currentColor;
}

@media (min-width: 52rem) {
  .play-about__cols {
    grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
  }
}

/* On a whiteboard the room is looking at the game, not at a paragraph. */
.board-mode .play-about {
  display: none;
}

/* ─────────── Shapes: typing the size ───────────
   Dragging a corner is how a child feels what a perimeter is, and it is
   still the main way in. But a task asking for six by four is a task
   about six and four, and finding them a pixel at a time turns it into a
   test of a trackpad. The boxes always show what the shape is now, so
   they read as a measurement as much as a control. */

.sizer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.9rem;
  margin-top: 0.8rem;
  padding-top: 0.8rem;
  border-top: var(--line-thin);
}

.sizer__label {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-sm);
  color: var(--ink-soft);
}

.sizer__field {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: var(--text-sm);
}

.sizer__name {
  font-family: var(--font-display);
  font-weight: 600;
}

.sizer__box {
  width: 4.5rem;
  padding: 0.35rem 0.5rem;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--text-base);
  text-align: center;
  color: var(--ink);
  background: var(--paper-deep);
  border: var(--line-thin);
  border-radius: 10px;
}

.sizer__box:focus-visible {
  outline: 3px solid var(--focus, #1f5fa8);
  outline-offset: 2px;
}

.sizer__unit {
  color: var(--ink-soft);
}


/* ─────────── The brand row on a phone ─────────── */

/* The logo, EN | PL and the parents button stay on one row on every phone.
   They needed about 370px and a 360px phone has 336, so they wrapped under
   the logo on most phones. A smaller logo and switch make room at 430px and
   below; under 380px the button keeps only its face. */
@media (max-width: 430px) {
  .hero__row {
    flex-wrap: nowrap;
    align-items: center;
  }

  .hero__brand {
    --logo-h: 30px;
    margin-bottom: 0;
    min-width: 0;
  }

  .hero__tools {
    gap: 0.4rem;
  }

  .lang-switch {
    height: 40px;
    font-size: 0.85rem;
  }

  .lang-switch__on,
  .lang-switch__go {
    min-width: 38px;
    padding: 0 0.45rem;
  }

  .hero__parents {
    min-height: 40px;
    padding: 0 0.7rem;
    font-size: 0.85rem;
  }
}

@media (max-width: 379px) {
  .hero__parents-label {
    display: none;
  }

  .hero__parents {
    min-width: 44px;
    padding: 0;
  }
}
