/* ==========================================================================
   GiftedPrep design system
   --------------------------------------------------------------------------
   One file. No dependencies. No build step. Works offline and from file://.

   WHO THIS IS FOR
   A six-to-ten year old on an iPad, with a parent nearby. Often a nervous
   child, days before a real test. So: calm, warm, generous. Nothing that
   flashes, buzzes or shakes. Touch targets a whole finger can hit.

   HOW IT IS ORGANISED
     1. Reset
     2. Tokens (light)
     3. Tokens (dark)
     4. Base elements
     5. Utilities
     6. Layout: app shell, top bar, footer
     7. Buttons, pills, chips, toggles
     8. Cards and grids
     9. Hero and page headers
    10. Question screen: progress, stem, choices, feedback
    11. Results: ring and bars
    12. Parent guide: prose, callouts, timeline, accordion
    13. Figures (inline SVG from figures.js)
    14. Motion, reduced motion, print
    15. The mascot (inline SVG from mascot.js)

   CLASS INVENTORY (so HTML can be wired without guessing)
     shell      .gp-app .gp-main .gp-screen[.is-active] .gp-container
                .gp-topbar .gp-topbar__left .gp-topbar__right
                .gp-brand .gp-brand__mark .gp-brand__name .gp-footer
                .gp-footer__links .gp-skip
     controls   .gp-btn [--primary|--ghost|--quiet|--lg|--icon] .gp-btn__label
                .gp-pill[.is-selected] .gp-toggle[.is-on]
                .gp-chip [--score|--streak]
                .gp-fieldset .gp-fieldset__legend
     cards      .gp-card [--test|--category|--action|--setup|--stats|--review]
                .gp-card__icon .gp-card__title .gp-card__sub .gp-card__badge
                .gp-card.is-selected
                .gp-grid [--tests|--categories|--start]
     headers    .gp-hero .gp-hero__eyebrow .gp-hero__title .gp-hero__lede
                .gp-page-title .gp-page-lede
     question   .gp-quiz .gp-progress .gp-progress__bar .gp-progress__fill
                .gp-progress__label
                .gp-question .gp-question__meta .gp-question__stemrow
                .gp-question__stem .gp-question__figure
                .gp-choices [--2col|--3col|--text]
                .gp-choice .gp-choice__badge .gp-choice__body .gp-choice__mark
                .gp-choice.is-selected|.is-correct|.is-incorrect|.is-revealed|.is-disabled
                .gp-feedback[.is-positive|.is-retry] .gp-feedback__head
                .gp-feedback__icon .gp-feedback__title .gp-feedback__body
                .gp-feedback__strategy .gp-feedback__actions
     results    .gp-results .gp-results__top .gp-ring .gp-ring__track
                .gp-ring__value .gp-ring__label
                .gp-bars .gp-bar .gp-bar__label .gp-bar__track .gp-bar__fill
                .gp-bar__value
     guide      .gp-prose .gp-callout[--tip|--info|--caution] .gp-callout__title
                .gp-timeline .gp-timeline__item .gp-timeline__day
                .gp-timeline__body
                .gp-accordion .gp-accordion__trigger .gp-accordion__panel
     mascot     .cz-mascot[data-mood=idle|curious|happy|oops|think|sleep]
                .cz-mascot__head .cz-mascot__ear[--l|--r]
                .cz-mascot__eye[--l|--r] .cz-mascot__pupils
                .cz-mascot__eyes[--open|--happy|--sleep]
                .cz-mascot__fx .cz-mascot__spark .cz-mascot__dot .cz-mascot__z
     figures    .gp-fig
     utilities  .gp-sr-only .gp-stack .gp-row[.--wrap|.--tools] .gp-hidden
                .gp-center .gp-muted
   ========================================================================== */


/* ==========================================================================
   1. Reset — :where() so specificity stays at 0 and anything can override
   ========================================================================== */

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

:where(html) {
  -webkit-text-size-adjust: 100%;   /* iOS must not inflate text on rotate */
  text-size-adjust: 100%;
  -moz-text-size-adjust: 100%;
}

:where(body, h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd, ul, ol) {
  margin: 0;
}

:where(ul[class], ol[class]) { list-style: none; padding: 0; }

:where(img, svg, video, canvas) { display: block; max-width: 100%; }
:where(img, video) { height: auto; }

:where(input, button, textarea, select) { font: inherit; color: inherit; }

:where(button) { background: none; border: 0; }

:where(a) { color: inherit; }

:where(fieldset) { border: 0; padding: 0; margin: 0; }

:where(table) { border-collapse: collapse; width: 100%; }


/* ==========================================================================
   2. Tokens — light. Defined on bare :root so nothing lives only in a query.
   --------------------------------------------------------------------------
   Contrast ratios measured against the surface each colour actually sits on.
   ========================================================================== */

:root {
  color-scheme: light dark;

  /* --- Surfaces ------------------------------------------------------- */
  --gp-bg:            #FDFBF7;   /* warm cream, not clinical white       */
  --gp-surface:       #FFFFFF;
  --gp-surface-2:     #F4F0E7;
  --gp-surface-3:     #EAE4D7;

  /* --- Text ----------------------------------------------------------- */
  --gp-ink:           #2B2926;   /* on --gp-bg      13.9:1  AAA          */
  --gp-ink-soft:      #58524A;   /* on --gp-bg       7.1:1  AAA          */
  --gp-ink-muted:     #756E64;   /* on --gp-bg       4.9:1  AA           */
  --gp-on-accent:     #FFFFFF;

  /* --- Brand ---------------------------------------------------------- */
  --gp-accent:        #BA5828;   /* on cream page    4.50:1 AA           */
  --gp-accent-strong: #9A4519;
  --gp-accent-soft:   #FBEDE4;
  --gp-accent-line:   #E9C4AC;

  --gp-secondary:       #26707C;  /* on white         4.9:1  AA          */
  --gp-secondary-soft:  #E3F1F2;
  --gp-secondary-line:  #A9D2D7;

  /* --- Semantic. Deliberately gentle: no pure red, no siren green. ---- */
  --gp-good:          #2F7D4F;   /* on white         4.8:1  AA           */
  --gp-good-soft:     #E5F3EA;
  --gp-good-line:     #A6D5B8;

  --gp-retry:         #9A6410;   /* amber, never red. on white 4.9:1 AA  */
  --gp-retry-soft:    #FBF0DC;
  --gp-retry-line:    #E4C489;


  /* --- CurioZoo palette ------------------------------------------------
     Eight hues, one per section, spread far enough apart that no two can be
     confused. Every value was searched until it clears AA 4.5:1 on BOTH the
     cream page and a white card -- cream is the harder of the two, which is
     what the old accent failed against.

     Deep is the contrast to the orange. Hue alone was not enough: tuned only
     against the background, Mango and Lagoon landed on the same lightness and
     measured 1.00:1 against each other. Deep is 3.0:1 against Mango, so the
     pair reads as a pair, including without colour vision. */
  --cz-deep:         #0A303D;
  --cz-deep-soft:    #E6F1F5;
  --cz-deep-line:    #B9D5DE;

  /* What is allowed to sit ON Deep. The brand orange is NOT: #BA5828 measures
     3.00:1 there, and 2.30:1 on the dark theme's Deep, so orange type on a
     deep teal panel fails as text in both themes -- it looked muddy before it
     was measured. Deep is a dark surface, so it borrows the dark theme's
     lifted accent, which clears AA on both. */
  --cz-on-deep:        #FDFBF7;   /* 13.52:1  AAA                             */
  --cz-on-deep-muted:  #A1AEB0;   /*  6.12:1  AA                              */
  --cz-on-deep-accent: #F0A16A;   /*  6.66:1  AA                              */
  --cz-mango:        #BA5828;
  --cz-mango-soft:   #FEEDE4;
  --cz-mango-line:   #F0C0A8;
  --cz-honey:        #926F1C;
  --cz-honey-soft:   #FEF6E4;
  --cz-honey-line:   #F1DBA7;
  --cz-leaf:        #328442;
  --cz-leaf-soft:   #E7FBEB;
  --cz-leaf-line:   #B3E6BD;
  --cz-jade:        #29826C;
  --cz-jade-soft:   #E6FCF6;
  --cz-jade-line:   #AFE9DB;
  --cz-lagoon:        #297D9A;
  --cz-lagoon-soft:   #E5F7FD;
  --cz-lagoon-line:   #ACDCEC;
  --cz-sky:        #4173C8;
  --cz-sky-soft:   #E6EEFC;
  --cz-sky-line:   #ADC4EB;
  --cz-orchid:        #995AB8;
  --cz-orchid-soft:   #F4E8FA;
  --cz-orchid-line:   #D4B5E3;
  --cz-flamingo:        #C84374;
  --cz-flamingo-soft:   #FCE6EE;
  --cz-flamingo-line:   #EBADC4;

  /* Text on a tinted room card. The section colour itself measured between
     3.92:1 and 4.36:1 against its own soft tint -- below AA on the room's
     name, which is the one word that has to be readable. */
  --cz-mango-ink:    #AF5325;
  --cz-honey-ink:    #8F6C1B;
  --cz-leaf-ink:    #318041;
  --cz-jade-ink:    #287F6A;
  --cz-lagoon-ink:    #277894;
  --cz-sky-ink:    #386AC1;
  --cz-orchid-ink:    #914EB3;
  --cz-flamingo-ink:    #BD3768;

  --gp-line:          #E2DCCF;
  --gp-line-strong:   #C9C0AE;
  --gp-focus:         #1E6B96;   /* focus ring, distinct from all states */

  /* --- Type ----------------------------------------------------------- */
  --gp-font-ui: ui-rounded, "SF Pro Rounded", -apple-system,
                "Segoe UI Variable Display", "Segoe UI", Nunito,
                "Trebuchet MS", system-ui, sans-serif;
  --gp-font-read: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
                  system-ui, "Helvetica Neue", Arial, sans-serif;
  --gp-font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
                  monospace;

  /* Fluid scale. Clamps keep a stem readable on a phone and calm on iPad. */
  --gp-text-xs:   0.8125rem;
  --gp-text-sm:   0.9375rem;
  --gp-text-base: clamp(1rem, 0.96rem + 0.2vw, 1.0625rem);
  --gp-text-md:   clamp(1.0625rem, 1rem + 0.35vw, 1.1875rem);
  --gp-text-lg:   clamp(1.1875rem, 1.08rem + 0.55vw, 1.375rem);
  --gp-text-xl:   clamp(1.375rem, 1.2rem + 0.85vw, 1.75rem);
  --gp-text-2xl:  clamp(1.625rem, 1.35rem + 1.35vw, 2.25rem);
  --gp-text-3xl:  clamp(2rem, 1.55rem + 2.1vw, 2.9rem);

  --gp-leading-tight: 1.2;
  --gp-leading-snug:  1.4;
  --gp-leading-body:  1.65;

  /* --- Space (4px base) ----------------------------------------------- */
  --gp-space-1:  0.25rem;
  --gp-space-2:  0.5rem;
  --gp-space-3:  0.75rem;
  --gp-space-4:  1rem;
  --gp-space-5:  1.25rem;
  --gp-space-6:  1.5rem;
  --gp-space-8:  2rem;
  --gp-space-10: 2.5rem;
  --gp-space-12: 3rem;
  --gp-space-16: 4rem;

  /* --- Radius --------------------------------------------------------- */
  --gp-radius-sm:   8px;
  --gp-radius-md:   14px;
  --gp-radius-lg:   20px;
  --gp-radius-xl:   28px;
  --gp-radius-pill: 999px;

  /* --- Shadow: layered and soft, never a hard drop ---------------------- */
  --gp-shadow-1: 0 1px 2px rgba(43, 41, 38, 0.05),
                 0 2px 6px rgba(43, 41, 38, 0.05);
  --gp-shadow-2: 0 2px 4px rgba(43, 41, 38, 0.06),
                 0 6px 16px rgba(43, 41, 38, 0.08);
  --gp-shadow-3: 0 4px 8px rgba(43, 41, 38, 0.07),
                 0 14px 34px rgba(43, 41, 38, 0.10);

  /* --- Motion --------------------------------------------------------- */
  --gp-dur-fast: 120ms;
  --gp-dur-mid:  220ms;
  --gp-dur-slow: 380ms;
  --gp-ease:     cubic-bezier(0.22, 0.72, 0.28, 1);

  /* --- Layout --------------------------------------------------------- */
  --gp-measure:  68ch;         /* readable line length for the guide      */
  --gp-shell:    1180px;
  --gp-tap:      64px;         /* minimum touch target                    */

  /* --- Figure colours (consumed by figures.js) ------------------------ */
  /* The canvas inside each figure cell stays light in BOTH themes. Shapes
     are drawn with a dark stroke, so a dark canvas would erase them, and a
     printed page would lose them entirely. Only the surround changes.    */
  --gp-fig-blue:   #2F6FB5;
  --gp-fig-red:    #C4503C;
  --gp-fig-green:  #3E8B5C;
  --gp-fig-yellow: #DFA22C;
  --gp-fig-purple: #7A5BB0;
  --gp-fig-orange: #D9762F;
  --gp-fig-teal:   #2C8A96;
  --gp-fig-pink:   #C55E93;
  --gp-fig-grey:   #8A8F99;
  --gp-fig-ink:    #2B2926;
  --gp-fig-stroke: #2B2926;
  --gp-fig-canvas: #FFFFFF;
  --gp-fig-frame:  #C9CEDA;
  --gp-fig-muted:  #8E95A3;
}


/* ==========================================================================
   3. Tokens — dark.
   Two blocks: the media query for "system" (no data-theme stamped), and the
   explicit attribute so a manual toggle wins in both directions.
   ========================================================================== */

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --gp-bg:            #15181E;
    --gp-surface:       #1E222A;
    --gp-surface-2:     #262B35;
    --gp-surface-3:     #313742;

    --gp-ink:           #EDEAE4;   /* on --gp-bg   14.2:1  AAA           */
    --gp-ink-soft:      #C2BCB2;   /* on --gp-bg    8.8:1  AAA           */
    --gp-ink-muted:     #99928A;   /* on --gp-bg    5.5:1  AA            */
    --gp-on-accent:     #17120E;

    --gp-accent:        #F0A16A;   /* on --gp-surface  8.4:1  AAA        */
    --gp-accent-strong: #F7BE93;
    --gp-accent-soft:   #33241A;
    --gp-accent-line:   #6A452C;

    --gp-secondary:      #6FC3CE;
    --gp-secondary-soft: #122E33;
    --gp-secondary-line: #2C5A61;

    --gp-good:          #74C795;   /* on --gp-surface  8.1:1  AAA        */
    --gp-good-soft:     #16301F;
    --gp-good-line:     #2E5A3E;

    --gp-retry:         #E8B968;   /* on --gp-surface  9.3:1  AAA        */
    --gp-retry-soft:    #33270F;
    --gp-retry-line:    #6A5124;


    /* --- CurioZoo palette, dark. Same hues, lifted until each clears AA on
       the dark card, which is the lighter and therefore harder surface. */
    --cz-deep:         #184353;
    --cz-deep-soft:    #0E2831;
    --cz-deep-line:    #2A5A6C;
    --cz-on-deep:        #FDFBF7;   /* 10.33:1  AAA                           */
    --cz-on-deep-muted:  #A1AEB0;   /*  4.68:1  AA                            */
    --cz-on-deep-accent: #F0A16A;   /*  5.09:1  AA                            */
    --cz-mango:        #DD6528;
    --cz-mango-soft:   #2D1F18;
    --cz-mango-line:   #624537;
    --cz-honey:        #AD8118;
    --cz-honey-soft:   #2D2718;
    --cz-honey-line:   #625537;
    --cz-leaf:        #309C45;
    --cz-leaf-soft:   #182D1C;
    --cz-leaf-line:   #376240;
    --cz-jade:        #26997C;
    --cz-jade-soft:   #182D28;
    --cz-jade-line:   #376257;
    --cz-lagoon:        #2593B7;
    --cz-lagoon-soft:   #18282D;
    --cz-lagoon-line:   #375762;
    --cz-sky:        #5888D9;
    --cz-sky-soft:   #18202D;
    --cz-sky-line:   #374762;
    --cz-orchid:        #AD6FCD;
    --cz-orchid-soft:   #26182D;
    --cz-orchid-line:   #543762;
    --cz-flamingo:        #DA5E8B;
    --cz-flamingo-soft:   #2D1820;
    --cz-flamingo-line:   #623747;

    --cz-mango-ink:    #DD6528;
    --cz-honey-ink:    #B58619;
    --cz-leaf-ink:    #32A348;
    --cz-jade-ink:    #28A182;
    --cz-lagoon-ink:    #2697BC;
    --cz-sky-ink:    #5586D9;
    --cz-orchid-ink:    #AA6ACB;
    --cz-flamingo-ink:    #D95887;

    --gp-line:          #333944;
    --gp-line-strong:   #48505D;
    --gp-focus:         #6BB6E0;

    --gp-shadow-1: 0 1px 2px rgba(0, 0, 0, 0.35),
                   0 2px 6px rgba(0, 0, 0, 0.30);
    --gp-shadow-2: 0 2px 4px rgba(0, 0, 0, 0.38),
                   0 6px 16px rgba(0, 0, 0, 0.34);
    --gp-shadow-3: 0 4px 8px rgba(0, 0, 0, 0.42),
                   0 14px 34px rgba(0, 0, 0, 0.40);

    /* Figure fills brighten slightly; canvas stays light on purpose. */
    --gp-fig-blue:   #3D82CE;
    --gp-fig-red:    #D65F49;
    --gp-fig-green:  #46A06A;
    --gp-fig-yellow: #E8AE38;
    --gp-fig-purple: #8D6BC9;
    --gp-fig-orange: #E5843A;
    --gp-fig-teal:   #339CAA;
    --gp-fig-pink:   #D46FA4;
    --gp-fig-canvas: #F7F5F0;
    --gp-fig-frame:  #A9B0BE;
    --gp-fig-muted:  #79808E;
  }
}

