/* ============================================================================
   NAPLAN Learning Quest — token layer
   Theme: Ochre & Ink · Type: Fredoka (display) + Lexend (body)
   Approved and merged 2026-08-26.

   ⚠ LOADED AFTER css/styles.css on purpose. styles.css still carries the old
   :root (--ink, --muted, --purple-dark, --blue ...) that the un-migrated screens
   depend on; those names do not collide with the ones here. The two that DO
   collide — --font-display and --font-body — must resolve to Fredoka/Lexend, so
   this file has to win. Screens migrate one at a time; the old tokens come out
   when the last one lands.

   Three tiers, in this order, and the rule that makes them work:
     1. PRIMITIVES  — raw palette and scales. Named for WHAT they are (--sand-200).
                      Never referenced directly by a component.
     2. SEMANTIC    — named for WHY (--text-secondary, --state-wrong-ink).
                      This is the only tier a screen or component should read.
     3. COMPONENT   — the small set of per-component overrides that genuinely
                      need to exist. Always point at semantic, never primitives.

   Dark mode is defined once, at the semantic tier only. Primitives never change
   between modes; the meaning of a primitive is fixed, only its ROLE swaps.

   Every colour pair in here is checked by tools/check-themes.js.
   ============================================================================ */

/* ---------------------------------------------------------------------------
   TIER 1 — PRIMITIVES
   --------------------------------------------------------------------------- */
:root{
  /* Sand — the warm neutral ground, taken from the illustrations' ochre skies */
  --sand-50:#fffdf7;  --sand-100:#f9f2e4; --sand-200:#f6ecd9; --sand-300:#e3d9c8;
  --sand-400:#cfc2ad; --sand-500:#a89c88; --sand-600:#8d8272; --sand-700:#6b6254;

  /* Ink — warm violet-dark, the app's existing text colour deepened */
  /* ⚠ --ink-500 was #645b78. That cleared 4.5:1 on a card but only 4.47:1 on the
     page ground where the gold blob is strongest — secondary text sits directly
     on that ground on the hub. Darkened to #5f5672, which clears 4.5:1 against
     EVERY surface the app paints: 4.89 gold blob / 4.84 clay / 5.06 violet /
     5.85 plain ground / 6.75 card. */
  --ink-900:#2f2a3d; --ink-700:#4a4359; --ink-500:#5f5672; --ink-300:#9a91ac;

  /* Violet — the action colour. The dusk sky in emusky, wombats and skatepark. */
  --violet-100:#efe9fb; --violet-200:#ddd0f7; --violet-300:#c2a7ff;
  --violet-600:#5b3fa8; --violet-700:#472f88; --violet-900:#2e2740;

  /* Green — success only. Never an action colour: an action colour that is also
     a status colour destroys the answer feedback signal. */
  --green-100:#e2f3ec; --green-300:#5fd3a3; --green-600:#0d7d55; --green-700:#0a5f41;
  --green-900:#1c3229;

  /* Clay — error. Deep enough to carry text, which #ff5d5d never was. */
  --clay-100:#fbeae2; --clay-300:#ff9b72; --clay-600:#a8481f; --clay-700:#8d3a17;
  --clay-900:#37231b;

  /* Gold — accent, focus ring, and the everyday chip colour */
  --gold-100:#f6ecd9; --gold-300:#e6bd76; --gold-500:#e0a020;
  --gold-700:#a05f13; --gold-800:#7a4a0d; --gold-900:#332b1e;

  /* Night — dark-mode surfaces. Never pure black: #000 makes light text vibrate
     and leaves no room to show elevation by lightening. */
  --night-900:#16131a; --night-800:#211d28; --night-700:#2b2634;
  --night-600:#332d3d; --night-400:#7d7288;
  --cream-100:#f0e9dc; --cream-300:#b0a598;

  /* ---- Type scale — 1.2 (minor third), rounded to whole pixels ----
     8 sizes, down from 46. Base is 17px: inside the 16–18px band the research
     supports for Year 3–5, and close enough to today's sizes to limit reflow. */
  --text-xs:12px;    /* non-essential only — never body copy */
  --text-sm:14px;    /* pills, labels, captions */
  --text-base:17px;  /* body copy, options, buttons */
  --text-lg:20px;    /* reading passages, question text */
  --text-xl:24px;
  --text-2xl:29px;
  --text-3xl:35px;
  --text-4xl:42px;

  /* ---- Weight ----
     The old file put 61% of declarations at 800, leaving hierarchy nothing to
     work with. 800 is gone; 700 is reserved for one thing per screen. */
  --weight-body:400;
  --weight-medium:500;
  --weight-strong:600;
  --weight-display:600;   /* Fredoka */
  --weight-shout:700;     /* reserved — at most one per screen */

  /* ---- Line height — 4 values, down from 16 ---- */
  --leading-tight:1.2;    /* display headings */
  --leading-snug:1.35;    /* UI text, buttons, options */
  --leading-normal:1.55;  /* body copy */
  --leading-loose:1.75;   /* reading passages — generous leading for young readers */

  /* ---- Spacing — 4px grid, down from 105 ad-hoc shorthands ---- */
  --space-1:4px;  --space-2:8px;  --space-3:12px; --space-4:16px;
  --space-5:20px; --space-6:24px; --space-8:32px; --space-10:40px;
  --space-12:48px; --space-16:64px;

  /* ---- Radius — 4 values + pill, down from 26 ---- */
  --radius-sm:8px; --radius-md:12px; --radius-lg:18px; --radius-xl:26px;
  --radius-pill:999px;

  /* ---- Motion ---- */
  --duration-fast:120ms; --duration-base:200ms; --duration-slow:320ms;
  --ease-out:cubic-bezier(.2,.8,.3,1);

  /* ---- Touch target ----
     WCAG 2.5.8 sets a 24px floor; 2.5.5 and both platform guidelines say 44–48.
     For a children's touch app 44 is the minimum, not the ambition. */
  --tap-min:44px;

  /* ---- Type families ---- */
  --font-display:"Fredoka",system-ui,sans-serif;
  --font-body:"Lexend",system-ui,sans-serif;
}

