/* ==========================================================================
   Homegrown — Neo-Brutalist design system
   Cream dot-grid paper, 3px ink borders, hard offset shadows, flat bold
   colour blocks. Parent and Kids modes share the language; kid themes swap
   the accent colour (--c).
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */
:root {
  --font-body: 'Space Grotesk', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-display: 'Archivo Black', var(--font-body);

  --bg: #f3efe6;
  --card: #ffffff;
  --ink: #14120e;
  --muted: #6b655a;
  --faintline: #d9d3c4;

  --yellow: #ffd43b;
  --pink: #ff90e8;
  --blue: #55ccf2;
  --green: #9ff26b;
  --orange: #ff8a3d;
  --red: #ff5c5c;
  --lilac: #c4b5fd;
  --teal: #2dd4bf;
  --yellow-theme: #f5c542;

  --star: #f5a300;

  --bw: 3px;                                /* standard border width */
  --shadow: 6px 6px 0 var(--ink);
  --shadow-sm: 4px 4px 0 var(--ink);
  --shadow-xs: 3px 3px 0 var(--ink);

  /* Accent colour — kids themes override this */
  --c: var(--pink);

  /* Category colours (flat) */
  --cat-main: var(--pink);
  --cat-side: var(--blue);
  --cat-math: var(--blue);
  --cat-science: var(--green);
  --cat-topics: var(--green);    /* shares science's hue — never on the same day as science in practice */
  --cat-english: var(--yellow);
  --cat-languages: var(--red);
  --cat-story: var(--lilac);
  --cat-build: var(--teal);
  --cat-tech: var(--lilac);
  --cat-creative: var(--pink);
  --cat-physical: var(--orange);
  --cat-chore: var(--blue);
  --cat-surprise: var(--star);   /* gold — the one that reads "special" */
  --cat-watch: var(--teal);      /* reused from build — the palette already repeats hues (tech/story share lilac) */
}

/* Kid theme worlds → accent swap */
body.theme-blue    { --c: var(--blue); }
body.theme-green   { --c: var(--green); }
body.theme-pink    { --c: var(--pink); }
body.theme-orange  { --c: var(--orange); }
body.theme-red     { --c: var(--red); }
body.theme-yellow  { --c: var(--yellow-theme); }
body.theme-lilac   { --c: var(--lilac); }
body.theme-teal    { --c: var(--teal); }

/* --------------------------------------------------------------------------
   2. Base
   -------------------------------------------------------------------------- */
* { margin: 0; padding: 0; box-sizing: border-box; }

html { color-scheme: light; }

body {
  font-family: var(--font-body);
  background: var(--bg);
  background-image: radial-gradient(var(--ink) 1px, transparent 1.4px);
  background-size: 26px 26px;
  background-attachment: fixed;
  color: var(--ink);
  min-height: 100vh;
  overflow-x: clip;
  -webkit-font-smoothing: antialiased;
}

.hidden { display: none !important; }

button { font-family: inherit; cursor: pointer; border: none; background: none; color: inherit; }
input, select, textarea { font-family: inherit; color: inherit; }
a { color: inherit; }

::selection { background: var(--yellow); }

::-webkit-scrollbar { width: 12px; height: 12px; }
::-webkit-scrollbar-track { background: var(--bg); border-left: var(--bw) solid var(--ink); }
::-webkit-scrollbar-thumb { background: var(--ink); }

/* Old ambient layer — not part of this design */
#bg-decor { display: none; }

/* --------------------------------------------------------------------------
   3. Top bar
   -------------------------------------------------------------------------- */
.topbar {
  position: sticky; top: 0; z-index: 100;
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px;
  padding: 14px 30px;
  background: var(--yellow);
  border-bottom: 4px solid var(--ink);
}

.brand { display: flex; align-items: center; gap: 14px; }
.brand-logo { display: flex; align-items: center; gap: 7px; height: 58px; }
.brand-nova { display: block; width: 58px; height: 58px; }
.brand-wording { display: flex; align-items: center; }
/* margin:0 because this is an <h1> — see the note in index.html. The word is
   assets/homegrown-wordmark.svg (glyph outlines + the green rule, viewBox cut
   to the ink), sized by height: 30px puts the letters at the same size the
   1.55rem live text had. A tagline version was tried here on 2026-09-12
   and pulled the same day — too cramped in the bar; later that day Tom
   dropped the tagline from the logo altogether, so the master
   assets/homegrown-logo-v2.svg is now exactly this composition (Nova 58 : word
   30, gap 7, word 20 down). If the wordmark file is ever rebuilt, rename it —
   SVGs are cached, unlike the no-cache HTML/CSS/JS. */
.brand-wordmark { margin: 0; line-height: 0; }
/* margin-top nudges the word 6px down the 58px row (a one-sided margin on a
   centred flex item moves it by half): centred by its box, the word sat at
   Nova's face and read as too high (Tom, 2026-09-12). This puts the letters'
   centre on the robot's middle, with the rule down by her base. */
.brand-wordmark img { display: block; height: 30px; width: auto; margin-top: 12px; }
.brand > #header-subtitle {
  font-size: 0.68rem; font-weight: 700;
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink);
  opacity: 0.75;
}

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

/* Mode toggle */
.mode-toggle { display: flex; gap: 10px; }
.mode-toggle button {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 20px;
  background: var(--card);
  border: var(--bw) solid var(--ink);
  box-shadow: var(--shadow-sm);
  font-size: 0.85rem; font-weight: 700; text-transform: uppercase;
  transition: transform 0.08s ease, box-shadow 0.08s ease;
}
.mode-toggle button svg { width: 16px; height: 16px; stroke-width: 2.4; }
.mode-toggle button:active { transform: translate(4px, 4px); box-shadow: none; }
.mode-toggle button.active {
  background: var(--ink); color: #fff;
  box-shadow: 4px 4px 0 var(--pink);
}
body.child-mode .mode-toggle button.active { box-shadow: 4px 4px 0 var(--c); }

/* Kid switcher */
.kid-switcher { position: relative; }
#kid-switcher-btn {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 16px 7px 8px;
  background: var(--card);
  border: var(--bw) solid var(--ink);
  box-shadow: var(--shadow-sm);
  font-weight: 700; font-size: 0.9rem; text-transform: uppercase;
  transition: transform 0.08s ease, box-shadow 0.08s ease;
}
#kid-switcher-btn:active { transform: translate(4px, 4px); box-shadow: none; }
#kid-switcher-btn svg { width: 15px; height: 15px; stroke-width: 2.6; }

/* Profile select — the Netflix-style front door into Kids mode */
#profile-select {
  min-height: 62vh;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 40px;
  padding: 40px 20px;
}
.profile-select-title {
  font-family: var(--font-display);
  font-size: clamp(1.4rem, 4vw, 2.2rem);
  text-transform: uppercase;
  background: var(--ink); color: #fff;
  padding: 12px 28px;
  transform: rotate(-1deg);
  box-shadow: 6px 6px 0 var(--yellow);
}
.profile-grid {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 34px;
  max-width: 760px;
}
.profile-tile {
  display: flex; flex-direction: column; align-items: center; gap: 14px;
  padding: 22px 26px;
  background: var(--card);
  border: var(--bw) solid var(--ink);
  box-shadow: var(--shadow);
  cursor: pointer;
  animation: pop 0.3s ease both;
  transition: transform 0.1s ease, box-shadow 0.1s ease, background 0.1s ease;
}
/* Hover effects that move an element or recolour it live behind
   @media (hover: hover) throughout: on touch devices iOS applies hover on the
   FIRST tap (so tiles shifted/recoloured and needed a second tap to actually
   select), and a "hover" state that sticks after tapping reads as broken.
   Real pointers keep the full effect. */
@media (hover: hover) {
  .profile-tile:hover {
    transform: translate(-3px, -3px);
    box-shadow: 9px 9px 0 var(--ink);
    background: var(--kid-color, var(--blue));
  }
}
.profile-tile:active { transform: translate(0, 0); box-shadow: var(--shadow-sm); }
.profile-avatar-ring {
  display: block;
  width: 116px; height: 116px;
  border-radius: 50%;
  border: 4px solid var(--ink);
  box-shadow: 0 0 0 6px var(--kid-color, var(--blue));
  overflow: hidden;
  background: var(--card);
}
.profile-avatar-ring img { width: 100%; height: 100%; object-fit: cover; }
.profile-name {
  font-family: var(--font-display);
  font-size: 1.05rem; text-transform: uppercase; letter-spacing: 0.03em;
  color: var(--ink);
}
/* Parent tile — same shape, deliberately not a kid: ink ring, tool icon */
.profile-parent-ring {
  display: flex; align-items: center; justify-content: center;
  background: var(--ink);
  box-shadow: 0 0 0 6px var(--yellow);
}
.profile-parent-ring svg { width: 44px; height: 44px; stroke-width: 2; color: #fff; }
@media (hover: hover) { .profile-tile-parent:hover { background: var(--yellow); } }
@media (max-width: 560px) {
  .profile-grid { gap: 18px; }
  .profile-tile { padding: 16px 18px; }
  .profile-avatar-ring { width: 88px; height: 88px; }
}

/* Avatars — flat circles with ink rings */
.avatar-xs, .avatar-sm, .avatar-lg { background: var(--card); border: 2px solid var(--ink); }
.avatar-xs { width: 28px; height: 28px; border-radius: 50%; }
.avatar-sm { width: 42px; height: 42px; border-radius: 50%; border-width: var(--bw); }
.avatar-lg { width: 72px; height: 72px; border-radius: 50%; border-width: var(--bw); box-shadow: var(--shadow-xs); }

/* --------------------------------------------------------------------------
   4. Layout & shared components
   -------------------------------------------------------------------------- */
main {
  position: relative; z-index: 1;
  max-width: 1360px;
  margin: 0 auto;
  padding: 32px 30px 90px;
}

.reveal { animation: pop 0.3s ease both; }
@keyframes pop {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

.btn {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 11px 20px;
  background: var(--card);
  border: var(--bw) solid var(--ink);
  box-shadow: var(--shadow-sm);
  font-size: 0.85rem; font-weight: 700; text-transform: uppercase;
  white-space: nowrap;
  transition: transform 0.08s ease, box-shadow 0.08s ease;
}
.btn svg { width: 16px; height: 16px; stroke-width: 2.6; }
.btn:active { transform: translate(4px, 4px); box-shadow: none; }

.btn-primary { background: var(--blue); }
.btn-primary:hover { background: var(--green); }
.btn-ghost { background: var(--card); }
.btn-ghost:hover { background: var(--bg); }
.btn-danger { background: var(--red); color: #fff; }
.btn-sm { padding: 8px 14px; font-size: 0.75rem; box-shadow: var(--shadow-xs); }
.btn-sm svg { width: 13px; height: 13px; }

.icon-btn {
  display: grid; place-items: center;
  width: 34px; height: 34px;
  background: var(--card);
  border: var(--bw) solid var(--ink);
  box-shadow: var(--shadow-xs);
  transition: transform 0.08s ease, box-shadow 0.08s ease;
}
.icon-btn svg { width: 15px; height: 15px; stroke-width: 2.6; }
.icon-btn:hover { background: var(--yellow); }
.icon-btn:active { transform: translate(3px, 3px); box-shadow: none; }
.icon-btn.danger:hover { background: var(--red); color: #fff; }
.icon-btn:disabled { opacity: 0.35; pointer-events: none; }

.badge {
  display: inline-grid; place-items: center;
  min-width: 22px; height: 22px;
  padding: 0 6px;
  border-radius: 50%;
  background: var(--red);
  border: 2px solid var(--ink);
  color: #fff;
  font-size: 0.72rem; font-weight: 700;
}

/* Category colours */
.cat-main     { --cat: var(--cat-main); }
.cat-side     { --cat: var(--cat-side); }
.cat-math     { --cat: var(--cat-math); }
.cat-science  { --cat: var(--cat-science); }
.cat-topics   { --cat: var(--cat-topics); }
.cat-english  { --cat: var(--cat-english); }
.cat-languages{ --cat: var(--cat-languages); }
.cat-story    { --cat: var(--cat-story); }
.cat-build    { --cat: var(--cat-build); }
.cat-tech     { --cat: var(--cat-tech); }
.cat-creative { --cat: var(--cat-creative); }
.cat-physical { --cat: var(--cat-physical); }
.cat-chore    { --cat: var(--cat-chore); }
.cat-surprise { --cat: var(--cat-surprise); }
.cat-watch    { --cat: var(--cat-watch); }

.cat-pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 10px;
  background: var(--cat, var(--pink));
  border: 2px solid var(--ink);
  font-size: 0.66rem; font-weight: 700;
  letter-spacing: 0.05em; text-transform: uppercase;
  color: var(--ink);
}
.cat-pill svg { width: 12px; height: 12px; stroke-width: 2.6; }
.cat-pill.onetime { background: var(--yellow); }

/* Reward shelf — parent side */
.reward-add { display: flex; gap: 8px; }
.reward-add input[type="text"] { flex: 1; }
.reward-cost-field { width: 104px; flex: none; text-align: center; }
.cost-pill {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 10px;
  background: var(--yellow);
  border: 2px solid var(--ink);
  font-size: 0.72rem; font-weight: 800;
  color: var(--ink);
}
.cost-pill svg { width: 12px; height: 12px; stroke-width: 2.6; fill: var(--ink); }
.cost-pill.spent { background: var(--bg); }
.claim-date { margin-left: 10px; font-size: 0.74rem; font-weight: 600; opacity: 0.6; }

/* Nova dock — the persistent guide, bottom-right of parent mode */
.nova-dock {
  position: fixed; right: 22px; bottom: 22px; z-index: 300;
  width: 68px; height: 68px;
  display: flex; align-items: center; justify-content: center;
  padding: 0;
  background: var(--card);
  border: var(--bw) solid var(--ink);
  border-radius: 50%;
  box-shadow: var(--shadow);
  cursor: pointer;
  transition: transform 0.1s ease, box-shadow 0.1s ease;
}
.nova-dock { background: var(--nova-accent, var(--card)); }
.nova-dock img { width: 50px; height: 50px; display: block; }
@media (hover: hover) { .nova-dock:hover { transform: translate(-2px, -2px); box-shadow: 7px 7px 0 var(--ink); } }
.nova-dock:active { transform: translate(0, 0); box-shadow: var(--shadow-sm); }
.nova-dock-badge {
  position: absolute; top: -4px; right: -4px;
  min-width: 24px; height: 24px;
  display: flex; align-items: center; justify-content: center;
  padding: 0 5px;
  background: var(--pink);
  border: 2px solid var(--ink);
  border-radius: 12px;
  font-family: var(--font-display); font-size: 0.74rem;
  color: var(--ink);
}

.nova-help {
  position: fixed; right: 22px; bottom: 100px; z-index: 300;
  width: min(380px, calc(100vw - 44px));
  max-height: min(560px, calc(100vh - 140px));
  display: flex; flex-direction: column;
  background: var(--card);
  border: var(--bw) solid var(--ink);
  box-shadow: var(--shadow);
  animation: pop 0.22s ease both;
}
.nova-help-head {
  display: flex; align-items: center; gap: 12px;
  padding: 14px 14px 14px 16px;
  background: var(--yellow);
  border-bottom: var(--bw) solid var(--ink);
}
.nova-help-avatar { width: 40px; height: 40px; flex: none; }
.nova-help-id { flex: 1; display: flex; flex-direction: column; line-height: 1.25; }
.nova-help-id strong { font-family: var(--font-display); font-size: 0.98rem; }
.nova-help-id small { font-size: 0.76rem; font-weight: 600; opacity: 0.7; }
.nova-help-body { overflow-y: auto; padding: 16px; }

.nova-section + .nova-section { margin-top: 22px; padding-top: 18px; border-top: 2px dashed var(--ink); }
.nova-section h4 {
  margin-bottom: 10px;
  font-family: var(--font-display);
  font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.05em;
}
.nova-note { margin: 0 0 10px; font-size: 0.8rem; opacity: 0.7; line-height: 1.5; }
.nova-points { display: flex; flex-direction: column; gap: 10px; padding-left: 18px; }
.nova-points li { font-size: 0.86rem; line-height: 1.55; }

.nova-steps { display: flex; flex-direction: column; gap: 10px; list-style: none; padding: 0; }
.nova-step { display: flex; gap: 11px; align-items: flex-start; }
.nova-step-mark {
  flex: none;
  width: 26px; height: 26px;
  display: flex; align-items: center; justify-content: center;
  background: var(--bg);
  border: 2px solid var(--ink);
  border-radius: 50%;
  font-family: var(--font-display); font-size: 0.78rem;
}
.nova-step-mark svg { width: 13px; height: 13px; stroke-width: 3.2; }
.nova-step.done .nova-step-mark { background: var(--green); }
.nova-step.done .nova-step-text strong { opacity: 0.55; text-decoration: line-through; }
.nova-step-text { display: flex; flex-direction: column; gap: 5px; }
.nova-step-text strong { font-size: 0.88rem; }
.nova-step-text small { font-size: 0.78rem; line-height: 1.45; opacity: 0.72; }
.nova-step-text .btn { align-self: flex-start; }

@media (max-width: 560px) {
  .nova-dock { width: 58px; height: 58px; right: 14px; bottom: 14px; }
  .nova-dock img { width: 42px; height: 42px; }
  .nova-help { right: 14px; left: 14px; bottom: 84px; width: auto; }
}

/* Nova — AI topic suggestions */
.label-optional {
  font-weight: 600; text-transform: none; letter-spacing: 0;
  opacity: 0.55;
}
.nova-thinking {
  display: flex; align-items: center; justify-content: center; gap: 12px;
  padding: 40px 20px;
  font-family: var(--font-display);
  font-size: 1rem; text-transform: uppercase; letter-spacing: 0.04em;
}
.nova-thinking svg {
  width: 22px; height: 22px; stroke-width: 2.4;
  animation: novaPulse 1.2s ease-in-out infinite;
}
@keyframes novaPulse {
  0%, 100% { opacity: 0.35; transform: scale(0.9); }
  50%      { opacity: 1;    transform: scale(1.1); }
}
@media (prefers-reduced-motion: reduce) {
  .nova-thinking svg { animation: none; }
}

.nova-list { display: flex; flex-direction: column; gap: 8px; margin-bottom: 14px; }
.nova-item {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 14px;
  background: var(--bg);
  border: 2px solid var(--ink);
  font-size: 0.92rem; font-weight: 600;
  cursor: pointer;
  transition: background 0.08s ease;
}
.nova-item:hover { background: var(--yellow); }
/* Suggestions are now buttons (tap = drop into the session form), so undo the
   UA button styling that the old label version never needed. */
.nova-item-btn {
  width: 100%;
  justify-content: space-between;
  text-align: left;
  font-family: inherit;
  color: inherit;
}
.nova-item-btn i { flex: none; width: 16px; height: 16px; opacity: 0.55; }

/* Sync sign-in */
.sync-form { display: flex; flex-direction: column; gap: 8px; }
.sync-form input[type="email"],
.sync-form input[type="password"] {
  padding: 11px 14px;
  background: var(--bg);
  border: 2px solid var(--ink);
  font-family: inherit; font-size: 0.9rem;
  color: var(--ink);
}
.sync-create {
  display: flex; align-items: center; gap: 8px;
  font-size: 0.8rem; font-weight: 600;
  cursor: pointer;
}
.sync-create input { width: 16px; height: 16px; accent-color: var(--ink); }

/* Parent PIN entry */
.pin-input {
  width: 100%;
  margin: 4px 0 6px;
  padding: 14px 16px;
  background: var(--bg);
  border: var(--bw) solid var(--ink);
  font-family: var(--font-display);
  font-size: 1.6rem; letter-spacing: 0.4em; text-align: center;
  color: var(--ink);
}
.pin-input:focus { outline: none; background: var(--yellow); }

/* Parent pricing aid on the Rewards tab */
.earn-rate {
  display: flex; align-items: flex-start; gap: 10px;
  margin-bottom: 14px;
  padding: 12px 16px;
  background: var(--yellow);
  border: 2px solid var(--ink);
  font-size: 0.84rem; line-height: 1.5;
}
.earn-rate svg { width: 16px; height: 16px; stroke-width: 2.4; flex: none; margin-top: 2px; }

/* Reward shop — child side, opened from the stars chip on the child's card
   (the chip itself is styled with the card, section 6). The dot says "you can
   afford something". */
.stars-pill-dot {
  position: absolute; top: -6px; right: -6px;
  width: 12px; height: 12px;
  background: var(--green);
  border: 2px solid var(--ink);
  border-radius: 50%;
  animation: dotPulse 1.6s ease-in-out infinite;
}
@keyframes dotPulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.25); }
}
@media (prefers-reduced-motion: reduce) {
  .stars-pill-dot { animation: none; }
}

