/* 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; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; }
.story-goal-words { white-space: normal; }

/* A teacher going over a story's questions: the bar to show the answers, and a student's picks */
.review-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 16px; margin: 0 0 14px; padding: 12px 14px; border: 2px solid var(--leaf); border-radius: 14px; background: var(--leaf-soft); }
.review-bar .review-summary { flex: 1 1 220px; margin: 0; font-weight: 700; }
.review-bar .review-toggle { margin-left: auto; }
.review-whose { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; font-weight: 700; }
.review-whose select { width: auto; max-width: 100%; }
.question.got-right { border-color: #2f9e44; }
.question.got-wrong { border-color: #d64545; }
.question.got-right .q-num { background: #2f9e44; color: #fff; }
.question.got-wrong .q-num { background: #d64545; color: #fff; }
.answer .pick-tag { flex: none; margin-left: auto; padding: 2px 10px; border: 1.5px solid currentColor; border-radius: 999px; font-family: inherit; font-size: .8rem; font-weight: 700; text-decoration: none; display: inline-block; }
.answer .pick-tag[hidden] { display: none; }
.answer-review .reveal-answer[hidden], .review-bar .review-toggle[hidden], .review-bar .review-summary[hidden] { display: none; }
@media (max-width: 560px) { .review-bar .review-toggle { width: 100%; margin-left: 0; } }

/* 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-chip .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-chip .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; }
}

/* Reading-skill tiles (Topics & skills, Class epics): every one wore the same 🎯, which told them
   apart not at all; the tiles are now just the skill and its grades, a row shorter each, so the
   whole list of skills takes far less scrolling. (Picked ones still turn purple with a check.) */
.choice.skill-tile .emoji { display: none; }
.choices.small > .choice.skill-tile { min-height: 0; padding-top: 10px; padding-bottom: 10px; }

/* Dark theme: the paintings' white paper glared on the dark cards (picker tiles, the story recipe,
   pack tiles, treasure cards), so they're dimmed a touch, like a page under a reading lamp. */
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) :is(.choices.with-pics .choice-img, .pick-review-part img, .pack-item img, .treasure-grid img.treasure-pic, img.award-pic, .select-pic) { filter: brightness(.86) saturate(.95); } }
:root[data-theme="dark"] :is(.choices.with-pics .choice-img, .pick-review-part img, .pack-item img, .treasure-grid img.treasure-pic, img.award-pic, .select-pic) { filter: brightness(.86) saturate(.95); }
.name-tag-name.sample { color: #9aa58f; font-style: italic; }
/* ...and the same gentle dimming for the home page's pictures: the topic fan on Today's story,
   book covers on the shelf, and the little covers on cards. */
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) :is(.today-fan img, .shelf .cover-img, .mini-cover img, .cover-strip img) { filter: brightness(.86) saturate(.95); } }
:root[data-theme="dark"] :is(.today-fan img, .shelf .cover-img, .mini-cover img, .cover-strip img) { filter: brightness(.86) saturate(.95); }

/* Admin: storyteller voices and the translator share a row on a wide screen (two slim cards when
   both are turned off), instead of two near-identical strips stacked. */
.svc-row { display: grid; gap: 14px; }
@media (min-width: 760px) { .svc-row:has(> .svc-off) { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); align-items: start; } }

/* The resting Today's story card (story writer off): its white words sat on a pale sage too light
   to read comfortably; a deeper, dusky sage keeps the sleepy look and makes the note easy to read. */
.today-card.resting { background: linear-gradient(135deg, #6f8c67, #5b7654); }
.today-card.resting .resting-note { color: #fff; text-shadow: 0 1px 2px rgba(0, 0, 0, .18); }
@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); }

/* Daily table on a phone (Admin, School): each number sits over its little bar instead of beside
   it, so the four columns fit the screen (the cost was cut off at "$0"). */
@media (max-width: 520px) {
  .day-bar-cell { flex-direction: column-reverse; align-items: flex-start; gap: 3px; font-weight: 700; }
  .day-bar { width: 52px; height: 6px; }
}
/* ...and a story's own pictures (cover and pages) in the kid's reader; the classroom screen keeps
   them at full brightness for the projector. */
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .reader:not(.presenter) img.story-img { filter: brightness(.88) saturate(.95); } }
:root[data-theme="dark"] .reader:not(.presenter) img.story-img { filter: brightness(.88) saturate(.95); }
/* The empty Library's "+" book is a link: it lifts a little when pointed at. */
a.ghost-book { text-decoration: none; cursor: pointer; transition: transform .2s cubic-bezier(.3, 1.6, .5, 1); }
a.ghost-book:hover { transform: translateY(-6px); }
@media (prefers-reduced-motion: reduce) { a.ghost-book { transition: none; } a.ghost-book:hover { transform: none; } }
/* The napping book's z's float up within their own space, so they never drift into a longer
   heading ("El cuento de hoy"). */
.resting-scene { height: 84px; margin-top: 0; }

/* Class tabs on a wide screen stay one row in any language (Spanish's "Épicas de la clase" was
   dropping alone onto a second line): they share the bar and tighten a little as needed. */
@media (min-width: 641px) {
  .tabs { flex-wrap: nowrap; }
  .tabs button { white-space: nowrap; }
  html:not([lang="en"]) .tabs button { padding: 8px clamp(8px, 1.1vw, 16px); font-size: clamp(.86rem, 1.3vw, 1.05rem); gap: 6px; }
}

/* The picker's big "Write my story!" on a phone stays one line in longer languages
   ("¡Escribir mi cuento!"): it shrinks its type a touch instead of wrapping. */
@media (max-width: 520px) { .wizard-nav > .pick-write.big { white-space: nowrap; font-size: clamp(1rem, 4.6vw, 1.25rem); padding-left: 10px; padding-right: 10px; } }
/* "Your story" on a narrow phone (360px): the three cards and their + signs stay in one row, and
   names wrap between words, never mid-word ("Unicornio s"). */
@media (max-width: 380px) {
  .pick-review.three { gap: 4px; flex-wrap: nowrap; }
  .pick-review.three .pick-review-part { width: auto; flex: 1 1 0; min-width: 0; padding: 6px 4px; }
  .pick-review.three .pick-review-part > span:last-child { font-size: .74rem; overflow-wrap: normal; word-break: normal; hyphens: none; }
  .pick-review.three > .pick-review-plus { flex: none; font-size: 1rem; }
}

/* Add a student on a phone: the two labels sit at the bottom of their row and the initial's label
   may wrap, so a long one ("Inicial del apellido") shows in full instead of "Inicial del ...". */
@media (max-width: 520px) {
  .add-student-grid > .f-initial > span { white-space: normal; overflow: visible; line-height: 1.15; align-self: end; }
  .add-student-grid > .f-first > span { align-self: end; line-height: 1.15; }
}

/* The new-reader badge's face before a look is picked: a big dashed 🎨 waiting to become the hero. */
.face-todo.hero-todo { width: 64px; height: 64px; font-size: 1.6rem; flex: none; background: var(--leaf-soft); animation: hero-wait 2.4s ease-in-out infinite; }
@keyframes hero-wait { 0%, 100% { rotate: -6deg; } 50% { rotate: 6deg; } }
@media (prefers-reduced-motion: reduce) { .face-todo.hero-todo { animation: none; } }

/* The ↑ back-to-top button on a phone: smaller and a little see-through (solid when touched), and
   the page keeps room at its end, so it never sits on top of the last tiles or buttons for good. */
@media (max-width: 520px) {
  .help-up { width: 40px; height: 40px; font-size: 1.1rem; bottom: 14px; }
  .help-up.show { opacity: .82; }
  .help-up.show:active { opacity: 1; }
  .stack.wrap.narrow:has(> .help-up) { padding-bottom: 56px; }
}

/* The picker's topics (26) on a wide screen: six across, so the last row is a centered pair
   instead of one topic alone. */
@media (min-width: 1000px) {
  .choices.with-pics:not(.small):has(> .choice:nth-child(26):last-child) > .choice { flex-basis: calc((100% - 5 * 12px) / 6); }
}
/* ...and the 26 reading skills (Topics & skills, Class epics): six across on a wide screen, ending
   in a centered pair instead of Point of view alone. */
@media (min-width: 1000px) { .choices.small:has(> .skill-tile:nth-child(26):last-child) > .choice { flex-basis: calc((100% - 5 * 10px) / 6); } }

/* The look editor's pinned hero shrinks into a slim bar as it pins. The browser's scroll anchoring
   would then scroll the page up to make up for the shrink, unpinning it, so it grew back and
   flickered on a wide screen; with anchoring off while the editor is on screen, it pins once
   and stays put. */
html:has(.look-preview) { overflow-anchor: none; }

/* The teacher's top bar on a phone: the nav buttons run in one row that swipes sideways (fading at an
   edge only where there's more to swipe to), under the logo, instead of wrapping onto a second row. */
