/* Self-hosted Manrope variable font (latin + latin-ext), weight range 200–800.
   Declared HERE — not via @import or a per-page <link> — so EVERY page that
   loads design-system.css (every route incl. the standalone homepage) gets
   --font-sans for free, with no extra request. No runtime Google Fonts CDN
   (privacy). The woff2s live in /public/fonts/manrope/. */
@font-face{font-family:'Manrope';font-style:normal;font-weight:200 800;font-display:swap;src:url('/fonts/manrope/manrope-var-latin.woff2') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}
@font-face{font-family:'Manrope';font-style:normal;font-weight:200 800;font-display:swap;src:url('/fonts/manrope/manrope-var-latin-ext.woff2') format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}

/*
 * Design System — single source of truth for brand colors and tokens.
 * Load this BEFORE dark-mode.css so that --accent is defined before rules reference it.
 * To change the brand color: edit --brand here. Everything cascades automatically.
 */

:root {
  /* Type-family tokens — mirror brand/brand.css @theme. Defined HERE too because
     the standalone homepage (index.hbs) loads design-system.css but NOT
     tailwind.css (where @theme normally emits these), so without this the
     homepage's `font-family: var(--font-sans)` resolved to nothing → system
     serif. Keep in sync with brand/brand.css. */
  --font-sans: 'Manrope', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, 'Courier New', monospace;

  /* Icon tokens (Lucide, as mask-image data-URIs) — global; tint via background-color: currentColor. */
  --icon-sun: url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2024%2024'%20fill%3D'none'%20stroke%3D'%23000'%20stroke-width%3D'2'%20stroke-linecap%3D'round'%20stroke-linejoin%3D'round'%3E%3Ccircle%20cx%3D'12'%20cy%3D'12'%20r%3D'4'%2F%3E%3Cpath%20d%3D'M12%202v2'%2F%3E%3Cpath%20d%3D'M12%2020v2'%2F%3E%3Cpath%20d%3D'm4.93%204.93%201.41%201.41'%2F%3E%3Cpath%20d%3D'm17.66%2017.66%201.41%201.41'%2F%3E%3Cpath%20d%3D'M2%2012h2'%2F%3E%3Cpath%20d%3D'M20%2012h2'%2F%3E%3Cpath%20d%3D'm6.34%2017.66-1.41%201.41'%2F%3E%3Cpath%20d%3D'm19.07%204.93-1.41%201.41'%2F%3E%3C%2Fsvg%3E");
  --icon-moon: url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2024%2024'%20fill%3D'none'%20stroke%3D'%23000'%20stroke-width%3D'2'%20stroke-linecap%3D'round'%20stroke-linejoin%3D'round'%3E%3Cpath%20d%3D'M12%203a6%206%200%200%200%209%209%209%209%200%201%201-9-9Z'%2F%3E%3C%2Fsvg%3E");
    /* Brand */
    --brand:        #8b5cf6;
    --brand-dark:   #7c3aed;
    --brand-hover:  #a78bfa;
    --color-on-brand: #ffffff;
    --brand-glow:   rgba(139, 92, 246, 0.30);
    --brand-faint:  rgba(139, 92, 246, 0.08);
    --brand-border: rgba(139, 92, 246, 0.18);

    /* Logo — theme-aware brand mark (faceted "Fi" icon, no background; sits
       inline as the leading "Fi" of the wordmark). Swap these two URLs (here +
       the [data-theme="dark"] block) to replace the logo everywhere at once. */
    --logo-mark: url("/img/fi-icon-light-nobg-shadow.svg?v=20260713d");   /* light mode: strong drop shadow */

    /* Bridge — existing code uses --accent; this maps it to the brand */
    --accent:       var(--brand);
    --accent-hover: var(--brand-dark);

    /* Page backgrounds — light mode: lavender tint matching the homepage.
       --bg-primary is the page bg, --bg-secondary is what cards sit at
       (--surface aliases this). 2026-05-20 polish: bumped --bg-secondary
       from pure white to #f4f4f5 light grey so cards read uniformly
       across the app instead of clashing white-on-lavender. */
    --bg-primary:   #e8e4f5;
    --bg-secondary: #f4f4f5;
    --bg-tertiary:  #ddd6f0;

    /* Text — three tiers in dark mode, two effectively in light mode.
       --text-muted was #9ca3af until 2026-05-20 — too washed-out for
       all the "small meta caption" surfaces (tab counts, listing IDs,
       action hints, drag tips, etc.). Bumped to match --text-secondary
       so every --text-3 reference darkens uniformly in light mode.
       2026-06-08: both bumped #6b7280 → #4b5563 (gray-500 → gray-600) —
       secondary/muted captions (order-detail labels, money rows, meta)
       were still hard to read on the tinted card backgrounds.
       Dark mode keeps a distinct third tier below (see [data-theme="dark"]). */
    --text-primary:   #111827;
    --text-secondary: #4b5563;
    --text-muted:     #4b5563;

    /* Borders & shadows */
    --border-color: rgba(139, 92, 246, 0.14);
    --border-light: rgba(139, 92, 246, 0.08);
    --shadow:       rgba(139, 92, 246, 0.10);
    --shadow-hover: rgba(139, 92, 246, 0.20);

    /* Wizard-layout aliases — setup.hbs CSS uses these shorter names */
    --text:       var(--text-primary);
    --muted:      var(--text-secondary);
    --muted-light: var(--text-muted);
    --bg:         var(--bg-primary);
    --card:       var(--bg-secondary);
    --border:     var(--border-color);
    --error:      #dc2626;

    /* product-management.hbs aliases */
    --card-bg:    var(--bg-secondary);
    /* Form inputs go white in light mode so they stand out against
       --surface (now #f4f4f5 grey). Was --bg-tertiary lavender before
       2026-05-20. Dark mode keeps --bg-primary so inputs are darker
       than --surface there. */
    --input-bg:   #ffffff;

    /* Status — unchanged */
    --success:       #16a34a;
    --success-hover: #15803d;
    --success-light: #4ade80;   /* success text on dark surfaces */
    --color-success-emerald: #10b981;   /* emerald data-viz green (index status-card SVGs); mirrors brand.css — needed here because brand.css/tailwind.css aren't loaded on every route */
    --danger:        #dc2626;
    --danger-hover:  #b91c1c;
    --danger-light:  #fca5a5;   /* danger text on dark surfaces */
    --warning:       #d97706;
    --warning-text:  #b45309;   /* warning text (darker amber for contrast) */

    /* Insight / info boxes */
    --insight-bg:     #fffbeb;
    --insight-border: #fbbf24;
    --insight-text:   #92400e;

    /* Brand UI primitives — lifted from the index redesign so all routes share it.
       Composite shadow values intentionally NOT reusing --shadow (which is a color). */
    --surface:           var(--bg-secondary);
    --text-2:            var(--text-secondary);
    --text-3:            var(--text-muted);
    --border-h:          rgba(139, 92, 246, 0.36);
    --shadow-card:       0 2px 4px rgba(0, 0, 0, 0.05), 0 6px 20px rgba(139, 92, 246, 0.12);
    --shadow-card-hover: 0 8px 32px rgba(139, 92, 246, 0.22), 0 16px 48px rgba(0, 0, 0, 0.09);
    --header-bg:         rgba(232, 228, 245, 0.85);

    /* ── Mobile sizing scale ──
       Reusable tokens for any route's @media (max-width: 768px) block. Don't
       reinvent these per-route — reference `var(--m-tap)` etc. instead. The
       scale is calibrated against Apple HIG (44px tap minimum) + the iOS
       16px input rule (anything smaller triggers focus-zoom). */
    --m-tap:           44px;   /* secondary actions, checkboxes, icon buttons */
    --m-tap-lg:        48px;   /* form inputs, generic buttons */
    --m-tap-xl:        52px;   /* primary CTAs */
    --m-input-min-fs:  16px;   /* defeats iOS focus-zoom on <input> */

    --m-thumb-sm:      56px;   /* compact list thumb on phone */
    --m-thumb-md:      72px;   /* medium list thumb on phone */

    --m-page-title:    1.5rem;
    --m-section-title: 1.2rem;
    --m-subsection:    1.05rem;
    --m-body:          0.9rem;
    --m-small:         0.78rem;
    --m-meta:          0.82rem;

    --m-radius:        12px;
    --m-radius-lg:     16px;
    --m-gap:           12px;
    --m-pad:           16px;
    --m-pad-sm:        10px;
    --m-pad-xs:        8px;

    --m-top-bar-h:     56px;   /* main.hbs .mobile-top-header */
    --m-bottom-bar-h:  72px;   /* bottom-tabs nav (content height; safe-area inset added on top) */
    --m-drawer-w:      280px;  /* sidebar off-canvas drawer */
}

/* Shared SEO assessment metadata. The score presentation remains surface-specific;
   this compact block is shared by the authenticated and public SEO results. */
