:root {
  /* All Seasons defaults; layout.njk may override via /api/org theme */
  --brand-primary: #003865;
  --brand-secondary: #1c8490;
  --brand-accent: #fcd51b;
  --brand-bg: #f3f7f8;
  --bg: var(--brand-bg);
  --panel: #ffffff;
  --ink: var(--brand-primary);
  --muted: #5b6b7c;
  --line: #d7e0ea;
  /* A heavier hairline, for a border that has to read against a tinted fill.
     Was written as var(--border, #d5dde6) — but --border is
     declared nowhere, so the fallback was the only value and the token
     reference was decoration. Named here so the next use finds this one. */
  --edge-strong: #d5dde6;

  /* State surfaces, inks and edges.
     These are not new colours — every value below was already sitting in rule
     bodies across ops/scheduling/time-off, repeated up to 14 times each.
     Naming them is pure substitution: nothing here moves a pixel.

     Deliberately NOT aliased to a same-valued token that means something else.
     #92400e is also --sales, but every literal use of it is a warning pill;
     #0f766e is also --maint, but four of its six uses are a focus highlight
     and a drop hint. Reskinning "sales" must not repaint every warning. */
  --surface-sunk: #f8fafc;      /* a well inside a card */
  --danger-surface: #fef2f2;
  --danger-ink: #b42318;
  --danger-edge: #fecaca;
  --warn-surface: #fffbeb;
  --warn-ink: #92400e;          /* only ever text on --warn-surface */
  --warn-edge: #b45309;         /* only ever a border or inset rule */
  --good-surface: #e8f5ef;
  --good-ink: #146c43;
  /* Tooltips invert. #f8fafc is the same value as --surface-sunk but a
     different idea — text on a dark ground, not a well in a card. Two names,
     because the day one of them is restyled the other must not follow. */
  --surface-inverse: #0f172a;
  --ink-inverse: #f8fafc;
  --accent: var(--brand-secondary);
  --ideal: #1f9d6a;
  --ok: #3b82f6;
  --warning: #d97706;
  --emergency: #dc2626;
  --store: #64748b;
  /* Routing days (item 9): which weekday a client belongs to.
     Seven hues a dispatcher has to tell apart on a card two centimetres
     wide, with no two adjacent days close in hue. Mirrored in
     scheduling/dayroutes.py DAY_COLOURS, which is what the API sends to
     draw the legend and the setup screen; test_day_routes.py pins them. */
  --route-day-0: #1d4ed8;   /* Mon */
  --route-day-1: #ea580c;   /* Tue */
  --route-day-2: #15803d;   /* Wed */
  --route-day-3: #7c3aed;   /* Thu */
  --route-day-4: #b45309;   /* Fri */
  --route-day-5: #0e7490;   /* Sat */
  --route-day-6: #9f1239;   /* Sun */
  /* Card-fill override palette (scheduling). Six annotation colours a
     dispatcher can put on a single card's FILL; the route-day stripe is never
     overridden, so these deliberately do NOT reuse the route-day hues — a
     fill that matched Tuesday's stripe colour would read as a route-day
     claim. Muted on purpose: they sit behind text. */
  --card-fill-slate: #e2e8f0;
  --card-fill-teal: #d5ebe9;
  --card-fill-moss: #dfe9d9;
  --card-fill-amber: #f3e8d3;
  --card-fill-plum: #e9ddef;
  --card-fill-rose: #f7dfe2;
  --maint: #0f766e;

  /* Status tints. The foreground of every status pill was already a token
     while its background was a raw hex, so half of each pair was invisible to
     anything reading the palette. Same values, now named. */
  --ideal-tint: #d1fae5;
  --ok-tint: #dbeafe;
  --warning-tint: #ffedd5;
  --emergency-tint: #fee2e2;
  --maint-tint: #ccfbf1;
  --store-tint: #e2e8f0;
  --neutral-tint: #f1f5f9;

  /* Three semantics that never got a foreground name either. */
  --info: #0369a1;
  --info-tint: #e0f2fe;
  --idea: #3730a3;
  --idea-tint: #e0e7ff;
  --sales: #92400e;
  --sales-tint: #fef3c7;

  /* A chart's second line, which is NOT --store. They collided because only
     one of the two concepts was ever named: --store is a neutral category
     chip, this is a series that has to stay legible against --maint teal.
     charts.js used to hardcode this as `store`, so executive.njk drew an
     orange line beside a slate chip on the same page. */
  --series-b: #ea580c;

  --shadow: 0 10px 30px rgba(0, 56, 101, 0.08);
  --radius: 14px;
  --font: "IBM Plex Sans", "Segoe UI", sans-serif;
  --display: "Fraunces", Georgia, serif;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  font-family: var(--font);
  color: var(--ink);
  background:
    radial-gradient(1200px 500px at 10% -10%, rgba(28, 132, 144, 0.18) 0%, transparent 55%),
    radial-gradient(900px 400px at 100% 0%, rgba(0, 56, 101, 0.12) 0%, transparent 50%),
    var(--bg);
  min-height: 100vh;
}

/* Ideas board (Help) */
.nav-ideas {
  display: flex !important;
  align-items: center;
  gap: 0.4rem;
}
.nav-ideas-icon {
  display: inline-flex;
  color: var(--accent);
}
.ideas-heading-icon {
  display: inline-flex;
  vertical-align: -0.35rem;
  margin-right: 0.25rem;
  color: var(--accent);
}
.ideas-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
}
.ideas-list-item {
  padding: 0.75rem 0;
  border-bottom: 1px solid var(--line);
}
.ideas-list-item:last-child { border-bottom: none; }
.ideas-card {
  display: block;
  padding: 0.85rem 1rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel);
  color: inherit;
  text-decoration: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.ideas-card:hover {
  border-color: var(--accent);
  text-decoration: none;
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.04);
}
.ideas-card:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.ideas-card-cta {
  display: inline-block;
  margin-top: 0.5rem;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--accent);
}
.ideas-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.75rem;
  margin-bottom: 0.85rem;
}
.ideas-count {
  margin-left: auto;
  color: var(--muted);
  font-size: 0.85rem;
}
.idea-stepper {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem;
  margin: 0 0 1rem;
  padding: 0;
  list-style: none;
}
.idea-stepper li {
  font-size: 0.8rem;
  font-weight: 600;
  padding: 0.25rem 0.6rem;
  border-radius: 999px;
  background: var(--neutral-tint);
  color: var(--muted);
}
.idea-stepper li.done {
  background: var(--ok-tint);
  color: var(--ok);
}
.idea-stepper li.current {
  background: rgba(14, 116, 144, 0.12);
  color: var(--accent);
}
/* A rejected idea never reaches the last two steps. Fading them says that
   without pretending the stages do not exist. */
.idea-stepper li.muted { opacity: 0.35; }
.idea-stepper-fork > span.done {
  background: var(--ok-tint);
  color: var(--ok);
}
.idea-vote-panel {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  margin-bottom: 1rem;
}
.idea-stepper-fork {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  background: transparent !important;
  padding: 0 !important;
  border-radius: 0 !important;
}
.idea-stepper-fork > span:not(.fork-or) {
  padding: 0.25rem 0.6rem;
  border-radius: 999px;
  background: var(--neutral-tint);
  color: var(--muted);
}
.idea-stepper-fork > span.current {
  background: rgba(14, 116, 144, 0.12);
  color: var(--accent);
}
.idea-stepper-fork .fork-or {
  font-size: 0.72rem;
  font-weight: 500;
  color: var(--muted);
  text-transform: lowercase;
}
.ideas-howto-details summary {
  cursor: pointer;
  list-style: disclosure-closed;
}
.ideas-howto-details[open] summary {
  list-style: disclosure-open;
}
.btn-link-muted {
  display: inline-block;
  margin-left: 0.35rem;
  font-size: 0.85rem;
  color: var(--muted);
  text-decoration: none;
  border: none;
  background: none;
  padding: 0.35rem 0.25rem;
}
.btn-link-muted:hover {
  color: var(--accent);
  text-decoration: underline;
}
.admin-ideas-list {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}
.admin-idea-card {
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 0.85rem 1rem;
  background: var(--panel);
}
.admin-idea-card-head {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.35rem 1rem;
  align-items: flex-start;
}
.admin-idea-meta {
  flex-shrink: 0;
}
.admin-idea-body {
  margin: 0.5rem 0 0.75rem;
  white-space: pre-wrap;
}
.admin-idea-form {
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  max-width: 28rem;
}
.admin-idea-form label {
  display: block;
  font-size: 0.85rem;
}
.admin-idea-form select,
.admin-idea-form textarea {
  display: block;
  width: 100%;
  margin-top: 0.25rem;
  font: inherit;
}
.admin-idea-comments {
  margin-top: 0.85rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--line);
}
.admin-idea-comments .ideas-comment-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
}
.admin-idea-comments .ideas-comment-list li {
  padding: 0.5rem 0.65rem;
  border-radius: 6px;
  background: rgba(15, 23, 42, 0.03);
}
.ideas-submit-panel {
  margin-bottom: 0;
}

/* Operations Client / Technician Information (responsive) */
.ops-info {
  margin-bottom: 1rem;
  padding: 1rem 1.1rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel);
}
.ops-info-head h3 {
  margin: 0 0 0.35rem;
  font-size: 1.15rem;
}
.ops-info-lede { margin: 0 0 0.85rem; }
.ops-info-subhead {
  margin: 1.1rem 0 0.5rem;
  font-size: 0.95rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}
.ops-info-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.75rem 1.25rem;
  margin: 0;
}
@media (min-width: 640px) {
  .ops-info-grid {
    grid-template-columns: 1fr 1fr;
  }
  .ops-info-field-wide { grid-column: 1 / -1; }
}
.ops-info-field dt {
  font-size: 0.8rem;
  color: var(--muted);
  margin-bottom: 0.2rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem;
}
.ops-info-field dd {
  margin: 0;
  font-size: 1rem;
  word-break: break-word;
}
.ops-person-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
}
.ops-person-card {
  padding: 0.75rem 0.85rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}
