:root {
    /* ── Cool sage-green scale ─────────────────────────────── */
    --forest-950: #0c1a11;
    --forest-900: #162c1d;
    --forest-800: #26422f;
    --forest-700: #365841;
    --forest-600: #466e53;
    --forest-500: #4e7a5d;       /* darkened from #568465 → ~4.9:1 on white (WCAG AA) */
    --forest-400: #78a085;
    --forest-300: #9cbda6;
    --forest-200: #c1d8c8;
    --forest-100: #dbeadf;
    --forest-50: #edf5ef;

    /* ── Sage neutrals (cool green tint) ───────────────────── */
    --sage-50: #f1f5f2;
    --sage-100: #e2eae4;
    --sage-200: #cdd8d0;
    /* 300/400 were REFERENCED by mappings/reconcile.html + reconcile.js long before
       they were defined — 11 of those sites had no fallback, so the declarations were
       invalid and silently dropped (N/A slot borders rendered as currentColor).
       --sage-300 is pinned to #cbd5c0, the value the fallback sites already used, so
       this defines the broken sites WITHOUT changing the ones that were working. */
    --sage-300: #cbd5c0;
    --sage-400: #aebcb2;
    --cream: #f1f5f2;

    /* ── Gold / warning accent ─────────────────────────────── */
    /* The app already used a de-facto amber ramp (96 amber-* utilities) and
       reconcile.html started formalising it as --gold-500/--gold-400 without ever
       declaring it — so the "new match" dot rendered transparent. Values are the
       amber steps the existing fallbacks already named. */
    --gold-400: #fbbf24;
    --gold-500: #f59e0b;
}

/* ── Global typography ───────────────────────────────────── */
body {
    font-family: 'Inter', ui-sans-serif, system-ui, -apple-system, sans-serif;
    -webkit-font-smoothing: antialiased;
    letter-spacing: -0.011em;
    font-size: 0.8125rem;
    line-height: 1.5;
    color: #1a2e20;
}

h1, h2, h3, .font-serif {
    font-family: 'Inter', ui-sans-serif, system-ui, -apple-system, sans-serif;
    font-weight: 600;
    letter-spacing: -0.02em;
}

.brand-logo {
    font-family: 'Inter', ui-sans-serif, system-ui, -apple-system, sans-serif;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    font-weight: 700;
    font-size: 0.6875rem;
}

/* ── Sidebar ─────────────────────────────────────────────── */
.sidebar {
    background: #ffffff;
    border-right: 1px solid var(--sage-200);
}

.sidebar-link {
    transition: all 0.15s ease;
    border-left: 2px solid transparent;
}

.sidebar-link:hover {
    background: var(--sage-50);
    border-left-color: var(--forest-300);
}

.sidebar-link.active {
    background: var(--forest-50);
    border-left-color: var(--forest-600);
    font-weight: 500;
    color: var(--forest-900);
}

/* ── Data tables ─────────────────────────────────────────── */
.data-table {
    border-collapse: separate;
    border-spacing: 0;
}

.data-table thead th {
    font-weight: 600;
    font-size: 0.75rem;          /* 12px — was 11px; readability on data-dense pages */
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--forest-600);    /* darker than -500 for AA on small uppercase headers */
    border-bottom: 1px solid var(--sage-200);
    padding: 0.625rem 1rem;
    white-space: nowrap;
    text-align: left;
}

.data-table tbody td {
    padding: 0.625rem 1rem;
    font-size: 0.875rem;         /* 14px — was 13px; readability for hours-long use */
    border-bottom: 1px solid var(--sage-100);
    color: var(--forest-900);
}

.data-table tbody tr {
    transition: background 0.12s ease;
}

.data-table tbody tr:hover {
    background: var(--sage-50);
}

.data-table tbody tr:last-child td {
    border-bottom: none;
}

/* Sortable column headers */
.data-table thead th .sort-arrow {
    color: var(--forest-600);
    pointer-events: none;
}

/* ── Async operations spinner ────────────────────────────── */
@keyframes spin { to { transform: rotate(360deg); } }
.animate-spin { animation: spin 1s linear infinite; }

/* ── One-shot attention pulse ─────────────────────────────── */
/* stock/session_entry.html has called markDirty() -> add('animate-pulse-once')
   on the Save-All button since it was written, but the class was never defined
   anywhere — so the "you have unsaved counts" cue silently did nothing. */
@keyframes pulse-once {
    0%   { transform: scale(1);    box-shadow: 0 0 0 0 rgba(70, 110, 83, 0.45); }
    50%  { transform: scale(1.04); box-shadow: 0 0 0 6px rgba(70, 110, 83, 0); }
    100% { transform: scale(1);    box-shadow: 0 0 0 0 rgba(70, 110, 83, 0); }
}
.animate-pulse-once { animation: pulse-once 0.6s ease-out 2; }
@media (prefers-reduced-motion: reduce) {
    .animate-pulse-once { animation: none; }
}

