/* ================================================================
   EXPLAINER PAGE + KNOWLEDGE GRAPH.
   Self-contained styles (hiw- prefix) so components.css stays lean.

   The filename is historical. The How It Works page this was written for
   was DELETED on 2026-08-22 and its .hiw-* type scale was inherited by
   "Why this app exists" (#page-learn-about-app), which is now the landing
   page. The file was not renamed because it also owns every .kg2-* rule
   for the Knowledge Graph tab, which several READMEs and concept-graph/
   modules name by this path; a rename would be a large diff for no
   behaviour change. Rules further down still carry .hiw-* names for the
   same reason — they are what the markup keys on.
   ================================================================ */

/* One measure for the explainer page, centred by `.container`'s own
   `margin: 0 auto` — 985px of text with the SAME gutter left and right at
   every width, rather than the 720px default. Two selectors stood here until
   2026-08-23, when "Why This App Exists" and "How to use it" became the one
   #page-learn-about-app; the measure was already identical, which is why the
   merged page needed no re-tuning. */
#page-learn-about-app .container {
  max-width: 985px;
}

/* --- Hero --- */
.hiw-hero {
  padding: 28px 0 8px;
}
/* The page title is CENTRED over the full 985px measure, so it reads as a
   masthead rather than as the first line of the prose underneath it. */
.hiw-hero h1 {
  font-size: 40px;
  line-height: 1.1;
  margin: 0 0 16px;
  letter-spacing: -0.02em;
  text-align: center;
}
/* No `max-width` of its own: the lead runs the full 985px measure the
   container sets. A narrower cap here left the text ragged on the right
   while the title above it was centred on the wider box — which is exactly
   the asymmetry this pass removes. */
.hiw-hero .hiw-lead {
  font-size: 20px;
  line-height: 1.6;
  color: var(--text);
  margin: 0 0 8px;
}
.hiw-hero .hiw-lead strong {
  color: var(--white);
}

/* Inline links (e.g. the Math Academy reference) */
#page-learn-about-app a {
  color: var(--accent-text);
  text-decoration: none;
  border-bottom: 1px solid color-mix(in srgb, var(--accent) 45%, transparent);
}
#page-learn-about-app a:hover {
  color: var(--white);
  border-bottom-color: var(--white);
}

/* --- The six-step loop (on "How to use it") and the sample map ---------
   The steps are a fixed 3 x 2, not the auto-fit grid components.css gives
   every other .steps-grid. They are ONE numbered sequence, and auto-fit
   reflows it by available width — at the default container that landed 4
   on the first row and 2 on the second, which reads as two groups of
   different sizes rather than steps 1-3 then 4-6. Below 900px it drops to
   two columns and then one; at every width the row break falls between
   whole steps.
   -------------------------------------------------------------------- */
#page-learn-about-app .steps-grid {
  grid-template-columns: repeat(3, 1fr);
}
@media (max-width: 900px) {
  #page-learn-about-app .steps-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
  #page-learn-about-app .steps-grid { grid-template-columns: 1fr; }
}

/* The cold-start notice, shared by both maps: the Knowledge Graph builds one
   into `.kg2-graph` and the landing page carries one in its markup. Top-LEFT
   because `.kg2-controls` owns the top-right, and so does Maximize here. */
.kg2-nodata {
  position: absolute;
  top: 12px;
  left: 14px;
  z-index: 6;
  max-width: 270px;
  padding: 7px 11px;
  font-size: 12px;
  line-height: 1.35;
  color: var(--muted);
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  border: 1px solid var(--border);
  border-radius: 8px;
  backdrop-filter: blur(4px);
}
.kg2-nodata[hidden] { display: none; }

/* --- Section scaffolding --- */
.hiw-section {
  margin: 56px 0;
}
.hiw-eyebrow {
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--accent-text);
  margin: 0 0 10px;
}
.hiw-section h2 {
  font-size: 26px;
  line-height: 1.2;
  margin: 0 0 14px;
  letter-spacing: -0.01em;
}
/* Body prose, one size across both pages. Like `.hiw-lead` it carries no
   `max-width`: the container owns the measure so every block of text starts
   and ends on the same two vertical edges. */
.hiw-section p {
  font-size: 20px;
  line-height: 1.7;
  color: var(--text);
  margin: 0 0 16px;
}
.hiw-section p .hiw-em {
  color: var(--white);
  font-weight: 600;
}

/* --- The "tier ladder" visual (worked → faded → full) --- */
.hiw-ladder {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
  margin: 24px 0 8px;
}
.hiw-rung {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 20px;
}
.hiw-rung-tag {
  display: inline-block;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--white);
  background: var(--card);
  border-radius: 999px;
  padding: 4px 12px;
  margin-bottom: 12px;
}
.hiw-rung:nth-child(3) .hiw-rung-tag { background: var(--accent); }
.hiw-rung h3 {
  font-size: 16px;
  margin: 0 0 6px;
  color: var(--white);
}
.hiw-rung p {
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--muted);
  margin: 0;
}
.hiw-rung-code {
  display: block;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 12px;
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 12px;
  margin: 12px 0 0;
  white-space: pre;
  overflow-x: auto;
}
.hiw-rung-arrow {
  text-align: center;
  color: var(--muted);
  font-size: 13px;
  letter-spacing: 0.04em;
  margin: 14px 0 0;
}

