/* ── FONTS ────────────────────────────────────────────────────────────────────
   THIS FILE NAMED POPPINS AND LORA TWENTY-FOUR TIMES AND DELIVERED NEITHER.

   It carried no @font-face and no @import, so the families arrived only if a
   page happened to carry its own Google Fonts <link>. Seven of them did not:
   nova_approvals, nova_tutor, nova_accommodations, nova_completions,
   nova_compliance_console, nova_ops_console and nova_project_lessons. Those
   pages rendered in whatever the reader's machine happened to have, which is
   why the approval queue looked fuzzy on a machine with a partial local Poppins
   and merely wrong on one without it.

   The severity was never the fuzziness. It is that the approval queue and the
   student tutor had typography that was a property of the reader's computer.

   IN THIS FILE BECAUSE THIS FILE IS ALREADY MANDATORY. Every page must start
   from nova-system.css and lint:conventions enforces it, so the fonts now
   arrive wherever that rule already reaches. Adding a <link> to seven pages
   would have fixed seven pages; page eight would have brought the gap back.

   SELF HOSTED, WHICH ALSO REMOVES A THIRD PARTY CALL FROM STUDENT BROWSERS.
   Every page that did carry the link made each reader fetch from
   fonts.googleapis.com and fonts.gstatic.com on load. Those two origins are now
   out of the CSP entirely rather than merely unused. For a product that will
   hold student records, that is worth having on principle.

   Latin subsets only, 83 KB for the set. Poppins ships one file per weight and
   Lora is variable, so one file covers 400 to 600. Both are SIL Open Font
   License 1.1, which permits redistribution; public/fonts/OFL.txt carries it.

   font-display: swap, so text is readable immediately in the fallback and
   reflows once the face lands. Never invisible while a font loads. */

@font-face { font-family: 'Poppins'; font-style: normal; font-weight: 300; font-display: swap;
  src: url('/fonts/poppins-300.woff2') format('woff2'); }
@font-face { font-family: 'Poppins'; font-style: normal; font-weight: 400; font-display: swap;
  src: url('/fonts/poppins-400.woff2') format('woff2'); }
@font-face { font-family: 'Poppins'; font-style: normal; font-weight: 500; font-display: swap;
  src: url('/fonts/poppins-500.woff2') format('woff2'); }
@font-face { font-family: 'Poppins'; font-style: normal; font-weight: 600; font-display: swap;
  src: url('/fonts/poppins-600.woff2') format('woff2'); }
@font-face { font-family: 'Poppins'; font-style: normal; font-weight: 700; font-display: swap;
  src: url('/fonts/poppins-700.woff2') format('woff2'); }
/* 800 is real: 23 declarations across the app use it. Without this face the
   browser synthesises bold by thickening outlines, which is the smeary look. */
@font-face { font-family: 'Poppins'; font-style: normal; font-weight: 800; font-display: swap;
  src: url('/fonts/poppins-800.woff2') format('woff2'); }
/* Variable: one file answers the whole 400 to 600 range Lora is asked for. */
@font-face { font-family: 'Lora'; font-style: normal; font-weight: 400 600; font-display: swap;
  src: url('/fonts/lora-400-600.woff2') format('woff2'); }

/*
 * ╔══════════════════════════════════════════════════════════════════╗
 * ║          NOVA+ Design System - v1.0                             ║
 * ║          Anthropic Academy Palette · Poppins + Lora             ║
 * ║          Based on Elite Interface Design Principles             ║
 * ╚══════════════════════════════════════════════════════════════════╝
 *
 * COLOR DOCTRINE (read before adding or changing a color):
 *  A brand color used as TEXT, or as a fill behind text, gets an AA-safe "-ink"
 *  sibling. The brand token itself stays decorative: borders, tints, eyebrows,
 *  rules, dots. NEVER darken a brand token to chase contrast, because that
 *  shifts the brand everywhere it is doing purely decorative work.
 *
 *  brand              decorative use        AA-safe text/fill sibling
 *  --orange  #d97757  borders, tints        --orange-ink  #ad5533  (5.09:1)
 *  --teal    #0891b2  rules, progress, dots --teal-dark   #0670a2  (5.46:1)
 *  --mid     #b0aea5  borders, dividers     --label-ink   #6f6e66  (5.12:1)
 *  --purple  #7c5cbf  role identity, tints  (none needed: 5.07:1 as text)
 *  --amber   #d97706  caution tints, dots   --amber-ink   #a65b05  (5.10:1)
 *  --pink    #c45c7a  IEP/504 flag, tints   --pink-ink    #ac516b  (5.07:1)
 *
 *  --amber-ink and --pink-ink were added Aug 2026 and were overdue: the rule
 *  above already said a brand colour used as a FILL BEHIND TEXT gets an AA-safe
 *  sibling, and these two were the only brand colours being used that way with
 *  no sibling to reach for. --teal, --orange and --green all had one. Every
 *  white-on-brand fill in the app now has somewhere correct to go.
 *
 *  --purple was added Aug 2026, and the reason is worth keeping. Two pages had
 *  independently invented a purple at DIFFERENT values (#7c5cbf and #7c3aed)
 *  for different meanings, because the palette had no purple and the roles it
 *  distinguishes are real: staff roles use teal, pink, gold and purple as
 *  identities, so folding purple into any of those makes two roles collide.
 *  It needs no -ink sibling because it already clears 4.5:1 as text, which is
 *  why the sibling column is empty rather than missing.
 *
 *  Every ratio above is measured against --surface (#ffffff). Re-measure when
 *  you touch one. AA needs 4.5:1 for normal text, 3:1 for large text and for
 *  non-text UI (borders, focus rings, graph strokes).
 *
 * PRINCIPLES BAKED IN:
 *  1. Signal color only  - orange/teal/pink earn their meaning through restraint
 *  2. Whitespace as signal - generous padding; breathing room is doing work
 *  3. Typography hierarchy - Poppins headings, Lora body, 2 weights max visible
 *  4. 100ms feedback - transitions on every interactive element
 *  5. Progressive disclosure - show only what's needed per role level
 *  6. Microinteractions - hover lift, button spring, focus rings
 *  7. Infinite forgiveness - destructive actions always confirmable
 */

