/* Serveris — Phase 1 styling.
   Plain CSS, no framework.  Same colour family as the desktop launcher
   so the two surfaces feel like siblings, but laid out for full-page
   browser views (not modal cards). */

:root {
  --bg:           #f1f5f9;
  --card:         #ffffff;
  --ink:          #1a1d24;
  --muted:        #5b6478;
  --line:         #e0e5ee;
  --primary:      #2563eb;
  --primary-d:    #1d4ed8;
  --danger:       #dc2626;
  --warn:         #d97706;
  --ok:           #15803d;
  /* Neutral surface/line/ink scale — every formerly-hardcoded slate/
     gray literal maps here so the dark theme below can flip the whole
     UI by overriding ONE block.  Light values = original literals. */
  --surface:      #ffffff;   /* cards, table rows, modals      */
  --surface-2:    #f8fafc;   /* table headers, subtle panels    */
  --surface-3:    #f1f5f9;   /* pills, hovers, ghost buttons    */
  --surface-4:    #e2e8f0;   /* pressed / hover-on-surface-3    */
  --line-2:       #e5e7eb;   /* hairline borders                */
  --line-3:       #cbd5e1;   /* stronger borders, input edges   */
  --ink-2:        #334155;   /* secondary headings              */
  --ink-3:        #475569;   /* tertiary text on light pills    */
}

/* ===== Dark theme =====
   Activated by <html data-theme="dark">.  The toggle button in the
   topbar (base.html) persists the choice in localStorage and an
   inline <head> script applies it before first paint (no flash).
   Semantic chips/banners (amber running-banner, green done-banner,
   state pills with their own bg+ink pairs) are intentionally left
   as-is — they carry their own contrast in both themes. */
html[data-theme="dark"] {
  --bg:           #0f172a;
  --card:         #1e293b;
  --ink:          #e6eaf2;
  --muted:        #94a3b8;
  --line:         #2e3a4f;
  --primary:      #60a5fa;
  --primary-d:    #3b82f6;
  --danger:       #f87171;
  --warn:         #fbbf24;
  --ok:           #4ade80;
  --surface:      #1e293b;
  --surface-2:    #233042;
  --surface-3:    #2b3a50;
  --surface-4:    #344862;
  --line-2:       #2e3a4f;
  --line-3:       #46566e;
  --ink-2:        #cbd5e1;
  --ink-3:        #a8b4c6;
  color-scheme: dark;   /* native scrollbars, date pickers, etc. */
}
/* Inputs keep readable text/edges on dark surfaces. */
html[data-theme="dark"] input,
html[data-theme="dark"] select,
html[data-theme="dark"] textarea {
  background: var(--surface-2);
  color: var(--ink);
  border-color: var(--line-3);
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  font-size: 14px;
  color: var(--ink);
  background: var(--bg);
  min-height: 100vh;
}
a { color: var(--primary); text-decoration: none; }
a:hover { text-decoration: underline; }
hr { border: 0; border-top: 1px solid var(--line); margin: 18px 0; }

/* ===== Top bar (when authenticated) ===== */
.topbar {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 22px;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  box-shadow: 0 1px 0 rgba(0,0,0,0.02);
}
.topbar-left  { display: flex; align-items: center; gap: 26px; }
.topbar-right { display: flex; align-items: center; gap: 10px; }
.brand {
  font-weight: 700; font-size: 17px; color: var(--ink);
}
.brand:hover { text-decoration: none; color: var(--primary); }
.navlinks { display: flex; gap: 18px; }
.navlinks a {
  color: var(--muted); font-weight: 500;
}
.navlinks a:hover { color: var(--ink); text-decoration: none; }
.who { color: var(--muted); font-size: 13px; display: inline-flex; gap: 8px; align-items: center; }

/* ===== Live agent-status banner (filled by the JS poller in base.html) ===== */
.agent-status-bar {
  /* No padding/margin when empty.  Children supply their own spacing. */
  position: sticky; top: 0; z-index: 50;
}
.agent-status {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 18px;
  font-size: 13px;
  border-bottom: 1px solid transparent;
}
.agent-status-running {
  background: #fef3c7; color: #78350f; border-bottom-color: #fbbf24;
}
.agent-status-done {
  background: #dcfce7; color: #14532d; border-bottom-color: #86efac;
}
/* Health: a run that is alive but no longer making progress. */
.agent-status-warn {
  background: #fef08a; color: #713f12; border-bottom-color: #eab308;
}
.agent-status-alert {
  background: #fee2e2; color: #7f1d1d; border-bottom-color: #ef4444;
  animation: agentAlertPulse 1.6s ease-in-out infinite;
}
@keyframes agentAlertPulse {
  0%, 100% { background: #fee2e2; }
  50%      { background: #fecaca; }
}
.agent-warn-ico { font-size: 16px; line-height: 1; }
@media (prefers-reduced-motion: reduce) {
  .agent-status-alert { animation: none; }
}
.agent-status-text {
  flex: 1;
  display: flex; align-items: center; gap: 6px;
  min-width: 0;            /* allow truncation on long log lines */
}
.agent-status-text .muted { color: inherit; opacity: 0.72; }
.agent-status-text strong { font-weight: 700; }
.agent-spin {
  width: 14px; height: 14px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: agent-spin-rot 0.9s linear infinite;
  flex-shrink: 0;
}
@keyframes agent-spin-rot { to { transform: rotate(360deg); } }
.agent-check {
  width: 20px; height: 20px;
  display: inline-flex; align-items: center; justify-content: center;
  background: #166534; color: #ffffff;
  border-radius: 50%;
  font-weight: 800;
  flex-shrink: 0;
}
.agent-bar {
  width: 160px;
  height: 8px;
  background: rgba(0, 0, 0, 0.08);
  border-radius: 4px;
  overflow: hidden;
  flex-shrink: 0;
}
.agent-bar-fill {
  display: block;
  height: 100%;
  background: #b45309;
  transition: width 0.35s ease;
}
.agent-pct {
  font-weight: 700; min-width: 36px; text-align: right;
  flex-shrink: 0;
}
.agent-ingest-link {
  color: #14532d; text-decoration: underline; font-weight: 700;
}
.agent-ingest-link:hover { text-decoration: none; }
.agent-dismiss {
  background: transparent; border: 0; cursor: pointer;
  font-size: 18px; line-height: 1; padding: 0 6px;
  color: inherit; opacity: 0.6;
}
.agent-dismiss:hover { opacity: 1; }

/* VQC Photo Server status widget — moved to the global topbar.
   Mirrors the launcher's "Photos on/off · Start · Stop" pattern. */
.photo-server-bar {
  display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
/* Tighter spacing when sitting inside the .topbar.  The topbar is
   already 12 px tall padding-wise, so use smaller button sizes
   and clip the URL when it's too long to keep the bar one line. */
.topbar-photos                { gap: 6px; }
.topbar-photos .photo-pill    { padding: 3px 10px; font-size: 11px; }
.topbar-photos #photo-url     { max-width: 220px; overflow: hidden;
                                text-overflow: ellipsis; white-space: nowrap; }
.photo-pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 12px;
  border-radius: 999px;
  font-size: 12px; font-weight: 600;
  white-space: nowrap;
}
.photo-pill-on  { background: #dcfce7; color: #166534; }
.photo-pill-off { background: var(--surface-3); color: var(--ink-3); }
.photo-pill .photo-dot {
  display: inline-block;
  width: 8px; height: 8px;
  background: currentColor;
  border-radius: 50%;
  animation: photo-pulse 1.4s ease-in-out infinite;
}
.photo-pill-off .photo-dot { background: #94a3b8; animation: none; }
@keyframes photo-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.35; }
}

/* Toolbar "first slot" — fixed-width wrapper around the first
   element in each toolbar row.  Used on the Orders page so the
   Order Filling button (row 1) and the Order to Production button
   (row 2) start at the same X coordinate, making the two pipeline
   stages read as a parallel column.  The contents (picker, "+ New
   order" button) sit at the left of the slot; the empty trailing
   space is padding that pushes the NEXT element to the right edge
   of the slot. */
.agent-first-slot {
  display: inline-flex;
  align-items: center;
  min-width: 280px;
}

/* Inline account picker — sits next to the Scan/Refresh buttons. */
.agent-picker-label {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; color: var(--muted);
}
.agent-picker-label > span { font-weight: 600; }
.agent-picker {
  padding: 6px 8px;
  border: 1px solid var(--line-3);
  border-radius: 5px;
  font-size: 12px;
  background: var(--surface);
  color: var(--ink);
  cursor: pointer;
  max-width: 260px;
}
.agent-picker:focus {
  outline: none; border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15);
}

/* Stop button on the running banner.  Brick-red so it reads as
   destructive next to the yellow running state.  Disabled state (set
   by JS once the click is in flight) shows the ellipsis "…". */
