/* ============================================================================
   MyNurse design tokens — FINAL. Navy primary, beige accent.
   Import first, before any component stylesheet:  <link rel="stylesheet" href="/css/tokens.css">
   Theme: set data-theme="light|dark" on <html>; omit to follow the OS.
   Course binding: put data-course="<canvas id>" on any subtree; components read
   var(--c), var(--c-strong), var(--c-soft), var(--c-on-soft), var(--c-on) and
   NEVER a course name.
   Surface binding: put data-surface="2"|"3" on any container whose background is
   --color-surface-2 / --color-surface-3 (hover rows, wells, sheets, the page
   canvas). This swaps --c-mark to the -strong ramp; see "Course marks" below.

   Base values and their proofs: design/v1/design-visual.md §1.2-§1.4, §8.
   Every ratio below was recomputed with the WCAG 2.x relative-luminance formula.
   Additions in this file (course -strong, quiz, chat, practice/AI) carry their
   computed ratio inline. Requirement: text >= 4.5:1, non-text UI >= 3:1.
   Resolves reviews.md F-28 (two token systems: ux §2.1 is struck, this file wins),
   F-29 (manifest colors), F-64 (course marks off pure white), F-65, F-67.
   ============================================================================ */

:root {
  color-scheme: light;

  /* ---- ramps (extend the system here; components use the roles below) ---- */
  --navy-50:#EDF1F8; --navy-100:#D8E1F0; --navy-200:#B4C4E0; --navy-300:#86A0C9; --navy-400:#5C7CAE;
  --navy-500:#3E5D8F; --navy-600:#2F4A76; --navy-700:#22385C; --navy-800:#182A47; --navy-900:#111D33; --navy-950:#0B1424;
  --beige-50:#FAF7F1; --beige-100:#F3EDE0; --beige-200:#E9DFC9; --beige-300:#DACAA6; --beige-400:#C8B283;
  --beige-500:#B39B66; --beige-600:#957D4C; --beige-700:#76623B; --beige-800:#57482C; --beige-900:#3A301E;
  --neutral-0:#FFFFFF; --neutral-50:#F7F8FA; --neutral-100:#EEF0F4; --neutral-200:#DEE2E9; --neutral-300:#C5CBD6;
  --neutral-400:#9BA4B3; --neutral-500:#6F7A8B; --neutral-600:#545E6E; --neutral-700:#3D4554; --neutral-800:#29303C;
  --neutral-900:#181D27; --neutral-950:#0F131A;

  /* ---- surfaces ---- */
  --color-canvas:#F6F3EC;          /* page background (beige-tinted) */
  --color-surface:#FFFFFF;         /* cards, calendar grid, lists, chart surface */
  --color-surface-2:#FAF8F3;       /* hover rows, subtle sections            -> data-surface="2" */
  --color-surface-3:#F0EBE0;       /* wells, skeletons, empty-state circle   -> data-surface="3" */
  --color-scrim:rgba(11,20,36,.48);
  --color-inverse-surface:#111D33; --color-inverse-text:#F2EEE6; --color-inverse-link:#9DB8E6;

  /* ---- text ---- */
  --color-text:#171D27;            /* 16.92:1 on surface */
  --color-text-2:#48525F;          /* 7.93:1 */
  --color-text-3:#5B6677;          /* 5.81:1 on surface, 4.89:1 on surface-3 */
  --color-text-disabled:#9BA4B3;   /* 2.51:1 - exempt, WCAG 1.4.3 inactive */

  /* ---- primary (navy) ---- */
  --color-primary:#22385C; --color-on-primary:#FFFFFF;             /* 11.74 */
  --color-primary-hover:#182A47; --color-primary-pressed:#111D33;  /* 14.37 / 16.84 */
  --color-primary-soft:#E6EDF7; --color-on-primary-soft:#182A47;   /* 12.20 */
  --color-primary-soft-hover:#D8E1F0;                              /* 10.92 */
  --color-link:#2F4A76;                                            /* 8.89 */

  /* ---- accent (beige). Beige also means "AI-generated / practice" - see --color-practice-* ---- */
  --color-accent:#C8B283; --color-on-accent:#2B2416;               /* 7.43 */
  --color-accent-hover:#BFA672;                                    /* 6.52 */
  --color-accent-soft:#F3EDE0; --color-on-accent-soft:#57482C;     /* 7.60 */
  --color-accent-text:#76623B;                                     /* 5.87 surface / 5.29 canvas / 4.93 surface-3 */
  --color-accent-strong:#957D4C;                                   /* non-text indicator, 3.95 surface / 3.32 surface-3 */

  /* ---- semantic ---- */
  --color-success:#1E7A46; --color-on-success:#FFFFFF; --color-success-soft:#E4F4EA; --color-on-success-soft:#145C33;
  --color-warning:#8A5A00; --color-on-warning:#FFFFFF; --color-warning-icon:#B97A00; --color-warning-soft:#FCF1D8; --color-on-warning-soft:#6B4500;
  --color-danger:#B3261E;  --color-on-danger:#FFFFFF;  --color-danger-soft:#FCEAE8;  --color-on-danger-soft:#8C1D17;
  --color-info:#0B6B8A;    --color-on-info:#FFFFFF;    --color-info-soft:#E2F2F8;    --color-on-info-soft:#08526A;

  /* ---- lines & focus ---- */
  --color-border:#DEE2E9; --color-border-strong:#C5CBD6;  /* decorative dividers only */
  --color-border-input:#7E889A;                           /* component boundaries, 3.57 surface / 3.37 surface-2 */
  --color-focus:#2F4A76;
  --color-border-outlook:#3E5D8F;                         /* outlined Exchange events, 6.63 */
  --color-now:#B3261E;

  /* ---- courses: identity / strong / soft / on-soft / on-solid ------------
     -X          identity fill and dot. Valid ONLY on --color-surface (>=3:1 there).
     -X-strong   NEW. Same hue stepped down; >=4.5:1 on --color-surface-3, so it is
                 legal as text AND as a mark on surface-2 / surface-3 / canvas.
                 Components must not choose: use var(--c-mark), bound below.
     Base hues unchanged from visual §1.4, so the CVD all-pairs validation still holds. */
  --course-pharm:#1BA4AB; --course-pharm-strong:#0E6E73; /* 6.01 surface · 5.66 s2 · 5.05 s3 · 5.42 canvas */
  --course-pharm-soft:#D6F8FA; --course-pharm-on-soft:#005357; --course-pharm-on:#0B1424;
  --course-hcc:#AD3E85;   --course-hcc-strong:#9A3676;   /* 6.64 surface · 6.25 s2 · 5.58 s3 · 5.99 canvas */
  --course-hcc-soft:#FDEAF4;   --course-hcc-on-soft:#6C2E54;   --course-hcc-on:#FFFFFF;
  --course-clin:#83340A;  --course-clin-strong:#83340A;  /* 8.53 surface · 8.04 s2 · 7.18 s3 · 7.70 canvas (base already passes) */
  --course-clin-soft:#FDECE6;  --course-clin-on-soft:#723214;  --course-clin-on:#FFFFFF;
  --course-ebp:#9D81EC;   --course-ebp-strong:#7350CC;   /* 5.60 surface · 5.28 s2 · 4.71 s3 · 5.06 canvas */
  --course-ebp-soft:#F0EEFD;   --course-ebp-on-soft:#4B3B78;   --course-ebp-on:#0B1424;
  --course-ot:#5F7723;    --course-ot-strong:#556B1F;    /* 5.98 surface · 5.64 s2 · 5.03 s3 · 5.40 canvas */
  --course-ot-soft:#EBF5DB;    --course-ot-on-soft:#3D5000;    --course-ot-on:#FFFFFF;
  --course-pnc:#CC860E;   --course-pnc-strong:#8F5C04;   /* 5.67 surface · 5.35 s2 · 4.77 s3 · 5.12 canvas */
  --course-pnc-soft:#FDEDDB;   --course-pnc-on-soft:#633F01;   --course-pnc-on:#0B1424;
  /* Health Assessment strand (added 2026-09-22). Hue 334, chosen by search, not by eye:
     it is the one region still clear of all seven course hues AND of the semantic
     colours (success/correct, danger, warning, info, practice-beige) under protan,
     deutan and tritan simulation. Worst pair ΔE2000 7.3 (clin, tritan) vs the
     palette's own weakest 5.1. Green looked obvious and was REJECTED: ΔE 1.3 from
     --color-success for a colour-blind reader, i.e. a course stripe that reads as
     a passing grade. */
  --course-assess:#6F2A48; --course-assess-strong:#5A2139; /* 12.27 surface · 11.56 s2 · 10.32 s3 · 11.07 canvas */
  --course-assess-soft:#FBEAF1; --course-assess-on-soft:#5A2139; --course-assess-on:#FFFFFF;
  --course-commons:#5A6474; --course-commons-strong:#3D4554; /* 8.45 surface · 7.98 s2 · 7.12 s3 · 7.64 canvas */
  --course-commons-soft:#EEF0F4; --course-commons-on-soft:#3D4554; --course-commons-on:#FFFFFF;

  /* ---- quiz & practice (Prepare tab) ------------------------------------
     No new hues: correctness reuses the semantic ramp, and every state also
     carries a glyph + a text label, so colour is never the only cue (F-65).
     "missed" = a correct option the student did NOT select: same fill as
     correct, distinguished by a dashed 2px border + a different glyph. */
  --color-quiz-correct:#1E7A46;            /* = success */
  --color-quiz-correct-soft:#E4F4EA; --color-on-quiz-correct-soft:#145C33;   /* 7.06 */
  --color-quiz-correct-border:#1E7A46;                                       /* 4.69 on correct-soft */
  --color-quiz-incorrect:#B3261E;          /* = danger */
  --color-quiz-incorrect-soft:#FCEAE8; --color-on-quiz-incorrect-soft:#8C1D17; /* 7.85 */
  --color-quiz-missed-border:#1E7A46;                                        /* 4.69 on correct-soft, dashed */
  --color-quiz-unanswered:#5B6677;         /* = text-3, 5.81 on surface */
  --color-quiz-flag:#B97A00;               /* = warning-icon, 3.59 non-text */
  --color-quiz-selected-ring:#2F4A76;      /* = focus, 8.89 */
  /* Practice / AI-generated content wears beige, never grade-green (F-67). */
  --color-practice:#76623B;                /* 5.87 surface · 5.29 canvas · 4.93 surface-3 */
  --color-practice-soft:#F3EDE0; --color-on-practice-soft:#57482C;           /* 7.60 */
  --color-ai-badge:#957D4C;                /* non-text mark, 3.95 surface */

  /* ---- Cornell study guides (Prepare, 0024) --------------------------------
     Her template: navy #1F3864 with light blues #DEEBF7 / #BDD7EE on a white
     page. Navy maps onto the navy ramp (header rows and headings = navy-700,
     the deeper navy-800 for the cue question); the two blues are new tokens.
     Ratios: on-cue 11.86 on cue-bg · white 11.74 on head · hl-text 13.89 on
     hl-bg · on-cue 9.66 on light-2 · text-3 4.80 on cue-bg · navy-700 10.61 on
     summary-bg. Rules and borders are decorative (non-text). */
  --cornell-navy:#22385C;          /* header rows, sub-headings, key terms  (= navy-700) */
  --cornell-navy-deep:#182A47;     /* the cue question                      (= navy-800) */
  --cornell-on-navy:#FFFFFF;        /* text on --cornell-head-bg */
  --cornell-head-bg:#22385C;       /* navy header rows and bands (navy-700); white 11.74 */
  --cornell-cue-bg:#DEEBF7;        /* cue cell */
  --cornell-on-cue:#182A47;
  --cornell-light-2:#BDD7EE;       /* title band, tile borders */
  --cornell-summary-bg:#EEF4FB;    /* the SUMMARY row, lighter than the cue */
  --cornell-hl-bg:#DEEBF7;         /* [[highlight]]: light blue behind navy */
  --cornell-hl-text:#111D33;
  --cornell-pearl-bg:#EEF4FB;      /* NCLEX PEARL callout */
  --cornell-pearl-bar:#22385C;
  --cornell-rule:#B4C4E0;          /* the workbook's ruled lines (decorative) */
  --cornell-border:#BDD7EE;
  --cornell-paper:#FFFFFF;         /* the page behind the table, light and print */

  /* ---- chat & presence (Group tab) --------------------------------------
     Presence dots are non-text UI: >=3:1 required against the surface they sit
     on, including hover rows (surface-2). Each dot also carries a shape:
     online = filled, idle = filled with a notch, offline = hollow ring.
     A 1.5px --color-surface ring separates the dot from an avatar photo. */
  --color-presence-online:#1E7A46;   /* 5.35 surface · 5.04 surface-2 */
  --color-presence-idle:#B97A00;     /* 3.59 surface · 3.38 surface-2 */
  --color-presence-offline:#7E889A;  /* 3.57 surface · 3.37 surface-2, rendered hollow */
  --color-presence-ring:var(--color-surface);
  --color-mention-soft:#FBF0D9;      /* message that @-mentions you: bg */
  --color-on-mention-soft:#171D27;   /* 14.96 on mention-soft */
  --color-mention-bar:#957D4C;       /* 3.49 on mention-soft, 3px left bar, non-text */
  --color-bubble-own:#E6EDF7;        /* = primary-soft */
  --color-on-bubble-own:#182A47;     /* 12.20 */
  --color-unread-divider:#B3261E;    /* = danger, 6.54 on surface; label is text + line */
  --color-typing:#5B6677;            /* = text-3, 5.81 */

  /* ---- charts ---- */
  --chart-surface:var(--color-surface);
  --chart-grid:var(--color-border);
  --chart-axis-text:var(--color-text-3);
  --chart-single:#3E5D8F;                 /* one-hue bars */
  --chart-deemph:#C5CBD6;                 /* non-selected series (emphasis form) */
  --chart-ord-1:#86A0C9; --chart-ord-2:#5C7CAE; --chart-ord-3:#3E5D8F; --chart-ord-4:#22385C;
  --chart-meter-track:#D8E1F0; --chart-spark:#86A0C9;
  /* Study-coverage meter (Prepare). The FILL carries the meaning (8.92 on track,
     11.74 on surface); the track is decorative, and every segment is also labelled. */
  --meter-track:#D8E1F0; --meter-fill:#22385C; --meter-fill-partial:#957D4C;

  /* ---- typography ---- */
  --font-sans:"Inter Variable",-apple-system,BlinkMacSystemFont,"SF Pro Text","Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
  --font-mono:ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  /* The type scale is relative to the root (phone pass, 2026-09-24), so a
     reader's own text-size setting reaches it; in px, a larger default font
     changed nothing. The root is 87.5% (14px at the default 16px — the size it
     always had, so every rem already in the view CSS keeps its value), and each
     step is written as its pixel size over 14: calc(16rem / 14) is 16px. */
  --text-hero:600 calc(48rem / 14)/calc(52rem / 14) var(--font-sans);     --track-hero:-0.02em;
  --text-display:600 calc(32rem / 14)/calc(40rem / 14) var(--font-sans);  --track-display:-0.015em;
  --text-h1:600 calc(24rem / 14)/calc(32rem / 14) var(--font-sans);       --track-h1:-0.01em;
  --text-h2:600 calc(20rem / 14)/calc(28rem / 14) var(--font-sans);       --track-h2:-0.005em;
  --text-h3:600 calc(16rem / 14)/calc(24rem / 14) var(--font-sans);
  --text-body-lg:400 calc(16rem / 14)/calc(24rem / 14) var(--font-sans);
  --text-body:400 calc(14rem / 14)/calc(20rem / 14) var(--font-sans);
  --text-body-sm:400 calc(13rem / 14)/calc(18rem / 14) var(--font-sans);
  --text-label:500 calc(13rem / 14)/calc(16rem / 14) var(--font-sans);    --track-label:0.01em;
  --text-caption:500 calc(12rem / 14)/calc(16rem / 14) var(--font-sans);  --track-caption:0.01em;
  --text-overline:600 calc(12rem / 14)/calc(16rem / 14) var(--font-sans); --track-overline:0.06em;

  /* ---- spacing / radius / elevation / z ---- */
  --space-0-5:2px; --space-1:4px; --space-2:8px; --space-3:12px; --space-4:16px; --space-5:20px; --space-6:24px;
  --space-8:32px; --space-10:40px; --space-12:48px; --space-16:64px;
  --gutter:16px;
  --radius-xs:4px; --radius-sm:6px; --radius-md:8px; --radius-lg:12px; --radius-xl:16px; --radius-2xl:20px; --radius-full:9999px;
  --shadow-1:0 1px 2px rgba(23,29,39,.06),0 1px 3px rgba(23,29,39,.08);
  --shadow-2:0 2px 6px rgba(23,29,39,.08),0 4px 12px rgba(23,29,39,.08);
  --shadow-3:0 6px 16px rgba(23,29,39,.12),0 2px 4px rgba(23,29,39,.06);
  --shadow-4:0 16px 40px rgba(23,29,39,.18),0 4px 8px rgba(23,29,39,.08);
  --elev-border:transparent;               /* dark mode swaps in a border */
  --z-sticky:10; --z-appbar:20; --z-fab:30; --z-drawer:40; --z-popover:50; --z-dialog:60; --z-toast:70;

  /* ---- sizes ---- */
  --size-appbar:56px; --size-tabbar:64px; --size-rail:72px; --size-sidebar:240px;
  --size-control-sm:32px; --size-control:40px; --size-control-lg:48px; --size-hit:44px;
  --size-icon-sm:16px; --size-icon:20px; --size-icon-lg:24px;
  --size-pill:22px; --size-event-min:24px;
  --size-presence:10px; --size-avatar-sm:24px; --size-avatar:32px; --size-avatar-lg:48px;

  /* ---- motion ---- */
  --dur-fast:100ms; --dur-base:180ms; --dur-slow:260ms; --dur-page:320ms;
  --ease-standard:cubic-bezier(.2,0,0,1); --ease-decel:cubic-bezier(0,0,0,1);
  --ease-accel:cubic-bezier(.3,0,1,1);    --ease-spring:cubic-bezier(.34,1.3,.64,1);

  /* ---- grading ---- */
  --grade-threshold:80;
}

