/* Cabinet MES shell styles.
 *
 * Loaded after Bootstrap. Most of the visual identity is applied by retuning
 * Bootstrap's own custom properties, so existing markup keeps working without
 * template edits. Shop-floor terminals are iPads, so a pointer-aware touch
 * layer near the bottom of this file enlarges targets and prevents iOS from
 * zooming the page when an operator focuses a field.
 */

/* ---------------------------------------------------------------- tokens -- */

:root {
    /* Neutrals carry a slight cool bias so the shop UI reads as instrument
       panel rather than office document. */
    --erp-bg: #eef1f5;
    --erp-bg-sunken: #e4e8ee;
    --erp-card: #ffffff;
    --erp-ink: #151b23;
    --erp-ink-soft: #384250;
    --erp-muted: #5f6b7a;
    --erp-line: #dbe1e9;
    --erp-line-strong: #c3ccd8;

    --erp-blue: #1668dc;
    --erp-blue-ink: #0f4ea8;
    --erp-blue-soft: #e8f0fd;
    --erp-green: #0f8a5f;
    --erp-green-soft: #e3f5ed;
    --erp-red: #c8362a;
    --erp-red-soft: #fdeae8;
    --erp-amber: #a86b08;
    --erp-amber-soft: #fdf2dc;
    --erp-purple: #6d43c8;
    --erp-purple-soft: #f0eafc;
    --erp-purple-ink: #6d43c8;
    --erp-purple-line: #cbb2ed;

    /* Semantic slots for surfaces that used to carry literal colours. Every
       one of them is re-pointed by the industrial theme further down, so a
       literal here would be a hole the theme cannot reach. */
    --erp-on-accent: #ffffff;
    --erp-red-ink: #a92e23;
    --erp-red-line: #e9a9a3;
    --erp-green-ink: #0b6f4c;
    --erp-indigo: #3b3fc4;
    --erp-indigo-soft: #e9ebfd;
    --erp-slate: #55606c;
    --erp-slate-line: #47515c;
    --erp-slate-hover: #4a545f;
    --erp-track-dim: rgba(0, 0, 0, .16);
    --erp-hover: #f5f8fc;
    /* The dark theme redefines this; the shop theme needs it too now that a
       CNC program name is rendered in both. */
    --erp-font-mono: "Cascadia Mono", "JetBrains Mono", Consolas,
        "SF Mono", ui-monospace, "Liberation Mono", monospace;

    /* Top bar. Dark in both themes, but not the same dark. */
    --erp-nav-bg: linear-gradient(180deg, #1d2634 0%, #171e29 100%);
    --erp-nav-line: #0d1219;
    --erp-nav-shadow: 0 1px 3px rgba(0, 0, 0, .18);
    --erp-nav-ink: rgba(255, 255, 255, .78);
    --erp-nav-ink-strong: #ffffff;
    --erp-nav-hover: rgba(255, 255, 255, .1);
    --erp-nav-active: rgba(255, 255, 255, .14);

    --erp-focus-ring: rgba(22, 104, 220, .45);
    --erp-press-ring: rgba(22, 104, 220, .14);

    /* The six configurable workflow accents (CvWorkflowStep.progress_color).
       Shared by the flow dials, the progress bars and the dashboard dots. */
    --erp-wf-blue: #5b9bf5;
    --erp-wf-green: #34b27b;
    --erp-wf-purple: #9269e0;
    --erp-wf-amber: #dda63f;
    --erp-wf-red: #dd7078;
    --erp-wf-gray: #8e9aab;

    /* Scanned-row tints. Kept as a flat list because the table override
       blocks below need the hover variant as a separate value. */
    --erp-scan-ready: #eef9f3;
    --erp-scan-ready-hover: #e2f3e8;
    --erp-scan-loaded: #e3f5ed;
    --erp-scan-loaded-hover: #d6eedf;
    --erp-scan-assembled: #e8f0fd;
    --erp-scan-assembled-hover: #dce8ff;
    --erp-scan-readyqc: #e9ebfd;
    --erp-scan-readyqc-hover: #e2e8ff;
    --erp-scan-qcpass: #e8f6ee;
    --erp-scan-qcpass-hover: #dff3e7;
    --erp-scan-qcfail: #fdeae8;
    --erp-scan-qcfail-hover: #fbd5d9;
    --erp-scan-painted: #e0cdfa;
    --erp-scan-hit: rgba(15, 138, 95, .24);
    --erp-scan-hit-paint: rgba(109, 67, 200, .18);

    /* CNC console. The operator screen carries its own palette in the page's
       own <style> block, which the theme could not reach while those values
       were literals. Defined here so both skins live in one file. */
    --cnc-surface: #ffffff;
    --cnc-surface-sunken: #f8fafc;
    --cnc-map-bg: #f8fafc;
    --cnc-minimap-bg: rgba(255, 255, 255, .64);
    --cnc-line-soft: rgba(148, 163, 184, .32);
    --cnc-line-mid: rgba(148, 163, 184, .55);
    --cnc-accent: #2563eb;
    --cnc-accent-soft: #93c5fd;
    --cnc-accent-ring: rgba(37, 99, 235, .18);
    --cnc-shadow: 0 6px 18px rgba(15, 23, 42, .04);
    --cnc-shadow-hover: 0 10px 26px rgba(15, 23, 42, .08);
    --cnc-shadow-menu: 0 12px 28px rgba(15, 23, 42, .16);
    --cnc-flag: #b42318;
    --cnc-muted: #4b5563;
    --cnc-muted-soft: #64748b;
    --cnc-muted-faint: #94a3b8;
    --cnc-muted-row: #6b7280;

    /* Sheet state, shared by the metric tiles, the material rows and the
       sheet cards. */
    --cnc-fill-complete: #edf8f1;
    --cnc-fill-progress: #eff6ff;
    --cnc-fill-rework: #fff1f2;
    --cnc-fill-waiting: #f8fafc;
    --cnc-chip-bg: #e5e7eb;
    --cnc-chip-ink: #374151;
    --cnc-chip-waiting-ink: #4b5563;
    --cnc-chip-complete-bg: #cdeed9;
    --cnc-chip-complete-ink: #166534;
    --cnc-chip-progress-bg: #dbeafe;
    --cnc-chip-progress-ink: #1d4ed8;
    --cnc-chip-rework-bg: #ffe0e5;
    --cnc-chip-rework-ink: #be123c;
    --cnc-rework-edge: #fb7185;

    /* Sheet thumbnail on the card. */
    --cnc-mini-fill: #dbeafe;
    --cnc-mini-stroke: #2563eb;
    --cnc-mini-fill-cut: #cdeed9;
    --cnc-mini-stroke-cut: #15803d;
    --cnc-mini-fill-recut: #ffd6dc;
    --cnc-mini-stroke-recut: #be123c;

    /* The nesting map itself: the one thing on the page an operator stares at
       for a whole shift. */
    --cnc-sheet-fill: #fff;
    --cnc-sheet-stroke: #1f2937;
    --cnc-part-fill: #e8f0fe;
    --cnc-part-stroke: #175cd3;
    --cnc-part-fill-cut: #dff3e7;
    --cnc-part-stroke-cut: #0f9d58;
    --cnc-part-fill-recut: #fde7e9;
    --cnc-part-stroke-recut: #b42318;
    --cnc-part-fill-selected: #dbeafe;
    --cnc-part-stroke-selected: #1a73e8;
    --cnc-part-ink: #1f2937;
    --cnc-row-selected: rgba(219, 234, 254, .65);

    --erp-radius: 12px;
    --erp-radius-sm: 9px;
    --erp-radius-lg: 16px;

    --erp-shadow-sm: 0 1px 2px rgba(19, 28, 40, .06), 0 1px 3px rgba(19, 28, 40, .04);
    --erp-shadow: 0 1px 2px rgba(19, 28, 40, .05), 0 4px 12px rgba(19, 28, 40, .07);
    --erp-shadow-lg: 0 2px 4px rgba(19, 28, 40, .05), 0 12px 28px rgba(19, 28, 40, .12);

    --erp-font: "Segoe UI Variable Text", "Segoe UI", -apple-system,
        BlinkMacSystemFont, "SF Pro Text", Roboto, system-ui, sans-serif;
    --erp-font-display: "Segoe UI Variable Display", "Segoe UI", -apple-system,
        BlinkMacSystemFont, "SF Pro Display", Roboto, system-ui, sans-serif;

    /* Minimum comfortable target for a gloved finger on a shop iPad. */
    --erp-touch-target: 44px;

    /* Bootstrap retuning. Components inherit these without markup changes. */
    --bs-body-bg: var(--erp-bg);
    --bs-body-color: var(--erp-ink);
    --bs-body-font-family: var(--erp-font);
    --bs-border-color: var(--erp-line);
    --bs-primary: var(--erp-blue);
    --bs-link-color: var(--erp-blue);
    --bs-link-hover-color: var(--erp-blue-ink);
    --bs-border-radius: var(--erp-radius-sm);
    --bs-border-radius-sm: 7px;
    --bs-border-radius-lg: var(--erp-radius);
}

/* ------------------------------------------------------------------ base -- */

html {
    /* Stop iOS from re-flowing text when an iPad is rotated. */
    -webkit-text-size-adjust: 100%;
}

body {
    background: var(--erp-bg);
    color: var(--erp-ink);
    display: flex;
    flex-direction: column;
    font-family: var(--erp-font);
    min-height: 100vh;
    min-height: 100dvh;
    -webkit-font-smoothing: antialiased;
}

main {
    flex: 1 0 auto;
    /* Landscape iPad home indicator sits over the bottom of the viewport. */
    padding-bottom: max(1.5rem, env(safe-area-inset-bottom));
}

footer {
    flex-shrink: 0;
}

h1, h2, h3, h4, h5, .h1, .h2, .h3, .h4, .h5 {
    font-family: var(--erp-font-display);
    letter-spacing: -.011em;
}

/* Digits in shop tables must line up column to column. */
.table,
.erp-stat strong,
.erp-progress-label,
.erp-job-sub,
.font-tabular {
    font-variant-numeric: tabular-nums;
}

:focus-visible {
    outline: 3px solid var(--erp-focus-ring);
    outline-offset: 2px;
}

/* ---------------------------------------------------------------- chrome -- */

.navbar.bg-dark {
    background: var(--erp-nav-bg) !important;
    border-bottom: 1px solid var(--erp-nav-line);
    box-shadow: var(--erp-nav-shadow);
    padding-top: max(.5rem, env(safe-area-inset-top));
    /* Pinned so an operator deep in a 100-row cabinet list can switch section
       without scrolling back to the top. */
    position: sticky;
    top: 0;
    z-index: 1035;
}

/* Measured from the real navbar by erp-ui.js, because its height changes with
   the iPad safe area and with the collapsed menu. */
:root {
    --erp-nav-height: 57px;
}

.navbar-brand {
    font-family: var(--erp-font-display);
    font-weight: 700;
    letter-spacing: -.015em;
}

.navbar-dark .navbar-nav .nav-link {
    border-radius: 8px;
    color: var(--erp-nav-ink);
    font-weight: 500;
    padding-inline: .7rem;
    transition: background-color .15s ease, color .15s ease;
}

.navbar-dark .navbar-nav .nav-link:hover,
.navbar-dark .navbar-nav .nav-link:focus-visible {
    background: var(--erp-nav-hover);
    color: var(--erp-nav-ink-strong);
}

.navbar-dark .navbar-nav .nav-link.active {
    background: var(--erp-nav-active);
    color: var(--erp-nav-ink-strong);
}

footer.bg-light {
    background: var(--erp-bg-sunken) !important;
    border-top: 1px solid var(--erp-line);
    padding-bottom: max(1rem, env(safe-area-inset-bottom));
}

/* ------------------------------------------------------ project sections -- */

.erp-nav-sprite { display: none; }

.erp-project-shell {
    align-items: start;
    display: grid;
    gap: 20px;
    grid-template-columns: var(--erp-project-nav-width, 232px) minmax(0, 1fr);
}

.erp-project-shell-plain { display: block; }

/* Column width is the single knob the collapse toggle turns. */
.erp-project-shell.is-collapsed { --erp-project-nav-width: 60px; }

.erp-project-main { min-width: 0; }

.erp-project-nav {
    background: var(--erp-card);
    border: 1px solid var(--erp-line);
    border-radius: var(--erp-radius);
    box-shadow: var(--erp-shadow-sm);
    overflow: hidden;
    position: sticky;
    /* Sits under the pinned navbar, which measures itself into this var. */
    top: calc(var(--erp-nav-height) + 12px);
}

.erp-project-nav-head {
    align-items: center;
    border-bottom: 1px solid var(--erp-line);
    display: flex;
    gap: 6px;
    justify-content: space-between;
    padding: 10px 8px 10px 12px;
}

.erp-project-nav-title {
    color: var(--erp-muted);
    font-family: var(--erp-font-display);
    font-size: .7rem;
    font-weight: 700;
    letter-spacing: .09em;
    overflow: hidden;
    text-overflow: ellipsis;
    text-transform: uppercase;
    white-space: nowrap;
}

.erp-project-nav-toggle {
    align-items: center;
    background: transparent;
    border: 1px solid transparent;
    border-radius: 8px;
    color: var(--erp-muted);
    cursor: pointer;
    display: inline-flex;
    flex: 0 0 auto;
    height: 32px;
    justify-content: center;
    padding: 0;
    width: 32px;
}

.erp-project-nav-toggle:hover {
    background: var(--erp-bg-sunken);
    color: var(--erp-ink);
}

.erp-project-nav-toggle .erp-nav-ico {
    transition: transform .18s ease;
    transform: rotate(180deg);
}

.is-collapsed .erp-project-nav-toggle .erp-nav-ico { transform: rotate(0deg); }

.erp-project-nav-list {
    display: flex;
    flex-direction: column;
    gap: 2px;
    list-style: none;
    margin: 0;
    padding: 8px;
}

.erp-project-link {
    align-items: center;
    border-radius: var(--erp-radius-sm);
    color: var(--erp-ink-soft);
    display: flex;
    font-size: .92rem;
    font-weight: 550;
    gap: 10px;
    min-height: 40px;
    padding: 8px 10px;
    text-decoration: none;
    transition: background-color .13s ease, color .13s ease;
}

.erp-project-link:hover {
    background: var(--erp-bg-sunken);
    color: var(--erp-ink);
}

.erp-project-link.active {
    background: var(--erp-blue-soft);
    color: var(--erp-blue-ink);
    font-weight: 650;
}

.erp-project-link.is-muted { color: var(--erp-muted); }
.erp-project-link.is-review { color: var(--erp-amber); }
.erp-project-link.is-review.active { background: var(--erp-amber-soft); color: var(--erp-amber); }

.erp-nav-ico {
    fill: currentColor;
    flex: 0 0 auto;
    height: 18px;
    width: 18px;
}

.erp-nav-label {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.erp-nav-badge {
    background: var(--erp-red);
    border-radius: 999px;
    color: var(--erp-on-accent);
    font-size: .7rem;
    font-weight: 700;
    margin-left: auto;
    padding: 1px 7px;
}

.erp-project-nav-sep {
    border-top: 1px solid var(--erp-line);
    margin-top: 6px;
    padding-top: 6px;
}

/* Collapsed rail: icons only, labels removed from the accessibility tree by
   width rather than display:none so the link keeps its accessible name. */
.is-collapsed .erp-project-nav-title,
.is-collapsed .erp-nav-badge { display: none; }

.is-collapsed .erp-nav-label {
    clip: rect(0 0 0 0);
    height: 1px;
    overflow: hidden;
    position: absolute;
    white-space: nowrap;
    width: 1px;
}

.is-collapsed .erp-project-link {
    justify-content: center;
    padding-inline: 8px;
}

.is-collapsed .erp-project-nav-head { justify-content: center; padding-inline: 8px; }

/* Below lg the rail becomes a horizontal scroller pinned under the navbar,
   which suits an iPad far better than a drawer that hides the sections. */
@media (max-width: 991.98px) {
    .erp-project-shell {
        display: block;
    }

    .erp-project-nav {
        margin-bottom: 16px;
        position: sticky;
        top: var(--erp-nav-height);
        z-index: 1020;
    }

    .erp-project-nav-head { display: none; }

    .erp-project-nav-list {
        -webkit-overflow-scrolling: touch;
        flex-direction: row;
        gap: 6px;
        overflow-x: auto;
        overscroll-behavior-x: contain;
        padding: 8px;
        scrollbar-width: thin;
    }

    .erp-project-nav-list > li { flex: 0 0 auto; }

    .erp-project-nav-sep {
        border-left: 1px solid var(--erp-line);
        border-top: 0;
        margin-left: 4px;
        margin-top: 0;
        padding-left: 10px;
        padding-top: 0;
    }

    .erp-project-link { white-space: nowrap; }
}

/* ------------------------------------------------------------ components -- */

.erp-card {
    background: var(--erp-card);
    border: 1px solid var(--erp-line);
    border-radius: var(--erp-radius);
    box-shadow: var(--erp-shadow-sm);
}

.erp-stats {
    display: grid;
    gap: 12px;
    grid-template-columns: repeat(4, minmax(0, 1fr));
}

.erp-stat {
    background: var(--erp-card);
    border: 1px solid var(--erp-line);
    border-radius: var(--erp-radius);
    box-shadow: var(--erp-shadow-sm);
    padding: 15px 13px;
    text-align: center;
}

.erp-stat strong {
    display: block;
    font-family: var(--erp-font-display);
    font-size: 27px;
    font-weight: 650;
    letter-spacing: -.02em;
    line-height: 1.15;
}

.erp-stat span {
    color: var(--erp-muted);
    font-size: 13px;
}

.erp-job-grid {
    display: grid;
    gap: 16px;
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

.erp-job-card {
    background: var(--erp-card);
    border: 1px solid var(--erp-line);
    border-radius: var(--erp-radius-lg);
    box-shadow: var(--erp-shadow-sm);
    padding: 16px;
    transition: border-color .15s ease, box-shadow .15s ease, transform .15s ease;
}

.erp-job-card:hover {
    border-color: var(--erp-line-strong);
    box-shadow: var(--erp-shadow);
}

/* ------------------------------------------------- dashboard project card -- */

.erp-job-card {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* A late job is the one thing that should be visible without reading. */
.erp-job-card.is-overdue {
    border-color: var(--erp-red-line);
    box-shadow: inset 3px 0 0 var(--erp-red), var(--erp-shadow-sm);
}

.erp-job-head {
    /* Without this the chip column stretches to the height of the title block
       and the status pill stretches with it - a 26px pill drawn 38px tall,
       with its text pinned to the top and a gap underneath. */
    align-items: flex-start;
    display: flex;
    gap: 10px;
    justify-content: space-between;
}

.erp-job-title { min-width: 0; }

.erp-job-title h2 {
    font-weight: 650;
    letter-spacing: -.011em;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.erp-job-sub {
    color: var(--erp-muted);
    font-size: 12.5px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.erp-job-chips {
    /* Same reason as .erp-job-head: pills keep their own height instead of
       being stretched to match their tallest neighbour. */
    align-items: flex-start;
    display: flex;
    flex: 0 0 auto;
    flex-wrap: wrap;
    gap: 4px;
    justify-content: flex-end;
}

.erp-job-signals {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.erp-signal {
    align-items: baseline;
    border-radius: 7px;
    display: inline-flex;
    font-size: 12px;
    font-weight: 650;
    gap: 5px;
    padding: 3px 8px;
}

.erp-signal-note { font-weight: 500; opacity: .8; }

.erp-signal-scheduled { background: var(--erp-bg-sunken); color: var(--erp-ink-soft); }
.erp-signal-due_soon { background: var(--erp-amber-soft); color: var(--erp-amber); }
.erp-signal-overdue { background: var(--erp-red-soft); color: var(--erp-red-ink); }
.erp-signal-alert { background: var(--erp-red-soft); color: var(--erp-red-ink); }

.erp-job-overall-bar { height: 8px; }

.erp-job-figures {
    display: grid;
    gap: 6px;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    margin: 0;
}

.erp-job-figures > div {
    background: var(--erp-bg);
    border-radius: var(--erp-radius-sm);
    padding: 6px 4px;
    text-align: center;
}

.erp-job-figures dt {
    color: var(--erp-muted);
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
}

.erp-job-figures dd {
    font-family: var(--erp-font-display);
    font-size: 15px;
    font-weight: 650;
    font-variant-numeric: tabular-nums;
    margin: 0;
}

/* Stage detail is collapsed by default: ten stacked bars per card made the
   dashboard unscannable. The dot strip keeps the shape of the job visible. */
.erp-job-stages > summary {
    align-items: center;
    cursor: pointer;
    display: flex;
    gap: 10px;
    justify-content: space-between;
    list-style: none;
    padding: 2px 0;
}

.erp-job-stages > summary::-webkit-details-marker { display: none; }

.erp-job-stages-label {
    color: var(--erp-muted);
    font-size: 12px;
    font-weight: 600;
}

.erp-job-stages-label::after { content: " \25BE"; }
.erp-job-stages[open] .erp-job-stages-label::after { content: " \25B4"; }

.erp-job-stages-dots {
    display: flex;
    flex-wrap: wrap;
    gap: 3px;
}

.erp-stage-dot {
    background: var(--erp-bg-sunken);
    border-radius: 3px;
    height: 8px;
    width: 14px;
}

.erp-stage-dot.is-active { opacity: .55; }
.erp-stage-dot.is-done { opacity: 1; }
.erp-stage-dot.is-active.workflow-blue, .erp-stage-dot.is-done.workflow-blue { background: var(--erp-wf-blue); }
.erp-stage-dot.is-active.workflow-green, .erp-stage-dot.is-done.workflow-green { background: var(--erp-wf-green); }
.erp-stage-dot.is-active.workflow-purple, .erp-stage-dot.is-done.workflow-purple { background: var(--erp-wf-purple); }
.erp-stage-dot.is-active.workflow-amber, .erp-stage-dot.is-done.workflow-amber { background: var(--erp-wf-amber); }
.erp-stage-dot.is-active.workflow-red, .erp-stage-dot.is-done.workflow-red { background: var(--erp-wf-red); }
.erp-stage-dot.is-active.workflow-gray, .erp-stage-dot.is-done.workflow-gray { background: var(--erp-wf-gray); }

.erp-job-stage-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding-top: 8px;
}

.erp-job-stage .erp-progress-label {
    font-size: 12px;
    margin-bottom: 3px;
}

.erp-job-stage .erp-progress { height: 6px; }

.erp-job-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: auto;
}

@media (max-width: 560px) {
    .erp-job-figures { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.erp-progress-label {
    display: flex;
    font-size: 13px;
    justify-content: space-between;
    margin-bottom: 5px;
}

.erp-progress {
    background: var(--erp-bg-sunken);
    border-radius: 999px;
    height: 10px;
    overflow: hidden;
}

.erp-progress-fill {
    /* Explicit, because the fill is not always a div: inside a <button> the
       markup has to be phrasing content, and an inline span would drop both
       the percentage width and the height. */
    display: block;
    height: 100%;
    min-width: 0;
    transition: width .25s ease;
}

.erp-progress {
    display: block;
}

.erp-progress-fill.cabinet { background: var(--erp-wf-green); }
.erp-progress-fill.cutting { background: var(--erp-wf-blue); }
.erp-progress-fill.assembly { background: var(--erp-wf-blue); }
.erp-progress-fill.qc { background: var(--erp-wf-green); }
.erp-progress-fill.paint { background: var(--erp-wf-purple); }
.erp-progress-fill.workflow-blue { background: var(--erp-wf-blue); }
.erp-progress-fill.workflow-green { background: var(--erp-wf-green); }
.erp-progress-fill.workflow-purple { background: var(--erp-wf-purple); }
.erp-progress-fill.workflow-amber { background: var(--erp-wf-amber); }
.erp-progress-fill.workflow-red { background: var(--erp-wf-red); }
.erp-progress-fill.workflow-gray { background: var(--erp-wf-gray); }

.erp-tag {
    border-radius: 999px;
    display: inline-block;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: .01em;
    padding: 4px 9px;
    white-space: nowrap;
}

.erp-tag.ready { background: var(--erp-green-soft); color: var(--erp-green); }
.erp-tag.painted { background: var(--erp-purple-soft); color: var(--erp-purple-ink); }
.erp-tag.wait { background: var(--erp-amber-soft); color: var(--erp-amber); }
.erp-tag.assembled { background: var(--erp-blue-soft); color: var(--erp-blue-ink); }
.erp-tag.qc-pass { background: var(--erp-green-soft); color: var(--erp-green); }
.erp-tag.qc-fail { background: var(--erp-red-soft); color: var(--erp-red-ink); }
.erp-tag.fn { background: var(--erp-purple-soft); color: var(--erp-purple-ink); }
.erp-tag.cab { background: var(--erp-green-soft); color: var(--erp-green); }
.erp-tag.cutting { background: var(--erp-blue-soft); color: var(--erp-blue-ink); }
.erp-tag.cut { background: var(--erp-green-soft); color: var(--erp-green-ink); }
.erp-tag.assembling { background: var(--erp-red-soft); color: var(--erp-red-ink); }
.erp-tag.done { background: var(--erp-green-soft); color: var(--erp-green); }
.erp-tag.pinned { background: var(--erp-indigo-soft); color: var(--erp-indigo); }
.erp-tag.readiness-preparation { background: var(--erp-amber-soft); color: var(--erp-amber); }
.erp-tag.readiness-ready { background: var(--erp-green-soft); color: var(--erp-green-ink); }
.erp-tag.readiness-on_hold { background: var(--erp-red-soft); color: var(--erp-red-ink); }

.erp-collapse-toggle {
    align-items: center;
    background: var(--erp-slate);
    border: 1px solid var(--erp-slate-line);
    border-radius: var(--erp-radius-sm);
    color: var(--erp-on-accent);
    cursor: pointer;
    display: inline-flex;
    font-size: .95rem;
    font-weight: 600;
    gap: 8px;
    padding: 9px 15px;
}

.erp-collapse-toggle:hover { background: var(--erp-slate-hover); }

.erp-chevron {
    align-items: center;
    display: inline-flex;
    height: 14px;
    justify-content: center;
    transition: transform .2s ease;
    width: 14px;
}

.erp-chevron::before {
    content: "\25BE";
    font-size: .8rem;
    line-height: 1;
}

.erp-collapse-btn[aria-expanded="false"] .erp-chevron { transform: rotate(-90deg); }
.erp-collapse-btn[aria-expanded="true"] .erp-chevron { transform: rotate(0deg); }

/* ----------------------------------------------------- production flow -- */

/* Horizontal stage chain on the project page. Deliberately a separate
 * namespace from .erp-progress, which four other templates still use for
 * their bar lists (dashboard cards keep those - a compact card reads better
 * as bars than as a chain). */

/* The strip pins under whatever chrome is already pinned above it: the navbar
 * on desktop, navbar + section rail on tablet. Both heights are measured into
 * these variables by erp-ui.js, so nothing here assumes a fixed bar height. */
/* The card is ordinary content: it never changes size and never pins, so it
   cannot move the document. Pinning is the mini bar's job. */

/* Taken out of the flow, so showing it costs the document no height. */
.erp-flow-mini {
    background: var(--erp-card);
    border-bottom: 1px solid var(--erp-line);
    box-shadow: var(--erp-shadow);
    left: 0;
    padding: 4px 12px 6px;
    position: fixed;
    top: calc(var(--erp-nav-height, 57px) + var(--erp-rail-height, 0px));
    width: 100%;
    z-index: 1010;
}

.erp-flow-mini[hidden] { display: none; }

.erp-flow-mini .erp-flow { padding: 2px 0; }
.erp-flow-mini .erp-flow-node { gap: 2px; width: 92px; }
.erp-flow-mini .erp-flow-dial { width: 38px; }
.erp-flow-mini .erp-flow-dial::before { inset: 4px; }
.erp-flow-mini .erp-flow-pct { font-size: .72rem; }
.erp-flow-mini .erp-flow-count { font-size: .58rem; }
.erp-flow-mini .erp-flow-detail { display: none; }

.erp-flow-mini .erp-flow-name {
    -webkit-line-clamp: 1;
    font-size: .68rem;
    min-height: 0;
}

.erp-flow-mini .erp-flow-step + .erp-flow-step::before {
    margin-top: 14px;
    width: 18px;
}

@media (pointer: coarse) {
    .erp-flow-mini .erp-flow-dial { width: 42px; }
    .erp-flow-mini .erp-flow-node { width: 100px; }
}

.erp-flow-head {
    align-items: baseline;
    display: flex;
    flex-wrap: wrap;
    gap: 6px 14px;
    justify-content: space-between;
    margin-bottom: 14px;
}

.erp-flow {
    display: flex;
    gap: 0;
    list-style: none;
    margin: 0;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    padding: 4px 2px 10px;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
}

.erp-flow-step {
    align-items: center;
    display: flex;
    flex: 0 0 auto;
}

/* The connector doubles as the gap between nodes. It lights up once the
   stage on its left is finished, so the eye follows the job downstream. */
.erp-flow-step + .erp-flow-step::before {
    background: var(--erp-line);
    content: "";
    flex: 0 0 auto;
    height: 2px;
    margin-top: 22px;
    width: 34px;
}

.erp-flow-step.is-after-complete::before { background: var(--erp-green); }

.erp-flow-node {
    align-items: center;
    background: none;
    border: 0;
    color: inherit;
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 4px 6px;
    text-align: center;
    text-decoration: none;
    width: 108px;
}

.erp-flow-name {
    color: var(--erp-ink-soft);
    font-family: var(--erp-font-display);
    font-size: .76rem;
    font-weight: 650;
    line-height: 1.2;
    min-height: 2.4em;
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}

/* The dial is a conic ring driven by --p (0-100), set by the template and
   refreshed by the delta poller. */
.erp-flow-dial {
    align-items: center;
    aspect-ratio: 1;
    background:
        conic-gradient(var(--erp-flow-ink, var(--erp-blue)) calc(var(--p, 0) * 1%), var(--erp-bg-sunken) 0);
    border-radius: 50%;
    display: flex;
    flex-direction: column;
    justify-content: center;
    position: relative;
    width: 66px;
}

.erp-flow-dial::before {
    background: var(--erp-card);
    border-radius: 50%;
    content: "";
    inset: 6px;
    position: absolute;
}

.erp-flow-pct,
.erp-flow-count {
    position: relative;
    z-index: 1;
}

.erp-flow-pct {
    font-family: var(--erp-font-display);
    font-size: .95rem;
    font-weight: 700;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
}

.erp-flow-count {
    color: var(--erp-muted);
    font-size: .68rem;
    font-variant-numeric: tabular-nums;
    line-height: 1.2;
}

.erp-flow-detail {
    color: var(--erp-muted);
    font-size: .66rem;
    line-height: 1.25;
    min-height: 1.25em;
}

/* Per-stage accent, reusing the configured progress_color. */
.erp-flow-blue { --erp-flow-ink: var(--erp-wf-blue); }
.erp-flow-green { --erp-flow-ink: var(--erp-wf-green); }
.erp-flow-purple { --erp-flow-ink: var(--erp-wf-purple); }
.erp-flow-amber { --erp-flow-ink: var(--erp-wf-amber); }
.erp-flow-red { --erp-flow-ink: var(--erp-wf-red); }
.erp-flow-gray { --erp-flow-ink: var(--erp-wf-gray); }

.erp-flow-node.is-complete { --erp-flow-ink: var(--erp-green); }
.erp-flow-node.is-complete .erp-flow-pct { color: var(--erp-green); }
.erp-flow-node.is-idle .erp-flow-pct { color: var(--erp-muted); }

/* Only actionable nodes advertise themselves. */
a.erp-flow-node,
button.erp-flow-node { cursor: pointer; }

a.erp-flow-node:hover .erp-flow-name,
button.erp-flow-node:hover .erp-flow-name { color: var(--erp-ink); }

a.erp-flow-node:hover .erp-flow-dial::before,
button.erp-flow-node:hover .erp-flow-dial::before { background: var(--erp-bg); }

.erp-flow-node:focus-visible {
    border-radius: var(--erp-radius-sm);
    outline: 3px solid var(--erp-focus-ring);
    outline-offset: 2px;
}

/* Selected = the cabinet table below is filtered to this stage. */
.erp-flow-node.is-selected .erp-flow-name { color: var(--erp-blue-ink); }

.erp-flow-node.is-selected .erp-flow-dial {
    box-shadow: 0 0 0 3px var(--erp-blue-soft), 0 0 0 4px var(--erp-blue);
}

@media (pointer: coarse) {
    .erp-flow-node { width: 116px; }
    .erp-flow-dial { width: 72px; }
    .erp-flow-step + .erp-flow-step::before { width: 26px; }

    /* Keep the pinned bar tappable even while compact. */
}

/* The cabinet controls form one pinned stack beneath the compact workflow.
   Both rows stay opaque while cabinet data scrolls underneath them. */
.cabinet-list-filter {
    background: var(--erp-bg);
    padding: 10px 0 8px;
    position: sticky;
    top: var(--erp-chrome-height, 8rem);
    z-index: 1009;
    scroll-margin-top: calc(var(--erp-chrome-height, 8rem) + 12px);
}

.cabinet-list-actions {
    background: var(--erp-bg);
    border-bottom: 1px solid var(--erp-line);
    padding: 4px 0 10px;
    position: sticky;
    top: calc(var(--erp-chrome-height, 8rem) + var(--erp-cabinet-filter-height, 4rem));
    z-index: 1008;
}

/* ----------------------------------------------------------- scan panels -- */

.scan-alert {
    left: 50%;
    max-width: 460px;
    position: fixed;
    top: 50%;
    transform: translate(-50%, -50%);
    width: min(460px, calc(100vw - 32px));
    z-index: 1080;
    box-shadow: var(--erp-shadow-lg);
}

.scan-alert-progress {
    background: var(--erp-track-dim);
    border-radius: 999px;
    height: 4px;
    overflow: hidden;
}

.scan-alert-progress > span {
    background: var(--erp-amber);
    display: block;
    height: 100%;
    width: 100%;
}

.scan-alert.show .scan-alert-progress > span {
    animation: scanAlertCountdown 3s linear forwards;
}

@keyframes scanAlertCountdown {
    from { width: 100%; }
    to { width: 0; }
}

.scan-panel {
    background: var(--erp-card);
    border: 2px solid var(--erp-line);
    border-radius: var(--erp-radius);
    padding: 14px;
    transition: border-color .15s ease, box-shadow .15s ease;
}

.scan-panel.active {
    border-color: var(--erp-blue);
    box-shadow: 0 0 0 4px var(--erp-press-ring);
}

.scan-input {
    font-size: 20px;
    font-weight: 700;
    letter-spacing: .02em;
}

.scan-modal-latest {
    background: var(--erp-bg);
    border: 1px solid var(--erp-line);
    border-radius: var(--erp-radius-sm);
    padding: 12px;
}

.scan-log {
    border: 1px solid var(--erp-line);
    border-radius: var(--erp-radius-sm);
    max-height: 260px;
    overflow: auto;
    -webkit-overflow-scrolling: touch;
}

.scan-log-item {
    border-bottom: 1px solid var(--erp-line);
    display: flex;
    gap: 10px;
    justify-content: space-between;
    padding: 10px;
}

.scan-log-item:last-child { border-bottom: 0; }
.scan-log-item.duplicate { background: var(--erp-amber-soft); }
.scan-log-item.error { background: var(--erp-red-soft); }
.scan-log-item.error strong { color: var(--erp-red); }
.scan-log-item.success { background: var(--erp-green-soft); }

#cabinetQcModal .qc-scanner-dialog {
    height: calc(100dvh - 2rem);
    margin-bottom: 1rem;
    margin-top: 1rem;
}

#cabinetQcModal .modal-content {
    max-height: 100%;
    overflow: hidden;
}

#cabinetQcModal .qc-scanner-form {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    min-height: 0;
}

#cabinetQcModal .modal-body {
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
}

#cabinetQcModal .qc-scanner-input-bar {
    background: var(--erp-card);
    padding-bottom: 10px;
    position: sticky;
    top: 0;
    z-index: 3;
}

.qc-queue-empty {
    border: 1px dashed var(--erp-line-strong);
    border-radius: var(--erp-radius-sm);
    padding: 18px;
    text-align: center;
}

.qc-queue-list {
    display: grid;
    gap: 12px;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 420px), 1fr));
}