/* ---------------------------------------------------------------------------
   TIER 2 — SEMANTIC (light)
   These are the only colour tokens a component may use.
   --------------------------------------------------------------------------- */
:root{
  --bg-page:var(--sand-200);
  --bg-surface:var(--sand-50);
  --bg-raised:var(--sand-100);
  --bg-sunken:var(--sand-100);

  --text-primary:var(--ink-900);       /* 13.59:1 on surface */
  --text-secondary:var(--ink-500);     /*  6.24:1 on surface — was 3.70:1 */
  --text-on-action:#ffffff;            /*  7.72:1 on action */
  --text-on-accent:var(--gold-800);

  --action:var(--violet-600);
  --action-hover:var(--violet-700);
  --action-soft:var(--violet-100);
  --action-soft-ink:var(--violet-700);

  --accent:var(--gold-500);           /* FILL only — 2.24:1 on surface, never a border */
  --accent-border:var(--gold-700);    /* 5.07:1 — the border-safe partner */
  --accent-soft:var(--gold-100);
  --accent-ink:var(--gold-800);

  --state-correct:var(--green-600);
  --state-correct-soft:var(--green-100);
  --state-correct-ink:var(--green-700);
  --state-wrong:var(--clay-600);
  --state-wrong-soft:var(--clay-100);
  --state-wrong-ink:var(--clay-700);   /* 6.53:1 — the misspelling was 2.50:1 */

  /* Two border tokens, because one was never enough. --border-subtle is
     decoration; --border-control is the boundary of an interactive thing and
     must clear 3:1 (WCAG 1.4.11). The old --line was 1.24:1 for both jobs. */
  --border-subtle:var(--sand-300);
  --border-control:var(--sand-600);    /* 3.71:1 on surface */

  --focus-ring:var(--gold-700);        /* 5.07:1 — visible on every surface */

  --elev-0:none;
  --elev-1:0 1px 2px rgba(47,42,61,.06);
  --elev-2:0 2px 4px rgba(47,42,61,.06), 0 6px 14px rgba(47,42,61,.07);
  --elev-3:0 4px 8px rgba(47,42,61,.07), 0 12px 28px rgba(47,42,61,.09);
  --elev-4:0 8px 16px rgba(47,42,61,.09), 0 24px 48px rgba(47,42,61,.12);
}

