/* ============================================================
   Jugnu Jar — puzzles.css
   Surfaces for Think & Solve and Secret Codes.

   Mobile first throughout: these are the newest screens and the
   most likely to be played on a phone, so nothing here assumes
   room it might not get.
   ============================================================ */

/* ============================================================
   Balance Scales
   ============================================================ */

.balance-question {
  color: #fff;
  text-align: center;
  font-size: clamp(17px, 4vw, 26px);
  margin: 2px 0 12px;
  text-shadow: 0 2px 0 rgba(45, 33, 80, .28);
}

.balance-board {
  display: flex;
  justify-content: center;
  margin-bottom: 14px;
}

/* ---- the tipping scale ---- */

.scale {
  position: relative;
  width: min(340px, 100%);
  padding-top: 8px;
}

.beam {
  position: relative;
  height: 96px;
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  /* The beam and both pans rotate as one, which is what makes it read as a
     single object rather than three pieces that happen to move together. */
  transform-origin: 50% 100%;
  transition: transform .5s cubic-bezier(.34, 1.3, .64, 1);
}
.beam::before {
  content: "";
  position: absolute;
  left: 6%;
  right: 6%;
  bottom: 0;
  height: 8px;
  border-radius: var(--r-pill);
  background: #6b5bb5;
}

.pan {
  width: 42%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  min-height: 96px;
}
.pan-items {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 2px;
  font-size: clamp(20px, 5.5vw, 30px);
  line-height: 1;
  margin-bottom: 4px;
}
.pan-plate {
  width: 100%;
  height: 12px;
  border-radius: 0 0 var(--r-pill) var(--r-pill);
  background: linear-gradient(180deg, #efe9ff, #c9b8ff);
  box-shadow: var(--shadow-1);
}

.scale-post {
  width: 12px;
  height: 46px;
  margin: 0 auto;
  background: #6b5bb5;
}
.scale-base {
  width: 55%;
  height: 12px;
  margin: 0 auto;
  border-radius: var(--r-pill);
  background: #6b5bb5;
}

/* ---- the fact rows used by the harder kinds ---- */

.balance-facts {
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: min(420px, 100%);
}

.fact-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 10px 8px;
  border-radius: var(--r-md);
  background: rgba(255, 255, 255, .18);
}
.fact-row.ask {
  background: rgba(255, 255, 255, .3);
  border: 3px dashed rgba(255, 255, 255, .55);
}

.fact-side {
  flex: 1 1 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 4px;
  min-width: 0;
  font-size: clamp(19px, 5vw, 28px);
  line-height: 1.15;
}
/* A pile must wrap internally, not just as a whole. Seven stars in one
   unbreakable inline-flex needed 270px in a 178px column, so they spilled out
   of the row on both sides — the leftmost one landing on top of the ⚖️. */
.fact-pile {
  display: inline-flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 2px;
  min-width: 0;
  max-width: 100%;
}
.fact-pile.counted { gap: 4px; }
.pile-count {
  font-size: clamp(17px, 4.2vw, 24px);
  font-weight: 900;
  color: #fff;
  text-shadow: 0 2px 0 rgba(45, 33, 80, .3);
}

.fact-eq { flex: 0 0 auto; font-size: clamp(17px, 4vw, 24px); }
.fact-unknown {
  font-size: clamp(22px, 6vw, 32px);
  font-weight: 900;
  color: #fff;
  text-shadow: 0 2px 0 rgba(45, 33, 80, .35);
}

.balance-hint {
  color: #fff;
  text-align: center;
  font-weight: 700;
  font-size: 14px;
  margin: 6px auto 10px;
  max-width: 44ch;
  opacity: .95;
}