.cabinet-qc-queue-card {
    background: var(--erp-card);
    border: 1px solid var(--erp-line-strong);
    border-left: 4px solid var(--erp-blue);
    border-radius: var(--erp-radius-sm);
    min-width: 0;
    padding: 14px;
}

.cabinet-qc-queue-card.has-issue {
    border-left-color: var(--erp-red);
}

.cabinet-qc-queue-card.is-submitting {
    opacity: .72;
}

.cabinet-qc-queue-header,
.cabinet-qc-queue-actions {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    justify-content: space-between;
}

.cabinet-qc-queue-header > div {
    min-width: 0;
}

.cabinet-qc-queue-actions {
    justify-content: flex-start;
    margin-top: 12px;
}

.cabinet-qc-card-status {
    margin-left: auto;
}

.cabinet-qc-fail-details {
    border-top: 1px solid var(--erp-line);
    margin-top: 12px;
    padding-top: 12px;
}

#cabinetQcModal .modal-footer {
    background: var(--erp-card);
    flex: 0 0 auto;
    z-index: 2;
}

@media (max-width: 575.98px) {
    .cabinet-qc-card-status {
        flex-basis: 100%;
        margin-left: 0;
    }
}

/* ------------------------------------------------- scanned-row highlights -- */

.scan-hit { animation: scanHit 900ms ease-out; }
.scan-loaded { background: var(--erp-green-soft) !important; }
.scan-ready { background: var(--erp-scan-ready) !important; }

