/* ═══════════════════════════════════════════════════════════════════════════
   ki_app.css — the institutional system applied to EXISTING markup (Session 58)

   ki.css is the system; this sheet points the legacy token layer at it and
   re-dresses the shared shell (the signed-in rail, the phone top bar and the
   bottom bar). Page-group sheets follow it: ki_parent.css, ki_child.css,
   ki_mc.css. Loaded only where ki.css is — never on a chalkboard lesson board.

   ⚑ THE TYPE MOVES BY TOKEN, NOT BY 317 EDITS. `var(--font-geist)` is read by
   317 declarations across the legacy sheets; repointing the token on `body.ki`
   moves all of them to Source Sans at once. The landing (`.hro--home`) is
   excluded — the brief keeps its Geist hero — and so the repoint is keyed on
   `:not(:has(.hro--home))`.
   ═══════════════════════════════════════════════════════════════════════════ */

body.ki:not(:has(.hro--home)) {
  --font-geist: var(--ki-sans);
  --font-ui: var(--ki-sans);
  --font-display: var(--ki-serif);
  --ls-head: 0;
}

/* The page grounds: white for public pages, ivory paper for the portal.
   ⚑ SESSION 59: every ki page now carries a blue tier class (ki.css section 13), and
   this Session 58 rule — at (0,3,1) — was out-ranking the tiers: it painted the portal
   #0D3256 instead of #0B2E4F, the public pages #1F2536 instead of #1A1F2E, and forced
   --surface back to white. Kept only for a page with NO tier, which none has today. */
body.ki.theme-parent:not(:has(.lnd)):not(.ki-t-public):not(.ki-t-portal):not(.ki-t-practice),
body.ki.theme-kid:not(.ki-t-public):not(.ki-t-portal):not(.ki-t-practice) {
  --k-bg: var(--ki-ivory);
  --bg: var(--ki-ivory);
  --bg-soft: var(--ki-stone);
  --surface: #FFFFFF;
  --line: var(--ki-rule);
  --line-soft: #E4E7EA;
  background: var(--ki-ivory);
  background-image: none;
}
body.ki main { background-image: none; }

