/* =====================================================================
   Shared UI components — Roach / Mertson Family Tree
   ===================================================================== */

/* ── Buttons ─────────────────────────────────────────────────────────── */
.btn {
    display:         inline-flex;
    align-items:     center;
    gap:             var(--space-2);
    padding:         var(--space-2) var(--space-4);
    border:          2px solid transparent;
    border-radius:   var(--radius-md);
    font-size:       var(--font-size-sm);
    font-weight:     600;
    line-height:     1.4;
    white-space:     nowrap;
    cursor:          pointer;
    transition:      background var(--transition-fast),
                     color var(--transition-fast),
                     border-color var(--transition-fast),
                     box-shadow var(--transition-fast);
    user-select:     none;
}
.btn:disabled { opacity: .5; pointer-events: none; }

.btn-primary {
    background: var(--color-primary);
    color:      var(--color-text-inverse);
    border-color: var(--color-primary);
}
.btn-primary:hover { background: var(--color-primary-hover); border-color: var(--color-primary-hover); }

.btn-accent {
    background: var(--color-accent);
    color:      var(--color-text-inverse);
    border-color: var(--color-accent);
}
.btn-accent:hover { background: var(--color-accent-hover); border-color: var(--color-accent-hover); }

.btn-outline {
    background:   transparent;
    color:        var(--color-primary);
    border-color: var(--color-primary);
}
.btn-outline:hover { background: var(--color-primary); color: var(--color-text-inverse); }

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

.btn-danger {
    background:   var(--color-danger);
    color:        #fff;
    border-color: var(--color-danger);
}
.btn-danger:hover { background: #a01020; }

.btn-sm { padding: var(--space-1) var(--space-3); font-size: var(--font-size-xs); }
.btn-lg { padding: var(--space-3) var(--space-6); font-size: var(--font-size-md); }
.btn-icon { padding: var(--space-2); }

/* ── Badges ─────────────────────────────────────────────────────────── */
.badge {
    display:       inline-flex;
    align-items:   center;
    gap:           var(--space-1);
    padding:       2px var(--space-2);
    border-radius: var(--radius-pill);
    font-size:     var(--font-size-xs);
    font-weight:   600;
    line-height:   1.5;
    white-space:   nowrap;
}
.badge-primary  { background: var(--color-primary-light); color: #fff; }
.badge-accent   { background: var(--color-accent);        color: #fff; }
.badge-success  { background: var(--color-success-bg);    color: var(--color-success);  border: 1px solid var(--color-success-border); }
.badge-warning  { background: var(--color-warning-bg);    color: var(--color-warning);  border: 1px solid var(--color-warning-border); }
.badge-danger   { background: var(--color-danger-bg);     color: var(--color-danger);   border: 1px solid var(--color-danger-border); }
.badge-info     { background: var(--color-info-bg);       color: var(--color-info);     border: 1px solid var(--color-info-border); }
.badge-muted    { background: var(--color-bg-subtle);     color: var(--color-text-muted); }

/* ── Cards ───────────────────────────────────────────────────────────── */
.card {
    background:    var(--color-bg-surface);
    border:        1px solid var(--color-border-subtle);
    border-radius: var(--radius-lg);
    box-shadow:    var(--shadow-sm);
}
.card-body   { padding: var(--space-6); }
.card-header {
    padding:       var(--space-4) var(--space-6);
    border-bottom: 1px solid var(--color-border-subtle);
    font-weight:   700;
    font-size:     var(--font-size-lg);
}
.card-footer {
    padding:       var(--space-4) var(--space-6);
    border-top:    1px solid var(--color-border-subtle);
    background:    var(--color-bg-subtle);
    border-radius: 0 0 var(--radius-lg) var(--radius-lg);
}

/* ── Stat cards (dashboard) ─────────────────────────────────────────── */
.stat-card {
    background:    var(--color-bg-surface);
    border:        1px solid var(--color-border-subtle);
    border-radius: var(--radius-lg);
    padding:       var(--space-5) var(--space-6);
    box-shadow:    var(--shadow-sm);
    display:       flex;
    align-items:   center;
    gap:           var(--space-4);
    transition:    box-shadow var(--transition-base);
}
.stat-card:hover { box-shadow: var(--shadow-md); }
/* A grid item won't shrink below its content's min-width by default, which lets a long
   unwrappable value push the card past its track. */
.stat-card { min-width: 0; }

.stat-card__icon {
    width:          48px;
    height:         48px;
    border-radius:  var(--radius-md);
    display:        flex;
    align-items:    center;
    justify-content:center;
    font-size:      22px;
    flex-shrink:    0;
}
.stat-card__icon--primary { background: rgba(30,58,82,.12); color: var(--color-primary); }
.stat-card__icon--accent  { background: rgba(224,112,16,.12); color: var(--color-accent); }
.stat-card__icon--success { background: var(--color-success-bg); color: var(--color-success); }
.stat-card__icon--warning { background: var(--color-warning-bg); color: var(--color-warning); }
.stat-card__icon--danger  { background: var(--color-danger-bg);  color: var(--color-danger); }

/* The text column must be allowed to shrink. A flex child defaults to min-width:auto, so a long
   value (an 8-figure inventory total) refuses to narrow and simply runs out past the card edge. */
.stat-card > div { min-width: 0; }

.stat-card__value {
    font-size:   var(--font-size-2xl);
    font-weight: 800;
    line-height: 1;
    color:       var(--color-text);
}
/* Money can be an order of magnitude longer than a count — "$12,345,678" vs "43". Give it its own
   size and keep the digits on one line; a wrapped or clipped dollar figure is worse than a smaller
   one. Cents are dropped at this scale (see formatMoneyWhole) — the title carries the exact value. */
.stat-card__value--money {
    font-size:            var(--font-size-xl);
    white-space:          nowrap;
    font-variant-numeric: tabular-nums;
    letter-spacing:       -.01em;
}
.stat-card__label {
    font-size: var(--font-size-sm);
    color:     var(--color-text-muted);
    margin-top: var(--space-1);
}
.stat-card__note {
    font-size:  var(--font-size-xs);
    color:      var(--color-warning);
    margin-top: 2px;
}

/* ── Toast notifications ─────────────────────────────────────────────── */
#toast-container {
    position:   fixed;
    bottom:     calc(var(--bottom-nav-h) + var(--space-4));
    right:      var(--space-4);
    z-index:    var(--z-toast);
    display:    flex;
    flex-direction: column;
    gap:        var(--space-2);
    pointer-events: none;
}
@media (min-width: 769px) {
    #toast-container { bottom: var(--space-4); }
}

.toast {
    display:       flex;
    align-items:   flex-start;
    gap:           var(--space-3);
    padding:       var(--space-3) var(--space-4);
    border-radius: var(--radius-md);
    background:    var(--color-text);
    color:         var(--color-text-inverse);
    box-shadow:    var(--shadow-lg);
    font-size:     var(--font-size-sm);
    font-weight:   500;
    max-width:     340px;
    pointer-events: auto;
    animation:     slideInToast .22s ease both;
}
@keyframes slideInToast {
    from { opacity: 0; transform: translateX(20px); }
    to   { opacity: 1; transform: translateX(0); }
}
.toast--success { background: var(--color-success); }
.toast--warning { background: var(--color-warning); }
.toast--error   { background: var(--color-danger); }
.toast--info    { background: var(--color-info); }

/* ── Confirm dialog ─────────────────────────────────────────────────── */
.confirm-overlay {
    position:  fixed; inset: 0;
    background: rgba(0,0,0,.5);
    display:   flex; align-items: center; justify-content: center;
    z-index:   var(--z-modal);
    padding:   var(--space-4);
}
/* A dialog with another dialog ON TOP of it.  (sweep item E34)
   "Add a location" opens the picker; "＋ New Location" inside it opens a second dialog, and the
   first stayed fully lit behind — its picker list still reading as live when it no longer was.
   The layer beneath is dimmed and pushed back so only one dialog ever looks operable; `inert` (set
   in App._pushOverlay) is what actually takes it out of reach of the mouse, the keyboard and the
   accessibility tree, so this rule is purely the part you can see. */
.confirm-overlay.is-under {
    background: rgba(0,0,0,.2);      /* the layer above supplies the rest of the darkening */
}
.confirm-overlay.is-under .confirm-dialog {
    opacity:    .45;
    filter:     saturate(.6);
    transform:  scale(.97);
    transition: opacity .15s ease, transform .15s ease;
}
.confirm-dialog {
    background:    var(--color-bg-surface);
    border-radius: var(--radius-xl);
    padding:       var(--space-8);
    max-width:     400px; width: 100%;
    box-shadow:    var(--shadow-xl);
}
.confirm-dialog h3 { font-size: var(--font-size-lg); margin-bottom: var(--space-3); }
.confirm-dialog p  { color: var(--color-text-secondary); margin-bottom: var(--space-6); }
.confirm-actions   { display: flex; gap: var(--space-3); justify-content: flex-end; }

/* ── Loading overlay ─────────────────────────────────────────────────── */
#loading-overlay {
    position:       fixed; inset: 0;
    background:     var(--color-bg-surface);
    display:        flex; align-items: center; justify-content: center;
    z-index:        var(--z-overlay);
    backdrop-filter:blur(2px);
}
#loading-overlay.hidden { display: none; }

/* ── Empty state ─────────────────────────────────────────────────────── */
.empty-state {
    text-align: center;
    padding:    var(--space-12) var(--space-6);
    color:      var(--color-text-muted);
}
.empty-state__icon  { font-size: 48px; margin-bottom: var(--space-4); }
.empty-state__title { font-size: var(--font-size-lg); font-weight: 600; color: var(--color-text-secondary); margin-bottom: var(--space-2); }

/* ── Inventory stock badges ─────────────────────────────────────────── */
.stock-badge { font-size: var(--font-size-xs); font-weight: 700; padding: 2px 8px; border-radius: var(--radius-pill); }
.stock-badge--ok       { background: var(--color-in-stock-bg);    color: var(--color-in-stock); }
.stock-badge--low      { background: var(--color-low-stock-bg);   color: var(--color-low-stock); }
.stock-badge--out      { background: var(--color-out-of-stock-bg); color: var(--color-out-of-stock); }

/* ── Role badge ─────────────────────────────────────────────────────── */
.role-badge            { font-size: 11px; font-weight: 700; padding: 2px 8px; border-radius: var(--radius-pill); text-transform: uppercase; letter-spacing: .04em; }
.role-badge--admin     { background: #2d1080; color: #fff; }
.role-badge--manager   { background: var(--color-primary); color: #fff; }
.role-badge--user      { background: var(--color-bg-subtle); color: var(--color-text-secondary); }
.role-badge--readonly  { background: var(--color-bg-muted); color: var(--color-text-muted); }

/* ── Refresh Modal (brand logo click) ──────────────────────────────── */
.refresh-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.55);
    z-index: 3000;
    display: flex;
    align-items: center;
    justify-content: center;
}
.refresh-modal {
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border);
    border-radius: 14px;
    padding: 32px 28px 24px;
    width: 300px;
    text-align: center;
    box-shadow: 0 12px 40px rgba(0,0,0,0.45);
}
.refresh-modal-icon    { font-size: 44px; margin-bottom: 12px; }
.refresh-modal-title   { font-size: 1.1rem; font-weight: 700; color: var(--color-text-secondary); margin-bottom: 6px; }
.refresh-modal-desc    { font-size: .825rem; color: var(--color-text-muted); margin-bottom: 22px; line-height: 1.5; }
.refresh-modal-offline { padding: 10px 14px; border-radius: 8px; background: var(--color-bg-subtle); color: var(--color-text-muted); font-size: .8rem; margin-bottom: 14px; }
.refresh-modal .btn-refresh-now {
    display: block; width: 100%;
    padding: 13px; border-radius: 8px; border: none;
    background: var(--color-accent); color: #fff;
    font-size: .95rem; font-weight: 600; cursor: pointer;
    margin-bottom: 10px;
}
.refresh-modal .btn-refresh-now:hover { opacity: .9; }
.refresh-modal .btn-refresh-cancel {
    display: block; width: 100%;
    padding: 11px; border-radius: 8px; border: none;
    background: var(--color-bg-subtle); color: var(--color-text-muted);
    font-size: .9rem; cursor: pointer;
}
.refresh-modal .btn-refresh-cancel:hover { color: var(--color-text-secondary); }

