/* ═══════════════════════════════════════════════════════════════
   TeachKit — Global Styles
   CSS Custom Properties + BEM naming + rem units
   Mobile-first responsive design

   Breakpoints (min-width media queries):
     480px  — sm  (larger phones, landscape)
     768px  — md  (tablets)
     1024px — lg  (desktops — sidebar becomes fixed)
     1280px — xl  (wide desktops)
   ═══════════════════════════════════════════════════════════════ */

/* ── Design Tokens ──────────────────────────────────────────── */

:root {
    /* Colours — Primary */
    --color-primary-50:  #eff6ff;
    --color-primary-100: #dbeafe;
    --color-primary-200: #bfdbfe;
    --color-primary-300: #93c5fd;
    --color-primary-400: #60a5fa;
    --color-primary-500: #3b82f6;
    --color-primary-600: #2563eb;
    --color-primary-700: #1d4ed8;
    --color-primary-800: #1e40af;
    --color-primary-900: #1e3a8a;

    /* Colours — Neutral */
    --color-gray-50:  #f9fafb;
    --color-gray-100: #f3f4f6;
    --color-gray-200: #e5e7eb;
    --color-gray-300: #d1d5db;
    --color-gray-400: #9ca3af;
    --color-gray-500: #6b7280;
    --color-gray-600: #4b5563;
    --color-gray-700: #374151;
    --color-gray-800: #1f2937;
    --color-gray-900: #111827;

    /* Colours — Semantic */
    --color-success: #059669;
    --color-success-bg: #ecfdf5;
    --color-success-strong: #15803d;
    --color-error: #dc2626;
    --color-error-bg: #fef2f2;
    --color-error-strong: #b91c1c;
    --color-warning: #d97706;
    --color-warning-bg: #fffbeb;
    --color-warning-strong: #b45309;
    --color-info: #2563eb;
    --color-info-bg: #eff6ff;

    /* Colours — Surface tokens (semantic, theme-aware)
       Page background is intentionally a slightly cool, deeper tone
       than gray-50 so white cards have visible separation on cheap
       displays. The chromatic delta (cool tint) matters as much as
       the luminance delta — gamma-crushed panels read tints better
       than near-equal greys.
       Dark counterparts live in the @media block below — every rule
       that uses these tokens flips for free. */
    --color-bg-page: #eef2f7;
    --color-surface: #fff;
    --color-surface-border: var(--color-gray-300);
    --color-text-body: var(--color-gray-800);
    --color-text-strong: var(--color-gray-900);
    --color-text-muted: var(--color-gray-600);
    --color-input-bg: #fff;
    --color-input-border: var(--color-gray-300);
    /* Hover background for neutral surfaces — sidebar links, ghost
       buttons, table rows, dropdown items, close buttons, etc. Not
       for tinted buttons (.btn--primary uses --color-primary-700) or
       tinted-state hovers (filter tabs use --color-gray-200 directly
       to step up from a primary-100 active background). */
    --color-surface-hover: var(--color-gray-100);

    /* Link colours — used by the global a / a:hover rules. Body links
       in prose (legal pages, descriptions) flow through these so they
       can flip to a lighter primary shade in dark mode.
       Light: primary-700 (#1d4ed8) — ~5.9:1 on the cool page-bg, AA
       solid. primary-600 was tried first but only hit ~4.2:1 on the
       page-bg (just under AA for normal text).
       Hover bumps to primary-800 for a noticeable but tasteful step.
       Buttons styled as <a> must override .btn--*:hover { color: ... }
       to avoid inheriting these on hover (specificity quirk: a:hover
       (0,1,1) beats a bare .btn-- class (0,1,0)). */
    --color-link: var(--color-primary-700);
    --color-link-hover: var(--color-primary-800);

    /* Typography */
    --font-sans: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
    --font-mono: 'Cascadia Code', 'Fira Code', 'JetBrains Mono', monospace;
    --text-xs:   0.75rem;
    --text-sm:   0.875rem;
    --text-base: 1rem;
    --text-lg:   1.125rem;
    --text-xl:   1.25rem;
    --text-2xl:  1.5rem;
    --text-3xl:  1.875rem;
    --line-height: 1.6;

    /* Spacing */
    --space-1:  0.25rem;
    --space-2:  0.5rem;
    --space-3:  0.75rem;
    --space-4:  1rem;
    --space-5:  1.25rem;
    --space-6:  1.5rem;
    --space-8:  2rem;
    --space-10: 2.5rem;
    --space-12: 3rem;
    --space-16: 4rem;

    /* Layout */
    --sidebar-width: 14rem;
    --header-height: 3.5rem;
    --content-max-width: 72rem;
    --border-radius: 0.375rem;
    --border-radius-lg: 0.5rem;

    /* Shadows */
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
    --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1);
    --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);

    /* Transitions */
    --transition-fast: 150ms ease;
    --transition-base: 200ms ease;
}


/* ── Dark mode token overrides ────────────────────────────────
   OS-driven only (prefers-color-scheme: dark). No manual toggle.
   Every rule that uses the surface/text/semantic tokens above
   flips automatically. Rules that still reference raw --color-gray-*
   or hardcoded #fff need to be tokenised one by one — see the
   sitewide audit in PROJECT_PLAN.md "Future: Dark Mode".
   The IDEs (.ide and .web-ide) maintain their OWN scoped token
   systems — see python.css and web-ide.css. Don't put IDE chrome
   colours in here. */

@media (prefers-color-scheme: dark) {
    :root {
        /* Surface tokens — page is deep slate, cards step up one tone
           (slate-800), border is slate-600 for clearly visible edges
           (was slate-700 — too subtle on the slate-800 cards, the
           top/right/bottom edges of cards-on-cards disappeared). */
        --color-bg-page: #0f172a;
        --color-surface: #1e293b;
        --color-surface-border: #475569;

        /* Text — slate-200 body, slate-100 strong, slate-400 muted.
           Body on surface ≈ 12:1 (AAA). Muted on surface ≈ 6.4:1 (AA). */
        --color-text-body: #e2e8f0;
        --color-text-strong: #f1f5f9;
        --color-text-muted: #94a3b8;

        /* Form inputs sit on the page bg, not on cards, so they
           need a slightly different tone from surface for a visible
           edge. slate-700 input on slate-800 card on slate-900 page. */
        --color-input-bg: #0f172a;
        --color-input-border: #475569;

        /* Hover surface — slate-700 reads as "elevated" against the
           slate-800 surface but a step below slate-600 borders, so a
           hovered bordered card has a clear hierarchy: bg slate-800,
           border slate-600, hover-fill slate-700. */
        --color-surface-hover: #334155;

        /* Link colours flip to lighter primary shades. primary-600 on
           slate-800 is ~2.8:1 (fails AA); primary-400 sits at ~6:1
           (passes AA). Hover goes a step lighter (primary-300, ~8:1). */
        --color-link: var(--color-primary-400);
        --color-link-hover: var(--color-primary-300);

        /* Strong semantic colours — original light-mode values are
           dark text shades that disappear on dark backgrounds. Flip
           to the matching -400 variants which sit clearly on dark. */
        --color-warning-strong: #fbbf24;
        --color-success-strong: #4ade80;
        --color-error-strong: #f87171;

        /* Semantic background tints — sit slightly LIGHTER than the
           slate-800 card surface so badges read as "elevated pills"
           rather than recessed dark spots. Earlier values
           (#052e2b etc.) were darker than slate-800, which made the
           Active / Paused pills disappear into the card. Each tint
           is now ~2× the luminance of slate-800; semantic -strong
           text tokens still hit AA on top (success ~6.7:1, warning
           ~7.5:1, etc.). */
        --color-success-bg: #0d3d2a;
        --color-error-bg:   #3d1717;
        --color-warning-bg: #3d2810;
        --color-info-bg:    #152d50;

        /* Shadows — black shadows on dark backgrounds disappear.
           Heavier opacity + larger blur preserves elevation. */
        --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
        --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.5),
                     0 2px 4px -2px rgba(0, 0, 0, 0.4);
        --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.5),
                     0 4px 6px -4px rgba(0, 0, 0, 0.4);
    }
}


/* ── Reduced Motion ────────────────────────────────────────── */
/* Disable all transitions and animations when user prefers    */

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}


/* ── Reset ──────────────────────────────────────────────────── */

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

html {
    font-size: 100%;
    -webkit-text-size-adjust: 100%;
}

body {
    font-family: var(--font-sans);
    font-size: var(--text-base);
    line-height: var(--line-height);
    color: var(--color-text-body);
    background-color: var(--color-bg-page);
    min-height: 100vh;
    overflow-x: hidden;
}

img {
    display: block;
    max-width: 100%;
}

a {
    color: var(--color-link);
    text-decoration: none;
}

a:hover {
    color: var(--color-link-hover);
    text-decoration: underline;
}


/* ── Skip Navigation ──────────────────────────────────────── */

.skip-nav {
    position: absolute;
    top: -100%;
    left: var(--space-4);
    z-index: 999;
    padding: var(--space-2) var(--space-4);
    background-color: var(--color-primary-600);
    color: #fff;
    font-size: var(--text-sm);
    font-weight: 500;
    border-radius: var(--border-radius);
    text-decoration: none;
}

.skip-nav:focus {
    top: var(--space-2);
    color: #fff;
    text-decoration: none;
}


/* ── Impersonation Banner ─────────────────────────────────── */
/* Sticky top warning banner shown when a super_admin is "viewing as"
   a teacher. Bright amber so it can never be missed. */

.impersonation-banner {
    position: sticky;
    top: 0;
    z-index: 200;
    width: 100%;
    background: #fef3c7;
    color: #78350f;
    border-bottom: 2px solid #d97706;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
}

.impersonation-banner__inner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    max-width: 90rem;
    margin: 0 auto;
    padding: var(--space-2) var(--space-4);
    font-size: 0.9375rem;
    font-weight: 500;
}

.impersonation-banner__icon {
    font-size: 1.125rem;
    line-height: 1;
}

.impersonation-banner__text {
    flex: 1 1 auto;
    min-width: 12rem;
}

.impersonation-banner__text strong {
    font-weight: 700;
}

.impersonation-banner__form {
    margin: 0;
    flex: 0 0 auto;
}

.impersonation-banner__stop {
    background: #b45309;
    color: #fff;
    border: 1px solid #92400e;
    padding: 0.375rem 0.875rem;
    border-radius: var(--border-radius);
    font-size: 0.8125rem;
    font-weight: 600;
    cursor: pointer;
    min-height: 2.25rem;
}

.impersonation-banner__stop:hover,
.impersonation-banner__stop:focus-visible {
    background: #92400e;
}


/* ── Global Focus Indicators ──────────────────────────────── */
/* Visible focus ring on all interactive elements via :focus-visible.
   Individual components may override with their own styles (e.g.
   form inputs use border-color + box-shadow instead). */

:focus-visible {
    outline: 2px solid var(--color-primary-500);
    outline-offset: 2px;
}

/* Components that provide their own visible focus style */
.form-input:focus-visible,
.form-select:focus-visible,
.form-textarea:focus-visible,
.file-input__native:focus + .file-input__trigger {
    outline: none;
}


/* ── Header ─────────────────────────────────────────────────── */

.header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: var(--header-height);
    padding: 0 var(--space-4);
    background-color: var(--color-surface);
    border-bottom: 1px solid var(--color-surface-border);
    position: sticky;
    top: 0;
    z-index: 100;
}

@media (min-width: 1024px) {
    .header {
        padding: 0 var(--space-6);
    }
}

.header__left {
    display: flex;
    align-items: center;
    gap: var(--space-3);
}

.header__brand {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-size: var(--text-lg);
    font-weight: 700;
    color: var(--color-text-strong);
    text-decoration: none;
}

.header__brand:hover {
    text-decoration: none;
    /* Keep the brand at its strong colour on hover — the previous
       primary-700 swap turned the wordmark blue, which read as a
       link state rather than a brand. */
    color: var(--color-text-strong);
}

.header__brand-icon {
    width: 24px;
    height: 24px;
    flex-shrink: 0;
}

/* The toolbox icon is a dark PNG over a light/white background.
   Flip to pure white in dark mode by zeroing all colour and inverting.
   Same recipe used for .public-header__brand-icon below. */
@media (prefers-color-scheme: dark) {
    .header__brand-icon {
        filter: brightness(0) invert(1);
    }
}

.header__right {
    display: flex;
    align-items: baseline;
    gap: var(--space-3);
}

.header__user {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
    color: var(--color-text-muted);
}

.header__avatar {
    width: 1.75rem;
    height: 1.75rem;
    border-radius: 50%;
}

.header__name {
    font-weight: 500;
    display: none;
}

@media (min-width: 480px) {
    .header__name {
        display: inline;
    }
}

.header__logout-form {
    display: inline;
}

.header__logout-form button[type="submit"] {
    font-size: var(--text-sm);
}

/* ── Hamburger Button ──────────────────────────────────────── */

.header__hamburger {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.75rem;
    height: 2.75rem;
    padding: 0;
    background: none;
    border: none;
    cursor: pointer;
    color: var(--color-text-muted);
    border-radius: var(--border-radius);
    -webkit-tap-highlight-color: transparent;
}

.header__hamburger:hover {
    background-color: var(--color-surface-hover);
    color: var(--color-text-body);
}

.header__hamburger svg {
    width: 1.5rem;
    height: 1.5rem;
}

@media (min-width: 1024px) {
    .header__hamburger {
        display: none;
    }
}


/* ── Layout ─────────────────────────────────────────────────── */

.layout {
    display: flex;
    min-height: calc(100vh - var(--header-height));
}

.layout--no-sidebar {
    display: block;
}

/* Inline primary nav for the student layout — sits inside .header__left
   next to the brand. Replaces the older standalone .student-nav row
   that lived below the header so the top-of-page chrome is one bar. */
.header__nav {
    display: flex;
    gap: var(--space-1);
    margin-left: var(--space-2);
}

.header__nav-link {
    padding: var(--space-1) var(--space-3);
    border-radius: var(--border-radius);
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--color-text-muted);
    text-decoration: none;
    min-height: 2.75rem;
    display: flex;
    align-items: center;
}

.header__nav-link:hover {
    background: var(--color-surface-hover);
    color: var(--color-text-body);
    text-decoration: none;
}


.content {
    flex: 1;
    padding: var(--space-4);
    max-width: var(--content-max-width);
    width: 100%;
    min-width: 0;
}

/* IDE pages: let the editor use the full viewport width. The 72rem
   cap makes sense for text-heavy pages but wastes space on large
   monitors when the tool is a full-bleed editor. */
.content:has(> .ide),
.content:has(> .web-ide) {
    max-width: none;
}

@media (min-width: 768px) {
    .content {
        padding: var(--space-6);
    }
}

@media (min-width: 1024px) {
    .content {
        padding: var(--space-8);
    }
}


/* ── Sidebar ────────────────────────────────────────────────── */

/* Mobile: off-canvas overlay */
.sidebar {
    position: fixed;
    top: 0;
    left: 0;
    width: min(var(--sidebar-width), 80vw);
    height: 100vh;
    padding: var(--space-4) 0;
    background-color: var(--color-surface);
    border-right: 1px solid var(--color-surface-border);
    flex-shrink: 0;
    z-index: 200;
    transform: translateX(-100%);
    transition: transform var(--transition-base);
    overflow-y: auto;
}

.sidebar.is-open {
    transform: translateX(0);
}

.sidebar__close {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.75rem;
    height: 2.75rem;
    padding: 0;
    margin: 0 var(--space-3) var(--space-2) auto;
    background: none;
    border: none;
    cursor: pointer;
    color: var(--color-text-muted);
    border-radius: var(--border-radius);
    -webkit-tap-highlight-color: transparent;
}

.sidebar__close:hover {
    background-color: var(--color-surface-hover);
    color: var(--color-text-body);
}

.sidebar__close svg {
    width: 1.25rem;
    height: 1.25rem;
}

/* Overlay backdrop */
.sidebar-overlay {
    display: none;
    position: fixed;
    inset: 0;
    background-color: rgba(0, 0, 0, 0.3);
    z-index: 199;
}

.sidebar-overlay.is-visible {
    display: block;
}

/* Desktop: sticky sidebar */
@media (min-width: 1024px) {
    .sidebar {
        position: sticky;
        top: var(--header-height);
        width: var(--sidebar-width);
        height: calc(100vh - var(--header-height));
        transform: none;
        transition: none;
        z-index: auto;
        overflow-y: auto;
    }

    .sidebar__close {
        display: none;
    }

    .sidebar-overlay {
        display: none !important;
    }
}

.sidebar__nav {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding: 0 var(--space-3);
}

.sidebar__link {
    display: block;
    padding: var(--space-3) var(--space-3);
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--color-text-muted);
    border-radius: var(--border-radius);
    text-decoration: none;
    transition: background-color var(--transition-fast), color var(--transition-fast);
    min-height: 2.75rem;
    line-height: 2.75rem;
    padding-top: 0;
    padding-bottom: 0;
}

@media (min-width: 1024px) {
    .sidebar__link {
        padding: var(--space-2) var(--space-3);
        min-height: auto;
        line-height: inherit;
    }
}

.sidebar__link:hover {
    background-color: var(--color-surface-hover);
    color: var(--color-text-strong);
    text-decoration: none;
}

.sidebar__link--active {
    background-color: var(--color-primary-50);
    color: var(--color-primary-700);
}

/* Active state for dark mode — primary-50 (#eff6ff) and primary-700
   (#1d4ed8) are both wrong-direction for dark surfaces. Flip to
   primary-900 bg + primary-300 text — dark navy tile with light
   blue text reads as "selected" against the slate-800 sidebar. */
@media (prefers-color-scheme: dark) {
    .sidebar__link--active {
        background-color: var(--color-primary-900);
        color: var(--color-primary-300);
    }
}

.sidebar__link--sub {
    padding-left: var(--space-6);
    font-size: var(--text-xs);
    color: var(--color-text-muted);
}

.sidebar__divider {
    border: none;
    border-top: 1px solid var(--color-surface-border);
    margin: var(--space-3) 0;
}


/* ── Flash Messages ─────────────────────────────────────────── */

.flash {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--space-3) var(--space-4);
    border-radius: var(--border-radius);
    margin-bottom: var(--space-4);
    font-size: var(--text-sm);
    font-weight: 500;
    animation: flash-in 0.3s ease;
}

.flash--success {
    background-color: var(--color-success-bg);
    color: var(--color-success);
    border: 1px solid #a7f3d0;
}

.flash--error {
    background-color: var(--color-error-bg);
    color: var(--color-error);
    border: 1px solid #fecaca;
}

.flash--warning {
    background-color: var(--color-warning-bg);
    color: var(--color-warning);
    border: 1px solid #fde68a;
}

.flash--info {
    background-color: var(--color-info-bg);
    color: var(--color-info);
    border: 1px solid #bfdbfe;
}

.flash__close {
    background: none;
    border: none;
    font-size: var(--text-lg);
    cursor: pointer;
    color: inherit;
    opacity: 0.6;
    padding: var(--space-2);
    line-height: 1;
    min-width: 2.75rem;
    min-height: 2.75rem;
    display: flex;
    align-items: center;
    justify-content: center;
}

.flash__close:hover {
    opacity: 1;
}

@keyframes flash-in {
    from { opacity: 0; transform: translateY(-0.5rem); }
    to   { opacity: 1; transform: translateY(0); }
}


/* ── Session-Expired Banner ────────────────────────────────── */

.session-banner {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 9999;
    background-color: var(--color-warning);
    color: #fff;
    padding: var(--space-3) var(--space-4);
    text-align: center;
    font-size: var(--text-sm);
    font-weight: 500;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}

.session-banner__link {
    color: #fff;
    text-decoration: underline;
    font-weight: 600;
    margin-left: var(--space-2);
}

.session-banner__link:hover {
    opacity: 0.9;
}


/* ── Buttons ────────────────────────────────────────────────── *
 *
 * Style guide:
 *
 *   .btn--primary       Blue solid   — THE main action per page/section.
 *                                      "Create Class", "Save", "Import".
 *   .btn--secondary     White + gray — Supporting/neutral actions.
 *                        border        "Edit", "Cancel", "View Archived",
 *                                      "Active Classes".
 *   .btn--danger        Red solid    — Irreversible destructive action.
 *                                      "Delete permanently".
 *   .btn--danger-outline Red text +  — Soft-destructive / reversible.
 *                        red border    "Archive", "Remove from class".
 *   .btn--ghost         No border/bg — Minimal emphasis, inline actions.
 *                                      "Log out", table row actions.
 *
 * Sizing:
 *   Default (.btn)      — Standard size, use for page-level actions.
 *   .btn--sm            — Compact, use inside tables, cards, inline.
 *
 * Rule: buttons side-by-side in .page-header__actions must all be
 * the same size (no mixing default + --sm).
 *
 * ────────────────────────────────────────────────────────────── */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-4);
    font-family: var(--font-sans);
    font-size: var(--text-sm);
    font-weight: 500;
    line-height: 1.5;
    border: 1px solid transparent;
    border-radius: var(--border-radius);
    cursor: pointer;
    text-decoration: none;
    min-height: 2.75rem;
    transition: background-color var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast);
    -webkit-tap-highlight-color: transparent;
}

.btn:hover {
    text-decoration: none;
}

/* Primary — main action (blue solid) */
.btn--primary {
    background-color: var(--color-primary-600);
    color: #fff;
}

.btn--primary:hover {
    background-color: var(--color-primary-700);
    color: #fff;
}

/* Secondary — neutral supporting action (white + gray border).
   Subtle box-shadow gives the button presence even when the border
   is low-contrast (slate-600 on slate-800 in dark, gray-300 on
   white in light). Hover shadow lifts the affordance further. */
.btn--secondary {
    background-color: var(--color-surface);
    color: var(--color-text-body);
    border-color: var(--color-surface-border);
    box-shadow: 0 1px 1px rgba(15, 23, 42, 0.04);
}

.btn--secondary:hover {
    background-color: var(--color-surface-hover);
    /* Explicit color: needed because a:hover wins on specificity
       (0,1,1) when .btn--secondary is applied to an <a>. Without
       this the text turns link-blue on hover. */
    color: var(--color-text-body);
    box-shadow: 0 2px 6px rgba(15, 23, 42, 0.10);
    border-color: var(--color-input-border);
}