.balance-options {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
  width: min(420px, 100%);
  margin: 0 auto;
}
.balance-tile {
  min-height: 60px;
  border: none;
  border-radius: var(--r-md);
  background: var(--c-card);
  color: var(--c-ink);
  font-size: clamp(17px, 4.5vw, 24px);
  font-weight: 900;
  box-shadow: var(--shadow-2);
  transition: transform .12s ease;
}
.balance-tile:active { transform: scale(.95); }
.balance-tile.right { background: var(--c-good); color: #fff; }
.balance-tile.wrong { background: var(--c-oops); color: #fff; opacity: .75; }

/* ============================================================
   Picture Logic (nonograms)
   ============================================================ */

.nono-caption {
  color: #fff;
  text-align: center;
  font-size: clamp(17px, 4vw, 26px);
  margin: 2px 0 12px;
  text-shadow: 0 2px 0 rgba(45, 33, 80, .28);
}

.nono-wrap { display: flex; flex-direction: column; align-items: center; }

.nono-board {
  display: inline-flex;
  flex-direction: column;
  gap: 3px;
  padding: 10px;
  border-radius: var(--r-md);
  background: rgba(255, 255, 255, .2);
  transition: transform .35s ease;
}
.nono-board.solved { transform: scale(1.04); }

.nono-row { display: flex; gap: 3px; align-items: stretch; }

/* Cells shrink with the viewport so a 5x5 grid plus its clues always fits a
   320px screen without the board scrolling sideways. */
.nono-cell,
.nono-clue,
.nono-corner {
  width: min(46px, 12vw);
  height: min(46px, 12vw);
}

.nono-cell {
  border: 2px solid rgba(255, 255, 255, .5);
  border-radius: 8px;
  background: rgba(255, 255, 255, .82);
  color: var(--c-ink-soft);
  font-size: min(20px, 5vw);
  font-weight: 900;
  padding: 0;
  transition: background .12s ease, transform .1s ease;
}
.nono-cell:active { transform: scale(.9); }
.nono-cell.filled { background: #4b3b8f; border-color: #3a2d72; }
.nono-cell.crossed { background: rgba(255, 255, 255, .35); }

.nono-clue {
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-weight: 900;
  font-size: min(15px, 3.9vw);
  line-height: 1.05;
  white-space: pre;
  text-shadow: 0 1px 0 rgba(45, 33, 80, .4);
}
.nono-clue.col { flex-direction: column; justify-content: flex-end; padding-bottom: 2px; }
.nono-clue.row { justify-content: flex-end; padding-right: 4px; }

.nono-controls {
  display: flex;
  gap: 10px;
  justify-content: center;
  margin-top: 14px;
  flex-wrap: wrap;
}

.nono-hint {
  color: #fff;
  text-align: center;
  font-weight: 700;
  font-size: 14px;
  margin: 12px auto 0;
  max-width: 44ch;
}

/* ============================================================
   Secret Codes
   ============================================================ */

.decode-riddle {
  color: #fff;
  text-align: center;
  font-size: clamp(16px, 3.8vw, 24px);
  margin: 2px auto 14px;
  max-width: 34ch;
  text-shadow: 0 2px 0 rgba(45, 33, 80, .28);
}

.coded-row,
.slot-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  justify-content: center;
  align-items: center;
  margin-bottom: 10px;
}

.coded-cell {
  min-width: 34px;
  padding: 8px 8px;
  border-radius: var(--r-sm);
  background: rgba(255, 255, 255, .22);
  color: #fff;
  font-weight: 900;
  font-size: clamp(15px, 4vw, 21px);
  text-align: center;
}
/* Morse patterns are wider than a single glyph and must not wrap mid-letter,
   or "-..-" reads as two separate letters. */
.coded-cell.morse {
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  letter-spacing: 2px;
  white-space: nowrap;
}
.coded-cell.symbol { font-size: clamp(18px, 5vw, 26px); }

.slot {
  width: clamp(30px, 8.5vw, 42px);
  height: clamp(38px, 10vw, 50px);
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--r-sm);
  border: 3px dashed rgba(255, 255, 255, .5);
  color: #fff;
  font-weight: 900;
  font-size: clamp(17px, 4.6vw, 24px);
}
.slot.right {
  background: var(--c-good);
  border-style: solid;
  border-color: var(--c-good-dark);
}

.letter-pad {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(38px, 1fr));
  gap: 5px;
  width: min(460px, 100%);
  margin: 10px auto 0;
}
.letter-key {
  min-height: 44px;
  border: none;
  border-radius: var(--r-sm);
  background: var(--c-card);
  color: var(--c-ink);
  font-weight: 900;
  font-size: 16px;
  box-shadow: var(--shadow-1);
  transition: transform .1s ease;
}
.letter-key:active { transform: scale(.9); }

.decode-controls { display: flex; justify-content: center; margin: 14px 0 6px; }

.key-box {
  width: min(460px, 100%);
  margin: 0 auto;
  padding: 12px;
  border-radius: var(--r-md);
  background: rgba(255, 255, 255, .2);
}
.key-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(58px, 1fr));
  gap: 6px;
}
.key-pair {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  padding: 6px 4px;
  border-radius: var(--r-sm);
  background: rgba(255, 255, 255, .55);
  color: var(--c-ink);
  font-size: 13px;
  font-weight: 800;
  border: none;
}
.key-pair b { font-size: 15px; }
.key-pair.tappable { cursor: pointer; }
.key-pair.tappable:active { transform: scale(.94); }
.key-sym { font-size: 16px; }
.key-morse {
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  letter-spacing: 1px;
  white-space: nowrap;
}
.key-grid.morse .key-pair { font-size: 12px; }

