/**
 * The web app's own styling.
 *
 * Colours, type and spacing come from tokens.css, the same file the website
 * uses, so the four course accents are Jay's character colours here too and a
 * change to them lands in both places at once. Nothing in this file hard-codes
 * a course colour: screens set `--accent` and everything reads from it.
 *
 * Light and dark both work, because tokens.css defines all three states: the
 * bare :root, the prefers-color-scheme query, and the explicit data-theme.
 */

*, *::before, *::after { box-sizing: border-box; }

body.webapp {
  margin: 0;
  min-height: 100dvh;
  /* `--ground`, not `--page`. This said `var(--page)` for its whole life and
     that token has never existed: the declaration was invalid, so the body was
     TRANSPARENT and what showed through was the browser's own canvas.
     It looked right for as long as the chosen scheme happened to match the
     device's, which is why nobody caught it. Give the app an explicit light
     theme on a dark machine and the chrome behind the content stays dark.
     Six declarations were affected, including the quiz review rows. */
  background: var(--ground);
  color: var(--ink);
  font-family: var(--font-body, system-ui, sans-serif);
  -webkit-font-smoothing: antialiased;
}

.wrap { max-width: 68rem; margin: 0 auto; padding: 1.5rem clamp(1rem, 4vw, 2rem) 5rem; }
.wrap--narrow { max-width: 44rem; }

/* Home is ONE column, and it is centred.
   The daily card used to run the full 68rem while the tiles under it stopped at
   46rem and sat left, so the screen had two different left-to-right measures and
   a wide empty gutter down the right of the tiles. Everything on this screen is
   the same width now, which is also how the app has it. */
.wrap--home { max-width: 46rem; }

/* --- Boot ---------------------------------------------------------------- */

.boot { display: grid; place-items: center; gap: 1rem; min-height: 70dvh; color: var(--ink-soft); }
.boot__spin {
  width: 34px; height: 34px; border-radius: 50%;
  border: 3px solid color-mix(in srgb, var(--chrome) 30%, transparent);
  border-top-color: var(--chrome);
  animation: spin 0.7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .boot__spin { animation-duration: 3s; } }

/* --- The bar ------------------------------------------------------------- */

.bar {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; gap: 1rem; flex-wrap: wrap;
  padding: 0.7rem clamp(1rem, 4vw, 2rem);
  background: color-mix(in srgb, var(--ground) 86%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid color-mix(in srgb, var(--ink) 10%, transparent);
}
.bar__home {
  display: flex; align-items: center; gap: 0.55rem;
  font-family: var(--font-display); font-weight: 700; font-size: 1.02rem;
  color: var(--ink); text-decoration: none;
}
.bar__home img { display: block; }
.bar__nav { display: flex; gap: 0.25rem; margin-right: auto; flex-wrap: wrap; }
.bar__nav a {
  padding: 0.35rem 0.7rem; border-radius: 999px;
  color: var(--ink-soft); text-decoration: none; font-size: 0.92rem;
}
.bar__nav a:hover { background: color-mix(in srgb, var(--ink) 10%, transparent); color: var(--ink); }
.bar__meta { display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; }

.chip {
  padding: 0.28rem 0.66rem; border-radius: 999px; font-size: 0.78rem;
  font-family: var(--font-label, inherit);
  background: color-mix(in srgb, var(--ink) 8%, transparent);
  color: var(--ink-soft); white-space: nowrap;
}
.chip--easy { background: color-mix(in srgb, var(--correct) 20%, transparent); color: var(--correct); font-weight: 600; }
.chip--hard { background: color-mix(in srgb, var(--incorrect) 20%, transparent); color: var(--incorrect); font-weight: 600; }
.chip--streak { background: color-mix(in srgb, var(--blockie) 20%, transparent); color: var(--blockie); }
.chip--btn { border: 0; cursor: pointer; font: inherit; font-size: 0.78rem; }
.chip--btn:hover { filter: brightness(1.2); background: color-mix(in srgb, var(--ink) 16%, transparent); }

/* --- Bits ---------------------------------------------------------------- */

.crumbs { display: flex; gap: 0.4rem; align-items: center; font-size: 0.82rem; color: var(--ink-faint); margin-bottom: 0.9rem; flex-wrap: wrap; }
.crumbs a { color: var(--ink-soft); text-decoration: none; }
.crumbs a:hover { text-decoration: underline; }
.crumbs i { font-style: normal; opacity: 0.5; }

.page-title { font-family: var(--font-display); font-size: clamp(1.6rem, 4vw, 2.3rem); margin: 0 0 0.6rem; }
.section-title { font-family: var(--font-display); font-size: 1.3rem; margin: 2.2rem 0 0.5rem; }
.lede { color: var(--ink-soft); margin: 0 0 1.4rem; max-width: 46rem; }
.empty { color: var(--ink-faint); padding: 2rem 0; }

.card {
  background: var(--surface);
  border: 1px solid color-mix(in srgb, var(--ink) 10%, transparent);
  border-radius: 18px;
  padding: clamp(1.1rem, 3vw, 1.7rem);
}

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.45rem;
  padding: 0.62rem 1.15rem; border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--ink) 18%, transparent);
  background: transparent; color: var(--ink);
  font: inherit; font-size: 0.95rem; cursor: pointer; text-decoration: none;
  transition: transform 0.12s ease, background 0.15s ease;
}
/* Hover BRIGHTENS. It never dims, and it never swaps the background.
   `.btn:hover:not(:disabled)` is (0,3,0) because :not() carries its argument's
   specificity, which beat `.btn--primary:hover` at (0,2,0). So hovering a
   primary button replaced its accent with a faint grey wash: the accent button
   went grey under the cursor and read as disabled at the moment of clicking it.
   Filter and border only, so nothing can override a colour again. */
.btn:hover:not(:disabled) {
  filter: brightness(1.14);
  border-color: color-mix(in srgb, var(--ink) 34%, transparent);
}
.btn:active:not(:disabled) { transform: translateY(1px); filter: brightness(1.05); }
.btn:disabled { opacity: 0.4; cursor: not-allowed; }
.btn--primary {
  background: var(--accent, var(--chrome)); border-color: transparent; color: var(--on-accent);
  font-weight: 600;
}
.btn--primary:hover:not(:disabled) { filter: brightness(1.12); border-color: transparent; }
.btn--wide { width: 100%; }
/* Stacked full-width buttons sat flush against each other, which reads as one
   two-tone control rather than two choices. */
.btn--wide + .btn--wide { margin-top: 0.6rem; }
.btn--yes { background: var(--correct); border-color: transparent; color: var(--on-accent); font-weight: 600; }
.btn--no  { background: color-mix(in srgb, var(--incorrect) 16%, transparent); border-color: transparent; color: var(--incorrect); font-weight: 600; }

.meter { height: 6px; border-radius: 999px; background: color-mix(in srgb, var(--ink) 12%, transparent); overflow: hidden; }
.meter > span { display: block; height: 100%; background: var(--accent, var(--chrome)); border-radius: 999px; }