/* ---------------------------------------------------------------------------
   TIER 2 — SEMANTIC (dark)

   ⚠ NOT CURRENTLY ACTIVE. <html> carries data-theme="light", which switches the
   media query below off. That is deliberate: only the LIGHT theme has been
   approved, and only the Welcome screen has migrated — a device set to dark would
   otherwise show a dark Welcome against 45 light screens.
   To enable dark later: remove data-theme="light" from the app's <html>, once
   every screen has a reviewed dark appearance.
   Only roles change. In dark mode elevation is shown by LIGHTENING the surface,
   not by casting a bigger shadow, so the shadows shrink and the surfaces climb.
   --------------------------------------------------------------------------- */
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]){
    --bg-page:var(--night-900);
    --bg-surface:var(--night-800);
    --bg-raised:var(--night-700);
    --bg-sunken:var(--night-900);

    --text-primary:var(--cream-100);   /* 13.68:1 on surface */
    --text-secondary:var(--cream-300); /*  6.83:1 on surface */
    --text-on-action:#1c1626;          /* dark label on a light action fill */
    --text-on-accent:var(--gold-900);

    --action:var(--violet-300);
    --action-hover:#d3bcff;
    --action-soft:var(--violet-900);
    --action-soft-ink:#cdb6ff;

    --accent:var(--gold-300);
    --accent-border:var(--gold-300);
    --accent-soft:var(--gold-900);
    --accent-ink:var(--gold-300);

    --state-correct:var(--green-300);
    --state-correct-soft:var(--green-900);
    --state-correct-ink:#7ce0b8;
    --state-wrong:var(--clay-300);
    --state-wrong-soft:var(--clay-900);
    --state-wrong-ink:#ffb094;         /* 8.38:1 */

    --border-subtle:var(--night-600);
    --border-control:var(--night-400); /* 3.65:1 on surface */
    --focus-ring:var(--gold-500);

    --elev-1:0 1px 2px rgba(0,0,0,.30);
    --elev-2:0 2px 6px rgba(0,0,0,.36);
    --elev-3:0 6px 16px rgba(0,0,0,.42);
    --elev-4:0 12px 32px rgba(0,0,0,.50);
  }
}
/* Manual override — the toggle must win in both directions, so dark is declared
   a second time rather than relying on the media query alone. */
:root[data-theme="dark"]{
  --bg-page:var(--night-900);       --bg-surface:var(--night-800);
  --bg-raised:var(--night-700);     --bg-sunken:var(--night-900);
  --text-primary:var(--cream-100);  --text-secondary:var(--cream-300);
  --text-on-action:#1c1626;         --text-on-accent:var(--gold-900);
  --action:var(--violet-300);       --action-hover:#d3bcff;
  --action-soft:var(--violet-900);  --action-soft-ink:#cdb6ff;
  --accent:var(--gold-300);         --accent-border:var(--gold-300);
  --accent-soft:var(--gold-900);    --accent-ink:var(--gold-300);
  --state-correct:var(--green-300); --state-correct-soft:var(--green-900);
  --state-correct-ink:#7ce0b8;
  --state-wrong:var(--clay-300);    --state-wrong-soft:var(--clay-900);
  --state-wrong-ink:#ffb094;
  --border-subtle:var(--night-600); --border-control:var(--night-400);
  --focus-ring:var(--gold-500);
  --elev-1:0 1px 2px rgba(0,0,0,.30);
  --elev-2:0 2px 6px rgba(0,0,0,.36);
  --elev-3:0 6px 16px rgba(0,0,0,.42);
  --elev-4:0 12px 32px rgba(0,0,0,.50);
}

/* ---------------------------------------------------------------------------
   TIER 3 — COMPONENTS
   Six mechanisms encoded three status states; four purple buttons were one
   button; three answer-option components were one component. Each set below
   collapses to a single definition with a complete state set.
   --------------------------------------------------------------------------- */

