/* ============================================================================================
   Shared list/table page theme (eis-list-*): header card (back link, actions slot), toolbar (and its
   actions area), table (selection column, child rows, nested sub-table, look-only tables with a sticky
   header), status pills, action buttons, footer, the styled dropdown and bootstrap-select. Behaviour and
   the markup contract live in js/shared/EisListTable.js (its header comment).
   Reference page: /Integration/IntegrationDashboard (Manage Configurations).

   Form fields are themed SITE-WIDE (see "Form fields" below): every .form-control / .form-select,
   checkbox, radio and switch, every bootstrap-select, the DataTables search box and rows-per-page
   control, and the styled dropdown that EisListTable.js puts in place of every native <select>
   (auto-enhance; opt out with data-eis-native). Unclassed inputs are not themed: a visible text-like
   field carries form-control.

   Every Bootstrap modal is also themed SITE-WIDE (see "Standard modal" below): the design first built for
   Manage Building Users is the default, with no opt-in class (opt out with data-eis-native).

   Page-level globals (tabs, scrollbars, empty rows) are scoped under the .eis-list-page root class, so
   pages that do not opt in are untouched by them. Put class="eis-list-page" on the page's root element,
   and render its modals inside it.
   ============================================================================================ */

/* --------------------------------------------------------------------------------------------
   Page-level rules (scoped to .eis-list-page)
   -------------------------------------------------------------------------------------------- */
.eis-list-page .nav-tabs {
    display: flex;
    background-color: #e7e7e9;
}

    .eis-list-page .nav-tabs .nav-link {
        border: none;
        color: #6c757d;
        padding: 0.60rem 1.25rem;
        font-weight: 500;
    }

        .eis-list-page .nav-tabs .nav-link.active {
            color: white;
            background-color: #265B61; /*Green Color*/
        }

/* Beaten by table.eis-list-table td.dataTables_empty below for the list tables themselves */
.eis-list-page td.dataTables_empty {
    font-weight: 600;
    padding: 24px 0px;
}

/* Scrollbars: thin, a rounded grey thumb on a light grey track, with no arrow buttons, on every scroll area
   inside an eis-list page (table wrap, dropdown menus, bootstrap-select lists, modals). Like the form
   fields, the field-related scroll areas get it on EVERY page: dropdown menus (the styled dropdown,
   bootstrap-select's list, any Bootstrap .dropdown-menu), textareas and list-box selects. Any other scroll
   area opts in with .eis-scrollbar (e.g. the Report filter bars' own multi-select menus). The page's own
   scrollbar is the browser's and stays as it is.
   Chromium and Safari get the ::-webkit-scrollbar rules. Chrome 121+ ignores those on any element that
   also has scrollbar-width or scrollbar-color, and its standard thin bar on Windows keeps the arrow
   buttons, so the standard properties go only to browsers without ::-webkit-scrollbar (Firefox). */
.eis-list-page ::-webkit-scrollbar,
.dropdown-menu::-webkit-scrollbar,
.dropdown-menu ::-webkit-scrollbar,
.eis-scrollbar::-webkit-scrollbar,
textarea.form-control::-webkit-scrollbar,
select.form-select::-webkit-scrollbar {
    width: 8px;
    height: 8px;
}

/* The track: a light slate rail under the thumb, so the scroll area reads as scrollable. */
.eis-list-page ::-webkit-scrollbar-track,
.dropdown-menu::-webkit-scrollbar-track,
.dropdown-menu ::-webkit-scrollbar-track,
.eis-scrollbar::-webkit-scrollbar-track,
textarea.form-control::-webkit-scrollbar-track,
select.form-select::-webkit-scrollbar-track {
    background-color: #F1F5F9;
    border-radius: 999px;
}

.eis-list-page ::-webkit-scrollbar-corner,
textarea.form-control::-webkit-scrollbar-corner {
    background-color: #F1F5F9;
}

.eis-list-page ::-webkit-scrollbar-thumb,
.dropdown-menu::-webkit-scrollbar-thumb,
.dropdown-menu ::-webkit-scrollbar-thumb,
.eis-scrollbar::-webkit-scrollbar-thumb,
textarea.form-control::-webkit-scrollbar-thumb,
select.form-select::-webkit-scrollbar-thumb {
    background-color: #CBD5E1;
    border-radius: 999px;
}

    .eis-list-page ::-webkit-scrollbar-thumb:hover,
    .dropdown-menu::-webkit-scrollbar-thumb:hover,
    .dropdown-menu ::-webkit-scrollbar-thumb:hover,
    .eis-scrollbar::-webkit-scrollbar-thumb:hover,
    textarea.form-control::-webkit-scrollbar-thumb:hover,
    select.form-select::-webkit-scrollbar-thumb:hover {
        background-color: #94A3B8;
    }

@supports not selector(::-webkit-scrollbar) {
    .eis-list-page *,
    .dropdown-menu,
    .dropdown-menu *,
    .eis-scrollbar,
    textarea.form-control,
    select.form-select {
        scrollbar-width: thin;
        scrollbar-color: #CBD5E1 #F1F5F9;
    }
}

/* --------------------------------------------------------------------------------------------
   List/table theme
   -------------------------------------------------------------------------------------------- */
:root {
    --eis-list-green: #265B61;
    --eis-list-green-soft: #E6F0EF;
    --eis-list-border: #E5E7EB;
    --eis-list-head-bg: #E6F0EF; /* every header: table header rows, panel headings, .card.eis-panel headers */
    --eis-list-subtle-bg: #F5F6F8; /* neutral light grey that is not a header: button hover, path bars */
    --eis-list-muted: #6B7280;
    --eis-list-text: #1F2937;
}

/* --------------------------------------------------------------------------------------------
   Form fields (site-wide: NOT scoped to .eis-list-page)
   Text inputs, textareas and native selects that carry .form-control / .form-select, checkboxes,
   radios and switches. Heights stay Bootstrap's (38px; -sm 31px, -lg 48px). Unclassed inputs are not
   themed: a visible text-like field must carry form-control, and a <select> that stays native
   (data-eis-native) carries form-select. The styled dropdown, bootstrap-select and the DataTables
   controls follow further down.
   -------------------------------------------------------------------------------------------- */