@media (prefers-color-scheme: dark) {
    .btn--secondary {
        box-shadow: 0 1px 2px rgba(0, 0, 0, 0.30);
    }

    .btn--secondary:hover {
        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.45);
        /* Stronger border on hover for darker surfaces — slate-500 on
           slate-700 hover bg reads clearly. */
        border-color: #64748b;
    }
}

/* Danger — irreversible destructive action (red solid) */
.btn--danger {
    background-color: var(--color-error);
    color: #fff;
}

.btn--danger:hover {
    background-color: #b91c1c;
    /* Same a:hover specificity workaround as .btn--secondary:hover. */
    color: #fff;
}

/* Danger outline — reversible destructive action (red text + border) */
.btn--danger-outline {
    background-color: var(--color-surface);
    color: var(--color-error);
    border-color: var(--color-error);
}

.btn--danger-outline:hover {
    background-color: var(--color-error-bg);
    color: #b91c1c;
    border-color: #b91c1c;
}

/* Ghost — minimal emphasis, inline (no border/bg) */
.btn--ghost {
    background: none;
    color: var(--color-text-muted);
    border: none;
}

.btn--ghost:hover {
    background-color: var(--color-surface-hover);
    color: var(--color-text-body);
}

/* Small variant — for tables, cards, inline use */
.btn--sm {
    padding: var(--space-1) var(--space-3);
    font-size: var(--text-xs);
    min-height: 2.25rem;
}


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

.form-group {
    margin-bottom: var(--space-4);
}

.form-label {
    display: block;
    margin-bottom: var(--space-1);
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--color-text-body);
}

.form-input,
.form-select,
.form-textarea {
    display: block;
    width: 100%;
    padding: var(--space-2) var(--space-3);
    font-family: var(--font-sans);
    font-size: var(--text-base);
    color: var(--color-text-body);
    background-color: var(--color-input-bg);
    border: 1px solid var(--color-input-border);
    border-radius: var(--border-radius);
    min-height: 2.75rem;
    transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}

/* Placeholder text — browsers default to a very dim, low-contrast
   shade that's especially hard to read on the dark input bg. Route
   through --color-text-muted (gray-600 light, slate-400 dark) so
   placeholders are readable but visibly distinct from typed text in
   both modes. */
input::placeholder,
textarea::placeholder {
    color: var(--color-text-muted);
    opacity: 1;
}

.form-textarea--code {
    font-family: var(--font-mono);
    tab-size: 4;
    white-space: pre;
    overflow-x: auto;
}

/* On desktop, inputs can be smaller */
@media (min-width: 768px) {
    .form-input,
    .form-select,
    .form-textarea {
        font-size: var(--text-sm);
    }
}

.form-input:focus,
.form-select:focus,
.form-textarea:focus {
    outline: none;
    border-color: var(--color-primary-500);
    box-shadow: 0 0 0 3px var(--color-primary-100);
}

.form-input--error {
    border-color: var(--color-error);
}

.form-error {
    margin-top: var(--space-1);
    font-size: var(--text-xs);
    color: var(--color-error);
}

.form-hint {
    margin-top: var(--space-1);
}

.form-textarea {
    resize: vertical;
    min-height: 6rem;
}

/* ── File Input (custom styled) ────────────────────────────── */

.file-input {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
}

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

.file-input__trigger {
    cursor: pointer;
    flex-shrink: 0;
}

.file-input__name {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Focus ring on the styled trigger when native input is focused */
.file-input__native:focus + .file-input__trigger {
    outline: none;
    border-color: var(--color-primary-500);
    box-shadow: 0 0 0 3px var(--color-primary-100);
}


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

.card {
    background-color: var(--color-surface);
    border: 1px solid var(--color-surface-border);
    border-radius: var(--border-radius-lg);
    padding: var(--space-4);
    box-shadow: 0 1px 3px rgba(15, 23, 42, 0.08), 0 1px 2px rgba(15, 23, 42, 0.04);
}

.card + .card {
    margin-top: var(--space-6);
}

/* Inside a grid, the container's `gap` handles spacing between
   cards. Without this override, .card + .card adds top margin to
   every card after the first, which (with align-items: stretch)
   shrinks those cards by exactly that margin and makes them look
   shorter than the first card. Vertical-stack spacing on regular
   pages is unaffected. */
.class-grid > .card + .card,
.school-grid > .card + .card {
    margin-top: 0;
}

@media (min-width: 768px) {
    .card {
        padding: var(--space-6);
    }
}

.card__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: var(--space-4);
    gap: var(--space-3);
    flex-wrap: wrap;
}

.card__title {
    font-size: var(--text-lg);
    font-weight: 600;
    color: var(--color-text-strong);
}

.card__header-actions {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
}


/* ── Auth Container ─────────────────────────────────────────── */

.auth-container {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    padding: var(--space-4);
}

.auth-footer {
    margin-top: var(--space-6);
    color: var(--color-text-muted);
    font-size: 0.8125rem;
    text-align: center;
}

.auth-footer a {
    color: var(--color-text-muted);
    text-decoration: none;
    margin: 0 var(--space-2);
}

.auth-footer a:hover {
    /* Use the link-hover token (primary-700 light, primary-300 dark)
       so contrast on the page-bg passes AA in both modes. The plain
       primary-600 only hits ~4.3:1 on the cool light page-bg. */
    color: var(--color-link-hover);
    text-decoration: underline;
}


/* ── Error Pages ────────────────────────────────────────────── */

.error-page {
    text-align: center;
    padding: var(--space-16) var(--space-4);
}

.error-page__code {
    font-size: 4rem;
    font-weight: 800;
    /* Was --color-gray-200 — gave ~1.1:1 contrast on the cool page-bg
       in light mode (totally invisible) but ~12:1 in dark (over-loud).
       --color-text-muted gives ~6:1 in both modes — strong AA for the
       large heading, AAA for ≥3:1 large-text rule. */
    color: var(--color-text-muted);
    line-height: 1;
    margin-bottom: var(--space-4);
}

@media (min-width: 768px) {
    .error-page__code {
        font-size: 6rem;
    }
}

.error-page__message {
    font-size: var(--text-lg);
    color: var(--color-text-muted);
    margin-bottom: var(--space-8);
}


/* ── Tables ─────────────────────────────────────────────────── */

.table-wrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    background-color: var(--color-surface);
    border: 1px solid var(--color-surface-border);
    border-radius: var(--border-radius-lg);
    box-shadow: 0 1px 3px rgba(15, 23, 42, 0.08), 0 1px 2px rgba(15, 23, 42, 0.04);
}

.table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--text-sm);
}

.table th,
.table td {
    padding: var(--space-3) var(--space-3);
    text-align: left;
    border-bottom: 1px solid var(--color-surface-border);
    white-space: nowrap;
}

@media (min-width: 768px) {
    .table th,
    .table td {
        padding: var(--space-3) var(--space-4);
        white-space: normal;
    }
}

.table th {
    font-weight: 600;
    color: var(--color-text-muted);
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    /* Header strip uses page-bg as a tint — slightly receded from
       the surface in both modes (light: cool slate vs white card,
       dark: slate-900 vs slate-800 card). */
    background-color: var(--color-bg-page);
}

.table tbody tr:hover {
    background-color: var(--color-surface-hover);
}

/* Details table (key-value) — no wrapping issues */
.table--details th,
.table--details td {
    white-space: normal;
}


/* ── Filter Tabs ──────────────────────────────────────────── */

.filter-tabs {
    display: flex;
    gap: var(--space-1);
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

.filter-tab {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-2) var(--space-4);
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--color-text-muted);
    text-decoration: none;
    border: none;
    background: none;
    cursor: pointer;
    font-family: inherit;
    border-radius: var(--border-radius);
    white-space: nowrap;
    min-height: 2.75rem;
    -webkit-tap-highlight-color: transparent;
}

/* Hover bumped one step beyond --color-surface-hover (gray-100/
   slate-700) — that token is tuned for surfaces that already have a
   container border (sidebar links, table rows). Filter tabs sit
   borderless on the page-bg, so the gray-100 lift was barely visible
   on the cool slate page-bg. gray-200/slate-600 gives a clearly
   readable hover state without colliding with the primary-tinted
   active state below. Adding a thin ring keeps the affordance
   visible even when the tab is over a busy background. */
.filter-tab:hover {
    background-color: var(--color-gray-200);
    color: var(--color-text-strong);
    text-decoration: none;
    box-shadow: inset 0 0 0 1px var(--color-surface-border);
}

@media (prefers-color-scheme: dark) {
    .filter-tab:hover {
        background-color: var(--color-gray-700);
    }
}

.filter-tab--active {
    background-color: var(--color-primary-100);
    color: var(--color-primary-800);
}

/* Active state in dark — primary-100 (light blue) and primary-800
   (dark blue) both wrong-direction for the slate sidebar/page surface.
   Flip to primary-900 + primary-300 (same recipe as sidebar-active). */
@media (prefers-color-scheme: dark) {
    .filter-tab--active {
        background-color: var(--color-primary-900);
        color: var(--color-primary-300);
    }
}

/* When the active tab is hovered, drop the neutral hover ring — the
   tinted fill is already an unmistakable signal and the ring would
   add visual noise. */
.filter-tab--active:hover {
    box-shadow: none;
    background-color: var(--color-primary-100);
    color: var(--color-primary-800);
}

@media (prefers-color-scheme: dark) {
    .filter-tab--active:hover {
        background-color: var(--color-primary-900);
        color: var(--color-primary-300);
    }
}


/* ── Utilities ──────────────────────────────────────────────── */

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

.text-sm {
    font-size: var(--text-sm);
}

.text-xs {
    font-size: var(--text-xs);
}

.mt-4 { margin-top: var(--space-4); }
.mt-6 { margin-top: var(--space-6); }
.mb-2 { margin-bottom: var(--space-2); }
.mb-4 { margin-bottom: var(--space-4); }
.mb-6 { margin-bottom: var(--space-6); }

.flex {
    display: flex;
}

.items-center {
    align-items: center;
}

.justify-between {
    justify-content: space-between;
}

.gap-2 { gap: var(--space-2); }
.gap-4 { gap: var(--space-4); }

/* Hide on mobile, show on desktop */
.hidden-mobile {
    display: none;
}

@media (min-width: 768px) {
    .hidden-mobile {
        display: revert;
    }
}


/* ── Login Card ─────────────────────────────────────────────── */

.login-card {
    width: 100%;
    max-width: 24rem;
    text-align: center;
}

.login-card--wide {
    max-width: 28rem;
}

.code-entry__section {
    text-align: left;
}

.code-entry__section + .code-entry__section {
    margin-top: 0;
}

.code-entry__heading {
    font-size: var(--text-base);
    font-weight: 600;
    margin: 0 0 var(--space-1) 0;
}

.code-entry__hint {
    margin: 0 0 var(--space-3) 0;
}

.code-entry__divider {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin: var(--space-5) 0;
    color: var(--color-text-muted);
    font-size: var(--text-sm);
}

.code-entry__divider::before,
.code-entry__divider::after {
    content: '';
    flex: 1;
    height: 1px;
    background: var(--color-surface-border);
}

.domain-list {
    list-style: none;
    padding: 0;
    margin: 0 0 var(--space-3) 0;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.domain-list code {
    display: inline-block;
    padding: var(--space-1) var(--space-2);
    background: var(--color-surface-hover);
    border-radius: var(--border-radius);
    font-size: var(--text-sm);
    color: var(--color-text-body);
}

.login-card__header {
    margin-bottom: var(--space-6);
}

.login-card__title {
    font-size: var(--text-2xl);
    font-weight: 700;
    /* "TeachKit" wordmark — not a link, so it stays at strong text
       colour rather than the brand blue. Auto-flips to slate-100 in
       dark mode for a clean white wordmark on the dark surface. */
    color: var(--color-text-strong);
    margin-bottom: var(--space-2);
}

.login-card__subtitle {
    font-size: var(--text-sm);
}

.login-card__dev {
    margin-top: var(--space-6);
    padding-top: var(--space-4);
    border-top: 1px solid var(--color-surface-border);
}

.login-card__dev-links {
    display: flex;
    gap: var(--space-2);
    justify-content: center;
    margin-top: var(--space-3);
}

.btn--google {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-3);
    width: 100%;
    padding: var(--space-3) var(--space-4);
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--color-text-body);
    background-color: var(--color-surface);
    border: 1px solid var(--color-input-border);
    border-radius: var(--border-radius);
    text-decoration: none;
    cursor: pointer;
    min-height: 2.75rem;
    transition: background-color var(--transition-fast), box-shadow var(--transition-fast);
}

.btn--google:hover {
    background-color: var(--color-surface-hover);
    box-shadow: var(--shadow-sm);
    text-decoration: none;
    color: var(--color-text-body);
}

.btn__icon {
    flex-shrink: 0;
}

.btn--full {
    width: 100%;
}

/* Join code text input — large, centered, monospace for easy reading */
.join-code-input {
    font-family: 'Courier New', Courier, monospace;
    font-size: var(--text-2xl);
    font-weight: 700;
    letter-spacing: 0.25em;
    text-align: center;
    text-transform: uppercase;
}

.form-hint {
    margin-top: var(--space-1);
}

/* Class Teachers Panel (shared classes) */
.teacher-list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
}

.teacher-card {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border: 1px solid var(--color-gray-200);
    border-radius: var(--radius-md);
    background: var(--color-white);
    min-width: 14rem;
}

.teacher-card__avatar {
    width: 2.25rem;
    height: 2.25rem;
    border-radius: 50%;
    background: var(--color-primary-100);
    color: var(--color-primary-700);
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    text-transform: uppercase;
}

.teacher-card__body {
    min-width: 0;
}

.teacher-card__name {
    font-weight: 600;
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.teacher-card__email {
    color: var(--color-text-muted);
    font-size: var(--text-sm);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.add-teacher-panel {
    margin-bottom: var(--space-4);
    padding: var(--space-4);
    border: 1px dashed var(--color-input-border);
    border-radius: var(--radius-md);
}

.teacher-search-results {
    list-style: none;
    margin: var(--space-2) 0 0;
    padding: 0;
    max-height: 16rem;
    overflow-y: auto;
}

.teacher-search-results__item {
    border-bottom: 1px solid var(--color-surface-border);
}

.teacher-search-results__item:last-child {
    border-bottom: none;
}

.teacher-search-results__btn {
    width: 100%;
    text-align: left;
    background: none;
    border: none;
    padding: var(--space-2) var(--space-3);
    cursor: pointer;
    border-radius: var(--radius-sm);
    color: var(--color-text-body);
}

.teacher-search-results__btn:hover {
    background: var(--color-surface-hover);
}

/* Class Code Panel (class detail page) */
.class-code-panel {
    margin-bottom: var(--space-6);
    padding: var(--space-4);
}

.class-code-panel__body {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    flex-wrap: wrap;
}

.class-code-panel__code {
    font-family: 'Courier New', Courier, monospace;
    font-size: var(--text-3xl);
    font-weight: 700;
    letter-spacing: 0.3em;
    color: var(--color-primary-700);
}

@media (prefers-color-scheme: dark) {
    .class-code-panel__code {
        /* primary-700 is the dark blue used in light mode; in dark
           it's invisible on the slate surface. Bump to primary-300
           for clear readability of the generated code. */
        color: var(--color-primary-300);
    }
}

.class-code-panel__actions {
    display: flex;
    gap: var(--space-2);
}

.class-code-panel__timer {
    margin-top: var(--space-2);
}

/* Class Code Fullscreen overlay — for showing the code to a whole class */
.class-code-fullscreen {
    position: fixed;
    inset: 0;
    z-index: 200;
    background: var(--color-surface);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: var(--space-6);
    text-align: center;
}

.class-code-fullscreen[hidden] {
    display: none;
}

.class-code-fullscreen__close {
    position: absolute;
    top: var(--space-4);
    right: var(--space-4);
    background: transparent;
    border: 1px solid var(--color-surface-border);
    border-radius: 0.5rem;
    color: var(--color-text-body);
    font-size: 2rem;
    line-height: 1;
    width: 3rem;
    height: 3rem;
    cursor: pointer;
}

.class-code-fullscreen__close:hover {
    background: var(--color-surface-hover);
}

.class-code-fullscreen__title {
    font-size: clamp(1.75rem, 3.5vw, 2.75rem);
    color: var(--color-text-strong);
    margin: 0 0 var(--space-2);
}

.class-code-fullscreen__domain {
    font-size: clamp(2rem, 5.5vw, 4rem);
    color: var(--color-text-strong);
    margin: 0 0 var(--space-4);
    line-height: 1.2;
}

.class-code-fullscreen__domain strong {
    font-family: 'Courier New', Courier, monospace;
    color: var(--color-primary-700);
    letter-spacing: 0.02em;
}

@media (prefers-color-scheme: dark) {
    .class-code-fullscreen__domain strong {
        color: var(--color-primary-300);
    }
}

.class-code-fullscreen__label {
    font-size: clamp(1.5rem, 3.5vw, 2.5rem);
    color: var(--color-text-muted);
    margin: 0 0 var(--space-4);
    text-transform: uppercase;
    letter-spacing: 0.1em;
}

.class-code-fullscreen__code {
    font-family: 'Courier New', Courier, monospace;
    font-weight: 700;
    color: var(--color-primary-700);
    /* Fluid scaling — fills the screen on a projector but stays readable on tablets */
    font-size: clamp(3.5rem, 18vw, 15rem);
    letter-spacing: 0.15em;
    line-height: 1.1;
    word-break: break-all;
}

@media (prefers-color-scheme: dark) {
    .class-code-fullscreen__code {
        color: var(--color-primary-300);
    }
}

.class-code-fullscreen__timer {
    margin-top: var(--space-6);
    font-size: clamp(1.125rem, 2vw, 1.5rem);
    color: var(--color-text-muted);
}

/* Join Class Panel (student dashboard) */
.join-class-panel {
    margin-bottom: var(--space-6);
    padding: var(--space-4);
}

.join-class-panel__body {
    display: flex;
    align-items: flex-end;
    gap: var(--space-3);
    flex-wrap: wrap;
}

.join-class-panel__body .form-group {
    margin-bottom: 0;
    flex: 1;
    min-width: 12rem;
}


/* ── Page Header ───────────────────────────────────────────── */

.page-header {
    display: flex;
    flex-direction: column;
    margin-bottom: var(--space-6);
    gap: var(--space-3);
}

@media (min-width: 768px) {
    .page-header {
        flex-direction: row;
        align-items: flex-start;
        justify-content: space-between;
        gap: var(--space-4);
    }
}

/* Modifier — keep title + actions on one line at all viewport widths.
   Use when the title is short and the actions are compact (e.g. the
   teacher dashboard header with its Dashboard title + Week A/B toggle).
   Default .page-header stacks on mobile, which is the right call when
   either side might overflow; this modifier opts out of that. */
.page-header--inline {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
}

.page-header__left {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

/* Text links inside tables/lists where the link IS the entity name
   (template list, student list, KB topic name link, etc.). Default
   primary-700 (light) is OK on white but feels thin in dark mode at
   primary-400. Use the link-hover token + medium weight so the name
   reads with presence in both modes without losing the link colour.
   The .table tbody a:not(.btn) selector applies the same treatment
   automatically to every entity-name link inside a table body, so
   templates don't need to opt in by adding the .text-link class. */
.text-link,
.table tbody a:not(.btn) {
    color: var(--color-link-hover);
    font-weight: 500;
}

.text-link:hover,
.table tbody a:not(.btn):hover {
    text-decoration: underline;
}

.page-header__title {
    font-size: var(--text-xl);
    font-weight: 700;
    color: var(--color-text-strong);
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
}

@media (min-width: 768px) {
    .page-header__title {
        font-size: var(--text-2xl);
    }
}

.page-header__subtitle {
    margin-top: var(--space-1);
}

.page-header__back {
    color: var(--color-text-muted);
    text-decoration: none;
}

.page-header__back:hover {
    /* Was primary-600 — fails AA on the cool light page-bg, and
       primary-700 in dark needs lifting too. Route through the link
       token. */
    color: var(--color-link-hover);
    text-decoration: none;
}

.page-header__breadcrumbs {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
}

.page-header__sep {
    user-select: none;
}

.page-header__actions {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-shrink: 0;
    flex-wrap: wrap;
}


/* ── Badges ────────────────────────────────────────────────── */

.badge {
    display: inline-block;
    padding: var(--space-1) var(--space-2);
    font-size: var(--text-xs);
    font-weight: 500;
    border-radius: var(--border-radius);
    background-color: var(--color-primary-100);
    color: var(--color-primary-700);
    /* 1px border in the matching family shade. Without this, the
       softer -bg variants (success/warning/muted/primary-tinted)
       blend into the surrounding card surface in both modes —
       most visible in dark where the dark-tinted bgs are within a
       luminance step of slate-800. Each variant overrides
       border-color to match its own family. */
    border: 1px solid var(--color-primary-300);
    line-height: 1.4;
}

.badge--muted {
    /* "you" pillbox + similar neutral pills. The previous gray-100
       bg + text-muted (gray-600) only hit ~3.9:1 even in light mode
       (badge text is text-xs, so AA needs 4.5:1). Route bg through
       --color-surface-hover and text through --color-text-body so
       the pill has solid contrast in both modes. */
    background-color: var(--color-surface-hover);
    color: var(--color-text-body);
    border-color: var(--color-text-muted);
}

.badge--primary {
    background-color: var(--color-primary-100);
    color: var(--color-primary-700);
    border-color: var(--color-primary-300);
}

@media (prefers-color-scheme: dark) {
    /* Primary-tinted badges (year group, "Today" pill, etc.) flip
       direction in dark — the soft tint becomes a deep navy capsule.
       Border flips to primary-700 to give a subtle outline. */
    .badge--primary {
        background-color: var(--color-primary-900);
        color: var(--color-primary-200);
        border-color: var(--color-primary-700);
    }
}

.badge--week {
    background-color: var(--color-info-bg);
    color: var(--color-info);
    border-color: var(--color-info);
}

@media (prefers-color-scheme: dark) {
    .badge--week {
        /* --color-info is primary-600 — too dark on the dark info-bg
           in dark mode. Flip to a brighter info shade. Border tracks
           the same family. */
        color: var(--color-primary-300);
        border-color: var(--color-primary-700);
    }
}

.badge--success {
    background-color: var(--color-success-bg);
    color: var(--color-success-strong);
    border-color: var(--color-success-strong);
}

.badge--warning {
    background-color: var(--color-warning-bg);
    color: var(--color-warning-strong);
    border-color: var(--color-warning-strong);
}

.badge--error {
    background-color: var(--color-error-bg);
    color: var(--color-error-strong);
    border-color: var(--color-error-strong);
}


/* ── Log viewer (admin) ────────────────────────────────────── */

.log-list {
    list-style: none;
    padding: 0;
    margin: 0;
}

.log-entry {
    padding: var(--space-3) 0;
    border-bottom: 1px solid var(--color-surface-border);
}

.log-entry:last-child {
    border-bottom: none;
}

.log-entry__header {
    display: flex;
    gap: var(--space-3);
    align-items: baseline;
    flex-wrap: wrap;
}

.log-entry__time {
    font-variant-numeric: tabular-nums;
}

.log-entry__message {
    margin-top: var(--space-2);
    font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
    white-space: pre-wrap;
    word-break: break-word;
}

.log-entry__trace {
    margin-top: var(--space-2);
}

.log-entry__trace summary {
    cursor: pointer;
}

.log-entry__trace pre {
    margin-top: var(--space-2);
    padding: var(--space-3);
    background-color: var(--color-bg-page);
    border-radius: var(--border-radius);
    font-size: 0.85rem;
    overflow-x: auto;
    white-space: pre;
}


/* ── Empty State ───────────────────────────────────────────── */

.empty-state {
    text-align: center;
    padding: var(--space-8) var(--space-4);
}

@media (min-width: 768px) {
    .empty-state {
        padding: var(--space-12) var(--space-4);
    }
}

.empty-state__message {
    font-size: var(--text-lg);
    color: var(--color-text-muted);
}


/* ── Class Grid ────────────────────────────────────────────── */

.class-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-4);
    /* All rows take the same height as the tallest item across the
       whole grid, not just within a single row. Without this, a
       2-line description in row 1 makes that row taller than row 2
       which only has 1-line descriptions. */
    grid-auto-rows: 1fr;
}

@media (min-width: 480px) {
    .class-grid {
        grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
    }
}

@media (min-width: 768px) {
    .class-grid {
        grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
    }
}

.class-card {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    text-decoration: none;
    color: inherit;
    transition: box-shadow var(--transition-fast), border-color var(--transition-fast);
}

.class-card:hover {
    box-shadow: var(--shadow-md);
    border-color: var(--color-primary-200);
    text-decoration: none;
    color: inherit;
}

.class-card__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
}