/* ---- Button — replaces .gnav-btn / .gset-btn / .gq-check / .na-check ---- */
.btn{
  font-family:var(--font-display); font-weight:var(--weight-display);
  font-size:var(--text-base); line-height:var(--leading-snug);
  min-height:var(--tap-min); padding:var(--space-3) var(--space-5);
  border:1px solid transparent; border-radius:var(--radius-md);
  cursor:pointer; display:inline-flex; align-items:center; justify-content:center;
  gap:var(--space-2);
  transition:background var(--duration-fast) var(--ease-out),
             transform var(--duration-fast) var(--ease-out),
             box-shadow var(--duration-fast) var(--ease-out);
}
.btn--primary{ background:var(--action); color:var(--text-on-action); box-shadow:var(--elev-2); }
.btn--primary:hover:not(:disabled){ background:var(--action-hover); transform:translateY(-2px); box-shadow:var(--elev-3); }
.btn--primary:active:not(:disabled){ transform:translateY(0); box-shadow:var(--elev-1); }
.btn--secondary{ background:var(--action-soft); color:var(--action-soft-ink); border-color:var(--border-control); }
.btn--secondary:hover:not(:disabled){ background:var(--bg-raised); transform:translateY(-2px); }
.btn--quiet{ background:transparent; color:var(--action-soft-ink); border-color:var(--border-control); }
.btn:disabled{ opacity:.55; cursor:not-allowed; box-shadow:none; transform:none; }
.btn[aria-busy="true"]{ pointer-events:none; opacity:.8; }

/* One focus ring, on everything interactive. The old file had focus styles on
   8 selectors and none of them was a primary button. */
.btn:focus-visible,
.option:focus-visible,
.listrow:focus-visible,
.drawer__head:focus-visible,
.field:focus-visible{
  outline:3px solid var(--focus-ring); outline-offset:3px;
}

/* ---- Answer option — replaces .gq-opt / .qzopt / .tp-opt ---- */
.option{
  display:flex; align-items:center; gap:var(--space-3); width:100%; text-align:left;
  font-family:var(--font-body); font-weight:var(--weight-body);
  font-size:var(--text-base); line-height:var(--leading-snug);
  min-height:var(--tap-min); padding:var(--space-3);
  background:var(--bg-surface); color:var(--text-primary);
  border:2px solid var(--border-control); border-radius:var(--radius-md);
  margin-bottom:var(--space-2); cursor:pointer;
  transition:background var(--duration-fast) var(--ease-out),
             border-color var(--duration-fast) var(--ease-out);
}
.option:hover:not(:disabled){ background:var(--bg-raised); }
.option:active:not(:disabled){ transform:scale(.99); }
.option[aria-pressed="true"]{ border-color:var(--action); background:var(--action-soft); }
.option__key{
  width:26px; height:26px; flex:0 0 auto; display:grid; place-items:center;
  border-radius:var(--radius-sm); background:var(--accent-soft); color:var(--accent-ink);
  font-size:var(--text-sm); font-weight:var(--weight-strong);
}
.option__label{ flex:1; }
.option__mark{ margin-left:auto; font-size:var(--text-lg); font-weight:var(--weight-shout); }

/* Correct / incorrect carry a MARK and a border change, not colour alone —
   the old .gq-opt.correct and .wrong differed only in fill. */
.option--correct{ background:var(--state-correct-soft); border-color:var(--state-correct); color:var(--state-correct-ink); }
.option--correct .option__key{ background:var(--state-correct); color:var(--bg-surface); }
.option--wrong{ background:var(--state-wrong-soft); border-color:var(--state-wrong); color:var(--state-wrong-ink); }
.option--wrong .option__key{ background:var(--state-wrong); color:var(--bg-surface); }
.option:disabled{ opacity:.55; cursor:default; }

/* ---- List row — replaces .sub-btn / .gsub-btn / .tp-setbtn ---- */
.listrow{
  display:flex; align-items:center; gap:var(--space-3); width:100%; text-align:left;
  font-family:var(--font-body); font-weight:var(--weight-medium);
  font-size:var(--text-base); line-height:var(--leading-snug);
  min-height:var(--tap-min); padding:var(--space-3);
  background:var(--bg-raised); color:var(--text-primary);
  border:1px solid var(--border-control); border-radius:var(--radius-md);
  margin-bottom:var(--space-2); cursor:pointer;
}
.listrow:hover{ background:var(--bg-surface); }
.listrow__index{
  width:26px; height:26px; flex:0 0 auto; display:grid; place-items:center;
  border-radius:var(--radius-sm); background:var(--accent-soft); color:var(--accent-ink);
  font-size:var(--text-sm); font-weight:var(--weight-strong);
}
.listrow__label{ flex:1; }

