:root {
  color-scheme: light;
  --page-plane: #f9f9f7;
  --surface-1: #fcfcfb;
  --text-primary: #0b0b0b;
  --text-secondary: #52514e;
  --text-muted: #898781;
  --gridline: #e1e0d9;
  --baseline: #c3c2b7;
  --success: #006300;
  --border: rgba(11, 11, 11, 0.10);
  --series-1: #2a78d6;
  --series-2: #eb6834;
  --series-3: #1baf7a;
  --status-good: #0ca30c;
  --status-warning: #fab219;
  /* Darker than --status-warning specifically for text/icon foreground use
     (the "!"/"?" info-button glyphs) — #fab219 itself is amber-on-near-white
     in light mode, ~1.8:1 contrast against --page-plane, unreadable on some
     screens. Only needed in light mode; --status-warning's own value already
     has strong contrast against dark mode's near-black backgrounds, so the
     dark overrides below just restore it. */
  --status-warning-icon: #b35900;
  --status-serious: #ec835a;
  --status-critical: #d03b3b;
  --sans: system-ui, -apple-system, "Segoe UI", sans-serif;
}

/* Theme modes: "auto" (default, no data-theme attribute)
   follows the OS/browser prefers-color-scheme setting live, with no JS
   involved — the media query below just gets excluded whenever the user has
   explicitly picked a mode via assets/theme.js, which sets data-theme on
   <html> to "light" or "dark". The explicit :root[data-theme="dark"] block
   below (outside any media query) covers picking Dark while the OS itself is
   in light mode, which the media query alone can't do. Keep both blocks'
   custom-property values identical. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --page-plane: #0d0d0d;
    --surface-1: #1a1a19;
    --text-primary: #ffffff;
    --text-secondary: #c3c2b7;
    --text-muted: #898781;
    --gridline: #2c2c2a;
    --baseline: #383835;
    --success: #0ca30c;
    --border: rgba(255, 255, 255, 0.10);
    --series-1: #3987e5;
    --series-2: #d95926;
    --series-3: #199e70;
    --status-warning-icon: #fab219;
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --page-plane: #0d0d0d;
  --surface-1: #1a1a19;
  --text-primary: #ffffff;
  --text-secondary: #c3c2b7;
  --text-muted: #898781;
  --gridline: #2c2c2a;
  --baseline: #383835;
  --success: #0ca30c;
  --border: rgba(255, 255, 255, 0.10);
  --series-1: #3987e5;
  --series-2: #d95926;
  --series-3: #199e70;
  --status-warning-icon: #fab219;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: var(--sans);
  background: var(--page-plane);
  color: var(--text-primary);
}

a { color: var(--series-1); }

.app-shell {
  display: flex;
  min-height: 100vh;
}

.app-nav {
  width: 220px;
  flex: 0 0 220px;
  background: var(--surface-1);
  border-right: 1px solid var(--border);
  padding: 20px 12px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  transition: width 0.15s ease, flex-basis 0.15s ease;
}

.app-nav .brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: 600;
  font-size: 15px;
  padding: 0 8px 16px;
  color: var(--text-primary);
}

.app-nav .nav-icon {
  width: 20px;
  height: 20px;
  flex: 0 0 20px;
  border-radius: 4px;
  overflow: hidden;
}

.app-nav .brand .nav-icon { border-radius: 5px; }

.app-nav .nav-icon-light { display: block; }
.app-nav .nav-icon-dark { display: none; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .app-nav .nav-icon-light { display: none; }
  :root:not([data-theme="light"]) .app-nav .nav-icon-dark { display: block; }
}

:root[data-theme="dark"] .app-nav .nav-icon-light { display: none; }
:root[data-theme="dark"] .app-nav .nav-icon-dark { display: block; }

.app-nav a {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 8px;
  border-radius: 6px;
  color: var(--text-secondary);
  text-decoration: none;
  font-size: 14px;
}

.app-nav a:hover { background: var(--gridline); }

.app-nav a.active {
  background: var(--series-1);
  color: #fff;
  font-weight: 600;
}

.app-nav .collapse-toggle {
  align-self: flex-end;
  width: 24px;
  height: 24px;
  margin: 0 4px 12px auto;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--page-plane);
  color: var(--text-secondary);
  font-size: 12px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

.app-nav .collapse-toggle:hover { background: var(--gridline); }

/* Light/Dark/Auto theme toggle — three-way segmented
   control, styled like the other segmented toggles (.granularity-toggle
   etc.) but living in the nav so it's reachable from every page. */