.meter--steps { display: flex; gap: 3px; height: 5px; background: none; margin: 0.6rem 0 1.2rem; }
.meter--steps i { flex: 1; border-radius: 999px; background: color-mix(in srgb, var(--ink) 12%, transparent); }
.meter--steps i.is-past { background: color-mix(in srgb, var(--accent, var(--chrome)) 55%, transparent); }
.meter--steps i.is-now { background: var(--accent, var(--chrome)); }
.meter--steps i.is-right { background: var(--correct); }
.meter--steps i.is-wrong { background: var(--incorrect); }

.toggle { display: inline-flex; padding: 3px; border-radius: 999px; background: color-mix(in srgb, var(--ink) 8%, transparent); margin-bottom: 1.6rem; }
.toggle a { padding: 0.4rem 1.1rem; border-radius: 999px; text-decoration: none; color: var(--ink-soft); font-size: 0.92rem; }
/* Green for Easy, red for Hard, as the app has it: `Difficulty.tint` is
   `Palette.correct` and `Palette.incorrect`, and the tokens here are those exact
   values in both schemes. Deliberately NOT the course accent, which is what this
   used to be: an orange "Easy" beside an orange "Hard" says nothing about which
   is which, and the child has to read the word. */
.toggle a.is-on { color: var(--on-accent); font-weight: 600; }
.toggle a.is-easy.is-on { background: var(--correct); }
.toggle a.is-hard.is-on { background: var(--incorrect); }

/* --- Characters ---------------------------------------------------------- */

.friend { position: relative; display: block; width: 100%; }
.friend img { position: absolute; left: 0; width: 100%; height: auto; display: block; }

/* Not met yet. Desaturated as well as faded, because a dimmed pink still reads
   as pink and the point is that you cannot tell who it is. Same values the app
   uses: no saturation, 28% opacity. */
.friend.is-locked img { filter: grayscale(1); opacity: 0.28; }
.friend__lock {
  position: absolute; left: 50%; top: 46%;
  width: 22%; aspect-ratio: 1;
  transform: translate(-50%, -50%);
  background: var(--ink-soft);
  -webkit-mask: var(--lock) center / contain no-repeat;
  mask: var(--lock) center / contain no-repeat;
}
:root {
  --lock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6 10V8a6 6 0 0 1 12 0v2h1a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h1Zm2 0h8V8a4 4 0 0 0-8 0v2Z' fill='%23000'/%3E%3C/svg%3E");
}
.friendcard.is-locked { border-color: color-mix(in srgb, var(--ink) 12%, transparent); }
.friendcard.is-locked b { color: var(--ink-faint); }

/* --- Sign in ------------------------------------------------------------- */

.signin { display: grid; place-items: center; min-height: 100dvh; padding: 2rem 1rem; }
.signin__card { max-width: 30rem; text-align: center; }
.signin__art { margin-bottom: 0.5rem; }
.signin h1 { font-family: var(--font-display); font-size: 1.7rem; margin: 0 0 0.6rem; }
.signin p { color: var(--ink-soft); margin: 0 0 1.4rem; }
.signin__form { display: grid; gap: 0.5rem; text-align: left; }
.signin__form label { font-size: 0.82rem; color: var(--ink-soft); }
.signin__form input {
  padding: 0.7rem 0.9rem; border-radius: 12px; font: inherit;
  border: 1px solid color-mix(in srgb, var(--ink) 20%, transparent);
  background: var(--ground); color: var(--ink);
}
.signin__form .btn { margin-top: 0.4rem; --accent: var(--blockie); }
.signin__warn {
  background: color-mix(in srgb, var(--blockie) 12%, transparent);
  border-radius: 12px; padding: 0.7rem 0.9rem;
  font-size: 0.92rem; color: var(--ink); text-align: left;
  margin: 0 0 1rem;
}
.signin__note { font-size: 0.8rem; color: var(--ink-faint); margin: 1rem 0 0; }
.signin__sell { font-size: 0.8rem; color: var(--ink-faint); margin: 1.2rem 0 0; }
.signin__error {
  background: color-mix(in srgb, var(--incorrect) 14%, transparent);
  color: var(--incorrect);
  border-radius: 12px; padding: 0.7rem 0.9rem; font-size: 0.88rem;
  margin: 0 0 1rem; text-align: left;
}
.signin__providers { display: grid; gap: 0.6rem; }
.btn--provider {
  width: 100%; justify-content: center; gap: 0.6rem;
  padding: 0.75rem 1.15rem; font-weight: 600;
  background: var(--ground);
  border: 1px solid color-mix(in srgb, var(--ink) 22%, transparent);
}
/* Only the border and a brighten. Re-asserting the background here was a
   defence against the generic hover swapping it, and that rule no longer
   touches colour, so this would just be the same pattern kept alive. */
.btn--provider:hover:not(:disabled) { border-color: var(--blockie); }
.btn--provider svg { flex: none; }

/* --- Home ---------------------------------------------------------------- */


.panel {
  display: block; text-decoration: none; color: inherit;
  background: var(--surface); border-radius: 18px; padding: 1.2rem;
  border: 1px solid color-mix(in srgb, var(--ink) 10%, transparent);
  --accent: var(--blockie);
}
.panel:hover { border-color: color-mix(in srgb, var(--blockie) 45%, transparent); }
.panel h2 { font-family: var(--font-display); font-size: 1.1rem; margin: 0 0 0.3rem; }
.panel p { color: var(--ink-soft); font-size: 0.9rem; margin: 0 0 0.7rem; }

/* --- Lists --------------------------------------------------------------- */

.group { margin-bottom: 1.8rem; }
.group h3 {
  font-family: var(--font-label, inherit); text-transform: uppercase; letter-spacing: 0.06em;
  font-size: 0.74rem; color: var(--ink-faint); margin: 0 0 0.55rem;
}
.rows { display: grid; gap: 4px; }
.row {
  display: flex; align-items: center; gap: 0.8rem;
  padding: 0.7rem 0.95rem; border-radius: 12px; text-decoration: none; color: inherit;
  background: var(--surface);
  /* The bar carries the difficulty, matching `Rectangle().fill(difficulty.tint)`
     in CourseView. Falls back to the accent where there is no difficulty to
     show, which is the stats rows on the progress screen. */
  border-left: 3px solid var(--difficulty, var(--accent, var(--chrome)));
}
.row:hover { background: color-mix(in srgb, var(--difficulty, var(--accent, var(--chrome))) 10%, var(--surface)); }
.row__name { flex: 1; }
.row__count { font-size: 0.8rem; color: var(--ink-faint); }
.row__state { width: 1rem; text-align: right; }
.tick { color: var(--correct); font-style: normal; }

/* --- A question ---------------------------------------------------------- */

.qhead { display: flex; align-items: center; gap: 0.8rem; flex-wrap: wrap; justify-content: space-between; }
.question__n { font-size: 0.78rem; color: var(--ink-faint); margin: 0 0 0.5rem; text-transform: uppercase; letter-spacing: 0.05em; }
.question__prompt { font-family: var(--font-display); font-size: clamp(1.15rem, 2.6vw, 1.5rem); line-height: 1.35; margin: 0 0 1.1rem; }
.question__figure { margin: 0 0 1.2rem; }
.question__figure img {
  max-width: 100%; height: auto; display: block; border-radius: 12px;
  background: #fff; padding: 0.6rem;
}
.question__nudge { font-size: 0.8rem; color: var(--ink-faint); text-align: center; margin: 0.7rem 0 0; }