/* ─────────────────────────────────────────────
   DESIGN TOKENS
───────────────────────────────────────────── */
:root {
  /* ── Palette (Anthropic Academy) ── */
  --bg:           #faf9f5;   /* warm off-white page background */
  --surface:      #ffffff;   /* card / panel surface */
  --surface-2:    #f5f4f0;   /* slightly darker surface for nested panels */
  --border:       #e8e6dc;   /* default border */
  --mid:          #b0aea5;   /* muted DECORATIVE only: borders, dividers, dots */
  --label-ink:    #6f6e66;   /* AA-safe muted TEXT: eyebrows, meta labels, th */
  --text:         #141413;   /* primary text */
  --text-soft:    #44545b;   /* secondary text, subtitles */

  /* ── Signal colors ── */
  --orange:       #d97757;   /* brand accent: borders, tints, eyebrows, rules */
  --orange-dark:  #b85e3a;   /* hover state for orange */
  --orange-ink:   #ad5533;   /* AA-safe orange: fills behind white text, orange text on light */
  --orange-light: #fdf2ed;   /* orange tint bg */
  --blue:         #6a9bcc;   /* secondary accent */
  --blue-light:   #eaf2fa;   /* blue tint bg */
  --green:        #788c5d;   /* success / on-state / approved */
  --green-dark:   #5a6e42;   /* green hover, matching --orange-dark / --teal-dark */
  --green-light:  #edf2e6;   /* green tint bg */

  /* ── NOVA functional colors ── */
  --teal:         #0891b2;   /* NOVA engagement / primary brand action */
  --teal-dark:    #0670a2;   /* teal hover / body-weight text use */
  --teal-light:   #e8f6fb;   /* NOVA alert card background */
  --pink:         #c45c7a;   /* IEP/504 flag, decorative (4.07:1, NOT AA as text) */
  --pink-ink:     #ac516b;   /* AA-safe pink: fills behind white text (5.07:1) */
  --pink-light:   #fceef3;   /* IEP/504 card background */
  --purple:       #7c5cbf;   /* PBIS / behavior-support role identity (5.07:1 on white) */
  --purple-light: #ede9fe;   /* purple tint bg */
  --amber:        #d97706;   /* caution / warning */
  --amber-ink:    #a65b05;   /* AA-safe amber: fills behind white text (5.10:1) */
  --amber-light:  #fef3c7;   /* warning bg */
  --red:          #dc2626;   /* error / critical */
  --red-light:    #fee2e2;   /* error bg */

  /* ── Sidebar (intentionally dark - unchanged) ── */
  --sidebar-bg:   #141413;
  --sidebar-text: #e8e6dc;
  --sidebar-mid:  #b0aea5;
  --sidebar-hover: rgba(255,255,255,.07);
  --sidebar-active: rgba(217,119,87,.15);

  /* ── Spacing ── */
  --space-xs:  .25rem;
  --space-sm:  .5rem;
  --space-md:  1rem;
  --space-lg:  1.5rem;
  --space-xl:  2rem;
  --space-2xl: 3rem;

  /* ── Shape ── */
  --radius-sm:  6px;
  --radius:     12px;
  --radius-lg:  18px;
  --radius-pill: 999px;

  /* ── Elevation ── */
  --shadow-sm:  0 1px 4px rgba(20,20,19,.06);
  --shadow:     0 2px 16px rgba(20,20,19,.08);
  --shadow-md:  0 4px 24px rgba(20,20,19,.12);
  --shadow-lg:  0 8px 40px rgba(20,20,19,.16);

  /* ── Motion (100ms principle) ── */
  --ease:       cubic-bezier(.4,0,.2,1);
  --duration:   150ms;
  --duration-md: 250ms;
}

/* ─────────────────────────────────────────────
   RESET + BASE
───────────────────────────────────────────── */
*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  font-size: 16px;
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  font-family: 'Lora', Georgia, serif;
  font-size: 1rem;
  line-height: 1.6;
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* ─────────────────────────────────────────────
   TYPOGRAPHY - hierarchy-first