.wheel-note {
  color: #fff;
  font-weight: 800;
  text-align: center;
  margin-bottom: 10px;
  font-size: 14px;
}

/* ============================================================
   Asking a yes or no question

   Replaces the native confirm(), which arrived in the operating system's font,
   announced the site's address and could not be styled. Deliberately shares
   the how-to panel's shape so it reads as part of the app rather than as a
   second kind of dialog.
   ============================================================ */

.ask-sheet {
  position: fixed;
  inset: 0;
  z-index: 70;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 18px;
  background: rgba(30, 20, 60, .62);
  overflow-y: auto;
}

.ask-card {
  width: min(440px, 100%);
  background: #fff;
  border-radius: var(--r-md);
  box-shadow: var(--shadow-1);
  padding: 20px 18px 16px;
  text-align: center;
}

.ask-title {
  margin: 0 0 8px;
  font-size: clamp(17px, 4.6vw, 21px);
  color: var(--c-ink);
}

.ask-message {
  margin: 0 0 16px;
  font-size: clamp(14px, 3.7vw, 16px);
  line-height: 1.5;
  color: #5a5470;
}

.ask-actions {
  display: flex;
  gap: 8px;
  justify-content: center;
  flex-wrap: wrap;
}
.ask-actions .big-btn { padding: 11px 18px; font-size: clamp(14px, 3.6vw, 16px); }

/* For the answers you cannot take back. */
.big-btn.danger {
  background: var(--c-bad, #e5484d);
  color: #fff;
}

/* ============================================================
   How to play
   ============================================================ */

.howto-sheet {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 18px;
  background: rgba(30, 20, 60, .62);
  overflow-y: auto;
}

.howto-card {
  width: min(520px, 100%);
  max-height: 88vh;
  overflow-y: auto;
  padding: 22px 20px 18px;
  border-radius: var(--r-lg);
  background: var(--c-card);
  color: var(--c-ink);
  box-shadow: var(--shadow-2);
  text-align: center;
}

.howto-title {
  font-size: clamp(19px, 4.4vw, 26px);
  margin-bottom: 12px;
}

.howto-steps {
  text-align: left;
  margin: 0 0 12px;
  padding-left: 1.3em;
  font-size: clamp(14px, 3.2vw, 16px);
  line-height: 1.5;
  font-weight: 600;
}
.howto-steps li { margin-bottom: 9px; }

.howto-art {
  margin: 6px 0 2px;
  font-size: 20px;
  line-height: 1.2;
}

.howto-tip {
  margin: 0 0 16px;
  padding: 10px 12px;
  border-radius: var(--r-md);
  background: #f4f0ff;
  color: var(--c-ink-soft);
  font-size: 13px;
  font-weight: 700;
  text-align: left;
  line-height: 1.45;
}

/* ============================================================
   Shared: the sequence row used by What Comes Next / Odd One Out
   ============================================================ */

.seq-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: center;
  align-items: center;
  margin-bottom: 8px;
}
.seq-cell {
  width: clamp(44px, 12vw, 64px);
  height: clamp(44px, 12vw, 64px);
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--r-md);
  background: rgba(255, 255, 255, .82);
  font-size: clamp(24px, 7vw, 38px);
  line-height: 1;
  box-shadow: var(--shadow-1);
}
.seq-cell.seq-blank {
  background: rgba(255, 255, 255, .28);
  border: 3px dashed rgba(255, 255, 255, .6);
  color: #fff;
  font-weight: 900;
}

/* ============================================================
   Fold & Punch
   ============================================================ */

.fold-stage { display: flex; flex-direction: column; align-items: center; }

.fold-caption {
  color: #fff;
  font-weight: 800;
  font-size: clamp(14px, 3.4vw, 19px);
  margin: 0 0 10px;
  text-shadow: 0 2px 0 rgba(45, 33, 80, .28);
}

/* The folded sheet and the opened sheet are the same grid at the same size,
   with the folded-away part left as a dashed outline. Drawing the folded half
   as its own smaller rectangle was clearer to write and much worse to use: a
   child then has to work out unaided that the tall shape is half of the square
   in the answers below. */
.fold-paper {
  position: relative;
  display: grid;
  grid-template-columns: repeat(var(--fold-cols), min(40px, 10vw));
  gap: 3px;
  padding: 7px;
  border-radius: var(--r-md);
  background: rgba(255, 255, 255, .9);
  box-shadow: var(--shadow-1);
}

