/* ===================================================================
   ระบบขายรถมือสอง — Custom styles layered on top of Bootstrap 5.3
   Theme is driven by [data-theme="light"|"dark"] on <html>, kept in
   sync with Bootstrap's own [data-bs-theme] attribute by app.js.
   =================================================================== */

:root {
    --sidebar-width: 240px;
    --sidebar-collapsed-width: 64px;
    --navbar-height: 56px;
    /* Overridden per-request by theme_color_css() (includes/functions.php) from the saved
       "Theme Color" setting — these are just the fallback/default values. */
    --theme-color: #2563eb;
    --theme-color-light: #3b82f6;
    --theme-color-rgb: 37, 99, 235;
}

:root[data-theme="light"] {
    --app-bg: #f1f5f9;
    --card-bg: #ffffff;
    --border-color: #e2e8f0;
    --text-muted: #64748b;
    --sidebar-bg: #1e293b;
    --sidebar-text: #cbd5e1;
    --sidebar-text-active: #ffffff;
    --sidebar-active-bg: var(--theme-color);
    --navbar-bg: #ffffff;
    --shadow: 0 1px 3px rgba(15, 23, 42, 0.08);
}

:root[data-theme="dark"] {
    --app-bg: #0b1220;
    --card-bg: #131c2e;
    --border-color: #24304a;
    --text-muted: #94a3b8;
    --sidebar-bg: #0a0f1c;
    --sidebar-text: #94a3b8;
    --sidebar-text-active: #ffffff;
    --sidebar-active-bg: var(--theme-color);
    --navbar-bg: #131c2e;
    --shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
}

body {
    background-color: var(--app-bg);
    color-scheme: light;
}
:root[data-theme="dark"] body {
    color-scheme: dark;
}