.seo-assessment-meta {
  display: grid;
  gap: 0.75rem;
  margin: 0 0 1.5rem;
  padding: 1rem 1.1rem;
  border: 1px solid var(--brand-border);
  border-radius: 0.75rem;
  background: linear-gradient(135deg, var(--brand-faint), var(--bg-secondary) 42%);
  box-shadow: 0 0.25rem 1rem var(--shadow);
  color: var(--text-secondary);
}
.seo-assessment-result-component {
  display: grid;
  gap: 0.85rem;
  margin: 0 0 1.5rem;
}
.seo-assessment-score-head {
  display: flex;
  align-items: end;
  justify-content: space-between;
  gap: 1rem;
}
.seo-assessment-score-head > div { display: grid; gap: 0.15rem; }
.seo-assessment-score-head strong { color: var(--text-primary); font-size: var(--text-lg); }
.seo-assessment-authority {
  padding: 0.25rem 0.55rem;
  border: 1px solid var(--brand-border);
  border-radius: 9999px;
  color: var(--brand-dark);
  background: var(--brand-faint);
  font-size: var(--text-2xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.seo-assessment-breakdown {
  display: grid;
  gap: 0.65rem;
  padding: 0.9rem 1rem;
  border: 1px solid var(--border-light);
  border-radius: 0.75rem;
  background: var(--bg-secondary);
}
.seo-assessment-breakdown-row { display: grid; gap: 0.35rem; }
.seo-assessment-breakdown-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  color: var(--text-secondary);
  font-size: var(--text-xs);
}
.seo-assessment-breakdown-head span { display: inline-flex; align-items: center; gap: 0.35rem; }
.seo-assessment-breakdown-head svg { width: 0.9rem; height: 0.9rem; fill: none; stroke: currentColor; stroke-width: 2; }
.seo-assessment-breakdown-head strong { color: var(--text-primary); font-size: var(--text-2xs); }
.seo-assessment-breakdown progress { width: 100%; height: 0.35rem; accent-color: var(--brand); }
.seo-assessment-breakdown-row--good progress { accent-color: var(--success); }
.seo-assessment-breakdown-row--warn progress { accent-color: var(--warning); }
.seo-assessment-breakdown-row--muted progress { accent-color: var(--text-muted); }
.seo-assessment-findings { display: grid; gap: 0.45rem; }
.seo-assessment-findings ul { display: grid; gap: 0.35rem; margin: 0; padding: 0; list-style: none; }
.seo-assessment-findings li { display: flex; align-items: flex-start; gap: 0.45rem; color: var(--text-secondary); font-size: var(--text-xs); }
.seo-assessment-findings li svg { width: 0.9rem; height: 0.9rem; flex: 0 0 auto; margin-top: 0.1rem; fill: none; stroke: var(--warning); stroke-width: 2; }
.seo-assessment-finding--good svg { stroke: var(--success); }
.seo-assessment-meta-head,
.seo-assessment-judge,
.seo-assessment-confidence {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  flex-wrap: wrap;
}
.seo-assessment-meta-head { justify-content: space-between; }
.seo-assessment-title { display: flex; align-items: center; gap: 0.65rem; }
.seo-assessment-title > div { display: grid; gap: 0.12rem; }
.seo-assessment-title strong { color: var(--text-primary); font-size: var(--text-sm); }
.seo-assessment-mark {
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  border-radius: var(--radius-md);
  color: var(--brand);
  background: var(--brand-faint);
  border: 1px solid var(--brand-border);
}
.seo-assessment-mark svg { width: 1.1rem; height: 1.1rem; fill: none; stroke: currentColor; stroke-width: 2; }
.seo-assessment-build,
.seo-assessment-judge-state {
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  color: var(--text-muted);
}
.seo-assessment-judge {
  justify-content: flex-start;
  padding: 0.7rem 0.75rem;
  border: 1px solid var(--border-light);
  border-radius: var(--radius-md);
  background: var(--bg-secondary);
  font-size: var(--text-xs);
}
.seo-assessment-status-dot { width: 0.55rem; height: 0.55rem; border-radius: var(--radius-full); background: var(--text-muted); flex: 0 0 auto; }
.seo-assessment-judge--available .seo-assessment-status-dot { background: var(--success); }
.seo-assessment-judge--unavailable .seo-assessment-status-dot { background: var(--warning); }
.seo-assessment-judge-copy {
  display: grid;
  gap: 0.15rem;
  flex: 1 1 18rem;
}
.seo-assessment-judge-copy strong { color: var(--text-primary); }
.seo-assessment-judge--available .seo-assessment-judge-state { color: var(--success); }
.seo-assessment-judge--unavailable .seo-assessment-judge-state { color: var(--warning); }
.seo-assessment-result { display: grid; gap: 0.55rem; }
.seo-assessment-confidence { justify-content: space-between; font-size: var(--text-xs); }
.seo-assessment-confidence strong { color: var(--text-primary); }
.seo-assessment-dimensions { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.seo-assessment-dimension { display: inline-flex; align-items: center; gap: 0.35rem; padding: 0.28rem 0.5rem; border: 1px solid var(--border-light); border-radius: var(--radius-full); background: var(--bg-secondary); font-size: var(--text-2xs); }
.seo-assessment-dimension span { color: var(--text-secondary); }
.seo-assessment-dimension strong { color: var(--brand-dark); }
.seo-assessment-evidence-wrap { border-top: 1px solid var(--border-light); padding-top: 0.55rem; font-size: var(--text-xs); }
.seo-assessment-evidence-wrap summary { cursor: pointer; color: var(--brand-dark); font-weight: 700; }
.seo-assessment-evidence {
  display: grid;
  gap: 0.3rem;
  margin: 0;
  padding: 0.55rem 0 0 1rem;
  border-top: 1px solid var(--border-light);
  font-size: var(--text-xs);
}
.seo-assessment-evidence span {
  color: var(--accent);
  font-weight: 700;
  text-transform: capitalize;
}
@media (max-width: 640px) {
  .seo-assessment-meta { padding: 0.85rem; }
  .seo-assessment-build { width: 100%; }
  .seo-assessment-judge-state { margin-left: 1.2rem; }
}

/* Dark mode — material-tracking purple style */
[data-theme="dark"] {
    /* Logo — dark-mode brand mark (lighter "Fi" facets for dark bg). Swap to replace. */
    --logo-mark: url("/img/fi-icon-dark-nobg-shadow.svg?v=20260713d");

    /* Bridge */
    --accent:       var(--brand);
    --accent-hover: var(--brand-hover);

    /* Page backgrounds — deep purple-dark */
    --bg-primary:   #221629;
    --bg-secondary: #2b1d38;
    --bg-tertiary:  #352644;

    /* Text */
    --text-primary:   #f3f4f6;
    --text-secondary: #9ca3af;
    --text-muted:     #8b91a0;  /* lifted from #6b7280 — readable on the lighter dark-purple bg */

    /* Borders & shadows */
    --border-color: rgba(167, 139, 250, 0.16);
    --border-light: rgba(167, 139, 250, 0.08);
    --shadow:       rgba(0, 0, 0, 0.40);
    --shadow-hover: rgba(0, 0, 0, 0.60);

    /* Insight boxes — purple-tinted in dark mode */
    --insight-bg:     rgba(139, 92, 246, 0.12);
    --insight-border: #8b5cf6;
    --insight-text:   #c7b3ff;

    /* Wizard-layout aliases (dark mode overrides) */
    --text:       var(--text-primary);
    --muted:      var(--text-secondary);
    --muted-light: var(--text-muted);
    --bg:         var(--bg-primary);
    --card:       var(--bg-secondary);
    --border:     var(--border-color);

    /* product-management.hbs aliases (dark mode) */
    --card-bg:    var(--bg-secondary);
    --input-bg:   var(--bg-primary);

    /* Brand UI primitive overrides for dark mode */
    --surface:           var(--bg-secondary);
    --text-2:            var(--text-secondary);
    --text-3:            var(--text-muted);
    --border-h:          rgba(167, 139, 250, 0.35);
    --shadow-card:       0 2px 6px rgba(0, 0, 0, 0.30), 0 8px 24px rgba(0, 0, 0, 0.38);
    --shadow-card-hover: 0 10px 34px rgba(0, 0, 0, 0.50), 0 0 0 1px rgba(167, 139, 250, 0.18);
    --header-bg:         rgba(34, 22, 41, 0.88);
}

/* Light mode page background — lavender gradient behind the sidebar layout */
body {
    background: var(--bg-primary);
}

/* Dark mode body gradient — replaces the old blue navy gradient */
[data-theme="dark"] body {
    background: linear-gradient(135deg, #221629 0%, #352644 100%) !important;
    background-attachment: fixed !important;
}

/* ============================================================
   Brand UI Primitives
   Lifted from the index redesign; shared across all routes.
   Class names mirror what index.hbs already uses, so it's a
   drop-in shared rule. Per-route inline <style> blocks will
   continue to win until they are removed.
   ============================================================ */

body {
    font-family: var(--font-sans);
    font-weight: 500; /* Manrope reads clean at medium; headings still set 600-800 */
    color: var(--text-primary);
    min-height: 100vh;
    -webkit-font-smoothing: antialiased;
}

/* ── Dark-mode toggle icon — CSS-token mask (var(--icon-sun) / var(--icon-moon),
   defined in :root above). GLOBAL: drives the sidebar pill, homepage header, and
   setup with no markup. Shows the current theme (sun in light, moon in dark),
   tinted via background-color. Reuse the tokens anywhere: mask + currentColor. ── */
.dark-mode-toggle,
.dark-mode-toggle-header { position: relative; }
.dark-mode-toggle::after,
.dark-mode-toggle-header::after {
    content: '';
    background-color: currentColor;
    -webkit-mask: var(--icon-sun) center / contain no-repeat;
    mask: var(--icon-sun) center / contain no-repeat;
    pointer-events: none;
}
[data-theme="dark"] .dark-mode-toggle::after,
[data-theme="dark"] .dark-mode-toggle-header::after {
    -webkit-mask-image: var(--icon-moon);
    mask-image: var(--icon-moon);
}
/* Homepage header: simple inline glyph. */
.dark-mode-toggle-header::after { display: inline-block; width: 18px; height: 18px; vertical-align: middle; }
/* Sidebar pill: icon rides the sliding knob (knob + pill chrome are in sidebar.css). */
.dark-mode-toggle::after {
    position: absolute; top: 7px; left: 7px;
    width: 12px; height: 12px; z-index: 1;
    transition: transform 0.3s;
    background-color: var(--warning);
}
[data-theme="dark"] .dark-mode-toggle::after {
    transform: translateX(22px);
    background-color: var(--brand);
}

/* ── Sticky brand header — homepage (index.hbs) ONLY.
   Scoped to a *classless* <header> so it can't leak onto the shared
   page-header partial (<header class="page-header">) or any other
   class'd <header> (mobile-top-header, dialog headers) — those set
   their own layout and must not inherit this flex/sticky/56px bar. ── */
header:not([class]) {
    position: sticky;
    top: 0;
    z-index: 100;
    height: 56px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 2rem;
    background: var(--header-bg);
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    border-bottom: 1px solid var(--border-color);
}

/* ── Brand lockup (CENTRAL — single source of truth) ──
   Faceted "Fi" mark + slanted "ndig" tail read as "Findig". Rendered by the
   brand-lockup partial in every header/brand spot; positioning is added by a
   context class (.logo, .mobile-top-logo, .setup-brand). Do NOT fork these. */
.brand-lockup {
    display: inline-flex;
    align-items: center;
    /* Tight: the "Fi" mark is the leading letters, so it butts against "ndig"
       and reads as a single word. */
    gap: 0;
    font-weight: 800;
    color: var(--text-primary);
    letter-spacing: -0.025em;
    text-decoration: none;
    user-select: none;
}
.brand-mark {
    /* Faceted "Fi" mark is landscape (~1.48:1) — size to aspect so it reads as
       the leading letters, not a floating badge. Theme-aware via --logo-mark. */
    width: 50px;
    height: 34px;
    background-image: var(--logo-mark);
    background-repeat: no-repeat;
    background-position: center;
    background-size: contain;
    flex-shrink: 0;
}
.brand-word {
    /* Sized to balance the mark, slanted (skewX, stronger than the ~14°
       faux-italic) to match the logo's forward lean; negative margin tucks it
       under that lean. */
    font-size: var(--text-2xl);
    display: inline-block;
    transform: skewX(-20deg);
    transform-origin: left bottom;
    margin-left: -9px;
}

.header-right {
    display: flex;
    align-items: center;
    gap: 8px;
    position: relative;
}

/* ── Buttons ── */

/* Base class — provides structural properties; variant classes add color/shadow.
   Use standalone when no colour variant applies (neutral/ghost appearance). */
.btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-family: inherit;
    font-weight: 600;
    cursor: pointer;
    text-decoration: none;
    border: none;
    border-radius: 8px;
    letter-spacing: -0.01em;
    transition: all 0.15s;
    padding: 8px 16px;
    font-size: var(--text-sm);
    color: var(--text-2);
    background: transparent;
}
.btn[hidden] { display: none; }

/* Canonical leading icon inside any .btn / .btn-* . A bare <use> SVG with only a
   viewBox has no intrinsic size and balloons to ~300×150 — pin it to 16px and let
   it inherit the button's text colour (Lucide symbols are stroke="currentColor"). */
.btn-icon {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
    stroke: currentColor;
    fill: none;
}

/* NOTE: .btn-sm and .btn-lg are defined AFTER all variants (near .btn-secondary)
   so their padding/font-size wins the cascade over variant defaults. */

.btn-ghost {
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--text-2);
    background: none;
    border: none;
    cursor: pointer;
    padding: 6px 10px;
    border-radius: 7px;
    text-decoration: none;
    transition: color 0.15s, background 0.15s;
    display: inline-flex;
    align-items: center;
}
.btn-ghost:hover {
    color: var(--text-primary);
    background: var(--brand-faint);
}
/* `display: inline-flex` above outranks the UA `[hidden] { display: none }`,
   so the HTML hidden attribute (and `el.hidden = true` from JS) needs a
   class-specificity rule to actually hide the element. */
.btn-ghost[hidden] { display: none; }

.btn-primary {
    font-size: var(--text-sm);
    font-weight: 700;
    color: #fff;
    background: linear-gradient(135deg, var(--brand) 0%, var(--brand-dark) 100%);
    border: none;
    cursor: pointer;
    padding: 8px 16px;
    border-radius: 8px;
    box-shadow: 0 2px 10px var(--brand-glow);
    transition: transform 0.15s, box-shadow 0.15s;
    letter-spacing: -0.01em;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.btn-primary:hover {
    transform: translateY(-1px);
    box-shadow: 0 4px 16px var(--brand-glow);
    color: #fff;
}
/* Full-width block primary (e.g. plan CTA) */
.btn--block {
    width: 100%;
    padding: 12px 16px;
    font-size: var(--text-base);
    border-radius: 10px;
    justify-content: center;
}

/* Disabled state for the canonical action buttons (was previously only on route forks) */
.btn-primary:disabled,
.btn-secondary:disabled {
    opacity: 0.6;
    cursor: not-allowed;
    box-shadow: none;
    transform: none;
}

.btn-hero {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    background: linear-gradient(135deg, var(--brand) 0%, var(--brand-dark) 100%);
    color: #fff;
    border: none;
    padding: 13px 28px;
    border-radius: 12px;
    font-size: var(--text-base);
    font-weight: 700;
    cursor: pointer;
    box-shadow: 0 4px 20px var(--brand-glow);
    transition: transform 0.18s ease, box-shadow 0.18s ease;
    letter-spacing: -0.01em;
    text-decoration: none;
}
.btn-hero:hover {
    transform: translateY(-2px);
    box-shadow: 0 8px 32px var(--brand-glow);
    color: #fff;
}

.btn-link {
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--text-2);
    background: none;
    border: none;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    text-decoration: none;
    transition: color 0.15s;
}
.btn-link:hover { color: var(--brand); }

/* ── Profile menu (header avatar + dropdown) ── */
.profile-btn {
    width: 32px;
    height: 32px;
    min-width: 32px;
    min-height: 32px;
    aspect-ratio: 1 / 1;
    border-radius: 50%;
    background: linear-gradient(135deg, var(--brand) 0%, var(--brand-dark) 100%);
    border: none;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    box-shadow: 0 2px 8px var(--brand-glow);
    transition: transform 0.15s, box-shadow 0.15s;
    position: relative;
}
/* Fill via inset:0 — a flex-item img with an intrinsic aspect ratio collapses to
   its aspect-scaled size (portrait photo → oval under border-radius) instead of
   filling. White backdrop shows only for transparent logos, never purple. */
.profile-btn-img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: 50%;
    background: var(--input-bg);
    display: block;
    pointer-events: none;
}
.profile-btn:hover {
    transform: scale(1.08);
    box-shadow: 0 4px 12px var(--brand-glow);
}
.profile-btn-initials {
    color: white;
    font-size: var(--text-xs);
    font-weight: 700;
    pointer-events: none;
}

.profile-menu {
    display: none;
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    min-width: 200px;
    background: var(--surface);
    border: 1px solid var(--border-color);
    border-radius: 12px;
    box-shadow: var(--shadow-card-hover);
    z-index: 200;
    overflow: hidden;
}
.profile-menu.open { display: block; }
.profile-menu-header { padding: 12px 14px 10px; }
.profile-menu-name {
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--text-primary);
}
.profile-menu-email {
    font-size: var(--text-xs);
    color: var(--text-3);
}
.profile-menu-divider {
    height: 1px;
    background: var(--border-color);
}
.profile-menu-item {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 10px 14px;
    font-size: var(--text-sm);
    color: var(--text-2);
    text-decoration: none;
    transition: background 0.15s;
}
.profile-menu-item:hover {
    background: var(--brand-faint);
    color: var(--text-primary);
}
.profile-menu-icon,
.profile-dropdown-icon {
    width: 16px;
    height: 16px;
    flex: 0 0 16px;
    stroke: currentColor;
    fill: none;
}
.profile-menu-disabled {
    opacity: 0.45;
    cursor: not-allowed;
    pointer-events: none;
}
.profile-menu-soon {
    margin-left: auto;
    font-size: var(--text-2xs);
    background: var(--brand-faint);
    color: var(--text-3);
    padding: 1px 6px;
    border-radius: 20px;
}
.profile-menu-logout { color: var(--danger); }
.profile-menu-logout:hover { background: var(--color-danger-bg); color: var(--danger); }
[data-theme="dark"] .profile-menu-logout:hover { background: var(--color-danger-tint); }

/* ── Hero ── */
.hero {
    text-align: center;
    padding: 5rem 2rem 3.5rem;
    max-width: 620px;
    margin: 0 auto;
}
.hero-badge {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    background: var(--brand-faint);
    border: 1px solid var(--brand-border);
    border-radius: 99px;
    padding: 5px 14px 5px 9px;
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--brand);
    margin-bottom: 1.75rem;
    letter-spacing: 0.01em;
}
.pulse {
    width: 7px;
    height: 7px;
    background: var(--brand);
    border-radius: 50%;
    animation: pulse 2.2s ease-in-out infinite;
}
@keyframes pulse {
    0%, 100% { opacity: 1; box-shadow: 0 0 0 0 rgba(139, 92, 246, 0.4); }
    50%      { opacity: 0.7; box-shadow: 0 0 0 4px rgba(139, 92, 246, 0); }
}
.hero h1 {
    font-size: clamp(2.2rem, 5vw, 3.4rem);
    font-weight: 900;
    letter-spacing: -0.045em;
    line-height: 1.08;
    margin-bottom: 1.1rem;
    background: linear-gradient(145deg, var(--text-primary) 30%, var(--brand) 100%);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
}
[data-theme="dark"] .hero h1 {
    background: linear-gradient(145deg, var(--brand-faint) 30%, var(--brand) 100%);
    -webkit-background-clip: text;
    background-clip: text;
}
.hero p {
    font-size: var(--text-base);
    color: var(--text-2);
    line-height: 1.7;
    margin-bottom: 2.25rem;
}
.hero-actions {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
}

/* ── Content sections + grid ── */
/* App layout — content offset for the fixed sidebar.
   Lives here (the main rulesheet) rather than sidebar.css so page layout is
   owned in one place, but SCOPED to `.has-mobile-header` — the marker class on
   the main.hbs <body>. Standalone pages (index.hbs, login, setup, legal) have
   their own layout, don't render the sidebar, and must NOT get this offset
   (a global `body` rule here would shove the homepage into a cramped strip).
   The desktop sidebar is fixed at 260px (68px collapsed); padding-left reserves
   the rail width + a 12px gutter. The ≤1024px drawer mode zeroes these out (with
   !important) in sidebar.css, which loads after this file. */
body.has-mobile-header {
    padding: 20px 12px 20px 272px;   /* 260px rail + 12px gutter */
    transition: padding-left 0.3s ease;
}
body.has-mobile-header.sidebar-collapsed {
    padding-left: 80px;              /* 68px collapsed rail + 12px gutter */
}

.content {
    max-width: 1760px;
    margin: 0 auto;
    padding: 2.5rem 0.75rem 6rem;
}
.section { margin-bottom: 2.5rem; }
.section-header {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 1rem;
}
.section-tag {
    font-size: var(--text-2xs);
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--brand);
    background: var(--brand-faint);
    border: 1px solid var(--border);
    border-radius: 5px;
    padding: 3px 8px;
    white-space: nowrap;
}
.section-line {
    flex: 1;
    height: 1px;
    background: var(--border-color);
}
.grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 14px;
}

