/* ═══════════════════════════════════════════════════════════════════════════
   Aphro — a play website for a four-year-old.

   Everything here is built on the Organic design system (css/organic.css).
   The --kid-* palette below is an extension authored for this project: six
   tabs need more distinguishable hues than the two base accents provide.

   Selected/unselected state is driven by three per-element custom properties
   — --tint (panel ground), --ink (text and icons on the tint), --base (the
   saturated fill when selected) — set once in markup. Classes then only
   flip between them, so no JavaScript ever writes a colour.
   ═══════════════════════════════════════════════════════════════════════ */

:root {
  --kid-rose: #d16b86;  --kid-rose-dark: #a3486a;  --kid-rose-100: #ffe4ea;
  --kid-teal: #4fa8b8;  --kid-teal-dark: #2f7c8c;  --kid-teal-100: #ddf1f4;
  --kid-sun:  #d9a640;  --kid-sun-dark:  #a97a1e;  --kid-sun-100:  #fdf0d2;
  --kid-plum: #9b6fb0;  --kid-plum-dark: #6f4a86;  --kid-plum-100: #f0e4f7;

  /* Springy — anything a finger caused. Overshoots. */
  --ease-spring: cubic-bezier(.34, 1.56, .64, 1);
  /* Settled — panel entrances. Decelerates. */
  --ease-settle: cubic-bezier(.22, 1, .36, 1);
}

/* ── Document ──────────────────────────────────────────────────────────────
   These rules exist to stop the four-year-old failure modes: rubber-band
   scrolling that reveals a grey void, double-tap zoom that strands the page
   at 2x, long-press selection over a drawing, and the blue tap flash. */

html, body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  background: var(--color-bg);
  overscroll-behavior: none;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