/* ============ dark theme: OS preference (unless the app pinned light) ============ */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --color-canvas:#0E141F; --color-surface:#151D2B; --color-surface-2:#1C2637; --color-surface-3:#243043;
    --color-scrim:rgba(0,0,0,.6);
    --color-inverse-surface:#F2EEE6; --color-inverse-text:#171D27; --color-inverse-link:#2F4A76;
    --color-text:#F2EEE6; --color-text-2:#B7BDC9; --color-text-3:#9AA3B2; --color-text-disabled:#6E7A8E;
    --color-primary:#9DB8E6; --color-on-primary:#0B1424; --color-primary-hover:#B4C9EE; --color-primary-pressed:#C9D8F3;
    --color-primary-soft:#22385C; --color-on-primary-soft:#D8E1F0; --color-primary-soft-hover:#2F4A76; --color-link:#9DB8E6;
    --color-accent:#D8C8A6; --color-on-accent:#2B2416; --color-accent-hover:#E9DFC9;
    --color-accent-soft:#3A301E; --color-on-accent-soft:#E9DFC9; --color-accent-text:#D8C8A6; --color-accent-strong:#D8C8A6;
    --color-success:#5CC489; --color-on-success:#0B1424; --color-success-soft:#173626; --color-on-success-soft:#9FE1B9;
    --color-warning:#E8B84A; --color-on-warning:#0B1424; --color-warning-icon:#E8B84A; --color-warning-soft:#3A2E12; --color-on-warning-soft:#F4D488;
    --color-danger:#F28B84;  --color-on-danger:#0B1424;  --color-danger-soft:#44201E;  --color-on-danger-soft:#F8B4AF;
    --color-info:#5FC0DF;    --color-on-info:#0B1424;    --color-info-soft:#123444;    --color-on-info-soft:#A6DEEF;
    --color-border:#2C3849; --color-border-strong:#3D4A5F; --color-border-input:#6E7A8E; --color-focus:#9DB8E6;
    --color-border-outlook:#86A0C9; --color-now:#F28B84;

    --course-pharm:#12A6AA; --course-pharm-strong:#1CBEC3; /* 7.41 surface · 6.66 s2 · 5.83 s3 · 8.08 canvas */
    --course-pharm-soft:#0D3738; --course-pharm-on-soft:#A9E4E6; --course-pharm-on:#0B1424;
    --course-hcc:#AB3E84;   --course-hcc-strong:#DE7CB8;   /* 6.18 surface · 5.56 s2 · 4.87 s3 · 6.75 canvas */
    --course-hcc-soft:#412736;   --course-hcc-on-soft:#F5C8E1;   --course-hcc-on:#FFFFFF;
    --course-clin:#C97C6A;  --course-clin-strong:#D8917F;  /* 6.66 surface · 5.99 s2 · 5.24 s3 · 7.27 canvas */
    --course-clin-soft:#442821;  --course-clin-on-soft:#FCCABE;  --course-clin-on:#0B1424;
    --course-ebp:#8C7AD2;   --course-ebp-strong:#A292E0;   /* 6.22 surface · 5.59 s2 · 4.89 s3 · 6.78 canvas */
    --course-ebp-soft:#312C45;   --course-ebp-on-soft:#D7D1FD;   --course-ebp-on:#0B1424;
    --course-ot:#599407;    --course-ot-strong:#7DBA22;    /* 7.18 surface · 6.45 s2 · 5.65 s3 · 7.83 canvas */
    --course-ot-soft:#28351D;    --course-ot-on-soft:#C9E0B8;    --course-ot-on:#0B1424;
    --course-pnc:#866113;   --course-pnc-strong:#C0973B;   /* 6.22 surface · 5.59 s2 · 4.90 s3 · 6.79 canvas */
    --course-pnc-soft:#3C2E14;   --course-pnc-on-soft:#ECD4AB;   --course-pnc-on:#FFFFFF;
    --course-assess:#DA4E8B; --course-assess-strong:#E97BAA; /* 6.34 surface · 5.70 s2 · 4.99 s3 · 6.92 canvas */
    --course-assess-soft:#3E1F2D; --course-assess-on-soft:#F6C9DC; --course-assess-on:#0B1424;
    --course-commons:#A3ADBE; --course-commons-strong:#C3CBD8; /* 10.11 surface · 9.09 s2 · 7.95 s3 · 11.03 canvas */
    --course-commons-soft:#29303C; --course-commons-on-soft:#DEE2E9; --course-commons-on:#0B1424;

    --color-quiz-correct:#5CC489;
    --color-quiz-correct-soft:#173626; --color-on-quiz-correct-soft:#9FE1B9;   /* 8.76 */
    --color-quiz-correct-border:#5CC489;                                       /* 6.10 on correct-soft */
    --color-quiz-incorrect:#F28B84;
    --color-quiz-incorrect-soft:#44201E; --color-on-quiz-incorrect-soft:#F8B4AF; /* 8.25 */
    --color-quiz-missed-border:#5CC489;                                        /* 6.10 on correct-soft, dashed */
    --color-quiz-unanswered:#9AA3B2;                                           /* 6.64 */
    --color-quiz-flag:#E8B84A;                                                 /* 9.16 */
    --color-quiz-selected-ring:#9DB8E6;                                        /* 8.40 */
    --color-practice:#D8C8A6;                                                  /* 10.25 surface · 11.18 canvas */
    --color-practice-soft:#3A301E; --color-on-practice-soft:#E9DFC9;           /* 9.78 */
    --color-ai-badge:#D8C8A6;                                                  /* 10.25 */

    /* Cornell (0024), dark: navy-900 cue cells with light-blue text, highlight =
       light-blue text on navy-800. on-cue 12.79 on cue-bg · white 14.37 on head ·
       hl-text 8.15 on hl-bg · navy 8.40 on paper · text 13.13 on summary-bg. */
    --cornell-navy:#9DB8E6; --cornell-navy-deep:#D8E1F0; --cornell-on-navy:#FFFFFF; --cornell-head-bg:#182A47;
    --cornell-cue-bg:#111D33; --cornell-on-cue:#D8E1F0; --cornell-light-2:#22385C;
    --cornell-summary-bg:#1C2637; --cornell-hl-bg:#182A47; --cornell-hl-text:#B4C4E0;
    --cornell-pearl-bg:#1C2637; --cornell-pearl-bar:#9DB8E6;
    --cornell-rule:#3D4A5F; --cornell-border:#2C3849; --cornell-paper:#151D2B;

    --color-presence-online:#5CC489;   /* 7.82 surface · 7.03 surface-2 */
    --color-presence-idle:#E8B84A;     /* 9.16 surface · 8.23 surface-2 */
    --color-presence-offline:#6E7A8E;  /* 3.89 surface · 3.50 surface-2, hollow */
    --color-presence-ring:var(--color-surface);
    --color-mention-soft:#3A2E12; --color-on-mention-soft:#F2EEE6;             /* 11.49 */
    --color-mention-bar:#E8B84A;                                               /* 7.21 on mention-soft */
    --color-bubble-own:#22385C; --color-on-bubble-own:#D8E1F0;                 /* 8.92 */
    --color-unread-divider:#F28B84;                                            /* 7.08 */
    --color-typing:#9AA3B2;                                                    /* 6.64 */

    --chart-single:#86A0C9; --chart-deemph:#3D4554;
    --chart-ord-1:#3E5D8F; --chart-ord-2:#5C7CAE; --chart-ord-3:#86A0C9; --chart-ord-4:#B4C4E0;
    --chart-meter-track:#182A47; --chart-spark:#5C7CAE;
    --meter-track:#182A47; --meter-fill:#9DB8E6; --meter-fill-partial:#D8C8A6; /* fill 7.14 on track */
    --shadow-1:none; --shadow-2:none; --shadow-3:0 8px 24px rgba(0,0,0,.4); --shadow-4:0 16px 48px rgba(0,0,0,.55);
    --elev-border:var(--color-border);
  }
}