.ops-person-actions { margin-top: 0.25rem; }
.ops-info-edit {
  margin-top: 1rem;
  border-top: 1px solid var(--line);
  padding-top: 0.75rem;
}
.ops-info-edit > summary {
  cursor: pointer;
  font-weight: 600;
  list-style: none;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--accent);
}
.ops-info-edit > summary::-webkit-details-marker { display: none; }
.ops-info-edit-body { margin-top: 0.75rem; }
.ops-info-form-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.65rem 1rem;
}
@media (min-width: 640px) {
  .ops-info-form-grid {
    grid-template-columns: 1fr 1fr;
  }
  .ops-info-form-grid .ops-span-2 { grid-column: 1 / -1; }
}
.ops-info-form label {
  display: block;
  font-size: 0.85rem;
}
.ops-info-form input,
.ops-info-form select,
.ops-info-form textarea {
  display: block;
  width: 100%;
  margin-top: 0.25rem;
  min-height: 44px;
  font: inherit;
  padding: 0.45rem 0.6rem;
  border: 1px solid var(--line);
  border-radius: 6px;
  box-sizing: border-box;
}
.ops-info-form textarea { min-height: 5rem; }
.ops-info-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.85rem;
}
.ops-touch {
  min-height: 44px;
  min-width: 44px;
  padding-left: 1rem;
  padding-right: 1rem;
  cursor: pointer;
}
.ops-check {
  display: flex !important;
  align-items: center;
  gap: 0.5rem;
  font-weight: 400 !important;
  min-height: 44px;
}
.ops-check input { width: auto; min-height: auto; margin: 0; }
@media (max-width: 640px) {
  .ops-info-actions .btn { flex: 1 1 auto; }
}

.pill.kind-idea {
  background: var(--idea-tint);
  color: var(--idea);
}
.pill.kind-bug {
  background: var(--emergency-tint);
  color: #991b1b;
}
@media (max-width: 640px) {
  .admin-idea-card-head {
    flex-direction: column;
  }
  .admin-idea-form {
    max-width: none;
  }
}
.idea-admin-note {
  margin: 0 0 0.85rem;
  padding: 0.65rem 0.75rem;
  border-left: 3px solid var(--accent);
  background: rgba(14, 116, 144, 0.06);
}
.user-id {
  font-size: 0.75rem;
  word-break: break-all;
}
.pill.warning {
  background: rgba(217, 119, 6, 0.15);
  color: var(--warning);
}
.pill.status-open {
  background: var(--ok-tint);
  color: var(--ok);
}
.pill.status-under_review {
  background: var(--warning-tint);
  color: var(--warning);
}
.pill.status-accepted {
  background: var(--ideal-tint);
  color: var(--ideal);
}
.pill.status-in_progress {
  background: var(--idea-tint);
  color: var(--idea);
}
.pill.status-complete {
  background: var(--ideal-tint);
  color: var(--ideal);
}
.pill.status-rejected {
  background: var(--emergency-tint);
  color: var(--emergency);
}

/* Voting. The count sits beside the card rather than inside it, because the
   card is a link and a button nested in an anchor is not valid markup — and
   more practically, a thumb aiming for the vote should never open the item. */
.ideas-row {
  display: flex;
  align-items: stretch;
  gap: 0.6rem;
}
.ideas-row .ideas-card { flex: 1; min-width: 0; }
.vote-form { margin: 0; flex: none; }
.vote-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.1rem;
  min-width: 4rem;
  height: 100%;
  min-height: 44px;
  padding: 0.5rem 0.4rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel);
  color: var(--muted);
  font: inherit;
  line-height: 1.1;
  cursor: pointer;
}
.vote-btn strong { font-size: 1.05rem; color: var(--ink); }
.vote-btn .vote-label { font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.05em; }
.vote-btn:hover { border-color: var(--accent); color: var(--accent); }
.vote-btn.voted {
  border-color: var(--accent);
  background: rgba(28, 132, 144, 0.1);
  color: var(--accent);
}
.vote-btn.voted strong { color: var(--accent); }
.vote-btn.is-closed { cursor: default; opacity: 0.6; }
.vote-btn.is-closed:hover { border-color: var(--line); color: var(--muted); }
@media (prefers-reduced-motion: reduce) {
  .ideas-card { transition: none; }
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.topnav {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.75rem 1.25rem;
  background: rgba(255,255,255,0.94);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line);
  border-top: 3px solid var(--brand-accent);
  position: sticky;
  top: 0;
  z-index: 40;
}
.topnav--utility { min-height: 3.25rem; }
.brand {
  font-family: var(--display);
  font-weight: 700;
  font-size: 1.15rem;
  color: var(--brand-primary);
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  flex-shrink: 0;
}
.brand:hover { text-decoration: none; color: var(--brand-secondary); }
.brand-logo {
  height: 40px;
  width: auto;
  max-width: 200px;
  object-fit: contain;
  display: block;
}
.brand--logo { font-size: 0; }
.platform-mark {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  font-family: var(--display);
  font-weight: 650;
  font-size: 0.72rem;
  letter-spacing: 0.18em;
  color: var(--muted);
  pointer-events: none;
  user-select: none;
  white-space: nowrap;
}

.app-shell {
  display: flex;
  align-items: stretch;
  min-height: calc(100vh - 3.5rem);
}
.app-sidebar {
  width: var(--sidebar-w, 240px);
  flex-shrink: 0;
  background: rgba(255, 255, 255, 0.96);
  border-right: 1px solid var(--line);
  position: sticky;
  top: 3.5rem;
  align-self: flex-start;
  height: calc(100vh - 3.5rem);
  overflow-y: auto;
  z-index: 30;
}
.side-nav {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding: 0.85rem 0.75rem 1.5rem;
}
.side-nav .nav-section {
  /* 0.85rem -> 0.6rem: 4px per heading, 20px across an admin's six. That
     covers the case where a section is force-opened because it holds the
     current page, which is the tightest state the rail has to render. */
  margin: 0.6rem 0.55rem 0.35rem;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}
.side-nav .nav-section:first-child { margin-top: 0.25rem; }

/* Collapsible sections.
 *
 * 24 destinations plus six headings is 1058px against a 744px rail — the rail
 * at 1280x800, which is the budget nav_registry.test.js pins; 1440x900 is the
 * roomier 844px. Five items sat below the fold with nothing saying so. Audit,
 * Admin and Help fold; Overview, Operations and Directory never do, because
 * NN/g's rule is not to accordion what people need most and those three are a
 * dispatcher's day.
 *
 * <details> rather than a hand-rolled disclosure: the summary is focusable and
 * in tab order, Enter and Space toggle it, the expanded state reaches
 * assistive tech without a hand-maintained aria-expanded, and it degrades to
 * always-open where <details> is unsupported — which is exactly today's
 * behaviour. */
.side-nav .nav-group { display: flex; flex-direction: column; }
.side-nav .nav-group-items { display: flex; flex-direction: column; gap: 0.15rem; }
.side-nav summary.nav-section {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  cursor: pointer;
  list-style: none;
  border-radius: 8px;
  padding: 0.1rem 0.2rem;
  margin-left: 0.35rem;
  margin-right: 0.35rem;
}
.side-nav summary.nav-section::-webkit-details-marker { display: none; }
/* NN/g ran a study on which icon reads as expandable; the caret won. Points
   right when closed, down when open, and it is click-activated, not hover. */
.side-nav summary.nav-section::after {
  content: "";
  width: 0; height: 0; margin-left: auto;
  border-left: 4px solid currentColor;
  border-top: 3.5px solid transparent;
  border-bottom: 3.5px solid transparent;
  transition: transform 0.12s ease;
}
.side-nav details[open] > summary.nav-section::after { transform: rotate(90deg); }
.side-nav summary.nav-section:hover { background: rgba(28, 132, 144, 0.1); }

/* Most-visited paths on the activity trail. Each is a link that re-filters the
   trail to that path, so the summary is a way in rather than a dead end. */
.top-paths { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.top-path {
  display: inline-flex; align-items: baseline; gap: 0.45rem;
  border: 1px solid var(--line); border-radius: 999px;
  padding: 0.25rem 0.7rem; text-decoration: none;
  background: var(--panel); font-size: 0.85rem;
}
.top-path:hover { border-color: var(--accent); }
.top-path-n { font-weight: 700; color: var(--ink); }
.top-path-p { color: var(--muted); }
.side-nav a {
  color: var(--ink);
  padding: 0.5rem 0.7rem;
  border-radius: 10px;
  text-decoration: none;
  font-size: 0.92rem;
  font-weight: 500;
}
.side-nav a:hover {
  background: rgba(28, 132, 144, 0.1);
  color: var(--accent);
  text-decoration: none;
}
.side-nav a.active {
  background: rgba(28, 132, 144, 0.14);
  color: var(--accent);
  font-weight: 600;
}
.app-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}
.app-main main,
main.guest-main {
  max-width: 1280px;
  width: 100%;
  margin: 0 auto;
  padding: 1.5rem;
}
.sidebar-backdrop {
  display: none;
}

main { max-width: 1280px; margin: 0 auto; padding: 1.5rem; }
.eyebrow {
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.72rem;
  color: var(--muted);
  font-weight: 600;
}
h1 {
  font-family: var(--display);
  font-size: clamp(1.8rem, 3vw, 2.4rem);
  margin: 0.2rem 0 0.4rem;
  font-weight: 650;
}
.lede { color: var(--muted); margin: 0 0 1.25rem; max-width: 52rem; }

.hero {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  align-items: flex-start;
  flex-wrap: wrap;
  margin-bottom: 1.25rem;
}
.badge-link {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  background: var(--accent);
  color: white !important;
  padding: 0.65rem 0.95rem;
  border-radius: 999px;
  text-decoration: none !important;
  font-weight: 600;
  box-shadow: var(--shadow);
}