───────────────────────────────────────────── */
h1, h2, h3, h4, h5, h6,
.heading,
button,
label,
.label,
.tag,
.badge,
nav,
.nav,
input,
select,
textarea {
  font-family: 'Poppins', Arial, sans-serif;
}

h1 { font-size: clamp(1.75rem, 4vw, 2.5rem); font-weight: 700; line-height: 1.2; letter-spacing: -.02em; }
h2 { font-size: clamp(1.25rem, 3vw, 1.75rem); font-weight: 700; line-height: 1.25; letter-spacing: -.015em; }
h3 { font-size: 1.15rem; font-weight: 600; line-height: 1.3; }
h4 { font-size: 1rem;    font-weight: 600; line-height: 1.35; }
h5 { font-size: .875rem; font-weight: 600; line-height: 1.4; }
h6 { font-size: .8rem;   font-weight: 600; line-height: 1.4; letter-spacing: .04em; text-transform: uppercase; color: var(--label-ink); }

p { line-height: 1.65; }
p + p { margin-top: .75em; }

strong { font-weight: 600; }
small  { font-size: .8rem; color: var(--text-soft); }

/* Links are underlined by default. Color alone is not an accessible link
   signal, and --teal as text measures 3.68:1 on --surface. --teal-dark #0670a2
   holds 5.46:1, so it is the link ink and no new token is needed.
   (Published as 4.83:1 here and in the doctrine table until Aug 17 2026. Both
   figures cleared AA so nothing rendered wrong, but the table is the thing the
   doctrine tells you to trust. Now checked: see lint-conventions.js.) */
a {
  color: var(--teal-dark);
  text-decoration: underline;
  text-underline-offset: .15em;
  transition: color var(--duration) var(--ease);
}
a:hover { color: var(--text); text-decoration: underline; }

/* Components that happen to be anchors are not prose links: no underline. */
.btn, .chip, .tag, .badge, .sidebar__item, .topbar__logo, .card--interactive {
  text-decoration: none;
}
.btn:hover, .chip:hover, .tag:hover, .sidebar__item:hover, .card--interactive:hover {
  text-decoration: none;
}

/* ─────────────────────────────────────────────
   LAYOUT UTILITIES
───────────────────────────────────────────── */
.container {
  width: 100%;
  max-width: 1100px;
  margin: 0 auto;
  padding: 0 var(--space-xl);
}

.container--narrow { max-width: 680px; }  /* optimal reading width */
.container--wide   { max-width: 1400px; }

.flex   { display: flex; }
.flex-col { display: flex; flex-direction: column; }
.gap-sm { gap: var(--space-sm); }
.gap-md { gap: var(--space-md); }
.gap-lg { gap: var(--space-lg); }

/* ─────────────────────────────────────────────
   CARDS
───────────────────────────────────────────── */
.card {
  background: var(--surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: var(--space-xl);
}

.card--sm  { padding: var(--space-lg); }
.card--lg  { padding: var(--space-2xl); }
.card--flat { box-shadow: none; border: 1.5px solid var(--border); }

/* Signal variants */
.card--teal  { border-left: 4px solid var(--teal);  background: var(--teal-light); }
.card--pink  { border-left: 4px solid var(--pink);  background: var(--pink-light); }
.card--orange { border-top: 4px solid var(--orange); }
.card--amber { border-left: 4px solid var(--amber); background: var(--amber-light); }
.card--green { border-left: 4px solid var(--green); background: var(--green-light); }
.card--red   { border-left: 4px solid var(--red);   background: var(--red-light); }

/* Hover lift - 100ms principle */
.card--interactive {
  cursor: pointer;
  transition: box-shadow var(--duration-md) var(--ease),
              transform var(--duration-md) var(--ease);
}
.card--interactive:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}

/* ─────────────────────────────────────────────
   BUTTONS
───────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-sm);
  padding: .65rem 1.25rem;
  border-radius: var(--radius-sm);
  font-family: 'Poppins', sans-serif;
  font-size: .875rem;
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
  border: none;
  transition: background var(--duration) var(--ease),
              transform var(--duration) var(--ease),
              box-shadow var(--duration) var(--ease);
  white-space: nowrap;
  text-decoration: none;
}

.btn:active { transform: scale(.97); }

/* Disabled. Every builder disables its generate button while a run is in
   flight, so the state has to read as unavailable rather than just inert.
   WCAG exempts disabled controls from the contrast minimum. */
.btn:disabled,
.btn[disabled] {
  background: var(--mid);
  color: #fff;
  border-color: var(--mid);
  cursor: not-allowed;
  transform: none;
  filter: none;
  box-shadow: none;
}

/* Primary
   Fill is --orange-ink, not --orange: white on --orange measures 3.1:1, which
   fails WCAG 2.1 AA for the 14px label. --orange-ink holds 5.1:1 at the same hue,
   so the brand accent is unchanged everywhere it is a border, tint, or eyebrow. */
