/* Design tokens ported from the Loadpad SC Portal (C:\Shared\Loadpad-SCPortal) so the two apps
   read as one product: Geist, an oklch slate/blue scale, 0.625rem radius, and a dark
   "surface strong" used for chrome (sidebar, auth brand panel) and emphasis.

   Bootstrap 5.3 drives almost everything off --bs-* custom properties, so the bulk of the
   restyle is remapping those onto the tokens below rather than rewriting page markup. The
   handful of component blocks further down exist because Bootstrap compiles per-variant
   colors (.btn-primary, .alert-danger, .table-warning...) to literal hex at build time —
   those can only be reached by redeclaring the variant's own variables. */

@font-face {
    font-family: 'Geist Variable';
    font-style: normal;
    font-display: swap;
    font-weight: 100 900;
    src: url('fonts/geist-latin.woff2') format('woff2-variations');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'Geist Variable';
    font-style: normal;
    font-display: swap;
    font-weight: 100 900;
    src: url('fonts/geist-latin-ext.woff2') format('woff2-variations');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
    --font-sans: 'Geist Variable', 'Segoe UI', system-ui, sans-serif;
    --radius: 0.625rem;

    --background: oklch(98.4% 0.003 247.858);
    --foreground: oklch(20.8% 0.042 265.755);
    --card: oklch(100% 0 0);
    --muted: oklch(96.8% 0.007 247.896);
    --muted-foreground: oklch(55.4% 0.046 257.417);
    --border: oklch(92.9% 0.013 255.508);
    --primary: oklch(55% 0.21 262);
    --primary-foreground: oklch(98.5% 0.005 255);
    --destructive: oklch(57.7% 0.245 27.325);
    --success: oklch(62% 0.15 150);
    --warning: oklch(66.6% 0.179 58.318);
    --info: oklch(62% 0.11 232);

    --surface-strong: oklch(26% 0.05 264);
    --surface-strong-accent: oklch(31% 0.065 264);
    --surface-strong-foreground: oklch(98.5% 0.005 255);

    --shadow-card: 0 1px 2px oklch(20.8% 0.042 265.755 / 0.06), 0 1px 3px oklch(20.8% 0.042 265.755 / 0.05);
    --shadow-pop: 0 10px 15px -3px oklch(20.8% 0.042 265.755 / 0.12), 0 4px 6px -4px oklch(20.8% 0.042 265.755 / 0.1);
}

/* ---- Bootstrap remap ------------------------------------------------- */

:root,
[data-bs-theme="light"] {
    --bs-body-font-family: var(--font-sans);
    --bs-body-font-size: 0.875rem;
    --bs-body-line-height: 1.5;
    --bs-body-bg: var(--background);
    --bs-body-color: var(--foreground);
    --bs-emphasis-color: var(--foreground);
    --bs-secondary-color: var(--muted-foreground);
    --bs-tertiary-color: var(--muted-foreground);
    --bs-secondary-bg: var(--muted);
    --bs-tertiary-bg: var(--muted);
    --bs-border-color: var(--border);
    --bs-border-color-translucent: var(--border);
    --bs-border-radius: var(--radius);
    --bs-border-radius-sm: 0.5rem;
    --bs-border-radius-lg: 0.875rem;
    --bs-link-color: var(--primary);
    --bs-link-hover-color: color-mix(in oklab, var(--primary), black 15%);
    --bs-heading-color: var(--foreground);
    --bs-code-color: var(--primary);
    --bs-focus-ring-color: color-mix(in oklab, var(--primary), transparent 75%);
}