/* ---------------- Login page ---------------- */
.login-body {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(135deg, #1e293b 0%, var(--theme-color) 100%);
}
.login-wrapper { width: 100%; max-width: 400px; padding: 16px; }
.login-card { border: none; border-radius: 16px; }

/* ---------------- Top navbar ---------------- */
.app-navbar {
    height: var(--navbar-height);
    background-color: var(--navbar-bg);
    border-bottom: 1px solid var(--border-color);
    box-shadow: var(--shadow);
    position: sticky;
    top: 0;
    z-index: 1030;
}

/* ---------------- Floating scroll-to-top/bottom buttons (car edit form — the page has
   a lot of stacked cards/sections, see assets/js/car-form.js) ---------------- */
.car-form-float-nav {
    position: fixed;
    right: 20px;
    bottom: 24px;
    z-index: 1020;
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.car-form-float-nav .btn {
    width: 46px;
    height: 46px;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: var(--shadow);
}

/* ---------------- Sticky license-plate indicator (car form, shown once the page
   heading scrolls out of view — see assets/js/car-form.js) ---------------- */
.scroll-plate-alert {
    position: fixed;
    top: var(--navbar-height);
    left: 50%;
    transform: translateX(-50%);
    z-index: 1025;
    background: var(--theme-color);
    color: #fff;
    padding: 6px 20px;
    border-radius: 0 0 10px 10px;
    box-shadow: var(--shadow);
    font-weight: 600;
    font-size: 0.9rem;
}

/* ---------------- Layout ---------------- */
.app-layout {
    display: flex;
    min-height: calc(100vh - var(--navbar-height));
}

.app-sidebar {
    width: var(--sidebar-width);
    flex-shrink: 0;
    background-color: var(--sidebar-bg);
    border-right: 1px solid var(--border-color);
    position: sticky;
    top: var(--navbar-height);
    height: calc(100vh - var(--navbar-height));
    overflow-y: auto;
    transition: transform 0.2s ease;
}

.sidebar-link {
    color: var(--sidebar-text) !important;
    border-radius: 8px;
    padding: 10px 14px;
    margin-bottom: 2px;
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 0.925rem;
}
.sidebar-link i { font-size: 1.05rem; width: 20px; text-align: center; }
.sidebar-link:hover { background-color: rgba(255, 255, 255, 0.08); color: var(--sidebar-text-active) !important; }
.sidebar-link.active { background-color: var(--sidebar-active-bg); color: var(--sidebar-text-active) !important; }
.sidebar-divider { border-color: rgba(255, 255, 255, 0.1); margin: 10px 4px; }

.app-main {
    flex-grow: 1;
    padding: 24px;
    min-width: 0;
}

@media (max-width: 767.98px) {
    .app-sidebar {
        position: fixed;
        left: 0;
        transform: translateX(-100%);
        z-index: 1040;
        box-shadow: var(--shadow);
    }
    .app-sidebar.show { transform: translateX(0); }
    .app-main { padding: 16px; }
}

/* Icon-only sidebar mode, toggled by the navbar hamburger button on desktop and persisted
   in localStorage; the html[data-sidebar-collapsed] attribute is applied pre-paint (see
   includes/header.php) to avoid a layout flash on load. */
@media (min-width: 768px) {
    html[data-sidebar-collapsed="true"] .app-sidebar { width: var(--sidebar-collapsed-width); }
    html[data-sidebar-collapsed="true"] .sidebar-link { justify-content: center; padding: 10px 0; }
    html[data-sidebar-collapsed="true"] .sidebar-link i { width: auto; font-size: 1.2rem; }
    html[data-sidebar-collapsed="true"] .sidebar-link span { display: none; }
}

/* ---------------- Cards / widgets ---------------- */
.card {
    background-color: var(--card-bg);
    border-color: var(--border-color);
}

.kpi-card { border-radius: 14px; border: 1px solid var(--border-color); }
.kpi-icon {
    width: 48px; height: 48px; border-radius: 12px;
    display: flex; align-items: center; justify-content: center;
    font-size: 1.4rem;
}
.kpi-value { font-size: 1.6rem; font-weight: 700; }
.kpi-label { color: var(--text-muted); font-size: 0.85rem; }

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

.settings-hub-card { transition: transform 0.15s ease, box-shadow 0.15s ease; }
.settings-hub-card:hover { transform: translateY(-2px); box-shadow: 0 6px 16px rgba(15, 23, 42, 0.12); border-color: var(--sidebar-active-bg); }

/* ---------------- Simple CSS bar charts (no chart library) ---------------- */
.bar-chart { display: flex; align-items: flex-end; gap: 10px; height: 200px; padding-top: 10px; }
.bar-chart-col { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; height: 100%; }
.bar-chart-bar {
    width: 100%;
    max-width: 42px;
    background: linear-gradient(180deg, var(--theme-color-light), var(--theme-color));
    border-radius: 6px 6px 0 0;
    min-height: 2px;
    transition: height 0.3s ease;
}
.bar-chart-label { font-size: 0.75rem; color: var(--text-muted); margin-top: 6px; text-align: center; }
.bar-chart-value { font-size: 0.72rem; color: var(--text-muted); margin-bottom: 2px; }

/* ---------------- Grouped revenue/profit comparison bars (dashboard trend) ---------------- */
.bar-chart-legend { display: flex; gap: 18px; margin-bottom: 10px; font-size: 0.8rem; color: var(--text-muted); }
.bar-chart-legend-item { display: flex; align-items: center; gap: 6px; }
.bar-chart-legend-swatch { width: 12px; height: 12px; border-radius: 3px; display: inline-block; }
.bar-chart-bar-pair { display: flex; align-items: flex-end; gap: 4px; height: 100%; }
.bar-chart-bar-pair .bar-chart-bar { width: 22px; max-width: 22px; background: none; border-radius: 4px 4px 0 0; }
.bar-chart-pair-values { display: flex; flex-direction: column; align-items: center; gap: 1px; margin-bottom: 2px; }
.bar-chart-pair-values span { font-size: 0.62rem; line-height: 1.1; color: var(--text-muted); }

.hbar-row { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.hbar-label { width: 130px; font-size: 0.85rem; flex-shrink: 0; }
.hbar-track { flex-grow: 1; background: var(--app-bg); border-radius: 6px; height: 18px; overflow: hidden; }
.hbar-fill { height: 100%; background: linear-gradient(90deg, var(--theme-color), var(--theme-color-light)); border-radius: 6px; }
.hbar-value { width: 50px; text-align: right; font-size: 0.8rem; color: var(--text-muted); }

/* ---------------- Simple CSS/SVG line chart (dashboard 12-month sales trend) ---------------- */
.line-chart-wrap { width: 100%; }
.line-chart-svg { width: 100%; height: 200px; display: block; overflow: visible; }
.line-chart-line { fill: none; stroke: var(--theme-color); stroke-width: 2; vector-effect: non-scaling-stroke; }
.line-chart-area { fill: rgba(var(--theme-color-rgb), 0.08); stroke: none; }
.line-chart-point { fill: var(--theme-color); stroke: var(--card-bg); stroke-width: 1.5; }
.line-chart-labels { display: flex; margin-top: 6px; }
.line-chart-labels span { flex: 1; font-size: 0.72rem; color: var(--text-muted); text-align: center; }

/* ---------------- Per-branch mini trend rows (dashboard "all branches" comparison) ---------------- */
.branch-trend-row { display: flex; align-items: center; gap: 14px; padding: 10px 0; border-bottom: 1px solid var(--app-bg); }
.branch-trend-row:last-child { border-bottom: none; }
.branch-trend-label { width: 140px; flex-shrink: 0; font-size: 0.85rem; font-weight: 600; }
.branch-trend-label .branch-trend-total { display: block; font-weight: 400; font-size: 0.75rem; color: var(--text-muted); }
.bar-chart-sm { height: 70px; flex-grow: 1; gap: 6px; }
.bar-chart-sm .bar-chart-bar { max-width: 28px; }
.bar-chart-sm .bar-chart-value { font-size: 0.65rem; }
.bar-chart-sm .bar-chart-label { font-size: 0.68rem; }

/* ---------------- Car image upload preview ---------------- */
.img-upload-preview { width: 90px; height: 68px; object-fit: cover; border-radius: 8px; border: 1px solid var(--border-color); position: relative; }

/* ---------------- Car video upload preview ---------------- */
.video-upload-preview { width: 90px; height: 68px; position: relative; }
.video-upload-preview video { width: 100%; height: 100%; object-fit: cover; border-radius: 8px; border: 1px solid var(--border-color); background: #000; cursor: pointer; }
.video-upload-preview .video-play-icon { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: #fff; font-size: 1.4rem; text-shadow: 0 0 4px rgba(0,0,0,.7); pointer-events: none; }

/* ---------------- Car list cover thumbnail (click to open gallery) ---------------- */
.car-thumb-sm { width: 72px; height: 56px; object-fit: cover; border-radius: 4px; border: 1px solid var(--border-color); cursor: pointer; }
.car-thumb-sm-placeholder { width: 72px; height: 56px; border-radius: 4px; cursor: pointer; }
#carImageCarouselInner img { width: 100%; max-height: 480px; object-fit: contain; background: var(--app-bg); }
/* carImageModal's fullscreen toggle (assets/js/cars.js's setGalleryFullscreen()) swaps
   #carImageModalDialog's size class between modal-lg and modal-fullscreen at runtime — the
   480px cap above is right for the small modal but leaves the photo tiny once the dialog
   itself fills the screen. Scoped to .modal-fullscreen only, reusing the same flex-grow +
   position:absolute/inset:0 technique as #carImagesCarousel below (proven cross-browser,
   including mobile Safari's percentage-height-through-flex-item quirk — see that rule's own
   comment) instead of a taller fixed max-height, so the image always fills the available
   space regardless of viewport size. */
#carImageModalDialog.modal-fullscreen .modal-content { display: flex; flex-direction: column; }
#carImageModalDialog.modal-fullscreen .modal-body { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }
#carImageModalDialog.modal-fullscreen #carImageCarousel { flex: 1 1 auto; min-height: 0; position: relative; }
#carImageModalDialog.modal-fullscreen #carImageCarouselInner { position: absolute; inset: 0; }
#carImageModalDialog.modal-fullscreen #carImageCarouselInner .carousel-item { position: absolute; inset: 0; }
#carImageModalDialog.modal-fullscreen #carImageCarouselInner img { width: 100%; height: 100%; max-height: none; object-fit: contain; }
/* "แสดงภาพ" before/after chooser modal (modules/cars/index.php's carImagesModal) — missed
   when that modal was added, so its <img> had no size constraint and could overflow past
   the modal's edges (worst on narrow/mobile viewports, where the modal itself is much
   narrower than a native-resolution photo). The modal is modal-fullscreen.
   Two iterations that both failed on an actual phone despite looking correct in markup
   checks: (1) max-height:calc(100vh - Npx) — mobile Safari's dynamic address-bar chrome
   shrinks the real visible viewport without shrinking the 100vh CSS value. (2) chaining
   height:100% down through #carImagesCarousel (a flex ITEM, not itself a flex container) to
   #carImagesCarouselInner/.carousel-item — (mobile) Safari is long known to be inconsistent
   resolving percentage heights through a flex-item-but-non-flex ancestor, even when
   Chrome/Firefox render the exact same CSS fine.
   Fixed by avoiding percentage-height inheritance entirely below the flex chain: once
   #carImagesCarousel gets a real height from flex-grow (robust everywhere, incl. Safari —
   this part was never the problem), everything under it is pinned via position:absolute +
   inset:0 against its immediately-positioned ancestor (Bootstrap's own .carousel/
   .carousel-inner are already position:relative) — a single-hop, non-percentage
   relationship with far more consistent cross-browser support than multi-level
   percentage-height cascading. */
/* Bootstrap's .modal-dialog-scrollable relies on .modal-content being a flex column so
   .modal-body can scroll independently while header/footer stay put — but several modals in
   this app wrap header/body/footer in a single <form> (for a full-form submit), and a <form>
   defaults to display:block, which breaks that flex chain. Without this, .modal-body's
   overflow-y:auto has no effect because its parent never gets a bounded height. */
.modal-dialog-scrollable .modal-content > form { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; overflow: hidden; }
.modal-dialog-scrollable .modal-content > form > .modal-body { min-height: 0; }

#carImagesModal .modal-content { display: flex; flex-direction: column; }
#carImagesModal .modal-body { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }
#carImagesViewer { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
#carImagesCarousel { flex: 1 1 auto; min-height: 0; position: relative; }
#carImagesCarouselInner { position: absolute; inset: 0; }
#carImagesCarouselInner .carousel-item { position: absolute; inset: 0; }
#carImagesCarouselInner img, #carImagesCarouselInner video { width: 100%; height: 100%; object-fit: contain; background: var(--app-bg); }

/* No `overflow: hidden` here on purpose — it used to clip any dropdown-menu that opened near
   the top/bottom edge of a short table (especially the last couple of rows). Corners are
   rounded per-cell instead so the card still looks rounded without clipping child content. */
.table-responsive-card { background: var(--card-bg); border: 1px solid var(--border-color); border-radius: 12px; }
.table-responsive-card > table { margin-bottom: 0; }
.table-responsive-card > table > thead > tr:first-child > th:first-child { border-top-left-radius: 11px; }
.table-responsive-card > table > thead > tr:first-child > th:last-child { border-top-right-radius: 11px; }
.table-responsive-card > table > tbody > tr:last-child > td:first-child { border-bottom-left-radius: 11px; }
.table-responsive-card > table > tbody > tr:last-child > td:last-child { border-bottom-right-radius: 11px; }

/* ---------------- Mobile card view (replaces the table below the md breakpoint) ---------------- */
.mobile-card-list { display: flex; flex-direction: column; gap: 10px; }
.mobile-card {
    background: var(--card-bg);
    border: 1px solid var(--border-color);
    border-radius: 12px;
    padding: 12px;
}
.mobile-card-facts { display: grid; grid-template-columns: 1fr 1fr; gap: 4px 10px; font-size: 0.85rem; }
.mobile-card-facts .label { color: var(--text-muted); }
.mobile-card-actions { display: flex; gap: 8px; justify-content: flex-end; flex-wrap: wrap; }

/* ---------------- Car full detail report (shared by print window + PDF rasterization) ----------------
   Kept as real classes (not an inline <style> string) so car-full-report-pdf.js can render
   this markup into a plain, attached DOM node and have html2canvas compute correct styles
   from it — jsPDF's built-in fonts can't draw Thai glyphs, so the report text always has to
   be rendered by the browser first. */
.car-report-print { font-family: "Tahoma", "Leelawadee UI", sans-serif; font-size: 12.5px; color: #000; background: #fff; }
.car-report-print .doc-header { display: flex; justify-content: space-between; align-items: flex-start; border-bottom: 2px solid #333; padding-bottom: 10px; margin-bottom: 14px; }
.car-report-print .doc-header h1 { font-size: 19px; margin: 0 0 4px 0; }
.car-report-print .doc-header .company-name { font-size: 14px; font-weight: bold; margin: 0 0 2px 0; }
.car-report-print .doc-header .meta { font-size: 11.5px; color: #444; }
.car-report-print .doc-header img { width: 120px; height: 90px; object-fit: cover; border: 1px solid #999; border-radius: 4px; }
.car-report-print h3 { font-size: 13px; margin: 16px 0 6px 0; border-bottom: 1px solid #999; padding-bottom: 3px; }
.car-report-print table.kv { width: 100%; border-collapse: collapse; }
.car-report-print table.kv th { width: 22%; background: #f0f0f0; font-weight: normal; text-align: left; border: 1px solid #999; padding: 5px 7px; }
.car-report-print table.kv td { width: 28%; border: 1px solid #999; padding: 5px 7px; }
.car-report-print table.itemized { width: 100%; border-collapse: collapse; }
.car-report-print table.itemized th, .car-report-print table.itemized td { border: 1px solid #999; padding: 5px 7px; text-align: left; }
.car-report-print table.itemized th { background: #f0f0f0; }
.car-report-print table.itemized tfoot td { background: #f7f7f7; }
.car-report-print .text-end { text-align: right; }
.car-report-print .text-muted { color: #666; }

/* ---------------- Car SKB label, แบบที่ 2 (branded A4-landscape ฉลากรถยนต์ใช้แล้ว) ----------------
   Shared by the print window (car-skb2-print.js, which duplicates this as an inline <style>
   string the same way car-full-report-print.js does for .car-report-print above — a print
   window is a separate document and can't reach this stylesheet) and the PDF download
   (car-skb2-pdf.js), which renders this markup into a plain attached DOM node for
   html2canvas — jsPDF's built-in fonts can't draw Thai glyphs, so the label is always
   rendered by the browser first, same reasoning as the full report. Keep both copies of
   this CSS in sync if the layout ever changes. */
.skb2-label { font-family: "Tahoma", "Leelawadee UI", sans-serif; font-size: 13px; color: #000; background: #fff; border: 3px solid #1565C0; border-radius: 10px; overflow: hidden; }
.skb2-label .skb2-header { background: linear-gradient(135deg, #1E88E5, #0D47A1); color: #fff; display: flex; align-items: center; gap: 16px; padding: 10px 20px; }
.skb2-label .skb2-header img { height: 60px; }
.skb2-label .skb2-header h1 { flex: 1; text-align: center; font-size: 30px; margin: 0; letter-spacing: 1px; }
.skb2-label .skb2-body { padding: 14px 20px; }
.skb2-label .skb2-row { display: flex; gap: 10px; margin-bottom: 8px; }
.skb2-label .skb2-field { flex: 1; display: flex; align-items: center; gap: 6px; }
.skb2-label .skb2-field.full { flex: 0 0 100%; }
.skb2-label .skb2-field label { font-weight: bold; color: #0D47A1; white-space: nowrap; }
.skb2-label .skb2-field .skb2-value { flex: 1; background: #FCEFDD; border: 1px solid #e0c9a6; border-radius: 4px; padding: 4px 10px; font-weight: bold; min-height: 1.4em; }
.skb2-label hr.skb2-divider { border: none; border-top: 2px solid #1565C0; margin: 10px 0; }
.skb2-label .skb2-warning { text-align: center; font-weight: bold; color: #D32F2F; font-size: 15px; padding: 8px; border-top: 2px solid #1565C0; border-bottom: 2px solid #1565C0; }
.skb2-label .skb2-footer { display: flex; gap: 16px; padding: 12px 20px 16px; }
.skb2-label .skb2-footer-left { flex: 0 0 40%; }
.skb2-label .skb2-price-label { font-weight: bold; color: #0D47A1; }
.skb2-label .skb2-price-value { font-size: 26px; font-weight: bold; color: #0D47A1; background: #FCEFDD; border: 1px solid #e0c9a6; border-radius: 4px; padding: 6px 10px; margin: 4px 0 10px; }
.skb2-label .skb2-dealer-value { background: #FCEFDD; border: 1px solid #e0c9a6; border-radius: 4px; padding: 6px 10px; font-weight: bold; font-size: 12px; }
.skb2-label .skb2-footer-right { flex: 1; }
.skb2-label .skb2-footer-right .skb2-field { margin-bottom: 8px; }
/* EV variant (car-skb-ev-print.js) reuses all of the above .skb2-label rules as-is,
   plus these two footer-left tweaks (battery-warranty field sits above the dealer box
   there, instead of the price box แบบที่ 2 has) — keep in sync with that file's inline
   <style> copy the same way as everything else on this page. */
.skb2-label .skb2-footer-left .skb2-field { margin-bottom: 10px; }
.skb2-label .skb2-dealer-value { margin-top: 4px; }

/* "หนังสือสัญญา" (สัญญาซื้อขายรถยนต์) — used-car-contract-print.js builds this markup for
   both print and the PDF download (used-car-contract-pdf.js, same html2canvas + jsPDF
   technique as the SKB labels above — jsPDF's built-in fonts can't draw Thai glyphs).
   Deliberately plain (black text on white, dotted-underline blanks) to match the source
   legal-template PDF's own look, unlike the branded SKB label. */
.ucc-page { position: relative; font-family: "Tahoma", "Leelawadee UI", sans-serif; font-size: 14px; line-height: 1.7; color: #000; background: #fff; padding: 30px 35px; }
.ucc-title { text-align: center; font-size: 20px; font-weight: bold; margin: 0 0 14px; }
.ucc-contract-no { position: absolute; top: 12px; right: 20px; font-size: 13px; font-weight: bold; }
.ucc-line { margin: 0 0 6px; }
.ucc-bold { font-weight: bold; }
.ucc-underline-head { font-weight: bold; text-decoration: underline; }
.ucc-indent { padding-left: 20px; }
.ucc-indent2 { padding-left: 40px; }
.ucc-party-table { width: 100%; border-collapse: collapse; margin: 8px 0 14px; }
.ucc-party-table td { border: 1px solid #000; padding: 6px 10px; width: 50%; vertical-align: top; }
.ucc-party-head { font-weight: bold; }
.ucc-page .fill { display: inline-block; border-bottom: 1px dotted #000; min-height: 1.3em; padding: 0 4px; text-align: center; vertical-align: bottom; }
.ucc-page .fill-left { text-align: left; }
/* .ucc-line-flex marks a line whose LAST element is the one true blank on that row (nothing
   else trailing) — its .fill-grow span then stretches to consume all remaining row width
   instead of stopping at min-width, so the dotted leader runs all the way to the margin like
   the source template's own blanks do. Earlier .fill spans on the same flex line (without
   fill-grow) keep their normal min-width sizing since flex-grow defaults to 0. */
.ucc-page .ucc-line-flex { display: flex; flex-wrap: wrap; align-items: flex-end; }
.ucc-page .fill-grow { flex: 1 1 auto; }
.ucc-sign-table { width: 100%; border-collapse: collapse; margin-top: 34px; }
.ucc-sign-table td { text-align: center; padding: 4px 8px; }
.ucc-sign-role { padding-top: 4px; }
.ucc-sign-table-witness { margin-top: 22px; }

/* Global loading indicator — shown by app.js during any apiGet/apiPost call, and by
   table-tools.js while building a large print/Excel export, so any page that fetches or
   processes a lot of data gives visible feedback without every page having to wire it up. */
#globalLoadingBar {
    position: fixed;
    top: 0;
    left: 0;
    height: 3px;
    width: 100%;
    z-index: 2000;
    overflow: hidden;
    pointer-events: none;
    opacity: 0;
    transition: opacity .15s ease;
}
#globalLoadingBar.active { opacity: 1; }
#globalLoadingBar.active::before {
    content: '';
    display: block;
    height: 100%;
    width: 40%;
    background: var(--theme-color);
    animation: globalLoadingBarSlide 1s ease-in-out infinite;
}
@keyframes globalLoadingBarSlide {
    0% { margin-left: -40%; }
    100% { margin-left: 100%; }
}

/* ---------------- Theme color picker (modules/settings/general.php) ---------------- */
.theme-color-swatch {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    border: 2px solid transparent;
    cursor: pointer;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 0 0 1px var(--border-color) inset;
}
.theme-color-swatch.theme-swatch-active {
    border-color: var(--card-bg);
    box-shadow: 0 0 0 2px var(--card-bg), 0 0 0 4px var(--text-muted);
}
.theme-color-swatch-custom {
    background: conic-gradient(red, yellow, lime, cyan, blue, magenta, red);
    color: #fff;
    font-size: 1rem;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
}
