/* ==========================================================================
   LDT STUDENT MANAGEMENT SYSTEM - MAIN STYLESHEET (MODERNIZED)
   ========================================================================== */

/* ==========================================================================
   0. MONTSERRAT (self-hosted, replaces fonts.googleapis.com CDN)
   ========================================================================== */
@font-face {
    font-family: 'Montserrat';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("../fonts/montserrat/montserrat-v31-latin-regular.e7198b2dcb57.woff2") format('woff2');
}

@font-face {
    font-family: 'Montserrat';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url("../fonts/montserrat/montserrat-v31-latin-500.f96e8aab37e8.woff2") format('woff2');
}

@font-face {
    font-family: 'Montserrat';
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url("../fonts/montserrat/montserrat-v31-latin-600.9e606da1cbeb.woff2") format('woff2');
}

@font-face {
    font-family: 'Montserrat';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url("../fonts/montserrat/montserrat-v31-latin-700.1c0792ac34ef.woff2") format('woff2');
}

/* ==========================================================================
   1. CSS VARIABLES - Modern Color Palette & Design Tokens
   ========================================================================== */
:root {
    /* Brand Colors - Enhanced */
    --ldt-primary: #F05409; /* LDT Orange - Primary Brand Color */
    --ldt-primary-light: #FF7A3D; /* Lighter Orange for hover states */
    --ldt-primary-dark: #D64B08; /* Darker Orange for active states */

    --ldt-secondary: #3D7D99; /* Blue-Grey - Secondary Color */
    --ldt-secondary-light: #5A9BB8; /* Lighter Blue-Grey */
    --ldt-secondary-dark: #2A5A74; /* Darker Blue-Grey */

    /* Neutral Colors - Improved */
    --ldt-dark: #1F2937; /* Dark Grey - improved from #272727 */
    --ldt-grey: #6B7280; /* Medium Grey */
    --ldt-light-grey: #F3F4F6; /* Light Grey background */
    --ldt-lighter-grey: #F9FAFB; /* Very Light background */
    --ldt-border: #E5E7EB; /* Border color */
    --ldt-black: #000000; /* Black */
    --ldt-white: #FFFFFF; /* White */
    --ldt-light: #F5F5F5; /* Light background */

    /* Semantic aliases – used across templates and component CSS */
    --ldt-text: #1F2937;           /* main body text */
    --ldt-text-muted: #6B7280;     /* secondary/muted text */
    --ldt-bg: #F9FAFB;             /* page-level background */
    --ldt-bg-secondary: #F3F4F6;   /* secondary surface background */
    --ldt-card-bg: #FFFFFF;        /* card / panel background */
    --ldt-card-dark: #1E293B;      /* card background in dark mode */
    --ldt-border-dark: #4B5563;    /* border colour in dark mode */

    /* Semantic Colors - More vibrant */
    --ldt-success: #10B981; /* Success green - improved */
    --ldt-success-light: #ECFDF5; /* Success background */
    --ldt-warning: #F59E0B; /* Warning amber - improved */
    --ldt-warning-light: #FFFBEB; /* Warning background */
    --ldt-danger: #EF4444; /* Error red - improved */
    --ldt-danger-light: #FEE2E2; /* Error background */
    --ldt-info: #3B82F6; /* Info blue */
    --ldt-info-light: #EFF6FF; /* Info background */

    /* --ldt-warning itself is too low-contrast on --ldt-warning-light for
       text, so .alert-warning and .badge-warning hard-coded this value.
       Named so it stops being a magic number, not a new colour. */
    --ldt-warning-text: #92400e;

    /* Subtle tinted backgrounds for status panels. Defined in BOTH themes so
       templates can use them safely; the dark-mode block overrides these to
       low-opacity rgba tints. Light-mode values mirror the *-light pales above. */
    --ldt-success-bg: #ECFDF5;
    --ldt-warning-bg: #FFFBEB;
    --ldt-danger-bg: #FEE2E2;
    --ldt-info-bg: #EFF6FF;
    --ldt-primary-bg: #FFF7ED; /* orange tint for info-required / pending panels */

    /* SPARK lockup - the brand's own colours, sampled from SPARK-Logo-Colour.png
       and signed off with the asset (V-DEC-1).  Deliberately NOT the --ldt-*
       tokens: the logo is the brand mark, not a themed component, and the two
       oranges differ (#EF5623 against the interface's #F05409). */
    --spark-orange: #EF5623;
    --spark-grey: #878787;
    --spark-ink: #140C0A;
    --spark-accent: #EF5623;
    --spark-glyph: #FFFFFF;
    --spark-glyph-ink: #FFFFFF;

    /* Spacing Scale - Updated */
    --spacing-xs: 0.25rem; /* 4px */
    --spacing-sm: 0.5rem; /* 8px */
    --spacing-md: 1rem; /* 16px */
    --spacing-lg: 1.5rem; /* 24px */
    --spacing-xl: 2rem; /* 32px */
    --spacing-2xl: 3rem; /* 48px */

    /* Shadows - Modern elevation system */
    --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.05);
    --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
    --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
    --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
    --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);

    /* Border Radius - Consistent */
    --radius-sm: 0.375rem; /* 6px */
    --radius-md: 0.5rem; /* 8px */
    --radius-lg: 0.75rem; /* 12px */
    --radius-xl: 1rem; /* 16px */
    --radius-full: 9999px; /* Full circle */

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

    /* Typography */
    --font-sans: 'Montserrat', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
    --font-mono: 'Courier New', monospace;
}

/* ==========================================================================
   DARK MODE - CSS Variables Override
   ========================================================================== */
body.dark-mode {
    color-scheme: dark; /* native browser controls (dropdowns, date pickers) use dark theme */

    /* Neutral Colors - Dark Theme */
    --ldt-dark: #F3F4F6; /* Light text on dark background */
    --ldt-grey: #D1D5DB; /* Medium grey for text */
    --ldt-light-grey: #374151; /* Dark grey backgrounds */
    --ldt-lighter-grey: #1F2937; /* Very dark background */
    --ldt-border: #4B5563; /* Border color for dark mode */
    --ldt-black: #FFFFFF; /* Inverted - use white as "black" */
    --ldt-white: #111827; /* Dark background instead of white */
    --ldt-light: #1F2937; /* Dark background */

    /* Primary Colors - Dark Theme */
    --ldt-primary: #F05409; /* Original orange for dark mode */
    --ldt-primary-dark: #D64B08; /* Original darker orange for gradients */
    --ldt-primary-light: #FF7A3D; /* Original light orange for backgrounds */
    --ldt-primary-bg: rgba(240, 84, 9, 0.1);

    /* Secondary Colors - Dark Theme */
    --ldt-secondary: #5BA3C7; /* Brighter blue for dark mode */
    --ldt-secondary-dark: #4A8DAF; /* Darker blue for gradients */
    --ldt-secondary-light: #7AB5D6; /* Light blue for backgrounds */
    --ldt-secondary-bg: rgba(91, 163, 199, 0.1);

    /* Status Colors - Dark Theme */
    --ldt-success: #51C88A; /* Brighter green for dark mode */
    --ldt-success-dark: #3FA771; /* Darker green */
    --ldt-success-light: #7FD9A8; /* Light green */
    --ldt-success-bg: rgba(81, 200, 138, 0.1);

    --ldt-warning: #FBBF24; /* Brighter amber for dark mode */
    --ldt-warning-dark: #F59E0B; /* Darker amber */
    --ldt-warning-light: #FCD34D; /* Light amber */
    --ldt-warning-bg: rgba(251, 191, 36, 0.1);
    --ldt-warning-text: #92400e; /* Still enough contrast against --ldt-warning-light in dark mode */

    --ldt-danger: #FF6B6B; /* Brighter red for dark mode */
    --ldt-danger-dark: #F97676; /* Darker red */
    --ldt-danger-light: #FF8787; /* Light red */
    --ldt-danger-bg: rgba(255, 107, 107, 0.1);

    --ldt-info: #3B82F6; /* Brighter blue for dark mode */
    --ldt-info-dark: #1D4ED8; /* Darker blue */
    --ldt-info-light: #60A5FA; /* Light blue */
    --ldt-info-bg: rgba(59, 130, 246, 0.1);

    /* Semantic aliases – dark mode overrides */
    --ldt-text: #F3F4F6;
    --ldt-text-muted: #9CA3AF;
    --ldt-bg: #111827;
    --ldt-bg-secondary: #1F2937;
    --ldt-card-bg: #1E293B;
    --ldt-border-dark: #334155;

    /* The lockup goes all white on dark, as SPARK-Logo-White.png already is,
       and as the LDT logo's own image swap does beside it (asset README). */
    --spark-orange: #FFFFFF;
    --spark-grey: #FFFFFF;
    --spark-ink: #FFFFFF;
    --spark-accent: #FFFFFF;
    --spark-glyph: #000000;
    --spark-glyph-ink: #000000;
}

