/*
 * primer.css — the single source of the Interactive Primer's look-and-feel.
 *
 * Page-level (light DOM) styling lives here. Design tokens are declared on :root
 * as CSS custom properties; because custom properties pierce shadow boundaries,
 * the Web Components inherit the same palette and typography automatically
 * (see js/components/shared.js for the component-internal stylesheet).
 */

/*
 * Themes. Colour tokens are grouped per theme and selected by `data-theme` on <html>
 * (set early, before paint, by js/boot.js and the inline script in index.html). The
 * LIGHT palette is the :root default so the app looks right even before JS runs. The
 * `viz` tokens drive diagrams and manim animations (see js/theme.js → themeColors()).
 */
:root {
  /* Typography. The reading face is STIX Two Text — a modern serif co-designed with the STIX
     math fonts, so prose sits comfortably beside KaTeX's Computer-Modern math. It's loaded by
     js/boot.js; Georgia/Times are the fallbacks if the webfont can't load (so the page still
     reads well offline). The UI face stays native system-sans for speed + a clean modern chrome. */
  --primer-font-body: "STIX Two Text", Georgia, "Iowan Old Style", "Times New Roman", serif;
  --primer-font-ui: system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
  --primer-font-display: var(--primer-font-body);  /* headings; the fun theme overrides */
  --primer-font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;  /* instrument readouts */

  /* Rhythm */
  --primer-measure: 42rem;        /* comfortable reading width */
  --primer-radius: 0.85rem;
  --primer-gap: 1.4rem;

  /* Palette — LIGHT (default): a calm, "primer"-like parchment + ink scheme. */
  --primer-bg: #f8f4ec;
  --primer-surface: #ffffff;
  --primer-ink: #20252f;
  --primer-ink-soft: #5a6675;
  --primer-accent: #4d5bd1;       /* links, interactive accents */
  --primer-accent-ink: #ffffff;
  --primer-border: #ebe5d9;
  --primer-control-bg: #f1ede4;       /* recessed HUD control surface */
  --primer-control-border: #d8d1c2;
  --primer-badge-bg: #eceefb;
  --primer-badge-ink: #3a45a6;
  --primer-star: #f5b301;         /* filled confidence star */

  /* Elevation & focus — modern depth. Shadows are warm-tinted so cards sit naturally on
     the parchment (a neutral black shadow reads cold against the cream). The focus ring is
     the accent at low alpha. Each theme overrides these to match its own backdrop. */
  --primer-shadow-sm: 0 1px 2px rgba(74, 60, 34, 0.06);
  --primer-shadow-md: 0 1px 2px rgba(74, 60, 34, 0.05), 0 6px 18px rgba(74, 60, 34, 0.07);
  --primer-shadow-lg: 0 12px 36px rgba(74, 60, 34, 0.14);
  --primer-ring: rgba(77, 91, 209, 0.40);
  /* Quiz panel: a warm golden card (the standardized "Quick quiz"). */
  --primer-quiz-bg: #fdf3d7;
  --primer-quiz-border: #ecd29a;
  --primer-quiz-ink: #7a5b16;     /* the "Quick quiz" header */
  /* Vignette panel: a calm sage/teal aside — a path off the main trail. */
  --primer-vignette-bg: #eef5f2;
  --primer-vignette-border: #5b9c8f;
  --primer-vignette-ink: #2f6b5e;
  /* Quiz feedback: correct (ok) / incorrect (bad), ink + subtle tinted background. */
  --primer-ok: #1a8f3c;
  --primer-ok-bg: #e6f6ec;
  --primer-bad: #c0392b;
  --primer-bad-bg: #fdecea;

  /* Visualisation palette (diagrams + animations) */
  --primer-viz-bg: #ffffff;       /* animation/diagram backdrop */
  --primer-viz-ink: #1f2430;      /* labels and text on diagrams */
  --primer-viz-line: #1f2430;     /* axes, strokes, number lines */
  /* Categorical fills are GENERATED by a golden-angle hue sequence (js/theme.js →
     themeColors().cat) from these three knobs, so early colours are maximally distinct
     and only crowd as more are used. Tune per theme here. */
  --primer-cat-hue: 210;
  --primer-cat-sat: 62%;
  --primer-cat-light: 52%;

  /* Confidence colour ramp (explorer node fills): hue is the rating 0→120
     (red→green); saturation/lightness are theme-tuned for text legibility. */
  --primer-conf-sat: 70%;
  --primer-conf-light: 62%;

  /* Active-course accent: the course members + the course predecessor/successor in the explorers. */
  --primer-course: #e3b15c;
}