.kpi-grid {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 0.85rem;
  margin-bottom: 1.25rem;
}
@media (max-width: 1000px) {
  .kpi-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.kpi {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1rem;
  box-shadow: var(--shadow);
}
.kpi .label { font-size: 0.72rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em; }
.kpi .value { font-size: 1.8rem; font-weight: 700; margin: 0.25rem 0; }
.kpi .delta { font-size: 0.85rem; color: var(--muted); }
.kpi .delta.up { color: var(--ideal); }
.kpi .delta.down { color: var(--emergency); }
.kpi-grid:empty { display: none; }

/* --- Executive headline ---------------------------------------------------
   One page, one number. Eleven tiles at 1.8rem/700 meant a tag count read as
   loudly as the number the business is judged on; the ideal rate now leads at
   a size nothing else on the page uses, and the three numbers that qualify it
   sit beside it rather than competing with it. */
.exec-headline {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
  gap: 1.5rem;
  align-items: center;
  margin-bottom: 1rem;
}
.exec-headline .label {
  font-size: 0.72rem; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.06em;
}
.exec-headline-value {
  font-size: clamp(2.6rem, 5vw, 3.6rem);
  font-weight: 700; line-height: 1.05;
  color: var(--brand-primary);
  margin: 0.35rem 0 0.25rem;
  font-family: var(--font-display, inherit);
}
/* Ideal-rate bands from the active Home profile color the headline number. */
.exec-headline-value.token-ideal { color: var(--ideal); }
.exec-headline-value.token-ok { color: var(--ok); }
.exec-headline-value.token-warning { color: var(--warning); }
.exec-headline-value.token-emergency { color: var(--emergency); }
/* auto-fit, not a fixed 3: the tile count follows the profile — the shorter
   ideal-rate window only appears when one is configured. */
.exec-headline-side {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(7.5rem, 1fr));
  gap: 1rem;
}
.exec-headline-side .value { font-size: 1.35rem; font-weight: 700; margin: 0.2rem 0; }
.exec-headline-side .delta { font-size: 0.8rem; color: var(--muted); }
.exec-headline-side .delta.up { color: var(--ideal); }
.exec-headline-side .delta.down { color: var(--emergency); }
/* The headline's own trend, same polarity as the side tiles: for a rate where
   higher is better, up is green. */
.exec-headline-main .delta { font-size: 0.85rem; color: var(--muted); margin-bottom: 0.15rem; }
.exec-headline-main .delta.up { color: var(--ideal); }
.exec-headline-main .delta.down { color: var(--emergency); }
@media (max-width: 900px) {
  .exec-headline { grid-template-columns: minmax(0, 1fr); }
}

/* One filter bar with one Apply, folded above the answer.
   There were three panels each with their own submit — scope, then tags, then
   chemicals stranded inside the outcome chart — all posting the same form. */
.exec-filters { display: flex; flex-direction: column; gap: 0.6rem; }
.exec-filter-collapse { margin-bottom: 1rem; }
/* The filter form is already inside the details' padded body. */
.exec-filter-collapse .ops-info-collapse-body { padding-top: 0.75rem; }
.exec-filter-row {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem 0.85rem;
}
.exec-filter-row > .label {
  font-size: 0.72rem; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.06em;
  min-width: 6.5rem;
}
.exec-check {
  font-size: 0.85rem; display: inline-flex; align-items: center; gap: 0.3rem;
}
.exec-apply { margin-left: auto; }

.grid-2 {
  display: grid;
  grid-template-columns: 1.4fr 1fr;
  gap: 1rem;
  margin-bottom: 1rem;
}
.grid-3 {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1rem;
  margin-bottom: 1rem;
}
@media (max-width: 1000px) {
  .grid-2, .grid-3 { grid-template-columns: 1fr; }
}

.panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1rem 1.1rem;
  box-shadow: var(--shadow);
}
.panel h3 { margin: 0 0 0.25rem; font-size: 1.05rem; }
.panel .sub { color: var(--muted); font-size: 0.85rem; margin-bottom: 0.75rem; }

.chart { width: 100%; height: 260px; }
.chart.tall { height: 360px; }
.chart.tall.rel-graph,
#rel-graph.rel-graph {
  height: min(70vh, 820px);
  min-height: 560px;
}
.chart svg { width: 100%; height: 100%; display: block; }
.chart-empty { color: var(--muted); padding: 1rem; font-size: 0.9rem; }
.chart.chart-placeholder {
  height: auto;
  color: var(--muted);
  font-size: 0.9rem;
}

.dash-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1rem;
  margin-top: 1rem;
}
.dash-gridstack-host {
  margin-top: 1rem;
  min-height: 12rem;
}
.dash-gridstack-host .grid-stack-item-content {
  overflow: auto;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 0.75rem 0.85rem;
}
.grid-stack-item.is-selected > .grid-stack-item-content {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.dash-edit-shell { max-width: 100%; }
.dash-edit-top {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: 0.75rem;
}
.dash-edit-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 1.25rem;
  align-items: flex-end;
  margin-bottom: 0.75rem;
}
.dash-edit-meta input[type="text"],
.dash-edit-meta select {
  display: block;
  margin-top: 0.25rem;
  min-width: 8rem;
}
/* The builder needs canvas room; other pages keep the 1280 reading measure. */
.app-main main:has(.dash-edit-shell) { max-width: 1600px; }
/* Same trade for the rule builder: it needs room for the diagram beside it.
   The Rules and Templates tabs are six-column tables and keep the 1280
   reading measure — 1600px of table is worse, not better. */
.app-main main:has(.rules-build) { max-width: 1600px; }
/* Scheduling is a workbench, not a reading measure. At 1280 the board got
   ~49% of the page — thirteen technician columns inside roughly 600px — while
   the queue and the side panel took the rest. Same precedent as the dashboard
   editor above. */
.dash-edit-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 20rem;
  gap: 0.75rem;
  align-items: start;
}
@media (min-width: 1101px) and (max-width: 1400px) {
  .dash-edit-body { grid-template-columns: minmax(0, 1fr) 18rem; }
}
/* Below the split, the rail stacks under the canvas instead of pinching it. */
@media (max-width: 1100px) {
  .dash-edit-body { grid-template-columns: 1fr; }
}
/* Panel padding is dead space around a preview; keep it tight on the canvas. */
.dash-canvas-wrap { min-width: 0; padding: 0.85rem; }
.dash-add-menu { position: relative; }
.dash-add-pop {
  position: absolute;
  /* Anchored left: the button sits at the start of the toolbar, so a
     right-anchored popover spills over the primary nav. */
  left: 0;
  top: calc(100% + 0.35rem);
  z-index: 40;
  width: 20rem;
  max-width: 90vw;
  padding: 0.35rem;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 12px 28px rgba(15, 32, 45, 0.18);
}
.dash-add-item {
  display: block;
  width: 100%;
  text-align: left;
  padding: 0.5rem 0.6rem;
  border: 0;
  border-radius: 8px;
  background: transparent;
  cursor: pointer;
  min-height: 44px;
}
.dash-add-item:hover,
.dash-add-item:focus-visible { background: var(--panel-alt, rgba(28, 132, 144, 0.08)); }
.dash-add-item .sub { display: block; font-size: 0.78rem; color: var(--muted); }
.dash-canvas {
  min-height: 28rem;
  background: linear-gradient(180deg, rgba(28, 132, 144, 0.04), transparent 40%);
}
/* The rail follows the canvas so editing a panel low on the board needs no scroll. */
.dash-side-panel {
  position: sticky;
  top: 1rem;
  max-height: calc(100vh - 2rem);
  overflow: auto;
}
@media (max-width: 1100px) {
  .dash-side-panel { position: static; max-height: none; }
}
.dash-side-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.35rem;
}
.dash-side-head .sub { font-weight: 600; color: var(--ink); }
.dash-side-panel .side-field {
  display: block;
  margin: 0.45rem 0;
  font-size: 0.9rem;
}
.dash-side-panel .side-field input,
.dash-side-panel .side-field select,
.dash-side-panel .side-field textarea {
  display: block;
  width: 100%;
  margin-top: 0.25rem;
}
.dash-side-panel .side-hint {
  display: block;
  margin-top: 0.2rem;
  font-size: 0.75rem;
  color: var(--muted);
  font-weight: 400;
}
.dash-side-panel .side-check {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin: 0.45rem 0;
  font-size: 0.85rem;
}
.dash-side-panel .side-summary {
  margin: 0.1rem 0 0.6rem;
  padding: 0.4rem 0.5rem;
  font-size: 0.8rem;
  color: var(--muted);
  background: var(--panel-alt, rgba(28, 132, 144, 0.07));
  border-radius: 8px;
}
.dash-side-panel .side-group {
  margin: 0.6rem 0;
  border-top: 1px solid var(--line);
  padding-top: 0.5rem;
}
.dash-side-panel .side-group > summary {
  cursor: pointer;
  font-size: 0.85rem;
  font-weight: 600;
  min-height: 32px;
  line-height: 32px;
}
.dash-side-panel .side-card {
  margin: 0.5rem 0;
  padding: 0.5rem;
  border: 1px solid var(--line);
  border-radius: 8px;
}
.dash-kpi-note { font-size: 0.72rem; line-height: 1.35; }
@media (max-width: 767px) {
  .dash-side-panel select,
  .dash-side-panel input[type="text"],
  .dash-side-panel input[type="number"] { min-height: 44px; }
  .dash-side-panel .btn { min-height: 44px; }
}
.dash-widget--wide,
.dash-widget.dash-widget--wide {
  grid-column: 1 / -1;
}
@media (max-width: 767px) {
  .dash-grid { grid-template-columns: 1fr; }
}
.dash-rich-text {
  font-size: 0.95rem;
  line-height: 1.45;
  color: var(--ink);
}
.dash-table-host { overflow-x: auto; }
.dash-filter-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 1rem;
  align-items: flex-start;
  margin: 0.75rem 0 0;
  padding: 0.65rem 0.85rem;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.dash-filter-bar label { font-size: 0.85rem; font-weight: 600; }