body {
    background: var(--background);
    color: var(--foreground);
    -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, h5, h6 {
    font-weight: 600;
    letter-spacing: -0.02em;
}

h1 {
    font-size: 1.5rem;
    margin-bottom: 1.25rem;
}

h1:focus {
    outline: none;
}

h3 {
    font-size: 1.125rem;
}

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

.tabular, .num {
    font-variant-numeric: tabular-nums;
}

/* ---- Buttons ---------------------------------------------------------- */

/* Bootstrap hardcodes 1rem on .btn/.form-control/.form-select rather than deriving from
   --bs-body-font-size, so each has to be brought down to the portal's 14px scale by hand. */
.btn {
    --bs-btn-font-weight: 600;
    --bs-btn-font-size: 0.875rem;
    --bs-btn-padding-y: 0.5rem;
    --bs-btn-padding-x: 1rem;
    --bs-btn-focus-shadow-rgb: 60, 110, 240;
    white-space: nowrap;
}

.btn-sm {
    --bs-btn-padding-y: 0.4rem;
    --bs-btn-padding-x: 0.8rem;
    --bs-btn-font-size: 0.8125rem;
}

.btn-primary {
    --bs-btn-color: var(--primary-foreground);
    --bs-btn-bg: var(--primary);
    --bs-btn-border-color: var(--primary);
    --bs-btn-hover-color: var(--primary-foreground);
    --bs-btn-hover-bg: color-mix(in oklab, var(--primary), black 12%);
    --bs-btn-hover-border-color: color-mix(in oklab, var(--primary), black 12%);
    --bs-btn-active-color: var(--primary-foreground);
    --bs-btn-active-bg: color-mix(in oklab, var(--primary), black 20%);
    --bs-btn-active-border-color: color-mix(in oklab, var(--primary), black 20%);
    --bs-btn-disabled-color: var(--primary-foreground);
    --bs-btn-disabled-bg: var(--primary);
    --bs-btn-disabled-border-color: var(--primary);
}

.btn-secondary {
    --bs-btn-color: var(--foreground);
    --bs-btn-bg: var(--card);
    --bs-btn-border-color: var(--border);
    --bs-btn-hover-color: var(--foreground);
    --bs-btn-hover-bg: var(--muted);
    --bs-btn-hover-border-color: var(--border);
    --bs-btn-active-color: var(--foreground);
    --bs-btn-active-bg: var(--muted);
    --bs-btn-active-border-color: var(--border);
    --bs-btn-disabled-color: var(--muted-foreground);
    --bs-btn-disabled-bg: var(--card);
    --bs-btn-disabled-border-color: var(--border);
}

.btn-success {
    --bs-btn-color: var(--primary-foreground);
    --bs-btn-bg: var(--success);
    --bs-btn-border-color: var(--success);
    --bs-btn-hover-color: var(--primary-foreground);
    --bs-btn-hover-bg: color-mix(in oklab, var(--success), black 12%);
    --bs-btn-hover-border-color: color-mix(in oklab, var(--success), black 12%);
    --bs-btn-active-color: var(--primary-foreground);
    --bs-btn-active-bg: color-mix(in oklab, var(--success), black 20%);
    --bs-btn-active-border-color: color-mix(in oklab, var(--success), black 20%);
    --bs-btn-disabled-color: var(--primary-foreground);
    --bs-btn-disabled-bg: var(--success);
    --bs-btn-disabled-border-color: var(--success);
}

.btn-danger {
    --bs-btn-color: var(--primary-foreground);
    --bs-btn-bg: var(--destructive);
    --bs-btn-border-color: var(--destructive);
    --bs-btn-hover-color: var(--primary-foreground);
    --bs-btn-hover-bg: color-mix(in oklab, var(--destructive), black 12%);
    --bs-btn-hover-border-color: color-mix(in oklab, var(--destructive), black 12%);
    --bs-btn-active-color: var(--primary-foreground);
    --bs-btn-active-bg: color-mix(in oklab, var(--destructive), black 20%);
    --bs-btn-active-border-color: color-mix(in oklab, var(--destructive), black 20%);
    --bs-btn-disabled-color: var(--primary-foreground);
    --bs-btn-disabled-bg: var(--destructive);
    --bs-btn-disabled-border-color: var(--destructive);
}

.btn-outline-primary {
    --bs-btn-color: var(--primary);
    --bs-btn-border-color: var(--primary);
    --bs-btn-hover-color: var(--primary-foreground);
    --bs-btn-hover-bg: var(--primary);
    --bs-btn-hover-border-color: var(--primary);
    --bs-btn-active-color: var(--primary-foreground);
    --bs-btn-active-bg: var(--primary);
    --bs-btn-active-border-color: var(--primary);
    --bs-btn-disabled-color: color-mix(in oklab, var(--primary), transparent 45%);
    --bs-btn-disabled-border-color: color-mix(in oklab, var(--primary), transparent 60%);
}

/* Bootstrap's own outline-secondary is a mid grey on white; the portal's equivalent is a
   plain bordered "card" button whose label stays fully legible. */
.btn-outline-secondary {
    --bs-btn-color: var(--foreground);
    --bs-btn-border-color: var(--border);
    --bs-btn-hover-color: var(--foreground);
    --bs-btn-hover-bg: var(--muted);
    --bs-btn-hover-border-color: var(--border);
    --bs-btn-active-color: var(--foreground);
    --bs-btn-active-bg: var(--muted);
    --bs-btn-active-border-color: var(--border);
    --bs-btn-disabled-color: var(--muted-foreground);
    --bs-btn-disabled-border-color: var(--border);
}

.btn-outline-danger {
    --bs-btn-color: var(--destructive);
    --bs-btn-border-color: color-mix(in oklab, var(--destructive), transparent 65%);
    --bs-btn-hover-color: var(--primary-foreground);
    --bs-btn-hover-bg: var(--destructive);
    --bs-btn-hover-border-color: var(--destructive);
    --bs-btn-active-color: var(--primary-foreground);
    --bs-btn-active-bg: var(--destructive);
    --bs-btn-active-border-color: var(--destructive);
    --bs-btn-disabled-color: color-mix(in oklab, var(--destructive), transparent 45%);
    --bs-btn-disabled-border-color: color-mix(in oklab, var(--destructive), transparent 75%);
}

.btn-outline-light {
    --bs-btn-color: oklch(100% 0 0 / 0.85);
    --bs-btn-border-color: oklch(100% 0 0 / 0.2);
    --bs-btn-hover-color: var(--surface-strong-foreground);
    --bs-btn-hover-bg: oklch(100% 0 0 / 0.1);
    --bs-btn-hover-border-color: oklch(100% 0 0 / 0.3);
    --bs-btn-active-color: var(--surface-strong-foreground);
    --bs-btn-active-bg: oklch(100% 0 0 / 0.15);
    --bs-btn-active-border-color: oklch(100% 0 0 / 0.3);
}

.btn-link {
    --bs-btn-color: var(--primary);
    --bs-btn-hover-color: color-mix(in oklab, var(--primary), black 15%);
    --bs-btn-font-weight: 600;
    text-decoration: none;
}

/* ---- Forms ------------------------------------------------------------ */

.form-label {
    font-size: 0.8125rem;
    font-weight: 500;
    margin-bottom: 0.375rem;
}

.form-control,
.form-select {
    border-color: var(--border);
    border-radius: var(--radius);
    background-color: var(--card);
    color: var(--foreground);
    font-size: 0.875rem;
    padding: 0.5rem 0.75rem;
}

.form-control-sm,
.form-select-sm {
    font-size: 0.8125rem;
}

.form-control::placeholder {
    color: var(--muted-foreground);
}

.form-control:focus,
.form-select:focus,
.form-check-input:focus,
.btn:focus-visible,
.btn:active:focus,
.btn-link.nav-link:focus {
    border-color: var(--primary);
    box-shadow: 0 0 0 3px color-mix(in oklab, var(--primary), transparent 85%);
    outline: none;
}

.form-control:disabled,
.form-select:disabled {
    background-color: var(--muted);
    color: var(--muted-foreground);
}

.form-check-input:checked {
    background-color: var(--primary);
    border-color: var(--primary);
}

.darker-border-checkbox.form-check-input {
    border-color: var(--muted-foreground);
}

/* Blazor's own validation state classes — matched to the token palette rather than the
   default template's raw hex. */
.valid.modified:not([type=checkbox]) {
    outline: 1px solid var(--success);
}

.invalid {
    outline: 1px solid var(--destructive);
}

.validation-message,
.text-danger {
    color: var(--destructive) !important;
}

.form-floating > .form-control-plaintext::placeholder,
.form-floating > .form-control::placeholder {
    color: var(--muted-foreground);
    text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder,
.form-floating > .form-control:focus::placeholder {
    text-align: start;
}

/* ---- Cards, tables, pagination ---------------------------------------- */

.card {
    --bs-card-bg: var(--card);
    --bs-card-border-color: var(--border);
    --bs-card-border-radius: 1rem;
    --bs-card-spacer-y: 1.125rem;
    --bs-card-spacer-x: 1.125rem;
    box-shadow: var(--shadow-card);
}

/* The list pages wrap their tables in a bare overflow div; giving the table itself the card
   treatment keeps them consistent with the portal's board without touching page markup. */
.table {
    --bs-table-bg: var(--card);
    --bs-table-color: var(--foreground);
    --bs-table-border-color: var(--border);
    --bs-table-hover-bg: var(--muted);
    --bs-table-hover-color: var(--foreground);
    margin-bottom: 0;
    font-size: 0.8125rem;
}

.table > thead > tr > th {
    height: 2.75rem;
    vertical-align: middle;
    background: var(--card);
    border-bottom: 1px solid var(--border);
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--muted-foreground);
    white-space: nowrap;
}

.table > tbody > tr > td {
    padding-top: 0.75rem;
    padding-bottom: 0.75rem;
    vertical-align: middle;
}

.table > tbody > tr:last-child > td {
    border-bottom: 0;
}

/* Row status tints — the list pages tag rows with Bootstrap's contextual table classes
   (see Maintenance.GetStatusRowClass); these keep that semantic but in the portal's palette,
   as a wash rather than Bootstrap's flat pastel. */
.table > tbody > tr.table-warning {
    --bs-table-bg: color-mix(in oklab, var(--warning), var(--card) 90%);
    --bs-table-color: var(--foreground);
}

.table > tbody > tr.table-info {
    --bs-table-bg: color-mix(in oklab, var(--info), var(--card) 90%);
    --bs-table-color: var(--foreground);
}

.table > tbody > tr.table-success {
    --bs-table-bg: color-mix(in oklab, var(--success), var(--card) 90%);
    --bs-table-color: var(--foreground);
}

/* The card shell the portal's board uses. Also the horizontal scroller — before this, half the
   list pages had an inline overflow-x wrapper and half didn't; every table now uses this. */
.table-card {
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: 1rem;
    box-shadow: var(--shadow-card);
    overflow-x: auto;
    /* A table card that is not a list page's own (detail pages, cards inside sections) scrolls its rows
       inside a capped box, so its headings can stick. List pages lift the cap below: their card is sized
       by the page column instead. */
    max-height: calc(100vh - 230px);
}

/* List pages keep their chrome -- title, filters, Add button, pagination -- on screen and scroll
   only the rows. The chrome is not made sticky one element at a time because each would need to
   know the height of everything above it; instead the content column becomes a fixed-height flex
   column and the table card takes whatever is left, so it is the only thing that scrolls and no
   height is ever hard-coded.

   :has(> .table-card) is what keeps this to list pages. The detail pages nest their table cards
   inside sections and want the page to scroll as one, so they never match. Gated to the desktop
   breakpoint: below it the sidebar stacks above the content and a viewport-height column would
   push the table off the bottom of the screen. */
@media (min-width: 641px) {
    .content:has(> .table-card) {
        height: 100vh;
        display: flex;
        flex-direction: column;
        overflow: hidden;
    }

    /* Everything above the table keeps its own height. Without this the filter panel takes the
       spare space, because .card-body carries flex: 1 1 auto and a page that puts both classes on
       one element makes that a flex item of this column. */
    .content:has(> .table-card) > * {
        flex: 0 0 auto;
    }

    /* A stretched Add button would run the width of the page -- a column flex container stretches
       its items across, and the button used to be an inline-block sized to its label. */
    .content:has(> .table-card) > .btn {
        align-self: flex-start;
    }

    /* Shrink-only, never grow: a list that fits keeps a card the height of its rows, with the
       pagination directly under it, and only a list too long to fit is squeezed into the space
       left and scrolled. Growing instead would frame three rows in a viewport-tall empty box. */
    .content:has(> .table-card) > .table-card {
        flex: 0 1 auto;
        /* Without this the card refuses to shrink below its content and scrolls the page instead. */
        min-height: 0;
        overflow: auto;
        max-height: none;
    }
}

/* Column headings stay put while the rows move under them. .table-card is already a scroll
   container in both axes (overflow-x: auto forces overflow-y to compute to auto), so this needs no
   help from the rules above and does nothing on a card short enough not to scroll. The background
   is required -- a transparent heading lets the first rows show through as they pass beneath. */
.table-card > .table > thead > tr > th,
.table-responsive:not(.tele-scroll) > .table > thead > tr > th {
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--card);
}