.class-card__name {
    font-size: var(--text-lg);
    font-weight: 600;
    color: var(--color-text-strong);
}

.class-card__description {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.class-card__footer {
    margin-top: auto;
    padding-top: var(--space-2);
    border-top: 1px solid var(--color-gray-100);
}

.class-card__year {
    flex-shrink: 0;
}


/* ── School Grid (admin dashboard) ─────────────────────────── */

.school-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-4);
}

.school-grid .card.card--link {
	text-align: center;
}

.school-grid .card__title {
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

@media (min-width: 480px) {
    .school-grid {
        grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
    }
}

@media (min-width: 768px) {
    .school-grid {
        grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
    }
}

.card--link {
    display: block;
    text-decoration: none;
    color: inherit;
    transition: box-shadow var(--transition-fast), border-color var(--transition-fast);
}

.card--link:hover {
    box-shadow: var(--shadow-md);
    border-color: var(--color-primary-300);
    text-decoration: none;
    color: inherit;
}

@media (prefers-color-scheme: dark) {
    .card--link:hover {
        /* primary-300 (light blue) on slate-800 reads as a soft ring;
           primary-700 + heavier shadow signals "elevated" on dark. */
        border-color: var(--color-primary-700);
    }
}

.card--muted {
    opacity: 0.65;
    background: var(--color-bg-page);
}

.school-grid__stats {
    display: flex;
    gap: var(--space-4);
    margin-top: var(--space-3);
    padding-top: var(--space-3);
    border-top: 1px solid var(--color-surface-border);
}

.stat {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-1);
	flex-grow: 1;
	flex-basis: 0;
	min-width: 0;
}

.stat__value {
    font-size: var(--text-xl);
    font-weight: 700;
    color: var(--color-text-strong);
}

.stat__label {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}


/* ── Class Sections (detail page) ──────────────────────────── */

.class-section {
    margin-bottom: var(--space-6);
}


/* ── Form Layout ───────────────────────────────────────────── */

.form-row {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

@media (min-width: 480px) {
    .form-row {
        flex-direction: row;
        flex-wrap: wrap;
    }
}

.form-group--inline {
    flex: 1;
    min-width: 8rem;
}

.form-actions {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-top: var(--space-6);
    flex-wrap: wrap;
}

/* Form containers — full width on mobile, constrained on desktop */
.form-container {
    max-width: 100%;
    background-color: var(--color-surface);
    border: 1px solid var(--color-surface-border);
    border-radius: var(--border-radius-lg);
    padding: var(--space-4);
    box-shadow: 0 1px 3px rgba(15, 23, 42, 0.08), 0 1px 2px rgba(15, 23, 42, 0.04);
}

@media (min-width: 768px) {
    .form-container {
        max-width: 36rem;
        padding: var(--space-6);
    }
}


/* ── Form Variants (small) ─────────────────────────────────── */

.form-label--sm {
    font-size: var(--text-xs);
    margin-bottom: var(--space-1);
}

.form-input--sm {
    padding: var(--space-1) var(--space-2);
    font-size: var(--text-sm);
    min-height: 2.25rem;
}

.form-textarea--sm {
    padding: var(--space-2);
    font-size: var(--text-sm);
    min-height: 4rem;
}

.form-help {
    margin-bottom: var(--space-3);
}

/* ── Template Data-File Rows ──────────────────────────────── */

.tpl-file-row {
    margin-bottom: var(--space-3);
    padding: var(--space-3);
}

.tpl-file-row__header {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: var(--space-2);
}

.tpl-file-row__header .form-label {
    margin-bottom: 0;
    white-space: nowrap;
}

.tpl-file-row__header .form-input {
    flex: 1;
    min-width: 0;
}

.tpl-file-row__remove {
    flex-shrink: 0;
}

/* ── Dashboard ───────────────────────────────────────────── */

/* Week toggle pill — segmented A | B control in the dashboard
   page-header. The active segment is filled; clicking the inactive
   segment fires a /api/week/set call and reloads. Replaces the
   older full-width .week-widget that took a whole row. */
.week-toggle {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    background: var(--color-surface);
    border: 1px solid var(--color-surface-border);
    border-radius: var(--radius);
    padding: var(--space-1);
}

.week-toggle__label {
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--color-text-muted);
    font-weight: 600;
    padding: 0 var(--space-2) 0 var(--space-3);
}

.week-toggle__btn {
    background: transparent;
    border: 0;
    border-radius: calc(var(--radius) - 2px);
    padding: var(--space-2) var(--space-3);
    font-weight: 600;
    color: var(--color-text-muted);
    cursor: pointer;
    min-width: 2.25rem;
    min-height: 2.25rem;
    transition: background 120ms ease, color 120ms ease;
}

.week-toggle__btn:hover:not(.week-toggle__btn--active):not(:disabled) {
    background: var(--color-surface-hover);
    color: var(--color-text-body);
}

.week-toggle__btn--active {
    background: var(--color-primary-700);
    color: #fff;
    cursor: default;
}

.week-toggle__btn:disabled {
    opacity: 0.6;
    cursor: not-allowed;
}

@media (prefers-color-scheme: dark) {
    .week-toggle__btn--active {
        background: var(--color-primary-300);
        color: var(--color-primary-900);
    }
}

.stale-banner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    background: var(--color-warning-bg, #fffbeb);
    border: 1px solid var(--color-warning, #d97706);
    border-radius: var(--radius);
    padding: var(--space-4) var(--space-6);
    margin-bottom: var(--space-6);
}

.stale-banner__text {
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--color-text);
    margin: 0;
}

.stale-banner__actions {
    display: flex;
    gap: var(--space-2);
    flex-shrink: 0;
}

@media (max-width: 479px) {
    .stale-banner {
        flex-direction: column;
        text-align: center;
        padding: var(--space-4);
    }

    .stale-banner__actions {
        width: 100%;
    }

    .stale-banner__actions .btn {
        flex: 1;
    }
}

.day-schedule {
    padding: var(--space-4) 0;
}

.day-schedule:not(:last-child) {
    border-bottom: 1px solid var(--color-border);
}

.day-schedule__heading {
    font-size: 0.875rem;
    font-weight: 600;
    margin: 0 0 var(--space-2) 0;
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.day-schedule--today {
    background: var(--color-primary-50);
    border-radius: var(--radius);
    padding-left: var(--space-4);
    padding-right: var(--space-4);
    margin-left: calc(-1 * var(--space-4));
    margin-right: calc(-1 * var(--space-4));
}

.day-schedule__heading--today {
    color: var(--color-primary-700);
}

@media (prefers-color-scheme: dark) {
    .day-schedule--today {
        /* primary-50 is near-white in dark — flip to primary-900 so
           today's row reads as a tinted blue zone on the slate-800
           card, not as a near-white burst. */
        background: var(--color-primary-900);
    }

    .day-schedule__heading--today {
        color: var(--color-primary-200);
    }

    /* On the primary-900 today bg, --color-text-muted (slate-400)
       only hits ~4:1 — fails AA on text-xs/sm. Bump to primary-200
       for "No classes" placeholder + period labels + any other
       muted text inside the today highlight. */
    .day-schedule--today .text-muted,
    .day-schedule--today .schedule-entry__period {
        color: var(--color-primary-200);
    }
}

.day-schedule__empty {
    margin: 0;
}

.schedule-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.schedule-entry {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius);
    min-height: 2.75rem;
}

.schedule-entry:hover {
    background: var(--color-surface-hover);
}

.schedule-entry__time {
    font-size: 0.8125rem;
    font-weight: 600;
    min-width: 6.5rem;
    color: var(--color-text);
}

.schedule-entry__period {
    min-width: 5rem;
}

.schedule-entry__class {
    flex: 1;
    font-weight: 500;
}

.schedule-entry__room {
    flex-shrink: 0;
}

@media (max-width: 479px) {
    .schedule-entry {
        flex-wrap: wrap;
        gap: var(--space-1) var(--space-3);
    }

    .schedule-entry__time {
        min-width: auto;
    }

    .schedule-entry__period {
        min-width: auto;
    }

    .schedule-entry__class {
        flex-basis: 100%;
        order: -1;
        font-size: 0.9375rem;
    }
}


/* ── Student Search (class detail, add students) ─────────── */

.student-search-list {
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    max-height: 20rem;
    overflow-y: auto;
}

.student-search-item {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    cursor: pointer;
    min-height: 2.75rem;
}

.student-search-item:not(:last-child) {
    border-bottom: 1px solid var(--color-border);
}

.student-search-item:hover {
    background: var(--color-surface-hover);
}

.student-search-item__info {
    flex: 1;
    font-size: 0.875rem;
}


/* ── Student Checklist (note form) ────────────────────────── */

.student-checklist {
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    max-height: 16rem;
    overflow-y: auto;
    margin-top: var(--space-2);
}

.student-checklist__item {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-4);
    cursor: pointer;
    min-height: 2.75rem;
    font-size: 0.875rem;
}

.student-checklist__item:not(:last-child) {
    border-bottom: 1px solid var(--color-border);
}

.student-checklist__item:hover {
    background: var(--color-surface-hover);
}


/* ── Flag Banners ────────────────────────────────────────── */

.flag-banners {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.flag-banner {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius);
    border-left: 4px solid;
}

.flag-banner--alert {
    background: var(--color-error-bg);
    border-left-color: var(--color-error);
    color: var(--color-error-strong);
}

.flag-banner--info {
    background: var(--color-primary-50);
    border-left-color: var(--color-primary-600);
    color: var(--color-primary-900);
}

@media (prefers-color-scheme: dark) {
    /* Flip both flag banners to use the dark semantic-bg tints with
       lighter text. The error/primary -bg tokens already flip; the
       error-strong token also flips (red-700 → red-400) so the dark
       text + border come through automatically. */
    .flag-banner--alert {
        color: var(--color-error-strong);
        border-left-color: var(--color-error-strong);
    }

    .flag-banner--info {
        background: var(--color-primary-900);
        color: var(--color-primary-100);
        border-left-color: var(--color-primary-400);
    }
}

.flag-banner--archived {
    opacity: 0.6;
    filter: grayscale(0.4);
}

.flag-banner__content {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    flex: 1;
    min-width: 0;
}

.flag-banner__row {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2);
    flex-wrap: wrap;
    min-width: 0;
}

.flag-banner__icon {
    flex-shrink: 0;
    margin-top: 0.125rem;
}

.flag-banner__text {
    font-size: 0.875rem;
    font-weight: 500;
}

.flag-banner__students {
    font-size: 0.8125rem;
    font-weight: 400;
    opacity: 0.8;
}

.flag-banner__actions {
    display: flex;
    gap: var(--space-1);
    flex-shrink: 0;
}

/* Flag indicator on student rows */
.flag-indicator {
    display: inline-block;
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 50%;
    margin-right: var(--space-1);
    vertical-align: middle;
}

.flag-indicator--alert {
    background: var(--color-error);
}

.flag-indicator--info {
    background: var(--color-primary-500);
}


/* ── Class Prep (dashboard) ──────────────────────────────── */

.prep-class {
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--color-gray-100);
}

.prep-class:last-child {
    border-bottom: none;
}

.prep-day-heading {
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--color-text-muted);
    padding: var(--space-3) var(--space-4) var(--space-1);
    border-top: 1px solid var(--color-gray-100);
}

.prep-day-heading:first-child {
    border-top: none;
}

.prep-class__name {
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--color-text-body);
    margin-bottom: var(--space-2);
}


/* ── Student Log Entries ─────────────────────────────────── */

.log-entries {
    display: flex;
    flex-direction: column;
}

.log-entry {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--color-gray-100);
}

.log-entry:last-child {
    border-bottom: none;
}

.log-entry__sentiment {
    flex-shrink: 0;
    width: 0.625rem;
    height: 0.625rem;
    border-radius: 50%;
    margin-top: 0.375rem;
}

.log-entry__sentiment--positive {
    background: var(--color-success);
}

.log-entry__sentiment--neutral {
    background: var(--color-gray-400);
}

.log-entry__sentiment--concern {
    background: var(--color-warning);
}

.log-entry__content {
    flex: 1;
    min-width: 0;
}

.log-entry__text {
    font-size: 0.875rem;
    color: var(--color-text-body);
    line-height: 1.4;
}

.log-entry__meta {
    display: flex;
    gap: var(--space-3);
    margin-top: var(--space-1);
    font-size: 0.8125rem;
    color: var(--color-text-muted);
}

/* Student log modal (class page) */
.log-modal {
    position: fixed;
    inset: 0;
    z-index: 50;
    display: flex;
    align-items: center;
    justify-content: center;
}

.log-modal__backdrop {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.4);
}

.log-modal__panel {
    position: relative;
    background: var(--color-surface);
    border-radius: var(--radius);
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);
    width: 90%;
    max-width: 32rem;
    max-height: 80vh;
    display: flex;
    flex-direction: column;
}

.log-modal__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--space-4);
    border-bottom: 1px solid var(--color-gray-200);
}

.log-modal__nav {
    display: flex;
    gap: var(--space-2);
}

.log-modal__body {
    flex: 1;
    overflow-y: auto;
    padding: var(--space-4);
}

.log-modal__form {
    display: flex;
    gap: var(--space-2);
    margin-bottom: var(--space-4);
    padding-bottom: var(--space-4);
    border-bottom: 1px solid var(--color-gray-200);
}

.log-modal__form textarea {
    flex: 1;
    min-height: 2.75rem;
    resize: none;
}

.log-modal__form select {
    width: auto;
    min-width: 6rem;
}


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

.task-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.task-card {
    display: flex;
    align-items: flex-start;
    padding: var(--space-3) var(--space-4);
    background: var(--color-surface);
    border: 1px solid var(--color-gray-200);
    border-radius: var(--radius);
    transition: border-color 0.15s;
}

.task-card:hover {
    border-color: var(--color-gray-300);
}

.task-card--done {
    opacity: 0.65;
    background: var(--color-bg-page);
}

.task-card--archived {
    opacity: 0.5;
    background: var(--color-bg-page);
}

.task-card__header {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    width: 100%;
}

.task-card__check {
    flex-shrink: 0;
    width: 1.5rem;
    height: 1.5rem;
    padding: 0;
    border: none;
    background: none;
    cursor: pointer;
    color: var(--color-gray-400);
    margin-top: 0.125rem;
}

.task-card__check:hover {
    color: var(--color-primary-500);
}

.task-card__check--done {
    color: var(--color-success-500, #22c55e);
}

.task-card__check svg {
    width: 100%;
    height: 100%;
}

.task-card__content {
    flex: 1;
    min-width: 0;
}

.task-card__title-row {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
}

.task-card__title {
    font-weight: 500;
    color: var(--color-text-strong);
}

.task-card__title--done {
    text-decoration: line-through;
    color: var(--color-text-muted);
}

.task-card__desc {
    margin-top: var(--space-1);
    font-size: 0.875rem;
    color: var(--color-text-muted);
    line-height: 1.4;
}

.task-card__meta {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-top: var(--space-1);
    font-size: 0.8125rem;
    color: var(--color-text-muted);
}

.task-card__due {
    display: flex;
    align-items: center;
    gap: 0.25rem;
}

.task-card__class {
    color: var(--color-link);
}

.task-card__progress {
    font-weight: 500;
}

/* Inline checklist on task cards */
.task-checklist {
    list-style: none;
    margin: var(--space-3) 0 0 0;
    padding: 0;
    display: grid;
    gap: 0.125rem;
}

.task-checklist__item {
    display: block;
}

.task-checklist__label {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: 0.25rem var(--space-2);
    border-radius: var(--border-radius);
    cursor: pointer;
    line-height: 1.4;
    color: var(--color-text-body);
    transition: background-color var(--transition-fast);
}

.task-checklist__label:hover {
    background-color: var(--color-surface-hover);
}

.task-checklist__check {
    flex-shrink: 0;
    width: 1rem;
    height: 1rem;
    margin: 0;
    cursor: pointer;
}

.task-checklist__check:disabled {
    cursor: default;
}

.task-checklist__text {
    font-size: 0.875rem;
}

.task-checklist__item--done .task-checklist__text {
    text-decoration: line-through;
    color: var(--color-text-muted);
}

.task-card__actions {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    flex-shrink: 0;
}

/* Filter bar */
.filter-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
    flex-wrap: wrap;
}

.card > .filter-tabs {
    padding: 0 var(--space-4);
    margin-bottom: var(--space-3);
}

.filter-select {
    min-width: 10rem;
}

.form-select--sm {
    font-size: 0.875rem;
    padding: var(--space-1) var(--space-2);
    min-height: 2.25rem;
}

/* Student checklist */
.student-checklist {
    max-height: 15rem;
    overflow-y: auto;
    border: 1px solid var(--color-gray-200);
    border-radius: var(--radius);
    padding: var(--space-2);
}

.checklist-item {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-1) var(--space-2);
    cursor: pointer;
    border-radius: var(--radius-sm, 0.25rem);
    font-size: 0.875rem;
}

.checklist-item:hover {
    background: var(--color-surface-hover);
}

.checklist-item input[type="checkbox"] {
    flex-shrink: 0;
}

/* ────────────────────────────────────────────────────────────────
   Record health warning — shared between task cards and flag
   banners. Surfaces when a class-scoped record names a pupil who
   has since left that class. Token-driven so it flips in dark
   mode automatically.
   ──────────────────────────────────────────────────────────────── */

.record-health-warning {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2);
    width: 100%;
    margin: var(--space-1) 0 0 0;
    padding: var(--space-2) var(--space-3);
    background: var(--color-warning-bg);
    color: var(--color-warning-strong);
    border: 1px solid var(--color-warning-strong);
    border-radius: var(--radius);
    font-size: 0.8125rem;
    font-weight: 500;
    line-height: 1.4;
}

.record-health-warning > span[aria-hidden] {
    flex-shrink: 0;
    font-size: 1rem;
    line-height: 1.2;
}

/* ────────────────────────────────────────────────────────────────
   Student picker (shared by task + flag forms)
   Two surfaces:
     - Class mode: a `.student-picker__list` checklist reusing the
       existing `.student-checklist` / `.checklist-item` chrome.
     - Search mode: a single `.student-picker__search` row holding
       chips, the input field, and the absolute-positioned
       `.student-picker__suggest` dropdown.
   ──────────────────────────────────────────────────────────────── */

.student-picker__chips {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.student-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: 0.25rem 0.5rem;
    background: var(--color-primary-50);
    color: var(--color-primary-700);
    border: 1px solid var(--color-primary-200);
    border-radius: 999px;
    font-size: 0.8125rem;
    line-height: 1.2;
}

@media (prefers-color-scheme: dark) {
    .student-chip {
        background: var(--color-primary-900);
        color: var(--color-primary-200);
        border-color: var(--color-primary-700);
    }
}

.student-chip__remove {
    appearance: none;
    background: transparent;
    border: none;
    color: inherit;
    font-size: 1.125rem;
    line-height: 1;
    padding: 0 0.125rem;
    cursor: pointer;
    min-width: 1.5rem;
    min-height: 1.5rem;
    border-radius: 999px;
}

.student-chip__remove:hover,
.student-chip__remove:focus-visible {
    background: var(--color-primary-200);
    outline: none;
}

@media (prefers-color-scheme: dark) {
    .student-chip__remove:hover,
    .student-chip__remove:focus-visible {
        background: var(--color-primary-700);
    }
}

.student-picker__search {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    padding: 0.375rem 0.5rem;
    background: var(--color-input-bg);
    border: 1px solid var(--color-input-border);
    border-radius: var(--radius);
    min-height: 2.75rem;
}

.student-picker__search:focus-within {
    border-color: var(--color-primary-500);
    box-shadow: 0 0 0 3px var(--color-primary-100);
}

.student-picker__search .student-picker__chips {
    display: contents;
}

.student-picker__field {
    flex: 1 1 12rem;
    min-width: 12rem;
    border: none;
    outline: none;
    background: transparent;
    padding: 0.25rem 0;
    font-size: 1rem;
}

.student-picker__suggest {
    position: absolute;
    top: calc(100% + 0.25rem);
    left: 0;
    right: 0;
    z-index: 20;
    background: var(--color-surface);
    border: 1px solid var(--color-input-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-md);
    list-style: none;
    margin: 0;
    padding: 0.25rem 0;
    max-height: 16rem;
    overflow-y: auto;
}