.btn--primary { background: var(--orange-ink); color: #fff; }
.btn--primary:hover { background: var(--orange-ink); filter: brightness(.9); color: #fff; text-decoration: none; }
.btn--primary:focus-visible { outline: 2px solid var(--orange-ink); outline-offset: 3px; }

/* Secondary */
.btn--secondary {
  background: transparent;
  color: var(--text-soft);
  border: 1.5px solid var(--border);
}
.btn--secondary:hover { border-color: var(--mid); color: var(--text); }

/* Teal (NOVA action) */
.btn--teal { background: var(--teal); color: #fff; }
.btn--teal:hover { background: var(--teal-dark); color: #fff; text-decoration: none; }

/* Ghost (orange text on a light ground needs --orange-ink to clear 4.5:1) */
.btn--ghost { background: transparent; color: var(--orange-ink); }
.btn--ghost:hover { background: var(--orange-light); }

/* Sizes */
.btn--sm { padding: .4rem .85rem; font-size: .78rem; }
.btn--lg { padding: .85rem 1.75rem; font-size: 1rem; }
.btn--block { width: 100%; }

/* ─────────────────────────────────────────────
   FORM ELEMENTS
───────────────────────────────────────────── */
input[type="text"],
input[type="email"],
input[type="password"],
input[type="search"],
input[type="number"],
textarea,
select {
  width: 100%;
  padding: .65rem 1rem;
  border: 1.5px solid var(--border);
  border-radius: var(--radius-sm);
  font-family: 'Lora', serif;
  font-size: .95rem;
  color: var(--text);
  background: var(--bg);
  outline: none;
  transition: border-color var(--duration) var(--ease);
}

/* A TRANSPARENT OUTLINE BESIDE THE SHADOW, and it is not decoration.
   Windows High Contrast (forced-colors) does not paint box-shadow. It DOES
   repaint an outline, including a transparent one, in the user's own colour. So
   a focus ring built only from a shadow disappears on exactly the machines a
   school is most likely to hand a student who needs it, and the student loses
   track of where they are typing.
   Found by Cowork on Sep 9, reading the deployed stylesheet. check:a11y passes
   these rules and is right to: something WAS put back. Its subject is "was a
   replacement provided" and it gets read as "can the user see focus", and those
   two come apart in one environment. */
input:focus, textarea:focus, select:focus {
  border-color: var(--orange);
  box-shadow: 0 0 0 3px rgba(217,119,87,.15);
  outline: 2px solid transparent;
  outline-offset: 2px;
}

label {
  font-size: .8rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--text-soft);
  display: block;
  margin-bottom: .4rem;
}

/* ─────────────────────────────────────────────
   BADGES & TAGS
───────────────────────────────────────────── */
.tag {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  font-size: .65rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  padding: .2rem .55rem;
  border-radius: var(--radius-sm);
}

.tag--default { background: var(--border);       color: var(--text-soft); }
.tag--orange  { background: var(--orange-light);  color: #8a3714; }
.tag--teal    { background: var(--teal-light);    color: var(--teal-dark); }
.tag--pink    { background: var(--pink-light);    color: #7a1a3c; }
.tag--green   { background: var(--green-light);   color: #3a4a25; }
.tag--amber   { background: var(--amber-light);   color: #78450a; }
.tag--red     { background: var(--red-light);     color: #8b1616; }
.tag--purple  { background: var(--purple-light);  color: #543a86; }

/* Badge: a compact round marker for step numbers and counts.
   Deliberately ink rather than a signal color. A step number is structure, not
   signal, and white on any of the signal fills sits under 4.5:1 at this size. */
.badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.3rem;
  height: 1.3rem;
  padding: 0 .4rem;
  border-radius: var(--radius-pill);
  background: var(--text);
  color: #faf9f5;
  font-size: .7rem;
  font-weight: 700;
  line-height: 1;
  flex-shrink: 0;
}

.badge--teal  { background: var(--teal-dark); }
.badge--muted { background: var(--surface-2); color: var(--text-soft); }

/* ─────────────────────────────────────────────
   NAVIGATION / SIDEBAR
───────────────────────────────────────────── */
.sidebar {
  background: var(--sidebar-bg);
  color: var(--sidebar-text);
  width: 240px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  padding: var(--space-lg) var(--space-md);
  gap: .2rem;
  min-height: 100vh;
}

.sidebar__logo {
  font-family: 'Poppins', sans-serif;
  font-size: 1.15rem;
  font-weight: 700;
  color: #faf9f5;
  margin-bottom: var(--space-lg);
  letter-spacing: -.01em;
}
.sidebar__logo span { color: var(--orange); }

.sidebar__section {
  font-size: .65rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--sidebar-mid);
  padding: .85rem 0 .35rem .5rem;
}

.sidebar__item {
  display: flex;
  align-items: center;
  gap: .55rem;
  padding: .5rem .7rem;
  border-radius: var(--radius-sm);
  font-family: 'Poppins', sans-serif;
  font-size: .83rem;
  font-weight: 500;
  color: var(--sidebar-mid);
  cursor: pointer;
  transition: background var(--duration) var(--ease),
              color var(--duration) var(--ease);
  text-decoration: none;
}
.sidebar__item:hover { background: var(--sidebar-hover); color: #faf9f5; text-decoration: none; }
.sidebar__item--active { background: var(--sidebar-active); color: var(--orange); }

.sidebar__badge {
  margin-left: auto;
  background: var(--orange);
  color: white;
  font-size: .62rem;
  font-weight: 700;
  padding: .1rem .4rem;
  border-radius: var(--radius-pill);
  min-width: 1.2rem;
  text-align: center;
}

/* ─────────────────────────────────────────────
   TOP HEADER BAR
───────────────────────────────────────────── */
.topbar {
  height: 56px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 var(--space-xl);
  position: sticky;
  top: 0;
  z-index: 50;
}

.topbar__logo {
  font-family: 'Poppins', sans-serif;
  font-size: 1.1rem;
  font-weight: 700;
  color: var(--text);
  letter-spacing: -.015em;
}
.topbar__logo span { color: var(--orange); }

/* ─────────────────────────────────────────────
   PAGE SHELL (sidebar + main layout)
───────────────────────────────────────────── */
.shell {
  display: flex;
  min-height: 100vh;
}

.main-content {
  flex: 1;
  padding: var(--space-xl) var(--space-2xl);
  overflow-y: auto;
  min-width: 0;
}

/* ─────────────────────────────────────────────
   STAT / METRIC CARDS
───────────────────────────────────────────── */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: var(--space-md);
}

.stat-card {
  background: var(--surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  padding: var(--space-lg);
  border: 1px solid var(--border);
}

.stat-card__value {
  font-family: 'Poppins', sans-serif;
  font-size: 2rem;
  font-weight: 700;
  color: var(--text);
  line-height: 1;
  margin-bottom: .25rem;
}

.stat-card__label {
  font-family: 'Poppins', sans-serif;
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--label-ink);
}

/* ─────────────────────────────────────────────
   PROGRESS / MASTERY BARS
───────────────────────────────────────────── */
.progress-track {
  height: 6px;
  background: var(--border);
  border-radius: var(--radius-pill);
  overflow: hidden;
}

.progress-fill {
  height: 100%;
  background: var(--teal);
  border-radius: var(--radius-pill);
  transition: width var(--duration-md) var(--ease);
}

.progress-fill--orange { background: var(--orange); }
.progress-fill--green  { background: var(--green); }
.progress-fill--amber  { background: var(--amber); }
.progress-fill--red    { background: var(--red); }

/* ─────────────────────────────────────────────
   IOS-STYLE TOGGLE
───────────────────────────────────────────── */
.toggle {
  position: relative;
  display: inline-block;
  width: 44px;
  height: 26px;
  flex-shrink: 0;
}
.toggle input { opacity: 0; width: 0; height: 0; }
.toggle__track {
  position: absolute;
  cursor: pointer;
  inset: 0;
  background: var(--border);
  border-radius: 26px;
  transition: background var(--duration) var(--ease);
}
.toggle__thumb {
  position: absolute;
  height: 20px;
  width: 20px;
  left: 3px;
  bottom: 3px;
  background: white;
  border-radius: 50%;
  transition: transform var(--duration) var(--ease);
  box-shadow: 0 1px 4px rgba(0,0,0,.2);
}
.toggle input:checked + .toggle__track { background: var(--green); }
.toggle input:checked + .toggle__track .toggle__thumb { transform: translateX(18px); }
.toggle input:focus-visible + .toggle__track { outline: 2px solid var(--orange); outline-offset: 2px; }

/* ─────────────────────────────────────────────
   NOTIFICATION / ALERT CARDS (3-taxonomy system)
───────────────────────────────────────────── */
.alert-card {
  background: var(--surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  padding: 1.1rem 1.1rem 1.1rem 1.25rem;
  display: flex;
  align-items: flex-start;
  gap: var(--space-md);
  border-left: 4px solid transparent;
  transition: box-shadow var(--duration-md) var(--ease),
              transform var(--duration-md) var(--ease);
}
.alert-card:hover { box-shadow: var(--shadow-md); transform: translateY(-1px); }

.alert-card--powerschool  { background: var(--surface-2);  border-left-color: var(--mid); }
.alert-card--nova         { background: var(--teal-light);  border-left-color: var(--teal); }
.alert-card--iep          { background: var(--pink-light);  border-left-color: var(--pink); }
.alert-card.resolved      { opacity: .45; }

/* ─────────────────────────────────────────────
   HERO / LANDING SECTIONS
───────────────────────────────────────────── */
.hero {
  background: var(--sidebar-bg);
  color: var(--sidebar-text);
  padding: var(--space-2xl) 0;
}

.hero__eyebrow {
  font-family: 'Poppins', sans-serif;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--orange);
  margin-bottom: var(--space-md);
}

.hero__title {
  font-size: clamp(2rem, 5vw, 3.5rem);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -.025em;
  color: #faf9f5;
  margin-bottom: var(--space-lg);
}

.hero__title em {
  font-style: normal;
  color: var(--orange);
}

.hero__sub {
  font-size: 1.1rem;
  color: #b0aea5;
  max-width: 580px;
  line-height: 1.65;
  margin-bottom: var(--space-xl);
}

/* ─────────────────────────────────────────────
   SECTION DIVIDER
───────────────────────────────────────────── */
.section-label {
  font-family: 'Poppins', sans-serif;
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--label-ink);
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  margin: var(--space-lg) 0 var(--space-md);
}
.section-label::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--border);
}

/* ─────────────────────────────────────────────
   TABLES
───────────────────────────────────────────── */
table {
  width: 100%;
  border-collapse: collapse;
  font-size: .875rem;
}

thead tr {
  border-bottom: 2px solid var(--border);
}

th {
  font-family: 'Poppins', sans-serif;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--label-ink);
  padding: .6rem .75rem;
  text-align: left;
}

td {
  padding: .75rem .75rem;
  border-bottom: 1px solid var(--border);
  color: var(--text);
  vertical-align: middle;
}

tr:last-child td { border-bottom: none; }
tbody tr:hover { background: var(--surface-2); }

/* ─────────────────────────────────────────────
   AVATAR
───────────────────────────────────────────── */
.avatar {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--orange);
  color: white;
  font-family: 'Poppins', sans-serif;
  font-weight: 700;
  font-size: .875rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.avatar--lg { width: 52px; height: 52px; font-size: 1.1rem; }
.avatar--sm { width: 26px; height: 26px; font-size: .7rem; }

/* ─────────────────────────────────────────────
   MASTERY / STATUS DOTS
───────────────────────────────────────────── */
.status-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  display: inline-block;
  flex-shrink: 0;
}
.status-dot--green  { background: var(--green); }
.status-dot--amber  { background: var(--amber); }
.status-dot--red    { background: var(--red); }
.status-dot--teal   { background: var(--teal); }
.status-dot--mid    { background: var(--mid); }

/* ─────────────────────────────────────────────
   MODAL OVERLAY
───────────────────────────────────────────── */
.modal-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(20,20,19,.4);
  z-index: 200;
  align-items: center;
  justify-content: center;
  backdrop-filter: blur(2px);
}
.modal-overlay.open { display: flex; }

.modal {
  background: var(--surface);
  border-radius: var(--radius-lg);
  padding: var(--space-xl);
  max-width: 440px;
  width: 90%;
  box-shadow: var(--shadow-lg);
  animation: modal-in .2s var(--ease);
}

@keyframes modal-in {
  from { opacity: 0; transform: scale(.96) translateY(8px); }
  to   { opacity: 1; transform: scale(1)   translateY(0); }
}

/* ─────────────────────────────────────────────
   TOOLTIP
───────────────────────────────────────────── */
[data-tooltip] { position: relative; cursor: default; }
[data-tooltip]::after {
  content: attr(data-tooltip);
  position: absolute;
  bottom: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%);
  background: var(--text);
  color: #faf9f5;
  font-family: 'Poppins', sans-serif;
  font-size: .72rem;
  font-weight: 500;
  padding: .3rem .65rem;
  border-radius: var(--radius-sm);
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--duration) var(--ease);
  z-index: 100;
}
[data-tooltip]:hover::after { opacity: 1; }