/* Bootstrap's .table-responsive only scrolls sideways; cap its height too so the headings stick. */
.table-responsive:not(.tele-scroll) {
    max-height: calc(100vh - 230px);
    overflow: auto;
}

/* ---- Alerts + badges --------------------------------------------------- */

.alert {
    --bs-alert-border-radius: var(--radius);
    border-width: 1px;
    padding: 0.75rem 0.875rem;
    font-size: 0.8125rem;
}

.alert-danger {
    --bs-alert-color: color-mix(in oklab, var(--destructive), var(--foreground) 20%);
    --bs-alert-bg: color-mix(in oklab, var(--destructive), transparent 92%);
    --bs-alert-border-color: color-mix(in oklab, var(--destructive), transparent 70%);
}

.alert-warning {
    --bs-alert-color: color-mix(in oklab, var(--warning), var(--foreground) 25%);
    --bs-alert-bg: color-mix(in oklab, var(--warning), transparent 92%);
    --bs-alert-border-color: color-mix(in oklab, var(--warning), transparent 65%);
}

.alert-success {
    --bs-alert-color: color-mix(in oklab, var(--success), var(--foreground) 20%);
    --bs-alert-bg: color-mix(in oklab, var(--success), transparent 92%);
    --bs-alert-border-color: color-mix(in oklab, var(--success), transparent 65%);
}