.student-picker__suggest-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    padding: 0.5rem 0.75rem;
    cursor: pointer;
    font-size: 0.875rem;
}

.student-picker__suggest-item--active,
.student-picker__suggest-item:hover {
    background: var(--color-surface-hover);
}

/* Fieldset wrapper used for the flag scope-mode radios */
.form-fieldset {
    border: 1px solid var(--color-gray-200);
    border-radius: var(--radius-md, 0.375rem);
    padding: var(--space-3);
}

.form-fieldset legend {
    padding: 0 var(--space-2);
}

/* Class student row actions (flag + remove) */
.student-row__actions {
    white-space: nowrap;
}

.student-row__actions .btn + .btn {
    margin-left: var(--space-1);
}

.student-row__flag-btn {
    color: var(--color-text-muted);
    padding: var(--space-1) var(--space-2);
}

.student-row__flag-btn:hover {
    color: var(--color-amber-600, #d97706);
}

/* Form actions */
.form-actions {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-2);
    margin-top: var(--space-4);
    padding-top: var(--space-4);
    border-top: 1px solid var(--color-gray-200);
}

/* Form hint */
.form-hint {
    font-size: 0.8125rem;
    color: var(--color-text-muted);
    margin-top: var(--space-1);
}

/* Text utilities */
.text-center { text-align: center; }
.py-8 { padding-top: var(--space-8); padding-bottom: var(--space-8); }

@media (max-width: 767px) {
    .task-card__actions {
        margin-top: var(--space-2);
    }
}


/* ── Pagination ──────────────────────────────────────────── */

.pagination {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-1);
    margin-top: var(--space-6);
    flex-wrap: wrap;
}

.pagination__link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2.25rem;
    min-height: 2.25rem;
    padding: var(--space-1) var(--space-2);
    border-radius: var(--radius);
    font-size: 0.875rem;
    font-weight: 500;
    text-decoration: none;
    color: var(--color-text-body);
    border: 1px solid var(--color-gray-200);
    background: var(--color-white);
    cursor: pointer;
}

@media (prefers-reduced-motion: no-preference) {
    .pagination__link {
        transition: background-color 0.15s ease, color 0.15s ease;
    }
}

a.pagination__link:hover {
    background: var(--color-surface-hover);
    color: var(--color-text-strong);
}

.pagination__link--active {
    background: var(--color-primary-600);
    border-color: var(--color-primary-600);
    color: var(--color-white);
    cursor: default;
}

.pagination__link--disabled {
    color: var(--color-gray-400);
    cursor: default;
    pointer-events: none;
}

.pagination__ellipsis {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2.25rem;
    min-height: 2.25rem;
    font-size: 0.875rem;
    color: var(--color-gray-400);
}

@media (max-width: 479px) {
    .pagination__link {
        min-width: 2.75rem;
        min-height: 2.75rem;
    }

    .pagination__ellipsis {
        min-width: 1.5rem;
    }
}


/* ── Periods Table (settings) ──────────────────────────────── */

.periods-col-num {
    width: 2.5rem;
}

.periods-col-label {
    min-width: 8rem;
}

.periods-col-time {
    width: 6rem;
}

.periods-col-action {
    width: 2.5rem;
}

@media (min-width: 768px) {
    .periods-col-num { width: 3rem; }
    .periods-col-time { width: 8rem; }
    .periods-col-action { width: 3rem; }
}


/* ── Inline Form (archive/restore buttons) ─────────────────── */

.inline-form {
    display: inline;
}


/* ── Join Code Display ─────────────────────────────────────── */

.join-code-section {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    align-items: flex-start;
}

.join-code-display {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}

.join-code-display__code {
    font-family: 'Courier New', Courier, monospace;
    font-size: 1.75rem;
    font-weight: 700;
    letter-spacing: 0.25em;
    padding: var(--space-2) var(--space-4);
    background-color: var(--color-bg-page);
    border: 2px dashed var(--color-input-border);
    border-radius: var(--radius);
    color: var(--color-text-strong);
    user-select: all;
}

.join-code-display__info {
    width: 100%;
    margin: 0;
}

/* ═══════════════════════════════════════════════════════════
   KNOWLEDGE BANK
   ═══════════════════════════════════════════════════════════ */

.kb-search-bar {
    margin-bottom: var(--space-4);
}

.kb-search-input {
    max-width: 24rem;
}

/* ── Topic cards (index page) ─────────────────────────────── */

.kb-topic-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.kb-topic-card {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    background: var(--color-surface);
    border: 1px solid var(--color-surface-border);
    border-radius: var(--radius);
}

.kb-topic-card__info {
    display: flex;
    align-items: baseline;
    gap: var(--space-3);
    min-width: 0;
}

.kb-topic-card__name {
    font-weight: 600;
    font-size: 1rem;
    /* Was var(--color-primary) — undefined token, so the name fell
       through to inherited body text colour. Use the link token now
       so it reads as a clickable name in both modes. */
    color: var(--color-link);
    text-decoration: none;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.kb-topic-card__name:hover {
    color: var(--color-link-hover);
    text-decoration: underline;
}

.kb-topic-card__count {
    font-size: 0.8125rem;
    color: var(--color-text-muted);
    white-space: nowrap;
}

.kb-topic-card__actions {
    display: flex;
    gap: var(--space-2);
    flex-shrink: 0;
}

.kb-topic-card__matches {
    flex-basis: 100%;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1) var(--space-2);
    align-items: center;
    padding-top: var(--space-2);
    border-top: 1px solid var(--color-surface-border);
    font-size: 0.8125rem;
}

.kb-topic-card__matches-label {
    color: var(--color-text-muted);
}

.kb-topic-card__match {
    color: var(--color-link);
    text-decoration: none;
    background: var(--color-primary-50);
    padding: 0.125rem var(--space-2);
    border-radius: var(--border-radius);
}

.kb-topic-card__match:hover {
    color: var(--color-link-hover);
    text-decoration: underline;
    background: var(--color-primary-100);
}

@media (prefers-color-scheme: dark) {
    .kb-topic-card__match {
        background: var(--color-primary-900);
        color: var(--color-primary-200);
    }

    .kb-topic-card__match:hover {
        background: var(--color-primary-800);
        color: var(--color-primary-100);
    }
}

.kb-no-results {
    margin-top: var(--space-4);
}

/* ── Entry cards (topic show page) ────────────────────────── */

.kb-entry-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.kb-entry-card {
    background: var(--color-surface);
    border: 1px solid var(--color-surface-border);
    border-radius: var(--radius);
    padding: var(--space-4) var(--space-5);
}

.kb-entry-card__header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-3);
}

.kb-entry-card__title {
    font-size: 1.125rem;
    font-weight: 600;
    margin: 0;
    color: var(--color-text-strong);
}

.kb-entry-card__actions {
    display: flex;
    gap: var(--space-2);
    flex-shrink: 0;
}

.kb-entry-card__content {
    white-space: pre-wrap;
    font-size: 0.9375rem;
    line-height: 1.6;
    color: var(--color-text-body);
}

/* ── Image thumbnails ─────────────────────────────────────── */

.kb-images {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr));
    gap: var(--space-3);
    margin-top: var(--space-3);
}

.kb-images__item {
    position: relative;
    aspect-ratio: 1;
    border-radius: var(--radius);
    overflow: hidden;
    border: 1px solid var(--color-surface-border);
    background: var(--color-surface-hover);
}

.kb-images__item--editable {
    cursor: default;
}

.kb-images__thumb {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.kb-images__delete {
    position: absolute;
    top: var(--space-1);
    right: var(--space-1);
    width: 1.5rem;
    height: 1.5rem;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(0, 0, 0, 0.6);
    color: #fff;
    border: none;
    border-radius: 50%;
    cursor: pointer;
    opacity: 0;
    transition: opacity 0.15s;
}

.kb-images__item--editable:hover .kb-images__delete,
.kb-images__delete:focus {
    opacity: 1;
}

/* ── Image upload area (entry form) ───────────────────────── */

.kb-image-actions {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-top: var(--space-3);
}

.kb-upload-label {
    cursor: pointer;
}

.kb-image-status {
    font-size: 0.8125rem;
    color: var(--color-text-muted);
}

.kb-content-textarea {
    font-family: inherit;
    resize: vertical;
    min-height: 12rem;
}

/* ── KB Tag Chips + Widgets ──────────────────────────────── */

.kb-tag-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: 0.25rem 0.5rem;
    background: var(--color-primary-50);
    color: var(--color-primary-700);
    border: 1px solid var(--color-primary-200);
    border-radius: 999px;
    font-size: 0.8125rem;
    line-height: 1.2;
    text-decoration: none;
}

.kb-tag-chip--link:hover,
.kb-tag-chip--link:focus-visible {
    background: var(--color-primary-100);
    outline: none;
}

/* Dark-mode chip palette — primary-200 text on primary-900 bg with a
   primary-700 ring. The text uses -200 (very pale blue) rather than
   -300 (more saturated blue) — pillboxes shouldn't shout, and -200
   still hits AAA on primary-900 (~9:1). */
@media (prefers-color-scheme: dark) {
    .kb-tag-chip {
        background: var(--color-primary-900);
        color: var(--color-primary-200);
        border-color: var(--color-primary-700);
    }

    .kb-tag-chip--link:hover,
    .kb-tag-chip--link:focus-visible {
        background: var(--color-primary-800);
        color: var(--color-primary-100);
    }

    .kb-tag-chip__remove:hover,
    .kb-tag-chip__remove:focus-visible {
        background: var(--color-primary-700);
    }
}

.kb-tag-chip--heading {
    font-size: 1rem;
    padding: 0.375rem 0.75rem;
}

.kb-tag-chip__remove {
    appearance: none;
    background: transparent;
    border: none;
    color: inherit;
    font-size: 1.125rem;
    line-height: 1;
    padding: 0 0.125rem;
    cursor: pointer;
    min-width: 1.5rem;
    min-height: 1.5rem;
    border-radius: 999px;
}

.kb-tag-chip__remove:hover,
.kb-tag-chip__remove:focus-visible {
    background: var(--color-primary-200);
    outline: none;
}

.kb-tag-input,
.kb-related-input {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    padding: 0.375rem 0.5rem;
    background: var(--color-input-bg);
    border: 1px solid var(--color-input-border, #d1d5db);
    border-radius: var(--radius, 0.375rem);
    min-height: 2.75rem;
}

.kb-tag-input:focus-within,
.kb-related-input:focus-within {
    border-color: var(--color-primary-500, #6366f1);
    box-shadow: 0 0 0 3px var(--color-primary-100, #e0e7ff);
}

.kb-tag-input__chips,
.kb-related-input__chips {
    display: contents;
    list-style: none;
    margin: 0;
    padding: 0;
}

.kb-tag-input__field,
.kb-related-input__field {
    flex: 1 1 8rem;
    min-width: 8rem;
    border: none;
    outline: none;
    background: transparent;
    padding: 0.25rem 0;
    font-size: 1rem;
}

.kb-tag-input__suggest,
.kb-related-input__suggest {
    position: absolute;
    top: calc(100% + 0.25rem);
    left: 0;
    right: 0;
    z-index: 20;
    background: var(--color-surface);
    border: 1px solid var(--color-input-border);
    border-radius: var(--radius, 0.375rem);
    box-shadow: var(--shadow-md);
    list-style: none;
    margin: 0;
    padding: 0.25rem 0;
    max-height: 16rem;
    overflow-y: auto;
}

.kb-tag-input__suggest-item,
.kb-related-input__suggest-item {
    padding: 0.5rem 0.75rem;
    cursor: pointer;
    font-size: 0.875rem;
}

.kb-tag-input__suggest-item--active,
.kb-tag-input__suggest-item:hover,
.kb-related-input__suggest-item--active,
.kb-related-input__suggest-item:hover {
    background: var(--color-surface-hover);
}

.kb-related-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: 0.25rem 0.5rem;
    background: var(--color-surface-hover);
    border: 1px solid var(--color-input-border);
    border-radius: var(--radius, 0.375rem);
    font-size: 0.8125rem;
    line-height: 1.2;
    color: var(--color-text-body);
}

.kb-related-chip__title {
    font-weight: 500;
}

.kb-related-chip__topic {
    font-size: 0.75rem;
}

.kb-related-chip__remove {
    appearance: none;
    background: transparent;
    border: none;
    color: inherit;
    font-size: 1.125rem;
    line-height: 1;
    padding: 0 0.125rem;
    cursor: pointer;
    min-width: 1.5rem;
    min-height: 1.5rem;
    border-radius: 999px;
}

.kb-related-chip__remove:hover,
.kb-related-chip__remove:focus-visible {
    background: var(--color-surface-border);
    outline: none;
}

/* Entry display: tag list + See also */

.kb-tag-list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    list-style: none;
    margin: var(--space-3) 0 0 0;
    padding: 0;
}

.kb-related {
    margin-top: var(--space-4);
    padding-top: var(--space-3);
    border-top: 1px solid var(--color-surface-border);
}

.kb-related__title {
    font-size: 0.875rem;
    font-weight: 600;
    text-transform: uppercase;
    color: var(--color-text-muted);
    letter-spacing: 0.05em;
    margin: 0 0 var(--space-2) 0;
}

.kb-related__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.kb-related__item a {
    font-weight: 500;
}

/* Tag index + tag show pages */

.kb-tag-index {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.kb-tag-index__item {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    background: var(--color-surface);
    border: 1px solid var(--color-surface-border);
    border-radius: var(--border-radius);
    transition: border-color var(--transition-fast);
}

.kb-tag-index__item:hover {
    border-color: var(--color-primary-300);
}

.kb-tag-index__name {
    font-weight: 500;
    color: var(--color-text-strong);
    text-decoration: none;
}

.kb-tag-index__name:hover {
    color: var(--color-link-hover);
    text-decoration: underline;
}

.kb-tag-index__count {
    margin-left: auto;
}

.kb-tag-entries {
    display: flex;
    flex-direction: column;
    gap: var(--space-6);
}

.kb-tag-entries__group {
    background: var(--color-surface);
    border: 1px solid var(--color-gray-200, #e5e7eb);
    border-radius: var(--radius, 0.375rem);
    padding: var(--space-4);
}

.kb-tag-entries__topic {
    font-size: 1.125rem;
    margin: 0 0 var(--space-3) 0;
}

.kb-tag-entries__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
}

.kb-tag-entries__list li + li {
    border-top: 1px solid var(--color-gray-100);
}

.kb-tag-entries__list a {
    display: block;
    padding: var(--space-2) var(--space-3);
    margin: 0 calc(-1 * var(--space-3));
    color: var(--color-text-body);
    text-decoration: none;
    border-radius: var(--border-radius);
    transition: color var(--transition-fast), background var(--transition-fast);
}

.kb-tag-entries__list a:hover {
    color: var(--color-primary-700);
    background: var(--color-primary-50);
    text-decoration: none;
}

/* ── Student Dashboard Tools ──────────────────────────────── */

.student-tools {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
    gap: var(--space-4);
}

.student-tool-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-6) var(--space-4);
    background: var(--color-surface);
    border: 1px solid var(--color-surface-border);
    border-radius: var(--border-radius-lg);
    text-decoration: none;
    text-align: center;
    color: inherit;
}

@media (prefers-reduced-motion: no-preference) {
    .student-tool-card {
        transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
    }
}

.student-tool-card:hover,
.student-tool-card:focus-visible {
    border-color: var(--color-primary-400);
    background: var(--color-primary-100);
    box-shadow: 0 2px 8px rgba(15, 23, 42, 0.10);
    text-decoration: none;
}

@media (prefers-color-scheme: dark) {
    .student-tool-card:hover,
    .student-tool-card:focus-visible {
        /* primary-100 stays nearly white in dark — flip to primary-900
           so the hovered tile reads as a tinted-blue elevation against
           the slate-800 card surrounding it. */
        background: var(--color-primary-900);
        border-color: var(--color-primary-700);
    }
}

.student-tool-card__icon {
    width: 3rem;
    height: 3rem;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--color-primary-600);
}

/* Icon contrast on hover — the primary-100 hover bg drops contrast
   from ~3.3:1 to ~2.8:1 against primary-600. Bump to primary-700
   so the icon stays readable in both states. */
.student-tool-card:hover .student-tool-card__icon,
.student-tool-card:focus-visible .student-tool-card__icon {
    color: var(--color-primary-700);
}

/* Dark mode — primary-600 disappears against the slate-800 surface
   AND the primary-900 hover. Use primary-400 default + primary-300
   on hover so the icons are clearly visible in both states. */
@media (prefers-color-scheme: dark) {
    .student-tool-card__icon {
        color: var(--color-primary-400);
    }

    .student-tool-card:hover .student-tool-card__icon,
    .student-tool-card:focus-visible .student-tool-card__icon {
        color: var(--color-primary-300);
    }
}

.student-tool-card__title {
    font-size: var(--text-base);
    font-weight: 600;
    margin: 0;
}

.student-tool-card__desc {
    font-size: var(--text-sm);
    margin: 0;
}

.student-tool-card__modes-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    margin-top: var(--space-1);
}

/* ── IDE Project Picker ────────────────────────────────────
   Shared between /tools/python and /tools/webdev.
   - .picker-section wraps each region (Start / Your projects)
   - .picker-grid is the responsive card grid
   - .picker-tile is the Start-section card (New project, templates)
   - .project-card is the Your-projects card with inline delete
*/

.picker-section {
    margin-bottom: var(--space-8);
}

.picker-section__header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
}

.picker-section__header .section-title {
    margin: 0;
}

.picker-sort {
    display: inline-flex;
    gap: var(--space-1);
}

.picker-sort__btn.is-active {
    background: var(--color-primary-50);
    border-color: var(--color-primary-300);
    color: var(--color-primary-700);
}

@media (prefers-color-scheme: dark) {
    .picker-sort__btn.is-active {
        background: var(--color-primary-900);
        border-color: var(--color-primary-700);
        color: var(--color-primary-200);
    }
}

.picker-grid {
    list-style: none;
    padding: 0;
    margin: 0;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
    gap: var(--space-4);
}

/* Make each <li> a flex container so the tile/card inside stretches
   to fill the grid cell — otherwise tiles size to content and end up
   shorter than the row height when their neighbours have more text. */
.picker-grid > li {
    display: flex;
}

.picker-grid--start {
    margin-bottom: var(--space-2);
}

.picker-tile {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-6) var(--space-4);
    background: var(--color-surface);
    border: 1px solid var(--color-surface-border);
    border-radius: var(--border-radius-lg);
    text-decoration: none;
    text-align: center;
    color: inherit;
    min-height: 10rem;
}

@media (prefers-reduced-motion: no-preference) {
    .picker-tile {
        transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
    }
}

.picker-tile:hover,
.picker-tile:focus-visible {
    /* Bumped from primary-300 to primary-400 + a heavier shadow so
       the hover read clearly on template tiles (the previous step
       was too subtle, especially on the dense picker grid). */
    border-color: var(--color-primary-400);
    box-shadow: 0 4px 12px rgba(15, 23, 42, 0.12);
    text-decoration: none;
}

.picker-tile--new {
    border-style: dashed;
    border-width: 2px;
    border-color: var(--color-primary-400);
    background: var(--color-primary-100);
    color: var(--color-primary-800);
}

.picker-tile--disabled {
    opacity: 0.55;
    cursor: not-allowed;
    background: var(--color-bg-page);
    border-style: dashed;
    border-color: var(--color-surface-border);
}

.picker-tile--disabled:hover,
.picker-tile--disabled:focus-visible {
    border-color: var(--color-surface-border);
    box-shadow: none;
}

/* Dark-mode picker tile palettes — primary-100/primary-800 flip
   directions on dark; replace with deep primary-900 + primary-200
   text so the "+ New project" tile reads as a tinted action surface
   on slate-800 instead of nearly white. */
@media (prefers-color-scheme: dark) {
    .picker-tile--new {
        background: var(--color-primary-900);
        color: var(--color-primary-200);
        border-color: var(--color-primary-700);
    }

    .picker-tile:hover,
    .picker-tile:focus-visible {
        /* Brighter hover ring in dark — primary-500 reads as a clear
           blue against the slate-800 surface. */
        border-color: var(--color-primary-500);
        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
    }
}

.picker-tile__icon {
    width: 3rem;
    height: 3rem;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--color-primary-600);
}

@media (prefers-color-scheme: dark) {
    .picker-tile__icon {
        color: var(--color-primary-300);
    }
}

.picker-tile__title {
    font-size: var(--text-base);
    font-weight: 600;
    margin: 0;
}

.picker-tile__desc {
    margin: 0;
}

.project-card {
    position: relative;
    flex: 1;
    background: var(--color-surface);
    border: 1px solid var(--color-surface-border);
    border-radius: var(--border-radius-lg);
    display: flex;
    align-items: stretch;
    min-height: 6rem;
}

@media (prefers-reduced-motion: no-preference) {
    .project-card {
        transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
    }
}

.project-card:hover,
.project-card:focus-within {
    border-color: var(--color-primary-300);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}

@media (prefers-color-scheme: dark) {
    .project-card:hover,
    .project-card:focus-within {
        border-color: var(--color-primary-700);
    }
}

.project-card__link {
    flex: 1;
    display: block;
    padding: var(--space-4) var(--space-4) var(--space-4) var(--space-4);
    padding-right: 3rem; /* leave room for the delete button */
    text-decoration: none;
    color: inherit;
    border-radius: var(--border-radius-lg);
    min-height: 2.75rem;
}

.project-card__link:hover,
.project-card__link:focus-visible {
    text-decoration: none;
}

.project-card__body {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.project-card__pill {
    align-self: flex-start;
    display: inline-block;
    padding: 0.125rem 0.5rem;
    font-size: var(--text-xs);
    font-weight: 600;
    background: var(--color-primary-50);
    color: var(--color-primary-700);
    border-radius: 999px;
    margin-bottom: var(--space-1);
}

@media (prefers-color-scheme: dark) {
    .project-card__pill {
        background: var(--color-primary-900);
        color: var(--color-primary-200);
    }
}

.project-card__title {
    font-size: var(--text-base);
    font-weight: 600;
    word-break: break-word;
}

.project-card__meta {
    margin: 0;
}

.project-card__delete {
    position: absolute;
    top: var(--space-2);
    right: var(--space-2);
    min-width: 2rem;
    min-height: 2rem;
    padding: var(--space-1);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--color-text-muted);
}