table.table > tbody > tr.scan-ready > *,
table.table-striped > tbody > tr.scan-ready:nth-of-type(odd) > *,
table.table-hover > tbody > tr.scan-ready:hover > * {
    --bs-table-bg: var(--erp-scan-ready);
    --bs-table-striped-bg: var(--erp-scan-ready);
    --bs-table-hover-bg: var(--erp-scan-ready-hover);
    --bs-table-bg-type: var(--erp-scan-ready);
    background-color: var(--erp-scan-ready) !important;
}

table.table > tbody > tr.scan-loaded > *,
table.table-striped > tbody > tr.scan-loaded:nth-of-type(odd) > *,
table.table-hover > tbody > tr.scan-loaded:hover > * {
    --bs-table-bg: var(--erp-scan-loaded);
    --bs-table-striped-bg: var(--erp-scan-loaded);
    --bs-table-hover-bg: var(--erp-scan-loaded-hover);
    --bs-table-bg-type: var(--erp-scan-loaded);
    background-color: var(--erp-scan-loaded) !important;
}

table.table > tbody > tr.scan-assembled > *,
table.table-striped > tbody > tr.scan-assembled:nth-of-type(odd) > *,
table.table-hover > tbody > tr.scan-assembled:hover > * {
    --bs-table-bg: var(--erp-scan-assembled);
    --bs-table-striped-bg: var(--erp-scan-assembled);
    --bs-table-hover-bg: var(--erp-scan-assembled-hover);
    --bs-table-bg-type: var(--erp-scan-assembled);
    background-color: var(--erp-scan-assembled) !important;
}