/* --- Two-column feature pairs --- */
.hiw-pairs {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  margin-top: 8px;
}
.hiw-pair {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 22px;
}
.hiw-pair h3 {
  font-size: 16px;
  margin: 0 0 8px;
  color: var(--white);
}
.hiw-pair p {
  font-size: 14px;
  line-height: 1.6;
  color: var(--muted);
  margin: 0;
}

/* --- Stat strip --- */
.hiw-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
  margin: 28px 0;
}
.hiw-stat {
  text-align: center;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 22px 16px;
}
.hiw-stat-num {
  display: block;
  font-size: 30px;
  font-weight: 700;
  color: var(--white);
  line-height: 1.1;
}
.hiw-stat-label {
  display: block;
  font-size: 13px;
  color: var(--muted);
  margin-top: 6px;
  line-height: 1.4;
}

/* --- Interactive concept graph --- */
.hiw-graph-wrap {
  position: relative;
  margin: 22px 0 8px;
  border: 1px solid var(--border);
  border-radius: 14px;
  background:
    radial-gradient(120% 120% at 50% 0%, rgb(var(--accent-rgb) / 0.06), transparent 60%),
    var(--surface);
  overflow: hidden;
}
#concept-graph-cy {
  width: 100%;
  height: 540px;
}
/* Dedicated Knowledge Graph tab: full-bleed. Kill the centered max-width and
   the heavy page side/bottom padding so the graph uses the whole width, and let
   the canvas fill the viewport below the sticky 56px topbar. */
#page-knowledge-graph.page { padding: 16px 16px 16px; }
.kg-container { max-width: none; margin: 0; }
.kg-tall #concept-graph-cy { height: calc(100vh - 210px); min-height: 520px; }

/* CTA button (How It Works → Knowledge Graph tab) */
.hiw-graph-cta { margin: 4px 0 8px; }
.hiw-graph-cta-btn {
  background: transparent;
  color: var(--accent-text);
  border: 1px solid color-mix(in srgb, var(--accent) 50%, transparent);
  border-radius: 999px;
  padding: 10px 20px;
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
  transition: background 120ms, color 120ms, border-color 120ms;
}
.hiw-graph-cta-btn:hover {
  background: var(--accent);
  color: var(--on-accent);
  border-color: var(--accent-text);
}
.hiw-graph-controls {
  position: absolute;
  top: 12px;
  right: 12px;
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 12px;
  color: var(--muted);
  z-index: 5;
}
.hiw-graph-controls label {
  display: flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
}
.hiw-graph-fit {
  background: var(--bg);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 6px;
  padding: 4px 10px;
  font-size: 12px;
  cursor: pointer;
}
.hiw-graph-fit:hover { border-color: var(--accent-text); color: var(--accent-text); }
.hiw-graph-info {
  position: absolute;
  left: 14px;
  bottom: 12px;
  max-width: 70%;
  font-size: 13px;
  color: var(--muted);
  z-index: 5;
  pointer-events: none;
}
.hiw-graph-info strong { color: var(--white); display: block; font-size: 14px; }
.cg-info-topic { font-size: 12px; }
.hiw-graph-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 16px;
  margin: 14px 2px 0;
  font-size: 12.5px;
  color: var(--muted);
}
/* On the full-bleed Knowledge Graph tab, pin the legend to the bottom of the
   viewport so it's always visible regardless of scroll (bottom-left holds the
   info text). Fixed positioning escapes the wrap's overflow; it only renders on
   this tab since the parent page is display:none otherwise. No panel/background
   behind it — just the coloured dots + labels floating over the canvas. */
.kg-tall .hiw-graph-legend {
  position: fixed;
  right: 18px;
  bottom: 14px;
  margin: 0;
  max-width: 60%;
  justify-content: flex-end;
  background: none;
  z-index: 40;
  pointer-events: none;
}
.cg-legend-item { display: inline-flex; align-items: center; gap: 7px; }
.cg-legend-dot { width: 10px; height: 10px; border-radius: 50%; display: inline-block; }
.hiw-graph-caption {
  font-size: 13px;
  color: var(--muted);
  margin: 12px 2px 0;
}
.hiw-graph-caption .cg-key-prereq { color: var(--accent-text); font-weight: 600; }

/* --- Closing note --- */
.hiw-note {
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: 12px;
  padding: 22px 24px;
  margin-top: 40px;
}
.hiw-note p {
  margin: 0;
  font-size: 20px;
  line-height: 1.7;
  color: var(--muted);
  max-width: none;
}
.hiw-note p strong { color: var(--white); }