.fold-cell {
  aspect-ratio: 1;
  border-radius: 7px;
  background: rgba(120, 108, 180, .1);
  display: block;
}

/* Where the paper is folded back on itself: no paper there any more, just the
   outline of where it used to reach. */
.fold-cell.away {
  background: none;
  border: 2px dashed rgba(120, 108, 180, .3);
}

/* A punched hole is a hole: you see through the paper to what is behind it. */
.fold-cell.punched {
  background: #3a2d72;
  box-shadow: inset 0 2px 4px rgba(0, 0, 0, .5);
}
.fold-cell.fresh { animation: pop-in .34s ease both; }

/* The crease, drawn down the middle of the sheet rather than around its edge.
   It is the only thing on screen saying which way the paper opens, so it is
   heavy rather than a hairline. */
.fold-paper.crease-right::before,
.fold-paper.crease-bottom::after {
  content: '';
  position: absolute;
  background: #f08a24;
  border-radius: 3px;
}
.fold-paper.crease-right::before { left: 50%; top: 6px; bottom: 6px; width: 5px; margin-left: -2px; }
.fold-paper.crease-bottom::after { top: 50%; left: 6px; right: 6px; height: 5px; margin-top: -2px; }

.fold-paper.opened { animation: pop-in .3s ease both; }

.fold-paper.mini {
  grid-template-columns: repeat(var(--fold-cols), min(24px, 6.2vw));
  gap: 2px;
  padding: 5px;
  box-shadow: none;
}
.fold-paper.mini .fold-cell { border-radius: 4px; }

/* Not .solve-hint: that one is soft purple, meant for a white card, and on the
   gradient here it is barely readable. */
.fold-hint {
  color: #fff;
  text-align: center;
  font-weight: 700;
  font-size: 14px;
  margin: 16px auto 0;
  max-width: 40ch;
  text-shadow: 0 1px 0 rgba(45, 33, 80, .35);
}

.fold-options {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
  justify-items: center;
  margin-top: 16px;
}

.fold-tile {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 10px;
  min-width: 0;
  border-radius: var(--r-md);
  background: rgba(255, 255, 255, .3);
  transition: transform .12s ease, background .12s ease;
}
.fold-tile:active { transform: scale(.94); }
.fold-tile.right { background: var(--c-good); }
.fold-tile.wrong { background: var(--c-oops); opacity: .8; }

/* ============================================================
   Who Has What
   ============================================================ */

.deduce-caption {
  color: #fff;
  text-align: center;
  font-size: clamp(17px, 4vw, 26px);
  margin: 2px 0 12px;
  text-shadow: 0 2px 0 rgba(45, 33, 80, .28);
}

.deduce-wrap { display: flex; flex-direction: column; align-items: center; }

.deduce-board {
  display: grid;
  grid-template-columns: repeat(var(--deduce-cols), min(52px, 13.5vw));
  gap: 4px;
  padding: 10px;
  border-radius: var(--r-md);
  background: rgba(255, 255, 255, .2);
  transition: transform .35s ease;
}
.deduce-board.solved { transform: scale(1.04); }