.dash-filter-bar > label:not(.chk) {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}
.dash-filter-bar .filter-stack select { min-width: 12rem; }
.dash-filter-bar .tag-checks,
.dash-filter-bar > .sub { flex-basis: 100%; }
.dash-editor-widget[draggable="true"] { cursor: grab; }
.dash-editor-widget.dragging { opacity: 0.5; }
.dash-editor-widget.drag-over { outline: 2px dashed var(--accent); }
.dash-widget-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.5rem;
  margin-bottom: 0.35rem;
}
.dash-widget-head h3 { margin: 0; font-size: 1.05rem; }
.dash-widget-link { font-size: 0.8rem; }
.dash-editor-widget {
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 0.75rem;
  margin-bottom: 0.75rem;
  background: #fff;
}
.dash-editor-widget-title {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  align-items: center;
  margin-bottom: 0.5rem;
}
.dash-editor-fields label { display: inline-block; margin-right: 1rem; margin-bottom: 0.35rem; }
.dash-check-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 0.25rem 0.75rem;
  margin: 0.35rem 0 0.75rem;
  font-size: 0.85rem;
}
.dash-kpi-host { margin-top: 0.25rem; }
/* Executive's fixed 5 columns squeeze KPI cards inside a half-width panel. */
.dash-kpi-host.kpi-grid {
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  margin-bottom: 0;
}
/* One card per row would push the rest out of a fixed-height panel on a phone. */
@media (max-width: 767px) {
  .dash-kpi-host.kpi-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.5rem;
  }
  .dash-kpi-host .kpi { padding: 0.5rem 0.6rem; }
  .dash-kpi-host .kpi .value { font-size: 1.45rem; }
  .dash-kpi-host .kpi .label { font-size: 0.62rem; }
  /* Sparklines read as noise at this width and cost a whole card of height. */
  .dash-kpi-host .dash-spark { display: none; }
}
/* .trend-up / .trend-down were removed. Nothing rendered them, and their
   polarity was the opposite of .delta.up/.delta.down twenty lines up: up was
   amber, down was blue. Two contradictory conventions in one stylesheet is a
   trap for whoever reaches for the next trend indicator, so the one that was
   live wins. Use .delta.up / .delta.down. */
.dash-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  margin: 0 0 0.4rem;
}
.dash-chip {
  font-size: 0.72rem;
  line-height: 1.5;
  padding: 0 0.4rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--muted);
  background: var(--panel);
}
.dash-site-search {
  display: block;
  width: min(100%, 26rem);
  margin: 0.35rem 0;
  padding: 0.35rem 0.5rem;
}
.dash-site-grid {
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  max-height: 15rem;
  overflow-y: auto;
  padding-right: 0.25rem;
}

.help-layout {
  display: grid;
  grid-template-columns: minmax(180px, 240px) 1fr;
  gap: 1rem;
  align-items: start;
}
.help-nav-title { margin: 0 0 0.75rem; font-size: 1.15rem; }
.help-nav nav { display: flex; flex-direction: column; gap: 0.25rem; }
.help-nav a {
  padding: 0.45rem 0.55rem;
  border-radius: 6px;
  color: var(--ink);
  text-decoration: none;
  font-size: 0.9rem;
}
.help-nav a:hover { background: var(--store-tint); }
.help-nav a.active { background: color-mix(in srgb, var(--accent) 18%, white); font-weight: 600; }
.help-article h1 { margin-top: 0; }
.help-article h2 { font-size: 1.1rem; margin-top: 1.25rem; }
.help-figure {
  margin: 1rem 0;
}
.help-figure img {
  max-width: 100%;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-sunk);
}
.help-figure figcaption {
  color: var(--muted);
  font-size: 0.8rem;
  margin-top: 0.35rem;
}
@media (max-width: 800px) {
  .help-layout { grid-template-columns: 1fr; }
}


.rel-graph-host {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  height: 100%;
}
.rel-graph-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.75rem;
  flex: 0 0 auto;
}
.rel-graph-search {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.85rem;
  color: var(--muted);
}
.rel-graph-search input {
  min-width: 10rem;
  padding: 0.35rem 0.5rem;
  border: 1px solid var(--line);
  border-radius: 6px;
  font: inherit;
}
.rel-graph-zoom-btns {
  display: inline-flex;
  gap: 0.25rem;
  margin-left: auto;
}
.rel-graph-zoom-btns .btn {
  min-width: 2.25rem;
  padding: 0.35rem 0.55rem;
}
.rel-graph-stage {
  flex: 1 1 auto;
  min-height: 0;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: linear-gradient(180deg, var(--surface-sunk) 0%, var(--neutral-tint) 100%);
  overflow: hidden;
}
.rel-graph-stage svg {
  width: 100%;
  height: 100%;
  display: block;
  touch-action: none;
  cursor: grab;
}
.rel-tooltip {
  position: absolute;
  z-index: 5;
  max-width: 260px;
  padding: 0.65rem 0.75rem;
  background: var(--surface-inverse);
  color: var(--ink-inverse);
  border-radius: 8px;
  font-size: 0.8rem;
  line-height: 1.35;
  box-shadow: 0 8px 24px rgba(15, 23, 42, 0.25);
  pointer-events: auto;
}
.rel-tooltip-body strong { font-weight: 650; }
.rel-tooltip-actions {
  margin-top: 0.5rem;
}
.rel-tooltip-actions .btn {
  font-size: 0.75rem;
  padding: 0.3rem 0.55rem;
}
.rel-legend {
  margin-bottom: 0.75rem;
}
.rel-legend-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.55rem 0.85rem;
  font-size: 0.85rem;
}
.rel-legend-row.sub {
  color: var(--muted);
  margin-top: 0.35rem;
  font-size: 0.8rem;
}
.rel-swatch {
  display: inline-block;
  width: 0.7rem;
  height: 0.7rem;
  border-radius: 999px;
  margin-right: 0.15rem;
  vertical-align: middle;
}
.rel-graph-panel { padding-bottom: 0.75rem; }

@media (max-width: 640px) {
  .chart.tall.rel-graph,
  #rel-graph.rel-graph {
    height: 65vh;
    min-height: 420px;
  }
  .rel-graph-zoom-btns { margin-left: 0; }
}


table.data {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.92rem;
}
table.data th, table.data td {
  text-align: left;
  padding: 0.55rem 0.4rem;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}
table.data th {
  color: var(--muted);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.pill {
  display: inline-block;
  padding: 0.15rem 0.5rem;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 600;
}
.pill.maintenance { background: var(--maint-tint); color: var(--maint); }
.pill.store { background: var(--store-tint); color: var(--store); }
/* Every classification has a pill — a backgroundless "service" beside an
   outlined source badge made the annotation outrank the thing annotated. */
.pill.service { background: var(--info-tint); color: var(--info); }
.pill.construction { background: var(--sales-tint); color: var(--sales); }
.pill.liner { background: var(--ideal-tint); color: var(--ideal); }
/* warn family, not --warning: the warning pair is 2.78:1 at pill size and
   the PASSING amber (--warn-ink on --warn-surface, 6.84:1) already sits on
   the same summary line as "default hours". */
.pill.unclassified { background: var(--warn-surface); color: var(--warn-ink); }
.filters a.warn:not(.active) { background: var(--warn-surface); color: var(--warn-ink); }
/* Source badge: outline, quiet — WaterLink people carry NOTHING (badge the
   exception; an all-WaterLink shop sees zero new chrome). */
.pill.source { background: transparent; border: 1px solid var(--line); color: var(--muted); font-weight: 500; }
.pill.ideal { background: var(--ideal-tint); color: var(--ideal); }
.pill.ok { background: var(--ok-tint); color: var(--ok); }
.pill.warning { background: var(--warning-tint); color: var(--warning); }
.pill.info { background: var(--info-tint); color: var(--info); }
.pill.emergency, .pill.critical, .pill.danger { background: var(--emergency-tint); color: var(--emergency); }
tr.rule-disabled td { opacity: 0.55; }
tr.rule-disabled td:first-child { text-decoration: line-through; text-decoration-thickness: 1px; }
.pill.sales { background: var(--sales-tint); color: var(--sales); }
.pill.email-on { background: var(--maint-tint); color: #0f766e; }
.pill.email-off { background: var(--neutral-tint); color: var(--muted); font-weight: 500; }
.pill.tag { background: rgba(28, 132, 144, 0.12); color: var(--accent); font-weight: 500; }
.pill.unknown { background: var(--neutral-tint); color: var(--muted); }

/* Key-value voice — Phase E extraction from the scheduling drawer.
   Two shapes, one voice:
   - .kv-row: a fact as a row (micro-label left, value right, hairline rules).
   - bare .k / .v: the same label+value voice for containers with their own
     layout (meta-cards etc.) — for years these classes had NO styles and
     rendered at body size, patched with inline styles per view.
   Scoped treatments (.to-balance, .sched-reading) deliberately override the
   base by specificity. Micro-label size is 0.7rem, the scale step both the
   drawer's 0.62 and the app's 0.72 labels absorb into (design/scale.md). */
.kv-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.75rem;
  padding: 0.4rem 0;
  font-size: 0.85rem;
}
/* Between-row rule via adjacency, not :first-of-type — a host that renders
   any other div before the list would otherwise keep a stray top border. */
.kv-row + .kv-row { border-top: 1px solid var(--line); }
.kv-label, .k {
  flex: none;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted);
}
.kv-label { align-self: center; }
.kv-value, .v {
  min-width: 0;
  overflow-wrap: anywhere;
  font-size: 0.85rem;
  font-weight: 500;
}
.kv-value { text-align: right; }
/* 600, not 650 — IBM Plex loads 400/500/600/700; 650 was synthesized. */
.kv-value.strong { font-weight: 600; font-variant-numeric: tabular-nums; }
.kv-value-slot { font-variant-numeric: tabular-nums; }

/* Inline save feedback beside a form's button. Lived in scheduling.css while
   six non-scheduling views consumed it — their ok/error colours never
   rendered. One home now. */
.form-status { font-size: 0.8rem; color: var(--muted); margin-left: 0.6rem; }
.form-status.ok { color: var(--good-ink); }
.form-status.error { color: var(--danger-ink); }
.tag-checks {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem 1rem;
  margin: 0.5rem 0 0.75rem;
}