.form-control,
.form-select {
    padding-left: 0.9rem;   /* left only: page rules reserve right-hand room for icons/spinners (pe-5, .eis-input-spinner) and the select's chevron */
    border: 1px solid var(--eis-list-border);
    border-radius: 8px;
    color: var(--eis-list-text);
    background-color: #fff;
}

    .form-control::placeholder {
        color: var(--eis-list-muted);
    }

    .form-control:hover,
    .form-select:hover {
        border-color: #CBD5E1;
    }

    /* site.css no longer gives .form-control:focus its blue ring / none; this is the ring everywhere. The
       colour is restated because Bootstrap's .form-control:focus sets its own. */
    .form-control:focus,
    .form-select:focus {
        outline: none;
        color: var(--eis-list-text);
        border-color: var(--eis-list-green);
        box-shadow: 0 0 0 0.2rem rgba(38, 91, 97, 0.15);
    }

    .form-control:disabled,
    .form-control[readonly],
    .form-select:disabled {
        background-color: #F3F4F6;
        color: var(--eis-list-muted);
        cursor: not-allowed;
    }

    /* Bootstrap's invalid state must still win over hover and focus above. */
    .form-control.is-invalid,
    .form-select.is-invalid,
    .was-validated .form-control:invalid,
    .was-validated .form-select:invalid {
        border-color: var(--bs-form-invalid-border-color, #dc3545);
    }

        .form-control.is-invalid:focus,
        .form-select.is-invalid:focus,
        .was-validated .form-control:invalid:focus,
        .was-validated .form-select:invalid:focus {
            border-color: var(--bs-form-invalid-border-color, #dc3545);
            box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);
        }

/* The size variants keep Bootstrap's heights; only the radius follows the theme (the rule above
   outranks Bootstrap's own -sm/-lg radius by load order). */
.form-control-sm,
.form-select-sm {
    border-radius: 6px;
}

.form-control-lg,
.form-select-lg {
    border-radius: 10px;
}

/* The 0.9rem inset above is for the 38px field. The sizes and a file input keep Bootstrap's own left
   padding: a file input's "Choose File" button is pulled flush to the field's edge by a margin sized for it. */
.form-control-sm,
.form-select-sm {
    padding-left: 0.5rem;
}

.form-control-lg,
.form-select-lg {
    padding-left: 1rem;
}

.form-control[type="file"] {
    padding-left: 0.75rem;
}

.form-control-sm[type="file"] {
    padding-left: 0.5rem;
}

.form-control-lg[type="file"] {
    padding-left: 1rem;
}

/* Extra small: an editor inside a table cell (e.g. Import Roster's inline cell editor), so an edited row
   keeps its height. Same border and colours as every field, a slimmer focus ring. */
.form-control-xs {
    height: 24px;
    padding: 2px 6px;
    font-size: 12px;
    border-radius: 4px;
}

    .form-control-xs:focus {
        box-shadow: 0 0 0 0.15rem rgba(38, 91, 97, 0.15);
    }

/* A read-only input that opens a picker when clicked (e.g. Import Roster's building list): white with a
   pointer while enabled, rather than the grey read-only look; disabled, it greys out like any field. */
.form-control.eis-field-picker[readonly]:not(:disabled) {
    background-color: #fff;
    color: var(--eis-list-text);
    cursor: pointer;
}

/* A small spinner inside a text field, on the right, while something loads for it (Manage Organizations'
   name check, the Individual Student Report's student list). Markup: the input, then straight after it
   span.eis-input-spinner > span.spinner-border.spinner-border-sm, both in a position-relative wrapper; show
   and hide it with d-none. The field keeps room for it on the right. */
.eis-input-spinner {
    position: absolute;
    right: 10px;
    top: 50%;
    transform: translateY(-50%);
    pointer-events: none;
}

.form-control:has(+ .eis-input-spinner) {
    padding-right: 2.25rem;
}

/* Input-group addons (.input-group-text, e.g. a password field's eye toggle) take the field's border and
   8px outer corners; Bootstrap's input-group rules still square the joined inner corners. */
.input-group-text {
    border-color: var(--eis-list-border);
    border-radius: 8px;
}

/* A field and its addon that read as ONE field (opt in with .eis-field-group on the .input-group, e.g. the
   Change / Set Password fields): the group takes the hover border and the green focus ring, so the ring is
   not cut off under the addon. An invalid field keeps its red border. */
.eis-field-group:hover > .form-control:not(.is-invalid),
.eis-field-group:hover > .input-group-text {
    border-color: #CBD5E1;
}

.eis-field-group:focus-within {
    border-radius: 8px;
    box-shadow: 0 0 0 0.2rem rgba(38, 91, 97, 0.15);
}

    .eis-field-group:focus-within > .form-control:not(.is-invalid),
    .eis-field-group:focus-within > .input-group-text {
        border-color: var(--eis-list-green);
    }

    .eis-field-group > .form-control:focus {
        box-shadow: none;
    }

/* Checkboxes and radios: a muted grey border (Bootstrap's #dee2e6 is too faint on white to see an unchecked
   box) and the theme's green when checked. The focus border is green; the ring is for the keyboard only
   (:focus-visible), so a mouse click on a checkbox or a switch shows no ring.
   Opt-out: data-eis-native on the input (or a container) keeps Bootstrap's own checkbox, as it keeps a
   select native (e.g. the teacher checklist grid). The :where() adds no specificity, so page rules that
   override these still win as before. */
.form-check-input:where(:not([data-eis-native], [data-eis-native] *)) {
    cursor: pointer;
    border-color: var(--eis-list-muted);
}

    .form-check-input:where(:not([data-eis-native], [data-eis-native] *)):checked,
    .form-check-input[type="checkbox"]:where(:not([data-eis-native], [data-eis-native] *)):indeterminate {
        background-color: var(--eis-list-green);
        border-color: var(--eis-list-green);
    }

    .form-check-input:where(:not([data-eis-native], [data-eis-native] *)):focus {
        border-color: var(--eis-list-green);
        box-shadow: none;
    }

    .form-check-input:where(:not([data-eis-native], [data-eis-native] *)):focus-visible {
        box-shadow: 0 0 0 0.2rem rgba(38, 91, 97, 0.15);
    }

    .form-check-input.is-invalid:where(:not([data-eis-native], [data-eis-native] *)):focus {
        border-color: var(--bs-form-invalid-border-color, #dc3545);
    }

    /* An opted-out checkbox keeps the look it had before the theme, which had no focus ring (site.css
       used to remove it from every .form-check-input). */
    .form-check-input:where([data-eis-native], [data-eis-native] *):focus {
        box-shadow: none;
    }

/* Switches: 42x20, grey track and white knob off, dark green on. The 42px switch is wider than the 2.5em
   gutter Bootstrap reserves, so the gutter (and the switch's matching negative margin) is widened to keep
   the label clear of it. Pages that lay a switch out themselves (flex, margin 0) are unaffected.
   ".eis-switch" is listed only to outrank site.css's Task 4367 switch colours, so it reads the same. */
.form-switch {
    padding-left: calc(42px + 0.5em);
}

    .form-switch .form-check-input:where(:not([data-eis-native], [data-eis-native] *)),
    .form-switch .form-check-input.eis-switch:where(:not([data-eis-native], [data-eis-native] *)) {
        width: 42px;
        height: 20px;
        margin-top: 0;
        margin-left: calc(-42px - 0.5em);
        background-color: #c1c9d0;
        border: none;
        border-radius: 24px;
        --bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='white'/%3e%3c/svg%3e");
    }

        .form-switch .form-check-input:where(:not([data-eis-native], [data-eis-native] *)):checked {
            background-color: #195b5b;
        }

        /* Bootstrap (light blue) and site.css (grey) recolour the knob on focus; it stays white. */
        .form-switch .form-check-input:where(:not([data-eis-native], [data-eis-native] *)):focus {
            --bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='white'/%3e%3c/svg%3e");
        }

/* Tabs: icon + label */
.eis-list-page .nav-tabs .nav-link {
    gap: 0.6rem;
    align-items: center;
}

    .eis-list-page .nav-tabs .nav-link .eis-list-tab-icon {
        font-size: 1.05rem;
    }

/* Section header */
.eis-list-card {
    border: 1px solid var(--eis-list-border) !important;
}

.eis-list-section-header {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin-bottom: 1.25rem;
    flex-wrap: wrap;
}

.eis-list-section-icon {
    width: 52px;
    height: 52px;
    border-radius: 14px;
    background-color: var(--eis-list-green-soft);
    color: var(--eis-list-green);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 1.4rem;
    flex-shrink: 0;
}

.eis-list-section-text {
    flex: 1 1 240px;
    min-width: 0;
}

.eis-list-section-title {
    text-align: left; /* site.css centres every h1-h5 */
    font-size: 1.25rem;
    font-weight: 700;
    color: var(--eis-list-text);
    margin: 0 0 0.2rem;
}

.eis-list-section-subtitle {
    color: var(--eis-list-muted);
    margin: 0;
}

/* .eis-list-header-btn: any other header button (in the _SectionHeader Actions slot), the same size as the
   Add button: btn-squishy for the main action, eis-modal-btn-outline for a secondary one. */
.eis-list-add-btn,
.eis-list-header-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-weight: 600;
    padding: 0.55rem 1.1rem;
}

/* Header extras (_SectionHeader BackUrl / Actions). The back link sits on its own line above the icon and
   title (the header wraps); the actions slot holds the page's own controls, before the Add button. */
.eis-list-back {
    flex: 1 0 100%;
    margin-bottom: -0.5rem; /* the header's 1rem gap is too much between the link and the title row */
}

.eis-list-back-link {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    color: var(--eis-list-muted);
    font-size: 0.875rem;
    font-weight: 600;
    text-decoration: none;
}

    .eis-list-back-link:hover {
        color: var(--eis-list-green);
        text-decoration: underline;
    }

    .eis-list-back-link:focus-visible {
        outline: 2px solid var(--eis-list-green);
        outline-offset: 2px;
        border-radius: 4px;
    }

.eis-list-section-actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
}

/* Context line above the toolbar, e.g. "Building: <strong>name</strong>" for the building a page works on. */
.eis-list-context {
    color: var(--eis-list-muted);
    margin: 0 0 0.75rem;
}

    .eis-list-context strong {
        color: var(--eis-list-text);
        font-weight: 600;
    }

/* Toolbar: search + filters */
.eis-list-toolbar {
    display: flex;
    gap: 0.75rem;
    margin-bottom: 1rem;
    flex-wrap: wrap;
}

.eis-list-search {
    position: relative;
    flex: 1 1 280px;
}

    .eis-list-search .eis-list-search-icon {
        position: absolute;
        left: 0.9rem;
        top: 50%;
        transform: translateY(-50%);
        color: var(--eis-list-muted);
        pointer-events: none;
    }

    .eis-list-search input {
        padding-left: 2.4rem;
        height: 44px;
        border-color: var(--eis-list-border);
    }

        .eis-list-search input:focus {
            border-color: var(--eis-list-green);
            box-shadow: 0 0 0 0.2rem rgba(38, 91, 97, 0.15);
        }

.eis-list-toolbar .form-select {
    flex: 0 1 200px;
    height: 44px;
    border-color: var(--eis-list-border);
}

/* Toolbar actions: the page's own buttons and menus (e.g. Export), the toolbar's last child, pushed to the
   right of the search box and filters. Markup and contract: EisListTable.js "Toolbar actions". The group
   keeps its width and stays on one line (the toolbar moves it to a line of its own when there is no room),
   so the toolbar row stays 44px tall and the search box's magnifier stays centred in it. */
.eis-list-toolbar-actions {
    display: flex;
    flex: 0 0 auto;
    align-items: center;
    gap: 0.75rem;
    margin-left: auto;
}

/* A toolbar button: white and bordered, 44px like the search box. Set through Bootstrap's .btn variables so
   its hover / active / open states keep the look. */