/* ---- Status — ONE mechanism for three states, replacing six ----
     .badge-status / .gsub-tag / .section-tag / .soon-tag / .tp-setbtn.done /
     .gsub-btn.done|.partial, whose pill radius ranged 8px to 30px. */
.status{
  display:inline-flex; align-items:center; gap:var(--space-1);
  font-family:var(--font-body); font-size:var(--text-sm); font-weight:var(--weight-strong);
  padding:var(--space-1) var(--space-3); border-radius:var(--radius-pill);
  border:1px solid transparent; white-space:nowrap;
}
.status--todo{ background:var(--bg-sunken); color:var(--text-secondary); border-color:var(--border-subtle); }
.status--doing{ background:var(--accent-soft); color:var(--accent-ink); border-color:var(--accent-border); }
.status--done{ background:var(--state-correct-soft); color:var(--state-correct-ink); border-color:var(--state-correct); }

/* ---- Card / tile ---- */
.card{
  background:var(--bg-surface); border:1px solid var(--border-subtle);
  border-radius:var(--radius-lg); padding:var(--space-5); box-shadow:var(--elev-2);
}
.card--flat{ box-shadow:var(--elev-0); }

/* ---- Progress ---- */
.progress{
  height:10px; border-radius:var(--radius-pill); background:var(--bg-sunken);
  border:1px solid var(--border-subtle); overflow:hidden;
}
.progress__fill{ display:block; height:100%; background:var(--state-correct); }

/* ---- Drawer — one definition replacing five copy-pasted collapsibles ----
   Opens only on a press of the head, never on hover. See the collapsibles rule. */
.drawer__head{
  display:flex; align-items:center; gap:var(--space-3); width:100%; text-align:left;
  min-height:var(--tap-min); padding:var(--space-3) var(--space-4);
  background:var(--bg-surface); color:var(--text-primary);
  border:1px solid var(--border-subtle); border-radius:var(--radius-lg);
  font-family:var(--font-display); font-weight:var(--weight-display);
  font-size:var(--text-lg); cursor:pointer;
}
.drawer__chevron{
  margin-left:auto; width:28px; height:28px; flex:0 0 auto; display:grid; place-items:center;
  border-radius:var(--radius-pill); background:var(--action-soft); color:var(--action-soft-ink);
  transition:transform var(--duration-base) var(--ease-out);
}
.drawer__head[aria-expanded="true"] .drawer__chevron{ transform:rotate(180deg); }
.drawer__body{ display:grid; grid-template-rows:0fr; transition:grid-template-rows var(--duration-base) var(--ease-out); }
.drawer__head[aria-expanded="true"] + .drawer__body{ grid-template-rows:1fr; }
.drawer__inner{ overflow:hidden; }

/* ---- Feedback / empty / error ---- */
/* Block, not flex: a flex container turns every bare text node and inline <code>
   into its own flex item, which shreds the line wrapping. */
.notice{
  display:block; padding:var(--space-4);
  border-radius:var(--radius-md); border:1px solid var(--border-subtle);
  background:var(--bg-raised); color:var(--text-primary);
  font-size:var(--text-base); line-height:var(--leading-normal);
}
.notice--error{ background:var(--state-wrong-soft); color:var(--state-wrong-ink); border-color:var(--state-wrong); }
.notice--empty{
  display:flex; flex-direction:column; align-items:center; gap:var(--space-2);
  color:var(--text-secondary); text-align:center;
}

/* ---- Reduced motion — declared ONCE, not duplicated in five drawer blocks ---- */
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{
    animation-duration:.01ms !important; animation-iteration-count:1 !important;
    transition-duration:.01ms !important; scroll-behavior:auto !important;
  }
  .drawer__body{ transition:none; }
}
