/* Magmatik Sales Dashboard — design system (cream / mauve, Poppins) */
@font-face { font-family:"Poppins"; src:url("../assets/fonts/Poppins-Regular.ttf") format("truetype"); font-weight:400; font-display:swap; }
@font-face { font-family:"Poppins"; src:url("../assets/fonts/Poppins-Medium.ttf") format("truetype"); font-weight:500; font-display:swap; }
@font-face { font-family:"Poppins"; src:url("../assets/fonts/Poppins-SemiBold.ttf") format("truetype"); font-weight:600 700; font-display:swap; }

:root {
  --cream:#FFFEF9; --cream-shade:#F6F3EB; --white:#FFFFFF;
  --ink:#1A1A1A; --ink80:rgba(26,26,26,.8); --ink60:rgba(26,26,26,.6); --ink40:rgba(26,26,26,.4);
  --ink25:rgba(26,26,26,.25); --ink15:rgba(26,26,26,.15); --ink08:rgba(26,26,26,.08); --ink04:rgba(26,26,26,.04);
  --mauve:#946C73; --mauve-hover:#825A61; --mauve-deep:#6E4A52; --mauve-tint:#F1E8EA; --mauve-soft:#E7D8DC; --mauve-light:#B89AA0;
  --teal:#006B68; --teal-tint:#E6EFEE; --slate:#6B7D8A; --slate-tint:#EDF0F2; --coral:#E74F3D;
  --accent:#946C73; --accent-soft:#F1E8EA;
  /* a much fainter wash than accent-soft, for a selected-row state that shouldn't
     compete with the metrics sitting on top of it */
  --sel-tint:rgba(148,108,115,.07);
  /* hairline tinted toward mauve-deep so borders read as warm paper edges, not grey rules */
  --line:rgba(110,74,82,.10); --line-soft:rgba(110,74,82,.06);
  --radius-lg:11px; --radius-md:8px; --radius-sm:5px;
  /* Layered shadows tinted toward the mauve-deep hue: a tight contact shadow, a mid
     ambient, and a wide soft cast — depth reads warm on cream, not grey and flat. */
  --shadow-soft:0 1px 1px rgba(110,74,82,.04),0 3px 8px rgba(110,74,82,.05),0 10px 26px rgba(110,74,82,.05);
  --shadow-card:0 1px 2px rgba(110,74,82,.06),0 8px 20px rgba(110,74,82,.10),0 26px 54px rgba(110,74,82,.11);
  --shadow-lift:0 2px 4px rgba(110,74,82,.06),0 14px 32px rgba(110,74,82,.12),0 34px 64px rgba(110,74,82,.13);
  --focus-ring:0 0 0 2px var(--cream),0 0 0 4px var(--mauve);
  --sync:#2E9E63;
}

* { box-sizing:border-box; }
html, body { margin:0; padding:0; background:var(--cream); color:var(--ink);
  font-family:"Poppins",system-ui,sans-serif; font-size:13px; -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility; }
/* Paper grain — a fixed, ultra-faint fractal-noise wash that sits *behind* the shell
   (z-index:-1) so the cream gutters read like stock, not flat digital fill, while the
   white panels stay perfectly clean on top. Pointer-inert; never touches text crispness. */
