:root {
    color-scheme: light;
    /* AHS Health palette — sourced from ahs.uwaterloo.ca/hlth230/style.css */
    --health-teal-dark:  #005963;
    --health-teal:       #0098A5;
    --health-teal-light: #97DFEF;
    --uw-gold:           #FFCC33;

    --blue:    var(--health-teal-dark);  /* primary interactive — links, focus, spinner */
    --gold:    var(--uw-gold);
    --gold-hover: #E6B800;
    --teal-hover: var(--health-teal);
    --green:   #16A34A;
    --red:     #DC2626;
    --purple:  #9333EA;
    --amber:   #D97706;
    --gray-50: #F7F7F7;
    --gray-100: #F3F4F6;
    --gray-200: #E5E7EB;
    --gray-300: #D1D5DB;
    --gray-400: #9CA3AF;
    --gray-500: #6B7280;
    --gray-600: #4B5563;
    --gray-700: #374151;
    --gray-800: #1F2937;
    --gray-900: #111827;
    --surface: #FFFFFF;
    --surface-muted: #F8FAFC;
    --danger-bg: #FEF2F2;
    --danger-border: #FECACA;
    --accent-bg: #FEF9DB;   /* gold tint — grade pills / score badges */
    --accent-fg: #7A5000;   /* dark gold — readable on gold tint */
    --accent-border: #F1C96B; /* gold border — achievement badge outline */
    --hover-bg: #E0F7FA;    /* teal-light tint — drag-over, hover fills */
    --open-bg:  #DCF3F6;    /* teal tint — active/open state */
    --open-fg:  #005963;    /* health-teal-dark */
    --closed-bg: #F3F4F6;   /* neutral gray — inactive/closed state */
    --closed-fg: #4B5563;
    --preview-bg: #FEF3C7;  /* amber tint — staff-only preview/beta state */
    --preview-fg: #92400E;  /* dark amber */
    --amber-bg: #FFFBEB;    /* pale amber — hint / warning callouts */
    --warning-bg: #FFF8E1;  /* warm amber tint — submission warning callout */
    --warning-border: #F1C96B;
    --border: var(--gray-200);
    /* Semantic aliases.  These reference the grays above, so they pick up the
       dark-mode palette automatically — no per-scheme override needed.  Added
       in the UI audit: --muted / --text-secondary / --font-mono were referenced
       across the admin, alerts, and import views but never defined, so muted
       text was silently rendering in full-strength body colour. */
    --muted: var(--gray-500);
    --text-secondary: var(--gray-600);
    --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    --success-bg: #E0F7FA;  /* teal-light tint — success state */
}

@media (prefers-color-scheme: dark) {
    :root {
        color-scheme: dark;
        --blue: #00C4D3;         /* bright teal — readable on dark backgrounds */
        --gold: #FFCC33;
        --gold-hover: #E6B800;
        --teal-hover: #00D4E8;
        --green: #4ADE80;
        --red: #F87171;
        --purple: #C084FC;
        --amber: #FBBF24;
        --gray-50: #0B1220;
        --gray-100: #111827;
        --gray-200: #1F2937;
        --gray-400: #9CA3AF;
        --gray-500: #9CA3AF;
        --gray-600: #CBD5E1;
        --gray-700: #D1D5DB;
        --gray-800: #E2E8F0;
        --gray-900: #E5E7EB;
        --surface: #111827;
        --surface-muted: #0F172A;
        --danger-bg: #3B1217;
        --danger-border: #7F1D1D;
        --accent-bg: #3D2800;   /* dark gold tint */
        --accent-fg: #FED34C;   /* soft gold — readable on dark gold tint */
        --accent-border: #7A4800; /* muted gold border — readable on dark */
        --hover-bg: #072D35;    /* dark teal tint */
        --open-bg:  #072D35;    /* dark teal — active/open state */
        --open-fg:  #67E8F9;    /* bright cyan-teal — readable on dark teal */
        --closed-bg: #1F2937;   /* dark gray — inactive/closed */
        --closed-fg: #9CA3AF;
        --preview-bg: #422006;  /* dark amber — staff-only preview/beta */
        --preview-fg: #FCD34D;  /* bright amber — readable on dark */
        --amber-bg: #422006;    /* dark amber — hint / warning callouts */
        --warning-bg: #3A2A06;  /* dark warm amber — submission warning callout */
        --warning-border: #7A4800;
        --success-bg: #072D35;
        /* --border inherits dark-mode --gray-200 automatically */
    }
}

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

body {
    font-family: system-ui, -apple-system, sans-serif;
    background: var(--gray-50);
    color: var(--gray-900);
    line-height: 1.5;
}

a { color: var(--blue); }

:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
}

.skip-link {
    position: absolute;
    left: -9999px;
    top: auto;
    width: 1px;
    height: 1px;
    overflow: hidden;
    padding: 0;
}

.skip-link:focus,
.skip-link:focus-visible {
    left: 1rem;
    top: .75rem;
    width: auto;
    height: auto;
    overflow: visible;
    z-index: 1000;
    padding: .45rem .7rem;
    border-radius: .35rem;
    background: var(--surface);
    border: 1px solid var(--gray-200);
    color: var(--gray-900);
    text-decoration: none;
}