.agent-stop-btn {
  background: #b91c1c; color: #ffffff;
  border: 1px solid #7f1d1d;
  border-radius: 5px;
  padding: 6px 12px;
  font-size: 12px;
  font-weight: 700;
  cursor: pointer;
  flex-shrink: 0;
  transition: background 0.12s;
}
.agent-stop-btn:hover:not(:disabled) { background: #991b1b; }
.agent-stop-btn:disabled { opacity: 0.6; cursor: not-allowed; }

/* ===== Flash messages ===== */
.flashes { padding: 0 22px; margin-top: 10px; }
.flash {
  padding: 10px 14px;
  border-radius: 6px;
  margin-bottom: 8px;
  font-size: 13px;
}
.flash-success { background: #dcfce7; color: #166534; border: 1px solid #86efac; }
.flash-danger  { background: #fee2e2; color: #991b1b; border: 1px solid #fca5a5; }
.flash-warning { background: #fef3c7; color: #78350f; border: 1px solid #fbbf24; }
.flash-info    { background: #dbeafe; color: #1e3a8a; border: 1px solid #93c5fd; }

/* ===== Main canvas ===== */
.main {
  padding: 22px;
  max-width: 1280px;
  margin: 0 auto;
}
.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 22px;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
}
.card h1 { margin: 0 0 6px; font-size: 22px; }
.card h2 { margin: 18px 0 6px; font-size: 16px; color: var(--ink); }
.card-header {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 14px;
}
/* Stacked variant — title on its own top line, toolbar on the
   line below it.  Used on the Offers page so the agent controls
   don't have to share a row with the heading. */
.card-header-stacked {
  flex-direction: column;
  align-items: stretch;
  gap: 12px;
}
.card-header-stacked > h1 { margin: 0; }

/* Toolbar row underneath the title — holds the agent form +
   auto-scan pill + download link.  flex-wrap so narrow screens
   wrap instead of overflowing. */
.agent-toolbar {
  display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
}
.agent-form {
  display: inline-flex; flex-wrap: wrap; gap: 6px; align-items: center;
  margin: 0;   /* kill the user-agent <form> default margin */
}

/* Paired Start/Stop control — kept as siblings so they sit
   immediately next to each other in the toolbar, with a small
   visual breather between them.  Each button keeps its own full
   rounded outline + drop shadow (unlike the merged-pair variant). */
.btn-pair { display: inline-flex; gap: 8px; }
.muted    { color: var(--muted); }
.small    { font-size: 11.5px; }
.center   { text-align: center; }
.mono     { font-family: "Consolas", "Menlo", monospace; font-size: 12px; }
.inline   { display: inline-block; }

/* ===== Auth (login) card ===== */
.auth-card {
  max-width: 380px;
  margin: 80px auto;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 30px 28px;
  box-shadow: 0 4px 12px rgba(15,23,42,0.06);
}
.auth-title { margin: 0; font-size: 26px; }
.auth-sub   { margin: 4px 0 22px; color: var(--muted); }

/* ===== Forms ===== */
.field, .field-inline {
  display: block;
  margin: 12px 0;
}
.field > span { display: block; font-weight: 600; font-size: 12.5px; margin-bottom: 4px; }
.field input, .field select, .field-inline input {
  width: 100%;
  padding: 9px 11px;
  border: 1px solid var(--line-3);
  border-radius: 6px;
  font-size: 14px;
  background: var(--surface);
}
.field input:focus, .field select:focus {
  outline: none; border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(37,99,235,0.15);
}
.field-inline {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 13px; color: var(--muted);
}
.field-inline input { width: auto; }
.err {
  color: var(--danger); font-size: 12px; margin-top: 4px;
}
.form-narrow { max-width: 460px; }
.form-actions {
  display: flex; gap: 8px; justify-content: flex-end; margin-top: 18px;
}

/* ===== Buttons =====
   Pronounced "3D" look — chunky drop shadow at rest, dramatic
   lift on hover, satisfying push-in on click.  Mirrors the
   launcher's _RoundedBtn but pushed harder for a more tactile feel.

     * Rest: 3-layer shadow (close-tight + mid + ambient) so the
       button reads as visibly raised off the page.
     * Hover: lifts -3 px, shadow stretches to ~18 px below — like
       it physically pops toward the cursor.
     * Active: sinks +2 px with a tight + inset shadow combo so it
       looks pushed into the page.
     * Colored variants additionally get a top-edge inset highlight
       AND a bottom-edge inset shadow — the bevel/rim that sells
       the raised-physical-button illusion.
*/
.btn {
  display: inline-block;
  padding: 9px 16px;
  font-size: 13px;
  font-weight: 600;
  border-radius: 6px;
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
  font-family: inherit;
  box-shadow:
    0 1px 2px  rgba(15, 23, 42, 0.20),
    0 4px 6px  rgba(15, 23, 42, 0.14),
    0 8px 14px rgba(15, 23, 42, 0.08);
  transform: translateY(0);
  transition:
    background 0.12s, border-color 0.12s, color 0.12s,
    transform 0.10s ease-out, box-shadow 0.15s ease-out;
}
.btn:hover {
  box-shadow:
    0 2px 3px   rgba(15, 23, 42, 0.24),
    0 8px 12px  rgba(15, 23, 42, 0.20),
    0 18px 28px rgba(15, 23, 42, 0.14);
  transform: translateY(-3px);
}
.btn:active {
  box-shadow:
    0 1px 1px rgba(15, 23, 42, 0.30),
    inset 0 2px 3px rgba(15, 23, 42, 0.20);
  transform: translateY(2px);
}
.btn:focus-visible {
  outline: 2px solid rgba(37, 99, 235, 0.45);
  outline-offset: 2px;
}
.btn[disabled], .btn:disabled {
  opacity: 0.55;
  cursor: not-allowed;
  transform: none;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.12);
}
.btn-block { width: 100%; margin-top: 6px; }
.btn-sm { padding: 6px 11px; font-size: 12px; }
.btn-primary {
  background: var(--primary); color: #ffffff; border-color: var(--primary-d);
}
.btn-primary:hover { background: var(--primary-d); text-decoration: none; }
.btn-ghost {
  background: var(--surface-3); color: var(--ink); border-color: var(--line-3);
}
.btn-ghost:hover { background: var(--surface-4); color: var(--ink); text-decoration: none; }
/* Green Start / red Stop for the Offers page auto-scan controls. */
.btn-success {
  background: #16a34a; color: #ffffff; border-color: #15803d;
}
.btn-success:hover { background: #15803d; text-decoration: none; }
.btn-danger {
  background: #dc2626; color: #ffffff; border-color: #b91c1c;
}
.btn-danger:hover { background: #b91c1c; text-decoration: none; }

/* Beveled bright/colored variants — top inset = glossy highlight,
   bottom inset = darker "rim" so the button looks like a physical
   key sticking up off the surface.  Both lighten/deepen on hover
   in proportion to the drop-shadow change. */
.btn-primary, .btn-success, .btn-danger {
  box-shadow:
    0 1px 2px   rgba(15, 23, 42, 0.22),
    0 4px 6px   rgba(15, 23, 42, 0.18),
    0 8px 14px  rgba(15, 23, 42, 0.10),
    inset 0 1px 0  rgba(255, 255, 255, 0.30),
    inset 0 -2px 0 rgba(0,   0,   0,   0.18);
}
.btn-primary:hover, .btn-success:hover, .btn-danger:hover {
  box-shadow:
    0 3px 4px   rgba(15, 23, 42, 0.26),
    0 10px 14px rgba(15, 23, 42, 0.22),
    0 20px 30px rgba(15, 23, 42, 0.16),
    inset 0 1px 0  rgba(255, 255, 255, 0.36),
    inset 0 -2px 0 rgba(0,   0,   0,   0.20);
}
.btn-primary:active, .btn-success:active, .btn-danger:active {
  box-shadow:
    0 1px 1px rgba(15, 23, 42, 0.32),
    inset 0 2px 4px rgba(0, 0, 0, 0.30),
    inset 0 -1px 0 rgba(0, 0, 0, 0.10);
}

/* Narrow numeric input next to the auto-scan controls. */
.agent-interval {
  width: 70px;
  padding: 6px 8px;
  border: 1px solid var(--line-3);
  border-radius: 5px;
  font-size: 12px;
  background: var(--surface);
  text-align: right;
}
.agent-interval:focus {
  outline: none; border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15);
}

/* Auto-scan countdown pill — renders next to the Start/Stop
   buttons.  Three states (off / on / busy) so the operator can
   tell at a glance whether the loop is idle-counting-down or
   actively running a scan right now.

   ``min-width`` + ``justify-content: center`` reserve the same
   horizontal space whether the pill has long text, short text,
   or is hidden — so the buttons either side of it don't shuffle
   left/right as the countdown ticks.  The JS toggles
   ``visibility: hidden`` (not ``display: none``) for the same
   reason: space stays reserved, only the ink disappears. */
.auto-pill {
  display: inline-flex; align-items: center; justify-content: center;
  gap: 6px;
  min-width: 260px;
  padding: 4px 12px;
  font-size: 12px; font-weight: 600;
  border-radius: 999px;
  white-space: nowrap;
}
.auto-pill-on   { background: #dcfce7; color: #166534; }
.auto-pill-busy { background: #fef3c7; color: #92400e; }
/* OFF: borderless white pill (matches launcher C_CARD).  Text
   muted slate; dot is forced red so "scanner is idle" reads at
   a glance without parsing the label. */
.auto-pill-off  { background: var(--surface); color: var(--ink-3); }
.auto-pill-off .auto-dot { background: #dc2626; }
.auto-jitter {
  font-size: 10px;
  font-weight: 500;
  opacity: 0.75;
  margin-left: 2px;
}

/* Order Filling Agent Log — one card per agent run, with a header
   strip + a tabular list of the orders processed in that run.
   Colour-coded result chips mirror the launcher's per-result palette
   (launcher.py:_RESULT_COLORS). */
.agent-run-card {
  border: 1px solid var(--line-2);
  border-radius: 8px;
  margin: 14px 0;
  background: var(--surface);
  overflow: hidden;
}
.agent-run-header {
  display: flex; justify-content: space-between; align-items: center;
  gap: 12px; flex-wrap: wrap;
  padding: 10px 14px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--line-2);
}
.agent-run-table { margin: 0; border: 0; }
.agent-run-table th { background: var(--surface-3); }
.agent-run-table td, .agent-run-table th { border-color: var(--line-2); }

/* Result chips — same palette as the launcher's popup.
   ADDED/CONFIRMED = green   (#16A34A / #DCFCE7)
   FAILED/ERROR    = red     (#991B1B / #FEE2E2)
   ALREADY         = blue    (#1E40AF / #DBEAFE)
   MANUAL          = amber   (#92400E / #FEF3C7)
   neutral fallback for anything else (slate). */
.pill.res-added   { background: #dcfce7; color: #166534; }
.pill.res-failed  { background: #fee2e2; color: #991b1b; }
.pill.res-already { background: #dbeafe; color: #1e40af; }
.pill.res-manual  { background: #fef3c7; color: #92400e; }
.pill.res-neutral { background: var(--surface-3); color: var(--ink-2); }

/* Production-report top-of-page counter strip — one tile per
   summary bucket (total / ok / warning / failed / skipped). */
.prod-counters {
  display: flex; gap: 8px; flex-wrap: wrap;
  margin: 6px 0 14px 0;
}
.prod-counter {
  flex: 1 1 110px;
  text-align: center;
  padding: 12px 8px;
  border-radius: 8px;
  border: 1px solid transparent;
  background: var(--surface-2);
}
.prod-counter > strong { display: block; font-size: 22px; line-height: 1.2; }
.prod-counter > span   { display: block; font-size: 11px; text-transform: uppercase;
                         letter-spacing: 0.5px; opacity: 0.78; margin-top: 2px; }
.prod-counter-total   { background: var(--surface-3); color: var(--ink-2); border-color: var(--line-2); }
.prod-counter-ok      { background: #dcfce7; color: #166534; border-color: #86efac; }
.prod-counter-warn    { background: #fef3c7; color: #92400e; border-color: #fcd34d; }
.prod-counter-failed  { background: #fee2e2; color: #991b1b; border-color: #fca5a5; }
.prod-counter-skipped { background: #dbeafe; color: #1e40af; border-color: #93c5fd; }

/* Processing-report cards — one per problematic PO.  Coloured
   left-edge accent + status badge, matches the launcher's popup
   (launcher.py:5286).  Other states inherit the neutral block. */
.report-card {
  border: 1px solid var(--line-2);
  border-left-width: 5px;
  border-radius: 8px;
  margin: 10px 0;
  padding: 12px 14px 8px;
  background: var(--surface);
}
.report-card-err  { border-left-color: #dc2626; }
.report-card-warn { border-left-color: #d97706; }
.report-card-skp  { border-left-color: #94a3b8; }

.report-card-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px;
  margin-bottom: 8px;
}
.report-card-head > strong { font-size: 14px; }

.report-badge {
  display: inline-block;
  padding: 3px 9px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.5px;
  border-radius: 999px;
  text-transform: uppercase;
}
.report-card-err  .report-badge { background: #fee2e2; color: #991b1b; }
.report-card-warn .report-badge { background: #fef3c7; color: #92400e; }
.report-card-skp  .report-badge { background: var(--surface-3); color: var(--ink-3); }

.report-kv {
  display: grid;
  grid-template-columns: 80px 1fr;
  column-gap: 12px;
  row-gap: 3px;
  margin: 0;
  font-size: 12px;
}
.report-kv > dt {
  font-weight: 700;
  color: var(--ink);
  text-align: right;
  padding-right: 6px;
}
.report-kv > dd { margin: 0; }
.report-err  { color: #b91c1c; font-weight: 600; }
.report-warn { color: #b45309; font-weight: 600; }

/* "All clear" empty-state hero block. */
.report-all-clear {
  text-align: center;
  padding: 32px 12px 36px;
  border: 1px solid #86efac;
  background: #f0fdf4;
  border-radius: 8px;
  margin: 8px 0;
}
.report-all-clear h3 { margin: 0 0 8px; color: #166534; }
.report-all-clear p  { margin: 0; color: #14532d; line-height: 1.5; }

/* Manual confirm queue — one card per pending PO, with a reason
   row + per-entry "Open on Xometry" / "Mark resolved" actions.
   Two flavors via the source-driven modifier classes below. */
.queue-card {
  border: 1px solid var(--line-2);
  border-left: 5px solid #f59e0b;
  border-radius: 8px;
  margin: 10px 0;
  padding: 12px 14px 10px;
  background: var(--surface);
}
.queue-card-safety { border-left-color: #f59e0b; }  /* amber */
.queue-card-error  { border-left-color: #dc2626; }  /* red */
.queue-source {
  display: inline-block;
  margin-left: 6px;
  padding: 2px 8px;
  font-size: 11px;
  font-weight: 700;
  border-radius: 999px;
}
.queue-card-safety .queue-source { background: #fef3c7; color: #92400e; }
.queue-card-error  .queue-source { background: #fee2e2; color: #991b1b; }
.queue-card-head {
  display: flex; justify-content: space-between; align-items: center;
  gap: 10px; flex-wrap: wrap;
  margin-bottom: 8px;
}
.queue-po { font-size: 14px; }
.queue-actions { display: inline-flex; gap: 6px; align-items: center; }

/* Small numeric badge tacked onto a button — used for the
   manual-confirm pending count on the Orders page. */
.btn-badge {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 7px;
  font-size: 10px;
  font-weight: 700;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.35);
  color: inherit;
  vertical-align: middle;
}

/* View tabs above the counter strip — switch between "Last run" and
   "All history" without leaving the page.  Each tab is a link the
   user can right-click / bookmark; the active one gets the blue
   underline + bold text. */
.report-tabs {
  display: flex; gap: 4px; flex-wrap: wrap;
  border-bottom: 1px solid var(--line-2);
  margin: 8px 0 0;
}
.report-tab {
  padding: 8px 14px;
  font-size: 13px;
  color: var(--muted);
  text-decoration: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;       /* overlap the strip's bottom border */
  border-top-left-radius: 4px;
  border-top-right-radius: 4px;
  transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.report-tab:hover { background: var(--surface-2); color: var(--ink); }
.report-tab.is-active {
  color: var(--ink);
  font-weight: 600;
  border-bottom-color: var(--primary);
  background: var(--surface);
}

/* Print PO picker toolbar (Select-all toggle + Print Selected btn). */
.print-toolbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap;
  padding: 10px 12px;
  margin: 8px 0 8px;
  background: var(--surface-2);
  border: 1px solid var(--line-2);
  border-radius: 8px;
}
.print-pickall {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 13px;
  cursor: pointer;
}
.print-pickall input[type="checkbox"] { transform: scale(1.15); }

/* Production folder browser — breadcrumb + listing table. */
.folder-crumbs {
  font-size: 13px;
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 4px;
  margin: 6px 0 4px;
}
.folder-crumbs a {
  color: var(--primary);
  text-decoration: none;
  padding: 2px 6px;
  border-radius: 4px;
}
.folder-crumbs a:hover { background: #eff6ff; }
.folder-crumbs .crumb-sep { color: var(--muted); }
.folder-crumbs > strong { padding: 2px 6px; }

.folder-table .folder-link,
.folder-table .file-link {
  color: var(--ink);
  text-decoration: none;
}
.folder-table .folder-link:hover,
.folder-table .file-link:hover { text-decoration: underline; color: var(--primary); }

/* PO-cell hover popover on /orders.  Absolutely-positioned float
   that the JS in orders_list.html shows on mouseenter (after a
   small delay) with a fetched parts manifest.  Styling matches the
   .parts-grid look from the detail page — same visual language. */
.po-popover {
  position: absolute;
  z-index: 1000;
  width: 360px;
  max-height: 380px;
  overflow: auto;
  background: var(--surface);
  border: 1px solid var(--line-3);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(15, 23, 42, 0.18),
              0 2px 6px  rgba(15, 23, 42, 0.10);
  pointer-events: none;
  opacity: 0;
  transform: translateY(-2px);
  transition: opacity 0.10s ease-out, transform 0.10s ease-out;
}
.po-popover.visible {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
}
.po-pop-header {
  padding: 8px 12px;
  font-size: 12px; font-weight: 700;
  border-bottom: 1px solid var(--line-2);
  background: var(--surface-2);
  color: var(--ink);
}
.po-pop-body  { padding: 8px; }
.po-pop-loading { color: var(--muted); font-size: 12px; padding: 16px 12px; text-align: center; }
.po-pop-empty   { color: var(--muted); font-size: 12px; padding: 16px 12px; }
.po-pop-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
}
.po-pop-card {
  border: 1px solid var(--line-2);
  border-radius: 6px;
  overflow: hidden;
  background: var(--surface);
  display: flex; flex-direction: column;
}
.po-pop-thumb {
  width: 100%;
  aspect-ratio: 1 / 1;
  background: var(--surface-3);
  display: flex; align-items: center; justify-content: center;
  border-bottom: 1px solid var(--line-2);
}
.po-pop-thumb > img { width: 100%; height: 100%; object-fit: contain; display: block; }
.po-pop-name {
  font-size: 11px; font-weight: 600;
  padding: 4px 6px 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.po-pop-card .small  { padding: 0 6px 4px; }
.po-pop-more { padding: 6px 10px 2px; text-align: center; }

/* Parts gallery on /orders/<po> — grid of cards, each card has a
   square thumbnail + part metadata.  Same visual idea as the
   launcher's _show_parts_preview_popup, but inline rather than a
   modal. */
.parts-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 12px;
  margin: 10px 0 16px;
}
.parts-card {
  border: 1px solid var(--line-2);
  border-radius: 8px;
  background: var(--surface);
  overflow: hidden;
  display: flex; flex-direction: column;
}
.parts-thumb {
  width: 100%;
  aspect-ratio: 1 / 1;
  background: var(--surface-3);
  display: flex; align-items: center; justify-content: center;
  border-bottom: 1px solid var(--line-2);
}
.parts-thumb > img {
  width: 100%; height: 100%;
  object-fit: contain;
  display: block;
}
.parts-meta { padding: 8px 10px 10px; }
.parts-name {
  font-weight: 600;
  font-size: 12px;
  margin-bottom: 6px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.parts-kv {
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: 8px;
  row-gap: 2px;
  font-size: 11px;
  margin: 0;
}
.parts-kv > dt { color: var(--muted); white-space: nowrap; }
.parts-kv > dd { margin: 0; color: var(--ink); }
.parts-kv > dd.mono, .parts-kv > .mono { font-family: ui-monospace, Consolas, monospace; }

/* Fill-shipping form on /orders/<po> — compact, side-by-side fields. */
.ship-form {
  display: flex; gap: 10px; flex-wrap: wrap; align-items: flex-end;
  margin: 6px 0 12px;
}
.ship-form .field { display: flex; flex-direction: column; gap: 3px; min-width: 160px; }
.ship-form .field > span { font-size: 12px; color: var(--muted); font-weight: 600; }
.ship-form .field > input {
  padding: 7px 10px;
  border: 1px solid var(--line-3);
  border-radius: 5px;
  background: var(--surface);
  font-size: 13px;
  font-family: inherit;
}
.ship-form .field > input:focus {
  outline: none; border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15);
}

/* Downloaded-files block on /orders/<po> — tech PDF + CAD ZIP.
   Each item is a clickable filename + size hint, stacked vertically. */
.file-list {
  list-style: none;
  margin: 8px 0 12px 0;
  padding: 0;
}
.file-list > li {
  padding: 6px 10px;
  margin: 4px 0;
  background: var(--surface-2);
  border: 1px solid var(--line-2);
  border-radius: 6px;
  display: flex;
  align-items: center;
  gap: 8px;
}
.file-list > li:hover { background: var(--surface-3); }
.file-list > li a {
  font-weight: 600;
  color: var(--primary);
  text-decoration: none;
}
.file-list > li a:hover { text-decoration: underline; }
.auto-dot {
  display: inline-block;
  width: 8px; height: 8px;
  background: currentColor;
  border-radius: 50%;
  animation: auto-pulse 1.4s ease-in-out infinite;
}
@keyframes auto-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.35; }
}

/* ===== Pills + badges ===== */
.pill {
  display: inline-block;
  padding: 2px 8px;
  font-size: 11px;
  font-weight: 700;
  border-radius: 999px;
  /* Pills should NEVER wrap mid-label — keeps "Instant job!",
     "Ready to pick up", etc. on one line.  Narrow columns
     should widen to fit instead. */
  white-space: nowrap;
}
.pill-ok  { background: #dcfce7; color: #166534; }
.pill-off { background: #fee2e2; color: #991b1b; }
/* Bubble row badge — flags a critical-dimension row that an operator
   touched by hand, so it survives the next "Scan drawings" rescan. */
.pill-manual {
  background: #fef3c7;
  color: #92400e;
  font-size: 10px;
  margin-left: 4px;
}

/* Double-click-to-edit affordances on bubble value cells.  The cell
   stays read-only-looking by default; a subtle dotted underline +
   "text" cursor hint that double-clicking activates an inline editor.
   See the inline <script> in orders_detail.html. */
.dblclick-edit {
  cursor: text;
  position: relative;
}
.dblclick-edit:hover {
  background: #FEF9C3;     /* very light yellow — invitation to click */
}
/* The tol-min/tol-max paired spans live inside a <td>, so add a
   subtle outline so it's clear they're individually editable. */
.dblclick-edit-pair {
  padding: 1px 3px;
  border-radius: 3px;
}
.dblclick-edit-pair:hover {
  background: #FEF9C3;
}
/* The <input>/<select> created by JS during editing — full-width,
   tight padding so it doesn't shift the table layout. */
.dblclick-edit-input {
  width: 100%;
  box-sizing: border-box;
  padding: 1px 3px;
  font-size: 12px;
  font-family: inherit;
  border: 1px solid #2563EB;
  border-radius: 3px;
  background: var(--surface);
}
/* Collapsible sections on /orders/<po> — empty/no-data sections
   start collapsed so the page lands focused on the bits that
   actually have content.  Matches the "click to open" pattern on
   Xometry's order page. */
details.card-section {
  margin: 0;
  padding: 0;
}
details.card-section > summary {
  list-style: none;             /* drop the default disclosure marker */
  cursor: pointer;
  font-size: 1.25em;            /* approx <h2> */
  font-weight: 600;
  padding: 4px 0;
  user-select: none;
  /* Firefox + Safari respect this; Chrome respects ::-webkit-details-marker below */
}
details.card-section > summary::-webkit-details-marker { display: none; }
details.card-section > summary::before {
  content: "\25B8";              /* right-pointing triangle */
  display: inline-block;
  width: 14px;
  margin-right: 6px;
  color: var(--ink-3);
  transition: transform 0.15s ease-out;
}
details.card-section[open] > summary::before {
  transform: rotate(90deg);
}
details.card-section > summary:hover {
  background: var(--surface-2);
}
/* Lift the muted "(0)" / "(3 parts)" counter inline with the summary
   so it inherits the click target — avoids the operator missing the
   triangle by clicking on the counter span. */
details.card-section > summary .muted,
details.card-section > summary .pill {
  font-size: 13px;
  font-weight: 400;
  margin-left: 6px;
}

/* Auto-purge banner on /orders — heads-up that invoiced orders'
   files will be deleted in N days, plus a "just cleaned" line.
   Bright red border so it can't be missed; soft tint so it doesn't
   feel like an error.  Both rows compose freely (one or both
   present). */
.auto-purge-banner {
  border-left: 4px solid #DC2626;     /* alert red */
  background: #FEF2F2;
  padding: 8px 12px;
  margin: 0 0 10px 0;
  border-radius: 4px;
  font-size: 13px;
  line-height: 1.5;
  color: #7F1D1D;                      /* deep red text */
}
.auto-purge-row {
  margin: 2px 0;
}
.auto-purge-row strong {
  color: #991B1B;
}
.auto-purge-row.auto-purge-recent strong {
  color: var(--ink-3);                      /* muted — this is "done" info */
}
.auto-purge-row.auto-purge-recent {
  color: #4B5563;
}
.auto-purge-po {
  color: #B91C1C;
  text-decoration: none;
  font-weight: 600;
  padding: 1px 3px;
  border-radius: 3px;
}
.auto-purge-po:hover {
  background: #FECACA;
  text-decoration: underline;
}
.auto-purge-count {
  font-size: 11px;
  font-weight: 400;
  color: var(--ink-3);
  margin-left: 2px;
}

/* Brief green flash after a successful save — fades back to normal. */
.cell-saved-flash {
  animation: cell-saved-flash-anim 0.7s ease-out;
}
@keyframes cell-saved-flash-anim {
  0%   { background: #BBF7D0; }
  100% { background: transparent; }
}
.role-badge {
  display: inline-block;
  padding: 1px 7px;
  font-size: 10.5px;
  font-weight: 700;
  border-radius: 4px;
  letter-spacing: 0.5px;
  text-transform: uppercase;
}
.role-admin    { background: #fee2e2; color: #991b1b; }
.role-operator { background: #dbeafe; color: #1e40af; }
.role-viewer   { background: var(--surface-3); color: var(--ink-3); }

/* ===== Account dropdown (role badge is the trigger) ===== */
.user-menu { position: relative; display: inline-block; }
.user-menu-btn {
  border: none;
  cursor: pointer;
  font-family: inherit;
  line-height: 1.5;
  display: inline-flex;
  align-items: center;
  gap: 3px;
}
.user-menu-caret { font-size: 9px; }
.user-menu-dropdown {
  position: absolute;
  right: 0;
  top: calc(100% + 6px);
  min-width: 150px;
  padding: 4px;
  background: var(--surface);
  border: 1px solid var(--line-2);
  border-radius: 8px;
  box-shadow: 0 6px 18px rgba(15, 23, 42, 0.14);
  z-index: 200;
}
.user-menu-dropdown[hidden] { display: none; }
.user-menu-dropdown form { margin: 0; }
.user-menu-item {
  display: block;
  width: 100%;
  box-sizing: border-box;
  text-align: left;
  padding: 8px 12px;
  background: none;
  border: none;
  font: inherit;
  font-size: 13px;
  color: var(--ink-2);
  cursor: pointer;
  border-radius: 6px;
  text-decoration: none;
}
.user-menu-item:hover { background: var(--surface-3); }

/* ===== Tables ===== */
.data-table {
  width: 100%;
  border-collapse: collapse;
  margin-top: 8px;
}
.data-table th, .data-table td {
  text-align: left;
  padding: 8px 10px;
  border-bottom: 1px solid var(--line);
  font-size: 13px;
}
.data-table th {
  background: var(--surface-2);
  font-weight: 600;
  color: var(--muted);
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.4px;
}
/* Keep column headers visible while scrolling long lists.  z-index
   stays below the agent-status banner (50) so a running-agent bar
   still slides over the header. */
.data-table thead th {
  position: sticky;
  top: 0;
  z-index: 5;
  box-shadow: 0 1px 0 var(--line);
}
.data-table .row-disabled { opacity: 0.55; }
.data-table tbody tr:hover { background: var(--surface-2); }

/* Compact order-detail header controls — Change state / Assignment forms
   moved into the top toolbar.  Inline so they sit beside the action
   buttons and wrap to a new line on narrow screens. */
.topbar-ctl {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin: 0;
}
.topbar-input {
  height: 32px;
  font-size: 13px;
  padding: 2px 8px;
  border: 1px solid var(--line-3);
  border-radius: 6px;
}
.topbar-comment {
  width: 140px;
  resize: none;
  vertical-align: middle;
  line-height: 1.4;
}

/* Sortable column headers (sort_th macro in _macros.html).
   The header cell is itself non-interactive; the <a> inside carries
   the click target so the underline / focus ring lands on the label.
   Active column shows arrow at full opacity; inactive shows the
   double-arrow at low opacity so the column is clearly clickable. */
.th-sort a {
  color: var(--muted);
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font: inherit;
  text-transform: inherit;
  letter-spacing: inherit;
}
.th-sort a:hover { color: var(--ink); text-decoration: none; }
.th-sort .th-arrow {
  font-size: 10px;
  opacity: 0.45;
  transition: opacity 0.12s;
}
.th-sort:hover .th-arrow { opacity: 0.85; }
.th-sort-active a       { color: var(--primary); }
.th-sort-active .th-arrow { opacity: 1; color: var(--primary); }

/* ===== Key/value layout (used on /me + order detail) ===== */
.kv {
  display: grid;
  grid-template-columns: 110px 1fr;
  gap: 6px 12px;
  margin: 10px 0 14px;
  font-size: 13px;
}
.kv dt { color: var(--muted); font-weight: 600; }
.kv dd { margin: 0; }

/* ===== Orders ===== */
.filter-bar {
  display: flex;
  gap: 10px;
  align-items: center;
  flex-wrap: wrap;
  margin-bottom: 14px;
  padding: 10px 12px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 6px;
}
.filter-input, .filter-select {
  padding: 7px 10px;
  border: 1px solid var(--line-3);
  border-radius: 5px;
  font-size: 13px;
}
.filter-input { min-width: 240px; }
.checkbox-inline {
  font-size: 13px; color: var(--muted);
  display: inline-flex; align-items: center; gap: 6px;
}
.po-link {
  font-weight: 700;
  color: var(--primary);
  text-decoration: none;
}
.po-link:hover { text-decoration: underline; }

/* State pills — same colour family as the desktop launcher so the
   two surfaces feel consistent. */
.state-pill {
  display: inline-block;
  padding: 2px 8px;
  font-size: 10.5px;
  font-weight: 700;
  border-radius: 4px;
  letter-spacing: 0.4px;
  text-transform: uppercase;
}
.state-NEW           { background: var(--surface-3); color: var(--ink-3); }
/* FILLED — orange to signal "data captured but waiting on operator
   to start the print job" (distinct from IN_PRODUCTION which is blue). */
.state-FILLED        { background: #ffedd5; color: #9a3412; }
.state-IN_PRODUCTION { background: #dbeafe; color: #1e40af; }
.state-VQC           { background: #fef3c7; color: #92400e; }
.state-READY         { background: #dbeafe; color: #1e40af; }
/* CHECKING — Xometry is reviewing the uploaded measurement report.
   Amber, distinct from READY (uploaded) so the operator can tell at
   a glance whether the order is still in their court or with Xometry. */
.state-CHECKING      { background: #fde68a; color: #78350f; }
/* APPROVED — Xometry signed off the VQC report.  Green, but
   distinguished from PRINTED (which is the shipping-docs printed
   step that comes immediately after). */
.state-APPROVED      { background: #d1fae5; color: #065f46; }
/* REJECTED — Xometry rejected the report; operator must re-QC. */
.state-REJECTED      { background: #fee2e2; color: #991b1b; }
/* RE_VQC — operator started fixing the rejection but hasn't re-zipped
   yet.  Slightly softer red than REJECTED so the two are visually
   distinguishable side by side. */
.state-RE_VQC        { background: #fecaca; color: #7f1d1d; }
/* Granular shipping lifecycle — mirrors Xometry portal labels.
   READY_TO_PICK_UP: order printed/labelled, sitting in our office waiting
   for carrier collection.  Light blue, distinct from READY (= report
   uploaded). */
.state-READY_TO_PICK_UP { background: #dbeafe; color: #1e40af; }
/* PICKED_UP: carrier has the package but courier system hasn't pushed
   a tracking-active event yet.  Indigo. */
.state-PICKED_UP     { background: #e0e7ff; color: #3730a3; }
/* IN_TRANSIT: tracking is live, package is between hubs.  Same indigo
   family as PICKED_UP but slightly darker. */
.state-IN_TRANSIT    { background: #c7d2fe; color: #312e81; }
/* DELIVERED: carrier confirmed delivery.  Green, paired with INVOICED
   so they read as "terminal good" states. */
.state-DELIVERED     { background: #bbf7d0; color: #14532d; }
/* PRINTED / SHIPPED — legacy aggregate states kept for old rows that
   pre-date the granular split.  Same colours as before. */
.state-PRINTED       { background: #bbf7d0; color: #14532d; }
.state-SHIPPED       { background: #e0e7ff; color: #3730a3; }
.state-INVOICED      { background: #dcfce7; color: #166534; }
.state-VOIDED        { background: #fee2e2; color: #991b1b; }

/* ===== Forms ===== */
.form-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}
.field textarea {
  width: 100%;
  padding: 9px 11px;
  border: 1px solid var(--line-3);
  border-radius: 6px;
  font-size: 13.5px;
  font-family: inherit;
  resize: vertical;
}
.field textarea:focus {
  outline: none; border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(37,99,235,0.15);
}
.field input[readonly] {
  background: var(--surface-3); color: var(--muted); cursor: not-allowed;
}

/* ===== Order detail page ===== */
.detail-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 28px;
  margin: 16px 0;
}
.detail-grid h2 {
  margin: 0 0 8px;
  font-size: 14px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--muted);
}
.notes-block {
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 14px 16px;
  margin: 10px 0 0;
}
.notes-block h2 {
  margin: 0 0 6px;
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--muted);
}

.action-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  margin: 10px 0;
}
.action-card {
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 14px 16px;
}
.action-card h3 {
  margin: 0 0 8px;
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--muted);
}
.form-stack > * { margin-bottom: 8px; }
.form-stack select, .form-stack input, .form-stack textarea {
  width: 100%;
  padding: 7px 10px;
  border: 1px solid var(--line-3);
  border-radius: 5px;
  font-size: 13px;
}

/* ===== Dashboard action tiles ===== */
.dash-actions {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 12px;
  margin-top: 12px;
}
.dash-tile {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 18px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 8px;
  text-decoration: none;
  color: var(--ink);
  transition: background 0.12s, transform 0.06s, border-color 0.12s;
}
.dash-tile:hover {
  background: var(--surface-3);
  border-color: #94a3b8;
  text-decoration: none;
  transform: translateY(-1px);
}
.dash-tile strong { font-size: 15px; }
.dash-tile-primary {
  background: linear-gradient(180deg, #3b82f6 0%, #2563eb 100%);
  color: #ffffff;
  border-color: #1d4ed8;
}
.dash-tile-primary:hover {
  background: linear-gradient(180deg, #2563eb 0%, #1d4ed8 100%);
  color: #ffffff;
}
.dash-tile-primary .muted { color: rgba(255,255,255,0.85); }

/* ── Pager ─────────────────────────────────────────────────────────
   Page navigator beneath paginated tables (orders, offers, VQC,
   audit).  Mirrors the .filter-bar look so it sits visually inside
   the same card with no extra chrome.
   Rendered by the pager() macro in _macros.html. */
.pager {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  padding: 12px 0 4px;
  font-size: 13px;
  color: #44506b;
}
.pager-info {
  margin-right: 12px;
  color: var(--ink-3);
}
.pager-num,
.pager-step {
  display: inline-block;
  min-width: 30px;
  text-align: center;
  padding: 5px 10px;
  border: 1px solid #d4d8e2;
  border-radius: 6px;
  background: var(--surface);
  color: var(--ink-2);
  text-decoration: none;
  line-height: 1.1;
}
.pager-num:hover,
.pager-step:hover {
  border-color: #2563eb;
  color: #2563eb;
}
.pager-current {
  background: #2563eb;
  color: #ffffff;
  border-color: #2563eb;
  font-weight: 600;
  cursor: default;
}
.pager-current:hover {
  background: #2563eb;
  color: #ffffff;
  border-color: #2563eb;
}
.pager-disabled {
  color: #9ca3af;
  background: var(--surface-3);
  border-color: var(--line-2);
  cursor: not-allowed;
}
.pager-disabled:hover {
  color: #9ca3af;
  border-color: var(--line-2);
}
.pager-ellipsis {
  padding: 5px 4px;
  color: #9ca3af;
}

/* ── VQC Quality Check (filesystem-driven photo view) ───────────────
   Each order is a card with a coloured left stripe (green / amber /
   red / grey) matching the launcher's per-order QC state.  Inside
   each card is a small table of parts with photo counts + action
   buttons (View / Add / Confirm / Skip). */
.vqc-check-card .agent-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}
.vqc-order-list { display: flex; flex-direction: column; gap: 12px; }
.vqc-order {
  display: flex;
  background: var(--surface);
  border: 1px solid var(--line-2);
  border-radius: 8px;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
  overflow: hidden;
}
.vqc-order-stripe {
  width: 6px;
  background: var(--vqc-stripe, #cbd5e1);
  flex: 0 0 6px;
}
.vqc-order-body {
  flex: 1 1 auto;
  padding: 12px 14px;
  min-width: 0;
}
.vqc-order-head {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.vqc-po { font-size: 14px; }
.vqc-meta { font-size: 12px; }
.vqc-parts-table {
  width: 100%;
  margin-top: 10px;
  border-collapse: collapse;
  font-size: 13px;
}
.vqc-parts-table thead th {
  background: var(--surface-2);
  color: var(--ink-3);
  font-weight: 600;
  text-align: left;
  padding: 6px 8px;
  border-bottom: 1px solid var(--line-2);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}
.vqc-parts-table tbody td {
  padding: 8px;
  border-bottom: 1px solid var(--line-2);
  vertical-align: middle;
}
.vqc-parts-table tbody tr:last-child td { border-bottom: 0; }
.vqc-part-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}

/* ── Modal (photo viewer + uploader) ──────────────────────────────── */
.vqc-modal {
  position: fixed;
  inset: 0;
  z-index: 9000;
  display: flex;
  align-items: center;
  justify-content: center;
}
.vqc-modal[hidden] { display: none; }
.vqc-modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(15, 23, 42, 0.55);
}
.vqc-modal-panel {
  position: relative;
  width: min(92vw, 1100px);
  max-height: 88vh;
  overflow: auto;
  background: var(--surface);
  border-radius: 10px;
  box-shadow: 0 20px 50px rgba(15, 23, 42, 0.35);
}
.vqc-modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 16px;
  border-bottom: 1px solid var(--line-2);
  background: var(--surface-2);
  border-radius: 10px 10px 0 0;
  position: sticky;
  top: 0;
  z-index: 1;
}
.vqc-photo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 12px;
  padding: 16px;
}
.vqc-thumb {
  margin: 0;
  border: 1px solid var(--line-2);
  border-radius: 6px;
  overflow: hidden;
  background: var(--surface-2);
  position: relative;
}
.vqc-thumb img {
  display: block;
  width: 100%;
  height: 140px;
  object-fit: cover;
}
.vqc-thumb figcaption {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 11px;
  color: var(--ink-3);
  padding: 4px 6px;
  background: var(--surface);
  word-break: break-all;
  gap: 6px;
}
.vqc-thumb-del {
  border: 0;
  background: transparent;
  color: #dc2626;
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  padding: 0 4px;
  flex: 0 0 auto;
}
.vqc-thumb-del:hover { color: #991b1b; }

/* ── Merged /vqc page — per-row photo expand ─────────────────────────
   Each main row carries its QC colour as --vqc-stripe via inline
   style.  We borrow that colour for the bottom border so the
   pipeline operator can spot QC state at-a-glance even before
   clicking expand. */
/* Enforce the percent widths in <colgroup> so the row never grows
   a phantom gap between columns under the default auto layout. */
.vqc-merged-table {
  table-layout: fixed;
}
.vqc-merged-table td,
.vqc-merged-table th {
  overflow: hidden;
  text-overflow: ellipsis;
}
.vqc-merged-table .vqc-row td {
  border-bottom: 2px solid var(--vqc-stripe, transparent);
}
.vqc-merged-table .vqc-row + .vqc-expand-row td {
  border-top: 0;
}
.vqc-photos-cell {
  display: flex;
  flex-direction: column;
  gap: 4px;
  align-items: flex-start;
  font-size: 12px;
}
.vqc-toggle {
  font-size: 12px !important;
  padding: 4px 8px !important;
}
.vqc-toggle.is-open {
  background: #e0e7ff !important;
  color: #1d4ed8 !important;
}
.vqc-expand-row[hidden] { display: none; }
.vqc-expand-cell {
  background: var(--surface-2);
  border-left: 4px solid var(--vqc-stripe, var(--line-3));
  padding: 12px 16px !important;
}
.vqc-expand-toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 8px;
}

/* Divider row that introduces the orphan-folder section inside the
   unified /vqc table.  Just a coloured strip — no borders — so it
   reads as a heading, not a data row. */
.vqc-divider-row td {
  background: var(--surface-3);
  color: var(--ink-3);
  font-weight: 600;
  font-size: 13px;
  padding: 10px 12px !important;
  border-top: 2px solid var(--line-3);
  border-bottom: 1px solid var(--line-2);
}
/* Orphan rows lean grey since most cells are em-dashes anyway. */
.vqc-row-orphan td:first-child { background: var(--surface-2); }

/* PO cell on /vqc — keep the PO link + compact 📷 toggle on the same
   line, internal-code subtitle wraps below.  The toggle uses tighter
   padding/font so it doesn't overpower the link it sits next to. */
.vqc-po-head {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.vqc-toggle-inline {
  font-size: 11px !important;
  padding: 2px 6px !important;
  min-height: 0;
  line-height: 1.3;
}

/* Part-name hover preview — small floating card with the reference
   image from /orders/<PO>/parts.json.  Same source the Orders page
   uses for its PO hover popover. */
.vqc-part-name {
  cursor: help;
  border-bottom: 1px dotted #94a3b8;
}
.vqc-part-name:hover,
.vqc-part-name:focus {
  color: #2563eb;
  outline: none;
}
.vqc-part-hover {
  position: absolute;
  z-index: 9000;
  width: 240px;
  background: var(--surface);
  border: 1px solid var(--line-3);
  border-radius: 8px;
  box-shadow: 0 14px 28px rgba(15, 23, 42, 0.18);
  pointer-events: none;
  font-size: 12px;
}
.vqc-part-hover[hidden] { display: none; }
.vqc-part-hover-head {
  padding: 8px 10px;
  border-bottom: 1px solid var(--line-2);
  font-weight: 600;
  font-size: 12px;
  color: var(--ink-2);
  background: var(--surface-2);
  border-radius: 8px 8px 0 0;
}
.vqc-part-hover-body { padding: 8px 10px; }
.vqc-part-hover-thumb {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--surface-3);
  border-radius: 6px;
  min-height: 180px;
  margin-bottom: 6px;
  overflow: hidden;
}
.vqc-part-hover-thumb img {
  max-width: 100%;
  max-height: 220px;
  object-fit: contain;
}

/* QC checklist surfaced when ✔ Confirm is clicked on a part row.
   The form sits in a row beneath the part, spanning the parts table
   width.  Visual cue: a coloured left strip + slightly lifted bg. */
.vqc-checklist-row[hidden] { display: none; }
.vqc-checklist-cell {
  background: #fffbeb;
  border-left: 4px solid #d97706;
  padding: 14px 16px !important;
}
.vqc-checklist-head {
  font-size: 13px;
  margin-bottom: 10px;
  color: var(--ink-2);
}
.vqc-checklist-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  background: var(--surface);
  border: 1px solid #fcd34d;
  border-radius: 6px;
  overflow: hidden;
}
.vqc-checklist-table thead th {
  background: #fef3c7;
  color: #78350f;
  font-weight: 600;
  text-align: left;
  padding: 6px 10px;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.4px;
}
.vqc-checklist-table thead th.center,
.vqc-checklist-table td.center { text-align: center; }
.vqc-checklist-table tbody td {
  padding: 6px 10px;
  border-top: 1px solid #fef3c7;
}
.vqc-radio {
  display: inline-block;
  cursor: pointer;
  padding: 2px 8px;
}
.vqc-radio input {
  vertical-align: middle;
  cursor: pointer;
}
.vqc-checklist-remarks {
  display: block;
  margin-top: 10px;
}
.vqc-checklist-remarks textarea {
  display: block;
  width: 100%;
  margin-top: 4px;
  padding: 6px 8px;
  font-family: inherit;
  font-size: 12px;
  border: 1px solid #fcd34d;
  border-radius: 6px;
  resize: vertical;
  min-height: 50px;
  background: var(--surface);
}
.vqc-checklist-actions {
  display: flex;
  gap: 8px;
  margin-top: 12px;
}

/* ── /vqc row-click expand ───────────────────────────────────────
   Whole .vqc-row-clickable acts as the disclosure button.  Chevron
   inside the PO cell flips ▾ → ▴ when the row is open (via the
   [data-vqc-open] flag set by the JS handler). */
.vqc-row-clickable {
  cursor: pointer;
}
.vqc-row-clickable:hover td:not(.vqc-photos-cell):not(.vqc-part-actions) {
  background: var(--surface-2);
}
.vqc-row-clickable:focus-visible {
  outline: 2px solid #2563eb;
  outline-offset: -2px;
}
/* Chevron sits inline with the muted subtitle line so the PO link
   on the top line stays single-height (matching Tech/Material/…
   cells which are single-line and vertically centred). */
/* Chevron sits on the same line as the PO link and mimics the
   .pill class used in the Photos/QC column on the same row (e.g.
   "? QC PENDING") — same height, same radius, same muted grey
   palette — so both pills read at the "same level" across the row. */
.vqc-row-chevron {
  display: inline-block;
  padding: 2px 10px;
  margin-left: 8px;
  font-size: 12px;
  font-weight: 700;
  line-height: 1.5;
  color: var(--ink-2);
  background: var(--surface-3);
  border-radius: 999px;
  vertical-align: middle;
  white-space: nowrap;
  transition: transform 0.15s ease, background 0.15s ease;
}
.vqc-row-clickable:hover .vqc-row-chevron {
  background: var(--line-3);
  color: var(--ink);
}
.vqc-row[data-vqc-open="1"] .vqc-row-chevron {
  background: #dbeafe;
  color: #1d4ed8;
  transform: rotate(180deg);
}

/* Inline part thumbnail in the expand row.  Mirrors the .parts-grid
   thumb style from the Orders detail page so users get the same
   visual cue. */
.vqc-part-cell {
  display: flex;
  gap: 10px;
  align-items: center;
}
.vqc-part-name-wrap {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.vqc-part-thumb {
  flex: 0 0 56px;
  width: 56px;
  height: 56px;
  border: 1px solid var(--line-2);
  border-radius: 6px;
  background: var(--surface-2);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.vqc-part-thumb img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.vqc-part-thumb-empty {
  color: #cbd5e1;
  font-size: 18px;
}

/* Top line of the /vqc PO cell — PO link + chevron pill side by
   side so the chevron lines up vertically with pills in other
   columns on the same row (e.g. "? QC PENDING" in Photos/QC). */
.vqc-po-line {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: nowrap;        /* never push the chevron to a new line */
  min-height: 22px;
}

/* ── Manual QC Checklist modal — launcher-style ────────────────────
   Dark navy header with brand + title, white body with checkbox
   rows, light footer with Cancel + Save QC.  Pure replication of
   the desktop launcher's QC popup so the operator sees the same
   layout whether they're on the tablet or the web. */
.vqc-qc-modal-panel {
  max-width: 720px;
  width: min(92vw, 720px);
}
.vqc-qc-modal-head {
  background: #0f172a;
  color: #e2e8f0;
  border-bottom: 0;
  border-radius: 10px 10px 0 0;
  padding: 14px 18px;
  display: flex;
  align-items: center;
  gap: 10px;
}
.vqc-qc-brand {
  color: #38bdf8;
  font-weight: 700;
  font-size: 14px;
}
.vqc-qc-sep {
  color: #1e3a5f;
  font-weight: 400;
}
.vqc-qc-modal-head strong {
  flex: 1;
  font-weight: 500;
  color: #cbd5e1;
  font-size: 14px;
}
.vqc-qc-close {
  background: transparent;
  border: 0;
  color: #94a3b8;
  font-size: 18px;
  cursor: pointer;
  padding: 0 6px;
  line-height: 1;
}
.vqc-qc-close:hover { color: #ffffff; }

.vqc-qc-context {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 12px 18px;
  border-bottom: 1px solid var(--line-2);
  font-size: 13px;
  background: var(--surface);
}
.vqc-qc-context .role-badge { background: #dbeafe; color: #1d4ed8; }

.vqc-qc-questions {
  list-style: none;
  margin: 0;
  padding: 8px 18px 16px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.vqc-qc-q-row {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 10px 8px;
  border-radius: 6px;
  cursor: pointer;
}
.vqc-qc-q-row:hover { background: var(--surface-2); }
.vqc-qc-q-row input[type=checkbox] {
  width: 18px;
  height: 18px;
  margin-top: 2px;
  flex-shrink: 0;
  cursor: pointer;
}
.vqc-qc-q-body { flex: 1; min-width: 0; }
.vqc-qc-q-label {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink-2);
  margin-bottom: 2px;
}
.vqc-qc-q-spec {
  color: #0f172a;
  background: var(--surface-3);
  padding: 1px 6px;
  border-radius: 4px;
  display: inline-block;
  margin: 2px 0;
}
.vqc-qc-q-hint {
  font-style: italic;
  margin-top: 2px;
}

.vqc-qc-remarks {
  display: block;
  padding: 0 18px 14px;
}
.vqc-qc-remarks textarea {
  display: block;
  width: 100%;
  margin-top: 4px;
  padding: 6px 8px;
  font-family: inherit;
  font-size: 12px;
  border: 1px solid var(--line-3);
  border-radius: 6px;
  resize: vertical;
  min-height: 50px;
  background: var(--surface);
}

.vqc-qc-modal-foot {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  padding: 12px 18px;
  background: var(--surface-2);
  border-top: 1px solid var(--line-2);
  border-radius: 0 0 10px 10px;
}

/* Merged VQC + Photos/QC column.  Stays a regular table-cell so its
   bottom border aligns with the neighbouring columns' (display:flex
   on a <td> turns it into a flex container and the cell stops
   stretching to the row height — that's what caused the staircase
   on the grey separator line).  Inline-flex layout for the two pills
   lives in the inner ``.vqc-qc-pills`` wrapper instead. */
.vqc-qc-cell {
  vertical-align: middle;
}
.vqc-qc-pills {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}
.vqc-photos-pill {
  margin-left: 0;
}

/* ── Batches Schedule (staged-delivery panel) ─────────────────────
   Renders on /orders/<po> when an order has scheduled sub-shipments.
   Mirrors the launcher logic: the order can't be marked shipped /
   invoiced until every non-cancelled batch is itself shipped. */
.batches-table { width: 100%; }
.batches-table tbody tr.batch-row-shipped td   { background: #f8fdf9; }
.batches-table tbody tr.batch-row-cancelled td { background: #fbf3f3; color: #94a3b8; }
.batch-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.batch-new-toggle {
  margin-top: 14px;
  padding: 10px 14px;
  border: 1px dashed var(--line-3);
  border-radius: 6px;
  background: var(--surface-2);
}
.batch-new-toggle summary {
  cursor: pointer;
  font-weight: 600;
  color: #1d4ed8;
}
.batch-new-form {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 10px;
  align-items: flex-end;
}
.batch-new-form .field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 130px;
}
.batch-new-form .field input {
  padding: 5px 8px;
  border: 1px solid var(--line-3);
  border-radius: 5px;
  font-size: 13px;
}

/* "5 / 8 batches" progress badge — shown next to the PO state pill
   in the Orders list when the order is batched. */
.batches-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  font-size: 11px;
  font-weight: 700;
  border-radius: 999px;
  background: #e0e7ff;
  color: #3730a3;
  margin-left: 6px;
}
.batches-badge-complete {
  background: #dcfce7;
  color: #166534;
}

/* Batches Schedule strip — inline on /vqc when a batched order is
   expanded.  Compact look so it sits naturally above the parts
   table without dominating the expand row. */
.vqc-batches {
  background: var(--surface);
  border: 1px solid #e0e7ff;
  border-left: 4px solid #6366f1;
  border-radius: 6px;
  padding: 10px 12px;
  margin-bottom: 12px;
}
.vqc-batches-head {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 8px;
  flex-wrap: wrap;
}
.vqc-batches-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.vqc-batches-table thead th {
  background: #eef2ff;
  color: #4338ca;
  font-weight: 600;
  text-align: left;
  padding: 5px 8px;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.4px;
}
.vqc-batches-table tbody td {
  padding: 6px 8px;
  border-top: 1px solid #eef2ff;
  vertical-align: middle;
}
.vqc-batches-row-shipped td   { background: #f8fdf9; }
.vqc-batches-row-cancelled td { background: #fbf3f3; color: #94a3b8; }

/* Inline batch-edit row revealed by the ✎ Edit button.  Forms a
   short 3-field strip (carrier, tracking, planned/actual dates,
   qty, value) directly below the batch row.  Filling carrier +
   tracking + actual_ship_date auto-flips state to SHIPPED on
   save — same trigger as the order-level orders_ship endpoint. */
.batch-edit-row[hidden] { display: none; }
.batch-edit-cell {
  background: #fef9c3;
  border-left: 4px solid #f59e0b;
  padding: 12px 14px !important;
}
.batch-edit-form {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: flex-end;
}
.batch-edit-form .field {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 130px;
}
.batch-edit-form .field input {
  padding: 5px 8px;
  border: 1px solid var(--line-3);
  border-radius: 5px;
  font-size: 13px;
}
.batch-edit-hint {
  margin: 0;
  flex: 1 0 100%;
  font-size: 11px;
}
.batch-edit-toggle.is-open {
  background: #fde68a !important;
  color: #78350f !important;
}

/* Shipping & Financial card grid on the order detail page.
   Mirrors the launcher's Shipping panel — each agent gets its own
   small card with a one-liner explanation + a primary action +
   a log link.  Cards auto-flow on a CSS grid; min-card-width 280
   px so they wrap cleanly on a 1280-px container. */
.shipping-financial-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 12px;
  margin-bottom: 14px;
}
.sf-card {
  border: 1px solid #e0e7ff;
  border-radius: 8px;
  padding: 12px;
  background: var(--surface);
}
.sf-card h3 {
  font-size: 14px;
  color: var(--ink-2);
  font-weight: 700;
}
.sf-card-stub {
  background: var(--surface-2);
  border-style: dashed;
  border-color: var(--line-3);
}
.sf-form {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: flex-end;
  margin-top: 8px;
}
.sf-form .field {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 70px;
  flex: 1 0 auto;
}
.sf-form .field input {
  padding: 5px 8px;
  border: 1px solid var(--line-3);
  border-radius: 5px;
  font-size: 13px;
}

/* ── /shipping tab — dedicated Shipping & Invoicing page ──────────
   Mirrors the launcher's Shipping popup: per-row Auto/Invoice/EU
   Ship actions + a top-of-page bulk Shipping → Excel.  Per-row
   inline edit reveals the carrier+tracking+ship_date form via the
   .ship-edit-toggle button. */
.shipping-toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

/* Shipping + Invoicing tables share one stylesheet so /shipping and
   /invoicing look identical.  Match the Virtual QC layout pattern:
   fixed table layout + every body cell vertically centres + a
   single uniform bottom border per row.  Without these, a tall PO
   cell + wrapped action buttons make the row look ragged at the
   bottom (the user's "marker red line must be parallel" report). */
.shipping-table {
  table-layout: fixed;
}
.shipping-table tbody td,
.shipping-table thead th {
  vertical-align: middle !important;
}
/* One uniform bottom border per row — overrides .data-table's
   per-cell border that can render unevenly when a cell adds its
   own border (e.g. ship-edit-cell has a left-stripe border). */
.shipping-table tbody td {
  border-bottom: 1px solid var(--line);
}

/* Inner wrapper inside the actions <td> — keeps the TD itself a
   standard table cell (border-bottom renders cleanly) while still
   giving us a flex row for the button group.  When ``display:flex``
   was directly on the <td>, the cell rendered differently from the
   other plain TDs and the bottom border appeared discontinuous
   across the row in some browsers. */
.shipping-table .ship-actions {
  white-space: nowrap;
}
.shipping-table .ship-actions-inner {
  display: flex;
  flex-wrap: nowrap;
  gap: 4px;
  align-items: center;
  justify-content: flex-start;
}
/* Per-row action buttons — use the standard ``.btn-sm`` size from
   line ~375 (same as the VQC tab buttons).  Labels are shortened
   in the templates ("Fill", "Manual", "Ship") so 4 buttons at full
   size still fit on one line in the 340px actions column. */
.shipping-table .ship-actions .btn-sm,
.shipping-table .ship-actions-inner .btn-sm {
  white-space: nowrap;
  flex-shrink: 0;
}
/* PO cell layout — keep all the stacked metadata (PO link, internal
   code, batches badge, VQC badge, customer) tight so the row stays
   roughly the same height as a single-line action cell.  Without
   tightening, the PO cell pushes the row to 5-6 lines and the
   single-line cells leave wide empty space at the bottom. */
.shipping-table .po-with-thumb { align-items: center; }
.shipping-table .po-text > .muted.small { line-height: 1.35; }
.ship-edit-row[hidden] { display: none; }
.ship-edit-cell {
  background: #eff6ff;
  border-left: 4px solid #3b82f6;
  padding: 12px 14px !important;
}
.ship-edit-form {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: flex-end;
}
.ship-edit-form .field {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 160px;
}
.ship-edit-form .field input {
  padding: 5px 8px;
  border: 1px solid var(--line-3);
  border-radius: 5px;
  font-size: 13px;
}
.ship-edit-hint {
  margin: 0;
  flex: 1 0 100%;
  font-size: 11px;
}
.ship-edit-toggle.is-open {
  background: #dbeafe !important;
  color: #1d4ed8 !important;
}

/* Notice on /orders/<po> pointing operators to the Shipping tab —
   replaces the old inline Shipping & Financial grid. */
.ship-redirect-card {
  background: #eff6ff;
  border: 1px solid #bfdbfe;
  border-radius: 8px;
  padding: 12px 14px;
  font-size: 13px;
  color: var(--ink-2);
}
.ship-redirect-card a {
  color: #1d4ed8;
  font-weight: 600;
  text-decoration: underline;
}

/* ── Fill Shipping Data modal ─────────────────────────────────────
   Per-row dialog opened from /shipping.  Inherits .vqc-modal /
   .vqc-modal-panel / .vqc-modal-head from the VQC photo modal so
   the look stays consistent.  Only the inner layout differs. */
.ship-fill-panel { max-width: 720px; width: min(94vw, 720px); }
.ship-fill-head  {
  background: #1d4ed8;
  color: #f8fafc;
  border-radius: 10px 10px 0 0;
}
.ship-fill-head strong { color: #ffffff; font-weight: 700; flex: 1; }
.ship-fill-context {
  margin: 0;
  padding: 12px 18px;
  border-bottom: 1px solid var(--line-2);
  background: var(--surface);
}
.ship-fill-form > * {
  padding-left: 18px;
  padding-right: 18px;
}
.ship-fill-row {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  padding-top: 10px;
}
.ship-fill-row .field {
  flex: 1 1 140px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.ship-fill-row .field input,
.ship-fill-row .field select {
  padding: 6px 10px;
  border: 1px solid var(--line-3);
  border-radius: 5px;
  font-size: 14px;
}

/* Preset chips — same look the launcher uses (blue pill, click to
   fill L/W/H). */
.ship-fill-presets {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  padding-top: 12px;
}
.ship-preset {
  background: #dbeafe;
  color: #1e40af;
  border: 0;
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.12s ease;
}
.ship-preset:hover { background: #bfdbfe; }

.ship-fill-photos {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding-top: 12px;
  padding-bottom: 14px;
}
.ship-fill-photos input[type=file] {
  padding: 6px 0;
  font-size: 13px;
}

.ship-fill-foot {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  padding: 12px 18px;
  border-top: 1px solid var(--line-2);
  background: var(--surface-2);
  border-radius: 0 0 10px 10px;
}

/* Selected packing-preset chip — same blue as the primary button so
   the operator sees which preset is staged for auto-attach. */
.ship-preset.is-selected {
  background: #1d4ed8;
  color: #ffffff;
}
.ship-preset.is-selected:hover { background: #1e40af; }

.ship-fill-packing-info {
  margin: 6px 0 0;
  font-size: 12px;
  line-height: 1.45;
  color: var(--ink-2);
}
.ship-fill-packing-info code {
  background: #eef2ff;
  color: #4338ca;
  padding: 1px 5px;
  border-radius: 4px;
  font-size: 11px;
}

/* Thumbnail grid inside the Fill Shipping Data modal — shows the
   actual packing photos that will be uploaded for the selected box
   preset.  Compact thumbs so a 5-photo set fits in one row. */
.ship-fill-packing-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
  gap: 8px;
  padding: 12px 18px 4px;
}
.ship-fill-packing-grid:empty { padding: 0; }
.ship-fill-thumb {
  margin: 0;
  border: 1px solid var(--line-2);
  border-radius: 6px;
  overflow: hidden;
  background: var(--surface-2);
}
.ship-fill-thumb img {
  display: block;
  width: 100%;
  height: 90px;
  object-fit: cover;
}
.ship-fill-thumb figcaption {
  font-size: 10px;
  color: var(--ink-3);
  padding: 3px 6px;
  background: var(--surface);
  border-top: 1px solid var(--line-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Info row inside the modal — packing info text on the left,
   🎲 Reshuffle button on the right.  Reshuffle stays hidden until
   the operator picks a preset that has 2+ sets available. */
.ship-fill-packing-meta {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
  padding: 6px 18px 0;
  flex-wrap: wrap;
}
.ship-fill-packing-meta .ship-fill-packing-info {
  flex: 1 1 auto;
  margin: 0;
  padding: 0;
}
.ship-fill-packing-meta button[hidden] { display: none; }

/* Manual ↗ button on /shipping — visually a button, semantically
   an <a> that opens the order on Xometry in a new tab.  Falls back
   to a disabled-looking <span> when the order has no derivable
   partner-portal URL (manually-entered orders). */
.ship-manual-link {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  text-decoration: none !important;   /* override .btn-ghost a-style */
  color: #0f766e !important;
  background: #ccfbf1 !important;
  font-weight: 600;
}
.ship-manual-link:hover {
  background: #99f6e4 !important;
  color: #0f766e !important;
}
.ship-manual-link.is-disabled {
  background: var(--surface-3) !important;
  color: #94a3b8 !important;
  cursor: not-allowed;
  pointer-events: none;
}

/* ── Manual QC Checklist modal — sections (reference, photos,
   checklist) added on top of the original checklist popup so the
   operator can do the full launcher VQC flow from one place. */
.vqc-qc-section {
  padding: 12px 18px 14px;
  border-bottom: 1px solid var(--line-2);
}
.vqc-qc-section:last-of-type { border-bottom: 0; }
.vqc-qc-section-head {
  margin: 0 0 8px;
  font-size: 13px;
  font-weight: 700;
  color: var(--ink-2);
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

/* Reference image panel — single large(ish) thumb, same source the
   inline parts-grid uses. */
.vqc-qc-ref {
  display: flex;
  gap: 14px;
  align-items: flex-start;
  flex-wrap: wrap;
}
.vqc-qc-ref img {
  width: 220px;
  height: 220px;
  object-fit: contain;
  background: var(--surface-2);
  border: 1px solid var(--line-2);
  border-radius: 6px;
}
.vqc-qc-ref a { display: block; }
.vqc-qc-ref .muted { flex: 1 1 200px; }

/* Photo strip — horizontal scroll of uploaded photos of the
   physical part.  Same square-cropped style the VQC photo modal
   uses for consistency. */
.vqc-qc-photo-strip {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
  gap: 8px;
  margin-bottom: 10px;
}
.vqc-qc-photo-strip:empty { display: none; }
.vqc-qc-thumb {
  margin: 0;
  border: 1px solid var(--line-2);
  border-radius: 6px;
  overflow: hidden;
  background: var(--surface-2);
}
.vqc-qc-thumb img {
  display: block;
  width: 100%;
  height: 90px;
  object-fit: cover;
}
.vqc-qc-thumb figcaption {
  font-size: 10px;
  color: var(--ink-3);
  padding: 3px 5px;
  border-top: 1px solid var(--line-2);
  background: var(--surface);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.vqc-qc-photo-tools {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.vqc-qc-upload-label {
  cursor: pointer;
}

/* Webcam preview block — appears below the tools when the operator
   clicks 📸 Use webcam, hides when they Stop.  16:9-ish aspect so the
   modal doesn't grow uncontrollably on phones. */
.vqc-qc-cam {
  margin-top: 10px;
  padding: 10px;
  background: #0f172a;
  border-radius: 8px;
}
.vqc-qc-cam[hidden] { display: none; }
.vqc-qc-cam video {
  display: block;
  width: 100%;
  max-height: 360px;
  background: #000;
  border-radius: 4px;
}
.vqc-qc-cam-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 8px;
  flex-wrap: wrap;
  color: #e2e8f0;
}
.vqc-qc-cam-actions .muted { color: #94a3b8; }

/* Inline first-part thumbnail next to the PO link in /orders, /vqc,
   /shipping tables.  44 px square so the row stays compact; lazy-
   loaded so a 50-row page doesn't fetch 50 images on first paint. */
.po-with-thumb {
  display: flex;
  align-items: flex-start;
  gap: 10px;
}
.po-text { flex: 1 1 auto; min-width: 0; }
.po-thumb {
  flex: 0 0 44px;
  width: 44px;
  height: 44px;
  border-radius: 6px;
  border: 1px solid var(--line-2);
  background: var(--surface-2);
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.po-thumb img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.po-thumb-empty {
  color: #cbd5e1;
  font-size: 18px;
  cursor: default;
}

/* ════════════════════════════════════════════════════════════════════
   Production Overview dashboard
   Follows Stephen Few / Deloitte / McKinsey dashboard guidelines:
   – Bullet cards over gauges
   – Sparklines beside headline numbers
   – Horizontal bars for mix breakdowns
   – Stacked-bar funnel for the WIP queue
   – Capacity load as a discrete day-by-day mini bar chart
   ════════════════════════════════════════════════════════════════════ */

.dash-greeting {
  background: linear-gradient(135deg, #F8FAFC 0%, #EFF6FF 100%);
  border-left: 4px solid #1e40af;
}

/* ── KPI row ──────────────────────────────────────────────────────── */
.dash-kpi-row {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 14px;
  margin-bottom: 14px;
}
.dash-kpi-row-3 {
  grid-template-columns: repeat(3, 1fr);
}
@media (max-width: 1100px) {
  .dash-kpi-row,
  .dash-kpi-row-3 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 600px) {
  .dash-kpi-row,
  .dash-kpi-row-3 { grid-template-columns: 1fr; }
}
.dash-kpi {
  background: var(--surface);
  border: 1px solid var(--line-2);
  border-radius: 8px;
  padding: 14px 16px;
  border-top: 4px solid #94A3B8;
  box-shadow: 0 1px 2px rgba(0,0,0,0.04);
  transition: transform .15s ease, box-shadow .15s ease;
}
.dash-kpi:hover {
  transform: translateY(-1px);
  box-shadow: 0 4px 8px rgba(0,0,0,0.06);
}
.dash-kpi-blue    { border-top-color: #1e40af; }
.dash-kpi-red     { border-top-color: #DC2626; background: #FEF2F2; }
.dash-kpi-green   { border-top-color: #16A34A; }
.dash-kpi-emerald { border-top-color: #047857; }
.dash-kpi-amber   { border-top-color: #D97706; background: #FFFBEB; }
.dash-kpi-teal    { border-top-color: #0E7490; }
.dash-kpi-label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--ink-3);
  font-weight: 600;
}
.dash-kpi-value {
  font-size: 30px;
  font-weight: 700;
  color: var(--ink);
  line-height: 1.1;
  margin: 4px 0;
}
.dash-kpi-sub {
  font-size: 12px;
  color: var(--ink-3);
  margin-bottom: 8px;
}
.dash-kpi-spark {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding-top: 6px;
  border-top: 1px solid var(--line-2);
}

/* ── WIP funnel ──────────────────────────────────────────────────── */
.dash-funnel {
  display: grid;
  grid-template-columns: repeat(10, 1fr);
  gap: 6px;
}
@media (max-width: 900px) {
  .dash-funnel { grid-template-columns: repeat(5, 1fr); }
}
@media (max-width: 500px) {
  .dash-funnel { grid-template-columns: repeat(2, 1fr); }
}
.dash-funnel-stage {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  text-decoration: none;
  padding: 8px 6px;
  border-radius: 6px;
  /* The stage colours arrive as CSS custom properties from the
     template (--stage-bg pastel, --stage-fg saturated) so the dark
     theme below can re-derive tile/border/count colours with
     color-mix() instead of fighting inline styles. */
  border: 1px solid var(--stage-fg, var(--line-2));
  background: var(--stage-bg, var(--surface-2));
  transition: filter .15s ease, transform .15s ease;
  position: relative;          /* anchor for ::after arrow + step badge */
}
.dash-funnel-stage-fill  { background: var(--stage-fg, var(--line-3)); }
.dash-funnel-stage-count { color: var(--stage-fg, var(--ink)); }
.dash-funnel-stage:hover {
  filter: brightness(0.96);
  transform: translateY(-1px);
}
/* Step-number badge top-left — makes the 1→2→3 chronology
   readable at a glance. */
.dash-funnel-stage-step {
  position: absolute;
  top: 4px;
  left: 4px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--surface-4);
  color: var(--ink-3);
  font-size: 10px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
}
/* Icon row above the label — large emoji centred so each stage
   has a recognisable picture without needing to read the text.
   The same icon is also painted as a faded watermark inside the
   colour block below (see .dash-funnel-stage-watermark) so the
   coloured rectangle isn't just an empty pane. */
.dash-funnel-stage-icon {
  font-size: 28px;
  line-height: 1.1;
  text-align: center;
  margin: 8px 0 4px;
  user-select: none;
}
/* Pictogram inside the coloured bar — same emoji as the icon row,
   blown up, semi-transparent, centred.  Sits BELOW the fill bar
   (z-index 0 vs 1) so the magnitude indicator still reads on top.
   The bar already has ``overflow:hidden`` so an over-sized icon
   gets cropped cleanly. */
.dash-funnel-stage-watermark {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 32px;
  line-height: 1;
  opacity: 0.85;
  pointer-events: none;
  user-select: none;
  z-index: 0;
  filter: saturate(1.5) contrast(1.15) drop-shadow(0 1px 1px rgba(15,23,42,0.18));
}
/* Right-pointing arrow connector between tiles.  Sits on the right
   edge of each non-last tile, vertically centred on the bar.  CSS
   ``content: ""`` triangle keeps the markup clean — no DOM nodes.
   Hidden on the narrower responsive grids where tiles wrap. */
.dash-funnel-stage-with-arrow::after {
  content: "▸";
  position: absolute;
  right: -7px;
  top: 50%;
  transform: translateY(-50%);
  color: #CBD5E1;
  font-size: 14px;
  z-index: 1;
  pointer-events: none;
}
@media (max-width: 900px) {
  .dash-funnel-stage-with-arrow::after { display: none; }
}
.dash-funnel-stage-label {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.3px;
  color: var(--ink-3);
  font-weight: 600;
  text-align: center;
  min-height: 24px;
}
.dash-funnel-stage-bar {
  height: 60px;
  border-radius: 4px;
  margin: 4px 0;
  position: relative;
  overflow: hidden;
}
.dash-funnel-stage-fill {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  border-radius: 0 0 4px 4px;
  transition: height .3s ease;
  z-index: 1;            /* sit above the pictogram watermark */
  opacity: 0.85;          /* slight transparency so the icon stays visible behind the fill */
}
.dash-funnel-stage-count {
  text-align: center;
  font-size: 18px;
  font-weight: 700;
}

/* ── Two- / three-column grids ────────────────────────────────────── */
.dash-grid-2col {
  display: grid;
  grid-template-columns: 2fr 1fr;
  gap: 14px;
  margin-bottom: 14px;
}
.dash-grid-3col {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
  margin-bottom: 14px;
}
@media (max-width: 1100px) {
  .dash-grid-2col, .dash-grid-3col { grid-template-columns: 1fr; }
}

/* ── Watch list cards (leading indicators) ────────────────────────── */
.dash-watch-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
}
.dash-watch-card {
  display: flex;
  flex-direction: column;
  text-decoration: none;
  background: var(--surface-2);
  border: 1px solid var(--line-2);
  border-radius: 6px;
  padding: 10px 12px;
  color: #0F172A;
  transition: background .15s ease, transform .15s ease;
}
.dash-watch-card:hover {
  background: #EFF6FF;
  transform: translateY(-1px);
}
.dash-watch-bad   { background: #FEF2F2; border-color: #FECACA; }
.dash-watch-bad:hover  { background: #FEE2E2; }
.dash-watch-warn  { background: #FFFBEB; border-color: #FDE68A; }
.dash-watch-warn:hover { background: #FEF3C7; }
.dash-watch-info  { background: #EFF6FF; border-color: #BFDBFE; cursor: default; }
.dash-watch-value {
  font-size: 22px;
  font-weight: 700;
  color: var(--ink);
  line-height: 1.1;
}
.dash-watch-label {
  font-size: 11px;
  color: var(--ink-3);
  font-weight: 600;
  margin-top: 2px;
}
.dash-watch-hint {
  font-size: 10px;
  color: #94A3B8;
  margin-top: 2px;
}

/* ── Ship-date load (capacity strip) ──────────────────────────────── */
.dash-capacity {
  display: grid;
  grid-template-columns: repeat(15, 1fr);
  gap: 4px;
  align-items: end;
}
.dash-cap-day {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 6px 2px;
  border-radius: 4px;
  background: var(--surface-2);
}
.dash-cap-day-today {
  background: #EFF6FF;
  border: 1px solid #BFDBFE;
}
.dash-cap-bar-track {
  width: 100%;
  height: 60px;
  background: transparent;
  display: flex;
  align-items: flex-end;
  border-bottom: 1px solid var(--line-2);
}
.dash-cap-bar-fill {
  width: 100%;
  border-radius: 2px 2px 0 0;
  transition: height .3s ease;
}
.dash-cap-day-count {
  font-size: 11px;
  font-weight: 700;
  color: #0F172A;
  margin-top: 4px;
}
.dash-cap-day-label {
  font-size: 9px;
  color: #94A3B8;
  text-transform: uppercase;
  letter-spacing: 0.3px;
  margin-top: 2px;
}
.dash-cap-day-date {
  font-size: 10px;
  color: var(--ink-3);
  font-weight: 600;
}

/* ── Quick actions row at the bottom ─────────────────────────────── */
.dash-quicklinks .dash-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

/* ===== Theme toggle (topbar) ===== */
.theme-toggle {
  background: transparent;
  border: 1px solid var(--line-3);
  border-radius: 8px;
  padding: 4px 9px;
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  color: var(--ink);
}
.theme-toggle:hover { background: var(--surface-3); }

/* ===== Dark theme — dashboard cards =====
   The dashboard's semantic cards keep their colour IDENTITY in dark
   mode but flip to dark-tinted surfaces: color-mix() re-derives each
   tint from the same stage/accent colour the light theme uses (the
   plain-colour line above each color-mix() is the fallback for
   browsers without color-mix support). */
html[data-theme="dark"] .dash-greeting {
  background: linear-gradient(135deg, #16213a 0%, #1b2a4a 100%);
  border-left-color: var(--primary);
}
html[data-theme="dark"] .dash-kpi-red {
  background: #2d1b22;
  background: color-mix(in srgb, #DC2626 14%, var(--card));
}
html[data-theme="dark"] .dash-kpi-amber {
  background: #2e2718;
  background: color-mix(in srgb, #D97706 14%, var(--card));
}
html[data-theme="dark"] .dash-funnel-stage {
  background: var(--surface-2);
  background: color-mix(in srgb, var(--stage-fg, #64748b) 16%, var(--card));
  border-color: var(--line-3);
  border-color: color-mix(in srgb, var(--stage-fg, #64748b) 45%, var(--card));
}
html[data-theme="dark"] .dash-funnel-stage-count {
  color: var(--ink);
  color: color-mix(in srgb, var(--stage-fg, #94a3b8) 55%, white);
}
html[data-theme="dark"] .dash-funnel-stage-fill {
  background: color-mix(in srgb, var(--stage-fg, #64748b) 70%, white);
}
/* Light theme dims tiles on hover; dark theme brightens instead. */
html[data-theme="dark"] .dash-funnel-stage:hover { filter: brightness(1.18); }
/* Sparkline strokes are dark blues/greens tuned for white cards —
   lift them on dark cards without touching the inline SVG colours. */
html[data-theme="dark"] .dash-kpi-spark svg { filter: brightness(1.7); }

/* ===== Dark theme — tinted panels & edit cells =====
   Large pastel surfaces (amber QC checklist, yellow batch-edit strip,
   blue ship-edit strip, indigo batches table, green all-clear hero)
   are light tints with dark accent text — unreadable when the rest of
   the page flips dark.  Re-derive each tint from its accent colour
   over the dark card, same recipe as the dashboard block above.
   Small semantic pills (state badges etc.) are left alone — they
   carry their own bg+ink contrast in both themes. */

/* Amber QC checklist (vqc confirm flow) */
html[data-theme="dark"] .vqc-checklist-cell {
  background: #2e2718;
  background: color-mix(in srgb, #d97706 14%, var(--card));
}
html[data-theme="dark"] .vqc-checklist-table {
  border-color: color-mix(in srgb, #d97706 40%, var(--card));
}
html[data-theme="dark"] .vqc-checklist-table thead th {
  background: color-mix(in srgb, #d97706 24%, var(--card));
  color: #fcd34d;
}
html[data-theme="dark"] .vqc-checklist-table tbody td {
  border-top-color: color-mix(in srgb, #d97706 24%, var(--card));
}
html[data-theme="dark"] .vqc-checklist-remarks textarea {
  border-color: color-mix(in srgb, #d97706 40%, var(--card));
}

/* Yellow batch-edit strip + toggle */
html[data-theme="dark"] .batch-edit-cell {
  background: #2c2a16;
  background: color-mix(in srgb, #eab308 12%, var(--card));
}
html[data-theme="dark"] .batch-edit-toggle.is-open {
  background: color-mix(in srgb, #eab308 28%, var(--card)) !important;
  color: #fde68a !important;
}

/* Blue ship-edit strip / redirect card / toggles */
html[data-theme="dark"] .ship-edit-cell,
html[data-theme="dark"] .ship-redirect-card {
  background: #1b2742;
  background: color-mix(in srgb, #3b82f6 14%, var(--card));
  border-color: color-mix(in srgb, #3b82f6 40%, var(--card));
}
html[data-theme="dark"] .ship-redirect-card a { color: var(--primary); }
html[data-theme="dark"] .ship-edit-toggle.is-open,
html[data-theme="dark"] .vqc-toggle.is-open {
  background: color-mix(in srgb, #3b82f6 26%, var(--card)) !important;
  color: var(--primary) !important;
}
html[data-theme="dark"] .vqc-row[data-vqc-open="1"] .vqc-row-chevron {
  background: color-mix(in srgb, #3b82f6 26%, var(--card));
  color: var(--primary);
}
html[data-theme="dark"] .ship-preset {
  background: color-mix(in srgb, #3b82f6 24%, var(--card));
  color: var(--primary);
}
html[data-theme="dark"] .ship-preset:hover {
  background: color-mix(in srgb, #3b82f6 36%, var(--card));
}
html[data-theme="dark"] .ship-preset.is-selected {
  background: #1d4ed8;
  color: #ffffff;
}
html[data-theme="dark"] .ship-fill-packing-info code {
  background: var(--surface-3);
  color: var(--primary);
}

/* Indigo batches strip (vqc expand + order detail) */
html[data-theme="dark"] .vqc-batches {
  border-color: color-mix(in srgb, #6366f1 35%, var(--card));
}
html[data-theme="dark"] .vqc-batches-table thead th {
  background: color-mix(in srgb, #6366f1 18%, var(--card));
  color: #a5b4fc;
}
html[data-theme="dark"] .vqc-batches-table tbody td {
  border-top-color: var(--line-2);
}
html[data-theme="dark"] .vqc-batches-row-shipped td,
html[data-theme="dark"] .batches-table tbody tr.batch-row-shipped td {
  background: color-mix(in srgb, #16a34a 9%, var(--card));
}
html[data-theme="dark"] .vqc-batches-row-cancelled td,
html[data-theme="dark"] .batches-table tbody tr.batch-row-cancelled td {
  background: color-mix(in srgb, #dc2626 8%, var(--card));
  color: var(--muted);
}
html[data-theme="dark"] .batches-badge {
  background: color-mix(in srgb, #6366f1 26%, var(--card));
  color: #a5b4fc;
}
html[data-theme="dark"] .batches-badge-complete {
  background: color-mix(in srgb, #16a34a 22%, var(--card));
  color: #86efac;
}
html[data-theme="dark"] .batch-new-toggle summary { color: var(--primary); }

/* Green "all clear" hero */
html[data-theme="dark"] .report-all-clear {
  background: #16291d;
  background: color-mix(in srgb, #16a34a 12%, var(--card));
  border-color: color-mix(in srgb, #16a34a 40%, var(--card));
}
html[data-theme="dark"] .report-all-clear h3 { color: #86efac; }
html[data-theme="dark"] .report-all-clear p  { color: #bbf7d0; }

/* Misc light-tint hovers */
html[data-theme="dark"] .folder-crumbs a:hover { background: var(--surface-3); }
