/* ============================================================================
   Deep water, with things that glow in it.
   ----------------------------------------------------------------------------
   The kids' screens are loud on purpose and the parent screens are quiet, but
   both come out of this one block — the parent register is the same tokens with
   the light turned off (see "the parent register" near the end).

   The idea worth keeping: down here it's dark, so anything that matters makes
   its own light, and each part of the app owns a colour. A ten-year-old finds
   the money screen by looking for the green, not by reading. That means a hue
   is a meaning, not a decoration — don't reuse one for a different area.

       cyan     video: channels, search, shorts, the day's clock
       magenta  the quiz
       lime     money
       amber    chores and anything waiting on a person
       violet   school — the part of the day that isn't theirs to spend

   Type is local on purpose. Every font here ships with iOS, because the phones
   are locked to an allowlist that doesn't include a font CDN — a webfont
   wouldn't load for the two people this is built for. SF Pro Rounded carries
   the personality, plain system sans carries the reading, and SF Mono carries
   every number that needs to line up.
   ========================================================================== */
:root {
  --abyss: #04121b;                      /* the water at the bottom */
  --bg: #071c26;
  --trench: #0a2431;                     /* opaque raised surface */
  --bg-raised: rgba(16, 52, 68, 0.66);   /* translucent: paired with backdrop-filter for sea glass */
  --line: rgba(234, 246, 247, 0.12);
  --text: #eaf7ff;
  --text-dim: #86b2c0;

  /* The five meanings. `-lit` is the same hue at low alpha, for the wash behind
     a glowing thing. */
  --time: #35e0ff;
  --time-lit: rgba(53, 224, 255, 0.16);
  --time-edge: rgba(53, 224, 255, 0.38);
  --time-edge-hi: rgba(53, 224, 255, 0.7);
  --quiz: #ff5ea8;
  --quiz-lit: rgba(255, 94, 168, 0.16);
  --quiz-edge: rgba(255, 94, 168, 0.38);
  --quiz-edge-hi: rgba(255, 94, 168, 0.7);
  --coin: #63eb7f;
  --coin-lit: rgba(99, 235, 127, 0.16);
  --coin-edge: rgba(99, 235, 127, 0.38);
  --coin-edge-hi: rgba(99, 235, 127, 0.7);
  --wait: #ffb454;
  --wait-lit: rgba(255, 180, 84, 0.16);
  --wait-edge: rgba(255, 180, 84, 0.3);
  --wait-edge-hi: rgba(255, 180, 84, 0.6);
  --school: #a78bfa;
  --school-lit: rgba(167, 139, 250, 0.16);
  --school-edge: rgba(167, 139, 250, 0.38);
  --school-edge-hi: rgba(167, 139, 250, 0.7);

  --accent: var(--time);                 /* kept: the whole app already asks for these two */
  --accent-2: #9defff;
  --good: var(--coin);
  --warn: var(--wait);
  --bad: #ff6b6b;
  --deep: var(--abyss);

  --font-body: -apple-system, BlinkMacSystemFont, "SF Pro Text", system-ui, sans-serif;
  --font-display: ui-rounded, "SF Pro Rounded", "Hiragino Maru Gothic ProN", var(--font-body);
  --font-data: ui-monospace, "SF Mono", ui-rounded, monospace;

  --radius: 20px;
  --radius-sm: 14px;
  --glass-blur: 16px;

  /* One shadow recipe, so a lit thing always looks lit the same way. */
  --lift: 0 10px 26px rgba(2, 10, 16, 0.5);
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  min-height: 100%;
  color: var(--text);
  font: 16px/1.45 var(--font-body);
  -webkit-font-smoothing: antialiased;
}

/* Rounded and heavy for anything that speaks. */
.title, .hello, .panel-title, .dest-name, .board-label, .sub-title { font-family: var(--font-display); }

/* The big numbers stay in the rounded face: SF Mono draws a slashed zero, which
   turns "30 minutes left" into "3Ø" at 62px. Tabular figures keep them steady
   as they count without borrowing the slash.  */
.minutes, .board-total, .earned-total, #locked-clock, .kid-clock {
  font-family: var(--font-display);
  font-variant-numeric: tabular-nums;
}

/* Mono is for the small numbers that have to line up in a column, where a
   monospaced digit earns its keep. */
.chore-timer, .standing .amount, .earned-rows .amount,
.money-chip, .count-chip, .dest-note, .row-item .amount, .earned-when {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}

/* Deep water, lighter near the surface. This lives on the root rather than on
   body: a fixed background only paints within its own element's box, and body
   is only as tall as its content — which left a hard horizontal seam under
   short screens. The root always covers the canvas. */
html {
  background:
    radial-gradient(120% 60% at 50% -10%, rgba(34, 195, 214, 0.10), transparent 60%),
    linear-gradient(180deg, #051620 0%, #08222d 55%, #0d3140 100%) fixed;
  background-color: var(--bg);
}

body {
  padding: max(20px, env(safe-area-inset-top)) 20px max(24px, env(safe-area-inset-bottom));
  display: flex;
  justify-content: center;
  min-height: 100vh;
  background: transparent;
  overflow-x: hidden;
}

#app {
  width: 100%;
  max-width: 480px;
  position: relative;
  z-index: 1; /* above the fixed wave layers */
}

.hidden { display: none !important; }

.screen {
  display: flex;
  flex-direction: column;
  gap: 18px;
  animation: fade 240ms ease both;
}

@keyframes fade { from { opacity: 0; transform: translateY(6px); } }

.title {
  margin: 8px 0 0;
  font-size: 30px;
  font-weight: 700;
  letter-spacing: -0.02em;
  text-align: center;
  /* A little shimmer on the one big heading everyone lands on first. */
  background: linear-gradient(90deg, var(--text) 20%, var(--accent-2) 55%, var(--accent) 85%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* Numbers inside a sentence keep the reading face — mono would slash the zeros
   in "0 of last 0" and make a phrase look like a serial number. Tabular figures
   are still worth having so the pill doesn't jitter as the count climbs. */
.time-pill { font-variant-numeric: tabular-nums; }

.subtle { color: var(--text-dim); font-size: 14px; margin: 0; }
.center { text-align: center; }
.push-right { margin-left: auto; }

/* ---------- sign-in ---------- */

.people {
  display: grid;
  /* Fixed at two columns: with four of us that's a tidy 2×2 at any width,
     instead of reflowing to 3-and-a-lonely-1 on a wider screen. */
  grid-template-columns: repeat(2, 1fr);
  gap: 14px;
}

.person {
  background: var(--bg-raised);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 22px 12px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  color: var(--text);
  font-size: 17px;
  font-weight: 600;
  cursor: pointer;
  transition: transform 120ms ease, border-color 120ms ease;
}

.person:active { transform: scale(0.97); }
.person:hover { border-color: var(--accent); }

.avatar {
  width: 58px;
  height: 58px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-size: 24px;
  font-weight: 700;
  color: #04222b;
  background: var(--accent);
  flex: none;
  position: relative;
  box-shadow: inset 0 0 0 2px rgba(234, 246, 247, 0.18), 0 2px 8px rgba(4, 18, 26, 0.35);
}

/* A porthole catches a little light. Uses ::before because ::after on an
   avatar is already the pencil badge on the editable ones — and it's absolutely
   positioned, so it stays out of the grid that centres the initial. */
.avatar::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: radial-gradient(58% 42% at 32% 22%, rgba(255, 255, 255, 0.3), transparent 70%);
  pointer-events: none;
}

.signin-step {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
}

/* ---------- home ---------- */

.home-header { display: flex; align-items: center; gap: 12px; }
.home-header .avatar { width: 44px; height: 44px; font-size: 18px; }
.hello { margin: 0; font-size: 20px; font-weight: 650; }

/* The gauge. It's the one thing on the screen that answers the only question a
   kid has when they open this, so it gets the size and the glow. */
.clock { position: relative; display: grid; place-items: center; margin: 0; }

/* Sized so the gauge, the leaderboard above it and the first destinations below
   all fit one screenful on the small phone. It was 268px and looked magnificent
   on its own, which is exactly the problem — it pushed everything you can
   actually tap below the fold. */
.ring { width: min(196px, 52vw); transform: rotate(-90deg); overflow: visible; }
.ring-track { fill: none; stroke: rgba(234, 247, 255, 0.07); stroke-width: 13; }
.ring-value {
  fill: none;
  stroke: var(--time);
  stroke-width: 13;
  stroke-linecap: round;
  filter: drop-shadow(0 0 10px rgba(53, 224, 255, 0.45));
  transition: stroke-dashoffset 600ms cubic-bezier(0.22, 1, 0.36, 1), stroke 300ms ease;
}

.clock-center { position: absolute; text-align: center; }
.minutes { margin: 0; font-size: 46px; font-weight: 700; letter-spacing: -0.03em; line-height: 1; }
.minutes-label {
  margin: 4px 0 0;
  color: var(--text-dim);
  font-size: 11px;
  font-family: var(--font-body);
  text-transform: uppercase;
  letter-spacing: 0.14em;
}

/* ---------- where you can go ---------- */

.dests { display: grid; grid-template-columns: repeat(2, 1fr); gap: 11px; }
.dest-wide { grid-column: 1 / -1; }

/* Each card is dark glass with its area's colour laid over it — a tinted wash,
   a matching hairline, and a bloom under it. `--hue` is set by the variant class
   below, so the card itself never names a colour. */
.dest {
  --hue: var(--time);
  --hue-lit: var(--time-lit);
  --hue-edge: var(--time-edge);
  --hue-edge-hi: var(--time-edge-hi);
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  min-height: 78px;
  padding: 13px 15px;
  border-radius: var(--radius);
  border: 1px solid var(--hue-edge);
  background:
    radial-gradient(120% 90% at 8% 0%, var(--hue-lit), transparent 62%),
    var(--trench);
  box-shadow: var(--lift);
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: transform 130ms ease, border-color 130ms ease, box-shadow 200ms ease;
}

.dest:active:not(:disabled) { transform: scale(0.975); }
.dest:hover:not(:disabled) {
  border-color: var(--hue-edge-hi);
  box-shadow: var(--lift), 0 0 0 1px var(--hue-edge);
}
.dest:focus-visible { outline: 2px solid var(--hue); outline-offset: 3px; }
.dest:disabled { opacity: 0.4; cursor: default; }

.dest-wide { min-height: 62px; flex-direction: row; align-items: center; gap: 12px; }

.dest-icon {
  font-size: 17px;
  line-height: 1;
  color: var(--hue);
  filter: drop-shadow(0 0 8px var(--hue-edge-hi));
}

.dest-name { font-size: 17px; font-weight: 700; letter-spacing: -0.01em; }
.dest-note {
  font-family: var(--font-data);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--hue);
}