.answer { animation: rise 0.22s ease; }
@keyframes rise { from { opacity: 0; transform: translateY(6px); } }
@media (prefers-reduced-motion: reduce) { .answer { animation: none; } }
.answer__label { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.07em; color: var(--accent, var(--chrome)); margin: 0 0 0.3rem; font-weight: 700; }
.answer__text { font-size: 1.05rem; margin: 0 0 1rem; }

.tip { border-left: 3px solid var(--accent, var(--chrome)); padding: 0.1rem 0 0.1rem 0.9rem; }
.tip__title { font-weight: 700; font-size: 0.86rem; margin: 0 0 0.2rem; color: var(--accent, var(--chrome)); }
.tip__body { font-size: 0.92rem; color: var(--ink-soft); margin: 0; white-space: pre-line; }

.pager { display: flex; gap: 0.6rem; justify-content: space-between; margin-top: 1.2rem; }
.pager .btn { flex: 1; }

/* --- Vocabulary ---------------------------------------------------------- */

.search {
  width: 100%; padding: 0.75rem 1rem; border-radius: 12px; font: inherit; margin-bottom: 1.6rem;
  border: 1px solid color-mix(in srgb, var(--ink) 18%, transparent);
  background: var(--surface); color: var(--ink);
}
.words { display: grid; gap: 4px; }
.word { background: var(--surface); border-radius: 12px; border-left: 3px solid color-mix(in srgb, var(--english) 45%, transparent); }
.word.is-known { border-left-color: var(--correct); }
.word summary { display: flex; gap: 0.7rem; align-items: baseline; padding: 0.65rem 0.95rem; cursor: pointer; list-style: none; }
.word summary::-webkit-details-marker { display: none; }
.word__w { font-weight: 600; }
.word__pos { font-size: 0.74rem; color: var(--ink-faint); text-transform: lowercase; }
.word__body { padding: 0 0.95rem 0.9rem; }
.word__def { margin: 0.2rem 0; font-size: 0.92rem; }
.word__def b { color: var(--english); font-weight: 600; font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.04em; margin-right: 0.3rem; }
.word__quote { margin: 0.1rem 0 0.5rem; font-size: 0.88rem; color: var(--ink-soft); font-style: italic; }
.word__list { margin: 0.3rem 0 0; font-size: 0.86rem; color: var(--ink-soft); }
.word__list b { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--ink-faint); margin-right: 0.35rem; }

.flash { position: relative; min-height: 15rem; display: grid; }
.flash__face {
  grid-area: 1 / 1; background: var(--surface); border-radius: 18px; padding: 1.6rem;
  border: 1px solid color-mix(in srgb, var(--english) 30%, transparent);
  display: grid; align-content: center; gap: 0.3rem;
}
.flash__front { text-align: center; }
.flash.is-flipped .flash__front { display: none; }
.flash:not(.is-flipped) .flash__back { display: none; }
.flash__word { font-family: var(--font-display); font-size: clamp(1.8rem, 6vw, 2.6rem); margin: 0; }
.flash__pos { font-size: 0.78rem; color: var(--ink-faint); text-transform: uppercase; letter-spacing: 0.06em; margin: 0; }
.flash__ask { color: var(--ink-soft); margin: 1rem 0 0; }
.flash__def { margin: 0.25rem 0; }
.flash__def b { color: var(--english); font-size: 0.74rem; text-transform: uppercase; letter-spacing: 0.05em; margin-right: 0.35rem; }
.flash__quote { margin: 0.1rem 0 0.6rem; color: var(--ink-soft); font-style: italic; font-size: 0.92rem; }
.flash__list { margin: 0.25rem 0; font-size: 0.88rem; color: var(--ink-soft); }
.flash__list b { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--ink-faint); margin-right: 0.35rem; }

/* --- Quizzes ------------------------------------------------------------- */

.papers { display: grid; grid-template-columns: repeat(auto-fill, minmax(6.5rem, 1fr)); gap: 0.6rem; }
.paper {
  display: grid; place-items: center; gap: 0.2rem; padding: 0.9rem 0.5rem;
  background: var(--surface); border-radius: 14px; text-decoration: none; color: inherit;
  border: 1px solid color-mix(in srgb, var(--ink) 10%, transparent);
}
.paper:hover { border-color: color-mix(in srgb, var(--blockie) 50%, transparent); }
.paper.is-perfect { border-color: color-mix(in srgb, var(--correct) 55%, transparent); }
.paper__n { font-family: var(--font-display); font-size: 1.5rem; font-weight: 700; }
.paper__score { font-size: 0.74rem; color: var(--ink-faint); }

.options { display: grid; gap: 0.5rem; }
.option {
  text-align: left; padding: 0.8rem 1rem; border-radius: 12px; font: inherit; cursor: pointer;
  background: var(--ground); color: var(--ink);
  border: 1px solid color-mix(in srgb, var(--ink) 16%, transparent);
}
.option:hover:not(:disabled) { border-color: var(--blockie); }
.option:disabled { cursor: default; }
.option.is-right { border-color: var(--correct); background: color-mix(in srgb, var(--correct) 14%, transparent); }
.option.is-wrong { border-color: var(--incorrect); background: color-mix(in srgb, var(--incorrect) 14%, transparent); }

.verdict { margin: 1rem 0; font-weight: 600; }
.verdict.is-right { color: var(--correct); }
.verdict.is-wrong { color: var(--incorrect); }

.review { text-align: left; margin: 1.4rem 0; padding: 0; list-style: none; display: grid; gap: 0.6rem; }
.review li { padding: 0.7rem 0.9rem; border-radius: 12px; background: var(--ground); border-left: 3px solid var(--correct); }
.review li.is-wrong { border-left-color: var(--incorrect); }
.review__q { margin: 0 0 0.3rem; font-size: 0.92rem; }
.review__a { margin: 0; font-size: 0.86rem; color: var(--ink-soft); }
.review__a b, .review__y b { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--ink-faint); margin-right: 0.3rem; }
.review__y { margin: 0.2rem 0 0; font-size: 0.86rem; color: var(--incorrect); }

/* --- Done screens -------------------------------------------------------- */

.done { text-align: center; display: grid; justify-items: center; gap: 0.4rem; }
.done h1 { font-family: var(--font-display); font-size: 1.7rem; margin: 0.4rem 0 0; }
.soon {
  display: inline-block; padding: 0.3rem 0.85rem; border-radius: 999px;
  background: color-mix(in srgb, var(--blockie) 18%, transparent);
  color: var(--blockie); font-size: 0.8rem; font-weight: 600;
  margin: 0.2rem 0 0.9rem !important;
}
.done p { color: var(--ink-soft); margin: 0 0 1rem; }
.done .pager { width: 100%; }

/* --- Progress ------------------------------------------------------------ */

.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(7rem, 1fr)); gap: 0.7rem; margin-bottom: 1rem; }
.stat { background: var(--surface); border-radius: 14px; padding: 0.9rem; text-align: center; }
.stat b { display: block; font-family: var(--font-display); font-size: 1.7rem; color: var(--blockie); }
.stat span { font-size: 0.74rem; color: var(--ink-faint); text-transform: uppercase; letter-spacing: 0.05em; }