.visually-hidden {
    position: absolute !important;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* ── Nav ─────────────────────────────────────────────── */

.nav {
    display: flex;
    align-items: center;
    gap: 1.5rem;
    padding: .75rem 1.5rem;
    background: #000000;
}

.nav-brand {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    font-weight: 700;
    font-size: 1.05rem;
    text-decoration: none;
    color: #0098A5;  /* health-teal — readable on black (6.4:1), matches AHS palette */
}

.nav-brand-logo {
    width: 2.4rem;
    height: 2.4rem;
    object-fit: contain;
    display: block;
}

.nav-link {
    font-size: .875rem;
    text-decoration: none;
    color: rgba(255,255,255,.85);
}

.nav-link:hover {
    color: #97DFEF;  /* health-teal-light — AHS palette, pale teal on black */
}

/* Small version label at the top of the admin page — admin-page-only
   per v0.4.102.  (The v0.4.99 nav-badge flavour was moved here so it
   doesn't appear in the global nav for instructor/admin users on
   non-admin pages.) */
.admin-version-banner {
    font-size: .75rem;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    color: var(--gray-500);
    margin: 0 0 .75rem 0;
    text-align: right;
}

/* ── AHS colour bar ──────────────────────────────────── */

.colour-bar {
    height: 5px;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
}

.colour-bar div:nth-child(1) { background: #97DFEF; }  /* health-teal-light */
.colour-bar div:nth-child(2) { background: #0098A5; }  /* health-teal */
.colour-bar div:nth-child(3) { background: #005963; }  /* health-teal-dark */

/* ── Main container ──────────────────────────────────── */

.main {
    /* min(900px, 100%) is identical to a flat 900px at any viewport wide
       enough to reach the cap, so desktop is unchanged; on a phone it simply
       tracks the viewport instead of needing a media query to "relax".  The
       fluid padding clamps to the same 1.5rem on desktop and only tightens
       below ~600px. */
    max-width: min(900px, 100%);
    margin: 2rem auto;
    padding: 0 clamp(1rem, 4vw, 1.5rem);
}

h1 { font-size: 1.4rem; margin-bottom: 1.25rem; }
h2 { font-size: 1rem;   margin-bottom: .4rem; }

/* ── Cards ───────────────────────────────────────────── */

.card-meta  { font-size: .8rem; color: var(--gray-600); margin-top: .2rem; }

/* Generic card surface — solid background + border so .card descendants
   don't inherit whatever's behind them.  Historically only `.card-meta`
   lived here; anything that reached for a plain `.card` class (e.g. the
   `+ Add Section` popup on the instructor dashboard, and the v0.4.96
   suite-editor popup) was transparent and unreadable. */
.card {
    background: var(--surface);
    color: var(--gray-900);
    border: 1px solid var(--border);
    border-radius: .5rem;
}

/* The `+ Section` popup inherits `.card`'s surface, and adds the
   shadow/padding/size specifics that make it feel like a floating menu
   rather than a page-level card.  Shared between the instructor
   dashboard (`assignments.leaf`) and the suite editor
   (`assignment-edit.leaf`). */
.add-section-popup {
    background: var(--surface);
    color: var(--gray-900);
    border: 1px solid var(--border);
    border-radius: .5rem;
    box-shadow: 0 4px 16px rgba(0, 0, 0, .25);
}

/* The HTML `hidden` attribute applies via `[hidden] { display: none }`
   in the UA stylesheet, but author-CSS rules like `.btn { display:
   inline-block }` override that, so a button with `hidden` would still
   render.  v0.4.104 hid the top-level New Script / New Family buttons
   via the attribute — they kept showing up because of this CSS
   collision.  Globally pin the attribute with !important so future
   uses Just Work. */
[hidden] { display: none !important; }

/* ── Buttons ─────────────────────────────────────────── */

.btn {
    display: inline-block;
    padding: .45rem .9rem;
    border-radius: .375rem;
    font-size: .875rem;
    font-weight: 500;
    text-decoration: none;
    cursor: pointer;
    border: 1px solid var(--gray-200);
    background: var(--surface);
    color: var(--gray-900);
    white-space: nowrap;
}

.btn-primary {
    background: #005963;  /* health-teal-dark */
    border-color: #005963;
    color: white;
}

.btn-primary:hover {
    background: #003D47;
    border-color: #003D47;
}

.btn + .btn { margin-left: .5rem; }

/* Assignment actions */
.action-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 1.95rem;
    padding: .25rem .6rem;
    font-size: .8rem;
    line-height: 1;
}

.action-danger {
    color: var(--gray-600);
    border-color: var(--gray-400);
    background: var(--gray-100);
}

/* ── Forms ───────────────────────────────────────────── */

.form {
    display: flex;
    flex-direction: column;
    gap: 1.1rem;
    max-width: min(620px, 100%);
}

.form--wide {
    max-width: none;
}

.form-label {
    display: flex;
    flex-direction: column;
    gap: .375rem;
    font-size: .875rem;
    font-weight: 500;
}

.form-input {
    padding: .5rem .75rem;
    border: 1px solid var(--gray-200);
    border-radius: .375rem;
    font-size: .875rem;
    font-family: inherit;
    background: var(--surface);
    color: var(--gray-900);
}

textarea.form-input {
    resize: vertical;
    font-family: monospace;
    font-size: .8rem;
}

/* ── Drop zone ───────────────────────────────────────── */

.drop-zone {
    border: 2px dashed var(--gray-200);
    border-radius: .5rem;
    padding: 2.5rem 1.5rem;
    text-align: center;
    cursor: pointer;
    transition: border-color .15s, background .15s;
    color: var(--gray-600);
    font-size: .9rem;
}

.drop-zone.drag-over {
    border-color: var(--blue);
    background: var(--hover-bg);
}

.drop-zone input[type=file] { display: none; }

.drop-filename {
    font-size: .85rem;
    color: var(--gray-600);
    min-height: 1.3rem;
    margin-top: .35rem;
}

/* ── Pending spinner ─────────────────────────────────── */

.pending-box {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1.25rem;
    padding: 4rem 0;
    color: var(--gray-600);
}

.spinner {
    width: 2.5rem;
    height: 2.5rem;
    border: 3px solid var(--gray-200);
    border-top-color: var(--blue);
    border-radius: 50%;
    animation: spin .8s linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }

/* ── Build failure ───────────────────────────────────── */

.error-box {
    background: var(--danger-bg);
    border: 1px solid var(--danger-border);
    border-radius: .5rem;
    padding: 1.25rem 1.5rem;
    margin-bottom: 1rem;
}

.error-box h2 { color: var(--red); }

.notice-box {
    background: var(--success-bg);
    border: 1px solid var(--border);
    border-radius: .5rem;
    padding: 1rem 1.25rem;
    margin-bottom: 1rem;
}

.compiler-output {
    margin-top: .75rem;
    font-size: .78rem;
    white-space: pre-wrap;
    overflow-x: auto;
    background: var(--surface);
    padding: .75rem;
    border-radius: .25rem;
    border: 1px solid var(--danger-border);
}

/* ── Results ─────────────────────────────────────────── */

.submission-header { margin-bottom: 1.25rem; }

.submission-header-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: .75rem;
    flex-wrap: wrap;
}

.score {
    font-size: 1.2rem;
    font-weight: 600;
    margin-bottom: 1rem;
}

.score-header {
    margin-top: .5rem;
    margin-bottom: .6rem;
    font-size: 1.05rem;
}

.grade-pill {
    display: inline-block;
    padding: .1rem .45rem;
    border-radius: 9999px;
    background: var(--accent-bg);
    color: var(--accent-fg);
    font-size: .95rem;
}

.assignment-title-cell {
    display: flex;
    align-items: center;
    gap: .45rem;
    flex-wrap: wrap;
}

.achievement-badges {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    flex-wrap: wrap;
}

.achievement-badge {
    display: inline-flex;
    align-items: center;
    padding: .28rem .7rem;
    border-radius: 9999px;
    background: var(--accent-bg);
    border: 1px solid var(--accent-border);
    color: var(--accent-fg);
    font-size: .78rem;
    font-weight: 600;
    line-height: 1.2;
    white-space: nowrap;
}

.achievement-badges-compact {
    gap: .3rem;
}

.achievement-badge-compact {
    padding: .18rem .5rem;
    font-size: .68rem;
}

/* "+N" overflow pill on the student-dashboard row: muted so it reads as a
   "more awards" affordance rather than an award itself.  Its title attribute
   lists the hidden badges. */
.achievement-badge-overflow {
    background: var(--gray-100);
    border-color: var(--gray-200);
    color: var(--text-secondary);
}

.exec-time {
    font-size: .875rem;
    font-weight: 400;
    color: var(--gray-600);
}

.results-table {
    width: 100%;
    border-collapse: collapse;
    font-size: .875rem;
    background: var(--surface);
    border: 1px solid var(--gray-200);
    border-radius: .5rem;
    overflow: hidden;
}

.results-table th {
    text-align: left;
    padding: .6rem .875rem;
    border-bottom: 2px solid var(--gray-200);
    color: var(--gray-600);
    font-weight: 600;
    font-size: .8rem;
    text-transform: uppercase;
    letter-spacing: .03em;
}

.results-table td {
    padding: .55rem .875rem;
    border-bottom: 1px solid var(--gray-100);
    vertical-align: top;
}

.results-table tr:last-child td { border-bottom: none; }

/* Section grouping for results tables — one block (optional heading + table)
   per test-suite section.  Shared by the server-rendered submission view
   (submission.leaf) and the browser runner's inline results (notebook.js,
   assignment-validate.js) so both group identically. */
.submission-section-block {
    margin-bottom: 1.5rem;
}
.submission-section-block:last-of-type {
    margin-bottom: 0;
}
.submission-section-heading {
    font-size: 1rem;
    font-weight: 600;
    margin: 1.25rem 0 .5rem 0;
    color: var(--gray-700);
    letter-spacing: .01em;
}

/* Sortable tables (see Public/sortable-table.js). A header button toggles
   asc/desc; the ↕/↑/↓ glyph reflects the current sort direction. */
.sort-header {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    padding: 0;
    border: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    cursor: pointer;
}
.sort-header::after {
    content: "↕";
    font-size: .8em;
    color: var(--gray-500);
}
th.sort-asc .sort-header::after { content: "↑"; }
th.sort-desc .sort-header::after { content: "↓"; }

.results-table .time {
    text-align: right;
    color: var(--gray-600);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.results-table .due-col {
    text-align: left;
    white-space: nowrap;
    width: 11rem;
}

/* Status colour strips — test outcome rows */
.status-pass    td:first-child { border-left: 3px solid var(--green); }
.status-fail    td:first-child { border-left: 3px solid var(--red); }
.status-error   td:first-child { border-left: 3px solid var(--purple); }
.status-timeout td:first-child { border-left: 3px solid var(--amber); }
.status-skipped td:first-child { border-left: 3px solid var(--gray-400); }

/* Assignment open/closed strips — teal/gray, not traffic-light colours */
.status-open    td:first-child { border-left: 3px solid var(--health-teal); }
.status-preview td:first-child { border-left: 3px solid var(--amber); }
.status-closed  td:first-child { border-left: 3px solid var(--gray-300); }

/* Tier badge */
.tier {
    display: inline-block;
    font-size: .72rem;
    padding: .1rem .4rem;
    border-radius: 9999px;
    background: var(--gray-100);
    color: var(--gray-600);
    font-weight: 500;
}

/* Per-section secret-tier aggregate (never itemized for students) */
.tier-summary-row {
    display: flex;
    align-items: center;
    gap: .6rem;
    border-left: 3px solid var(--gray-400);
    padding: .35rem 0 .35rem .6rem;
    margin: .25rem 0 .3rem;
    font-size: .9rem;
}

.tier-summary-row:last-child { margin-bottom: 0; }

.tier-summary-release { border-left-color: var(--amber); }
.tier-summary-secret  { border-left-color: var(--purple); }

.tier-summary-counts { font-weight: 500; }

.tier-summary-note {
    color: var(--gray-600);
    font-style: italic;
    font-size: .85rem;
}

/* Long result expand */
details > summary {
    cursor: pointer;
    color: var(--gray-600);
    font-size: .8rem;
    margin-top: .3rem;
}

details pre {
    margin-top: .4rem;
    font-size: .76rem;
    white-space: pre-wrap;
    background: var(--gray-50);
    padding: .6rem .75rem;
    border-radius: .25rem;
    border: 1px solid var(--gray-200);
    overflow-x: auto;
}

.result-mark {
    display: inline-block;
    font-size: .76rem;
    font-weight: 600;
    padding: .12rem .5rem;
    border-radius: 9999px;
    border: 1px solid transparent;
    white-space: nowrap;
}

.result-mark-pass {
    color: var(--open-fg);
    background: var(--open-bg);
    border-color: var(--open-fg);
}

.result-mark-fail {
    color: var(--closed-fg);
    background: var(--danger-bg);
    border-color: var(--closed-fg);
}

.result-mark-error {
    color: var(--purple);
    background: var(--gray-100);
    border-color: var(--purple);
}

.result-mark-timeout {
    color: var(--amber);
    background: var(--gray-100);
    border-color: var(--amber);
}

.result-mark-skipped {
    color: var(--gray-500);
    background: var(--gray-100);
    border-color: var(--gray-400);
}

.points-label {
    font-size: .7rem;
    color: var(--gray-500);
    margin-left: .3rem;
    white-space: nowrap;
}

/* Dependency-skip row annotations */
.skip-blocker {
    font-size: .75rem;
    color: var(--gray-500);
    margin-top: .2rem;
}

.skip-reason {
    color: var(--gray-500);
    font-style: italic;
}

/* Per-attempt delta column */
.delta-col {
    width: 2rem;
    text-align: center;
    color: var(--gray-500);
}

.delta-cell {
    text-align: center;
    font-weight: 700;
    font-size: 1rem;
}

.delta-improved  { color: var(--green); }
.delta-regressed { color: var(--red); }

.delta-summary {
    color: var(--gray-600);
    font-size: .9em;
}

/* ── Misc ────────────────────────────────────────────── */

.empty { color: var(--gray-600); font-size: .95rem; }

code { font-family: ui-monospace, monospace; font-size: .9em; }

/* ── Notebook page ───────────────────────────────────── */

.notebook-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: .35rem;
    flex-wrap: wrap;
    gap: .75rem;
}

.notebook-header h1 { margin-bottom: 0; }

.notebook-toolbar {
    display: flex;
    align-items: center;
    gap: .75rem;
    width: 100%;
}

.notebook-actions {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: .5rem;
}

.nb-status {
    font-size: .875rem;
    color: var(--gray-600);
}

/* Full-viewport iframe minus the nav + the (now-compacted) Submit/Download
   header.  The 8rem reserve tracks the trimmed chrome above (nav + colour bar +
   the .5rem .main margin + the slim header row); previously 9rem, which left
   the outer page itself scrolling because the real chrome exceeded it. */
.jl-frame {
    width: 100%;
    height: calc(100vh - 8rem);
    border: 1px solid var(--gray-200);
    border-radius: .5rem;
    background: var(--surface);
    display: block;
}

/* ── Alt-submit link ─────────────────────────────────── */
.alt-submit {
    font-size: .875rem;
    color: var(--gray-600);
    margin-top: .75rem;
}

/* ── Auth pages ──────────────────────────────────────── */

.auth-box {
    max-width: min(420px, 100%);
    margin: 3rem auto;
}

/* Chickadee mascot above the login heading. The PNG is transparent, so it sits
   cleanly on the page background in both light and dark mode. */
.auth-logo {
    display: block;
    width: 200px;
    height: 200px;
    max-width: 80%;
    margin: 0 auto 1rem;
}

.auth-box h1 { margin-bottom: 1.5rem; }

.auth-alt {
    margin-top: 1rem;
    font-size: .875rem;
    color: var(--gray-600);
}

/* ── Nav username + logout button ────────────────────── */

/* Applied alongside .nav-link on the account-menu toggle; color intentionally
   overrides nav-link's white — username appears dimmed, less prominent than nav actions. */
.nav-username {
    font-size: .875rem;
    color: rgba(255,255,255,.6);
}

/* ── Nav dropdown menus ──────────────────────────────── */

/* A nav item with more than one option (the Instructor course picker, the
   account/log-out menu) renders as a click-to-open dropdown.  Toggled by the
   `open` class from app.js; the menu is display:none until then, so no inline
   style is needed and check-styles stays green. */
.nav-dropdown {
    position: relative;
    display: inline-flex;
    align-items: center;
}

/* The account menu sits at the far right of the nav, where the bare username
   link used to. */
.nav-user {
    margin-left: auto;
}

.nav-dropdown-toggle {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
    font-family: inherit;
}

.nav-dropdown-caret {
    font-size: .65em;
    line-height: 1;
    transition: transform .12s ease;
}

.nav-dropdown.open .nav-dropdown-caret {
    transform: rotate(180deg);
}

.nav-dropdown-menu {
    display: none;
    position: absolute;
    top: calc(100% + .55rem);
    left: 0;
    min-width: 11rem;
    background: var(--surface);
    border: 1px solid var(--gray-200);
    border-radius: 8px;
    box-shadow: 0 6px 20px rgba(0,0,0,.22);
    padding: .3rem;
    z-index: 50;
}

/* The account menu is flush to the right edge of the nav, so its panel opens
   rightward-aligned to avoid spilling off-screen. */
.nav-user .nav-dropdown-menu {
    left: auto;
    right: 0;
}

.nav-dropdown.open .nav-dropdown-menu {
    display: block;
}

.nav-dropdown-item {
    display: block;
    width: 100%;
    box-sizing: border-box;
    text-align: left;
    padding: .5rem .7rem;
    font-size: .875rem;
    font-family: inherit;
    color: var(--gray-700);
    text-decoration: none;
    background: none;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    white-space: nowrap;
}

.nav-dropdown-item:hover {
    background: var(--hover-bg);
    color: var(--gray-900);
}

.nav-dropdown-item-active {
    color: var(--blue);
    font-weight: 600;
}

/* ── Course tabs ─────────────────────────────────────── */

.course-tabs {
    display: flex;
    gap: 0;
    padding: 0 1.5rem;
    background: var(--surface);
    border-bottom: 2px solid var(--gray-200);
    overflow-x: auto;
}

.course-tab {
    padding: .5rem 1.1rem;
    font-size: .875rem;
    font-weight: 500;
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    margin-bottom: -2px;
    cursor: pointer;
    color: var(--gray-600);
    white-space: nowrap;
    transition: color .12s, border-color .12s;
}

.course-tab:hover {
    color: var(--gray-900);
    border-bottom-color: var(--gray-400);
}

.course-tab-active {
    color: var(--blue);         /* health-teal-dark */
    border-bottom-color: var(--gold); /* UW gold underline */
    font-weight: 600;
}

.btn-link {
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
    font-family: inherit;
}

/* ── Form error messages ─────────────────────────────── */

.form-error {
    padding: .5rem .875rem;
    border-left: 3px solid var(--red);
    background: color-mix(in srgb, var(--red) 8%, var(--surface));
    color: var(--red);
    border-radius: 0 .25rem .25rem 0;
    margin-bottom: 1rem;
}

/* ── Admin dashboard ─────────────────────────────────── */

.admin-section {
    margin-bottom: 2.5rem;
}

.admin-section h2 {
    margin-bottom: .875rem;
}

/* ── Section tab bar (admin + instructor) ────────────── */
/* Inlined into each page rather than a Leaf fragment: LeafKit 1.x raises a
   false-positive "cyclically referenced" error on #extend of a shared
   partial here. */

.admin-tabs,
.instructor-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: .25rem;
    border-bottom: 1px solid var(--border);
    margin-bottom: 1.5rem;
}

.admin-tab,
.instructor-tab {
    padding: .55rem .9rem;
    text-decoration: none;
    color: var(--gray-600);
    font-weight: 500;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
}

.admin-tab:hover,
.instructor-tab:hover {
    color: var(--gray-900);
}

.admin-tab[aria-current="page"],
.instructor-tab[aria-current="page"] {
    color: var(--gray-900);
    font-weight: 600;
    border-bottom-color: var(--gray-900);
}

/* ── Assignment status badge variants ────────────────── */

.tier-open {
    background: var(--open-bg);
    color: var(--open-fg);
}

.tier-closed {
    background: var(--closed-bg);
    color: var(--closed-fg);
}

.tier-preview {
    background: var(--preview-bg);
    color: var(--preview-fg);
}

.tier-unpublished {
    background: var(--gray-100);
    color: var(--gray-600);
}

/* A personal deadline extension keeps a class-closed assignment actionable for
   one student: same palette as "open" (it reads as open, per design), but
   labelled "extended" so the accommodation is visible. */
.tier-extended {
    background: var(--open-bg);
    color: var(--open-fg);
}

/* Staff-only ("preview") badge on the student dashboard stays on one line. */
.staff-only-tag { white-space: nowrap; }

/* ── Inline publish form (inside <details>) ──────────── */

.publish-details summary::-webkit-details-marker { display: none; }

.reorder-controls {
    display: inline-flex;
    align-items: center;
    gap: .2rem;
    margin-right: .35rem;
}

.reorder-btn {
    border: 1px solid var(--gray-200);
    background: var(--surface);
    border-radius: .25rem;
    color: var(--gray-600);
    font-size: .75rem;
    line-height: 1;
    min-width: 1.2rem;
    min-height: 1.2rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
}

#users-table th[data-sort-key]:focus-visible,
#assignment-submissions-table th[data-sort-key]:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: -2px;
}