/* ── Camera Scanner ──────────────────────────────────────────────────── */
/* ── The scanner panel follows the THEME, like everything else ──────────────
   John, 2026-08-06: *"why does scan screen not follow the lightmode/dark mode like all other
   screens? its always dark"* — and he was right that it was the only thing in the app that didn't.
   This block was written as a camera viewfinder, where a black chrome around the video is the right
   call, and it hardcoded `#111` with `#fff` text and a stack of `rgba(255,255,255,…)`. But the panel
   long ago stopped being just a viewfinder: it carries a Take Photo button, a manual entry field, a
   Submit and a live result list. That is a FORM, and a form has no business ignoring the theme.
   Everything here now reads from the variables, so light follows the OS exactly like every other
   surface. **The one thing deliberately left black is the video area itself** (`#tt-scanner-reader`)
   — that is the camera feed, and black is correct behind it in either theme. */
.scanner-overlay {
    position:   fixed;
    inset:      0;
    /* Matches the app's own modal scrim (app.html `.modal-overlay.open`) instead of a near-opaque
       black that only made sense when the panel behind it was a viewfinder. */
    background: rgba(0,0,0,.5);
    display:    flex;
    align-items: center;
    justify-content: center;
    z-index:    1200;
    padding:    var(--space-4);
    opacity:    0;
    transition: opacity .2s ease;
    pointer-events: none;
}
.scanner-overlay.open {
    opacity:        1;
    pointer-events: all;
}

.scanner-modal {
    background:    var(--color-bg-surface);
    color:         var(--color-text);
    border:        1px solid var(--color-border);
    border-radius: var(--radius-xl);
    width:         100%;
    max-width:     440px;
    max-height:    92vh;
    max-height:    92dvh;           /* never taller than the screen — dvh, or iOS puts the
                                       scanner's controls under the browser chrome */
    display:       flex;
    flex-direction: column;
    overflow:      hidden;
    box-shadow:    0 24px 64px rgba(0,0,0,.7);
}