.friends { display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); gap: 1rem; align-items: end; }
.friendcard { margin: 0; background: var(--surface); border-radius: 18px; padding: 1rem; text-align: center;
  border: 1px solid color-mix(in srgb, var(--accent) 24%, transparent); }
.friendcard__art { width: 74px; margin: 0 auto 0.7rem; display: flex; align-items: flex-end; min-height: 130px; }
.friendcard figcaption { display: grid; gap: 0.15rem; }
.friendcard b { font-family: var(--font-display); color: var(--accent); }
.friendcard span { font-size: 0.78rem; color: var(--ink-soft); }
.friendcard__lvl { font-size: 0.72rem !important; color: var(--ink-faint) !important; }
.friendcard .meter { margin-top: 0.4rem; }

/* --- Foot ---------------------------------------------------------------- */

.webapp__foot {
  display: flex; gap: 1rem; flex-wrap: wrap; justify-content: center; align-items: center;
  padding: 1rem; font-size: 0.74rem; color: var(--ink-faint);
  border-top: 1px solid color-mix(in srgb, var(--ink) 8%, transparent);
}
.webapp__foot a { color: var(--ink-soft); }
.webapp__stub { max-width: 26rem; text-align: center; }

@media (max-width: 560px) {
  .bar__nav { order: 3; width: 100%; justify-content: center; }

  /* Deliberately NOT stacked. Turning the tile into a column looks tidier in a
     stylesheet and costs about 370px of height each, so all four fill a phone
     screen and a half before vocabulary and quizzes are even reachable. Side
     by side, all six fit in one scroll. */
      
  .wrap { padding-top: 1rem; }
  .page-title { font-size: 1.45rem; }
  .friendcard__art { min-height: 104px; width: 62px; }
}

/* ===========================================================================
   The app's own furniture: nav with icons, the daily card, flip cards,
   achievements, and the rewards that make working on a laptop worth anything.
   =========================================================================== */

/* --- Nav ------------------------------------------------------------------ */

.bar__nav a { display: inline-flex; align-items: center; gap: 0.4rem; }
.bar__nav a.is-on { background: color-mix(in srgb, var(--blockie) 18%, transparent); color: var(--blockie); }
.bar__nav svg { flex: none; }
.chip--blocks {
  display: inline-flex; align-items: center; gap: 0.3rem;
  background: color-mix(in srgb, var(--blockie) 16%, transparent); color: var(--blockie);
  font-weight: 700;
}

.eyebrow {
  font-family: var(--font-label, inherit); text-transform: uppercase;
  letter-spacing: 0.07em; font-size: 0.74rem; color: var(--ink-faint);
  margin: 1.8rem 0 0.6rem; display: flex; align-items: center; gap: 0.5rem;
}
.eyebrow__count { margin-left: auto; text-transform: none; letter-spacing: 0; }

/* --- The daily card ------------------------------------------------------- */

.daily { display: flex; align-items: center; gap: 1.1rem; margin-bottom: 0.4rem; }
.daily__art { width: 60px; flex: none; }
.daily__text { flex: 1; min-width: 0; }
.daily__streak {
  display: flex; align-items: center; gap: 0.4rem; margin: 0 0 0.2rem;
  font-family: var(--font-display); font-size: 1.15rem; color: var(--ink);
}
.daily__streak svg { color: var(--non-verbal); }
.daily__goal { margin: 0 0 0.6rem; font-size: 0.88rem; color: var(--ink-soft); }
.daily__blocks { text-align: center; color: var(--blockie); flex: none; }
.daily__blocks b { display: block; font-family: var(--font-display); font-size: 1.4rem; }

.dots { display: flex; gap: 4px; flex-wrap: wrap; }
.dots i {
  width: 22px; height: 7px; border-radius: 999px;
  background: color-mix(in srgb, var(--ink) 14%, transparent);
}
.dots i.is-on { background: var(--blockie); }

/* --- Flip cards ----------------------------------------------------------- */

/* `align-items: start` so a flipped card grows on its own rather than stretching
   every other card in its row to match. */
.flipgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr)); gap: 0.7rem; align-items: start; }
.flipcard { perspective: 900px; }
.flipcard__inner {
  position: relative; width: 100%; min-height: 7.5rem;
  border: 0; padding: 0; background: none; cursor: pointer; font: inherit;
  transform-style: preserve-3d; transition: transform 0.45s var(--ease-spring, ease);
}
.flipcard.is-flipped .flipcard__inner { transform: rotateY(180deg); }
@media (prefers-reduced-motion: reduce) { .flipcard__inner { transition-duration: 0.01ms; } }

.flipcard__face {
  position: absolute; inset: 0; backface-visibility: hidden;
  /* Inherits the inner's own min-height, so the face that is in normal flow
     still fills the card instead of shrinking to its text. Without it the front
     collapsed to the height of the word and the "Tap to flip" hint, which is
     positioned against the bottom, landed on top of the part of speech.
     `inherit` rather than a number because the value changes at the breakpoint,
     and two copies of it would only agree until one of them was edited. */
  min-height: inherit;
  display: flex; flex-direction: column; justify-content: center; gap: 0.2rem;
  padding: 0.9rem; border-radius: 14px; text-align: left;
  background: var(--surface);
  border: 1px solid color-mix(in srgb, var(--english) 28%, transparent);
}
/* The face that is SHOWING sits in normal flow, so it is the one that sets the
   card's height. With both faces absolute inside a fixed 7.5rem the card was
   always front-sized, and the back — which carries two definitions, synonyms and
   antonyms, and is always the longer of the two — was clipped mid-word.
   The hidden face stays absolute so it still stacks behind for the 3D flip. */
.flipcard:not(.is-flipped) .flipcard__front,
.flipcard.is-flipped .flipcard__back { position: relative; inset: auto; }

.flipcard__front { align-items: center; text-align: center; }
.flipcard__front b { font-family: var(--font-display); font-size: 1.1rem; color: var(--ink); }
.flipcard__front i { font-size: 0.72rem; color: var(--ink-faint); font-style: normal; text-transform: uppercase; letter-spacing: 0.05em; }
.flipcard__back { transform: rotateY(180deg); }
.flipcard__def { font-size: 0.8rem; color: var(--ink); }
.flipcard__def em, .flipcard__list em {
  font-style: normal; font-size: 0.66rem; text-transform: uppercase;
  letter-spacing: 0.05em; color: var(--english); margin-right: 0.3rem;
}
.flipcard__list { font-size: 0.76rem; color: var(--ink-soft); }
.flipcard.is-known .flipcard__face { border-color: color-mix(in srgb, var(--correct) 55%, transparent); }
.flipcard__tick { position: absolute; top: 0.5rem; right: 0.6rem; color: var(--correct); }

/* --- Progress ------------------------------------------------------------- */

/* Block flow, NOT the old `.friends` grid.
   That rule laid four friend cards out in auto-fit columns, and when this
   became a card containing a row, a total and a note, all three became columns
   of it: the blocks total was drawn straight across the friends. */