.publish-form {
    margin-top: .75rem;
    padding: .75rem;
    border: 1px solid var(--gray-200);
    border-radius: 6px;
    background: var(--gray-50);
    display: flex;
    flex-direction: column;
    gap: .6rem;
    min-width: 260px;
}

/* ── Validate page results panel ─────────────────────── */

#validate-results {
    margin-top: 1.25rem;
    padding-bottom: 2rem;
}

#validate-results .score {
    font-size: 1.1rem;
    font-weight: 600;
    margin-bottom: .75rem;
}

/* ── Inline notebook results panel ───────────────────── */
.nb-results {
    margin-top: 1.25rem;
    padding-bottom: 2rem;
}

.nb-results .score {
    font-size: 1.1rem;
    font-weight: 600;
    margin-bottom: .75rem;
}

.nb-results-link {
    display: inline-block;
    margin-top: .875rem;
    font-size: .875rem;
}

/* ── Inline "+ Section" popup (assignments.leaf + assignment-edit.leaf) ──
   Identical rules formerly duplicated in both views' embedded <style>
   blocks; consolidated here (v0.4.x UI audit). */
.add-section-details { margin: 0; padding: 0; }
.add-section-details > summary { margin: 0; }
.add-section-details > summary::-webkit-details-marker { display: none; }
.add-section-details > summary::marker { content: ""; }
.add-section-details[open] .add-section-popup { display: block; }
.section-block.section-dragging { opacity: .55; }