* {
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

a { color: var(--color-accent-700); }
a:hover { color: var(--color-accent-800); }

button { font: inherit; color: inherit; }

/* Author `display` values would otherwise beat the UA sheet's [hidden] rule. */
[hidden] { display: none !important; }

/* ── Motion tokens ─────────────────────────────────────────────────────── */

@keyframes floaty    { 0%, 100% { transform: translateY(0) }    50% { transform: translateY(-9px) } }
@keyframes wob       { 0%, 100% { transform: rotate(-3.5deg) }  50% { transform: rotate(3.5deg) } }
@keyframes breathe   { 0%, 100% { transform: scale(1) }         50% { transform: scale(1.04) } }
@keyframes spin      { to { transform: rotate(360deg) } }
@keyframes blink     { 0%, 90%, 100% { transform: scaleY(1) }   95% { transform: scaleY(.08) } }

@keyframes popIn {
  from { opacity: 0; transform: translateY(14px) scale(.985) }
  to   { opacity: 1; transform: none }
}
@keyframes popBounce {
  0%   { opacity: 0; transform: scale(0) rotate(-22deg) }
  60%  { opacity: 1; transform: scale(1.28) rotate(7deg) }
  100% { opacity: 1; transform: scale(1) rotate(0) }
}
@keyframes numBounce {
  0%   { transform: scale(.55) }
  55%  { transform: scale(1.12) }
  100% { transform: scale(1) }
}
@keyframes tabBob {
  0%, 100% { transform: translateY(-6px)  rotate(-.6deg) }
  50%      { transform: translateY(-13px) rotate(.6deg) }
}
@keyframes bigBob {
  0%, 100% { transform: translateY(0)     rotate(-2deg) }
  50%      { transform: translateY(-26px) rotate(2deg) }
}

/* The accessibility path for motion sensitivity. `.idle` marks the ambient
   loops, `.enter` the one-shot entrances; the flag stills both. Wired to the
   parent setting and to prefers-reduced-motion in js/config.js. */
body.reduce-motion .idle  { animation-play-state: paused !important; }
body.reduce-motion .enter { animation: none !important; }

/* ── Shell ─────────────────────────────────────────────────────────────────
   The 100dvh cap matters: iPad Safari's toolbar changes the viewport, and
   without it the bottom row of every tab clips. */

.app {
  height: 100vh;
  max-height: 100dvh;
  display: flex;
  flex-direction: column;
  background: var(--color-bg);
  font-family: var(--font-body);
  padding: 16px 22px 20px;
  gap: 14px;
  box-sizing: border-box;
  overflow: hidden;
}

/* ── Header ────────────────────────────────────────────────────────────── */

.header {
  display: flex;
  align-items: flex-end;
  gap: 14px;
  flex: none;
}

/* Tapping the name re-opens the splash — a front door from anywhere. */
.logo {
  flex: none;
  align-self: center;
  display: flex;
  gap: 5px;
  padding: 0 8px 0 0;
  border: 0;
  background: transparent;
  cursor: pointer;
}

.logo-tile {
  width: 34px;
  height: 44px;
  border-radius: 9px;
  box-shadow: var(--shadow-sm);
  display: grid;
  place-items: center;
  font-family: var(--font-heading);
  font-size: 23px;
  color: #ffffff;
  background: var(--base);
}

/* Alternating tilt — it reads as handmade rather than as a grid. */
.logo-tile:nth-child(1) { transform: rotate(-4deg) }
.logo-tile:nth-child(2) { transform: rotate(3deg) }
.logo-tile:nth-child(3) { transform: rotate(-2deg) }
.logo-tile:nth-child(4) { transform: rotate(4deg) }
.logo-tile:nth-child(5) { transform: rotate(-3deg) }

.tabs {
  flex: 1;
  display: flex;
  gap: 12px;
  justify-content: flex-end;
}

.tab {
  flex: 1;
  height: 88px;
  border: 0;
  padding: 0;
  cursor: pointer;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  background: var(--color-surface);
  color: var(--base);
  transition: transform .3s var(--ease-spring), background .25s ease;
}

/* LETTERS and NUMBERS use a glyph rather than an icon, and sit tighter. */
.tab--glyph { gap: 0; }
.tab-glyph { font-family: var(--font-heading); font-size: 30px; line-height: 1.1; }
.tab-glyph--num { font-size: 28px; line-height: 1.15; }

.tab-label {
  font-family: var(--font-heading);
  font-size: clamp(13px, 1.7vw, 19px);
}

.tab.is-active {
  background: var(--base);
  color: #ffffff;
  transform: translateY(-6px);
  animation: tabBob 2.6s ease-in-out infinite;
}

/* tabBob's 0% keyframe carries a tilt, so stilling it means removing the
   animation rather than pausing it — the resting state is the clean lift. */
body.reduce-motion .tab.is-active { animation: none; }

/* The animals tab's eyes are cut-outs: they take the tab's own ground so the
   holes track the active/inactive swap. */
.tab .cutout { fill: var(--color-surface); }
.tab.is-active .cutout { fill: var(--base); }

/* ── Splash ────────────────────────────────────────────────────────────────
   Shown once per calendar day, and whenever the name is tapped. */

.splash {
  position: fixed;
  inset: 0;
  z-index: 60;
  background: var(--color-bg);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 44px;
  cursor: pointer;
  overflow: hidden;
  opacity: 1;
  transition: opacity .5s ease;
}

.splash.is-closing {
  opacity: 0;
  pointer-events: none;
}

.splash-blob {
  position: absolute;
  border-radius: 50%;
}
.splash-blob--1 { left: -120px; top: -100px;    width: 420px; height: 420px; background: var(--kid-teal-100) }
.splash-blob--2 { right: -100px; bottom: -120px; width: 460px; height: 460px; background: var(--kid-rose-100) }
.splash-blob--3 { right: 120px; top: -80px;     width: 240px; height: 240px; background: var(--kid-sun-100) }
.splash-blob--4 { left: 70px; bottom: -90px;    width: 260px; height: 260px; background: var(--kid-plum-100) }

.splash-name {
  position: relative;
  display: flex;
  gap: 22px;
}

.splash-tile {
  width: clamp(92px, 13vw, 148px);
  height: clamp(118px, 16.5vw, 188px);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  display: grid;
  place-items: center;
  font-family: var(--font-heading);
  font-size: clamp(62px, 9vw, 104px);
  color: #ffffff;
  background: var(--base);
  animation: bigBob 2.8s ease-in-out infinite;
}

/* A slow rolling wave down the name. */
.splash-tile:nth-child(2) { animation-delay: .15s }
.splash-tile:nth-child(3) { animation-delay: .3s }
.splash-tile:nth-child(4) { animation-delay: .45s }
.splash-tile:nth-child(5) { animation-delay: .6s }

.splash-cta {
  position: relative;
  background: var(--color-surface);
  border-radius: 999px;
  padding: 18px 46px;
  box-shadow: var(--shadow-sm);
  animation: breathe 2.4s ease-in-out infinite;
}
.splash-cta span {
  font-family: var(--font-heading);
  font-size: 30px;
}

/* ── Panels ────────────────────────────────────────────────────────────────
   All six stay mounted so the canvases keep their state: leaving MESSY and
   coming back shows the same pile. Only the active one is displayed. */

.panel {
  flex: 1;
  min-height: 0;
  display: none;
}
.panel.is-active {
  display: flex;
  animation: popIn .45s var(--ease-settle);
}
body.reduce-motion .panel.is-active { animation: none; }

.panel-col {
  flex-direction: column;
  gap: 14px;
}

/* ── LETTERS ───────────────────────────────────────────────────────────── */

.letter-row {
  flex: none;
  display: flex;
  gap: 14px;
}

.letter-btn {
  flex: 1;
  height: 104px;
  border: 0;
  padding: 0;
  cursor: pointer;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  font-family: var(--font-heading);
  font-size: 52px;
  background: var(--color-surface);
  color: var(--ink);
  transition: background .25s ease, transform .3s var(--ease-spring);
}
.letter-btn.is-on {
  background: var(--base);
  color: #ffffff;
  transform: scale(1.04);
}

.letter-body {
  flex: 1;
  min-height: 0;
  display: flex;
  gap: 14px;
}

.trace {
  flex: 1;
  min-width: 0;
  position: relative;
  background: var(--color-surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}

.trace-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  touch-action: none;
  cursor: crosshair;
}

.trace-hint {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  position: absolute;
  left: 16px;
  top: 12px;
  font-family: var(--font-heading);
  font-size: 18px;
  color: var(--color-neutral-600);
  pointer-events: none;
}

.trace-wipe {
  position: absolute;
  right: 12px;
  bottom: 12px;
  font-size: 14px;
  padding: 10px 18px;
  /* The handoff draws this at 39px, below its own 44px floor, and does not
     list it among the two documented exceptions. It is positioned in a corner,
     so the height is free. A miss here draws on the canvas, which is harmless. */
  min-height: 44px;
}

.reveal {
  flex: 1;
  min-width: 0;
  border: 0;
  font: inherit;
  color: inherit;
  text-align: center;
  cursor: pointer;
  -webkit-appearance: none;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 18px;
  background: var(--tint);
  transition: background .3s;
}

.reveal-art {
  flex: 1;
  min-height: 0;
  display: grid;
  place-items: center;
  color: var(--ink);
  animation: floaty 3.6s ease-in-out infinite;
}
.reveal-art svg {
  max-height: 100%;
  animation: popBounce .45s var(--ease-spring) both;
}

/* A real photograph, when the family has supplied one. Circular with a thick
   ring in the letter's ink, so a snapshot of the actual puppy still sits in
   the same chunky geometric system as the placeholder silhouettes. */
.reveal-photo {
  height: 100%;
  max-height: 300px;
  max-width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: 50%;
  border: 10px solid var(--ink);
  box-shadow: var(--shadow-md);
  animation: popBounce .45s var(--ease-spring) both;
}

/* She covered the letter — the animal notices. */
@keyframes cheer {
  0%   { transform: scale(1) rotate(0) }
  25%  { transform: scale(1.12) rotate(-6deg) }
  50%  { transform: scale(1.12) rotate(6deg) }
  75%  { transform: scale(1.08) rotate(-4deg) }
  100% { transform: scale(1) rotate(0) }
}
.reveal-art.is-cheering { animation: cheer .9s var(--ease-spring); }

.reveal-word {
  flex: none;
  font-family: var(--font-heading);
  font-size: 54px;
  line-height: 1.05;
}

/* Counter-shapes (eyes, teeth, nostrils) take the panel tint, not white, so
   they read as cut-outs in the silhouette. */
.reveal .cutout { fill: var(--tint); }

/* ── NUMBERS ───────────────────────────────────────────────────────────── */

.num-row {
  flex: none;
  display: flex;
  gap: 10px;
}

.num-btn {
  flex: 1;
  height: 96px;
  border: 0;
  padding: 0;
  cursor: pointer;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  font-family: var(--font-heading);
  font-size: 44px;
  background: var(--color-surface);
  color: var(--ink);
  transition: background .25s ease, transform .3s var(--ease-spring);
}
.num-btn.is-on {
  background: var(--base);
  color: #ffffff;
  transform: scale(1.06);
}

.num-stage {
  flex: 1;
  min-height: 0;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 52px;
  padding: 20px 46px;
  background: var(--tint);
  transition: background .3s;
}

.num-face {
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
}

.num-big {
  font-family: var(--font-heading);
  font-size: 164px;
  line-height: 1;
  color: var(--ink);
  animation: numBounce .45s var(--ease-spring);
}

.num-word {
  font-family: var(--font-heading);
  font-size: 44px;
  line-height: 1.1;
}

.num-stars {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  justify-content: center;
  align-content: center;
  max-width: 440px;
}

/* Ten stars cascade in over about a second. */
.num-star {
  color: var(--ink);
  animation: popBounce .5s var(--ease-spring) both;
}

/* ── PAINT ─────────────────────────────────────────────────────────────── */

.paint {
  position: relative;
  gap: 16px;
}

.paint-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.paper {
  flex: 1;
  min-height: 0;
  width: 100%;
  display: block;
  border-radius: var(--radius-lg);
  background: #ffffff;
  box-shadow: var(--shadow-md);
  touch-action: none;
  cursor: crosshair;
}

.gallery {
  flex: none;
  height: 84px;
  display: flex;
  gap: 12px;
  align-items: center;
  overflow-x: auto;
  padding: 6px 2px 2px;
}

/* Every one of these carries an icon now: for a child who cannot read, the
   icon is the label, and the words are for the parent beside her. */
.keep-btn {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  flex: none;
  height: 62px;
  border: 0;
  cursor: pointer;
  background: var(--kid-sun);
  color: #ffffff;
  border-radius: 999px;
  padding: 0 24px;
  font-family: var(--font-heading);
  font-size: 20px;
  white-space: nowrap;
  box-shadow: var(--shadow-sm);
}
.keep-btn:hover, .keep-btn:active { background: var(--kid-sun-dark); }

.thumb-wrap { position: relative; flex: none; }

.thumb {
  width: 102px;
  height: 62px;
  border: 3px solid var(--color-neutral-300);
  border-radius: 12px;
  padding: 0;
  cursor: pointer;
  background: #ffffff;
  overflow: hidden;
  display: block;
}
.thumb span {
  display: block;
  width: 100%;
  height: 100%;
  background-size: cover;
  background-position: center;
}

/* A small badge, not a full-width button — deleting must not be a stray tap. */
.thumb-del {
  position: absolute;
  top: -7px;
  right: -7px;
  width: 28px;
  height: 28px;
  border: 0;
  border-radius: 50%;
  background: var(--color-neutral-700);
  color: #ffffff;
  cursor: pointer;
  display: grid;
  place-items: center;
  padding: 0;
}

/* The empty state points back at the button that fills the strip, rather than
   spelling it out to someone who cannot read it. */
.gallery-hint {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  color: var(--color-neutral-600);
  white-space: nowrap;
}
.gallery-hint-arrow {
  display: grid;
  place-items: center;
  color: var(--kid-sun-dark);
  animation: nudge 1.9s ease-in-out infinite;
}
@keyframes nudge {
  0%, 100% { transform: translateX(0) }
  50%      { transform: translateX(-6px) }
}

/* Every row is fixed-height so the column never collapses on a short viewport. */
.tools {
  width: 236px;
  flex: none;
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 2px;
}

.swatches {
  flex: none;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
  justify-items: center;
}

.swatch {
  width: 44px;
  height: 44px;
  border: 4px solid transparent;
  border-radius: 50%;
  cursor: pointer;
  padding: 0;
  transition: border-color .25s ease;
}
.swatch.is-on { border-color: var(--color-neutral-900); }

.swatch-more {
  grid-column: span 4;
  width: 100%;
  height: 44px;
  border: 4px solid transparent;
  border-radius: 999px;
  cursor: pointer;
  padding: 0;
  display: grid;
  place-items: center;
  background: conic-gradient(#d16b86, #d9a640, #8fa073, #4fa8b8, #9b6fb0, #d16b86);
  transition: transform .2s;
}
.swatch-more.is-on { border-color: var(--color-neutral-900); }
.swatch-more:hover { transform: scale(1.04); }
.swatch-more span {
  font-family: var(--font-heading);
  font-size: 17px;
  color: #ffffff;
  text-shadow: 0 1px 3px rgba(32, 30, 29, .45);
}

.sizes {
  flex: none;
  height: 46px;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
}

.brushes {
  flex: none;
  height: 54px;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
}

.tool-btn {
  height: 100%;
  min-height: 0;
  border: 3px solid transparent;
  border-radius: var(--radius-md);
  background: var(--color-surface);
  cursor: pointer;
  display: grid;
  place-items: center;
  padding: 0;
  color: var(--color-neutral-800);
}
.tool-btn.is-on { border-color: var(--color-accent); }

.size-dot {
  border-radius: 50%;
  background: var(--color-neutral-900);
}
.size-dot--s { width: 10px; height: 10px }
.size-dot--m { width: 20px; height: 20px }
.size-dot--l { width: 32px; height: 32px }

.replay-btn {
  flex: none;
  height: 54px;
  border: 0;
  cursor: pointer;
  background: var(--kid-teal);
  color: #ffffff;
  border-radius: 999px;
  font-family: var(--font-heading);
  font-size: 21px;
  white-space: nowrap;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
}
.replay-btn:hover { background: var(--kid-teal-dark); }

.oops-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  flex: none;
  height: 48px;
  border: 0;
  cursor: pointer;
  background: var(--color-surface);
  border-radius: 999px;
  font-family: var(--font-heading);
  font-size: 19px;
  color: var(--color-text);
  white-space: nowrap;
}
.oops-btn:hover { background: var(--color-neutral-300); }

.fresh-btn {
  flex: none;
  height: 44px;
  font-size: 16px;
  white-space: nowrap;
}

/* Colour picker — scoped to the paint panel, and closes on a backdrop tap so
   it can never trap her. */
.picker-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(32, 30, 29, .26);
  border-radius: var(--radius-lg);
  z-index: 10;
}