.friends.card { display: block; padding: 1.2rem; }
.friends__row { display: grid; grid-template-columns: repeat(5, 1fr); gap: 0.5rem; align-items: end; }
.friends__row .friendcard { padding: 0.7rem 0.4rem; }
.friends__row .friendcard__art { width: 100%; max-width: 64px; min-height: 92px; }
.friends__total { text-align: center; margin: 1.1rem 0 0.2rem; }
.friends__total b { display: block; font-family: var(--font-display); font-size: 1.7rem; color: var(--blockie); }
.friends__total span { font-size: 0.86rem; color: var(--ink-soft); }
.friends__note { text-align: center; font-size: 0.78rem; color: var(--ink-faint); margin: 0.3rem 0 0; }

.stats .stat svg { color: var(--blockie); display: block; margin: 0 auto 0.2rem; }
.rows--stats .row--stat { display: grid; grid-template-columns: 1fr auto; gap: 0.2rem 0.8rem; }
.row--stat .meter { grid-column: 1 / -1; }

.badges { display: grid; grid-template-columns: repeat(auto-fill, minmax(6.5rem, 1fr)); gap: 0.6rem; }
.badge { margin: 0; text-align: center; }
.badge__disc {
  display: grid; place-items: center; width: 52px; height: 52px; margin: 0 auto 0.4rem;
  border-radius: 50%; background: color-mix(in srgb, var(--ink) 8%, transparent);
  color: var(--ink-faint);
}
.badge figcaption { font-size: 0.72rem; color: var(--ink-faint); line-height: 1.25; }
.badge.is-earned .badge__disc { background: var(--blockie); color: var(--on-accent); }
.badge.is-earned figcaption { color: var(--ink); font-weight: 600; }

/* --- Quiz marks ----------------------------------------------------------- */