/* ============ dark theme: explicit app toggle (wins over the OS) ============
   Identical block. Kept duplicated rather than @import-ed so this file has no
   dependencies and one HTTP request. If you edit one, edit both; tests/test_tokens.py
   asserts the two blocks declare the same property set. */
:root[data-theme="dark"] {
  color-scheme: dark;
  --color-canvas:#0E141F; --color-surface:#151D2B; --color-surface-2:#1C2637; --color-surface-3:#243043;
  --color-scrim:rgba(0,0,0,.6);
  --color-inverse-surface:#F2EEE6; --color-inverse-text:#171D27; --color-inverse-link:#2F4A76;
  --color-text:#F2EEE6; --color-text-2:#B7BDC9; --color-text-3:#9AA3B2; --color-text-disabled:#6E7A8E;
  --color-primary:#9DB8E6; --color-on-primary:#0B1424; --color-primary-hover:#B4C9EE; --color-primary-pressed:#C9D8F3;
  --color-primary-soft:#22385C; --color-on-primary-soft:#D8E1F0; --color-primary-soft-hover:#2F4A76; --color-link:#9DB8E6;
  --color-accent:#D8C8A6; --color-on-accent:#2B2416; --color-accent-hover:#E9DFC9;
  --color-accent-soft:#3A301E; --color-on-accent-soft:#E9DFC9; --color-accent-text:#D8C8A6; --color-accent-strong:#D8C8A6;
  --color-success:#5CC489; --color-on-success:#0B1424; --color-success-soft:#173626; --color-on-success-soft:#9FE1B9;
  --color-warning:#E8B84A; --color-on-warning:#0B1424; --color-warning-icon:#E8B84A; --color-warning-soft:#3A2E12; --color-on-warning-soft:#F4D488;
  --color-danger:#F28B84;  --color-on-danger:#0B1424;  --color-danger-soft:#44201E;  --color-on-danger-soft:#F8B4AF;
  --color-info:#5FC0DF;    --color-on-info:#0B1424;    --color-info-soft:#123444;    --color-on-info-soft:#A6DEEF;
  --color-border:#2C3849; --color-border-strong:#3D4A5F; --color-border-input:#6E7A8E; --color-focus:#9DB8E6;
  --color-border-outlook:#86A0C9; --color-now:#F28B84;

  --course-pharm:#12A6AA; --course-pharm-strong:#1CBEC3;
  --course-pharm-soft:#0D3738; --course-pharm-on-soft:#A9E4E6; --course-pharm-on:#0B1424;
  --course-hcc:#AB3E84;   --course-hcc-strong:#DE7CB8;
  --course-hcc-soft:#412736;   --course-hcc-on-soft:#F5C8E1;   --course-hcc-on:#FFFFFF;
  --course-clin:#C97C6A;  --course-clin-strong:#D8917F;
  --course-clin-soft:#442821;  --course-clin-on-soft:#FCCABE;  --course-clin-on:#0B1424;
  --course-ebp:#8C7AD2;   --course-ebp-strong:#A292E0;
  --course-ebp-soft:#312C45;   --course-ebp-on-soft:#D7D1FD;   --course-ebp-on:#0B1424;
  --course-ot:#599407;    --course-ot-strong:#7DBA22;
  --course-ot-soft:#28351D;    --course-ot-on-soft:#C9E0B8;    --course-ot-on:#0B1424;
  --course-pnc:#866113;   --course-pnc-strong:#C0973B;
  --course-pnc-soft:#3C2E14;   --course-pnc-on-soft:#ECD4AB;   --course-pnc-on:#FFFFFF;
  --course-assess:#DA4E8B; --course-assess-strong:#E97BAA;
  --course-assess-soft:#3E1F2D; --course-assess-on-soft:#F6C9DC; --course-assess-on:#0B1424;
  --course-commons:#A3ADBE; --course-commons-strong:#C3CBD8;
  --course-commons-soft:#29303C; --course-commons-on-soft:#DEE2E9; --course-commons-on:#0B1424;

  --color-quiz-correct:#5CC489;
  --color-quiz-correct-soft:#173626; --color-on-quiz-correct-soft:#9FE1B9;
  --color-quiz-correct-border:#5CC489;
  --color-quiz-incorrect:#F28B84;
  --color-quiz-incorrect-soft:#44201E; --color-on-quiz-incorrect-soft:#F8B4AF;
  --color-quiz-missed-border:#5CC489;
  --color-quiz-unanswered:#9AA3B2; --color-quiz-flag:#E8B84A; --color-quiz-selected-ring:#9DB8E6;
  --color-practice:#D8C8A6; --color-practice-soft:#3A301E; --color-on-practice-soft:#E9DFC9; --color-ai-badge:#D8C8A6;
  --cornell-navy:#9DB8E6; --cornell-navy-deep:#D8E1F0; --cornell-on-navy:#FFFFFF; --cornell-head-bg:#182A47;
  --cornell-cue-bg:#111D33; --cornell-on-cue:#D8E1F0; --cornell-light-2:#22385C;
  --cornell-summary-bg:#1C2637; --cornell-hl-bg:#182A47; --cornell-hl-text:#B4C4E0;
  --cornell-pearl-bg:#1C2637; --cornell-pearl-bar:#9DB8E6;
  --cornell-rule:#3D4A5F; --cornell-border:#2C3849; --cornell-paper:#151D2B;

  --color-presence-online:#5CC489; --color-presence-idle:#E8B84A; --color-presence-offline:#6E7A8E;
  --color-presence-ring:var(--color-surface);
  --color-mention-soft:#3A2E12; --color-on-mention-soft:#F2EEE6; --color-mention-bar:#E8B84A;
  --color-bubble-own:#22385C; --color-on-bubble-own:#D8E1F0;
  --color-unread-divider:#F28B84; --color-typing:#9AA3B2;

  --chart-single:#86A0C9; --chart-deemph:#3D4554;
  --chart-ord-1:#3E5D8F; --chart-ord-2:#5C7CAE; --chart-ord-3:#86A0C9; --chart-ord-4:#B4C4E0;
  --chart-meter-track:#182A47; --chart-spark:#5C7CAE;
  --meter-track:#182A47; --meter-fill:#9DB8E6; --meter-fill-partial:#D8C8A6;
  --shadow-1:none; --shadow-2:none; --shadow-3:0 8px 24px rgba(0,0,0,.4); --shadow-4:0 16px 48px rgba(0,0,0,.55);
  --elev-border:var(--color-border);
}

