/* ============================================================
   McNelly Ent Inventory — design system

   Tokens first, then the app shell, then components. The nav
   chrome is always the neutral dark theme; only `.content` is
   re-themed per company (see the theme blocks at the bottom),
   which is why every component reads its colors from variables.
   ============================================================ */

:root {
    /* Surfaces: a ramp, so panels actually separate from the page. */
    --bg: #0e1116;
    --bg-sunken: #0a0d11;
    --bg-panel: #161b22;
    --bg-raised: #1c222c;
    --bg-hover: rgba(255, 255, 255, 0.04);

    --border: #232a34;
    --border-strong: #303845;

    --text: #e6e9ef;
    --text-muted: #8b95a5;
    --text-faint: #626c7a;

    --accent: #4d7cfe;
    --accent-hover: #6a92ff;
    --accent-soft: rgba(77, 124, 254, 0.12);
    --accent-text: #ffffff;

    /* Name links (item / unit / container names): a darkish gold that reads as
       "jump to this thing," distinct from the blue action accent. */
    --gold-link: #cfa63f;
    --gold-link-hover: #e6bd5e;
    /* Reprint-label control: a lighter blue than the standard button. */
    --print-blue: #6a92ff;
    --print-blue-hover: #86a7ff;

    --success: #3fbf87;
    --success-soft: rgba(63, 191, 135, 0.12);
    --warn: #e0a33a;
    --warn-soft: rgba(224, 163, 58, 0.12);
    --danger: #e5646b;
    --danger-soft: rgba(229, 100, 107, 0.12);

    --radius-sm: 5px;
    --radius: 8px;
    --radius-lg: 12px;
    --radius-pill: 999px;

    --shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
    --shadow-lg: 0 8px 30px rgba(0, 0, 0, 0.45);

    --body-font: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    --heading-font: var(--body-font);
    --mono-font: ui-monospace, SFMono-Regular, "Cascadia Mono", Consolas, monospace;

    --sidebar-w: 236px;
}

* { box-sizing: border-box; }

/* `display: flex/grid` on a component beats the `hidden` attribute, which
   silently un-hides things the JS thinks it hid. Make hidden actually hide. */
[hidden] { display: none !important; }

body {
    margin: 0;
    font-family: var(--body-font);
    font-size: 0.875rem;
    line-height: 1.55;
    color: var(--text);
    background: var(--bg);
    -webkit-font-smoothing: antialiased;
}

a { color: var(--accent); text-decoration: none; }

/* The clickable name of an item, unit, or container — gold, so a "go look at
   this thing" link reads differently from the blue action accent. */
.name-link { color: var(--gold-link); }
.name-link:hover { color: var(--gold-link-hover); text-decoration: underline; }
a:hover { text-decoration: underline; }

/* Themed scrollbars, so a scrollable panel (the dashboard's container/job/part
   lists especially) shows the same dark bar as the page instead of the
   browser's default light track. Colours come from the same variables the
   surfaces do, so they follow each company theme. Both the standard property
   and the WebKit pseudo-elements, since neither alone covers every browser. */
* { scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
    background: var(--border-strong);
    border-radius: var(--radius-pill);
    border: 2px solid transparent;
    background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover {
    background: var(--text-faint);
    background-clip: padding-box;
}
::-webkit-scrollbar-corner { background: transparent; }

h1, h2, h3 { font-family: var(--heading-font); line-height: 1.25; }
h1 { font-size: 1.5rem; font-weight: 650; letter-spacing: -0.01em; margin: 0 0 0.35rem; }
h2 { font-size: 1.0625rem; font-weight: 600; margin: 0 0 0.9rem; }
h3 { font-size: 0.9375rem; font-weight: 600; margin: 1.25rem 0 0.6rem; }

/* ---------- App shell ---------------------------------------------- */

.app { display: grid; grid-template-columns: var(--sidebar-w) 1fr; min-height: 100vh; }

.sidebar {
    position: sticky;
    top: 0;
    align-self: start;
    height: 100vh;
    overflow-y: auto;
    padding: 1rem 0.75rem 2rem;
    background: var(--bg-sunken);
    border-right: 1px solid var(--border);
}

.brand {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.4rem 0.5rem 1.1rem;
    color: var(--text);
    font-weight: 650;
    letter-spacing: -0.01em;
    text-decoration: none;
}
.brand:hover { text-decoration: none; }
.brand-mark {
    display: grid;
    place-items: center;
    width: 30px;
    height: 30px;
    flex-shrink: 0;
    border-radius: 8px;
    background: linear-gradient(135deg, var(--accent), #8b5cf6);
    color: #fff;
    font-size: 0.8rem;
    font-weight: 700;
}
.brand-text { font-size: 0.9rem; line-height: 1.15; }
.brand-text small { display: block; font-size: 0.7rem; font-weight: 500; color: var(--text-faint); }

/* The hamburger lives in the sidebar header but only appears on narrow screens
   (see the responsive block); on desktop the nav is always open, so it's hidden
   and `.sidebar-head` is just the brand's container — no visual change. */
.nav-toggle {
    display: none;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: 1px solid var(--border-strong);
    color: var(--text-muted);
    padding: 0.4rem 0.5rem;
    border-radius: var(--radius-sm);
    cursor: pointer;
}
.nav-toggle:hover { background: var(--bg-hover); color: var(--text); }
.nav-toggle .ico { width: 20px; height: 20px; }

.nav-group { margin-bottom: 1.1rem; }
.nav-group-title {
    padding: 0 0.6rem;
    margin-bottom: 0.3rem;
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--text-faint);
}

.nav-link {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.4rem 0.6rem;
    margin-bottom: 1px;
    border-radius: var(--radius-sm);
    color: var(--text-muted);
    font-weight: 500;
    text-decoration: none;
}
.nav-link:hover { background: var(--bg-hover); color: var(--text); text-decoration: none; }
.nav-link.active { background: var(--accent-soft); color: #cddcff; font-weight: 600; }
.nav-link.active .ico { color: var(--accent); }
.nav-link .ico { flex-shrink: 0; color: var(--text-faint); }
.nav-link:hover .ico { color: var(--text-muted); }

.ico { width: 16px; height: 16px; stroke: currentColor; fill: none; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }

/* ---------- Top bar (inside main) ----------------------------------- */

.main { display: flex; flex-direction: column; min-width: 0; }

.topbar {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 0.75rem 1.75rem;
    border-bottom: 1px solid var(--border);
    background: rgba(14, 17, 22, 0.85);
    backdrop-filter: blur(8px);
    position: sticky;
    top: 0;
    z-index: 20;
}
.topbar-spacer { flex: 1; }

/* Company scope switcher. Each tab carries a hint of its company's colour so
   you can tell at a glance which of the three you're working inside. */
.company-tabs { display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; }
.company-tab {
    --tab: var(--text-faint);
    display: inline-flex;          /* centres a wordmark and a text label alike */
    align-items: center;
    justify-content: center;
    min-height: 44px;
    padding: 0.5rem 1.15rem;
    border-radius: var(--radius-pill);
    color: var(--text-muted);
    font-weight: 550;
    text-decoration: none;
    border: 1px solid transparent;
}
.company-tab:hover { background: var(--bg-hover); color: var(--text); text-decoration: none; }
.company-tab.active {
    color: var(--tab);
    border-color: var(--tab);
    background: color-mix(in srgb, var(--tab) 14%, transparent);
}
.company-tab.theme-tab-currentcup { --tab: #e4b155; }
.company-tab.theme-tab-fulcrum { --tab: #00c8d6; }
.company-tab.theme-tab-pivot { --tab: #e0703b; }
.company-tab:first-child { --tab: var(--accent); }

/* Company wordmarks keep their real brand colours — dimmed when the tab isn't
   the one you're in, so the active company still reads first. The logos have
   very different aspect ratios (Current Coffee is a long wordmark, Pivot is
   stacked), so cap BOTH dimensions and let object-fit letterbox them: every
   mark is centred in its pill and none get stretched. */
.company-logo {
    display: block;
    height: 26px;
    width: auto;
    max-width: 200px;
    object-fit: contain;
    opacity: 0.55;
    transition: opacity 0.12s ease;
}
.company-tab:hover .company-logo { opacity: 0.85; }
.company-tab.active .company-logo { opacity: 1; }

/* An icon-only mark sits beside the company name rather than replacing it. */
.company-logo-icon { height: 22px; width: 22px; margin-right: 0.5rem; }

.badge-shared { background: var(--bg-raised); border-color: var(--border-strong); color: var(--text-muted); }

/* The company filter bar — sits above the sub-tabs, below the description. */
.filter-panel { padding: 0.9rem 1rem; margin-bottom: 0.25rem; }
.filter-panel .field label {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.filter-panel .filter-count { margin: 0.7rem 0 0; }

/* Sub-tabs within a company's scope (Parts / Consumables / … / Overview). */
.subtabs {
    display: flex;
    gap: 0.25rem;
    flex-wrap: wrap;
    margin: 1rem 0 1.25rem;
    border-bottom: 1px solid var(--border);
}
.subtab {
    padding: 0.5rem 0.9rem;
    color: var(--text-muted);
    font-weight: 550;
    text-decoration: none;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
}
.subtab:hover { color: var(--text); text-decoration: none; }
.subtab.active { color: var(--accent); border-bottom-color: var(--accent); }

.mono { font-family: var(--mono-font); font-size: 0.8125rem; color: var(--text-muted); }

/* Organize's mode tabs — big scanner-friendly targets. */
.mode-tabs { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 0.6rem; margin-bottom: 1.25rem; }
.mode-tab {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.15rem;
    padding: 0.75rem 1rem;
    background: var(--bg-panel);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    color: var(--text-muted);
    font-weight: 600;
    text-align: left;
    cursor: pointer;
}
.mode-tab small { font-weight: 400; font-size: 0.75rem; color: var(--text-faint); }
.mode-tab:hover { background: var(--bg-raised); color: var(--text); }
.mode-tab.active { background: var(--accent-soft); border-color: var(--accent); color: #cddcff; }
.mode-tab.active small { color: var(--text-muted); }
.mode-tab-danger.active { background: var(--danger-soft); border-color: var(--danger); color: #f2a3a7; }

.scan-prompt { margin: 0 0 0.75rem; font-weight: 550; }

/* ---------- Charts -----------------------------------------------------
   Rendered from the server as plain elements — no charting library, in line
   with the no-front-end-dependencies rule. Each chart is a single series, so
   it needs one hue and no legend; the heading names it.
   Palette validated against the dark panel surface (#161b22) for the
   lightness band, chroma floor, CVD separation and contrast. */

.chart-bars {
    display: flex;
    align-items: flex-end;
    gap: 2px;               /* the 2px surface gap between adjacent bars */
    height: 140px;
    padding-top: 0.5rem;
}
.chart-bar { flex: 1; height: 100%; display: flex; align-items: flex-end; }
.chart-bar-fill {
    width: 100%;
    min-height: 2px;
    background: #4d7cfe;
    border-radius: 3px 3px 0 0;   /* rounded data-end, square on the baseline */
}
.chart-bar:hover .chart-bar-fill { background: #7fa3ff; }
.chart-axis {
    display: flex;
    justify-content: space-between;
    margin-top: 0.4rem;
    font-size: 0.75rem;
    color: var(--text-faint);
}

.hbar-row { display: flex; align-items: center; gap: 0.75rem; margin-bottom: 0.5rem; }
.hbar-label { flex: 0 0 12rem; font-size: 0.8125rem; }
.hbar-track { flex: 1; height: 10px; background: var(--bg-sunken); border-radius: 999px; }
.hbar-fill { height: 100%; border-radius: 999px; min-width: 3px; }
.hbar-blue { background: #4d7cfe; }
.hbar-green { background: #2f9e6d; }
.hbar-amber { background: #b8842b; }
.hbar-value {
    flex: 0 0 5.5rem;
    text-align: right;
    font-variant-numeric: tabular-nums;
    font-weight: 600;
}

.stat-warn { color: #e0a33a; }
.stat-danger { color: var(--danger); }
.whoami {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    color: var(--text-muted);
    font-weight: 500;
}
.avatar-dot {
    display: grid;
    place-items: center;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    background: var(--bg-raised);
    border: 1px solid var(--border-strong);
    color: var(--text);
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
}
.logout-form { display: flex; align-items: center; gap: 0.6rem; margin: 0; }
.logout-form label { margin: 0; }

/* ---------- Notification bell ---------------------------------------- */
/* The topbar stays the neutral dark theme regardless of company scope, so
   these read from the root variables directly. */
.notif-wrap { position: relative; display: inline-flex; }
.notif-btn { position: relative; padding: 0.3rem 0.45rem; }
.notif-btn.has-unread { color: var(--text); }
.notif-badge {
    position: absolute;
    top: -3px;
    right: -3px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: var(--radius-pill);
    background: var(--danger);
    color: #fff;
    font-size: 0.625rem;
    font-weight: 700;
    line-height: 16px;
    text-align: center;
}
.notif-panel {
    position: absolute;
    top: calc(100% + 0.5rem);
    right: 0;
    width: 340px;
    max-width: 92vw;
    background: var(--bg-panel);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    z-index: 60;
    overflow: hidden;
}
.notif-panel[hidden] { display: none; }
.notif-panel-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.6rem 0.85rem;
    border-bottom: 1px solid var(--border);
}
.notif-list { list-style: none; margin: 0; padding: 0; max-height: 22rem; overflow-y: auto; }
.notif-empty { padding: 1.25rem 0.85rem; color: var(--text-faint); font-size: 0.8125rem; text-align: center; }
.notif-item {
    padding: 0.6rem 0.85rem;
    border-bottom: 1px solid var(--border);
    cursor: pointer;
}
.notif-item:last-child { border-bottom: none; }
.notif-item:hover { background: var(--bg-hover); }
.notif-unread { background: var(--accent-soft); }
.notif-unread:hover { background: var(--accent-soft); }
.notif-tag {
    display: inline-block;
    margin-bottom: 0.3rem;
    padding: 0.05rem 0.45rem;
    border-radius: var(--radius-pill);
    font-size: 0.625rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    text-transform: uppercase;
}
.notif-tag-low_stock { background: var(--danger-soft); color: #f2a3a7; border: 1px solid rgba(229, 100, 107, 0.35); }
.notif-tag-reorder_report { background: var(--accent-soft); color: #a8c1ff; border: 1px solid rgba(77, 124, 254, 0.35); }
.notif-item-title { font-weight: 600; }
.notif-item-body { color: var(--text-muted); font-size: 0.8125rem; margin-top: 0.1rem; }
.notif-item-when { color: var(--text-faint); font-size: 0.6875rem; margin-top: 0.25rem; }

.content {
    flex: 1;
    width: 100%;
    max-width: 1240px;
    margin: 0 auto;
    padding: 1.75rem;
    background: var(--bg);
    color: var(--text);
}

/* ---------- Messages ------------------------------------------------ */

.messages { list-style: none; padding: 1rem 1.75rem 0; margin: 0 auto; max-width: 1240px; }
.message {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.6rem 0.85rem;
    margin-bottom: 0.5rem;
    border-radius: var(--radius);
    border: 1px solid transparent;
    font-weight: 500;
}
.message-success { background: var(--success-soft); border-color: rgba(63, 191, 135, 0.3); color: #8ce0b9; }
.message-error { background: var(--danger-soft); border-color: rgba(229, 100, 107, 0.3); color: #f2a3a7; }

/* ---------- Panels & page heads ------------------------------------- */

.panel {
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 1.25rem 1.35rem;
    margin-bottom: 1.25rem;
    background: var(--bg-panel);
    box-shadow: var(--shadow);
}
.panel > :last-child { margin-bottom: 0; }

.detail-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 1rem;
    flex-wrap: wrap;
}
.detail-header h1, .detail-header h2 { margin-bottom: 0; }
.detail-header p { margin: 0; }

.hint { color: var(--text-muted); font-size: 0.8125rem; }
.content > .hint { margin-top: 0; margin-bottom: 1.25rem; max-width: 78ch; }
.empty-hint { color: var(--text-faint); font-size: 0.8125rem; }

/* ---------- Tables --------------------------------------------------- */

.data-table {
    width: 100%;
    border-collapse: collapse;
    font-variant-numeric: tabular-nums;
}
.data-table th {
    text-align: left;
    padding: 0.5rem 0.75rem;
    border-bottom: 1px solid var(--border-strong);
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-faint);
    white-space: nowrap;
}
.data-table td {
    padding: 0.6rem 0.75rem;
    border-bottom: 1px solid var(--border);
    vertical-align: middle;
}
.data-table tbody tr:last-child td { border-bottom: none; }
.data-table tbody tr:hover td { background: var(--bg-hover); }
.data-table td:only-child { color: var(--text-muted); }

/* ---------- Definition grids ---------------------------------------- */

.detail-grid { display: grid; grid-template-columns: max-content 1fr; gap: 0.5rem 1.25rem; margin: 0; }
.detail-grid dt { font-size: 0.8125rem; color: var(--text-muted); }
.detail-grid dd { margin: 0; font-weight: 500; }

.link-list { list-style: none; padding: 0; margin: 0; }
.link-list li { padding: 0.3rem 0; border-bottom: 1px solid var(--border); }
.link-list li:last-child { border-bottom: none; }

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

button, .btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    padding: 0.45rem 0.85rem;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    background: var(--accent);
    color: var(--accent-text);
    font: inherit;
    font-weight: 550;
    line-height: 1.3;
    cursor: pointer;
    white-space: nowrap;
    text-decoration: none;
}
button:hover, .btn:hover { background: var(--accent-hover); text-decoration: none; }
button:disabled { opacity: 0.45; cursor: not-allowed; }
button:focus-visible, .btn:focus-visible, a:focus-visible,
input:focus-visible, select:focus-visible, textarea:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 1px;
}

.btn-secondary {
    background: var(--bg-raised);
    color: var(--text);
    border-color: var(--border-strong);
}
.btn-secondary:hover { background: var(--border); }

.btn-danger { background: transparent; color: var(--danger); border-color: rgba(229, 100, 107, 0.4); }
.btn-danger:hover { background: var(--danger-soft); color: #f2a3a7; }

.btn-ghost { background: transparent; color: var(--text-muted); border-color: var(--border-strong); }
.btn-ghost:hover { background: var(--bg-hover); color: var(--text); }

.btn-sm { padding: 0.3rem 0.6rem; font-size: 0.8125rem; }

/* Reprint-label button: lighter blue, white icon + text. Sits wherever a
   thing can have its QR label reprinted (item / unit / container). */
.btn-print { background: var(--print-blue); color: #fff; }
.btn-print:hover { background: var(--print-blue-hover); color: #fff; }
.btn-print .ico { color: #fff; }

/* The "+ Add part/consumable/machine" button on a company-themed catalogue:
   its background is the company's accent (gold / cyan / rust), where white
   label text washes out — force black so it stays legible. Scoped to themed
   `.content` so the umbrella (neutral blue) pages keep the default. */
.content[class*="theme-"] .btn-add-item,
.content[class*="theme-"] .btn-add-item:hover { color: #111; }

/* A plain text link that sits next to a submit button (e.g. "Cancel"). */
.btn-link { background: none; border: none; color: var(--text-muted); padding: 0.45rem 0.5rem; }
.btn-link:hover { background: none; color: var(--text); text-decoration: underline; }

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

form label { display: block; margin-bottom: 0.85rem; font-size: 0.8125rem; color: var(--text-muted); }
form p { margin: 0 0 0.85rem; }
form p > label { margin-bottom: 0.3rem; }

input, select, textarea {
    padding: 0.45rem 0.6rem;
    background: var(--bg-sunken);
    color: var(--text);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    font: inherit;
}
input::placeholder { color: var(--text-faint); }
input:focus, select:focus, textarea:focus { border-color: var(--accent); }

form input, form select, form textarea {
    display: block;
    margin-top: 0.3rem;
    width: 100%;
    max-width: 440px;
}
form input[type="checkbox"], form input[type="radio"] {
    display: inline-block;
    width: auto;
    margin: 0 0.4rem 0 0;
    accent-color: var(--accent);
}
form .helptext { display: block; margin-top: 0.25rem; font-size: 0.75rem; color: var(--text-faint); }
form ul { list-style: none; padding: 0; margin: 0.3rem 0 0; }
form ul label { display: flex; align-items: center; gap: 0.4rem; margin-bottom: 0.2rem; color: var(--text); }

/* A row of labelled fields ending in a submit button — the scan/checkout
   bars. Fields sit side by side instead of stacking. */
.field-row { display: flex; gap: 0.75rem; align-items: flex-end; flex-wrap: wrap; }
.field { display: flex; flex-direction: column; gap: 0.25rem; }
.field > label { margin: 0; font-size: 0.75rem; color: var(--text-muted); }
.field input, .field select, .field textarea { margin-top: 0; width: auto; max-width: none; }
.field-grow { flex: 1 1 20rem; }
.field-grow input { width: 100%; }
.field-num input { width: 5rem; }
.field-row button { margin-bottom: 1px; }

/* Inline forms (table-row actions, scan bars) must NOT stack their fields. */
.inline-form { display: flex; gap: 0.4rem; align-items: center; flex-wrap: wrap; }
.inline-form label { display: inline-flex; align-items: center; gap: 0.35rem; margin: 0; white-space: nowrap; }
.inline-form input, .inline-form select { display: inline-block; margin-top: 0; width: auto; max-width: none; }
.inline-form input[type="text"], .inline-form input[type="search"] { min-width: 13rem; }
.inline-form input[type="number"] { width: 4.5rem; }

.form-error { color: var(--danger); }

.login-wrap { max-width: 380px; margin: 10vh auto; }
.login-brand { display: flex; align-items: center; gap: 0.75rem; justify-content: center; margin-bottom: 1.75rem; }
.login-brand .brand-mark { width: 40px; height: 40px; border-radius: 10px; font-size: 1rem; }
.login-wrap h1 { margin: 0; font-size: 1.25rem; }
.login-form {
    padding: 1.75rem;
    background: var(--bg-panel);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
}
.login-form input { max-width: none; }
.login-form button { width: 100%; margin-top: 0.5rem; padding: 0.6rem; }

/* ---------- Search / filters ----------------------------------------- */

.search-bar { display: flex; gap: 0.5rem; align-items: center; }
.search-bar input {
    width: 100%;
    max-width: none;
    padding: 0.7rem 0.9rem;
    font-size: 1rem;
    background: var(--bg-panel);
    border-radius: var(--radius);
}

/* Camera-scan button injected next to any input[data-camera-scan], and the
   full-screen live-preview overlay it opens. Uses the browser's native
   BarcodeDetector — no vendored QR-decoding library. */
.scan-btn { flex-shrink: 0; padding: 0.6rem 0.8rem; }
.scan-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.85);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 100;
}
.scan-box {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.75rem;
    padding: 1rem;
    max-width: 92vw;
}
.scan-box video {
    max-width: 90vw;
    max-height: 60vh;
    border-radius: var(--radius);
    background: #000;
}
.scan-box .hint { color: var(--text-muted); }
.filter-chips { display: flex; gap: 0.4rem; flex-wrap: wrap; margin: 0.75rem 0 1.25rem; }
.filter-chip {
    padding: 0.3rem 0.75rem;
    border-radius: var(--radius-pill);
    border: 1px solid var(--border-strong);
    background: transparent;
    color: var(--text-muted);
    font-size: 0.8125rem;
    font-weight: 500;
    cursor: pointer;
}
.filter-chip:hover { background: var(--bg-hover); color: var(--text); }
.filter-chip.active { background: var(--accent); border-color: var(--accent); color: var(--accent-text); }
.search-jump {
    padding: 0.7rem 0.9rem;
    margin-bottom: 1rem;
    background: var(--accent-soft);
    border: 1px solid rgba(77, 124, 254, 0.35);
    border-radius: var(--radius);
    font-weight: 500;
}
#find-results h2 { margin: 1.5rem 0 0.6rem; }

/* ---------- Badges ---------------------------------------------------- */

.badge {
    display: inline-flex;
    align-items: center;
    padding: 0.1rem 0.5rem;
    border-radius: var(--radius-pill);
    background: var(--accent-soft);
    border: 1px solid rgba(77, 124, 254, 0.35);
    color: #a8c1ff;
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    vertical-align: middle;
}
.badge-low-stock { background: var(--danger-soft); border-color: rgba(229, 100, 107, 0.35); color: #f2a3a7; }
.badge-ok { background: var(--success-soft); border-color: rgba(63, 191, 135, 0.35); color: #8ce0b9; }
.badge-warn { background: var(--warn-soft); border-color: rgba(224, 163, 58, 0.35); color: #f0cd8c; }

/* ---------- Stat tiles ------------------------------------------------ */

.stat-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: 0.85rem; margin-bottom: 1.5rem; }
.stat-tile {
    padding: 1rem 1.1rem;
    background: var(--bg-panel);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow);
}
.stat-value { font-size: 1.75rem; font-weight: 650; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.stat-label { margin-top: 0.15rem; color: var(--text-muted); font-size: 0.8125rem; }

/* ---------- Detail pages ---------------------------------------------- */

.detail-columns { display: flex; gap: 2rem; align-items: flex-start; flex-wrap: wrap; }
.detail-columns .detail-grid { flex: 1 1 340px; }
.detail-media { display: flex; flex-direction: column; gap: 0.6rem; align-items: center; }
.detail-photo { max-width: 220px; border-radius: var(--radius); border: 1px solid var(--border); }
.detail-qr { width: 128px; height: 128px; background: #fff; padding: 6px; border-radius: var(--radius); }

/* ---------- Dashboard board -------------------------------------------- */

.board { display: flex; gap: 1.25rem; align-items: flex-start; flex-wrap: wrap; }
.board-column { flex: 1 1 260px; }
.board-column-wide { flex: 3 1 600px; }

.drop-zone {
    border: 1px dashed var(--border-strong);
    border-radius: var(--radius);
    min-height: 4rem;
    padding: 0.6rem;
}
.drop-zone.drag-over { border-color: var(--accent); background: var(--accent-soft); }

.vehicle-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 1rem; }
.vehicle-card {
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 0.85rem;
    background: var(--bg-panel);
    box-shadow: var(--shadow);
    cursor: pointer;
    transition: border-color 0.12s ease, transform 0.12s ease;
}
.vehicle-card:hover { border-color: var(--border-strong); transform: translateY(-1px); }
.vehicle-card-header { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; font-weight: 600; }
.vehicle-card-header a { color: inherit; }
.vehicle-meta { font-size: 0.75rem; color: var(--text-muted); margin-top: 0.2rem; }
.vehicle-photo { max-width: 240px; border-radius: var(--radius); display: block; margin-bottom: 1rem; }
.vehicle-card-photo { width: 100%; height: 100px; object-fit: cover; border-radius: var(--radius-sm); margin-bottom: 0.6rem; }

/* ---------- Dashboard grid --------------------------------------------
   Find + containers on the left, technicians in the middle, vehicles on the
   right — the flow of a hand-off, left to right. */
.dash-grid { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 1.25rem; align-items: start; }
.dash-col { display: flex; flex-direction: column; gap: 1.25rem; min-width: 0; }
.dash-scroll { max-height: 22rem; overflow-y: auto; }
@media (max-width: 1200px) { .dash-grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 820px) { .dash-grid { grid-template-columns: 1fr; } }

/* On desktop the board is one screenful: the three columns share a fixed
   height below the sticky topbar and each scrolls its OWN content, so their
   tops stay locked together and a drag runs straight across. The left column
   (Jobs / Containers / Find a part) is what you scroll to bring a source into
   line; Technicians and Vehicles — the drop targets — never leave the screen.
   (Native HTML5 drag doesn't auto-scroll mid-drag, so keeping the targets
   fixed is what makes the drag usable.) The per-panel scroll boxes give way to
   this per-column one. Only in the true three-column layout (>1200px): at
   narrower widths the grid folds to 2/1 columns and a panel wraps to a second
   row, which a fixed board height would squash — those keep normal page
   scrolling. */
@media (min-width: 1201px) {
    .dash-grid {
        align-items: stretch;
        height: calc(100vh - 11rem);
        min-height: 26rem;
    }
    .dash-col {
        overflow-y: auto;
        min-height: 0;
        padding-right: .4rem;
    }
    .dash-col > .panel { flex: 0 0 auto; }
    .dash-scroll { max-height: none; overflow: visible; }
}

/* A person/vehicle on the board: a drag handle AND a drop target AND a card
   you can open. Cursor stays `grab` only where dragging is possible. */
.board-card {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    padding: 0.6rem 0.7rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-raised);
    margin-bottom: 0.5rem;
    cursor: pointer;
}
.board-card:hover { border-color: var(--border-strong); }
.board-card.dragging { opacity: 0.4; }
.board-card.drag-over { outline: 2px solid var(--success); outline-offset: 2px; }
.board-card-body { flex: 1; min-width: 0; }
.board-card-body strong { display: block; }
.board-card-avatar { width: 38px; height: 38px; border-radius: 50%; object-fit: cover; flex-shrink: 0; font-size: 0.9rem; }
.board-card-vehicle { border-left: 3px solid var(--accent); }

/* ---------- The card overlay ------------------------------------------ */
.card-box { max-width: 640px; }
.card-head { display: flex; gap: 1.25rem; align-items: flex-start; flex-wrap: wrap; margin-bottom: 1rem; }
.card-photo { flex: 0 0 auto; }
.card-photo-img {
    width: 150px;
    height: 150px;
    border-radius: var(--radius);
    object-fit: cover;
    font-size: 3rem;
}
.card-info { flex: 1 1 16rem; min-width: 0; }
.card-info h2 { margin-bottom: 0.15rem; }
.card-info .detail-grid { margin: 0.75rem 0; }
.card-notes {
    padding: 0.6rem 0.75rem;
    margin-bottom: 0.75rem;
    background: var(--warn-soft);
    border: 1px solid rgba(224, 163, 58, 0.35);
    border-radius: var(--radius-sm);
    font-size: 0.8125rem;
    white-space: pre-wrap;
}

/* Faint card tints — recognition only, no meaning. Kept low-alpha so text
   contrast is untouched and they never read as a status.

   Scoped to both card types explicitly (.tech-card.tint-X, .board-card.tint-X)
   rather than a bare .tint-X — a bare class has the same specificity as the
   base .tech-card/.board-card background rules below, so whichever is later
   in the file silently wins. Pairing the tint with its card class raises
   specificity so a tint always overrides the base background regardless of
   source order. */
.tech-card.tint-blue, .board-card.tint-blue { background: rgba(77, 124, 254, 0.16); border-color: rgba(77, 124, 254, 0.4); }
.tech-card.tint-green, .board-card.tint-green { background: rgba(63, 191, 135, 0.15); border-color: rgba(63, 191, 135, 0.4); }
.tech-card.tint-amber, .board-card.tint-amber { background: rgba(224, 163, 58, 0.15); border-color: rgba(224, 163, 58, 0.4); }
.tech-card.tint-red, .board-card.tint-red { background: rgba(229, 100, 107, 0.15); border-color: rgba(229, 100, 107, 0.4); }
.tech-card.tint-purple, .board-card.tint-purple { background: rgba(150, 110, 240, 0.16); border-color: rgba(150, 110, 240, 0.4); }
.tech-card.tint-teal, .board-card.tint-teal { background: rgba(45, 190, 200, 0.15); border-color: rgba(45, 190, 200, 0.4); }
.tech-card.tint-pink, .board-card.tint-pink { background: rgba(232, 110, 180, 0.15); border-color: rgba(232, 110, 180, 0.4); }

/* The vehicle's photo, left of its information. */
.vehicle-thumb {
    width: 64px;
    height: 64px;
    border-radius: var(--radius-sm);
    object-fit: cover;
    flex-shrink: 0;
    font-size: 1.5rem;
}

/* The technicians pool is itself the drop target for un-assigning. Bubbles
   here are stacked one per line and sized up — this is the list you're
   dragging FROM, so the grab targets should be generous. */
#technician-list.drop-zone { min-height: 5rem; }
#technician-list { display: flex; flex-direction: column; gap: 0.5rem; }
#technician-list .empty-hint { margin: 0; }
#technician-list .tech-card {
    width: 100%;
    justify-content: flex-start;
    gap: 0.65rem;
    padding: 0.45rem 1rem 0.45rem 0.45rem;
    font-size: 1rem;
    font-weight: 600;
}
#technician-list .tech-card-avatar { width: 40px; height: 40px; font-size: 1.05rem; }

/* A crew sharing a dispatcher-created CrewLink — boxed together with the
   job number on a tag at the top. Each bubble underneath is still its own
   drag source/drop target (only the vehicle-drop moves the whole crew).
   Clicking the tag unlinks the crew (a board-only undo, see
   dashboard/api.py's DashboardCrewUnlinkAPIView). */
.tech-group {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    padding: 1rem 0.5rem 0.5rem;
    margin-top: 0.7rem;
    position: relative;
}
.tech-group-tag {
    position: absolute;
    top: -0.7rem;
    left: 0.6rem;
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    background: var(--bg-raised);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-pill);
    padding: 0.15rem 0.65rem;
    font: inherit;
    font-size: 0.7rem;
    font-weight: 600;
    line-height: 1.4;
    color: var(--text-muted);
    cursor: pointer;
    appearance: none;
    -webkit-appearance: none;
}
.tech-group-tag:hover { color: var(--danger); border-color: var(--danger); }
.tech-group-tag .ico { width: 11px; height: 11px; }

/* A rider on a vehicle card: name, then their totes, then their parts link. */
.rider-row { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.rider-row a.badge { text-decoration: none; }

/* A carried thing, with its Return button pinned right. */
.carry-row { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; }

.board-lower { margin-top: 1.5rem; }

/* Draggable rows: a portable container, or a part from the search. */
.portable-card {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.6rem 0.75rem;
    border-bottom: 1px solid var(--border);
    cursor: grab;
}
.portable-card:last-child { border-bottom: none; }
.portable-card:hover { background: var(--bg-hover); }
.portable-card:active { cursor: grabbing; }
.portable-card.dragging { opacity: 0.4; }
.portable-card-muted { cursor: default; opacity: 0.5; }
.portable-card-muted:hover { background: none; }
.portable-card > div:first-child { min-width: 0; }

/* Where a part actually lives — shown before you drag it anywhere. */
.part-where { color: var(--text-faint); }

/* The whole technicians panel is the unassign target. */
#technician-panel.drag-over {
    outline: 2px dashed var(--accent);
    outline-offset: -4px;
    background: var(--accent-soft);
}

/* A technician is a drop target for containers and parts. */
.tech-card.drag-over {
    outline: 2px solid var(--success);
    outline-offset: 2px;
    background: var(--success);
}
.tech-card.dragging { opacity: 0.4; }

.modal-narrow { max-width: 520px; }

.tech-slot { margin-top: 0.6rem; min-height: 2.75rem; display: flex; flex-wrap: wrap; gap: 0.4rem; }
.tech-card {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.25rem 0.7rem 0.25rem 0.25rem;
    border-radius: var(--radius-pill);
    border: 1px solid var(--border);
    background: var(--bg-raised);
    color: var(--text);
    font-size: 0.8125rem;
    font-weight: 550;
    cursor: grab;
    box-shadow: var(--shadow);
}
.tech-card:active { cursor: grabbing; }
.tech-card-readonly { cursor: default; opacity: 0.9; }
.tech-card-avatar { width: 26px; height: 26px; border-radius: 50%; object-fit: cover; font-size: 0.75rem; flex-shrink: 0; }

/* The job number a technician is currently assigned to — pinned to the
   right edge of their bubble so a solo assignment (no crew, no tag above)
   is still visible at a glance. */
.tech-card-job { margin-left: auto; flex-shrink: 0; }
.tech-card-avatar.person-photo-placeholder { font-size: 0.75rem; }

/* ---------- People ------------------------------------------------------ */

.person-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: 1rem; }
.person-card {
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 1rem 0.75rem;
    text-align: center;
    background: var(--bg-panel);
    box-shadow: var(--shadow);
}
.person-photo { width: 88px; height: 88px; border-radius: 50%; object-fit: cover; margin: 0 auto 0.6rem; display: block; }
.person-photo-placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--bg-raised);
    border: 1px solid var(--border-strong);
    color: var(--text);
    font-size: 1.75rem;
    font-weight: 600;
}
.person-photo-large { width: 150px; height: 150px; margin-bottom: 1rem; }
.person-name { font-weight: 600; }
.person-meta { font-size: 0.75rem; color: var(--text-muted); }
.person-edit { font-size: 0.8125rem; }

/* ---------- Modal -------------------------------------------------------- */

.modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.6);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 100;
    padding: 1rem;
}
.modal-overlay[hidden] { display: none; }
.modal-box {
    background: var(--bg-panel);
    color: var(--text);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    padding: 1.5rem;
    max-width: 720px;
    width: 100%;
    max-height: 80vh;
    overflow-y: auto;
}
.modal-close {
    float: right;
    background: none;
    border: none;
    color: var(--text-muted);
    font-size: 1.25rem;
    line-height: 1;
    padding: 0.15rem 0.4rem;
    cursor: pointer;
}
.modal-close:hover { background: var(--bg-hover); color: var(--text); }

/* A job note in full, wrapped as typed and scrollable within the modal
   (.modal-box already caps at 80vh) rather than overflowing the page. */
.note-modal-body { white-space: pre-wrap; word-break: break-word; line-height: 1.5; }
.note-modal-body mark { background: var(--accent-soft); color: inherit; border-radius: 3px; padding: 0 0.15em; }

/* ---------- Audit scanning ------------------------------------------------ */

.scan-log { list-style: none; padding: 0; margin: 0; max-height: 280px; overflow-y: auto; font-family: var(--mono-font); font-size: 0.8125rem; }
.scan-log li { padding: 0.35rem 0.5rem; border-bottom: 1px solid var(--border); }
.scan-ok { color: var(--success); }
.scan-error { color: var(--danger); }
.scan-unknown { color: var(--warn); }

.report-section.report-ok { border-color: rgba(63, 191, 135, 0.5); }
.report-section.report-warn { border-color: rgba(224, 163, 58, 0.5); }
.report-section.report-bad { border-color: rgba(229, 100, 107, 0.5); }

/* ---------- Audit report (results screen) --------------------------------
   An accuracy gauge + headline counts, then discrepancies grouped and
   colour-coded most-urgent first, then what checked out. */
.stat-ok { color: var(--success); }

.audit-summary { display: flex; align-items: center; gap: 1.75rem; flex-wrap: wrap; margin-bottom: 1.75rem; }

/* Accuracy gauge: a conic-gradient donut filled to --pct, hue by threshold. */
.accuracy-ring {
    --pct: 100;
    --ring: var(--success);
    position: relative;
    width: 108px;
    height: 108px;
    flex-shrink: 0;
    border-radius: 50%;
    background: conic-gradient(var(--ring) calc(var(--pct) * 1%), var(--bg-raised) 0);
    display: grid;
    place-items: center;
}
.accuracy-ring::before {
    content: "";
    position: absolute;
    inset: 9px;
    border-radius: 50%;
    background: var(--bg);
}
.accuracy-ring-inner { position: relative; text-align: center; line-height: 1.1; }
.accuracy-pct { font-size: 1.5rem; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--ring); }
.accuracy-label { font-size: 0.65rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); }
.accuracy-ok { --ring: var(--success); }
.accuracy-mid { --ring: var(--warn); }
.accuracy-low { --ring: var(--danger); }

.audit-stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0.7rem; flex: 1 1 320px; }
.audit-stat {
    padding: 0.75rem 0.5rem;
    background: var(--bg-panel);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    text-align: center;
}
.audit-stat-num { font-size: 1.6rem; font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums; }
.audit-stat-label { margin-top: 0.3rem; font-size: 0.75rem; color: var(--text-muted); }

/* A left rail carries the rectify/quarantine marks; the heading and the cards
   both align to its right edge, so the colored line still matches the heading. */
.audit-section { margin-bottom: 1.75rem; padding-left: 3.9rem; }
.audit-section-head { display: flex; align-items: center; gap: 0.5rem 0.6rem; flex-wrap: wrap; margin-bottom: 0.7rem; }
.audit-section-head h2 { margin: 0; }
.audit-section-head .ico { width: 18px; height: 18px; }
/* The section explanation sits inline, to the right of the heading. */
.audit-section-note { color: var(--text-muted); font-size: 0.8125rem; font-weight: 400; }
.audit-section-note::before { content: "—"; margin-right: 0.45rem; color: var(--text-faint); }
.audit-section > .hint { margin: 0 0 0.7rem; }

.audit-rows { display: flex; flex-direction: column; gap: 0.5rem; }

/* The colored card sits at the section's left edge (aligned with the heading);
   the rectify/quarantine "mark" floats just off its left — see .audit-mark. */
.audit-row {
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: 0.7rem;
    padding: 0.7rem 0.9rem;
    background: var(--bg-panel);
    border: 1px solid var(--border);
    border-left-width: 4px;
    border-radius: var(--radius);
}
.audit-row .ico { width: 18px; height: 18px; flex-shrink: 0; margin-top: 1px; }
.audit-row-good { border-left-color: var(--success); }
.audit-row-good .ico { color: var(--success); }
.audit-row-warn { border-left-color: var(--warn); }
.audit-row-warn .ico { color: var(--warn); }
.audit-row-bad { border-left-color: var(--danger); }
.audit-row-bad .ico { color: var(--danger); }
.audit-row-body { flex: 1; min-width: 0; }
.audit-row-title { font-weight: 600; }
a.audit-row-title { color: var(--text); }
a.audit-row-title:hover { color: var(--accent); }
.audit-row-meta { font-size: 0.8125rem; color: var(--text-muted); margin-top: 0.15rem; }

.audit-allclear { display: flex; align-items: center; gap: 1rem; border-color: rgba(63, 191, 135, 0.4); }
.audit-allclear .ico { width: 36px; height: 36px; color: var(--success); flex-shrink: 0; }
.audit-allclear h2 { margin: 0 0 0.15rem; }

/* Rectification controls layered onto a finding row (the finding text stays;
   these sit under it). Each button is its own little form. */
.audit-fix { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem; margin-top: 0.55rem; }
.audit-fix form { margin: 0; }
.audit-fix select { padding: 0.3rem 0.5rem; font-size: 0.8125rem; }

/* The green "this finding was handled" line. */
.audit-resolved {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    margin-top: 0.5rem;
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--success);
}
.audit-resolved .ico { width: 15px; height: 15px; }

/* The amber "sent to quarantine" note on a missing row. */
.audit-quarantined {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    margin-top: 0.5rem;
    font-size: 0.8125rem;
    color: var(--warn);
}
.audit-quarantined .ico { width: 15px; height: 15px; }
.audit-quarantined a { color: var(--warn); text-decoration: underline; }

/* On the quarantine page: a "it turned up over here" callout with a one-tap place. */
.audit-sighting {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-top: 0.55rem;
    padding: 0.5rem 0.7rem;
    background: var(--warn-soft);
    border: 1px solid rgba(224, 163, 58, 0.35);
    border-radius: var(--radius-sm);
    font-size: 0.8125rem;
}
.audit-sighting .ico { width: 16px; height: 16px; flex-shrink: 0; }
.audit-sighting form { margin: 0 0 0 auto; }

/* ---------- Audit list cards (accuracy at a glance) ----------------------- */
.audit-cards { display: flex; flex-direction: column; gap: 0.85rem; }
.audit-card {
    display: flex;
    align-items: center;
    gap: 1.1rem;
    padding: 1rem 1.25rem;
    background: var(--bg-panel);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow);
    color: var(--text);
    text-decoration: none;
    transition: border-color 0.12s ease, transform 0.12s ease;
}
.audit-card:hover { border-color: var(--border-strong); text-decoration: none; transform: translateY(-1px); }
.audit-card-score { flex-shrink: 0; width: 66px; text-align: center; }
.audit-card-pct { font-size: 1.5rem; font-weight: 700; line-height: 1; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.audit-card-pct-label { font-size: 0.62rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-faint); margin-top: 0.15rem; }
.audit-card-score.score-ok .audit-card-pct { color: var(--success); }
.audit-card-score.score-mid .audit-card-pct { color: var(--warn); }
.audit-card-score.score-low .audit-card-pct { color: var(--danger); }
.audit-card-live { width: 24px; height: 24px; color: var(--text-faint); }
.audit-card-body { flex: 1; min-width: 0; }
.audit-card-title { font-weight: 650; }
.audit-card-meta { font-size: 0.8125rem; color: var(--text-muted); margin-top: 0.15rem; }
.audit-card-by { font-size: 0.75rem; color: var(--text-faint); margin-top: 0.15rem; }
.audit-card-chev { width: 20px; height: 20px; color: var(--text-faint); flex-shrink: 0; }
.audit-card:hover .audit-card-chev { color: var(--text-muted); }

/* Two accuracy gauges on the report: as found → after fixes. */
.audit-rings { display: flex; align-items: center; gap: 0.85rem; flex-shrink: 0; }
.audit-ring-arrow { width: 22px; height: 22px; color: var(--text-faint); }

.audit-rectified-note {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.7rem 0.9rem;
    margin: 0 0 1.5rem;
    background: var(--success-soft);
    border: 1px solid rgba(63, 191, 135, 0.3);
    border-radius: var(--radius);
    font-size: 0.875rem;
}
.audit-rectified-note .ico { width: 18px; height: 18px; flex-shrink: 0; }

/* Compact per-row status chips (keep discrepancy rows to a single tidy line). */
.audit-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.25rem 0.6rem;
    border-radius: var(--radius-pill);
    font-size: 0.75rem;
    font-weight: 600;
    white-space: nowrap;
    flex-shrink: 0;
}
.audit-chip .ico { width: 13px; height: 13px; }
.audit-chip-ok { background: var(--success-soft); color: #8ce0b9; border: 1px solid rgba(63, 191, 135, 0.35); }
.audit-chip-warn { background: var(--warn-soft); color: #f0cd8c; border: 1px solid rgba(224, 163, 58, 0.35); }
a.audit-chip-warn:hover { text-decoration: none; border-color: var(--warn); }

/* Rectify / quarantine / fixed "mark": a compact colored badge floating just
   off the left of the card, so it stands out while the card stays aligned with
   the heading. */
.audit-row > .audit-mark {
    position: absolute;
    right: calc(100% + 0.45rem);
    top: 50%;
    transform: translateY(-50%);
    z-index: 3;
    line-height: 0;
}
.audit-mark-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 27px;
    height: 27px;
    border-radius: var(--radius-sm);
    border: 1px solid transparent;
    background: var(--bg-raised);
    cursor: pointer;
    list-style: none;
    box-shadow: var(--shadow);
}
.audit-mark-btn::-webkit-details-marker { display: none; }
.audit-mark-btn .ico { width: 15px; height: 15px; }
/* Labelled variant — a short pill ("Fix ▾" / "Fixed") instead of a bare icon. */
.audit-mark-pill {
    width: auto;
    height: auto;
    gap: 0.25rem;
    padding: 0.3rem 0.55rem;
    font-size: 0.75rem;
    font-weight: 600;
    line-height: 1;
}
.audit-mark-pill .audit-caret { font-size: 0.7em; }
.audit-mark-warn { background: var(--warn-soft); border-color: rgba(224, 163, 58, 0.55); color: #f0cd8c; }
.audit-mark-warn:hover { border-color: var(--warn); color: #f5d89b; }
.audit-mark-ok { background: var(--success-soft); border-color: rgba(63, 191, 135, 0.55); color: #8ce0b9; }
.audit-menu.audit-mark[open] > .audit-mark-btn { border-color: var(--warn); color: #f5d89b; }
/* The rectify menu opens to the right, over the card (not off into the margin). */
.audit-mark .audit-menu-panel { top: -2px; left: calc(100% + 0.4rem); }

/* The rectify dropdown — a native <details> menu, no JS. Sits to the left of
   the item line so a row with lots of issues stays a clean, uniform height. */
.audit-menu { position: relative; flex-shrink: 0; }
.audit-menu > summary { list-style: none; cursor: pointer; }
.audit-menu > summary::-webkit-details-marker { display: none; }
.audit-menu-trigger {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.3rem 0.6rem;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    background: var(--bg-raised);
    color: var(--text-muted);
    font-size: 0.8125rem;
    font-weight: 550;
    white-space: nowrap;
}
.audit-menu-trigger:hover { color: var(--text); border-color: var(--text-faint); }
.audit-menu[open] > .audit-menu-trigger { color: var(--text); border-color: var(--accent); background: var(--accent-soft); }
.audit-caret { font-size: 0.7em; }
.audit-menu-panel {
    position: absolute;
    top: calc(100% + 5px);
    left: 0;
    z-index: 40;
    min-width: 240px;
    padding: 0.35rem;
    background: var(--bg-raised);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    box-shadow: var(--shadow-lg);
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
}
.audit-menu-panel form { margin: 0; }
.audit-menu-heading {
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--text-faint);
    padding: 0.15rem 0.55rem 0.35rem;
}
.audit-menu-item {
    display: block;
    width: 100%;
    text-align: left;
    padding: 0.4rem 0.55rem;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--text);
    border: 1px solid transparent;
    font: inherit;
    font-size: 0.8125rem;
    font-weight: 500;
    cursor: pointer;
}
.audit-menu-item:hover { background: var(--bg-hover); }
.audit-menu-else {
    display: flex;
    gap: 0.3rem;
    align-items: center;
    margin-top: 0.15rem;
    padding-top: 0.35rem;
    border-top: 1px solid var(--border);
}
.audit-menu-else select { flex: 1; min-width: 0; padding: 0.3rem 0.4rem; font-size: 0.8125rem; }

@media (max-width: 600px) {
    .audit-card { gap: 0.85rem; padding: 0.85rem 1rem; }
    .audit-menu-panel { min-width: 210px; }
    /* No room for the rail on a phone — drop it and sit the mark inside the
       card's left instead, still first thing on the line. */
    .audit-section { padding-left: 0; }
    .audit-row > .audit-mark { position: relative; right: auto; top: auto; transform: none; }
    .audit-mark .audit-menu-panel { top: calc(100% + 5px); left: 0; }
}

@media (max-width: 600px) {
    .audit-stats { grid-template-columns: repeat(2, 1fr); }
    .audit-summary { gap: 1rem; }
}

/* ---------- Responsive -----------------------------------------------------
   Everything below is mobile-only (inside max-width queries) — the desktop
   layout above is deliberately left untouched. Two breakpoints: ~tablet/large
   phone (900px) collapses the shell to a top bar + hamburger menu; ~phone
   (600px) tightens spacing and reflows the busier components. */

@media (max-width: 900px) {
    .app { grid-template-columns: 1fr; }

    /* Sidebar becomes a sticky top bar: brand + hamburger always in reach, the
       nav itself tucked behind the toggle instead of a long horizontal scroll. */
    .sidebar {
        position: sticky;
        top: 0;
        z-index: 40;
        height: auto;
        max-height: 100vh;
        overflow-y: auto;
        padding: 0.4rem 0.85rem;
        border-right: none;
        border-bottom: 1px solid var(--border);
    }
    .sidebar-head { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; }
    .brand { padding: 0.35rem 0.25rem; }
    .brand-text small { display: none; }
    .nav-toggle { display: inline-flex; }

    /* Collapsed by default; the hamburger reveals the full menu as a dropdown. */
    .sidebar .nav-group { display: none; margin: 0.35rem 0 0.55rem; }
    .sidebar.nav-open { padding-bottom: 0.85rem; }
    .sidebar.nav-open .nav-group { display: block; }
    .nav-link { padding: 0.6rem 0.7rem; }   /* roomier tap targets */

    /* The topbar stops being sticky (the sidebar carries the nav now) and wraps
       instead of overflowing; the flex spacer would fight the wrap, so drop it. */
    .topbar {
        position: static;
        flex-wrap: wrap;
        gap: 0.5rem 0.75rem;
        padding: 0.6rem 1rem;
    }
    .topbar-spacer { display: none; }
    /* Company switcher gets its own row; the bell/log-out wrap beneath it. */
    .company-tabs { flex: 1 1 100%; }

    .content, .messages { padding-left: 1rem; padding-right: 1rem; }

    /* Any wide table scrolls inside itself, so the page never scrolls sideways.
       Headers already never wrap; nowrap keeps body cells from collapsing the
       columns, so the table keeps its shape and slides horizontally as a unit. */
    .data-table {
        display: block;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        white-space: nowrap;
    }
}

@media (max-width: 600px) {
    .content { padding: 1rem 0.85rem 2.5rem; }
    .messages { padding-left: 0.85rem; padding-right: 0.85rem; }
    h1 { font-size: 1.3rem; }

    /* Free up the crowded top row — the avatar/name is redundant with Log out. */
    .whoami { display: none; }
    .company-tab { min-height: 40px; padding: 0.4rem 0.85rem; }

    /* Headings and their action buttons stack rather than squeeze. */
    .detail-header { flex-direction: column; align-items: stretch; gap: 0.6rem; }
    .detail-header .btn,
    .detail-header .inline-form { align-self: flex-start; }

    /* Filter/scan/checkout rows and the fields inside them go full width. */
    .field-grow { flex-basis: 100%; }
    .inline-form input[type="text"],
    .inline-form input[type="search"] { min-width: 0; flex: 1 1 100%; }

    /* Horizontal bar charts: shrink the label/value gutters so the bar survives. */
    .hbar-label { flex-basis: 7rem; }
    .hbar-value { flex-basis: 3.75rem; }

    /* Stat tiles: tighter min so they stay two-up on most phones, one-up on tiny. */
    .stat-grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 0.6rem; }
    .stat-value { font-size: 1.45rem; }

    /* Modals use the space they have; big card photos scale down. */
    .modal-overlay { padding: 0.5rem; }
    .modal-box { padding: 1.15rem; max-height: 88vh; }
    .card-head { gap: 0.85rem; }
    .card-photo-img { width: 96px; height: 96px; font-size: 2rem; }
    .person-photo-large { width: 120px; height: 120px; }

    /* Keep the notification dropdown anchored to the bell but never wider than
       the screen, so it can't hang off the edge on a phone. */
    .notif-panel { width: min(340px, calc(100vw - 1rem)); }
}

/* ============================================================
   Company tab themes — scoped to `.content`, so the sidebar and
   topbar stay neutral no matter which company tab is open.
   ============================================================ */

/* Current Coffee Services — deep teal-green, gold accents, serif headings */
.content.theme-currentcup {
    --bg: #334f4c;
    --bg-sunken: #2a4340;
    --bg-panel: #2d4744;
    --bg-raised: #3b5b57;
    --bg-hover: rgba(255, 255, 255, 0.06);
    --border: #4a6a66;
    --border-strong: #e4b155;
    --text: #ffffff;
    --text-muted: #cfe0dc;
    --text-faint: #a8c2bd;
    --accent: #e4b155;
    --accent-hover: #f3cd82;
    --accent-soft: rgba(228, 177, 85, 0.15);
    --accent-text: #2a1f08;
    --heading-font: Georgia, "Times New Roman", serif;
}
.content.theme-currentcup a { color: #f3cd82; }
.content.theme-currentcup .badge { background: rgba(228, 177, 85, 0.2); border-color: #e4b155; color: #f3cd82; }

/* Fulcrum Technologies — dark navy, electric cyan, monospace headings */
.content.theme-fulcrum {
    --bg: #0a0f18;
    --bg-sunken: #070b12;
    --bg-panel: #111925;
    --bg-raised: #1a2534;
    --border: #223044;
    --border-strong: #2e405a;
    --text: #e3f6ff;
    --text-muted: #7d92a8;
    --text-faint: #5d7186;
    --accent: #00c8d6;
    --accent-hover: #2fe0ec;
    --accent-soft: rgba(0, 200, 214, 0.12);
    --accent-text: #04070e;
    --heading-font: ui-monospace, SFMono-Regular, Consolas, monospace;
}
.content.theme-fulcrum a { color: #00e5f5; }
.content.theme-fulcrum .badge { background: rgba(0, 200, 214, 0.15); border-color: #00c8d6; color: #7ef0f8; }

/* Pivot Floor Cleaning — teal-green with rust accents and gold borders */
.content.theme-pivot {
    --bg: #243836;
    --bg-sunken: #1c2c2a;
    --bg-panel: #213431;
    --bg-raised: #2d4441;
    --border: #3d5652;
    --border-strong: #c99840;
    --text: #ffffff;
    --text-muted: #d8cfc0;
    --text-faint: #ab9f8c;
    --accent: #cb5c28;
    --accent-hover: #e0703b;
    --accent-soft: rgba(203, 92, 40, 0.15);
    --accent-text: #ffffff;
}
.content.theme-pivot a { color: #ef7f45; }
.content.theme-pivot h1, .content.theme-pivot h2, .content.theme-pivot h3 { color: #f0c674; }
.content.theme-pivot .badge { background: rgba(203, 92, 40, 0.2); border-color: #cb5c28; color: #f0a077; }

/* ─── Bulk stock mover ──────────────────────────────────────────────── */

/* Wide: two panes side by side, drag between them. The rail is redundant
   and hidden, so the grid holds exactly two items. */
.move-panes { display: grid; grid-template-columns: 1fr 1fr; gap: 1.25rem; }
.move-panes > .move-pane { min-width: 0; }
.move-drop-rail { display: none; }

/* Narrow: source and rail share the top row, destination spans the row
   below. A move stays a SIDEWAYS drag — the shorter gesture, and the one
   that doesn't fight vertical scrolling — while the destination still
   shows what's landed. Grid places all three directly; nesting the source
   in a wrapper stopped it behaving like a grid item. */
@media (max-width: 800px) {
    .move-panes {
        grid-template-columns: 1fr 3.25rem;
        gap: 0.6rem;
    }
    .move-pane[data-side="source"] {
        grid-column: 1;
        grid-row: 1;
        /* The rail is as tall as this pane, so a nearly-empty source would
           otherwise shrink it to an unusable sliver. */
        min-height: 12rem;
    }
    .move-pane[data-side="dest"] {
        grid-column: 1 / -1;
        grid-row: 2;
    }

    .move-drop-rail {
        grid-column: 2;
        grid-row: 1;
        display: flex;
        flex-direction: column;
        align-items: center;
        /* Copies of the label spread down the rail; extras past the bottom
           are clipped rather than squeezed. */
        justify-content: space-around;
        overflow: hidden;
        border: 2px dashed var(--border);
        border-radius: var(--radius-lg);
        background: var(--bg-panel);
        color: var(--text-faint);
        text-align: center;
        /* The rail is a drop target, never a scroll surface. */
        touch-action: none;
        transition: border-color 0.12s, background 0.12s, color 0.12s;
    }
    /* vertical-rl with no rotation reads top-to-bottom — down the rail,
       the way you're about to drag. */
    .move-drop-rail .rail-label {
        writing-mode: vertical-rl;
        font-size: 0.8rem;
        font-weight: 600;
        letter-spacing: 0.04em;
        padding: 0.6rem 0;
        max-height: 100%;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
    .move-drop-rail.drop-target {
        border-color: var(--accent);
        border-style: solid;
        background: color-mix(in srgb, var(--accent) 14%, var(--bg-panel));
        color: var(--accent);
    }
    .move-drop-rail.rail-idle { opacity: 0.5; }
}

.move-pane { transition: border-color 0.12s, background 0.12s; }
.move-pane.drop-target {
    border-color: var(--accent);
    background: color-mix(in srgb, var(--accent) 8%, var(--bg-panel));
}

.move-list { list-style: none; padding: 0; margin: 0; }
.move-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.5rem;
    padding: 0.55rem 0.6rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    margin-bottom: 0.4rem;
    background: var(--bg);
    cursor: grab;
    user-select: none;
    /* Vertical swipe still scrolls the list; only a sideways drag is ours. */
    touch-action: pan-y;
}
.move-item:hover { border-color: var(--accent); }
.move-item.selected { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.move-item.dragging { opacity: 0.4; }
.move-item-name { font-weight: 600; }
.move-item-meta { color: var(--text-faint); font-family: Consolas, monospace; font-size: 0.85rem; }

.move-ghost {
    position: fixed;
    z-index: 1000;
    pointer-events: none;
    transform: translate(-50%, -50%);
    padding: 0.35rem 0.7rem;
    border-radius: var(--radius);
    background: var(--accent);
    color: #fff;
    font-size: 0.85rem;
    box-shadow: var(--shadow);
}

.move-note { padding: 0.3rem 0; border-bottom: 1px solid var(--border); }
.move-note.error { color: var(--danger); }

#qty-dialog {
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--bg-panel);
    color: var(--text);
    padding: 1.25rem;
    min-width: min(22rem, 90vw);
}
#qty-dialog::backdrop { background: rgba(0, 0, 0, 0.5); }
/* 16px is a hard floor, not a taste call: focusing an input smaller than
   this makes mobile browsers zoom the whole page in, and they don't zoom
   back out when the dialog closes — you're left pinching to find the
   destination again. */
#qty-dialog input { font-size: 16px; }

/* ─── Vendor CSV import ─────────────────────────────────────────────── */

.import-tally { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-bottom: 1rem; }
.badge-danger { background: rgba(229, 100, 107, 0.16); border-color: var(--danger); color: var(--danger); }
.was { color: var(--text-faint); text-decoration: line-through; }
.check-row { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.5rem; }

/* ─── Importer freshness ────────────────────────────────────────────── */

.sync-status {
    font-size: 0.875rem;
    color: var(--text-faint);
    margin-bottom: 1rem;
}
.sync-status.sync-stale {
    color: var(--warn);
    border: 1px solid var(--warn);
    border-radius: var(--radius);
    background: color-mix(in srgb, var(--warn) 10%, transparent);
    padding: 0.6rem 0.8rem;
}

/* ─── Building maintenance ──────────────────────────────────────────── */

/* A shared row for the get-forms that carry a search box and a couple of
   selects (supplies search, calendar filters). */
.filter-bar {
    display: flex;
    gap: 0.6rem;
    align-items: flex-end;
    flex-wrap: wrap;
    margin-bottom: 0.75rem;
}
.filter-bar label { display: flex; flex-direction: column; gap: 0.25rem; font-size: 0.8125rem; color: var(--text-muted); }
.filter-bar .checkbox-inline { flex-direction: row; align-items: center; gap: 0.4rem; }

/* Calendar beside its day list on a desktop; stacked on a phone, with the
   day list first — on a small screen "what do I do today" beats the grid. */
.cal-layout { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); gap: 1rem; align-items: start; }
@media (max-width: 900px) {
    .cal-layout { grid-template-columns: 1fr; }
    .cal-day-panel { order: -1; }
}

.cal-head { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.75rem; }
.cal-head h2 { margin: 0; flex: 1; font-size: 1.05rem; }

.cal-grid { width: 100%; border-collapse: collapse; table-layout: fixed; }
.cal-grid th {
    padding: 0.4rem 0;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--text-faint);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.cal-cell { border: 1px solid var(--border); padding: 0; height: 4.25rem; vertical-align: top; }
.cal-outside { background: var(--bg-sunken); }
.cal-outside .cal-date { color: var(--text-faint); }
.cal-today { border-color: var(--accent); }
.cal-selected { background: var(--accent-soft); }

.cal-day {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    height: 100%;
    padding: 0.35rem 0.4rem;
    color: inherit;
    text-decoration: none;
}
.cal-day:hover { background: var(--bg-hover); }
.cal-date { font-size: 0.8125rem; font-weight: 600; }
.cal-count {
    align-self: flex-start;
    padding: 0.05rem 0.4rem;
    border-radius: var(--radius-pill);
    background: var(--warn-soft);
    border: 1px solid rgba(224, 163, 58, 0.35);
    color: #f0cd8c;
    font-size: 0.6875rem;
    font-weight: 600;
}
.cal-count.cal-clear { background: var(--success-soft); border-color: rgba(63, 191, 135, 0.35); color: #8ce0b9; }
.cal-count.cal-overdue { background: var(--danger-soft); border-color: rgba(229, 100, 107, 0.35); color: #f2a3a7; }
.cal-legend { margin-top: 0.75rem; }

.task-day-list { list-style: none; margin: 0; padding: 0; }
.task-row {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    padding: 0.6rem 0;
    border-bottom: 1px solid var(--border);
}
.task-row:last-child { border-bottom: 0; }
.task-body { display: flex; flex-direction: column; gap: 0.15rem; flex: 1; min-width: 0; }
.task-title { font-weight: 500; }
.task-done .task-title { color: var(--text-muted); text-decoration: line-through; }
.task-notes { white-space: pre-line; }
.task-toggle-form { margin: 0; }

/* Big enough to hit with a thumb while holding a mop. */
.task-check {
    width: 1.9rem;
    height: 1.9rem;
    flex: none;
    padding: 0;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--success);
    font-size: 1rem;
    line-height: 1;
    cursor: pointer;
}
.task-check:hover { background: var(--bg-hover); }
.task-check[aria-pressed="true"] { background: var(--success-soft); border-color: rgba(63, 191, 135, 0.5); }
.task-check:disabled { opacity: 0.5; cursor: default; }

.row-retired td { opacity: 0.6; }

/* ─── Building floor plan ───────────────────────────────────────────── */

:root {
    --fp-room: #1b2230;
    --fp-open: #171d29;
    --fp-wet: #16262b;
    --fp-store: #21212e;
    --fp-service: #2a2028;
    --fp-entry: #1d2733;
    --fp-line: #46536b;
    --fp-fixture: #7f8da3;
}

.bp-layout { display: grid; grid-template-columns: minmax(0, 300px) minmax(0, 1fr); gap: 1rem; align-items: start; }
@media (max-width: 900px) {
    .bp-layout { grid-template-columns: 1fr; }
}
.bp-actions { display: flex; gap: 0.5rem; align-items: center; }

.bp-rail h2 { margin-top: 0; font-size: 1rem; }
.bp-source-list { list-style: none; margin: 0; padding: 0; max-height: 60vh; overflow-y: auto; }
.bp-source {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    padding: 0.55rem 0.6rem;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    margin-bottom: 0.4rem;
    background: var(--bg-raised);
    cursor: grab;
    /* Without this a drag scrolls the page on touch instead of dragging. */
    touch-action: none;
}
.bp-source:active { cursor: grabbing; }
.bp-source-name { font-weight: 500; }

/* The plan is wide by nature; let it scroll inside its panel rather than
   forcing the whole page sideways. */
.bp-stage-scroll { overflow-x: auto; }
.bp-stage { position: relative; min-width: 720px; }
.bp-image, .floorplan { display: block; width: 100%; height: auto; }

/* The plan carries no text of its own — room names come from the areas
   pinned onto it, so the drawing is walls and fixtures only. */
.fp-shell { fill: var(--bg-sunken); stroke: var(--fp-line); stroke-width: 3; }
.fp-entrance { stroke: var(--accent); stroke-width: 5; stroke-linecap: round; }
.room-box { stroke: var(--fp-line); stroke-width: 2; }
.fx { fill: none; stroke: var(--fp-fixture); stroke-width: 2; }
.fx-wall { stroke: var(--fp-line); stroke-width: 3; }

/* Markers sit on top of the plan, positioned in percentages. */
.bp-marker {
    position: absolute;
    transform: translate(-50%, -50%);
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.25rem 0.55rem;
    border: 1px solid var(--accent);
    border-radius: var(--radius-pill);
    background: var(--bg-panel);
    color: var(--text);
    font-size: 0.75rem;
    font-weight: 500;
    cursor: pointer;
    touch-action: none;
    white-space: nowrap;
}
.bp-marker-over { background: var(--accent); border-color: var(--accent); color: var(--accent-text); }
.bp-fixture { border-color: var(--success); }
/* A fixture with no container can't take stock — say so visually. */
.bp-fixture-plain { border-style: dashed; border-color: var(--border-strong); color: var(--text-muted); }
.bp-editing .bp-marker { cursor: grab; box-shadow: 0 0 0 3px var(--accent-soft); }

.bp-edit-bar {
    padding: 0.75rem;
    margin-bottom: 0.75rem;
    border: 1px dashed var(--border-strong);
    border-radius: var(--radius);
    background: var(--bg-sunken);
}
.bp-palette-group { margin-bottom: 0.6rem; }
.bp-palette { display: flex; flex-wrap: wrap; gap: 0.4rem; list-style: none; margin: 0.35rem 0 0; padding: 0; }
.bp-palette-item {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.3rem 0.6rem;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-pill);
    background: var(--bg-raised);
    font-size: 0.75rem;
    cursor: grab;
    touch-action: none;
}
.bp-palette-item:hover { border-color: var(--accent); }

/* Fixture glyphs: drawn with borders and radii, so there's no icon font or
   sprite to vendor (project rule: no front-end dependencies). */
.bp-icon { width: 0.8rem; height: 0.8rem; flex: none; border: 2px solid currentColor; }
.bp-icon-room { border-radius: 2px; border-style: solid; }
.bp-icon-garbage { border-radius: 0 0 4px 4px; border-top-width: 4px; }
.bp-icon-recycling { border-radius: 0 0 4px 4px; border-top-width: 4px; border-style: dashed; }
.bp-icon-paper_towel, .bp-icon-toilet_paper { border-radius: 50%; border-width: 3px; }
.bp-icon-soap, .bp-icon-sanitizer { border-radius: 3px 3px 6px 6px; }
.bp-icon-mop_station { border-radius: 0; border-left-width: 5px; }
.bp-icon-supply_cabinet { border-radius: 1px; border-right-width: 5px; }
.bp-icon-vending { border-radius: 2px; border-bottom-width: 5px; }
.bp-icon-first_aid { border-radius: 2px; border-color: var(--success); }
.bp-icon-extinguisher { border-radius: 3px; border-color: var(--danger); }
.bp-icon-other { border-radius: 50%; border-style: dotted; }

.bp-ghost {
    position: fixed;
    z-index: 1000;
    transform: translate(-50%, -150%);
    padding: 0.3rem 0.6rem;
    border-radius: var(--radius-pill);
    background: var(--accent);
    color: var(--accent-text);
    font-size: 0.75rem;
    font-weight: 600;
    pointer-events: none;
    box-shadow: var(--shadow-lg);
}
body.bp-dragging { user-select: none; }
.bp-status-error { color: var(--danger); }

#bp-qty-dialog {
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-lg);
    background: var(--bg-panel);
    color: var(--text);
    padding: 1.25rem;
    min-width: min(20rem, 90vw);
}
#bp-qty-dialog::backdrop { background: rgba(0, 0, 0, 0.5); }
/* 16px floor: anything smaller makes mobile browsers zoom on focus. */
#bp-qty-dialog input { font-size: 16px; width: 100%; }
#bp-qty-dialog menu { display: flex; gap: 0.5rem; justify-content: flex-end; padding: 0; margin: 0.75rem 0 0; }

/* ─── Job load-outs / prep ──────────────────────────────────────────── */

/* A pick-list line the technician is short on, and the "N short" tag — the
   one thing a manager scans a prep sheet for. */
.data-table tr.row-short > td { background: var(--danger-soft); }
.text-short { color: var(--danger); }
/* An inactive load-out in the list — present but dimmed. */
tr.row-muted > td { color: var(--text-faint); }

/* Job lifecycle badge (dashboard queue, job list, job detail): Open →
   Dispatched → Completed, with the archived states muted/red. */
.job-status {
    display: inline-flex;
    align-items: center;
    padding: 0.1rem 0.5rem;
    border-radius: var(--radius-pill);
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    border: 1px solid transparent;
    white-space: nowrap;
}
.job-status-open { background: var(--accent-soft); border-color: rgba(77, 124, 254, 0.35); color: #a8c1ff; }
.job-status-dispatched { background: var(--warn-soft); border-color: rgba(224, 163, 58, 0.35); color: #f0c579; }
.job-status-completed { background: var(--success-soft); border-color: rgba(63, 191, 135, 0.35); color: #8ce0b9; }
.job-status-invoiced,
.job-status-closed { background: var(--bg-raised); border-color: var(--border-strong); color: var(--text-faint); }
.job-status-canceled { background: var(--danger-soft); border-color: rgba(229, 100, 107, 0.35); color: #f2a3a7; }

/* List pager (catalogue / units) — count on the left, prev/next on the right. */
.pagination {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-top: 1rem;
    padding-top: 0.85rem;
    border-top: 1px solid var(--border);
}
.pagination-links { display: flex; gap: 0.5rem; }

/* Live suggestions dropdown under a search field (Receiving lookup). */
.search-bar { position: relative; }
.autocomplete {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    z-index: 30;
    margin: 0;
    padding: 0.25rem;
    list-style: none;
    background: var(--bg-raised);
    border: 1px solid var(--border-strong);
    border-radius: 8px;
    box-shadow: 0 10px 28px rgba(0, 0, 0, 0.32);
    max-height: 340px;
    overflow-y: auto;
}
.autocomplete li {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    padding: 0.5rem 0.6rem;
    border-radius: 6px;
    cursor: pointer;
}
.autocomplete li:hover,
.autocomplete li.is-active { background: var(--bg-hover); }

/* Action callout — a highlighted strip with one primary action (print label). */
.callout {
    background: var(--accent-soft);
    border: 1px solid var(--accent);
    border-radius: 8px;
    padding: 0.75rem 1rem;
    margin: 0 0 1.1rem;
}
.callout-action {
    display: flex;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
}
.callout-action > div:first-child { margin-right: auto; }

/* ─── Parts usage suggestions ───────────────────────────────────────── */

/* A Service Fusion note can be a single 1,500-character line. Left to size
   itself the evidence cell shoved the source picker and Confirm button off
   the panel, so it is capped and ellipsised — the full note is one click
   away in the modal. */
.suggestions-table { table-layout: fixed; }
.suggestions-table .suggestion-evidence { max-width: 20rem; }
.suggestions-table .suggestion-evidence .btn-link {
    display: block;
    width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    text-align: left;
}
/* Confirm and Dismiss stay side by side rather than wrapping under the row. */
.suggestions-table .suggestion-actions { white-space: nowrap; }
.suggestions-table select { max-width: 100%; }
.suggestions-table td { vertical-align: top; word-break: break-word; }

/* ─── Duplicate part review ─────────────────────────────────────────── */

/* Two candidate rows stacked as radio choices — picking one IS the decision,
   so the whole row is the click target rather than just the dot. */
.dup-choice {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    padding: 0.45rem 0.6rem;
    border: 1px solid var(--border);
    border-radius: 6px;
    cursor: pointer;
}
.dup-choice + .dup-choice { margin-top: 0.4rem; }
.dup-choice:hover { background: var(--bg-hover); }
.dup-choice > span { display: flex; flex-direction: column; gap: 0.1rem; }
.dup-choice strong { font-variant-numeric: tabular-nums; }
.duplicates-table .duplicate-actions { white-space: nowrap; vertical-align: top; }
.duplicates-table td { vertical-align: top; }

/* The "merged into / retired" line on a superseded part's detail page. */
.callout-inline {
    margin: 0.5rem 0 0;
    padding: 0.5rem 0.75rem;
    border-left: 3px solid var(--danger);
    background: var(--danger-soft);
    font-size: 0.875rem;
}