/* ── Cards ── */
.card {
    background: var(--surface);
    border: 1px solid var(--border-color);
    border-radius: 18px;
    padding: 32px 24px 28px;
    text-align: center;
    text-decoration: none;
    color: inherit;
    cursor: pointer;
    transition:
        transform 0.22s cubic-bezier(0.16, 1, 0.3, 1),
        box-shadow 0.22s cubic-bezier(0.16, 1, 0.3, 1),
        border-color 0.2s ease;
    box-shadow: var(--shadow-card);
    position: relative;
}
.card:hover {
    transform: translateY(-5px);
    box-shadow: var(--shadow-card-hover);
    border-color: var(--border-h);
}
.card::before {
    content: '';
    position: absolute;
    top: 0;
    left: 12px;
    right: 12px;
    height: 1px;
    background: linear-gradient(90deg, transparent, rgba(139, 92, 246, 0.5), transparent);
    opacity: 0;
    transition: opacity 0.22s ease;
    border-radius: 1px;
}
.card:hover::before { opacity: 1; }
.card-icon {
    font-size: var(--text-3xl);
    display: block;
    margin-bottom: 14px;
    line-height: 1;
}
.card-title {
    font-size: var(--text-base);
    font-weight: 700;
    color: var(--text-primary);
    letter-spacing: -0.015em;
    margin-bottom: 5px;
}
.card-desc {
    font-size: var(--text-xs);
    color: var(--text-3);
    line-height: 1.5;
}

/* ── Slim inline alert bar ──
   Compact in-content status strip — used between page headers and content
   grids on /stock, /settings, /orders. Smaller and quieter than the
   .warning-banner below; sits inline with content rather than competing
   with it. */
.alert-bar {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 10px 16px;
    margin-bottom: 1.25rem;
    border-radius: 10px;
    font-size: var(--text-sm);
    font-weight: 500;
    border: 1px solid transparent;
    flex-wrap: wrap;
}
.alert-bar-icon {
    width: 16px;
    height: 16px;
    stroke: currentColor;
    fill: none;
    vertical-align: -3px;
    margin-right: 6px;
}
.alert-bar a {
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
}
.alert-bar-danger {
    background: var(--color-danger-tint);
    color: var(--danger);
    border-color: var(--color-danger-bg-strong);
}
.alert-bar-danger a { color: var(--danger); }
.alert-bar-danger a:hover { text-decoration: underline; }
[data-theme="dark"] .alert-bar-danger {
    background: var(--color-danger-tint);
    color: var(--danger-light);
    border-color: var(--color-danger-bg-strong);
}
[data-theme="dark"] .alert-bar-danger a { color: var(--danger-light); }
.alert-bar-warning {
    background: var(--insight-bg);
    color: var(--insight-text);
    border-color: var(--insight-border);
}
.alert-bar-warning a { color: var(--insight-text); }
.alert-bar-warning a:hover { text-decoration: underline; }
.alert-bar-info {
    background: var(--color-info-bg);
    color: var(--color-info-accent);
    border-color: var(--color-info-border);
}
.alert-bar-info a { color: var(--color-info-accent); }
.alert-bar-info a:hover { text-decoration: underline; }

/* ── Warning / status banners (shared) ──
   Use these instead of inline `style="background:#xxx;color:white"` —
   the inline approach previously shipped a white-on-grey banner that was
   unreadable in light mode. */
.warning-banner {
    border-radius: 12px;
    padding: 18px 28px;
    margin-bottom: 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 15px;
    flex-wrap: wrap;
    text-align: center;
    font-size: var(--text-lg);
    font-weight: 600;
    border: 1px solid transparent;
}
.warning-banner-danger {
    background: linear-gradient(135deg, var(--color-danger-bg) 0%, var(--color-danger-bg-strong) 100%);
    color: var(--danger);
    border-color: var(--color-danger-bg-strong);
    box-shadow: 0 4px 14px var(--color-danger-tint);
}
[data-theme="dark"] .warning-banner-danger {
    background: linear-gradient(135deg, var(--color-danger-tint) 0%, var(--color-danger-bg-strong) 100%);
    color: var(--danger-light);
    border-color: var(--color-danger-bg-strong);
}
.warning-banner-warning {
    background: var(--insight-bg);
    color: var(--insight-text);
    border-color: var(--insight-border);
}
.warning-banner-pulse { animation: warning-pulse 4s ease-in-out infinite; }
@keyframes warning-pulse {
    0%, 100% { box-shadow: 0 4px 14px rgba(220, 38, 38, 0.10); }
    50%      { box-shadow: 0 4px 24px rgba(220, 38, 38, 0.25); }
}

.btn-danger {
    background: linear-gradient(135deg, var(--danger) 0%, var(--danger-hover) 100%);
    color: white;
    padding: 8px 16px;
    border-radius: 8px;
    text-decoration: none;
    font-weight: 600;
    font-size: var(--text-sm);
    box-shadow: 0 2px 8px var(--color-danger-bg-strong);
    transition: transform 0.18s ease, box-shadow 0.18s ease;
    border: none;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.btn-danger:hover {
    transform: translateY(-1px);
    box-shadow: 0 4px 14px var(--color-danger-bg-strong);
    color: white;
}

/* ============================================================
   Shared route components
   Promoted from per-view inline <style> blocks so the design
   stays modular. Per-route inline styles still win locally; goal
   is to drain those over time. Naming matches existing class
   conventions (.filter-bar, .stat-card, .panel-card, .chip, etc.).
   ============================================================ */

/* ── Page header ── */
.page-container {
    max-width: 1760px;
    margin: 0 auto;
    padding: 2rem 0.75rem 3rem;
}
.page-container--narrow { max-width: 880px; }

.page-header {
    margin-bottom: 2.25rem;
    padding-top: 0.75rem;
}
.page-header h1,
.page-title {
    font-size: var(--text-3xl);
    font-weight: 800;
    letter-spacing: -0.03em;
    margin: 0 0 0.5rem;
    line-height: 1.1;
    color: var(--brand);
    text-shadow: 0 4px 16px var(--brand-glow);
}
[data-theme="dark"] .page-header h1,
[data-theme="dark"] .page-title {
    color: var(--brand-hover);
}
.page-header p,
.page-subtitle {
    font-size: var(--text-base);
    color: var(--text-2);
    margin: 0;
    line-height: 1.5;
    max-width: 640px;
}
.page-header .label-eyebrow {
    color: var(--brand);
    margin-bottom: 0.6rem;
}
/* Accent underline under the route title so the page header reads with more
   presence. Short brand bar (not a full-width rule) — scoped to .page-header
   so it never lands on other .page-title uses. */
.page-header h1::after,
.page-header .page-title::after {
    content: "";
    display: block;
    width: 2.75rem;
    height: 0.1875rem;
    margin-top: 0.55rem;
    border-radius: 999px;
    background: var(--brand);
    box-shadow: 0 1px 8px var(--brand-glow);
}

/* Small meta line that hangs under the page title — last sync, item count, etc.
   Used by every route that wants a sub-title-style line without bringing back
   the full .page-subtitle paragraph. */
.page-header-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    font-size: var(--text-xs);
    color: var(--text-3);
    margin-top: 0.4rem;
    line-height: 1.5;
}
.page-header-meta time { font-variant-numeric: tabular-nums; }

/* ── Heading ladder ──
   Used app-wide so every route's headers and sub-headers line up.
   Page-title is the route's main h1.
   Section-title is an h2 — e.g. "Charts", "Filters", "Product breakdown".
   Subsection-title is an h3 — small heading inside a card.
   Label-eyebrow is a tiny uppercase label above a section. */
.section-title {
    font-size: var(--text-lg);
    font-weight: 700;
    letter-spacing: -0.015em;
    color: var(--text-primary);
    margin: 0 0 1rem;
    line-height: 1.3;
}
.subsection-title {
    font-size: var(--text-base);
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--text-primary);
    margin: 0 0 0.5rem;
    line-height: 1.4;
}
.label-eyebrow {
    font-size: var(--text-2xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: var(--text-2);
    margin: 0 0 0.55rem;
    line-height: 1.4;
    display: block;
}
.label-eyebrow--brand { color: var(--brand); }

/* ── Filter bar (sync-log + others) ──
   Soft brand-tinted card. Lighter than .stat-card / .panel-card so it reads
   as a control surface, not a content surface. Generous radius, no shadow. */
.filter-bar {
    background: var(--brand-faint);
    border: 1px solid var(--brand-border);
    border-radius: 16px;
    padding: 18px 22px;
    margin-bottom: 1.5rem;
    display: flex;
    gap: 8px;
    justify-content: center;
    flex-wrap: wrap;
}
/* Dark mode — the light-mode brand-faint tint is too washed on the dark
   page, so sit the bar on the same solid --surface as the cards and keep a
   brand-tinted border for its control-surface identity. */
[data-theme="dark"] .filter-bar {
    background: var(--surface);
    border-color: var(--brand-border);
}
.filter-btn {
    padding: 8px 18px;
    border: 1.5px solid var(--border-color);
    border-radius: 8px;
    background: var(--surface);
    color: var(--text-2);
    font-weight: 600;
    font-size: var(--text-sm);
    cursor: pointer;
    text-decoration: none;
    transition: border-color 0.15s, color 0.15s, background 0.15s, transform 0.1s;
    appearance: none;
    -webkit-appearance: none;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    line-height: 1.2;
}
.filter-btn:hover {
    border-color: var(--brand);
    color: var(--brand);
}
.filter-btn.active {
    background: var(--brand);
    color: #fff;
    border-color: var(--brand);
    box-shadow: 0 2px 8px var(--brand-glow);
}

/* ── Stat cards (statistics, profit, server-status …) ── */
.stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 1.1rem;
    margin-bottom: 1.5rem;
}
.stat-card {
    background: var(--surface);
    border: 1px solid var(--border-color);
    border-radius: 14px;
    padding: 1.25rem 1.4rem;
    box-shadow: var(--shadow-card);
    position: relative;
    /* NOT overflow:hidden — that clipped info-tip tooltips inside the card
       (unreadable on /statistics). The top accent stripe (::after) is masked to
       a full-height rounded layer instead, so it follows the corners without
       any clip. */
}
.stat-card::after {
    content: '';
    position: absolute;
    /* Cover the whole border box (offset by the 1px border), round it to the
       card radius, then mask away everything but the top 3px. A 3px-tall stripe
       can't round to a 14px corner — the radius clamps to its height into a flat
       ellipse and overhangs the card's circular corner. A full-height rounded
       ::after has true 14px corners, so the visible top band follows the card
       outline exactly. This replaces the old overflow:hidden clip (which broke
       the info-tip tooltips). */
    inset: -1px;
    border-radius: 14px;
    background: linear-gradient(90deg, var(--brand), var(--brand-hover));
    -webkit-mask: linear-gradient(180deg, #000 3px, transparent 3px);
            mask: linear-gradient(180deg, #000 3px, transparent 3px);
    pointer-events: none;
}
.stat-card.accent-warm::after {
    background: linear-gradient(90deg, var(--color-warning), var(--color-warning-light));
}
.stat-card.accent-success::after {
    background: linear-gradient(90deg, var(--success), var(--color-success-emerald));
}
.stat-card.accent-danger::after {
    background: linear-gradient(90deg, var(--danger), var(--danger-light));
}
.stat-card .stat-label {
    font-size: var(--text-xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-3);
    margin-bottom: 0.45rem;
}
.stat-card .stat-value {
    font-size: var(--text-xl);
    font-weight: 800;
    color: var(--text-primary);
    letter-spacing: -0.02em;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
}
.stat-card .stat-sub {
    font-size: var(--text-xs);
    color: var(--text-2);
    margin-top: 0.3rem;
}

/* "Hero" stat-card variant — bigger, bolder values with a brand-gradient
   text fill. Use when the route wants its KPIs to pop (material-tracking,
   future dashboards). Add .accent-warm to flip the gradient to amber. */
.stat-card.is-hero { padding: 1.6rem 1.5rem; }
.stat-card.is-hero .stat-value {
    font-size: var(--text-3xl);
    line-height: 1;
    letter-spacing: -0.03em;
    background: linear-gradient(135deg, var(--brand-dark), var(--brand));
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
}
[data-theme="dark"] .stat-card.is-hero .stat-value {
    background: linear-gradient(135deg, var(--brand-hover), var(--brand));
    -webkit-background-clip: text;
    background-clip: text;
}
.stat-card.is-hero.accent-warm .stat-value {
    background: linear-gradient(135deg, var(--insight-text), var(--color-warning));
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
}
[data-theme="dark"] .stat-card.is-hero.accent-warm .stat-value {
    background: linear-gradient(135deg, var(--color-warning-light), var(--color-warning));
    -webkit-background-clip: text;
    background-clip: text;
}

/* ── Panel card — flat surface with a thin brand stripe on top.
   Matches .stat-card so headers feel consistent across the app. ── */
.panel-card {
    background: var(--surface);
    border-radius: 14px;
    box-shadow: var(--shadow-card);
    border: 1px solid var(--border-color);
    margin-bottom: 16px;
    overflow: hidden;
    position: relative;
}
.panel-card::before {
    content: '';
    position: absolute;
    top: 0; left: 0; right: 0;
    height: 3px;
    background: linear-gradient(90deg, var(--brand), var(--brand-hover));
    border-top-left-radius: 14px;
    border-top-right-radius: 14px;
    z-index: 1;
}
.panel-card-header {
    background: var(--surface);
    color: var(--text-primary);
    padding: 14px 20px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    border-bottom: 1px solid var(--border-light);
}
.panel-card-header h2,
.panel-card-header h3 {
    margin: 0;
    color: var(--text-primary);
    font-size: var(--text-lg);
    font-weight: 700;
    letter-spacing: -0.01em;
}
.panel-card-body {
    padding: 16px 20px;
}
.panel-card-section {
    padding: 12px 20px;
    border-top: 1px solid var(--border-color);
}

/* ── Chips / tags / badges ── */
.chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 4px 12px;
    border-radius: 20px;
    font-size: var(--text-xs);
    font-weight: 600;
    background: var(--brand-faint);
    color: var(--brand-dark);
    border: 1px solid var(--brand-border);
    line-height: 1.4;
}
[data-theme="dark"] .chip {
    color: var(--insight-text);
}
.chip-count { font-weight: 800; }

.tag {
    padding: 2px 10px;
    background: var(--brand-faint);
    border: 1px solid var(--brand-border);
    border-radius: 10px;
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--brand-dark);
    text-transform: capitalize;
    display: inline-block;
    line-height: 1.5;
}
[data-theme="dark"] .tag { color: var(--insight-text); }

.badge {
    padding: 1px 7px;
    border-radius: 4px;
    font-size: var(--text-2xs);
    font-weight: 700;
    color: #fff;
    vertical-align: middle;
    margin-left: 4px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.badge-warning       { background: var(--color-warning); }
.badge-warning-light { background: var(--color-warning-light); }
.badge-brand         { background: var(--brand); }
.badge-success   { background: var(--success); }
.badge-danger    { background: var(--danger); }
.badge-neutral   { background: var(--text-3); }
.badge-info      { background: var(--info); }

/* ── List rows (order-row, stat-item, …) ── */
.list-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 0;
    border-bottom: 1px solid var(--border-light);
}
.list-row:last-child { border-bottom: none; }
.list-row-key {
    font-weight: 600;
    color: var(--text-primary);
    min-width: 140px;
    flex-shrink: 0;
}
.list-row-value {
    margin-left: auto;
    font-weight: 700;
    color: var(--text-primary);
}