/* ── Inline extension/override <details> (assignment-submissions.leaf +
   course-student-submissions.leaf) — render the <summary> as a clean icon
   button aligned with the Retest/Reset buttons.  Consolidated from two
   identical embedded blocks (v0.4.x UI audit). */
.ext-summary { margin-top: 0; list-style: none; }
.ext-summary::-webkit-details-marker { display: none; }
.ext-details[open] > .ext-summary { background: var(--gray-100); }
.ext-details form { min-width: 14rem; }
@media (max-width: 640px) { .ext-details form { min-width: 0; } }
/* Inline set/clear panel shared by the grade-override control
   (assignment-submissions.leaf) and the register-pending-student control
   (instructor-students.leaf) — hoisted from a page block so both pages render
   identically. */
.form-flush { margin: 0; }
.ext-panel {
    margin-top: .4rem;
    display: flex;
    flex-direction: column;
    gap: .3rem;
    padding: .5rem;
    background: var(--gray-50);
    border: 1px solid var(--gray-300);
    border-radius: .25rem;
}
.ext-field-label { font-size: .78rem; color: var(--gray-700); }
.ext-field-input { width: 100%; margin-top: .2rem; }
.ext-panel-actions { display: flex; gap: .3rem; }

/* ── Submission view (submission.leaf) ───────────────── */
/* Migrated out of submission.leaf's embedded <style> block (v0.4.x UI audit)
   so the page-level CSS lives in one cacheable sheet.  The base
   .achievement-badge / .achievement-badges rules are NOT redefined here —
   they're the global ones above; only the "full" size modifier is page-local. */

.submission-score-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
    flex-wrap: wrap;
}

/* Secondary "Autograded: …%" line shown under an overridden grade. */
.score-autograded { font-size: .9rem; color: var(--gray-600); }

