:root {
    --sidebar-width: 240px;
    --sidebar-collapsed-width: 68px;
    /* The sidebar's own dark gradient/accent colors are deliberately NOT theme-dependent - it's
       already a dark surface by design in both light and dark mode (see the visual-design-pass
       history in CLAUDE.md), so nothing here needs a [data-bs-theme="dark"] override. */
    --sidebar-bg: #1a2030;
    --sidebar-bg-end: #232a3d;
    --sidebar-fg: #b8c0cc;
    --sidebar-fg-active: #ffffff;
    --sidebar-accent: #4f7cff;
    --sidebar-accent-end: #7c5cff;
    --topbar-height: 60px;

    /* ---- Theme-aware tokens - light values here, dark overrides in the block below ----
       Kept as our own small set alongside Bootstrap 5.3's native dark-mode variables (--bs-*)
       rather than duplicating everything: plain body/muted text and "surface" colors already
       reuse Bootstrap's own --bs-body-color/--bs-secondary-color/--bs-card-bg/--bs-tertiary-bg
       (already dark-aware for free), these tokens only cover the app-specific surfaces Bootstrap
       has no equivalent for (topbar, icon buttons, dividers, track backgrounds, the scroll fade
       hint). See CLAUDE.md's dark-mode entry for the full Phase 0-6 plan - the world map's own
       colors (Phase 5) and vendored DataTables/Select2/SweetAlert2 theming (Phase 3) are
       deliberately NOT touched by this pass. */
    --content-bg: #f4f6f9;
    --topbar-bg: #fff;
    --icon-btn-bg: var(--content-bg);
    --icon-btn-bg-hover: #e9edf3;
    --icon-btn-color: #495057;
    --icon-btn-color-hover: #212529;
    --divider-color: #eef0f3;
    --track-bg: #eef0f3;
    --scroll-fade-color: rgba(0, 0, 0, .06);

    --transition-fast: .15s ease-in-out;
}

[data-bs-theme="dark"] {
    --content-bg: #12151d;
    --topbar-bg: #1c2029;
    --icon-btn-bg: #232838;
    --icon-btn-bg-hover: #2c3244;
    --icon-btn-color: #c7ccd6;
    --icon-btn-color-hover: #ffffff;
    --divider-color: rgba(255, 255, 255, .08);
    --track-bg: rgba(255, 255, 255, .10);
    --scroll-fade-color: rgba(255, 255, 255, .10);
}

body {
    background-color: var(--content-bg);
}

/* ---- Shared micro-interactions (used across sidebar/topbar/cards/buttons) ---- */
.btn {
    transition: transform var(--transition-fast), box-shadow var(--transition-fast), background-color var(--transition-fast), color var(--transition-fast);
}

.btn:hover:not(:disabled) {
    transform: translateY(-1px);
}

.btn-primary {
    background: linear-gradient(135deg, var(--sidebar-accent), var(--sidebar-accent-end));
    border-color: var(--sidebar-accent);
    box-shadow: 0 2px 8px rgba(79, 124, 255, .28);
}