.paper__top { display: flex; align-items: center; gap: 0.4rem; }
.paper__mark { display: grid; place-items: center; width: 22px; height: 22px; border-radius: 50%; font-size: 0.7rem; }
.paper__mark.is-done { background: var(--correct); color: #fff; }
/* The app's own Brand.Palette.star, as an adaptive pair. Darker on light than
   it looks like it should be, because white has to clear 4.5:1 on it. */
.paper__mark.is-perfect { background: var(--star); color: var(--on-accent); }
:root { --star: #96690A; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { --star: #F2C438; } }
:root[data-theme="dark"] { --star: #F2C438; }
.paper__mark.is-todo { background: color-mix(in srgb, var(--ink) 10%, transparent); color: var(--ink-faint); }
.paper.is-perfect { border-color: color-mix(in srgb, var(--star) 60%, transparent); }
.paper.is-done { border-color: color-mix(in srgb, var(--correct) 45%, transparent); }

/* --- Rewards -------------------------------------------------------------- */

/* From the TOP. It used to rise from the bottom, where on a laptop it is
   several hundred pixels from the question a child is looking at and simply
   missed. The reward has to be seen or it is not a reward. */
.toast {
  position: fixed; left: 50%; top: 4.6rem; z-index: 60;
  display: flex; align-items: center; gap: 0.45rem;
  padding: 0.6rem 1.1rem; border-radius: 999px;
  background: var(--blockie); color: var(--on-accent); font-size: 0.95rem;
  box-shadow: 0 8px 26px rgb(0 0 0 / 0.28);
  transform: translate(-50%, 0);
  /* Same rule, for the same reason. A frozen toast only blocks nothing rather
     than blocking everything, but a child who switches tab should still come
     back to their blocks rather than to a blank, so it slides without fading. */
  opacity: 1;
  animation: toast-in 0.3s var(--ease-spring, ease);
}
@keyframes toast-in { from { transform: translate(-50%, -2rem); } }
.toast.is-out { opacity: 0; transform: translate(-50%, -1rem); transition: all 0.3s ease; }
.toast b { font-family: var(--font-display); }

.party {
  position: fixed; inset: 0; z-index: 70; display: grid; place-items: center;
  padding: 1.5rem; background: rgb(0 0 0 / 0.55); backdrop-filter: blur(3px);
  /* This layer's OPACITY is never animated, and that is load-bearing.
     A hidden tab freezes an animation at currentTime 0, inside its own active
     interval, where the `from` keyframe still applies — `animation-fill-mode`
     changes nothing, because the freeze is not before the animation, it is at
     its first frame. Fading opacity from 0 therefore leaves this at 0 while it
     is still `position: fixed; inset: 0; z-index: 70`: an invisible full-screen
     click-blocker, and the app reads as frozen. A child switching tabs while a
     friend is arriving is enough to hit it, which is the same shape as the
     requestAnimationFrame version of this bug, reached by a different route.
     So the backdrop COLOUR fades instead. Frozen, that is a clear backdrop with
     a perfectly visible, perfectly clickable card on it. */
  opacity: 1;
  animation: party-in 0.25s ease;
}
@keyframes party-in { from { background-color: rgb(0 0 0 / 0); backdrop-filter: blur(0); } }
.party.is-out { opacity: 0; transition: opacity 0.3s ease; }
.party__card {
  background: var(--surface); border-radius: 22px; padding: 1.8rem 1.6rem;
  text-align: center; max-width: 22rem; width: 100%;
  border: 1px solid color-mix(in srgb, var(--blockie) 40%, transparent);
  /* No `both`, for the reason above: resting state is the untransformed card. */
  animation: party-card-in 0.32s var(--ease-spring, ease);
}
@keyframes party-card-in { from { transform: scale(0.94); } }
.party__disc {
  display: grid; place-items: center; width: 74px; height: 74px; margin: 0 auto 0.8rem;
  border-radius: 50%; background: var(--blockie); color: var(--on-accent);
}
.party__label { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--blockie); margin: 0; font-weight: 700; }
.party__card h2 { font-family: var(--font-display); font-size: 1.5rem; margin: 0.2rem 0 0.3rem; }
.party__detail { color: var(--ink-soft); margin: 0 0 0.8rem; }
.party__reward {
  display: inline-flex; align-items: center; gap: 0.35rem; margin: 0 0 1.2rem;
  padding: 0.3rem 0.8rem; border-radius: 999px; font-size: 0.85rem; font-weight: 600;
  background: color-mix(in srgb, var(--blockie) 16%, transparent); color: var(--blockie);
}
.party__card .btn { width: 100%; --accent: var(--blockie); }

/* A friend turning up. Same card, but wearing their own colour rather than
   Blockie's, because the whole point is WHICH of them just grew. The inline
   `--accent` on the card is the character's, so the button inherits it and the
   `--accent: var(--blockie)` above must not apply here. */
.party__card--friend { border-color: color-mix(in srgb, var(--accent) 45%, transparent); }
.party__card--friend .btn { --accent: inherit; }
/* Sized by WIDTH, like every other place a friend is drawn.
   `.friend` is `width: 100%` with its height coming from `aspect-ratio`, and its
   blocks are absolutely positioned against that width. Give it a height instead
   and the width stays at 100% of the card, the images size off THAT, and the
   artwork bursts out of the card at three times the size — which is exactly what
   shipped. `.friendcard__art` is the pattern; this is the same one, larger.
   `min-height` rather than `height` because a five-block friend is twice as tall
   as a one-block friend and must be allowed to grow. */
.party__art {
  width: 104px; margin: 0 auto 0.9rem; min-height: 132px;
  display: flex; align-items: flex-end;
}
@media (prefers-reduced-motion: reduce) {
  .toast, .party, .party__card { animation-duration: 0.01ms; transition-duration: 0.01ms; }
}

@media (max-width: 700px) {
  .bar__nav a span { display: none; }
  .bar__nav a { padding: 0.45rem 0.6rem; }
  .friends__row { grid-template-columns: repeat(5, 1fr); gap: 0.25rem; }
  .friendcard { padding: 0.5rem 0.25rem; }
  .friendcard figcaption span { font-size: 0.66rem; }
  .daily { gap: 0.7rem; }
  .daily__art { width: 46px; }
}


/* ===========================================================================
   Home the way the app has it, and cards big enough to answer.
   =========================================================================== */

/* --- Course tiles: the app's line art, 2x2 -------------------------------- */

.courses {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1rem;
}
.course {
  display: block; text-decoration: none; color: inherit; overflow: hidden;
  background: var(--surface); border-radius: 20px;
  border: 1px solid color-mix(in srgb, var(--accent) 26%, transparent);
  transition: transform 0.16s ease, border-color 0.16s ease;
}
.course:hover { transform: translateY(-3px); border-color: color-mix(in srgb, var(--accent) 60%, transparent); }
.course__scene {
  display: grid; place-items: center; padding: 1.4rem; min-height: 9.5rem;
  color: var(--accent);
  background: linear-gradient(160deg,
    color-mix(in srgb, var(--accent) 22%, transparent),
    color-mix(in srgb, var(--accent) 9%, transparent));
}
.course__scene svg {
  width: 100%; max-width: 15rem; height: auto; display: block;
  stroke-width: 2.4; color: var(--accent);
}
/* The art is drawn on a ~1700-unit canvas, so without this a 16-unit stroke is
   half a pixel by the time it fits a tile. Same reason the website pins it. */
.course__scene svg * { vector-effect: non-scaling-stroke; }
.course__text { display: block; padding: 1rem 1.15rem 1.2rem; }
.course__text b {
  display: block; font-family: var(--font-display); font-size: 1.25rem;
  color: var(--accent); margin-bottom: 0.15rem;
}
.course__text span { font-size: 0.9rem; color: var(--ink-soft); }

/* --- The study card, which is a card and not a button --------------------- */

.studycard {
  display: flex; align-items: center; gap: 1rem; margin: 0 0 1.6rem;
  padding: 1rem 1.2rem; border-radius: 18px; text-decoration: none; color: inherit;
  background: var(--surface);
  border: 1px solid color-mix(in srgb, var(--english) 32%, transparent);
}
.studycard:hover { border-color: color-mix(in srgb, var(--english) 65%, transparent); }
.studycard__art { width: 52px; flex: none; }
.studycard__text { flex: 1; min-width: 0; display: block; }
.studycard__text b { display: block; font-family: var(--font-display); font-size: 1.15rem; }
.studycard__text > span { display: block; font-size: 0.88rem; color: var(--ink-soft); margin-bottom: 0.5rem; }
.studycard__meter { display: flex; align-items: center; gap: 0.7rem; }
.studycard__meter .meter { flex: 1; }
.studycard__meter i { font-style: normal; font-size: 0.78rem; color: var(--ink-faint); white-space: nowrap; }
.studycard__go { font-size: 1.6rem; color: var(--ink-faint); flex: none; }
.studycard.is-done { border-color: color-mix(in srgb, var(--correct) 45%, transparent); }

/* --- Flip cards, big enough to read and to answer ------------------------- */

.flipgrid { grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); gap: 0.9rem; }
.flipcard__inner { min-height: 12.5rem; }
.flipcard__face { padding: 1rem; gap: 0.3rem; }
.flipcard__front {
  cursor: pointer; border: 1px solid color-mix(in srgb, var(--english) 28%, transparent);
  width: 100%; font: inherit;
}
.flipcard__front b { font-size: 1.35rem; }
.flipcard__front i { font-size: 0.74rem; }
.flipcard__hint {
  position: absolute; left: 0; right: 0; bottom: 0.7rem;
  font-size: 0.7rem; color: var(--ink-faint);
}
.flipcard__back { justify-content: space-between; }
/* No `overflow: hidden`. Combined with the fixed card height that is what cut
   "Copiousness" in half: the back carries two senses, synonyms and antonyms and
   is always longer than the front, so it needs the card to grow rather than a
   crop. The face-in-flow rule above lets it. */
.flipcard__body { display: grid; gap: 0.25rem; align-content: start; }
.flipcard__def { font-size: 0.84rem; margin: 0; }
.flipcard__list { font-size: 0.78rem; margin: 0; }
.flipcard__ask { display: grid; grid-template-columns: 1fr 1fr; gap: 0.4rem; flex: none; }
.btn--sm { padding: 0.45rem 0.6rem; font-size: 0.85rem; }

@media (max-width: 560px) {
  .courses { grid-template-columns: 1fr; }
  .course__scene { min-height: 7.5rem; padding: 1rem; }
  .flipgrid { grid-template-columns: 1fr; }
}

/* ---------------------------------------------------------------------------
   The debug bar

   Off unless ?debug=1. Fixed to the bottom and deliberately plain: it is a
   bench, not part of the app, and it should never be mistaken for one at a
   glance. `z-index` sits UNDER `.party` (70) so a celebration still covers it,
   which is the honest arrangement — the bar must not be usable while a card it
   fired is up.
   --------------------------------------------------------------------------- */
.debugbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
  /* One row that scrolls sideways, never several that stack. Wrapping put three
     rows of buttons over the bottom third of a phone screen, which is worse
     than useless on the exact screen size the bar is most in the way on. */
  display: flex; flex-wrap: nowrap; align-items: center; gap: 0.35rem;
  overflow-x: auto; overscroll-behavior-x: contain;
  padding: 0.45rem 0.6rem;
  /* A flat token, not a color-mix. This has to be genuinely opaque: content
     showing through a debug bar makes both of them unreadable. */
  background: var(--surface);
  color: var(--ink);
  font-size: 0.72rem;
  border-top: 2px solid var(--blockie);
}
.debugbar > * { flex: 0 0 auto; }
.debugbar__tag {
  text-transform: uppercase; letter-spacing: 0.09em; font-weight: 700;
  opacity: 0.55; margin-right: 0.2rem;
}
.debugbar__b {
  font: inherit; font-weight: 600; cursor: pointer; white-space: nowrap;
  padding: 0.28rem 0.6rem; border-radius: 999px;
  background: color-mix(in srgb, var(--ink) 10%, transparent);
  color: inherit;
  border: 1px solid color-mix(in srgb, var(--ink) 22%, transparent);
}
.debugbar__b:hover { filter: brightness(1.35); }
/* No `margin-left: auto` — it fights `overflow-x` on a scrolling row and pushes
   the close button off past the end where it cannot be reached. */
.debugbar__b--off { padding: 0.28rem 0.55rem; }
.debugbar__state { margin-left: 0.5rem; opacity: 0.7; font-variant-numeric: tabular-nums; }
.debugbar__state.is-held { color: var(--incorrect); opacity: 1; font-weight: 700; }

/* The bar covers the foot of the page, so give everything room to clear it. */
body:has(.debugbar) .wrap { padding-bottom: 4.5rem; }

/* ---------------------------------------------------------------------------
   The back chevron, and page headings
   --------------------------------------------------------------------------- */