.theme-toggle {
  display: flex;
  gap: 0;
  border: 1px solid var(--border);
  border-radius: 6px;
  overflow: hidden;
  margin: 4px 8px 16px;
}

.theme-toggle .theme-option {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-secondary);
  background: var(--page-plane);
  border: none;
  border-right: 1px solid var(--border);
  padding: 6px 4px;
  cursor: pointer;
}

.theme-toggle .theme-option svg { flex: 0 0 auto; display: block; }

.theme-toggle .theme-option:last-child { border-right: none; }
.theme-toggle .theme-option:hover { background: var(--gridline); }

.theme-toggle .theme-option.active {
  background: var(--series-1);
  color: #fff;
}

.app-nav .logout {
  margin-top: auto;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}

.app-nav .logout a {
  color: var(--text-primary);
  font-weight: 600;
}

/* Icon-only collapsed mode — desktop sidebar only. Small
   screens have their own separate hamburger/overlay mechanic (below) where
   the nav is either fully hidden or fully shown with labels, never
   icon-only, so this whole thing is scoped off small screens entirely
   (previously applied there too, back when small screens got a horizontal
   icon-pill bar instead of an overlay — follow-up). */
@media (min-width: 781px) {
  .app-nav.collapsed .brand span.label,
  .app-nav.collapsed a.nav-link span.label,
  .app-nav.collapsed .theme-toggle .theme-option span.label { display: none; }
  .app-nav.collapsed .brand,
  .app-nav.collapsed a.nav-link { justify-content: center; padding-left: 8px; padding-right: 8px; }
  .app-nav.collapsed .collapse-toggle { align-self: center; margin-right: 0; }
  .app-nav.collapsed .theme-toggle { flex-direction: column; margin-left: 0; margin-right: 0; }
  .app-nav.collapsed .theme-toggle .theme-option {
    border-right: none;
    border-bottom: 1px solid var(--border);
    padding: 6px 0;
  }
  .app-nav.collapsed .theme-toggle .theme-option:last-child { border-bottom: none; }
  .app-nav.collapsed { width: 60px; flex-basis: 60px; padding-left: 8px; padding-right: 8px; }
}

.app-main {
  flex: 1;
  min-width: 0;
  padding: 24px 32px 64px;
}

.app-main h1 {
  font-size: 22px;
  margin: 0 0 4px;
}

.page-subtitle {
  color: var(--text-secondary);
  font-size: 13px;
  margin: 0 0 24px;
}

/* Sticky on every screen size, always — a direct child of the (tall)
   .app-main, not nested inside a shorter wrapper shared with the controls
   bar below, so it can stay pinned for the full length of the page rather
   than scrolling away once that shorter combined block has passed
   (follow-up: nav.js has the full reasoning). */
.app-header-top {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: flex-start;
  gap: 12px;
  background: var(--page-plane);
}

.app-header-titles { min-width: 0; }

/* Hidden on the desktop sidebar layout — this is the small-screen nav
   trigger only (follow-up); see the max-width:780px block
   for its shown/active styling. */
.mobile-menu-toggle { display: none; }

.controls-mount { margin-bottom: 20px; }

/* Desktop: the controls bar (Report period, granularity, comparison text)
   stacks directly below the header strip above and stays pinned there too
   — `top` matches that strip's own measured height (nav.js sets the CSS
   var), so together they read as one continuous sticky block even though
   they're independently-sticky siblings, not one shared wrapper (see the
   comment on .app-header-top for why). On small screens this bar is NOT
   sticky — it's tall enough (Report period, wrapped granularity toggle,
   bounds note) that pinning all of it would eat a large share of a small
   viewport, so only the header strip above stays put and this scrolls
   away normally (follow-up: "hamburger icon and page name should be
   sticky" — narrower than the whole block). */
@media (min-width: 781px) {
  .controls-mount {
    position: sticky;
    top: var(--header-top-height, 64px);
    z-index: 19;
    background: var(--page-plane);
    padding-bottom: 4px;
    border-bottom: 1px solid var(--border);
  }
}

/* The sidebar-style sticky nav only makes sense in the desktop vertical
   layout — on small screens .app-nav is either hidden or an overlay (below),
   never a beside-the-content column. */
@media (min-width: 781px) {
  .app-nav {
    position: sticky;
    top: 0;
    align-self: flex-start;
    height: 100vh;
    overflow-y: auto;
  }
}

.controls-top-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 8px 16px;
}

.controls-period-field {
  display: flex;
  align-items: center;
  gap: 8px;
}