.btn.eis-list-toolbar-btn {
    --bs-btn-color: var(--eis-list-text);
    --bs-btn-bg: #fff;
    --bs-btn-border-color: var(--eis-list-border);
    --bs-btn-hover-color: var(--eis-list-text);
    --bs-btn-hover-bg: #F3F4F6;
    --bs-btn-hover-border-color: #CBD5E1;
    --bs-btn-active-color: var(--eis-list-text);
    --bs-btn-active-bg: #F3F4F6;
    --bs-btn-active-border-color: #CBD5E1;
    --bs-btn-disabled-color: var(--eis-list-muted);
    --bs-btn-disabled-bg: #F3F4F6;
    --bs-btn-disabled-border-color: var(--eis-list-border);
    height: 44px;
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0 1rem;
    border-radius: 8px;
    font-weight: 600;
    white-space: nowrap;
}

    .btn.eis-list-toolbar-btn:focus-visible {
        outline: 2px solid var(--eis-list-green);
        outline-offset: 2px;
        box-shadow: none;
    }

    /* A menu toggle: the styled dropdown's chevron instead of Bootstrap's triangle; it turns over while open. */
    .btn.eis-list-toolbar-btn.dropdown-toggle::after {
        content: "\f078";
        font-family: "Font Awesome 6 Free";
        font-weight: 900;
        font-size: 0.75rem;
        border: 0;
        margin-left: 0.25rem;
        vertical-align: middle;
        color: var(--eis-list-muted);
        transition: transform 0.15s ease;
    }

    .btn.eis-list-toolbar-btn.dropdown-toggle[aria-expanded="true"]::after {
        transform: rotate(180deg);
    }

/* A menu opened from the toolbar or the header (ul.dropdown-menu.eis-list-menu): the styled dropdown's card. */
.eis-list-menu {
    min-width: 10rem;
    padding: 0.35rem;
    border: 1px solid var(--eis-list-border);
    border-radius: 10px;
    box-shadow: 0 10px 25px rgba(17, 24, 39, 0.10);
}

    .eis-list-menu .dropdown-item {
        display: flex;
        align-items: center;
        gap: 0.6rem;
        border-radius: 6px;
        padding: 0.5rem 0.75rem;
        color: var(--eis-list-text);
    }

        .eis-list-menu .dropdown-item:hover,
        .eis-list-menu .dropdown-item:focus {
            background-color: #F3F4F6;
            color: var(--eis-list-text);
        }

        .eis-list-menu .dropdown-item:active {
            background-color: var(--eis-list-green-soft);
            color: var(--eis-list-green);
        }

/* Table */
.eis-list-table-wrap {
    border: 1px solid var(--eis-list-border);
    border-radius: 10px;
    overflow-x: auto;
}

table.eis-list-table {
    margin: 0 !important;
    width: 100% !important;
    border-collapse: collapse !important;
}

    table.eis-list-table thead th {
        background-color: var(--eis-list-head-bg) !important; /* beats the global yellow th in site.css */
        color: var(--eis-list-text);
        font-weight: 600;
        font-size: 0.9rem;
        white-space: nowrap;
        border-bottom: 1px solid var(--eis-list-border);
        padding: 0.6rem 1rem;
        vertical-align: middle;
    }

    /* 8px top and bottom: a text row is about 41px, a row with the 38px action buttons about 55px. */
    table.eis-list-table tbody td {
        padding: 0.5rem 1rem;
        vertical-align: middle;
        border-bottom: 1px solid var(--eis-list-border);
        color: var(--eis-list-text);
    }

    table.eis-list-table tbody tr:last-child td {
        border-bottom: 0;
    }

    table.eis-list-table tbody tr:hover td {
        background-color: #FAFBFC;
    }

    table.eis-list-table td.dataTables_empty,
    table.eis-list-table td.eis-list-empty-cell {
        text-align: center;
        font-weight: 600;
        padding: 2rem 0;
        color: var(--eis-list-muted);
    }

/* Look-only tables (EisListTable.js "Look-only tables"): table.eis-list-table without DataTables takes every
   rule above as it is; an empty list may show one td.eis-list-empty-cell (styled with the empty row above).
   Sticky header in a scroll box: the wrap is the scroll box (max height from --eis-list-scroll-max-height,
   260px by default) and the header cells stick to its top. They are already opaque (the light grey above).
   The line under them is an inset shadow: under border-collapse a sticky cell's bottom border stays behind
   with the table and scrolls away. */
.eis-list-table-wrap.eis-list-table-wrap--scroll {
    max-height: var(--eis-list-scroll-max-height, 260px);
    overflow: auto;
}

table.eis-list-table.eis-list-table--sticky-head > thead > tr > th {
    position: sticky;
    top: 0;
    z-index: 2;
    border-bottom: 0;
    box-shadow: inset 0 -1px 0 var(--eis-list-border);
}

/* Compact rows (opt in with eis-list-table--compact), for a look-only table in a modal or a scroll box: about
   as many rows fit as with Bootstrap's table-sm. Beats the selection column's padding below on specificity;
   that column only keeps its narrow width. */
table.eis-list-table.eis-list-table--compact > thead > tr > th,
table.eis-list-table.eis-list-table--compact > tbody > tr > td {
    padding: 0.3rem 0.75rem;
}

    table.eis-list-table.eis-list-table--compact > thead > tr > th.eis-list-check-cell,
    table.eis-list-table.eis-list-table--compact > tbody > tr > td.eis-list-check-cell {
        width: 40px;
        padding-right: 0.25rem;
    }

/* Row selection column (EisListTable.js "Row selection"): narrow, the checkbox centred in header and rows. */
table.eis-list-table th.eis-list-check-cell,
table.eis-list-table td.eis-list-check-cell {
    width: 48px;
    padding-left: 0.75rem;
    padding-right: 0.5rem;
    text-align: center;
}

    table.eis-list-table .eis-list-check-cell > .form-check-input {
        float: none;
        margin: 0;
        width: 1.1em;
        height: 1.1em;
        vertical-align: middle;
    }

/* Child rows (EisListTable.js "Child rows"): the expander column, the open row and the content under it. */
table.eis-list-table th.eis-list-expander-cell,
table.eis-list-table td.eis-list-expander-cell {
    width: 48px;
    padding-left: 0.75rem;
    padding-right: 0;
    text-align: center;
}

.eis-list-expander {
    width: 30px;
    height: 30px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 1px solid transparent;
    border-radius: 8px;
    background-color: transparent;
    color: var(--eis-list-green);
}

    .eis-list-expander:hover {
        background-color: var(--eis-list-green-soft);
    }

    .eis-list-expander:focus-visible {
        outline: 2px solid var(--eis-list-green);
        outline-offset: 2px;
    }

    .eis-list-expander > i {
        font-size: 0.85rem;
        transition: transform 0.2s ease;
    }

    .eis-list-expander[aria-expanded="true"] > i {
        transform: rotate(90deg);
    }

/* The open row runs straight into its child row (no line between them); the child row is white, even on hover,
   and its content starts past the expander column. Only a sub-table's header is grey, so it reads as a header
   and not as part of the band around it. */
table.eis-list-table tbody tr.eis-list-row-expanded > td {
    border-bottom-color: transparent;
}

table.eis-list-table tbody tr.eis-list-child-row > td,
table.eis-list-table tbody tr.eis-list-child-row:hover > td {
    padding: 0 1rem 1rem 3.5rem;
    background-color: #fff;
}

/* Child content with nothing to list ("No teachers assigned"). */
.eis-list-child-empty {
    margin: 0;
    padding: 0.5rem 0;
    color: var(--eis-list-muted);
}

/* Nested detail table (table.eis-list-subtable), e.g. a student's teachers in a child row: compact, white,
   bordered and rounded. Its rules restate what the outer list table's descendant rules would otherwise give
   its cells (padding, header colour), so it also reads the same outside a list table. */
table.eis-list-subtable {
    width: 100%;
    margin: 0;
    border-collapse: separate;
    border-spacing: 0;
    border: 1px solid var(--eis-list-border);
    border-radius: 8px;
    background-color: #fff;
    font-size: 0.875rem;
}

    table.eis-list-subtable > thead > tr > th {
        background-color: var(--eis-list-head-bg) !important; /* beats the global yellow th in site.css */
        color: var(--eis-list-text);
        font-weight: 600;
        font-size: 0.8125rem;
        white-space: nowrap;
        text-align: left;
        vertical-align: middle;
        padding: 0.5rem 0.75rem;
        border-bottom: 1px solid var(--eis-list-border);
    }

        table.eis-list-subtable > thead > tr > th:first-child {
            border-top-left-radius: 7px;
        }

        table.eis-list-subtable > thead > tr > th:last-child {
            border-top-right-radius: 7px;
        }

    table.eis-list-subtable > tbody > tr > td {
        padding: 0.5rem 0.75rem;
        vertical-align: middle;
        border-bottom: 1px solid var(--eis-list-border);
        color: var(--eis-list-text);
        background-color: #fff;
    }

    table.eis-list-subtable > tbody > tr:last-child > td {
        border-bottom: 0;
    }

        table.eis-list-subtable > tbody > tr:last-child > td:first-child {
            border-bottom-left-radius: 7px;
        }

        table.eis-list-subtable > tbody > tr:last-child > td:last-child {
            border-bottom-right-radius: 7px;
        }

    table.eis-list-subtable > tbody > tr:hover > td {
        background-color: #FAFBFC;
    }

    /* Inside a list table, the outer row hover (tbody tr:hover td) would grey every cell of the sub-table at
       once; its cells stay white and only the sub-table row under the pointer is highlighted. */
    table.eis-list-table tbody tr:hover table.eis-list-subtable > tbody > tr > td {
        background-color: #fff;
    }

    table.eis-list-table tbody tr:hover table.eis-list-subtable > tbody > tr:hover > td {
        background-color: #FAFBFC;
    }

    /* Sortable header (data-eis-list-sub-sort, sorted by EisListTable.js): the arrow follows aria-sort. */
    table.eis-list-subtable > thead > tr > th[data-eis-list-sub-sort] {
        cursor: pointer;
        user-select: none;
    }

        table.eis-list-subtable > thead > tr > th[data-eis-list-sub-sort]::after {
            content: "\f0dc";
            font-family: "Font Awesome 6 Free";
            font-weight: 900;
            font-size: 0.75rem;
            margin-left: 0.4rem;
            color: #9CA3AF;
        }

        table.eis-list-subtable > thead > tr > th[data-eis-list-sub-sort][aria-sort="ascending"]::after {
            content: "\f0de";
            color: var(--eis-list-green);
        }

        table.eis-list-subtable > thead > tr > th[data-eis-list-sub-sort][aria-sort="descending"]::after {
            content: "\f0dd";
            color: var(--eis-list-green);
        }

        table.eis-list-subtable > thead > tr > th[data-eis-list-sub-sort]:focus-visible {
            outline: 2px solid var(--eis-list-green);
            outline-offset: -2px;
        }