/* Dark mode sidebar styling */
body.dark-mode .sidenav {
    background: linear-gradient(135deg, #0F172A 0%, #030712 100%);
}

/* Same pairing as the light-mode block below: a drawer destination that has
   to POST is a <button>, and naming only `a` here left it on the light
   palette while every link around it switched. */
body.dark-mode .sidenav a,
body.dark-mode .sidenav button.nav-link {
    color: var(--ldt-dark);
}

body.dark-mode .sidenav a:hover,
body.dark-mode .sidenav button.nav-link:hover {
    background-color: rgba(240, 84, 9, 0.15);
    color: var(--ldt-primary);
}

body.dark-mode .sidenav-section-title {
    color: var(--ldt-grey);
}

body.dark-mode .sidenav-user-section {
    border-top-color: var(--ldt-border);
}

/* Dark mode component overrides */
body.dark-mode table {
    background: var(--ldt-white);
    box-shadow: var(--shadow-md);
}

/* The bare `body.dark-mode thead` and `body.dark-mode th` rules that used to
   sit here are gone with their light-mode counterparts (N-68, N-74): they put
   white text on Bootstrap's white cells in dark mode too. Their
   .table-highlight equivalents are further down this block and already won
   every tie for SPARK's own tables, so nothing that was styled has lost its
   styling. */

body.dark-mode td {
    color: var(--ldt-dark);
    border-bottom-color: var(--ldt-border);
}

/* A Bootstrap .table in dark mode. Found while capturing the fix above, and
   the same root cause: Bootstrap paints --bs-table-bg (#fff) onto every cell,
   so the table stayed white while the rule directly above coloured its text
   with dark mode's --ldt-dark (near-white) - pale grey on white on the agent
   accounts screen, the SAR list and the portal change-request lists.

   Retuning Bootstrap's own custom properties rather than out-specifying its
   selector: they inherit, and its cell rule reads them, so this holds wherever
   that rule applies. SPARK's own .table-highlight tables do not read them and
   are untouched. The agent portal never sets body.dark-mode at all, so it is
   out of scope here too. */
body.dark-mode .table {
    --bs-table-bg: transparent;
    --bs-table-color: var(--ldt-text);
    --bs-table-border-color: var(--ldt-border);
    --bs-table-striped-color: var(--ldt-text);
    --bs-table-striped-bg: rgba(255, 255, 255, 0.03);
    --bs-table-hover-color: var(--ldt-text);
    --bs-table-hover-bg: rgba(255, 255, 255, 0.06);
}

body.dark-mode tbody tr:hover {
    background-color: var(--ldt-light-grey);
}

body.dark-mode .hoverTable tr:hover td {
    background-color: var(--ldt-light-grey);
    color: var(--ldt-dark);
}

body.dark-mode .table-highlight tr:hover {
    background-color: var(--ldt-light-grey);
}

/* Dark mode table-highlight specific styling */
body.dark-mode .table-highlight {
    background: var(--ldt-white);
}

body.dark-mode .table-highlight thead {
    background: linear-gradient(135deg, #546E7A 0%, #455A64 100%);
}

body.dark-mode .table-highlight thead th {
    color: #FFFFFF !important;
    padding: 1rem;
    text-align: left;
    border: none;
    font-weight: 600;
    font-size: 0.9375rem;
    letter-spacing: 0.025em;
}

body.dark-mode .table-highlight tbody th {
    color: var(--ldt-dark);
}

body.dark-mode .table-highlight td {
    color: var(--ldt-dark);
    padding: 1rem;
    text-align: left;
    border-bottom: 1px solid var(--ldt-border);
}

body.dark-mode .table-highlight tbody tr {
    transition: all var(--transition-fast);
}

body.dark-mode .table-highlight tbody tr:hover {
    background-color: var(--ldt-light-grey);
}

body.dark-mode .attendance-summary table {
    background-color: var(--ldt-white);
}

body.dark-mode .attendance-summary thead {
    background: linear-gradient(135deg, var(--ldt-secondary) 0%, var(--ldt-secondary-dark) 100%);
}

/* Dark mode form inputs */
body.dark-mode input[type="text"],
body.dark-mode input[type="email"],
body.dark-mode input[type="password"],
body.dark-mode input[type="search"],
body.dark-mode input[type="number"],
body.dark-mode input[type="date"],
body.dark-mode input[type="tel"],
body.dark-mode input[type="url"],
body.dark-mode input[type="time"],
body.dark-mode input[type="datetime-local"],
body.dark-mode textarea,
body.dark-mode select {
    background-color: #1F2937;
    color: var(--ldt-dark);
    border-color: var(--ldt-border);
}

body.dark-mode input[type="text"]:focus,
body.dark-mode input[type="email"]:focus,
body.dark-mode input[type="password"]:focus,
body.dark-mode input[type="search"]:focus,
body.dark-mode input[type="number"]:focus,
body.dark-mode input[type="date"]:focus,
body.dark-mode input[type="tel"]:focus,
body.dark-mode input[type="url"]:focus,
body.dark-mode input[type="time"]:focus,
body.dark-mode input[type="datetime-local"]:focus,
body.dark-mode textarea:focus,
body.dark-mode select:focus {
    background-color: #111827;
    border-color: var(--ldt-primary);
    box-shadow: 0 0 0 3px var(--ldt-primary-bg);
}

/* Dark mode cards and containers */
body.dark-mode .card {
    background-color: #1F2937;
    color: var(--ldt-dark);
    border-color: var(--ldt-border);
}

body.dark-mode .badge {
    background-color: var(--ldt-light-grey);
    color: var(--ldt-dark);
}

/* Without these the rule above outranks .badge-danger and .badge-warning. */
body.dark-mode .badge-danger {
    background-color: var(--ldt-danger-light);
    color: #7f1d1d;
}

body.dark-mode .badge-warning {
    background-color: var(--ldt-warning-light);
    color: var(--ldt-warning-text);
}

body.dark-mode .alert {
    background-color: rgba(17, 24, 39, 0.8);
    border-color: var(--ldt-border);
    color: var(--ldt-dark);
}

body.dark-mode .alert-success {
    background-color: rgba(81, 200, 138, 0.15);
    border-color: var(--ldt-success);
    color: var(--ldt-success-light);
}

body.dark-mode .alert-warning {
    background-color: rgba(251, 191, 36, 0.15);
    border-color: var(--ldt-warning);
    color: var(--ldt-warning-light);
}

body.dark-mode .alert-danger {
    background-color: rgba(255, 107, 107, 0.15);
    border-color: var(--ldt-danger);
    color: var(--ldt-danger-light);
}

body.dark-mode .alert-info {
    background-color: rgba(59, 130, 246, 0.15);
    border-color: var(--ldt-info);
    color: var(--ldt-info-light);
}

/* Dark mode pagination and navigation */
body.dark-mode .pagination {
    background-color: transparent;
}

body.dark-mode .pagination a {
    background-color: var(--ldt-light-grey);
    color: var(--ldt-dark);
    border-color: var(--ldt-border);
}

body.dark-mode .pagination a:hover {
    background-color: var(--ldt-primary);
    color: #FFFFFF;
    border-color: var(--ldt-primary);
}

body.dark-mode .pagination .active {
    background-color: var(--ldt-primary);
    border-color: var(--ldt-primary);
    color: #FFFFFF;
}

/* Dark mode tabs */
body.dark-mode .nav-tabs {
    border-bottom-color: var(--ldt-border);
}

body.dark-mode .nav-tabs .nav-link {
    color: var(--ldt-grey);
    border-bottom-color: transparent;
}

body.dark-mode .nav-tabs .nav-link:hover {
    color: var(--ldt-dark);
    border-bottom-color: var(--ldt-primary);
}

body.dark-mode .nav-tabs .nav-link.active {
    color: var(--ldt-grey);
    background-color: var(--ldt-light-grey);
    border-bottom-color: var(--ldt-primary);
}

/* Dark mode code/pre blocks */
body.dark-mode pre {
    background-color: #0F172A;
    color: var(--ldt-dark);
    border-color: var(--ldt-border);
}

body.dark-mode code {
    background-color: #1F2937;
    color: var(--ldt-primary-light);
}

/* Dark mode datatable */
body.dark-mode .dataTables_wrapper {
    color: var(--ldt-dark);
}

body.dark-mode .dataTables_length,
body.dark-mode .dataTables_filter,
body.dark-mode .dataTables_info,
body.dark-mode .dataTables_paginate {
    color: var(--ldt-dark);
}

body.dark-mode .dataTables_paginate .paginate_button {
    background-color: var(--ldt-light-grey);
    color: var(--ldt-dark);
    border-color: var(--ldt-border);
}

body.dark-mode .dataTables_paginate .paginate_button:hover {
    background-color: var(--ldt-primary);
    color: #FFFFFF;
    border-color: var(--ldt-primary);
}

body.dark-mode .dataTables_paginate .paginate_button.current {
    background-color: var(--ldt-primary);
    color: #FFFFFF;
    border-color: var(--ldt-primary);
}

/* Dark mode card header – light gradient must be overridden explicitly */
body.dark-mode .card-header {
    background: #1a2435;
    border-bottom-color: var(--ldt-border);
    color: var(--ldt-dark);
}

body.dark-mode .card-footer {
    background: #111827;
    border-top-color: var(--ldt-border);
    color: var(--ldt-dark);
}

/* Dark mode Bootstrap form controls (.form-control / .form-select) */
body.dark-mode .form-control,
body.dark-mode .form-select,
body.dark-mode .form-control:disabled,
body.dark-mode .form-control[readonly] {
    background-color: #1F2937;
    color: var(--ldt-dark);
    border-color: var(--ldt-border);
}

body.dark-mode .form-control:focus,
body.dark-mode .form-select:focus {
    background-color: #111827;
    color: var(--ldt-dark);
    border-color: var(--ldt-primary);
    box-shadow: 0 0 0 3px rgba(240, 84, 9, 0.15);
}

/* Browsers give an autofilled field their own light background, which no
   background rule can override, and the light text above vanishes on it.
   An inset shadow paints over that background. */
body.dark-mode :is(input, textarea, select):autofill {
    box-shadow: 0 0 0 100vmax #1F2937 inset;
    -webkit-text-fill-color: var(--ldt-dark);
    caret-color: var(--ldt-dark);
}

body.dark-mode :is(input, textarea, select):autofill:focus {
    box-shadow: 0 0 0 3px rgba(240, 84, 9, 0.15), 0 0 0 100vmax #111827 inset;
}

body.dark-mode .form-control::placeholder {
    color: var(--ldt-grey);
}

/* Dark mode select – replace arrow SVG with light stroke */
body.dark-mode select {
    background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23F3F4F6' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e");
    background-repeat: no-repeat;
    background-position: right 1rem center;
    background-size: 1.1em;
}

/* Select option list – supplementary to color-scheme:dark */
body.dark-mode option {
    background-color: #1F2937;
    color: var(--ldt-dark);
}

/* Dark mode secondary button – prevents it inverting to a light background */
body.dark-mode .btn-secondary {
    background: #374151;
    color: #F9FAFB;
    border: 1px solid #4B5563;
}

body.dark-mode .btn-secondary:hover {
    background: #4B5563;
    color: #FFFFFF;
}

/* Dark mode add-attendance card-header button hover */
body.dark-mode .card-header .btn:hover {
    background-color: var(--ldt-light-grey);
    color: var(--ldt-dark);
}

/* Dark mode attendance autosave note */
body.dark-mode .att-autosave-note {
    color: var(--ldt-dark);
    background: #1F2937;
    border-left-color: var(--ldt-info);
}

/* Dark mode attendance comment-filled */
body.dark-mode .att-comment-filled {
    background-color: #374151;
    color: #9CA3AF;
}

body.dark-mode .att-comment-filled:focus {
    background-color: #1F2937;
    color: var(--ldt-dark);
}


/* ==========================================================================
   2. RESET & BASE STYLES
   ========================================================================== */
* {
    box-sizing: border-box;
}

html {
    scroll-behavior: smooth;
}

body {
    margin: 0;
    padding: 0;
    font-family: var(--font-sans);
    font-size: 0.9375rem; /* 15px - improved from 11pt */
    line-height: 1.6;
    color: var(--ldt-dark);
    background-color: var(--ldt-lighter-grey);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* Remove default margins and padding */
h1, h2, h3, h4, h5, h6, p, ul, ol, li {
    margin-top: 0;
}

/* ==========================================================================
   3. TYPOGRAPHY
   ========================================================================== */
h1, h2, h3, h4, h5, h6 {
    color: var(--ldt-dark);
    margin-bottom: 1rem;
    font-weight: 600;
    font-family: var(--font-sans);
    line-height: 1.3;
    letter-spacing: -0.01em;
}

h1 {
    font-size: 2rem; /* 32px - modern and bold */
    color: var(--ldt-primary);
    font-weight: 700;
    margin-bottom: 1.5rem;
}

h2 {
    font-size: 1.5rem; /* 24px */
    color: var(--ldt-dark);
    border-bottom: 3px solid var(--ldt-primary);
    padding-bottom: 0.75rem;
    margin-bottom: 1.5rem;
}

h3 {
    font-size: 1.25rem; /* 20px */
    color: var(--ldt-dark);
    margin-bottom: 1rem;
}

h4, h5 {
    font-size: 1.125rem; /* 18px */
    color: var(--ldt-dark);
}

h6 {
    font-size: 1rem; /* 16px */
    font-weight: 600;
    color: var(--ldt-grey);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

p {
    margin-bottom: 1rem;
    color: var(--ldt-grey);
}

small {
    font-size: 0.875rem; /* 14px */
    color: var(--ldt-grey);
}

strong {
    font-weight: 600;
    color: var(--ldt-dark);
}

a {
    color: var(--ldt-primary);
    text-decoration: none;
    transition: color var(--transition-fast);
}

a:hover {
    color: var(--ldt-primary-dark);
}

/* ==========================================================================
   4. LAYOUT - Header, Sidebar, Main Container
   ========================================================================== */

/* Header - Modern and Responsive */
.main-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    position: sticky;
    top: 0;
    padding: 1rem var(--spacing-lg);
    background: var(--ldt-white);
    box-shadow: var(--shadow-md);
    flex-wrap: wrap;
    gap: var(--spacing-md);
    z-index: 100;
}

.header-left {
    display: flex;
    align-items: center;
    gap: var(--spacing-md);
    order: 1;
}

.header-right {
    display: flex;
    align-items: center;
    gap: var(--spacing-lg);
    order: 3;
    flex: 1;
    justify-content: flex-end;
}

.site-title {
    margin: 0;
    font-size: 1.5rem;
    font-weight: 700;
    text-align: center;
    color: var(--ldt-dark);
    order: 2;
    flex: 5;
    /* The heading holds an inline SVG now, not a line of text; without this the
       line-height of the (empty) text box adds a few pixels under it. */
    line-height: 0;
}

/* The SPARK lockup, V-DEC-1.  Height-led because the header is: the viewBox is
   4.8:1, so width follows.  44px on desktop, 30px on a phone (below), which is
   the floor the asset README sets - under about 30px the three icons stop
   reading as icons.  Every fill inside the file is a var() with the light value
   as its fallback, so the theme swap is the custom properties alone. */
.spark-lockup {
    height: 44px;
    width: auto;
    max-width: 100%;
    display: inline-block;
    vertical-align: middle;
}

.logo {
    height: 60px;
    width: auto;
    transition: transform var(--transition-fast);
}

.logo:hover {
    transform: scale(1.05);
}

.menu-toggle {
    font-size: 1.5rem;
    cursor: pointer;
    color: var(--ldt-primary);
    padding: var(--spacing-sm);
    border-radius: var(--radius-md);
    border: none;
    background: transparent;
    transition: all var(--transition-fast);
    display: block;
}

.menu-toggle:hover {
    background-color: rgba(240, 84, 9, 0.1);
    transform: scale(1.1);
}

/* Dark Mode Toggle Button */
.dark-mode-toggle-container {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 1rem 0.5rem 0.5rem 0.5rem;
    /*    border-top: 1px solid var(--ldt-border); */
}

.dark-mode-toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: var(--radius-md);
    border: 1px solid var(--ldt-border);
    background-color: transparent;
    color: var(--ldt-grey);
    cursor: pointer;
    font-size: 1.5rem;
    transition: all var(--transition-base);
}

.dark-mode-toggle:hover {
    background-color: var(--ldt-light-grey);
    color: var(--ldt-primary);
    border-color: var(--ldt-primary);
}

.dark-mode-toggle:focus {
    outline: 2px solid var(--ldt-primary);
    outline-offset: 2px;
}

.mode-icon {
    display: inline-flex;
    align-items: center;
    transition: transform var(--transition-base);
}

.dark-mode-toggle:hover .mode-icon {
    transform: scale(1.1);
}

/* One line-art icon, drawn by core/_icon.html.  Shared by every shell since
   V1 promoted the partial out of admissions/ (V-DEC-6); the applicant portal
   defined this rule inline until then, with these exact values. */
.portal-icon {
    width: 1.15rem;
    height: 1.15rem;
    flex: 0 0 auto;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.8;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* The staff header's three symbols, a little larger than a drawer icon - the
   emoji they replaced were set at 1.5rem.  Not written as
   `.mode-icon .portal-icon`, which the applicant shell already defines at its
   own smaller size: one selector, one definition, one shell each. */
.dark-mode-toggle .portal-icon,
.menu-toggle .portal-icon,
.notifications-link .portal-icon {
    width: 1.4rem;
    height: 1.4rem;
}

/* The context bar - visual plan §4.1, under the header on every staff page.
   Same white as the header so it reads as one strip, and so .breadcrumb-item's
   existing grey keeps the 4.8:1 it has there; a tinted background would drop it
   under 4.5:1. */
.context-bar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--spacing-md);
    padding: var(--spacing-sm) var(--spacing-lg);
    background: var(--ldt-white);
    border-bottom: 1px solid var(--ldt-border);
}

/* The breadcrumb component is main.css's own (section 11), reused rather than
   restyled - only the strip's own spacing is overridden. */
.context-bar .breadcrumb {
    padding: 0;
    margin: 0 auto 0 0;
    font-size: 0.875rem;
}

/* An empty crumb draws nothing, and draws no separator before the next one:
   a page inside no drawer destination has no group and no destination to name. */
.context-bar .breadcrumb-item:empty {
    display: none;
}

/* Sidebar Navigation - Modern */
.sidenav {
    height: 100vh;
    width: 240px;
    position: fixed;
    z-index: 1000;
    top: 0;
    left: -240px;
    background: linear-gradient(135deg, var(--ldt-dark) 0%, #0f172a 100%);
    overflow-y: auto;
    overflow-x: hidden;
    /*    padding-top: 80px; */
    box-shadow: var(--shadow-xl);
    transition: left 0.3s ease !important;
    display: flex;
    flex-direction: column;
}

.sidenav.open {
    left: 0 !important;
}

/* The drawer styles its destinations as `.sidenav a`, so a destination that
   has to POST - the student portal's apply-for-another-course bridge - is a
   <button> and matched none of this: it kept the global button rule's wider
   padding, its own font size and no left rail, which read as a permanently
   selected item sitting next to its neighbours. Named here so one rule
   describes a drawer destination whichever element carries it. */
.sidenav a,
.sidenav button.nav-link {
    padding: var(--spacing-md) var(--spacing-md);
    text-decoration: none;
    font-size: 0.95rem;
    color: #e5e7eb;
    display: flex;
    align-items: center;
    gap: var(--spacing-md);
    transition: all var(--transition-fast);
    border-left: 4px solid transparent;
    position: relative;
}

.sidenav a:hover,
.sidenav button.nav-link:hover {
    background-color: rgba(255, 255, 255, 0.1);
    border-left-color: var(--ldt-primary);
    color: var(--ldt-white);
    padding-left: calc(var(--spacing-lg) + 4px);
}

.sidenav a.active,
.sidenav button.nav-link.active {
    background-color: rgba(240, 84, 9, 0.15);
    border-left-color: var(--ldt-primary);
    color: var(--ldt-primary);
    font-weight: 600;
}

.sidenav .closebtn {
    position: absolute;
    top: 1rem;
    right: 1.5rem;
    font-size: 2rem;
    background: transparent;
    border: none;
    color: var(--ldt-white);
    cursor: pointer;
    padding: 0;
    transition: color var(--transition-fast);
}

.sidenav .closebtn:hover {
    color: var(--ldt-primary);
}

/* Sidebar Search Form */
/* The panel frames the staff drawer's search FIELD, so it is asked for by
   the presence of one rather than by the form element alone. The student
   portal's apply-for-another-course bridge is a form too - a POST-only
   destination wrapping a single nav link - and it was being painted
   rgba(255,255,255,0.1), the exact colour of .nav-link:hover, which left
   that one item looking permanently selected. The hidden CSRF input is
   excluded or every such form would match. */
.sidenav form:has(input:not([type="hidden"])) {
    background: rgba(255, 255, 255, 0.1);
    padding: 0.5rem var(--spacing-md);
    margin: var(--spacing-sm) 0;
    border-radius: var(--radius-md);
}

.sidenav form input {
    width: 100%;
    padding: 0.375rem var(--spacing-sm);
    border: 1px solid rgba(255, 255, 255, 0.3);
    border-radius: var(--radius-sm);
    background: rgba(255, 255, 255, 0.95);
    color: var(--ldt-dark);
    margin-bottom: 0.25rem;
    font-family: var(--font-sans);
    font-size: 0.875rem;
}

.sidenav form input::placeholder {
    color: var(--ldt-grey);
}

.sidenav form input:focus {
    outline: none;
    background: var(--ldt-white);
    border-color: var(--ldt-primary);
    box-shadow: 0 0 0 2px rgba(240, 84, 9, 0.2);
}

/* :not(.nav-link) - this is the staff drawer's search button, an orange
   filled control sitting under the search field. A button that has opted
   into .nav-link is a navigation link that happens to POST, and this rule
   (0,1,2) outranks the class (0,1,0), so without the guard it repainted the
   student portal's "Apply for Another Course" bridge white-on-orange and it
   read as permanently selected. */
.sidenav form button:not(.nav-link) {
    width: 100%;
    padding: 0.375rem;
    background: var(--ldt-primary);
    color: white;
    border: none;
    border-radius: var(--radius-sm);
    cursor: pointer;
    font-weight: 600;
    font-size: 0.8rem;
    transition: background var(--transition-fast);
}

.sidenav form button:not(.nav-link):hover {
    background: var(--ldt-primary-dark);
}

/* Main Content Area */
#main {
    transition: margin-left var(--transition-base);
    padding: var(--spacing-lg);
    min-height: 100vh;
    background: var(--ldt-lighter-grey);
}

#main.sidebar-open {
    margin-left: 240px;
}