/* Status badges (MaintenanceDetail) render as the portal's pill: a dot, a hairline border and a
   tinted wash, tone driven by whichever bg-* class the page picked. */
.badge {
    --tone: var(--muted-foreground);
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.1875rem 0.625rem;
    border: 1px solid color-mix(in oklab, var(--tone), transparent 75%);
    border-radius: 999px;
    background: color-mix(in oklab, var(--tone), transparent 90%) !important;
    color: color-mix(in oklab, var(--tone), var(--foreground) 30%) !important;
    font-size: 0.75rem;
    font-weight: 600;
}

.badge::before {
    content: '';
    width: 0.375rem;
    height: 0.375rem;
    border-radius: 50%;
    background: var(--tone);
    flex: none;
}

.badge.bg-primary { --tone: var(--primary); }
.badge.bg-secondary { --tone: var(--muted-foreground); }
.badge.bg-success { --tone: var(--success); }
.badge.bg-warning { --tone: var(--warning); }
.badge.bg-info { --tone: var(--info); }
.badge.bg-danger { --tone: var(--destructive); }

/* ---- Modal (Components/Shared/Modal.razor) ----------------------------- */

/* Only the scrim ever carries the blur — a backdrop-filter on an ancestor of the panel would
   soften the panel's own text too, and it must stay perfectly crisp. The panel is a sibling
   stacked above this, so it sits outside what gets filtered. */
.modal-scrim {
    position: fixed;
    inset: 0;
    z-index: 1050;
    background: oklch(12.9% 0.042 264.695 / 0.4);
    backdrop-filter: blur(3px);
    animation: modal-scrim-in 0.15s ease-out;
}

/* .modal covers the whole viewport, so without this it would swallow every click meant for the
   scrim behind it and click-outside-to-close would never fire. Bootstrap already sets
   .modal-content back to pointer-events: auto, so the panel itself stays clickable, and wheel
   events over the panel still scroll .modal for forms taller than the viewport. */
.modal-popup {
    pointer-events: none;
    --bs-modal-padding: 1.25rem;
    --bs-modal-border-radius: 1rem;
    --bs-modal-border-color: var(--border);
    --bs-modal-bg: var(--background);
    --bs-modal-box-shadow: var(--shadow-pop);
    --bs-modal-header-padding: 1.25rem;
    z-index: 1055;
}

.modal-popup .modal-content {
    box-shadow: var(--shadow-pop);
    animation: modal-pop-in 0.18s ease-out;
}

.modal-popup .modal-title {
    font-size: 1.1875rem;
    font-weight: 600;
    letter-spacing: -0.02em;
}

/* The Save/Cancel pair has to live inside the page's <EditForm> for submit to work, so the
   footer ends up nested inside .modal-body rather than as a sibling of it. These margins pull
   it back out to the panel's edges so it still reads as a real footer. */
/* Corner radii are left to Bootstrap's own .modal-footer rule (--bs-modal-inner-border-radius);
   it already matches the panel, and the footer's corners sit on the panel's edge once the
   negative margins above pull it out there. */
.modal-body .modal-footer {
    margin: 1.25rem -1.25rem -1.25rem;
    padding: 1rem 1.25rem;
}

@keyframes modal-scrim-in {
    from { opacity: 0; }
}

@keyframes modal-pop-in {
    from { opacity: 0; transform: translateY(8px) scale(0.98); }
}

@media (prefers-reduced-motion: reduce) {
    .modal-scrim,
    .modal-popup .modal-content {
        animation: none;
    }
}

/* ---- Blazor error boundary -------------------------------------------- */

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, var(--destructive);
    padding: 1rem 1rem 1rem 3.7rem;
    border-radius: var(--radius);
    color: white;
}

    .blazor-error-boundary::after {
        content: "An error has occurred."
    }

/* ---- Per-field edit toggle (EditToggle.razor) -------------------------- */
/* Deliberately muted by default, only picking up the accent color on hover/focus -- a record page
   should read as a document first, with editing a quiet affordance rather than the visual lead. */

.edit-toggle-btn {
    color: var(--muted-foreground);
    line-height: 1;
}

.edit-toggle-btn:hover,
.edit-toggle-btn:focus-visible {
    color: var(--primary);
}

/* ---- Toast (Toast.razor) ------------------------------------------------ */
/* Mirrors mobile's Toast.vue -- same dark pill, same fixed positioning intent, just anchored to the
   browser viewport instead of a mobile app-shell. */

.toast-banner {
    position: fixed;
    left: 50%;
    bottom: 24px;
    transform: translateX(-50%);
    z-index: 1080;
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 13px 18px;
    border-radius: 14px;
    background: #201e1d;
    box-shadow: 0 8px 24px rgba(32, 30, 29, 0.28);
    max-width: min(420px, calc(100vw - 32px));
}

.toast-dot {
    flex: none;
    width: 8px;
    height: 8px;
    border-radius: 99px;
    background: var(--primary);
}

.toast-text {
    font-size: 14px;
    color: #f8f4f4;
}

/* ---- Merged audit trail (BreakdownDetail.razor / MaintenanceDetail.razor) ---------------------- */
/* Same system-row / chat-bubble split as mobile's equivalent feed in DetailView.vue. */

.feed-system-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 5px 2px;
    font-size: 13px;
    color: var(--muted-foreground);
}

.feed-dot {
    flex: none;
    width: 7px;
    height: 7px;
    border-radius: 99px;
}

.feed-system-text {
    flex: 1;
}

.feed-system-time {
    flex: none;
    font-size: 11.5px;
    color: var(--muted-foreground);
    opacity: 0.8;
    white-space: nowrap;
}

.post-close-tag {
    margin-left: 6px;
    padding: 1px 7px;
    border-radius: 999px;
    background: color-mix(in oklab, var(--destructive), transparent 85%);
    color: var(--destructive);
    font-size: 10.5px;
    font-weight: 600;
    white-space: nowrap;
}