/* ── THE SIGNED-IN RAIL (≥1024px) — a navy portal sidebar ─────────────────── */
@media (min-width: 1024px) {
  body.ki:has(> .knav:not(.knav--test):not(.knav--public)) > .knav {
    background: var(--ki-navy);
    border-right: 0;
    color: #fff;
  }
  body.ki:has(> .knav:not(.knav--test):not(.knav--public)) .knav-brand {
    color: #fff; font-family: var(--ki-serif); font-weight: 700; font-size: 19px;
  }
  body.ki:has(> .knav:not(.knav--test):not(.knav--public)) .knav-brand .brand-mark {
    background: var(--ki-brand, #005F82); color: #fff; border-radius: 0; box-shadow: inset 0 0 0 1px rgba(255,255,255,.35);
  }
  body.ki:has(> .knav:not(.knav--test):not(.knav--public)) .knav-link,
  body.ki:has(> .knav:not(.knav--test):not(.knav--public)) .knav-link--quiet,
  body.ki:has(> .knav:not(.knav--test):not(.knav--public)) .knav-soon {
    color: var(--ki-on-navy-2); background: transparent; border-radius: 0;
    font: 600 15px/1.3 var(--ki-sans); border: 0; box-shadow: none;
  }
  body.ki:has(> .knav:not(.knav--test):not(.knav--public)) .knav-link:hover {
    color: #fff; background: rgba(255,255,255,.07);
  }
  body.ki:has(> .knav:not(.knav--test):not(.knav--public)) .knav-link.is-active {
    color: #fff; background: rgba(255,255,255,.10); box-shadow: inset 3px 0 0 #E9C46A;
  }
  body.ki:has(> .knav:not(.knav--test):not(.knav--public)) .knav-link__ico,
  body.ki:has(> .knav:not(.knav--test):not(.knav--public)) .knav-link__ico svg { color: inherit; stroke: currentColor; }
  body.ki:has(> .knav:not(.knav--test):not(.knav--public)) .knav-group,
  body.ki:has(> .knav:not(.knav--test):not(.knav--public)) .knav-group--weekly,
  body.ki:has(> .knav:not(.knav--test):not(.knav--public)) .knav-more {
    border-top-color: rgba(255,255,255,.16);
  }
  body.ki:has(> .knav:not(.knav--test):not(.knav--public)) .knav-who {
    background: rgba(255,255,255,.06); color: #fff; border: 1px solid rgba(255,255,255,.22); border-radius: 0;
  }
  body.ki:has(> .knav:not(.knav--test):not(.knav--public)) .knav-more__panel a,
  body.ki:has(> .knav:not(.knav--test):not(.knav--public)) .knav-more__panel button { color: var(--ki-on-navy-2); }
  body.ki:has(> .knav:not(.knav--test):not(.knav--public)) .knav-link--cta,
  body.ki:has(> .knav:not(.knav--test):not(.knav--public)) .knav-done {
    background: #fff; color: var(--ki-navy); border: 2px solid #fff; border-radius: var(--ki-r);
    font-weight: 700; box-shadow: none;
  }
  body.ki:has(> .knav:not(.knav--test):not(.knav--public)) .knav-link--cta:hover { background: #E3F1F7; border-color: #E3F1F7; color: var(--ki-navy); }  /* S61: was the 12% light-blue TINT over the navy rail = navy ink on near-navy, 1.3:1 */
}

/* ── PHONE / TABLET TOP BAR (<1024px) and the bottom bar ─────────────────── */
body.ki .knav:not(.knav--public) {
  background: #fff; border-bottom: 1px solid var(--ki-rule); box-shadow: none; backdrop-filter: none;
}
body.ki .knav .knav-brand { font-family: var(--ki-serif); font-weight: 700; color: var(--ki-ink); }
body.ki .brand-mark { border-radius: 0; background: var(--ki-blue); color: #fff; font-family: var(--ki-serif); font-style: normal; box-shadow: none; }
body.ki .knav-burger { border-radius: 0; }
@media (max-width: 1023px) {
  body.ki .knav .knav-link.is-active { box-shadow: inset 4px 0 0 var(--ki-blue); border-radius: 0; }
}
body.ki .knav-bottom { background: #fff; border-top: 1px solid var(--ki-rule-2); box-shadow: none; }
body.ki .knav-bottom__item.is-active,
body.ki .knav-bottom__item[aria-current="page"] { color: var(--ki-blue); box-shadow: inset 0 3px 0 var(--ki-blue); }

/* ── SHARED LEGACY PRIMITIVES — buttons, cards, inputs, headings ──────────── */
body.ki .btn, body.ki .btn-primary, body.ki .btn-xl {
  border-radius: var(--ki-r); box-shadow: none; font-family: var(--ki-sans); font-weight: 700; letter-spacing: .01em;
}
body.ki .card, body.ki .card-xl { border-radius: 0; box-shadow: none; border: 1px solid var(--ki-rule); }
body.ki .input, body.ki .textarea, body.ki select, body.ki input[type="text"],
body.ki input[type="email"], body.ki input[type="password"], body.ki input[type="number"] {
  border-radius: var(--ki-r);
}
body.ki .toast { border-radius: 0; box-shadow: none; border: 1px solid var(--ki-rule-2); }
body.ki .kg__btn { border-radius: 0; box-shadow: none; }
body.ki .kg__panel, body.ki .knav-more__panel { border-radius: 0; box-shadow: none; }
body.ki .kg__panel { border: 1px solid var(--ki-rule-2); }

/* The legacy ambient glow (style.css `body::before`, two warm radial gradients
   behind every page) is the soft-SaaS depth trick the brief removes. Off on every
   page the system reaches; the landing keeps its own hero glow, which is a
   different element (`.hro__glow`). */
body.ki::before { background: none; }

/* ═══════════════════════════════════════════════════════════════════════════
   SESSION 59 — the shell and the LEGACY token layer on the three blues.
   ki.css section 13 flips the --ki-* tokens; this flips the older names the
   legacy sheets still paint with (style.css / theme.css / surfaces / scenario /
   learn …: --ink 121 readers, --line 98, --ink-soft 94, --surface 69, --bg-soft 59,
   --ink-mute 99 …), so a legacy card on a portal or practice page turns into a
   blue panel with light ink instead of a white island. The landing is excluded:
   it paints with its own --lnd-* / --pub-* and the brief keeps it as it is.
   Page-group sheets (ki_public/parent/child/mc/auth) tune what this cannot reach.
   ═══════════════════════════════════════════════════════════════════════════ */
body.ki-t-public:not(:has(.lnd--dark)), body.ki-t-portal, body.ki-t-practice {
  --ink:            #F3EFE6;
  --ink-soft:       #D2DBE5;
  --ink-mute:       var(--ki-ink-3);
  --ink-faint:      var(--ki-ink-3);
  --k-ink:          #F3EFE6;
  --k-muted:        var(--ki-ink-3);
  --line:           rgba(255, 255, 255, .16);
  --line-soft:      rgba(255, 255, 255, .10);
  --k-line:         rgba(255, 255, 255, .16);
  --k-line-soft:    rgba(255, 255, 255, .10);
  --surface:        var(--ki-panel);
  --surface-tier-0: var(--ki-panel);
  --surface-tier-1: var(--ki-ground);
  --surface-tier-2: var(--ki-stone);
  --bg:             var(--ki-ground);
  --bg-soft:        var(--ki-stone);
  --k-bg:           var(--ki-ground);
  --k-card:         var(--ki-panel);
  --k-tint:         var(--ki-stone);
  --warm-50:        var(--ki-panel);
  --warm-100:       var(--ki-ground);
  --warm-200:       var(--ki-stone);
  --warm-300:       rgba(255, 255, 255, .22);
  --teal-50:        rgba(140, 203, 230, .12);
  --blue-50:        rgba(140, 203, 230, .12);
  --k-blue-50:      rgba(140, 203, 230, .12);
}

/* ── the signed-in shell on blue ─────────────────────────────────────────── */
/* the rail already reads var(--ki-navy) (above), which each tier sets */
body.ki-t-portal .knav:not(.knav--public),
body.ki-t-practice .knav:not(.knav--public) { background: var(--ki-navy-2); border-bottom-color: var(--ki-rule); }
:is(body.ki-t-portal, body.ki-t-practice) .knav .knav-brand { color: #FFFFFF; }
:is(body.ki-t-portal, body.ki-t-practice) .knav .knav-burger span { background: #FFFFFF; }
:is(body.ki-t-portal, body.ki-t-practice) .knav .knav-burger { background: transparent; border-color: var(--ki-rule-2); }
@media (max-width: 1023px) {
  :is(body.ki-t-portal, body.ki-t-practice) .knav .knav-menu { background: var(--ki-navy); border-color: var(--ki-rule); }
  :is(body.ki-t-portal, body.ki-t-practice) .knav .knav-link { color: var(--ki-ink); }
  :is(body.ki-t-portal, body.ki-t-practice) .knav .knav-link.is-active { color: #FFFFFF; box-shadow: inset 4px 0 0 #E9C46A; background: rgba(255,255,255,.06); }
}
:is(body.ki-t-portal, body.ki-t-practice) .knav-bottom { background: var(--ki-navy); border-top-color: var(--ki-rule-2); }
:is(body.ki-t-portal, body.ki-t-practice) .knav-bottom__item { color: var(--ki-ink-2); }
:is(body.ki-t-portal, body.ki-t-practice) .knav-bottom__item.is-active,
:is(body.ki-t-portal, body.ki-t-practice) .knav-bottom__item[aria-current="page"] { color: #FFFFFF; box-shadow: inset 0 3px 0 #E9C46A; }
:is(body.ki-t-portal, body.ki-t-practice) .kg__btn { background: transparent; border-color: var(--ki-rule-2); color: #FFFFFF; }
:is(body.ki-t-portal, body.ki-t-practice) .kg__panel { background: var(--ki-navy); border-color: var(--ki-rule-2); }
:is(body.ki-t-portal, body.ki-t-practice) .kg__item { color: var(--ki-ink); }
:is(body.ki-t-portal, body.ki-t-practice) .toast { background: var(--ki-navy); color: #FFFFFF; }
/* every legacy primary button: white fill, Korva-blue ink — the same rule as .ki-btn */
:is(body.ki-t-portal, body.ki-t-practice) :is(.btn-primary, .btn.btn-primary) { background: #FFFFFF; border-color: #FFFFFF; color: var(--ki-brand); }
:is(body.ki-t-portal, body.ki-t-practice) :is(.btn-primary, .btn.btn-primary):hover { background: #E3F1F7; color: var(--ki-brand); }

/* the logo square stays Korva blue on every tier (the light accent is for TEXT) */
body.ki .brand-mark { background: var(--ki-brand, #005F82); }

/* ═══════════════════════════════════════════════════════════════════════════
   SESSION 59b — every content container LIFTS OFF the ground.
   The panel tokens moved (ki.css §13: +9-10 dL*, was +4.1-4.5, which read as the
   ground itself). These are the containers that sat DIRECTLY on the ground in a
   token that is not the panel — the inset well (--ki-stone, 3-4 dL* BELOW the
   ground), the ground colour itself, or the alternating band — measured by
   scratch_s59b/panel_audit.py. Each becomes a raised panel with a hairline.
   --ki-stone is unchanged and stays the INSET tone for wells INSIDE a panel
   (answer options, table heads, the input well), where it reads as cut in.
   ═══════════════════════════════════════════════════════════════════════════ */
/* ⚑ !important on these two declarations only, and on purpose: the page-group sheets
   style these containers at (0,4,1) (`body.ki.ki-t-portal.theme-parent .x`), and this is
   the one shared statement of "a container on the ground is a raised panel". Raising
   every selector here to match would be four tier-specific copies of one rule. */
:is(body.ki-t-public, body.ki-t-portal, body.ki-t-practice) :is(
  .ki-note, .cm-identity, .ks-empty, .trs-card, .kpath, .ks-hero--idle, .k-band--cream, .q-header,
  .sec-empty, .sec-note, .lh-tile__art, .lh-tile__body
) {
  background-color: var(--ki-panel) !important;
  border-color: var(--ki-rule);
}
:is(body.ki-t-public, body.ki-t-portal, body.ki-t-practice) :is(.cm-identity, .ks-empty, .kpath, .ks-hero--idle, .k-band--cream, .q-header, .sec-empty) {
  border: 1px solid var(--ki-rule) !important;
}
/* the Learn tile is ONE raised panel: its art strip sits a hairline below the body */
:is(body.ki-t-public, body.ki-t-portal, body.ki-t-practice) .lh-tile__art { border-bottom: 1px solid var(--ki-rule); }
:is(body.ki-t-public, body.ki-t-portal, body.ki-t-practice) .ki-note { border-left: 4px solid var(--ki-ochre); }
:is(body.ki-t-public, body.ki-t-portal, body.ki-t-practice) .trs-card { border-top: 4px solid var(--ki-ochre); }
/* the resume row's chevron is coloured INLINE with var(--ks-purple), a dark teal that is
   ALSO a fill under white text elsewhere, so the token cannot flip; 1.3:1 on the panel.
   Found by eye in Session 59b (the route walk measures text, not icons). */
:is(body.ki-t-public, body.ki-t-portal, body.ki-t-practice) .ks-resume > svg { color: var(--ki-blue) !important; }
/* the four pastel section tints back the icon chips (This Week, section cards); on blue
   they were cream / pink / mint islands. The chip becomes an inset well; the section
   colour stays on the glyph. Found by scratch_s59b/icon_check.py. */
body.ki-t-public:not(:has(.lnd--dark)), body.ki-t-portal, body.ki-t-practice {
  --section-quant-soft:    var(--ki-stone);
  --section-abstract-soft: var(--ki-stone);
  --section-reading-soft:  var(--ki-stone);
  --section-writing-soft:  var(--ki-stone);
}
/* two icons drawn in a dark token on blue (icon_check.py): the dashboard's child-row
   chevrons (#005F82 on the ground, 1.95) and the community identity glyph (#8A6100, 1.78) */
:is(body.ki-t-public, body.ki-t-portal, body.ki-t-practice) .dash-nav__item svg { color: var(--ki-blue) !important; stroke: currentColor; }
:is(body.ki-t-public, body.ki-t-portal, body.ki-t-practice) .cm-identity__ico,
:is(body.ki-t-public, body.ki-t-portal, body.ki-t-practice) .cm-identity__ico svg { color: var(--ki-ochre-ink) !important; }
/* the parallel --sec-*-soft family (style.css section hubs, learn.css feed icons) */
body.ki-t-public:not(:has(.lnd--dark)), body.ki-t-portal, body.ki-t-practice {
  --sec-quant-soft: var(--ki-stone); --sec-abstract-soft: var(--ki-stone);
  --sec-reading-soft: var(--ki-stone); --sec-writing-soft: var(--ki-stone);
}
/* /practice/this-week writes its icon chip's fill INLINE from drop_meta()['soft'] (a Python
   literal), so no token reaches it: matched by its own inline geometry. */
:is(body.ki-t-portal, body.ki-t-practice) div[style*="width: 54px; height: 54px"] { background: var(--ki-stone) !important; color: #FFFFFF !important; border: 1px solid var(--ki-rule-2); }
/* Virtual Lessons' tile count reads --vl-ink, a section ink tuned for the old panel (4.25) */
:is(body.ki-t-public, body.ki-t-portal, body.ki-t-practice) .vl-tile__count { color: var(--ki-ink-2); }
/* Session 60: the terms re-accept banner (base.html, inline cream #FFF4EF) appears for every
   existing parent after the legal version bump. On blue it was a cream island; it becomes a
   raised notice with an ochre edge — still unmistakably a notice. */
:is(body.ki-t-public, body.ki-t-portal, body.ki-t-practice) .consent-banner {
  background: var(--ki-panel); color: var(--ki-ink); border-bottom: 1px solid var(--ki-rule);
  box-shadow: inset 4px 0 0 var(--ki-ochre);
}
:is(body.ki-t-public, body.ki-t-portal, body.ki-t-practice) .consent-banner strong { color: #FFFFFF; }
:is(body.ki-t-public, body.ki-t-portal, body.ki-t-practice) .consent-banner__cta { color: var(--ki-ochre-ink); }

/* ═══════════════════════════════════════════════════════════════════════════
   SESSION 61 — CONTRAST IN EVERY STATE (hover, focus, reveal)
   Found by scratch_s61/state_sweep.py, which hovers and focuses every interactive
   element on every page and drives every reveal, measuring against the background
   each text run ACTUALLY sits on. 83 findings before this block; see
   scratch_s61/contrast_audit.txt for the full list with element ids.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ⚑ THE ROOT CAUSE OF "HOVER TURNS THE TEXT DARK". style.css:182 is a bare
   `a:hover { color: var(--blue-700) }` — a dark teal — at (0,1,1). That outranks the
   (0,1,0) class rule that gives a tile or link its colour, so EVERY <a> component
   whose colour comes from its class went dark teal under the pointer: the Practice and
   Learn doors (1.10:1), "Not now", the breadcrumbs. Landing and Session 44 already
   recorded this trap twice. style.css itself is NOT edited, because the chalkboard
   lesson pages load it too and must not change. This rule matches it at the SAME
   specificity (:where() adds none), loads later, so it wins over it on the three blue
   tiers — and loses to every component that declares its own hover colour.
   The landing is excluded: its CTA is coral and handles this itself. */
:where(body.ki-t-public:not(:has(.lnd--dark)), body.ki-t-portal, body.ki-t-practice) a:hover {
  color: var(--ki-blue-dk);
}

/* The two doors on the child home: hover lightens the panel and keeps the words white. */
body.ki.theme-kid .kpath-tile:hover,
body.ki.theme-kid .kpath-tile:focus-visible { color: #FFFFFF; }
body.ki.theme-kid .kpath-tile--practice:hover { background-color: #17304A; }

/* breadcrumbs: Korva blue as INK on blue was 1.85:1 on hover */
:is(body.ki-t-public, body.ki-t-portal, body.ki-t-practice) .kcrumbs__link:hover {
  color: var(--ki-blue-dk); background: rgba(255, 255, 255, .08);
}

/* a hover must never READ worse than rest (the sweep's DARKENED rule) */
:is(body.ki-t-portal, body.ki-t-practice) a.mistake-chip:hover,
:is(body.ki-t-portal, body.ki-t-practice) a.mistake-chip:hover * { color: #FFFFFF; }
body.ki .ka-reveal:hover { color: #FFFFFF; }
/* brand-filled primaries (vibrant.css paints them !important): hover goes DEEPER, so the
   white text gains contrast (7.1 -> 8.9) instead of losing it to a lighter fill (5.55) */
:is(body.ki-t-portal, body.ki-t-practice) .btn.btn-primary.btn-lg:hover {
  background: #00506E !important; border-color: #00506E !important; color: #FFFFFF !important;
}
/* "Delete data": the red ink on its hover fill measured 4.09 */
:is(body.ki-t-portal, body.ki-t-practice) .btn-ghost:hover { color: #FFD3C9; }
:is(body.ki-t-portal, body.ki-t-practice) .btn-ghost:not([class*="del"]):hover { color: #FFFFFF; }

/* ── THE VIRTUAL LESSON WALKTHROUGH ("Watch it worked through") ────────────────
   Every colour in it is an INLINE style written by the page or by its script, so these
   need !important. Measured before: the ANSWER at 1.27:1 (dark green #33573D on a teal
   box — the text the colour of its container), step numbers white on light blue 1.78,
   "Thinking it through..." 2.55, earlier steps faded to 3.45. */
:is(body.ki-t-portal, body.ki-t-practice) #wt-answer {
  background: rgba(143, 220, 166, .14) !important;
  border-left: 4px solid var(--ki-green);
  border-radius: 0 !important;
}
:is(body.ki-t-portal, body.ki-t-practice) #wt-answer > div { color: var(--ki-green) !important; font-size: 12.5px !important; }
:is(body.ki-t-portal, body.ki-t-practice) #wt-answer > p {
  color: #FFFFFF !important; font-weight: 700; font-size: 16px !important; margin: 0;
}
/* step number: Korva blue fill (white on it 7.1), not the light accent */
:is(body.ki-t-portal, body.ki-t-practice) #wt-steps > div > div:first-child {
  background: var(--ki-brand) !important; color: #FFFFFF !important; border-radius: 0 !important;
}
:is(body.ki-t-portal, body.ki-t-practice) #wt-steps > div > div:nth-child(2) > div:first-child { color: var(--ki-blue) !important; }
:is(body.ki-t-portal, body.ki-t-practice) #wt-steps .wt-step-text { color: var(--ki-ink) !important; }
/* earlier steps stay legible: de-emphasised by a softer ink, not by fading the whole row */
:is(body.ki-t-portal, body.ki-t-practice) #wt-steps > div:not(:last-child) { opacity: 1 !important; }
:is(body.ki-t-portal, body.ki-t-practice) #wt-steps > div:not(:last-child) .wt-step-text { color: var(--ki-ink-2) !important; }
/* the highlight the script draws over the question */
:is(body.ki-t-portal, body.ki-t-practice) #wt-question mark {
  background: rgba(233, 196, 106, .28) !important; color: #FFFFFF; border-bottom: 2px solid var(--ki-ochre);
}
/* inline `background: var(--primary); color: white` fills (the Virtual Lesson's "How to attack it"
   numbers, 1.78:1): --primary is the LIGHT accent on these tiers because most legacy rules use it
   as ink, so a white-on-it fill takes Korva blue instead (7.1) */
:is(body.ki-t-portal, body.ki-t-practice) [style*="background: var(--primary)"][style*="color: white"] {
  background: var(--ki-brand) !important; border-radius: 0 !important;
}
/* the walkthrough's ANSWER label on its green-tinted box (3.97 with --ki-green; this is 5.29) */
:is(body.ki-t-portal, body.ki-t-practice) #wt-answer > div { color: #C8F4D4 !important; }
/* settings' "Delete data": the portal sheet's (0,4,1) hover kept its red ink at 4.09 */
body.ki .kip-del:hover, body.ki .kip-del:focus-visible { color: #FFD3C9 !important; }

/* ── Reading-passage FORMATS on blue (Session 61) ────────────────────────────
   Reading passages come in six shapes and a page sweep only meets whichever one is
   served. The OPINION-QUOTE shape kept its light-theme cream (`--gold-50`) while its text
   took the flipped warm-white ink: 1.06:1, the text the colour of its box — found by the
   route walk on the one run that happened to serve it. The mistake page repeats every
   shape in its own inline <style> with literal creams and dark greens. Each shape is now
   an inset on the passage sheet, with light ink, and is verified by injecting its exact
   markup into a live page (scratch_s61/format_inject.py). */
:is(body.ki-t-portal, body.ki-t-practice) .opinion-quote {
  background: rgba(233, 196, 106, .05) !important; border-left: 3px solid var(--ki-ochre) !important;
  border-radius: 0 !important; color: var(--ki-ink);
}
:is(body.ki-t-portal, body.ki-t-practice) .quote-label { color: var(--ki-ochre-ink) !important; }
:is(body.ki-t-portal, body.ki-t-practice) .quote-text { color: var(--ki-ink) !important; }
:is(body.ki-t-portal, body.ki-t-practice) .quote-attribution { color: var(--ki-ink-2) !important; }
:is(body.ki-t-portal, body.ki-t-practice) .survey-response {
  background: var(--ki-stone) !important; border-left: 3px solid var(--ki-rule-2) !important; border-radius: 0 !important;
}
:is(body.ki-t-portal, body.ki-t-practice) .response-label { color: var(--ki-green) !important; }
:is(body.ki-t-portal, body.ki-t-practice) .response-attribution { color: var(--ki-ink-3) !important; }
:is(body.ki-t-portal, body.ki-t-practice) .response-text { color: var(--ki-ink) !important; }
:is(body.ki-t-portal, body.ki-t-practice) .passage-pre,
:is(body.ki-t-portal, body.ki-t-practice) .passage-para { color: var(--ki-ink); }
:is(body.ki-t-portal, body.ki-t-practice) .line-num { color: var(--ki-ink-3) !important; border-right-color: var(--ki-rule) !important; }
:is(body.ki-t-portal, body.ki-t-practice) .line-num-blank { border-right-color: var(--ki-rule) !important; }

/* ═══ SESSION 61b — THE ADMIN SURFACE (light, off the blue tiers via ki_tier='admin') ═══
   Swept by scratch_s61/admin_sweep.py after Session 61's sweep turned out never to have
   signed in as an admin: 1,106 findings on the blue public tier, 31 once admin pages were
   taken off it, 0 after this block. */
/* the ACTIVE tab: vibrant.css's `.adm-nav a.is-active { color: var(--vb-fill) }` (0,2,1)
   beat the tab's own white (0,2,0), so its name was Korva blue on its Korva-blue fill:
   1.00:1 — invisible. Pre-existing since Session 23. */
body.ki.ki-t-admin .adm-nav a.adm-nav__tab.is-active,
body.ki.ki-t-admin .adm-nav a.adm-nav__tab.is-active:hover { color: #FFFFFF; }
/* primaries hover DEEPER (vibrant lightened them under white text, 7.1 -> 5.55) */
body.ki.ki-t-admin :is(.btn-primary, .k-btn--primary, .cm-btn--primary):hover:not(:disabled) {
  background: #00506E !important; border-color: #00506E !important; filter: none; color: #FFFFFF;
}
body.ki.ki-t-admin .btn-soft:hover { color: #00415A; filter: none; }
/* a DISABLED primary (FAQ "Publish" with no answer yet) — exempt from AA, but the operator
   still has to read what it would do: 1.69 -> readable grey on a light grey */
body.ki.ki-t-admin :is(.btn-primary, .cm-btn--primary):disabled,
body.ki.ki-t-admin :is(.btn-primary, .cm-btn--primary)[aria-disabled="true"] {
  background: #E4E8EA !important; border-color: #C3CAD0 !important; color: #3F4A54 !important; opacity: 1;
}