/* The app's nav-bar back button, as a link. Sits above the crumbs rather than
   replacing them: the chevron is the one-tap way out, the crumbs say where out
   goes and let you skip a level. */
.backlink {
  display: inline-grid; place-items: center;
  width: 2.2rem; height: 2.2rem; margin-bottom: 0.5rem;
  border-radius: 50%; color: var(--ink); text-decoration: none;
  background: color-mix(in srgb, var(--ink) 8%, transparent);
}
.backlink:hover { filter: brightness(1.25); background: color-mix(in srgb, var(--ink) 14%, transparent); }
.backlink:focus-visible { outline: 2px solid var(--accent, var(--blockie)); outline-offset: 2px; }

/* A course keeps its colour on its own screen, as the app does. */
.page-title--accent { color: var(--accent, var(--ink)); }

/* The account menu */
.acct { position: relative; }
.acct__toggle { display: inline-flex; align-items: center; gap: 0.35rem; }
.acct__menu {
  position: absolute; right: 0; top: calc(100% + 0.45rem); z-index: 40;
  min-width: 14rem; padding: 0.9rem;
  background: var(--surface); border-radius: 14px;
  border: 1px solid color-mix(in srgb, var(--ink) 14%, transparent);
  box-shadow: 0 12px 30px rgb(0 0 0 / 0.28);
}
.acct__who { display: flex; gap: 0.55rem; align-items: flex-start; margin: 0 0 0.8rem; }
.acct__who span { display: grid; gap: 0.1rem; min-width: 0; }
.acct__who b { font-size: 0.92rem; }
.acct__who i { font-style: normal; font-size: 0.76rem; color: var(--ink-soft); overflow-wrap: anywhere; }
.acct__out { width: 100%; }

/* The theme toggle sits with the other header chips, square rather than pill so
   it reads as an icon button beside them rather than a very short label. */
.chip--theme { display: inline-grid; place-items: center; padding: 0.32rem; width: 1.9rem; }

/* ---------------------------------------------------------------------------
   Home
   --------------------------------------------------------------------------- */

/* App name left, settings right, one row. */
.homebar { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-bottom: 1.1rem; }
.homebar__name { font-family: var(--font-display); font-size: 1.6rem; margin: 0; }
.homebar__cog {
  display: grid; place-items: center; width: 2.3rem; height: 2.3rem;
  border: 0; border-radius: 50%; cursor: pointer; color: var(--ink);
  background: color-mix(in srgb, var(--ink) 8%, transparent);
}
.homebar__cog:hover { filter: brightness(1.25); }

/* What to do next. Always first, because a screen made of progress is a wall of
   zeros on a fresh account. */
.starthere {
  display: flex; align-items: center; gap: 1rem;
  padding: 1rem 1.1rem; margin-bottom: 1.1rem;
  border-radius: 18px; text-decoration: none; color: inherit;
  background: var(--surface);
  border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent);
  border-left: 4px solid var(--accent);
}
.starthere:hover { filter: brightness(1.06); }
.starthere__text { display: grid; gap: 0.15rem; min-width: 0; flex: 1; }
.starthere__text i {
  font-style: normal; font-size: 0.7rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.09em; color: var(--accent);
}
.starthere__text b { font-family: var(--font-display); font-size: 1.15rem; }
.starthere__text span { font-size: 0.86rem; color: var(--ink-soft); }
.starthere__go { color: var(--accent); flex: 0 0 auto; }

/* The unlock prompt, at the very bottom of Home and nowhere else. */
.unlock {
  display: flex; align-items: center; gap: 1rem; margin-top: 2rem;
  padding: 1rem 1.1rem; border-radius: 18px; text-decoration: none; color: inherit;
  background: color-mix(in srgb, var(--blockie) 10%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--blockie) 30%, transparent);
}
.unlock:hover { filter: brightness(1.06); }
.unlock__art { width: 54px; flex: 0 0 auto; display: flex; align-items: flex-end; }
.unlock__text { display: grid; gap: 0.2rem; flex: 1; min-width: 0; }
.unlock__text b { font-family: var(--font-display); font-size: 1rem; }
.unlock__text span { font-size: 0.82rem; color: var(--ink-soft); }
.unlock__go { color: var(--blockie); flex: 0 0 auto; }

/* ---------------------------------------------------------------------------
   Papers: the builder
   --------------------------------------------------------------------------- */

/* Each section on its own card. Flat rows with only headings between them read
   as one long form. */
.build { padding: 1.1rem 1.2rem; margin-bottom: 1rem; }
.build .eyebrow { margin-top: 0; }
.build__note { font-size: 0.84rem; color: var(--ink-soft); margin: 0 0 0.7rem; }
.build__note--print { margin-top: 0.6rem; }
.build__timing { display: flex; align-items: center; gap: 0.4rem; font-size: 0.88rem; margin: 0.8rem 0 0.3rem; }
.build__pool { font-size: 0.84rem; color: var(--ink-soft); margin: 0; }
.build__pool.is-warn { color: var(--incorrect); font-weight: 600; }

.toggles { display: grid; gap: 4px; }
.toggle-row {
  display: flex; align-items: center; gap: 0.7rem; cursor: pointer;
  padding: 0.6rem 0.8rem; border-radius: 12px; background: var(--ground);
  border: 1px solid transparent;
}
.toggle-row.is-on { border-color: color-mix(in srgb, var(--blockie) 45%, transparent); }
.toggle-row--sm { padding: 0.45rem 0.7rem; }
.toggle-row input { width: 1.05rem; height: 1.05rem; accent-color: var(--blockie); flex: 0 0 auto; }
.toggle-row__text { display: grid; gap: 0.1rem; flex: 1; min-width: 0; }
.toggle-row__text b { font-size: 0.94rem; }
.toggle-row__text span { font-size: 0.78rem; color: var(--ink-soft); }
.toggle-row__count { font-size: 0.82rem; color: var(--ink-faint); font-variant-numeric: tabular-nums; }

.seg { display: inline-flex; padding: 3px; border-radius: 999px; background: color-mix(in srgb, var(--ink) 8%, transparent); }
.seg--wrap { display: flex; flex-wrap: wrap; }
.seg__b {
  font: inherit; font-size: 0.9rem; border: 0; cursor: pointer;
  padding: 0.35rem 0.9rem; border-radius: 999px; background: none; color: var(--ink-soft);
}
.seg__b.is-on { background: var(--blockie); color: var(--on-accent); font-weight: 600; }
.seg__b:hover:not(.is-on) { filter: brightness(1.2); background: color-mix(in srgb, var(--ink) 8%, transparent); }

.topicpick { margin-top: 0.9rem; display: grid; gap: 1rem; }
.topicpick__group h3 { font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.07em;
  color: var(--accent); margin: 0 0 0.4rem; }
.topicpick__group { display: grid; gap: 3px; }

.field {
  width: 100%; font: inherit; padding: 0.6rem 0.8rem; border-radius: 12px;
  background: var(--ground); color: var(--ink);
  border: 1px solid color-mix(in srgb, var(--ink) 14%, transparent);
}
/* A secondary ACTION: the accent, quietly. Outlined-and-neutral read as
   information sitting next to the one real button, when all three of them do
   something. */
