/* Degree Planner V5.2 — extracted verbatim from the inline <style> block.
   ORDER IS LOAD-BEARING: the @media (max-width:768px) block must stay LAST.
   ~20 mobile rules beat their desktop counterparts on source order alone. */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
.degree-logged { margin: 12px 0; border: 1px solid var(--border-mid); border-radius: var(--radius-lg); padding: 10px 12px; }
.degree-logged summary { cursor: pointer; font-weight: 600; }
.degree-logged-row { display: flex; align-items: center; gap: 12px; padding: 8px 0; border-bottom: 1px solid var(--border-light); }
.degree-logged-row:last-child { border-bottom: 0; }
.degree-logged-description { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.degree-logged-meta { color: var(--text-secondary); font-size: 12px; margin-top: 3px; }
/* DP-137: why a logged row earns no hours, or why it still does. */
.degree-logged-note { color: var(--text-secondary); font-size: 12px; margin-top: 3px; }
.degree-logged-note.is-excluded { color: var(--warn-text); }
.degree-logged-row .btn { flex-shrink: 0; }
/* Plus Jakarta Sans, the default text face since 6.0.6. Copyright 2020 The Plus
   Jakarta Sans Project Authors, SIL Open Font License 1.1 (fonts/ holds the
   licence). One variable file covers weights 200-800 for Latin; glyphs outside
   the range (arrows, stars) fall through to system-ui. Self-hosted because the
   CSP allows font-src 'self' only, and every page preloads the file, which is
   also the reference that puts it in the release (deploy/build-static.mjs). */
@font-face {
  font-family:'Plus Jakarta Sans';
  src:url('fonts/plus-jakarta-sans-latin-wght-normal.woff2') format('woff2');
  font-weight:200 800; font-style:normal; font-display:swap;
  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;
}
:root {
  /* Rice University palette */
  --rice-blue:#002856;         /* official Rice Blue */
  --rice-blue-deep:#001a3d;    /* header/hover */
  --rice-blue-soft:#1d4b8f;    /* body accents */
  --rice-blue-bright:#2d6cdf;  /* interactive accent */
  --rice-gray-50:#f7f8fa;
  --rice-gray-100:#eef1f5;
  --rice-gray-200:#dfe4ec;
  --rice-gray-300:#c4ccd8;
  --rice-gray-400:#8a95a6;
  --rice-gray-600:#4a5568;
  --rice-gray-900:#14202f;

  --bg-primary:#ffffff;
  --bg-secondary:var(--rice-gray-50);
  --bg-tertiary:var(--rice-gray-100);
  --text-primary:var(--rice-gray-900);
  --text-secondary:#3d4a5c;
  --text-tertiary:#6b7689;
  --text-muted:#6b7689;
  --border-light:rgba(15,30,58,0.08);
  --border-mid:rgba(15,30,58,0.16);
  --border-strong:rgba(15,30,58,0.28);

  --accent:var(--rice-blue);
  --accent-bg:#e4ecf7;

  --danger-bg:#fdecec; --danger-text:#a2292a; --danger:#c53030;
  --success-bg:#e6f3e7; --success-text:#2f6b35;
  --warn-bg:#fdf1dd;   --warn-text:#7a5010;

  /* DP60 moved --radius-lg from 10px and kept its name and references. DP-125
     (owner, 2026-09-29: "less rounded corners; sharp & clean") takes the scale to
     2-4px: tags 2, controls 3, cards and dialogs 4. */
  --radius-sm:2px; --radius-md:3px; --radius-lg:4px;
  /* DP60: none, so the ~16 rules asking for a resting card/button shadow flatten
     at the token. --shadow-md/lg still lift things that actually float. */
  --shadow-sm:none;
  --shadow-md:0 4px 12px rgba(15,30,58,0.08);
  --shadow-lg:0 12px 32px rgba(15,30,58,0.14);
  --control-h:34px;   /* shared button/input height; clears the 24px tap floor */

  --font-sans:'Plus Jakarta Sans',system-ui,'Helvetica Neue',Helvetica,Arial,sans-serif;
  --font-mono:ui-monospace,SFMono-Regular,Menlo,monospace;
}
/* Views differ in height, so the scrollbar used to appear on some and not others.
   Every appearance narrowed the content box by the scrollbar width, so switching
   tabs re-flowed every card and table sideways. Reserving the gutter permanently
   makes the content width identical on every view, scrolling or not. The
   overflow-y fallback covers browsers without scrollbar-gutter. */
html { font-size:15px; overscroll-behavior:none; overflow-y:scroll; scrollbar-gutter:stable; }
/* Column flex, and the reason is the footer. #layout used to carry
   min-height:calc(100vh - 52px), which forced the grid to fill the viewport and
   then stacked the ~290px footer *below* that — so every view, however short,
   scrolled ~290px into nothing but disclaimers. Flex lets #layout take the
   leftover height instead of demanding a viewport of its own, so a short view
   has no scrollbar at all and a long one scrolls exactly its own content.
   Every other body child is display:none (scripts, closed overlays, the desktop
   mobile-nav) or position:fixed (open overlays, #notepad-root, the mode badge),
   so none of them become flex items. */
body { font-family:var(--font-sans); background:var(--bg-tertiary); color:var(--text-primary);
  min-height:100vh; display:flex; flex-direction:column;
  -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility; overscroll-behavior:none;
  /* Jakarta's proportional 1 is half the width of its 0, which crowded "0 of 1",
     "Year 1" and MATH 101. Tabular figures also line up credits and counts. */
  font-variant-numeric:tabular-nums; }
/* Controls take the browser's own face unless told otherwise, so a button without
   a font rule drew in system-ui beside Jakarta text. Zero specificity: any
   component rule that names a font still wins. */
:where(button, input, select, textarea) { font-family:inherit; }

/* DP60 keyboard floor. :where() = ZERO specificity, so every component's own
   focus rule -- including .sem-plan-title's deliberate outline:none -- outranks
   it. Keep it that way; a bare selector list here would override all of them. */
:where(a[href], button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline:2px solid var(--rice-blue); outline-offset:2px;
}

/* RICE BRAND HEADER */
#rice-brand { background:var(--rice-blue); color:#fff; height:52px; display:flex; align-items:center; padding:0 1.5rem; position:sticky; top:0; z-index:50; border-bottom:3px solid var(--rice-blue-bright); }
#rice-brand .wordmark { font-family:var(--font-sans); font-weight:700; font-size:17px; letter-spacing:.01em; color:#fff; text-decoration:none; display:flex; align-items:center; gap:10px; }
#rice-brand .shield { width:26px; height:26px; border-radius:3px; background:#fff; color:var(--rice-blue); display:grid; place-items:center; font-weight:800; font-size:13px; letter-spacing:-.02em; }
#rice-brand .divider { width:1px; height:22px; background:rgba(255,255,255,.3); margin:0 16px; }
#rice-brand .page-label { font-size:13px; color:rgba(255,255,255,.88); font-weight:400; letter-spacing:.01em; }
#rice-brand .spacer { flex:1; }
#rice-brand .brand-link { color:rgba(255,255,255,.78); font-size:12px; text-decoration:none; margin-left:18px; transition:color .12s;
  background:none; border:none; padding:0; cursor:pointer; font-family:var(--font-sans); }
#rice-brand .brand-link:hover { color:#fff; }

/* Email/inbox icon in the top-right of the brand header. */
#rice-brand .inbox-icon { position:relative; margin-left:16px; background:none; border:none; padding:6px; border-radius:var(--radius-md); color:rgba(255,255,255,.82); cursor:pointer; display:inline-flex; align-items:center; justify-content:center; transition:background .12s,color .12s; }
#rice-brand .inbox-icon:hover { background:rgba(255,255,255,.08); color:#fff; }
.inbox-badge { position:absolute; top:-2px; right:-2px; min-width:16px; height:16px; padding:0 4px; border-radius:8px; background:#c53030; color:#fff; font-size:10px; font-weight:700; line-height:1; display:flex; align-items:center; justify-content:center; box-shadow:0 0 0 2px var(--rice-blue); }

/* The rail — the sidebar's white panel and its right border — is painted by the
   grid, not by #sidebar. It used to come from stretching #sidebar to the full
   row height, and that stretch is exactly what gave position:sticky zero travel
   to work with: the nav had nowhere to stick to, so at the bottom of a long page
   it slid up under the header instead of holding still. Painting the rail here
   frees #sidebar to be its natural height and stick properly. */
#layout { display:grid; grid-template-columns:240px 1fr; flex:1 0 auto; min-width:0;
  /* Owner, 2026-10-18: the footer is a scroll-down item, never floating mid-screen
     under a short view. #layout sits in #platform-shell, a plain block, so the
     body's column flex cannot stretch it; at least one screen tall keeps the footer
     at or below the fold. align-content keeps short views' rows their own height. */
  min-height:calc(100vh - var(--app-bar-h)); align-content:start; }

/* SIDEBAR — DP-72. The rail is fixed to the viewport under the app bar, so it runs
   from the header to the bottom edge on every page height, holds still beside the
   footer, and never slides up when #layout ends before the viewport does (the old
   sticky rail was clipped by #layout's box, which is where the gap came from). It
   paints its own background and hairline; #layout only reserves the column. Short
   windows scroll the rail's own contents so Settings stays reachable. */
:root { --app-bar-h:55px; --rail-w:240px; --rail-w-collapsed:52px; }
#sidebar { position:fixed; top:var(--app-bar-h); bottom:0; left:0; width:var(--rail-w); box-sizing:border-box; z-index:40;
  display:flex; flex-direction:column; padding:1rem .75rem; background:var(--bg-primary); border-right:1px solid var(--border-light);
  overflow:hidden auto; overscroll-behavior:contain; scrollbar-width:thin; }
.sb-section { margin-bottom:1.75rem; }
.sb-section h2 { font-size:10.5px; font-weight:600; color:var(--rice-blue); letter-spacing:.12em; text-transform:uppercase; margin-bottom:.65rem; padding-left:4px; }
.nav-btn { width:100%; background:none; border:none; border-left:3px solid transparent; border-radius:0 var(--radius-md) var(--radius-md) 0; padding:9px 12px; font-size:13.5px; font-weight:500; color:var(--text-secondary); cursor:pointer; text-align:left; transition:all .12s; display:flex; align-items:center; gap:10px; }
.nav-btn:hover { background:var(--bg-secondary); color:var(--rice-blue); }
.nav-btn.active { background:var(--accent-bg); color:var(--rice-blue); border-left-color:var(--rice-blue); font-weight:600; }
.nav-btn .nav-ico { width:16px; display:inline-flex; align-items:center; justify-content:center; color:currentColor; opacity:.85; }

/* Sidebar toggle — one control, in the app bar just left of the wordmark (DP-72).
   Same place and same icon in both states; only the label/tooltip changes. */
#rice-brand .sb-toggle-btn { display:inline-flex; align-items:center; justify-content:center; flex-shrink:0;
  width:36px; height:36px; margin:0 8px 0 -10px; padding:0; border:0; border-radius:var(--radius-md);
  background:none; color:rgba(255,255,255,.82); cursor:pointer; transition:background .12s, color .12s; }
#rice-brand .sb-toggle-btn:hover { background:rgba(255,255,255,.1); color:#fff; }
#rice-brand .sb-toggle-btn svg { display:block; }
body.sb-collapsed #layout { grid-template-columns:var(--rail-w-collapsed) 1fr; }
body.sb-collapsed #sidebar { width:var(--rail-w-collapsed); padding:.75rem 4px; }
body.sb-collapsed .sb-section h2,
body.sb-collapsed .nav-label { display:none; }
body.sb-collapsed .nav-btn { padding:9px 0; justify-content:center; gap:0; }

