/* ============================================================================
   Level Ledger — Design System tokens (Phase 1 foundation)
   ----------------------------------------------------------------------------
   Centralized design tokens. The brand accent (--ll-primary) is copper (#C8862F),
   matching the mobile/manager surfaces; positive/value green lives separately in
   --ll-success so the two no longer share a value (the prior overload).

   No theme switching, dark mode, density, or animations are activated here —
   tokens are defined so those can be layered later without touching components.
   ============================================================================ */

/* ── Typography: warm/hospitality display headings (Phase 2). Offline-first — the heading
   font is the vendored 'LL Display' (drop a Fraunces/Bricolage woff2 at fonts/ll-display.woff2),
   gracefully falling back to a warm system serif when absent. Body stays a clean sans. ── */
@font-face {
  font-family: 'LL Display';
  /* Real Fraunces variable font (TTF) — the prior ll-display.woff2 failed to render, so headings
     fell back to a system serif/sans. The TTF is the same font validated in the native app. */
  src: url('/fonts/Fraunces.ttf') format('truetype'),
       url('/fonts/ll-display.woff2') format('woff2');
  font-weight: 300 800;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'LL Text';   /* Inter — the operational/data sans of the pairing (offline-vendored) */
  src: url('/fonts/Inter.ttf') format('truetype');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
:root {
  --ll-font-display: 'LL Display', 'Fraunces', 'Bricolage Grotesque', 'Iowan Old Style', 'Palatino Linotype', Palatino, 'Book Antiqua', Georgia, serif;
  --ll-font-body: 'LL Text', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
  /* ── Brand: copper "liquid gold" signature (proposal v1, locked) ── */
  --ll-brand: #C8862F;
  --ll-brand-strong: #9E6620;
  --ll-brand-bright: #E0A24A;
  --ll-brand-soft: rgba(200,134,47,.15);
  /* Copper as TEXT/LINK on a light surface: #C8862F is 2.99:1 (fails AA). This darker copper is ~4.7:1.
     Use for copper-colored text/links/icons; buttons keep --ll-primary (dark ink on a copper fill). */
  --ll-copper-ink: #9E6620;
  --ll-on-brand: #160E03;
  /* ── Warm neutrals: unify the system's TEMPERATURE with the copper brand so the
     accent reads as the host, not a guest in a cool room. Dark rail + light canvas
     structure is kept; only the temperature shifts (cool navy/blue → warm espresso/cream). ── */
  --ll-espresso:       #1b130b;   /* warm near-black — the backdrop copper glows against (sidebar) */
  --ll-espresso-hover: #2a1f12;
  --ll-cream:          #f6f1e7;   /* warm off-white canvas — paper/linen, hospitality */
}
/* Comfortable reading rhythm: airy body, tight display headings (the pairing balance). */
body { line-height: 1.55; }
h1, h2, h3, .toolbar h2,
.card-title, .scard-name, .comp-section-title, .modal-title { font-family: var(--ll-font-display); letter-spacing: -0.01em; line-height: 1.18; }
/* Display font on the big numeric KPIs too — Fraunces with tabular figures reads
   editorial and ties the headings + the data into one voice (homogeneous style). */
.stat-card-value, .kpi-value, .metric-value { font-family: var(--ll-font-display); font-variant-numeric: tabular-nums; letter-spacing: -0.01em; }

/* ── Confidence seal ── the recurring cost-confidence mark (llConfidenceSeal in ll-confidence-seal.js).
   Fill level encodes the state — ● Confirmed / ◑ Estimated / ○ Missing — monochrome copper so the hue
   stays free for the semantic chip/pill beside it. Sits inline before the confidence label. */
.ll-seal { display:inline-block; width:9px; height:9px; border-radius:50%; border:1.5px solid var(--ll-brand); box-sizing:border-box; vertical-align:baseline; margin-right:5px; flex:0 0 auto; }
.ll-seal--confirmed { background: var(--ll-brand); }
.ll-seal--estimated { background: linear-gradient(90deg, var(--ll-brand) 0 50%, transparent 50% 100%); }
.ll-seal--missing   { background: transparent; }
/* The Confirmed seal "stamps" in — a brief press + copper ink-bleed as the cost resolves to certain. */
@media (prefers-reduced-motion: no-preference) {
  .ll-seal--confirmed { animation: ll-seal-stamp .5s cubic-bezier(.2,.8,.2,1) both; }
  @keyframes ll-seal-stamp {
    0%   { transform: scale(.35); opacity: 0; box-shadow: 0 0 0 3px rgba(200,134,47,.35); }
    60%  { transform: scale(1.18); }
    100% { transform: scale(1); opacity: 1; box-shadow: 0 0 0 0 rgba(200,134,47,0); }
  }
}
/* Brand choice: Fraunces everywhere for consistency. Body sets it; form controls don't inherit
   font-family by default, so force it (inline monospace fields keep their own via specificity). */
button, input, select, textarea { font-family: inherit; }
table { font-variant-numeric: tabular-nums; }

/* ── Dark mode (desktop) — flips the semantic tokens; the heavily-tokenized UI follows.
   Light remains the default; `body.dark` opts in (persisted toggle in the sidebar). ── */
body.dark {
  color-scheme: dark;
  --ll-copper-ink:     #E0A24A;   /* on dark, the bright copper reads with plenty of contrast */
  /* Warm ink, not cool slate — the surface is espresso/copper, so the text is a warm off-white in the
     same temperature (was #f1f5f9…#94a3b8 blue-grey, which read as a guest palette on the brown ground).
     Luminance held ≈ the old values, so contrast is unchanged. */
  --ll-text-strong:    #f5efe4;
  --ll-text-primary:   #e8ddcc;
  --ll-text-body:      #d3c7b3;
  --ll-text-secondary: #a99a84;
  --ll-surface:          #211a12;
  --ll-surface-elevated: #2a2118;
  --ll-background:     #15100a;
  --ll-border:         #3a2f22;
  --ll-border-strong:  #4a3c2b;
  --ll-border-subtle:  #261d13;
  --ll-sidebar-bg:     var(--ll-espresso);   /* one warm near-black for the rail in both themes */
  --ll-sidebar-hover:  var(--ll-espresso-hover);
  --ll-sidebar-text:   #94a3b8;
  --ll-success:        #34d399;  --ll-success-bg: #0f2e22;
  --ll-warning:        #fbbf24;  --ll-warning-bg: #3a2c10;
  --ll-danger:         #f87171;  --ll-danger-bg:  #3a1620;
  --ll-info:           #60a5fa;  --ll-info-bg:    #142544;
  --ll-focus-ring:     rgba(200,134,47,.5);   /* copper focus */
}
body.dark { background: var(--ll-background); color: var(--ll-text-primary); }
body.dark input, body.dark select, body.dark textarea {
  background: var(--ll-surface-elevated); color: var(--ll-text-primary); border-color: var(--ll-border);
}
body.dark .llx-toast { background: var(--ll-surface-elevated); color: var(--ll-text-primary); border-color: var(--ll-border); }
body.dark #llx-mute { background: rgba(20,28,40,.85); }

/* The left sidebar is a PERMANENT dark surface — independent of the theme. Pin its token
   context to the light-mode (primitive) values so it renders identically in both light and
   dark mode (dark sidebar + light/dark content). Without this, dark mode would flip the
   sidebar's internal text/border tokens and break it (e.g. dark logo text on a dark bar). */
.sidebar {
  --ll-sidebar-bg:       var(--ll-espresso);
  --ll-sidebar-hover:    var(--ll-espresso-hover);
  --ll-sidebar-text:     var(--ll-slate-400);
  --ll-text-strong:      var(--ll-ink);
  --ll-text-primary:     var(--ll-slate-800);
  --ll-text-body:        var(--ll-slate-700);
  --ll-text-secondary:   var(--ll-slate-500);
  --ll-border:           var(--ll-slate-300);
  --ll-border-strong:    var(--ll-slate-400);
  --ll-border-subtle:    var(--ll-slate-100);
  --ll-surface:          var(--ll-white);
  --ll-surface-elevated: var(--ll-white);
  --ll-background:        var(--ll-slate-50);
}

:root {
  /* ── Primitive greys (raw, value = current) ── */
  --ll-ink:           #0f172a;
  --ll-slate-800:     #1e293b;
  --ll-slate-700:     #334155;
  --ll-slate-500:     #64748b;
  --ll-slate-400:     #94a3b8;
  --ll-slate-300:     #cbd5e1;
  --ll-slate-200:     #e2e8f0;
  --ll-slate-100:     #f1f5f9;
  --ll-slate-50:      #f8fafc;
  --ll-white:         #ffffff;

  /* ── Semantic: text ── */
  --ll-text-strong:    var(--ll-ink);       /* headings, KPI values   (#0f172a) */
  --ll-text-primary:   var(--ll-slate-800); /* default UI text        (#1e293b) */
  --ll-text-body:      var(--ll-slate-700); /* table cell body text   (#334155) */
  --ll-text-secondary: var(--ll-slate-500); /* labels, secondary text (#64748b) */
  --ll-text-muted:     var(--ll-slate-400); /* hints, captions        (#94a3b8) */
  --ll-text-inverse:   var(--ll-white);

  /* ── Semantic: surfaces / borders (warm-tinted to match the copper system) ── */
  --ll-surface:        #fffdf9;   /* card — barely-warm white (not cold over cream) */
  --ll-surface-elevated: #fffdf9;
  --ll-background:     var(--ll-cream);
  --ll-border:         #e9e1d3;   /* warm hairline (was cool slate) */
  --ll-border-strong:  #d8ccb6;
  --ll-border-subtle:  #f1ebe0;

  /* ── Semantic: sidebar ── */
  --ll-sidebar-bg:     var(--ll-espresso);
  --ll-sidebar-hover:  var(--ll-espresso-hover);
  --ll-sidebar-active: var(--ll-primary);
  --ll-sidebar-text:   var(--ll-slate-400);

  /* ── Semantic: brand + status ──
     --ll-primary is the BRAND ACCENT = copper (matches mobile/manager --accent #C8862F).
     It is intentionally distinct from --ll-success (positive/value green) so the two
     meanings, previously both #059669, no longer collide. On copper, use --ll-on-brand
     for text (copper is light enough that white fails AA). */
  --ll-primary:        var(--ll-brand);        /* #C8862F copper */
  --ll-primary-hover:  var(--ll-brand-strong); /* #9E6620 */
  --ll-secondary:      #c2843a;   /* brass accent — reserved, not yet applied */
  --ll-success:        #059669;  --ll-success-bg: #d1fae5;
  --ll-warning:        #b45309;  --ll-warning-bg: #fef3c7;
  --ll-danger:         #dc2626;  --ll-danger-bg:  #fee2e2;
  --ll-info:           #1d4ed8;  --ll-info-bg:    #dbeafe;
  --ll-focus-ring:     var(--ll-brand);   /* copper focus — on-brand, was cool blue */

  /* ── Typography scale (defined for Phase 2; not yet applied) ── */
  --ll-font-xs:  0.8125rem;  /* 13px floor */
  --ll-font-sm:  0.8125rem;  /* 13px */
  --ll-font-md:  0.875rem;   /* 14px */
  --ll-font-lg:  1rem;       /* 16px */
  --ll-font-xl:  1.25rem;    /* 20px */
  --ll-font-2xl: 1.875rem;   /* 30px */
  --ll-line-tight: 1.2;
  --ll-line-body:  1.45;
  --ll-weight-normal: 400;
  --ll-weight-medium: 500;
  --ll-weight-semibold: 600;
  --ll-weight-bold: 700;

  /* ── Spacing (4px scale) ── */
  --ll-space-xs: 4px;  --ll-space-sm: 8px;  --ll-space-md: 12px;
  --ll-space-lg: 16px; --ll-space-xl: 24px; --ll-space-2xl: 32px;

  /* ── Radius ── crisp, near-square "instrument/ledger" geometry (was 6/10/14, softer SaaS default) */
  --ll-radius-sm: 4px; --ll-radius-md: 6px; --ll-radius-lg: 8px;

  /* ── Shadow ── the identity is carried by HAIRLINE borders + a copper state-edge, not soft drop
     shadows. --ll-shadow-md is now a barely-there hairline lift; overlays keep the deeper --ll-shadow-lg. */
  --ll-shadow-sm: 0 1px 2px rgba(0,0,0,.04);
  --ll-shadow-md: 0 1px 0 rgba(0,0,0,.04);
  --ll-shadow-lg: 0 8px 24px rgba(0,0,0,.12);

  /* ── Motion (clamped <=200ms; not yet applied) ── */
  --ll-transition-fast: 120ms;
  --ll-transition-base: 160ms;
  --ll-transition-max:  200ms;

  /* ── Visualization palette (Visual-Identity arc, Fase 0) ───────────────────
     The diagram series are the bar's OWN liquids — warm-forward, hospitality,
     deliberately NOT the cool blue/teal of a generic ERP. Series 1 is the copper
     brand; the rest are a spirits-shelf gradient (wine → vermouth → curaçao →
     whisky → cassis). Used by inline-SVG viz (sparkline, timeline, donut, flow);
     no external chart library (offline-vendored doctrine). */
  --ll-chart-1: var(--ll-brand);   /* copper — primary series */
  --ll-chart-2: #7b2d26;           /* Barolo wine red */
  --ll-chart-3: #4e6e4e;           /* vermouth / herbal green (muted, not acid) */
  --ll-chart-4: #2e6e8e;           /* curaçao blue — the one cool counterpoint */
  --ll-chart-5: #d8a24a;           /* whisky amber — bright warm */
  --ll-chart-6: #6b4e8e;           /* cassis / violet accent */
  /* Viz semantics: thresholds reuse the status tokens; track = the "empty" arc/
     bar; ink = axis/label hairline text. */
  --ll-viz-ok:    var(--ll-success);
  --ll-viz-warn:  var(--ll-warning);
  --ll-viz-bad:   var(--ll-danger);
  --ll-viz-track: var(--ll-border);
  --ll-viz-ink:   var(--ll-text-secondary);
}

/* ── Visualization base classes (Fase 0) — containers only; the SVG itself is
   generated inline by the viz modules. No page consumes these yet, so adding them
   leaves every surface visually unchanged until a later phase opts in. ── */
.viz { display: inline-block; vertical-align: middle; line-height: 0; }
.viz-svg { display: block; overflow: visible; }
.viz-block { display: block; width: 100%; }
/* A small legend row for multi-series viz. */
.viz-legend { display: flex; flex-wrap: wrap; gap: var(--ll-space-md); align-items: center;
  font-size: var(--ll-font-sm); color: var(--ll-viz-ink); }
.viz-legend .viz-dot { display: inline-block; width: 9px; height: 9px; border-radius: 2px;
  margin-right: 5px; vertical-align: middle; }
/* The protagonist card — the current-shift "hero" (Fase C) and any lead KPI. A quiet
   copper top-edge marks it as the focal surface without shouting; everything else stays
   the calm default card. */
.hero-card { border-top: 3px solid var(--ll-brand); }

/* ── Barcode scanner ── shared across desktop (#barcode-scan-modal) + mobile (#mbc-overlay):
   the live camera stage is the hero — masked reticle + copper corner brackets + a sweeping
   laser, a glassy status chip, an optional torch toggle, and a green success flash on a read. */
.scanner-stage{position:relative;width:100%;aspect-ratio:4/3;max-height:54vh;background:#0b0a09;border-radius:var(--ll-radius-md);overflow:hidden;display:flex}
.scanner-video{width:100%;height:100%;display:block;object-fit:cover;background:#0b0a09}
.scanner-reticle{position:absolute;left:50%;top:48%;transform:translate(-50%,-50%);width:80%;height:44%;border-radius:12px;pointer-events:none;box-shadow:0 0 0 9999px rgba(11,10,9,.5)}
.sc-corner{position:absolute;width:24px;height:24px;border:3px solid var(--ll-primary);filter:drop-shadow(0 0 3px rgba(200,134,47,.5))}
.sc-corner.tl{left:-2px;top:-2px;border-right:0;border-bottom:0;border-top-left-radius:12px}
.sc-corner.tr{right:-2px;top:-2px;border-left:0;border-bottom:0;border-top-right-radius:12px}
.sc-corner.bl{left:-2px;bottom:-2px;border-right:0;border-top:0;border-bottom-left-radius:12px}
.sc-corner.br{right:-2px;bottom:-2px;border-left:0;border-top:0;border-bottom-right-radius:12px}
.scanner-laser{position:absolute;left:6%;right:6%;height:2px;top:6%;border-radius:2px;background:linear-gradient(90deg,transparent,var(--ll-primary),transparent);box-shadow:0 0 9px 1px rgba(200,134,47,.7);animation:scanSweep 2.1s cubic-bezier(.45,0,.55,1) infinite}
@keyframes scanSweep{0%{top:6%}50%{top:94%}100%{top:6%}}
.scanner-status-chip{position:absolute;left:50%;bottom:10px;transform:translateX(-50%);max-width:88%;background:rgba(11,10,9,.72);color:#fff;font-size:0.8125rem;line-height:1.3;padding:5px 12px;border-radius:999px;text-align:center;-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px)}
.scanner-torch{position:absolute;top:8px;right:8px;width:40px;height:40px;border-radius:50%;background:rgba(11,10,9,.6);border:1px solid rgba(255,255,255,.28);color:#fff;cursor:pointer;font-size:18px;line-height:1;display:flex;align-items:center;justify-content:center;-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px);transition:background .15s,transform .12s}
.scanner-torch:hover{transform:scale(1.06)}
.scanner-torch.on{background:var(--ll-primary);color:#1a1206;border-color:var(--ll-primary)}
.scanner-stage.detected .sc-corner{border-color:var(--ll-success);filter:drop-shadow(0 0 4px rgba(47,158,68,.6))}
.scanner-stage.detected .scanner-laser{display:none}
.scanner-stage.detected::after{content:'';position:absolute;inset:0;background:var(--ll-success);opacity:0;animation:scanFlash .5s ease-out;pointer-events:none}
@keyframes scanFlash{0%{opacity:.4}100%{opacity:0}}
@media(prefers-reduced-motion:reduce){.scanner-laser{animation:none;top:50%}.scanner-stage.detected::after{animation:none}}

/* ── Unified LOADING state (Usability #4, phase A) ───────────────────────────────────────────────
   A spinner + label, visually DISTINCT from an empty state (which is just text) so "still loading"
   never reads as "nothing here". Keeps the literal "Loading…" text node so the i18n overlay still
   translates it. Reuses the ll-spin keyframe (also defined here so the class works standalone). */
.ll-loading{display:flex;align-items:center;justify-content:center;gap:10px;padding:26px 16px;color:var(--ll-text-secondary);font-size:0.9rem}
.ll-loading::before{content:"";width:16px;height:16px;flex-shrink:0;border:2px solid var(--ll-border-strong);border-top-color:var(--ll-brand);border-radius:50%;animation:ll-spin .7s linear infinite}
@keyframes ll-spin{to{transform:rotate(360deg)}}
@media(prefers-reduced-motion:reduce){.ll-loading::before{animation:none}}

/* ── Unified inline ERROR (Usability #4, phase B) ────────────────────────────────────────────────
   One shared, theme-aware inline error built on the semantic danger tokens — the canonical name for a
   persistent, in-context error (validation, load failure). dashboard's .banner-error is the established
   alias that resolves to the same token language, so both read correctly on light and espresso grounds. */
.ll-inline-error{background:var(--ll-danger-bg);color:var(--ll-danger);border:1px solid color-mix(in srgb,var(--ll-danger) 38%,transparent);
  border-radius:var(--ll-radius-md,10px);padding:10px 14px;font-size:0.82rem}