table.table > tbody > tr.scan-ready-qc > *,
table.table-striped > tbody > tr.scan-ready-qc:nth-of-type(odd) > *,
table.table-hover > tbody > tr.scan-ready-qc:hover > * {
    --bs-table-bg: var(--erp-scan-readyqc);
    --bs-table-striped-bg: var(--erp-scan-readyqc);
    --bs-table-hover-bg: var(--erp-scan-readyqc-hover);
    --bs-table-bg-type: var(--erp-scan-readyqc);
    background-color: var(--erp-scan-readyqc) !important;
}

table.table > tbody > tr.scan-qc-pass > *,
table.table-striped > tbody > tr.scan-qc-pass:nth-of-type(odd) > *,
table.table-hover > tbody > tr.scan-qc-pass:hover > * {
    --bs-table-bg: var(--erp-scan-qcpass);
    --bs-table-striped-bg: var(--erp-scan-qcpass);
    --bs-table-hover-bg: var(--erp-scan-qcpass-hover);
    --bs-table-bg-type: var(--erp-scan-qcpass);
    background-color: var(--erp-scan-qcpass) !important;
}

table.table > tbody > tr.scan-qc-fail > *,
table.table-striped > tbody > tr.scan-qc-fail:nth-of-type(odd) > *,
table.table-hover > tbody > tr.scan-qc-fail:hover > * {
    --bs-table-bg: var(--erp-scan-qcfail);
    --bs-table-striped-bg: var(--erp-scan-qcfail);
    --bs-table-hover-bg: var(--erp-scan-qcfail-hover);
    --bs-table-bg-type: var(--erp-scan-qcfail);
    background-color: var(--erp-scan-qcfail) !important;
}