:root[data-theme="dark"] {
  --primer-bg: #14171f;
  --primer-surface: #1e222c;
  --primer-ink: #e8eaed;
  --primer-ink-soft: #9aa3b2;
  --primer-accent: #8c9eff;
  --primer-accent-ink: #14171f;
  --primer-border: #2c323e;
  --primer-control-bg: #11151d;       /* recessed HUD control surface (darker than surface) */
  --primer-control-border: #323b4a;
  --primer-badge-bg: #232a3a;
  --primer-badge-ink: #aeb9ff;
  --primer-star: #ffd24d;
  --primer-quiz-bg: #2e2716;
  --primer-quiz-border: #4f4226;
  --primer-quiz-ink: #f0cf78;
  --primer-vignette-bg: #16302b;
  --primer-vignette-border: #4f9d8c;
  --primer-vignette-ink: #8fd6c6;
  --primer-ok: #4ccb76;
  --primer-ok-bg: #16321f;
  --primer-bad: #ff6b6b;
  --primer-bad-bg: #3a1d1d;

  /* Deeper, neutral shadows read correctly on the dark backdrop. */
  --primer-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.30);
  --primer-shadow-md: 0 2px 4px rgba(0, 0, 0, 0.30), 0 8px 22px rgba(0, 0, 0, 0.42);
  --primer-shadow-lg: 0 16px 40px rgba(0, 0, 0, 0.55);
  --primer-ring: rgba(140, 158, 255, 0.45);

  --primer-viz-bg: #1e222c;
  --primer-viz-ink: #e8eaed;
  --primer-viz-line: #e8eaed;
  --primer-cat-hue: 210;
  --primer-cat-sat: 60%;
  --primer-cat-light: 66%;        /* lighter so fills pop on the dark backdrop */

  /* Darker, muted fills so the light node text stays readable on them. */
  --primer-conf-sat: 45%;
  --primer-conf-light: 34%;
  --primer-course: #8a6d2a;
}

:root[data-theme="fun"] {
  --primer-bg: #fff7fb;
  --primer-surface: #ffffff;
  --primer-ink: #2b2350;
  --primer-ink-soft: #6b5fa0;
  /* A deep rose (not the old #ff5da2): as a link on the near-white bg AND as the background
     under white --primer-accent-ink (active buttons, .focus-course) it clears WCAG AA 4.5:1,
     which the lighter pink failed. Still unmistakably the "fun" pink. */
  --primer-accent: #c81e66;
  --primer-accent-ink: #ffffff;
  --primer-border: #ffd6ec;
  --primer-control-bg: #fdeef7;       /* recessed HUD control surface */
  --primer-control-border: #ffd0e6;
  --primer-badge-bg: #e7f6ff;
  --primer-badge-ink: #1a8fd6;
  --primer-star: #ffb627;
  --primer-quiz-bg: #fff3c4;
  --primer-quiz-border: #ffdf8a;
  --primer-quiz-ink: #8a6d12;
  --primer-vignette-bg: #eafff7;
  --primer-vignette-border: #4fcab0;
  --primer-vignette-ink: #1f8f78;
  --primer-ok: #1fa84f;
  --primer-ok-bg: #e3f8e8;
  --primer-bad: #e23b54;
  --primer-bad-bg: #fde6ea;

  /* Soft pink-tinted shadows to match the cheerful backdrop. */
  --primer-shadow-sm: 0 1px 3px rgba(214, 79, 142, 0.12);
  --primer-shadow-md: 0 2px 6px rgba(214, 79, 142, 0.14), 0 10px 26px rgba(214, 79, 142, 0.16);
  --primer-shadow-lg: 0 16px 38px rgba(214, 79, 142, 0.22);
  --primer-ring: rgba(255, 93, 162, 0.45);

  --primer-viz-bg: #fffdf7;
  --primer-viz-ink: #2b2350;
  --primer-viz-line: #2b2350;
  --primer-cat-hue: 200;
  --primer-cat-sat: 85%;
  --primer-cat-light: 60%;        /* punchy */

  /* Bright and cheerful — fun's dark ink stays readable on them. */
  --primer-conf-sat: 90%;
  --primer-conf-light: 72%;
  --primer-course: #f2ad3c;

  /* Playful shapes + a rounded display font (loaded by js/theme.js while active). */
  --primer-radius: 1rem;
  --primer-font-display: "Fredoka", "Baloo 2", var(--primer-font-ui);
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--primer-bg);
  color: var(--primer-ink);
  font-family: var(--primer-font-body);
  font-size: 18px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