/* ── Cards ────────────────────────────────────────────────── */
.card {
    background: white;
    border: 1px solid var(--sage-200);
    border-radius: 0.625rem;
    transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.card:hover {
    border-color: var(--forest-200);
    box-shadow: 0 2px 12px rgba(22, 44, 29, 0.05);
}

/* ── Form inputs ──────────────────────────────────────────── */
.form-input {
    border: 1px solid var(--sage-200);
    border-radius: 0.5rem;
    padding: 0.5rem 0.75rem;
    font-size: 0.8125rem;
    transition: all 0.15s ease;
    background: white;
    color: var(--forest-900);
}

.form-input:focus {
    outline: none;
    border-color: var(--forest-400);
    box-shadow: 0 0 0 3px rgba(70, 110, 83, 0.12);
}

.form-input[readonly] {
    background: var(--sage-50);
    color: var(--forest-500);
}

/* ── Buttons ──────────────────────────────────────────────── */
.btn-primary {
    background: var(--forest-800);
    color: white;
    padding: 0.5rem 1.25rem;
    border-radius: 0.5rem;
    font-size: 0.8125rem;
    font-weight: 500;
    letter-spacing: 0.01em;
    transition: all 0.15s ease;
    border: 1px solid transparent;
}

.btn-primary:hover {
    background: var(--forest-700);
    box-shadow: 0 1px 4px rgba(22, 44, 29, 0.15);
}

.btn-secondary {
    background: white;
    color: var(--forest-800);
    padding: 0.5rem 1.25rem;
    border-radius: 0.5rem;
    font-size: 0.8125rem;
    font-weight: 500;
    border: 1px solid var(--sage-200);
    transition: all 0.15s ease;
}

.btn-secondary:hover {
    background: var(--sage-50);
    border-color: var(--forest-300);
}

.btn-export {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: 0.5rem;
    border: 1px solid var(--sage-200);
    background: white;
    color: var(--forest-600);
    cursor: pointer;
    transition: all 0.15s;
}
.btn-export:hover {
    background: var(--forest-50);
    border-color: var(--forest-400);
    color: var(--forest-700);
}

.btn-danger {
    color: #b91c1c;
    font-size: 0.8125rem;
    font-weight: 500;
    transition: color 0.15s ease;
}

.btn-danger:hover {
    color: #991b1b;
}

/* Filled danger button — the one source of truth for destructive confirm
   actions (modals, delete buttons). Replaces ad-hoc `bg-red-700 text-white`. */
.btn-danger-solid {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.5rem 1.25rem;
    font-size: 0.8125rem;
    font-weight: 500;
    color: #fff;
    background: #b91c1c;
    border-radius: 0.375rem;
    transition: background 0.15s ease;
}
.btn-danger-solid:hover { background: #991b1b; }

/* ── Decision action chips (accept / reject / skip) ─────────
   One source of truth for the decision verbs, used in the pending
   queue cards, the decided-history table, the bulk bar, and the JS
   action rebuild. Previously these were re-styled inline in 4 places.
   .btn-chip = shape/size base; -sm / -lg = density variants. */
.btn-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0.375rem 0.75rem;
    font-size: 0.75rem;
    font-weight: 500;
    line-height: 1.2;
    border-radius: 0.375rem;
    border: 1px solid transparent;
    white-space: nowrap;
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease;
}
.btn-chip-sm { padding: 0.25rem 0.5rem; }
.btn-chip-lg { padding: 0.5rem 1rem; font-size: 0.8125rem; }

.btn-accept  { background: #ecfdf5; color: #047857; }
.btn-accept:hover  { background: #d1fae5; }
.btn-reject  { background: #fef2f2; color: #dc2626; }
.btn-reject:hover  { background: #fee2e2; }
.btn-skip    { background: #f3f4f6; color: #4b5563; }
.btn-skip:hover    { background: #e5e7eb; }

/* Outline chip — the fill variant the family was missing.
   .btn-chip is a SHAPE base: padding, radius, min-height and `border: 1px solid
   transparent`. It needs a fill modifier (accept/reject/skip). There was no
   OUTLINE variant, so six templates independently reached for `.btn-secondary`
   alongside it — which does not work: .btn-chip is declared LATER at equal
   specificity, so its transparent border wins while .btn-secondary's white
   background stays. The result is a white button with no border on a white
   card: no affordance at all. Shipped live in #366 on the Reporting filters.
   Use this instead of mixing the two families. */
.btn-chip-outline { background: white; border-color: var(--sage-200); color: var(--forest-700); }
.btn-chip-outline:hover { background: var(--sage-50); border-color: var(--forest-300); }

/* ── Status badges ────────────────────────────────────────── */
.badge {
    display: inline-flex;
    align-items: center;
    padding: 0.125rem 0.625rem;
    border-radius: 9999px;
    font-size: 0.6875rem;
    font-weight: 500;
    letter-spacing: 0.03em;
    text-transform: uppercase;
}

.badge-active   { background: var(--forest-50); color: var(--forest-700); }
.badge-inactive { background: #f3f4f6; color: #6b7280; }
.badge-superadmin { background: #fef2f2; color: #991b1b; }
.badge-am       { background: var(--forest-100); color: var(--forest-700); }
.badge-brand-admin { background: #faf5ff; color: #6b21a8; }
.badge-warehouse { background: #fffbeb; color: #92400e; }
.badge-production { background: #f0fdf4; color: #166534; }

/* Semantic status badges — use these instead of ad-hoc bg-*-50/text-*-700.
   All foreground colours meet WCAG AA on their tint. */
.badge-success { background: #f0fdf4; color: #166534; }
.badge-warning { background: #fffbeb; color: #92400e; }
.badge-danger  { background: #fef2f2; color: #991b1b; }
.badge-info    { background: #eff6ff; color: #1e40af; }
.badge-neutral { background: #f3f4f6; color: #4b5563; }

/* ── Pagination ───────────────────────────────────────────── */
.pagination-link {
    padding: 0.375rem 0.75rem;
    font-size: 0.8125rem;
    border: 1px solid var(--sage-200);
    border-radius: 0.5rem;
    color: var(--forest-800);
    transition: all 0.15s ease;
}

.pagination-link:hover {
    background: var(--sage-50);
    border-color: var(--forest-300);
}

/* ── Search input ─────────────────────────────────────────── */
.search-input {
    border: 1px solid var(--sage-200);
    border-radius: 0.5rem;
    padding: 0.375rem 0.75rem;
    padding-left: 2.25rem;
    font-size: 0.8125rem;
    background: white;
    transition: all 0.15s ease;
    width: 16rem;
    color: var(--forest-900);
}

.search-input:focus {
    outline: none;
    border-color: var(--forest-400);
    box-shadow: 0 0 0 3px rgba(70, 110, 83, 0.12);
}

.search-input::placeholder {
    color: var(--forest-500);    /* was forest-400 — more legible hint text */
    opacity: 0.8;
}

/* ── HTMX indicators ─────────────────────────────────────── */
.htmx-indicator { display: none; }
.htmx-request .htmx-indicator { display: inline-flex; }
.htmx-request.htmx-indicator { display: inline-flex; }

/* ── Modal ────────────────────────────────────────────────── */
.modal-backdrop {
    background: rgba(12, 26, 17, 0.45);
    backdrop-filter: blur(3px);
}

/* ── Sidebar nav counts ───────────────────────────────────── */
.nav-count {
    font-size: 0.6875rem;        /* 11px — was 10px */
    font-weight: 500;
    color: var(--forest-600);    /* was forest-400 (2.9:1, failed AA on white) */
    min-width: 1.25rem;
    text-align: right;
    opacity: 0;
    transition: opacity 0.3s ease;
}

.nav-count-visible {
    opacity: 0.9;                /* was 0.6 — opacity compounded the low contrast */
}

/* ── Divider labels ───────────────────────────────────────── */
.divider-label {
    font-size: 0.6875rem;        /* 11px — was 10px */
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--forest-600);    /* was forest-400 — AA on white */
}

/* ── Scrollbar ────────────────────────────────────────────── */
::-webkit-scrollbar { width: 5px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--sage-200); border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: var(--forest-300); }

/* ── Credential cards ─────────────────────────────────────── */
.cred-card {
    transition: all 0.2s ease;
}

.cred-card:hover {
    border-color: var(--forest-200);
    box-shadow: 0 2px 12px rgba(22, 44, 29, 0.05);
}

.cred-initials-badge {
    letter-spacing: 0.05em;
}

.cred-field-label {
    font-size: 0.6875rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--forest-600);    /* was forest-400 — AA on white */
    min-width: 5.5rem;
    flex-shrink: 0;
}

.cred-action-btn {
    flex-shrink: 0;
    padding: 0.25rem;
    border-radius: 0.25rem;
    color: var(--forest-300);
    transition: all 0.15s ease;
    opacity: 0;
}

.cred-field-row:hover .cred-action-btn,
.cred-action-btn:focus {
    opacity: 1;
}

.cred-action-btn:hover {
    color: var(--forest-600);
    background: var(--forest-50);
}

/* ── Stats cards ──────────────────────────────────────────── */
.stat-card {
    background: white;
    border: 1px solid var(--sage-200);
    border-radius: 0.625rem;
    padding: 1rem 1.25rem;
    transition: all 0.2s ease;
}

.stat-card:hover {
    border-color: var(--forest-200);
    box-shadow: 0 2px 8px rgba(22, 44, 29, 0.04);
}

/* ── Empty state ──────────────────────────────────────────── */
.empty-state {
    padding: 3rem 1rem;
    text-align: center;
    color: var(--forest-600);    /* was forest-400 — AA on white */
}

/* ── Link styles ──────────────────────────────────────────── */
.link-primary {
    color: var(--forest-600);
    transition: color 0.15s ease;
}

.link-primary:hover {
    color: var(--forest-800);
}

/* ── Brand switcher ───────────────────────────────────────── */
.brand-select {
    background: var(--sage-50);
    border: 1px solid var(--sage-200);
    color: var(--forest-900);
    font-size: 0.8125rem;
    border-radius: 0.5rem;
    padding: 0.375rem 0.5rem;
    width: 100%;
    transition: border-color 0.15s ease;
}

.brand-select:focus {
    outline: none;
    border-color: var(--forest-400);
}

.brand-select option {
    background: white;
    color: var(--forest-900);
}

/* ── Toast notifications ──────────────────────────────────── */
.toast {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    padding: 0.75rem 1rem;
    border-radius: 0.625rem;
    font-size: 0.8125rem;
    background: white;
    border: 1px solid var(--sage-200);
    box-shadow: 0 8px 30px rgba(12, 26, 17, 0.1), 0 2px 8px rgba(12, 26, 17, 0.05);
    transform: translateX(calc(100% + 2rem));
    opacity: 0;
    transition: transform 0.35s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.35s cubic-bezier(0.22, 1, 0.36, 1);
    position: relative;
    overflow: hidden;
    min-width: 280px;
    max-width: 420px;
}

.toast-enter {
    transform: translateX(0);
    opacity: 1;
}

.toast-exit {
    transform: translateX(calc(100% + 2rem));
    opacity: 0;
}

.toast-success { border-left: 3px solid var(--forest-500); }
.toast-error   { border-left: 3px solid #ef4444; }
.toast-warning { border-left: 3px solid #f59e0b; }
.toast-info    { border-left: 3px solid #3b82f6; }

.toast-icon { flex-shrink: 0; display: flex; align-items: center; }
.toast-text { flex: 1; color: var(--forest-900); line-height: 1.4; }

.toast-close {
    flex-shrink: 0;
    border: none;
    background: none;
    cursor: pointer;
    color: var(--forest-300);
    font-size: 1.125rem;
    padding: 0 0.125rem;
    transition: color 0.15s ease;
    line-height: 1;
}

.toast-close:hover { color: var(--forest-600); }

.toast-progress {
    position: absolute;
    bottom: 0;
    left: 0;
    height: 2px;
    width: 100%;
    animation: toast-timer 4s linear forwards;
}

.toast-progress-success { background: var(--forest-500); }
.toast-progress-error   { background: #ef4444; }
.toast-progress-warning { background: #f59e0b; }
.toast-progress-info    { background: #3b82f6; }

@keyframes toast-timer {
    from { width: 100%; }
    to { width: 0%; }
}

/* ── Selection / accent override ──────────────────────────── */
::selection {
    background: var(--forest-200);
    color: var(--forest-900);
}

/* ── Focus-visible ring ───────────────────────────────────── */
*:focus-visible {
    outline: 2px solid var(--forest-400);
    outline-offset: 2px;
}

/* ── Mobile sidebar ──────────────────────────────────────── */
.sidebar-open {
    transform: translateX(0) !important;
}

/* ══════════════════════════════════════════════════════════
   MOBILE RESPONSIVENESS
   ══════════════════════════════════════════════════════════ */

/* ── Responsive tables ───────────────────────────────────── */
/* Any card/div containing a data-table becomes scrollable on small screens */
.card:has(.data-table),
.data-table-wrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

@media (max-width: 1023px) {
    .data-table {
        min-width: 600px;
    }
}

/* ── Small-screen table compaction ───────────────────────── */
@media (max-width: 639px) {
    .data-table thead th {
        padding: 0.5rem 0.625rem;
        font-size: 0.625rem;
    }
    .data-table tbody td {
        padding: 0.5rem 0.625rem;
        font-size: 0.75rem;
    }
    /* Hide lower-priority columns on tiny screens */
    .data-table .hide-mobile {
        display: none;
    }
}

/* Touch devices can't hover, so row actions/controls revealed only on hover
   (opacity-0 group-hover:opacity-100) are invisible & unusable. Force them
   visible wherever the primary input has no hover (phones/tablets). */
@media (hover: none) {
    .opacity-0.group-hover\:opacity-100 {
        opacity: 1 !important;
    }
}

/* ── Responsive stat cards ───────────────────────────────── */
@media (max-width: 639px) {
    .stat-card {
        padding: 0.75rem 1rem;
    }
    .stat-card .text-2xl {
        font-size: 1.25rem;
    }
}

/* ── Responsive form rows ────────────────────────────────── */
@media (max-width: 639px) {
    .form-row-responsive {
        flex-direction: column;
    }
    .form-row-responsive > * {
        width: 100%;
    }
}

/* ── Mobile page headers ─────────────────────────────────── */
@media (max-width: 639px) {
    h1.font-serif, h1.text-2xl {
        font-size: 1.25rem;
    }
    /* Stack header + action buttons vertically */
    .mb-6.flex.items-center.justify-between,
    .mb-6.flex.items-start.justify-between {
        flex-direction: column;
        align-items: stretch;
        gap: 0.75rem;
    }
    /* Full-width action buttons on mobile */
    .btn-primary {
        text-align: center;
    }
}

/* ── Mobile cards ────────────────────────────────────────── */
@media (max-width: 639px) {
    .card {
        border-radius: 0.5rem;
    }
    .card .px-6 {
        padding-left: 1rem;
        padding-right: 1rem;
    }
    .card .p-6 {
        padding: 1rem;
    }
    .card .p-5 {
        padding: 0.875rem;
    }
}

/* ── Mobile search input ─────────────────────────────────── */
@media (max-width: 639px) {
    .search-input {
        width: 100%;
    }
}

/* ── Mobile toolbar spacing ──────────────────────────────── */
@media (max-width: 639px) {
    .flex.items-center.gap-3 {
        flex-wrap: wrap;
        gap: 0.5rem;
    }
}

/* ── Mobile badge text ───────────────────────────────────── */
@media (max-width: 639px) {
    .badge {
        font-size: 0.5625rem;
        padding: 0.0625rem 0.5rem;
    }
}

/* ── Touch-friendly tap targets ──────────────────────────── */
@media (max-width: 1023px) {
    .sidebar-link {
        padding-top: 0.625rem;
        padding-bottom: 0.625rem;
    }
    .btn-primary, .btn-secondary {
        min-height: 2.5rem;
    }
    .btn-export {
        width: 2.5rem;
        height: 2.5rem;
    }
}

/* ── Mobile variant tags ─────────────────────────────────── */
@media (max-width: 639px) {
    .variant-tag {
        font-size: 0.75rem;
        padding: 0.25rem 0.5rem;
    }
}

/* ── Full-width modals on mobile ─────────────────────────── */
@media (max-width: 639px) {
    .fixed .bg-white.rounded-lg.shadow-xl {
        margin: 0.5rem;
        max-width: 100%;
    }
}

/* ══════════════════════════════════════════════════════════
   ANIMATIONS & TRANSITIONS
   ══════════════════════════════════════════════════════════ */

/* ── Smooth scroll ──────────────────────────────────────── */
html { scroll-behavior: smooth; }

/* ── Page loading bar (top) ─────────────────────────────── */
#page-loader {
    position: fixed;
    top: 0;
    left: 0;
    height: 2.5px;
    background: linear-gradient(90deg, var(--forest-400), var(--forest-600), var(--forest-400));
    background-size: 200% 100%;
    z-index: 9999;
    width: 0%;
    opacity: 0;
    transition: opacity 0.2s;
    pointer-events: none;
}

#page-loader.loading {
    opacity: 1;
    animation: loader-progress 1.8s cubic-bezier(0.4, 0, 0.2, 1) forwards,
               loader-shimmer 1.5s ease-in-out infinite;
}

#page-loader.done {
    width: 100% !important;
    opacity: 0;
    transition: width 0.15s ease-out, opacity 0.35s ease 0.15s;
}

@keyframes loader-progress {
    0%   { width: 0%; }
    20%  { width: 30%; }
    50%  { width: 60%; }
    80%  { width: 82%; }
    100% { width: 90%; }
}

@keyframes loader-shimmer {
    0%   { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}

/* ── Content entrance ───────────────────────────────────── */
.page-enter {
    animation: fadeSlideUp 0.35s cubic-bezier(0.22, 1, 0.36, 1) both;
}

@keyframes fadeSlideUp {
    from {
        opacity: 0;
        transform: translateY(8px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

/* ── Card hover lift ────────────────────────────────────── */
.card {
    transition: border-color 0.25s ease, box-shadow 0.25s ease, transform 0.25s cubic-bezier(0.22, 1, 0.36, 1);
}

.card:hover {
    border-color: var(--forest-200);
    box-shadow: 0 4px 16px rgba(22, 44, 29, 0.07);
    transform: translateY(-1px);
}

.card:active {
    transform: translateY(0);
    transition-duration: 0.1s;
}

/* ── Stat card hover ────────────────────────────────────── */
.stat-card {
    transition: all 0.25s cubic-bezier(0.22, 1, 0.36, 1);
}

.stat-card:hover {
    border-color: var(--forest-200);
    box-shadow: 0 4px 16px rgba(22, 44, 29, 0.06);
    transform: translateY(-1px);
}

/* ── .btn-primary / .btn-secondary need a flex context ────────────────────
   These two were the ONLY .btn-* rules with no `display`, so a <button>
   stayed inline-block. Invisible until a button contains an icon, then:
     · `justify-center` at the call site is INERT — there is no flex context.
     · no `gap`, so icon and label are separated only by collapsed whitespace.
     · the SVG sits on the TEXT BASELINE, riding low and adding descender
       space — the Reporting export button measured 54px against 40px for the
       text-only button directly beside it.
   .btn-chip / .btn-export / .btn-danger-solid already declare inline-flex, so
   they are NOT re-declared here; .btn-danger is deliberately a text-style
   button (colour only) and is left inline. */
.btn-primary,
.btn-secondary {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    min-height: 2.5rem;
    line-height: 1.2;
}
.btn-primary > svg,
.btn-secondary > svg { flex-shrink: 0; }

/* Already inline-flex — it just never had a gap for an icon, and sits beside a
   .btn-secondary in modal footers, so match that height. */
.btn-danger-solid { gap: 0.5rem; min-height: 2.5rem; }

/* ── Button press animation ─────────────────────────────── */
.btn-primary {
    transition: all 0.2s cubic-bezier(0.22, 1, 0.36, 1);
}

.btn-primary:active {
    transform: scale(0.97);
    box-shadow: none;
}

.btn-secondary:active {
    transform: scale(0.97);
}

.btn-export:active {
    transform: scale(0.92);
}

/* ── Table row stagger entrance ─────────────────────────── */
.data-table tbody tr {
    animation: tableRowIn 0.3s cubic-bezier(0.22, 1, 0.36, 1) both;
}

@keyframes tableRowIn {
    from {
        opacity: 0;
        transform: translateY(4px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

/* Stagger delays for first 20 rows */
.data-table tbody tr:nth-child(1)  { animation-delay: 0.02s; }
.data-table tbody tr:nth-child(2)  { animation-delay: 0.04s; }
.data-table tbody tr:nth-child(3)  { animation-delay: 0.06s; }
.data-table tbody tr:nth-child(4)  { animation-delay: 0.08s; }
.data-table tbody tr:nth-child(5)  { animation-delay: 0.10s; }
.data-table tbody tr:nth-child(6)  { animation-delay: 0.12s; }
.data-table tbody tr:nth-child(7)  { animation-delay: 0.14s; }
.data-table tbody tr:nth-child(8)  { animation-delay: 0.16s; }
.data-table tbody tr:nth-child(9)  { animation-delay: 0.18s; }
.data-table tbody tr:nth-child(10) { animation-delay: 0.20s; }
.data-table tbody tr:nth-child(11) { animation-delay: 0.22s; }
.data-table tbody tr:nth-child(12) { animation-delay: 0.24s; }
.data-table tbody tr:nth-child(13) { animation-delay: 0.26s; }
.data-table tbody tr:nth-child(14) { animation-delay: 0.28s; }
.data-table tbody tr:nth-child(15) { animation-delay: 0.30s; }
.data-table tbody tr:nth-child(n+16) { animation-delay: 0.32s; }

/* ── Clickable table rows ───────────────────────────────── */
.data-table tbody tr[onclick],
.data-table tbody tr a {
    cursor: pointer;
}

.data-table tbody tr:hover {
    background: var(--sage-50);
    transition: background 0.15s ease;
}

/* ── Modal transitions ──────────────────────────────────── */
.modal-backdrop {
    background: rgba(12, 26, 17, 0.45);
    backdrop-filter: blur(3px);
    animation: backdropIn 0.2s ease both;
}

@keyframes backdropIn {
    from { opacity: 0; backdrop-filter: blur(0px); }
    to   { opacity: 1; backdrop-filter: blur(3px); }
}

.modal-content {
    animation: modalIn 0.3s cubic-bezier(0.22, 1, 0.36, 1) both;
}

@keyframes modalIn {
    from {
        opacity: 0;
        transform: scale(0.95) translateY(8px);
    }
    to {
        opacity: 1;
        transform: scale(1) translateY(0);
    }
}

/* ── Badge entrance animation ───────────────────────────── */
.badge {
    animation: badgeIn 0.25s cubic-bezier(0.22, 1, 0.36, 1) both;
}

@keyframes badgeIn {
    from { opacity: 0; transform: scale(0.8); }
    to   { opacity: 1; transform: scale(1); }
}

/* ── Running status pulse ───────────────────────────────── */
.badge-running, .status-running {
    animation: statusPulse 2s ease-in-out infinite;
}

@keyframes statusPulse {
    0%, 100% { opacity: 1; }
    50%      { opacity: 0.6; }
}

/* ── Form input focus glow ──────────────────────────────── */
.form-input {
    transition: border-color 0.2s ease, box-shadow 0.25s ease;
}

.form-input:focus {
    border-color: var(--forest-400);
    box-shadow: 0 0 0 3px rgba(70, 110, 83, 0.12);
}

/* ── Checkbox & toggle smooth ───────────────────────────── */
input[type="checkbox"] {
    transition: all 0.15s ease;
}

input[type="checkbox"]:checked {
    animation: checkPop 0.2s cubic-bezier(0.22, 1, 0.36, 1);
}

@keyframes checkPop {
    0%   { transform: scale(1); }
    50%  { transform: scale(1.15); }
    100% { transform: scale(1); }
}

/* ── Sidebar nav count fade in ──────────────────────────── */
.nav-count {
    transition: opacity 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}

/* ── Sidebar link smooth interactions ───────────────────── */
.sidebar-link {
    transition: all 0.2s cubic-bezier(0.22, 1, 0.36, 1);
    border-left: 2px solid transparent;
}

.sidebar-link:hover {
    background: var(--sage-50);
    border-left-color: var(--forest-300);
    padding-left: calc(0.75rem + 2px);
}

.sidebar-link.active {
    background: var(--forest-50);
    border-left-color: var(--forest-600);
    font-weight: 500;
    color: var(--forest-900);
}

/* ── Sidebar link icons ─────────────────────────────────── */
.sidebar-link svg {
    transition: opacity 0.2s ease;
}

.sidebar-link:hover svg {
    opacity: 0.7;
}

.sidebar-link.active svg {
    opacity: 0.8;
}

/* ── Colour/size tag transitions ────────────────────────── */
.variant-tag, [class*="bg-forest-50"] {
    transition: all 0.15s ease;
}

/* ── Search input expand on focus ───────────────────────── */
.search-input {
    transition: all 0.25s cubic-bezier(0.22, 1, 0.36, 1);
}

.search-input:focus {
    width: 20rem;
}

@media (max-width: 639px) {
    .search-input:focus {
        width: 100%;
    }
}

/* ── Link underline animation ───────────────────────────── */
a.link-animated {
    position: relative;
    text-decoration: none;
}

a.link-animated::after {
    content: '';
    position: absolute;
    bottom: -1px;
    left: 0;
    width: 0;
    height: 1px;
    background: currentColor;
    transition: width 0.25s cubic-bezier(0.22, 1, 0.36, 1);
}

a.link-animated:hover::after {
    width: 100%;
}

/* ── Skeleton loading shimmer ───────────────────────────── */
.skeleton {
    background: linear-gradient(90deg, var(--sage-100) 25%, var(--sage-50) 50%, var(--sage-100) 75%);
    background-size: 200% 100%;
    animation: skeletonShimmer 1.5s ease-in-out infinite;
    border-radius: 0.375rem;
}

@keyframes skeletonShimmer {
    0%   { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}

/* ── Dropdown/select smooth ─────────────────────────────── */
select, .brand-select {
    transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

select:focus, .brand-select:focus {
    box-shadow: 0 0 0 3px rgba(70, 110, 83, 0.1);
}

/* ── Export button tooltip ──────────────────────────────── */
.btn-export {
    position: relative;
}

.btn-export::after {
    content: 'Export CSV';
    position: absolute;
    bottom: calc(100% + 6px);
    left: 50%;
    transform: translateX(-50%) translateY(4px);
    padding: 0.25rem 0.625rem;
    font-size: 0.6875rem;
    font-weight: 500;
    white-space: nowrap;
    background: var(--forest-900);
    color: white;
    border-radius: 0.375rem;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.2s ease, transform 0.2s cubic-bezier(0.22, 1, 0.36, 1);
}

.btn-export:hover::after {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
}

/* ── Batch card status dropdown ─────────────────────────── */
.status-select {
    transition: all 0.2s ease;
}

/* ── Ripple effect on interactive elements ──────────────── */
.ripple {
    position: relative;
    overflow: hidden;
}

.ripple::before {
    content: '';
    position: absolute;
    inset: 0;
    background: radial-gradient(circle at var(--ripple-x, 50%) var(--ripple-y, 50%), rgba(22, 44, 29, 0.06) 0%, transparent 60%);
    opacity: 0;
    transition: opacity 0.4s ease;
}

.ripple:active::before {
    opacity: 1;
    transition-duration: 0.1s;
}

/* ── Tab switching animation ────────────────────────────── */
.tab-content {
    animation: tabFade 0.25s ease both;
}

@keyframes tabFade {
    from { opacity: 0; transform: translateY(4px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* ── Brand card hover on dashboard ──────────────────────── */
.brand-card {
    transition: all 0.3s cubic-bezier(0.22, 1, 0.36, 1);
}

.brand-card:hover {
    transform: translateY(-2px);
    box-shadow: 0 8px 24px rgba(22, 44, 29, 0.08);
}

/* ══════════════════════════════════════════════════════════
   CUSTOM SELECT DROPDOWNS
   ══════════════════════════════════════════════════════════ */

/* ── Wrapper ─────────────────────────────────────────────── */
.custom-select {
    position: relative;
    width: 100%;
}

/* ── Trigger button ──────────────────────────────────────── */
.custom-select-trigger {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    border: 1px solid var(--sage-200);
    border-radius: 0.5rem;
    padding: 0.5rem 0.75rem;
    font-size: 0.8125rem;
    background: white;
    color: var(--forest-900);
    cursor: pointer;
    transition: border-color 0.2s ease, box-shadow 0.25s ease, background 0.15s ease;
    user-select: none;
    min-height: 2.375rem;
    text-align: left;
    line-height: 1.4;
}

.custom-select-trigger:hover {
    border-color: var(--forest-300);
    background: var(--sage-50);
}

.custom-select-trigger:focus {
    outline: none;
    border-color: var(--forest-400);
    box-shadow: 0 0 0 3px rgba(70, 110, 83, 0.12);
}

.custom-select.open .custom-select-trigger {
    border-color: var(--forest-400);
    box-shadow: 0 0 0 3px rgba(70, 110, 83, 0.12);
}

/* ── Trigger text ────────────────────────────────────────── */
.custom-select-value {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.custom-select-placeholder {
    color: var(--forest-500);    /* was forest-400 @ .6 (2.9:1) — now AA */
    opacity: 0.85;
}

/* ── Chevron icon ────────────────────────────────────────── */
.custom-select-arrow {
    flex-shrink: 0;
    width: 1rem;
    height: 1rem;
    margin-left: 0.5rem;
    color: var(--forest-400);
    transition: transform 0.25s cubic-bezier(0.22, 1, 0.36, 1), color 0.15s ease;
}

.custom-select.open .custom-select-arrow {
    transform: rotate(180deg);
    color: var(--forest-600);
}

/* ── Dropdown panel ──────────────────────────────────────── */
.custom-select-dropdown {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    background: white;
    border: 1px solid var(--sage-200);
    border-radius: 0.5rem;
    box-shadow: 0 8px 24px rgba(12, 26, 17, 0.1), 0 2px 8px rgba(12, 26, 17, 0.04);
    z-index: 60;
    max-height: 0;
    overflow: hidden;
    opacity: 0;
    transform: translateY(-4px);
    transition: max-height 0.3s cubic-bezier(0.22, 1, 0.36, 1),
                opacity 0.2s ease,
                transform 0.25s cubic-bezier(0.22, 1, 0.36, 1);
    pointer-events: none;
}

.custom-select.open .custom-select-dropdown {
    max-height: 15rem;
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
}

/* ── Options scrollable area ─────────────────────────────── */
.custom-select-options {
    overflow-y: auto;
    max-height: 14.5rem;
    padding: 0.25rem;
}

.custom-select-options::-webkit-scrollbar { width: 4px; }
.custom-select-options::-webkit-scrollbar-track { background: transparent; }
.custom-select-options::-webkit-scrollbar-thumb { background: var(--sage-200); border-radius: 2px; }

/* ── Type-to-filter search box (long lists only) ─────────── */
.custom-select-search {
    display: block;
    width: calc(100% - 0.5rem);
    margin: 0.25rem;
    padding: 0.45rem 0.6rem;
    font-size: 0.8125rem;
    line-height: 1.2;
    color: var(--forest-900);
    background: var(--sage-50);
    border: 1px solid var(--sage-200);
    border-radius: 0.375rem;
    outline: none;
    box-sizing: border-box;
}
.custom-select-search:focus { border-color: var(--forest-400); background: #fff; }
.custom-select-search::placeholder { color: var(--forest-900); opacity: 0.4; }

.custom-select-noresults {
    padding: 0.6rem 0.75rem;
    font-size: 0.8125rem;
    color: var(--forest-900);
    opacity: 0.5;
    text-align: center;
}

/* Make room for the search box without clipping the option list */
.custom-select.open .custom-select-dropdown.cs-has-search { max-height: 17rem; }
.custom-select-dropdown.cs-has-search .custom-select-options { max-height: 13rem; }

/* ── Individual option ───────────────────────────────────── */
.custom-select-option {
    padding: 0.5rem 0.75rem;
    font-size: 0.8125rem;
    color: var(--forest-900);
    border-radius: 0.375rem;
    cursor: pointer;
    transition: background 0.12s ease, color 0.12s ease, padding-left 0.2s cubic-bezier(0.22, 1, 0.36, 1);
    display: flex;
    align-items: center;
    gap: 0.5rem;
    position: relative;
}

.custom-select-option:hover,
.custom-select-option.highlighted {
    background: var(--forest-50);
    color: var(--forest-800);
    padding-left: 1rem;
}

.custom-select-option.selected {
    background: var(--forest-50);
    color: var(--forest-800);
    font-weight: 500;
}

/* Selected check mark */
.custom-select-option.selected::after {
    content: '';
    display: block;
    width: 0.375rem;
    height: 0.625rem;
    margin-left: auto;
    border: solid var(--forest-600);
    border-width: 0 1.5px 1.5px 0;
    transform: rotate(45deg);
    flex-shrink: 0;
    animation: checkIn 0.2s cubic-bezier(0.22, 1, 0.36, 1) both;
}

@keyframes checkIn {
    from { opacity: 0; transform: rotate(45deg) scale(0.5); }
    to   { opacity: 1; transform: rotate(45deg) scale(1); }
}

/* ── Size variants ───────────────────────────────────────── */
.custom-select-trigger.text-sm {
    font-size: 0.8125rem;
    padding: 0.375rem 0.625rem;
    min-height: 2.125rem;
}

.custom-select-trigger.text-xs {
    font-size: 0.75rem;
    padding: 0.25rem 0.5rem;
    min-height: 1.875rem;
}

.custom-select-trigger.text-xs .custom-select-arrow,
.custom-select-trigger.text-sm .custom-select-arrow {
    width: 0.875rem;
    height: 0.875rem;
}

/* ── Disabled state ──────────────────────────────────────── */
.custom-select.disabled .custom-select-trigger {
    background: var(--sage-50);
    color: #6b7280;
    cursor: not-allowed;
    border-color: var(--sage-200);
}

.custom-select.disabled .custom-select-trigger:hover {
    border-color: var(--sage-200);
    background: var(--sage-50);
}

/* ── Native select hidden (but still submits form) ───────── */
.custom-select select {
    position: absolute;
    width: 0;
    height: 0;
    opacity: 0;
    pointer-events: none;
    overflow: hidden;
}

/* ── Filter-type selects (smaller inline) ────────────────── */
.custom-select-inline .custom-select-trigger {
    padding: 0.25rem 0.5rem;
    font-size: 0.75rem;
    min-height: 1.75rem;
    border-radius: 0.375rem;
}

.custom-select-inline .custom-select-dropdown {
    min-width: 10rem;
}

.custom-select-inline .custom-select-option {
    padding: 0.375rem 0.625rem;
    font-size: 0.75rem;
}

/* ── Mobile ──────────────────────────────────────────────── */
@media (max-width: 639px) {
    .custom-select-dropdown {
        max-height: 12rem;
    }
    .custom-select.open .custom-select-dropdown {
        max-height: 12rem;
    }
}

/* ══════════════════════════════════════════════════════════
   STOCK ENTRY MATRIX — MOBILE (375 px phone optimised)
   ══════════════════════════════════════════════════════════ */

/*
 * Warehouse staff count stock on their phones. The colour×size
 * matrix grid must be usable at 375 px.  Key constraints:
 *   – font-size ≥ 16 px on <input> prevents iOS auto-zoom
 *   – touch targets ≥ 40 px tall
 *   – colour column sticks left, but truncates to save space
 *   – horizontal scroll still works for many-size products
 */

@media (max-width: 639px) {
    /* ── Matrix quantity inputs ─────────────────────────────── */
    .qty-input {
        font-size: 1rem !important;       /* 16 px — prevents iOS zoom */
        width: 2.75rem !important;         /* 44 px — narrower than desktop 64 px */
        min-height: 2.5rem;                /* 40 px touch target */
        padding: 0.375rem 0 !important;    /* vertical only — no side padding */
        border-radius: 0.375rem;
    }

    /* ── Tighter table cell padding ────────────────────────── */
    .product-form table td {
        padding: 0.125rem 0.125rem;
    }
    .product-form table th {
        padding: 0.375rem 0.125rem;
        font-size: 0.5625rem;             /* 9 px — compact headers */
        min-width: unset !important;       /* override inline min-w-[70px] */
        letter-spacing: 0;
    }

    /* ── Sticky colour column — truncated ──────────────────── */
    .product-form td.sticky,
    .product-form th.sticky {
        max-width: 4.5rem;                 /* 72 px */
        padding-left: 0.375rem !important;
        padding-right: 0.25rem !important;
        font-size: 0.6875rem;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    /* ── Row / column / grand total cells ──────────────────── */
    .product-form .row-total,
    .product-form .col-total,
    .product-form .grand-total {
        font-size: 0.6875rem;
        padding: 0.25rem 0.125rem !important;
    }

    /* ── Product card header compact ───────────────────────── */
    .product-form > .px-6 {
        padding: 0.625rem 0.75rem !important;
    }
    .product-form .font-serif {
        font-size: 0.875rem;
    }

    /* ── Product nav chips — horizontal scroll ─────────────── */
    #product-nav > .flex {
        flex-wrap: nowrap;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        padding-bottom: 0.375rem;
        scrollbar-width: none;             /* Firefox */
    }
    #product-nav > .flex::-webkit-scrollbar {
        display: none;                     /* Chrome/Safari */
    }
    .product-chip {
        flex-shrink: 0;
        font-size: 0.75rem;
        padding: 0.375rem 0.625rem;
    }

    /* ── Save bar compact ──────────────────────────────────── */
    #save-bar {
        padding-left: 1rem !important;
        padding-right: 1rem !important;
        padding-top: 0.5rem !important;
        padding-bottom: 0.5rem !important;
    }
    #save-bar .btn-primary {
        padding: 0.375rem 0.875rem;
        font-size: 0.75rem;
    }

    /* ── Session controls card — stack on mobile ───────────── */
    .session-controls {
        flex-direction: column;
        gap: 0.75rem !important;
    }
    .session-controls > div {
        width: 100%;
    }
    .session-controls .form-input,
    .session-controls .custom-select-trigger {
        width: 100%;
    }

    /* ── Add-product section — stack ───────────────────────── */
    .add-product-row {
        flex-direction: column;
        gap: 0.75rem !important;
    }
    .add-product-row > div {
        width: 100%;
        min-width: unset !important;
    }
    .add-product-row .custom-select {
        width: 100%;
    }

    /* ── Batch import row — stack ──────────────────────────── */
    .batch-import-row {
        flex-direction: column;
        gap: 0.75rem !important;
    }
    .batch-import-row > div,
    .batch-import-row > button {
        width: 100%;
        min-width: unset !important;
    }

    /* ── Summary modal — full-width on phone ───────────────── */
    #summary-modal .bg-white {
        margin: 0.25rem;
        max-height: 90vh;
        border-radius: 0.75rem;
    }
    #summary-modal .px-6 {
        padding-left: 1rem;
        padding-right: 1rem;
    }

    /* ── Page header compact ───────────────────────────────── */
    .stock-entry-header {
        flex-wrap: wrap;
        gap: 0.375rem;
    }
    .stock-entry-header h1 {
        font-size: 1.125rem;
    }
    .stock-entry-header .badge {
        font-size: 0.5625rem;
    }
}

/* Read-only matrix quantity display — also needs touch-friendly sizing */
@media (max-width: 639px) {
    .qty-display {
        font-size: 0.875rem;
        min-width: 2.75rem;
        display: inline-block;
        text-align: center;
    }
}

/* ── Reduce motion for accessibility ────────────────────── */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
    html { scroll-behavior: auto; }
}

/* ── Command palette (Ctrl+K) ───────────────────────────────────────────────
   DOM built by static/js/command-palette.js; data from #cmdk-data in base.html. */
.cmdk-overlay {
    position: fixed;
    inset: 0;
    z-index: 80;
    background: rgba(22, 44, 29, 0.32);
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: 12vh 1rem 0;
}
.cmdk-overlay.hidden { display: none; }
.cmdk-panel {
    width: 100%;
    max-width: 34rem;
    background: #fff;
    border: 1px solid var(--sage-200);
    border-radius: 0.75rem;
    box-shadow: 0 16px 48px rgba(22, 44, 29, 0.18);
    overflow: hidden;
    animation: cmdk-pop 0.12s ease-out;
}
@keyframes cmdk-pop {
    from { opacity: 0; transform: translateY(-6px) scale(0.99); }
    to   { opacity: 1; transform: none; }
}
.cmdk-inputrow {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    padding: 0.75rem 1rem;
    border-bottom: 1px solid var(--sage-100);
}
.cmdk-icon { height: 1rem; width: 1rem; color: var(--forest-400); flex-shrink: 0; }
.cmdk-input {
    flex: 1;
    border: none;
    outline: none;
    background: transparent;
    font-size: 0.875rem;
    color: var(--forest-900, #162c1d);
    font-family: inherit;
}
.cmdk-kbd {
    font-size: 0.625rem;
    color: var(--forest-400);
    border: 1px solid var(--sage-200);
    border-radius: 0.25rem;
    padding: 0.0625rem 0.375rem;
}
.cmdk-list { max-height: 19rem; overflow-y: auto; padding: 0.375rem 0 0.5rem; }
.cmdk-group {
    font-size: 0.625rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--forest-400);
    font-weight: 600;
    padding: 0.625rem 1rem 0.25rem;
}
.cmdk-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    margin: 0 0.375rem;
    padding: 0.4375rem 0.625rem;
    border-radius: 0.375rem;
    font-size: 0.8125rem;
    color: #1a2e20;
    cursor: pointer;
}
.cmdk-item.cmdk-sel { background: var(--forest-50); }
.cmdk-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cmdk-hint { font-size: 0.6875rem; color: var(--forest-400); flex-shrink: 0; }
.cmdk-empty { padding: 1.25rem 1rem; font-size: 0.8125rem; color: var(--forest-400); text-align: center; }
.cmdk-foot {
    display: flex;
    gap: 1rem;
    padding: 0.5rem 1rem;
    border-top: 1px solid var(--sage-100);
    font-size: 0.6875rem;
    color: var(--forest-400);
}
.cmdk-foot b {
    font-weight: 500;
    border: 1px solid var(--sage-200);
    border-radius: 0.25rem;
    padding: 0 0.25rem;
    font-size: 0.625rem;
}
.cmdk-foot-right { margin-left: auto; }

/* ── Grid entry (stock supplied / counts / moves / gifting) ────────────────
   Behavior lives in static/js/grid-entry.js. */
/* A counted (non-zero) cell — visibly distinct from untouched ones, so a
   half-done session reads at a glance. */
.qty-input.qty-filled {
    background: var(--forest-50);
    border-color: var(--forest-300);
    font-weight: 600;
    color: var(--forest-800);
}
.key-hint {
    font-weight: 500;
    border: 1px solid var(--sage-200);
    border-radius: 0.25rem;
    padding: 0 0.3125rem;
    font-size: 0.625rem;
    color: var(--forest-900);
    opacity: 0.6;
}

/* Range highlight (Shift+arrows / Shift+click) — the rectangle Ctrl+R/Ctrl+D
   act on. Declared after .qty-filled so selection wins visually. */
.qty-input.qty-range {
    background: var(--forest-100);
    border-color: var(--forest-500);
    box-shadow: inset 0 0 0 1px var(--forest-500);
}

/* ═══════════════════════════════════════════════════════════════════════════
   LAYOUT PRIMITIVES
   ───────────────────────────────────────────────────────────────────────────
   Added 2026-07-20 after the UI audit found the app had a rich COMPONENT
   vocabulary but no LAYOUT vocabulary — so every page hand-rolled its own
   header (20 distinct wrapper chains across 47 pages), its own tab strip (5
   implementations, 3 of them in inline <style>), and its own field labels
   (there was no .form-label at all, which is why 86% of inputs ended up with
   no associated <label>).

   These are the missing primitives. Prefer them over ad-hoc utility chains.
   See docs/ui-professionalism-audit-2026-07-20.md.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Page header ──────────────────────────────────────────────────────────
   Use templates/components/_page_header.html rather than these directly.
   Stacks on mobile: the old hand-rolled headers used `flex items-center
   justify-between` with no wrap, so a title + 2 buttons squashed into one row
   on a 375px phone. */
.page-header {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    margin-bottom: 1.75rem;
}
@media (min-width: 640px) {
    .page-header {
        flex-direction: row;
        align-items: flex-start;
        justify-content: space-between;
        gap: 1rem;
    }
}
.page-header-main { display: flex; align-items: flex-start; gap: 0.875rem; min-width: 0; }
/* 44px icon tile — the #364 pattern, hidden on phones where it costs more
   width than it earns. */
.page-header-icon {
    display: none;
    flex-shrink: 0;
    place-items: center;
    height: 2.75rem;
    width: 2.75rem;
    border-radius: 0.75rem;
    background: var(--forest-50);
    color: var(--forest-600);
    box-shadow: inset 0 0 0 1px var(--forest-100);
}
@media (min-width: 640px) { .page-header-icon { display: grid; } }
.page-header-eyebrow {
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--forest-600);
    margin-bottom: 0.375rem;
}
.page-header-titlerow { display: flex; align-items: center; gap: 0.625rem; flex-wrap: wrap; }
.page-header-title { font-size: 1.5rem; font-weight: 600; letter-spacing: -0.02em; color: var(--forest-900); }
/* AA-safe: the hand-rolled headers used text-gray-400 (#9ca3af, 2.8:1). */
.page-header-sub { font-size: 0.875rem; color: var(--forest-600); margin-top: 0.375rem; max-width: 42rem; line-height: 1.55; }
.page-header-actions { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; flex-shrink: 0; }
.page-header-back {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    font-size: 0.75rem;
    color: var(--forest-600);
    margin-bottom: 0.5rem;
    transition: color 0.15s ease;
}
.page-header-back:hover { color: var(--forest-800); }

/* ── Segmented control ────────────────────────────────────────────────────
   Replaces 4 ad-hoc implementations that used three DIFFERENT active greens.
   The active state is driven by [aria-selected="true"] / .is-active in CSS,
   NOT by JS class-toggling — reporting/home.html styled its tabs only from JS,
   so both tabs rendered identical and unstyled until the script ran (a visible
   flash on every page load). */
.segmented {
    display: inline-flex;
    padding: 0.1875rem;
    border-radius: 0.5rem;
    border: 1px solid var(--sage-200);
    background: var(--sage-50);
    gap: 0.1875rem;
}
.segmented-item {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.375rem;
    min-height: 2.25rem;
    padding: 0.375rem 1rem;
    border-radius: 0.375rem;
    font-size: 0.8125rem;
    font-weight: 500;
    color: var(--forest-600);
    background: transparent;
    border: none;
    cursor: pointer;
    white-space: nowrap;
    transition: background 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
}
.segmented-item:hover { color: var(--forest-800); }
.segmented-item.is-active,
.segmented-item[aria-selected="true"] {
    background: white;
    color: var(--forest-900);
    box-shadow: 0 1px 2px rgba(22, 44, 29, 0.08);
}
.segmented-item:disabled { opacity: 0.5; cursor: not-allowed; }

/* ── Tab strip (underline style) ──────────────────────────────────────────
   Promoted from 3 byte-identical inline <style> copies in production/, all of
   which referenced --gray-400/--gray-700 (tokens that never existed) and so
   fell through to hardcoded, contrast-failing hex. */
.tab-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    min-height: 2.75rem;
    padding: 0.625rem 0.125rem;
    font-size: 0.8125rem;
    font-weight: 500;
    color: var(--forest-600);
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    cursor: pointer;
    white-space: nowrap;
    transition: color 0.15s ease, border-color 0.15s ease;
}
.tab-btn:hover { color: var(--forest-800); }
.tab-btn.active,
.tab-btn[aria-selected="true"] { color: var(--forest-900); border-bottom-color: var(--forest-600); }
/* Horizontally scrollable on narrow screens — _warehouse_nav.html's 4 tabs
   measured ~440px and the last one was clipped and unreachable at 375px. */
.tab-scroll { display: flex; gap: 1.25rem; overflow-x: auto; white-space: nowrap; -ms-overflow-style: none; scrollbar-width: none; }
.tab-scroll::-webkit-scrollbar { display: none; }

/* ── Form primitives ──────────────────────────────────────────────────────
   There was no label class at all before this. */
.form-label {
    display: block;
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--forest-600);
    margin-bottom: 0.375rem;
}
.form-label .form-label-note { text-transform: none; letter-spacing: 0; font-weight: 400; color: var(--forest-500); }
/* Replaces the text-[0.7rem] text-gray-400 helper-text pattern (2.8:1). */
.field-help { font-size: 0.75rem; color: var(--forest-600); margin-top: 0.375rem; line-height: 1.5; }
.field-group + .field-group { margin-top: 1.25rem; }
/* Bordered scroll box for checkbox lists (store pickers, column pickers). */
.checklist {
    border: 1px solid var(--sage-200);
    border-radius: 0.5rem;
    padding: 0.5rem;
    max-height: 9rem;
    overflow-y: auto;
    background: white;
}
/* min-height is the TOUCH TARGET, not decoration: the checkbox glyph is 16px, so
   the clickable <label> row is what has to clear the 36px floor. */
.checklist-item {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-height: 2.25rem;
    padding: 0.375rem 0.375rem;
    font-size: 0.8125rem;
    color: var(--forest-800);
    cursor: pointer;
    border-radius: 0.25rem;
}
/* Same rule for radio rows (store level / view / mode). */
.radio-item {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    min-height: 2.25rem;
    padding: 0.25rem 0.25rem;
    font-size: 0.875rem;
    color: var(--forest-800);
    cursor: pointer;
}
.radio-item input[type="radio"] { accent-color: var(--forest-600); }
.checklist-item:hover { background: var(--sage-50); }
/* 16px minimum — several pickers shipped 12-14px boxes. */
.checklist-item input[type="checkbox"], .check-box { height: 1rem; width: 1rem; accent-color: var(--forest-600); flex-shrink: 0; }

/* ── Card modifiers ───────────────────────────────────────────────────────── */
.card-muted { background: var(--sage-50); }
.card-section-title {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--forest-600);
    margin-bottom: 0.875rem;
}
/* Small numbered step marker, so a multi-part builder reads as a sequence
   rather than as N equal-weight control groups. */
.card-step {
    display: inline-grid;
    place-items: center;
    height: 1.25rem;
    width: 1.25rem;
    border-radius: 9999px;
    background: var(--forest-50);
    color: var(--forest-700);
    font-size: 0.625rem;
    font-weight: 700;
    letter-spacing: 0;
    box-shadow: inset 0 0 0 1px var(--forest-100);
}

/* ── Disabled buttons ─────────────────────────────────────────────────────
   custom.css had NO :disabled rule, yet 5+ call sites set btn.disabled during
   async work — the button stayed full-saturation with a live hover state while
   being unclickable. */
.btn-primary:disabled, .btn-secondary:disabled, .btn-danger:disabled, .btn-chip:disabled {
    opacity: 0.55;
    cursor: not-allowed;
    box-shadow: none;
}
.btn-primary:disabled:hover { background: var(--forest-800); }
.btn-primary:disabled:active, .btn-secondary:disabled:active { transform: none; }

/* Touch-target floor for the chip family — .btn-chip computed to 28.4px and
   .btn-chip-sm to 24.4px, and those are the ONLY controls that accept or
   reject a recommendation in decisions/. */
/* Both variants clear 36px. -sm stays visually smaller (tighter padding, 12px
   text) but is no longer a smaller TARGET — it was 24.4px, and in decisions/ it
   is the control that reverses an accepted recommendation. Row heights in dense
   tables grow slightly; that is the intended trade. */
.btn-chip { min-height: 2.25rem; }
.btn-chip-sm { min-height: 2.25rem; }

/* ── Draggable column picker (reporting builder) ──────────────────────────
   Moved out of an inline <style> in reporting/home.html, which hardcoded
   #f0f5f0 / #cbd5c0 / #6b7280 off-token. The drag handle was #cbd5c0 on white
   — about 1.5:1, i.e. invisible until hover, on the page's only reorder
   affordance. */
.col-row { cursor: grab; display: flex; align-items: center; gap: 0.5rem; padding: 0.375rem 0.5rem; font-size: 0.8125rem; user-select: none; }
.col-row:hover { background: var(--sage-50); }
.col-row.dragging { opacity: 0.4; cursor: grabbing; background: var(--forest-50); }
.col-row.drop-target { border-top: 2px solid var(--forest-500); }
.col-row .drag-handle { color: var(--sage-300); cursor: grab; font-size: 0.95rem; line-height: 1; user-select: none; transition: color 0.15s ease; }
.col-row:hover .drag-handle { color: var(--forest-600); }
.col-row .col-measure { color: var(--gold-500); }

/* ── Product picker (quick-add rows) ──────────────────────────────────────
   Replaces the native <input list="…"> dropdown, which is unstyled browser
   chrome and hides the list until poked (owner, 2026-08-16). On-token, and
   sized so the whole catalogue is scannable without covering the row beneath
   the one being typed into. */
.pp-wrap { position: relative; }
.pp-panel {
    display: none;
    position: absolute;
    z-index: 30;
    top: calc(100% + 0.25rem);
    left: 0;
    /* At least readable, never wider than the screen: on a phone the product
       input is only a few rem wide and the panel inherited that, wrapping every
       product name down one letter per line. */
    width: max(100%, 12rem);
    max-width: min(22rem, 90vw);
    background: #fff;
    border: 1px solid var(--sage-200);
    border-radius: 0.375rem;
    box-shadow: 0 8px 20px -6px rgba(22, 44, 29, 0.18);
    overflow: hidden;
}
.pp-wrap.pp-open .pp-panel { display: block; }
.pp-list { max-height: 15rem; overflow-y: auto; padding: 0.25rem; }
.pp-item {
    display: block;
    width: 100%;
    text-align: left;
    padding: 0.375rem 0.5rem;
    font-size: 0.8125rem;
    color: var(--forest-800);
    background: transparent;
    border: 0;
    border-radius: 0.25rem;
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.pp-item:hover, .pp-item.is-active { background: var(--forest-50); color: var(--forest-900); }
.pp-empty { padding: 0.5rem; font-size: 0.75rem; color: var(--forest-600); }
.pp-foot {
    padding: 0.3125rem 0.625rem;
    border-top: 1px solid var(--sage-100);
    font-size: 0.6875rem;
    color: var(--forest-600);
    background: var(--sage-50);
}

/* ── Product History layout ───────────────────────────────────────────────
   The records have the page to themselves. A products rail used to sit beside
   them (owner, 2026-08-16: "all products visible and filterable"); the owner
   had it removed on 2026-08-18, so the two-column grid, the rail and the rail's
   own link styling went with it. The pp-* rules below did NOT — those belong to
   the quick-add product picker, which is a different control.

   min-width: 0 stays: the wide records table has to shrink and scroll inside
   its own wrapper rather than push the page sideways.

   Written here rather than as Tailwind utilities on the element: the
   production stylesheet is TREE-SHAKEN from a scan of the templates, and a
   layout that silently loses its rules in prod while looking right in dev is a
   failure this codebase has already had once (the decisions bulk-bar). */
.history-records { min-width: 0; }

/* The picker panel overflows the entry row and has to paint over the records
   below it. z-index on the panel is NOT enough inside a <table>: a later cell
   still wins, and so does raising the cell the panel lives in. Verified in the
   browser — lifting the ROW is what works. */
.quick-add-row { position: relative; z-index: 20; }

/* Keep the columns that carry NAMES readable.
   The entry row's date fields are native controls with a fixed intrinsic width
   that ignores whatever the column wants. Measured on Discounts at 1440px: the
   two date pickers took 296px of a 657px row, leaving the Product field 63px and
   Store 46px — the placeholders rendered as "Produc!" and "Ston", and the product
   name wrapped onto two lines. Capping the dates at what they actually need hands
   that space back to the fields being typed into. */
.history-records .quick-add-row input[type="date"] { width: 8rem; min-width: 0; }
.history-records .data-table th:first-child,
.history-records .data-table td:first-child { min-width: 10rem; }
/* A floor so the row never crushes: below this the wrapper scrolls, which is the
   honest outcome on a narrow screen. Sized for the widest of the three (Discounts:
   product + store + discount + two dates + actions). */
.history-records .data-table { min-width: 40rem; }
/* Slightly tighter gutters than a read-only table. These carry an inline entry
   row, so every column holds a CONTROL rather than a word, and the standard 16px
   gutters spent 192px of a 750px table on whitespace — enough that "Store" could
   not render its own placeholder. 12px keeps the same rhythm and buys the row back. */
.history-records .data-table th,
.history-records .data-table td { padding-left: 0.75rem; padding-right: 0.75rem; }

/* The card head on the Product History pages: a long title next to an action.
   On a phone both were wrapping — "COGS history — all products" over two lines
   and "+ Add COGS" broken across two as well, which is the scruffiest thing on
   the page. The title gives way, the action never breaks. */
.history-card-head { gap: 0.75rem; }
.history-card-head h2 { min-width: 0; }
.history-card-head .btn-primary { white-space: nowrap; flex-shrink: 0; }

/* ── Production batch — Items table ────────────────────────────────────────
   production/batch_detail.html, the Items tab.

   ALIGNMENT IS PER COLUMN, NOT PER CELL. The table used to set `text-right` on
   every header and then let each <td> choose for itself; the cells drifted out of
   agreement with the headers above them (a right-aligned "Received vs target"
   header over a left-reading "awaiting receipt" cell, etc.) and the whole table
   read as crooked. Now one class per column is carried by BOTH the <th> and every
   <td> under it, so the two cannot disagree — text left, numbers right.
   These beat `.data-table thead th`/`.data-table tbody td` on specificity
   (two classes + an element vs one class + two elements). */
.items-table th.col-text,
.items-table td.col-text { text-align: left; }

.items-table th.col-num,
.items-table td.col-num,
.items-table th.col-act,
.items-table td.col-act { text-align: right; }

/* The Target cell holds an <input>, and the control's own right padding (0.75rem)
   plus its border sits between the digits and the cell's right edge — so a header
   flush to that edge floats a whole pad-width right of the numbers it labels. Pad
   the header by the same amount and the word lands over the digits. */
.items-table th.col-target { padding-right: calc(1rem + 0.75rem + 1px); }

/* ── Lines with no target ─────────────────────────────────
   "If the target is 0 units, don't clutter" (owner, 2026-08-17). Hidden, NOT
   removed: the row stays in the DOM with its editable target input, one click
   from view. The toggle is a checkbox + label rather than script, so the reveal
   survives a JS error on the page and adds no handler to collide with. */
.items-table tbody tr.no-target-row { display: none; }
.items-table:has(.no-target-toggle:checked) tbody tr.no-target-row { display: table-row; }

.items-table td.no-target-foot { padding: 0.625rem 1rem; }

/* The checkbox is the state; the label is the control. Kept in the layout (not
   display:none) so it stays focusable and the keyboard can toggle it. */
.items-table .no-target-toggle {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}

.items-table .no-target-label {
    display: inline-flex;
    align-items: center;
    font-size: 0.75rem;
    font-weight: 500;
    color: var(--forest-600);
    cursor: pointer;
    border-bottom: 1px dashed var(--sage-300);
    padding-bottom: 1px;
    transition: color 0.15s ease, border-color 0.15s ease;
}

.items-table .no-target-label:hover {
    color: var(--forest-800);
    border-bottom-color: var(--forest-600);
}

.items-table .no-target-toggle:focus-visible + .no-target-label {
    outline: 2px solid var(--forest-600);
    outline-offset: 2px;
    border-radius: 2px;
}

/* One label, two readings — the word flips with the state it will move to. */
.items-table .no-target-when-shown { display: none; }
.items-table:has(.no-target-toggle:checked) .no-target-when-hidden { display: none; }
.items-table:has(.no-target-toggle:checked) .no-target-when-shown { display: inline; }

/* ── Production batch — "Add Product to Batch" colour rows ─────────────────
   production/batch_detail.html, under the Items table. One row per colour of the
   chosen product, each with a target quantity.

   WHY THESE RULES ARE HERE AND NOT IN THE TEMPLATE'S <style> OR IN TAILWIND
   tailwind.min.css is generated at deploy time from the content globs in
   web/tailwind.config.js, so a utility class that only ever appears inside a JS
   string concatenation can be tree-shaken out of the production build — the config's
   own note records that happening to the decisions bulk-bar's translate-y-full. These
   classes are applied by classList.toggle from JS and would be exactly that case.
   custom.css ships whole, so a rule keyed on a semantic class here cannot be shaken
   out, and the alignment rules above already made this file the batch page's home.

   ONE STATE, NOT TWO. `.is-excluded` means one thing: this colour is not part of the
   order and pressing "Add to Batch" will not create a line for it. Only a positive
   WHOLE number of units clears it (owner, 2026-08-17) — blank, 0, negative and
   fractional are all the same non-order. The strike-through and the red field are two
   faces of that single state, driven by the single isExcludedQty predicate in the
   template, and the server refuses the same values in
   BatchItemService.validate_quantities. A colour the user sees refused that still gets
   written (or the reverse) is the one genuinely bad outcome here, so the visual, the
   submit filter and the write path all read from the same rule. */
.colour-row-entry {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.colour-row-entry .colour-name {
    min-width: 120px;
    font-size: 0.875rem;
    color: var(--forest-800, #26422f);
}

.colour-row-entry.is-excluded .colour-name {
    text-decoration: line-through;
    color: var(--forest-400, #78a085);
}

/* The field itself carries the refusal, because the field is what the user has to fix.
   Beats `.form-input` (one class) and `.form-input:focus` (two) on specificity, so the
   red survives focus — the value is still not orderable while you are standing in it. */
.colour-row-entry.is-excluded .colour-qty {
    border-color: #dc2626;
    background: #fef2f2;
}

.colour-row-entry.is-excluded .colour-qty:focus {
    border-color: #dc2626;
    box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.12);
}

.colour-row-entry.is-new-colour .colour-name::after {
    content: " new";
    /* inline-block so the is-excluded line-through above does NOT propagate into this
       badge — a descendant cannot cancel an inherited text-decoration, but an atomic
       inline-level box is never crossed by its ancestor's line. */
    display: inline-block;
    margin-left: 0.375rem;
    font-size: 0.625rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    text-decoration: none;
    color: var(--forest-500, #4e7a5d);
}

/* ── Batches: a product opening onto its production runs ──────────────────
   Written here rather than as Tailwind utilities on the elements: the production
   stylesheet is TREE-SHAKEN from a scan of the templates, and a layout that looks
   right in dev and loses its rules in prod is a failure this codebase has had. */
.batch-product-row { cursor: pointer; }
.batch-product-row:hover { background: var(--forest-50); }
.batch-caret {
    width: 0.75rem; height: 0.75rem; display: inline-block; vertical-align: -1px;
    margin-right: 0.35rem; color: var(--forest-500);
    transition: transform 120ms ease;
}
.batch-product-row[aria-expanded="true"] .batch-caret { transform: rotate(90deg); }
.batch-detail-row > td { background: var(--sage-50); }
.batch-inner { width: 100%; border-collapse: collapse; font-size: 0.8125rem; }
.batch-inner th {
    text-align: left; padding: 0.5rem 1.5rem; font-size: 0.6875rem;
    text-transform: uppercase; letter-spacing: 0.04em; color: var(--forest-600);
}
.batch-inner td { padding: 0.5rem 1.5rem; border-top: 1px solid var(--sage-100); }
.batch-inner .text-right { text-align: right; }

/* ── Printable garment labels ─────────────────────────────────────────────
   REBUILT 2026-08-19 ("the UI for labels page is very poor"). The old sheet used
   grid auto-fill with max-content tracks; against a 101mm-wide barcode that
   resolved to ONE column, so the page read as a loose vertical stack of images.
   Flex-wrap on natural-width cards tiles predictably, because the card is as wide
   as the code inside it and nothing has to guess a track size. */
.label-group { margin-bottom: 2rem; }
.label-group-title {
    font-family: var(--font-serif, Georgia, serif);
    font-size: 1rem; color: var(--forest-900);
    margin: 0 0 0.75rem; display: flex; align-items: baseline; gap: 0.5rem;
}
.label-group-title span { font-family: inherit; font-size: 0.75rem; color: var(--forest-500); }

.label-sheet { display: flex; flex-wrap: wrap; gap: 5mm; align-items: flex-start; }

.label-card {
    border: 1px solid var(--sage-200); border-radius: 0.25rem;
    padding: 3mm 3mm 2mm; background: #fff;
    break-inside: avoid; page-break-inside: avoid;
    margin: 0;                      /* <figure> carries a default margin */
    display: inline-flex; flex-direction: column; gap: 1.5mm;
}
.label-head { display: flex; flex-direction: column; line-height: 1.25; }
.label-product { font-size: 3.2mm; font-weight: 600; color: #000; }
.label-variant { font-size: 2.8mm; color: #444; }
.label-bars { line-height: 0; }     /* kill the inline-SVG descender gap */
.label-bars svg { display: block; }
.label-foot {
    font-size: 0.6875rem; color: var(--forest-500);
    border-top: 1px solid var(--sage-100); padding-top: 1.5mm;
}

@media print {
    /* Everything that is not a label is noise on a sheet of garment tags. */
    .no-print, .page-header, nav, header, footer, aside { display: none !important; }
    .label-card { border-color: #000; }
    .label-sheet { gap: 3mm; }
    .label-group { margin-bottom: 0; }
}
}