@media (max-width: 720px) {
  .hiw-hero h1 { font-size: 30px; }
  .hiw-ladder,
  .hiw-pairs,
  .hiw-stats { grid-template-columns: 1fr; }
}

/* ============================================================
   Knowledge Graph tab v2 — lesson graph (concept-graph/lesson-graph.js)
   Two-pane: left = the bubble graph with its docked readout along the bottom;
   right = the lesson for whichever concept is selected, plus Practice ⤢ and
   (Colab edition only) the link into the notebook section that teaches it.

   The order is the DOM order — see index.html. Do not restore it with
   `row-reverse`: that would leave the lesson pane first for a keyboard and for
   the stacked narrow layout, where "read the lesson, then find the map under
   it" is backwards.
   ============================================================ */
.kg2 .kg2-wrap {
  display: flex;
  /* Was a flat `calc(100vh - 92px)`: the topbar's height plus 36px of page
     padding, with the bar's half of it written out by hand. The bar is 44px
     now (styles/layout.css `--dd-topbar-h`), and a literal here would have
     left the pane 12px short of the space it has. */
  height: calc(100vh - var(--dd-topbar-h) - 36px);
  min-height: 480px;
  border: 1px solid var(--border);
  border-radius: 14px;
  overflow: hidden;
  background: var(--surface);
}

/* right-hand lesson pane */
.kg2-info {
  flex: 0 0 38%;
  max-width: 580px;
  display: flex;
  flex-direction: column;
  border-left: 1px solid var(--border);
  background: var(--surface);
  min-width: 0;
}
.kg2-info-head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
  background: var(--panel-deep);
}
.kg2-info-head-meta { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.kg2-meta-topic {
  font-size: 12px; color: var(--muted); font-weight: 600;
  display: flex; align-items: center; gap: 6px;
}
.kg2-meta-lesson { font-size: 12.5px; color: var(--text); }
.kg2-chip-dot { width: 10px; height: 10px; border-radius: 50%; display: inline-block; border: 1px solid rgb(var(--well-rgb) / calc(.3 * var(--well-k))); }

.kg2-max {
  flex: 0 0 auto;
  background: var(--accent);
  color: var(--on-accent);
  border: none;
  border-radius: 999px;
  padding: 8px 16px;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
  transition: filter 120ms, transform 120ms;
}
.kg2-max:hover { filter: brightness(1.1); transform: translateY(-1px); }

/* The way into the notebook, and the way back to it. Ghost rather than filled:
   selecting a concept has ALREADY steered the tab beside the panel, so this is
   the fallback route (a plain browser tab has no panel to steer) and the
   copyable link — not the primary action on the pane. */
.kg2-colab-link {
  flex: 0 0 auto;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--text);
  cursor: pointer;
  font-size: 12.5px;
  font-weight: 600;
  padding: 7px 13px;
  text-decoration: none;
  white-space: nowrap;
  transition: border-color 120ms, color 120ms;
}
.kg2-colab-link:hover { border-color: var(--accent-text); color: var(--accent-text); }
/* A concept the registry has and the notebooks do not. Not a link, and not
   silence either — silence is what the normal deploy looks like. */
.kg2-colab-link.is-missing {
  color: var(--muted);
  cursor: default;
  font-weight: 500;
}
.kg2-colab-link.is-missing:hover { border-color: var(--border); color: var(--muted); }

.kg2-info-body { flex: 1 1 auto; overflow-y: auto; padding: 20px 22px; }
.kg2-placeholder { color: var(--muted); font-size: 14px; line-height: 1.6; }
.kg2-placeholder strong { color: var(--text); }
.kg2-placeholder-more { display: block; margin-top: 12px; }

/* Nothing selected — so the header bar above holds nothing: no concept name,
   no Practice ⤢, no Colab link. `setPlaceholder` empties and hides all three,
   which left a padded, bordered, empty strip sitting over the prompt. */
.kg2-info:has(.kg2-placeholder) .kg2-info-head { display: none; }
.kg2-title { font-size: 21px; line-height: 1.3; margin-bottom: 12px; color: var(--text); }
.kg2-concept, .kg2-worked, .kg2-watch { font-size: 14px; line-height: 1.65; color: var(--text); }
.kg2-info-body p { margin: 10px 0; }
.kg2-info-body h4 { margin: 16px 0 6px; font-size: 15px; color: var(--text); }
.kg2-info-body ul, .kg2-info-body ol { margin: 8px 0 8px 22px; }
.kg2-info-body li { margin: 4px 0; }
.kg2-info-body code {
  background: var(--bg); border: 1px solid var(--border); border-radius: 4px;
  padding: 1px 5px; font-family: "SFMono-Regular", Consolas, monospace; font-size: 12.5px;
}
.kg2-info-body pre {
  background: var(--bg); border: 1px solid var(--border); border-radius: 8px;
  padding: 12px 14px; overflow-x: auto; margin: 12px 0;
}
.kg2-info-body pre code { background: none; border: none; padding: 0; font-size: 12.5px; line-height: 1.5; }
.kg2-worked h3, .kg2-watch h3 {
  font-size: 12px; text-transform: uppercase; letter-spacing: .7px; color: var(--muted);
  margin: 22px 0 8px; padding-bottom: 5px; border-bottom: 1px solid var(--border);
}
.kg2-watch { background: color-mix(in srgb, var(--accent) 8%, transparent); border-radius: 10px; padding: 2px 14px 12px; margin-top: 18px; }
.kg2-watch h3 { color: var(--accent-text); border-color: color-mix(in srgb, var(--accent) 30%, transparent); }