/* ============ course binding by Canvas course id ============
   Components read --c / --c-strong / --c-mark / --c-soft / --c-on-soft / --c-on. */
/* Default (no course / Student Commons). Declared FIRST so the six id rules below
   win by source order at equal specificity. Never add a bare [data-course] rule
   after these - it would out-order every course. */
:root { --c:var(--course-commons); --c-strong:var(--course-commons-strong); --c-soft:var(--course-commons-soft); --c-on-soft:var(--course-commons-on-soft); --c-on:var(--course-commons-on); }
[data-course="43448"] { --c:var(--course-pharm); --c-strong:var(--course-pharm-strong); --c-soft:var(--course-pharm-soft); --c-on-soft:var(--course-pharm-on-soft); --c-on:var(--course-pharm-on); } /* Pharmacology I */
[data-course="43447"] { --c:var(--course-hcc);   --c-strong:var(--course-hcc-strong);   --c-soft:var(--course-hcc-soft);   --c-on-soft:var(--course-hcc-on-soft);   --c-on:var(--course-hcc-on); }   /* Health Care Concepts II */
[data-course="43450"] { --c:var(--course-clin);  --c-strong:var(--course-clin-strong);  --c-soft:var(--course-clin-soft);  --c-on-soft:var(--course-clin-on-soft);  --c-on:var(--course-clin-on); }  /* HCC II Clinical */
[data-course="43446"] { --c:var(--course-ebp);   --c-strong:var(--course-ebp-strong);   --c-soft:var(--course-ebp-soft);   --c-on-soft:var(--course-ebp-on-soft);   --c-on:var(--course-ebp-on); }   /* Evidence-Based Practice */
[data-course="43442"] { --c:var(--course-ot);    --c-strong:var(--course-ot-strong);    --c-soft:var(--course-ot-soft);    --c-on-soft:var(--course-ot-on-soft);    --c-on:var(--course-ot-on); }    /* Old Testament History */
[data-course="43453"] { --c:var(--course-pnc);   --c-strong:var(--course-pnc-strong);   --c-soft:var(--course-pnc-soft);   --c-on-soft:var(--course-pnc-on-soft);   --c-on:var(--course-pnc-on); }   /* Prof. Nursing Concepts II */
/* Completed SUQ-26 courses. A colour names a STRAND, not a term, so each summer course
   takes the colour of the subject it continues this term; clinical rotations keep
   their own strand as HCC II Clinical does. Health Assessment has no successor and
   gets the assess strand. Before 2026-09-22 these six had no binding at all. */