.project-card__delete:hover,
.project-card__delete:focus-visible {
    color: var(--color-danger, #dc2626);
    background: var(--color-danger-50, #fef2f2);
}

/* ── Recovery surface (unsaved-work) ───────────────────────
   Two visual elements driven by ide-picker.js when a localStorage
   backup is detected:
     1. .picker-tile--continue: the "Continue from unsaved" tile
        in the Start grid, when the backup has no id (orphan).
     2. .project-card--unsaved + .project-card__pill--unsaved:
        marks the existing project card whose id matches the
        backup. Same shape as the "Last opened" pill but amber
        so the urgency reads at a glance.
*/

.picker-tile--continue {
    border-color: var(--color-warning);
    background: var(--color-warning-bg);
}

.picker-tile--continue:hover,
.picker-tile--continue:focus-visible {
    border-color: var(--color-warning-strong);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}

.picker-tile--continue .picker-tile__icon {
    color: var(--color-warning-strong);
}

.project-card--unsaved {
    border-color: var(--color-warning);
}

.project-card--unsaved:hover,
.project-card--unsaved:focus-within {
    border-color: var(--color-warning-strong);
}

.project-card__pill--unsaved {
    background: var(--color-warning-bg);
    color: var(--color-warning-strong);
}

/* ── Assignment picker cards ─────────────────────────────── */

.picker-grid--assignments {
    margin-bottom: var(--space-2);
}

.assignment-card {
    position: relative;
    flex: 1;
    background: var(--color-surface);
    border: 1px solid var(--color-surface-border);
    border-left: 3px solid var(--color-primary-500);
    border-radius: var(--border-radius-lg);
    display: flex;
    align-items: stretch;
    min-height: 7rem;
}

/* Status-driven left border. Reads the pill class via :has() so the
   partial doesn't need to add status modifiers — the existing pill
   class is the single source of truth for the variant. The card-level
   .assignment-card--locked also works (already added by the partial)
   for the page-bg + hover overrides below. */
.assignment-card:has(.assignment-card__status--new) {
    border-left-color: var(--color-error);
}

.assignment-card:has(.assignment-card__status--active) {
    border-left-color: var(--color-success);
}

.assignment-card--locked,
.assignment-card:has(.assignment-card__status--locked) {
    border-left-color: var(--color-gray-400);
    /* gray-200 in light gives a clearly-grey card surface that's
       distinct from both the white surface and the cool page-bg.
       Earlier value (--color-bg-page) merged into the page bg, so
       the locked card looked see-through. Dark mode keeps bg-page
       (slate-900) — that genuinely sits below slate-800 surface
       and reads as recessed; gray-200 (#e5e7eb) doesn't flip and
       would look like a bright tile in dark mode. */
    background: var(--color-gray-200);
}

@media (prefers-color-scheme: dark) {
    .assignment-card--locked,
    .assignment-card:has(.assignment-card__status--locked) {
        background: var(--color-bg-page);
    }
}

@media (prefers-reduced-motion: no-preference) {
    .assignment-card {
        transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
    }
}

.assignment-card:hover,
.assignment-card:focus-within {
    border-color: var(--color-primary-300);
    border-left-color: var(--color-primary-600);
    background: var(--color-primary-50);
}

/* Preserve the status-coloured left border on hover — without these
   the green/red/amber accent would flip to blue every hover. */
.assignment-card:has(.assignment-card__status--new):hover,
.assignment-card:has(.assignment-card__status--new):focus-within {
    border-left-color: var(--color-error-strong);
}

.assignment-card:has(.assignment-card__status--active):hover,
.assignment-card:has(.assignment-card__status--active):focus-within {
    border-left-color: var(--color-success-strong);
}

/* Locked hover stays in the muted/grey family — locked = deactivated,
   not warning, so a primary-blue hover would mislead. Subtle bg lift
   from page-bg → surface-hover gives just enough interactive
   affordance (the card is still clickable to view). */
.assignment-card--locked:hover,
.assignment-card--locked:focus-within,
.assignment-card:has(.assignment-card__status--locked):hover,
.assignment-card:has(.assignment-card__status--locked):focus-within {
    background: var(--color-surface-hover);
    border-color: var(--color-surface-border);
    border-left-color: var(--color-gray-400);
}

.assignment-card__link:hover,
.assignment-card__link:focus-visible {
    text-decoration: none;
}

/* Dark-mode hover — primary-50 / warning-bg both need flipping. */
@media (prefers-color-scheme: dark) {
    .assignment-card:hover,
    .assignment-card:focus-within {
        background: var(--color-primary-900);
        border-color: var(--color-primary-700);
        border-left-color: var(--color-primary-400);
    }

    .assignment-card:has(.assignment-card__status--new):hover,
    .assignment-card:has(.assignment-card__status--new):focus-within {
        border-left-color: var(--color-error-strong);
    }

    .assignment-card:has(.assignment-card__status--active):hover,
    .assignment-card:has(.assignment-card__status--active):focus-within {
        border-left-color: var(--color-success-strong);
    }

    .assignment-card--locked:hover,
    .assignment-card--locked:focus-within,
    .assignment-card:has(.assignment-card__status--locked):hover,
    .assignment-card:has(.assignment-card__status--locked):focus-within {
        background: var(--color-surface-hover);
        border-color: var(--color-surface-border);
        /* Slate-500 override — gray-400 (#9ca3af) is too bright against
           slate-800 in dark mode and makes locked stand out MORE than
           non-locked. Slate-500 keeps the muted-but-visible feel. */
        border-left-color: #64748b;
    }

    /* Same dark-mode override for the resting (non-hover) locked state. */
    .assignment-card--locked,
    .assignment-card:has(.assignment-card__status--locked) {
        border-left-color: #64748b;
    }
}

.assignment-card__link {
    flex: 1;
    display: block;
    padding: var(--space-4);
    text-decoration: none;
    color: inherit;
    border-radius: var(--border-radius-lg);
    min-height: 2.75rem;
}

.assignment-card__body {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.assignment-card__status {
    align-self: flex-start;
    display: inline-block;
    padding: 0.125rem 0.5rem;
    font-size: var(--text-xs);
    font-weight: 600;
    border-radius: 999px;
    margin-bottom: var(--space-1);
}

.assignment-card__status--new {
    background: var(--color-error-bg);
    color: var(--color-error);
    /* 1px border in the -strong shade of the family. Flips
       automatically (red-700 light / red-400 dark) so the pill
       has a clearly-visible outline in both modes. Without it the
       dark error-bg (#3d1717) blends into the slate-800 card. */
    border: 1px solid var(--color-error-strong);
}

.assignment-card__status--active {
    background: var(--color-success-bg);
    color: var(--color-success-strong);
    border: 1px solid var(--color-success-strong);
}

.assignment-card__status--locked {
    /* Muted-grey treatment — locked = deactivated. Mirrors the
       .badge--muted recipe (surface-hover bg + text-body) so contrast
       hits AA in both light and dark modes. text-muted border for
       parity with the red/green pills' framed look. */
    background: var(--color-surface-hover);
    color: var(--color-text-body);
    border: 1px solid var(--color-text-muted);
}

/* Pill-on-hover inversion. On card hover the surface goes primary-50
   (default) or surface-hover (locked case) — both clash with at-rest
   pills that share the same hue family. All three pill variants
   invert on card hover to a solid capsule + high-contrast text so
   they read as "selected status" regardless of the hovered surface.
   Same shape, different colour family per pill. */
.assignment-card:hover .assignment-card__status--new,
.assignment-card:focus-within .assignment-card__status--new {
    background: var(--color-error);
    color: #fff;
    border-color: var(--color-error);
}

.assignment-card:hover .assignment-card__status--active,
.assignment-card:focus-within .assignment-card__status--active {
    background: var(--color-success);
    color: #fff;
    border-color: var(--color-success);
}

.assignment-card:hover .assignment-card__status--locked,
.assignment-card:focus-within .assignment-card__status--locked {
    background: var(--color-text-muted);
    color: var(--color-surface);
    border-color: var(--color-text-muted);
}

@media (prefers-color-scheme: dark) {
    .assignment-card__status--new {
        background: var(--color-error-bg);
        color: var(--color-error-strong);
    }

    .assignment-card:hover .assignment-card__status--new,
    .assignment-card:focus-within .assignment-card__status--new {
        /* Inversion in dark — light red capsule with deep-red text
           pops against the primary-900 hovered card surface.
           Border merges with the solid fill in dark too. */
        background: var(--color-error-strong);
        color: #450a0a;
        border-color: var(--color-error-strong);
    }

    .assignment-card:hover .assignment-card__status--active,
    .assignment-card:focus-within .assignment-card__status--active {
        /* success-strong in dark = green-400 — light green capsule
           with deep green text pops against primary-900 hover.
           Border merges with the solid fill. */
        background: var(--color-success-strong);
        color: #052e2b;
        border-color: var(--color-success-strong);
    }

    /* Locked pill: text-muted bg + surface text already flips
       automatically — slate-400 capsule + slate-800 text in dark
       still reads as a clear "selected status" against the
       primary-900 hovered card surface. No override needed. */
}

.assignment-card__title {
    font-size: var(--text-base);
    font-weight: 600;
    word-break: break-word;
}

.assignment-card__class,
.assignment-card__deadline {
    margin: 0;
}

/* ── Assignments list on the class detail page ────────────── */

.assignment-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.assignment-list__item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    background: var(--color-surface);
    border: 1px solid var(--color-surface-border);
    border-left: 3px solid var(--color-primary-500);
    border-radius: var(--border-radius-md, 0.5rem);
}

.assignment-list__item--locked {
    border-left-color: var(--color-gray-400);
    background: var(--color-bg-page);
}

.assignment-list__item--archived {
    border-left-color: var(--color-gray-400);
    opacity: 0.85;
}

.assignment-list__body {
    flex: 1 1 auto;
    min-width: 0;
}

.assignment-list__title {
    font-weight: 600;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    word-break: break-word;
}

.assignment-list__meta {
    margin-top: var(--space-1);
}

.assignment-list__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

/* ── Assignment banner inside the editor ─────────────────── */

.ide__assignment-banner,
.web-ide__assignment-banner {
    padding: var(--space-2) var(--space-4);
    background: var(--color-primary-50, #eef3ff);
    color: var(--color-primary-900, #0f172a);
    border-bottom: 1px solid var(--color-primary-200, #bfdbfe);
    font-size: var(--text-sm);
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-1);
}

.ide__assignment-banner--locked,
.web-ide__assignment-banner--locked {
    /* Muted-grey treatment — locked = deactivated, no warning. The
       page-bg + surface-border combo flips automatically in dark mode. */
    background: var(--color-bg-page);
    color: var(--color-text-muted);
    border-bottom-color: var(--color-surface-border);
}

.ide__assignment-banner-label,
.web-ide__assignment-banner-label {
    font-weight: 600;
}

.ide__assignment-banner-meta,
.web-ide__assignment-banner-meta {
    opacity: 0.85;
}

/* Phase 1c author-mode banner — amber so teachers can never confuse
   it with the assignment banner (blue, students see this). Uses the
   warning colour family because "author mode = not what students
   see" benefits from a strong visual flag. */
.ide__author-banner {
    padding: var(--space-2) var(--space-4);
    background: var(--color-warning-bg);
    color: var(--color-warning-strong);
    border-bottom: 1px solid var(--color-warning-strong);
    font-size: var(--text-sm);
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.ide__author-banner-label-wrap {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    min-width: 0;
}

.ide__author-banner-label {
    font-weight: 600;
}

.ide__author-banner-meta {
    opacity: 0.85;
}

/* Right-side cluster: copy-to-starter shortcut + the view switcher.
   Flex so they sit on one row at desktop, wrap to next line on
   narrow viewports without breaking the banner layout. */
.ide__author-banner-actions {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
}

/* Copy reference → starter button. Reads like a hint, not a
   primary action — small text-button styling so it doesn't fight
   the segmented control next to it. */
.ide__author-banner-copy {
    appearance: none;
    background: transparent;
    border: 1px solid var(--color-warning-strong);
    border-radius: 999px;
    color: var(--color-warning-strong);
    font-size: 0.8125rem;
    font-weight: 600;
    padding: 0.35rem 0.85rem;
    cursor: pointer;
    min-height: 1.75rem;
}

.ide__author-banner-copy:hover {
    background: var(--color-warning-bg);
}

/* Reference | Starter segmented control. Pill shape, two buttons
   sharing a tinted background; active button gets the warning-
   strong fill (matches the surrounding amber) with white text. */
.ide__author-switcher {
    display: inline-flex;
    border-radius: 999px;
    overflow: hidden;
    background: var(--color-surface);
    border: 1px solid var(--color-warning-strong);
}

.ide__author-switcher-btn {
    appearance: none;
    background: transparent;
    border: 0;
    color: var(--color-warning-strong);
    font-size: 0.8125rem;
    font-weight: 600;
    padding: 0.35rem 0.85rem;
    cursor: pointer;
    min-height: 1.75rem;
}

.ide__author-switcher-btn:hover {
    background: var(--color-warning-bg);
}

.ide__author-switcher-btn--active,
.ide__author-switcher-btn--active:hover {
    background: var(--color-warning-strong);
    color: #fff;
    cursor: default;
}

/* ── Assignment-form template picker ──────────────────────── */

.form-help-panel {
    padding: var(--space-3) var(--space-4);
    background: var(--color-gray-50, #f8fafc);
    border: 1px solid var(--color-gray-200);
    border-radius: var(--border-radius-md, 0.5rem);
}

.form-help-panel p {
    margin: 0;
}

/* ── Assignment reuse banner + picker modal ────────────────── */

.reuse-banner {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    padding: var(--space-3) var(--space-4);
    margin-bottom: var(--space-5);
    background: var(--color-primary-50);
    border: 1px solid var(--color-primary-200);
    border-radius: var(--border-radius-md, 0.5rem);
    flex-wrap: wrap;
}

@media (prefers-color-scheme: dark) {
    .reuse-banner {
        background: var(--color-primary-900);
        border-color: var(--color-primary-700);
        color: var(--color-primary-100);
    }
}

.reuse-banner__text {
    flex: 1 1 18rem;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.reuse-picker {
    position: fixed;
    inset: 0;
    z-index: 60;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* The `hidden` HTML attribute applies `display: none`, but the class
 * selector above wins on specificity. Re-assert so the modal is
 * actually hidden on page load and closes cleanly when the JS sets
 * `hidden = true`. */
.reuse-picker[hidden] {
    display: none;
}

.reuse-picker__backdrop {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.4);
}

.reuse-picker__panel {
    position: relative;
    background: var(--color-surface);
    border-radius: var(--radius);
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);
    width: 90%;
    max-width: 44rem;
    max-height: 85vh;
    display: flex;
    flex-direction: column;
}

.reuse-picker__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--space-4);
    border-bottom: 1px solid var(--color-surface-border);
}

.reuse-picker__title {
    margin: 0;
    font-size: var(--text-lg, 1.125rem);
    color: var(--color-text-strong);
}

.reuse-picker__filters {
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--color-surface-border);
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.reuse-picker__tabs {
    display: flex;
    gap: var(--space-1);
    flex-wrap: wrap;
}

.reuse-picker__tab {
    min-height: 2.75rem;
    padding: 0 var(--space-3);
    border: 1px solid var(--color-surface-border);
    background: var(--color-surface);
    color: var(--color-text-body);
    border-radius: 999px;
    font-size: var(--text-sm);
    cursor: pointer;
}

.reuse-picker__tab[aria-selected="true"] {
    background: var(--color-primary-600);
    color: #fff;
    border-color: var(--color-primary-600);
}

.reuse-picker__tab:focus-visible {
    outline: 2px solid var(--color-primary-500);
    outline-offset: 2px;
}

.reuse-picker__controls {
    display: flex;
    gap: var(--space-3);
    flex-wrap: wrap;
}

.reuse-picker__control {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    min-width: 8rem;
}

.reuse-picker__control--grow {
    flex: 1 1 16rem;
}

.reuse-picker__body {
    flex: 1;
    overflow-y: auto;
    padding: var(--space-2);
}

.reuse-picker__status {
    padding: var(--space-4);
    text-align: center;
    color: var(--color-text-muted);
}

.reuse-picker__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0;
}

.reuse-picker__item {
    min-height: 2.75rem;
    padding: var(--space-3) var(--space-4);
    border: 1px solid transparent;
    border-radius: var(--border-radius-md, 0.5rem);
    cursor: pointer;
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}

.reuse-picker__item:hover,
.reuse-picker__item:focus-visible {
    background: var(--color-primary-50);
    border-color: var(--color-primary-200);
    outline: none;
}

@media (prefers-color-scheme: dark) {
    .reuse-picker__item:hover,
    .reuse-picker__item:focus-visible {
        background: var(--color-primary-900);
        border-color: var(--color-primary-700);
    }
}

.reuse-picker__item-title {
    font-weight: 600;
    color: var(--color-text-strong);
    /* Defend against pathologically-long titles (rare in practice;
     * real assignment titles have spaces so wrap fine, but a single
     * unbroken 100-char string would push horizontal scroll on
     * mobile). */
    word-break: break-word;
}

.reuse-picker__item-meta {
    display: flex;
    gap: var(--space-2);
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    flex-wrap: wrap;
    align-items: center;
}

.reuse-picker__pill {
    padding: 0.125rem 0.5rem;
    border-radius: 999px;
    font-size: 0.6875rem;
    font-weight: 500;
    background: var(--color-surface-hover);
    color: var(--color-text-body);
}

.reuse-picker__pill--tool {
    background: var(--color-primary-50);
    color: var(--color-primary-700);
}

.reuse-picker__pill--archived {
    background: var(--color-warning-bg);
    color: var(--color-warning-strong);
}

@media (prefers-color-scheme: dark) {
    .reuse-picker__pill--tool {
        background: var(--color-primary-900);
        color: var(--color-primary-200);
    }
}

/* ── Student Dashboard Classes ────────────────────────────── */

.student-classes {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
    gap: var(--space-4);
}

.student-class-card {
    padding: var(--space-4);
    background: var(--color-surface);
    border: 1px solid var(--color-surface-border);
    border-radius: var(--border-radius-lg);
}

.student-class-card__name {
    font-size: var(--text-base);
    font-weight: 600;
    margin: 0;
}

.student-class-card__desc {
    font-size: var(--text-sm);
    margin: var(--space-1) 0 0;
}

.section-title {
    font-size: var(--text-lg);
    font-weight: 600;
    margin: 0 0 var(--space-3);
}


/* ── Tool Assignment (class detail) ──────────────────────── */

.tool-assignment {
    padding: var(--space-3) 0;
    border-bottom: 1px solid var(--color-gray-100);
}

.tool-assignment:last-child {
    border-bottom: none;
}

.tool-assignment__header {
    margin-bottom: var(--space-2);
}

.tool-assignment__modes {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.tool-assignment__badge {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
}

.tool-remove-btn {
    background: none;
    border: none;
    cursor: pointer;
    padding: 0 0.125rem;
    font-size: var(--text-base);
    line-height: 1;
    color: inherit;
    opacity: 0.6;
}

.tool-remove-btn:hover {
    opacity: 1;
}

.tool-manage-item {
    padding: var(--space-3) 0;
    border-bottom: 1px solid var(--color-gray-100);
}

.tool-manage-item:last-child {
    border-bottom: none;
}

.tool-manage-item__header {
    margin-bottom: var(--space-2);
}

.tool-manage-modes {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin-top: var(--space-2);
}

.tool-checkbox {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    cursor: pointer;
    min-height: 2.75rem;
}

.tool-checkbox--indent {
    padding-left: var(--space-6);
}


/* ── Tools fieldset on class creation form ────────────────── */

.form-tools {
    border: 1px solid var(--color-surface-border);
    border-radius: var(--radius-md);
    padding: var(--space-3) var(--space-4);
    background: var(--color-bg-page);
}

.form-tools legend {
    padding: 0 var(--space-2);
    font-weight: 600;
    color: var(--color-text-body);
}

.form-tools__hint {
    margin: 0 0 var(--space-3);
}

.form-tools__tier-options {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.form-tools__tier-option {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    padding: var(--space-3);
    background: var(--color-surface);
    border: 1px solid var(--color-surface-border);
    border-radius: var(--radius-sm);
    cursor: pointer;
    min-height: 2.75rem;
}

.form-tools__tier-option:hover {
    border-color: var(--color-primary-400);
}

.form-tools__tier-option input[type="radio"],
.form-tools__tier-option input[type="checkbox"] {
    margin-top: 0.25rem;
    flex: 0 0 auto;
}

.form-tools__tier-option span {
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
    font-size: var(--text-sm);
}

.form-tools__tier-option input:checked ~ span strong {
    color: var(--color-primary-700);
}

@media (prefers-color-scheme: dark) {
    /* Selected option title was primary-700 (dark blue, hard to read
       on the dark form-tools panel). Use primary-200 for visibility. */
    .form-tools__tier-option input:checked ~ span strong {
        color: var(--color-primary-200);
    }
}


/* ── Default tools (always-available tier controls) ───────── */
/*
   Lives at the top of the class tools card. Per-row segmented
   Tier 1/2/3 buttons for Web IDE, plus a collapsible per-student
   overrides panel. Python IDE gets a row with no controls (tiered
   support comes later). Hidden entirely for archived classes.
*/

.default-tools {
    padding: var(--space-3) 0;
    margin-bottom: var(--space-3);
    border-bottom: 1px solid var(--color-gray-200);
}

.default-tools__heading {
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin: 0 0 var(--space-3);
}

.default-tools__row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) 0;
}

.default-tools__name {
    flex: 1 1 12rem;
    min-width: 10rem;
}

.default-tools__tier-control {
    display: inline-flex;
    align-items: stretch;
    border: 1px solid var(--color-gray-300);
    border-radius: var(--radius-md);
    overflow: hidden;
    background: var(--color-surface);
}

.default-tools__tier-control--readonly {
    padding: 0.5rem var(--space-3);
    color: var(--color-text-muted);
    font-size: var(--text-sm);
}

.default-tools__tier-btn {
    appearance: none;
    border: none;
    background: transparent;
    color: var(--color-text-body);
    padding: 0.5rem var(--space-3);
    font-size: var(--text-sm);
    line-height: 1.2;
    cursor: pointer;
    border-right: 1px solid var(--color-gray-300);
    min-height: 2.25rem;
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    white-space: nowrap;
}

.default-tools__tier-btn:last-child {
    border-right: none;
}

.default-tools__tier-btn:hover {
    background: var(--color-surface-hover);
}

.default-tools__tier-btn--active,
.default-tools__tier-btn--active:hover {
    background: var(--color-primary-600);
    color: #fff;
}

/* Compact "Tier 2 — HTML + CSS" summary shown in view mode.
   Replaced by the segmented control + overrides toggle when
   Manage Tools is clicked. */
.default-tools__tier-summary {
    padding: 0.5rem var(--space-3);
    color: var(--color-text-body);
    font-size: var(--text-sm);
    font-weight: 500;
}

/* :not([hidden]) so the [hidden] attribute (display: none) wins
   when the row is in view mode — without this scope, display:
   inline-flex would override hidden. */
.default-tools__tier-edit:not([hidden]) {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
}

.default-tools__tier-btn-num {
    font-weight: 600;
}

.default-tools__tier-btn-label {
    font-size: 0.8125rem;
    color: var(--color-text-muted);
}

/* On the active (blue) button, the label lifts to a lighter shade
   so the text stays readable rather than fading into the background. */
.default-tools__tier-btn--active .default-tools__tier-btn-label {
    color: var(--color-primary-100);
}

/* Narrow viewports: drop the description to keep the segmented
   control from wrapping to two lines at awkward widths. The title
   attribute on each button surfaces the label on hover. */
@media (max-width: 640px) {
    .default-tools__tier-btn-label {
        display: none;
    }
}

.default-tools__overrides {
    padding: var(--space-3) var(--space-4);
    margin: var(--space-2) 0 var(--space-3);
    background: var(--color-bg-page);
    border: 1px solid var(--color-surface-border);
    border-radius: var(--radius-md);
}

.default-tools__overrides-hint {
    margin: 0 0 var(--space-3);
}

.default-tools__overrides-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.default-tools__override-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) 0;
    border-bottom: 1px solid var(--color-gray-100);
}

.default-tools__override-row:last-child {
    border-bottom: none;
}

.default-tools__override-name {
    flex: 1 1 10rem;
    min-width: 8rem;
    font-size: var(--text-sm);
}

.default-tools__override-controls {
    display: inline-flex;
    gap: var(--space-1);
    align-items: center;
}

.default-tools__override-btn {
    appearance: none;
    border: 1px solid var(--color-gray-300);
    background: var(--color-surface);
    color: var(--color-text-body);
    padding: 0.25rem 0.75rem;
    font-size: 0.8125rem;
    font-weight: 500;
    cursor: pointer;
    border-radius: var(--radius-sm);
    /* Matches .btn--sm — project-wide convention for compact
       inline buttons. Gives a predictable tap target on touch. */
    min-height: 2.25rem;
    min-width: 2.25rem;
}

.default-tools__override-btn:hover:not(.default-tools__override-btn--active) {
    background: var(--color-surface-hover);
}

.default-tools__override-btn--active {
    background: var(--color-primary-600);
    color: #fff;
    border-color: var(--color-primary-600);
}

.default-tools__override-btn--active:hover {
    background: var(--color-primary-700);
    border-color: var(--color-primary-700);
}

/* Override rows: extra ring to distinguish a teacher-pinned tier
   from the tier the student would inherit from the class. */
.default-tools__override-btn--override.default-tools__override-btn--active {
    box-shadow: 0 0 0 2px var(--color-amber-200, #fde68a);
}

.default-tools__override-clear {
    appearance: none;
    border: 1px solid var(--color-gray-300);
    background: var(--color-surface);
    color: var(--color-text-body);
    padding: 0.25rem 0.75rem;
    font-size: 0.8125rem;
    border-radius: var(--radius-sm);
    cursor: pointer;
    margin-left: var(--space-2);
}

.default-tools__override-clear:hover:not(:disabled) {
    background: var(--color-surface-hover);
}

.default-tools__override-clear:disabled {
    cursor: default;
    opacity: 0.6;
}

.default-tools__override-clear--active {
    background: var(--color-primary-600);
    color: #fff;
    border-color: var(--color-primary-600);
    opacity: 1;
}

.default-tools__override-clear--active:disabled {
    opacity: 1;
}


/* ── Inline panel (used inside cards for add-students, add-timetable, etc.) */

.inline-panel {
    padding: var(--space-4);
    margin-bottom: var(--space-4);
    background-color: var(--color-bg-page);
    border: 1px solid var(--color-surface-border);
    border-radius: var(--radius-md);
}

.inline-panel__title {
    font-size: var(--text-lg);
    font-weight: 600;
    margin: 0 0 var(--space-4) 0;
}


/* ── Binary Practice Tool ────────────────────────────────── */

.bp__stats {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    margin-bottom: var(--space-4);
}

.bp__score {
    font-size: var(--text-lg);
    font-weight: 600;
}

.bp__streak {
    font-size: var(--text-sm);
    color: var(--color-primary-600);
    font-weight: 500;
}

.bp__card {
    max-width: 36rem;
}

.bp__prompt {
    font-size: var(--text-xl);
    text-align: center;
    padding: var(--space-6) 0;
    line-height: 1.6;
}

.bp__value {
    font-family: var(--font-mono);
    letter-spacing: 0.05em;
}

.bp__value--binary {
    color: var(--color-primary-700);
}

.bp__value--decimal {
    color: var(--color-text-body);
}

.bp__operator {
    font-size: var(--text-lg);
    color: var(--color-text-muted);
    padding: 0 var(--space-2);
}

.bp__input {
    font-family: var(--font-mono);
    font-size: var(--text-lg);
    letter-spacing: 0.1em;
    text-align: center;
    max-width: 20rem;
}

.bp__input--correct {
    border-color: var(--color-success);
    background-color: var(--color-success-bg);
}

.bp__input--incorrect {
    border-color: var(--color-error);
    background-color: var(--color-error-bg);
}

.bp__feedback {
    margin-top: var(--space-4);
    padding: var(--space-3) var(--space-4);
    border-radius: var(--border-radius);
    font-weight: 500;
    text-align: center;
}

.bp__feedback:empty {
    display: none;
}

.bp__feedback--correct {
    background-color: var(--color-success-bg);
    color: var(--color-success);
}

.bp__feedback--incorrect {
    background-color: var(--color-error-bg);
    color: var(--color-error);
}


/* ── Pixel Editor Tool ────────────────────────────────────── */

.pe__layout {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.pe__sidebar {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    background: var(--color-surface);
    border: 1px solid var(--color-gray-200);
    border-radius: var(--border-radius-lg);
    padding: var(--space-4);
    box-shadow: var(--shadow-sm);
}

.pe__control-group {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.pe__control-row {
    display: flex;
    gap: var(--space-3);
    align-items: center;
}

.pe__control-row .form-group--inline {
    flex: 1;
    min-width: 0;
    margin-bottom: 0;
}

.pe__info {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    padding: var(--space-2) 0;
    border-top: 1px solid var(--color-gray-100);
    border-bottom: 1px solid var(--color-gray-100);
}

.pe__info strong {
    color: var(--color-text-body);
}

.pe__palette {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.pe__palette-slot {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-3);
    border: 2px solid var(--color-gray-200);
    border-radius: var(--border-radius);
    cursor: pointer;
    min-height: 2.75rem;
    background: var(--color-surface);
    position: relative;
}

.pe__palette-slot:hover {
    border-color: var(--color-gray-400);
}

.pe__palette-slot--active {
    border-color: var(--color-primary-600);
    box-shadow: 0 0 0 1px var(--color-primary-600);
}

.pe__palette-slot--hidden {
    display: none;
}

.pe__color-swatch {
    width: 1.5rem;
    height: 1.5rem;
    border: 1px solid var(--color-gray-400);
    border-radius: 0.1875rem;
    flex-shrink: 0;
}

.pe__color-label {
    font-family: var(--font-mono);
    font-size: var(--text-sm);
    color: var(--color-text-body);
    flex: 1;
}

.pe__color-edit-wrap {
    position: relative;
    width: 1.75rem;
    height: 1.75rem;
    flex-shrink: 0;
    border: 1px solid var(--color-gray-300);
    border-radius: var(--border-radius);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
}

.pe__color-edit-wrap:hover {
    background: var(--color-surface-hover);
    border-color: var(--color-gray-400);
}

.pe__color-edit-icon {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    line-height: 1;
    pointer-events: none;
}

.pe__color-input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
    border: none;
    padding: 0;
}

.pe__actions {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.pe__main {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    min-width: 0;
}

.pe__canvas-wrap {
    position: relative;
    border: 1px solid var(--color-gray-300);
    border-radius: var(--border-radius);
    overflow: hidden;
    /* The pixel-editor draws onto a <canvas> — this background shows
       through transparent pixels in the student's drawing. Treated as
       drawing canvas (analogous to the Web IDE preview iframe), NOT
       chrome, so it stays white in dark mode. */
    background: #ffffff;
    width: fit-content;
    max-width: 100%;
}

.pe__canvas {
    display: block;
    image-rendering: pixelated;
    image-rendering: -moz-crisp-edges;
    cursor: crosshair;
}

.pe__binary-wrap {
    border: 1px solid var(--color-surface-border);
    border-radius: var(--border-radius);
    background: var(--color-bg-page);
    overflow: hidden;
}

.pe__binary-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--space-2) var(--space-3);
    border-bottom: 1px solid var(--color-gray-200);
    background: var(--color-surface);
}

.pe__binary-output {
    font-family: var(--font-mono);
    font-size: var(--text-sm);
    word-break: break-all;
    padding: var(--space-3);
    line-height: 1.8;
    white-space: pre-wrap;
}

.pe__save-indicator {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
}

.pe__save-indicator--saving {
    color: var(--color-warning);
}

.pe__save-indicator--saved {
    color: var(--color-success);
}

.pe__save-indicator--error {
    color: var(--color-error);
}

@media (min-width: 768px) {
    .pe__layout {
        display: grid;
        grid-template-columns: 15rem 1fr;
        gap: var(--space-6);
        align-items: start;
    }

    .pe__sidebar {
        position: sticky;
        top: calc(var(--header-height) + var(--space-4));
    }
}


/* ── Responsive ───────────────────────────────────────────── */

@media (max-width: 767px) {
    .kb-topic-card {
        flex-direction: column;
        align-items: flex-start;
    }

    .kb-entry-card__header {
        flex-direction: column;
    }

    .kb-images {
        grid-template-columns: repeat(auto-fill, minmax(6rem, 1fr));
    }
}

@media (prefers-reduced-motion: no-preference) {
    .kb-images__delete {
        transition: opacity 0.15s;
    }
}

/* ─── Student Work Viewer ─────────────────────────────────────────── */

.student-work-filter {
    margin-bottom: var(--space-4);
    max-width: 20rem;
}

.student-work-group {
    margin-bottom: var(--space-6);
}

.student-work-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: var(--space-3);
    grid-template-columns: 1fr;
}

@media (min-width: 480px) {
    .student-work-list {
        grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
    }
}

.student-work-item {
    margin: 0;
    display: flex;
}

.student-work-item__link {
    flex: 1;
    display: block;
    padding: var(--space-4);
    border: 1px solid var(--color-surface-border);
    border-radius: var(--border-radius-lg);
    background: var(--color-surface);
    color: inherit;
    text-decoration: none;
    min-height: 2.75rem;
}

.student-work-item__link:hover,
.student-work-item__link:focus-visible {
    border-color: var(--color-primary-300);
    background: var(--color-primary-50);
    text-decoration: none;
    outline: none;
}

.student-work-item__title {
    display: block;
    font-weight: 500;
    margin-bottom: var(--space-1);
}

.student-work-item__meta {
    display: block;
}

.student-work-item__pill {
    display: inline-block;
    padding: 0.125rem 0.5rem;
    margin-bottom: var(--space-1);
    font-size: var(--text-xs);
    font-weight: 600;
    border-radius: 999px;
    background: var(--color-primary-50);
    color: var(--color-primary-700);
    border: 1px solid var(--color-primary-200);
}

.student-work-item--assignment .student-work-item__link {
    border-left: 3px solid var(--color-primary-500);
}

.student-work-item--locked .student-work-item__link {
    border-left-color: var(--color-gray-400);
    /* gray-200 in light = clearly-grey card surface. Dark mode keeps
       bg-page (slate-900) — see .assignment-card--locked above for
       the rationale on the per-mode split. */
    background: var(--color-gray-200);
}

.student-work-item--locked .student-work-item__pill {
    /* Muted-grey treatment — matches .assignment-card__status--locked.
       border-color drops to surface-border so the pill looks contained
       but doesn't compete with the (now grey) left accent. */
    background: var(--color-surface-hover);
    color: var(--color-text-body);
    border-color: var(--color-surface-border);
}

/* Locked items shouldn't turn blue on hover — stay in the muted/grey
   family so the deactivated context isn't lost. */
.student-work-item--locked .student-work-item__link:hover,
.student-work-item--locked .student-work-item__link:focus-visible {
    background: var(--color-surface-hover);
    border-color: var(--color-surface-border);
}

/* Pill-on-hover inversion (light mode) — same problem as the
   assignment-card pill: card hover bg primary-50 + pill bg primary-50
   = pill blends into hover. Invert to a solid mid-blue capsule. */
.student-work-item__link:hover .student-work-item__pill,
.student-work-item__link:focus-visible .student-work-item__pill {
    background: var(--color-primary-700);
    color: #fff;
    border-color: var(--color-primary-700);
}

/* Locked pill stays grey on hover (no inversion-to-blue from the
   default rule above). Slightly darker grey to give a subtle
   "selected" feel without breaking the deactivated semantic. */
.student-work-item--locked .student-work-item__link:hover .student-work-item__pill,
.student-work-item--locked .student-work-item__link:focus-visible .student-work-item__pill {
    background: var(--color-text-muted);
    color: var(--color-surface);
    border-color: var(--color-text-muted);
}

/* Dark mode parity with the assignment-card treatment — flip the
   primary-50 hover bg, the pill bg, the locked-pill border, and
   apply the pill-inversion-on-hover. */
@media (prefers-color-scheme: dark) {
    .student-work-item__link:hover,
    .student-work-item__link:focus-visible {
        background: var(--color-primary-900);
        border-color: var(--color-primary-700);
    }

    .student-work-item__pill {
        background: var(--color-primary-900);
        color: var(--color-primary-200);
        border-color: var(--color-primary-700);
    }

    /* Inverted pill on hover (dark) — light blue capsule with deep
       navy text pops against the primary-900 hover surface. */
    .student-work-item__link:hover .student-work-item__pill,
    .student-work-item__link:focus-visible .student-work-item__pill {
        background: var(--color-primary-300);
        color: var(--color-primary-900);
        border-color: var(--color-primary-300);
    }

    .student-work-item--locked .student-work-item__link {
        /* Slate-500 border override — gray-400 is too bright on
           slate-800 and makes locked stand out MORE than non-locked.
           bg-page override — gray-200 (#e5e7eb) doesn't flip and
           would look like a bright tile against the slate-900 page. */
        border-left-color: #64748b;
        background: var(--color-bg-page);
    }

    /* Light-mode rules already use surface-hover / surface-border /
       text-muted / text-body — all of which flip automatically in
       dark mode. No further dark-specific overrides needed for the
       locked pill or link hover. */
}

/* "My Work" grid on the student dashboard reuses the same list block */

/* ─── IDE Read-Only Banner (teacher viewer) ───────────────────────── */

.ide__readonly-banner {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-4);
    /* Muted-grey treatment — read-only is a deactivated context, not
       a warning. Tokens flip automatically in dark mode. */
    background: var(--color-bg-page);
    color: var(--color-text-muted);
    border-bottom: 1px solid var(--color-surface-border);
    font-size: 0.875rem;
    flex: 0 0 auto;
}