/* One block per lesson segment — the same units the practice screen pages
   through, so the dock and the lesson agree on where one concept ends. */
.kg2-seg + .kg2-seg { border-top: 1px solid var(--border); margin-top: 26px; padding-top: 20px; }
.kg2-seg-num {
  font-size: 11px; text-transform: uppercase; letter-spacing: .7px;
  color: var(--muted); font-weight: 700; margin-bottom: 4px;
}
.kg2-seg-title { font-size: 16px; line-height: 1.35; color: var(--text); margin: 0 0 10px; }

/* prereq / unlock nav */
.kg2-nav { display: flex; gap: 18px; margin-top: 26px; padding-top: 16px; border-top: 1px solid var(--border); flex-wrap: wrap; }
.kg2-nav-col { flex: 1 1 200px; min-width: 0; }
.kg2-nav-col h4 { font-size: 11px; text-transform: uppercase; letter-spacing: .7px; color: var(--muted); margin: 0 0 8px; }
.kg2-nav-empty { font-size: 12.5px; color: var(--muted); font-style: italic; }
.kg2-chip {
  display: flex; align-items: center; gap: 7px; width: 100%; text-align: left;
  background: var(--bg); border: 1px solid var(--border); border-radius: 7px;
  color: var(--text); font: inherit; font-size: 12.5px; padding: 7px 10px; margin-bottom: 5px;
  cursor: pointer; line-height: 1.3; transition: border-color 120ms, background 120ms;
}
.kg2-chip:hover { border-color: var(--accent-text); background: color-mix(in srgb, var(--accent) 10%, var(--bg)); }

/* left graph pane — the canvas is inset by the docked readout's height so the
   bottom panel never covers bubbles (see .kg2-dock). */
.kg2-graph { flex: 1 1 auto; position: relative; min-width: 0; --kg2-dock-h: 144px; }
/* Nothing has been in the dock yet, so it is one line of prompt. `has-dock` is
   added by lesson-graph.js the first time a concept is shown there and never
   removed — see showDock. */
.kg2-graph:not(.has-dock) { --kg2-dock-h: 44px; }
#kg-cy { position: absolute; inset: 0 0 var(--kg2-dock-h, 0px) 0; }
.kg2-controls { position: absolute; top: 12px; right: 14px; z-index: 5; display: flex; gap: 8px; }
.kg2-fit {
  background: color-mix(in srgb, var(--surface) 88%, transparent); color: var(--text);
  border: 1px solid var(--border); border-radius: 6px; padding: 5px 12px; font-size: 12px; cursor: pointer;
  backdrop-filter: blur(4px);
}
.kg2-fit:hover { border-color: var(--accent-text); color: var(--accent-text); }
.kg2-legend {
  position: absolute; bottom: calc(var(--kg2-dock-h, 0px) + 12px); left: 14px; z-index: 5;
  display: flex; flex-wrap: wrap; gap: 5px 14px;
  max-width: 70%; background: color-mix(in srgb, var(--surface) 88%, transparent);
  border: 1px solid var(--border); border-radius: 8px; padding: 8px 12px; font-size: 11.5px; backdrop-filter: blur(4px);
}
.kg2-li { display: flex; align-items: center; gap: 6px; color: var(--muted); }
.kg2-li-dot { width: 11px; height: 11px; border-radius: 50%; border: 1px solid rgb(var(--well-rgb) / calc(.25 * var(--well-k))); }
/* Chapter / Category legend. The two modes are the same list at two grains,
   so the fine families are NESTED under the chapter they belong to rather than
   listed flat: a flat list of fourteen chips is a lookup table, a nested one
   says which notebook each subject sits in, which is half the thing the colour
   is encoding. The head takes a whole row (flex-basis 100%) so each chapter's
   families wrap under it and not beside the previous chapter's.
   Capped and scrollable because Category mode is 4 heads + 14 families: at
   full height it would cover the bottom third of the canvas it is explaining. */