/* Ease the colour swap when the theme changes. */
body { transition: background-color 0.2s ease, color 0.2s ease; }

h1, h2 { font-family: var(--primer-font-display); }

main, .primer-shell {
  max-width: var(--primer-measure);
  margin: 0 auto;
  padding: 2.25rem 1rem 4.5rem;
}

a { color: var(--primer-accent); }

/*
 * Accessibility utilities (light DOM). Shadow-DOM controls carry their own focus rings (see
 * js/components/shared.js); these cover the light-DOM surfaces — links, the skip link, and any
 * focusable element render.js/pages emit — plus a global reduced-motion honour.
 */

/* Visually hidden but readable by assistive tech. Used for the skip link, off-screen headings,
   and live-region status text. (index.html carries a page-local copy for its pre-CSS paint.) */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* Skip-to-content: the first focusable element on every page. Off-screen until focused, then it
   slides into the top-left so a keyboard user can jump straight past the fixed chrome to <main>. */
.skip-link {
  position: fixed; top: 0.5rem; left: -999px; z-index: 2000;
  padding: 0.55rem 0.9rem; border-radius: var(--primer-radius);
  background: var(--primer-surface); color: var(--primer-ink);
  border: 1px solid var(--primer-accent); box-shadow: var(--primer-shadow-md);
  font-family: var(--primer-font-ui); text-decoration: none;
}
.skip-link:focus, .skip-link:focus-visible { left: 0.5rem; }

/* A consistent, theme-tinted focus ring for light-DOM interactives (links included). Only shows
   for keyboard/assistive focus (:focus-visible), so mouse clicks stay ring-free. The main landmark
   is programmatically focusable (tabindex=-1, set by the skip link target) but shouldn't show a
   ring when jumped to. */
a:focus-visible,
[tabindex]:focus-visible,
summary:focus-visible {
  outline: 3px solid var(--primer-accent);
  outline-offset: 2px;
  border-radius: 3px;
}
main:focus, main:focus-visible, [tabindex="-1"]:focus { outline: none; }

/* Honour "reduce motion": drop non-essential transitions/animations site-wide. Component shadow
   sheets do the same locally (shared.js and the menu/pathway/quiz components). */
@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;
  }
}

/* <primer-title> is a metadata carrier, not visible content: render.js reads its text for the
   <h1> + document.title. Hide it so the raw title never flashes before the shell is built. */
primer-title { display: none; }

/*
 * Cards (light DOM). <primer-card> adopts this class, and because cards are slotted
 * into <primer-concept> their styling must live in the document stylesheet — slotted
 * content is styled here, not by the components' shadow stylesheet (js/components/shared.js).
 * Surface/border/radius match the shadow `.card`; the vertical padding here is tighter.
 */