/* "Offline" runner badge (admin overview + runner detail pages). */
.runner-badge-offline {
    display: inline-block;
    font-size: .7rem;
    font-weight: 600;
    padding: .1rem .4rem;
    border-radius: 999px;
    background: var(--gray-200);
    color: var(--gray-600);
    vertical-align: middle;
    margin-left: .3rem;
    letter-spacing: .03em;
    text-transform: uppercase;
}

.achievement-badges-full .achievement-badge { font-size: .82rem; }

.test-cell-main {
    display: flex;
    flex-direction: column;
    gap: .3rem;
}

.test-short-result {
    color: var(--gray-600);
    font-size: .88rem;
    line-height: 1.4;
}

.test-hint {
    margin-top: .4rem;
    padding: .35rem .55rem;
    border-left: 3px solid var(--amber);
    background: var(--amber-bg);
    border-radius: .25rem;
    font-size: .85rem;
    line-height: 1.4;
    color: var(--gray-800);
}

.test-output-details { margin-top: .4rem; }

.test-output-details summary {
    cursor: pointer;
    color: var(--blue);
    font-size: .9rem;
}

.test-output-pre {
    margin-top: .5rem;
    padding: .85rem 1rem;
    border-radius: .5rem;
    background: var(--gray-50);
    border: 1px solid var(--border);
    color: var(--gray-900);
    white-space: pre-wrap;
    word-break: break-word;
    overflow-x: auto;
    line-height: 1.45;
}

.test-output-row td { padding-top: 0; }

.test-output-panel { padding: .35rem 0 .2rem; }

.test-output-heading {
    font-size: .74rem;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--gray-500);
    font-weight: 700;
}

.test-output-pre-wide { margin-top: .35rem; }

.warning-box {
    margin-bottom: 1rem;
    padding: .85rem 1rem;
    border-radius: .5rem;
    background: var(--warning-bg);
    border: 1px solid var(--warning-border);
}

.warning-box h2 {
    margin: 0 0 .5rem 0;
    font-size: 1rem;
}

.warning-list {
    margin: 0;
    padding-left: 1.25rem;
}

/* Tag shown next to a grade that an instructor has manually overridden.
   Used on the student dashboard, the submission page, and the instructor
   roster / per-student views. */
.grade-override-tag {
    display: inline-block;
    margin-left: .35rem;
    padding: 0 .3rem;
    font-size: .68rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .02em;
    color: var(--gray-700);
    background: var(--gray-100);
    border: 1px solid var(--gray-300);
    border-radius: .2rem;
    vertical-align: middle;
}
.grade-override-active { border-color: var(--gray-500); background: var(--gray-100); }

/* ── Student dashboard (index.leaf + _assignment-row.leaf) ───────────── */

.assignment-section-heading {
    font-size: 1.05rem;
    font-weight: 600;
    margin-top: 1.5rem;
    margin-bottom: .4rem;
}

.assignment-table { margin-bottom: .5rem; }
.assignment-table--ungrouped { margin-top: 1rem; }

.text-muted { color: var(--gray-600); }

.due-extension-note { font-size: .75rem; color: var(--gray-600); }

.submission-history-cell {
    display: flex;
    flex-direction: column;
    gap: .2rem;
}

.submission-history-latest { font-size: .82rem; }
.submission-history-more { font-size: .78rem; color: var(--gray-600); }

.assignment-actions-cell {
    display: flex;
    gap: .4rem;
    flex-wrap: nowrap;
    align-items: center;
}

/* Square-ish icon-only action button (edit / upload / reset glyphs). */
.action-btn-icon { padding: .3rem .45rem; }
/* Compact action button used in dense submission/roster table rows. */
.action-btn-tight { padding: .25rem .35rem; }

/* Wrapper form that should not introduce vertical rhythm (inline action).
   display:inline is a no-op for flex-item forms (flex blockifies children),
   so it's safe for both inline contexts and existing flex-row uses. */
.inline-form { display: inline; margin: 0; }

/* ── Account / enroll / consent / setup pages (UI audit) ─────────────────
   Page-specific components replacing inline styles on the small static
   pages.  Grouped here so they share the one cacheable stylesheet. */

/* Account: key/value detail list. */
.detail-grid {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: .4rem 1.25rem;
    max-width: 480px;
}
.detail-grid dt { color: var(--gray-600); }
.detail-grid dd { margin: 0; }

/* Enroll: intro paragraph + course checklist. */
.enroll-intro { margin-bottom: 1.25rem; color: var(--gray-600); }
.fieldset-plain { border: none; padding: 0; margin: 0 0 1.5rem; }
.fieldset-plain > legend { margin-bottom: .75rem; font-weight: 600; }
.checkbox-list { display: flex; flex-direction: column; gap: .6rem; }
.checkbox-row { display: flex; align-items: center; gap: .6rem; cursor: pointer; }

/* Setup-new / generic option fieldset with radio rows. */
.option-fieldset {
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: .75rem 1rem;
    margin-bottom: 1.25rem;
}
.option-fieldset > legend { padding: 0 .4rem; font-weight: 600; font-size: .9rem; }
.radio-row { display: flex; align-items: center; gap: .5rem; cursor: pointer; }
.radio-row + .radio-row { margin-top: .4rem; }
.field-note { margin-top: .25rem; font-size: .82rem; }

/* Consent: scope list + small print. */
.consent-scope-list { margin: 0 0 1rem 1.25rem; }
.fine-print { font-size: .9rem; }
.consent-note { color: var(--gray-600); font-size: .85rem; margin-bottom: 1rem; }

/* ── Shared page components (UI audit: replaces repeated inline styles) ──
   Cross-page building blocks so individual templates carry semantic class
   names instead of inline style="" attributes.  Page-unique styling still
   lives in each page; these are only the patterns that recurred widely. */

/* Success/confirmation banner (distinct from the red .error-box / neutral
   .notice-box) — green-outlined, sits above page content. */
.notice-banner {
    margin-bottom: 1rem;
    padding: 1rem;
    border: 1px solid var(--green);
    border-radius: .5rem;
    background: var(--success-bg);
}
.notice-banner p { margin: 0; color: var(--green); font-weight: 600; }

/* A title row: heading on the left, actions on the right, wrapping on
   narrow screens.  The heading inside sheds its default margin. */
.page-titlebar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
    flex-wrap: wrap;
    margin-bottom: 1rem;
}
.page-titlebar h1, .page-titlebar h2 { margin: 0; }
.page-titlebar--baseline { align-items: baseline; }

/* Secondary text shown next to / under a page title. */
.page-subtitle { margin: .35rem 0 0; color: var(--text-secondary); }

/* Horizontal cluster of controls (button groups, inline actions). */
.toolbar { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.toolbar--end { justify-content: flex-end; }

/* A compact inline form field: "Label <input>" on one line. */
.field-inline {
    display: flex;
    align-items: center;
    gap: .4rem;
    font-size: .875rem;
    white-space: nowrap;
}
/* A stacked field: label above its control. */
.field-stack {
    display: flex;
    flex-direction: column;
    gap: .2rem;
    font-size: .85rem;
}
/* Compact form control sizing for dense toolbars/editor rows. */
.input-compact { font-size: .875rem; padding: .2rem .5rem; }

/* Common block-level bottom spacing for standalone sections/notices. */
.section-gap { margin-bottom: 1rem; }

/* A button row sitting below form content (relies on .btn + .btn spacing). */
.form-actions { margin-top: 1rem; }

/* A form that should not affect layout (its children participate directly,
   e.g. a course-tab button inside the tab bar). */
.contents-form { display: contents; }
/* Centre a button's label (full-width SSO button). */
.btn--center { text-align: center; }

/* ── Diagnostic cards (admin + instructor dashboards) ────────────────────
   Unified from four near-identical embedded copies (UI audit). One card
   style everywhere: a flex column with a consistent min-height so cards
   align uniformly across the admin and instructor dashboards. */
.diagnostics-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: .75rem;
}
.diagnostic-card {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    min-height: 5.5rem;
    padding: .75rem .9rem;
    border: 1px solid var(--border);
    border-radius: .5rem;
    background: var(--surface);
}
.diagnostic-label {
    color: var(--gray-600);
    font-size: .82rem;
    line-height: 1.25;
}
.diagnostic-value {
    font-size: 1.2rem;
    font-weight: 600;
    line-height: 1.2;
    color: var(--gray-900);
}