.scanner-modal__header {
    display:         flex;
    align-items:     center;
    justify-content: space-between;
    padding:         var(--space-4) var(--space-5);
    border-bottom:   1px solid var(--color-border-subtle);
    flex-shrink:     0;             /* header (with ✕) always visible */
}
.scanner-modal__title {
    color:       var(--color-text);
    font-weight: 600;
    font-size:   var(--font-size-sm);
}
.scanner-modal__close {
    background: none;
    border:     none;
    cursor:     pointer;
    color:      var(--color-text-muted);
    font-size:  1.2rem;
    line-height: 1;
    padding:    var(--space-1) var(--space-2);
    border-radius: var(--radius-sm);
    transition: color .15s;
}
.scanner-modal__close:hover { color: var(--color-text); }

.scanner-modal__body {
    padding:    var(--space-4);
    flex:       1 1 auto;
    min-height: 0;
    overflow-y: auto;   /* video can scroll; header + footer stay pinned */
}

/* Container Quagga2 / html5-qrcode renders into.
   position:relative is critical — Quagga2 injects position:absolute canvas
   elements; without this they escape the container and blank the screen. */
#tt-scanner-reader {
    width:         100%;
    min-height:    220px;
    border-radius: var(--radius-lg);
    overflow:      hidden;
    /* Deliberately black in BOTH themes — this is the camera feed itself, not chrome. */
    background:    #000;
    position:      relative;
}
#tt-scanner-reader video {
    width:      100% !important;
    max-height: 55vh;
    display:    block;
    object-fit: cover;
}
/* Keep Quagga2's overlay canvas inside the reader box */
#tt-scanner-reader canvas {
    position:   absolute !important;
    top:        0 !important;
    left:       0 !important;
    max-width:  100% !important;
    max-height: 55vh !important;
}

.scanner-hint {
    color:      var(--color-text-muted);
    text-align: center;
    font-size:  var(--font-size-xs);
    margin-top: var(--space-3);
}
.scanner-error {
    color:       var(--color-danger);
    text-align:  center;
    font-size:   var(--font-size-sm);
    margin-top:  var(--space-3);
    white-space: pre-wrap;
    line-height: 1.5;
}

.scanner-modal__footer {
    padding:         var(--space-3) var(--space-5) var(--space-5);
    display:         flex;
    justify-content: center;
    flex-shrink:     0;   /* Cancel button always reachable */
}
.scanner-cancel-btn {
    color:        var(--color-text-secondary) !important;
    border-color: var(--color-border) !important;
    font-size:    var(--font-size-sm);
}
.scanner-cancel-btn:hover {
    color:        var(--color-text) !important;
    border-color: var(--color-text-muted) !important;
}

/* "Starting camera…" status line above the video */
.scanner-status {
    color:       var(--color-text-muted);
    font-size:   var(--font-size-xs);
    text-align:  center;
    padding:     var(--space-2) 0 var(--space-3);
    font-style:  italic;
}

/* "or enter manually" divider */
.scanner-divider {
    display:         flex;
    align-items:     center;
    gap:             var(--space-3);
    padding:         var(--space-2) var(--space-5);
    color:           var(--color-text-muted);
    font-size:       var(--font-size-xs);
    text-transform:  uppercase;
    letter-spacing:  .06em;
}
.scanner-divider::before,
.scanner-divider::after {
    content:    '';
    flex:       1;
    height:     1px;
    background: var(--color-border-subtle);
}

/* Manual entry row */
.scanner-manual {
    display:    flex;
    gap:        var(--space-2);
    padding:    0 var(--space-4) var(--space-3);
}
.scanner-manual-input {
    flex:            1;
    background:      var(--color-bg-subtle) !important;
    border-color:    var(--color-border)    !important;
    color:           var(--color-text)      !important;
    font-family:     monospace;
    font-size:       var(--font-size-sm);
    text-transform:  uppercase;
    letter-spacing:  .04em;
}
/* The input uppercases + letter-spaces what you TYPE (part numbers read better that way),
   but applying that to the placeholder made the hint too wide and it got clipped. Keep the
   placeholder in normal case/spacing so the whole hint fits. */
.scanner-manual-input::placeholder {
    color:          var(--color-text-muted) !important;
    text-transform: none;
    letter-spacing: normal;
    font-family:    var(--font-family-base, system-ui, sans-serif);
}
.scanner-manual-input:focus {
    border-color: var(--color-accent) !important;
    outline:      none;
    box-shadow:   0 0 0 2px rgba(224,112,16,.35);
}

/* Live part matches under the manual/handheld box — same type-to-search behaviour as the
   pickers elsewhere. A handheld still just types the code + Enter and never sees this. */
.scanner-manual-results {
    margin:        0 var(--space-4) var(--space-3);
    max-height:    190px;
    overflow-y:    auto;
    border-radius: var(--radius-md, 8px);
}
.scanner-manual-results:empty { display: none; }
.scanner-manual-results:not(:empty) {
    border:     1px solid var(--color-border-subtle);
    background: var(--color-bg-subtle);
}
.scanner-manual-result {
    display:       block;
    width:         100%;
    text-align:    left;
    padding:       var(--space-2) var(--space-3);
    background:    none;
    border:        0;
    border-bottom: 1px solid var(--color-border-subtle);
    color:         var(--color-text);
    cursor:        pointer;
    font-size:     var(--font-size-sm);
}
.scanner-manual-result:last-child { border-bottom: 0; }
.scanner-manual-result:hover,
.scanner-manual-result:focus-visible { background: var(--color-bg-muted); outline: none; }
.scanner-manual-result .pn   { font-family: monospace; font-weight: 600; }
.scanner-manual-result .meta { display: block; color: var(--color-text-muted); font-size: var(--font-size-xs); margin-top: 2px; }

/* ── Photo-capture (primary scan method) ─────────────────────────────── */
.scanner-photo-cta {
    padding:    var(--space-2) 0 var(--space-1);
    text-align: center;
}
.scanner-photo-btn {
    width:         100%;
    padding:       var(--space-4);
    border:        none;
    border-radius: var(--radius-lg);
    background:    var(--color-accent);
    color:         #fff;
    font-size:     var(--font-size-md);
    font-weight:   700;
    cursor:        pointer;
    transition:    filter .15s;
}
.scanner-photo-btn:hover   { filter: brightness(1.08); }
.scanner-photo-btn:active  { filter: brightness(.95); }
.scanner-photo-help {
    color:      var(--color-text-muted);
    font-size:  var(--font-size-xs);
    margin-top: var(--space-2);
    line-height: 1.5;
}
.scanner-preview {
    width:         100%;
    max-height:    40vh;
    object-fit:    contain;
    border-radius: var(--radius-lg);
    margin-top:    var(--space-3);
    background:    #000;
}

/* Defined scan window overlay for live mode.
   Stays white-on-dark in BOTH themes on purpose — it is drawn ON TOP of the camera picture, not on
   the panel, so it has to read against whatever the lens is looking at, not against the surface. */
.scanner-window {
    position:       absolute;
    top:            42%;   /* thin slot — only ONE stacked barcode fits (must match _coverCropRect) */
    bottom:         42%;
    left:           8%;
    right:          8%;
    border:         2px solid rgba(255,255,255,.35);
    border-radius:  var(--radius-md);
    box-shadow:     0 0 0 100vmax rgba(0,0,0,.35);
    pointer-events: none;
    z-index:        2;
}
.scanner-window__corner {
    position: absolute;
    width:    22px;
    height:   22px;
    border:   3px solid var(--color-accent);
}
.scanner-window__corner.tl { top: -2px; left: -2px;  border-right: none;  border-bottom: none; border-radius: var(--radius-md) 0 0 0; }
.scanner-window__corner.tr { top: -2px; right: -2px; border-left: none;   border-bottom: none; border-radius: 0 var(--radius-md) 0 0; }
.scanner-window__corner.bl { bottom: -2px; left: -2px;  border-right: none; border-top: none;  border-radius: 0 0 0 var(--radius-md); }
.scanner-window__corner.br { bottom: -2px; right: -2px; border-left: none;  border-top: none;  border-radius: 0 0 var(--radius-md) 0; }