:root[data-theme="dark"] {
  --gp-bg:            #15181E;
  --gp-surface:       #1E222A;
  --gp-surface-2:     #262B35;
  --gp-surface-3:     #313742;

  --gp-ink:           #EDEAE4;
  --gp-ink-soft:      #C2BCB2;
  --gp-ink-muted:     #99928A;
  --gp-on-accent:     #17120E;

  --gp-accent:        #F0A16A;
  --gp-accent-strong: #F7BE93;
  --gp-accent-soft:   #33241A;
  --gp-accent-line:   #6A452C;

  --gp-secondary:      #6FC3CE;
  --gp-secondary-soft: #122E33;
  --gp-secondary-line: #2C5A61;

  --gp-good:          #74C795;
  --gp-good-soft:     #16301F;
  --gp-good-line:     #2E5A3E;

  --gp-retry:         #E8B968;
  --gp-retry-soft:    #33270F;
  --gp-retry-line:    #6A5124;

  --gp-line:          #333944;
  --gp-line-strong:   #48505D;
  --gp-focus:         #6BB6E0;

  --gp-shadow-1: 0 1px 2px rgba(0, 0, 0, 0.35), 0 2px 6px rgba(0, 0, 0, 0.30);
  --gp-shadow-2: 0 2px 4px rgba(0, 0, 0, 0.38), 0 6px 16px rgba(0, 0, 0, 0.34);
  --gp-shadow-3: 0 4px 8px rgba(0, 0, 0, 0.42), 0 14px 34px rgba(0, 0, 0, 0.40);

  --gp-fig-blue:   #3D82CE;
  --gp-fig-red:    #D65F49;
  --gp-fig-green:  #46A06A;
  --gp-fig-yellow: #E8AE38;
  --gp-fig-purple: #8D6BC9;
  --gp-fig-orange: #E5843A;
  --gp-fig-teal:   #339CAA;
  --gp-fig-pink:   #D46FA4;
  --gp-fig-canvas: #F7F5F0;
  --gp-fig-frame:  #A9B0BE;
  --gp-fig-muted:  #79808E;
}


/* ==========================================================================
   4. Base
   ========================================================================== */

body {
  margin: 0;
  min-height: 100dvh;
  background: var(--gp-bg);           /* explicit: never borrow the host's */
  color: var(--gp-ink);
  font-family: var(--gp-font-ui);
  font-size: var(--gp-text-base);
  line-height: var(--gp-leading-body);
  -webkit-font-smoothing: antialiased;
  display: flex;
  flex-direction: column;
  padding-left: env(safe-area-inset-left);
  padding-right: env(safe-area-inset-right);
}

button, a, label, summary, [role="button"] {
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

:focus-visible {
  outline: 3px solid var(--gp-focus);
  outline-offset: 2px;
  border-radius: var(--gp-radius-sm);
}
:focus:not(:focus-visible) { outline: none; }

::selection { background: var(--gp-accent-soft); color: var(--gp-ink); }


/* ==========================================================================
   5. Utilities
   ========================================================================== */

.gp-sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.gp-hidden, [hidden] { display: none !important; }

.gp-center { text-align: center; }

.gp-muted { color: var(--gp-ink-muted); font-size: var(--gp-text-sm); }

.gp-stack { display: flex; flex-direction: column; gap: var(--gp-space-6); }

.gp-row {
  display: flex;
  align-items: center;
  gap: var(--gp-space-3);
}
.gp-row--wrap { flex-wrap: wrap; }
.gp-row--tools { justify-content: space-between; gap: var(--gp-space-4); }

.gp-skip {
  position: absolute;
  left: var(--gp-space-4);
  top: -100px;
  z-index: 100;
  padding: var(--gp-space-3) var(--gp-space-5);
  background: var(--gp-accent);
  color: var(--gp-on-accent);
  border-radius: var(--gp-radius-md);
  font-weight: 700;
  text-decoration: none;
  transition: top var(--gp-dur-fast) var(--gp-ease);
}
.gp-skip:focus { top: var(--gp-space-4); }


/* ==========================================================================
   6. Shell
   ========================================================================== */

.gp-container {
  width: 100%;
  max-width: var(--gp-shell);
  margin-inline: auto;
  padding-inline: var(--gp-space-5);
}

.gp-main {
  flex: 1 1 auto;
  padding-block: var(--gp-space-8) var(--gp-space-12);
}

/* Screens are all in the DOM; the router flips .is-active. */
.gp-screen { display: none; }
.gp-screen.is-active { display: block; animation: gp-fade var(--gp-dur-mid) var(--gp-ease); }

@keyframes gp-fade {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

.gp-topbar {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gp-space-3);
  padding: var(--gp-space-3) var(--gp-space-5);
  padding-top: calc(var(--gp-space-3) + env(safe-area-inset-top));
  background: color-mix(in srgb, var(--gp-bg) 88%, transparent);
  backdrop-filter: saturate(180%) blur(12px);
  -webkit-backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid var(--gp-line);
}

.gp-topbar__left,
.gp-topbar__right {
  display: flex;
  align-items: center;
  gap: var(--gp-space-2);
  min-width: 0;
}

.gp-brand {
  display: inline-flex;
  align-items: center;
  gap: var(--gp-space-2);
  text-decoration: none;
  font-weight: 800;
  font-size: var(--gp-text-md);
  letter-spacing: -0.01em;
  /* The mark carries its own whitespace, so the wrapper adds almost none: the
     padding was making a 34px logo sit in a 50px hole. */
  padding: 2px var(--gp-space-2) 2px 0;
  border-radius: var(--gp-radius-md);
}
/* The mark carries its own colours now, so it sits on the bar rather than
   inside a tinted tile: a gradient chip behind an animal reads as two logos. */
.gp-brand__mark {
  display: grid;
  place-items: center;
  width: 46px; height: 46px;
  flex: none;
}
.gp-brand__mark svg { width: 46px; height: 46px; }
.gp-brand__name { white-space: nowrap; }
.gp-brand__zoo { color: var(--gp-accent); }

.gp-footer {
  border-top: 1px solid var(--gp-line);
  padding: var(--gp-space-8) var(--gp-space-5);
  padding-bottom: calc(var(--gp-space-8) + env(safe-area-inset-bottom));
  color: var(--gp-ink-muted);
  font-size: var(--gp-text-xs);
  line-height: 1.6;
  text-align: center;
  max-width: 78ch;
  margin-inline: auto;
}
.gp-footer__links {
  margin-top: var(--gp-space-3);
  display: flex;
  gap: var(--gp-space-5);
  justify-content: center;
  flex-wrap: wrap;
}
.gp-footer a { color: var(--gp-secondary); text-underline-offset: 3px; }


/* ==========================================================================
   7. Buttons, pills, chips
   ========================================================================== */

.gp-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--gp-space-2);
  min-height: 48px;
  padding: var(--gp-space-3) var(--gp-space-5);
  border-radius: var(--gp-radius-pill);
  border: 2px solid transparent;
  background: var(--gp-surface-2);
  color: var(--gp-ink);
  font-family: inherit;
  font-size: var(--gp-text-base);
  font-weight: 700;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition: transform var(--gp-dur-fast) var(--gp-ease),
              background-color var(--gp-dur-fast) var(--gp-ease),
              border-color var(--gp-dur-fast) var(--gp-ease),
              box-shadow var(--gp-dur-fast) var(--gp-ease);
}
.gp-btn:hover { background: var(--gp-surface-3); }
.gp-btn:active { transform: scale(0.97); }
.gp-btn svg { width: 20px; height: 20px; flex: none; }

.gp-btn--primary {
  background: var(--gp-accent);
  color: var(--gp-on-accent);
  box-shadow: var(--gp-shadow-2);
}
.gp-btn--primary:hover { background: var(--gp-accent-strong); }

.gp-btn--ghost {
  background: transparent;
  border-color: var(--gp-line-strong);
  color: var(--gp-ink);
}
.gp-btn--ghost:hover { background: var(--gp-surface-2); }

.gp-btn--quiet {
  background: transparent;
  color: var(--gp-ink-soft);
}
.gp-btn--quiet:hover { background: var(--gp-surface-2); color: var(--gp-ink); }

.gp-btn--lg {
  min-height: var(--gp-tap);
  padding: var(--gp-space-4) var(--gp-space-8);
  font-size: var(--gp-text-md);
}

.gp-btn--icon {
  min-height: 48px;
  width: 48px;
  padding: 0;
  flex: none;
}
.gp-btn--icon svg { width: 22px; height: 22px; }

.gp-btn.is-active {
  background: var(--gp-accent-soft);
  border-color: var(--gp-accent-line);
  color: var(--gp-accent-strong);
}

.gp-btn[disabled],
.gp-btn[aria-disabled="true"] {
  opacity: 0.45;
  cursor: not-allowed;
  transform: none;
}

/* On narrow screens the top bar keeps the icons and drops the words. During a
   quiz it carries a back button, the brand, two chips and three controls, which
   will not fit on a 375px phone, so the wordmark and the button labels go. */
@media (max-width: 720px) {
  .gp-topbar .gp-btn__label { display: none; }
  .gp-topbar .gp-btn--quiet { width: 48px; padding: 0; }
}
@media (max-width: 560px) {
  .gp-topbar { padding-inline: var(--gp-space-3); gap: var(--gp-space-1); }
  .gp-brand__name { display: none; }
  .gp-topbar__left, .gp-topbar__right { gap: var(--gp-space-1); }
  .gp-chip { padding: var(--gp-space-2) var(--gp-space-3); font-size: var(--gp-text-xs); }
  .gp-btn--icon { width: 44px; min-height: 44px; }
}
/* Below this the score chip has to go too, or nothing fits. The score is still
   announced in the feedback panel and shown in full on the results screen. */
@media (max-width: 400px) {
  .gp-chip--streak { display: none; }
}

/* Grade picker */
.gp-pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 56px;
  min-width: 108px;
  padding: var(--gp-space-3) var(--gp-space-5);
  border-radius: var(--gp-radius-pill);
  border: 2px solid var(--gp-line-strong);
  background: var(--gp-surface);
  color: var(--gp-ink-soft);
  font-weight: 700;
  font-size: var(--gp-text-base);
  cursor: pointer;
  transition: all var(--gp-dur-fast) var(--gp-ease);
}
.gp-pill:hover { border-color: var(--gp-accent-line); color: var(--gp-ink); }
.gp-pill:active { transform: scale(0.97); }
.gp-pill.is-selected {
  background: var(--gp-accent);
  border-color: var(--gp-accent);
  color: var(--gp-on-accent);
  box-shadow: var(--gp-shadow-2);
}

.gp-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--gp-space-2);
  padding: var(--gp-space-2) var(--gp-space-4);
  border-radius: var(--gp-radius-pill);
  background: var(--gp-surface-2);
  border: 1px solid var(--gp-line);
  font-size: var(--gp-text-sm);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.gp-chip svg { width: 17px; height: 17px; }
.gp-chip--score  { background: var(--gp-good-soft);  border-color: var(--gp-good-line);  color: var(--gp-good); }
.gp-chip--streak { background: var(--gp-accent-soft); border-color: var(--gp-accent-line); color: var(--gp-accent-strong); }

.gp-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--gp-space-3);
  cursor: pointer;
  min-height: 48px;
}
.gp-toggle::before {
  content: "";
  width: 52px; height: 30px;
  border-radius: var(--gp-radius-pill);
  background: var(--gp-line-strong);
  position: relative;
  transition: background-color var(--gp-dur-mid) var(--gp-ease);
  flex: none;
  box-shadow: inset 0 0 0 2px transparent;
}
.gp-toggle::after {
  content: "";
  position: absolute;
  width: 24px; height: 24px;
  margin-left: 3px;
  border-radius: 50%;
  background: #fff;
  box-shadow: var(--gp-shadow-1);
  transition: transform var(--gp-dur-mid) var(--gp-ease);
}
.gp-toggle.is-on::before { background: var(--gp-good); }
.gp-toggle.is-on::after  { transform: translateX(22px); }