/* ── Clickable diagnostic cards with sparklines ─────────
   Shared by the admin dashboard (admin.leaf) and the instructor dashboard
   (assignments.leaf); both poll a /metrics/cards endpoint and cycle the
   window on click. */
.diagnostic-card-cyclable {
    cursor: pointer;
    user-select: none;
}
.diagnostic-card-cyclable:hover {
    border-color: var(--health-teal);
}
.diagnostic-card-cyclable:focus-visible {
    outline: 2px solid var(--health-teal-dark);
    outline-offset: 2px;
}
.diagnostic-window-chip {
    font-weight: 600;
    color: var(--health-teal-dark);
}
.diagnostic-spark {
    display: flex;
    align-items: flex-end;
    gap: 1px;
    height: 28px;
    margin-top: .4rem;
}
.spark-slot {
    flex: 1 1 0;
    height: 100%;
    display: flex;
    align-items: flex-end;
}
.spark-fill {
    width: 100%;
    height: var(--bar-h, 0);
    min-height: 2px;
    background: var(--health-teal);
    border-radius: 1px 1px 0 0;
}
.spark-fill-empty {
    /* An empty bucket still draws a faint 2px baseline tick (not transparent)
       so a histogram always shows its full axis — e.g. the grade distribution
       reads as a fixed 0–100% range even when most buckets have no students.
       Populated buckets rise in --health-teal well above this baseline. */
    min-height: 2px;
    background: var(--border);
}

/* ── Assignment editor: header + suite editor (new + edit pages) ─────────
   Shared component classes replacing inline styles duplicated across
   assignment-new.leaf and assignment-edit.leaf (UI audit).  display:* is
   intentionally left inline on JS-toggled elements (a class display rule
   would collide with scripts that clear style.display via ''). */
.editor-titlebar {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 1.25rem;
}
.editor-title-col { flex: 1; min-width: 16rem; }
.editor-actions {
    display: flex;
    gap: .6rem;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
}
.editor-block { margin-bottom: 1.25rem; }
/* Borderless, oversized assignment-name field at the top of the editor. */
.assignment-name-input {
    font-size: 1.4rem;
    font-weight: 600;
    border: none;
    border-bottom: 2px solid var(--border);
    border-radius: 0;
    padding: .15rem 0;
    background: transparent;
    width: 100%;
}
.assignment-meta-row {
    display: flex;
    gap: 1.25rem;
    flex-wrap: wrap;
    margin-top: .6rem;
    align-items: center;
}
/* JS-shown proximity warning by the due-date field (palette amber, was a
   hardcoded #c05000); display stays inline (toggled to '' by script). */
.date-warning { color: var(--amber); margin-top: .4rem; }
/* JS-shown grading-mode hint under the section picker (display toggled inline). */
.grading-mode-hint { margin-top: .3rem; }
/* Runner-requirements row + its two grow-to-fill labelled inputs. */
.runner-req-row { display: flex; gap: 1rem; flex-wrap: wrap; margin: .5rem 0 1.25rem; }
.req-field { display: flex; align-items: center; gap: .4rem; font-size: .875rem; flex: 1; min-width: 12rem; }
.input-sm { font-size: .875rem; padding: .25rem .5rem; }

/* Suite editor header row + the "+ Section" pop-out menu. */
/* Generic header bar for an editor block: a heading on the left, an
   action toolbar on the right.  Shared by the Files, Global Inputs, and
   Test Suite blocks on the assignment new/edit pages. */
.editor-block-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
    flex-wrap: wrap;
    margin-bottom: .75rem;
}
.suite-section-popup {
    position: absolute;
    z-index: 100;
    top: 100%;
    right: 0;
    margin-top: .25rem;
    padding: 1rem;
    min-width: 18rem;
    box-shadow: 0 4px 16px rgba(0, 0, 0, .15);
}
.popup-anchor { position: relative; }

/* "+ Add Test" type dropdown (built from the Test Editor catalog by
   test-editor-modal.js).  Reuses the .add-section-popup chrome; this class
   owns the anchored position + the grouped-menu internal layout. */
.add-test-menu {
    position: absolute;
    z-index: 100;
    top: 100%;
    right: 0;
    margin-top: .25rem;
    padding: .4rem;
    min-width: 17rem;
    max-height: 60vh;
    overflow-y: auto;
    box-shadow: 0 4px 16px rgba(0, 0, 0, .15);
}
.add-test-details[open] .add-test-menu { display: block; }
.add-test-group { padding: .15rem 0; }
.add-test-group + .add-test-group { border-top: 1px solid var(--border); margin-top: .15rem; }
.add-test-group-label {
    font-size: .68rem;
    text-transform: uppercase;
    letter-spacing: .03em;
    color: var(--gray-500);
    padding: .3rem .5rem .15rem;
}
.add-test-item {
    display: block;
    width: 100%;
    text-align: left;
    background: none;
    border: none;
    border-radius: .3rem;
    padding: .35rem .5rem;
    font-size: .85rem;
    color: var(--gray-900);
    cursor: pointer;
}
.add-test-item:hover, .add-test-item:focus {
    background: var(--gray-100);
    outline: none;
}

/* Inline editor (accordion) hosted in a detail row beneath a suite/achievement
   row.  Shared by the suite editor (suite-table.js) and the achievements editor
   (achievements-editor.js) through ChickadeeUI.accordion. */
.suite-row-expanded > td { background: var(--gray-100); }
/* A continuous left accent bar ties the open editor to its row (mirrors the
   status colour-strips at .status-pass &c.). */
.suite-row-expanded > td:first-child { border-left: 3px solid var(--blue); }
.suite-detail-row > td {
    padding: 0;   /* padding lives on .suite-detail-inner so the collapsed
                     (grid 0fr) state is genuinely zero-height — no flash */
    background: var(--gray-100);
    border-top: none;
    border-bottom: 1px solid var(--gray-200);  /* delineate from the next test */
    border-left: 3px solid var(--blue);
}
/* Height animation: a single-row grid transitions grid-template-rows 0fr -> 1fr,
   animating the editor's intrinsic height with no magic max-height (the family
   editor's height varies a lot).  The inner clips while the row is partly open
   (overflow:hidden) and can shrink below its content (min-height:0). */
.suite-detail-anim {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows .18s ease;
}
.suite-detail-anim.is-open { grid-template-rows: 1fr; }
.suite-detail-inner {
    overflow: hidden;
    min-height: 0;
    padding: .75rem 1rem 1rem;
}
.suite-detail-host { display: flex; flex-direction: column; gap: .5rem; }
.suite-detail-actions {
    display: flex;
    align-items: center;
    gap: .6rem;
    margin-top: .75rem;
    padding-top: .6rem;
    border-top: 1px solid var(--border);
}
.suite-detail-status { font-size: .8rem; }
.suite-detail-status-error { color: var(--red); }

