/* MissionCashView — ported design system (colors/layout from Mission_launchpad) */

/* ---------------------------------------------------------------------------
   Theme tokens. Every colour in this stylesheet goes through one of these, so
   a theme is just a different set of values — see the [data-theme="light"]
   block below. Dark is the default and is what :root carries, so a page whose
   theme attribute never gets set (JS disabled, or the inline <head> script in
   core/base.html not having run yet) still renders in the original dark look
   rather than unstyled.

   Naming: --bg/--surface* are backgrounds back to front, --text* are text on
   those, and --on-accent/--on-neutral are text sitting on a filled control.
   Tinted badge and alert backgrounds are mixed from their own ink colour with
   color-mix() instead of being hard-coded rgba(), so each theme gets a tint
   that sits correctly on that theme's background.
   --------------------------------------------------------------------------- */
:root {
    color-scheme: dark;
    --scheme: dark;

    --bg: #16171a;
    --surface: #1e1e1e;
    --surface-2: #1c1c1c;
    --surface-3: #262626;
    --table-head-bg: #0d1b2a;

    --border: #2a2a2a;
    --border-strong: #3a3a3a;
    --border-subtle: #242424;

    --text: #fff;
    --text-soft: #ccc;
    --text-muted: #aaa;
    --text-faint: #777;
    --link: #4e9fff;

    --accent: #00a3eb;
    --accent-hover: #0088cc;
    --accent-strong: #00509e;
    --on-accent: #fff;

    --neutral-bg: #333333;
    --neutral-hover: #404040;
    --on-neutral: #fff;

    --positive: #4fd08a;
    --negative: #ff6b6b;
    --warning: #f97316;
    --info: #2bb3e6;
    --danger: #dc3545;
    --danger-hover: #bb2d3b;
    --brand: #00aeef;

    --alert-success: #27ae60;
    --alert-success-ink: #2ecc71;
    --alert-info-ink: #7fd3f7;
    --alert-warning: #f39c12;
    --alert-warning-ink: #f5b041;

    --today-bg: rgba(250, 204, 21, 0.22);
    --today-ink: #facc15;

    /* Strength of the tint mixed behind a status badge / alert. */
    --badge-tint: 18%;
    --alert-tint: 12%;

    --overlay: rgba(0, 0, 0, 0.6);
    --shadow-soft: rgba(0, 0, 0, 0.15);
    --shadow-strong: rgba(0, 0, 0, 0.5);
    --focus-ring: rgba(0, 80, 158, 0.25);

    /* Chevron drawn into the <select> background — a data: URI can't read a
       custom property, so each theme carries its own copy with the stroke
       colour baked in. */
    --select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%23aaaaaa' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

:root[data-theme="light"] {
    color-scheme: light;
    --scheme: light;

    --bg: #f4f6f9;
    --surface: #ffffff;
    --surface-2: #ffffff;
    --surface-3: #eff2f7;
    --table-head-bg: #e9eef5;

    --border: #dde2e9;
    --border-strong: #c3cad4;
    --border-subtle: #edf0f4;

    --text: #181b20;
    --text-soft: #39404b;
    --text-muted: #5c6675;
    --text-faint: #6f7886;
    --link: #0b5cad;

    /* Darker than the dark theme's #00a3eb: these carry white text on buttons
       and chips, which needs the contrast. */
    --accent: #0a6490;
    --accent-hover: #084c6e;
    --accent-strong: #00509e;

    --neutral-bg: #e4e8ee;
    --neutral-hover: #d5dae2;
    --on-neutral: #1f242b;

    --positive: #166534;
    --negative: #b91c1c;
    --warning: #92400e;
    --info: #0369a1;
    --danger: #c62828;
    --danger-hover: #a01c1c;

    --alert-success: #166534;
    --alert-success-ink: #166534;
    --alert-info-ink: #0369a1;
    --alert-warning: #92400e;
    --alert-warning-ink: #92400e;

    --badge-tint: 12%;
    --alert-tint: 10%;

    --today-bg: rgba(250, 204, 21, 0.45);
    --today-ink: #a16207;

    --overlay: rgba(15, 20, 30, 0.45);
    --shadow-soft: rgba(16, 24, 40, 0.1);
    --shadow-strong: rgba(16, 24, 40, 0.25);
    --focus-ring: rgba(10, 111, 163, 0.2);

    --select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%235c6675' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

/* The login screen sits on a fixed dark photographic background in both
   themes, so the card on top of it keeps the dark theme's text colours
   whichever theme is active. */
.login-wrapper {
    --text: #fff;
    --text-soft: #ccc;
    --text-faint: #777;
    --link: #4e9fff;
}

*, *::before, *::after {
    box-sizing: border-box;
}

html, body {
    height: 100%;
}
body {
    font-family: 'Satoshi', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
        'Helvetica Neue', Arial, sans-serif;
    margin: 0;
    padding: 0;
    background-color: var(--bg);
    min-height: 100vh;
    color: var(--text);
}
h1, h2, h3, h4, h5, h6, p, label, th, td, span, div, li, a, input, select, textarea {
    color: var(--text);
}

/* Full-page splash shown until window 'load' fires, masking font/CDN asset loading time */
#page-loader {
    position: fixed;
    inset: 0;
    z-index: 9999;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: var(--bg);
    transition: opacity 0.3s ease;
}
#page-loader img {
    width: 140px;
    max-width: 40vw;
    animation: page-loader-pulse 1.4s ease-in-out infinite;
}
#page-loader.page-loader-hidden {
    opacity: 0;
    pointer-events: none;
}
@keyframes page-loader-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.45; }
}

/* Placeholder shown on dashboard stat/table values while QuickBooks data loads async */
.loading-dots::after {
    content: '';
    animation: loading-dots 1.2s steps(4, end) infinite;
}
@keyframes loading-dots {
    0% { content: ''; }
    25% { content: '.'; }
    50% { content: '..'; }
    75%, 100% { content: '...'; }
}

/* Sidebar navigation */
.sidebar {
    position: fixed;
    top: 0;
    left: 0;
    width: 210px;
    height: 100vh;
    background: var(--surface);
    color: var(--text);
    padding-top: 30px;
    z-index: 1000;
    display: flex;
    flex-direction: column;
    box-shadow: 2px 0 8px var(--shadow-soft);
    min-height: 100vh;
}
.sidebar-logo {
    width: 100%;
    padding-bottom: 10px;
    border-bottom: 1px solid var(--border);
    margin-bottom: 20px;
    text-align: center;
}
.sidebar nav ul {
    list-style: none;
    padding: 0;
    margin: 0;
}
.sidebar nav ul li {
    list-style: none;
    margin: 0 0 10px 0;
    padding: 0;
}
.sidebar nav ul li a,
.sidebar nav ul li .link-button {
    color: var(--text) !important;
    text-decoration: none !important;
    display: flex;
    align-items: center;
    padding: 10px 20px;
    border-radius: 6px;
    transition: background 0.2s;
    font-size: 16px;
    font-weight: 500;
    background: none;
    box-shadow: none;
    width: 100%;
    text-align: left;
    border: none;
    cursor: pointer;
    font-family: inherit;
}
.sidebar nav ul li a:hover,
.sidebar nav ul li .link-button:hover {
    background: var(--accent-strong);
    color: var(--on-accent) !important;
}
.sidebar nav ul li i {
    margin-right: 10px;
    font-size: 18px;
}
.sidebar-footer-links {
    margin-top: auto;
    padding: 20px 20px 40px 20px;
    border-top: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.sidebar-footer-links a {
    color: var(--link) !important;
    font-size: 13px;
    text-decoration: none !important;
}

.main-content {
    margin-left: 210px;
    padding: 30px 30px 30px 15px;
    min-height: 0;
}

/* Cards / dashboard grid */
.card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 20px;
    margin-bottom: 30px;
}
.card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 20px;
    min-width: 0;
}
.card h2 {
    margin-top: 0;
    font-size: 18px;
    font-weight: 600;
}
/* Payment schedule rows (project create/edit). The row itself is a flex container with two
   mutually-exclusive content blocks (only one ever shown, by .payment-schedule-title-row)
   plus the Remove control — kept this simple instead of nesting nested grids/display:contents
   tricks, which rendered unreliably. flex-wrap must stay on even above the mobile breakpoint
   below: .payment-schedule-errors uses flex-basis: 100% to drop onto its own line when a row
   fails validation, which only works in a wrapping flex container — without it the browser
   has nowhere to put that line and instead squeezes every field down to fit, which is what
   produced the overlapping/garbled row reported as a UI bug. */
.payment-schedule-row {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 10px;
    padding-bottom: 12px;
    margin-bottom: 12px;
    border-bottom: 1px solid var(--border);
}
.payment-schedule-row .form-group { min-width: 0; }
.payment-schedule-row .form-group label { font-size: 12px; color: var(--text-muted); }
.payment-schedule-remove {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 13px;
    color: var(--text-muted);
    white-space: nowrap;
    padding-bottom: 10px;
    cursor: pointer;
    flex-shrink: 0;
}
.payment-schedule-remove input { accent-color: var(--negative); cursor: pointer; }
.payment-schedule-errors { flex-basis: 100%; margin: 0; }
.payment-schedule-row-draggable { cursor: default; }
.payment-schedule-row-draggable.dragging { opacity: 0.4; }
.payment-schedule-drag-handle {
    flex-shrink: 0;
    align-self: center;
    padding: 4px 6px;
    color: var(--text-faint);
    cursor: grab;
}
.payment-schedule-drag-handle:active { cursor: grabbing; }
.payment-schedule-rows-dropzone { min-height: 10px; border-radius: 8px; transition: background-color 0.15s ease; }
.payment-schedule-rows-dropzone.drag-over { background-color: color-mix(in srgb, var(--accent) 10%, transparent); outline: 2px dashed var(--accent); outline-offset: 4px; }

/* Ordinary payment row: date/amount/estimate/invoice/PO/invoice sent all on one row. */
.payment-schedule-payment-fields {
    flex: 1;
    display: grid;
    /* Details gets roughly 2.5x the width of a reference column. It holds free text,
       while Estimate/Invoice/PO hold short codes ("EST-1041", "WZ-1639") that need far
       less room than an equal share gives them — so the space comes off those three
       rather than off Date and Amount, which have fixed-width date and number inputs.
       Collapses to two columns under 900px (below), where Details flows as another
       cell and gets the full half-width. */
    grid-template-columns:
        minmax(0, 0.95fr)   /* Date */
        minmax(0, 0.9fr)    /* Amount exVAT */
        minmax(0, 2fr)      /* Details */
        minmax(0, 1fr)      /* Estimate number — widest label of the three, and wraps
                               onto two lines below this, which makes the whole row
                               taller than its neighbours */
        minmax(0, 0.95fr)   /* Invoice number */
        minmax(0, 0.9fr)    /* PO Number — a full "PO-88421" has to fit, not just most of it */
        minmax(0, 0.95fr);  /* Invoice sent? */
    gap: 10px;
    align-items: end;
    min-width: 0;
}

/* Title/divider row: a single large centred title + its colour picker — the payment fields
   are hidden entirely, and vice versa for ordinary rows, so only one block ever shows. */
.payment-schedule-title-fields {
    display: none;
    flex: 1;
    align-items: center;
    gap: 12px;
    min-width: 0;
}
.payment-schedule-row.payment-schedule-title-row .payment-schedule-title-fields { display: flex; }
.payment-schedule-row.payment-schedule-title-row .payment-schedule-payment-fields { display: none; }
.payment-schedule-title-fields .form-group:first-child { flex: 1; min-width: 0; }
.payment-schedule-title-input {
    width: 100%;
    text-align: center;
    font-size: 16px;
    font-weight: 700;
}
.payment-schedule-row.payment-schedule-title-row {
    border-radius: 6px;
    border-bottom-width: 2px;
    padding: 10px 12px 12px;
}
.payment-schedule-color-group input[type=color] { width: 44px; height: 36px; padding: 2px; cursor: pointer; }
@media (max-width: 900px) {
    /* flex-wrap itself is already set unconditionally above */
    .payment-schedule-payment-fields { grid-template-columns: 1fr 1fr; }
    .payment-schedule-remove { flex-basis: 100%; padding-bottom: 0; }
}

/* Collapsible dashboard sections */
.collapsible-card h2 { margin-bottom: 0; }
.collapsible-card .card-body { margin-top: 15px; }
.card-toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    width: 100%;
    padding: 0;
    background: none;
    border: 0;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}
.card-toggle:hover { color: var(--accent); }
.card-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; border-radius: 4px; }
.card-toggle-icon {
    flex: none;
    font-size: 14px;
    color: var(--text-muted);
    transition: transform 0.15s ease-in-out;
}
.is-collapsed .card-toggle-icon { transform: rotate(-90deg); }