.ide__readonly-banner[hidden] {
    display: none;
}

.ide__readonly-banner svg {
    flex-shrink: 0;
    color: var(--color-text-muted);
}

.ide__readonly-banner-title {
    font-weight: 600;
}

/* Assignment prev/next nav inside the read-only banner. Appears on
   the right via margin-left:auto so the existing flex layout (icon +
   text span) stays untouched. */
.ide__readonly-banner-nav {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-left: auto;
    flex-wrap: wrap;
    justify-content: flex-end;
}

.ide__readonly-banner-nav-btn {
    display: inline-flex;
    align-items: center;
    padding: 0.25rem 0.625rem;
    background: transparent;
    border: 1px solid var(--color-surface-border);
    border-radius: 4px;
    color: var(--color-text-body);
    font-size: 0.813rem;
    font-weight: 500;
    text-decoration: none;
    line-height: 1.25;
    white-space: nowrap;
}

.ide__readonly-banner-nav-btn:hover {
    background: var(--color-surface-hover);
}

.ide__readonly-banner-nav-btn[aria-disabled="true"] {
    opacity: 0.4;
    cursor: not-allowed;
    pointer-events: none;
}

.ide__readonly-banner-nav-count {
    font-size: 0.813rem;
    color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
}

/* ─── Pixel Editor Viewer ─────────────────────────────────────── */

.pe-viewer {
    display: grid;
    gap: var(--space-6);
    grid-template-columns: 1fr;
}

@media (min-width: 768px) {
    .pe-viewer {
        grid-template-columns: minmax(0, 2fr) minmax(12rem, 1fr);
        align-items: start;
    }
}

.pe-viewer__canvas-wrap {
    display: flex;
    justify-content: center;
    width: 100%;
}

.pe-viewer__meta .details {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--space-1) var(--space-3);
    margin-bottom: var(--space-4);
}