.scan-painted { background: var(--erp-scan-painted) !important; }

table.table > tbody > tr.scan-painted > *,
table.table-striped > tbody > tr.scan-painted:nth-of-type(odd) > *,
table.table-hover > tbody > tr.scan-painted:hover > * {
    --bs-table-bg: var(--erp-scan-painted);
    --bs-table-striped-bg: var(--erp-scan-painted);
    --bs-table-hover-bg: var(--erp-scan-painted);
    --bs-table-bg-type: var(--erp-scan-painted);
    background-color: var(--erp-scan-painted) !important;
}

@keyframes scanHit {
    0% { box-shadow: inset 0 0 0 999px var(--erp-scan-hit); }
    100% { box-shadow: inset 0 0 0 999px transparent; }
}

.scan-painted.scan-hit { animation-name: paintScanHit; }

@keyframes paintScanHit {
    0% { box-shadow: inset 0 0 0 999px var(--erp-scan-hit-paint); }
    100% { box-shadow: inset 0 0 0 999px transparent; }
}

/* ---------------------------------------------------------------- tables -- */

.table {
    --bs-table-border-color: var(--erp-line);
}

.table > thead > tr > th {
    background: var(--erp-bg-sunken);
    color: var(--erp-ink-soft);
    font-size: .74rem;
    font-weight: 700;
    letter-spacing: .055em;
    text-transform: uppercase;
    white-space: nowrap;
}

/* Opt-in sticky header, applied by templates that own a long shop list.
 *
 * On a mouse the page scrolls and the header scrolls away, which is the
 * familiar desktop behaviour. On a touch terminal the list becomes its own
 * scroll region with a pinned header, so an operator scrolling 100 cabinets
 * never loses the column meanings. Scoped to pointer:coarse because turning
 * the table into a nested scroller on desktop would fight the mouse wheel.
 */
@media (pointer: coarse) {
    .erp-sticky-head {
        /* --erp-chrome-height is everything currently pinned above the list
           (navbar + section rail + workflow strip); the remainder covers the
           filter row, so the list still ends inside the viewport. */
        max-height: calc(100dvh - var(--erp-chrome-height, 8rem) - var(--erp-cabinet-toolbar-height, 7rem) - 1rem);
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
        overscroll-behavior: contain;
    }

    .erp-sticky-head .table > thead > tr > th {
        position: sticky;
        top: 0;
        z-index: 2;
    }
}

/* Bootstrap's .table-responsive is used across the shop pages already. */
.table-responsive {
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
}

/* Instruction text differs by input device: a mouse double-clicks, a finger
 * taps once (see static/js/erp-touch.js). Swapping in CSS keeps both wordings
 * in the template and avoids a flash of the wrong hint on load. */
.erp-hint-touch { display: none; }

@media (pointer: coarse) {
    .erp-hint-mouse { display: none; }
    .erp-hint-touch { display: inline; }
}

/* -------------------------------------------------------- touch/tablet -- */

/* iOS zooms the whole page when a focused control is under 16px. Applying
   this by viewport rather than pointer keeps a mouse-driven iPad correct. */
@media (max-width: 1366px) {
    .form-control,
    .form-select,
    .form-control-sm,
    .form-select-sm,
    input[type="text"],
    input[type="search"],
    input[type="number"],
    input[type="password"],
    input[type="email"],
    textarea,
    select {
        font-size: 16px;
    }
}