.gp-fieldset { margin-top: var(--gp-space-4); }
.gp-fieldset__legend {
  font-size: var(--gp-text-sm);
  font-weight: 700;
  color: var(--gp-ink-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: var(--gp-space-3);
}


/* ==========================================================================
   8. Cards and grids
   ========================================================================== */

.gp-card {
  background: var(--gp-surface);
  border: 1px solid var(--gp-line);
  border-radius: var(--gp-radius-xl);
  padding: var(--gp-space-6);
  box-shadow: var(--gp-shadow-1);
}

.gp-card__title {
  font-size: var(--gp-text-lg);
  font-weight: 800;
  line-height: var(--gp-leading-snug);
  letter-spacing: -0.01em;
  margin-bottom: var(--gp-space-2);
}

.gp-card__sub {
  color: var(--gp-ink-soft);
  font-size: var(--gp-text-sm);
  line-height: 1.55;
}

.gp-card__icon {
  display: grid;
  place-items: center;
  width: 56px; height: 56px;
  border-radius: var(--gp-radius-md);
  background: var(--gp-accent-soft);
  color: var(--gp-accent-strong);
  margin-bottom: var(--gp-space-4);
  flex: none;
}
.gp-card__icon svg { width: 30px; height: 30px; }

.gp-card__badge {
  display: inline-block;
  margin-top: var(--gp-space-3);
  padding: 2px var(--gp-space-3);
  border-radius: var(--gp-radius-pill);
  background: var(--gp-surface-2);
  border: 1px solid var(--gp-line);
  color: var(--gp-ink-muted);
  font-size: var(--gp-text-xs);
  font-weight: 700;
}

/* Non-tappable card variants — the base .gp-card plus a little context. */
.gp-card--setup  { border-color: var(--gp-accent-line); }
.gp-card--stats  { background: var(--gp-surface-2); }
.gp-card--review { border-left: 5px solid var(--gp-retry); }
.gp-card--setup > * + *,
.gp-card--stats > * + *,
.gp-card--review > * + * { margin-top: var(--gp-space-4); }

/* Tappable card variants */
.gp-card--action,
.gp-card--test,
.gp-card--category {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  min-height: 132px;
  transition: transform var(--gp-dur-fast) var(--gp-ease),
              box-shadow var(--gp-dur-mid) var(--gp-ease),
              border-color var(--gp-dur-fast) var(--gp-ease);
}
.gp-card--action:hover,
.gp-card--test:hover,
.gp-card--category:hover {
  border-color: var(--gp-accent-line);
  box-shadow: var(--gp-shadow-3);
  transform: translateY(-3px);
}
.gp-card--action:active,
.gp-card--test:active,
.gp-card--category:active { transform: translateY(0) scale(0.985); }

.gp-card--test .gp-card__icon {
  background: var(--gp-secondary-soft);
  color: var(--gp-secondary);
  width: 62px; height: 62px;
}
.gp-card--category { min-height: 112px; padding: var(--gp-space-5); }
.gp-card--category .gp-card__icon {
  width: 46px; height: 46px;
  margin-bottom: var(--gp-space-3);
}
.gp-card--category .gp-card__icon svg { width: 26px; height: 26px; }
.gp-card--category .gp-card__title { font-size: var(--gp-text-md); }

.gp-card.is-selected {
  border-color: var(--gp-accent);
  box-shadow: 0 0 0 3px var(--gp-accent-soft), var(--gp-shadow-2);
}

/* The category picker is a stack of groups. Each group has a heading and its
   own grid; the outer element must NOT be a grid, or the headings land in the
   same columns as the cards. */
.gp-catgroups {
  display: flex;
  flex-direction: column;
  gap: var(--gp-space-8);
}

/* Battery headings above a group of category cards. */
.gp-battery-head {
  font-size: var(--gp-text-md);
  font-weight: 800;
  letter-spacing: -0.01em;
  margin: var(--gp-space-6) 0 var(--gp-space-3);
}
.gp-battery-head:first-child { margin-top: 0; }
.gp-battery-head .gp-muted { font-weight: 500; }

.gp-grid { display: grid; gap: var(--gp-space-5); }

.gp-grid--start,
.gp-grid--tests {
  grid-template-columns: repeat(auto-fit, minmax(258px, 1fr));
}
.gp-grid--categories {
  grid-template-columns: repeat(auto-fill, minmax(232px, 1fr));
  gap: var(--gp-space-4);
}


/* ==========================================================================
   9. Hero and page headers
   ========================================================================== */

/* On a wide screen the hero and the grade picker sit side by side, so an iPad
   in landscape does not open on a half-empty page. */
.gp-home-top {
  display: grid;
  gap: var(--gp-space-6);
  align-items: center;
}
@media (min-width: 900px) {
  .gp-home-top { grid-template-columns: 1.05fr 0.95fr; gap: var(--gp-space-10); }
}

.gp-hero { max-width: 40ch; }
.gp-hero__eyebrow {
  color: var(--gp-secondary);
  font-size: var(--gp-text-sm);
  font-weight: 700;
  letter-spacing: 0.03em;
  margin-bottom: var(--gp-space-3);
}
.gp-hero__title {
  font-size: var(--gp-text-3xl);
  line-height: var(--gp-leading-tight);
  letter-spacing: -0.025em;
  font-weight: 800;
  text-wrap: balance;
}
.gp-hero__lede {
  margin-top: var(--gp-space-4);
  font-size: var(--gp-text-md);
  color: var(--gp-ink-soft);
  max-width: 56ch;
}

.gp-page-title {
  font-size: var(--gp-text-2xl);
  font-weight: 800;
  line-height: var(--gp-leading-tight);
  letter-spacing: -0.02em;
  text-wrap: balance;
}
/* The lede sits under the page title. It used to carry a negative top margin,
   which pulled it up hard against the heading: measured at -8px, so the two
   boxes actually overlapped. A real gap instead. */
.gp-page-lede {
  color: var(--gp-ink-soft);
  max-width: 62ch;
  margin-top: var(--gp-space-3);
}

.gp-grade-note { margin-top: var(--gp-space-4); }

/* A page heading with a control beside it — used by the Parent Guide's
   language switch. The control sits at the right on a wide screen and stays
   at the right when it wraps onto its own line on a phone, so it never reads
   as a stray button hanging under the title. */
.gp-page-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gp-space-3) var(--gp-space-4);
  flex-wrap: wrap;
  margin-bottom: var(--gp-space-6);
}
.gp-page-head .gp-page-title { margin: 0; }

/* Flags are colour emoji; keep them off the text stack so they render the same
   on every platform, and give them room to breathe next to the label. */
.gp-flag {
  font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif;
  font-size: 1.25em;
  line-height: 1;
}
/* margin-left:auto keeps the switch hard right in both states: beside the
   title, and on its own line once the pair no longer fits. */
#gp-lang-toggle { flex: none; margin-left: auto; }

/* The set-length pills hold one or two digits, so the 108px min-width meant
   for word labels pushed them onto a second row on a phone. They keep the full
   56px height, so the touch target is unchanged. */
#gp-count-picker .gp-pill {
  min-width: 0;
  flex: 1 1 0;
  padding-inline: var(--gp-space-3);
}
@media (max-width: 560px) {
  /* The label stays here even though the top bar drops its labels: the flag
     alone is not an accessible name for a language switch. */
  #gp-lang-toggle .gp-btn__label { display: inline; }
}


/* ==========================================================================
   10. Question screen
   ========================================================================== */

.gp-quiz {
  max-width: 940px;
  display: flex;
  flex-direction: column;
  gap: var(--gp-space-5);
}

.gp-progress { display: flex; flex-direction: column; gap: var(--gp-space-2); }
.gp-progress__bar {
  height: 12px;
  border-radius: var(--gp-radius-pill);
  background: var(--gp-surface-3);
  overflow: hidden;
}
.gp-progress__fill {
  height: 100%;
  width: 0;
  border-radius: inherit;
  background: linear-gradient(90deg, var(--gp-secondary), var(--gp-accent));
  transition: width var(--gp-dur-slow) var(--gp-ease);
}
.gp-progress__label {
  font-size: var(--gp-text-sm);
  color: var(--gp-ink-muted);
  font-weight: 700;
  text-align: center;
  flex: 1 1 auto;
}

/* Arrows either side of the counter, for stepping back over answered puzzles. */
.gp-progress__nav {
  display: flex;
  align-items: center;
  gap: var(--gp-space-2);
}
.gp-progress__nav .gp-btn--icon { flex: none; }

/* A puzzle being looked at again, rather than answered for the first time. */
.gp-review-note {
  display: flex;
  align-items: center;
  gap: var(--gp-space-2);
  margin-top: var(--gp-space-3);
  padding: var(--gp-space-2) var(--gp-space-4);
  border-radius: var(--gp-radius-pill);
  background: var(--gp-secondary-soft);
  border: 1px solid var(--gp-secondary-line);
  color: var(--gp-secondary);
  font-size: var(--gp-text-sm);
  font-weight: 700;
  width: fit-content;
}
.gp-review-note svg { width: 17px; height: 17px; }

.gp-question {
  background: var(--gp-surface);
  border: 1px solid var(--gp-line);
  border-radius: var(--gp-radius-xl);
  padding: var(--gp-space-6);
  box-shadow: var(--gp-shadow-1);
}
.gp-question__meta {
  font-size: var(--gp-text-xs);
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--gp-secondary);
  margin-bottom: var(--gp-space-3);
}
.gp-question__stemrow {
  display: flex;
  align-items: flex-start;
  gap: var(--gp-space-3);
}
.gp-question__stem {
  flex: 1 1 auto;
  font-size: var(--gp-text-xl);
  font-weight: 700;
  line-height: var(--gp-leading-snug);
  letter-spacing: -0.012em;
  text-wrap: pretty;
}
.gp-question__figure:not(:empty) {
  margin-top: var(--gp-space-6);
  padding: var(--gp-space-4);
  background: var(--gp-surface-2);
  border-radius: var(--gp-radius-lg);
  overflow-x: auto;          /* wide figures scroll, the page never does */
}
.gp-question__figure .gp-fig { margin-inline: auto; max-height: 42vh; }

/* --- Answer choices -------------------------------------------------- */

.gp-choices {
  display: grid;
  gap: var(--gp-space-4);
  grid-template-columns: 1fr;
}
@media (min-width: 700px) {
  .gp-choices--2col { grid-template-columns: repeat(2, 1fr); }
  .gp-choices--3col { grid-template-columns: repeat(3, 1fr); }
}
/* Text-only choices read better in one column even on a wide iPad. */
.gp-choices--text { grid-template-columns: 1fr; max-width: 640px; }

.gp-choice {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--gp-space-4);
  width: 100%;
  min-height: 88px;
  padding: var(--gp-space-4) var(--gp-space-5);
  border-radius: var(--gp-radius-lg);
  border: 2px solid var(--gp-line-strong);
  background: var(--gp-surface);
  color: var(--gp-ink);
  font-size: var(--gp-text-md);
  font-weight: 600;
  text-align: left;
  cursor: pointer;
  box-shadow: var(--gp-shadow-1);
  transition: transform var(--gp-dur-fast) var(--gp-ease),
              border-color var(--gp-dur-fast) var(--gp-ease),
              background-color var(--gp-dur-fast) var(--gp-ease),
              box-shadow var(--gp-dur-mid) var(--gp-ease);
}
.gp-choice:hover:not(.is-disabled) {
  border-color: var(--gp-accent);
  box-shadow: var(--gp-shadow-2);
}
.gp-choice:active:not(.is-disabled) { transform: scale(0.98); }

.gp-choice__badge {
  display: grid;
  place-items: center;
  width: 40px; height: 40px;
  flex: none;
  border-radius: 50%;
  background: var(--gp-surface-2);
  border: 2px solid var(--gp-line-strong);
  font-weight: 800;
  font-size: var(--gp-text-base);
  color: var(--gp-ink-soft);
  transition: all var(--gp-dur-fast) var(--gp-ease);
}
.gp-choice__body { flex: 1 1 auto; min-width: 0; }
.gp-choice__body .gp-fig { max-height: 132px; margin-inline: auto; }

/* The state mark. Never colour alone: shape + label + border weight too. */
.gp-choice__mark {
  display: none;
  place-items: center;
  width: 34px; height: 34px;
  flex: none;
  border-radius: 50%;
  color: #fff;
}
.gp-choice__mark svg { width: 21px; height: 21px; }
.gp-choice.is-correct .gp-choice__mark,
.gp-choice.is-incorrect .gp-choice__mark,
.gp-choice.is-revealed .gp-choice__mark { display: grid; }

.gp-choice.is-selected {
  border-color: var(--gp-accent);
  background: var(--gp-accent-soft);
}
.gp-choice.is-selected .gp-choice__badge {
  background: var(--gp-accent);
  border-color: var(--gp-accent);
  color: var(--gp-on-accent);
}

.gp-choice.is-correct {
  border-color: var(--gp-good);
  border-width: 3px;
  background: var(--gp-good-soft);
}
.gp-choice.is-correct .gp-choice__badge {
  background: var(--gp-good); border-color: var(--gp-good); color: #fff;
}
.gp-choice.is-correct .gp-choice__mark { background: var(--gp-good); }

/* Not-red on purpose. A wrong answer gets a dashed amber edge, not a siren. */
.gp-choice.is-incorrect {
  border-color: var(--gp-retry);
  border-width: 3px;
  border-style: dashed;
  background: var(--gp-retry-soft);
}
.gp-choice.is-incorrect .gp-choice__badge {
  background: var(--gp-retry); border-color: var(--gp-retry); color: #fff;
}
.gp-choice.is-incorrect .gp-choice__mark { background: var(--gp-retry); }

/* The right answer, shown after a wrong pick: outlined, not filled. */
.gp-choice.is-revealed {
  border-color: var(--gp-good);
  border-width: 3px;
  background: var(--gp-surface);
  box-shadow: 0 0 0 4px var(--gp-good-soft);
}
.gp-choice.is-revealed .gp-choice__badge {
  border-color: var(--gp-good); color: var(--gp-good);
}
.gp-choice.is-revealed .gp-choice__mark { background: var(--gp-good); }

.gp-choice.is-disabled { cursor: default; }
.gp-choice.is-disabled:not(.is-correct):not(.is-incorrect):not(.is-revealed) {
  opacity: 0.5;
}

/* --- Feedback panel --------------------------------------------------- */

.gp-feedback {
  border-radius: var(--gp-radius-xl);
  padding: var(--gp-space-6);
  border: 2px solid var(--gp-line);
  background: var(--gp-surface-2);
  animation: gp-rise var(--gp-dur-mid) var(--gp-ease);
}
@keyframes gp-rise {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}
.gp-feedback.is-positive {
  background: var(--gp-good-soft);
  border-color: var(--gp-good-line);
}
.gp-feedback.is-retry {
  background: var(--gp-retry-soft);
  border-color: var(--gp-retry-line);
}
.gp-feedback__head {
  display: flex;
  align-items: center;
  gap: var(--gp-space-3);
  margin-bottom: var(--gp-space-3);
}
.gp-feedback__icon {
  display: grid;
  place-items: center;
  width: 40px; height: 40px;
  flex: none;
  border-radius: 50%;
  color: #fff;
}
.gp-feedback__icon svg { width: 24px; height: 24px; }
.gp-feedback.is-positive .gp-feedback__icon { background: var(--gp-good); }
.gp-feedback.is-retry    .gp-feedback__icon { background: var(--gp-retry); }

.gp-feedback__title {
  font-size: var(--gp-text-lg);
  font-weight: 800;
  letter-spacing: -0.01em;
}
.gp-feedback.is-positive .gp-feedback__title { color: var(--gp-good); }
.gp-feedback.is-retry    .gp-feedback__title { color: var(--gp-retry); }

.gp-feedback__body {
  font-family: var(--gp-font-read);
  font-size: var(--gp-text-base);
  color: var(--gp-ink);
  max-width: 62ch;
}
.gp-feedback__strategy {
  margin-top: var(--gp-space-4);
  padding: var(--gp-space-3) var(--gp-space-4);
  border-left: 4px solid var(--gp-secondary);
  border-radius: 0 var(--gp-radius-sm) var(--gp-radius-sm) 0;
  background: color-mix(in srgb, var(--gp-surface) 70%, transparent);
  font-size: var(--gp-text-sm);
  color: var(--gp-ink-soft);
  max-width: 62ch;
}
.gp-feedback__actions {
  margin-top: var(--gp-space-5);
  display: flex;
  gap: var(--gp-space-3);
  flex-wrap: wrap;
}


/* ==========================================================================
   11. Results
   ========================================================================== */

.gp-results__top { display: flex; justify-content: center; }

.gp-ring {
  position: relative;
  width: 190px; height: 190px;
  display: grid;
  place-items: center;
}
.gp-ring__track { position: absolute; inset: 0; }
.gp-ring__track svg { width: 100%; height: 100%; }
.gp-ring__value {
  font-size: var(--gp-text-3xl);
  font-weight: 800;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.gp-ring__label {
  font-size: var(--gp-text-sm);
  color: var(--gp-ink-muted);
  font-weight: 700;
  margin-top: var(--gp-space-1);
}

.gp-bars { display: flex; flex-direction: column; gap: var(--gp-space-4); }
.gp-bar { display: grid; gap: var(--gp-space-1); }
.gp-bar__label {
  display: flex;
  justify-content: space-between;
  gap: var(--gp-space-3);
  font-size: var(--gp-text-sm);
  font-weight: 700;
}
.gp-bar__value { color: var(--gp-ink-muted); font-variant-numeric: tabular-nums; }
.gp-bar__track {
  height: 14px;
  border-radius: var(--gp-radius-pill);
  background: var(--gp-surface-3);
  overflow: hidden;
}
.gp-bar__fill {
  height: 100%;
  border-radius: inherit;
  background: var(--gp-secondary);
  transition: width var(--gp-dur-slow) var(--gp-ease);
}
.gp-bar__fill[data-tone="good"] { background: var(--gp-good); }
.gp-bar__fill[data-tone="mid"]  { background: var(--gp-secondary); }
.gp-bar__fill[data-tone="low"]  { background: var(--gp-retry); }


/* ==========================================================================
   12. Parent guide
   ========================================================================== */

.gp-prose {
  font-family: var(--gp-font-read);
  max-width: var(--gp-measure);
  color: var(--gp-ink);
  font-size: var(--gp-text-base);
}
.gp-prose > * + * { margin-top: var(--gp-space-4); }

.gp-prose h2 {
  font-family: var(--gp-font-ui);
  font-size: var(--gp-text-xl);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: var(--gp-leading-tight);
  margin-top: var(--gp-space-12);
  padding-top: var(--gp-space-5);
  border-top: 2px solid var(--gp-line);
  text-wrap: balance;
}
.gp-prose h2:first-child { margin-top: 0; border-top: 0; padding-top: 0; }

.gp-prose h3 {
  font-family: var(--gp-font-ui);
  font-size: var(--gp-text-lg);
  font-weight: 800;
  letter-spacing: -0.01em;
  margin-top: var(--gp-space-8);
}
.gp-prose h4 {
  font-family: var(--gp-font-ui);
  font-size: var(--gp-text-md);
  font-weight: 700;
  margin-top: var(--gp-space-6);
}

.gp-prose p { max-width: var(--gp-measure); }
.gp-prose strong { font-weight: 700; }
.gp-prose em { font-style: italic; }

.gp-prose ul, .gp-prose ol {
  padding-left: var(--gp-space-6);
  display: flex;
  flex-direction: column;
  gap: var(--gp-space-2);
}
.gp-prose ul { list-style: disc; }
.gp-prose ol { list-style: decimal; }
.gp-prose li::marker { color: var(--gp-accent); }

.gp-prose a { color: var(--gp-secondary); text-underline-offset: 3px; }

.gp-prose blockquote {
  margin-inline: 0;
  padding: var(--gp-space-4) var(--gp-space-5);
  border-left: 4px solid var(--gp-accent-line);
  background: var(--gp-surface-2);
  border-radius: 0 var(--gp-radius-md) var(--gp-radius-md) 0;
  color: var(--gp-ink-soft);
  font-style: italic;
}

.gp-prose code {
  font-family: var(--gp-font-mono);
  font-size: 0.9em;
  background: var(--gp-surface-2);
  padding: 1px 6px;
  border-radius: 6px;
}

.gp-prose table {
  font-size: var(--gp-text-sm);
  border: 1px solid var(--gp-line);
  border-radius: var(--gp-radius-md);
  overflow: hidden;
}
.gp-prose thead { background: var(--gp-surface-2); }
.gp-prose th, .gp-prose td {
  padding: var(--gp-space-3) var(--gp-space-4);
  text-align: left;
  border-bottom: 1px solid var(--gp-line);
  vertical-align: top;
}
.gp-prose th { font-weight: 800; }
.gp-prose tbody tr:last-child td { border-bottom: 0; }

/* Tables scroll inside their own box; the page body never scrolls sideways. */
.gp-prose .gp-table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }

.gp-callout {
  padding: var(--gp-space-5);
  border-radius: var(--gp-radius-lg);
  border: 1px solid var(--gp-line);
  border-left: 5px solid var(--gp-ink-muted);
  background: var(--gp-surface-2);
}
.gp-callout__title {
  font-family: var(--gp-font-ui);
  font-weight: 800;
  font-size: var(--gp-text-base);
  margin-bottom: var(--gp-space-2);
  display: flex;
  align-items: center;
  gap: var(--gp-space-2);
}
.gp-callout > * + * { margin-top: var(--gp-space-3); }
.gp-callout--tip {
  border-left-color: var(--gp-good);
  background: var(--gp-good-soft);
  border-color: var(--gp-good-line);
}
.gp-callout--tip .gp-callout__title { color: var(--gp-good); }
.gp-callout--info {
  border-left-color: var(--gp-secondary);
  background: var(--gp-secondary-soft);
  border-color: var(--gp-secondary-line);
}
.gp-callout--info .gp-callout__title { color: var(--gp-secondary); }
.gp-callout--caution {
  border-left-color: var(--gp-retry);
  background: var(--gp-retry-soft);
  border-color: var(--gp-retry-line);
}
.gp-callout--caution .gp-callout__title { color: var(--gp-retry); }

.gp-timeline {
  display: flex;
  flex-direction: column;
  gap: var(--gp-space-4);
  border-left: 3px solid var(--gp-line);
  padding-left: var(--gp-space-6);
  margin-left: var(--gp-space-6);
}
@media (max-width: 560px) {
  /* The day badge hangs into the gutter, so on a phone drop it inline above
     the card rather than letting it clip off the screen edge. */
  .gp-timeline { border-left: 0; padding-left: 0; margin-left: 0; }
  .gp-timeline__day { position: static; margin-bottom: var(--gp-space-2); box-shadow: none; }
  .gp-timeline__body { margin-left: 0; }
}
.gp-timeline__item { position: relative; }
.gp-timeline__day {
  position: absolute;
  left: calc(-1 * var(--gp-space-6) - 22px);
  top: 2px;
  display: grid;
  place-items: center;
  width: 42px; height: 42px;
  border-radius: 50%;
  background: var(--gp-accent);
  color: var(--gp-on-accent);
  font-family: var(--gp-font-ui);
  font-weight: 800;
  font-size: var(--gp-text-sm);
  box-shadow: 0 0 0 5px var(--gp-bg);
}
.gp-timeline__body {
  background: var(--gp-surface);
  border: 1px solid var(--gp-line);
  border-radius: var(--gp-radius-lg);
  padding: var(--gp-space-5);
  margin-left: var(--gp-space-4);
}
.gp-timeline__body > * + * { margin-top: var(--gp-space-3); }
.gp-timeline__body h3 { margin-top: 0; }

.gp-accordion {
  border: 1px solid var(--gp-line);
  border-radius: var(--gp-radius-lg);
  background: var(--gp-surface);
  overflow: hidden;
}
.gp-accordion + .gp-accordion { margin-top: var(--gp-space-3); }
.gp-accordion__trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gp-space-4);
  width: 100%;
  min-height: 60px;
  padding: var(--gp-space-4) var(--gp-space-5);
  font-family: var(--gp-font-ui);
  font-weight: 700;
  font-size: var(--gp-text-base);
  text-align: left;
  cursor: pointer;
  list-style: none;
}
.gp-accordion__trigger::-webkit-details-marker { display: none; }
.gp-accordion__trigger::after {
  content: "";
  width: 11px; height: 11px;
  flex: none;
  border-right: 2.5px solid var(--gp-ink-muted);
  border-bottom: 2.5px solid var(--gp-ink-muted);
  transform: rotate(45deg) translate(-3px, -3px);
  transition: transform var(--gp-dur-mid) var(--gp-ease);
}
.gp-accordion[open] .gp-accordion__trigger::after {
  transform: rotate(-135deg) translate(-3px, -3px);
}
.gp-accordion__trigger:hover { background: var(--gp-surface-2); }
.gp-accordion__panel {
  padding: 0 var(--gp-space-5) var(--gp-space-5);
  border-top: 1px solid var(--gp-line);
  padding-top: var(--gp-space-4);
}
.gp-accordion__panel > * + * { margin-top: var(--gp-space-3); }


/* ==========================================================================
   13. Figures
   ========================================================================== */

.gp-fig {
  display: block;
  max-width: 100%;
  height: auto;
}


/* ==========================================================================
   14. Motion and print
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  .gp-btn:active, .gp-choice:active, .gp-pill:active,
  .gp-card--action:hover, .gp-card--test:hover, .gp-card--category:hover {
    transform: none !important;
  }
}

@media print {
  .gp-topbar, .gp-footer, .gp-skip,
  .gp-btn, .gp-accordion__trigger::after { display: none !important; }

  body { background: #fff; color: #000; }
  .gp-screen { display: block !important; }
  .gp-prose { max-width: none; font-size: 11pt; }
  .gp-prose h2, .gp-prose h3 { break-after: avoid; }
  .gp-callout, .gp-timeline__body, .gp-card {
    border: 1px solid #999; box-shadow: none; break-inside: avoid;
  }
  .gp-accordion__panel { display: block !important; }
  .gp-prose a::after { content: " (" attr(href) ")"; font-size: 9pt; color: #555; }
}

/* ==================================================================== */
/* Math Lab                                                             */
/* ==================================================================== */

.gp-crumb { margin-bottom: var(--gp-space-2); font-size: var(--gp-text-sm); }
.gp-crumb a { color: var(--gp-ink-soft); text-decoration: none; font-weight: 600; }
.gp-crumb a:hover { color: var(--gp-ink); text-decoration: underline; }

.gp-grid--topics {
  display: grid;
  gap: var(--gp-space-4);
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  margin-top: var(--gp-space-6);
}

/* A topic card leads with its number and picture so a child who cannot yet
   read the title still knows which one they were on. */
.gp-card--topic {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--gp-space-1);
  padding: var(--gp-space-5);
  text-decoration: none;
  min-height: 190px;
}
.gp-topic__num {
  position: absolute;
  top: var(--gp-space-3);
  right: var(--gp-space-4);
  font-size: var(--gp-text-lg);
  font-weight: 800;
  color: var(--gp-line-strong);
}
.gp-topic__emoji { font-size: 2.2rem; line-height: 1; margin-bottom: var(--gp-space-1); }
.gp-topic__count { margin-top: auto; font-size: var(--gp-text-sm); color: var(--gp-ink-soft); }
.gp-topic__bar {
  display: block;
  height: 7px;
  border-radius: 99px;
  background: var(--gp-surface-2);
  overflow: hidden;
  margin-top: var(--gp-space-3);
}
.gp-topic__bar > span { display: block; height: 100%; background: var(--gp-accent); }

.gp-card--action.is-disabled { opacity: 0.45; cursor: not-allowed; }

/* ---- the lesson ---- */

.gp-teach {
  margin: var(--gp-space-6) 0 var(--gp-space-8);
  padding: var(--gp-space-6);
  border: 2px solid var(--gp-line);
  border-radius: var(--gp-radius-lg);
  background: var(--gp-surface);
}
.gp-teach__say {
  font-size: var(--gp-text-lg);
  font-weight: 600;
  line-height: var(--gp-leading-snug);
  margin: 0 0 var(--gp-space-4);
}
.gp-teach__show { margin: 0 0 var(--gp-space-5); text-align: center; }
.gp-teach__fig { max-width: 380px; margin: 0 auto var(--gp-space-2); }
.gp-teach__show figcaption {
  font-size: var(--gp-text-sm);
  color: var(--gp-ink-soft);
}
.gp-teach__tip {
  display: flex;
  gap: var(--gp-space-3);
  align-items: flex-start;
  padding: var(--gp-space-4);
  border-radius: var(--gp-radius-md);
  background: var(--gp-surface-2);
  border-left: 5px solid var(--gp-accent);
}
.gp-teach__tip p { margin: 0; font-weight: 600; }

.gp-turn {
  font-size: var(--gp-text-xl);
  font-weight: 800;
  margin: 0 0 var(--gp-space-4);
}

/* ---- one exercise ---- */

.gp-exwrap {
  padding: var(--gp-space-6);
  border: 2px solid var(--gp-line);
  border-radius: var(--gp-radius-lg);
  background: var(--gp-surface);
}
.gp-ex__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gp-space-3);
  margin-bottom: var(--gp-space-3);
}
.gp-ex__badge {
  display: inline-flex;
  align-items: center;
  gap: var(--gp-space-2);
  padding: var(--gp-space-1) var(--gp-space-3);
  border-radius: var(--gp-radius-pill);
  background: var(--gp-surface-2);
  font-size: var(--gp-text-sm);
  font-weight: 700;
}
.gp-ex__count { font-size: var(--gp-text-sm); color: var(--gp-ink-soft); }
.gp-ex__ask {
  font-size: var(--gp-text-xl);
  font-weight: 700;
  line-height: var(--gp-leading-snug);
  margin: 0 0 var(--gp-space-4);
}
.gp-ex__fig { max-width: 340px; margin: 0 auto var(--gp-space-5); }

.gp-ex__choices {
  display: grid;
  gap: var(--gp-space-3);
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
}
.gp-ex__choices--tf { grid-template-columns: repeat(2, 1fr); max-width: 420px; }

.gp-mchoice {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--gp-space-2);
  min-height: 96px;
  padding: var(--gp-space-3);
  border: 3px solid var(--gp-line-strong);
  border-radius: var(--gp-radius-lg);
  background: var(--gp-surface);
  color: var(--gp-ink);
  font-size: var(--gp-text-lg);
  font-weight: 700;
  cursor: pointer;
  transition: border-color var(--gp-dur-fast) var(--gp-ease),
              transform var(--gp-dur-fast) var(--gp-ease);
}
.gp-mchoice:hover:not(:disabled) { border-color: var(--gp-accent-line); }
.gp-mchoice:active:not(:disabled) { transform: scale(0.97); }
.gp-mchoice:disabled { cursor: default; }
.gp-mchoice__label { font-size: var(--gp-text-2xl); font-weight: 800; }
.gp-mchoice svg { max-width: 130px; }
/* Right and wrong are never signalled by colour alone. */
.gp-mchoice.is-right { border-color: var(--gp-good); background: var(--gp-good-soft); }
.gp-mchoice.is-right::after { content: " ✓"; font-weight: 800; }
.gp-mchoice.is-wrong { border-color: var(--gp-retry); background: var(--gp-retry-soft); }
.gp-mchoice.is-wrong::after { content: " ✕"; font-weight: 800; }

.gp-numrow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--gp-space-3);
}
.gp-numrow__label { font-weight: 700; }
.gp-numrow__input {
  flex: 1 1 120px;
  min-width: 110px;
  min-height: 60px;
  padding: var(--gp-space-3) var(--gp-space-4);
  border: 3px solid var(--gp-line-strong);
  border-radius: var(--gp-radius-md);
  background: var(--gp-surface);
  color: var(--gp-ink);
  font-size: var(--gp-text-2xl);
  font-weight: 800;
  text-align: center;
}
.gp-numrow__input:focus-visible { outline: 3px solid var(--gp-accent); outline-offset: 2px; }

.gp-paper {
  padding: var(--gp-space-4);
  border-radius: var(--gp-radius-md);
  background: var(--gp-surface-2);
  border-left: 5px solid var(--gp-accent);
  margin-bottom: var(--gp-space-4);
}
.gp-paper__cue { margin: 0; font-weight: 700; }
.gp-paper__hint { margin: var(--gp-space-2) 0 0; color: var(--gp-ink-soft); }

/* ---- build it ---- */

.gp-bframe {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 4px;
  max-width: 340px;
  padding: 6px;
  border: 3px solid var(--gp-ink);
  border-radius: 8px;
  background: var(--gp-fig-canvas, #fdfbf7);
}
.gp-barray {
  display: grid;
  gap: 8px;
  max-width: 340px;
}
.gp-bcell {
  aspect-ratio: 1;
  border: 2px solid var(--gp-line-strong);
  border-radius: 6px;
  background: transparent;
  cursor: pointer;
  min-height: 44px;
}
.gp-barray .gp-bcell { border-radius: 50%; }
.gp-bcell.is-on { background: var(--gp-accent); border-color: var(--gp-ink); }
.gp-bcell.is-on::after { content: "●"; color: var(--gp-on-accent); font-size: 0; }
.gp-build { margin-bottom: var(--gp-space-3); }
.gp-build__now { margin: 0 0 var(--gp-space-4); font-weight: 700; }

/* ---- collect ---- */

.gp-collect { list-style: none; margin: var(--gp-space-4) 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: var(--gp-space-2); }
.gp-collect__item {
  padding: var(--gp-space-2) var(--gp-space-3);
  border-radius: var(--gp-radius-pill);
  font-weight: 700;
  font-size: var(--gp-text-sm);
  border: 2px solid var(--gp-line-strong);
}
.gp-collect__item.is-right { border-color: var(--gp-good); background: var(--gp-good-soft); }
.gp-collect__item.is-right::before { content: "✓ "; }
.gp-collect__item.is-wrong { border-color: var(--gp-retry); background: var(--gp-retry-soft); }
.gp-collect__item.is-wrong::before { content: "✕ "; }
.gp-collect__item.is-repeat { color: var(--gp-ink-soft); }
.gp-collect__item.is-repeat::before { content: "↺ "; }
.gp-collect__score { margin-top: var(--gp-space-3); font-weight: 700; }

/* ---- feedback ---- */

.gp-fb {
  margin-top: var(--gp-space-5);
  padding: var(--gp-space-4) var(--gp-space-5);
  border-radius: var(--gp-radius-md);
  border-left: 6px solid var(--gp-line-strong);
  background: var(--gp-surface-2);
}
.gp-fb.is-right { border-left-color: var(--gp-good); }
.gp-fb.is-wrong { border-left-color: var(--gp-retry); }
.gp-fb__title { margin: 0 0 var(--gp-space-2); font-weight: 800; font-size: var(--gp-text-lg); }
.gp-fb__why { margin: 0; color: var(--gp-ink-soft); }

/* ---- moving between exercises ---- */

.gp-exnav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gp-space-4);
  margin-top: var(--gp-space-5);
}
.gp-dots { display: flex; gap: 6px; flex-wrap: wrap; justify-content: center; flex: 1; }
.gp-dot {
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--gp-line-strong); opacity: 0.4;
}
.gp-dot.is-done { opacity: 1; background: var(--gp-good); }
.gp-dot.is-now { opacity: 1; background: var(--gp-accent); transform: scale(1.4); }