.card-note {
    color: var(--text-muted);
    font-size: 13px;
    margin: -6px 0 12px 0;
}
.stat-box-grid { margin-bottom: 20px; }
.stat-value {
    font-size: 30px;
    font-weight: 700;
}
.stat-value.positive { color: var(--positive); }
.stat-value.neutral { color: var(--warning); }
.stat-box-breakdown-toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    width: 100%;
    margin-top: 10px;
}
.stat-box-breakdown-toggle .card-toggle-icon { color: inherit; }
.stat-box-breakdown-toggle.is-collapsed .card-toggle-icon { transform: rotate(-90deg); }
.stat-box-breakdown {
    list-style: none;
    margin: 10px 0 0 0;
    padding: 10px 0 0 0;
    border-top: 1px solid var(--border);
    max-height: 220px;
    overflow-y: auto;
}
.stat-box-breakdown li {
    display: flex;
    gap: 16px;
    padding: 6px 0;
    font-size: 13px;
}
.stat-box-breakdown li:not(:last-child) { border-bottom: 1px solid var(--border-subtle); }
.stat-box-breakdown-empty { color: var(--text-muted); }
.stat-box-breakdown li span:first-child { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.stat-box-breakdown li span:last-child { flex-shrink: 0; margin-left: auto; font-weight: 600; }
.chart-container {
    display: flex;
    justify-content: center;
    align-items: center;
    width: 100%;
    max-width: 100%;
    overflow: hidden;
}
.chart-container > div,
.chart-container .js-plotly-plot,
.chart-container .plot-container {
    width: 100% !important;
    max-width: 100%;
}
.stat-row {
    display: flex;
    justify-content: space-between;
    gap: 10px;
    padding: 8px 0;
    border-bottom: 1px solid var(--border);
    font-size: 14px;
}
.stat-row:last-child {
    border-bottom: none;
}
.stat-row span { min-width: 0; overflow-wrap: anywhere; }
.stat-row .value.positive { color: var(--positive); }
.stat-row .value.negative { color: var(--negative); }

/* Page header */
.page-header {
    margin-bottom: 30px;
    padding-bottom: 15px;
}
.page-header h1 {
    margin: 0;
    font-size: 32px;
    font-weight: 600;
}
.page-header p {
    color: var(--text-muted);
    margin: 6px 0 0 0;
}

/* Admin page */
.admin-container {
    max-width: 1200px;
    margin: 0;
}
.form-group {
    display: flex;
    flex-direction: column;
    gap: 8px;
    flex: 1;
    min-width: 200px;
}
.form-group label {
    font-weight: 500;
    font-size: 14px;
}
.form-group input,
.form-group select,
.form-group textarea {
    padding: 10px 12px;
    background: var(--surface-2);
    border: 1px solid var(--border-strong);
    border-radius: 6px;
    color: var(--text);
    font-size: 14px;
    transition: border-color 0.2s;
}
.form-group select {
    cursor: pointer;
    /* Safari paints selects as a native light "menulist" and ignores the background set above,
       leaving white text on grey. Drawing the control ourselves — including the chevron the
       native appearance would have provided — keeps it dark in every browser. */
    appearance: none;
    -webkit-appearance: none;
    padding-right: 34px;
    background-image: var(--select-chevron);
    background-repeat: no-repeat;
    background-position: right 12px center;
    background-size: 12px 8px;
}
/* The open dropdown list is painted by the browser, not by the rules above: without a dark
   color-scheme it renders on a light system background while still taking the white option
   text, which is what made the month selectors unreadable. The explicit option colours cover
   the browsers that paint the list from the element's own colours instead. */
select {
    color-scheme: var(--scheme);
}
select option {
    background: var(--surface-2);
    color: var(--text);
}
select option:checked {
    background: var(--accent-strong);
    color: var(--on-accent);
}
.form-group input:focus,
.form-group select:focus,
.form-group textarea:focus {
    outline: none;
    border-color: var(--accent-strong);
    box-shadow: 0 0 0 3px var(--focus-ring);
}
.radio-inline-group {
    display: flex;
    gap: 20px;
}
.radio-inline-group ul { list-style: none; margin: 0; padding: 0; display: flex; gap: 20px; }
.radio-inline-group li { margin: 0; }
.radio-inline-group label {
    display: flex;
    align-items: center;
    gap: 6px;
    font-weight: 400;
    cursor: pointer;
}
.radio-inline-group input[type="radio"] {
    width: 16px;
    height: 16px;
    accent-color: var(--accent);
    cursor: pointer;
}
/* Native date inputs default to a dark calendar-picker icon, invisible on our dark background */
.form-group input[type="date"] {
    color-scheme: var(--scheme);
    cursor: pointer;
}
.form-group input[type="date"]::-webkit-calendar-picker-indicator {
    opacity: 1;
    cursor: pointer;
}
:root:not([data-theme="light"]) .form-group input[type="date"]::-webkit-calendar-picker-indicator {
    filter: invert(1) brightness(2);
}

.form-section-title {
    margin: 24px 0 12px 0;
    padding-bottom: 6px;
    border-bottom: 1px solid var(--border);
    font-size: 15px;
    color: var(--link);
}
.form-section-title:first-child { margin-top: 0; }

.checkbox-grid ul {
    list-style: none;
    margin: 0;
    padding: 10px 12px;
    background: var(--surface-2);
    border: 1px solid var(--border-strong);
    border-radius: 6px;
    max-height: 220px;
    overflow-y: auto;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 6px 12px;
}
.checkbox-grid li { margin: 0; }
.checkbox-grid label {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    font-weight: 400;
    cursor: pointer;
    color: var(--text);
}
.checkbox-grid input[type="checkbox"] {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
    accent-color: var(--accent);
    cursor: pointer;
}

/* Standalone checkboxes outside .checkbox-grid (e.g. the create-project "Integrations"
   toggles) — resets the generic .form-group input background/padding/border, which is
   meant for text inputs, so the box doesn't render as a large filled square. */
.form-group input.integration-checkbox {
    width: 16px;
    height: 16px;
    padding: 0;
    background: none;
    border: none;
    accent-color: var(--accent);
    cursor: pointer;
}

.job-type-grid ul {
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
}
.job-type-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}
.job-type-checkbox-label {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    cursor: pointer;
    color: var(--text);
    min-width: 0;
}
.job-type-checkbox-label input[type="checkbox"] {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
    accent-color: var(--accent);
    cursor: pointer;
}

.tag-input-chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    padding: 8px 10px;
    background: var(--surface-2);
    border: 1px solid var(--border-strong);
    border-radius: 6px;
}
.tag-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    background: var(--accent);
    color: var(--on-accent);
    font-size: 13px;
    padding: 3px 6px 3px 10px;
    border-radius: 999px;
}
.tag-chip-remove {
    background: none;
    border: none;
    color: var(--on-accent);
    cursor: pointer;
    font-size: 15px;
    line-height: 1;
    padding: 0 2px;
}
.tag-input-entry {
    flex: 1;
    min-width: 140px;
    background: none;
    border: none;
    color: var(--text);
    font-size: 13px;
    outline: none;
}

.section-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 10px;
}
.section-header h2 {
    margin: 0;
    font-size: 18px;
    font-weight: 600;
}

/* Project calendar (FullCalendar dark theme overrides) */
#project-calendar, #asset-calendar {
    --fc-border-color: var(--border);
    --fc-page-bg-color: transparent;
    --fc-neutral-bg-color: var(--surface-3);
    --fc-list-event-hover-bg-color: var(--surface-3);
    --fc-today-bg-color: var(--today-bg);
    --fc-button-bg-color: var(--neutral-bg);
    --fc-button-border-color: var(--neutral-bg);
    --fc-button-hover-bg-color: var(--neutral-hover);
    --fc-button-hover-border-color: var(--neutral-hover);
    --fc-button-active-bg-color: var(--accent);
    --fc-button-active-border-color: var(--accent);
}
#project-calendar .fc-toolbar-title,
#project-calendar .fc-col-header-cell-cushion,
#project-calendar .fc-daygrid-day-number,
#asset-calendar .fc-toolbar-title,
#asset-calendar .fc-col-header-cell-cushion,
#asset-calendar .fc-daygrid-day-number {
    color: var(--text);
}
#asset-calendar .fc-col-header-cell { background: var(--surface-3); }
#asset-calendar .fc-event { font-size: 12px; border-radius: 4px; padding: 1px 4px; }
#project-calendar .fc-daygrid-day.fc-day-other .fc-daygrid-day-number {
    color: var(--text-faint);
}
#project-calendar .fc-day-today .fc-daygrid-day-number {
    color: var(--today-ink);
    font-weight: 700;
}
#project-calendar .fc-event {
    cursor: pointer;
    font-size: 12px;
    /* A real border so each status's edge colour shows. The fill is translucent so a
       packed week stays readable — the date and any event beneath show through instead
       of being covered — and without an edge the events lose their boundaries. */
    border: 1px solid;
    border-radius: 4px;
    padding: 1px 2px;
}
#project-calendar .fc-event .fc-event-title,
#project-calendar .fc-event .fc-event-time {
    /* Follows the theme rather than being pinned to white. The fill is translucent, so
       what sits behind the text is the calendar surface — dark in dark mode, light in
       light mode — and a fixed colour would be unreadable in one of them. */
    color: var(--text);
    font-weight: 500;
}

/* Production status colours, shared by the calendar events and the key below it.
   Status drives the colour (see _calendar_events in projects/views.py): on a production
   calendar what matters at a glance is whether the work is actually booked.

   The alphas differ per theme on purpose. A translucent fill takes on whatever sits
   behind it, so the same rgba() reads as two different colours: yellow at 35% over
   white still looks yellow, but over near-black it goes olive. Dark mode therefore runs
   heavier so the hue survives, and yellow heavier again than green because it is the
   lightest of the three and loses the most against a dark ground. */
:root {
    --cal-confirmed-fill: rgba(79, 208, 138, 0.42);
    --cal-confirmed-edge: #4fd08a;
    --cal-pending-fill: rgba(250, 204, 21, 0.62);
    --cal-pending-edge: #facc15;
    /* Yellow needs a heavy alpha to stay yellow over a dark ground (above), which makes
       the fill itself light — so this is the one status whose label can't use --text.
       White on that yellow is unreadable; dark ink on it is not. */
    --cal-pending-ink: #16181c;
    --cal-none-fill: rgba(148, 163, 184, 0.28);
    --cal-none-edge: #94a3b8;
}
:root[data-theme="light"] {
    --cal-confirmed-fill: rgba(45, 176, 106, 0.30);
    --cal-confirmed-edge: #2db06a;
    --cal-pending-fill: rgba(234, 179, 8, 0.34);
    --cal-pending-edge: #ca9a04;
    /* Light mode's fill is pale over white, so the ordinary text colour reads fine. */
    --cal-pending-ink: var(--text);
    --cal-none-fill: rgba(100, 116, 139, 0.22);
    --cal-none-edge: #64748b;
}
#project-calendar .fc-event.cal-status-confirmed { background: var(--cal-confirmed-fill); border-color: var(--cal-confirmed-edge); }
#project-calendar .fc-event.cal-status-pending   { background: var(--cal-pending-fill);   border-color: var(--cal-pending-edge); }
#project-calendar .fc-event.cal-status-none      { background: var(--cal-none-fill);      border-color: var(--cal-none-edge); }
#project-calendar .fc-event.cal-status-pending .fc-event-title,
#project-calendar .fc-event.cal-status-pending .fc-event-time { color: var(--cal-pending-ink); }

.users-section { margin-bottom: 30px; }
.users-section h2 {
    margin-top: 0;
    margin-bottom: 20px;
    font-size: 20px;
}
.table-wrapper {
    overflow-x: auto;
    border-radius: 8px;
    border: 1px solid var(--border);
}
.admin-table {
    width: 100%;
    border-collapse: collapse;
    background: var(--surface);
}
.admin-table thead { background: var(--table-head-bg); }
.admin-table th {
    padding: 15px;
    text-align: left;
    font-weight: 600;
    color: var(--text);
    border-bottom: 2px solid var(--border);
    font-size: 14px;
}
.admin-table tbody tr {
    border-bottom: 1px solid var(--border);
    transition: background 0.2s;
}
.admin-table tbody tr:hover { background: var(--surface-3); }
.admin-table td { padding: 15px; font-size: 14px; }

.admin-table th.sortable-col {
    cursor: pointer;
    user-select: none;
    position: relative;
    padding-right: 24px;
}
.admin-table th.sortable-col:hover { color: var(--link); }
.admin-table th.sortable-col::after {
    content: '\2195';
    position: absolute;
    right: 8px;
    opacity: 0.4;
    font-size: 11px;
}
.admin-table th.sortable-col.sort-asc::after { content: '\2191'; opacity: 1; color: var(--link); }
.admin-table th.sortable-col.sort-desc::after { content: '\2193'; opacity: 1; color: var(--link); }

/* Drag-to-reorder column headers (invoice_list.html) */
.admin-table th.draggable-col { cursor: grab; }
.admin-table th.draggable-col.dragging { cursor: grabbing; opacity: 0.4; }
.admin-table th.draggable-col.drag-over { box-shadow: inset 3px 0 0 var(--accent); }

.user-type {
    display: inline-block;
    padding: 6px 12px;
    border-radius: 4px;
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}
.user-type.admin { background: color-mix(in srgb, var(--negative) var(--badge-tint), var(--surface)); color: var(--negative); }
.user-type.approver { background: color-mix(in srgb, var(--warning) var(--badge-tint), var(--surface)); color: var(--warning); }
.user-type.standard { background: color-mix(in srgb, var(--accent) var(--badge-tint), var(--surface)); color: var(--accent); }