.picker {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  z-index: 11;
  background: var(--color-surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: 20px 22px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  animation: popIn .3s var(--ease-settle);
}

.picker-head {
  display: flex;
  align-items: center;
  gap: 24px;
}
.picker-title {
  font-family: var(--font-heading);
  font-size: 25px;
}
.picker-close {
  margin-left: auto;
  width: 44px;
  height: 44px;
  border: 0;
  border-radius: 50%;
  background: var(--color-neutral-200);
  cursor: pointer;
  display: grid;
  place-items: center;
  color: var(--color-text);
}
.picker-close:hover { background: var(--color-neutral-300); }

.picker-grid {
  display: grid;
  grid-template-columns: repeat(10, 42px);
  gap: 9px;
}

.picker-swatch {
  width: 42px;
  height: 42px;
  border: 3px solid rgba(32, 30, 29, .12);
  border-radius: 50%;
  cursor: pointer;
  padding: 0;
  transition: transform .15s;
}
.picker-swatch:hover { transform: scale(1.14); }
.picker-swatch.is-on { border-color: var(--color-neutral-900); }

/* ── ANIMALS ───────────────────────────────────────────────────────────── */

.zoo-chip-row {
  flex: none;
  min-height: 76px;
  display: flex;
  align-items: center;
}

.zoo-chip {
  display: inline-flex;
  align-items: baseline;
  border-radius: 999px;
  padding: 8px 40px;
  box-shadow: var(--shadow-sm);
  background: var(--tint);
  animation: popBounce .4s var(--ease-spring) both;
}
.zoo-chip span {
  font-family: var(--font-heading);
  font-size: 56px;
  line-height: 1;
}
.zoo-chip-initial { color: var(--ink); }
.zoo-chip-rest { color: var(--color-text); }

.zoo-hint {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  font-family: var(--font-heading);
  font-size: 38px;
  color: var(--color-neutral-600);
}

.zoo-grid {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: 1fr 1fr;
  gap: 16px;
}

.zoo-card {
  border: 0;
  cursor: pointer;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  display: grid;
  place-items: center;
  padding: 0;
  background: var(--tint);
  transition: transform .22s var(--ease-spring), background .2s;
}
.zoo-card.is-on {
  background: var(--base);
  transform: scale(1.05);
}
.zoo-card > span { color: var(--ink); }

/* Deliberately desynchronized — nothing on the grid ever pulses in unison. */
.zoo-card--cat     > span { animation: floaty 3.4s ease-in-out infinite }
.zoo-card--fish    > span { animation: wob 2.8s ease-in-out infinite }
.zoo-card--dino    > span { animation: floaty 4.2s ease-in-out .2s infinite }
.zoo-card--digger  > span { animation: wob 3.6s ease-in-out .4s infinite }
.zoo-card--octopus > span { animation: floaty 3.1s ease-in-out .6s infinite }
.zoo-card--crab    > span { animation: wob 2.1s ease-in-out infinite }

.zoo-card .cutout { fill: var(--tint); }
.zoo-card .blink { animation: blink 4.4s ease-in-out infinite; }
.zoo-card--octopus .blink { animation-duration: 5.2s; }
.zoo-card .wheel { animation: spin 3.4s linear infinite; }

/* ── MESSY ─────────────────────────────────────────────────────────────── */

.messy { gap: 12px; }

.tub {
  flex: 1;
  min-height: 0;
  width: 100%;
  display: block;
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  box-shadow: var(--shadow-md);
  touch-action: none;
  cursor: pointer;
}

.messy-bar {
  flex: none;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
}

.pour-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  border: 4px solid transparent;
  cursor: pointer;
  border-radius: 999px;
  padding: 10px 18px;
  font-family: var(--font-heading);
  font-size: 19px;
  white-space: nowrap;
  flex: none;
  background: var(--tint);
  transition: border-color .25s ease, transform .2s ease;
}
.pour-btn.is-on { border-color: var(--ink); }
.pour-btn > span:first-child { display: grid; place-items: center; color: var(--ink); }