[data-course="42452"] { --c:var(--course-pnc); --c-strong:var(--course-pnc-strong); --c-soft:var(--course-pnc-soft); --c-on-soft:var(--course-pnc-on-soft); --c-on:var(--course-pnc-on); } /* Prof. Nursing Concepts I */
[data-course="42456"] { --c:var(--course-hcc); --c-strong:var(--course-hcc-strong); --c-soft:var(--course-hcc-soft); --c-on-soft:var(--course-hcc-on-soft); --c-on:var(--course-hcc-on); } /* Health Care Concepts I */
[data-course="42458"] { --c:var(--course-hcc); --c-strong:var(--course-hcc-strong); --c-soft:var(--course-hcc-soft); --c-on-soft:var(--course-hcc-on-soft); --c-on:var(--course-hcc-on); } /* HCC I Skills Lab */
[data-course="42461"] { --c:var(--course-clin); --c-strong:var(--course-clin-strong); --c-soft:var(--course-clin-soft); --c-on-soft:var(--course-clin-on-soft); --c-on:var(--course-clin-on); } /* HCC I Clinical */
[data-course="42455"] { --c:var(--course-assess); --c-strong:var(--course-assess-strong); --c-soft:var(--course-assess-soft); --c-on-soft:var(--course-assess-on-soft); --c-on:var(--course-assess-on); } /* Health Assessment */
[data-course="42453"] { --c:var(--course-assess); --c-strong:var(--course-assess-strong); --c-soft:var(--course-assess-soft); --c-on-soft:var(--course-assess-on-soft); --c-on:var(--course-assess-on); } /* Health Assessment Lab */
[data-course="31382"], [data-course=""] { --c:var(--course-commons); --c-strong:var(--course-commons-strong); --c-soft:var(--course-commons-soft); --c-on-soft:var(--course-commons-on-soft); --c-on:var(--course-commons-on); }