.shop-balance {
  display: flex; align-items: center; gap: 10px;
  margin-bottom: 18px;
  padding: 14px 18px;
  background: var(--yellow);
  border: var(--bw) solid var(--ink);
  font-family: var(--font-display); font-size: 1.5rem;
}
.shop-balance svg { width: 22px; height: 22px; fill: var(--ink); stroke-width: 2.2; }
.shop-balance small { font-family: var(--font-body); font-size: 0.78rem; font-weight: 700; text-transform: uppercase; opacity: 0.7; }
.shop-grid { grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); }

.reward-card {
  display: flex; flex-direction: column; align-items: flex-start; gap: 10px;
  padding: 18px;
  background: var(--card);
  border: var(--bw) solid var(--ink);
  box-shadow: var(--shadow);
  animation: pop 0.3s ease both;
}
.reward-card h4 { flex: 1; font-family: var(--font-display); font-size: 1.02rem; line-height: 1.3; }
.reward-card .btn { width: 100%; justify-content: center; }
.reward-cost {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 12px;
  background: var(--yellow);
  border: 2px solid var(--ink);
  font-family: var(--font-display);
  font-size: 0.9rem;
  color: var(--ink);
}
.reward-cost svg { width: 15px; height: 15px; stroke-width: 2.4; fill: var(--ink); }
.reward-card.locked { opacity: 0.55; }
.reward-card.locked .reward-cost { background: var(--bg); }
.reward-card.locked .btn { cursor: not-allowed; }

/* Sidebar settings button — sits under the Explorers panel */
.settings-btn {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  width: 100%;
  padding: 14px 18px;
  background: var(--card);
  border: var(--bw) solid var(--ink);
  box-shadow: var(--shadow);
  font-family: var(--font-display);
  font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--ink);
  cursor: pointer;
  transition: transform 0.08s ease, box-shadow 0.08s ease, background 0.08s ease;
}
.settings-btn svg { width: 17px; height: 17px; stroke-width: 2.4; }
.settings-btn:hover {
  background: var(--yellow);
  transform: translate(-2px, -2px);
  box-shadow: 6px 6px 0 var(--ink);
}
.settings-btn:active { transform: translate(0, 0); box-shadow: 2px 2px 0 var(--ink); }

/* Settings modal */
.settings-section { margin-bottom: 22px; }
.settings-section h4 {
  display: flex; align-items: center; gap: 8px;
  margin-bottom: 6px;
  font-family: var(--font-display);
  font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.04em;
}
.settings-section h4 svg { width: 15px; height: 15px; stroke-width: 2.4; }
/* Settings isn't a <form>, so it misses the `form .field` spacing the kid
   modal gets — needed here for the profile editor's name field + avatar picker. */
.settings-section .field { margin-bottom: 18px; }
.settings-hint {
  margin-bottom: 12px;
  font-size: 0.84rem; line-height: 1.5;
  opacity: 0.75;
}
.settings-actions { display: flex; flex-wrap: wrap; gap: 8px; }
/* Settings → Explorers (decision 32, step 5): one row per child. */
.settings-explorers { display: flex; flex-direction: column; gap: 8px; margin-bottom: 12px; }
.settings-explorer {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 8px 6px 6px;
  background: var(--card);
  border: 2px solid var(--ink);
  border-left: 8px solid var(--kid-color, var(--blue));
}
.settings-explorer img {
  width: 32px; height: 32px; border-radius: 50%; object-fit: cover;
  background: var(--card); border: 2px solid var(--ink);
}
.settings-explorer-name {
  flex: 1; min-width: 0;
  font-weight: 700; font-size: 0.9rem; text-transform: uppercase;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.settings-actions .btn { flex: 1; min-width: 150px; justify-content: center; }
.settings-meta {
  margin-top: 12px;
  font-size: 0.76rem; font-weight: 600;
  opacity: 0.6;
}
.settings-check {
  display: flex; align-items: center; gap: 8px;
  margin-top: 12px;
  font-size: 0.84rem; font-weight: 600;
  cursor: pointer;
}
.settings-check input { width: 16px; height: 16px; accent-color: var(--ink); cursor: pointer; }

/* Empty states */
.empty-state {
  grid-column: 1 / -1;
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  padding: 48px 20px;
  background: var(--card);
  border: var(--bw) dashed var(--ink);
  text-align: center;
  font-size: 0.95rem; font-weight: 600;
}
.empty-state svg { width: 34px; height: 34px; stroke-width: 2; }
.empty-state small { font-size: 0.8rem; font-weight: 600; color: var(--muted); }

/* --------------------------------------------------------------------------
   5. Parent view
   -------------------------------------------------------------------------- */
/* minmax(0,…), not bare 1fr: a bare fr track refuses to shrink below its
   content's natural width (the scroll strips inside measure ~450px), which
   on a phone dragged the whole page out sideways — the sticky topbar stayed
   viewport-wide, so swiping "broke the header". An explicit 0 minimum lets
   the track fit the viewport and the strips scroll inside themselves.
   Verified live: bare 1fr → 454px track in a 347px grid; minmax(0,1fr) →
   347px track, page exactly viewport-wide. */
.parent-layout {
  display: grid;
  grid-template-columns: 296px minmax(0, 1fr);
  gap: 30px;
  align-items: start;
}
.parent-layout > * { min-width: 0; }

/* The left menu (decision 35): Explorers, the six sections, Settings — a bar
   attached to the far left of the screen (Tom, 2026-09-17: "a proper menu
   bar attached to the far left"), full height under the top bar, white with
   an ink right border, like the lesson pages' sidebar. Fixed, so it is out
   of the page flow: main shifts right by --rail-w (body.has-rail, below) and
   the bar scrolls inside itself if a big family makes it taller than the
   window. --topbar-h is kept true by syncTopbarHeight() in app.js. */
:root { --rail-w: 300px; --topbar-h: 90px; }
.sidebar {
  display: flex; flex-direction: column; gap: 20px;
  position: fixed; top: var(--topbar-h); left: 0; bottom: 0; z-index: 50;
  width: var(--rail-w); box-sizing: border-box;
  padding: 22px 18px 24px 22px;
  overflow-y: auto; scrollbar-width: none;
  background: var(--card);
  border-right: var(--bw) solid var(--ink);
}
.sidebar::-webkit-scrollbar { display: none; }
/* Inside the bar the Explorers panel is a plain list, not a card in a card. */
.sidebar .panel { padding: 0; background: transparent; border: 0; box-shadow: none; }
@media (min-width: 1021px) {
  body.has-rail main {
    max-width: none; margin: 0;
    padding-left: calc(var(--rail-w) + 36px); padding-right: 36px;
  }
  body.has-rail .parent-layout { grid-template-columns: minmax(0, 1fr); }
  body.has-rail .main-col { max-width: 1120px; margin: 0 auto; width: 100%; }
}
.sidebar:focus { outline: none; }
.rail-backdrop { display: none; }   /* a div in the grid otherwise takes column two */
.rail-toggle { display: none; width: 40px; height: 40px; }

.panel {
  background: var(--card);
  border: var(--bw) solid var(--ink);
  box-shadow: var(--shadow);
  padding: 20px;
}

#kids-roster { display: flex; flex-direction: column; gap: 12px; }

.kid-card {
  display: flex; align-items: center; gap: 12px;
  padding: 12px;
  background: var(--bg);
  border: var(--bw) solid var(--ink);
  cursor: pointer;
  transition: transform 0.08s ease, box-shadow 0.08s ease, background 0.08s ease;
}
@media (hover: hover) { .kid-card:hover { background: var(--yellow); } }
.kid-card.active {
  background: var(--kid-color, var(--blue));
  box-shadow: var(--shadow-sm);
}
.kid-card:focus-visible { outline: 3px solid var(--blue); outline-offset: 3px; }
.kid-card .kid-text { flex: 1; min-width: 0; }
/* One card, the current explorer (decision 38): a surface with a Switch
   button on it, and the list of the others dropping below when open. */
.kid-card { position: relative; cursor: default; }
@media (hover: hover) { .kid-card:hover { background: var(--kid-color, var(--blue)); } }
.kid-card .kid-text { padding-right: 34px; }
.explorer-switch-btn { position: absolute; top: 8px; right: 8px; width: 32px; height: 32px; box-shadow: none; background: var(--card); }
.explorer-switch-btn[aria-expanded="true"] { background: var(--yellow); }
.explorer-menu {
  display: flex; flex-direction: column; gap: 2px;
  margin-top: 6px; padding: 6px;
  background: var(--card);
  border: var(--bw) solid var(--ink);
  box-shadow: var(--shadow-xs);
}
.explorer-menu[hidden] { display: none; }
.explorer-menu-item {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 8px;
  background: transparent;
  border: var(--bw) solid transparent;
  font-size: 0.85rem; font-weight: 700; text-align: left;
  cursor: pointer;
}
.explorer-menu-item:hover, .explorer-menu-item:focus-visible { background: var(--bg); border-color: var(--ink); outline: none; }
.explorer-menu-avatar { width: 28px; height: 28px; border-radius: 50%; border: 2px solid var(--kid-color, var(--ink)); object-fit: cover; flex: 0 0 auto; }
.explorer-menu-name { flex: 1; min-width: 0; text-transform: uppercase; }
.explorer-menu .kid-today { margin-top: 0; }
.kid-card h4 { font-size: 1rem; font-weight: 700; text-transform: uppercase; }
.kid-card p { font-size: 0.78rem; font-weight: 600; }
/* Today's progress on each roster card — always visible (unlike the actions,
   which only appear on hover), so the whole family reads at a glance. */
.kid-today {
  display: inline-flex; align-items: center; gap: 5px;
  margin-top: 5px;
  padding: 2px 8px;
  border: 2px solid var(--ink);
  background: var(--card);
  font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em;
}
.kid-today.done { background: var(--green); }
.kid-today svg { width: 12px; height: 12px; stroke-width: 3; }

/* A turned-in quest row: green edge bar so a completed day scans instantly. */
.session-row.done .session-bar { background: var(--green); }

/* Sheet links (decision 34) on the child's quest modal and the Completed card
   wear lilac — the pen-and-paper kind. (The Today run-sheet's chips went with
   the tab, decision 38.) */
.quest-link-chip.sheet, .sub-link.sheet { background: var(--lilac); }

/* 24px, was 34px: with the hero gone the column is tabs → explorer line →
   panel, and the wider gap read as three unrelated blocks (decision 32). */
.main-col { display: flex; flex-direction: column; gap: 24px; min-width: 0; }

/* Explorer line — who the per-child tabs are about (decision 32). Replaced the
   Current Explorer hero card: the roster card already shows the same face,
   name, stars and today-count, so this is a label with the child's colour,
   not a second dashboard. Same chip styling as the roster's .kid-today. */
.explorer-line {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 7px 14px 7px 9px;
  background: var(--kid-color, var(--pink));
  border: var(--bw) solid var(--ink);
  box-shadow: var(--shadow-sm);
}
.explorer-line img {
  width: 30px; height: 30px; border-radius: 50%; object-fit: cover;
  background: var(--card); border: 2px solid var(--ink);
}
.explorer-line b {
  font-family: var(--font-display); font-size: 1.05rem; text-transform: uppercase;
  margin-right: 4px;
}
.explorer-stars, .explorer-today {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 9px;
  border: 2px solid var(--ink);
  background: var(--card);
  font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em;
}
.explorer-stars { background: var(--yellow); }
.explorer-stars svg { width: 12px; height: 12px; stroke-width: 2.6; fill: currentColor; }
.explorer-today.done { background: var(--green); }
.explorer-today svg { width: 12px; height: 12px; stroke-width: 3; }

/* Sections — a vertical list in the rail (decision 35). Two small group
   labels split the three daily jobs from the three weekly "stock the shelf"
   ones, which is what the Shelves fold-out used to do with a click. */
.tabs { display: flex; flex-direction: column; gap: 8px; }
.tabs-group {
  margin: 10px 0 -2px 2px;
  font-size: 0.68rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--muted);
}
.tabs-group:first-child { margin-top: 0; }
.tabs button {
  display: flex; align-items: center; gap: 10px;
  padding: 11px 16px;
  background: var(--card);
  border: var(--bw) solid var(--ink);
  font-size: 0.85rem; font-weight: 700; text-transform: uppercase;
  text-align: left;
  transition: transform 0.08s ease, box-shadow 0.08s ease;
}
.tabs button svg { width: 16px; height: 16px; stroke-width: 2.6; flex: 0 0 auto; }
.tabs button .badge { margin-left: auto; }
.tabs button:hover { background: var(--yellow); }
.tabs button:active { transform: translate(3px, 3px); }
.tabs button.active { background: var(--green); box-shadow: var(--shadow-sm); }