.kg2-legend-grouped { max-width: 78%; max-height: 44%; overflow: hidden auto; row-gap: 2px; }
.kg2-legend-grouped .kg2-li-head { flex: 0 0 100%; margin-top: 5px; color: var(--text); font-weight: 700; }
.kg2-legend-grouped .kg2-li-head:first-child { margin-top: 0; }
.kg2-legend-grouped .kg2-li-sub { margin-left: 15px; }
/* Sections mode with no exercise map: every concept falls to prep, which reads
   as a finished answer rather than a missing file. Flag it in the legend. */
.kg2-legend-grouped .kg2-li-warn { flex: 0 0 100%; color: var(--warn); }
/* Category mode folds, because its full list is tall enough to cover the
   prerequisite floor a BT layout puts in this exact corner. <details> holds
   the state, so a recolour cannot reset it. */
.kg2-legend-fold { flex: 0 0 100%; }
.kg2-legend-fold > summary { cursor: pointer; color: var(--muted); font-weight: 600; list-style-position: inside; }
.kg2-legend-fold > summary:hover { color: var(--text); }
.kg2-legend-fold[open] > summary { margin-bottom: 5px; }
.kg2-legend-fold-body { display: flex; flex-wrap: wrap; gap: 2px 14px; }
/* Matches the washed-out, dashed bubbles used for projected (unmeasured) concepts. */
.kg2-li-projected { /* graph-legend */ background: rgba(138, 101, 151, .42); border-style: dashed; border-color: rgb(var(--tint-rgb) / calc(.55 * var(--tint-k))); }
.kg2-status { position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); color: var(--muted); font-size: 14px; }

/* ---- Colab edition: no lesson pane -------------------------------------
   The lesson lives in the notebook on this deploy — that is the fork. A pane
   rendering a second copy of it beside the map is two sources of truth for
   what a concept teaches, the same problem the practice rail solved by
   dropping its prompt and worked example, and here it also spent 38% of the
   width on something the learner is being sent to Colab to read. Selecting a
   bubble routes the tab; the dock along the bottom names the concept and
   carries its learner model.

   `#kg-colab-link` and `#kg-maximize` live inside this aside's header, so
   `kc-colab-route.js` moves them into `.kg2-controls` before it disappears —
   see that file. Inert on the normal deploy, where the pane is the point. */
html.dd-colab-edition .kg2-info { display: none; }
html.dd-colab-edition .kg2-controls #kg-colab-link,
html.dd-colab-edition .kg2-controls .kg2-max {
  border-radius: 6px;
  font-size: 12px;
  font-weight: 600;
  padding: 5px 12px;
}

@media (max-width: 820px) {
  .kg2 .kg2-wrap { flex-direction: column; height: auto; }
  /* Stacked, the graph is on top and the lesson under it — same order as the
     DOM, so the divider moves to the lesson's TOP edge. */
  .kg2-info { flex: none; max-width: none; border-left: none; border-top: 1px solid var(--border); max-height: 46vh; }
  /* With nothing selected this pane is one sentence, and in a side panel it was
     eating a fifth of the screen below the graph to say so. The second
     sentence explains Practice ⤢ and the chain highlight — worth having on a
     wide screen, not worth a paragraph of empty pane on a narrow one. */
  .kg2-info:has(.kg2-placeholder) .kg2-info-body { padding: 12px 16px; }
  .kg2-placeholder-more { display: none; }
  /* Colab edition: the pane is gone, so the wrap has one child. Give it a real
     height and let the graph fill it, instead of pinning the graph to 74vh and
     leaving dead space under it. */
  html.dd-colab-edition .kg2 .kg2-wrap { height: calc(100vh - var(--dd-topbar-h) - 36px); }
  html.dd-colab-edition .kg2-graph { height: auto; }
  /* Narrow: the dock's three columns stack, so it needs more room. */
  .kg2-graph { height: 74vh; --kg2-dock-h: 220px; }
  .kg2-dock { flex-direction: column; gap: 10px; overflow-y: auto; }
  .kg2-dock-col + .kg2-dock-col { border-left: 0; padding-left: 0; border-top: 1px solid var(--border); padding-top: 10px; }
  .kg2-dock-mastery { max-width: none; }
}

/* ============================================================
   Knowledge Graph — maximize overlay (own focused practice page)
   ============================================================ */
/* Inside the embedded iframe (?embed=1): hide app chrome so no tabs show and
   only the practice page is visible — it reads as its own separate page.

   🔴 THE TOPBAR ITSELF IS NOT HIDDEN, AND IT WAS UNTIL 2026-09-01. It carried
   `display: none !important` in the list below, which took the whole bar out —
   including the CONCEPT PILL (#dd-concept, concept-pill.js), the one readout on
   the practice screen that says how far into this concept the learner is. So
   the Knowledge Graph's own Practice ⤢ overlay — the surface whose entire
   subject IS one concept — was the single place in the app where that reading
   could not be seen, and it disappeared at the exact moment the learner started
   working the problem. Seth, 2026-09-01: "it keeps the progress bar displaying
   what your estimated competency for the problem is at the top rather than
   … get rid of the competency bar at the top".

   What actually had to go is the NAVIGATION — the tab strip and the two side
   cells (level pill, account control) — because the overlay has its own bar
   above this one with the concept's name and Minimize in it. The bar is a
   3-column grid whose cells are placed by explicit `grid-column`
   (styles/layout.css), so hiding the outer two leaves the middle one centred
   on the viewport rather than reflowing anything. The notch goes with them: it
   is the session clock, and this flow deliberately runs with no session or
   quota (practice/lessons.js). */