/* Status badges (invoices) */
.status-badge {
    display: inline-block;
    padding: 6px 12px;
    border-radius: 4px;
    font-size: 12px;
    font-weight: 600;
}
.status-badge.draft { background: color-mix(in srgb, var(--text-muted) var(--badge-tint), var(--surface)); color: var(--text-muted); }
.status-badge.pending { background: color-mix(in srgb, var(--warning) var(--badge-tint), var(--surface)); color: var(--warning); }
.status-badge.ready { background: color-mix(in srgb, var(--positive) var(--badge-tint), var(--surface)); color: var(--positive); }
.status-badge.sent { background: color-mix(in srgb, var(--accent) var(--badge-tint), var(--surface)); color: var(--accent); }
.status-badge.viewed { background: color-mix(in srgb, var(--info) var(--badge-tint), var(--surface)); color: var(--info); }
.status-badge.paid { background: color-mix(in srgb, var(--positive) var(--badge-tint), var(--surface)); color: var(--positive); }
.status-badge.overdue { background: color-mix(in srgb, var(--negative) var(--badge-tint), var(--surface)); color: var(--negative); }
.status-badge.accepted { background: color-mix(in srgb, var(--positive) var(--badge-tint), var(--surface)); color: var(--positive); }
.status-badge.closed { background: color-mix(in srgb, var(--text-muted) var(--badge-tint), var(--surface)); color: var(--text-muted); }
.status-badge.rejected { background: color-mix(in srgb, var(--negative) var(--badge-tint), var(--surface)); color: var(--negative); }
.status-badge.unpaid { background: color-mix(in srgb, var(--warning) var(--badge-tint), var(--surface)); color: var(--warning); }

/* Buttons */
.btn {
    padding: 10px 16px;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    font-size: 14px;
    font-weight: 500;
    transition: all 0.2s;
    text-decoration: none;
    display: inline-block;
    text-align: center;
}
.btn:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 12px var(--shadow-soft);
    color: var(--on-accent);
}
.btn:active { transform: translateY(0); }
.btn-primary { background: var(--accent); color: var(--on-accent); }
.btn-primary:hover { background: var(--accent-hover); }
.btn-cancel { background: var(--neutral-bg); color: var(--on-neutral); }
.btn-cancel:hover { background: var(--neutral-hover); }
.btn-danger { background: var(--danger); color: var(--on-accent); }
.btn-danger:hover { background: var(--danger-hover); }
.btn-sm { padding: 6px 10px; font-size: 12px; }

.action-buttons {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}
.action-buttons form { margin: 0; display: inline-flex; }

/* Dashboard month/forecast selector */
.month-selector {
    margin-top: 15px;
    display: flex;
    align-items: flex-end;
    gap: 10px;
    flex-wrap: wrap;
}
.month-selector .form-group { flex: none; min-width: 180px; }
.forecast-banner {
    margin-top: 15px;
    margin-bottom: 0;
    max-width: 650px;
}

/* Weekly Forecast page's week navigator — same layout as .month-selector, plus its
   Prev/Next buttons (disabled ones are shown as inert spans, not real <a> links). */
.week-selector { align-items: center; }

/* Chart of Accounts page's hierarchy rows — indentation is set inline per row (depth),
   this just handles the visual weight for section labels and "Total for X" subtotals. */
.coa-row.coa-header td:first-child { font-style: italic; color: var(--text-muted); }
.coa-row.coa-total td { font-weight: 700; border-top: 1px solid var(--border-subtle); }

/* Alerts */
.alert {
    padding: 12px 16px;
    margin-bottom: 20px;
    border-radius: 6px;
    border-left: 4px solid;
}
.alert-success { background: color-mix(in srgb, var(--alert-success) var(--alert-tint), var(--bg)); border-left-color: var(--alert-success); color: var(--alert-success-ink); }
.alert-error { background: color-mix(in srgb, var(--danger) var(--alert-tint), var(--bg)); border-left-color: var(--danger); color: var(--negative); }
.alert-info { background: color-mix(in srgb, var(--accent) var(--alert-tint), var(--bg)); border-left-color: var(--accent); color: var(--alert-info-ink); }
.alert-warning { background: color-mix(in srgb, var(--alert-warning) var(--alert-tint), var(--bg)); border-left-color: var(--alert-warning); color: var(--alert-warning-ink); }

/* Legal content pages */
.legal-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 30px;
    max-width: 800px;
    line-height: 1.6;
}
.legal-card h1 { font-size: 26px; margin-top: 0; }
.legal-card h2 { font-size: 18px; color: var(--accent); margin-top: 30px; }
.legal-card p, .legal-card li { color: var(--text-soft); font-size: 14px; }

/* Login page */
.login-wrapper {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    justify-content: center;
    align-items: center;
}
.login-card {
    background-color: rgba(26, 26, 26, 0.95);
    padding: 40px;
    border-radius: 15px;
    width: 100%;
    max-width: 400px;
    box-shadow: 0 10px 30px var(--shadow-strong);
}
.brand-section {
    display: flex;
    align-items: center;
    margin-bottom: 30px;
}
.brand-logo { width: 60px; height: 60px; margin-right: 15px; }
.brand-text h1 { color: var(--brand); margin: 0; font-size: 28px; font-weight: bold; }
.brand-text p { margin: 0; font-size: 16px; color: var(--text-soft); }
.sso-text { margin: 20px 0; font-size: 15px; color: var(--text-soft); text-align: center; }
.google-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    margin: 20px auto 0 auto;
    width: 100%;
    padding: 12px;
    background: #fff;
    color: #444;
    border-radius: 8px;
    border: 1px solid #ddd;
    cursor: pointer;
    font-size: 15px;
    font-weight: 500;
    transition: transform 0.2s;
}
.google-btn:hover { transform: scale(1.02); }
.mock-sso-note {
    margin-top: 16px;
    font-size: 12px;
    color: var(--text-faint);
    text-align: center;
}

/* Responsive */
@media (max-width: 768px) {
    .main-content { margin-left: 0; padding: 68px 15px 15px 15px; }
    .sidebar { transform: translateX(-210px); transition: transform 0.25s ease; z-index: 1100; }
    .sidebar.open { transform: translateX(0); box-shadow: 4px 0 24px var(--shadow-strong); }
    .sidebar-toggle-btn { display: flex !important; }
    .sidebar-close-btn { display: block; }
    .form-group { min-width: 100%; }
}

.sidebar-toggle-btn {
    display: none;
    position: fixed;
    top: 14px;
    left: 14px;
    z-index: 1200;
    background: var(--surface);
    border: 1px solid var(--border-strong);
    color: var(--text);
    border-radius: 8px;
    width: 42px;
    height: 42px;
    font-size: 20px;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    line-height: 1;
}
.sidebar-close-btn {
    display: none;
    position: absolute;
    top: 12px;
    right: 12px;
    background: transparent;
    border: none;
    color: var(--text-muted);
    font-size: 24px;
    cursor: pointer;
    line-height: 1;
    padding: 4px 8px;
}

/* Confirm dialog modal */
.modal-backdrop {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: var(--overlay);
    z-index: 2000;
    align-items: center;
    justify-content: center;
}
.modal-backdrop.visible {
    display: flex;
}
.modal-box {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 24px;
    max-width: 400px;
    width: 90%;
    box-shadow: 0 10px 30px var(--shadow-strong);
}
.modal-box p {
    margin: 0 0 20px 0;
    font-size: 15px;
    line-height: 1.5;
    /* Preserves line breaks in a multi-line message (e.g. one warning per payment schedule
    row) while still wrapping normally — has no effect on existing single-line messages. */
    white-space: pre-line;
}
.modal-actions {
    justify-content: flex-end;
}
.sidebar-close-btn:hover { color: var(--text); }
.sidebar-backdrop {
    display: none;
    position: fixed;
    inset: 0;
    background: var(--overlay);
    z-index: 1050;
}
.sidebar-backdrop.visible { display: block; }

/* FullCalendar's toolbar buttons share one text colour across every state, so
   in the light theme they're filled with the accent rather than the light
   neutral — that keeps white button text legible on the active button and the
   inactive ones alike. */
:root[data-theme="light"] #project-calendar {
    --fc-button-bg-color: var(--accent);
    --fc-button-border-color: var(--accent);
    --fc-button-hover-bg-color: var(--accent-hover);
    --fc-button-hover-border-color: var(--accent-hover);
    --fc-button-active-bg-color: var(--accent-strong);
    --fc-button-active-border-color: var(--accent-strong);
}

/* Light/dark theme switch (sidebar footer). The button carries
   role="switch" + aria-checked, which is what the script in core/base.html
   keeps in step with the data-theme attribute on <html>. */
.theme-switch {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-top: auto;
    padding: 20px 20px 0 20px;
}
/* With the switch present it takes over as the element that pushes the footer
   to the bottom of the sidebar. */
.theme-switch ~ .sidebar-footer-links { margin-top: 0; }
.theme-switch-label {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    color: var(--text-muted);
}
.theme-switch-track {
    position: relative;
    flex: none;
    width: 46px;
    height: 26px;
    padding: 0;
    border: 1px solid var(--border-strong);
    border-radius: 999px;
    background: var(--surface-3);
    cursor: pointer;
    transition: background 0.2s, border-color 0.2s;
}
.theme-switch-track:hover { border-color: var(--accent); }
.theme-switch-track:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}
.theme-switch-knob {
    position: absolute;
    top: 2px;
    left: 2px;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: var(--text);
    color: var(--surface);
    font-size: 10px;
    transition: transform 0.2s ease;
}
.theme-switch-track[aria-checked="true"] .theme-switch-knob { transform: translateX(20px); }
.theme-switch-track .theme-switch-icon-light { display: none; }
.theme-switch-track[aria-checked="true"] .theme-switch-icon-dark { display: none; }
.theme-switch-track[aria-checked="true"] .theme-switch-icon-light { display: block; }
@media (prefers-reduced-motion: reduce) {
    .theme-switch-knob { transition: none; }
}

/* A button whose label is preceded by an icon image (e.g. Slack alert on Project
   Views) — .btn is inline-block/centred text, which can't align the two. */
.btn-with-icon {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}
.btn-icon {
    flex: none;
    width: 16px;
    height: 16px;
    display: block;
}

/* The browser's own [hidden] rule is display:none, but any author rule setting a
   display (e.g. .form-group's flex) outranks it and the element stays on screen.
   Pinning it here means `el.hidden = true` reliably hides an element whatever
   classes it carries — which is how the Slack alert dialog shows one alert type's
   fields at a time. */
[hidden] {
    display: none !important;
}

/* A disabled button has to read as disabled — .btn otherwise renders one exactly
   like a live one, hover lift included. */
.btn:disabled,
.btn[disabled] {
    opacity: 0.5;
    cursor: not-allowed;
}
.btn:disabled:hover,
.btn[disabled]:hover {
    transform: none;
    box-shadow: none;
}

/* ---------------------------------------------------------------------------
   Halloween decoration for the login screen (templates/accounts/_halloween.html).
   Seasonal and self-retiring — accounts.views._halloween_active decides when it
   renders at all, so deleting it later is just these rules, that template and
   that helper. Nothing here is reused anywhere else.
   --------------------------------------------------------------------------- */
/* Shared by every seasonal overlay. Decoration only: it sits behind the sign-in card
   and every click goes straight through to the page beneath. */
.season-overlay {
    position: fixed;
    inset: 0;
    z-index: 1;
    overflow: hidden;
    pointer-events: none;
}
.login-wrapper .login-card {
    position: relative;
    z-index: 2;
}

/* Warm pumpkin light behind the card, over the dark background photograph. */
.halloween-glow {
    position: absolute;
    left: 50%;
    top: 50%;
    width: min(900px, 120vw);
    height: min(900px, 120vw);
    transform: translate(-50%, -50%);
    background: radial-gradient(circle, rgba(255, 117, 24, 0.17) 0%, rgba(255, 117, 24, 0.07) 42%, transparent 68%);
}

.halloween-web {
    position: absolute;
    top: 0;
    width: clamp(120px, 18vw, 230px);
    height: clamp(120px, 18vw, 230px);
    color: #d7dbe6;
    opacity: 0.4;
}
/* The anchor threads are the heavier ones; the spiral between them is finer, which
   is what stops the whole thing reading as a fan of lines. */
.halloween-web-radials { stroke-width: 1.1; }
.halloween-web-threads { stroke-width: 0.8; opacity: 0.85; }
.halloween-web-left { left: 0; }
/* Same drawing mirrored, rather than a second corner's worth of path data. */
.halloween-web-right { right: 0; transform: scaleX(-1); }

.halloween-spider {
    position: absolute;
    top: 0;
    right: clamp(70px, 12vw, 150px);
    display: flex;
    flex-direction: column;
    align-items: center;
    color: #d7dbe6;
    opacity: 0.5;
    transform-origin: top center;
    animation: halloween-spider-sway 6s ease-in-out infinite;
}
.halloween-spider-thread {
    width: 1px;
    height: clamp(60px, 11vh, 120px);
    background: currentColor;
}
.halloween-spider-body { width: 34px; height: 29px; margin-top: -2px; }
@keyframes halloween-spider-sway {
    0%, 100% { transform: rotate(-3.5deg); }
    50% { transform: rotate(3.5deg); }
}

/* Each bat drifts right to left; the inner element squashes to suggest wingbeats,
   which reads better at this size than animating the wings themselves would. */
.halloween-bat {
    position: absolute;
    left: 0;
    color: #cdc8dc;
    opacity: 0.45;
    will-change: transform;
    animation: halloween-bat-drift linear infinite;
}
.halloween-bat-flap { animation: halloween-bat-flap 0.42s ease-in-out infinite; }
.halloween-bat-svg { display: block; width: 100%; height: auto; }

.halloween-bat-1 { top: 15%; width: 72px; animation-duration: 19s; animation-delay: -2s; }
.halloween-bat-2 { top: 30%; width: 46px; opacity: 0.32; animation-duration: 26s; animation-delay: -11s; }
.halloween-bat-2 .halloween-bat-flap { animation-duration: 0.56s; }
.halloween-bat-3 { top: 69%; width: 58px; animation-duration: 23s; animation-delay: -17s; }
.halloween-bat-3 .halloween-bat-flap { animation-duration: 0.49s; }