.bubble-row {
    display: flex;
    justify-content: flex-start;
    padding: 4px 2px;
}

.bubble-row-own {
    justify-content: flex-end;
}

.bubble {
    max-width: 78%;
    border-radius: var(--radius);
    padding: 10px 13px;
    background: var(--muted);
}

.bubble-own {
    background: color-mix(in oklab, var(--primary), transparent 88%);
}

.bubble-meta strong {
    font-size: 13.5px;
}

/* ---- Photo attachments (PhotoPicker.razor + the audit-trail feed) ----------------------------- */

.photo-picker label.btn {
    cursor: pointer;
}

/* Several photos side by side (Log breakdown form, a breakdown's "logged" entry). */
.photo-thumbs {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}

.photo-thumb {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
}

.photo-thumb img {
    display: block;
    max-width: 160px;
    max-height: 160px;
    border-radius: var(--radius);
    border: 1px solid var(--border);
}

.photo-thumbs .feed-photo {
    max-width: 240px;
    max-height: 240px;
}

.photo-preview img,
.feed-photo {
    display: block;
    max-width: 100%;
    max-height: 320px;
    border-radius: var(--radius);
    border: 1px solid var(--border);
}

/* A photo posted with a comment sits directly above/below the text inside the same bubble. */
.bubble .feed-photo {
    margin-top: 6px;
}

/* ---- Diesel (Diesel.razor / DieselDetail.razor / DieselConsumptionCards.razor) ---------------- */

.diesel-truck-row {
    cursor: pointer;
}

.diesel-needs-attention-row {
    cursor: pointer;
}

.diesel-needs-attention-row:hover {
    text-decoration: underline;
}

.diesel-review-row {
    cursor: pointer;
}

/* ---- Alerts (Alerts.razor) ---------------------------------------------------------------------- */

.fleet-alert-row {
    cursor: pointer;
}

.fleet-alert-row:hover {
    text-decoration: underline;
}

/* The docket image frame on the review detail page. A fixed, clipped square -- sized off viewport
   height (min(...)) so it scales up on a large/1080p+ display without depending on how wide its
   Bootstrap column happens to be, and capped at 640px so it doesn't get absurd on an ultrawide.
   overflow: hidden is what actually keeps a rotated image inside its own box -- see the razor
   file's comment on why that matters (a CSS transform doesn't change the layout space reserved for
   the element, only how it paints, so an unclipped rotation spills into whatever is next to it). */
.diesel-docket-frame {
    width: 100%;
    height: min(62vh, 560px);
    display: flex;
    overflow: hidden;   /* at Fit the whole photo shows: no scroll bars */
    background: var(--muted);
    border: 1px solid var(--border);
    border-radius: var(--radius);
}

/* Zoomed in: the photo is moved by dragging it (js/media-viewer.js); the wheel / touchpad still scroll it. No scroll bars are drawn, and the pointer
   is a hand over the whole photo (closed while dragging). */
.diesel-docket-frame.pannable {
    overflow: auto;
    scrollbar-width: none;          /* Firefox */
}

.diesel-docket-frame.pannable::-webkit-scrollbar {
    display: none;                  /* Chrome, Edge, Safari */
}

.diesel-docket-frame.pannable,
.diesel-docket-frame.pannable * {
    cursor: grab;
}

.diesel-docket-frame.pannable.panning,
.diesel-docket-frame.pannable.panning * {
    cursor: grabbing;
}

.diesel-docket-frame .diesel-docket-image {
    user-select: none;
    -webkit-user-drag: none;
}

/* The Review screen gives the photo all the height the page has. */
.diesel-docket-frame.tall {
    height: max(480px, calc(100vh - 250px));
}

/* The zoomable layer. js/media-viewer.js gives it the photo's visual size (rotation and zoom already applied) and the photo is centred and turned
   inside it. Auto margins centre it when it is smaller than the frame and start it at the top-left when it is bigger, so all of it can be reached. */
.diesel-docket-zoom {
    position: relative;
    flex: none;
    margin: auto;
}

.diesel-docket-image {
    position: absolute;
    top: 50%;
    left: 50%;
    max-width: none;
    transition: transform 0.15s ease;
}

/* Docket / slip viewer: arrows, photo and tools in one block of one width. */
.media-viewer {
    width: 100%;
    max-width: 640px;
}

.media-viewer.media-viewer-large {
    max-width: none;
}

.media-viewer-head {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.5rem;
}

.media-viewer-head .justify-self-start { justify-self: start; }
.media-viewer-head .justify-self-end { justify-self: end; }

.media-viewer-tools {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.5rem;
}

.diesel-locked-field {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    min-height: calc(1.5em + 0.75rem + 2px); /* matches Bootstrap's .form-control height */
    padding: 0.375rem 0.75rem;
    background: var(--muted);
    border: 1px solid var(--border);
    border-radius: var(--radius);
}

/* Log form pinned beside the data rather than over it, so the readings stay checkable while
   capturing a docket. Collapses to a single column below the tablet breakpoint. */
/* Log-transaction drawer. Slides in from the right over a faint scrim, so the cards and the recent
   closing readings stay readable behind it — that visibility is the point, and is why this is not a
   centred modal. */
.diesel-scrim {
    position: fixed;
    inset: 0;
    background: oklch(20.8% 0.042 265.755 / 0.18);
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.2s ease, visibility 0.2s ease;
    z-index: 1040;
}

.diesel-scrim.diesel-open {
    opacity: 1;
    visibility: visible;
}

.diesel-drawer {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    width: min(380px, 100vw);
    display: flex;
    flex-direction: column;
    background: var(--card);
    border-left: 1px solid var(--border);
    box-shadow: var(--shadow-pop);
    transform: translateX(100%);
    transition: transform 0.22s ease;
    z-index: 1045;
}

.diesel-drawer.diesel-open {
    transform: translateX(0);
}

.diesel-drawer-head {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 1rem 1.25rem;
    border-bottom: 1px solid var(--border);
}

.diesel-drawer-body {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 1.25rem;
}