@media (pointer: coarse) {
    /* Fingers, not cursors: every interactive element gets a comfortable
       target even where the template asked for a compact Bootstrap size. */
    .btn,
    .form-control,
    .form-select,
    .page-link,
    .nav-link,
    .dropdown-item {
        min-height: var(--erp-touch-target);
    }

    .btn {
        align-items: center;
        display: inline-flex;
        justify-content: center;
        padding-inline: 1rem;
    }

    .btn-sm {
        min-height: var(--erp-touch-target);
        padding-block: .5rem;
    }

    /* Checkboxes and radios in shop checklists are hit with a fingertip.
       Selecting cabinets for a label batch is the densest such flow. */
    .form-check-input {
        height: 1.35rem;
        margin-top: .15rem;
        position: relative;
        width: 1.35rem;
    }

    /* Bootstrap renders these with appearance:none, so a pseudo-element can
       extend the hit area to a full finger target without moving the box or
       changing the table layout. */
    .form-check-input::after {
        content: "";
        height: var(--erp-touch-target);
        left: 50%;
        position: absolute;
        top: 50%;
        transform: translate(-50%, -50%);
        width: var(--erp-touch-target);
    }

    .form-check-label {
        min-height: 1.6rem;
        padding-left: .2rem;
    }

    /* Record links inside table cells open a cabinet or part. Vertical padding
       on an inline element grows the hit area without altering the line box,
       so the table keeps its rhythm. */
    .table td a:not(.btn),
    .table th a:not(.btn) {
        padding-block: .7rem;
    }

    /* Breadcrumbs are the back-navigation on a tablet and were 22px tall. */
    .breadcrumb-item > a {
        align-items: center;
        display: inline-flex;
        min-height: var(--erp-touch-target);
    }

    .navbar-brand {
        align-items: center;
        display: inline-flex;
        min-height: var(--erp-touch-target);
    }

    /* Table row actions need vertical breathing room to stay tappable. */
    .table > tbody > tr > td,
    .table > tbody > tr > th {
        padding-bottom: .7rem;
        padding-top: .7rem;
    }

    /* Remove hover-only affordances: they either never fire or stick after
       a tap on touch hardware. */
    .erp-job-card:hover {
        border-color: var(--erp-line);
        box-shadow: var(--erp-shadow-sm);
    }

    .erp-job-card:active,
    .erp-job-card.erp-pressed,
    .final-checklist-main.erp-pressed {
        border-color: var(--erp-blue);
        box-shadow: 0 0 0 3px var(--erp-press-ring);
    }

    /* Tappable regions advertise themselves; on touch there is no hover to
       discover them with. */
    .final-checklist-main {
        cursor: pointer;
    }

    /* Kill the legacy 300ms tap delay and the grey flash on tap. */
    a, button, .btn, .erp-job-card, .nav-link, [role="button"] {
        touch-action: manipulation;
        -webkit-tap-highlight-color: var(--erp-press-ring);
    }

    /* Text selection on long-press fights drag-scrolling in dense tables. */
    .erp-job-card, .erp-tag, .table > thead {
        -webkit-user-select: none;
        user-select: none;
    }
}

/* iPad portrait: three-across project cards become unreadable. */
@media (max-width: 1200px) {
    .erp-job-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 900px) {
    .erp-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .erp-job-grid { grid-template-columns: 1fr; }
}

@media (max-width: 560px) {
    .erp-stats { grid-template-columns: 1fr; }
}

/* The navbar collapses on tablets; give the opened menu tappable rows. */
@media (max-width: 991.98px) {
    .navbar .navbar-nav {
        gap: 2px;
        padding-block: .35rem;
    }

    /* Below lg the menu is a drawer that is realistically operated by finger,
       so size it for touch without waiting for a pointer:coarse match. */
    .navbar .navbar-nav .nav-link {
        align-items: center;
        display: flex;
        min-height: var(--erp-touch-target);
        padding-block: .6rem;
    }

    .navbar .navbar-nav .btn {
        min-height: var(--erp-touch-target);
    }

    .navbar-toggler {
        min-height: var(--erp-touch-target);
        min-width: var(--erp-touch-target);
    }

    .navbar .navbar-nav.ms-auto {
        align-items: flex-start;
        border-top: 1px solid var(--erp-nav-hover);
        margin-top: .4rem;
        padding-top: .5rem;
    }
}

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: .001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .001ms !important;
    }
}

/* ------------------------------------------------ industrial dark theme -- */

/* Opt-in second skin, selected by data-theme="industrial" on <html> (see the
 * no-flash bootstrap in templates/base.html). It is a token layer plus a short
 * list of overrides for surfaces Bootstrap hard-codes to a light value; no
 * component markup is theme-aware, so the default shop theme is untouched.
 *
 * The element also carries data-bs-theme="dark", which flips Bootstrap's own
 * dark palette. That covers forms, dropdowns, modals, close buttons and
 * offcanvas for free; what is left below is what Bootstrap keeps light on
 * purpose (.table-light, .bg-light, the pastel alerts, outline-secondary).
 */