@keyframes halloween-bat-drift {
    /* Starts and ends fully off-screen, so a bat never pops in or out mid-air. */
    0% { transform: translateX(115vw) translateY(0); }
    25% { transform: translateX(86vw) translateY(-26px); }
    50% { transform: translateX(57vw) translateY(14px); }
    75% { transform: translateX(28vw) translateY(-18px); }
    100% { transform: translateX(-12vw) translateY(0); }
}
@keyframes halloween-bat-flap {
    0%, 100% { transform: scaleY(1); }
    50% { transform: scaleY(0.52); }
}

@media (prefers-reduced-motion: reduce) {
    /* The webs, spider and glow stay — only the movement goes. */
    .halloween-spider,
    .halloween-bat,
    .halloween-bat-flap {
        animation: none;
    }
    .halloween-bat-1 { transform: translateX(72vw); }
    .halloween-bat-2 { transform: translateX(22vw); }
    .halloween-bat-3 { transform: translateX(48vw); }
}

/* ---------------------------------------------------------------------------
   Christmas decoration for the login screen (templates/accounts/_christmas.html).
   Seasonal and self-retiring — SEASONAL_THEMES in accounts/views.py decides when
   it renders at all, so removing it later is just these rules, that template and
   that entry. Nothing here is reused anywhere else.

   The wire path, the bulbs' positions and the snow scatter are all generated from
   one sag formula and a seeded shuffle, so the bulbs stay on the wire at any width
   and the snow doesn't need 46 hand-written rules — each flake carries its own
   custom properties inline and shares the single .xmas-flake rule below.
   --------------------------------------------------------------------------- */
.xmas-glow {
    position: absolute;
    left: 50%;
    top: 50%;
    width: min(1000px, 130vw);
    height: min(1000px, 130vw);
    transform: translate(-50%, -50%);
    background: radial-gradient(circle, rgba(120, 170, 255, 0.16) 0%, rgba(90, 140, 230, 0.07) 45%, transparent 70%);
}

/* Fairy lights ----------------------------------------------------------- */
.xmas-lights {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 96px;
    color: #6b7384;
}
.xmas-wire {
    display: block;
    width: 100%;
    height: 96px;
}
.xmas-bulb {
    position: absolute;
    left: var(--x);
    top: var(--y);
    width: 11px;
    height: 15px;
    margin-left: -5.5px;
    border-radius: 50% 50% 48% 48% / 42% 42% 58% 58%;
    background: currentColor;
    /* The glow is the bulb's own colour, so each one lights its patch of sky. */
    box-shadow: 0 0 10px 2px currentColor, 0 0 22px 6px currentColor;
    animation: xmas-twinkle 3.4s ease-in-out infinite;
    animation-delay: var(--twinkle-delay);
}
/* The cap the bulb hangs from, so it meets the wire rather than floating under it. */
.xmas-bulb::before {
    content: "";
    position: absolute;
    left: 50%;
    top: -4px;
    width: 5px;
    height: 5px;
    margin-left: -2.5px;
    border-radius: 1px;
    background: #6b7384;
    box-shadow: none;
}
.xmas-bulb-red { color: #ff4d4d; }
.xmas-bulb-green { color: #3fd07a; }
.xmas-bulb-gold { color: #ffc23d; }
.xmas-bulb-blue { color: #58a6ff; }
.xmas-bulb-white { color: #fff4d6; }
@keyframes xmas-twinkle {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.45; }
}

/* Snow ------------------------------------------------------------------- */
.xmas-snow {
    position: absolute;
    inset: 0;
}
.xmas-flake {
    position: absolute;
    top: -12px;
    left: var(--x);
    width: var(--size);
    height: var(--size);
    border-radius: 50%;
    background: #fff;
    opacity: var(--opacity);
    /* Fall and sway are separate animations on one element: the fall is linear and
       never resets mid-screen, while the sideways drift runs on its own slower cycle,
       which is what stops 46 flakes descending in visible lockstep. */
    animation: xmas-fall var(--fall) linear infinite, xmas-sway var(--sway) ease-in-out infinite alternate;
    animation-delay: var(--delay), var(--delay);
    will-change: transform;
}
@keyframes xmas-fall {
    from { transform: translateY(-5vh); }
    to { transform: translateY(105vh); }
}
@keyframes xmas-sway {
    from { margin-left: 0; }
    to { margin-left: var(--drift); }
}

/* Settled snow along the bottom edge ------------------------------------- */
.xmas-drift {
    position: absolute;
    left: -2%;
    right: -2%;
    bottom: -42px;
    height: 110px;
    background: rgba(255, 255, 255, 0.82);
    border-radius: 50% 50% 0 0 / 70% 70% 0 0;
    /* Blurred rather than crisp: a hard curved edge reads as a grey hill sitting on
       the photograph, where a soft one reads as snow banked against the bottom. */
    filter: blur(9px);
    opacity: 0.2;
}

@media (prefers-reduced-motion: reduce) {
    /* The lights, the settled snow and the glow stay — only the movement goes, with
       the flakes frozen partway down rather than hidden. */
    .xmas-bulb,
    .xmas-flake {
        animation: none;
    }
    .xmas-flake { transform: translateY(42vh); margin-left: var(--drift); }
}

/* Profile pictures (templates/core/_avatar.html) — hotlinked from Google Workspace,
   with the person's initials showing through if the picture can't be loaded. */
.avatar {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    border-radius: 50%;
    overflow: hidden;
    background: var(--surface-3);
    border: 1px solid var(--border-strong);
    color: var(--text-muted);
    font-weight: 600;
    line-height: 1;
    user-select: none;
}
.avatar-initials { letter-spacing: 0.02em; }
/* Covers the initials when it loads, uncovers them when it doesn't. */
.avatar-img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.avatar-sm { width: 28px; height: 28px; font-size: 11px; }
.avatar-xs { width: 18px; height: 18px; font-size: 8px; border-width: 0; }

/* The logout row carries the signed-in user's picture beside it. Selectors are as
   specific as the generic sidebar rules above (.sidebar nav ul li, .sidebar nav ul li
   .link-button), which would otherwise win on specificity and flatten the padding. */
.sidebar nav ul li.sidebar-user {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 0 20px;
}
.sidebar nav ul li.sidebar-user form { flex: 1; min-width: 0; }
.sidebar nav ul li.sidebar-user .link-button { padding-left: 0; }

/* The production lead's picture on a calendar event (projects/project_list.html). */
.calendar-event {
    display: flex;
    align-items: center;
    gap: 5px;
    min-width: 0;
    padding: 1px 2px;
}
.calendar-event .avatar {
    /* The event's own colour is the background here, so the initials need to read on
       it rather than on a card. */
    background: rgba(0, 0, 0, 0.25);
    color: #fff;
}
.calendar-event-title {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* Technicians on the job, stacked right after the production lead and before the
   title. The title shrinks first, so the faces stay visible on a short event. */
.calendar-event-title { flex: 1 1 auto; min-width: 0; }
.calendar-event-techs {
    display: inline-flex;
    align-items: center;
    flex: none;
}
.calendar-event-techs .avatar + .avatar { margin-left: -5px; }
.calendar-event-techs .avatar { box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.35); }
.calendar-event-techs-more {
    margin-left: 3px;
    font-size: 10px;
    font-weight: 600;
    color: #fff;
}

/* Key for the project calendar's event colours (projects/project_list.html). */
.calendar-key {
    display: flex;
    flex-wrap: wrap;
    gap: 10px 26px;
    margin-top: 16px;
    padding-top: 14px;
    border-top: 1px solid var(--border);
}
.calendar-key-group {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 14px;
    min-width: 0;
}
.calendar-key-heading {
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted);
}
.calendar-key-heading small { font-weight: 400; text-transform: none; letter-spacing: 0; }
.calendar-key-item {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-size: 13px;
    white-space: nowrap;
}
.calendar-key-swatch {
    width: 12px;
    height: 12px;
    flex: none;
    border-radius: 3px;
    /* Matches the events: translucent fill, solid edge. The edge also stops a pale
       swatch disappearing against the card behind it. The swatch carries the same
       cal-status-* class as the events, so the key cannot drift from what is drawn. */
    border: 1px solid;
}
.calendar-key-swatch.cal-status-confirmed { background: var(--cal-confirmed-fill); border-color: var(--cal-confirmed-edge); }
.calendar-key-swatch.cal-status-pending   { background: var(--cal-pending-fill);   border-color: var(--cal-pending-edge); }
.calendar-key-swatch.cal-status-none      { background: var(--cal-none-fill);      border-color: var(--cal-none-edge); }

/* Job Type filter above the calendar */
.calendar-filters {
    margin-bottom: 16px;
    padding-bottom: 14px;
    border-bottom: 1px solid var(--border);
}
.calendar-filters-head {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px 14px;
    margin-bottom: 10px;
}
.calendar-filter-state {
    font-size: 13px;
    color: var(--accent);
}
.calendar-filter-options {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 18px;
}
.calendar-filter-option {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-size: 13px;
    font-weight: 400;
    white-space: nowrap;
    cursor: pointer;
}
.calendar-filter-count {
    font-size: 11px;
    color: var(--text-faint);
    background: var(--neutral-hover);
    border-radius: 10px;
    padding: 1px 7px;
}

/* Year view (multiMonthYear). The rules above style .fc-daygrid-* only, so without
   these the twelve month blocks fall back to FullCalendar's own ink, which is unreadable
   on the dark theme. */
#project-calendar .fc-multimonth {
    border-color: var(--border);
}
#project-calendar .fc-multimonth-title {
    color: var(--text);
    font-weight: 600;
    background: transparent;
}
#project-calendar .fc-multimonth-daygrid {
    background: transparent;
}
#project-calendar .fc-multimonth-daygrid .fc-daygrid-day-number {
    color: var(--text);
}
#project-calendar .fc-multimonth-daygrid .fc-day-other .fc-daygrid-day-number {
    color: var(--text-faint);
}
/* A year's worth of events can only be colour, not text — a title is unreadable in a
   cell this size. The bar itself is built in project_list.html's eventContent rather
   than hidden here, because FullCalendar measures the rendered event to decide whether
   to collapse the day into a "+2 more" link, and CSS applied afterwards is too late. */
#project-calendar .fc-multimonth .fc-event {
    padding: 0;
}
/* In the year grid the bar is colour only — the name it carries is clipped away, since
   no title is legible in a cell this size. The popover below undoes this. */
#project-calendar .calendar-event-bar {
    height: 5px;
    border-radius: 2px;
    font-size: 0;
    line-height: 0;
    overflow: hidden;
}
/* On a busy day FullCalendar collapses the rest into a "+2 more" link, which opens a
   popover listing them. Left in place — it is the only thing that fits in a year cell
   and it still says the day is busy — but restyled, because its default is a blue link
   that is unreadable against the dark theme and far too loud at this size. */
#project-calendar .fc-multimonth .fc-daygrid-more-link {
    font-size: 10px;
    line-height: 1.2;
    padding: 0 2px;
    color: var(--text-muted);
    background: var(--neutral-hover);
    border-radius: 3px;
}
#project-calendar .fc-multimonth .fc-daygrid-more-link:hover {
    color: var(--text);
}
/* The popover it opens shows full event titles, so it keeps the ordinary styling the
   month view uses rather than the year view's bar-only treatment. */
#project-calendar .fc-popover {
    background: var(--surface);
    border: 1px solid var(--border);
}
#project-calendar .fc-popover-title,
#project-calendar .fc-popover-header {
    color: var(--text);
    background: var(--table-head-bg);
}
/* Inside the popover the same node becomes a readable line — this is the one place in
   year view where there is room for the job's name. */
#project-calendar .fc-popover .calendar-event-bar {
    height: auto;
    font-size: 12px;
    line-height: 1.4;
    padding: 1px 4px;
    overflow: visible;
    color: var(--text);
}

/* Contact Directory (templates/contacts/) */

/* Grouped navigation: the parent opens a second panel beside the sidebar.

   Specificity here matches `.sidebar nav ul li a` so these win without !important —
   the same trap that made .sidebar-user need matching specificity. */
.sidebar nav ul li.nav-group { position: relative; }

/* The parent is a <button>, so it needs the anchor styling applying by hand. */
.sidebar nav ul li.nav-group > .nav-group-toggle {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 12px 20px;
    background: none;
    border: 0;
    font: inherit;
    text-align: left;
    color: var(--text);
    cursor: pointer;
}
.sidebar nav ul li.nav-group > .nav-group-toggle:hover,
.sidebar nav ul li.nav-group.is-open > .nav-group-toggle {
    background: var(--neutral-hover);
}
/* The page you are on lives inside this group — the parent says so even while closed. */
.sidebar nav ul li.nav-group.is-current > .nav-group-toggle {
    color: var(--accent);
}
.nav-group-chevron {
    margin-left: auto;
    font-size: 11px;
    color: var(--text-faint);
    transition: transform 0.15s ease;
}
.sidebar nav ul li.nav-group.is-open .nav-group-chevron { transform: rotate(90deg); }

/* The second panel. Hidden by default rather than display:none-d from a class, so the
   closed state needs no JavaScript to be correct on first paint. */