/* ─────────────────────────────────────────────
   CHIP / FILTER ROW
───────────────────────────────────────────── */
.chip-row { display: flex; flex-wrap: wrap; gap: .5rem; }

.chip {
  padding: .35rem .9rem;
  border-radius: var(--radius-pill);
  border: 1.5px solid var(--border);
  background: var(--surface);
  font-family: 'Poppins', sans-serif;
  font-size: .78rem;
  font-weight: 500;
  color: var(--text-soft);
  cursor: pointer;
  transition: all var(--duration) var(--ease);
}
.chip:hover { border-color: var(--orange); color: var(--orange-ink); }
.chip--active {
  background: var(--orange-ink);
  border-color: var(--orange-ink);
  color: white;
}

/* ─────────────────────────────────────────────
   YPA INDICATOR (You-Peer-AI flow)
───────────────────────────────────────────── */
.ypa-track {
  display: flex;
  align-items: center;
  gap: .5rem;
  font-family: 'Poppins', sans-serif;
  font-size: .75rem;
  font-weight: 600;
}
.ypa-step {
  padding: .25rem .65rem;
  border-radius: var(--radius-pill);
  border: 1.5px solid var(--border);
  color: var(--label-ink);
  transition: all var(--duration) var(--ease);
}
.ypa-step--active  { border-color: var(--teal);   color: var(--teal);   background: var(--teal-light); }
.ypa-step--done    { border-color: var(--green);  color: var(--green);  background: var(--green-light); }
.ypa-step--locked  { opacity: .4; }
.ypa-arrow { color: var(--label-ink); font-size: .7rem; }