.btn--quiet {
  background: color-mix(in srgb, var(--blockie) 14%, transparent);
  color: var(--blockie); border-color: transparent; font-weight: 600;
}
.btn--quiet:hover:not(:disabled) {
  background: color-mix(in srgb, var(--blockie) 22%, transparent);
  border-color: transparent;
}
.paper-actions { margin-bottom: 1.4rem; }

/* The saved library */
.libgroup { margin-bottom: 1.4rem; }
.librow { background: var(--surface); border-radius: 14px; padding: 0.8rem 0.9rem; display: grid; gap: 0.6rem; }
.librow__open {
  display: grid; gap: 0.15rem; text-align: left; font: inherit; color: inherit;
  background: none; border: 0; cursor: pointer; padding: 0;
}
.librow__open b { font-family: var(--font-display); font-size: 1.02rem; }
.librow__open span { font-size: 0.82rem; color: var(--ink-soft); }
.librow__open i { font-style: normal; font-size: 0.76rem; color: var(--ink-faint); }
/* Actions, not information.
   These were the neutral `chip` grey, which is the same treatment as the "12 of
   242" counts elsewhere in the app, so a row of things you can DO read as a row
   of labels. They take the accent instead.
   Delete keeps the destructive colour rather than joining them: it is the only
   one here with no undo, and a row where every action looks identical is where
   somebody deletes a paper meaning to rename it. */
.librow__acts { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.librow__acts .chip--btn {
  background: color-mix(in srgb, var(--blockie) 14%, transparent);
  color: var(--blockie);
  font-weight: 600;
}
.librow__acts .chip--btn:hover {
  filter: brightness(1.14);
  background: color-mix(in srgb, var(--blockie) 22%, transparent);
}
.librow__acts .chip--btn[data-action="paper-delete"] {
  background: color-mix(in srgb, var(--incorrect) 14%, transparent);
  color: var(--incorrect);
}
.librow__acts .chip--btn[data-action="paper-delete"]:hover {
  background: color-mix(in srgb, var(--incorrect) 22%, transparent);
}

/* ---------------------------------------------------------------------------
   Papers: the printed sheet

   One markup for the on-screen preview and for the printer, so a preview cannot
   disagree with what comes out. On screen it is a scaled-down page; in print
   everything else is hidden and this is laid out at exact A4.
   --------------------------------------------------------------------------- */

.sheet {
  background: #fff; color: #000;
  padding: 2rem; border-radius: 14px;
  border: 1px solid color-mix(in srgb, var(--ink) 16%, transparent);
  font-size: 0.92rem; line-height: 1.45;
}
.sheet__head h1 { font-family: var(--font-display); font-size: 1.5rem; margin: 0 0 0.8rem; color: #000; }
.sheet__fields { display: flex; flex-wrap: wrap; gap: 1.4rem; margin-bottom: 0.7rem; font-size: 0.9rem; }
.sheet__fields span { display: flex; align-items: baseline; gap: 0.5rem; flex: 1 1 8rem; }
.sheet__fields i { flex: 1; border-bottom: 1px solid #000; min-width: 4rem; height: 1rem; }
.sheet__allow { margin: 0 0 0.4rem; font-size: 0.9rem; }
.sheet__rubric { margin: 0 0 1.2rem; font-size: 0.84rem; }
.sheet__qs, .sheet__as { margin: 0; padding-left: 1.6rem; }
.sheet__q { margin-bottom: 1.1rem; break-inside: avoid; }
.sheet__prompt { margin-bottom: 0.4rem; }
.sheet__opts { list-style: upper-alpha; margin: 0.3rem 0 0; padding-left: 1.4rem; }
.sheet__opts li { margin-bottom: 0.15rem; }
.sheet__fig { margin: 0.5rem 0; }
.sheet__fig img { max-width: 100%; max-height: 46mm; }
.sheet__line { border-bottom: 1px solid #000; height: 1.4rem; margin-top: 0.3rem; }
.sheet__work { border: 1px solid #bbb; height: 3.4rem; margin-top: 0.3rem; border-radius: 4px; }
.sheet__key { margin-top: 2rem; }
.sheet__key h2 { font-family: var(--font-display); font-size: 1.2rem; margin: 0 0 0.3rem; color: #000; }
.sheet__a { break-inside: avoid; margin-bottom: 0.35rem; }
.sheet__an { display: none; }
.sheet__at { display: inline; }
.sheet__at b { font-weight: 700; }
.sheet__at i { font-style: normal; color: #555; font-size: 0.82rem; margin-left: 0.4rem; }
.sheet__foot { display: none; }

@media print {
  /* Exact A4, not Letter. */
  @page { size: A4; margin: 14mm 14mm 16mm; }

  /* Everything that is not the paper. The app chrome, the builder, the debug
     bar: a printed exam paper must not carry a navigation bar down its side. */
  body.webapp > *:not(#app), .bar, .crumbs, .backlink, .page-title, .lede,
  .paper-actions, .debugbar, .toast, .party, .webapp__foot { display: none !important; }

  body.webapp { background: #fff !important; }
  .wrap { max-width: none; padding: 0; }

  .sheet {
    border: 0; border-radius: 0; padding: 0;
    font-size: 11pt; line-height: 1.4; color: #000; background: #fff;
  }
  .sheet__head h1 { font-size: 17pt; }
  .sheet__q { margin-bottom: 9pt; }
  .sheet__fig img { max-height: 42mm; }

  /* The key always starts on its own page: a child must not be able to read the
     answers off the bottom of the last question. */
  .sheet__key { break-before: page; margin-top: 0; }

  /* Black and white by construction. A parent prints these weekly on an inkjet. */
  .sheet, .sheet * { color: #000 !important; background: transparent !important; }
  .sheet__at i { color: #444 !important; }
  .sheet__work { border-color: #999 !important; }
}

/* Three actions rather than two, so they wrap on a narrow window instead of
   squeezing the labels. */
.pager--paper { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 0.9rem; }
.pager--paper .btn { flex: 1 1 auto; }

/* ---------------------------------------------------------------------------
   Locked content

   Visible and legible, never hidden. A parent who cannot see what they would be
   buying has no reason to buy it, and hiding it makes the app look emptier than
   it is. Dimmed enough to read as unavailable, not so dim it cannot be read.
   --------------------------------------------------------------------------- */
.row--locked, .paper--locked, .flipcard--locked { opacity: 0.55; }
.row--locked { border-left-color: color-mix(in srgb, var(--ink) 22%, transparent); }
.row--locked:hover, .paper--locked:hover, .flipcard--locked:hover { opacity: 0.75; filter: none; }
.row--locked .row__state, .paper__mark.is-locked, .flipcard--locked .flipcard__hint { color: var(--ink-faint); }
.paper__mark.is-locked { background: none; }
.flipcard--locked { text-decoration: none; color: inherit; cursor: pointer; }
.flipcard--locked .flipcard__face { position: relative; inset: auto; }

/* The unlock screen */
.unlockcard { text-align: center; }
.unlockcard__art { display: grid; place-items: end center; width: 96px; margin: 0 auto 1rem; }
.unlockcard .rows { margin: 1.2rem 0; text-align: left; }
.unlockcard .row--stat { grid-template-columns: 1fr; }
.build__note--quota { margin-top: 0.7rem; text-align: center; }