/* Course marks (F-64). --c-mark is what a dot, bar or solid pill paints with.
   On --color-surface the identity hue clears 3:1; anywhere else it does not, so
   the -strong ramp is swapped in automatically. Never hand-pick between them.
   Safe by default: --c-mark is the -strong ramp everywhere, and ONLY a container
   that declares data-surface="1" (i.e. its background really is --color-surface)
   opts back into the identity hue. A component that forgets the attribute is
   merely darker, never inaccessible. */
:root { --c-mark:var(--c-strong); }
[data-surface="1"] { --c-mark:var(--c); }
[data-surface="2"], [data-surface="3"] { --c-mark:var(--c-strong); }

/* ============ depth, wash and motion (ADDITIVE, 2026-09-20) ============
   Added for the visual pass. Nothing above is redefined; every value here is
   built out of tokens already declared, so all of it re-themes for free and
   none of it can break a measured contrast ratio:

   * The washes interpolate between two surfaces that ALREADY carry the same
     text colour at >=7:1 (a -soft token and --color-surface). Any colour on
     the line between two passing backgrounds passes for that same text, so a
     gradient cannot quietly drop a ratio below 4.5.
   * The lift/duration values are the 150-200ms band the visual brief asks for;
     the motion block below zeroes every --dur-* under prefers-reduced-motion
     AND under the Calm switch (data-motion="reduce"), so a component that
     animates with these is behind both switches automatically. */