.dest-quiz { --hue: var(--quiz); --hue-lit: var(--quiz-lit); --hue-edge: var(--quiz-edge); --hue-edge-hi: var(--quiz-edge-hi); }
.dest-coin { --hue: var(--coin); --hue-lit: var(--coin-lit); --hue-edge: var(--coin-edge); --hue-edge-hi: var(--coin-edge-hi); }

.dest-school { --hue: var(--school); --hue-lit: var(--school-lit); --hue-edge: var(--school-edge); --hue-edge-hi: var(--school-edge-hi); }

/* The two errands at the bottom. Same shape, no light — they don't compete with
   the four things worth opening. */
.dest-quiet {
  min-height: 58px;
  justify-content: center;
  border-color: var(--line);
  background: var(--trench);
  box-shadow: none;
}
.dest-quiet .dest-name { font-size: 15px; font-weight: 600; color: var(--text-dim); }
.dest-quiet:hover:not(:disabled) { border-color: var(--line); box-shadow: none; color: var(--text); }
.dest-quiet:hover:not(:disabled) .dest-name { color: var(--text); }

/* ---------- buttons ---------- */

.btn {
  font: inherit;
  font-weight: 600;
  border-radius: 14px;
  border: 1px solid transparent;
  padding: 15px 18px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  transition: transform 120ms ease;
}

.btn:disabled { opacity: 0.45; cursor: default; }
.btn:active:not(:disabled) { transform: scale(0.98); }