/* "Use live scanner instead" link */
.scanner-live-toggle {
    display:        block;
    margin:         var(--space-3) auto 0;
    background:     none;
    border:         none;
    color:          var(--color-text-secondary);
    font-size:      var(--font-size-xs);
    text-decoration:underline;
    cursor:         pointer;
    padding:        var(--space-2);
}
.scanner-live-toggle:hover { color: var(--color-text); }

/* Multi-barcode picker — choose which decoded code to use */
.scanner-picker { padding: var(--space-2) 0; }
.scanner-picker__title {
    color:        var(--color-text-secondary);
    font-size:    var(--font-size-sm);
    text-align:   center;
    margin-bottom: var(--space-3);
}
.scanner-picker__btn {
    display:        flex;
    flex-direction: column;
    gap:            2px;
    width:          100%;
    text-align:     left;
    padding:        var(--space-3) var(--space-4);
    margin-bottom:  var(--space-2);
    background:     var(--color-bg-subtle);
    border:         1px solid var(--color-border);
    border-radius:  var(--radius-md);
    cursor:         pointer;
    color:          var(--color-text);
}
.scanner-picker__btn:hover {
    border-color: var(--color-accent);
    background:   rgba(224,112,16,.15);
}
.scanner-picker__type {
    font-size:      var(--font-size-xs);
    color:          rgba(255,255,255,.5);
    text-transform: uppercase;
    letter-spacing: .04em;
}
.scanner-picker__val {
    font-family:    monospace;
    font-size:      var(--font-size-md);
    letter-spacing: .03em;
    word-break:     break-all;
}

/* ── Scan workflow (Add / Use) ───────────────────────────────────────── */
.scan-home { max-width: 560px; }
.scan-mode-grid {
    display:               grid;
    grid-template-columns: 1fr 1fr;
    gap:                   var(--space-4);
    margin-bottom:         var(--space-5);
}
.scan-mode-btn {
    display:        flex;
    flex-direction: column;
    align-items:    center;
    gap:            4px;
    padding:        var(--space-6) var(--space-4);
    border:         2px solid var(--color-border);
    border-radius:  var(--radius-lg);
    background:     var(--color-bg-surface);
    /* A <button> does NOT inherit `color` — it defaults to the UA's `buttontext`. The card set a
       background but never a colour, so in light mode the bold "Use Stock" / "Transfer" labels came
       out near-white on white and simply WERE NOT THERE, while the sub-line survived because it
       sets its own var. Found by rendering the light palette during the scanner theme fix. */
    color:          var(--color-text);
    cursor:         pointer;
    transition:     transform .12s, border-color .12s, background .12s;
}
.scan-mode-btn:active { transform: scale(.97); }
.scan-mode-btn__icon  { font-size: 2rem; line-height: 1; }
.scan-mode-btn__label { font-size: var(--font-size-md); font-weight: 800; }
.scan-mode-btn__sub   { font-size: var(--font-size-xs); color: var(--color-text-muted); }
.scan-mode-btn--add:hover { border-color: var(--color-success); background: rgba(34,160,80,.06); }
.scan-mode-btn--use:hover { border-color: var(--color-accent);  background: rgba(224,112,16,.06); }
/* Transfer now sits in the grid beside Use — same tile shape/size (base .scan-mode-btn). */
.scan-mode-btn--xfer:hover { border-color: var(--color-primary); background: var(--color-bg-subtle); }

.scan-options {
    display:        flex;
    flex-direction: column;
    gap:            var(--space-4);
    padding:        var(--space-4);
    border:         1px solid var(--color-border-subtle);
    border-radius:  var(--radius-lg);
    background:     var(--color-bg-subtle);
    margin-bottom:  var(--space-5);
}
.scan-toggle { display: flex; align-items: center; gap: var(--space-2); font-size: var(--font-size-sm); cursor: pointer; }
.scan-loc .form-label { display: block; margin-bottom: var(--space-1); }

.scan-tally {
    border:        1px solid var(--color-border-subtle);
    border-radius: var(--radius-lg);
    overflow:      hidden;
}
.scan-tally__head {
    padding:        var(--space-2) var(--space-4);
    background:     var(--color-bg-subtle);
    font-size:      var(--font-size-xs);
    text-transform: uppercase;
    letter-spacing: .05em;
    color:          var(--color-text-secondary);
    font-weight:    700;
}
.scan-tally__row {
    display:         flex;
    justify-content: space-between;
    align-items:     center;
    padding:         var(--space-2) var(--space-4);
    border-top:      1px solid var(--color-border-subtle);
}
.scan-tally__pn  { font-family: monospace; font-size: var(--font-size-sm); }
.scan-tally__qty { font-weight: 800; }
.scan-tally__qty.is-add { color: var(--color-success); }
.scan-tally__qty.is-use { color: var(--color-accent); }

/* Confirm / not-found cards (reuse .modal-overlay) */
.scan-confirm__head {
    padding:       var(--space-4) var(--space-5);
    font-weight:   800;
    font-size:     var(--font-size-md);
    border-bottom: 1px solid var(--color-border-subtle);
}
.scan-confirm__head.is-add { color: var(--color-success); }
.scan-confirm__head.is-use { color: var(--color-accent); }
.scan-confirm__body   { padding: var(--space-5); }
.scan-confirm__pn     { font-size: var(--font-size-lg); font-weight: 800; }
.scan-confirm__desc   { color: var(--color-text-secondary); font-size: var(--font-size-sm); margin: var(--space-1) 0 var(--space-2); }
.scan-confirm__desc code { background: var(--color-bg-subtle); padding: 1px 5px; border-radius: 4px; font-size: .85em; }
.scan-confirm__meta   { color: var(--color-text-muted); font-size: var(--font-size-sm); }
.scan-confirm__actions {
    display:         flex;
    gap:             var(--space-3);
    justify-content: flex-end;
    padding:         var(--space-4) var(--space-5);
    border-top:      1px solid var(--color-border-subtle);
}

.scan-stepper {
    display:         flex;
    align-items:     center;
    justify-content: center;
    gap:             var(--space-3);
    margin-top:      var(--space-4);
}
.scan-stepper__btn {
    width:         48px;
    height:        48px;
    border:        1px solid var(--color-border);
    border-radius: var(--radius-md);
    background:    var(--color-bg-surface);
    color:         var(--color-text);
    font-size:     1.5rem;
    cursor:        pointer;
}
.scan-stepper__btn:active { background: var(--color-bg-subtle); }
.scan-stepper__val {
    width:        80px;
    height:       48px;
    text-align:   center;
    font-size:    var(--font-size-lg);
    font-weight:  800;
    border:       1px solid var(--color-border);
    border-radius:var(--radius-md);
    background:   var(--color-bg-surface);
    color:        var(--color-text);
}
.scan-choices { display: flex; flex-direction: column; gap: var(--space-2); margin-top: var(--space-3); }
.scan-choice  { justify-content: flex-start; }