/* Day strip */
.day-strip { display: flex; gap: 8px; flex-wrap: wrap; padding-bottom: 16px; }
.day-tab {
  flex: 1; min-width: 72px;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  padding: 11px 8px;
  background: var(--card);
  border: var(--bw) solid var(--ink);
  font-size: 0.82rem; font-weight: 700; text-transform: uppercase;
  transition: transform 0.08s ease, box-shadow 0.08s ease;
  position: relative;
}
.day-tab:hover { background: var(--yellow); }
.day-tab:active { transform: translate(3px, 3px); }
.day-tab.active {
  background: var(--ink); color: var(--yellow);
  box-shadow: 4px 4px 0 var(--pink);
}
body.child-mode .day-tab.active { box-shadow: 4px 4px 0 var(--c); }
.day-tab .count {
  display: inline-grid; place-items: center;
  min-width: 20px; height: 20px; padding: 0 5px;
  border-radius: 999px;
  border: 2px solid currentColor;
  font-size: 0.66rem; font-weight: 700;
}
/* The parent's tiles read done/total and fill green when the day is complete
   (decision 47) — the week-at-a-glance the Completed tab used to give. */
.day-tab .count.all-done { background: var(--green); color: var(--ink); border-color: var(--ink); }
/* Stacked tiles — day over date over count. The child's strip since the
   start; the parent's timetable strip too since 2026-09-19 (decision 47,
   Tom: "look more like the kids date selector"), so the family learns one
   date picker. */
.day-strip.stacked .day-tab { flex-direction: column; gap: 3px; padding: 10px 6px 8px; }
.day-strip.stacked .day-tab .day-date {
  font-size: 0.64rem; font-weight: 600; text-transform: none; letter-spacing: 0;
  opacity: 0.6;
}
.day-strip.stacked .day-tab.active .day-date { opacity: 0.85; }

.week-nav {
  display: flex; align-items: center; justify-content: center; gap: 16px;
  margin-bottom: 12px;
}
/* The child's panel is a flex column whose gap (20px) separates the week row
   from the day tiles; the parent's timetable panel is not, so it says so
   here (Tom, 2026-09-19: "there should be a space like in the kids view").
   The id outranks the appended block's `.week-nav { margin: 0 }`. */
#panel-timetable .week-nav { margin-bottom: 20px; }
.week-nav span {
  font-family: var(--font-display); font-size: 0.85rem; text-transform: uppercase; letter-spacing: 0.03em;
  min-width: 150px; text-align: center;
}
/* Compact week-nav used inside the session modal's date picker */
.week-nav-sm { gap: 12px; margin: 4px 0 10px; }
.week-nav-sm span { min-width: 130px; text-align: center; font-size: 0.78rem; }

.day-tab.today::after {
  content: '';
  position: absolute; top: -6px; right: -6px;
  width: 14px; height: 14px;
  background: var(--green);
  border: 2px solid var(--ink);
  border-radius: 50%;
}

.schedule-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px;
  padding-bottom: 10px;
}
.schedule-head h3 {
  font-family: var(--font-display);
  font-size: 1.5rem; text-transform: uppercase;
}
.schedule-head-actions { display: inline-flex; gap: 8px; flex-wrap: wrap; justify-content: flex-end; }

/* Session rows */
.schedule-list { display: flex; flex-direction: column; gap: 18px; }

.schedule-group-header h5 {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--font-display);
  font-size: 0.85rem; text-transform: uppercase;
  background: var(--ink); color: #fff;
  padding: 7px 16px;
  transform: rotate(-1deg);
}
.schedule-group-header h5 svg { width: 15px; height: 15px; stroke-width: 2.4; }

.session-row {
  display: grid;
  grid-template-columns: 112px 8px 1fr auto;
  gap: 18px;
  align-items: center;
  padding: 18px 20px;
  background: var(--card);
  border: var(--bw) solid var(--ink);
  box-shadow: var(--shadow);
  animation: pop 0.25s ease both;
  transition: transform 0.1s ease, box-shadow 0.1s ease;
}
@media (hover: hover) { .session-row:hover { transform: translate(-2px, -2px); box-shadow: 8px 8px 0 var(--ink); } }
.session-row { cursor: grab; }
.session-row.dragging { opacity: 0.4; cursor: grabbing; }
.session-row.drag-over { box-shadow: 0 -4px 0 var(--ink); border-color: var(--ink); background: var(--yellow); }
.session-time { text-align: center; }
.session-time .t-range {
  display: block;
  font-family: var(--font-display);
  font-size: 0.78rem; text-transform: uppercase;
  background: var(--yellow);
  border: 2px solid var(--ink);
  box-shadow: var(--shadow-xs);
  padding: 9px 6px;
  transform: rotate(-3deg);
}
.drag-handle {
  display: flex; justify-content: center;
  margin-top: 9px; color: var(--muted);
}
.drag-handle svg { width: 16px; height: 16px; stroke-width: 2.4; }
.session-bar {
  width: 8px; height: 100%; min-height: 48px;
  background: var(--cat, var(--pink));
  border: 2px solid var(--ink);
}
.session-info { min-width: 0; }
.session-info h4 { display: flex; align-items: center; gap: 10px; font-size: 1.05rem; font-weight: 700; flex-wrap: wrap; }
.session-info p {
  margin-top: 5px;
  font-size: 0.85rem; font-weight: 500; line-height: 1.5;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

/* Slim rows — the parent Timetable (decision 32). The sticker column, the
   two-line briefing and the edit/delete buttons made each card ~140px for one
   line of text: 1.5 quests per screen. Now handle · colour bar · title +
   pills · one-line briefing · Done tick fit in about 60px, and the row itself
   is the edit control (delete lives inside the form). The Today run-sheet
   keeps the full .session-row above. */
#parent-schedule-list { gap: 10px; }
.session-row.slim {
  grid-template-columns: auto 8px minmax(0, 1fr) auto;
  gap: 14px;
  padding: 10px 16px 10px 10px;
  box-shadow: var(--shadow-sm);
  cursor: pointer;
}
@media (hover: hover) { .session-row.slim:hover { box-shadow: 6px 6px 0 var(--ink); } }
.session-row.slim .drag-handle { margin: 0; padding: 6px 2px; cursor: grab; }
.session-row.slim .session-bar { min-height: 34px; }
.session-row.slim .session-info h4 { font-size: 0.95rem; gap: 8px; }
.session-row.slim .session-info p { margin-top: 2px; font-size: 0.8rem; -webkit-line-clamp: 1; }
.session-row.slim .status-pill { white-space: nowrap; }
.cat-pill.links { background: var(--card); color: var(--muted); }

/* Billing (decision 49): the banner over the parent's page, the plan status in
   Settings and the paywall box. Tone colours: ok green, warn yellow, bad red. */
.billing-banner {
  display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap;
  padding: 10px 14px;
  border: var(--bw) solid var(--ink);
  background: var(--yellow);
  font-size: 0.86rem; font-weight: 700;
}
.billing-banner.bad { background: var(--red); color: #fff; }
.billing-banner.bad .btn-primary { color: var(--ink); }
.billing-status { font-weight: 700; }
.billing-status.warn { color: var(--orange); }
.billing-status.bad { color: var(--red); }
.paywall .paywall-title { font-family: var(--font-display); font-size: 1.2rem; text-transform: uppercase; margin-bottom: 8px; }
.paywall .paywall-body { font-size: 0.9rem; font-weight: 500; line-height: 1.5; margin-bottom: 8px; }
.paywall .paywall-price { font-family: var(--font-display); font-size: 1rem; margin-bottom: 6px; }
.paywall .paywall-price:empty, .paywall .paywall-body:empty { display: none; }
.paywall .confirm-actions { flex-wrap: wrap; }

/* Get started (decision 48): the first-run checklist, in the page rather than
   a floating dock. Flat card, the professional pass's spacing; the current
   step carries the ink border and the primary button, done steps go quiet. */
.get-started {
  margin-bottom: 24px; padding: 16px 20px 18px;
  background: var(--card);
  border: var(--bw) solid var(--ink);
}
.get-started-head { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
.get-started-head h3 { font-family: var(--font-display); font-size: 1.1rem; text-transform: uppercase; }
.get-started-count { margin-right: auto; font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); }
.get-started-head .icon-btn { box-shadow: none; }
.get-started-steps { list-style: none; display: flex; flex-direction: column; gap: 8px; }
.get-started-step {
  display: grid; grid-template-columns: 28px minmax(0, 1fr) auto;
  gap: 12px; align-items: center;
  padding: 10px 12px;
  border: 2px solid var(--faintline);
}
.get-started-step.current { border-color: var(--ink); background: var(--bg); }
.get-started-step.done { opacity: 0.65; }
.step-mark {
  width: 28px; height: 28px; border-radius: 50%;
  display: grid; place-items: center;
  border: 2px solid var(--ink); background: var(--card);
  font-size: 0.8rem; font-weight: 800;
}
.step-mark svg { width: 14px; height: 14px; stroke-width: 3; }
.get-started-step.done .step-mark { background: var(--green); }
.get-started-text strong { display: block; font-size: 0.92rem; }
.get-started-text p { margin-top: 2px; font-size: 0.8rem; font-weight: 500; line-height: 1.45; color: var(--muted); }
.get-started-done { margin-left: 6px; font-size: 0.66rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); }
.get-started-actions { display: inline-flex; gap: 8px; flex-wrap: wrap; justify-content: flex-end; }
.get-started-actions .btn[disabled] { opacity: 0.5; cursor: not-allowed; }
.empty-actions { display: inline-flex; gap: 8px; flex-wrap: wrap; justify-content: center; margin-top: 6px; }
@media (max-width: 680px) {
  .get-started { padding: 14px 14px 16px; }
  .get-started-step { grid-template-columns: 28px minmax(0, 1fr); }
  .get-started-actions { grid-column: 2; justify-content: flex-start; }
}

/* Expanding rows (decision 47, Tom: "each lesson card will show if a lesson
   has been completed, then when clicked on it open up to show notes and
   pictures") — the Completed tab folded into the Timetable. The body is a
   fifth grid child spanning every column under the head cells; the chevron
   is the keyboard control and a click anywhere on the head toggles. A row
   with no card behind it (deleted or moved — decision 6 keeps the work) is a
   dashed "ghost" under an "Also done" heading. */
.row-end { display: inline-flex; align-items: center; gap: 8px; }
.row-toggle {
  width: 28px; height: 28px; padding: 0;
  display: grid; place-items: center;
  border: 2px solid transparent; background: transparent; color: var(--ink);
  cursor: pointer;
}
.row-toggle svg { width: 16px; height: 16px; stroke-width: 2.6; transition: transform 0.15s ease; }
.row-toggle:focus-visible { outline: 3px solid var(--blue); outline-offset: 2px; }
.session-row.slim.open .row-toggle svg { transform: rotate(180deg); }
.session-row.slim.open .session-info p { -webkit-line-clamp: unset; }
.row-body {
  grid-column: 1 / -1;
  display: flex; flex-direction: column; gap: 12px;
  margin-top: 2px; padding: 12px 0 4px 32px;
  border-top: 2px solid var(--faintline);
  cursor: auto;
}
.row-body[hidden] { display: none; }
.row-links, .row-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.row-work { display: flex; flex-direction: column; gap: 10px; }
.row-work .sub-media, .row-work .sub-links { margin: 0; }
.row-work > .sub-link { align-self: flex-start; }
.row-empty { font-size: 0.8rem; font-weight: 600; color: var(--muted); }
.session-row.slim.ghost { border-style: dashed; background: var(--bg); }
.session-row.slim.static .drag-handle { visibility: hidden; }   /* done, ghost, or a past day: no reordering */
.cat-pill.gone { background: var(--card); color: var(--muted); }

/* Submissions. Columns, not grid: cards vary a lot in height (a photo card
   next to a bare one), and a grid row grows to its tallest card, punching a
   hole under every short one. Column flow packs them masonry-style; the
   column width auto-fits the container like the old minmax(340px, 1fr). */
.submissions-grid {
  columns: 20rem;
  column-gap: 22px;
}
.submissions-grid > * {
  break-inside: avoid;
  margin-bottom: 22px;
}

.sub-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.sub-student { display: flex; align-items: center; gap: 10px; }
.sub-student h4 { font-size: 1rem; font-weight: 700; text-transform: uppercase; }

.status-pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 12px;
  border: 2px solid var(--ink);
  font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
}
.status-pill svg { width: 12px; height: 12px; stroke-width: 2.6; }
.status-pill.pending { background: var(--orange); }
.status-pill.done { background: var(--green); }
.status-pill.missed { background: var(--card); color: var(--muted); }