.filters { display: flex; gap: 0.4rem; margin-bottom: 1rem; flex-wrap: wrap; }
.filters a, .btn {
  border: 1px solid var(--line);
  background: white;
  color: var(--ink);
  padding: 0.45rem 0.8rem;
  border-radius: 999px;
  text-decoration: none;
  font-size: 0.9rem;
  cursor: pointer;
}
.filters a.active, .filters .btn.active, .btn.primary {
  background: var(--accent);
  border-color: var(--accent);
  color: white;
}
.btn.primary { font-weight: 600; }
.btn.danger {
  background: var(--emergency-tint);
  border-color: var(--danger-edge);
  color: var(--emergency);
  font-weight: 600;
}
.btn.danger:hover { background: var(--danger-edge); }

.search-bar {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  align-items: center;
  margin-bottom: 0.85rem;
}
.rule-form label {
  display: block;
  font-size: 0.85rem;
  margin-bottom: 0.55rem;
  color: var(--ink);
}
.rule-form input[type="text"],
.rule-form input[type="number"],
.rule-form select {
  display: block;
  width: 100%;
  margin-top: 0.25rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 0.45rem 0.6rem;
  font: inherit;
  background: white;
}
.rules-build {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  gap: 1rem;
  align-items: start;
}
/* align-self is load-bearing: a grid item stretched to the row height has
   nothing left to stick against. */
.rule-shape-panel { position: sticky; top: 1rem; align-self: start; }
.rule-shape svg { width: 100%; height: auto; display: block; }
@media (max-width: 1100px) {
  /* Diagram BELOW the builder — the deliberate inverse of the catalog's old
     order:-1. A picture of a rule you have not built yet is not worth the top
     of the screen. */
  .rules-build { grid-template-columns: 1fr; }
  .rule-shape-panel { position: static; }
}
.rule-form-row {
  display: flex;
  gap: 0.75rem;
  flex-wrap: wrap;
}
.rule-form-row label { flex: 1 1 8rem; }
.rule-form .match-panel[aria-hidden="true"] {
  display: none !important;
}

.toggle {
  display: inline-flex;
  border: 1px solid var(--line);
  border-radius: 999px;
  overflow: hidden;
}
.toggle button {
  border: 0;
  background: white;
  padding: 0.45rem 0.9rem;
  cursor: pointer;
}
.toggle button.active.maintenance { background: #0f766e; color: white; }
.toggle toggle button.active.store,
.toggle button.active.store { background: #475569; color: white; }

.meta-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0.75rem;
  margin: 1rem 0;
}
@media (max-width: 900px) {
  .meta-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.meta-card {
  background: var(--surface-sunk);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 0.8rem;
}
.ops-info-collapse {
  margin-bottom: 1rem;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: #fff;
  padding: 0;
}
.ops-info-collapse > .ops-info-collapse-summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  padding: 0.85rem 2rem 0.85rem 1rem;
  position: relative;
  min-height: 44px;
  box-sizing: border-box;
}
.ops-info-collapse > .ops-info-collapse-summary::-webkit-details-marker { display: none; }
.ops-info-collapse > .ops-info-collapse-summary::after {
  content: "▸";
  position: absolute;
  right: 0.85rem;
  top: 50%;
  transform: translateY(-50%);
  color: var(--muted);
  font-size: 0.85rem;
}
.ops-info-collapse[open] > .ops-info-collapse-summary::after {
  transform: translateY(-50%) rotate(90deg);
}
.ops-info-collapse-title {
  font-weight: 700;
  color: var(--ink);
  font-size: 1rem;
}
.ops-info-collapse-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  align-items: center;
}
.ops-info-collapse-body {
  padding: 0 1rem 1rem;
  border-top: 1px solid var(--line);
}
.ops-info.ops-info-collapse {
  padding: 0;
  background: #fff;
}
.ops-info.ops-info-collapse .ops-info-grid {
  margin-top: 0.75rem;
}

.visit-card-list {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}
.visit-card {
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface-sunk);
  padding: 0.85rem 1rem;
}
.visit-card-head {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 0.75rem;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: 0.5rem;
}
.visit-when { font-weight: 700; }
.visit-pills { display: flex; flex-wrap: wrap; gap: 0.35rem; }
.pill.coverage { background: var(--store-tint); color: var(--ink); font-weight: 600; }
.pill.coverage.chem_work { background: var(--ok-tint); color: #1e40af; }
.pill.coverage.work_only { background: var(--neutral-tint); color: var(--muted); }
.pill.coverage.chem_only { background: #ecfdf5; color: #047857; }
.visit-who { font-size: 0.9rem; margin: 0.2rem 0 0.45rem; }
.visit-site { margin-bottom: 0.35rem; font-weight: 600; }
.visit-readings { margin: 0.35rem 0 0.55rem; }
.visit-work {
  margin-top: 0.55rem;
  padding: 0.65rem 0.75rem;
  border-radius: 10px;
  border: 1px dashed var(--line);
  background: #fff;
  cursor: pointer;
  min-height: 44px;
}
.visit-work:hover, .visit-work:focus-visible {
  border-color: var(--accent);
  outline: none;
}
.visit-work.muted { cursor: default; border-style: solid; opacity: 0.85; }
.visit-work-preview { margin-top: 0.2rem; }
/* A second reading row on the same card: the tech treated the water and tested
   again. Indented so it reads as belonging to the visit above it, not as a
   separate one. */
.visit-retest {
  margin-top: 0.15rem;
  padding-left: 0.7rem;
  border-left: 2px solid var(--line);
}
.visit-retest-label { margin-right: 0.4rem; white-space: nowrap; }
/* Points at the card holding this day's work. Tappable — it opens the same
   worklog drawer — so it gets a real target height. */
.visit-work-note {
  margin-top: 0.35rem;
  padding: 0.4rem 0.55rem;
  border-radius: 8px;
  cursor: pointer;
  min-height: 44px;
  display: flex;
  align-items: center;
}
.visit-work-note:hover, .visit-work-note:focus-visible {
  color: var(--accent);
  outline: none;
}
.visit-card-summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 0.65rem;
  align-items: center;
  min-height: 44px;
  padding: 0.25rem 0;
}
.visit-card-summary::-webkit-details-marker { display: none; }
.visit-card-compact { padding-top: 0.5rem; padding-bottom: 0.5rem; }
.visit-load-more { min-height: 44px; }
.visit-sync-hint {
  margin-top: 0.45rem;
  line-height: 1.35;
  color: var(--muted);
}

@media (max-width: 480px) {
  .meta-grid { grid-template-columns: 1fr; }
}

.worklog-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin: 0.5rem 0 0.85rem;
}
/* Home view editor (admin config → Home): sectioned, preview-first. */
.home-subnav {
  display: flex; flex-wrap: wrap; gap: 0.35rem;
  margin: 0.25rem 0 1rem; padding-bottom: 0.65rem;
  border-bottom: 1px solid var(--line);
}
.home-subnav button {
  border: 1px solid var(--line); background: transparent;
  border-radius: 999px; padding: 0.35rem 0.85rem; cursor: pointer;
  font: inherit; font-size: 0.85rem; color: inherit;
}
.home-subnav button.active {
  background: var(--brand-primary); border-color: var(--brand-primary);
  color: var(--ink-inverse);
}
.home-section-grid {
  display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: 1.25rem; align-items: start;
}
@media (max-width: 900px) { .home-section-grid { grid-template-columns: 1fr; } }
.home-preview-col {
  background: var(--surface-sunk); border: 1px solid var(--line);
  border-radius: 10px; padding: 0.85rem;
}
.home-profile-form .home-sentence input,
.home-profile-form .home-sentence select {
  width: auto; display: inline-block; margin: 0 0.15rem;
  vertical-align: baseline;
}
.home-profile-form .home-sentence input[type="number"] { width: 4.5rem; }
.home-mixbar-track {
  display: flex; height: 22px; border-radius: 6px; overflow: hidden;
  margin: 0.4rem 0 0.3rem; border: 1px solid var(--line);
}
.home-ideal-preview {
  font-size: clamp(2.4rem, 4vw, 3.2rem); font-weight: 700;
  color: var(--brand-primary); margin: 0.35rem 0;
  font-family: var(--font-display, inherit);
}
.home-ideal-preview.token-ideal { color: var(--ideal); }
.home-ideal-preview.token-ok { color: var(--ok); }
.home-ideal-preview.token-warning { color: var(--warning); }
.home-ideal-preview.token-emergency { color: var(--emergency); }
.home-rule-card { margin-bottom: 0.6rem; cursor: grab; }
.home-rule-card.dragging { opacity: 0.55; }
.home-rule-head { display: flex; flex-wrap: wrap; gap: 0.4rem; align-items: center; }
.home-rule-head input { flex: 1; min-width: 7rem; }
.home-rule-head select { width: auto; }
.home-group { margin: 0.5rem 0; padding: 0.5rem 0.65rem; }
.home-cond-row { display: flex; flex-wrap: wrap; gap: 0.35rem; align-items: center; margin: 0.35rem 0; }
.home-cond-row select, .home-cond-row input { width: auto; }
.home-cond-params { display: inline-flex; gap: 0.3rem; align-items: center; flex-wrap: wrap; }
.home-group-actions { display: flex; gap: 0.4rem; margin-top: 0.35rem; }
/* Only rendered once a rule has two groups — see home_profiles.js. */
.home-rule-combine { margin: 0.45rem 0 0.35rem; }
.home-rule-combine select { margin: 0 0.25rem; }
.rule-flow svg { width: 100%; height: auto; }
.home-profile-form h4 { margin: 0.25rem 0 0.5rem; }
.home-preview-col .data td, .home-preview-col .data th { font-size: 0.8rem; }

/* Triage chart chemical picker (incident_triage / alert_triage). */
.factor-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin: 0.5rem 0 0.75rem;
}
.factor-chips .factor-chip[aria-pressed="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.worklog-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.25rem 0.55rem;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--surface-sunk);
  font-size: 0.8rem;
}
.worklog-chip .n {
  font-weight: 700;
  color: var(--accent);
}
/* A table lent to the query rather than one of the warehouse's own, so it reads
   as a different kind of thing in the list. */