:root {
  /* elevation: a card rests on --shadow-1 and steps up one on hover/focus */
  --shadow-hover:var(--shadow-2);
  --lift:-1px; --lift-lg:-2px;
  --dur-lift:160ms; --dur-enter:200ms;
  --hairline:1px solid var(--color-border);

  /* Restrained accent washes - the GPA chip, a notice, a hero.
     NOTE, and it is not a small one: a custom property substitutes the var()s
     INSIDE it at the element that DECLARES it, not at the element that uses it.
     These are declared on :root, so they bake in :root's values and inherit
     already-resolved. That is correct for the tokens below, which only ever
     change at :root (the dark blocks). It is WRONG for anything course-bound:
     a --wash-course token here would freeze the commons hue and every course
     would wash the same grey. A course wash is written out literally in the
     rule that paints it, where var(--c-soft) resolves against that element. */
  --wash-brand:linear-gradient(135deg, var(--color-primary-soft), var(--color-surface) 72%);
  --wash-accent:linear-gradient(135deg, var(--color-accent-soft), var(--color-surface) 72%);
  --wash-warn:linear-gradient(135deg, var(--color-warning-soft), var(--color-surface) 78%);
  --wash-danger:linear-gradient(135deg, var(--color-danger-soft), var(--color-surface) 78%);

  /* grid rhythm: one column on a phone, two at md, three at lg */
  --bp-md:600px; --bp-lg:900px;
}

/* ============ base ============ */
html { background:var(--color-canvas); color:var(--color-text); font:400 87.5%/calc(20rem / 14) var(--font-sans); -webkit-font-smoothing:antialiased; -webkit-text-size-adjust:100%; text-size-adjust:100%; }
body { margin:0; background:var(--color-canvas); min-height:100dvh;
       padding-inline:max(var(--gutter), env(safe-area-inset-left)) max(var(--gutter), env(safe-area-inset-right)); }