@media (max-width: 520px) {
  #topbar > #nav { flex-wrap: nowrap; overflow-x: auto; overflow-y: visible; flex: 1 1 100%; min-width: 0; gap: 6px; padding: 2px 2px 14px; margin-bottom: -10px; scrollbar-width: none;
    --fl: 0px; --fr: 0px; -webkit-mask-image: linear-gradient(90deg, transparent, #000 var(--fl), #000 calc(100% - var(--fr)), transparent); mask-image: linear-gradient(90deg, transparent, #000 var(--fl), #000 calc(100% - var(--fr)), transparent); }
  #topbar > #nav.more-left { --fl: 28px; }
  #topbar > #nav.more-right { --fr: 36px; }
  #topbar > #nav::-webkit-scrollbar { display: none; }
  #topbar > #nav > * { flex: none; }
}

/* My character on a phone: the jump buttons are a two-across list, each colored icon beside a
   label big enough to read (instead of seven squeezed tiles with tiny words). An odd last one
   runs the whole width. */
@media (max-width: 520px) {
  .me-jumps { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  /* Two across, unless the family has set big text: then one per row so no label is cut off. */
  .me-jumps { grid-template-columns: repeat(auto-fit, minmax(min(100%, max(6.5rem, calc(50% - 4px))), 1fr)); }
  .me-jumps .jump-tile { flex-direction: row; justify-content: flex-start; gap: 10px; min-height: 52px; padding: 6px 10px 6px 6px; font-size: .86rem; text-align: left; border-radius: 999px; }
  .me-jumps .jump-tile:last-child:nth-child(odd) { grid-column: 1 / -1; justify-self: center; min-width: calc(50% - 4px);
    min-width: clamp(calc(50% - 4px), (13rem + 8px - 100%) * 999, 100%); }
  .me-jumps .jump-tile[style*="--hue"] { background: linear-gradient(90deg, hsl(var(--hue) 80% 95%), var(--card) 75%); }
  .me-jumps .jump-tile[style*="--hue"] .jump-icon { flex: none; width: 2.2em; height: 2.2em; font-size: 1.05rem; }
}
@media (max-width: 520px) and (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .me-jumps .jump-tile[style*="--hue"] { background: linear-gradient(90deg, hsl(var(--hue) 30% 20%), var(--card) 75%); } }
@media (max-width: 520px) { :root[data-theme="dark"] .me-jumps .jump-tile[style*="--hue"] { background: linear-gradient(90deg, hsl(var(--hue) 30% 20%), var(--card) 75%); } }

/* Progress with no students yet: a faint dashed sketch of the table to come, in the class's
   color (a face, a name, a level dot, a story bar, a score ring per row), fading row by row. */
.ghost-table { display: grid; gap: 10px; padding: 14px 16px; border-radius: 16px; background: hsl(var(--hue) 70% 96%); border: 2px dashed hsl(var(--hue) 40% 80%); }
.ghost-row { display: grid; grid-template-columns: 34px minmax(60px, 1.4fr) 22px minmax(60px, 1.6fr) minmax(30px, .8fr) 26px; align-items: center; gap: 14px; opacity: calc(1 - var(--i) * .28); }
.ghost-face, .ghost-dot, .ghost-ring { display: block; border-radius: 50%; border: 2px dashed hsl(var(--hue) 40% 68%); }
.ghost-face { width: 34px; height: 34px; background: hsl(var(--hue) 70% 92%); }
.ghost-dot { width: 22px; height: 22px; border-style: solid; background: hsl(var(--hue) 45% 80%); border-color: transparent; }
.ghost-ring { width: 26px; height: 26px; border-width: 4px; border-style: solid; border-color: hsl(var(--hue) 40% 84%); border-top-color: hsl(var(--hue) 45% 66%); }
.ghost-line { display: block; height: 10px; border-radius: 999px; background: hsl(var(--hue) 40% 86%); }
.ghost-line.name { width: 80%; height: 12px; background: hsl(var(--hue) 40% 80%); }
.ghost-line.bar { background: linear-gradient(90deg, hsl(var(--hue) 45% 70%) calc(70% - var(--i) * 25%), hsl(var(--hue) 40% 88%) 0); }
.ghost-line.short { width: 60%; }
@media (max-width: 520px) { .ghost-row { grid-template-columns: 30px 1fr 18px 1fr 22px; gap: 10px; } .ghost-line.short { display: none; } .ghost-face { width: 30px; height: 30px; } .ghost-dot { width: 18px; height: 18px; } .ghost-ring { width: 22px; height: 22px; } }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .ghost-table { background: hsl(var(--hue) 25% 18%); border-color: hsl(var(--hue) 25% 34%); }
  :root:not([data-theme="light"]) .ghost-face { background: hsl(var(--hue) 25% 24%); border-color: hsl(var(--hue) 25% 42%); }
  :root:not([data-theme="light"]) .ghost-dot, :root:not([data-theme="light"]) .ghost-line.name { background: hsl(var(--hue) 25% 36%); }
  :root:not([data-theme="light"]) .ghost-line { background: hsl(var(--hue) 20% 28%); }
  :root:not([data-theme="light"]) .ghost-line.bar { background: linear-gradient(90deg, hsl(var(--hue) 30% 42%) calc(70% - var(--i) * 25%), hsl(var(--hue) 20% 28%) 0); }
  :root:not([data-theme="light"]) .ghost-ring { border-color: hsl(var(--hue) 20% 30%); border-top-color: hsl(var(--hue) 30% 48%); } }
:root[data-theme="dark"] .ghost-table { background: hsl(var(--hue) 25% 18%); border-color: hsl(var(--hue) 25% 34%); }
:root[data-theme="dark"] .ghost-face { background: hsl(var(--hue) 25% 24%); border-color: hsl(var(--hue) 25% 42%); }
:root[data-theme="dark"] .ghost-dot, :root[data-theme="dark"] .ghost-line.name { background: hsl(var(--hue) 25% 36%); }
:root[data-theme="dark"] .ghost-line { background: hsl(var(--hue) 20% 28%); }
:root[data-theme="dark"] .ghost-line.bar { background: linear-gradient(90deg, hsl(var(--hue) 30% 42%) calc(70% - var(--i) * 25%), hsl(var(--hue) 20% 28%) 0); }
:root[data-theme="dark"] .ghost-ring { border-color: hsl(var(--hue) 20% 30%); border-top-color: hsl(var(--hue) 30% 48%); }

/* The new-reader wizard's path: done steps are round ✓ buttons that go back to that step (they
   lift and show their picture when pointed at), and the line under the path fills in green up
   to the step you're on. */
.steps.step-pics::before { left: 18px; right: 18px; height: 4px; margin-top: -2px; border-radius: 999px;
  background: linear-gradient(90deg, var(--leaf) var(--fill, 0%), var(--line) var(--fill, 0%)); transition: background .3s; }
.steps.step-pics button { position: relative; width: 30px; height: 30px; padding: 0; display: grid; place-items: center; border-radius: 50%; cursor: pointer;
  font: inherit; font-size: .85rem; font-weight: 900; line-height: 1; color: #fff; background: var(--leaf); border: 2px solid var(--leaf);
  transition: transform .15s cubic-bezier(.3, 1.6, .5, 1), background .15s; }
.steps.step-pics button:hover, .steps.step-pics button:focus-visible { transform: translateY(-3px) scale(1.12); background: var(--leaf-soft); color: transparent; }
.steps.step-pics button:hover::after, .steps.step-pics button:focus-visible::after { content: attr(data-pic); position: absolute; inset: 0; display: grid; place-items: center; color: initial; font-size: .95rem; }
.steps.step-pics button:focus-visible { outline: 3px solid var(--sun); outline-offset: 2px; }
.steps.step-pics button:active { transform: translateY(0) scale(.95); }
@media (max-width: 360px) { .steps.step-pics button { width: 26px; height: 26px; font-size: .75rem; } }
@media (prefers-reduced-motion: reduce) { .steps.step-pics button { transition: none; } }

/* Focus period form: the "covers N story days" line and its little calendar strip sit together
   in one soft panel under the dates (with room to breathe), instead of a note jammed against
   the date boxes with the strip hanging off its edge. */
.focus-cover { display: grid; gap: 10px; margin-top: 4px; padding: 12px 14px; border-radius: 14px; background: var(--leaf-soft); }
.focus-cover .special-explain { background: none; padding: 0; }
.focus-cover .day-strip { margin: 0; padding-top: 10px; border-top: 1px dashed var(--line-strong); }
.focus-cover .strip-day:not(.story) { background: transparent; }
.focus-cover:has(.day-strip:empty) { gap: 0; }

/* Ready to write: the topic and goal pictures each wear a little ✏️ badge in the corner (as the
   hero wears ⭐), saying "tap to change me" without a line of words under them. The pencil
   wiggles when pointed at. */
.pick-review.three .pick-review-part:not(.hero) { position: relative; }
.pick-review.three .pick-review-part:not(.hero)::after { content: "✏️"; position: absolute; top: -10px; right: -10px; width: 28px; height: 28px; border-radius: 50%;
  display: grid; place-items: center; font-size: .85rem; background: var(--card); border: 2px solid var(--leaf); box-shadow: 0 2px 6px rgba(0,0,0,.12);
  transition: transform .2s cubic-bezier(.3, 1.6, .5, 1); }
.pick-review.three .pick-review-part:not(.hero):hover::after, .pick-review.three .pick-review-part:not(.hero):focus-visible::after { transform: scale(1.18) rotate(-14deg); }
@media (prefers-reduced-motion: reduce) { .pick-review.three .pick-review-part:not(.hero)::after { transition: none; } }

/* Special day form: "Solo story that day" draws the day's stories as little books, the solo 📖
   plus the team 🤝 book, or the solo one faded and crossed out with the team one instead; the
   label under them is big enough to read. */
.solo-pick .seg-option { gap: 6px; min-height: 64px; padding: 8px 6px; }
.solo-pick .seg-option > span:last-child { font-size: .9rem; line-height: 1.2; }
.day-books { display: inline-flex; align-items: center; gap: 4px; }
.day-book { position: relative; display: grid; place-items: center; width: 28px; height: 32px; font-size: .95rem; border-radius: 3px 7px 7px 3px;
  background: var(--card); border: 2px solid var(--line-strong); border-left-width: 4px; box-shadow: 0 2px 0 var(--line-strong); }
.day-book.team { border-color: hsl(340 60% 70%); background: hsl(340 80% 96%); box-shadow: 0 2px 0 hsl(340 50% 78%); }
.day-book.gone { opacity: .45; filter: grayscale(1); }
.day-book.gone::after { content: ""; position: absolute; left: -5px; right: -5px; top: 50%; height: 3px; margin-top: -1.5px; border-radius: 3px; background: #d9534f; transform: rotate(-35deg); }
.day-book-join { font-weight: 900; font-size: .9rem; color: var(--muted); }
.solo-pick .seg-option:has(input:checked) .day-book:not(.gone) { transform: translateY(-2px) rotate(-4deg); }
.solo-pick .seg-option:has(input:checked) .day-book.team { transform: translateY(-2px) rotate(4deg); }
.day-book { transition: transform .2s cubic-bezier(.3, 1.6, .5, 1); }
@media (prefers-reduced-motion: reduce) { .day-book { transition: none; } }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .day-book.team { border-color: hsl(340 35% 50%); background: hsl(340 25% 22%); box-shadow: 0 2px 0 hsl(340 30% 30%); } }
:root[data-theme="dark"] .day-book.team { border-color: hsl(340 35% 50%); background: hsl(340 25% 22%); box-shadow: 0 2px 0 hsl(340 30% 30%); }

/* Home: the reading-badge progress under "My bookshelf" sits on its own little gold card (the
   cheer, then the sticker road to the medal), instead of loose lines floating by the heading. */
.shelf-head > .read-count-wrap { width: fit-content; max-width: 100%; gap: 6px; margin: 2px 0 0; padding: 10px 16px 10px 12px; border-radius: 18px;
  background: linear-gradient(135deg, #fff8dc, var(--card) 80%); border: 2px solid #f1d27a; box-shadow: 0 3px 0 #ecd08a; }
.shelf-head > .read-count-wrap .next-badge { font-size: .85rem; color: #8a6a12; }
.shelf-head > .read-count-wrap .read-count { color: var(--ink); }
@media (min-width: 760px) { .shelf-head > .read-count-wrap { align-items: flex-start; } .shelf-head .read-count, .shelf-head .next-badge { justify-content: flex-start; text-align: left; align-self: flex-start; } }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .shelf-head > .read-count-wrap { background: linear-gradient(135deg, #3a3216, var(--card) 80%); border-color: #6b5a24; box-shadow: 0 3px 0 #4a3f1a; }
  :root:not([data-theme="light"]) .shelf-head > .read-count-wrap .next-badge { color: #e6cf86; } }
:root[data-theme="dark"] .shelf-head > .read-count-wrap { background: linear-gradient(135deg, #3a3216, var(--card) 80%); border-color: #6b5a24; box-shadow: 0 3px 0 #4a3f1a; }
:root[data-theme="dark"] .shelf-head > .read-count-wrap .next-badge { color: #e6cf86; }

/* The picture-button pickers on teacher forms (role, pronoun, how stories name students): a
   bigger picture over a label big enough to read, instead of a tiny emoji and tiny words. */
.seg-pick:not(.solo-pick) .seg-option { gap: 5px; min-height: 62px; padding: 8px 6px; font-size: .88rem; line-height: 1.15; }
.seg-pick:not(.solo-pick) .seg-emoji { font-size: 1.6rem; transition: transform .2s cubic-bezier(.3, 1.6, .5, 1); }
.seg-pick .seg-option:hover .seg-emoji { transform: scale(1.12) rotate(-5deg); }
.seg-pick .seg-option:has(input:checked) .seg-emoji { transform: scale(1.08); }
@media (prefers-reduced-motion: reduce) { .seg-pick .seg-emoji { transition: none; } }

/* "One tap next time": the add-to-home-screen steps show Safari's Share button, Chrome's ⋮ menu
   and the "Add to Home Screen" menu item as little copies of how they look on the phone. */
.ui-chip { display: inline-flex; align-items: center; gap: 5px; vertical-align: middle; margin: 0 2px; padding: 2px 8px; border-radius: 8px; line-height: 1.3;
  font-weight: 700; font-size: .9em; color: var(--ink); background: var(--card); border: 1.5px solid var(--line-strong); box-shadow: 0 2px 0 var(--line-strong); }
.ui-chip.share { color: #1a73e8; padding: 3px 7px; }
.ui-chip.dots { font-weight: 900; padding: 1px 9px; }
.ui-chip.menu-row { border-radius: 10px; padding: 2px 10px 2px 6px; margin: 2px; }
.chip-hold { white-space: nowrap; }
.chip-hold > .ui-chip { white-space: normal; }
.ui-chip.menu-row .menu-plus { flex: none; }
.menu-plus { display: inline-grid; place-items: center; width: 18px; height: 18px; border-radius: 5px; font-size: .75rem; background: var(--leaf-soft); color: var(--leaf-dark); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .ui-chip.share { color: #8ab4f8; } }
:root[data-theme="dark"] .ui-chip.share { color: #8ab4f8; }

/* Class epic length, clearer: a small gap where a usual story's pages end and the epic's extra
   pages begin, and if it's set shorter than usual, the missing pages as dashed outlines. */
.book-leaf { transition: background .2s, margin .2s; }
.book-leaf.past-usual { margin-left: 7px; position: relative; }
.book-leaf.past-usual::before { content: ""; position: absolute; left: -6px; top: -3px; bottom: -3px; width: 2px; border-radius: 2px; background: var(--sun); }
.book-leaf.ghost { background: transparent; box-shadow: none; outline: 1.5px dashed var(--line-strong); outline-offset: -1.5px; animation: none; }

/* The End: the page-turning bar stops floating over the story questions (where it hid an answer
   and the Check button on a phone) and settles at the bottom of the page instead, under the
   last buttons. Every other page keeps it pinned to the bottom of the screen. */
.reader:not(.presenter) .reader-bar:has(.arrived) { position: relative; bottom: auto; margin-top: 4px; }

/* A class page on a phone: its fact chips (grade, term, school, reading range) wrap onto a
   second line instead of running off the right edge, where the school was cut mid-word and the
   reading range could only be found by swiping. */
@media (max-width: 520px) {
  .row.spread:has(> .stack > .class-page-name) .fact-chips { flex-wrap: wrap; overflow: visible; -webkit-mask-image: none; mask-image: none; width: calc(100vw - 24px); max-width: none; margin-right: 0; }
  .row.spread:has(> .stack > .class-page-name) .fact-chip { white-space: normal; max-width: 100%; flex-wrap: wrap; row-gap: 4px; }
  /* With big text the label wraps beside its icon (not under it), the range dots stay inside the
     chip, and a two-line chip rounds like a card instead of bulging into an oval. */
  .row.spread:has(> .stack > .class-page-name) .fact-chip { display: inline-grid; grid-template-columns: auto minmax(0, 1fr); column-gap: 6px; border-radius: 1.2em; }
  .row.spread:has(> .stack > .class-page-name) .fact-chip > .range-dots { grid-column: 2; margin-left: 0; padding-bottom: 5px; }
}

/* The picker's 26 topics on a phone: four across, matching the goals step (a 4 x 4 of the same
   size tiles), instead of three big tiles a row; seven rows to scroll instead of nine, the last
   pair centered. */
@media (max-width: 520px) {
  .choices.with-pics:not(.small):has(> .choice:nth-child(26):last-child) { gap: 6px; }
  .choices.with-pics:not(.small):has(> .choice:nth-child(26):last-child) > .choice { flex-basis: calc((100% - 3 * 6px) / 4); padding: 5px 3px 7px; font-size: .72rem; }
}

/* Add story days: the range about to be added is drawn above its words the way it will look in
   the list (dates, week chips, timeline), inside a dashed "not added yet" outline; the panel
   sits a little apart from the weekday buttons above it. */
.rule-preview { display: grid; gap: 10px; margin-top: 6px; padding: 12px 14px; border-radius: 14px; background: var(--leaf-soft); }
.rule-preview .special-explain { background: none; padding: 0; }
.rule-ghost { display: grid; gap: 8px; justify-items: start; padding: 10px 12px; border-radius: 12px; border: 2px dashed color-mix(in srgb, var(--leaf) 55%, transparent); background: var(--card);
  animation: seat-pop .3s cubic-bezier(.3, 1.6, .5, 1); }
.rule-ghost:empty { display: none; }
.rule-ghost .rule-line { width: 100%; }
@media (prefers-reduced-motion: reduce) { .rule-ghost { animation: none; } }

/* Today's story on a phone: the fan of topic pictures stands in the middle of the card, between
   the words and the button, at a size you can see what they are (it was three thumbnails
   squeezed into the corner beside the button). */
@media (max-width: 520px) {
  .today-card > .today-fan { position: relative; right: auto; bottom: auto; transform: none; align-self: center; justify-content: center; margin: 4px 0 0; padding: 0 0 12px 26px; }
  .today-card > .today-fan img { width: 84px; border-width: 4px; border-radius: 14px; margin-left: -26px; }
  .today-card:has(> .today-fan) > a.btn.big { display: flex; width: fit-content; margin-left: auto; margin-right: auto; }
}

/* Progress table: a row's cells line up through their middle (the count, its bar, the badges and
   the grade chip sat at different heights), and a student's warning icons stay on the line with
   their name instead of dropping under it. */
@media (min-width: 641px) {
  tr[data-student] > td { vertical-align: middle; }
  tr[data-student] > td.cell-name { white-space: nowrap; }
  tr[data-student] > td.cell-name > .name-link { vertical-align: middle; }
  tr[data-student] > td.cell-name > .flag-icon { vertical-align: middle; margin-left: 2px; }
}

/* Students and Progress on a phone: each student's card opens with a proper header (a bigger
   face and name over a soft divider), so whose card it is reads first, apart from the labels. */
@media (max-width: 640px) {
  table.cards-on-phone td.cell-name { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 10px; padding-bottom: 10px; margin-bottom: 2px;
    border-bottom: 1.5px dashed var(--line); font-size: 1.2rem; font-weight: 800; }
  table.cards-on-phone td.cell-name .avatar, table.cards-on-phone td.cell-name .face-todo { width: 46px !important; height: 46px !important; flex: none; }
  table.cards-on-phone td.cell-name .face-todo { font-size: 1.3rem; }
  table.cards-on-phone td.cell-name .name-link { font-size: inherit; padding-left: 0; gap: 10px; }
}

/* Small phones (360px and under), kids' pages: the top bar stays one row. The 🍃 logo keeps
   its place but the word beside it steps aside, so the language menu and the Me button fit
   next to it instead of wrapping onto a second row on every page. */
@media (max-width: 360px) {
  .topbar:has(#topbar-extra) .brand > span:not(.logo) { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .topbar:has(#topbar-extra) { flex-wrap: nowrap; gap: 8px; }
}
/* ...and a bookshelf card's badge with a long label (Spanish "Preguntas pendientes") folds onto
   two lines inside its pill instead of being cut off with "…". */
@media (max-width: 380px) {
  .book-badges .badge { white-space: normal; text-overflow: clip; line-height: 1.2; border-radius: 10px; text-align: left; }
}

/* Small phones (380px and under), teacher pages:
   - the daily table (Admin, School) tightens its columns so the last one (cost or reads) fits
     instead of being cut off at "COS" / "$0.";
   - a "Turned off" pill stays one piece instead of breaking "En / pausa" over two lines;
   - a special day's kind cards center both names (a two-line "Épica de la clase" sat left). */
@media (max-width: 380px) {
  table:has(.day-bar-cell) th, table:has(.day-bar-cell) td { padding: 8px 5px; }
  table:has(.day-bar-cell) th { font-size: .66rem; letter-spacing: .02em; }
  table:has(.day-bar-cell) td:first-child { font-size: .85rem; }
  table:has(.day-bar-cell) .day-bar { width: 40px; }
}
.off-pill { white-space: nowrap; flex: none; }
.kind-name { text-align: center; }

/* Small phones: color dots (skin, hair, favorite color) that don't fill their last row sit
   centered under the others instead of stuck to the left; and a long one-word label on a look
   tile ("Impermeable", "Ropa de explorador") gets room: on a phone 360px or narrower, the try-on
   tiles go three across (a bigger face too) instead of four too-narrow ones. */
@media (max-width: 520px) { .choices.swatches, .choices.small.swatches { justify-content: center; } }
@media (max-width: 360px) {
  .choices.with-pics:has(> .choice .choice-art .avatar):not(:has(> .choice:nth-child(3):last-child)):has(> .choice:nth-child(4)) > .choice { flex-basis: calc((100% - 2 * 6px) / 3); font-size: .74rem; }
  .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: 58px !important; height: 58px !important; }
}

/* Edit class, "Archive this class": the checkbox sits at the start of the label's first line
   and the label uses the full width (it floated beside the middle of a wrapped label, which
   looked indented); on a phone the 📦 sits at the top beside the words. */
.archive-zone .check { display: flex; align-items: flex-start; gap: 10px; }
.archive-zone .check > input { flex: none; margin-top: .3em; }
@media (max-width: 520px) { .archive-zone { align-items: flex-start; gap: 12px; } .archive-zone-icon { width: 40px; height: 40px; font-size: 1.35rem; } }

/* A focus period's little calendar strip on a small phone: slimmer days, so a whole week (Sunday
   to Saturday) fits on one line instead of the weekend days wrapping alone. */
@media (max-width: 380px) {
  .day-strip { gap: 3px; }
  .strip-day { width: 29px; }
  .strip-day.week-start { margin-left: 5px; }
}

/* The picker's 26 topics on a phone 360px or narrower: three across, so long names
   ("Superhéroes", "Celebraciones") fit inside their tiles; wider phones keep four across. */
@media (max-width: 360px) {
  .choices.with-pics:not(.small):has(> .choice:nth-child(26):last-child) > .choice { flex-basis: calc((100% - 2 * 6px) / 3); font-size: .76rem; }
}
/* ...but the small details under a story's title in that header (kind, language, level) stay
   small and quiet; only the name or title itself is big. */
@media (max-width: 640px) { table.cards-on-phone td.cell-name .muted { font-size: .85rem; font-weight: 600; line-height: 1.5; } }

/* The End: the page-turning bar drops the hidden ▶ (there's no next page) instead of keeping its
   empty slot, so ◀ and "The End" sit centered under the trail. */
.reader:not(.presenter) .reader-bar:has(.arrived) .btn.round:disabled { display: none; }

/* A narrow column inside the page's own column (Help, Account, the kids' Me page, the start
   page) doesn't add its side padding a second time: on a phone those pages lost twice the
   margin of every other page, squeezing their text. Wider screens are unchanged (the narrow
   column is centered well inside the page there anyway). */
.wrap .wrap:not(.card) { padding-left: 0; padding-right: 0; }

/* New-reader wizard: the picked treasures sit beside the name and step in the "hero so far"
   badge, not under them, so picking the first one grows the badge sideways instead of making it
   taller and shoving the whole page (and the tile just tapped) down. */
.hero-so-far-text:has(> .pick-thumbs) { display: grid; grid-template-columns: auto auto; align-items: center; column-gap: 12px; }
.hero-so-far-text > .pick-thumbs { grid-column: 2; grid-row: 1 / span 2; margin-top: 0; }

/* Focus period form: the topic and goal pickers' Clear button holds its place, unseen, until
   something is picked (see limitPicker). */
.limit-line .limit-clear-idle { visibility: hidden; }
.limit-line { flex-wrap: nowrap; justify-content: space-between; }
.limit-line > span { flex: 1 1 auto; min-width: 0; }
.limit-line > .btn { flex: none; }

/* Starting treasures: the backpack row's "N of 3 picked" is the same size before and after the
   bag fills (only its color changes), so the third pick doesn't nudge the tiles below. */
.pack-row > p.muted { padding: 8px 12px; border-radius: 12px; }

/* Days off form: date and note side by side (the note taking the room), the date tiles, the
   hint, then Add; the hint takes no space until a date is picked. */
.skip-form > * + * { margin-top: 10px; }
.skip-fields > input[type="date"] { flex: 0 0 auto; width: auto; }
.skip-fields > input[type="text"] { flex: 1 1 200px; min-width: 0; }
.skip-form .skip-hint { margin: 0; }
.skip-form .skip-hint:empty { display: none; }

/* Reading-level tiles: each tile stacks the same way from the top (picture, grade, what it means,
   meter at the bottom), so a two-line meaning ("Un poco más difícil") doesn't lift its picture and
   grade above the rest of the row. */
.choice[class*="lvl-"]:not([data-value="0"]) { justify-content: flex-start; }
.choice[class*="lvl-"]:not([data-value="0"]) > .choice-meter { margin-top: auto; }

/* Signed out (the sign-in page) on a phone, the teacher's top bar holds only the language menu:
   it stays on the logo's row, at the right, instead of taking a whole second row of its own. */
@media (max-width: 520px) {
  #topbar > #nav:not(:has(a)) { flex: none; margin: 0 0 0 auto; padding: 0; -webkit-mask-image: none; mask-image: none; overflow: visible; }
}

/* A link whose class (or student) is archived: the reader card from the broken-link picture,
   solid instead of dashed and tilted the other way, asleep under a moon, z's drifting up. */
.sleeping-scene .lost-card { rotate: 6deg; left: 22px; border-style: solid; border-color: #c9d6bb; }
.sleeping-scene .lost-qr { opacity: .35; }
.sleep-moon { position: absolute; right: -6px; top: -2px; font-size: 1.9rem; line-height: 1; filter: drop-shadow(0 3px 5px rgba(0, 0, 0, .15)); }
.sleeping-scene i { position: absolute; left: 112px; top: 40px; font-style: normal; font-weight: 900; color: var(--leaf-dark); opacity: 0; animation: zzz 3s ease-in infinite; }
.sleeping-scene i:nth-of-type(1) { font-size: .8rem; }
.sleeping-scene i:nth-of-type(2) { font-size: 1rem; animation-delay: 1s; }
.sleeping-scene i:nth-of-type(3) { font-size: 1.25rem; animation-delay: 2s; }
@media (prefers-reduced-motion: reduce) {
  .sleeping-scene i { animation: none; opacity: .8; }
  .sleeping-scene i:nth-of-type(2) { transform: translate(10px, -12px); } .sleeping-scene i:nth-of-type(3) { transform: translate(22px, -26px); }
}

/* A class tile (for an admin): the teacher on one line, their school on its own small line under
   the name with a 🏫, instead of "Lincoln Ele…" cut off after the teacher's name. */
.tile-teacher { flex-wrap: wrap; }
.tile-teacher .tile-school { flex: 1 0 100%; padding-left: 31px; white-space: nowrap; font-size: .85rem; }
.tile-teacher .tile-school::before { content: "🏫 "; margin-right: 0; }

/* Dark mode, My character's treasures: each painted picture sits in a soft round glow that fades
   into the card (like a lit display case), instead of a hard-edged cream square glaring off the
   dark card. */
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .treasure-grid img.treasure-pic { width: 112px; height: 112px; margin: -6px 0 -8px; border-radius: 50%; box-shadow: none;
  -webkit-mask-image: radial-gradient(circle closest-side, #000 62%, transparent 100%); mask-image: radial-gradient(circle closest-side, #000 62%, transparent 100%); } }
:root[data-theme="dark"] .treasure-grid img.treasure-pic { width: 112px; height: 112px; margin: -6px 0 -8px; border-radius: 50%; box-shadow: none;
  -webkit-mask-image: radial-gradient(circle closest-side, #000 62%, transparent 100%); mask-image: radial-gradient(circle closest-side, #000 62%, transparent 100%); }

/* Dark mode, the topic picture beside a topic menu (Class epics, library days): the same soft
   round glow as My character's treasures, instead of a hard cream square on the dark form. */
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .select-pic { width: 84px; height: 84px; border-radius: 50%; box-shadow: none;
  -webkit-mask-image: radial-gradient(circle closest-side, #000 62%, transparent 100%); mask-image: radial-gradient(circle closest-side, #000 62%, transparent 100%); } }
:root[data-theme="dark"] .select-pic { width: 84px; height: 84px; border-radius: 50%; box-shadow: none;
  -webkit-mask-image: radial-gradient(circle closest-side, #000 62%, transparent 100%); mask-image: radial-gradient(circle closest-side, #000 62%, transparent 100%); }
/* ...and the prize on a story's The End page, glowing in the middle of its sunburst. */
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) img.award-pic { border-radius: 50%; box-shadow: none;
  -webkit-mask-image: radial-gradient(circle closest-side, #000 62%, transparent 100%); mask-image: radial-gradient(circle closest-side, #000 62%, transparent 100%); } }
:root[data-theme="dark"] img.award-pic { border-radius: 50%; box-shadow: none;
  -webkit-mask-image: radial-gradient(circle closest-side, #000 62%, transparent 100%); mask-image: radial-gradient(circle closest-side, #000 62%, transparent 100%); }

/* A phone held sideways (a short, wide screen): the story gets the room. The top bar scrolls away
   with the page instead of staying pinned, and the page-turning bar becomes one slim row (the
   trail beside the buttons instead of above them), so a page shows several lines, not two. */
@media (max-height: 500px) and (orientation: landscape) {
  .topbar { position: relative; }
  .reader:not(.presenter) .reader-bar { flex-wrap: nowrap; gap: 8px; padding: 6px 0; }
  .reader:not(.presenter) .reader-bar > .trail { flex: 1 1 auto; min-width: 60px; max-width: 240px; margin: 0; padding-top: 0; }
  .reader:not(.presenter) .reader-bar > .btn.round:disabled { display: none; }
  .reader:not(.presenter) .page.cover .story-img { max-height: 30vh; width: auto; }
  .reader:not(.presenter) .reader-bar > .btn { flex: none; }
}

/* A class page on a wide screen (tablet sideways, laptop): "Next story days" moves up into the
   Today card's empty top-right corner, beside today's tile and status, instead of a row of its
   own under everything, so the card is shorter and the tab's own content starts higher. */
@media (min-width: 760px) {
  .today-strip.stack:has(> .next-days) { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 24px; row-gap: 12px; align-items: start; }
  .today-strip.stack:has(> .next-days) > * { grid-column: 1; margin-top: 0; }
  .today-strip.stack > .next-days { grid-column: 2; grid-row: 1 / span 3; flex-wrap: wrap; max-width: 200px; justify-content: flex-start; gap: 8px; margin: 0; padding: 10px 12px; border-radius: 16px; background: color-mix(in srgb, var(--card) 70%, transparent); }
  .today-strip.stack > .next-days > .muted { flex: 0 0 100%; font-size: .85rem; }
}

/* My character's treasures on a wider screen: a short last row sits centered under the rows above
   (as with the story picker's topics), instead of stuck to the left beside an empty gap. */
@media (min-width: 521px) {
  .treasure-grid { display: flex; flex-wrap: wrap; justify-content: center; }
  .treasure-grid > .treasure { flex: 0 0 calc((100% - 3 * 10px) / 4); min-width: 0; }
}
@media (min-width: 521px) and (max-width: 700px) { .treasure-grid > .treasure { flex-basis: calc((100% - 2 * 10px) / 3); } }

/* The quick-pick date tiles (Special days, Days off) a touch slimmer, so the six on Special days
   fit one row in the Date column on a tablet or laptop instead of leaving the last one alone. */
.date-quick { gap: 6px; }
.date-quick-btn .date-tile { width: 44px; }

/* Starting treasures on a tablet or computer: four across instead of three huge tiles a row
   (about half the scrolling for 12 items and 10 powers), a short last row centered. */
@media (min-width: 521px) {
  .pack-row + .stack > .choices.with-pics { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; }
  .pack-row + .stack > .choices.with-pics > .choice { flex: 0 0 calc((100% - 3 * 10px) / 4); min-width: 0; }
}

/* Admin and school-admin pages: "New teacher" and its form sit together in their own soft,
   dashed panel under the people list (the heading as its tab), so adding someone reads as a
   separate step instead of more rows of the list. */
.add-panel-head { margin: 22px 0 0 !important; padding: 12px 16px 0; border: 2px dashed var(--line-strong); border-bottom: 0; border-radius: 16px 16px 0 0;
  background: color-mix(in srgb, var(--leaf-soft) 55%, var(--card)); font-size: 1.05rem; }
.add-panel-head + form { margin-top: 0 !important; padding: 12px 16px 16px; border: 2px dashed var(--line-strong); border-top: 0; border-radius: 0 0 16px 16px;
  background: color-mix(in srgb, var(--leaf-soft) 55%, var(--card)); }
.add-panel-head + form input, .add-panel-head + form select { background: var(--card); }

/* The End on a tablet or computer: the prize box is as wide as the story questions under it, so
   the two line up and the prize's words get room (they wrapped into a narrow column beside the
   hero and sunburst). */
@media (min-width: 761px) { .award { max-width: 720px; padding: 18px 24px; gap: 22px; } }

/* Progress, one student's stories: a student still making their character shows the same dashed
   🎨 face beside their name as in the table above (it was a 📖), at the header's size. */
.face-todo.detail-todo { width: 56px; height: 56px; font-size: 1.5rem; flex: none; }

/* Kids' pages: a choice with just two options (glasses or not, English or Spanish) sits as a
   centered pair of modest tiles, instead of two tiles stuck to the left of a wide card. */
main.wrap:not(.wide) .choices:has(> .choice:nth-child(2):last-child) { grid-template-columns: repeat(2, minmax(0, 190px)); justify-content: center; }
main.wrap:not(.wide) .choices.small.with-pics:has(> .choice:nth-child(2):last-child) { grid-template-columns: repeat(2, minmax(0, 150px)); }
main.wrap:not(.wide) .choices.swatches { justify-content: center; }

/* "Its questions are still waiting": on a tablet or computer the card keeps room on its right for
   its big faint question marks, so the sentence never runs under them (it did on an upright iPad). */
@media (min-width: 521px) { .unread-card.quiz-card { padding-right: 110px; } }

/* A class page's header at any width: "Edit class" stays beside the class name, top right (as on
   a phone), instead of dropping onto a row of its own under the fact chips on an upright tablet. */
.row.spread:has(> .stack > .class-page-name) { flex-wrap: nowrap; align-items: flex-start; }
.row.spread:has(> .stack > .class-page-name) > .stack { flex: 1; min-width: 0; }
.row.spread:has(> .stack > .class-page-name) > a.btn { flex: none; }

/* Word hunt at the end of a story: its lines wrap evenly, so a sentence never leaves one word
   ("it!") alone on a line of its own under the rest. */
.word-hunt p, .word-hunt .skill-meaning, .word-hunt-tip { text-wrap: balance; }

/* Help lines and notes everywhere (under form fields, in cards, in lists) wrap without leaving
   one short word alone on their last line ("term.", "it!"), which read like a stray fragment. */
p, li, .field-note, small.muted { text-wrap: pretty; }

/* Who's reading, with many readers on one device (a class tablet): a short last row sits centered
   under the others instead of one name stranded at the left; and on a phone, five or more
   readers go three across with smaller faces, so a whole class needs far less scrolling. */
.who-grid { display: flex; flex-wrap: wrap; justify-content: center; }
.who-grid > .who-card { flex: 0 0 132px; min-width: 0; }
@media (max-width: 520px) {
  .who-grid > .who-card { flex-basis: calc((100% - 12px) / 2); width: auto !important; }
  .who-grid:has(> .who-card:nth-child(5)) { gap: 8px; }
  .who-grid:has(> .who-card:nth-child(5)) > .who-card { flex-basis: calc((100% - 2 * 8px) / 3); }
  .who-grid:has(> .who-card:nth-child(5)) .who-face { width: 60px; height: 60px; font-size: 1.7rem; }
  .who-grid:has(> .who-card:nth-child(5)) .who-face .avatar { width: 56px !important; height: 56px !important; }
  .who-grid:has(> .who-card:nth-child(5)) .who-btn { padding: 10px 4px 9px; gap: 6px; }
  .who-grid:has(> .who-card:nth-child(5)) .who-name { font-size: .9rem; }
  .who-grid:has(> .who-card:nth-child(5)) .who-forget { top: 2px; right: 2px; width: 22px; height: 22px; font-size: .75rem; }
  .who-grid:has(> .who-card:nth-child(5)) .who-btn { padding-top: 14px; }
}

/* Help: a class tab named in the guide is a little copy of the tab (its picture beside its
   name, on the tab bar's tint), and opens that tab. */
.help-tab { display: inline-flex; align-items: center; gap: 4px; padding: 0 8px 0 5px; margin: 0 1px; border-radius: 8px; vertical-align: baseline;
  font-weight: 700; font-size: .92em; line-height: 1.6; color: var(--ink); text-decoration: none; white-space: nowrap;
  background: var(--card-2); border: 1.5px solid var(--line); box-shadow: 0 2px 0 var(--line); transition: border-color .15s, transform .12s; }
a.help-tab:hover { border-color: var(--leaf); transform: translateY(-1px); }
a.help-tab:focus-visible { outline: 3px solid var(--sun); outline-offset: 2px; }
.help-tab-icon { font-size: .95em; }

/* My character: the hero's ring (drawn outside its circle) lines up with the cards' edge below
   instead of poking past it toward the screen edge on a phone. */
.me-head { padding-left: 7px; padding-top: 4px; }

/* The classroom screen on a big display (a 1080p TV or projector): a short page of words (up to
   about 30, as young readers' pages are) grows to fill it (it stopped at 48px, a small block in a
   big empty page, hard to read from the back row), sized by the screen's width and height so it
   still fits a shorter screen; and each answer's A/B/C circle grows with its words. */
.reader.presenter .page:not(.with-img):not(.cover) > .story-text.tiny-text { font-size: clamp(1.6rem, min(4.2vw, 7vh), 4.6rem); }
.reader.presenter .answer::before { width: 1.5em; height: 1.5em; font-size: .9em; }

/* A kid reading on a big computer screen: a short page of words grows with the screen (it stayed
   phone-sized, a small block in the middle of a tall, empty page), sized by both its width and
   height so it still fits a shorter laptop. */
@media (min-width: 1200px) {
  .reader:not(.presenter) .page:not(.with-img) .story-text.tiny-text { font-size: clamp(2.1rem, min(2.2vw, 4.4vh), 2.9rem); }
  .reader:not(.presenter) .page:not(.with-img):not(.cover):has(> .story-text.tiny-text) > .story-text { max-width: 30ch; }
}

/* Classes page on a wide screen: class tiles a little wider (still four across), so a two-word
   name like "Other room" stays on one line and the tiles' rows line up with each other. */
@media (min-width: 900px) { .grid:has(> .class-tile) { grid-template-columns: repeat(auto-fill, minmax(270px, 1fr)); } }

/* My character on a big computer screen: the page uses more of the width (as the home page does),
   so the treasure cards are wide enough for their words instead of tall, narrow columns. */
@media (min-width: 1200px) { .wrap.narrow:has(> .me-head) { max-width: 860px; } }

/* Teacher forms on a big screen (Edit class, New class): the seven picture styles sit in one row
   instead of four and three in the middle of a wide card, so the whole choice is seen at once. */
@media (min-width: 1200px) {
  main.wrap.wide .choices.with-pics:has(> .choice:nth-child(7):last-child) { max-width: calc(7 * 150px + 6 * 12px); flex-wrap: nowrap; }
  main.wrap.wide .choices.small.with-pics:has(> .choice:nth-child(7):last-child) { max-width: calc(7 * 150px + 6 * 10px); }
  main.wrap.wide .choices.with-pics:has(> .choice:nth-child(7):last-child) > .choice { flex: 1 1 0; max-width: 150px; }
}

/* The new-reader wizard on a big computer screen: as wide as My character, so the look step's 12
   hair styles sit in two rows of six (as there) instead of three rows of four in a narrow column. */
@media (min-width: 1200px) { .wrap.narrow:has(> .hero-so-far) { max-width: 860px; } }
/* ...and its starting treasures six across there (two even rows of items, the powers' last four
   centered), instead of four huge tiles a row. */
@media (min-width: 1200px) { .pack-row + .stack > .choices.with-pics > .choice { flex-basis: calc((100% - 5 * 10px) / 6); } }

/* The class epic's stage on a tablet or computer, for a small class (up to 8): the cast stands
   bigger (larger faces and names), filling the stage instead of two small rings in a wide band. */
@media (min-width: 760px) {
  .epic-cast-list:not(:has(> .epic-cast-kid:nth-child(9))) { gap: 12px 28px; }
  .epic-cast-list:not(:has(> .epic-cast-kid:nth-child(9))) > .epic-cast-kid { width: 96px; font-size: .95rem; gap: 6px; }
  .epic-cast-list:not(:has(> .epic-cast-kid:nth-child(9))) > .epic-cast-kid .avatar,
  .epic-cast-list:not(:has(> .epic-cast-kid:nth-child(9))) > .epic-cast-kid .face-todo { width: 80px !important; height: 80px !important; font-size: 1.6rem; }
}

/* A story's cover on a big computer screen: the how-to lines under the title (keys, the turn
   button, Read to me) grow a little with the big cover, instead of small print far below it. */
@media (min-width: 1200px) { .reader:not(.presenter) .page.cover .turn-hint { font-size: 1.1rem; } }

/* Add a student on a wide screen: "+ Add" sits right under the name boxes, beside the pronoun
   choice, instead of below a tall empty gap left by the pronoun column. */
@media (min-width: 900px) {
  form.card.stack:has(> .add-student-grid > .field:nth-child(3)) { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); column-gap: 16px; row-gap: 0; align-items: start; }
  form.card.stack:has(> .add-student-grid > .field:nth-child(3)) > h3 { grid-column: 1 / -1; margin-bottom: 14px; }
  form.card.stack:has(> .add-student-grid > .field:nth-child(3)) > .add-student-grid { display: contents; }
  form.card.stack:has(> .add-student-grid > .field:nth-child(3)) > .add-student-grid > .field:nth-child(3) { grid-column: 3; grid-row: 2 / span 2; }
  form.card.stack:has(> .add-student-grid > .field:nth-child(3)) > div:last-child { grid-column: 1 / span 2; grid-row: 3; margin-top: 12px; }
}

/* The story picker's goals on a big screen: the same size tiles as the topics on the step before
   (six across, the last row centered), instead of four much bigger tiles in a narrower block, so
   the two steps match and the goals need less scrolling. */
@media (min-width: 1000px) {
  .choices.with-pics:not(.small):has(> .choice:nth-child(16):last-child) { display: flex; flex-wrap: wrap; justify-content: center; gap: 12px; max-width: none; }
  .choices.with-pics:not(.small):has(> .choice:nth-child(16):last-child) > .choice { flex: 0 0 calc((100% - 5 * 12px) / 6); min-width: 0; }
}

/* Progress, "could use a nudge": each card's buttons sit along its bottom edge, so cards side by
   side line them up even when one card's reason runs a line longer. */
.nudges li.nudge-card { display: flex; flex-direction: column; gap: 8px; }
.nudges li.nudge-card > .nudge-actions { margin-top: auto; padding-top: 2px; }

/* My character's treasure cards: where each one came from ("Starting treasure", "Earned in …")
   sits along the card's bottom edge, so it lines up across a row instead of floating at
   different heights after descriptions of different lengths. */
.treasure-grid > .treasure { display: flex; flex-direction: column; }
.treasure-grid > .treasure > div:last-child { flex: 1; display: flex; flex-direction: column; align-items: center; }
.treasure-grid > .treasure > div:last-child > .muted:last-child { margin-top: auto; padding-top: 6px; }

/* Progress on a wide screen, "N of M have read today's story": the class's faces sit beside the
   count on the same row (it was a short heading over two small faces in a wide, mostly empty
   card), so the card is shorter and the faces are right next to the number they make up. */
@media (min-width: 900px) {
  #read-today:not(:has(> p)) { display: flex; align-items: center; gap: 12px 28px; flex-wrap: wrap; }
  #read-today:not(:has(> p)) > * { margin-top: 0; }
  #read-today:not(:has(> p)) > .today-faces { flex: 1 1 260px; justify-content: flex-start; padding-left: 24px; border-left: 2px dashed var(--line); }
}

/* Story questions on a tablet or computer: a question whose answers are all short ("A kite",
   "The sun") lays them side by side (three across, or two by two for four), instead of three
   long, mostly empty bars stacked down the page; the questions take about half the scrolling. */
@media (min-width: 760px) {
  .question.short-answers > .answer { display: inline-flex; vertical-align: top; width: calc((100% - (var(--cols) - 1) * 10px) / var(--cols)); margin-right: 10px; }
  .question.short-answers[style*="--cols: 2"] > .answer:nth-of-type(2n),
  .question.short-answers[style*="--cols: 3"] > .answer:nth-of-type(3n) { margin-right: 0; }
}

/* Class epic form: the skills' "check mark means usual for this grade" line sits right under its
   "Reading skills to practice" heading (a paragraph margin left a gap that made it look detached),
   with the same small space as the other headings and their notes. */
.stack > h4 + .skill-box { margin-top: -14px; }
.skill-box > p:first-child { margin: 0 0 10px; }
/* ...and three-option choices too (he / she / just my name), centered like the picture styles above. */
@media (min-width: 521px) { main.wrap:not(.wide) .choices:not(.swatches):has(> .choice:nth-child(3):last-child) { grid-template-columns: repeat(3, minmax(0, 150px)); justify-content: center; } }

/* QR cards on screen: the cards sit centered under the how-to note (a class of two left them in
   the left corner of a wide, empty page); printing keeps its own sheet layout. */
@media screen and (min-width: 521px) { .cards { grid-template-columns: repeat(auto-fit, minmax(230px, 250px)); justify-content: center; } }

/* The start page on a big computer screen, with readers saved: as wide as My character, so
   "Who's reading?" fits more names a row (nine in two rows instead of three, no one left alone). */
@media (min-width: 1200px) { .wrap.narrow:has(.who-grid) { max-width: 860px; } }

/* Help on a big screen: the section chips become a sidebar that stays in view beside the guide
   (they were a block at the top that scrolled away, with empty space either side of a narrow
   column), so any section is one click away from anywhere in it. */
@media (min-width: 1280px) {
  .stack.wrap.narrow:has(> .help-toc) { max-width: 1080px; display: grid; grid-template-columns: 260px minmax(0, 1fr); column-gap: 32px; row-gap: 14px; align-items: start; }
  .stack.wrap.narrow:has(> .help-toc) > * { grid-column: 2; margin-top: 0; }
  .stack.wrap.narrow:has(> .help-toc) > h1, .stack.wrap.narrow:has(> .help-toc) > h1 + p { grid-column: 1 / -1; }
  .stack.wrap.narrow:has(> .help-toc) > .help-toc { grid-column: 1; grid-row: 3 / span 10; position: sticky; top: calc(var(--topbar-h, 68px) + 16px);
    display: flex; flex-direction: column; flex-wrap: nowrap; gap: 6px; }
  .stack.wrap.narrow:has(> .help-toc) > .help-toc > .help-chip { justify-content: flex-start; width: 100%; text-align: left; }
  .stack.wrap.narrow:has(> .help-toc) > .help-up { display: none; }
}

/* My character on a big screen: the jump buttons become a sidebar that stays in view beside the
   page (as on the teachers' Help), each colored icon beside its name, so a kid deep in Look can
   hop to Picture style without scrolling back up. */
@media (min-width: 1280px) {
  .wrap.narrow:has(> .me-head) { max-width: 1120px; display: grid; grid-template-columns: 220px minmax(0, 1fr); column-gap: 28px; row-gap: 0; align-items: start; }
  .wrap.narrow:has(> .me-head) > * { grid-column: 2; }
  .wrap.narrow:has(> .me-head) > .me-head { grid-column: 1 / -1; }
  .wrap.narrow:has(> .me-head) > .me-jumps { grid-column: 1; grid-row: 2 / span 9; position: sticky; top: calc(var(--topbar-h, 68px) + 16px);
    display: flex; flex-direction: column; gap: 8px; }
  .wrap.narrow:has(> .me-head) > .me-jumps > .jump-tile { flex-direction: row; justify-content: flex-start; gap: 10px; min-height: 52px; padding: 6px 12px 6px 6px; font-size: .9rem; text-align: left; border-radius: 999px; }
  .wrap.narrow:has(> .me-head) > .me-jumps > .jump-tile[style*="--hue"] { background: linear-gradient(90deg, hsl(var(--hue) 80% 95%), var(--card) 75%); }
  .wrap.narrow:has(> .me-head) > .me-jumps > .jump-tile .jump-icon { flex: none; width: 2.2em; height: 2.2em; font-size: 1.05rem; }
  .wrap.narrow:has(> .me-head) > .help-up { display: none; }
}
@media (min-width: 1280px) and (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .wrap.narrow:has(> .me-head) > .me-jumps > .jump-tile[style*="--hue"] { background: linear-gradient(90deg, hsl(var(--hue) 30% 20%), var(--card) 75%); } }
@media (min-width: 1280px) { :root[data-theme="dark"] .wrap.narrow:has(> .me-head) > .me-jumps > .jump-tile[style*="--hue"] { background: linear-gradient(90deg, hsl(var(--hue) 30% 20%), var(--card) 75%); } }

/* A class page (and Admin) on a computer or sideways tablet: the tab bar stays pinned just under
   the top bar while you scroll a long tab (Topics & skills, Progress), so switching to another
   tab never means scrolling back up first. */
@media (min-width: 900px) and (min-height: 600px) {
  .tabs[role="tablist"] { position: sticky; top: calc(var(--topbar-h, 68px) + 8px); z-index: 6;
    background: color-mix(in srgb, var(--card-2) 92%, transparent); -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
    box-shadow: 0 8px 18px -12px rgba(40, 60, 30, .35); }
}

/* Dark mode: the little fans of painted topic pictures (Today's story, the start page, the teacher
   sign-in) wear soft paper-colored frames and are dimmed a touch, like every other painted
   picture in dark mode, instead of bright white frames glaring off the dark page. */
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) :is(.today-fan, .topic-strip) img { border-color: #cfc7b2; background: #cfc7b2; filter: brightness(.86) saturate(.95); } }
:root[data-theme="dark"] :is(.today-fan, .topic-strip) img { border-color: #cfc7b2; background: #cfc7b2; filter: brightness(.86) saturate(.95); }

/* Add special day: the note (a sentence students read) gets the full width of the form, so a
   message is seen whole as it's typed, instead of a narrow box in one column with the other
   two columns empty beside it. */
.form-grid > .special-note { grid-column: 1 / -1; }

/* "Your hero is bringing along their treasures" on a tablet or computer: the "+3 more" pill is a
   compact "+3" bubble, so it stays on the row with the treasures instead of wrapping alone onto
   a line of its own (it did in Spanish, "+3 más"). */
@media (min-width: 521px) {
  .bringing .pill.more-pill { padding: 0 12px !important; min-width: 44px; justify-content: center; }
  .bringing .pill.more-pill .more-words { display: none; }
  .bringing .pill.more-pill::after { content: attr(data-n); font-weight: 900; }
}

/* A teacher opening a story (not the classroom screen): the cover picture leaves room for the
   story's details card above it, so the whole cover (picture, title, Starring) shows above the
   page controls instead of running under them on a laptop or 1080p screen. */
@media (min-width: 700px) {
  main:has(.story-about) .reader:not(.presenter) .cover .story-img { height: clamp(140px, calc(100vh - 680px), 540px); }
}

/* My character's Look on a big screen (beside the jump sidebar): the 12 hair styles sit in two
   even rows of six, instead of five a row that left two alone at the left of a third row. */
@media (min-width: 1000px) {
  .choices.with-pics:has(> .choice .choice-art .avatar):has(> .choice:nth-child(12):last-child) { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); }
}
/* ...and the pinned bar spans the page's width (its buttons still at the left), so the page
   scrolling under it never peeks out beside a short bar (Admin's "+ Add" did). */
@media (min-width: 900px) and (min-height: 600px) { .tabs[role="tablist"] { width: 100%; } }

/* The End's prize: the painted treasure fills the middle of its sunburst (the paintings have a
   wide empty margin, which left a tiny telescope lost in the rays), zoomed in on the treasure. */
.award-prize img.award-pic { object-fit: cover; object-view-box: inset(16%); }

/* A story that isn't on this kid's shelf: their shelf of colorful books with a dashed gap and a
   "?" where that book would stand (instead of a lone emoji). */
.missing-shelf .shelf-book { display: block; width: 30px; border-radius: 5px 5px 3px 3px; background: linear-gradient(90deg, color-mix(in srgb, var(--c) 80%, #000) 0 4px, var(--c) 4px);
  box-shadow: inset 0 10px 0 -6px rgba(255, 255, 255, .45), inset 0 -14px 0 -10px rgba(255, 255, 255, .45); }
.missing-shelf .shelf-book.b0 { height: 76px; } .missing-shelf .shelf-book.b1 { height: 90px; rotate: 6deg; transform-origin: 50% 100%; }
.missing-shelf .shelf-book.b3 { height: 84px; } .missing-shelf .shelf-book.b4 { height: 70px; }
.missing-shelf .ghost-book.g2 { border-style: dashed; color: var(--leaf-dark); }

/* Teacher "That page isn't here": a centered card with a little scene, a page (two lines and a
   heading) drifting off its dashed spot like a falling leaf, instead of a wide bare card. */
.gone-card { max-width: 560px; margin-left: auto; margin-right: auto; }
.gone-scene { position: relative; width: 140px; height: 104px; margin: 4px auto 0; }
.gone-slot { position: absolute; left: 22px; top: 14px; width: 62px; height: 80px; border-radius: 8px; border: 2px dashed var(--line-strong); }
.gone-page { position: absolute; left: 50px; top: 6px; width: 62px; height: 80px; border-radius: 8px; padding: 12px 10px; display: grid; gap: 7px; align-content: start;
  background: var(--card); border: 2px solid var(--line-strong); box-shadow: 0 8px 16px -8px rgba(40, 60, 30, .45); rotate: 14deg; animation: gone-drift 3.6s ease-in-out infinite; }
.gone-page i { display: block; height: 5px; border-radius: 999px; background: var(--line); }
.gone-page i:first-child { width: 70%; height: 7px; background: color-mix(in srgb, var(--leaf) 45%, var(--line)); }
.gone-leaf { position: absolute; right: 0; bottom: 0; font-size: 1.6rem; rotate: -20deg; }
@keyframes gone-drift { 50% { translate: 6px -5px; rotate: 20deg; } }
@media (prefers-reduced-motion: reduce) { .gone-page { animation: none; } }

/* Reading level on a laptop or bigger: 1st-12th grade four across (three even rows under
   Kindergarten) instead of three across in four rows, so the whole choice fits in view. */
@media (min-width: 1000px) {
  .choices:has(> .choice[class*="lvl-"][data-value="0"]):has(> .choice[class*="lvl-"][data-value="12"]) { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* Class form: "Kids can read from" and "up to" sit side by side, and the K-12 dots run under the
   pair (they draw both ends), instead of hanging under "up to" alone. */
.range-field { display: grid; gap: 6px; min-width: 0; }
.range-field-pair { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.range-field .range-ribbon { padding-top: 4px; }
.range-field .rr-dot { max-width: 30px; }
@media (min-width: 900px) { .form-grid > .range-field { grid-column: span 2; } }

/* "What grade are you in?" on a laptop or bigger: 1st-12th grade four across (three rows under
   Kindergarten, as the reading levels), so Next stays in view on a 768-tall screen. */
@media (min-width: 1000px) {
  .choices.small:has(> .grade-tile[data-value="0"]):has(> .grade-tile[data-value="12"]) { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
/* ...each grade's number circle beside its name (as Kindergarten's), so the rows are shorter. */
@media (min-width: 1000px) {
  .choices.small:has(> .grade-tile[data-value="0"]):has(> .grade-tile[data-value="12"]) > .grade-tile { flex-direction: row; justify-content: center; gap: 12px; min-height: 0; padding-top: 8px; padding-bottom: 8px; }
}

/* The classroom screen's "Show the answer" sits on its question's own line, beside the speaker,
   instead of a row of its own under the answers (each question is a row shorter). */
.question legend > .reveal-answer { flex: none; margin: -6px 0 0 auto; }
.question legend > .reveal-answer + .hear-it { margin-left: 10px; }

/* The End on a tablet or computer: the word hunt is as wide as the story questions and the prize
   box above it (it was narrower, so the page's three boxes didn't line up), and its how-to line
   gets room to sit on one line. */
@media (min-width: 761px) { .reader:not(.presenter) .word-hunt { max-width: 720px; padding: 16px 24px; } }

/* Admin's reader page on a phone: the hero sits beside the name (smaller) instead of on a row of
   its own above it, and the treasure list's backpack sits at the top of its card, not floating
   halfway down beside a tall column of pills. */
@media (max-width: 520px) {
  .reader-banner { flex-direction: row; align-items: flex-start; gap: 12px; }
  .reader-banner .me-hero { width: 72px; height: 72px; }
  .reader-banner .me-hero .avatar { width: 60px !important; height: 60px !important; }
  .reader-banner > .stack > .fact-chips { margin-left: -84px; }
  .treasure-strip { align-items: flex-start; }
}

/* Add special day on a laptop or wider: the two kind cards (team-up, class epic) line up with the
   form's columns below them, each as wide as the Date and Team size boxes, instead of two
   narrower cards that matched nothing. */
@media (min-width: 900px) {
  .kind-picker { max-width: none; grid-template-columns: repeat(auto-fill, minmax(min(100%, 290px), 1fr)); column-gap: 16px; }
}

/* Dark mode, starting treasures: each painted treasure sits in the same soft round glow as on My
   character, instead of a hard cream square (which, with the bag full and the rest dimmed, made
   a grid of gray boxes). */
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .pack-row + .stack > .choices.with-pics .choice-img { border-radius: 50%; background: transparent;
  -webkit-mask-image: radial-gradient(circle closest-side, #000 62%, transparent 100%); mask-image: radial-gradient(circle closest-side, #000 62%, transparent 100%); } }
:root[data-theme="dark"] .pack-row + .stack > .choices.with-pics .choice-img { border-radius: 50%; background: transparent;
  -webkit-mask-image: radial-gradient(circle closest-side, #000 62%, transparent 100%); mask-image: radial-gradient(circle closest-side, #000 62%, transparent 100%); }

/* Topics & skills on a laptop or bigger: the topic and goal pictures nine across, so the 26 topics
   take three rows instead of four (9, 9, 8) and the 16 goals two (9, 7), a shorter form. */
@media (min-width: 1200px) { .choices.small.with-pics:has(> .choice:nth-child(13)) > .choice { flex-basis: calc((100% - 8 * 10px) / 9); } }

/* My character's sidebar (big screens): the part being read is lit, its button standing out in its
   own color with a little pointer, so the kid sees where they are on the long page. */
@media (min-width: 1280px) {
  .wrap.narrow:has(> .me-head) > .me-jumps > .jump-tile.here { border-color: hsl(var(--hue) 55% 55%); box-shadow: 0 3px 0 hsl(var(--hue) 50% 45%), 0 0 0 4px hsl(var(--hue) 70% 85% / .6); transform: translateX(6px); }
  .wrap.narrow:has(> .me-head) > .me-jumps > .jump-tile { transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease; }
}
@media (min-width: 1280px) and (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .wrap.narrow:has(> .me-head) > .me-jumps > .jump-tile.here { box-shadow: 0 3px 0 hsl(var(--hue) 40% 30%), 0 0 0 4px hsl(var(--hue) 40% 40% / .5); } }
@media (min-width: 1280px) and (prefers-reduced-motion: reduce) { .wrap.narrow:has(> .me-head) > .me-jumps > .jump-tile.here { transform: none; } }

/* Help's sidebar (big screens): the section being read is lit in its own color with a soft ring,
   so it's clear where you are in the guide. */
@media (min-width: 1280px) {
  .stack.wrap.narrow:has(> .help-toc) > .help-toc > .help-chip.here { border-color: hsl(var(--hue) 55% 50%); background: hsl(var(--hue) 70% 95%);
    box-shadow: 0 3px 0 hsl(var(--hue) 50% 45%), 0 0 0 4px hsl(var(--hue) 70% 85% / .6); transform: translateX(6px); }
}
@media (min-width: 1280px) and (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .stack.wrap.narrow:has(> .help-toc) > .help-toc > .help-chip.here { background: hsl(var(--hue) 30% 20%); box-shadow: 0 3px 0 hsl(var(--hue) 40% 30%), 0 0 0 4px hsl(var(--hue) 40% 40% / .5); } }
@media (min-width: 1280px) and (prefers-reduced-motion: reduce) { .stack.wrap.narrow:has(> .help-toc) > .help-toc > .help-chip.here { transform: none; } }

/* My character's Reading badges: the sticker road to the next badge sits centered over the row of
   medals it leads to, instead of stuck to the left above a centered row. */
#me-badges .next-badge-line { justify-content: center; }

/* "Your changes save by themselves": when the line wraps (a phone), its little cloud stays beside
   the first line instead of floating between the two. */
.autosave-note { align-items: flex-start; }
.autosave-note .autosave-icon { margin-top: 1px; }

/* "The story writer isn't set up" (Classes, Class epics): its headline bold, the why and how-to in
   plain weight, the setting's name as code, instead of one heavy bold block. */
.ends-soon.notice-lead { font-weight: 500; }
.ends-soon.notice-lead strong { font-weight: 800; }
.ends-soon.notice-lead code { font-size: .85em; padding: 1px 6px; border-radius: 6px; background: color-mix(in srgb, var(--card) 70%, transparent); border: 1px solid color-mix(in srgb, var(--sun) 40%, transparent); overflow-wrap: anywhere; }

/* Evening greeting: the few tiny dots of "stars" (which on a phone landed on the heading's words
   and looked like specks) become a small cluster of real twinkling stars in the card's top corner,
   clear of the words. */
.me-card.sky-evening { position: relative; background: linear-gradient(160deg, var(--card) 40%, #ece6fb 100%); }
.me-card.sky-evening::after { content: "✦ ✧\A  ✦"; white-space: pre; position: absolute; top: 10px; right: 14px; pointer-events: none;
  font-size: .8rem; line-height: 1.1; letter-spacing: 2px; color: #a58fe0; opacity: .85; animation: dusk-twinkle 3.2s ease-in-out infinite; }
@keyframes dusk-twinkle { 50% { opacity: .35; } }
@media (prefers-reduced-motion: reduce) { .me-card.sky-evening::after { animation: none; } }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .me-card.sky-evening { background: linear-gradient(160deg, var(--card) 40%, #2b2445 100%); }
  :root:not([data-theme="light"]) .me-card.sky-evening::after { color: #e8e0ff; } }
:root[data-theme="dark"] .me-card.sky-evening { background: linear-gradient(160deg, var(--card) 40%, #2b2445 100%); }
:root[data-theme="dark"] .me-card.sky-evening::after { color: #e8e0ff; }

/* Start page on a computer: "How Hojas works" runs left to right as a little path, the four step
   pictures in a row joined by a dashed trail and each step's words under its picture, instead of
   a tall list (the page is a touch wider there to give each step room). */
@media (min-width: 1200px) {
  .wrap.narrow:has(.how-steps) { max-width: 860px; }
  .how-steps { grid-template-columns: repeat(4, minmax(0, 1fr)); column-gap: 18px; }
  .how-steps li { flex-direction: column; align-items: center; text-align: center; gap: 10px; padding-bottom: 0; }
  .how-steps li > span:last-child { padding-top: 0; font-size: .95rem; }
  .how-steps li:not(:last-child)::before { left: calc(50% + 34px); right: calc(-50% + 16px); top: 26px; bottom: auto; border-left: 0; border-top: 3px dashed var(--line-strong); }
}
/* ...lined up with the form's left edge, under its "Picture style" label, like every other field. */
@media (min-width: 1200px) { main.wrap.wide .choices.with-pics:has(> .choice:nth-child(7):last-child) { margin-left: 0; justify-content: flex-start; } }

/* QR cards: a name pill without a hero face is as tall as one with a face, so on a printed sheet
   every card's code and steps sit at the same height (a face pushed its card's code lower). */
.qr-card .name { box-sizing: border-box; min-height: 46px; align-items: center; }
.qr-card .name:not(.with-face) { display: flex; }

/* Printing a table (Progress, Students, Stories): the whole table fits the page width (no cut-off
   last column or printed scrollbar), its header repeats on each page, and a student's row is never
   split across pages; the pinned tab-bar styling doesn't print. */
@media print {
  .table-wrap { overflow: visible !important; }
  .table-wrap table { width: 100%; table-layout: auto; font-size: .82rem; }
  .table-wrap th, .table-wrap td { padding: 6px 6px; }
  .table-wrap thead { display: table-header-group; }
  .table-wrap tr { break-inside: avoid; page-break-inside: avoid; }
  .days-bar, .meter-cell progress { max-width: 70px; }
}

/* A story page printed from the browser (Ctrl+P): the page-turning bar and the on-screen how-to
   lines (keys, Read to me) don't print, so the bar isn't laid over the title and the page is just
   the story; "Print or keep it (PDF)" makes the whole book. */
@media print {
  .reader-bar, .turn-hint, .last-page-hint, .hunt-line { display: none !important; }
}

/* Printing the Students or Stories tab: the parts for working on screen (Add a student, Print QR
   cards, each row's Progress and ⋯ buttons, the stories' search and kind filter) are left off, so
   the sheet is just the class list; the reading range and pronoun menus print as plain text. */
@media print {
  form.card.stack:has(> .add-student-grid), .row:has(> a[href*="#/cards/"]), td.cell-actions, th:last-child:empty,
  .story-filter-row { display: none !important; }
  .table-wrap td select { appearance: none; -webkit-appearance: none; border: 0; background: none; padding: 0; min-width: 0; min-height: 0; box-shadow: none; }
  .cell-range .range-pair .range-dash { display: none !important; }
  .cell-range .range-pair { gap: 2px; }
}

/* Printing: everything shows in its finished state, so a picture or face that pops in on screen
   (like the hero's face in a story cover's "Starring" badge) isn't caught mid-animation and
   left out of the printout. */
@media print { *, *::before, *::after { animation: none !important; transition: none !important; } }

/* Printing any page: the parts for working on screen (forms to add things, buttons, quick-pick date
   tiles) are left off; nothing on paper can be tapped, so the sheet is just what's set up. */
@media print {
  main form, main .btn, main .date-quick, main details:has(> form) { display: none !important; }
}

/* Printing (the kids' pages): a shelf of books, a card and each treasure stay whole on one page
   instead of a book being sliced in two at the page break. */
@media print {
  .shelf > *, main:not(.wide) .card, .stat-card, .treasure, .award, .question, .reading-badge { break-inside: avoid; page-break-inside: avoid; }
  .shelf-group:not(:has(> .shelf > :nth-child(9))) { break-inside: avoid; page-break-inside: avoid; display: block; }
  .shelf-group > * + * { margin-top: 14px; }
}

/* Printing Help: the guide flows from page to page (a long section may continue onto the next
   page, its heading kept with its first lines) instead of each section jumping to a new sheet and
   leaving most pages half empty; the section chips, which do nothing on paper, are left off. */
@media print {
  .help-toc { display: none !important; }
  .card.help-section { break-inside: auto; page-break-inside: auto; }
  .help-section .help-head { break-after: avoid; page-break-after: avoid; }
  .help-section p { orphans: 3; widows: 3; }
}

/* Printing My character: the jump buttons (nothing to tap on paper) are left off, and each set of
   choices stays whole on one page with its heading, instead of "Hair style" or "Glasses" left
   alone at the foot of a page with its pictures on the next. */
@media print {
  .me-jumps { display: none !important; }
  .card.me-section:not(#me-look) { break-inside: avoid; page-break-inside: avoid; }
  #me-look.card { break-inside: auto; page-break-inside: auto; }
  .choices { break-inside: avoid; page-break-inside: avoid; }
  h2, h3 { break-after: avoid; page-break-after: avoid; }
}

/* Printing Admin: the "New teacher" heading (its form doesn't print) and the cost card's round "?"
   are left off, and the long lists may continue onto the next page instead of jumping whole to a
   new one and leaving half a page empty. */
@media print { .add-panel-head, .actions-help > summary { display: none !important; } }

/* Printing the bookshelf: the faint dashed "books still to come" (an on-screen nudge) are left
   off, so the paper shows only the stories read. */
@media print { .ghost-slot { display: none !important; } }

/* Keyboard focus, everywhere (kids' and teachers' pages): any link or button that hasn't a ring of
   its own gets the same sunny one as the choice tiles (a bookshelf book showed the browser's thin
   black line), so a kid moving with Tab or a switch always sees where they are. */
:where(a, button, summary, [tabindex]):focus-visible { outline: 3px solid var(--sun); outline-offset: 3px; }
a.book:focus-visible { outline-offset: 4px; border-radius: 16px; }

/* With the tab bar pinned under the top bar (computer, sideways tablet), the browser keeps
   whatever gets keyboard focus, or is jumped to, below both bars instead of half hidden under
   them. */
@media (min-width: 900px) and (min-height: 600px) {
  html:has(.tabs[role="tablist"]) { scroll-padding-top: calc(var(--topbar-h, 68px) + 84px); }
}

/* The look editor (My character, the new-reader wizard): its hero stays pinned under the top bar
   while the kid scrolls the choices, so a choice getting keyboard focus is kept below the pinned
   hero instead of hidden behind it. */
:has(> .look-preview) .choice { scroll-margin-top: calc(var(--topbar-h, 68px) + 96px); }

/* A form with Save and Cancel pinned to the bottom of the screen (New class, Edit class): the
   browser keeps whatever gets keyboard focus above that bar instead of hidden behind it. */
html:has(.form-savebar) { scroll-padding-bottom: 96px; }

/* A class page on a phone with big text: when the class name needs the room, "Edit class" steps
   down a line instead of sitting on top of the name. At normal sizes they still share a row. */
@media (max-width: 520px) {
  .row.spread:has(> .stack > .class-page-name) { flex-wrap: wrap; row-gap: 10px; }
  .row.spread:has(> .stack > .class-page-name) > .stack { flex: 1 1 8rem; }
}

/* Small phones with big text: the language menu and the Me button stay side by side as a pair.
   When the pair can't fit beside the logo, it moves down to its own row together (as on a larger
   phone) instead of stacking into a tall column of two. */
@media (max-width: 360px) {
  .topbar:has(#topbar-extra) { flex-wrap: wrap; }
  #topbar-extra { flex: none; }
  #topbar-extra > .row { flex-wrap: nowrap; }
}
/* The 🍃 logo's tile grows with the leaf when text is made bigger, so the leaf stays inside it. */
.brand .logo { width: max(40px, 1.9em); height: max(40px, 1.9em); }

/* A tablet held upright: a short page of words (up to about 30) grows into the tall page instead
   of staying a three-line strip in the middle of it. Sized by width and height, so a tablet on
   its side keeps the size it had. */
@media (min-width: 700px) and (max-width: 1199px) {
  .reader:not(.presenter) .page:not(.with-img) .story-text.tiny-text { font-size: clamp(2.1rem, min(5.4vw, 4.4vh), 2.7rem); }
  .reader:not(.presenter) .page:not(.with-img):not(.cover):has(> .story-text.tiny-text) > .story-text { max-width: 30ch; }
}

/* The classroom screen's word hunt: its lines (what the skill is, the example, how to play) are
   as readable from the back row as the questions above them, and its find-dots grow to match. */
.reader.presenter .word-hunt p { font-size: clamp(1.25rem, 2.3vw, 2rem); }
.reader.presenter .word-hunt .skill-meaning { max-width: 30em; padding: 10px 18px; }
.reader.presenter .hunt-dots { gap: 12px; }
.reader.presenter .hunt-dots > span { width: 38px; height: 38px; }
.reader.presenter .hunt-dots > span::after { font-size: 1.05rem; }
.reader.presenter .hunt-dots > span.got::after { font-size: 1.25rem; }
/* The yellow skill note hugs its words: balanced lines left an empty strip at its right edge. */
.word-hunt .skill-meaning { text-wrap: pretty; }

/* The "Your story" recipe (topic + goal): its pictures melt into their green cards with the same
   soft feather the picker tiles use, instead of showing their paper as a pale square. */
.pick-review-part:not(.hero) 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"]) .pick-review-part:not(.hero) img { -webkit-mask-image: none; mask-image: none; border-radius: 12px; } }
:root[data-theme="dark"] .pick-review-part:not(.hero) img { -webkit-mask-image: none; mask-image: none; border-radius: 12px; }

/* A student's own reading range on a wide screen (the two menus side by side): the same small
   round → badge the stacked layout uses sits between them, instead of a plain dash. */
@media screen and (min-width: 1181px) {
  .cell-range .range-pair { align-items: center; gap: 6px; }
  .cell-range .range-pair .range-dash { display: grid; place-items: center; flex: none; width: 22px; height: 22px; border-radius: 50%;
    font-size: 0; background: var(--leaf-soft); }
  .cell-range .range-pair .range-dash::after { content: "→"; font-size: .8rem; font-weight: 900; color: var(--leaf-dark); line-height: 1; }
}

/* Picture-style samples show the style itself, background and all (the comic's panel frame, the
   pixel art's sky): crisp little rounded cards instead of the soft feather the topic paintings get. */
.choices.with-pics .choice-img[src*="/styles/"] { -webkit-mask-image: none; mask-image: none; mix-blend-mode: normal;
  border-radius: 10px; box-shadow: 0 0 0 1px var(--line), 0 3px 8px -4px rgba(40, 60, 30, .35); }

/* The Admin and School dashboards on a phone: the number tiles sit two by two (four tall cards
   took four screens of scrolling), the colored chip above its label so both fit a half-width tile. */
@media (max-width: 520px) {
  .stat-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .stat-grid > .stat-card { padding: 14px 12px 12px; }
  .stat-grid > .stat-card > .stat-label { flex-direction: column; align-items: flex-start; gap: 6px; padding-right: 26px; line-height: 1.25; }
  .stat-grid > .stat-card > .stat-label .stat-icon { width: 32px; height: 32px; border-radius: 10px; font-size: 1.05rem; }
  .stat-grid > .stat-card > .stat-label .muted { font-size: .82rem; }
  .stat-grid > .stat-card .muted { font-size: .82rem; }
  .stat-grid > .stat-card > .stat-help { top: 10px; right: 10px; }
}

/* A card that opens with a paragraph (the library template's "This is how the story reads"):
   the card's own padding is the top space, so the paragraph doesn't add a blank strip above it. */
.card > p:first-child { margin-top: 0; }

/* Touch screens: the small chips and links teachers tap on a phone (the class's Topics & skills
   chip, "See who ›", the Stories tab's kind filters, a story's "Didn't work" pill; a kid's "See all my treasures") keep their
   size but get an invisible ring of extra tap room, so a thumb lands on them the first time. */
@media (pointer: coarse) {
  :is(a.set-chip, button.kind-chip, summary.status-pill, .with-ring > span > a, a.award-more) { position: relative; }
  :is(a.set-chip, button.kind-chip, summary.status-pill, .with-ring > span > a, a.award-more)::before { content: ""; position: absolute; inset: -8px -3px; }
}

/* Filter chips that aren't picked (Solo, Team-up, Open mode, Ready…): drained of color instead of
   faded, so their words stay crisp and readable (fading took small text below easy-reading
   contrast). The picked chip keeps its color, outline and lift, so it still stands out. */
.kind-chip:not(.on) { opacity: 1; filter: saturate(.25); }
.kind-chip:not(.on):hover { filter: none; }
@media (prefers-reduced-motion: no-preference) { .kind-chip { transition: transform .1s, filter .15s; } }

/* Dark theme date tiles: the month band turns a bright green (or pink), so its letters go dark
   instead of white, readable at a glance instead of glowing into the band. */
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .date-tile-month { color: #10200e; } }
:root[data-theme="dark"] .date-tile-month { color: #10200e; }

/* The story picker's steps not reached yet: a see-through card with a dashed outline, its words
   muted but readable (fading the whole step made "Goal" and "Write it!" hard to read), so the
   kid can see what's coming while it still clearly isn't open yet. */
.pick-steps li.locked button { opacity: 1; background: transparent; border-style: dashed; border-color: var(--line-strong); box-shadow: none; color: var(--muted); }
.pick-steps li.locked .pick-step-num { background: transparent; }
/* ...and in the dark theme, the step you're on has a bright green circle, so its number is dark. */
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .pick-steps li.now .pick-step-num { color: #10200e; } }
:root[data-theme="dark"] .pick-steps li.now .pick-step-num { color: #10200e; }

/* Dark theme: a past special day's tile has a dim gray band, so its month letters stay light
   (the dark letters are only for the bright green and pink bands)... */
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .special-row.muted .date-tile-month { color: var(--ink); } }
:root[data-theme="dark"] .special-row.muted .date-tile-month { color: var(--ink); }
/* ...and a red "Remove" button's words are a lighter red, readable on the dark card. */
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .btn.danger { color: #ff8f86; } }
:root[data-theme="dark"] .btn.danger { color: #ff8f86; }

/* Dark theme: the little ▶ in the "tap ▶ to turn the page" hints sits on a bright green dot, so
   it's dark, like the other marks on bright green. */
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .mini-turn { color: #10200e; } }
:root[data-theme="dark"] .mini-turn { color: #10200e; }
/* The reading levels' warm "challenge" cards: their small caption ("Big challenge") is a touch
   stronger than plain muted gray, so it stays readable on the orange. */
.choice[class*="lvl-heat"] .sub { color: color-mix(in srgb, var(--muted) 72%, var(--ink)); }

/* The dashboards' tiles two by two on a phone: a tile's "?" explanation opens across the full
   width under its tile, lined up with the tile grid's edges, instead of running off the left side
   (it opened leftward from the button, which only fit when each tile was a whole row). */
@media (max-width: 520px) {
  .stat-grid > .stat-card > .stat-help > ul { width: calc(100vw - 24px); max-width: none; box-sizing: border-box; }
  .stat-grid > .stat-card:nth-child(odd) > .stat-help > ul { left: calc(38px - (100vw - 34px) / 2); right: auto; }
  .stat-grid > .stat-card:nth-child(even) > .stat-help > ul { left: auto; right: -10px; }
}

/* The story picker's step boxes on a phone: what was chosen ("Rescatar a un amigo o amiga") may
   take two short lines under the step name instead of being cut off with "…". */
@media (max-width: 520px) {
  .pick-step-chosen { white-space: normal; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2;
    text-wrap: balance; line-height: 1.15; overflow-wrap: anywhere; }
}

/* The template page's "story / blanks" switch on a phone: it spans the card and each half may
   wrap its label onto two short lines, so a longer label ("Mostrar los espacios") stays inside
   the card instead of poking past its edge. */
@media (max-width: 520px) {
  .view-switch { display: grid; width: 100%; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); box-sizing: border-box; }
  .view-switch > button { white-space: normal; text-wrap: balance; line-height: 1.2; }
}

/* A bookshelf card's badge with a long label ("Preguntas pendientes") folds onto two lines inside
   its pill on every screen, not only the smallest phones, instead of being cut off with "…". */
.book-badges .badge { white-space: normal; text-overflow: clip; line-height: 1.2; border-radius: 10px; text-align: left; }

/* Tablets and small laptops too: the button row can wrap there (it does in Spanish), leaving the
   "?" at the start of a line, where a card opening leftward from it ran off the screen. So up to
   1100px the "?" card spans the button row under it, as on a phone. */
@media (min-width: 761px) and (max-width: 1100px) {
  .row:has(> .actions-help) { position: relative; }
  .actions-help { position: static; }
  .actions-help > ul { left: 0; right: 0; width: auto; }
}

/* My character's two small buttons under Done ("Cambiar quién lee", "Mi enlace y código QR"):
   with big text (or longer words) each wraps its label inside itself instead of pushing past the
   screen edge. At normal sizes they stay one line each. */
@media (max-width: 520px) {
  .me-actions { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .me-actions > .btn:not(.primary) { white-space: normal; text-wrap: balance; min-width: 0; border-radius: min(999px, 1.3em); }
}

/* "Just use my name" on the kid's side: a long name (Maximiliano, Christopher) shrinks to fit its
   name-tag sticker instead of being cut off ("Chri…"); the card's width is the measure. */
.choice:has(> .name-tag), .choice:has(.name-tag-name[style*="--len"]) { container-type: inline-size; }
.name-tag-name[style*="--len"] { font-size: clamp(.6rem, calc((100cqi - 24px) / (var(--len) * .6)), 1rem); padding-left: min(8px, 1.2cqi + 2px); padding-right: min(8px, 1.2cqi + 2px); }

/* The roster on a wide screen: a long student name (Maximiliana-Guadalupe R.) wraps onto two lines
   in its column instead of stretching the table past its card, which hid the ⋯ menu at the right
   edge behind a sideways scroll. Short names stay on one line. */
@media (min-width: 641px) {
  td.cell-name > .student-name strong { white-space: normal; width: max-content; max-width: 9.5em; overflow-wrap: break-word; text-wrap: balance; line-height: 1.25; }
}

/* The bookshelf's last row, when it isn't full: its wooden plank still runs the shelf's whole
   width (it stopped under the last book, a stub of a shelf), so every row looks like a real shelf. */
.shelf { overflow-x: clip; overflow-clip-margin: 8px; }
.shelf > .shelf-slot:last-child::after { right: -100vw; }

/* Progress on a phone for a full class (more than 12 students): the "read today" faces pack into
   a tighter grid (smaller faces, six to a row), so the class fits in about half the scrolling and
   the nudges and table below are reached sooner. A small class keeps the big faces. */
@media (max-width: 520px) {
  .today-faces:has(> .today-face:nth-child(13)) { display: grid; grid-template-columns: repeat(auto-fill, minmax(52px, 1fr)); gap: 10px 4px; }
  .today-faces:has(> .today-face:nth-child(13)) > .today-face { width: auto; font-size: .68rem; gap: 3px; }
  .today-faces:has(> .today-face:nth-child(13)) > .today-face .avatar,
  .today-faces:has(> .today-face:nth-child(13)) > .today-face .face-todo { width: 38px !important; height: 38px !important; border-width: 2.5px; }
  .today-faces:has(> .today-face:nth-child(13)) > .today-face.read::after { width: 16px; height: 16px; font-size: .62rem; top: -3px; right: 2px; }
}

/* Long tables on a laptop (Stories, Progress, the roster, Admin's lists): the column headings stay
   pinned under the top bar (and under the class tabs) while the rows scroll, so "Status" or
   "Questions" is never a scroll back up away. Every table fits its card at these widths, so the
   sideways scroll box (which stopped headings from pinning) is clipped instead. */
@media screen and (min-width: 1000px) and (min-height: 600px) {
  .table-wrap { overflow-x: clip; overflow-clip-margin: 6px; }
  .table-wrap thead th { position: sticky; top: calc(var(--topbar-h, 68px) - 1px); z-index: 3; background: var(--card);
    box-shadow: 0 -12px 0 var(--card), 0 1px 0 var(--line), 0 8px 10px -10px rgba(40, 60, 30, .35); }
  html:has(.tabs[role="tablist"]) .table-wrap thead th { top: calc(var(--topbar-h, 68px) + 64px); }
}
/* ...and a control that gets keyboard focus while tabbing up a long table is kept just below
   those pinned headings, instead of tucked under them. */
@media screen and (min-width: 1000px) and (min-height: 600px) {
  html:has(.table-wrap thead th) { scroll-padding-top: calc(var(--topbar-h, 68px) + 48px); }
  html:has(.tabs[role="tablist"]):has(.table-wrap thead th) { scroll-padding-top: calc(var(--topbar-h, 68px) + 112px); }
}

/* Dark theme date tiles: the blue (day off) and purple (epic, library, assigned) tiles turn
   brighter, as the green ones do, so their dark month letters read clearly on the band. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .date-tile.off { --tile: #8fb0e8; }
  :root:not([data-theme="light"]) :is(.date-tile.epic, .date-tile.library, .day-page.assigned) { --tile: #b39ef0; }
}
:root[data-theme="dark"] .date-tile.off { --tile: #8fb0e8; }
:root[data-theme="dark"] :is(.date-tile.epic, .date-tile.library, .day-page.assigned) { --tile: #b39ef0; }
.answer-review .answer.wrong { text-decoration: none; }
.answer-review .answer.wrong > span[lang] { text-decoration: line-through; }