#content {
    transition: margin-left var(--transition-base);
    padding: 0 var(--spacing-lg);
}

.container {
    max-width: 1400px;
    margin: 0 auto;
    padding: var(--spacing-md);
    width: 100%;
}

/* Page Header */
.page-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: var(--spacing-md);
    flex-wrap: wrap;
    gap: var(--spacing-md);
}

/* ==========================================================================
   5. FORMS - Modern Input Styling
   ========================================================================== */
/* Opt-in, not automatic (N-71, N-75).
   These declarations used to sit on the bare `form` element, so every form in
   the product became a padded, shadowed panel up to 95vw wide - including the
   one-button forms that post a single action from inside a table cell or a
   list item. Those stopped being buttons and became panels that covered the
   row or the bullet they belonged to: four action forms per row piling up on
   the agent accounts table, and eight "Use my agent's value" forms hiding the
   very list text the applicant was being asked to choose between.

   The default is inverted rather than the inline forms exempted. A page-level
   form that is missed renders flat - visible and harmless - whereas an inline
   form that is missed goes on covering its neighbours, which is neither. */
form.form-card {
    background: var(--ldt-white);
    padding: var(--spacing-xl);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
    max-width: min(1500px, 95vw);
    margin: 0 auto;
}

.form-group {
    margin-bottom: var(--spacing-lg);
}

.form-group label {
    margin-bottom: var(--spacing-sm);
}

.form-group .help-text {
    font-size: 0.875rem;
    color: var(--ldt-grey);
    margin-top: 0.25rem;
}

label {
    display: block;
    margin-bottom: 0.5rem;
    color: var(--ldt-dark);
    font-weight: 600;
    font-size: 0.9375rem;
    transition: color var(--transition-fast);
}

label:hover {
    color: var(--ldt-primary);
}

input[type="text"],
input[type="email"],
input[type="tel"],
input[type="password"],
input[type="date"],
input[type="datetime-local"],
input[type="time"],
input[type="number"],
input[type="url"],
textarea,
select {
    width: 100%;
    padding: 0.75rem 1rem;
    margin-bottom: 1rem;
    border: 2px solid var(--ldt-border);
    border-radius: var(--radius-md);
    font-size: 0.9375rem;
    font-family: var(--font-sans);
    transition: all var(--transition-fast);
    background: var(--ldt-white);
    color: var(--ldt-dark);
}

input[type="text"]::placeholder,
input[type="email"]::placeholder,
input[type="tel"]::placeholder,
input[type="password"]::placeholder,
input[type="date"]::placeholder,
input[type="time"]::placeholder,
input[type="number"]::placeholder,
input[type="url"]::placeholder,
textarea::placeholder {
    color: var(--ldt-grey);
}

input[type="text"]:focus,
input[type="email"]:focus,
input[type="tel"]:focus,
input[type="password"]:focus,
input[type="date"]:focus,
input[type="datetime-local"]:focus,
input[type="time"]:focus,
input[type="number"]:focus,
input[type="url"]:focus,
textarea:focus,
select:focus {
    outline: none;
    border-color: var(--ldt-primary);
    box-shadow: 0 0 0 3px rgba(240, 84, 9, 0.1);
    background: #fafafa;
}

textarea {
    resize: vertical;
    min-height: 120px;
    font-family: var(--font-sans);
}

select {
    appearance: none;
    background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e");
    background-repeat: no-repeat;
    background-position: right 1rem center;
    background-size: 1.2em;
    padding-right: 2.5rem;
    cursor: pointer;
}

/* Checkboxes and Radios */
input[type="checkbox"],
input[type="radio"] {
    width: 1.25rem;
    height: 1.25rem;
    margin-right: 0.5rem;
    cursor: pointer;
    accent-color: var(--ldt-primary);
}

/* Error States */
.field-error {
    border-color: var(--ldt-danger) !important;
}

.error-message {
    color: var(--ldt-danger);
    font-size: 0.875rem;
    margin-top: -0.75rem;
    margin-bottom: 0.75rem;
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.error-message:before {
    content: "⚠";
}

/* Success States */
input.success,
select.success,
textarea.success {
    border-color: var(--ldt-success);
}

/* ==========================================================================
   6. BUTTONS - Modern with Better Hover States
   ========================================================================== */
.btn,
input[type="submit"],
button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 0.75rem 1.5rem;
    font-size: 0.9375rem;
    font-weight: 600;
    text-align: center;
    text-decoration: none;
    border-radius: var(--radius-md);
    transition: all var(--transition-fast);
    cursor: pointer;
    border: none;
    font-family: var(--font-sans);
    white-space: nowrap;
    user-select: none;
    position: relative;
}

/* Primary Button */
.btn-primary,
input[type="submit"] {
    background: linear-gradient(135deg, var(--ldt-primary) 0%, var(--ldt-primary-dark) 100%);
    color: var(--ldt-white);
    box-shadow: 0 4px 6px rgba(240, 84, 9, 0.2);
}