.card {
  display: block;
  background: var(--primer-surface);
  border: 1px solid var(--primer-border);
  border-radius: var(--primer-radius);
  padding: 1.15rem 1.6rem;
  margin: var(--primer-gap) 0;
  box-shadow: var(--primer-shadow-md);
}
/* Collapse the first/last child's outer margin so the 5px top/bottom padding is the
   actual gap (otherwise a leading <p>'s margin stacks on top of it). */
.card > :first-child { margin-top: 0; }
.card > :last-child { margin-bottom: 0; }

/* The standard "intro illustration" inside a card (subject + course intros, and the many image-led
   pages to come). It floats top-right at a third of the card's width with the prose flowing around
   it; on a narrow screen it stops floating and centres so it never shrinks to a thumbnail. Keep the
   shared look here — author with just <img class="card-image" src="…" alt="…"> (no inline styles). */
.card-image {
  float: right;
  width: 33%;
  height: auto;
  margin: 0.1rem 0 0.7rem 1.25rem;
  border-radius: var(--primer-radius);
}
@media (max-width: 32rem) {
  .card-image { float: none; display: block; width: min(62%, 240px); margin: 0.2rem auto 0.9rem; }
}

/* A wide code block scrolls horizontally inside its column instead of overflowing the page
   (same approach as a wide display equation, below). Inline <code> in prose still wraps. */
pre {
  overflow-x: auto;
  max-width: 100%;
}

/* <primer-quiz> renders its own golden card inside its shadow root, so it sits at the
   top level (not wrapped in a .card). Give the host the same vertical rhythm as a card
   so the gap before/after a quiz matches the gap between cards. */
primer-quiz { display: block; margin: var(--primer-gap) 0; }

/* Tables. Wrap a plain <table> in <primer-table> for consistent, themed presentation:
   centered cells, hairline borders, a shaded header row, and horizontal scroll on overflow.
   Light DOM, so styling lives here; author with <primer-table><table>…</table></primer-table>. */
primer-table { display: block; overflow-x: auto; margin: var(--primer-gap) 0; }
primer-table > table {
  border-collapse: collapse;
  margin: 0 auto; /* centre the table within the block */
  background: var(--primer-surface);
  color: var(--primer-ink);
  font-family: var(--primer-font-ui);
  font-size: 0.95rem;
}
primer-table th,
primer-table td {
  border: 1px solid var(--primer-border);
  padding: 0.45rem 0.85rem;
  text-align: center;
  vertical-align: middle;
}
primer-table thead th { background: var(--primer-control-bg); font-weight: 700; }
primer-table caption {
  caption-side: top;
  color: var(--primer-ink-soft);
  font-family: var(--primer-font-ui);
  font-size: 0.85rem;
  padding-bottom: 0.4rem;
  text-align: center;
}

/*
 * Tinted callouts that sit INSIDE a card: <primer-theorem> (a formal statement) and
 * <primer-vignette> (a collapsible aside). Both are light DOM (slotted), so their
 * styling lives here. They share an "eyebrow" header — a small uppercase label with an icon
 * before it — and the same accent-rule + tinted-panel shape, differing only in colour token and
 * (for the vignette) being collapsible. The eyebrow icons are masked SVGs tinted by currentColor,
 * so they follow the theme.
 */
.theorem {
  display: block;
  background: var(--primer-badge-bg);
  border-left: 4px solid var(--primer-accent);
  border-radius: var(--primer-radius);
  padding: 0.9rem 1.2rem;
  margin: var(--primer-gap) 0;
  box-shadow: var(--primer-shadow-sm);
}
.theorem > :first-child { margin-top: 0; }
.theorem > :last-child { margin-bottom: 0; }

/* Shared eyebrow (icon + label) for theorem and vignette headers. */
.eyebrow {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--primer-font-ui);
  font-size: 0.85rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-bottom: 0.55rem;
}
.eyebrow-icon {
  flex: none;
  width: 1.05em;
  height: 1.05em;
  background-color: currentColor;            /* the masked SVG is tinted to the eyebrow colour */
  -webkit-mask: var(--eyebrow-icon) center / contain no-repeat;
  mask: var(--eyebrow-icon) center / contain no-repeat;
}
.theorem .eyebrow { color: var(--primer-badge-ink); }
.theorem .eyebrow-icon { --eyebrow-icon: url("/images/gears.svg"); }

