/* --------------------------------------------------------------------------
   TB-377: Plus Jakarta Sans, self-hosted.

   The published book (the Dropbox HTML/DOCX) has always set Plus Jakarta Sans,
   but pulled it from fonts.googleapis.com — so it only looked right online, and
   the Terminal used the Windows system stack instead. Students on Windows, Mac
   and an offline DOCX therefore saw three different typefaces for one textbook.

   It is served from 'self' because the CSP is `font-src 'self'`; a Google Fonts
   link is blocked outright, exactly as `style-src 'self'` silently killed the
   inline image styling in BUG-171.

   One variable file per subset covers weights 200-800. Licence: SIL Open Font
   Licence 1.1 — see fonts/OFL.txt, which must ship with the font.
   Latin + latin-ext only: this is an English textbook, and U+2122 (™) sits in
   the latin subset, so the trademark marks render.
   -------------------------------------------------------------------------- */
@font-face {
  font-family: 'Plus Jakarta Sans';
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url("fonts/PlusJakartaSans-Variable-latin.7660bd9909fb.woff2") format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Plus Jakarta Sans';
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url("fonts/PlusJakartaSans-Variable-latin-ext.341687eeeb6a.woff2") format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ==========================================================================
   Z-Change Terminal — Visual System  ("Z-Change Blue")   [v2, round 2]
   Plain CSS, no build step. Drop-in for the <style> block in base.html:
   same class vocabulary retuned to the owned Z-Change Blue palette + new
   components for the document library and reading page.
   Principles: Storytelling-with-Data cheat-sheet + WCAG-AA.
   v2 changes (design-review round 2): AA-safe --faint & --pass; cyan is
   decorative-contrast only (never small text); governance gets a real teal;
   doc cards rebuilt (spine + page-fold + typographic ID, one category signal);
   type/weight/radius tightened; opaque ring; row-hover vs zebra fixed.
   ========================================================================== */

/* 1. DESIGN TOKENS --------------------------------------------------------- */
:root {
  /* Brand — Z-Change Blue (owned) */
  --brand:      #0A527F;  --brand-600: #083F61;  --brand-700: #06304A;
  --brand-100:  #CFE3EF;  --brand-050: #EAF3F8;
  --accent:     #12B0D9;  --accent-050:#E6F7FC;   /* cyan: fills / large only, NEVER small text */
  --gold:       #BD8B13;  --gold-2:    #D99A00;   /* game / awards only */
  --grad:       linear-gradient(120deg, #0A527F 0%, #12799F 55%, #12B0D9 100%);
  --grad-warm:  linear-gradient(120deg, #F2C75C, #E8912B);

  /* Neutrals (cool) — --faint darkened to pass AA as text */
  --ink:    #16232B;   --muted:  #5A6B75;   --faint:  #6A7580;   /* faint ≈4.7:1 on white */
  --line:   #DCE5EB;   --line-2: #C7D3DB;
  --surface: #FFFFFF;  --surface-2: #F4F7F9;  --bg: #F1F5F8;

  /* Semantic (consistent, never decorative) */
  --pass: #177A4F; --pass-050: #E4F3EC;   /* ≈4.8:1 */
  --fail: #C0392B; --fail-050: #FBECEA;
  --warn: #9A6708; --warn-050: #FBF1DC;
  --info: var(--accent);

  /* Track / category tints — controlled blue→cyan→teal→gold→green family */
  --t1b:#EAF3F8; --t1f:#0A527F;   /* blue  (company)    */
  --t2b:#E6F7FC; --t2f:#0A6C88;   /* cyan  (cycles) — AA as text (~4.7:1) */
  --t3b:#E3F1F3; --t3f:#136B77;   /* teal  (governance) */
  --t4b:#FBF1D8; --t4f:#8A6410;   /* gold  (awards)     */
  --t5b:#E7F4EE; --t5f:#177A4F;   /* green (pass)       */
  --t6b:#EAF3F8; --t6f:#083F61;   /* deep blue          */

  /* Radii — one small (12), one large (20), one hero (24) */
  --r: 12px; --r-lg: 20px; --r-xl: 24px; --pill: 999px;

  /* Shadows — light, blue-tinted */
  --sh-sm: 0 1px 2px rgba(10,47,64,.06);
  --sh:    0 4px 14px -8px rgba(10,47,64,.16), 0 1px 3px rgba(10,47,64,.06);
  --sh-lg: 0 18px 40px -18px rgba(10,47,64,.22), 0 2px 6px rgba(10,47,64,.06);
  --sh-glow: 0 16px 40px -18px rgba(10,47,64,.32);
  --hi: inset 0 1px 0 rgba(255,255,255,.65);   /* top inner highlight — subtle "flat-with-depth" (all cards) */

  /* Spacing — 4px scale */
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:24px; --sp-6:32px;

  /* Type scale — the ONLY sizes */
  --fs-display:1.75rem; --fs-h2:1.375rem; --fs-h3:1.125rem; --fs-body:0.9375rem; --fs-sm:0.8125rem; --fs-micro:0.6875rem;

  --t: 170ms cubic-bezier(.34,1.3,.5,1);          /* small controls (slight overshoot) */
  --t-calm: 200ms cubic-bezier(.2,.7,.3,1);        /* large cards (no bounce) */
}

/* 2. BASE ------------------------------------------------------------------ */
* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  /* TB-377: matches the published book. System stack stays as the fallback for
     the swap window and for any subset the self-hosted file does not cover. */
  font-family: 'Plus Jakarta Sans', "Segoe UI Variable", "Segoe UI", system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
  margin: 0; color: var(--ink); font-size: var(--fs-body); line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  background:
    radial-gradient(1000px 460px at 12% -8%, rgba(10,47,64,.05), transparent 60%),
    radial-gradient(900px 460px at 100% -4%, rgba(18,176,217,.06), transparent 55%),
    var(--bg);
  background-attachment: fixed;
}
a { color: var(--brand); text-decoration: none; } a:hover { color: var(--brand-600); }
h1,h2,h3,h4 { color: var(--ink); font-weight: 700; letter-spacing: -.01em; margin: 0 0 .4em; }
h2 { font-size: var(--fs-h2); } h3 { font-size: var(--fs-h3); }
p { margin: 0 0 var(--sp-3); }
:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
/* The hidden attribute must always win — author display rules (.btn inline-flex
   etc.) otherwise override the UA [hidden] style. From DS-002 §17.0 amendment
   2026-07-10 (TB-104 acceptance finding). */
[hidden] { display: none !important; }

/* 3. APP SHELL + SIDEBAR --------------------------------------------------- */
.app { display: flex; min-height: 100vh; }
.sidebar { width: 262px; flex: none; position: sticky; top: 0; height: 100vh;
  background: var(--surface); border-right: 1px solid var(--line);
  display: flex; flex-direction: column; padding: 20px 14px; gap: 4px; }
.brand { display: flex; align-items: center; gap: 11px; color: var(--ink); padding: 4px 8px 16px; }
.brand .mark { height: 40px; width: auto; }
.brand .name { font-weight: 800; font-size: 1.0625rem; line-height: 1.05; letter-spacing: -.03em; }
.brand .name small { display: block; font-weight: 700; font-size: 0.625rem; color: var(--muted);
  letter-spacing: .6px; text-transform: uppercase; margin-top: 3px; }
.nav { display: flex; flex-direction: column; gap: 3px; flex: 1 1 auto; min-height: 0;
  overflow-y: auto; scrollbar-width: thin; scrollbar-color: var(--line-2) transparent; }
.nav .cap { font-size: 0.65625rem; font-weight: 700; letter-spacing: .7px; text-transform: uppercase;
  color: var(--muted); padding: 12px 12px 4px; display: flex; align-items: center; gap: 6px; }
.navitem { display: flex; align-items: center; gap: 11px; padding: 10px 12px; border-radius: var(--r);
  color: var(--muted); font-size: 0.875rem; font-weight: 700; transition: var(--t); }
.navitem svg { width: 19px; height: 19px; flex: none; stroke: currentColor; }
.navitem:hover { background: var(--surface-2); color: var(--ink); }
.navitem.active { background: var(--brand-050); color: var(--brand); box-shadow: inset 3px 0 0 var(--brand); }
/* DS-051 §2a (TB-232): the Battle pin — urgent styling for a LIVE battle.
   Status is conveyed by the badge TEXT ("Live"), never color alone. */
.navitem--live { background: var(--brand-050); color: var(--brand);
  box-shadow: inset 3px 0 0 var(--fail); }
.navpill-live { margin-left: auto; flex: none; font-size: var(--fs-micro);
  font-weight: 800; letter-spacing: .5px; text-transform: uppercase;
  background: var(--fail); color: #fff; padding: 2px 8px;
  border-radius: var(--pill); }
/* DS-038 §2.2: "View as student" control — reuses .navitem styling; no new
   design tokens. Only the layout glue a <form>/<button>/<select> needs. */
.viewas { margin: 0; }
.viewas-btn { width: 100%; border: 0; background: transparent; cursor: pointer;
  text-align: left; font-family: inherit; }
.viewas-sec { width: 100%; margin: 2px 0 2px 40px; max-width: calc(100% - 40px);
  padding: 4px 6px; border: 1px solid var(--line); border-radius: var(--r);
  background: var(--surface); color: var(--ink); font: inherit; font-size: 0.75rem; }
/* DS-039 §A.2: student active-course switcher — FIXED chrome at the top of the
   sidebar. Reuses .navitem styling; only the disclosure glue is new (no new
   design tokens). */
.course-switcher { margin: 4px 0 8px; }
.course-switcher > summary { cursor: pointer; list-style: none;
  border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); }
.course-switcher > summary::-webkit-details-marker { display: none; }
.course-switcher .cs-active { display: flex; flex-direction: column; min-width: 0;
  line-height: 1.25; }
.course-switcher .cs-active b { color: var(--ink); font-size: 0.8125rem; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.course-switcher .cs-active small { color: var(--muted); font-size: 0.6875rem; font-weight: 600; }
.course-switcher .cs-chev { margin-left: auto; width: 16px; height: 16px; transition: var(--t); }
.course-switcher[open] .cs-chev { transform: rotate(180deg); }
.cs-menu { display: flex; flex-direction: column; gap: 2px; padding: 4px 0 2px; }
.cs-opt { width: 100%; border: 0; background: transparent; cursor: pointer;
  text-align: left; font-family: inherit; font-size: 0.8125rem; }
.cs-opt-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cs-opt-name small { color: var(--muted); font-weight: 600; }
.cs-opt.cs-current { background: var(--brand-050); color: var(--brand); }
.cs-badge { margin-left: auto; flex: none; background: var(--brand-050); color: var(--brand); }
/* DS-049 §2d (TB-224): persistent header course chip — FIXED chrome below the
   brand naming the current course + role, with a "Switch course" control. Reuses
   the sidebar's card language; no new design tokens. Absent when there is no
   current course and on the gate itself (guarded in base.html). */
.coursechip { display: flex; align-items: center; gap: 10px; margin: 0 0 8px;
  padding: 8px 10px; border: 1px solid var(--line); border-radius: var(--r);
  background: var(--brand-050); }
.coursechip .cc-crest { width: 30px; height: 30px; flex: none; border-radius: 9px;
  display: grid; place-items: center; font-weight: 800; font-size: 0.875rem; color: #fff;
  background: var(--grad); }
.coursechip .cc-body { display: flex; flex-direction: column; min-width: 0; line-height: 1.25; }
.coursechip .cc-body b { color: var(--ink); font-size: 0.8125rem; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.coursechip .cc-body small { color: var(--muted); font-size: 0.6875rem; font-weight: 600; }
.coursechip form { margin: 0 0 0 auto; flex: none; }
.coursechip .cc-switch { border: 1px solid var(--brand-100); background: var(--surface);
  color: var(--brand); font-family: inherit; font-size: 0.6875rem; font-weight: 800;
  padding: 5px 9px; border-radius: var(--pill); cursor: pointer; transition: var(--t); }
.coursechip .cc-switch:hover { background: var(--brand); color: #fff; border-color: var(--brand); }
.side-foot { margin-top: auto; padding: 12px 8px 4px; border-top: 1px solid var(--line);
  display: flex; align-items: center; gap: 10px; }
.avatar { width: 40px; height: 40px; border-radius: 13px; flex: none; display: grid; place-items: center;
  background: var(--grad); color: #fff; font-weight: 800; }

.content { flex: 1; min-width: 0; }
.content-inner { max-width: 1000px; margin: 0 auto; padding: var(--sp-6) 34px 76px; }

/* 4. HERO / PAGE HEADER ---------------------------------------------------- */
.hero { position: relative; overflow: hidden; background: var(--grad); border-radius: var(--r-xl);
  padding: 28px 30px; box-shadow: var(--sh-glow); color: #fff; display: flex; align-items: center;
  gap: 26px; flex-wrap: wrap; }
.hero::after { content: ""; position: absolute; inset: 0; pointer-events: none;
  background-image: radial-gradient(rgba(255,255,255,.14) 1.5px, transparent 1.5px); background-size: 22px 22px; opacity: .45; }
.hero .lead { flex: 1; min-width: 240px; position: relative; z-index: 1; }
.hero h1, .hero h2 { color: #fff; font-size: var(--fs-display); margin-bottom: 4px; }
.hero .subtitle { color: rgba(255,255,255,.92); font-size: var(--fs-body); margin-bottom: 16px; font-weight: 500; }
.gchips { display: flex; gap: 10px; flex-wrap: wrap; }
.gchip { background: rgba(255,255,255,.16); border: 1px solid rgba(255,255,255,.28); border-radius: 14px;
  padding: 9px 13px; display: flex; align-items: center; gap: 9px; color: #fff; }
.gchip .big { font-weight: 800; font-size: 0.9375rem; } .gchip .lbl { font-size: 0.75rem; color: rgba(255,255,255,.92); font-weight: 600; }
.hero .ring { --val:0; width: 116px; height: 116px; flex: none; border-radius: 50%; position: relative; z-index: 1;
  background: conic-gradient(#fff calc(var(--val)*1%), rgba(255,255,255,.28) 0); display: grid; place-items: center; }
.hero .ring .hole { width: 90px; height: 90px; border-radius: 50%; background: var(--brand-700);
  display: grid; place-items: center; text-align: center; }
.hero .ring .pct { font-size: 1.5625rem; font-weight: 800; color: #fff; }
.hero .ring .sub { font-size: 0.625rem; font-weight: 700; color: rgba(255,255,255,.92); text-transform: uppercase; letter-spacing: .5px; }
/* T2 (live-audit 2026-07-23): naked action links inside a hero inherited the
   brand-blue `a` color (#0A527F), which is the SAME color the hero gradient
   starts at — 1:1 contrast, effectively invisible. Hero CTAs get an explicit
   high-contrast treatment (white text + gold underline, ~7:1 on the darkest
   part of the gradient, WCAG AAA) plus a hover state; the "·" separator sits in
   a white-colored .hero-links paragraph so it reads too. Scoped to hero CTAs —
   the rest of the hero is untouched. */
.hero .hero-links { color: rgba(255,255,255,.85); position: relative; z-index: 1; }
.hero a.hero-cta { color: #fff; font-weight: 700; text-decoration: underline;
  text-decoration-color: var(--gold-2); text-underline-offset: 3px; text-decoration-thickness: 2px; }
.hero a.hero-cta:hover { color: var(--gold-2); text-decoration-color: #fff; }

.page-head { margin: 4px 0 8px; }
.page-head .kicker { color: var(--brand); font-weight: 700; font-size: var(--fs-micro);
  letter-spacing: 1.2px; text-transform: uppercase; display: inline-flex; align-items: center; gap: 8px; }
.page-head .kicker::before { content: ""; width: 18px; height: 3px; border-radius: 2px; background: var(--accent); }
.page-head h1 { font-size: var(--fs-display); margin: 6px 0 6px; }
.page-head p { color: var(--muted); max-width: 62ch; }
.reward-summary .gchip { background: var(--surface); border-color: var(--line); color: var(--ink); }
.reward-summary .gchip .lbl { color: var(--muted); }
.crest-formal-title { margin: 0 0 4px; font-size: var(--fs-micro); font-weight: 800; letter-spacing: .08em; text-transform: uppercase; }
.tm { vertical-align: super; font-size: .55em; line-height: 0; }

/* 5. BUTTONS --------------------------------------------------------------- */
.btn { display: inline-flex; align-items: center; gap: 8px; background: var(--brand); color: #fff; border: 0;
  padding: 11px 18px; border-radius: var(--r); cursor: pointer; font: inherit; font-weight: 700; font-size: 0.875rem;
  text-decoration: none; transition: var(--t); }
.btn:hover { transform: translateY(-2px); box-shadow: var(--sh); color: #fff; background: var(--brand-600); }
.btn:active { transform: translateY(0); background: var(--brand-700); }
.btn.light { background: #fff; color: var(--brand); } .btn.light:hover { background: var(--brand-050); }
.btn.ghost { background: transparent; color: var(--brand); border: 1.5px solid var(--line-2); }
.btn.ghost:hover { border-color: var(--brand); background: var(--brand-050); }
.btn.accent { background: var(--accent); color: #06303d; } .btn.accent:hover { background: #0FA0C6; color: #06303d; }
.btn.sm { padding: 8px 13px; font-size: 0.8125rem; }
.btn svg { width: 17px; height: 17px; stroke: currentColor; }
.btn[disabled] { opacity: .5; cursor: not-allowed; transform: none; box-shadow: none; }
.linkbtn { background: none; border: 0; color: var(--brand); cursor: pointer; font: inherit; font-weight: 700; padding: 0; }

/* 6. STAT CARDS ------------------------------------------------------------ */
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 14px; margin: 18px 0 8px; }
.stat { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); padding: 16px 18px;
  box-shadow: var(--hi), var(--sh-sm); display: flex; align-items: center; gap: 14px; transition: var(--t-calm); }
.stat:hover { transform: translateY(-2px); box-shadow: var(--hi), var(--sh); }
.stat .ico { width: 46px; height: 46px; border-radius: var(--r); flex: none; display: grid; place-items: center; }
.stat .ico svg { width: 23px; height: 23px; stroke: currentColor; }
.stat .figure { font-size: 1.5rem; font-weight: 800; line-height: 1; letter-spacing: -.02em; }
.stat .figure small { font-size: 0.9375rem; color: var(--muted); font-weight: 700; }
.stat .label { font-size: 0.75rem; color: var(--muted); font-weight: 600; margin-top: 4px; }
.i-blue{background:var(--t1b);color:var(--t1f);} .i-cyan{background:var(--t2b);color:var(--t2f);}
.i-gold{background:var(--t4b);color:var(--t4f);} .i-teal{background:var(--t5b);color:var(--t5f);}
.i-slate{background:var(--t3b);color:var(--t3f);}

/* 7. SECTION HEADER -------------------------------------------------------- */
.section-head { display: flex; align-items: center; gap: 10px; margin: 30px 0 14px; }
.section-head h3 { margin: 0; }
.section-head .count { font-size: 0.8125rem; color: var(--muted); font-weight: 600; }
.section-head .rule { flex: 1; height: 1px; background: var(--line); }
.section-head.accent h3 { display: flex; align-items: center; gap: 10px; }
.section-head.accent h3::before { content: ""; width: 4px; height: 18px; border-radius: 3px; background: var(--accent); }

/* 8. GENERIC CARD + TABLE -------------------------------------------------- */
.card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r);
  padding: 18px; margin: 14px 0; box-shadow: var(--hi), var(--sh-sm); }
.muted { color: var(--muted); }
.pass { color: var(--pass); font-weight: 700; } .fail { color: var(--fail); font-weight: 700; }
table { border-collapse: separate; border-spacing: 0; width: 100%; min-width: 60rem; margin: 12px 0; font-size: 0.875rem;
  border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }

/* BUG-210/226/269/273: comparison tables keep a readable canvas and scroll
   inside their route-local host instead of crushing identities or widening the
   document body. The element selector above is the contract: a bare table gets
   the floor without an author remembering an opt-in class. :has() makes its
   immediate host the automatic scroll route; explicit labelled regions remain
   for known comparison surfaces and keyboard affordance. */
main:has(> table),
main :has(> table) {
  min-width: 0;
  max-width: 100%;
  overflow-x: auto;
  overscroll-behavior-inline: contain;
  -webkit-overflow-scrolling: touch;
}
.readable-table-region {
  width: 100%;
  min-width: 0;
  max-width: 100%;
  overflow-x: auto;
  overscroll-behavior-inline: contain;
  -webkit-overflow-scrolling: touch;
}
.readable-table-region:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}
/* Rare opt-out for tables whose deliberate narrow-screen contract is a compact
   two-column layout or a row/card projection. `.readable-table` remains in
   existing markup as a no-op compatibility marker; it no longer owns width. */
table.table-width-auto { min-width: 0; }
.course-unit-actions { display: flex; gap: 8px; }
.course-units-table th:first-child,
.course-units-table td:first-child { min-width: 9rem; width: 9rem; }
.course-units-table .chip {
  white-space: nowrap;
  overflow-wrap: normal;
  word-break: normal;
}
.e3-check-table th { white-space: nowrap; }
/* Table content wraps at normal language boundaries by default. Atomic tokens
   receive the stricter rule below; a surface that truly needs mid-token breaks
   must add a narrow, documented override for that descriptive column. */
th, td { padding: 10px 13px; text-align: left; border-bottom: 1px solid var(--line);
  overflow-wrap: normal; word-break: normal; }
th { background: var(--surface-2); font-weight: 700; font-size: 0.75rem; color: var(--muted);
  text-transform: uppercase; letter-spacing: .3px; }
/* BUG-218: console tables keep readable column widths inside their explicit
   keyboard-focusable .tbl-wrap regions instead of widening the whole page or
   crushing identifiers into one fragment per line on phones. */
.instructor-console-table { min-width: max-content; }
.instructor-console-table th { white-space: nowrap; }
tr:last-child td { border-bottom: 0; }
tbody tr:hover td { background: var(--accent-050); }

/* BUG-103/210/226/269/273: table identifiers are atomic reading units. The
   Terminal's global overflow safety may wrap prose anywhere, but semantic code
   tokens, email links, and explicitly marked identifiers stay whole in every
   table, including a bare table. There are currently no identifier opt-outs. */
table :is(code, a[href^="mailto:"], [data-table-identifier]) {
  white-space: nowrap;
  overflow-wrap: normal;
  word-break: normal;
}

/* The Explorer schema record projection is a deliberate page-specific layout:
   its first column shrinks to the now-global atomic token width. */
.explorer-schema-table th:first-child,
.explorer-schema-table td:first-child { width: 1%; }

/* 9. MODULE CARDS (learn) -------------------------------------------------- */
.modgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 16px; margin-bottom: 20px; }
.modcard { position: relative; display: block; background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: 20px; box-shadow: var(--hi), var(--sh-sm);
  transition: transform var(--t-calm), box-shadow var(--t-calm), border-color var(--t-calm); overflow: hidden; }
.modcard:hover { transform: translateY(-4px); box-shadow: var(--hi), var(--sh-lg); border-color: var(--brand-100); }
.modcard .top { display: flex; align-items: center; gap: 13px; margin-bottom: 12px; }
.modcard .tile { width: 46px; height: 46px; border-radius: var(--r); flex: none; display: grid; place-items: center; }
.modcard .tile svg { width: 24px; height: 24px; stroke: currentColor; }
.modcard.c1 .tile{background:var(--t1b);color:var(--t1f)} .modcard.c2 .tile{background:var(--t2b);color:var(--t2f)}
.modcard.c3 .tile{background:var(--t3b);color:var(--t3f)} .modcard.c4 .tile{background:var(--t4b);color:var(--t4f)}
.modcard.c5 .tile{background:var(--t5b);color:var(--t5f)} .modcard.c6 .tile{background:var(--t6b);color:var(--t6f)}
.modcard .ttl { font-weight: 700; font-size: 1rem; color: var(--ink); letter-spacing: -.01em; line-height: 1.25; }
.modcard .arrow { margin-left: auto; color: var(--faint); transition: var(--t); flex: none; }
.modcard:hover .arrow { color: var(--brand); transform: translateX(3px); }
.modcard .arrow svg { width: 19px; height: 19px; stroke: currentColor; display: block; }
.modcard .meta { font-size: 0.8125rem; color: var(--muted); font-weight: 600; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.modcard.done { border-color: rgba(189,139,19,.45); box-shadow: 0 0 0 1px rgba(189,139,19,.30), var(--hi), var(--sh-sm); }
.modcard.done:hover { box-shadow: 0 0 0 1px rgba(189,139,19,.30), var(--hi), 0 16px 34px -16px rgba(189,139,19,.42); }
/* "Next up" — the one emphasized card per view (accent, not a low-contrast chip) */
.modcard.next { border-color: var(--brand-100); background: linear-gradient(180deg, #F4FBFD, var(--surface));
  box-shadow: inset 3px 0 0 var(--accent), var(--hi), var(--sh-sm); }
.modcard.next:hover { box-shadow: inset 3px 0 0 var(--accent), var(--hi), var(--sh-lg); }
.module-finder { display: flex; align-items: center; gap: 10px; margin: 0 0 18px;
  padding: 12px; border: 1px solid var(--line); border-radius: var(--r);
  background: var(--surface); box-shadow: var(--hi), var(--sh-sm); }
.module-finder input[type="search"] { flex: 1 1 280px; min-width: 0; }
.module-finder__status { flex: none; color: var(--muted); font-size: var(--fs-sm);
  font-weight: 700; font-variant-numeric: tabular-nums; }
.module-finder__empty { padding-block: 32px; }
.progress { height: 8px; background: #E6EDF1; border-radius: var(--pill); overflow: hidden; margin-top: 11px; }
.progress > span { display: block; height: 100%; background: var(--grad); border-radius: var(--pill); transition: width .6s cubic-bezier(.34,1.2,.5,1); }

/* 10. NEW — DOCUMENT LIBRARY (/about) ------------------------------------- */
/* One category signal (the icon-tile + typographic ID, colored by --cat) +
   a document "spine" and a folded corner so a card reads as a DOCUMENT. */
.doclib { display: grid; grid-template-columns: repeat(auto-fill, minmax(272px, 1fr)); gap: 16px; margin-bottom: 6px; }
.doccard { --cat: var(--brand); position: relative; display: flex; flex-direction: column; background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--r); padding: 18px;
  box-shadow: inset 3px 0 0 var(--cat), var(--hi), var(--sh-sm);
  transition: transform var(--t-calm), box-shadow var(--t-calm), border-color var(--t-calm); }
.doccard:hover { transform: translateY(-4px); box-shadow: inset 3px 0 0 var(--cat), var(--hi), var(--sh-lg); border-color: var(--brand-100); }
.doccard .top { display: flex; align-items: flex-start; gap: 13px; margin-bottom: 10px; }
.doccard .tile { width: 42px; height: 42px; border-radius: var(--r); flex: none; display: grid; place-items: center;
  background: var(--brand-050); color: var(--cat); }
/* BUG-006: these are line-style outline icons — they must NOT be filled, or
   they render as solid black glyphs. Match every other hub tile icon: stroke in
   the category colour, no fill. */
.doccard .tile svg { width: 22px; height: 22px; stroke: currentColor; fill: none;
  stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.doccard .hd { min-width: 0; }
.doccard .id { font-family: ui-monospace, 'Cascadia Code', Consolas, monospace; font-variant-numeric: tabular-nums;
  font-size: 0.75rem; font-weight: 700; letter-spacing: .3px; color: var(--cat); display: block; margin-bottom: 1px; }
.doccard .ttl { font-weight: 700; font-size: 1rem; color: var(--ink); line-height: 1.25; letter-spacing: -.01em; }
.doccard .desc { font-size: 0.8125rem; color: var(--muted); line-height: 1.45; margin-top: 6px; flex: 1; }
.doccard .foot { display: flex; align-items: center; gap: 8px; margin-top: 14px; min-height: 22px; }
.doccard .open { margin-left: auto; display: inline-flex; align-items: center; gap: 5px; color: var(--brand);
  font-weight: 700; font-size: 0.8125rem; opacity: 0; transform: translateX(-4px); transition: var(--t); }
.doccard:hover .open, .doccard:focus-visible .open { opacity: 1; transform: none; }
.doccard.cat-hb  { --cat: var(--t1f); } .doccard.cat-hb  .tile { background: var(--t1b); }
.doccard.cat-cyc { --cat: var(--t2f); } .doccard.cat-cyc .tile { background: var(--t2b); }
.doccard.cat-gov { --cat: var(--t3f); } .doccard.cat-gov .tile { background: var(--t3b); }

/* 11. NEW — DOCUMENT READING PAGE ----------------------------------------- */
/* BUG-180: the reading surface is a white card, matching the published book.
   Long-form prose sat directly on the grey app background while the Dropbox
   HTML/DOCX render put it on a white card — the owner reads both and found the
   published one markedly easier. This is the same consistency argument that
   moved the Terminal onto Plus Jakarta Sans (TB-377).

   The 760px measure is kept deliberately rather than copying the published
   1000px: with the padding below the text column lands near 670px, a more
   comfortable line length than the published render's ~910px.

   `[data-textbook-library]` is excluded — that page is a LIST containing its own
   .card elements, so carding it again nests a card inside a card. */
.doc-read { max-width: 760px; margin: 0 auto; }
.doc-read:not([data-textbook-library]) {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 18px;
  padding: 40px 44px;
  box-shadow: 0 4px 14px -8px rgba(10, 47, 64, .16);
}
@media (max-width: 640px) {
  /* 44px of side padding costs a third of a phone's width. */
  .doc-read:not([data-textbook-library]) { padding: 24px 18px; border-radius: 14px; }
}
.doc-read .doc-bar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 18px; }
.doc-read .cls { font-size: var(--fs-micro); font-weight: 700; letter-spacing: 1px; text-transform: uppercase;
  color: var(--brand); background: var(--brand-050); padding: 4px 10px; border-radius: var(--pill); }
.doc-read .doc-meta { font-size: var(--fs-sm); color: var(--muted); font-weight: 600; font-variant-numeric: tabular-nums; }
.doc-read .doc-bar .btn { margin-left: auto; }
.doc-read .doc-title { font-size: var(--fs-display); font-weight: 800; letter-spacing: -.02em; margin: 0 0 4px; }
.doc-read .doc-sub { color: var(--muted); margin: 0 0 18px; }
.doc-read .band { height: 4px; width: 88px; border-radius: 3px; background: var(--grad); margin: 0 0 26px; }
.prose { font-size: 0.96875rem; line-height: 1.7; color: #23333c; }
/* The renderer demotes source headings because the page owns h1: source h2
   becomes h3 and source h3 becomes h4. Style the emitted hierarchy. */
.prose h2, .prose h3 { font-size: var(--fs-h2); color: var(--brand); margin: 34px 0 12px; padding-bottom: 6px; border-bottom: 1px solid var(--line); }
.prose h4 { font-size: var(--fs-h3); color: var(--brand-600); margin: 22px 0 8px; }
.prose h5, .prose h6 { font-size: var(--fs-body); color: var(--brand-600); font-weight: 700; margin: 18px 0 6px; }
.prose p { margin: 0 0 14px; }
.prose ul, .prose ol { margin: 0 0 14px; padding-left: 22px; } .prose li { margin: 5px 0; }
.prose strong { color: var(--ink); }
.prose a { color: var(--brand); text-decoration: underline; text-underline-offset: 2px; }
.prose table { font-size: 0.875rem; box-shadow: var(--sh-sm); }
.prose thead th, .prose table tr:first-child th { background: var(--brand); color: #fff; text-transform: none;
  letter-spacing: 0; font-size: 0.78125rem; font-weight: 700; }
/* BUG-022: only the renderer-tagged Learning Objectives table gets this
   three-column contract. Shrink the outer columns to their content and leave
   the unconstrained Objective column the remaining width. */
.prose table.lo { table-layout: auto; max-width: none; }
.prose table.lo th:first-child, .prose table.lo td:first-child,
.prose table.lo th:last-child, .prose table.lo td:last-child { white-space: nowrap; }
.prose table.lo th:first-child, .prose table.lo td:first-child { min-width: 7rem; }
.prose table.lo th:last-child, .prose table.lo td:last-child { min-width: 10rem; }
.prose table.lo th:nth-child(2), .prose table.lo td:nth-child(2) { width: auto; overflow-wrap: anywhere; }
.prose table.lo td:first-child { font-weight: 600; color: var(--brand-600); }
.prose table.lo td:last-child { color: var(--muted); font-size: 0.84375rem; }
.prose tbody tr:nth-child(even) td { background: var(--surface-2); }
.prose tbody tr:hover td { background: var(--brand-050); }
.prose blockquote { margin: 18px 0; padding: 14px 18px; background: var(--accent-050);
  border-left: 4px solid var(--accent); border-radius: 0 var(--r) var(--r) 0; color: #234; }
.prose blockquote p:last-child { margin: 0; }
.prose figure { margin: 20px 0; text-align: center; }
.prose figure img { max-width: 100%; border: 1px solid var(--line); border-radius: var(--r); }
/* BUG-171: the renderer emits bare <img> inside <p>, so `.prose figure img`
   above never matched it, and CSP discards inline styles. Every rendered image
   needs a class-based cap or print-resolution diagrams (up to 4800px) overflow
   the 760px reading column and force the whole page to scroll sideways.
   `height: auto` keeps the aspect ratio once width is constrained. */
.md-img, .prose img { max-width: 100%; height: auto; border: 1px solid var(--line); border-radius: var(--r); }
.prose figcaption { font-size: 0.78125rem; color: var(--muted); margin-top: 8px; font-style: italic; }
.prose code { background: var(--surface-2); border: 1px solid var(--line); border-radius: 6px; padding: 1px 6px; font-size: .9em; }

/* 12. BADGES / PILLS ------------------------------------------------------- */
.chip { display: inline-flex; align-items: center; gap: 5px; font-size: 0.71875rem; font-weight: 700;
  padding: 3px 10px; border-radius: var(--pill); background: var(--surface-2); color: var(--muted); }
.chip svg { width: 12px; height: 12px; stroke: currentColor; }
.chip.done, .chip.pass { background: var(--pass-050); color: var(--pass); }
.chip.info { background: var(--brand-050); color: var(--brand); }
.chip.pdf { background: var(--fail-050); color: var(--fail); }
.chip.gold { background: var(--t4b); color: var(--t4f); }

/* 13. EMPTY STATE --------------------------------------------------------- */
.empty { text-align: center; padding: 48px 24px; color: var(--muted); }
.empty .eico { width: 64px; height: 64px; margin: 0 auto 14px; border-radius: var(--r-lg); display: grid; place-items: center;
  background: var(--brand-050); color: var(--brand); }
.empty .eico svg { width: 30px; height: 30px; stroke: currentColor; }
.empty h3 { color: var(--ink); margin-bottom: 4px; } .empty p { max-width: 42ch; margin: 0 auto 16px; }

/* 14. FORMS --------------------------------------------------------------- */
input[type=text],input[type=password],input[type=email],input[type=number],select,textarea {
  width: 100%; font: inherit; font-size: 0.875rem; padding: 11px 13px; color: var(--ink); background: #fff;
  border: 1.5px solid var(--line-2); border-radius: var(--r); transition: var(--t); }
input::placeholder, textarea::placeholder { color: var(--faint); }
input:focus,select:focus,textarea:focus { outline: 0; border-color: var(--brand); box-shadow: 0 0 0 4px var(--brand-050); }
label { font-weight: 700; font-size: 0.8125rem; color: var(--muted); }

/* 15. RESPONSIVE ---------------------------------------------------------- */
/* Sidebar/nav flat-wall rules removed by TB-105 (DS-003): the mobile sidebar
   is now the off-canvas drawer defined in §18. Content rules kept. */
@media (max-width: 880px) {
  .content-inner { padding: 22px 18px 60px; } .hero { padding: 22px; }
  .doc-read { max-width: 100%; }
  .module-finder { flex-wrap: wrap; }
  .module-finder input[type="search"] { flex-basis: calc(100% - 74px); min-height: 44px; }
  .module-finder__status { flex-basis: 100%; }
}

/* C5 (live-audit 2026-07-23): phone touch targets + no horizontal overflow for
   the course-authoring surfaces (Textbook Library + Weekly Learning Plan
   editor). Desktop stays compact; only <=880px bumps interactive controls to
   the 44px floor and keeps wide content from exceeding the viewport width. */
.tbl-wrap { max-width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; }
@media (max-width: 560px) {
  .course-unit-head {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center;
  }
  .course-unit-head h3 {
    min-width: 0;
    overflow-wrap: normal;
    word-break: normal;
  }
  .course-unit-head .chip { white-space: nowrap; }
  .course-unit-head .rule { display: none; }
  .course-unit-actions {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    width: 100%;
  }
  .course-unit-actions form,
  .course-unit-actions .btn { width: 100%; }
  .prose table.lo th:last-child, .prose table.lo td:last-child { white-space: normal; }
  /* A two-column schema cannot give both identifiers and column lists a useful
     reading measure on a phone. Preserve table semantics in the DOM while each
     body row becomes one full-width record in the working column. */
  .explorer-schema-table,
  .explorer-schema-table tbody,
  .explorer-schema-table tbody tr,
  .explorer-schema-table tbody td { display: block; width: 100%; }
  .explorer-schema-table thead {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }
  .explorer-schema-table tbody tr { padding: 12px 13px; border-bottom: 1px solid var(--line); }
  .explorer-schema-table tbody tr:last-child { border-bottom: 0; }
  .explorer-schema-table tbody td { padding: 0; border: 0; }
  .explorer-schema-table tbody td:first-child {
    width: 100%;
    margin-bottom: 8px;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--line);
  }
  .explorer-schema-table tbody td:last-child { overflow-wrap: anywhere; }
}
/* DS-055 (TB-246/247): the inventory multi-add bar sticks to the bottom of its
   card on desktop (Slice A); on phones (below) it becomes a viewport-bottom bar
   with an opaque background + z-index so the last inventory row scrolls under it
   without being obscured (audit C2 + C5). */
.inv-actionbar { z-index: 20; }
@media (max-width: 880px) {
  /* Kill the ~8px 390px overflow: nothing may be wider than the viewport. */
  .content, .content-inner, .doc-read, .card, table, .tbl-wrap { max-width: 100%; }
  .card { overflow-wrap: anywhere; }
  /* Checkboxes were 13x13 — give them a 44px hit area (visual box stays small
     via transform-free padding trick: a big transparent tap target). */
  input.tap-check { min-width: 24px; min-height: 24px; width: 24px; height: 24px;
    margin: 10px; }
  /* Search / preview / assign-tray buttons + selects to the 44px floor. */
  .doc-read .btn, .doc-read .btn.sm,
  .assign-tray .btn, .assign-tray select,
  input[type="search"], .doc-read select {
    min-height: 44px; }
  .doc-read input[type="search"] { flex: 1 1 auto; min-width: 0; }
  /* Weekly-plan up/down + Show/Hide/Remove were 37x38 — 44px min both ways. */
  .btn.ghost.sm { min-height: 44px; min-width: 44px; }
  /* The Unassigned "Add to week" picker (inside a wrapped table) to 44px. */
  .tbl-wrap select, .tbl-wrap .btn { min-height: 44px; }
  /* DS-055 Slice B: the weeks-list summary + manage controls, the rename field,
     and the inventory add-bar's own select/button all meet the 44px floor. */
  .week-summary { min-height: 44px; }
  .week-manage input[type="text"], .inv-actionbar select,
  .inv-actionbar .btn, .inv-controls input[type="search"] { min-height: 44px; }
  /* The inventory add-bar becomes a full-width sticky BOTTOM bar pinned to the
     viewport, so it stays reachable while scrolling a long inventory and never
     clips the last row (audit C2 + C5). Opaque background so rows pass under. */
  .inv-actionbar { position: sticky; bottom: 0; left: 0; right: 0;
    background: var(--bg, #fff); }
  /* The assign tray becomes a full-width sticky bar that never clips the last
     chapter row (C2 + C5): its own scroll padding is handled by the last card. */
  .assign-tray { left: 0; right: 0; }
}

/* 16. STUDENT CORE — DASHBOARD / MY PROGRESS / QUIZZES (DS-001) ------------ */
/* Landed by TB-101 from the DS-001 mockups' labeled §16a–f style blocks so
   TB-102 can build My Progress + Quizzes on top. Six disjoint blocks; the
   .achstrip/.chip.locked rule appears in two mockups and is merged once. */

/* 16a. Group subhead (module groups inside a course section) */
.subhead { font-size: 0.75rem; font-weight: 700; color: var(--muted);
  text-transform: uppercase; letter-spacing: .6px; margin: 18px 0 10px; }

/* 16b. Hero XP chip (ported from hub-legacy, tokenized) */
.gchip.xpchip { min-width: 190px; }
.gchip.xpchip .col { display: flex; flex-direction: column; gap: 6px; flex: 1; }
.gchip.xpchip .row { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; }
.xpbar { height: 6px; border-radius: 999px; background: rgba(255,255,255,.25); overflow: hidden; }
.xpbar > span { display: block; height: 100%; border-radius: 999px; background: #fff; }
.hero .actions { margin-top: 16px; }

/* 16c. Achievements strip (dashboard + My progress) */
.achstrip { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.achstrip .more { margin-left: auto; font-size: 0.8125rem; font-weight: 700; white-space: nowrap; }
.chip.locked { color: var(--faint); }

/* 16d. Progress rows (My progress) — replaces card-in-card + glow dot */
.progrow { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r);
  padding: 16px 18px; margin: 10px 0; box-shadow: var(--hi), var(--sh-sm); }
.progrow > .row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.progrow .tile { width: 36px; height: 36px; border-radius: 10px; flex: none; display: grid; place-items: center; }
.progrow .tile svg { width: 19px; height: 19px; stroke: currentColor; fill: none;
  stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.progrow .ttl { font-weight: 700; font-size: 0.9375rem; color: var(--ink); letter-spacing: -.01em; }
a.ttl:hover { color: var(--brand); }
.progrow .chip { margin-left: auto; }
.progrow .progress { margin-top: 12px; }
.progrow details { margin-top: 12px; }
.progrow summary { cursor: pointer; font-weight: 700; font-size: 0.8125rem; color: var(--muted);
  list-style: none; display: inline-flex; align-items: center; gap: 6px; }
.progrow summary::-webkit-details-marker { display: none; }
.progrow summary svg { width: 14px; height: 14px; stroke: currentColor; fill: none;
  stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; transition: var(--t); }
.progrow details[open] summary svg { transform: rotate(90deg); }
.progrow summary:hover { color: var(--brand); }
.progrow table { margin: 12px 0 2px; }
.warn { color: var(--warn); font-weight: 700; }

/* Module tint tiles reuse the t1..t6 pairs */
.tint-1{background:var(--t1b);color:var(--t1f)} .tint-2{background:var(--t2b);color:var(--t2f)}
.tint-3{background:var(--t3b);color:var(--t3f)} .tint-4{background:var(--t4b);color:var(--t4f)}
.tint-5{background:var(--t5b);color:var(--t5f)} .tint-6{background:var(--t6b);color:var(--t6f)}

/* 16e. Quiz cards */
.quizgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 16px; margin-bottom: 20px; }
.quizcard { display: flex; flex-direction: column; gap: 10px; background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--r-lg); padding: 20px;
  box-shadow: var(--hi), var(--sh-sm);
  transition: transform var(--t-calm), box-shadow var(--t-calm), border-color var(--t-calm); }
.quizcard.open:hover { transform: translateY(-4px); box-shadow: var(--hi), var(--sh-lg); border-color: var(--brand-100); }
.quizcard .top { display: flex; align-items: flex-start; gap: 13px; }
.quizcard .tile { width: 42px; height: 42px; border-radius: var(--r); flex: none; display: grid;
  place-items: center; background: var(--brand-050); color: var(--brand); }
.quizcard .tile svg { width: 22px; height: 22px; stroke: currentColor; fill: none;
  stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.quizcard .hd { min-width: 0; }
.quizcard .ttl { font-weight: 700; font-size: 1rem; color: var(--ink); line-height: 1.25; letter-spacing: -.01em; }
.quizcard .meta { font-size: 0.8125rem; color: var(--muted); font-weight: 600; margin-top: 3px; }
.quizcard .window { font-size: 0.8125rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.quizcard .foot { display: flex; align-items: center; gap: 10px; margin-top: auto; padding-top: 4px; flex-wrap: wrap; }
.quizcard .last { font-size: 0.8125rem; color: var(--muted); font-weight: 600; }
.quizcard .foot .btn { margin-left: auto; }
.quizcard.shut { background: var(--surface-2); }
.quizcard.shut .tile { background: var(--surface); color: var(--faint); }
.quizcard.shut .ttl { color: var(--muted); }

/* 16f. Page head with a right-side action */
.headbar { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.headbar .page-head { flex: 1; min-width: 260px; margin: 4px 0 8px; }
.headbar .btn { margin-top: 26px; flex: none; }

/* 16g. Section-head action link (TB-106 polish round, DS-001 amendment 2) */
.section-head .act { margin-left: auto; font-size: 0.8125rem; font-weight: 700; white-space: nowrap; }

/* 17. LEARNING SURFACES — MODULE / LESSON / WORKBENCH / RUNNER (DS-002) ---- */
/* Landed by TB-103 from DS-002 §2/§17, copied verbatim from
   _handoff/mockups/DS-002/_ds002-additions.css (single source for all DS-002
   mockups). 17e/17f/17g feed the TB-104 quiz runner + results build. */

/* 17a. Breadcrumb link above page-head */
.crumb { display: inline-flex; align-items: center; gap: 6px; font-size: 0.8125rem;
  font-weight: 700; color: var(--muted); margin-bottom: 2px; }
.crumb:hover { color: var(--brand); }
.crumb svg { width: 15px; height: 15px; stroke: currentColor; fill: none;
  stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.learning-context-nav { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 8px;
  margin: 0 0 var(--sp-3); }

/* 17b. Lesson banner (module page) */
.lessonlink { display: flex; align-items: center; gap: 14px; background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--r-lg); padding: 18px 20px;
  margin: 16px 0; color: inherit;
  box-shadow: inset 3px 0 0 var(--brand), var(--hi), var(--sh-sm);
  transition: transform var(--t-calm), box-shadow var(--t-calm); }
.lessonlink:hover { transform: translateY(-2px);
  box-shadow: inset 3px 0 0 var(--brand), var(--hi), var(--sh); }
.lessonlink .tile { width: 42px; height: 42px; border-radius: var(--r); flex: none;
  background: var(--brand-050); color: var(--brand); display: grid; place-items: center; }
.lessonlink .tile svg { width: 22px; height: 22px; stroke: currentColor; fill: none;
  stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.lessonlink .go { margin-left: auto; color: var(--brand); font-weight: 700;
  font-size: 0.8125rem; flex: none; }

/* 17c. Question rows (module page) */
.qlist { display: flex; flex-direction: column; gap: 10px; margin-top: 14px; }
.qrow { display: flex; align-items: center; gap: 13px; background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--r); padding: 14px 16px;
  box-shadow: var(--hi), var(--sh-sm); color: inherit;
  transition: transform var(--t-calm), box-shadow var(--t-calm), border-color var(--t-calm); }
.qrow:hover { transform: translateY(-2px); box-shadow: var(--hi), var(--sh);
  border-color: var(--brand-100); }
.qrow .num { width: 34px; height: 34px; border-radius: 10px; flex: none; display: grid;
  place-items: center; background: var(--surface-2); color: var(--muted);
  font-weight: 800; font-size: 0.8125rem; }
/* TB-106 polish round (DS-002 amendment 1): sizes the passed-row check glyph in
   CSS, replacing the width/height attributes on the svg in module_detail.html. */
.qrow .num svg { width: 15px; height: 15px; }
.qrow.done .num { background: var(--pass-050); color: var(--pass); }
.qrow .prompt { flex: 1; min-width: 0; font-weight: 600; color: var(--ink); }
.qrow .chip { flex: none; }

/* 17d. Workbench (question page) */
.sqlbox { font-family: ui-monospace, 'Cascadia Code', Consolas, monospace;
  font-size: 0.84375rem; line-height: 1.55; min-height: 130px; }
.callout { display: flex; gap: 10px; align-items: flex-start; background: var(--warn-050);
  border: 1px solid #EAD9B0; border-radius: var(--r); padding: 12px 14px; margin: 12px 0;
  font-size: 0.875rem; color: #5C4A12; }
.callout svg { width: 17px; height: 17px; flex: none; stroke: currentColor; fill: none;
  stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; margin-top: 1px; }
.schema summary { cursor: pointer; font-weight: 700; font-size: 0.8125rem; color: var(--muted);
  list-style: none; display: inline-flex; align-items: center; gap: 6px; }
.schema summary::-webkit-details-marker { display: none; }
.schema summary svg { width: 14px; height: 14px; stroke: currentColor; fill: none;
  stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; transition: var(--t); }
.schema[open] summary svg { transform: rotate(90deg); }
.schema summary:hover { color: var(--brand); }
.resultcard { border-radius: var(--r); border: 1px solid var(--line);
  background: var(--surface); padding: 16px 18px; margin-top: 16px;
  box-shadow: var(--hi), var(--sh-sm); }
.resultcard.ok { border-color: rgba(23,122,79,.4);
  box-shadow: inset 3px 0 0 var(--pass), var(--hi), var(--sh-sm); }
.resultcard.bad { border-color: rgba(192,57,43,.35);
  box-shadow: inset 3px 0 0 var(--fail), var(--hi), var(--sh-sm); }
.resultcard .verdict { display: flex; align-items: center; gap: 8px; font-weight: 800; }
.resultcard.ok .verdict { color: var(--pass); }
.resultcard.bad .verdict { color: var(--fail); }
.resultcard .verdict svg { width: 18px; height: 18px; stroke: currentColor; fill: none;
  stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }

/* 17e. Quiz runner */
.quizbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin: 8px 0 14px; }
.learning-resource-links { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 2px 6px; }
.timerchip { margin-left: auto; display: inline-flex; align-items: center; gap: 7px;
  font-variant-numeric: tabular-nums; font-weight: 800; font-size: 0.875rem;
  background: var(--brand-050); color: var(--brand); border-radius: var(--pill);
  padding: 7px 14px; }
.timerchip.low { background: var(--fail-050); color: var(--fail); }
.timerchip svg { width: 15px; height: 15px; stroke: currentColor; fill: none;
  stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.choice { display: flex; align-items: center; gap: 10px; border: 1.5px solid var(--line-2);
  border-radius: var(--r); padding: 11px 14px; margin: 8px 0; cursor: pointer;
  font-weight: 600; color: var(--ink); transition: var(--t); }
.choice:hover { border-color: var(--brand); background: var(--brand-050); }
.choice:has(input:checked) { border-color: var(--brand); background: var(--brand-050);
  box-shadow: 0 0 0 1px var(--brand); }
.choice input { accent-color: var(--brand); width: 16px; height: 16px; flex: none; }
.qnav { display: flex; gap: 10px; margin-top: 14px; }
.qmapdot { width: 34px; height: 34px; border-radius: 10px; border: 1.5px solid var(--line-2);
  display: grid; place-items: center; font-weight: 800; font-size: 0.8125rem;
  color: var(--muted); background: var(--surface); cursor: pointer; transition: var(--t); }
.qmapdot:hover { border-color: var(--brand); }
.qmapdot.answered { border-color: var(--brand); background: var(--brand-050); color: var(--brand); }
.qmapdot.blank { color: var(--fail); border-color: #EECFCA; background: var(--fail-050); }
/* 17e (amendment 2026-07-10): review-map container */
.qmap { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 6px; }

/* 17f. Quiz results header */
.scorehead { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; margin: 6px 0 16px; }
.scorehead .big { font-size: 2.125rem; font-weight: 800; letter-spacing: -.02em; }
.scorehead .big small { font-size: 1.125rem; color: var(--muted); font-weight: 700; }
/* 17f (amendment 2026-07-10): fail-toned retry chip + right-aligned action */
.chip.retry { background: var(--fail-050); color: var(--fail); }
.scorehead .btn { margin-left: auto; }

/* 17g. Lesson prose extras (markdown pipeline emits .mdcode) */
.prose .mdcode { background: var(--surface-2); border: 1px solid var(--line);
  border-radius: 10px; padding: 12px 14px; overflow-x: auto;
  font-family: ui-monospace, 'Cascadia Code', Consolas, monospace;
  font-size: 0.78125rem; line-height: 1.55; }

/* 18. MOBILE SHELL (BUG-001): top bar + drawer nav below 880px ---------- */
/* Landed by TB-105 from DS-003, copied verbatim from
   _handoff/mockups/DS-003/_ds003-additions.css. §15 reworked in tandem. */
.topbar { display: none; }
.scrim { position: fixed; inset: 0; z-index: 50; background: rgba(10,47,64,.42);
  opacity: 0; pointer-events: none; transition: opacity 200ms ease; }

@media (max-width: 880px) {
  .crumb, .learning-context-nav a, .learning-resource-links a {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
  }
  .crumb { margin-bottom: 4px; }
  .learning-context-nav { gap: 0 8px; }
  .learning-resource-links { flex-basis: 100%; gap: 0 8px; }
  .app { flex-direction: column; }

  .topbar { position: sticky; top: 0; z-index: 40; display: flex;
    align-items: center; gap: 10px; background: var(--surface);
    border-bottom: 1px solid var(--line); padding: 10px 14px; }
  .topbar .brand { padding: 0; gap: 9px; }
  .topbar .brand .mark { height: 30px; }
  .topbar .brand .name { font-size: 0.9375rem; }

  .menubtn { width: 40px; height: 40px; flex: none; border-radius: var(--r);
    border: 1.5px solid var(--line-2); background: var(--surface);
    color: var(--ink); display: grid; place-items: center; cursor: pointer;
    transition: var(--t); }
  .menubtn:hover { border-color: var(--brand); background: var(--brand-050); }
  .menubtn svg { width: 20px; height: 20px; stroke: currentColor; fill: none;
    stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

  /* The existing .sidebar becomes the drawer */
  .sidebar { position: fixed; top: 0; bottom: 0; left: 0;
    width: min(310px, 86vw); height: 100dvh; z-index: 60;
    border-right: 1px solid var(--line); box-shadow: var(--sh-lg);
    transform: translateX(-105%);
    transition: transform 240ms cubic-bezier(.2,.7,.3,1); }
  body.drawer-open .sidebar { transform: none; }
  body.drawer-open .scrim { opacity: 1; pointer-events: auto; }
  body.drawer-open { overflow: hidden; }

  /* Inside the drawer the nav is vertical again: caps + sections restored */
  .nav { flex-direction: column; flex-wrap: nowrap; }
  .nav .cap { display: flex; }
}

@media (prefers-reduced-motion: reduce) {
  .sidebar, .scrim { transition: none; }
}

/* 19. SETUP CONSOLE (DS-004) — ships verbatim from
   _handoff/mockups/DS-004/_ds004-additions.css ------------------------- */

/* 19a. Setup console readiness header */
.readybar { display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: 16px 20px; margin: 4px 0 20px;
  box-shadow: var(--hi), var(--sh-sm); }
.readybar .big { font-size: 1.5rem; font-weight: 800; letter-spacing: -.02em; }
.readybar .big small { font-size: 0.875rem; color: var(--muted); font-weight: 700; }
.readybar .progress { flex: 1; min-width: 160px; margin: 0; }

/* 19b. Setup checklist rows.
   BUG-010: the row must WRAP. Without flex-wrap, a content-heavy inline body
   (DS-048 step 3 "People": roster forms + long meta) claims its max-content
   flex-basis and crushes the flex:1 head to ~0px — the title/meta text then
   wraps one word per line and overflows into the body. Wrapping lets any body
   too wide for the line drop BELOW the head as a full-width row instead. */
.setuplist { display: flex; flex-direction: column; gap: 10px; }
.setuprow { display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--r); padding: 15px 18px;
  box-shadow: var(--hi), var(--sh-sm); }
.setuprow .st { width: 34px; height: 34px; border-radius: 10px; flex: none;
  display: grid; place-items: center; }
.setuprow .st svg { width: 18px; height: 18px; stroke: currentColor; fill: none;
  stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.setuprow.done .st { background: var(--pass-050); color: var(--pass); }
.setuprow.todo .st { background: var(--surface-2); color: var(--faint); }
.setuprow.warn .st { background: var(--warn-050); color: var(--warn); }
/* BUG-010: a real flex-basis so the head can NEVER be squeezed below a
   readable width on its line — with wrap on, an oversized body yields and
   drops to the next line instead of stealing the head's space. */
.setuprow .hd { flex: 1 1 240px; min-width: 0; }
/* BUG-010: title and meta are block rows inside the head — the meta wraps
   cleanly BELOW the title (finally activating .sub's margin-top) instead of
   flowing inline after it. */
.setuprow .hd .ttl, .setuprow .hd .sub { display: block; }
.setuprow .ttl { font-weight: 700; color: var(--ink); font-size: 0.9375rem; }
.setuprow .sub { font-size: 0.8125rem; color: var(--muted); margin-top: 2px;
  overflow-wrap: anywhere; /* BUG-010: join-link URLs etc. break, never overflow */ }
.setuprow .sub .warntext { color: var(--warn); font-weight: 700; }
.setuprow .btn { flex: none; }
/* BUG-010: inline step bodies (forms/column divs) may shrink and never exceed
   the card, so a wrapped body clears the head at any viewport. Inline
   min-widths on the wizard bodies still win over this floor. */
.setuprow > div, .setuprow > form { min-width: 0; max-width: 100%; }
/* DS-048 (TB-218): highlight the "do this next" wizard step. */
.setuprow.next { border-color: var(--accent); box-shadow: var(--hi), 0 0 0 2px var(--accent-050, rgba(80,120,255,.18)); }

/* 19c. Below 880px the head takes its own full row (icon above it) so the
   action/body always stacks underneath (DS-004 §5; base row wraps at every
   width since BUG-010). */
@media (max-width: 880px) {
  .setuprow .hd { flex-basis: 100%; }
  .setuprow .st { order: -1; }
}

/* 19d. Preview-as-student banner (DS-004 §4 — behavior specified, CSS not in
   the §19 block; built from existing tokens/chip+btn vocabulary). Pinned to
   the top of the viewport while a staff user previews as a student. */
.previewbar { position: sticky; top: 0; z-index: 50; display: flex;
  align-items: center; gap: 12px; flex-wrap: wrap;
  background: var(--warn-050); border-bottom: 1px solid var(--warn);
  color: var(--ink); padding: 10px 18px; font-size: 0.84375rem; font-weight: 700; }
.previewbar .dot { width: 9px; height: 9px; border-radius: 50%;
  background: var(--warn); flex: none; }
.previewbar form { margin: 0 0 0 auto; }

/* DS-028/TB-183 rich-text WYSIWYG toolbar + editable surface (composer only). */
.mat-source,
.mat-source > *,
.mat-src-filelink,
.mat-src-filelink > *,
.mat-src-text,
.mat-src-text > label,
.rt-editor {
  min-width: 0;
  max-width: 100%;
}
.mat-src-filelink input { max-width: 100%; }
.mat-src-text > label { display: block; }
.rt-toolbar { display: flex; flex-wrap: wrap; gap: 4px; align-items: center;
  padding: 6px; border: 1px solid var(--line); border-bottom: none;
  border-radius: 10px 10px 0 0; background: var(--surface-2); }
.rt-toolbar .rt-btn { padding: 4px 8px; min-width: 30px; line-height: 1.1; }
.rt-toolbar .rt-color { width: 30px; height: 28px; padding: 0; border: 1px solid var(--line);
  border-radius: 8px; background: #fff; cursor: pointer; }
.rt-editor { border: 1px solid var(--line); border-radius: 0 0 10px 10px;
  min-height: 120px; padding: 12px 14px; background: #fff; overflow-wrap: anywhere; }
.rt-editor:focus { outline: 2px solid var(--brand); outline-offset: -1px; }
.rt-editor iframe { max-width: 100%; }
.rt-source { width: 100%; }
.rt-limitations { margin: 5px 0 0; color: var(--muted); font-size: .82rem; }
.rt-feedback { min-height: 1.25rem; margin: 4px 0 8px; color: var(--muted); font-size: .82rem; }
.rt-feedback.is-error { color: #9f2d20; font-weight: 700; }


/* DS-029/TB-184: course-page HERO banner (a default, editable, deletable
   section kind). Full-width tasteful gradient by default; a validated bg-image
   URL overrides it; an optional dark overlay keeps text legible over photos. */
.cph-hero { position: relative; overflow: hidden; border-radius: var(--r-xl);
  background: var(--grad); background-size: cover; background-position: center;
  padding: 48px 40px; margin: 0 0 22px; box-shadow: var(--shadow, 0 8px 30px rgba(6,48,74,.12)); }
.cph-hero--overlay::before { content: ""; position: absolute; inset: 0;
  background: linear-gradient(120deg, rgba(6,48,74,.72) 0%, rgba(6,48,74,.42) 100%);
  pointer-events: none; }
.cph-hero__inner { position: relative; z-index: 1; max-width: 720px; }
.cph-hero__title { color: #fff; font-size: var(--fs-display); line-height: 1.1;
  margin: 0 0 10px; font-weight: 800; }
.cph-hero__sub { color: rgba(255,255,255,.92); font-size: var(--fs-body);
  font-weight: 500; margin: 0 0 20px; max-width: 60ch; }
.cph-hero__links { display: flex; flex-wrap: wrap; gap: 10px; }
.cph-hero__btn { display: inline-flex; align-items: center; gap: 6px;
  padding: 9px 16px; border-radius: 999px; font-weight: 700; font-size: 0.875rem;
  background: #fff; color: var(--brand-700); border: 1px solid rgba(255,255,255,.6);
  transition: transform .12s ease, box-shadow .12s ease; }
.cph-hero__btn:hover { color: var(--brand-700); transform: translateY(-1px);
  box-shadow: 0 6px 18px rgba(0,0,0,.18); }
.cph-hero__btn::after { content: "\2197"; font-size: 0.75rem; opacity: .7; }
@media (max-width: 640px) { .cph-hero { padding: 34px 22px; } }


/* DS-051 §7 (TB-234): My Team & Totem — sticky jump-link bar. Sticks below
   the mobile topbar (z below its 40); anchors SCROLL to sections (nothing is
   hidden/collapsed) and .jumptarget's scroll-margin keeps each heading clear
   of the sticky bars when jumped to. */
.jumpbar { position: sticky; top: 0; z-index: 30; display: flex; flex-wrap: wrap;
  gap: 4px; align-items: center; padding: 8px 10px; margin: 0 0 16px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r); box-shadow: var(--sh-sm); }
.jumpbar a { padding: 6px 12px; border-radius: var(--pill); font-weight: 600;
  font-size: 0.875rem; color: var(--brand); }
.jumpbar a:hover { background: var(--brand-050); }
.jumptarget { scroll-margin-top: 130px; }
@media (max-width: 880px) { .jumpbar { top: 54px; } }