.btn-primary:hover,
input[type="submit"]:hover {
    background: linear-gradient(135deg, var(--ldt-primary-dark) 0%, #b83a06 100%);
    transform: translateY(-2px);
    box-shadow: 0 8px 12px rgba(240, 84, 9, 0.3);
}

.btn-primary:active,
input[type="submit"]:active {
    transform: translateY(0);
    box-shadow: 0 2px 4px rgba(240, 84, 9, 0.2);
}

/* Secondary Button */
.btn-secondary {
    background: var(--ldt-dark);
    color: var(--ldt-white);
}

.btn-secondary:hover {
    background: linear-gradient(135deg, var(--ldt-dark) 0%, #383838 100%);
    transform: translateY(-2px);
    box-shadow: 0 8px 12px rgba(0, 0, 0, 0.15);
}

.btn-secondary:active {
    transform: translateY(0);
}

/* Success Button */
.btn-success {
    background: var(--ldt-success);
    color: var(--ldt-white);
}

.btn-success:hover {
    background: #0d9e6f;
    transform: translateY(-2px);
}

/* Danger Button */
.btn-danger {
    background: var(--ldt-danger);
    color: var(--ldt-white);
}

.btn-danger:hover {
    background: #dc2626;
    transform: translateY(-2px);
}

/* Reset for a <button> that must render exactly like the plain, unstyled
   <a> it replaces - the bare `button` rule above otherwise adds a layout
   and an implicit background this one control never had (N-203). Its one
   site (view_module_students.html) sits inside a <nav>, so the nav-scoped
   rules below restore `nav a`'s weight and hover-underline (main.css:1625)
   rather than the 400-weight, no-underline look a bare reset would give it. */
.btn-plain-link {
    display: inline;
    background: none;
    padding: 0;
    margin: 0;
    font: inherit;
    white-space: normal;
    color: var(--ldt-primary);
}

.btn-plain-link:hover {
    color: var(--ldt-primary-dark);
}

nav .btn-plain-link {
    font-weight: 600;
    position: relative;
}

nav .btn-plain-link::after {
    content: '';
    position: absolute;
    width: 0;
    height: 2px;
    bottom: -2px;
    left: 0;
    background: var(--ldt-primary);
    transition: width var(--transition-fast);
}

nav .btn-plain-link:hover::after {
    width: 100%;
}

/* Link Button */
.btn-link {
    background: transparent;
    color: var(--ldt-primary);
    text-decoration: underline;
}

.btn-link:hover {
    color: var(--ldt-primary-dark);
}

/* Small Button */
.btn-sm {
    padding: 0.5rem 1rem;
    font-size: 0.8125rem;
}

/* Large Button */
.btn-lg {
    padding: 1rem 2rem;
    font-size: 1rem;
}

/* Full Width Button */
.btn-block {
    width: 100%;
}

/* Button Loading State */
.btn.loading {
    position: relative;
    color: transparent;
    pointer-events: none;
}

.btn.loading::after {
    content: '';
    position: absolute;
    width: 16px;
    height: 16px;
    top: 50%;
    left: 50%;
    margin: -8px 0 0 -8px;
    border: 2px solid rgba(255, 255, 255, 0.3);
    border-top-color: white;
    border-radius: 50%;
    animation: spin 0.6s linear infinite;
}

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

/* Button Group */
.btn-group {
    display: flex;
    gap: 0.5rem;
    margin-bottom: var(--spacing-md);
}

/* ==========================================================================
   7. TABLES - Responsive & Modern
   ========================================================================== */
table {
    width: 100%;
    border-collapse: collapse;
    margin-bottom: var(--spacing-xl);
    background: var(--ldt-white);
    box-shadow: var(--shadow-md);
    border-radius: var(--radius-lg);
    overflow: hidden;
}

/* Scoped to .table-highlight, not the bare elements (N-68, N-74).
   The dark thead gradient and the white header text are one design, and they
   only hold together on a table this stylesheet controls. On a Bootstrap
   .table they came apart: Bootstrap paints --bs-table-bg (#fff) onto every
   cell through `.table > :not(caption) > * > *`, which is more specific than a
   bare `thead`, so the gradient was covered over and the !important white text
   landed on white. That made the headers invisible on /agent/drafts/, on
   /agent/staff/accounts/, on the SAR list and on the portal change-request
   list - measured, not inferred.

   SPARK's own tables all carry .table-highlight and are unaffected; a
   Bootstrap .table now keeps Bootstrap's own header colours, which are
   legible. */
.table-highlight thead {
    background: linear-gradient(135deg, #546E7A 0%, #455A64 100%);
}

/* thead th, not any th: the white is one half of the dark thead gradient and
   only holds on a cell that has it.  A <th scope="rowgroup"> inside a tbody -
   the sub-category heading on the student portal's resources list - got the
   !important white with no gradient behind it and rendered white on white. */
.table-highlight thead th {
    padding: 1rem;
    text-align: left;
    border: none;
    color: #FFFFFF !important;
    font-weight: 600;
    font-size: 0.9375rem;
    letter-spacing: 0.025em;
}

td {
    padding: 1rem;
    text-align: left;
    border-bottom: 1px solid var(--ldt-border);
    color: var(--ldt-grey);
}

tbody tr {
    transition: all var(--transition-fast);
}

tbody tr:hover {
    background-color: rgba(240, 84, 9, 0.05);
}

tbody tr:last-child td {
    border-bottom: none;
}

/* Highlighted Table Rows */
.hoverTable tr:hover td {
    background-color: rgba(240, 84, 9, 0.08);
    color: var(--ldt-dark);
}

/* Base table-highlight text colour – uses the adaptive --ldt-text variable so
   cells are readable in BOTH light and dark mode regardless of inheritance.
   (Previously only dark-mode td colour was set, leaving light-mode and some
   HTMX-swapped contexts to inherit unpredictably.) */
.table-highlight {
    color: var(--ldt-text);
}
.table-highlight td {
    color: var(--ldt-text);
}

/* A row-group heading inside a tbody reads as a cell, not as a column header,
   so it takes the cell colour rather than the thead gradient's white. */
.table-highlight tbody th {
    color: var(--ldt-text);
    font-weight: 600;
}

.table-highlight tr:hover {
    background-color: rgba(61, 125, 153, 0.08);
}

/* Table Actions */
.actions {
    display: flex;
    gap: 0.5rem;
    text-align: right;
    flex-wrap: wrap;
}

td.actions {
    white-space: nowrap;
    width: auto;
}

td.actions .btn {
    padding: 0.5rem 1rem;
    font-size: 0.8125rem;
}

.table-responsive {
    margin: 0;
    padding: 0;
    overflow-x: auto;
    border-radius: var(--radius-lg);
    -webkit-overflow-scrolling: touch;
}

.table-responsive table {
    min-width: 500px;
    margin-bottom: 0;
}

/* Attendance Summary Table */
.attendance-summary {
    margin: var(--spacing-xl) 0;
}

.attendance-summary table {
    background-color: var(--ldt-lighter-grey);
}

.attendance-summary thead {
    background: linear-gradient(135deg, var(--ldt-secondary) 0%, var(--ldt-secondary-dark) 100%);
}

.attendance-summary th {
    text-align: center;
    padding: 1rem;
}

.attendance-summary td {
    text-align: center;
    padding: 1rem;
}

.attendance-summary td strong {
    color: var(--ldt-success);
    font-weight: 700;
}

/* ==========================================================================
   8. CARDS - Modern Component Styling
   ========================================================================== */
.card {
    background: var(--ldt-white);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
    margin-bottom: var(--spacing-xl);
    overflow: hidden;
    transition: all var(--transition-base);
    border: 1px solid var(--ldt-border);
}

.card-header {
    background: linear-gradient(135deg, #f8f9fa 0%, #f3f4f6 100%);
    /*    padding: var(--spacing-lg); */
    padding: 1rem 1.5rem;
    border-bottom: 2px solid var(--ldt-border);
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.card-header h3 {
    margin: 0;
    color: var(--ldt-primary);
    font-size: 1.25rem;
    flex: 1;
}

.card-header-actions {
    display: flex;
    gap: var(--spacing-sm);
}

.card-body {
    padding: var(--spacing-lg);
}

.card-footer {
    padding: var(--spacing-lg);
    border-top: 1px solid var(--ldt-border);
    background: var(--ldt-lighter-grey);
    display: flex;
    justify-content: space-between;
    align-items: center;
}

/* ==========================================================================
   9. MESSAGES & ALERTS - Modern Notifications
   ========================================================================== */
.messages {
    list-style: none;
    padding: 0;
    margin: 0 auto var(--spacing-lg);
    width: 100%;
    max-width: 600px;
    z-index: 500;
}

#messages-container {
    position: fixed !important;
    top: 2.5rem;
    left: 50%;
    transform: translateX(-50%);
    z-index: 1050;
    width: max-content;
    max-width: 90vw;
}

@keyframes message-pop {
    from {
        transform: translateY(-8px);
        opacity: 0;
    }
    to {
        transform: translateY(0);
        opacity: 1;
    }
}

.message {
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
    border-left: 4px solid currentColor;
    font-weight: 500;
    animation: message-pop 0.2s ease-out;
    padding: var(--spacing-md) var(--spacing-lg) var(--spacing-md) calc(var(--spacing-lg) + 4px);
    padding-right: 2.5rem;
    position: relative;
    margin-bottom: var(--spacing-md);
    border-radius: var(--radius-md);
    opacity: 1;
    transition: opacity var(--transition-slow) ease;
    display: flex;
    align-items: center;
    gap: var(--spacing-md);
}

.message-success {
    background-color: #ECFDF5;
    color: #10B981;
    border-left-color: var(--ldt-success);
}

.message-warning {
    background-color: #FFFBEB;
    color: #92400e;
    border-left-color: var(--ldt-warning);
}

.message-error {
    background-color: #FEE2E2;
    color: #EF4444;
    border-left-color: var(--ldt-danger);
}

.message-info {
    background-color: #EFF6FF;
    color: #3B82F6;
    border-left-color: var(--ldt-info);
}

.message-close {
    position: absolute;
    top: 50%;
    right: 1rem;
    transform: translateY(-50%);
    background: none;
    border: none;
    font-size: 1.5rem;
    cursor: pointer;
    opacity: 0.6;
    transition: opacity var(--transition-fast);
    color: inherit;
    padding: 0;
}

.message-close:hover {
    opacity: 1;
}

/* Alert Styles */
.alert {
    padding: var(--spacing-lg);
    border-radius: var(--radius-md);
    margin-bottom: var(--spacing-lg);
    border-left: 4px solid transparent;
}

.alert-success {
    background-color: var(--ldt-success-light);
    border-left-color: var(--ldt-success);
    color: var(--ldt-success);
}

.alert-error,
.alert-danger {
    background-color: var(--ldt-danger-light);
    border-left-color: var(--ldt-danger);
    color: var(--ldt-danger);
}

.alert-warning {
    background-color: var(--ldt-warning-light);
    border-left-color: var(--ldt-warning);
    color: var(--ldt-warning-text);
}

.alert-info {
    background-color: var(--ldt-info-light);
    border-left-color: var(--ldt-info);
    color: var(--ldt-info);
}

.alert-icon {
    font-size: 1.25rem;
    flex-shrink: 0;
}

/* ==========================================================================
   10. BADGES & STATUS INDICATORS
   ========================================================================== */
.badge {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.375rem 0.75rem;
    border-radius: var(--radius-full);
    font-size: 0.8125rem;
    font-weight: 600;
    white-space: nowrap;
    letter-spacing: 0.025em;
}

.badge-primary {
    background-color: rgba(240, 84, 9, 0.1);
    color: var(--ldt-primary);
}

.badge-secondary {
    background-color: rgba(61, 125, 153, 0.1);
    color: var(--ldt-secondary);
}

.badge-success {
    background-color: var(--ldt-success-light);
    color: var(--ldt-success);
}

.badge-danger {
    background-color: var(--ldt-danger-light);
    color: var(--ldt-danger);
}

.badge-warning {
    background-color: var(--ldt-warning-light);
    color: var(--ldt-warning-text);
}

.badge-info {
    background-color: var(--ldt-info-light);
    color: var(--ldt-info);
}

/* Status Indicator Dot */
.badge.dot {
    padding: 0.5rem;
}

.badge.dot::before {
    content: '';
    width: 0.65rem;
    height: 0.65rem;
    border-radius: 50%;
    background: currentColor;
}

/* Pill Badge */
.badge-pill {
    border-radius: var(--radius-full);
    padding: 0.5rem 1rem;
}

/* ==========================================================================
   11. NAVIGATION - Enhanced with Modern Tabs
   ========================================================================== */
nav {
    margin-bottom: var(--spacing-xl);
}

nav a {
    color: var(--ldt-primary);
    text-decoration: none;
    font-weight: 600;
    transition: color var(--transition-fast);
    position: relative;
}

nav a:hover {
    color: var(--ldt-primary-dark);
}

nav a::after {
    content: '';
    position: absolute;
    width: 0;
    height: 2px;
    bottom: -2px;
    left: 0;
    background: var(--ldt-primary);
    transition: width var(--transition-fast);
}

nav a:hover::after {
    width: 100%;
}

/* Navigation Tabs */
.nav-tabs {
    display: flex;
    gap: 0.5rem;
    border-bottom: 2px solid var(--ldt-border);
    margin-bottom: var(--spacing-lg);
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

/* `.nav-tab-selected` shares the whole box, not only the colour (N-301).
   Two templates wrote `class="nav-tab{% if current %}-selected{% endif %}"`,
   which *replaces* the class rather than joining it, so the current tab lost
   the padding, the font weight and the flex row along with the grey.  Both
   templates now join the classes; this list is what stops the next author
   paying for the same mistake, and costs nothing where both are present. */
.nav-tab,
.nav-tab-selected {
    padding: var(--spacing-md) var(--spacing-lg);
    font-size: 0.9375rem;
    font-weight: 600;
    color: var(--ldt-grey);
    cursor: pointer;
    transition: all var(--transition-fast);
    white-space: nowrap;
    text-decoration: none;
    background: transparent;
    /* Sides off, bottom kept: this used to read `border: none` *after*
       `border-bottom: 3px solid transparent`, which reset the style to none on
       all four sides - so the hover and selected rules below set a colour on a
       border that had no style and no width, and the orange underline the
       visual system asks for could not render anywhere (N-302). */
    border: none;
    border-bottom: 3px solid transparent;
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.nav-tab:hover {
    color: var(--ldt-primary);
    border-bottom-color: rgba(240, 84, 9, 0.3);
}

/* The `:hover` copies are what keep the current tab's underline at full
   strength under the pointer.  `.nav-tab:hover` is (0,2,0) and this rule was
   (0,1,0), so hovering the current tab faded its own marker to 30% - invisible
   until N-302 made the underline render at all. */
.nav-tab.active,
.nav-tab.active:hover,
.nav-tab-selected,
.nav-tab-selected:hover {
    color: var(--ldt-primary);
    border-bottom-color: var(--ldt-primary);
}

/* --------------------------------------------------------------------------
   The student record's two-level local navigation

   The student record's grouped destinations, rendered as one tab row by the owner's D-05
   decision (§0 V-24, 2026-09-09), with the open group's destinations on a
   second row beneath it.  Markup:
   students/templates/students/partials/_student_record_tabs.html.

   `.record-tabs` is `.nav-tabs` that wraps instead of scrolling, and that is
   the fix for the one thing V-24 handed this slice: `.nav-tabs` is `nowrap`
   with `overflow-x: auto` above 640px, so a tab that does not fit is scrolled
   out of view with no affordance, and the tab that does not fit is the last
   one - Restricted information.  Reordering only chooses a different casualty;
   wrapping means there is not one, at any width.  Retaining a destination and
   keeping it reachable are two requirements, and §9.1 asks for both (N-303).
   -------------------------------------------------------------------------- */
.record-tabs {
    flex-wrap: wrap;
    overflow-x: visible;
}

.record-subtabs {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin: calc(var(--spacing-lg) * -1 + 0.35rem) 0 var(--spacing-lg);
}

/* The author `display: flex` above beats the browser's own `[hidden]` rule, so
   the groups that are not open have to be hidden here rather than by the
   attribute alone. */
.record-subtabs[hidden] {
    display: none;
}

.record-subtab {
    padding: 0.3rem 0.75rem;
    font-size: 0.85rem;
    font-weight: 500;
    color: var(--ldt-grey);
    text-decoration: none;
    white-space: nowrap;
    border-radius: 999px;
    background-color: rgba(61, 125, 153, 0.09);
    transition: all var(--transition-fast);
}

.record-subtab:hover {
    color: var(--ldt-primary);
    background-color: rgba(240, 84, 9, 0.12);
}

.record-subtab-current,
.record-subtab-current:hover {
    color: #FFFFFF;
    font-weight: 600;
    background-color: var(--ldt-primary);
}

/* The boundary tab.  The restricted destinations are the eight the sensitive
   shell separates on purpose, so the group that reaches them is tinted the way
   the Sensitive Info tab always has been - the same rgba the two record
   templates carried inline - rather than styled like its five neighbours. */
.record-tab-restricted {
    background-color: rgba(61, 125, 153, 0.1);
}

body.dark-mode .record-subtab {
    color: var(--ldt-grey);
    background-color: rgba(255, 255, 255, 0.06);
}

body.dark-mode .record-subtab:hover {
    color: var(--ldt-primary);
    background-color: rgba(240, 84, 9, 0.18);
}

body.dark-mode .record-subtab-current,
body.dark-mode .record-subtab-current:hover {
    color: #FFFFFF;
    background-color: var(--ldt-primary);
}

body.dark-mode .record-tab-restricted {
    background-color: rgba(61, 125, 153, 0.22);
}

/* Breadcrumb Navigation */
.breadcrumb {
    display: flex;
    align-items: center;
    gap: var(--spacing-sm);
    padding: var(--spacing-md) 0;
    margin-bottom: var(--spacing-lg);
    flex-wrap: wrap;
}

.breadcrumb-item {
    color: var(--ldt-grey);
}

/* Two crumbs (Dashboard, the group) are <a> elements now - same look as the
   plain-text crumb beside them, an underline only on hover so the strip
   still reads as "where you are", not a row of links. */
.breadcrumb-item[href] {
    text-decoration: none;
}

.breadcrumb-item[href]:hover {
    text-decoration: underline;
}

.breadcrumb-item.active {
    color: var(--ldt-dark);
    font-weight: 600;
}

.breadcrumb-item + .breadcrumb-item::before {
    display: inline-block;
    padding: 0 var(--spacing-sm);
    color: var(--ldt-border);
    content: "/";
}

/* The enrolment wizard stacks two breadcrumbs and a row of correction buttons
   above every step. At the breadcrumb's own spacing that is most of a phone
   screen before the step itself, so the strips are tightened there. */
@media screen and (max-width: 640px) {
    .enrolment-strip {
        padding: var(--spacing-xs) 0;
        margin-bottom: var(--spacing-sm);
        gap: var(--spacing-xs);
    }
}

/* ==========================================================================
   12. GRID LAYOUTS - Responsive Grid System
   ========================================================================== */
.grid {
    display: grid;
    gap: var(--spacing-lg);
    grid-auto-flow: row;
}

.grid-cols-1 {
    grid-template-columns: 1fr;
}

.grid-cols-2 {
    grid-template-columns: repeat(2, 1fr);
}

.grid-cols-3 {
    grid-template-columns: repeat(3, 1fr);
}

.grid-cols-4 {
    grid-template-columns: repeat(4, 1fr);
}

/* Flex Layout */
.flex {
    display: flex;
}

.flex-col {
    flex-direction: column;
}

.flex-wrap {
    flex-wrap: wrap;
}

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

.justify-center {
    justify-content: center;
}

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

.gap-1 {
    gap: var(--spacing-sm);
}

.gap-2 {
    gap: var(--spacing-md);
}

.gap-3 {
    gap: var(--spacing-lg);
}

.gap-4 {
    gap: var(--spacing-xl);
}

/* ==========================================================================
   13. UTILITY CLASSES - Spacing, Text, and Display
   ========================================================================== */

/* Margin Utilities */
.m-auto {
    margin: auto;
}

.mx-auto {
    margin-left: auto;
    margin-right: auto;
}

.my-auto {
    margin-top: auto;
    margin-bottom: auto;
}

.mt-1 {
    margin-top: var(--spacing-sm);
}

.mt-2 {
    margin-top: var(--spacing-md);
}

.mt-3 {
    margin-top: var(--spacing-lg);
}

.mt-4 {
    margin-top: var(--spacing-xl);
}

.mb-1 {
    margin-bottom: var(--spacing-sm);
}

.mb-2 {
    margin-bottom: var(--spacing-md);
}

.mb-3 {
    margin-bottom: var(--spacing-lg);
}

.mb-4 {
    margin-bottom: var(--spacing-xl);
}

.ml-1 {
    margin-left: var(--spacing-sm);
}

.ml-2 {
    margin-left: var(--spacing-md);
}

.ml-3 {
    margin-left: var(--spacing-lg);
}

.ml-4 {
    margin-left: var(--spacing-xl);
}

.mr-1 {
    margin-right: var(--spacing-sm);
}

.mr-2 {
    margin-right: var(--spacing-md);
}

.mr-3 {
    margin-right: var(--spacing-lg);
}

.mr-4 {
    margin-right: var(--spacing-xl);
}

/* Padding Utilities */
.p-0 {
    padding: 0;
}

.p-1 {
    padding: var(--spacing-sm);
}

.p-2 {
    padding: var(--spacing-md);
}

.p-3 {
    padding: var(--spacing-lg);
}

.p-4 {
    padding: var(--spacing-xl);
}

.px-1 {
    padding-left: var(--spacing-sm);
    padding-right: var(--spacing-sm);
}

.px-2 {
    padding-left: var(--spacing-md);
    padding-right: var(--spacing-md);
}

.px-3 {
    padding-left: var(--spacing-lg);
    padding-right: var(--spacing-lg);
}

.py-1 {
    padding-top: var(--spacing-sm);
    padding-bottom: var(--spacing-sm);
}

.py-2 {
    padding-top: var(--spacing-md);
    padding-bottom: var(--spacing-md);
}

.py-3 {
    padding-top: var(--spacing-lg);
    padding-bottom: var(--spacing-lg);
}

/* Text Alignment */
.text-left {
    text-align: left;
}

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

.text-right {
    text-align: right;
}

.text-justify {
    text-align: justify;
}

/* Text Styling */
.font-bold {
    font-weight: 700;
}

.font-semibold {
    font-weight: 600;
}

.font-medium {
    font-weight: 500;
}

.font-normal {
    font-weight: 400;
}

.font-light {
    font-weight: 300;
}

/* Bootstrap-compatible weight utilities */
.fw-600 { font-weight: 600; }
.fw-500 { font-weight: 500; }
.fw-700 { font-weight: 700; }

/* Detail label – used in student and admissions detail views */
.detail-label {
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--ldt-grey);
    margin-bottom: 0.2rem;
}

/* Student profile layout */
.profile-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 2rem;
    flex-wrap: wrap;
    gap: 1rem;
}

.profile-actions {
    display: flex;
    gap: 1rem;
    flex-wrap: wrap;
}

.details-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
    gap: 1.5rem;
}

.detail-item {
    display: flex;
    flex-direction: column;
}

.detail-item label {
    font-size: 0.875rem;
    color: var(--ldt-text-muted);
    margin-bottom: 0.25rem;
    font-weight: 500;
}

.detail-item span {
    font-size: 1rem;
    color: var(--ldt-text);
}

/* Django's "Clear" option on a file field is a choice, not a field label. */
.detail-item .clearable-file-input label {
    display: inline;
    font-size: 0.875rem;
    font-weight: 400;
    color: var(--ldt-text);
}

.uppercase {
    text-transform: uppercase;
}

.lowercase {
    text-transform: lowercase;
}

.capitalize {
    text-transform: capitalize;
}

.truncate {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Text Colors */
.text-primary {
    color: var(--ldt-primary);
}

.text-secondary {
    color: var(--ldt-secondary);
}

.text-success {
    color: var(--ldt-success);
}

.text-danger {
    color: var(--ldt-danger);
}

.text-warning {
    color: var(--ldt-warning);
}

.text-info {
    color: var(--ldt-info);
}

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

/* Bootstrap's .text-muted uses --bs-secondary-color which doesn't adapt to
   dark mode. Override it here so it uses the project's adaptive muted colour.
   Without this, .text-muted resolves to #6B7280 (medium grey) in dark mode,
   which is near-invisible on dark backgrounds. */
body.dark-mode .text-muted {
    color: var(--ldt-text-muted) !important;
}

.text-dark {
    color: var(--ldt-dark);
}

.text-light {
    color: var(--ldt-light);
}

/* Background Colors */
.bg-primary {
    background-color: var(--ldt-primary);
    color: white;
}

.bg-secondary {
    background-color: var(--ldt-secondary);
    color: white;
}

.bg-success {
    background-color: var(--ldt-success);
    color: white;
}

.bg-danger {
    background-color: var(--ldt-danger);
    color: white;
}

.bg-warning {
    background-color: var(--ldt-warning);
    color: white;
}

.bg-info {
    background-color: var(--ldt-info);
    color: white;
}

.bg-light {
    background-color: var(--ldt-light);
}

.bg-lighter {
    background-color: var(--ldt-lighter-grey);
}

/* Display Utilities */
.d-none {
    display: none;
}

.d-inline {
    display: inline;
}

.d-inline-block {
    display: inline-block;
}

.d-block {
    display: block;
}

.d-flex {
    display: flex;
}

.d-grid {
    display: grid;
}

.hidden {
    display: none !important;
}

.visible {
    display: block !important;
}

/* Visibility Utilities */
.invisible {
    visibility: hidden;
}

.visible {
    visibility: visible;
}

/* Opacity Utilities */
.opacity-50 {
    opacity: 0.5;
}

.opacity-75 {
    opacity: 0.75;
}

.opacity-100 {
    opacity: 1;
}

/* Width/Height Utilities */
.w-full {
    width: 100%;
}

.w-auto {
    width: auto;
}

.h-auto {
    height: auto;
}

/* ==========================================================================
   14. ANIMATIONS - Modern Transitions & Effects
   ========================================================================== */
@keyframes fadeIn {
    from {
        opacity: 0;
        transform: translateY(-10px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

.fade-in {
    animation: fadeIn var(--transition-base) ease-out;
}

/* Flash messages fade out after 7 seconds and then stop taking up space. */
.message.fade-in[data-auto-dismiss] {
    animation: message-dismiss 0.5s ease 7s forwards;
}

@keyframes message-dismiss {
    99% {
        opacity: 0;
    }
    100% {
        opacity: 0;
        visibility: hidden;
        height: 0;
        margin: 0;
        padding: 0;
        border-width: 0;
        overflow: hidden;
    }
}

@keyframes slideIn {
    from {
        transform: translateX(-20px);
        opacity: 0;
    }
    to {
        transform: translateX(0);
        opacity: 1;
    }
}

.slide-in {
    animation: slideIn var(--transition-base) ease-out;
}

@keyframes slideInRight {
    from {
        transform: translateX(20px);
        opacity: 0;
    }
    to {
        transform: translateX(0);
        opacity: 1;
    }
}

.slide-in-right {
    animation: slideInRight var(--transition-base) ease-out;
}

@keyframes scalePulse {
    0%, 100% {
        transform: scale(1);
    }
    50% {
        transform: scale(1.05);
    }
}

.pulse {
    animation: scalePulse 2s ease-in-out infinite;
}

@keyframes shimmer {
    0% {
        background-position: -1000px 0;
    }
    100% {
        background-position: 1000px 0;
    }
}

.shimmer-loading {
    animation: shimmer 2s infinite;
    background: linear-gradient(90deg, #f5f5f5 25%, #e5e5e5 50%, #f5f5f5 75%);
    background-size: 1000px 100%;
}

/* ==========================================================================
   15. ACCESSIBILITY - Keyboard Navigation & Screen Readers
   ========================================================================== */

/* Focus styles for keyboard navigation */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
    outline: 3px solid var(--ldt-primary);
    outline-offset: 2px;
    border-radius: var(--radius-md);
}

/* Reduce motion for users who prefer it */
@media (prefers-reduced-motion: reduce) {
    * {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
}

/* High contrast mode support */
@media (prefers-contrast: more) {
    :root {
        --ldt-primary: #c84a07;
        --ldt-secondary: #2a5a74;
        --ldt-dark: #000000;
        --ldt-border: #333333;
    }
}

/* Skip to content link */
.skip-to-content {
    position: absolute;
    top: -40px;
    left: 0;
    background: var(--ldt-primary);
    color: white;
    padding: 0.5rem 1rem;
    text-decoration: none;
    z-index: 100;
    border-radius: var(--radius-md);
}

.skip-to-content:focus {
    top: 1rem;
    left: 1rem;
}

/* ==========================================================================
   16. RESPONSIVE DESIGN - Mobile-First Approach
   ========================================================================== */

/* Mobile: 320px and up (default styles) */
@media screen and (max-width: 640px) {
    /* Adjust typography for smaller screens */
    h1 {
        font-size: 1.5rem;
    }

    h2 {
        font-size: 1.25rem;
    }

    h3 {
        font-size: 1.125rem;
    }

    /* Adjust header */
    .main-header {
        padding: 0.75rem;
        gap: 0.5rem;
    }

    .menu-toggle {
        display: block;
    }

    /* The heading holds a picture now, and `flex: 5` - a zero basis - let the
       phone squeeze it to 50px wide, which scales the whole lockup down with
       the box and takes it far below the README's 30px floor.  A content-sized,
       unshrinkable item wraps to its own row instead, which is what the grey
       wordmark it replaced did at this width. */
    .site-title {
        font-size: 1.25rem;
        order: 1;
        flex: 0 0 auto;
    }

    .spark-lockup {
        /* The asset README's floor: below about 30px the icons stop reading.
           At 30px the lockup is about 144px wide, which is what the grey
           wordmark it replaced measured - so the header wraps where it always
           wrapped and the phone gains no extra row. */
        height: 30px;
    }

    .logo {
        height: 50px;
    }

    /* Hide some elements on mobile */
    .header-right {
        order: 3;
        flex: 0 0 auto;
    }

    .context-bar {
        padding: var(--spacing-sm) 0.75rem;
    }

    /* Adjust content padding */
    #main {
        padding: var(--spacing-md);
    }

    #content {
        padding: 0 var(--spacing-md);
    }

    /* Adjust forms */
    form.form-card {
        padding: var(--spacing-lg);
        max-width: 100%;
    }

    /* Stack form groups */
    .form-group {
        margin-bottom: var(--spacing-md);
    }

    /* Full-width button on mobile */
    .btn {
        width: 100%;
        justify-content: center;
    }

    .btn-group {
        flex-direction: column;
    }

    /* Adjust tables - horizontal scroll on small screens */
    table {
        font-size: 0.875rem;
    }

    th, td {
        padding: 0.75rem 0.5rem;
    }

    /* Stack tabs */
    .nav-tabs {
        flex-wrap: wrap;
        gap: 0.25rem;
    }

    /* Paired for the same reason the base box rule is (N-301): a template that
       writes only `nav-tab-selected` would otherwise keep the desktop padding
       and type at phone width while every tab beside it shrank. */
    .nav-tab,
    .nav-tab-selected {
        padding: var(--spacing-sm) var(--spacing-md);
        font-size: 0.875rem;
    }

    /* Adjust cards */
    .card-body {
        padding: var(--spacing-md);
    }

    .card-header {
        padding: var(--spacing-md);
    }

    .card-header h3 {
        font-size: 1.125rem;
    }

    /* Adjust grid layouts */
    .grid {
        gap: var(--spacing-md);
    }

    .grid-cols-2,
    .grid-cols-3,
    .grid-cols-4 {
        grid-template-columns: 1fr;
    }

    /* Adjust messages width */
    .messages {
        max-width: 100%;
        width: 95%;
    }

    /* Adjust page header */
    .page-header {
        flex-direction: column;
        align-items: flex-start;
    }

    /* Action buttons in tables */
    .actions {
        flex-direction: column;
    }

    td.actions {
        white-space: normal;
    }
}

/* Tablet: 768px and up */
@media screen and (min-width: 641px) and (max-width: 1024px) {
    h1 {
        font-size: 1.875rem;
    }

    h2 {
        font-size: 1.5rem;
    }

    .main-header {
        padding: 1rem;
    }

    .grid-cols-4 {
        grid-template-columns: repeat(2, 1fr);
    }

    #content {
        padding: 0 var(--spacing-lg);
    }

    .messages {
        width: 90%;
    }

    .sidenav {
        width: 240px;
        left: -240px;
    }
}

/* Desktop: 1024px and up */
@media screen and (min-width: 1025px) {
    /* Desktop styles */
    .grid-cols-4 {
        grid-template-columns: repeat(4, 1fr);
    }

    .grid-cols-3 {
        grid-template-columns: repeat(3, 1fr);
    }
}

/* Extra Large: 1400px and up */
@media screen and (min-width: 1401px) {
    .container {
        max-width: 1380px;
    }

    #content {
        padding: 0 4rem;
    }
}

/* Landscape mode adjustments */
@media screen and (max-height: 600px) and (orientation: landscape) {
    .main-header {
        padding: 0.5rem;
    }

    .logo {
        height: 40px;
    }

    form.form-card {
        padding: var(--spacing-md);
    }

    .card-body {
        padding: var(--spacing-md);
    }
}

/* Touch device adjustments */
@media (hover: none) and (pointer: coarse) {
    button,
    .btn,
    a {
        padding: 0.875rem 1.5rem;
    }

    /* Increase touch target sizes */
    input[type="checkbox"],
    input[type="radio"] {
        width: 1.5rem;
        height: 1.5rem;
    }
}

/* ==========================================================================
   17. PRINT STYLES - Optimize for Printing
   ========================================================================== */
@media print {
    /* Hide navigation and interactive elements */
    .sidenav,
    .context-bar,
    .menu-toggle,
    .btn,
    .logout-btn,
    .actions,
    .message-close,
    nav,
    .skip-to-content {
        display: none !important;
    }

    /* Reset colors for printing */
    body {
        background: white;
        color: black;
        font-size: 12pt;
    }

    /* The lockup is all white in dark mode, and a reader who prints with dark
       mode on still prints on white paper - so the brand colours come back for
       print whatever the theme. */
    body.dark-mode {
        --spark-orange: #EF5623;
        --spark-grey: #878787;
        --spark-ink: #140C0A;
        --spark-accent: #EF5623;
        --spark-glyph: #FFFFFF;
        --spark-glyph-ink: #FFFFFF;
    }

    /* Ensure content is visible */
    #main {
        margin-left: 0 !important;
        padding: 0;
        min-height: auto;
    }

    #content {
        padding: 0 !important;
    }

    /* Prevent page breaks inside elements */
    table,
    .card,
    form,
    .page-header {
        page-break-inside: avoid;
    }

    /* Show URLs only for links a reader cannot follow off the page.
       Scoped to absolute URLs: conventions 2.1 now requires every HTMX anchor
       to carry a native href, so `a[href]` printed " (/students/)" after every
       in-app link on every printed page (N-208). */
    a[href^="http"]:after {
        content: " (" attr(href) ")";
    }

    /* Remove shadows and adjust borders for cleaner print */
    .card,
    table,
    form.form-card {
        box-shadow: none;
        border: 1px solid #ccc;
    }

    /* Adjust heading sizes for print */
    h1 {
        font-size: 24pt;
    }

    h2 {
        font-size: 20pt;
    }

    h3 {
        font-size: 16pt;
    }

    /* Make header sticky not needed in print */
    .main-header {
        position: static;
        box-shadow: none;
        border: 1px solid #ccc;
    }

    /* Ensure tables have visible borders */
    table, th, td {
        border: 1px solid #000;
    }
}

/* Additional sidebar enhancements */
.sidenav-section {
    padding: var(--spacing-md) 0;
    border-bottom: 1px solid rgba(255, 255, 255, 0.1);
    flex: 0 0 auto;
}

/* Collapsible drawer groups – visual slice V6, V-DEC-2 (accordion, 2026-09-06).

   Each group is a <details> written by {% nav_group %}; the heading is its
   <summary>, which is why .nav-section-label is no longer `pointer-events:
   none` – it is now the control that opens the group. Everything in this block
   is reached only through core/master.html: the applicant, agent and student
   shells have a .sidenav-section but no group headings in it, so none of this
   crosses into them. Checked against all four shells plus help, login and print
   (rule 6): the print sheet already hides .sidenav outright.
   The drawer measured 2693px tall with every group expanded. */
.nav-group {
    border-bottom: 1px solid rgba(255, 255, 255, 0.07);
}

.nav-group:last-child {
    border-bottom: none;
}

summary.nav-section-label {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    margin: 0;
    padding: 0.55rem var(--spacing-lg);
    font-size: 0.65rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.5);
    cursor: pointer;
    user-select: none;
    /* The native disclosure marker is replaced, not merely restyled: a summary
       with any `display` other than list-item loses its ::marker in Chrome and
       Safari, and this one has to be a flex row to place the chevron and the
       overdue flag. .nav-group-chevron below is the affordance instead. */
    list-style: none;
    transition: background-color var(--transition-fast), color var(--transition-fast);
}

summary.nav-section-label::-webkit-details-marker {
    display: none;
}

summary.nav-section-label:hover {
    background-color: rgba(255, 255, 255, 0.07);
    color: var(--ldt-white);
}

/* Keyboard focus is the whole reason <details> was chosen over a div and a
   click handler, so it has to be visible. Inset, because the drawer clips. */
summary.nav-section-label:focus-visible {
    outline: 2px solid var(--ldt-primary);
    outline-offset: -2px;
}

.nav-group-label {
    flex: 0 1 auto;
}

/* The overdue mark's word – §3.6 requires one beside every hexagon, so that a
   browser which cannot render mask-image loses the shape and not the meaning. */
.nav-group-flag {
    color: var(--ldt-primary);
    font-size: 0.58rem;
    letter-spacing: 0.04em;
}

/* Drawn rather than borrowed from a font: no remote origin is permitted (rule
   7 / N-177), and a border triangle renders identically in every engine. */
/* A count, not a state, so a pill and not a hexagon. On a link it sits at the
   right edge; on a group heading it follows the label, where the overdue flag
   goes, and the chevron keeps the right edge. */
.nav-count {
    flex: 0 0 auto;
    min-width: 1.4rem;
    padding: 0.1rem 0.45rem;
    border-radius: 999px;
    background: var(--ldt-primary);
    color: var(--ldt-white);
    font-size: 0.72rem;
    font-weight: 700;
    line-height: 1.3;
    text-align: center;
    letter-spacing: 0;
}

.nav-link .nav-count {
    margin-left: auto;
}

summary.nav-section-label .nav-count {
    padding: 0.05rem 0.4rem;
    font-size: 0.6rem;
}

.nav-group-chevron {
    margin-left: auto;
    flex: 0 0 auto;
    width: 0;
    height: 0;
    border-left: 4px solid transparent;
    border-right: 4px solid transparent;
    border-top: 5px solid currentColor;
    transform: rotate(-90deg);
    transition: transform var(--transition-fast);
}

.nav-group[open] > summary .nav-group-chevron {
    transform: rotate(0deg);
}


.sidenav-user-section {
    padding: 0.25rem 0.25rem;
    border-top: 1px solid rgba(255, 255, 255, 0.1);
    background: #1F2937;
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    position: sticky;
    top: 0;
    z-index: 1;
}

body.dark-mode .sidenav-user-section {
    background: #0F172A;
}

/* A collapsible filter panel: the body is hidden until the header toggles
   `show` onto it, through hx_actions.js's `toggle-class`.  Shared because two
   pages need it - the attendance register, where it started, and the report
   builder, whose header carried the toggle with no class to toggle and so had
   never collapsed anything (N-207). */
.filter-content { display: none; }
.filter-content.show { display: block; }

/* The utility area's one nav link - Help Centre, beside Logout.
   System plan §5.1 asks that help and account controls share one predictable
   area reachable without scrolling past every feature link; Help Centre used to
   be the last group in the drawer, below all thirty-five other destinations.
   Scoped to .sidenav-user-section, which in the applicant, agent and student
   shells contains no .nav-link at all, so this reaches the staff shell only.
   It is still a .nav-link so that one current-destination mechanism covers
   every drawer link - .sidenav a.active still paints it, without the 4px rule
   that reads as a list marker in a centred block. */
.sidenav-user-section .nav-link {
    align-self: stretch;
    justify-content: center;
    padding: 0.3rem var(--spacing-sm);
    font-size: 0.8rem;
    gap: 0.35rem;
    border-left: none;
}

/* Only the padding: .sidenav a:hover and .sidenav a.active set border-left-COLOR
   and nothing re-declares the style, so the `border-left: none` above already
   suppresses the 4px rule in every state.  Measured on a server-rendered /help/
   page: active reads `none 0px rgb(240,84,9)`. */
.sidenav-user-section .nav-link:hover {
    padding-left: var(--spacing-sm);
}

/* The drawer's one hexagon (visual plan §4.3): identity, at the badge size the
   system reserves for "who or what a row is". No size override – the point of
   .hex-badge being 34x30 everywhere is that the reader learns one shape. */
.sidenav-user-badge {
    letter-spacing: 0;
}

.sidenav-user-name {
    margin: 0.35rem 0 0.5rem 0;
    color: #e5e7eb;
    font-weight: 600;
    font-size: 0.875rem;
    display: flex;
    align-items: center;
    gap: var(--spacing-sm);
    justify-content: center;
    text-align: center;
    line-height: 1.2;
}

.logout-link {
    display: inline-flex;
    align-items: center;
    gap: 0.1rem;
    padding: 0.15rem 0.15rem;
    background: rgba(240, 84, 9, 0.2);
    border-radius: 0.25rem;
    color: var(--ldt-primary);
    font-weight: 300;
    font-size: 0.75rem;
    line-height: 0.25;
    text-decoration: none;
    transition: all var(--transition-fast);
    white-space: nowrap;
}

.logout-link:hover {
    background: rgba(240, 84, 9, 0.3);
    color: var(--ldt-white);
}

.htmx-link {
    cursor: pointer;
}

.nav-link {
    cursor: pointer;
    padding: var(--spacing-md) var(--spacing-lg);
    text-decoration: none;
    font-size: 0.95rem;
    color: #e5e7eb;
    display: flex;
    align-items: center;
    gap: var(--spacing-md);
    transition: all var(--transition-fast);
    border-left: 4px solid transparent;
    position: relative;
}

/* A <button> wearing .nav-link is a nav link that happens to POST - the
   portal's apply-for-another-course bridge. It takes the class's colour,
   size and padding; only the UA button's own chrome has to go. Declared
   above :hover so the hover still lights the left rail. */
button.nav-link {
    width: 100%;
    background: none;
    border: none;
    border-left: 4px solid transparent;
    font-family: inherit;
    text-align: left;
}

.nav-link:hover {
    background-color: rgba(255, 255, 255, 0.1);
    border-left-color: var(--ldt-primary);
    color: var(--ldt-white);
    padding-left: calc(var(--spacing-lg) + 4px);
}

.nav-link.active {
    background-color: rgba(240, 84, 9, 0.15);
    border-left-color: var(--ldt-primary);
    color: var(--ldt-primary);
    font-weight: 600;
}

/* Notifications link styling */
.notifications-link {
    display: inline-flex;
    align-items: center;
    padding: var(--spacing-sm);
    text-decoration: none;
    color: var(--ldt-dark);
    font-size: 1.5rem;
    transition: transform var(--transition-fast);
}

.notifications-link:hover {
    transform: scale(1.15);
}

.badge-notification {
    position: absolute;
    top: -8px;
    right: -8px;
    background: var(--ldt-danger);
    color: white;
    border-radius: var(--radius-full);
    padding: 0.25rem 0.5rem;
    font-size: 0.75rem;
    font-weight: 700;
    min-width: 20px;
    text-align: center;
}

/* ==========================================================================
   Quill rich-text editor (email body) – dark mode
   The snow theme ships light backgrounds + dark text and has no dark variant,
   so without these overrides the editor and its toolbar are invisible /
   unreadable in dark mode. Scope strictly to .dark-mode so light mode keeps
   Quill's default appearance.
   ========================================================================== */
body.dark-mode .ql-toolbar.ql-snow,
body.dark-mode .ql-container.ql-snow {
    border-color: var(--ldt-border);
}
body.dark-mode .ql-container.ql-snow {
    background-color: #1F2937;
}
body.dark-mode .ql-editor {
    color: var(--ldt-dark);
}
body.dark-mode .ql-editor.ql-blank::before {
    /* placeholder text */
    color: var(--ldt-text-muted);
}
/* Toolbar icons + labels */
body.dark-mode .ql-snow .ql-stroke { stroke: var(--ldt-dark); }
body.dark-mode .ql-snow .ql-fill { fill: var(--ldt-dark); }
body.dark-mode .ql-snow .ql-picker { color: var(--ldt-dark); }
/* Dropdown panels (size, colour, background pickers) */
body.dark-mode .ql-snow .ql-picker-options {
    background-color: #1F2937;
    border-color: var(--ldt-border);
}
body.dark-mode .ql-snow .ql-picker-item { color: var(--ldt-dark); }
body.dark-mode .ql-snow.ql-toolbar button:hover .ql-stroke,
body.dark-mode .ql-snow .ql-toolbar button:hover .ql-stroke,
body.dark-mode .ql-snow.ql-toolbar button.ql-active .ql-stroke {
    stroke: var(--ldt-primary);
}
body.dark-mode .ql-snow.ql-toolbar button:hover .ql-fill,
body.dark-mode .ql-snow .ql-toolbar button.ql-active .ql-fill {
    fill: var(--ldt-primary);
}

/* ---------------------------------------------------------------------
   Hover effects converted from onmouseover/onmouseout attributes
   (2026-07-13, CSP hardening fix-up – inline event-handler attributes are
   blocked outright once 'unsafe-inline' is dropped from script-src, and
   unlike inline <script> blocks a nonce does not cover them; :hover is
   simply the right tool for a hover effect and needs no JS at all).
   --------------------------------------------------------------------- */
.student-cohort-card-clickable:hover {
    background: #f9fafb;
}

.student-dashboard-card:hover {
    box-shadow: 0 4px 16px rgba(61, 125, 153, 0.18);
    transform: translateY(-2px);
}

/* Whole-card links (applicant inbox and notifications).  The colour stops the
   link hover colour; dark mode's card colour still wins. */
.applicant-card-clickable:hover {
    box-shadow: var(--shadow-lg);
    transform: translateY(-2px);
    color: var(--bs-body-color);
}

#more-actions-menu a:hover {
    background: #f9fafb;
}