.controls-period-label {
  font-size: 13px;
  color: var(--text-secondary);
}

/* The current selection doubles as the drawer's open/close trigger — no
   separate "Edit range" button (UX-review follow-up). */
.controls-period-button {
  display: flex;
  align-items: center;
  gap: 6px;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-primary);
  background: var(--page-plane);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 6px 12px;
  cursor: pointer;
}

.controls-period-button:hover { background: var(--gridline); }

.controls-chevron {
  color: var(--text-muted);
  font-size: 11px;
}

.controls-comparison-text {
  font-size: 13px;
  color: var(--text-muted);
}

.controls-drawer { margin-top: 8px; }

.controls-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 16px;
}

.controls-bar + .controls-bar { margin-top: 10px; }

.controls-info-wrap { position: relative; display: flex; }

.controls-info-button {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  border: 1px solid var(--status-warning-icon);
  background: var(--page-plane);
  color: var(--status-warning-icon);
  font: inherit;
  font-size: 13px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

.controls-info-button:hover { background: var(--gridline); }

.controls-info-popup {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  width: 340px;
  max-width: min(340px, 80vw);
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 12px 14px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
  z-index: 30;
}

.controls-info-popup p {
  font-size: 12px;
  color: var(--text-secondary);
  margin: 0;
}

.controls-info-popup p + p { margin-top: 10px; }

.controls-group {
  display: flex;
  align-items: center;
  gap: 10px;
}

.controls-field {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--text-secondary);
}

.date-input {
  font: inherit;
  font-size: 13px;
  color: var(--text-primary);
  background: var(--page-plane);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 4px 8px;
}

.granularity-toggle,
.preset-group {
  gap: 0;
  border: 1px solid var(--border);
  border-radius: 6px;
  overflow: hidden;
}

.granularity-toggle button,
.preset-group button {
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-secondary);
  background: var(--page-plane);
  border: none;
  border-right: 1px solid var(--border);
  padding: 6px 12px;
  cursor: pointer;
}

.granularity-toggle button:last-child,
.preset-group button:last-child { border-right: none; }

.granularity-toggle button:hover,
.preset-group button:hover { background: var(--gridline); }

.granularity-toggle button.active {
  background: var(--series-1);
  color: #fff;
}

/* Full "Daily"/"Weekly"/"Monthly" by default; swapped for a bare
   "D"/"W"/"M" on small screens (max-width:780px block below) to keep the
   now-relocated top bar compact there (follow-up). */
.granularity-toggle .label-short { display: none; }

.controls-bounds-note {
  font-size: 11px;
  color: var(--text-muted);
  margin-left: auto;
}

.kpi-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 12px;
  margin-bottom: 28px;
}

.stat-tile {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px 16px;
}

.stat-tile .label {
  font-size: 12px;
  color: var(--text-secondary);
  margin-bottom: 6px;
  display: flex;
  align-items: center;
  gap: 6px;
}

.stat-tile .value {
  font-size: 22px;
  font-weight: 600;
  line-height: 1.2;
}

.stat-tile .delta {
  font-size: 12px;
  margin-top: 4px;
}

.stat-tile .delta.good { color: var(--success); }
.stat-tile .delta.bad { color: var(--status-critical); }
.stat-tile .delta.flat { color: var(--text-muted); }
.stat-tile .delta.no-data { color: var(--status-warning); }

.stat-tile .sparkline { margin-top: 8px; display: block; }

.panel-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(420px, 1fr));
  gap: 20px;
  margin-bottom: 24px;
}

.panel {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 16px 20px 20px;
  /* Grid items default to min-width: auto, i.e. their content's min-content
     size -- a wide unwrapped table (inventory turnover, cohort retention,
     campaigns) was blowing out the whole single-column grid track on small
     screens, dragging every OTHER panel/chart on the page wider than the
     viewport along with it. This lets a panel shrink to
     the grid track's actual width; .table-scroll below then gives an
     over-wide table its own horizontal scroll instead. */
  min-width: 0;
}

.panel h2 {
  font-size: 15px;
  margin: 0 0 2px;
  display: flex;
  align-items: center;
  gap: 6px;
}

.panel .panel-note {
  font-size: 12px;
  color: var(--text-muted);
  margin: 0 0 12px;
}

.pending-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--gridline);
  color: var(--text-secondary);
  border-radius: 999px;
  padding: 3px 10px;
  font-size: 12px;
  font-weight: 600;
}

.pending-badge::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--status-warning);
}