.sidebar nav ul li.nav-group > ul.nav-flyout {
    display: none;
    list-style: none;
    margin: 0;
    padding: 8px 0;
    position: absolute;
    top: 0;
    left: 100%;
    min-width: 215px;
    background: var(--surface);
    border-left: 1px solid var(--border);
    border-radius: 0 10px 10px 0;
    box-shadow: 6px 0 18px var(--shadow-soft);
    z-index: 1001;
}
.sidebar nav ul li.nav-group.is-open > ul.nav-flyout { display: block; }
.nav-flyout-title {
    padding: 6px 20px 10px;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-faint);
}
.sidebar nav ul li.nav-group > ul.nav-flyout li a {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 20px;
    font-size: 14px;
    white-space: nowrap;
    color: var(--text);
}
.sidebar nav ul li.nav-group > ul.nav-flyout li a:hover {
    background: var(--neutral-hover);
}

@media (max-width: 768px) {
    /* The sidebar is the whole drawer at this width, so there is nothing to the right of
       it to fly out into. The panel expands underneath the parent instead — same markup,
       and the only pattern that fits a phone. */
    .sidebar nav ul li.nav-group > ul.nav-flyout {
        position: static;
        min-width: 0;
        border-left: 0;
        border-radius: 0;
        box-shadow: none;
        padding: 2px 0 6px;
        background: var(--table-head-bg);
    }
    .nav-flyout-title { display: none; }
    .sidebar nav ul li.nav-group > ul.nav-flyout li a { padding-left: 44px; font-size: 13px; }
}

/* The three directories, as a tab strip at the top of each sub-page. */
.directory-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 22px;
    border-bottom: 1px solid var(--border);
    padding-bottom: 0;
}
.directory-tab {
    padding: 9px 16px;
    border-radius: 8px 8px 0 0;
    font-size: 14px;
    font-weight: 500;
    color: var(--text-muted);
    text-decoration: none;
    /* Transparent rather than absent, so the tab doesn't move by 2px when it becomes
       active. */
    border-bottom: 2px solid transparent;
}
.directory-tab:hover { color: var(--text); background: var(--neutral-hover); }
.directory-tab.is-active {
    color: var(--text);
    background: var(--surface);
    border-bottom-color: var(--accent);
}

/* Expenses (templates/expenses/) */
.expense-thumb {
    width: 44px;
    height: 44px;
    object-fit: cover;
    border-radius: 6px;
    border: 1px solid var(--border);
    display: block;
}
.expense-review {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 20px;
    align-items: start;
}
.expense-receipt-image {
    width: 100%;
    max-height: 70vh;
    object-fit: contain;
    border-radius: 8px;
    border: 1px solid var(--border);
    /* Receipts are photographed on white paper; a light mat keeps a dark theme from
       making the edges of the photo disappear into the card. */
    background: var(--surface-3);
    display: block;
}
.expense-approval {
    margin-top: 20px;
    padding-top: 4px;
    border-top: 1px solid var(--border);
}
@media (max-width: 900px) {
    .expense-review { grid-template-columns: minmax(0, 1fr); }
}

/* Count of items needing attention, on a sidebar nav item. */
.nav-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 19px;
    height: 19px;
    margin-left: auto;
    padding: 0 6px;
    border-radius: 999px;
    background: var(--negative);
    color: var(--on-accent);
    font-size: 11px;
    font-weight: 700;
    line-height: 1;
}

/* ---------------------------------------------------------------------------
   Installed-app (home screen) safe areas.

   Launched from an iPhone home screen the page covers the whole screen, notch and
   home indicator included (viewport-fit=cover in core/base.html). These keep content
   out from under them. env() resolves to 0 in a normal browser window and on any
   device without insets, so none of this changes the desktop layout.
   --------------------------------------------------------------------------- */
.sidebar {
    padding-top: calc(30px + env(safe-area-inset-top, 0px));
}
.sidebar-footer-links {
    padding-bottom: calc(40px + env(safe-area-inset-bottom, 0px));
}
.sidebar-close-btn {
    top: calc(12px + env(safe-area-inset-top, 0px));
}
.sidebar-toggle-btn {
    top: calc(14px + env(safe-area-inset-top, 0px));
    left: calc(14px + env(safe-area-inset-left, 0px));
}
@media (max-width: 768px) {
    .main-content {
        /* 68px already clears the floating menu button; the inset clears the notch. */
        padding-top: calc(68px + env(safe-area-inset-top, 0px));
        padding-bottom: calc(15px + env(safe-area-inset-bottom, 0px));
        padding-left: calc(15px + env(safe-area-inset-left, 0px));
        padding-right: calc(15px + env(safe-area-inset-right, 0px));
    }
}

/* Settings link, sitting with the theme switch at the foot of the sidebar rather than
   among the main navigation. Matches the nav links without being inside that list. */
.sidebar-bottom-link {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: auto;
    padding: 10px 20px 0 20px;
    color: var(--text) !important;
    text-decoration: none !important;
    font-size: 16px;
    font-weight: 500;
}
.sidebar-bottom-link:hover { color: var(--accent) !important; }
/* With the link present it takes over pushing the footer to the bottom. */
.sidebar-bottom-link ~ .theme-switch { margin-top: 0; }

.avatar-lg { width: 84px; height: 84px; font-size: 28px; }
.settings-avatar-row {
    display: flex;
    align-items: flex-start;
    gap: 20px;
    margin-top: 16px;
    flex-wrap: wrap;
}
.settings-avatar-fields { flex: 1; min-width: 240px; }
/* Alert subscriptions, shown as sliding switches to match the alerts page in
   mission-gateway-alerts. The control is a real checkbox with its native appearance
   removed — so it still posts with the form, still takes keyboard focus, and is still
   announced as a checkbox, none of which a <div> styled to look like a switch would be. */
.toggle-group { margin-top: 10px; }
.toggle-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    padding: 16px 0;
    border-bottom: 1px solid var(--border);
}
.toggle-item:last-child { border-bottom: none; }
.toggle-label {
    display: flex;
    flex-direction: column;
    cursor: pointer;
    min-width: 0;
}
.toggle-label .title {
    font-weight: 600;
    font-size: 16px;
    color: var(--text);
    margin-bottom: 4px;
}
.toggle-label .description {
    font-size: 13px;
    color: var(--text-faint);
}

.toggle-switch {
    position: relative;
    flex: none;
    appearance: none;
    -webkit-appearance: none;
    width: 50px;
    height: 28px;
    margin: 0;
    padding: 0;
    border: none;
    border-radius: 14px;
    background-color: var(--neutral-bg);
    cursor: pointer;
    transition: background-color 0.3s;
}
.toggle-switch:checked { background-color: var(--accent); }
.toggle-switch::after {
    content: "";
    position: absolute;
    top: 2px;
    left: 2px;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    /* Stays white in both themes: it reads against the accent and the neutral alike. */
    background-color: #fff;
    transition: left 0.3s;
}
.toggle-switch:checked::after { left: 24px; }
.toggle-switch:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 3px;
}
@media (prefers-reduced-motion: reduce) {
    .toggle-switch, .toggle-switch::after { transition: none; }
}

/* A Save button that has been pressed: greyed out and inert until the next page
   arrives, so an impatient second click can't reach it (templates/core/base.html).
   Deliberately not the disabled attribute — see the comment on that handler. */
.btn.is-saving,
button.is-saving,
input.is-saving {
    opacity: 0.55;
    pointer-events: none;
    cursor: progress;
}
.btn.is-saving:hover {
    transform: none;
    box-shadow: none;
}

/* ---------------------------------------------------------------------------
   Header bar across the top of every page: search, alerts, help
   (templates/core/base.html).
   --------------------------------------------------------------------------- */
.app-header {
    display: flex;
    align-items: center;
    gap: 16px;
    margin: -10px 0 22px 0;
    padding-bottom: 14px;
    border-bottom: 1px solid var(--border);
}

/* Search --------------------------------------------------------------- */
.app-search {
    position: relative;
    flex: 1;
    min-width: 0;
    max-width: 520px;
}
.app-search-icon {
    position: absolute;
    left: 12px;
    top: 50%;
    transform: translateY(-50%);
    font-size: 13px;
    color: var(--text-faint);
    pointer-events: none;
}
.app-search input {
    width: 100%;
    padding: 10px 12px 10px 34px;
    background: var(--surface-2);
    border: 1px solid var(--border-strong);
    border-radius: 8px;
    color: var(--text);
    font-size: 14px;
    font-family: inherit;
}
.app-search input:focus {
    outline: none;
    border-color: var(--accent-strong);
    box-shadow: 0 0 0 3px var(--focus-ring);
}
.app-search-results {
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    right: 0;
    z-index: 1500;
    max-height: 60vh;
    overflow-y: auto;
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: 10px;
    box-shadow: 0 10px 30px var(--shadow-strong);
}
.app-search-group {
    padding: 10px 12px 4px;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted);
}
.app-search-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 12px;
    color: var(--text) !important;
    text-decoration: none !important;
}
.app-search-item:hover,
.app-search-item:focus-visible {
    background: var(--surface-3);
    outline: none;
}
.app-search-item i { flex: none; width: 16px; color: var(--text-muted); }
.app-search-label { display: block; font-size: 14px; }
.app-search-sub { display: block; font-size: 12px; color: var(--text-faint); }
.app-search-empty { margin: 0; padding: 14px 12px; font-size: 13px; color: var(--text-muted); }

/* Bell and help --------------------------------------------------------- */
.app-header-actions {
    position: relative;
    display: flex;
    align-items: center;
    gap: 8px;
    margin-left: auto;
}
.app-header-btn {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    background: var(--surface-2);
    border: 1px solid var(--border-strong);
    border-radius: 9px;
    color: var(--text);
    font-size: 16px;
    cursor: pointer;
}
.app-header-btn:hover { border-color: var(--accent); color: var(--accent); }
.app-header-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.app-header-badge {
    position: absolute;
    top: -5px;
    right: -5px;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    border-radius: 999px;
    background: var(--negative);
    color: var(--on-accent);
    font-size: 11px;
    font-weight: 700;
    line-height: 18px;
}

.alerts-panel {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    z-index: 1500;
    width: min(380px, 90vw);
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: 12px;
    box-shadow: 0 10px 30px var(--shadow-strong);
    overflow: hidden;
}
.alerts-panel-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 12px 14px;
    border-bottom: 1px solid var(--border);
}
.alerts-panel-body { max-height: 56vh; overflow-y: auto; }
.alert-item {
    display: flex;
    align-items: stretch;
    border-bottom: 1px solid var(--border-subtle);
}
.alert-item:last-child { border-bottom: none; }
/* Read alerts stay in the list but recede, so the ones still needing attention stand out. */
.alert-item.is-read { opacity: 0.5; }
.alert-item-main {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    flex: 1;
    min-width: 0;
    padding: 12px 14px;
    color: var(--text) !important;
    text-decoration: none !important;
}
.alert-item-main:hover { background: var(--surface-3); }
.alert-item-main > i { flex: none; width: 16px; margin-top: 2px; color: var(--accent); }
.alert-item-title { display: block; font-size: 14px; font-weight: 600; }
.alert-item-body { display: block; font-size: 12px; color: var(--text-faint); margin-top: 2px; }
.alert-item-read {
    flex: none;
    width: 40px;
    background: none;
    border: none;
    border-left: 1px solid var(--border-subtle);
    color: var(--text-muted);
    cursor: pointer;
}
.alert-item-read:hover { color: var(--positive); background: var(--surface-3); }

/* Help dialogue --------------------------------------------------------- */
.help-section { padding: 18px 0; border-bottom: 1px solid var(--border); }
.help-section:last-child { border-bottom: none; padding-bottom: 0; }
.help-section h3 {
    display: flex;
    align-items: center;
    gap: 9px;
    margin: 0 0 8px 0;
    font-size: 16px;
    color: var(--accent);
}
.help-what { margin: 0 0 10px 0; font-size: 14px; color: var(--text-soft); }
.help-how { margin: 0; padding-left: 20px; }
.help-how li { font-size: 13px; color: var(--text-muted); margin-bottom: 6px; line-height: 1.5; }

@media (max-width: 768px) {
    /* The floating menu button sits top-left, so the bar starts below it. */
    .app-header { flex-wrap: wrap; margin-top: 0; }
    .app-search { max-width: none; order: 2; flex-basis: 100%; }
    .app-header-actions { order: 1; margin-left: 0; }
}

/* Archived projects: server-side search and paging (projects/views.py _archived_page). */
.archived-search { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 12px; }
.archived-search input[type=search] { max-width: 320px; flex: 1 1 220px; }
.archived-count { color: var(--text-muted); font-size: 13px; }
.archived-pager { display: flex; align-items: center; justify-content: center; gap: 14px; margin: 14px 0 4px; color: var(--text-muted); font-size: 13px; }

/* ---------------------------------------------------------------------------
   Editable rate tables (Sales → rental list / file transfer, Tools → data rates)
   — static/js/editable_table.js
   --------------------------------------------------------------------------- */