.sub-session { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
.sub-session h5 { font-size: 0.98rem; font-weight: 700; }
.sub-session span { font-size: 0.7rem; font-weight: 700; text-transform: uppercase; color: var(--muted); }

.sub-notes {
  font-size: 0.88rem; font-weight: 500;
  font-style: italic; line-height: 1.5;
  padding: 10px 14px;
  background: var(--bg);
  border: 2px solid var(--ink);
  border-left: 8px solid var(--ink);
}

.sub-link {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 9px 14px;
  background: var(--blue);
  border: 2px solid var(--ink);
  box-shadow: var(--shadow-xs);
  font-size: 0.8rem; font-weight: 700;
  text-decoration: none;
  max-width: 100%; overflow: hidden;
  transition: transform 0.08s ease, box-shadow 0.08s ease;
}
.sub-link span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ---- Work files on submissions (work.js) ---- */
.sub-media {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
  gap: 6px; margin: 8px 0 2px;
}
.sub-media-item { position: relative; margin: 0; }
.sub-media-open { display: block; width: 100%; padding: 0; border: 0; background: none; cursor: zoom-in; text-decoration: none; color: inherit; }
.sub-media-open:focus-visible { outline: 3px solid var(--blue); outline-offset: 3px; }
.sub-media-item img, .sub-media-item video {
  width: 100%; height: 84px; object-fit: cover; display: block;
  border: 2px solid var(--ink); border-radius: 8px; background: var(--bg);
}
.sub-media-pdf a {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  height: 84px; border: 2px solid var(--ink); border-radius: 8px;
  background: var(--bg); font-size: 0.75rem; font-weight: 700;
  color: inherit; text-decoration: none;
}
.sub-media-pdf svg { width: 15px; height: 15px; }
.sub-media-del {
  position: absolute; top: -6px; right: -6px; width: 20px; height: 20px;
  border-radius: 50%; border: 2px solid var(--ink); background: var(--card);
  font-size: 10px; line-height: 1; cursor: pointer; padding: 0;
  display: none; align-items: center; justify-content: center;
}
@media (hover: hover) { .sub-media-item:hover .sub-media-del { display: flex; } }
/* No mouse = no hover to reveal the delete cross, so it's always on. */
@media (hover: none) { .sub-media-del { display: flex; } }
/* A labelled chip, not a bare icon — the old 14px icon at half opacity was
   near-invisible on a phone, where its hover reveal also never fires. */
.sub-add-work {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 10px;
  background: var(--card);
  border: 2px solid var(--ink);
  font-family: inherit; font-size: 0.7rem; font-weight: 700;
  letter-spacing: 0.05em; text-transform: uppercase;
  color: var(--ink);
  cursor: pointer;
}
@media (hover: hover) { .sub-add-work:hover { background: var(--yellow); } }
.sub-add-work svg { width: 16px; height: 16px; stroke-width: 2.4; }

/* Links the parent adds to a finished quest (2026-09-11) — the child's link
   chip, wrapped so the delete cross can sit on its corner like a photo's. */
.sub-links { display: flex; flex-wrap: wrap; gap: 8px; margin: 8px 0 2px; }
.sub-link-wrap { position: relative; display: inline-flex; max-width: 100%; }
@media (hover: hover) { .sub-link-wrap:hover .sub-media-del { display: flex; } }
.confirm-form p { margin-bottom: 18px; }
.confirm-form .field { text-align: left; margin-bottom: 14px; }
.confirm-form .confirm-actions { margin-top: 22px; }

/* Undo on a finished row (2026-09-04) — same chip as Add photo, but the
   hover warns: this one takes stars away rather than adding to the record. */
@media (hover: hover) { .sub-undo:hover { background: var(--red); color: #fff; } }

/* Undo inside the child quest modal — visible only while the day is still
   submittable, styled as a quiet escape hatch under the Done! pill. */
.quest-undo-btn {
  display: inline-flex; align-items: center; gap: 6px;
  margin-top: 10px; padding: 8px 12px;
  background: var(--card);
  border: 2px solid var(--ink);
  font-family: inherit; font-size: 0.75rem; font-weight: 700;
  letter-spacing: 0.05em; text-transform: uppercase;
  color: var(--ink);
  cursor: pointer;
}
@media (hover: hover) { .quest-undo-btn:hover { background: var(--red); color: #fff; } }
.quest-undo-btn svg { width: 15px; height: 15px; stroke-width: 2.4; }
.rec-media { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.rec-img { width: 110px; height: 82px; object-fit: cover; border: 1px solid #999; }
.sub-link:hover { background: var(--green); }
.sub-link:active { transform: translate(3px, 3px); box-shadow: none; }
.sub-link svg { width: 13px; height: 13px; flex-shrink: 0; stroke-width: 2.6; }

/* --------------------------------------------------------------------------
   6. Kids view
   -------------------------------------------------------------------------- */
#child-view { display: flex; flex-direction: column; gap: 26px; }

/* The child's card in the kid rail — the parent rail's compact explorer card
   (decision 47, Tom: "make the kids name card look more like the more compact
   version thats on the parent dashboard"): .kid-card.active in the child's
   colour, the face, the name, a stars chip that still opens the shop, the
   streak beside it, and today's count as the same chip the parent sees. The
   old hero — ring round the face, big tilted pills — is gone; its ids live on
   in this markup, so renderChild is unchanged. The KIDS ZONE sticker came
   back the same day (Tom liked it): a small straight label on the top edge,
   matching the section stickers after decision 37, with the card's top
   padding grown so the greeting clears it. */
.child-card { --kid-color: var(--c); }
/* Two classes: the professional pass sets .kid-card padding later in the file. */
.kid-card.child-card { padding-top: 18px; }
.child-card::before {
  content: 'KIDS ZONE';
  position: absolute; top: -10px; left: 10px;
  padding: 3px 9px;
  background: var(--ink); color: var(--yellow);
  font-family: var(--font-display);
  font-size: 0.58rem; letter-spacing: 0.1em; line-height: 1.2;
}
.child-card .kid-text { padding-right: 0; }
/* Same size as the name (Tom, 2026-09-19: "at least the same size as the
   names") — the two lines read as one greeting, "Good afternoon, Leo". */
.child-card .greeting {
  margin-bottom: 1px;
  font-size: 0.95rem; font-weight: 700; line-height: 1.1;
  text-transform: uppercase; letter-spacing: 0.02em;
}
.child-card h4 { overflow-wrap: anywhere; }
.child-stats { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 4px; }
.child-stats .kid-streak { margin-left: 0; }
.stars-pill {
  position: relative;
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 8px;
  background: var(--yellow);
  border: 2px solid var(--ink);
  font-family: var(--font-display); font-size: 0.8rem; line-height: 1.4;
  color: var(--ink);
  cursor: pointer;
}
@media (hover: hover) { .stars-pill:hover { box-shadow: var(--shadow-xs); } }
.stars-pill:active { transform: translate(1px, 1px); box-shadow: none; }
.stars-pill svg { width: 12px; height: 12px; fill: var(--ink); stroke-width: 2.4; flex: none; }
.stars-pill-shop { fill: none !important; opacity: 0.75; }
.kid-streak { margin-left: 6px; font-weight: 700; white-space: nowrap; }

/* Quest sections */
.quests-section { display: flex; flex-direction: column; gap: 18px; }
.quests-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.quests-head h3 {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: var(--font-display);
  font-size: 1.25rem; text-transform: uppercase;
  background: var(--ink); color: #fff;
  padding: 9px 20px;
  transform: rotate(-1deg);
  box-shadow: 4px 4px 0 var(--c);
}
.quests-head h3 svg { width: 18px; height: 18px; stroke-width: 2.4; }

.quests-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 24px;
}

.quest-card {
  position: relative;
  display: flex; flex-direction: column; gap: 12px;
  padding: 24px 22px 20px;
  background: var(--card);
  border: var(--bw) solid var(--ink);
  box-shadow: var(--shadow);
  cursor: pointer;
  animation: pop 0.3s ease both;
  transition: transform 0.1s ease, box-shadow 0.1s ease;
}
@media (hover: hover) { .quest-card:hover { transform: translate(-3px, -3px); box-shadow: 9px 9px 0 var(--ink); } }
.quest-card:active { transform: translate(2px, 2px); box-shadow: var(--shadow-xs); }
.quest-card::before {
  content: '';
  position: absolute; top: -2px; left: -2px; right: -2px;
  height: 8px;
  background: var(--cat, var(--c));
  border: 2px solid var(--ink);
}
.quest-card.done { background: var(--bg); }
.quest-card.missed { background: var(--bg); opacity: 0.65; cursor: default; }
@media (hover: hover) { .quest-card.missed:hover { transform: none; box-shadow: var(--shadow); } }

.quest-card .q-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 4px; }
.quest-card .q-time {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--muted);
}
.quest-card .q-time svg { width: 13px; height: 13px; stroke-width: 2.6; }

.q-status {
  width: 32px; height: 32px;
  display: grid; place-items: center;
  border: 2px solid var(--ink);
  border-radius: 50%;
}
.q-status svg { width: 15px; height: 15px; stroke-width: 3; }
.q-status.todo { background: var(--card); }
.q-status.done { background: var(--green); }
.q-status.missed { background: var(--card); opacity: 0.6; }

.quest-card h4 {
  font-family: var(--font-display);
  font-size: 1.05rem;
  line-height: 1.3;
}

.quest-card .q-foot { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-top: auto; flex-wrap: wrap; }
.quest-card .q-go {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--ink); color: #fff;
  padding: 7px 14px;
  font-size: 0.72rem; font-weight: 700; text-transform: uppercase;
}
.quest-card .q-go svg { width: 13px; height: 13px; stroke-width: 2.6; }
@media (hover: hover) { .quest-card:hover .q-go { background: var(--c); color: var(--ink); } }

/* Topic deck editor (parent) */
.deck-add { display: flex; gap: 10px; margin-bottom: 18px; }
.deck-add input {
  flex: 1;
  min-width: 0; /* inputs have a large intrinsic minimum; without this the rewards form (two inputs + button) pushed the page wider than a phone */
  padding: 12px 14px;
  background: var(--card);
  border: var(--bw) solid var(--ink);
  font-size: 0.92rem;
}
.deck-add input:focus { outline: none; box-shadow: var(--shadow-xs); }
.deck-hint {
  margin: -4px 0 12px;
  font-size: 0.78rem; color: var(--muted);
}
/* Inside a form field the hint follows an input rather than a heading, so the
   negative tuck above would clamp it against the input's border. */
.field .deck-hint {
  margin: 8px 0 0;
  line-height: 1.45;
}
.deck-list { display: flex; flex-direction: column; gap: 10px; }
.deck-row {
  display: flex; align-items: center; gap: 14px;
  padding: 12px 16px;
  background: var(--card);
  border: var(--bw) solid var(--ink);
  box-shadow: var(--shadow-xs);
}
.deck-row.used { background: var(--bg); }
.deck-row .deck-text { flex: 1; font-weight: 700; min-width: 0; overflow-wrap: anywhere; }
/* The generic .deck-hint class assumes it trails a form input (negative top
   margin to tuck close underneath) — inside a topic row it needs its own
   line and normal weight instead, so the specific task doesn't compete with
   the bold topic text above it. */
.deck-row .deck-text .deck-hint { display: block; margin: 4px 0 0; font-weight: 500; }
.deck-row.used .deck-text { opacity: 0.6; }
.deck-row .deck-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.status-pill.in-deck { background: var(--green); }
.btn-sm { padding: 7px 12px; font-size: 0.72rem; box-shadow: none; }

@media (max-width: 720px) {
  .deck-row { flex-wrap: wrap; }
  .deck-row .deck-text { flex: 1 0 100%; }
}

/* Mystery Project roll — the one-big-button moment of the day */
.roll-box {
  width: 100%;
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 34px 24px;
  background: var(--cat-surprise);
  border: var(--bw) solid var(--ink);
  box-shadow: var(--shadow);
  text-align: center;
  transition: transform 0.1s ease, box-shadow 0.1s ease;
}
.roll-box:hover { transform: translate(-3px, -3px); box-shadow: 9px 9px 0 var(--ink); }
.roll-box:active { transform: translate(3px, 3px); box-shadow: var(--shadow-xs); }
.roll-dice { font-size: 2.6rem; line-height: 1; }
.roll-title {
  font-family: var(--font-display);
  font-size: 1.35rem; text-transform: uppercase; letter-spacing: 0.01em;
}
.roll-sub {
  font-size: 0.72rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.06em; opacity: 0.7;
}
@media (prefers-reduced-motion: no-preference) {
  .roll-box:hover .roll-dice { animation: rollWobble 0.6s ease-in-out infinite; }
}
@keyframes rollWobble {
  0%, 100% { transform: rotate(-8deg); }
  50%      { transform: rotate(8deg); }
}

/* Reading log */
/* ---- Child watchlist (read-only — the parent stocks it) ---- */
/* Chips, not cards: these are short titles, and a wrapping row keeps a list of
   a dozen shows to a couple of lines instead of a dozen 300px cards. */
.watch-hint {
  margin: -10px 0 0;
  font-size: 0.82rem; font-weight: 600; color: var(--muted);
}
.watch-list { display: flex; flex-wrap: wrap; gap: 12px; }
.watch-chip {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 11px 16px;
  background: var(--card);
  border: var(--bw) solid var(--ink);
  box-shadow: var(--shadow-xs);
  font-size: 0.92rem; font-weight: 700; line-height: 1.25;
  overflow-wrap: anywhere;
  animation: pop 0.3s ease both;
}
.watch-chip svg {
  width: 16px; height: 16px; stroke-width: 2.6;
  color: var(--c); flex-shrink: 0;
}
/* The empty state is a block in a flex row — without this it shrinks to its
   text and sits stranded on the left. */
.watch-list .empty-state { flex: 1 1 100%; }

.book-card {
  display: flex; flex-direction: column; gap: 10px;
  padding: 22px;
  background: var(--card);
  border: var(--bw) solid var(--ink);
  box-shadow: var(--shadow);
  animation: pop 0.3s ease both;
}
.book-card h4 { font-family: var(--font-display); font-size: 1.02rem; line-height: 1.3; }
.book-card .book-author { font-size: 0.8rem; font-weight: 600; color: var(--muted); }
.book-card .book-foot { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-top: auto; flex-wrap: wrap; }
.book-card .book-date { font-size: 0.68rem; font-weight: 700; text-transform: uppercase; color: var(--muted); }
.feeling-pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 12px;
  border: 2px solid var(--ink);
  font-size: 0.68rem; font-weight: 700; text-transform: uppercase;
}
.feeling-pill.ok    { background: var(--blue); }
.feeling-pill.good  { background: var(--green); }
.feeling-pill.loved { background: var(--pink); }
.feeling-pill.dnf   { background: var(--red); }
.book-card.unseen { background: #fff8e1; }

/* --------------------------------------------------------------------------
   7. Modals
   -------------------------------------------------------------------------- */
.backdrop {
  position: fixed; inset: 0; z-index: 900;
  background: rgba(20, 18, 14, 0.45);
}

.modal {
  position: fixed; z-index: 1000;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: min(560px, calc(100vw - 32px));
  max-height: min(88vh, 900px);
  overflow-y: auto;
  padding: 26px;
  background: var(--card);
  border: var(--bw) solid var(--ink);
  box-shadow: 10px 10px 0 var(--ink);
  animation: modalPop 0.18s ease both;
}
@keyframes modalPop {
  from { opacity: 0; transform: translate(-50%, -48%) scale(0.97); }
  to   { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}

.modal-head {
  display: flex; align-items: center; justify-content: space-between;
  margin: -26px -26px 22px;
  padding: 16px 20px;
  background: var(--yellow);
  border-bottom: var(--bw) solid var(--ink);
}
.modal-head h3 {
  display: flex; align-items: center; gap: 10px;
  font-family: var(--font-display);
  font-size: 1.05rem; text-transform: uppercase;
}
.modal-head h3 svg { width: 18px; height: 18px; stroke-width: 2.4; }

/* Forms */
form .field { margin-bottom: 18px; }
.form-row { display: flex; gap: 14px; }
.form-row .field { flex: 1; }

.field label {
  display: block;
  margin-bottom: 8px;
  font-size: 0.72rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.08em;
}
.field input, .field select, .field textarea {
  width: 100%;
  padding: 12px 14px;
  background: var(--bg);
  border: var(--bw) solid var(--ink);
  font-size: 0.92rem; font-weight: 500;
  outline: none;
}
.field input:focus, .field select:focus, .field textarea:focus {
  background: #fffbe8;
  box-shadow: var(--shadow-xs);
}
.field input::placeholder, .field textarea::placeholder { color: var(--muted); }
.field textarea { resize: vertical; line-height: 1.5; }
.field select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%2314120e' stroke-width='3' stroke-linecap='square'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 13px center;
}

/* Settings dropdowns live outside .field, so they need the same treatment. */
.settings-select {
  width: 100%;
  padding: 12px 14px;
  background: var(--bg);
  border: var(--bw) solid var(--ink);
  font-size: 0.92rem; font-weight: 600;
  outline: none;
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%2314120e' stroke-width='3' stroke-linecap='square'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 13px center;
}
.settings-select:focus { background-color: #fffbe8; box-shadow: var(--shadow-xs); }

.day-checks { display: flex; flex-wrap: wrap; gap: 8px; }
.day-chip {
  position: relative;
  display: flex; align-items: center; justify-content: center;
  min-width: 56px;
  padding: 8px 14px;
  background: var(--bg);
  border: 2px solid var(--ink);
  font-size: 0.78rem; font-weight: 700; text-transform: uppercase;
  text-align: center;
  cursor: pointer;
  transition: transform 0.08s ease, box-shadow 0.08s ease, background 0.08s ease;
}
.day-chip input { position: absolute; opacity: 0; pointer-events: none; }
.day-chip:has(input:checked) { background: var(--green); }

/* Repeat / one-time recurrence toggle (add-session form).
   Selectors are scoped under .recur-toggle so they out-specify `.field label`
   (which would otherwise force display:block and kill the flex gap). */
.recur-toggle { display: flex; gap: 8px; }
.recur-toggle .recur-opt {
  position: relative;
  flex: 1;
  display: flex; align-items: center; justify-content: center; gap: 12px;
  margin-bottom: 0;
  padding: 11px 16px;
  background: var(--bg);
  border: 2px solid var(--ink);
  font-size: 0.78rem; font-weight: 700; text-transform: uppercase;
  cursor: pointer;
  transition: transform 0.08s ease, box-shadow 0.08s ease, background 0.08s ease;
}
.recur-toggle .recur-opt svg { width: 15px; height: 15px; stroke-width: 2.6; flex-shrink: 0; }
.recur-toggle .recur-opt input { position: absolute; opacity: 0; pointer-events: none; }
.recur-toggle .recur-opt:has(input:checked) { background: var(--yellow); box-shadow: var(--shadow-xs); }

.avatar-picker { display: flex; align-items: flex-start; gap: 20px; width: 100%; }
.avatar-picker > div { flex: 1; min-width: 0; }
.avatar-picker-help { margin: 0 0 8px; font-size: 0.78rem; font-weight: 600; color: var(--muted); }
.avatar-options { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; }
.avatar-option {
  display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 9px;
  min-width: 0; min-height: 154px; padding: 12px 7px; background: var(--bg);
  border: 2px solid var(--ink); cursor: pointer; font: inherit;
  transition: transform .08s ease, box-shadow .08s ease, background .08s ease;
}
.avatar-option img { width: 94px; height: 94px; border-radius: 50%; background: var(--card); filter: drop-shadow(0 3px 0 rgba(20,18,14,.18)); }
.avatar-option span { max-width: 100%; font-size: .78rem; font-weight: 700; line-height: 1.1; text-align: center; }
.avatar-option.selected { background: var(--yellow); transform: translate(-2px, -2px); box-shadow: 4px 4px 0 var(--ink); }
@media (hover: hover) { .avatar-option:hover { background: var(--yellow); transform: translate(-2px, -2px); box-shadow: 4px 4px 0 var(--ink); } }
.avatar-option-upload { border-style: dashed; }
.avatar-option-upload.selected { border-style: solid; }
.avatar-option-upload svg { width: 34px; height: 34px; stroke-width: 1.8; color: var(--muted); }
.avatar-option-upload img { object-fit: cover; }

.theme-picker { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; }
.theme-opt {
  position: relative;
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 14px 8px;
  background: var(--bg);
  border: var(--bw) solid var(--ink);
  cursor: pointer;
  font-size: 0.72rem; font-weight: 700; text-transform: uppercase;
  transition: transform 0.08s ease, box-shadow 0.08s ease;
}
.theme-opt input { position: absolute; opacity: 0; pointer-events: none; }
.theme-opt svg { width: 20px; height: 20px; stroke-width: 2.4; }
.theme-opt-blue    { --to: var(--blue); }
.theme-opt-green   { --to: var(--green); }
.theme-opt-pink    { --to: var(--pink); }
.theme-opt-orange  { --to: var(--orange); }
.theme-opt-red     { --to: var(--red); }
.theme-opt-yellow  { --to: var(--yellow-theme); }
.theme-opt-lilac   { --to: var(--lilac); }
.theme-opt-teal    { --to: var(--teal); }
.theme-opt:hover { background: var(--card); }
.theme-opt:has(input:checked) {
  background: var(--to);
  box-shadow: var(--shadow-sm);
  transform: rotate(-2deg);
}

.feeling-picker { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; }
.feeling-opt {
  position: relative;
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 16px 8px;
  background: var(--bg);
  border: var(--bw) solid var(--ink);
  cursor: pointer;
  font-size: 0.74rem; font-weight: 700; text-transform: uppercase;
  text-align: center;
  transition: transform 0.08s ease, box-shadow 0.08s ease;
}
.feeling-opt input { position: absolute; opacity: 0; pointer-events: none; }
.feeling-emoji { font-size: 1.8rem; line-height: 1; }
.feeling-opt-ok    { --fo: var(--blue); }
.feeling-opt-good  { --fo: var(--green); }
.feeling-opt-loved { --fo: var(--pink); }
.feeling-opt-dnf   { --fo: var(--red); }
.feeling-opt:hover { background: var(--card); }
.feeling-opt:has(input:checked) {
  background: var(--fo);
  box-shadow: var(--shadow-sm);
  transform: rotate(-2deg);
}

/* Custom on-brand date picker (used by the reading-log form) */
.date-picker-wrap { position: relative; }
.date-picker-btn {
  display: flex; align-items: center; gap: 10px;
  width: 100%;
  padding: 12px 14px;
  background: var(--bg);
  border: var(--bw) solid var(--ink);
  font-size: 0.92rem; font-weight: 600;
  cursor: pointer; text-align: left;
  transition: background 0.08s ease;
}
.date-picker-btn:hover { background: var(--card); }
.date-picker-btn svg { width: 16px; height: 16px; stroke-width: 2.6; color: var(--muted); flex-shrink: 0; }

.date-picker-pop {
  position: absolute; z-index: 50; top: calc(100% + 8px); left: 0;
  width: 280px;
  background: var(--card);
  border: var(--bw) solid var(--ink);
  box-shadow: var(--shadow);
  padding: 14px;
}
.date-picker-head {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 12px;
}
.date-picker-head span {
  font-family: var(--font-display);
  font-size: 0.8rem; text-transform: uppercase;
}
.date-picker-head .icon-btn { width: 28px; height: 28px; }
.date-picker-head .icon-btn svg { width: 13px; height: 13px; }
.date-picker-dow {
  display: grid; grid-template-columns: repeat(7, 1fr);
  margin-bottom: 6px;
}
.date-picker-dow span {
  text-align: center;
  font-size: 0.62rem; font-weight: 700; text-transform: uppercase;
  color: var(--muted);
}
.date-picker-grid {
  display: grid; grid-template-columns: repeat(7, 1fr);
  gap: 4px;
}
.date-picker-day {
  aspect-ratio: 1;
  display: grid; place-items: center;
  font-size: 0.8rem; font-weight: 700;
  background: var(--bg);
  border: 2px solid transparent;
  cursor: pointer;
  transition: transform 0.08s ease, background 0.08s ease;
}
.date-picker-day:hover:not(:disabled) { border-color: var(--ink); }
.date-picker-day.other-month { color: var(--muted); opacity: 0.4; }
.date-picker-day.today { border-color: var(--ink); }
.date-picker-day.selected { background: var(--c); border-color: var(--ink); box-shadow: var(--shadow-xs); }
.date-picker-day:disabled { cursor: default; }

.link-row { display: flex; gap: 10px; margin-bottom: 10px; }
.link-row input { flex: 1; padding: 10px 12px; font-size: 0.85rem; background: var(--bg); border: var(--bw) solid var(--ink); outline: none; }
.link-row input:focus { background: #fffbe8; }
.link-row .icon-btn { flex-shrink: 0; align-self: center; }

.modal-actions {
  display: flex; justify-content: flex-end; gap: 12px;
  margin-top: 24px;
}
.modal-actions .btn-delete { margin-right: auto; }
.btn-delete:hover { background: var(--red); color: #fff; }

/* Quest modal (kids) */
.quest-modal { width: min(600px, calc(100vw - 32px)); }
.quest-head {
  background: var(--c);
  margin: -26px -26px 20px;
  padding: 16px 20px;
  border-bottom: var(--bw) solid var(--ink);
  display: flex; align-items: center; justify-content: space-between;
}
.quest-title {
  font-family: var(--font-display);
  font-size: 1.5rem; text-transform: uppercase;
  line-height: 1.15;
  margin-bottom: 10px;
}
.quest-time {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 0.75rem; font-weight: 700; text-transform: uppercase;
  background: var(--yellow);
  border: 2px solid var(--ink);
  padding: 5px 12px;
  margin-bottom: 16px;
  transform: rotate(-1deg);
}
.quest-time svg { width: 14px; height: 14px; stroke-width: 2.6; }
.quest-desc {
  font-size: 0.95rem; font-weight: 500; line-height: 1.6;
  padding: 14px 18px;
  background: var(--bg);
  border: 2px solid var(--ink);
  border-left: 8px solid var(--ink);
  margin-bottom: 18px;
}

/* Sits right under the pick it belongs to, not floating loose — pulled up
   into quest-desc's own bottom margin rather than adding a second gap. */
.quest-shuffle-btn { margin: -10px 0 18px; }

.quest-links-section { margin-bottom: 18px; }
.quest-links-section h4, .quest-submit h4 {
  display: flex; align-items: center; gap: 8px;
  font-family: var(--font-display);
  font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.05em;
  margin-bottom: 12px;
}
.quest-links-section h4 svg, .quest-submit h4 svg { width: 15px; height: 15px; stroke-width: 2.6; }
#quest-links { display: flex; flex-wrap: wrap; gap: 10px; }

.quest-link-chip {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 10px 16px;
  background: var(--blue);
  border: 2px solid var(--ink);
  box-shadow: var(--shadow-xs);
  font-size: 0.85rem; font-weight: 700;
  text-decoration: none;
  transition: transform 0.08s ease, box-shadow 0.08s ease;
}
.quest-link-chip:hover { background: var(--green); }
.quest-link-chip:active { transform: translate(3px, 3px); box-shadow: none; }
.quest-link-chip svg { width: 14px; height: 14px; stroke-width: 2.6; }

.quest-submit { margin-bottom: 6px; }
.quest-submit input, .quest-submit textarea {
  width: 100%;
  padding: 12px 14px;
  background: var(--bg);
  border: var(--bw) solid var(--ink);
  font-size: 0.9rem; font-weight: 500;
  outline: none;
  margin-bottom: 12px;
}
.quest-submit input:focus, .quest-submit textarea:focus { background: #fffbe8; box-shadow: var(--shadow-xs); }
.quest-submit textarea { resize: vertical; }

.quest-status {
  display: flex; flex-direction: column; gap: 12px;
  padding: 16px 18px;
  background: var(--bg);
  border: 2px solid var(--ink);
  font-size: 0.9rem; font-weight: 500; line-height: 1.5;
}
.quest-status .status-pill { align-self: flex-start; }
.quest-status a { font-weight: 700; word-break: break-all; }

.btn-done {
  width: 100%;
  justify-content: center;
  padding: 16px;
  background: var(--c);
  border: var(--bw) solid var(--ink);
  box-shadow: var(--shadow);
  font-family: var(--font-display);
  font-size: 1.1rem; text-transform: uppercase;
  transition: transform 0.08s ease, box-shadow 0.08s ease;
}
.btn-done:hover:not(:disabled) { background: var(--green); }
.btn-done:active:not(:disabled) { transform: translate(5px, 5px); box-shadow: none; }
.btn-done:disabled { background: var(--bg); cursor: default; box-shadow: var(--shadow-xs); }
.btn-done svg { width: 19px; height: 19px; stroke-width: 2.6; }

/* --------------------------------------------------------------------------
   Custom Confirm Dialog
   -------------------------------------------------------------------------- */
.confirm-overlay {
  position: fixed; inset: 0;
  background: rgba(20, 18, 14, 0.6);
  display: grid; place-items: center;
  z-index: 9999;
  animation: fadeIn 0.15s ease;
}
.confirm-overlay.hidden { display: none; }
.confirm-box {
  background: var(--bg);
  border: var(--bw) solid var(--ink);
  box-shadow: 8px 8px 0 var(--ink);
  padding: 32px 36px;
  max-width: 440px;
  width: 90%;
  text-align: center;
  animation: confirmPop 0.2s ease;
}
.confirm-icon {
  width: 52px; height: 52px;
  background: var(--yellow);
  border: var(--bw) solid var(--ink);
  box-shadow: var(--shadow-xs);
  display: grid; place-items: center;
  margin: 0 auto 18px;
  transform: rotate(-3deg);
}
.confirm-icon svg { width: 26px; height: 26px; stroke-width: 2.4; }
.confirm-box p {
  font-size: 1rem; font-weight: 600;
  line-height: 1.5;
  margin-bottom: 24px;
}
.confirm-actions {
  display: flex; gap: 12px; justify-content: center;
}
.confirm-actions-3 { flex-wrap: wrap; }

@keyframes confirmPop {
  from { transform: scale(0.9) translateY(10px); opacity: 0; }
  to { transform: scale(1) translateY(0); opacity: 1; }
}

/* --------------------------------------------------------------------------
   8. Toasts
   -------------------------------------------------------------------------- */
#toast-root {
  position: fixed;
  bottom: 24px; right: 24px;
  z-index: 1200;
  display: flex; flex-direction: column; gap: 12px;
  pointer-events: none;
}
.toast {
  display: flex; align-items: center; gap: 11px;
  padding: 14px 20px;
  background: var(--card);
  border: var(--bw) solid var(--ink);
  box-shadow: var(--shadow);
  font-size: 0.88rem; font-weight: 700;
  animation: toastIn 0.22s ease both;
}
.toast.out { animation: toastOut 0.2s ease both; }
.toast svg { width: 18px; height: 18px; flex-shrink: 0; stroke-width: 2.6; }
.toast.success { background: var(--green); }
.toast.star { background: var(--yellow); }
.toast.star svg { fill: var(--ink); }

@keyframes toastIn {
  from { opacity: 0; transform: translateX(24px); }
  to   { opacity: 1; transform: none; }
}
@keyframes toastOut {
  to { opacity: 0; transform: translateX(24px); }
}

/* --------------------------------------------------------------------------
   9. Responsive
   -------------------------------------------------------------------------- */
/* Narrow windows (under 1020px): the rail becomes a drawer, opened from the
   top bar's menu button (681-1020px) or the phone bar's Menu (decision 35).
   Full height, over the top bar, like the lesson pages' own drawer. z 850 is
   under the modal backdrop (900): Settings and the kid form shut the drawer
   before they open, and a modal must never end up beneath it. */
@media (max-width: 1020px) {
  .parent-layout { grid-template-columns: minmax(0, 1fr); }
  .sidebar {
    position: fixed; top: 0; left: 0; bottom: 0; z-index: 850;
    width: min(320px, 88vw); max-height: none;
    margin: 0;
    padding: calc(14px + env(safe-area-inset-top)) 16px calc(16px + env(safe-area-inset-bottom));
    box-sizing: border-box;
    background: var(--card);
    border-right: var(--bw) solid var(--ink);
    transform: translateX(-104%);
    /* Shut, it is hidden as well as off-screen: out of the tab order and the
       accessibility tree (Codex). The visibility flip waits for the slide. */
    visibility: hidden;
    transition: transform 0.18s ease, visibility 0s linear 0.18s;
  }
  body.rail-open .sidebar {
    transform: none; visibility: visible;
    transition: transform 0.18s ease, visibility 0s;
    box-shadow: 8px 0 0 rgb(20 18 14 / 0.16);
  }
  body.rail-open { overflow: hidden; }
  /* The rail lives inside <main>, which is its own stacking context at z 1 —
     so its 850 counted only against its siblings, and the sticky top bar
     (100) and the Nova dock (300) painted over the drawer and its close
     button (Codex round 2). While the drawer is open, main itself rises above
     both; the modal backdrop (900) and modals (1000) still win, and the page
     can't scroll, so main's content never rides up over the bar. */
  body.rail-open main { z-index: 850; }
}
/* The record export shares z 300 with the Nova dock and comes earlier in the
   DOM, so the dock (and an open help panel) painted over the document and
   stayed clickable (Codex round 3; pre-dated the rail). Nothing of Nova's
   belongs on that screen. */
body.record-open #nova-dock, body.record-open #nova-help { display: none !important; }
@media (max-width: 1020px) {
  .rail-backdrop { display: none; position: fixed; inset: 0; z-index: 840; background: rgb(20 18 14 / 0.45); }
  body.rail-open .rail-backdrop { display: block; }
  body.has-rail .rail-toggle:not(.hidden) { display: grid; }
}
/* Both rules, or the open state's own transition outranks this one (Codex round 4). */
@media (prefers-reduced-motion: reduce) { .sidebar, body.rail-open .sidebar { transition: none; } }

@media (max-width: 680px) {
  main { padding: 20px 14px 70px; }
  .topbar { padding: 12px 16px; flex-wrap: wrap; }
  .brand > #header-subtitle { display: none; }
  .mode-toggle button span { display: none; }
  .mode-toggle button { padding: 10px 14px; }
  .session-row { grid-template-columns: 1fr; gap: 12px; }
  .session-bar { display: none; }
  .session-row.today-row { grid-template-columns: 1fr; }
  .session-row.slim { grid-template-columns: auto minmax(0, 1fr) auto; gap: 10px; padding: 10px 12px 10px 8px; }
  .today-prep-row { grid-template-columns: minmax(0, 1fr); gap: 6px; }
  .today-prep-label { padding-top: 0; }
  .session-time { text-align: left; display: flex; align-items: center; gap: 12px; }
  .form-row { flex-direction: column; gap: 0; }
  .theme-picker { grid-template-columns: repeat(2, 1fr); }
  #toast-root { left: 14px; right: 14px; bottom: 14px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

/* --------------------------------------------------------------------------
   Record of education
   Deliberately NOT in the app's neo-brutalist system. This is the one screen
   someone outside the family might read, and cream dot-grid with hard yellow
   shadows would undercut it. Plain document: white paper, serif headings,
   black on white, no decoration.
   -------------------------------------------------------------------------- */
.record-view {
  position: fixed; inset: 0; z-index: 300;
  overflow-y: auto; background: #f1f1ee; padding: 0 0 4rem;
}
body.record-open { overflow: hidden; }

.record-toolbar {
  position: sticky; top: 0; z-index: 2;
  display: flex; justify-content: space-between; align-items: center; gap: 1rem;
  padding: 0.75rem 1.25rem;
  background: var(--ink); border-bottom: 3px solid var(--ink);
}

.record-paper {
  max-width: 46rem; margin: 2rem auto; padding: 3.5rem 3rem;
  background: #fff; color: #14110f;
  font-family: 'Space Grotesk', system-ui, sans-serif;
  font-size: 0.94rem; line-height: 1.6;
  box-shadow: 0 2px 18px rgba(0, 0, 0, 0.12);
}
.record-paper h1, .record-paper h2 {
  font-family: 'Fraunces', Georgia, serif; font-weight: 800; color: #14110f;
}
.record-paper h1 { font-size: 1.9rem; margin: 0 0 0.4rem; }
.record-paper h2 {
  font-size: 1.05rem; margin: 0 0 0.75rem;
  padding-bottom: 0.35rem; border-bottom: 1px solid #14110f;
  text-transform: uppercase; letter-spacing: 0.06em;
}
.record-paper section { margin-top: 2.25rem; }

.rec-head { border-bottom: 3px solid #14110f; padding-bottom: 1.25rem; }
/* A letterhead, not a banner: the logo small and first, the brand line last
   (2026-09-20). The document stays plain — decision 14. */
.rec-logo { display: block; height: 30px; width: auto; margin: 0 0 1.4rem; }
.rec-note { margin: -0.25rem 0 0.75rem; font-size: 0.82rem; color: #5c5750; }
.rec-approach p { margin: 0 0 0.75rem; }
.rec-approach p:last-child { margin-bottom: 0; }
.rec-approach h3 {
  font-family: 'Space Grotesk', system-ui, sans-serif; font-size: 0.74rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.07em; color: #5c5750; margin: 1.1rem 0 0.3rem;
}
.rec-approach h3:first-child { margin-top: 0; }
/* The export modal's prompts: a plain group, the fields it already has. */
.record-questions { border: var(--bw) solid var(--ink); padding: 14px 16px 4px; margin: 0 0 14px; }
.record-questions legend { font-weight: 700; font-size: 0.9rem; padding: 0 6px; }
.record-questions .field { margin-bottom: 12px; }
.record-questions textarea { min-height: 0; }
.rec-examples { color: #4a453f; font-size: 0.86rem; }
.rec-week td:first-child { width: 7rem; }
.rec-log-day td:first-child, .rec-log-week td:first-child { width: 7.5rem; }
.rec-detail div + div { margin-top: 0.15rem; }
.rec-table .rec-week-row th {
  padding: 1.1rem 0 0.35rem; border-bottom: 1px solid #14110f;
  font-size: 0.74rem; letter-spacing: 0.07em; color: #14110f;
}
.rec-resources { margin: 0; padding: 0 0 0 1.1rem; columns: 2; column-gap: 2rem; }
.rec-resources li { break-inside: avoid; margin: 0 0 0.25rem; }
.rec-count { color: #5c5750; font-size: 0.8rem; }
.rec-foot-brand { display: flex; align-items: center; gap: 0.45rem; margin-top: 0.6rem !important; }
.rec-foot-brand img { width: 18px; height: 18px; }
.rec-sub { margin: 0 0 0.3rem; font-size: 1.05rem; }
.rec-meta { margin: 0; font-size: 0.8rem; color: #5c5750; }

.rec-stats { display: flex; flex-wrap: wrap; gap: 1.75rem; }
.rec-stats div { display: flex; flex-direction: column; }
.rec-stats strong { font-family: 'Fraunces', Georgia, serif; font-size: 1.7rem; line-height: 1; }
.rec-stats span { font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.06em; color: #5c5750; }

.rec-table { width: 100%; border-collapse: collapse; }
.rec-table th {
  text-align: left; font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.07em;
  color: #5c5750; font-weight: 600; padding: 0 0.6rem 0.4rem 0; border-bottom: 1px solid #c8c3bb;
}
.rec-table td { padding: 0.5rem 0.6rem 0.5rem 0; border-bottom: 1px solid #eae6df; vertical-align: top; }
.rec-table td:last-child, .rec-table th:last-child { padding-right: 0; }
.rec-date { white-space: nowrap; color: #5c5750; font-variant-numeric: tabular-nums; }
.rec-detail { font-size: 0.84rem; color: #4a453f; margin-top: 0.2rem; }
.rec-detail a { color: #4a453f; }
.rec-empty { color: #5c5750; font-style: italic; margin: 0; }

.rec-foot {
  margin-top: 2.5rem; padding-top: 1rem; border-top: 1px solid #c8c3bb;
  font-size: 0.78rem; color: #5c5750;
}
.rec-foot p { margin: 0; }

/* Filled worksheets embedded in the record (Option A, 2026-09-21). Each
   .rec-sheet is a shadow host carrying one sheet's real pages with the
   worksheet's own CSS, isolated from the record around it. */
.rec-worksheets { margin-top: 2rem; }
.rec-sheet-block { margin: 1.5rem 0 2rem; }
.rec-sheet-head {
  font-family: 'Instrument Serif', Georgia, serif; font-size: 1.05rem; font-weight: 400;
  margin: 0 0 0.6rem; color: #14110f;
}
.rec-sheet { border: 1px solid #d8d3ca; background: #fff; overflow: hidden; }

@media (max-width: 700px) {
  .record-paper { margin: 0; padding: 2rem 1.25rem; box-shadow: none; }
}

/* Print: the record is the only thing on the page. Without this the app's
   fixed topbar, sidebar and dock all land on the paper. */
@media print {
  body.record-open > *:not(.record-view) { display: none !important; }
  /* The app's dot-grid canvas is the body's background; with "background
     graphics" ticked it printed under the record's last page. */
  body.record-open { background: #fff !important; }
  .no-print { display: none !important; }
  .record-view { position: static; overflow: visible; background: #fff; padding: 0; }
  .record-paper { margin: 0; padding: 0; max-width: none; box-shadow: none; font-size: 10.5pt; }
  .record-paper section { break-inside: auto; }
  .rec-table tr { break-inside: avoid; }
  .record-paper h2 { break-after: avoid; }
  .rec-table .rec-week-row th { break-after: avoid; }
  .rec-resources { columns: 2; }
  /* The worksheet appendix starts on a fresh page, and each sheet after the
     first gets its own. The status line is on-screen only. */
  .rec-worksheets { break-before: page; }
  .rec-sheet-block + .rec-sheet-block { break-before: page; }
  .rec-sheet-head { break-after: avoid; }
  .rec-worksheet-status { display: none !important; }
  /* overflow:hidden on screen frames each sheet; in print it would clip the
     shadow content across page breaks (Codex). */
  .rec-sheet { border: 0; overflow: visible; }
}

/* Erasure section — visually separated so it can't be mistaken for the
   routine settings above it. */
.settings-danger { border-top: 3px solid var(--ink); padding-top: 18px; }
.settings-danger h4 { color: var(--red); }

/* --------------------------------------------------------------------------
   iPhone-quality mobile pass (2026-07-21)
   The earlier ≤680 rules made things FIT; this makes them feel native. Kept as
   one block, appended so it wins the cascade over the older ≤680 rules.
   -------------------------------------------------------------------------- */

/* Touch polish, all sizes: kill the grey iOS tap flash (the hard-shadow
   :active states are the app's own press feedback) and the double-tap-to-zoom
   delay on controls. Harmless on desktop. */
button, a, label, input, select, textarea { -webkit-tap-highlight-color: transparent; }
button, a, .day-tab, .tabs button { touch-action: manipulation; }

@media (max-width: 680px) {
  /* ---- Topbar: one compact row, not two -------------------------------
     The brand row + switcher chip stacked to ~290px of sticky yellow — over a
     third of an iPhone screen, on every scroll position. One 60-ish px row. */
  .topbar {
    flex-wrap: nowrap;
    padding: 8px 14px;
    padding-top: calc(8px + env(safe-area-inset-top));
  }
  .brand { flex: 0 1 auto; min-width: 0; }
  /* .brand-logo keeps its desktop height: 58px, which is what actually sets
     the bar's height — so the mark can fill that box rather than floating at
     34px inside 24px of dead headroom. Bigger logo, identical yellow bar. */
  .brand-nova { width: 52px; height: 52px; }
  .brand-wordmark img { height: 26px; margin-top: 11px; }
  #kid-switcher-btn { padding: 7px 12px; }
  #kid-switcher-btn .avatar-xs { width: 24px; height: 24px; }

  /* ---- Day strip: one scrollable row ----------------------------------
     Wrapping to a second ragged row is the single most "shrunken desktop"
     thing on the page. Native pattern instead: a single row that scrolls
     horizontally, bleeds to the screen edge, snaps per chip, no scrollbar.
     JS centres the active day after each render. */
  .day-strip {
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x proximity;
    scrollbar-width: none;
    /* bleed through main's 14px gutters so chips scroll to the glass edge */
    margin-inline: -14px;
    padding-inline: 14px;
  }
  .day-strip::-webkit-scrollbar { display: none; }
  .day-tab { flex: 0 0 auto; scroll-snap-align: center; }
  .day-tab { min-width: 76px; }
  /* Hard offset shadows on the active chip need headroom inside a scroll
     container, or the shadow clips at the container edge. */
  .day-strip { padding-top: 4px; padding-bottom: 14px; }

  /* ---- Modals become bottom sheets ------------------------------------
     A centred dialog is a desktop idiom; on a phone the native gesture-space
     is the bottom. Full width, rounded top corners only, slide-up entrance,
     borders kept top-only so the sheet reads as rising from the frame. */
  .modal {
    top: auto; bottom: 0; left: 0; right: 0;
    transform: none;
    width: 100%;
    max-height: 90dvh;
    border-left: 0; border-right: 0; border-bottom: 0;
    border-radius: 16px 16px 0 0;
    box-shadow: 0 -8px 0 rgb(20 18 14 / 0.14);
    padding: 22px 18px;
    padding-bottom: calc(22px + env(safe-area-inset-bottom));
    overscroll-behavior: contain;
    animation: sheetUp 0.24s cubic-bezier(0.2, 0.8, 0.3, 1);
  }
  @keyframes sheetUp {
    from { transform: translateY(28px); opacity: 0; }
    to   { transform: none; opacity: 1; }
  }

  /* ---- iOS input zoom -------------------------------------------------
     Safari auto-zooms the whole page when a focused input's font is under
     16px, then leaves it zoomed. 16px kills that outright. */
  input, select, textarea { font-size: 16px; }

  /* ---- Respect the home indicator ------------------------------------ */
  .nova-dock { bottom: calc(14px + env(safe-area-inset-bottom)); }
  #toast-root { bottom: calc(14px + env(safe-area-inset-bottom)); }
  main { padding-bottom: calc(70px + env(safe-area-inset-bottom)); }
}

/* --------------------------------------------------------------------------
   Compact child hero (2026-07-21)
   Tom's screenshot was ~960px — between the phone rules (<=680) and desktop —
   where the hero still ran full-size and sprawled across two airy rows. Shrink
   the pieces below laptop width and the card pulls itself into one tight row;
   phones tighten further. Appended so it wins the cascade.
   -------------------------------------------------------------------------- */
@media (max-width: 1020px) {
  /* (The compact-hero sizes that used to live here went with the banner —
     the child's card is in the kid rail now, decision 36.) */

  /* Parent day strip wrapped SAT/SUN onto a stretched second row at this
     width — same fix as the phone strip: one row, scroll, snap, no bar. */
  .day-strip { flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch;
               scroll-snap-type: x proximity; scrollbar-width: none;
               padding-top: 4px; padding-bottom: 14px; }
  .day-strip::-webkit-scrollbar { display: none; }
  .day-tab { flex: 0 0 auto; scroll-snap-align: center; }
}

/* The 2026-09-03 phone roster strip (sidebar as a row of face-only chips,
   Settings as a gear beside it) is gone: below 1020px the whole rail is a
   drawer now (decision 35), so the roster keeps its desktop column layout. */

@media (max-width: 680px) {
  /* The explorer line shows on phones again (2026-09-17, decision 35): the
     roster that used to sit above it is in the drawer now, so this is the
     only place Timetable and Completed name the child they are about, and
     tapping it opens the drawer to switch (renderExplorerLine). */
  .explorer-line { padding: 6px 12px 6px 8px; }
  /* One line, not two shouting ones — the day strip above already carries
     the date, so this is a label, not a headline. */
  .schedule-head h3 { font-size: 1.15rem; }
  .schedule-head { gap: 10px; }
}

/* --------------------------------------------------------------------------
   Bottom bar — phones, parent mode (2026-09-03; reworked 2026-09-17, decision
   35). On a phone the thumb zone is the bottom, so the three daily sections
   and a Menu button sit in a fixed bar there — the rail itself is the drawer
   Menu opens. The bar lives inside #parent-view, so it vanishes with it in
   kid mode / the picker / the record view; z 200 keeps it under the drawer
   (850), the backdrop (900) and modals (1000).
   -------------------------------------------------------------------------- */
.phone-bar { display: none; }
@media (max-width: 680px) {
  body.has-rail .phone-bar {
    display: flex;
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 200;
    margin: 0;
    padding: 8px 8px calc(8px + env(safe-area-inset-bottom));
    background: var(--card);
    border-top: var(--bw) solid var(--ink);
    gap: 6px;
  }
  .phone-bar button {
    position: relative;
    display: flex; flex: 1 1 0; min-width: 0;
    flex-direction: column; align-items: center; justify-content: center;
    gap: 4px;
    padding: 7px 2px;
    background: var(--card);
    border: 2px solid var(--ink);
    font-size: 0.5rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.02em;
  }
  .phone-bar button svg { width: 19px; height: 19px; stroke-width: 2.6; }
  .phone-bar button.active { background: var(--green); }
  .phone-bar .phone-menu-icon { display: contents; }
  /* Count pills ride the button's corner instead of wrapping under the label. */
  .phone-bar button .badge { position: absolute; top: -6px; right: 4px; }

  /* Everything that used to own the bottom edge clears the bar. */
  body.has-rail main { padding-bottom: calc(96px + env(safe-area-inset-bottom)); }
  body.has-rail .nova-dock { bottom: calc(86px + env(safe-area-inset-bottom)); }
  body.has-rail #toast-root { bottom: calc(96px + env(safe-area-inset-bottom)); }
  /* Menu on the bar opens the drawer; no second trigger in the top bar. */
  body.has-rail .rail-toggle:not(.hidden) { display: none; }
}


/* The child's card in the kid rail is the compact explorer card — see
   .child-card in section 6 (decision 47). */
/* The child's colour marks the open section, as it does everything else here. */
.kid-rail .tabs button.active { background: var(--c); }
.kid-main .tab-panel { display: flex; flex-direction: column; gap: 26px; }

/* --------------------------------------------------------------------------
   Phone child page: week nav and day strip pulled tight (2026-09-04, Tom:
   "tighten those too", right after the hero)
   Between the hero and the first quest card sat ~255px on a 360-wide phone:
   the 26px section gap three times over, a week nav carrying its own 12px
   margin, and day chips stacked three-high (day / date / count) inside a
   strip padded 4px + 14px for the active chip's shadow. Chips go single-row
   (FRI 4 ②), the same shape as the parent's strip; the strip keeps only the
   headroom the today-dot (6px above) and the shadow (4px below) need; the
   sections sit 16px apart. Appended so it wins the cascade.
   -------------------------------------------------------------------------- */
@media (max-width: 680px) {
  #child-view { gap: 16px; }
  .week-nav { margin-bottom: 0; gap: 10px; }
  .week-nav span { min-width: 0; font-size: 0.8rem; }
  /* Timetable head on a phone: the date on its own line, then Export record
     and Add session share the second at .btn-sm size (decision 47 moved the
     export here from the retired Completed tab). */
  #panel-timetable .schedule-head { flex-wrap: wrap; }
  #panel-timetable .schedule-head h3 { width: 100%; }
  #panel-timetable .schedule-head .btn { padding: 8px 12px; font-size: 0.75rem; }
  .row-body { padding-left: 0; }
  .day-strip.stacked { padding-top: 8px; padding-bottom: 8px; }
  .day-strip.stacked .day-tab {
    flex-direction: row; align-items: baseline; gap: 6px;
    padding: 8px 10px;
  }
  .day-strip.stacked .day-tab .day-date { font-size: 0.7rem; }
  .day-strip.stacked .day-tab .count { align-self: center; }
}


/* ==========================================================================
   Professional pass (2026-09-17, Tom: "make this look like a professional
   platform — check the layout and spacing. What would the big names in the
   space do?")
   Skool, Teachable and Kajabi share three habits this app lacked: ONE
   elevation rule (resting surfaces are flat; only what you can press or have
   picked carries a shadow), ONE spacing scale (4/8/12/16/24/32) and a quiet
   canvas (a slim header, a faint texture, 2px lines). The brand stays — ink
   borders, hard offset shadows, the display face — but each is now used for
   one job instead of everywhere at once. Appended so it wins the cascade;
   the earlier rules still describe the pieces.
   ========================================================================== */
:root { --bw: 2px; --rail-w: 296px; }
body { background-image: radial-gradient(rgb(20 18 14 / 0.16) 1px, transparent 1.4px); }

/* 1. Header: 72px, not 90. The logo keeps its 58:30 ratio (decision 30),
   scaled to 48:25 with the same one-sided nudge (10px moves the word 5px). */
.topbar { border-bottom-width: 3px; }
@media (min-width: 681px) { .topbar { padding: 10px 28px; } }   /* the phone block keeps its safe-area padding */
.brand { gap: 12px; }
.brand-logo { height: 48px; gap: 6px; }
.brand-nova { width: 48px; height: 48px; }
.brand-wordmark img { height: 25px; margin-top: 10px; }
.brand > #header-subtitle { font-size: 0.64rem; }
#kid-switcher-btn { padding: 6px 14px 6px 7px; }

/* 2. Elevation: flat at rest, lifted on hover, marked when picked. Primary
   buttons keep a small shadow because they are the things you press. */
.session-row, .session-row.slim, .quest-card, .book-card, .reward-card,
.explorer-line, .today-prep, .kid-card, .panel, .quests-head h3 { box-shadow: none; }
@media (hover: hover) {
  .session-row:not(.drag-over):hover { transform: none; box-shadow: var(--shadow-sm); }
  .session-row.slim:not(.drag-over):hover { transform: none; box-shadow: var(--shadow-sm); }
  .quest-card:hover { transform: translate(-2px, -2px); box-shadow: var(--shadow-sm); }
  .quest-card.missed:hover { transform: none; box-shadow: none; }
}
.quest-card:active { transform: none; box-shadow: none; }
/* The drop-target mark on a timetable row is a signal, not elevation: it
   outranks the flat rule and the hover lift (Codex, round 2). */
.session-row.drag-over, .session-row.slim.drag-over { box-shadow: 0 -4px 0 var(--ink); transform: none; }
.btn { box-shadow: var(--shadow-xs); }
.day-tab.active { box-shadow: 3px 3px 0 var(--pink); }
body.child-mode .day-tab.active { box-shadow: 3px 3px 0 var(--c); }

/* 3. The rail is a list, not a stack of boxes: rows are flat until picked,
   the explorer card carries a light line unless open, Settings and Switch
   profile sit at the foot of the bar. */
.sidebar { gap: 16px; }
@media (min-width: 1021px) { .sidebar { padding: 24px 16px 24px 20px; } }   /* the drawer keeps its safe-area padding */
#kids-roster { gap: 8px; }
.kid-card { padding: 10px 12px; gap: 10px; background: var(--card); border-color: var(--faintline); }
.kid-card.active { border-color: var(--ink); box-shadow: var(--shadow-xs); }
.kid-card h4 { font-size: 0.95rem; }
.kid-card p { font-size: 0.74rem; }
.tabs { gap: 4px; }
.tabs-group { margin: 14px 0 4px 12px; font-size: 0.64rem; }
.tabs-group:first-child { margin-top: 2px; }
.tabs button { padding: 10px 12px; font-size: 0.8rem; background: transparent; border-color: transparent; }
.tabs button:hover { background: var(--bg); }
.tabs button:active { transform: none; }
.tabs button.active { background: var(--green); border-color: var(--ink); box-shadow: var(--shadow-xs); }
.kid-rail .tabs button.active { background: var(--c); }
.settings-btn { margin-top: auto; padding: 12px 16px; font-size: 0.78rem; box-shadow: none; }
.settings-btn:hover { transform: none; box-shadow: var(--shadow-xs); }
.settings-btn:active { transform: translate(1px, 1px); box-shadow: none; }

/* 4. Content rhythm: the page starts level with the rail, blocks sit 24px
   apart, controls share one height (36–40px), type has fewer sizes. */
@media (min-width: 1021px) {
  body.has-rail main { padding-top: 24px; }
  /* The rail's one card IS the current explorer now (decision 38); the line
     would say it twice. Under 1020px it stays the drawer's switch. */
  .explorer-line { display: none; }
}
.main-col { gap: 24px; }
.explorer-line { padding: 6px 12px 6px 8px; }
.btn { padding: 9px 16px; font-size: 0.8rem; }
.btn-sm { padding: 7px 12px; font-size: 0.72rem; }
.icon-btn { width: 36px; height: 36px; }
.day-strip { gap: 6px; }
.day-tab { padding: 9px 8px; font-size: 0.8rem; min-width: 64px; }
@media (min-width: 681px) { .schedule-head h3 { font-size: 1.35rem; } }
.quests-section { gap: 14px; }
.quests-head h3 { font-size: 0.98rem; padding: 7px 14px; transform: none; }   /* the tilt was a flourish, not a signal */
.quests-grid { gap: 16px; }
.quest-card { padding: 18px 18px 16px; gap: 10px; }
.session-row.slim { padding: 8px 14px 8px 8px; gap: 12px; }
.kid-main .tab-panel { gap: 20px; }
.week-nav { margin: 0; }

/* 5. Settings is three tabs (decision 39) — the rail's list style, laid
   across the top of the pop-up. */
.settings-tabs { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 18px; }
.settings-tabs button {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 8px 12px;
  background: transparent; border: var(--bw) solid transparent;
  font-size: 0.78rem; font-weight: 700; text-transform: uppercase;
}
.settings-tabs button svg { width: 15px; height: 15px; stroke-width: 2.6; }
.settings-tabs button:hover { background: var(--bg); }
.settings-tabs button.active { background: var(--green); border-color: var(--ink); box-shadow: var(--shadow-xs); }
/* Phones: three equal tabs on one row, labels only (the icons cost the width). */
@media (max-width: 680px) {
  .settings-tabs { gap: 4px; }
  .settings-tabs button { flex: 1 1 0; justify-content: center; padding: 8px 4px; font-size: 0.7rem; }
  .settings-tabs button svg { display: none; }
}

/* 6. Lessons inside the app (decision 40): the lesson page in a frame that
   fills the pane below its head; this week's modules in the kid rail. The
   parent's section (decision 56) is the same panel and the same week list in
   the parent rail; the kid panel gets its column from .kid-main .tab-panel. */
.kid-main .lesson-panel { gap: 12px; }
#panel-lesson { display: flex; flex-direction: column; gap: 12px; }
.lesson-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 12px 20px; flex-wrap: wrap; }
.lesson-head-words { display: grid; gap: 2px; min-width: 0; }
.lesson-kicker { font-size: 0.64rem; font-weight: 800; letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); }
.lesson-head h3 { margin: 0; font-family: var(--font-display); font-size: 1.35rem; line-height: 1.05; }
.lesson-head-side { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.lesson-count { font-size: 0.78rem; font-weight: 800; color: var(--muted); white-space: nowrap; }
.lesson-hint { font-size: 0.78rem; font-weight: 700; color: var(--muted); }
.lesson-frame {
  display: block; width: 100%; min-height: 0; flex: 1 1 auto;
  background: #f3efe6; border: var(--bw) solid var(--ink);
}
.lesson-empty { padding: 40px 12px; }
/* The panel is as tall as the pane, so the lesson scrolls inside its frame and
   the page underneath stays put. */
body.lesson-open main { padding-top: 24px; padding-bottom: 24px; }
body.lesson-open .lesson-panel { height: calc(100vh - var(--topbar-h) - 48px); height: calc(100dvh - var(--topbar-h) - 48px); }
@media (max-width: 680px) {
  /* The phone bar owns the bottom edge (the <=680 block above): keep its clearance. */
  body.lesson-open main { padding-top: 20px; padding-bottom: calc(96px + env(safe-area-inset-bottom)); }
  body.lesson-open .lesson-panel { height: calc(100vh - var(--topbar-h) - 20px - 96px - env(safe-area-inset-bottom)); height: calc(100dvh - var(--topbar-h) - 20px - 96px - env(safe-area-inset-bottom)); }
  .lesson-head h3 { font-size: 1.1rem; }
}
/* The week list in the rail: the lesson page's sidebar, in the rail's list style. */
.kid-week { display: flex; flex-direction: column; gap: 4px; }
.kid-week-head { display: grid; gap: 6px; padding: 0 12px 10px; }
.kid-week-head .tabs-group { margin: 14px 0 0; }
.kid-week-title { font-family: var(--font-display); font-size: 1rem; line-height: 1.1; }
.kid-week-bar { height: 10px; border: 2px solid var(--ink); background: var(--card); overflow: hidden; }
.kid-week-bar i { display: block; height: 100%; background: var(--green); transition: width 0.25s ease; }
.kid-week-head small { font-size: 0.7rem; font-weight: 800; color: var(--muted); }
.kid-week-days, .kid-week-steps { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.kid-week-day-btn {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "day count" "label count";
  align-items: center; column-gap: 8px; width: 100%;
  padding: 8px 12px; text-align: left;
  background: transparent; border: var(--bw) solid transparent; box-shadow: none;
}
.kid-week-day-btn:hover { background: var(--bg); }
.kid-week-day.current > .kid-week-day-btn { border-color: var(--ink); background: var(--card); }
.kid-week-dayname { grid-area: day; font-size: 0.62rem; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted); }
.kid-week-label { grid-area: label; font-size: 0.8rem; font-weight: 800; line-height: 1.2; }
.kid-week-count { grid-area: count; font-size: 0.66rem; font-weight: 800; padding: 2px 6px; border: 2px solid var(--ink); background: var(--card); }
.kid-week-day.done .kid-week-count { background: var(--green); }
.kid-week-steps { padding: 4px 0 8px 10px; }
.kid-week-step {
  display: grid; grid-template-columns: 18px minmax(0, 1fr); gap: 8px; align-items: start; width: 100%;
  padding: 6px 8px 6px 10px; text-align: left;
  background: transparent; border: var(--bw) solid transparent; border-left-width: 4px; box-shadow: none;
}
.kid-week-step:hover { background: var(--bg); }
.kid-week-step.current { background: var(--yellow); border-color: var(--ink); }
.kid-week-tick { width: 16px; height: 16px; margin-top: 1px; border: 2px solid var(--ink); border-radius: 50%; background: var(--card); box-sizing: border-box; }
.kid-week-step.done .kid-week-tick {
  background: var(--ink) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='M4 10.5l4 4 8-9' fill='none' stroke='%239ff26b' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / 80% no-repeat;
}
.kid-week-step-text { display: grid; gap: 1px; min-width: 0; }
.kid-week-step-title { font-size: 0.76rem; font-weight: 700; line-height: 1.2; }
.kid-week-step-meta { font-size: 0.6rem; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; color: var(--muted); }
/* The quest pop-up's Start lesson is a button, styled like the chips beside it. */
button.quest-link-chip { cursor: pointer; font-family: inherit; }

/* Screen-reader-only text (first use: a lesson's Completed state, decision 40). */
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* 7. The lesson layout pass (Tom, 2026-09-17): real hit targets in the week
   list, and a tighter week head so a five-day week needs less scrolling. */
/* Nova floats bottom-right, which is exactly where the lesson's Complete
   button sits — on a phone it covered it. The lesson pane is a working
   surface like the record export, so it hides the dock the same way. */
body.lesson-open #nova-dock, body.lesson-open #nova-help { display: none !important; }
.kid-week-head { padding: 0 12px 8px; gap: 5px; }
/* The week row (decision 56): arrows walk the weeks the child's cards point
   at; the label is the timetable's own week wording. */
.kid-week-nav { display: flex; align-items: center; gap: 6px; }
.kid-week-nav .kid-week-when { flex: 1; margin: 0; text-align: center; }
.kid-week-arrow { width: 28px; height: 28px; box-shadow: none; }
.kid-week-arrow svg { width: 14px; height: 14px; }
.kid-week-loading { color: var(--muted); }
.kid-week-day-btn { min-height: 44px; }
.kid-week-step { min-height: 44px; align-content: center; }
/* Room between the cards (Tom, 2026-09-21, from a screenshot: the current
   lesson's yellow card sat 2px under the day card, so the two borders read
   as one thick line): 4px between days and between lessons, the menu's own
   row gap; 8px from a day card to its lessons and 12px after them. */
.kid-week-days { gap: 4px; }
.kid-week-steps { padding: 8px 0 12px 10px; gap: 4px; }

/* 8. Photo viewer for attached work (2026-09-19, work.js openPhotoViewer).
   Dark ground so the photo reads; the controls keep the brand — ink borders,
   the small hard shadow, the display face on the caption. 9990 sits under the
   confirm boxes (9999), above everything else. The overlay scrolls nothing
   itself, and overscroll-behavior stops a wheel or a flick over it from
   scrolling the Completed tab underneath. */
.photo-overlay {
  position: fixed; inset: 0; z-index: 9990;
  /* minmax(0, 1fr) on the column, not a bare auto: the caption is one nowrap
     line, and an auto track grows to it — 686px wide on a 375px phone, the
     arrows off the left edge (decision 31's lesson again). */
  display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr);
  background: rgb(20 18 14 / 0.94);
  overflow: auto; overscroll-behavior: contain;
  animation: fadeIn 0.15s ease;
}
/* Referenced by .confirm-overlay since the start but never defined — so it did nothing there until now. */
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
.photo-overlay.hidden { display: none; }
.photo-bar {
  display: flex; align-items: center; gap: 12px;
  padding: calc(12px + env(safe-area-inset-top)) calc(16px + env(safe-area-inset-right)) 12px calc(16px + env(safe-area-inset-left));
  color: #fff;
}
.photo-bar-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.photo-caption { font-family: var(--font-display); font-size: 0.9rem; line-height: 1.3; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.photo-count { font-size: 0.7rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: rgb(255 255 255 / 0.7); }
.photo-bar .btn, .photo-bar .icon-btn { flex: none; color: var(--ink); }
.photo-bar .icon-btn { width: 40px; height: 40px; }
/* The stage is the grid's 1fr row; the photo is positioned inside it, because
   a percentage max-height on a centred grid item resolves against nothing and
   a 1600x1200 photo ran off the bottom of a 720px window. The insets are the
   breathing room; the max sizes subtract the same numbers. */
.photo-stage { position: relative; display: grid; place-items: center; min-height: 0; }
#photo-img {
  position: absolute; inset: 8px 16px calc(16px + env(safe-area-inset-bottom)); margin: auto;
  max-width: calc(100% - 32px); max-height: calc(100% - 24px - env(safe-area-inset-bottom));
  width: auto; height: auto; display: block;
  border: var(--bw) solid var(--ink); background: var(--bg);
}
#photo-img:not([src]) { display: none; }
.photo-overlay.loading .photo-stage::before {
  content: 'Loading…'; color: rgb(255 255 255 / 0.7);
  font-size: 0.8rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
}
.photo-error {
  max-width: 420px; padding: 20px 24px; text-align: center;
  background: var(--bg); border: var(--bw) solid var(--ink); box-shadow: var(--shadow-sm);
  font-weight: 600; line-height: 1.5;
}
.photo-nav {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 44px; height: 44px; display: grid; place-items: center;
  background: var(--card); border: var(--bw) solid var(--ink); box-shadow: var(--shadow-xs);
  cursor: pointer; padding: 0;
}
.photo-nav svg { width: 22px; height: 22px; stroke-width: 2.6; }
.photo-nav:hover { background: var(--yellow); }
.photo-nav:active { transform: translateY(-50%) translate(2px, 2px); box-shadow: none; }
.photo-nav-prev { left: calc(12px + env(safe-area-inset-left)); }
.photo-nav-next { right: calc(12px + env(safe-area-inset-right)); }
.photo-overlay :focus-visible { outline: 3px solid var(--yellow); outline-offset: 3px; }
@media (max-width: 680px) {
  /* The arrows sit at the foot on a phone, clear of the photo; a swipe does the same job. */
  .photo-nav { top: auto; bottom: calc(12px + env(safe-area-inset-bottom)); transform: none; }
  .photo-nav:active { transform: translate(2px, 2px); }
  #photo-img { bottom: calc(68px + env(safe-area-inset-bottom)); max-height: calc(100% - 76px - env(safe-area-inset-bottom)); }
  /* Icon only: the label took 125px of a 375px bar and left the caption 'Bronze Age Cook…'. */
  .photo-bar .btn { padding: 8px 10px; }
  .photo-bar .btn span { display: none; }
  .photo-bar .btn svg { width: 16px; height: 16px; }
  .photo-caption { white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
}

/* ==========================================================================
   Free time as chip clouds (2026-09-19, Tom: "the list view of free time
   items is very long — more compact and tidy for both parent and child").
   The parent's lists were full-width rows, ~60px each; a dozen shows ran
   to 878px. Both pages now show the same chips — the parent's with a ✕ —
   and the two sections sit side by side on a wide screen. Appended so it
   wins over the earlier .watch-chip and .icon-btn rules (decision 37).
   ========================================================================== */
.freetime-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 32px; align-items: start; }
@media (min-width: 1100px) {
  .freetime-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 40px; }
}
.freetime-section { min-width: 0; }
.freetime-section .deck-add { margin-bottom: 14px; }
.tag-list { display: flex; flex-wrap: wrap; gap: 8px; }
.tag-list .empty-state { flex: 1 1 100%; }
.tag-chip {
  display: inline-flex; align-items: center; gap: 2px;
  max-width: 100%;
  padding: 3px 3px 3px 12px;
  background: var(--card);
  border: var(--bw) solid var(--ink);
  font-size: 0.85rem; font-weight: 700; line-height: 1.3;
}
.tag-chip .tag-text { min-width: 0; overflow-wrap: anywhere; }
.tag-chip .tag-remove {
  width: 26px; height: 26px;
  border: 0; box-shadow: none; background: transparent;
  color: var(--muted);
}
.tag-chip .tag-remove svg { width: 13px; height: 13px; stroke-width: 3; }
.tag-chip .tag-remove:hover { background: var(--red); color: #fff; }
.tag-chip .tag-remove:active { transform: none; }
/* The child's chips: the same size as the parent's, flat, tighter gaps. */
.watch-list { gap: 8px; }
.watch-chip { padding: 6px 12px; gap: 7px; font-size: 0.85rem; box-shadow: none; }
.watch-chip svg { width: 14px; height: 14px; }
.kpanel-freetime .quests-section, #kpanel-freetime .quests-section { gap: 12px; }

/* ==========================================================================
   Home (2026-09-21, decision 58, Tom: "a dashboard homepage for the parents,
   instead of always being on a child's timetable" — "the things that need my
   attention"). The parent's front door: the date and a greeting, the Get
   started card, then "Needs you" (one row per thing, the fixing button on the
   row) beside "This week" (one card per explorer, the rail card's look with
   the five weekdays under it). Written to the professional pass: flat at
   rest, 2px lines, the 4/8/12/16/24/32 scale, the display face for titles.
   Appended so it wins the cascade (decision 37's rule).
   ========================================================================== */
#panel-home { display: flex; flex-direction: column; gap: 24px; }
#panel-home .get-started { margin-bottom: 0; }   /* the column's gap spaces it */

.home-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 12px 20px; flex-wrap: wrap; }
.home-head-words { display: grid; gap: 2px; min-width: 0; }
.home-kicker { font-size: 0.64rem; font-weight: 800; letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); }
.home-head h3 { margin: 0; font-family: var(--font-display); font-size: 1.35rem; line-height: 1.05; }
.home-head-side { display: inline-flex; align-items: center; gap: 12px; font-size: 0.78rem; font-weight: 700; color: var(--muted); }

.home-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 24px; align-items: start; }

.home-card { background: var(--card); border: var(--bw) solid var(--ink); padding: 16px 20px 18px; min-width: 0; }
.home-card-head { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
.home-card-head h4 { display: inline-flex; align-items: center; gap: 8px; font-family: var(--font-display); font-size: 1.1rem; text-transform: uppercase; }
.home-card-head h4 svg { width: 18px; height: 18px; stroke-width: 2.4; }
.home-card-head small { margin-left: auto; font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); }

/* Needs you */
.needs-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.needs-item {
  display: grid; grid-template-columns: 34px minmax(0, 1fr) auto;
  gap: 12px; align-items: center;
  padding: 10px 12px;
  border: 2px solid var(--faintline);
}
.needs-icon { width: 34px; height: 34px; display: grid; place-items: center; border: 2px solid var(--ink); background: var(--yellow); }
.needs-icon svg { width: 16px; height: 16px; stroke-width: 2.6; }
.needs-icon.book { background: var(--lilac); }
.needs-icon.plan { background: var(--blue); }
.needs-text { min-width: 0; }
.needs-text strong { display: block; font-size: 0.92rem; }
.needs-text p { margin: 2px 0 0; font-size: 0.8rem; font-weight: 500; line-height: 1.45; color: var(--muted); }
.needs-actions { display: inline-flex; gap: 8px; flex-wrap: wrap; justify-content: flex-end; }
.needs-empty {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  padding: 20px 12px;
  font-size: 0.85rem; font-weight: 600; color: var(--muted);
}
.needs-empty svg { width: 18px; height: 18px; stroke-width: 2.4; }
@media (max-width: 680px) {
  .needs-item { grid-template-columns: 34px minmax(0, 1fr); }
  .needs-actions { grid-column: 2; justify-content: flex-start; }
}

/* This week: one card per explorer, in a row that wraps (four children fit
   one row at the column's full width, decision 61). */
.home-explorers { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 12px; }
.home-explorer {
  display: grid; grid-template-columns: 42px minmax(0, 1fr) auto; gap: 8px 12px; align-items: center;
  padding: 12px 12px 12px 14px;
  background: var(--kid-color, var(--blue));
  border: var(--bw) solid var(--ink);
  color: inherit; text-decoration: none;
  transition: box-shadow 0.08s ease;
}
@media (hover: hover) { .home-explorer:hover { box-shadow: var(--shadow-sm); } }
.home-explorer:active { box-shadow: none; }
.home-explorer:focus-visible { outline: 3px solid var(--ink); outline-offset: 3px; }
.home-explorer .kid-text { padding-right: 0; }
.home-explorer h4 { font-size: 0.95rem; font-weight: 700; text-transform: uppercase; }
.home-explorer p { font-size: 0.74rem; font-weight: 600; }
.home-explorer .kid-streak { margin-left: 0; }
.home-explorer .kid-today { margin-top: 5px; }
.home-explorer-go { width: 20px; height: 20px; stroke-width: 2.8; align-self: start; }
.home-days { grid-column: 1 / -1; display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 4px; margin-top: 4px; }
.home-day {
  display: grid; place-items: center; gap: 2px;
  padding: 5px 2px 4px;
  min-height: 40px;
  background: var(--card); border: 2px solid var(--ink);
  font-size: 0.6rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.04em;
}
.home-day span { font-size: 0.68rem; letter-spacing: 0; }
.home-day svg { width: 13px; height: 13px; stroke-width: 3.2; }
.home-day.done { background: var(--green); }
.home-day.today { background: var(--ink); color: var(--yellow); }
.home-day.today.done { color: var(--green); }
.home-day.ahead { opacity: 0.6; }
.home-day.none { opacity: 0.5; border-style: dashed; }

/* Home has no rail (decision 61): the content column takes the page,
   centred at the same width it has beside a rail, starting level with where
   the rail would start. */
body.home-open .parent-layout { grid-template-columns: minmax(0, 1fr); }
#rail.settled .reveal { animation: none; }
body.home-open .main-col { max-width: 1120px; margin: 0 auto; width: 100%; }
@media (min-width: 1021px) { body.home-open main { padding-top: 24px; } }

/* ==========================================================================
   Parent notes (2026-09-21, decision 60): a note per child per week, a daily
   one when a day deserves it. The box under the Timetable's day strip, the
   note pop-up (the confirm-box shape), and the rows in the record.
   ========================================================================== */
.notes-box { display: flex; flex-direction: column; gap: 6px; margin: 0 0 16px; padding: 10px 14px; background: var(--card); border: var(--bw) solid var(--ink); }
.notes-row { display: flex; align-items: center; gap: 10px; min-height: 32px; }
.notes-label { display: inline-flex; align-items: center; gap: 6px; flex: 0 0 auto; min-width: 88px; font-size: 0.68rem; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); }
.notes-label svg { width: 14px; height: 14px; stroke-width: 2.6; }
.notes-text { flex: 1; min-width: 0; font-size: 0.85rem; font-weight: 500; line-height: 1.45; white-space: pre-line; overflow-wrap: anywhere; }
.notes-text.notes-empty { color: var(--muted); font-style: italic; }
.notes-edit { width: 32px; height: 32px; box-shadow: none; flex: 0 0 auto; }
.notes-add-day {
  align-self: flex-start; display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 0; background: transparent; border: 0; box-shadow: none; cursor: pointer;
  font-size: 0.72rem; font-weight: 800; letter-spacing: 0.04em; text-transform: uppercase; color: var(--muted);
}
.notes-add-day:hover { color: var(--ink); }
.notes-add-day svg { width: 13px; height: 13px; stroke-width: 3; }
.note-box .field textarea { width: 100%; }
@media (max-width: 680px) {
  .notes-row { flex-wrap: wrap; }
  .notes-label { min-width: 0; }
}
/* In the record: a quiet row under the week's heading, or above a day's entries. */
.rec-table .rec-note-row td { background: #f7f4ee; font-style: italic; color: #2e2a25; }
.rec-note-who { display: block; margin-bottom: 0.15rem; font-style: normal; font-size: 0.68rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: #5c5750; }
.rec-note-inline { font-style: italic; }
.rec-note-inline .rec-note-who { display: inline; margin: 0 0.4rem 0 0; }

/* ============================================================
   Lesson full screen: the lesson box (head + frame) fills the screen.
   Real element full screen where the browser has it; body.lesson-full
   covers the window on an iPhone, which has none. <main> is a stacking
   context (decision 35), so the fallback lifts main, not the panel.
   ============================================================ */
.lesson-head-end { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.lesson-full-btn, .lesson-print-btn { flex: none; }
.lesson-full-btn .i-exit { display: none; }
.lesson-panel:fullscreen .lesson-full-btn .i-enter,
body.lesson-full .lesson-full-btn .i-enter { display: none; }
.lesson-panel:fullscreen .lesson-full-btn .i-exit,
body.lesson-full .lesson-full-btn .i-exit { display: inline-block; }
body.lesson-open .lesson-panel:fullscreen {
  display: flex; flex-direction: column; gap: 12px;
  width: 100%; height: 100%; margin: 0; padding: 16px 24px 24px;
  background: var(--bg); overflow: hidden;
}
.lesson-panel:-webkit-full-screen { width: 100%; height: 100%; background: var(--bg); padding: 16px 24px 24px; display: flex; flex-direction: column; gap: 12px; }
body.lesson-full main { z-index: 960; }
body.lesson-open.lesson-full .lesson-panel {
  position: fixed; inset: 0; z-index: 960;
  display: flex; flex-direction: column; gap: 12px;
  height: auto; margin: 0; background: var(--bg);
  padding: calc(12px + env(safe-area-inset-top)) 12px calc(12px + env(safe-area-inset-bottom));
}