/* Placement picker (which location to add to / use from) */
.scan-places { display: flex; flex-direction: column; gap: var(--space-2); }
.scan-place {
    display:         flex;
    align-items:     center;
    justify-content: space-between;
    gap:             var(--space-3);
    width:           100%;
    padding:         var(--space-3) var(--space-4);
    border:          1px solid var(--color-border);
    border-radius:   var(--radius-md);
    background:      var(--color-bg-surface);
    color:           var(--color-text);   /* buttons don't inherit colour — see .scan-mode-btn */
    cursor:          pointer;
    font-size:       var(--font-size-sm);
    text-align:      left;
}
.scan-place:hover  { border-color: var(--color-primary); background: var(--color-bg-subtle); }
.scan-place strong { font-size: var(--font-size-md); }
.scan-place--new   { justify-content: center; color: var(--color-accent); font-weight: 700; }

/* "It's not here" on the Use confirm card (E26). Understated on purpose — it is the exception, not
   the action, and it must not compete with the Use button. */
.scan-nothere-row { text-align: center; margin-top: var(--space-2); }
.scan-nothere-row .scan-nothere-confirm {
    background: none; border: none; cursor: pointer;
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
    text-decoration: underline;
    padding: var(--space-1) var(--space-2);
}
.scan-nothere-row .scan-nothere-confirm:hover { color: var(--color-accent); }

/* Transfer destination: "…or any location in the plant" — the storage map, in line under the
   part's own placements. Separated by a rule so the shortcuts above still read as the quick path. */
.scan-dest-any {
    margin-top:  var(--space-3);
    padding-top: var(--space-3);
    border-top:  1px solid var(--color-border-subtle);
}
.scan-dest-any .scan-confirm__meta { margin-bottom: var(--space-2); }

/* Negative-stock warning in the Use confirm card */
.scan-warn {
    margin-top:     var(--space-3);
    padding:        var(--space-2) var(--space-3);
    background:     rgba(224,112,16,.12);
    border:         1px solid rgba(224,112,16,.45);
    border-radius:  var(--radius-md);
    color:          var(--color-accent);
    font-size:      var(--font-size-sm);
    font-weight:    700;
    text-align:     center;
}
.scan-fixcount {
    margin-right:    auto;     /* push to the left of Cancel / Use */
    background:      none;
    border:          none;
    cursor:          pointer;
    color:           var(--color-accent);
    text-decoration: underline;
    font-size:       var(--font-size-sm);
    padding:         var(--space-2);
}
.btn-warn-go {
    background:   var(--color-accent) !important;
    border-color: var(--color-accent) !important;
    color:        #fff !important;
}

/* Add / Use Stock chooser overlay (launched from Parts) */
.scan-actions__head {
    display:         flex;
    align-items:     center;
    justify-content: space-between;
    padding:         var(--space-4) var(--space-5);
    border-bottom:   1px solid var(--color-border-subtle);
}
.scan-actions__title { font-size: var(--font-size-lg); font-weight: 800; }
.scan-actions__close {
    background:  none;
    border:      none;
    cursor:      pointer;
    font-size:   1.2rem;
    line-height: 1;
    color:       var(--color-text-muted);
    padding:     var(--space-1) var(--space-2);
    border-radius: var(--radius-sm);
}
.scan-actions__close:hover { color: var(--color-text-secondary); }
.scan-actions__body { padding: var(--space-5); overflow-y: auto; }
.btn-stock-actions { font-weight: 700; }
.parts-show-inactive {
    display:     flex;
    align-items: center;
    gap:         6px;
    font-size:   var(--font-size-sm);
    color:       var(--color-text-secondary);
    cursor:      pointer;
    white-space: nowrap;
}

/* Read-only "stock by location" breakdown on the Parts edit form */
.loc-breakdown {
    margin-top:    var(--space-4);
    padding:       var(--space-3) var(--space-4);
    border:        1px solid var(--color-border-subtle);
    border-radius: var(--radius-md);
    background:    var(--color-bg-subtle);
}
.loc-breakdown__head {
    font-size:      var(--font-size-xs);
    text-transform: uppercase;
    letter-spacing: .05em;
    font-weight:    700;
    color:          var(--color-text-secondary);
    margin-bottom:  var(--space-2);
}
.loc-breakdown__row {
    display:         flex;
    justify-content: space-between;
    align-items:     center;
    padding:         var(--space-1) 0;
    border-top:      1px solid var(--color-border-subtle);
    font-size:       var(--font-size-sm);
}
.loc-breakdown__row:first-of-type { border-top: none; }

/* E25/E12 — releasing an empty spot. The control only renders at qty 0 and only for someone who
   may place stock, so it is deliberately quiet: this is tidying, not a destructive action. */
.loc-breakdown__right { display: inline-flex; align-items: center; gap: var(--space-3); }
.btn-link-danger {
    background:   none;
    border:       none;
    padding:      0;
    cursor:       pointer;
    font-size:    var(--font-size-xs);
    color:        var(--color-text-muted);
    text-decoration: underline;
}
.btn-link-danger:hover { color: var(--color-danger); }

/* "Link a barcode" control on the part form */
.link-bc { margin-top: var(--space-4); }
.link-bc-list { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-2); }
.link-bc-chip {
    display:        inline-flex;
    align-items:    center;
    gap:            6px;
    padding:        2px 8px;
    border-radius:  999px;
    background:     var(--color-bg-subtle);
    border:         1px solid var(--color-border-subtle);
    font-family:    monospace;
    font-size:      var(--font-size-xs);
}
.link-bc-chip button {
    border: none; background: none; cursor: pointer;
    color: var(--color-text-muted); font-size: 12px; line-height: 1; padding: 0;
}
.link-bc-chip button:hover { color: var(--color-danger); }

/* Clear (✕) inside the Parts search box */
.search-bar .search-clear {
    position:        absolute;
    right:           6px;
    top:             50%;
    transform:       translateY(-50%);
    width:           22px;
    height:          22px;
    border:          none;
    border-radius:   50%;
    background:      var(--color-bg-muted, rgba(0,0,0,.07));
    color:           var(--color-text-muted);
    font-size:       12px;
    line-height:     1;
    cursor:          pointer;
    display:         flex;
    align-items:     center;
    justify-content: center;
}
.search-bar .search-clear:hover { color: var(--color-text-secondary); }
.search-bar .form-control { padding-right: 1.9rem; }

/* Only ONE clear button. `input[type=search]` makes WebKit render its own ✕, which sat right next to
   the styled .search-clear above — two X's in the same box. Suppressed only on a bar that carries our
   replacement, so every other module keeps the native one as its only way to clear. */
.search-bar.has-custom-clear input[type="search"]::-webkit-search-cancel-button,
.search-bar.has-custom-clear input[type="search"]::-webkit-search-decoration {
    -webkit-appearance: none;
    appearance:         none;
    display:            none;
}

/* iPhone portrait: keep the search box usable; wrap the action buttons below it */
@media (max-width: 768px) {
    .panel-actions { flex: 1 1 100%; }        /* Add/Use Stock + New Part drop to their own row */
    .panel-actions .btn { flex: 1 1 auto; }   /* and share that row */
    .search-bar { flex: 1 1 60%; min-width: 0; }
}

@media (max-width: 768px) {
    .scan-mode-btn { padding: var(--space-6) var(--space-2); }
}