.et-toolbar { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-bottom: 12px; }
.et-search { flex: 1 1 260px; max-width: 420px; }
.et-last-edit { margin-left: auto; font-size: 12px; color: var(--text-muted); }
.et-table td { vertical-align: top; }
.et-table td input, .et-table td select, .et-table td textarea { width: 100%; box-sizing: border-box; font: inherit; }
.et-table td textarea { resize: vertical; min-height: 44px; }
.et-multiline { white-space: pre-line; color: var(--text-soft); font-size: 13px; line-height: 1.45; }
.et-num { white-space: nowrap; text-align: right; font-variant-numeric: tabular-nums; }
.et-group-row td { background: var(--surface-3); font-weight: 700; font-size: 13px; letter-spacing: .02em; padding: 8px 15px !important; }
.et-handle-col, .et-handle { width: 22px; }
.et-handle { cursor: grab; color: var(--text-faint); user-select: none; text-align: center; }
.et-actions-col { width: 1%; }
.et-actions { white-space: nowrap; }
.et-actions .btn { margin-left: 4px; }
.et-row.is-changed td:first-child { box-shadow: inset 3px 0 0 var(--accent); }
.et-row.has-error td { background: rgba(220, 53, 69, 0.08); }
.et-row.dragging { opacity: .4; }
.et-row.drag-over td { box-shadow: inset 0 2px 0 var(--accent); }
.et-error { color: var(--negative); font-size: 12px; margin-top: 4px; white-space: normal; }
.et-empty { margin-top: 10px; }
.et-save-bar { display: none; position: sticky; bottom: 0; z-index: 5; margin-top: 12px; padding: 10px 14px;
    background: var(--surface-2); border: 1px solid var(--border-strong); border-radius: 10px; align-items: center; gap: 10px; }
.et-save-bar.visible { display: flex; }
.et-spacer { flex: 1; }
.et-save-error { color: var(--negative); font-size: 13px; }
.calc-settings-form { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 12px; }
.calc-settings-form label { display: flex; flex-direction: column; gap: 4px; font-size: 13px; }
.calc-settings-form .action-buttons { grid-column: 1 / -1; }

/* Data Calculator (Tools) */
.calc-grid { display: grid; grid-template-columns: minmax(320px, 1fr) minmax(320px, 1fr); gap: 20px; align-items: start; }
@media (max-width: 1000px) { .calc-grid { grid-template-columns: 1fr; } }
.calc-tabs { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 14px; }
.calc-tab { background: var(--neutral-bg); color: var(--on-neutral); border: 1px solid var(--border-strong); border-radius: 999px; padding: 6px 14px; cursor: pointer; font: inherit; font-size: 13px; }
.calc-tab.active { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.calc-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 12px; }
.calc-row-wide { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.calc-checks { display: flex; flex-direction: column; gap: 6px; }
.calc-check { display: flex; align-items: center; gap: 8px; font-weight: 400; font-size: 14px; }
.calc-output .stat-row .value { text-align: right; }
.calc-grand { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; margin-top: 14px; padding: 12px 14px; border-radius: 10px; background: var(--surface-3); }
.calc-grand strong { font-size: 20px; color: var(--brand); }
#calc-format { width: 100%; }
.calc-print-header, .calc-print-only { display: none; }
@media print {
    .sidebar, .sidebar-toggle-btn, .app-header, .calc-no-print, .messages, .site-footer { display: none !important; }
    .main-content { margin: 0 !important; padding: 0 !important; }
    .calc-print-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; }
    .calc-print-header img { height: 36px; }
    .calc-print-only { display: block; }
    .calc-grid { grid-template-columns: 1fr; }
    .card { box-shadow: none !important; border: 1px solid #ccc; break-inside: avoid; }
    body, .card, .stat-row, h1, h2, h3, td, th, div, span { color: #111 !important; background: #fff !important; }
    @page { size: A4 portrait; margin: 12mm; }
}

/* Project edit page — full width, fields in a responsive grid */
.project-edit-info { max-width: 900px; }
.form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); column-gap: 20px; }
.form-grid > .span-full { grid-column: 1 / -1; }
.form-grid .form-group { min-width: 0; }
.project-edit-actions { flex-wrap: wrap; }
.project-edit-delete { margin-left: auto; }

/* Clients → details dialogue */
.clickable-row { cursor: pointer; }
.clickable-row:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.client-details-box { position: relative; max-width: 980px; width: min(980px, 94vw); max-height: 88vh; overflow-y: auto; }
.modal-close-x { position: absolute; top: 10px; right: 14px; background: none; border: 0; font-size: 26px; line-height: 1; color: var(--text-muted); cursor: pointer; }
.client-details-head { display: flex; gap: 14px; align-items: center; margin-bottom: 14px; padding-right: 30px; }
.client-details-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); column-gap: 24px; }
.client-notes-form textarea { width: 100%; box-sizing: border-box; font: inherit; }
.client-crm-list { margin: 0; padding-left: 18px; line-height: 1.7; }