body::before { content:""; position:fixed; inset:0; z-index:-1; pointer-events:none; opacity:.5;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0.43 0 0 0 0 0.29 0 0 0 0 0.32 0 0 0 0.045 0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E"); }
[hidden] { display:none !important; }
::selection { background:var(--mauve-tint); color:var(--mauve-deep); }
a { color:var(--accent); text-decoration:none; }
button { font-family:inherit; }
img { max-width:100%; }

/* ---- interaction states (accessible focus + tactile press) ---- */
button, .cli-row, .rep-row { -webkit-tap-highlight-color:transparent; }
button:focus-visible, .mg-in:focus-visible, .mg-sel:focus-visible,
.cli-row:focus-visible, .rep-row:focus-visible, a:focus-visible {
  outline:none; box-shadow:var(--focus-ring); border-radius:4px;
}
.btn:active, .btn-reset:active, .cta:active, .seg button:active, .hamburger:active { transform:translateY(1px); }

/* mobile-only chrome — hidden on desktop, activated in the media queries below */
.topbar { display:none; }
.drawer-backdrop { display:none; }

.eyebrow { font-weight:600; font-size:9px; line-height:1; letter-spacing:.18em; text-transform:uppercase; color:var(--ink40); }
.title { font-weight:600; font-size:16px; line-height:1.2; letter-spacing:-.01em; color:var(--ink); margin-top:5px; }
.num { font-variant-numeric:tabular-nums; white-space:nowrap; }

[data-scroll]::-webkit-scrollbar { width:10px; height:10px; }
[data-scroll]::-webkit-scrollbar-thumb { background:var(--ink15); border-radius:8px; border:3px solid var(--cream); }
[data-scroll]::-webkit-scrollbar-track { background:transparent; }
@keyframes mgspin { to { transform:rotate(360deg); } }
@keyframes mgfade { from { opacity:0; transform:translateY(6px); } to { opacity:1; transform:none; } }

/* ---- shell ---- */
.app { display:flex; min-height:100dvh; }

/* ---- sidebar ---- */
.sidebar { width:256px; flex:none; height:100dvh; position:sticky; top:0; background:var(--cream-shade);
  border-right:1px solid var(--ink08); display:flex; flex-direction:column; padding:26px 22px; }
.brand-row { display:flex; align-items:center; gap:12px; }
.brand-row img { width:34px; height:34px; }
.brand-name { font-weight:600; font-size:15px; line-height:1; letter-spacing:.04em; color:var(--ink); }
.brand-sub { font-weight:500; font-size:9px; line-height:1.4; letter-spacing:.22em; text-transform:uppercase; color:var(--accent); margin-top:3px; }
.nav { margin-top:34px; display:flex; flex-direction:column; gap:2px; }
.navitem { position:relative; display:flex; align-items:center; gap:11px; padding:9px 12px; border-radius:var(--radius-sm); cursor:pointer;
  font-weight:500; font-size:13px; color:var(--ink60); background:transparent;
  transition:background .18s ease, color .18s ease, transform .18s ease; }
/* left accent rail — grows from the vertical centre into a full bar when active */
.navitem::before { content:""; position:absolute; left:0; top:50%; width:3px; height:0; transform:translateY(-50%);
  background:var(--accent); border-radius:0 3px 3px 0; transition:height .2s ease; }
.navitem:hover { background:var(--accent-soft); color:var(--mauve-deep); }
.navitem:hover:not(.active) { transform:translateX(2px); }
.navitem.active { background:var(--accent-soft); color:var(--mauve-deep); }
.navitem.active::before { height:60%; }
/* Grouped view nav. View items are the primary level (a touch bolder than the
   section subitems); the historical item carries a small second-line caption. */
.view-item { font-weight:600; }
.view-item .view-label { display:flex; flex-direction:column; gap:2px; min-width:0; }
.view-item .view-sub { font-weight:500; font-size:10px; line-height:1.3; letter-spacing:0;
  text-transform:none; color:var(--ink40); }
/* Section subnav under a view — indented and smaller. Only the active view's subnav
   shows; the body.view-* class toggles the others off (both share the same sections). */
.subnav { display:flex; flex-direction:column; gap:2px; margin:4px 0 6px; }
.subnav .navitem { padding-left:26px; font-size:12px; font-weight:500; }
body:not(.view-monthly) #subnavMonthly { display:none; }
body:not(.view-historical) #subnavHistorical { display:none; }
.nav-dot { width:5px; height:5px; border-radius:50%; background:var(--ink15); flex:none; transition:background .18s ease, transform .18s ease; }
.navitem:hover .nav-dot { background:var(--mauve-light); }
.navitem.active .nav-dot { background:var(--accent); transform:scale(1.2); }
.active-view { margin-top:26px; padding:16px; background:var(--white); border-radius:6px; border:1px solid var(--ink08); }
.active-view .lbl { font-weight:600; font-size:9px; line-height:1; letter-spacing:.2em; text-transform:uppercase; color:var(--ink40); }
.active-view .summary { margin-top:10px; font-weight:500; font-size:12px; line-height:1.5; color:var(--ink80); }
.active-view .count { margin-top:12px; display:flex; align-items:baseline; gap:6px; }
.active-view .count b { font-weight:600; font-size:19px; line-height:1; color:var(--accent); }
.active-view .count span { font-weight:500; font-size:11px; color:var(--ink40); }
.side-spacer { flex:1; }
.side-actions { display:flex; flex-direction:column; gap:8px; }
.btn { display:flex; align-items:center; gap:9px; width:100%; text-align:left; padding:9px 12px;
  border:1px solid var(--ink15); background:transparent; border-radius:4px; font-weight:500; font-size:12px; color:var(--ink80); cursor:pointer; transition:.15s; }
.btn:hover { background:var(--accent-soft); border-color:var(--ink25); }
.btn svg { stroke:var(--teal); flex:none; }

/* ---- main ---- */
/* 100dvh (not 100vh): on mobile the scroll container then matches the *visible*
   viewport, so the last panel clears the browser chrome and the sticky topbar
   stays reachable at the top. overscroll-behavior stops scroll-chaining jitter. */
.main { flex:1; height:100dvh; overflow-y:auto; overscroll-behavior:contain; position:relative; scroll-behavior:smooth; }
.filterbar { position:sticky; top:0; z-index:20; background:var(--cream); border-bottom:1px solid var(--ink08);
  padding:14px 34px; display:flex; flex-wrap:wrap; align-items:flex-end; gap:14px 18px; }
/* title block grows to push the filters to the right edge; when the filters can't fit
   beside it they wrap as a single group to their own line (never a partial break) */
.filterbar > :first-child { flex:1 1 auto; }
.filterbar-title { font-weight:600; font-size:16px; line-height:1.1; letter-spacing:-.01em; color:var(--ink); white-space:nowrap; }
.filterbar-sub { font-weight:500; font-size:11px; line-height:1.3; color:var(--ink40); margin-top:3px; }
/* flex:0 1 auto + min-width:0 lets the filter block shrink and wrap its own
   fields (e.g. when the Custom range From/To inputs appear) instead of
   overflowing the row to the right. */
.filters { display:flex; align-items:flex-end; gap:9px; flex-wrap:wrap; justify-content:flex-end; flex:0 1 auto; min-width:0; }
.field { display:flex; flex-direction:column; gap:4px; }
.field > span { font-weight:600; font-size:8px; line-height:1; letter-spacing:.16em; text-transform:uppercase; color:var(--ink40); }
.mg-in, .mg-sel { font-family:inherit; font-weight:500; font-size:12px; color:var(--ink);
  border:1px solid var(--ink15); background:var(--white); border-radius:4px; padding:6px 8px; }
.mg-sel { padding:6px 26px 6px 8px; min-width:112px; cursor:pointer; appearance:none; -webkit-appearance:none;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path d='M1 1l4 4 4-4' fill='none' stroke='%231A1A1A' stroke-opacity='0.5' stroke-width='1.2'/></svg>");
  background-repeat:no-repeat; background-position:right 10px center; }
input.mg-in[type=date]::-webkit-calendar-picker-indicator { opacity:.45; cursor:pointer; }
.btn-reset { padding:7px 13px; border:1px solid var(--ink15); background:transparent; border-radius:4px;
  font-weight:500; font-size:12px; color:var(--ink60); cursor:pointer; transition:.15s; }
.btn-reset:hover { background:var(--accent-soft); border-color:var(--ink25); }
/* the From/To pair flows inline with the other fields; display:contents lets the
   wrapper toggle visibility without adding a layout box */
.field-pair { display:contents; }

/* Live-sync pill — sits in the sidebar under the brand, so it shows on every view.
   A calm status marker, not a button, so a full pill radius is fine. Full-width
   under the brand (the flex-column sidebar stretches it). The dot's green comes
   from its own background; the ::after ring is the soft pulsing halo, which under
   prefers-reduced-motion collapses to nothing (animation-duration ~0), leaving a
   static green dot. */
.sync-pill { display:flex; align-items:center; gap:7px; margin-top:15px; padding:6px 12px;
  background:var(--white); border:1px solid var(--line); border-radius:999px;
  font-weight:500; font-size:11px; line-height:1; color:var(--ink40); }
.sync-pill #syncLabel { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.sync-dot { position:relative; width:7px; height:7px; border-radius:50%; background:var(--sync); flex:none; }
.sync-dot::after { content:""; position:absolute; inset:0; border-radius:50%;
  box-shadow:0 0 0 0 rgba(46,158,99,.4); animation:syncpulse 2s ease-out infinite; }
/* rgba literals below are --sync (#2E9E63) at the halo's own opacities — kept
   literal to match the rest of the sheet's rgba-literal technique. */
@keyframes syncpulse {
  0%   { box-shadow:0 0 0 0 rgba(46,158,99,.4); }
  70%  { box-shadow:0 0 0 7px rgba(46,158,99,0); }
  100% { box-shadow:0 0 0 0 rgba(46,158,99,0); }
}

/* ---- Period picker (years → months) ---- */
.periodpick { position:relative; display:flex; }
.periodpick-trigger { width:100%; display:flex; align-items:center; text-align:left; }
.periodpick-triggerlabel { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
/* Capped to the space beneath the trigger: at ≤1023px the page itself doesn't
   scroll (.app is position:fixed), so a 12-month level rendering past the
   viewport bottom would put the earliest months genuinely out of reach. The
   subtrahend covers the trigger's own offset from the viewport top (~169px at
   the static-filterbar breakpoints, less when sticky) plus the card's padding
   and a bottom margin. On any viewport tall enough for the content the cap
   never engages — it's purely defensive. */
.periodpick-panel { position:absolute; top:calc(100% + 6px); left:0; z-index:50;
  min-width:230px; max-width:min(300px,calc(100vw - 32px));
  max-height:max(140px,calc(100dvh - 184px)); display:flex; flex-direction:column;
  background:var(--white); border:1px solid var(--line-soft); border-radius:var(--radius-md);
  box-shadow:var(--shadow-card); padding:6px; }
/* min-height:0 lets the list actually shrink below its content height inside the
   flex column, so it — not the panel — absorbs the overflow and the year's back
   row stays pinned above it. The 6px panel padding keeps the scrolling list clear
   of the rounded corners. */
.pp-list { flex:1 1 auto; min-height:0; overflow-y:auto; overscroll-behavior:contain;
  display:flex; flex-direction:column; gap:1px; }
.pp-list::-webkit-scrollbar { width:10px; }
.pp-list::-webkit-scrollbar-thumb { background:var(--ink15); border-radius:8px; border:3px solid var(--white); }
.pp-list::-webkit-scrollbar-track { background:transparent; }
.pp-yearhead { flex:none; display:flex; margin-bottom:4px; padding-bottom:4px; border-bottom:1px solid var(--line-soft); }
.pp-row { display:flex; align-items:center; gap:9px; width:100%; padding:7px 9px; border:none;
  background:transparent; border-radius:var(--radius-sm); cursor:pointer; text-align:left;
  font-family:inherit; font-weight:500; font-size:12px; color:var(--ink80);
  transition:background .15s ease, color .15s ease; }
.pp-row:hover, .pp-row:focus-visible { background:var(--accent-soft); color:var(--mauve-deep); }
.pp-row.is-active { color:var(--mauve-deep); font-weight:600; }
.pp-dot { width:5px; height:5px; border-radius:50%; background:var(--ink15); flex:none;
  transition:background .18s ease, transform .18s ease; }
.pp-row:hover .pp-dot { background:var(--mauve-light); }
.pp-row.is-active .pp-dot { background:var(--accent); transform:scale(1.2); }
.pp-row--year .pp-label { flex:1; }
.pp-chev { font-size:12px; line-height:1; color:var(--ink40); flex:none; }
.pp-yearhead .pp-row { font-weight:600; color:var(--ink); }
.pp-yearhead .pp-chev--back { color:var(--ink60); }
.pp-label { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }

/* Active-filter chips — a full-width row that wraps below the filters, right-
   aligned to sit under them. Hidden entirely when no categorical filter is set. */
.chips { display:flex; align-items:center; flex-wrap:wrap; gap:8px; flex-basis:100%; justify-content:flex-end; padding-top:4px; }
.chips .chips-lbl { font-weight:600; font-size:8px; letter-spacing:.16em; text-transform:uppercase; color:var(--ink40); }
.chip { display:inline-flex; align-items:center; gap:7px; padding:4px 9px; background:var(--mauve-tint);
  border:1px solid var(--mauve-soft); border-radius:var(--radius-sm); font-weight:500; font-size:11px; color:var(--mauve-deep); cursor:pointer; }
.chip .x { font-size:10px; opacity:.55; }
.chip:hover { border-color:var(--mauve-light); }
.chip:hover .x { opacity:1; }
.chips .link { font-size:11px; }

.content { padding:30px 34px 56px; display:flex; flex-direction:column; gap:26px; }

/* Entry choreography — sections rise + fade in a short cascade on first paint. Runs once
   (the .content children persist across filter re-renders, so it never re-triggers on a
   filter change). Gives the dashboard a composed "assembling" feel instead of a hard cut. */
.content > * { animation:mgfade .55s cubic-bezier(.22,.61,.36,1) both; }
.content > *:nth-child(1) { animation-delay:.03s; }
.content > *:nth-child(2) { animation-delay:.09s; }
.content > *:nth-child(3) { animation-delay:.15s; }
.content > *:nth-child(4) { animation-delay:.21s; }
.content > *:nth-child(5) { animation-delay:.27s; }
.content > *:nth-child(6) { animation-delay:.33s; }
.content > *:nth-child(n+7) { animation-delay:.39s; }

@media (prefers-reduced-motion:reduce) {
  *, *::before, *::after { animation-duration:.001ms !important; animation-delay:0s !important;
    transition-duration:.001ms !important; scroll-behavior:auto !important; }
}

/* ---- KPI strip ---- */
/* minmax(0,1fr) (not bare 1fr) forces every column to an equal width — bare 1fr lets a
   track grow to fit its widest value, which made the cards different widths. 6-up only
   at ≥1440 where the columns are wide enough for the RON figures. */
.kpi-strip { display:grid; grid-template-columns:repeat(6,minmax(0,1fr)); gap:14px; }
.kpi-feature { grid-column:span 2; color:var(--cream); border-radius:var(--radius-lg); padding:22px 24px;
  position:relative; overflow:hidden; isolation:isolate;
  display:flex; flex-direction:column; box-shadow:var(--shadow-card);
  /* soft top-right highlight over the mauve gives the hero tile depth instead of a flat fill;
     the inset ring is a lit glass edge (bright top, shadowed base) that catches the eye */
  background:radial-gradient(120% 140% at 100% 0%, var(--mauve-hover) 0%, var(--accent) 46%, var(--mauve-deep) 100%);
  box-shadow:var(--shadow-card),inset 0 1px 0 rgba(255,255,255,.14),inset 0 -1px 0 rgba(0,0,0,.10); }
/* a wide diagonal sheen sweeping off the top-left corner — the "polished stone" catch-light */
.kpi-feature::before { content:""; position:absolute; inset:0; z-index:-1; pointer-events:none;
  background:linear-gradient(128deg, rgba(255,255,255,.10) 0%, rgba(255,255,255,0) 34%); }
.kpi-feature .ftop { display:flex; justify-content:space-between; align-items:flex-start; }
.kpi-feature .flabel { font-weight:600; font-size:9px; line-height:1; letter-spacing:.2em; text-transform:uppercase; opacity:.75; }
.kpi-feature img { width:18px; height:18px; opacity:.5; }
/* label pins to the top; the number block centres in the space beneath it so the tall
   hero (2-row span at ≤1439) reads balanced rather than bottom-heavy */
.kpi-feature .fbottom { display:flex; flex-direction:column; margin-top:auto; margin-bottom:auto; }
.kpi-feature .fval { font-weight:600; font-size:33px; line-height:1; letter-spacing:-.02em; }
.kpi-feature .fsub { font-weight:500; font-size:12px; line-height:1.4; opacity:.8; margin-top:8px; }
/* transactions + avg order sit in a hairline-topped footer strip so the hero holds two
   lines of context without a separate (redundant) card orphaning the KPI row */
.kpi-feature .fmeta { margin-top:14px; padding-top:12px; border-top:1px solid rgba(255,255,255,.16);
  display:flex; flex-wrap:wrap; gap:6px 16px; font-weight:500; font-size:11px; line-height:1; opacity:.82; }
.kpi-feature .fmeta span { white-space:nowrap; }
.kpi-feature .fmeta b { font-weight:600; font-size:13px; letter-spacing:-.01em; margin-right:4px; }
/* label pinned to the top, value+helper grouped at the bottom (mirrors the hero's
   top-label / bottom-number rhythm) so the number sits low on the same line as the hero
   figure and the card never looks crammed at the top */
.kpi-card { background:var(--white); border:1px solid var(--line-soft); border-radius:var(--radius-md); padding:20px;
  box-shadow:var(--shadow-soft); display:flex; flex-direction:column; min-height:126px;
  transition:box-shadow .25s ease, transform .25s ease, border-color .25s ease; }
.kpi-card:hover { box-shadow:var(--shadow-lift); border-color:var(--line); transform:translateY(-3px); }
.kpi-card .lbl { font-weight:600; font-size:9px; line-height:1.2; letter-spacing:.13em; text-transform:uppercase; color:var(--ink40); }
/* label pins to the top; the value block centres in the space beneath it (auto margins)
   so the number sits mid-card, not floated to the bottom — matches the hero rhythm */
.kpi-card .kv { display:flex; flex-direction:column; gap:9px; margin-top:auto; margin-bottom:auto; }
.kpi-card .val { font-weight:600; font-size:21px; line-height:1.05; letter-spacing:-.01em; color:var(--ink); }
/* every card reserves exactly one sub line (empty or not) and never wraps — so the value
   rows and sub rows line up pixel-for-pixel across all four cards */
/* one reserved sub line, never wrapping; a long value (e.g. the Daily "biggest
   sale" client name) clips with an ellipsis rather than overflowing the card. */
.kpi-card .sub { font-weight:500; font-size:11px; line-height:1.3; min-height:15px; white-space:nowrap;
  overflow:hidden; text-overflow:ellipsis; }

/* Period-over-period delta line. Ink by default (direction shown by the arrow,
   not colour); coral only for an adverse rise (e.g. discount climbing). On the
   mauve hero the text goes cream. */
.delta { display:flex; align-items:center; gap:5px; font-weight:500; font-size:10.5px; line-height:1.2; color:var(--ink40); }
.delta .arr { font-size:9px; }
.delta b { font-weight:600; color:var(--ink60); }
.delta.bad b { color:var(--coral); }
.delta.muted { color:var(--ink40); }
.kpi-feature .delta { color:rgba(255,254,249,.72); margin-top:9px; }
.kpi-feature .delta b { color:var(--cream); }

/* ---- banner ---- */
/* Neutral grey, not mauve — this is an informational data note, so it should read calm,
   not alert-like. Cool slate tint on paper-neutral text. */
.banner { display:flex; align-items:flex-start; gap:10px; padding:12px 16px; background:var(--slate-tint);
  border:1px solid var(--ink08); border-radius:4px; font-weight:500; font-size:12px; line-height:1.5; color:var(--slate); }
.banner .dot { width:6px; height:6px; border-radius:50%; background:var(--slate); margin-top:5px; flex:none; }
/* Coral FLAG variant (Daily high-discount alert) — a faint coral wash + coral dot,
   text kept in readable ink so the note reads as a caution, not an error state.
   Coral stays scoped to alerting; it never becomes a second general accent. */
.banner-flag { background:rgba(231,79,61,.07); border-color:rgba(231,79,61,.18); color:var(--ink80); }
.banner-flag .dot { background:var(--coral); }
/* Two stacked notes (flag + data note) breathe apart without a divider. */
#dailyNotes { display:flex; flex-direction:column; gap:12px; }

/* ---- panels ---- */
.panel { background:var(--white); border:1px solid var(--line-soft); border-radius:var(--radius-md);
  box-shadow:var(--shadow-soft); padding:22px 24px; transition:box-shadow .25s ease, transform .25s ease, border-color .25s ease; }
.panel:hover { box-shadow:var(--shadow-card); border-color:var(--line); transform:translateY(-2px); }
/* single-line titles now, so heads centre their right-side control/hint against the title
   (was baseline, which left the toggle sitting high); title drops its eyebrow offset */
.panel-head { display:flex; align-items:center; justify-content:space-between; gap:12px; margin-bottom:16px; min-height:26px; }
.panel-head .title { margin-top:0; }
.title-lead { margin-top:0; margin-bottom:16px; }
.panel-hint { font-weight:500; font-size:10px; line-height:1.3; color:var(--ink40); text-align:right; }
/* align-items:start so each panel sizes to its own row count — otherwise the shorter
   list (e.g. categories) stretches to match the taller one (brands), leaving a void. */
.grid-2 { display:grid; grid-template-columns:1fr 1fr; gap:18px; align-items:start; }
.grid-products { display:grid; grid-template-columns:300px 1fr; gap:18px; }

/* ---- trend ---- */
.trend-stats { display:flex; gap:26px; text-align:right; }
.trend-stats .k { font-weight:600; font-size:9px; line-height:1; letter-spacing:.14em; text-transform:uppercase; color:var(--ink40); }
.trend-stats .v { font-weight:600; font-size:14px; line-height:1.3; color:var(--ink); margin-top:4px; }
.trend-wrap { position:relative; }
.trend-svg { width:100%; height:170px; display:block; margin-top:8px; touch-action:none; }
/* Pointer crosshair + tooltip overlay. Inert to the pointer so it never steals
   the SVG's own move events; positioned in JS against the wrap. */
.trend-cursor { position:absolute; inset:0; pointer-events:none; }
.trend-cline { position:absolute; width:1px; background:var(--mauve); opacity:.35; }
.trend-dot { position:absolute; width:9px; height:9px; border-radius:50%; background:var(--accent);
  border:2px solid var(--white); transform:translate(-50%,-50%); box-shadow:0 0 0 3px rgba(148,108,115,.16); }
.trend-tip { position:absolute; transform:translate(-50%,calc(-100% - 12px)); white-space:nowrap;
  background:var(--white); border:1px solid var(--line); border-radius:var(--radius-sm);
  box-shadow:var(--shadow-soft); padding:6px 10px; text-align:center; }
.trend-tip .d { font-weight:600; font-size:9px; letter-spacing:.12em; text-transform:uppercase; color:var(--ink40); }
.trend-tip .v { font-weight:600; font-size:12px; color:var(--ink); margin-top:2px; }
.trend-axis { display:flex; justify-content:space-between; margin-top:8px; }
.trend-axis span { font-weight:500; font-size:10px; color:var(--ink40); }

/* ---- channel donut ---- */
/* The donut panel is shorter than the bestsellers table it sits beside; equal-height
   grid stretch would leave a void at the bottom, so the donut+legend group is centred
   in the space below the title (auto margins top/bottom) to fill the panel evenly. */
#channelPanel { display:flex; flex-direction:column; }
#channelPanel .donut-wrap { margin-top:auto; }
#channelPanel .legend { margin-bottom:auto; }
.donut-wrap { display:flex; justify-content:center; margin:14px 0; }
.donut-wrap svg { width:158px; height:158px; }
.legend { display:flex; flex-direction:column; gap:8px; }
.legend-row { display:flex; align-items:center; gap:9px; }
.legend-row .sw { width:9px; height:9px; border-radius:2px; flex:none; }
.legend-row .nm { flex:1; font-weight:500; font-size:12px; color:var(--ink80); }
.legend-row .pc { font-weight:500; font-size:12px; color:var(--ink40); }
.legend-row .vl { width:78px; text-align:right; font-weight:500; font-size:12px; color:var(--ink); }
/* Donut hover: arc widens (20→24) and its legend row lifts into the accent tint.
   The whole donut dims slightly so the hovered segment reads as the focus. */
.donut-seg { transition:stroke-width .16s ease, opacity .16s ease; cursor:pointer; }
.donut-wrap:hover .donut-seg { opacity:.5; }
.donut-wrap .donut-seg.on { stroke-width:24; opacity:1; }
.donut-main, .donut-sub { transition:opacity .16s ease; }
.legend-row { border-radius:4px; margin:0 -6px; padding:0 6px; transition:background .15s ease; cursor:default; }
.legend-row.hl { background:var(--sel-tint); }
.legend-row.hl .nm { color:var(--mauve-deep); font-weight:600; }

/* ---- bestsellers ---- */
.seg { display:flex; border:1px solid var(--ink15); border-radius:var(--radius-sm); overflow:hidden; background:var(--cream-shade); }
.seg button { padding:6px 13px; border:0; cursor:pointer; font-weight:500; font-size:11px; background:transparent; color:var(--ink60); transition:color .15s ease, background .15s ease; }
.seg button:hover:not(.on) { color:var(--mauve-deep); background:var(--accent-soft); }
.seg button + button { border-left:1px solid var(--ink15); }
.seg button.on { background:var(--accent); color:var(--cream); box-shadow:inset 0 1px 0 rgba(255,255,255,.16); }
.best-head { display:grid; grid-template-columns:26px 1fr 56px 92px; gap:8px; padding:8px 0; border-bottom:1px solid var(--ink08);
  font-weight:600; font-size:9px; letter-spacing:.1em; text-transform:uppercase; color:var(--ink40); }
.best-row { display:grid; grid-template-columns:26px 1fr 56px 92px; gap:8px; padding:9px 0; border-bottom:1px solid var(--ink04); align-items:center; }
.best-row .rank { font-weight:600; font-size:12px; color:var(--accent); }
.best-row .best-name { min-width:0; font-weight:500; font-size:12px; color:var(--ink); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.best-row .sku { font-weight:600; font-size:11px; color:var(--ink60); letter-spacing:.02em; }
.best-row .u { text-align:right; font-weight:500; font-size:12px; color:var(--ink60); }
.best-row .v { text-align:right; font-weight:500; font-size:12px; color:var(--ink); }

/* Sales by brand / category — same columnar pattern as Bestsellers, 5 cols. */
.sb-head { display:grid; grid-template-columns:1fr 48px 96px 92px 58px; gap:8px; padding:8px 0; border-bottom:1px solid var(--ink08);
  font-weight:600; font-size:9px; letter-spacing:.1em; text-transform:uppercase; color:var(--ink40); }
.sb-row { display:grid; grid-template-columns:1fr 48px 96px 92px 58px; gap:8px; padding:9px 0; border-bottom:1px solid var(--ink04); align-items:center; }
.sb-row .sb-name { min-width:0; font-weight:500; font-size:12px; color:var(--ink); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.sb-row .sb-u, .sb-row .sb-dr { text-align:right; font-weight:500; font-size:12px; color:var(--ink60); }
.sb-row .sb-v { text-align:right; font-weight:500; font-size:12px; color:var(--ink); }
/* D(%) in pale mauve — sets the derived discount rate apart from the hard RON figures. */
.sb-row .sb-dp { text-align:right; font-weight:500; font-size:12px; color:var(--mauve-light); }
.cell-r { text-align:right; }

/* Muted value bar under each brand/category row — a quiet ranking cue, not a
   second data series. Faint mauve-light on a near-invisible track, sitting on the
   row's bottom hairline so it reads as an extension of the divider. */
.sb-row { position:relative; }
.sb-row .sb-bar { position:absolute; left:0; right:0; bottom:-1px; height:2px; background:var(--ink04); border-radius:1px; }
.sb-row .sb-bar > i { display:block; height:100%; background:var(--mauve-light); border-radius:1px; opacity:.55; }

/* Table zero state — shown in place of rows when filters match nothing. */
.zero-state { padding:30px 10px; text-align:center; }
.zero-state .zs-msg { font-weight:500; font-size:12px; color:var(--ink40); }
.zero-state .link { margin-top:6px; }

/* ---- clients ---- */
.cli-head { display:grid; grid-template-columns:1fr 130px 96px 130px; gap:8px; padding:9px 12px; border-bottom:1px solid var(--ink08);
  font-weight:600; font-size:9px; letter-spacing:.1em; text-transform:uppercase; color:var(--ink40); }
.cli-row { display:grid; grid-template-columns:1fr 130px 96px 130px; gap:8px; padding:11px 12px; border-bottom:1px solid var(--ink04);
  align-items:center; cursor:pointer; border-radius:3px; transition:background .12s; }
.cli-row:hover { background:var(--cream-shade); }
.cli-row.open { background:var(--cream-shade); }
.cli-name { display:flex; align-items:center; gap:8px; min-width:0; }
.cli-name .nm { font-weight:500; font-size:13px; color:var(--ink); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; flex:0 1 auto; }
.cli-company { font-weight:500; font-size:11px; color:var(--ink40); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; flex:0 1 auto; min-width:0; }
.cli-chev { color:var(--accent); font-size:10px; transition:transform .15s; display:inline-block; }
.cli-row.open .cli-chev { transform:rotate(90deg); }
.cli-val { text-align:right; font-weight:600; font-size:13px; color:var(--ink); }
.cli-disc { text-align:right; font-weight:500; font-size:12px; color:var(--ink60); }
.cli-gp { text-align:right; font-weight:500; font-size:13px; color:var(--accent); }
.cli-detail { padding:8px 12px 16px 30px; background:var(--cream-shade); border-bottom:1px solid var(--ink04); }
.cli-detail .lbl { font-weight:600; font-size:9px; letter-spacing:.14em; text-transform:uppercase; color:var(--ink40); padding:8px 0; }
/* item table inside an expanded client row reuses the Daily ledger's .lb-items/.lb-ihead/.li-* — see below. */
.cli-detail .lb-items { margin-top:2px; }

/* ---- Daily ledger ("who bought") ----
   One block per purchase, always open. Blocks are set apart by whitespace and a
   single faint hairline — never a boxed card — keeping the panel calm even with
   many purchases. */
.daily-ledger { display:flex; flex-direction:column; }
.ledger-block { padding:16px 0; border-bottom:1px solid var(--ink04); }
.ledger-block:first-child { padding-top:4px; }
.ledger-block:last-child { padding-bottom:2px; border-bottom:0; }
.lb-head { display:flex; align-items:baseline; justify-content:space-between; gap:12px; }
.lb-cli { display:flex; align-items:baseline; flex-wrap:wrap; gap:6px 8px; min-width:0; }
.lb-name { font-weight:600; font-size:14px; line-height:1.2; color:var(--ink); }
.lb-cli .cli-company { flex:0 1 auto; }
.lb-meta { font-weight:500; font-size:11px; line-height:1.2; color:var(--ink40); }
/* Purchase date on a week/custom range. flex-basis:100% breaks it onto its own
   line under the name, so it never reads as part of the "last bought" date. */
.lb-date { flex-basis:100%; margin-top:3px; font-weight:500; font-size:11px; line-height:1.2; color:var(--ink40); }
.lb-total { flex:none; font-weight:600; font-size:15px; color:var(--ink); }
.lb-items { margin-top:11px; }
/* mini column header, one per block — quiet enough to read as part of the block */
.lb-ihead { display:grid; grid-template-columns:1fr 46px 118px 56px 104px; gap:8px; padding:0 0 7px;
  font-weight:600; font-size:8px; letter-spacing:.1em; text-transform:uppercase; color:var(--ink40); }
.lb-item { display:grid; grid-template-columns:1fr 46px 118px 56px 104px; gap:8px; padding:7px 0;
  border-top:1px solid var(--ink04); align-items:center; }
.li-name { min-width:0; font-weight:500; font-size:12px; color:var(--ink80); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.li-qty { text-align:right; font-weight:500; font-size:12px; color:var(--ink60); }
.li-price { text-align:right; font-weight:500; font-size:12px; color:var(--ink60); }
/* discount in pale mauve like the brand/category tables; coral once it breaches 20% */
.li-disc { text-align:right; font-weight:500; font-size:12px; color:var(--mauve-light); }
.li-disc.hot { color:var(--coral); }
.li-total { text-align:right; font-weight:500; font-size:12px; color:var(--ink); }

/* Ledger type badges — small tinted pills, one saturated (New = mauve) and two
   neutral (Recurring, Walk-in), so New is the only one that draws the eye. */
.badge { display:inline-flex; align-items:center; padding:2px 8px; border-radius:999px;
  font-weight:600; font-size:9px; line-height:1.5; letter-spacing:.06em; text-transform:uppercase; flex:none; }
.badge-new { background:var(--mauve-tint); color:var(--mauve-deep); }
.badge-rec { background:var(--cream-shade); color:var(--ink60); }
.badge-walkin { background:var(--ink04); color:var(--ink40); }

/* ---- reps ---- */
.rep-grid { display:grid; grid-template-columns:1fr 300px; gap:18px; }
.rep-head { display:grid; grid-template-columns:1.4fr 1fr 56px 70px 56px; gap:10px; padding:8px 0; border-bottom:1px solid var(--ink08);
  font-weight:600; font-size:9px; letter-spacing:.1em; text-transform:uppercase; color:var(--ink40); }
.rep-row { padding:10px 0; border-bottom:1px solid var(--ink04); cursor:pointer; border-radius:3px; transition:background .12s; }
.rep-row:hover { background:var(--cream-shade); }
.rep-row.sel { background:var(--sel-tint); }
.rep-cells { display:grid; grid-template-columns:1.4fr 1fr 56px 70px 56px; gap:10px; align-items:center; }
.rep-name { display:flex; align-items:center; gap:8px; font-weight:500; font-size:13px; color:var(--ink); }
.rep-name .dot { width:6px; height:6px; border-radius:50%; flex:none; }
.rep-v { text-align:right; font-weight:600; font-size:13px; color:var(--ink); }
.rep-x { text-align:right; font-weight:500; font-size:12px; color:var(--ink60); }
.rep-bar { margin-top:7px; height:5px; background:var(--cream-shade); border-radius:3px; overflow:hidden; }
.rep-bar > div { height:100%; border-radius:3px; }
.dossier { background:var(--cream-shade); border-radius:6px; border:1px solid var(--ink08); padding:22px 24px; }
.dossier .sel-full { width:100%; margin-top:8px; font-weight:600; font-size:14px; padding:9px 26px 9px 11px; }
.dossier-grid { display:grid; grid-template-columns:1fr 1fr; gap:10px; margin-top:14px; }
.dossier-kpi { background:var(--white); border-radius:4px; padding:14px; border:1px solid var(--ink08); }
.dossier-kpi .lbl { font-weight:600; font-size:9px; line-height:1.2; letter-spacing:.1em; text-transform:uppercase; color:var(--ink40); }
.dossier-kpi .val { font-weight:600; font-size:17px; line-height:1.1; letter-spacing:-.01em; color:var(--ink); margin-top:8px; }
.dossier-kpi .dsub { font-weight:500; font-size:10.5px; line-height:1.2; color:var(--ink40); margin-top:4px; }
.dossier-house { margin-top:14px; padding:14px 15px; border-radius:var(--radius-md); position:relative; overflow:hidden;
  background:radial-gradient(130% 150% at 100% 0%, var(--mauve-hover) 0%, var(--accent) 52%, var(--mauve-deep) 100%);
  box-shadow:var(--shadow-soft),inset 0 1px 0 rgba(255,255,255,.14),inset 0 -1px 0 rgba(0,0,0,.10); }
.dossier-house .lbl { font-weight:600; font-size:9px; line-height:1.2; letter-spacing:.12em; text-transform:uppercase; color:var(--cream); opacity:.7; }
.dossier-house .val { font-weight:600; font-size:16px; line-height:1.2; color:var(--cream); margin-top:6px; }
/* white-space:normal overrides the .num nowrap so the three figures wrap inside
   the narrow dossier tile instead of clipping at its right edge. */
.dossier-house .vsub { font-weight:500; font-size:11px; line-height:1.4; color:var(--cream); opacity:.78; margin-top:5px; white-space:normal; }

/* ---- empty / loading ---- */
.center-screen { min-height:100dvh; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:20px; padding:24px; text-align:center; }
.center-screen .spin { width:54px; height:54px; opacity:.9; animation:mgspin 9s linear infinite; }
.center-screen .hint { font-weight:600; font-size:10px; line-height:1; letter-spacing:.28em; text-transform:uppercase; color:var(--ink40); }
/* Live-data failure card — minimal: heading, a line, and a Retry button,
   centred in .center-screen (no boxed card needed). */
.fail-card { width:min(460px,92vw); display:flex; flex-direction:column; align-items:center; gap:14px; text-align:center; }
.fail-card h2 { margin:0; font-weight:600; font-size:18px; color:var(--ink); }
.fail-card p { margin:0; font-weight:500; font-size:12px; line-height:1.5; color:var(--ink40); }
.cta { padding:10px 18px; background:var(--accent); color:var(--cream); border:0; border-radius:5px; font-weight:600; font-size:13px; cursor:pointer; transition:.15s; }
.cta:hover { background:var(--mauve-hover); }
.link { background:none; border:0; color:var(--accent); font-weight:500; font-size:12px; cursor:pointer; }
.link:hover { color:var(--mauve-hover); }
.err { margin-top:10px; padding:9px 14px; background:var(--coral); color:#fff; border-radius:6px; font-weight:500; font-size:12px; }

/* ---- sign-in ---- (same grammar as the fail card; forms stack tight) */
.auth-card form { display:flex; flex-direction:column; align-items:stretch; gap:10px; width:min(280px,100%); }
.auth-card .cta { width:min(280px,100%); }
.auth-divider { font-weight:600; font-size:10px; letter-spacing:.28em; text-transform:uppercase; color:var(--ink40); }
.auth-input { padding:10px 12px; border:1px solid var(--ink40); border-radius:5px; background:transparent; color:var(--ink); font:inherit; font-size:13px; text-align:center; }
.auth-input:focus { outline:none; border-color:var(--accent); }

/* ---- responsive: tablet & mobile (additive; desktop cascade untouched) ---- */

/* Below 1440 the 6-up row can't hold the RON figures at an even width, so the strip
   becomes a hero block (2 cols × 2 rows) beside a uniform 2×2 of the four cards — every
   card identical, no lonely tall card, hero broad enough to keep its footer on one line.
   The flat 6-up row returns at ≥1440px; phones collapse to 2-up below. */
@media (max-width:1439px) {
  .kpi-strip { grid-template-columns:repeat(4,minmax(0,1fr)); }
  .kpi-feature { grid-row:span 2; }
}

@media (max-width:1023px) {
  /* App-shell lock. The shell is pinned to the *current* viewport (position:fixed
     inset:0), so the document body has nothing tall in flow and can never scroll or
     rubber-band. That removes the phantom shaded band at the bottom (previously the
     100dvh .main was taller than the visible area whenever the URL bar showed, letting
     the whole document scroll). Only .main scrolls now, and only vertically. */
  html, body { height:100%; overflow:hidden; overscroll-behavior:none; }
  .app { position:fixed; inset:0; min-height:0; }
  /* .main is the sole scroll container. overflow-x:hidden defeats the drift: without it
     overflow-y:auto forces overflow-x to compute as `auto`, so any sub-pixel width
     overflow let momentum scrolling slide the layout sideways. */
  .main { height:100%; overflow-x:hidden; overscroll-behavior:contain; }

  /* sidebar becomes an off-canvas drawer; .main stays the scroll container */
  .sidebar { position:fixed; top:0; left:0; height:100dvh; width:min(280px,86vw);
    transform:translateX(-100%); transition:transform .25s ease; z-index:50; overflow-y:auto;
    box-shadow:0 0 44px rgba(26,26,26,.20); }
  .app.drawer-open .sidebar { transform:none; }

  .drawer-backdrop { display:block; position:fixed; inset:0; z-index:45;
    background:rgba(26,26,26,.38); }

  /* slim sticky top bar with hamburger (lives inside .main so main keeps scrolling) */
  .topbar { display:flex; align-items:center; gap:12px; position:sticky; top:0; z-index:30;
    background:var(--cream); border-bottom:1px solid var(--ink08); padding:10px 16px; }
  .hamburger { display:flex; align-items:center; justify-content:center; width:38px; height:38px;
    border:1px solid var(--ink15); background:var(--white); border-radius:6px;
    color:var(--ink80); cursor:pointer; flex:none; }
  .hamburger:hover { background:var(--accent-soft); }
  .topbar-brand { display:flex; flex-direction:column; line-height:1; }
  .topbar-brand b { font-weight:600; font-size:14px; letter-spacing:.04em; color:var(--ink); }
  .topbar-brand span { font-weight:500; font-size:8px; letter-spacing:.2em; text-transform:uppercase;
    color:var(--accent); margin-top:3px; }

  /* filter bar: not sticky (scrolls away under the topbar), controls wrap full-width */
  .filterbar { position:static; padding:14px 16px; flex-wrap:wrap; gap:12px; }
  .filters { flex:1 1 100%; justify-content:flex-start; gap:10px; }
  .field { flex:1 1 132px; }
  .mg-sel, .mg-in { width:100%; min-width:0; }
  .periodpick-panel { left:0; right:0; min-width:0; max-width:none; }

  .content { padding:22px 16px 48px; gap:20px; }

  /* KPI strip keeps the 4-col hero-block layout from the ≤1439 rule (tablet). */

  /* multi-column sections collapse to one column */
  .grid-2, .grid-products, .rep-grid { grid-template-columns:1fr; }
}

@media (max-width:639px) {
  /* phones: 2-up cards under a full-width hero banner (hero back to a single row) */
  .kpi-strip { grid-template-columns:repeat(2,minmax(0,1fr)); gap:10px; }
  .kpi-feature { grid-row:auto; padding:18px; }
  .kpi-feature .fval { font-size:27px; }

  /* extra bottom padding clears the mobile browser chrome / home indicator */
  .content { padding:18px 12px calc(40px + env(safe-area-inset-bottom)); gap:16px; }
  .panel { padding:18px 15px; }
  .filterbar-title { font-size:15px; }

  /* trend panel head: the "incl VAT" qualifier steps back from the title, and the
     peak-day/daily-avg stats — which wrap onto their own line at this width — read
     left-aligned under the title instead of right-aligned toward the middle of the
     panel; the date half of "peak day" steps back so the RON figure carries the eye. */
  .title-sub { font-weight:500; font-size:11px; color:var(--ink40); }
  .trend-stats { text-align:left; }
  .trend-stats .tdate { font-weight:500; color:var(--ink60); }

  /* Data tables reflow to stacked rows instead of scrolling sideways — this keeps
     the content perfectly centred (no horizontal scroll region to catch the thumb)
     and lets every name show in full. Column headers give way to inline labels. */
  .best-head, .cli-head, .rep-head, .sb-head { display:none; }

  /* shared inline stat label (uppercase micro-caption above each number) */
  .best-row .u::before, .best-row .v::before,
  .cli-val::before, .cli-disc::before, .cli-gp::before,
  .sb-row .sb-u::before, .sb-row .sb-v::before, .sb-row .sb-dr::before, .sb-row .sb-dp::before,
  .rep-cells > span:nth-child(n+2)::before {
    display:block; font-weight:600; font-size:8px; line-height:1;
    letter-spacing:.1em; text-transform:uppercase; color:var(--ink40); margin-bottom:3px;
  }

  /* Bestsellers: rank rail, full product name on top, Units / Value beneath.
     Row-gap opened up from the title line to the stats line beneath it, so the
     two feel like distinct rows rather than crowding the wrapped product name. */
  .best-row { grid-template-columns:22px 1fr auto; column-gap:12px; row-gap:10px; padding:12px 2px; }
  .best-row .rank { grid-column:1; grid-row:1 / span 2; align-self:center; font-size:14px; }
  .best-row .best-name { grid-column:2 / 4; grid-row:1; white-space:normal; line-height:1.4; }
  .best-row .u { grid-column:2; grid-row:2; text-align:left; color:var(--ink); }
  .best-row .u::before { content:"Units"; }
  .best-row .v { grid-column:3; grid-row:2; text-align:right; }
  .best-row .v::before { content:"Value"; }

  /* Sales by brand / category: full name row, then Units / Value / D(RON) / D(%) as
     labelled stats in a 2-col grid — numbers left-aligned to sit under their label. */
  .sb-row { grid-template-columns:1fr 1fr; grid-template-areas:"name name" "u v" "dr dp";
    gap:9px 8px; padding:13px 2px; }
  .sb-name { grid-area:name; white-space:normal; overflow:visible; }
  .sb-u { grid-area:u; }
  .sb-v { grid-area:v; }
  .sb-dr { grid-area:dr; }
  .sb-dp { grid-area:dp; }
  .sb-row .sb-u, .sb-row .sb-v, .sb-row .sb-dr, .sb-row .sb-dp { text-align:left; }
  .sb-row .sb-u::before { content:"Units"; }
  .sb-row .sb-v::before { content:"Value"; }
  .sb-row .sb-dr::before { content:"D (RON)"; }
  .sb-row .sb-dp::before { content:"D (%)"; }

  /* Clients: full name row, then Value / Avg disc / Gross profit as labelled stats */
  .cli-row { grid-template-columns:1fr 1fr 1fr;
    grid-template-areas:"name name name" "val disc gp"; gap:9px 8px; padding:13px 12px; }
  .cli-name { grid-area:name; }
  .cli-name .nm, .cli-company { white-space:normal; overflow:visible; }
  .cli-val { grid-area:val; }
  .cli-disc { grid-area:disc; }
  .cli-gp { grid-area:gp; }
  .cli-val, .cli-disc, .cli-gp { text-align:left; }
  .cli-val::before { content:"Value"; }
  .cli-disc::before { content:"Avg disc"; }
  .cli-gp::before { content:"Gross profit"; }

  /* Reps: full name row, then Total sales / GP% / AOV / Txns beneath */
  .rep-cells { grid-template-columns:1.6fr 1fr 1fr 1fr; column-gap:8px; row-gap:8px; }
  .rep-cells .rep-name { grid-column:1 / -1; }
  .rep-cells .rep-v, .rep-cells .rep-x { text-align:left; }
  .rep-cells > span:nth-child(2)::before { content:"Total sales"; }
  .rep-cells > span:nth-child(3)::before { content:"GP%"; }
  .rep-cells > span:nth-child(4)::before { content:"AOV"; }
  .rep-cells > span:nth-child(5)::before { content:"Txns"; }
}

/* Daily ledger item grid stacks on phones — full item name, then Qty / Price /
   Disc / Total as labelled stats, following the same ::before idiom as the
   other tables. The mini column header gives way to the inline labels. */
@media (max-width:639px) {
  .lb-ihead { display:none; }
  .lb-item { grid-template-columns:1fr 1fr; grid-template-areas:"name name" "qty price" "disc total";
    gap:8px; padding:11px 0; }
  .li-name { grid-area:name; white-space:normal; }
  .li-qty { grid-area:qty; } .li-price { grid-area:price; }
  .li-disc { grid-area:disc; } .li-total { grid-area:total; }
  .lb-item > span { text-align:left; }
  .lb-item > span:not(.li-name)::before { display:block; font-weight:600; font-size:8px; line-height:1;
    letter-spacing:.1em; text-transform:uppercase; color:var(--ink40); margin-bottom:3px; }
  .li-qty::before { content:"Qty"; }
  .li-price::before { content:"Unit · incl VAT"; }
  .li-disc::before { content:"Disc"; }
  .li-disc:empty { display:none; } /* no discount on this line — drop the floating "Disc" label */
  .li-total::before { content:"Total"; }
}

/* ---- historical era: hide panels the era can't support ----
   Historical rows have NULL→''→0 cost/gp (no per-line cost data in the ERP
   archive), so GP/margin and rep-scorecard figures would read as false zeros.
   Line-level discounts ARE real in the archive (16,776 of 35,045 lines), so
   discount figures stay visible everywhere. The KPI cards below have no ids
   of their own (built in render.js), so they're targeted positionally by
   their fixed render order inside #kpiStrip: 1 hero + [GP, Cost, Discount,
   Units] cards. */
body.era-historical #kpiStrip > div.kpi-card:nth-of-type(2), /* Gross profit */
body.era-historical #kpiStrip > div.kpi-card:nth-of-type(3) { display:none; } /* Cost of sales (NULL → false "0 RON") */

/* The Active-view card reports the rep/brand/channel filter state, which only
   the monthly filter bar sets. Daily has no such filters — it slices by window
   alone — so the card would always read "All reps, brands & channels" over a
   line count for the whole current era, next to a view showing one day. */
body.view-daily .active-view { display:none; }

/* With two cards gone the strip holds hero(span 2) + Discount + Units = 4
   tracks, so any wider grid would leave dead trailing columns. Repack: 4
   explicit columns and the hero back to a single row — one clean line at
   every width ≥640. On phones (2-col base) the two cards go full-width under
   the hero instead of sitting beside empty tracks. */
body.era-historical .kpi-strip { grid-template-columns:repeat(4,minmax(0,1fr)); }
@media (max-width:1439px) {
  body.era-historical .kpi-feature { grid-row:auto; }
}
@media (max-width:639px) {
  body.era-historical .kpi-strip { grid-template-columns:repeat(2,minmax(0,1fr)); }
  body.era-historical .kpi-strip .kpi-card { grid-column:span 2; }
}

/* GP column in the client table — the one per-table figure the archive can't
   support (no cost data). Discount columns in brand/category/client tables
   stay visible: line-level discounts are real historical data. Hidden in both
   header and data rows so the grid stays aligned (both simply stop using
   their last track). */
body.era-historical .cli-head > span:nth-child(4),
body.era-historical .cli-gp { display:none; }

/* …and drop the hidden column's track so the client table doesn't keep dead
   trailing whitespace where GP used to sit. (The ≤639 stacked layout
   re-declares its own grid and simply loses the hidden area's row, so it
   needs no override.) */
@media (min-width:640px) {
  body.era-historical .cli-head,
  body.era-historical .cli-row { grid-template-columns:1fr 130px 96px; }
}

/* Rep scorecard section — all historical rows are attributed to a single
   "Administrator" rep, so per-rep breakdowns are meaningless. */
body.era-historical #sec-team { display:none; }

/* ---- print ---- */
@media print {
  @page { size: landscape; margin: 12mm; }
  * { -webkit-print-color-adjust:exact !important; print-color-adjust:exact !important; }
  /* Kill entry animations/transitions for print: `.content > *` starts at opacity:0
     (mgfade fill:both), so a print taken mid-animation renders blank/faint panels.
     Force every section visible and static. */
  *, .content > * { animation:none !important; transition:none !important; }
  .content > * { opacity:1 !important; transform:none !important; }
  html, body { height:auto !important; overflow:visible !important; background:#fff !important; }
  .mg-noprint, .sidebar, .topbar, .filterbar, .drawer-backdrop { display:none !important; }
  /* neutralise the ≤1023px mobile rule `.app{position:fixed;inset:0}` — left in place
     it pins the whole app to one viewport, so a portrait/narrow print clips to page 1. */
  .app { display:block !important; position:static !important; inset:auto !important; min-height:0 !important; }
  .main, [data-scroll] { height:auto !important; max-height:none !important; overflow:visible !important; display:block !important; }
  .content { padding-top:0 !important; }
  .panel:hover { transform:none !important; }
  .panel, .dossier, section { box-shadow:none !important; }
  /* Only keep the small KPI tiles unbreakable — forcing break-inside:avoid on the tall
     data panels (full brand/category tables, clients, team) pushes them past a page
     boundary and leaves blank pages. Large panels flow and split naturally instead. */
  .kpi-card, .kpi-feature { box-shadow:none !important; break-inside:avoid; page-break-inside:avoid; }
}