/* ── Empty state ── */
.empty-state {
    padding: 56px 20px;
    text-align: center;
    color: var(--text-3);
}
.empty-state h3 {
    margin: 0 0 0.5rem;
    color: var(--text-2);
    font-size: var(--text-lg);
    font-weight: 700;
}
.empty-state p {
    margin: 0 0 1rem;
    font-size: var(--text-base);
}

/* ── Insight / callout box ── */
.insight-box {
    background: var(--insight-bg);
    border-left: 4px solid var(--insight-border);
    padding: 14px 18px;
    margin: 1rem 0;
    border-radius: 8px;
    color: var(--insight-text);
}
.insight-box h3 {
    margin: 0 0 0.5rem;
    color: var(--insight-text);
    font-size: var(--text-base);
}
.insight-box ul { list-style: none; margin: 0; padding: 0; }
.insight-box li { padding: 4px 0; }
.insight-box li::before { content: '💡 '; }

/* ── Form inputs (used in bug-report, login, register, setup) ── */
.form-group { margin-bottom: 1rem; }
.form-label {
    display: block;
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--text-primary);
    margin-bottom: 0.4rem;
}
.form-input,
.form-select,
.form-textarea {
    width: 100%;
    padding: 10px 14px;
    background: var(--input-bg);
    border: 1.5px solid var(--border-color);
    border-radius: 8px;
    font-size: var(--text-base);
    color: var(--text-primary);
    transition: border-color 0.15s, box-shadow 0.15s;
    font-family: inherit;
}
.form-input:focus,
.form-select:focus,
.form-textarea:focus {
    outline: none;
    border-color: var(--brand);
    box-shadow: 0 0 0 3px var(--brand-faint);
}
.form-textarea {
    min-height: 120px;
    resize: vertical;
    line-height: 1.5;
}
.form-help {
    font-size: var(--text-xs);
    color: var(--text-3);
    margin-top: 0.3rem;
}

/* ── btn-secondary (ghost-with-border, used as cancel/back) ── */
.btn-secondary {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: transparent;
    color: var(--text-2);
    border: 1.5px solid var(--border-color);
    border-radius: 8px;
    padding: 8px 16px;
    font-size: var(--text-sm);
    font-weight: 600;
    text-decoration: none;
    cursor: pointer;
    transition: border-color 0.15s, color 0.15s, background 0.15s;
}
.btn-secondary:hover {
    border-color: var(--brand);
    color: var(--brand);
    background: var(--brand-faint);
}
/* Compact secondary (e.g. inline outline action) */
.btn-secondary--compact {
    padding: 4px 10px;
    font-size: var(--text-xs);
    color: var(--text-3);
    border-width: 1px;
}

/* Size modifiers — MUST follow all variant definitions so they win the cascade */
.btn-sm { padding: 4px 10px;  font-size: var(--text-xs); }
.btn-lg { padding: 11px 22px; font-size: var(--text-base); }

/* ── Data table (statistics, profit, production-planner) ── */
.data-table {
    width: 100%;
    background: var(--surface);
    border-radius: 12px;
    box-shadow: var(--shadow-card);
    border: 1px solid var(--border-color);
    border-collapse: separate;
    border-spacing: 0;
    overflow: hidden;
}
.data-table th {
    text-align: left;
    padding: 12px 14px;
    background: var(--bg-tertiary);
    font-size: var(--text-xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-2);
    border-bottom: 1px solid var(--border-color);
}
.data-table td {
    padding: 12px 14px;
    font-size: var(--text-base);
    color: var(--text-primary);
    border-bottom: 1px solid var(--border-light);
}
.data-table tr:last-child td { border-bottom: none; }
.data-table tr:hover td { background: var(--brand-faint); }
.data-table .num,
.data-table .right { text-align: right; font-variant-numeric: tabular-nums; }
.data-table .center { text-align: center; }

/* Flat variant — embed inside a panel-card (strips card chrome: shadow, border, radius) */
.data-table.data-table--flat {
    box-shadow: none;
    border: none;
    border-radius: 0;
    border-collapse: collapse;
    background: transparent;
}
.data-table.data-table--flat th { background: transparent; }

/* ── Section label (small uppercase eyebrow) ── */
.section-label {
    font-size: var(--text-2xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: var(--text-2);
    margin-bottom: 0.85rem;
}

/* ── Animations ── */
@keyframes fadeIn {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: translateY(0); }
}
.fade-in { animation: fadeIn 0.4s ease both; }

/* ============================================================
   /orders hub — see archive/Notes/ORDERS_HUB_PLAN.md
   All visual rules for the orders view live here so colors,
   spacing and typography stay editable in one file.
   ============================================================ */

/* ── Top tab strip (Open · Packed · Shipped · All · Order log) ── */
.orders-tabs {
    display: flex;
    gap: 4px;
    margin-bottom: 1.25rem;
    border-bottom: 1px solid var(--border-color);
    padding: 0 0.25rem;
    flex-wrap: wrap;
}
.orders-tab {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 10px 16px;
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--text-2);
    text-decoration: none;
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    transition: color 0.15s, border-color 0.15s;
    line-height: 1.2;
    cursor: pointer;
    font-family: inherit;
    -webkit-appearance: none;
    appearance: none;
    outline: none;
    border-radius: 0;
}
.orders-tab:hover { color: var(--text-primary); }
.orders-tab.active {
    color: var(--brand);
    border-bottom-color: var(--brand);
}
.orders-tab-count {
    background: var(--brand-faint);
    color: var(--brand-dark);
    border: 1px solid var(--brand-border);
    border-radius: 99px;
    padding: 1px 8px;
    font-size: var(--text-xs);
    font-weight: 700;
    line-height: 1.4;
    min-width: 20px;
    text-align: center;
}
.orders-tab.active .orders-tab-count {
    background: var(--brand);
    color: #fff;
    border-color: var(--brand);
}
[data-theme="dark"] .orders-tab-count { color: var(--insight-text); }
[data-theme="dark"] .orders-tab.active .orders-tab-count { color: #fff; }

/* Listing sub-nav pills (Setup / Optimization) — shared by /listings/:id and
   /listings/:id/seo so the two full-window pages read as one and you can flip
   between them. Solid brand-filled active state; readable in light + dark. */
.listing-subnav {
    display: inline-flex; gap: 0.35rem; padding: 0.3rem;
    background: var(--bg-tertiary); border: 1px solid var(--border-color);
    border-radius: 11px; margin: 0.5rem 0 1.75rem;
}
.listing-subnav-item {
    padding: 0.5rem 1.2rem; font-size: var(--text-base); font-weight: 600;
    color: var(--text-2); border-radius: 8px; text-decoration: none;
    transition: background 0.12s, color 0.12s;
}
.listing-subnav-item:hover { color: var(--text-primary); background: var(--brand-faint); }
.listing-subnav-item.is-active { color: var(--color-on-brand); background: var(--brand); }
.listing-subnav-item.is-active:hover { color: var(--color-on-brand); background: var(--brand-hover); }
.orders-tab-divider {
    width: 1px;
    background: var(--border-color);
    margin: 8px 4px;
}

/* Canonical tab panel — pair with .orders-tab/.orders-tabs */
.tab-panel { display: none; }
.tab-panel.active { display: block; }

/* ── Completed-archive filter pills ──
   Sub-filter inside the Completed tab: "All" + one pill per terminal status.
   State variant (.is-active), distinct from the canonical .chip. */
.orders-filter-pills {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 1.1rem;
}
.orders-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 14px;
    border-radius: 20px;
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--text-2);
    text-decoration: none;
    background: var(--surface);
    border: 1px solid var(--border-color);
    transition: color 0.15s, background 0.15s, border-color 0.15s;
}
.orders-pill:hover {
    color: var(--brand);
    border-color: var(--brand-border);
}
.orders-pill.is-active {
    color: var(--brand-dark);
    background: var(--brand-faint);
    border-color: var(--brand-border);
}
.orders-pill-count {
    font-size: var(--text-xs);
    font-weight: 700;
    color: var(--text-3);
    font-variant-numeric: tabular-nums;
}
.orders-pill.is-active .orders-pill-count { color: var(--brand-dark); }

/* ── Toolbar (search) ── */
.orders-toolbar {
    display: flex;
    gap: 12px;
    align-items: center;
    margin-bottom: 1.25rem;
    flex-wrap: wrap;
}
.orders-search {
    flex: 1;
    min-width: 240px;
    max-width: 420px;
    padding: 10px 14px;
    background: var(--surface);
    border: 1px solid var(--border-color);
    border-radius: 10px;
    font-size: var(--text-base);
    color: var(--text-primary);
    transition: border-color 0.15s, box-shadow 0.15s;
}
.orders-search::placeholder { color: var(--text-3); }
.orders-search:focus {
    outline: none;
    border-color: var(--brand);
    box-shadow: 0 0 0 3px var(--brand-faint);
}
.orders-toolbar-spacer { flex: 1; }
.orders-toolbar-meta {
    font-size: var(--text-sm);
    color: var(--text-3);
}

/* ── Card grid ──
   Multi-column by default; collapses to a single column the moment any card
   is expanded so the open card can span the full screen width and the others
   stack neatly below it. JS toggles .has-expanded on click. */
.orders-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
    gap: 1.1rem;
}
.orders-grid.has-expanded {
    grid-template-columns: 1fr;
}

/* ── Order card ── */
.order-card {
    background: var(--surface);
    border: 1px solid var(--border-color);
    border-radius: 16px;
    box-shadow: var(--shadow-card);
    overflow: hidden;
    cursor: pointer;
    transition: transform 0.18s cubic-bezier(0.16, 1, 0.3, 1),
                box-shadow 0.18s ease,
                border-color 0.15s ease;
    display: flex;
    flex-direction: column;
    position: relative;
}

/* Collapse arrow — only visible when the card is expanded.
   Pinned to the top-right of the card so it's always reachable
   regardless of how tall the detail panel grows. */
.order-card-collapse {
    position: absolute;
    top: 10px;
    right: 12px;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: var(--surface);
    border: 1px solid var(--border-color);
    color: var(--text-2);
    font-size: var(--text-sm);
    line-height: 1;
    cursor: pointer;
    display: none;
    align-items: center;
    justify-content: center;
    z-index: 5;
    transition: background 0.15s, color 0.15s, border-color 0.15s;
    padding: 0;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.06);
}
.order-card.is-expanded .order-card-collapse { display: flex; }
.order-card-collapse:hover {
    background: var(--brand-faint);
    color: var(--brand);
    border-color: var(--brand-border);
}
/* Expanded cards stop being click-targets themselves */
.order-card.is-expanded { cursor: default; }

/* Make room for the absolute-positioned ▴ collapse arrow when expanded —
   ship-by date / status content shifts left so they don't get covered. */
.order-card.is-expanded .order-card-top { padding-right: 50px; }

/* Selection checkbox — top-left of the card. Only visible on hover/selected
   so resting cards stay clean. */
.order-card-select {
    position: absolute;
    top: 10px;
    left: 12px;
    z-index: 4;
    width: 22px;
    height: 22px;
    border-radius: 6px;
    background: var(--surface);
    border: 1px solid var(--border-color);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    opacity: 0;
    transition: opacity 0.15s, background 0.15s, border-color 0.15s;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.06);
}
.order-card:hover .order-card-select,
.order-card.is-selected .order-card-select { opacity: 1; }
.order-card-select input { margin: 0; cursor: pointer; accent-color: var(--brand); }
.order-card.is-selected {
    outline: 2px solid var(--brand);
    outline-offset: -2px;
}

/* Bulk-action toolbar — appears when ≥1 card is selected */
.orders-bulk-toolbar {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    padding: 10px 16px;
    background: var(--brand-faint);
    border: 1px solid var(--brand-border);
    border-radius: 12px;
    margin-bottom: 1rem;
    color: var(--brand-dark);
    font-size: var(--text-sm);
}
[data-theme="dark"] .orders-bulk-toolbar { color: var(--insight-text); }
.orders-bulk-toolbar[hidden] { display: none; }
.orders-bulk-count strong { color: var(--brand); font-size: var(--text-base); }
.orders-bulk-label {
    color: var(--text-2);
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-weight: 700;
}
.orders-bulk-statuses {
    display: inline-flex;
    flex-wrap: wrap;
    gap: 6px;
}
.orders-bulk-statuses .order-status-pill {
    cursor: pointer;
    padding: 4px 12px;
}

/* Hint paragraph above the orders grid */
.orders-drag-hint {
    font-size: var(--text-xs);
    color: var(--text-2);
    margin-bottom: 0.85rem;
    margin-top: -0.4rem;
    font-style: italic;
}

.order-card:hover {
    transform: translateY(-3px);
    box-shadow: var(--shadow-card-hover);
    border-color: var(--border-h);
}

.order-card-top {
    display: flex;
    gap: 14px;
    padding: 16px 18px;
    align-items: flex-start;
}

/* Ship-by date pinned to the top-right of the card. Color shifts to amber
   when the deadline is within 2 days, red when it's already past. */
.order-card-shipby {
    flex-shrink: 0;
    text-align: right;
    padding: 6px 12px;
    border-radius: 10px;
    background: var(--brand-faint);
    border: 1px solid var(--brand-border);
    line-height: 1.3;
    align-self: flex-start;
}
.order-card-shipby-label {
    font-size: var(--text-2xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--brand);
    opacity: 0.85;
}
.order-card-shipby-date {
    font-size: var(--text-base);
    font-weight: 700;
    color: var(--brand-dark);
    font-variant-numeric: tabular-nums;
}
[data-theme="dark"] .order-card-shipby-date { color: var(--insight-text); }
.order-card-shipby.is-soon {
    background: var(--color-warning-soft-bg);
    border-color: var(--color-warning-soft-border);
}
.order-card-shipby.is-soon .order-card-shipby-label { color: var(--warning-text); }
.order-card-shipby.is-soon .order-card-shipby-date { color: var(--insight-text); }
[data-theme="dark"] .order-card-shipby.is-soon {
    background: var(--color-warning-soft-bg);
    border-color: var(--color-warning-soft-border);
}
[data-theme="dark"] .order-card-shipby.is-soon .order-card-shipby-label,
[data-theme="dark"] .order-card-shipby.is-soon .order-card-shipby-date {
    color: var(--color-warning-soft-border);
}
/* Shipped — green pill replaces the ship-by date once the order is out. */
.order-card-shipby.is-shipped {
    background: var(--color-success-bg-soft);
    border-color: var(--color-success-border);
}
.order-card-shipby.is-shipped .order-card-shipby-label { color: var(--success-hover); }
.order-card-shipby.is-shipped .order-card-shipby-date { color: var(--color-success-fg); }
[data-theme="dark"] .order-card-shipby.is-shipped {
    background: var(--color-success-bg-soft);
    border-color: var(--color-success-border);
}
[data-theme="dark"] .order-card-shipby.is-shipped .order-card-shipby-label,
[data-theme="dark"] .order-card-shipby.is-shipped .order-card-shipby-date {
    color: var(--color-success-border);
}