/* Rotating disclosure caret on rows that open an inline editor (pattern-family
   and notebook-check rows in the suite editor; every achievement row).  Script
   rows open the modal instead, so they deliberately carry no caret. */
.accordion-caret {
    display: inline-flex;
    align-items: center;
    color: var(--gray-500);
    transition: transform .18s ease;
}
.suite-row-expanded .accordion-caret { transform: rotate(90deg); }

/* Editor-only row affordances — the shared, student-facing .results-table is
   untouched.  Firmer separators between tests, and a hover fill (skipping the
   open row, which has its own background). */
#suite-sections tbody tr[data-id] > td,
.achievements-body tr[data-i] > td {
    border-bottom: 1px solid var(--gray-200);
}
/* No separator between the open row and its editor — they read as one unit.
   Scoped to match the firmer-separator rule above so it actually wins. */
#suite-sections tbody tr[data-id].suite-row-expanded > td,
.achievements-body tr[data-i].suite-row-expanded > td {
    border-bottom: none;
}
#suite-sections tbody tr[data-id]:not(.suite-row-expanded):hover > td,
.achievements-body tr[data-i]:not(.suite-row-expanded):hover > td {
    background: var(--gray-50);
}

@media (prefers-reduced-motion: reduce) {
    .suite-detail-anim { transition: none; }
    .accordion-caret { transition: none; }
}

/* Achievements editor — composable condition builder (achievements-editor.js). */
.am-conditions { display: flex; flex-direction: column; gap: .4rem; margin: .4rem 0 .6rem; }
.am-condition { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; }
.am-condition .form-input { width: auto; }
.am-cond-signal { min-width: 9rem; }
.am-cond-value { width: 6rem; }
.am-cond-testref { min-width: 12rem; }
.am-cond-unit { color: var(--gray-500); font-size: .85rem; }
.am-cond-remove { line-height: 1; }
.form-input--inline { display: inline-block; width: auto; margin: 0 .25rem; }

/* A suite section block: header bar, view/edit modes, per-section toolbars. */
.section-block { margin-bottom: 1.25rem; }
.section-header {
    display: flex;
    align-items: center;
    gap: .5rem;
    flex-wrap: wrap;
    margin-bottom: .4rem;
    padding: .4rem .6rem;
    background: var(--gray-100);
    border-radius: .4rem;
}
.section-drag-handle {
    color: var(--gray-500);
    font-weight: 700;
    cursor: grab;
    user-select: none;
    font-size: 1rem;
    flex-shrink: 0;
}
.section-view { display: flex; align-items: center; gap: .4rem; flex: 1; min-width: 0; flex-wrap: wrap; }
/* .section-edit/.section-create-toolbar: display toggled by JS, left inline. */
.section-edit { align-items: center; gap: .5rem; flex: 1; flex-wrap: wrap; }
.section-create-toolbar { display: flex; align-items: center; gap: .4rem; justify-content: flex-end; margin: .15rem 0 .25rem; }
.section-rename-form { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; flex: 1; }
.section-name-input { font-size: .85rem; padding: .25rem .45rem; flex: 1; min-width: 8rem; }
.section-spacer { flex: 1; }
.section-vars-form { margin: .25rem 0 .5rem; }
.section-vars-table { font-size: .78rem; width: 100%; }
.section-var-namecell { width: 14rem; white-space: nowrap; }
.section-var-valid { display: inline-block; width: 1rem; color: var(--green); font-size: .95rem; text-align: center; }
.section-var-name-input { width: calc(100% - 1.5rem); padding: .2rem .4rem; font-size: .78rem; font-family: monospace; }
.section-var-value-input { width: 100%; padding: .2rem .4rem; font-size: .78rem; font-family: monospace; }
.section-var-removecell { width: 2.5rem; text-align: right; }
.icon-btn-xs { padding: .2rem .4rem; display: inline-flex; align-items: center; }

/* Small inline icon-button (edit/cancel pencils in section + assignment headers). */
.icon-btn-text { display: inline-flex; align-items: center; padding: .1rem .25rem; color: var(--gray-500); }
/* Small pill-ish buttons used in section toolbars and family editor. */
.btn-xs { padding: .2rem .55rem; font-size: .75rem; }
.btn-sm { padding: .2rem .6rem; font-size: .8rem; }

/* Pattern-family / notebook-check editor body (modal). */
.family-editor-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: .6rem; }
.family-subhead { display: flex; justify-content: space-between; align-items: center; margin-bottom: .3rem; }
.editor-status { font-size: .8rem; color: var(--gray-500); }
.family-editor-body { flex-direction: column; gap: .75rem; }

/* Auto-detected runner-requirements note. */
.detected-note { margin: .75rem 0 .4rem; }
/* Error detail line under an .error-box heading. */
.error-detail { margin-top: .5rem; }

