/* PRISM global styles */

/* ════════════════════════════════════════════════════════════════
   Design tokens — single source of truth.

   Brand: the PRISM marketing/landing identity (prismschools.com).
   Primary rgb(0,92,154), sky rgb(44,182,255), 8px radius, DM Sans.
   The app previously ran a separate Tailwind-blue palette; that divergence
   is what made the login screen look like a different product from the app
   behind it. Landing is now the single source — do not reintroduce #3b82f6.
   ════════════════════════════════════════════════════════════════ */
:root {
    /* Brand primitives (named as on the landing site, so the two stay comparable) */
    --prism-blue:      #005c9a;
    --prism-blue-dark: #00426f;
    --prism-sky:       #2cb6ff;
    --prism-sky-soft:  #a6dbff;
    --prism-bg-soft:   #e3f4ff;
    --prism-bg-softer: #f7fbff;

    /* Shell */
    --sidebar-width:     240px;
    --sidebar-bg:        #04283d;
    --sidebar-border:    #0b3b58;
    --sidebar-hover:     #0b3b58;
    --sidebar-active-bg: rgba(44,182,255,.14);
    --sidebar-active-fg: var(--prism-sky-soft);
    --sidebar-fg:        #90b3c9;
    --sidebar-fg-bright: #eaf6ff;
    --accent:            var(--prism-blue);
    --accent-hover:      #2085ce;
    --accent-contrast:   #ffffff;
    --topbar-height:     60px;
    --topbar-bg:         #ffffff;
    --topbar-border:     #dbe7f0;
    --body-bg:           var(--prism-bg-softer);
    --card-bg:           #ffffff;
    --card-border:       #dbe7f0;
    --card-radius:       8px;
    --card-shadow:       0 1px 2px rgba(0,92,154,.08);
    --card-shadow-hover: 0 8px 24px rgba(0,92,154,.12);
    --transition-fast:   0.15s ease;
    --transition-base:   0.2s ease;

    /* Neutrals — biased toward the brand blue rather than a neutral grey ramp,
       so surfaces sit under the brand instead of beside it. */
    --text:            #12293b;
    /* Both neutrals clear 4.5:1 against every surface token below — the previous
       pair failed on --surface-muted, which is the table-header ground. */
    --text-muted:      #4d6376;
    --text-faint:      #586d80;
    --border:          #dbe7f0;
    --border-strong:   #b9cfe0;
    --surface-subtle:  #f5f9fd;
    --surface-muted:   #eaf2f9;

    /* Semantic colors + subtle (bg / border / fg) triplets.
       Success/warning/danger are status, not brand — they stay independent of
       the accent so a red always reads as risk and never as decoration. */
    --success:         #22c55e;
    --success-strong:  #16a34a;
    --success-bg:      #f0fdf4;
    --success-border:  #bbf7d0;
    --success-fg:      #136435;

    --warning:         #f59e0b;
    --warning-strong:  #d97706;
    --warning-bg:      #fffbeb;
    --warning-border:  #fcd34d;
    --warning-fg:      #854d0e;

    --danger:          #ef4444;
    --danger-strong:   #dc2626;
    --danger-bg:       #fef2f2;
    --danger-border:   #fca5a5;
    --danger-fg:       #991b1b;

    --info:            var(--prism-blue);
    --info-strong:     var(--prism-blue-dark);
    --info-bg:         var(--prism-bg-soft);
    --info-border:     var(--prism-sky-soft);
    --info-fg:         var(--prism-blue);

    /* Mastery stoplight — one source for Quick Log, class matrix, heatmaps, EWS */
    --mastery-not-yet:        #ef4444;
    --mastery-not-yet-strong: #dc2626;
    --mastery-developing:        #f59e0b;
    --mastery-developing-strong: #d97706;
    --mastery-mastered:        #22c55e;
    --mastery-mastered-strong: #16a34a;

    /* Risk scale (maps onto semantic) */
    --risk-low:    var(--success);
    --risk-medium: var(--warning);
    --risk-high:   var(--danger);

    /* Spacing scale */
    --space-1: 4px;
    --space-2: 8px;
    --space-3: 12px;
    --space-4: 16px;
    --space-5: 24px;
    --space-6: 32px;

    /* Bootstrap overrides — bound to the brand so unstyled components inherit it
       rather than Bootstrap's defaults, which fail contrast on tinted grounds. */
    --bs-link-color:        var(--accent);
    --bs-link-color-rgb:    0, 92, 154;
    --bs-link-hover-color:  var(--accent-hover);
    --bs-primary:           var(--accent);
    --bs-primary-rgb:       0, 92, 154;

    /* Type scale */
    --fs-xs:  0.72rem;
    --fs-sm:  0.8rem;
    --fs-md:  0.875rem;
    --fs-base: 0.9375rem;
    --fs-lg:  1.05rem;
    --fs-xl:  1.25rem;
}