.worklog-chip--scope {
  border-style: dashed;
  border-color: var(--accent);
}
.dataset-scope-head {
  margin: 1.25rem 0 0.35rem;
  font-size: 0.95rem;
}
.dataset-scope-list {
  margin: 0.75rem 0 0;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.3rem 0.9rem;
  font-size: 0.82rem;
}
.dataset-scope-list dt {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.78rem;
  color: var(--accent);
  white-space: nowrap;
}
.dataset-scope-list dd {
  margin: 0;
  color: var(--muted);
}
@media (max-width: 559px) {
  /* Term over definition; the two-column grid squeezes both to nothing. */
  .dataset-scope-list { grid-template-columns: 1fr; gap: 0.15rem; }
  .dataset-scope-list dd { margin-bottom: 0.5rem; }
}
tr.worklog-row {
  cursor: pointer;
}
tr.worklog-row:hover,
tr.worklog-row:focus-visible {
  background: #f0f9fa;
  outline: none;
}
.worklog-drawer[hidden] { display: none !important; }
.worklog-drawer {
  position: fixed;
  inset: 0;
  z-index: 80;
}
.worklog-drawer-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(15, 23, 42, 0.35);
}
.worklog-drawer-panel {
  position: absolute;
  top: 0;
  right: 0;
  height: 100%;
  width: min(28rem, 100%);
  background: #fff;
  border-left: 1px solid var(--line);
  box-shadow: -8px 0 24px rgba(15, 23, 42, 0.12);
  display: flex;
  flex-direction: column;
  padding: 1rem 1.1rem 1.25rem;
  overflow: auto;
}
.worklog-drawer-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 0.75rem;
  margin-bottom: 0.85rem;
}
.worklog-drawer-head h2 { margin: 0 0 0.25rem; font-size: 1.15rem; }
body.worklog-drawer-open { overflow: hidden; }
.worklog-task-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
}
.worklog-task {
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 0.7rem 0.8rem;
  background: var(--surface-sunk);
}
.worklog-task-top {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.4rem;
}
.worklog-task-notes {
  margin-top: 0.4rem;
  font-size: 0.9rem;
  color: var(--muted);
  white-space: pre-wrap;
}
@media (max-width: 640px) {
  .worklog-drawer-panel {
    width: 100%;
    border-left: none;
  }
}

button.help {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.05rem;
  height: 1.05rem;
  padding: 0;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: white;
  color: var(--muted);
  font-size: 0.68rem;
  font-weight: 700;
  line-height: 1;
  cursor: help;
  text-transform: none;
  letter-spacing: 0;
  vertical-align: middle;
  margin-left: 0.2rem;
}
button.help:hover,
button.help:focus-visible,
button.help[aria-expanded="true"] {
  color: var(--ink);
  border-color: #94a3b8;
  outline: none;
}
.help-tip {
  position: absolute;
  z-index: 40;
  max-width: 18rem;
  padding: 0.65rem 0.8rem;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--surface-inverse);
  color: var(--ink-inverse);
  font-size: 0.82rem;
  font-weight: 400;
  line-height: 1.35;
  box-shadow: 0 10px 28px rgba(15, 23, 42, 0.22);
  text-transform: none;
  letter-spacing: 0;
}
table.data th {
  white-space: nowrap;
}

.readings { display: flex; flex-wrap: wrap; gap: 0.35rem; }
.reading {
  background: var(--surface-sunk);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 0.2rem 0.45rem;
  font-size: 0.78rem;
  font-weight: 600;
}
.reading.ideal { background: var(--ideal-tint); color: var(--ideal); border-color: #a7f3d0; }
.reading.ok { background: var(--ok-tint); color: var(--ok); border-color: #bfdbfe; }
.reading.warning { background: var(--warning-tint); color: var(--warning); border-color: #fed7aa; }
.reading.emergency { background: var(--emergency-tint); color: var(--emergency); border-color: var(--danger-edge); }
.reading.unknown { background: var(--neutral-tint); color: var(--muted); }

.chem-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr));
  gap: 0.85rem;
  margin-top: 0.5rem;
}
.chem-card {
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 0.55rem 0.65rem 0.35rem;
  background: var(--surface-sunk);
  min-width: 0;
}
.chem-title {
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--muted);
  text-transform: uppercase;
}
.chem-chart { height: 180px; }

.vessel-tabs a { font-weight: 600; }
.admin-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin: 0 0 1rem;
}
.admin-tabs a {
  padding: 0.45rem 0.85rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: white;
  color: var(--ink);
  text-decoration: none;
  font-size: 0.9rem;
  font-weight: 600;
}
.admin-tabs a.active {
  background: var(--ink);
  color: white;
  border-color: var(--ink);
}
.rule-form textarea {
  display: block;
  width: 100%;
  margin-top: 0.25rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 0.45rem 0.6rem;
  font: inherit;
  background: white;
  min-height: 7rem;
}
.filters .chk {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  border: 1px solid var(--line);
  background: white;
  color: var(--ink);
  padding: 0.45rem 0.8rem;
  border-radius: 999px;
  font-size: 0.9rem;
}
.reading[hidden] { display: none !important; }
.reading-unit[hidden] { display: none !important; }

.chart-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 0.55rem 1rem;
  margin-top: 0.55rem;
  font-size: 0.82rem;
  color: var(--muted);
}
.chart-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}
.chart-legend .swatch {
  width: 0.75rem;
  height: 0.75rem;
  border-radius: 2px;
  display: inline-block;
}

/* Pager under a panel table. Buttons are 44px so a thumb can hit them, and the
   count sits between them because "which ten am I looking at" is the question
   the pager exists to answer. */
.lv-pager {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-top: 0.75rem;
}
.lv-pager .btn { min-height: 44px; }
.lv-pager-status { margin: 0 auto; font-variant-numeric: tabular-nums; }

.bar-row {
  display: grid;
  grid-template-columns: 1fr 3fr auto;
  gap: 0.5rem;
  align-items: center;
  margin: 0.35rem 0;
  font-size: 0.88rem;
}
.bar-track {
  height: 10px;
  background: #eef2f7;
  border-radius: 999px;
  overflow: hidden;
}
.bar-fill { height: 100%; background: var(--emergency); border-radius: 999px; }
.bar-fill.tech { background: var(--accent); }

.error-box {
  background: #fff1f2;
  border: 1px solid #fecdd3;
  color: #9f1239;
  padding: 1rem;
  border-radius: 12px;
}
.warehouse-sync {
  margin-left: 0.75rem;
  font-size: 0.78rem;
  font-weight: 500;
  color: var(--muted);
  white-space: nowrap;
}
/* The drawer's copy of the sync stamp. Only one of the two is ever shown; the
   header keeps it wherever the utility row has room for it. */
.side-nav-sync {
  display: none;
  margin: 1rem 0 0;
  padding-top: 0.85rem;
  border-top: 1px solid var(--line);
  font-size: 0.75rem;
  line-height: 1.45;
  color: var(--muted);
}
.topnav-right {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  font-size: 0.85rem;
  color: var(--muted);
}
.topnav-right form { margin: 0; }
.topnav-right .btn { padding: 0.35rem 0.7rem; font-size: 0.82rem; }
.role-pill {
  background: rgba(28, 132, 144, 0.12);
  color: var(--accent);
  border-radius: 999px;
  padding: 0.15rem 0.55rem;
  font-size: 0.75rem;
  font-weight: 600;
}

details.role-legend {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0.85rem 1rem;
  box-shadow: var(--shadow);
  margin-bottom: 0;
}
details.role-legend summary {
  cursor: pointer;
  font-weight: 600;
  color: var(--ink);
  list-style: revert;
}
details.role-legend[open] summary { margin-bottom: 0.25rem; }

.client-type-tags {
  gap: 0.3rem;
  align-items: center;
}
.client-type-tags .pill {
  margin: 0;
}
.pill-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  align-items: center;
}
.pill.inherited {
  background: var(--neutral-tint);
  color: var(--muted);
  font-weight: 500;
  border: 1px dashed var(--line);
}
.pill.chip {
  background: #eef2f7;
  color: var(--ink);
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
}
.chip-x {
  border: 0;
  background: transparent;
  color: inherit;
  cursor: pointer;
  font-size: 0.85rem;
  line-height: 1;
  padding: 0 0.1rem;
  font-weight: 700;
}
.chip-x:hover { color: var(--emergency); }

.inline-form {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
  align-items: center;
}
.inline-form select,
.inline-form input[type="text"] {
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 0.4rem 0.55rem;
  font: inherit;
  background: white;
}

.group-card {
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 0.75rem 0.85rem;
  margin-bottom: 0.75rem;
  background: var(--surface-sunk);
}
.group-card-head {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  margin-bottom: 0.45rem;
}

.users-panel-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
  margin-bottom: 0.85rem;
}
.user-card-list {
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
}
.user-card {
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface-sunk);
  padding: 0;
}
.user-card-summary {
  list-style: none;
  cursor: pointer;
  display: grid;
  grid-template-columns: minmax(10rem, 1.2fr) minmax(12rem, 2fr);
  gap: 0.75rem 1.25rem;
  align-items: start;
  padding: 0.85rem 1rem;
  position: relative;
  padding-right: 2rem;
}
.user-card-summary::-webkit-details-marker { display: none; }
.user-card-summary::after {
  content: "▸";
  position: absolute;
  right: 0.85rem;
  top: 0.9rem;
  color: var(--muted);
  font-size: 0.85rem;
  transition: transform 0.15s ease;
}
.user-card[open] > .user-card-summary::after { transform: rotate(90deg); }
.user-card-summary:focus-visible,
.add-user-panel > summary:focus-visible,
.notify-policy-row > summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
  .user-card-summary::after { transition: none; }
}
.user-card-identity {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  min-width: 0;
}
.user-card-meta {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  min-width: 0;
}
.user-card-signin { word-break: break-word; }
.user-card-body {
  padding: 0 1rem 1rem;
  border-top: 1px solid var(--line);
}
.user-card-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1rem 1.25rem;
  margin-top: 0.85rem;
}
.user-card-section {
  margin: 0 0 0.45rem;
  font-size: 0.9rem;
  font-weight: 700;
}
.user-card-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: center;
}
.add-user-panel > summary {
  cursor: pointer;
  list-style: none;
}
.add-user-panel > summary::-webkit-details-marker { display: none; }
@media (max-width: 1000px) {
  .user-card-summary {
    grid-template-columns: 1fr;
  }
  .user-card-grid {
    grid-template-columns: 1fr;
  }
}