/* Source cell: partner name + subtitle */
.eis-list-source {
    display: flex;
    align-items: center;
    gap: 0.9rem;
    min-width: 200px;
}

.eis-list-source-name {
    font-weight: 600;
    line-height: 1.25;
}

.eis-list-source-sub {
    color: var(--eis-list-muted);
    font-size: 0.85rem;
}

/* Configuration key/value block */
.eis-list-config {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    column-gap: 1rem;
    row-gap: 0.15rem;
    background-color: #F8F9FA;
    border-radius: 8px;
    padding: 0.5rem 0.9rem;
    font-size: 0.85rem;
    min-width: 280px;
    max-width: 440px;
}

.eis-list-config-key {
    font-weight: 600;
    color: #374151;
    white-space: nowrap;
}

.eis-list-config-value {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    min-width: 0;
    color: #4B5563;
}

    .eis-list-config-value .eis-list-truncate {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        min-width: 0;
    }

/* Date + time cell */
.eis-list-datetime {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    white-space: nowrap;
}

.eis-list-datetime-icon {
    color: var(--eis-list-muted);
    font-size: 1.05rem;
}

.eis-list-datetime-text {
    display: flex;
    flex-direction: column;
    line-height: 1.3;
}

.eis-list-time {
    color: var(--eis-list-muted);
    font-size: 0.85rem;
}

/* Updated-by name */
.eis-list-user {
    white-space: nowrap;
}

/* Status: toggle (Data Source) */
.eis-list-status {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    white-space: nowrap;
}

    .eis-list-status .form-switch {
        margin: 0;
        padding-left: 2.5em;
        min-height: 0;
    }

/* Toggle that saves on click (Manage Students participation): while its request is in flight the page adds
   eis-list-switch-saving and the knob turns into a thick spinning ring in place, so the switch keeps its
   footprint; the page moves the knob only after the save succeeds.
   Markup: <div class="form-check form-switch eis-list-switch"><input class="form-check-input" ...>
   <span class="spinner-border eis-list-switch-spinner" aria-hidden="true"></span></div>.
   The knob is the 20px switch's background image: its centre sits 10px in from the left (off) or right (on). */
.eis-list-page .eis-list-switch {
    position: relative;
    display: inline-flex;
    align-items: center;
    margin: 0;
    padding: 0;
    min-height: 0;
}

    .eis-list-page .eis-list-switch .form-check-input {
        float: none;
        margin: 0;
    }

.eis-list-switch-spinner {
    --bs-spinner-width: 16px;
    --bs-spinner-height: 16px;
    --bs-spinner-border-width: 3px;
    display: none;
    position: absolute;
    top: 50%;
    left: 2px;
    margin-top: -8px;
    color: #265B61; /* white would vanish on the light-grey "off" track */
    pointer-events: none;
}

    .form-check-input:checked + .eis-list-switch-spinner {
        left: 24px;
        color: #fff;
    }

.eis-list-switch-saving .eis-list-switch-spinner {
    display: inline-block;
}

/* Hides the white knob under the spinner; beats Bootstrap's .form-switch .form-check-input(:checked). */
.eis-list-page .form-switch.eis-list-switch-saving .form-check-input {
    background-image: none;
    cursor: progress;
}

.eis-list-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    border-radius: 999px;
    padding: 0.25rem 0.75rem;
    font-size: 0.8rem;
    font-weight: 600;
    white-space: nowrap;
}

.eis-list-pill-success {
    background-color: #DCF5E3;
    color: #1E7B3A;
}

.eis-list-pill-muted {
    background-color: #EEF0F2;
    color: #6B7280;
}

.eis-list-pill-warning {
    background-color: #FEF3C7;
    color: #B45520;
}

.eis-list-pill-danger {
    background-color: #FDE2E2;
    color: #B42318;
}

.eis-list-pill-info {
    background-color: #E0F2FE;
    color: #075985;
}

/* Bordered action buttons */
.eis-list-actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    justify-content: center;
}

.eis-list-table .eis-list-action-btn {
    width: 38px;
    height: 38px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--eis-list-border);
    border-radius: 8px;
    background-color: #fff;
    color: #374151;
    padding: 0;
}

    .eis-list-table .eis-list-action-btn:hover {
        background-color: #F3F4F6;
    }

    .eis-list-table .eis-list-action-btn:focus-visible {
        outline: 2px solid var(--eis-list-green);
        outline-offset: 2px;
    }

    .eis-list-table .eis-list-action-btn.eis-list-action-danger {
        color: #DC2626;
        background-color: #FEF2F2;
        border-color: #FECACA;
    }

        .eis-list-table .eis-list-action-btn.eis-list-action-danger:hover {
            background-color: #FEE2E2;
        }

    .eis-list-table .eis-list-action-btn.eis-list-action-primary {
        color: var(--eis-list-green);
    }

/* Footer: "Showing X to Y of Z" + pagination */
/* Three columns: rows per page (left) | "Showing X to Y of Z" (centre) | pagination (right) */
.eis-list-table-footer {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: 1rem;
    padding: 0.9rem 1rem;
    border-top: 1px solid var(--eis-list-border);
}

    .eis-list-table-footer .dataTables_length {
        justify-self: start;
    }

    .eis-list-table-footer .dataTables_info {
        justify-self: center;
        text-align: center;
    }

    .eis-list-table-footer .dataTables_paginate {
        justify-self: end;
    }

    .eis-list-table-footer .dataTables_info {
        padding: 0 !important;
        color: var(--eis-list-muted);
    }

    .eis-list-table-footer .dataTables_length {
        padding: 0 !important;
    }

        .eis-list-table-footer .dataTables_length label {
            display: inline-flex;
            align-items: center;
            gap: 0.5rem;
            margin: 0;
            color: var(--eis-list-muted);
            white-space: nowrap;
        }

        .eis-list-table-footer .dataTables_length select {
            width: auto;
            min-width: 72px;
            height: 36px;
            border-color: var(--eis-list-border);
            border-radius: 8px;
        }

            .eis-list-table-footer .dataTables_length select:focus {
                border-color: var(--eis-list-green);
                box-shadow: 0 0 0 0.2rem rgba(38, 91, 97, 0.15);
            }

    .eis-list-table-footer .dataTables_paginate {
        margin: 0 !important;
    }

        .eis-list-table-footer .dataTables_paginate .pagination {
            margin: 0;
            gap: 0.35rem;
        }

        .eis-list-table-footer .dataTables_paginate .page-link {
            border-radius: 8px !important;
            min-width: 36px;
            height: 36px;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            border: 1px solid var(--eis-list-border);
        }

        .eis-list-table-footer .dataTables_paginate .page-item.active .page-link {
            background-color: var(--eis-list-green);
            border-color: var(--eis-list-green);
            color: #fff;
        }

        .eis-list-table-footer .dataTables_paginate .page-item.disabled .page-link {
            background-color: #F3F4F6;
            color: #9CA3AF;
        }

/* Sortable headers: room for the DataTables up/down indicator */
table.eis-list-table.dataTable > thead > tr > th.sorting,
table.eis-list-table.dataTable > thead > tr > th.sorting_asc,
table.eis-list-table.dataTable > thead > tr > th.sorting_desc {
    padding-right: 1.9rem;
}

@media (max-width: 576px) {
    .eis-list-toolbar .form-select {
        flex: 1 1 100%;
    }

    .eis-list-toolbar-actions {
        flex: 1 1 100%;
        flex-wrap: wrap;
        margin-left: 0;
    }

    .eis-list-table-footer {
        grid-template-columns: 1fr;
        justify-items: center;
    }

        .eis-list-table-footer .dataTables_length,
        .eis-list-table-footer .dataTables_paginate {
            justify-self: center;
        }
}

/* A loading spinner that replaces a 38px action button keeps the same footprint, so icons do not shift */
.eis-list-actions > .spinner-border-sm {
    margin: 0 11px;
}

/* Keyboard focus ring on the Add buttons (and the other header buttons) */
.eis-list-add-btn:focus-visible,
.eis-list-header-btn:focus-visible {
    outline: 2px solid var(--eis-list-green) !important;
    outline-offset: 2px;
}