.btn-primary {
  background: linear-gradient(135deg, var(--accent-2), var(--accent) 60%, #1a94a8);
  color: #04222b;
  box-shadow: 0 6px 16px rgba(34, 195, 214, 0.28);
}

.btn-secondary {
  background: var(--bg-raised);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
  color: var(--text);
  border-color: var(--line);
}

.btn-ghost { background: transparent; color: var(--text); border-color: var(--line); }
.btn-link { background: none; border: none; color: var(--text-dim); padding: 8px; font-size: 14px; }

.error { color: var(--bad); font-size: 14px; text-align: center; margin: 0; }

/* ---------- parent ---------- */

.kid-cards { display: flex; flex-direction: column; gap: 12px; }

.kid-card {
  background: var(--bg-raised);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 16px;
  display: flex;
  align-items: center;
  gap: 14px;
}

.kid-card .avatar { width: 40px; height: 40px; font-size: 16px; }
.kid-card h2 { margin: 0; font-size: 17px; }
.kid-card .bar { height: 6px; border-radius: 3px; background: var(--bg); margin-top: 8px; overflow: hidden; }
.kid-card .bar span { display: block; height: 100%; background: var(--good); }

/* ---------- misc ---------- */

/* A spinning life-ring rather than a generic loading ring — same element,
   same class, just restyled. */
.spinner {
  width: 40px;
  height: 40px;
  margin: 60px auto;
  border-radius: 50%;
  position: relative;
  background: repeating-conic-gradient(var(--accent) 0deg 45deg, var(--text) 45deg 90deg);
  animation: spin 1.3s linear infinite;
}

.spinner::after {
  content: '';
  position: absolute;
  inset: 10px;
  border-radius: 50%;
  background: var(--bg);
}

/* The same spinner, sized to sit inside a panel rather than fill a screen. The
   parent home shows its layout at once and then fills three regions from three
   separate requests, so each one holds a spinner instead of a blank space. */
.spinner-sm {
  width: 22px;
  height: 22px;
  margin: 18px auto;
}

.spinner-sm::after { inset: 6px; }

/* Smaller again, to sit inline in a destination card's note while the School
   card waits for today's timetable. */
.spinner-dot {
  display: inline-block;
  width: 14px;
  height: 14px;
  margin: 0;
  vertical-align: -3px;
}
.spinner-dot::after { inset: 4px; }

@keyframes spin { to { transform: rotate(360deg); } }

/* Stop the animation for anyone who asks the system for less motion. The shape
   stays, so the region still reads as busy rather than empty. */
@media (prefers-reduced-motion: reduce) {
  .spinner, .spinner-sm { animation: none; }
}

/* ---------- search + player (phase 2) ---------- */

.topbar { display: flex; align-items: center; gap: 12px; }

.time-pill {
  margin-left: auto;
  background: var(--bg-raised);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 6px 14px;
  font-size: 14px;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
}

.time-pill.low { border-color: var(--warn); color: var(--warn); }
.time-pill.out { border-color: var(--bad); color: var(--bad); }

.search-form { display: flex; gap: 10px; }

.search-form input {
  flex: 1;
  min-width: 0;
  font: inherit;
  color: var(--text);
  background: var(--bg-raised);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 14px 16px;
  -webkit-appearance: none;
}

.search-form input:focus { outline: none; border-color: var(--accent); }

.results { display: flex; flex-direction: column; gap: 10px; }

.result {
  display: flex;
  gap: 12px;
  align-items: center;
  text-align: left;
  background: var(--bg-raised);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 10px;
  color: var(--text);
  font: inherit;
  cursor: pointer;
}

.result:active { transform: scale(0.99); }

.result img {
  width: 120px;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: 10px;
  background: #000;
  flex: none;
}

.result .meta { min-width: 0; }
.result .name {
  font-weight: 600;
  font-size: 15px;
  line-height: 1.25;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.result .who { color: var(--text-dim); font-size: 13px; margin-top: 4px; }

.stage { position: relative; }

.frame {
  position: relative;
  aspect-ratio: 16 / 9;
  background: #000;
  border-radius: 14px;
  overflow: hidden;
}

.frame iframe { width: 100%; height: 100%; border: 0; display: block; }

.overlay {
  position: absolute;
  inset: 0;
  background: rgba(4, 18, 26, 0.94);
  border-radius: 14px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 20px;
  text-align: center;
}

.overlay h2 { margin: 0; font-size: 24px; }

.video-title { margin: 0; font-size: 17px; font-weight: 650; line-height: 1.3; }

/* ---------- quiz (phase 3) ---------- */

.dots { display: flex; gap: 7px; justify-content: center; }

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

.dot.right { background: var(--good); border-color: var(--good); }
.dot.wrong { background: var(--bad); border-color: var(--bad); }

.quiz-card {
  background: var(--bg-raised);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 22px 18px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.prompt {
  margin: 0;
  font-size: 26px;
  font-weight: 650;
  line-height: 1.3;
  letter-spacing: -0.01em;
}

.quiz-form { display: flex; flex-direction: column; gap: 12px; }

.quiz-form input {
  font: inherit;
  font-size: 22px;
  font-weight: 650;
  text-align: center;
  color: var(--text);
  background: var(--bg);
  border: 2px solid var(--line);
  border-radius: 14px;
  padding: 14px 16px;
  -webkit-appearance: none;
}

.quiz-form input:focus { outline: none; border-color: var(--accent); }

/* The sign button sits to the LEFT of the box, where the minus sign goes when
   you write the number. The box keeps the rest of the width. */
.quiz-entry { display: flex; gap: 10px; align-items: stretch; }
.quiz-entry input { flex: 1; min-width: 0; }

.sign-btn {
  flex: none;
  width: 62px;
  padding: 0;
  font-size: 19px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

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

.choice {
  font: inherit;
  font-size: 19px;
  font-weight: 650;
  color: var(--text);
  background: var(--bg);
  border: 2px solid var(--line);
  border-radius: 14px;
  padding: 16px 10px;
  cursor: pointer;
}

.choice.picked { border-color: var(--accent); background: rgba(34, 195, 214, 0.18); }

.feedback {
  background: var(--bg-raised);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
  border: 1px solid var(--line);
  border-left: 4px solid var(--good);
  border-radius: 14px;
  padding: 18px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.feedback.miss { border-left-color: var(--bad); }
.feedback p { margin: 0; }
.feedback-headline { font-size: 18px; font-weight: 700; }
.feedback.miss .feedback-headline { color: var(--bad); }
.feedback:not(.miss) .feedback-headline { color: var(--good); }

.learn { color: var(--accent); font-size: 14px; text-decoration: none; font-weight: 600; }

.won {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  text-align: center;
}

.won-emoji { font-size: 56px; margin: 10px 0 0; }
.won h2 { margin: 0; font-size: 26px; }
.won .btn { width: 100%; }

#quiz.finished .topbar,
#quiz.finished .dots { display: none; }

/* ---------- parent detail (phase 4) ---------- */

.panel {
  background: var(--bg-raised);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.panel-title { margin: 0; font-size: 15px; font-weight: 700; }
.panel-title .subtle { font-weight: 500; }

.kid-clock { margin: 0; font-size: 22px; font-weight: 700; }

.grant-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
.grant-row .btn { padding: 12px 4px; font-size: 15px; }

.standards { display: flex; flex-direction: column; gap: 10px; }

.standard { display: grid; grid-template-columns: 1fr auto; gap: 4px 10px; align-items: baseline; }
.standard .name { font-size: 14px; font-weight: 600; }
.standard .code { color: var(--text-dim); font-size: 12px; font-variant-numeric: tabular-nums; }
.standard .score { font-size: 13px; font-weight: 650; font-variant-numeric: tabular-nums; }
.standard .track {
  grid-column: 1 / -1;
  height: 6px;
  border-radius: 3px;
  background: var(--bg);
  overflow: hidden;
}
.standard .track span { display: block; height: 100%; }
.standard.untested .score { color: var(--text-dim); font-weight: 500; }

.rows { display: flex; flex-direction: column; gap: 9px; }

.row-item {
  display: flex;
  gap: 10px;
  align-items: baseline;
  font-size: 14px;
  border-bottom: 1px solid var(--line);
  padding-bottom: 8px;
}
.rows .row-item:last-child { border-bottom: none; padding-bottom: 0; }
.row-item .what { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.row-item .when { color: var(--text-dim); font-size: 12px; white-space: nowrap; }
.row-item .tag { font-size: 12px; font-weight: 700; }
.row-item .tag.pass { color: var(--good); }
.row-item .tag.quit { color: var(--text-dim); }

.kid-card { cursor: pointer; text-align: left; width: 100%; font: inherit; color: var(--text); }
.kid-card:active { transform: scale(0.995); }

/* ---------- shorts (phase 5) ---------- */

.chips { display: flex; flex-wrap: wrap; gap: 8px; }

.chip {
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  background: var(--bg-raised);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 9px 14px;
  cursor: pointer;
}

.chip:active { transform: scale(0.97); }
.chip.on { border-color: var(--accent); color: var(--accent); }

.shorts-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }

.short {
  position: relative;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 12px;
  overflow: hidden;
  background: #000;
  cursor: pointer;
  /* 3:4, not the 9:16 of the video itself. YouTube only gives a landscape
     thumbnail for a short, so a full-height portrait tile cropped it to a sliver
     of the middle — and three rows of slivers pushed everything under the grid
     off the screen. This shows more of the picture in two thirds the height. */
  aspect-ratio: 3 / 4;
}

.short img { width: 100%; height: 100%; object-fit: cover; display: block; }

.short .len {
  position: absolute;
  right: 5px;
  bottom: 5px;
  background: rgba(0, 0, 0, 0.72);
  color: #fff;
  font-size: 11px;
  font-weight: 650;
  border-radius: 5px;
  padding: 1px 5px;
}

/* Shorts are vertical, so the stage flips with them. Height drives the box
   and width follows from the aspect ratio. */
#player.portrait .stage { display: flex; justify-content: center; }
#player.portrait .frame {
  aspect-ratio: 9 / 16;
  height: 62vh;
  width: auto;
  max-width: 100%;
  margin: 0 auto;
}

/* ---------- parent preview (test mode) ---------- */

.preview-banner {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--warn);
  color: #221603;
  border-radius: 12px;
  padding: 9px 12px;
  font-size: 14px;
  font-weight: 650;
  margin-bottom: 14px;
}

.preview-banner .btn {
  margin-left: auto;
  padding: 7px 12px;
  font-size: 13px;
  background: #221603;
  color: var(--warn);
  border-color: #221603;
}

/* ---------- approved sites + phone setup ---------- */

.webframe {
  height: 66vh;
  border: 1px solid var(--line);
  border-radius: 14px;
  overflow: hidden;
  background: #fff;
}
.webframe iframe { width: 100%; height: 100%; border: 0; display: block; }
/* The growth page is ours and renders dark, so no white flash behind it. */
.growthframe { height: 78vh; background: #0d0d0d; }

.site-row { display: flex; align-items: center; gap: 10px; width: 100%; }
.site-row .btn { padding: 8px 12px; font-size: 13px; }

.allowlist {
  margin: 0;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 12px;
  font-size: 13px;
  line-height: 1.7;
  overflow-x: auto;
  white-space: pre;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

.standard.locked { opacity: 0.45; }
.standard.mastered .name { color: var(--good); }

.badge {
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  border-radius: 999px;
  padding: 1px 7px;
  vertical-align: 1px;
}
.badge.done { background: rgba(45, 212, 165, 0.18); color: var(--good); }
.badge.locked { background: rgba(143, 184, 194, 0.15); color: var(--text-dim); }

/* ---------- version + what's new ---------- */

.version-tag {
  align-self: center;
  background: none;
  border: none;
  color: var(--text-dim);
  font: inherit;
  font-size: 12px;
  letter-spacing: 0.02em;
  padding: 6px 10px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.version-tag .vnum { font-variant-numeric: tabular-nums; }

/* A dot means there's something in the list you haven't read. */
.vdot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
}

.release {
  background: var(--bg-raised);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 16px;
  margin-bottom: 12px;
}

.release.current { border-color: var(--accent); }

.release h2 {
  margin: 0 0 4px;
  font-size: 17px;
  display: flex;
  align-items: baseline;
  gap: 8px;
}

.release .when { color: var(--text-dim); font-size: 13px; font-weight: 500; }
.release .now {
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--accent);
  border: 1px solid var(--accent);
  border-radius: 999px;
  padding: 1px 7px;
}
.release ul { margin: 10px 0 0; padding-left: 18px; }
.release li { font-size: 14px; line-height: 1.5; margin-bottom: 6px; }
.release li:last-child { margin-bottom: 0; }

/* ---------- profile pictures ---------- */

.avatar {
  background-size: cover;
  background-position: center;
  overflow: hidden;
}

/* A photo replaces the initial, so hide the letter when one is set. */
.avatar.has-photo { color: transparent; }

.avatar-edit {
  border: none;
  padding: 0;
  cursor: pointer;
  position: relative;
}

.avatar-edit::after {
  content: '✎';
  position: absolute;
  right: -2px;
  bottom: -2px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--bg-raised);
  border: 1px solid var(--line);
  color: var(--text-dim);
  font-size: 10px;
  display: grid;
  place-items: center;
}

.avatar-xl { width: 120px; height: 120px; font-size: 46px; }

.sheet {
  position: fixed;
  inset: 0;
  background: rgba(4, 15, 22, 0.78);
  display: grid;
  place-items: center;
  padding: 24px;
  z-index: 50;
}

.sheet-card {
  background: var(--bg-raised);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 24px 20px;
  width: 100%;
  max-width: 340px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
}

.sheet-card h2 { margin: 0; font-size: 20px; }
.sheet-card .btn { width: 100%; }

/* ---------- channels ---------- */

.channel-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
}

.channel-tile {
  background: none;
  border: none;
  padding: 0;
  color: var(--text);
  font: inherit;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7px;
}

.channel-pic {
  width: 100%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: var(--bg-raised) center/cover;
  border: 1px solid var(--line);
  display: grid;
  place-items: center;
  font-size: 22px;
  font-weight: 700;
  color: var(--text-dim);
  position: relative;
  box-shadow: inset 0 0 0 2px rgba(234, 246, 247, 0.12);
}

.channel-pic::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: radial-gradient(55% 40% at 32% 22%, rgba(255, 255, 255, 0.32), transparent 70%);
  pointer-events: none;
}

.channel-tile .cname {
  font-size: 12px;
  font-weight: 600;
  line-height: 1.25;
  text-align: center;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.channel-tile .unsynced { color: var(--warn); font-size: 10px; }

.channel-head { display: flex; align-items: center; gap: 12px; }
.channel-head .channel-pic { width: 52px; height: 52px; flex: none; }
.channel-head h2 { margin: 0; }

/* ---------- photo cropper ---------- */

/* The sheet centres its children, which makes them shrink-to-fit; the crop
   step has to claim the full width or the circle inside it has nothing to
   measure against. */
#avatar-crop { width: 100%; }

.crop-viewport {
  position: relative;
  /* Sized from its container, not from vw: viewport units are one more thing
     that can resolve to zero, and a zero-width crop circle is a bad failure. */
  width: 100%;
  max-width: 260px;
  aspect-ratio: 1;
  margin: 0 auto;
  border-radius: 50%;
  overflow: hidden;
  background: var(--bg);
  touch-action: none;          /* we handle drag and pinch ourselves */
  cursor: grab;
  user-select: none;
}

.crop-viewport:active { cursor: grabbing; }

.crop-image {
  position: absolute;
  top: 0;
  left: 0;
  transform-origin: 0 0;
  max-width: none;             /* the cropper sets the size explicitly */
  -webkit-user-drag: none;
}

/* A hairline so the edge of the circle is visible against a dark photo. */
.crop-ring {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  box-shadow: inset 0 0 0 2px rgba(234, 246, 247, 0.4);
  pointer-events: none;
}

.zoom-row {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  margin-top: 14px;
  color: var(--text-dim);
  font-size: 18px;
}

.zoom-row input[type='range'] {
  flex: 1;
  accent-color: var(--accent);
}

.hint {
  margin: 0;
  background: rgba(255, 180, 84, 0.14);
  border-left: 3px solid var(--warn);
  border-radius: 8px;
  padding: 10px 12px;
  font-size: 14px;
  line-height: 1.45;
}

#feedback-explanation { white-space: pre-line; }

/* ---------- sea ---------- */
/*
  Two fixed, tileable wave layers drifting behind every screen. Each is a
  single periodic curve (starts and ends at the same y) rendered as a
  repeating background, so a plain background-position animation loops
  seamlessly with no visible seam and no JS involved.
*/

body::before,
body::after {
  content: '';
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 0;
  pointer-events: none;
  background-repeat: repeat-x;
  background-position: left bottom;
}

/* preserveAspectRatio='none' matters: the default letterboxes the viewBox
   inside the background-size box, which leaves transparent gutters and the
   waves tile as disconnected blocks. */
body::before {
  height: 150px;
  opacity: 0.55;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 200' preserveAspectRatio='none'%3E%3Cpath d='M0,100 C240,40 480,160 720,100 C960,40 1200,160 1440,100 L1440,200 L0,200 Z' fill='%230e3a47'/%3E%3C/svg%3E");
  background-size: 1440px 100%;
  animation: drift-back 26s linear infinite;
}

body::after {
  height: 108px;
  opacity: 0.8;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 200' preserveAspectRatio='none'%3E%3Cpath d='M0,100 C240,40 480,160 720,100 C960,40 1200,160 1440,100 L1440,200 L0,200 Z' fill='%23145a68'/%3E%3C/svg%3E");
  background-size: 1440px 100%;
  animation: drift-front 15s linear infinite;
}

@keyframes drift-back { from { background-position-x: 0; } to { background-position-x: -1440px; } }
@keyframes drift-front { from { background-position-x: 0; } to { background-position-x: -1440px; } }

@media (prefers-reduced-motion: reduce) {
  body::before, body::after { animation: none; }
}

/* Setup guide: grouped by destination, so each part reads as its own errand. */

/* The search term is the actual instruction — iOS moves its menus, but search
   finds them on any version. Give it the weight of a step, not a footnote. */

/* ---------- board money ---------- */

.board {
  background: var(--bg-raised);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 22px 18px;
  text-align: center;
}

.board-label {
  margin: 0;
  font-size: 13px;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.board-total {
  margin: 4px 0 6px;
  font-size: 46px;
  font-weight: 720;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--good);
}

/* How many chores are waiting on you, in the panel heading. Warm rather than
   green: it's a to-do, not a total. */
.count-chip {
  font-size: 13px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--warn);
  background: rgba(255, 180, 84, 0.16);
  border-radius: 999px;
  padding: 2px 9px;
  vertical-align: 1px;
}

.money-row { display: flex; align-items: center; gap: 10px; width: 100%; }
.money-row .btn { padding: 8px 12px; font-size: 13px; }
.money-row .amount { font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
.money-row .amount.plus { color: var(--good); }
.money-row .amount.minus { color: var(--bad); }

.chore-pending { color: var(--warn); font-size: 12px; }
.chore-denied { color: var(--text-dim); font-size: 12px; }

/* Chore rows carry buttons, so the description needs to wrap rather than be
   clipped to an ellipsis — "Unload…" tells a parent nothing. It takes a full
   row of its own, which keeps the amount and both buttons together on the next
   line instead of stranding one of them. */
.money-row { flex-wrap: wrap; align-items: center; }
.money-row .what {
  flex: 1 1 100%;
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
}

.wc-toggle {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 10px 0 14px;
  font-size: 14px;
  cursor: pointer;
}
.wc-toggle input { width: 20px; height: 20px; accent-color: var(--good); }

/* ---------- the daily check-in gate ---------- */

.wc-steps {
  margin: 12px 0 4px;
  padding-left: 20px;
  font-size: 14px;
  line-height: 1.6;
}

#wc-amount {
  width: 100%;
  font: inherit;
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  font-size: 20px;
  color: var(--text);
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 14px 16px;
  -webkit-appearance: none;
}
#wc-amount:focus { outline: none; border-color: var(--accent); }

#wc-pick { width: 100%; }

/* Capped rather than full height: a phone screenshot is tall and portrait, and
   left alone it pushed Done off the bottom of the screen. */
.wc-preview {
  display: block;
  max-height: 220px;
  margin: 12px auto 0;
  border-radius: 14px;
  border: 1px solid var(--line);
}

.wc-done { width: 100%; margin-top: 16px; }

#wc-school { width: 100%; margin-top: 4px; }

/* ---------- the Apple Wallet figure, on a kid's page ---------- */

/* The current number, stated once and plainly, before either box that changes
   it. A parent should never edit a figure they cannot see. */
.wallet-now {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px 10px;
  margin: 12px 0 16px;
  padding: 12px 14px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 14px;
}
.wallet-now-label {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-dim);
}
.wallet-now-amount {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  font-size: 22px;
  font-weight: 700;
  color: var(--good);
}
.wallet-now-amount.stale { color: var(--text-dim); }
.wallet-now-when { flex: 1 1 100%; font-size: 12px; color: var(--text-dim); }

/* Each box says what it is FOR, in the words a parent would use out loud.
   "Hand money over" and "Their checking" were our names for them, not hers. */
.do-label {
  margin: 16px 0 6px;
  font-size: 14px;
  font-weight: 700;
}
.do-help { margin: 6px 0 0; }

/* ---------- the parent's summary card ---------- */

/* One card per kid, and the whole house reads off two of them. */
/* The face lines up with the name, not with the middle of a tall card. Centred
   was right when the card was three short lines; it now carries two balances
   and a Friday, and the avatar drifted down beside the money. */
.kid-summary { align-items: flex-start; }
.kid-summary .avatar { margin-top: 2px; }

.kid-summary h2 { display: flex; align-items: baseline; flex-wrap: wrap; gap: 8px; }

/* What is waiting on the parent, on the card that owns it. */
.ks-waiting { color: var(--warn); background: rgba(255, 180, 84, 0.16); }

.ks-pots { display: flex; gap: 18px; margin: 8px 0 4px; }
.ks-pot { display: flex; flex-direction: column; gap: 1px; }

.ks-label {
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-dim);
}