.btn-primary:hover {
    background: linear-gradient(135deg, #3f6bee, #6c4cf0);
    border-color: #3f6bee;
    box-shadow: 0 4px 12px rgba(79, 124, 255, .4);
}

/* Gentle entrance for the main content area on every page load/navigation - the one touch
   that makes the whole app feel less like a static default template. */
@keyframes fadeInUp {
    from { opacity: 0; transform: translateY(6px); }
    to { opacity: 1; transform: translateY(0); }
}

.dashboard-main > * {
    animation: fadeInUp .35s ease-out both;
}

/* ---- Sidebar ---- */
.dashboard-sidebar {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    width: var(--sidebar-width);
    background: linear-gradient(180deg, var(--sidebar-bg), var(--sidebar-bg-end));
    display: flex;
    flex-direction: column;
    overflow: hidden;
    z-index: 1030;
    transition: width .2s ease-in-out;
}

html[dir="rtl"] .dashboard-sidebar {
    left: auto;
    right: 0;
}

/* Sized a bit larger than the bi-bar-chart-line-fill icon it replaces/falls back to (that
   icon rendered at 1.05rem, inherited from .brand's font-size) - the icon glyph filled its
   box more visually than the logo image did at the same literal size, so this is bumped up
   for a comparable visual weight. object-fit keeps a non-square source image from distorting. */
.brand-logo {
    height: 1.75rem;
    width: 1.75rem;
    object-fit: contain;
    flex-shrink: 0;
}

/* Same idea for the login page's larger logo (was font-size: 2.25rem on the icon it replaces). */
.auth-logo {
    height: 3.25rem;
    width: 3.25rem;
    object-fit: contain;
}

/* Holds the sidebar's own toggle button + brand - always visible, height matches the
   topbar so the two align in a straight line across the page. */
.sidebar-top {
    height: var(--topbar-height);
    display: flex;
    align-items: center;
    gap: .5rem;
    padding-inline: 1rem;
    border-bottom: 1px solid rgba(255, 255, 255, .08);
    flex-shrink: 0;
}

/* Crossfades with .topbar-brand below rather than an instant display:none/flex swap - both
   animate max-width + opacity (display:none can't be transitioned at all), so the logo/name
   visibly shrinks away here as it grows in over there instead of just popping. */
.sidebar-brand {
    display: flex;
    align-items: center;
    gap: .5rem;
    color: #fff;
    font-weight: 600;
    font-size: 1.05rem;
    white-space: nowrap;
    overflow: hidden;
    max-width: 180px;
    opacity: 1;
    transition: max-width .25s ease-in-out, opacity .18s ease-in-out;
}

body.sidebar-collapsed .sidebar-brand {
    max-width: 0;
    opacity: 0;
    pointer-events: none;
}

/* With the brand shrunk away, center the lone toggle button in the narrow rail - also drop
   .sidebar-top's gap so the zero-width (but still flex-participating) brand doesn't leave the
   button visibly off-center. */
body.sidebar-collapsed .sidebar-top {
    justify-content: center;
    padding-inline: 0;
    gap: 0;
}

/* Mirror of .sidebar-brand, living in the topbar - collapsed to nothing by default (the
   sidebar's own brand already covers it), grown in only while the sidebar is collapsed. The
   short transition-delay staggers it just after .sidebar-brand starts shrinking, so one
   visibly hands off to the other instead of both changing at once. */
.topbar-brand {
    display: flex;
    align-items: center;
    gap: .5rem;
    font-weight: 600;
    color: var(--bs-body-color);
    max-width: 0;
    opacity: 0;
    overflow: hidden;
    white-space: nowrap;
    transition: max-width .25s ease-in-out .08s, opacity .18s ease-in-out .08s;
    pointer-events: none;
}

body.sidebar-collapsed .topbar-brand {
    max-width: 220px;
    opacity: 1;
    pointer-events: auto;
}

/* Dark-sidebar-appropriate variant of .icon-btn (which is styled for the light topbar) - a
   flat near-invisible fill read as "just a white circle" against the dark gradient, so this
   uses a low-opacity dark fill plus a subtle border for actual definition instead. Qualified
   with .dashboard-sidebar so its specificity beats .icon-btn's regardless of source order in
   this file (equal-specificity same-selector-count rules would otherwise just be a fragile
   ordering dependency). */
.dashboard-sidebar .sidebar-toggle-btn {
    background-color: rgba(79, 124, 255, .12);
    border: 1px solid var(--sidebar-accent);
    color: var(--sidebar-fg-active);
    flex-shrink: 0;
}

.dashboard-sidebar .sidebar-toggle-btn:hover {
    background-color: rgba(79, 124, 255, .22);
    border-color: var(--sidebar-accent-end);
    color: #fff;
}

.dashboard-sidebar .nav {
    padding-inline: .6rem;
    gap: .15rem;
}

.dashboard-sidebar .nav-link {
    color: var(--sidebar-fg);
    padding: .65rem 1rem;
    display: flex;
    align-items: center;
    gap: .75rem;
    border-radius: 8px;
    font-size: .93rem;
    transition: color var(--transition-fast), background-color var(--transition-fast), transform var(--transition-fast);
}

.dashboard-sidebar .nav-link i {
    font-size: 1.05rem;
    width: 1.25rem;
    text-align: center;
    flex-shrink: 0;
    transition: transform var(--transition-fast);
}

.dashboard-sidebar .nav-link span {
    white-space: nowrap;
    overflow: hidden;
}

/* Icon-only rail: hide the label, center the icon in the narrower link. Nav links keep
   their title="" attribute (set in _Layout.cshtml) so hovering still shows the page name. */
body.sidebar-collapsed .dashboard-sidebar .nav-link {
    justify-content: center;
    padding-inline: 0;
}

body.sidebar-collapsed .dashboard-sidebar .nav-link span {
    display: none;
}

.dashboard-sidebar .nav-link:hover {
    color: var(--sidebar-fg-active);
    background-color: rgba(255, 255, 255, .07);
    transform: translateX(2px);
}

html[dir="rtl"] .dashboard-sidebar .nav-link:hover {
    transform: translateX(-2px);
}

.dashboard-sidebar .nav-link:hover i {
    transform: scale(1.1);
}

.dashboard-sidebar .nav-link.active {
    color: var(--sidebar-fg-active);
    background: linear-gradient(90deg, rgba(79, 124, 255, .28), rgba(124, 92, 255, .1));
    box-shadow: inset 3px 0 0 var(--sidebar-accent);
}

html[dir="rtl"] .dashboard-sidebar .nav-link.active {
    background: linear-gradient(270deg, rgba(79, 124, 255, .28), rgba(124, 92, 255, .1));
    box-shadow: inset -3px 0 0 var(--sidebar-accent);
}

/* ---- Content area ---- */
.dashboard-content {
    margin-left: var(--sidebar-width);
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    transition: margin .2s ease-in-out;
}

html[dir="rtl"] .dashboard-content {
    margin-left: 0;
    margin-right: var(--sidebar-width);
}

/* Collapsed state - toggled by the sidebar's own toggle button (dashboard.js:
   toggleSidebar()). Shrinks the sidebar to an icon-only rail rather than hiding it
   entirely, so navigation is always reachable without re-opening it first. Works the same
   way at any screen size; JS also defaults it on for narrow screens on load. Declared after
   the base/RTL content-margin rules above so it wins the tie on specificity
   (html[dir="rtl"] .dashboard-content and body.sidebar-collapsed .dashboard-content are
   equally specific - source order is the tiebreaker). */
body.sidebar-collapsed .dashboard-sidebar {
    width: var(--sidebar-collapsed-width);
}

body.sidebar-collapsed .dashboard-content {
    margin-left: var(--sidebar-collapsed-width);
}

html[dir="rtl"] body.sidebar-collapsed .dashboard-content {
    margin-left: 0;
    margin-right: var(--sidebar-collapsed-width);
}

.dashboard-topbar {
    height: var(--topbar-height);
    background-color: var(--topbar-bg);
    box-shadow: 0 1px 3px rgba(16, 24, 40, .06);
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 1.5rem;
    position: sticky;
    top: 0;
    z-index: 1020;
}

.dashboard-main {
    padding: 1.5rem;
    flex: 1;
}

.page-title {
    font-weight: 600;
    margin-bottom: 1.25rem;
}

/* ---- Topbar icon buttons (hamburger, language switch, profile) ---- */
.icon-btn {
    position: relative;
    width: 38px;
    height: 38px;
    border-radius: 50%;
    border: none;
    background-color: var(--icon-btn-bg);
    color: var(--icon-btn-color);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 1.15rem;
    transition: background-color .15s ease-in-out, color .15s ease-in-out;
}

.icon-btn:hover {
    background-color: var(--icon-btn-bg-hover);
    color: var(--icon-btn-color-hover);
    transform: scale(1.08);
}

.icon-btn .icon-btn-badge {
    position: absolute;
    bottom: -2px;
    inset-inline-end: -4px;
    background-color: var(--sidebar-accent);
    color: #fff;
    font-size: .55rem;
    font-weight: 700;
    line-height: 1;
    padding: 2px 4px;
    border-radius: 999px;
    border: 2px solid var(--icon-btn-bg);
}

/* ---- Data tables (mobile-first convention - use for every list/Index view) ----
   Bootstrap's plain .table-responsive (horizontal scroll) leaves two problems on a phone:
   the row's identifying column scrolls away with everything else, so you lose track of
   which row you're looking at, and there's no visual hint that there's more to scroll to.
   Add .table-responsive-frozen alongside .table-responsive on the wrapper div to fix both -
   no per-cell markup needed, it targets :first-child automatically. */
.table-responsive-frozen {
    position: relative;
}

.table-responsive-frozen table th:first-child,
.table-responsive-frozen table td:first-child {
    position: sticky;
    inset-inline-start: 0;
    /* Matches the card these tables always sit inside, not a hardcoded white - Bootstrap's own
       dark-mode-aware surface variable, so the frozen column blends in correctly either theme.
       color set explicitly too, not left to inherit - the header cell inherits from .table-light
       (--bs-table-color), and without this it'd inherit that fixed-light color even after the
       [data-bs-theme="dark"] .table-light override above repaints it, since this rule's
       background-color (higher specificity, :first-child) already wins over that one's - color
       needs the same explicit treatment or it's left stranded on the old value. */
    background-color: var(--bs-card-bg);
    color: var(--bs-body-color);
    z-index: 1;
}

.table-responsive-frozen table thead th:first-child {
    background-color: var(--bs-tertiary-bg); /* matches Bootstrap's table-light thead, either theme */
}

.table-responsive-frozen table th {
    white-space: nowrap;
}

/* Fade hinting there's more to scroll to - inset-inline-end so it's on the correct side in RTL. */
.table-responsive-frozen::after {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    inset-inline-end: 0;
    width: 24px;
    background: linear-gradient(to var(--fade-direction, right), transparent, var(--scroll-fade-color));
    pointer-events: none;
}

html[dir="rtl"] .table-responsive-frozen {
    --fade-direction: left;
}

/* Long free-text columns (file paths, etc.) - truncate instead of wrapping, which used to
   blow up row height. Pair with a title="" attribute on the cell for the full value. */
.text-truncate-cell {
    max-width: 260px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ---- Dashboard home (KPI cards + charts) ---- */
/* Each card sets --stat-color/--stat-color-rgb inline (style="--stat-color:#16a34a;
   --stat-color-rgb:22,163,74") - one pair of variables drives the icon badge, the accent bar,
   and the value color, so a card's "identity color" only needs to be declared once. */
.stat-card {
    position: relative;
    overflow: hidden;
    transition: transform var(--transition-fast), box-shadow var(--transition-fast);
}

.stat-card:hover {
    transform: translateY(-3px);
    box-shadow: 0 .75rem 1.5rem rgba(16, 24, 40, .1) !important;
}

.stat-card::before {
    content: "";
    position: absolute;
    inset-inline-start: 0;
    top: 0;
    bottom: 0;
    width: 4px;
    background: var(--stat-color, var(--sidebar-accent));
}

.stat-icon {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: rgba(var(--stat-color-rgb, 79, 124, 255), .13);
    color: var(--stat-color, var(--sidebar-accent));
    font-size: 1.1rem;
    margin-bottom: .65rem;
}

.stat-card .label {
    font-size: .78rem;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--bs-secondary-color);
    margin-bottom: .35rem;
}

.stat-card .value {
    font-size: 1.5rem;
    font-weight: 700;
    line-height: 1.1;
}

.chart-panel-title {
    font-size: .95rem;
    font-weight: 700;
    margin-bottom: .75rem;
    display: flex;
    align-items: center;
    gap: .5rem;
}

.chart-panel-title i {
    color: var(--sidebar-accent);
    font-size: 1rem;
}

/* Chart/table panels get a lighter hover lift than stat cards - noticeable without fighting
   mouse movement while reading a wide table or a chart's own hover tooltips. */
.panel-card {
    transition: box-shadow var(--transition-fast);
}

.panel-card:hover {
    box-shadow: 0 .5rem 1.25rem rgba(16, 24, 40, .08) !important;
}

.top-list-table {
    width: 100%;
    font-size: .85rem;
}

.top-list-table td {
    padding: .4rem .25rem;
    border-bottom: 1px solid var(--divider-color);
}

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

.top-list-table td:first-child {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 1px; /* forces the ellipsis to respect the table's fixed layout */
}

.top-list-table {
    table-layout: fixed;
}

.top-list-table td:last-child {
    text-align: end;
    color: var(--bs-secondary-color);
    width: 60px;
    white-space: nowrap;
}

/* ---- Ranked list with inline percentage bars (Top OS panel) - a plain list instead of a chart,
   deliberately different from the bar charts used for Browsers/Countries so the "top entity"
   panels aren't all the same visual three times over; scales cleanly to any category count. ---- */
.ranked-list-row {
    display: flex;
    align-items: center;
    gap: .6rem;
    padding: .45rem 0;
    font-size: .85rem;
}

.ranked-list-row + .ranked-list-row {
    border-top: 1px solid var(--divider-color);
}

.ranked-list-label {
    flex: 0 0 34%;
    display: flex;
    align-items: center;
    gap: .4rem;
    overflow: hidden;
}

.ranked-list-label-text {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ranked-list-icon {
    flex: 0 0 auto;
    width: 14px;
    height: 14px;
    font-size: .85rem;
    object-fit: contain;
    color: var(--bs-secondary-color);
}

/* The OS logos (Apple/Android/Linux/Ubuntu) are plain black-fill SVGs, not currentColor-aware -
   they'd be invisible against a dark card. Only targets <img> icons, not the Windows <i> glyph
   above (which already re-colors correctly via `color`/--bs-secondary-color on its own). */
[data-bs-theme="dark"] img.ranked-list-icon {
    filter: invert(1);
}

.ranked-list-bar-track {
    flex: 1 1 auto;
    height: .5rem;
    border-radius: 1rem;
    background: var(--track-bg);
    overflow: hidden;
}

.ranked-list-bar-fill {
    height: 100%;
    border-radius: 1rem;
    background: linear-gradient(90deg, var(--sidebar-accent), #8b5cf6);
}

.ranked-list-value {
    flex: 0 0 auto;
    min-width: 78px;
    text-align: end;
    color: var(--bs-secondary-color);
    white-space: nowrap;
}

/* ---- Countries world map (D3 + TopoJSON) ---- */
#chartCountriesMap {
    position: relative;
}

.map-country {
    stroke: #fff;
    stroke-width: .5;
    transition: opacity .1s ease-in-out;
}

/* A white stroke reads as a subtle gap against a light card; against a dark one it would look
   like a bright grid overlay instead. Match the card behind it so countries still separate
   cleanly without shouting - the fill colors themselves are re-tuned for dark mode separately,
   in mapColorScale()/mapNoDataColor() (dashboard-home.js), not here. */
[data-bs-theme="dark"] .map-country {
    stroke: var(--bs-card-bg);
}

.map-country:hover {
    opacity: .8;
    cursor: pointer;
}

.map-legend {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 8px;
    /* Locked to LTR regardless of page language - the gradient bar itself is always built
       light(low)-to-dark(high) left-to-right (see updateMapLegend()'s `to right` gradient,
       which is a literal physical direction, not direction-relative), so without this the
       flex container's RTL item-reversal would swap the "0"/max labels to the wrong ends of
       the bar while the gradient stayed put. Same "real data shouldn't mirror for RTL"
       reasoning already applied to the map itself. */
    direction: ltr;
}

.map-legend-bar {
    flex: 1;
    height: 10px;
    border-radius: 5px;
}

.map-legend-label {
    font-size: .75rem;
    color: var(--bs-secondary-color);
    flex-shrink: 0;
}

.map-tooltip {
    position: absolute;
    z-index: 10;
    pointer-events: none;
    background-color: #1e2530;
    color: #fff;
    font-size: .8rem;
    padding: 4px 10px;
    border-radius: 6px;
    white-space: nowrap;
}

/* ---- Footer ---- */
.dashboard-footer {
    text-align: center;
    padding: 1rem 1.5rem;
    font-size: .8rem;
    color: var(--bs-secondary-color);
}

/* ---- Auth pages (no sidebar) ---- */
.auth-page {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    background:
        radial-gradient(circle at 15% 20%, rgba(79, 124, 255, .10), transparent 40%),
        radial-gradient(circle at 85% 80%, rgba(124, 92, 255, .10), transparent 40%),
        var(--content-bg);
}

.auth-card {
    width: 100%;
    max-width: 380px;
    position: relative;
    animation: fadeInUp .4s ease-out both;
}

.auth-card .card {
    border-top: 3px solid var(--sidebar-accent) !important;
}

/* Sits on the credentials card itself (top corner) rather than floating on the page, so
   it's right there next to the fields instead of off in a page corner. */
.auth-lang-switch {
    position: absolute;
    top: .75rem;
    inset-inline-end: .75rem;
    z-index: 1;
}

/* ---- Create/Edit form cards (Sites, Users, Settings, ...) ----
   Was a bare `.card` pinned to a fixed pixel max-width with no header styling - read as a
   small square stranded in the corner of an otherwise empty page. Wrap the card in
   `.form-card-wrap` (a centered, responsive-width column) and give the card itself a colored
   icon + title header, matching the accent-stripe treatment already used on the login card. */
.form-card-wrap {
    max-width: 640px;
    margin-inline: auto;
}

.form-card {
    border-top: 3px solid var(--sidebar-accent) !important;
}

.form-card-header {
    display: flex;
    align-items: center;
    gap: .9rem;
    margin-bottom: 1.5rem;
}

.form-card-icon {
    width: 48px;
    height: 48px;
    border-radius: 12px;
    background: linear-gradient(135deg, var(--sidebar-accent), var(--sidebar-accent-end));
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.35rem;
    flex-shrink: 0;
}

.form-card-header h5 {
    margin-bottom: 0;
    font-weight: 700;
}

.form-card-header p {
    margin-bottom: 0;
}

/* Icon prefix on text inputs (input-group + input-group-text) - plain Bootstrap component,
   no custom border/RTL logic needed (Bootstrap's own RTL stylesheet already handles side
   flipping for input-group correctly) - sits beside the input rather than inside the <label>
   so it can't interfere with asp-for's auto-generated (and localized) label text. */
.form-card .input-group-text {
    background-color: var(--bs-tertiary-bg);
    color: var(--sidebar-accent);
    width: 42px;
    justify-content: center;
}

/* ---- Select2 (select2-bootstrap-5-theme) accent-color overrides ----
   The bootstrap-5 theme ships with Bootstrap's own default blue (#0d6efd/#86b7fe) hardcoded,
   not a CSS variable - these rules just repaint the same states (focus ring, dropdown border,
   selected option) with this app's actual accent color instead, so Select2 doesn't look like a
   slightly-different shade of blue from every other focused input/button in the app. */
.select2-container--bootstrap-5 .select2-selection:focus,
.select2-container--bootstrap-5.select2-container--focus .select2-selection,
.select2-container--bootstrap-5.select2-container--open .select2-selection {
    border-color: var(--sidebar-accent) !important;
    box-shadow: 0 0 0 .25rem rgba(79, 124, 255, .25) !important;
}

.select2-container--bootstrap-5 .select2-dropdown {
    border-color: var(--sidebar-accent) !important;
}

.select2-container--bootstrap-5 .select2-search__field:focus {
    border-color: var(--sidebar-accent) !important;
    box-shadow: 0 0 0 .25rem rgba(79, 124, 255, .25) !important;
}

/* Keyboard/mouse-hovered option - a filled accent pill instead of the theme's neutral gray,
   consistent with the accent-colored active state used everywhere else (sidebar nav, buttons). */
.select2-container--bootstrap-5 .select2-results__option--highlighted[aria-selected] {
    background-color: var(--sidebar-accent) !important;
    color: #fff !important;
}

/* The already-selected option, shown when reopening the dropdown. */
.select2-container--bootstrap-5 .select2-results__option[aria-selected="true"]:not(.select2-results__option--highlighted) {
    background-color: rgba(79, 124, 255, .12) !important;
    color: var(--sidebar-accent) !important;
}

/* ---- Dark-mode overrides for vendored libraries with no data-bs-theme awareness of their own
   (Bootstrap's .table-light color variant, select2-bootstrap-5-theme, SweetAlert2) - see the
   dark-mode Phase 0-6 plan in CLAUDE.md; this is Phase 3. Each was inspected live in dark mode
   first (computed styles, not guessed) before writing these. ---- */

/* Bootstrap's .table-light/.table-dark variants are intentionally NOT theme-adaptive by
   Bootstrap's own design (fixed --bs-table-* custom properties regardless of data-bs-theme) -
   repaint those same properties to Bootstrap's own dark-aware tokens instead of fighting
   individual background-color/color declarations, so every cell that already inherits from
   --bs-table-bg/--bs-table-color (the mechanism Bootstrap's own table CSS uses) picks it up for
   free. Used for every DataTables header in the app (Home's site-comparison table, Sites, Users,
   LogEntries all use <thead class="table-light">). */
[data-bs-theme="dark"] .table-light {
    --bs-table-color: var(--bs-body-color);
    --bs-table-bg: var(--bs-tertiary-bg);
    --bs-table-border-color: var(--bs-border-color);
    --bs-table-striped-bg: var(--bs-tertiary-bg);
    --bs-table-striped-color: var(--bs-body-color);
    --bs-table-active-bg: var(--bs-secondary-bg);
    --bs-table-active-color: var(--bs-body-color);
    --bs-table-hover-bg: var(--bs-secondary-bg);
    --bs-table-hover-color: var(--bs-body-color);
}

/* select2-bootstrap-5-theme is a static compiled theme predating data-bs-theme entirely - it
   hardcodes light colors throughout. Separate from (and doesn't touch) the accent-color
   overrides above, which only repaint focus/selected states, not the base light/dark palette.
   Backgrounds deliberately match what native Bootstrap form-controls/dropdowns already look
   like in dark mode (checked live) - --bs-body-bg for the input-like surfaces (selection box,
   search field), --bs-tertiary-bg for the popup panel, matching the standard "popup sits one
   shade above the page" convention used elsewhere in this app too. */
[data-bs-theme="dark"] .select2-container--bootstrap-5 .select2-selection {
    background-color: var(--bs-body-bg);
    color: var(--bs-body-color);
}

/* The vendored theme hardcodes .select2-selection__rendered's own color to #212529 (Bootstrap's
   light-mode body text) - a child element's own color rule always wins over the parent's, so the
   .select2-selection override above alone never reaches the visible text. #212529 also happens
   to exactly equal --bs-body-bg's dark-mode value, so the selected option's text was rendering
   the same color as its own background - invisible, not just mis-colored. */
[data-bs-theme="dark"] .select2-container--bootstrap-5 .select2-selection__rendered {
    color: var(--bs-body-color);
}

[data-bs-theme="dark"] .select2-container--bootstrap-5 .select2-selection__placeholder {
    color: var(--bs-secondary-color);
}

[data-bs-theme="dark"] .select2-container--bootstrap-5 .select2-dropdown {
    background-color: var(--bs-tertiary-bg);
    color: var(--bs-body-color);
}

[data-bs-theme="dark"] .select2-container--bootstrap-5 .select2-search__field {
    background-color: var(--bs-body-bg);
    color: var(--bs-body-color);
}

[data-bs-theme="dark"] .select2-container--bootstrap-5 .select2-results__option {
    color: var(--bs-body-color);
}

/* SweetAlert2 ships one fixed light theme - covers both the confirm/delete dialogs
   (confirmAndSubmit) and the toast variant (showFlashToast), since both share .swal2-popup. */
[data-bs-theme="dark"] .swal2-popup {
    background-color: var(--bs-tertiary-bg);
    color: var(--bs-body-color);
}

[data-bs-theme="dark"] .swal2-title,
[data-bs-theme="dark"] .swal2-html-container {
    color: var(--bs-body-color);
}