:focus-visible { outline:2px solid var(--color-focus); outline-offset:2px; border-radius:var(--radius-xs); }
::selection { background:var(--color-primary-soft); color:var(--color-on-primary-soft); }
.tabular { font-variant-numeric:tabular-nums; }
@media (min-width:600px)  { :root { --gutter:24px; } }
@media (min-width:900px)  { :root { --gutter:32px; } }
/* ============ motion: the device's preference, or her own switch ============
   Two doors to one rule. The media query is the OS "Reduce Motion" setting;
   `data-motion` is the Calm switch in Settings → Appearance (js/ui.js setMotion,
   applied before first paint by js/theme.js, stored per device in localStorage):

     (none)   auto    follow the device — the media query decides
     "reduce" calm    always still, whatever the device says
     "full"   full    animations on, even when the device asks for less

   Both roads zero the same tokens and clamp the same properties, so a component
   animating with --dur-* is behind both switches by construction. JS that
   scrolls or animates itself reads ui.js reducedMotion(), the same decision. */
@media (prefers-reduced-motion: reduce) {
  :root:not([data-motion="full"]) { --dur-fast:1ms; --dur-base:1ms; --dur-slow:1ms; --dur-page:1ms; --dur-lift:1ms; --dur-enter:1ms; }
  :root:not([data-motion="full"]) *, :root:not([data-motion="full"]) *::before, :root:not([data-motion="full"]) *::after { animation-duration:1ms !important; animation-iteration-count:1 !important; transition-duration:1ms !important; scroll-behavior:auto !important; }
}
:root[data-motion="reduce"] { --dur-fast:1ms; --dur-base:1ms; --dur-slow:1ms; --dur-page:1ms; --dur-lift:1ms; --dur-enter:1ms; }
:root[data-motion="reduce"] *, :root[data-motion="reduce"] *::before, :root[data-motion="reduce"] *::after { animation-duration:1ms !important; animation-iteration-count:1 !important; transition-duration:1ms !important; scroll-behavior:auto !important; }

/* ============ reading preferences (Settings → Appearance; this device only) ============
   Four knobs for a tired reader, each an attribute on <html> that js/theme.js
   restores before first paint and js/ui.js setReadingPref() flips live:

   * data-textsize   The root is 87.5% (14px); every step of the type scale is
                     written as its pixel size over 14, so one root change
                     scales every view at once. 112 → 15.68px, 125 → 17.5px,
                     140 → 19.6px. Browser zoom still multiplies on top.
   * data-leading    Relaxed line height: the same scale, each line ~1.5-1.9×
                     its size instead of ~1.4×, and the root line box with it.
   * data-spacing    Wide letter- and word-spacing, inherited from the root;
                     headings keep their own --track-* (tightened, not opened).
   * data-measure    A ceiling on line length for running text: paragraphs,
                     list items and the long-form bodies (notes, chat, study
                     material, the reader's notes). Cards, tables and controls
                     keep their width — only the text wraps sooner. */
html[data-textsize="112"] { font-size:98%; }
html[data-textsize="125"] { font-size:109.375%; }
html[data-textsize="140"] { font-size:122.5%; }

:root[data-leading="relaxed"] {
  --text-hero:600 calc(48rem / 14)/calc(60rem / 14) var(--font-sans);
  --text-display:600 calc(32rem / 14)/calc(46rem / 14) var(--font-sans);
  --text-h1:600 calc(24rem / 14)/calc(38rem / 14) var(--font-sans);
  --text-h2:600 calc(20rem / 14)/calc(32rem / 14) var(--font-sans);
  --text-h3:600 calc(16rem / 14)/calc(28rem / 14) var(--font-sans);
  --text-body-lg:400 calc(16rem / 14)/calc(30rem / 14) var(--font-sans);
  --text-body:400 calc(14rem / 14)/calc(26rem / 14) var(--font-sans);
  --text-body-sm:400 calc(13rem / 14)/calc(24rem / 14) var(--font-sans);
  --text-label:500 calc(13rem / 14)/calc(20rem / 14) var(--font-sans);
  --text-caption:500 calc(12rem / 14)/calc(20rem / 14) var(--font-sans);
  --text-overline:600 calc(12rem / 14)/calc(20rem / 14) var(--font-sans);
}
html[data-leading="relaxed"] { line-height:calc(26rem / 14); }

html[data-spacing="wide"] { letter-spacing:0.02em; word-spacing:0.08em; }
:root[data-spacing="wide"] { --track-hero:0; --track-display:0; --track-h1:0; --track-h2:0; --track-label:0.03em; --track-caption:0.03em; --track-overline:0.08em; }

:root[data-measure="on"] :is(p, li, dd, dt, blockquote, figcaption, .settings-row-sub, .vx-hero-sub, .vx-empty-text, .settings-note,
  .nt-md, .nt-proposal-body, .nt-rev-body, .ch-md, .ch-msg-main, .cd-msg-body, .pp-material-body, .pp-guide-body, .pp-rev-text,
  .pp-stem, .pp-opt-text, .pp-sheet-body, .rd-text, .rd-pnote-text, .lead) { max-width:68ch; }
/* Windows High Contrast: drop our colours and let the OS palette through. Every
   state below also carries a glyph + text label, which is the real fallback. */
@media (forced-colors: active) {
  .event-pill, .chip, .badge, .quiz-option, .presence, .mention, .unread-divider, .meter {
    forced-color-adjust:none; border:1px solid CanvasText; background:Canvas; color:CanvasText;
  }
  .quiz-option[data-state="correct"], .quiz-option[data-state="incorrect"],
  .quiz-option[data-state="missed"] { border-width:2px; }
  .presence[data-state="offline"] { background:Canvas; }
  .meter > .fill { background:Highlight; }
}