.ks-amount {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  font-size: 19px;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--good);
}
/* A figure nobody has checked in a week is still shown, just not in the colour
   that means "this is right". */
.ks-amount.stale { color: var(--text-dim); }

.ks-friday {
  margin: 0 0 6px;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--text-dim);
}
.ks-friday-cut { color: var(--bad); }
.ks-friday:empty { display: none; }

/* ---------- how to actually send it ---------- */

/* ---------- the home headline ---------- */

/* Two pots, side by side, first thing on the screen. This is what a kid opens
   the app to find out. */
.home-wallet {
  display: flex;
  align-items: stretch;
  gap: 14px;
  width: 100%;
  text-align: left;
  font: inherit;
  color: var(--text);
  background: var(--bg-raised);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
  border: 1px solid var(--line);
  border-radius: 18px;
  padding: 16px;
  margin-bottom: 6px;
  cursor: pointer;
}
.home-wallet:active { transform: scale(0.995); }

/* Equal halves, so neither number looks like the important one by accident. */
.hw-pot { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; gap: 2px; }

.hw-rule { flex: 0 0 1px; background: var(--line); }

.hw-label {
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-dim);
}

.hw-amount {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  font-size: 26px;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--good);
  line-height: 1.1;
}
.hw-amount.stale { color: var(--text-dim); }