/* Vignette — a collapsible aside (a path off the main trail) inside a card. Starts collapsed; the
   <summary> is the eyebrow (footsteps icon + title), and expands to card-like body content. */
.vignette { display: block; }
.vignette-details {
  background: var(--primer-vignette-bg);
  border-left: 4px solid var(--primer-vignette-border);
  border-radius: var(--primer-radius);
  padding: 0.9rem 1.2rem;
  margin: var(--primer-gap) 0;
  box-shadow: var(--primer-shadow-sm);
}
.vignette-summary {
  cursor: pointer;
  list-style: none;                          /* hide the native disclosure triangle… */
  color: var(--primer-vignette-ink);
  margin-bottom: 0;
}
.vignette-summary::-webkit-details-marker { display: none; }  /* …including in WebKit */
.vignette-summary .eyebrow { margin-bottom: 0; }
.vignette-summary .eyebrow-icon { --eyebrow-icon: url("/images/foot-steps.svg"); }
/* A chevron affordance at the end of the row that flips when open. */
.vignette-summary .eyebrow::after {
  content: "▸";
  margin-left: auto;
  font-size: 0.9em;
  transition: transform 0.15s ease;
}
.vignette-details[open] .vignette-summary .eyebrow::after { transform: rotate(90deg); }
.vignette-details[open] .vignette-summary { margin-bottom: 0.6rem; }
.vignette-summary:focus-visible { outline: 2px solid var(--primer-ring); outline-offset: 2px; border-radius: 4px; }
.vignette-body > :first-child { margin-top: 0; }
.vignette-body > :last-child { margin-bottom: 0; }

/*
 * Concept cross-references (light DOM). <primer-ref> wraps its text in an
 * <a class="concept-ref"> pointing at another lesson; it sits inside slotted card prose,
 * so it is styled here. It inherits the accent link colour (the `a` rule above); the dotted
 * underline marks it as a *concept* link (a jump elsewhere in the tree) rather than a plain
 * external link, without shouting.
 */
a.concept-ref {
  text-decoration: underline;
  text-decoration-style: dotted;
  text-underline-offset: 0.15em;
  text-decoration-thickness: 1px;
}
a.concept-ref:hover { text-decoration-style: solid; }

/*
 * A small gold course crest shown to the LEFT of a <primer-ref> whose target is a course
 * (course: true) — the inline-link echo of the shield on course nodes (the graph) and course
 * page titles. Sized in em so it tracks the surrounding text; nudged onto the baseline.
 */
.concept-ref-crest {
  height: 0.95em;
  width: auto;
  vertical-align: -0.12em;
  margin-right: 0.25em;
}

/*
 * A `todo/…` placeholder reference — a concept the author plans to write but hasn't yet. Rendered
 * by <primer-ref> as a muted, NON-link span (no accent colour, no confidence dot) plus a small
 * "todo" chip, so it reads as planned rather than a working link.
 */
.concept-todo {
  color: var(--primer-ink-soft);
  text-decoration: underline dotted var(--primer-ink-soft);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.15em;
  cursor: default;
}
.concept-todo-tag {
  margin-left: 0.3em;
  font-family: var(--primer-font-ui);
  font-size: 0.62rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  vertical-align: 0.08em;
  color: var(--primer-ink-soft);
  background: var(--primer-badge-bg);
  border-radius: 999px;
  padding: 0.05rem 0.4rem;
}

/*
 * The ⧉ confidence icon that follows the reference words. Its colour is set inline by
 * <primer-ref> from the target concept's star rating (the same RED→YELLOW→GREEN ramp as the
 * pathway nodes); with no rating the inline colour is empty and this default ink shows
 * through. A monochrome glyph (not an emoji), so it takes the colour cleanly.
 */