/* ---------------------------------------------------------------------
   Report Builder chart hover tooltip. The element is created and
   positioned from the pointer by reportbuilder/report_builder.js, so only
   its appearance lives here. pointer-events must stay none: the tooltip
   follows the cursor and would otherwise become the hover target itself
   and flicker.
   --------------------------------------------------------------------- */
.rb-chart-tooltip {
    position: fixed;
    z-index: 1080;
    max-width: 22rem;
    padding: 0.35rem 0.6rem;
    border: 1px solid rgba(255, 255, 255, 0.15);
    border-radius: 0.375rem;
    background: rgba(31, 41, 55, 0.96);
    color: #FFFFFF;
    font-size: 0.8125rem;
    line-height: 1.35;
    pointer-events: none;
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.22);
}

.rb-chart-tooltip[hidden] {
    display: none;
}

.rb-chart-tooltip-label {
    font-weight: 600;
}

/* ==========================================================================
   18. HEX SYSTEM - state/identity primitives (SPARK visual system, slice V0)
   The hexagon means state or identity only - never a container, a button,
   a divider or a bullet. Three sizes, one job each. clip-path cannot round
   a polygon's corners, so the shape is drawn with mask-image from an inline
   SVG data URI (soft corners, chosen 2026-09-05) - the path below is copied
   verbatim from docs/Planned/assets/spark-current-vs-hex/07-hex-system.html
   so every consumer traces the same corner. Flat-top, so it is wider than
   tall (2:sqrt(3)) - the width/height pairs below must not be swapped.
   ========================================================================== */