.shake-btn {
  border: 0;
  cursor: pointer;
  background: var(--color-accent-500);
  color: var(--color-bg);
  border-radius: 999px;
  padding: 12px 24px;
  font-family: var(--font-heading);
  font-size: 21px;
  white-space: nowrap;
  margin-left: auto;
  flex: none;
  display: flex;
  align-items: center;
  gap: 8px;
}
.shake-btn:hover  { background: var(--color-accent-600); }
.shake-btn:active { background: var(--color-accent-700); }

/* Deliberately the smallest, dimmest control on the row. */
.tip-btn {
  font-size: 15px;
  padding: 11px 18px;
  white-space: nowrap;
  flex: none;
}

/* ── MORNING ───────────────────────────────────────────────────────────── */

.morning { gap: 20px; }

.morning-side {
  width: clamp(240px, 30vw, 340px);
  flex: none;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.morning-day {
  margin: 0 0 4px;
  font-size: 16px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--kid-plum-dark);
}

.morning-title {
  font-size: 46px;
  margin: 0;
  line-height: 1.03;
}

.weather-stage {
  flex: 1;
  min-height: 0;
  border-radius: var(--radius-lg);
  display: grid;
  place-items: center;
  box-shadow: var(--shadow-sm);
  background: var(--tint, var(--color-surface));
  color: var(--ink, var(--color-neutral-600));
  transition: background .3s;
}