/* ─────────────────────────────────────────────
   CATCH-UP BRIEFING CARD
───────────────────────────────────────────── */
.briefing-card {
  background: linear-gradient(135deg, #141413 0%, #1e2c33 100%);
  border-radius: var(--radius);
  padding: var(--space-xl);
  color: #faf9f5;
  position: relative;
  overflow: hidden;
}
.briefing-card::before {
  content: '';
  position: absolute;
  top: -40px; right: -40px;
  width: 200px; height: 200px;
  background: radial-gradient(circle, rgba(8,145,178,.25) 0%, transparent 70%);
  pointer-events: none;
}
.briefing-card__eyebrow {
  font-family: 'Poppins', sans-serif;
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--teal);
  margin-bottom: .5rem;
}
.briefing-card__title {
  font-family: 'Poppins', sans-serif;
  font-size: 1.15rem;
  font-weight: 700;
  color: #faf9f5;
  margin-bottom: .5rem;
}
.briefing-card__body {
  font-size: .9rem;
  color: #b0aea5;
  line-height: 1.6;
}

/* ─────────────────────────────────────────────
   RESPONSIVE BREAKPOINTS
───────────────────────────────────────────── */
@media (max-width: 900px) {
  .shell { flex-direction: column; }
  .sidebar { width: 100%; min-height: auto; flex-direction: row; flex-wrap: wrap; padding: var(--space-md); }
  .sidebar__section { display: none; }
  .main-content { padding: var(--space-lg) var(--space-md); }
}