.pending-panel {
  border-style: dashed;
  color: var(--text-secondary);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  justify-content: center;
  min-height: 120px;
}

/* Lets a table wider than its panel (e.g. campaigns, which is intentionally
   left as many columns) scroll internally instead of
   forcing the panel -- and via grid blowout, every other chart on the page
   -- wider than the viewport. */
.table-scroll {
  overflow-x: auto;
}

/* renderTimelineBars: every campaign bar always renders
   (no top-N truncation), so once there are more than fit comfortably, the
   strip scrolls internally rather than growing the panel unboundedly or
   dropping rows. */
.timeline-scroll {
  overflow-y: auto;
}

table.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}

table.data-table th, table.data-table td {
  text-align: left;
  padding: 6px 10px;
  border-bottom: 1px solid var(--gridline);
  font-variant-numeric: tabular-nums;
}

table.data-table th {
  color: var(--text-secondary);
  font-weight: 600;
  font-size: 12px;
}

table.data-table td.num, table.data-table th.num { text-align: right; }

.bar-row.clickable { cursor: pointer; }
.bar-row.clickable:hover rect { opacity: 0.82; }
.bar-row.clickable.selected rect { opacity: 1; }

.drilldown-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--surface-1);
  border: 1px solid var(--series-1);
  border-radius: 8px;
  padding: 8px 14px;
  margin-bottom: 16px;
  font-size: 13px;
  color: var(--text-primary);
}

.drilldown-clear {
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  color: var(--series-1);
  background: none;
  border: none;
  cursor: pointer;
  padding: 0;
}

.drilldown-clear:hover { text-decoration: underline; }

.legend {
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
  font-size: 12px;
  color: var(--text-secondary);
  margin-bottom: 8px;
}

.legend .swatch {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.legend .dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  display: inline-block;
}

.chart-toolbar {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 4px;
}

.chart-toolbar .legend { margin-bottom: 0; }

.chart-mode-toggle {
  display: flex;
  gap: 0;
  border: 1px solid var(--border);
  border-radius: 6px;
  overflow: hidden;
  margin-left: auto;
  flex-shrink: 0;
}

.chart-mode-toggle button {
  font: inherit;
  font-size: 11px;
  font-weight: 600;
  color: var(--text-secondary);
  background: var(--page-plane);
  border: none;
  border-right: 1px solid var(--border);
  padding: 4px 10px;
  cursor: pointer;
}

.chart-mode-toggle button:last-child { border-right: none; }

.chart-mode-toggle button:hover { background: var(--gridline); }

.chart-mode-toggle button.active {
  background: var(--series-1);
  color: #fff;
}

.chart-compare-hint {
  font-size: 11px;
  color: var(--text-muted);
  align-self: center;
}

.chart-tooltip {
  position: fixed;
  pointer-events: none;
  background: var(--text-primary);
  color: var(--page-plane);
  font-size: 12px;
  padding: 6px 10px;
  border-radius: 6px;
  line-height: 1.5;
  z-index: 1000;
  opacity: 0;
  transition: opacity 0.08s ease;
  white-space: nowrap;
}

/* Widget info tooltips — a small (i) icon next to a panel/tile title
   explaining what it shows, why it matters, and where its data comes from
   (docs/widget-descriptions.md). Reveals on hover for devices that have one
   (gated behind hover:hover/pointer:fine so it doesn't get "stuck" open
   after a tap on touch, which has no hover-leave event); a click/tap always
   toggles the .open class too — that's what touch relies on, dismissed by
   tapping elsewhere via the same outside-click pattern as
   .controls-info-popup above. */
.info-icon-wrap { position: relative; display: inline-flex; }

.info-icon-btn {
  width: 15px;
  height: 15px;
  border-radius: 50%;
  border: 1px solid var(--text-muted);
  background: none;
  color: var(--text-muted);
  font: inherit;
  font-size: 10px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  flex-shrink: 0;
}

.info-icon-btn:hover, .info-icon-btn:focus-visible { color: var(--text-primary); border-color: var(--text-primary); }

.info-icon-popup {
  display: none;
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  width: 260px;
  max-width: min(260px, 80vw);
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 12px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
  z-index: 30;
  font-size: 12px;
  font-weight: 400;
  color: var(--text-secondary);
  line-height: 1.5;
  text-align: left;
  white-space: normal;
}

/* Flipped on by charts.js's positionPopup() when the default left-aligned
   placement above would overflow the right edge of the viewport (right-most
   column tiles/charts). */
.info-icon-popup.align-right { left: auto; right: 0; }