.order-card-shipby.is-late {
    background: var(--color-danger-bg);
    border-color: var(--danger-light);
}
.order-card-shipby.is-late .order-card-shipby-label { color: var(--danger); }
.order-card-shipby.is-late .order-card-shipby-date { color: var(--danger); }
[data-theme="dark"] .order-card-shipby.is-late {
    background: var(--color-danger-tint);
    border-color: var(--color-danger-bg-strong);
}
[data-theme="dark"] .order-card-shipby.is-late .order-card-shipby-label,
[data-theme="dark"] .order-card-shipby.is-late .order-card-shipby-date {
    color: var(--danger-light);
}
.order-card-thumb {
    width: 78px;
    height: 78px;
    flex-shrink: 0;
    border-radius: 10px;
    object-fit: cover;
    background: var(--bg-tertiary);
    border: 1px solid var(--border-color);
}
.order-card-thumb-fallback {
    width: 78px;
    height: 78px;
    flex-shrink: 0;
    border-radius: 10px;
    background: linear-gradient(135deg, var(--brand-faint), var(--bg-tertiary));
    border: 1px solid var(--border-color);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--brand);
    opacity: 0.6;
}
.order-card-thumb-fallback svg { width: 38px; height: 38px; }

/* Multi-item orders show a mosaic of up to 3 distinct product images inside
   the same 78px box. The container background shows through the 1px grid gaps
   as subtle seams between tiles. */
.order-card-thumb-mosaic {
    width: 78px;
    height: 78px;
    flex-shrink: 0;
    border-radius: 10px;
    overflow: hidden;
    border: 1px solid var(--border-color);
    background: var(--border-color);
    display: grid;
    gap: 1px;
}
.order-card-thumb-mosaic--2 {
    grid-template-columns: 1fr 1fr;
}
.order-card-thumb-mosaic--3 {
    grid-template-columns: 1fr 1fr;
    grid-template-rows: 1fr 1fr;
}
/* Two squares on top, one full-width rectangle on the bottom. */
.order-card-thumb-mosaic--3 .order-card-thumb-tile:nth-child(3) {
    grid-column: 1 / 3;
}
.order-card-thumb-tile {
    width: 100%;
    height: 100%;
    min-width: 0;
    min-height: 0;
    object-fit: cover;
    background: var(--bg-tertiary);
}
/* Broken-image fallback for a single mosaic tile — keeps its grid slot. */
.order-card-thumb-tile--fb {
    display: flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(135deg, var(--brand-faint), var(--bg-tertiary));
    color: var(--brand);
    opacity: 0.6;
}
.order-card-thumb-tile--fb svg { width: 20px; height: 20px; }

.order-card-headline {
    flex: 1;
    min-width: 0;
}
.order-card-buyer {
    font-size: var(--text-base);
    font-weight: 700;
    color: var(--text-primary);
    letter-spacing: -0.01em;
    line-height: 1.3;
    margin-bottom: 4px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.order-card-returning-row {
    margin-bottom: 6px;
}
.order-card-returning {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin-left: 0;
    text-transform: none;
    letter-spacing: 0;
}
.order-card-returning svg {
    width: 11px;
    height: 11px;
}
.order-card-meta-row {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 12px;
    font-size: var(--text-xs);
    color: var(--text-3);
    margin-bottom: 8px;
}
.order-card-meta-row strong { color: var(--text-2); font-weight: 600; }
.order-card-totals {
    display: flex;
    align-items: baseline;
    gap: 10px;
}
.order-card-total {
    font-size: var(--text-lg);
    font-weight: 800;
    color: var(--text-primary);
    letter-spacing: -0.01em;
    font-variant-numeric: tabular-nums;
}
.order-card-profit {
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--success);
    font-variant-numeric: tabular-nums;
}
.order-card-profit.is-negative { color: var(--danger); }

/* ── Items section ── */
.order-card-items {
    padding: 8px 18px 4px;
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.order-card-item {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: baseline;
    font-size: var(--text-sm);
    color: var(--text-2);
    line-height: 1.4;
}
.order-card-item-qty {
    color: var(--brand);
    font-weight: 700;
    flex-shrink: 0;
    min-width: 24px;
}
.order-card-item-name {
    color: var(--text-primary);
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.order-card-item-variant {
    color: var(--text-3);
    font-size: var(--text-xs);
    margin-left: 6px;
}
.order-card-item-pers {
    flex-basis: 100%;
    color: var(--text-3);
    font-size: var(--text-xs);
    font-style: italic;
    margin-left: 32px;
    white-space: pre-line;
    overflow-wrap: anywhere;
}

/* ── Card footer (status + flags) ── */
.order-card-footer {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 12px 18px 14px;
    border-top: 1px solid var(--border-light);
    margin-top: auto;
    flex-wrap: wrap;
}

/* ── Status pill ──
   Uniform brand-themed look applied app-wide (in-card footer, bulk toolbar,
   status manager). `!important` is intentional: the orders.js renderer sets
   `style="background:<status.color>"` inline on every pill, which we want
   to drop in favor of the site palette. The status's identity now comes
   from its label text, not a unique color. */
.order-status-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 12px;
    border-radius: 99px;
    font-size: var(--text-xs);
    font-weight: 700;
    color: var(--brand-dark) !important;
    line-height: 1.4;
    background: var(--brand-faint) !important;
    letter-spacing: 0.01em;
    border: 1px solid var(--brand-border);
    cursor: pointer;
    font-family: inherit;
}
.order-status-pill::before {
    content: '';
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--brand);
    display: inline-block;
}
.order-status-pill::after {
    content: '▾';
    font-size: var(--text-2xs);
    margin-left: 2px;
    opacity: 0.7;
}
.order-status-pill-readonly { cursor: default; }
.order-status-pill-readonly::after { content: none; }

/* Status pill dropdown — opens on pill click */
.status-dropdown {
    position: absolute;
    z-index: 50;
    background: var(--surface);
    border: 1px solid var(--border-color);
    border-radius: 10px;
    box-shadow: var(--shadow-card-hover);
    padding: 6px;
    min-width: 200px;
    display: none;
}
.status-dropdown.open { display: block; }
.status-dropdown button {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    background: none;
    border: none;
    padding: 7px 10px;
    border-radius: 6px;
    font-size: var(--text-sm);
    color: var(--text-primary);
    cursor: pointer;
    text-align: left;
    font-family: inherit;
}
.status-dropdown button:hover { background: var(--brand-faint); }
.status-dropdown button[disabled] { opacity: 0.4; cursor: default; }
.status-dropdown .dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    flex-shrink: 0;
    background: var(--brand) !important;   /* uniform brand color; labels disambiguate */
}

/* Coupon pill — small accent next to the status pill */
.order-coupon-pill {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 10px;
    border-radius: 99px;
    font-size: var(--text-xs);
    font-weight: 700;
    background: var(--insight-bg);
    color: var(--insight-text);
    border: 1px solid var(--insight-border);
    line-height: 1.5;
    letter-spacing: 0.01em;
}

/* Tracking pill — quiet at-a-glance flag for whether a tracking number is
   saved, so the operator can scan the queue without expanding each card.
   Muted neutral by default; soft-green when a tracking number exists. */
.order-tracking-pill {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 10px;
    border-radius: 99px;
    font-size: var(--text-xs);
    font-weight: 600;
    background: transparent;
    color: var(--text-3);
    border: 1px solid var(--border-light);
    line-height: 1.5;
    letter-spacing: 0.01em;
}
.order-tracking-pill svg {
    width: 12px;
    height: 12px;
    opacity: 0.85;
}
.order-tracking-pill.is-saved {
    background: var(--color-success-bg-soft);
    color: var(--color-success-fg);
    border-color: var(--color-success-border);
}

/* ── Empty state ── */
.orders-empty {
    text-align: center;
    padding: 60px 20px;
    background: var(--surface);
    border: 1px dashed var(--border-color);
    border-radius: 16px;
    color: var(--text-3);
}
.orders-empty-icon { margin-bottom: 12px; line-height: 0; }
.orders-empty-icon svg { width: 48px; height: 48px; stroke: var(--text-3); }
.orders-empty-title {
    font-size: var(--text-lg);
    font-weight: 700;
    color: var(--text-2);
    margin-bottom: 6px;
}
.orders-empty-sub { font-size: var(--text-sm); }

/* ── Pagination ── */
/* Gear icon in the "Customize statuses" tab — inherits the tab's text color. */
.orders-tab-icon {
    width: 15px;
    height: 15px;
    flex: 0 0 auto;
    stroke: currentColor;
    fill: none;
}

.orders-pagination {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 12px;
    margin-top: 1.5rem;
}
.orders-pagination-meta {
    font-size: var(--text-sm);
    color: var(--text-3);
}
.orders-pagination .is-disabled {
    opacity: 0.45;
    pointer-events: none;
}

/* Date-range filter pair in the orders toolbar — a small inline label + native
   date picker, sharing the search field's surface/border tokens. */
.orders-daterange {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: var(--text-sm);
    color: var(--text-3);
}
.orders-date-input {
    padding: 8px 10px;
    background: var(--surface);
    border: 1px solid var(--border-color);
    border-radius: 10px;
    font-size: var(--text-sm);
    color: var(--text-primary);
    transition: border-color 0.15s, box-shadow 0.15s;
}
.orders-date-input:focus {
    outline: none;
    border-color: var(--brand);
    box-shadow: 0 0 0 3px var(--brand-faint);
}

/* ── Inline-expanding card detail ──
   Click a card → its detail panel slides down underneath the existing card
   content, and the parent grid switches to single-column so the expanded
   card spans the full screen width. Visual rules all centralized here. */
.order-card.is-expanded {
    cursor: default;
    border-color: var(--border-h);
    box-shadow: var(--shadow-card-hover);
}
/* The header overview thumb (single or mosaic) duplicates the per-item thumbs
   shown inside the open detail — drop it while the card is expanded. Same for
   the total/profit summary row: the detail's Money block is the full, itemised
   version of the same numbers. */
.order-card.is-expanded .order-card-thumb,
.order-card.is-expanded .order-card-thumb-mosaic,
.order-card.is-expanded .order-card-thumb-fallback,
.order-card.is-expanded .order-card-totals { display: none; }
.order-card-detail {
    max-height: 0;
    opacity: 0;
    overflow: hidden;
    transition: max-height 0.32s cubic-bezier(0.16, 1, 0.3, 1),
                opacity 0.18s ease;
    border-top: 1px solid var(--border-light);
    background: var(--surface);
}
.order-card.is-expanded .order-card-detail {
    max-height: 2000px;
    opacity: 1;
}

/* Inner container — explicit 2-column grid with named areas:
   row 1: [items (wide)] [customer (narrow, top-right)]
   row 2: [money]        [reference]
   Collapses to single column on narrow screens. */
.order-card-detail-inner {
    padding: 1.75rem 2rem 2rem;
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
    grid-template-areas:
        "items     customer"
        "money     reference";
    gap: 1.6rem 2.5rem;
    align-items: start;
}
.order-detail-section-items     { grid-area: items; }
.order-detail-section-customer  { grid-area: customer; }
.order-detail-section-money     { grid-area: money; }
.order-detail-section-reference { grid-area: reference; }

/* Copy-address affordance inside the Customer panel. Sits below the
   address lines so it never crowds the actual data — small, ghost-style,
   flips into a confirm state via .is-copied for 1.5s after click. */
.order-address-block { line-height: 1.55; }
.order-address-copy {
    display: block;
    width: fit-content;
    margin-top: 10px;
    background: transparent;
    border: 1px solid var(--border-color);
    color: var(--text-2);
    padding: 6px 12px;
    border-radius: 8px;
    font: inherit;
    font-size: var(--text-xs);
    font-weight: 600;
    cursor: pointer;
    transition: border-color 0.15s, color 0.15s, background 0.15s;
}
.order-address-copy:hover  { border-color: var(--brand); color: var(--brand); background: var(--brand-faint); }
.order-address-copy:active { transform: translateY(1px); }
.order-address-copy.is-copied {
    border-color: var(--success, #16a34a);
    color: var(--success, #16a34a);
    background: var(--color-success-tint);
}

@media (max-width: 720px) {
    /* Expanded-card detail only (always inside .order-card.is-expanded).
       IMPORTANT: every section/row/item rule is scoped under
       .order-card-detail-inner so it has higher specificity (0,2,0) than the
       base order-detail and order-item rules, which are defined LATER in this
       file — at equal specificity source order would otherwise let the base win
       (this is why an earlier, unscoped attempt had no visible effect).
       Condensed hard per operator: small top/bottom padding, tight gaps/rows. */
    .order-card-detail-inner {
        grid-template-columns: 1fr !important;   /* never fall back to the desktop 2-col grid on a phone */
        grid-template-areas:
            "items"
            "customer"
            "money"
            "reference" !important;
        padding: var(--m-pad-sm);      /* 10 all round — was 28/32 */
        gap: 12px;                      /* between the stacked flowing sections */
    }
    .order-card-detail-inner .order-detail-section-label {
        margin-bottom: 5px;
        padding-bottom: 5px;
    }
    /* MONEY + REFERENCE: tight key/value rows so the sections stop being tall. */
    .order-card-detail-inner .order-detail-row { padding: 2px 0; }
    .order-card-detail-inner .order-detail-row.is-highlight .v { font-size: var(--text-base); }
    /* Items: smaller thumb + tight rows free width for the title/chips, and
       pack the title / variation chips / meta close together (one block, not
       three stacked rows). */
    .order-card-detail-inner .order-item {
        grid-template-columns: var(--m-thumb-sm) 1fr auto;
        gap: var(--m-pad-sm);
        padding: var(--m-pad-xs) 0;
    }
    .order-card-detail-inner .order-item-thumb,
    .order-card-detail-inner .order-item-thumb-fallback {
        width: var(--m-thumb-sm);
        height: var(--m-thumb-sm);
    }
    .order-card-detail-inner .order-item-title-row { margin-bottom: 2px; }
    .order-card-detail-inner .order-item-variations { margin-bottom: 2px; }
    .order-card-detail-inner .order-item-meta { margin-top: 2px; }
}

/* Sections are chrome-less: the expanded card is the one box, the info flows
   inside it. Structure comes from the small-caps labels (with their underline)
   and the grid gaps — no nested borders/backgrounds to space or clip oddly. */
.order-detail-section {
    font-size: var(--text-base);
    color: var(--text-primary);
    line-height: 1.6;
    min-width: 0;
}
.order-detail-section-label {
    font-size: var(--text-2xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: var(--brand);
    margin-bottom: 0.85rem;
    padding-bottom: 0.55rem;
    border-bottom: 1px solid var(--border-light);
}

.order-detail-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 12px;
    padding: 6px 0;
}
.order-detail-row + .order-detail-row { border-top: 1px dashed var(--border-light); }
.order-detail-row .k {
    color: var(--text-2);
    font-size: var(--text-sm);
}
.order-detail-row .v {
    color: var(--text-primary);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    text-align: right;
}
.order-detail-row.is-highlight .v { color: var(--brand); font-size: var(--text-lg); }

.order-detail-divider {
    border: none;
    border-top: 1px solid var(--border-color);
    margin: 0.6rem 0;
}

/* Loading placeholder — only ever rendered inside an expanded card so it
   can't bleed into closed cards. */
.order-detail-loading {
    grid-column: 1 / -1;
    text-align: center;
    color: var(--text-3);
    padding: 2rem;
    font-size: var(--text-base);
    background: var(--surface);
    border: 1px dashed var(--border-color);
    border-radius: 12px;
}

/* ── Rich item row inside the Items section ──
   [thumbnail]  [title + variation chips + personalization]  [qty]
*/
.order-item {
    display: grid;
    grid-template-columns: 64px 1fr auto;
    gap: 14px;
    align-items: center;
    padding: 12px 0;
}
.order-item + .order-item { border-top: 1px dashed var(--border-light); }

.order-item-thumb,
.order-item-thumb-fallback {
    width: 64px;
    height: 64px;
    border-radius: 10px;
    object-fit: cover;
    background: var(--bg-tertiary);
    border: 1px solid var(--border-color);
}
.order-item-thumb-fallback {
    display: flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(135deg, var(--brand-faint), var(--bg-tertiary));
    color: var(--brand);
    opacity: 0.6;
}
.order-item-thumb-fallback svg { width: 30px; height: 30px; }

/* ── Action buttons inside the Reference section ── */
.order-actions {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    margin-top: 14px;
    padding-top: 14px;
    border-top: 1px solid var(--border-light);
}
.order-actions-terminal {
    color: var(--text-3);
    font-size: var(--text-sm);
    font-style: italic;
    justify-content: flex-start;
}
.order-ship-form {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 10px;
    padding: 12px;
    background: var(--bg-tertiary);
    border: 1px dashed var(--border-color);
    border-radius: 10px;
}
.order-ship-form .form-input {
    flex: 1 1 120px;
    padding: 8px 12px;
    font-size: var(--text-sm);
}
.order-ship-form button {
    flex-shrink: 0;
}

/* Standalone tracking section in the Reference card. Editable any time —
   even before the order has been marked shipped. */
.order-tracking-form {
    margin-top: 6px;
}
.order-tracking-row {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    margin-top: 6px;
}
.order-tracking-row .form-input {
    flex: 1 1 140px;
    padding: 7px 12px;
    font-size: var(--text-sm);
}
.order-tracking-row button { flex-shrink: 0; padding: 7px 14px; font-size: var(--text-sm); }
.order-tracking-hint {
    font-size: var(--text-xs);
    color: var(--text-3);
    margin-top: 6px;
    font-style: italic;
}

/* ── Status manager (Phase B.5) ── */
.status-manager {
    background: var(--surface);
    border: 1px solid var(--border-color);
    border-radius: 14px;
    padding: 1.5rem 1.75rem;
    box-shadow: var(--shadow-card);
    margin-bottom: 1rem;
}
.status-table {
    width: 100%;
    border-collapse: collapse;
    margin: 1rem 0;
}
.status-table th {
    text-align: left;
    padding: 8px 10px;
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-3);
    font-weight: 700;
    border-bottom: 1px solid var(--border-color);
}
.status-table td {
    padding: 10px;
    border-bottom: 1px solid var(--border-light);
    vertical-align: middle;
}
.status-table tr:last-child td { border-bottom: none; }
.status-table .status-order {
    width: 70px;
    font-variant-numeric: tabular-nums;
    color: var(--text-3);
    font-size: var(--text-sm);
}
/* Drag-to-reorder grip — grab it to slot a status into position. The whole row
   only becomes draggable while the grip is held (JS), so the label input stays
   editable and text-selectable. */
.status-table .status-drag-grip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: 6px;
    color: var(--text-3);
    cursor: grab;
    touch-action: none;         /* let pointer drags work on touch without scroll */
}
.status-table .status-drag-grip:hover { background: var(--brand-faint); color: var(--brand); }
.status-table .status-drag-grip:active { cursor: grabbing; }
.status-table .status-drag-grip svg { width: 18px; height: 18px; }
/* Picked-up row: highlighted + lifted with a shadow, floating above the others
   (which slide aside via a FLIP animation in orders.js) and following the
   cursor. Opaque cells so it cleanly covers rows it passes over. */