/* Where each pot actually lives, on its own line under the name.
   "Checking" is a word a kid has to be taught; "Apple Wallet" is an icon they
   already tap. Both pots carry the line, not just checking, for two reasons:
   it keeps the two amounts on the same baseline, and naming both halves is
   what explains the model -- one pot is in here, the other is on your phone. */
.hw-where {
  font-size: 11px;
  line-height: 1.2;
  color: var(--text-dim);
  margin-bottom: 3px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.hw-note { font-size: 12px; color: var(--text-dim); }
/* A Friday that pays nothing is the one note that should not read as good news. */
.hw-note-bad { color: var(--bad); font-weight: 700; }

.hw-total { margin: 0 0 14px; }

/* ---------- checking, the other pot ---------- */

/* Deliberately quieter than the savings board above it. Savings is the number
   this app is responsible for; checking is a note about somebody else's. */
.checking { border-color: rgba(122, 214, 176, 0.20); }

.checking-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 4px;
}

.checking-label { font-size: 15px; font-weight: 700; }

.checking-total {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  font-size: 22px;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--good);
  white-space: nowrap;
}

/* A week-old figure is shown greyed rather than hidden. Hiding it would lose
   the only number anybody has; colouring it says do not trust this. */
.checking-total.stale { color: var(--text-dim); }

#checking-when { margin: 0 0 12px; }
#checking-total-line { margin-top: 12px; font-weight: 700; color: var(--text); }

/* ---------- phones, sign-ins, and cashing out ---------- */

.panel-sub {
  margin: 18px 0 4px;
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-dim);
}

/* A browser that has signed in as both a kid and a parent. This is the one
   row a parent is looking for, so it gets the red treatment the missed-chore
   banner uses rather than blending into a list of four phones. */
.device-mixed {
  background: rgba(255, 107, 107, 0.10);
  border: 1px solid rgba(255, 107, 107, 0.45);
  border-radius: 12px;
  padding: 10px 12px;
}
.device-flag {
  display: block;
  margin-top: 2px;
  font-size: 12px;
  font-weight: 700;
  color: var(--bad);
  white-space: normal;
}

/* Both lists carry buttons, so their text cells wrap rather than clip. */
#device-list .what, #revoke-list .what, #payout-list .what {
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
}
#device-list .chore-pending { display: block; color: var(--text-dim); }

/* Two accounts here are both called "Dad". The address is what tells them
   apart, so it is not optional detail. */
.account-email {
  display: block;
  margin-top: 2px;
  font-size: 12px;
  color: var(--text-dim);
  word-break: break-all;
}

/* The kid's cash-out history. A payout leaves the board, so it reads as a
   subtraction even though it is the good outcome. */
#cashout-history .amount.minus { color: var(--text-dim); }
#cashout-cancel { margin-top: 10px; }
#cashout-form.hidden { display: none; }

/* ---------- a missed chore, where nobody can miss it ---------- */

/* The one red thing on a kid's home screen, above the leaderboard and the
   clock. Red is reserved: nothing else on this screen uses it, so the banner
   reads as an exception rather than as decoration. It is a button, and it
   opens the money screen where the individual lines are. */
.missed-banner {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  width: 100%;
  text-align: left;
  font: inherit;
  color: var(--text);
  background: rgba(255, 107, 107, 0.13);
  border: 1px solid rgba(255, 107, 107, 0.45);
  border-radius: 16px;
  padding: 14px 16px;
  margin-bottom: 14px;
  cursor: pointer;
}
.missed-banner:active { transform: scale(0.995); }

/* A filled circle, not an emoji. An emoji renders at a different size and
   weight on every device, and this one has to look deliberate. */
.missed-mark {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 999px;
  background: var(--bad);
  color: #2a0b0b;
  font-size: 18px;
  font-weight: 800;
  line-height: 1;
}

.missed-text { flex: 1; min-width: 0; }

.missed-headline {
  display: block;
  font-size: 15px;
  font-weight: 700;
  color: var(--bad);
}

/* The reasons, clipped to one line. The whole list is one tap away, and a
   banner that grows to eight lines is a panel, not a banner. */
.missed-detail {
  display: block;
  margin-top: 2px;
  font-size: 13px;
  color: var(--text-dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The arithmetic, spelled out. It wraps freely: this is the line a kid reads
   twice, and clipping it would hide the number that matters. */
.missed-friday {
  display: block;
  margin-top: 3px;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

/* The parent's version of the same news: a red chip beside Board money, and a
   red Friday line under whichever kid it belongs to. */
.count-chip.count-bad { color: var(--bad); background: rgba(255, 107, 107, 0.16); }

/* One tap per job. Ghost buttons on purpose — eight filled buttons would
   outshout the Take off button that ends the job. */
.allow-quick-label { margin: 0 0 8px; }
.allow-quick {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  margin-bottom: 14px;
}
.allow-quick .missed-pick {
  padding: 9px 13px;
  font-size: 14px;
  min-height: 40px;
  border-color: rgba(255, 107, 107, 0.35);
}
.allow-quick .missed-pick:active { background: rgba(255, 107, 107, 0.16); }
.allow-quick .missed-pick:disabled { opacity: 0.45; }

/* ---------- the Friday that has not happened yet ---------- */

/* A promise, not a record, so it is drawn differently from the history below
   it: a coin-tinted edge and a number big enough to read from across a room.
   Everything else on this screen is money they already have. */
.upcoming { border-color: rgba(255, 199, 92, 0.28); }

.upcoming-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 10px;
}

.upcoming-when { font-size: 15px; font-weight: 700; }

/* The old $20, struck through, only appears once something came off it. It sits
   next to the new number rather than replacing it, because the gap between the
   two is the whole message. */
.upcoming-base {
  margin-left: 8px;
  color: var(--text-dim);
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  font-size: 14px;
}

.upcoming-net {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  font-size: 24px;
  font-weight: 700;
  letter-spacing: -0.02em;
  white-space: nowrap;
}
.upcoming-net.plus { color: var(--good); }
.upcoming-net.minus { color: var(--text-dim); }

/* A deduction is the one number on this screen that has to sting a little. */
#upcoming-taken .amount.minus { color: var(--bad); font-weight: 700; }

/* The reason has to wrap. Every other .row-item clips to an ellipsis, which is
   fine for a chore the kid already knows they did — it is not fine here, where
   the sentence is the only reason a dollar is missing. */
#upcoming-taken .what {
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
}

#upcoming-note { margin: 10px 0 0; }

/* Parent: amount, then what was missed, then the button. The reason gets its
   own full-width line — "Never took the trash out" does not fit beside a
   number and a button at 375px, and truncating the reason defeats it. */
.allow-form {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 12px;
}
.allow-form input {
  font: inherit;
  color: var(--text);
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 14px 16px;
  -webkit-appearance: none;
}
.allow-form input:focus { outline: none; border-color: var(--accent); }
.allow-form #allow-cents {
  width: 96px;
  flex: 0 0 auto;
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
}
/* Reason first, on its own full-width line, then the amount and the button
   beside it. A parent thinks "he never took the trash out" before they think
   "that is two dollars", and the reason is what the kid reads afterwards. */