.info-icon-wrap.open .info-icon-popup { display: block; }

@media (hover: hover) and (pointer: fine) {
  .info-icon-wrap:hover .info-icon-popup { display: block; }
}

.state-banner {
  font-size: 13px;
  color: var(--text-muted);
  padding: 8px 0;
}

.state-banner.error { color: var(--status-critical); }

.freshness-banner {
  background: color-mix(in srgb, var(--status-warning) 14%, var(--surface-1));
  border: 1px solid var(--status-warning);
  border-radius: 10px;
  padding: 12px 16px;
  margin-bottom: 16px;
  font-size: 13px;
  color: var(--text-primary);
}

.freshness-banner strong { display: block; }

.freshness-banner ul {
  margin: 4px 0 0;
  padding-left: 18px;
}

.freshness-banner li + li { margin-top: 2px; }

@media (max-width: 780px) {
  .app-shell { flex-direction: column; }
  .app-main { padding: 16px; }

  /* .app-header-top is already sticky at every screen size (base rule
     above) -- only the extra breathing room + boundary line are
     small-screen-specific here, since .controls-mount isn't sticky at this
     breakpoint (see its min-width:781px rule) and needs a clear visual
     handoff to where it scrolls away normally (follow-up feedback:
     "hamburger icon and page name should be sticky"). */
  .app-header-top {
    padding: 8px 0;
    margin-bottom: 8px;
    border-bottom: 1px solid var(--border);
  }

  /* Charts/panels are laid out for desktop widths (420px-minimum columns) —
     a single, full-width column is the only way they fit without pushing
     the page wider than the viewport (follow-up: "all charts are off
     screen on right side, wider than visible"). Chart SVGs measure their
     own container's clientWidth (assets/charts.js), so they resize down to
     fit correctly once the panel around them isn't artificially wide. */
  .panel-grid { grid-template-columns: 1fr; }

  .mobile-menu-toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    flex: 0 0 36px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--surface-1);
    color: var(--text-primary);
    font-size: 18px;
    line-height: 1;
    cursor: pointer;
  }

  .mobile-menu-toggle:hover { background: var(--gridline); }

  /* Folds into an on-demand full-screen overlay behind the hamburger button
     above, instead of the permanent horizontal icon-pill bar this used to
     be (it competed with page content for vertical space) — follow-up.
     Sits at a lower z-index than .app-header-top
     (20) so that strip — and its hamburger toggle, to close the menu
     again — stays visible and clickable above the overlay rather than the
     overlay covering it. */
  .app-nav {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 15;
    width: auto;
    flex: none;
    overflow-y: auto;
    border-right: none;
    box-shadow: 0 12px 28px rgba(0, 0, 0, 0.3);
    /* Content starts below the sticky header, not underneath it -- the
       header's opaque background only safely masks the overlay's own
       background in that region, not real content (nav.js sets this to the
       header's actual measured height). */
    padding-top: var(--mobile-header-offset, 64px);
  }

  .app-nav.mobile-open { display: flex; }

  /* Icon-only desktop mode has no small-screen equivalent — the overlay is
     always either hidden or fully shown with labels. */
  .app-nav .collapse-toggle { display: none; }

  /* Redundant with the drawer's own comparison-period fields once it's
     opened, and the least essential thing to see at a glance — dropped
     here to keep the small-screen top bar compact (follow-up: "redesign
     of top bar for responsive small screen view").
     Granularity stays on the same row as the period selector right after
     it (D/W/M's short labels, set in controls.js, are what make that fit);
     bounds-note claims its own full row via flex-basis rather than fight
     them for space on the first one. */
  .controls-top-bar { padding: 10px 12px; gap: 8px; }
  .controls-comparison-text { display: none; }
  .controls-bounds-note { margin-left: 0; flex-basis: 100%; }
  .granularity-toggle .label-full { display: none; }
  .granularity-toggle .label-short { display: inline; }

  /* The drawer overflowed the viewport horizontally on small screens: its
     rows (.controls-bar) already wrap as a whole via flex-wrap, but a
     SINGLE group within a row -- the comparison-period control in
     particular ("Comparison period:" label + From field + To field, none
     of which wrap internally) -- was wider on its own than the drawer's
     available width, so it just overflowed rather than wrapping (follow-up:
     "the drawer with period selection is also out of page on mobile").
     Letting each group wrap its own children fixes that without changing
     desktop layout, where there's room for it to stay on one line. */
  .controls-group { flex-wrap: wrap; }
  .controls-bar { padding: 10px 12px; gap: 10px; }
}