.login-shell {
  position: relative;
  z-index: 1;
  min-height: calc(100vh - 4rem);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem 1rem 2rem;
}
body.auth-page {
  background: #e8f1f4;
}
body.auth-page .topnav--utility {
  background: rgba(255, 255, 255, 0.72);
  backdrop-filter: blur(8px);
  border-bottom-color: rgba(0, 56, 101, 0.08);
}
body.auth-page .brand {
  /* Client brand lives on the auth card (“For …”), not the chrome */
  visibility: hidden;
  pointer-events: none;
}
body.auth-page .platform-mark {
  font-size: 0.78rem;
  letter-spacing: 0.2em;
  color: var(--brand-primary);
  opacity: 0.72;
}
body.auth-page .warehouse-sync {
  display: none;
}
body.auth-page .login-shell {
  min-height: calc(100vh - 3.25rem);
  /* Atmosphere plate — soft so the card stays readable */
  background-color: #d9e8ee;
  background-image:
    linear-gradient(
      180deg,
      rgba(243, 247, 248, 0.72) 0%,
      rgba(243, 247, 248, 0.55) 40%,
      rgba(227, 240, 244, 0.62) 100%
    ),
    url("/brand/kadunko-login-bg.jpg");
  background-size: cover;
  background-position: center 35%;
  background-repeat: no-repeat;
}
body.auth-page .login-shell::before {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(255, 255, 255, 0.18);
  pointer-events: none;
  z-index: 0;
}
body.auth-page .login-card {
  position: relative;
  z-index: 1;
  background: #fff;
  border: 1px solid rgba(0, 56, 101, 0.1);
  border-radius: 16px;
  box-shadow:
    0 18px 40px rgba(0, 56, 101, 0.12),
    0 2px 8px rgba(0, 56, 101, 0.06);
  padding: 2rem 1.75rem 1.75rem;
  width: 100%;
  max-width: 400px;
  text-align: center;
}
.login-card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 2rem;
  width: 100%;
  max-width: 380px;
}
.login-product {
  margin: 0;
  font-family: var(--display);
  font-weight: 650;
  font-size: clamp(1.85rem, 4vw, 2.35rem);
  letter-spacing: 0.04em;
  color: var(--brand-primary);
  line-height: 1.1;
}
.login-tagline {
  margin: 0.35rem 0 0;
  font-size: 0.95rem;
  color: var(--muted);
}
.login-org {
  margin: 1rem 0 0;
  padding-top: 0.85rem;
  border-top: 1px solid var(--line);
}
.login-org-label {
  margin: 0 0 0.45rem;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}
.login-logo {
  display: block;
  height: auto;
  width: auto;
  max-height: 40px;
  max-width: 180px;
  margin: 0 auto;
  object-fit: contain;
}
.login-org-name {
  margin: 0;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--ink);
}
.login-card form {
  text-align: left;
  margin-top: 0.5rem;
}
.login-card h1 {
  margin: 0 0 0.25rem;
  font-family: var(--display);
  color: var(--brand-primary);
}
.login-card .login-product + .sub,
.login-card .login-tagline + .sub {
  margin-top: 1rem;
}
.login-card label {
  display: block;
  font-size: 0.85rem;
  font-weight: 600;
  margin-top: 1rem;
  text-align: left;
}
.login-card input {
  width: 100%;
  margin-top: 0.3rem;
  padding: 0.6rem 0.7rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  font: inherit;
}
.login-card button { width: 100%; margin-top: 1.25rem; }

.comment-list { display: flex; flex-direction: column; gap: 0.6rem; margin: 0.75rem 0; }
.comment-item {
  background: var(--surface-sunk);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 0.6rem 0.75rem;
}
.comment-item .comment-meta { font-size: 0.75rem; color: var(--muted); margin-bottom: 0.25rem; }

footer.page-foot {
  color: var(--muted);
  font-size: 0.8rem;
  padding: 2rem 1.5rem;
  text-align: center;
}

.table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  max-width: 100%;
}
.nav-toggle {
  display: none;
  margin-left: auto;
  min-height: 44px;
  padding: 0.45rem 0.9rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel);
  color: var(--brand-primary);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}

.dash-kpi-spark {
  height: 28px;
  margin-top: 0.35rem;
}
.dash-kpi-host .kpi.thresh-green .value,
.dash-kpi-host .kpi.thresh-ideal .value { color: var(--ideal); }
.dash-kpi-host .kpi.thresh-yellow .value,
.dash-kpi-host .kpi.thresh-warning .value { color: var(--warning); }
.dash-kpi-host .kpi.thresh-red .value,
.dash-kpi-host .kpi.thresh-emergency .value { color: var(--emergency); }
.dash-kpi-host .kpi.thresh-accent .value { color: var(--accent); }
.dash-table-host td.thresh-ideal { color: var(--ideal); font-weight: 600; }
.dash-table-host td.thresh-warning { color: var(--warning); font-weight: 600; }
.dash-table-host td.thresh-emergency { color: var(--emergency); font-weight: 600; }
.dash-tabs {
  display: flex;
  gap: 0.35rem;
  flex-wrap: wrap;
  margin-bottom: 1rem;
}
.dash-tabs a {
  padding: 0.4rem 0.75rem;
  border-radius: 999px;
  border: 1px solid var(--line);
  color: var(--muted);
  text-decoration: none;
  font-size: 0.88rem;
  font-weight: 600;
}
.dash-tabs a.active {
  background: rgba(28, 132, 144, 0.14);
  color: var(--accent);
  border-color: transparent;
}
.readonly-banner {
  background: var(--warn-surface);
  border: 1px solid #fde68a;
  color: var(--sales);
  padding: 0.65rem 0.9rem;
  border-radius: 10px;
  margin-bottom: 1rem;
  font-size: 0.9rem;
}

.breadcrumb {
  margin: 0 0 0.5rem;
  font-size: 0.9rem;
}
.breadcrumb a { color: var(--accent); text-decoration: none; font-weight: 600; }
.breadcrumb a:hover { text-decoration: underline; }

.compare-picker {
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 0.65rem 0.85rem;
  background: var(--surface-sunk);
}
.compare-picker > summary {
  cursor: pointer;
  font-weight: 600;
  list-style: none;
}
.compare-picker > summary::-webkit-details-marker { display: none; }
.compare-tech-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 0.35rem;
  margin: 0.5rem 0 0;
  max-height: 16rem;
  overflow: auto;
}
.compare-tech-label {
  font-size: 0.88rem;
  display: flex;
  align-items: center;
  gap: 0.3rem;
  flex-wrap: wrap;
}
.compare-tech-label[hidden] { display: none !important; }

@media (max-width: 959px) {
  .nav-toggle { display: inline-flex; align-items: center; }
  .app-sidebar {
    position: fixed;
    left: 0;
    top: 0;
    height: 100vh;
    width: min(280px, 86vw);
    transform: translateX(-105%);
    transition: transform 0.2s ease;
    box-shadow: var(--shadow);
    z-index: 50;
  }
  body.nav-open .app-sidebar {
    transform: translateX(0);
  }
  .sidebar-backdrop {
    display: block;
    position: fixed;
    inset: 0;
    background: rgba(0, 56, 101, 0.35);
    z-index: 45;
  }
  .sidebar-backdrop[hidden] { display: none; }
  /* The utility row cannot fit brand, Menu, your name, Account and Sign out on
     a phone; squeezing them all in clipped the Sign out label. Drop the two
     that tell you nothing you don't know — your own name and role. */
  .topnav-right .role-pill,
  .topnav-right .nav-user { display: none; }
  .warehouse-sync {
    font-size: 0.7rem;
    max-width: 11rem;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  /* The image must obey the anchor, which shrinks below. Without this it keeps
     its intrinsic width, spills past its own box and lands under the sync
     stamp. */
  .brand-logo { height: 32px; max-width: min(160px, 34vw); }
  /* Nothing left to give it in the utility row; the drawer shows it instead. */
  .warehouse-sync { display: none; }
  .side-nav-sync { display: block; }
  /* Account is reachable only from here — it is not in the drawer — so the bar
     has to fit both it and Sign out on one line. Tighten the bar rather than
     drop a destination; "Sign out" wrapping to two lines was the symptom. */
  .topnav { padding-left: 0.85rem; padding-right: 0.85rem; gap: 0.6rem; }
  .topnav-right { gap: 0.6rem; }
  .topnav-right .btn { white-space: nowrap; }
  /* The platform mark is absolutely centred, so it is out of flow and lands on
     top of whatever occupies the middle of the bar. On a phone that is the
     client's name on one side and the Menu button on the other, and they
     collide. Below the sidebar breakpoint the bar has no spare middle, so the
     mark steps aside — Kadunko is still named in the tab title, on the sign-in
     page and on /app. */
  body:not(.auth-page) .platform-mark { display: none; }
  /* A long client name must not push Menu off the edge either. */
  .brand { min-width: 0; flex-shrink: 1; }
  /* ...but a logo is already capped by width above, so shrinking its box only
     detaches the box from the image inside it. */
  .brand--logo { flex-shrink: 0; }
  .brand:not(.brand--logo) {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 1rem;
  }
  .app-main main,
  main.guest-main,
  main { padding: 0.85rem; }
  .kpi-grid:not(.dash-kpi-host) { grid-template-columns: 1fr !important; }
  .btn, .filters a, .toggle button, .admin-tabs a, .login-card button,
  .inbox-bell {
    min-height: 44px;
  }
  /* Anchored to the bell, the panel hung 114px off the left edge of a 375px
     screen and cut the first third of every row — including the unread rail,
     which left unread as colour-only, the one thing it must never be. */
  .inbox-panel {
    position: fixed;
    top: auto;
    left: 0.75rem;
    right: 0.75rem;
    width: auto;
  }
  .panel { min-width: 0; }
  table.data th { white-space: nowrap; }
  .side-nav a { min-height: 44px; display: flex; align-items: center; }
  .chem-edge-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 0.5rem;
  }
}