/* Settings is secondary navigation; data controls remain mounted across saves. */
body:has(#sec-mode-badge) #sidebar { padding-bottom:52px; }
.settings-nav { margin-top:auto; color:var(--text-tertiary); position:relative; }
.settings-badge { display:inline-flex; align-items:center; justify-content:center; width:16px; height:16px;
  border-radius:50%; background:var(--danger); color:#fff; font-size:11px; font-weight:700; margin-left:auto; }
body.sb-collapsed .settings-badge { position:absolute; right:0; top:0; }
.mobile-settings { display:none; }
.settings-content { max-width:760px; }
.settings-section { padding:20px 0; border-bottom:1px solid var(--border-light); }
.settings-section:first-child { padding-top:0; }
.settings-section:last-child { border-bottom:0; }
.settings-section h2 { margin:0 0 12px; font-size:15px; font-weight:600; }
.settings-actions, .settings-links { display:flex; flex-wrap:wrap; align-items:center; gap:8px; }
.settings-editors { display:grid; gap:8px; }
.settings-editor { display:flex; align-items:center; justify-content:space-between; gap:16px;
  width:100%; min-height:48px; padding:12px 14px; border:1px solid var(--border-mid); border-radius:var(--radius-md);
  background:var(--bg-primary); color:var(--text-primary); font:500 14px var(--font-sans); text-align:left; cursor:pointer; }
.settings-editor:hover, .settings-editor:focus-visible { background:var(--bg-secondary); border-color:var(--border-strong); }
.settings-editor svg { flex-shrink:0; color:var(--text-tertiary); }
.settings-links { gap:12px 22px; }
.settings-links a { color:var(--rice-blue); font-size:13px; text-underline-offset:3px; }
.settings-note { margin:10px 0; color:var(--text-secondary); font-size:12px; line-height:1.6; overflow-wrap:anywhere; }
/* The plan export's opt-in to include rating keys (DP-133), its note aligned under the label text. */
.settings-check { display:flex; align-items:flex-start; gap:8px; margin-top:14px; font-size:13px; color:var(--text-primary); cursor:pointer; }
.settings-check input { flex:0 0 auto; width:15px; height:15px; margin:2px 0 0; accent-color:var(--rice-blue); cursor:pointer; }
.settings-error { color:var(--danger); }
.settings-section .data-io-status:empty { display:none; }

/* MAIN — explicitly the second track: the fixed rail is out of flow (DP-72), so
   without this #main would be the grid's first item and land under the rail. */
#main { grid-column:2; padding:2rem 2.25rem; min-width:0; background:var(--bg-tertiary); }
/* min-height pins the rule under the title to the same y on every view, whether
   or not that view has a toolbar-right and however tall its controls are. */
.toolbar { display:flex; align-items:flex-end; justify-content:space-between; margin-bottom:1.5rem; gap:12px; flex-wrap:wrap; padding-bottom:1rem; border-bottom:1px solid var(--border-light); min-height:64px; box-sizing:border-box; }
.toolbar-left h1 { font-size:24px; font-weight:600; letter-spacing:-.015em; color:var(--rice-blue); line-height:1.2; }
.toolbar-left p { font-size:13px; color:var(--text-tertiary); margin-top:4px; font-weight:400; }
.toolbar-right { display:flex; gap:8px; flex-wrap:wrap; align-items:center; }
.add-btn { background:var(--rice-blue); border:1px solid var(--rice-blue); border-radius:var(--radius-md); padding:8px 16px; min-height:var(--control-h); font-size:13px; font-weight:500; color:#fff; cursor:pointer; display:inline-flex; align-items:center; gap:6px; transition:all .12s; white-space:nowrap; }
/* DP60: colour carries the hover; the lift went with the resting shadow. */
.add-btn:hover { background:var(--rice-blue-deep); border-color:var(--rice-blue-deep); }
.add-btn.ghost { background:var(--bg-primary); color:var(--rice-blue); border-color:var(--border-mid); box-shadow:none; }
.add-btn.ghost:hover { background:var(--accent-bg); border-color:var(--rice-blue); }


.past-badge { font-size:10px; font-weight:600; padding:2px 8px; border-radius:var(--radius-sm); background:var(--bg-tertiary); color:var(--text-secondary); border:1px solid var(--border-light); text-transform:uppercase; letter-spacing:.04em; }
.grade-pill { font-size:11px; font-weight:700; padding:2px 9px; border-radius:var(--radius-sm); font-variant-numeric:tabular-nums; }

/* DEGREE VIEW */
/* Degree Progress header: a row of stat cards. This was briefly compressed into a
   single dense strip and reverted — the strip read as a toolbar, not as figures.
   The compression this tab needed is in the two requirement sections below. */
/* 138px, not 150: three fixed stats plus a dept GPA for each of two programs is
   five cards, and at 150px the fifth dropped to a row of its own on a 13" laptop.
   auto-fit still collapses unused tracks, so a student tracking nothing gets three
   full-width cards rather than three narrow ones. */
.deg-top { display:grid; grid-template-columns:repeat(auto-fit,minmax(138px,1fr)); gap:12px; margin-bottom:1.5rem; }
/* DP60: one hairline, no 3px navy cap, no shadow. The value is 21px, under the
   24px .toolbar-left h1 it used to tie. */
.deg-stat { background:var(--bg-primary); border:1px solid var(--border-light); border-radius:var(--radius-md); padding:.85rem 1.05rem; }
.deg-stat-label { font-size:11px; color:var(--text-tertiary); margin-bottom:4px; font-weight:500; letter-spacing:.04em; text-transform:uppercase; }
.deg-stat-val { font-size:21px; font-weight:600; color:var(--rice-blue); font-variant-numeric:tabular-nums; letter-spacing:-.01em; }
/* The unit that trails a figure — "/ 120", "programs". Same line, quieter. */
.deg-stat-of { font-size:13px; color:var(--text-tertiary); font-weight:400; }
.deg-stat-sub { font-size:11px; color:var(--text-tertiary); margin-top:3px; }
.deg-stat-bar { margin-top:8px; }


/* PROGRAM SECTIONS */
.deg-section { background:var(--bg-primary); border:1px solid var(--border-light); border-radius:var(--radius-lg); overflow:hidden; margin-bottom:12px; box-shadow:var(--shadow-sm); }
.deg-section-header { display:flex; align-items:flex-start; justify-content:space-between; flex-wrap:wrap; gap:10px; padding:14px 18px; background:var(--bg-secondary); border-bottom:1px solid var(--border-light); cursor:pointer; user-select:none; transition:background .1s; }
.deg-section-header:hover { background:var(--bg-tertiary); }
.deg-section-title { font-size:15px; font-weight:600; display:flex; align-items:center; gap:10px; color:var(--rice-blue); flex:1; min-width:0; }
.deg-section-meta { font-size:12px; color:var(--text-tertiary); display:flex; align-items:center; flex-wrap:wrap; gap:10px; flex-shrink:0; }
.deg-section-body { display:none; }
.deg-section-body.open { display:block; }

/* Graduation and Distribution Requirements are the point of this tab. DP60 kept
   the larger title, the status badge and the extra air, and dropped the 3px cap
   and the 18x2 navy bar that said the same thing twice more. */
.deg-section--primary .deg-section-header { padding:13px 18px; }
.deg-section--primary .deg-section-title { font-size:16px; gap:9px; }
.deg-section--primary { margin-bottom:18px; }

/* Break before the per-program checklists. Mirrors .my-projected-header so the
   Degree Progress and Multi-Year tabs use one idiom for the same kind of break. */
.deg-progs-header { margin:22px 0 12px; padding-top:18px; border-top:1px solid var(--border-light); }
.deg-progs-title { font-size:14px; font-weight:600; color:var(--rice-blue); letter-spacing:.06em; text-transform:uppercase; }
.deg-progs-sub { font-size:12px; color:var(--text-tertiary); margin-top:4px; line-height:1.5; }
.deg-group { padding:11px 18px; border-bottom:1px solid var(--border-light); }
.deg-group:last-child { border-bottom:none; }
/* One line per requirement — what fills it, then the count and the caret — and
   the whole line is the button (js/progress-views.js reqLineIdent). Lines are in
   sentence case; the quiet uppercase label is the section's, said once above a
   run of lines that share it. */
.deg-group-title { font-size:13px; font-weight:500; line-height:1.4; color:var(--text-primary); display:flex; align-items:center; justify-content:space-between; gap:8px; cursor:pointer; }
.deg-group-title + [id] { margin-top:8px; }
.deg-line-label { min-width:0; overflow-wrap:anywhere; }
.deg-line-label .req-line-code { font-weight:600; font-variant-numeric:tabular-nums; }
.deg-line-label .req-line-name { font-weight:400; }
.deg-group-note { font-size:11.5px; color:var(--text-tertiary); font-weight:400; text-transform:none; letter-spacing:0; }
.deg-req-section { padding:14px 18px 0; font-size:11px; font-weight:700; line-height:1.4; letter-spacing:.05em; text-transform:uppercase; color:var(--text-tertiary); }
.deg-req-section + .deg-group { padding-top:6px; }
/* Set in under the label, so a line with no section after a run reads as its own. */
.deg-group.in-section { padding-left:30px; }
.req-list { display:flex; flex-direction:column; gap:2px; }
.req-item { display:flex; align-items:flex-start; gap:8px; font-size:13px; padding:4px 0; }
.req-status { width:20px; height:20px; border-radius:50%; display:flex; align-items:center; justify-content:center; flex-shrink:0; font-size:10px; font-weight:700; margin-top:1px; background:var(--bg-tertiary); color:var(--text-tertiary); border:1.5px solid var(--border-light); }
.req-status.done { background:var(--success-bg); color:var(--success-text); border-color:var(--success-text); }
.req-sem { font-size:11px; color:var(--text-tertiary); margin-left:6px; }
.prog-badge { font-size:11px; font-weight:600; padding:3px 10px; border-radius:var(--radius-sm); letter-spacing:.02em; }
.prog-badge.done { background:var(--success-bg); color:var(--success-text); }
.prog-badge.partial { background:var(--warn-bg); color:var(--warn-text); }
.prog-badge.empty { background:var(--bg-tertiary); color:var(--text-tertiary); }
.dist-grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(180px,1fr)); gap:12px; padding:18px; }
/* DP60: the tint separates it; the border was a third frame. */
.dist-card { background:var(--bg-secondary); border-radius:var(--radius-md); padding:13px 15px; }
.dist-card-top { display:flex; align-items:center; justify-content:space-between; margin-bottom:10px; }
.dist-label { font-size:13px; font-weight:600; color:var(--rice-blue); }
.dist-count { font-size:12px; font-weight:600; font-variant-numeric:tabular-nums; }
.dist-count.done { color:var(--success-text); }
.dist-count.warn { color:var(--warn-text); }
.prog-bar-wrap { background:var(--bg-tertiary); border-radius:var(--radius-sm); height:6px; overflow:hidden; flex:1; min-width:60px; border:1px solid var(--border-light); }
.prog-bar-fill { height:100%; border-radius:var(--radius-sm); transition:width .4s; background:var(--rice-blue); }

/* GRADUATION + DISTRIBUTION REQUIREMENTS
   Six readouts per section, one line each, on a 2px rule instead of inside a card.
   The card version spent ~86px per requirement — a border, 26px of padding, a 6px
   bar and a two-line course title — to show one fraction, so the two sections that
   are the point of this tab ran to 617px together and never fit on one screen with
   the header. Rendering both markups on the same transcript at the same width
   measured 249+368px before against 157+232px after — a 37% cut with nothing
   dropped: the course titles the list used to spell out are on the codes' tooltip. */
.req-strip { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:0 28px; padding:8px 18px 14px; }
.req-stat { padding:9px 0 10px; border-top:1px solid var(--border-light); }
/* No rule above the first row — the section header already draws that line. */
.req-strip > .req-stat:nth-child(-n+3) { border-top:none; padding-top:4px; }
.req-stat-top { display:flex; align-items:baseline; justify-content:space-between; gap:10px; }
.req-stat-label { font-size:12px; font-weight:600; color:var(--rice-blue); line-height:1.35; }
.req-stat-count { font-size:11.5px; font-weight:600; font-variant-numeric:tabular-nums; white-space:nowrap; }
.req-stat-count.done { color:var(--success-text); }
.req-stat-count.warn { color:var(--warn-text); }
.req-stat-count.empty { color:var(--text-tertiary); }
.req-stat-rule { margin-top:6px; height:3px; border-radius:2px; background:var(--bg-tertiary); overflow:hidden; }
.req-stat-rule > span { display:block; height:100%; border-radius:2px; transition:width .4s; }
/* The courses that satisfied the requirement: codes on one line, full titles on
   hover. Truncated rather than wrapped so a row's height never depends on how
   long a course happens to be named. */
.req-stat-courses { display:block; margin-top:5px; font-size:11px; line-height:1.4; color:var(--text-secondary);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; cursor:default; }
.req-stat-note { display:block; margin-top:4px; font-size:10.5px; line-height:1.45; color:var(--text-tertiary); }

/* Multi-Year's "Projected Completion" runs the same six readouts in a half-width
   column, where a label and its count will not share a line. Stack them there. */
.my-req-strip { gap:0 18px; padding:0; }
.my-req-strip .req-stat-top { flex-direction:column; align-items:flex-start; gap:1px; }
.my-req-strip .req-stat-label { font-size:11px; line-height:1.3; }
/* A shortfall sentence wraps to three lines in a 110px column and drags the whole
   grid row down with it. The row keeps it as a tooltip (reqStat sets title). */
.my-req-strip .req-stat-note { display:none; }

/* CUSTOM PROGRAM BUILDER */
.prog-req-row { display:flex; gap:8px; align-items:center; margin-bottom:6px; }
.prog-req-row input { flex:1; }
.prog-req-row .btn-icon { background:none; border:none; cursor:pointer; color:var(--text-tertiary); font-size:16px; padding:0 4px; }
.prog-req-row .btn-icon:hover { color:var(--danger); }
.add-req-btn { background:none; border:1px dashed var(--border-mid); border-radius:var(--radius-md); padding:7px 12px; font-size:12px; color:var(--text-tertiary); cursor:pointer; width:100%; margin-top:4px; transition:all .12s; font-weight:500; }
.add-req-btn:hover { border-color:var(--rice-blue); color:var(--rice-blue); background:var(--accent-bg); }
.group-block { background:var(--bg-secondary); border-radius:var(--radius-md); padding:14px; margin-bottom:10px; border:1px solid var(--border-light); }
.group-block-header { display:flex; gap:8px; align-items:center; margin-bottom:10px; }
.group-block-header input { flex:1; }
.del-group-btn { background:none; border:none; cursor:pointer; color:var(--text-tertiary); font-size:14px; }
.del-group-btn:hover { color:var(--danger); }

/* MODALS */
/* Lock page scroll while any modal is open.
   The lock has to name <html>. `html` carries overflow-y:scroll above so the
   scrollbar gutter is reserved on every view — and once the root element's
   overflow is anything but `visible`, the body's overflow stops propagating to
   the viewport. So `body{overflow:hidden}` alone clipped the body box and left
   the page scrolling merrily behind every open modal. scrollbar-gutter:stable
   means flipping scroll→hidden costs no reflow, so nothing jumps.
   Only <html>: the same rule on <body> made body a scroll container, and the
   sticky #rice-brand then stuck to body instead of the viewport, so on a scrolled
   page it slid off the top behind every open modal while the fixed tabs stayed.
   The account form docked into the sign-in page is not a modal: a phone with the
   keyboard up still has to scroll to reach Sign in. */
html:has(.modal-overlay.open:not(.acct-docked)) { overflow: hidden; }
.modal-overlay { display:none; position:fixed; inset:0; background:rgba(0,20,58,.55); backdrop-filter:blur(2px); z-index:100; align-items:center; justify-content:center; padding:1rem; }
.modal-overlay.open { display:flex; }
.modal { background:var(--bg-primary); border:1px solid var(--border-mid); border-radius:var(--radius-lg); padding:1.75rem; width:100%; max-width:480px; max-height:92vh; overflow-y:auto; box-shadow:var(--shadow-lg); border-top:3px solid var(--rice-blue); }
.modal-header { display:flex; align-items:center; justify-content:space-between; margin-bottom:1.25rem; padding-bottom:.75rem; border-bottom:1px solid var(--border-light); }
.modal-header h3 { font-size:17px; font-weight:600; color:var(--rice-blue); letter-spacing:-.005em; }
.modal-close { background:none; border:none; cursor:pointer; font-size:20px; color:var(--text-tertiary); padding:0 4px; line-height:1; transition:color .12s; }
.modal-close:hover { color:var(--rice-blue); }
.field { margin-bottom:13px; }
.field label { display:block; font-size:11.5px; color:var(--text-secondary); margin-bottom:5px; font-weight:600; letter-spacing:.02em; text-transform:uppercase; }
.field input, .field select { width:100%; padding:8px 11px; min-height:var(--control-h); font-size:13px; font-family:var(--font-sans); border:1px solid var(--border-mid); border-radius:var(--radius-md); background:var(--bg-primary); color:var(--text-primary); outline:none; transition:border-color .15s, box-shadow .15s; appearance:none; }
.field input:focus, .field select:focus { border-color:var(--rice-blue); box-shadow:0 0 0 3px rgba(0,40,86,.1); }
.field .hint { font-size:11px; color:var(--text-tertiary); margin-top:4px; font-style:italic; }
.field .hint:empty { display:none; }
.field-row { display:grid; grid-template-columns:1fr 1fr; gap:10px; }
.modal-actions { display:flex; gap:8px; justify-content:space-between; margin-top:1.5rem; padding-top:1rem; border-top:1px solid var(--border-light); align-items:center; }
/* Dedicated term picker: keep both actions reachable on a narrow screen. */
.term-picker-actions, .term-picker-actions .btn-row { flex-wrap:wrap; }
.term-picker .field { min-width:0; }
.term-picker input, .term-picker select { width:100%; }
.btn-cancel { background:var(--bg-primary); border:1px solid var(--border-mid); border-radius:var(--radius-md); padding:8px 16px; min-height:var(--control-h); font-size:13px; font-weight:500; cursor:pointer; color:var(--text-secondary); transition:all .12s; font-family:var(--font-sans); }
.btn-cancel:hover { background:var(--bg-secondary); border-color:var(--border-strong); color:var(--text-primary); }
.btn-save { background:var(--rice-blue); border:1px solid var(--rice-blue); border-radius:var(--radius-md); padding:8px 20px; min-height:var(--control-h); font-size:13px; font-weight:600; cursor:pointer; color:#fff; transition:all .12s; font-family:var(--font-sans); }
.btn-save:hover { background:var(--rice-blue-deep); border-color:var(--rice-blue-deep); }
.btn-delete { background:#fff; border:1px solid var(--danger); border-radius:var(--radius-md); padding:8px 14px; min-height:var(--control-h); font-size:13px; font-weight:500; cursor:pointer; color:var(--danger); transition:all .12s; font-family:var(--font-sans); }
.btn-delete:hover { background:var(--danger); color:#fff; }
.dist-selector { display:flex; gap:6px; flex-wrap:wrap; }
.dist-pill { padding:7px 14px; border-radius:var(--radius-md); border:1px solid var(--border-mid); font-size:12px; font-weight:600; cursor:pointer; background:var(--bg-primary); color:var(--text-secondary); transition:all .12s; user-select:none; font-variant-numeric:tabular-nums; }
.dist-pill:hover { border-color:var(--rice-blue); color:var(--rice-blue); }
.dist-pill.sel-d1 { background:var(--rice-blue); color:#fff; border-color:var(--rice-blue); }
.dist-pill.sel-d2 { background:#2e7d46; color:#fff; border-color:#2e7d46; }
.dist-pill.sel-d3 { background:#a85d0a; color:#fff; border-color:#a85d0a; }
.dist-pill.sel-ad { background:#6b2c91; color:#fff; border-color:#6b2c91; }
.dist-pill.sel-fwis { background:#2f6b35; color:#fff; border-color:#2f6b35; }
.dist-pill.sel-lpap { background:#7a5010; color:#fff; border-color:#7a5010; }
.modal-divider { font-size:11px; font-weight:700; color:var(--rice-blue); text-transform:uppercase; letter-spacing:.08em; margin:18px 0 10px; padding-bottom:6px; border-bottom:1px solid var(--border-light); }
.prog-del-btn { background:none; border:none; cursor:pointer; color:var(--text-tertiary); font-size:13px; padding:4px 6px; border-radius:4px; margin-left:4px; }
.prog-del-btn:hover { color:var(--danger); background:var(--danger-bg); }

/* ── DEFAULT: mobile-only elements hidden on desktop ─────────────── */
#mobile-nav { display:none; }

/* ── MOBILE (≤768px) ─────────────────────────────────────────────── */

/* AUTOCOMPLETE */
.ac-drop { position:absolute; top:100%; left:0; right:0; background:var(--bg-primary); border:1px solid var(--border-mid); border-radius:var(--radius-md); z-index:200; max-height:260px; overflow-y:auto; box-shadow:var(--shadow-md); margin-top:4px; }
.ac-item { padding:10px 14px; cursor:pointer; font-size:13px; border-bottom:1px solid var(--border-light); display:flex; align-items:baseline; gap:10px; transition:background .08s; }
.ac-item:last-child { border-bottom:none; }
.ac-item:hover, .ac-item.active { background:var(--accent-bg); }
.ac-empty { padding:10px 14px; font-size:12px; color:var(--text-tertiary); font-style:italic; }

/* Log Course hints: the catalog description, and which tracked requirement the
   course satisfies. Both are populated from js/modals.js on a catalog pick or a
   dept+num blur, and both stay out of the layout until they have something to say. */
.p-desc-preview { display:none; font-size:12px; line-height:1.5; color:var(--text-secondary); margin-bottom:10px; padding:8px 12px; background:var(--bg-secondary); border-radius:var(--radius-md); border:1px solid var(--border-light); }
.p-desc-preview.show { display:block; }
#p-req-match { font-size:11px; line-height:1.6; margin-bottom:10px; padding:7px 12px; background:var(--accent-bg); border-radius:var(--radius-md); border:1px solid rgba(0,32,91,.15); }
.ac-code { font-variant-numeric:tabular-nums; font-weight:600; font-size:12px; color:var(--rice-blue); flex-shrink:0; }
.ac-name { color:var(--text-primary); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.ac-meta { font-size:11px; color:var(--text-tertiary); flex-shrink:0; margin-left:auto; white-space:nowrap; }
.ac-dist-tag { font-size:10px; font-weight:700; padding:2px 6px; border-radius:3px; background:var(--rice-blue); color:#fff; margin-left:4px; letter-spacing:.02em; }
.ac-status-taken { font-size:10px; font-weight:700; padding:2px 7px; border-radius:var(--radius-sm); white-space:nowrap; margin-left:4px; background:var(--success-bg); color:var(--success-text); flex-shrink:0; }
.ac-status-planned { font-size:10px; font-weight:700; padding:2px 7px; border-radius:var(--radius-sm); white-space:nowrap; margin-left:4px; background:var(--accent-bg); color:var(--rice-blue); flex-shrink:0; }
/* "no Fall 2026 section". Amber, not red: it is a caution about a published
   schedule that can be out of date, not an error and not a refusal. */
.ac-status-unoffered { font-size:10px; font-weight:600; padding:2px 7px; border-radius:var(--radius-sm); white-space:nowrap; margin-left:4px; background:var(--warn-bg); color:var(--warn-text); flex-shrink:0; }
/* "No longer offered (last offered Fall 2021)" — a fact from the schedule history,
   neutral rather than amber: logging the course is fine, it just will not run again.
   Where a planned term comes after its last offering the whole row is inert. */
.ac-status-retired { font-size:10px; font-weight:600; padding:2px 7px; border-radius:var(--radius-sm); white-space:nowrap; margin-left:4px; background:var(--bg-secondary); color:var(--text-secondary); border:1px solid var(--border-light); flex-shrink:0; }
/* A retired row's long label wraps under the title instead of past a narrow panel's edge. */
.ac-item.is-retired { flex-wrap:wrap; row-gap:4px; }
.ac-item.is-retired .ac-name { flex:1 1 0; min-width:6em; }
.ac-item.is-retired .ac-status-retired { white-space:normal; min-width:0; flex-shrink:1; }
.ac-item.is-unavailable { cursor:default; }
.ac-item.is-unavailable:hover, .ac-item.is-unavailable.active { background:transparent; }
.ac-item.is-unavailable .ac-code, .ac-item.is-unavailable .ac-name, .ac-item.is-unavailable .ac-meta { color:var(--text-tertiary); }


.ad-toggle { background:var(--bg-primary); border:1px solid var(--border-mid); border-radius:var(--radius-md); padding:7px 14px; font-size:12px; font-weight:600; cursor:pointer; color:var(--text-secondary); transition:all .12s; white-space:nowrap; }
.ad-toggle:hover { border-color:var(--rice-blue); color:var(--rice-blue); }
.ad-toggle.active { background:#6b2c91; color:#fff; border-color:#6b2c91; }


/* MULTI-YEAR PLANNER */
.my-controls { display:flex; align-items:center; gap:12px; margin-bottom:1.5rem; flex-wrap:wrap; }
/* Inside the toolbar the bottom margin is not spacing, it is 22.5px of extra
   toolbar height — which pushed the Multi-Year title down relative to every
   other view. */
.toolbar-right .my-controls { margin-bottom:0; }
.my-controls label { font-size:12px; color:var(--text-secondary); font-weight:500; }
.my-controls select { padding:7px 11px; font-size:13px; font-family:var(--font-sans); border:1px solid var(--border-mid); border-radius:var(--radius-md); background:var(--bg-primary); color:var(--text-primary); outline:none; appearance:none; cursor:pointer; transition:border-color .12s; }
.my-controls select:hover, .my-controls select:focus { border-color:var(--rice-blue); }
/* DP-11: a stack of academic-year sections, not a grid of loose cards. The two
   columns are per year (.plan-year-terms, further down), because Fall beside
   Spring is the point and an auto-fill count that follows the window width put
   Spring 2027 next to Fall 2027 at three columns — a different academic year. */
.semester-grid { display:flex; flex-direction:column; gap:22px; }
/* Column flex so the credits bar sits on the card's bottom edge. Two-up rows
   stretch cards to the tallest in the row, and a bar that stopped where the
   course list ended left a white strip under it. */
.sem-plan-card { display:flex; flex-direction:column; background:var(--bg-primary); border:1px solid var(--border-light); border-radius:var(--radius-lg); overflow:hidden; box-shadow:var(--shadow-sm); transition:box-shadow .15s, transform .1s; }
.sem-plan-card:hover { box-shadow:var(--shadow-md); }
.sem-plan-header { position:relative; isolation:isolate; min-height:44px; box-sizing:border-box; display:flex; flex-direction:column; padding:8px; background:var(--bg-secondary); border-bottom:1px solid var(--border-light); }
/* Native Enter/Space activation, with the hit area covering the whole header.
   Only the independent menu and suggestion buttons sit above that target. */
.sem-plan-title { font-size:13.5px; font-weight:600; color:var(--rice-blue);
  background:none; border:none; padding:0; margin:0; font-family:inherit; text-align:left;
  cursor:pointer; display:inline-flex; align-items:baseline; gap:3px; }
.sem-plan-title::after { content:""; position:absolute; inset:0; z-index:1; cursor:pointer; }
.sem-plan-title:hover::after { background:rgba(0,32,91,.04); box-shadow:inset 0 0 0 1px var(--border-mid); }
.sem-plan-title:focus-visible { outline:none; }
.sem-plan-title:focus-visible::after { outline:2px solid var(--rice-blue); outline-offset:-3px; }
.sem-plan-header .sem-menu-btn, .sem-plan-actions-line button { position:relative; z-index:2; }
.sem-plan-title-chev { color:var(--rice-blue-bright); font-size:20px; line-height:1; font-weight:500; margin-left:3px; }
.sem-plan-meta { flex-wrap:wrap; font-size:11px; color:var(--text-tertiary); display:flex; gap:8px; align-items:center; font-variant-numeric:tabular-nums; }
.sem-plan-body { padding:4px; flex:1 1 auto; }
/* DP-71: one compact line — handle, code, title, marks, credits, action — with
   the row's own padding as the only spacing. Titles wrap when the line is full. */
.planned-course-row { display:flex; align-items:center; gap:3px 5px; padding:3px 4px; border-radius:var(--radius-sm); font-size:12.5px; line-height:1.4; transition:background .1s; }
.planned-course-row:hover { background:var(--accent-bg); }
.planned-course-code { font-variant-numeric:tabular-nums; font-weight:600; font-size:11px; color:var(--rice-blue); min-width:68px; flex-shrink:0; }
.plan-prereq-asterisk { color:var(--warn-text); font-weight:700; margin-left:1px; }
.planned-course-name { flex:1; color:var(--text-primary); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.planned-course-cr { font-size:11px; color:var(--text-tertiary); flex-shrink:0; font-variant-numeric:tabular-nums; }
.planned-course-del { background:none; border:none; cursor:pointer; color:var(--text-tertiary); font-size:13px; padding:0 3px; opacity:0; transition:opacity .1s; }
.planned-course-row:hover .planned-course-del { opacity:1; }
.planned-course-del:hover { color:var(--danger); }
/* Touch devices: hover-reveal controls must stay visible; the drag hint describes an interaction HTML5 DnD doesn't support there */
@media (hover: none) { .planned-course-del { opacity:.55; } }
.add-planned-btn { width:100%; background:none; border:1px dashed var(--border-mid); border-radius:var(--radius-sm); padding:7px; font-size:12px; color:var(--text-tertiary); cursor:pointer; margin-top:4px; transition:all .12s; font-weight:500; }
.add-planned-btn:hover { border-color:var(--rice-blue); color:var(--rice-blue); background:var(--accent-bg); }
.sem-credits-bar { height:4px; background:var(--bg-tertiary); overflow:hidden; }
.sem-credits-fill { height:100%; background:var(--rice-blue); transition:width .3s; }
.sem-credits-fill.over { background:var(--danger); }
/* T037: one action row — context line (#plan-notice) left, the three action units right. */
.my-plan-actions { display:flex; align-items:center; justify-content:flex-start; flex-wrap:wrap; gap:4px 6px; margin:0 0 12px; padding:8px; background:var(--bg-primary); border:1px solid var(--border-light); border-radius:var(--radius-md); }
#my-plan-actions .btn { min-height:36px; font-size:12px; box-shadow:none; }
#my-plan-actions > .btn { background:transparent; border-color:transparent; }
#my-plan-actions > .btn:hover, #my-plan-actions > .btn[aria-expanded="true"] { background:#f3f3f4; border-color:transparent; }
#my-plan-actions .plan-grad-control { margin-left:auto; min-height:36px; font-size:12px; }
#my-plan-actions #plan-menu-btn { margin-left:0; width:36px; min-width:36px; height:36px; padding:0; }
.plan-years-container { padding:10px; background:#e8edf4; border:1px solid #cbd4e0; border-radius:var(--radius-lg); min-width:0; }
.plan-years-container > .plan-notice { margin:0 0 8px; }
#plan-menu-btn { margin-left:auto; }
.plan-bulk-group, .sem-sug-actions { display:flex; flex-wrap:wrap; align-items:center; gap:6px; }
.plan-bulk-group { flex:1 0 100%; padding-top:8px; margin-top:4px; border-top:1px solid var(--border-light); }
#plan-accept-all-btn { background:var(--rice-blue); border-color:var(--rice-blue); color:#fff; }
#plan-reject-all-btn { color:var(--danger-text); border-color:var(--border-strong); background:var(--bg-primary); }
.my-plan-actions > .plan-notice { flex:1 1 240px; margin:0; }
/* DP-11: the header is the top bar of the projected panel rather than a rule
   across the page, and the panel now leads the Plan view instead of trailing it —
   below a stack of academic years, a hairline divider read as the end of the page
   and the figures underneath it were easy to never reach. */
/* DP-81: same face as the rest of the page, sentence case, one modest weight step
   between label and value. The whole header is the disclosure; the trailing
   "Details ⌄" names what it opens instead of a boxed chevron shouting for it. */
.my-projected-header { margin:0; }
.my-projected-title { font-size:13px; font-weight:600; color:var(--text-primary); letter-spacing:0; text-transform:none; }
.my-projected-toggle { display:flex; align-items:center; gap:8px; width:100%; min-height:36px; padding:5px 14px;
  background:var(--bg-secondary); border:1px solid var(--border-light); border-bottom:none;
  border-radius:var(--radius-md) var(--radius-md) 0 0;
  cursor:pointer; text-align:left; font-family:var(--font-sans); color:var(--text-primary); }
.my-projected-toggle:hover { background:var(--bg-primary); }
.my-projected-toggle:focus-visible { outline:2px solid var(--rice-blue); outline-offset:2px; }
.my-projected-expand { display:inline-flex; align-items:center; justify-content:center; gap:3px;
  flex:0 0 auto; min-height:24px; margin-left:auto; padding:0 4px 0 8px; box-sizing:border-box;
  border-radius:var(--radius-sm); color:var(--text-secondary); font-size:11.5px; font-weight:500; }
.my-projected-toggle .chevron { display:block; flex:0 0 16px; width:16px; height:16px; transition:transform .15s ease; }
.my-projected-toggle .chevron.open { transform:rotate(180deg); }
.my-projected-toggle:hover .my-projected-expand { background:var(--bg-tertiary); color:var(--text-primary); }
@media (prefers-reduced-motion: reduce) { .my-projected-toggle .chevron { transition:none; } }

/* Closed by default. `.proj-detail.open` outranks `.proj-detail` on specificity,
   so this pair holds wherever either rule lands in the file. */
.proj-detail { display:none; }
.proj-detail.open { display:block; margin-top:14px; border-top:1px solid var(--border-light); }
.proj-group + .proj-group { border-top:1px solid var(--border-light); }
.proj-group-label { padding:12px 0 2px; font-size:10.5px; font-weight:700; letter-spacing:.08em;
  text-transform:uppercase; color:var(--text-tertiary); }
.proj-detail .req-strip { padding:0 0 8px; }
.proj-rows { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:0 28px; padding-bottom:8px; }
/* Run heading: the catalog title shared by the rows under it. Full-width so the
   three-column flow restarts cleanly beneath it. */
.proj-sub { grid-column:1/-1; padding:12px 0 1px; font-size:11px; font-weight:600;
  color:var(--text-tertiary); }
.proj-group-label + .proj-rows > .proj-sub:first-child { padding-top:4px; }
.proj-row { display:flex; align-items:baseline; justify-content:space-between; gap:12px;
  padding:7px 0; border-top:1px solid var(--border-light); font-size:12px; }
.proj-row-label { color:var(--text-secondary); min-width:0;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.proj-row-val { flex:0 0 auto; font-weight:700; font-variant-numeric:tabular-nums; }
.proj-row-val.done { color:var(--success-text); }
.proj-row-val.warn { color:var(--warn-text); }
/* Three tracks need ~230px each to hold two course codes plus the tally. Below
   that they drop rather than ellipsise every label. */
@media (max-width:900px) { .proj-rows { grid-template-columns:repeat(2,minmax(0,1fr)); } }
@media (max-width:560px) { .proj-rows { grid-template-columns:1fr; } }

/* Segmented two-state control (Progress: Completed / Projected). One border for
   the pair, a hairline between them — not two buttons that happen to be adjacent. */
.seg { display:inline-flex; flex:0 0 auto; border:1px solid var(--border-mid);
  border-radius:var(--ctl-r); background:var(--bg-primary); overflow:hidden; }
.seg-btn { min-height:var(--ctl-h); padding:0 13px; cursor:pointer;
  font-family:var(--font-sans); font-size:12px; font-weight:600; line-height:1;
  color:var(--text-tertiary); background:none; border:none;
  transition:background .12s, color .12s; }
.seg-btn + .seg-btn { border-left:1px solid var(--border-light); }
.seg-btn:hover { color:var(--text-primary); background:var(--bg-secondary); }
.seg-btn[aria-pressed="true"] { color:#fff; background:var(--rice-blue); }
/* DP-86: the handle is a real 24px target that is visible at rest — a mid-tone
   glyph, not a 55% ghost — with a soft hover/focus field and a distinct grab
   state. Same box in every row so handles line up down a card. */
.plan-drag-handle { display:inline-flex; align-items:center; justify-content:center; width:24px; min-height:24px; flex-shrink:0;
  border-radius:var(--radius-sm); color:var(--text-secondary); cursor:grab; font-size:12px; line-height:1;
  user-select:none; -webkit-user-select:none; opacity:1; touch-action:none; transition:background .1s, color .1s; }
.plan-drag-handle.spacer { visibility:hidden; cursor:default; }
.planned-course-row:hover .plan-drag-handle, .plan-drag-handle:hover { color:var(--text-primary); }
.plan-drag-handle:hover, .plan-drag-handle:focus-visible { background:var(--bg-tertiary); }
.plan-drag-handle:focus-visible { outline:2px solid var(--rice-blue); outline-offset:-1px; }
.plan-drag-handle:active, .planned-course-row.dragging .plan-drag-handle { cursor:grabbing; background:var(--accent-bg); color:var(--rice-blue); }
.sem-plan-header .sem-menu-btn { min-width:28px; min-height:28px; font-size:17px; color:var(--text-secondary); border-color:transparent; }
.sem-plan-header .sem-menu-btn:hover, .sem-plan-header .sem-menu-btn:focus-visible, .sem-plan-header .sem-menu-btn[aria-expanded="true"] {
  background:var(--bg-primary); color:var(--text-primary); border-color:var(--border-mid); }
/* Placement is a local card treatment; ordinary navigation stays available. */
/* Remove-semester × in the header of a user-added extra semester. Subtle by default,
   visible on card hover; danger-tinted when hovered directly. */

/* "+ Add semester" card — dashed placeholder that swaps into an inline input on click. */
.sem-add-card { display:flex; align-items:stretch; justify-content:center; background:transparent; border:2px dashed var(--border-mid); box-shadow:none; min-height:140px; padding:0; overflow:visible; transition:border-color .12s,background .12s; }
.sem-add-card:hover { border-color:var(--rice-blue); background:var(--bg-primary); box-shadow:none; }
.sem-add-card .sem-add-btn { margin:auto; min-height:var(--ctl-h); font-size:var(--ctl-fs); color:var(--text-tertiary); }
.sem-add-card:hover .sem-add-btn { color:var(--rice-blue); }

.sem-plan-card.pending-pick-target { position:relative; cursor:pointer; border-color:var(--rice-blue); background:#f0f6fc; }
.sem-plan-card.pending-pick-target .sem-plan-header { background:transparent; }
.pending-add-hint { position:absolute; inset:0; width:100%; border:0; border-radius:inherit;
  background:rgba(227,239,249,.55); color:var(--rice-blue); font:inherit; font-weight:600;
  cursor:pointer; display:grid; place-items:center; z-index:1; }
.pending-add-hint span { background:#f0f6fc; padding:6px 12px; border:1px solid #b5cbe0; border-radius:var(--radius-sm); }
/* Occupied bodies already reserve the hidden +add row. Keep the label there,
   below titles and expanded warnings; empty bodies retain their centered cue. */
.pending-pick-target .sem-plan-body:has(.planned-course-row) .pending-add-hint { place-items:end center; padding-bottom:4px; }
.pending-pick-target .sem-plan-body:has(.planned-course-row) .pending-add-hint span { padding-block:5px; }
.pending-pick-target .add-planned-btn { visibility:hidden; }
.plan-source-target { background:#f0f6fc; border-color:#b5cbe0; }
.plan-source-target .sem-plan-header { background:transparent; }
.plan-apply-all { color:var(--rice-blue); background:var(--accent-bg); border-color:#b5cbe0; font-weight:600; white-space:nowrap; }
.plan-apply-all:disabled { opacity:.65; cursor:default; }
.plan-apply-blocked { font-size:11px; color:var(--text-secondary); white-space:normal; }
.plan-bulk-label { align-self:center; padding:0 8px; font-size:12px; color:var(--text-secondary); }
#plan-bulk-group, .sem-sug-group, .sem-sug-group > .btn-group { flex-wrap:wrap; }
[data-plan-source] { cursor:grab; }
[data-plan-source]:active { cursor:grabbing; }
#adv-saved-overlay.plan-source-away { opacity:0; pointer-events:none; }
.pending-add-hint:focus-visible { outline:3px solid var(--rice-blue); outline-offset:-3px; }
/* Only prerequisite disclosures rise above the placement target. Raising every
   row button lets an occupied course title steal an Add-here click/tap. */
.pending-pick-target details,
.pending-pick-target .row-prereq-warn { position:relative; z-index:2; }
.plan-course-added { animation:planAddedFade 2.2s ease-out; }
@keyframes planAddedFade { 0%, 28% { background:#dcefe0; } 100% { background:transparent; } }
.plan-added-status { position:fixed; left:50%; bottom:80px; transform:translateX(-50%); z-index:9999;
  width:max-content; max-width:calc(100vw - 32px); padding:8px 14px; border:1px solid #9fc3a7;
  border-radius:var(--radius-sm); background:#e9f5ec; color:#244e30; box-shadow:var(--shadow-sm);
  font-size:13px; pointer-events:none; }
#plan-added-status button { pointer-events:auto; margin-left:8px; min-height:36px; white-space:normal; }
#plan-added-status button:focus-visible { outline:2px solid var(--rice-blue); outline-offset:2px; }
body:has(.modal-overlay.open) #plan-added-status,
body:has(#adv-saved-overlay[style*="display: flex"]) #plan-added-status,
body:has(#adv-compare-overlay:not(.is-hidden)) #plan-added-status,
body:has(#multiyear-view.pending-add-mode) #plan-added-status { visibility:hidden; }
@media (prefers-reduced-motion:reduce) { .plan-course-added { animation:none; background:#dcefe0; } }
.planned-course-row.dragging { opacity:0.65; }
.sem-plan-body.plan-drop-target.plan-drop-active { outline:2px dashed var(--rice-blue); outline-offset:2px; background:var(--accent-bg); }
.gap-list-collapsed {
  display: block;
  max-height: 4.6em; /* roughly 3 lines at 1.55 line-height */
  overflow: hidden;
  position: relative;
}
.gap-list-collapsed::after {
  content: "";
  text-align: right;
  position: absolute;
  bottom: 0;
  right: 0;
  width: 100%;
  height: 1.2em;
  background: linear-gradient(to bottom, transparent, var(--bg-primary));
}
/* When inside a dist-card which has bg-secondary */
.dist-card .gap-list-collapsed::after {
  background: linear-gradient(to bottom, transparent, var(--bg-secondary));
}
.gap-list-expanded {
  display: block;
  max-height: none;
}
.my-summary-row { margin-bottom:20px; display:grid; grid-template-columns:1fr; gap:12px; align-items:stretch; }
.my-summary-row:has(> .my-plan-block:nth-child(2)) { grid-template-columns:1fr 1fr; }
.my-summary-row .my-plan-block { margin-bottom:0; display:flex; flex-direction:column; min-height:0; }
.my-summary-row .my-plan-block > .dist-grid,
.my-summary-row .my-plan-block > .req-strip { flex:1; }
.my-plan-block { margin-bottom:20px; }
.my-plan-block-title { font-size:11px; font-weight:700; color:var(--rice-blue); text-transform:uppercase; letter-spacing:.08em; margin-bottom:10px; display:flex; align-items:center; gap:8px; }
.my-plan-block-title::before { content:""; width:18px; height:2px; background:var(--rice-blue); display:inline-block; }
/* Card container used in multi-year AI search */
.card { background:var(--bg-primary); border:1px solid var(--border-light); border-radius:var(--radius-lg); padding:1.1rem 1.25rem; box-shadow:var(--shadow-sm); }


/* Scrollbar polish */
::-webkit-scrollbar { width:10px; height:10px; }
::-webkit-scrollbar-track { background:var(--bg-secondary); }
::-webkit-scrollbar-thumb { background:var(--rice-gray-300); border-radius:5px; border:2px solid var(--bg-secondary); }
::-webkit-scrollbar-thumb:hover { background:var(--rice-gray-400); }

/* Settings data tools: keep the file input out of visual and keyboard flow. */
.visually-hidden { position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0 0 0 0); clip-path:inset(50%); white-space:nowrap; border:0; }
.data-io-status { flex:1 1 100%; font-size:12.5px; color:var(--text-tertiary); line-height:1.45; }
/* No reserved blank line before the first click. */
.data-io-status:empty { display:none; }
.data-io-status.ok { color:var(--success-text); }
.data-io-status.err { color:#b94a00; }

/* PLAN BUILDER (checklist) */
#plan-builder-section { margin-bottom:1.5rem; }
.pb-program { background:var(--bg-primary); border:1px solid var(--border-light); border-radius:var(--radius-lg); margin-bottom:14px; box-shadow:var(--shadow-sm); overflow:hidden; }
.pb-program-header { display:flex; align-items:flex-start; justify-content:space-between; flex-wrap:wrap; gap:10px; padding:13px 18px; background:var(--bg-secondary); border-bottom:1px solid var(--border-light); cursor:pointer; user-select:none; }
.pb-program-header:hover { background:var(--bg-tertiary); }
.pb-program-title { font-size:14.5px; font-weight:600; color:var(--rice-blue); display:flex; align-items:center; gap:8px; flex:1; min-width:0; }
.pb-program-body { display:none; }
.pb-program-body.open { display:block; }
.pb-group { padding:12px 18px; border-bottom:1px solid var(--border-light); }
.pb-group:last-child { border-bottom:none; }
.pb-group-title { font-size:12px; font-weight:600; color:var(--text-secondary); margin-bottom:8px; text-transform:uppercase; letter-spacing:.04em; display:flex; align-items:center; justify-content:space-between; gap:8px; }
.pb-group-note { font-size:11px; color:var(--text-tertiary); font-weight:400; text-transform:none; letter-spacing:0; }
/* Unified course row — used by Degree Progress, the plan-builder checklist, and the Apply
   Standard Progression picker. Same visual language everywhere: mono course code, name,
   credits, distribution tags, a subtle ⓘ hint, and an inline expandable prereq panel. */
.course-row { align-items:flex-start; gap:8px; padding:4px 8px; margin:0 -8px; border-radius:var(--radius-sm); transition:background .1s; }
.course-row:hover { background:var(--bg-secondary); }
.course-row-left { flex-shrink:0; padding-top:2px; display:flex; align-items:center; }
.course-row-right { flex-shrink:0; padding-top:2px; display:flex; align-items:center; gap:6px; }
.course-row-info { flex:1; min-width:0; cursor:pointer; }
.course-row-header { display:flex; align-items:center; gap:6px; flex-wrap:wrap; font-size:13px; }
.course-row-faded .course-row-info { opacity:.6; }
.course-warn-badge { font-size:12px; color:var(--warn-text); background:var(--warn-bg); padding:0 6px; border-radius:9px; font-weight:600; }
.pb-row-check { width:14px; height:14px; cursor:pointer; accent-color:var(--rice-blue); }
.pb-dist-tag { font-size:9px; font-weight:700; padding:1px 5px; border-radius:3px; background:#E6F1FB; color:#042C53; }
.pb-ad-tag { font-size:9px; font-weight:700; padding:1px 5px; border-radius:3px; background:#FBEAF0; color:#993556; }
/* The "+" that joins a distribution chip to an AD chip ("D1 + AD"). Was the last
   inline style left in the grid's row template. */
.pb-dist-plus { font-size:9px; font-weight:700; margin-left:2px; color:var(--text-tertiary); }
/* The prerequisite warning on a planned row. One line: it names the first missing
   course and counts the alternatives, with the full list on the title. The clamp
   is belt and braces — a course with an unusually long single option should shrink
   rather than wrap the row. */
.row-prereq-warn { color:#d63031; font-weight:700; font-size:11px; margin-left:5px; cursor:default;
  min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.row-prereq-need { font-weight:500; }
.pb-status { font-size:10px; font-weight:600; padding:2px 8px; border-radius:var(--radius-sm); text-transform:uppercase; letter-spacing:.04em; white-space:nowrap; }
.pb-status.ready { background:var(--success-bg); color:var(--success-text); }
.pb-status.taken { background:var(--accent-bg); color:var(--rice-blue); }
.pb-status.warn { background:var(--warn-bg); color:var(--warn-text); }
.pb-empty-state { padding:2rem 1rem; text-align:center; color:var(--text-tertiary); font-size:13px; }
.pb-section-title { font-size:12px; font-weight:700; color:var(--rice-blue); text-transform:uppercase; letter-spacing:.08em; margin:1.25rem 0 .65rem; display:flex; align-items:center; gap:8px; }
.pb-section-title::before { content:""; width:18px; height:2px; background:var(--rice-blue); display:inline-block; }
.pb-toolbar-info { font-size:12px; color:var(--text-tertiary); margin-bottom:8px; padding:8px 12px; background:var(--accent-bg); border-radius:var(--radius-sm); border-left:3px solid var(--rice-blue); }

/* Auto-plan result banner — replaces the raw alert() dialog. */


/* TAPPABLE REQUIREMENT ROWS (degree planner) */
.req-item.tappable { cursor:pointer; border-radius:var(--radius-sm); padding:5px 8px; margin:0 -8px; transition:background .12s; }
.req-item.tappable:hover { background:var(--accent-bg); }

/* PREREQ / DESCRIPTION PANEL */
.prereq-info-panel { display:none; margin-top:9px; padding:11px 14px; background:var(--bg-secondary); border-left:3px solid var(--rice-blue); border-radius:0 var(--radius-sm) var(--radius-sm) 0; font-size:12px; line-height:1.65; color:var(--text-secondary); }
.prereq-info-panel.open { display:block; }
.prereq-met { color:var(--success-text); font-weight:500; }
.prereq-missing { color:var(--warn-text); font-weight:500; }
.course-desc-text { font-style:italic; color:var(--text-secondary); line-height:1.55; margin-bottom:9px; padding-bottom:7px; border-bottom:1px solid var(--border-light); }
.course-info-hint { font-size:10px; color:var(--text-tertiary); font-weight:500; margin-left:4px; opacity:.7; user-select:none; }
.req-item.tappable:hover .course-info-hint { opacity:1; color:var(--rice-blue); }


/* ── INBOX MODAL (student) ─────────────────────────────────────────── */
.inbox-item { padding:12px 14px; border:1px solid var(--border-light); border-radius:var(--radius-md); background:var(--bg-primary); margin-bottom:8px; cursor:pointer; transition:border-color .12s,box-shadow .12s; }
.inbox-item:hover { border-color:var(--border-mid); box-shadow:var(--shadow-sm); }
.inbox-item.unread { border-left:3px solid var(--rice-blue-bright); background:var(--accent-bg); }
.inbox-item-head { display:flex; align-items:center; justify-content:space-between; gap:10px; margin-bottom:4px; }
.inbox-item-from { font-weight:600; font-size:13px; color:var(--text-primary); display:flex; align-items:center; gap:6px; }
.inbox-item-actions { display:flex; align-items:center; gap:8px; flex-shrink:0; }
.inbox-item-ts { font-size:11px; color:var(--text-tertiary); flex-shrink:0; }
.inbox-item-delete { background:none; border:none; padding:4px; border-radius:var(--radius-sm); color:var(--text-tertiary); cursor:pointer; display:inline-flex; align-items:center; justify-content:center; transition:background .12s,color .12s; }
.inbox-item-delete:hover { background:var(--danger-bg); color:var(--danger); }

/* Inbox tab nav (Inbox | Send) */
.inbox-tabs { display:flex; gap:2px; border-bottom:2px solid var(--border-light); margin:-4px 0 12px; }
.inbox-tab { background:none; border:none; border-bottom:2px solid transparent; margin-bottom:-2px; padding:8px 16px; font-size:13px; font-weight:500; color:var(--text-secondary); cursor:pointer; font-family:var(--font-sans); transition:color .12s; }
.inbox-tab:hover { color:var(--rice-blue); }
.inbox-tab.active { color:var(--rice-blue); border-bottom-color:var(--rice-blue); font-weight:600; }
.inbox-tab-panel[hidden] { display:none !important; }

/* Send tab: filters + advisor picker + compose */
.inbox-send-filters { display:flex; flex-wrap:wrap; gap:10px; align-items:flex-end; padding:12px 14px; background:var(--bg-secondary); border:1px solid var(--border-light); border-radius:var(--radius-md); }
.inbox-send-filter-field { display:flex; flex-direction:column; gap:3px; min-width:150px; }
.inbox-send-filter-field-grow { flex:1; min-width:180px; }
.inbox-send-filter-field label { font-size:10px; font-weight:600; color:var(--text-tertiary); letter-spacing:.06em; text-transform:uppercase; }
.inbox-send-filter-field select,
.inbox-send-filter-field input { padding:6px 9px; font-size:12.5px; font-family:var(--font-sans); border:1px solid var(--border-mid); border-radius:var(--radius-sm); background:var(--bg-primary); color:var(--text-primary); outline:none; }
.inbox-send-filter-field select:focus,
.inbox-send-filter-field input:focus { border-color:var(--rice-blue); }
.inbox-send-count { font-size:11px; color:var(--text-tertiary); }
.inbox-send-results { display:flex; flex-direction:column; gap:6px; overflow-y:auto; max-height:260px; padding-right:2px; }
.inbox-send-result { padding:9px 12px; background:var(--bg-primary); border:1px solid var(--border-light); border-radius:var(--radius-md); cursor:pointer; transition:border-color .12s,box-shadow .12s; }
.inbox-send-result:hover { border-color:var(--rice-blue); box-shadow:var(--shadow-sm); }
.inbox-send-result-head { display:flex; align-items:baseline; justify-content:space-between; gap:8px; }
.inbox-send-result-name { font-size:13px; font-weight:600; color:var(--text-primary); }
.inbox-send-result-email { font-size:11px; color:var(--text-tertiary); font-family:var(--font-mono); }
.inbox-send-result-meta { font-size:11px; color:var(--text-secondary); margin-top:3px; }
.inbox-send-result-notes { font-size:11px; color:var(--text-tertiary); margin-top:3px; font-style:italic; }

/* Compose (once an advisor is picked) */
.inbox-send-compose { display:flex; flex-direction:column; gap:6px; padding:12px 14px; background:var(--bg-secondary); border:1px solid var(--rice-blue); border-radius:var(--radius-md); }
.inbox-send-compose[hidden] { display:none !important; }
.inbox-send-compose-header { display:flex; align-items:flex-start; justify-content:space-between; gap:8px; margin-bottom:4px; }
.inbox-send-compose-to { font-size:13px; font-weight:600; color:var(--text-primary); }
.inbox-send-compose-sub { font-size:11px; color:var(--text-tertiary); margin-top:2px; }
#ist-subject { padding:7px 10px; font-size:13px; font-family:var(--font-sans); border:1px solid var(--border-mid); border-radius:var(--radius-sm); background:var(--bg-primary); color:var(--text-primary); outline:none; }
#ist-body { min-height:120px; padding:8px 10px; font-size:13px; font-family:var(--font-sans); line-height:1.55; border:1px solid var(--border-mid); border-radius:var(--radius-sm); background:var(--bg-primary); color:var(--text-primary); outline:none; resize:vertical; }
#ist-subject:focus, #ist-body:focus { border-color:var(--rice-blue); }
.inbox-send-flash { font-size:11px; color:var(--success-text); background:var(--success-bg); padding:0 10px; border-radius:var(--radius-sm); max-height:0; overflow:hidden; transition:max-height .18s,padding .18s; }
.inbox-send-flash.show { max-height:32px; padding:6px 10px; }
.inbox-item-subject { font-size:12px; font-weight:500; color:var(--text-secondary); margin-bottom:4px; }
.inbox-item-body { font-size:12.5px; color:var(--text-secondary); line-height:1.55; white-space:pre-wrap; max-height:2.6em; overflow:hidden; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; }
.inbox-item-body.expanded { max-height:none; display:block; -webkit-line-clamp:none; }
.inbox-role-tag { font-size:9px; font-weight:700; padding:2px 6px; border-radius:3px; background:var(--accent-bg); color:var(--rice-blue); letter-spacing:.04em; }

/* ── ADVISOR NOTEPAD ────────────────────────────────────────────────── */
/* The notepad + back-to-dashboard link ship inside index.html but stay hidden
   until the page is opened with ?advisor=1, which adds body.advisor-mode. */
#notepad-root { position:fixed; right:24px; bottom:24px; z-index:200; display:none; flex-direction:column; align-items:flex-end; gap:10px; pointer-events:none; width:max-content; max-width:calc(100vw - 40px); }
body.advisor-mode #notepad-root { display:flex; }
#advisor-back-link { display:none; }
body.advisor-mode #advisor-back-link { display:inline-block; }
#notepad-root > * { pointer-events:auto; }
.notepad-bubble { width:52px; height:52px; border-radius:50%; background:var(--rice-blue); color:#fff; border:none; box-shadow:var(--shadow-lg); cursor:pointer; display:grid; place-items:center; transition:transform .15s,background .15s; }
.notepad-bubble:hover { background:var(--rice-blue-deep); transform:scale(1.05); }
#notepad-panel { width:360px; max-width:calc(100vw - 40px); background:var(--bg-primary); border:1px solid var(--border-mid); border-radius:var(--radius-lg); box-shadow:var(--shadow-lg); border-top:3px solid var(--rice-blue); padding:14px 14px 12px; display:none; flex-direction:column; gap:10px; flex-shrink:0; transition:width .18s ease; }
#notepad-panel.open { display:flex; }
/* Expanded — bigger writing space without going full-screen. Scales textarea too. */
#notepad-panel.expanded { width:min(720px, calc(100vw - 40px)); }
#notepad-panel.expanded #notepad-textarea { min-height:min(420px, 55vh); max-height:min(560px, 65vh); }
.notepad-header { display:flex; align-items:flex-start; justify-content:space-between; gap:8px; }
.notepad-header-actions { display:flex; align-items:center; gap:2px; }
.notepad-title { font-size:13px; font-weight:700; color:var(--rice-blue); letter-spacing:.02em; }
.notepad-sub { font-size:10.5px; color:var(--text-tertiary); margin-top:2px; }
.notepad-icon-btn { background:none; border:none; color:var(--text-tertiary); cursor:pointer; padding:4px 6px; border-radius:var(--radius-sm); display:inline-flex; align-items:center; justify-content:center; line-height:1; transition:background .12s,color .12s; }
.notepad-icon-btn:hover { background:var(--bg-secondary); color:var(--rice-blue); }
.notepad-close { font-size:20px; }
/* Swap between expand / collapse icons based on panel state. */
#notepad-panel .notepad-icon-collapse { display:none; }
#notepad-panel.expanded .notepad-icon-expand { display:none; }
#notepad-panel.expanded .notepad-icon-collapse { display:inline-block; }
#notepad-textarea { width:100%; min-height:160px; max-height:320px; padding:10px 12px; font-size:13px; font-family:var(--font-sans); line-height:1.55; border:1px solid var(--border-mid); border-radius:var(--radius-md); background:var(--bg-secondary); color:var(--text-primary); resize:vertical; outline:none; transition:min-height .18s ease,max-height .18s ease; }
#notepad-textarea:focus { border-color:var(--rice-blue); background:var(--bg-primary); }
.notepad-flash { font-size:11px; color:var(--success-text); background:var(--success-bg); padding:0 10px; border-radius:var(--radius-sm); max-height:0; overflow:hidden; transition:max-height .18s,padding .18s; }
.notepad-flash.show { max-height:32px; padding:6px 10px; }
.notepad-actions { display:flex; align-items:center; justify-content:flex-end; gap:8px; }

/* Advisor shell page */
#advisor-main { padding:28px 32px 60px; max-width:1100px; margin:0 auto; }
.advisor-hero h1 { font-size:22px; color:var(--rice-blue); margin-bottom:6px; }
.advisor-hero p { font-size:13px; color:var(--text-secondary); line-height:1.55; max-width:720px; }

/* Student picker on the advisor dashboard */
.advisor-student-list { margin-top:24px; }
.advisor-list-title { font-size:11px; font-weight:700; color:var(--rice-blue); letter-spacing:.08em; text-transform:uppercase; margin-bottom:10px; }
.advisor-student-item { background:var(--bg-primary); border:1px solid var(--border-light); border-radius:var(--radius-lg); margin-bottom:12px; overflow:hidden; transition:border-color .12s,box-shadow .12s; }
.advisor-student-item:hover { border-color:var(--rice-blue); box-shadow:var(--shadow-md); }
.advisor-student-row { display:flex; align-items:center; gap:14px; padding:14px 18px; cursor:pointer; }
.advisor-student-row:focus-visible { border-radius:var(--radius-lg); }
.advisor-student-avatar { width:40px; height:40px; border-radius:50%; background:var(--rice-blue); color:#fff; display:grid; place-items:center; font-weight:700; font-size:14px; letter-spacing:-.02em; flex-shrink:0; }
.advisor-student-info { display:flex; flex-direction:column; flex:1; min-width:0; }
.advisor-student-name { font-size:14px; font-weight:600; color:var(--text-primary); display:inline-flex; align-items:center; gap:8px; flex-wrap:wrap; }
.advisor-student-sub { font-size:11.5px; color:var(--text-tertiary); margin-top:2px; }
/* Request sign — small red pill next to the student name whenever they've sent a ticket. */
.advisor-request-badge { font-size:10.5px; font-weight:700; padding:2px 8px; border-radius:var(--radius-sm); background:#c53030; color:#fff; letter-spacing:.03em; }
.advisor-student-item.has-requests { border-left:3px solid #c53030; }
.advisor-requests-toggle { color:var(--danger-text); }
.advisor-requests-toggle:hover { color:var(--danger); background:var(--danger-bg); }
.advisor-request-item { padding:10px 12px; background:var(--bg-primary); border:1px solid var(--border-light); border-left:3px solid var(--danger); border-radius:var(--radius-md); margin-bottom:6px; }
.advisor-request-item:last-child { margin-bottom:0; }
.advisor-request-subject { font-size:12px; font-weight:600; color:var(--text-primary); margin:4px 0; }
.advisor-request-actions { display:flex; justify-content:flex-end; margin-top:8px; }
.advisor-student-arrow { font-size:18px; color:var(--rice-blue); flex-shrink:0; opacity:.55; transition:opacity .12s,transform .12s; }
.advisor-student-item:hover .advisor-student-arrow { opacity:1; transform:translateX(3px); }

/* Inline history toggle + panel — stays inside the same white card. */
.advisor-history-toggle { width:100%; display:flex; align-items:center; justify-content:space-between; gap:8px; padding:8px 18px; background:var(--bg-secondary); border:none; border-top:1px solid var(--border-light); cursor:pointer; font-family:inherit; font-size:11px; font-weight:600; color:var(--text-tertiary); letter-spacing:.06em; text-transform:uppercase; transition:background .12s,color .12s; }
.advisor-history-toggle:hover { background:var(--bg-tertiary); color:var(--rice-blue); }
.advisor-history-toggle-label { text-align:left; }
.advisor-history-chev { font-size:12px; color:var(--rice-blue); }
.advisor-history-content { padding:10px 18px 14px; background:var(--bg-secondary); border-top:1px solid var(--border-light); }
.advisor-history-content[hidden] { display:none !important; }
.advisor-history-empty { font-size:12px; color:var(--text-tertiary); font-style:italic; }
.advisor-history-item { padding:8px 12px; background:var(--bg-primary); border:1px solid var(--border-light); border-radius:var(--radius-md); margin-bottom:6px; }
.advisor-history-item:last-child { margin-bottom:0; }
.advisor-history-meta { display:flex; align-items:center; justify-content:space-between; gap:10px; margin-bottom:4px; }
.advisor-history-from { font-size:11.5px; font-weight:600; color:var(--rice-blue); }
.advisor-history-ts { font-size:10.5px; color:var(--text-tertiary); }
.advisor-history-body { font-size:12px; color:var(--text-secondary); line-height:1.5; white-space:pre-wrap; }

/* Advisor dashboard filter bar */
.advisor-filter-bar { display:flex; align-items:flex-end; gap:12px; flex-wrap:wrap; margin-top:24px; padding:14px 16px; background:var(--bg-primary); border:1px solid var(--border-light); border-radius:var(--radius-lg); }
.advisor-filter-field { display:flex; flex-direction:column; gap:4px; min-width:160px; }
.advisor-filter-field-grow { flex:1; min-width:220px; }
.advisor-filter-field label { font-size:10.5px; font-weight:600; color:var(--text-tertiary); letter-spacing:.06em; text-transform:uppercase; }
.advisor-filter-field select,
.advisor-filter-field input { padding:7px 10px; font-size:13px; font-family:var(--font-sans); border:1px solid var(--border-mid); border-radius:var(--radius-md); background:var(--bg-primary); color:var(--text-primary); outline:none; transition:border-color .12s; }
.advisor-filter-field select:focus,
.advisor-filter-field input:focus { border-color:var(--rice-blue); }
.advisor-empty-state { padding:20px; text-align:center; font-size:13px; color:var(--text-tertiary); font-style:italic; }

@media (max-width:640px) {
  #notepad-root { right:12px; bottom:12px; }
  #notepad-panel { width:calc(100vw - 24px); }
}

/* ── MODE BADGE ────────────────────────────────────────────────────────────
   States which data world the user is in. Bottom-LEFT on purpose: the advisor
   notepad owns bottom-right. Deliberately quiet — this is a standing fact, not
   an alert, and an alert-coloured chip on every page stops being read by week
   two. The sandbox variant is the exception and is meant to be hard to ignore. */
.sec-mode-badge {
  position:fixed; left:14px; bottom:12px; z-index:60;
  padding:4px 10px; border-radius:999px;
  background:var(--bg-primary); border:1px solid var(--border-light);
  box-shadow:var(--shadow-sm);
  font-size:10.5px; font-weight:600; letter-spacing:.05em; text-transform:uppercase;
  color:var(--text-tertiary); white-space:nowrap; pointer-events:auto; cursor:default;
  opacity:.72; transition:opacity .12s;
}
.sec-mode-badge:hover { opacity:1; }
.sec-mode-badge--sandbox {
  background:#fff6e5; border-color:#e0a72a; color:#7a5200; opacity:1;
  letter-spacing:.06em; cursor:help;   /* the sandbox variant still carries a title */
}

/* ── IDLE WARNING ──────────────────────────────────────────────────────────
   Live mode only; never rendered in demo. Top-centre and non-modal on purpose:
   it has to interrupt without stealing the click that would dismiss it, and the
   countdown has to stay readable while the user finishes a sentence. */
.sec-idle-warning {
  position:fixed; top:62px; left:50%; transform:translateX(-50%); z-index:200;
  display:flex; align-items:center; gap:14px;
  padding:9px 12px 9px 16px; border-radius:var(--radius-md);
  background:#fff6e5; border:1px solid #e0a72a; box-shadow:var(--shadow-md);
  font-size:12.5px; font-weight:500; color:#7a5200; max-width:calc(100vw - 32px);
}
.sec-idle-warning-btn {
  background:var(--rice-blue); border:1px solid var(--rice-blue); color:#fff;
  border-radius:var(--radius-sm); padding:5px 11px; cursor:pointer;
  font-family:var(--font-sans); font-size:12px; font-weight:600; white-space:nowrap;
}
.sec-idle-warning-btn:hover { background:var(--rice-blue-deep); border-color:var(--rice-blue-deep); }

@media print {
  .sec-idle-warning { display:none !important; }
  /* The plain demo chip is screen furniture — drop it. The SANDBOX warning is
     not: a printed degree audit built from mock data must say so on the paper,
     or it walks into an advising meeting looking official. */
  .sec-mode-badge:not(.sec-mode-badge--sandbox) { display:none !important; }
  .sec-mode-badge--sandbox {
    position:static; display:block; margin:0 0 10px; border-radius:4px;
    opacity:1; box-shadow:none; border:1.5px solid #000; color:#000;
    background:transparent; text-align:center; font-size:10pt; padding:6px;
  }
  /* On screen the chip is two words so it fits the gutter. On paper there is no
     tooltip to hover, so spell the warning out. */
  .sec-mode-badge--sandbox::after { content:" — NOT AN OFFICIAL ACADEMIC RECORD"; }

  #sidebar, #settings-view, .mobile-settings, .brand-link, .toolbar-right, .add-btn, .modal-overlay, #prog-search-drop, .ac-drop, #mobile-nav, .plan-drag-handle, .planned-course-del, .inbox-icon, #notepad-root,
  .courses-search, .courses-refine, .req-plan-link, .sug-act, .adv-band-divider,
  /* Added after WP-03/05/09/16 introduced them. Each is a control or a prompt:
     useless on paper, and several of them read as content once the thing that
     made them look clickable is gone. */
  .btn-cancel, #plan-notice, .add-planned-btn,
  .sem-sug-count, .btn-back,
  .prog-del-btn, .adv-page-btn, .adv-star-btn, .adv-sm-btn,
  .rev-row-btn, .courses-reset, .gap-more-link, .deg-collapse-bar,
  /* Courses is a search surface. Its filter panel, its results toolbar and the
     per-row Compare and "show more" controls are the machinery of searching; what
     is worth printing is the list of courses the search produced. The description
     prints in full rather than truncated, since "show more" is not an option on
     paper. */
  .adv-filter-box, #adv-results-toolbar, .adv-desc-toggle, .btn-mini-nowrap,
  #adv-saved-btn, #adv-compare-btn {
    display: none !important;
  }
  .adv-desc-preview { display: none !important; }
  .adv-desc-full { display: inline !important; }

  /* A printed plan is a record of what you have committed to. A suggestion is a
     proposal, and on paper — with the ✓ and ✕ that make it answerable stripped
     out by the rule above — it is indistinguishable from a course you actually
     intend to take. Printing one is a wrong answer someone could carry into an
     advising meeting, so the rows come out and a line says how many were left. */
  .planned-course-row.is-suggested { display: none !important; }
  .sug-alts { display: none !important; }
  #sem-rails { display: none !important; }
  #sem-saved, #sem-saved-notice, .sem-course-suggested, .sem-pending-title { display: none !important; }
  .print-only { display: block !important; font-size: 9pt; font-style: italic;
    color: #444; padding: 4px 10px; }
  /* background:none is load-bearing. #layout paints the 240px sidebar rail as a
     gradient on screen; with "Background graphics" enabled that prints as a grey
     stripe down the left of every page of a document whose whole purpose is to
     be printed and carried into an advising meeting. */
  #layout { display: block !important; background: none !important; min-height: 0 !important; }
  #main { padding: 0 !important; width: 100% !important; overflow: visible !important; }
  /* Undoes the screen column-flex so print sees a plain block flow. */
  body { background: #fff !important; color: #000 !important; display: block !important; }
  #site-footer { padding-left: 0 !important; }
  #rice-brand { position: static !important; border-bottom: 2px solid #000 !important; color: #000 !important; background: #fff !important; }
  #rice-brand .wordmark, #rice-brand .page-label { color: #000 !important; }
  #rice-brand .shield { border: 1px solid #000 !important; }
  #rice-brand .divider { background: #000 !important; }
  /* .stat-card, .home-card and .division-card went with My Courses and Home in
     WP-03; .course-table and .table-wrap with them. */
  .deg-stat, .dist-card, .sem-plan-card { border: 1px solid #ddd !important; box-shadow: none !important; page-break-inside: avoid; }
  .req-stat { page-break-inside: avoid; }
  /* The fill prints; the track is a background-color, which Chrome and Safari drop
     unless "Background graphics" is on. Without an outline a 0% row prints as a blank
     gap and a 30% row as a stub with no visible 100% mark — the same reason
     .prog-bar-wrap has carried a printed border since the card layout. */
  .req-stat-rule { border: 1px solid #ddd !important; height: 4px; }
  .req-stat-rule > span { print-color-adjust: exact; -webkit-print-color-adjust: exact; }
  .prog-bar-wrap { border: 1px solid #ddd !important; }
  .prog-bar-fill { print-color-adjust: exact; -webkit-print-color-adjust: exact; }
  /* The per-semester credit bar was the one track with neither half of the pair.
     Its background is the track and its fill is a background colour, so without
     these a printout with "Background graphics" off shows nothing where the bar
     is — the exact failure the two rules above were written for. */
  .sem-credits-bar { border: 1px solid #ddd !important; }
  .sem-credits-fill { print-color-adjust: exact; -webkit-print-color-adjust: exact; }
  .chevron { display: none !important; }
  a { text-decoration: none !important; color: #000 !important; }
}

.suggest-reason { font-size:10.5px; font-weight:600; padding:2px 8px; border-radius:var(--radius-sm); background:var(--accent-bg); color:var(--rice-blue); white-space:nowrap; }

/* ── COURSES (search) ────────────────────────────────────────────────── */
#courses-view { padding-bottom:40px; }
.adv-section-title { font-size:12px; font-weight:700; color:var(--rice-blue); letter-spacing:.08em; text-transform:uppercase; margin-bottom:14px; display:flex; align-items:center; gap:8px; }
.adv-section-title::before { content:""; width:18px; height:2px; background:var(--rice-blue); display:inline-block; flex-shrink:0; }
.adv-filter-box { background:var(--bg-primary); border:1px solid var(--border-light); border-radius:var(--radius-lg); padding:18px 20px; margin-bottom:20px; box-shadow:var(--shadow-sm); }
.adv-filter-grid { display:grid; grid-template-columns:1fr 1fr 1fr; gap:12px; margin-bottom:16px; }
@media(max-width:640px){ .adv-filter-grid { grid-template-columns:1fr; } }
.adv-filter-label { font-size:11px; font-weight:700; color:var(--text-secondary); display:block; margin-bottom:4px; text-transform:uppercase; letter-spacing:.04em; }
.adv-filter-input { width:100%; padding:7px 10px; font-size:13px; border:1px solid var(--border-mid); border-radius:var(--radius-md); background:var(--bg-primary); color:var(--text-primary); box-sizing:border-box; }
.adv-dist-pill { padding:6px 14px; font-size:12px; font-weight:500; border:1px solid var(--border-mid); border-radius:var(--radius-md); cursor:pointer; background:var(--bg-primary); color:var(--rice-blue); transition:all .12s; user-select:none; box-shadow:var(--shadow-sm); white-space:nowrap; }
.adv-dist-pill:hover { background:var(--accent-bg); border-color:var(--rice-blue); }
.adv-dist-pill.active { background:var(--rice-blue); color:#fff; border-color:var(--rice-blue); box-shadow:var(--shadow-sm); }
.adv-filter-row-label { font-size:11px; font-weight:700; color:var(--text-secondary); white-space:nowrap; min-width:80px; text-transform:uppercase; letter-spacing:.04em; }
.adv-saved-row { display:flex; align-items:center; flex-wrap:wrap; gap:4px 8px; padding:5px 0; border-bottom:1px solid var(--border-light); }
.adv-saved-row:last-child { border-bottom:none; }
.adv-saved-row-info { flex:1; min-width:0; }
.adv-saved-row-remove { background:none; border:none; cursor:pointer; color:var(--text-tertiary); font-size:16px; line-height:1; padding:0 4px; }
.adv-saved-row-remove:hover { color:var(--danger); }
.adv-desc-toggle { background:none; border:none; cursor:pointer; font-size:11.5px; font-weight:600; color:var(--rice-blue); padding:0; margin-left:2px; }
.adv-desc-toggle:hover { text-decoration:underline; }
.adv-compare-empty { display:flex; flex-direction:column; gap:10px; }
.adv-compare-empty-title { font-size:13px; font-weight:600; color:var(--text-tertiary); text-align:center; padding:8px 0 4px; }
.adv-compare-slot-search { width:100%; padding:7px 10px; font-size:13px; border:1px solid var(--border-mid); border-radius:var(--radius-md); background:var(--bg-primary); color:var(--text-primary); box-sizing:border-box; }
.adv-compare-suggest { padding:5px 8px; font-size:12px; border-radius:var(--radius-sm); cursor:pointer; color:var(--text-primary); }
.adv-compare-suggest:hover { background:var(--accent-bg); color:var(--rice-blue); }
.adv-course-card { background:var(--bg-primary); border:1px solid var(--border-light); border-radius:var(--radius-lg); padding:14px 16px; margin-bottom:10px; box-shadow:var(--shadow-sm); transition:box-shadow .12s; }
.adv-course-card:hover { box-shadow:var(--shadow-md); }
.adv-course-card-header { display:flex; align-items:flex-start; gap:10px; margin-bottom:8px; }
.adv-star-btn { background:none; border:none; cursor:pointer; line-height:1; padding:2px; flex-shrink:0; color:var(--text-tertiary); transition:color .1s,transform .1s; display:inline-flex; align-items:center; }
.adv-star-btn:hover { transform:scale(1.15); }
.adv-star-btn.starred { color:#f59e0b; }
.adv-course-code { font-size:13px; font-weight:700; color:var(--rice-blue); white-space:nowrap; }
.adv-course-name { font-size:14px; font-weight:600; color:var(--text-primary); flex:1; }
.adv-course-meta { display:flex; align-items:center; gap:6px; flex-wrap:wrap; margin-left:auto; flex-shrink:0; }
.adv-course-desc { font-size:12px; color:var(--text-secondary); line-height:1.55; margin:4px 0 6px 30px; }
.adv-course-prereq { font-size:11.5px; color:var(--text-tertiary); margin-left:30px; }
.adv-course-prereq strong { color:var(--text-secondary); }
.adv-sm-btn { padding:6px 12px !important; font-size:12px !important; }
.adv-compare-overlay { position:fixed; inset:0; z-index:9999; background:rgba(0,0,0,.55); display:flex; align-items:center; justify-content:center; padding:20px; }
.adv-compare-box { background:var(--bg-primary); border-radius:var(--radius-lg); box-shadow:0 8px 40px rgba(0,0,0,.25); max-width:980px; width:100%; max-height:86vh; overflow-y:auto; padding:24px; }
.adv-compare-grid { display:grid; gap:16px; }
.adv-compare-col { background:var(--bg-secondary); border:1px solid var(--border-light); border-radius:var(--radius-md); padding:16px; }
.adv-compare-col h4 { margin:0 0 4px; font-size:14px; color:var(--rice-blue); }
/* Was an inline style plus onmouseover/onmouseout that set this.style.color. */
.adv-cmp-remove { position:absolute; top:8px; right:8px; background:none; border:none; cursor:pointer; font-size:18px; line-height:1; color:var(--text-tertiary); transition:color .12s ease; }
.adv-cmp-remove:hover, .adv-cmp-remove:focus-visible { color:var(--danger); }
.adv-compare-col .adv-compare-sub { font-size:12px; color:var(--text-tertiary); margin-bottom:10px; }
/* Prerequisites are a div: the check rows and sources are block markup, which a <p> cannot hold. */
.adv-compare-col p, .adv-compare-col .adv-compare-prereqs { font-size:12px; color:var(--text-secondary); line-height:1.55; margin:6px 0; }
.adv-queue-label { font-size:11px; color:var(--text-secondary); margin-top:4px; }


/* ══ MEETING TIMES — the section picker inside the Add-a-Class modal ══════════
   Rows are buttons, not links: they mutate the form they sit in. Times get the
   mono face because a column of them is read by scanning, and proportional
   digits make that harder than it needs to be. */
.mt-hint { font-weight:400; color:var(--text-tertiary); }
  padding:8px 12px; background:var(--bg-secondary); border-radius:var(--radius-md); }
  background:var(--bg-primary); border:1px solid var(--border-light); border-radius:var(--radius-md);
  padding:9px 12px; font-family:var(--font-sans); transition:border-color .12s, background .12s; }
.mt-when { font-variant-numeric:tabular-nums; font-size:12.5px; font-weight:600; color:var(--text-primary); }
.mt-meta { display:flex; flex-wrap:wrap; gap:4px 10px; font-size:11px; color:var(--text-tertiary); }
.mt-sec { font-variant-numeric:tabular-nums; }
.mt-open { color:var(--success-text); }
.mt-full { color:var(--danger); }
/* No cap published — a headcount, not a verdict, so it stays the neutral colour
   of the rest of the meta line rather than borrowing green or red. */
.mt-nocap { color:var(--text-tertiary); }
#f-section-notice { font-size:11.5px; line-height:1.5; color:var(--text-secondary); margin-bottom:14px;
  padding:8px 12px; background:var(--accent-bg); border:1px solid var(--border-light);
  border-radius:var(--radius-md); }

/* The read-only twin, in the Add-a-Planned-Course modal. A panel, not a picker:
   a plan records a semester, so there is nothing here to click. */
.mt-panel { margin-bottom:14px; padding:9px 12px 10px; background:var(--bg-secondary);
  border:1px solid var(--border-light); border-radius:var(--radius-md);
  font-size:11.5px; line-height:1.5; color:var(--text-secondary); }
.mt-panel-warn { background:var(--warn-bg); border-color:rgba(122,80,16,.2); }
.mt-panel-head { font-size:11px; font-weight:600; color:var(--text-secondary); margin-bottom:6px; }
/* Four rows fit whole; a fifth peeks over the edge to show there is more. Sized
   so the common case (most courses run 1–4 sections) never scrolls at all. */
.mt-panel-list { list-style:none; display:flex; flex-direction:column; gap:5px;
  margin:0 0 7px; max-height:172px; overflow-y:auto; }
.mt-panel-list li { display:flex; flex-direction:column; gap:2px; }
.mt-panel-list .mt-when { font-size:12px; }
.mt-panel > .mt-hint { display:block; font-size:10.5px; line-height:1.45; }

/* ══ ACCOUNT — header chip, modal panels ═════════════════════════════════════
   The chip is the only standing indicator of the three account states, so its
   colour has to carry meaning at a glance: neutral when signed out, amber when
   locked or in conflict, green when saved, red when a save failed. */
.account-chip { background:rgba(255,255,255,.12); border:1px solid rgba(255,255,255,.28); color:#fff;
  font-family:var(--font-sans); font-size:12px; font-weight:600; letter-spacing:.01em;
  padding:5px 12px; border-radius:100px; cursor:pointer; transition:background .12s, border-color .12s;
  max-width:180px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; flex-shrink:0; }
.account-chip:hover, .account-chip:focus-visible { background:rgba(255,255,255,.22); border-color:rgba(255,255,255,.5); }
.account-chip.ok { border-color:rgba(120,220,150,.6); }
.account-chip.locked, .account-chip.warn { background:rgba(255,196,90,.22); border-color:rgba(255,196,90,.65); }
.account-chip.err { background:rgba(255,120,110,.22); border-color:rgba(255,120,110,.7); }

.acct-p { font-size:12.5px; line-height:1.6; color:var(--text-secondary); margin:0 0 14px; }
.acct-muted { color:var(--text-tertiary); font-size:12px; }
.acct-warn { color:#b94a00; }
/* display:block matters: a <label> is inline by default, so the 14px below was
   silently doing nothing and every field sat flush against the next one. */
.acct-field { display:block; margin-bottom:14px; }
.acct-label { display:block; font-size:11px; font-weight:600; color:var(--text-secondary);
  text-transform:uppercase; letter-spacing:.05em; margin-bottom:5px; }
.acct-input { width:100%; box-sizing:border-box; padding:9px 12px; font-size:13px;
  font-family:var(--font-sans); color:var(--text-primary); background:var(--bg-primary);
  border:1px solid var(--border-mid); border-radius:var(--radius-md); transition:border-color .12s; }
.acct-input:focus { outline:none; border-color:var(--rice-blue); }
.acct-hint { font-size:11px; color:var(--text-tertiary); margin-top:5px; line-height:1.45; }
/* A hint that belongs to the field above it sits under that field, not a line
   and a half below it — .acct-field already carries 14px of its own. */
.acct-field + .acct-hint { margin-top:-9px; margin-bottom:14px; }
/* Live password feedback. Deliberately quiet — this reads while you are still
   typing, so a red banner for "you are 3 characters in" would be nagging. */
.acct-hint-ok { color:var(--success-text); }
.acct-hint-bad { color:#b94a00; }

/* The password field and its Show/Hide button share one border, so the button
   reads as part of the field rather than as an action next to it. */
.acct-pw-wrap { position:relative; display:block; }
.acct-pw-wrap .acct-input { padding-right:58px; }
.acct-reveal { position:absolute; top:50%; right:6px; transform:translateY(-50%);
  background:none; border:none; padding:4px 6px; cursor:pointer; border-radius:var(--radius-sm);
  font-family:var(--font-sans); font-size:11px; font-weight:600; letter-spacing:.03em;
  color:var(--text-tertiary); }
.acct-reveal:hover { color:var(--rice-blue); background:var(--bg-secondary); }

/* A real <form>, so Enter submits and password managers see a submission. */
.acct-form { display:block; }
/* 650k PBKDF2 iterations is a visible pause. Dim the panel so the wait reads as
   "working", not as "the button did nothing"; _acctSetBusy also sets aria-busy. */
.acct-busy { opacity:.6; transition:opacity .12s; }
.acct-check { display:flex; align-items:center; gap:8px; font-size:12.5px;
  color:var(--text-secondary); margin-bottom:14px; cursor:pointer; }
.acct-check input { margin:0; }
/* The terms box wraps to two lines: tick on the first line, text left-aligned. */
.acct-check.acct-terms { align-items:flex-start; line-height:1.45; margin:10px 0 14px; }
.acct-check.acct-terms input { flex:none; margin-top:2px; }
.acct-check.acct-terms a { color:var(--rice-blue); font-weight:600; text-underline-offset:2px; }
.acct-actions { display:flex; flex-wrap:wrap; gap:8px; margin-top:4px; }
.acct-actions + .acct-p { margin-top:14px; }
.acct-links { display:flex; flex-wrap:wrap; gap:14px; margin-top:14px;
  padding-top:12px; border-top:1px solid var(--border-light); }
.acct-link { background:none; border:none; padding:0; cursor:pointer; font-family:var(--font-sans);
  font-size:11.5px; color:var(--rice-blue); text-decoration:underline; text-underline-offset:2px; }
.acct-link:hover { color:var(--rice-blue-deep); }
.acct-link-danger { color:var(--danger); }
.acct-row { display:flex; justify-content:space-between; align-items:baseline; gap:12px;
  font-size:12.5px; padding:7px 0; border-bottom:1px solid var(--border-light); }
.acct-row .acct-label { margin:0; }
.acct-danger { margin-top:16px; padding-top:12px; border-top:1px solid var(--border-light); }
.acct-table { width:100%; border-collapse:collapse; font-size:12px; margin-bottom:14px; }
.acct-table th, .acct-table td { text-align:left; padding:6px 8px; border-bottom:1px solid var(--border-light); }
.acct-table th { font-size:10.5px; text-transform:uppercase; letter-spacing:.05em; color:var(--text-tertiary); }

/* The recovery key. Mono, large, and selectable — people transcribe this by hand
   onto paper, and an ambiguous glyph here costs someone their account. */
.acct-recovery { font-family:var(--font-mono); font-size:15px; font-weight:600; letter-spacing:.08em;
  line-height:1.9; word-break:break-all; user-select:all; text-align:center;
  padding:14px 12px; margin-bottom:14px; color:var(--text-primary);
  background:var(--bg-secondary); border:1px dashed var(--border-strong); border-radius:var(--radius-md); }

.acct-flash { font-size:12px; line-height:1.5; padding:8px 12px; margin-bottom:14px;
  border-radius:var(--radius-md); border:1px solid transparent; }
.acct-flash.ok { background:var(--success-bg); color:var(--success-text); border-color:rgba(47,107,53,.2); }
.acct-flash.err { background:var(--danger-bg); color:var(--danger-text); border-color:rgba(160,40,40,.2); }

.acct-sync-synced { color:var(--success-text); font-weight:600; }
.acct-sync-syncing, .acct-sync-pending { color:var(--text-tertiary); }
.acct-sync-conflict { color:#b94a00; font-weight:600; }
.acct-sync-error { color:var(--danger); font-weight:600; }
.acct-sync-off { color:var(--text-tertiary); }

/* Generic buttons the account panels use; the older modals have their own. */
.btn { background:var(--bg-primary); border:1px solid var(--border-mid); border-radius:var(--radius-md);
  padding:8px 16px; min-height:var(--control-h); display:inline-flex; align-items:center; justify-content:center; gap:6px;
  font-size:13px; font-weight:500; cursor:pointer; color:var(--text-secondary);
  font-family:var(--font-sans); transition:all .12s; }
.btn:hover, .btn:focus-visible { background:var(--bg-secondary); border-color:var(--border-strong); color:var(--text-primary); }
.btn-primary { background:var(--rice-blue); border-color:var(--rice-blue); color:#fff; font-weight:600; }
.btn-primary:hover { background:var(--rice-blue-deep); border-color:var(--rice-blue-deep); color:#fff; }

/* ══ SETUP ═══════════════════════════════════════════════════════════════════
   Two screens of labelled controls and nothing else (DP-20): plainer than the
   rest of the app, so the questions get the attention. */
#setup-overlay { backdrop-filter:none; top:var(--wiz-view-top, 0px); bottom:auto;
  left:var(--wiz-view-left, 0px); right:auto; width:var(--wiz-view-width, 100%);
  height:var(--wiz-view-height, 100dvh); box-sizing:border-box; padding:16px; align-items:center; }
#setup-overlay .wiz-modal { height:620px; max-height:calc(var(--wiz-view-height, 100dvh) - 32px);
  display:flex; flex-direction:column; overflow:visible; padding-bottom:0; }
#setup-overlay .modal-header { flex:0 0 auto; }
#setup-body { display:flex; flex-direction:column; min-height:0; flex:1 1 auto; }
.wiz-scroll { flex:1 1 auto; min-height:0; overflow-y:auto; overscroll-behavior:contain;
  scrollbar-gutter:stable; padding:3px; margin:0 -3px; }
.wiz-sections { flex:0 0 auto; }
.wiz-sections { display:flex; gap:4px; padding:4px; margin-bottom:20px; border-radius:var(--radius-md); background:var(--bg-secondary); }
.wiz-section { flex:1; min-height:40px; padding:8px 12px; border:1px solid transparent; border-radius:var(--radius-md);
  background:transparent; color:var(--text-secondary); font:500 13px var(--font-sans); cursor:pointer; }
.wiz-section[aria-pressed="true"] { background:var(--bg-primary); color:var(--rice-blue); border-color:var(--border-mid); font-weight:600; }
.wiz-section:hover { color:var(--rice-blue); }
.wiz-section:focus-visible { outline:2px solid var(--rice-blue); outline-offset:2px; }
.wiz-muted { color:var(--text-tertiary); }
.wiz-hint { font-size:11.5px; color:var(--text-tertiary); line-height:1.5; margin:6px 0 0; }
.wiz-optional { font-weight:400; text-transform:none; letter-spacing:0; color:var(--text-tertiary); font-size:10.5px; }

.wiz-field { display:block; margin-bottom:14px; }
.wiz-field-year .wiz-input { max-width:160px; }
.wiz-label { display:block; font-size:11px; font-weight:600; color:var(--text-secondary);
  text-transform:uppercase; letter-spacing:.05em; margin-bottom:5px; }
.wiz-input { width:100%; box-sizing:border-box; padding:8px 12px; min-height:var(--control-h); font-size:13px;
  font-family:var(--font-sans); color:var(--text-primary); background:var(--bg-primary);
  border:1px solid var(--border-mid); border-radius:var(--radius-md); transition:border-color .15s, box-shadow .15s; }
/* Setup's fields answer to focus exactly the way the modal fields do (.field). */
.wiz-input:focus { outline:none; border-color:var(--rice-blue); box-shadow:0 0 0 3px rgba(0,40,86,.1); }

.wiz-search { margin-bottom:12px; }
/* A viewport-positioned panel escapes the body scroller without moving fields. */
.wiz-search .ac-drop { position:fixed; z-index:110; margin:0; bottom:auto; right:auto;
  left:var(--wiz-drop-left, 0px); top:var(--wiz-drop-top, 0px); width:var(--wiz-drop-width, 280px);
  max-height:var(--wiz-drop-height, 240px); overflow-y:auto; overscroll-behavior:contain;
  border:1px solid var(--border-mid); box-shadow:var(--shadow-lg); }
#setup-overlay .ms-opt { min-height:36px; box-sizing:border-box; }
#setup-overlay .ms-opt.is-on { background:var(--accent-bg); }
@media (max-width:600px) {
  #setup-overlay .wiz-modal { border-radius:var(--radius-lg); }
  #setup-overlay .wiz-input, #setup-overlay .ms-filter { font-size:16px; }
}
.wiz-row { display:flex; gap:8px; align-items:flex-start; margin-bottom:12px; }
.wiz-row .wiz-search { flex:1 1 auto; margin-bottom:0; min-width:0; }
.wiz-grow { flex:1 1 auto; min-width:0; }
.wiz-narrow { flex:0 0 128px; width:128px; }
.wiz-tiny { flex:0 0 84px; width:84px; }
.wiz-row .btn { flex:0 0 auto; }
.wiz-drop-empty { padding:10px 12px; font-size:12px; color:var(--text-tertiary); line-height:1.5; }

.wiz-chips { display:flex; flex-wrap:wrap; gap:6px; margin-bottom:14px; }
.wiz-chip { display:inline-flex; align-items:center; gap:6px; padding:5px 6px 5px 11px;
  font-size:12px; font-weight:500; color:var(--text-primary); background:var(--bg-secondary);
  border:1px solid var(--border-mid); border-radius:var(--radius-sm); }
.wiz-chip-x { background:none; border:none; padding:0 3px; cursor:pointer; line-height:1;
  font-size:15px; color:var(--text-tertiary); font-family:var(--font-sans); border-radius:50%; }
.wiz-chip-x:hover { color:var(--danger); }

/* The box-plus-Add row on the interests step. It does NOT reuse .wiz-row/.wiz-grow:
   those carry a phone rule (max-width:768px) that gives the field its own line and
   stretches the button across the next one, which is right for the four-across
   add-a-course row and wrong here — one field and a three-letter button fit side
   by side at 375px, and stacking them made Add look like a section heading. */
.wiz-entry { display:flex; align-items:stretch; gap:8px; }
.wiz-entry .wiz-input { flex:1 1 auto; width:auto; min-width:0; }
/* Outlined, not filled and not bare: Continue is the only primary button on the
   step, and a borderless Add read as a caption sitting under the field rather
   than as the control that takes what you typed. */
.wiz-entry .btn { flex:0 0 auto; }
.wiz-add { padding:0 14px; color:var(--text-secondary); background:var(--bg-secondary);
  border:1px solid var(--border-mid); }
.wiz-add:hover:not(:disabled) { color:var(--rice-blue); border-color:var(--rice-blue);
  background:var(--bg-secondary); }
.wiz-add:disabled { opacity:.5; cursor:not-allowed; }
.wiz-warn { color:var(--danger); }

/* Degree setup's optional actions use the same field shape as program search. */
.wiz-field-control { display:flex; align-items:center; justify-content:space-between; gap:8px;
  text-align:left; cursor:pointer; font-weight:500; }
.wiz-field-control:hover { border-color:var(--rice-blue); }
.wiz-field-control-icon, .wiz-disclose-caret { flex:0 0 auto; font-size:16px;
  line-height:1; color:var(--text-tertiary); }
.wiz-disclose-caret { transition:transform .12s ease; }
.wiz-disclose[aria-expanded="true"] .wiz-disclose-caret { transform:rotate(180deg); }
.wiz-disclose-panel { margin-top:6px; padding:12px; border:1px solid var(--border-mid);
  border-radius:var(--radius-md); background:var(--bg-primary); box-shadow:var(--shadow-lg); }
.wiz-disclose-panel[hidden] { display:none; }
.wiz-custom-term { max-width:280px; margin-bottom:12px; }
.wiz-custom-term[hidden] { display:none; }
/* DP-137: the transfer-only row hides with [hidden]; .wiz-row's display:flex would win. */
.wiz-row[hidden] { display:none; }
.wiz-check { display:inline-flex; align-items:center; gap:6px; min-height:36px; font-size:12.5px; color:var(--text-secondary); }
.wiz-check input { margin:0; accent-color:var(--rice-blue); }
.wiz-credit-actions { align-items:center; }
.wiz-credit-actions .wiz-hint { margin:0; }
.wiz-credit-actions { margin-bottom:4px; }
/* AP & transfer: the credit-type switch, the AP picker's preview and the quiet links. */
.wiz-seg { display:flex; margin-bottom:12px; }
.wiz-seg .seg-btn { flex:1 1 0; }
.wiz-ap-year { align-items:center; flex-wrap:wrap; }
.wiz-ap-year-label { font-size:12.5px; color:var(--text-secondary); }
.wiz-ap-year-hint { margin:0; flex:1 1 200px; }
.wiz-ap-preview { display:flex; flex-direction:column; gap:3px; margin:0 0 10px; padding:9px 11px; font-size:12.5px; line-height:1.45;
  color:var(--text-secondary); background:var(--bg-secondary); border:1px solid var(--border-light); border-radius:var(--radius-md); }
.wiz-ap-preview[hidden] { display:none; }
.wiz-ap-preview.is-award { border-color:var(--rice-blue); }
.wiz-ap-preview.is-award .wiz-ap-result { color:var(--text-primary); font-weight:600; }
.wiz-ap-note, .wiz-ap-source { font-size:11.5px; color:var(--text-tertiary); }
.wiz-ap-source a { color:inherit; }
.wiz-linklike { padding:4px 0; margin:0 0 8px; border:0; background:none; cursor:pointer; font:inherit; font-size:12px;
  color:var(--rice-blue); text-decoration:underline; text-underline-offset:2px; }
.wiz-linklike[hidden] { display:none; }
.wiz-credit-actions .wiz-linklike { margin:0; }
.wiz-choice { display:flex; flex-wrap:wrap; gap:4px 16px; margin-bottom:8px; }
.wiz-choice[hidden] { display:none; }
.wiz-drop-empty { padding:10px 12px; font-size:12px; color:var(--text-tertiary); }
.wiz-list-exam .wiz-list-name { font-variant-numeric:tabular-nums; }
.wiz-credit-intro { margin:0 0 12px; }
.wiz-level { flex:0 0 176px; width:176px; }

/* Subjects floats over the dialog; only its list scrolls. Keep the filter out
   of that scroller so the first row cannot disappear underneath it. */
.ms { position:relative; }
.ms-trigger { display:flex; align-items:center; justify-content:space-between; gap:8px;
  width:100%; box-sizing:border-box; padding:8px 12px; min-height:var(--control-h); cursor:pointer; text-align:left;
  font-family:var(--font-sans); font-size:13px; color:var(--text-primary);
  background:var(--bg-primary); border:1px solid var(--border-mid);
  border-radius:var(--radius-md); transition:border-color .12s; }
.ms-trigger:hover { border-color:var(--rice-blue); }
.ms.is-open .ms-trigger { border-color:var(--rice-blue); }
.ms-trigger-text.is-empty { color:var(--text-tertiary); }
.ms-caret { flex:0 0 auto; color:var(--text-tertiary); transition:transform .15s ease; }
.ms.is-open .ms-caret { transform:rotate(180deg); }

.ms-panel { position:fixed; z-index:110; left:var(--ms-left, 0px); top:var(--ms-top, 0px);
  width:var(--ms-width, 280px); max-height:var(--ms-height, 320px); box-sizing:border-box;
  display:flex; flex-direction:column; border:1px solid var(--border-mid);
  border-radius:var(--radius-md); background:var(--bg-primary); box-shadow:var(--shadow-lg);
  overflow:hidden; animation:ms-appear .12s ease-out; }
.ms-filter { display:block; flex-shrink:0; width:100%; box-sizing:border-box; padding:10px 12px;
  font-family:var(--font-sans); font-size:12.5px; color:var(--text-primary);
  background:var(--bg-secondary); border:none; border-bottom:1px solid var(--border-light); }
.ms-filter:focus { outline:none; background:var(--bg-primary); }
/* Keep Filter focus inside its field, clear of the scrolling option rows. */
.ms-panel .ms-filter:focus-visible { outline:2px solid var(--rice-blue-bright);
  outline-offset:-2px; box-shadow:none; }
.ms-list { min-height:0; max-height:260px; overflow-y:auto; padding:4px 0;
  scroll-padding-block:4px; overscroll-behavior:contain; }
@keyframes ms-appear { from { opacity:0; } to { opacity:1; } }
@media (prefers-reduced-motion: reduce) { .ms-panel { animation:none; } }

/* An option is a <label> row around a native checkbox: 24 of them read as a list
   far faster than as a flow of pills, and the box means "chosen" is legible
   without colour. The row keeps display:flex, so a filtered-out row needs its own
   [hidden] rule — the UA's display:none loses to any author display (T037). */
.ms-opt { display:flex; align-items:center; gap:9px; padding:7px 12px; cursor:pointer;
  font-size:12.5px; color:var(--text-primary); border-bottom:1px solid var(--border-light);
  transition:background .08s; }
.ms-opt[hidden] { display:none; }
.ms-opt:last-of-type { border-bottom:none; }
.ms-opt:hover, .ms-opt:has(.ms-check:focus-visible) { background:var(--accent-bg); }
.ms-opt:has(.ms-check:focus-visible) { box-shadow:inset 2px 0 0 var(--rice-blue); }
.ms-opt.is-on { font-weight:600; color:var(--rice-blue); }
.ms-check { flex:0 0 auto; width:15px; height:15px; margin:0; accent-color:var(--rice-blue); cursor:pointer; }
.ms-opt-label { min-width:0; }

@media (prefers-reduced-motion: reduce) { .ms-caret, .wiz-disclose-caret { transition:none; } }

/* Capped and scrollable: logging a full transcript here is a supported answer,
   and 40 rows must not push the Continue button off the bottom of the screen. */
.wiz-list { max-height:190px; overflow-y:auto; margin-bottom:8px;
  border:1px solid var(--border-light); border-radius:var(--radius-md); }
.wiz-list-row { display:flex; align-items:center; gap:8px; padding:6px 8px 6px 11px;
  font-size:12px; border-bottom:1px solid var(--border-light); }
.wiz-list-row:last-child { border-bottom:none; }
.wiz-list-code { font-variant-numeric:tabular-nums; font-weight:600; font-size:11.5px;
  color:var(--text-primary); flex:0 0 auto; }
.wiz-list-name { color:var(--text-secondary); flex:1 1 auto; min-width:0;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.wiz-list-meta { color:var(--text-tertiary); font-size:11px; flex:0 0 auto; }
/* Reads as the row's grade; a border shows on hover or focus, so it is quiet
   until wanted. No caret: the select's own arrow is dropped with appearance. */
.wiz-list-grade { flex:0 0 auto; appearance:none; -webkit-appearance:none; cursor:pointer;
  min-width:34px; padding:1px 6px; font-size:11px; font-weight:600; text-align:center;
  color:var(--text-secondary); background:var(--bg-secondary);
  border:1px solid transparent; border-radius:var(--radius-sm); }
.wiz-list-grade:has(option[value=""]:checked) { color:var(--text-tertiary); font-weight:400; }
.wiz-list-grade:hover, .wiz-list-grade:focus-visible { border-color:var(--border-mid); background:var(--bg-primary); }

.wiz-actions { display:flex; flex-wrap:wrap; align-items:center; gap:12px; margin-bottom:14px; }
.wiz-result { font-size:12.5px; line-height:1.5; padding:9px 12px; margin-bottom:14px;
  border-radius:var(--radius-md); border:1px solid transparent; }
.wiz-result-ok { background:var(--success-bg); color:var(--success-text); border-color:rgba(47,107,53,.2); }
.wiz-result-warn { background:var(--warn-bg); color:var(--warn-text); border-color:rgba(180,120,20,.25); }

/* Actions stay separate from the body scroller on every step. */
.wiz-footer { flex:0 0 auto; display:flex; justify-content:space-between;
  align-items:center; gap:12px; flex-wrap:wrap-reverse; margin-top:18px;
  padding:14px 0 18px; background:var(--bg-primary);
  border-top:1px solid var(--border-light); }
.wiz-footer-right { display:flex; gap:8px; margin-left:auto; }
.wiz-skip { background:none; border:none; padding:0; cursor:pointer; font-family:var(--font-sans);
  font-size:11.5px; color:var(--text-tertiary); text-decoration:underline; text-underline-offset:2px; }
.wiz-skip:hover { color:var(--text-secondary); }

/* ══ FOOTER — disclaimers ════════════════════════════════════════════════════
   Quiet but not hidden. A non-affiliation notice in 8px grey is a notice nobody
   reads, which defeats the point of having one. */
#site-footer { margin:36px 0 0; padding:22px 26px; background:var(--bg-secondary);
  border-top:1px solid var(--border-light); flex:0 0 auto; }
/* .sec-mode-badge is position:fixed at left:14px/bottom:12px and floats over
   whatever is at the end of the page, which is this footer — without a
   reservation it lands squarely on the policy links. It only exists in demo and
   sandbox mode, though, so a live deployment should not carry 26px of empty
   footer forever. :has() ties the reservation to the badge actually being there.
   js/security.js:221 creates it as #sec-mode-badge on <body>. */
body:has(#sec-mode-badge) #site-footer { padding-bottom:48px; }
/* Two columns above ~900px. The two disclaimer paragraphs stacked were 279px of
   footer under a 721px home view — the footer was the reason a short page
   scrolled at all, and it read as the page's main content rather than its fine
   print. Side by side they are ~150px and the whole thing fits without pushing
   anything off screen. auto-fit collapses back to one column when there is not
   room for two, so no breakpoint is needed. */
#site-footer .footer-cols { display:grid; gap:6px 40px;
  grid-template-columns:repeat(auto-fit, minmax(330px, 1fr)); align-items:start; }
/* Only on index.html, where a 240px sidebar sits to the left of everything else:
   the footer is a sibling of #layout and therefore full-bleed, so without this
   its first character started 248px to the left of every other first character
   on the page. The sibling combinator is what scopes it — advisor.html and
   privacy.html have no #layout and keep the flat 26px. 2.25rem matches #main's
   horizontal padding. */
#layout ~ #site-footer { padding-left:calc(240px + 2.25rem); }
body.sb-collapsed #layout ~ #site-footer { padding-left:calc(52px + 2.25rem); }
#site-footer .footer-main { max-width:78ch; font-size:11.5px; line-height:1.6;
  color:var(--text-secondary); margin-bottom:0; }
#site-footer .footer-main strong { color:var(--text-primary); font-weight:600; }
#site-footer .footer-links { display:flex; flex-wrap:wrap; align-items:center; gap:8px 18px; margin-top:14px;
  padding-top:12px; border-top:1px solid var(--border-light); }
#site-footer .footer-links a { font-size:11.5px; color:var(--rice-blue); text-decoration:none; }
#site-footer.footer-compact .footer-links { margin:0; padding:0; border:0; gap:8px 20px; }
#site-footer.footer-compact .footer-links a { display:inline-flex; align-items:center;
  min-height:28px; font-size:12px; }
#site-footer .footer-links a:focus-visible { outline:2px solid var(--rice-blue);
  outline-offset:4px; border-radius:2px; }
#site-footer .footer-disclaimers { max-width:92ch; margin-top:8px;
  color:var(--text-secondary); font-size:12px; line-height:1.6; }
#site-footer .footer-disclaimers p { margin:0; }
#site-footer .footer-disclaimers p + p { margin-top:4px; }
#site-footer .footer-links a:hover { text-decoration:underline; text-underline-offset:2px; }
/* Was margin-left:auto, which flung the catalog date to the far right edge —
   on a wide monitor it sat ~760px from the links it belongs with and read as an
   unrelated stray. It is a footnote to the links, so it flows with them. */
#site-footer .footer-stamp { font-size:11px; color:var(--text-tertiary); font-family:var(--font-mono);
  padding-left:12px; border-left:1px solid var(--border-light); }

/* ══ DOCUMENT PAGES (privacy.html / terms.html) ═══════════════════════════════════════════
   A policy page is a reading surface, not an app view: one column, a measure
   that tops out around 74 characters, and type large enough that the person
   scanning for "do you sell my data" actually finds the sentence. Nothing here
   is shared with #main-content, so these rules cannot regress the planner. */
.doc-body { background:var(--bg-primary); }
.doc-shell { width:100%; max-width:800px; margin:0 auto; padding:34px 26px 8px; }

.doc-hero { margin-bottom:26px; }
.doc-hero h1 { font-size:29px; font-weight:700; letter-spacing:-.02em; color:var(--rice-blue); }
.doc-hero .doc-sub { margin-top:8px; font-size:14.5px; line-height:1.6; color:var(--text-secondary); max-width:70ch; }
.doc-hero .doc-stamp { margin-top:12px; font-family:var(--font-mono); font-size:11px;
  letter-spacing:.02em; color:var(--text-tertiary); }

.doc-card { padding:24px 0; border-top:1px solid var(--border-light);
  margin:0; scroll-margin-top:68px; }
.doc-card [id] { scroll-margin-top:68px; }
.doc-card h2 { font-size:18px; font-weight:650; letter-spacing:-.01em; color:var(--text-primary);
  margin-bottom:12px; }
.doc-card h3 { font-size:13px; font-weight:650; letter-spacing:.02em; text-transform:uppercase;
  color:var(--rice-blue-soft); margin:22px 0 9px; }
.doc-card h3:first-of-type { margin-top:4px; }
.doc-card p { font-size:14px; line-height:1.72; color:var(--text-secondary); margin-bottom:12px; max-width:74ch; }
.doc-card p:last-child { margin-bottom:0; }
.doc-card strong { color:var(--text-primary); font-weight:600; }
.doc-card code { font-family:var(--font-mono); font-size:12.5px; background:var(--bg-tertiary);
  border:1px solid var(--border-light); border-radius:var(--radius-sm); padding:1px 5px; color:var(--text-primary); }
.doc-card a { color:var(--rice-blue-bright); text-underline-offset:2px; }

/* The lead card carries the whole answer for anyone who reads one thing. */
.doc-card-lead { border-left:3px solid var(--rice-blue); }
.doc-card-legal { background:var(--bg-secondary); }

.doc-list { list-style:none; margin:0 0 12px; padding:0; max-width:74ch; }
.doc-list li { position:relative; padding-left:17px; font-size:14px; line-height:1.7;
  color:var(--text-secondary); margin-bottom:9px; }
.doc-list li::before { content:''; position:absolute; left:2px; top:.72em;
  width:5px; height:5px; border-radius:50%; background:var(--rice-gray-300); }
.doc-list li:last-child { margin-bottom:0; }

.doc-toc { display:flex; flex-wrap:wrap; gap:4px 18px; margin:0 0 10px; }
.doc-toc a { display:inline-flex; align-items:center; min-height:32px; font-size:12px;
  font-weight:500; color:var(--rice-blue); text-decoration:underline; text-underline-offset:3px; }
.doc-toc a:focus-visible, .doc-card a:focus-visible { outline:2px solid var(--rice-blue);
  outline-offset:4px; border-radius:2px; }
.doc-body #site-footer { padding-inline:max(26px, calc((100% - 748px) / 2)); }

.doc-table { width:100%; border-collapse:collapse; margin:6px 0 14px; font-size:13px; }
.doc-table th { text-align:left; font-size:10.5px; font-weight:650; letter-spacing:.05em;
  text-transform:uppercase; color:var(--text-tertiary);
  padding:0 12px 8px 0; border-bottom:1px solid var(--border-mid); }
.doc-table td { padding:10px 12px 10px 0; border-bottom:1px solid var(--border-light);
  color:var(--text-secondary); line-height:1.55; vertical-align:top; }
.doc-table tr:last-child td { border-bottom:none; }
.doc-table td:first-child { color:var(--text-primary); font-weight:600; width:26%; }
.doc-yes { color:var(--warn-text); }
.doc-no  { color:var(--success-text); font-weight:600; }

.doc-note, .doc-warn, .doc-strong { font-size:13.5px; line-height:1.65; border-radius:var(--radius-md);
  padding:12px 14px; margin:14px 0; max-width:76ch; }
.doc-note   { background:var(--bg-secondary); border-left:3px solid var(--rice-gray-300); color:var(--text-secondary); }
.doc-warn   { background:var(--warn-bg);   border-left:3px solid #d19a30; color:var(--warn-text); }
.doc-strong { background:var(--accent-bg); border-left:3px solid var(--rice-blue); color:var(--text-primary); }
.doc-card .doc-note:last-child, .doc-card .doc-warn:last-child { margin-bottom:0; }

.doc-contact { font-family:var(--font-mono); font-size:14px; }
/* Deliberately loud. A placeholder contact address that ships to production is
   a policy page with no way to reach anyone, so it should be impossible to miss
   in a screenshot or a glance at the deployed page. */
.doc-todo { display:inline-block; background:var(--warn-bg); color:var(--warn-text);
  border:1px dashed #d19a30; border-radius:var(--radius-sm); padding:3px 9px; font-weight:600; }

.doc-foot-note { max-width:74ch; margin:22px 2px 0; font-size:12.5px; line-height:1.7;
  color:var(--text-tertiary); font-style:italic; }

/* The version log (js/version-log.js): the footer link's dialog in the app, and versions.html. */
.version-log { max-height:60vh; overflow-y:auto; }
.version-log-page { max-height:none; overflow:visible; padding:22px 0 8px; border-top:1px solid var(--border-light); }
.version-log-entry + .version-log-entry { margin-top:16px; padding-top:14px; border-top:1px solid var(--border-light); }
.version-log-entry h4 { margin:0 0 6px; font-size:13.5px; font-weight:600; color:var(--text-primary); }
.version-log-entry ul { margin:0; padding-left:18px; }
.version-log-entry li { font-size:13.5px; line-height:1.6; color:var(--text-secondary); }

/* ── RESPONSIVE (must stay LAST so mobile overrides beat base rules) ── */
/* ── COURSES: the one search box ─────────────────────────────────────── */
/* #adv-kw used to be the first cell of the filter grid, one field among nine.
   It is now the thing you came here to use, so it sits above the box at the size
   that says so. The filters below it still narrow both halves of the result. */
.courses-search { display:flex; gap:8px; align-items:center; margin-bottom:6px; }
.courses-search-examples { display:flex; align-items:baseline; flex-wrap:wrap; gap:4px;
  margin:0 0 10px; font-size:12px; color:var(--text-secondary); }
.courses-search-examples button { padding:4px 2px; border:0; background:none; color:inherit;
  font:inherit; cursor:pointer; text-decoration:underline; text-underline-offset:3px; }
.courses-search-examples button:hover { color:var(--text-primary); }
.courses-catalog-browse { max-height:min(480px, 55dvh); overflow:auto; overscroll-behavior:contain; margin-bottom:16px; }
.courses-catalog-heading { margin:20px 0 10px; font-size:16px; font-weight:600; scroll-margin-top:16px; }
.courses-refine { display:flex; align-items:flex-start; flex-wrap:wrap; gap:8px; margin-bottom:16px; }
.courses-refine > .chip { min-height:37px; }
/* The filter panel sits in the top layer, outside the page's layout. */
.courses-filter-panel { position:fixed; inset:auto; margin:0; padding:0; box-sizing:border-box;
  width:min(440px, calc(100vw - 24px)); max-height:calc(100dvh - 24px); overflow:auto;
  background:var(--bg-primary); color:var(--text-primary); border:1px solid var(--border-mid);
  border-radius:var(--radius-lg); box-shadow:var(--shadow-md); }
.courses-filter-heading { position:sticky; top:0; z-index:1; display:flex; align-items:center;
  justify-content:space-between; padding:10px 16px; background:var(--bg-primary);
  border-bottom:1px solid var(--border-light); font-size:13px; font-weight:600; }
.courses-filter-body { padding:14px 16px 6px; }
.courses-filter-panel .adv-filter-grid { grid-template-columns:minmax(0,1fr) minmax(0,1fr); gap:10px; margin-bottom:14px; }
.courses-filter-panel .adv-filter-label, .courses-filter-panel .adv-filter-row-label {
  font-size:12px; font-weight:500; text-transform:none; letter-spacing:0; }
.courses-filter-panel .adv-filter-row-label { flex-basis:100%; }
.courses-filter-panel .adv-dist-pill { padding:6px 10px; box-shadow:none; }
#courses-filters-btn { display:inline-flex; align-items:center; gap:5px; }
#courses-filters-btn[aria-expanded="true"] { border-color:var(--rice-blue); }
/* Courses discovery rows: actions stay adjacent on the left at every width. */
#courses-view .adv-course-card { border:0; border-bottom:1px solid var(--border-light); border-radius:0;
  padding:6px 0; margin:0; box-shadow:none; background:transparent; }
#courses-view .adv-course-card-header { display:flex; align-items:center; flex-wrap:wrap; gap:10px; margin:0; }
#courses-view .courses-row-actions, #courses-view .courses-suggestion-actions { display:flex; flex-direction:row; gap:2px; align-items:center; }
#courses-view .courses-row-actions .btn, #courses-view .courses-suggestion-actions .btn { min-width:32px; min-height:32px; justify-content:center; }
/* DP62: a suggestion row is one line, so its two controls set the line's height.
   28px keeps them clear of the 24px target floor and takes 8px off every row. */
#courses-view .courses-suggestion-actions .btn { min-width:28px; min-height:28px; }
#courses-view .adv-course-main { flex:1; min-width:120px; }
#courses-view .adv-course-meta { gap:8px; flex-wrap:wrap; font-size:11px; }
#courses-view .courses-suggestion-row { padding:4px 0; gap:2px 12px; }
.courses-review-meta { color:var(--text-secondary); font-size:11px; }
.courses-review-filters select { width:100%; margin-top:5px; }
@media (max-width:600px) {
  #courses-view .adv-course-meta { flex-basis:100%; padding-left:76px; }
}
/* ── DP62: Suggested for you is a list of lines, not of stacked blocks ──
   Actions, code, title and the metadata sit across one row on a desktop; the
   code and the title were a column inside a wrapper before, with the metadata on
   a third line under both. Everything still wraps when the width runs out — the
   title takes the room it needs and the metadata drops to its own line — and the
   Add and Save controls stay first in the DOM, so they stay on the left and
   first in the focus order at every width. */
.courses-suggestions { border-top:1px solid var(--border-light); }
.courses-suggestion-row { display:flex; align-items:center; flex-wrap:wrap; gap:2px 12px;
  padding:4px 0; border-bottom:1px solid var(--border-light); }
.courses-suggestion-open { display:flex; align-items:baseline; flex-wrap:wrap; gap:2px 10px;
  flex:1 1 16rem; min-width:0; padding:0; border:0; background:none; text-align:left;
  font-family:inherit; line-height:1.4; cursor:pointer; border-radius:var(--radius-sm); }
.courses-suggestion-open:hover .adv-course-name { text-decoration:underline; }
.courses-suggestion-open .adv-course-code { flex:0 0 auto; min-width:5rem; }
.courses-suggestion-open .adv-course-name { flex:1 1 auto; min-width:0; font-weight:500; overflow-wrap:anywhere; }
/* Right-aligned, so the metadata of every row ends on the same edge, and last to
   claim width: a long title should push the reason down, not the other way round. */
.courses-suggestion-meta { display:flex; flex-wrap:wrap; align-items:baseline; justify-content:flex-end;
  gap:3px 6px; flex:0 1 auto; min-width:0; margin:0; text-align:right;
  color:var(--text-secondary); font-size:11px; line-height:1.4; }
.courses-suggestion-reason { overflow-wrap:anywhere; }
.courses-suggestion-actions { display:flex; align-items:center; gap:4px; flex-shrink:0; }
.courses-suggestion-actions .adv-star-btn { justify-content:center; min-width:28px; min-height:28px; }
.adv-band-divider.adv-band-sug { font-size:13px; font-weight:600; letter-spacing:0; text-transform:none; }
.adv-band-sug::after { display:none; }
.adv-band-sug .suggest-refresh { margin-left:auto; font-size:12px; font-weight:500; letter-spacing:0;
  text-transform:none; border-color:transparent; background:none; }
@media (max-width:480px) {
  /* The actions stay a pair on the left; the title and then the metadata take the
     lines they need under it rather than the controls stacking into a rail. */
  .courses-suggestion-row { align-items:center; gap:2px 8px; padding:6px 0; }
  .courses-suggestion-open { flex:1 1 10rem; }
  .courses-suggestion-meta { flex:1 0 100%; justify-content:flex-start; text-align:left; }
  .courses-suggestion-actions .btn { min-width:32px; min-height:32px; }
}
@media print { .courses-filter-panel, #courses-filters-btn { display:none !important; } }
.course-description { margin-bottom:12px; }
.course-description > summary { cursor:pointer; font-weight:600; }
.course-description[open] > summary { margin-bottom:8px; }
.courses-q { flex:1; min-width:0; padding:11px 14px; font-size:14px; font-family:var(--font-sans); border:1px solid var(--border-mid); border-radius:var(--radius-md); background:var(--bg-primary); color:var(--text-primary); outline:none; }
.courses-q:focus { border-color:var(--rice-blue); }
.courses-reset { flex-shrink:0; }
.courses-resting-empty { font-size:13px; color:var(--text-tertiary); padding:12px 0; }

/* The seam between "matched your words" and "matched the description". Two bands,
   one list, so pagination stays a single slice. */
.adv-band-divider { display:flex; align-items:center; gap:10px; margin:14px 0 10px; font-size:10.5px; font-weight:700; letter-spacing:.08em; text-transform:uppercase; color:var(--text-tertiary); }
.adv-band-divider::after { content:""; flex:1; height:1px; background:var(--border-light); }
/* Refresh sits at the far end of the band, past the rule. The rule is the ::after
   pseudo-element, which is always the last flex child, so the button is ordered
   after it rather than placed after it. */
.adv-band-sug .suggest-refresh { order:1; }
/* Sized off the control system's small height rather than its own padding, so it
   keeps a 24px target on a phone. The type is the band's, not a button's: this is
   a control on a label line, and at --ctl-fs-sm it reads as a second heading. */
.suggest-refresh { display:inline-flex; align-items:center; justify-content:center; gap:5px;
  flex-shrink:0; min-height:var(--ctl-h-sm); padding:0 var(--ctl-px-sm);
  font-family:var(--font-sans); font-size:10.5px; font-weight:700;
  letter-spacing:.08em; text-transform:uppercase; line-height:1;
  color:var(--text-tertiary); background:var(--bg-secondary);
  border:1px solid var(--border-light); border-radius:var(--ctl-r); cursor:pointer;
  transition:background .12s, border-color .12s, color .12s; }
.suggest-refresh:hover { color:var(--rice-blue); border-color:var(--border-mid); }
.suggest-refresh:active .suggest-refresh-ico { transform:rotate(-90deg); }
.suggest-refresh-ico { transition:transform .18s ease; }
@media (prefers-reduced-motion: reduce) { .suggest-refresh-ico { transition:none; } }
.adv-course-open:hover .adv-course-code, .adv-course-open:hover .adv-course-name { text-decoration:underline; }
.adv-dist-badge { font-size:10px; font-weight:700; padding:2px 6px; border-radius:3px; background:var(--accent-bg); color:var(--rice-blue); }
.adv-cr-badge { font-size:11px; color:var(--text-tertiary); }

/* ── COURSE DETAIL OVERLAY ───────────────────────────────────────────── */
.course-ov-body { overflow-y:auto; flex:1; min-height:0; padding-right:2px; }
.course-ov-sec { margin-top:14px; padding-top:12px; border-top:1px solid var(--border-light); }
.course-ov-h { font-size:10.5px; font-weight:700; letter-spacing:.08em; text-transform:uppercase; color:var(--text-tertiary); margin-bottom:6px; }
.course-ov-row { font-size:12.5px; color:var(--text-primary); padding:3px 0; display:flex; gap:8px; }
.course-ov-crn { font-variant-numeric:tabular-nums; font-size:11.5px; color:var(--text-tertiary); flex-shrink:0; min-width:44px; }
.course-ov-note { color:var(--text-tertiary); }

/* ── COURSE PAGE (WP-23) ─────────────────────────────────────────────────────
   A page, not a dialog: one column, capped at a comfortable measure, and the same
   type scale as the rest of the app. No hero and no cards — the sections are
   separated by a rule and a label, which is what every other long readout here
   does, and a course page that looked like a different product would be the
   loudest thing in the app for no reason. */
.cp-wrap { max-width:720px; margin:0 auto; padding:18px 16px 40px; }
.cp-toolbar .toolbar-left { flex:1 1 360px; min-width:0; }
.cp-toolbar .cp-title { flex:1; min-width:0; overflow-wrap:anywhere; }
.cp-toolbar + .cp-wrap { padding-top:0; }
.cp-title-name { font-weight:500; color:var(--text-secondary); }
.cp-meta { font-size:12.5px; color:var(--text-tertiary); margin:0 0 14px; }
.cp-sem { font-size:12.5px; padding:5px 8px; }
.cp-no-terms { font-size:12.5px; color:var(--text-tertiary); }
.cp-sec { margin-top:16px; padding-top:14px; border-top:1px solid var(--border-light); }
.cp-sec:first-of-type { border-top:none; }
.cp-h { font-size:10.5px; font-weight:700; letter-spacing:.08em; text-transform:uppercase;
        color:var(--text-tertiary); margin:0 0 6px; }
.cp-row { font-size:12.5px; color:var(--text-primary); padding:3px 0; display:flex; gap:8px; }
.cp-crn { font-variant-numeric:tabular-nums; font-size:11.5px; color:var(--text-tertiary);
          flex-shrink:0; min-width:44px; }
.cp-note, .cp-absent { color:var(--text-tertiary); }
.cp-current-summary { display:flex; align-items:center; flex-wrap:wrap; gap:8px 16px; font-size:13px; }
.cp-current .cp-sec { margin-top:12px; padding-top:10px; }
.cp-current .cp-row { align-items:baseline; overflow-wrap:anywhere; }
.cp-current .cp-row > span:last-child { min-width:0; }
.cp-section-note { margin:0 0 6px; font-size:12px; color:var(--text-tertiary); }
.cp-current .cp-reviews-link { min-height:32px; font-family:inherit; font-size:13px; }
.cp-unlocks-count { font-size:12.5px; color:var(--text-secondary); margin:0 0 6px; }
.cp-unlocks { display:flex; flex-wrap:wrap; gap:6px; margin:0; }
/* Each unlocked course is a real control, not decorated text: it opens that
   course's page, so it takes a tab stop and a 24 px target like every other
   control in the app. */
.cp-link { font-variant-numeric:tabular-nums; font-size:11.5px; padding:4px 7px; min-height:24px;
           background:var(--bg-subtle); border:1px solid var(--border-light); border-radius:4px;
           color:var(--rice-blue); cursor:pointer; }
.cp-link:hover { border-color:var(--rice-blue); }
.cp-more { font-size:11.5px; color:var(--text-tertiary); align-self:center; }
.course-ov-actions { align-items:center; gap:10px; flex-wrap:wrap; }
.course-ov-add { display:flex; align-items:center; gap:6px; font-size:12.5px; color:var(--text-secondary); }
.course-ov-add select { padding:6px 10px; font-size:12.5px; font-family:var(--font-sans); border:1px solid var(--border-mid); border-radius:var(--radius-md); background:var(--bg-primary); color:var(--text-primary); }

/* ── COURSE REVIEWS (WP-08b, js/reviews.js) ─────────────────────────────── */
/* Everything reviews renders lives in the course modal or #review-overlay and
   reuses course-ov-* for sections and rows. These classes replace what were
   inline styles; existing tokens only. .rv- prefix, nothing else uses it. */
/* Reviews begin with the three discovery metrics; optional detail stays folded. */
.rv-heading { display:flex; align-items:center; justify-content:space-between; gap:8px 16px; flex-wrap:wrap; margin-bottom:10px; }
.rv-heading .cp-h { margin:0; font-size:14px; letter-spacing:0; text-transform:none; color:var(--text-primary); }
.rv-heading .rv-write { margin:0; }
.rv-metrics { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:12px; padding-bottom:10px; }
.rv-metrics .rv-kv { display:block; padding:0; }
.rv-metrics .rv-kv > span { display:block; }
.rv-metrics .rv-kv > span:first-child { margin-bottom:4px; font-size:12px; }
.rv-metrics .rv-kv b { font-size:17px; }
.rv-metrics .rv-muted { display:block; }
.rv-details { font-size:12px; border-top:1px solid var(--border-light); }
.rv-details summary { padding:10px 0; color:var(--text-secondary); cursor:pointer; }
.rv-details summary:focus-visible { outline:2px solid var(--rice-blue); outline-offset:2px; }
.rv-sub { color:var(--text-secondary); }
.rv-muted { color:var(--text-tertiary); font-size:12px; }
.rv-kv { justify-content:space-between; }
.rv-kv b { font-weight:600; font-variant-numeric:tabular-nums; }
/* Hours-per-week histogram: one chip per bucket, count under the label. */
.rv-hist { display:inline-flex; gap:4px; flex-wrap:wrap; }
.rv-chip { display:inline-flex; flex-direction:column; align-items:center; min-width:36px; padding:2px 5px; font-size:10.5px; line-height:1.3; color:var(--text-secondary); border:1px solid var(--border-light); border-radius:var(--radius-sm); background:transparent; font-variant-numeric:tabular-nums; }
.rv-chip.is-filled { background:var(--bg-secondary); color:var(--text-primary); }
.rv-chip b { font-weight:600; }
/* Published comments. */
.rv-text { font-size:12.5px; line-height:1.5; color:var(--text-primary); white-space:pre-wrap; padding:8px 0; border-top:1px solid var(--border-light); }
.rv-text-meta { display:flex; align-items:center; justify-content:space-between; gap:8px; margin-top:4px; font-size:11px; color:var(--text-tertiary); }
.rv-flag { display:inline-flex; align-items:center; gap:6px; }
.rv-flag select { padding:2px 6px; font-size:11px; font-family:var(--font-sans); border:1px solid var(--border-light); border-radius:var(--radius-sm); background:var(--bg-primary); color:var(--text-secondary); }
.rv-flag-btn { background:none; border:none; padding:0; font-family:var(--font-sans); font-size:11px; font-weight:600; color:var(--rice-blue); cursor:pointer; }
.rv-flag-btn:hover { text-decoration:underline; }
.rv-report { position:relative; }
.rv-report summary { display:inline-flex;align-items:center;min-height:32px;padding:4px 6px;list-style:none;border-radius:var(--radius-sm);color:var(--rice-blue);font-size:11px;font-weight:600;cursor:pointer; }
.rv-report summary::-webkit-details-marker { display:none; }
.rv-report summary:hover,.rv-report[open] summary { background:var(--bg-secondary); }
.rv-report summary:focus-visible { outline:2px solid var(--rice-blue);outline-offset:2px; }
.rv-report-options { position:absolute;z-index:5;right:0;top:100%;display:flex;flex-wrap:wrap;align-items:center;gap:8px;width:245px;max-width:calc(100vw - 32px);box-sizing:border-box;padding:10px;border:1px solid var(--border-mid);border-radius:var(--radius-md);background:var(--bg-primary);box-shadow:0 6px 20px rgba(0,0,0,.12); }
.rv-report-options label { font-size:11px;color:var(--text-secondary); }
.rv-report-options select { flex:1;min-width:0;min-height:32px; }
.rv-report-options .rv-flag-btn { margin-left:auto;min-height:32px;padding:5px 9px;border:1px solid var(--border-mid);border-radius:var(--radius-sm);background:var(--bg-primary); }
.rv-write { margin-top:6px; }
.rv-write-btn { font-size:12px; padding:6px 12px; }
/* "Review" on a logged row in the Plan grid: same scale as the ✎ edit control. */
.rev-row-btn { font-family:var(--font-sans); font-size:10px; font-weight:600; padding:1px 6px; margin-left:4px; border:1px solid var(--border-light); border-radius:var(--radius-sm); background:var(--bg-primary); color:var(--text-secondary); cursor:pointer; white-space:nowrap; flex-shrink:0; }
.rev-row-btn:hover { border-color:var(--border-strong); color:var(--text-primary); }
/* Done reads quieter than the Review still to do. */
.rev-row-btn.is-reviewed { border-color:transparent; background:transparent; color:var(--text-tertiary); font-weight:500; }
.rev-row-btn.is-reviewed::before { content:'✓'; margin-right:3px; color:var(--success-text); }
/* The overlay: consent panel, then the form. */
.rv-consent p { font-size:13px; line-height:1.55; margin:8px 0; color:var(--text-primary); }
.rv-consent a { color:var(--rice-blue); }
.rv-consent .rv-facts { margin:8px 0 0 18px; padding:0; font-size:13px; line-height:1.55; color:var(--text-primary); }
.rv-consent .rv-facts li { margin:5px 0; }
.rv-consent-actions { display:flex; flex-wrap:wrap; gap:8px; margin-top:14px; }
.rv-lead { font-size:12px; color:var(--text-secondary); padding-bottom:8px; }
.rv-field { display:flex; align-items:center; justify-content:space-between; gap:12px; padding:7px 0; border-top:1px solid var(--border-light); font-size:12.5px; color:var(--text-primary); }
.rv-field > span:first-child { color:var(--text-secondary); flex:0 0 auto; }
.rv-field select, .rv-input { padding:6px 10px; font-size:12.5px; font-family:var(--font-sans); border:1px solid var(--border-mid); border-radius:var(--radius-md); background:var(--bg-primary); color:var(--text-primary); }
.rv-input { width:220px; max-width:100%; }
.rv-choices { display:inline-flex; gap:10px; flex-wrap:wrap; justify-content:flex-end; }
.rv-choices label { font-size:12.5px; color:var(--text-primary); display:inline-flex; align-items:center; gap:4px; cursor:pointer; }
.rv-comment { margin-top:10px; }
.rv-textarea { width:100%; box-sizing:border-box; padding:9px 11px; font-family:var(--font-sans); font-size:13px; line-height:1.5; border:1px solid var(--border-mid); border-radius:var(--radius-md); background:var(--bg-primary); color:var(--text-primary); resize:vertical; }
.rv-comment-meta { display:flex; justify-content:space-between; gap:8px; margin-top:4px; font-size:11px; color:var(--text-tertiary); font-variant-numeric:tabular-nums; }
.rv-status { margin-top:8px; min-height:18px; font-size:13px; color:var(--text-secondary); }
.rv-status.is-error { color:var(--danger-text); }
/* DP-16: the grade consent box, the manage panel, the "you reviewed this" line. */
.rv-grade { margin-top:12px; padding:10px 12px; border:1px solid var(--border-light); border-radius:var(--radius-md); background:var(--bg-secondary); }
.rv-check { display:flex; align-items:flex-start; gap:8px; font-size:13px; font-weight:600; color:var(--text-primary); cursor:pointer; }
.rv-check input { margin-top:2px; }
.rv-grade-detail { margin:6px 0 2px 24px; line-height:1.5; }
.rv-grade-detail b { color:var(--text-primary); }
.rv-grade .rv-field { border-top:none; padding-top:4px; }
.rv-manage p { font-size:13px; line-height:1.55; margin:8px 0; color:var(--text-primary); }
.rv-mine { justify-content:space-between; align-items:center; flex-wrap:wrap; color:var(--text-secondary); }
.rv-term { margin-top:10px; }
.rv-pending p { line-height:1.5; }
@media (max-width: 600px) {
  .rv-field { flex-direction:column; align-items:flex-start; gap:6px; }
  .rv-choices { justify-content:flex-start; }
  .rv-input { width:100%; }
}

/* ── SEMESTER FOCUS ──────────────────────────────────────────────────── */
#semester-view { padding-bottom:40px; }
/* DP43: back control, term title and year label as one row.
   align-items:baseline matched the back control's inner TEXT baseline to a 24px
   heading's, which lifted the whole control box above the heading's cap height —
   it read as something dropped beside Fall 2026 rather than as part of the row,
   and the 4px margin-top on .toolbar-left p pushed the year label the other way.
   A 24px heading, a 12px control and a 13px caption have no shared baseline worth
   aligning to; their optical centres do. The control treatment itself is at the
   end of the button rules, after the shared quiet group, because that group is
   further down this file than this section and would otherwise win — which is
   exactly what had happened to the .btn-back declarations that used to be here:
   every one of them was overridden, so the control was never styled from here. */
.sem-toolbar .toolbar-left { display:flex; align-items:center; gap:6px 12px; flex-wrap:wrap; }
.sem-toolbar .toolbar-left h1 { line-height:1.2; }
.sem-toolbar .toolbar-left p { margin-top:0; }
/* One cluster: the term's actions read as a group ending in the ⋯, and the
   toolbar's own rule is the separation from the blocks below. */
.sem-toolbar { margin-bottom:18px; }
.sem-toolbar .toolbar-right { align-items:center; gap:6px; }

/* ── DP61: the Semester view is four blocks, and they are one composition ──
   Planned courses, Saved courses, Remaining requirements and this term's
   suggestions each open with the same head — name left, one measure right, a
   hairline under both — and each fills its column with rows of the same rhythm.
   They previously had four different heads and four different row heights for
   one line of content each, which is the composition the owner rejected; a set
   of overrides on top of it would have kept it. */
/* The blocks stack here; DP-124 composes them as two columns of cards in
   home.css (since 6.0.6: the term, its requirements and the suggestions, with
   saved courses beside them). The DP61 lesson both keep: a left column for management and a
   right one for discovery gave the halves unequal amounts of content — management
   ran out around 390px while the open requirements ran on to 830px, and the
   bottom-left quarter of the page was empty. */
.sem-focus { display:flex; flex-direction:column; margin-top:0; }
.sem-focus > * { min-width:0; margin-top:26px; }
.sem-focus > *:first-child { margin-top:0; }
.sem-focus > .sem-saved-notice { margin-top:8px; }
/* An empty block takes no room and leaves no gap: a term with nothing saved, or a
   student with nothing left to require, must not push a blank band into the stack. */
#sem-saved:empty, #sem-rails:empty { display:none; }
.sem-block { min-width:0; }
.sem-block-head { display:flex; align-items:baseline; justify-content:space-between; flex-wrap:wrap;
  gap:2px 16px; min-height:24px; padding-bottom:6px; border-bottom:1px solid var(--border-mid); }
.sem-block-title { margin:0; font-size:11px; font-weight:700; letter-spacing:.075em;
  text-transform:uppercase; color:var(--text-secondary); }
.sem-block-meta { display:inline-flex; align-items:baseline; gap:10px; min-width:0;
  font-size:11.5px; color:var(--text-tertiary); font-variant-numeric:tabular-nums; }
.sem-credits { font-size:11.5px; font-weight:600; color:var(--text-secondary); font-variant-numeric:tabular-nums; }
.sem-credits.sem-credits-full { color:var(--success-text); }
.sem-empty { font-size:13px; color:var(--text-tertiary); padding:12px 0; line-height:1.5; }
.sem-empty p { margin:0 0 4px; }
.sem-empty-link { background:none; border:none; padding:0; font-family:var(--font-sans);
  font-size:13px; color:var(--rice-blue); cursor:pointer; text-decoration:underline; }

/* "Suggest" on an open semester card, "plan →" on an unmet requirement row. Both
   are the same idea — turn a gap into a next step — so they read the same. */
.req-plan-link { background:none; border:none; padding:0 2px; font-family:var(--font-sans); font-size:10.5px; font-weight:600; color:var(--rice-blue-bright); cursor:pointer; white-space:nowrap; }
.req-plan-link:hover { text-decoration:underline; }

/* ── SUGGESTED ROWS (§1.3) ───────────────────────────────────────────── */
/* Shipped unused: WP-05 adds the .is-suggested class and the two buttons when it
   wires autofill, so that package is wiring rather than styling. A suggestion is
   the same row as a planned course with the weight taken out of it — flat, dashed
   rule, normal-weight code — because it is a proposal, not a commitment. */
.planned-course-row.is-suggested { background:transparent; border-left:2px dashed var(--rice-blue-bright); box-shadow:none; }
.planned-course-row.is-suggested .planned-course-code { font-weight:500; }
/* Capped, because a reason can be as long as "Major Concentration (Finance) Core
   Requirements" and an uncapped pill wrapped the row to 54px against a real row's
   31px — a suggestion is meant to read as lighter than the thing above it, not as
   nearly twice the height. The full why list is already on the title attribute,
   which is where this file puts detail everywhere else. */
.sug-why { font-size:10.5px; font-weight:600; padding:2px 8px; border-radius:var(--radius-sm);
  background:var(--accent-bg); color:var(--rice-blue); margin-left:4px;
  max-width:14ch; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  /* Shrinkable, and it is the FIRST thing that gives. A semester card is ~290px
     wide in the three-column grid; with the pill unshrinkable the dismiss button
     was pushed past the card's right edge and simply could not be clicked. The
     reason can lose characters — it has a tooltip. The answer buttons cannot. */
  flex:0 1 auto; min-width:0; }
/* 24px answer buttons (§1.3) are taller than the ✕ on a real row, which pushed the
   suggested row to 38px against a real row's 31px. Trimming the vertical padding
   puts it back at 32px, so a semester card reads as one list with some of its rows
   proposed rather than as two lists at different scales. */
.planned-course-row.is-suggested { flex-wrap:nowrap; padding-top:4px; padding-bottom:4px; }
/* A flex item will not shrink below its content unless told to, so a course with a
   very long title (STAT 311, "HONORS PROBABILITY AND MATHEMATICAL STATISTICS")
   pushed the row 24px wider than the card and took the buttons with it, ellipsis
   or no ellipsis. Scoped to suggested rows: real rows have one small button and do
   not overflow, and this is not the commit to go changing how they lay out. */
.planned-course-row.is-suggested .planned-course-name { min-width:0; }

/* ── ACCOUNT: "Your data" panel ──────────────────────────────────────── */
.acct-data { margin-top:14px; padding-top:12px; border-top:1px solid var(--border-light); }
.acct-data .acct-actions { margin-top:8px; }

/* ── PLAN: autofill toolbar, notice, first-run hero ──────────────────────── */
.plan-notice { font-size:12.5px; color:var(--text-secondary); line-height:1.45; margin:-4px 0 12px; }
.plan-notice:empty { display:none; }        /* no reserved blank row before the first run */
.plan-notice.muted { color:var(--text-tertiary); }

/* DP40 removed .plan-hero and .plan-hero-line with the empty-plan banner they
   dressed — a dashed box reading "No planned courses." above a grid of visibly
   empty semester cards. #plan-hero is still the container above the summary and
   is left empty, so nothing here reserves height for it. */


/* "N suggested · Accept all" on a semester card header and in Semester Focus. */
.sem-sug-count { font-size:10.5px; font-weight:600; color:var(--rice-blue-bright); white-space:nowrap; }
.sem-sug-count:empty { display:none; }

/* ── SEMESTER FOCUS: the suggestion rails ───────────────────────────────── */

.rail { margin-bottom:18px; }
.rail-head { font-size:10.5px; font-weight:700; letter-spacing:.08em; text-transform:uppercase;
  color:var(--text-tertiary); margin-bottom:6px; }
.rail-row { display:flex; align-items:center; gap:4px 8px; padding:4px 4px;
  border-bottom:1px solid var(--border-light); }
.rail-row:last-child { border-bottom:none; }
/* DP41: the badges and the two answers are each one group, so a narrow rail
   wraps between them and never between Add and Dismiss. */
.rail-meta { display:inline-flex; align-items:center; gap:4px; flex:0 1 auto; min-width:0; }
.rail-meta:empty { display:none; }
.rail-acts { display:inline-flex; align-items:center; gap:4px; flex:0 0 auto; margin-left:auto; }
.rail-open { flex:1; min-width:0; display:flex; align-items:baseline; gap:8px;
  background:none; border:none; padding:0; text-align:left; cursor:pointer; font-family:var(--font-sans); }
.rail-open:hover .rail-code, .rail-open:hover .rail-name { text-decoration:underline; }
.rail-code { font-variant-numeric:tabular-nums; font-size:11.5px; font-weight:600; color:var(--rice-blue); white-space:nowrap; }
.rail-name { font-size:12.5px; color:var(--text-primary); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.rail-dist { font-size:9px; font-weight:700; padding:1px 4px; border-radius:3px; background:var(--accent-bg); color:var(--rice-blue); }
.rail-cr { font-size:11px; color:var(--text-tertiary); white-space:nowrap; }
/* "not offered" is a fact about the shipped term only; a term Rice has not
   published gets no badge at all rather than a guess. */
.rail-off, .rail-warn { font-size:9px; font-weight:700; padding:1px 4px; border-radius:3px;
  background:var(--warn-bg); color:var(--warn-text); white-space:nowrap; }
/* In a suggested row this chip sits alongside the why pill inside a ~290px card.
   Both are allowed to give before the answer buttons do; the pill goes first
   because "prereq" is the fact that changes whether you would take the course. */
.planned-course-row.is-suggested .rail-warn { flex:0 1 auto; min-width:0; overflow:hidden; }

/* Semester card header, two lines. The first says what the term is and must not
   wrap the name; the second appears only when there is something to act on. */
.sem-plan-line { display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between; gap:8px; }
.sem-plan-line .sem-plan-title { white-space:nowrap; flex-shrink:0; }
.sem-plan-actions-line { justify-content:flex-start; gap:12px; margin-top:2px; }
.sem-cr { color:var(--text-secondary); }
.sem-cr-over { color:var(--danger-text); font-weight:500; }
.sem-conflict { color:#d63031; font-size:10px; font-weight:600; }

/* The two answers on a suggested row. Borderless so a semester card does not turn
   into a grid of boxes; the target is the padding, not the border. */
.sug-act { display:inline-flex; align-items:center; justify-content:center; flex-shrink:0;
  width:24px; height:24px; padding:0; background:none; border:none; border-radius:var(--radius-md);
  font-size:14px; line-height:1; color:var(--text-tertiary); cursor:pointer; }
.sug-act:hover { background:var(--bg-secondary); color:var(--text-primary); }
.sug-act-accept:hover { color:var(--success-text); }

/* Suggested-course alternatives: a clear disclosure and full-row choices. */
.sug-row-actions { display:inline-flex; flex:0 0 auto; flex-wrap:nowrap; align-items:center; gap:8px; }
.sug-alts-btn { display:inline-flex; align-items:center; gap:7px; flex-shrink:0; min-height:30px; padding:4px 8px;
  background:var(--bg-primary); border:1px solid var(--border-color); border-radius:var(--radius-md);
  font-family:inherit; font-size:12px; font-weight:600; line-height:1.2; color:var(--text-primary); cursor:pointer; }
.sug-alts-btn:hover, .sug-alts-btn[aria-expanded="true"] { background:var(--bg-secondary); border-color:var(--rice-blue-bright); }
.sug-alts-chevron { width:7px; height:7px; border-right:1.5px solid currentColor; border-bottom:1.5px solid currentColor;
  transform:translateY(-2px) rotate(45deg); }
.sug-alts-btn[aria-expanded="true"] .sug-alts-chevron { transform:translateY(2px) rotate(225deg); }
.sug-alts { margin:0 0 6px; padding:4px 8px 6px 12px; border-left:2px dashed var(--border-color);
  font-size:12px; color:var(--text-secondary); }
.sug-alts-list { list-style:none; margin:0; padding:3px; max-height:280px; overflow-y:auto; overscroll-behavior:contain;
  border:1px solid var(--border-color); border-radius:var(--radius-md); background:var(--bg-primary); }
.sug-alt { margin:0; padding:0; }
.sug-alt + .sug-alt { border-top:1px solid var(--border-light); }
.sug-alt-use { display:grid; grid-template-columns:minmax(0,1fr) auto; gap:3px 8px; width:100%; min-height:44px; padding:8px;
  background:none; border:0; border-radius:var(--radius-sm); font-family:inherit; font-size:12px; line-height:1.45;
  color:var(--text-primary); text-align:left; cursor:pointer; }
.sug-alt-code { font-weight:600; }
.sug-alt-meta { display:flex; align-items:center; justify-content:flex-end; gap:4px; }
.sug-alt-name { grid-column:1 / -1; min-width:0; overflow-wrap:anywhere; }
.sug-alt-cr { font-size:11px; color:var(--text-tertiary); }
.sug-alt-off { grid-column:1 / -1; font-size:11px; color:var(--warning-text, #b45309); }
.sug-alt-use:hover { background:var(--bg-secondary); }
.sug-alts-btn:focus-visible, .sug-alt-use:focus-visible { outline:2px solid var(--rice-blue-bright); outline-offset:1px; }
.sug-alts-note, .sug-alts-status { margin:2px 0 0; font-size:12px; color:var(--text-secondary); }
.sug-alts-status:empty { display:none; }

/* ── TAP TARGETS ─────────────────────────────────────────────────────────
   Small controls whose visible glyph is the right size but whose BOX was not.
   Every one of these measured under 24x24 at 375px, several under 20. The glyphs
   are unchanged — the padding and line-height grow the hit area, and where a
   control sits in a row the growth is horizontal or absorbed by the row's own
   height so nothing gets taller. The ✓/✕ pair on a suggested row is already
   exactly 24x24 and is deliberately not touched here. */
.planned-course-del { min-width:24px; min-height:24px; display:inline-flex;
  align-items:center; justify-content:center; padding:0; line-height:1; }
.req-plan-link { min-height:24px; padding:5px 6px; display:inline-flex;
  align-items:center; }
.modal-close { min-width:32px; min-height:32px; display:inline-flex; align-items:center;
  justify-content:center; padding:0; line-height:1; }
.prog-del-btn { min-width:24px; min-height:24px; display:inline-flex; align-items:center;
  justify-content:center; padding:0; line-height:1; }
/* .btn-back's box is set with its control treatment at the end of the button
   rules (DP43) — 28px, past this block's 24px floor. */
.rail-open { min-height:24px; padding:2px 0; }

/* Progress program management shares the direct Degree editor in Settings. */
#degree-view .deg-stat-count { display:flex; align-items:baseline; gap:6px; white-space:nowrap; }
#degree-view .deg-progs-header { display:flex; align-items:center; justify-content:space-between; gap:12px; }
#degree-view .deg-progs-title { margin:0; font-size:16px; font-weight:600; letter-spacing:0; text-transform:none; }
#degree-view .deg-progs-empty { padding:4px 0 18px; color:var(--text-tertiary); font-size:13px; }
#degree-view .deg-program .deg-section-header { padding:0; gap:0; align-items:center; background:var(--bg-primary); cursor:default; }
#degree-view .deg-program-toggle { display:flex; flex:1 1 240px; align-items:center; gap:14px; min-width:0; padding:14px 16px; border:0; border-radius:0; background:none; color:var(--text-primary); font:inherit; text-align:left; cursor:pointer; }
#degree-view .deg-program-toggle:hover { background:var(--bg-secondary); }
#degree-view .deg-program-heading { flex:1; min-width:0; }
#degree-view .deg-program .deg-section-title { display:block; line-height:1.4; overflow-wrap:anywhere; }
#degree-view .deg-program .deg-section-meta { margin-top:3px; }
#degree-view .deg-program-actions { display:flex; gap:2px; padding:0 10px 0 4px; margin-left:auto; }
#degree-view .deg-program-toggle:focus-visible,
#degree-view .req-plan-link:focus-visible { outline:2px solid var(--rice-blue); outline-offset:-2px; }
#degree-view .req-plan-link { display:inline-flex; align-items:center; justify-content:center; gap:4px; flex:0 1 auto; width:auto; height:auto; min-height:28px; padding:4px 7px; border:1px solid var(--border-mid); border-radius:var(--radius); background:transparent; font-size:11.5px; font-weight:600; line-height:1.35; color:var(--rice-blue); text-decoration:none; white-space:normal; text-align:left; }
#degree-view .req-stat-top { flex-wrap:wrap; gap:3px 8px; }
#degree-view .req-stat-top .req-stat-count { margin-left:auto; }
#degree-view .row-6-wrap .req-plan-link { margin-left:auto; }
#degree-view .req-plan-link:hover { background:var(--bg-secondary); text-decoration:none; }
@media (max-width:600px) {
  #degree-view .deg-program-actions { padding:0 10px 8px; }
}

/* ── WP-16: what used to be inline style="" on index.html ─────────────────
   Moved verbatim so style-src can drop 'unsafe-inline'. Declarations are
   unchanged; only where they live has changed. Elements with an id are scoped by
   that id, which is the least invention: no new names to agree on, and the rule
   sits at a specificity between the class rules it used to sit above and the
   inline styles JS still writes, so both keep behaving as they did. */
#pending-add-bar { display:none; margin:8px 0; padding:6px 10px; background:#f0f6fc; border:1px solid #b5cbe0; border-radius:var(--radius-sm); font-size:13px; }
#pending-add-course-label { font-weight:600; font-size:13px; color:var(--text-primary); }
#prog-search-input { padding:8px 12px; font-size:13px; font-family:var(--font-sans); border:1px solid var(--border-mid); border-radius:var(--radius-md); background:var(--bg-primary); color:var(--text-primary); outline:none; width:220px; }
#prog-search-drop { display:none; min-width:300px; }
#adv-dist-pills { display:flex; gap:6px; flex-wrap:wrap; }
#adv-results-toolbar { margin-bottom:12px; display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:8px; }
#adv-results-count { font-size:13px; font-weight:600; color:var(--text-primary); }
#adv-saved-btn { padding:6px 12px; font-size:12px; font-weight:500; border:1px solid var(--border-mid); border-radius:var(--radius-md); background:var(--bg-secondary); color:var(--text-primary); cursor:pointer; }
#adv-compare-btn { display:none; padding:6px 12px; font-size:12px; font-weight:500; border:1px solid var(--border-mid); border-radius:var(--radius-md); background:var(--bg-secondary); color:var(--text-primary); cursor:pointer; }
#adv-saved-overlay { display:none; position:fixed; inset:0; z-index:9998; background:rgba(0,0,0,.55); align-items:center; justify-content:center; padding:20px; }
#adv-saved-title { font-size:16px; font-weight:700; color:var(--text-primary); }
#adv-saved-modal-footer { display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin-top:16px; padding-top:14px; border-top:1px solid var(--border-light); }
#adv-compare-title { font-size:16px; font-weight:700; color:var(--text-primary); }
#inbox-tab-inbox { overflow-y:auto; flex:1; margin:-4px -4px 0; padding:4px; }
#inbox-tab-send { overflow-y:auto; flex:1; display:flex; flex-direction:column; gap:10px; }
#inbox-footer-hint { font-size:11px; color:var(--text-tertiary); }
#interest-degree-plan-overlay { z-index:141; }
#interest-degree-plan-title { line-height:1.3; font-size:16px; }
#interest-degree-plan-credits { margin:0 0 14px; font-size:14px; color:var(--text-primary); line-height:1.5; }
#interest-degree-plan-dist { margin:0 0 14px; font-size:14px; color:var(--text-primary); line-height:1.5; }
#interest-degree-plan-ad { margin:0 0 16px; font-size:14px; color:var(--text-primary); line-height:1.5; }
#interest-degree-plan-desc-label { margin:0 0 6px; font-size:12px; color:var(--text-tertiary); text-transform:uppercase; letter-spacing:0.02em; display:none; }
#interest-degree-plan-desc { margin:0 0 16px; font-size:13px; color:var(--text-secondary); line-height:1.6; background:var(--bg-secondary); padding:8px 10px; border-radius:var(--radius-sm); border-left:3px solid var(--rice-blue); display:none; }
#interest-degree-plan-sem { width:100%; padding:8px 10px; font-size:13px; border:1px solid var(--border-mid); border-radius:var(--radius-md); background:var(--bg-primary); color:var(--text-primary); }
#prog-icon { width:80px; }
#p-dist-notice { display:none; font-size:11px; color:var(--success-text); margin-bottom:10px; padding:6px 12px; background:var(--success-bg); border-radius:var(--radius-md); border:1px solid rgba(47,107,53,.2); }
#p-dept { text-transform:uppercase; font-variant-numeric:tabular-nums; }
#p-num { font-variant-numeric:tabular-nums; }
#plan-builder-section { overflow-y:auto; flex:1; padding-right:4px; }
#my-dist-notice { display:none; font-size:11px; color:var(--success-text); margin-bottom:10px; padding:6px 12px; background:var(--success-bg); border-radius:var(--radius-md); border:1px solid rgba(47,107,53,.2); }
#my-dept { text-transform:uppercase; font-variant-numeric:tabular-nums; }
#my-num { font-variant-numeric:tabular-nums; }
#my-prereq-notice { display:none; font-size:11px; color:var(--text-secondary); margin-bottom:10px; padding:7px 12px; background:var(--warn-bg); border-radius:var(--radius-md); border:1px solid rgba(122,80,16,.2); }

/* Shared shapes that appeared more than once, and the one-offs that had no id. */
.adv-filter-row { display:flex; align-items:center; gap:8px; flex-wrap:wrap; padding:10px 0; border-top:1px solid var(--border-light); }
.mb0 { margin-bottom:0; }
.btn-row { display:flex; gap:8px; }
.ist-eyebrow { margin:0 0 6px; font-size:12px; color:var(--text-tertiary); text-transform:uppercase; letter-spacing:0.02em; }
.row-wrap { display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
/* These seven sit on .modal, which the mobile block restyles as a bottom sheet.
   As inline styles they beat that block, which is almost certainly not what anyone
   intended — the sheet was written for all of them. WP-16 kept the old behaviour
   with qualified selectors so the conversion stayed mechanical; this unqualifies
   them, so under 768px the sheet wins and above it these still do.

   In practice it moves two dialogs and only their height cap: the course overlay
   from 90vh to 88vh, and the Rice progression overlay from 92vh to 88vh. The other
   five already computed to 88vh because they set no max-height of their own. */
.modal-w560 { max-width:560px; width:100%; }
.field-rel { margin-bottom:16px; position:relative; }
.dist-row { display:flex; flex-wrap:wrap; gap:8px; align-items:center; margin-bottom:4px; }
.mr10 { margin-right:10px; }
.row-6 { display:flex; align-items:center; gap:6px; }
.row-split-wrap { display:flex; align-items:center; justify-content:space-between; gap:12px; flex-wrap:wrap; }
.pending-eyebrow { font-size:11px; font-weight:600; color:var(--rice-blue); letter-spacing:.08em; text-transform:uppercase; margin-bottom:4px; }
.txt-13-sec { font-size:13px; color:var(--text-secondary); }
.btn-compact { flex-shrink:0; font-size:12px; }
.gap8 { gap:8px; }
.rel { position:relative; }
.mb12 { margin-bottom:12px; }
.ico-4 { vertical-align:-2px; margin-right:4px; }
.ico-5 { vertical-align:-2px; margin-right:5px; }
.ico-6 { vertical-align:-2px; margin-right:6px; }
.btn-clear-all { margin-left:auto; font-size:12px; padding:6px 14px; }
.btn-row-center { display:flex; gap:8px; align-items:center; }
.row-split-mb16 { display:flex; align-items:center; justify-content:space-between; margin-bottom:16px; }
.row-split-mb18 { display:flex; align-items:center; justify-content:space-between; margin-bottom:18px; }
.row-12 { display:flex; align-items:center; gap:12px; }
.row-8 { display:flex; align-items:center; gap:8px; }
.txt-11 { font-size:11px; }
.txt-11-label { font-size:11px; color:var(--text-tertiary); font-weight:600; }
.txt-11-label-mt { font-size:11px; color:var(--text-tertiary); font-weight:600; margin-top:8px; }
.txt-11-sec { font-size:11px; color:var(--text-tertiary); }
.btn-row-end { display:flex; gap:8px; justify-content:flex-end; margin-top:8px; }
.sec-divider-top { margin-top:12px; padding-top:12px; border-top:1px solid var(--border-light); }
.ml-auto { margin-left:auto; }
.mb16 { margin-bottom:16px; }
.modal-w540 { max-width:540px; }
.mt12 { margin-top:12px; }
.btn-row-right { display:flex; gap:8px; margin-left:auto; }
.modal-w460 { max-width:460px; width:100%; }
.btn-mini { padding:4px 10px; font-size:12px; border:1px solid var(--border-mid); border-radius:var(--radius-md); background:var(--bg-secondary); color:var(--text-primary); cursor:pointer; }
.btn-mini-sec { padding:4px 10px; font-size:12px; border:1px solid var(--border-mid); border-radius:var(--radius-md); background:var(--bg-secondary); color:var(--text-secondary); cursor:pointer; }
.modal-tall-900 { max-width:900px; width:100%; max-height:92vh; display:flex; flex-direction:column; }
.modal-tall-720 { max-width:720px; width:100%; max-height:90vh; display:flex; flex-direction:column; }
.modal-tall-720b { max-width:720px; width:100%; max-height:88vh; display:flex; flex-direction:column; }
.modal-tall-640 { max-width:640px; width:100%; max-height:90vh; display:flex; flex-direction:column; }
.saved-panel { background:var(--bg-primary); border-radius:var(--radius-lg); box-shadow:0 8px 40px rgba(0,0,0,.25); max-width:660px; width:100%; max-height:82vh; overflow-y:auto; padding:24px; }

/* ── WP-16: what used to be inline style="" in js/advanced-search.js ──── */
.adv-empty-note { font-size:13px; color:var(--text-tertiary); padding:12px 0; }
.txt-tertiary { color:var(--text-tertiary); }
.btn-mini-nowrap { padding:4px 8px; font-size:11px; font-weight:500; border:1px solid var(--border-mid); border-radius:var(--radius-md); background:var(--bg-secondary); color:var(--text-primary); cursor:pointer; white-space:nowrap; }
.pr24 { padding-right:24px; }
.my1 { margin:1px 0; }
.cmp-code { font-size:13px; font-weight:700; color:var(--rice-blue); }
.txt-13 { font-size:13px; color:var(--text-primary); }
.txt-11-sec-ml { font-size:11px; color:var(--text-tertiary); margin-left:4px; }
.adv-dist-chip-ml { font-size:10px; font-weight:700; padding:2px 6px; border-radius:3px; background:#E6F1FB; color:#042C53; margin-left:6px; }
.adv-dist-chip { font-size:10px; font-weight:700; padding:2px 6px; border-radius:3px; background:#E6F1FB; color:#042C53; }
.cmp-eyebrow { font-size:10px; font-weight:700; color:var(--text-tertiary); letter-spacing:.07em; text-transform:uppercase; margin-bottom:6px; }
.adv-pager { display:flex; align-items:center; justify-content:center; gap:6px; padding:18px 0 6px; flex-wrap:wrap; }
.adv-pager-gap { color:var(--text-tertiary); padding:0 4px; }

/* Pagination buttons: one class and two modifiers, replacing three style strings
   built in JS and interpolated into the markup. */
.adv-page-btn { border-radius:var(--radius-sm); font-size:13px; cursor:pointer; padding:0 10px; height:30px; border:1px solid var(--border-mid); background:var(--bg-secondary); color:var(--text-primary); }
.adv-page-btn.is-current { border-color:var(--rice-blue); background:var(--rice-blue); color:#fff; font-weight:600; cursor:default; }
.adv-page-btn.is-disabled { opacity:0.35; cursor:default; }

/* One tab stop per course row, so the course modal is reachable without a mouse. */
.adv-course-main { flex:1; min-width:0; }
.adv-course-open { display:flex; align-items:baseline; gap:8px; flex-wrap:wrap; cursor:pointer; min-height:var(--ctl-h-sm); padding:2px 0; box-sizing:border-box; }
.adv-course-open:focus-visible { border-radius:var(--radius-sm); }


/* ── WP-16: what used to be inline style="" in the smaller files ───────── */
/* js/security.js — the access-denied page, which replaces document.body. */
.sec-denied { max-width:520px; margin:14vh auto; padding:0 24px; font-family:'Libre Franklin',system-ui,sans-serif; }
.sec-denied-eyebrow { font-size:11px; font-weight:600; letter-spacing:.08em; text-transform:uppercase; color:#8a8f98; margin-bottom:10px; }
.sec-denied-h1 { font-size:24px; font-weight:600; margin:0 0 12px; color:#00205b; }
.sec-denied-p { font-size:14px; line-height:1.6; color:#4a4f57; margin:0 0 20px; }
.sec-denied-note { font-size:13px; color:#6b7280; margin:0; }
.sec-denied-link { color:#00205b; }

/* js/boot.js — the empty-state block it writes when there is nothing to show. */
.boot-empty { text-align:center; padding:32px 16px; color:var(--text-tertiary); font-size:13px; line-height:1.6; }
.boot-empty-glyph { font-size:28px; margin-bottom:8px; }
.boot-empty-note { font-size:11px; margin-top:6px; }

/* js/catalog.js — the autocomplete's distribution tag takes its colour from the
   fixed DIST_COLORS palette, so the palette lives here as a table keyed on the
   attribute rather than being written into every row's markup. */
.ac-dist-tag[data-dist] { color:#1a1a18; }
.ac-dist-tag[data-dist="D1"], .ac-dist-tag[data-dist="D1+AD"] { background:#B5D4F4; }
.ac-dist-tag[data-dist="D2"], .ac-dist-tag[data-dist="D2+AD"] { background:#9FE1CB; }
.ac-dist-tag[data-dist="D3"], .ac-dist-tag[data-dist="D3+AD"] { background:#FAC775; }
.ac-dist-tag[data-dist="AD"] { background:#F4C0D1; }
.ac-req { font-weight:600; }
.ac-req.is-met { color:var(--success-text); }
.ac-req.is-unmet { color:#b94a00; }

/* js/advisor-dashboard.js, advisor.html */
.btn-xs { font-size:11px; padding:4px 10px; }
.op80 { opacity:.8; }

/* ── WP-16: what used to be inline style="" in js/progress-views.js ────── */
.flex1 { flex:1; }
.row-6-wrap { display:flex; align-items:center; gap:6px; flex-wrap:wrap; }
.txt-10-sec { font-size:10px; color:var(--text-tertiary); }
.txt-10-met { font-size:10px; color:var(--success-text); font-weight:600; }
.sem-status-dot { width:8px; height:8px; border-radius:50%; background:var(--success-text); display:inline-block; margin-right:4px; }
.is-placeholder-row { opacity:.55; font-style:italic; }
.op55-11 { opacity:.55; font-size:11px; }
.op45 { opacity:.45; }
.gap-list { margin:0 0 0 18px; padding:0; color:var(--text-secondary); line-height:1.55; }
.mt5-bold { margin-top:4px; font-weight:600; }
.mt4 { margin-top:4px; }
.mt10-11 { margin-top:10px; font-size:11px; }
.ml3 { margin-left:3px; }
.mb6-label { margin-bottom:6px; color:var(--text-secondary); font-weight:500; }
.span-all { grid-column:1/-1; }
.bold-mb3 { font-weight:600; margin-bottom:4px; }
.bold-warn { font-weight:600; color:var(--warn-text); }
.italic { font-style:italic; }
.txt-12-sec-loose { font-size:12px; line-height:1.55; color:var(--text-tertiary); }
.txt-12-sec { font-size:12px; color:var(--text-tertiary); }
.row-split-baseline { display:flex; justify-content:space-between; align-items:baseline; margin-bottom:4px; }
.deg-collapse-bar { cursor:pointer; user-select:none; background:var(--bg-secondary); border-radius:6px; margin-top:4px; }
.gap-more-link { cursor:pointer; color:var(--rice-blue); font-weight:500; user-select:none; font-size:10px; }

/* Values that were chosen in JS and written into the markup. The palettes are
   fixed, so they live here as tables keyed on an attribute, and the row carries
   the key rather than the colour. */
.grade-pill[data-grade] { background:var(--bg-secondary); color:#1a1a18; }
.grade-pill[data-grade="A+"] { background:#c8f7c5; }
.grade-pill[data-grade="A"] { background:#d4f5d0; }
.grade-pill[data-grade="A-"] { background:#dff5dc; }
.grade-pill[data-grade="B+"] { background:#d4eaf7; }
.grade-pill[data-grade="B"] { background:#daeef9; }
.grade-pill[data-grade="B-"] { background:#e2f2fb; }
.grade-pill[data-grade="C+"] { background:#fdf3cd; }
.grade-pill[data-grade="C"] { background:#fdf6d8; }
.grade-pill[data-grade="C-"] { background:#fef8e4; }
.grade-pill[data-grade="D+"] { background:#fde8d0; }
.grade-pill[data-grade="D"] { background:#fdecd8; }
.grade-pill[data-grade="D-"] { background:#fef0e3; }
.grade-pill[data-grade="F"] { background:#fcd6d6; }
.grade-pill[data-grade="P"] { background:#e8f8e8; }
.grade-pill[data-grade="S"] { background:#e8f8e8; }
.grade-pill[data-grade="CR"] { background:#e8f8e8; }

/* gpaColor's four tiers, named by gpaTone() (js/core.js) instead of returning a
   colour into an attribute. */
.gpa-good { color:var(--success-text); }
.gpa-ok { color:var(--accent); }
.gpa-warn { color:var(--warn-text); }
.gpa-bad { color:var(--danger-text); }
.tone-met { color:var(--success-text); }
.tone-blue { color:var(--rice-blue); }

/* Requirement rows: done and not-done differ only in two colours. */
.req-code { font-variant-numeric:tabular-nums; font-weight:600; font-size:12px; color:var(--text-tertiary); }
.req-code.is-done { color:var(--rice-blue); }
.req-name { color:var(--text-secondary); }
.req-name.is-done { color:var(--text-primary); }
/* DP-137: met by a planned course. The term tag says "Planned", the mark is hollow,
   and nothing borrows the green that means earned. */
.req-code.is-planned { color:var(--rice-blue); }
.req-name.is-planned { color:var(--text-primary); }
.req-sem.is-planned { color:var(--rice-blue); font-weight:600; }
.req-status.planned { background:transparent; border:1.5px dashed var(--rice-blue); }
.prog-badge.planned { background:var(--accent-bg); color:var(--rice-blue); }
.req-stat-count.planned { color:var(--rice-blue); }
.req-stat-rule > span.is-planned { background:var(--rice-blue); }
.txt-10-planned { font-size:10px; color:var(--rice-blue); font-weight:600; }

/* Progress bars. The percentage is data on the element and applied by
   js/progress-views.js after render with a CSSOM write, which style-src does not
   govern; the two fill colours are classes. */
.prog-bar-fill { background:var(--rice-blue); }
.prog-bar-fill.is-met { background:var(--success-text); }
.prog-bar-fill.is-partial { background:var(--accent); }
.req-stat-rule > span.is-met { background:var(--success-text); }

/* Group and field headings, indents, and the two row tones. */
.deg-group-head { cursor:default; margin-bottom:0; }
.deg-group-head.has-note { margin-bottom:6px; }
.deg-field-head { font-size:11px; font-weight:700; color:var(--text-tertiary); margin:18px 0 6px 0; letter-spacing:.04em; text-transform:uppercase; border-bottom:1px dashed var(--border-light); padding-bottom:4px; }
.deg-field-head.is-first { margin-top:6px; }
.deg-indent { padding-left:16px; }
.deg-indent.is-grayed { opacity:0.4; pointer-events:none; }
.prog-grid { padding:0 0 4px; }
.prog-grid.cols-1 { grid-template-columns:1fr; }
.prog-grid.cols-2 { grid-template-columns:repeat(2,1fr); }
.planned-course-row.is-placeholder-row { opacity:.55; font-style:italic; }
.planned-course-row.is-past-row { background:var(--bg-secondary); }


/* ── WP-16: what used to be inline style attributes in the last four files —
   rice-progressions.js, plan-builder.js, interest-search.js, modals.js ─── */
.rp-lead { font-size:14px; color:var(--text-secondary); margin-bottom:6px; }
.rp-panel { border:1px solid var(--border-light); border-radius:var(--radius-lg); background:var(--bg-primary); box-shadow:var(--shadow-sm); }
.rp-scroll-pad { max-height:240px; overflow-y:auto; padding:0 14px 10px; }
.rp-box { margin:10px 0 16px; border:1px solid var(--border-light); border-radius:var(--radius-md); background:var(--bg-secondary); }
.my8 { margin-top:8px; margin-bottom:8px; }
.rp-scroll { margin-top:10px; max-height:240px; overflow-y:auto; }
.rp-btn-row { margin-top:10px; display:flex; gap:8px; flex-wrap:wrap; }
.rp-note { margin-bottom:10px; border:1px solid var(--border-light); border-radius:var(--radius-md); padding:8px 12px; background:var(--bg-secondary); }
.btn-sm { font-size:12px; padding:5px 12px; }
.txt-125-sec { font-size:12.5px; color:var(--text-secondary); }
.rp-label { font-size:11px; font-weight:600; color:var(--text-secondary); margin-bottom:6px; }
.rp-chip-warn { font-size:10px; font-weight:700; padding:2px 6px; border-radius:4px; background:var(--warn-bg); color:var(--warn-text); white-space:nowrap; }
.rp-chip-ok { font-size:10px; font-weight:700; padding:2px 6px; border-radius:4px; background:var(--success-bg); color:var(--success-text); white-space:nowrap; }
.rp-code { font-variant-numeric:tabular-nums; font-weight:600; color:var(--rice-blue); }
.rp-actions { display:flex; justify-content:flex-end; gap:8px; margin-top:16px; padding-top:12px; border-top:1px solid var(--border-light); }
.rp-row { display:flex; align-items:center; gap:8px; flex-wrap:wrap; font-size:12px; padding:5px 0; border-bottom:1px solid var(--border-light); }
.rp-head-row { display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin-bottom:12px; }
.rp-toggle-pad { cursor:pointer; font-size:12px; font-weight:600; color:var(--rice-blue); padding:8px 12px; }
.rp-toggle { cursor:pointer; font-size:12px; font-weight:600; color:var(--rice-blue); }
.txt-secondary { color:var(--text-secondary); }
.link-inline { color:var(--rice-blue); cursor:pointer; text-decoration:underline; }
.prewrap { white-space:pre-wrap; }
.pb-lead { font-weight:500; font-size:13px; color:var(--text-primary); margin-bottom:8px; }
.pb-lead-blue { font-weight:600; font-size:13px; color:var(--rice-blue); margin-bottom:8px; }
.txt-primary { color:var(--text-primary); }
.btn-sm-pad { padding:7px 12px; font-size:12px; }
.is-title { min-width:0; flex:1; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.is-actions { margin-top:10px; padding-top:10px; border-top:1px solid var(--border-light); display:flex; gap:8px; flex-wrap:wrap; }
.mb6 { margin-bottom:6px; }
.is-name { font-weight:500; font-size:13px; color:var(--text-primary); margin-left:8px; }
.is-meta { font-size:11px; color:var(--text-tertiary); flex-shrink:0; }
.is-row { display:flex; align-items:center; justify-content:space-between; gap:10px; padding:10px 12px; border:1px solid var(--border-light); border-radius:var(--radius-md); background:var(--bg-primary); cursor:pointer; }
.inp-dept { max-width:80px; text-transform:uppercase; }
.inp-num { max-width:70px; }
.my2 { margin:2px 0; }
.mb8 { margin-bottom:8px; }
.req-match-head { font-weight:600; margin-bottom:4px; font-size:11px; text-transform:uppercase; letter-spacing:.04em; color:var(--rice-blue); }
.txt-blue-bold { color:var(--rice-blue); font-weight:600; }
.is-detail { padding:12px; border:1px solid var(--border-light); border-top:none; border-radius:0 0 var(--radius-md) var(--radius-md); background:var(--bg-secondary); cursor:default; }

/* Initially hidden, revealed by JS. Deliberately NOT !important: every reveal in
   this codebase sets an explicit inline display ('block', 'flex'), and an inline
   value beats a class, so those keep working untouched. The two places that
   revealed by clearing the inline style instead were changed to remove the class.

   It sits here, last before the mobile block, because it has to beat the ordinary
   class rules it is hiding — .adv-compare-overlay carries display:flex. The T037
   block below restates it with !important as its last rule, so an element that
   carries is-hidden in markup can only be shown by removing the class: an inline
   display write cannot beat it (that is how the Compare overlay went dark once). */
.is-hidden { display:none; }
/* Shown only on paper. The mirror of .is-hidden: something the screen does not
   need and the printout does — currently the note that stands in for suggestions
   the printout leaves out. */
.print-only { display:none; }

/* ══ T037 · ONE CONTROL SYSTEM ═══════════════════════════════════════════════
   The approved T036 proposal (status/T036.md §3.1). Before this block the app
   had 30 button selectors at 15 heights, 5 radii, 10 type sizes and 7 focus
   rings. This block defines the tokens and the four roles ONCE and re-points
   every legacy selector at them; the markup is untouched (differential vs the
   previous commit is zero DOM hunks). T039 renames the markup to the role
   classes and deletes the legacy names from the selector lists below.

   Roles:  primary   .btn-primary   (.add-btn, .btn-save)         ≤1 per view
           secondary .btn           (.btn-cancel as an action, .add-btn.ghost)
           quiet     .btn-quiet     (Cancel/Close/Undo/← back, text links)
           danger    .btn-danger    (.btn-delete, Clear/Delete, Reject all)
   Sizes:  --ctl-h 32 everywhere a control stands alone; --ctl-h-sm 24 for
           controls inside a row (the a11ycheck floor). Plan rows themselves keep
           the WP-05 height; only their controls are sized here.
   It sits after every desktop rule so source order settles ties, and before the
   mobile block, which must stay last. */
:root {
  --ctl-h:32px; --ctl-h-sm:24px; --ctl-r:var(--radius-md);
  --ctl-fs:13px; --ctl-fs-sm:12px; --ctl-px:12px; --ctl-px-sm:8px; --ctl-gap:8px;
  --focus-ring:0 0 0 2px var(--bg-primary), 0 0 0 4px var(--rice-blue-bright);
}

/* Base: every standalone control. Secondary is the base look. */
.btn, .add-btn, .btn-cancel, .btn-save, .btn-delete, .sec-idle-warning-btn,
.btn-mini, .btn-mini-sec, .btn-mini-nowrap, .adv-page-btn, #adv-saved-btn, #adv-compare-btn {
  display:inline-flex; align-items:center; justify-content:center; gap:6px;
  min-height:var(--ctl-h); padding:0 var(--ctl-px); border-radius:var(--ctl-r);
  font-family:var(--font-sans); font-size:var(--ctl-fs); font-weight:500; line-height:1.2;
  border:1px solid var(--border-mid); background:var(--bg-primary); color:var(--text-primary);
  cursor:pointer; white-space:nowrap; box-shadow:none; text-decoration:none;
  transition:background .12s, border-color .12s, color .12s; }
.btn:hover, .add-btn.ghost:hover, .btn-cancel:hover, .btn-mini:hover, .btn-mini-sec:hover, .btn-mini-nowrap:hover,
.adv-page-btn:hover, #adv-saved-btn:hover, #adv-compare-btn:hover {
  background:var(--bg-secondary); border-color:var(--border-strong); color:var(--text-primary); }
.add-btn.ghost { background:var(--bg-primary); border-color:var(--border-mid); color:var(--text-primary); font-weight:500; box-shadow:none; }
.btn:disabled, .add-btn:disabled, .btn-cancel:disabled, .btn-save:disabled { opacity:.45; cursor:default; }

/* Primary */
.btn-primary, .add-btn, .btn-save, .sec-idle-warning-btn {
  background:var(--rice-blue); border-color:var(--rice-blue); color:#fff; font-weight:600; }
.btn-primary:hover, .add-btn:hover, .btn-save:hover, .sec-idle-warning-btn:hover {
  background:var(--rice-blue-deep); border-color:var(--rice-blue-deep); color:#fff; box-shadow:none; }
.add-btn.ghost:hover { background:var(--bg-secondary); border-color:var(--border-strong); color:var(--text-primary); }

/* Quiet: navigation, dismissal, text links that are really buttons. */
.btn-quiet, .btn-back, .cp-back, .wiz-skip, .acct-link, .sem-req-showagain,
.adv-desc-toggle, .req-plan-link, .rv-flag-btn, .sem-empty-link, .gap-more-link, .rp-toggle {
  display:inline-flex; align-items:center; gap:4px; min-height:var(--ctl-h-sm); padding:0 6px;
  border:1px solid transparent; border-radius:var(--ctl-r); background:none;
  font-family:var(--font-sans); font-size:var(--ctl-fs-sm); font-weight:500; line-height:1.2;
  color:var(--text-secondary); text-decoration:none; cursor:pointer; white-space:nowrap; }
.btn-quiet:hover, .btn-back:hover, .cp-back:hover, .wiz-skip:hover, .acct-link:hover,
.sem-req-showagain:hover, .adv-desc-toggle:hover, .req-plan-link:hover,
.rv-flag-btn:hover, .sem-empty-link:hover, .gap-more-link:hover, .rp-toggle:hover {
  background:var(--bg-secondary); color:var(--text-primary); text-decoration:none; }
.btn.btn-quiet { border-color:transparent; background:none; }
.btn.btn-quiet:hover { background:var(--bg-secondary); border-color:transparent; }
/* DP43: the one back control that sits INSIDE a toolbar row rather than above a
   page body, so it needs an edge to be read as a control at all — under the quiet
   group alone it was secondary-grey text on a transparent border, indistinguishable
   from the year label two items to its right until you hovered it. It keeps that
   group's radius and type scale; a hairline border in the same token every .btn
   uses, the page's own surface, and 28px against the toolbar's 32px actions are
   the whole difference. Recognizably a control, still second to them. */
.btn-back { min-height:28px; padding:0 9px; border-color:var(--border-mid);
  background:var(--bg-primary); font-weight:600; }
.btn-back:hover { background:var(--bg-secondary); border-color:var(--border-strong); color:var(--text-primary); }
/* Page back controls share the compact bordered treatment used by Semester.
   Class Chats keeps the heading layout only: it has no back control (DP65). */
.cp-toolbar .toolbar-left, .chat-heading .toolbar-left {
  display:flex; align-items:center; gap:6px 12px; flex-wrap:wrap; }
.cp-toolbar .cp-back {
  min-height:28px; padding:0 9px; margin:0; border-color:var(--border-mid);
  background:var(--bg-primary); font-size:var(--ctl-fs-sm); font-weight:600; }
.cp-toolbar .cp-back:hover {
  background:var(--bg-secondary); border-color:var(--border-strong); color:var(--text-primary); }
.sem-empty-link { display:inline; min-height:0; padding:0; text-decoration:underline; font-size:inherit; }

/* Danger: destructive, always last in its group. */
.btn-danger, .btn-delete, .acct-link-danger, .prog-del-btn { color:var(--danger); }
.btn-delete, .btn.btn-danger { background:none; border-color:transparent; }
.btn-danger:hover, .btn-delete:hover, .acct-link-danger:hover, .prog-del-btn:hover {
  background:var(--danger-bg); border-color:var(--danger); color:var(--danger); }

/* Small: controls that sit inside a row or a card header. */
.btn-sm, .btn-compact, .btn-clear-all, .rv-write-btn, .btn-mini, .btn-mini-sec, .btn-mini-nowrap, .adv-page-btn,
#adv-saved-btn, #adv-compare-btn, .rev-row-btn {
  min-height:var(--ctl-h-sm); padding:0 var(--ctl-px-sm); font-size:var(--ctl-fs-sm); }
/* Two legacy rules carry !important; matched here until T039 deletes both. */
.adv-sm-btn { min-height:var(--ctl-h-sm); padding:0 var(--ctl-px-sm) !important; font-size:var(--ctl-fs-sm) !important; }
.rev-row-btn { margin-left:4px; border-color:var(--border-light); color:var(--text-secondary); }

/* Icon buttons: a square target around a glyph. */
.btn-icon, .sug-act, .planned-course-del, .modal-close, .wiz-chip-x,
.inbox-item-delete, .prog-del-btn, .adv-star-btn, .adv-saved-row-remove, .notepad-icon-btn {
  display:inline-flex; align-items:center; justify-content:center; flex-shrink:0;
  min-width:var(--ctl-h-sm); min-height:var(--ctl-h-sm); padding:0; margin:0;
  border:1px solid transparent; border-radius:var(--ctl-r); background:none; line-height:1;
  color:var(--text-tertiary); cursor:pointer; }
.btn-icon:hover, .sug-act:hover, .modal-close:hover, .wiz-chip-x:hover,
.adv-star-btn:hover, .adv-saved-row-remove:hover, .notepad-icon-btn:hover, .inbox-item-delete:hover {
  background:var(--bg-secondary); color:var(--text-primary); }
.btn-icon.btn-lg, .modal-close { min-width:var(--ctl-h); min-height:var(--ctl-h); font-size:20px; }
.sug-act { font-size:14px; }
.sug-act-accept:hover { color:var(--success-text); }
.inbox-item-delete:hover { background:var(--danger-bg); color:var(--danger); }
.adv-star-btn:hover { transform:none; background:none; color:var(--text-primary); }
.adv-star-btn.starred, .adv-star-btn.starred:hover { color:#f59e0b; }
.planned-course-del { margin-left:0; }
.prog-del-btn { margin-left:4px; }
.rev-row-btn { display:inline-flex; align-items:center; }

/* Chips: filters and tags; a state, not an action. */
.chip, .dist-pill, .adv-dist-pill, .ad-toggle, .wiz-chip, .cp-link {
  display:inline-flex; align-items:center; gap:6px; min-height:var(--ctl-h-sm); padding:0 10px;
  border:1px solid var(--border-mid); border-radius:var(--radius-sm); background:var(--bg-primary);
  font-family:var(--font-sans); font-size:var(--ctl-fs-sm); font-weight:500; line-height:1.2;
  color:var(--text-secondary); cursor:pointer; box-shadow:none; user-select:none; white-space:nowrap; }
.chip:hover, .dist-pill:hover, .adv-dist-pill:hover, .ad-toggle:hover, .cp-link:hover {
  border-color:var(--rice-blue); color:var(--rice-blue); background:var(--bg-primary); }
.chip.is-on, .chip[aria-pressed="true"], .adv-dist-pill.active { background:var(--rice-blue); border-color:var(--rice-blue); color:#fff; }
/* Pressed dist pills keep their per-distribution colour (rules at the top of the file). */
.chip.dist-pill.sel-d2 { background:#2e7d46; border-color:#2e7d46; }
.chip.dist-pill.sel-d3 { background:#a85d0a; border-color:#a85d0a; }
.chip.dist-pill.sel-fwis { background:#2f6b35; border-color:#2f6b35; }
.chip.dist-pill.sel-lpap { background:#7a5010; border-color:#7a5010; }
.chip.ad-toggle[aria-pressed="true"] { background:#6b2c91; border-color:#6b2c91; }
/* A long program name ("BS in Electrical and Computer Engineering · Photonics, …")
   wraps inside its chip instead of running past a phone screen. */
.wiz-chip { padding:4px 2px 4px 10px; cursor:default; white-space:normal; max-width:100%; text-align:left; }
.wiz-chip { color:var(--text-primary); background:var(--bg-secondary); }
.cp-link { font-variant-numeric:tabular-nums; font-size:11.5px; }

/* Selects and text inputs share the control height and radius. */
.ctl, #my-grad-year, .my-controls select, .cp-sem, .adv-filter-input,
.field input, .field select, .wiz-input, .rv-field select, .rv-input, .adv-compare-slot-search,
.inbox-send-filter-field select, .inbox-send-filter-field input {
  min-height:var(--ctl-h); padding:0 var(--ctl-px); border:1px solid var(--border-mid); border-radius:var(--ctl-r);
  background:var(--bg-primary); color:var(--text-primary); font-family:var(--font-sans); font-size:var(--ctl-fs); }
/* Plan graduation year shares the toolbar's control rhythm without a box. */
#multiyear-view .plan-grad-control { display:flex; align-items:center; gap:2px; min-height:var(--ctl-h); white-space:nowrap; }
#multiyear-view .plan-grad-control label { color:var(--text-secondary); font-size:var(--ctl-fs); font-weight:500; }
#multiyear-view #my-grad-year { width:auto; padding:0 6px; border-color:transparent; background:transparent; font-weight:500; font-variant-numeric:tabular-nums; cursor:pointer; appearance:auto; }
#multiyear-view #my-grad-year:hover { background:var(--bg-secondary); border-color:var(--border-mid); }
#multiyear-view #my-grad-year:focus-visible { outline:2px solid var(--rice-blue); outline-offset:2px; }
.cp-sem { font-size:var(--ctl-fs); }
.field input:hover, .field select:hover, #my-grad-year:hover, .cp-sem:hover { border-color:var(--border-strong); }

/* Segmented cluster: adjacent controls share one border; radius on the outer ends only. */
.btn-group, .btn-split { display:inline-flex; align-items:stretch; }
.btn-group > *, .btn-split > * { border-radius:0; margin-left:-1px; position:relative; }
.btn-group > :first-child, .btn-split > :first-child { border-top-left-radius:var(--ctl-r); border-bottom-left-radius:var(--ctl-r); margin-left:0; }
.btn-group > :last-child, .btn-split > :last-child { border-top-right-radius:var(--ctl-r); border-bottom-right-radius:var(--ctl-r); }
.btn-group > .btn-quiet, .btn-group > .btn-danger { border-color:var(--border-mid); }
.btn-group > :hover, .btn-group > :focus-visible, .btn-split > :focus-visible { z-index:1; }
.btn-count { font-variant-numeric:tabular-nums; color:inherit; opacity:.75; margin-left:2px; }

/* One focus ring. box-shadow rather than outline so it survives the clipped ends of a
   segmented cluster; :focus-visible only, so mouse clicks stay quiet. Replaces the
   global outline rule and its seven local variants. */
button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible, summary:focus-visible,
[role="button"]:focus-visible, [role="menuitem"]:focus-visible, .req-item.tappable:focus-visible, a.brand-link:focus-visible,
.field input:focus-visible, .field select:focus-visible, .acct-input:focus-visible, .wiz-input:focus-visible {
  outline:none; box-shadow:var(--focus-ring); }
#rice-brand :focus-visible { box-shadow:0 0 0 2px var(--rice-blue), 0 0 0 4px #fff; }

/* The five defects found by the T036 audit (status/T036.md §1.8). */
/* (a) The course code and name on every plan row are <button>s with no rule of their own,
       so they rendered with the browser's default button chrome. */
.row-course-link { background:none; border:0; margin:0; padding:2px 0; line-height:20px; text-align:left;
  cursor:pointer; border-radius:2px; vertical-align:baseline; }
.row-course-link.planned-course-name { font-family:inherit; font-size:inherit; font-weight:inherit; display:inline-block; }
.row-course-link:hover { text-decoration:underline; }
/* (b) Print is a <button> styled as a link; give it the 24 px target without moving it. */
#rice-brand button.brand-link { min-height:var(--ctl-h-sm); display:inline-flex; align-items:center; padding:0 4px; margin-left:14px; border-radius:var(--ctl-r); }
/* (c) .cp-sem and (d) #adv-saved-btn are covered by the select and base lists above. */
/* (e) Dialog dist pills (div[role=button]) and Courses dist pills now share one chip rule. */
/* Sub-24 px targets the T038 walk found; the glyphs are unchanged. */
.sem-plan-title { min-height:var(--ctl-h-sm); }
.add-planned-btn { min-height:var(--ctl-h-sm); border-radius:var(--ctl-r); font-size:var(--ctl-fs-sm); }

/* ── Menu (js/menu.js) — one element, positioned by class + custom properties ── */
.menu { position:fixed; top:var(--menu-top, 0); left:var(--menu-left, 0); z-index:300; min-width:180px; max-width:min(320px, calc(100vw - 16px)); padding:4px; background:var(--bg-primary); border:1px solid var(--border-mid); border-radius:var(--ctl-r); box-shadow:var(--shadow-md); display:flex; flex-direction:column; }
.menu.menu-below-left { left:auto; right:var(--menu-right, 0); }
.menu-item { display:flex; align-items:center; justify-content:flex-start; width:100%; min-height:var(--ctl-h); padding:0 10px; border:0; border-radius:var(--radius-sm); background:none; color:var(--text-primary); font-family:var(--font-sans); font-size:var(--ctl-fs); font-weight:500; line-height:1.2; text-align:left; cursor:pointer; white-space:nowrap; }
.menu-item:hover, .menu-item:focus-visible { background:var(--bg-secondary); }
.menu-item.is-danger { color:var(--danger); }
.menu-item.is-danger:hover, .menu-item.is-danger:focus-visible { background:var(--danger-bg); }
.menu-item[disabled] { opacity:.45; cursor:default; }
.menu-item[disabled]:hover { background:none; }
.menu-sep { height:1px; margin:4px 2px; background:var(--border-light); }
/* A button that opens a menu keeps its caret in its own aria-hidden span, so a
   script can rewrite the label ("Autofill again") without losing the caret. */
.btn-menu-caret { margin-left:6px; font-size:10px; line-height:1; opacity:.7; }
.btn-group .btn { font-variant-numeric:tabular-nums; }

/* ── Projected completion, one row (commit 4). Big figures, small labels; the
   detail behind them is one quiet link away on Progress. ── */
/* DP-81: one compact line of value+label pairs in the body face. Values are a
   size step up, not a display size; met figures stay neutral and only what is
   still short carries the one accent. */
.my-summary-row .my-projected-block { padding:8px 14px; background:var(--bg-primary); border:1px solid var(--border-light); border-radius:var(--radius-md); }
.headline-row { display:flex; align-items:baseline; flex-wrap:wrap; gap:4px 20px; min-height:24px; }
.headline { display:inline-flex; align-items:baseline; gap:5px; font-size:12px; font-weight:500; color:var(--text-secondary); white-space:nowrap; }
.headline-val { font-size:14px; font-weight:600; letter-spacing:0; font-variant-numeric:tabular-nums; color:var(--text-primary); }
.headline-val.done { color:var(--text-primary); }
.headline-val.warn { color:var(--warn-text); }
.headline-link { margin-left:auto; }

/* ── Semester card / view: "3 suggested ✓│✕" and the ⋯ (commit 3) ── */
.sem-sug-group { display:inline-flex; align-items:center; gap:8px; }
.sem-sug-count { font-size:11px; }
.sem-plan-meta .sem-menu-btn { margin-left:2px; }
.sem-block-meta #sem-sug-line { display:inline-flex; align-items:center; gap:8px; }
.sem-block-meta .btn-group .btn { min-height:20px; }

/* ── Semester view: the requirements block (#sem-reqs) ──
   DP61: one line per open demand — label left, count right — under the shared
   block head, so the panel is a scan of what is left rather than a stack of
   two-line rows. Since 6.0.6 it is a card of the main column, at full length. ── */
.sem-reqs { display:flex; flex-direction:column; }
.sem-reqs:empty { display:none; }
.sem-req-section { display:flex; flex-direction:column; }
.sem-req-head { display:flex; align-items:baseline; justify-content:space-between; gap:8px;
  margin:14px 0 3px; }
.sem-req-section:first-child .sem-req-head { margin-top:8px; }
.sem-req-head h3 { margin:0; font-size:11px; font-weight:700; letter-spacing:.05em;
  text-transform:uppercase; color:var(--text-tertiary); }
.sem-req-group { font-size:11px; font-weight:600; color:var(--text-tertiary); margin:6px 0 1px; padding:0 6px; }
.sem-req-row { display:flex; align-items:baseline; justify-content:space-between; gap:6px 12px; width:100%;
  min-height:var(--ctl-h-sm); padding:4px 6px; border:1px solid transparent; border-radius:var(--ctl-r); background:none;
  font-family:var(--font-sans); font-size:var(--ctl-fs-sm); line-height:1.35; color:var(--text-secondary); text-align:left; cursor:pointer; }
.sem-req-row:hover { background:var(--bg-secondary); color:var(--text-primary); }
.sem-req-row.is-on { background:var(--accent-bg); border-color:var(--rice-blue); color:var(--rice-blue); }
.sem-req-label { min-width:0; overflow-wrap:anywhere; }
.sem-req-count { flex-shrink:0; font-weight:600; font-variant-numeric:tabular-nums; }
.sem-req-fold, .sem-req-showagain { align-self:flex-start; }
.sem-req-hours { display:flex; align-items:center; flex-wrap:wrap; gap:4px;
  margin-top:12px; padding-top:8px; border-top:1px solid var(--border-light);
  font-size:11px; color:var(--text-tertiary); }
.sem-req-empty { font-size:12.5px; color:var(--text-tertiary); line-height:1.5; }

/* Plan cards reserve a line for the full title. Metadata and actions can wrap
   independently, so narrow cards (or an extra action) cannot squeeze it away. */
.sem-plan-body .planned-course-row { flex-wrap:wrap; gap:2px 5px; min-height:28px; }
/* DP-71: the title shares the line with the code and credits and wraps only when
   the card is too narrow to hold it; it is never clipped. */
.sem-plan-body .planned-course-name { order:0; flex:0 1 auto; min-width:0; min-height:0;
  white-space:normal; overflow:visible; text-overflow:clip; overflow-wrap:anywhere; line-height:1.4; }
.sem-plan-body .planned-course-name:empty { display:none; }
.sem-plan-body .planned-course-cr { margin-left:0; }
.sem-plan-body .plan-drag-handle.spacer { display:none; }
.sem-plan-body .planned-course-del { flex-shrink:0; order:3; margin-left:auto; }
.sem-plan-body .sug-row-actions { order:3; margin-left:auto; }
/* Review and credits sit at the card's right edge, apart from the code, title
   and marks. Every row has a credits span; whichever of the two comes first takes
   the free space, so the edit or delete control after them must not also. */
.sem-plan-body .planned-course-row > .rev-row-btn,
.sem-plan-body .planned-course-row > .planned-course-cr { margin-left:auto; }
.sem-plan-body .planned-course-row > .rev-row-btn + .planned-course-cr,
.sem-plan-body .planned-course-row > .planned-course-cr ~ .planned-course-del,
.sem-plan-body .planned-course-row > .planned-course-cr ~ .sug-row-actions { margin-left:0; }
.sem-plan-body .planned-course-row:focus-within .planned-course-del { opacity:1; }
.sem-plan-body .row-prereq-warn { order:0; flex:0 1 auto; min-width:0; margin-left:0;
  white-space:normal; overflow-wrap:anywhere; }
details.row-prereq-warn { font-weight:500; color:var(--warn-text); position:relative; max-width:100%; }
details.row-prereq-warn > summary { min-height:24px; display:flex; align-items:center; gap:4px; cursor:pointer; list-style:none; font-size:11px; }
details.row-prereq-warn > summary::-webkit-details-marker { display:none; }
details.row-prereq-warn > summary::after { content:'▾'; font-size:10px; }
details.row-prereq-warn[open] > summary::after { content:'▴'; }
.plan-suggestion-resolution { display:block; white-space:normal; font-size:12px; line-height:1.45; padding:6px 8px; background:var(--warn-bg); border-radius:var(--radius-sm); overflow-wrap:anywhere; }
.plan-suggestion-resolution .btn { margin:4px 4px 0 0; min-height:28px; white-space:normal; }

/* ── DP61: one rhythm for every row in this view ──
   A row is one line — code, title, marks, credits, action — with the credits and
   the action aligned down the column. The title had been given a full-width line
   of its own (flex:1 0 100%), so every row was two lines in a column with room
   to spare; it shares the line now and wraps only when it runs out of room. A
   prerequisite warning still takes its own line: it is a warning, not a name. */
/* DP60: separated rows, not one bordered card per course (was a 1px box plus a
   10px gutter each). Row padding is the spacing now. */
.sem-course-item { margin:0; border:0; border-top:1px solid var(--border-light); border-radius:0; }
.sem-course-item:first-child { border-top:0; }
/* Carries the pending distinction the card used to carry (the ✓/✕ pair was the
   only other mark). Inset rule, as .ms-opt does it. MUST stay after
   .sem-course-item: same specificity, later wins. */
.sem-course-suggested { background:var(--bg-secondary); box-shadow:inset 2px 0 0 var(--rice-blue); }
#sem-rows .planned-course-row { display:flex; flex-wrap:wrap; align-items:center; gap:2px 6px; padding:4px; margin:0; border-radius:0; }
#sem-rows .plan-drag-handle { display:none; }
#sem-rows .planned-course-name { flex:0 1 auto; order:0; width:auto; min-width:0; max-width:none; white-space:normal; overflow:visible; text-overflow:clip; overflow-wrap:anywhere; font-size:13px; line-height:1.45; }
#sem-rows .row-course-link.planned-course-name,
.sem-plan-body .row-course-link.planned-course-name { min-height:24px; }
/* A column, not a prefix: every code starts and every title starts at the same x. */
#sem-rows .planned-course-code { flex:0 0 auto; min-width:5rem; font-size:12px; }
#sem-rows .planned-course-cr { margin-left:0; flex:0 0 auto; min-width:0; text-align:left; font-variant-numeric:tabular-nums; }
#sem-rows .planned-course-del, #sem-rows .sug-act { opacity:1; width:auto; min-height:var(--ctl-h-sm); padding:2px 7px; font-family:var(--font-sans); font-size:12px; }
/* The answers are real text buttons here, so the invisible target extender the
   24px glyphs carry on a phone (see the 768px block) only pushed this row's
   content past its own box, which made .sem-focus scroll sideways when narrow. */
#sem-rows .sug-act::after { content:none; }
#sem-rows .sug-row-actions { flex:0 0 auto; order:3; margin-left:auto; }
#sem-rows .row-prereq-warn { order:0; flex:0 1 auto; min-width:0; margin-left:0; white-space:normal; overflow-wrap:anywhere; }
/* DP42 removed .sem-course-why, the explanation paragraph under a pending
   suggestion; the row's own padding is the whole card's spacing now, so the
   card closes directly under the row rather than reserving a second block. */
.sem-pending-title { margin:18px 0 4px; font-size:11px; font-weight:700; letter-spacing:.06em;
  text-transform:uppercase; color:var(--text-tertiary); }
/* Saved courses is a block like the others now: the head carries the rule, so the
   section does not need a second one of its own above it. */
.sem-saved-count { font-size:11.5px; color:var(--text-secondary); font-variant-numeric:tabular-nums; }
.sem-saved-hint, .sem-saved-notice { margin:8px 0 0; color:var(--text-secondary); font-size:12.5px; line-height:1.5; }
.sem-saved-notice:empty { display:none; }
.sem-saved-row { display:flex; align-items:center; flex-wrap:wrap; gap:2px 10px;
  padding:4px 8px; border-top:1px solid var(--border-light); }
.sem-saved-row:first-child { border-top:0; }
.sem-saved-open { display:flex; align-items:center; flex-wrap:wrap; gap:2px 10px; flex:1 1 14rem;
  min-width:0; min-height:24px; padding:0; background:none; border:0; font-family:var(--font-sans); text-align:left; cursor:pointer; }
.sem-saved-code { flex:0 0 auto; min-width:5rem; font-variant-numeric:tabular-nums; font-size:12px; font-weight:600; color:var(--rice-blue); }
.sem-saved-name { flex:1 1 auto; min-width:0; color:var(--text-primary); font-size:13px; line-height:1.45; overflow-wrap:anywhere; }
.sem-saved-open:hover .sem-saved-name { text-decoration:underline; }
/* State, not prose: quiet and last to take room, but never hidden — "Planned ·
   Fall 2026, Spring 2027" is the answer to "can I add this", and a tooltip is
   not an answer on a phone. It wraps; it does not truncate. */
.sem-saved-meta { flex:0 1 auto; min-width:0; margin:0; font-size:11px; line-height:1.45;
  color:var(--text-tertiary); overflow-wrap:anywhere; }
.sem-saved-actions { display:inline-flex; align-items:center; flex:0 0 auto; gap:6px; margin-left:auto; }
.sem-req-courses { color:var(--text-tertiary); overflow-wrap:anywhere; }
.sem-req-courses::before { content:" · "; }
/* DP41 put a rail row's code and title on one line and its badges and answers on
   the second. DP61 lets the two share a line when the column has room for them,
   so a rail reads with the same rhythm as the rows in the other three blocks;
   they still wrap to two lines when it does not, and never between Add and
   Dismiss. Each rail's own label stays as the sub-heading of its group. */
.sem-rails .rail { margin:0; }
.sem-rails .rail + .rail { margin-top:14px; }
.sem-rails .rail-head { margin:10px 0 2px; }
:is(#sem-rails, .sem-req-options) .rail-row { flex-wrap:wrap; align-items:center; gap:2px 10px; padding:6px 6px; }
:is(#sem-rails, .sem-req-options) .rail-open { flex:1 1 12rem; display:flex; flex-direction:row; flex-wrap:wrap;
  align-items:baseline; gap:2px 10px; }
:is(#sem-rails, .sem-req-options) .rail-code { flex:0 0 auto; min-width:5rem; }
:is(#sem-rails, .sem-req-options) .rail-name { flex:1 1 auto; min-width:0; white-space:normal; overflow:visible; overflow-wrap:anywhere; line-height:1.4; }
:is(#sem-rails, .sem-req-options) .rail-meta { margin-left:auto; }
:is(#sem-rails, .sem-req-options) .sug-act { width:auto; min-height:var(--ctl-h-sm); padding:2px 7px; font-size:12px; }
:is(#sem-rails, .sem-req-options) .sug-act::after { content:none; }

/* Batch course logging: scoped to the existing log dialog. */
#past-overlay .past-course-details { margin: 12px 0; }
#past-overlay .past-course-details summary { cursor: pointer; font-size: 13px; margin-bottom: 12px; color: var(--text-secondary); }
#past-overlay .past-batch { margin: 16px 0; min-width: 0; }
#past-overlay .past-batch h4 { margin: 0 0 8px; }
#past-overlay .past-batch-row { border-bottom: 1px solid var(--border-mid); padding: 12px 0; }
#past-overlay .past-batch-name { overflow-wrap: anywhere; margin-bottom: 8px; }
#past-overlay .past-batch-fields { display: flex; align-items: end; flex-wrap: wrap; gap: 8px; }
#past-overlay .past-batch-fields label { flex: 1 1 80px; min-width: 0; }
#past-overlay .past-batch-fields input,
#past-overlay .past-batch-fields select { display: block; width: 100%; min-width: 0; box-sizing: border-box; }
#past-overlay .past-batch-tools { margin: 12px 0; }
#past-overlay .past-batch-tools label,
#past-overlay .past-repeat-check { display: flex; align-items: start; gap: 8px; font-size: 12px; }
#past-overlay .past-batch-tools input,
#past-overlay .past-repeat-check input { width: auto; flex: 0 0 auto; margin-top: 2px; }
#past-overlay .past-batch-error,
#past-overlay .past-repeat-notice { color: var(--text-primary); font-size: 13px; overflow-wrap: anywhere; }
#past-overlay .past-batch-error { border-left: 3px solid var(--danger-text); padding-left: 10px; }
#past-overlay .past-term-facts { margin: -6px 0 12px; font-size: 12px; line-height: 1.45; color: var(--text-secondary); overflow-wrap: anywhere; }
#past-overlay .past-save-actions { flex-wrap: wrap; }

/* ── Plan · academic-year sections (DP-11) ─────────────────────────────────
   #my-semester-grid is a column of these. Each section is one academic year:
   a heading line, then a two-up row of semester cards. Fall and Spring take the
   two columns; a Summer term takes the next cell in the SAME section, which is
   what "Summer inside its academic year" has to mean in a grid. ── */
.plan-year-head { display:flex; align-items:baseline; flex-wrap:wrap; gap:3px 10px;
  margin:0 0 10px; padding-bottom:0; border-bottom:1px solid var(--border-light); }
.plan-year-heading { margin:0; width:100%; font:inherit; }
.plan-year-toggle { display:flex; align-items:center; flex-wrap:wrap; gap:4px 10px;
  width:100%; min-height:40px; padding:6px 2px; border:0; background:transparent;
  color:var(--text-primary); font:inherit; text-align:left; cursor:pointer; }
.plan-year-toggle:hover { background:var(--bg-secondary); }
.plan-year-toggle:focus-visible { outline:2px solid var(--rice-blue); outline-offset:2px; }
.plan-year-toggle .plan-year-meta { flex-basis:auto; margin-left:auto; }
.plan-year-chevron { flex:0 0 14px; transition:transform .15s ease; }
.plan-year-toggle[aria-expanded="true"] .plan-year-chevron { transform:rotate(90deg); }
@media (prefers-reduced-motion:reduce) { .plan-year-chevron { transition:none; } }
.plan-year-label { font-size:13px; font-weight:700; color:var(--rice-blue); margin:0;
  letter-spacing:.06em; text-transform:uppercase; font-variant-numeric:tabular-nums; }
.plan-year-sub { font-size:11.5px; color:var(--text-tertiary); }
.plan-year-meta { margin-left:auto; font-size:11px; color:var(--text-tertiary);
  font-variant-numeric:tabular-nums; }
.plan-year-terms { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:14px; }
.plan-add-row { margin-top:2px; }
/* Two 310px cards need 634px with the gap; the shell spends 240px on the sidebar
   and 72px on #main's padding, so below ~980px the second column would start
   squeezing the cards rather than the page. One column from there down — no
   horizontal scroll at any width, which is the acceptance condition. */
@media (max-width:980px) { .plan-year-terms { grid-template-columns:1fr; } }

/* The term the student is in, and the terms that have ended. Specificity (0,2,0)
   so these outrank the plain .sem-plan-header background above. */
.sem-plan-card.sem-plan-current { border-color:var(--rice-blue); }
.sem-plan-card.sem-plan-current .sem-plan-header { background:var(--accent-bg); }
.sem-plan-card.sem-plan-past .sem-plan-header { background:var(--bg-tertiary); }
.sem-plan-card.sem-plan-past .sem-plan-title { color:var(--text-secondary); }
/* The term a student has just created (planRevealSemester, the DP-07 seam). The
   same ring the pick targets use, so "look here" reads the same way twice; the
   class comes off on a timer, and .sem-plan-card's box-shadow transition takes
   it from there. */
.sem-plan-card.sem-plan-revealed { border-color:var(--rice-blue); box-shadow:0 0 0 3px rgba(0,40,86,.22),var(--shadow-md); }

/* Past years use the same quiet divider as the other academic-year headers. */
.plan-past-years { margin-bottom:4px; }
.plan-past-toggle { display:flex; align-items:center; gap:10px; width:100%; min-height:40px;
  padding:7px 0; background:transparent; border:0; border-bottom:1px solid var(--border-light);
  border-radius:0; cursor:pointer; text-align:left; font-family:var(--font-sans); }
.plan-past-toggle:hover { border-bottom-color:var(--border-mid); }
.plan-past-toggle:focus-visible { outline:2px solid var(--rice-blue); outline-offset:3px; }
.plan-past-toggle .chevron { flex:0 0 14px; color:var(--text-tertiary);
  transition:transform .15s ease; }
.plan-past-toggle .chevron.open { transform:rotate(90deg); }
@media (prefers-reduced-motion: reduce) { .plan-past-toggle .chevron { transition:none; } }
.plan-past-label { min-width:0; font-size:13px; font-weight:700; color:var(--text-secondary);
  letter-spacing:.06em; font-variant-numeric:tabular-nums; }
.plan-past-tag { flex:0 0 auto; font-size:10px; font-weight:600; color:var(--text-tertiary); }
.plan-past-meta { margin-left:auto; font-size:11px; color:var(--text-tertiary);
  font-variant-numeric:tabular-nums; }
.plan-past-body { margin-top:12px; display:flex; flex-direction:column; gap:22px; }
/* Finished years are quieter than the ones still in play, without losing a row. */
.plan-year-past .plan-year-label { color:var(--text-secondary); }

/* DP-70: only reorder controls/feedback, not shared row density. */
.plan-order-row, [data-order-list] { position:relative; }
.plan-order-handle, #sem-rows .plan-order-handle {
  display:inline-flex; min-width:28px; min-height:28px; padding:3px; border:1px solid transparent;
  border-radius:4px; background:transparent; color:var(--text-secondary); opacity:1;
  touch-action:none; cursor:grab; font:inherit; flex-shrink:0; }
.plan-order-handle:focus-visible { outline:2px solid var(--rice-blue); outline-offset:1px; }
.plan-order-handle:hover, .plan-order-handle[aria-pressed="true"] {
  background:var(--accent-bg); border-color:var(--border-mid); }
/* The row is what you drag; the handle is for the keyboard and shows only with its focus. */
.plan-order-row[draggable="true"] { cursor:grab; -webkit-user-select:none; user-select:none; -webkit-touch-callout:none; }
.plan-order-row[draggable="true"] .row-course-link { cursor:pointer; }
.plan-order-row.plan-order-lifted, .plan-order-row.plan-order-lifted .row-course-link { cursor:grabbing; }
.plan-order-row > .plan-order-handle:not(:focus-visible) { opacity:0; pointer-events:none; }
.plan-order-row.plan-order-lifted { z-index:2; background:var(--bg-primary);
  box-shadow:0 3px 10px rgba(0,40,86,.2); transform:translateY(-1px); }
.plan-order-before::before, .plan-order-after::after, .plan-order-empty::before {
  content:""; position:absolute; left:0; right:0; height:2px; z-index:3;
  background:var(--rice-blue); pointer-events:none; }
.plan-order-before::before, .plan-order-empty::before { top:-2px; }
.plan-order-after::after { bottom:-2px; }
@media (pointer:coarse) { .plan-order-handle, #sem-rows .plan-order-handle { min-width:36px; min-height:36px; } }

/* The projected panel: the disclosure bar above joins the always-visible
   headline row below into one box, so the two read as one thing to open. */
.my-summary-row .my-projected-block { border-radius:0 0 var(--radius-md) var(--radius-md); }

/* ── Visibility utilities — LAST in the block, on purpose ──────────────────
   .is-hidden at :1735 is (0,1,0) and so is every component base rule above;
   whichever comes later wins, and the base rules set display:inline-flex. A
   utility whose only job is to override display is the one legitimate
   !important; without it "Accept all (0)" and Undo rendered on the Plan
   toolbar (T037 review, commit 1). The three component [hidden] rules stay. */
.is-hidden, [hidden] { display:none !important; }

@media screen and (max-width:768px) {
  .mobile-settings { display:inline-flex; align-items:center; gap:7px; padding:9px 7px; border:0; border-radius:4px;
    color:rgba(255,255,255,.85); background:none; font:inherit; font-size:12px; cursor:pointer; }
  .mobile-settings.active, .mobile-settings:hover { background:rgba(255,255,255,.12); color:#fff; }

  /* 24px is fine for a mouse and not for a thumb. The target grows without the
     BOX growing: an absolutely positioned ::after extends the clickable area past
     the button's own edges, so the row stays 32px instead of the 48px a pair of
     real 40px boxes forced. Vertically it reaches 40px; horizontally it reaches
     32px, which is where the two buttons meet — any wider and each would swallow
     clicks meant for the other. */
  .sug-act { position:relative; font-size:16px; }
  .sug-act::after { content:""; position:absolute; top:-6px; bottom:-6px; left:-4px; right:-4px; }
  /* Rows are adjacent, so a button's reach upward is contested by the button of
     the row above it — the vertical target can only be as tall as the row. 36px
     is the ceiling the row can afford while still reading lighter than the real
     rows above it (29.5px), and it buys a 32 × 36 target from a 24px glyph. */
  .planned-course-row.is-suggested { padding-top:6px; padding-bottom:6px; }
  .sug-row-actions { flex:0 1 auto; order:3; justify-content:flex-end; }
  .sug-alts-btn { min-height:36px; }
  .rail-row { padding:8px 4px; }
  .rail-name { white-space:normal; }
  .sem-focus > * { margin-top:22px; }
  /* Narrow enough that a row's own parts need the width: the state line and the
     actions each take a line rather than squeezing the title out of one. */
  .sem-saved-meta, .sem-saved-actions { flex:1 0 100%; }
  .sem-saved-actions { margin-left:0; }
  .courses-search { flex-wrap:wrap; }
  .courses-q { flex:1 1 100%; }
  .course-ov-actions { flex-direction:column; align-items:stretch; }
  /* Layout — the sidebar is gone here, so the rail gradient it paints has to go
     with it, or a 240px white band sits behind the content. Both selectors,
     since body.sb-collapsed #layout outranks a bare #layout. */
  #layout,
  body.sb-collapsed #layout { grid-template-columns:1fr; background:none; }
  #sidebar { display:none; }
  #main { padding:1rem 0.875rem 74px; }

  /* Top bar */
  #rice-brand { padding:0 0.875rem; }
  #rice-brand .page-label, #rice-brand .divider { display:none; }
  #rice-brand .brand-link { font-size:11px; margin-left:8px; white-space:nowrap; }
  /* 375px cannot hold the shield, the word, a chip and three links. The word goes:
     the shield is the mark, and the full name is in the title bar and the footer.
     Without this the account chip is the thing that loses, and it truncates to
     "Your …", which is the one label here that has to be readable — with accounts
     off it is the only route to the export. */
  #rice-brand .wordmark > span:not(.shield) { display:none; }

  /* Mobile bottom nav */
  #mobile-nav {
    display:flex;
    position:fixed;
    bottom:0; left:0; right:0;
    height:58px;
    background:var(--bg-primary);
    border-top:1px solid var(--border-light);
    z-index:60;
    justify-content:space-around;
    align-items:stretch;
    box-shadow:0 -2px 10px rgba(15,30,58,0.10);
    padding-bottom:env(safe-area-inset-bottom,0px);
  }
  .mnav-btn {
    flex:1;
    display:flex; flex-direction:column; align-items:center; justify-content:center; gap:3px;
    background:none; border:none; cursor:pointer;
    color:var(--text-tertiary);
    font-family:var(--font-sans);
    padding:0 4px;
    transition:color .12s;
    -webkit-tap-highlight-color:transparent;
  }
  .mnav-btn.active { color:var(--rice-blue); }
  .mnav-ico { width:20px; height:20px; display:flex; align-items:center; justify-content:center; }
  .mnav-label { font-size:10px; font-weight:500; line-height:1; }

  /* Toolbar */
  .toolbar { flex-direction:column; align-items:flex-start; gap:8px; margin-bottom:1rem; padding-bottom:.75rem; }
  .toolbar-left h1 { font-size:19px; }
  .cp-toolbar .toolbar-left { flex:none; width:100%; }
  .toolbar-right { width:100%; display:flex; flex-wrap:wrap; gap:8px; }
  /* These two carried !important until WP-16, for one reason: the elements had
     inline width/min-width in index.html, and an inline style beats a rule. The
     inline styles are gone, and both rules now win on ordinary cascade order —
     same id specificity as the base rule, later in the file. */
  #prog-search-input { width:100%; box-sizing:border-box; }
  #prog-search-drop { min-width:unset; left:0; right:0; width:100%; }

  /* Home view */
  /* Three buttons across is two too many on a phone: one per row, full width. */

  /* Course titles get the row width; actions wrap separately on narrow screens. */
  .adv-course-card-header { display:grid; grid-template-columns:32px minmax(0,1fr); gap:8px; margin-bottom:0; }
  .adv-course-card-header > .adv-star-btn { width:32px; min-height:32px; justify-content:center; }
  .adv-course-open { flex-direction:column; align-items:flex-start; gap:3px; }
  .adv-course-name { overflow-wrap:anywhere; }
  .adv-course-meta { grid-column:1 / -1; margin-left:0; min-width:0; }

  /* Degree Progress */
  .deg-top { grid-template-columns:repeat(2,1fr); }

  /* Dist grids */
  .dist-grid { grid-template-columns:repeat(2,minmax(0,1fr)); }
  /* Two columns, so the "first row" the desktop rule exempts is the first two. */
  .req-strip { grid-template-columns:repeat(2,minmax(0,1fr)); }
  /* Scoped to the section bodies — Multi-Year's copy of the strip sets padding:0. */
  #deg-body .req-strip { padding-left:14px; padding-right:14px; }
  .req-strip > .req-stat:nth-child(3) { border-top:1px solid var(--border-light); padding-top:9px; }
  .req-strip > .req-stat:nth-child(-n+2) { border-top:none; padding-top:4px; }

  /* Multi-Year Plan */
  .my-summary-row { grid-template-columns:1fr !important; }
  .semester-grid { gap:18px; }
  /* One column already comes from the 980px rule; this keeps the year heading
     readable when the meta no longer fits beside the label. */
  .plan-year-meta { margin-left:0; flex-basis:100%; }
  .plan-past-toggle { flex-wrap:wrap; gap:6px 8px; }
  .plan-past-toggle .chevron { margin-left:auto; }
  .plan-past-meta { order:1; flex-basis:100%; margin-left:0; }
  .my-controls { flex-wrap:wrap; }
  .my-plan-actions > .plan-notice { flex-basis:100%; }
  .headline-row { gap:4px 16px; }
  .headline-link { margin-left:0; flex-basis:100%; justify-content:flex-start; }   /* context line wraps above the actions */

  /* Plan builder rows → stack controls below course info */
  .pb-status { display:none; }

  /* Modals → bottom sheet */
  .modal-overlay { padding:0; align-items:flex-end; }
  .modal { max-width:100%; width:100%; border-radius:var(--radius-lg) var(--radius-lg) 0 0; border-top:3px solid var(--rice-blue); border-left:none; border-right:none; border-bottom:none; max-height:88vh; padding:1.25rem 1rem; }
  .field-row { grid-template-columns:1fr; }

  /* Course tables scroll horizontally */

  /* Suggested courses */

  /* On a phone there is no gutter to float in: fixed positioning either collides
     with the 58px bottom nav or sits on top of card text. Drop it into normal
     flow instead, so it scrolls with the page and covers nothing. The bottom
     margin clears the nav when you reach the end of the page. */
  .sec-mode-badge {
    position:static; display:block; margin:2px 10px 70px;
    text-align:center; font-size:9.5px; letter-spacing:.04em;
  }

  /* Account chip: the email prefix is the first thing to go when the header is
     26px of horizontal space wide. */
  .account-chip { max-width:110px; padding:4px 10px; font-size:11px; }
  .acct-actions .btn { flex:1 1 auto; }
  .acct-recovery { font-size:13px; letter-spacing:.05em; }

  /* Section picker: the meta line wraps to its own row rather than squeezing. */
  .mt-when { font-size:12px; }

  /* Setup guide. The four-across add-a-course row squeezed the course field down
     to about 100px on a 375px screen — it read "Cou" — so the search gets its own
     line and the term/grade/Add trio shares the next one. */
  .wiz-row { flex-wrap:wrap; }
  .wiz-row .wiz-search, .wiz-grow { flex:1 1 100%; width:100%; }
  .wiz-narrow { flex:1 1 120px; width:auto; }
  .wiz-level { flex:1 1 120px; width:auto; }
  .wiz-tiny { flex:0 0 88px; width:88px; }
  .wiz-row .btn { flex:1 1 auto; }
  .wiz-list { max-height:150px; }
  .wiz-list-meta { display:none; }
  .wiz-footer-right { flex:1 1 auto; }
  .wiz-footer-right .btn { flex:1 1 auto; }

  /* All three selectors, because "last rule wins" only settles ties. The desktop
     inset rules are `#layout ~ #site-footer` and `body.sb-collapsed #layout ~
     #site-footer` — both outrank a bare `#site-footer` no matter where they sit
     in the file, so a plain override here would have left the phone footer
     indented 274px off the left edge of a 375px screen. */
  #site-footer,
  #layout ~ #site-footer,
  body.sb-collapsed #layout ~ #site-footer,
  /* The badge reservation has to be in this list too. On a phone the badge drops
     into normal flow (below), so it needs no reservation at all — but its
     `body:has(#sec-mode-badge) #site-footer` selector outranks a bare
     `#site-footer`, and its 48px would quietly beat the 78px that clears the
     fixed bottom nav, hiding the policy links behind it. */
  body:has(#sec-mode-badge) #site-footer { padding:20px 16px 78px; }   /* clears the fixed bottom nav */
  #site-footer .footer-stamp { margin-left:0; width:100%; padding-left:0; border-left:none; }

  /* Document pages. privacy.html has no bottom nav, so no 78px reservation —
     the footer rule above still applies to it, which is harmless padding. */
  .doc-shell { padding:22px 14px 4px; }
  .doc-hero h1 { font-size:23px; }
  .doc-card { padding:20px 0; }
  .doc-body #site-footer { padding:20px 14px; }
  /* Three narrow columns at 375px are unreadable. Each row becomes a stacked
     block, and because the header row is then hidden, every cell that is not
     self-describing reprints its column name from data-label. Without that the
     bare "No" in the third column loses the question it answers. */
  .doc-table, .doc-table tbody, .doc-table tr, .doc-table td { display:block; width:100%; }
  .doc-table thead { display:none; }
  .doc-table tr { padding:12px 0; border-bottom:1px solid var(--border-light); }
  .doc-table tr:last-child { border-bottom:none; }
  .doc-table td { border-bottom:none; padding:2px 0; }
  .doc-table td:first-child { width:auto; font-size:14px; margin-bottom:4px; }
  .doc-table td[data-label]::before { content:attr(data-label) ' '; font-size:10.5px;
    font-weight:650; letter-spacing:.05em; text-transform:uppercase; color:var(--text-tertiary); }
}

/* Class Chats: compact room navigation and text-sized conversation bubbles. */
.chat-room-heading {display:flex;align-items:center;justify-content:space-between;gap:8px 16px;flex-wrap:wrap}
.chat-privacy {color:var(--text-muted);font-size:13px;line-height:1.6}
.chat-layout {display:grid;grid-template-columns:minmax(160px,210px) minmax(0,1fr);gap:20px}
.chat-room-list {border-right:1px solid var(--border-light);padding-right:16px;min-width:0}
.chat-room-list h2 {font-size:12px;color:var(--text-secondary);font-weight:600;margin:4px 0 8px}
.chat-room-list p,.chat-room p {font-size:13px;line-height:1.5}.chat-room {min-width:0}.chat-room h2 {font-size:16px;font-weight:600}
.chat-room-choice {display:flex;flex-direction:column;width:100%;text-align:left;gap:2px;padding:8px 10px;border:0;border-left:2px solid transparent;border-bottom:1px solid var(--border-light);border-radius:0;background:none;color:inherit;margin:0;cursor:pointer;overflow-wrap:anywhere;font:inherit;font-size:13px}
.chat-room-choice span,.chat-room-choice small {font-size:11px;color:var(--text-secondary)}
.chat-room-choice:hover {background:var(--bg-secondary)}
.chat-room-choice.selected {border-left-color:var(--rice-blue);background:var(--accent-bg);color:var(--rice-blue)}
.chat-candidate {display:flex;align-items:center;gap:6px;flex-wrap:wrap;padding:8px 0;border-bottom:1px solid var(--border-light);font-size:13px}
.chat-candidate span {font-size:11px;color:var(--text-secondary)}
.chat-toolbar,.chat-item-actions {display:flex;gap:6px;flex-wrap:wrap}
.chat-messages {display:flex;flex-direction:column;gap:6px;max-height:48vh;min-height:160px;overflow-y:auto;overscroll-behavior:contain;padding:8px 4px;overflow-wrap:anywhere}
.chat-message {align-self:flex-start;width:fit-content;max-width:min(86%,640px);padding:7px 10px;border:0;border-radius:var(--radius-lg);background:var(--bg-secondary);overflow-wrap:anywhere}
.chat-message.is-mine {align-self:flex-end;background:var(--accent-bg)}
.chat-message header {display:flex;align-items:baseline;gap:10px;font-size:11px;flex-wrap:wrap;color:var(--text-secondary)}
.chat-message header strong {font-weight:600}.chat-message time {font-size:10px;color:var(--text-tertiary)}
.chat-message-star {display:inline-flex;align-items:center;justify-content:center;min-width:28px;min-height:28px;margin:-5px -7px -5px auto;padding:4px;border:0;border-radius:5px;background:transparent;color:var(--text-secondary);cursor:pointer}
.chat-message-star:hover,.chat-message-star:focus-visible {background:var(--bg-primary);color:var(--rice-blue)}
.chat-message-star:focus-visible {outline:2px solid var(--rice-blue);outline-offset:2px}
.chat-message-star.is-starred,.chat-message-star.is-starred:hover {color:#b7791f}
.chat-message-star.is-starred svg {fill:currentColor}
.chat-message p {white-space:pre-wrap;margin:3px 0 0}.chat-message small {display:block;margin:3px 0 0;color:var(--text-muted);font-size:10px}
.chat-item-actions {gap:2px;margin-top:3px}.chat-item-actions .btn {font-size:10px;min-height:24px;padding:0 5px;border-color:transparent;background:none;color:var(--text-secondary)}
.chat-item-actions .btn:hover {color:var(--text-primary);background:var(--bg-primary)}
.chat-composer {display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:end;gap:6px 8px;margin-top:12px;padding-top:10px;border-top:1px solid var(--border-light)}
.chat-composer label,.chat-composer p,.chat-composer small {grid-column:1/-1}.chat-composer label {font-size:12px;color:var(--text-secondary)}
.chat-composer small {font-size:11px;color:var(--text-muted)}
.chat-composer textarea,.chat-form textarea,.chat-form input:not([type="checkbox"]),.chat-form select {display:block;width:100%;box-sizing:border-box;background:var(--bg-primary);color:inherit;border:1px solid var(--border-mid);border-radius:var(--radius-sm);padding:8px;margin:6px 0;font:inherit;font-size:13px}
.chat-composer textarea {min-height:60px;max-height:160px;resize:vertical;margin:0}.chat-form textarea {min-height:88px;resize:vertical}
.chat-form {border:1px solid var(--border-mid);padding:16px;border-radius:var(--radius-sm);margin-bottom:16px;background:var(--bg-primary)}
.chat-form label {font-size:13px;line-height:1.6}.chat-form .btn {margin:8px 8px 0 0}.chat-consent {display:flex;align-items:flex-start;gap:8px;margin:16px 0}.chat-consent input {margin-top:5px;flex-shrink:0}
/* Message search (DP64): one compact row above the log, status line under it. */
.chat-search {display:flex;gap:6px;align-items:center;margin:8px 0 4px}
.chat-search:not(.is-open) {justify-content:flex-end}
.chat-search input {flex:1 1 auto;min-width:0;box-sizing:border-box;background:var(--bg-primary);color:inherit;border:1px solid var(--border-mid);border-radius:var(--radius-sm);padding:6px 8px;margin:0;font:inherit;font-size:13px}
.chat-search-status {font-size:12px;color:var(--text-secondary);margin:0 0 4px}
/* DP82: conversation actions and private auxiliary panels. */
.chat-room {background:var(--bg-primary);border:1px solid var(--border-light);border-radius:var(--radius-sm);padding:12px;align-self:start}
.chat-room-heading h2 {margin:0;overflow-wrap:anywhere}
#class-chat-root .chat-messages {background:var(--bg-primary);padding:12px 4px;min-height:120px;max-height:clamp(120px,calc(100dvh - 420px),520px)}
.chat-heading {min-height:40px;margin-bottom:16px;padding-bottom:10px}
#class-chat-root :is(button,input,textarea,summary,[tabindex]) {scroll-margin-block:70px}
.chat-message {position:relative;min-width:110px;padding:8px 12px;background:var(--bg-secondary)}
.chat-message.is-mine {background:var(--accent-bg)}
.chat-message-menu {margin-top:3px;max-width:100%}
.chat-message-menu summary {display:flex;align-items:center;justify-content:center;cursor:pointer;width:32px;min-height:28px;border-radius:4px;list-style:none;color:var(--text-secondary);letter-spacing:2px}
.chat-message-menu summary::-webkit-details-marker {display:none}
.chat-message-menu summary:hover,.chat-message-menu[open] summary {background:var(--bg-primary);color:var(--text-primary)}
.chat-message-menu .chat-item-actions {display:flex;flex-wrap:wrap;gap:4px}
.chat-message-menu .btn {min-height:32px;padding:3px 8px;font-size:12px}
.chat-message-menu:focus-within summary {outline:1px solid var(--rice-blue)}
.chat-message:focus {outline:2px solid var(--rice-blue);outline-offset:2px}
.chat-icon {display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:36px;min-height:36px;padding:4px;font-size:20px}
.chat-saved-button:hover {color:#b7791f}
.chat-search input {min-height:36px}
.chat-composer {margin-top:6px;background:var(--bg-primary)}
.chat-reply-preview {grid-column:1/-1;display:flex;flex-wrap:wrap;align-items:center;gap:4px 10px;border-left:2px solid var(--border-mid);padding:5px 8px;margin:4px 0;max-width:100%;box-sizing:border-box;font-size:12px}
.chat-reply-preview>strong {width:100%;font-weight:500;color:var(--text-secondary)}
.chat-quote-link {display:block;min-width:0;max-width:100%;flex:1 1 160px;text-align:left;background:transparent;border:0;color:var(--text-secondary);font:inherit;padding:4px;cursor:pointer;overflow-wrap:anywhere;white-space:pre-wrap;max-height:76px;overflow:auto}
.chat-quote-link span {display:block;font-weight:600;color:var(--text-primary)}
.chat-original-unavailable {color:var(--text-secondary)}
.chat-action-status {font-size:12px;color:var(--text-secondary);margin:4px 0 8px}
.chat-history-context {display:flex;align-items:center;justify-content:space-between;gap:6px;flex-wrap:wrap;margin:8px 0;font-size:12px;color:var(--text-secondary)}
.chat-pending-choice {grid-column:1/-1;font-size:12px;color:var(--text-secondary)}
.chat-pending-choice .btn {margin-right:6px;margin-bottom:4px;min-height:32px}
.chat-aux {min-width:0;min-height:200px;overflow-wrap:anywhere}
.chat-aux .chat-room-heading {margin-bottom:10px}
.chat-aux .chat-private-note {font-size:12px;color:var(--text-secondary)}
#chat-saved-search {box-sizing:border-box;width:100%;min-height:36px;font:inherit;font-size:13px;padding:6px 8px;background:var(--bg-primary);color:var(--text-primary);border:1px solid var(--border-mid);border-radius:var(--radius-sm)}
.chat-saved-list {max-height:55dvh;overflow:auto;overscroll-behavior:contain}
.chat-saved-row {border-bottom:1px solid var(--border-light);padding:10px 0}
.chat-saved-row header {display:flex;align-items:baseline;gap:6px 12px;flex-wrap:wrap;font-size:12px}
.chat-saved-row header span,.chat-saved-row small {color:var(--text-secondary);font-size:11px}
.chat-saved-row p {white-space:pre-wrap;margin:5px 0;max-height:120px;overflow:auto}
.chat-saved-row .chat-toolbar {margin-top:6px}
@media(hover:hover){.chat-message-menu:not([open]) summary{opacity:0.55}.chat-message:hover .chat-message-menu summary,.chat-message:focus-within .chat-message-menu summary{opacity:1}}
@media(max-width:700px){.chat-room{padding:10px}.chat-message-menu summary,.chat-message-menu .btn{min-height:36px}.chat-layout>.chat-room-list{display:flex;flex-wrap:wrap;align-items:stretch;gap:4px;max-height:140px}.chat-room-list>h2,.chat-room-list>.chat-candidate{flex:1 0 100%}.chat-room-list>.chat-room-choice{flex:1 1 96px;width:auto;margin-top:0}.chat-room-list>.chat-dm-entry{border-top:0}#class-chat-root .chat-messages{max-height:clamp(100px,calc(100dvh - 585px),320px)}}
@media(max-height:500px){.chat-layout>.chat-room-list{max-height:80px}#class-chat-root .chat-messages{max-height:120px;min-height:100px}.chat-composer textarea{min-height:44px}.chat-saved-list{max-height:50dvh}}
/* Direct messages (DP64): the entry sits under the rooms; the panel reuses the room
   log/composer styles, with its own list, people and identity-choice pieces. */
.chat-dm-entry {margin-top:10px;border-top:1px solid var(--border-light)}
.chat-dm-title {display:flex;align-items:center;gap:6px 12px;flex-wrap:wrap;min-width:0}
.chat-dm-title h2 {margin:0}
.chat-dm-course,.chat-dm-identity {font-size:12px;color:var(--text-secondary)}
.chat-dm-identity {margin:4px 0 10px}
.chat-dm-list,.chat-dm-people {list-style:none;margin:0;padding:0}
.chat-dm-conversation {display:grid;grid-template-columns:minmax(0,1fr) auto;gap:2px 12px;width:100%;text-align:left;padding:8px 6px;border:0;border-bottom:1px solid var(--border-light);border-radius:0;background:none;color:inherit;font:inherit;font-size:13px;cursor:pointer;overflow-wrap:anywhere}
.chat-dm-conversation:hover {background:var(--bg-secondary)}
.chat-dm-conversation time {grid-column:2;grid-row:1;font-size:11px;color:var(--text-tertiary);white-space:nowrap}
.chat-dm-peer {display:flex;gap:8px;align-items:baseline;min-width:0}
.chat-dm-unread {font-style:normal;font-size:11px;color:var(--rice-blue);font-weight:600}
.chat-dm-preview {grid-column:1;color:var(--text-secondary);font-size:12px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.chat-dm-person {display:flex;align-items:center;justify-content:space-between;gap:8px;padding:8px 0;border-bottom:1px solid var(--border-light);font-size:13px}
.chat-dm-person span {display:block;font-size:11px;color:var(--text-secondary)}
.chat-dm-empty {padding:12px 0;color:var(--text-muted);font-size:13px}
.chat-dm-intro {font-size:13px;line-height:1.6;color:var(--text-muted)}
.chat-dm-choice {border:0;padding:0;margin:12px 0 0;min-width:0}
.chat-dm-choice legend {font-size:13px;font-weight:600;margin-bottom:6px;padding:0}
.chat-dm-option {display:flex;align-items:center;gap:8px;font-size:13px;margin-top:8px}
.chat-dm-input {display:block;width:100%;box-sizing:border-box;margin:6px 0 4px;padding:8px;font:inherit;font-size:13px;background:var(--bg-primary);color:inherit;border:1px solid var(--border-mid);border-radius:var(--radius-sm)}
.chat-dm-error {color:var(--danger);font-size:13px;margin:8px 0 0}
.chat-empty {padding:20px 0;max-width:660px}.chat-empty h2 {font-size:16px;margin-bottom:10px}.chat-empty p {line-height:1.7;color:var(--text-muted)}.chat-notice {padding:10px;border:1px solid var(--border-mid);border-radius:var(--radius-sm);font-size:13px;margin:12px 0;overflow-wrap:anywhere}
@media(max-width:700px){.chat-layout{grid-template-columns:1fr;gap:16px}.chat-room-list{border-right:0;border-bottom:1px solid var(--border-light);padding:0 0 12px;max-height:28vh;overflow-y:auto}.chat-messages{max-height:48vh}.chat-message{max-width:92%}.chat-form{padding:12px}.chat-toolbar .btn{padding:5px 8px}.chat-dm-conversation{grid-template-columns:1fr}.chat-dm-conversation time{grid-column:1;grid-row:auto}.chat-dm-person{flex-wrap:wrap}}

/* Manual prerequisite review and remaining-course placement (DP34/36). */
#manual-plan-overlay { z-index: 1400; }
/* Account unlock may appear while another dialog is open. */
#account-overlay { z-index: 10000; }
.manual-plan-modal { width: min(520px, calc(100vw - 28px)); max-height: 85dvh; overflow-y: auto; }
.manual-plan-target { font-weight: 600; }
.manual-plan-choice { display: grid; gap: 5px; margin: 12px 0; font-size: 13px; }
.manual-plan-choice select { width: 100%; }
.manual-plan-preview { list-style: none; padding: 0; margin: 14px 0; }
.manual-plan-preview li { display: flex; justify-content: space-between; gap: 12px; padding: 7px 0; border-bottom: 1px solid var(--border-light); font-size: 13px; }
.manual-plan-error { font-size: 12px; line-height: 1.5; }
/* DP-92: independent viewport rails. Space is reserved by the active Plan,
   so the fixed browser never covers semester cards or vanishes at page bottom. */
:root { --course-browser-w:312px; --course-browser-rail-w:44px; }
.plan-requirements-layout { display:block; min-width:0; }
.plan-years-container > .semester-grid { min-width:0; container-type:inline-size; container-name:plan-grid; }
body.plan-rail-active #main { padding-right:calc(var(--course-browser-rail-w) + 18px); }
body.plan-rail-active.plan-rail-expanded #main { padding-right:calc(var(--course-browser-w) + 18px); }
body.plan-rail-active #site-footer { padding-right:calc(var(--course-browser-rail-w) + 18px); }
body.plan-rail-active.plan-rail-expanded #site-footer { padding-right:calc(var(--course-browser-w) + 18px); }
.plan-requirements-rail { display:none; position:fixed; right:0; top:var(--app-bar-h); bottom:0; z-index:40; width:var(--course-browser-rail-w); border-left:1px solid var(--border-mid); background:var(--bg-primary); padding:6px 2px; }
body.plan-rail-active:not(.plan-rail-expanded) .plan-requirements-rail { display:block; }
#plan-requirements-expand { width:38px; min-height:38px; font-size:24px; color:var(--rice-blue); }
#plan-requirements-expand[hidden] { display:none; }
/* Two cards across need ~330px each; below that the year row goes single-column
   whatever the viewport, which is what the container query measures. */
@container plan-grid (max-width:660px) { .plan-year-terms { grid-template-columns:1fr; } }
.plan-requirements-btn { gap:7px; scroll-margin-top:calc(var(--app-bar-h) + 8px); }
.plan-requirements-btn svg { flex-shrink:0; color:var(--rice-blue); }
.plan-requirements-btn[aria-expanded="true"] { background:var(--accent-bg); border-color:var(--rice-blue); color:var(--rice-blue); }
.plan-requirements-sidebar { display:none; position:fixed; right:0; top:var(--app-bar-h); bottom:0; width:var(--course-browser-w); z-index:40;
  box-sizing:border-box; flex-direction:column; min-width:0; padding:10px 10px max(12px, env(safe-area-inset-bottom, 0px)); border:0; border-left:1px solid var(--border-mid); border-radius:0; background:var(--bg-primary); }
.plan-requirements-sidebar.is-open { display:flex; }
.plan-requirements-heading { display:flex; align-items:center; gap:8px; margin:-10px -10px 6px; padding:8px 10px; border-bottom:1px solid var(--border-light); background:#f7f7f8; color:var(--text-primary); }
.plan-requirements-heading h2 { flex:1 1 auto; min-width:0; margin:0; font-size:14px; font-weight:650; line-height:1.35; }
.plan-requirements-close { min-width:36px; min-height:36px; margin-right:-4px; font-size:24px; color:var(--rice-blue); }
.plan-requirements-back { display:none; gap:5px; }
.plan-requirements-sidebar > :not(#plan-requirements-list) { flex-shrink:0; }
.plan-requirements-sidebar button:focus-visible { outline:2px solid var(--rice-blue); outline-offset:-2px; }
/* DP-75: the field reserves room on the right for the clear control; the control is
   the full field height and 36px wide, the glyph inside it 12px. Hidden while the
   field is empty (the [hidden] rule has to outrank the flex display). */
.plan-requirements-search-wrap { position:relative; margin-bottom:8px; }
#plan-requirements-search { display:block; width:100%; min-width:0; min-height:32px;
  margin:0; padding:6px 38px 6px 9px; border:1px solid var(--border-mid);
  border-radius:var(--ctl-r); background:var(--bg-primary); color:var(--text-primary);
  font:inherit; font-size:12px; box-sizing:border-box; }
#plan-requirements-search::-webkit-search-cancel-button, #plan-requirements-search::-webkit-search-decoration { -webkit-appearance:none; appearance:none; display:none; }
.req-search-clear { position:absolute; top:0; right:0; bottom:0; width:36px; display:flex; align-items:center; justify-content:center;
  margin:0; padding:0; border:0; border-radius:0 var(--ctl-r) var(--ctl-r) 0; background:none; color:var(--text-tertiary); cursor:pointer; }
.req-search-clear[hidden] { display:none; }
.req-search-clear:hover { color:var(--text-primary); background:var(--bg-secondary); }
.req-search-clear:focus-visible { outline:2px solid var(--rice-blue); outline-offset:-2px; }
.req-search-clear svg { display:block; }
#plan-requirements-selection { font-size:12px; line-height:1.5; color:var(--text-secondary); margin-bottom:8px; }
#plan-requirements-selection:empty { margin-bottom:0; }
#plan-requirements-list { flex:1; min-height:0; overflow-y:auto; overscroll-behavior:contain; scrollbar-gutter:stable; }
.plan-browser-type { width:100%; margin:0 0 8px; min-height:34px; }
.plan-browser-row { border-bottom:1px solid var(--border-mid); padding:4px 0; }
.plan-requirements-sidebar .plan-browser-course { display:flex; flex-wrap:wrap; align-items:center; gap:3px 5px; min-width:0; min-height:36px; padding:4px; }
.plan-requirements-sidebar .plan-browser-course > .req-course-main { flex:1 1 12rem; min-width:0; }
.plan-browser-course .plan-drag-handle { flex:0 0 24px; }
.plan-browser-meta { font-size:11px; color:var(--text-secondary); }
.plan-browser-warning { font-size:11px; line-height:1.45; color:var(--warn-text); overflow-wrap:anywhere; }
.plan-browser-fit { font-size:11px; line-height:1.45; color:var(--text-secondary); margin:0 4px 4px; }
.plan-browser-fit > summary { display:inline-flex; align-items:center; min-height:26px; cursor:pointer; color:var(--rice-blue); }
.plan-browser-fit > :not(summary) { margin:3px 0; overflow-wrap:anywhere; }
.plan-browser-actions { display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:6px; margin:0 0 6px; font-size:11px; color:var(--text-secondary); }
.req-list-heading { font-size:11px; color:var(--text-tertiary); font-weight:600; margin:12px 0 5px; }
.req-course-option { display:block; width:100%; padding:6px 6px; text-align:left; border:0; border-bottom:1px solid var(--border-light); background:transparent; color:var(--text-primary); cursor:pointer; font:inherit; }
.req-course-option:hover, .req-course-option.is-selected { background:var(--accent-bg); }
.req-course-option:focus-visible { outline:2px solid var(--rice-blue); outline-offset:-2px; }
.req-course-main { display:grid; gap:2px; font-size:12px; line-height:1.35; }
.req-course-main > span { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.req-placement-target { outline:1px solid var(--rice-blue); outline-offset:1px; cursor:pointer; }
.req-place-course { margin:8px 0; width:100%; }
#semester-view .sem-req-courses { font-size:11px; }
@media (max-width:900px) {
  body.plan-rail-active #main, body.plan-rail-active.plan-rail-expanded #main { padding-right:2.25rem; }
  .plan-requirements-sidebar { top:calc(var(--app-bar-h) + 8px); bottom:auto; right:12px; width:min(340px, calc(100vw - 32px)); height:min(480px, 60dvh); max-height:calc(100dvh - var(--app-bar-h) - 96px); border:1px solid var(--border-mid); border-radius:var(--radius-lg); box-shadow:var(--shadow-md); overflow:auto; }
  .plan-requirements-rail { top:calc(var(--app-bar-h) + 8px); right:12px; bottom:auto; width:40px; height:40px; border:1px solid var(--border-mid); border-radius:var(--radius-lg); padding:0; }
  .plan-requirements-heading { flex-wrap:wrap; border-radius:var(--radius-lg) var(--radius-lg) 0 0; }
  .plan-requirements-back { display:inline-flex; order:0; }
  .plan-requirements-heading h2 { order:1; text-align:right; }
  .plan-requirements-close { display:none; }
}
@media (max-width:768px) {
  /* Above the fixed bottom nav. */
  .plan-requirements-sidebar { bottom:auto; max-height:calc(100dvh - var(--app-bar-h) - 96px - env(safe-area-inset-bottom, 0px)); }
  #my-plan-actions .plan-grad-control { margin-left:0; }
  #my-plan-actions #plan-menu-btn { margin-left:auto; }
  body.plan-rail-active #main, body.plan-rail-active.plan-rail-expanded #main { padding-right:.85rem; }
  body.plan-rail-active #site-footer, body.plan-rail-active.plan-rail-expanded #site-footer { padding-right:1rem; }
  .plan-years-container { padding:7px; }
  /* DP-72 shell on phones: the rail and its app-bar toggle are desktop furniture;
     #mobile-nav is the phone's navigation and stays as it was. */
  #rice-brand .sb-toggle-btn { display:none; }
  #main { grid-column:1; }
}
@media print { .plan-requirements-sidebar, .plan-requirements-rail, .plan-requirements-btn, .req-place-course, .sb-toggle-btn { display:none !important; } body.plan-rail-active #main, body.plan-rail-active.plan-rail-expanded #main { padding-right:0; } }

/* Sidebar summaries stay visible independently of each bounded choice pool. */
.req-suggestions-jump { margin-bottom: 3px; }
.req-discovery-actions { display:flex; align-items:center; flex-wrap:wrap; gap:6px; margin-bottom:4px; }
.req-discovery-actions .btn { min-height:32px; }
.req-course-code-line .req-saved-indicator { display:inline-flex; align-items:center; flex:none; margin-right:auto; color:var(--warning, #b7791f); }
.req-course-code-line .req-saved-indicator svg { width:13px; height:13px; }
#courses-back-btn { margin-bottom:8px; }
#courses-back-btn, #courses-browse-btn { min-height:36px; }
#courses-page-title { scroll-margin-top:16px; }
.req-group-toggle { display: flex; align-items: center; gap: 7px; width: 100%; min-height: 36px; padding: 6px 2px; border: 0; border-bottom: 1px solid var(--border-light); background: none; color: var(--text-primary); text-align: left; font: inherit; font-size: 12px; cursor: pointer; }
.req-group-toggle:hover { color: var(--rice-blue); }
.req-group-label { flex: 1; min-width: 0; line-height: 1.4; }
.req-group-count { white-space: nowrap; font-size: 11px; color: var(--text-secondary); }
.req-group-options { max-height: 240px; overflow-y: auto; overscroll-behavior: contain; padding: 0 2px 6px 8px; }
.req-hours-summary { display: flex; justify-content: space-between; gap: 10px; padding: 5px 2px; font-size: 11px; line-height: 1.4; color: var(--text-secondary); }
.req-hours-summary strong { white-space: nowrap; font-weight: 500; }
.plan-requirements-sidebar .req-course-code-line { display:inline-flex; align-items:baseline; gap:6px; flex:0 0 auto; }
.req-course-code-line > span { font-size: 10.5px; color: var(--text-tertiary); }
.req-search-mapping { display: block; margin-top: 3px; color: var(--text-secondary); font-size: 10.5px; line-height: 1.4; }
.req-sidebar-suggestions { margin-top: 12px; border-top: 1px solid var(--border-light); }
.req-constraint-count { margin-top: 8px; font-size: 10.5px; line-height: 1.4; color: var(--text-secondary); }

/* Category → requirement disclosure → course, without card borders on every level. */
.plan-requirements-sidebar .req-list-heading { margin: 22px 0 8px; font-size: 11px; font-weight: 700; letter-spacing: .045em; text-transform: uppercase; color: var(--text-secondary); }
.plan-requirements-sidebar .req-sidebar-group { margin-bottom: 5px; }
.plan-requirements-sidebar .req-group-toggle { min-height: 36px; padding: 6px 2px; gap: 10px; font-size: 13px; }
.plan-requirements-sidebar .req-group-label { font-weight: 550; }
.plan-requirements-sidebar .req-group-options { max-height: min(320px, 45dvh); margin: 6px 0 12px; padding: 0 4px 4px 10px; border-left: 2px solid var(--border-light); }
.plan-requirements-sidebar .req-course-option { padding: 5px 5px; border-bottom: 0; }
/* DP-71: code, credits and title on one line; the title wraps when it must. */
.plan-requirements-sidebar .req-course-main { display:flex; flex-wrap:wrap; align-items:baseline; gap:1px 8px; line-height:1.4; }
.plan-requirements-sidebar .req-course-main > span:not(.req-course-code-line) { flex:1 1 9rem; min-width:0; white-space:normal; overflow:visible; text-overflow:clip; overflow-wrap:anywhere; }
.plan-requirements-sidebar .req-constraint-count { margin: 14px 5px 2px; }
.plan-requirements-sidebar .req-constraint-count:first-child { margin-top: 4px; }
.plan-requirements-sidebar .req-hours-summary { padding: 7px 2px; }
.plan-requirements-sidebar .req-sidebar-suggestions { margin-top: 22px; padding-top: 4px; }
/* DP80 — compact private term grades; optional reviews use their own overlay. */
.tc-modal { width: min(640px, calc(100vw - 28px)); max-width: 640px; max-height: calc(100dvh - 32px); overflow-y: auto; }
.tc-note { color: var(--text-secondary); font-size: 13px; line-height: 1.5; margin: 10px 0; }
.tc-term { display: flex; align-items: center; gap: 12px; font-size: 13px; }
.tc-term select { flex: 1; min-width: 0; }
.tc-confirm { display: flex; align-items: center; gap: 8px; font-size: 13px; margin: 12px 0; }
.tc-confirm input { width: 18px; height: 18px; flex-shrink: 0; }
.tc-rows { margin: 12px 0; }
.tc-row { display: grid; grid-template-columns: minmax(0, 1fr) 148px 100px; gap: 10px; align-items: center; padding: 9px 0; border-bottom: 1px solid var(--border-light); }
.tc-course { display: flex; flex-direction: column; min-width: 0; gap: 3px; font-size: 13px; overflow-wrap: anywhere; }
.tc-course span { color: var(--text-secondary); font-size: 12px; }
.tc-grade select { width: 100%; min-height: 36px; }
.tc-review { min-height: 36px; }
.tc-course .tc-reviewed { display: inline-flex; vertical-align: -2px; margin-left: 6px; color: #16a34a; }
.tc-review-note { font-size: 11px; color: var(--text-secondary); line-height: 1.4; }
.tc-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin: 12px 0; }
.tc-actions .btn { min-height: 36px; }
.tc-status { font-size: 12px; line-height: 1.5; color: var(--text-secondary); }
.tc-error { color: var(--red, #a52626); }
.tc-manual-entry { margin: 0 0 12px; white-space: normal; text-align: left; }
@media (max-width: 520px) {
  .tc-row { grid-template-columns: minmax(0, 1fr) 130px; gap: 6px 10px; }
  .tc-review, .tc-review-note { grid-column: 2; justify-self: start; }
  .tc-course { grid-row: span 2; }
}

.private-storage-notice { padding:10px 18px; background:var(--bg-secondary); border-bottom:1px solid var(--border-mid); font-size:13px; line-height:1.5; }
.private-storage-notice:empty { display:none; }
.private-storage-notice button { margin:4px 6px 0 0; }

/* Account access is closed from the initial HTML, including script failure. */
body.account-required > :not(#account-gate):not(#account-overlay):not(#session-save-recovery):not(script):not(noscript) { display:none !important; }
#account-gate { max-width:560px; margin:10vh auto; padding:24px; }
#account-gate[hidden] { display:none !important; }
#account-gate .wordmark { display:flex; align-items:center; gap:10px; margin-bottom:20px; font-weight:700; font-size:17px; color:var(--rice-blue); }
#account-gate .shield { display:grid; place-items:center; width:28px; height:28px; border-radius:3px; background:var(--rice-blue); color:#fff; font-size:14px; font-weight:800; }
#account-gate h1 { margin-bottom:8px; }
#account-gate-message { line-height:1.5; color:var(--text-secondary); }
#account-gate > .acct-actions { margin-top:20px; }
/* The account form docked into the sign-in page (js/account-gate.js): part of the
   page, not a dialog over it. No backdrop, no title bar or × (the page heading
   names the step), and the gate's own buttons give way while it shows. */
#account-overlay.acct-docked { position:static; background:none; backdrop-filter:none; padding:0; margin-top:20px; }
#account-overlay.acct-docked.open { display:block; }
#account-overlay.acct-docked .modal { max-width:none; max-height:none; overflow:visible; box-shadow:none; }
#account-overlay.acct-docked .modal-header { display:none; }
#account-gate:has(> #account-overlay.open) > .acct-actions { display:none; }
#account-gate .account-gate-foot { margin-top:28px; font-size:12px; line-height:1.5; color:var(--text-muted); }
#account-gate .account-gate-foot a { color:var(--rice-blue); text-decoration:none; white-space:nowrap; }
#account-gate .account-gate-foot a:hover { text-decoration:underline; }