@media (max-width: 600px) {
  .sidebar { display: none; }
  .stat-grid { grid-template-columns: 1fr 1fr; }
  h1 { font-size: 1.6rem; }
}

/* ─────────────────────────────────────────────
   PRINT
───────────────────────────────────────────── */
@media print {
  .sidebar, .topbar, .btn { display: none !important; }
  body { background: white; color: black; }
  .card { box-shadow: none; border: 1px solid #ccc; }
}

/* ─────────────────────────────────────────────
   WCAG FOCUS RING (universal)
───────────────────────────────────────────── */
:focus-visible {
  outline: 2px solid var(--orange);
  outline-offset: 3px;
  border-radius: 3px;
}

/* ─────────────────────────────────────────────
   UTILITY - ANIMATION ENTRIES
───────────────────────────────────────────── */
@keyframes fadein {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes pulsedot {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%       { opacity: .5; transform: scale(.8); }
}
@keyframes shimmer {
  from { background-position: -200px 0; }
  to   { background-position: calc(200px + 100%) 0; }
}

.animate-fadein { animation: fadein .3s var(--ease) both; }

/* Loading skeleton */
.skeleton {
  background: linear-gradient(90deg, var(--border) 25%, var(--surface-2) 50%, var(--border) 75%);
  background-size: 200px 100%;
  animation: shimmer 1.2s infinite;
  border-radius: var(--radius-sm);
}

/* ─────────────────────────────────────────────
   TUTOR (NOVA Learn, LP-1)
   The persistent-tutor conversation surface. Lives in the system, not on the
   page, so every Learn view renders a tutoring turn the same way.
───────────────────────────────────────────── */

/* Accommodation notice. Shown to the STUDENT, inline, above the conversation.
   It names the SUPPORT being delivered ("extended time"), never the reason it
   exists: IEP and disability status stay in the accommodations layer. Teal, not
   pink, on purpose. Pink is the staff-side IEP flag; a student's own view of
   their supports should read as ordinary, not as a clinical marker. */
.acc-banner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-sm);
  background: var(--teal-light);
  border: 1px solid var(--teal);
  border-left: 4px solid var(--teal);
  border-radius: var(--radius-md);
  padding: .7rem .95rem;
  margin-bottom: var(--space-lg);
  font-size: .85rem;
  color: var(--text);
}
.acc-banner__label {
  font-family: 'Poppins', system-ui, sans-serif;
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--teal-dark);
}
.acc-banner__item {
  background: var(--surface);
  border: 1px solid var(--teal);
  border-radius: 999px;
  padding: .15rem .65rem;
  font-size: .78rem;
  font-weight: 600;
  color: var(--teal-dark);
}
.acc-banner__note { color: var(--text-soft); font-size: .8rem; }

/* Conversation log */
.tutor-log {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  min-height: 240px;
  margin-bottom: var(--space-lg);
}
.tutor-turn {
  max-width: 82%;
  padding: .8rem 1rem;
  border-radius: var(--radius-md);
  line-height: 1.6;
  animation: fadein .25s var(--ease) both;
}
.tutor-turn--tutor {
  align-self: flex-start;
  background: var(--surface);
  border: 1.5px solid var(--border);
  border-left: 4px solid var(--teal);
}
.tutor-turn--student {
  align-self: flex-end;
  background: var(--surface-2);
  border: 1.5px solid var(--border);
}
.tutor-turn__who {
  display: block;
  font-family: 'Poppins', system-ui, sans-serif;
  font-size: .66rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--label-ink);
  margin-bottom: .3rem;
}

/* Chunking: the step list a chunking accommodation turns on */
.tutor-steps {
  margin: .6rem 0 0;
  padding-left: 1.1rem;
  color: var(--text-soft);
  font-size: .88rem;
}
.tutor-steps li { margin-bottom: .25rem; }

