/* ============================================================================
   AROS SIGNATURE LAYER — loads LAST, after integration.css.

   tokens/components/layout gave the app the AROS palette and geometry. This
   file carries the design *language* — docs/aros-design-language.md — across
   every page: overview, kpt, pnl, complaints, inventory, procurement, outlets,
   oos, reports, admin.

   Rules owned here: 1 (mono/sans split), 2 (numbers are objects), 3 (flat
   planes, hairline separation), 5 (dark marks importance), 6 (semantic colour
   only), 7 (state chips), 10 (thin measurement bars).
   Rules 4, 11 and 12 (card = bar + body + bar, anchored zones, density) belong
   to public/css/aros/overview.css. This file gives rule 5 something to mark by
   establishing the full-bleed header bar generically, and keeps its selectors
   at low specificity (`.chart-container > .chart-header:first-child`) so a
   page-scoped rule in overview.css always wins.

   Scope rule: restyle only classes that already exist in the markup. No new
   elements, no JS change. Where the language needs structure the DOM does not
   have (two-line value pills, the tolerance bar, the EST chip, nav counts),
   the vocabulary ships flagged NO MARKUP YET and is listed in the handover.
   ========================================================================== */

:root {
  /* Rule 1. The Nerd Font is installed locally; every fallback is a system
     font, so a machine without it degrades to SF Mono / Menlo, not a serif. */
  --aros-sig-mono: 'JetBrainsMono Nerd Font Mono', ui-monospace, SFMono-Regular,
                   'SF Mono', Menlo, monospace;

  --aros-sig-label-size:    0.6875rem;   /* 11px — labels, captions   */
  --aros-sig-label-size-sm: 0.625rem;    /* 10px — column heads, chips */
  --aros-sig-track:         0.08em;
  --aros-sig-label-weight:  500;

  /* Rule 5. Near-black, cooler than the graphite text ink so the bar reads as
     chrome rather than as a very bold heading. */
  --aros-sig-bar-bg:       #1B1F26;
  --aros-sig-bar-fg:       rgba(255, 255, 255, 0.94);   /* 16.4:1 on bar */
  --aros-sig-bar-fg-muted: rgba(255, 255, 255, 0.62);   /*  6.9:1 on bar */
  --aros-sig-bar-line:     rgba(255, 255, 255, 0.16);
  --aros-sig-bar-h:        34px;

  /* Rule 6. THE one blue for data. Darkened from --viz-series-1 (#2A78D6, the
     in-system blue) because white on #2A78D6 is 4.46:1 and chip text is 10px. */
  --aros-sig-blue:    #1D5BB8;   /* white on this = 6.4:1 */
  --aros-sig-blue-fg: #FFFFFF;

  /* THE SELECTED CONTROL, deliberately NOT the data blue. A pill saying "which
     view am I on" is chrome; the blue above is reserved for marks that encode a
     value. They were the same colour, which made the control read as data.
     Ink on the sand chrome, white on ink = 15.9:1. */
  --aros-sig-sel:    var(--p-graphite-950, #1A1A18);
  --aros-sig-sel-fg: #FFFFFF;
}

:root[data-mode="dark"] {
  --aros-sig-bar-bg:  #101010;
  --aros-sig-blue:    #4C8FE8;
  --aros-sig-blue-fg: #10131A;
  /* Inverted on dark: ink on ink would vanish, so the selected pill goes light. */
  --aros-sig-sel:    var(--p-graphite-025, #F5F4F0);
  --aros-sig-sel-fg: #10131A;
}

:root[data-theme="apple-light"] {
  --aros-sig-blue: var(--p-apple-blue-600, #0069D9);
}


/* ═══════════════════════════════════════════════════════════════════════════
   RULE 1 — TWO TYPE FAMILIES, STRICTLY ASSIGNED
   Sans carries content: values, headlines, prose, descriptions.
   Mono carries everything else: labels, card headers, column heads, units,
   captions, metadata, chips. There is no bold sans label in this app.
   ═════════════════════════════════════════════════════════════════════════ */

.card-label,
.card-desc,
.chart-desc,
.filter-label,
.filter-context-bar,
.header-subtitle,
.last-synced,
.comm-page-subtitle,
.comm-sync-status,
.rep-period-label,
.rep-field label,
.loc-field label,
.grp-sel-count,
.cmp-in-col-label,
.cmp-in-meta,
.cmp-d-label,
.cmp-in-trend-detail,
.insight-title,
.oos-hero-scope,
.oos-sub,
.oos-alert-meta,
.oos-imp-label,
.oos-imp-codes,
.oos-code,
.map-legend-item,
.progress-detail,
.slide-timeline-label,
.slide-text-small,
.nav-label,
.filter-group > label,
.grp-detail-pane label,
.modal-body label,
legend,
caption {
  font-family: var(--aros-sig-mono);
  text-transform: uppercase;
  letter-spacing: var(--aros-sig-track);
  font-weight: var(--aros-sig-label-weight);
  font-variant-numeric: tabular-nums;
}

.card-label,
.filter-label,
.filter-context-bar,
.header-subtitle,
.last-synced,
.comm-page-subtitle,
.comm-sync-status,
.rep-period-label,
.rep-field label,
.loc-field label,
.cmp-in-col-label,
.insight-title,
.progress-detail {
  font-size: var(--aros-sig-label-size);
  color: var(--color-text-muted);
  line-height: 1.4;
}

/* Rule 9 lives here too: the provenance line under a figure is a caption. */
.card-desc,
.chart-desc,
.oos-sub,
.oos-alert-meta,
.cmp-in-meta,
.cmp-in-trend-detail,
.slide-text-small,
.map-legend-item {
  font-size: var(--aros-sig-label-size-sm);
  font-weight: 400;
  letter-spacing: 0.06em;
  color: var(--color-text-subtle);
  line-height: 1.45;
}

/* Column heads — the same micro-label, one step smaller. Generic `th` so the
   language lands on tables this file has never seen. */
th,
.pnl-table th,
.rep-table th,
.oos-table th,
.cb-table th {
  font-family: var(--aros-sig-mono);
  font-size: var(--aros-sig-label-size-sm);
  font-weight: var(--aros-sig-label-weight);
  text-transform: uppercase;
  letter-spacing: var(--aros-sig-track);
  color: var(--color-text-muted);
  border-bottom: 1px solid var(--color-border);
}

/* Prose stays sans and stays unshouted — rule 1's other half. */
.oos-hero-note,
.chart-title + .chart-desc.is-prose,
.cmp-in-note,
.insight-text,
.grp-empty {
  text-transform: none;
  letter-spacing: normal;
}

.oos-hero-note,
.cmp-in-note,
.insight-text {
  font-family: var(--font-family-base, inherit);
}


/* ═══════════════════════════════════════════════════════════════════════════
   RULE 2 — NUMBERS ARE OBJECTS, NOT TEXT
   Value: large, 600, tight tracking, tabular. Unit demoted to ~half size on
   the baseline. Delta to the right in small mono, semantic colour.
   ═════════════════════════════════════════════════════════════════════════ */

/* Tabular figures are mandatory — digits align column-to-column AND row-to-row. */
.card-value,
.num,
.rep-num,
.oos-num,
.value,
.oos-hero-items,
.oos-hero-money,
.oos-imp-per,
.progress-text,
.grp-pill-count,
.oos-pill-count,
td,
th {
  font-variant-numeric: tabular-nums;
}

/* Figures inside tables also take the mono face so the column reads as a rule. */
.pnl-table td.num,
.rep-table td.rep-num,
.oos-table .oos-num,
.pnl-table .total-row td,
.rep-table .rep-subtotal td {
  font-family: var(--aros-sig-mono);
  letter-spacing: -0.01em;
}

/* The value. Size is bounded by the card so six KPIs in a row can never push a
   horizontal scrollbar; a row of four or fewer gets the full 34-40px hero. */
.summary-card { container-type: inline-size; }

.card-value {
  font-family: var(--font-family-base, inherit);
  font-size: clamp(1.15rem, 13cqi, 1.75rem);
  font-weight: 600;
  letter-spacing: -0.025em;
  line-height: 1.12;
  color: var(--color-text);
  margin-top: 3px;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.summary-cards:not(:has(.summary-card:nth-child(5))) .card-value,
.financial-cards:not(:has(.summary-card:nth-child(5))) .card-value {
  font-size: clamp(1.4rem, 13cqi, 2.375rem);   /* up to 38px */
}

.oos-hero-items,
.oos-hero-money {
  font-weight: 600;
  letter-spacing: -0.025em;
}

/* The demoted unit. Only .oos-hero-unit exists in the markup today; the rest
   are the shapes a follow-up markup change would emit. NO MARKUP YET for the
   KPI cards — see the handover list. */
.oos-hero-unit,
.card-value .unit,
.card-value small,
.oos-hero-money .unit,
.aros-unit {
  font-size: 0.5em;
  font-weight: 500;
  color: var(--color-text-subtle);
  letter-spacing: 0.01em;
  margin-left: 2px;
  vertical-align: baseline;
  text-transform: none;
}

/* Delta / annotation: small mono, semantic colour, sits to the right. */
.positive,
.negative,
.pnl-table .positive,
.pnl-table .negative,
.aros-delta {
  font-family: var(--aros-sig-mono);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
}

.positive, .pnl-table .positive { color: var(--color-status-good-text); }
.negative, .pnl-table .negative { color: var(--color-status-critical-text); }


/* ═══════════════════════════════════════════════════════════════════════════
   RULE 3 — FLAT PLANES, HAIRLINE SEPARATION
   Page (porcelain) → card (white) → nested surface (light grey).
   1px border and a plane change, never a shadow. No translucency, no
   gradients, no glass. This actively neutralises the legacy .glass-card.
   ═════════════════════════════════════════════════════════════════════════ */

.glass-card,
.summary-card,
.chart-container,
.oos-hero-card,
.insight-card,
.cmp-insight-card,
.cmp-card,
.slide-card,
.grp-detail-pane,
.grp-stores-pane {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg, 14px);
  box-shadow: none;
  background-color: var(--color-surface);
  background-image: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

/* Hover is a border change, not a lift. */
.glass-card:hover,
.summary-card:hover,
.chart-container:hover {
  box-shadow: none;
  border-color: var(--color-border-strong);
}

/* The insight card's radial bloom is decoration (rules 3 + 6). */
.cmp-insight-card::before { display: none; }

/* Nested surfaces: header bars, wells, footers, toolbars. */
.filter-context-bar,
.chart-error,
.chart-empty,
.oos-empty,
.cmp-empty,
.cmp-in-action,
.rep-print-head {
  background: var(--color-surface-alt);
  background-image: none;
  border: 1px solid var(--color-border);
  box-shadow: none;
}

/* Shadow survives only where something genuinely floats. */
.select-dropdown,
.modal-content,
.loc-modal-content,
.store-popup,
.d3-tooltip { box-shadow: var(--elevation-overlay); }

/* ── THE tooltip ────────────────────────────────────────────────────────────
   One card, shared by every chart in the app. It was a translucent dark glass
   panel; rules 1 and 3 both refuse that (no translucency, no glass), and a dark
   plane floating over light cards read as a foreign object. It is now a light
   sectioned card built from the same surface/border/ink tokens as everything
   else, so it looks like a piece of the dashboard that lifted off the page.

   Anatomy — four zones, each optional, in this order:
     .tt-id    who and when
     .tt-main  the number, with an optional range rail
     .tt-rows  any number of label/value pairs (multi-series charts live here)
     .tt-cmp   the one comparison worth footing the card with
   Padding lives on .d3-tooltip so legacy `<strong>x</strong>y<br>z` content
   still sits correctly; the zones bleed back out to the edges (--tt-px/py).
   ─────────────────────────────────────────────────────────────────────────── */
.d3-tooltip {
  --tt-px: 13px;
  --tt-py: 10px;
  background: var(--color-surface);
  background-image: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  color: var(--color-text);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--tt-py) var(--tt-px);
  overflow: hidden;
  font-family: var(--font-family-base, inherit);
  font-size: 0.75rem;
  line-height: 1.5;
  font-variant-numeric: tabular-nums;
  max-width: 268px;
}

/* The name line of a tooltip is a label, so it takes the mono micro-label
   treatment rather than reading as a bold sans heading. */
.d3-tooltip strong {
  display: block;
  margin-bottom: 3px;
  font-family: var(--aros-sig-mono);
  font-size: var(--aros-sig-label-size-sm);
  font-weight: 700;
  letter-spacing: var(--aros-sig-track);
  text-transform: uppercase;
  color: var(--color-text);
}

/* Zones bleed to the card edge; a shared rule keeps the four in step. */
.d3-tooltip .tt-id,
.d3-tooltip .tt-main,
.d3-tooltip .tt-rows,
.d3-tooltip .tt-cmp {
  margin-left: calc(var(--tt-px) * -1);
  margin-right: calc(var(--tt-px) * -1);
  padding-left: var(--tt-px);
  padding-right: var(--tt-px);
  border-bottom: 1px solid var(--color-border);
}
.d3-tooltip > :first-child { margin-top: calc(var(--tt-py) * -1); }
.d3-tooltip > :last-child  { margin-bottom: calc(var(--tt-py) * -1); border-bottom: 0; }

/* Zone 1 — who and when. */
.d3-tooltip .tt-id { padding-top: 9px; padding-bottom: 8px; }
.d3-tooltip .tt-name {
  font-family: var(--aros-sig-mono);
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-text);
}
.d3-tooltip .tt-sub {
  font-family: var(--aros-sig-mono);
  font-size: 0.59rem;
  letter-spacing: 0.04em;
  color: var(--color-text-subtle);
  margin-top: 2px;
}

/* Zone 2 — the number. Big enough to be the reason you hovered. */
.d3-tooltip .tt-main { padding-top: 11px; padding-bottom: 10px; }
.d3-tooltip .tt-v {
  font-size: 1.75rem;
  font-weight: 600;
  letter-spacing: -0.025em;
  line-height: 1;
  color: var(--color-text);
}
.d3-tooltip .tt-u {
  font-size: 0.42em;
  font-weight: 500;
  color: var(--color-text-muted);
  margin-left: 3px;
}

/* The range as a rail with the point estimate marked — a band you can see beats
   two numbers you subtract in your head. */
.d3-tooltip .tt-rail {
  position: relative;
  height: 3px;
  border-radius: 999px;
  background: var(--color-surface-alt);
  margin: 11px 0 5px;
}
.d3-tooltip .tt-rail > i {
  position: absolute;
  top: 50%;
  width: 7px; height: 7px;
  margin: -3.5px 0 0 -3.5px;
  border-radius: 999px;
  background: var(--color-text);
}
.d3-tooltip .tt-legs {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
  font-family: var(--aros-sig-mono);
  font-size: 0.59rem;
  color: var(--color-text-subtle);
}
.d3-tooltip .tt-legs .tt-legs-l {
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* Zone 3 — label/value pairs. Values right-aligned so they compare vertically. */
.d3-tooltip .tt-rows { padding-top: 7px; padding-bottom: 7px; }
.d3-tooltip .tt-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 14px;
  padding: 1.5px 0;
}
.d3-tooltip .tt-row > span:first-child {
  color: var(--color-text-muted);
  font-size: 0.7rem;
}
.d3-tooltip .tt-row > span:last-child {
  font-family: var(--aros-sig-mono);
  font-weight: 700;
  color: var(--color-text);
  white-space: nowrap;
}
/* A series row carries its own swatch, so identity is never colour-alone. */
.d3-tooltip .tt-row > span:first-child > i {
  display: inline-block;
  width: 8px; height: 8px;
  border-radius: 2px;
  margin-right: 6px;
  vertical-align: baseline;
}

/* Zone 4 — the comparison, on the alt surface so it reads as a footing. */
.d3-tooltip .tt-cmp {
  padding-top: 8px;
  padding-bottom: 8px;
  background: var(--color-surface-alt);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
.d3-tooltip .tt-cl {
  font-family: var(--aros-sig-mono);
  font-size: 0.56rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}
.d3-tooltip .tt-cv {
  font-family: var(--aros-sig-mono);
  font-size: 0.72rem;
  font-weight: 700;
  color: var(--color-text);
  white-space: nowrap;
}
.d3-tooltip .tt-cmp.is-empty { justify-content: flex-start; }
.d3-tooltip .tt-cmp.is-empty .tt-cl { text-transform: none; letter-spacing: 0.02em; }

/* Direction uses the AA-safe text companions, not the mark hues. */
.d3-tooltip .tt-up   { color: var(--color-status-good-text); font-weight: 700; }
.d3-tooltip .tt-dn   { color: var(--color-status-critical-text); font-weight: 700; }
.d3-tooltip .tt-flat { color: var(--color-text-subtle); font-weight: 600; }


/* ═══════════════════════════════════════════════════════════════════════════
   RULE 5 — DARK MARKS IMPORTANCE  (+ the bar rule 5 marks by)
   .chart-header is already "label left, controls right" and is always the
   first child of .chart-container, so the full-bleed bar needs no new element:
   the header is pulled out to the card's padding edge. .chart-container is
   overflow:hidden, so the card radius clips the bar's corners.
   Default bar = light nested surface. Dark = the two primary cards per page,
   named explicitly below. Darkness loses its meaning if spent freely.

   EVERY RULE IN THIS BLOCK IS SCOPED `:not(.aros-panel)`. It works by pulling
   the bar out through the card's own 22px padding — which only exists on a
   legacy card. A converted .aros-panel has padding:0, so the same -22px pulled
   the bar outside the card, where overflow:hidden clipped it away: nine bars
   rendered as empty stubs with invisible titles. overview.css owns the bar for
   converted panels (.aros-panelbar); this block owns it for pages still on
   legacy markup. One node, one owner — do not add a bar rule here that can
   reach an .aros-panel.
   ═════════════════════════════════════════════════════════════════════════ */

/* Sand, exactly as on the converted pages. The three --aros-sig-bar-* values are
   rebound here rather than a background being set, so the "primary card" block
   further down — which reads --aros-sig-bar-bg — follows automatically instead of
   staying near-black. That block is what made every unconverted page show a dark
   bar while Overview showed sand. */
.chart-container:not(.aros-panel) > .chart-header:first-child {
  --aros-sig-bar-bg: #E6D8C7;
  --aros-sig-bar-fg: #241F1A;
  --aros-sig-bar-fg-muted: rgba(36,31,26,.66);
  --aros-sig-bar-line: rgba(36,31,26,.20);

  margin: -22px -22px 16px;
  padding: 0 18px;
  min-height: var(--aros-sig-bar-h);
  background: var(--aros-sig-bar-bg);
  border-bottom: 1px solid var(--aros-sig-bar-line);
  border-radius: 0;
  gap: 14px;
}

.chart-container:not(.aros-panel) > .chart-header:first-child .chart-title {
  font-family: var(--aros-sig-mono);
  font-size: var(--aros-sig-label-size);
  font-weight: var(--aros-sig-label-weight);
  text-transform: uppercase;
  letter-spacing: var(--aros-sig-track);
  color: var(--color-text);
  gap: 7px;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Rule 6: the title icon was accent-blue decoration on every card. */
.chart-container:not(.aros-panel) > .chart-header:first-child .chart-title svg {
  width: 14px;
  height: 14px;
  color: var(--color-text-subtle);
  opacity: 1;
  flex-shrink: 0;
}

/* Deliberately NOT truncated, unlike the title above. These three declarations
   (overflow/text-overflow/white-space) were written when the desc sat inline in
   the bar's right-hand slot, where one ellipsised line was the lesser evil. The
   Edge block hands it its own full-width row, so all the ellipsis did was eat
   the end of a sentence that had room to wrap. Un-truncating has to happen HERE:
   this selector outranks overview.css's `.chart-header > .chart-desc` 0-5-0 to
   0-2-0, so a counter-rule there is a specificity race over a stale declaration. */
.chart-container:not(.aros-panel) > .chart-header:first-child .chart-desc {
  margin-top: 0;
  min-width: 0;
}

/* Controls / legend on the right of the bar. */
.chart-container:not(.aros-panel) > .chart-header:first-child .chart-group-toggle,
.chart-container:not(.aros-panel) > .chart-header:first-child .oos-pill-row {
  background: transparent;
  padding: 0;
  gap: 4px;
  flex-shrink: 0;
}

/* A pill in the bar has to be shorter than the bar. The base .rep-mode-btn is
   min-height 32px and the bar is 34px, so the default left 1px of air and the
   active pill's surface read as touching the sand edges. */
.chart-container:not(.aros-panel) > .chart-header:first-child .oos-pill {
  min-height: 24px;
  padding: 0 10px;
}

.chart-container:not(.aros-panel) > .chart-header:first-child .group-pill {
  padding: 2px 8px;
  border-color: transparent;
  background: transparent;
}

/* ── The two primary cards per page ─────────────────────────────────────────
   Named by the id of the card's own .chart-body, so this stays correct when a
   grid is reordered. Two per page, no more (rule 5). */
.chart-container:has(> #chart-revenue-trend)      > .chart-header:first-child,
.chart-container:has(> #chart-payment-breakdown)  > .chart-header:first-child,
.chart-container:has(> #chart-kpt-trend)          > .chart-header:first-child,
.chart-container:has(> #chart-kpt-distribution)   > .chart-header:first-child,
.chart-container:has(> #chart-pnl-waterfall)      > .chart-header:first-child,
.chart-container:has(> #chart-pnl-fees)           > .chart-header:first-child,
.chart-container:has(> #chart-cmp-outlet)         > .chart-header:first-child,
.chart-container:has(> #chart-cmp-reason)         > .chart-header:first-child,
.chart-container:has(> #chart-revenue-drivers)    > .chart-header:first-child,
.chart-container:has(> #chart-inventory-velocity) > .chart-header:first-child,
.chart-container:has(> #chart-proc-suppliers)     > .chart-header:first-child,
.chart-container:has(> #chart-proc-categories)    > .chart-header:first-child,
.chart-container:has(> #chart-outlets-trend)      > .chart-header:first-child,
.chart-container:has(> #chart-outlets-ranking)    > .chart-header:first-child,
.chart-container:has(> #oos-impact-list)          > .chart-header:first-child,
.chart-container:has(> #oos-cross-branch)         > .chart-header:first-child {
  background: var(--aros-sig-bar-bg);
  border-bottom-color: transparent;
}

.chart-container:has(> #chart-revenue-trend)      > .chart-header:first-child .chart-title,
.chart-container:has(> #chart-payment-breakdown)  > .chart-header:first-child .chart-title,
.chart-container:has(> #chart-kpt-trend)          > .chart-header:first-child .chart-title,
.chart-container:has(> #chart-kpt-distribution)   > .chart-header:first-child .chart-title,
.chart-container:has(> #chart-pnl-waterfall)      > .chart-header:first-child .chart-title,
.chart-container:has(> #chart-pnl-fees)           > .chart-header:first-child .chart-title,
.chart-container:has(> #chart-cmp-outlet)         > .chart-header:first-child .chart-title,
.chart-container:has(> #chart-cmp-reason)         > .chart-header:first-child .chart-title,
.chart-container:has(> #chart-revenue-drivers)    > .chart-header:first-child .chart-title,
.chart-container:has(> #chart-inventory-velocity) > .chart-header:first-child .chart-title,
.chart-container:has(> #chart-proc-suppliers)     > .chart-header:first-child .chart-title,
.chart-container:has(> #chart-proc-categories)    > .chart-header:first-child .chart-title,
.chart-container:has(> #chart-outlets-trend)      > .chart-header:first-child .chart-title,
.chart-container:has(> #chart-outlets-ranking)    > .chart-header:first-child .chart-title,
.chart-container:has(> #oos-impact-list)          > .chart-header:first-child .chart-title,
.chart-container:has(> #oos-cross-branch)         > .chart-header:first-child .chart-title {
  color: var(--aros-sig-bar-fg);
}

.chart-container:has(> #chart-revenue-trend)      > .chart-header:first-child .chart-desc,
.chart-container:has(> #chart-payment-breakdown)  > .chart-header:first-child .chart-desc,
.chart-container:has(> #chart-kpt-trend)          > .chart-header:first-child .chart-desc,
.chart-container:has(> #chart-kpt-distribution)   > .chart-header:first-child .chart-desc,
.chart-container:has(> #chart-pnl-waterfall)      > .chart-header:first-child .chart-desc,
.chart-container:has(> #chart-pnl-fees)           > .chart-header:first-child .chart-desc,
.chart-container:has(> #chart-cmp-outlet)         > .chart-header:first-child .chart-desc,
.chart-container:has(> #chart-cmp-reason)         > .chart-header:first-child .chart-desc,
.chart-container:has(> #chart-revenue-drivers)    > .chart-header:first-child .chart-desc,
.chart-container:has(> #chart-inventory-velocity) > .chart-header:first-child .chart-desc,
.chart-container:has(> #chart-proc-suppliers)     > .chart-header:first-child .chart-desc,
.chart-container:has(> #chart-proc-categories)    > .chart-header:first-child .chart-desc,
.chart-container:has(> #chart-outlets-trend)      > .chart-header:first-child .chart-desc,
.chart-container:has(> #chart-outlets-ranking)    > .chart-header:first-child .chart-desc,
.chart-container:has(> #oos-impact-list)          > .chart-header:first-child .chart-desc,
.chart-container:has(> #oos-cross-branch)         > .chart-header:first-child .chart-desc,
.chart-container:has(> #chart-revenue-trend)      > .chart-header:first-child .chart-title svg,
.chart-container:has(> #chart-payment-breakdown)  > .chart-header:first-child .chart-title svg,
.chart-container:has(> #chart-pnl-waterfall)      > .chart-header:first-child .chart-title svg,
.chart-container:has(> #chart-pnl-fees)           > .chart-header:first-child .chart-title svg,
.chart-container:has(> #chart-revenue-drivers)    > .chart-header:first-child .chart-title svg,
.chart-container:has(> #chart-inventory-velocity) > .chart-header:first-child .chart-title svg,
.chart-container:has(> #chart-proc-suppliers)     > .chart-header:first-child .chart-title svg,
.chart-container:has(> #chart-proc-categories)    > .chart-header:first-child .chart-title svg,
.chart-container:has(> #chart-outlets-trend)      > .chart-header:first-child .chart-title svg,
.chart-container:has(> #chart-outlets-ranking)    > .chart-header:first-child .chart-title svg {
  color: var(--aros-sig-bar-fg-muted);
}

/* Controls sitting on a dark bar. */
.chart-container:has(> #chart-revenue-trend) > .chart-header:first-child .group-pill,
.chart-container:has(> #chart-kpt-trend)     > .chart-header:first-child .group-pill,
.chart-container:has(> #chart-pnl-trend)     > .chart-header:first-child .group-pill,
.chart-container:has(> #chart-outlets-trend) > .chart-header:first-child .group-pill,
.chart-container:has(> #chart-proc-suppliers) > .chart-header:first-child .group-pill {
  color: var(--aros-sig-bar-fg-muted);
  border-color: transparent;
}

.chart-container:has(> #chart-revenue-trend) > .chart-header:first-child .group-pill.active,
.chart-container:has(> #chart-kpt-trend)     > .chart-header:first-child .group-pill.active,
.chart-container:has(> #chart-pnl-trend)     > .chart-header:first-child .group-pill.active,
.chart-container:has(> #chart-outlets-trend) > .chart-header:first-child .group-pill.active,
.chart-container:has(> #chart-proc-suppliers) > .chart-header:first-child .group-pill.active {
  background: var(--aros-sig-bar-fg);
  border-color: transparent;
  color: var(--aros-sig-bar-bg);
}

.chart-container:has(> #chart-revenue-trend) > .chart-header:first-child .flip-btn,
.chart-container:has(> #chart-outlets-trend) > .chart-header:first-child .flip-btn {
  color: var(--aros-sig-bar-fg-muted);
  border-color: var(--aros-sig-bar-line);
  background: transparent;
}


/* ═══════════════════════════════════════════════════════════════════════════
   RULE 6 — COLOUR IS SEMANTIC ONLY
   One blue for data. Red = breach, amber = warn, green = clear, grey =
   neutral. No coloured icon chips, no per-card colour identity, no palette
   rotation across bars, no gradients.
   ═════════════════════════════════════════════════════════════════════════ */

/* The per-card icon chip. JS sets `style="--accent: #6366F1"` inline, but that
   only writes a custom property — overriding `background` here beats the
   legacy gradient on source order at equal specificity. */
.card-icon-wrap,
.insight-icon,
.modal-icon,
.cmp-in-spark {
  background: var(--color-surface-alt);
  background-image: none;
  color: var(--color-text-muted);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm, 8px);
  box-shadow: none;
}

/* Sidebar and nav icons follow the row's own colour, never an accent. */
.nav-item svg,
.chart-title svg,
.filter-label svg,
.oos-alert svg { color: currentColor; }

/* Bar-chart palette rotation and gradient fills. D3 writes these with
   `.attr('fill', …)` — a presentation attribute, which any CSS declaration
   outranks. Only single-series bars are flattened; charts whose fill encodes
   a state (inventory velocity, wastage severity, waterfall sign) keep theirs. */
#chart-top-branches rect.bar,
#chart-outlets-ranking rect.outlet-bar,
#chart-proc-suppliers rect.bar,
#chart-proc-top-items rect.bar {
  fill: var(--aros-sig-blue);
}

/* Bar ink for Top Items, Peak Hours and Outlet revenue — these rank a single
   measure, so the mark is a measurement rather than a series and takes the chrome
   ink. Outlet revenue also drops a per-outlet colour scale this way: 37 categorical
   hues encoded nothing, since the outlet is already named on the axis. */
#chart-top-items rect.bar,
#chart-peak-hours rect.bar,
#chart-outlet-revenue rect.outlet-bar {
  fill: #1B1F26;
}

/* Espresso for the revenue hero's restaurant-count marks — a warm neutral, so the
   count reads as context behind the revenue line instead of a second series
   competing with it.

   These fills are decided HERE and nowhere else. The bar was in the blue group
   above while revenueTrend.js set `.attr('fill', '#3A3532')`, and per the note on
   that group CSS outranks a presentation attribute — so the attribute said espresso
   while the bar rendered blue. Two owners, and the losing one was the one you could
   see in the chart module. */
#chart-revenue-trend rect.branch-bar,
#chart-revenue-trend rect.branch-swatch { fill: #3A3532; }

/* The text needs !important, and only because the legacy styles.css already uses it:
   `.chart-body text { fill: var(--text-tertiary) !important }` paints every label in
   every chart grey and outranks any normal declaration. (That rule is also why the
   chart modules' `.style('fill', x + ' !important')` never worked — a value string
   with "!important" in it is invalid and gets dropped, so those labels were grey by
   default rather than by choice.) */
#chart-revenue-trend text.branch-label,
#chart-revenue-trend .branch-axis text { fill: #3A3532 !important; }

/* Their value labels ride the same neutral ink. */
#chart-top-items text.bar-value,
#chart-top-branches text.bar-value,
#chart-proc-suppliers text.bar-value,
#chart-proc-top-items text.bar-value { fill: var(--color-text); }


/* ═══════════════════════════════════════════════════════════════════════════
   SEGMENTED CONTROLS — rule 1 type + rule 6 colour
   White with a hairline; the active one is a solid blue fill, white text.
   ═════════════════════════════════════════════════════════════════════════ */

.period-pills,
.cmp-pills,
.rep-mode,
.chart-group-toggle,
.comm-view-toggle,
.wastage-mode-toggle,
.group-toggle,
.grp-toggle {
  background: transparent;
  padding: 0;
  gap: 6px;
  border-radius: 0;
}

.pill,
.group-pill,
.cmp-pill,
.view-pill,
.rep-mode-btn,
.rep-btn,
.platform-pill,
.oos-pill,
.grp-pill,
.grp-btn,
.rep-step-btn {
  font-family: var(--aros-sig-mono);
  font-size: var(--aros-sig-label-size-sm);
  font-weight: var(--aros-sig-label-weight);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 6px 11px;
  border-radius: var(--radius-sm, 8px);
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-text-muted);
  box-shadow: none;
  font-variant-numeric: tabular-nums;
}

.pill:hover,
.group-pill:hover,
.cmp-pill:hover,
.view-pill:hover,
.rep-mode-btn:hover,
.rep-btn:hover,
.platform-pill:hover,
.oos-pill:hover,
.grp-pill:hover {
  color: var(--color-text);
  border-color: var(--color-border-strong);
  background: var(--color-surface);
  box-shadow: none;
}

.pill.active,
.group-pill.active,
.cmp-pill.active,
.view-pill.active,
.view-pill[data-view="reconciliation"].active,
.rep-mode-btn.active,
.platform-pill.active,
.oos-pill.active,
.grp-pill.active,
.grp-btn-primary {
  background: var(--edge-accent, var(--aros-sig-sel));
  border-color: transparent;
  color: var(--edge-accent-fg, var(--aros-sig-sel-fg));
  box-shadow: none;
}

/* The count/value half of a pill. */
.oos-pill-count,
.grp-pill-count {
  font-family: var(--aros-sig-mono);
  font-size: 0.625rem;
  background: var(--color-surface-sunken);
  color: var(--color-text-subtle);
  border-radius: var(--radius-sm, 8px);
  letter-spacing: 0;
}

.oos-pill.active .oos-pill-count,
.grp-pill.active .grp-pill-count {
  background: rgba(255, 255, 255, 0.22);
  color: var(--edge-accent-fg, var(--aros-sig-sel-fg));
}

.grp-pill-new {
  border-style: dashed;
  background: transparent;
  color: var(--color-text-muted);
}

.filter-apply-btn,
.extra-kpi-toggle,
.sync-btn,
.loc-add-btn {
  font-family: var(--aros-sig-mono);
  font-size: var(--aros-sig-label-size-sm);
  font-weight: var(--aros-sig-label-weight);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  border-radius: var(--radius-sm, 8px);
  box-shadow: none;
  background-image: none;
}


/* ═══════════════════════════════════════════════════════════════════════════
   RULE 7 — STATE TRAVELS IN MONO UPPERCASE CHIPS
   HIGH · MEDIUM · ESCALATED · WATCH · ACT NOW · CLEAR · EST
   ═════════════════════════════════════════════════════════════════════════ */

.oos-sev-crit,
.oos-sev-warn,
.oos-sev-ok,
.oos-badge,
.oos-alert-badge,
.cmp-in-pri,
.cmp-in-badge,
.cmp-tag,
.oos-imp-label,
.oos-code,
.slide-scenario-row .cls {
  font-family: var(--aros-sig-mono);
  font-size: var(--aros-sig-label-size-sm);
  font-weight: var(--aros-sig-label-weight);
  text-transform: uppercase;
  letter-spacing: var(--aros-sig-track);
  padding: 2px 7px;
  border-radius: var(--radius-sm, 8px);
  border: 1px solid transparent;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.oos-sev-crit,
.oos-badge-chronic,
.oos-imp-label-out {
  color: var(--color-status-critical-text);
  background: var(--color-status-critical-surface);
}

.oos-sev-warn,
.oos-badge-recurring {
  color: var(--color-status-warning-text);
  background: var(--color-status-warning-surface);
}

.oos-sev-ok,
.oos-imp-label-sell {
  color: var(--color-status-good-text);
  background: var(--color-status-good-surface);
}

/* "new" is neutral information, not a colour-coded state (rule 6). */
.oos-badge-new,
.oos-code-more {
  color: var(--color-text-muted);
  background: var(--color-surface-sunken);
}

.oos-code-out  { color: var(--color-status-critical-text); background: var(--color-status-critical-surface); }
.oos-code-sell { color: var(--color-status-good-text);     background: var(--color-status-good-surface); }

/* Rule 8 — estimates never look like actuals. Bordered, never filled, so it
   reads as "outlined = not measured".
   NO MARKUP YET: nothing emits .aros-est / [data-est] today. The figures that
   need it are listed in the handover. */
.aros-est,
[data-est="1"]::after {
  font-family: var(--aros-sig-mono);
  font-size: var(--aros-sig-label-size-sm);
  font-weight: var(--aros-sig-label-weight);
  text-transform: uppercase;
  letter-spacing: var(--aros-sig-track);
  color: var(--color-text-muted);
  background: transparent;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm, 8px);
  padding: 1px 6px;
  margin-left: 6px;
  vertical-align: middle;
  white-space: nowrap;
}

[data-est="1"]::after { content: 'EST'; display: inline-block; }

/* Empty and error states are status, not prose. */
.chart-error,
.chart-empty,
.oos-empty,
.cmp-empty {
  font-family: var(--aros-sig-mono);
  font-size: var(--aros-sig-label-size);
  text-transform: uppercase;
  letter-spacing: var(--aros-sig-track);
  color: var(--color-text-subtle);
  opacity: 1;
}

.chart-error { color: var(--color-status-critical-text); }


/* ═══════════════════════════════════════════════════════════════════════════
   RULE 10 — MEASUREMENT IS A THIN BAR, NOT A PIE
   4-5px rounded track: dark segment = actual, 2px tick = limit, red past the
   tick = breach. Legend swatches in mono.
   ═════════════════════════════════════════════════════════════════════════ */

.progress-bar-container,
.slide-invest-bar-wrap {
  height: 5px;
  border-radius: 999px;
  background: var(--color-surface-sunken);
  border: none;
  overflow: hidden;
}

.progress-bar,
.slide-invest-bar-fill {
  border-radius: 999px;
  background-image: none;
  background-color: var(--color-text);
}

/* NO MARKUP YET — the actual/limit/breach bar has no counterpart in the DOM.
   Shipping the vocabulary so a follow-up can emit it without a CSS round-trip.
   Expected: .aros-tol > .aros-tol-actual + .aros-tol-limit + .aros-tol-breach */
.aros-tol {
  position: relative;
  height: 5px;
  border-radius: 999px;
  background: var(--color-surface-sunken);
  overflow: hidden;
}

.aros-tol-actual,
.aros-tol-breach {
  position: absolute;
  top: 0;
  bottom: 0;
  border-radius: 999px;
}

.aros-tol-actual { left: 0; background: var(--color-text); }
.aros-tol-breach { background: var(--color-status-critical); }

.aros-tol-limit {
  position: absolute;
  top: -2px;
  bottom: -2px;
  width: 2px;
  background: var(--color-text);
}

.aros-tol-legend {
  display: flex;
  gap: 12px;
  margin-top: 6px;
  font-family: var(--aros-sig-mono);
  font-size: var(--aros-sig-label-size-sm);
  text-transform: uppercase;
  letter-spacing: var(--aros-sig-track);
  color: var(--color-text-subtle);
}

.aros-tol-legend span { display: inline-flex; align-items: center; gap: 5px; }

.aros-tol-legend span::before {
  content: '';
  width: 8px;
  height: 8px;
  border-radius: 2px;
  background: currentColor;
}

.aros-tol-legend .is-actual::before { background: var(--color-text); }
.aros-tol-legend .is-limit::before  { background: var(--color-text); width: 2px; height: 10px; border-radius: 0; }
.aros-tol-legend .is-breach::before { background: var(--color-status-critical); }


/* ═══════════════════════════════════════════════════════════════════════════
   SIDEBAR — rule 1 labels, rule 3 planes, rule 6 colour
   Near-white rail, muted icon + mono label rows, active = light grey pill with
   darker text. Overrides integration.css, which had the planes the other way
   round (alt rail, white active) and a saffron marker.
   ═════════════════════════════════════════════════════════════════════════ */

.sidebar {
  background: var(--color-surface);
  border-right: 1px solid var(--color-border);
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

.nav-item {
  position: relative;
  color: var(--color-text-muted);
  border-radius: var(--radius-sm, 8px);
  font-weight: var(--aros-sig-label-weight);
}

.nav-item:hover {
  background: var(--color-surface-alt);
  color: var(--color-text);
}

.nav-item.active {
  background: var(--color-surface-sunken);
  color: var(--color-text);
  font-weight: 600;
  box-shadow: none;
}

/* The leading marker is ink, not saffron — chrome carries no hue (rule 6). */
.nav-item.active::before { background: var(--color-text); }

.nav-item svg { opacity: 0.85; }
.nav-item.active svg { opacity: 1; }

.nav-label {
  /* 10px: "P&L / COMMISSIONS" is the longest label in the rail and must still
     clear the 210px hover width the legacy sheet sizes it to. */
  font-size: 0.625rem;
  letter-spacing: 0.05em;
}

/* Hairline divider between the analysis pages and the operational ones. */
.nav-item[data-page="oos"] {
  margin-top: 9px;
  border-top: 1px solid var(--color-border);
  padding-top: 14px;
  border-radius: 0 0 var(--radius-sm, 8px) var(--radius-sm, 8px);
}

/* Right-aligned tabular count badges. NO MARKUP YET — no nav item renders one. */
.nav-item .nav-count {
  margin-left: auto;
  font-family: var(--aros-sig-mono);
  font-size: 0.625rem;
  font-variant-numeric: tabular-nums;
  color: var(--color-text-subtle);
  letter-spacing: 0;
}


/* ═══════════════════════════════════════════════════════════════════════════
   RESPONSIVE
   styles.css shrinks .card-value, .card-label and .chart-container padding
   below 768px inside a media block. Because this file loads later, its
   unprefixed rules would beat those at equal specificity — restate them here.
   ═════════════════════════════════════════════════════════════════════════ */

@media (max-width: 768px) {
  .chart-container:not(.aros-panel) > .chart-header:first-child {
    margin: -14px -14px 12px;
    padding: 8px 14px;
    min-height: 0;
    gap: 4px;
  }

  .card-value { font-size: clamp(1rem, 13cqi, 1.35rem); }
  .summary-cards:not(:has(.summary-card:nth-child(5))) .card-value {
    font-size: clamp(1.1rem, 13cqi, 1.6rem);
  }

  .card-label { font-size: 0.6rem; letter-spacing: 0.06em; }
  .card-desc  { font-size: 0.5625rem; letter-spacing: 0.05em; }

  .pill, .group-pill, .cmp-pill, .view-pill, .rep-mode-btn,
  .platform-pill, .oos-pill, .grp-pill {
    min-height: 34px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
}

@media (max-width: 400px) {
  .card-value { font-size: clamp(0.95rem, 13cqi, 1.2rem); }
  .nav-label  { font-size: 0.5625rem; }
}


/* ═══════════════════════════════════════════════════════════════════════════
   PRINT — the Reports tab's PDF path goes through here. A dark bar would
   print as a solid black band; flip it to a hairline rule.
   ═════════════════════════════════════════════════════════════════════════ */

@media print {
  .chart-container:not(.aros-panel) > .chart-header:first-child {
    margin: 0 0 10px;
    padding: 0 0 6px;
    background: transparent;
    border-bottom: 1px solid #ccc;
  }

  .chart-container:not(.aros-panel) > .chart-header:first-child .chart-title,
  .chart-container:not(.aros-panel) > .chart-header:first-child .chart-desc { color: #222; }

  .chart-container:not(.aros-panel) > .chart-header:first-child .chart-title svg { color: #666; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   LEGACY PAGES — parity with the Overview tile (rules 1, 2, 3, 11)

   Fifteen of sixteen pages still use `.summary-card` (icon chip + label + value +
   description in a row) while Overview uses the AROS tile (label + window /
   composed number / caption). These rules bring the legacy tile to the same
   vocabulary WITHOUT touching markup on every page: same plane, same type, same
   anchored zones. Scoped `:not(.aros-kpi)` so the converted tiles keep their own
   composition.
   ═════════════════════════════════════════════════════════════════════════ */

.summary-card:not(.aros-kpi) {
  /* A column, not a row: the value must sit under its label so a row of tiles
     aligns on one baseline (rule 11), which an icon-beside-text layout cannot do. */
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: space-between;
  gap: var(--space-2, 8px);
  min-height: 108px;
  padding: 13px 15px;
  background: var(--color-surface, #fff);
  border: 1px solid var(--color-border, #E4E3DE);
  border-radius: var(--radius-md, 10px);
  box-shadow: none;
}

/* Rule: no icon chips in the UI. The tinted 44px square was the single loudest
   element on these pages and encoded nothing the label does not say. */
.summary-card:not(.aros-kpi) .card-icon-wrap { display: none; }

.summary-card:not(.aros-kpi) .card-content {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}

.summary-card:not(.aros-kpi) .card-label {
  font-family: var(--aros-sig-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--color-text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Rule 2: a figure is a composed object — tabular so a column of tiles lines up
   digit for digit. `proportional-nums` was doing the opposite. */
.summary-card:not(.aros-kpi) .card-value {
  font-size: clamp(21px, 1.8vw, 28px);
  font-weight: 600;
  line-height: 1.05;
  letter-spacing: -.02em;
  color: var(--color-text);
  font-variant-numeric: tabular-nums;
}

/* Rule 9: the provenance line, demoted to mono like every other caption. */
.summary-card:not(.aros-kpi) .card-desc {
  margin-top: 0;
  font-family: var(--aros-sig-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: .04em;
  color: var(--color-text-subtle);
  line-height: 1.3;
}

/* ── Revenue hero: two measures mirrored about the x-axis ───────────────────
   Above the axis: ORDERS (espresso, same treatment the restaurant-count bars
   used to have — it is the primary volume measure now). Below: outlet count as
   a short inverted bar, deliberately quieter because it is context, not signal. */
/* Outlet count is a tinted strip under the axis — the estate behind the bars,
   not a second series competing with them. */
/* Flat deep blue, white bold numerals. No opacity ramp: the number already
   states the count, so tinting encoded it twice and only cost contrast. */
#chart-revenue-trend .outlet-cell {
  fill: #16406F;
  stroke: var(--color-surface, #fff);
  stroke-width: 0.75;
}
#chart-revenue-trend .outlet-num {
  font-family: var(--aros-sig-mono, var(--font-mono));
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .02em;
  font-variant-numeric: tabular-nums;
  fill: #FFFFFF;
}
#chart-revenue-trend .mirror-caption {
  font-family: var(--aros-sig-mono, var(--font-mono));
  font-size: 8.5px;
  letter-spacing: .07em;
  text-transform: uppercase;
  fill: var(--color-text-subtle, #96948D);
}

/* ── Mobile top bar: pills, not slabs ────────────────────────────────────────
   Flattening .nav-group left the items with the vertical rail's sizing: 51px
   blocks in a 60px bar, so the active item read as a grey slab with the rail's
   left-edge marker stranded beside it. In a horizontal bar the item IS the
   target — real pill, centred, with air around it.

   THIS MUST LIVE IN signature.css. layout.css sets .nav-item.active first, but
   signature.css:1107 restyles it at the same specificity and loads later, so an
   override written in layout.css silently loses. Same trap as the rm-rate/rm-skew
   classes: written, shipped, and invisible. */
@media (max-width: 768px) {
  .sidebar { height: 56px; align-items: center; padding-block: 0; }
  .sidebar-nav { align-items: center; gap: var(--space-1); }

  .nav-item {
    min-height: 40px;
    height: 40px;
    padding: 0 var(--space-4);
    border-radius: var(--radius-pill, 999px);
    align-items: center;
  }

  /* The rail's active marker is a left edge; on a row that is a stray tick beside
     the label. The filled pill IS the state — no separate marker. */
  .nav-item.active::before,
  .nav-item[aria-current="page"]::before { display: none; }

  .nav-item.active,
  .nav-item[aria-current="page"] {
    background: var(--aros-sig-sel);
    color: var(--aros-sig-sel-fg);
    box-shadow: none;
  }
  .nav-item.active svg,
  .nav-item[aria-current="page"] svg { color: currentColor; opacity: 1; }

  /* Group boundary: a short centred hairline, not a full-height edge that reads
     as a broken box against the pill's own radius. */
  .nav-group + .nav-group > .nav-item:first-of-type {
    margin-left: var(--space-3);
    border-left: 0;
    padding-left: var(--space-4);
    position: relative;
  }
  .nav-group + .nav-group > .nav-item:first-of-type::after {
    content: "";
    position: absolute;
    left: calc(var(--space-3) * -0.5);
    top: 50%;
    transform: translateY(-50%);
    width: 1px;
    height: 18px;
    background: var(--color-border);
  }
}

/* ── Segmented controls get a track ──────────────────────────────────────────
   The pills were naked: three buttons floating with nothing to say they belong
   to one another, so an inactive pill read as unstyled text rather than as the
   other half of a switch. Wrapping them in a recessed track makes the SET the
   object and the active pill the position within it — which is what a segmented
   control is.

   Applied to the three real segmented groups (period quick-picks, the chart
   day/week/month toggle, and the report mode switch). NOT applied to the outlet
   chips: those carry different values each, so they are independent chips in a
   scroller, not positions in one control.

   Must live in signature.css — components.css sets .period-pills/.chart-group-
   toggle first and loads earlier, so a track written there loses. */
.period-pills,
.chart-group-toggle,
.rep-mode {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 4px;
  border-radius: var(--radius-pill, 999px);
  background: var(--color-surface-sunken, rgba(0, 0, 0, .05));
  border: var(--border-width-hairline) solid var(--color-border);
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, .04);
}

/* Inside a track the buttons lose their own borders — the track is the edge. */
.period-pills .pill,
.chart-group-toggle .group-pill,
.rep-mode .rep-mode-btn {
  border-color: transparent;
  background: transparent;
  box-shadow: none;
}
.period-pills .pill:hover:not(.active),
.chart-group-toggle .group-pill:hover:not(.active),
.rep-mode .rep-mode-btn:hover:not(.active) {
  background: var(--cx-tint-hover, rgba(0, 0, 0, .05));
  border-color: transparent;
}

/* The active pill is the only lit thing in the track, so it needs no border. */
.period-pills .pill.active,
.chart-group-toggle .group-pill.active,
.rep-mode .rep-mode-btn.active {
  border-color: transparent;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .18);
}

/* The quick-picks are seven wide and still have to wrap on a laptop; a wrapped
   track needs its rows to breathe or the two lines touch. */
.filter-bar .period-pills { row-gap: 4px; }

/* On the Overview the track sits on a white panel, so sink it a shade further
   than the page ground to keep the recessed read. */
#page-overview .chart-group-toggle {
  background: var(--color-surface-alt, #F2F1ED);
}

/* ── Filter bar, rebuilt ─────────────────────────────────────────────────────
   It was five labelled columns — BRANCH / FROM / TO / VIEW / QUICK — each
   spending a row on a mono uppercase caption above its control, then Apply
   stranded on a line of its own. 141px of chrome to answer "which branches,
   what dates".

   Three changes:
   1. FROM and TO become ONE range control. They were always one range; two boxes
      with two captions said it twice. Both inputs survive, so every reader of
      #filter-start / #filter-end is untouched.
   2. Captions go visually-hidden. A calendar icon in the range, a pin in the
      branch box and the pill track itself already say what each control is; the
      labels stay in the DOM for screen readers.
   3. One row, controls at a consistent 44px.
   ──────────────────────────────────────────────────────────────────────────── */
.filter-bar .filter-label.sr-only,
.filter-bar #filter-group-range .filter-label {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.filter-bar { align-items: center; row-gap: 10px; padding-block: 12px; }
.filter-bar .filter-group { flex-direction: row; align-items: center; gap: 8px; }

/* the merged range */
.range-shell {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 44px;
  padding: 0 14px;
  border-radius: var(--radius-pill, 999px);
  border: var(--border-width-hairline) solid var(--color-border);
  background: var(--color-surface);
}
.range-shell:focus-within { border-color: var(--color-action-primary-bg); }
.range-ico { color: var(--color-text-subtle); flex: 0 0 auto; }
.range-in {
  border: 0 !important;
  background: transparent !important;
  padding: 0 !important;
  height: auto !important;
  min-height: 0 !important;
  width: 9.5ch;
  text-align: center;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
}
.range-in:focus { outline: 0; box-shadow: none; }
.range-dash { color: var(--color-text-subtle); flex: 0 0 auto; }

/* branch box matches the range's shape so the row reads as one set of controls */
.filter-bar .custom-select > .filter-input {
  height: 44px;
  border-radius: var(--radius-pill, 999px);
  padding-inline: 16px;
}

/* the view switch loses its caption too — the words either side already name it */
.filter-bar #dim-switch .dim-row {
  height: 44px;
  padding: 0 14px;
  border-radius: var(--radius-pill, 999px);
  border: var(--border-width-hairline) solid var(--color-border);
  background: var(--color-surface);
  display: inline-flex;
  align-items: center;
  gap: 10px;
}
.filter-bar #dim-switch > .filter-label { display: none; }
.filter-bar #filter-group-branch > .filter-label,
.filter-bar .filter-group > .filter-label:has(+ .period-pills) { display: none; }

/* Apply sits at the end of the row and keeps the control height. */
.filter-bar .filter-apply-btn { height: 44px; border-radius: var(--radius-pill, 999px); }

/* ── The filter bar below 1600px ───────────────────────────────────────────
   The five groups total more than the bar's inner width once the viewport
   drops under ~1600: measured at 1440 the branch (140) + range (352) + view
   (199) + quick pills (399) already exceed the 1168px available, so the pills
   wrapped to a second row and Apply was pushed onto a third — 158px of chrome
   above every page, and Apply stranded where nobody looks for it.
   The pills scroll instead of wrapping, exactly like the outlet chips on the
   Overview panel. Everything stays on ONE row at every width. */
@media (max-width: 1727px) {
  /* NOT flex-wrap:nowrap. That was tried and it is worse than the wrapping it
     cured: nowrap lets every item shrink past its own content, so the branch box
     printed over the start date and the last two quick pills scrolled silently
     out of view. Only the pills group is allowed to give — everything else keeps
     its content width and the bar wraps if it genuinely cannot fit. */
  /* flex-basis, NOT auto. Line-breaking happens at the BASE size, before any
     shrinking — so with `auto` the pills group demanded its full ~875-1019px
     content width, broke to a second row, and the overflow-x:auto below never
     got the chance to do its job. A small basis lets it take what is left of
     the row and scroll the remainder. */
  .filter-bar .filter-group:has(.period-pills) { flex: 1 1 auto; min-width: 0; }
  .filter-bar #filter-group-branch,
  .filter-bar #dim-switch { flex: 0 0 auto; }
  .filter-bar .period-pills {
    flex-wrap: nowrap;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
    min-width: 0;
  }
  .filter-bar .period-pills::-webkit-scrollbar { height: 0; }
  .filter-bar .filter-apply-btn { flex: 0 0 auto; }

  /* The row is ~180px over budget at 1280. Rather than scroll the quick pills
     out of reach — LAST MO / MONTH / WEEK are the most-used controls on the bar
     — take the space back from the two widest items, which are carrying it in
     padding and redundant words. The dates keep all four digits of the year. */
  .filter-bar .range-in { width: 8.2ch; }
  .filter-bar .range-shell { padding: 0 10px; gap: 4px; }
  .filter-bar #filter-group-branch > .filter-label,
  .filter-bar #dim-switch > .filter-label { display: none; }
  .filter-bar .dim-row { gap: 5px; }
  .filter-bar .period-pills { gap: 4px; }
  .filter-bar .period-pills .pill { padding-inline: 10px; }
  .filter-bar #filter-group-range { flex: 0 0 auto; }
}