.chem-band-list { display: flex; flex-direction: column; gap: 0.65rem; }
.chem-edge-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
  gap: 0.65rem;
  margin-top: 0.5rem;
}
.chem-edge-grid label {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  font-size: 0.85rem;
}
.chem-band-card summary { cursor: pointer; }
.factor-multi { border: 0; padding: 0; margin: 0.75rem 0; }
.factor-multi-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(5.5rem, 1fr));
  gap: 0.35rem 0.75rem;
  margin-top: 0.35rem;
}
.factor-multi-item {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  font-weight: 400;
  font-size: 0.9rem;
}
.manual-site-results {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  margin: 0.35rem 0 0.75rem;
  max-height: 14rem;
  overflow: auto;
}
.manual-site-option {
  text-align: left;
  border: 1px solid var(--edge-strong);
  background: #fff;
  border-radius: 6px;
  padding: 0.55rem 0.75rem;
  cursor: pointer;
  min-height: 44px;
}
.manual-site-option:hover { border-color: var(--accent); }
.manual-datetime-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: center;
}
.manual-datetime-row input { flex: 1 1 12rem; }

/* --- site visit records ---------------------------------------------------
   A photograph is evidence, so the grid favours seeing it over fitting a lot
   of them: 8rem cells stay legible on a phone, and the thumbnails are buttons
   because a photo you can only open with a mouse is one half the people on a
   truck cannot open at all. */
.vr-record { padding: 0.85rem 0; border-bottom: 1px solid var(--line); }
.vr-record:last-of-type { border-bottom: none; }
.vr-record-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.5rem; }
.vr-body { margin: 0.4rem 0 0.6rem; white-space: pre-wrap; }
.vr-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr));
  gap: 0.5rem;
}
.vr-thumb {
  padding: 0; border: 1px solid var(--line); background: none; cursor: pointer;
  border-radius: 6px; overflow: hidden; aspect-ratio: 4 / 3; min-height: 44px;
}
/* cover, so a portrait and a landscape sit in one tidy grid — the FULL frame,
   uncropped and at its real ratio, is what the lightbox is for. */
.vr-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.vr-thumb:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.vr-add { margin-top: 0.9rem; }
.vr-add > summary { display: inline-block; cursor: pointer; }

.vr-lightbox {
  position: fixed; inset: 0; z-index: 1000;
  background: rgba(6, 38, 60, 0.88);
  display: grid; place-items: center; gap: 1rem; padding: 1.5rem;
}
.vr-lightbox[hidden] { display: none; }
/* contain, not cover: the point of opening a photo is to see all of it, at the
   ratio it was taken. */
.vr-lightbox img { max-width: 100%; max-height: 80vh; object-fit: contain; border-radius: 6px; }
.vr-lightbox-close { min-height: 44px; }


/* --- notification bell ------------------------------------------------------
   Quiet until there is something. An always-lit badge is a badge people stop
   seeing. */

.inbox { position: relative; }
.inbox-bell {
  position: relative;
  padding: 0.3rem 0.5rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--panel);
  color: var(--muted);
  cursor: pointer;
  font-size: 0.9rem;
  line-height: 1;
}
.inbox-bell.has-unread { color: var(--accent); border-color: var(--accent); }
.inbox-count {
  position: absolute;
  top: -0.35rem;
  right: -0.35rem;
  min-width: 1.15rem;
  padding: 0 0.25rem;
  border-radius: 999px;
  background: var(--danger-ink);
  color: var(--panel);
  font-size: 0.68rem;
  font-weight: 700;
  line-height: 1.15rem;
  text-align: center;
}
.inbox-count[hidden] { display: none; }

.inbox-panel {
  position: absolute;
  right: 0;
  top: calc(100% + 0.4rem);
  z-index: 900;
  width: min(22rem, calc(100vw - 2rem));
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: 0 10px 30px rgba(6, 38, 60, 0.18);
}
.inbox-panel[hidden] { display: none; }
.inbox-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.6rem 0.75rem;
  border-bottom: 1px solid var(--line);
}
.inbox-list {
  list-style: none;
  margin: 0;
  padding: 0;
  max-height: 24rem;
  overflow-y: auto;
}
.inbox-list li { border-bottom: 1px solid var(--line); }
.inbox-list li:last-child { border-bottom: 0; }
.inbox-list li > * {
  display: grid;
  gap: 0.1rem;
  padding: 0.6rem 0.75rem;
  text-decoration: none;
  color: var(--ink);
}
.inbox-list a:hover { background: var(--surface-sunk); }
.inbox-list .t { font-weight: 600; font-size: 0.9rem; }
/* Unread carries a rail rather than a colour swap: the text stays as legible
   as everything else, and the difference survives being colour-blind. */
.inbox-list li.unread { border-left: 3px solid var(--accent); }
.inbox-list li.read > * { color: var(--muted); }
/* Waiting for its window: present, not shouting. Dotted rather than solid so
   the difference from unread survives being colour-blind. */
.inbox-list li.waiting { border-left: 3px dotted var(--accent); }
.inbox-list li.waiting > * { color: var(--muted); }
.inbox-list .when { font-size: 0.72rem; }
.inbox-foot {
  padding: 0.45rem 0.75rem;
  border-top: 1px solid var(--line);
  text-align: center;
}
/* The full page reuses the dropdown's list; roomier rows, real tap targets.
   overflow clips the unread rail to the card's corner — without it a 3px bar
   runs square past a 14px radius and reads as a rendering bug. */
.inbox-page { border-radius: var(--radius); overflow: hidden; }
.inbox-page li > * { padding: 0.85rem 1rem; min-height: 44px; }
.inbox-panel { overflow: hidden; }
.inbox-list a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}
/* Nothing in the sheet said what disabled looks like, so a dead button was
   pixel-identical to a live one — and the Inbox shows one by default. */
.btn:disabled, .btn[disabled] { opacity: 0.55; cursor: default; }
.pref-line {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 44px;
}
.pref-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  min-width: 44px;
}
.pref-matrix { max-width: 34rem; }
.pref-matrix td { vertical-align: middle; }
.pref-matrix td:nth-child(n + 2), .pref-matrix th:nth-child(n + 2) {
  text-align: center;
  width: 6rem;
}

/* A capability, shown beside the role pill because it is not a role. Outlined
   rather than filled: it sits next to the rank and should not compete with it. */
.pill.cap-expenses {
  border-color: var(--accent);
  color: var(--accent);
  background: transparent;
}

/* --- the settings index ----------------------------------------------------
   Seven screens whose names never said enough on their own. The card gives
   each one the sentence a nav label had nowhere to put, so the page is read
   once and then navigated by memory. */
.settings-cards {
  list-style: none;
  margin: 0.75rem 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(22rem, 100%), 1fr));
  gap: 0.6rem;
}
.settings-cards a {
  display: grid;
  gap: 0.15rem;
  height: 100%;
  padding: 0.7rem 0.85rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel);
  text-decoration: none;
  color: inherit;
}
.settings-cards a:hover { border-color: var(--accent); }
.settings-cards .t { font-weight: 600; color: var(--ink); }

/* --- collapsing the rail ----------------------------------------------------
   The scheduling board is the page that actually wants the width — it is
   already allowed 1760px where everything else caps at 1280 — so collapsing
   gives it 240px back, and the toggle is the same hamburger that opens the
   drawer on a phone. One control, one meaning: show or hide the menu.

   Collapse is to ZERO, not to an icon rail. An icon rail needs an icon per
   destination and there are fifteen; the only icon in the product today is the
   Ideas bulb. A strip of unlabelled boxes is worse than no strip. */
@media (min-width: 960px) {
  .nav-toggle {
    display: inline-flex;
    align-items: center;
    /* Beside the brand, not floated right: this button controls the rail on
       the LEFT, and `margin-left:auto` sent it into the centred wordmark,
       which is absolutely positioned and does not push back — it rendered as
       "KADUNKOMenu". */
    order: -1;
    margin-left: 0.6rem;
    margin-right: 0.4rem;
    min-height: 36px;
    padding: 0.3rem 0.7rem;
    font-size: 0.85rem;
  }
  body.rail-collapsed .app-sidebar {
    /* Not display:none — the rail is sticky and position-dependent, and
       removing it from flow makes the main column jump on every navigation.
       Zero width with the content clipped keeps the layout stable. */
    width: 0;
    border-right: 0;
    overflow: hidden;
  }
  /* The board earns the whole window once the rail is gone. Everything else
     keeps its reading measure — a 1,700px line of prose is not a feature. */
  body.rail-collapsed .app-main main:has(.sched-page) {
    max-width: none;
    padding-left: 1rem;
    padding-right: 1rem;
  }
}
/* Wider than the old 1760 even with the rail open: the board is a grid of
   columns, one per technician, and it is the one page where more columns
   visible at once is the whole job. */
.app-main main:has(.sched-page) { max-width: min(100%, 2200px); }

/* Working hours on the technician profile: read-only, with a route to the form.
   The page is called "Technician profile" and is where somebody lands looking
   for a technician; hours live on Scheduling setup, and a page that simply did
   not mention them is how an edit gets made against nothing. */
.tech-shift { margin-bottom: 1rem; }
.tech-shift-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  flex-wrap: wrap;
}
.tech-shift-head h2 { margin: 0; }
.tech-shift-days {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 0.9rem;
  padding: 0;
  margin: 0.4rem 0 0;
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
}
.tech-shift-days li { white-space: nowrap; }
.tech-shift .sub.warn { color: var(--warn-ink); }

/* An aside inside a How-to: the one thing on the page a reader must not skim
   past. Deliberately not a warning colour — most of these are "this is how it
   works", not "you are about to break something". */
.help-note {
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: 0 8px 8px 0;
  background: var(--surface-sunk);
  padding: 0.75rem 1rem;
  margin: 1.1rem 0;
}
.help-note p { margin: 0; }
