/* Hojas — leafy, calm, readable. Works from small phones to classroom projectors. */
/* Warm picture-book paper (it matches the watercolor topic art), leafy greens, and
   chunky controls that press down like real buttons. */
:root {
  --bg: #f7f4e9;
  --bg2: #e9f0da;
  --card: #fffdf7;
  --card-2: #f3f6ea;
  --ink: #22301f;
  --muted: #5f6d59;
  --line: #dde4cf;
  --line-strong: #c9d5b8;
  --leaf: #3f8f3a;
  --leaf-dark: #2c6a29;
  --leaf-soft: #e0efd4;
  --sun: #f2b632;
  --berry: #d0506a;
  --sky: #3e7fc1;
  --ok: #2f9e44;
  --bad: #d64545;
  --avatar-bg: #e3efd5;
  --tip-bg: #22301f;
  --tip-ink: #fffdf7;
  --shadow: 0 1px 2px rgba(60, 80, 40, 0.06), 0 10px 28px -12px rgba(60, 80, 40, 0.22);
  --press: 0 3px 0 var(--line-strong);
  --leaf-pattern: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160' viewBox='0 0 160 160'%3E%3Cg fill='%233f8f3a' fill-opacity='0.03'%3E%3Cpath d='M30 40c14-18 36-18 44-4-14 16-34 20-44 4z'/%3E%3Cpath d='M112 104c10-22 32-28 42-16-10 20-30 28-42 16z'/%3E%3Cpath d='M96 22c4-10 16-12 20-4-6 8-14 10-20 4z'/%3E%3Cpath d='M20 122c6-12 20-14 26-6-6 10-18 14-26 6z'/%3E%3C/g%3E%3C/svg%3E");
  --radius: 22px;
  --ui-font: "Baloo 2", system-ui, sans-serif;
  --read-font: "Andika", "Atkinson Hyperlegible", system-ui, sans-serif;
  color-scheme: light;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #121a11; --bg2: #1a2618; --card: #1d2a1b; --card-2: #233221; --ink: #e8f1e3; --muted: #a7b9a0; --line: #2f422b; --line-strong: #3d5538;
    --leaf: #6cc463; --leaf-dark: #8fd887; --leaf-soft: #253a22; --avatar-bg: #2a3d27; --tip-bg: #e8f1e3; --tip-ink: #121a11;
    --shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 10px 28px -12px rgba(0, 0, 0, 0.6); color-scheme: dark;
  }
}
:root[data-theme="dark"] {
  --bg: #121a11; --bg2: #1a2618; --card: #1d2a1b; --card-2: #233221; --ink: #e8f1e3; --muted: #a7b9a0; --line: #2f422b; --line-strong: #3d5538;
  --leaf: #6cc463; --leaf-dark: #8fd887; --leaf-soft: #253a22; --avatar-bg: #2a3d27; --tip-bg: #e8f1e3; --tip-ink: #121a11;
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 10px 28px -12px rgba(0, 0, 0, 0.6); color-scheme: dark;
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0; min-height: 100vh; background-color: var(--bg); color: var(--ink);
  font-family: var(--ui-font); font-size: 18px; line-height: 1.45;
  background-image: var(--leaf-pattern), radial-gradient(circle at 10% 0%, var(--bg2) 0, transparent 42%), radial-gradient(circle at 100% 100%, var(--bg2) 0, transparent 38%);
  background-attachment: fixed;
}
button, input, select, textarea { font: inherit; color: inherit; }
img { max-width: 100%; }
a { color: var(--leaf-dark); }
h1, h2, h3 { line-height: 1.15; margin: 0.3em 0; text-wrap: balance; }
h1 { font-size: clamp(1.7rem, 4vw, 2.2rem); font-weight: 800; letter-spacing: -0.01em; }
h2 { font-size: 1.4rem; font-weight: 800; }
h3 { font-size: 1.15rem; font-weight: 700; }
.muted { color: var(--muted); }
.center { text-align: center; }
.hidden { display: none !important; }
[hidden] { display: none !important; }   /* the hidden attribute wins over .btn and other display rules */

/* ---- layout ---------------------------------------------------------------- */
.topbar {
  display: flex; align-items: center; gap: 10px; padding: 10px 16px; flex-wrap: wrap;
  background: color-mix(in srgb, var(--card) 88%, transparent); border-bottom: 1px solid var(--line); position: sticky; top: 0; z-index: 10;
  -webkit-backdrop-filter: saturate(1.4) blur(10px); backdrop-filter: saturate(1.4) blur(10px);
  box-shadow: 0 6px 20px -16px rgba(60, 80, 40, 0.5);
}
.brand { display: flex; align-items: center; gap: 10px; font-weight: 800; font-size: 1.45rem; color: var(--leaf-dark); text-decoration: none; letter-spacing: -0.01em; }
.brand .logo { font-size: 1.3rem; width: 40px; height: 40px; border-radius: 14px; display: grid; place-items: center; background: var(--leaf-soft); box-shadow: inset 0 -3px 0 rgba(63, 143, 58, 0.18); }
.topbar .spacer { flex: 1; }
.wrap { width: 100%; max-width: 980px; margin: 0 auto; padding: 16px; }
.wrap.narrow { max-width: 640px; }
.wrap.wide { max-width: 1280px; }
.stack > * + * { margin-top: 14px; }
.row { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.row.spread { justify-content: space-between; }
.range-pair { flex-wrap: nowrap; }   /* a student's lowest – highest reading level, side by side (stacked on a phone) */
.grid { display: grid; gap: 14px; grid-template-columns: repeat(auto-fill, minmax(min(100%, 220px), 1fr)); }

.card { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: clamp(16px, 2.4vw, 22px); box-shadow: var(--shadow); }
.card h2, .card h3 { margin-top: 0; }
/* A heading partway down a card ("New teacher") gets room above it; only the first one sits at the top. */
.card.stack > * + h2, .card.stack > * + h3 { margin-top: 22px; }
.hero-banner { text-align: center; padding: 28px 16px 20px; }
.hero-banner h1 { font-size: clamp(2.6rem, 8vw, 4rem); color: var(--leaf-dark); margin: 0.1em 0 0; text-shadow: 0 3px 0 var(--leaf-soft); }
.hero-banner p { font-size: 1.2rem; margin: 4px 0 0; }
/* Start page: a fan of topic pictures, like a stack of storybooks */
.topic-strip { display: flex; justify-content: center; align-items: flex-end; padding: 8px 0 4px; }
.topic-strip img { width: clamp(64px, 13vw, 116px); aspect-ratio: 1; object-fit: cover; border-radius: 18px; border: 4px solid var(--card); box-shadow: var(--shadow); margin: 0 -8px; }
.topic-strip img:nth-child(odd) { transform: rotate(-6deg) translateY(4px); }
.topic-strip img:nth-child(even) { transform: rotate(5deg); }
.topic-strip img:nth-child(4) { transform: scale(1.12) translateY(-6px); z-index: 1; }
@media (max-width: 520px) { .topic-strip img:nth-child(n+6) { display: none; } }
.big-emoji { font-size: clamp(3rem, 12vw, 5rem); line-height: 1; }

/* ---- buttons & inputs --------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px; text-align: center;
  min-height: 46px; padding: 8px 18px; border-radius: 999px; border: 2px solid var(--line-strong);
  background: var(--card); cursor: pointer; font-weight: 700; text-decoration: none; color: var(--ink);
  box-shadow: var(--press); transition: transform .08s ease, box-shadow .08s ease, background .15s, border-color .15s;
}
.btn:hover:not(:disabled) { transform: translateY(-1px); border-color: var(--leaf); }
.btn:active:not(:disabled) { transform: translateY(2px); box-shadow: 0 1px 0 var(--line-strong); }
.btn:disabled { opacity: .45; cursor: not-allowed; }
.btn.primary { background: linear-gradient(180deg, #4fa548, var(--leaf)); border-color: var(--leaf-dark); color: #fff; box-shadow: 0 4px 0 var(--leaf-dark); text-shadow: 0 1px 0 rgba(0, 0, 0, 0.15); }
.btn.primary:active:not(:disabled) { box-shadow: 0 1px 0 var(--leaf-dark); }
.btn.sun { background: var(--sun); border-color: #d99a12; color: #3a2a00; box-shadow: 0 4px 0 #d99a12; }
.btn.danger { border-color: var(--bad); color: var(--bad); box-shadow: 0 3px 0 color-mix(in srgb, var(--bad) 45%, transparent); }
.btn.ghost { background: transparent; border-color: transparent; box-shadow: none; }
.btn.small { min-height: 36px; padding: 4px 12px; font-size: .9rem; }
.btn.big { min-height: 60px; padding: 12px 28px; font-size: 1.25rem; }
.btn.round { width: 54px; height: 54px; padding: 0; font-size: 1.2rem; }
.btn:focus-visible, .choice:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible { outline: 3px solid var(--sun); outline-offset: 2px; }

label.field { display: block; font-weight: 700; }
label.field > span { display: block; margin-bottom: 4px; }
input[type="text"], input[type="email"], input[type="password"], input[type="date"], input[type="number"], select, textarea {
  width: 100%; min-height: 46px; padding: 8px 12px; border-radius: 14px; border: 2px solid var(--line-strong); background: var(--card);
  transition: border-color .15s, box-shadow .15s;
}
input[type="text"]:focus, input[type="email"]:focus, input[type="password"]:focus, input[type="date"]:focus, input[type="number"]:focus, select:focus, textarea:focus {
  border-color: var(--leaf); box-shadow: 0 0 0 4px var(--leaf-soft); outline: none;
}
textarea { min-height: 90px; resize: vertical; }
input[type="range"] { width: 100%; accent-color: var(--leaf); }
input[type="checkbox"], input[type="radio"] { width: 22px; height: 22px; accent-color: var(--leaf); }
.check { display: inline-flex; align-items: center; gap: 8px; font-weight: 600; }

/* ---- choice grids (topics, goals, looks) ------------------------------------ */
.choices { display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(min(100%, 140px), 1fr)); }
.choices.small { grid-template-columns: repeat(auto-fill, minmax(min(100%, 150px), 1fr)); gap: 10px; }
.choices.small .choice { font-size: .95rem; }
@media (max-width: 520px) { .choices.small { grid-template-columns: repeat(auto-fill, minmax(min(46%, 128px), 1fr)); } .choices.small .choice { font-size: .9rem; } .choices.small.with-pics { grid-template-columns: repeat(auto-fill, minmax(min(46%, 104px), 1fr)); } }
.choice {
  position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; text-align: center;
  min-width: 0; min-height: 84px; padding: 10px 8px 12px; border-radius: 18px; border: 2px solid var(--line-strong); background: var(--card);
  cursor: pointer; font-weight: 700; line-height: 1.15; box-shadow: var(--press);
  transition: transform .1s ease, box-shadow .1s ease, border-color .15s, background .15s;
}
.choice:hover:not(:disabled) { transform: translateY(-2px); border-color: var(--leaf); box-shadow: 0 5px 0 var(--line-strong); }
.choice:active:not(:disabled) { transform: translateY(2px); box-shadow: 0 1px 0 var(--line-strong); }
.choices.small .choice { min-height: 60px; }
.choice .emoji { font-size: 2rem; line-height: 1.1; }
/* Long names ("Personification", "Vowel teams & diphthongs") wrap inside the tile instead of spilling out. */
.choice .label { display: block; max-width: 100%; overflow-wrap: break-word; hyphens: auto; text-wrap: balance; }
.choice .sub { display: block; font-size: .78rem; font-weight: 600; color: var(--muted); }
.choice .swatch { width: 34px; height: 34px; border-radius: 50%; border: 2px solid rgba(0,0,0,.15); }
.choice.on { border-color: var(--leaf); background: var(--leaf-soft); box-shadow: 0 3px 0 var(--leaf); }
/* A little check badge on whatever is picked */
.choice.on::after {
  content: "✓"; position: absolute; top: -8px; right: -8px; width: 26px; height: 26px; border-radius: 50%;
  display: grid; place-items: center; background: var(--leaf); color: #fff; font-size: .9rem; font-weight: 800;
  border: 2px solid var(--card); box-shadow: 0 2px 6px rgba(0,0,0,.15); animation: award-pop .3s ease-out;
}
.choice:disabled { opacity: .4; cursor: not-allowed; }
/* A sticker in the top-left corner (a topic already made: "Done"), clear of the picked ✓ on the right */
.choice-corner {
  position: absolute; top: -8px; left: -6px; z-index: 1; padding: 2px 8px; border-radius: 999px; transform: rotate(-6deg);
  background: var(--leaf-soft); color: var(--leaf-dark); font-size: .72rem; font-weight: 800; white-space: nowrap;
  border: 2px solid var(--card); box-shadow: 0 2px 6px rgba(0,0,0,.15);
}
.explored-line { margin: 0; font-weight: 800; color: var(--leaf-dark); }
/* Young readers' Next button in the story picker: stays in reach below a long picture grid */
.young-next { position: sticky; bottom: 10px; z-index: 3; padding: 8px 0 2px; }
.young-next .btn:disabled { opacity: .55; }
/* Open mode, today's story read: when the next one unlocks */
.next-story-in { margin: 0; font-weight: 800; }
/* Story picker: what the teacher's reading skill means, in kid words */
.skill-card { gap: 6px; }
.skill-what { padding: 6px 12px; border-radius: 12px; background: var(--card-2); font-size: .95rem; }
/* Story picker review: the treasures the hero brings along */
.bringing { gap: 6px; padding: 10px 12px; border-radius: 14px; background: var(--card-2); }
.bringing p { margin: 0; font-weight: 700; }
.bringing .inventory { justify-content: center; }
/* Last story page: a nudge on to The End, and a glowing ▶ */
.last-page-hint { margin: 14px 0 0; text-align: center; font-weight: 800; color: var(--leaf-dark); }
.btn.round.glow { animation: next-glow 1.8s ease-in-out infinite; }
@keyframes next-glow { 0%, 100% { box-shadow: 0 3px 0 var(--leaf-dark), 0 0 0 0 rgba(245, 179, 1, .6); } 50% { box-shadow: 0 3px 0 var(--leaf-dark), 0 0 0 8px rgba(245, 179, 1, 0); } }
@media (prefers-reduced-motion: reduce) { .btn.round.glow { animation: none; } }
/* The End: where the new treasure goes next */
.award-next { margin-top: 4px; font-size: .9rem; font-weight: 700; color: var(--leaf-dark); }
/* My character: the reading badges, earned in gold and the rest waiting in gray */
.badge-shelf { display: flex; flex-wrap: wrap; gap: 8px; }
.reading-badge { display: inline-flex; align-items: center; gap: 6px; padding: 6px 12px; border-radius: 999px; font-weight: 800; font-size: .9rem;
  background: var(--card-2); color: var(--muted); border: 2px dashed var(--line-strong); }
.reading-badge.earned { background: linear-gradient(135deg, #ffe27a, #f5b301); color: #4a3300; border: 2px solid #e0a200; }
/* The End: a reading badge just earned */
.milestone-banner { margin: 0 auto 12px; max-width: 520px; padding: 10px 16px; border-radius: 16px; text-align: center;
  font-weight: 800; font-size: 1.1rem; background: linear-gradient(135deg, #ffe27a, #f5b301); color: #4a3300; animation: award-pop .5s ease both; }
@media (prefers-reduced-motion: reduce) { .milestone-banner { animation: none; } }
/* The End: the gold badge a perfect first try earns */
.perfect-note { width: 100%; margin: 0; text-align: center; font-weight: 700; color: var(--leaf-dark); }
/* Bookshelf: every question right on the first try earns a gold badge */
.badge.perfect-badge { background: linear-gradient(135deg, #ffe27a, #f5b301); color: #4a3300; box-shadow: 0 0 0 1px #e0a200 inset; }
/* Team-up card on home: the teacher's note for the day */
.teacher-note { margin: 0; padding: 6px 12px; border-radius: 12px; background: rgba(255, 255, 255, .22); font-weight: 700; font-style: italic; }
/* Story cover, not finished yet: the treasure waiting at The End */
.treasure-tease { display: inline-block; margin: 4px auto 0; padding: 6px 14px; border-radius: 999px; background: color-mix(in srgb, var(--sun) 30%, transparent);
  font-weight: 800; animation: tease-bob 2.6s ease-in-out infinite; }
@keyframes tease-bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-3px); } }
@media (prefers-reduced-motion: reduce) { .treasure-tease { animation: none; } }
/* Class story lists: whether each story has been read, under its readers */
.read-count-note { font-size: .85rem; margin-top: 2px; }
/* Class tiles: the class's day at a glance */
.tile-today { margin-top: 6px; font-size: .9rem; font-weight: 700; color: var(--leaf-dark); }
.tile-today-link { text-decoration: underline; cursor: pointer; white-space: nowrap; }
/* Account: a password box with its Show button beside it */
.pw-row { flex-wrap: nowrap; gap: 8px; }
.pw-row input { flex: 1; min-width: 0; }
/* Topics & skills: what students will be able to pick, above each picture grid */
.limit-line { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; margin: 0; font-weight: 700; }
/* Home, right after a school kid makes their hero: the cheer line */
.hello-line.hero-ready { color: var(--leaf-dark); font-weight: 800; animation: award-pop .5s ease both; }
@media (prefers-reduced-motion: reduce) { .hello-line.hero-ready { animation: none; } }
/* Wait screen: the "still writing, it's fine to leave" note after the usual minute */
.wait-slow { padding: 10px 14px; border-radius: 14px; background: var(--leaf-soft); color: var(--leaf-dark); font-weight: 700; animation: award-pop .4s ease both; }
.wait-slow[hidden] { display: none; }
.wait-slow p { margin: 0; }
/* Word hunt: where the tapped word is hiding, and a jump to that page */
.hunt-line { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 8px 12px; margin-top: 10px; font-weight: 700; }
.hunt-line:empty { display: none; }
.hunt-back { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 12px; margin-bottom: 10px;
  padding: 8px 12px; border-radius: 14px; background: var(--leaf-soft); color: var(--leaf-dark); font-weight: 800; }
/* Team-up invite: the story idea sits on the left like the rest of the card */
.card .wait-picks { justify-content: flex-start; }
.card.writing .wait-picks { justify-content: center; }
.say-yes-line { margin: 0; font-weight: 800; color: var(--leaf-dark); }
/* Today strip on a team-up day: the teams forming so far */
.teams-today { gap: 4px; padding: 10px 12px; border-radius: 12px; background: color-mix(in srgb, var(--card) 70%, transparent); }
.teams-list { margin: 0; padding-left: 20px; }
/* Roster: archived students folded away under the class list */
.archived-students > summary { cursor: pointer; font-weight: 800; }
.archived-students[open] > summary { margin-bottom: 8px; }
.archived-students .card { border: 0; box-shadow: none; padding: 0; background: transparent; }
/* Tiles with pictures: topics (painted art) and looks (your hero wearing it) */
.choices.with-pics { grid-template-columns: repeat(auto-fill, minmax(min(100%, 150px), 1fr)); }
.choices.small.with-pics { grid-template-columns: repeat(auto-fill, minmax(min(100%, 112px), 1fr)); }
.choice-img { width: 100%; aspect-ratio: 1; object-fit: cover; border-radius: 12px; background: var(--card-2); display: block; }
.choices.with-pics .choice { justify-content: flex-start; padding: 8px 8px 10px; }
.choice-art { display: grid; place-items: center; }
.choice-art .avatar { width: 64px !important; height: 64px !important; }
/* Phones: three picture tiles to a row, so the topic and goal lists are a short scroll, not a long one. */
@media (max-width: 520px) {
  .choices.with-pics, .choices.small.with-pics { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
  .choices.with-pics .choice { padding: 6px 5px 8px; min-height: 0; font-size: .85rem; border-radius: 14px; }
  .choices.with-pics .choice-img { border-radius: 9px; }
  .choices.with-pics .choice-art .avatar { width: 56px !important; height: 56px !important; }
  .choices.small.swatches { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
  .choices.small.swatches .choice { min-height: 0; padding: 8px 4px 10px; }
  .choices.small.swatches .swatch { width: 28px; height: 28px; }
}
/* Hover descriptions (see enableTips in dom.js) */
.tip-pop {
  position: absolute; z-index: 200; max-width: min(300px, calc(100vw - 16px)); padding: 8px 12px; border-radius: 12px;
  background: var(--tip-bg); color: var(--tip-ink); font-family: var(--ui-font); font-size: .92rem; font-weight: 600; line-height: 1.35;
  box-shadow: 0 10px 24px -8px rgba(0, 0, 0, 0.35); pointer-events: none; opacity: 0; transform: translateY(4px);
  transition: opacity .15s ease, transform .15s ease;
}
.tip-pop.below { transform: translateY(-4px); }
.tip-pop.show { opacity: 1; transform: none; }
[data-tip] { cursor: help; }
.choice[data-tip] { cursor: pointer; }
@media (prefers-reduced-motion: reduce) { .tip-pop { transition: none; } .choice, .btn { transition: none; } }

.steps { display: flex; gap: 6px; justify-content: center; margin: 6px 0 12px; }
.steps span { width: 10px; height: 10px; border-radius: 50%; background: var(--line); }
.steps span.on { background: var(--leaf); }

/* ---- kid home -------------------------------------------------------------- */
.me-card { display: flex; gap: 16px; align-items: center; flex-wrap: wrap; }
/* The hero (Avataaars, drawn by avatar.js) in a round badge */
.avatar { flex: none; display: inline-block; border-radius: 50%; overflow: hidden; background: var(--avatar-bg); line-height: 0; vertical-align: middle; box-shadow: inset 0 -4px 0 rgba(0, 0, 0, 0.05); }
.avatar svg { width: 100%; height: 100%; display: block; }
.look-preview .avatar { border: 5px solid var(--card); box-shadow: var(--shadow); }
.inventory { display: flex; flex-wrap: wrap; gap: 8px; }
.pill { display: inline-flex; align-items: center; gap: 6px; padding: 4px 12px; border-radius: 999px; background: var(--leaf-soft); font-weight: 600; font-size: .95rem; }
.pill.power { background: #efe3ff; }
.pill.more-pill { background: var(--card); border: 2px dashed var(--line-strong); color: var(--leaf-dark); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .pill.power { background: #3a2d52; } }
.today-card { background: linear-gradient(135deg, var(--leaf), var(--leaf-dark)); color: #fff; border: none; }
.today-card .btn { background: #fff; color: var(--leaf-dark); border-color: #fff; }
.teamup-card { background: linear-gradient(135deg, #ffb347, #f06a8b); color: #fff; border: none; }
.teamup-card .btn { background: #fff; color: #b0304f; border-color: #fff; }

.shelf { display: grid; gap: 14px; grid-template-columns: repeat(auto-fill, minmax(min(46%, 170px), 1fr)); }
.book {
  display: flex; flex-direction: column; border-radius: 18px; overflow: hidden; background: var(--card);
  border: 1px solid var(--line); box-shadow: var(--shadow); text-decoration: none; color: inherit; cursor: pointer; text-align: left; padding: 0;
  transition: transform .15s ease, box-shadow .15s ease;
}
.book:hover { transform: translateY(-3px) rotate(-0.5deg); box-shadow: 0 16px 30px -14px rgba(60, 80, 40, 0.4); }
.library-pic { width: 60px; height: 60px; border-radius: 14px; object-fit: cover; flex: none; box-shadow: var(--shadow); }
.book .cover-img { aspect-ratio: 4 / 3; width: 100%; object-fit: cover; background: var(--leaf-soft); display: flex; align-items: center; justify-content: center; font-size: 2.6rem; }
.book .info { padding: 8px 10px; }
.book .title { font-weight: 800; line-height: 1.2; }
.book .meta { font-size: .85rem; color: var(--muted); }
.badge { display: inline-block; padding: 1px 8px; border-radius: 999px; font-size: .8rem; font-weight: 700; background: var(--sun); color: #3a2a00; }
.badge.green { background: var(--leaf-soft); color: var(--leaf-dark); }
.badge.red { background: #fde1e1; color: #9b2c2c; }

/* ---- the storybook -------------------------------------------------------- */
.reader { display: flex; flex-direction: column; min-height: calc(100vh - 90px); }
.reader-stage { flex: 1; touch-action: pan-y; }
.page { background: var(--card); border-radius: var(--radius); box-shadow: var(--shadow); border: 1px solid var(--line); padding: clamp(14px, 3vw, 32px); min-height: 60vh; }
.page.with-img { display: grid; gap: 20px; align-items: center; }
@media (min-width: 860px) and (orientation: landscape) { .page.with-img { grid-template-columns: 1fr 1fr; } }
.story-img { width: 100%; border-radius: 14px; aspect-ratio: 4 / 3; object-fit: cover; background: var(--leaf-soft); }
.story-img.pending { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; color: var(--muted); font-size: 1rem; }
.story-text { font-family: var(--read-font); font-size: clamp(1.25rem, 2.6vw, 1.6rem); line-height: 1.7; }
.story-text p { margin: 0 0 .8em; }
.cover { text-align: center; }
.cover .story-img { max-width: 720px; margin: 0 auto 12px; display: block; }
.story-title { font-size: clamp(1.8rem, 5vw, 3rem); color: var(--leaf-dark); }
.starring { font-size: 1.2rem; color: var(--muted); }
.turn-hint { font-size: .95rem; color: var(--muted); margin-top: 4px; }
.reader-bar { position: sticky; bottom: 0; display: flex; gap: 10px; align-items: center; justify-content: center; flex-wrap: wrap; padding: 12px 0; background: linear-gradient(transparent, var(--bg) 30%); }
.reader-count { min-width: 110px; text-align: center; font-weight: 700; color: var(--muted); }
.the-end { text-align: center; font-size: clamp(2rem, 6vw, 3rem); color: var(--leaf-dark); }
.award { display: flex; gap: 16px; align-items: center; max-width: 520px; margin: 10px auto 20px; padding: 16px; border-radius: 16px; background: #fff6da; color: #3a2a00; border: 2px dashed var(--sun); }
.award-emoji { font-size: 3rem; }
.award-pic { width: 96px; height: 96px; border-radius: 16px; object-fit: cover; flex: none; box-shadow: var(--shadow); animation: award-wiggle 1.2s ease-in-out 1.1s 2; }
@media (prefers-reduced-motion: reduce) { .award-pic { animation: none; } }
.award-name { font-size: 1.3rem; font-weight: 800; }
.quiz { max-width: 720px; margin: 0 auto; }
.quiz > h3 { text-align: center; font-size: 1.5rem; color: var(--leaf-dark); margin: 18px 0 12px; }
.question .hear-it { margin: 0; }
.question { border: 2px solid var(--line); border-radius: 14px; margin: 0 0 12px; padding: 10px 14px; }
.question legend { font-weight: 800; padding: 0 6px; font-family: var(--read-font); font-size: 1.15rem; }
.answer { display: flex; gap: 10px; align-items: center; padding: 8px 10px; border-radius: 10px; cursor: pointer; font-family: var(--read-font); font-size: 1.1rem; }
.answer:hover { background: var(--leaf-soft); }
.answer.right { background: #d9f7df; color: #145a24; font-weight: 700; }
.answer.wrong { background: #fde1e1; color: #8a1f1f; text-decoration: line-through; }
.quiz-result { font-size: 1.3rem; font-weight: 800; margin-top: 10px; text-align: center; }

/* Classroom presenter: huge type for the big screen. */
.reader.presenter { min-height: 100vh; background: var(--bg); padding: 16px; }
.reader.presenter .story-text { font-size: clamp(1.6rem, 3.4vw, 3rem); }
.reader.presenter .story-title { font-size: clamp(2.4rem, 6vw, 5rem); }
.reader.presenter .page { min-height: calc(100vh - 110px); }
/* The full-screen element scrolls long pages; page turns reset it to the top. */
:fullscreen { overflow: auto; background: var(--bg); }

/* ---- writing animation -------------------------------------------------- */
.writing { text-align: center; padding: 40px 16px; }
.writing .tree { font-size: 5rem; display: inline-block; animation: sway 2.6s ease-in-out infinite; transform-origin: bottom center; }
.writing .falling { position: relative; height: 70px; overflow: hidden; }
.writing .falling span { position: absolute; top: -30px; font-size: 1.6rem; animation: fall 3.2s linear infinite; }
@keyframes sway { 0%, 100% { transform: rotate(-4deg); } 50% { transform: rotate(4deg); } }
@keyframes fall { to { transform: translateY(120px) rotate(300deg); opacity: 0; } }
.loading { display: flex; gap: 10px; align-items: center; justify-content: center; padding: 30px; color: var(--muted); }
.leaf-spin { display: inline-block; animation: spin 1.6s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .leaf-spin, .writing .tree, .writing .falling span { animation: none; } }

/* ---- picture PIN pad -------------------------------------------------------- */
.pin-pad { display: grid; grid-template-columns: repeat(3, minmax(70px, 110px)); gap: 12px; justify-content: center; }
.pin-pad button { aspect-ratio: 1; font-size: clamp(2.2rem, 9vw, 3.2rem); border-radius: 22px; border: 2px solid var(--line-strong); background: var(--card); cursor: pointer; box-shadow: 0 4px 0 var(--line-strong); transition: transform .1s ease, box-shadow .1s ease, border-color .15s; }
.pin-pad button:hover { transform: translateY(-2px); border-color: var(--leaf); box-shadow: 0 6px 0 var(--line-strong); }
.pin-pad button:active { transform: translateY(3px); box-shadow: 0 1px 0 var(--line-strong); }
/* The 3 pictures are being checked: the pad rests (no second guess while waiting) */
.pin-pad.checking { opacity: .5; transition: opacity .2s; }
.pin-pad.checking button { cursor: progress; transform: none; }
.pin-dots { display: flex; gap: 12px; justify-content: center; margin: 14px 0; min-height: 56px; }
.pin-dots span { width: 60px; height: 60px; border-radius: 16px; border: 3px dashed var(--line-strong); display: flex; align-items: center; justify-content: center; font-size: 2rem; }
.pin-dots span.empty { font-size: 1.2rem; font-weight: 800; color: var(--line-strong); }
.pin-dots span.filled { border-style: solid; border-color: var(--leaf); background: var(--leaf-soft); }
.pin-dots span.pop-in { animation: award-pop .3s ease-out; }
@media (prefers-reduced-motion: reduce) { .pin-dots span.pop-in { animation: none; } }

/* ---- teacher console ------------------------------------------------------ */
.tabs { display: flex; gap: 6px; flex-wrap: wrap; padding: 6px; margin-bottom: 14px; background: var(--card-2); border: 1px solid var(--line); border-radius: 999px; width: fit-content; max-width: 100%; }
.tabs button { border: none; background: none; padding: 8px 16px; font-weight: 700; cursor: pointer; color: var(--muted); min-height: 40px; border-radius: 999px; transition: background .15s, color .15s; }
.tabs button:hover { color: var(--leaf-dark); }
.tabs button.on { color: var(--leaf-dark); background: var(--card); box-shadow: 0 2px 0 var(--line-strong), 0 4px 10px -6px rgba(60, 80, 40, 0.3); }
@media (max-width: 640px) { .tabs { border-radius: 18px; } }
.table-wrap { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: .95rem; }
th, td { text-align: left; padding: 8px 10px; border-bottom: 1px solid var(--line); vertical-align: middle; }
th { color: var(--muted); font-size: .8rem; text-transform: uppercase; letter-spacing: .05em; }
tbody tr:hover td { background: color-mix(in srgb, var(--leaf-soft) 45%, transparent); }
/* Form fields line up along the top (hints under some boxes no longer push the others down), with room for long dropdown choices. */
.form-grid { display: grid; gap: 14px 16px; grid-template-columns: repeat(auto-fill, minmax(min(100%, 290px), 1fr)); align-items: start; }
.row > select { width: auto; flex: 0 1 260px; }
/* Inline forms (a date and a note next to their button) share the row instead of each taking a whole line. */
.row > input[type="date"] { width: auto; flex: 0 1 220px; }
.row > input[type="text"], .row > input[type="email"] { width: auto; flex: 1 1 220px; }
/* Dropdowns inside tables show their whole choice ("Class range") */
.table-wrap td select { width: auto; min-width: 10.5em; }
.table-wrap td .btn { white-space: nowrap; }
.table-wrap td .signin { min-width: 7.5em; }
.weekdays { display: flex; gap: 6px; flex-wrap: wrap; }
.weekdays label { display: inline-flex; align-items: center; gap: 4px; padding: 6px 10px; border: 2px solid var(--line); border-radius: 10px; }
.list-item { display: flex; gap: 10px; align-items: center; justify-content: space-between; flex-wrap: wrap; padding: 10px 0; border-bottom: 1px solid var(--line); }
.template-text { white-space: pre-wrap; font-family: var(--read-font); background: var(--bg2); padding: 10px; border-radius: 10px; }

/* Printable QR cards */
.cards { display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); }
.qr-card { border: 2px dashed var(--line); border-radius: 14px; padding: 12px; text-align: center; background: #fff; color: #1f2a1c; break-inside: avoid; }
.qr-card img { width: 180px; height: 180px; }
.qr-card .name { font-size: 1.4rem; font-weight: 800; }
.qr-card .link { font-size: .6rem; word-break: break-all; color: #555; }
@media print {
  .topbar, .no-print, .tabs { display: none !important; }
  body { background: #fff; }
  .wrap { max-width: none; padding: 0; }
  .card { box-shadow: none; border: none; }
}

.toast { position: fixed; left: 50%; bottom: 20px; transform: translate(-50%, 120px); background: var(--ink); color: var(--bg); padding: 12px 20px; border-radius: 14px; font-weight: 700; z-index: 100; transition: transform .25s; max-width: calc(100% - 32px); }
.toast.show { transform: translate(-50%, 0); }
.toast.error { background: var(--bad); color: #fff; }

@media (max-width: 520px) {
  body { font-size: 17px; }
  .wrap { padding: 12px; }
  .topbar { padding: 8px 12px; }
  .btn { padding: 8px 14px; }
  /* The teacher's bar wraps to three rows on a phone (a quarter of the screen): it scrolls
     away with the page there instead of staying pinned over long lists like the roster. */
  #topbar { position: relative; }
}

/* Class setup checklist (teacher console) */
.checklist { border: 2px dashed var(--leaf); }
.checklist ol { list-style: none; margin: 0; padding: 0; }
.checklist li { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding: 8px 0; border-bottom: 1px solid var(--line); }
.checklist li:last-child { border-bottom: none; }
.checklist .check-text { flex: 1; min-width: 180px; font-weight: 600; }
.checklist li.done .check-text { color: var(--muted); text-decoration: line-through; font-weight: 400; }
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* Finishing a story: falling leaves and stars, and the award pops in. */
.party { position: fixed; inset: 0; pointer-events: none; overflow: hidden; z-index: 50; }
.party span { position: absolute; top: -3rem; animation-name: party-fall; animation-timing-function: ease-in; animation-fill-mode: forwards; }
@keyframes party-fall {
  0% { transform: translateY(0) rotate(0deg); opacity: 1; }
  85% { opacity: 1; }
  100% { transform: translateY(110vh) rotate(540deg); opacity: 0; }
}
.award { animation: award-pop .7s cubic-bezier(.2, 1.6, .4, 1) .35s both; }
.award-emoji { animation: award-wiggle 1.2s ease-in-out 1.1s 2; }
@keyframes award-pop { from { transform: scale(.4); opacity: 0; } to { transform: scale(1); opacity: 1; } }
@keyframes award-wiggle { 0%, 100% { transform: rotate(0); } 25% { transform: rotate(-12deg) scale(1.15); } 75% { transform: rotate(12deg) scale(1.15); } }
@media (prefers-reduced-motion: reduce) { .award, .award-emoji { animation: none; } }

/* Story picker: the choices so far, pinned to the bottom with the Write button. */
.pick-bar {
  position: sticky; bottom: 0; z-index: 5; display: flex; gap: 10px; align-items: center; justify-content: center; flex-wrap: wrap;
  margin: 0 -16px -16px; padding: 12px 16px calc(12px + env(safe-area-inset-bottom));
  background: var(--card); border-top: 2px solid var(--line); box-shadow: 0 -6px 18px rgba(40, 70, 30, 0.12);
}
.pick-summary { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; justify-content: center; }
.pick-slot { padding: 6px 12px; border-radius: 999px; border: 2px dashed var(--line); color: var(--muted); font-weight: 700; }
.pick-slot.on { border-style: solid; border-color: var(--leaf); background: var(--leaf-soft); color: var(--ink); animation: award-pop .35s ease-out; }
.pick-plus { font-weight: 800; color: var(--muted); }
.pick-extra { flex-basis: 100%; text-align: center; font-size: .9rem; color: var(--muted); }
.pick-bar .btn { background: var(--card); color: var(--leaf-dark); border-color: var(--leaf); }
.pick-bar .btn.ready { background: var(--leaf); color: #fff; }
/* Making a reader: until a step is done, Next says what's missing and looks quieter */
.btn.primary.not-ready { background: var(--card); color: var(--leaf-dark); border-color: var(--leaf); }
/* Anything scrolled into view (a card, a step, a heading) stops just below the sticky top bar,
   whose height app code keeps in --topbar-h (it's taller on a phone, where its buttons wrap). */
html { scroll-padding-top: calc(var(--topbar-h, 68px) + 12px); }
@media (max-width: 520px) { .pick-bar { margin: 0 -12px -12px; } .pick-bar .btn { width: 100%; } }

/* "Today in your class" strip (teacher console) */
.today-strip { background: linear-gradient(135deg, var(--card), var(--leaf-soft)); }
.today-strip h2 { font-size: 1.25rem; }

/* Waiting for a story: the hero packs their things while the steps light up. */
.wait-hero { display: flex; justify-content: center; }
.wait-hero .avatar { animation: hero-hop 1.4s ease-in-out infinite; }
@keyframes hero-hop { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-10px); } }
.wait-pack .pill, .wait-pack .pack-item { animation: award-pop .5s cubic-bezier(.2, 1.6, .4, 1) both; }
.wait-pack .inventory { gap: 12px; }
.wait-pack { margin-bottom: 14px; }
.pack-item { display: flex; flex-direction: column; align-items: center; gap: 4px; width: 84px; font-size: .78rem; font-weight: 700; line-height: 1.15; text-align: center; }
.pack-item img, .pack-item .pack-emoji { width: 64px; height: 64px; border-radius: 16px; object-fit: cover; box-shadow: var(--shadow); background: var(--card); display: grid; place-items: center; font-size: 2rem; }
.pack-item.power img { outline: 3px solid #d9c6f5; }
.wait-steps { list-style: none; display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; padding: 0; margin: 8px 0; }
.wait-steps li { padding: 6px 14px; border-radius: 999px; border: 2px solid var(--line); color: var(--muted); font-weight: 700; }
.wait-steps li.on { border-color: var(--leaf); background: var(--leaf-soft); color: var(--ink); animation: step-pulse 1.6s ease-in-out infinite; }
.wait-steps li.done { border-color: var(--leaf); color: var(--leaf-dark); }
.wait-steps li.done::before { content: "✓ "; }
@keyframes step-pulse { 0%, 100% { box-shadow: 0 0 0 0 var(--leaf-soft); } 50% { box-shadow: 0 0 0 6px var(--leaf-soft); } }
.wait-line { font-size: 1.2rem; font-weight: 700; min-height: 1.6em; }
@media (prefers-reduced-motion: reduce) { .wait-hero .avatar, .wait-pack .pill, .wait-pack .pack-item, .wait-steps li.on { animation: none; } }
/* On a phone, what shows it's working (the steps and the silly line) comes right under
   "Writing your story...", and the rest is a little smaller, so it's in view without scrolling. */
@media (max-width: 520px) {
  .card.writing { display: flex; flex-direction: column; padding-top: 12px; }
  .card.writing > * { order: 2; }
  .card.writing > .falling, .card.writing > .wait-hero, .card.writing > h2 { order: 0; }
  .card.writing > .wait-steps, .card.writing > .wait-line, .card.writing > .wait-slow { order: 1; }
  .card.writing > .wait-line { margin-top: 4px; margin-bottom: 8px; }
  .writing .falling { height: 34px; }
  .wait-hero .avatar { width: 92px !important; height: 92px !important; }
  .pack-item { width: 70px; }
  .pack-item img, .pack-item .pack-emoji { width: 50px; height: 50px; font-size: 1.6rem; }
}

.handoff { border: 2px solid var(--leaf); }

.special-explain { background: var(--leaf-soft); border-radius: 12px; padding: 10px 14px; margin: 0; }
details > summary { cursor: pointer; padding: 6px 0; }

.end-actions { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; margin-top: 24px; }

/* Progress tab: students who could use a nudge */
.nudges { margin: 0; padding-left: 20px; }
.nudges li { margin: 4px 0; }
tr.flagged td:first-child { box-shadow: inset 4px 0 0 var(--sun); }

.shelf-group h3 { margin: 4px 0 0; }

/* Topics & skills tab: each focus period folds into a one-line summary */
.focus-fold { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); margin-top: 12px; }
.focus-fold > .focus-summary { cursor: pointer; padding: 14px 16px; list-style-position: inside; }
.focus-fold > form.card { box-shadow: none; border: none; border-top: 1px solid var(--line); border-radius: 0 0 var(--radius) var(--radius); }

/* Read to me: the sentence being read lights up like a karaoke line. */
.story-text .sent, .story-title { border-radius: 6px; transition: background-color .25s, box-shadow .25s; }
.story-text .sent.reading, .story-title.reading { background: #fff2b3; color: #2b2100; box-shadow: 0 0 0 3px #fff2b3; }

/* Roster: per-student save note */
.row-status { display: block; font-size: .85rem; min-height: 1.2em; color: var(--muted); }
.row-status.ok { color: var(--ok); }
.row-status.wait { color: #9a6700; }
.row-status.bad { color: var(--bad); }

/* Making a reader: "your hero so far" at the top of every step */
.hero-so-far { display: flex; align-items: center; gap: 12px; background: var(--card); border: 1px solid var(--line); border-radius: 999px; padding: 6px 18px 6px 6px; box-shadow: var(--shadow); width: fit-content; max-width: 100%; margin: 0 auto; }
.hero-so-far .avatar { width: 64px; height: 64px; }
.hero-so-far-text { line-height: 1.25; }

.field-hint { font-size: .9rem; margin-top: 4px; }
.epic-cast { background: var(--bg2); border-radius: 12px; padding: 10px 14px; margin: 0; display: grid; gap: 8px; }
.epic-cast-list { display: flex; flex-wrap: wrap; gap: 10px 14px; }
.epic-cast-kid { display: flex; flex-direction: column; align-items: center; gap: 2px; font-size: .8rem; font-weight: 700; width: 62px; text-align: center; line-height: 1.1; }
.epic-cast-kid .avatar, .epic-cast-kid .face-todo { width: 44px !important; height: 44px !important; }

.teamup-line { font-size: 1.2rem; font-weight: 700; margin: 0; }

/* Library preview: parts that change per student */
mark.blank-filled { background: #fff2b3; color: #2b2100; border-radius: 4px; padding: 0 3px; }
.preview-text { font-size: 1.15rem; }

/* My character: the treasure collection */
.treasure-count { font-weight: 700; font-size: 1.1rem; margin: 0; }
.treasure { display: flex; gap: 12px; align-items: flex-start; padding: 10px 0; border-bottom: 1px solid var(--line); }
.treasure:last-child { border-bottom: none; }
.treasure-emoji { font-size: 2rem; line-height: 1; min-width: 2.4rem; text-align: center; }
.treasure-pic { width: 64px; height: 64px; border-radius: 14px; object-fit: cover; flex: none; box-shadow: var(--shadow); }
.treasure .pill { font-size: .75rem; padding: 1px 8px; }

/* QR cards: steps for the family on each card */
.qr-card .card-brand { font-weight: 700; }
.qr-card .card-steps { text-align: left; font-size: .85rem; margin: 6px 0; padding-left: 20px; }
.qr-card .card-steps li { margin: 2px 0; }
.qr-card .card-keep { font-size: .75rem; font-style: italic; margin-bottom: 4px; }

/* Start page: how Hojas works */
.how-steps { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.how-steps li { display: flex; gap: 12px; align-items: center; }
.how-icon { font-size: 2rem; min-width: 2.6rem; text-align: center; }

/* Home greeting: the hero waves hello */
.hello-line { margin: 0; font-weight: 600; }
.wave-hello { display: inline-block; transform-origin: 50% 90%; animation: wave-hello 1.4s ease-in-out .3s 2; }
@keyframes wave-hello { 0%, 100% { transform: rotate(0); } 25% { transform: rotate(-8deg); } 75% { transform: rotate(8deg); } }
@media (prefers-reduced-motion: reduce) { .wave-hello { animation: none; } }

.fail-why { font-size: .85rem; max-width: 42ch; }

/* Storybook: a leafy path that fills in as you read, toward the treasure */
/* The path gets a whole row to itself; the arrows, page count and Read to me sit together under it. */
.trail { flex: 0 0 100%; display: flex; align-items: center; justify-content: center; gap: 10px; margin: 0 0 4px; padding-top: 14px; }
.trail-path { position: relative; flex: 0 1 520px; height: 10px; border-radius: 999px; background: var(--line); }
.trail-fill { position: absolute; inset: 0 auto 0 0; width: 0; border-radius: 999px; background: linear-gradient(90deg, #8fd887, var(--leaf)); transition: width .45s ease; }
.trail-leaf { position: absolute; top: 50%; left: 0; transform: translate(-50%, -60%); font-size: 1.4rem; transition: left .45s ease; }
.trail-goal { font-size: 1.4rem; }
/* The kid's hero walking the path: a little bob with each page turn */
.trail-hero { line-height: 0; transform: translate(-50%, -55%); }
.trail-hero .avatar { border: 2px solid var(--card); box-shadow: 0 2px 6px rgba(0,0,0,.18); }
.trail-hero.step { animation: hero-step .45s ease; }
@keyframes hero-step { 0%, 100% { transform: translate(-50%, -55%); } 50% { transform: translate(-50%, -85%); } }
.trail.arrived .trail-goal { animation: award-wiggle 1s ease-in-out 2; }
@media (prefers-reduced-motion: reduce) { .trail-fill, .trail-leaf { transition: none; } .trail.arrived .trail-goal, .trail-hero.step { animation: none; } }

.field-note { display: block; font-weight: 400; margin-top: 4px; }

/* Classes list: current classes up front, past ones folded by term */
.class-tile { text-decoration: none; color: inherit; position: relative; transition: transform .15s ease, box-shadow .15s ease, border-color .15s; }
.class-tile:hover { transform: translateY(-3px); border-color: var(--leaf); box-shadow: 0 16px 30px -14px rgba(60, 80, 40, 0.4); }
.class-tile::after { content: "›"; position: absolute; top: 14px; right: 18px; font-size: 1.8rem; line-height: 1; color: var(--leaf); font-weight: 800; }
.class-tile.archived { opacity: .75; }
.past-classes > summary { padding: 8px 0; font-weight: 700; }

/* Picture PIN: words under the pictures, a pop on tap, a gentle shake when wrong */
.pin-pad button { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; }
.pin-pad .pin-emoji { font-size: clamp(2rem, 8vw, 2.8rem); line-height: 1; }
.pin-pad .pin-word { font-size: .8rem; font-weight: 700; color: var(--muted); }
.pin-pad button.pop { animation: pin-pop .3s ease-out; }
@keyframes pin-pop { 0% { transform: scale(1); } 50% { transform: scale(1.15); background: var(--leaf-soft); } 100% { transform: scale(1); } }
.pin-pad.shake { animation: pin-shake .5s ease-in-out; }
@keyframes pin-shake { 0%, 100% { transform: translateX(0); } 20%, 60% { transform: translateX(-10px); } 40%, 80% { transform: translateX(10px); } }
@media (prefers-reduced-motion: reduce) { .pin-pad button.pop, .pin-pad.shake { animation: none; } }

.invite-summary { font-size: 1.15rem; font-weight: 700; margin: 0; min-height: 1.4em; }

/* Roster: the student you just added stands out */
tr.just-added td { background: var(--leaf-soft); }

/* Classroom presenter: a labeled exit and a tip that fades away */
.present-exit { position: fixed; top: 10px; left: 10px; z-index: 5; }
.present-tip { position: fixed; top: 12px; left: 50%; transform: translateX(-50%); z-index: 5; max-width: min(92vw, 640px);
  background: var(--ink); color: var(--bg); padding: 10px 16px; border-radius: 14px; font-weight: 700; text-align: center;
  transition: opacity .6s ease; }
.present-tip.gone { opacity: 0; pointer-events: none; }

/* End of story: a word hunt for the skill the story practiced */
.word-hunt { max-width: 640px; margin: 10px auto 18px; padding: 14px 16px; border-radius: 16px; background: var(--leaf-soft); text-align: center; }
.word-hunt h3 { margin-top: 0; }
.word-chips { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; }
.word-chip { padding: 6px 14px; border-radius: 999px; background: var(--card); border: 2px solid var(--leaf); font-family: var(--read-font); font-weight: 700; font-size: 1.15rem; }

.help-section h2 { font-size: 1.3rem; }
.help-section p { margin: 0; }

/* Saved-link page: the new hero, and home-screen steps (this device's own steps first) */
.saved-hero { margin: 0 auto; }
.home-steps { margin: 0; padding-left: 20px; }
.home-steps li { margin: 4px 0; }
.home-steps li.mine { font-weight: 700; }

.cost-note { margin: 0; font-size: .9rem; }

/* Roster: one plain sign-in status per student */
.signin { font-weight: 600; font-size: .9rem; }
.signin.ok { color: var(--ok); }
.signin.wait { color: #9a6700; }
.signin.bad { color: var(--bad); }
.signin-hint { font-weight: 400; font-size: .8rem; max-width: 28ch; }

/* Home: the character card opens the treasures; an empty shelf that looks ready */
.link-card { text-decoration: none; color: inherit; cursor: pointer; transition: transform .1s ease, box-shadow .15s; }
.link-card:hover { transform: translateY(-2px); }
.link-card:focus-visible { outline: 3px solid var(--sun); outline-offset: 3px; }
.see-more { color: var(--leaf-dark); font-weight: 700; font-size: .95rem; }
.empty-shelf .spines { display: flex; gap: 6px; justify-content: center; align-items: flex-end; height: 70px; border-bottom: 6px solid #b07a50; padding: 0 20px; }
.empty-shelf .spines span { width: 16px; border-radius: 4px 4px 0 0; opacity: .35; }
.empty-shelf .spines span:nth-child(1) { height: 50px; } .empty-shelf .spines span:nth-child(2) { height: 62px; }
.empty-shelf .spines span:nth-child(3) { height: 44px; } .empty-shelf .spines span:nth-child(4) { height: 58px; }
.empty-shelf .spines span:nth-child(5) { height: 48px; }

/* Library: topic emoji, skill tags, who it is for */
.library-item { align-items: flex-start; }
/* Picking for a class: a story outside its reading range or languages says so */
.library-misfit { margin-top: 6px; padding: 4px 10px; border-radius: 10px; background: color-mix(in srgb, var(--sun) 22%, transparent); font-size: .85rem; font-weight: 700; }
.library-emoji { font-size: 2rem; line-height: 1; }

/* Story pictures: an artist at work while painting, and a gentle fade-in when ready */
.story-img.pending { text-align: center; padding: 12px; }
.painting { position: relative; font-size: 3rem; line-height: 1; display: inline-block; }
.painting .brush { position: absolute; right: -18px; bottom: 4px; font-size: 1.8rem; transform-origin: 20% 80%; animation: brush-dab 1.2s ease-in-out infinite; }
@keyframes brush-dab { 0%, 100% { transform: rotate(-10deg) translate(0, 0); } 50% { transform: rotate(18deg) translate(-8px, -6px); } }
img.fade-pic { opacity: 0; transform: scale(.98); transition: opacity .6s ease, transform .6s ease; }
img.fade-pic.loaded { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { .painting .brush { animation: none; } img.fade-pic { opacity: 1; transform: none; transition: none; } }

.row input[type="search"] { flex: 1; min-width: 200px; min-height: 42px; padding: 6px 12px; border-radius: 12px; border: 2px solid var(--line); background: var(--card); }

/* Kid top bar: a globe on the language menu, and a "Me" button with the kid's own hero */
.lang-pick { display: inline-flex; align-items: center; gap: 4px; }
.me-btn { gap: 6px; padding-left: 6px; }
.me-btn .avatar { width: 28px; height: 28px; }
.who-btn { display: inline-flex; align-items: center; gap: 10px; }

/* Team-up page: a small pulsing dot says the page is keeping watch for friends' answers */
.live-note { display: flex; align-items: center; gap: 8px; margin: 0; }
.live-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--leaf); animation: live-pulse 1.6s ease-in-out infinite; flex: none; }
@keyframes live-pulse { 0%, 100% { opacity: .35; transform: scale(.8); } 50% { opacity: 1; transform: scale(1.1); } }
@media (prefers-reduced-motion: reduce) { .live-dot { animation: none; } }

/* Roster and Progress on phones: each student becomes a small card (name on top, the
   details in two columns with their labels, the buttons along the bottom) instead of a
   wide table that scrolls sideways. */
@media (max-width: 640px) {
  table.cards-on-phone thead { display: none; }
  table.cards-on-phone, table.cards-on-phone tbody { display: block; width: 100%; }
  table.cards-on-phone tr { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 12px; padding: 12px 14px; margin-bottom: 12px;
    border: 1px solid var(--line); border-radius: 16px; background: var(--card); box-shadow: var(--press); }
  table.cards-on-phone tr.flagged { box-shadow: inset 4px 0 0 var(--sun), var(--press); }
  table.cards-on-phone tr.flagged td:first-child { box-shadow: none; }
  table.cards-on-phone td { display: block; padding: 0; border: 0; min-width: 0; }
  table.cards-on-phone tbody tr:hover td { background: none; }
  table.cards-on-phone td[data-label]::before { content: attr(data-label); display: block; font-size: .7rem; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--muted); margin-bottom: 2px; }
  table.cards-on-phone td.cell-name, table.cards-on-phone td.cell-actions, table.cards-on-phone td.cell-range { grid-column: 1 / -1; }
  table.cards-on-phone td.cell-name { font-size: 1.1rem; }
  table.cards-on-phone td select { min-width: 0; width: 100%; }
  /* A student's own reading range: lowest over highest, each full width, so neither level is cut off */
  table.cards-on-phone .range-pair { flex-direction: column; align-items: stretch; gap: 6px; }
  table.cards-on-phone .range-pair select { flex: none; }
  table.cards-on-phone .range-dash { display: none; }
  table.cards-on-phone .signin-hint { max-width: none; }
  .card.table-wrap:has(table.cards-on-phone) { background: transparent; border: 0; box-shadow: none; padding: 0; }
}

/* Teacher story page: what the story is, at a glance */
.story-about { padding: 12px 16px; display: grid; gap: 8px; }
.story-about-line { font-weight: 700; }
.story-about-tags { gap: 6px; }

/* Story picker: a guided 1-2-3 path. The step bar shows what's picked and what's next. */
.pick-steps { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.pick-steps li { position: relative; }
.pick-steps li + li::before { content: ""; position: absolute; left: -8px; top: 50%; width: 8px; height: 3px; background: var(--line-strong); }
.pick-steps li.done + li::before { background: var(--leaf); }
.pick-steps button {
  width: 100%; height: 100%; display: flex; align-items: center; gap: 10px; text-align: left; padding: 8px 10px; min-height: 64px;
  border-radius: 18px; border: 2px solid var(--line-strong); background: var(--card); color: var(--ink); font: inherit; cursor: pointer;
  box-shadow: var(--press); transition: transform .1s ease, border-color .15s, background .15s;
}
.pick-steps li.done button { border-color: var(--leaf); background: var(--leaf-soft); }
.pick-steps li.now button { border-color: var(--leaf-dark); box-shadow: 0 0 0 4px var(--leaf-soft), var(--press); }
.pick-steps li.locked button { opacity: .55; cursor: not-allowed; box-shadow: none; }
.pick-steps li.open:not(.now) button:hover { transform: translateY(-2px); }
.pick-step-num { flex: none; width: 40px; height: 40px; border-radius: 50%; display: grid; place-items: center; font-weight: 800; font-size: 1.2rem; background: var(--card-2); border: 2px solid var(--line-strong); }
.pick-steps li.now .pick-step-num { background: var(--leaf); border-color: var(--leaf-dark); color: #fff; }
.pick-step-pic { flex: none; width: 44px; height: 44px; border-radius: 12px; object-fit: cover; }
.pick-step-text { display: flex; flex-direction: column; min-width: 0; line-height: 1.15; }
.pick-step-title { font-weight: 800; font-size: .95rem; }
.pick-step-chosen { font-size: .8rem; font-weight: 600; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 520px) {
  .pick-steps button { flex-direction: column; justify-content: center; text-align: center; gap: 4px; padding: 8px 4px; }
  .pick-step-text { align-items: center; max-width: 100%; }
  .pick-step-chosen { max-width: 100%; }
}
/* Step 3: the story taking shape, topic + goal */
.pick-review { display: flex; align-items: center; justify-content: center; gap: 12px; flex-wrap: wrap; }
.pick-review-part { display: flex; flex-direction: column; align-items: center; gap: 6px; width: min(42%, 180px); padding: 8px; border-radius: 18px;
  border: 2px solid var(--leaf); background: var(--leaf-soft); font: inherit; font-weight: 800; color: var(--ink); cursor: pointer; box-shadow: 0 3px 0 var(--leaf); }
.pick-review-part img { width: 100%; aspect-ratio: 1; object-fit: cover; border-radius: 12px; }
.pick-review-part .emoji { font-size: 3rem; }
.pick-review-plus { font-size: 2rem; font-weight: 800; color: var(--leaf); }
.pick-write { animation: award-pop .4s ease-out; }
.pick-optional { border-top: 1px dashed var(--line-strong); padding-top: 12px; }
.pick-optional p { margin: 4px 0 0; }
@media (prefers-reduced-motion: reduce) { .pick-write { animation: none; } }

/* Making a hero: the hero stays in view while you scroll through the choices, just under the
   top bar at its real height (two rows on a phone with the Me button, so a fixed spot hid it) */
.look-preview { position: sticky; top: calc(var(--topbar-h, 68px) + 4px); z-index: 4; padding: 8px 0; background: linear-gradient(var(--card) 80%, transparent); }
@media (max-width: 520px) { .look-preview .avatar { width: 104px !important; height: 104px !important; } }

/* Story lists: a small picture beside each title, and its topic under it */
.story-cell { display: flex; align-items: center; gap: 10px; min-width: 180px; }
.story-thumb { width: 44px; height: 44px; border-radius: 10px; object-fit: cover; flex: none; box-shadow: var(--shadow); }
.story-thumb.emoji { display: grid; place-items: center; font-size: 1.5rem; background: var(--leaf-soft); box-shadow: none; }
.story-topic { font-size: .8rem; }

/* Under a teacher dropdown: the chosen style's (or topic's) picture beside its description */
.select-desc { display: flex; align-items: center; gap: 10px; margin-top: 6px; }
.select-pic { width: 72px; height: 72px; border-radius: 12px; object-fit: cover; flex: none; box-shadow: var(--shadow); }

/* Making a reader: room above "Powers", and the picked treasures as little pictures in the hero bar */
.picks-powers { margin-top: 22px !important; }
.pick-thumbs { display: flex; gap: 4px; margin-top: 2px; }
.pick-thumbs img { width: 24px; height: 24px; border-radius: 6px; object-fit: cover; }

/* Teacher story page (admin): the storyteller voice's status and its button */
.voice-line { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; font-size: .95rem; }

/* Admin overview: the storyteller voices at a glance */
.voice-summary ul { margin: 0; padding-left: 20px; display: grid; gap: 4px; }
.voice-summary code { font-size: .85rem; background: var(--card-2); padding: 1px 6px; border-radius: 6px; overflow-wrap: anywhere; }

/* Questions: a skipped question gets a gentle nudge when a kid checks their answers */
.question.needs-answer { border-color: var(--sun); box-shadow: 0 0 0 4px color-mix(in srgb, var(--sun) 30%, transparent); animation: pin-shake .5s ease-in-out; }
.question.needs-answer legend::after { content: " 👆"; }
.question.needs-answer::before { content: attr(data-pick); display: block; font-weight: 800; color: #9a6700; margin: 2px 0 6px; }
@media (prefers-reduced-motion: reduce) { .question.needs-answer { animation: none; } }

/* Classroom presenter: The End readable from the back of the room */
.reader.presenter .quiz { max-width: 1100px; }
.reader.presenter .quiz > h3 { font-size: clamp(1.8rem, 3vw, 2.6rem); }
.reader.presenter .question legend { font-size: clamp(1.4rem, 2.4vw, 2.1rem); }
.reader.presenter .answer { font-size: clamp(1.3rem, 2.2vw, 1.9rem); padding: 10px 14px; }
.reader.presenter .answer input { width: 28px; height: 28px; }
.reader.presenter .word-hunt { max-width: 1100px; }
.reader.presenter .word-hunt h3 { font-size: clamp(1.6rem, 2.6vw, 2.2rem); }
.reader.presenter .word-hunt p { font-size: clamp(1.1rem, 1.8vw, 1.5rem); }
.reader.presenter .word-chip { font-size: clamp(1.4rem, 2.4vw, 2rem); padding: 8px 20px; }
.assign-hint { flex-basis: 100%; margin: 0; }

/* Team-ups: each teammate's hero with their answer */
.team-members { display: flex; flex-wrap: wrap; gap: 10px; }
.team-member { display: flex; align-items: center; gap: 8px; padding: 6px 12px 6px 6px; border-radius: 999px; background: var(--card-2); border: 2px solid var(--line); font-size: .95rem; line-height: 1.2; }
.team-member.accepted { border-color: var(--leaf); background: var(--leaf-soft); }
.team-member.declined { opacity: .6; }

/* Roster and Progress: each student's hero beside their name */
.student-name { display: flex; align-items: center; gap: 8px; }
.student-name strong { white-space: nowrap; }
.face-todo { width: 34px; height: 34px; border-radius: 50%; display: inline-grid; place-items: center; background: var(--card-2); border: 2px dashed var(--line-strong); font-size: .9rem; flex: none; }
.cell-name .btn.ghost { gap: 8px; }

/* Story cover: the stars' heroes in a row, overlapping a little like a group photo */
.cover-cast { display: flex; flex-wrap: wrap; justify-content: center; margin: 4px auto 2px; max-width: 720px; }
.cover-cast .avatar { border: 3px solid var(--card); box-shadow: var(--shadow); margin: 0 -6px 6px; animation: award-pop .5s cubic-bezier(.2, 1.6, .4, 1) both; }
.cover-cast .avatar:nth-child(2) { animation-delay: .08s; } .cover-cast .avatar:nth-child(3) { animation-delay: .16s; } .cover-cast .avatar:nth-child(4) { animation-delay: .24s; }
@media (prefers-reduced-motion: reduce) { .cover-cast .avatar { animation: none; } }

/* Treasure pills with their painted picture (home greeting) */
.pill.with-pic { padding-left: 4px; }
.pill-pic { width: 26px; height: 26px; border-radius: 50%; object-fit: cover; border: 2px solid var(--card); }

/* Bookshelf: friends in a team-up or epic peek out from the bottom of its cover */
.book-cover { position: relative; }
.book-cast { position: absolute; left: 8px; bottom: 8px; display: flex; align-items: center; }
.book-cast .avatar { border: 2px solid var(--card); margin-right: -8px; box-shadow: 0 2px 6px rgba(0, 0, 0, .18); }
.book-cast-more { margin-left: 12px; padding: 1px 7px; border-radius: 999px; background: var(--card); font-size: .75rem; font-weight: 800; box-shadow: 0 2px 6px rgba(0, 0, 0, .18); }
.class-faces { gap: 16px; } .class-faces .book-cast { position: static; }

/* The treasure collection as a grid of little collector cards, newest first */
.treasure-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 128px), 1fr)); gap: 10px; }
.treasure-grid .treasure { min-width: 0; overflow-wrap: anywhere; }
.treasure-grid .treasure { flex-direction: column; align-items: center; text-align: center; gap: 6px; padding: 12px 10px;
  border: 2px solid var(--line); border-radius: 18px; background: var(--card-2); animation: award-pop .35s ease both; }
.treasure-grid .treasure:last-child { border-bottom: 2px solid var(--line); }
.treasure-grid .treasure.power { border-color: #c9a8f5; }
.treasure-grid .treasure-pic { width: 96px; height: 96px; }
.treasure-grid .treasure-emoji { font-size: 3rem; min-height: 96px; display: grid; place-items: center; }
.treasure-grid .treasure > div { display: grid; gap: 4px; justify-items: center; font-size: .92rem; }
.treasure-grid .treasure strong { font-size: 1rem; }
@media (prefers-reduced-motion: reduce) { .treasure-grid .treasure { animation: none; } }
.voice-summary .voice-problem { margin: 0; padding: 8px 12px; border-radius: 12px; background: color-mix(in srgb, var(--bad) 12%, transparent); overflow-wrap: anywhere; }
.voice-summary .voice-problem p { margin: 6px 0 0; }
/* Progress nudges: the next step for each one, right beside it */
.nudge-actions { display: inline-flex; flex-wrap: wrap; gap: 6px; margin-left: 8px; vertical-align: middle; }
.nudges li { margin: 8px 0; }
/* Team-up: classmates already on a team, shown (not pickable) under the "who" choices */
.busy-mates { gap: 8px 14px; font-size: .92rem; }
.busy-mate { display: inline-flex; align-items: center; gap: 6px; opacity: .75; }
.voice-note { font-size: .82rem; margin-top: 2px; }
/* Bookshelf: a storyteller can read this book (or is getting ready to) */
.badge.voice-badge { background: #efe3ff; color: #4b2a7a; }
.badge.voice-badge.making { opacity: .75; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .badge.voice-badge { background: #3a2d52; color: #e6d8ff; } }
:root[data-theme="dark"] .badge.voice-badge { background: #3a2d52; color: #e6d8ff; }

/* Word hunt: tap a word to hear it (a little bounce each time) */
button.word-chip { cursor: pointer; color: var(--ink); box-shadow: 0 3px 0 var(--leaf); transition: transform .08s ease; }
button.word-chip:active { transform: translateY(2px); box-shadow: 0 1px 0 var(--leaf); }
button.word-chip.said { animation: word-bounce .45s ease; background: var(--sun); }
button.word-chip.found { background: var(--leaf-soft); border-color: var(--leaf); }
.hunt-score { margin: 4px 0; font-weight: 800; color: var(--leaf-dark); }
@keyframes word-bounce { 0% { transform: scale(1); } 40% { transform: scale(1.18); } 100% { transform: scale(1); } }
.word-hunt-tip { margin: -4px 0 10px; font-size: 1rem; font-weight: 700; }   /* how to play: easy to read, not small print */
@media (prefers-reduced-motion: reduce) { button.word-chip.said { animation: none; } }
.listen-hint { margin-top: 0; }

.voice-summary .voice-progress { margin: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; }
.voice-summary .voice-progress progress { flex: 1 1 160px; height: 10px; accent-color: var(--leaf); }

.badge.plain { background: var(--card-2); color: var(--muted); border: 1px solid var(--line); }

/* A treasure earned in the last day */
.treasure-grid .treasure { position: relative; }
.treasure-grid .treasure.new { border-color: var(--sun); box-shadow: 0 0 0 3px color-mix(in srgb, var(--sun) 35%, transparent); }
.treasure-new { position: absolute; top: -8px; right: -6px; }
/* Home: a treasure earned in the last day glows among the others */
.pill.new-pill { box-shadow: 0 0 0 2px var(--sun), 0 0 12px color-mix(in srgb, var(--sun) 70%, transparent); animation: new-glow 2.4s ease-in-out infinite; }
.pill .new-tag { font-size: .72rem; font-weight: 800; padding: 0 6px; border-radius: 999px; background: var(--sun); color: #3a2a00; }
@keyframes new-glow { 0%, 100% { box-shadow: 0 0 0 2px var(--sun), 0 0 6px transparent; } 50% { box-shadow: 0 0 0 2px var(--sun), 0 0 14px color-mix(in srgb, var(--sun) 80%, transparent); } }
@media (prefers-reduced-motion: reduce) { .pill.new-pill { animation: none; } }
.award-more { display: inline-block; margin-top: 6px; font-weight: 700; }

/* Picker review: the kid's hero + topic + goal, three across (smaller on phones) */
.pick-review.three { gap: 6px; }
.pick-review.three .pick-review-part { width: min(28%, 160px); }
.pick-review.three .pick-review-plus { font-size: 1.5rem; }
.pick-review-part.hero svg { width: 100%; height: auto; }
.pick-review-part.hero { cursor: default; }
.pick-review-part.hero { box-shadow: none; border-color: var(--sun); background: var(--card); }

/* Bookshelf: stories read so far, with a badge at milestones */
.read-count { margin: -4px 0 0; font-weight: 700; display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.read-badge { font-size: .85rem; }
.read-count-wrap { gap: 4px; margin-top: -4px; }
.read-count-wrap .read-count { margin: 0; }
.next-badge { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; font-size: .9rem; font-weight: 700; color: var(--muted); }
.next-badge progress { width: 140px; height: 10px; accent-color: var(--sun); }

/* Tap a sentence to hear it */
.tap-to-hear .story-text .sent { cursor: pointer; border-radius: 6px; }
@media (hover: hover) { .tap-to-hear .story-text .sent:hover { background: color-mix(in srgb, var(--sun) 18%, transparent); } }

/* Select words to translate them: the button under the selection, then the translation */
.translate-pop { position: absolute; z-index: 60; max-width: min(420px, calc(100vw - 16px)); padding: 10px 12px; border-radius: 16px;
  background: var(--card); border: 2px solid var(--leaf); box-shadow: var(--shadow); display: grid; gap: 8px; justify-items: start; }
.translate-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; width: 100%; font-size: .9rem; }
.translate-close { min-height: 30px; padding: 2px 10px; }
.translate-text { margin: 0; font-family: var(--read-font); font-size: 1.2rem; line-height: 1.45; }
.translate-busy { font-weight: 700; }
/* Translation bubble: the picked words, then their translation, each with a hear button */
.translate-row { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 4px 10px; width: 100%; }
.translate-lang { grid-column: 1 / -1; font-size: .75rem; font-weight: 800; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); }
.translate-row .translate-original, .translate-row .translate-text { grid-column: 1 / 3; margin: 0; }
.translate-original { font-family: var(--read-font); font-size: 1.05rem; color: var(--muted); }
.translate-row.from { padding-bottom: 8px; border-bottom: 1px dashed var(--line-strong); }
.translate-hear { min-height: 34px; padding: 2px 10px; }
.present-tip { cursor: pointer; }   /* click to hide it early */

/* The End: the kid's hero hops beside the treasure they just earned */
.award-hero { flex: none; display: inline-flex; animation: hero-hop .6s ease-in-out 1.1s 3; }
.award-hero svg { width: 84px; height: 84px; }
@media (prefers-reduced-motion: reduce) { .award-hero { animation: none; } }
@media (max-width: 420px) { .award-hero svg { width: 64px; height: 64px; } }
/* Class tiles: what's stopping a current class from getting stories, with the fix */
.tile-warning { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; margin-top: 8px; padding: 8px 10px; border-radius: 12px;
  background: color-mix(in srgb, var(--sun) 22%, transparent); font-size: .9rem; font-weight: 700; }
/* Waiting for a story: the topic and goal the kid picked, as little pictures */
.wait-picks { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 8px 12px; }
.wait-pick { display: inline-flex; align-items: center; gap: 8px; padding: 4px 12px 4px 4px; border-radius: 999px; background: var(--card); border: 2px solid var(--leaf); font-weight: 800; animation: award-pop .5s ease both; }
.wait-pick img { width: 44px; height: 44px; border-radius: 50%; object-fit: cover; }
@media (prefers-reduced-motion: reduce) { .wait-pick { animation: none; } }
/* Read, but the questions at The End are still waiting: tap to go straight to them */
.badge.quiz-badge { background: #dff1ff; color: #174a7a; cursor: pointer; animation: quiz-nudge 2.4s ease-in-out infinite; }
.badge.quiz-badge:hover { filter: brightness(.95); }
@keyframes quiz-nudge { 0%, 85%, 100% { transform: none; } 90% { transform: rotate(-6deg); } 95% { transform: rotate(6deg); } }
@media (prefers-reduced-motion: reduce) { .badge.quiz-badge { animation: none; } }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .badge.quiz-badge { background: #1f3a55; color: #cfe7ff; } }
:root[data-theme="dark"] .badge.quiz-badge { background: #1f3a55; color: #cfe7ff; }
/* Me page: quick jumps to each part of a long page */
.me-jumps { display: flex; flex-wrap: wrap; gap: 8px; }

/* Starting treasures: the bag is full, and how to swap one */
.picks-full { margin: 0; padding: 8px 12px; border-radius: 12px; background: var(--leaf-soft, #e6f4df); color: var(--ink, inherit); font-weight: 600; }

/* The End's "you earned" card on a phone: the hero and treasure side by side on top, the words
   below at full width (squeezed into one row, the words got a narrow strip and ran into the edge) */
@media (max-width: 480px) {
  .award { flex-wrap: wrap; justify-content: center; text-align: center; }
  .award > div:last-child { flex: 1 1 100%; min-width: 0; }
}

/* Progress: a student's name opens their stories, so it reads as a link */
.name-link .name-link-text { color: var(--leaf-dark); text-decoration: underline; text-underline-offset: 3px; }
.name-link .name-link-arrow { color: var(--leaf-dark); font-weight: 800; }

/* "Your story" review: the hero fits its tile like the topic and goal pictures do (it's drawn at
   a fixed 120px, which spilled over the tile and the card on a phone) */
.pick-review-part.hero .avatar { width: 100% !important; height: auto !important; aspect-ratio: 1; max-width: 120px; }

/* Phone cards: the name or title always leads the card, even when it isn't the first column */
@media (max-width: 640px) { table.cards-on-phone td.cell-name { order: -1; } }

/* Admin teacher cards on a phone: a long email gets the whole width and may wrap */
@media (max-width: 640px) { table.cards-on-phone td.cell-email { grid-column: 1 / -1; overflow-wrap: anywhere; } }


/* "Your story: topic + goal": the plus and the goal wrap as one piece */
.wait-picks-and { display: inline-flex; align-items: center; gap: 12px; }

/* Classroom presenter cover: the picture is sized by the screen's height, so on a projector
   the title and the class's heroes fit below it instead of falling off the bottom */
.reader.presenter .cover .story-img { height: min(44vh, 540px); width: auto; max-width: 100%; aspect-ratio: 4 / 3; }

/* The kids' cover on a short laptop screen (a Chromebook's 1366x768): the picture takes the
   height that's left, so the title and heroes still show above the page controls. Tall screens
   keep the full-size picture; phones (sized by width) are unchanged. */
@media (min-width: 700px) {
  .reader:not(.presenter) .cover .story-img { height: clamp(220px, calc(100vh - 420px), 540px); width: auto; max-width: 100%; aspect-ratio: 4 / 3; }
}

/* Teacher sign-in: a wrong email or password stays in the form until the teacher types again */
.login-problem { margin: 0; color: var(--bad); font-weight: 700; }
.login-problem:empty { display: none; }

/* Add a student: a name the server won't take is explained right under the name box */
.name-note:not(:empty) { color: var(--bad); font-weight: 700; }
/* ...while "that name is already in the class" is a heads-up, not a problem */
.name-note.info:not(:empty) { color: var(--ink); }

/* Start page link box: what to paste, said right under the box */
.link-note { margin: 8px 0 0; font-weight: 700; color: var(--bad); }
.link-note:empty { display: none; }

/* Printing QR cards: no blank extra page (the screen's full-height body spilled onto one),
   and cards compact enough for two rows (six cards) a sheet. The codes stay about 1.5 inches,
   plenty for a phone camera. */
@media print {
  body { min-height: 0; }
  .cards { gap: 8px; }
  .qr-card { padding: 8px; }
  .qr-card img { width: 140px; height: 140px; }
  .qr-card .name { font-size: 1.2rem; }
  .qr-card .card-steps { font-size: .78rem; margin: 4px 0; }
  .qr-card .card-steps li { margin: 1px 0; }
}

/* Words meant only for a printed page (say, what to do with a printed reader link) */
.print-only { display: none; }
@media print { .print-only { display: block; font-weight: 700; } }

/* Dark mode: The End's award card turns a warm dark gold (its pale yellow left the grey and
   green lines faint), and the "Today's story" card keeps a deep green behind its white words
   (dark mode's lighter greens washed them out, and its button's green words on white). */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .award { background: #3a3116; color: #fff1c7; }
  :root:not([data-theme="light"]) .today-card { background: linear-gradient(135deg, #2f7a2a, #3f8f3a); }
  :root:not([data-theme="light"]) .today-card .btn { color: #2f7a2a; }
}
:root[data-theme="dark"] .award { background: #3a3116; color: #fff1c7; }
:root[data-theme="dark"] .today-card { background: linear-gradient(135deg, #2f7a2a, #3f8f3a); }
:root[data-theme="dark"] .today-card .btn { color: #2f7a2a; }

/* Dark mode: green buttons keep a deep green behind their white words (dark mode's lighter
   green left white-on-green at about 2:1, too faint to read comfortably) */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .btn.primary:not(.not-ready) { background: linear-gradient(180deg, #3a8d34, #2f7a2a); border-color: #25601f; box-shadow: 0 4px 0 #1d4d19; }
  :root:not([data-theme="light"]) .btn.primary:not(.not-ready):active:not(:disabled) { box-shadow: 0 1px 0 #1d4d19; }
}
:root[data-theme="dark"] .btn.primary:not(.not-ready) { background: linear-gradient(180deg, #3a8d34, #2f7a2a); border-color: #25601f; box-shadow: 0 4px 0 #1d4d19; }
:root[data-theme="dark"] .btn.primary:not(.not-ready):active:not(:disabled) { box-shadow: 0 1px 0 #1d4d19; }

/* Help: a long section's paragraphs, with a little space between them */
.help-section p { margin: 0; }
.help-section p + p { margin-top: 10px; }

/* Word hunt: what the skill is, in kid words */
.word-hunt .skill-meaning { margin: 0 0 8px; font-size: .95rem; }

/* A shelf story that didn't work: faded cover, and a line saying tapping it helps */
.book-failed .cover-img { filter: grayscale(.85); opacity: .6; }
.book-failed .failed-next { font-size: .8rem; font-weight: 700; color: var(--leaf-dark); margin-top: 2px; }

/* A choice meant for other grades (reading skills outside the level being written for): faded,
   still pickable, and full strength once picked or hovered. */
.choice.dim:not(.on) { opacity: .55; }
.choice.dim:not(.on):hover, .choice.dim:not(.on):focus-visible { opacity: 1; }

/* A short story page with no picture (a younger reader's page): bigger words fill the page
   instead of a small paragraph over empty space. The classroom screen keeps its own size. */
.reader:not(.presenter) .page:not(.with-img) .story-text.short-text { font-size: clamp(1.5rem, 4.8vw, 2.1rem); line-height: 1.65; }

/* The class's story days are about to run out: the same sunny warning as a class tile's. */
.ends-soon { padding: 8px 12px; border-radius: 12px; background: color-mix(in srgb, var(--sun) 22%, transparent); font-weight: 700; }

/* "Not Remi? Switch reader" under the greeting on a shared device: small, out of the way. */
.not-me { margin: -6px 4px 0; display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 6px; }

/* Word hunt: the word on its page is tappable but looks like any other word (the kid has to
   find it); once tapped it lights up and pops, and the bar above says they found it. */
.hunt-target { cursor: pointer; border-radius: 6px; }
.hunt-target:focus-visible { outline: 3px solid var(--leaf); outline-offset: 2px; }
.hunt-target.got { display: inline-block; background: #c8f2c2; color: #14381a; box-shadow: 0 0 0 4px #c8f2c2; animation: hunt-pop .6s ease-out; }
.hunt-back.got { background: color-mix(in srgb, var(--leaf) 22%, transparent); font-weight: 800; justify-content: center; }
@keyframes hunt-pop { 0% { transform: scale(1); } 40% { transform: scale(1.25); } 100% { transform: scale(1); } }
@media (prefers-reduced-motion: reduce) { .hunt-target.got { animation: none; } }

/* Back at the word hunt after finding a word: its chip pops once, so the find is easy to see. */
button.word-chip.just-found { animation: hunt-pop .7s ease-out .15s; }
@media (prefers-reduced-motion: reduce) { button.word-chip.just-found { animation: none; } }

/* The next-badge bar on home: a soft, rounded track like the reader's trail, not the browser's
   default dark gray bar, with a sunny fill for how close the next badge is. */
.next-badge progress { -webkit-appearance: none; appearance: none; border: 0; border-radius: 999px; overflow: hidden;
  background: var(--leaf-soft); height: 12px; }
.next-badge progress::-webkit-progress-bar { background: var(--leaf-soft); border-radius: 999px; }
.next-badge progress::-webkit-progress-value { background: var(--sun); border-radius: 999px; }
.next-badge progress::-moz-progress-bar { background: var(--sun); border-radius: 999px; }

/* The admin's "storyteller voice: N of M pages done" bar: the same soft, rounded track as the
   kids' badge bar (not the browser's dark gray one), filled in leaf green. */
.voice-summary .voice-progress progress { -webkit-appearance: none; appearance: none; border: 0; border-radius: 999px; overflow: hidden;
  background: var(--leaf-soft); height: 12px; }
.voice-summary .voice-progress progress::-webkit-progress-bar { background: var(--leaf-soft); border-radius: 999px; }
.voice-summary .voice-progress progress::-webkit-progress-value { background: var(--leaf); border-radius: 999px; }
.voice-summary .voice-progress progress::-moz-progress-bar { background: var(--leaf); border-radius: 999px; }

/* The road to the next reading badge: a sticker slot per story, starred once read, and the medal
   swinging at the end. The newest star pops in; reduced motion keeps everything still. */
.badge-track { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 5px; }
.track-dot { width: 24px; height: 24px; border-radius: 50%; display: grid; place-items: center; font-size: .9rem; line-height: 1;
  border: 2px dashed rgba(224, 162, 0, .55); background: var(--card-2); }
.track-dot.filled { border: 2px solid #e0a200; background: radial-gradient(circle at 35% 30%, #fff6cf, #ffd45a); box-shadow: 0 2px 0 #d99a12; }
.track-dot.latest { animation: track-pop .7s cubic-bezier(.3, 1.6, .5, 1) .25s both; }
.track-medal { font-size: 1.45rem; line-height: 1; margin-left: 3px; transform-origin: 50% 0; filter: drop-shadow(0 2px 0 rgba(0, 0, 0, .12));
  animation: medal-sway 3.2s ease-in-out infinite; }
@keyframes track-pop { 0% { transform: scale(.2) rotate(-40deg); } 100% { transform: none; } }
@keyframes medal-sway { 0%, 100% { transform: rotate(-7deg); } 50% { transform: rotate(7deg); } }
@media (prefers-reduced-motion: reduce) { .track-dot.latest, .track-medal { animation: none; } }
.next-badge-line { margin: 0; }

/* Roster: each student's buttons on one line, the less-used ones behind a "⋯" menu that floats
   above the table (top layer), so a class of 25 is a short list, not a wall of buttons. */
.row-actions { gap: 8px; justify-content: flex-end; }
.btn.more-btn { min-width: 44px; padding: 4px 10px; font-size: 1.25rem; line-height: 1; letter-spacing: 1px; }
.btn.more-btn.open { background: var(--leaf-soft); border-color: var(--leaf); }
.more-pop { position: fixed; inset: auto; margin: 0; padding: 6px; min-width: 190px; border: 1px solid var(--line-strong); border-radius: 16px;
  background: var(--card); color: var(--ink); box-shadow: var(--shadow), 0 18px 40px -16px rgba(40, 60, 30, .35); }
.more-pop:popover-open { display: flex; flex-direction: column; gap: 2px; animation: more-in .16s ease-out; }
.more-pop.above:popover-open { animation-name: more-in-up; }
.more-pop .more-item { display: flex; justify-content: flex-start; width: 100%; min-height: 40px; padding: 6px 12px; border: 0; border-radius: 10px;
  background: transparent; box-shadow: none; font-weight: 700; text-align: left; white-space: nowrap; }
.more-pop .more-item:hover, .more-pop .more-item:focus-visible { background: var(--leaf-soft); outline: none; }
.more-pop .more-item.ghost { margin-top: 4px; border-top: 1px solid var(--line); border-radius: 0 0 10px 10px; color: var(--muted); }
.more-pop .more-item.ghost:hover, .more-pop .more-item.ghost:focus-visible { background: #fde1e1; color: #9b2c2c; }
@keyframes more-in { from { opacity: 0; transform: translateY(-6px) scale(.97); } }
@keyframes more-in-up { from { opacity: 0; transform: translateY(6px) scale(.97); } }
@media (prefers-reduced-motion: reduce) { .more-pop:popover-open { animation: none; } }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .more-pop .more-item.ghost:hover, :root:not([data-theme="light"]) .more-pop .more-item.ghost:focus-visible { background: #4a2323; color: #ffd4d4; } }
:root[data-theme="dark"] .more-pop .more-item.ghost:hover, :root[data-theme="dark"] .more-pop .more-item.ghost:focus-visible { background: #4a2323; color: #ffd4d4; }
@media (max-width: 640px) { .row-actions { justify-content: flex-start; } }
.split-btn { display: inline-flex; align-items: stretch; }
.split-btn > .btn { border-radius: 999px 0 0 999px; }
.split-btn > .more-wrap { display: inline-flex; }
.split-btn .btn.more-btn { min-width: 40px; margin-left: -2px; padding: 4px 8px; border-radius: 0 999px 999px 0; }
.split-btn > .btn:hover, .split-btn .more-btn:hover { position: relative; z-index: 1; }
.more-pop .more-item:hover, .more-pop .more-item:active { transform: none; }
/* Laptop widths: a student's two range dropdowns stack, so the whole row (and its buttons) fits
   without the table scrolling sideways. */
@media (min-width: 641px) and (max-width: 1180px) {
  .cell-range .range-pair { flex-direction: column; align-items: stretch; gap: 6px; }
  .cell-range .range-pair select { flex: none; }
  .cell-range .range-dash { display: none; }
}

/* Kid home on a phone: the hero sits beside the greeting, and the line under it, the class and
   the treasures use the card's full width, instead of squeezing into a thin column next to
   the avatar (one treasure per line). */
@media (max-width: 520px) {
  .me-card { display: grid; grid-template-columns: auto 1fr; gap: 10px 14px; align-items: center; }
  .me-card > .stack { display: contents; }
  .me-card > .stack > * { grid-column: 1 / -1; margin: 0; }
  .me-card > .stack > h1 { grid-column: 2; font-size: clamp(1.45rem, 6.6vw, 1.8rem); line-height: 1.15; }
  .me-card .wave-hello .avatar { width: 76px !important; height: 76px !important; }
  .me-card .inventory { margin-top: 2px; gap: 6px; }
  .me-card .inventory .pill { font-size: .85rem; padding: 3px 10px; gap: 5px; }
  .me-card .inventory .pill.with-pic { padding-left: 3px; }
  .me-card .inventory .pill-pic { width: 22px; height: 22px; }
}
/* "A story is waiting" / "questions waiting" cards: the line starts at the card's top edge like
   every other card, not under an extra paragraph gap. */
.unread-card > p { margin: 0; }

/* Schedule: each block of story days at a glance. Its week is seven little day chips with the
   story days lit in green, and a slim timeline under it fills as the dates go by, with a
   glowing dot on today while the block is running. */
.rule-item { align-items: flex-start; padding: 14px 0; }
.rule-glance { flex: 1 1 300px; display: grid; gap: 8px; min-width: 0; }
.rule-week { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; }
.week-chips { display: inline-flex; gap: 4px; }
.week-chip { width: 28px; height: 28px; border-radius: 9px; display: grid; place-items: center; font-size: .78rem; font-weight: 800;
  color: var(--muted); background: var(--card-2); border: 1px dashed var(--line-strong); }
.week-chip.on { color: #fff; background: linear-gradient(180deg, #4fa548, var(--leaf)); border: 1px solid var(--leaf-dark); box-shadow: 0 2px 0 var(--leaf-dark); }
.rule-item.muted .week-chip.on { background: var(--muted); border-color: var(--muted); box-shadow: none; }
.rule-line { position: relative; display: block; height: 6px; max-width: 420px; border-radius: 999px; background: var(--leaf-soft); }
.rule-fill { position: absolute; inset: 0 auto 0 0; border-radius: 999px; background: color-mix(in srgb, var(--leaf) 55%, var(--leaf-soft)); }
.rule-item.muted .rule-fill { background: var(--line-strong); }
.rule-today { position: absolute; top: 50%; width: 14px; height: 14px; margin: -7px 0 0 -7px; border-radius: 50%; background: var(--sun);
  border: 2px solid var(--card); box-shadow: 0 0 0 3px color-mix(in srgb, var(--sun) 35%, transparent); animation: today-pulse 2.4s ease-in-out infinite; }
@keyframes today-pulse { 50% { box-shadow: 0 0 0 6px color-mix(in srgb, var(--sun) 15%, transparent); } }
@media (prefers-reduced-motion: reduce) { .rule-today { animation: none; } }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .week-chip.on { color: #10240e; } }
:root[data-theme="dark"] .week-chip.on { color: #10240e; }

/* Story questions: each answer is a big, tappable card with a lettered bubble (A, B, C) instead
   of a small radio dot. The picked one lights up green; after checking, a right pick turns into
   a ✓ and a wrong one into a ✗. The real radio stays underneath for keyboards and screen readers. */
.question { counter-reset: answer; }
.answer { counter-increment: answer; position: relative; gap: 12px; margin: 8px 0; padding: 10px 14px; min-height: 54px;
  border: 2px solid var(--line-strong); border-radius: 16px; background: var(--card); box-shadow: 0 3px 0 var(--line-strong);
  transition: transform .1s ease, box-shadow .1s ease, background .15s, border-color .15s; }
.answer input { position: absolute; opacity: 0; pointer-events: none; }
.answer::before { content: counter(answer, upper-alpha); flex: none; width: 34px; height: 34px; border-radius: 50%; display: grid; place-items: center;
  font-family: inherit; font-weight: 800; font-size: 1rem; background: var(--leaf-soft); color: var(--leaf-dark); transition: background .15s, color .15s; }
.answer:hover { background: var(--card); border-color: var(--leaf); transform: translateY(-1px); }
.answer:active { transform: translateY(2px); box-shadow: 0 1px 0 var(--line-strong); }
.answer:has(input:focus-visible) { outline: 3px solid var(--sun); outline-offset: 2px; }
.answer:has(input:checked) { border-color: var(--leaf); background: color-mix(in srgb, var(--leaf-soft) 75%, var(--card)); box-shadow: 0 3px 0 var(--leaf); }
.answer:has(input:checked)::before { background: var(--leaf); color: #fff; animation: answer-pop .35s cubic-bezier(.3, 1.6, .5, 1); }
.question .answer.right { border-color: #2f9e44; background: #d9f7df; box-shadow: 0 3px 0 #2f9e44; }
.question .answer.right::before { content: "✓"; background: #2f9e44; color: #fff; }
.question .answer.wrong { border-color: #d64545; background: #fde1e1; box-shadow: 0 3px 0 #d64545; }
.question .answer.wrong::before { content: "✗"; background: #d64545; color: #fff; }
.answer:has(input:disabled) { cursor: default; transform: none; }
@keyframes answer-pop { 0% { transform: scale(.6); } 100% { transform: none; } }
@media (prefers-reduced-motion: reduce) { .answer, .answer::before { transition: none; } .answer:has(input:checked)::before { animation: none; } }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .question .answer.right { background: #1f3d24; color: #c9f5d2; }
  :root:not([data-theme="light"]) .question .answer.wrong { background: #4a2323; color: #ffd4d4; }
}
:root[data-theme="dark"] .question .answer.right { background: #1f3d24; color: #c9f5d2; }
:root[data-theme="dark"] .question .answer.wrong { background: #4a2323; color: #ffd4d4; }

/* Progress: a slim meter under "stories read" and the question score, so the class can be
   scanned by eye (green and full is great; red is the one to look at). */
.meter-cell { display: inline-flex; flex-direction: column; align-items: flex-start; gap: 5px; min-width: 76px; }
.mini-meter { display: block; width: 76px; height: 6px; border-radius: 999px; background: var(--leaf-soft); overflow: hidden; }
.mini-meter > span { display: block; height: 100%; border-radius: 999px; background: var(--leaf); transition: width .4s ease; }
.mini-meter.sun > span { background: var(--sun); }
.mini-meter.red > span { background: var(--bad); }
.meter-cell .badge { white-space: nowrap; }

/* Bookshelf covers wear their stickers: a sunny "New!" ribbon across the corner of a book not
   read yet, and a round green ✓ seal on one read to the end (instead of two more text badges). */
.cover-ribbon { position: absolute; top: 14px; left: -34px; width: 124px; transform: rotate(-45deg); padding: 3px 0; text-align: center;
  background: linear-gradient(180deg, #ffd45a, var(--sun)); color: #3a2a00; font-size: .72rem; font-weight: 800; letter-spacing: .03em;
  box-shadow: 0 2px 6px rgba(0, 0, 0, .22); border-top: 1px dashed rgba(255, 255, 255, .7); border-bottom: 1px dashed rgba(255, 255, 255, .7); }
.cover-seal { position: absolute; top: 8px; right: 8px; width: 32px; height: 32px; border-radius: 50%; display: grid; place-items: center;
  background: radial-gradient(circle at 35% 30%, #5fc95f, #2f9e44); color: #fff; font-weight: 900; font-size: 1.05rem;
  border: 3px solid #fff; box-shadow: 0 3px 8px rgba(0, 0, 0, .25); transform: rotate(-8deg); }
.book:hover .cover-seal { transform: rotate(4deg) scale(1.08); transition: transform .2s ease; }
.book-badges:empty { display: none; }

/* Special days: the kind of day is two big picture cards, team-up or class epic, instead of a
   dropdown. The chosen one lifts, takes its color (team-up's warm sunset, the epic's castle
   purple) and gets a check; the radio underneath keeps keyboards and screen readers working. */
.kind-picker { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; max-width: 520px; }
.kind-option { position: relative; display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 14px 10px 12px; cursor: pointer;
  border: 2px solid var(--line-strong); border-radius: 18px; background: var(--card); box-shadow: 0 3px 0 var(--line-strong);
  transition: transform .12s ease, box-shadow .12s ease, border-color .15s, background .15s; }
.kind-option input { position: absolute; opacity: 0; pointer-events: none; }
.kind-option:hover { transform: translateY(-2px); border-color: var(--leaf); }
.kind-option:has(input:focus-visible) { outline: 3px solid var(--sun); outline-offset: 2px; }
.kind-emoji { font-size: 2.3rem; line-height: 1.1; transition: transform .2s cubic-bezier(.3, 1.6, .5, 1); }
.kind-name { font-weight: 800; }
.kind-option:has(input:checked) { transform: translateY(-2px); }
.kind-option:has(input:checked) .kind-emoji { transform: scale(1.12) rotate(-6deg); }
.kind-option:has(input:checked)::after { content: "✓"; position: absolute; top: -9px; right: -9px; width: 26px; height: 26px; border-radius: 50%;
  display: grid; place-items: center; font-weight: 900; font-size: .85rem; color: #fff; border: 2px solid var(--card); }
.kind-option:has(input[value="teamUp"]:checked) { border-color: #f06a8b; background: linear-gradient(135deg, #fff1e0, #ffe3ea); box-shadow: 0 3px 0 #e0567a; }
.kind-option:has(input[value="teamUp"]:checked)::after { background: #f06a8b; }
.kind-option:has(input[value="epic"]:checked) { border-color: #8b6fd6; background: linear-gradient(135deg, #f1ebff, #e6eeff); box-shadow: 0 3px 0 #7357c4; }
.kind-option:has(input[value="epic"]:checked)::after { background: #8b6fd6; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .kind-option:has(input[value="teamUp"]:checked) { background: linear-gradient(135deg, #4a2e22, #4a2232); }
  :root:not([data-theme="light"]) .kind-option:has(input[value="epic"]:checked) { background: linear-gradient(135deg, #352a55, #26304f); }
}
:root[data-theme="dark"] .kind-option:has(input[value="teamUp"]:checked) { background: linear-gradient(135deg, #4a2e22, #4a2232); }
:root[data-theme="dark"] .kind-option:has(input[value="epic"]:checked) { background: linear-gradient(135deg, #352a55, #26304f); }
@media (prefers-reduced-motion: reduce) { .kind-option, .kind-emoji { transition: none; } }

/* Reading levels, seen at a glance: easier ones a soft green, the kid's own grade sunny, harder
   ones warming from gold to orange the further above their grade, and a little meter along each
   card's bottom that grows from K to 12th. The picked one keeps the usual green with its check. */
.choice.lvl-easier:not(.on) { background: color-mix(in srgb, var(--leaf-soft) 55%, var(--card)); }
.choice.lvl-mine:not(.on) { background: color-mix(in srgb, #ffe9a8 60%, var(--card)); border-color: var(--sun); box-shadow: 0 3px 0 #d99a12; }
.choice.lvl-heat-1:not(.on) { background: color-mix(in srgb, #ffe7b8 40%, var(--card)); }
.choice.lvl-heat-2:not(.on) { background: color-mix(in srgb, #ffd9a6 42%, var(--card)); }
.choice.lvl-heat-3:not(.on) { background: color-mix(in srgb, #ffc995 42%, var(--card)); }
.choice.lvl-heat-4:not(.on) { background: color-mix(in srgb, #ffb889 45%, var(--card)); }
.choice-meter { position: relative; display: block; width: 70%; height: 6px; margin: 6px auto 0; border-radius: 999px; overflow: hidden;
  background: linear-gradient(90deg, #7cc76f, var(--sun) 55%, #f0803c); }
.choice-meter::after { content: ""; position: absolute; inset: 0 0 0 var(--fill); background: color-mix(in srgb, var(--ink) 12%, var(--card)); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .choice.lvl-mine:not(.on) { background: color-mix(in srgb, #6b5310 40%, var(--card)); }
  :root:not([data-theme="light"]) .choice.lvl-heat-1:not(.on) { background: color-mix(in srgb, #5c4320 28%, var(--card)); }
  :root:not([data-theme="light"]) .choice.lvl-heat-2:not(.on) { background: color-mix(in srgb, #66391c 30%, var(--card)); }
  :root:not([data-theme="light"]) .choice.lvl-heat-3:not(.on) { background: color-mix(in srgb, #6e321c 32%, var(--card)); }
  :root:not([data-theme="light"]) .choice.lvl-heat-4:not(.on) { background: color-mix(in srgb, #762a1c 36%, var(--card)); }
}
:root[data-theme="dark"] .choice.lvl-mine:not(.on) { background: color-mix(in srgb, #6b5310 40%, var(--card)); }
:root[data-theme="dark"] .choice.lvl-heat-1:not(.on) { background: color-mix(in srgb, #5c4320 28%, var(--card)); }
:root[data-theme="dark"] .choice.lvl-heat-2:not(.on) { background: color-mix(in srgb, #66391c 30%, var(--card)); }
:root[data-theme="dark"] .choice.lvl-heat-3:not(.on) { background: color-mix(in srgb, #6e321c 32%, var(--card)); }
:root[data-theme="dark"] .choice.lvl-heat-4:not(.on) { background: color-mix(in srgb, #762a1c 36%, var(--card)); }

/* Class tiles on a story day: a ring that fills as the class reads today's story, the count in
   its middle, turning into a green ✓ seal once everyone has read. */
.with-ring { display: flex; align-items: center; gap: 12px; }
.today-ring { flex: none; position: relative; width: 50px; height: 50px; border-radius: 50%; display: grid; place-items: center;
  background: conic-gradient(var(--leaf) var(--p), var(--leaf-soft) 0); }
.today-ring::before { content: ""; position: absolute; inset: 6px; border-radius: 50%; background: var(--card); }
.today-ring > span { position: relative; font-size: .78rem; font-weight: 800; color: var(--leaf-dark); letter-spacing: -.02em; }
.today-ring.done { background: radial-gradient(circle at 35% 30%, #5fc95f, #2f9e44); box-shadow: 0 3px 8px -2px rgba(47, 158, 68, .55); }
.today-ring.done::before { display: none; }
.today-ring.done > span { color: #fff; font-size: 1.3rem; }

/* Skin and hair colors: a palette of round paint-pot swatches instead of a card per color with
   a small dot and "Tone 3" under it. The name is still there for screen readers and shows as a
   tip on hover; the chosen color grows a little inside a green ring and gets its check. */
.choices.swatches, .choices.small.swatches { display: flex; flex-wrap: wrap; gap: 14px; padding: 6px 2px; }
.choices.swatches .choice { width: 56px; height: 56px; min-height: 0; padding: 0; border-radius: 50%; border: 3px solid var(--card);
  background: var(--card); box-shadow: 0 0 0 2px var(--line-strong), 0 4px 0 1px var(--line-strong); }
.choices.swatches .choice .swatch { width: 100%; height: 100%; border: 0;
  box-shadow: inset -5px -7px 0 rgba(0, 0, 0, .14), inset 4px 5px 0 rgba(255, 255, 255, .28); }
.choices.swatches .choice .label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.choices.swatches .choice:hover:not(:disabled) { transform: translateY(-2px) scale(1.05); box-shadow: 0 0 0 2px var(--leaf), 0 5px 0 1px var(--line-strong); }
.choices.swatches .choice.on { transform: scale(1.1); background: var(--card); box-shadow: 0 0 0 3px var(--leaf), 0 0 0 7px var(--leaf-soft); }
.choices.swatches .choice.on::after { top: -10px; right: -10px; width: 24px; height: 24px; font-size: .8rem; }
@media (max-width: 520px) {
  .choices.small.swatches { gap: 12px; }
  .choices.small.swatches .choice { width: 50px; height: 50px; padding: 0; }
  .choices.small.swatches .swatch { width: 100%; height: 100%; }
}
@media (prefers-reduced-motion: reduce) { .choices.swatches .choice.on, .choices.swatches .choice:hover:not(:disabled) { transform: none; } }

/* Class tabs: a small picture beside each name, so the bar can be scanned at a glance. Faded
   on the tabs not open, full color (with a little hop) on the open one. */
.tabs button { display: inline-flex; align-items: center; gap: 7px; }
.tab-icon { font-size: 1.05rem; line-height: 1; filter: grayscale(.6); opacity: .7; transition: filter .15s, opacity .15s, transform .2s cubic-bezier(.3, 1.6, .5, 1); }
.tabs button:hover .tab-icon { filter: none; opacity: 1; }
.tabs button.on .tab-icon { filter: none; opacity: 1; transform: scale(1.15) rotate(-6deg); }
@media (prefers-reduced-motion: reduce) { .tab-icon { transition: none; } .tabs button.on .tab-icon { transform: none; } }
@media (max-width: 520px) {
  .tabs { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); width: 100%; border-radius: 22px; gap: 4px; }
  .tabs button { justify-content: flex-start; padding: 8px 12px; text-align: left; }
}

/* A story's first page opens like a storybook: its first letter is big, in leaf green, set in a
   soft green tile with a sunny edge, and the words wrap around it. */
.page.opening .story-text p:first-child::first-letter { float: left; font-family: var(--ui-font); font-weight: 800; font-size: 3.1em; line-height: 1;
  margin: .08em .14em 0 0; padding: .06em .16em .02em; border-radius: 16px; color: var(--leaf-dark);
  background: linear-gradient(160deg, var(--leaf-soft), color-mix(in srgb, var(--sun) 25%, var(--leaf-soft))); border: 2px solid color-mix(in srgb, var(--sun) 60%, transparent); }
.reader.presenter .page.opening .story-text p:first-child::first-letter { border-radius: 24px; }

/* Story status as a colored pill: green when ready, sunny while being written or checked, red
   when it didn't work. A story that didn't work keeps its explanation folded under the pill
   (a small arrow says it opens) instead of a long paragraph stretching the row. */
.status-pill { display: inline-flex; align-items: center; gap: 4px; padding: 3px 10px; border-radius: 999px; font-size: .85rem; font-weight: 800; white-space: nowrap; }
.status-pill.ok { background: var(--leaf-soft); color: var(--leaf-dark); }
.status-pill.wait { background: color-mix(in srgb, var(--sun) 28%, var(--card)); color: #7a5300; }
.status-pill.bad { background: #fde1e1; color: #9b2c2c; }
.fail-details > summary { list-style: none; cursor: pointer; }
.fail-details > summary::-webkit-details-marker { display: none; }
.fail-details > summary::after { content: "▸"; margin-left: 2px; transition: transform .15s; }
.fail-details[open] > summary::after { transform: rotate(90deg); }
.fail-details > summary:hover { filter: brightness(.96); }
.fail-details .fail-why { margin-top: 6px; max-width: 46ch; font-size: .85rem; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .status-pill.wait { color: #ffd98a; }
  :root:not([data-theme="light"]) .status-pill.bad { background: #4a2323; color: #ffd4d4; }
}
:root[data-theme="dark"] .status-pill.wait { color: #ffd98a; }
:root[data-theme="dark"] .status-pill.bad { background: #4a2323; color: #ffd4d4; }

/* Kid home: the "Today's story" card is the day's main door, so it gets some atmosphere: a warm
   sunlit glow in its corner, soft rings like ripples, and a big leaf drifting gently behind the
   words (all decoration, behind the text and buttons). Still in reduced motion. */
.today-card { position: relative; overflow: hidden; isolation: isolate; }
.today-card::before { content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background:
    radial-gradient(circle at 100% 0%, rgba(255, 230, 140, .45), transparent 42%),
    radial-gradient(circle at 92% 110%, transparent 58px, rgba(255, 255, 255, .10) 59px 61px, transparent 62px 96px, rgba(255, 255, 255, .08) 97px 99px, transparent 100px); }
.today-card::after { content: "🍃"; position: absolute; z-index: -1; right: 18px; bottom: -14px; font-size: 6.5rem; line-height: 1; opacity: .28;
  pointer-events: none; transform-origin: 30% 80%; transform: rotate(-12deg); animation: leaf-drift 6s ease-in-out infinite; }
@keyframes leaf-drift { 0%, 100% { transform: rotate(-12deg) translateY(0); } 50% { transform: rotate(-2deg) translateY(-8px); } }
@media (prefers-reduced-motion: reduce) { .today-card::after { animation: none; } }
@media (max-width: 520px) { .today-card::after { font-size: 4.8rem; right: 8px; } }

/* Help: every section as a chip at the top (its picture and title) to jump straight to it; the
   section lands just under the top bar and glows softly for a moment. */
.help-toc { display: flex; flex-wrap: wrap; gap: 8px; }
.help-chip { display: inline-flex; align-items: center; gap: 7px; padding: 7px 14px 7px 8px; border-radius: 999px; cursor: pointer;
  border: 2px solid var(--line-strong); background: var(--card); color: var(--ink); font: inherit; font-weight: 700; font-size: .9rem;
  box-shadow: 0 3px 0 var(--line-strong); transition: transform .1s ease, box-shadow .1s ease, border-color .15s; }
.help-chip:hover { transform: translateY(-2px); border-color: var(--leaf); }
.help-chip:active { transform: translateY(2px); box-shadow: 0 1px 0 var(--line-strong); }
.help-chip:focus-visible { outline: 3px solid var(--sun); outline-offset: 2px; }
.help-chip-icon { width: 28px; height: 28px; border-radius: 50%; display: grid; place-items: center; background: var(--leaf-soft); font-size: 1rem; }
.help-section { scroll-margin-top: calc(var(--topbar-h, 68px) + 12px); }
.help-section.help-landed { animation: help-glow 1.6s ease-out; }
@keyframes help-glow { 0%, 30% { box-shadow: 0 0 0 4px var(--sun), var(--shadow); } 100% { box-shadow: var(--shadow); } }
@media (prefers-reduced-motion: reduce) { .help-chip { transition: none; } }

/* Picture PIN: the slot the next tap fills glows sunny and breathes, and each tapped picture
   wears a small green number sticker for its place in the order (a picture tapped twice gets
   two). */
.pin-dots span.empty.next { border-color: var(--sun); color: #b07d00; background: color-mix(in srgb, var(--sun) 14%, var(--card)); animation: pin-next 1.6s ease-in-out infinite; }
@keyframes pin-next { 50% { transform: scale(1.07); box-shadow: 0 0 0 5px color-mix(in srgb, var(--sun) 22%, transparent); } }
.pin-pad button { position: relative; }
.pin-orders { position: absolute; top: -9px; right: -9px; display: flex; gap: 3px; }
.pin-order { width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center;
  background: var(--leaf); color: #fff; font-size: .85rem; font-weight: 800; border: 2px solid var(--card); box-shadow: 0 2px 6px rgba(0, 0, 0, .18); animation: award-pop .3s ease-out; }
@media (prefers-reduced-motion: reduce) { .pin-dots span.empty.next, .pin-order { animation: none; } }

/* Admin Overview: the four numbers as dashboard tiles: a colored picture chip by the label, the
   number big and bold, and a band of the tile's color along its top. */
.stat-card { position: relative; overflow: hidden; display: flex; flex-direction: column; gap: 6px; --tone: var(--leaf); --tone-soft: var(--leaf-soft); }
.stat-card::before { content: ""; position: absolute; inset: 0 0 auto 0; height: 5px; background: var(--tone); }
.stat-card.sun { --tone: var(--sun); --tone-soft: color-mix(in srgb, var(--sun) 22%, var(--card)); }
.stat-card.sky { --tone: #4a90d9; --tone-soft: color-mix(in srgb, #4a90d9 18%, var(--card)); }
.stat-card.berry { --tone: #d65a8c; --tone-soft: color-mix(in srgb, #d65a8c 16%, var(--card)); }
.stat-label { display: flex; align-items: center; gap: 10px; font-weight: 700; }
.stat-icon { width: 38px; height: 38px; border-radius: 12px; display: grid; place-items: center; font-size: 1.2rem; background: var(--tone-soft); flex: none; }
.stat-value { font-family: var(--ui-font); font-size: clamp(2rem, 4vw, 2.6rem); font-weight: 800; line-height: 1.05; letter-spacing: -.02em; color: var(--ink); }
.stat-value a { color: inherit; text-decoration: underline 3px var(--tone); text-underline-offset: 6px; }
.stat-value a:hover { color: var(--leaf-dark); }
.stat-card .muted { font-size: .92rem; }

/* Story being written: the steps are a little trail. A connector joins each step to the next
   (green once that step is done), the step happening now is a solid green pill with a light
   sweeping across it, and the steps still to come wait in a dashed outline. */
.wait-steps { gap: 0; row-gap: 10px; }
.wait-steps li { position: relative; overflow: visible; border-style: dashed; }
.wait-steps li:not(:last-child) { margin-right: 34px; }
.wait-steps li:not(:last-child)::after { content: ""; position: absolute; top: 50%; right: -32px; width: 28px; height: 3px; margin-top: -1.5px; border-radius: 2px; background: var(--line-strong); }
.wait-steps li.done:not(:last-child)::after { background: var(--leaf); }
.wait-steps li.done { border-style: solid; background: var(--card); }
.wait-steps li.on { border-style: solid; background: linear-gradient(180deg, #4fa548, var(--leaf)); color: #fff; border-color: var(--leaf-dark);
  box-shadow: 0 3px 0 var(--leaf-dark); isolation: isolate; }
.wait-steps li.on > * { position: relative; }
.wait-steps li.on::before { content: ""; position: absolute; inset: 0; z-index: -1; border-radius: inherit;
  background: linear-gradient(105deg, transparent 30%, rgba(255, 255, 255, .45) 50%, transparent 70%) -150% 0 / 60% 100% no-repeat; animation: step-sweep 2.2s ease-in-out infinite; }
@keyframes step-sweep { to { background-position: 250% 0; } }
@media (prefers-reduced-motion: reduce) { .wait-steps li.on::before { animation: none; background: none; } }

/* Edit class: archiving (which locks every student out) sits apart in its own box with a big
   📦, set off from the everyday settings; ticking it warms the box so the change can't be missed
   before Save. */
.archive-zone { display: flex; align-items: center; gap: 14px; padding: 14px 16px; border: 2px dashed var(--line-strong); border-radius: 16px;
  background: var(--card-2); transition: background .2s, border-color .2s; }
.archive-zone-icon { flex: none; width: 46px; height: 46px; border-radius: 14px; display: grid; place-items: center; font-size: 1.6rem;
  background: var(--card); filter: grayscale(.5); opacity: .8; transition: filter .2s, opacity .2s, transform .25s cubic-bezier(.3, 1.6, .5, 1); }
.archive-zone .field-note { margin-top: 4px; }
.archive-zone:has(input:checked) { border-style: solid; border-color: #e08a2e; background: color-mix(in srgb, #ffb347 18%, var(--card)); }
.archive-zone:has(input:checked) .archive-zone-icon { filter: none; opacity: 1; transform: rotate(-8deg) scale(1.08); }
@media (prefers-reduced-motion: reduce) { .archive-zone, .archive-zone-icon { transition: none; } }
.archive-zone input[type="checkbox"] { accent-color: #e08a2e; }

/* Making a character: the step dots are a little trail. Steps done are full green dots, the step
   you're on stretches into a glowing green pill (it grows in as you arrive), and the steps
   ahead are soft hollow dots, all on a thin track so it reads as one path. */
.steps { position: relative; align-items: center; gap: 8px; width: fit-content; margin: 8px auto 14px; padding: 4px 6px; }
.steps::before { content: ""; position: absolute; left: 10px; right: 10px; top: 50%; height: 2px; margin-top: -1px; background: var(--line); z-index: -1; }
.steps span { position: relative; width: 12px; height: 12px; background: var(--card); border: 2px solid var(--line-strong); }
.steps span.on { background: var(--leaf); border-color: var(--leaf); }
.steps span.now { width: 32px; border-radius: 999px; box-shadow: 0 0 0 4px var(--leaf-soft); animation: step-grow .45s cubic-bezier(.3, 1.6, .5, 1); }
@keyframes step-grow { from { width: 12px; } }
@media (prefers-reduced-motion: reduce) { .steps span.now { animation: none; } }

/* QR cards that go home: the name on a leafy green band, the code inside a camera-viewfinder
   frame of green corner brackets ("scan me", without words), and scissors on the dashed edge
   for cutting out. Colors print as shown. */
.qr-card { position: relative; border-color: #b9c9a8; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
.qr-card::before { content: "✂️"; position: absolute; top: -12px; left: 14px; font-size: 1rem; line-height: 1; transform: rotate(-90deg); }
.qr-card .name { display: inline-block; margin: 2px 0 8px; padding: 3px 16px; border-radius: 999px; background: #e0efd4; color: #2d6a28; }
.qr-frame { display: inline-block; position: relative; padding: 10px; line-height: 0; margin-bottom: 6px;
  --c: #3f8f3a; --l: 22px; --w: 4px;
  background:
    linear-gradient(var(--c), var(--c)) top left / var(--l) var(--w), linear-gradient(var(--c), var(--c)) top left / var(--w) var(--l),
    linear-gradient(var(--c), var(--c)) top right / var(--l) var(--w), linear-gradient(var(--c), var(--c)) top right / var(--w) var(--l),
    linear-gradient(var(--c), var(--c)) bottom left / var(--l) var(--w), linear-gradient(var(--c), var(--c)) bottom left / var(--w) var(--l),
    linear-gradient(var(--c), var(--c)) bottom right / var(--l) var(--w), linear-gradient(var(--c), var(--c)) bottom right / var(--w) var(--l);
  background-repeat: no-repeat; border-radius: 6px; }
@media print { .qr-frame { padding: 7px; --l: 18px; --w: 3px; } }

/* Turning a page: the new page slides in from the side you're heading toward with a slight
   paper tilt, like turning a real page (quick, so reading isn't slowed). Off in reduced motion. */
.turn-next { animation: turn-next .34s cubic-bezier(.2, .8, .3, 1); transform-origin: 0 50%; }
.turn-back { animation: turn-back .34s cubic-bezier(.2, .8, .3, 1); transform-origin: 100% 50%; }
@keyframes turn-next { from { opacity: 0; transform: perspective(1400px) translateX(48px) rotateY(-9deg); } }
@keyframes turn-back { from { opacity: 0; transform: perspective(1400px) translateX(-48px) rotateY(9deg); } }
@media (prefers-reduced-motion: reduce) { .turn-next, .turn-back { animation: none; } }

/* Teacher top bar: the button for the part of the console you're in is lit (soft green with a
   leaf-green edge and a little dot under it), so it's always clear where you are. */
#nav a[aria-current="page"] { position: relative; background: var(--leaf-soft); border-color: var(--leaf); color: var(--leaf-dark); box-shadow: 0 3px 0 var(--leaf); }
#nav a[aria-current="page"]::after { content: ""; position: absolute; left: 50%; bottom: -13px; width: 6px; height: 6px; margin-left: -3px; border-radius: 50%; background: var(--leaf); }

/* The End: the treasure just earned sits on a sunburst of soft golden rays that turns slowly
   behind it, like a prize being revealed (lilac rays for a power). Still in reduced motion. */
.award-prize { position: relative; flex: none; display: grid; place-items: center; width: 124px; height: 124px; isolation: isolate; }
.award-prize::before { content: ""; position: absolute; inset: -6px; z-index: -1; border-radius: 50%;
  background: repeating-conic-gradient(from 0deg, rgba(240, 168, 20, .85) 0deg 12deg, transparent 12deg 30deg);
  -webkit-mask: radial-gradient(circle, #000 30%, transparent 70%); mask: radial-gradient(circle, #000 30%, transparent 70%);
  animation: prize-spin 14s linear infinite; }
.award-prize::after { content: ""; position: absolute; inset: 22px; z-index: -1; border-radius: 50%; background: radial-gradient(circle, rgba(255, 236, 160, .95), rgba(255, 236, 160, 0) 70%); }
.award-prize.power::before { background: repeating-conic-gradient(from 0deg, rgba(150, 105, 230, .7) 0deg 12deg, transparent 12deg 30deg); }
.award-prize.power::after { background: radial-gradient(circle, rgba(232, 220, 255, .95), rgba(232, 220, 255, 0) 70%); }
.award-prize .award-pic { width: 88px; height: 88px; }
@keyframes prize-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .award-prize::before { animation: none; } }
@media (max-width: 520px) { .award-prize { width: 100px; height: 100px; } .award-prize .award-pic { width: 72px; height: 72px; } }

/* Special days: each day leads with a tear-off calendar tile (a colored band with the month, a big
   day number, the weekday) in its kind's color: team-up sunset pink, class epic castle purple. */
.special-row { align-items: center; }
.special-what { display: flex; align-items: center; gap: 14px; min-width: 0; }
.special-sub { font-size: .9rem; margin-top: 2px; }
.date-tile { flex: none; width: 58px; border-radius: 12px; overflow: hidden; text-align: center; background: var(--card); border: 2px solid var(--tile, var(--leaf));
  box-shadow: 0 3px 0 var(--tile, var(--leaf)); line-height: 1.05; --tile: #f06a8b; }
.date-tile.epic { --tile: #8b6fd6; }
.date-tile-month { display: block; padding: 2px 0 3px; background: var(--tile); color: #fff; font-size: .7rem; font-weight: 800; text-transform: uppercase; letter-spacing: .06em; }
.date-tile-day { display: block; padding-top: 4px; font-size: 1.45rem; font-weight: 800; color: var(--ink); }
.date-tile-wd { display: block; padding-bottom: 4px; font-size: .68rem; font-weight: 700; color: var(--muted); }
.special-row.muted .date-tile { --tile: var(--line-strong); }
@media (max-width: 520px) { .special-row > .row { padding-left: 72px; } }

/* My character: the hero leads the page, standing on a soft sunny spotlight with a ring of
   leaf green, beside the title. */
.me-head { display: flex; align-items: center; gap: 18px; }
.me-head h1 { margin: 0; }
.me-head p { margin: 4px 0 0; }
.me-hero { flex: none; position: relative; display: grid; place-items: center; width: 124px; height: 124px; border-radius: 50%;
  background: radial-gradient(circle at 50% 40%, color-mix(in srgb, var(--sun) 35%, var(--card)), var(--leaf-soft) 70%);
  box-shadow: 0 0 0 4px var(--card), 0 0 0 7px color-mix(in srgb, var(--leaf) 45%, transparent), var(--shadow); }
.me-hero .avatar { background: transparent; box-shadow: none; }
@media (max-width: 520px) { .me-head { gap: 14px; } .me-hero { width: 92px; height: 92px; } .me-hero .avatar { width: 78px !important; height: 78px !important; } }

/* Roster sign-in: a three-part track over each student's sign-in words (pictures picked,
   character made, all set). Done parts fill green; the part they're on now waits in sun yellow;
   a locked-out student's track turns red. */
.signin-track { display: flex; gap: 3px; width: 72px; margin-bottom: 5px; }
.signin-track > span { flex: 1; height: 6px; border-radius: 999px; background: var(--line); }
.signin-track > span.done { background: var(--leaf); }
.signin-track > span.next { background: color-mix(in srgb, var(--sun) 70%, var(--card)); }
.signin.bad .signin-track > span.done { background: var(--bad); }
.signin.ok .signin-track > span { background: var(--ok); }

/* Read to me, while it's reading: the button turns a soft storyteller lilac with three little
   sound bars bouncing in it, so it's clear the story is being read (and that this stops it). */
.btn.reading-now { background: linear-gradient(180deg, #f3ecff, #e4d8ff); border-color: #8b6fd6; color: #3d2a73; box-shadow: 0 3px 0 #7357c4; }
.sound-bars { display: inline-flex; align-items: flex-end; gap: 2px; height: 14px; margin-left: 4px; }
.sound-bars > span { width: 3px; height: 100%; border-radius: 2px; background: #8b6fd6; transform-origin: 50% 100%; animation: sound-bar .9s ease-in-out infinite; }
.sound-bars > span:nth-child(2) { animation-delay: -.3s; }
.sound-bars > span:nth-child(3) { animation-delay: -.6s; }
@keyframes sound-bar { 0%, 100% { transform: scaleY(.3); } 50% { transform: scaleY(1); } }
@media (prefers-reduced-motion: reduce) { .sound-bars > span { animation: none; transform: scaleY(.7); } .sound-bars > span:nth-child(2) { transform: none; } }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .btn.reading-now { background: linear-gradient(180deg, #3a2d52, #2f2445); color: #e6d8ff; } :root:not([data-theme="light"]) .sound-bars > span { background: #c4b0ff; } }
:root[data-theme="dark"] .btn.reading-now { background: linear-gradient(180deg, #3a2d52, #2f2445); color: #e6d8ff; }
:root[data-theme="dark"] .sound-bars > span { background: #c4b0ff; }

/* Toasts: a leaf-green edge (red for a problem), a little spring as they arrive, a slim bar along
   the bottom that shrinks while the message stays up, and a tap puts one away early. */
.toast { overflow: hidden; cursor: pointer; border-left: 6px solid var(--leaf); padding-bottom: 15px;
  transition: transform .45s cubic-bezier(.3, 1.5, .5, 1); box-shadow: 0 12px 30px -10px rgba(0, 0, 0, .45); }
.toast.error { border-left-color: #8f1d1d; }
.toast::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 4px; background: var(--leaf); transform-origin: 0 50%; transform: scaleX(0); }
.toast.error::after { background: rgba(255, 255, 255, .7); }
.toast.show::after { animation: toast-life var(--life, 3500ms) linear forwards; }
@keyframes toast-life { from { transform: scaleX(1); } to { transform: scaleX(0); } }
@media (prefers-reduced-motion: reduce) { .toast { transition: none; } }

/* Start page: the fan of storybook pictures is dealt out one by one as the page opens (each
   flips up into its place), and pointing at one lifts it and turns it straight, like picking a
   book off the pile. Still in reduced motion. */
.topic-strip img { transform: none; rotate: -6deg; translate: 0 4px; transition: translate .25s cubic-bezier(.3, 1.6, .5, 1), rotate .25s ease, scale .25s ease;
  animation: fan-deal .55s cubic-bezier(.3, 1.4, .5, 1) both; animation-delay: calc(.15s + var(--i, 0) * .08s); }
.topic-strip img:nth-child(odd) { transform: none; rotate: -6deg; translate: 0 4px; }
.topic-strip img:nth-child(even) { transform: none; rotate: 5deg; translate: 0 0; }
.topic-strip img:nth-child(4) { transform: none; rotate: 0deg; scale: 1.12; translate: 0 -6px; }
.topic-strip img:hover { rotate: 0deg; translate: 0 -14px; scale: 1.14; z-index: 2; }
@keyframes fan-deal { from { opacity: 0; transform: translateY(40px) rotate(-20deg) scale(.6); } }
@media (prefers-reduced-motion: reduce) { .topic-strip img { animation: none; transition: none; } }

/* Library, before anything is in it: an empty shelf waiting for its first books, dashed book
   outlines standing where stories will go (the middle one with a +), on a wooden plank. */
.library-empty { align-items: center; text-align: center; padding: 8px 0 4px; }
.library-empty > p { max-width: 60ch; margin: 0 auto; }
.library-empty > .row { justify-content: center; }
.empty-shelf { width: min(320px, 90%); margin: 4px auto 6px; }
.empty-books { display: flex; align-items: flex-end; justify-content: center; gap: 8px; height: 104px; }
.ghost-book { display: grid; place-items: center; width: 34px; border-radius: 6px 6px 3px 3px; border: 2px dashed var(--line-strong);
  background: color-mix(in srgb, var(--leaf-soft) 50%, transparent); color: var(--leaf-dark); font-weight: 800; font-size: 1.6rem; line-height: 1; }
.ghost-book.g0 { height: 74px; rotate: -8deg; translate: 4px 0; transform-origin: 50% 100%; }
.ghost-book.g1 { height: 92px; }
.ghost-book.g2 { height: 100px; width: 42px; border-style: solid; border-color: var(--leaf); background: var(--leaf-soft); box-shadow: 0 0 0 4px color-mix(in srgb, var(--leaf) 15%, transparent);
  animation: ghost-bob 2.6s ease-in-out infinite; }
.ghost-book.g3 { height: 84px; }
.ghost-book.g4 { height: 70px; }
.shelf-plank { height: 14px; border-radius: 4px; background: linear-gradient(180deg, #c99a63, #a8773f); box-shadow: 0 6px 12px -6px rgba(90, 60, 20, .6); }
@keyframes ghost-bob { 50% { translate: 0 -6px; } }
@media (prefers-reduced-motion: reduce) { .ghost-book.g2 { animation: none; } }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .shelf-plank { background: linear-gradient(180deg, #8a6640, #6b4c2c); } }
:root[data-theme="dark"] .shelf-plank { background: linear-gradient(180deg, #8a6640, #6b4c2c); }

/* Today's story while the story writer isn't set up: the card rests, a soft sage instead of
   bright green, its leaf still and its sprout asleep, so it doesn't look like something to tap. */
.today-card.resting { background: linear-gradient(135deg, #9db596, #86a17e); }
.today-card.resting::after { animation: none; opacity: .18; }
.today-card.resting h2 { opacity: .9; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .today-card.resting { background: linear-gradient(135deg, #34452f, #2c3b28); } }
:root[data-theme="dark"] .today-card.resting { background: linear-gradient(135deg, #34452f, #2c3b28); }
.today-card.resting::before { opacity: .35; }

/* Focus period form: its days as a little calendar strip under the "covers N story days" line,
   story days lit green, days off soft and dashed, a small gap where each new week starts. */
.day-strip { display: flex; flex-wrap: wrap; gap: 4px; margin-top: -4px; margin-bottom: 8px; }
.day-strip:empty { display: none; }
.strip-day { width: 34px; padding: 3px 0 4px; border-radius: 9px; text-align: center; line-height: 1.1; border: 1px dashed var(--line-strong); color: var(--muted); background: var(--card); }
.strip-day.story { border: 1px solid var(--leaf-dark); background: linear-gradient(180deg, #4fa548, var(--leaf)); color: #fff; box-shadow: 0 2px 0 var(--leaf-dark); }
.strip-day.week-start { margin-left: 8px; }
.strip-wd { display: block; font-size: .62rem; font-weight: 700; opacity: .85; text-transform: uppercase; }
.strip-num { display: block; font-size: .92rem; font-weight: 800; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .strip-day.story { color: #10240e; } }
:root[data-theme="dark"] .strip-day.story { color: #10240e; }

/* Story questions: the score as a row of big stars, one per question, gold for each right
   answer, popping in one after another (soft outlines for the ones still to get). */
.score-stars { display: flex; justify-content: center; gap: 6px; margin-top: 12px; }
.score-stars:empty { display: none; }
.score-star { font-size: 2.4rem; line-height: 1; color: var(--line-strong); animation: star-in .5s cubic-bezier(.3, 1.6, .5, 1) both; animation-delay: calc(var(--i) * .15s); }
.score-star.got { color: #f5b301; text-shadow: 0 2px 0 #c98f00, 0 0 14px rgba(245, 179, 1, .45); }
@keyframes star-in { from { opacity: 0; transform: scale(.2) rotate(-60deg); } }
@media (prefers-reduced-motion: reduce) { .score-star { animation: none; } }

/* Writing a class epic: "Starring all N" is a little stage. Castle-purple curtains with a warm
   spotlight, a wooden stage floor along the bottom, and the whole class standing on it in
   bigger rings, bobbing gently in turn like a cast taking a bow. Still in reduced motion. */
.epic-cast { position: relative; overflow: hidden; padding: 14px 16px 26px; border-radius: 16px; color: #fff;
  background:
    radial-gradient(ellipse at 50% 0%, rgba(255, 236, 170, .38), transparent 60%),
    repeating-linear-gradient(90deg, rgba(0, 0, 0, .10) 0 14px, transparent 14px 34px),
    linear-gradient(180deg, #7a5cc9, #5b3fa6); }
.epic-cast::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 16px;
  background: repeating-linear-gradient(90deg, #b5844d 0 46px, #a97a44 46px 48px); box-shadow: 0 -3px 0 rgba(0, 0, 0, .18); }
.epic-cast > strong { text-shadow: 0 1px 2px rgba(0, 0, 0, .3); }
.epic-cast-list { justify-content: center; position: relative; z-index: 1; gap: 10px 16px; }
.epic-cast-kid { width: 70px; color: #fff; text-shadow: 0 1px 2px rgba(0, 0, 0, .35); animation: cast-bow 2.8s ease-in-out infinite; }
.epic-cast-kid:nth-child(3n+2) { animation-delay: -.9s; }
.epic-cast-kid:nth-child(3n) { animation-delay: -1.8s; }
.epic-cast-kid .avatar, .epic-cast-kid .face-todo { width: 56px !important; height: 56px !important; border: 3px solid #fff; border-radius: 50%; background: #efe7ff;
  box-shadow: 0 4px 10px -2px rgba(0, 0, 0, .4); }
@keyframes cast-bow { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-4px); } }
@media (prefers-reduced-motion: reduce) { .epic-cast-kid { animation: none; } }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .epic-cast { background: radial-gradient(ellipse at 50% 0%, rgba(255, 236, 170, .22), transparent 60%), repeating-linear-gradient(90deg, rgba(0, 0, 0, .14) 0 14px, transparent 14px 34px), linear-gradient(180deg, #4b3780, #35255e); } }
:root[data-theme="dark"] .epic-cast { background: radial-gradient(ellipse at 50% 0%, rgba(255, 236, 170, .22), transparent 60%), repeating-linear-gradient(90deg, rgba(0, 0, 0, .14) 0 14px, transparent 14px 34px), linear-gradient(180deg, #4b3780, #35255e); }

/* The bookshelf is a real shelf: every row of books stands on a wooden plank (each book's slot
   carries its piece, meeting its neighbors' across the gap), with a soft shadow under the wood. */
.shelf { row-gap: 30px; padding-bottom: 14px; }
.shelf-slot { position: relative; display: flex; }
.shelf-slot > .book { flex: 1; position: relative; z-index: 1; }
.shelf-slot::after { content: ""; position: absolute; left: -8px; right: -8px; bottom: -13px; height: 11px; z-index: 0;
  background: linear-gradient(180deg, #c99a63, #a8773f); border-top: 2px solid #d9ae78; box-shadow: 0 7px 10px -6px rgba(90, 60, 20, .55); }
.shelf-slot:first-child::after { border-top-left-radius: 4px; border-bottom-left-radius: 4px; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .shelf-slot::after { background: linear-gradient(180deg, #8a6640, #6b4c2c); border-top-color: #9c7650; } }
:root[data-theme="dark"] .shelf-slot::after { background: linear-gradient(180deg, #8a6640, #6b4c2c); border-top-color: #9c7650; }

/* Progress, on a story day: the class as faces under the read ring. A student who has read
   today's story is in full color in a green ring with a ✓; one who hasn't yet is faded in a
   dashed ring, so whom to nudge is plain at a glance. */
.today-faces { display: flex; flex-wrap: wrap; gap: 12px 14px; }
.today-face { position: relative; display: flex; flex-direction: column; align-items: center; gap: 4px; width: 68px; font-size: .78rem; font-weight: 700; text-align: center; line-height: 1.1; }
.today-face .avatar, .today-face .face-todo { width: 48px !important; height: 48px !important; border-radius: 50%; border: 3px dashed var(--line-strong); }
.today-face:not(.read) .avatar, .today-face:not(.read) .face-todo { filter: grayscale(.85); opacity: .6; }
.today-face:not(.read) { color: var(--muted); }
.today-face.read .avatar, .today-face.read .face-todo { border: 3px solid var(--leaf); }
.today-face.read::after { content: "✓"; position: absolute; top: -4px; right: 6px; width: 20px; height: 20px; border-radius: 50%; display: grid; place-items: center;
  background: var(--leaf); color: #fff; font-size: .7rem; font-weight: 900; border: 2px solid var(--card); }

/* "Write my story": pressing it sends sparkles and leaves bursting out of the button, and while
   the story is on its way the button stays bright with a light sweeping across it (instead of
   the faded look a broken button has). */
.spark { position: fixed; z-index: 200; pointer-events: none; font-size: 1.4rem; translate: -50% -50%; animation: spark-fly .9s cubic-bezier(.2, .8, .3, 1) forwards; }
@keyframes spark-fly { 0% { opacity: 1; transform: translate(0, 0) scale(.4); } 70% { opacity: 1; } 100% { opacity: 0; transform: translate(var(--dx), var(--dy)) rotate(var(--rot)) scale(1.1); } }
.btn.primary.sending:disabled { opacity: 1; cursor: progress; position: relative; overflow: hidden; }
.btn.primary.sending::after { content: ""; position: absolute; inset: 0; background: linear-gradient(105deg, transparent 30%, rgba(255, 255, 255, .45) 50%, transparent 70%) -150% 0 / 60% 100% no-repeat;
  animation: step-sweep 1.4s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) { .btn.primary.sending::after { animation: none; background: none; } }

/* Progress: each student who could use a nudge is a little card, with their face and name, each
   reason on its own line led by its icon in a soft sunny chip, and the next-step buttons along
   the bottom. A sun-yellow edge on the left ties it to the flagged rows in the table below. */
.nudges { list-style: none; padding: 0; display: grid; gap: 10px; grid-template-columns: repeat(auto-fill, minmax(min(100%, 340px), 1fr)); }
.nudges li.nudge-card { margin: 0; display: grid; gap: 8px; padding: 12px 14px; border: 1px solid var(--line); border-left: 5px solid var(--sun); border-radius: 14px; background: var(--card-2); }
.nudge-who { display: flex; align-items: center; gap: 10px; font-size: 1.05rem; }
.nudge-who .avatar, .nudge-who .face-todo { width: 38px !important; height: 38px !important; }
.nudge-why { display: grid; gap: 6px; }
.nudge-reason { display: flex; align-items: flex-start; gap: 8px; font-size: .92rem; line-height: 1.35; }
.nudge-icon { flex: none; width: 26px; height: 26px; border-radius: 8px; display: grid; place-items: center; font-size: .9rem; background: color-mix(in srgb, var(--sun) 25%, var(--card)); }
.nudge-card .nudge-actions { margin: 2px 0 0; }
.nudge-card .nudge-actions:empty { display: none; }
.nudges li.nudge-card { align-content: start; } .nudge-card .nudge-actions { align-items: center; }

/* A story's cover looks like a real book cover: a leafy cloth binding with a stitched spine down
   its left edge, a soft inner frame, and the picture set in like a pasted-on plate with a thin
   paper border. */
.reader:not(.presenter) .page.cover { position: relative; padding-left: clamp(30px, 5vw, 50px);
  background: linear-gradient(90deg, color-mix(in srgb, var(--leaf) 14%, var(--card)) 0 20px, var(--card) 20px);
  border: 2px solid color-mix(in srgb, var(--leaf) 30%, var(--line)); box-shadow: inset 0 0 0 8px var(--card), inset 0 0 0 9px color-mix(in srgb, var(--leaf) 22%, transparent), var(--shadow); }
.reader:not(.presenter) .page.cover::before { content: ""; position: absolute; top: 14px; bottom: 14px; left: 9px; width: 3px;
  background: repeating-linear-gradient(180deg, color-mix(in srgb, var(--leaf) 55%, transparent) 0 8px, transparent 8px 14px); }
.reader:not(.presenter) .cover .story-img { padding: 6px; background: #fff; border-radius: 16px; box-shadow: 0 10px 24px -12px rgba(40, 60, 30, .55); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .reader:not(.presenter) .cover .story-img { background: #e8e4d6; } }
:root[data-theme="dark"] .reader:not(.presenter) .cover .story-img { background: #e8e4d6; }

/* Reading badges as real medals: a striped ribbon over a round medal with its number big. Earned
   ones are shiny gold; the ones still to come are gray silhouettes with a little lock, and the
   next one to earn has a soft sunny glow. Names stay underneath. */
.badge-shelf { gap: 14px 10px; justify-content: flex-start; }
.reading-badge { display: flex; flex-direction: column; align-items: center; gap: 6px; width: 92px; padding: 0; border: 0; background: none; border-radius: 0; text-align: center; font-size: .78rem; line-height: 1.15; color: var(--muted); }
.reading-badge.earned { background: none; border: 0; color: #8a6200; }
.medal { position: relative; display: flex; flex-direction: column; align-items: center; }
.medal-ribbon { width: 30px; height: 22px; margin-bottom: -6px; clip-path: polygon(0 0, 100% 0, 80% 100%, 20% 100%);
  background: repeating-linear-gradient(90deg, var(--line-strong) 0 6px, var(--line) 6px 12px); }
.medal-disc { width: 58px; height: 58px; border-radius: 50%; display: grid; place-items: center; font-size: 1.3rem; font-weight: 900; color: var(--muted);
  background: var(--card-2); border: 3px dashed var(--line-strong); }
.medal-lock { position: absolute; right: -4px; bottom: -2px; font-size: .9rem; }
.reading-badge.earned .medal-ribbon { background: repeating-linear-gradient(90deg, #d64545 0 6px, #2f6fb5 6px 12px); }
.reading-badge.earned .medal-disc { color: #6b4a00; border: 3px solid #e0a200; background: radial-gradient(circle at 35% 30%, #fff6cf, #ffd45a 45%, #f5b301);
  box-shadow: inset 0 0 0 4px rgba(255, 255, 255, .35), 0 4px 10px -3px rgba(180, 120, 0, .6); text-shadow: 0 1px 0 rgba(255, 255, 255, .6); }
.reading-badge.next .medal-disc { border-color: var(--sun); box-shadow: 0 0 0 5px color-mix(in srgb, var(--sun) 22%, transparent); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .reading-badge.earned { color: #ffd98a; } }
:root[data-theme="dark"] .reading-badge.earned { color: #ffd98a; }

/* A story's kind as a little pill in its own color: solo leaf green, team-up sunset pink, class
   epic castle purple (the colors the special-day picker and calendar tiles use). */
.kind-pill { display: inline-flex; align-items: center; gap: 4px; padding: 2px 9px; border-radius: 999px; font-size: .8rem; font-weight: 800; white-space: nowrap;
  background: var(--leaf-soft); color: var(--leaf-dark); }
.kind-pill.teamUp { background: #ffe3ea; color: #a8325a; }
.kind-pill.epic { background: #ece4ff; color: #5b3fa6; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .kind-pill.teamUp { background: #4a2232; color: #ffc6d6; } :root:not([data-theme="light"]) .kind-pill.epic { background: #352a55; color: #d9cbff; } }
:root[data-theme="dark"] .kind-pill.teamUp { background: #4a2232; color: #ffc6d6; }
:root[data-theme="dark"] .kind-pill.epic { background: #352a55; color: #d9cbff; }

/* Kid home: the greeting card's sky follows the time of day the greeting names: a peachy sunrise
   in the morning, a clear bright sky in the afternoon, and a soft lilac dusk with a few tiny
   stars in the evening (all faint, behind the words). */
.me-card.sky-morning { background: linear-gradient(160deg, #fff3df 0%, var(--card) 55%); }
.me-card.sky-afternoon { background: linear-gradient(160deg, #e3f3ff 0%, var(--card) 55%); }
.me-card.sky-evening { background:
  radial-gradient(1.5px 1.5px at 78% 22%, #b8a6e8 99%, transparent), radial-gradient(1.5px 1.5px at 88% 38%, #b8a6e8 99%, transparent),
  radial-gradient(2px 2px at 69% 12%, #c9bbf0 99%, transparent), radial-gradient(1.5px 1.5px at 93% 15%, #b8a6e8 99%, transparent),
  linear-gradient(160deg, var(--card) 40%, #ece6fb 100%); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .me-card.sky-morning { background: linear-gradient(160deg, #3a2e20 0%, var(--card) 55%); }
  :root:not([data-theme="light"]) .me-card.sky-afternoon { background: linear-gradient(160deg, #1f3140 0%, var(--card) 55%); }
  :root:not([data-theme="light"]) .me-card.sky-evening { background: radial-gradient(1.5px 1.5px at 78% 22%, #e8e0ff 99%, transparent), radial-gradient(1.5px 1.5px at 88% 38%, #e8e0ff 99%, transparent), radial-gradient(2px 2px at 69% 12%, #fff 99%, transparent), radial-gradient(1.5px 1.5px at 93% 15%, #e8e0ff 99%, transparent), linear-gradient(160deg, var(--card) 40%, #2b2445 100%); }
}
:root[data-theme="dark"] .me-card.sky-morning { background: linear-gradient(160deg, #3a2e20 0%, var(--card) 55%); }
:root[data-theme="dark"] .me-card.sky-afternoon { background: linear-gradient(160deg, #1f3140 0%, var(--card) 55%); }
:root[data-theme="dark"] .me-card.sky-evening { background: radial-gradient(1.5px 1.5px at 78% 22%, #e8e0ff 99%, transparent), radial-gradient(1.5px 1.5px at 88% 38%, #e8e0ff 99%, transparent), radial-gradient(2px 2px at 69% 12%, #fff 99%, transparent), radial-gradient(1.5px 1.5px at 93% 15%, #e8e0ff 99%, transparent), linear-gradient(160deg, var(--card) 40%, #2b2445 100%); }

/* Account: under the new password, ten little segments light up as it grows: sun yellow while
   it's still short, all turning leaf green together once it reaches the 10-character minimum. */
.pw-bar { display: flex; gap: 4px; max-width: 360px; margin-top: 6px; }
.pw-bar > span { flex: 1; height: 7px; border-radius: 999px; background: var(--line); transition: background .15s, transform .15s; }
.pw-bar > span.on { background: var(--sun); }
.pw-bar.ok > span { background: var(--leaf); animation: pw-ok .35s ease-out; }
@keyframes pw-ok { 50% { transform: scaleY(1.6); } }
@media (prefers-reduced-motion: reduce) { .pw-bar > span { transition: none; } .pw-bar.ok > span { animation: none; } }

/* A story's cover: the green ▶ that opens the book breathes softly, with a ring rippling out
   from it, so it's plain where to start. It stops for good once a page is turned. */
.btn.round.primary.start-here { animation: start-breathe 1.8s ease-in-out infinite; }
@keyframes start-breathe { 0% { box-shadow: 0 4px 0 var(--leaf-dark), 0 0 0 0 color-mix(in srgb, var(--leaf) 60%, transparent); transform: scale(1); }
  35% { transform: scale(1.06); } 70%, 100% { box-shadow: 0 4px 0 var(--leaf-dark), 0 0 0 16px color-mix(in srgb, var(--leaf) 0%, transparent); transform: scale(1); } }
@media (prefers-reduced-motion: reduce) { .btn.round.primary.start-here { animation: none; box-shadow: 0 4px 0 var(--leaf-dark), 0 0 0 5px var(--leaf-soft); } }

/* Adding a student: how stories refer to them is three picture buttons side by side (🧒 name,
   👦 he, 👧 she); the chosen one is lit green. */
div.field { font-weight: 700; }
div.field > .field-title { display: block; margin-bottom: 4px; }
.seg-pick { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; }
.seg-option { position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; min-height: 48px; padding: 6px 4px; cursor: pointer;
  border: 2px solid var(--line-strong); border-radius: 14px; background: var(--card); font-size: .8rem; font-weight: 700; text-align: center; line-height: 1.1;
  box-shadow: 0 2px 0 var(--line-strong); transition: border-color .15s, background .15s, transform .1s; }
.seg-option input { position: absolute; opacity: 0; pointer-events: none; }
.seg-emoji { font-size: 1.3rem; line-height: 1; }
.seg-option:hover { border-color: var(--leaf); }
.seg-option:has(input:focus-visible) { outline: 3px solid var(--sun); outline-offset: 2px; }
.seg-option:has(input:checked) { border-color: var(--leaf); background: var(--leaf-soft); color: var(--leaf-dark); box-shadow: 0 2px 0 var(--leaf); transform: translateY(-1px); }

/* Home: the "a story is waiting" and "questions waiting" cards show the book they're about, as a
   little tilted cover with a sticker in its corner (📖 to read, ❓ questions), beside the words. */
.unread-card { display: flex; align-items: center; gap: 16px; }
.unread-card > .stack { flex: 1; min-width: 0; }
.mini-cover { position: relative; flex: none; width: 74px; height: 92px; border-radius: 6px 10px 10px 6px; overflow: visible; rotate: -5deg;
  background: var(--leaf-soft); box-shadow: inset 5px 0 0 rgba(0, 0, 0, .12), 0 6px 14px -6px rgba(40, 60, 30, .5); display: grid; place-items: center; }
.mini-cover img { width: 100%; height: 100%; object-fit: cover; border-radius: inherit; }
.mini-cover-emoji { font-size: 2.2rem; }
.mini-cover-sticker { position: absolute; top: -10px; right: -10px; width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center; font-size: 1rem;
  background: var(--card); border: 2px solid var(--sun); box-shadow: 0 2px 6px rgba(0, 0, 0, .18); rotate: 5deg; }
@media (max-width: 520px) { .mini-cover { width: 60px; height: 76px; } }

/* Classroom screen: after a few still seconds the controls (and Exit, and the cursor) fade away
   so the class sees just the story; any move, tap or key brings them straight back. The cover
   picture is a little smaller there, so the whole cover, "Starring" line included, fits above
   the controls. */
.reader.presenter .reader-bar, body:has(.reader.presenter) .present-exit { transition: opacity .5s ease, transform .5s ease; }
.reader.presenter.idle .reader-bar { opacity: 0; transform: translateY(16px); pointer-events: none; }
body:has(.reader.presenter.idle) .present-exit { opacity: 0; pointer-events: none; }
.reader.presenter.idle { cursor: none; }
.reader.presenter .cover .story-img { height: min(36vh, 540px); }
@media (prefers-reduced-motion: reduce) { .reader.presenter .reader-bar, body:has(.reader.presenter) .present-exit { transition: none; } }

/* Word hunt: words still to find wait in a dashed outline; a found word turns solid leaf green,
   and a row of dots above the words fills green, one per find. */
button.word-chip:not(.found) { border-style: dashed; }
button.word-chip.found { position: relative; background: linear-gradient(180deg, #4fa548, var(--leaf)); border: 2px solid var(--leaf-dark); color: #fff; box-shadow: 0 3px 0 var(--leaf-dark); }
.hunt-dots { display: flex; justify-content: center; gap: 6px; margin: 2px 0 10px; }
.hunt-dots > span { width: 12px; height: 12px; border-radius: 50%; border: 2px dashed var(--leaf); background: var(--card); }
.hunt-dots > span.got { border-style: solid; background: var(--leaf); box-shadow: 0 0 0 3px var(--leaf-soft); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) button.word-chip.found { color: #10240e; } }
:root[data-theme="dark"] button.word-chip.found { color: #10240e; }
/* A day off's calendar tile is a calm night blue (no story that day). */
.date-tile.off { --tile: #5b7bb5; }

/* Saving a new reader's link: a pressed "Copy link" turns green with a ✅ for a moment. */
.btn.copy-btn.copied { background: var(--leaf-soft); border-color: var(--leaf); color: var(--leaf-dark); box-shadow: 0 3px 0 var(--leaf); animation: award-pop .35s ease-out; }
@media (prefers-reduced-motion: reduce) { .btn.copy-btn.copied { animation: none; } }

/* Topics & skills: each folded period shows its skills as little purple pills and the topics
   (and goals) students may pick as a small fanned stack of their pictures. */
.focus-summary .skill-pill { display: inline-flex; margin-left: 8px; padding: 2px 9px; border-radius: 999px; font-size: .8rem; font-weight: 800; background: #ece4ff; color: #5b3fa6; vertical-align: middle; }
.pic-stack { display: inline-flex; align-items: center; margin-left: 12px; vertical-align: middle; }
.pic-stack img, .pic-stack-emoji { width: 38px; height: 38px; border-radius: 9px; object-fit: cover; border: 2px solid var(--card); box-shadow: 0 2px 5px rgba(0, 0, 0, .18); margin-left: -8px; background: var(--leaf-soft); }
.pic-stack > :first-child { margin-left: 0; }
.pic-stack > :nth-child(odd) { rotate: -6deg; } .pic-stack > :nth-child(even) { rotate: 5deg; }
.pic-stack-emoji { display: inline-grid; place-items: center; font-size: .95rem; }
.pic-stack-more { margin-left: 4px; font-size: .78rem; font-weight: 800; color: var(--muted); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .focus-summary .skill-pill { background: #352a55; color: #d9cbff; } }
:root[data-theme="dark"] .focus-summary .skill-pill { background: #352a55; color: #d9cbff; }

/* Locked out of the picture PIN for a few minutes: the ⏳ sits in a sunny ring that empties as
   the wait runs down (smoothly, second by second); when it's over the ring turns into a green
   seal with a 🔑, ready to try again. */
.wait-ring { --p: 100%; position: relative; width: 132px; height: 132px; margin: 4px auto 0; border-radius: 50%; display: grid; place-items: center;
  background: conic-gradient(var(--sun) var(--p), var(--line) 0); transition: background .9s linear; }
.wait-ring::before { content: ""; position: absolute; inset: 11px; border-radius: 50%; background: var(--card); }
.wait-ring-icon { position: relative; font-size: 3.4rem; line-height: 1; animation: wait-tip 4s ease-in-out infinite; }
.wait-ring.done { background: radial-gradient(circle at 35% 30%, #5fc95f, #2f9e44); box-shadow: 0 6px 16px -6px rgba(47, 158, 68, .6); animation: award-pop .5s ease-out; }
.wait-ring.done::before { display: none; }
.wait-ring.done .wait-ring-icon { animation: none; }
@keyframes wait-tip { 0%, 40% { rotate: 0deg; } 50%, 90% { rotate: 180deg; } 100% { rotate: 360deg; } }
@media (prefers-reduced-motion: reduce) { .wait-ring-icon, .wait-ring.done { animation: none; } }

/* Admin Overview, by day: stories and cost each have a slim bar scaled to the busiest day. */
.day-bar-cell { display: inline-flex; align-items: center; gap: 10px; }
.day-bar { display: inline-block; width: 120px; height: 8px; border-radius: 999px; background: var(--leaf-soft); overflow: hidden; }
.day-bar > span { display: block; height: 100%; border-radius: 999px; background: var(--leaf); }
.day-bar-cell.sun .day-bar > span { background: var(--sun); }
@media (max-width: 640px) { .day-bar { width: 60px; } }

/* Picture tiles (topics, goals, items): pointing at one makes its picture lean in a little, and
   picking one gives it a happy pop, so choosing feels like picking up a card. */
.choices.with-pics .choice-img { transition: transform .25s cubic-bezier(.3, 1.6, .5, 1); }
.choices.with-pics .choice:hover:not(:disabled) .choice-img { transform: scale(1.05) rotate(-2deg); }
.choices.with-pics .choice.on .choice-img { animation: pic-pick .5s cubic-bezier(.3, 1.6, .5, 1); }
@keyframes pic-pick { 0% { transform: scale(.9) rotate(4deg); } 60% { transform: scale(1.08) rotate(-3deg); } 100% { transform: none; } }
@media (prefers-reduced-motion: reduce) { .choices.with-pics .choice-img { transition: none; } .choices.with-pics .choice:hover .choice-img { transform: none; } .choices.with-pics .choice.on .choice-img { animation: none; } }
/* Light theme: the painted vignettes have white paper edges, which sat in the tile as a pale box.
   Multiplying lets the paper melt into whatever holds it (picker tiles, the step bar, the "your story" recipe,
   the waiting screen), so each reads as painted right onto it. Dark keeps the framed picture. */
.choices.with-pics .choice-img, .pick-step-pic, .pick-review-part img, .wait-pick img { mix-blend-mode: multiply; background: transparent; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) :is(.choices.with-pics .choice-img, .pick-step-pic, .pick-review-part img, .wait-pick img) { mix-blend-mode: normal; background: var(--card-2); } }
:root[data-theme="dark"] :is(.choices.with-pics .choice-img, .pick-step-pic, .pick-review-part img, .wait-pick img) { mix-blend-mode: normal; background: var(--card-2); }

/* Admin: a reader's page opens with a profile banner, the hero on a spotlight beside the name,
   and each fact (grade, reading level, language, pronoun, joined, time zone) as a small chip with
   its picture. */
.reader-banner { display: flex; align-items: center; gap: 20px; flex-wrap: wrap; }
.fact-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.fact-chip { display: inline-flex; align-items: center; gap: 6px; padding: 4px 11px; border-radius: 999px; font-size: .88rem; font-weight: 700;
  background: var(--card-2); border: 1px solid var(--line); color: var(--ink); }
@media (max-width: 520px) { .reader-banner { flex-direction: column; align-items: flex-start; } .reader-banner .me-hero { width: 96px; height: 96px; } .reader-banner .me-hero .avatar { width: 80px !important; height: 80px !important; } }

/* Read to me: the sentence being read is swiped with a highlighter pen (a warm marker stroke with
   soft, slightly slanted ends that sweeps in from the left), like a grown-up following along with
   a marker, instead of a flat yellow box. A plain highlight in reduced motion. */
.story-text .sent.reading, .story-title.reading {
  box-shadow: none; padding: 0 .12em; margin: 0 -.12em; border-radius: .25em .5em .35em .45em;
  background: linear-gradient(100deg, rgba(255, 220, 90, 0) 0%, #ffe27a 1.5%, #ffd84d 50%, #ffe27a 98%, rgba(255, 220, 90, 0) 100%) no-repeat 0 60% / 100% 78%;
  -webkit-box-decoration-break: clone; box-decoration-break: clone; animation: marker-swipe .5s cubic-bezier(.3, .8, .4, 1) both; }
@keyframes marker-swipe { from { background-size: 0% 78%; } }
@media (prefers-reduced-motion: reduce) { .story-text .sent.reading, .story-title.reading { animation: none; } }

/* A story that didn't work: the kid's own hero stands ready to try again (a hopeful little bounce)
   while a few leaves drift down past them, instead of a lone falling leaf. Still in reduced motion. */
.oops-scene { position: relative; height: 128px; display: grid; place-items: center; }
.oops-hero { display: grid; place-items: center; width: 116px; height: 116px; border-radius: 50%; background: radial-gradient(circle at 50% 40%, color-mix(in srgb, var(--sun) 30%, var(--card)), var(--leaf-soft) 70%);
  animation: oops-bounce 2.4s ease-in-out .4s infinite; }
.oops-leaf { position: absolute; top: 0; left: calc(50% + var(--x)); font-size: 1.5rem; opacity: 0; animation: oops-fall 4.5s ease-in-out infinite; animation-delay: calc(var(--i) * 1.4s); }
@keyframes oops-bounce { 0%, 70%, 100% { transform: translateY(0); } 80% { transform: translateY(-8px) rotate(-3deg); } 90% { transform: translateY(0) rotate(2deg); } }
@keyframes oops-fall { 0% { opacity: 0; transform: translate(0, -6px) rotate(0); } 15% { opacity: .9; } 85% { opacity: .8; } 100% { opacity: 0; transform: translate(18px, 110px) rotate(140deg); } }
@media (prefers-reduced-motion: reduce) { .oops-hero { animation: none; } .oops-leaf { animation: none; opacity: .8; } .oops-leaf:nth-child(2) { top: 70px; } }
.oops-leaf:nth-child(1) { --x: -108px; } .oops-leaf:nth-child(2) { --x: 74px; } .oops-leaf:nth-child(3) { --x: -96px; top: 34px; }
@media (prefers-reduced-motion: reduce) { .oops-leaf:nth-child(2) { top: 64px; } }

/* Today in your class: the next story days as a row of small calendar tiles (leaf green; pink or
   purple when a team-up or class epic falls on one). */
.next-days { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.next-days .date-tile { width: 46px; border-radius: 10px; box-shadow: 0 2px 0 var(--tile); }
.next-days .date-tile-month { font-size: .6rem; padding: 1px 0 2px; }
.next-days .date-tile-day { font-size: 1.1rem; padding-top: 2px; }
.next-days .date-tile-wd { font-size: .6rem; padding-bottom: 3px; }
.date-tile.next { --tile: var(--leaf); }

/* My character: the jump buttons are a tidy grid of little tiles, a big picture over a small
   label, like an app menu, instead of a ragged wrap of pills. The part you jump to lands just
   under the top bar and glows for a moment. */
.me-jumps { display: grid; grid-template-columns: repeat(auto-fit, minmax(76px, 1fr)); gap: 8px; }
.jump-tile { display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 10px 6px 8px; cursor: pointer; font: inherit; font-size: .78rem; font-weight: 800; line-height: 1.15; text-align: center; color: var(--ink);
  border: 2px solid var(--line-strong); border-radius: 16px; background: var(--card); box-shadow: 0 3px 0 var(--line-strong); transition: transform .12s ease, border-color .15s; }
.jump-icon { font-size: 1.6rem; line-height: 1; transition: transform .2s cubic-bezier(.3, 1.6, .5, 1); }
.jump-tile:hover { transform: translateY(-2px); border-color: var(--leaf); }
.jump-tile:hover .jump-icon { transform: scale(1.15) rotate(-6deg); }
.jump-tile:active { transform: translateY(2px); box-shadow: 0 1px 0 var(--line-strong); }
.jump-tile:focus-visible { outline: 3px solid var(--sun); outline-offset: 2px; }
#me-items, #me-badges, #me-look, #me-language, #me-level, #me-art, #me-pronoun { scroll-margin-top: calc(var(--topbar-h, 68px) + 12px); }
.help-landed { animation: help-glow 1.6s ease-out; }
@media (max-width: 520px) { .me-jumps { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; } .jump-tile { font-size: .7rem; padding: 8px 2px 6px; } .jump-icon { font-size: 1.35rem; } }
@media (prefers-reduced-motion: reduce) { .jump-tile, .jump-icon { transition: none; } }

/* Teacher sign-in: the kids' fan of storybook pictures dealt out above the card, the 👁 Show
   button tucked inside the password box, and a full-width Sign in button. */
.login-fan { padding-top: 18px; margin-bottom: -18px; position: relative; z-index: 1; }
.login-fan img { width: clamp(56px, 10vw, 92px); }
.login-card { padding-top: 34px; }
.login-card .pw-row { position: relative; display: block; }
.login-card .pw-row input { width: 100%; padding-right: 96px; }
.login-card .pw-row .btn { position: absolute; right: 6px; top: 50%; transform: translateY(-50%); min-height: 34px; }
.login-card .pw-row .btn:active { transform: translateY(-50%); }
.btn.login-submit { width: 100%; }

/* The bookshelf's group names are label plates like on a library shelf: a warm card-stock plate
   with little brass "screws" at its ends, and the count in a round tag. */
.shelf-group h3.shelf-label { display: inline-flex; align-self: flex-start; align-items: center; gap: 8px; margin: 10px 0 0; padding: 6px 22px; border-radius: 10px; font-size: 1.05rem;
  background: linear-gradient(180deg, #fff8e6, #f5e8c4); color: #5a4220; border: 1px solid #d9c290; box-shadow: 0 2px 0 #c9ad72, inset 0 1px 0 rgba(255, 255, 255, .7); position: relative; }
.shelf-label::before, .shelf-label::after { content: ""; position: absolute; top: 50%; width: 6px; height: 6px; margin-top: -3px; border-radius: 50%;
  background: radial-gradient(circle at 35% 35%, #fff1c2, #b8892e); box-shadow: 0 1px 0 rgba(0, 0, 0, .2); }
.shelf-label::before { left: 8px; } .shelf-label::after { right: 8px; }
.shelf-count { min-width: 24px; height: 24px; padding: 0 6px; border-radius: 999px; display: inline-grid; place-items: center; font-size: .8rem; font-weight: 900; background: #5a4220; color: #fff8e6; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .shelf-group h3.shelf-label { background: linear-gradient(180deg, #4a3c22, #3a2f1b); color: #f5e3b5; border-color: #6b5530; box-shadow: 0 2px 0 #2a2214; } :root:not([data-theme="light"]) .shelf-count { background: #f5e3b5; color: #3a2f1b; } }
:root[data-theme="dark"] .shelf-group h3.shelf-label { background: linear-gradient(180deg, #4a3c22, #3a2f1b); color: #f5e3b5; border-color: #6b5530; box-shadow: 0 2px 0 #2a2214; }
:root[data-theme="dark"] .shelf-count { background: #f5e3b5; color: #3a2f1b; }

/* People lists (admin Teachers): a colored circle with each person's initials beside their name. */
.initials { display: inline-grid; place-items: center; width: 32px; height: 32px; margin-right: 10px; border-radius: 50%; vertical-align: middle; flex: none;
  font-size: .78rem; font-weight: 900; letter-spacing: .02em; color: hsl(var(--hue) 45% 28%); background: hsl(var(--hue) 70% 88%); border: 2px solid hsl(var(--hue) 50% 72%); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .initials { color: hsl(var(--hue) 70% 85%); background: hsl(var(--hue) 30% 24%); border-color: hsl(var(--hue) 35% 38%); } }
:root[data-theme="dark"] .initials { color: hsl(var(--hue) 70% 85%); background: hsl(var(--hue) 30% 24%); border-color: hsl(var(--hue) 35% 38%); }

/* A link that doesn't work: a little reader card (QR frame and two faded lines) tilted on the
   page, with a magnifying glass sweeping back and forth over it, searching. Still in reduced motion. */
.lost-scene { position: relative; width: 150px; height: 120px; margin: 4px auto 6px; }
.lost-card { position: absolute; left: 25px; top: 14px; width: 92px; height: 100px; border-radius: 12px; rotate: -8deg; display: flex; flex-direction: column; align-items: center; gap: 6px; padding-top: 10px;
  background: var(--card); border: 2px dashed #b9c9a8; box-shadow: 0 8px 18px -10px rgba(40, 60, 30, .45); }
.lost-qr { width: 44px; height: 44px; border-radius: 6px; opacity: .5;
  background: linear-gradient(var(--leaf), var(--leaf)) top left / 12px 3px, linear-gradient(var(--leaf), var(--leaf)) top left / 3px 12px,
    linear-gradient(var(--leaf), var(--leaf)) top right / 12px 3px, linear-gradient(var(--leaf), var(--leaf)) top right / 3px 12px,
    linear-gradient(var(--leaf), var(--leaf)) bottom left / 12px 3px, linear-gradient(var(--leaf), var(--leaf)) bottom left / 3px 12px,
    linear-gradient(var(--leaf), var(--leaf)) bottom right / 12px 3px, linear-gradient(var(--leaf), var(--leaf)) bottom right / 3px 12px,
    repeating-conic-gradient(var(--line-strong) 0 25%, transparent 0 50%) center / 10px 10px; background-repeat: no-repeat, no-repeat, no-repeat, no-repeat, no-repeat, no-repeat, no-repeat, no-repeat, repeat; }
.lost-line { width: 60px; height: 6px; border-radius: 999px; background: var(--line); }
.lost-line.short { width: 40px; }
.lost-glass { position: absolute; left: 70px; top: 30px; font-size: 2.6rem; line-height: 1; filter: drop-shadow(0 4px 6px rgba(0, 0, 0, .2)); animation: lost-search 3.2s ease-in-out infinite; }
@keyframes lost-search { 0%, 100% { transform: translate(0, 0) rotate(0deg); } 25% { transform: translate(-46px, -10px) rotate(-12deg); } 50% { transform: translate(-20px, 26px) rotate(6deg); } 75% { transform: translate(10px, 4px) rotate(10deg); } }
@media (prefers-reduced-motion: reduce) { .lost-glass { animation: none; } }
.school-name { display: inline-flex; align-items: center; }
.school-name .initials { border-radius: 10px; }

/* The End of a story: the finished trail warms from leaf green into gold, and the trophy sits in a
   soft golden glow, a little bigger, so arriving feels like winning. */
.trail-goal { display: inline-grid; place-items: center; width: 40px; height: 40px; border-radius: 50%; transition: background .4s, box-shadow .4s, transform .4s; }
.trail.arrived .trail-fill { background: linear-gradient(90deg, #8fd887, var(--leaf) 55%, #f5b301); }
.trail.arrived .trail-goal { background: radial-gradient(circle, #fff3c4 30%, #ffd45a); box-shadow: 0 0 0 4px color-mix(in srgb, var(--sun) 35%, transparent), 0 0 18px rgba(245, 179, 1, .55); transform: scale(1.12); }
.trail.arrived .trail-goal { margin-left: 8px; }

/* Class form: the picture style is a row of small picture tiles (seven across on a wide screen). */
.choices.art-pick { grid-template-columns: repeat(auto-fill, minmax(min(46%, 108px), 1fr)); }
@media (max-width: 520px) { .choices.art-pick { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

/* Starting treasures: a backpack with three slots beside the count; each pick pops into a slot
   as its picture (a purple ring for a power), empty slots wait with their number. */
.pack-row { display: flex; align-items: center; flex-wrap: wrap; gap: 10px 14px; padding: 10px 14px; border-radius: 16px; background: var(--card-2); border: 1px solid var(--line); }
.pack-row > p { margin: 0; }
.pack-bag { font-size: 2rem; line-height: 1; }
.pack-slots { display: flex; gap: 8px; }
.pack-slot { width: 52px; height: 52px; border-radius: 14px; display: grid; place-items: center; font-weight: 800; color: var(--line-strong); font-size: 1.4rem;
  border: 2px dashed var(--line-strong); background: var(--card); overflow: hidden; }
.pack-slot.filled { border: 2px solid var(--leaf); box-shadow: 0 2px 0 var(--leaf); animation: award-pop .35s ease-out; }
.pack-slot.filled.power { border-color: #8b6fd6; box-shadow: 0 2px 0 #7357c4; }
.pack-slot img { width: 100%; height: 100%; object-fit: cover; }
@media (prefers-reduced-motion: reduce) { .pack-slot.filled { animation: none; } }
.seg-pick.two { grid-template-columns: repeat(2, minmax(0, 1fr)); }

/* Making a character: the first name is written in big, friendly story letters on a dashed
   handwriting line, like writing your name inside a book. */
input.hero-name-input { font-family: var(--read-font); font-size: clamp(1.8rem, 6vw, 2.4rem); font-weight: 700; text-align: center; padding: 10px 14px 6px; min-height: 0;
  border: 0; border-radius: 14px 14px 0 0; background: color-mix(in srgb, var(--leaf-soft) 45%, var(--card)); box-shadow: none;
  border-bottom: 3px dashed var(--leaf); color: var(--leaf-dark); letter-spacing: .02em; }
input.hero-name-input::placeholder { color: var(--line-strong); font-weight: 600; }
input.hero-name-input:focus { outline: none; border-bottom-style: solid; box-shadow: 0 4px 0 -1px color-mix(in srgb, var(--leaf) 30%, transparent); }

/* Making a character, the grade step: each grade's number sits big in a round badge, colored by
   school stage (elementary leaf green, middle school sunny gold, high school sky blue). */
.choice.grade-tile .emoji { display: grid; place-items: center; width: 40px; height: 40px; border-radius: 50%; font-family: var(--ui-font); font-size: 1.25rem; font-weight: 900;
  color: #fff; background: var(--band); box-shadow: 0 2px 0 color-mix(in srgb, var(--band) 70%, #000); }
.choice.grade-tile { --band: #3f8f3a; }
.choice.grade-tile.band-mid { --band: #e0a200; }
.choice.grade-tile.band-high { --band: #4a90d9; }
/* Teacher tables: a reading level shows its number in a small round badge, colored by school
   stage like the kids' grade step (elementary green, middle gold, high blue). */
.grade-chip { display: inline-flex; align-items: center; gap: 8px; white-space: nowrap; --band: #3f8f3a; }
.grade-chip.band-mid { --band: #e0a200; } .grade-chip.band-high { --band: #4a90d9; }
.grade-num { display: inline-grid; place-items: center; width: 26px; height: 26px; border-radius: 50%; font-size: .8rem; font-weight: 900; color: #fff; background: var(--band); box-shadow: 0 2px 0 color-mix(in srgb, var(--band) 70%, #000); }

/* Language tiles: a little speech bubble saying hello in that language ("Hi!", "¡Hola!"), so the
   two are told apart at a glance without flags. */
.choice.lang-tile .emoji { position: relative; display: inline-block; padding: 4px 12px 5px; margin-bottom: 6px; border-radius: 14px; font-family: var(--read-font); font-size: 1.05rem; font-weight: 800;
  line-height: 1.2; color: #fff; background: linear-gradient(180deg, #5fae58, #3f8f3a); box-shadow: 0 2px 0 #2e6f2a; }
.choice.lang-tile .emoji::after { content: ""; position: absolute; left: 50%; bottom: -6px; width: 12px; height: 12px; margin-left: -8px; background: #3f8f3a; clip-path: polygon(0 0, 100% 0, 30% 100%); }
.choices.small .choice.lang-tile .emoji { font-size: .9rem; padding: 3px 10px 4px; }

/* Today's story: its big button (Make my story / Read it) catches the light, a soft shine sweeping
   across it every few seconds, and lifts when pointed at, so the day's main tap invites a press.
   Still in reduced motion. */
.today-card .btn.big { position: relative; overflow: hidden; isolation: isolate; transition: transform .15s ease, box-shadow .15s ease; box-shadow: 0 4px 0 rgba(0, 0, 0, .18); }
.today-card .btn.big::after { content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(105deg, transparent 35%, rgba(255, 236, 160, .75) 50%, transparent 65%) -160% 0 / 60% 100% no-repeat; animation: big-shine 4.5s ease-in-out 1s infinite; }
.today-card .btn.big:hover { transform: translateY(-3px); box-shadow: 0 7px 0 rgba(0, 0, 0, .18); }
@keyframes big-shine { 0%, 55% { background-position: -160% 0; } 85%, 100% { background-position: 260% 0; } }
@media (prefers-reduced-motion: reduce) { .today-card .btn.big::after { animation: none; background: none; } }

/* Bookshelf: a story still being written wears a sticker of a pencil busy writing on its cover
   (scribbling back and forth), and the cover is a little faded until the story is ready. */
.cover-writing { position: absolute; top: 8px; right: 8px; width: 38px; height: 38px; border-radius: 50%; display: grid; place-items: center;
  background: var(--card); border: 3px solid var(--sun); box-shadow: 0 3px 8px rgba(0, 0, 0, .22); }
.cover-writing > span { font-size: 1.15rem; line-height: 1; animation: pencil-scribble 1.1s ease-in-out infinite; }
.book:has(.cover-writing) .cover-img { filter: saturate(.6) brightness(1.05); }
@keyframes pencil-scribble { 0%, 100% { transform: translate(-2px, 1px) rotate(-8deg); } 25% { transform: translate(2px, -1px) rotate(4deg); } 50% { transform: translate(-1px, 2px) rotate(-4deg); } 75% { transform: translate(2px, 0) rotate(6deg); } }
@media (prefers-reduced-motion: reduce) { .cover-writing > span { animation: none; } }

/* Your classes: each class tile in its own color, a band along its top and its initials badge
   beside the name (the color comes from the class, so it stays the same every visit). */
.class-tile { overflow: hidden; padding-top: 26px; }
.class-tile::before { content: ""; position: absolute; inset: 0 0 auto 0; height: 8px; background: linear-gradient(90deg, hsl(var(--hue) 60% 62%), hsl(calc(var(--hue) + 30) 65% 70%)); }
.class-tile-name { display: flex; align-items: center; margin-right: 30px; }
.class-tile-name .initials { width: 38px; height: 38px; border-radius: 12px; font-size: .9rem; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .class-tile::before { background: linear-gradient(90deg, hsl(var(--hue) 40% 45%), hsl(calc(var(--hue) + 30) 45% 50%)); } }
:root[data-theme="dark"] .class-tile::before { background: linear-gradient(90deg, hsl(var(--hue) 40% 45%), hsl(calc(var(--hue) + 30) 45% 50%)); }

/* Story questions: "Check my answers" is a big button centered under the questions, like the
   score and the word hunt around it. */
.quiz > .btn.quiz-check { display: flex; margin: 6px auto 0; min-width: min(100%, 280px); }

/* A class's page wears the class's own color from "Your classes": its initials badge beside the
   name, and a band of the same color along the top of the "Today in your class" box. */
.class-page-name { display: flex; align-items: center; }
.class-page-name .initials { width: 44px; height: 44px; border-radius: 14px; font-size: 1rem; margin-right: 12px; }
.today-strip { position: relative; overflow: hidden; }
.today-strip::before { content: ""; position: absolute; inset: 0 0 auto 0; height: 6px; background: linear-gradient(90deg, hsl(var(--hue) 60% 62%), hsl(calc(var(--hue) + 30) 65% 70%)); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .today-strip::before { background: linear-gradient(90deg, hsl(var(--hue) 40% 45%), hsl(calc(var(--hue) + 30) 45% 50%)); } }
:root[data-theme="dark"] .today-strip::before { background: linear-gradient(90deg, hsl(var(--hue) 40% 45%), hsl(calc(var(--hue) + 30) 45% 50%)); }

/* Kid top bar: a treasure earned in the last day puts a little glowing sparkle on the Me button. */
.me-btn { position: relative; }
.me-new { position: absolute; top: -8px; right: -6px; width: 22px; height: 22px; border-radius: 50%; display: grid; place-items: center; font-size: .75rem;
  background: radial-gradient(circle at 35% 30%, #fff6cf, #ffd45a); border: 2px solid var(--card); box-shadow: 0 0 0 3px color-mix(in srgb, var(--sun) 35%, transparent);
  animation: me-new-glow 2s ease-in-out infinite; }
@keyframes me-new-glow { 50% { box-shadow: 0 0 0 6px color-mix(in srgb, var(--sun) 12%, transparent); transform: scale(1.08) rotate(10deg); } }
@media (prefers-reduced-motion: reduce) { .me-new { animation: none; } }

/* "Get your class ready": numbered steps on a path. Done steps are a green ✓, the next step to do
   is a solid sunny circle with its button in green (and a soft highlight on its row), and the rest
   wait in dashed circles; a thin line joins the circles from step to step. */
.setup-path li { position: relative; padding-left: 4px; }
.setup-path .step-num { position: relative; z-index: 1; flex: none; width: 32px; height: 32px; border-radius: 50%; display: grid; place-items: center; font-weight: 900; font-size: .9rem;
  color: var(--muted); background: var(--card); border: 2px dashed var(--line-strong); }
.setup-path li:not(:last-child)::before { content: ""; position: absolute; left: 19px; top: calc(50% + 16px); height: calc(100% - 32px); width: 2px; background: var(--line-strong); }
.setup-path li.done .step-num { border: 2px solid var(--leaf-dark); background: var(--leaf); color: #fff; }
.setup-path li.done:not(:last-child)::before { background: var(--leaf); }
.setup-path li.next { background: color-mix(in srgb, var(--sun) 12%, transparent); border-radius: 12px; }
.setup-path li.next .step-num { border: 2px solid #d99a12; background: var(--sun); color: #3a2a00; box-shadow: 0 0 0 4px color-mix(in srgb, var(--sun) 25%, transparent); }

/* Kid home, stories waiting from missed days: each day is a little tear-off calendar page to tap
   (leaf green; purple with a 📚 sticker when the teacher already picked a library story). */
.day-page { position: relative; overflow: visible; width: 62px; padding: 0; cursor: pointer; font: inherit; text-decoration: none; --tile: var(--leaf); transition: transform .12s ease; }
.day-page .date-tile-month { border-radius: 10px 10px 0 0; }
.day-page:hover:not(:disabled) { transform: translateY(-3px) rotate(-2deg); }
.day-page:active:not(:disabled) { transform: translateY(1px); box-shadow: 0 1px 0 var(--tile); }
.day-page:focus-visible { outline: 3px solid var(--sun); outline-offset: 2px; }
.day-page:disabled { opacity: .5; cursor: not-allowed; }
.day-page.assigned { --tile: #8b6fd6; }
.day-page-sticker { position: absolute; top: -10px; right: -10px; width: 24px; height: 24px; border-radius: 50%; display: grid; place-items: center; font-size: .75rem;
  background: var(--card); border: 2px solid var(--tile); }

/* Who's reading? on a shared device: a grid of profile cards, each hero big in a leafy ring with
   the name under it; the card lifts and the hero bounces when pointed at, and the small forget ✕
   sits in the card's corner. */
.who-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(118px, 1fr)); gap: 12px; }
.who-card { position: relative; }
.who-card .who-btn { display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 14px 8px 12px; border-radius: 18px; text-decoration: none; color: var(--ink);
  background: var(--card); border: 2px solid var(--line-strong); box-shadow: 0 4px 0 var(--line-strong); transition: transform .12s ease, border-color .15s; }
.who-card .who-btn:hover { transform: translateY(-3px); border-color: var(--leaf); }
.who-card .who-btn:active { transform: translateY(2px); box-shadow: 0 1px 0 var(--line-strong); }
.who-card .who-btn:focus-visible { outline: 3px solid var(--sun); outline-offset: 2px; }
.who-face { display: grid; place-items: center; width: 80px; height: 80px; border-radius: 50%; font-size: 2.2rem; background: var(--leaf-soft); box-shadow: 0 0 0 3px var(--card), 0 0 0 6px color-mix(in srgb, var(--leaf) 40%, transparent); transition: transform .25s cubic-bezier(.3, 1.6, .5, 1); }
.who-card .who-btn:hover .who-face { transform: scale(1.06) rotate(-4deg); }
.who-name { font-weight: 800; font-size: 1.05rem; text-align: center; overflow-wrap: anywhere; }
.who-forget { position: absolute; top: 6px; right: 6px; width: 28px; height: 28px; border-radius: 50%; border: 0; background: transparent; color: var(--muted); font: inherit; font-size: .9rem; cursor: pointer; opacity: .55; }
.who-forget:hover, .who-forget:focus-visible { opacity: 1; background: #fde1e1; color: #9b2c2c; outline: none; }
@media (prefers-reduced-motion: reduce) { .who-card .who-btn, .who-face { transition: none; } }

/* Story lists: each story's day as a small calendar tile in its kind's color. */
.mini-date .date-tile { width: 44px; border-radius: 9px; box-shadow: 0 2px 0 var(--tile); }
.mini-date .date-tile-month { font-size: .58rem; padding: 1px 0 2px; }
.mini-date .date-tile-day { font-size: 1.05rem; padding-top: 2px; }
.mini-date .date-tile-wd { font-size: .58rem; padding-bottom: 2px; }
.date-tile.teamUp { --tile: #f06a8b; }
.mini-date { display: inline-block; vertical-align: middle; } .mini-date .date-tile { display: block; }
.quiz > .btn.quiz-check[hidden] { display: none; }
.story-about-line { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px; }

/* A short Finished shelf: faint dashed books stand in its empty spots, waiting for the next
   stories read (on a phone, just the one beside the last book). */
.ghost-shelf-book { flex: 1; min-height: 120px; margin-top: 30%; border-radius: 14px; border: 2px dashed var(--line-strong); background: color-mix(in srgb, var(--leaf-soft) 35%, transparent); opacity: .7; }
.ghost-slot:nth-last-child(2) .ghost-shelf-book { opacity: .5; } .ghost-slot:nth-last-child(1) .ghost-shelf-book { opacity: .3; }
@media (max-width: 520px) { .ghost-slot ~ .ghost-slot { display: none; } }
.ghost-shelf-book { display: grid; place-items: center; } .ghost-shelf-book::after { content: "🍃"; font-size: 1.6rem; opacity: .35; }

/* Adding story days: the weekdays are toggle chips, the same look as a saved range's week. A
   picked day is a solid green chip; the rest wait soft and dashed. The checkbox stays underneath
   for keyboards and screen readers. */
.weekdays label { position: relative; cursor: pointer; min-width: 56px; justify-content: center; padding: 8px 12px; border-radius: 12px; font-weight: 800;
  border: 2px dashed var(--line-strong); background: var(--card); color: var(--muted); transition: background .15s, border-color .15s, transform .1s; }
.weekdays label input { position: absolute; opacity: 0; pointer-events: none; }
.weekdays label:hover { border-color: var(--leaf); transform: translateY(-1px); }
.weekdays label:has(input:focus-visible) { outline: 3px solid var(--sun); outline-offset: 2px; }
.weekdays label:has(input:checked) { border: 2px solid var(--leaf-dark); background: linear-gradient(180deg, #4fa548, var(--leaf)); color: #fff; box-shadow: 0 2px 0 var(--leaf-dark); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .weekdays label:has(input:checked) { color: #10240e; } }
:root[data-theme="dark"] .weekdays label:has(input:checked) { color: #10240e; }

/* Treasure collection: treasures earned in stories are the rare cards. A warm golden frame, a gold
   🏆 sticker in the corner, and a shine that sweeps across when pointed at; starting picks stay
   plain. (A power keeps its purple inner edge.) */
.treasure-grid .treasure.earned { position: relative; overflow: hidden; isolation: isolate; border-color: #e8bf4a;
  background: linear-gradient(160deg, color-mix(in srgb, #ffe9a8 45%, var(--card-2)), var(--card-2) 55%); box-shadow: 0 3px 0 #d9a92c; }
.treasure-grid .treasure.earned.power { box-shadow: inset 0 0 0 2px #c9a8f5, 0 3px 0 #d9a92c; }
.treasure-grid .treasure.earned::before { content: "🏆"; position: absolute; top: 6px; left: 6px; width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center; font-size: .8rem;
  background: radial-gradient(circle at 35% 30%, #fff6cf, #ffd45a); box-shadow: 0 1px 3px rgba(0, 0, 0, .2); }
.treasure-grid .treasure.earned::after { content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: linear-gradient(110deg, transparent 35%, rgba(255, 255, 255, .7) 50%, transparent 65%) -160% 0 / 60% 100% no-repeat; }
.treasure-grid .treasure.earned:hover::after { animation: card-shine .9s ease-out; }
@keyframes card-shine { to { background-position: 260% 0; } }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .treasure-grid .treasure.earned { background: linear-gradient(160deg, color-mix(in srgb, #6b5310 40%, var(--card-2)), var(--card-2) 55%); } }
:root[data-theme="dark"] .treasure-grid .treasure.earned { background: linear-gradient(160deg, color-mix(in srgb, #6b5310 40%, var(--card-2)), var(--card-2) 55%); }
@media (prefers-reduced-motion: reduce) { .treasure-grid .treasure.earned:hover::after { animation: none; } }

/* Progress: the student whose stories are open below is lit in the table (a leaf-green edge and a
   soft green row), and their detail leads with the read ring beside two count chips; many waiting
   days warm the chip to sunny. */
tbody tr.open-student td { background: color-mix(in srgb, var(--leaf-soft) 70%, transparent); }
tbody tr.open-student td:first-child { box-shadow: inset 4px 0 0 var(--leaf); }
.fact-chip.warm { background: color-mix(in srgb, var(--sun) 25%, var(--card)); border-color: #e0a200; }
@media (max-width: 640px) { table.cards-on-phone tr.open-student { box-shadow: inset 4px 0 0 var(--leaf), var(--press); background: color-mix(in srgb, var(--leaf-soft) 60%, var(--card)); } table.cards-on-phone tr.open-student td { background: none; } }

/* Story questions: each question's number sits in a round sunny badge at the start of its line. */
.question legend { display: flex; align-items: flex-start; gap: 10px; }
.q-num { flex: none; width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center; margin-top: -2px;
  font-family: var(--ui-font); font-size: .95rem; font-weight: 900; color: #3a2a00; background: var(--sun); box-shadow: 0 2px 0 #d99a12; }
.reader.presenter .q-num { width: 44px; height: 44px; font-size: 1.3rem; }
/* Admin story list: each school story's class with its own color badge, the teacher under it. */
.where-class { display: inline-flex; align-items: center; }
.where-class .initials { width: 28px; height: 28px; border-radius: 9px; font-size: .7rem; margin-right: 8px; }
.where-teacher { display: block; font-size: .82rem; }

/* Story picker: the teacher's skill for the story is a little mission card. A purple ribbon down
   its side and a 🎯 badge (the purple teachers see on skills), and each skill as a purple tag with
   its meaning beside it. */
.card.skill-card { position: relative; padding-left: 64px; border-color: #c9a8f5; background: linear-gradient(100deg, color-mix(in srgb, #ece4ff 55%, var(--card)), var(--card) 45%); }
.card.skill-card::before { content: "🎯"; position: absolute; left: 14px; top: 16px; width: 36px; height: 36px; border-radius: 50%; display: grid; place-items: center; font-size: 1.1rem;
  background: var(--card); border: 2px solid #8b6fd6; box-shadow: 0 2px 0 #7357c4; }
.card.skill-card::after { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 6px; border-radius: var(--radius) 0 0 var(--radius); background: linear-gradient(180deg, #8b6fd6, #c9a8f5); }
.skill-card .skill-what { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; background: color-mix(in srgb, #ece4ff 40%, var(--card-2)); }
.skill-tag { flex: none; padding: 2px 10px; border-radius: 999px; background: #8b6fd6; color: #fff; font-size: .85rem; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .card.skill-card { background: linear-gradient(100deg, color-mix(in srgb, #352a55 60%, var(--card)), var(--card) 45%); } :root:not([data-theme="light"]) .skill-card .skill-what { background: color-mix(in srgb, #352a55 45%, var(--card-2)); } }
:root[data-theme="dark"] .card.skill-card { background: linear-gradient(100deg, color-mix(in srgb, #352a55 60%, var(--card)), var(--card) 45%); }
:root[data-theme="dark"] .skill-card .skill-what { background: color-mix(in srgb, #352a55 45%, var(--card-2)); }
@media (max-width: 520px) { .card.skill-card { padding-left: 18px; padding-top: 58px; } .card.skill-card::before { top: 12px; } }

/* Reading-skill tiles (focus periods, class epics): skills are purple everywhere they're shown, so
   a picked skill lights up purple with its 🎯, and the tiles lift with a purple edge on hover. */
.choice.skill-tile .emoji { font-size: 1.2rem; filter: grayscale(.6); opacity: .7; }
.choice.skill-tile:hover:not(:disabled) { border-color: #8b6fd6; }
.choice.skill-tile.on { border-color: #8b6fd6; background: color-mix(in srgb, #ece4ff 75%, var(--card)); box-shadow: 0 3px 0 #7357c4; }
.choice.skill-tile.on::after { background: #8b6fd6; }
.choice.skill-tile.on .emoji { filter: none; opacity: 1; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .choice.skill-tile.on { background: color-mix(in srgb, #352a55 75%, var(--card)); } }
:root[data-theme="dark"] .choice.skill-tile.on { background: color-mix(in srgb, #352a55 75%, var(--card)); }

/* Story picker: how much of the topic (or goal) map a kid has explored, as a little dotted trail
   that fills green toward a 🏁, beside the words. */
.explored-line { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 12px; }
.explore-trail { position: relative; display: inline-block; width: 120px; height: 8px; border-radius: 999px; margin-right: 18px;
  background: radial-gradient(circle, var(--line-strong) 1.6px, transparent 2px) 0 50% / 10px 8px repeat-x; }
.explore-trail::before { content: ""; position: absolute; inset: 0 auto 0 0; width: var(--p); border-radius: 999px; background: linear-gradient(90deg, #8fd887, var(--leaf)); }
.explore-flag { position: absolute; right: -20px; top: 50%; transform: translateY(-58%); font-size: 1rem; }

/* Fold-out sections ("What do these columns mean?", past days, archived students...): instead of
   the browser's tiny triangle, a round leafy chevron that turns as it opens, and the whole line
   highlights softly when pointed at, so it's clear it opens. */
details:not(.focus-fold):not(.fail-details) > summary { list-style: none; display: inline-flex; align-items: center; gap: 10px; padding: 6px 14px 6px 6px; border-radius: 999px; transition: background .15s; }
details:not(.focus-fold):not(.fail-details) > summary::-webkit-details-marker { display: none; }
details:not(.focus-fold):not(.fail-details) > summary::before { content: "›"; flex: none; width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center;
  font-size: 1.15rem; font-weight: 900; line-height: 1; color: var(--leaf-dark); background: var(--leaf-soft); transition: transform .2s ease; }
details[open]:not(.focus-fold):not(.fail-details) > summary::before { transform: rotate(90deg); }
details:not(.focus-fold):not(.fail-details) > summary:hover { background: color-mix(in srgb, var(--leaf-soft) 60%, transparent); }
details:not(.focus-fold):not(.fail-details) > summary:focus-visible { outline: 3px solid var(--sun); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { details > summary::before { transition: none; } }
@media print { details > summary::before { display: none; } }

/* My character: when a change saves, the hero at the top does a happy hop and a green ✓ pops
   beside it for a moment. A still ✓ in reduced motion. */
.me-hero::after { content: "✓"; position: absolute; right: -2px; bottom: 4px; width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center;
  background: var(--leaf); color: #fff; font-weight: 900; border: 3px solid var(--card); opacity: 0; transform: scale(.3); pointer-events: none; }
.me-hero.saved { animation: hero-happy .6s cubic-bezier(.3, 1.6, .5, 1); }
.me-hero.saved::after { animation: saved-check 1.6s ease forwards; }
@keyframes hero-happy { 30% { transform: translateY(-10px) rotate(-4deg); } 60% { transform: translateY(0) rotate(3deg); } }
@keyframes saved-check { 0% { opacity: 0; transform: scale(.3); } 20%, 75% { opacity: 1; transform: scale(1); } 100% { opacity: 0; transform: scale(1); } }
@media (prefers-reduced-motion: reduce) { .me-hero.saved { animation: none; } .me-hero.saved::after { animation: saved-check-still 1.6s step-end forwards; } }
@keyframes saved-check-still { 0% { opacity: 1; transform: none; } 100% { opacity: 0; } }

/* Roster: a row whose change just saved glows green for a moment. */
tbody tr.row-saved td { animation: row-saved 1.4s ease-out; }
@keyframes row-saved { 0%, 25% { background: color-mix(in srgb, var(--leaf) 28%, transparent); } 100% { background: transparent; } }
@media (prefers-reduced-motion: reduce) { tbody tr.row-saved td { animation: none; } }
@media (max-width: 640px) { table.cards-on-phone tr.row-saved { animation: row-saved 1.4s ease-out; } table.cards-on-phone tr.row-saved td { animation: none; } }

/* Today's story, once it's read: the card is stamped with a big tilted gold ✓ seal in its corner
   (in place of the drifting leaf), so "today's done" reads at a glance. It lands with a little
   stamp; still in reduced motion. */
.today-card.today-done::after { content: "✓"; right: 22px; bottom: auto; top: 50%; width: 96px; height: 96px; margin-top: -48px; border-radius: 50%; display: grid; place-items: center;
  font-size: 3.2rem; font-weight: 900; line-height: 1; color: #fff; opacity: .95; rotate: -14deg;
  background: radial-gradient(circle at 35% 30%, #ffe27a, #f5b301 70%); border: 4px dashed rgba(255, 255, 255, .8); box-shadow: 0 0 0 5px rgba(245, 179, 1, .4), 0 8px 18px -6px rgba(0, 0, 0, .35);
  text-shadow: 0 2px 0 rgba(150, 100, 0, .45); animation: done-stamp .6s cubic-bezier(.3, 1.6, .5, 1) .3s both; transform: none; }
.today-card.today-done > * { position: relative; z-index: 1; margin-right: 120px; }
@keyframes done-stamp { from { opacity: 0; transform: scale(1.8); } }
@media (prefers-reduced-motion: reduce) { .today-card.today-done::after { animation: none; } }
@media (max-width: 520px) { .today-card.today-done::after { width: 64px; height: 64px; margin-top: 0; top: 14px; font-size: 2.1rem; right: 14px; } .today-card.today-done > * { margin-right: 0; } .today-card.today-done > h2 { margin-right: 76px; } }
@media (max-width: 520px) { .today-card.today-done > p:first-of-type { margin-right: 70px; } }
.date-tile.library { --tile: #8b6fd6; }
@media (max-width: 520px) { .special-row > .btn { margin-left: 72px; } }

/* Top bar language picker: one pill like the buttons beside it (🌐 inside, the dropdown's own box
   gone, a small leafy arrow), instead of a globe floating next to a form box. */
.lang-pick { position: relative; gap: 6px; min-height: 36px; padding: 0 30px 0 12px; border-radius: 999px; cursor: pointer;
  border: 2px solid var(--line-strong); background: var(--card); box-shadow: var(--press); transition: border-color .15s, transform .08s; }
.lang-pick:hover { border-color: var(--leaf); transform: translateY(-1px); }
.lang-pick:focus-within { outline: 3px solid var(--sun); outline-offset: 2px; }
.lang-pick select { -webkit-appearance: none; appearance: none; border: 0 !important; background: transparent !important; box-shadow: none !important; padding: 0 !important;
  min-height: 32px !important; font: inherit; font-weight: 800; font-size: .9rem; color: var(--ink); cursor: pointer; outline: none; }
.lang-pick::after { content: ""; position: absolute; right: 12px; top: 50%; width: 7px; height: 7px; margin-top: -6px; border-right: 2.5px solid var(--leaf-dark); border-bottom: 2.5px solid var(--leaf-dark); transform: rotate(45deg); pointer-events: none; }

/* Account: "Signed in as" reads like a name badge. A band in the person's own color along the top,
   their initials big, the name as the heading and role / email / school as chips. */
.id-card { position: relative; overflow: hidden; border-top: 6px solid hsl(var(--hue) 55% 60%); }
.id-card::before { content: ""; position: absolute; inset: 0 0 auto 0; height: 92px; pointer-events: none;
  background: linear-gradient(180deg, hsl(var(--hue) 70% 88% / .55), transparent); }
.id-card > * { position: relative; }
.id-card-head { display: flex; align-items: center; gap: 4px; }
.id-card-head .initials { width: 64px; height: 64px; font-size: 1.45rem; border-width: 3px; margin-right: 14px;
  box-shadow: 0 4px 0 hsl(var(--hue) 45% 72%); }
.id-card-head h2 { margin: 0; font-size: 1.6rem; line-height: 1.15; }
.id-card-eyebrow { font-size: .78rem; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .id-card::before { background: linear-gradient(180deg, hsl(var(--hue) 35% 30% / .5), transparent); }
  :root:not([data-theme="light"]) .id-card-head .initials { box-shadow: 0 4px 0 hsl(var(--hue) 30% 16%); } }
:root[data-theme="dark"] .id-card::before { background: linear-gradient(180deg, hsl(var(--hue) 35% 30% / .5), transparent); }
:root[data-theme="dark"] .id-card-head .initials { box-shadow: 0 4px 0 hsl(var(--hue) 30% 16%); }

/* Reader cover tips: the keys and buttons they mention, drawn like the real thing (keycaps with a
   bottom edge, the round green page button, tiny copies of Read to me / Translate). */
.turn-hint { line-height: 2; }
.turn-hint .keycap { display: inline-grid; place-items: center; min-width: 1.9em; height: 1.75em; padding: 0 .45em; margin: 0 .1em; vertical-align: .05em;
  border: 1.5px solid var(--line-strong); border-radius: 7px; background: var(--card); box-shadow: 0 3px 0 var(--line-strong);
  font: inherit; font-size: .85em; font-weight: 900; line-height: 1; color: var(--ink); }
.turn-hint .keycap.space { min-width: 5.5em; font-size: .78em; font-weight: 800; }
.turn-hint .mini-turn { display: inline-grid; place-items: center; width: 1.7em; height: 1.7em; margin: 0 .1em; vertical-align: -.05em; border-radius: 50%;
  background: var(--leaf); color: #fff; font-size: .8em; padding-left: .12em; box-shadow: 0 2px 0 var(--leaf-dark); }
.turn-hint .mini-btn { display: inline-block; padding: 0 .65em; margin: 0 .1em; line-height: 1.7; border-radius: 999px; white-space: nowrap;
  border: 1.5px solid var(--line-strong); background: var(--card); box-shadow: 0 2px 0 var(--line-strong); font-weight: 800; font-size: .9em; color: var(--ink); }
/* Room for half the hero's face at the path's start, so on a phone it isn't cut off at the edge. */
.trail { padding-left: 16px; }

/* Help: every section in its own color. The chip's icon circle, the card's top band and the
   icon tile by the card's title all share it, so a jump lands on the card that matches the chip. */
.help-chip[style*="--hue"] .help-chip-icon { background: hsl(var(--hue) 70% 90%); box-shadow: inset 0 0 0 1.5px hsl(var(--hue) 50% 76%); }
.help-chip[style*="--hue"]:hover { border-color: hsl(var(--hue) 50% 55%); }
.help-section[style*="--hue"] { border-top: 5px solid hsl(var(--hue) 55% 62%); }
.help-head { display: flex; align-items: center; gap: 12px; }
.help-head-icon { flex: none; width: 42px; height: 42px; border-radius: 13px; display: grid; place-items: center; font-size: 1.35rem;
  background: hsl(var(--hue, 130) 70% 90%); box-shadow: inset 0 0 0 2px hsl(var(--hue, 130) 50% 78%), 0 3px 0 hsl(var(--hue, 130) 45% 80%); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .help-chip[style*="--hue"] .help-chip-icon,
  :root:not([data-theme="light"]) .help-head-icon { background: hsl(var(--hue, 130) 30% 24%); box-shadow: inset 0 0 0 1.5px hsl(var(--hue, 130) 35% 40%); }
  :root:not([data-theme="light"]) .help-section[style*="--hue"] { border-top-color: hsl(var(--hue) 40% 45%); } }
:root[data-theme="dark"] .help-chip[style*="--hue"] .help-chip-icon, :root[data-theme="dark"] .help-head-icon { background: hsl(var(--hue, 130) 30% 24%); box-shadow: inset 0 0 0 1.5px hsl(var(--hue, 130) 35% 40%); }
:root[data-theme="dark"] .help-section[style*="--hue"] { border-top-color: hsl(var(--hue) 40% 45%); }

/* Me page: each jump button in its own color (a soft wash with the icon on a tinted circle), and
   the card it jumps to wears the same color as a band along its top. On a phone the buttons fill
   every row edge to edge (7 of them: a row of 4, then 3 a little wider) instead of leaving a gap. */
.jump-tile[style*="--hue"] { background: linear-gradient(180deg, hsl(var(--hue) 80% 95%), var(--card) 70%); border-color: hsl(var(--hue) 45% 80%); box-shadow: 0 3px 0 hsl(var(--hue) 40% 78%); }
.jump-tile[style*="--hue"]:hover { border-color: hsl(var(--hue) 55% 58%); }
.jump-tile[style*="--hue"] .jump-icon { display: grid; place-items: center; width: 2.1em; height: 2.1em; border-radius: 50%; font-size: 1.25rem;
  background: hsl(var(--hue) 75% 88%); box-shadow: inset 0 0 0 2px hsl(var(--hue) 55% 78%); }
.me-section { border-top: 6px solid hsl(var(--hue) 60% 64%); background-image: linear-gradient(180deg, hsl(var(--hue) 80% 94% / .7), transparent 90px); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .jump-tile[style*="--hue"] { background: linear-gradient(180deg, hsl(var(--hue) 30% 20%), var(--card) 70%); border-color: hsl(var(--hue) 30% 34%); box-shadow: 0 3px 0 hsl(var(--hue) 30% 14%); }
  :root:not([data-theme="light"]) .jump-tile[style*="--hue"] .jump-icon { background: hsl(var(--hue) 30% 26%); box-shadow: inset 0 0 0 2px hsl(var(--hue) 35% 38%); }
  :root:not([data-theme="light"]) .me-section { border-top-color: hsl(var(--hue) 40% 45%); background-image: linear-gradient(180deg, hsl(var(--hue) 30% 22% / .6), transparent 90px); } }
:root[data-theme="dark"] .jump-tile[style*="--hue"] { background: linear-gradient(180deg, hsl(var(--hue) 30% 20%), var(--card) 70%); border-color: hsl(var(--hue) 30% 34%); box-shadow: 0 3px 0 hsl(var(--hue) 30% 14%); }
:root[data-theme="dark"] .jump-tile[style*="--hue"] .jump-icon { background: hsl(var(--hue) 30% 26%); box-shadow: inset 0 0 0 2px hsl(var(--hue) 35% 38%); }
:root[data-theme="dark"] .me-section { border-top-color: hsl(var(--hue) 40% 45%); background-image: linear-gradient(180deg, hsl(var(--hue) 30% 22% / .6), transparent 90px); }
@media (max-width: 520px) { .me-jumps { display: flex; flex-wrap: wrap; justify-content: center; } .me-jumps .jump-tile { flex: 0 0 calc(25% - 4.5px); min-width: 0; }
  .jump-tile[style*="--hue"] .jump-icon { font-size: 1.1rem; } }

/* A button that goes to (or picks) one class wears that class's badge: its colored initials,
   the same as on its tile on the Classes page, with a matching edge. Easy to tell Room 12 from
   Other room without reading. */
.btn.class-btn { display: inline-flex; align-items: center; gap: 0; padding-left: 6px; border-color: hsl(var(--hue) 45% 72%); box-shadow: 0 3px 0 hsl(var(--hue) 40% 78%); }
.btn.class-btn:hover { border-color: hsl(var(--hue) 50% 55%); }
.btn.class-btn .initials { width: 26px; height: 26px; border-radius: 8px; font-size: .66rem; margin-right: 8px; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .btn.class-btn { border-color: hsl(var(--hue) 30% 36%); box-shadow: 0 3px 0 hsl(var(--hue) 30% 16%); } }
:root[data-theme="dark"] .btn.class-btn { border-color: hsl(var(--hue) 30% 36%); box-shadow: 0 3px 0 hsl(var(--hue) 30% 16%); }

/* Step-by-step screens (making a reader, first-day setup, writing a story): Back / Cancel and the
   big next button stay on one row. On a phone the next button stretches to fill it (its words may
   wrap inside), instead of dropping under Back and leaving both stranded on the left. */
.wizard-nav { flex-wrap: nowrap; align-items: center; }
.wizard-nav > :first-child { flex: none; }
@media (max-width: 520px) {
  .wizard-nav { gap: 10px; }
  .wizard-nav > :last-child { flex: 1 1 auto; min-width: 0; white-space: normal; text-align: center; justify-content: center; line-height: 1.2; }
  .wizard-nav > :last-child.big { padding-left: 14px; padding-right: 14px; }
}

/* Class form: the reading range drawn as K-12 dots. Lit dots (in their school-stage color) are
   the range, its two ends a little bigger; the class's own grade has a small dot beneath it. */
.range-ribbon { display: flex; gap: 3px; padding: 2px 0 8px; }
.rr-dot { position: relative; flex: 1 1 0; min-width: 0; max-width: 24px; aspect-ratio: 1; display: grid; place-items: center; border-radius: 50%; cursor: pointer;
  font-size: .62rem; font-weight: 900; color: var(--muted); background: var(--card-2); border: 1.5px dashed var(--line-strong);
  transition: transform .15s cubic-bezier(.3, 1.6, .5, 1), background .15s; --band: #3f8f3a; }
.rr-dot.band-mid { --band: #e0a200; } .rr-dot.band-high { --band: #4a90d9; }
.rr-dot:hover { transform: scale(1.18); }
.rr-dot.in { background: var(--band); border: 1.5px solid var(--band); color: #fff; }
.rr-dot.in.end { transform: scale(1.15); box-shadow: 0 2px 0 color-mix(in srgb, var(--band) 60%, #000); }
.rr-dot.here::after { content: ""; position: absolute; left: 50%; bottom: -8px; width: 5px; height: 5px; margin-left: -2.5px; border-radius: 50%; background: var(--ink); }
@media (prefers-reduced-motion: reduce) { .rr-dot { transition: none; } }

/* Start page: "How Hojas works" as a little path. Each step's picture sits in its own colored
   circle with its number pinned on, and a dashed trail joins the circles top to bottom, so the
   four lines read as one journey: make a hero, pick, read, earn. */
.how-steps { gap: 0; counter-reset: how; }
.how-steps li { position: relative; align-items: flex-start; padding-bottom: 16px; counter-increment: how; --hue: 140; }
.how-steps li:nth-child(2) { --hue: 285; } .how-steps li:nth-child(3) { --hue: 205; } .how-steps li:nth-child(4) { --hue: 42; }
.how-steps li:last-child { padding-bottom: 0; }
.how-steps li:not(:last-child)::before { content: ""; position: absolute; left: 25px; top: 54px; bottom: 2px; border-left: 3px dashed var(--line-strong); }
.how-steps li > span:last-child { padding-top: 12px; }
.how-icon { position: relative; flex: none; display: grid; place-items: center; width: 52px; min-width: 52px; height: 52px; border-radius: 50%; font-size: 1.6rem;
  background: hsl(var(--hue) 75% 90%); box-shadow: inset 0 0 0 2px hsl(var(--hue) 50% 78%), 0 3px 0 hsl(var(--hue) 40% 80%); }
.how-icon::after { content: counter(how); position: absolute; right: -4px; top: -4px; width: 20px; height: 20px; border-radius: 50%; display: grid; place-items: center;
  font-size: .72rem; font-weight: 900; color: #fff; background: hsl(var(--hue) 55% 45%); box-shadow: 0 0 0 2px var(--card); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .how-icon { background: hsl(var(--hue) 30% 24%); box-shadow: inset 0 0 0 2px hsl(var(--hue) 35% 38%), 0 3px 0 hsl(var(--hue) 30% 14%); } }
:root[data-theme="dark"] .how-icon { background: hsl(var(--hue) 30% 24%); box-shadow: inset 0 0 0 2px hsl(var(--hue) 35% 38%), 0 3px 0 hsl(var(--hue) 30% 14%); }
.stack > .how-steps { margin-top: 20px; }
.stack > .how-steps + p { margin-top: 18px; }

/* Number boxes with big round − / + on either side; the team-size one also shows the team as a
   row of little classmates (one colored head-and-shoulders per seat) that grows and shrinks. */
.stepper { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.stepper input[type="number"] { order: 1; width: 5.5em; text-align: center; font-weight: 800; -moz-appearance: textfield; appearance: textfield; }
.stepper input[type="number"]::-webkit-inner-spin-button, .stepper input[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.step-btn { order: 0; flex: none; width: 44px; height: 44px; border-radius: 50%; display: grid; place-items: center; cursor: pointer; padding: 0;
  font: inherit; font-size: 1.35rem; font-weight: 900; line-height: 1; color: var(--leaf-dark); background: var(--card);
  border: 2px solid var(--line-strong); box-shadow: 0 3px 0 var(--line-strong); transition: transform .08s, border-color .15s; }
.step-btn.plus { order: 2; }
.step-btn:hover:not(:disabled) { border-color: var(--leaf); transform: translateY(-1px); }
.step-btn:active:not(:disabled) { transform: translateY(2px); box-shadow: 0 1px 0 var(--line-strong); }
.step-btn:disabled { opacity: .35; cursor: default; }
.stepper-pic { order: 3; display: flex; flex-wrap: wrap; gap: 3px; align-items: flex-end; min-height: 28px; }
.team-seat { position: relative; width: 16px; height: 22px; animation: seat-pop .25s cubic-bezier(.3, 1.6, .5, 1); }
.team-seat::before { content: ""; position: absolute; left: 4px; top: 0; width: 8px; height: 8px; border-radius: 50%; background: hsl(var(--hue) 55% 62%); }
.team-seat::after { content: ""; position: absolute; left: 0; bottom: 0; width: 16px; height: 12px; border-radius: 8px 8px 3px 3px; background: hsl(var(--hue) 55% 62%); }
@keyframes seat-pop { from { transform: scale(.4); opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .team-seat { animation: none; } .step-btn { transition: none; } }

/* Story questions: a question with an answer picked has its number badge filled in (sky blue,
   so it doesn't look like "right"), and the Check button carries one dot per question that fills
   as each is answered. Once all are, the button glows, ready to press. */
.question:has(input:checked) .q-num { background: #4a90d9; color: #fff; box-shadow: 0 2px 0 #2f6db0; transform: scale(1.08); }
.q-num { transition: background .2s, transform .2s cubic-bezier(.3, 1.6, .5, 1); }
.quiz-check { flex-wrap: wrap; justify-content: center; column-gap: 10px; row-gap: 4px; }
.quiz-dots { display: inline-flex; gap: 5px; align-items: center; }
.quiz-dots > span { width: 10px; height: 10px; border-radius: 50%; border: 2px solid rgba(255,255,255,.75); background: transparent; transition: background .2s, transform .2s cubic-bezier(.3, 1.6, .5, 1); }
.quiz-dots > span.on { background: #fff; transform: scale(1.15); }
.quiz-check.all-picked { animation: check-ready 1.8s ease-in-out infinite; }
@keyframes check-ready { 0%, 100% { box-shadow: 0 4px 0 var(--leaf-dark), 0 0 0 0 color-mix(in srgb, var(--sun) 0%, transparent); }
  50% { box-shadow: 0 4px 0 var(--leaf-dark), 0 0 0 7px color-mix(in srgb, var(--sun) 45%, transparent); } }
@media (prefers-reduced-motion: reduce) { .quiz-check.all-picked { animation: none; box-shadow: 0 4px 0 var(--leaf-dark), 0 0 0 4px color-mix(in srgb, var(--sun) 45%, transparent); }
  .q-num, .quiz-dots > span { transition: none; } }
@media (prefers-reduced-motion: reduce) { :root .btn.primary.quiz-check.all-picked:not(.not-ready) { box-shadow: 0 4px 0 #1d4d19, 0 0 0 4px color-mix(in srgb, var(--sun) 45%, transparent); } }

/* A filter that's narrowing a list (a menu off its "everything" choice, or words in a search box)
   turns green with a small funnel dot, so a short list is never a mystery. */
select.filter.filter-on, input.filter.filter-on { border-color: var(--leaf) !important; background-color: color-mix(in srgb, var(--leaf-soft) 75%, var(--card)) !important;
  font-weight: 800; color: var(--leaf-dark); box-shadow: 0 0 0 3px color-mix(in srgb, var(--leaf) 18%, transparent); }
select.filter.filter-on { background-image: radial-gradient(circle, var(--leaf) 0 4px, transparent 4.5px) !important; background-repeat: no-repeat !important;
  background-position: 12px 50% !important; background-size: 10px 10px !important; padding-left: 30px !important; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) select.filter.filter-on, :root:not([data-theme="light"]) input.filter.filter-on { color: #bff0b8; background-color: #234a22 !important; } }
:root[data-theme="dark"] select.filter.filter-on, :root[data-theme="dark"] input.filter.filter-on { color: #bff0b8; background-color: #234a22 !important; }

/* "Write it!" on a phone: the treasures the hero brings show as a little pile of round picture
   tokens (a slight tilt each, overlapping like things tipped out of a backpack) instead of a
   ragged column of one-name-per-line pills. Tapping one still shows what it is. */
@media (max-width: 520px) {
  .bringing .inventory { gap: 0; padding: 4px 0 2px 10px; align-items: center; }
  .bringing .pill:not(.more-pill) { width: 54px; height: 54px; padding: 0 !important; margin-left: -10px; border-radius: 50%; justify-content: center; position: relative;
    border: 3px solid var(--card); box-shadow: 0 3px 8px rgba(0,0,0,.14); transform: rotate(var(--tilt, -4deg)); transition: transform .2s cubic-bezier(.3, 1.6, .5, 1); }
  .bringing .pill:nth-child(2n) { --tilt: 5deg; } .bringing .pill:nth-child(3n) { --tilt: -7deg; }
  .bringing .pill:not(.more-pill):active { transform: rotate(0) scale(1.12); z-index: 1; }
  .bringing .pill .pill-name, .bringing .pill .new-tag { display: none; }
  .bringing .pill .pill-pic { width: 100%; height: 100%; border: 0; }
  .bringing .pill .pill-emoji { font-size: 1.6rem; }
  .bringing .pill.more-pill { margin-left: 6px; font-size: .82rem; }
}
@media (max-width: 520px) and (prefers-reduced-motion: reduce) { .bringing .pill { transition: none; } }

/* Topics & skills: each focus period card (and "+ New focus period") opens with the same round
   leafy chevron as the other fold-outs, on the card's right edge, turning as it opens; the whole
   line lights softly when pointed at, so the card plainly opens. */
.focus-fold > .focus-summary { position: relative; list-style: none; padding-right: 58px; border-radius: var(--radius); transition: background .15s; }
.focus-fold > .focus-summary::-webkit-details-marker { display: none; }
.focus-fold > .focus-summary::after { content: "›"; position: absolute; right: 16px; top: 50%; width: 30px; height: 30px; margin-top: -15px; border-radius: 50%;
  display: grid; place-items: center; font-size: 1.25rem; font-weight: 900; line-height: 1; color: var(--leaf-dark); background: var(--leaf-soft); transition: transform .2s ease; }
.focus-fold[open] > .focus-summary::after { transform: rotate(90deg); }
.focus-fold[open] > .focus-summary { border-radius: var(--radius) var(--radius) 0 0; }
.focus-fold > .focus-summary:hover { background: color-mix(in srgb, var(--leaf-soft) 45%, transparent); }
.focus-fold > .focus-summary:focus-visible { outline: 3px solid var(--sun); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { .focus-fold > .focus-summary::after { transition: none; } }
@media print { .focus-fold > .focus-summary::after { display: none; } }

/* Story picker: the "explored" trail is a real path now: full width under the words, chunky and
   leafy, with the kid's hero standing where they've got to and the 🏁 waiting at the end. */
.explored-line { display: grid; gap: 10px; }
.explored-line .explore-trail { display: block; width: auto; height: 12px; margin: 6px 26px 4px 13px; background: var(--line); }
.explored-line .explore-trail::before { box-shadow: inset 0 -2px 0 rgba(0,0,0,.08); }
.explore-hero { position: absolute; left: var(--p); top: 50%; transform: translate(-50%, -55%); line-height: 0; }
.explore-hero .avatar { border: 2px solid var(--card); box-shadow: 0 2px 6px rgba(0,0,0,.18); border-radius: 50%; }
.explored-line .explore-flag { right: -26px; font-size: 1.2rem; }

/* Stories lists: the stars' hero faces as a little overlapping group above their names. */
.hero-faces { display: flex; align-items: center; margin: 0 0 4px 6px; }
.hero-faces > * { margin-left: -6px; border: 2px solid var(--card); border-radius: 50%; box-shadow: 0 1px 3px rgba(0,0,0,.12); background: var(--card-2); }
.hero-faces .face-todo { width: 28px; height: 28px; font-size: .75rem; }
.hero-faces-more { display: grid; place-items: center; min-width: 28px; height: 28px; padding: 0 4px; font-size: .72rem; font-weight: 800; color: var(--leaf-dark); background: var(--leaf-soft) !important; border-radius: 999px !important; }

/* A story page with no picture: its words sit in the middle of the page, like a page in a real
   book, instead of three lines at the top of a big empty sheet. (Long pages fill it anyway.) */
.reader:not(.presenter) .page:not(.with-img):not(.cover):has(> .story-text) { display: flex; flex-direction: column; justify-content: center; }
.reader:not(.presenter) .page:not(.with-img):not(.cover):has(> .story-text) > .hunt-back { align-self: stretch; margin-bottom: auto; }
.reader:not(.presenter) .page:not(.with-img):not(.cover):has(> .story-text) > .hunt-back ~ .story-text { margin-bottom: auto; }

/* The hero in the Look editor, once pinned while scrolling: a slim strip with a smaller face
   (and a soft shadow under it), so the choices beneath stay uncovered. */
.look-preview .avatar { transition: width .2s ease, height .2s ease, border-width .2s ease; }
.look-preview.stuck { margin: 0 -16px; padding: 6px 0; background: var(--card); box-shadow: 0 6px 10px -6px rgba(0,0,0,.18); border-radius: 0 0 16px 16px; }
.look-preview.stuck .avatar { width: 58px !important; height: 58px !important; border-width: 3px; }
.stack > .look-preview + * { margin-top: 14px; }
@media (prefers-reduced-motion: reduce) { .look-preview .avatar { transition: none; } }

/* QR cards: the kid's hero face tucked into the left of their name pill. */
.qr-card .name.with-face { display: inline-flex; align-items: center; gap: 8px; padding-left: 4px; }
.qr-card .name.with-face .avatar { border: 2px solid #fff; border-radius: 50%; box-shadow: 0 1px 3px rgba(0,0,0,.15); }

/* Home greeting on a phone: the hero's treasures as the same little pile of round picture tokens
   as on "Write it!", in one tidy row with "+N more", instead of three ragged rows of name pills. */
@media (max-width: 520px) {
  .me-card .inventory { gap: 0; padding: 4px 0 2px 10px; align-items: center; flex-wrap: nowrap; }
  .me-card .inventory .pill:not(.more-pill) { width: 44px; height: 44px; padding: 0 !important; margin-left: -10px; border-radius: 50%; justify-content: center; flex: none;
    border: 3px solid var(--card); box-shadow: 0 3px 8px rgba(0,0,0,.14); transform: rotate(var(--tilt, -4deg)); }
  .me-card .inventory .pill:nth-child(2n) { --tilt: 5deg; } .me-card .inventory .pill:nth-child(3n) { --tilt: -7deg; }
  .me-card .inventory .pill .pill-name, .me-card .inventory .pill .new-tag { display: none; }
  .me-card .inventory .pill .pill-pic { width: 100%; height: 100%; border: 0; }
  .me-card .inventory .pill .pill-emoji { font-size: 1.35rem; }
  .me-card .inventory .pill.more-pill { margin-left: 8px; flex: none; }
}

/* Class tiles: a student still making their hero shows as a small dashed 🎨 face in the row. */
.class-faces .face-todo.tile-todo { width: 30px; height: 30px; font-size: .75rem; background: var(--card); }
.class-faces .hero-faces-more { margin-left: 4px; }
.class-faces .face-todo.tile-todo { margin-right: -8px; border: 2px dashed var(--line-strong); box-shadow: 0 0 0 2px var(--card); }

/* Start page: each way in has a small picture in its corner. "New here?" a hero with a sparkle;
   "Have a link?" a tiny copy of the teacher's QR card (green corner brackets around a code, a
   name pill on top), tilted like it was just handed over. */
.start-path { position: relative; }
.start-path > h2 { padding-right: 76px; }
.start-art { position: absolute; top: 14px; right: 16px; pointer-events: none; }
.new-art { width: 58px; height: 58px; border-radius: 50%; display: grid; place-items: center; font-size: 2rem;
  background: radial-gradient(circle at 40% 35%, #fff8d6, #ffe6a3); box-shadow: inset 0 0 0 2px #f1cf6a, 0 3px 0 #e6c35a; transform: rotate(-6deg); }
.new-art i { position: absolute; right: -6px; top: -6px; font-style: normal; font-size: 1.1rem; animation: art-twinkle 2.4s ease-in-out infinite; }
@keyframes art-twinkle { 0%, 100% { transform: scale(1) rotate(0); } 50% { transform: scale(1.25) rotate(15deg); } }
.card-art { width: 54px; height: 66px; border-radius: 8px; background: #fff; border: 1.5px dashed #b9c9a8; box-shadow: 0 4px 10px rgba(0,0,0,.12); transform: rotate(7deg);
  display: flex; flex-direction: column; align-items: center; gap: 4px; padding-top: 6px; }
.ca-name { width: 30px; height: 7px; border-radius: 999px; background: #e0efd4; }
.ca-code { position: relative; width: 36px; height: 36px; padding: 5px;
  background: linear-gradient(#3f8f3a, #3f8f3a) 0 0 / 9px 2px, linear-gradient(#3f8f3a, #3f8f3a) 0 0 / 2px 9px,
    linear-gradient(#3f8f3a, #3f8f3a) 100% 0 / 9px 2px, linear-gradient(#3f8f3a, #3f8f3a) 100% 0 / 2px 9px,
    linear-gradient(#3f8f3a, #3f8f3a) 0 100% / 9px 2px, linear-gradient(#3f8f3a, #3f8f3a) 0 100% / 2px 9px,
    linear-gradient(#3f8f3a, #3f8f3a) 100% 100% / 9px 2px, linear-gradient(#3f8f3a, #3f8f3a) 100% 100% / 2px 9px;
  background-repeat: no-repeat; }
.ca-code::after { content: ""; position: absolute; inset: 6px; background:
  conic-gradient(#1f2a1c 25%, transparent 0 50%, #1f2a1c 0 75%, transparent 0) 0 0 / 6px 6px,
  linear-gradient(90deg, #1f2a1c 50%, transparent 0) 0 0 / 4px 100%; opacity: .85; }
@media (prefers-reduced-motion: reduce) { .new-art i { animation: none; } }
.start-path > p { padding-right: 66px; }

/* Teacher sign-in, wrong password: the card shakes its head once and the password box goes red. */
.login-card.login-shake { animation: pin-shake .45s ease-in-out; }
input.login-wrong { border-color: #d64545 !important; box-shadow: 0 0 0 3px color-mix(in srgb, #d64545 22%, transparent) !important; background: color-mix(in srgb, #fde1e1 55%, var(--card)); }
@media (prefers-reduced-motion: reduce) { .login-card.login-shake { animation: none; } }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) input.login-wrong { background: #3a2222; } }
:root[data-theme="dark"] input.login-wrong { background: #3a2222; }

/* Start page: a paste that isn't a Hojas link (or nothing pasted) makes the box shake and go red. */
input.link-shake { animation: pin-shake .45s ease-in-out; }
@media (prefers-reduced-motion: reduce) { input.link-shake { animation: none; } }
.start-path > p.link-note { padding-right: 0; }

/* Admin: each server service (voices, translator) has a power light at the end of its heading. */
.svc-head { display: flex; align-items: center; gap: 8px; }
.status-light { margin-left: auto; flex: none; width: 18px; height: 18px; border-radius: 50%; border: 2px solid var(--card);
  background: #9aa39a; box-shadow: 0 0 0 2px #c9cfc6, inset 0 -3px 4px rgba(0,0,0,.25); }
.status-light.on { background: radial-gradient(circle at 35% 30%, #c9ffc0, #3fbf4a 60%); box-shadow: 0 0 0 2px #9fdc98, 0 0 12px 2px rgba(63,191,74,.55); }
.status-light.busy { background: radial-gradient(circle at 35% 30%, #fff1b8, #f0b400 60%); box-shadow: 0 0 0 2px #f1d27a, 0 0 10px 2px rgba(240,180,0,.5); animation: light-pulse 1.6s ease-in-out infinite; }
.status-light.bad { background: radial-gradient(circle at 35% 30%, #ffc9c9, #d64545 60%); box-shadow: 0 0 0 2px #f0a3a3, 0 0 10px 2px rgba(214,69,69,.5); }
.status-light.off { background: radial-gradient(circle at 35% 30%, #c4c9c2, #7d857b 60%); }
@keyframes light-pulse { 50% { opacity: .55; } }
@media (prefers-reduced-motion: reduce) { .status-light.busy { animation: none; } }
.status-light.part { background: radial-gradient(circle at 35% 30%, #fff1b8, #f0b400 60%); box-shadow: 0 0 0 2px #f1d27a, 0 0 10px 2px rgba(240,180,0,.45); }

/* "One tap next time": the steps for the device in your hand stand out as a green card with a
   pointing hand; the other device's steps sit quieter below. */
.home-steps { list-style: none; padding: 0; display: grid; gap: 8px; }
.home-steps li { margin: 0; padding: 10px 14px 10px 44px; position: relative; border-radius: 14px; border: 2px dashed var(--line); color: var(--muted); font-weight: 400; }
.home-steps li::before { content: "📱"; position: absolute; left: 12px; top: 10px; font-size: 1.1rem; opacity: .55; }
.home-steps li.mine { order: -1; font-weight: 400; color: var(--ink); border: 2px solid var(--leaf); background: color-mix(in srgb, var(--leaf-soft) 65%, var(--card)); box-shadow: 0 3px 0 var(--leaf); }
.home-steps li.mine::before { content: "👉"; opacity: 1; animation: point-nudge 1.4s ease-in-out infinite; }
@keyframes point-nudge { 50% { transform: translateX(4px); } }
@media (prefers-reduced-motion: reduce) { .home-steps li.mine::before { animation: none; } }

/* Library preview: each page looks like a page of the book. A green tab with its number, a
   folded top corner, and the story in the storybook font the kids read it in. */
.preview-page { position: relative; padding-top: 44px; overflow: hidden; }
.preview-page::after { content: ""; position: absolute; top: 0; right: 0; width: 30px; height: 30px;
  background: linear-gradient(225deg, var(--bg) 50%, color-mix(in srgb, var(--line-strong) 55%, var(--card)) 50%); border-bottom-left-radius: 8px; box-shadow: -2px 2px 4px rgba(0,0,0,.08); }
.page-tab { position: absolute; top: 0; left: 22px; display: inline-flex; align-items: baseline; gap: 4px; padding: 5px 12px 6px; border-radius: 0 0 12px 12px;
  background: var(--leaf); color: #fff; box-shadow: 0 3px 0 var(--leaf-dark); font-weight: 800; line-height: 1; }
.page-tab b { font-size: 1.05rem; } .page-tab span { font-size: .75rem; opacity: .85; }
.preview-page .preview-text { font-family: var(--read-font); font-size: 1.12rem; line-height: 1.7; }

/* Me page: a treasure with no painting (a power made up in a story) sits on the same rounded,
   shadowed tile as the painted ones, with a soft glow behind its emoji, instead of floating bare. */
.treasure-grid .treasure-emoji { width: 96px; height: 96px; min-height: 0; border-radius: 14px; box-shadow: var(--shadow); font-size: 3.2rem;
  background: radial-gradient(circle at 50% 45%, #fffbe6 0 35%, #f6ecd2 75%); }
.treasure-grid .power .treasure-emoji, .treasure-grid .treasure-emoji:has(+ div .pill.power) { background: radial-gradient(circle at 50% 45%, #fbf6ff 0 35%, #ece0fa 75%); }

/* Teacher: a story that didn't work. A little torn book page (lines of text, a jagged bottom
   edge) with an autumn leaf drifting down past it, in the card's corner. */
.failed-card { position: relative; }
.failed-card > h2, .failed-card > p { padding-right: 96px; }
.torn-scene { position: absolute; top: 16px; right: 20px; width: 76px; height: 86px; pointer-events: none; }
.torn-page { position: absolute; left: 6px; top: 4px; width: 56px; height: 70px; padding: 12px 9px 0; display: grid; align-content: start; gap: 6px;
  background: #fffdf6; border: 1.5px solid #e2d6b8; border-bottom: 0; transform: rotate(-8deg); box-shadow: 0 4px 10px rgba(0,0,0,.12);
  clip-path: polygon(0 0, 100% 0, 100% 82%, 88% 90%, 74% 80%, 60% 92%, 46% 82%, 32% 94%, 18% 82%, 0 90%); }
.torn-page i { display: block; height: 4px; border-radius: 2px; background: #d9cfb6; }
.torn-page i.short { width: 60%; }
.torn-leaf { position: absolute; right: 0; top: 0; font-size: 1.5rem; animation: leaf-drift 3.2s ease-in-out infinite; }
@keyframes leaf-drift { 0% { transform: translate(0, -4px) rotate(-10deg); } 50% { transform: translate(-8px, 30px) rotate(25deg); } 100% { transform: translate(0, -4px) rotate(-10deg); } }
@media (prefers-reduced-motion: reduce) { .torn-leaf { animation: none; transform: translate(-4px, 26px) rotate(15deg); } }
@media (max-width: 520px) { .failed-card > p { padding-right: 0; } .torn-scene { transform: scale(.8); transform-origin: top right; } }
.stack.failed-card > .torn-scene + h2 { margin-top: 0; }
.torn-page { background: linear-gradient(180deg, #fff8e4, #f6e9c6); filter: drop-shadow(0 3px 5px rgba(120,90,30,.25)); }
.torn-page i { background: #cdb98a; }

/* Phone tidy-ups for choice grids and the Me page's last row:
   - a choice with exactly 3 options (He / She / Just my name) sits in one row of 3, not 2 + 1;
   - a 3-across picture grid whose last row has a single tile (7 art styles) centers that tile;
   - Me's bottom buttons: the big Done across the full width first, the other two side by side. */
@media (max-width: 520px) {
  .choices:not(.with-pics):not(.swatches):has(> .choice:nth-child(3):last-child) { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
  .choices:not(.with-pics):not(.swatches):has(> .choice:nth-child(3):last-child) > .choice { padding-left: 4px; padding-right: 4px; justify-content: flex-start; padding-top: 12px; }
  .choices.with-pics > .choice:last-child:nth-child(3n + 1) { grid-column: 2; }
  .me-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
  .me-actions > .btn { justify-content: center; text-align: center; margin: 0; }
  .me-actions > .btn.primary { grid-column: 1 / -1; order: -1; }
}
@media (max-width: 520px) { .me-actions { align-items: stretch; } .me-actions > .btn { align-self: stretch; display: inline-flex; align-items: center; line-height: 1.2; } }

/* A story's reader chips: the reader's hero face first, with a small mark pinned to it (a green
   ✓ once read to the end, a closed book while waiting). */
.badge.reader-chip { display: inline-flex; align-items: center; gap: 7px; padding: 3px 12px 3px 3px; font-size: .85rem; }
.reader-chip-face { position: relative; display: inline-grid; line-height: 0; }
.reader-chip-face .avatar { border: 2px solid var(--card); border-radius: 50%; }
.reader-chip-face .face-todo { width: 24px; height: 24px; font-size: .65rem; }
.reader-chip-face i { position: absolute; right: -5px; bottom: -4px; width: 14px; height: 14px; border-radius: 50%; display: grid; place-items: center;
  font-style: normal; font-size: .55rem; font-weight: 900; line-height: 1; background: var(--card); box-shadow: 0 0 0 1.5px var(--card); }
.badge.green .reader-chip-face i { background: #2f9e44; color: #fff; }

/* "What grade are you in?" on a phone: Kindergarten across the top as one wide tile (its K badge
   beside the word), then 1st-12th in four even rows of three, colored by school stage, so the
   whole list fits on screen with no lone tile at the end. */
@media (max-width: 520px) {
  .choices.small:has(> .grade-tile[data-value="0"]):has(> .grade-tile[data-value="12"]) { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
  .choices.small > .grade-tile[data-value="0"]:has(~ .grade-tile[data-value="12"]) { grid-column: 1 / -1; flex-direction: row; justify-content: center; gap: 12px; min-height: 0; padding-top: 8px; padding-bottom: 8px; }
  .choices.small:has(> .grade-tile[data-value="12"]) > .grade-tile { padding-left: 2px; padding-right: 2px; font-size: .82rem; }
  .choices.small:has(> .grade-tile[data-value="12"]) > .grade-tile .emoji { width: 36px; height: 36px; font-size: 1.1rem; }
}
@media (max-width: 520px) { .choices.small > .grade-tile[data-value="0"]:has(~ .grade-tile[data-value="12"]) { font-size: .95rem; } }

/* A class's tabs on a phone: a tidy panel of picture tiles (icon above a short label), four
   across then three filling the row, like the kids' Me page buttons, instead of a two-column
   list with Class epics left alone at the bottom. The open tab is a raised white tile. */
@media (max-width: 520px) {
  .tabs { display: flex; flex-wrap: wrap; gap: 4px; padding: 5px; border-radius: 20px; }
  .tabs button { flex: 1 1 calc(25% - 4px); min-width: 0; flex-direction: column; justify-content: center; gap: 3px; padding: 7px 2px 6px;
    text-align: center; font-size: .7rem; line-height: 1.15; border-radius: 14px; }
  .tabs button .tab-icon { font-size: 1.3rem; }
}

/* Color swatches on a phone: a set of 6 (skin tones) or 12 (favorite colors) sits six across,
   so they fill whole rows instead of five and a lone one left over. */
@media (max-width: 520px) {
  .choices.small.swatches:has(> .choice:nth-child(6):last-child),
  .choices.small.swatches:has(> .choice:nth-child(12):last-child) { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 10px 8px; }
  .choices.small.swatches:has(> .choice:nth-child(6):last-child) > .choice,
  .choices.small.swatches:has(> .choice:nth-child(12):last-child) > .choice { width: 100%; height: auto; aspect-ratio: 1; padding: 0; }
}

/* Add a student, on a phone: First name and the one-letter Last initial side by side (the initial
   a small box with its letter centered), their notes running full width beneath. */
@media (max-width: 520px) {
  .add-student-grid { grid-template-columns: minmax(0, 1fr) 92px; column-gap: 10px; row-gap: 4px; }
  .add-student-grid > .f-first, .add-student-grid > .f-initial { display: contents; }
  .add-student-grid > .f-first > span { grid-column: 1; grid-row: 1; }
  .add-student-grid > .f-first > input { grid-column: 1; grid-row: 2; }
  .add-student-grid > .f-first > small { grid-column: 1 / -1; grid-row: 3; }
  .add-student-grid > .f-initial > span { grid-column: 2; grid-row: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .add-student-grid > .f-initial > input { grid-column: 2; grid-row: 2; text-align: center; font-weight: 800; }
  .add-student-grid > .f-initial > small { grid-column: 1 / -1; grid-row: 4; margin-top: 0; }
  .add-student-grid > .f-first > span, .add-student-grid > .f-initial > span { display: block; margin-bottom: 0; font-weight: 700; }
  .add-student-grid > :not(.f-first):not(.f-initial) { grid-column: 1 / -1; margin-top: 12px; }
}
.add-student-grid > .f-initial > input { text-align: center; font-weight: 800; text-transform: uppercase; }

/* Bookshelf card badges stay neat one-line pills (a touch smaller on a phone), so a longer
   Spanish label like "Preguntas pendientes" doesn't fold into a lopsided block. */
.book-badges .badge { white-space: nowrap; max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
@media (max-width: 520px) { .book-badges .badge { font-size: .72rem; padding: 2px 8px; } }

/* "Next story days" on a phone: the label on its own line, the calendar tiles together in one
   row beneath it, so a longer label (Spanish) never pushes the last tile onto a line alone. */
@media (max-width: 520px) {
  .next-days { row-gap: 6px; }
  .next-days > .muted:first-child { flex: 0 0 100%; }
}

/* "Your story" recipe (hero + topic + goal): the three cards are always the same height, pictures
   lined up along the top and labels in a matching band beneath (up to two lines), so a long
   Spanish goal like "Resolver un misterio" doesn't make its card taller than the others. */
.pick-review.three { align-items: stretch; }
.pick-review.three .pick-review-plus { align-self: center; }
.pick-review.three .pick-review-part { justify-content: flex-start; }
.pick-review.three .pick-review-part > span:last-child { min-height: 2.5em; display: flex; align-items: center; justify-content: center; text-align: center;
  line-height: 1.2; overflow-wrap: anywhere; }
@media (max-width: 520px) { .pick-review.three .pick-review-part > span:last-child { font-size: .85rem; } }

/* Password boxes with a Show button (Account): the button sits inside the box at its right end,
   as on the sign-in page, so the box keeps its full width in any language. */
.pw-row { position: relative; display: block; }
.pw-row input { width: 100%; padding-right: 116px; }
.pw-row .btn { position: absolute; right: 6px; top: 50%; transform: translateY(-50%); min-height: 34px; }
.pw-row .btn:active { transform: translateY(-50%); }

/* Story questions: each question card has an unbroken top edge, with the numbered question as a
   heading inside it, instead of a heading sitting on the border (which left a stub of line beside
   a question long enough to wrap onto two lines). */
.question { padding-top: 12px; }
.question > legend { float: left; width: 100%; padding: 0; margin: 0 0 10px; }
.question > legend + * { clear: both; }

/* Classroom screen: a page without a picture fills the screen (the controls hide while idle) and
   its words sit in the middle, where the whole class can see them, not in a band at the top. */
.reader.presenter .page:not(.with-img):not(.cover):has(> .story-text) { display: flex; flex-direction: column; justify-content: center; min-height: calc(100vh - 32px); }
.reader.presenter .page:not(.with-img):not(.cover):has(> .story-text) > .story-text { max-width: 30em; margin-left: auto; margin-right: auto; }

/* Storybook on a tall screen (a tablet): the page reaches down to the page-turn controls instead
   of stopping at 60% of the screen and leaving an empty gap above them. */
.reader:not(.presenter) .page:not(.cover) { min-height: max(60vh, calc(100dvh - 300px)); }

/* A class's tabs on a tablet: one even row of seven picture tiles (icon above the label), instead
   of five pills and then Stories and Class epics left on a second line. */
@media (min-width: 521px) and (max-width: 1090px) {
  .tabs { display: flex; flex-wrap: nowrap; width: 100%; gap: 4px; padding: 5px; border-radius: 20px; }
  .tabs button { flex: 1 1 0; min-width: 0; flex-direction: column; justify-content: center; gap: 4px; padding: 8px 2px 7px;
    text-align: center; font-size: .78rem; line-height: 1.15; border-radius: 14px; }
  .tabs button .tab-icon { font-size: 1.4rem; }
}

/* Wider screens too (tablet, laptop): "What grade are you in?" keeps Kindergarten as one wide tile
   on top with 1st-12th in even rows of three, and the color palettes fill whole rows (10 hair
   colors as two rows of five, 6 skin tones and 12 favorite colors six across), never a straggler. */
@media (min-width: 521px) {
  .choices.small:has(> .grade-tile[data-value="0"]):has(> .grade-tile[data-value="12"]) { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .choices.small > .grade-tile[data-value="0"]:has(~ .grade-tile[data-value="12"]) { grid-column: 1 / -1; flex-direction: row; justify-content: center; gap: 12px; min-height: 0; padding-top: 8px; padding-bottom: 8px; }
  .choices.swatches:has(> .choice:nth-child(10):last-child) { display: grid; grid-template-columns: repeat(5, max-content); }
  .choices.swatches:has(> .choice:nth-child(6):last-child),
  .choices.swatches:has(> .choice:nth-child(12):last-child) { display: grid; grid-template-columns: repeat(6, max-content); }
}
@media (min-width: 521px) { .choices.with-pics:has(> .choice:nth-child(10):last-child) { grid-template-columns: repeat(5, minmax(0, 1fr)); } }

/* Admin's four number cards: always even rows (two by two on a tablet, four across on a wide
   screen), never three with Readers left alone underneath. */
.stat-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (min-width: 1091px) { .stat-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (max-width: 520px) { .stat-grid { grid-template-columns: minmax(0, 1fr); } }
.stat-grid + * { margin-top: 12px !important; }

/* The cover on a short wide screen (a tablet held sideways, a laptop): the picture leaves room for
   everything now under it (the title, the stars' faces, "Starring…", the gift hint and how-to tips),
   so they show above the page controls instead of hiding under them. */
@media (min-width: 700px) {
  .reader:not(.presenter) .cover .story-img { height: clamp(180px, calc(100dvh - 610px), 540px); }
}

/* Seven picture tiles (the art styles) on a tablet or laptop: a balanced 4 + 3 with the short row
   centered, instead of six across and Comic book alone on its own line. */
@media (min-width: 521px) {
  .choices.with-pics:has(> .choice:nth-child(7):last-child) { display: flex; flex-wrap: wrap; justify-content: center; }
  .choices.with-pics:has(> .choice:nth-child(7):last-child) > .choice { flex: 0 0 calc((100% - 3 * 12px) / 4); max-width: 150px; }
  .choices.small.with-pics:has(> .choice:nth-child(7):last-child) > .choice { flex-basis: calc((100% - 3 * 10px) / 4); }
}

/* Reading level with every grade on offer (K-12): Kindergarten as one wide tile on top (picture,
   name and meter in a row), then 1st-12th fill even rows (two across on a phone, three wider),
   instead of 12th grade left alone at the bottom. */
.choices:has(> .choice[class*="lvl-"][data-value="0"]):has(> .choice[class*="lvl-"][data-value="12"]) > .choice[data-value="0"] {
  grid-column: 1 / -1; flex-direction: row; flex-wrap: wrap; justify-content: center; align-items: center; column-gap: 12px; min-height: 0; }
@media (min-width: 521px) {
  .choices:has(> .choice[class*="lvl-"][data-value="0"]):has(> .choice[class*="lvl-"][data-value="12"]) { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.choices:has(> .choice[class*="lvl-"][data-value="12"]) > .choice[class*="lvl-"][data-value="0"] > .choice-meter { flex: 0 0 120px; width: 120px; margin: 0 0 0 6px; }
.choices:has(> .choice[class*="lvl-"][data-value="12"]) > .choice[class*="lvl-"][data-value="0"] { flex-wrap: nowrap !important; justify-content: center !important; }
@media (max-width: 520px) { .choices:has(> .choice[class*="lvl-"][data-value="12"]) > .choice[class*="lvl-"][data-value="0"] { column-gap: 8px; padding-left: 8px; padding-right: 8px; } .choices:has(> .choice[class*="lvl-"][data-value="12"]) > .choice[class*="lvl-"][data-value="0"] > .choice-meter { flex: 0 1 60px; min-width: 30px; } }

/* Focus period form: the name across the top, then From and To side by side, so the date range
   reads as one pair instead of To dropping alone onto a line of its own. */
@media (min-width: 521px) {
  .form-grid.name-dates { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .form-grid.name-dates > :first-child { grid-column: 1 / -1; }
}
/* Its section headings (Topics / Goals / Skills) sit right on top of their one-line hint. */
.focus-fold form h4 { margin: 22px 0 0; font-size: 1.05rem; }
.focus-fold form h4 + p.muted { margin-top: 2px; }

/* The story picker's big picture grids (26 topics, 16 goals): whatever's left over in the last row
   sits centered under the others (three across on a phone, four on a tablet, five on a laptop),
   instead of one or two tiles stranded at the left. */
.choices.with-pics:not(.small):has(> .choice:nth-child(13)) { display: flex; flex-wrap: wrap; justify-content: center; gap: 12px; }
.choices.with-pics:not(.small):has(> .choice:nth-child(13)) > .choice { flex: 0 0 calc((100% - 3 * 12px) / 4); min-width: 0; }
@media (min-width: 1000px) { .choices.with-pics:not(.small):has(> .choice:nth-child(13)) > .choice { flex-basis: calc((100% - 4 * 12px) / 5); } }
@media (max-width: 520px) {
  .choices.with-pics:not(.small):has(> .choice:nth-child(13)) { gap: 8px; }
  .choices.with-pics:not(.small):has(> .choice:nth-child(13)) > .choice { flex-basis: calc((100% - 2 * 8px) / 3); }
}

/* The focus period form's topic and goal pickers (26 and 16 small picture tiles): the leftover
   tiles in the last row sit centered under the rows above (three across on a phone, six on a
   tablet, eight on a laptop), as in the kids' picker, instead of stranded at the left. */
.choices.small.with-pics:has(> .choice:nth-child(13)) { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; }
.choices.small.with-pics:has(> .choice:nth-child(13)) > .choice { flex: 0 0 calc((100% - 5 * 10px) / 6); min-width: 0; }
@media (min-width: 1000px) { .choices.small.with-pics:has(> .choice:nth-child(13)) > .choice { flex-basis: calc((100% - 7 * 10px) / 8); } }
@media (max-width: 520px) {
  .choices.small.with-pics:has(> .choice:nth-child(13)) { gap: 8px; }
  .choices.small.with-pics:has(> .choice:nth-child(13)) > .choice { flex-basis: calc((100% - 2 * 8px) / 3); }
}
/* The reading-skill picker too (focus periods, class epics): its last row centered. */
.choices.small:has(> .skill-tile) { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; }
.choices.small:has(> .skill-tile) > .choice { flex: 0 0 calc((100% - 3 * 10px) / 4); min-width: 0; }
@media (min-width: 1000px) { .choices.small:has(> .skill-tile) > .choice { flex-basis: calc((100% - 4 * 10px) / 5); } }
@media (max-width: 520px) { .choices.small:has(> .skill-tile) > .choice { flex-basis: calc((100% - 10px) / 2); } }

/* Making a hero: each look part's heading shows whether it's picked yet. A soft sun dot that
   gently pulses while it's waiting, a green ✓ that pops in once it has a choice. */
h3.look-head { display: flex; align-items: center; gap: 8px; }
h3.look-head::after { content: ""; width: 12px; height: 12px; border-radius: 50%; background: var(--sun); box-shadow: 0 0 0 3px color-mix(in srgb, var(--sun) 30%, transparent);
  animation: look-wait 1.6s ease-in-out infinite; }
h3.look-head.picked::after { content: "✓"; width: 20px; height: 20px; display: grid; place-items: center; font-size: .72rem; font-weight: 900; color: #fff;
  background: var(--leaf); box-shadow: none; animation: look-done .35s cubic-bezier(.3, 1.6, .5, 1); }
@keyframes look-wait { 50% { transform: scale(1.25); } }
@keyframes look-done { from { transform: scale(.3); } }
@media (prefers-reduced-motion: reduce) { h3.look-head::after { animation: none !important; } }

/* Class epic goal: a slim bar under the box fills as the goal is written (amber near the limit). */
.goal-bar { height: 6px; margin-top: 6px; border-radius: 999px; background: var(--line); overflow: hidden; }
.goal-bar > span { display: block; height: 100%; width: var(--p, 0%); border-radius: 999px; background: linear-gradient(90deg, #8fd887, var(--leaf)); transition: width .2s ease, background .2s; }
.goal-bar.near > span { background: linear-gradient(90deg, #f6c94a, #e0a200); }
@media (prefers-reduced-motion: reduce) { .goal-bar > span { transition: none; } }
/* …and when "Still to pick" sends the kid to it, that part's heading calls out: its dot swells
   with a sunny ring three times and the title glows. */
h3.look-head { scroll-margin-top: 160px; }
h3.look-head.look-call { animation: look-call-text 1.8s ease-out; border-radius: 10px; }
h3.look-head.look-call::after { animation: look-call 0.6s ease-in-out 3; }
@keyframes look-call { 50% { transform: scale(1.8); box-shadow: 0 0 0 8px color-mix(in srgb, var(--sun) 35%, transparent); } }
@keyframes look-call-text { 0%, 40% { background: color-mix(in srgb, var(--sun) 35%, transparent); box-shadow: 0 0 0 6px color-mix(in srgb, var(--sun) 35%, transparent); } }
@media (prefers-reduced-motion: reduce) { h3.look-head.look-call { animation: none; background: color-mix(in srgb, var(--sun) 30%, transparent); } }
/* The same red-and-shake for any empty required box (teacher forms), selects and text areas too. */
select.login-wrong, textarea.login-wrong { border-color: #d64545 !important; box-shadow: 0 0 0 3px color-mix(in srgb, #d64545 22%, transparent) !important; }
textarea.link-shake, select.link-shake { animation: pin-shake .45s ease-in-out; }
@media (prefers-reduced-motion: reduce) { textarea.link-shake, select.link-shake { animation: none; } }
/* A step's tiles with nothing picked yet, when "Next" is pressed too soon: a sunny glow around them. */
.choices.choices-call { border-radius: 18px; animation: choices-call 1.8s ease-out; }
@keyframes choices-call { 0%, 45% { box-shadow: 0 0 0 6px color-mix(in srgb, var(--sun) 55%, transparent); background: color-mix(in srgb, var(--sun) 18%, transparent); } }
@media (prefers-reduced-motion: reduce) { .choices.choices-call { animation: none; box-shadow: 0 0 0 6px color-mix(in srgb, var(--sun) 55%, transparent); } }
.day-bar-cell.sky .day-bar > span { background: #4a90d9; }
/* "Last page! Tap ▶ for The End": the ▶ drawn as the little green page button, as on the cover. */
.last-page-hint .mini-turn { display: inline-grid; place-items: center; width: 1.7em; height: 1.7em; margin: 0 .15em; vertical-align: -.1em; border-radius: 50%;
  background: var(--leaf); color: #fff; font-size: .85em; padding-left: .12em; box-shadow: 0 2px 0 var(--leaf-dark); }
.last-page-hint { line-height: 1.9; }

/* Classroom screen tip: the keys it names (← → and the space bar) drawn as keycaps, light on its
   dark bubble, and "Read to me" as a tiny copy of that button. */
.present-tip { line-height: 2; }
.present-tip .keycap { display: inline-grid; place-items: center; min-width: 1.9em; height: 1.7em; padding: 0 .45em; margin: 0 .12em; vertical-align: .05em;
  border: 1.5px solid rgba(255,255,255,.55); border-radius: 7px; background: rgba(255,255,255,.14); box-shadow: 0 3px 0 rgba(255,255,255,.35);
  font: inherit; font-size: .85em; font-weight: 900; line-height: 1; color: inherit; }
.present-tip .keycap.space { min-width: 5.5em; font-size: .78em; }
.present-tip .mini-btn { display: inline-block; padding: 0 .65em; margin: 0 .1em; line-height: 1.7; border-radius: 999px; white-space: nowrap;
  border: 1.5px solid rgba(255,255,255,.55); background: rgba(255,255,255,.14); font-size: .9em; }

/* The reading path's 🏆: room on its right so, glowing at The End, it isn't cut off at a phone's
   edge (the path keeps its full width; the trophy just sits a little in from the side). */
.trail { padding-right: 14px; }
.trail .trail-goal { flex: none; }

/* Word hunt progress: one stamp per word, big enough to read at a glance. A faint 🔎 in a dashed
   circle while that word is still to find; a green ✓ that pops in once it's found. */
.hunt-dots { gap: 8px; margin: 4px 0 12px; }
.hunt-dots > span { width: 26px; height: 26px; display: grid; place-items: center; border: 2px dashed color-mix(in srgb, var(--leaf) 70%, transparent); background: var(--card); }
.hunt-dots > span::after { content: "🔎"; font-size: .72rem; opacity: .45; filter: grayscale(.4); }
.hunt-dots > span.got { border: 2px solid var(--leaf-dark); background: var(--leaf); box-shadow: 0 2px 0 var(--leaf-dark), 0 0 0 3px var(--leaf-soft); animation: hunt-stamp .4s cubic-bezier(.3, 1.6, .5, 1); }
.hunt-dots > span.got::after { content: "✓"; font-size: .85rem; font-weight: 900; color: #fff; opacity: 1; filter: none; }
@keyframes hunt-stamp { from { transform: scale(.4) rotate(-20deg); } }
@media (prefers-reduced-motion: reduce) { .hunt-dots > span.got { animation: none; } }

/* "Today's story" while the story writer is resting: a closed book napping, z's drifting up. */
.resting-scene { position: relative; display: flex; justify-content: center; align-items: flex-end; height: 64px; margin-top: 4px; }
.resting-book { font-size: 2.6rem; line-height: 1; filter: saturate(.7); transform: rotate(-8deg); }
.resting-scene i { position: absolute; left: calc(50% + 18px); bottom: 34px; font-style: normal; font-weight: 900; color: rgba(255,255,255,.9);
  animation: zzz 3s ease-in infinite; opacity: 0; }
.resting-scene i:nth-of-type(1) { font-size: .8rem; }
.resting-scene i:nth-of-type(2) { font-size: 1rem; animation-delay: 1s; }
.resting-scene i:nth-of-type(3) { font-size: 1.25rem; animation-delay: 2s; }
@keyframes zzz { 0% { transform: translate(0, 0); opacity: 0; } 20% { opacity: 1; } 100% { transform: translate(22px, -30px) rotate(10deg); opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .resting-scene i { animation: none; opacity: .9; }
  .resting-scene i:nth-of-type(2) { transform: translate(10px, -12px); } .resting-scene i:nth-of-type(3) { transform: translate(22px, -26px); }
}

/* Story-day timeline: a little notch at each new month and a 🏁 at its end. */
.rule-line { margin-right: 22px; }
.rule-notch { position: absolute; top: -3px; bottom: -3px; width: 2px; margin-left: -1px; border-radius: 2px; background: var(--card); box-shadow: 0 0 0 1px color-mix(in srgb, var(--leaf) 35%, transparent); }
.rule-flag { position: absolute; left: 100%; top: 50%; transform: translate(4px, -55%); font-size: .9rem; line-height: 1; }
.rule-item.muted .rule-flag { filter: grayscale(1); opacity: .6; }
.today-card.resting .resting-note { margin: 0; text-align: center; font-weight: 700; color: rgba(255,255,255,.92); font-size: .95rem; }

/* A student's own reading range, stacked (lowest above highest): instead of hiding the dash
   between them, a small round ↓ badge sits on the seam, so the two boxes read as "from … to". */
.cell-range .range-pair { position: relative; }
@media (max-width: 1180px) {
  .cell-range .range-pair .range-dash { display: grid !important; place-items: center; position: absolute; left: 50%; top: 50%; width: 20px; height: 20px;
    margin: -10px 0 0 -10px; z-index: 1; border-radius: 50%; font-size: 0; background: var(--leaf-soft); box-shadow: 0 0 0 2px var(--card); }
  .cell-range .range-pair .range-dash::after { content: "↓"; font-size: .75rem; font-weight: 900; color: var(--leaf-dark); line-height: 1; }
}

/* Reading medals: centered on the shelf, so a short last row (on a phone, the 50 and 100 medals)
   sits in the middle under the others instead of at the left. */
.badge-shelf { justify-content: center; }

/* Story picker steps: a finished step gets a small green ✓ pinned to its corner (it can still be
   tapped to change it), so done / now / still to come read at a glance. */
.pick-steps li.done:not(.now) button::after { content: "✓"; position: absolute; top: -7px; right: -7px; width: 22px; height: 22px; border-radius: 50%;
  display: grid; place-items: center; font-size: .75rem; font-weight: 900; color: #fff; background: var(--leaf); box-shadow: 0 0 0 2px var(--card);
  animation: look-done .35s cubic-bezier(.3, 1.6, .5, 1); }
.pick-steps li.done:not(.now) button { position: relative; overflow: visible; }
@media (prefers-reduced-motion: reduce) { .pick-steps li.done button::after { animation: none; } }

/* Add a student, wider screens: the Last initial box is sized for one letter (its label and hint
   keep the column), so it's plain at a glance that only an initial goes there. */
@media (min-width: 521px) { .add-student-grid > .f-initial > input { width: 84px; } }

/* Picture tiles (topics, goals, picture styles, hair and outfits): every name sits in the same
   two-line band, so a row of one-line names is as tall as a row with two-line ones and the
   tiles line up in an even grid. */
.choices.with-pics .choice .label { min-height: 2.4em; display: flex; align-items: center; justify-content: center; line-height: 1.2; }

/* Special days list: a team-up day's size as a row of little classmates beside its name. */
.team-mini { display: inline-flex; align-items: flex-end; gap: 2px; margin-left: 10px; vertical-align: -3px; }
.team-mini .team-seat { width: 12px; height: 16px; animation: none; }
.team-mini .team-seat::before { left: 3px; width: 6px; height: 6px; }
.team-mini .team-seat::after { width: 12px; height: 9px; border-radius: 6px 6px 2px 2px; }

/* Home greeting: "See my treasures" as a small backpack pill that looks tappable (the whole card
   opens Me); its arrow nudges along when the card is pointed at or pressed. */
.me-card .see-more { align-self: flex-start; display: inline-flex; align-items: center; gap: 6px; padding: 4px 12px 4px 8px; border-radius: 999px;
  background: var(--card); border: 2px solid color-mix(in srgb, var(--leaf) 45%, var(--line)); box-shadow: 0 2px 0 color-mix(in srgb, var(--leaf) 35%, var(--line)); font-size: .88rem; }
.see-more-arrow { font-size: 1.1rem; line-height: 1; transition: transform .2s ease; }
.me-card:hover .see-more-arrow, .me-card:active .see-more-arrow { transform: translateX(4px); }
@media (prefers-reduced-motion: reduce) { .see-more-arrow { transition: none; } }
.me-card .see-more { width: fit-content; }

/* School page: the school's badge beside its name. */
.school-title { display: flex; align-items: center; gap: 4px; margin: 0; }
.school-title .initials { width: 44px; height: 44px; border-radius: 14px; font-size: 1rem; margin-right: 12px; }
.stat-card .mini-meter { width: 100%; max-width: 160px; margin-top: 6px; }
/* The day-by-day table on a phone: dates on one line and shorter bars, so all four columns fit. */
@media (max-width: 520px) { .day-bar { width: 44px; } .day-bar-cell { gap: 6px; } table td:first-child:has(+ td .day-bar-cell) { white-space: nowrap; } }
/* …and on a wide screen too: the 7 picture styles stay 4 + 3 (the grid is only as wide as four tiles). */
@media (min-width: 521px) {
  .choices.with-pics:not(.small):has(> .choice:nth-child(7):last-child) { max-width: calc(4 * 150px + 3 * 12px); margin-left: auto; margin-right: auto; }
  .choices.small.with-pics:has(> .choice:nth-child(7):last-child) { max-width: calc(4 * 150px + 3 * 10px); margin-left: auto; margin-right: auto; }
}

/* Class tiles for an admin or school admin: the teacher's colored initials before their name. */
.tile-teacher { display: flex; align-items: center; flex-wrap: wrap; row-gap: 2px; }
.tile-teacher .initials { width: 24px; height: 24px; font-size: .6rem; margin-right: 7px; border-width: 1.5px; }
.tile-teacher > span:nth-child(2) { color: var(--ink); font-weight: 700; }
.tile-teacher .tile-school { white-space: pre; }
/* On a narrow tile the school drops off rather than wrapping onto its own line with a stray "·". */
.tile-teacher { flex-wrap: nowrap; min-width: 0; }
.tile-teacher .tile-school { overflow: hidden; text-overflow: ellipsis; white-space: pre; min-width: 0; }
.tile-teacher > span:nth-child(2) { white-space: nowrap; flex: none; } .tile-teacher .initials { flex: none; } .tile-teacher .tile-school { flex: 1 1 0; }
/* The empty spots stand full height on the shelf beside the real books (same top and bottom), so
   the row reads as one tidy shelf with room for more, not boxes sunk lower than the book. */
.ghost-shelf-book { margin-top: 0; align-self: stretch; }

/* "Who's reading?": a reader with no hero saved on this device shows their first letter, big, on
   their own color (instead of the same green book for everyone); an odd last card sits centered. */
.who-letter { width: 100%; height: 100%; border-radius: 50%; display: grid; place-items: center; font-family: var(--ui-font); font-weight: 900; font-size: 2.3rem; line-height: 1;
  color: hsl(var(--hue) 45% 30%); background: hsl(var(--hue) 70% 88%); box-shadow: inset 0 0 0 3px hsl(var(--hue) 50% 76%); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .who-letter { color: hsl(var(--hue) 70% 85%); background: hsl(var(--hue) 30% 26%); box-shadow: inset 0 0 0 3px hsl(var(--hue) 35% 40%); } }
:root[data-theme="dark"] .who-letter { color: hsl(var(--hue) 70% 85%); background: hsl(var(--hue) 30% 26%); box-shadow: inset 0 0 0 3px hsl(var(--hue) 35% 40%); }
.who-grid { justify-content: center; }
@media (max-width: 520px) { .who-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } .who-grid > .who-card:last-child:nth-child(odd) { grid-column: 1 / -1; justify-self: center; width: calc(50% - 6px); } }
@media (min-width: 521px) { .who-grid { grid-template-columns: repeat(auto-fit, minmax(118px, 132px)); } }

/* Admin's Schools list: each school's school admins as a little overlapping stack of initials. */
.school-admins { position: relative; display: inline-flex; align-items: center; margin-left: 12px; padding-right: 10px; }
.school-admins .initials { width: 26px; height: 26px; font-size: .6rem; margin-right: -8px; border-width: 1.5px; box-shadow: 0 0 0 2px var(--card); }
.school-admins i { position: absolute; right: -6px; bottom: -6px; font-style: normal; font-size: .8rem; }

/* Kid top bar: the Me button lit, with a dot under it, while you're on your Me page. */
.me-btn[aria-current="page"] { position: relative; background: var(--leaf-soft); border-color: var(--leaf); color: var(--leaf-dark); box-shadow: 0 3px 0 var(--leaf); }
.me-btn[aria-current="page"]::after { content: ""; position: absolute; left: 50%; bottom: -12px; width: 6px; height: 6px; margin-left: -3px; border-radius: 50%; background: var(--leaf); }

/* Classroom screen cover: fills the screen with everything centered, the picture in the same white
   storybook frame as on the kids' cover, and "Starring …" big enough to read from the back row. */
.reader.presenter .page.cover { display: flex; flex-direction: column; justify-content: center; align-items: center; min-height: calc(100vh - 32px); }
.reader.presenter .cover .story-img { padding: 8px; background: #fff; border-radius: 18px; box-shadow: 0 14px 30px -14px rgba(40, 60, 30, .55); }
.reader.presenter .cover .starring { font-size: clamp(1.2rem, 2.2vw, 1.9rem); font-weight: 800; color: var(--leaf-dark); margin-top: 6px; }
.reader.presenter .cover .cover-cast .avatar { width: clamp(64px, 7vw, 96px) !important; height: clamp(64px, 7vw, 96px) !important; }

/* Treasures on a phone (two across): an odd last treasure sits centered under the others. */
@media (max-width: 520px) {
  .treasure-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .treasure-grid > .treasure:last-child:nth-child(odd) { grid-column: 1 / -1; justify-self: center; width: calc(50% - 5px); }
}

/* Class page header: the reading range chip ends with K-12 as tiny dots, the range lit in its
   school-stage colors and the class's own grade with a small mark beneath. */
.range-dots { display: inline-flex; align-items: center; gap: 2px; margin-left: 8px; }
.range-dots i { position: relative; width: 7px; height: 7px; border-radius: 50%; background: var(--line-strong); opacity: .55; --band: #3f8f3a; }
.range-dots i.band-mid { --band: #e0a200; } .range-dots i.band-high { --band: #4a90d9; }
.range-dots i.in { background: var(--band); opacity: 1; }
.range-dots i.here::after { content: ""; position: absolute; left: 50%; top: 10px; width: 3px; height: 3px; margin-left: -1.5px; border-radius: 50%; background: var(--ink); }

/* "Get your class ready" on a phone: each step's button sits under its words (lined up with the
   text, clear of the number column), and the dotted path runs from each number down to the next. */
@media (max-width: 640px) {
  .setup-path li > .btn { margin-left: 42px; }
  .setup-path li:not(:last-child)::before { top: 40px; height: auto; bottom: -8px; }
}

/* "Save your link": the link as a little browser address bar. */
.link-bar { display: flex; align-items: flex-start; gap: 8px; margin: 0; padding: 8px 14px; border-radius: 999px; text-align: left;
  background: var(--card); border: 2px solid var(--line-strong); box-shadow: inset 0 2px 4px rgba(0,0,0,.06); }
.link-bar-lock { flex: none; font-size: .85rem; line-height: 1.5; }
.link-bar-text { min-width: 0; overflow-wrap: anywhere; font-size: .85rem; line-height: 1.5; color: var(--muted);
  font-family: ui-monospace, SFMono-Regular, Consolas, monospace; }
.link-bar-text b { color: var(--ink); font-weight: 700; }
@media (max-width: 520px) { .link-bar { border-radius: 18px; } }
@media print { .link-bar { border-radius: 10px; box-shadow: none; } }

/* Teacher top bar: who's signed in as a small chip (colored initials, name, then school on wider
   screens), instead of a gray line that wrapped onto its own row on a phone. */
#who { display: flex; min-width: 0; }
.who-chip { display: inline-flex; align-items: center; gap: 6px; min-width: 0; max-width: 100%; padding: 3px 12px 3px 3px; border-radius: 999px; text-decoration: none;
  color: var(--ink); background: var(--card); border: 1.5px solid var(--line); font-size: .85rem; font-weight: 700; transition: border-color .15s; }
.who-chip:hover { border-color: var(--leaf); }
.who-chip .initials { width: 26px; height: 26px; font-size: .62rem; margin: 0; border-width: 1.5px; flex: none; }
.who-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.who-school { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--muted); font-weight: 600; }
.who-school::before { content: "·"; margin-right: 6px; }
@media (max-width: 900px) { .who-school { display: none; } }
@media (max-width: 520px) { .who-name { display: none; } .who-chip { padding-right: 3px; } }

/* Me page: "Your changes save by themselves" with a little cloud (not a floppy disk) that turns
   into a green ✓ for a moment each time something saves. */
.autosave-note { display: flex; align-items: center; gap: 6px; }
.autosave-icon { flex: none; width: 24px; height: 24px; border-radius: 50%; display: grid; place-items: center; font-size: .85rem; background: var(--card-2); }
.autosave-icon::before { content: "☁️"; }
.autosave-note.just-saved { color: var(--leaf-dark); }
.autosave-note.just-saved .autosave-icon { background: var(--leaf); animation: look-done .35s cubic-bezier(.3, 1.6, .5, 1); }
.autosave-note.just-saved .autosave-icon::before { content: "✓"; color: #fff; font-weight: 900; }
@media (prefers-reduced-motion: reduce) { .autosave-note.just-saved .autosave-icon { animation: none; } }
.autosave-note:not(.just-saved) .autosave-icon { background: #8cc4f0; box-shadow: inset 0 0 0 1.5px #5aa3dc; }

/* A story without a title (didn't work / still writing): its topic in quiet italics in the title's
   place, over a faded, grayer picture. */
.story-cell.untitled .story-thumb { opacity: .55; filter: grayscale(.6); }
.untitled-title { font-style: italic; color: var(--muted); font-weight: 600; }

/* Storybook page number as a little page tab ("1 / 3", the number big), narrower than
   "Page 1 of 3", so on a phone Read to me fits on the same row as the arrows. */
.reader-count.as-tab { min-width: 0; display: inline-flex; align-items: baseline; gap: 4px; padding: 4px 12px 5px; border-radius: 12px;
  background: var(--card); border: 2px solid var(--line); color: var(--muted); }
.reader-count.as-tab b { font-size: 1.15rem; color: var(--leaf-dark); font-weight: 900; }
.reader-count.as-tab span { font-size: .8rem; }

/* Staff tables: a person's classes as small colored class badges, each a link to its class. */
.class-badges { display: inline-flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.class-badges a { line-height: 0; text-decoration: none; transition: transform .15s; }
.class-badges a:hover { transform: translateY(-2px); }
.class-badges .initials { width: 28px; height: 28px; border-radius: 9px; font-size: .66rem; margin: 0; }

/* Language tiles: only the chosen language's speech bubble is green (it pops when picked); the
   others say hello in soft gray, so which language is on reads at a glance, not just by the ✓. */
.choice.lang-tile:not(.on) .emoji { color: var(--ink); background: var(--card-2); box-shadow: 0 2px 0 var(--line-strong), inset 0 0 0 1.5px var(--line-strong); }
.choice.lang-tile:not(.on) .emoji::after { background: var(--line-strong); }
.choice.lang-tile:not(.on):hover .emoji { background: var(--leaf-soft); }
.choice.lang-tile.on .emoji { animation: look-done .35s cubic-bezier(.3, 1.6, .5, 1); }
@media (prefers-reduced-motion: reduce) { .choice.lang-tile.on .emoji { animation: none; } }

/* "Waiting for you" cards: the little cover is tappable too (it lifts when pointed at), and its
   ❓ / 📖 sticker gives a couple of gentle nudges to catch the eye, then rests. */
.unread-card .mini-cover { cursor: pointer; transition: transform .2s cubic-bezier(.3, 1.6, .5, 1); }
.unread-card .mini-cover:hover { transform: translateY(-3px) rotate(2deg); }
.unread-card .mini-cover-sticker { animation: sticker-nudge 1.1s ease-in-out .6s 2; }
@keyframes sticker-nudge { 0%, 100% { transform: rotate(0) scale(1); } 30% { transform: rotate(-14deg) scale(1.15); } 60% { transform: rotate(10deg) scale(1.1); } }
@media (prefers-reduced-motion: reduce) { .unread-card .mini-cover-sticker { animation: none; } .unread-card .mini-cover { transition: none; } }

/* Making a reader: the step dots become a little path of pictures. Each step's picture waits
   faintly in a circle; done steps turn into a green ✓; the current one sits big in its green pill. */
.steps.step-pics { gap: 6px; }
.steps.step-pics span { width: 26px; height: 26px; display: grid; place-items: center; font-size: .75rem; line-height: 1; color: #fff; font-weight: 900; }
.steps.step-pics span:not(.on) { filter: grayscale(.8); opacity: .6; }
.steps.step-pics span.now { width: 44px; height: 30px; font-size: 1rem; background: var(--leaf-soft); border-color: var(--leaf); }
@media (max-width: 360px) { .steps.step-pics span { width: 22px; height: 22px; font-size: .65rem; } }
.stat-card .stat-ring { display: flex; align-items: center; gap: 10px; margin-top: 6px; }
/* Glasses try-on: just two tiles, side by side and no wider than two hair-style tiles. */
.choices.small.with-pics:has(> .choice:nth-child(2):last-child) { grid-template-columns: repeat(2, minmax(0, 150px)); }

/* The End's "See all my treasures": the same little backpack pill as on the home greeting. */
.award-more.see-more { display: inline-flex; align-items: center; gap: 6px; width: fit-content; margin: 4px auto 0; padding: 4px 12px 4px 8px; border-radius: 999px;
  text-decoration: none; font-weight: 800; font-size: .9rem; color: var(--leaf-dark); background: var(--card);
  border: 2px solid color-mix(in srgb, var(--leaf) 45%, var(--line)); box-shadow: 0 2px 0 color-mix(in srgb, var(--leaf) 35%, var(--line)); }
.award-more.see-more:hover .see-more-arrow { transform: translateX(4px); }

/* A class's Stories tab: kind filter chips. Each is a kind pill made tappable; the picked one is
   raised with a ring, the others quieter. */
.kind-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.kind-chip { font: inherit; cursor: pointer; border: 2px solid transparent; transition: transform .1s, opacity .15s; }
.kind-chip:not(.kind-pill) { padding: 3px 12px; border-radius: 999px; font-size: .82rem; font-weight: 800; color: var(--muted); background: var(--card-2); border-color: var(--line); }
.kind-chip:not(.on) { opacity: .6; }
.kind-chip:hover { opacity: 1; transform: translateY(-1px); }
.kind-chip.on { opacity: 1; border-color: currentColor; box-shadow: 0 2px 0 color-mix(in srgb, currentColor 35%, transparent); }
.kind-chip:not(.kind-pill).on { color: var(--leaf-dark); border-color: var(--leaf); background: var(--leaf-soft); }
.kind-chip.kind-pill { font-size: .82rem; font-weight: 800; padding: 3px 12px; }

/* Reading level with all of K-12 on a phone: three across and compact (smaller picture, slimmer
   tile), so the whole ladder and "Write my story!" come into view with far less scrolling. */
@media (max-width: 520px) {
  .choices:has(> .choice[class*="lvl-"][data-value="12"]) { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; }
  .choices:has(> .choice[class*="lvl-"][data-value="12"]) > .choice:not([data-value="0"]) { min-height: 0; padding: 6px 4px 8px; gap: 2px; font-size: .78rem; }
  .choices:has(> .choice[class*="lvl-"][data-value="12"]) > .choice:not([data-value="0"]) .emoji { font-size: 1.3rem; }
  .choices:has(> .choice[class*="lvl-"][data-value="12"]) > .choice .sub { font-size: .66rem; }
  .choices:has(> .choice[class*="lvl-"][data-value="12"]) > .choice:not([data-value="0"]) .choice-meter { width: 80%; margin-top: 3px; }
}

/* Badge track: the next star to earn glows softly sunny (a gentle pulse), so "read one more" has a
   place to land, not just a row of identical empty circles. */
.track-dot.up-next { border: 2px solid #e0a200; border-style: dashed; background: color-mix(in srgb, var(--sun) 25%, var(--card)); animation: next-glow 2s ease-in-out infinite; }
@keyframes next-glow { 50% { box-shadow: 0 0 0 5px color-mix(in srgb, var(--sun) 30%, transparent); } }
@media (prefers-reduced-motion: reduce) { .track-dot.up-next { animation: none; box-shadow: 0 0 0 3px color-mix(in srgb, var(--sun) 30%, transparent); } }

/* Progress table: a student's treasure count as a little backpack chip (a dash for none). */
.items-chip { display: inline-flex; align-items: center; gap: 5px; padding: 2px 10px 2px 6px; border-radius: 999px; font-weight: 800; font-size: .85rem;
  background: color-mix(in srgb, var(--sun) 20%, var(--card)); border: 1.5px solid color-mix(in srgb, var(--sun) 55%, var(--line)); }

/* Me page treasure cards: "item" / "power" as a tiny tag with its picture (🎒 / ✨), the power one
   in its lilac and a little sparkle-bright, so powers and items read apart at a glance. */
.treasure-grid .pill.kind-tag { padding: 1px 9px; font-size: .75rem; font-weight: 800; text-transform: capitalize; }
.treasure-grid .pill.kind-tag.power { background: #ece0fa; color: #5b3fa6; box-shadow: inset 0 0 0 1.5px #c9a8f5; }
.treasure-grid .pill.kind-tag.item { color: var(--leaf-dark); box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--leaf) 40%, transparent); }

/* Story-day week chips: Saturday and Sunday are rounder and softly tinted (and set a little
   apart), so the two S's and the shape of the school week read at a glance. */
.week-chip.weekend { border-radius: 50%; background: color-mix(in srgb, #4a90d9 10%, var(--card-2)); border-color: color-mix(in srgb, #4a90d9 35%, var(--line-strong)); }
.week-chip.weekend:first-child { margin-right: 4px; }
.week-chip.weekend:last-child { margin-left: 4px; }
.week-chip.weekend.on { background: linear-gradient(180deg, #4fa548, var(--leaf)); border-color: var(--leaf-dark); }
/* …and in the "Add story days" picker, Saturday and Sunday get the same soft weekend tint. */
.weekdays label.weekend { background: color-mix(in srgb, #4a90d9 10%, var(--card-2)); border-color: color-mix(in srgb, #4a90d9 35%, var(--line-strong)); }

/* Special days: the next story days as little tear-off tiles under the date box. Tap one to pick
   it; the picked one stands up with a ring, and a day that already has this kind sits dimmed. */
.date-quick { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.date-quick-btn { padding: 0; border: 0; background: none; cursor: pointer; border-radius: 11px; transition: transform .15s cubic-bezier(.3, 1.6, .5, 1); }
.date-quick-btn .date-tile { display: block; width: 46px; border-radius: 10px; box-shadow: 0 2px 0 var(--tile); }
.date-quick-btn .date-tile-month { font-size: .6rem; padding: 1px 0 2px; }
.date-quick-btn .date-tile-day { font-size: 1.1rem; padding-top: 2px; }
.date-quick-btn .date-tile-wd { font-size: .6rem; padding-bottom: 3px; }
.date-quick-btn:hover { transform: translateY(-2px) rotate(-2deg); }
.date-quick-btn.on { transform: translateY(-3px); }
.date-quick-btn.on .date-tile { background: color-mix(in srgb, var(--tile) 16%, var(--card)); box-shadow: 0 0 0 3px color-mix(in srgb, var(--tile) 35%, transparent), 0 3px 0 var(--tile); }
.date-quick-btn.has { opacity: .45; }
.date-quick-btn:focus-visible { outline: 3px solid var(--sun); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { .date-quick-btn, .date-quick-btn:hover, .date-quick-btn.on { transition: none; transform: none; } }

/* Roster: under each student's level, the K-12 dots with their range lit and where they read now
   as a bigger dot ringed in the card color, so the column reads as a little chart. */
.reading-at { display: inline-flex; flex-direction: column; align-items: flex-start; gap: 7px; }
.reading-at .range-dots { margin-left: 2px; gap: 3px; }
.reading-at .range-dots i.here { transform: scale(1.75); box-shadow: 0 0 0 1.5px var(--card); z-index: 1; }
.reading-at .range-dots i.here::after { content: none; }

/* A page with no picture reads like a page of a book: the words keep a comfortable line length
   (about 60 letters) in the middle of the page instead of running edge to edge on a wide screen,
   and a little leaf flourish closes the page. */
.reader:not(.presenter) .page:not(.with-img):not(.cover):has(> .story-text) > .story-text { width: 100%; max-width: 36ch; margin-left: auto; margin-right: auto; }
.reader .page:not(.with-img):not(.cover) > .story-text::after {
  content: "🍃"; display: block; width: min(9em, 70%); margin: .5em auto 0; text-align: center; font-size: .75em; line-height: 1.4;
  background: linear-gradient(var(--line-strong), var(--line-strong)) left center / 36% 2px no-repeat,
              linear-gradient(var(--line-strong), var(--line-strong)) right center / 36% 2px no-repeat;
}

/* Today's story, still to make: a fan of three painted topic pictures in the card's corner, like
   cards held out to choose from. Pointing at the card spreads them a little; tapping them picks. */
.today-card:has(> .today-fan)::after { display: none; }
.today-fan { position: absolute; right: clamp(16px, 5vw, 56px); bottom: 50%; transform: translateY(50%); display: flex; z-index: 0; }
.today-fan img { width: clamp(64px, 11vw, 112px); aspect-ratio: 1; object-fit: cover; border-radius: 16px; border: 4px solid #fff; background: #fff;
  box-shadow: 0 6px 16px -6px rgba(0, 0, 0, .35); margin-left: -22px; transition: rotate .3s cubic-bezier(.3, 1.6, .5, 1), translate .3s cubic-bezier(.3, 1.6, .5, 1); }
.today-fan img:first-child { margin-left: 0; }
.today-fan img:nth-child(1) { rotate: -10deg; translate: 0 6px; }
.today-fan img:nth-child(2) { rotate: 2deg; translate: 0 -6px; z-index: 1; position: relative; }
.today-fan img:nth-child(3) { rotate: 12deg; translate: 0 8px; }
.today-card:hover .today-fan img:nth-child(1) { rotate: -16deg; translate: -8px 4px; }
.today-card:hover .today-fan img:nth-child(2) { rotate: 0deg; translate: 0 -14px; }
.today-card:hover .today-fan img:nth-child(3) { rotate: 18deg; translate: 8px 6px; }
.today-card:has(> .today-fan) > :not(.today-fan) { position: relative; z-index: 1; }
/* Phones: the fan tucks into the bottom corner beside the button, smaller. */
@media (max-width: 520px) {
  .today-fan { right: 10px; bottom: 24px; transform: none; }
  .today-fan img { width: 46px; border-width: 3px; border-radius: 10px; margin-left: -18px; }
}
@media (prefers-reduced-motion: reduce) { .today-fan img { transition: none; } }

/* A story's page (staff), on a wide screen: who has read it sits beside what the story is,
   instead of in a row of its own, so the book itself starts higher up the screen. */
@media (min-width: 900px) {
  .story-about:has(> .readers-line) { grid-template-columns: minmax(0, 1fr) auto; column-gap: 28px; align-items: center; }
  .story-about:has(> .readers-line) > * { grid-column: 1 / -1; }
  .story-about:has(> .readers-line) > .story-about-line, .story-about:has(> .readers-line) > .story-about-tags { grid-column: 1; }
  .story-about > .readers-line { grid-column: 2 !important; grid-row: 1 / span 2; max-width: 46vw; padding-left: 24px; border-left: 2px dashed var(--line); }
}
/* The story page's "?": a round button at the end of the action row that opens what each button
   does as a little card under it. */
.actions-help { position: relative; align-self: center; }
details.actions-help:not(.focus-fold):not(.fail-details) > summary { list-style: none; width: 36px; height: 36px; padding: 0; border-radius: 50%; display: grid; place-items: center;
  font-weight: 900; font-size: 1.05rem; color: var(--leaf-dark); background: var(--card); border: 2px solid var(--line-strong); box-shadow: var(--press); }
.actions-help > summary::-webkit-details-marker { display: none; }
details.actions-help > summary::before { content: none !important; }
details.actions-help:not(.focus-fold):not(.fail-details) > summary:hover { border-color: var(--leaf); }
details.actions-help[open]:not(.focus-fold):not(.fail-details) > summary, details.actions-help[open]:not(.focus-fold):not(.fail-details) > summary:hover { background: var(--leaf); border-color: var(--leaf); color: #fff; }
.actions-help > ul { position: absolute; z-index: 20; top: calc(100% + 10px); right: 0; width: min(460px, 86vw); margin: 0; padding: 14px 16px 14px 32px;
  display: grid; gap: 6px; background: var(--card); border: 1px solid var(--line); border-radius: 16px; box-shadow: var(--shadow); animation: award-pop .25s ease-out; }
@media (max-width: 760px) {
  /* Narrow: the card spans the whole button row under it, and the "?" stays where it is. */
  .row:has(> .actions-help) { position: relative; }
  .actions-help { position: static; }
  .actions-help > ul { left: 0; right: 0; width: auto; }
}
@media (prefers-reduced-motion: reduce) { .actions-help > ul { animation: none; } }

/* Class epic length: one little book page per page, a usual story's worth in green and the epic's
   extra pages paler, so the length reads as a stack rather than a number. */
.book-leaf { width: 9px; height: 13px; border-radius: 1px 3px 3px 1px; background: var(--leaf); box-shadow: inset 2px 0 0 rgba(0, 0, 0, .18);
  animation: seat-pop .25s cubic-bezier(.3, 1.6, .5, 1); }
.book-leaf.extra { background: color-mix(in srgb, var(--leaf) 38%, var(--card)); }
.stepper-pic:has(> .book-leaf) { gap: 2px; max-width: 260px; align-items: center; }
@media (prefers-reduced-motion: reduce) { .book-leaf { animation: none; } }

/* A question's "hear it": a round speaker button at the end of the question line. Pressing it
   gives a little sound-wave ring so the tap is felt even before the voice starts. */
.question legend > .hear-it { flex: none; margin-left: auto; width: 40px; height: 40px; margin-top: -6px; padding: 0; border-radius: 50%; display: grid; place-items: center;
  font-size: 1.1rem; cursor: pointer; background: var(--card); border: 2px solid var(--line-strong); box-shadow: var(--press); transition: transform .1s ease; }
.question legend > .hear-it:hover { border-color: var(--leaf); transform: translateY(-1px); }
.question legend > .hear-it:active { transform: translateY(2px); box-shadow: 0 1px 0 var(--line-strong); }
.question legend > .hear-it:focus-visible { outline: 3px solid var(--sun); outline-offset: 2px; }
.question legend > .hear-it.saying { animation: hear-ring .7s ease-out; }
@keyframes hear-ring { from { box-shadow: 0 0 0 0 color-mix(in srgb, var(--leaf) 55%, transparent), var(--press); } to { box-shadow: 0 0 0 12px transparent, var(--press); } }
.reader.presenter .question legend > .hear-it { width: 54px; height: 54px; font-size: 1.5rem; }
@media (prefers-reduced-motion: reduce) { .question legend > .hear-it.saying { animation: none; } }
@media print { .question legend > .hear-it { display: none; } }

/* A class with no students yet: five empty seats in the class's color, dashed like the library's
   empty shelf; the middle one, with a +, goes to the name box. */
.empty-class { display: grid; justify-items: center; gap: 10px; padding-top: 22px; text-align: center; }
.empty-class p { margin: 0; }
.empty-seats { display: flex; align-items: flex-end; gap: 14px; padding-bottom: 8px; border-bottom: 4px solid hsl(var(--hue) 35% 82%); }
.empty-seat { position: relative; width: 38px; height: 50px; display: block; }
.empty-seat::before { content: ""; position: absolute; left: 9px; top: 0; width: 20px; height: 20px; border-radius: 50%; border: 2px dashed hsl(var(--hue) 40% 68%); }
.empty-seat::after { content: ""; position: absolute; left: 0; bottom: 0; width: 38px; height: 24px; border-radius: 18px 18px 6px 6px; border: 2px dashed hsl(var(--hue) 40% 68%); }
.empty-seat:nth-child(odd) { transform: translateY(-2px); }
button.empty-seat { padding: 0; border: 0; background: none; cursor: pointer; width: 46px; height: 60px; font-size: 1.3rem; font-weight: 900; color: hsl(var(--hue) 50% 38%);
  display: grid; place-items: end center; padding-bottom: 2px; transition: transform .15s cubic-bezier(.3, 1.6, .5, 1); }
button.empty-seat::before { left: 11px; width: 24px; height: 24px; border-style: solid; background: hsl(var(--hue) 70% 92%); }
button.empty-seat::after { width: 46px; height: 30px; border-style: solid; background: hsl(var(--hue) 70% 92%); z-index: -1; }
button.empty-seat { isolation: isolate; }
button.empty-seat:hover { transform: translateY(-4px); }
button.empty-seat:focus-visible { outline: 3px solid var(--sun); outline-offset: 4px; border-radius: 12px; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) button.empty-seat::before, :root:not([data-theme="light"]) button.empty-seat::after { background: hsl(var(--hue) 30% 24%); }
  :root:not([data-theme="light"]) button.empty-seat { color: hsl(var(--hue) 60% 78%); } :root:not([data-theme="light"]) .empty-seats { border-bottom-color: hsl(var(--hue) 25% 30%); } }
:root[data-theme="dark"] button.empty-seat::before, :root[data-theme="dark"] button.empty-seat::after { background: hsl(var(--hue) 30% 24%); }
:root[data-theme="dark"] button.empty-seat { color: hsl(var(--hue) 60% 78%); } :root[data-theme="dark"] .empty-seats { border-bottom-color: hsl(var(--hue) 25% 30%); }
@media (prefers-reduced-motion: reduce) { button.empty-seat { transition: none; } }

/* The End's last buttons on a phone: one tidy stack of equal width, the main way on (back to
   the shelf, or the next story) first and in green, the smaller choices under it. */
@media (max-width: 520px) {
  .page.end > .end-actions { flex-direction: column; align-items: stretch; width: min(100%, 330px); margin-left: auto; margin-right: auto; gap: 10px; }
  .page.end > .end-actions > .btn { justify-content: center; }
  .page.end > .end-actions > .btn.primary { order: -1; }
  .page.end > .end-actions > .btn:not(.primary) { font-size: 1rem; min-height: 50px; }
}

/* Progress: the "tap a name" line and the columns' "?" share a line just above the table. */
.progress-lead { justify-content: space-between; flex-wrap: nowrap; align-items: center; gap: 12px; }
.progress-lead > p { margin: 0; }
@media print {
  .progress-lead > .actions-help { flex: 1; }
  .progress-lead > .actions-help > summary { display: none !important; }
  .progress-lead > .actions-help > ul { position: static; width: auto; box-shadow: none; animation: none; }
}

/* "Your story": the hero, topic and goal cards stand the same height with their names on one
   line across, the hero's face as big as the pictures beside it, and a gold star pinned on the
   hero card (the one that isn't a pick to change). */
.pick-review.three { align-items: stretch; }
.pick-review.three > .pick-review-plus { align-self: center; }
.pick-review.three .pick-review-part > span:last-child { margin-top: auto; }
.pick-review.three .pick-review-part.hero { position: relative; }
.pick-review.three .pick-review-part.hero .avatar { max-width: none; }
.pick-review.three .pick-review-part.hero::after { content: "⭐"; position: absolute; top: -10px; right: -10px; width: 28px; height: 28px; border-radius: 50%;
  display: grid; place-items: center; font-size: .9rem; background: var(--card); border: 2px solid var(--sun); box-shadow: 0 2px 6px rgba(0,0,0,.12); }

/* The class form is long: Save and Cancel ride along at the bottom of the screen as a frosted bar,
   and once something has changed, Save shows a small dot so it's clear there's something to save. */
.form-savebar { --pad: clamp(16px, 2.4vw, 22px); position: sticky; bottom: 0; z-index: 6; margin: 0 calc(-1 * var(--pad)) calc(-1 * var(--pad)); padding: 12px var(--pad); border-radius: 0 0 var(--radius) var(--radius);
  background: color-mix(in srgb, var(--card) 88%, transparent); backdrop-filter: blur(8px); border-top: 1px solid var(--line); }
.form-savebar > .btn.primary { position: relative; }
form.changed .form-savebar > .btn.primary::after { content: ""; position: absolute; top: -4px; right: -4px; width: 12px; height: 12px; border-radius: 50%;
  background: var(--sun); border: 2px solid var(--card); animation: award-pop .3s ease-out; }
@media (max-width: 520px) { .form-savebar > .btn { flex: 1; justify-content: center; } }
@media (prefers-reduced-motion: reduce) { form.changed .form-savebar > .btn.primary::after { animation: none; } }

/* Me page treasure cards (light theme): the painted treasure sits right on its card instead of in a
   square: its paper fades out softly at the edges into the card, so it reads as the treasure itself. */
.treasure-grid img.treasure-pic { mix-blend-mode: multiply; background: transparent; box-shadow: none; border-radius: 0;
  -webkit-mask-image: radial-gradient(closest-side, #000 62%, transparent 100%); mask-image: radial-gradient(closest-side, #000 62%, transparent 100%); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .treasure-grid img.treasure-pic { mix-blend-mode: normal; -webkit-mask-image: none; mask-image: none; border-radius: 14px; box-shadow: var(--shadow); } }
:root[data-theme="dark"] .treasure-grid img.treasure-pic { mix-blend-mode: normal; -webkit-mask-image: none; mask-image: none; border-radius: 14px; box-shadow: var(--shadow); }

/* A story's cover (solo or team): the hero faces and "Starring …" as one name-badge pill under the
   title, like a movie credit, instead of a face floating over a gray line. */
.cover-credit { display: inline-flex; align-items: center; gap: 12px; margin: 6px auto 12px; padding: 5px 20px 5px 6px; border-radius: 999px;
  background: var(--leaf-soft); border: 2px dashed color-mix(in srgb, var(--leaf) 45%, transparent); }
.cover-credit .cover-cast { margin: 0; flex-wrap: nowrap; padding-left: 6px; }
.cover-credit .cover-cast .avatar { width: 48px !important; height: 48px !important; margin: 0 0 0 -10px; border-width: 2px; box-shadow: none; }
.cover-credit .starring { margin: 0; font-size: 1.1rem; font-weight: 800; color: var(--leaf-dark); }
.page.cover:has(> .cover-credit) { text-align: center; }
.reader.presenter .cover-credit .cover-cast .avatar { width: clamp(56px, 6vw, 84px) !important; height: clamp(56px, 6vw, 84px) !important; }
.reader.presenter .cover-credit .starring { font-size: clamp(1.2rem, 2.2vw, 1.9rem); margin: 0; }
@media (max-width: 520px) { .cover-credit { padding-right: 14px; gap: 8px; } .cover-credit .cover-cast .avatar { width: 40px !important; height: 40px !important; } .cover-credit .starring { font-size: 1rem; } }

/* Stories tab: each story's read ring sits beside who's in it, so the column reads at a glance. */
.readers-cell { display: flex; align-items: center; gap: 10px; }
.readers-cell .today-ring { width: 38px; height: 38px; font-size: .68rem; }
.readers-cell-who { display: grid; gap: 2px; }
.readers-cell-who .hero-faces { margin-bottom: 0; }

/* Admin's Reader accounts: open mode / school / all as chips, a little larger than the kind chips. */
.mode-chips { align-items: center; }
.mode-chips .kind-chip { font-size: .9rem; padding: 6px 14px; }

/* A story's inside pages feel like a book: a soft fold shadow down the left (the spine side) and
   the edges of the pages still to read peeking out behind, a thinner stack as The End nears. */
.reader:not(.presenter) .page:not(.cover):not(.end) { position: relative;
  background-image: linear-gradient(90deg, color-mix(in srgb, var(--ink) 7%, transparent), transparent 26px); }
.reader:not(.presenter) .page.pages-left-1 { box-shadow: 4px 4px 0 -1px var(--card), 4px 4px 0 0 var(--line-strong), var(--shadow); }
.reader:not(.presenter) .page.pages-left-2 { box-shadow: 4px 4px 0 -1px var(--card), 4px 4px 0 0 var(--line-strong), 8px 8px 0 -1px var(--card), 8px 8px 0 0 var(--line-strong), var(--shadow); }
.reader:not(.presenter) .page.pages-left-3 { box-shadow: 4px 4px 0 -1px var(--card), 4px 4px 0 0 var(--line-strong), 8px 8px 0 -1px var(--card), 8px 8px 0 0 var(--line-strong), 12px 12px 0 -1px var(--card), 12px 12px 0 0 var(--line-strong), var(--shadow); }
@media (max-width: 520px) { .reader:not(.presenter) .page[class*="pages-left-"]:not(.pages-left-0) { margin-right: 8px; } }

/* Your classes: a dashed ghost tile at the end of the grid, a + where the next class goes. */
.class-tile-new { display: grid; place-items: center; min-height: 160px; border-radius: var(--radius); border: 2px dashed var(--line-strong);
  color: var(--leaf-dark); text-decoration: none; transition: border-color .15s, background .15s, transform .15s cubic-bezier(.3, 1.6, .5, 1); }
.class-tile-new > span { width: 54px; height: 54px; border-radius: 50%; display: grid; place-items: center; font-size: 1.6rem; font-weight: 900;
  background: var(--leaf-soft); box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--leaf) 35%, transparent); }
.class-tile-new:hover { border-color: var(--leaf); background: color-mix(in srgb, var(--leaf-soft) 45%, transparent); transform: translateY(-2px); }
.class-tile-new:focus-visible { outline: 3px solid var(--sun); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { .class-tile-new { transition: none; } }
@media (max-width: 520px) { .class-tile-new { min-height: 96px; } }

/* The new-reader wizard's grade step on a phone: 1st-12th four to a row (three short rows instead
   of four tall ones), each a smaller tile with its number badge, so Next stays on screen. */
@media (max-width: 520px) {
  .choices.small:has(> .grade-tile[data-value="0"]):has(> .grade-tile[data-value="12"]) { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; }
  .choices.small:has(> .grade-tile[data-value="12"]) > .grade-tile:not([data-value="0"]) { min-height: 0; padding: 7px 2px 6px; gap: 3px; font-size: .72rem; border-radius: 14px; }
  .choices.small:has(> .grade-tile[data-value="12"]) > .grade-tile .emoji { width: 32px; height: 32px; font-size: 1rem; }
}

/* QR cards: the three steps for home as picture steps, a round numbered badge with each step's
   picture (scan, pick pictures, read), easier to follow at a glance than a small numbered list. */
.qr-card .card-steps { list-style: none; counter-reset: step; padding-left: 0; display: grid; gap: 6px; margin: 8px 0; }
.qr-card .card-steps li { counter-increment: step; display: grid; grid-template-columns: 34px 1fr; align-items: center; column-gap: 8px; margin: 0; line-height: 1.25; }
.qr-card .card-steps li::before { content: attr(data-icon); position: relative; width: 32px; height: 32px; border-radius: 50%; display: grid; place-items: center;
  font-size: 1rem; background: #e6f4e2; border: 2px solid #3f8f3a; }
.qr-card .card-steps li::after { content: counter(step); position: absolute; left: 21px; top: 50%; translate: 0 -24px; width: 15px; height: 15px; border-radius: 50%;
  display: grid; place-items: center; font-size: .6rem; font-weight: 900; color: #fff; background: #3f8f3a; }
.qr-card .card-steps li { position: relative; }

/* Making a hero: five little dots under the pinned face, one per part, filling green as each is
   picked (a dot jumps to its part). In the slim pinned bar they sit beside the small face. */
.look-dots { display: flex; justify-content: center; gap: 6px; margin-top: 8px; }
.look-dots > button { width: 14px; height: 14px; padding: 0; border-radius: 50%; cursor: pointer; border: 2px dashed var(--sun); background: var(--card);
  transition: background .2s, border-color .2s, transform .2s cubic-bezier(.3, 1.6, .5, 1); }
.look-dots > button.on { border: 2px solid var(--leaf-dark); background: var(--leaf); transform: scale(1.1); }
.look-dots > button:focus-visible { outline: 3px solid var(--sun); outline-offset: 2px; }
.look-preview.stuck:has(.look-dots) { display: flex; align-items: center; justify-content: center; gap: 14px; }
.look-preview.stuck .look-dots { margin-top: 0; }
@media (prefers-reduced-motion: reduce) { .look-dots > button { transition: none; } }

/* A stat card's "turned off" note as a small pill (its full explanation on hover or tap). */
.off-pill { display: inline-flex; align-items: center; gap: 4px; margin-top: 4px; padding: 3px 10px; border-radius: 999px; font-size: .8rem; font-weight: 800;
  color: #7a5200; background: color-mix(in srgb, var(--sun) 25%, var(--card)); border: 1.5px dashed color-mix(in srgb, var(--sun) 80%, #a06d00); cursor: help; }
.off-pill:focus-visible { outline: 3px solid var(--sun); outline-offset: 2px; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .off-pill { color: #ffe08a; background: color-mix(in srgb, var(--sun) 18%, var(--card)); } }
:root[data-theme="dark"] .off-pill { color: #ffe08a; background: color-mix(in srgb, var(--sun) 18%, var(--card)); }

/* Light theme picker tiles (topics, goals, items): many paintings carry their own cream paper, which
   multiplying alone leaves as a faint square. A soft feather around the edges melts that paper into
   the tile; full-bleed paintings just get a gentle vignette edge. */
.choices.with-pics .choice-img {
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 9%, #000 91%, transparent), linear-gradient(180deg, transparent, #000 9%, #000 91%, transparent);
  -webkit-mask-composite: source-in; mask-image: linear-gradient(90deg, transparent, #000 9%, #000 91%, transparent), linear-gradient(180deg, transparent, #000 9%, #000 91%, transparent);
  mask-composite: intersect; border-radius: 0; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .choices.with-pics .choice-img { -webkit-mask-image: none; mask-image: none; border-radius: 12px; } }
:root[data-theme="dark"] .choices.with-pics .choice-img { -webkit-mask-image: none; mask-image: none; border-radius: 12px; }

/* A template's "story / blanks" view as a two-sided switch: a sliding pill under the side on show. */
.view-switch { display: inline-grid; grid-template-columns: 1fr 1fr; position: relative; padding: 4px; border-radius: 999px; background: var(--card-2); border: 1px solid var(--line); }
.view-switch > button { position: relative; z-index: 1; font: inherit; font-size: .88rem; font-weight: 800; padding: 7px 16px; border: 0; border-radius: 999px; background: none; color: var(--muted); cursor: pointer; white-space: nowrap; transition: color .2s; }
.view-switch > button.on { color: var(--leaf-dark); }
.view-switch::before { content: ""; position: absolute; top: 4px; bottom: 4px; left: 4px; width: calc(50% - 4px); border-radius: 999px; background: var(--card);
  box-shadow: 0 2px 0 var(--line-strong), 0 0 0 2px var(--leaf); transition: translate .25s cubic-bezier(.3, 1.4, .5, 1); }
.view-switch:has(> button[data-raw="true"].on)::before { translate: 100% 0; }
.view-switch > button:focus-visible { outline: 3px solid var(--sun); outline-offset: 2px; }
@media (max-width: 420px) { .view-switch > button { padding: 7px 10px; font-size: .8rem; } }
@media (prefers-reduced-motion: reduce) { .view-switch::before, .view-switch > button { transition: none; } }

/* A shelf still filling up (its empty book spots showing): on a wide screen the four spots share
   the whole width, so the wooden shelf runs wall to wall instead of stopping partway across. */
@media (min-width: 700px) { .shelf:has(> .ghost-slot) { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

/* Today in your class: today's settings as small chips (focus, topics, goals, skills, read-aloud,
   questions) instead of one long sentence. */
.set-chips { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.set-chip { display: inline-flex; align-items: center; gap: 4px; padding: 4px 12px; border-radius: 999px; font-size: .85rem; font-weight: 700;
  background: var(--card); border: 1.5px solid color-mix(in srgb, var(--leaf) 40%, var(--line)); color: var(--ink); }
.set-chip[data-tip] { cursor: help; letter-spacing: .08em; }
.set-chip.off { color: var(--muted); border-style: dashed; border-color: var(--line-strong); background: transparent; }
a.set-chip.focus { text-decoration: none; color: var(--leaf-dark); border-color: var(--leaf); background: var(--leaf-soft); letter-spacing: 0; }
a.set-chip.focus.none { background: transparent; border-style: dashed; color: var(--muted); }
a.set-chip.focus:hover { border-style: solid; color: var(--leaf-dark); }
.set-chip:focus-visible { outline: 3px solid var(--sun); outline-offset: 2px; }

/* The picture PIN: the pictures are what a pre-reader goes by, so they fill their tiles (about
   twice as big on a phone), each sitting on a soft round spot, with the word small underneath. */
.pin-pad .pin-emoji { font-size: clamp(2.6rem, 12vw, 3.4rem); width: 1.45em; height: 1.45em; display: grid; place-items: center; border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--leaf-soft) 80%, transparent) 55%, transparent 72%); transition: transform .2s cubic-bezier(.3, 1.6, .5, 1); }
.pin-pad button:hover .pin-emoji { transform: scale(1.08) rotate(-4deg); }
.pin-pad .pin-word { font-size: .75rem; margin-top: -2px; }
@media (prefers-reduced-motion: reduce) { .pin-pad .pin-emoji { transition: none; } .pin-pad button:hover .pin-emoji { transform: none; } }

/* Progress: each student's story days as a slim split bar, made (green) then still waiting (red). */
.days-bar { display: block; width: 76px; height: 6px; margin-top: 6px; border-radius: 999px;
  background: linear-gradient(90deg, var(--leaf) var(--made), #e8796f var(--made)); }
.days-bar[style*="--made: 0%"] { background: #e8796f; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .days-bar { background: linear-gradient(90deg, var(--leaf) var(--made), #b0534b var(--made)); } }
:root[data-theme="dark"] .days-bar { background: linear-gradient(90deg, var(--leaf) var(--made), #b0534b var(--made)); }

/* The hero preview sits on its section's own tint while in place (its card-colored backing showed
   as a pale box on the Me page's tinted Look section); it gets the solid strip only once pinned. */
.look-preview:not(.stuck) { background: transparent; }

/* Admin's All stories: who, status and kind as three groups of chips on one line, a thin divider
   between groups (wrapping onto more lines on a narrow screen). */
.chip-filters { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px; }
.chip-filters > .kind-chips + .kind-chips { padding-left: 14px; border-left: 2px solid var(--line); }
.chip-filters > .kind-chips:last-child { flex-basis: 100%; padding-left: 0 !important; border-left: 0 !important; }
@media (max-width: 520px) { .chip-filters > .kind-chips + .kind-chips { padding-left: 0; border-left: 0; } .chip-filters { gap: 10px; } }

/* Picking a reading level with every grade on offer, on a phone: 1st-12th four to a row in more
   compact tiles (same colors, emoji, words and meter), so the list is three short rows, not four
   tall ones, and Write my story comes into view sooner. */
@media (max-width: 520px) {
  .choices:has(> .choice[class*="lvl-"][data-value="0"]):has(> .choice[class*="lvl-"][data-value="12"]) { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; }
  .choices:has(> .choice[class*="lvl-"][data-value="12"]) > .choice[class*="lvl-"]:not([data-value="0"]) { min-height: 0; padding: 6px 3px 7px; gap: 2px; font-size: .74rem; border-radius: 14px; }
  .choices:has(> .choice[class*="lvl-"][data-value="12"]) > .choice[class*="lvl-"]:not([data-value="0"]) .emoji { font-size: 1.35rem; }
  .choices:has(> .choice[class*="lvl-"][data-value="12"]) > .choice[class*="lvl-"]:not([data-value="0"]) .sub { font-size: .62rem; line-height: 1.1; }
  .choices:has(> .choice[class*="lvl-"][data-value="12"]) > .choice[class*="lvl-"]:not([data-value="0"]) .choice-meter { width: 80%; height: 5px; margin-top: 3px; }
}

/* Classroom screen: a page with no picture keeps a readable line length in the middle of the
   screen (as in a big book), instead of lines running edge to edge across a projector. */
.reader.presenter .page:not(.with-img):not(.cover):has(> .story-text) > .story-text { max-width: 34ch; width: 100%; }

/* Start page: Go lights up green with a little arrow once a Hojas link is in the box. */
.go-btn.ready { animation: pic-pick .45s cubic-bezier(.3, 1.6, .5, 1); }
.go-btn.ready::after { content: " ▶"; }
@media (prefers-reduced-motion: reduce) { .go-btn.ready { animation: none; } }
form.row:has(> .go-btn) { flex-wrap: nowrap; }
form.row:has(> .go-btn) > input { min-width: 0; flex: 1 1 auto; }
.go-btn { flex: none; }

/* Account: the password strength segments share the full width of the box above them, and Save
   gives a small pop as it turns green (ready to save). */
.pw-bar { max-width: none !important; }
.save-wake { animation: pic-pick .45s cubic-bezier(.3, 1.6, .5, 1); }
@media (prefers-reduced-motion: reduce) { .save-wake { animation: none; } }

/* The round treasure tokens (home greeting, "Write it!" on a phone): the painted treasure sat small
   in the middle of its paper, so the token zooms in on it to fill the circle. */
@media (max-width: 520px) {
  .me-card .inventory .pill.with-pic:not(.more-pill), .bringing .pill.with-pic { overflow: hidden; }
  .me-card .inventory .pill.with-pic .pill-pic, .bringing .pill.with-pic .pill-pic { transform: scale(1.5); }
}

/* A class tile with no students yet: three small dashed empty seats where the faces go. */
.tile-seats { display: inline-flex; align-items: flex-end; gap: 6px; padding: 2px 0; }
.tile-seats .empty-seat { width: 22px; height: 28px; }
.tile-seats .empty-seat::before { left: 5px; width: 12px; height: 12px; border-width: 1.5px; }
.tile-seats .empty-seat::after { width: 22px; height: 14px; border-radius: 11px 11px 4px 4px; border-width: 1.5px; }

/* Me page treasure cards (light theme): the painted treasure sat small in the middle of its paper,
   so the picture is drawn larger (its soft faded edge grows with it) and the treasure fills the card. */
.treasure-grid img.treasure-pic { width: 128px; height: 128px; margin: -10px 0 -14px; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .treasure-grid img.treasure-pic { width: 96px; height: 96px; margin: 0; } }
:root[data-theme="dark"] .treasure-grid img.treasure-pic { width: 96px; height: 96px; margin: 0; }

/* Waiting for a story (light theme): the items being packed lose their cream square and shadow;
   each treasure is drawn a little bigger and feathers into the card, so they read as the objects
   themselves being packed. Powers keep their framed portraits; dark keeps the framed tiles. */
.pack-item.item img { background: transparent; box-shadow: none; border-radius: 0; mix-blend-mode: multiply; transform: scale(1.3);
  -webkit-mask-image: radial-gradient(closest-side, #000 60%, transparent 100%); mask-image: radial-gradient(closest-side, #000 60%, transparent 100%); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .pack-item.item img { background: var(--card); box-shadow: var(--shadow); border-radius: 16px; mix-blend-mode: normal; transform: none; -webkit-mask-image: none; mask-image: none; } }
:root[data-theme="dark"] .pack-item.item img { background: var(--card); box-shadow: var(--shadow); border-radius: 16px; mix-blend-mode: normal; transform: none; -webkit-mask-image: none; mask-image: none; }

/* The End's prize (light theme): the treasure just earned glows in its sunburst without a cream
   square around it; the painting is a bit bigger and feathers into the burst. */
img.award-pic { mix-blend-mode: multiply; box-shadow: none; border-radius: 0; background: transparent;
  -webkit-mask-image: radial-gradient(closest-side, #000 62%, transparent 100%); mask-image: radial-gradient(closest-side, #000 62%, transparent 100%); }
.award-prize img.award-pic { width: 104px; height: 104px; }
@media (max-width: 520px) { .award-prize img.award-pic { width: 92px; height: 92px; } }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) img.award-pic { mix-blend-mode: normal; box-shadow: var(--shadow); border-radius: 16px; -webkit-mask-image: none; mask-image: none; } }
:root[data-theme="dark"] img.award-pic { mix-blend-mode: normal; box-shadow: var(--shadow); border-radius: 16px; -webkit-mask-image: none; mask-image: none; }

/* The reader's page arrows: one with nowhere to go (back on the cover, forward at The End) fades
   away instead of sitting there as a big pale button that does nothing; its spot is kept, so the
   bar doesn't shift. */
.reader-bar .btn.round:disabled { visibility: hidden; opacity: 0; }

/* A topic dropdown's picture (Class epics, library and the like), light theme: no white box with a
   shadow; the painting is a bit bigger and feathers into the page like the kids' topic tiles. */
.select-pic { width: 88px; height: 88px; box-shadow: none; border-radius: 0; mix-blend-mode: multiply;
  -webkit-mask-image: radial-gradient(closest-side, #000 66%, transparent 100%); mask-image: radial-gradient(closest-side, #000 66%, transparent 100%); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .select-pic { width: 72px; height: 72px; border-radius: 12px; box-shadow: var(--shadow); mix-blend-mode: normal; -webkit-mask-image: none; mask-image: none; } }
:root[data-theme="dark"] .select-pic { width: 72px; height: 72px; border-radius: 12px; box-shadow: var(--shadow); mix-blend-mode: normal; -webkit-mask-image: none; mask-image: none; }

/* Picture styles (7 of them) on a phone: four across, then three centered under them, instead of
   3 + 3 + one tile left alone on its own row. */
@media (max-width: 520px) {
  .choices.with-pics:has(> .choice:nth-child(7):last-child) { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px; }
  .choices.with-pics:has(> .choice:nth-child(7):last-child) > .choice { flex: 0 0 calc((100% - 3 * 6px) / 4); grid-column: auto; padding: 5px 3px 7px; font-size: .74rem; }
}

/* Topics & skills: read-aloud and questions as on/off switches (a sliding knob, green when on),
   and a setting that's off fades, so "on" in its name never reads as on when it isn't. */
label.switch { gap: 10px; padding: 6px 14px 6px 8px; border-radius: 999px; border: 2px solid var(--line); background: var(--card); cursor: pointer; transition: opacity .2s, border-color .2s; }
label.switch:has(input:checked) { border-color: color-mix(in srgb, var(--leaf) 50%, var(--line)); background: var(--leaf-soft); }
label.switch:has(input:not(:checked)) { opacity: .6; border-style: dashed; }
label.switch input[type="checkbox"] { appearance: none; -webkit-appearance: none; position: relative; flex: none; width: 40px; height: 24px; margin: 0; border-radius: 999px;
  background: var(--line-strong); cursor: pointer; transition: background .2s; }
label.switch input[type="checkbox"]::after { content: ""; position: absolute; top: 3px; left: 3px; width: 18px; height: 18px; border-radius: 50%; background: #fff;
  box-shadow: 0 1px 3px rgba(0,0,0,.25); transition: translate .2s cubic-bezier(.3, 1.5, .5, 1); }
label.switch input[type="checkbox"]:checked { background: var(--leaf); }
label.switch input[type="checkbox"]:checked::after { translate: 16px 0; }
label.switch input[type="checkbox"]:focus-visible { outline: 3px solid var(--sun); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { label.switch input[type="checkbox"], label.switch input[type="checkbox"]::after { transition: none; } }

/* The reader's bar on a phone: "Cover" and "The End" don't hold a wide fixed spot, so the bar
   stays one row on every page (Read to me no longer drops to a second line on the cover). */
@media (max-width: 520px) {
  .reader-bar { gap: 8px; }
  .reader-count:not(.as-tab) { min-width: 64px; font-size: .9rem; }
}
@media (max-width: 380px) { .reader-bar { gap: 6px; } .reader-bar > .btn:not(.round) { padding-left: 12px; padding-right: 12px; font-size: .9rem; } .reader-count:not(.as-tab) { min-width: 56px; } }

/* Classroom screen questions: the right answer stays hidden until the teacher presses
   "Show the answer", then it lights up green with a pop. */
.question .reveal-answer { display: block; margin: 10px 0 0 auto; }
.reader.presenter .question .reveal-answer { font-size: clamp(1rem, 1.6vw, 1.3rem); padding: 8px 18px; }
.question .answer.right.revealed { animation: pic-pick .5s cubic-bezier(.3, 1.6, .5, 1); }
@media (prefers-reduced-motion: reduce) { .question .answer.right.revealed { animation: none; } }

/* "Just use my name": a little name-tag sticker with the kid's own name on it (a red band on top,
   the name below in the story font), tilted like a sticker on a shirt. */
.name-tag { display: inline-flex; flex-direction: column; align-items: stretch; min-width: 54px; max-width: 100%; border-radius: 8px; overflow: hidden;
  background: #fff; border: 2px solid #e05a5a; box-shadow: 0 2px 4px rgba(0,0,0,.12); transform: rotate(-4deg); }
.name-tag-top { display: block; height: 9px; background: #e05a5a; }
.name-tag-name { display: block; padding: 2px 8px 3px; font-family: var(--read-font); font-size: 1rem; font-weight: 700; color: #1f2a1c; line-height: 1.2;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.choice:hover:not(:disabled) .name-tag { transform: rotate(2deg); }
.choice .name-tag { transition: transform .2s cubic-bezier(.3, 1.6, .5, 1); }
@media (prefers-reduced-motion: reduce) { .choice .name-tag { transition: none; } }
/* The roster's "Just their name" option: a smaller name tag that fits the picture-button row. */
.seg-emoji .name-tag { min-width: 40px; max-width: 86px; border-width: 1.5px; border-radius: 6px; }
.seg-emoji .name-tag-top { height: 6px; }
.seg-emoji .name-tag-name { font-size: .78rem; padding: 1px 6px 2px; }

/* Picking starting treasures (light theme): the item paintings' cream paper still showed as a
   square in each tile, so items get the treasure cards' soft round fade and a little zoom; the
   powers below (full portraits) keep the picker's square feather. Also the picked treasures in
   the pack slots and the hero badge drop their squares. */
.pack-row + .stack > h3:first-child + .choices .choice-img {
  -webkit-mask-image: radial-gradient(closest-side, #000 62%, transparent 100%); mask-image: radial-gradient(closest-side, #000 62%, transparent 100%);
  -webkit-mask-composite: source-over; mask-composite: add; transform: scale(1.15); }
.pack-slot.filled.item img { mix-blend-mode: multiply; transform: scale(1.35); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .pack-row + .stack > h3:first-child + .choices .choice-img { -webkit-mask-image: none; mask-image: none; transform: none; }
  :root:not([data-theme="light"]) .pack-slot.filled.item img { mix-blend-mode: normal; transform: none; } }
:root[data-theme="dark"] .pack-row + .stack > h3:first-child + .choices .choice-img { -webkit-mask-image: none; mask-image: none; transform: none; }
:root[data-theme="dark"] .pack-slot.filled.item img { mix-blend-mode: normal; transform: none; }

/* Admin Overview: a service turned off on this server is a slim card, its name and the "Turned off"
   pill side by side (the how-to on hover), instead of a card of paragraphs. */
.card.svc-off { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding-top: 12px; padding-bottom: 12px; }
.card.svc-off h2 { margin: 0; font-size: 1.1rem; color: var(--muted); }
.card.svc-off .off-pill { margin-top: 0; }

/* The new-reader badge's picked treasures: little round tokens (as on the home greeting) that zoom
   in on the treasure, overlapping like a small pile, instead of tiny cream squares. */
.pick-thumbs { gap: 0; padding-left: 6px; }
.pick-thumbs > img, .pick-thumbs > span { width: 28px; height: 28px; margin-left: -6px; border-radius: 50%; border: 2px solid var(--card); box-shadow: 0 2px 4px rgba(0,0,0,.12);
  background: var(--card); object-fit: cover; object-position: center; display: inline-grid; place-items: center; font-size: .9rem; }
.pick-thumbs > img { object-fit: cover; object-view-box: inset(17%); transform: rotate(-4deg); }
.pick-thumbs > :nth-child(2) { transform: rotate(5deg); } .pick-thumbs > :nth-child(3) { transform: rotate(-7deg); }

/* A shelf still filling up: the empty spots stand like books of different heights on the plank,
   and the next spot (where the next finished story goes) has a sunny outline. */
.ghost-slot { align-items: flex-end; }
.ghost-slot .ghost-shelf-book { align-self: flex-end; height: 88%; }
.ghost-slot:nth-last-child(2) .ghost-shelf-book { height: 76%; }
.ghost-slot:nth-last-child(1) .ghost-shelf-book { height: 64%; }
.shelf-slot:not(.ghost-slot) + .ghost-slot .ghost-shelf-book { height: 92%; opacity: .9; border-color: color-mix(in srgb, var(--sun) 80%, #b07a00);
  background: color-mix(in srgb, var(--sun) 12%, transparent); }
.shelf-slot:not(.ghost-slot) + .ghost-slot .ghost-shelf-book::after { content: "✨"; opacity: .7; }

/* Me page treasure cards (light theme): a treasure with no painting (its emoji) glows softly in
   the card like the painted ones float, instead of sitting in a boxed tile with a shadow. */
.treasure-grid .treasure-emoji { box-shadow: none; border-radius: 50%; width: 110px; height: 110px; margin: -6px auto -8px; font-size: 3.4rem;
  background: radial-gradient(closest-side, color-mix(in srgb, var(--sun) 30%, transparent), transparent) !important; animation: emoji-float 3.5s ease-in-out infinite; }
.treasure-grid .power .treasure-emoji, .treasure-grid .treasure-emoji:has(+ div .pill.power) { background: radial-gradient(closest-side, rgba(150, 110, 230, .28), transparent) !important; }
@keyframes emoji-float { 0%, 100% { translate: 0 0; } 50% { translate: 0 -5px; } }
@media (prefers-reduced-motion: reduce) { .treasure-grid .treasure-emoji { animation: none; } }

/* Reading badges: the next medal to earn wears a sunny ring that fills as stories are read toward
   it (one story of five fills a fifth), so how close it is shows on the medal itself. */
.reading-badge.next .medal-disc { position: relative; }
.reading-badge.next .medal-disc::after { content: ""; position: absolute; inset: -9px; border-radius: 50%; pointer-events: none;
  background: conic-gradient(#f5b301 var(--p, 0%), color-mix(in srgb, var(--sun) 18%, transparent) 0);
  -webkit-mask: radial-gradient(closest-side, transparent calc(100% - 5px), #000 calc(100% - 4px)); mask: radial-gradient(closest-side, transparent calc(100% - 5px), #000 calc(100% - 4px)); }
.reading-badge.next .medal-disc { box-shadow: none; }

/* Help on a phone: the section shortcuts as a tidy two-column grid of equal tiles (picture over a
   short title) instead of ten ragged rows of pills, so the guide starts a screen sooner. */
@media (max-width: 520px) {
  .help-toc { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; }
  .help-chip { justify-content: flex-start; padding: 6px 8px 6px 6px; border-radius: 14px; font-size: .78rem; line-height: 1.15; text-align: left; min-height: 44px; }
  .help-chip-icon { width: 26px; height: 26px; flex: none; }
}

/* Me's two smaller buttons on a phone: one line each ("My link & QR code" no longer wraps). */
@media (max-width: 520px) { .me-actions > .btn:not(.primary) { font-size: .86rem; padding-left: 8px; padding-right: 8px; white-space: nowrap; gap: 5px; } }

/* Look editor on a phone: hair styles (12) and outfits (10) as four try-on faces across, the last
   row centered, so each list is a row shorter and no outfit is left alone on its own line. */
@media (max-width: 520px) {
  .choices.with-pics:has(> .choice .choice-art .avatar):not(:has(> .choice:nth-child(3):last-child)):has(> .choice:nth-child(4)) { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px; }
  .choices.with-pics:has(> .choice .choice-art .avatar):not(:has(> .choice:nth-child(3):last-child)):has(> .choice:nth-child(4)) > .choice { flex: 0 0 calc((100% - 3 * 6px) / 4); grid-column: auto; padding: 5px 2px 7px; font-size: .72rem; }
  .choices.with-pics:has(> .choice .choice-art .avatar):not(:has(> .choice:nth-child(3):last-child)):has(> .choice:nth-child(4)) .choice-art .avatar { width: 50px !important; height: 50px !important; }
}

/* A class page's header on a phone: Edit class sits beside the class name (as a compact button),
   and the class's fact chips run in one row that scrolls sideways, so the Today card and tabs
   come up about a third of a screen sooner. */
@media (max-width: 520px) {
  .row.spread:has(> .stack > .class-page-name) { flex-wrap: nowrap; align-items: flex-start; }
  .row.spread:has(> .stack > .class-page-name) > .stack { min-width: 0; flex: 1; }
  .row.spread:has(> .stack > .class-page-name) > a.btn { flex: none; padding: 6px 10px; font-size: .82rem; }
  .row.spread:has(> .stack > .class-page-name) .fact-chips { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; margin-right: -84px; padding-bottom: 2px;
    -webkit-mask-image: linear-gradient(90deg, #000 85%, transparent); mask-image: linear-gradient(90deg, #000 85%, transparent); }
  .row.spread:has(> .stack > .class-page-name) .fact-chips::-webkit-scrollbar { display: none; }
  .row.spread:has(> .stack > .class-page-name) .fact-chip { flex: none; white-space: nowrap; }
}

/* Picture PIN: Start over waits out of sight (keeping its spot) until a picture has been tapped. */
.pin-clear { transition: opacity .2s ease, transform .2s ease; }
.pin-clear.idle { opacity: 0; visibility: hidden; transform: translateY(4px); }
@media (prefers-reduced-motion: reduce) { .pin-clear { transition: none; } }

/* Schedule's weekday picker on a phone: all seven days in one row like a week, instead of five and
   a stray two. */
@media (max-width: 520px) {
  .weekdays { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 4px; }
  .weekdays label { min-width: 0; padding: 8px 0; font-size: .78rem; border-radius: 10px; }
}

/* Treasure pills' little round pictures: zoomed in on the treasure (its painting's paper trimmed
   away) and a touch bigger, so the telescope or lantern is recognizable at a glance. */
.pill-pic { object-view-box: inset(17%); width: 30px; height: 30px; }
.me-card .inventory .pill-pic { width: 28px; height: 28px; }
@media (max-width: 520px) { .me-card .inventory .pill.with-pic .pill-pic, .bringing .pill.with-pic .pill-pic { transform: scale(1.1); } }

/* Roster cards on a phone: a student's lowest and highest reading level side by side (a little →
   between), not stacked, so each student's card is a row shorter. */
@media (max-width: 520px) {
  table.cards-on-phone .cell-range .range-pair { flex-direction: row !important; align-items: center; gap: 14px; }
  table.cards-on-phone .cell-range .range-pair select { flex: 1 1 0 !important; min-width: 0; font-size: .82rem; padding-left: 10px; padding-right: 26px; background-position: right 6px center; }
  table.cards-on-phone .cell-range .range-pair .range-dash { margin: -10px 0 0 -10px; }
  table.cards-on-phone .cell-range .range-pair .range-dash::after { content: "→"; }
}

/* A reader's treasures (admin's reader page): led by a little backpack, like the kids' own pack. */
.treasure-strip { display: flex; align-items: center; gap: 14px; }
.treasure-strip-bag { flex: none; width: 46px; height: 46px; border-radius: 14px; display: grid; place-items: center; font-size: 1.5rem; background: #fdecef; box-shadow: inset 0 0 0 2px #f6c9d3; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .treasure-strip-bag { background: #3a2229; box-shadow: inset 0 0 0 2px #5a3440; } }
:root[data-theme="dark"] .treasure-strip-bag { background: #3a2229; box-shadow: inset 0 0 0 2px #5a3440; }

/* Waiting screen: a treasure with no painting (its emoji) glows softly like the painted items
   beside it, instead of sitting in a white box with a shadow. */
.pack-item .pack-emoji { box-shadow: none; border-radius: 50%; background: radial-gradient(closest-side, color-mix(in srgb, var(--sun) 30%, transparent), transparent); }
.pack-item.power .pack-emoji { background: radial-gradient(closest-side, rgba(150, 110, 230, .28), transparent); }

/* Today in your class: today's calendar tile leads the heading. */
.today-head { display: flex; align-items: center; gap: 14px; }
.today-head h2 { margin: 0; }
.today-head .date-tile { width: 54px; transform: rotate(-4deg); }

/* The End's word hunt: a dashed treasure-map edge around the card, and what the skill means as a
   little sunny sticky note pinned in it (tilted a touch), so the three lines read as a title, a
   note to remember, and how to play, instead of one block of centered text. */
.word-hunt { border: 2px dashed color-mix(in srgb, var(--leaf) 55%, transparent); }
.word-hunt .skill-meaning { display: inline-block; max-width: 34em; margin: 4px auto 12px; padding: 8px 14px; border-radius: 4px 12px 12px 12px; text-align: left;
  background: #fff6c9; color: #4a3b00; box-shadow: 0 3px 8px -4px rgba(120, 90, 0, .35); transform: rotate(-1deg); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .word-hunt .skill-meaning { background: #4a4120; color: #fff2bf; } }
:root[data-theme="dark"] .word-hunt .skill-meaning { background: #4a4120; color: #fff2bf; }

/* Admin's AI cost card: how costs are worked out sits behind a small "?" in the card's corner. */
.stat-card:has(> .stat-help) { position: relative; }
.stat-card > .stat-help { position: absolute; top: 12px; right: 12px; }
details.actions-help.stat-help:not(.focus-fold):not(.fail-details) > summary { width: 28px; height: 28px; font-size: .9rem; }
.stat-card > .stat-help > ul { left: -12px; right: auto; width: min(420px, 86vw); list-style: none; padding-left: 16px; font-size: .88rem; line-height: 1.45; }
@media (max-width: 760px) { .stat-card > .stat-help { position: absolute; } .stat-card > .stat-help > ul { position: absolute; left: auto; right: -12px; width: min(340px, 86vw); } }
.stat-card:has(> .stat-help[open]) { overflow: visible; z-index: 6; }

/* Home's "questions are waiting" card wears the questions' own sky blue (as the quiz badge and the
   question numbers do), with a few faint question marks drifting in its corner. */
.unread-card.quiz-card { position: relative; overflow: hidden; isolation: isolate; border-color: #b9dcf7;
  background: linear-gradient(135deg, #eef7ff, var(--card) 60%); }
.unread-card.quiz-card::after { content: "?  ?\A  ?"; white-space: pre; position: absolute; right: 22px; top: 50%; translate: 0 -50%; z-index: -1; pointer-events: none;
  font-size: 2.6rem; font-weight: 900; line-height: 1; color: #4a90d9; opacity: .12; rotate: 8deg; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .unread-card.quiz-card { border-color: #2c4a66; background: linear-gradient(135deg, #1b2d3d, var(--card) 60%); } }
:root[data-theme="dark"] .unread-card.quiz-card { border-color: #2c4a66; background: linear-gradient(135deg, #1b2d3d, var(--card) 60%); }

/* A class page's header (wide screens): Edit class lines up with the class name, not halfway down. */
@media (min-width: 521px) { .row.spread:has(> .stack > .class-page-name) { align-items: flex-start; } .row.spread:has(> .stack > .class-page-name) > a.btn { margin-top: 6px; } }
@media (max-width: 520px) { .unread-card.quiz-card::after { top: auto; bottom: 10px; right: 14px; translate: none; font-size: 1.6rem; opacity: .1; } }
@media (max-width: 520px) { table.cards-on-phone .row-status:empty { display: none; } }

/* Phone treasure piles (home greeting, "Write it!"): "+3 more" is one more round token at the end
   of the pile (just "+3"), matching the tokens, instead of a wide dashed pill. */
@media (max-width: 520px) {
  .me-card .inventory .pill.more-pill, .bringing .pill.more-pill { width: 40px; height: 40px; padding: 0 !important; margin-left: -6px; border-radius: 50%; justify-content: center;
    border: 3px solid var(--card); border-style: solid; background: var(--leaf-soft); box-shadow: 0 3px 8px rgba(0,0,0,.14); rotate: 6deg; }
  .me-card .inventory .pill.more-pill .more-words, .bringing .pill.more-pill .more-words { display: none; }
  .me-card .inventory .pill.more-pill::after, .bringing .pill.more-pill::after { content: attr(data-n); font-size: .8rem; font-weight: 900; color: var(--leaf-dark); }
}

/* Home: "My bookshelf" with the reading-badge progress beside it on a wide screen. */
@media (min-width: 760px) {
  .shelf-head { display: flex; align-items: center; justify-content: space-between; gap: 10px 24px; flex-wrap: wrap; }
  .shelf-head > h2 { margin: 0; }
  .shelf-head > .read-count-wrap { align-items: flex-end; gap: 4px; }
  .shelf-head .read-count { margin: 0; }
}
@media (min-width: 760px) { .shelf-head .read-count { justify-content: flex-end; text-align: right; align-self: flex-end; } }

/* Help: a small round ↑ in the corner, shown once the section chips have scrolled away. */
.help-up { position: fixed; right: max(16px, env(safe-area-inset-right)); bottom: 20px; z-index: 20; width: 46px; height: 46px; border-radius: 50%; cursor: pointer;
  font-size: 1.3rem; font-weight: 900; color: #fff; background: var(--leaf); border: 2px solid var(--leaf-dark); box-shadow: 0 3px 0 var(--leaf-dark), 0 6px 14px -4px rgba(0,0,0,.3);
  opacity: 0; visibility: hidden; transform: translateY(12px); transition: opacity .2s, transform .25s cubic-bezier(.3, 1.6, .5, 1), visibility .2s; }
.help-up.show { opacity: 1; visibility: visible; transform: none; }
.help-up:focus-visible { outline: 3px solid var(--sun); outline-offset: 2px; }
@media print { .help-up { display: none; } }
@media (prefers-reduced-motion: reduce) { .help-up { transition: none; } }

/* Special days with none coming: a blank dashed calendar tile waiting for one, beside the line. */
.special-none { display: flex; align-items: center; gap: 14px; }
.special-none p { margin: 0; }
.date-tile.empty-tile { --tile: var(--line-strong); border-style: dashed; box-shadow: none; background: transparent; transform: rotate(-4deg); }
.date-tile.empty-tile .date-tile-month { height: 14px; background: color-mix(in srgb, var(--line-strong) 60%, transparent); }
.date-tile.empty-tile .date-tile-day { padding: 6px 0 8px; font-size: 1.2rem; opacity: .55; filter: grayscale(.3); }

/* New-reader wizard's step pictures: the steps still to come are a touch bigger and keep a hint of
   their color, so a kid can see what's coming (bag, face, speech, mirror...) instead of gray specks. */
.steps.step-pics span { width: 30px; height: 30px; font-size: .85rem; }
.steps.step-pics span:not(.on) { filter: grayscale(.35); opacity: .8; }
.steps.step-pics span.now { width: 48px; height: 34px; font-size: 1.05rem; }
@media (max-width: 360px) { .steps.step-pics span { width: 26px; height: 26px; font-size: .75rem; } }
@media (max-width: 520px) { table.cards-on-phone td:has(> .solo-dash) { display: none; } }

/* The reader's bottom bar: its backing fades in across the whole window (frosted, a little see-
   through) instead of as a box the width of the book, which left a visible seam at its edges on a
   wide screen. */
.reader:not(.presenter) .reader-bar { background: none; isolation: isolate; }
.reader:not(.presenter) .reader-bar::before { content: ""; position: absolute; z-index: -1; top: 0; bottom: 0; left: calc(50% - 50vw); right: calc(50% - 50vw);
  background: color-mix(in srgb, var(--bg) 82%, transparent); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  -webkit-mask-image: linear-gradient(transparent, #000 34%); mask-image: linear-gradient(transparent, #000 34%); pointer-events: none; }

/* QR cards: the name pill always sits on its own line above the code (on a wide phone card it had
   room to slip in beside the code, half over the camera frame). */
.qr-card .name, .qr-card .name.with-face { display: flex; width: fit-content; margin-left: auto; margin-right: auto; }
.qr-card .name:not(.with-face) { display: block; }

/* Story goals (16 of them): four across, a tidy 4 x 4, instead of rows of five (or three on a phone)
   that left one goal alone at the bottom. */
.choices.with-pics:not(.small):has(> .choice:nth-child(16):last-child) { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); max-width: 760px; margin-left: auto; margin-right: auto; }
.choices.with-pics:not(.small):has(> .choice:nth-child(16):last-child) > .choice { grid-column: auto; }
@media (max-width: 520px) {
  .choices.with-pics:not(.small):has(> .choice:nth-child(16):last-child) { gap: 6px; }
  .choices.with-pics:not(.small):has(> .choice:nth-child(16):last-child) > .choice { padding: 5px 3px 7px; font-size: .72rem; }
}