/* Styled dropdown that stands in for every native <select> (EisListTable auto-enhance / enhanceSelect):
   div.eis-list-select (the wrap, right after the visually hidden <select>) > button.eis-list-select-btn +
   ul.eis-list-select-menu. 38px like a form-control by default; 44px in a list toolbar, 36px in a list
   table footer, eis-list-select--sm 31px and --lg 48px (from the select's form-select-sm/-lg). */
/* min-width 0: a long option (a district name) shrinks the dropdown, its label ending in an ellipsis, instead of
   pushing the next filter onto a line of its own; the menu still shows the full text. */
.eis-list-toolbar .eis-list-select {
    flex: 0 1 200px;
    min-width: 0;
}

/* A select that was a full-width form field (form-select / form-control, so neither --auto nor --inline)
   fills its container as the native one did (width:100%), also as a flex item in a d-flex row. Zero
   specificity, so every other width rule (toolbar, input group, a mirrored inline width or w-* class) still
   wins; a DataTables rows-per-page control keeps its own size. */
:where(.eis-list-select:not(.eis-list-select--auto):not(.eis-list-select--inline):not(.dataTables_length *)) {
    width: 100%;
}

.eis-list-select-btn {
    width: 100%;
    height: 38px;
    font-size: 1rem;   /* the size of a .form-control beside it and of the menu's items (body text is 14px) */
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0 0.9rem;
    background-color: #fff;
    border: 1px solid var(--eis-list-border);
    border-radius: 8px;
    color: var(--eis-list-text);
    text-align: left;
}

    .eis-list-select-btn:hover {
        border-color: #CBD5E1;
    }

    .eis-list-select-btn:focus-visible,
    .eis-list-select-btn[aria-expanded="true"] {
        outline: none;
        border-color: var(--eis-list-green);
        box-shadow: 0 0 0 0.2rem rgba(38, 91, 97, 0.15);
    }