:root {
    --hex-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 87' preserveAspectRatio='none'%3E%3Cpath d='M26.4 2.5 73.6 2.5 97.1 43.5 73.6 84.5 26.4 84.5 2.9 43.5Z' fill='white' stroke='white' stroke-width='5' stroke-linejoin='round'/%3E%3C/svg%3E");
}

.hex-mark,
.hex-badge,
.hex-figure {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    -webkit-mask-image: var(--hex-mask);
    mask-image: var(--hex-mask);
    -webkit-mask-size: 100% 100%;
    mask-size: 100% 100%;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    background-color: var(--ldt-grey);
}

/* Mark - 11x10. State in a list or table row. Always sits beside the word
   for that state, never instead of it - a failed mask then costs nothing. */
.hex-mark {
    width: 11px;
    height: 10px;
}

.hex-mark-success { background-color: var(--ldt-success); }
.hex-mark-warning { background-color: var(--ldt-warning); }
.hex-mark-danger { background-color: var(--ldt-danger); }
.hex-mark-muted { background-color: var(--ldt-border); }
/* Brand orange, kept distinct from -warning (amber) - the attendance register's
   third state, "needs attention", so it never fights the accessibility-styled
   Absent/Late warning colours it sits beside. */
.hex-mark-primary { background-color: var(--ldt-primary); }

