/* ==========================================================================
   Cartis — app stylesheet
   "Nairobi Corporate Modern": clean, data-dense, no shadows/gradients.
   Tokens and components follow docs/design_system.md. Never hardcode colours
   outside the token list here.
   ========================================================================== */

:root {
  /* ── Brand palette — teal-forward "Location Hub" rebrand ──────────────────
     Source of truth: the Location Hub prototype. The Material-style names below
     (--surface*, --primary-container, …) are kept as compatibility ALIASES
     mapped onto this palette, so every existing component re-skins with no
     markup change. They'll be retired as templates move to the brand tokens
     during the Location Hub phase. */
  --deep:  #0B2F33;   /* darkest teal — solid buttons, headings, hovers */
  --teal:  #0F9F8F;   /* primary — links, active states, accents, data bars */
  --mint:  #5EEAD4;   /* bright accent — text on dark, selection */
  --bg:    #F5FAF9;   /* page background */
  --ink:   #183236;   /* body text */
  --gold:  #E9A23B;   /* secondary accent — active nav, highlights */
  --coral: #E05A67;   /* negative / chart-down / decorative red */
  --line:  #DEEAE7;   /* borders */
  --line2: #EDF4F2;   /* lighter dividers */
  --thead: #F1F7F5;   /* table header fill */
  --muted: #5E736F;   /* secondary text */
  --faint: #93A7A3;   /* tertiary text / icons */
  --tint:  #EAF7F4;   /* subtle teal fill */

  /* ── Compatibility aliases (old name → brand token) ─────────────────────── */
  /* Surfaces */
  --surface:           var(--bg);
  --surface-lowest:    #ffffff;
  --surface-low:       #eef6f3;      /* subtle row/hover tint */
  --surface-container: var(--tint);
  --surface-high:      #dceeea;      /* focus ring, bar track, tint badge */
  --surface-highest:   #cde8e1;

  /* Text */
  --on-surface:        var(--ink);
  --on-variant:        var(--muted);
  --outline:           var(--muted);   /* used for small label text — keep legible */
  --outline-variant:   var(--line);

  /* Primary — teal (solid buttons use --deep for AA contrast; see .btn-primary) */
  --primary-container:    var(--teal);
  --on-primary:           #ffffff;
  --on-primary-container: var(--deep);

  /* Secondary — gold */
  --secondary-container:    var(--gold);
  --on-secondary-container: #5a3d00;

  /* Tertiary — deep teal / mint */
  --tertiary-container:    var(--deep);
  --on-tertiary-container: var(--mint);

  /* Semantic — error kept readable on light; brand coral lives at --coral */
  --error:              #c62f3b;
  --error-container:    #fbe0e2;
  --on-error-container: #7a1620;

  /* Navigation (sidebar) — deep-teal shell with pale-mint text */
  --nav-bg:     var(--deep);
  --nav-fg:     #eafbf7;                 /* rgb(234,251,247) — sidebar text */
  --nav-muted:  rgba(234,251,247,0.55);  /* dimmed section labels */
  --nav-accent: rgba(94,234,212,0.15);   /* mint 15% — hover / selected */
  --nav-border: rgba(94,234,212,0.12);   /* subtle right divider */

  /* Radius */
  --r:      4px;
  --r-md:   6px;

  /* Warning triangle for error states, carried in CSS so no template has to
     hand-write an icon. Painted via `mask` with currentColor, so it always
     matches the text colour of whatever alert it sits in. */
  --icon-alert: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0Z'/%3E%3Cline x1='12' y1='9' x2='12' y2='13'/%3E%3Cline x1='12' y1='17' x2='12.01' y2='17'/%3E%3C/svg%3E");
  --r-lg:   8px;
  --r-xl:   12px;
  --r-full: 9999px;
  --r-card: 14px;   /* cards, KPI tiles, slot cards (Location Hub redesign) */
  --r-btn:  10px;   /* buttons, nav items */

  /* Elevation — a single whisper-soft shadow; the design is otherwise flat. */
  --shadow-card: 0 1px 2px rgba(11, 47, 51, 0.04);

  /* Type — Instrument Sans (body) + Space Grotesk (display/headings/numbers) */
  --font:         "Instrument Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --font-display: "Space Grotesk", "Instrument Sans", system-ui, sans-serif;
  --fd:           var(--font-display);   /* prototype alias */
}

* { box-sizing: border-box; }

html, body { height: 100%; }

body {
  margin: 0;
  font-family: var(--font);
  font-size: 16px;
  color: var(--on-surface);
  background: var(--surface);
  -webkit-font-smoothing: antialiased;
}

a { color: var(--teal); text-decoration: none; }
a:hover { color: var(--deep); }

h1, h2, h3 { margin: 0; letter-spacing: -0.02em; }

/* Display type — Space Grotesk on headings, titles and KPI numbers. */
h1, h2, h3,
.page-title, .card-title, .stat .value,
.brand, .auth-brand, .auth-card h1 {
  font-family: var(--font-display);
}

.num { font-variant-numeric: tabular-nums; }

/* --- Utilities ------------------------------------------------------------ */

/* Visible to screen readers, not on screen. For labelling a column whose header
   would otherwise be an empty cell, which reads as nothing at all. */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --- Buttons ------------------------------------------------------------- */

.btn {
  font-family: var(--font-display);
  font-size: 13.5px;
  font-weight: 600;
  padding: 8px 14px;
  border-radius: var(--r-btn);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  border: 1px solid transparent;
  line-height: 1.2;
  text-decoration: none;
}
.btn:hover { text-decoration: none; }
/* Primary is the brand teal (matches the Location Hub CTA); deep on hover.
   Buttons are often <a>, so each hover re-asserts its text colour to beat the
   global `a:hover { color: var(--deep) }` rule (which otherwise hid the label). */