/* A drawer that flies in is motion for its own sake if the viewer has asked for less of it. */
@media (prefers-reduced-motion: reduce) {
    .diesel-drawer,
    .diesel-scrim {
        transition: none;
    }
}

.metric-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 0.75rem;
}

.metric-card {
    /* --accent is set per card below; each one tints its own background, rule and value so the four
       windows read as four distinct figures rather than one wall of numbers. */
    background: color-mix(in oklab, var(--metric-accent) 7%, var(--card));
    border: 1px solid color-mix(in oklab, var(--metric-accent) 22%, var(--border));
    border-left: 3px solid var(--metric-accent);
    border-radius: var(--radius);
    padding: 0.85rem 1rem;
}

.metric-card:nth-child(1) { --metric-accent: var(--primary); }
.metric-card:nth-child(2) { --metric-accent: var(--info); }
.metric-card:nth-child(3) { --metric-accent: var(--success); }
.metric-card:nth-child(4) { --metric-accent: var(--warning); }

.metric-card .metric-card-value {
    color: color-mix(in oklab, var(--metric-accent) 78%, var(--foreground));
}

.metric-card-title {
    font-size: 0.8rem;
    color: var(--muted-foreground);
    white-space: nowrap;
}

.metric-card-value {
    font-size: 1.6rem;
    font-weight: 600;
    line-height: 1.2;
    margin-top: 0.15rem;
}

.metric-card-unit {
    font-size: 0.9rem;
    font-weight: 400;
    color: var(--muted-foreground);
}

.metric-card.metric-card-has-value .metric-card-title {
    color: color-mix(in oklab, var(--metric-accent) 55%, var(--muted-foreground));
}

/* Stays grey even inside a coloured card: a tinted dash would read as a real figure. */
.metric-card .metric-card-value.metric-card-empty {
    color: var(--muted-foreground);
}

.metric-card-sub {
    font-size: 0.78rem;
    color: var(--muted-foreground);
}

/* The four accent colours mean "these are the four time windows". A card row that is not four
   windows -- the asset totals strip -- drops them rather than borrowing the meaning. */
.metric-cards-plain .metric-card:nth-child(1),
.metric-cards-plain .metric-card:nth-child(2),
.metric-cards-plain .metric-card:nth-child(3),
.metric-cards-plain .metric-card:nth-child(4) {
    --metric-accent: var(--border);
    background: var(--card);
}

.metric-cards-plain .metric-card .metric-card-value {
    color: var(--foreground);
}

.metric-cards-plain .metric-card.metric-card-has-value .metric-card-title {
    color: var(--muted-foreground);
}

.metric-cards-plain .metric-card .metric-card-value.metric-card-empty {
    color: var(--muted-foreground);
}

/* Twelve-month activity trend. Fixed plot height so bars share one baseline, and the month labels
   sit outside it so a tall bar never squeezes them. */
.trend {
    /* Column flex + full height so the chart matches whatever sits beside it in the row. */
    display: flex;
    flex-direction: column;
    height: 100%;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--card);
    padding: 0.85rem 1rem;
}

.trend-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
}

.trend-caption {
    font-size: 0.8rem;
    color: var(--muted-foreground);
}

.trend-legend {
    display: flex;
    gap: 0.85rem;
    flex-wrap: wrap;
    font-size: 0.78rem;
    color: var(--muted-foreground);
}

.trend-key {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
}

.trend-swatch {
    width: 0.6rem;
    height: 0.6rem;
    border-radius: 2px;
}

.trend-plot {
    display: flex;
    gap: 0.5rem;
    margin-top: 0.6rem;
    /* The plot takes whatever height the row gives it -- which is set by the problems box beside it,
       three rows tall -- so the two boxes end level. The floor is only for a narrow screen where
       they stack and there is nothing to match. */
    /* The plot takes whatever height the row gives it -- beside the problems box that is three rows
       tall, so the two end level. The floor is what a chart standing on its own gets. */
    flex: 1;
    min-height: 110px;
}

.trend-month {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.trend-bars {
    flex: 1;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    gap: 2px;
}

.trend-bar {
    flex: 1;
    max-width: 10px;
    border-radius: 2px 2px 0 0;
    min-height: 2px;
}

.trend-month-label {
    margin-top: 0.3rem;
    text-align: center;
    font-size: 0.68rem;
    color: var(--muted-foreground);
}

.trend-scale {
    margin-top: 0.4rem;
    font-size: 0.72rem;
    color: var(--muted-foreground);
}

/* Sticky asset header. Bleeds through .content's own horizontal padding so its background covers
   the full width as rows scroll under it, rather than leaving a gap down each side. */
.asset-header {
    position: sticky;
    top: 0;
    z-index: 5;
    display: flex;
    align-items: center;
    gap: 0.75rem 1rem;
    flex-wrap: wrap;
    margin: -1.5rem -1.5rem 1rem;
    padding: 0.75rem 1.5rem;
    background: var(--background);
    border-bottom: 1px solid var(--border);
}

.asset-header-title {
    font-size: 1.35rem;
    font-weight: 600;
    margin: 0;
}

/* Pills sit inline with the title here, so they lose the block-level spacing they carry elsewhere. */
.asset-header-pills {
    display: flex;
    gap: 0.25rem;
    margin: 0;
    margin-left: auto;
}

.asset-header-pills .nav-link {
    padding: 0.25rem 0.7rem;
    font-size: 0.85rem;
}

/* A metric card that is also a link. Keeps the card's own colours rather than inheriting link blue,
   and only hints at being clickable on hover -- these sit among cards that are not links. */
a.metric-card {
    color: inherit;
    display: block;
    transition: border-color 0.15s ease;
}

a.metric-card:hover {
    border-color: color-mix(in oklab, var(--primary) 45%, var(--border));
}

/* Month-over-month line chart. Colours come from --mtrend-color, set per instance, so one component
   draws every series without a class per colour. */
.mtrend {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--card);
    padding: 0.85rem 1rem;
    height: 100%;
}

.mtrend-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
}