/* Composer */
.tutor-composer {
  display: flex;
  gap: var(--space-sm);
  align-items: flex-end;
  border-top: 1.5px solid var(--border);
  padding-top: var(--space-md);
}
.tutor-input {
  flex: 1;
  font-family: 'Lora', Georgia, serif;
  font-size: .95rem;
  line-height: 1.5;
  color: var(--text);
  background: var(--surface);
  border: 1.5px solid var(--border);
  border-radius: var(--radius-md);
  padding: .65rem .85rem;
  resize: vertical;
  min-height: 48px;
}
/* Same forced-colors reasoning as the input:focus rule above, and this one
   matters more: it is the box a student types into to talk to the tutor. */
.tutor-input:focus {
  border-color: var(--teal);
  outline: 2px solid transparent;
  outline-offset: 2px;
  box-shadow: 0 0 0 3px var(--teal-light);
}

/* "Last time" recall line: the persistence made visible to the student */
.tutor-recall {
  border-left: 3px solid var(--mid);
  padding-left: .8rem;
  color: var(--label-ink);
  font-size: .84rem;
  margin-bottom: var(--space-md);
}

/* ─────────────────────────────────────────────
   DEMO PROVENANCE
   Every page that shows a student by name is showing a FICTIONAL student, and
   every one of them is served by express.static, so it is readable without a
   session. That combination is fine on its own and deliberately so: a pilot
   evaluator has to be able to look. What is not fine is a page that shows
   "Marcus T., IEP Active, Review Overdue" and gives the viewer no way to know
   it is invented, because the reasonable reading of an unlabelled roster is
   that it is real. Fall 2026 puts ~30 real students behind this UI, so the
   label has to be in place BEFORE the data can be mistaken for theirs.

   It lives here rather than on the page because it was page-local CSS on
   nova_iep_builder.html and needed to reach three more pages: copying it would
   have been four component redefinitions of the kind audit-components.js is
   currently burning down.

   Text is #78450a on --amber-light (7.11:1), the pair .tag--amber already
   ships. NOT --amber-ink, which measures 4.58:1 on this ground: it is sized
   for white-on-fill, and the margin is too thin for 11.5px text.

   Enforced by test/smoke/demo-disclaimer.js: a page carrying a roster name
   without .demo-banner fails there.
───────────────────────────────────────────── */
.demo-banner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .6rem;
  background: var(--amber-light);
  border-bottom: 1px solid var(--amber);
  color: #78450a;
  font-family: 'Poppins', system-ui, sans-serif;
  font-size: .72rem;
  font-weight: 600;
  line-height: 1.45;
  padding: .4rem 1.5rem;
  flex-shrink: 0;
}
.demo-banner strong { font-weight: 800; }
/* The qualifier: what is fictional, and what the page cannot do. Lighter weight,
   same ink, because it is the half carrying the actual promise.
   flex/min-width are not padding to satisfy the component audit: the banner is a
   flex row, and without them this span refuses to shrink below its longest
   unbroken run and pushes the row wider than the viewport. That was visible at
   375px before they were added. */
.demo-banner__note {
  flex: 1 1 auto;
  min-width: 0;
  font-weight: 500;
}
@media print { .demo-banner { display: none !important; } }

/* Read-aloud control: one per tutor turn, for the students whose IEP authorizes
   it. Sits inside .tutor-turn rather than beside it, so it travels with the text
   it reads and a screen reader meets it in the right order. See
   public/nova_speak.js for why the voice must be a local one. */
.tutor-speak {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  margin-top: .55rem;
  padding: .28rem .7rem;
  border: 1.5px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--label-ink);
  font-family: 'Poppins', system-ui, sans-serif;
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: .02em;
  cursor: pointer;
  transition: border-color .15s var(--ease), color .15s var(--ease);
}
.tutor-speak::before {
  content: '';
  width: .55rem;
  height: .55rem;
  border-radius: 50%;
  background: var(--teal);
  flex: none;
}
.tutor-speak:hover:not(:disabled) { border-color: var(--teal); color: var(--text); }
.tutor-speak:focus-visible { outline: 2px solid var(--teal); outline-offset: 2px; }
.tutor-speak[data-speaking="true"] { border-color: var(--teal); color: var(--text); }
.tutor-speak[data-speaking="true"]::before {
  border-radius: 1px;
  animation: fadein .6s var(--ease) infinite alternate;
}
.tutor-speak:disabled { cursor: not-allowed; opacity: .7; }
.tutor-speak:disabled::before { background: var(--mid); }

/* VISUALLY HIDDEN, for text that a screen reader needs and the layout does not.
   Added Sep 9 2026, because check:a11y found that eight student surfaces have no
   h1: nothing announces what page a student is on. Several of those pages carry
   their name in a logo or a banner that is an image or a styled div, and the
   heading has to exist without changing a design that is already approved.

   NOT display:none and NOT visibility:hidden, both of which remove the text from
   the accessibility tree along with the screen, which would defeat the purpose.
   The clip-path plus 1px box is the pattern that leaves it readable to assistive
   technology.

   It stays out of the way of focus: anything focusable inside one of these would
   be a keyboard trap the sighted user cannot see, so do not put controls here. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