/* 📷 icon button in the search bar toolbar */
.btn-scan-icon {
    background:    none;
    border:        1px solid var(--color-border);
    border-radius: var(--radius-md);
    cursor:        pointer;
    font-size:     1.25rem;
    line-height:   1;
    padding:       5px 9px;
    color:         var(--color-text-secondary);
    transition:    border-color .15s, background .15s;
    flex-shrink:   0;
}
.btn-scan-icon:hover {
    border-color: var(--color-primary);
    background:   var(--color-bg-subtle);
}

/* Small "📷 Scan" link below a form input */
.btn-scan-field {
    display:       inline-flex;
    align-items:   center;
    gap:           4px;
    background:    none;
    border:        1px solid var(--color-border);
    border-radius: var(--radius-md);
    cursor:        pointer;
    font-size:     var(--font-size-xs);
    color:         var(--color-text-muted);
    padding:       4px 10px;
    margin-top:    var(--space-2);
    transition:    border-color .15s, color .15s;
}
.btn-scan-field:hover {
    border-color: var(--color-primary);
    color:        var(--color-primary);
}

/* ── Data-change refresh banner ──────────────────────────────────────── */
.dv-banner {
    display: none;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-4);
    background: var(--color-primary);
    color: var(--color-text-inverse);
    font-size: var(--font-size-sm);
    position: sticky;
    top: 0;
    z-index: 100;
}
.dv-banner--visible { display: flex; }
.dv-banner__msg  { flex: 1; }
.dv-banner__refresh { flex-shrink: 0; background: rgba(255,255,255,.2); border-color: rgba(255,255,255,.4); color: #fff; }
.dv-banner__refresh:hover { background: rgba(255,255,255,.3); }
.dv-banner__dismiss {
    background: none;
    border: none;
    color: rgba(255,255,255,.7);
    font-size: var(--font-size-base);
    cursor: pointer;
    padding: 0 var(--space-1);
    line-height: 1;
}
.dv-banner__dismiss:hover { color: #fff; }

/* ── Parts: Location expand/collapse ─────────────────────────────────── */
.btn-loc-expand {
    background: none;
    border: none;
    color: var(--color-text-secondary);
    font-size: inherit;
    cursor: pointer;
    padding: 0;
    display: inline-block;
    opacity: 0.8;
    line-height: inherit;
}
.btn-loc-expand:hover { opacity: 1; color: var(--color-text); text-decoration: underline; }

/* Tighter horizontal padding on ✏️ 🗑️ action buttons so the Actions column stays compact */
.actions-cell .btn { padding-left: 6px; padding-right: 6px; }

.part-loc-row td.part-loc-cell {
    background: var(--color-bg-subtle);
    padding: var(--space-2) var(--space-4) var(--space-3) var(--space-8);
    border-bottom: 2px solid var(--color-border);
}

.part-loc-table {
    border-collapse: collapse;
    font-size: var(--font-size-xs);
    width: auto;
    min-width: 260px;
}
.part-loc-table th {
    text-align: left;
    padding: 3px 20px 3px 0;
    color: var(--color-text-secondary);
    font-weight: 600;
    border-bottom: 1px solid var(--color-border);
    white-space: nowrap;
}
.part-loc-table td {
    padding: 3px 20px 3px 0;
    vertical-align: middle;
    border-bottom: 1px solid var(--color-border-subtle);
    white-space: nowrap;
}
.part-loc-table tr:last-child td { border-bottom: none; }

/* ── Part search widget (Adjustments create form) ─────────────────── */
.part-search-wrap { position: relative; }
.part-search-row { display: flex; gap: var(--space-2); align-items: center; }
.part-search-row .form-control { flex: 1; min-width: 0; }
.part-search-scan-btn { flex-shrink: 0; }

/* ── Coming Soon placeholders (admin dev preview) ─────────────────────── */
.nav-soon {
    margin-left:    auto;
    font-size:      9px;
    font-weight:    700;
    text-transform: uppercase;
    letter-spacing: .05em;
    background:     rgba(224,112,16,.25);
    color:         var(--color-accent);
    padding:       2px 6px;
    border-radius: var(--radius-pill);
}
.coming-soon { max-width: 720px; margin: 0 auto; }
.coming-soon__hero { text-align: center; padding: var(--space-8) var(--space-4) var(--space-6); }
.coming-soon__icon { font-size: 56px; margin-bottom: var(--space-3); }
.coming-soon__title {
    display: flex; align-items: center; justify-content: center; flex-wrap: wrap;
    gap: var(--space-3); font-size: var(--font-size-2xl); font-weight: 700;
    color: var(--color-text); margin-bottom: var(--space-2);
}
.coming-soon__tagline {
    color: var(--color-text-muted); font-size: var(--font-size-md);
    max-width: 520px; margin: 0 auto; line-height: 1.5;
}
.coming-soon__card {
    background: var(--color-bg-surface); border: 1px solid var(--color-border-subtle);
    border-radius: var(--radius-lg); box-shadow: var(--shadow-sm); padding: var(--space-6);
}
.coming-soon__card h3 {
    font-size: var(--font-size-xs); text-transform: uppercase; letter-spacing: .05em;
    color: var(--color-text-secondary); margin: 0 0 var(--space-4);
}
.coming-soon__features { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--space-3); }
.coming-soon__features li {
    display: flex; gap: var(--space-3); align-items: flex-start;
    font-size: var(--font-size-sm); color: var(--color-text); line-height: 1.5;
}
.coming-soon__features li::before { content: "✓"; color: var(--color-success); font-weight: 700; flex-shrink: 0; }
.coming-soon__phase { text-align: center; margin-top: var(--space-5); color: var(--color-text-muted); font-size: var(--font-size-xs); }

/* ── Vendor detail modal (Phase 2) ────────────────────────────────────── */
.vendor-section-title { font-size: var(--font-size-sm); font-weight: 700; color: var(--color-text); margin: 0 0 var(--space-3); }
.vendor-linecard-add, .vendor-contact-add { display: flex; gap: var(--space-2); flex-wrap: wrap; margin-bottom: var(--space-3); }
.vendor-linecard-add .form-control { flex: 1; min-width: 0; }
.vendor-contact-add .form-control { flex: 1; min-width: 120px; }
.vendor-chip-list { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--space-2); }
.vendor-chip { display: inline-flex; align-items: center; gap: 6px; background: var(--color-bg-subtle); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-pill); padding: 4px 6px 4px 12px; font-size: var(--font-size-sm); }
.vendor-chip button { border: none; background: none; cursor: pointer; color: var(--color-text-muted); font-size: 13px; line-height: 1; padding: 0 2px; }
.vendor-chip button:hover { color: var(--color-danger); }
.vendor-contact-list { display: grid; gap: var(--space-2); margin-bottom: var(--space-3); }
.vendor-contact-row { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-2) var(--space-3); background: var(--color-bg-subtle); border-radius: var(--radius-md); }
.vendor-contact-row .vc-main { flex: 1; min-width: 0; }
.vendor-contacts-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); }
.vc-rc { display: inline-flex; align-items: center; gap: 4px; font-size: var(--font-size-xs); color: var(--color-text-secondary); cursor: pointer; flex-shrink: 0; }
.lc-results { max-height: 280px; overflow-y: auto; margin-top: var(--space-2); }
.lc-row { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding: var(--space-2) var(--space-3); border-bottom: 1px solid var(--color-border-subtle); }
.recip-table { width: 100%; border-collapse: collapse; font-size: var(--font-size-sm); margin-bottom: var(--space-2); }
.recip-table th, .recip-table td { border-bottom: 1px solid var(--color-border-subtle); padding: var(--space-2); text-align: left; }
.recip-table th:nth-child(2), .recip-table th:nth-child(3),
.recip-table td:nth-child(2), .recip-table td:nth-child(3) { width: 48px; text-align: center; }