.gp-done { text-align: center; padding: var(--gp-space-6) 0; }
.gp-done__mark { font-size: 3rem; margin: 0 0 var(--gp-space-2); }
.gp-done h3 { font-size: var(--gp-text-xl); margin: 0 0 var(--gp-space-2); }
.gp-done p { color: var(--gp-ink-soft); margin: 0 0 var(--gp-space-5); }

@media (max-width: 560px) {
  .gp-ex__choices { grid-template-columns: repeat(2, 1fr); }
  .gp-exwrap, .gp-teach { padding: var(--gp-space-4); }
}

/* The lesson folds away once it has been read. */
.gp-teachwrap { margin: var(--gp-space-5) 0 var(--gp-space-8); }
.gp-teach__toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--gp-space-2);
  padding: var(--gp-space-3) var(--gp-space-5);
  border: 2px solid var(--gp-line-strong);
  border-radius: var(--gp-radius-pill);
  background: var(--gp-surface);
  font-weight: 700;
  cursor: pointer;
  min-height: 48px;
  list-style: none;
}
.gp-teach__toggle::-webkit-details-marker { display: none; }
.gp-teach__toggle::after { content: " ▾"; }
.gp-teachwrap[open] .gp-teach__toggle::after { content: " ▴"; }
.gp-teachwrap .gp-teach { margin: var(--gp-space-4) 0 0; }

/* The lesson's own "done reading" button, and a label that says what the
   toggle will do rather than just naming the section. */
.gp-teach__go { margin-top: var(--gp-space-2); }
.gp-teachwrap[open] .gp-teach__toggle-shut,
.gp-teachwrap:not([open]) .gp-teach__toggle-open { display: none; }

/* ---- colour the map ---- */