.pe-viewer__meta dt {
    color: var(--color-text-muted, #6b7280);
    font-weight: 500;
}

.pe-viewer__palette {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.pe-viewer__palette-swatch {
    display: inline-block;
    width: 1.75rem;
    height: 1.75rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm, 4px);
}

.student-work-fallback__content {
    white-space: pre-wrap;
    word-break: break-word;
    font-family: var(--font-mono, ui-monospace, monospace);
    font-size: 0.875rem;
    margin: 0;
    max-height: 70vh;
    overflow-y: auto;
}

/* ─── Fullscreen scroll lock ─────────────────────────────────────────
   Applied to <html> and <body> by main.js (python + web-ide) while
   the IDE is fullscreen. Prevents the page behind from scrolling
   with mousewheel, touchpad, or keyboard when the IDE overlays the
   viewport. `overscroll-behavior: none` blocks rubber-band scroll
   propagation on iOS/macOS trackpads. */
html.ide-scroll-lock,
body.ide-scroll-lock {
    overflow: hidden;
    overscroll-behavior: none;
    touch-action: none;
}


/* ── Web IDE features page ──────────────────────────────────
   Standalone content page at /tools/webdev/features, linked from
   the IDE's Help modal via "See more features" (target=_blank).
   Narrow prose column on top of the app layout — no IDE chrome. */
.webide-features {
    max-width: 48rem;
}

.webide-features__section {
    margin-bottom: var(--space-8);
    padding-bottom: var(--space-6);
    border-bottom: 1px solid var(--color-surface-border);
}

.webide-features__section:last-of-type {
    border-bottom: 0;
}

.webide-features__section h2 {
    margin: 0 0 var(--space-3) 0;
    font-size: 1.375rem;
    color: var(--color-text-strong);
}

.webide-features__section h3 {
    margin: var(--space-4) 0 var(--space-2) 0;
    font-size: 1rem;
    color: var(--color-text-strong);
}

.webide-features__section p {
    margin: 0 0 var(--space-3) 0;
    line-height: 1.65;
    color: var(--color-text-body);
}

.webide-features__section ul {
    margin: 0 0 var(--space-3) var(--space-4);
    line-height: 1.7;
    color: var(--color-text-body);
}

.webide-features__section li {
    margin-bottom: var(--space-2);
}

.webide-features__section pre {
    /* Code block — slightly receded from the page surface in both
       modes (page-bg sits one tone below cards). */
    background: var(--color-bg-page);
    border: 1px solid var(--color-surface-border);
    border-radius: var(--border-radius);
    padding: var(--space-3);
    overflow-x: auto;
    margin: 0 0 var(--space-3) 0;
    font-size: 0.85rem;
    line-height: 1.5;
}

.webide-features__section code {
    /* Inline code — surface-hover gives a subtle "pill" tint that
       reads in both modes (gray-100 light, slate-700 dark). */
    background: var(--color-surface-hover);
    padding: 0.1em 0.3em;
    border-radius: 3px;
    font-size: 0.9em;
    color: var(--color-text-body);
}

.webide-features__section pre code {
    background: transparent;
    padding: 0;
    border-radius: 0;
    font-size: inherit;
    color: var(--color-text-strong);
}

.webide-features__table {
    width: 100%;
    margin: 0 0 var(--space-3) 0;
    border-collapse: collapse;
}

.webide-features__table td {
    padding: var(--space-1) var(--space-3);
    border-bottom: 1px solid var(--color-surface-border);
    vertical-align: top;
    font-size: 0.9rem;
}

.webide-features__table td:first-child {
    width: 40%;
    white-space: nowrap;
}

.webide-features__footer {
    margin-top: var(--space-6);
    text-align: center;
}


/* ── Public layout (privacy / terms) ─────────────────────────
   Minimal indexable chrome around legal pages reached by
   unauthenticated visitors. Reuses .webide-features prose styles
   for the body. */
.layout-public {
    background: var(--color-bg-page);
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}

.public-header {
    background: var(--color-surface);
    border-bottom: 1px solid var(--color-surface-border);
}

.public-header__inner,
.public-footer__inner {
    max-width: 56rem;
    margin: 0 auto;
    padding: var(--space-4) var(--space-6);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    flex-wrap: wrap;
}

.public-header__brand {
    display: inline-flex;
    align-items: center;
    gap: 0.55rem;
    font-weight: 700;
    font-size: 1.125rem;
    color: var(--color-text-strong);
    text-decoration: none;
}

/* Keep the brand at strong text colour on hover — overrides the
   default a:hover blue swap so the wordmark doesn't flash to a
   link state every time the cursor crosses it. */
.public-header__brand:hover {
    color: var(--color-text-strong);
    text-decoration: none;
}

.public-header__brand-icon {
    width: 26px;
    height: 26px;
    flex-shrink: 0;
}

@media (prefers-color-scheme: dark) {
    .public-header__brand-icon {
        filter: brightness(0) invert(1);
    }
}

.public-header__nav a,
.public-footer__links a {
    color: var(--color-text-muted);
    text-decoration: none;
    margin-left: var(--space-4);
}

.public-header__nav a:hover,
.public-footer__links a:hover {
    /* Routes through --color-link-hover (primary-700 light,
       primary-300 dark) — both AA+ on the public surface. */
    color: var(--color-link-hover);
    text-decoration: underline;
}

.public-main {
    flex: 1;
    padding: var(--space-8) var(--space-6);
    max-width: 56rem;
    width: 100%;
    margin: 0 auto;
    box-sizing: border-box;
}

.public-footer {
    background: var(--color-surface);
    border-top: 1px solid var(--color-surface-border);
    color: var(--color-text-muted);
    font-size: 0.875rem;
}

.public-footer__links a:first-child {
    margin-left: 0;
}


/* ── Share pages ───────────────────────────────────────────────
   Public /share/{slug} routes. Reuse the .public-* header/footer
   chrome and inject the share's title + attribution INTO the
   header on the right (next to the TeachKit brand) — was
   previously its own strip below the header but that's wasted
   vertical real-estate, especially on small screens.

   The unavailable stub doesn't pass shareMeta so the meta block
   isn't emitted there; the page reads as a plain TeachKit-
   branded error rather than "this share has a title".

   Layout uses flex on .public-header__inner (already row +
   space-between via the .public-* base styles) so the brand
   stays left and the meta block fills the rest right-aligned. */
.share-header-meta {
    /* Fill remaining row width to the right of the brand. min-width
       0 lets the truncation rules below actually trigger — without
       it, a long title would push the brand off-screen. */
    flex: 1;
    min-width: 0;
    margin-left: var(--space-4);
    text-align: right;
    overflow: hidden;
}

.share-header-meta__title {
    margin: 0;
    font-size: 1rem;
    font-weight: 600;
    color: var(--color-text-strong);
    line-height: 1.25;
    /* Single-line + ellipsis. Multi-line wrap would push the
       header taller than it should be. */
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.share-header-meta__byline {
    margin: 0;
    font-size: 0.8125rem;
    color: var(--color-text-muted);
    line-height: 1.25;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* On the narrowest viewports the title alone is more important
   than carrying the byline — drop it visually rather than
   shrinking everything. `display: none` removes it from the
   accessibility tree too, but the page's `<title>` element
   carries the work title (announced by screen readers on load),
   and the share content itself usually reveals authorship via
   names / context, so the loss is acceptable. */
@media (max-width: 480px) {
    .share-header-meta__byline {
        display: none;
    }
}

.share-fallback-card,
.share-unavailable-card {
    /* Centre at the natural .card width — feels less like a 404 page
       and more like a deliberate state. */
    max-width: 36rem;
    margin: 0 auto;
}

/* Lobotomized owl: every direct child after the first gets a
   reasonable top gap. Catches the h1 → p, p → p sequences without
   needing per-element rules. */
.share-fallback-card > * + *,
.share-unavailable-card > * + * {
    margin-top: var(--space-4);
}

.share-fallback-card__title {
    margin-top: 0;
}

/* Visit-TeachKit / similar action bar inside the share cards. The
   owl selector gives it the same space-4 as paragraphs, but a CTA
   feels under-anchored at that distance — bump it slightly so the
   button reads as a deliberate next step rather than another body
   element. */
.share-card-actions {
    margin-top: var(--space-6);
}

/* The Report link is the most actionable thing in the footer when a
   viewer thinks the content is wrong. Dim it slightly less than the
   other footer links so it's findable without being alarming. */
.share-footer__report {
    color: var(--color-warning-strong);
}

/* Share pages override .public-main's 56rem prose cap because the
   content is dominantly an interactive editor + output rather than
   reading material. Run-only mode self-constrains via
   .ide__share-run-only's own max-width (36rem); code mode wants
   close to viewport width on big monitors so the editor isn't
   pinched into a prose column.

   Made into a flex column so a child .ide can `flex: 1` and fill
   exactly the remaining viewport height — robust against changes
   to the share-page chrome (header, title strip, footer, padding)
   that would otherwise drift from any hard-coded "subtract Nrem
   from 100vh" math. .layout-public is already a flex column on
   the body, so this just continues the chain. */
.share-main {
    max-width: 100%;
    padding: var(--space-3) var(--space-4);
    display: flex;
    flex-direction: column;
}

@media (min-width: 768px) {
    .share-main {
        padding: var(--space-4) var(--space-6);
    }
}


/* ── Published-work overview at /work ──────────────────────────
   School-scoped safeguarding surface. Filters card sits above the
   table; per-row action buttons are inline with the row data. */
.work-filters {
    margin-bottom: var(--space-6);
}

/* Action button group inside a .form-row — aligns to the row's
   baseline, vertically centres with the inputs above the label
   row, and keeps the buttons together as the row wraps on narrow
   viewports. The form-row's own gap handles horizontal spacing
   between the actions group and other form-groups. */
.form-group--actions {
    display: flex;
    align-items: flex-end;
    gap: var(--space-2);
}

/* Read-only display of the active "filtered to one student" pill.
   Looks input-shaped without being editable — matches the rest of
   the filter form so the student name doesn't visually float. */
.form-input--readonly {
    background-color: var(--color-bg-page);
    cursor: not-allowed;
    margin: 0;
    display: flex;
    align-items: center;
}

/* Per-row action button cell on data tables. Right-aligned so the
   actions feel like a sticky end-of-row affordance rather than a
   data column. */
.table__actions-header {
    text-align: right;
}

.table__actions {
    text-align: right;
    white-space: nowrap;
}

.table__actions .btn + .btn {
    margin-left: var(--space-2);
}


/* ── Landing page ──────────────────────────────────────────────
   Public homepage at /. Hero is sized so a pupil on a typical
   classroom Chromebook sees the title + Sign-in button without
   needing to scroll. The descriptive sections live below for
   adults browsing in advance. */
.landing-hero {
    /* Subtle vertical gradient: surface (white in light, slate-800 in
       dark) fading into page-bg. Auto-flips correctly in both modes. */
    background: linear-gradient(180deg, var(--color-surface) 0%, var(--color-bg-page) 100%);
    border-bottom: 1px solid var(--color-surface-border);
    padding: var(--space-12) var(--space-4);
    text-align: center;
}

.landing-hero__inner {
    max-width: 36rem;
    margin: 0 auto;
}

.landing-hero__title {
    margin: 0 0 var(--space-3) 0;
    font-size: clamp(2.25rem, 6vw, 3.5rem);
    font-weight: 800;
    color: var(--color-text-strong);
    letter-spacing: -0.02em;
}

.landing-hero__tagline {
    margin: 0 0 var(--space-8) 0;
    font-size: 1.125rem;
    color: var(--color-text-body);
}

.btn--landing {
    width: auto;
    min-width: 16rem;
    padding: var(--space-4) var(--space-6);
    font-size: 1rem;
    font-weight: 600;
    min-height: 3rem;
}

.landing-hero__note {
    margin: var(--space-6) 0 0 0;
}

.landing-section {
    padding: var(--space-10) var(--space-6);
    border-bottom: 1px solid var(--color-surface-border);
}

.landing-section--students {
    background: var(--color-surface);
}

.landing-section--about {
    background: var(--color-surface);
}

.landing-section__inner {
    max-width: 48rem;
    margin: 0 auto;
}

.landing-section h2 {
    margin: 0 0 var(--space-4) 0;
    font-size: 1.5rem;
    color: var(--color-text-strong);
}

.landing-section__intro {
    margin: 0 0 var(--space-5) 0;
    line-height: 1.65;
    color: var(--color-text-body);
}

.landing-list {
    list-style: none;
    padding: 0;
    margin: 0;
}

.landing-list li {
    padding: var(--space-4) 0;
    border-top: 1px solid var(--color-surface-border);
    line-height: 1.65;
    color: var(--color-text-body);
}

.landing-list li:last-child {
    border-bottom: 1px solid var(--color-surface-border);
}

.landing-list strong {
    color: var(--color-text-strong);
    font-weight: 600;
}

.landing-list--plain li {
    border-top: 0;
    border-bottom: 0;
    padding: var(--space-2) 0;
}

.landing-cta {
    background: var(--color-bg-page);
    padding: var(--space-12) var(--space-6);
    text-align: center;
}

.landing-cta__inner {
    max-width: 32rem;
    margin: 0 auto;
}

.landing-cta__title {
    margin: 0 0 var(--space-6) 0;
    font-size: 1.5rem;
    color: var(--color-text-strong);
}

@media (min-width: 768px) {
    .landing-hero {
        padding: var(--space-16) var(--space-6);
    }

    .landing-section {
        padding: var(--space-12) var(--space-6);
    }
}

/* ─────────────────────────────────────────────────────────────
 * Template save modal — used by all save-stateful tools' editors
 * for the in-editor "Save as template" flow. Markup lives in
 * templates/partials/template-save-modal.php; behaviour in
 * public/assets/js/modules/template-modal.js.
 * ────────────────────────────────────────────────────────────── */

.template-modal {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-4);
}

.template-modal[hidden] {
    display: none;
}

.template-modal__backdrop {
    position: absolute;
    inset: 0;
    background: rgba(15, 23, 42, 0.6);
}

.template-modal__dialog {
    position: relative;
    /* Was --color-white (undefined token, fell through to white).
       Use --color-surface so the dialog flips with the rest of the
       site in dark mode. */
    background: var(--color-surface);
    border-radius: var(--radius-lg, 0.75rem);
    box-shadow: 0 20px 50px -10px rgba(15, 23, 42, 0.45);
    width: 100%;
    max-width: 32rem;
    max-height: calc(100vh - var(--space-8));
    overflow-y: auto;
    padding: var(--space-6);
}

.template-modal__header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-4);
    margin-bottom: var(--space-4);
}

.template-modal__title {
    margin: 0;
    font-size: 1.25rem;
    color: var(--color-text-strong);
}

.template-modal__close {
    background: transparent;
    border: 0;
    font-size: 1.5rem;
    line-height: 1;
    color: var(--color-text-muted);
    cursor: pointer;
    padding: var(--space-1) var(--space-2);
    border-radius: var(--radius);
    min-height: 2.75rem;
    min-width: 2.75rem;
}

.template-modal__close:hover,
.template-modal__close:focus {
    color: var(--color-text-strong);
    background: var(--color-surface-hover);
}

body.template-modal-open {
    overflow: hidden;
}

/* Modal styles deliberately don't animate by default — opens
 * instantly so screen readers announce the dialog content
 * immediately. If you want a fade-in, wrap a transition in a
 * `prefers-reduced-motion: no-preference` block. */


/* ─────────────────────────────────────────────────────────────
 * Publish dialog — used by every save-stateful tool's editor to
 * manage a piece of work's public-share lifecycle. Markup in
 * templates/partials/publish-dialog.php; behaviour in
 * public/assets/js/modules/publish-dialog.js.
 *
 * Reuses the modal scaffolding pattern from .template-modal but
 * with its own class tree so the two can evolve independently.
 * Three states (not-published / published / banned) plus a loading
 * overlay are all in the same partial; JS toggles `hidden`.
 * ────────────────────────────────────────────────────────────── */

.publish-dialog {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-4);
}

.publish-dialog[hidden] {
    display: none;
}

.publish-dialog__backdrop {
    position: absolute;
    inset: 0;
    background: rgba(15, 23, 42, 0.6);
}

.publish-dialog__panel {
    position: relative;
    background: var(--color-surface);
    border-radius: var(--radius-lg, 0.75rem);
    box-shadow: 0 20px 50px -10px rgba(15, 23, 42, 0.45);
    width: 100%;
    max-width: 32rem;
    max-height: calc(100vh - var(--space-8));
    overflow-y: auto;
    padding: var(--space-6);
}

.publish-dialog__header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-4);
    margin-bottom: var(--space-4);
}

.publish-dialog__title {
    margin: 0;
    font-size: 1.25rem;
    color: var(--color-text-strong);
}

.publish-dialog__close {
    background: transparent;
    border: 0;
    font-size: 1.5rem;
    line-height: 1;
    color: var(--color-text-muted);
    cursor: pointer;
    padding: var(--space-1) var(--space-2);
    border-radius: var(--radius);
    min-height: 2.75rem;
    min-width: 2.75rem;
}

.publish-dialog__close:hover,
.publish-dialog__close:focus {
    color: var(--color-text-strong);
    background: var(--color-surface-hover);
}

.publish-dialog__body > section + section,
.publish-dialog__body > section > * + * {
    margin-top: var(--space-4);
}

.publish-dialog__body p:first-child {
    margin-top: 0;
}

/* Share-URL row in the published state. Input + Copy button live
   side-by-side on wide viewports; stack vertically on narrow. */
.publish-dialog__url-row {
    margin-top: var(--space-4);
}

.publish-dialog__url-controls {
    display: flex;
    align-items: stretch;
    gap: var(--space-2);
    margin-top: var(--space-2);
}

.publish-dialog__url-controls .form-input {
    flex: 1;
    min-width: 0;
    /* Tabular feel — share URLs are single-line strings, not prose. */
    font-family: var(--font-family-mono, monospace);
    font-size: 0.875rem;
}

@media (max-width: 480px) {
    .publish-dialog__url-controls {
        flex-direction: column;
    }
}

/* Per-tool options slot. Spacing handled by the form fieldset
   inside the slot — nothing extra here. */
.publish-dialog__options {
    margin-top: var(--space-4);
}

.publish-dialog__options:empty {
    display: none;
}

/* Action row sits at the bottom of each state's section. Mirror the
   primary/secondary order used elsewhere — primary action on the
   left so the eye lands on it first, dangerous action separated. */
.publish-dialog__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin-top: var(--space-6);
}

/* Loading overlay sits on top of the body during API calls.
   Translucent surface so the user can still see context but knows
   they can't interact. */
.publish-dialog__loading {
    position: absolute;
    inset: 0;
    background: rgba(255, 255, 255, 0.85);
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-3);
    border-radius: var(--radius-lg, 0.75rem);
    color: var(--color-text-muted);
    font-size: 0.875rem;
}

.publish-dialog__loading[hidden] {
    display: none;
}

@media (prefers-color-scheme: dark) {
    .publish-dialog__loading {
        background: rgba(15, 23, 42, 0.85);
    }
}

@media (prefers-reduced-motion: no-preference) {
    .publish-dialog__spinner {
        width: 1.25rem;
        height: 1.25rem;
        border: 2px solid var(--color-surface-border);
        border-top-color: var(--color-primary-600);
        border-radius: 50%;
        animation: publish-dialog-spin 1s linear infinite;
    }

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

@media (prefers-reduced-motion: reduce) {
    /* Replace the spinning ring with a static dot — same visual
       affordance ("something is happening") without motion. */
    .publish-dialog__spinner {
        width: 0.5rem;
        height: 0.5rem;
        border-radius: 50%;
        background: var(--color-primary-600);
    }
}

body.publish-dialog-open {
    overflow: hidden;
}

/* "Out of sync" banner shown above the share URL when the
   student has unpublished changes. Amber to read as a hint
   ("press Update share when you're ready"), not red (no error,
   no urgency). The icon is an alert triangle for visual weight
   without being alarming. */
.publish-dialog__sync-banner {
    display: flex;
    gap: var(--space-2);
    align-items: flex-start;
    padding: var(--space-3) var(--space-4);
    background: var(--color-warning-bg);
    color: var(--color-warning-strong);
    border: 1px solid var(--color-warning-strong);
    border-radius: var(--border-radius-md);
    font-size: 0.9rem;
    line-height: 1.4;
    margin-top: var(--space-3);
}

.publish-dialog__sync-banner[hidden] {
    display: none;
}

.publish-dialog__sync-banner svg {
    flex-shrink: 0;
    margin-top: 0.1em;
}

/* ── Publish toolbar button — three appearance states ──────────
   Shared by the Python IDE and the Web IDE — both apply the
   `ide__btn-publish` class plus the same modifier classes below.
   Lives in app.css (not python.css / web-ide.css) so a single
   source serves every save-stateful editor that hooks into the
   shared publish-dialog module.

   Default (no modifier): inherits .btn--secondary look — neutral,
   says "you could publish this".

   .ide__btn-publish--published: subtle indicator that the work IS
   currently published. Same secondary base; just a green dot via
   ::before so a quick glance reads "online" without dominating
   the toolbar.

   .ide__btn-publish--pending: amber styling. Fires when the
   student has unpublished edits ahead of the public version. The
   colour shift is the unmissable signal — easy to spot on a
   wide-screen IDE where small toolbar status changes get lost. */

.ide__btn-publish--published::before {
    content: '';
    display: inline-block;
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 50%;
    background: var(--color-success-strong);
    margin-right: var(--space-1);
    flex-shrink: 0;
    /* Vertically centre the dot relative to the button text. */
    transform: translateY(-1px);
}

.ide__btn-publish--pending,
.ide__btn-publish--pending:hover {
    background: var(--color-warning-bg);
    border-color: var(--color-warning-strong);
    color: var(--color-warning-strong);
}

.ide__btn-publish--pending:hover {
    /* Slight darken on hover, dark-mode-friendly via the same
       --color-warning-bg token (which flips in dark mode). */
    filter: brightness(0.96);
}

.ide__btn-publish--pending::before {
    /* Pulsing amber dot for extra attention. Skipped under
       prefers-reduced-motion (per the project's a11y stance). */
    content: '';
    display: inline-block;
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 50%;
    background: var(--color-warning-strong);
    margin-right: var(--space-1);
    flex-shrink: 0;
    transform: translateY(-1px);
}

@media (prefers-reduced-motion: no-preference) {
    .ide__btn-publish--pending::before {
        animation: ide-publish-pulse 1.4s ease-in-out infinite;
    }
}

@keyframes ide-publish-pulse {
    0%, 100% { opacity: 1; }
    50%      { opacity: 0.45; }
}

/* Python share options provider — auto-run checkbox sits below the
   mode radios in its own row. The standalone label keeps it visually
   separate from the radio fieldset above (different question, no
   business sharing the same tier-options container). */
.publish-options-python__autorun {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-top: var(--space-3);
    color: var(--color-text-body);
    font-size: 0.95rem;
    cursor: pointer;
}

.publish-options-python__autorun input[type="checkbox"] {
    /* Bigger hit target than the browser default — easier to tap on
       a tablet, accessible on touch. */
    width: 1.1rem;
    height: 1.1rem;
    flex-shrink: 0;
}

/* ─────────────────────────────────────────────────────────────
 * Template owner banner — appears when a teacher opens
 * `?template={slug}` for a template they own. Behaviour in
 * public/assets/js/modules/template-modal.js (mountTemplateOwnerBanner).
 * ────────────────────────────────────────────────────────────── */

.template-owner-banner {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-3);
    background: var(--color-primary-50);
    color: var(--color-primary-900);
    border: 1px solid var(--color-primary-200);
    border-radius: var(--border-radius-lg);
    padding: var(--space-3) var(--space-4);
    margin-bottom: var(--space-4);
}

@media (prefers-color-scheme: dark) {
    /* "Editing template" banner — flip the primary-50/900/200 triplet
       to deep-navy bg + light text so it reads as a tinted notice on
       the dark editor surface. */
    .template-owner-banner {
        background: var(--color-primary-900);
        color: var(--color-primary-100);
        border-color: var(--color-primary-700);
    }
}

/* The Discard button is .btn--ghost which sets text-muted explicitly.
   On the primary-tinted banner that fails AA in both modes (light:
   gray-600 on primary-50 = ~6:1 OK; dark: slate-400 on primary-900
   only ~4:1, fails AA). Use color: inherit so the button picks up
   the banner's coordinated text colour (primary-900 light /
   primary-100 dark) and stays distinct from the tinted bg. */
.template-owner-banner .btn--ghost {
    color: inherit;
}

.template-owner-banner .btn--ghost:hover,
.template-owner-banner .btn--ghost:focus-visible {
    color: inherit;
    /* Step up one shade of the same primary family — keeps the hover
       in the banner's hue rather than going neutral grey. */
    background-color: var(--color-primary-100);
}

@media (prefers-color-scheme: dark) {
    .template-owner-banner .btn--ghost:hover,
    .template-owner-banner .btn--ghost:focus-visible {
        background-color: var(--color-primary-800);
    }
}

.template-owner-banner__title {
    font-size: 0.875rem;
    line-height: 1.5;
}

.template-owner-banner__title strong {
    font-weight: 600;
}

.template-owner-banner__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

@media (min-width: 480px) {
    .template-owner-banner {
        flex-direction: row;
        align-items: center;
        justify-content: space-between;
    }
}

/* ─────────────────────────────────────────────────────────────
   Lesson Mode — live in-class fullscreen view
   ───────────────────────────────────────────────────────────── */

.lesson-mode {
    position: fixed;
    inset: 0;
    /* Above .header (z-index: 100) and any sticky chrome. */
    z-index: 110;
    background: var(--color-bg-page);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

/* Lock page scroll behind the lesson overlay so a stray mousewheel
   doesn't move the layout underneath. JS adds this on mount, removes
   it on unload. */
body.lesson-mode-active {
    overflow: hidden;
}

.lesson-mode__topbar {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    padding: var(--space-3) var(--space-4);
    background: var(--color-surface);
    border-bottom: 1px solid var(--color-surface-border);
    flex-wrap: wrap;
}

.lesson-mode__topbar-left {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
    flex: 1 1 auto;
    min-width: 0;
}

.lesson-mode__back {
    color: var(--color-text-muted);
    text-decoration: none;
    font-size: 0.875rem;
    min-height: 2.75rem;
    display: inline-flex;
    align-items: center;
}

.lesson-mode__back:hover { color: var(--color-text-strong); }

/* Title + "Started" stacked as a single heading block so the
   alignment with sibling controls (Back link, topic input) is
   driven by the centre of the block, not by the title text alone. */
.lesson-mode__heading {
    display: flex;
    flex-direction: column;
    gap: 2px;
    line-height: 1.1;
}

.lesson-mode__title {
    margin: 0;
    font-size: 1.125rem;
    color: var(--color-text-strong);
    line-height: 1.2;
}

.lesson-mode__started {
    font-size: 0.75rem;
    color: var(--color-text-muted);
    line-height: 1;
}

.lesson-mode__topic-wrap {
    display: flex;
    flex: 1 1 16rem;
    min-width: 12rem;
    max-width: 28rem;
}

.lesson-mode__topic {
    width: 100%;
    border: 1px solid var(--color-input-border);
    background: var(--color-input-bg);
    color: var(--color-text-body);
    border-radius: var(--radius-sm, 0.25rem);
    padding: var(--space-2) var(--space-3);
    font-family: inherit;
    font-size: 0.875rem;
    min-height: 2.5rem;
}

.lesson-mode__topic:focus-visible {
    outline: 2px solid var(--color-primary-700);
    outline-offset: 2px;
}

.lesson-mode__topbar-actions {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.lesson-mode__layout {
    flex: 1 1 auto;
    display: grid;
    grid-template-columns: 1fr;
    overflow: hidden;
}

@media (min-width: 768px) {
    .lesson-mode__layout {
        grid-template-columns: 1fr 22rem;
    }
}

.lesson-mode__main {
    overflow-y: auto;
    padding: var(--space-4);
}

.lesson-mode__empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    height: 100%;
    color: var(--color-text-muted);
    gap: var(--space-2);
}

.lesson-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
    gap: var(--space-3);
}