/* ── Project detail modal (Phase 3) ───────────────────────────────────── */
.proj-part-add { display: flex; gap: var(--space-2); align-items: flex-start; margin-bottom: var(--space-3); }
.proj-part-list { margin-top: var(--space-2); }
.proj-part-list .data-table { font-size: var(--font-size-sm); }

/* ── DataTable expandable rows (chevron reveals a child row) ───────────── */
.data-table .expand-cell { width: 34px; text-align: center; padding: 0; }
.expand-toggle { background: none; border: none; cursor: pointer; color: var(--color-text-muted);
    font-size: 12px; line-height: 1; padding: 6px 8px; border-radius: var(--radius-sm);
    transition: color .15s ease, background .15s ease; }
.expand-toggle:hover { color: var(--color-text); background: var(--color-bg-subtle); }
.data-table tr.expand-row > td { background: var(--color-bg-subtle);
    border-bottom: 1px solid var(--color-border-subtle); padding: 0; }

/* ── RFQ detail + pricing matrix (Phase 4) ────────────────────────────── */
.rfq-head { display: flex; gap: var(--space-3); align-items: flex-end; flex-wrap: wrap; margin-bottom: var(--space-4); }
.rfq-head label { display: flex; flex-direction: column; gap: 4px; font-size: var(--font-size-xs); color: var(--color-text-secondary); }
.rfq-vendor-add { display: flex; gap: var(--space-2); flex-wrap: wrap; margin-bottom: var(--space-3); }
.rfq-vendor-add .form-control { flex: 1; min-width: 0; }
.rfq-matrix-wrap { overflow-x: auto; }
.rfq-matrix { border-collapse: collapse; width: 100%; font-size: var(--font-size-sm); }
.rfq-matrix th, .rfq-matrix td { border: 1px solid var(--color-border-subtle); padding: var(--space-2); text-align: left; vertical-align: top; }
.rfq-matrix th { background: var(--color-bg-subtle); white-space: nowrap; }
.rfq-matrix-part { min-width: 160px; }
.rfq-cell { white-space: nowrap; }
.rfq-cell .rfq-price { width: 90px; display: inline-block; }
.rfq-cell--min { background: var(--color-success-bg); }
.rfq-cell--awarded { outline: 2px solid var(--color-success); outline-offset: -2px; }
.rfq-award { border: none; background: none; cursor: pointer; font-size: 18px; color: var(--color-accent); padding: 0 4px; }
.rfq-award:disabled { opacity: .3; cursor: default; }
.rfq-price-val { font-weight: 600; }
.rfq-v-pick { display: inline-flex; align-items: center; gap: 6px; flex: 1; min-width: 0; }
.rfq-vendor-row { display: flex; align-items: center; gap: var(--space-2); padding: 5px 0; flex-wrap: wrap; }
/* Quote modal */
.rfq-quote-head { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-bottom: var(--space-3); }
.rfq-quote-head label { display: flex; flex-direction: column; gap: 4px; font-size: var(--font-size-xs); color: var(--color-text-secondary); }
.rfq-quote-head .form-control { min-width: 120px; }
.q-att-row { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding: var(--space-2) var(--space-3); background: var(--color-bg-subtle); border-radius: var(--radius-md); margin-bottom: 4px; }

/* ── Manufacturer picker (parts form, Phase 1 fix) ────────────────────── */
.mfr-status { min-height: 15px; margin-top: 4px; }
.mfr-ok  { color: var(--color-success); font-size: var(--font-size-xs); font-weight: 600; }
.mfr-new { color: var(--color-text-secondary); font-size: var(--font-size-xs); }

/* ── Category combobox (parts form) ───────────────────────────────────── */
.cat-input-row { display: flex; gap: 6px; align-items: center; }
.cat-input-row .form-control { flex: 1; min-width: 0; }
.cat-arrow { flex-shrink: 0; border: 1px solid var(--color-border); background: var(--color-bg-surface); border-radius: var(--radius-md); cursor: pointer; padding: 0 12px; height: 38px; color: var(--color-text-secondary); font-size: 13px; }
.cat-arrow:hover { border-color: var(--color-primary); background: var(--color-bg-subtle); }
.ext-link { font-size: 11px; color: var(--color-text-muted); }
.vendor-search-hint { font-size: var(--font-size-xs); color: var(--color-text-muted); margin: -2px 0 var(--space-3); }

/* ── RFQ send-email vendor checkboxes (Phase 4 fix) ───────────────────── */
.rfq-vendor-row { display: flex; align-items: center; gap: var(--space-2); padding: 4px 0; }
.rfq-vendor-row label { display: flex; align-items: center; gap: 6px; flex: 1; font-size: var(--font-size-sm); cursor: pointer; }
.rfq-vendor-row .vendor-email { color: var(--color-text-muted); font-size: var(--font-size-xs); }

/* ── Approvals (Phase 5) ──────────────────────────────────────────────── */
.appr-card { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding: var(--space-3) var(--space-4); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-md); margin-bottom: var(--space-2); background: var(--color-bg-surface); }
.appr-main { min-width: 0; }
.appr-actions { display: flex; gap: var(--space-2); flex-wrap: wrap; flex-shrink: 0; }
/* A card that opens its order reads as clickable: pointer, left accent, hover lift, focus ring. */
.appr-card--open { cursor: pointer; border-left: 3px solid var(--color-primary); transition: background .12s ease, border-color .12s ease, box-shadow .12s ease; }
.appr-card--open:hover { background: var(--color-bg-elevated, rgba(127,127,127,.08)); border-color: var(--color-primary); box-shadow: 0 2px 10px rgba(0,0,0,.14); }
.appr-card--open:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; }
.appr-open-hint { flex-shrink: 0; white-space: nowrap; font-size: var(--font-size-xs); font-weight: 600; color: var(--color-primary); margin-left: auto; }
.appr-card--open .appr-actions { margin-left: 0; }

/* ── Assets tree (Phase 7) ────────────────────────────────────────────── */
.asset-tree { padding: var(--space-2) 0; }
.asset-node { display: flex; align-items: center; gap: 8px; padding: 6px 8px; border-bottom: 1px solid var(--color-border-subtle); }
.asset-node strong { font-size: var(--font-size-sm); }
.asset-node-actions { margin-left: auto; display: flex; gap: 4px; flex-shrink: 0; }

/* ── CMMS Dashboard (Phase 9) ─────────────────────────────────────────── */
.kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: var(--space-3); margin-bottom: var(--space-5); }
.kpi-tile { background: var(--color-bg-surface); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-lg); box-shadow: var(--shadow-sm); padding: var(--space-4); text-align: center; }
.kpi-tile__icon { font-size: 22px; }
.kpi-tile__val { font-size: var(--font-size-2xl); font-weight: 800; color: var(--color-primary); line-height: 1.1; }
.kpi-tile__label { font-size: var(--font-size-xs); color: var(--color-text-muted); text-transform: uppercase; letter-spacing: .04em; }
.cmmsdash-cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: var(--space-4); }
.cmmsdash-card-title { font-weight: 700; font-size: var(--font-size-sm); padding: var(--space-3) var(--space-4); border-bottom: 1px solid var(--color-border-subtle); }