.allow-form #allow-what { flex: 1 1 100%; min-width: 0; order: -1; }
.allow-form button { flex: 1 1 auto; }

/* The parent balance list carries two numbers per kid — what is on the board
   now, and what Friday will add. The second needs its own line, so this cell
   has to wrap where every other .row-item .what clips to an ellipsis. */
#parent-money .what { white-space: normal; overflow: visible; text-overflow: clip; }
#parent-money .friday {
  display: block;
  margin-top: 2px;
  color: var(--text-dim);
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  font-size: 12px;
}

/* ---------- picking a chore ---------- */

/* Two across on a phone. Wide enough for "Clean the dining room" on one line at
   the SE's 375px, which is the narrowest screen in the house. */
.chore-picks {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 9px;
}

.chore-pick {
  display: flex;
  flex-direction: column;
  gap: 3px;
  text-align: left;
  padding: 12px;
  border-radius: 14px;
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, 0.04);
  color: var(--text);
  font: inherit;
  cursor: pointer;
  transition: border-color 0.15s ease, transform 0.1s ease;
}

.chore-pick:active { transform: scale(0.98); }
.chore-pick:hover { border-color: var(--accent); }
.chore-pick-title { font-size: 14px; font-weight: 650; line-height: 1.25; }
.chore-pick-meta { font-size: 12px; color: var(--text-dim); }

/* The two feed controls, side by side above the grid. */
.shorts-bar { display: flex; gap: 9px; }
.shorts-bar .btn { flex: 1; }

/* ---------- locked out ---------- */

/* The countdown is the only thing on the screen, so it's centred and amber
   rather than the green that means "you earned this". */
#locked-clock {
  text-align: center;
  color: var(--warn);
  margin: 8px 0 18px;
}

/* The question a parent is reading needs the full width — squeezed into a third
   of the row it wraps every two words. */
#kid-identity .row-item { flex-wrap: wrap; }
#kid-identity .what { flex: 1 1 100%; white-space: normal; overflow: visible; text-overflow: clip; }

/* ---------- the earnings log ---------- */

.earned-total {
  margin: 2px 0 0;
  text-align: center;
  font-size: 34px;
  font-weight: 720;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--good);
}

/* Month/day on the left at a fixed width so the bars all start on the same
   line — ragged bar starts make months look different sizes when they aren't. */
.earned-when { flex: none !important; width: 56px; font-variant-numeric: tabular-nums; }

.earned-bar {
  flex: 1;
  height: 8px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.07);
  overflow: hidden;
}

.earned-bar > span {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--accent), var(--good));
}

.earned-rows .row-item { gap: 10px; align-items: center; }
.earned-rows .amount { font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
.earned-rows .amount.plus { color: var(--good); }

.sub-title {
  margin: 16px 0 0;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-dim);
}

.standing {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 9px 0;
  border-bottom: 1px solid var(--line);
}
.standing:last-child { border-bottom: none; }

.standing-place { width: 22px; font-size: 17px; text-align: center; }
.standing .avatar { width: 30px; height: 30px; font-size: 14px; flex: none; }
.standing-name { font-weight: 650; white-space: nowrap; }
.standing .amount { font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
.standing .amount.plus { color: var(--good); }

/* Your own row, so you can find yourself without reading the names. */
.standing-me .standing-name { color: var(--accent); }

/* Who you're handing it to. A face and a name, because at ten and twelve the
   face is what they read first. */
.give-who { display: flex; flex-wrap: wrap; gap: 9px; }

.give-kid {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 8px 14px 8px 8px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, 0.04);
  color: var(--text);
  font: inherit;
  font-weight: 650;
  cursor: pointer;
}

.give-kid .avatar { width: 30px; height: 30px; font-size: 14px; }
.give-kid.picked { border-color: var(--accent); color: var(--accent); }

.chore-other { margin-top: 4px; }
.chore-other summary {
  font-size: 13px;
  color: var(--text-dim);
  cursor: pointer;
  padding: 6px 0;
}
.chore-other[open] summary { margin-bottom: 8px; }

.chore-pay {
  margin: 0;
  font-size: 30px;
  font-weight: 720;
  font-variant-numeric: tabular-nums;
  color: var(--good);
}

/* The checklist is the contract: this is what makes it a dollar. Left-aligned
   inside a centring sheet, because a bulleted list read down a centre line is
   miserable. */
.chore-details {
  align-self: stretch;
  margin: 0;
  padding-left: 20px;
  display: flex;
  flex-direction: column;
  gap: 5px;
  font-size: 14px;
  line-height: 1.35;
  color: var(--text);
}

.stepper {
  display: flex;
  align-items: center;
  gap: 10px;
  align-self: stretch;
}
.stepper-label { flex: 1; font-size: 14px; color: var(--text-dim); }
.sheet-card .stepper-btn {
  width: 40px;
  flex: none;
  padding: 8px 0;
  font-size: 18px;
  line-height: 1;
}
.stepper-count {
  min-width: 22px;
  text-align: center;
  font-size: 18px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.chore-timer-note {
  margin: 0;
  font-size: 13px;
  line-height: 1.4;
  color: var(--text-dim);
  text-align: center;
}

/* A chore on the clock: countdown on one line, the way out beside it. */
.chore-row { flex-wrap: wrap; align-items: center; gap: 8px; }
.chore-row .what { flex: 1 1 100%; }
.chore-row .chore-done { margin-left: auto; padding: 7px 12px; font-size: 13px; }
.chore-photo { padding: 7px 12px; font-size: 13px; }
.chore-row .chore-photo { margin-left: auto; }
.chore-row .chore-done + .chore-photo { margin-left: 0; }
.money-row .chore-photo:disabled { opacity: 0.45; }

/* The photo itself, as big as the sheet allows. */
.photo-card { max-width: 480px; }
.photo-card img {
  width: 100%;
  border-radius: 14px;
  border: 1px solid var(--line);
  background: var(--bg);
}

.chore-timer {
  font-size: 20px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--accent);
}

/* Time's up reads as words, not digits, so it can't be mistaken for the clock
   still running. */
.chore-timer.chore-timer-up {
  font-size: 13px;
  font-weight: 650;
  color: var(--good);
}

/* The swap button stays put whether or not it's available — its disabled state
   is the explanation, so it shouldn't move or vanish. */
#quiz-skip { font-size: 14px; padding: 11px 14px; }
#quiz-skip:disabled { opacity: 0.4; }

/* ============================================================================
   The parent register
   ----------------------------------------------------------------------------
   Same tokens, light off. The kids' screens glow because they're a place to
   spend time in; these two screens are a place to read a number and make a
   decision, so the colour drops to where it carries meaning — a balance, an
   amount, a countdown — and everything else goes to hairlines and mono.

   Scoped by screen id rather than by a body class so it can't leak: a kid's
   screen has no way to end up inside #parent or #kid.
   ========================================================================== */
#parent .panel,
#kid .panel {
  background: rgba(10, 36, 49, 0.55);
  border-color: var(--line);
  box-shadow: none;
}