/* Assignment-edit inline name/due header (view + JS-toggled edit modes). */
.assign-header-view { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.assign-header-view h1 { margin: 0; }
.assign-header-edit { padding: .75rem 1rem; border: 1px solid var(--border); border-radius: .5rem; background: var(--gray-50); }
.assign-header-edit-top { display: flex; align-items: center; justify-content: space-between; margin-bottom: .6rem; }
.field-gap { margin-bottom: .5rem; }
.input-block { display: block; width: 100%; }

/* Global-inputs editor rows (edit page). */
.global-input-name-input { width: calc(100% - 1.5rem); padding: .2rem .4rem; font-family: monospace; }
.global-input-value-input { width: 100%; padding: .2rem .4rem; font-family: monospace; }

/* BrightSpace grade-sync collapsible. */
.bs-summary { cursor: pointer; font-weight: 600; font-size: .9rem; padding: .4rem 0; }
.bs-body { margin-top: .75rem; max-width: 520px; }
.bs-note { margin: .3rem 0 .6rem; }

/* Suite editor container + editor-block header headings. */
.suite-editor-section { margin-top: 1.25rem; }
.editor-block-head h2 { margin: 0; }

/* "Generate starter tests" panel (display toggled by JS, kept inline). */
.gen-tests-panel {
    margin-bottom: .75rem;
    padding: .75rem 1rem;
    border: 1px solid var(--border);
    border-radius: .5rem;
    background: var(--gray-50);
}

/* <summary> rendered as a button (no disclosure marker). */
.summary-btn { cursor: pointer; list-style: none; }
.summary-btn::-webkit-details-marker { display: none; }
/* Compact form inside a pop-out menu. */
.popup-form { margin: 0; gap: .6rem; }
/* Standard compact editor field control + compact button sizes. */
.editor-input { font-size: .85rem; padding: .3rem .5rem; }
.btn-compact { font-size: .85rem; padding: .3rem .6rem; }
.btn-tiny { font-size: .8rem; padding: .25rem .5rem; }
.select-xs { padding: .2rem .5rem; font-size: .8rem; }

/* Generate-starter-tests panel internals. */
.gen-tests-row { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; margin-bottom: .5rem; }
.gen-tests-title { font-size: .875rem; font-weight: 600; }
.fn-checklist { display: flex; flex-wrap: wrap; gap: .4rem .9rem; margin-bottom: .6rem; }
.gen-template-row { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; margin-bottom: .4rem; }
.gen-template-label { font-size: .8rem; display: flex; align-items: center; gap: .3rem; }
.gen-tests-prompt { margin-bottom: .4rem; }
/* Right-aligned action buttons inside a table cell (notebook files table). */
.cell-actions { display: flex; gap: .4rem; justify-content: flex-end; flex-wrap: wrap; }
/* Inline upload-status text (colour also set by JS on error). */
.upload-status-inline { font-size: .78rem; color: var(--gray-500); margin-left: .5rem; }
/* A function checkbox item in the generate-tests checklist (built in JS). */
.fn-check-item { font-size: .8rem; display: flex; align-items: center; gap: .3rem; cursor: pointer; }

/* Pattern-family editor body internals. */
.label-note { color: var(--gray-600); font-weight: 400; }
.subhead-label { font-size: .85rem; }
.table-sm { font-size: .8rem; }
.hint-xs { font-size: .72rem; }
.family-empty-note { margin: .3rem 0 0; font-size: .72rem; color: var(--gray-500); }
.fv-valid-col { width: 2rem; }
.fv-name-col { width: 12rem; }
.fv-action-col { width: 4rem; }
.case-num-col { width: 2.25rem; }

/* Instructor dashboard (assignments.leaf): section toolbar + per-section bits. */
.section-toolbar { display: flex; justify-content: flex-end; align-items: center; flex-wrap: wrap; gap: .5rem; margin-bottom: 1.5rem; }
.section-mode-note { font-size: .78rem; color: var(--gray-500); }
.section-action { font-size: .8rem; padding: .2rem .55rem; }
.section-action--push { margin-left: auto; }
.grading-mode-select { font-size: .85rem; padding: .25rem .45rem; }
/* Tight row of icon/action buttons in an assignment-row Actions cell; the
   compact padding comes from the row so individual buttons stay class-clean. */
.row-actions-tight { display: flex; gap: .2rem; flex-wrap: nowrap; align-items: center; white-space: nowrap; }
.row-actions-tight .btn { padding: .25rem .35rem; }
.cell-subrow { margin-top: .25rem; }
.nowrap { white-space: nowrap; }
.status-toggle-btn { font-size: .8rem; padding: .25rem .45rem; min-width: 5.5rem; }
.section-empty-cell { color: var(--gray-500); font-style: italic; padding: .6rem .75rem; text-align: center; }
.publish-label { font-size: .8rem; }
.publish-uw-warning { color: var(--amber); font-size: .8rem; margin-top: -.25rem; margin-bottom: .25rem; }
.dashboard-block { margin-bottom: 1.5rem; }
.ungrouped-heading { font-size: 1rem; font-weight: 600; color: var(--gray-600); margin-bottom: .4rem; }

/* Pre-draft "upload a notebook to begin" placeholder. */
.predraft-note {
    margin-top: 1.25rem;
    padding: 1rem 1.25rem;
    border: 1px dashed var(--border);
    border-radius: .5rem;
    background: var(--gray-50);
    color: var(--gray-500);
    font-size: .875rem;
}

/* ── Suite editor drag/drop (assignment-new.leaf + assignment-edit.leaf) ──
   Consolidated from two duplicated embedded <style> blocks (UI audit). */
.suite-drag-handle { cursor: grab; user-select: none; color: var(--gray-500); padding: 0 .3rem; }
.suite-drag-handle:active { cursor: grabbing; }
.suite-row-dragging { opacity: .35; }
tr.drop-before td:first-child { border-top: 2px solid var(--blue); }
tr.drop-after  td:first-child { border-bottom: 2px solid var(--blue); }
tr.drop-adopt  { outline: 2px solid var(--blue); outline-offset: -2px; }
.suite-name-cell { display: flex; align-items: center; gap: .4rem; }
.suite-root-drop { height: 2rem; text-align: center; font-size: .75rem; color: var(--gray-500); cursor: default; }
.suite-root-drop.drop-hover { background: var(--hover-bg); }
.suite-child-indent { padding-left: 2rem; white-space: nowrap; }
.suite-child-connector { color: var(--gray-500); margin-right: .25rem; font-size: .85em; }
.suite-upload-error { font-size: .78rem; color: var(--red); margin-top: .2rem; }
.suite-file-hint { font-size: .75rem; color: var(--gray-500); margin-top: .2rem; }
.suite-file-hint a { color: inherit; }
#suite-config-table td { vertical-align: top; }

/* ── CodeMirror 6 host + Test Editor modal dark mode (new + edit pages) ───
   Consolidated from two duplicated embedded <style> blocks (UI audit). */
#cm-editor-mount .cm-editor { height: 100%; min-height: 240px; }
#cm-editor-mount .cm-scroller { overflow: auto; }
@media (prefers-color-scheme: dark) {
    #cm-editor-mount .cm-editor    { background: var(--gray-100); }
    #cm-editor-mount .cm-gutters   { background: var(--gray-200); border-color: var(--gray-200); color: var(--gray-500); }
    #cm-editor-mount .cm-content   { color: var(--gray-900); caret-color: var(--gray-900); }
    #cm-editor-mount .cm-activeLine { background: var(--gray-200); }
    #cm-editor-mount .cm-selectionBackground, #cm-editor-mount ::selection { background: var(--hover-bg) !important; }
    #cm-editor-mount .cm-cursor    { border-left-color: var(--gray-900); }
    #test-editor-overlay input, #test-editor-overlay select, #test-editor-overlay textarea { background: var(--gray-100); color: var(--gray-900); border-color: var(--gray-200); }
}

/* ════════════════════════════════════════════════════════════════════
   Responsive design  —  see docs/responsive-design-plan.md
   --------------------------------------------------------------------
   Hard constraint: the desktop (>1024px) rendering is unchanged.  Every
   rule below is either width-agnostic intrinsic CSS that is identical at
   desktop by construction (see .main / .form / .auth-box above), or lives
   inside a (max-width) media query so it can only take effect on smaller
   screens.
   Breakpoints:   phone ≤640px      tablet ≤1024px      desktop >1024px
   ════════════════════════════════════════════════════════════════════ */

/* Column-hiding utilities for tables.  Tag a <th> and the matching <td>s in
   every row with one of these to drop that column on small screens.  Outside
   the media queries the classes carry no rule, so applying them in markup can
   never change the desktop layout. */
@media (max-width: 1024px) { .col-hide-tablet { display: none; } }
@media (max-width: 640px)  { .col-hide-phone  { display: none; } }

/* Horizontal-scroll wrapper for dense, desktop-first tables (admin runner /
   audit log).  Width-agnostic: no scrollbar at desktop when the table fits;
   on a narrow screen it confines the overflow to the table instead of letting
   it push the whole page wider. */
.table-scroll { overflow-x: auto; }

/* Filter/search inputs keep their authored desktop width via the
   --filter-width custom property (so desktop is unchanged) and span the full
   row on phones. */
.filter-input { width: var(--filter-width, 16rem); max-width: 100%; }

@media (max-width: 640px) {
    /* Let the top nav wrap onto multiple lines instead of overflowing the
       viewport; the account/username link sits inline rather than being
       pushed to the far right. */
    .nav { flex-wrap: wrap; row-gap: .35rem; column-gap: 1.1rem; }
    .nav-user { margin-left: 0; }

    /* Allow long assignment titles to wrap inside their flex cell rather than
       forcing the table (and page) wider than the screen. */
    .assignment-title-cell { min-width: 0; }

    /* Comfortable tap targets for the icon/action buttons. */
    .action-btn { min-height: 2.4rem; }

    /* Filter/search inputs span the row. */
    .filter-input { width: 100%; }

    /* iOS Safari auto-zooms any focused input under 16px; keep phone inputs
       at 1rem so the extension/grade-override flow doesn't zoom-and-pan. */
    .form-input { font-size: 1rem; }

    /* The publish popover is absolutely positioned from an Actions cell;
       its desktop floor would clip off a phone viewport. */
    .publish-form { min-width: 0; }
}