.kg-embed .guest-banner,
.kg-embed .tp-banner { display: none !important; }
.kg-embed .topbar .tabs,
.kg-embed .topbar-side,
.kg-embed .practice-notch { display: none !important; }
.kg-embed main.page:not(#page-practice) { display: none !important; }
/* 🔴 `display: flex`, NOT `block`. This rule exists to beat `.hidden` so the
   practice page is on screen in the embed — but `#page-practice` is a FLEX
   COLUMN with a fixed height (`calc(100vh - var(--dd-topbar-h))`) and
   `overflow: hidden` (styles/practice/layout.css). Forcing it to `block` threw
   that away: `.practice-container` stopped being a flex item, took its
   content's full natural height instead of the page's, and `.practice-left`
   grew with it — so the panel's own `overflow-y: auto` never engaged and the
   lesson was simply CUT OFF at the bottom of the iframe with nothing to
   scroll. A long lesson (einops, 2119px in a 1037px page) lost half its text.
   Keep the display value the page's own rule uses; only the visibility is
   this rule's business.

   🔴 THE HEIGHT SUBTRACTS THE TOPBAR AGAIN. It was a flat `100vh` for as
   long as the embed hid `.topbar` entirely — reserving 44px for a bar that was
   not on the page would have left a dead band at the bottom of the iframe. The
   bar is back (stripped to the concept pill, above), so the page has to fit
   under it or the last 44px of the practice panel is pushed out of the frame
   and the panel's own `overflow-y` never reaches it. */
.kg-embed #page-practice { display: flex !important; height: calc(100vh - var(--dd-topbar-h)); }
/* Single-concept view: the adaptive-queue framing (what Practice is, where to
   start across all topics) is about a different flow and reads as noise here.
   The concept pill in the topbar is the header for this page. */
.kg-embed #self-report-row { display: none !important; }

/* Parent overlay: full-screen, above everything, with a slim Minimize bar. */
.kg-maxi { position: fixed; inset: 0; z-index: 9999; display: flex; flex-direction: column; background: var(--bg); }
.kg-maxi.hidden { display: none; }
.kg-maxi-bar {
  flex: 0 0 auto; display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 8px 16px; background: var(--surface); border-bottom: 1px solid var(--border);
}
.kg-maxi-title { font-size: 14px; font-weight: 700; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kg-maxi-min {
  flex: 0 0 auto; background: var(--accent); color: var(--on-accent); border: none; border-radius: 999px;
  padding: 7px 16px; font-size: 13px; font-weight: 700; cursor: pointer; transition: filter 120ms;
}
.kg-maxi-min:hover { filter: brightness(1.1); }
.kg-maxi-frame { flex: 1 1 auto; width: 100%; border: 0; background: var(--bg); }
body.kg-maxi-open { overflow: hidden; }

/* ============================================================
   Knowledge Graph — mastery colouring: view toggle, hover popup, legend
   ============================================================ */
/* Mastery ↔ Lessons segmented toggle (in .kg2-controls) */
/* The Mastery ↔ Lessons switch, by ID and not by class. It used to carry
   `.kg2-seg` — which is ALSO the class on every lesson segment block in the
   pane opposite (see `.kg2-seg + .kg2-seg` above), so `display: inline-flex`
   landed on those too and laid each concept out beside its own worked example
   in two unreadable columns. One name, two unrelated things, and the collision
   only showed once the lesson pane was narrow enough to notice. */
#kg-colormode { display: inline-flex; border: 1px solid var(--border); border-radius: 7px; overflow: hidden; background: color-mix(in srgb, var(--surface) 88%, transparent); backdrop-filter: blur(4px); }
/* 5px 9px, not 5px 11px: the switch carries FOUR readings now (Mastery /
   Sections / Categories / Math-code) and at the old padding the strip reached
   the Fit button on a narrow pane. */
#kg-colormode button { background: transparent; color: var(--muted); border: 0; padding: 5px 9px; font: inherit; font-size: 12px; cursor: pointer; white-space: nowrap; }
#kg-colormode button + button { border-left: 1px solid var(--border); }
#kg-colormode button.active { background: var(--accent); color: var(--on-accent); font-weight: 700; }
#kg-colormode button:not(.active):hover { color: var(--text); }

/* Mastery legend: gray "no estimate" chip + red→blue gradient scale */
.kg2-legend-mastery .kg2-li-scale { display: inline-flex; align-items: center; gap: 6px; }
.kg2-scale-bar { display: inline-block; width: 74px; height: 10px; border-radius: 5px;
  /* NOT tokens: this legend has to match the node colours
     concept-graph/lesson-graph.js paints on the cytoscape canvas, and those
     are a fixed data scale, not theme chrome. Re-theming the legend alone
     would make it lie about the graph beside it. Same for
     .kg2-li-projected above. */
  /* graph-legend */
  background: linear-gradient(90deg, #d64848 0%, #8a6597 50%, #3b82f6 100%); border: 1px solid rgb(var(--well-rgb) / calc(.25 * var(--well-k))); }

/* Learner-model readout, docked across the bottom of the graph pane.
   Fixed height (--kg2-dock-h, which also insets #kg-cy) so hovering bubble to
   bubble never reflows the canvas under the cursor. */
.kg2-dock {
  position: absolute; left: 0; right: 0; bottom: 0; height: var(--kg2-dock-h, 132px); z-index: 20;
  display: flex; align-items: stretch; gap: 22px;
  /* Scrolls rather than clips: in a narrow pane the columns wrap taller than the
     fixed height, and a cut-off confidence line would misread as missing data. */
  padding: 12px 18px; box-sizing: border-box; overflow: hidden auto;
  background: var(--panel);
  border-top: 1px solid var(--border);
  font-size: 12.5px; color: var(--text);
}
/* Showing the selected (gold-highlighted) node rather than a hover preview. */
.kg2-dock.is-pinned { border-top-color: color-mix(in srgb, var(--gold) 55%, var(--border)); }
.kg2-dock-empty { margin: auto; color: var(--muted); font-size: 13px; }
.kg2-dock-col { display: flex; flex-direction: column; justify-content: center; min-width: 0; }
.kg2-dock-col + .kg2-dock-col { border-left: 1px solid var(--border); padding-left: 22px; }
.kg2-dock-id { flex: 1 1 30%; }
.kg2-dock-mastery { flex: 1 1 34%; max-width: 420px; }
.kg2-dock-stats { flex: 1 1 26%; justify-content: center; }
.kg2-dock-title { font-weight: 700; font-size: 15px; line-height: 1.3; margin-bottom: 4px; }
.kg2-dock-meta { font-size: 11.5px; color: var(--muted); }
.kg2-dock-evidence { margin-top: 7px; font-size: 11px; color: var(--muted); line-height: 1.35; }
.kg2-dock-headline { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin-bottom: 7px; }
.kg2-dock-headline strong { font-size: 22px; line-height: 1; font-variant-numeric: tabular-nums; }
.kg2-dock-band { font-size: 11.5px; color: var(--muted); }
/* mastery bar: fill = P(known), shaded band = confidence interval, ticks = gates */
.kg2-dock-track {
  position: relative; height: 10px; border-radius: 5px; overflow: hidden;
  background: color-mix(in srgb, var(--text) 14%, transparent);
}
.kg2-dock-fill { height: 100%; border-radius: 5px; }
.kg2-dock-ci {
  position: absolute; top: 0; bottom: 0;
  background: repeating-linear-gradient(135deg,
    rgb(var(--tint-rgb) / calc(.34 * var(--tint-k))) 0 3px, rgb(var(--tint-rgb) / calc(.10 * var(--tint-k))) 3px 6px);
  border-left: 1px solid rgb(var(--tint-rgb) / calc(.7 * var(--tint-k))); border-right: 1px solid rgb(var(--tint-rgb) / calc(.7 * var(--tint-k)));
}
/* Inferred band — no graded attempt has landed on this concept, so the interval
   is nearly the whole scale. Drawn flatter and unbordered so a full-width stripe
   reads as "we don't know" rather than as a very wide measurement. */
.kg2-dock-ci.is-inferred {
  background: repeating-linear-gradient(135deg,
    rgb(var(--tint-rgb) / calc(.16 * var(--tint-k))) 0 2px, rgb(var(--tint-rgb) / calc(.04 * var(--tint-k))) 2px 7px);
  border-left: 0; border-right: 0;
}
.kg2-dock-gate { position: absolute; top: 0; bottom: 0; width: 2px; background: color-mix(in srgb, var(--text) 60%, transparent); }
.kg2-dock-gate.is-mastery { background: var(--gold); }
.kg2-dock-scale { display: flex; justify-content: space-between; font-size: 10px; color: var(--muted); margin-top: 3px; }
.kg2-dock-ci-label { font-size: 11.5px; color: var(--text); margin-top: 6px; line-height: 1.35; }
.kg2-dock-dim { color: var(--muted); }
.kg2-dock-row { display: flex; justify-content: space-between; gap: 14px; padding: 2px 0; color: var(--muted); }
.kg2-dock-row span + span { color: var(--text); font-variant-numeric: tabular-nums; }

/* Mastery handoff toast — shown on the graph after the embedded practice page
   reports a concept crossed the 0.95 mastery gate. */
.kg2-mastered-toast {
  position: fixed; right: 22px; bottom: 22px; z-index: 60; max-width: 330px;
  background: var(--panel);
  border: 1px solid rgb(var(--info-rgb) / 0.5); border-radius: 12px;
  padding: 14px 16px; box-shadow: 0 12px 34px rgb(var(--well-rgb) / calc(.5 * var(--well-k)));
  animation: kg2-toast-in .28s ease-out;
}
@keyframes kg2-toast-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
.kg2-mastered-title { font-weight: 700; font-size: 14px; margin-bottom: 5px; color: var(--info); }
.kg2-mastered-body { font-size: 12.5px; line-height: 1.5; color: var(--muted); margin-bottom: 11px; }
.kg2-mastered-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.kg2-mastered-actions button { font: inherit; font-size: 12.5px; border-radius: 7px; padding: 6px 11px; cursor: pointer; border: 1px solid var(--border); }
.kg2-mastered-go { background: var(--accent); color: var(--on-accent); border-color: transparent; font-weight: 700; }
.kg2-mastered-go:hover { filter: brightness(1.1); }
.kg2-mastered-stay { background: transparent; color: var(--muted); }
.kg2-mastered-stay:hover { color: var(--text); }

/* ---- Right pane tabs: Lesson | Metadata | Settings (lesson-graph.js builds
   the strip; 2026-09-06). Same control vocabulary as #kg-colormode. Hidden
   with the head when nothing is selected. ---- */
.kg2-tabs {
  flex: 0 0 auto;
  display: flex;
  gap: 0;
  padding: 0 16px;
  border-bottom: 1px solid var(--border);
  background: var(--panel-deep);
}
.kg2-tabs button {
  background: transparent; border: 0; border-bottom: 2px solid transparent;
  color: var(--muted); font: inherit; font-size: 12.5px; font-weight: 600;
  padding: 8px 12px; cursor: pointer; margin-bottom: -1px;
}
.kg2-tabs button:hover { color: var(--text); }
.kg2-tabs button[aria-selected="true"] { color: var(--accent-text); border-bottom-color: var(--accent); }
.kg2-info:has(.kg2-placeholder) .kg2-tabs { display: none; }

/* Metadata tab */
.kg2-md-grid { display: grid; grid-template-columns: max-content 1fr; gap: 6px 14px; font-size: 13px; align-items: baseline; }
.kg2-md-k { color: var(--muted); font-size: 11px; text-transform: uppercase; letter-spacing: .6px; }
.kg2-md-v { color: var(--text); min-width: 0; overflow-wrap: anywhere; }
.kg2-md-dim { color: var(--muted); font-size: 12px; }
.kg2-md-notes { margin-top: 20px; padding-top: 14px; border-top: 1px solid var(--border); font-size: 14px; line-height: 1.6; }
.kg2-md-foot { margin-top: 20px; color: var(--muted); font-size: 12px; }

/* Settings tab */
.kg2-set { display: flex; flex-direction: column; gap: 18px; font-size: 14px; }
.kg2-set-guest { color: var(--muted); font-size: 14px; line-height: 1.6; }
.kg2-set-guest strong { color: var(--text); }
.kg2-set-row { display: block; }
.kg2-set-row small { display: block; color: var(--muted); font-size: 12px; line-height: 1.5; margin-top: 4px; }
.kg2-set-toggle { display: flex; gap: 10px; align-items: flex-start; cursor: pointer; }
.kg2-set-toggle input { margin-top: 4px; width: 16px; height: 16px; accent-color: var(--accent); }
.kg2-set-weight { padding: 14px; border: 1px solid var(--border); border-radius: 10px; background: var(--bg); }
.kg2-set-weight.is-off { opacity: .45; pointer-events: none; }
.kg2-set-head { display: flex; justify-content: space-between; gap: 10px; align-items: baseline; flex-wrap: wrap; }
.kg2-set-head output { color: var(--muted); font-size: 12.5px; }
.kg2-set-weight input[type="range"] { width: 100%; margin: 12px 0 8px; accent-color: var(--accent); }
.kg2-set-presets { display: inline-flex; border: 1px solid var(--border); border-radius: 7px; overflow: hidden; }
.kg2-set-presets button { background: transparent; color: var(--muted); border: 0; padding: 4px 10px; font: inherit; font-size: 12px; cursor: pointer; }
.kg2-set-presets button + button { border-left: 1px solid var(--border); }
.kg2-set-presets button.active { background: var(--accent); color: var(--on-accent); }
.kg2-set-status { color: var(--muted); font-size: 12px; min-height: 1.2em; }
.kg2-li-off { /* graph-legend */ background: rgba(120, 120, 120, .22); border-style: solid; }
.kg2-li-edge { /* graph-legend */ display: inline-block; width: 22px; height: 0; margin-right: 6px; vertical-align: middle; border-top: 3px solid #e3212c; }
.kg2-li-edge-pre { /* graph-legend */ border-top: 1px dashed #e3212c; opacity: .6; }