/* Badge - 34x30. Who or what a row is - initials, or a cohort code. */
.hex-badge {
    width: 34px;
    height: 30px;
    color: var(--ldt-white);
    font-weight: 800;
    font-size: 0.66rem;
}

.hex-badge-primary { background-color: var(--ldt-primary); }
.hex-badge-secondary { background-color: var(--ldt-secondary); }

/* Figure - 48x42. A headline count, on overview screens only - never more
   than three on a page. */
.hex-figure {
    width: 48px;
    height: 42px;
    color: var(--ldt-white);
    font-weight: 800;
    font-size: 1rem;
    font-variant-numeric: tabular-nums;
}

.hex-figure-primary { background-color: var(--ldt-primary); }
.hex-figure-secondary { background-color: var(--ldt-secondary); }
.hex-figure-neutral { background-color: var(--ldt-dark); }

/* ==========================================================================
   19. SHARED LIST COMPONENTS - pagination and empty states
   ========================================================================== */
/* One definition each, for components whose markup is already shared.

   Pagination was defined twice - identically - in students_list.css and
   admissions_staff.css, while core/_pagination.html was included by seven
   templates. The other five loaded neither stylesheet, so they rendered the
   shared partial with no rule at all: bare inline links in light mode, and a
   disabled Prev/Next indistinguishable from an active one because
   .page-link-disabled's opacity was never applied (N-238). Moved here
   unchanged, so the two pages that already had it are unaffected.

   The dark-mode rules for .pagination sit in section 9 and are more specific
   than these, so they still win, exactly as they did when these declarations
   lived in the page stylesheets.

   Print already hides this control through `nav { display: none !important }`
   in section 17, which these rules cannot and must not override. */
.pagination {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    padding: 1rem;
}

/* `background-color` is declared even though it is transparent, and that is
   not redundant. Bootstrap's own `.page-link { background-color: #fff }` loads
   first and matches this markup, and neither page-stylesheet copy claimed the
   property - so in dark mode the disabled Prev/Next rendered as a bright white
   pill, because `body.dark-mode .pagination a` rescues the anchors and not the
   disabled <span>. Measured before this line: disabled rgb(255,255,255),
   active rgb(55,65,81). The control that does nothing was the loudest thing in
   the row. The dark-mode rule in section 9 is still more specific than this
   one, so the anchors keep their dark pill. */