/* Sales → CRM */
.crm-summary { display: flex; gap: 14px; flex-wrap: wrap; align-items: stretch; margin-bottom: 16px; }
.crm-stat { background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 10px 16px; display: flex; flex-direction: column; min-width: 150px; }
.crm-stat span { font-size: 12px; color: var(--text-muted); }
.crm-stat strong { font-size: 22px; }
.crm-stat small { color: var(--text-muted); }
.crm-summary-actions { margin-left: auto; display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.crm-toggle { display: inline-flex; border: 1px solid var(--border-strong); border-radius: 999px; overflow: hidden; }
.crm-toggle a { padding: 6px 12px; font-size: 13px; color: var(--text-soft); text-decoration: none; }
.crm-toggle a.is-active { background: var(--accent); color: var(--on-accent); }
.crm-board { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(250px, 1fr); gap: 12px; overflow-x: auto; padding-bottom: 8px; align-items: start; }
.crm-column { background: var(--surface-2); border: 1px solid var(--border); border-radius: 12px; display: flex; flex-direction: column; min-height: 300px; }
.crm-column-head { padding: 10px 12px; border-bottom: 1px solid var(--border); }
.crm-column-title { font-weight: 700; }
.crm-count { font-weight: 400; color: var(--text-muted); font-size: 12px; margin-left: 4px; }
.crm-column-total { font-size: 12px; color: var(--text-muted); }
.crm-column-body { padding: 10px; display: flex; flex-direction: column; gap: 8px; flex: 1; min-height: 120px; border-radius: 0 0 12px 12px; }
.crm-column-body.drag-over { background: rgba(0, 163, 235, 0.08); }
.crm-card { background: var(--surface); border: 1px solid var(--border-strong); border-radius: 10px; padding: 10px 12px; cursor: grab; }
.crm-card.dragging { opacity: .4; }
.crm-card.is-overdue { border-left: 3px solid var(--negative); }
.crm-card-title { font-weight: 600; color: var(--text); text-decoration: none; display: block; }
.crm-card-title:hover { color: var(--link); }
.crm-card-meta { font-size: 12px; color: var(--text-muted); margin: 2px 0 8px; }
.crm-card-foot { display: flex; align-items: center; gap: 8px; font-size: 12px; }
.crm-card-foot > :last-child { margin-left: auto; }
.crm-card-foot .avatar, .crm-card-foot img { width: 22px; height: 22px; font-size: 10px; }
.crm-next.is-overdue { color: var(--negative); font-weight: 600; }
.crm-empty { color: var(--text-faint); font-size: 13px; text-align: center; margin: 20px 0; }
.crm-filters { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 14px; align-items: center; }
.crm-filters input[type=search] { min-width: 260px; }
.crm-status { display: inline-block; padding: 2px 8px; border-radius: 999px; font-size: 12px; font-weight: 600; background: var(--neutral-bg); }
.crm-status-won { background: rgba(79, 208, 138, 0.18); color: var(--positive); }
.crm-status-lost { background: rgba(255, 107, 107, 0.15); color: var(--negative); }
.crm-status-open { background: rgba(0, 163, 235, 0.15); color: var(--info); }
.crm-stage-bar { display: flex; list-style: none; padding: 0; margin: 0 0 16px; gap: 4px; flex-wrap: wrap; }
.crm-stage-bar li { flex: 1; min-width: 110px; padding: 8px 10px; background: var(--surface-3); font-size: 13px; text-align: center; clip-path: polygon(0 0, calc(100% - 10px) 0, 100% 50%, calc(100% - 10px) 100%, 0 100%, 10px 50%); }
.crm-stage-bar li.is-past { background: rgba(0, 163, 235, 0.35); }
.crm-stage-bar li.is-current { background: var(--accent); color: var(--on-accent); font-weight: 700; }
.crm-detail-grid { display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(300px, 1fr); gap: 20px; align-items: start; }
@media (max-width: 1000px) { .crm-detail-grid { grid-template-columns: 1fr; } }
.crm-status-actions { flex-wrap: wrap; }
.crm-lost-form, .crm-inline-form { display: inline-flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.crm-project-box { margin-top: 16px; padding-top: 12px; border-top: 1px solid var(--border); }
.crm-activity-grid { display: grid; grid-template-columns: 130px 1fr 210px; gap: 10px; }
.crm-activity-grid label { display: flex; flex-direction: column; gap: 4px; font-size: 13px; }
.crm-activity-subject { grid-column: span 1; }
.crm-activity-notes { grid-column: 1 / -1; }
@media (max-width: 700px) { .crm-activity-grid { grid-template-columns: 1fr; } }
.crm-timeline { list-style: none; padding: 0; margin: 18px 0 0; }
.crm-activity { display: flex; gap: 10px; align-items: flex-start; padding: 10px 0; border-top: 1px solid var(--border-subtle); }
.crm-activity-body { flex: 1; min-width: 0; }
.crm-activity.is-done .crm-activity-body strong { text-decoration: line-through; color: var(--text-muted); }
.crm-check { width: 22px; height: 22px; border-radius: 50%; border: 2px solid var(--border-strong); background: none; color: var(--positive); cursor: pointer; display: grid; place-items: center; padding: 0; font-size: 11px; }
.crm-activity.is-overdue .crm-check { border-color: var(--negative); }
.crm-badge-overdue { color: var(--negative); font-size: 11px; font-weight: 700; margin-left: 6px; text-transform: uppercase; }
.crm-activity-notes-text { font-size: 13px; color: var(--text-soft); }
.crm-people { list-style: none; padding: 0; margin: 0; }
.crm-people li { display: flex; justify-content: space-between; gap: 10px; padding: 8px 0; border-top: 1px solid var(--border-subtle); }
.crm-new-person { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.crm-new-person p, .crm-new-person button { grid-column: 1 / -1; }
.crm-add-person summary { cursor: pointer; color: var(--link); margin-top: 10px; }
.calc-grid .form-group, .calc-row .form-group { margin-bottom: 14px; min-width: 0; }
.calc-row input, .calc-row select, #calc-format, #calc-format-search { box-sizing: border-box; width: 100%; }

/* Inputs in the new Sales/Tools/CRM forms that don't sit inside a .form-group get the
   same look as the rest of the app's fields. */
.et-search, .et-table input, .et-table select, .et-table textarea,
.crm-filters input, .crm-filters select, .crm-activity-grid input, .crm-activity-grid select, .crm-activity-grid textarea,
.crm-inline-form select, .crm-lost-form input, .crm-new-person input, .calc-settings-form input,
.client-notes-form textarea, .crm-stages input {
    padding: 8px 10px;
    background: var(--surface-2);
    border: 1px solid var(--border-strong);
    border-radius: 6px;
    color: var(--text);
    font-size: 14px;
    font-family: inherit;
    box-sizing: border-box;
}
.et-search:focus, .et-table input:focus, .et-table select:focus, .et-table textarea:focus,
.crm-filters input:focus, .crm-activity-grid input:focus, .crm-activity-grid select:focus, .crm-activity-grid textarea:focus,
.calc-settings-form input:focus, .client-notes-form textarea:focus, .crm-new-person input:focus {
    outline: none;
    border-color: var(--accent);
}
.et-table td { padding: 10px 12px; }
.et-table textarea.et-longtext { resize: none; overflow: hidden; }
.crm-activity-with { grid-column: 1 / -1; max-width: 420px; }
.crm-select-filter { width: 100%; margin-bottom: 6px; padding: 8px 10px; background: var(--surface-2); border: 1px solid var(--border-strong); border-radius: 6px; color: var(--text); font: inherit; font-size: 13px; box-sizing: border-box; }

/* Title rows on the rental list (editable_table.js) — coloured section headings */
.et-title-row td { color: #fff; font-weight: 700; font-size: 15px; letter-spacing: .01em; padding-top: 10px; padding-bottom: 10px; }
.et-title-row:hover { filter: brightness(1.05); }
.et-title-row .et-handle { color: rgba(255, 255, 255, 0.7); }
.et-title-fields { display: flex; gap: 10px; align-items: center; }
.et-table .et-title-fields .et-title-input { flex: 1; max-width: 520px; background: rgba(0, 0, 0, 0.25); border-color: rgba(255, 255, 255, 0.35); color: #fff; font-weight: 700; }
.et-table .et-title-fields .et-title-input::placeholder { color: rgba(255, 255, 255, 0.7); }
.et-table .et-title-fields .et-title-colour { width: 44px; height: 34px; padding: 2px; cursor: pointer; flex: none; }
.et-title-row .et-error { color: #fff; background: rgba(0,0,0,.35); padding: 2px 6px; border-radius: 4px; display: inline-block; }

/* ---------------------------------------------------------------------------
   Asset Tracking
   --------------------------------------------------------------------------- */
.asset-input, .asset-filters input[type=search], .asset-quick-find input, .asset-qty-form input {
    padding: 8px 10px; background: var(--surface-2); border: 1px solid var(--border-strong); border-radius: 6px;
    color: var(--text); font: inherit; font-size: 14px; box-sizing: border-box;
}
.asset-input:focus, .asset-quick-find input:focus { outline: none; border-color: var(--accent); }
.req { color: var(--negative); }
.form-group.has-error input, .form-group.has-error select, .form-group.has-error textarea { border-color: var(--negative) !important; box-shadow: 0 0 0 1px var(--negative); }
.field-error { color: var(--negative); font-size: 12px; margin-top: 4px; }
.nowrap { white-space: nowrap; }

.asset-filters { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin-bottom: 16px; }
.asset-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.asset-chip { display: inline-flex; align-items: center; gap: 6px; padding: 6px 12px; border-radius: 999px; border: 1px solid var(--chip); color: var(--text); cursor: pointer; font-size: 13px; font-weight: 500; }
.asset-chip input { accent-color: var(--chip); margin: 0; }
.asset-chip:has(input:checked) { background: var(--chip); color: #fff; }
.asset-cat { display: inline-block; padding: 3px 9px; border-radius: 999px; font-size: 12px; font-weight: 600; background: color-mix(in srgb, var(--chip) 22%, transparent); border: 1px solid var(--chip); white-space: nowrap; }

.asset-techs { display: inline-flex; flex-wrap: wrap; gap: 6px; vertical-align: middle; }
.asset-tech { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; background: var(--surface-3); border-radius: 999px; padding: 2px 8px 2px 2px; }
.asset-tech img, .asset-tech-initials { width: 22px; height: 22px; border-radius: 50%; object-fit: cover; }
.asset-tech-initials { display: inline-grid; place-items: center; background: var(--neutral-bg); font-size: 9px; font-weight: 700; }

.asset-pstatus { display: inline-block; padding: 3px 9px; border-radius: 999px; font-size: 12px; font-weight: 600; white-space: nowrap; background: var(--neutral-bg); }
.asset-pstatus-part_dispatched, .asset-pstatus-part_returned { background: rgba(249, 115, 22, 0.18); color: var(--warning); }
.asset-pstatus-ready { background: rgba(0, 163, 235, 0.18); color: var(--info); }
.asset-pstatus-out { background: rgba(139, 92, 246, 0.2); color: #a78bfa; }
.asset-pstatus-returned { background: rgba(79, 208, 138, 0.18); color: var(--positive); }
.asset-pstatus-overdue { background: var(--danger); color: #fff; }
.asset-row-overdue td:first-child { box-shadow: inset 4px 0 0 var(--danger); }
.asset-due { color: var(--warning); font-weight: 700; }

.asset-status { display: inline-block; padding: 2px 8px; border-radius: 999px; font-size: 12px; font-weight: 600; background: var(--neutral-bg); }
.asset-status-available { background: rgba(79, 208, 138, 0.18); color: var(--positive); }
.asset-status-out { background: rgba(139, 92, 246, 0.2); color: #a78bfa; }
.asset-status-repair { background: rgba(249, 115, 22, 0.18); color: var(--warning); }
.asset-status-retired { color: var(--text-muted); }

.asset-thumb { width: 44px; height: 44px; object-fit: contain; border-radius: 8px; background: var(--surface-3); padding: 3px; box-sizing: border-box; display: inline-grid; place-items: center; vertical-align: middle; }
.asset-thumb.is-big { width: 84px; height: 84px; padding: 8px; font-size: 30px; }
.asset-thumb-icon { color: var(--text-muted); font-size: 18px; }
.asset-type-header { display: flex; gap: 16px; align-items: center; }
.asset-picture-preview img { max-height: 70px; margin-top: 8px; }
.asset-serial-row { display: flex; gap: 8px; }
.asset-serial-row input { flex: 1; min-width: 0; }
.asset-quick-find { display: flex; flex-direction: column; gap: 2px; }
.asset-quick-find input { min-width: 260px; }

.asset-opp-tabs { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-bottom: 16px; }
.asset-opp-tab { padding: 8px 14px; border-radius: 10px; border: 1px solid var(--border-strong); text-decoration: none; color: var(--text); font-weight: 600; border-top: 3px solid var(--chip); }
.asset-opp-tab.is-active { background: color-mix(in srgb, var(--chip) 22%, var(--surface)); border-color: var(--chip); }
.asset-add-service summary { list-style: none; cursor: pointer; }
.asset-add-service[open] form { margin-top: 8px; }
.asset-project-grid { display: grid; grid-template-columns: minmax(0, 1.7fr) minmax(280px, 1fr); gap: 20px; align-items: start; }
@media (max-width: 1000px) { .asset-project-grid { grid-template-columns: 1fr; } }
.asset-kit tr.is-complete td { background: rgba(79, 208, 138, 0.07); }
.asset-qty-form input { width: 74px; }
.asset-tags { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }
.asset-tags a { font-size: 11px; padding: 1px 6px; border-radius: 4px; background: var(--surface-3); text-decoration: none; color: var(--text-soft); font-family: ui-monospace, Menlo, monospace; }
.asset-history { list-style: none; padding: 0; margin: 0; max-height: 420px; overflow-y: auto; }
.asset-history li { display: flex; flex-direction: column; padding: 6px 0; border-top: 1px solid var(--border-subtle); font-size: 13px; }
.asset-history li small { color: var(--text-muted); }
.is-undone, .asset-history li.is-undone span { opacity: .5; text-decoration: line-through; }

.scan-panel { border-radius: 12px; }
.scan-controls { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin-bottom: 12px; }
.scan-mode { display: inline-flex; border: 1px solid var(--border-strong); border-radius: 10px; overflow: hidden; }
.scan-mode-btn { background: none; border: 0; color: var(--text-soft); padding: 9px 16px; font: inherit; font-weight: 600; cursor: pointer; }
.scan-mode-btn.active { background: var(--accent); color: var(--on-accent); }
.scan-panel.is-check-in .scan-mode-btn.active { background: var(--positive); color: #062; }
.scan-opp-select { flex: 1; min-width: 260px; }
.scan-label { display: block; font-weight: 700; margin-bottom: 6px; }
.scan-input { width: 100%; box-sizing: border-box; font-size: 22px; padding: 14px 16px; font-family: ui-monospace, Menlo, monospace; letter-spacing: .05em;
    background: var(--surface-2); color: var(--text); border: 2px solid var(--accent); border-radius: 10px; }
.scan-panel.is-check-in .scan-input { border-color: var(--positive); }
.scan-input:focus { outline: none; box-shadow: 0 0 0 4px rgba(0, 163, 235, 0.25); }
.scan-flash { margin-top: 10px; min-height: 22px; padding: 0; border-radius: 8px; font-weight: 600; }
.scan-flash.is-ok, .scan-flash.is-warn, .scan-flash.is-error { padding: 10px 14px; }
.scan-flash.is-ok { background: rgba(79, 208, 138, 0.18); color: var(--positive); }
.scan-flash.is-warn { background: rgba(249, 115, 22, 0.18); color: var(--warning); }
.scan-flash.is-error { background: rgba(220, 53, 69, 0.2); color: var(--negative); }
.scan-log { list-style: none; padding: 0; margin: 12px 0 0; max-height: 360px; overflow-y: auto; }
.scan-entry { padding: 8px 10px; border-top: 1px solid var(--border-subtle); display: flex; justify-content: space-between; gap: 10px; align-items: center; flex-wrap: wrap; font-size: 14px; }
.scan-entry.is-ok i { color: var(--positive); }
.scan-entry.is-warn i { color: var(--warning); }
.scan-entry.is-error i { color: var(--negative); }
.scan-entry-actions { display: flex; gap: 6px; }
.scan-entry.is-undone .scan-entry-head { opacity: .5; text-decoration: line-through; }
.asset-no-techs { color: var(--text-muted); font-size: 12px; }
.asset-header-techs { margin-top: 8px; }

/* Asset page — live Mosyle details */
.mosyle-battery { display: grid; grid-template-columns: auto 1fr auto; gap: 10px; align-items: center; padding: 10px 12px; margin-bottom: 8px; border-radius: 10px; background: var(--surface-3); --level: var(--positive); }
.mosyle-battery.is-mid { --level: var(--warning); }
.mosyle-battery.is-low { --level: var(--negative); }
.mosyle-battery-label { font-size: 13px; color: var(--text-soft); }
.mosyle-battery-label i { color: var(--level); }
.mosyle-battery-bar { height: 10px; border-radius: 999px; background: var(--neutral-bg); overflow: hidden; }
.mosyle-battery-bar span { display: block; height: 100%; background: var(--level); border-radius: 999px; }
.mosyle-battery strong { color: var(--level); }
.mosyle-battery-chip { font-size: 12px; font-weight: 600; color: var(--positive); white-space: nowrap; }
.mosyle-battery-chip.is-mid { color: var(--warning); }
.mosyle-battery-chip.is-low { color: var(--negative); }
.mosyle-update { color: var(--warning); font-weight: 600; }
.link-button { background: none; border: 0; padding: 0; color: var(--link); cursor: pointer; font: inherit; text-decoration: underline; }
.asset-details .stat-row { gap: 16px; }
.asset-details .stat-row > span:first-child { flex-shrink: 0; white-space: nowrap; overflow-wrap: normal; }
.asset-details .stat-row .value { text-align: right; }
.asset-status { white-space: nowrap; }
.asset-service-list { display: flex; flex-wrap: wrap; gap: 4px; }
.asset-service-list .asset-cat { text-decoration: none; color: var(--text); display: inline-flex; align-items: center; gap: 5px; }
.asset-service-list .asset-cat:hover { filter: brightness(1.2); }
.asset-cat-status { width: 8px; height: 8px; border-radius: 50%; padding: 0; display: inline-block; }
.asset-cat-status.asset-pstatus-not_started { background: var(--text-faint); }
.asset-status-stack { display: flex; flex-direction: column; align-items: flex-start; gap: 3px; }

/* ---------- Users page: access groups ---------- */
.access-group-list { display: flex; flex-direction: column; gap: 8px; margin-top: 10px; }
.access-group-card { border: 1px solid var(--border-color, #2c3440); border-radius: 10px; padding: 10px 14px; background: var(--card-bg, rgba(255,255,255,0.02)); }
.access-group-card > summary { cursor: pointer; display: flex; flex-wrap: wrap; align-items: center; gap: 10px; list-style: none; }
.access-group-card > summary::-webkit-details-marker { display: none; }
.access-group-pages { display: flex; flex-wrap: wrap; gap: 4px; }
.access-chip { display: inline-block; padding: 2px 8px; border-radius: 999px; font-size: 0.78rem; background: rgba(0,163,235,0.14); color: #00a3eb; margin: 1px 2px; white-space: nowrap; }
.access-group-form { margin-top: 12px; display: flex; flex-direction: column; gap: 12px; }
.access-group-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 12px; }
.access-group-grid label { display: flex; flex-direction: column; gap: 4px; font-weight: 600; }
.access-group-fieldset { border: 1px solid var(--border-color, #2c3440); border-radius: 8px; padding: 8px 12px; display: flex; flex-wrap: wrap; gap: 8px 18px; }
.access-group-fieldset legend { font-weight: 600; padding: 0 4px; }
.access-group-fieldset label, .access-group-picks label { display: flex; align-items: center; gap: 6px; font-weight: 400; }
.access-group-picks { display: flex; flex-wrap: wrap; gap: 8px 18px; }
.access-group-actions { display: flex; gap: 8px; }
.perm-cell { white-space: nowrap; }
.access-via { color: #00a3eb; margin-left: 4px; font-size: 0.8rem; }
.slack-id-input { font-family: ui-monospace, monospace; font-size: 0.8rem; padding: 3px 6px; transition: box-shadow .3s; }
.slack-id-input.is-saved { box-shadow: 0 0 0 2px #2ecc71; }

.mosyle-sync-line { margin: -4px 0 12px; }
.mosyle-sync-line.is-error { color: #e74c3c; }

/* ---------- Field Solutions › Daily Operations Schedule ---------- */
.ops-toolbar { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 10px; margin-bottom: 12px; }
.ops-nav { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.ops-nav .btn.is-active { border-color: #00a3eb; color: #00a3eb; }
.ops-range { margin-left: 6px; }
.ops-filters { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-bottom: 14px; }
.ops-filters select, .ops-filters input[type="search"] { max-width: 240px; }
.ops-type-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.ops-type-chip { border: 1px solid var(--chip); background: transparent; color: var(--text-muted); border-radius: 999px; padding: 4px 10px; font: inherit; font-size: 0.82rem; cursor: pointer; opacity: .55; }
.ops-type-chip.is-on { background: color-mix(in srgb, var(--chip) 22%, transparent); color: var(--text); opacity: 1; }
.ops-check { display: flex; align-items: center; gap: 6px; font-weight: 400; }
.ops-table { width: 100%; }
.ops-table th.ops-sortable { cursor: pointer; user-select: none; white-space: nowrap; }
.ops-table th[data-dir="asc"]::after { content: " ▲"; font-size: .7em; }
.ops-table th[data-dir="desc"]::after { content: " ▼"; font-size: .7em; }
.ops-col-done { width: 56px; text-align: center; }
.ops-day-title td { background: color-mix(in srgb, #00a3eb 14%, var(--surface)); border-top: 2px solid #00a3eb; font-weight: 600; padding: 8px 12px; }
.ops-day.is-weekend .ops-day-title td { background: color-mix(in srgb, #95a5a6 14%, var(--surface)); border-top-color: #95a5a6; }
.ops-day.is-past .ops-day-title td { background: color-mix(in srgb, #7f8c8d 10%, var(--surface)); border-top-color: #7f8c8d; }
.ops-day.is-today .ops-day-title td { background: color-mix(in srgb, #2ecc71 18%, var(--surface)); border-top-color: #2ecc71; }
.ops-today-pill { background: #2ecc71; color: #fff; border-radius: 999px; padding: 1px 8px; font-size: .75rem; margin-left: 6px; }
.ops-day-count { color: var(--text-muted); font-weight: 400; font-size: .85rem; margin-left: 10px; }
.ops-day-add { float: right; background: none; border: 0; color: #00a3eb; cursor: pointer; font: inherit; font-size: .85rem; }
.ops-empty td { color: var(--text-muted); font-style: italic; padding: 8px 12px; }
.ops-task { cursor: pointer; }
.ops-task:hover td { background: color-mix(in srgb, #00a3eb 6%, transparent); }
.ops-task.is-done td:not(.ops-col-done) { opacity: .5; text-decoration: line-through; text-decoration-color: color-mix(in srgb, var(--text) 40%, transparent); }
.ops-task.is-outstanding td { background: color-mix(in srgb, #e74c3c 10%, transparent); }
.ops-task.is-outstanding td:first-child { box-shadow: inset 3px 0 0 #e74c3c; }
.ops-task.is-highlighted td { animation: ops-flash 2.4s ease-out; }
@keyframes ops-flash { 0%, 40% { background: color-mix(in srgb, #f1c40f 30%, transparent); } }
.ops-type { display: inline-block; white-space: nowrap; padding: 2px 8px; border-radius: 999px; font-size: .8rem; background: color-mix(in srgb, var(--chip) 20%, transparent); border: 1px solid color-mix(in srgb, var(--chip) 55%, transparent); }
.ops-notes { max-width: 420px; white-space: normal; }
.ops-person { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
.ops-date-link { font-weight: 600; font-size: .85rem; }
.ops-outstanding { border: 1px solid color-mix(in srgb, #e74c3c 50%, transparent); background: color-mix(in srgb, #e74c3c 7%, transparent); border-radius: 12px; padding: 10px 14px; margin-bottom: 14px; }
.ops-outstanding > summary { cursor: pointer; font-weight: 600; color: #e74c3c; }
.ops-outstanding table { margin-top: 10px; }
.ops-task-box { max-width: 640px; position: relative; }
.ops-form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.ops-form-grid label { display: flex; flex-direction: column; gap: 4px; font-weight: 600; }
.ops-form-grid .ops-span-2 { grid-column: span 2; }
@media (max-width: 640px) { .ops-form-grid { grid-template-columns: 1fr; } .ops-form-grid .ops-span-2 { grid-column: auto; } }
.ops-filters select, .ops-filters input[type="search"], .ops-nav input[type="date"] { padding: 7px 10px; border-radius: 8px; border: 1px solid var(--border); background: var(--surface); color: var(--text); font: inherit; font-size: .9rem; }
.ops-filters input[type="search"] { min-width: 220px; }
.ops-form-grid input, .ops-form-grid select, .ops-form-grid textarea { padding: 8px 10px; border-radius: 8px; border: 1px solid var(--border); background: var(--bg, var(--surface)); color: var(--text); font: inherit; font-weight: 400; width: 100%; box-sizing: border-box; }
.ops-form-grid textarea { resize: vertical; }
.ops-form-grid label small { font-weight: 400; display: inline; }
.ops-table td:last-child { white-space: nowrap; }
.access-group-grid input { padding: 8px 10px; border-radius: 8px; border: 1px solid var(--border); background: var(--surface); color: var(--text); font: inherit; font-weight: 400; }

/* ---------------------------------------------------------------------------
   Home dashboard: page tiles, Quicklinks and the weekly rota.
   --------------------------------------------------------------------------- */
.sidebar nav ul li a.is-current { color: var(--accent); }
.home-section { margin-bottom: 28px; }
.home-section-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 12px; }
.home-section-head h2 { margin: 0; font-size: 1.15rem; }
.home-layout-actions { display: flex; gap: 8px; align-items: center; }
.home-editing-only { display: none !important; }
.home-section.is-editing .home-editing-only { display: flex !important; gap: 8px; }
.home-section.is-editing p.home-editing-only { display: block !important; }
.home-section.is-editing #home-edit-layout { display: none; }
.home-tiles { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: 14px; }
.home-tile { position: relative; }
.home-tile-link {
    display: flex; flex-direction: column; align-items: flex-start; gap: 6px; height: 100%; box-sizing: border-box;
    padding: 18px 16px; border-radius: 12px; background: var(--surface); border: 1px solid var(--border);
    color: var(--text); text-decoration: none; transition: border-color .15s ease, transform .15s ease, box-shadow .15s ease;
}
.home-tile-link:hover, .home-tile-link:focus-visible { border-color: var(--accent); transform: translateY(-2px); box-shadow: 0 6px 18px rgba(0,0,0,.18); }
.home-tile-icon { width: 42px; height: 42px; border-radius: 10px; display: grid; place-items: center; font-size: 1.2rem; color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, transparent); }
.home-tile-label { font-weight: 700; line-height: 1.25; }
.home-tile-section { font-size: .78rem; color: var(--text-faint); }
.home-section.is-editing .home-tile-link { cursor: grab; border-style: dashed; }
.home-section.is-editing .home-tile-link:hover { transform: none; }
.home-tile.is-dragging { opacity: .45; }
.home-tile-move { position: absolute; top: 8px; right: 8px; gap: 4px; }
.home-tile-move button { border: 1px solid var(--border-strong); background: var(--surface-3); color: var(--text); border-radius: 6px; width: 26px; height: 26px; cursor: pointer; font-size: .75rem; }
.home-tile-move button:hover { border-color: var(--accent); }
.home-edit-hint { margin-top: -4px; }
.home-quicklinks { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(112px, 1fr)); gap: 10px; }
.home-quicklink { display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 12px 8px; border-radius: 10px; background: var(--surface); border: 1px solid var(--border); color: var(--text); text-decoration: none; font-size: .85rem; text-align: center; }
.home-quicklink:hover, .home-quicklink:focus-visible { border-color: var(--accent); }
.home-quicklink-img { width: 40px; height: 40px; border-radius: 9px; object-fit: contain; }
.home-quicklink-placeholder { display: grid; place-items: center; font-weight: 700; font-size: 1.1rem; color: #fff; background: var(--ql, #555); }
.rota-table th, .rota-table td { vertical-align: top; }
.rota-person-col { min-width: 210px; }
.rota-day-col { min-width: 112px; white-space: nowrap; }
.rota-day-col.is-today { background: color-mix(in srgb, #2ecc71 28%, var(--table-head-bg)); }
.rota-day-num { color: var(--text-faint); font-weight: 400; margin-left: 4px; }
.rota-person { text-align: left; font-weight: 500; }
.rota-person .ops-today-pill { vertical-align: middle; }
.rota-copy { display: none; margin-top: 6px; border: 0; background: none; color: var(--link); cursor: pointer; padding: 0; font: inherit; font-size: .78rem; }
tr:hover .rota-copy, tr.is-own .rota-copy, .rota-copy:focus-visible { display: block; }
tr.is-own > * { background: color-mix(in srgb, var(--accent) 7%, transparent); }
.rota-cell { height: 48px; }
.rota-cell.is-weekend { background: color-mix(in srgb, var(--text) 3%, transparent); }
.rota-cell.is-editable { cursor: pointer; }
.rota-cell.is-editable:hover, .rota-cell.is-editable:focus-visible { outline: 1px dashed var(--accent); outline-offset: -3px; }
.rota-cell.is-editable:empty::after, .rota-cell.is-editable:not([data-entry]):hover::after { content: "+"; color: var(--text-faint); }
.rota-chip { display: inline-block; padding: 2px 8px; border-radius: 999px; font-size: .78rem; white-space: nowrap; background: color-mix(in srgb, var(--chip) 22%, transparent); border: 1px solid color-mix(in srgb, var(--chip) 60%, transparent); }
.rota-hours { display: block; margin-top: 4px; font-size: .78rem; color: var(--text-muted); }
.rota-box { max-width: 420px; }
.rota-error { color: var(--negative); margin: 10px 0 0; }
@media (max-width: 768px) { .home-tiles { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); } }
.muted { color: var(--text-faint); }

/* Inventory: grid / list switch and import preview. */
.view-switch { display: inline-flex; border: 1px solid var(--border-strong); border-radius: 8px; overflow: hidden; }
.view-switch-btn { border: 0; background: transparent; color: var(--text-soft); padding: 7px 12px; cursor: pointer; font: inherit; font-size: .88rem; }
.view-switch-btn + .view-switch-btn { border-left: 1px solid var(--border-strong); }
.view-switch-btn[aria-pressed="true"] { background: var(--accent); color: var(--on-accent); }
#inventory-views[data-view="list"] .inventory-grid, #inventory-views[data-view="grid"] .inventory-list { display: none; }
.crm-filters .btn.is-active { border-color: var(--accent); color: var(--accent); }
.inventory-grid { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 14px; }
.inventory-card { position: relative; display: flex; flex-direction: column; gap: 6px; height: 100%; box-sizing: border-box; padding: 14px; border-radius: 12px; background: var(--surface); border: 1px solid var(--border); color: var(--text); text-decoration: none; }
.inventory-card:hover, .inventory-card:focus-visible { border-color: var(--accent); }
.inventory-card-picture { height: 110px; border-radius: 8px; display: grid; place-items: center; background: var(--surface-3); font-size: 2.2rem; color: var(--text-faint); overflow: hidden; }
.inventory-card-picture img { max-width: 100%; max-height: 100%; object-fit: contain; }
.inventory-card-name { font-weight: 700; line-height: 1.25; }
.inventory-card-meta { font-size: .8rem; color: var(--text-muted); }
.inventory-card-counts { display: flex; flex-wrap: wrap; gap: 4px 10px; font-size: .8rem; color: var(--text-soft); margin-top: auto; }
.inventory-card-counts .is-out strong { color: var(--warning); }
.inventory-card-counts .is-repair strong { color: var(--negative); }
.inventory-card-incomplete { position: absolute; top: 10px; right: 10px; font-size: .72rem; padding: 2px 7px; border-radius: 999px; background: color-mix(in srgb, var(--warning) 22%, transparent); border: 1px solid color-mix(in srgb, var(--warning) 55%, transparent); }
.inventory-grid-empty { grid-column: 1 / -1; text-align: center; padding: 28px; }
.import-stats { display: flex; flex-wrap: wrap; gap: 12px; margin: 12px 0; }
.import-stats > div { display: flex; flex-direction: column; min-width: 120px; padding: 10px 14px; border-radius: 10px; background: var(--surface-3); }
.import-stats strong { font-size: 1.5rem; }
.import-stats span { font-size: .8rem; color: var(--text-muted); }
.import-stats .is-bad strong { color: var(--negative); }

/* Asset Tracking: Prepare → Check out → Check in, and the Global check in. */
.asset-pstatus-preparing { background: rgba(0, 163, 235, 0.18); color: var(--info); }
.asset-cat-status.asset-pstatus-preparing { background: var(--info); }
.scan-panel.is-prepare .scan-mode-btn.active { background: #b7950b; color: #fff; }
.scan-panel.is-prepare .scan-input { border-color: #b7950b; }
.scan-step { display: inline-grid; place-items: center; width: 18px; height: 18px; border-radius: 50%; font-size: 11px; margin-right: 4px; background: color-mix(in srgb, currentColor 20%, transparent); }
.asset-stage-steps { margin: 0 0 12px; padding-left: 20px; color: var(--text-soft); font-size: .88rem; }
.asset-stage-steps li { margin-bottom: 2px; }
.asset-stages { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; }
.asset-stage { margin: 0; }
.asset-stage-head { display: flex; justify-content: space-between; align-items: center; gap: 8px; margin-bottom: 8px; flex-wrap: wrap; }
.asset-stage-head h3 { margin: 0; font-size: 1rem; }
.asset-stage-count { display: inline-block; min-width: 22px; padding: 1px 7px; border-radius: 999px; background: var(--surface-3); font-size: .8rem; text-align: center; margin-left: 4px; }
.asset-stage-list { list-style: none; margin: 0; padding: 0; max-height: 420px; overflow: auto; }
.asset-stage-list li { display: flex; align-items: center; gap: 8px; padding: 5px 0; border-bottom: 1px solid var(--border-subtle); font-size: .88rem; }
.asset-stage-list li span { color: var(--text-muted); flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.asset-stage-list li form { margin: 0; }
.asset-stage-list .btn-sm { padding: 2px 7px; }
@media (max-width: 1100px) { .asset-stages { grid-template-columns: 1fr; } }
.checkin-card { max-width: 1000px; }
.checkin-card .scan-controls { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; }
.checkin-card .scan-input { border-color: var(--positive); }
.checkin-basket-head { display: flex; justify-content: space-between; align-items: center; gap: 10px; flex-wrap: wrap; margin: 18px 0 8px; }
.checkin-group { margin-bottom: 14px; }
.checkin-group h4 { margin: 0 0 4px; font-size: .9rem; color: var(--text-soft); }
.checkin-group.is-problem h4 { color: var(--negative); }
.checkin-group.is-problem li { color: var(--negative); }

/* Admin › Users — Add user / Add group dialogues */
.admin-modal { position: relative; max-width: 720px; width: min(720px, 94vw); max-height: 88vh; overflow-y: auto; }
.admin-modal h2 { margin: 0 0 14px; padding-right: 30px; }
.admin-modal-form { display: flex; flex-direction: column; gap: 14px; margin-top: 0; }
.admin-modal .access-group-grid select { padding: 8px 10px; border-radius: 8px; border: 1px solid var(--border); background: var(--surface); color: var(--text); font: inherit; font-weight: 400; }
.admin-modal .modal-actions { display: flex; gap: 8px; }
.admin-section-head { display: flex; flex-direction: column; align-items: flex-start; gap: 10px; margin-bottom: 18px !important; }
.admin-section-head h2 { margin: 0; }