#parent .panel-title,
#kid .panel-title {
  font-family: var(--font-body);
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text-dim);
}

/* Numbers a parent scans: mono, tight, no glow. */
#parent .amount,
#kid .amount,
#kid .kid-clock,
#kid #kid-money {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
}

#kid .kid-clock { font-size: 26px; font-weight: 700; letter-spacing: -0.02em; }

/* The kid cards on the parent home are navigation, not destinations — one
   hairline each, no tint. */
#parent .kid-card {
  background: rgba(10, 36, 49, 0.55);
  box-shadow: none;
}

/* Row rhythm: a parent reads down a list of these, so the dividers do the work
   and nothing is emphasised except the decision. */
#parent .row-item,
#kid .row-item { font-size: 15px; }

/* ---------- quality floor ---------- */

/* Keyboard focus stays visible everywhere, not just on the cards. */
.btn:focus-visible,
.chip:focus-visible,
.choice:focus-visible,
.person:focus-visible,
.kid-card:focus-visible,
.chore-pick:focus-visible,
.give-kid:focus-visible {
  outline: 2px solid var(--time);
  outline-offset: 3px;
}

/* Everything that moves here is decoration on top of something already legible,
   so honouring the setting costs nothing. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .wave, .wave-back { animation: none !important; }
}

/* ---------- the quiz wears its own colour ---------- */

/* The home screen promises magenta for the quiz, so the quiz has to be magenta
   when you get there — otherwise the colour is decoration rather than a map.
   Right and wrong are the exception: green-for-correct is a convention older and
   stronger than this palette, so the dots keep it. Don't "fix" that for
   consistency.  */
#quiz .btn-primary {
  background: linear-gradient(135deg, #ff8cc2, var(--quiz) 60%, #d63d84);
  box-shadow: 0 6px 16px rgba(255, 94, 168, 0.28);
}

#quiz .time-pill {
  border-color: var(--quiz-edge-hi);
  color: #ffc4de;
}

#quiz .quiz-card {
  border-color: var(--quiz-edge);
  background:
    radial-gradient(120% 80% at 6% 0%, var(--quiz-lit), transparent 58%),
    var(--bg-raised);
}

#quiz .choice.picked {
  border-color: var(--quiz);
  color: #ffd0e6;
  background: var(--quiz-lit);
}

#quiz-input:focus { border-color: var(--quiz); }

/* Board money is the green room, chores the amber one — same idea. */
#money .board-total { color: var(--coin); }
#money .btn-primary {
  background: linear-gradient(135deg, #a8f5b8, var(--coin) 60%, #34c455);
  box-shadow: 0 6px 16px rgba(99, 235, 127, 0.26);
}

/* Chores are the amber corner. Kept to a hairline and the price rather than a
   full wash: there are eight of these in a grid, and eight glowing cards would
   shout over the balance above them. */
.chore-pick {
  border-color: var(--wait-edge);
  background:
    radial-gradient(120% 90% at 8% 0%, rgba(255, 180, 84, 0.07), transparent 60%),
    rgba(255, 255, 255, 0.03);
}
.chore-pick:hover { border-color: var(--wait-edge-hi); }
.chore-pick-meta { color: var(--wait); opacity: 0.85; }

/* A parent's primary action doesn't need to glow — it's the only button in the
   row that's filled, which is emphasis enough on a screen you read rather than
   play in. */
#parent .btn-primary,
#kid .btn-primary {
  background: #1f6f80;
  color: var(--text);
  box-shadow: none;
}
#parent .btn-primary:hover,
#kid .btn-primary:hover { background: #24808f; }

/* ---------- thumbs on a short ---------- */

/* Thumbs and "next" are one row of controls, so they sit on one line: the two
   thumbs at their own width and the skip taking whatever's left.
   The row wraps rather than squeezing. Fitting three controls across 280px of
   SE screen means one of them ends up too small to hit, so on a narrow phone
   "Next short" drops to its own full-width line instead. */
.vote-row { display: flex; flex-wrap: wrap; align-items: stretch; gap: 10px; }
.vote-row #next-short { flex: 1 1 136px; margin: 0; }

.vote {
  /* 78px is the floor, not the size: when the row wraps and the two thumbs have
     a line to themselves, they take half each rather than huddling on the left. */
  flex: 1 1 78px;
  min-width: 78px;
  min-height: 56px;
  display: grid;
  place-items: center;
  font-size: 26px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, 0.04);
  cursor: pointer;
  transition: transform 120ms ease, border-color 120ms ease, background 160ms ease;
}

.vote:active { transform: scale(0.94); }

/* Voted state is the button itself lighting up rather than a tick somewhere
   else, so the thing you pressed is the thing that answers. Up borrows the
   video cyan; down goes grey, because "no thanks" isn't an error. */
#vote-up.on {
  border-color: var(--time-edge-hi);
  background: var(--time-lit);
}
#vote-down.on {
  border-color: rgba(234, 247, 255, 0.4);
  background: rgba(234, 247, 255, 0.08);
}

.vote-note { margin: 0; font-size: 13px; color: var(--text-dim); }

/* ---------- control sizing ---------- */

/* Kid thumbs, not cursors. Every control on a kid screen clears 48px of height,
   which is the size a ten-year-old actually hits on the first try. Tidying the
   proportions of this row cost it that, and the kids noticed before I did — so
   sizing here only ever goes up, and a control that won't fit at full size gets
   its own line rather than a trim. */

/* A submit button next to a full-width field was ending up a cramped square:
   "Go" is two letters, so horizontal padding alone gave it no width. A minimum
   width makes it read as a button, and matching the field's corner and height
   makes the pair look like one control rather than two. */
.search-form .btn { min-width: 104px; flex: none; }
.search-form input,
.search-form .btn { border-radius: var(--radius-sm); padding-top: 16px; padding-bottom: 16px; }

/* Topic chips are a row of things to tap, so they're sized to be tapped. They
   end up close to the buttons above them in height; that's the cost of being
   hittable, and it's the right trade on a phone. */
.chip { font-size: 15px; padding: 12px 17px; }

/* Room between the grid and what follows it, so the page has a visible bottom
   rather than trailing off into more tiles. Full width: it's the one thing you
   press after scanning nine tiles, so it shouldn't need aiming at. */
#shorts-more-tiles { align-self: stretch; }

/* The back arrow in a topbar is the most-pressed control in the app and was the
   smallest thing in it. The negative margin cancels the extra left padding, so
   the target grows outwards while the words stay lined up with the content
   underneath. */
.btn-link { padding: 13px 14px; font-size: 15px; min-height: 48px; }
.topbar .btn-link:first-child { margin-left: -6px; }

/* The −/+ for how many rooms was a 40×34 square in a sheet you use with one
   thumb while holding the phone. */
.sheet-card .stepper-btn { width: 52px; min-height: 48px; padding: 0; font-size: 22px; }

/* "Open" on an approved website. Scoped to the kid screen: the same class marks
   the parent's Yes/No rows, and that register is deliberately flatter. */
#sites .site-row .btn { padding: 13px 16px; font-size: 15px; min-height: 48px; }

/* "I'm done" and "Add a picture" on the kid's own chore list. These were the
   last 13px buttons left on a kid screen, and they're the ones pressed with wet
   hands straight after cleaning a bathroom. */
#money .chore-row .btn { padding: 13px 15px; font-size: 15px; min-height: 48px; }

/* ---------- the parent register ---------- */

/* A parent's rows stay denser than a kid's — more information per screen is the
   point of these — but dense is not the same as unhittable. 44px is the floor
   here, against 48px on a kid screen. */
.money-row .btn,
.site-row .btn,
.chore-photo { padding: 11px 14px; font-size: 14px; min-height: 44px; }

/* The four grant buttons share one row, so they can't grow sideways: at 320px
   each gets about 64px. Height and type size are what's available, and 4px of
   horizontal padding was making "+25¢" touch its own edges. */
.grant-row { gap: 7px; }
.grant-row .btn { padding: 12px 2px; font-size: 16px; min-height: 48px; }

/* A row that carries buttons aligns on their centres, not on the baseline of
   the text beside them — otherwise taller buttons hang below the row. */
.money-row, .site-row { align-items: center; }

/* An empty status line still costs a gap in a flex column, which is 18px of
   nothing between the controls and the content. */
.subtle:empty, .error:empty { display: none; }