.part-search-dropdown {
    position: absolute;
    top: 100%;
    left: 0; right: 0;
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
    z-index: 200;
    max-height: 260px;
    overflow-y: auto;
    margin-top: 2px;
}
.part-search-option {
    padding: var(--space-3) var(--space-4);
    cursor: pointer;
    border-bottom: 1px solid var(--color-border-subtle);
    font-size: var(--font-size-sm);
}
.part-search-option:last-child { border-bottom: none; }
.part-search-option:hover { background: var(--color-bg-subtle); }
.part-search-empty { color: var(--color-text-muted); font-style: italic; cursor: default; }
.part-selected-chip {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    background: var(--color-bg-subtle);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    font-size: var(--font-size-sm);
}
.btn-chip-clear {
    background: none;
    border: none;
    cursor: pointer;
    color: var(--color-text-secondary);
    font-size: var(--font-size-sm);
    padding: 0;
    line-height: 1;
    flex-shrink: 0;
}
.btn-chip-clear:hover { color: var(--color-danger); }

/* Datasheet / link affordances (parts list + any url form field) */
.ds-link { text-decoration: none; opacity: .75; margin-left: 4px; }
.ds-link:hover { opacity: 1; }
.url-field { display: flex; gap: var(--space-2); align-items: stretch; }
.url-field input { flex: 1 1 auto; min-width: 0; }
.url-field .url-open { flex: 0 0 auto; white-space: nowrap; }
.url-field .url-open:disabled { opacity: .45; cursor: default; }

/* ── Settings → Storage Map (E25) ─────────────────────────────────────────────
   The plant's spots, grouped by area. Reads as a walk through the building, which is also
   how the count sheet (E27) will print — hence no sort_order column: the coordinates
   already sort into walking order. */
.spot-area { margin-bottom: var(--space-5); }
.spot-area__head {
    display:       flex;
    align-items:   baseline;
    gap:           var(--space-3);
    font-weight:   600;
    padding:       var(--space-2) 0;
    border-bottom: 1px solid var(--color-border);
    margin-bottom: var(--space-1);
}
.spot-row {
    display:         flex;
    align-items:     center;
    justify-content: space-between;
    gap:             var(--space-3);
    padding:         var(--space-2) 0 var(--space-2) var(--space-4);
    border-bottom:   1px solid var(--color-border-subtle);
    font-size:       var(--font-size-sm);
}
.spot-row--retired { opacity: 0.55; }
.spot-row__where { flex: 1 1 auto; display: flex; align-items: center; gap: var(--space-2); }
.spot-row__what  { flex: 0 0 auto; }
.spot-actions    { display: inline-flex; gap: var(--space-3); flex: 0 0 auto; }
.btn-link {
    background: none; border: none; padding: 0; cursor: pointer;
    font-size: var(--font-size-xs); color: var(--color-accent); text-decoration: underline;
}
.settings-section-head {
    display: flex; align-items: flex-start; justify-content: space-between;
    gap: var(--space-4); margin-bottom: var(--space-4);
}
.settings-section-head h3 { margin: 0 0 2px; }

/* A locked settings panel states the rule in words. A greyed-out control still looks operable —
   John's standing rule that a locked record shows TEXT, not disabled inputs. */
.settings-locked {
    padding:       var(--space-5);
    border:        1px dashed var(--color-border);
    border-radius: var(--radius-md);
    color:         var(--color-text-muted);
    font-size:     var(--font-size-sm);
    line-height:   1.6;
}

/* E26 — a flagged placement. Quiet enough to live in a list, loud enough that the next person
   looking at this part cannot miss that the shelf and the system disagree. */
.loc-breakdown__row--flagged { background: var(--color-danger-bg); }
.disc-flag { font-size: var(--font-size-xs); }

/* ── E27 count sheet ──────────────────────────────────────────────────────────
   Built to be PRINTED and carried round the plant on a clipboard, so the screen layout and the
   paper layout are the same thing. PDF is the browser's own "Save as PDF" — the server has no PDF
   writer, and adding one would be a dependency that dies at the VM move. */
.cs-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-4); margin-bottom: var(--space-5); }
.cs-head h3 { margin: 0 0 4px; }
.cs-actions { display: flex; align-items: center; gap: var(--space-3); flex: 0 0 auto; }
.cs-area { margin-bottom: var(--space-6); break-inside: avoid; }
.cs-area__head { margin: 0 0 var(--space-2); }
.cs-qty { font-variant-numeric: tabular-nums; font-weight: 600; }
/* The write-in box — the whole reason this is printed rather than just read. */
.cs-count { border-bottom: 1px solid var(--color-border); min-width: 90px; }
.cs-row--empty td { color: var(--color-text-muted); }

@media print {
    /* Everything that is chrome rather than sheet. */
    .sidebar, .topbar, .bottom-nav, .report-nav, .cs-actions, #toast-container,
    .panel-toolbar, .panel-actions { display: none !important; }
    body, #main-content, .tab-panel { background: #fff !important; color: #000 !important; }
    .cs-table, .cs-table th, .cs-table td { border-color: #999 !important; color: #000 !important; }
    .cs-area { page-break-inside: avoid; }
    .cs-count { border-bottom: 1px solid #000 !important; }
    .badge { border: 1px solid #666 !important; color: #000 !important; background: none !important; }
    a[href]:after { content: ""; }   /* no URL noise on paper */
}

/* E26 in the scan flow — the flag sits beside the location button, not inside it, so tapping the
   location still just picks it. Tap-first (iPad): both targets stay full height. */
.scan-place-row { display: flex; align-items: stretch; gap: var(--space-2); }
.scan-place-row .scan-place { flex: 1 1 auto; }
.scan-place-row .scan-nothere { flex: 0 0 auto; padding: 0 var(--space-2); white-space: nowrap; }

/* The shared chain block (E2/E6, E30) — same treatment wherever the chain is shown. */
.chain-flag {
    margin: var(--space-3) 0;
    padding: 8px 12px;
    border-radius: var(--radius-md);
    background: var(--color-bg-subtle);
    border-left: 3px solid var(--color-border);
}
.chain-flag--danger { border-left-color: var(--color-danger); }
.chain-flag--ok     { border-left-color: var(--color-success); }

/* E9 — nav badges. Small, quiet, and only ever on a nav item the role can actually use.
   Counts are decided server-side; this is only the paint. */
.nav-badge {
    margin-left:   auto;
    min-width:     20px;
    padding:       1px 6px;
    border-radius: var(--radius-pill);
    background:    var(--color-accent);
    color:         #fff;
    font-size:     11px;
    font-weight:   700;
    line-height:   1.5;
    text-align:    center;
    flex:          0 0 auto;
}
.bottom-nav-item .nav-badge { margin-left: 2px; }

/* E19 — what a job has cost. Three figures, because "committed" and "received" answer different
   questions and a single total would hide the one E17's close gate depends on. */
.job-cost-summary {
    display: flex;
    gap: var(--space-6);
    padding: var(--space-3) 0 var(--space-2);
}
.job-cost-summary strong { font-size: var(--font-size-lg); font-variant-numeric: tabular-nums; }