/* ── Dark theme ─────────────────────────────────────────────────────
   Toggled via [data-theme="dark"] on <html>; Bootstrap components are
   handled in parallel by data-bs-theme="dark". Only token overrides here.

   The accent inverts: rgb(0,92,154) is a mid-dark blue that fails contrast
   on a dark ground, so dark mode promotes the sky tint to the accent role. */
[data-theme="dark"] {
    --sidebar-bg:        #041b29;
    --sidebar-border:    #0d3149;
    --sidebar-hover:     #0d3149;
    --accent:            #4db2ef;
    --accent-hover:      #7fcbf7;
    --accent-contrast:   #04283d;

    --topbar-bg:        #0c1f2d;
    --topbar-border:    #1d3b4f;
    --body-bg:          #071722;
    --card-bg:          #0e2433;
    --card-border:      #1d3b4f;
    --card-shadow:       0 1px 3px rgba(0,0,0,.4), 0 1px 2px rgba(0,0,0,.3);
    --card-shadow-hover: 0 4px 12px rgba(0,0,0,.5), 0 2px 4px rgba(0,0,0,.35);

    --text:            #e2ecf3;
    --text-muted:      #93aec2;
    --text-faint:      #6b8598;
    --border:          #1d3b4f;
    --border-strong:   #2d5470;
    --surface-subtle:  #0f2a3b;
    --surface-muted:   #143349;

    --success-bg: rgba(34,197,94,.14);  --success-border: rgba(34,197,94,.40); --success-fg: #4ade80;
    --warning-bg: rgba(245,158,11,.14); --warning-border: rgba(245,158,11,.40); --warning-fg: #fbbf24;
    --danger-bg:  rgba(239,68,68,.14);  --danger-border:  rgba(239,68,68,.40);  --danger-fg:  #f87171;
    --info-bg:    rgba(44,182,255,.16); --info-border:    rgba(44,182,255,.40); --info-fg:     #8fd3ff; --info-strong: #8fd3ff;
}
[data-theme="dark"] body { color: var(--text); }
/* Meeting-type badges read better with lighter ink on dark. */
[data-theme="dark"] .badge-type-blue   { background:#0d3149; color:#a6dbff; }
[data-theme="dark"] .badge-type-purple { background:#3b2a5f; color:#e9d5ff; }
[data-theme="dark"] .badge-type-green  { background:#14402a; color:#bbf7d0; }
[data-theme="dark"] .badge-type-yellow { background:#453a14; color:#fde68a; }
[data-theme="dark"] .badge-type-red    { background:#4a1f1f; color:#fecaca; }
[data-theme="dark"] .badge-type-orange { background:#4a2f14; color:#fed7aa; }
[data-theme="dark"] .badge-type-slate  { background:#143349; color:#c2d4e0; }

/* ════════════════════════════════════════════════════════════════
   Accessibility layer.

   These are global affordances, not per-view opt-ins. Nine views used to
   hand-roll their own :focus-visible rule; one rule here replaces all of them.
   ════════════════════════════════════════════════════════════════ */

/* Skip link — first tab stop on every page, visible only when focused.
   Matches the landing site's .skip-link so the two behave identically. */
.skip-link {
    position: absolute;
    top: -60px;
    left: var(--space-2);
    z-index: 2000;
    background: var(--accent);
    color: var(--accent-contrast);
    padding: var(--space-2) var(--space-3);
    border-radius: var(--card-radius);
    font-size: var(--fs-md);
    font-weight: 600;
    text-decoration: none;
    transition: top var(--transition-fast);
}
.skip-link:focus {
    top: var(--space-2);
    color: var(--accent-contrast);
}

/* Global keyboard focus ring. :focus-visible (not :focus) so pointer users
   don't get a ring on every click, keyboard users always do. */
:focus-visible {
    outline: 2px solid var(--accent-hover);
    outline-offset: 2px;
    border-radius: 2px;
}
/* Bootstrap sets its own box-shadow ring on controls; keep the outline as the
   single, consistent signal rather than stacking two rings. */
.btn:focus-visible,
.form-control:focus-visible,
.form-select:focus-visible,
.form-check-input:focus-visible {
    box-shadow: none;
    outline: 2px solid var(--accent-hover);
    outline-offset: 2px;
}
/* The main content region is focus target for the skip link; it should not
   show a ring when focused programmatically. */
#main:focus { outline: none; }

/* Respect a reduced-motion preference globally. The shimmer, typewriter cursor,
   sidebar slide and card transitions all animate; only the Polly button used to
   honour this. */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* ════════════════════════════════════════════════════════════════
   Print.

   MTSS and IEP meetings are paper events — a case manager prints a profile and
   carries it into the room — but the app shipped with no print rules at all, so
   printing a student produced the sidebar, the topbar, the floating action button
   and a dark background if the user happened to be in dark mode.

   Utilities:
     .prism-no-print    never printed
     .prism-print-only  printed, hidden on screen
     window.prismPrintSection("#sel")  prints just that subtree
   ════════════════════════════════════════════════════════════════ */

.prism-print-only { display: none; }
.prism-print-head { margin-bottom: 10pt; padding-bottom: 6pt; border-bottom: 2px solid #000; }
.prism-print-head h2 { margin: 0 0 2pt; font-size: 15pt; }
.prism-print-value { display: none; }

@media print {
    /* Print is always on white. Dark mode must not follow the page onto paper, and
       browsers drop background colours by default anyway — so force the tokens to a
       light set rather than letting half-applied colours through. */
    :root, [data-theme="dark"] {
        --body-bg:        #ffffff;
        --card-bg:        #ffffff;
        --surface-subtle: #ffffff;
        --surface-muted:  #f2f2f2;
        --card-border:    #999999;
        --border:         #999999;
        --border-strong:  #666666;
        --text:           #000000;
        --text-muted:     #333333;
        --text-faint:     #555555;
        --card-shadow:       none;
        --card-shadow-hover: none;
    }

    html, body {
        background: #fff !important;
        color: #000 !important;
        font-size: 11pt;
    }

    @page { margin: 14mm; }

    /* App chrome has no business on paper. */
    .prism-sidebar,
    .prism-topbar,
    .sidebar-overlay,
    .skip-link,
    .prism-toast-stack,
    .ql-fab,
    .va-fab,
    #va-panel,
    .modal,
    .modal-backdrop,
    .offcanvas,
    .tooltip,
    .popover,
    .impersonation-banner,
    .prism-no-print {
        display: none !important;
    }

    .prism-print-only { display: block !important; }
    span.prism-print-value { display: inline !important; }

    .prism-main { margin-left: 0 !important; }
    .prism-content { padding: 0 !important; }

    /* Controls print as dead weight — the reader cannot click them. */
    button,
    .btn,
    input[type="button"],
    input[type="submit"],
    .filter-pill,
    .az-pill,
    .dropdown-toggle,
    .btn-close,
    .form-check-input,
    .pagination {
        display: none !important;
    }

    /* Keep a record intact across page boundaries wherever possible. */
    .prism-card,
    .prism-panel,
    .profile-section,
    .rpt-card,
    .doc-panel,
    .audit-card,
    .card,
    .student-card,
    .lead-row,
    .hist-row,
    tr {
        break-inside: avoid;
        page-break-inside: avoid;
    }
    h1, h2, h3, h4 { break-after: avoid; page-break-after: avoid; }

    /* Cards become plain ruled blocks; boxes-within-boxes waste paper. */
    .prism-card, .prism-panel, .profile-section, .rpt-card, .doc-panel, .audit-card, .card {
        border: 1px solid #999 !important;
        box-shadow: none !important;
        border-radius: 0 !important;
        margin-bottom: 10pt !important;
    }

    /* A long table should repeat its header on every sheet, and must not be stuck
       inside a scroll box that clips it to one screen's width. */
    thead { display: table-header-group; }
    tfoot { display: table-footer-group; }
    .prism-table thead th { position: static !important; }
    .tbl-x-scroll,
    .prism-table-wrap,
    .table-responsive {
        overflow: visible !important;
    }
    .tbl-x-scroll::after { display: none !important; }

    /* The split-pane system clamps panes to the viewport height and scrolls them
       independently; on paper that would print one screenful and drop the rest. */
    .prism-split,
    .prism-split > [class*="col-"],
    .prism-split .split-body,
    .prism-split > [class*="col-"] > .meeting-panel,
    .prism-split > [class*="col-"] > .workspace-panel {
        height: auto !important;
        max-height: none !important;
        overflow: visible !important;
        display: block !important;
    }
    .prism-split .split-head { position: static !important; }

    /* Anything that scrolls on screen prints in full. */
    [style*="overflow-y"], [style*="overflow:auto"], [style*="max-height"] {
        max-height: none !important;
        overflow: visible !important;
    }

    /* Form controls hold values worth printing, but their chrome is not: a paper record
       should read "Grade 4", not show a dropdown with a chevron, and the accommodations
       picker should print the accommodations rather than its "type to search" prompt. */
    select,
    textarea,
    input[type="text"],
    input[type="number"],
    input[type="date"],
    input[type="email"],
    .ts-wrapper .ts-control {
        border: none !important;
        background: none !important;
        box-shadow: none !important;
        padding-left: 0 !important;
        appearance: none !important;
        -webkit-appearance: none !important;
        resize: none !important;
        color: #000 !important;
    }
    /* Tom-Select renders its control as a sibling of the (visually hidden) <select>, so
       the printed value comes from the control. Everything in it that exists for typing
       — the live input and its placeholder, the per-item remove, the clear button, the
       magnifying-glass background — is interaction, not record. Descendant selectors,
       because the input is not a direct child. */
    .ts-wrapper input,
    .ts-wrapper .remove,
    .ts-wrapper .clear-button,
    .ts-dropdown,
    select::-ms-expand {
        display: none !important;
    }
    .ts-wrapper .ts-control {
        background-image: none !important;
        padding-left: 0 !important;
        min-height: 0 !important;
    }
    .ts-wrapper .ts-control > .item {
        border: none !important;
        background: none !important;
        padding-left: 0 !important;
        margin: 0 !important;
    }

    /* A panel collapsed on screen is still part of the record on paper. */
    .prism-section-body { display: block !important; }
    .prism-section-toggle { display: none !important; }
    .is-collapsed { padding-bottom: inherit !important; }

    a { text-decoration: none !important; color: #000 !important; }

    /* Print one region only. Everything outside the target collapses, but the target's
       own ancestors must stay visible or it would be hidden with them. */
    body.prism-printing-section .prism-print-hidden { display: none !important; }
}

/* ════════════════════════════════════════════════════════════════
   Shared component layer — views opt in instead of re-declaring.
   ════════════════════════════════════════════════════════════════ */

/* Page header — carries the page's one <h1>. Rendered by
   Views/Shared/_PageHeader.cshtml; views should not hand-roll a title block. */
.prism-page-header {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3) var(--space-4);
    flex-wrap: wrap;
    margin-bottom: var(--space-4);
}
.prism-page-header .page-title {
    font-size: var(--fs-xl);
    font-weight: 600;
    color: var(--text);
    margin: 0;
    line-height: 1.25;
}
.prism-page-header .page-sub {
    font-size: var(--fs-sm);
    color: var(--text-muted);
    margin: 2px 0 0;
    max-width: 70ch;
}
.prism-page-header .page-actions {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
}

/* Card */
.prism-card {
    background: var(--card-bg);
    border: 1px solid var(--card-border);
    border-radius: var(--card-radius);
    box-shadow: var(--card-shadow);
}
.prism-card:hover { box-shadow: var(--card-shadow-hover); }
.prism-card-title {
    font-size: var(--fs-xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--text-muted);
    margin-bottom: var(--space-3);
}

/* Panel — the padded card body that six view files each re-declared under their
   own name (.rpt-card alone appeared identically in three), at differing radii and
   padding. The markup keeps its existing class names so no view had to change;
   the definition lives here once. New views should use .prism-panel directly. */
.prism-panel,
.profile-section,
.rpt-card,
.doc-panel,
.audit-card {
    background: var(--card-bg);
    border: 1px solid var(--card-border);
    border-radius: var(--card-radius);
    box-shadow: var(--card-shadow);
    padding: var(--space-4) var(--space-5);
    margin-bottom: var(--space-4);
}
.prism-panel > h2,
.prism-panel > h3,
.prism-panel > h4 {
    font-size: var(--fs-md);
    font-weight: 600;
    color: var(--text);
    margin: 0 0 var(--space-3);
}

/* Collapsible panel toggle (window.prismCollapsibleSections). */
.prism-section-toggle {
    margin-left: auto;
    background: none;
    border: none;
    padding: 2px 6px;
    color: var(--text-faint);
    line-height: 1;
    cursor: pointer;
    border-radius: 4px;
    flex-shrink: 0;
}
.prism-section-toggle:hover { color: var(--accent); background: var(--surface-muted); }
.prism-section-toggle i { font-size: .8em; }
/* A collapsed panel keeps its heading but sheds the body's spacing. */
.is-collapsed { padding-bottom: var(--space-3) !important; }
.is-collapsed > h2, .is-collapsed > h3,
.is-collapsed > .d-flex { margin-bottom: 0 !important; }

/* Empty state */
.prism-empty { text-align: center; padding: var(--space-6) var(--space-5); }
.prism-empty-icon { font-size: 2rem; color: var(--border-strong); margin-bottom: var(--space-2); }
.prism-empty-title { font-size: var(--fs-md); font-weight: 600; color: var(--text-muted); margin-bottom: var(--space-1); }
.prism-empty-sub { font-size: var(--fs-sm); color: var(--text-faint); }

/* Skeleton loading shimmer */
.prism-skeleton {
    display: inline-block;
    min-width: 28px;
    height: 1em;
    border-radius: 6px;
    background: linear-gradient(90deg, var(--surface-muted) 25%, var(--surface-subtle) 37%, var(--surface-muted) 63%);
    background-size: 400% 100%;
    animation: prism-shimmer 1.2s ease-in-out infinite;
    vertical-align: middle;
}
@keyframes prism-shimmer {
    0%   { background-position: 100% 50%; }
    100% { background-position: 0 50%; }
}

/* Metric pill */
.prism-pill {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: var(--fs-sm);
    font-weight: 600;
    background: var(--surface-muted);
    color: var(--text-muted);
    border-radius: 20px;
    min-width: 32px;
    height: 22px;
    padding: 0 10px;
    line-height: 1;
    text-decoration: none;
    font-variant-numeric: tabular-nums;
}
.prism-pill.has-value { background: var(--info-bg); color: var(--info-fg); }
a.prism-pill:hover { background: var(--info-border); color: var(--info-strong); }

/* Mastery badges — color + text, never color-only */
.badge-mastery-ny,
.badge-mastery-dev,
.badge-mastery-m {
    display: inline-flex; align-items: center; gap: 4px;
    font-size: var(--fs-xs); font-weight: 600;
    border-radius: 6px; padding: 2px 8px; border: 1px solid transparent;
}
.badge-mastery-ny  { background: var(--danger-bg);  color: var(--danger-fg);  border-color: var(--danger-border); }
.badge-mastery-dev { background: var(--warning-bg); color: var(--warning-fg); border-color: var(--warning-border); }
.badge-mastery-m   { background: var(--success-bg); color: var(--success-fg); border-color: var(--success-border); }

/* Risk badges */
.badge-risk-low,
.badge-risk-med,
.badge-risk-high {
    display: inline-flex; align-items: center; gap: 4px;
    font-size: var(--fs-xs); font-weight: 600;
    border-radius: 6px; padding: 2px 8px; border: 1px solid transparent;
}
.badge-risk-low  { background: var(--success-bg); color: var(--success-fg); border-color: var(--success-border); }
.badge-risk-med  { background: var(--warning-bg); color: var(--warning-fg); border-color: var(--warning-border); }
.badge-risk-high { background: var(--danger-bg);  color: var(--danger-fg);  border-color: var(--danger-border); }

/* Tables — sticky header, zebra, sortable affordance, horizontal-scroll hint.
   Wrap a <table class="prism-table"> in <div class="prism-table-wrap">. */
.prism-table-wrap { overflow-x: auto; border-radius: var(--card-radius); border: 1px solid var(--card-border); }
.prism-table-wrap::-webkit-scrollbar { height: 8px; }
.prism-table-wrap::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 4px; }
.prism-table { width: 100%; margin: 0; border-collapse: separate; border-spacing: 0; font-size: var(--fs-md); }
.prism-table thead th {
    position: sticky; top: 0; z-index: 2;
    background: var(--surface-muted); color: var(--text-muted);
    font-size: var(--fs-xs); font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
    padding: 10px 14px; white-space: nowrap; border-bottom: 1px solid var(--card-border);
}
.prism-table tbody td { padding: 10px 14px; border-bottom: 1px solid var(--surface-muted); vertical-align: middle; }
.prism-table tbody tr:nth-child(even) td { background: var(--surface-subtle); }
.prism-table tbody tr:hover td { background: var(--info-bg); }
.prism-table tbody tr:last-child td { border-bottom: none; }
/* Sortable header affordance. The <th> carries aria-sort; these mirror it visually. */
.prism-table th.sortable { cursor: pointer; user-select: none; }
.prism-table th.sortable::after { content: '\f0dc'; font-family: 'Font Awesome 6 Free'; font-weight: 900; font-size: .7em; opacity: .35; margin-left: 6px; }
.prism-table th.sortable.sort-asc::after  { content: '\f0de'; opacity: .9; }
.prism-table th.sortable.sort-desc::after { content: '\f0dd'; opacity: .9; }

/* Rows that navigate. Applied to the <a>/<button> that wraps a list row so the
   row is reachable by keyboard and announced as the control it actually is. */
.prism-row-link {
    display: block;
    color: inherit;
    text-decoration: none;
    width: 100%;
    text-align: left;
    background: none;
    border: none;
    padding: 0;
}
.prism-row-link:hover { color: inherit; text-decoration: none; }

/* ════════════════════════════════════════════════════════════════
   Existing rules
   ════════════════════════════════════════════════════════════════ */

/* AI typewriter cursor */
.prism-cursor {
    display: inline-block;
    width: 2px;
    height: 1em;
    background: var(--accent-hover);
    margin-left: 1px;
    vertical-align: text-bottom;
    animation: prism-blink 0.6s step-end infinite;
}
@keyframes prism-blink {
    0%, 100% { opacity: 1; }
    50%       { opacity: 0; }
}
/* While the typewriter is animating, the region is click-to-skip. */
.prism-typing { cursor: pointer; }
.badge.bg-danger-subtle { background-color: var(--danger-bg) !important; }
.badge.bg-warning-subtle { background-color: var(--warning-bg) !important; }
.badge.bg-secondary-subtle { background-color: var(--surface-subtle) !important; }
/* Text utilities point at the -fg tones, not the vivid --danger/--warning/--success
   fills. The fills are tuned to be seen as a block of colour and fail 4.5:1 as text
   (--warning on white is ~2:1); the -fg tones are the readable members of each
   triplet, and they are what Bootstrap's *-subtle badge backgrounds expect. */
.text-danger { color: var(--danger-fg) !important; }
.text-warning { color: var(--warning-fg) !important; }
.text-success { color: var(--success-fg) !important; }
.text-secondary { color: var(--text-muted) !important; }
.text-primary { color: var(--accent) !important; }
.badge.bg-primary-subtle { background-color: var(--info-bg) !important; }
.text-primary-emphasis { color: var(--info-strong) !important; }
.text-danger-emphasis { color: var(--danger-fg) !important; }
.text-warning-emphasis { color: var(--warning-fg) !important; }
.text-success-emphasis { color: var(--success-fg) !important; }
.border-danger-subtle { border-color: var(--danger-border) !important; }
.border-warning-subtle { border-color: var(--warning-border) !important; }
.border-secondary-subtle { border-color: var(--border-strong) !important; }

/* Bootstrap absolutes that ignore the theme. These stayed white-on-dark once the
   theme toggle was exposed; bind them to the surface tokens so they follow it. */
.bg-white { background-color: var(--card-bg) !important; }
.text-dark { color: var(--text) !important; }
.input-group-text { background-color: var(--surface-subtle); border-color: var(--border); color: var(--text-muted); }

/* Tom-Select ships a Bootstrap 5 theme with baked-in light colours, so its control,
   selected items and dropdown stayed light once dark mode was exposed. Bind them to
   the surface tokens. */
.ts-wrapper .ts-control,
.ts-wrapper.single .ts-control {
    background: var(--card-bg);
    border-color: var(--border);
    color: var(--text);
}
.ts-wrapper .ts-control input,
.ts-wrapper .ts-control input::placeholder { color: var(--text-muted); }
.ts-wrapper .ts-control > .item {
    background: var(--info-bg);
    color: var(--info-fg);
    border: 1px solid var(--info-border);
    border-radius: 4px;
}
.ts-dropdown {
    background: var(--card-bg);
    border-color: var(--border);
    color: var(--text);
}
.ts-dropdown .option:hover,
.ts-dropdown .active { background: var(--info-bg); color: var(--info-fg); }
.ts-wrapper.disabled .ts-control { background: var(--surface-muted); }

/* Meeting type badge colors — used on Meeting page and Admin/MeetingTypes.
   A categorical palette: these are labels, not status, so they stay distinct
   from the semantic triplets above. */
.meeting-type-badge { font-size:.68rem; padding:2px 8px; border-radius:20px; font-weight:600; }
.badge-type-blue   { background:var(--prism-bg-soft); color:var(--prism-blue-dark); }
.badge-type-purple { background:#f3e8ff; color:#6b21a8; }
.badge-type-green  { background:#dcfce7; color:#166534; }
.badge-type-yellow { background:#fef9c3; color:#854d0e; }
.badge-type-red    { background:#fee2e2; color:#991b1b; }
.badge-type-orange { background:#ffedd5; color:#9a3412; }
.badge-type-slate  { background:var(--surface-muted); color:var(--text-muted); }

/* Google Picker renders at a fixed z-index that sits below Bootstrap modals (1055).
   These two rules ensure the Picker overlay always appears on top. */
.picker-dialog-bg { z-index: 20000 !important; }

/* ── Horizontal scroll fade hint ─────────────────────────────────────
   Wrap any horizontally-scrollable region in div.tbl-x-scroll.
   A right-side gradient fade appears when more content lies off-screen
   and disappears once the user scrolls to the far right.
   JS init: window.initScrollHints() — called globally on DOMContentLoaded
   and after each ajaxComplete. */
.tbl-x-scroll {
    position: relative;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}
.tbl-x-scroll::after {
    content: '';
    position: absolute;
    right: 0; top: 0; bottom: 0;
    width: 48px;
    background: linear-gradient(to right, transparent, var(--card-bg, #fff));
    pointer-events: none;
    border-radius: 0 var(--card-radius, 8px) var(--card-radius, 8px) 0;
    transition: opacity .2s;
}
.tbl-x-scroll.scroll-at-end::after,
.tbl-x-scroll.scroll-no-overflow::after { opacity: 0; }

/* Mobile-only: make scroll bars visible so users know content scrolls */
@media (max-width: 767.98px) {
    .tbl-x-scroll::-webkit-scrollbar { height: 4px; }
    .tbl-x-scroll::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 2px; }
}
.picker-dialog    { z-index: 20001 !important; }

/* ── Standards mastery grid key ──────────────────────────────────────
   Legend under the standards heat map rendered by
   wwwroot/js/standards-heatmap.js (Student Profile + Meeting Prep).
   Wraps to a second line in narrow columns rather than forcing the
   page to scroll sideways. */
.goal-heatmap-key { display: flex; flex-wrap: wrap; gap: 6px 14px; margin-top: 8px; font-size: .72rem; color: var(--text-muted); }
.goal-heatmap-key-item { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
.goal-heatmap-key-swatch { display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; border-radius: 3px; font-size: .7rem; font-weight: 600; }
.goal-heatmap-key-swatch-none { background: var(--surface-subtle); color: var(--text-faint); border: 1px solid var(--card-border); }
/* Marks a row whose standard is one of the student's current individual goals. */
.goal-heatmap-goal-badge { display: inline-flex; align-items: center; gap: 3px; margin-left: 6px; padding: 0 6px; border-radius: 20px; background: var(--warning-border); color: var(--warning-fg); font-size: .6rem; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; vertical-align: middle; }
.goal-heatmap-goal-badge i { font-size: .55rem; }

/* ── Master-detail split panes ───────────────────────────────────────
   Two-panel (list + detail) views wrap their columns in
   <div class="row g-3 prism-split">. On desktop the row is bounded to
   the viewport height (set inline by window.initSplitPanes — accounts for
   the sticky topbar and anything above the row), so each column scrolls
   independently and the page itself does not scroll. Within a column,
   tag the pinned header as .split-head and the scrolling region as
   .split-body. Below 992px the split collapses to natural stacked flow
   (JS clears the inline height) and views fall back to scrollIntoView. */
@media (min-width: 992px) {
    /* The row is height-bounded by initSplitPanes; clip so only panes scroll. */
    .prism-split { overflow: hidden; }

    /* Each column is a full-height flex column. */
    .prism-split > [class*="col-"] {
        height: 100%;
        min-height: 0;              /* allow flex children to shrink & scroll */
        display: flex;
        flex-direction: column;
    }

    /* Card panels (Group / InterventionLibrary / CurriculumSet / Admin) are flex
       columns: a pinned .split-head over a scrolling .split-body. These cards are
       never display-toggled by JS, so forcing flex here is safe. */
    .prism-split > [class*="col-"] > .card {
        flex: 1 1 auto;
        min-height: 0;
        display: flex;
        flex-direction: column;
    }
    /* Toggled inner detail bodies (e.g. #groupDetailContent) fill the card. */
    .prism-split .card > .h-100 { flex: 1 1 auto; min-height: 0; }

    /* Simple panels (Meeting / Intervention) fill the column and scroll as a
       whole. They ARE display-toggled via jQuery show()/hide(), so we never force
       their display — the sticky .split-head pins within the panel's own scroll.
       Zero the pane's top padding so the pinned header sits flush against the top
       (otherwise scrolling content bleeds through the padding band above it); the
       header re-adds that breathing room via its own padding-top below. */
    .prism-split > [class*="col-"] > .meeting-panel,
    .prism-split > [class*="col-"] > .workspace-panel {
        flex: 1 1 auto;
        min-height: 0;
        overflow-y: auto;
        padding-top: 0;
    }

    /* Pinned header + scrolling body contract, shared by both families. */
    .prism-split .split-head { position: sticky; top: 0; z-index: 3; flex-shrink: 0; background: var(--card-bg); }
    .prism-split .split-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; }

    /* Whole-panel-scroll heads restore the pane's top padding inside the header so
       it fully covers the top edge as content scrolls beneath. */
    .prism-split .meeting-panel > .split-head,
    .prism-split .workspace-panel > .split-head { padding-top: 22px; }
}