.deduce-head,
.deduce-corner,
.deduce-cell {
  aspect-ratio: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.deduce-head { font-size: min(27px, 7vw); line-height: 1; }

.deduce-cell {
  border: 2px solid rgba(255, 255, 255, .5);
  border-radius: 8px;
  background: rgba(255, 255, 255, .82);
  color: var(--c-ink-soft);
  font-size: min(24px, 6vw);
  font-weight: 900;
  padding: 0;
  transition: background .12s ease, transform .1s ease;
}
.deduce-cell:active { transform: scale(.9); }
.deduce-cell.yes { background: var(--c-good); color: #fff; }
.deduce-cell.no { background: rgba(255, 255, 255, .35); color: #fff; }

.deduce-clues-title {
  color: #fff;
  font-weight: 800;
  font-size: 15px;
  margin: 16px 0 8px;
  text-shadow: 0 2px 0 rgba(45, 33, 80, .28);
}

.deduce-clues {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: center;
  max-width: 100%;
}

.deduce-clue {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 6px 10px;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, .88);
  box-shadow: var(--shadow-1);
  font-size: min(22px, 5.6vw);
  line-height: 1;
}
.deduce-clue.yes { box-shadow: var(--shadow-1), inset 0 0 0 3px var(--c-good); }
.deduce-clue.no { box-shadow: var(--shadow-1), inset 0 0 0 3px var(--c-oops); }
.deduce-clue .clue-sign { font-size: min(17px, 4.4vw); }

.deduce-controls {
  display: flex;
  gap: 10px;
  justify-content: center;
  margin-top: 16px;
  flex-wrap: wrap;
}

.deduce-hint {
  color: #fff;
  text-align: center;
  font-weight: 700;
  font-size: 14px;
  margin: 12px auto 0;
  max-width: 44ch;
}

/* The key reads code, then arrow, then letter — the direction of the child's
   work. The header says which is which, because "E A" on its own does not. */
.key-head {
  display: flex;
  justify-content: center;
  gap: 26px;
  color: #fff;
  font-size: 12px;
  font-weight: 800;
  opacity: .9;
  margin: 0 0 8px;
  text-shadow: 0 1px 0 rgba(45, 33, 80, .35);
}

.key-arrow {
  color: var(--c-ink-soft);
  opacity: .55;
  font-size: 12px;
}
.key-code { color: var(--c-ink-soft); font-weight: 800; }
.key-letter { color: var(--c-ink); }

/* ============================================================
   River Crossing
   Two banks with water between them, and a boat that sits on
   one side or the other. The boat is drawn outside the scene
   rather than inside a bank, so it can slide across without the
   banks having to reflow around it.
   ============================================================ */

.river-wrap { display: flex; flex-direction: column; align-items: center; gap: 10px; }

.river-says {
  text-align: center;
  font-weight: 800;
  font-size: clamp(15px, 3.4vw, 19px);
  color: var(--c-ink);
  background: rgba(255, 255, 255, .92);
  border-radius: var(--r-md);
  padding: 10px 14px;
  margin: 0 auto 4px;
  max-width: 34ch;
  min-height: 2.6em;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: var(--shadow-1);
}
.river-says.warn { background: #ffe9e4; color: #a33a22; }
.river-says.good { background: #e2f7e6; color: #21713c; }

.river-scene {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: 6px;
  width: 100%;
  max-width: 460px;
  align-items: stretch;
  transition: transform .2s ease;
}
.river-scene.solved { transform: scale(1.03); }

.river-bank {
  min-height: 96px;
  border-radius: var(--r-md);
  background: linear-gradient(160deg, #d9f0b8, #b6de84);
  box-shadow: inset 0 0 0 3px rgba(255, 255, 255, .5), var(--shadow-1);
  padding: 8px 6px;
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  justify-content: center;
  gap: 4px;
}

.river-water {
  width: clamp(34px, 9vw, 56px);
  border-radius: var(--r-md);
  background: repeating-linear-gradient(
    -45deg, #8fd3f4 0 10px, #6ec1e8 10px 20px);
  box-shadow: inset 0 0 0 3px rgba(255, 255, 255, .35);
}

.river-one {
  font-size: clamp(26px, 6.4vw, 36px);
  line-height: 1;
  background: rgba(255, 255, 255, .85);
  border-radius: var(--r-sm);
  padding: 3px 5px;
  box-shadow: var(--shadow-1);
  transition: transform .12s ease;
}
.river-one:active { transform: scale(.88); }
.river-one.aboard { background: rgba(255, 255, 255, .95); }

/* The two that fell out. Named rather than animated with a bare utility
   class: `.wiggle` in animations.css is shared, and a story reader once
   inherited an infinite pulse meant for a small button. */
.river-one.trouble {
  background: #ffd5cc;
  box-shadow: 0 0 0 3px #e2553a;
}

.river-boat {
  display: flex;
  align-items: center;
  gap: 4px;
  background: rgba(255, 255, 255, .82);
  border-radius: var(--r-md);
  padding: 5px 10px;
  box-shadow: var(--shadow-1);
  transition: transform .3s ease;
}
.river-boat.at-near { transform: translateX(clamp(-70px, -16vw, -40px)); }
.river-boat.at-far  { transform: translateX(clamp(40px, 16vw, 70px)); }

.river-rower { font-size: clamp(24px, 5.6vw, 32px); line-height: 1; }
.river-hull { display: flex; gap: 3px; }
.river-hullart { font-size: clamp(24px, 5.6vw, 32px); line-height: 1; }

.river-seat {
  display: inline-block;
  width: clamp(30px, 7vw, 40px);
  height: clamp(30px, 7vw, 40px);
  border-radius: var(--r-sm);
  border: 2px dashed rgba(90, 70, 140, .35);
}

.river-counter {
  font-weight: 800;
  font-size: 14px;
  color: var(--c-ink-soft);
}

.river-controls { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; }

/* Who must never be left alone together, as pictures. Three of the six
   Think & Solve topics need no reading and this one keeps that. */
.river-rules {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  justify-content: center;
  padding-top: 2px;
}
.river-rule {
  display: flex;
  align-items: center;
  gap: 2px;
  background: rgba(255, 255, 255, .8);
  border-radius: var(--r-sm);
  padding: 3px 8px;
  font-size: clamp(17px, 4vw, 22px);
  line-height: 1;
  box-shadow: var(--shadow-1);
}
.river-zap { font-size: .72em; opacity: .85; }

/* ============================================================
   Same Shape, Turned
   The shape is drawn as a grid of squares. Options are the same
   drawing shrunk, so the child compares like with like -- a
   different drawing style between prompt and answers would add
   a difference that is nothing to do with the puzzle.
   ============================================================ */

.turn-stage {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}

.turn-shape {
  display: grid;
  grid-template-columns: repeat(var(--turn-cols), var(--turn-size));
  grid-template-rows: repeat(var(--turn-rows), var(--turn-size));
  gap: 2px;
}
.turn-shape.big  { --turn-size: clamp(22px, 5.6vw, 32px); }
.turn-shape.mini { --turn-size: clamp(13px, 3.4vw, 19px); }

.turn-cell {
  border-radius: 4px;
  background: rgba(120, 100, 170, .13);
}
.turn-cell.on {
  background: linear-gradient(150deg, #ffc98a, #f0913f);
  box-shadow: inset 0 -2px 0 rgba(0, 0, 0, .12);
}

.turn-arrow { font-size: 20px; opacity: .8; }

.turn-hint {
  text-align: center;
  font-size: 14px;
  font-weight: 700;
  color: var(--c-ink-soft);
  max-width: 30ch;
  margin: 6px auto 0;
}

.turn-options {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
  max-width: 380px;
  margin: 0 auto;
}
.turn-tile {
  background: rgba(255, 255, 255, .92);
  border-radius: var(--r-md);
  padding: 12px 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 84px;
  box-shadow: var(--shadow-1);
  transition: transform .12s ease;
}
.turn-tile:active { transform: scale(.95); }
.turn-tile.right { background: var(--c-good); }
.turn-tile.right .turn-cell { background: rgba(255, 255, 255, .35); }
.turn-tile.right .turn-cell.on { background: #fff; }
.turn-tile.wrong { background: var(--c-oops); opacity: .8; }
.turn-tile.wrong .turn-cell { background: rgba(255, 255, 255, .3); }
.turn-tile.wrong .turn-cell.on { background: rgba(255, 255, 255, .85); }
/* ============================================================
   Four Squares (mini sudoku)
   The 2x2 boxes are marked with a heavier line rather than a
   different colour, so the grid still reads as one grid.
   ============================================================ */

.sud-wrap { display: flex; flex-direction: column; align-items: center; gap: 10px; }

.sud-caption {
  text-align: center;
  font-size: clamp(15px, 3.2vw, 18px);
  font-weight: 800;
  color: #fff;
  margin: 0 0 2px;
  text-shadow: 0 1px 0 rgba(45, 33, 80, .35);
}

/* The four to choose from. Shown always, because a picture that happens not
   to appear among the givens is otherwise invisible until it is tapped to. */
.sud-key {
  display: flex;
  gap: 6px;
  background: rgba(255, 255, 255, .82);
  border-radius: var(--r-md);
  padding: 5px 10px;
  box-shadow: var(--shadow-1);
}
.sud-keycell { font-size: clamp(20px, 4.6vw, 26px); line-height: 1; }

/* The four 2x2 boxes are drawn OVER the grid rather than built as four nested
   containers. Nesting made the lines easy but put the cells in box order in
   the DOM, so a screen reader read row 1 col 1, row 1 col 2, row 2 col 1 --
   the cells stay in reading order and a crosshair marks the boxes. */
.sud-board {
  position: relative;
  display: grid;
  grid-template-columns: repeat(4, var(--sud-size));
  grid-template-rows: repeat(4, var(--sud-size));
  --sud-size: clamp(52px, 15vw, 74px);
  gap: 3px;
  padding: 7px;
  background: rgba(255, 255, 255, .5);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-2);
  transition: transform .2s ease;
}
.sud-board::before,
.sud-board::after {
  content: '';
  position: absolute;
  background: rgba(90, 70, 150, .5);
  border-radius: 2px;
  pointer-events: none;
}
.sud-board::before { left: 50%; top: 5px; bottom: 5px; width: 3px; margin-left: -1.5px; }
.sud-board::after  { top: 50%; left: 5px; right: 5px; height: 3px; margin-top: -1.5px; }
.sud-board.solved { transform: scale(1.04); }

.sud-cell {
  background: rgba(255, 255, 255, .92);
  border-radius: var(--r-sm);
  font-size: calc(var(--sud-size) * .58);
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform .12s ease, background .12s ease;
}
.sud-cell:active { transform: scale(.9); }
.sud-cell.fixed { background: #e8e2f6; box-shadow: inset 0 0 0 2px rgba(110, 90, 170, .28); }

/* A tap on a square that cannot change says so, rather than doing nothing. */
.sud-cell.nudge { background: #ffe0d8; }


.sud-controls { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; }

.sud-hint {
  text-align: center;
  font-weight: 800;
  background: rgba(255, 255, 255, .92);
  border-radius: var(--r-md);
  padding: 8px 14px;
  margin: 8px auto 0;
  max-width: 32ch;
  color: var(--c-ink);
  box-shadow: var(--shadow-1);
}

.sud-tip {
  text-align: center;
  font-size: 13px;
  font-weight: 700;
  color: #fff;
  opacity: .88;
  max-width: 32ch;
  text-shadow: 0 1px 0 rgba(45, 33, 80, .35);
}
/* ============================================================
   Find the Heavy One
   The beam tilts by moving the two pans rather than rotating a
   bar, so the balls inside stay upright and readable.
   ============================================================ */

.weigh-wrap { display: flex; flex-direction: column; align-items: center; gap: 10px; }

.weigh-says {
  text-align: center;
  font-weight: 800;
  font-size: clamp(15px, 3.4vw, 19px);
  color: var(--c-ink);
  background: rgba(255, 255, 255, .92);
  border-radius: var(--r-md);
  padding: 10px 14px;
  margin: 0 auto 4px;
  max-width: 32ch;
  min-height: 2.6em;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: var(--shadow-1);
}
.weigh-says.warn { background: #ffe9e4; color: #a33a22; }
.weigh-says.good { background: #e2f7e6; color: #21713c; }

.weigh-beam {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 6px;
  width: 100%;
  max-width: 420px;
  /* Room for the rising pan. Without it the side that goes UP slides under
     the message saying which side went down. */
  margin-top: 14px;
  /* And room below for the pan that goes DOWN, which otherwise covers the
     line saying how many weighings are left. */
  margin-bottom: 14px;
}
.weigh-post { font-size: clamp(24px, 6vw, 34px); line-height: 1; }

.weigh-pan {
  position: relative;
  min-height: 60px;
  border-radius: var(--r-md);
  background: rgba(255, 255, 255, .82);
  box-shadow: inset 0 0 0 3px rgba(120, 100, 170, .18), var(--shadow-1);
  padding: 6px 4px;
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  justify-content: center;
  gap: 3px;
  transition: transform .45s ease, box-shadow .18s ease, background .18s ease;
}

/* The side being filled. Every ball tapped goes here, so it has to be
   obvious at a glance which one it is -- the pan IS the control, and a child
   taps the side they want rather than a switch somewhere else. */
.weigh-pan.lit {
  background: #fff;
  box-shadow: inset 0 0 0 3px #ffb648, 0 0 0 3px rgba(255, 182, 72, .45), var(--shadow-1);
}

/* How many are on this side. The balance will not weigh until they match, and
   counting eighteen balls by eye to find out why is not a fair thing to ask. */
/* In the outer corner of each pan. Centred, it sat under the message saying
   which side went down, and beside the balance in the middle. */
.weigh-count {
  position: absolute;
  top: -9px;
  min-width: 22px;
  padding: 1px 6px;
  border-radius: var(--r-pill);
  background: #5b3ea8;
  color: #fff;
  font-size: 12px;
  font-weight: 900;
  line-height: 1.5;
  text-align: center;
  pointer-events: none;
}
.weigh-count:empty { display: none; }
.weigh-pan.left  .weigh-count { left: 8px; }
.weigh-pan.right .weigh-count { right: 8px; }
.weigh-beam.down-left  .weigh-pan.left  { transform: translateY(12px); }
.weigh-beam.down-left  .weigh-pan.right { transform: translateY(-12px); }
.weigh-beam.down-right .weigh-pan.left  { transform: translateY(-12px); }
.weigh-beam.down-right .weigh-pan.right { transform: translateY(12px); }

/* Full width whether or not anything is in it. Sized to its contents it
   collapsed to a narrow pill once every ball was on the pans, which looked
   like a stray bit of furniture rather than the shelf they came from. */
.weigh-tray {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  justify-content: center;
  align-content: center;
  width: 100%;
  max-width: 420px;
  min-height: 52px;
  padding: 6px;
  border-radius: var(--r-md);
  background: rgba(255, 255, 255, .38);
}
.weigh-tray.picking { box-shadow: 0 0 0 3px #ffb648; }

/* Balls carry their number. Plain white circles looked right and made the
   puzzle unplayable: once a few had been weighed there was no telling them
   apart, so "the left side went down" could not be acted on. */
.weigh-ball {
  --ball: clamp(34px, 8.4vw, 44px);
  width: var(--ball);
  height: var(--ball);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: calc(var(--ball) * .46);
  font-weight: 900;
  font-variant-numeric: tabular-nums;
  color: #4a3a7a;
  background: radial-gradient(circle at 34% 30%, #ffffff, #d9d2ee 70%, #bdb2dd);
  box-shadow: inset 0 -2px 3px rgba(80, 60, 140, .22), var(--shadow-1);
  transition: transform .12s ease, box-shadow .12s ease;
}
.weigh-ball.small { --ball: clamp(28px, 7vw, 38px); font-size: calc(var(--ball) * .42); }
.weigh-ball:active { transform: scale(.86); }
.weigh-ball.pickable { box-shadow: 0 0 0 3px #ffb648, var(--shadow-1); }
.weigh-ball.is-heavy { box-shadow: 0 0 0 4px #21a05a, var(--shadow-1); color: #1d6b41; }
.weigh-ball.is-wrong { box-shadow: 0 0 0 4px #e2553a, var(--shadow-1); color: #93331f; }

.weigh-counter {
  font-weight: 800;
  font-size: 14px;
  color: var(--c-ink-soft);
  /* Kept inside the board. Unconstrained it ran wider than the balance and
     the tray and looked like it belonged to the page rather than the game. */
  max-width: 420px;
  text-align: center;
  line-height: 1.35;
}
.weigh-controls { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; max-width: 420px; }

/* Tidying up and starting over are housekeeping, not the game. Full-size they
   pushed the board up the screen and read as being as important as weighing. */
.weigh-controls .minor {
  padding: 9px 16px;
  font-size: clamp(13px, 3.2vw, 15px);
  min-height: 0;
}

.weigh-tip {
  text-align: center;
  font-size: 13px;
  font-weight: 700;
  color: #fff;
  opacity: .88;
  max-width: 32ch;
  text-shadow: 0 1px 0 rgba(45, 33, 80, .35);
}
/* ============================================================
   Activity colours — Think & Solve and Secret Codes
   ============================================================

   Every one of these topics offers a single activity, so `router.entryPath`
   sends a child straight into the game and the picker is never drawn. That is
   precisely why these were missing: nothing rendered them, so nothing looked
   wrong. The pills on the topic screen did show, sharing one lavender default.

   They are declared anyway. The day one of these topics gains a second
   activity the picker appears, and it should appear finished rather than grey.
   ============================================================ */

.act-card.balance  { background: linear-gradient(150deg, #b3b9ff, #5560d8); }
.act-card.nonogram { background: linear-gradient(150deg, #9fdcf5, #2790bb); }
.act-card.fold     { background: linear-gradient(150deg, #bcc6e8, #5e6fa6); }
.act-card.deduce   { background: linear-gradient(150deg, #e0aee0, #9f479f); }
.act-card.weigh    { background: linear-gradient(150deg, #e8c9a0, #a4742f); }
.act-card.sudoku   { background: linear-gradient(150deg, #9ee0b8, #2b9760); }
.act-card.turn     { background: linear-gradient(150deg, #f0a9d4, #bd3a8a); }
.act-card.river    { background: linear-gradient(150deg, #93cfe8, #2277a0); }
.act-card.decode   { background: linear-gradient(150deg, #c3b1f0, #6640c4); }

.act-pill.balance  { background: #e6e8ff; color: #4550c0; }
.act-pill.nonogram { background: #e0f4fd; color: #155f7c; }
.act-pill.fold     { background: #e9edf8; color: #4f5e91; }
.act-pill.deduce   { background: #f8e6f8; color: #8c3d8c; }
.act-pill.weigh    { background: #f6ecdd; color: #7f5820; }
.act-pill.sudoku   { background: #e2f6ea; color: #1b6941; }
.act-pill.turn     { background: #fde9f5; color: #a52f77; }
.act-pill.river    { background: #e0f1f9; color: #1c6385; }
.act-pill.decode   { background: #ece5fb; color: #5936a8; }