/* "Show more" is a way down the page, not an action on the level of Play. It
   stays quiet by being a ghost button — transparent, no glow — rather than by
   being a small one. Emphasis is carried by fill and colour here; size is only
   ever about whether a kid can hit it. */

/* ---------- the school day ---------- */

/* A timetable is read down the left edge, so the time is a fixed column and the
   subject takes whatever is left. Times are the one place in the app where mono
   is right: eight rows of numbers that have to line up. */
.periods { display: flex; flex-direction: column; gap: 2px; }

.period {
  display: grid;
  grid-template-columns: 78px 1fr;
  align-items: baseline;
  gap: 4px 12px;
  padding: 11px 12px;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
}

.period-at {
  font-family: var(--font-data);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  color: var(--text-dim);
  white-space: nowrap;
}

/* The end of the block, under its start. Dimmer, because the start is the thing
   you scan for — but present, because "8:00" alone read as a full hour. */
.period-until {
  display: block;
  font-size: 11px;
  opacity: 0.7;
}

.period-name { font-size: 16px; font-weight: 600; line-height: 1.25; }

/* What the activity actually is, when the name above is a category. Sits in the
   subject column, under the name, so the time column stays clean. */
.period-detail {
  grid-column: 2;
  font-size: 13px;
  color: var(--text-dim);
  line-height: 1.3;
}
.period-untimed .period-detail { grid-column: 1; }

/* Done is dimmed rather than struck through or hidden: a kid looking at 2pm
   still wants to see that English happened, just not to read it first. */
.period-done { opacity: 0.42; }

/* On now is the only lit row, so the screen answers "where am I supposed to be"
   without being read. */
.period-now {
  border-color: var(--school-edge-hi);
  background:
    radial-gradient(120% 140% at 0% 50%, var(--school-lit), transparent 70%),
    rgba(255, 255, 255, 0.03);
}
.period-now .period-name { font-weight: 700; }
.period-now .period-at { color: var(--school); }

/* A tag for anything that isn't a normal class — a break, or a plan that isn't
   settled. Sits under the name so a long subject still wraps cleanly. */
.period-tag {
  grid-column: 2;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.period-open .period-tag { color: var(--wait); }
.period-now .period-tag { color: var(--school); }

/* An untimed activity — orientation has an order but no clock — loses the time
   column rather than showing an invented one. */
.period-untimed { grid-template-columns: 1fr; }
.period-untimed .period-tag { grid-column: 1; }

/* The "now" pill next to the panel title, so the heading carries the answer too. */
.schedule-now {
  font-size: 12px;
  font-weight: 700;
  color: var(--school);
  background: var(--school-lit);
  border-radius: 999px;
  padding: 3px 10px;
  vertical-align: 1px;
}

/* ---------- the week grid ---------- */

.schedule-views { justify-content: center; }

/* Five days plus a time column don't fit a phone, so the table scrolls inside
   its own box. -webkit-overflow-scrolling keeps it feeling native on iOS. */
/* No horizontal padding: a sticky `left: 0` column pins to the content edge, so
   any padding to its left becomes a strip that scrolling cells show through. */
.week-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  /* Room for the last hour label and the scrollbar to coexist. */
  padding-bottom: 14px;
}

/* ---------- the week, as a calendar ---------- */

/* One axis, measured in minutes. Position is when a thing starts and height is
   how long it runs, so an activity that begins at 11:45 sits three-quarters of
   the way down the 11 o'clock hour and a 30-minute lunch is half the height of
   an hour. This replaced a slot grid that could only place things on the hour —
   it dropped a 11:45 piano lesson entirely, and equal-height rows made a long
   subject name read as a long class. */

.week-cal { display: flex; gap: 3px; min-width: 560px; }

.week-stack { display: flex; flex-direction: column; flex: 1 1 0; min-width: 96px; }

/* The hour labels. Pinned, because you scroll sideways to reach Friday and a
   calendar with the clock scrolled off the edge is unreadable. */
.week-gutter {
  position: sticky;
  left: 0;
  z-index: 3;
  flex: none;
  width: 52px;
  /* Lines up with the columns, which sit under a day heading. */
  margin-top: 34px;
  background: var(--trench);
  box-shadow: 1px 0 0 var(--line);
}

.week-hour {
  position: absolute;
  right: 6px;
  /* Centred on its line rather than hanging below it. */
  transform: translateY(-50%);
  font-family: var(--font-data);
  font-size: 10px;
  font-variant-numeric: tabular-nums;
  color: var(--text-dim);
  white-space: nowrap;
}

.week-day {
  height: 34px;
  text-align: center;
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 700;
  color: var(--text-dim);
  line-height: 1.15;
}

.week-day-num { display: block; font-size: 11px; font-weight: 600; opacity: 0.75; }
.week-day-today, .week-day-special { color: var(--school); }
.week-day-today .week-day-num, .week-day-special .week-day-num { opacity: 1; }

/* Hour lines come from the background so they can never drift away from the
   labels beside them — the size is set per column in JS from the same scale. */
.week-col {
  position: relative;
  border-radius: 8px;
  background-image: linear-gradient(to bottom, var(--line) 0 1px, transparent 1px);
  background-repeat: repeat-y;
}

.week-act {
  position: absolute;
  left: 0;
  right: 0;
  overflow: hidden;
  padding: 5px 7px;
  border-radius: 8px;
  border: 1px solid transparent;
  background: rgba(255, 255, 255, 0.05);
  font-size: 12px;
  font-weight: 650;
  line-height: 1.2;
}

.week-act-name { display: block; }

.week-act-at {
  display: block;
  margin-top: 2px;
  font-family: var(--font-data);
  font-size: 10px;
  font-variant-numeric: tabular-nums;
  font-weight: 500;
  color: var(--text-dim);
}

.week-act-detail {
  display: block;
  margin-top: 2px;
  font-size: 10px;
  font-weight: 500;
  color: var(--text-dim);
  /* A domain is one long unbroken word, so it needs permission to break or it
     runs off the side of a 96px column. */
  overflow-wrap: anywhere;
}

/* Same meanings as the day view: a break is quiet, an unsettled plan is amber,
   and anything on today's column borrows the school hue. */
.week-act-break { color: var(--text-dim); font-weight: 500; }
.week-act-open { color: var(--wait); border-color: var(--wait-edge); }
.week-act-outdoor { border-color: var(--school-edge); }
.week-act-today { background: var(--school-lit); border-color: var(--school-edge); }

/* No stated finish, so the bottom edge is deliberately soft rather than a line
   that would claim one. */
.week-act-open-ended {
  border-bottom-style: dashed;
  border-bottom-color: var(--line);
}

/* ---- parent → kid: the four tabs ----
   The tab row stays put while the pane scrolls, so switching never means
   scrolling back up first. Each pane spaces its panels the way .screen does,
   because the pane now sits between the screen and its panels. */
.kid-tabs {
  position: sticky;
  top: 0;
  z-index: 5;
  flex-wrap: nowrap;
  gap: 6px;
  margin: 0 -20px;
  padding: 8px 20px;
  background: rgba(7, 28, 38, 0.86);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
}
.kid-tabs .chip {
  flex: 1 1 0;
  min-height: 44px;
  padding: 10px 6px;
  font-size: 15px;
  text-align: center;
}
.kid-tab { display: flex; flex-direction: column; gap: 18px; }

/* ---- parent home: the inbox ----
   A row names the kid first, because the list mixes both kids and a parent
   reads the name before the request. The chip reuses the waiting colour. */
.inbox-kid {
  display: inline-block;
  margin-right: 6px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--wait);
  background: var(--wait-lit);
  border: 1px solid var(--wait-edge);
  vertical-align: 1px;
}

/* ---- folds ----
   A <details> dressed as a panel heading. The summary is a kid control, so it
   clears 48px like every other one. */
.fold-summary {
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 48px;
  margin: -4px 0;
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
}
.fold-summary::-webkit-details-marker { display: none; }
.fold-summary::after {
  content: '＋';
  font-size: 20px;
  font-weight: 500;
  color: var(--text-dim);
}
.fold[open] > .fold-summary::after { content: '－'; }
.fold[open] > .fold-summary { margin-bottom: 8px; }
.fold + .fold { border-top: 1px solid var(--line); padding-top: 4px; }

/* Rows past the fold wait behind the button under the list. */
.row-item.folded-away { display: none; }