.weather-ask {
  font-family: var(--font-heading);
  font-size: 26px;
  color: var(--color-neutral-600);
  text-align: center;
  padding: 0 30px;
}

/* The sun pops in, then breathes. */
.weather-art { animation: popBounce .45s var(--ease-spring) both; }
.weather-art--sun { animation: popBounce .45s var(--ease-spring) both, breathe 5s ease-in-out .5s infinite; }

.morning-main {
  flex: 1;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.morning-block {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.morning-label {
  font-family: var(--font-heading);
  font-size: 24px;
}

.morning-row {
  flex: 1;
  min-height: 0;
  display: flex;
  gap: 14px;
}

.round-btn {
  border: 0;
  cursor: pointer;
  flex: none;
  height: 100%;
  max-height: min(106px, 10.5vw);
  min-height: 54px;
  aspect-ratio: 1;
  border-radius: 50%;
  display: grid;
  place-items: center;
  box-shadow: var(--shadow-sm);
  background: var(--color-surface);
  color: var(--base);
  transition: background .3s ease;
}
.round-btn.is-on {
  background: var(--base);
  color: #ffffff;
}

.sticker-row { gap: 10px; }

.sticker {
  border: 2px dashed var(--color-neutral-400);
  cursor: pointer;
  flex: none;
  width: clamp(56px, 7vw, 88px);
  height: 100%;
  max-height: 112px;
  min-height: 58px;
  border-radius: var(--radius-md);
  background: transparent;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: 0;
  transition: background .3s ease;
}
.sticker.is-on { background: var(--tint); }

.sticker-star {
  color: var(--ink);
  opacity: 0;
  transform: scale(.35);
  transition: opacity .3s ease, transform .35s var(--ease-spring);
}
.sticker.is-on .sticker-star {
  opacity: 1;
  transform: scale(1);
}

.sticker-letter {
  font-family: var(--font-heading);
  font-size: 17px;
  color: var(--color-neutral-700);
}

/* ═══════════════════════════════════════════════════════════════════════════
   Screens

   The handoff specifies one device: an iPad on a table, landscape. That layout
   is the reference and stays untouched above 700px, because it is the spec and
   it is what was verified against the design.

   Below that, a phone is genuinely a different shape rather than a squeezed
   tablet — six tabs, a 236px tool column and ten number buttons do not survive
   a 375px width by shrinking — so the panels rearrange. Two axes matter and
   they are independent:

     • NARROW  (≤700px)  — a phone held upright. Columns become rows, side-by-
                           side panels stack, the name mark collapses to its
                           first tile to buy the tabs their width back.
     • SHORT   (≤540px tall) — a phone on its side, or a split view. Width is
                           fine here; height is the whole problem, so only the
                           fixed-height rows shrink and nothing rearranges.

   A phone in landscape is short but not narrow, and gets the tablet
   arrangement with shorter rows — which is the right answer: at 852px wide the
   paint sidebar fits perfectly well.

   Every tap target stays at or above 44px in both layouts. The paint swatches
   are the documented exception in the handoff and are 40px here.
   ═══════════════════════════════════════════════════════════════════════ */

/* Notch and home indicator. The ground runs under them (viewport-fit=cover),
   but nothing tappable may. */
.app {
  padding-top: max(16px, env(safe-area-inset-top));
  padding-right: max(22px, env(safe-area-inset-right));
  padding-bottom: max(20px, env(safe-area-inset-bottom));
  padding-left: max(22px, env(safe-area-inset-left));
}

/* ── Narrow: a phone held upright ──────────────────────────────────────── */

@media (max-width: 700px) {
  /* The 28px corner is proportioned for 88px tabs and full-width panels. On a
     47px tab it eats the whole shape and everything reads as a blob, so the
     radii scale with the layout rather than staying absolute. */
  :root {
    --radius-lg: 18px;
    --radius-md: 12px;
  }

  .app {
    gap: 10px;
    padding-top: max(12px, env(safe-area-inset-top));
    padding-right: max(12px, env(safe-area-inset-right));
    padding-bottom: max(12px, env(safe-area-inset-bottom));
    padding-left: max(12px, env(safe-area-inset-left));
  }

  /* The full name costs ~200px the six tabs cannot spare. Her initial still
     reads as hers and still opens the front door. */
  .logo { padding-right: 6px; }
  .logo-tile:nth-child(n + 2) { display: none; }
  .logo-tile:first-child {
    width: 40px;
    height: 46px;
    font-size: 25px;
    transform: none;
  }

  .tabs { gap: 6px; }
  .tab { height: 74px; gap: 1px; }
  /* Less headroom up here than on a tablet, so the active tab lifts less. */
  .tab.is-active { transform: translateY(-4px); }
  .tab svg { width: 30px; height: 30px; }
  .tab-glyph { font-size: 23px; }
  .tab-glyph--num { font-size: 21px; }
  .tab-label { font-size: 10px; letter-spacing: -0.02em; }

  /* ── LETTERS ── */
  .letter-row { gap: 8px; }
  .letter-btn { height: 68px; font-size: 36px; }
  /* Tracing and the reward stack rather than halving an already narrow width. */
  .letter-body { flex-direction: column; gap: 10px; }
  .trace, .reveal { flex: 1 1 0; min-height: 0; }
  .reveal { padding: 10px; gap: 4px; }
  .reveal-word { font-size: 34px; }
  .reveal-photo { border-width: 7px; max-height: 190px; }
  .trace-hint { font-size: 14px; left: 12px; top: 9px; }
  .trace-wipe { right: 8px; bottom: 8px; font-size: 13px; padding: 9px 15px; }

  /* ── NUMBERS ── */
  /* Ten across would be 30px each. Two rows of five keeps every one of them
     comfortably past the 44px floor. */
  .num-row { flex-wrap: wrap; gap: 8px; }
  .num-btn { flex: 1 1 calc(20% - 7px); height: 60px; font-size: 30px; }
  .num-stage { flex-direction: column; gap: 6px; padding: 12px; }
  .num-big { font-size: clamp(92px, 30vw, 150px); }
  .num-word { font-size: clamp(30px, 9vw, 44px); }
  .num-stars { gap: 10px; max-width: 100%; }
  .num-star svg { width: clamp(40px, 12vw, 58px); height: clamp(40px, 12vw, 58px); }

  /* ── PAINT ── */
  /* The paper takes the width; the tools become a fixed block beneath it. */
  .paint { flex-direction: column; gap: 8px; }
  .tools {
    width: auto;
    flex: none;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: stretch;
    gap: 7px;
    overflow: visible;
    padding: 0;
  }
  /* Swatches stretch to fill the row rather than sitting at a fixed size, so a
     larger phone gets larger targets for free. The handoff puts these at the
     44px floor and calls them the one exception; this keeps them as close to it
     as the width allows — 43px on a 393px screen, 47px on a 430px one. */
  .swatches {
    flex: 1 1 100%;
    grid-template-columns: repeat(8, 1fr);
    gap: 4px;
    justify-items: stretch;
  }
  .swatch {
    width: 100%;
    height: auto;
    aspect-ratio: 1;
    max-width: 52px;
    justify-self: center;
    border-width: 3px;
  }
  .swatch-more { grid-column: span 8; height: 44px; border-width: 3px; }
  .swatch-more span { font-size: 15px; }
  .sizes { flex: 1 1 120px; height: 44px; gap: 6px; }
  .brushes { flex: 2 1 170px; height: 44px; gap: 6px; }
  .replay-btn { flex: 1 1 100%; height: 46px; font-size: 18px; }
  .oops-btn { flex: 1 1 45%; height: 44px; font-size: 16px; }
  .fresh-btn { flex: 1 1 45%; height: 44px; font-size: 14px; }

  .gallery { height: 68px; gap: 8px; }
  .keep-btn { height: 52px; padding: 0 16px; font-size: 17px; gap: 6px; }
  .thumb { width: 84px; height: 52px; }
  .gallery-hint { font-size: 12px; }

  .picker { padding: 14px; gap: 10px; width: min(94vw, 420px); }
  .picker-grid { grid-template-columns: repeat(8, 1fr); gap: 6px; }
  .picker-swatch { width: 100%; aspect-ratio: 1; height: auto; }
  .picker-title { font-size: 20px; }

  /* ── ANIMALS ── */
  .zoo-chip-row { min-height: 54px; }
  .zoo-chip { padding: 6px 22px; }
  .zoo-chip span { font-size: 34px; }
  .zoo-hint { font-size: 24px; gap: 10px; }
  .zoo-hint svg { width: 26px; height: 26px; }
  /* Three columns would make each card narrower than its own artwork. */
  .zoo-grid {
    grid-template-columns: repeat(2, 1fr);
    grid-template-rows: repeat(3, 1fr);
    gap: 10px;
  }
  .zoo-card svg { width: 92px; height: 92px; }

  /* ── MESSY ── */
  .messy { gap: 8px; }
  .messy-bar { gap: 7px; }
  .pour-btn {
    flex: 1 1 calc(50% - 4px);
    justify-content: center;
    padding: 10px 8px;
    font-size: 16px;
    border-width: 3px;
  }
  .shake-btn { flex: 1 1 60%; margin-left: 0; justify-content: center; padding: 11px 14px; font-size: 18px; }
  .shake-btn svg { width: 24px; height: 24px; }
  .tip-btn { flex: 1 1 30%; justify-content: center; font-size: 13px; padding: 11px 10px; }

  /* ── MORNING ── */
  .morning { flex-direction: column; gap: 10px; }
  .morning-day { font-size: 13px; margin-bottom: 2px; }
  .morning-title { font-size: 28px; }
  .weather-ask { font-size: 17px; padding: 0 16px; }
  .morning-label { font-size: 18px; }
  .round-btn svg { width: 60%; height: 60%; }
  .sticker-star svg { width: 26px; height: 26px; }
  .sticker-letter { font-size: 13px; }

  /* Stacked, the three question blocks would each stretch to a third of a very
     tall column while their buttons stay capped, leaving three bands of dead
     ground. So the blocks hug their contents and the weather picture takes all
     the slack — it is the one thing here that is better bigger. */
  .morning-side { width: auto; flex: 1 1 auto; min-height: 0; gap: 8px; }
  /* Capped so the empty state does not read as a void; the slack that is left
     falls below the sticker strip, where it looks like margin. */
  .weather-stage { flex: 1 1 auto; min-height: 96px; max-height: 38vh; }
  .weather-stage svg { width: auto; height: min(100%, 150px); }
  .morning-main { flex: none; gap: 10px; }
  .morning-block { flex: none; gap: 4px; }
  .morning-row { flex: none; gap: 8px; height: auto; }
  .round-btn { height: auto; width: min(72px, 17vw); max-height: none; min-height: 48px; }
  .sticker { width: auto; flex: 1 1 0; height: auto; min-height: 52px; max-height: none; aspect-ratio: 3 / 4; }

  /* ── Splash ── */
  .splash { gap: 26px; }
  .splash-name { gap: 10px; }
  .splash-tile {
    width: clamp(52px, 16vw, 92px);
    height: clamp(66px, 20vw, 118px);
    font-size: clamp(34px, 11vw, 64px);
  }
  .splash-cta { padding: 13px 28px; }
  .splash-cta span { font-size: 21px; }
  .splash-blob { transform: scale(.6); }
}

/* Very narrow — the labels stop fitting under the icons, and the icon is the
   label anyway for the person using this. */
@media (max-width: 430px) {
  .tab-label { display: none; }
  .tab { gap: 0; }
  .tab svg { width: 34px; height: 34px; }
  .tab-glyph { font-size: 28px; }
  .tab-glyph--num { font-size: 25px; }
}

/* ── Short: a phone on its side, or a split view ───────────────────────────
   Width is not the problem here, so nothing rearranges — only the fixed-height
   rows give way, so the activity keeps as much of the screen as possible. */

@media (max-height: 540px) {
  :root { --radius-lg: 18px; }

  .app {
    gap: 8px;
    padding-top: max(8px, env(safe-area-inset-top));
    padding-bottom: max(8px, env(safe-area-inset-bottom));
  }

  .logo-tile { width: 26px; height: 34px; font-size: 17px; border-radius: 7px; }
  .tab { height: 54px; gap: 0; }
  .tab svg { width: 24px; height: 24px; }
  .tab-glyph { font-size: 19px; }
  .tab-glyph--num { font-size: 17px; }
  .tab-label { font-size: 10px; }
  .tab.is-active { transform: translateY(-4px); }

  .letter-btn { height: 52px; font-size: 30px; }
  .reveal-word { font-size: 28px; }
  .reveal-photo { max-height: 150px; border-width: 6px; }
  .trace-hint { font-size: 13px; }

  .num-btn { height: 50px; font-size: 26px; }
  .num-big { font-size: 78px; }
  .num-word { font-size: 26px; }
  .num-star svg { width: 34px; height: 34px; }
  .num-stars { gap: 8px; }

  .gallery { height: 58px; }
  .keep-btn { height: 46px; font-size: 16px; }
  .thumb { width: 76px; height: 46px; }
  .tools { width: 176px; gap: 5px; }
  .swatch { width: 34px; height: 34px; }
  .swatches { gap: 5px; }
  .swatch-more { height: 40px; }
  .sizes { height: 38px; }
  .brushes { height: 42px; }
  .replay-btn { height: 42px; font-size: 17px; }
  .oops-btn { height: 38px; font-size: 15px; }
  .fresh-btn { height: 36px; font-size: 13px; }
  .picker-grid { grid-template-columns: repeat(10, 30px); gap: 5px; }
  .picker-swatch { width: 30px; height: 30px; }

  .zoo-chip-row { min-height: 46px; }
  .zoo-chip span { font-size: 30px; }
  .zoo-hint { font-size: 22px; }
  .zoo-card svg { width: 78px; height: 78px; }

  .morning-title { font-size: 24px; }
  .morning-day { font-size: 12px; }
  .morning-label { font-size: 16px; }
  .round-btn { max-height: min(60px, 14vh); min-height: 44px; }
  .sticker { min-height: 44px; max-height: 68px; }
  .sticker-star svg { width: 22px; height: 22px; }
  .sticker-letter { font-size: 12px; }
  .weather-stage svg { width: auto; height: 108px; }

  .pour-btn { font-size: 15px; padding: 8px 12px; border-width: 3px; min-height: 44px; }
  .shake-btn { font-size: 16px; padding: 8px 16px; }
  .shake-btn svg { width: 22px; height: 22px; }
  .tip-btn { font-size: 13px; padding: 8px 12px; min-height: 44px; }

  .splash { gap: 20px; }
  .splash-tile {
    width: clamp(46px, 9vw, 92px);
    height: clamp(58px, 12vw, 118px);
    font-size: clamp(30px, 6vw, 64px);
  }
  .splash-cta { padding: 10px 26px; }
  .splash-cta span { font-size: 19px; }
}

/* Short but wide — a phone on its side. The tool column is 411px of controls
   trying to fit 315px of height, and it was scrolling, which the brief rules
   out. Width is the thing there is plenty of here, so the column gets wider
   and lays its controls out in rows instead. */
@media (max-height: 540px) and (min-width: 701px) {
  /* 372px wide is chosen, not guessed: eight swatch columns at 5px gaps put
     each swatch at 42px, and the remaining rows then fit 44px controls inside
     the 315px of height with room to spare. The paper still gets 456px. */
  .tools {
    width: 372px;
    max-width: 48%;
    flex-direction: row;
    flex-wrap: wrap;
    align-content: flex-start;
    gap: 6px;
    overflow: hidden;
  }
  .swatches {
    flex: 1 1 100%;
    grid-template-columns: repeat(8, 1fr);
    gap: 5px;
    justify-items: stretch;
  }
  .swatch {
    width: 100%;
    height: auto;
    aspect-ratio: 1;
    max-width: 46px;
    justify-self: center;
  }
  .swatch-more { grid-column: span 8; height: 44px; }
  .sizes { flex: 1 1 140px; height: 44px; }
  .brushes { flex: 1 1 180px; height: 44px; }
  .replay-btn { flex: 1 1 100%; height: 44px; }
  .oops-btn { flex: 1 1 46%; height: 44px; }
  .fresh-btn { flex: 1 1 40%; height: 44px; }
}

/* Narrow AND short at once — a small phone on its side. The tools cannot be a
   block beneath the paper here; there is no height for one. */
@media (max-width: 700px) and (max-height: 540px) {
  .paint { flex-direction: row; }
  .tools { flex: none; width: 150px; flex-direction: column; flex-wrap: nowrap; overflow-y: auto; }
  .swatches { flex: none; grid-template-columns: repeat(4, 1fr); }
  .swatch-more { grid-column: span 4; }
  .sizes, .brushes { flex: none; }
  .replay-btn, .oops-btn, .fresh-btn { flex: none; }
  .letter-body { flex-direction: row; }
  .zoo-grid { grid-template-columns: repeat(3, 1fr); grid-template-rows: repeat(2, 1fr); }
  .morning { flex-direction: row; }
  .morning-side { width: clamp(180px, 26vw, 260px); }
  .weather-stage { flex: 1; height: auto; }
  .num-stage { flex-direction: row; gap: 20px; }
}