.btn-primary { background: var(--teal); color: #fff; }
.btn-primary:hover { background: var(--deep); color: #fff; }
.btn-ghost {
  background: var(--surface-lowest);
  border-color: var(--line);
  color: var(--deep);
}
.btn-ghost:hover { background: var(--tint); color: var(--deep); }
/* Icons inside ghost/secondary buttons pick up the teal accent. */
.btn-ghost svg { color: var(--teal); }
.btn-gold { background: var(--secondary-container); color: var(--on-secondary-container); }
.btn-gold:hover { background: #d8912b; color: var(--on-secondary-container); }
.btn-block { width: 100%; }
/* A smaller button, for row-level actions inside a table. (.btn-lg is the
   landing page's own; this one is general.) */
.btn-sm { font-size: 13px; padding: 6px 12px; }

/* --- Forms --------------------------------------------------------------- */

.field { margin-bottom: 14px; }
.field label {
  display: block;
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--on-variant);
  margin-bottom: 6px;
}
.field input,
.field select {
  width: 100%;
  font-family: var(--font);
  font-size: 16px;
  color: var(--on-surface);
  background: var(--surface-lowest);
  border: 1px solid var(--outline-variant);
  border-radius: var(--r);
  padding: 9px 11px;
}
.field input:focus,
.field select:focus {
  outline: none;
  border-color: var(--primary-container);
  box-shadow: 0 0 0 3px var(--surface-high);
}
.field .helptext { display: block; font-size: 13px; color: var(--on-variant); margin-top: 5px; }
/* Error surfaces. There used to be three unrelated treatments — bare red text
   for a field error, a flat tinted box for a form-level one, a bordered row for
   a message — so a rejected upload read as a stray red sentence rather than as
   something that had stopped the action. They now share one alert look, and the
   ::before glyph means the markup does not change to gain an icon. */
.field .errorlist,
.form-errors,
.form-nonfield {
  list-style: none;
  margin: 8px 0 0;
  padding: 10px 12px;
  font-size: 13px;
  /* 1.25rem, set on every callout in this family (.insight and .messages li
     too) so a warning and a rejection are spaced identically wherever they
     appear. A length rather than a ratio, so the three different font sizes
     in the family still land on one rhythm. Desktop figure — the mobile pass
     can override it in the max-width blocks at the foot of this file. */
  line-height: 1.25rem;
  background: #fcebec;
  border: 1px solid #f6d3d6;
  border-radius: var(--r-md);
  color: var(--on-error-container);
}
.form-nonfield { font-size: 14px; margin: 0 0 14px; }

.field .errorlist li,
.form-errors li,
.form-nonfield,
.messages li.error {
  display: flex;
  gap: 9px;
  align-items: flex-start;
}
.field .errorlist li + li,
.form-errors li + li,
.form-nonfield div + div { margin-top: 6px; }
/* One icon for the box, so its messages need a single wrapper to sit beside
   it rather than becoming flex siblings of the glyph. */
.form-nonfield > div { flex: 1; }

.field .errorlist li::before,
.form-errors li::before,
.form-nonfield::before,
.messages li.error::before {
  content: "";
  flex: none;
  width: 16px;
  /* One line tall, not 16px with a nudge. The mask is `center / contain`, so
     the glyph still draws at 16px and centres itself in the taller box —
     which keeps it level with the first line of text at whatever line-height
     the family carries, instead of needing a margin retuned each time. */
  height: 1.25rem;
  background: currentColor;
  -webkit-mask: var(--icon-alert) center / contain no-repeat;
  mask: var(--icon-alert) center / contain no-repeat;
}

/* An input whose value was rejected says so itself, not only underneath. */
.field input.is-error,
.field select.is-error { border-color: var(--error); }

/* --- Cards --------------------------------------------------------------- */

.card {
  background: var(--surface-lowest);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}
.card-header {
  padding: 15px 18px;
  border-bottom: 1px solid var(--line2);
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.card-title { font-family: var(--font-display); font-size: 15px; font-weight: 600;
  letter-spacing: -0.01em; color: var(--deep); }
.card-body { padding: 18px; }

/* --- Badges -------------------------------------------------------------- */

.badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-family: var(--font-display);
  font-size: 11.5px;
  font-weight: 500;
  padding: 2px 9px;
  border-radius: var(--r-full);
  border: 1px solid transparent;
}
/* Soft brand pills — teal for good, warm-gold for caution, coral for problem. */
.b-green { background: var(--tint); color: var(--teal);  border-color: #c9eae3; }
.b-gold  { background: #fbf3e4;     color: #9a6712;      border-color: #f0deb6; }
.b-red   { background: #fcebec;     color: var(--coral); border-color: #f6d3d6; }
.b-blue  { background: var(--tint); color: var(--deep);  border-color: #c9eae3; }
.b-grey  { background: var(--surface-container); color: var(--muted); border-color: var(--line); }

/* --- App shell: sidebar + main (no top bar; brand + account live in the
       sidebar, matching the Location Hub prototype) ----------------------- */

.app { min-height: 100vh; display: flex; align-items: stretch; }

.sidebar {
  width: 240px; flex: 0 0 240px;
  background: var(--nav-bg);
  border-right: 1px solid var(--nav-border);
  padding: 16px 12px;
  display: flex; flex-direction: column; gap: 2px;
  position: sticky; top: 0; height: 100vh; overflow-y: auto;
}

/* Brand (sidebar top) — gradient logo tile + two-tone wordmark. */
.brand { display: flex; align-items: center; gap: 10px; padding: 6px 8px 14px; text-decoration: none; }
.brand:hover { text-decoration: none; }
.brand .mark {
  width: 34px; height: 34px; flex: none; border-radius: 9px;
  background: linear-gradient(145deg, var(--teal), var(--mint));
  color: var(--deep); display: grid; place-items: center;
  font-family: var(--font-display); font-weight: 700; font-size: 14px;
}
.brand .brand-name { font-family: var(--font-display); font-weight: 600; font-size: 15px;
  color: #fff; letter-spacing: 0.005em; }
.brand .brand-name span { color: var(--mint); }

/* Logo image — renders once static/img/cartis-logo.svg exists (replaces the
   text mark). Sidebar sits on the dark shell; if the artwork is dark and doesn't
   read there, supply a light/mono variant and we'll wire it separately. */
.brand-logo { height: 70px; width: auto; max-width: 100%; display: block; }
.auth-brand .brand-logo { height: 100px; width: auto; max-width: 100%; }

.nav-section { font-family: var(--font-display); font-size: 10px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.14em; color: var(--nav-muted);
  padding: 10px 12px 5px; }
.nav-item {
  display: flex; align-items: center; gap: 11px;
  padding: 9px 12px; border-radius: var(--r-btn);
  font-family: var(--font-display); font-size: 14px; font-weight: 500; color: var(--nav-fg);
  background: transparent; border: none; margin-bottom: 2px; text-decoration: none;
}
.nav-item:hover:not(.active) { background: var(--nav-accent); color: var(--nav-fg); text-decoration: none; }
/* Selected shares the mint tint with hover; brighter mint text + weight marks it. */
.nav-item.active { background: var(--nav-accent); color: var(--mint); font-weight: 600; }
.nav-item svg { width: 18px; height: 18px; flex: 0 0 18px; }

/* Account card + sign out (sidebar bottom). */
.nav-foot { margin-top: auto; padding-top: 12px; display: flex; flex-direction: column; gap: 8px; }
.nav-account {
  display: flex; align-items: center; gap: 10px; text-decoration: none;
  background: rgba(255, 255, 255, 0.05); border: 1px solid var(--nav-border);
  border-radius: 12px; padding: 10px 11px;
}
.nav-account:hover { text-decoration: none; background: rgba(94, 234, 212, 0.10); }
.nav-account .na-avatar {
  width: 32px; height: 32px; flex: none; border-radius: 8px;
  background: rgba(94, 234, 212, 0.16); color: var(--mint);
  display: grid; place-items: center;
  font-family: var(--font-display); font-weight: 600; font-size: 14px;
}
.nav-account .na-info { min-width: 0; display: flex; flex-direction: column; }
.nav-account .na-name { font-family: var(--font-display); font-size: 13px; color: #fff;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.nav-account .na-plan { font-size: 11px; color: var(--mint); }
.nav-signout { text-align: left; padding: 6px 12px; font-size: 13px; color: #7fa8a2;
  background: transparent; border: none; cursor: pointer; }
.nav-signout:hover { color: var(--nav-fg); }

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

/* Mobile menu toggle — fixed top-left (there's no top bar to hold it). */
.nav-toggle { display: none; position: fixed; top: 12px; left: 12px; z-index: 55;
  width: 40px; height: 40px; align-items: center; justify-content: center;
  background: var(--deep); color: var(--mint); border: none;
  border-radius: var(--r-btn); cursor: pointer; box-shadow: var(--shadow-card); }
.nav-toggle svg { width: 22px; height: 22px; }
.nav-backdrop { display: none; }

/* --- Mobile: sidebar becomes an off-canvas drawer ------------------------ */
@media (max-width: 860px) {
  .nav-toggle { display: inline-flex; }
  .main { padding: 62px 16px 18px; }   /* clear the fixed toggle */

  .sidebar {
    position: fixed; top: 0; bottom: 0; left: 0; z-index: 60; height: 100vh;
    width: 260px; flex-basis: 260px;
    transform: translateX(-100%); transition: transform .22s ease;
  }
  .sidebar.open { transform: translateX(0); }

  .nav-backdrop.show {
    display: block; position: fixed; inset: 0;
    background: rgba(11, 47, 51, 0.45); z-index: 50;
  }

  /* Let wide tables scroll horizontally instead of breaking the layout. */
  .data-table { display: block; overflow-x: auto; white-space: nowrap; }

  .stat-row, .slot-row { grid-template-columns: repeat(2, 1fr); }
}

.page-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 20px; }
.page-title { font-size: 22px; font-weight: 700; }
.page-sub { font-size: 14px; color: var(--on-variant); margin-top: 3px; }

/* --- Empty state --------------------------------------------------------- */

.empty {
  text-align: center;
  padding: 56px 24px;
  color: var(--on-variant);
}
.empty h3 { font-size: 16px; color: var(--on-surface); margin-bottom: 8px; }
.empty p { font-size: 16px; margin: 0 auto 18px; max-width: 380px; }

/* --- Auth layout (centered card) ----------------------------------------- */

/* The backdrop is static/img/auth-map.svg — a drawn road network, a planned
   run, catchment rings and order-density dots. See the comment in that file for
   why it is drawn and not photographed (short version: img-src is 'self' data:,
   so there is no stock CDN to pull from, and 6KB of SVG stays crisp on a
   display no JPEG of a sane size would cover).
   --deep is painted underneath, so a failed image request degrades to the brand
   ground rather than to white — on which the dark logo inside the card would
   still read, but the page would look broken. */
.auth-wrap {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 24px;
  background: var(--deep) url("../img/auth-map.18775df053c9.svg") center / cover no-repeat;
}
/* The card has to win against a busy ground, which the flat 1px border it wore
   on a near-white page no longer does. A real shadow lifts it; the near-white
   fill (not pure #fff) keeps it from glaring against the deep teal. */
.auth-card {
  width: 100%;
  max-width: 400px;
  background: var(--surface-lowest);
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: var(--r-xl);
  padding: 32px;
  box-shadow: 0 24px 60px rgba(4, 23, 26, 0.42), 0 2px 8px rgba(4, 23, 26, 0.22);
}
.auth-brand { display: flex; align-items: center; justify-content: center; gap: 9px; font-weight: 700; margin-bottom: 22px; }
.auth-brand .mark {
  width: 30px; height: 30px; background: var(--deep); color: var(--mint);
  border-radius: var(--r-md); display: grid; place-items: center;
}
.auth-card h1 { font-size: 20px; font-weight: 700; margin-bottom: 4px; }
.auth-card .sub { font-size: 14px; color: var(--on-variant); margin-bottom: 22px; }
.auth-foot { font-size: 14px; color: var(--on-variant); margin-top: 18px; text-align: center; }

/* --- Messages ------------------------------------------------------------ */

.messages { list-style: none; margin: 0 0 18px; padding: 0; }
.messages li {
  padding: 10px 14px; border-radius: var(--r-md); font-size: 14px; margin-bottom: 8px;
  background: var(--surface-low); border: 1px solid var(--outline-variant);
  line-height: 1.25rem;   /* see the error surfaces above */
}
.messages li.error { background: var(--error-container); border-color: var(--error); color: var(--on-error-container); }
.messages li.success { background: #d6f5e8; border-color: #4eddbb; color: #1a6641; }

/* --- Data tables --------------------------------------------------------- */

.data-table { width: 100%; border-collapse: collapse; font-size: 14px; }
.data-table thead th {
  font-family: var(--font-display); font-size: 12px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--faint); padding: 9px 16px;
  border-bottom: 1px solid var(--line); text-align: left;
}
.data-table thead th.right { text-align: right; }
.data-table tbody tr { border-bottom: 1px solid var(--line2); }
.data-table tbody tr:last-child { border-bottom: none; }
.data-table tbody tr:hover { background: var(--tint); }
.data-table td { padding: 11px 16px; }

/* Money and counts never wrap. "KSh" breaking onto the line above its own
   figure is the single most common way one of these tables looks broken, and
   a split number is unreadable rather than merely ugly. */
.data-table td.num, .data-table th.right { white-space: nowrap; }

/* The Area column holds the longest strings on the page, and with every column
   auto-width it took all the slack — leaving the money columns too narrow to
   hold "KSh 1,234,567" on one line. Capping it makes the AREA name wrap (it
   has somewhere to go: a second line reads fine) instead of the figures.
   Percentage, not pixels: this table sits in .hub-grid and is read on phones. */
.area-table th:first-child, .area-table td:first-child { width: 30%; }

/* Outside-Nairobi towns: expandable rows with a sub-locality drill-down */
.ot-head, .ot-town > summary {
  display: grid; grid-template-columns: 1fr 90px 150px; align-items: center;
  gap: 8px; padding: 11px 16px; font-size: 14px;
}
.ot-head {
  border-bottom: 1px solid var(--line); color: var(--faint);
  font-family: var(--font-display); font-size: 10px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.08em;
}
.ot-head .right, .ot-town .right { text-align: right; }
.ot-town { border-bottom: 1px solid var(--line2); }
.ot-town:last-child { border-bottom: none; }
.ot-town > summary { cursor: pointer; list-style: none; }
.ot-town[data-flat] > summary { cursor: default; }
.ot-town > summary::-webkit-details-marker { display: none; }
.ot-town > summary:hover { background: var(--tint); }
.ot-name { display: flex; align-items: center; gap: 7px; }
.ot-caret { color: var(--muted); transition: transform .15s; flex-shrink: 0; }
.ot-town[open] > summary .ot-caret { transform: rotate(90deg); }
.ot-subs { padding: 2px 16px 10px 40px; }
.ot-sub {
  display: flex; justify-content: space-between; padding: 5px 0; font-size: 13px;
  color: var(--muted); border-top: 1px solid var(--line2);
}

/* Clickable rows (e.g. area list → detail view) */
.data-table tr.row-link { cursor: pointer; }
.row-arrow { display: inline-flex; align-items: center; color: var(--outline); }
.row-arrow:hover { color: var(--primary-container); }
.data-table tr.row-link:hover .row-arrow { color: var(--primary-container); }
.data-table td.right { text-align: right; font-variant-numeric: tabular-nums; }
.rank { display:inline-grid; place-items:center; width:22px; height:22px; border-radius:var(--r-full);
  background:var(--surface-container); color:var(--on-variant); font-size:11px; font-weight:700; }
.rank.top { background: var(--secondary-container); color: var(--on-secondary-container); }
.muted { color: var(--on-variant); font-size: 13px; }

/* --- KPI stat cards ------------------------------------------------------ */

.stat-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-bottom: 18px; }
.stat {
  background: var(--surface-lowest); border: 1px solid var(--line);
  border-radius: var(--r-card); box-shadow: var(--shadow-card); padding: 16px 18px;
}
.stat .label { font-family: var(--font-display); font-size: 10.5px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.09em; color: var(--muted); }
.stat .value { font-family: var(--font-display); font-size: 30px; font-weight: 600;
  color: var(--deep); letter-spacing: -0.02em; margin-top: 7px; font-variant-numeric: tabular-nums; }
.stat .sub { font-size: 12px; color: var(--muted); margin-top: 8px; }

/* --- Context strip ------------------------------------------------------- */

.context-strip {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px 16px;
  background: var(--surface-lowest); border: 1px solid var(--line);
  border-radius: var(--r-xl); padding: 11px 15px; margin-bottom: 18px; font-size: 13px;
}
.context-strip .cs-item { display: flex; align-items: baseline; gap: 6px; color: var(--muted); }
.context-strip .cs-item b { color: var(--ink); font-weight: 500; }
.context-strip .pills { display: flex; gap: 7px; margin-left: auto; }

/* --- Tabs ---------------------------------------------------------------- */

/* Scrolls rather than wraps or squashes. The labels went from one word each
   ("Area", "Timing") to two ("Areas & Zones", "Delivery Margin"), which is ~730px
   of strip — more than the content column has at 900px wide. Wrapping to a second
   row puts a lone tab under the others and breaks the single-line-of-tabs read;
   shrinking the text makes the navigation the smallest type on the page. So it
   scrolls, with the scrollbar hidden and the last tab clipped as the affordance.
   -webkit-overflow-scrolling keeps it momentum-scrolled on iOS. */
.tabs {
  display: flex; gap: 26px; border-bottom: 1px solid var(--line); margin-bottom: 20px;
  overflow-x: auto; -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.tabs::-webkit-scrollbar { display: none; }
.s-tab { flex: none; white-space: nowrap; }
@media (max-width: 900px) { .tabs { gap: 18px; } }
.s-tab {
  font-family: var(--font-display); font-size: 14.5px; font-weight: 500; color: var(--muted);
  background: transparent; border: none; border-bottom: 2.5px solid transparent;
  padding: 0 1px 12px; margin-bottom: -1px; cursor: pointer;
}
.s-tab:hover { color: var(--deep); }
.s-tab.active { color: var(--deep); font-weight: 600; border-bottom-color: var(--teal); }
.tab-panel { display: none; }
.tab-panel.active { display: block; }

/* --- Share bars ---------------------------------------------------------- */

.bar-wrap { display: flex; align-items: center; gap: 9px; }
.bar-track { flex: 1; height: 8px; background: var(--line2); border-radius: var(--r-full);
  overflow: hidden; min-width: 46px; }
.bar-fill { height: 100%; border-radius: var(--r-full);
  background: linear-gradient(90deg, var(--teal), var(--mint)); }

/* --- Hub layout + section headers ---------------------------------------- */

.hub-grid { display: grid; grid-template-columns: 1fr 350px; gap: 18px; align-items: start; }
/* Section headings inside a tab ("Rest of Kenya", "Pickup orders"). At 11px
   in muted grey these read as labels on the card below them rather than as
   divisions of the tab, so a reader scrolling the Areas tab had nothing to tell
   them they had left one breakdown and entered another. 14px/800 in ink makes
   them structure. Letter-spacing eases off as the size goes up — 0.07em is
   tuned for 11px caps and sprawls at 14. */
.section-head { font-size: 14px; font-weight: 800; text-transform: uppercase;
  letter-spacing: 0.045em; color: var(--deep); margin: 24px 0 10px; }
.mini-bar-row { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; font-size: 14px; }
.mini-bar-row .mb-name { width: 92px; flex: 0 0 92px; }
.mini-bar-row .mb-val { margin-left: auto; font-variant-numeric: tabular-nums; font-weight: 600; }

@media (max-width: 900px) { .hub-grid { grid-template-columns: 1fr; } .stat-row { grid-template-columns: repeat(2, 1fr); } }

/* --- Month-over-month comparison overlay --------------------------------- */

/* Compare-to-previous toggle bar (above the KPI row). */
.cmp-bar { display: flex; align-items: center; gap: 10px; margin: 0 0 16px; }
.cmp-title { font-size: 12.5px; color: var(--muted); }
.cmp-sub { font-size: 11.5px; color: var(--faint); }
.cmp-toggle { width: 38px; height: 22px; border-radius: var(--r-full); border: none; padding: 0;
  background: #cbd9d6; position: relative; cursor: pointer; transition: background 0.18s; flex: none; }
.cmp-toggle.on { background: var(--teal); }
.cmp-toggle .cmp-knob { position: absolute; top: 3px; left: 3px; width: 16px; height: 16px;
  border-radius: 50%; background: #fff; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); transition: left 0.18s; }
.cmp-toggle.on .cmp-knob { left: 19px; }

/* Comparison bits render only while #hub carries .cmp-on (toggled in JS).
   Scoped to #hub, because the toggle IS #hub: unscoped, these rules also hid
   the Trends page, which has no #hub wrapper and no toggle to turn one on —
   so its four "vs previous period" deltas and its "% of customers" line were
   computed on every request and never drawn. .swing-note rides with the delta
   it qualifies: a correction to a number that isn't on screen is noise. */
#hub .stat-delta, #hub .movers-card, #hub .cmp-arrow, #hub .cmp-inline,
#hub .swing-note { display: none; }
#hub.cmp-on .stat-delta { display: flex; }
#hub.cmp-on .movers-card, #hub.cmp-on .swing-note { display: block; }
#hub.cmp-on .cmp-arrow, #hub.cmp-on .cmp-inline { display: inline; }

/* KPI delta pill. */
.stat-delta { align-items: center; gap: 8px; margin-top: 9px; }
.delta-pill { font-family: var(--font-display); font-size: 12.5px; font-weight: 600;
  padding: 2px 8px; border-radius: 7px; }
.delta-pill.up { background: var(--tint); color: var(--teal); }
.delta-pill.down { background: #fcebec; color: var(--coral); }
.delta-pill.flat { background: var(--surface-container); color: var(--muted); }
.delta-note { font-size: 12px; color: var(--faint); }

/* Area-table direction arrow + "· vs prev" header hint. */
.cmp-arrow { font-size: 11px; margin-left: 2px; }
.cmp-arrow.up { color: var(--teal); }
.cmp-arrow.down { color: var(--coral); }
.cmp-arrow.flat { color: var(--faint); }
.cmp-inline { color: var(--faint); font-weight: 500; }

/* Top movers card. */
.movers-head { font-family: var(--font-display); font-size: 10px; font-weight: 600;
  letter-spacing: 0.08em; text-transform: uppercase; margin: 4px 0 9px; }
.movers-head.up { color: var(--teal); }
.movers-head.down { color: var(--coral); margin-top: 14px; }
.mover-row { display: grid; grid-template-columns: 82px 1fr 46px; gap: 8px;
  align-items: center; margin-bottom: 8px; font-size: 13px; }
.mover-row .mv-name { color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mover-row .bar-track { height: 7px; }
.mv-fill { height: 100%; border-radius: var(--r-full); }
.mv-fill.up { background: var(--teal); }
.mv-fill.down { background: var(--coral); }
.mv-delta { text-align: right; font-family: var(--font-display); font-size: 12.5px;
  font-weight: 600; font-variant-numeric: tabular-nums; }
.mv-delta.up { color: var(--teal); }
.mv-delta.down { color: var(--coral); }

/* --- Timing tab: slot cards + heat cells --------------------------------- */

.slot-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-bottom: 18px; }
.slot-card {
  background: var(--surface-lowest); border: 1px solid var(--line);
  border-radius: var(--r-card); box-shadow: var(--shadow-card); padding: 16px;
}
.slot-card .slot-head { display: flex; align-items: center; gap: 8px; font-family: var(--font-display);
  font-weight: 600; font-size: 15px; color: var(--deep); }
.slot-card .slot-range { font-size: 13px; color: var(--muted); margin-top: 2px; }
.slot-card .slot-count { font-family: var(--font-display); font-size: 24px; font-weight: 600;
  color: var(--deep); margin-top: 10px; font-variant-numeric: tabular-nums; }
/* The share reads as a small solid chip rather than a caption. As muted grey
   under a 24px count it was the least visible thing on the card, and it is the
   figure that makes the count mean anything — 180 orders says nothing until you
   know it is 42% of the day. --deep rather than --teal: this sits INSIDE a card
   at 11.5px, where white on teal is 3.3:1 and under the 4.5:1 small text wants;
   on deep it is ~14:1. inline-block so the chip hugs its text — the element is
   a div, and left as a block it would stripe the whole card width. */
.slot-card .slot-pct {
  display: inline-block; margin-top: 7px;
  padding: 3px 10px; border-radius: var(--r-full);
  background: var(--deep); color: #fff;
  font-family: var(--font-display); font-size: 11.5px; font-weight: 600;
  letter-spacing: 0.01em; line-height: 1.35;
}
.slot-card .slot-top { margin-top: 10px; border-top: 1px solid var(--line2); padding-top: 10px; }
.slot-card .slot-top .st { display: flex; justify-content: space-between; font-size: 13px; margin-bottom: 3px; }
.slot-card .slot-top .st span:last-child { color: var(--on-variant); font-variant-numeric: tabular-nums; }

.heat-cell {
  display: inline-block; min-width: 44px; text-align: center;
  padding: 5px 8px; border-radius: var(--r); font-size: 13px; font-variant-numeric: tabular-nums;
}
/* Teal intensity ramp — light tint to solid teal (was an off-brand blue ramp). */
.hc-0 { background: var(--line2); color: var(--faint); }
.hc-1 { background: var(--tint);  color: var(--teal); }
.hc-2 { background: #a6e0d6;      color: var(--deep); }
.hc-3 { background: var(--teal);  color: #ffffff; }

.insight {
  display: flex; gap: 10px; padding: 12px 14px; border-radius: var(--r-xl);
  font-size: 14px; align-items: flex-start; margin-bottom: 18px;
  line-height: 1.25rem;   /* see the error surfaces above */
}
.insight.teal { background: var(--tint); border: 1px solid #c9eae3; color: var(--ink); }
.insight.teal svg { color: var(--teal); }
.insight svg { flex: none; margin-top: 1px; }  /* keep the icon from shrinking */
/* 14px, not the 13px this used to carry: gold was the only variant that shrank
   itself below the .insight base, which made the app's warnings the smallest
   text on the page. */
.insight.gold { background: #fbf3e4; border: 1px solid #f0deb6; color: var(--ink); }
.insight.gold svg { color: var(--gold); }
/* For a notice the reader must not skim past. Used on the overlap warning,
   where skimming means adding two dashboards together and double-counting. */
.insight.strong { font-weight: 600; }
/* Something the user did was rejected. Same shape as .teal/.gold so a failure
   reads as part of the same family of callouts, not a different language. */
.insight.error { background: #fcebec; border: 1px solid #f6d3d6; color: var(--ink); }
.insight.error svg { color: var(--error); }
/* Banner variant: title/copy left, action button right. */
.insight.between { justify-content: space-between; align-items: center; gap: 12px; }

/* --- Payment tab: stacked split bar + segment colours -------------------- */

.seg-mpesa { background: #1a6641; }   /* M-Pesa green / resolved */
.seg-card  { background: var(--primary-container); }  /* Deep blue */
.seg-cod   { background: var(--secondary-container); } /* Gold / review */
.seg-pos   { background: #7b5ea7; }                    /* Violet / in-store POS */
.seg-other { background: var(--outline); }             /* Grey / outside */
.seg-red   { background: var(--error); }               /* Red / unresolved */
/* Customers: new vs repeat — two-tone teal (matches the prototype). */
.seg-new    { background: var(--deep); }               /* new customers */
.seg-repeat { background: var(--primary-container); }  /* repeat customers (teal) */

/* Payment-method % numbers, tinted by method (readable text variants). */
.pt-mpesa { color: #1a6641; }        /* green */
.pt-card  { color: var(--teal); }    /* teal */
.pt-cod   { color: #9a6712; }        /* gold */
.pt-pos   { color: #6b4f95; }        /* violet */
.pt-other { color: var(--muted); }   /* grey */
.pay-zero { color: var(--faint); }   /* a 0% cell — dimmed to cut noise */

/* Segmented toggle (Orders / Revenue on the overall payment mix). */
.seg-toggle { display: flex; gap: 2px; background: var(--line2); border-radius: 9px; padding: 3px; }
.seg-btn { font-family: var(--font-display); font-size: 12px; font-weight: 500;
  color: var(--muted); background: transparent; border: none; border-radius: 7px;
  padding: 4px 10px; cursor: pointer; }
.seg-btn.active { background: #fff; color: var(--deep); box-shadow: var(--shadow-card); }

.pay-bar { display: flex; height: 8px; border-radius: var(--r-full); overflow: hidden;
  background: var(--line2); min-width: 90px; }
.pay-bar > span { height: 100%; }

.legend-dot { display: inline-block; width: 9px; height: 9px; border-radius: var(--r-full);
  margin-right: 6px; vertical-align: middle; }

.mix-row { margin-bottom: 12px; }
.mix-row .mix-head { display: flex; justify-content: space-between; font-size: 14px; margin-bottom: 5px; }
.mix-row .mix-head .num { font-variant-numeric: tabular-nums; color: var(--on-variant); }
.mix-track { height: 8px; border-radius: var(--r-full); background: var(--line2); overflow: hidden; }
.mix-track > span { display: block; height: 100%; }

/* Order-mix legend rendered as a compact, aligned table. */
.mix-table th, .mix-table td { padding: 8px 12px; }
.mix-table td .legend-dot { margin-right: 8px; }
.mix-table tbody tr:hover { background: transparent; }  /* legend, not a row list */
.mix-table .mix-total td { border-top: 1px solid var(--line); font-weight: 600; color: var(--deep); }

/* --- Quality tab: resolution cards + inline review queue ----------------- */
.q-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 14px; margin-bottom: 16px; }
.q-card {
  background: var(--surface-lowest); border: 1px solid var(--line);
  border-radius: var(--r-card); box-shadow: var(--shadow-card); padding: 16px 18px;
}
.q-card .qc-label { display: flex; align-items: center; gap: 8px; font-family: var(--font-display);
  font-size: 10.5px; font-weight: 600; letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--muted); margin-bottom: 10px; }
.q-card .qc-dot { width: 9px; height: 9px; border-radius: 3px; background: var(--qc); flex: none; }
.q-card .qc-figs { display: flex; align-items: baseline; gap: 8px; }
.q-card .qc-count { font-family: var(--font-display); font-size: 27px; font-weight: 600;
  color: var(--deep); font-variant-numeric: tabular-nums; }
.q-card .qc-pct { font-family: var(--font-display); font-size: 13px; font-weight: 600; color: var(--qc); }
.q-card .qc-bar { height: 7px; background: var(--line2); border-radius: var(--r-full);
  overflow: hidden; margin: 10px 0 9px; }
.q-card .qc-bar > span { display: block; height: 100%; border-radius: var(--r-full); background: var(--qc); }
.q-card .qc-note { font-size: 12px; color: var(--muted); line-height: 1.35; }
/* Bucket colour, exposed to the card's children via a custom property. */
.q-card.k-resolved   { --qc: var(--teal); }
.q-card.k-review     { --qc: var(--gold); }
.q-card.k-unresolved { --qc: var(--coral); }
.q-card.k-outside    { --qc: var(--muted); }
.q-card.k-pickup     { --qc: var(--faint); }

/* Assign-area select — inline review queue and the standalone review page. */
.rq-select { flex: 1; font-family: var(--font-display); font-size: 12.5px; padding: 6px 9px;
  border: 1px solid var(--line); border-radius: var(--r-btn); background: var(--surface-lowest);
  color: var(--deep); min-width: 88px; }
.rq-select:focus { outline: none; border-color: var(--teal); box-shadow: 0 0 0 3px var(--tint); }
.rq-raw { font-family: ui-monospace, Menlo, monospace; font-size: 12px; color: var(--ink); }

/* --- Account / settings pages -------------------------------------------- */

/* Stacked cards, comfortable reading width. */
.settings-cols { display: flex; flex-direction: column; gap: 16px; max-width: 620px; }

/* Read-only key/value rows inside a card. */
.info-row { display: flex; align-items: center; justify-content: space-between;
  gap: 16px; padding: 10px 0; border-bottom: 1px solid var(--outline-variant); }
.info-row:first-child { padding-top: 0; }
.info-row:last-child { border-bottom: none; padding-bottom: 0; }
.info-label { font-size: 14px; color: var(--on-variant); }
.info-value { display: inline-flex; align-items: center; gap: 8px; font-weight: 500; text-align: right; }

/* Security action rows: description on the left, button on the right. */
.action-row { display: flex; align-items: center; justify-content: space-between;
  gap: 16px; padding: 12px 0; border-bottom: 1px solid var(--outline-variant); }
.action-row:first-child { padding-top: 0; }
.action-row:last-child { border-bottom: none; padding-bottom: 0; }
.action-title { font-weight: 600; font-size: 16px; }

/* Form cards (change password, add email, logout confirm). */
.form-card { max-width: 480px; }
.settings-cols .form-card { max-width: none; }
.form-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 18px; }

/* Email list rows. */
.email-row { display: flex; align-items: center; gap: 10px; padding: 10px 0;
  border-bottom: 1px solid var(--outline-variant); cursor: pointer; }
.email-row:last-of-type { border-bottom: none; }
.email-row input[type="radio"] { margin: 0; flex: 0 0 auto; }
.email-addr { font-weight: 500; margin-right: auto; }

/* --- Public landing page (templates/landing.html) -------------------------
   The only page an anonymous visitor sees before the auth card. It is wider and
   airier than the app shell, but draws entirely on the tokens above — no new
   colours, no gradients, no shadows beyond --shadow-card, so it reads as the
   same product as the dashboard behind it. All `lp-` prefixed so none of it can
   leak into the app. */

body.landing { background: var(--surface-lowest); }

.lp-wrap { width: 100%; max-width: 1080px; margin: 0 auto; padding: 0 24px; }

/* Header ------------------------------------------------------------------ */
.lp-nav { border-bottom: 1px solid var(--line); background: var(--surface-lowest); }
.lp-nav-inner { display: flex; align-items: center; justify-content: space-between;
  gap: 16px; min-height: 68px; }
.lp-brand { display: inline-flex; align-items: center; }
.lp-brand img { height: 34px; width: auto; display: block; }
.lp-nav-links { display: flex; align-items: center; gap: 18px; }
.lp-nav-links > a:not(.btn) { font-family: var(--font-display); font-size: 14px;
  font-weight: 600; color: var(--deep); }
.lp-nav-links > a:not(.btn):hover { color: var(--teal); }

/* A larger button, for the hero and closing calls to action. */
.btn-lg { font-size: 15px; padding: 12px 22px; }

/* Hero -------------------------------------------------------------------- */
.lp-hero { padding: 76px 0 68px; background: var(--tint);
  border-bottom: 1px solid var(--line); }
.lp-eyebrow { font-family: var(--font-display); font-size: 12px; font-weight: 600;
  letter-spacing: 0.09em; text-transform: uppercase; color: var(--teal);
  margin: 0 0 18px; }
.lp-h1 { font-family: var(--font-display); font-size: 52px; font-weight: 700;
  line-height: 1.06; letter-spacing: -0.03em; color: var(--deep); margin: 0 0 22px; }
.lp-lede { font-size: 18px; line-height: 1.6; color: var(--ink);
  max-width: 60ch; margin: 0 0 30px; }
.lp-cta { display: flex; flex-wrap: wrap; gap: 12px; }
.lp-note { font-size: 13.5px; color: var(--muted); margin: 18px 0 0; }

/* Shared section furniture ------------------------------------------------ */
.lp-section { padding: 72px 0; border-bottom: 1px solid var(--line2); }
.lp-h2 { font-family: var(--font-display); font-size: 30px; font-weight: 700;
  letter-spacing: -0.02em; color: var(--deep); margin: 0 0 12px; }
.lp-sub { font-size: 16px; color: var(--muted); margin: 0 0 34px; }
.lp-steps-section { background: var(--surface-lowest); }

/* How it works ------------------------------------------------------------ */
.lp-steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px;
  list-style: none; margin: 30px 0 0; padding: 0; counter-reset: none; }
.lp-step { position: relative; padding-top: 6px; }
.lp-step-n { display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: var(--r-full);
  background: var(--deep); color: var(--mint);
  font-family: var(--font-display); font-size: 14px; font-weight: 600;
  margin-bottom: 14px; }
.lp-step h3 { font-family: var(--font-display); font-size: 18px; font-weight: 600;
  color: var(--deep); margin: 0 0 8px; }
.lp-step p { font-size: 15px; line-height: 1.6; color: var(--muted); margin: 0; }

/* What you get ------------------------------------------------------------ */
.lp-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
.lp-feature { background: var(--surface-lowest); border: 1px solid var(--line);
  border-radius: var(--r-card); padding: 22px; box-shadow: var(--shadow-card); }
.lp-feature h3 { font-family: var(--font-display); font-size: 17px; font-weight: 600;
  color: var(--deep); margin: 0 0 8px; }
.lp-feature p { font-size: 14.5px; line-height: 1.6; color: var(--muted); margin: 0; }

/* Closing call to action -------------------------------------------------- */
.lp-closer { padding: 78px 0; background: var(--tint); text-align: center; }
.lp-closer .lp-lede { margin-left: auto; margin-right: auto; }
.lp-closer .lp-cta { justify-content: center; }

/* Footer ------------------------------------------------------------------ */
.lp-foot { background: var(--deep); color: var(--nav-fg); padding: 26px 0; }
.lp-foot-inner { display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap; }
.lp-foot-brand { font-family: var(--font-display); font-weight: 700; font-size: 16px; }
.lp-foot-links { display: flex; gap: 20px; flex-wrap: wrap; }
.lp-foot-links a { color: var(--nav-fg); font-size: 14px; }
.lp-foot-links a:hover { color: var(--mint); }

/* Responsive -------------------------------------------------------------- */
@media (max-width: 900px) {
  .lp-steps, .lp-grid { grid-template-columns: repeat(2, 1fr); }
  .lp-h1 { font-size: 40px; }
}
@media (max-width: 620px) {
  .lp-steps, .lp-grid { grid-template-columns: 1fr; }
  .lp-hero { padding: 52px 0 46px; }
  .lp-section, .lp-closer { padding: 52px 0; }
  .lp-h1 { font-size: 33px; }
  .lp-lede { font-size: 16.5px; }
  .lp-h2 { font-size: 25px; }
  .lp-cta .btn { width: 100%; }
  .lp-foot-inner { flex-direction: column; align-items: flex-start; gap: 12px; }
}

/* --- County-grouped area table ------------------------------------------- */
.data-table tr.county-head td {
  background: var(--thead);
  border-top: 1px solid var(--line);
  font-family: var(--font-display); font-size: 11px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--deep); padding-top: 9px; padding-bottom: 9px;
}
.data-table tr.county-head:first-child td { border-top: none; }
/* A county-head band also carries the "Pending review" row, whose second line
   is a SENTENCE, not a label. The uppercase + letter-spacing above is right for
   "NAIROBI COUNTY" and wrong for prose: caps make a sentence slower to read and
   read as shouting on a row that is already a nag. */
.data-table tr.county-head td .row-note {
  text-transform: none; letter-spacing: 0; font-weight: 400;
  font-family: var(--font-body, inherit); font-size: 12px;
  color: var(--on-variant); margin-top: 2px;
}
/* Indent the area name under its county header. */
.data-table td.area-cell { padding-left: 20px; }

/* The same expander outside a table. No border of its own: with the button
   present the last town is no longer the last thing in the card, so it keeps
   the divider it would otherwise drop — giving the button one too draws 2px. */
.ot-town:has(~ .more-btn.ot-more) { border-bottom: 1px solid var(--line2); }

/* "+N more <county> areas" expander row. */
.data-table tr.more-toggle td { padding: 0; }
.more-btn { display: flex; align-items: center; gap: 7px; width: 100%; text-align: left;
  padding: 10px 16px 10px 20px; font-family: var(--font-display); font-size: 12.5px;
  font-weight: 500; color: var(--teal); background: transparent; border: none; cursor: pointer; }
.more-btn:hover { background: var(--tint); }
.more-btn svg { flex: none; transition: transform .15s ease; }
.more-btn.open svg { transform: rotate(90deg); }

/* --- Inline "?" explainer tooltips --------------------------------------- */
/* Hover on desktop; tabindex=0 makes it tap-to-focus on mobile (no hover). */
.info-tip {
  position: relative; display: inline-flex; align-items: center; justify-content: center;
  width: 15px; height: 15px; margin-left: 5px; border-radius: var(--r-full);
  background: var(--surface-container); color: var(--on-variant);
  font-size: 10px; font-weight: 700; line-height: 1; cursor: help;
  vertical-align: middle; text-transform: none; letter-spacing: 0;
  font-variant-numeric: normal;
}
.info-tip::after {
  content: attr(data-tip); position: absolute; bottom: calc(100% + 7px); left: 50%;
  transform: translateX(-50%); width: max-content; max-width: 230px;
  background: var(--on-surface); color: var(--surface-lowest);
  font-size: 13px; font-weight: 400; text-transform: none; letter-spacing: 0;
  text-align: left; line-height: 1.35; padding: 8px 10px; border-radius: var(--r-md);
  opacity: 0; pointer-events: none; transition: opacity .12s ease; z-index: 60;
  box-shadow: 0 4px 14px rgba(11, 47, 51, .18);
}
.info-tip:hover::after, .info-tip:focus::after { opacity: 1; }
/* A tip in a CARD HEADER sits on the top edge of a clipping container
   (.card is overflow:hidden, to keep tables inside its radius), so the
   default upward tooltip is cut off entirely and the reader sees nothing.
   .tip-below opens it downward, into the card body, where there is room.
   Escaping the ancestor's overflow would need position:fixed and JS; this
   stays CSS-only, which is the rule for these tooltips. */
.info-tip.tip-below::after { top: calc(100% + 7px); bottom: auto; }
/* A tip whose TRIGGER is a SOLID PILL. Same escape from the 15x15 badge sizing
   as .tip-inline, but the phrase carries brand fill instead of a dotted rule —
   used where the fact is an exclusion from the number beside it and has to be
   seen, not discovered. Padding and radius match .badge; the fill and the
   deepening hover match .btn-primary, so it reads as one family with the rest
   of the app's solid teal. cursor:help is inherited from .info-tip and is
   deliberate: it is button-SHAPED, and must not promise a click. */
.info-tip.tip-pill {
  width: auto; height: auto; margin-left: 0;
  display: inline-flex; vertical-align: baseline;
  padding: 3px 10px; border-radius: var(--r-full);
  background: var(--teal); color: #fff;
  font-family: var(--font-display); font-size: 11.5px; font-weight: 600;
  line-height: 1.35; letter-spacing: 0.01em; text-decoration: none;
  transition: background .15s ease;
}
.info-tip.tip-pill:hover, .info-tip.tip-pill:focus { background: var(--deep); }

/* A tip whose TRIGGER is a phrase rather than a "?" badge. The badge sizing
   above is fixed 15x15, which crushes real text into a circle; this keeps the
   tooltip behaviour and drops the badge costume. The dotted underline is what
   signals the phrase is explainable, since there's no "?" glyph to do it. */
.info-tip.tip-inline {
  width: auto; height: auto; border-radius: 0; background: none;
  color: inherit; font-size: inherit; font-weight: inherit; line-height: inherit;
  margin-left: 0; display: inline; vertical-align: baseline;
  text-decoration: underline dotted;
  text-underline-offset: 2px;
}

/* --- Executive Key Takeaways — above the tabs ---------------------------- */
/* Each takeaway is its OWN full-width card, sharing the KPI row's surface,
   border, radius and shadow (.stat), so the numbers and the sentences that
   explain them read as one object instead of two designs stacked. It replaced a
   single card of hairline-separated rows, which packed the sentences so tightly
   that the list read as fine print under the figures rather than the thing to
   read first.
   Still deliberately NOT a stack of .insight banners: full-width teal bars
   out-shout the KPIs they exist to explain. The colour restraint is the point —
   structure comes from the cards, emphasis from the lead's weight alone. */
.takeaways { margin-bottom: 18px; }
.takeaways-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 16px; flex-wrap: wrap; margin-bottom: 9px;
}
.takeaways-title {
  display: inline-flex; align-items: center; gap: 7px;
  font-family: var(--font-display); font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.085em; color: var(--deep);
}
.takeaways-title svg { flex: none; color: var(--teal); }
/* ONE row, four columns, mirroring .stat-row directly above it — the takeaways
   line up under the KPIs they explain, one card per number-ish idea, rather
   than running down the page as a list. The view caps the list at
   services.TAKEAWAY_LIMIT so the row never wraps to a stranded second line;
   anything past four is still on its own tab and in the PDF. */
.takeaway-list {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px;
}
/* Vibrant, unlike the KPI cards, and on purpose: this row is the one thing on
   the page that says what to DO, and as plain white cards it read as more of
   the same furniture. The tint carries it — a teal wash plus a gradient top
   rule — while the TEXT stays high-contrast ink on near-white, so the colour
   never costs legibility. It stops short of a solid teal fill, which would
   out-shout the KPI row it is meant to explain. */
.takeaway {
  position: relative; display: flex; flex-direction: column; gap: 10px;
  background: linear-gradient(168deg, var(--tint) 0%, var(--surface-lowest) 62%);
  border: 1px solid var(--surface-high);
  border-radius: var(--r-card); box-shadow: var(--shadow-card);
  padding: 16px 16px 14px; overflow: hidden;
}
.takeaway::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 3px;
  background: linear-gradient(90deg, var(--teal), var(--mint));
}
.takeaway-body { min-width: 0; flex: 1; }
.takeaway-lead {
  margin: 0; font-family: var(--font-display); font-size: 14.5px; font-weight: 600;
  line-height: 1.38; color: var(--deep); letter-spacing: -0.005em;
}
.takeaway-detail {
  margin: 6px 0 0; font-size: 12.5px; line-height: 1.5; color: var(--on-variant);
}
/* The jump link is an affordance, not a call to action. Pinned to the bottom of
   the card by the flex column, so four cards of unequal text still line their
   links up along one baseline. */
.takeaway-go {
  align-self: flex-start; white-space: nowrap;
  font-family: var(--font-display); font-size: 12px; font-weight: 600;
  color: var(--teal); text-decoration: none;
  padding: 5px 11px; border-radius: var(--r-full);
  border: 1px solid var(--surface-high); background: var(--surface-lowest);
  transition: background .15s ease, border-color .15s ease, color .15s ease;
}
.takeaway-go:hover {
  background: var(--teal); border-color: var(--teal); color: #fff;
  text-decoration: none;
}
/* Two up on a tablet. Never three: a 3-wide grid leaves the fourth card alone
   on a second row, which is the stranded-tab problem one element over. */
@media (max-width: 1180px) { .takeaway-list { grid-template-columns: repeat(2, 1fr); } }

/* Phones stay 2x2 rather than falling to four full-width rows, and drop the
   detail line to earn it. Four stacked cards carrying lead AND detail run past
   500px — most of two phone screens of prose before the reader reaches the tabs
   the takeaways point at, which is the opposite of a summary. 2x2 with the lead
   alone fits the whole set above the fold; the detail is one tap away in the
   tab, which is where the link already goes.
   The jump link has to be allowed to wrap here — "See Areas & Zones Breakdown"
   is wider than a half-width phone card, and the nowrap it carries on desktop
   would push it out of the card. */
@media (max-width: 640px) {
  .takeaway { padding: 13px 12px; gap: 9px; }
  .takeaway-lead { font-size: 13.5px; line-height: 1.35; }
  .takeaway-detail { display: none; }
  .takeaway-go { white-space: normal; font-size: 11px; padding: 4px 9px; line-height: 1.3; }
}

/* --- Help / FAQ accordion (native <details>, no JS) ---------------------- */
.faq-wrap { max-width: 720px; }
.faq { border-bottom: 1px solid var(--outline-variant); }
.faq summary {
  padding: 15px 4px; font-weight: 600; font-size: 15px; cursor: pointer;
  list-style: none; display: flex; align-items: center; justify-content: space-between;
  gap: 16px; color: var(--on-surface);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: "+"; color: var(--on-variant); font-weight: 400; font-size: 20px;
  line-height: 1; flex: 0 0 auto;
}
.faq[open] summary::after { content: "\2013"; }  /* en dash */
.faq summary:hover { color: var(--primary-container); }
.faq-body {
  padding: 0 4px 16px; color: var(--on-variant); font-size: 14px; line-height: 1.55;
}

/* --- Trends: period picker + over-time chart ------------------------------ */
/* Bars are divs, not a charting library: the CSP allows no external scripts
   (config/middleware.py), and every other chart in the dashboard is drawn the
   same way. trend_series() supplies the heights as percentages. */

.trend-picker {
  display: flex; flex-wrap: wrap; align-items: flex-end;
  gap: 12px; padding: 16px 18px; margin-bottom: 18px;
}
.trend-picker .field { margin-bottom: 0; }
.trend-picker .field input { min-width: 160px; }

.trend-chart {
  display: flex; align-items: flex-end; gap: 4px;
  /* padding-top is headroom for the value labels, which sit above the tallest
     bar. It has to be PADDING rather than margin: overflow-x:auto forces
     overflow-y to compute to auto, so anything outside the padding box would be
     clipped instead of drawn. */
  height: 200px; overflow-x: auto; padding: 20px 0 4px;
}
.trend-col {
  flex: 1 0 26px; min-width: 26px; height: 100%;
  display: flex; flex-direction: column; justify-content: flex-end;
}
.trend-bar {
  position: relative;   /* anchors .trend-val */
  background: var(--teal); border-radius: 3px 3px 0 0;
  min-height: 2px;  /* a bucket with orders must never render as nothing */
}
.trend-col:hover .trend-bar { background: var(--deep); }

/* Order count above each bar. Hidden by default and switched on only when the
   bars are few enough to read: at 26px per column the labels collide from about
   16 bars on, and a day-bucketed month is 31. The hover title carries the same
   figure either way, so nothing is lost on a dense chart. */
.trend-val {
  display: none;
  position: absolute; bottom: 100%; left: 50%;
  transform: translateX(-50%);
  margin-bottom: 5px;
  font-family: var(--font-display);
  font-size: 11px; font-weight: 600; line-height: 1;
  color: var(--deep); white-space: nowrap;
}
.trend-chart.has-values .trend-val { display: block; }
.trend-col:hover .trend-val { color: var(--teal); }
/* A zero bucket is real information, but it shouldn't shout next to the counts
   that matter. */
.trend-val.is-zero { color: var(--faint); font-weight: 500; }
.trend-x {
  font-size: 10px; color: var(--faint); text-align: center;
  margin-top: 6px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* --- Reality checks ------------------------------------------------------ */

/* A correction to a figure printed nearby: quieter than a finding, louder than
   a footnote. Sits directly above the table or beneath the split it qualifies,
   never in a banner of its own — see services.py "Reality checks". */
.card-note {
  margin: 0 18px 12px; padding: 9px 12px; font-size: 12.5px; line-height: 1.5;
  color: var(--on-variant); background: var(--surface-container);
  border-left: 2.5px solid var(--gold); border-radius: 0 var(--r-md) var(--r-md) 0;
}
.card-note b { color: var(--ink); font-weight: 600; }
.card-body .card-note { margin-left: 0; margin-right: 0; }