.status-table tr.status-row-lifted {
    position: relative;
    z-index: 5;
    cursor: grabbing;
    box-shadow: var(--shadow-card-hover);
}
.status-table tr.status-row-lifted td {
    /* Opaque so the row it floats over never shows through: the translucent
       brand tint (--brand-faint, 8% alpha) is composited over the solid table
       surface via a flat gradient layer. */
    background: linear-gradient(var(--brand-faint), var(--brand-faint)), var(--surface);
    border-color: transparent;
}
.status-table tr.status-row-lifted td:first-child { border-top-left-radius: 8px; border-bottom-left-radius: 8px; }
.status-table tr.status-row-lifted td:last-child  { border-top-right-radius: 8px; border-bottom-right-radius: 8px; }
.status-table .status-label-input {
    padding: 6px 10px;
    width: 100%;
    background: var(--input-bg);
    border: 1px solid var(--border-color);
    border-radius: 6px;
    font-size: var(--text-base);
    color: var(--text-primary);
    font-family: inherit;
}
.status-color-input {
    width: 38px;
    height: 28px;
    border: 1px solid var(--border-color);
    border-radius: 6px;
    background: none;
    cursor: pointer;
    padding: 2px;
}
.status-table .status-delete-btn {
    background: none;
    border: 1px solid var(--border-color);
    color: var(--danger);
    border-radius: 6px;
    padding: 5px 10px;
    cursor: pointer;
    font-size: var(--text-xs);
    font-weight: 600;
}
.status-table .status-delete-btn:hover {
    background: var(--color-danger-tint);
    border-color: var(--danger);
}
.status-table .status-system-badge {
    background: var(--brand-faint);
    color: var(--brand-dark);
    font-size: var(--text-2xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    padding: 2px 6px;
    border-radius: 4px;
    margin-left: 6px;
}
[data-theme="dark"] .status-table .status-system-badge { color: var(--insight-text); }
.status-loading {
    text-align: center;
    padding: 1.5rem;
    color: var(--text-3);
    font-size: var(--text-base);
}
.status-add-row {
    display: flex;
    gap: 10px;
    align-items: center;
    flex-wrap: wrap;
    padding-top: 1rem;
    border-top: 1px solid var(--border-color);
}
.status-add-row .form-input { flex: 1 1 200px; }
.order-item-body { min-width: 0; }
.order-item-title-row {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    margin-bottom: 6px;
}
.order-item-title {
    font-size: var(--text-base);
    font-weight: 700;
    color: var(--text-primary);
    letter-spacing: -0.005em;
    line-height: 1.3;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Variation chips: little pill per attribute. Etsy shows e.g. "Color: Green" */
.order-item-variations {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-bottom: 4px;
}
.order-item-variation {
    display: inline-flex;
    align-items: baseline;
    gap: 4px;
    padding: 3px 9px;
    background: var(--brand-faint);
    border: 1px solid var(--brand-border);
    border-radius: 99px;
    font-size: var(--text-xs);
    line-height: 1.4;
}
.order-item-variation .k {
    color: var(--brand);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-size: var(--text-2xs);
}
.order-item-variation .v {
    color: var(--brand-dark);
    font-weight: 600;
}
[data-theme="dark"] .order-item-variation .v { color: var(--insight-text); }

/* Per-item meta line: material cost · txn id · "View on Etsy" link */
.order-item-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 8px;
    margin-top: 6px;
    font-size: var(--text-xs);
    color: var(--text-3);
    font-variant-numeric: tabular-nums;
}
.order-item-meta-sep { opacity: 0.5; }
.order-item-link {
    color: var(--brand);
    text-decoration: none;
    font-weight: 600;
}
.order-item-link:hover { text-decoration: underline; color: var(--brand-dark); }

/* Personalization text under an item row */
.order-item-pers {
    margin-top: 6px;
    padding: 8px 12px;
    background: var(--brand-faint);
    border-left: 3px solid var(--brand);
    border-radius: 6px;
    font-size: var(--text-sm);
    color: var(--text-primary);
    line-height: 1.45;
}

/* Buyer note (message_from_buyer) — receipt-level gift / packing instructions,
   shown at the top of the Items column on the pack screen so it can't be missed. */
.order-buyer-note {
    margin-bottom: 12px;
    padding: 10px 14px;
    background: var(--color-info-bg);
    border-left: 3px solid var(--color-info-accent);
    border-radius: 8px;
    line-height: 1.5;
}
.order-buyer-note-label {
    display: block;
    margin-bottom: 3px;
    font-size: var(--text-2xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-info-accent);
}
.order-buyer-note-body {
    font-size: var(--text-sm);
    color: var(--text-primary);
    word-break: break-word;
}
/* Canceled-order variant — manual-restock reminder. Amber, not red:
   nothing is broken, the operator just has a decision to make. */
.order-buyer-note--canceled {
    background: var(--color-warning-bg);
    border-left-color: var(--color-warning);
}
.order-buyer-note--canceled .order-buyer-note-label {
    color: var(--color-warning);
}
/* Refunded-order variant — same manual-restock reminder, refund framing. */
.order-buyer-note--refunded {
    background: var(--color-warning-bg);
    border-left-color: var(--color-warning);
}
.order-buyer-note--refunded .order-buyer-note-label {
    color: var(--color-warning);
}

/* Manual-pick picker (personalized + surprise/mixed orders) */
.order-manual-pick-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    border-radius: 999px;
    background: var(--color-warning-soft-bg);
    color: var(--color-warning-soft-fg);
    border: 1px solid var(--color-warning-soft-border);
    font-size: var(--text-xs);
    font-weight: 600;
    margin-left: 8px;
    cursor: help;
}
/* Order-level "out of stock → plan production" pill. A LINK (not a span):
   clicking it deep-links to the planner's Negative Stock tab so the operator
   can resolve the shortfall fast. Danger-tinted to match the per-line badge. */
.order-stock-link {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    border-radius: 999px;
    background: var(--color-danger-bg);
    color: var(--color-danger-fg-deep);
    border: 1px solid var(--color-danger-light);
    font-size: var(--text-xs);
    font-weight: 600;
    margin-left: 8px;
    text-decoration: none;
    cursor: pointer;
}
.order-stock-link:hover {
    background: var(--color-danger-light);
    color: var(--color-danger-fg-deep);
}
.order-item-pick {
    margin-top: 10px;
    padding: 10px 12px;
    background: var(--color-warning-soft-bg);
    border: 1px dashed var(--color-warning-soft-border);
    border-radius: 8px;
}
.order-item-pick-label {
    font-size: var(--text-sm);
    font-weight: 700;
    color: var(--color-warning-soft-fg);
    margin-bottom: 8px;
}
.order-item-pick-hint {
    font-weight: 400;
    color: var(--color-warning-soft-fg);
    opacity: 0.8;
    margin-left: 4px;
}

/* Dark-mode overrides for the manual-pick picker. The hardcoded light-orange
   surfaces (#fff7ed) are white-on-white against the dark page; switch to
   muted amber tones that stay legible on --bg-secondary. */
[data-theme="dark"] .order-manual-pick-pill {
    background: var(--color-warning-soft-bg);
    color: var(--color-warning-soft-border);
    border-color: var(--color-warning-soft-border);
}
[data-theme="dark"] .order-item-pick {
    background: var(--color-warning-soft-bg);
    border-color: var(--color-warning-soft-border);
}
[data-theme="dark"] .order-item-pick-label {
    color: var(--color-warning-soft-border);
}
[data-theme="dark"] .order-item-pick-hint {
    color: var(--color-warning-soft-border);
}
.order-pick-slots {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-bottom: 10px;
}
.order-pick-slot {
    display: flex;
    gap: 8px;
    align-items: center;
}
.order-pick-slot .order-pick-select,
.order-pick-slot .order-pick-type-select {
    flex: 1;
    min-width: 0;
}
.order-pick-slot .order-pick-qty {
    flex: none;
    width: 56px;
    text-align: center;
}
.order-pick-remove {
    background: transparent;
    border: 1px solid var(--border-color);
    border-radius: 6px;
    width: 30px;
    height: 30px;
    cursor: pointer;
    color: var(--text-muted);
    font-size: var(--text-lg);
    line-height: 1;
}
.order-pick-remove:hover { background: var(--bg-primary); }
.order-pick-actions {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}
.order-pick-status {
    margin-top: 8px;
    font-size: var(--text-sm);
    color: var(--text-muted);
    min-height: 1.2em;
}
.order-pick-status.is-error { color: var(--danger-hover); font-weight: 600; }
.order-pick-recorded {
    padding: 8px 12px;
    background: var(--color-success-bg-soft);
    border-left: 3px solid var(--color-success-emerald);
    border-radius: 6px;
    font-size: var(--text-base);
    color: var(--color-success-fg);
    font-weight: 600;
}

.order-item-qty {
    font-size: var(--text-lg);
    font-weight: 800;
    color: var(--brand);
    font-variant-numeric: tabular-nums;
    align-self: center;
    flex-shrink: 0;
}

/* ============================================================
   Info tip — small ⓘ glyph that reveals a one-line explanation
   on hover/focus. Pure CSS, no JS. Used via the {{> info-tip}}
   partial; classes: .info-tip wraps button + bubble, button is
   .info-tip-trigger, bubble is .info-tip-bubble. Bubble defaults
   above the trigger; add .info-tip--below to flip it.
   ============================================================ */
.info-tip {
    position: relative;
    display: inline-flex;
    vertical-align: middle;
    margin-left: 4px;
    line-height: 1;
    text-transform: none;
    letter-spacing: normal;
    font-weight: normal;
}
.info-tip-trigger {
    width: 16px;
    height: 16px;
    min-width: 16px;
    min-height: 16px;     /* beats the global button{min-height} mobile rule */
    flex-shrink: 0;        /* don't let flex parents compress into an oval */
    aspect-ratio: 1 / 1;
    border-radius: 50%;
    border: 1px solid var(--border-color);
    background: var(--surface);
    color: var(--text-3);
    font-size: var(--text-2xs);
    font-weight: 700;
    line-height: 1;
    cursor: help;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-family: inherit;
    transition: color 0.15s, border-color 0.15s, background 0.15s;
}
.info-tip-trigger:hover,
.info-tip-trigger:focus {
    color: var(--brand);
    border-color: var(--brand);
    background: var(--brand-faint);
    outline: none;
}
.info-tip-bubble {
    position: absolute;
    bottom: calc(100% + 8px);
    left: 50%;
    transform: translateX(-50%) translateY(4px);
    width: max-content;
    max-width: 280px;
    padding: 8px 12px;
    background: var(--text-primary);
    color: var(--surface);
    border-radius: 8px;
    font-size: var(--text-xs);
    font-weight: 500;
    line-height: 1.45;
    text-align: left;
    text-transform: none;
    letter-spacing: normal;
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s ease, transform 0.15s ease;
    z-index: 200;
    white-space: normal;
}
.info-tip-bubble::after {
    content: '';
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
    border: 5px solid transparent;
    border-top-color: var(--text-primary);
}
.info-tip-trigger:hover + .info-tip-bubble,
.info-tip-trigger:focus + .info-tip-bubble,
.info-tip:hover .info-tip-bubble,
.info-tip:focus-within .info-tip-bubble {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
}
/* Flip the bubble below the trigger for tips near the top of the viewport */
.info-tip--below .info-tip-bubble {
    bottom: auto;
    top: calc(100% + 8px);
    transform: translateX(-50%) translateY(-4px);
}
.info-tip--below .info-tip-bubble::after {
    top: auto;
    bottom: 100%;
    border-top-color: transparent;
    border-bottom-color: var(--text-primary);
}
.info-tip--below:hover .info-tip-bubble,
.info-tip--below:focus-within .info-tip-bubble {
    transform: translateX(-50%) translateY(0);
}
/* Left/right edge anchoring — prevents the bubble from overflowing the
   page edge when the trigger is at the start or end of a row. */