.concept-ref-icon {
  margin-left: 0.3em;
  color: var(--primer-ink); /* unrated → default ink */
  font-size: 0.92em;
  vertical-align: baseline;
  text-decoration: none; /* it's a link, but show the glyph only — never an underline */
  cursor: pointer;
}

/*
 * Math (light DOM). <primer-math> renders KaTeX into itself; it's inline by default
 * (a custom element starts as display:inline), so inline math flows with the prose.
 * The `display` attribute makes it a centered block, like KaTeX's own display mode.
 *
 * A display equation can be wider than its column; rather than overflow the page, it
 * scrolls horizontally inside its own panel. `justify-content: safe center` keeps the
 * equation centered when it fits but falls back to start-aligned when it overflows, so
 * the left edge stays reachable (plain centering + overflow clips the left, unscrollable).
 */
primer-math[display] {
  display: flex;
  justify-content: safe center;
  overflow-x: auto;
  overflow-y: hidden;
  margin: 0.75rem 0;
  scrollbar-width: thin;
}
/* The wrapper owns the vertical spacing; pad the bottom so the scrollbar (when present)
   doesn't sit on the equation. */
primer-math[display] .katex-display {
  margin: 0;
  padding-bottom: 0.25rem;
}

/* Landing / index helpers (light DOM) */
.primer-tree-list { list-style: none; padding: 0; }
.primer-tree-list li { margin: 0.4rem 0; }

/*
 * MathLive virtual keyboard (the math input editor). MathLive renders it into the document
 * body — outside our component shadow roots — so it's styled here, globally. The keycap
 * variables go on `body` (per MathLive's docs); raising --keycap-max-width lets the keys
 * widen to fill the row instead of staying narrow + centred. The keyboard panel is then
 * capped at 640px and centred, so it's edge-to-edge on a phone but doesn't stretch on a
 * wide screen.
 */
body {
  /* Keys grow to fill the row (no narrow cap), comfortable touch height, and the keyboard's
     own horizontal + per-row padding zeroed so the keys reach the edges. */
  --keycap-max-width: 9999px;
  --keycap-gap: 3px;
  --keycap-height: 2.4rem;
  --keyboard-padding-horizontal: 0px;
  --keyboard-padding-top: 0px;          /* no grey gap above the top row */
  --keyboard-row-padding-left: 0px;
  --keyboard-row-padding-right: 0px;
}
/* The grey host (.ML__keyboard) + its full-width grey backdrop (.MLK__backdrop) stay full
   width. The plate is absolutely positioned, so padding on the backdrop is ignored — the 5px
   grey band above/below the keys is created by insetting the plate itself (top/bottom below). */
.ML__keyboard .MLK__backdrop {
  padding-top: 0;
  padding-bottom: 0;
}
/* editToolbar="none" empties the toolbar but leaves the element (min-height:32px) — that 32px
   is the grey gap above the keys. Hide it. */
.ML__keyboard .MLK__toolbar {
  display: none;
}
/* The plate is absolutely positioned (MathLive sets left + an explicit width, so plain auto
   margins can't centre it). Re-anchor it left:0/right:0 with auto width so max-width + auto
   margins centre it at 640px on a wide screen (full width on a phone), and drop its top offset. */
.ML__keyboard .MLK__plate {
  top: 0;
  left: 0;
  right: 0;
  width: auto;
  max-width: 640px;
  margin-inline: auto;
  /* The plate is transparent over the grey backdrop and is sized by its content; padding here
     grows it 5px at top + bottom, revealing the grey band above and below the keys. */
  padding-top: 5px;
  padding-bottom: 5px;
}
/* MathLive sizes each keycap to ~10% of the panel (min(--keycap-max-width, 10cqw)), assuming
   ~10 keys per row; our rows have only 5–6, so they'd leave a big side gap. The rows are
   flexboxes, so make every keycap flex-grow equally to fill the full row width. */
.ML__keyboard .MLK__row > * {
  flex: 1 1 0;
  max-width: none;
}