/* Pupil card */

.lesson-card {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding: var(--space-3);
    background: var(--color-surface);
    border: 1px solid var(--color-surface-border);
    border-radius: var(--radius-md, 0.5rem);
    transition: border-color 0.15s ease, transform 0.15s ease;
    /* Anchor for .lesson-card__flag-popover. */
    position: relative;
}

.lesson-card--absent {
    opacity: 0.4;
    background: var(--color-bg-page);
}

.lesson-card--absent .lesson-card__actions,
.lesson-card--absent .lesson-card__note-btn { pointer-events: none; }

.lesson-card__header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: var(--space-2);
    min-height: 1.5rem;
}

.lesson-card__name {
    font-weight: 600;
    color: var(--color-text-strong);
    font-size: 0.95rem;
    line-height: 1.2;
    overflow: hidden;
    text-overflow: ellipsis;
    -webkit-line-clamp: 2;
    display: -webkit-box;
    -webkit-box-orient: vertical;
}

.lesson-card__indicators {
    display: flex;
    gap: 4px;
    flex-shrink: 0;
}

.lesson-card__flag,
.lesson-card__sentiment {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    display: inline-block;
}

.lesson-card__flag--alert { background: var(--color-error-strong); }
.lesson-card__flag--info { background: var(--color-primary-700); }
.lesson-card__sentiment--positive { background: var(--color-success); }
.lesson-card__sentiment--neutral { background: var(--color-text-muted); }
.lesson-card__sentiment--concern { background: var(--color-warning-strong); }

/* Flag indicator trigger — looks like a cluster of dots, but is a
   real button so keyboard + screen-reader users can open the
   popover. Hover ring hints at interactivity without competing
   with the dots themselves. */
.lesson-card__flag-btn {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 4px;
    margin: -4px;
    background: transparent;
    border: 0;
    border-radius: 999px;
    cursor: pointer;
    color: inherit;
}

.lesson-card__flag-btn:hover,
.lesson-card__flag-btn:focus-visible {
    background: var(--color-surface-hover);
    outline: none;
}

.lesson-card__flag-btn[aria-expanded="true"] {
    background: var(--color-surface-hover);
}

/* Popover anchored to the card's top-right (where the dots live).
   Width is capped so it doesn't stretch the layout — flag text
   wraps inside. Stacked above siblings via z-index so it overlays
   neighbouring cards without taking the whole screen. */
.lesson-card__flag-popover {
    position: absolute;
    top: calc(100% - var(--space-2));
    right: var(--space-3);
    z-index: 30;
    min-width: 14rem;
    max-width: min(20rem, calc(100vw - 2rem));
    padding: var(--space-2) var(--space-3);
    background: var(--color-surface);
    border: 1px solid var(--color-surface-border);
    border-radius: var(--radius-sm, 0.25rem);
    box-shadow: var(--shadow-md);
    color: var(--color-text-body);
    font-size: 0.875rem;
}

.lesson-card__flag-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.lesson-card__flag-item {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--space-2);
    align-items: start;
}

.lesson-card__flag-badge {
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 2px 8px;
    border-radius: 999px;
    border: 1px solid transparent;
    white-space: nowrap;
}

.lesson-card__flag-badge--alert {
    background: var(--color-error-bg);
    color: var(--color-error-strong);
    border-color: var(--color-error-strong);
}

.lesson-card__flag-badge--info {
    background: var(--color-info-bg);
    color: var(--color-primary-700);
    border-color: var(--color-primary-700);
}

.lesson-card__flag-text {
    color: var(--color-text-body);
    line-height: 1.4;
    word-break: break-word;
}

@media (prefers-color-scheme: dark) {
    .lesson-card__flag-badge--info {
        color: var(--color-primary-200);
        border-color: var(--color-primary-400);
    }
}

/* Picker — flag accordion. Same flag-item/badge classes as the card
   popover so visual treatment is consistent across surfaces. */
.lesson-picker__flags[hidden] { display: none; }

.lesson-picker__flags {
    margin: var(--space-2) 0 var(--space-3);
    padding: var(--space-2) var(--space-3);
    background: var(--color-bg-page);
    border: 1px solid var(--color-surface-border);
    border-radius: var(--radius-sm, 0.25rem);
    text-align: left;
}

.lesson-picker__flags-summary {
    cursor: pointer;
    font-size: 0.875rem;
    color: var(--color-text-muted);
    list-style: revert;
    padding: 2px 0;
}

.lesson-picker__flags[open] .lesson-picker__flags-summary {
    color: var(--color-text-strong);
    margin-bottom: var(--space-2);
}

.lesson-picker__flags-summary:focus-visible {
    outline: 2px solid var(--color-primary-700);
    outline-offset: 2px;
    border-radius: var(--radius-sm, 0.25rem);
}

/* Recovery banner — non-modal, sits below the topbar. Amber palette
   to read as "attention, but not urgent" — same colour family as the
   topic callout in the end-of-lesson review. */
.lesson-mode__recovery-banner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    flex-wrap: wrap;
    padding: var(--space-2) var(--space-3);
    background: var(--color-warning-bg);
    border-bottom: 1px solid var(--color-warning-strong);
    color: var(--color-text-body);
    font-size: 0.875rem;
}

.lesson-mode__recovery-text strong {
    color: var(--color-text-strong);
}

.lesson-mode__recovery-actions {
    display: flex;
    gap: var(--space-2);
    flex-shrink: 0;
}

.lesson-card__actions {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--space-1);
}

.lesson-tap {
    min-height: 2.75rem;
    border: 1px solid var(--color-surface-border);
    background: var(--color-surface);
    color: var(--color-text-body);
    border-radius: var(--radius-sm, 0.25rem);
    cursor: pointer;
    font-size: 1.25rem;
    font-weight: 700;
    line-height: 1;
    transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.lesson-tap:hover { background: var(--color-surface-hover); }
.lesson-tap:focus-visible { outline: 2px solid var(--color-primary-700); outline-offset: 2px; }

.lesson-tap--positive:hover {
    background: var(--color-success-bg);
    border-color: var(--color-success-strong);
    color: var(--color-success-strong);
}
.lesson-tap--concern:hover {
    background: var(--color-error-bg);
    border-color: var(--color-error-strong);
    color: var(--color-error-strong);
}

.lesson-card--flash-positive { animation: lessonFlashPositive 0.5s ease; }
.lesson-card--flash-neutral { animation: lessonFlashNeutral 0.5s ease; }
.lesson-card--flash-concern { animation: lessonFlashConcern 0.5s ease; }

@media (prefers-reduced-motion: no-preference) {
    @keyframes lessonFlashPositive {
        0% { background: var(--color-success-bg); }
        100% { background: var(--color-surface); }
    }
    @keyframes lessonFlashNeutral {
        0% { background: var(--color-surface-hover); }
        100% { background: var(--color-surface); }
    }
    @keyframes lessonFlashConcern {
        0% { background: var(--color-error-bg); }
        100% { background: var(--color-surface); }
    }
}

.lesson-card__footer {
    display: flex;
    justify-content: space-between;
    gap: var(--space-1);
    flex-wrap: wrap;
}

.lesson-card__note-btn,
.lesson-card__absent-btn {
    border: none;
    background: none;
    color: var(--color-text-muted);
    cursor: pointer;
    padding: 4px 6px;
    font-size: 0.75rem;
    border-radius: var(--radius-sm, 0.25rem);
    min-height: 1.75rem;
}

.lesson-card__note-btn:hover,
.lesson-card__absent-btn:hover {
    background: var(--color-surface-hover);
    color: var(--color-text-strong);
}

.lesson-card__absent-btn[aria-pressed="true"] {
    color: var(--color-warning-strong);
}

/* Inline note editor */

.lesson-card__note-editor {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding-top: var(--space-2);
    border-top: 1px solid var(--color-surface-border);
}

.lesson-card__note-input {
    width: 100%;
    border: 1px solid var(--color-input-border);
    background: var(--color-input-bg);
    color: var(--color-text-body);
    border-radius: var(--radius-sm, 0.25rem);
    padding: var(--space-2);
    font-family: inherit;
    font-size: 0.875rem;
    resize: vertical;
}

.lesson-card__note-sentiments {
    display: flex;
    gap: var(--space-1);
    flex-wrap: wrap;
}

.lesson-card__note-sentiment {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 0.75rem;
    color: var(--color-text-muted);
    cursor: pointer;
}

.lesson-card__note-sentiment input { margin: 0; }

.lesson-card__note-actions {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-1);
}

/* Timeline rail */

.lesson-mode__timeline {
    background: var(--color-surface);
    border-left: 1px solid var(--color-surface-border);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.lesson-mode__timeline-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--color-surface-border);
}

.lesson-mode__timeline-title {
    margin: 0;
    font-size: 0.875rem;
    color: var(--color-text-strong);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.lesson-mode__timeline-count {
    background: var(--color-surface-hover);
    color: var(--color-text-body);
    font-size: 0.75rem;
    padding: 2px 8px;
    border-radius: 999px;
    font-weight: 600;
}

.lesson-mode__timeline-list {
    list-style: none;
    margin: 0;
    padding: 0;
    overflow-y: auto;
    flex: 1 1 auto;
}

.lesson-mode__timeline-empty {
    padding: var(--space-4);
    color: var(--color-text-muted);
    font-size: 0.875rem;
    line-height: 1.5;
}

.lesson-timeline__entry {
    display: grid;
    grid-template-columns: auto 1fr auto;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
    border-bottom: 1px solid var(--color-surface-border);
    align-items: start;
}

.lesson-timeline__icon {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    margin-top: 6px;
}

.lesson-timeline__icon--positive { background: var(--color-success-strong); }
.lesson-timeline__icon--neutral { background: var(--color-text-muted); }
.lesson-timeline__icon--concern { background: var(--color-error-strong); }
.lesson-timeline__icon--skip { background: transparent; border: 1px dashed var(--color-text-muted); }
.lesson-timeline__icon--groups { background: var(--color-primary-700); }

.lesson-timeline__groups {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-top: 6px;
}

.lesson-timeline__group-row {
    display: flex;
    gap: var(--space-2);
    align-items: baseline;
    font-size: 0.8125rem;
    color: var(--color-text-body);
}

.lesson-timeline__group-label {
    font-weight: 600;
    color: var(--color-text-strong);
    flex-shrink: 0;
    min-width: 4.5rem;
}

.lesson-timeline__body { min-width: 0; }
.lesson-timeline__text {
    font-size: 0.875rem;
    color: var(--color-text-body);
    word-break: break-word;
}
.lesson-timeline__note {
    margin-top: 4px;
    color: var(--color-text-muted);
    font-style: italic;
    word-break: break-word;
}

.lesson-timeline__remove {
    border: none;
    background: none;
    color: var(--color-text-muted);
    font-size: 1.25rem;
    line-height: 1;
    cursor: pointer;
    padding: 0 4px;
    border-radius: 4px;
}

.lesson-timeline__remove:hover {
    color: var(--color-error-strong);
    background: var(--color-error-bg);
}

/* Overlays (picker + review) */

.lesson-overlay {
    position: fixed;
    inset: 0;
    background: rgba(15, 23, 42, 0.55);
    /* Sits above the lesson mode root (110). */
    z-index: 120;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-4);
}

.lesson-overlay[hidden] { display: none; }

.lesson-overlay__panel {
    background: var(--color-surface);
    border: 1px solid var(--color-surface-border);
    border-radius: var(--radius-md, 0.5rem);
    box-shadow: var(--shadow-lg);
    max-width: 36rem;
    width: 100%;
    max-height: calc(100vh - 4rem);
    overflow-y: auto;
    padding: var(--space-5);
}

.lesson-picker__name {
    margin: 0 0 var(--space-1) 0;
    font-size: 2.5rem;
    color: var(--color-text-strong);
    text-align: center;
}

.lesson-picker__pool {
    text-align: center;
    margin: 0 0 var(--space-4) 0;
}

.lesson-picker__actions,
.lesson-picker__sentiments {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
}

@media (min-width: 480px) {
    .lesson-picker__actions { grid-template-columns: 1fr 1fr; }
    .lesson-picker__sentiments { grid-template-columns: 1fr 1fr 1fr; }
}

.lesson-picker__btn {
    min-height: 2.75rem;
    border: 1px solid var(--color-surface-border);
    background: var(--color-surface);
    color: var(--color-text-body);
    cursor: pointer;
    font-weight: 500;
}

.lesson-picker__btn--positive {
    background: var(--color-success-bg);
    border-color: var(--color-success-strong);
    color: var(--color-success-strong);
}
.lesson-picker__btn--positive:hover {
    background: var(--color-success);
    color: #fff;
    border-color: var(--color-success);
}

.lesson-picker__btn--neutral:hover { background: var(--color-surface-hover); }

.lesson-picker__btn--concern {
    background: var(--color-error-bg);
    border-color: var(--color-error-strong);
    color: var(--color-error-strong);
}
.lesson-picker__btn--concern:hover {
    background: var(--color-error);
    color: #fff;
    border-color: var(--color-error);
}

.lesson-picker__footer {
    display: flex;
    justify-content: space-between;
    margin-top: var(--space-3);
    padding-top: var(--space-3);
    border-top: 1px solid var(--color-surface-border);
}

/* Note modal */

.lesson-note__title {
    margin: 0 0 var(--space-3) 0;
    font-size: 1.25rem;
    color: var(--color-text-strong);
}

.lesson-note__input {
    width: 100%;
    border: 1px solid var(--color-input-border);
    background: var(--color-input-bg);
    color: var(--color-text-body);
    border-radius: var(--radius-sm, 0.25rem);
    padding: var(--space-2);
    font-family: inherit;
    font-size: 0.95rem;
    resize: vertical;
    margin-bottom: var(--space-3);
}

.lesson-note__sentiments {
    display: flex;
    gap: var(--space-3);
    margin-bottom: var(--space-3);
    flex-wrap: wrap;
}

.lesson-note__sentiment {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    cursor: pointer;
    color: var(--color-text-body);
}

.lesson-note__sentiment input { margin: 0; }

.lesson-note__actions {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-2);
}

/* Review modal */

.lesson-review {
    max-width: 48rem;
}

.lesson-review__topic-callout {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
    background: var(--color-warning-bg);
    border: 1px solid var(--color-warning-strong);
    color: var(--color-warning-strong);
    border-radius: var(--radius-sm, 0.25rem);
    margin-bottom: var(--space-3);
    font-size: 0.875rem;
}

.lesson-review__topic-callout[hidden] { display: none; }

.lesson-review__topic-icon {
    flex-shrink: 0;
    margin-top: 2px;
}

.lesson-review__topic-callout strong {
    color: var(--color-text-strong);
}

.lesson-review__header {
    margin-bottom: var(--space-3);
}

.lesson-review__header h2 {
    margin: 0 0 4px 0;
    color: var(--color-text-strong);
}

.lesson-review__body {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    margin-bottom: var(--space-3);
}

.lesson-review__student-header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-1);
    margin-top: var(--space-3);
    border-bottom: 1px solid var(--color-surface-border);
}

.lesson-review__student-header:first-child {
    margin-top: 0;
}

.lesson-review__student-name {
    font-weight: 600;
    color: var(--color-text-strong);
    font-size: 1rem;
}

.lesson-review__row {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--space-2) var(--space-3);
    padding: var(--space-3);
    background: var(--color-bg-page);
    border-radius: var(--radius-sm, 0.25rem);
    align-items: start;
}

.lesson-review__time {
    font-variant-numeric: tabular-nums;
}

.lesson-review__include {
    margin-top: 4px;
    width: 1.25rem;
    height: 1.25rem;
}

.lesson-review__meta {
    display: flex;
    gap: var(--space-2);
    align-items: center;
    flex-wrap: wrap;
}

.lesson-review__name {
    font-weight: 600;
    color: var(--color-text-strong);
}

.lesson-review__sentiment {
    font-size: 0.75rem;
    padding: 2px 8px;
    border-radius: 999px;
    border: 1px solid transparent;
}

.lesson-review__sentiment--positive {
    background: var(--color-success-bg);
    color: var(--color-success-strong);
    border-color: var(--color-success-strong);
}
.lesson-review__sentiment--neutral {
    background: var(--color-surface-hover);
    color: var(--color-text-body);
    border-color: var(--color-surface-border);
}
.lesson-review__sentiment--concern {
    background: var(--color-error-bg);
    color: var(--color-error-strong);
    border-color: var(--color-error-strong);
}

.lesson-review__saved-pill {
    font-size: 0.75rem;
    padding: 2px 8px;
    background: var(--color-success);
    color: #fff;
    border-radius: 999px;
}

.lesson-review__content {
    grid-column: 2;
    width: 100%;
    border: 1px solid var(--color-input-border);
    background: var(--color-input-bg);
    color: var(--color-text-body);
    border-radius: var(--radius-sm, 0.25rem);
    padding: var(--space-2);
    font-family: inherit;
    font-size: 0.875rem;
    resize: vertical;
}

.lesson-review__footer {
    display: flex;
    justify-content: space-between;
    gap: var(--space-2);
    padding-top: var(--space-3);
    border-top: 1px solid var(--color-surface-border);
    flex-wrap: wrap;
}

/* Make Groups modal */

.lesson-groups {
    max-width: 56rem;
}

.lesson-groups__header {
    margin-bottom: var(--space-3);
}

.lesson-groups__header h2 {
    margin: 0 0 4px 0;
    color: var(--color-text-strong);
}

.lesson-groups__subtitle {
    margin: 0;
}

.lesson-groups__size-row {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
    flex-wrap: wrap;
}

.lesson-groups__size-row label {
    font-weight: 600;
    color: var(--color-text-strong);
}

.lesson-groups__size-input {
    width: 5rem;
    padding: var(--space-2);
    border: 1px solid var(--color-input-border);
    background: var(--color-input-bg);
    color: var(--color-text-body);
    border-radius: var(--radius-sm, 0.25rem);
    font-size: 1rem;
}

.lesson-groups__flags {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
}

.lesson-groups__flag-row {
    border: 1px solid var(--color-surface-border);
    border-radius: var(--radius-sm, 0.25rem);
    padding: var(--space-3);
    background: var(--color-bg-page);
}

.lesson-groups__flag-head {
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
    margin-bottom: 4px;
    flex-wrap: wrap;
}

.lesson-groups__flag-type {
    font-size: 0.75rem;
    padding: 2px 8px;
    border-radius: 999px;
    border: 1px solid transparent;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    font-weight: 600;
    flex-shrink: 0;
}

.lesson-groups__flag-type--alert {
    background: var(--color-error-bg);
    color: var(--color-error-strong);
    border-color: var(--color-error-strong);
}

.lesson-groups__flag-type--info {
    background: var(--color-warning-bg);
    color: var(--color-warning-strong);
    border-color: var(--color-warning-strong);
}

.lesson-groups__flag-content {
    color: var(--color-text-body);
    font-size: 0.9375rem;
}

.lesson-groups__flag-pupils {
    color: var(--color-text-muted);
    font-size: 0.8125rem;
    margin-bottom: var(--space-2);
}

.lesson-groups__flag-radios {
    display: flex;
    gap: var(--space-2);
    flex-wrap: wrap;
}

.lesson-groups__intent {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    border: 1px solid var(--color-surface-border);
    border-radius: var(--radius-sm, 0.25rem);
    background: var(--color-surface);
    cursor: pointer;
    font-size: 0.875rem;
}

.lesson-groups__intent input { margin: 0; }

.lesson-groups__intent:has(input:checked) {
    border-color: var(--color-primary-700);
    background: var(--color-primary-50);
    color: var(--color-primary-700);
    font-weight: 600;
}

.lesson-groups__no-flags {
    margin: 0 0 var(--space-3) 0;
}

.lesson-groups__errors {
    margin-bottom: var(--space-3);
}

.lesson-groups__error {
    margin: 0 0 var(--space-2) 0;
    padding: var(--space-2) var(--space-3);
    background: var(--color-error-bg);
    border: 1px solid var(--color-error-strong);
    color: var(--color-error-strong);
    border-radius: var(--radius-sm, 0.25rem);
    font-size: 0.875rem;
}

.lesson-groups__footer {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-2);
    padding-top: var(--space-3);
    border-top: 1px solid var(--color-surface-border);
    flex-wrap: wrap;
}

.lesson-groups__results-hint {
    margin: 0 0 var(--space-3) 0;
}

.lesson-groups__list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
    gap: var(--space-3);
    margin-bottom: var(--space-3);
}

.lesson-group-card {
    border: 1px solid var(--color-surface-border);
    border-radius: var(--radius-sm, 0.25rem);
    padding: var(--space-3);
    background: var(--color-bg-page);
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease;
}

.lesson-group-card:hover {
    background: var(--color-surface-hover);
    border-color: var(--color-primary-700);
}

.lesson-group-card__head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: var(--space-2);
}

.lesson-group-card__head h3 {
    margin: 0;
    font-size: 1rem;
    color: var(--color-text-strong);
}

.lesson-group-card__count {
    background: var(--color-surface-hover);
    color: var(--color-text-body);
    padding: 2px 8px;
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 600;
}

.lesson-group-card__pupils {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.lesson-group-chip {
    border: 1px solid var(--color-surface-border);
    background: var(--color-surface);
    color: var(--color-text-body);
    border-radius: var(--radius-sm, 0.25rem);
    padding: 4px 10px;
    font-size: 0.8125rem;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}

.lesson-group-chip:hover {
    background: var(--color-surface-hover);
}

.lesson-group-chip--moving,
.lesson-group-chip--moving:hover {
    background: var(--color-primary-700);
    color: #fff;
    border-color: var(--color-primary-700);
    transform: scale(1.05);
}