.info-tip--left .info-tip-bubble {
    left: 0;
    transform: translateY(4px);
}
.info-tip--left .info-tip-bubble::after { left: 10px; }
.info-tip--left:hover .info-tip-bubble,
.info-tip--left:focus-within .info-tip-bubble { transform: translateY(0); }
.info-tip--right .info-tip-bubble {
    left: auto;
    right: 0;
    transform: translateY(4px);
}
.info-tip--right .info-tip-bubble::after { left: auto; right: 10px; }
.info-tip--right:hover .info-tip-bubble,
.info-tip--right:focus-within .info-tip-bubble { transform: translateY(0); }
/* Below + right-anchored. For a tip in the last column of a card that clips its
   own overflow (e.g. an overflow:hidden table-wrap, or a mobile overflow-x:auto
   scroll box): renders downward into the table body so it isn't cut off at the
   top edge, and right-aligns so a wide bubble doesn't spill past the right edge. */
.info-tip--below-right .info-tip-bubble {
    bottom: auto;
    top: calc(100% + 8px);
    left: auto;
    right: 0;
    transform: translateY(-4px);
}
.info-tip--below-right .info-tip-bubble::after {
    top: auto;
    bottom: 100%;
    left: auto;
    right: 10px;
    border-top-color: transparent;
    border-bottom-color: var(--text-primary);
}
.info-tip--below-right:hover .info-tip-bubble,
.info-tip--below-right:focus-within .info-tip-bubble { transform: translateY(0); }

/* ============================================================
   Setup health banner — mounted by public/js/setup-banner.js at
   the top of every page that has setup gaps. Light mode = warm
   amber on cream; dark mode = amber-tinted on dark surface.
   ============================================================ */
.setup-health-banner {
    background: var(--insight-bg);
    border: 1px solid var(--insight-border);
    color: var(--insight-text);
    border-radius: 10px;
    padding: 0.85rem 1.1rem;
    margin: 1rem auto;
    max-width: 1100px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    font-size: var(--text-sm);
    line-height: 1.4;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.04);
}
.setup-health-banner-body {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.6em;
    min-width: 0;
}
.setup-health-banner-headline { color: var(--insight-text); }
.setup-health-banner-detail   { color: var(--insight-text); opacity: 0.85; }
.setup-health-banner-cta {
    background: var(--insight-text);
    color: var(--surface);
    text-decoration: none;
    border-radius: 8px;
    padding: 0.45rem 0.95rem;
    font-weight: 600;
    white-space: nowrap;
    transition: opacity 0.15s ease;
}
.setup-health-banner-cta:hover {
    opacity: 0.88;
    color: var(--surface);
}
[data-theme="dark"] .setup-health-banner-cta {
    background: var(--color-warning-light);
    color: var(--color-code-bg);
}

/* ============================================================
   MOBILE RESPONSIVE — added 2026-05-22
   Single-codebase responsive (no UA sniffing). One breakpoint at
   768px for "phone vs everything else"; the existing 1024px rule
   in sidebar.css handles "tablet vs desktop" sidebar collapse.
   Body padding for top hamburger header + bottom tab bar lives in
   sidebar.css (which owns body layout and loads last).
   ============================================================ */

/* ── Cookie consent banner ── */
.cookie-banner {
    display: none; /* shown via JS style.display='flex' */
    position: fixed;
    bottom: 0; left: 0; right: 0;
    z-index: 9999;
    background: var(--bg-secondary);
    border-top: 1px solid var(--border-color);
    padding: 1rem 1.5rem;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    box-shadow: 0 -2px 12px var(--shadow);
}
.cookie-banner-text {
    margin: 0;
    color: var(--text-secondary);
    font-size: var(--text-base);
}
.cookie-banner-btn {
    background: var(--accent);
    color: #fff;
    border: none;
    border-radius: 8px;
    padding: 0.5rem 1.25rem;
    font-size: var(--text-base);
    cursor: pointer;
    white-space: nowrap;
}

/* Visibility helpers */
.mobile-only { display: none; }
@media (max-width: 768px) {
    .desktop-only { display: none !important; }
    .mobile-only  { display: revert !important; }
}

/* Tap-target utilities — reference the --m-tap* tokens so the values stay
   consistent across every route. Don't hardcode 44px / 56px in route blocks;
   apply these classes or use var(--m-tap*) instead. */
.tap-target {
    min-height: var(--m-tap);
    min-width: var(--m-tap);
}
.tap-target-lg {
    min-height: var(--m-tap-xl);
    padding-left: 20px;
    padding-right: 20px;
    font-size: var(--text-base);
    font-weight: 600;
}

/* Horizontal-scroll wrapper — opt-in on wide tables */
@media (max-width: 768px) {
    .scroll-x-mobile {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: thin;
    }
}

@media (max-width: 768px) {
    /* Stat-card grid (.stat-grid, used by /materials, /stats,
       /server-status, etc.) → 2×2 on phone instead of 1-col stack. */
    .stat-grid {
        grid-template-columns: 1fr 1fr;
        gap: 8px;
        margin-bottom: 1rem;
    }
    .stat-card {
        padding: 0.9rem 0.95rem;
    }

    /* Typography compresses — uses --m-* scale tokens */
    h1 { font-size: var(--m-page-title); line-height: 1.3; }
    h2 { font-size: var(--m-section-title); line-height: 1.3; }
    h3 { font-size: var(--m-subsection); }

    /* Defeat iOS auto-zoom on focus (any <16px input triggers it) */
    input, select, textarea { font-size: var(--m-input-min-fs); }

    /* Thumb-friendly form controls */
    input[type="text"],
    input[type="email"],
    input[type="password"],
    input[type="number"],
    input[type="search"],
    input[type="tel"],
    input[type="url"],
    input[type="date"],
    select,
    textarea {
        min-height: var(--m-tap-lg);
        padding: 12px 14px;
        width: 100%;
        box-sizing: border-box;
    }
    textarea { min-height: 96px; }

    /* Buttons get tap-target sizing */
    button, .btn, .btn-ghost, .btn-primary, .btn-secondary, .btn-hero, .btn-danger {
        min-height: var(--m-tap);
    }
    .btn-primary, .btn-hero {
        min-height: var(--m-tap-xl);
        padding: 14px 22px;
        font-size: var(--text-base);
    }

    /* iOS-home-screen pattern: strip the card chrome entirely (no card
       background, border, shadow, or radius) so the squircle icon sits
       directly on the page background. 3-column grid for real home-screen
       density at phone widths. The squircle on the icon is the only
       rounded shape — no more nested squircle-in-squircle. */
    .grid {
        grid-template-columns: repeat(3, 1fr) !important;
        gap: 16px 6px !important;
    }
    .card {
        background: transparent !important;
        border: none !important;
        box-shadow: none !important;
        border-radius: 0 !important;
        padding: 4px 0 !important;
        min-height: 0;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: flex-start;
        text-align: center;
    }
    .card:hover {
        background: transparent !important;
        box-shadow: none !important;
        transform: none !important;
        border-color: transparent !important;
    }
    .card::before {
        display: none !important;
    }
    .card-icon {
        width: 58px !important;
        height: 58px !important;
        padding: 14px;
        background: var(--brand-faint);
        color: var(--brand);
        border-radius: 16px;
        margin: 0 0 6px 0;
        display: block;
        box-sizing: border-box;
        flex-shrink: 0;
        box-shadow: 0 2px 8px var(--brand-border);
    }
    .card-title {
        font-size: var(--text-xs);
        font-weight: 500;
        line-height: 1.15;
        color: var(--text-2);
        letter-spacing: -0.005em;
        text-align: center;
    }
    .card-desc {
        display: none;
    }

    /* Section/content spacing */
    .section { margin-bottom: 1.5rem; }
    .section-header { flex-wrap: wrap; gap: 8px; }
    .content { padding: 16px; max-width: 100%; }
    /* Page wrapper: trim the desktop 2rem/3rem top/bottom on phone (the body
       already reserves bottom space for the tab bar) so cards aren't floating
       in dead space above and below. */
    .page-container { padding: 12px 12px 20px; max-width: 100%; }

    /* Hero compresses, actions stack full-width */
    .hero { padding: 28px 16px; }
    .hero h1 { font-size: var(--text-xl); line-height: 1.25; }
    .hero p  { font-size: var(--text-base); }
    .hero-actions {
        flex-direction: column;
        gap: 10px;
        width: 100%;
    }
    .hero-actions > * { width: 100%; }

    /* Top brand header collapses */
    header { padding: 12px 16px; }

    /* Tables shrink (use .scroll-x-mobile wrapper for genuinely wide ones) */
    table { font-size: var(--text-sm); }

    /* Setup banner stacks */
    .setup-health-banner {
        flex-wrap: wrap;
        margin: 12px;
        padding: 12px 14px;
        font-size: var(--text-sm);
    }
    .setup-health-banner-cta {
        width: 100%;
        text-align: center;
        margin-top: 4px;
    }

    /* Profile dropdown widens for thumb */
    .profile-dropdown, .profile-menu { min-width: 240px; }
    .profile-dropdown-item, .profile-menu-item {
        min-height: 48px;
        padding: 12px 16px;
    }

    /* Cookie banner (base rules are above in non-media section) */
    .cookie-banner {
        flex-direction: column;
        align-items: stretch;
        padding: 16px;
    }
    .cookie-banner button { width: 100%; }
}

/* Sticky-bottom action bar — primary action floats in thumb zone on phone.
   Hosts <body class="has-sticky-action"> so the bottom-tab-bar lifts above it. */
.sticky-action-bar { display: none; }
@media (max-width: 768px) {
    .sticky-action-bar {
        display: flex;
        position: fixed;
        bottom: 0;
        left: 0;
        right: 0;
        z-index: 900;
        padding: 12px 16px;
        padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px));
        background: var(--surface);
        border-top: 1px solid var(--border-color);
        box-shadow: 0 -4px 16px var(--shadow);
        gap: 10px;
    }
    .sticky-action-bar > * { flex: 1; min-height: 52px; }
}

/* ============================================================
   ROUTE-SPECIFIC MOBILE REFLOWS — added 2026-05-22
   Per-route overrides for the existing card / table / form layouts.
   Each block is mobile-only (@media max-width: 768px) so desktop
   stays exactly as it was.
   ============================================================ */