:root[data-theme="industrial"] {
    --erp-bg: #041118;
    --erp-bg-sunken: #071922;
    --erp-card: #0a202a;
    --erp-elevated: #0d2732;
    --erp-ink: #e8f7fa;
    --erp-ink-soft: #c2dde4;
    --erp-muted: #89a8b2;
    --erp-line: rgba(25, 230, 230, .2);
    --erp-line-strong: rgba(25, 230, 230, .38);

    /* Cyan is the interactive colour, so it takes the --erp-blue slot that
       links, primary buttons and the selected-stage ring already read. */
    --erp-blue: #19e6e6;
    --erp-blue-ink: #7ff4f4;
    --erp-blue-soft: rgba(25, 230, 230, .14);
    --erp-green: #3ddf8c;
    --erp-green-soft: rgba(61, 223, 140, .14);
    --erp-green-ink: #6fecab;
    --erp-red: #ff5d6c;
    --erp-red-soft: rgba(255, 93, 108, .15);
    --erp-red-ink: #ff8a95;
    --erp-red-line: rgba(255, 93, 108, .55);
    --erp-amber: #f4c84a;
    --erp-amber-soft: rgba(244, 200, 74, .14);
    --erp-purple: #ef3ea8;
    --erp-purple-soft: rgba(239, 62, 168, .15);
    --erp-purple-ink: #f9a8d4;
    --erp-purple-line: rgba(239, 62, 168, .5);
    --erp-indigo: #7ff4f4;
    --erp-indigo-soft: rgba(25, 230, 230, .12);

    /* Panels are cut, not rounded. */
    --erp-radius: 6px;
    --erp-radius-sm: 4px;
    --erp-radius-lg: 8px;

    /* Depth comes from a hairline highlight along the top edge rather than a
       drop shadow, which is invisible against a near-black ground. */
    --erp-shadow-sm: inset 0 1px 0 rgba(25, 230, 230, .07);
    --erp-shadow: inset 0 1px 0 rgba(25, 230, 230, .1), 0 6px 18px rgba(0, 0, 0, .55);
    --erp-shadow-lg: inset 0 1px 0 rgba(25, 230, 230, .12), 0 16px 40px rgba(0, 0, 0, .7);

    --erp-on-accent: #041118;
    --erp-slate: #103040;
    --erp-slate-line: rgba(25, 230, 230, .3);
    --erp-slate-hover: #16404f;
    --erp-track-dim: rgba(0, 0, 0, .5);
    --erp-hover: #0d2732;

    --erp-nav-bg: linear-gradient(180deg, #071922 0%, #041118 100%);
    --erp-nav-line: rgba(25, 230, 230, .28);
    --erp-nav-shadow: 0 1px 0 rgba(25, 230, 230, .12);
    --erp-nav-ink: #89a8b2;
    --erp-nav-ink-strong: #19e6e6;
    --erp-nav-hover: rgba(25, 230, 230, .1);
    --erp-nav-active: rgba(25, 230, 230, .18);

    --erp-focus-ring: rgba(25, 230, 230, .6);
    --erp-press-ring: rgba(25, 230, 230, .22);

    /* Workflow accents keep their six identities but move onto the cyan
       ground: saturated enough to read at 8px, never neon. */
    --erp-wf-blue: #19e6e6;
    --erp-wf-green: #3ddf8c;
    --erp-wf-purple: #ef3ea8;
    --erp-wf-amber: #f4c84a;
    --erp-wf-red: #ff5d6c;
    --erp-wf-gray: #5c7c88;

    /* Scanned rows are tinted, not filled: a saturated row would out-shout
       the data in it. The narrow left indicator below carries the signal. */
    --erp-scan-ready: rgba(61, 223, 140, .09);
    --erp-scan-ready-hover: rgba(61, 223, 140, .16);
    --erp-scan-loaded: rgba(61, 223, 140, .14);
    --erp-scan-loaded-hover: rgba(61, 223, 140, .21);
    --erp-scan-assembled: rgba(25, 230, 230, .12);
    --erp-scan-assembled-hover: rgba(25, 230, 230, .19);
    --erp-scan-readyqc: rgba(25, 230, 230, .16);
    --erp-scan-readyqc-hover: rgba(25, 230, 230, .23);
    --erp-scan-qcpass: rgba(61, 223, 140, .12);
    --erp-scan-qcpass-hover: rgba(61, 223, 140, .19);
    --erp-scan-qcfail: rgba(255, 93, 108, .14);
    --erp-scan-qcfail-hover: rgba(255, 93, 108, .22);
    --erp-scan-painted: rgba(239, 62, 168, .16);
    --erp-scan-hit: rgba(25, 230, 230, .26);
    --erp-scan-hit-paint: rgba(239, 62, 168, .22);

    --erp-font-mono: "Cascadia Mono", "JetBrains Mono", Consolas,
        "SF Mono", ui-monospace, "Liberation Mono", monospace;

    /* CNC console. The nesting map is the page's instrument: parts stay as
       outlines over a dark sheet so the cut ones read as filled and the
       recuts as alarmed, rather than every rectangle competing at once. */
    --cnc-surface: #0a202a;
    --cnc-surface-sunken: #0d2732;
    --cnc-map-bg: #030d13;
    --cnc-minimap-bg: rgba(4, 17, 24, .6);
    --cnc-line-soft: rgba(25, 230, 230, .18);
    --cnc-line-mid: rgba(25, 230, 230, .32);
    --cnc-accent: #19e6e6;
    --cnc-accent-soft: rgba(25, 230, 230, .55);
    --cnc-accent-ring: rgba(25, 230, 230, .3);
    --cnc-shadow: inset 0 1px 0 rgba(25, 230, 230, .07);
    --cnc-shadow-hover: inset 0 1px 0 rgba(25, 230, 230, .14), 0 8px 22px rgba(0, 0, 0, .6);
    --cnc-shadow-menu: 0 16px 36px rgba(0, 0, 0, .75);
    --cnc-flag: #ff8a95;
    --cnc-muted: #89a8b2;
    --cnc-muted-soft: #89a8b2;
    --cnc-muted-faint: #5c7c88;
    --cnc-muted-row: #89a8b2;

    --cnc-fill-complete: rgba(61, 223, 140, .12);
    --cnc-fill-progress: rgba(25, 230, 230, .12);
    --cnc-fill-rework: rgba(255, 93, 108, .13);
    --cnc-fill-waiting: #0d2732;
    --cnc-chip-bg: rgba(137, 168, 178, .16);
    --cnc-chip-ink: #c2dde4;
    --cnc-chip-waiting-ink: #89a8b2;
    --cnc-chip-complete-bg: rgba(61, 223, 140, .18);
    --cnc-chip-complete-ink: #6fecab;
    --cnc-chip-progress-bg: rgba(25, 230, 230, .18);
    --cnc-chip-progress-ink: #7ff4f4;
    --cnc-chip-rework-bg: rgba(255, 93, 108, .2);
    --cnc-chip-rework-ink: #ff8a95;
    --cnc-rework-edge: #ff5d6c;

    --cnc-mini-fill: rgba(25, 230, 230, .22);
    --cnc-mini-stroke: #19e6e6;
    --cnc-mini-fill-cut: rgba(61, 223, 140, .32);
    --cnc-mini-stroke-cut: #3ddf8c;
    --cnc-mini-fill-recut: rgba(255, 93, 108, .32);
    --cnc-mini-stroke-recut: #ff5d6c;

    --cnc-sheet-fill: #071922;
    --cnc-sheet-stroke: rgba(25, 230, 230, .45);
    --cnc-part-fill: rgba(25, 230, 230, .1);
    --cnc-part-stroke: #19e6e6;
    --cnc-part-fill-cut: rgba(61, 223, 140, .3);
    --cnc-part-stroke-cut: #3ddf8c;
    --cnc-part-fill-recut: rgba(255, 93, 108, .3);
    --cnc-part-stroke-recut: #ff5d6c;
    --cnc-part-fill-selected: rgba(239, 62, 168, .38);
    --cnc-part-stroke-selected: #ef3ea8;
    --cnc-part-ink: #e8f7fa;
    --cnc-row-selected: rgba(25, 230, 230, .16);

    /* Bootstrap slots that are not derived from the --erp-* set above. */
    --bs-emphasis-color: var(--erp-ink);
    --bs-secondary-color: var(--erp-muted);
    --bs-secondary-bg: var(--erp-bg-sunken);
    --bs-tertiary-bg: var(--erp-elevated);
    --bs-heading-color: var(--erp-ink);
    --bs-primary-rgb: 25, 230, 230;
    --bs-link-color-rgb: 25, 230, 230;
    --bs-code-color: #7ff4f4;
    --bs-border-color-translucent: var(--erp-line);
}

/* Faint instrument grid behind the whole shell. Fixed, so scrolling a long
   cabinet list does not drag a texture with it. */
[data-theme="industrial"] body {
    background-attachment: fixed;
    background-image:
        linear-gradient(rgba(25, 230, 230, .028) 1px, transparent 1px),
        linear-gradient(90deg, rgba(25, 230, 230, .028) 1px, transparent 1px);
    background-size: 44px 44px, 44px 44px;
}

/* Section headings read as panel labels rather than prose. */
[data-theme="industrial"] .erp-card > h2.h5,
[data-theme="industrial"] .erp-card > .h5,
[data-theme="industrial"] .erp-flow-head > .h5 {
    font-size: .8rem;
    letter-spacing: .1em;
    text-transform: uppercase;
}

/* Anything countable gets the technical face and fixed-width digits. */
[data-theme="industrial"] .erp-stat strong,
[data-theme="industrial"] .erp-job-figures dd,
[data-theme="industrial"] .erp-flow-pct,
[data-theme="industrial"] .erp-flow-count,
[data-theme="industrial"] .erp-progress-label,
[data-theme="industrial"] .erp-tag,
[data-theme="industrial"] .erp-signal {
    font-family: var(--erp-font-mono);
    font-variant-numeric: tabular-nums;
}

[data-theme="industrial"] .erp-stat span,
[data-theme="industrial"] .erp-job-figures dt {
    letter-spacing: .07em;
    text-transform: uppercase;
}

[data-theme="industrial"] .erp-job-figures > div,
[data-theme="industrial"] .scan-modal-latest {
    background: var(--erp-elevated);
    border: 1px solid var(--erp-line);
}

/* Status chips are outlined rather than filled: a solid pill of colour on a
   near-black panel bleeds into the surrounding text. */
[data-theme="industrial"] .erp-tag,
[data-theme="industrial"] .erp-signal {
    border: 1px solid currentColor;
    border-radius: var(--erp-radius-sm);
}

[data-theme="industrial"] .erp-tag.assembled,
[data-theme="industrial"] .erp-tag.cutting { color: var(--erp-blue); }
[data-theme="industrial"] .erp-tag.pinned { color: var(--erp-indigo); }
[data-theme="industrial"] .erp-tag.cut,
[data-theme="industrial"] .erp-tag.readiness-ready { color: var(--erp-green); }
[data-theme="industrial"] .erp-tag.qc-fail,
[data-theme="industrial"] .erp-tag.assembling,
[data-theme="industrial"] .erp-tag.readiness-on_hold,
[data-theme="industrial"] .erp-signal-overdue,
[data-theme="industrial"] .erp-signal-alert { color: var(--erp-red); }

[data-theme="industrial"] .erp-signal-scheduled {
    background: var(--erp-elevated);
    color: var(--erp-muted);
}

/* Bootstrap keeps .table-light light on purpose; 34 shop tables use it as
   their header row. */
[data-theme="industrial"] .table-light,
[data-theme="industrial"] .table > thead > tr > th {
    --bs-table-color: var(--erp-ink-soft);
    --bs-table-bg: var(--erp-elevated);
    --bs-table-border-color: var(--erp-line);
    --bs-table-striped-bg: var(--erp-elevated);
    --bs-table-striped-color: var(--erp-ink-soft);
    --bs-table-active-bg: var(--erp-elevated);
    --bs-table-active-color: var(--erp-ink);
    --bs-table-hover-bg: var(--erp-elevated);
    --bs-table-hover-color: var(--erp-ink);
    background: var(--erp-elevated);
    color: var(--erp-ink-soft);
}

[data-theme="industrial"] .table {
    --bs-table-color: var(--erp-ink);
    --bs-table-striped-color: var(--erp-ink);
    --bs-table-hover-color: var(--erp-ink);
    --bs-table-striped-bg: rgba(25, 230, 230, .04);
    --bs-table-hover-bg: rgba(25, 230, 230, .09);
}

/* A tinted row also gets a narrow bar in its first cell, so the state stays
   legible to an operator who cannot separate the tints. The colour travels in
   its own property rather than in `color`, which would repaint the cell's
   text along with the bar. */
[data-theme="industrial"] .table > tbody > tr[class*="scan-"] > *:first-child {
    box-shadow: inset 3px 0 0 var(--erp-row-flag, var(--erp-green));
}

[data-theme="industrial"] tr.scan-qc-fail { --erp-row-flag: var(--erp-red); }
[data-theme="industrial"] tr.scan-painted { --erp-row-flag: var(--erp-purple); }
[data-theme="industrial"] tr.scan-assembled,
[data-theme="industrial"] tr.scan-ready-qc { --erp-row-flag: var(--erp-blue); }

[data-theme="industrial"] .bg-light,
[data-theme="industrial"] .bg-white {
    background-color: var(--erp-card) !important;
    color: var(--erp-ink);
}

/* The pastel alert palette is unreadable on this ground; rebuild each variant
   as a tinted panel with a coloured leading edge. */
[data-theme="industrial"] .alert {
    --bs-alert-bg: var(--erp-elevated);
    --bs-alert-color: var(--erp-ink);
    --bs-alert-border-color: var(--erp-line);
    border-left-width: 3px;
}

[data-theme="industrial"] .alert-info {
    --bs-alert-bg: var(--erp-blue-soft);
    --bs-alert-border-color: var(--erp-blue);
}

[data-theme="industrial"] .alert-success {
    --bs-alert-bg: var(--erp-green-soft);
    --bs-alert-border-color: var(--erp-green);
}

[data-theme="industrial"] .alert-warning {
    --bs-alert-bg: var(--erp-amber-soft);
    --bs-alert-border-color: var(--erp-amber);
}

[data-theme="industrial"] .alert-danger {
    --bs-alert-bg: var(--erp-red-soft);
    --bs-alert-border-color: var(--erp-red);
}

[data-theme="industrial"] .alert-light,
[data-theme="industrial"] .alert-secondary {
    --bs-alert-bg: var(--erp-elevated);
    --bs-alert-border-color: var(--erp-line);
}

/* Buttons. Primary is the one saturated surface in the theme, so it stays the
   unambiguous "do the thing" control. */
[data-theme="industrial"] .btn-primary {
    --bs-btn-bg: var(--erp-blue);
    --bs-btn-border-color: var(--erp-blue);
    --bs-btn-color: var(--erp-on-accent);
    --bs-btn-hover-bg: #4ff0f0;
    --bs-btn-hover-border-color: #4ff0f0;
    --bs-btn-hover-color: var(--erp-on-accent);
    --bs-btn-active-bg: #00aeb8;
    --bs-btn-active-border-color: #00aeb8;
    --bs-btn-active-color: var(--erp-on-accent);
    --bs-btn-disabled-bg: var(--erp-elevated);
    --bs-btn-disabled-border-color: var(--erp-line);
    --bs-btn-disabled-color: var(--erp-muted);
    font-weight: 600;
}

[data-theme="industrial"] .btn-success {
    --bs-btn-bg: var(--erp-green);
    --bs-btn-border-color: var(--erp-green);
    --bs-btn-color: var(--erp-on-accent);
    --bs-btn-hover-bg: #63e8a5;
    --bs-btn-hover-border-color: #63e8a5;
    --bs-btn-hover-color: var(--erp-on-accent);
    --bs-btn-disabled-bg: var(--erp-elevated);
    --bs-btn-disabled-border-color: var(--erp-line);
    --bs-btn-disabled-color: var(--erp-muted);
}

[data-theme="industrial"] .btn-outline-primary {
    --bs-btn-color: var(--erp-blue);
    --bs-btn-border-color: var(--erp-line-strong);
    --bs-btn-hover-bg: var(--erp-blue-soft);
    --bs-btn-hover-border-color: var(--erp-blue);
    --bs-btn-hover-color: var(--erp-blue-ink);
    --bs-btn-active-bg: var(--erp-blue);
    --bs-btn-active-color: var(--erp-on-accent);
    --bs-btn-disabled-color: var(--erp-muted);
}

/* The workhorse: 103 uses, and Bootstrap's #6c757d is illegible here. */
[data-theme="industrial"] .btn-outline-secondary {
    --bs-btn-color: var(--erp-ink-soft);
    --bs-btn-border-color: var(--erp-line);
    --bs-btn-hover-bg: var(--erp-elevated);
    --bs-btn-hover-border-color: var(--erp-line-strong);
    --bs-btn-hover-color: var(--erp-ink);
    --bs-btn-active-bg: var(--erp-elevated);
    --bs-btn-active-border-color: var(--erp-blue);
    --bs-btn-active-color: var(--erp-ink);
    --bs-btn-disabled-color: var(--erp-muted);
}

[data-theme="industrial"] .btn-outline-danger {
    --bs-btn-color: var(--erp-red);
    --bs-btn-border-color: var(--erp-red-line);
    --bs-btn-hover-bg: var(--erp-red-soft);
    --bs-btn-hover-border-color: var(--erp-red);
    --bs-btn-hover-color: var(--erp-red-ink);
    --bs-btn-active-bg: var(--erp-red);
    --bs-btn-active-color: var(--erp-on-accent);
    --bs-btn-disabled-color: var(--erp-muted);
}

[data-theme="industrial"] .btn-outline-success {
    --bs-btn-color: var(--erp-green);
    --bs-btn-border-color: rgba(61, 223, 140, .45);
    --bs-btn-hover-bg: var(--erp-green-soft);
    --bs-btn-hover-border-color: var(--erp-green);
    --bs-btn-hover-color: var(--erp-green-ink);
    --bs-btn-active-bg: var(--erp-green);
    --bs-btn-active-color: var(--erp-on-accent);
    --bs-btn-disabled-color: var(--erp-muted);
}

[data-theme="industrial"] .btn-outline-light {
    --bs-btn-color: var(--erp-ink-soft);
    --bs-btn-border-color: var(--erp-line-strong);
    --bs-btn-hover-bg: var(--erp-nav-hover);
    --bs-btn-hover-border-color: var(--erp-blue);
    --bs-btn-hover-color: var(--erp-blue);
}

/* Bootstrap's .text-bg-* pins white ink and takes the fill from --bs-*-rgb,
   which this theme repoints at light accents - white on cyan is 1.6:1. Each
   light fill therefore needs the ink inverted, and Bootstrap sets it with
   !important. */
[data-theme="industrial"] .text-bg-primary,
[data-theme="industrial"] .text-bg-success,
[data-theme="industrial"] .text-bg-info,
[data-theme="industrial"] .text-bg-warning,
[data-theme="industrial"] .text-bg-light {
    color: var(--erp-on-accent) !important;
}

[data-theme="industrial"] .text-bg-secondary,
[data-theme="industrial"] .text-bg-dark {
    background-color: var(--erp-elevated) !important;
    box-shadow: inset 0 0 0 1px var(--erp-line);
    color: var(--erp-ink) !important;
}

[data-theme="industrial"] .text-bg-danger {
    background-color: var(--erp-red) !important;
    color: var(--erp-on-accent) !important;
}

[data-theme="industrial"] .text-bg-info {
    background-color: var(--erp-blue) !important;
}

[data-theme="industrial"] .text-bg-warning {
    background-color: var(--erp-amber) !important;
}

/* Workflow chain. The ring already draws itself from --erp-wf-*; what the
   dark ground needs is a visible unfilled track and a lit connector. */
[data-theme="industrial"] .erp-flow-dial::before { background: var(--erp-card); }
[data-theme="industrial"] .erp-progress { background: var(--erp-elevated); }
[data-theme="industrial"] .erp-stage-dot { background: var(--erp-elevated); }

[data-theme="industrial"] .erp-flow-mini {
    background: rgba(7, 25, 34, .96);
    border-bottom-color: var(--erp-line-strong);
}

/* Only the stage the operator selected moves, and only faintly. */
[data-theme="industrial"] .erp-flow-node.is-selected .erp-flow-dial {
    animation: erpFlowPulse 2.4s ease-in-out infinite;
}

@keyframes erpFlowPulse {
    0%, 100% { box-shadow: 0 0 0 3px var(--erp-blue-soft), 0 0 0 4px var(--erp-blue); }
    50% { box-shadow: 0 0 0 3px var(--erp-blue-soft), 0 0 0 4px var(--erp-blue), 0 0 14px rgba(25, 230, 230, .45); }
}

[data-theme="industrial"] .erp-project-link.active {
    box-shadow: inset 2px 0 0 var(--erp-blue);
}

[data-theme="industrial"] .form-control,
[data-theme="industrial"] .form-select {
    background-color: var(--erp-elevated);
    border-color: var(--erp-line);
    color: var(--erp-ink);
}

[data-theme="industrial"] .form-control:focus,
[data-theme="industrial"] .form-select:focus {
    border-color: var(--erp-blue);
    box-shadow: 0 0 0 3px var(--erp-press-ring);
}

[data-theme="industrial"] .breadcrumb { --bs-breadcrumb-divider-color: var(--erp-muted); }

[data-theme="industrial"] code,
[data-theme="industrial"] pre {
    background: var(--erp-elevated);
    border-radius: var(--erp-radius-sm);
}

/* ---------------------------------------------------------- theme switch -- */

/* Rendered in two places against two different grounds: the dark navbar, and
   the ordinary page background on the sign-in screen, which blanks the navbar.
   The page-level colours are the default and the navbar overrides them, so a
   third include site would land on a readable pair rather than on white ink
   over a light card. */
.erp-theme-toggle {
    align-items: center;
    background: transparent;
    border: 1px solid var(--erp-line-strong);
    border-radius: var(--erp-radius-sm);
    color: var(--erp-ink-soft);
    cursor: pointer;
    display: inline-flex;
    font-size: .78rem;
    font-weight: 650;
    gap: 6px;
    letter-spacing: .06em;
    min-height: 34px;
    padding: 4px 10px;
    text-transform: uppercase;
    white-space: nowrap;
}

.erp-theme-toggle:hover,
.erp-theme-toggle:focus-visible {
    background: var(--erp-bg-sunken);
    color: var(--erp-ink);
}

.navbar .erp-theme-toggle { color: var(--erp-nav-ink); }

.navbar .erp-theme-toggle:hover,
.navbar .erp-theme-toggle:focus-visible {
    background: var(--erp-nav-hover);
    color: var(--erp-nav-ink-strong);
}

.erp-theme-toggle .erp-nav-ico { height: 16px; width: 16px; }

/* The button advertises the theme it switches TO, so the face matching the
   theme already in use is removed - display:none rather than visibility, so
   the button's accessible name never contains both wordings at once. */
.erp-theme-face {
    align-items: center;
    display: inline-flex;
    gap: 6px;
}

[data-theme="industrial"] .erp-theme-face-industrial,
:root:not([data-theme="industrial"]) .erp-theme-face-shop { display: none; }

@media (pointer: coarse) {
    .erp-theme-toggle { min-height: var(--erp-touch-target); }
}

/* ----------------------------------------------------------------- print -- */

/* Label templates are standalone documents and never load this file. This
   only tidies incidental printing of shop pages. */
@media print {
    .navbar, footer, .btn, .erp-collapse-toggle, .scan-panel { display: none !important; }
    body { background: #fff; color: #000; }
    .erp-card, .erp-job-card, .erp-stat { box-shadow: none; }
}