.mtrend-badge {
    font-size: 0.78rem;
    font-weight: 600;
    padding: 0.15rem 0.5rem;
    border-radius: 999px;
    background: color-mix(in oklab, var(--border) 45%, var(--card));
    color: var(--muted-foreground);
    white-space: nowrap;
}

.mtrend-badge-good { background: color-mix(in oklab, var(--success) 15%, var(--card)); color: var(--success); }
.mtrend-badge-warn { background: color-mix(in oklab, var(--warning) 18%, var(--card)); color: var(--warning); }
.mtrend-badge-bad  { background: color-mix(in oklab, var(--destructive) 15%, var(--card)); color: var(--destructive); }
.mtrend-badge-live {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    background: color-mix(in oklab, var(--success) 15%, var(--card));
    color: var(--success);
}

.mtrend-live-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--success);
    animation: mtrend-live-pulse 2s ease-in-out infinite;
}

@keyframes mtrend-live-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.35; }
}

.mtrend-svg {
    display: block;
    margin-top: 0.4rem;
    width: 100%;
    /* Height follows the viewBox ratio -- pinning it would scale the drawing unevenly. */
    height: auto;
}

.mtrend-grid {
    stroke: var(--border);
    stroke-width: 1;
}

.mtrend-line {
    fill: none;
    stroke: var(--mtrend-color);
    stroke-width: 2;
    stroke-linejoin: round;
    stroke-linecap: round;
}

.mtrend-point {
    fill: var(--card);
    stroke: var(--mtrend-color);
    stroke-width: 2;
}

/* The month still in progress: filled rather than hollow, so it reads as "not finished". */
.mtrend-point-running {
    fill: var(--mtrend-color);
}

.mtrend-axis {
    font-size: 10px;
    fill: var(--muted-foreground);
}

.mtrend-value {
    font-size: 10px;
    font-weight: 600;
    fill: var(--foreground);
}

.mtrend-legend {
    display: flex;
    gap: 0.9rem;
    flex-wrap: wrap;
}

.mtrend-legend-item {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.78rem;
    color: var(--muted-foreground);
}

/* The colour comes in as --swatch (set inline per legend item), never as an inline `background`:
   that shorthand resets background-image, which is what draws the dashed swatch below -- it used
   to wipe the telemetry swatch out entirely, leaving the legend showing only "Docket". */
.mtrend-legend-swatch {
    width: 12px;
    height: 3px;
    border-radius: 2px;
    display: inline-block;
    background: var(--swatch);
}

/* Matches the dashed stroke on the telemetry line itself -- the swatch carries the same secondary
   encoding as the line it stands for, not just its colour. */
.mtrend-legend-swatch-dashed {
    width: 14px;
    background: linear-gradient(to right, var(--swatch) 60%, transparent 40%) 0 0 / 6px 3px repeat-x;
}

/* Export to PDF is the browser's own print-to-PDF, so the work here is making the page print like a
   report rather than like a screenshot of an app: chrome and controls gone, cards kept whole across
   page breaks, and everything a size that fits the paper. */
@media print {
    .sidebar,
    .report-actions,
    .asset-header-pills,
    #blazor-error-ui,
    .btn {
        display: none !important;
    }

    @page {
        size: A4 landscape;
        margin: 10mm;
    }

    body {
        background: #fff;
    }

    .page {
        display: block;
    }

    .content {
        padding: 0 !important;
    }

    .asset-header {
        position: static;
        margin: 0 0 0.5rem;
        padding: 0 0 0.4rem;
    }

    /* A card split across a page break is the single thing that makes a printed dashboard unreadable. */
    .card,
    .trend,
    .mtrend,
    .table-card {
        break-inside: avoid;
        box-shadow: none;
    }

    .card {
        border: 1px solid #ddd;
        margin-bottom: 0.5rem !important;
        padding: 0.6rem !important;
    }

    .metric-card {
        padding: 0.45rem 0.6rem;
    }

    .metric-card-value {
        font-size: 1.15rem;
    }

    .table,
    .metric-card-sub,
    .metric-card-title {
        font-size: 0.72rem;
    }

    h5 {
        font-size: 0.95rem;
    }
}

/* ---- Training tours (wwwroot/js/tour.js) ------------------------------
   Four shades frame the highlighted control, so everything else is dimmed and unclickable. The
   cover sits on the control itself during a Look step, which is what keeps a tour from ever pressing
   a real Save. Above every modal, drawer and toast in the app (the highest of those is 1080). */

.fm-tour-shade,
.fm-tour-ring,
.fm-tour-cover,
.fm-tour-card {
    position: fixed;
    z-index: 2000;
}

.fm-tour-shade {
    background: oklch(20.8% 0.042 265.755 / 0.55);
}

.fm-tour-ring {
    border-radius: var(--radius);
    box-shadow: 0 0 0 3px var(--primary);
    pointer-events: none;
    transition: top 0.15s ease, left 0.15s ease, width 0.15s ease, height 0.15s ease;
}

.fm-tour-cover {
    background: transparent;
    cursor: not-allowed;
}

.fm-tour-card {
    z-index: 2001;
    width: min(380px, calc(100vw - 32px));
    padding: 1rem 1.1rem 0.75rem;
    background: var(--card);
    color: var(--foreground);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-pop);
}

.fm-tour-card.fm-tour-centred {
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}

.fm-tour-card.fm-tour-docked {
    top: auto;
    left: 50%;
    bottom: 16px;
    transform: translateX(-50%);
}

.fm-tour-meta {
    display: flex;
    justify-content: space-between;
    gap: 0.75rem;
    font-size: 0.75rem;
    color: var(--muted-foreground);
    margin-bottom: 0.35rem;
}

.fm-tour-title {
    font-size: 1rem;
    font-weight: 600;
    margin: 0 0 0.35rem;
}

.fm-tour-body {
    font-size: 0.875rem;
    line-height: 1.5;
}

.fm-tour-hint {
    margin-top: 0.6rem;
    padding: 0.4rem 0.6rem;
    border-radius: calc(var(--radius) - 0.25rem);
    background: var(--muted);
    font-size: 0.8rem;
    color: var(--primary);
    font-weight: 500;
}