@media (max-width: 768px) {
    /* ── /orders ── phone-only redesign. The desktop card stacks chrome via
       absolute positioning (checkbox top-left, ship-by floating right,
       collapse top-right) that collides on a 375px width. On phone we:
         • hide bulk-select entirely (rare phone workflow),
         • restructure .order-card-top as a clean CSS grid
           [thumb | identity | status-pill],
         • inline the ship-by chip under the identity stack instead of
           floating it right (collision avoidance + better hierarchy),
         • give the card breathing padding so it doesn't feel squeezed. */

    /* Tabs scroll horizontally */
    .orders-tabs {
        flex-wrap: nowrap;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;            /* Firefox */
        margin-left: -16px;
        margin-right: -16px;
        padding: 0 16px;
    }
    .orders-tabs::-webkit-scrollbar { display: none; }  /* Chrome/Safari */
    .orders-tab {
        flex-shrink: 0;
        padding: 12px 14px;
        font-size: var(--m-body);
    }
    .orders-tab-divider { display: none; }

    /* Toolbar + search */
    .orders-toolbar {
        flex-direction: column;
        align-items: stretch;
        gap: var(--m-pad-sm);
    }
    .orders-search {
        max-width: 100%;
        min-width: 0;
        min-height: var(--m-tap-lg);
    }
    .orders-toolbar-spacer { display: none; }
    .orders-drag-hint { display: none; }      /* desktop "drag-to-bulk" hint */

    /* Bulk-status toolbar — appears only when ≥1 card is selected (JS toggles
       the [hidden] attribute). Header row: [N selected] [Select all] [Clear].
       Status options below in a 2-column grid so 7 statuses fit in ~4 rows
       instead of one 7-tall stack that ate most of the viewport. Sticky-top
       so it stays reachable while scrolling cards. */
    .orders-bulk-toolbar[hidden] { display: none !important; }
    .orders-bulk-toolbar {
        position: sticky;
        top: var(--m-top-bar-h);
        z-index: 700;
        display: grid !important;
        grid-template-columns: 1fr auto auto;
        grid-template-areas:
            "count selall clear"
            "stats stats  stats";
        column-gap: 12px;
        row-gap: 8px;
        padding: 12px;
        background: var(--surface);
        border: 1px solid var(--brand-border);
        border-radius: var(--m-radius);
        box-shadow: 0 6px 20px var(--brand-border);
        margin: 0 0 12px;
    }
    .orders-bulk-toolbar .orders-toolbar-spacer,
    .orders-bulk-toolbar .orders-bulk-label {
        display: none !important;
    }
    .orders-bulk-count {
        grid-area: count;
        font-size: var(--m-body);
        color: var(--text-primary);
        white-space: nowrap;
        align-self: center;
    }
    .orders-bulk-count strong {
        font-size: var(--text-lg);
        color: var(--brand);
        margin-right: 4px;
    }
    .orders-bulk-toolbar #ordersBulkSelectAll {
        grid-area: selall;
        font-size: var(--m-small);
        align-self: center;
    }
    .orders-bulk-toolbar #ordersBulkClear {
        grid-area: clear;
        font-size: var(--m-small);
        align-self: center;
    }

    /* Status options: 2-column grid of compact buttons. Each keeps its inline
       brand-color background (set by JS) so the user reads "tap this color
       to apply that status". Caret hidden since it's an apply-action, not
       an open-dropdown. Labels truncate if longer than fits. */
    .orders-bulk-statuses {
        grid-area: stats;
        display: grid !important;
        grid-template-columns: 1fr 1fr;
        gap: 6px;
        overflow: visible;
        flex: none;
        margin-top: 2px;
    }
    .orders-bulk-statuses .order-status-pill {
        width: 100%;
        min-height: var(--m-tap);
        padding: 8px 10px;
        font-size: var(--m-small);
        border-radius: 8px;
        justify-content: flex-start;
        text-align: left;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
    .orders-bulk-statuses .order-status-pill::after {
        content: none;     /* no dropdown caret on bulk-apply pills */
    }

    /* "Select all on this page" — discoverability entry-point that shows
       on phone before the user has tapped any card. Once the bulk toolbar
       is visible it has its own Select All link, so this one hides to
       avoid duplication. Inline button styled as a subtle text link. */
    .orders-select-all-fab {
        display: inline-flex;
        align-items: center;
        padding: 8px 12px;
        background: transparent;
        color: var(--brand);
        font-size: var(--m-small);
        font-weight: 600;
        text-decoration: underline;
        border: none;
        cursor: pointer;
        margin: 0 0 8px;
        min-height: var(--m-tap);
    }
    /* When toolbar is visible (no [hidden]) the fab hides — sibling combinator
       requires the fab to come AFTER the toolbar in DOM order, which it does
       per views/orders.hbs. */
    .orders-bulk-toolbar:not([hidden]) ~ .orders-select-all-fab {
        display: none;
    }

    /* Card grid → single column with comfortable gap */
    .orders-grid {
        grid-template-columns: 1fr;
        gap: var(--m-gap);
    }

    /* Card outer chrome: rounded + soft shadow. No left rail anymore —
       thumb is back inline in the top zone, checkbox lives in the footer. */
    .order-card {
        border-radius: var(--m-radius-lg);
        box-shadow: 0 1px 2px rgba(0,0,0,0.04), 0 4px 12px var(--brand-faint);
    }

    /* ── Checkbox: bottom-left of card. Absolute-positioned to overlay
       the footer's left edge; footer gets padding-left to clear it. */
    .order-card-select {
        display: flex !important;
        opacity: 1 !important;
        position: absolute;
        top: auto;
        bottom: 10px;
        left: var(--m-pad);
        width: 38px;
        height: 38px;
        border-radius: 8px;
        z-index: 4;
    }
    .order-card-select input { transform: scale(1.3); }

    /* Collapse arrow stays top-right when expanded */
    .order-card.is-expanded .order-card-collapse {
        display: flex !important;
        width: var(--m-tap) !important;
        height: var(--m-tap) !important;
        top: 6px;
        right: 6px;
        font-size: var(--text-lg);
    }

    /* ── Top zone: thumb left | headline+shipby right (2-col grid, thumb
       spans both rows). Clean, no checkbox to dodge. */
    .order-card-top {
        display: grid !important;
        grid-template-columns: var(--m-thumb-sm) 1fr;
        grid-template-areas:
            "thumb headline"
            "thumb shipby";
        column-gap: 12px;
        row-gap: 2px;
        align-items: start;
        padding: 10px var(--m-pad) 8px var(--m-pad);
    }
    .order-card.is-expanded .order-card-top {
        padding-right: calc(var(--m-pad) + var(--m-tap));
    }
    .order-card-thumb,
    .order-card-thumb-fallback,
    .order-card-thumb-mosaic {
        position: static !important;
        grid-area: thumb;
        top: auto !important;
        left: auto !important;
        width: var(--m-thumb-sm) !important;
        height: var(--m-thumb-sm) !important;
        border-radius: var(--m-radius);
        margin: 0;
    }
    .order-card-thumb-fallback svg {
        width: calc(var(--m-thumb-sm) / 2);
        height: calc(var(--m-thumb-sm) / 2);
    }
    .order-card-headline {
        grid-area: headline;
        min-width: 0;
    }
    .order-card-shipby {
        grid-area: shipby;
    }
    .order-card-buyer {
        font-size: var(--text-base);
        line-height: 1.25;
        margin-bottom: 4px;
    }
    .order-card-meta-row {
        font-size: var(--m-small);
        gap: 2px 8px;
        margin-bottom: 4px;
    }
    .order-card-totals {
        gap: 8px;
        flex-wrap: wrap;
    }
    .order-card-total { font-size: var(--text-lg); }
    .order-card-profit { font-size: var(--m-small); }

    /* Ship-by chip — inline pill that sits under the totals */
    .order-card-shipby {
        padding: 4px 10px;
        border-radius: 99px;
        font-size: var(--m-small);
        line-height: 1.3;
        display: inline-flex;
        align-items: baseline;
        gap: 6px;
        width: fit-content;
    }
    .order-card-shipby-label,
    .order-card-shipby-date { display: inline; font-size: inherit; }
    .order-card-shipby-label::after { content: ' '; }

    /* Items zone — back to symmetric padding */
    .order-card-items {
        padding: 6px var(--m-pad) 2px;
    }
    .order-card-item {
        padding: 3px 0;
        font-size: var(--m-body);
    }

    /* Footer: status pill stays visible so tap-to-change-status works.
       Padding-left clears the absolute-positioned checkbox at bottom-left
       (38px wide + 10px gap). Pills wrap onto the next line if needed. */
    .order-card-footer {
        padding: 8px var(--m-pad) 8px calc(var(--m-pad) + 38px + 10px);
        gap: 6px;
        border-top: 1px solid var(--border-light);
        min-height: calc(38px + 10px);   /* just clears the 38px checkbox at bottom:10px */
        flex-wrap: wrap;
        align-items: center;
    }
    .order-status-pill {
        min-height: 36px;
        padding: 8px 14px;
        font-size: var(--m-meta);
    }

    /* Detail-panel actions (Mark packed / Mark shipped): stack full-width so
       they read as two distinct tap targets instead of wrapping into a cramped,
       orphaned-looking pair. Mark packed is .btn-secondary (intermediate), Mark
       shipped is .btn-primary (the advancing CTA) — clear visual hierarchy. */
    .order-actions {
        flex-direction: column;
        align-items: stretch;
    }
    .order-actions .btn-primary,
    .order-actions .btn-secondary {
        width: 100%;
    }

    /* Page header: route titles are 2.6rem desktop, far too big on phone.
       Targeted override beats the global h1 rule's specificity loss. Uses
       the same --m-page-title token as the generic h1 rule above. */
    .page-header {
        margin-bottom: 1rem;
        padding-top: 0.25rem;
    }
    .page-header h1,
    .page-title {
        font-size: var(--m-page-title);
        letter-spacing: -0.02em;
    }
    /* Declutter: drop the descriptive subtitle sentences on phone. The route
       title stays, and the bottom tab bar also shows where you are. */
    .page-header p,
    .page-subtitle {
        display: none;
    }

    /* Status manager (?view=statuses) — table needs scroll-x; add-row stacks. */
    .status-table {
        display: block;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        white-space: nowrap;
        font-size: var(--text-sm);
    }
    .status-add-row {
        flex-direction: column;
        align-items: stretch;
        gap: var(--m-pad-sm);
    }
    .status-add-row .form-input {
        flex: 1 1 auto;
        width: 100%;
    }
    .status-add-row .btn-primary {
        width: 100%;
    }

    /* /products mobile rules moved to public/css/routes/product-management.css
       per CLAUDE.md §1.6. */

    /* ── /stock ── inherits its own breakpoints inside views/stock.hbs (760px,
       640px, 600px) — leave those untouched. This block patches the few
       things they don't cover or that collide with new mobile chrome. */

    /* Flat (embedded) tables scroll-x on mobile so they don't blow their card width */
    .data-table.data-table--flat {
        display: block;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        max-width: 100%;
    }
    .data-table.data-table--flat thead,
    .data-table.data-table--flat tbody {
        display: table;
        width: 100%;
        min-width: max-content;
    }

    /* Stock-adjust + add-variant inputs are scoped (.stock-adjust input[..])
       at higher specificity than my global mobile input rule, so they need
       a targeted override to (a) defeat iOS auto-zoom on focus (need 16px),
       (b) hit the 48px tap target. */
    .stock-adjust select,
    .stock-adjust input[type="number"],
    .add-variant-form input[type="text"],
    .add-variant-form select {
        font-size: var(--m-input-min-fs);
        min-height: var(--m-tap-lg);
    }
    .stock-adjust .btn-add,
    .stock-adjust .btn-remove {
        min-height: var(--m-tap);
        font-size: var(--m-body);
        padding: 12px;
    }

    /* Consumables toggle: 4-col on desktop crowds at 375px. Collapse to
       2-col [section-tag | chevron] and let the meta line wrap to row 2. */
    .consumables-toggle {
        grid-template-columns: 1fr auto;
        gap: 8px;
        padding: 14px;
    }
    .consumables-toggle-meta {
        grid-column: 1 / -1;
        margin-top: -2px;
    }
    .consumables-grid {
        padding: 0 14px 14px;
        padding-top: 14px;
    }

    /* Tighter inter-tile gap on phone (the 14px default reads as a big
       empty band between stacked tiles when each tile is short). And
       shorten the consumables-section top margin so it doesn't sit half
       a screen below the last product tile. */
    .stock-grid {
        gap: 8px;
    }
    .consumables-section {
        margin-top: 1rem;
    }

    /* Phone tile layout — vertical app-tile, compact. Icon top, product
       name centered below, then a single horizontal row pairing the stock
       count (left) with the low/neg pills (right). 4-row grid, items
       centered. Desktop 5-col grid layout is overridden via flex/grid.

       !important is intentional: views/stock.hbs has an inline <style> block
       that loads AFTER design-system.css and wins on equal specificity
       without it. Full migration of that inline block to public CSS is a
       follow-up cleanup task (see TODO). */
    .stock-tile-toggle {
        display: grid !important;
        grid-template-columns: auto auto;
        grid-template-areas:
            "icon    icon"
            "info    info"
            "counts  pills"
            "chevron chevron";
        justify-content: center;
        justify-items: center;
        align-items: center;
        padding: 14px 16px !important;
        column-gap: 12px !important;
        row-gap: 6px !important;
        text-align: center !important;
    }
    .stock-tile-icon {
        grid-area: icon;
        font-size: var(--text-2xl) !important;
    }
    .stock-tile-info {
        grid-area: info;
        text-align: center !important;
        overflow: visible !important;
    }
    .stock-tile-name {
        font-size: var(--text-lg) !important;
        white-space: normal !important;
        overflow: visible !important;
        text-overflow: clip !important;
    }
    .stock-tile-dim {
        font-size: var(--text-2xs) !important;
        white-space: normal !important;
        overflow: visible !important;
        text-overflow: clip !important;
    }
    .stock-tile-counts {
        grid-area: counts;
        text-align: right !important;
        line-height: 1.1 !important;
    }
    .stock-tile-total {
        font-size: var(--text-xl) !important;
    }
    .stock-tile-total-label {
        font-size: var(--text-2xs) !important;
    }
    .stock-tile-pills {
        grid-area: pills;
        flex-direction: row !important;
        justify-content: flex-start !important;
        align-items: center !important;
        flex-wrap: wrap;
        gap: 4px;
    }
    .stock-tile-pills:empty {
        display: none;       /* don't reserve space if no warnings */
    }
    .stock-tile-chevron {
        grid-area: chevron;
        margin-top: 2px;
    }

    /* /settings mobile rules live in public/css/routes/settings.css per
       CLAUDE.md §1.6 — route-specific styles in the route's own file,
       not design-system.css. */

    /* ── /setup ── views/layouts/setup.hbs has a 600px breakpoint already;
       this just covers the 600–768px tablet-portrait gap. */
    .setup-card {
        padding: 1.75rem 1.25rem;
    }

    /* /profit-analysis mobile rules moved to public/css/routes/profit-analysis.css
       per CLAUDE.md §1.6. */

    /* /production-planner mobile rules moved to
       public/css/routes/production-planner.css per CLAUDE.md §1.6. */
}

/* ============================================================
   Supporter badge — earned "award" pill (Immich-style).
   On-brand gradient + soft glow. Two animations:
     • a subtle shine sweep (an animated background layer, so it
       clips to the pill WITHOUT overflow:hidden, which would
       break the 3D flip below);
     • every 60s the pill hops + rolls ~4× and lands on its
       backside reading "Thank you!" (the ::after face).
   Reusable: homepage top bar, sidebar drawer, /support page.
   On-brand tokens only; white/rgba used solely for the sheen.
   ============================================================ */
.supporter-badge {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 0.4em;
    padding: 0.32em 0.8em;
    border-radius: 999px;
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.01em;
    line-height: 1;
    color: #fff;
    text-decoration: none;
    /* layer 0 = moving shine (clipped to the box automatically); layer 1 = base.
       Soft-edged band so there's no hard line to flicker at the loop. */
    background:
        linear-gradient(115deg, transparent 38%, rgba(255, 255, 255, 0.4) 50%, transparent 62%),
        linear-gradient(135deg, var(--brand) 0%, var(--brand-dark) 100%);
    background-size: 250% 100%, 100% 100%;
    background-position: 160% 0, 0 0;
    border: 1px solid var(--brand-border);
    box-shadow: 0 1px 8px var(--brand-glow), inset 0 1px 0 rgba(255, 255, 255, 0.28);
    transform-style: preserve-3d;
    backface-visibility: hidden;
    will-change: transform;
    transition: box-shadow 0.15s ease;
    animation:
        supporter-shine 6s ease-in-out infinite,
        supporter-flip 60s linear 10s infinite;
}
.supporter-badge:hover {
    color: #fff;
    box-shadow: 0 3px 14px var(--brand-glow), inset 0 1px 0 rgba(255, 255, 255, 0.28);
}
/* front content hides while the pill faces away (so it doesn't ghost through) */
.supporter-badge > svg,
.supporter-badge > span { backface-visibility: hidden; }
.supporter-badge svg { width: 13px; height: 13px; flex-shrink: 0; }

/* backside — revealed by the flip; says "Thank you!" */
.supporter-badge::after {
    content: "Thank you!";
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: inherit;
    background: linear-gradient(135deg, var(--brand-dark) 0%, var(--brand) 100%);
    color: #fff;
    font-weight: 700;
    white-space: nowrap;
    transform: rotateX(180deg);
    backface-visibility: hidden;
}

/* Shine sweeps L→R once, then SNAPS back while fully off-screen and holds —
   every position change at a boundary is clear→clear, so nothing flickers.
   160% and -60% both park the band completely outside the pill. */
@keyframes supporter-shine {
    0%, 12%       { background-position: 160% 0, 0 0; }   /* off-left, clear, hold */
    40%           { background-position: -60% 0, 0 0; }   /* swept across, off-right, clear */
    40.01%, 100%  { background-position: 160% 0, 0 0; }   /* snap back (clear→clear), hold */
}
/* Street-sign spinner: rotates around the HORIZONTAL axle. One continuous eased
   spin (accelerate → decelerate) to the backside, hold on "Thank you!", then a
   second eased spin back to the front. The per-keyframe cubic-beziers are what
   make it feel like a real sign winding up and coasting to a stop. */
@keyframes supporter-flip {
    /* The flip lives at the START of the cycle so a 10s animation-delay puts the
       first flip ~10s after load, then it repeats every 60s (10s, 70s, …). */
    0%   { transform: perspective(520px) rotateX(0deg);
           animation-timing-function: cubic-bezier(0.45, 0, 0.15, 1); }
    11%  { transform: perspective(520px) rotateX(1260deg); }      /* accel→decel spin to back */
    15%  { transform: perspective(520px) rotateX(1260deg);
           animation-timing-function: cubic-bezier(0.45, 0, 0.15, 1); }   /* hold "Thank you!" */
    20%, 100% { transform: perspective(520px) rotateX(1440deg); } /* coast to front, then idle */
}

.supporter-badge--lg { gap: 0.5em; padding: 0.6em 1.2em; font-size: var(--text-base); }
.supporter-badge--lg svg { width: 18px; height: 18px; }

@media (prefers-reduced-motion: reduce) {
    .supporter-badge { animation: none; }
}

/* ============================================================
   Dark-mode survivors (migrated from the retired dark-mode.css)
   ------------------------------------------------------------
   dark-mode.css was pre-token legacy: ~40 !important rules + raw
   hex, most of it dead (classes that no longer render) or redundant
   (components now dark-theme automatically via the [data-theme="dark"]
   token redefinitions in brand/brand.css). These are the only live
   rules, tokenized — no raw hex, no !important. 2026-06-09.
   ============================================================ */

/* Muted form labels in dark mode (bare <label>, e.g. register/settings). */
[data-theme="dark"] label { color: var(--text-secondary); }

/* Bare form controls without .form-input (e.g. register inputs). */
[data-theme="dark"] select,
[data-theme="dark"] input[type="number"],
[data-theme="dark"] input[type="text"] {
    background: var(--bg-tertiary);
    color: var(--text-primary);
    border-color: var(--border-color);
}
[data-theme="dark"] select:focus,
[data-theme="dark"] input:focus {
    border-color: var(--accent);
}

/* /orders detail item rows get a tinted, rounded card in dark mode. */
[data-theme="dark"] .order-item {
    background: var(--bg-tertiary);
    border-left-color: var(--border-color);
    border-radius: 10px;
    padding-left: 12px;
    padding-right: 12px;
}