.gp-cm__rule { margin: 0 0 var(--gp-space-4); color: var(--gp-ink-soft); }
.gp-cm { display: flex; justify-content: center; margin-bottom: var(--gp-space-4); }
.gp-cm__grid {
  display: grid;
  background: var(--gp-fig-canvas, #fdfbf7);
  border: 3px solid var(--gp-ink);
  border-radius: 10px;
  overflow: hidden;
}
/* Each square is one piece of a country. Borders are drawn only on the sides
   where the country actually changes, so the countries read as whole shapes. */
.gp-cm__cell {
  aspect-ratio: 1;
  border: 0;
  background: transparent;
  cursor: pointer;
  padding: 0;
  box-shadow: none;
}
.gp-cm__cell[data-edge*="u"] { border-top: 3px solid var(--gp-fig-stroke, #2f3542); }
.gp-cm__cell[data-edge*="r"] { border-right: 3px solid var(--gp-fig-stroke, #2f3542); }
.gp-cm__cell[data-edge*="d"] { border-bottom: 3px solid var(--gp-fig-stroke, #2f3542); }
.gp-cm__cell[data-edge*="l"] { border-left: 3px solid var(--gp-fig-stroke, #2f3542); }
.gp-cm__cell[data-paint="red"]    { background: var(--gp-fig-red, #d9614f); }
.gp-cm__cell[data-paint="blue"]   { background: var(--gp-fig-blue, #3b82c4); }
.gp-cm__cell[data-paint="green"]  { background: var(--gp-fig-green, #4f9d69); }
.gp-cm__cell[data-paint="yellow"] { background: var(--gp-fig-yellow, #e0a83c); }
.gp-cm__cell:focus-visible { outline: 3px solid var(--gp-focus); outline-offset: -3px; }
.gp-cm__score { margin: 0 0 var(--gp-space-4); font-weight: 700; }

/* Two tracks of topics on the grade page. */
.gp-track { margin-top: var(--gp-space-8); }
.gp-track__head { font-size: var(--gp-text-xl); font-weight: 800; margin: 0 0 var(--gp-space-1); }
.gp-track__sub { color: var(--gp-ink-soft); margin: 0 0 var(--gp-space-4); }

/* ---- Tower of Hanoi ---- */

.gp-hanoi {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--gp-space-3);
  margin-bottom: var(--gp-space-4);
}
/* A whole tower is one big target. A six-year-old should not have to hit a
   disc, only the pile it belongs to. */
.gp-peg {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: center;
  min-height: 190px;
  padding: var(--gp-space-2) var(--gp-space-1) 0;
  border: 3px solid var(--gp-line-strong);
  border-radius: var(--gp-radius-md);
  background: var(--gp-fig-canvas, #fdfbf7);
  cursor: pointer;
}
.gp-peg.is-picked { border-color: var(--gp-accent); box-shadow: 0 0 0 4px var(--gp-accent-line); }
.gp-peg__post {
  position: absolute;
  bottom: 16px;
  width: 9px;
  height: 150px;
  border-radius: 5px;
  background: var(--gp-fig-grey, #8b93a1);
}
.gp-peg__base {
  position: absolute;
  bottom: 8px;
  left: 8px; right: 8px;
  height: 10px;
  border-radius: 5px;
  background: var(--gp-fig-ink, #2f3542);
}
.gp-peg__discs {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  width: 100%;
  margin-bottom: 20px;
}
.gp-disc {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 26px;
  border-radius: 6px;
  border: 2.5px solid var(--gp-fig-ink, #2f3542);
  color: var(--gp-fig-ink, #2f3542);
  font-weight: 800;
  font-size: var(--gp-text-sm);
}
.gp-disc[data-tone="blue"]   { background: var(--gp-fig-blue, #3b82c4); }
.gp-disc[data-tone="green"]  { background: var(--gp-fig-green, #4f9d69); }
.gp-disc[data-tone="yellow"] { background: var(--gp-fig-yellow, #e0a83c); }
.gp-disc[data-tone="orange"] { background: var(--gp-fig-orange, #dd8341); }
.gp-disc[data-tone="red"]    { background: var(--gp-fig-red, #d9614f); }
.gp-disc[data-tone="teal"]   { background: var(--gp-fig-teal, #3f9aa6); }
.gp-hanoi__count { margin: 0 0 var(--gp-space-2); font-weight: 700; }
.gp-hanoi__say { margin: 0; min-height: 1.5em; color: var(--gp-ink-soft); font-weight: 600; }

/* Doubling chips: tap to switch a number on or off. Named gp-dchip because
   gp-chip already belongs to the score and streak chips in the top bar. */
.gp-dchips { display: flex; flex-wrap: wrap; gap: var(--gp-space-3); }
.gp-dchip {
  min-width: 68px;
  min-height: 68px;
  padding: var(--gp-space-3);
  border: 3px solid var(--gp-line-strong);
  border-radius: var(--gp-radius-md);
  background: var(--gp-surface);
  color: var(--gp-ink);
  font-size: var(--gp-text-xl);
  font-weight: 800;
  cursor: pointer;
}
.gp-dchip.is-on { background: var(--gp-accent); border-color: var(--gp-ink); color: var(--gp-on-accent); }
.gp-dchip.is-on::after { content: " ✓"; font-size: var(--gp-text-sm); }

/* ---- prime sieve ---- */

.gp-sieve {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(48px, 1fr));
  gap: 6px;
  max-width: 520px;
  margin-bottom: var(--gp-space-4);
}
.gp-scell {
  aspect-ratio: 1;
  min-height: 48px;
  border: 2.5px solid var(--gp-line-strong);
  border-radius: 8px;
  background: var(--gp-surface);
  color: var(--gp-ink);
  font-weight: 800;
  font-size: var(--gp-text-base);
  cursor: pointer;
}
/* Crossed out is shown by a line as well as a fade, never by colour alone. */
.gp-scell.is-out {
  color: var(--gp-ink-soft);
  text-decoration: line-through;
  background: var(--gp-surface-2);
  border-style: dashed;
  opacity: 0.65;
}

/* ---- magic square ---- */

.gp-magic {
  display: grid;
  grid-template-columns: repeat(3, 72px);
  gap: 6px;
  margin-bottom: var(--gp-space-4);
}
.gp-mcell {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 1;
  width: 72px;
  border: 3px solid var(--gp-line-strong);
  border-radius: 8px;
  background: var(--gp-surface);
  color: var(--gp-ink);
  font-size: var(--gp-text-xl);
  font-weight: 800;
  text-align: center;
}
.gp-mcell.is-given { background: var(--gp-surface-2); color: var(--gp-ink-soft); }
.gp-mcell:focus-visible { outline: 3px solid var(--gp-focus); outline-offset: 2px; }
.gp-magic__pool { margin: 0 0 var(--gp-space-4); font-weight: 700; }

/* ---- Caesar cipher ---- */

.gp-cipher__coded {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: var(--gp-text-xl);
  font-weight: 700;
  letter-spacing: 0.14em;
  padding: var(--gp-space-4);
  border-radius: var(--gp-radius-md);
  background: var(--gp-surface-2);
  margin: 0 0 var(--gp-space-4);
  overflow-wrap: anywhere;
}
.gp-cipher__dial {
  display: flex;
  align-items: center;
  gap: var(--gp-space-4);
  margin-bottom: var(--gp-space-4);
}
.gp-cipher__n { font-weight: 700; }

/* ---- the subtraction game and the three doors ---- */

.gp-nim__pile { font-size: var(--gp-text-2xl); font-weight: 800; margin: 0 0 var(--gp-space-4); }
.gp-nim__take { display: flex; flex-wrap: wrap; gap: var(--gp-space-3); margin-bottom: var(--gp-space-4); }
.gp-nim__say { margin: 0 0 var(--gp-space-2); font-weight: 700; min-height: 1.5em; }
.gp-nim__score { margin: 0; color: var(--gp-ink-soft); font-weight: 600; }

.gp-doors { display: flex; gap: var(--gp-space-4); margin-bottom: var(--gp-space-4); }
.gp-door {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--gp-space-1);
  padding: var(--gp-space-4);
  font-size: 2.4rem;
  border: 3px solid var(--gp-line-strong);
  border-radius: var(--gp-radius-lg);
  background: var(--gp-surface);
  color: var(--gp-ink);
  cursor: pointer;
}
.gp-door span { font-size: var(--gp-text-base); font-weight: 800; }
.gp-door.is-picked { border-color: var(--gp-accent); box-shadow: 0 0 0 4px var(--gp-accent-line); }
/* An opened door is shown as opened, not merely faded. */
.gp-door.is-open { opacity: 0.5; border-style: dashed; }
.gp-door.is-open::after { content: "empty"; font-size: var(--gp-text-sm); font-weight: 700; }
.gp-doors__choice { display: flex; gap: var(--gp-space-3); margin-bottom: var(--gp-space-4); }

/* ---- function machine ---- */

.gp-machine {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--gp-space-3);
  margin-bottom: var(--gp-space-3);
}
.gp-machine__log {
  list-style: none;
  margin: 0 0 var(--gp-space-4);
  padding: 0;
  max-height: 190px;
  overflow-y: auto;
}
.gp-machine__row {
  padding: var(--gp-space-2) var(--gp-space-3);
  border-bottom: 1px solid var(--gp-line);
  font-weight: 600;
}
.gp-machine__row:first-child { background: var(--gp-surface-2); border-radius: var(--gp-radius-sm, 6px); }

/* ================================================================== */
/* Fun: name the flag                                                 */
/* ================================================================== */

.gp-backlink { margin-bottom: var(--gp-space-4); }
.gp-grid--modes { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--gp-space-4); }
.gp-card--mode {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--gp-space-2);
  cursor: pointer;
  text-align: left;
}
.gp-card--mode.is-selected { border-color: var(--gp-accent); box-shadow: 0 0 0 3px var(--gp-accent-line); }
.gp-pill small { font-weight: 600; opacity: 0.7; margin-left: var(--gp-space-1); }
.gp-btn--big { min-height: 60px; font-size: var(--gp-text-lg); padding-inline: var(--gp-space-8); }

/* The score sits with the back link so both are reachable at any moment. */
.gp-flagbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--gp-space-3);
  margin-bottom: var(--gp-space-5);
}
.gp-flagbar__score { display: flex; gap: var(--gp-space-3); margin: 0; }
.gp-tally {
  display: inline-flex;
  align-items: center;
  gap: var(--gp-space-2);
  padding: var(--gp-space-2) var(--gp-space-4);
  border-radius: var(--gp-radius-pill);
  border: 2px solid var(--gp-line-strong);
  font-weight: 800;
  font-size: var(--gp-text-lg);
}
.gp-tally--right { color: var(--gp-good); border-color: var(--gp-good); }
.gp-tally--wrong { color: var(--gp-retry); border-color: var(--gp-retry); }

.gp-flagq { text-align: center; }
/* A flag is a picture of a real thing, so it gets a plain light mount and a
   border: several flags are mostly white and would vanish otherwise. */
.gp-flagq__img {
  display: flex;
  justify-content: center;
  margin: var(--gp-space-4) 0 var(--gp-space-5);
}
.gp-flagq__img img {
  width: min(320px, 78vw);
  height: auto;
  aspect-ratio: 4 / 3;
  object-fit: contain;
  background: var(--gp-fig-canvas, #fdfbf7);
  border: 3px solid var(--gp-ink);
  border-radius: var(--gp-radius-md);
  padding: var(--gp-space-2);
}
.gp-flagq__ask { font-size: var(--gp-text-lg); font-weight: 800; margin: 0 0 var(--gp-space-4); }
.gp-flagq__choices {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: var(--gp-space-3);
  max-width: 720px;
  margin: 0 auto;
}
.gp-choice--flag { justify-content: center; text-align: center; min-height: 62px; }
.gp-flagq__say { margin: var(--gp-space-5) 0 var(--gp-space-4); font-weight: 800; font-size: var(--gp-text-lg); }
.gp-flagq__say.is-right { color: var(--gp-good); }
.gp-flagq__say.is-wrong { color: var(--gp-retry); }

.gp-flagdone { text-align: center; position: relative; }
.gp-flagdone__head { font-size: var(--gp-text-2xl); font-weight: 800; margin: 0 0 var(--gp-space-2); }
.gp-flagdone__score { font-size: var(--gp-text-lg); margin: 0 0 var(--gp-space-6); }
.gp-flagdone__again {
  display: flex; flex-wrap: wrap; gap: var(--gp-space-3);
  justify-content: center; margin-top: var(--gp-space-6);
}

/* ---- the vault ---- */

.gp-vault {
  margin: var(--gp-space-6) auto;
  padding: var(--gp-space-6);
  max-width: 720px;
  border: 3px solid var(--gp-accent);
  border-radius: var(--gp-radius-lg);
  background: var(--gp-surface-2);
}
.gp-vault__badge {
  display: inline-flex; align-items: center; gap: var(--gp-space-2);
  margin: 0 0 var(--gp-space-2);
  font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase;
  font-size: var(--gp-text-sm); color: var(--gp-accent);
}
.gp-vault__head { font-size: var(--gp-text-xl); margin: 0 0 var(--gp-space-2); }
.gp-vault__told {
  margin-top: var(--gp-space-5);
  padding: var(--gp-space-4);
  border-radius: var(--gp-radius-md);
  border-left: 5px solid var(--gp-line-strong);
  background: var(--gp-surface);
  text-align: left;
}
.gp-vault__told.is-right { border-left-color: var(--gp-good); }
.gp-vault__told.is-wrong { border-left-color: var(--gp-retry); }
.gp-vault__name { font-weight: 800; margin: 0 0 var(--gp-space-2); }
.gp-vault__story { margin: 0; color: var(--gp-ink-soft); }

/* ---- the celebration ---- */

.gp-confetti { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
.gp-confetti span {
  position: absolute;
  top: -14px;
  left: calc(var(--i) * 7.1%);
  width: 11px; height: 15px;
  border-radius: 2px;
  background: var(--gp-accent);
  animation: gp-fall 2.6s linear infinite;
  animation-delay: calc(var(--i) * 0.13s);
}
.gp-confetti span:nth-child(3n)   { background: var(--gp-good); }
.gp-confetti span:nth-child(3n+1) { background: var(--gp-fig-blue, #3b82c4); }
@keyframes gp-fall {
  0%   { transform: translateY(0) rotate(0deg); opacity: 1; }
  100% { transform: translateY(340px) rotate(520deg); opacity: 0; }
}
/* Anyone who asked for less movement gets a still badge instead. */
@media (prefers-reduced-motion: reduce) {
  .gp-confetti span { animation: none; opacity: 0; }
}

/* Said out loud when part of the question bank did not load, so a short round
   is never passed off as a full one. */
.gp-warnbox {
  margin-bottom: var(--gp-space-4);
  padding: var(--gp-space-4);
  border-radius: var(--gp-radius-md);
  border-left: 5px solid var(--gp-retry);
  background: var(--gp-retry-soft, var(--gp-surface-2));
}
.gp-warnbox p { margin: 0; }

/* ---- country outlines ---- */

/* The outlines are injected inline, not used as <img>, so currentColor works
   and one rule can colour every shape correctly in both themes. */
.gp-shapebox {
  display: flex;
  justify-content: center;
  margin: var(--gp-space-4) 0 var(--gp-space-5);
  color: var(--gp-fig-blue, #3b82c4);
}
.gp-shapefig {
  width: min(300px, 72vw);
  height: auto;
  max-height: 46vh;
}
.gp-typerow { max-width: 560px; margin: 0 auto var(--gp-space-2); }
.gp-typehint { text-align: center; margin: 0 0 var(--gp-space-2); font-size: var(--gp-text-sm); }

/* ====================================================================
   Tiles — a room on the map, or a game inside one
   ====================================================================
   A tile is the main thing a child touches, so it is built to be aimed at
   rather than read: big art, a short name, and a whole card that is the tap
   target. The home page uses them for rooms and the games hub for games. Minimum height is well past the 44px
   guideline because the hand doing the tapping is six years old.

   Colour comes from the palette tokens, which already carry a light and a
   dark value, so none of this needs a dark-theme override.
   ==================================================================== */

.cz-tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--gp-space-5);
}

.cz-tile {
  --room: var(--gp-accent);
  --room-soft: var(--gp-accent-soft);
  --room-line: var(--gp-accent-line);
  --room-ink: var(--gp-accent-strong);

  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: var(--gp-space-4);
  min-height: 128px;
  padding: var(--gp-space-5);
  border: 2px solid var(--room-line);
  border-radius: var(--gp-radius-xl);
  background: var(--room-soft);
  text-decoration: none;
  color: var(--gp-ink);
  transition: transform var(--gp-dur-fast) var(--gp-ease),
              box-shadow var(--gp-dur-fast) var(--gp-ease);
}

.cz-tile:hover,
.cz-tile:focus-visible {
  transform: translateY(-3px);
  box-shadow: var(--gp-shadow-2);
}
.cz-tile:active { transform: translateY(0) scale(0.99); }

.cz-tile__pic {
  display: grid;
  place-items: center;
  width: 76px; height: 76px;
  border-radius: var(--gp-radius-lg);
  background: var(--gp-surface);
  border: 2px solid var(--room-line);
  flex: none;
}
.cz-creature { width: 56px; height: 56px; display: block; }

.cz-tile__text { display: grid; gap: 3px; min-width: 0; }
.cz-tile__name {
  font-size: var(--gp-text-lg);
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--room-ink);
}
.cz-tile__blurb {
  font-size: var(--gp-text-sm);
  line-height: var(--gp-leading-snug);
  color: var(--gp-ink-soft);
}
.cz-tile__meta {
  font-size: var(--gp-text-xs);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--gp-ink-muted);
}
.cz-tile__go {
  font-size: 26px;
  line-height: 1;
  color: var(--room);
  transition: transform var(--gp-dur-fast) var(--gp-ease);
}
.cz-tile:hover .cz-tile__go { transform: translateX(4px); }

/* A room that does not exist yet: visible so the zoo looks like it is growing,
   but plainly not a door you can open. */
.cz-tile.is-soon {
  background: var(--gp-surface-2);
  border-color: var(--gp-line);
  border-style: dashed;
  cursor: default;
}
.cz-tile.is-soon .cz-tile__name { color: var(--gp-ink-muted); }
.cz-tile.is-soon .cz-creature { opacity: 0.45; }

/* One class per palette hue. Adding a section means adding an entry to ROOMS
   and, if it uses a new hue, three lines here. */
.cz-tile--mango    { --room: var(--cz-mango);    --room-soft: var(--cz-mango-soft);    --room-line: var(--cz-mango-line); --room-ink: var(--cz-mango-ink); }
.cz-tile--honey    { --room: var(--cz-honey);    --room-soft: var(--cz-honey-soft);    --room-line: var(--cz-honey-line); --room-ink: var(--cz-honey-ink); }
.cz-tile--leaf     { --room: var(--cz-leaf);     --room-soft: var(--cz-leaf-soft);     --room-line: var(--cz-leaf-line); --room-ink: var(--cz-leaf-ink); }
.cz-tile--jade     { --room: var(--cz-jade);     --room-soft: var(--cz-jade-soft);     --room-line: var(--cz-jade-line); --room-ink: var(--cz-jade-ink); }
.cz-tile--lagoon   { --room: var(--cz-lagoon);   --room-soft: var(--cz-lagoon-soft);   --room-line: var(--cz-lagoon-line); --room-ink: var(--cz-lagoon-ink); }
.cz-tile--sky      { --room: var(--cz-sky);      --room-soft: var(--cz-sky-soft);      --room-line: var(--cz-sky-line); --room-ink: var(--cz-sky-ink); }
.cz-tile--orchid   { --room: var(--cz-orchid);   --room-soft: var(--cz-orchid-soft);   --room-line: var(--cz-orchid-line); --room-ink: var(--cz-orchid-ink); }
.cz-tile--flamingo { --room: var(--cz-flamingo); --room-soft: var(--cz-flamingo-soft); --room-line: var(--cz-flamingo-line); --room-ink: var(--cz-flamingo-ink); }

/* The welcome band. Deep is the one surface the brand orange may not sit on as
   text, so everything here uses the on-deep tokens. */
.cz-welcome {
  background: var(--cz-deep);
  border-radius: var(--gp-radius-xl);
  padding: var(--gp-space-8) var(--gp-space-6);
  display: grid;
  /* Words, then the mascot leaning on the right-hand edge. */
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: var(--gp-space-6);
}
.cz-welcome__text { display: grid; gap: var(--gp-space-3); }
.cz-welcome__eyebrow {
  font-size: var(--gp-text-xs);
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--cz-on-deep-accent);
  margin: 0;
}
.cz-welcome__title {
  font-size: var(--gp-text-3xl);
  line-height: var(--gp-leading-tight);
  font-weight: 800;
  letter-spacing: -0.02em;
  color: var(--cz-on-deep);
  margin: 0;
}
.cz-welcome__lede {
  font-size: var(--gp-text-md);
  line-height: var(--gp-leading-snug);
  color: var(--cz-on-deep-muted);
  margin: 0;
  max-width: 54ch;
}

.cz-sectionhead {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--gp-space-4);
  flex-wrap: wrap;
}
.cz-sectionhead h2 { margin: 0; font-size: var(--gp-text-xl); }
.cz-sectionhead p { margin: 0; color: var(--gp-ink-muted); font-size: var(--gp-text-sm); }

/* The room's own banner, shown at the top of a section page. */
/* No --room defaults here. They would sit later in the file than the hue
   classes at equal specificity and quietly win, which painted the purple Test
   Practice banner in the brand orange. Fallbacks go at the point of use. */
.cz-roomhead {
  display: flex;
  align-items: center;
  gap: var(--gp-space-4);
  padding: var(--gp-space-5);
  border: 2px solid var(--room-line, var(--gp-accent-line));
  border-radius: var(--gp-radius-xl);
  background: var(--room-soft, var(--gp-accent-soft));
}
.cz-roomhead__pic {
  display: grid; place-items: center;
  width: 68px; height: 68px; flex: none;
  border-radius: var(--gp-radius-lg);
  background: var(--gp-surface);
  border: 2px solid var(--room-line, var(--gp-accent-line));
}
/* --room-ink, not --room: this heading sits on the tint, where the plain
   section colour measures below AA. */
.cz-roomhead h1 { margin: 0; font-size: var(--gp-text-2xl);
  color: var(--room-ink, var(--gp-accent-strong)); }
.cz-roomhead p { margin: 3px 0 0; color: var(--gp-ink-soft); font-size: var(--gp-text-sm); }

@media (max-width: 560px) {
  .cz-tile { min-height: 112px; padding: var(--gp-space-4); gap: var(--gp-space-3); }
  .cz-tile__pic { width: 62px; height: 62px; }
  .cz-creature { width: 46px; height: 46px; }
  .cz-tile__go { display: none; }
  .cz-welcome { padding: var(--gp-space-6) var(--gp-space-5); }
}

@media (prefers-reduced-motion: reduce) {
  .cz-tile, .cz-tile__go { transition: none; }
  .cz-tile:hover, .cz-tile:focus-visible { transform: none; }
  .cz-tile:hover .cz-tile__go { transform: none; }
}
/* ==========================================================================
   15. The mascot (inline SVG from modules/mascot.js)
   --------------------------------------------------------------------------
   The logo, animated. Markup comes from modules/mascot.js; the mood is a data
   attribute on the <svg> and everything below reacts to it.

   THE MOUTH
   The bar under the eyes carries a seam along its centre line. Every
   expression is that one path scaled vertically about its own end points, so
   the corners stay pinned and only the curve between them deepens, flattens
   or inverts. A negative scale is a frown. One path, eight faces, and the
   logo's silhouette never moves, which is what stops an expressive mascot
   from becoming an unstable logo.

   WHY IDLE USES THREE DIFFERENT PERIODS
   The breath, the blink, the glance and the ear flick run at 4.3s, 4.3s,
   9.1s and 7.7s. Nothing lines up, so the combination takes about five
   minutes to repeat and the mascot reads as alive rather than as a loop. Put
   them all on one period and the eye finds the seam within seconds.

   TWO RULES THE WHOLE SECTION OBEYS
   1. Nothing flashes, buzzes or shakes. This is section 1's promise to a
      nervous seven year old and it is not suspended because the thing moving
      is cute. It moves often; it never moves fast. Rotations stay under
      twenty degrees, the hop is eight units, and the only quick thing in the
      set is a blink, which is quick in life too.
   2. A held pose is a transition, a repeating one is an animation. Mixing
      them on one property means the animation wins while it runs and the
      element snaps when it is removed, so each mood picks one or the other.

   The reduced-motion block in section 14 collapses every animation here to
   nothing, and each keyframe is written so that its 0% frame is the resting
   pose. That is why reduced motion leaves a still, correct, still-smiling
   mascot rather than one frozen mid-blink.
   ========================================================================== */

.cz-mascot {
  display: block;
  width: 100%;
  height: 100%;
  /* The hop and the sparkles reach above y=0. */
  overflow: visible;
}

/* transform-box: view-box makes a px transform-origin mean user units, which
   is what every origin below is written in. Without it the origins are read
   against each element's own bounding box and every pivot is wrong. */
.cz-mascot__head,
.cz-mascot__pupils,
.cz-mascot__ear,
.cz-mascot__eye,
.cz-mascot__mouth,
.cz-mascot__spark,
.cz-mascot__z path {
  transform-box: view-box;
}

/* Low on the face, so a tilt swings the head over the bar rather than
   spinning it about the bridge of its nose. */
.cz-mascot__head { transform-origin: 32px 42px; }

/* Each ear pivots at its own base. --dir is +1 on the left and -1 on the
   right, so one keyframe drives both and they always move in opposite
   directions; a pair of ears moving together is a head tilt, not a twitch. */
.cz-mascot__ear--l { transform-origin: 19px 19px; --dir: 1; }
.cz-mascot__ear--r { transform-origin: 45px 19px; --dir: -1; }

/* A blink is the eye squashed about its own centre. The disc carries
   vector-effect="non-scaling-stroke", so a shut eye is a clean 2.6 line and
   not a flattened lens. Both the disc and the pupil carry these classes, so
   one rule squashes the whole eye. */
.cz-mascot__eye--l { transform-origin: 21.5px 27px; }
.cz-mascot__eye--r { transform-origin: 42.5px 27px; }

/* The seam's end points. Every expression is a scaleY about here. */
.cz-mascot__mouth { transform-origin: 32px 48.9px; }

/* The bar itself never moves, and this rule is here to say so. A logo whose
   silhouette wobbles stops being a logo; the seam drawn on it does all the
   expressing. Anything that later tries to transform the whole mascot has to
   step over this line deliberately. */
.cz-mascot__bar { transform: none; }

.cz-mascot__head,
.cz-mascot__ear { transition: transform var(--gp-dur-slow) var(--gp-ease); }
.cz-mascot__eye {
  transition: transform var(--gp-dur-mid) var(--gp-ease),
              opacity var(--gp-dur-mid) var(--gp-ease);
}
.cz-mascot__arc { transition: opacity var(--gp-dur-mid) var(--gp-ease); }
.cz-mascot__pupils {
  transition: transform var(--gp-dur-slow) var(--gp-ease),
              opacity var(--gp-dur-mid) var(--gp-ease);
}
/* Slower than a blink and faster than a mood change: an expression that
   arrives with the head movement reads as one gesture. */
.cz-mascot__mouth { transition: transform 320ms var(--gp-ease); }

/* Three sets of eyes live in the markup at once and the mood cross-fades
   between them. Bending a round eye into a smile reads as a wince.

   What cross-fades is the CONTENTS of the eye, never the white disc. Dark ink
   is only legible on that disc: on the page itself it disappears in dark mode,
   and on the Deep welcome panel it disappears in both. */
.cz-mascot__eyes,
.cz-mascot__oh { transition: opacity var(--gp-dur-mid) var(--gp-ease); }
.cz-mascot__eyes--open  { opacity: 1; }
.cz-mascot__eyes--happy,
.cz-mascot__eyes--sleep { opacity: 0; }

/* The one shape the seam cannot make, so it is a second element. */
.cz-mascot__oh { opacity: 0; }

/* Sparkles, dots and z are silent until a mood asks for them. */
.cz-mascot__spark,
.cz-mascot__dot,
.cz-mascot__z path { opacity: 0; }

/* --- keyframes ------------------------------------------------------- */

@keyframes cz-breathe {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(1.4px); }
}

/* Two blinks close together and then a long pause, which is how eyes actually
   behave. Evenly spaced single blinks read as a metronome. */
@keyframes cz-blink {
  0%, 84%   { transform: scaleY(1); }
  86%       { transform: scaleY(0.07); }
  88%       { transform: scaleY(1); }
  90%       { transform: scaleY(0.07); }
  92%, 100% { transform: scaleY(1); }
}

/* Idle looking-about: four stops, none of them far. This is the loop that
   does most of the work of making a still logo look awake. */
@keyframes cz-wander {
  0%, 12%   { transform: translate(0, 0); }
  22%, 34%  { transform: translate(2.6px, -0.8px); }
  46%, 58%  { transform: translate(-2.4px, 1px); }
  70%, 82%  { transform: translate(1.2px, 1.6px); }
  92%, 100% { transform: translate(0, 0); }
}

/* One ear, once, briefly. Nothing else in idle moves this fast. */
@keyframes cz-flick {
  0%, 62%, 76%, 100% { transform: rotate(0deg); }
  66% { transform: rotate(calc(var(--dir) * -9deg)); }
  70% { transform: rotate(calc(var(--dir) * 5deg)); }
  73% { transform: rotate(calc(var(--dir) * -2deg)); }
}

@keyframes cz-tilt {
  0%, 4%    { transform: rotate(0deg); }
  12%, 30%  { transform: rotate(-6deg); }
  42%       { transform: rotate(0deg); }
  55%, 75%  { transform: rotate(5deg); }
  86%, 100% { transform: rotate(0deg); }
}

/* Snap and stare, snap and stare. A pupil that slides continuously wobbles;
   one that arrives and holds looks like it is reading something. */
@keyframes cz-glance {
  0%, 6%    { transform: translate(0, 0); }
  28%       { transform: translate(-4.2px, 1.4px); }
  34%, 50%  { transform: translate(-2px, -2.6px); }
  60%, 80%  { transform: translate(4.6px, 1.2px); }
  88%, 100% { transform: translate(0, 0); }
}

@keyframes cz-twitch {
  0%, 44%, 56%, 100% { transform: rotate(0deg); }
  47% { transform: rotate(calc(var(--dir) * -11deg)); }
  50% { transform: rotate(calc(var(--dir) * 8deg)); }
  53% { transform: rotate(calc(var(--dir) * -4deg)); }
}

/* Crouch, leap, hang, land, squash, rest. Take out the crouch and the squash
   and it stops being a jump and becomes a lift in a shaft. */
@keyframes cz-hop {
  0%        { transform: translateY(0); }
  8%        { transform: translateY(2px); }
  14%, 30%  { transform: translateY(-8.5px); }
  44%       { transform: translateY(0); }
  50%       { transform: translateY(1.6px); }
  56%, 100% { transform: translateY(0); }
}

@keyframes cz-earflap {
  0%        { transform: rotate(0deg); }
  8%        { transform: rotate(calc(var(--dir) * 6deg)); }
  16%, 30%  { transform: rotate(calc(var(--dir) * -14deg)); }
  46%       { transform: rotate(calc(var(--dir) * 9deg)); }
  54%       { transform: rotate(calc(var(--dir) * -4deg)); }
  62%, 100% { transform: rotate(0deg); }
}

/* A single nod, for the wink. */
@keyframes cz-nod {
  0%, 100% { transform: rotate(0deg) translateY(0); }
  35%      { transform: rotate(-5deg) translateY(-2px); }
  70%      { transform: rotate(2deg) translateY(0); }
}

/* A small jump backwards, for the surprise. */
@keyframes cz-startle {
  0%, 100% { transform: translateY(0); }
  30%      { transform: translateY(-3.5px); }
  60%      { transform: translateY(0.8px); }
}

/* --x and --y carry each sparkle's position, so one keyframe serves all
   three. They have to be repeated inside every frame because a transform is
   replaced wholesale, not merged. */
@keyframes cz-spark {
  0%, 12%   { transform: translate(var(--x), var(--y)) scale(0);    opacity: 0; }
  30%       { transform: translate(var(--x), var(--y)) scale(1.15); opacity: 1; }
  55%, 100% { transform: translate(var(--x), var(--y)) scale(0);    opacity: 0; }
}

@keyframes cz-dot {
  0%, 100% { opacity: 0.15; }
  20%, 45% { opacity: 1; }
}

/* Up and gently to the right. The horizontal travel is capped at 5 because
   the z starts at x=52.5 and is 5.5 wide, and 52.5 + 5 + 5.5 is the last
   value that stays inside the 64 box. */
@keyframes cz-drift {
  0%   { transform: translate(0, 0);       opacity: 0; }
  15%  { transform: translate(1px, -3px);  opacity: 1; }
  75%  { transform: translate(3.5px, -15px); opacity: 1; }
  100% { transform: translate(5px, -21px); opacity: 0; }
}

/* --- moods ------------------------------------------------------------ */

/* idle: the resting state, and not a still one. Four loops of three different
   lengths, none of them large enough to pull a child off a question. */
.cz-mascot[data-mood="idle"] .cz-mascot__head   { animation: cz-breathe 4.3s ease-in-out infinite; }
.cz-mascot[data-mood="idle"] .cz-mascot__eye    { animation: cz-blink 4.3s linear infinite; }
.cz-mascot[data-mood="idle"] .cz-mascot__pupils { animation: cz-wander 9.1s ease-in-out infinite; }
.cz-mascot[data-mood="idle"] .cz-mascot__ear    { animation: cz-flick 7.7s linear infinite; }

/* curious: the signature. The brand is called CurioZoo, so the one thing the
   mascot has to look like it is doing is noticing. */
.cz-mascot[data-mood="curious"] .cz-mascot__head   { animation: cz-tilt 6.5s ease-in-out infinite; }
.cz-mascot[data-mood="curious"] .cz-mascot__eye    { animation: cz-blink 5.3s linear infinite; }
.cz-mascot[data-mood="curious"] .cz-mascot__pupils { animation: cz-glance 6.5s ease-in-out infinite; }
.cz-mascot[data-mood="curious"] .cz-mascot__ear    { animation: cz-twitch 5.3s linear infinite; }
.cz-mascot[data-mood="curious"] .cz-mascot__mouth  { transform: scaleY(0.85); }

/* happy: after a right answer. Three hops at 760ms, which is why setMood is
   called with 2300 there; a fourth hop starts to look like gloating. */
.cz-mascot[data-mood="happy"] .cz-mascot__head  { animation: cz-hop 760ms var(--gp-ease) 3; }
.cz-mascot[data-mood="happy"] .cz-mascot__ear   { animation: cz-earflap 760ms var(--gp-ease) 3; }
.cz-mascot[data-mood="happy"] .cz-mascot__spark { animation: cz-spark 760ms var(--gp-ease) 3; }
.cz-mascot[data-mood="happy"] .cz-mascot__pupils      { opacity: 0; }
.cz-mascot[data-mood="happy"] .cz-mascot__eyes--happy { opacity: 1; }
.cz-mascot[data-mood="happy"] .cz-mascot__mouth       { transform: scaleY(2.1); }
.cz-mascot__spark--1 { --x: 9.5px;  --y: 15px; animation-delay: 0ms; }
.cz-mascot__spark--2 { --x: 32px;   --y: 5px;  animation-delay: 60ms; }
.cz-mascot__spark--3 { --x: 54.5px; --y: 15px; animation-delay: 30ms; }

/* oops: after a wrong one. It ducks, looks away, and the smile flattens the
   other way by three quarters. It must never look disappointed in the child:
   the panel underneath already says "here is why", and a sad animal on top of
   that is a telling-off. That is why the frown is small and the duck is not. */
.cz-mascot[data-mood="oops"] .cz-mascot__head   { transform: translateY(6px); }
.cz-mascot[data-mood="oops"] .cz-mascot__pupils { transform: translate(-1px, 3.2px); }
.cz-mascot[data-mood="oops"] .cz-mascot__ear    { transform: rotate(calc(var(--dir) * 16deg)); }
.cz-mascot[data-mood="oops"] .cz-mascot__mouth  { transform: scaleY(-0.75); }

/* think: instead of a spinner. A spinner says nothing is happening. */
.cz-mascot[data-mood="think"] .cz-mascot__head   { transform: rotate(-3deg); }
.cz-mascot[data-mood="think"] .cz-mascot__pupils { transform: translate(-3.4px, -3.4px); }
.cz-mascot[data-mood="think"] .cz-mascot__ear    { transform: rotate(calc(var(--dir) * 14deg)); }
.cz-mascot[data-mood="think"] .cz-mascot__mouth  { transform: scaleY(0.2); }
.cz-mascot[data-mood="think"] .cz-mascot__dot    { animation: cz-dot 1.4s ease-in-out infinite; }
/* Left to right, so it counts rather than flickers. */
.cz-mascot__dot--1 { animation-delay: 0ms; }
.cz-mascot__dot--2 { animation-delay: 160ms; }
.cz-mascot__dot--3 { animation-delay: 320ms; }

/* sleep: for an app left open. */
.cz-mascot[data-mood="sleep"] .cz-mascot__head { animation: cz-breathe 4s ease-in-out infinite; }
.cz-mascot[data-mood="sleep"] .cz-mascot__ear  { transform: rotate(calc(var(--dir) * 20deg)); }
.cz-mascot[data-mood="sleep"] .cz-mascot__pupils      { opacity: 0; }
.cz-mascot[data-mood="sleep"] .cz-mascot__eyes--sleep { opacity: 1; }
.cz-mascot[data-mood="sleep"] .cz-mascot__z path { animation: cz-drift 4s linear infinite; }
/* Negative delays start the second and third z partway through their own
   drift, so all three are already spread out on the first frame. */
.cz-mascot__z1 { animation-delay: 0s; }
.cz-mascot__z2 { animation-delay: -1.33s; }
.cz-mascot__z3 { animation-delay: -2.66s; }

/* wink: one eye, one nod, one wide smile. The cheapest way to make a mascot
   look like it is on the child's side.

   The shut eye is the happy arc, not the blink's flat line. Squashing the eye
   works for a blink because a blink is over in 60ms; held for a second and a
   half it stops reading as a closed eye and starts reading as a dash through
   the face. The white disc stays under the arc, because dark ink is legible
   on nothing else. */
.cz-mascot[data-mood="wink"] .cz-mascot__head   { animation: cz-nod 700ms var(--gp-ease) 1; }
.cz-mascot[data-mood="wink"] .cz-mascot__ear--r { transform: rotate(calc(var(--dir) * 14deg)); }
.cz-mascot[data-mood="wink"] .cz-mascot__mouth  { transform: scaleY(1.75); }
.cz-mascot[data-mood="wink"] .cz-mascot__pupils .cz-mascot__eye--r { opacity: 0; }
.cz-mascot[data-mood="wink"] .cz-mascot__eyes--happy { opacity: 1; }
.cz-mascot[data-mood="wink"] .cz-mascot__arc--l      { opacity: 0; }
.cz-mascot[data-mood="wink"] .cz-mascot__arc--r      { opacity: 1; }

/* wow: eyes wide, ears up, mouth round. For a personal best or a first. */
.cz-mascot[data-mood="wow"] .cz-mascot__head  { animation: cz-startle 520ms var(--gp-ease) 1; }
.cz-mascot[data-mood="wow"] .cz-mascot__eye   { transform: scale(1.14); }
.cz-mascot[data-mood="wow"] .cz-mascot__ear   { transform: rotate(calc(var(--dir) * -18deg)); }
.cz-mascot[data-mood="wow"] .cz-mascot__mouth { opacity: 0; }
.cz-mascot[data-mood="wow"] .cz-mascot__oh    { opacity: 1; }

/* --- where it is used ------------------------------------------------- */

/* The top bar. Hovering or focusing the brand makes it look up at you, which
   is the cheapest possible invitation to press it. */
.gp-brand:hover .cz-mascot[data-mood="idle"] .cz-mascot__pupils,
.gp-brand:focus-visible .cz-mascot[data-mood="idle"] .cz-mascot__pupils {
  transform: translate(0, -3px);
}

/* The welcome panel. Its background is Deep, and the brand orange is not
   allowed to sit on Deep, so the mascot is recoloured through the variables
   modules/mascot.js reads. The layout for this lives with the rest of
   .cz-welcome, further up. */
.cz-welcome__pet {
  --cz-mascot-tone: var(--cz-on-deep-accent);
  --cz-mascot-inner: var(--cz-deep);
  --cz-mascot-paper: var(--cz-deep);
  width: 116px;
  height: 116px;
  flex: none;
  align-self: end;
}

@media (max-width: 560px) {
  .cz-welcome { grid-template-columns: 1fr; justify-items: start; }
  .cz-welcome__pet { width: 84px; height: 84px; }
}

@media (prefers-reduced-motion: reduce) {
  /* Section 14 already stops every animation above. What it cannot do is hide
     the three effects that only make sense in motion: a sparkle that never
     grows and a z that never drifts are just specks on the mascot's face.
     The expressions themselves stay, because a face is not motion. */
  .cz-mascot__spark,
  .cz-mascot__dot,
  .cz-mascot__z path { opacity: 0 !important; }
  .cz-mascot[data-mood="think"] .cz-mascot__dot { opacity: 0.55 !important; }
}

/* ====================================================================
   Name the Element
   ==================================================================== */

.cz-elemq { text-align: center; }

.cz-elem-pic {
  display: grid;
  place-items: center;
  width: 128px; height: 128px;
  margin: var(--gp-space-5) auto var(--gp-space-3);
  border-radius: var(--gp-radius-xl);
  background: var(--gp-surface);
  border: 2px solid var(--gp-line);
}
.cz-elemart { width: 92px; height: 92px; display: block; }

.cz-elem-ask {
  font-size: var(--gp-text-lg);
  line-height: var(--gp-leading-snug);
  color: var(--gp-ink);
  max-width: 34ch;
  margin: 0 auto var(--gp-space-2);
}
.cz-elem-hint { margin: 0 0 var(--gp-space-4); font-size: var(--gp-text-sm); }
.cz-elem-extra { margin-top: var(--gp-space-2); font-size: var(--gp-text-sm); }
.cz-elem-sym { font-size: var(--gp-text-xl); font-weight: 800; letter-spacing: 0.01em; }

/* The big tile for "what is this symbol", drawn like a cell of the real table */
.cz-elem-tile {
  display: grid;
  place-content: center;
  width: 132px; height: 132px;
  margin: var(--gp-space-5) auto var(--gp-space-3);
  border-radius: var(--gp-radius-lg);
  border: 3px solid var(--cell-line, var(--gp-line-strong));
  background: var(--cell-bg, var(--gp-surface-2));
  color: var(--cell-ink, var(--gp-ink));
}
.cz-elem-tile__z { font-size: var(--gp-text-sm); font-weight: 700; opacity: .75; }
.cz-elem-tile__sym { font-size: 46px; font-weight: 800; line-height: 1.05; }

/* ---- the periodic table ----
   18 columns wide, with the f-block on rows 9 and 10 as every printed table
   does. Cells are square and scale with the viewport, so the whole table fits
   a phone without a horizontal scrollbar. */
.cz-pt {
  display: grid;
  grid-template-columns: repeat(18, 1fr);
  grid-auto-rows: minmax(0, 1fr);
  gap: clamp(1px, 0.3vw, 3px);
  max-width: 760px;
  margin: var(--gp-space-4) auto 0;
}
.cz-pt__cell {
  aspect-ratio: 1;
  display: grid;
  place-content: center;
  padding: 0;
  border: 1px solid var(--cell-line, var(--gp-line));
  border-radius: clamp(2px, 0.5vw, 5px);
  background: var(--cell-bg, var(--gp-surface-2));
  color: var(--cell-ink, var(--gp-ink));
  cursor: pointer;
  min-width: 0;
  overflow: hidden;
  transition: transform var(--gp-dur-fast) var(--gp-ease);
}
.cz-pt__cell:hover:not(:disabled) { transform: scale(1.18); z-index: 2; }
.cz-pt__cell:disabled { cursor: default; }
.cz-pt__z { display: none; }
.cz-pt__sym {
  font-size: clamp(7px, 1.35vw, 13px);
  font-weight: 800;
  line-height: 1;
}
/* The f-block rows sit apart from the main block. */
.cz-pt__cell[data-style*="grid-row:9"] { margin-top: 10px; }

.cz-pt__cell.is-correct {
  background: var(--gp-good); border-color: var(--gp-good);
  color: #fff; transform: scale(1.25); z-index: 3;
}
.cz-pt__cell.is-incorrect {
  background: var(--gp-retry); border-color: var(--gp-retry); color: #fff;
}

/* One colour per family, so the table's shape is visible before any answer:
   the noble gases really are a column, the metals really are most of it. */
.cz-pt__cell--nonmetal,             .cz-elem-tile.cz-pt__cell--nonmetal
  { --cell-bg: var(--cz-leaf-soft);     --cell-line: var(--cz-leaf-line);     --cell-ink: var(--cz-leaf-ink); }
.cz-pt__cell--noble-gas,            .cz-elem-tile.cz-pt__cell--noble-gas
  { --cell-bg: var(--cz-orchid-soft);   --cell-line: var(--cz-orchid-line);   --cell-ink: var(--cz-orchid-ink); }
.cz-pt__cell--halogen,              .cz-elem-tile.cz-pt__cell--halogen
  { --cell-bg: var(--cz-lagoon-soft);   --cell-line: var(--cz-lagoon-line);   --cell-ink: var(--cz-lagoon-ink); }
.cz-pt__cell--alkali-metal,         .cz-elem-tile.cz-pt__cell--alkali-metal
  { --cell-bg: var(--cz-mango-soft);    --cell-line: var(--cz-mango-line);    --cell-ink: var(--cz-mango-ink); }
.cz-pt__cell--alkaline-earth-metal, .cz-elem-tile.cz-pt__cell--alkaline-earth-metal
  { --cell-bg: var(--cz-honey-soft);    --cell-line: var(--cz-honey-line);    --cell-ink: var(--cz-honey-ink); }
.cz-pt__cell--transition-metal,     .cz-elem-tile.cz-pt__cell--transition-metal
  { --cell-bg: var(--cz-sky-soft);      --cell-line: var(--cz-sky-line);      --cell-ink: var(--cz-sky-ink); }
.cz-pt__cell--metalloid,            .cz-elem-tile.cz-pt__cell--metalloid
  { --cell-bg: var(--cz-jade-soft);     --cell-line: var(--cz-jade-line);     --cell-ink: var(--cz-jade-ink); }
.cz-pt__cell--metal,                .cz-elem-tile.cz-pt__cell--metal
  { --cell-bg: var(--gp-surface-3);     --cell-line: var(--gp-line-strong);   --cell-ink: var(--gp-ink-soft); }
.cz-pt__cell--lanthanide,           .cz-elem-tile.cz-pt__cell--lanthanide
  { --cell-bg: var(--cz-flamingo-soft); --cell-line: var(--cz-flamingo-line); --cell-ink: var(--cz-flamingo-ink); }
.cz-pt__cell--actinide,             .cz-elem-tile.cz-pt__cell--actinide
  { --cell-bg: var(--cz-flamingo-soft); --cell-line: var(--cz-flamingo-line); --cell-ink: var(--cz-flamingo-ink); }

.gp-flagq__choices--tight { max-width: 420px; margin-inline: auto; }

@media (prefers-reduced-motion: reduce) {
  .cz-pt__cell, .cz-pt__cell:hover:not(:disabled) { transition: none; transform: none; }
}

/* ====================================================================
   Browsing mode
   ==================================================================== */

.cz-learnlink { width: 100%; justify-content: center; margin-top: var(--gp-space-4); }
.cz-learnlink .gp-btn__label { white-space: normal; }

.cz-learn { display: grid; gap: var(--gp-space-4); }
.cz-learn__bar {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--gp-space-4); flex-wrap: wrap;
}
.cz-learn__head { margin: 0; }
.cz-learn__jump { margin: 0; }
.gp-pill--small { font-size: var(--gp-text-xs); padding: 6px 12px; }

.cz-learn__card {
  display: grid;
  justify-items: center;
  gap: var(--gp-space-2);
  padding: var(--gp-space-6) var(--gp-space-5);
  border: 2px solid var(--gp-line);
  border-radius: var(--gp-radius-xl);
  background: var(--gp-surface);
  text-align: center;
}
.cz-learn__media {
  display: grid; place-items: center;
  width: 100%; min-height: 200px;
}
.cz-learn__flag {
  max-width: min(320px, 100%); height: auto;
  border-radius: var(--gp-radius-sm);
  border: 1px solid var(--gp-line);
}
.cz-learn__media .gp-shapefig { width: 100%; max-width: 260px; height: auto; color: var(--gp-accent); }
.cz-learn__big {
  font-size: var(--gp-text-2xl); font-weight: 800; color: var(--gp-ink-soft);
  margin: 0; line-height: var(--gp-leading-tight);
}
.cz-learn__name {
  margin: 0; font-size: var(--gp-text-2xl); font-weight: 800;
  letter-spacing: -0.02em; color: var(--gp-accent); line-height: var(--gp-leading-tight);
}
.cz-learn__sub { margin: 0; color: var(--gp-ink-soft); font-size: var(--gp-text-md); }
.cz-learn__note { margin: 0; color: var(--gp-ink-muted); font-size: var(--gp-text-sm); }

.cz-learn__nav {
  display: flex; align-items: center; justify-content: center;
  gap: var(--gp-space-5);
}
.cz-learn__nav .gp-btn { min-width: 84px; }
.cz-learn__count { margin: 0; font-size: var(--gp-text-md); color: var(--gp-ink-soft); }
.cz-learn__hint { text-align: center; margin: 0; font-size: var(--gp-text-xs); }

/* ---- the periodic table page ---- */

.cz-pt__cell.is-picked {
  outline: 3px solid var(--gp-focus);
  outline-offset: 1px;
  transform: scale(1.25);
  z-index: 3;
}
.cz-elem-detail:empty { display: none; }
.cz-elem-detail {
  display: flex; align-items: center; gap: var(--gp-space-5);
  flex-wrap: wrap;
  padding: var(--gp-space-5);
  border: 2px solid var(--gp-line);
  border-radius: var(--gp-radius-xl);
  background: var(--gp-surface);
  margin-top: var(--gp-space-5);
}
.cz-elem-card {
  display: grid; place-content: center; flex: none;
  width: 104px; height: 104px;
  border-radius: var(--gp-radius-lg);
  border: 3px solid var(--cell-line, var(--gp-line-strong));
  background: var(--cell-bg, var(--gp-surface-2));
  color: var(--cell-ink, var(--gp-ink));
}
.cz-elem-card__z { font-size: var(--gp-text-sm); font-weight: 700; opacity: .75; }
.cz-elem-card__sym { font-size: 38px; font-weight: 800; line-height: 1.05; }
.cz-elem-facts { display: grid; gap: 2px; min-width: 0; }
.cz-elem-facts__name { margin: 0; font-size: var(--gp-text-xl); font-weight: 800; }
.cz-elem-facts__es { margin: 0; color: var(--gp-ink-soft); }
.cz-elem-facts__meta { margin: 0; color: var(--gp-ink-muted); font-size: var(--gp-text-sm); }
.cz-elem-facts__use { margin: 4px 0 0; color: var(--gp-ink); }

.cz-facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--gp-space-5);
  margin-top: var(--gp-space-6);
}
.cz-fact h2 { margin: 0 0 var(--gp-space-2); font-size: var(--gp-text-lg); color: var(--gp-accent); }
.cz-fact p { margin: 0 0 var(--gp-space-3); line-height: var(--gp-leading-body); }
.cz-fact p:last-child { margin-bottom: 0; }
.cz-fact--wide { grid-column: 1 / -1; }

.cz-legend { margin-top: var(--gp-space-6); display: grid; gap: var(--gp-space-2); }
.cz-legend__head { font-size: var(--gp-text-lg); margin: 0 0 var(--gp-space-2); }
.cz-legend__row {
  display: flex; align-items: flex-start; gap: var(--gp-space-3);
  font-size: var(--gp-text-sm); line-height: var(--gp-leading-snug);
}
.cz-legend__swatch {
  flex: none; width: 26px; height: 26px; border-radius: 7px;
  background: var(--cell-bg, var(--gp-surface-2));
  border: 2px solid var(--cell-line, var(--gp-line));
}

@media (max-width: 560px) {
  .cz-learn__media { min-height: 150px; }
  .cz-learn__nav .gp-btn { min-width: 64px; }
}

/* The table scrolls sideways rather than shrinking its cells below a tappable
   size. 18 columns in 375px is a 12px cell; a child cannot hit that. */
.cz-pt-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
@media (max-width: 720px) {
  .cz-pt { min-width: 560px; }
  .cz-pt-scroll { margin-inline: calc(var(--gp-space-5) * -1); padding-inline: var(--gp-space-5); }
}

/* ====================================================================
   Learn and Practice
   ====================================================================
   A game page offers two different things and used to present them as a form
   with a link under it. They are now two labelled sections, in the order they
   should be used: looking first, because being tested on material you have
   never met is not a game.

   The colour means the ACTION, not the game — learn is jade everywhere, so it
   is recognisable as a mode across all four. */

.cz-mode {
  position: relative;
  border: 2px solid var(--mode-line, var(--gp-line));
  border-radius: var(--gp-radius-xl);
  background: var(--mode-bg, var(--gp-surface));
  padding: var(--gp-space-6) var(--gp-space-5) var(--gp-space-5);
  margin-top: var(--gp-space-6);
}
.cz-mode__tag {
  position: absolute;
  top: 0; left: var(--gp-space-5);
  transform: translateY(-50%);
  margin: 0;
  padding: 4px 12px;
  border-radius: var(--gp-radius-pill);
  background: var(--mode-tag, var(--gp-ink));
  color: var(--gp-on-accent);
  font-size: var(--gp-text-xs);
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.cz-mode__body {
  display: flex;
  align-items: flex-start;
  gap: var(--gp-space-4);
  margin-bottom: var(--gp-space-4);
}
.cz-mode__icon {
  display: grid; place-items: center;
  width: 56px; height: 56px; flex: none;
  border-radius: var(--gp-radius-lg);
  background: var(--gp-surface);
  border: 2px solid var(--mode-line, var(--gp-line));
  color: var(--mode-ink, var(--gp-ink));
}
.cz-mode__icon svg { width: 30px; height: 30px; }
.cz-mode__title {
  margin: 0 0 2px;
  font-size: var(--gp-text-lg);
  color: var(--mode-ink, var(--gp-ink));
}
.cz-mode__blurb {
  margin: 0;
  color: var(--gp-ink-soft);
  font-size: var(--gp-text-sm);
  line-height: var(--gp-leading-snug);
}
.cz-mode__go { width: 100%; justify-content: center; }

.cz-mode--learn {
  --mode-bg: var(--cz-jade-soft);
  --mode-line: var(--cz-jade-line);
  --mode-ink: var(--cz-jade-ink);
  --mode-tag: var(--cz-jade);
}
.cz-mode--learn .cz-mode__go {
  background: var(--cz-jade);
  border-color: var(--cz-jade);
  color: var(--gp-on-accent);
}
.cz-mode--practice {
  --mode-tag: var(--gp-accent);
  padding: var(--gp-space-6) 0 0;
  border: 0;
  background: none;
}
.cz-mode--practice .cz-mode__tag { left: var(--gp-space-4); }
.cz-mode--practice .gp-card--setup { margin-top: 0; }

@media (max-width: 560px) {
  .cz-mode { padding: var(--gp-space-6) var(--gp-space-4) var(--gp-space-4); }
  .cz-mode__icon { width: 46px; height: 46px; }
  .cz-mode__icon svg { width: 24px; height: 24px; }
}

/* The back control sits in the page, above the title, not in the top bar.
   In the bar it was a bare arrow beside the logo with no idea where it went;
   here it says its destination and is the same shape on every screen, next to
   the thing it takes you back from. */
.gp-backslot:empty { display: none; }
.gp-backslot { margin-bottom: var(--gp-space-4); }
.gp-backslot .gp-backlink { margin: 0; }

/* ============================================================ */
/* Guess the Angle                                               */
/* ============================================================ */

/* The room keeps the blue of the tile the child tapped to get here. Declared
   after the tile hues so it wins, and it only sets values -- it never provides
   a --room default, which is what made the purple room turn orange. */
.cz-room--sky {
  --room: var(--cz-sky);
  --room-soft: var(--cz-sky-soft);
  --room-line: var(--cz-sky-line);
  --room-ink: var(--cz-sky-ink);
}

.cz-ang { display: block; width: 100%; height: auto; }

.cz-ang-fig {
  display: flex;
  justify-content: center;
  margin: var(--gp-space-4) 0 var(--gp-space-5);
}
.cz-ang-fig .cz-ang { max-width: 280px; }
.cz-ang-fig .cz-ang--bounce { max-width: 420px; }

.cz-ang-ask {
  margin: 0;
  font-size: 1.15rem;
  font-weight: 700;
  line-height: 1.35;
  text-align: center;
  color: var(--gp-ink);
}
.cz-ang-hint { margin: var(--gp-space-2) 0 0; text-align: center; font-size: .92rem; }
.cz-ang-extra { margin-top: var(--gp-space-3); text-align: center; }

/* Only shown from three upwards, so it always reads as something earned. */
.cz-ang-streak {
  margin: var(--gp-space-2) auto 0;
  padding: 2px var(--gp-space-3);
  width: max-content;
  border-radius: var(--gp-radius-pill);
  background: var(--room-soft, var(--gp-accent-soft));
  color: var(--room-ink, var(--gp-accent-strong));
  font-size: .82rem;
  font-weight: 700;
}

/* Two angles side by side. They stay side by side even on a narrow phone,
   because comparing them is the entire question and stacking would turn it
   into a memory test. */
.cz-ang-choices--wide { grid-template-columns: 1fr 1fr; gap: var(--gp-space-3); }
.gp-choice--fig { min-height: 0; padding: var(--gp-space-3); }
.gp-choice--fig .gp-choice__body { width: 100%; }
.gp-choice--fig .cz-ang { max-width: 190px; margin: 0 auto; }

.cz-ang-choices--sort { grid-template-columns: repeat(2, 1fr); gap: var(--gp-space-3); }
.cz-ang-choices--sort .gp-choice { min-height: 72px; padding: var(--gp-space-3) var(--gp-space-4); }
.cz-ang-choice__sub {
  display: block;
  margin-top: 2px;
  font-size: .78rem;
  font-weight: 500;
  color: var(--gp-ink-muted);
}
@media (min-width: 700px) {
  .cz-ang-choices--sort { grid-template-columns: repeat(3, 1fr); }
}

/* ---- the workshop ---- */

.cz-ang-lab { margin-bottom: var(--gp-space-5); }
.cz-ang-lab__head { margin: 0 0 var(--gp-space-2); font-size: 1.2rem; }
.cz-ang-lab__lede { margin: 0 0 var(--gp-space-4); color: var(--gp-ink-muted); }
.cz-ang-lab__note {
  margin: var(--gp-space-4) 0 0;
  padding: var(--gp-space-3) var(--gp-space-4);
  border-left: 4px solid var(--room-line, var(--gp-accent-line));
  border-radius: var(--gp-radius-sm);
  background: var(--room-soft, var(--gp-accent-soft));
  color: var(--gp-ink);
  font-size: .95rem;
}

.cz-ang-lab__stage { display: grid; justify-items: center; gap: var(--gp-space-2); }
.cz-ang-lab__stage .cz-ang { max-width: 260px; }
.cz-ang-lab__read { margin: 0; text-align: center; line-height: 1.2; }
.cz-ang-lab__read strong { display: block; font-size: 2.1rem; color: var(--room-ink, var(--gp-accent-strong)); }
.cz-ang-lab__read span { font-size: .9rem; color: var(--gp-ink-muted); }

.cz-ang-stops { margin-top: var(--gp-space-4); justify-content: center; }

.cz-ang-lab--trap { border-color: var(--room-line, var(--gp-accent-line)); }
.cz-ang-trap__pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--gp-space-3);
  align-items: center;
}
.cz-ang-trap__one { text-align: center; }
.cz-ang-trap__one .cz-ang { max-width: 170px; margin: 0 auto; }
.cz-ang-trap__val {
  margin: var(--gp-space-1) 0 0;
  font-weight: 700;
  color: var(--room-ink, var(--gp-accent-strong));
}

.cz-ang-fams {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: var(--gp-space-4);
  margin-bottom: var(--gp-space-4);
}
.cz-ang-fam { text-align: center; }
.cz-ang-fam__pic .cz-ang { max-width: 120px; margin: 0 auto; }
.cz-ang-fam__name { margin: var(--gp-space-1) 0 0; font-weight: 700; }
.cz-ang-fam__hint { margin: 2px 0 0; font-size: .82rem; color: var(--gp-ink-muted); }

.cz-ang-scenes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: var(--gp-space-4);
}
.cz-ang-scene { margin: 0; }
.cz-ang-scene__pic .cz-ang { max-width: 180px; margin: 0 auto; }
.cz-ang-scene figcaption { display: block; text-align: center; font-size: .88rem; }
.cz-ang-scene__deg {
  display: inline-block;
  margin-left: var(--gp-space-2);
  padding: 1px var(--gp-space-2);
  border-radius: var(--gp-radius-pill);
  background: var(--room-soft, var(--gp-accent-soft));
  color: var(--room-ink, var(--gp-accent-strong));
  font-weight: 700;
}
.cz-ang-scene__fact {
  display: block;
  margin-top: 2px;
  color: var(--gp-ink-muted);
  font-size: .8rem;
}

/* An angle that belongs to the object is a different claim from an angle that
   happens to be in one drawing, so the two do not get to look the same. */
.cz-ang-scene__deg.is-fixed {
  background: var(--room, var(--gp-accent));
  color: var(--gp-bg);
}

/* A topic's rule, repeated over every question in it. Quieter than the
   question, because it is a reminder and not the thing being asked. */
.gp-ex__recap {
  margin: 0 0 var(--gp-space-3);
  padding: var(--gp-space-2) var(--gp-space-3);
  border-left: 3px solid var(--gp-accent-line);
  border-radius: var(--gp-radius-sm);
  background: var(--gp-accent-soft);
  color: var(--gp-ink);
  font-size: .88rem;
  line-height: 1.45;
}