.fm-tour-actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.85rem;
}

.fm-tour-restart,
.fm-tour-exit {
    padding-left: 0;
    color: var(--muted-foreground);
}

/* Back / Next get the whole row; these sit on a line of their own beneath, so adding a button here
   can never push Next off the card. */
.fm-tour-links {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.25rem 1rem;
    margin-top: 0.35rem;
}

.fm-tour-practice {
    margin-top: 0.6rem;
    padding-top: 0.5rem;
    border-top: 1px solid var(--border);
    font-size: 0.75rem;
    color: var(--muted-foreground);
}

.fm-tour-next:disabled {
    opacity: 0.5;
}

.fm-tour-spacer {
    flex: 1;
}

.fm-tour-card.fm-tour-loading .fm-tour-body {
    color: var(--muted-foreground);
}

@media (prefers-reduced-motion: reduce) {
    .fm-tour-ring {
        transition: none;
    }
}

/* The Training page's module list. */

.training-progress {
    height: 0.5rem;
}

.training-module {
    display: flex;
    align-items: center;
    gap: 1rem;
}

.training-module-status {
    flex-shrink: 0;
    width: 1.75rem;
    height: 1.75rem;
    border-radius: 50%;
    display: grid;
    place-items: center;
    font-size: 0.85rem;
    background: var(--muted);
    color: var(--muted-foreground);
}

.training-module-status.done {
    background: color-mix(in oklab, var(--success), white 80%);
    color: var(--success);
}

@media (max-width: 575.98px) {
    .training-module {
        flex-wrap: wrap;
    }
}

/* ---- Searchable dropdowns (wwwroot/js/searchable-select.js) ------------
   Every <select> opens as this list. Above modals (1055) and the training tour's card (2001), so a
   dropdown still works inside either. */

.ss-menu {
    position: fixed;
    z-index: 2002;
    display: flex;
    flex-direction: column;
    max-height: min(340px, calc(100vh - 16px));
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-pop);
    overflow: hidden;
}

.ss-search {
    flex: none;
    margin: 8px;
    padding: 0.4rem 0.6rem;
    border: 1px solid var(--border);
    border-radius: calc(var(--radius) - 0.25rem);
    font: inherit;
    font-size: 0.875rem;
    color: var(--foreground);
    background: var(--background);
    outline: none;
}

.ss-search:focus {
    border-color: var(--primary);
    box-shadow: 0 0 0 3px color-mix(in oklab, var(--primary), transparent 80%);
}

.ss-list {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 0 4px 6px;
}

.ss-option {
    padding: 0.4rem 0.6rem;
    border-radius: calc(var(--radius) - 0.3rem);
    font-size: 0.875rem;
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.ss-option.ss-placeholder {
    color: var(--muted-foreground);
}

.ss-option.ss-selected {
    font-weight: 600;
}

.ss-option.ss-active {
    background: var(--muted);
}

.ss-empty {
    padding: 0.5rem 0.6rem;
    font-size: 0.85rem;
    color: var(--muted-foreground);
}

/* While a tour is on screen the navigation menu is greyed out and cannot be clicked, so the trainee
   can only work within the page. A click step's own control (tour.js marks it) stays live. */
body:has(.fm-tour) .sidebar {
    filter: grayscale(1);
    opacity: 0.45;
}

body:has(.fm-tour) .sidebar * {
    pointer-events: none;
}

body:has(.fm-tour) .sidebar .fm-tour-target,
body:has(.fm-tour) .sidebar .fm-tour-target * {
    pointer-events: auto;
}

/* On a narrow window the menu is behind a hamburger; keep that live while a step points into the menu. */
body:has(.fm-tour) .sidebar:has(.fm-tour-target) .navbar-toggler {
    pointer-events: auto;
}

/* Diesel consumption chart: drag to pan along the timeline. */
.mtrend-pan .mtrend-svg { cursor: grab; touch-action: pan-y; user-select: none; }
.mtrend-pan.mtrend-dragging .mtrend-svg { cursor: grabbing; }

/* The chart draws at 1:1 pixels, so its labels are sized like the page's own small text. */
.mtrend-pan .mtrend-axis { font-size: 12px; }

/* ---- Emailing a report (Components/Shared/ReportEmails.razor) ------------------------------- */

.report-builder-list,
.report-email-pick {
    max-height: 14rem;
    overflow-y: auto;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 0.5rem 0.75rem;
}

/* Telemetry tables: the headings stay put and only the rows scroll. */
.tele-scroll {
    max-height: calc(100vh - 230px);
    min-height: 260px;
    overflow: auto;
}

.tele-scroll thead th {
    position: sticky;
    top: 0;
    z-index: 2;
    background: var(--bs-body-bg, #fff);
    box-shadow: inset 0 -1px 0 var(--border, #dee2e6);
}

/* A cancelled diesel docket: only the number is kept, so the row is dulled out. */
.diesel-row-cancelled td {
    opacity: .5;
    background: var(--bs-tertiary-bg, #f1f3f5);
}

/* The truck shown over the page while a link is being followed (js/nav-loader.js). Click-through, so the
   old page stays usable and a second click is never swallowed; fades in and out so it never pops. */
#fm-nav-loader {
    position: fixed;
    inset: 0;
    z-index: 1900;
    display: flex;
    align-items: center;
    justify-content: center;
    background: color-mix(in oklab, var(--background), transparent 12%);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.12s ease;
}

#fm-nav-loader.on {
    opacity: 1;
}



/* Review: a field the system matched is green (and can be changed with a reason); a field that needs attention is amber. */
.field-matched {
    min-height: calc(1.5em + 0.75rem + 2px);
    padding: 0.375rem 0.75rem;
    border: 1px solid color-mix(in oklab, var(--success), transparent 55%);
    border-radius: var(--radius);
    background: color-mix(in oklab, var(--success), var(--card) 88%);
    color: var(--foreground);
}

.field-attention .form-control,
.field-attention .form-select {
    border-color: var(--warning);
    background-color: color-mix(in oklab, var(--warning), var(--card) 90%);
}