.pagination .page-link {
    padding: .4em 1em;
    border-radius: 6px;
    border: 1px solid var(--ldt-border, #d1d5db);
    background-color: transparent;
    text-decoration: none;
    color: inherit;
    font-size: .85rem;
    cursor: pointer;
}

.pagination .page-link:hover:not(.page-link-disabled) {
    border-color: var(--ldt-primary);
}

/* The two page-stylesheet copies disagreed on one declaration: students_list.css
   set `cursor: pointer` on .page-link and admissions_staff.css did not. The
   students form is kept, because it is the one this slice was told to extract
   from - and .page-link-disabled is given `cursor: default` so the pointer no
   longer follows a control that does nothing. */
.pagination .page-link-disabled {
    opacity: .4;
    cursor: default;
}

.pagination .page-info {
    font-size: .82rem;
    opacity: .7;
}

/* Active-filter dot on a filter disclosure's toggle. Was `.ss-filter-active-dot`
   in students_list.css, which is a page stylesheet only the students directory
   loads - so the tasks and referrals filter blocks System Slice D added would
   have rendered the dot as unstyled black body text, and the fix would have
   been the copy §2.2 forbids. Moved here on its second and third consumer,
   with one change: `var(--ldt-primary)` rather than a literal #F05409, which
   is the same colour in light mode and is the one that survives
   `body.dark-mode` and `@media (prefers-contrast: more)` (conventions §7). */
.filter-active-dot {
    color: var(--ldt-primary);
    font-size: .7rem;
    vertical-align: middle;
}

/* The result-count / active-filter line above a list's rows (conventions §4
   item 4). Was `.ss-list-meta` in students_list.css - a page stylesheet only
   the students directory loads, so the referral queue System Slice D gave the
   same line to would have rendered it as unstyled body text. Moved here on its
   second consumer, with `var(--ldt-primary)` in place of the literal #F05409
   for the same reason as .filter-active-dot above. */
.list-meta {
    padding: .75rem 1rem;
    font-size: .85rem;
    opacity: .8;
}

.list-meta .filtered {
    color: var(--ldt-primary);
    font-weight: 600;
}

/* Empty state. Was declared in an inline <style> inside agent_master.html, so
   it existed in the agent shell and nowhere else. Moved here verbatim, which
   makes core/partials/_empty_state.html usable from every shell. */
.empty-state {
    border: 1px dashed var(--ldt-border, #e5e7eb);
    border-radius: 8px;
    padding: 2.5rem 1.5rem;
    text-align: center;
    color: var(--ldt-text, #6b7280);
}

body.dark-mode .empty-state {
    border-color: #334155;
}

/* An empty state placed in a table row is not a row. Without this, both
   `tbody tr:hover` (section 7) and `.table-highlight tr:hover` light the
   message up in the same colour a real, selectable row uses - which is the
   "non-interactive elements must not imply clickability" problem the visual
   plan's V2 exists to fix. Specific enough to beat `.table-highlight
   tr:hover`, which is (0,2,1) to this rule's (0,3,1). */
tr.empty-state-row:hover,
.table-highlight tr.empty-state-row:hover {
    background-color: transparent;
}

/* ==========================================================================
   20. STUDENT PHOTO AVATAR - a real photo (or initials fallback), masked to
   the same hex shape as .hex-badge/.hex-mark/.hex-figure (section 18) via
   the shared --hex-mask, just sized by --student-avatar-size instead of
   one of that section's three fixed sizes - this is a photo of a person,
   not a compact state badge, so it does not fit "one fixed size everywhere"
   without looking either tiny or oversized next to a name. mask-image
   clips the whole painted box, fallback text and photo <img> alike, so
   only the container needs it. One definition, used on the student record
   header, the student list, and the attendance register
   (students/partials/_student_avatar.html).
   ========================================================================== */
.student-avatar {
    --student-avatar-size: 3.25rem;
    display: inline-flex;
    flex: 0 0 var(--student-avatar-size);
    align-items: center;
    justify-content: center;
    position: relative;
    width: var(--student-avatar-size);
    height: var(--student-avatar-size);
    -webkit-mask-image: var(--hex-mask);
    mask-image: var(--hex-mask);
    -webkit-mask-size: 100% 100%;
    mask-size: 100% 100%;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    background: var(--ldt-primary);
    color: var(--ldt-white);
    font-weight: 700;
    font-size: calc(var(--student-avatar-size) * 0.32);
}

.student-avatar--sm { --student-avatar-size: 2rem; }
.student-avatar--lg { --student-avatar-size: 4.5rem; }

/* Student list's identity column: the exact .hex-badge footprint (section
   18, 34x30, not square) so a photo sits in the same slot the initials
   badge already occupied there, rather than a new element beside it. */
.student-avatar--badge {
    width: 34px;
    height: 30px;
    flex-basis: 34px;
    font-size: 0.66rem;
    font-weight: 800;
    vertical-align: middle;
}

.student-avatar-image {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    background: var(--ldt-card-bg);
}

/* The photo sits in a plain <button popovertarget> so "view larger" needs no
   JS at all - the Popover API opens/closes/light-dismisses it natively. */
.student-avatar-trigger {
    all: unset;
    position: absolute;
    inset: 0;
    cursor: zoom-in;
}

/* [popover]'s UA stylesheet already centres this (position: fixed; inset: 0;
   margin: auto; width/height: fit-content) - only sizing and chrome here. */
.student-avatar-popover {
    padding: 0;
    border: 0;
    border-radius: 8px;
    overflow: hidden;
    background: transparent;
    max-width: min(90vw, 480px);
    max-height: 90vh;
}

.student-avatar-popover::backdrop {
    background: rgba(0, 0, 0, 0.6);
}

.student-avatar-popover img {
    display: block;
    max-width: 100%;
    max-height: 90vh;
}

.student-avatar-popover-close {
    all: unset;
    position: absolute;
    top: 0.4rem;
    right: 0.4rem;
    width: 1.75rem;
    height: 1.75rem;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.55);
    color: var(--ldt-white);
    cursor: pointer;
    font-size: 1.1rem;
    line-height: 1;
}

/* ==========================================================================
   21. WHAT'S NEW SINCE v1.4
   ========================================================================== */
.whats-new {
    width: min(64rem, calc(100vw - 2rem));
    max-width: none;
    max-height: calc(100vh - 2rem);
    margin: auto;
    padding: 0;
    overflow: auto;
    border: 1px solid var(--ldt-border);
    border-radius: 14px;
    background: var(--ldt-card-bg);
    color: var(--ldt-text);
    box-shadow: 0 1.5rem 4rem rgba(15, 23, 42, .32);
}

.whats-new::backdrop {
    background: rgba(15, 23, 42, .72);
}

.whats-new form {
    margin: 0;
}

.whats-new-header {
    display: grid;
    grid-template-columns: 1fr auto auto;
    align-items: center;
    gap: 2rem;
    min-height: 4.5rem;
    padding: 1rem 1.5rem 1rem 2rem;
    background: linear-gradient(120deg, var(--ldt-primary), var(--ldt-primary-dark));
    color: #fff;
}

.whats-new-header p {
    margin: 0;
    color: #fff;
    font-size: 1rem;
    font-weight: 800;
    letter-spacing: .03em;
    text-transform: uppercase;
}

.whats-new-header > span {
    font-size: .85rem;
    font-weight: 700;
    text-transform: uppercase;
}

.whats-new-close {
    width: 2.5rem;
    height: 2.5rem;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: #fff;
    font-size: 2rem;
    font-weight: 300;
    line-height: 1;
}

.whats-new-close:hover,
.whats-new-close:focus-visible {
    background: rgba(255, 255, 255, .18);
}

.whats-new-slides {
    min-height: 23rem;
}

.whats-new-slide {
    display: grid;
    grid-template-columns: 16rem 1fr;
    align-items: center;
    gap: 3rem;
    min-height: 23rem;
    padding: 2.5rem 3.5rem;
}

.whats-new-slide[hidden] {
    display: none;
}

.whats-new-art {
    display: grid;
    place-items: center;
    width: 12rem;
    aspect-ratio: 1.08;
    margin: auto;
    background: linear-gradient(145deg, var(--ldt-primary-light), var(--ldt-primary));
    color: #fff;
    clip-path: polygon(25% 6%, 75% 6%, 100% 50%, 75% 94%, 25% 94%, 0 50%);
}

.whats-new-art svg {
    width: 5.5rem;
    height: 5.5rem;
    overflow: visible;
    fill: none;
    stroke: currentColor;
    stroke-width: 3.5;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.whats-new-copy {
    padding-left: 2.75rem;
    border-left: 1px solid var(--ldt-border);
}

.whats-new-copy h2 {
    margin: 0 0 .5rem;
    color: var(--ldt-text);
    font-size: clamp(2rem, 4vw, 2.75rem);
    font-weight: 800;
    letter-spacing: -.025em;
}

.whats-new-lead {
    margin: 0 0 1.5rem;
    color: var(--ldt-text);
    font-size: 1.05rem;
}

.whats-new-copy ul {
    display: grid;
    gap: 1rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.whats-new-copy li {
    display: grid;
    grid-template-columns: 1.75rem 1fr;
    align-items: start;
    gap: .75rem;
    color: var(--ldt-text-muted);
}

.whats-new-copy li::before {
    display: grid;
    place-items: center;
    width: 1.75rem;
    height: 1.75rem;
    border-radius: 50%;
    background: var(--ldt-primary);
    color: #fff;
    content: "✓";
    font-size: .9rem;
    font-weight: 800;
}

.whats-new-footer {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: 1.5rem;
    padding: 1.25rem 2rem;
    border-top: 1px solid var(--ldt-border);
}

.whats-new-footer > div:first-child {
    display: grid;
    justify-items: start;
    gap: .35rem;
}

.whats-new-footer small {
    color: var(--ldt-text-muted);
}

.whats-new-back,
.whats-new-next {
    min-height: 3rem;
    padding: .65rem 1.5rem;
    border: 0;
    border-radius: 8px;
    font-weight: 700;
}

.whats-new-back {
    min-width: 8rem;
    background: var(--ldt-dark);
    color: var(--ldt-white);
}

.whats-new-back:disabled {
    background: var(--ldt-bg-secondary);
    color: var(--ldt-text-muted);
    cursor: default;
    opacity: .65;
}

.whats-new-next {
    min-width: 14rem;
    justify-self: end;
    background: var(--ldt-primary);
    color: #fff;
    box-shadow: 0 .3rem .65rem rgba(240, 84, 9, .2);
}

.whats-new-next:hover,
.whats-new-next:focus-visible {
    background: var(--ldt-primary-dark);
}

.whats-new-close:focus-visible,
.whats-new-back:focus-visible,
.whats-new-next:focus-visible {
    outline: 3px solid var(--ldt-info);
    outline-offset: 2px;
}

.whats-new-progress {
    display: flex;
    align-items: center;
    gap: .65rem;
}

.whats-new-progress span {
    width: .75rem;
    height: .75rem;
    border-radius: 999px;
    background: var(--ldt-border);
    transition: width .15s ease, background-color .15s ease;
}

.whats-new-progress span.active {
    width: 2rem;
    background: var(--ldt-primary);
}

body.dark-mode .whats-new {
    border-color: var(--ldt-border-dark);
}

@media (max-width: 720px) {
    .whats-new {
        width: calc(100vw - 1rem);
        max-height: calc(100vh - 1rem);
    }

    .whats-new-header {
        gap: .75rem;
        padding: .75rem 1rem;
    }

    .whats-new-header p {
        font-size: .78rem;
    }

    .whats-new-slide {
        grid-template-columns: 1fr;
        gap: 1.25rem;
        min-height: 0;
        padding: 1.5rem;
    }

    .whats-new-slides {
        min-height: 0;
    }

    .whats-new-art {
        width: 7rem;
    }

    .whats-new-art svg {
        width: 3.5rem;
        height: 3.5rem;
    }

    .whats-new-copy {
        padding: 0;
        border: 0;
    }

    .whats-new-copy h2 {
        font-size: 1.8rem;
    }

    .whats-new-lead {
        margin-bottom: 1rem;
        font-size: .95rem;
    }

    .whats-new-copy ul {
        gap: .75rem;
    }

    .whats-new-copy li {
        font-size: .9rem;
    }

    .whats-new-footer {
        grid-template-areas: "progress progress" "back next";
        grid-template-columns: 1fr 1fr;
        gap: 1rem;
        padding: 1rem;
    }

    .whats-new-footer > div:first-child {
        grid-area: back;
    }

    .whats-new-footer small {
        display: none;
    }

    .whats-new-progress {
        grid-area: progress;
        justify-self: center;
    }

    .whats-new-next {
        grid-area: next;
    }

    .whats-new-back,
    .whats-new-next {
        min-width: 0;
        width: 100%;
        padding-inline: .75rem;
        font-size: .85rem;
    }
}

@media (prefers-reduced-motion: reduce) {
    .whats-new-progress span {
        transition: none;
    }
}

@media (prefers-contrast: more) {
    .whats-new {
        border-width: 2px;
    }

    .whats-new-copy {
        border-left-width: 2px;
    }
}

@media print {
    .whats-new {
        display: none;
    }
}

/* A contact form shows one value box for the chosen type: the country-code
   field for a phone type, the plain box for anything else. */
.contact-value-form:has(option[data-value-type="phone"]:checked) .contact-text-value,
.contact-value-form:not(:has(option[data-value-type="phone"]:checked)) .contact-phone-value {
    display: none;
}

.student-record-open {
    border: 0;
    padding: 0;
    background: none;
    color: var(--ldt-primary, #0d6efd);
    text-align: left;
    text-decoration: underline;
    overflow-wrap: anywhere;
    cursor: pointer;
}

.student-record-popover {
    width: min(44rem, calc(100vw - 2rem));
    max-height: 80vh;
    margin: auto;
    padding: 1.25rem;
    overflow: auto;
    border: 1px solid var(--ldt-border);
    border-radius: .5rem;
    background: var(--ldt-bg);
    color: var(--ldt-text);
    box-shadow: 0 1rem 3rem rgba(0, 0, 0, .25);
}

.student-record-popover::backdrop {
    background: rgba(0, 0, 0, .4);
}

.student-record-popover-header {
    display: flex;
    align-items: start;
    justify-content: space-between;
    gap: 1rem;
}

.student-record-popover-body {
    overflow-wrap: anywhere;
}

.student-record-popover-body img,
.student-record-popover-body table {
    max-width: 100%;
}

.student-email-preview {
    display: block;
    width: 100%;
    height: min(60vh, 640px);
    border: 1px solid var(--ldt-border, #e5e7eb);
    background: #fff;
}