.eis-list-select-label {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.eis-list-select-caret {
    font-size: 0.75rem;
    color: var(--eis-list-muted);
    transition: transform 0.15s ease;
}

/* Loading state (aria-busy="true" on the <select>, see EisListTable.enhanceSelect): a small ring in place of
   the caret, same footprint, so the field does not change size. */
.eis-list-select-spinner {
    --bs-spinner-width: 0.85rem;
    --bs-spinner-height: 0.85rem;
    --bs-spinner-border-width: 0.15em;
    display: none;
    flex-shrink: 0;
    color: var(--eis-list-green);
}

.eis-list-select.is-loading .eis-list-select-spinner {
    display: inline-block;
}

.eis-list-select.is-loading .eis-list-select-caret {
    display: none;
}

.eis-list-select.is-loading .eis-list-select-btn:disabled {
    cursor: progress;
}

.eis-list-select-btn[aria-expanded="true"] .eis-list-select-caret {
    transform: rotate(180deg);
}

.eis-list-select-menu {
    width: max-content;
    max-width: 320px;
    padding: 0.35rem;
    border: 1px solid var(--eis-list-border);
    border-radius: 10px;
    box-shadow: 0 10px 25px rgba(17, 24, 39, 0.10);
}

    /* Long options (building names, "Name (email)") wrap inside the menu instead of scrolling sideways. */
    .eis-list-select-menu .dropdown-item {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 1rem;
        border-radius: 6px;
        padding: 0.5rem 0.75rem;
        color: var(--eis-list-text);
        white-space: normal;
        overflow-wrap: anywhere;
    }

        .eis-list-select-menu .dropdown-item:hover,
        .eis-list-select-menu .dropdown-item:focus {
            background-color: #F3F4F6;
            color: var(--eis-list-text);
        }

        .eis-list-select-menu .dropdown-item.active,
        .eis-list-select-menu .dropdown-item:active {
            background-color: var(--eis-list-green-soft);
            color: var(--eis-list-green);
            font-weight: 600;
        }

        /* A disabled option (e.g. the source teacher in Teacher Reassignment's "To" list) reads as
           unavailable: Bootstrap's disabled item colour, which the item colour above would otherwise override. */
        .eis-list-select-menu .dropdown-item:disabled {
            color: var(--bs-dropdown-link-disabled-color, #ADB5BD);
        }

.eis-list-select-check {
    font-size: 0.8rem;
    visibility: hidden;
}

.eis-list-select-menu .dropdown-item.active .eis-list-select-check {
    visibility: visible;
}

/* Rows per page (footer) */
.eis-list-table-footer .dataTables_length {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    color: var(--eis-list-muted);
    white-space: nowrap;
}

/* (0,3,0): beats the --sm modifier the footer select's form-select-sm would otherwise give it. */
.eis-list-table-footer .eis-list-select > .eis-list-select-btn {
    height: 36px;
    min-width: 76px;
    gap: 0.75rem;
    padding: 0 0.9rem;
    border-radius: 8px;
    font-size: inherit;
}

    .eis-list-table-footer .eis-list-select > .eis-list-select-menu {
        font-size: var(--bs-dropdown-font-size);
    }

        .eis-list-table-footer .eis-list-select > .eis-list-select-menu .dropdown-item {
            padding: 0.5rem 0.75rem;
        }

/* List toolbar filters: 44px, the toolbar search box's height. */
.eis-list-toolbar .eis-list-select > .eis-list-select-btn {
    height: 44px;
}

/* Styled dropdown: long option lists (districts) scroll inside the menu, and a disabled select
   (e.g. a district picker waiting for its state) reads as disabled. */
.eis-list-select-menu {
    max-height: 320px;
    overflow-y: auto;
}

.eis-list-select-btn:disabled {
    background-color: #F3F4F6;
    color: var(--eis-list-muted);
    cursor: not-allowed;
}

/* Opt-in search box at the top of a styled dropdown (EisListTable enhanceSelect, search option). It stays
   pinned while the items scroll under it: the negative margins and top offset (the menu's 0.35rem padding)
   pull it over that padding so nothing shows above it, and it keeps the menu's rounded top corners. */
.eis-list-select-search-item {
    position: sticky;
    top: -0.35rem;
    z-index: 1;
    margin: -0.35rem -0.35rem 0.25rem;
    padding: 0.35rem;
    background-color: #fff;
    border-bottom: 1px solid var(--eis-list-border);
    border-radius: 10px 10px 0 0;
}

.eis-list-select-menu .eis-list-select-search {
    height: 34px;
    padding-left: 0.9rem;
    border: 1px solid var(--eis-list-border);
    border-radius: 8px;
    color: var(--eis-list-text);
    background-color: #fff;
}

    .eis-list-select-menu .eis-list-select-search::placeholder {
        color: var(--eis-list-muted);
    }

    .eis-list-select-menu .eis-list-select-search:hover {
        border-color: #CBD5E1;
    }

    .eis-list-select-menu .eis-list-select-search:focus {
        outline: none;
        border-color: var(--eis-list-green);
        box-shadow: 0 0 0 0.2rem rgba(38, 91, 97, 0.15);
    }

.eis-list-select-empty .dropdown-item-text {
    display: block;
    padding: 0.5rem 0.75rem;
    font-size: 0.875rem;
}

/* Sizes, mirrored from the select's form-select-sm / form-select-lg (or form-control-sm/-lg). */
.eis-list-select--sm > .eis-list-select-btn {
    height: 31px;
    gap: 0.5rem;
    padding: 0 0.75rem;
    font-size: 0.875rem;
    border-radius: 6px;
}

    .eis-list-select--sm > .eis-list-select-menu {
        font-size: 0.875rem;
    }

        .eis-list-select--sm > .eis-list-select-menu .dropdown-item {
            padding: 0.35rem 0.6rem;
        }

.eis-list-select--lg > .eis-list-select-btn {
    height: 48px;
    padding: 0 1rem;
    font-size: 1.25rem;
    border-radius: 10px;
}

/* Inline: the select was inline-level (an unclassed <select>, or d-inline-block), so the control stays on
   the line with the text around it ("Show [10] entries"). Full width unless it is also --auto, or the
   select's inline width / w-* class (mirrored onto the wrap) says otherwise. */
.eis-list-select--inline {
    display: inline-block;
    width: 100%;
    max-width: 100%;
    vertical-align: middle;
}

/* Auto width: the select had no width of its own (no form-select/form-control, or w-auto), so it was as
   wide as its longest option. The hidden sizer lists every option's text in the label's grid cell, so the
   button is as wide as the longest one, as the native select was, whichever option is picked. */
.eis-list-select--auto {
    width: fit-content;
    max-width: 100%;
}

.eis-list-select--inline.eis-list-select--auto {
    width: auto;
}

.eis-list-select--auto > .eis-list-select-btn {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
}

    .eis-list-select--auto > .eis-list-select-btn > .eis-list-select-label,
    .eis-list-select-sizer {
        grid-row: 1;
        grid-column: 1;
    }

    .eis-list-select--auto > .eis-list-select-btn > .eis-list-select-caret,
    .eis-list-select--auto > .eis-list-select-btn > .eis-list-select-spinner {
        grid-row: 1;
        grid-column: 2;
    }

.eis-list-select-sizer {
    height: 0;
    overflow: hidden;
    visibility: hidden;
}

    .eis-list-select-sizer > span {
        display: block;
        white-space: nowrap;
    }

/* In an .input-group: a flex item like an input, with the button's corners joined to its neighbours.
   The visually hidden <select> sits right before the wrap, so Bootstrap's :first-child / :last-child
   rules see the select, not the control; these restate them for the button. */
.input-group > .eis-list-select {
    position: relative;
    flex: 1 1 auto;
    width: 1%;
    min-width: 0;
}

    .input-group > .eis-list-select:focus-within {
        z-index: 5;   /* the focus ring over the neighbour, as Bootstrap does for a focused input */
    }

    /* The select is first, so the control is the first thing shown: no -1px overlap (Bootstrap's
       :not(:first-child) rule, specificity 0,7,0, gives the wrap one). */
    .input-group > :first-child + .eis-list-select {
        margin-left: 0 !important;
    }

    .input-group > :not(:first-child) + .eis-list-select > .eis-list-select-btn {
        border-top-left-radius: 0;
        border-bottom-left-radius: 0;
    }

    .input-group > .eis-list-select:not(:last-child) > .eis-list-select-btn {
        border-top-right-radius: 0;
        border-bottom-right-radius: 0;
    }

.input-group-sm > .eis-list-select > .eis-list-select-btn {
    height: 31px;
    font-size: 0.875rem;
    border-radius: 6px;
}

.input-group-lg > .eis-list-select > .eis-list-select-btn {
    height: 48px;
    font-size: 1.25rem;
    border-radius: 10px;
}

/* In a modal the field can sit in a flex row (e.g. Source Name + Fetch button): take the free width. */
.modal .eis-list-select:not(.eis-list-select--auto) {
    flex: 1 1 auto;
    min-width: 0;
}

/* The select's is-invalid class is mirrored onto the button (EisListTable syncSelect), styled like
   Bootstrap's .form-select.is-invalid. */
.eis-list-select-btn.is-invalid {
    border-color: var(--bs-form-invalid-border-color, #dc3545);
}

    .eis-list-select-btn.is-invalid:focus-visible,
    .eis-list-select-btn.is-invalid[aria-expanded="true"] {
        border-color: var(--bs-form-invalid-border-color, #dc3545);
        box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);
    }

/* --------------------------------------------------------------------------------------------
   bootstrap-select, site-wide: selects a page script drives through selectpicker / changed.bs.select
   (multi-selects, live-search pickers; EisListTable never enhances these), restyled to match the
   styled dropdown above. Replaces site.css's old bootstrap-select block. bootstrap-select's own CSS
   puts !important outlines on the button, and page styles often use !important too, so these do.
   The width is not forced here (bootstrap-select's 220px default and data-width stay); only the
   list-theme modals make them full width.
   -------------------------------------------------------------------------------------------- */

.eis-list-page .modal .bootstrap-select {
    width: 100% !important;
}

/* bootstrap-select copies every class of the select onto its wrapper div, form-control / form-select
   included. The wrapper must not take the field look (a second border around the button, the native
   chevron, padding that insets the button), so it is reset; the :not() selector matches Bootstrap's
   .form-select.is-invalid:not([multiple]):not([size]) padding rule on specificity. */
.bootstrap-select.form-control,
.bootstrap-select.form-select,
.bootstrap-select.form-select:not([multiple]):not([size]) {
    padding: 0;
    border: 0;
    background-color: transparent;
    background-image: none;
    box-shadow: none;
}

/* The button: 38px like the styled dropdown and a form-control (0.375rem vertical padding and the 1.5 line
   height; bootstrap-select's label fills the button's content box, so the height comes from padding rather
   than a fixed height, which would lift the text). */
.bootstrap-select > .dropdown-toggle {
    padding: 0.375rem 0.9rem !important;
    border: 1px solid var(--eis-list-border) !important;
    border-radius: 8px !important;
    background-color: #fff !important;
    color: var(--eis-list-text) !important;
    font-weight: 400 !important;
    line-height: 1.5 !important;
    box-shadow: none !important;
}

    /* Mouse focus shows no ring and no outline (bootstrap-select's own CSS adds an !important outline); the
       ring is for the keyboard and while the menu is open, as on the styled dropdown. */
    .bootstrap-select > .dropdown-toggle:focus,
    .bootstrap-select > select.mobile-device:focus + .dropdown-toggle {
        outline: none !important;
        outline-offset: 0 !important;
        border-color: var(--eis-list-border) !important;
        box-shadow: none !important;
    }

    .bootstrap-select > .dropdown-toggle:hover {
        border-color: #CBD5E1 !important;
    }

    /* Open: Bootstrap 5 marks the toggle itself (aria-expanded, .show); .show on the wrapper is kept
       for bootstrap-select's own bookkeeping. */
    .bootstrap-select > .dropdown-toggle:focus-visible,
    .bootstrap-select > .dropdown-toggle[aria-expanded="true"],
    .bootstrap-select.show > .dropdown-toggle {
        border-color: var(--eis-list-green) !important;
        box-shadow: 0 0 0 0.2rem rgba(38, 91, 97, 0.15) !important;
    }

    .bootstrap-select > .dropdown-toggle.disabled,
    .bootstrap-select > .dropdown-toggle:disabled {
        background-color: #F3F4F6 !important;
        color: var(--eis-list-muted) !important;
    }

    /* The styled dropdown's chevron instead of Bootstrap's triangle; it turns over while open. */
    .bootstrap-select > .dropdown-toggle::after {
        content: "\f078";
        font-family: "Font Awesome 6 Free";
        font-weight: 900;
        font-size: 0.75rem;
        border: 0;
        margin: 0 0 0 0.75rem;
        vertical-align: middle;
        color: var(--eis-list-muted);
        transition: transform 0.15s ease;
    }

    .bootstrap-select > .dropdown-toggle[aria-expanded="true"]::after,
    .bootstrap-select.show > .dropdown-toggle::after {
        transform: rotate(180deg);
    }

/* A select with form-select-sm / form-control-sm (copied onto the wrapper): Bootstrap's small field. */
.bootstrap-select.form-select-sm > .dropdown-toggle,
.bootstrap-select.form-control-sm > .dropdown-toggle {
    padding: 0.25rem 0.75rem !important;
    font-size: 0.875rem;
    border-radius: 6px !important;
}

.bootstrap-select .filter-option-inner-inner {
    color: var(--eis-list-text);
    text-overflow: ellipsis;
}

.bootstrap-select > .dropdown-toggle.bs-placeholder .filter-option-inner-inner {
    color: var(--eis-list-muted);
}

/* Invalid: a page script sets is-invalid on the <select>, which bootstrap-select keeps inside its
   wrapper; bootstrap-select only copies classes to the wrapper on refresh, so match the select. */
.bootstrap-select:has(> select.is-invalid) > .dropdown-toggle {
    border-color: var(--bs-form-invalid-border-color, #dc3545) !important;
}

    .bootstrap-select:has(> select.is-invalid) > .dropdown-toggle:focus-visible,
    .bootstrap-select:has(> select.is-invalid) > .dropdown-toggle[aria-expanded="true"],
    .bootstrap-select.show:has(> select.is-invalid) > .dropdown-toggle {
        box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25) !important;
    }

/* The menu: rounded card with the theme's shadow, never wider than the button. */
.bootstrap-select > .dropdown-menu {
    max-width: 100%;
    padding: 0.35rem;
    border: 1px solid var(--eis-list-border);
    border-radius: 10px;
    box-shadow: 0 10px 25px rgba(17, 24, 39, 0.10);
}

/* The list is at most 320px tall, as the styled dropdown's menu is, then it scrolls. Without data-size,
   bootstrap-select sizes the list to the window (every district filled the screen), writing max-height and
   min-height inline on the menu and on its scrolling div.inner (min-height beats max-height), hence
   !important. Only div.inner scrolls (bootstrap-select listens to it); the menu around it (search box,
   Select All) grows with the list, so its own inline limit can never clip it. */
.bootstrap-select > .dropdown-menu > .inner {
    max-height: 320px !important;
    min-height: 0 !important;
    overflow-y: auto !important;
}

.bootstrap-select > .dropdown-menu {
    max-height: none !important;
    min-height: 0 !important;
}

/* Items: grey hover and keyboard highlight, soft-green selected rows. Long labels (building names,
   "Name (email)") wrap inside the button-wide menu, as the styled dropdown's do in a modal;
   bootstrap-select's nowrap would stretch the menu past the button. */
.bootstrap-select .dropdown-menu li > a {
    padding: 0.5rem 0.75rem;
    border-radius: 6px;
    color: var(--eis-list-text);
    white-space: normal;
    overflow-wrap: anywhere;
}

    .bootstrap-select .dropdown-menu li > a:hover,
    .bootstrap-select .dropdown-menu li > a:focus,
    .bootstrap-select .dropdown-menu li > a:active,
    .bootstrap-select .dropdown-menu li.active > a {
        background-color: #F3F4F6 !important;
        color: var(--eis-list-text) !important;
    }

    .bootstrap-select .dropdown-menu li.selected > a,
    .bootstrap-select .dropdown-menu li.selected > a:hover,
    .bootstrap-select .dropdown-menu li.selected > a:focus,
    .bootstrap-select .dropdown-menu li.selected.active > a {
        background-color: var(--eis-list-green-soft) !important;
        color: var(--eis-list-green) !important;
        font-weight: 600;
    }

/* The multi-selects' tick (show-tick): centred on the row and in from the right like the styled
   dropdown's check, now that the rows are taller. It takes the row's colour, so it is green. */
.bootstrap-select.show-tick .dropdown-menu .selected span.check-mark {
    top: 50%;
    right: 0.75rem;
    transform: translateY(-50%);
}

/* Live search box: the menu's padding already insets it. Its input is a .form-control, so the site-wide
   input rule styles it; this only gives it the styled dropdown's 34px. */
.bootstrap-select .bs-searchbox,
.bootstrap-select .bs-actionsbox,
.bootstrap-select .bs-searchbox + .bs-actionsbox {
    padding: 0 0 0.35rem;
}

.bootstrap-select .bs-searchbox .form-control {
    height: 34px;
    padding-top: 0.25rem;
    padding-bottom: 0.25rem;
}

/* Select All / Deselect All (data-actions-box) keep site.css's solid green buttons; a page that wants
   another look styles them in its own stylesheet (ManageBuildingUsers.css does). */

/* "No results matched": the styled dropdown's empty row. */
.bootstrap-select .no-results {
    margin: 0;
    padding: 0.5rem 0.75rem;
    background: transparent;
    color: var(--eis-list-muted);
    font-size: 0.875rem;
    white-space: normal;
}

/* --------------------------------------------------------------------------------------------
   DataTables tables that are not on the list theme (no data-eis-list-table): the search box is a
   .form-control-sm (themed above) and EisListTable puts the styled dropdown in place of the
   rows-per-page select, inline in DataTables' "Show [10] entries" label (31px, from form-select-sm).
   -------------------------------------------------------------------------------------------- */
/* Server-mode tables (EisListTable data-eis-list-server): the wrapper DataTables builds around the table
   hosts the loading ring below, which is positioned against it. */
.eis-list-table-wrap .dataTables_wrapper {
    position: relative;
}

/* A server-mode table whose last request failed (EisListTable showServerError adds eis-list-server-error to the
   wrapper): the previous result's pager and rows-per-page selector would page through rows that are no longer
   shown, so they are hidden until the next successful draw. visibility keeps their place, so the footer does
   not jump, and takes them out of the tab order. */
.dataTables_wrapper.eis-list-server-error .eis-list-table-footer .dataTables_paginate,
.dataTables_wrapper.eis-list-server-error .eis-list-table-footer .dataTables_length {
    visibility: hidden;
}

/* --------------------------------------------------------------------------------------------
   Standard modal: the DEFAULT for every Bootstrap modal on every page (Task 4457; the design first
   built for Manage Building Users). No opt-in class is needed; the .eis-modal-* classes add the
   optional parts.
   Header: .modal-header > div > h6.modal-title + optional p.eis-modal-subtitle, then the .btn-close
           (white, left-aligned green title; never a coloured header bar).
   Body:   optional .eis-modal-error banner, then the content (form.eis-modal-form for the form rhythm,
           p.eis-modal-message for a confirmation's text).
   Footer: .modal-footer > Cancel (.btn.eis-modal-btn-secondary, left) + .eis-modal-actions (right; the
           primary action last: .btn.btn-squishy, or .btn.btn-danger for a destructive one; a secondary
           outline action is .btn.eis-modal-btn-outline). A lone button (Close, OK) sits on the right; an
           acknowledgement (OK, Understood) is the primary .btn-squishy, a lone Close the secondary.
           Buttons belong in the footer, not the body: a submit button outside its <form> takes form="id".
   Width:  560px by default; .modal-sm / .modal-lg / .modal-xl on the .modal-dialog as usual.
   Opt-out: data-eis-native on the .modal (or on an element that borrows modal classes for a page card)
   keeps Bootstrap's own look. The :where() adds no specificity, so page rules still win as before.
   -------------------------------------------------------------------------------------------- */
.modal:where(:not([data-eis-native])) {
    --bs-modal-width: 560px; /* .modal-sm / -lg / -xl on the dialog override this */
}

.modal-content:where(:not([data-eis-native] *)) {
    border: none;
    border-radius: 0.5rem;
    box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
}

/* White over any legacy header colour (.bg-eis-green, bg-light): the title carries the colour. The close
   button is centred vertically on the title (or on the title and its subtitle). */
.modal-header:where(:not([data-eis-native] *)) {
    align-items: center;
    gap: 1rem;
    padding: 2rem 1.5rem 1rem;
    border-bottom: 0;
    background-color: #fff;
    color: var(--eis-list-text);
}

    /* A white close button (made for a dark header) would vanish on the white one. */
    .modal-header:where(:not([data-eis-native] *)) .btn-close-white {
        filter: none;
    }

.modal-title:where(:not([data-eis-native] *)) {
    margin: 0 0 0.25rem;
    text-align: left; /* site.css centres h1-h5; any heading level reads the same */
    font-size: 1.25rem;
    font-weight: 600;
    color: var(--eis-list-green);
}

    /* No subtitle under it (or the title sits straight in the header): no gap either, so the close button
       lines up with the title itself. */
    .modal-title:where(:not([data-eis-native] *)):last-child,
    .modal-header > .modal-title:where(:not([data-eis-native] *)) {
        margin-bottom: 0;
    }

.eis-modal-subtitle {
    margin: 0;
    font-size: 0.875rem;
    color: var(--eis-list-muted);
}

/* The header's bottom padding is the gap above the body; a modal without a header pads the body at the top
   too. The space above the footer is always 1.5rem: instead of bottom padding, an empty ::after carries a
   1.5rem top margin, which collapses with the last field's mb-3 (or a message's 1rem margin), so the gap is
   the larger of the two rather than their sum, whatever the body ends with. */
.modal-body:where(:not([data-eis-native] *)) {
    padding: 1.5rem 1.5rem 0;
}

    .modal-body:where(:not([data-eis-native] *))::after {
        content: "";
        display: block;
        margin-top: 1.5rem;
    }

.modal-header:where(:not([data-eis-native] *)) + .modal-body,
.modal-header:where(:not([data-eis-native] *)) + form > .modal-body:first-child {
    padding-top: 0;
}

.modal-footer:where(:not([data-eis-native] *)) {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: center;
    gap: 0.5rem;
    padding: 0 1.5rem 1.5rem;
    border-top: 0;
}

    /* Bootstrap gives every direct footer child a margin; the gap above does the spacing instead. */
    .modal-footer:where(:not([data-eis-native] *)) > * {
        margin: 0;
    }

    /* A lone button (Close, OK) sits on the right. */
    .modal-footer:where(:not([data-eis-native] *)) > :only-child {
        margin-left: auto;
    }

/* The right-hand button group; margin-left:auto keeps it right-aligned even when it is alone. */
.eis-modal-actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-left: auto;
}

/* A confirmation's text, in the theme's muted grey (no text-muted needed). Its bottom margin is the
   gap a form's last field leaves (mb-3), so every modal has the same space above the footer. */
.eis-modal-message {
    margin: 0 0 1rem;
    color: var(--eis-list-muted);
}

/* Form spacing: the same vertical rhythm in every modal. No bottom padding: the last field's mb-3 plus the
   body's 0.5rem make the gap above the footer. */
.eis-modal-form {
    padding: 0.5rem 0 0;
}

.modal:where(:not([data-eis-native])) .form-label {
    margin-bottom: 0.375rem;
}

.modal:where(:not([data-eis-native])) .form-text {
    margin-top: 0.25rem;
    font-size: 0.8125rem;
    color: var(--eis-list-muted);
}

/* Error banner above the form (text set by Integration.js showError). */
.eis-modal-error,
.eis-modal-success {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.75rem 1rem;
    border-radius: 0.5rem;
    font-size: 12px;
}

.eis-modal-error {
    margin-bottom: 1rem;
    background-color: rgba(var(--bs-danger-rgb), 0.1);
    color: rgba(128, 0, 0, 0.9);
}

/* Inline success message (e.g. a passed connection test). Colours match the success toast. */
.eis-modal-success {
    background-color: #E4EBE4;
    color: #1F621D;
}

    .eis-modal-error p,
    .eis-modal-success p {
        margin: 0;
        overflow-wrap: anywhere;
    }

/* Full-width result line on its own row at the top of a footer. */
.modal-footer > .eis-modal-footer-message {
    flex: 1 0 100%;
}

/* Secondary (outline) action beside the primary button, e.g. Test Connection in a modal or Verify in a page
   card. */
.eis-modal-btn-outline {
    color: var(--eis-list-green);
    background-color: #fff;
    border: 1px solid var(--eis-list-green);
}

    .eis-modal-btn-outline:hover,
    .eis-modal-btn-outline:active {
        color: var(--eis-list-green);
        background-color: var(--eis-list-green-soft);
        border-color: var(--eis-list-green);
    }

    .eis-modal-btn-outline:focus-visible {
        outline: 2px solid var(--eis-list-green);
        outline-offset: 2px;
    }

    .eis-modal-btn-outline:disabled {
        color: var(--eis-list-green);
        background-color: #fff;
        border-color: var(--eis-list-green);
        opacity: 0.65;
    }

/* Neutral (grey outline) action: every modal's Cancel / Close / No (it replaced the old yellow .Cancel-Btn;
   first used by Manage Building Users, Task 4448). */
.eis-modal-btn-secondary {
    color: var(--eis-list-text);
    background-color: #fff;
    border: 1px solid #D1D5DB;
}

    .eis-modal-btn-secondary:hover,
    .eis-modal-btn-secondary:active {
        color: var(--eis-list-text);
        background-color: var(--eis-list-subtle-bg);
        border-color: #C2C7CF;
    }

    .eis-modal-btn-secondary:focus-visible {
        outline: 2px solid var(--eis-list-muted);
        outline-offset: 2px;
    }

    /* Disabled (e.g. SSO Configuration while a request is in flight): the same button, faded, not
       Bootstrap's transparent .btn:disabled. */
    .eis-modal-btn-secondary:disabled {
        color: var(--eis-list-text);
        background-color: #fff;
        border-color: #D1D5DB;
        opacity: 0.65;
    }

/* --------------------------------------------------------------------------------------------
   Panels: the DEFAULT for every legacy .panel on every page (Task 4466), and for a Bootstrap .card that
   opts in with .eis-panel. A light-green heading (--eis-list-head-bg, the table header rows' colour) with a
   left-aligned green title over a hairline divider; never a strong coloured header bar.
   Panel:    .panel > .panel-heading, then .panel-content / .panel-content-lg (padded) or .panel-body
             (unpadded, as before: pages pad it themselves). A panel may hold several heading + content
             steps; a heading that follows content gets a divider above it too.
   Collapse: a heading that toggles a .collapse right after it (data-bs-toggle on the heading or on a link
             in it) drops its divider while the section is closed, so a closed row is one bordered strip.
             Keep the .collapse a direct sibling of its heading: Change Building and the teacher checklist
             scripts depend on that structure.
   Toggle:   .eis-panel-toggle on the heading's collapse link stretches it over the whole heading, so a
             click anywhere on the heading opens or closes the section; put an
             <i class="bi bi-chevron-right eis-panel-chevron" aria-hidden="true"> first inside it, and it
             turns down while the section is open (aria-expanded="true"). Reference: Change Building.
   Variants: .panel-blue (a highlighted panel, e.g. the current evaluation cycle) takes a deeper green
             heading than the standard one; .panel-checklist is a compact row (tighter heading, small gap
             between rows).
   Card:     .card.eis-panel themes its .card-header the same way, through Bootstrap's card variables.
   Opt-out:  data-eis-native on the panel (or an ancestor) keeps it unthemed. The :where() adds no
             specificity, so page rules still win.
   -------------------------------------------------------------------------------------------- */
.panel:where(:not([data-eis-native], [data-eis-native] *)) {
    margin: 1.5rem 0;
    padding: 0; /* a panel straight inside a .row would otherwise take the gutter, insetting its heading */
    border: 1px solid var(--eis-list-border);
    border-radius: 10px;
    background-color: #fff;
    box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
}

/* The radius is the panel's less its border, so the tinted heading never pokes past the rounded corner. The
   1rem inset lines the title up with the body text: .panel-content, and the p-3 that pages put on .panel-body. */
.panel-heading:where(:not([data-eis-native] *)) {
    padding: 0.875rem 1rem;
    border-bottom: 1px solid var(--eis-list-border);
    border-radius: 9px 9px 0 0;
    background-color: var(--eis-list-head-bg);
    color: var(--eis-list-green);
    font-size: 1rem;
    font-weight: 600;
    text-align: left;
}

    /* A later step in a multi-step panel (Impersonate, Send Building-Wide Email). */
    :is(.panel-content, .panel-content-lg, .panel-body, .collapse, .collapsing) + .panel-heading:where(:not([data-eis-native] *)) {
        border-top: 1px solid var(--eis-list-border);
        border-radius: 0;
    }

    /* Nothing under it, or its section is closed: no divider, and round the bottom corners too. */
    .panel-heading:where(:not([data-eis-native] *)):last-child,
    .panel-heading:where(:not([data-eis-native] *)):has(+ .collapse:not(.show)) {
        border-bottom-color: transparent;
        border-bottom-left-radius: 9px;
        border-bottom-right-radius: 9px;
    }

    .panel-heading:where(:not([data-eis-native] *))[data-bs-toggle] {
        cursor: pointer;
    }

    /* site.css centres and colours every h1-h5; a heading inside a panel heading reads as its title. */
    .panel-heading:where(:not([data-eis-native] *)) :is(h1, h2, h3, h4, h5, h6) {
        margin: 0;
        text-align: left;
        font-size: 1.125rem;
        font-weight: 600;
        color: inherit;
    }

    .panel-heading:where(:not([data-eis-native] *)) a:not(.btn) {
        color: inherit;
        text-decoration: none;
    }

    /* Section toggle: the heading's padding moves onto the link, so the whole heading is the click target. */
    .panel-heading:where(:not([data-eis-native] *)):has(> .eis-panel-toggle) {
        padding: 0;
    }

        .panel-heading > .eis-panel-toggle {
            display: flex;
            align-items: center;
            gap: 0.5rem;
            padding: 0.875rem 1rem;
            border-radius: inherit;
        }

            .panel-heading > .eis-panel-toggle:hover {
                background-color: rgba(38, 91, 97, 0.06);
            }

        .eis-panel-toggle > .eis-panel-chevron {
            flex-shrink: 0;
            font-size: 0.875rem;
            transition: transform 0.15s ease;
        }

        .eis-panel-toggle[aria-expanded="true"] > .eis-panel-chevron {
            transform: rotate(90deg);
        }

.panel-content:where(:not([data-eis-native] *)) {
    padding: 1rem;
}

.panel-content-lg:where(:not([data-eis-native] *)) {
    padding: 1.5rem;
    font-size: 1.125rem;
    line-height: 1.25;
}

/* One step deeper than --eis-list-head-bg, so it stands out among the standard headings (title 5.72:1, AA). */
.panel-blue > .panel-heading:where(:not([data-eis-native] *)) {
    background-color: #CFE3E1;
}

.panel-checklist:where(:not([data-eis-native], [data-eis-native] *)) {
    margin: 0.375rem 0;
    border-radius: 8px;
}

    .panel-checklist .panel-heading:where(:not([data-eis-native] *)) {
        padding: 0.5rem 0.75rem;
        border-radius: 7px 7px 0 0;
    }

    .panel-checklist .panel-heading:where(:not([data-eis-native] *)):last-child,
    .panel-checklist .panel-heading:where(:not([data-eis-native] *)):has(+ .collapse:not(.show)) {
        border-radius: 7px;
    }

.card.eis-panel {
    --bs-card-border-color: var(--eis-list-border);
    --bs-card-border-radius: 10px;
    --bs-card-inner-border-radius: 9px;
    --bs-card-cap-bg: var(--eis-list-head-bg);
    --bs-card-cap-color: var(--eis-list-green);
    --bs-card-cap-padding-y: 0.875rem;
    --bs-card-cap-padding-x: 1rem; /* Bootstrap's card body inset, so title and body line up */
    box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
}

    .card.eis-panel > .card-header {
        font-size: 1rem;
        font-weight: 600;
        text-align: left;
    }

        .card.eis-panel > .card-header :is(h1, h2, h3, h4, h5, h6) {
            margin: 0;
            text-align: left;
            font-size: 1.125rem;
            font-weight: 600;
            color: inherit;
        }

/* Added by EisListTable to a loading ring's host only when that host is not already positioned (a server
   table outside .eis-list-table-wrap, or one DataTables did not wrap). */
.eis-list-loader-host {
    position: relative;
}

/* Server-mode loading ring: a ring with "Loading..." under it, over the rows region while a page is
   fetched (created by EisListTable, no page markup). Layered on site.css's .loader-overlay (absolute,
   white dimming, centred, z-index) rather than re-declaring it, and on its display:flex, which Bootstrap's
   d-none (display:none !important) still beats, so no display here. The box is measured in JS on every
   show (top = bottom of the header row, left/width = the table), hence unsetting the shared inset; the
   header row, toolbar and footer stay uncovered and usable. */
.loader-overlay.eis-list-loader {
    inset: auto;
    flex-direction: column;
    gap: 0.75rem;
}

    .eis-list-loader .spinner-border {
        --bs-spinner-width: 2.5rem;
        --bs-spinner-height: 2.5rem;
        --bs-spinner-border-width: 0.3em;
        flex-shrink: 0;
    }

.eis-list-loader-text {
    color: var(--eis-list-green);   /* #265B61, as .text-eis-green on the ring */
    font-weight: 600;
    font-size: 0.95rem;
    line-height: 1.2;
}

/* Holds an empty tbody open on the first draw, so the ring has a rows region to cover. DataTables
   replaces the tbody's rows on draw, which takes this row with it. */
table.eis-list-table tbody tr.eis-list-loader-placeholder > td {
    height: 180px;
    padding: 0;
    border-bottom: 0;
}

/* Busy overlay (EisListTable.showBusy / hideBusy / runBusy): the loading ring above, laid over a whole
   element (a card body, a table container) while a save or delete runs, with "Saving..." under it. It
   reuses .loader-overlay (dimming, centring, z-index) and .eis-list-loader (column, ring size, text);
   only the box differs: it covers the whole element, so the inset the server loader unsets is restored.
   The JS pads it so the ring sits in the visible part of a tall element. */
.eis-list-page .eis-list-busy-host {
    position: relative;
}

.eis-list-page .loader-overlay.eis-list-loader.eis-list-busy {
    inset: 0;
    cursor: progress;
}
