/* App design layer — sits on top of Bootstrap (loaded after bootstrap.min.css).
 *
 * A single source of design tokens + reusable component classes, ported from the
 * "Citizen Canvassing Web App" design draft. Two jobs:
 *   1. Remap Bootstrap's own --bs-* variables so stock components (buttons, cards,
 *      forms, badges, text/bg utilities) inherit the palette/shape for free.
 *   2. Add app-specific components the draft introduces (stat tiles, chips,
 *      segmented controls, status tiles, soft badges, progress strip, the circular
 *      progress ring, sticky bars, the desktop left rail).
 * No build step — plain CSS custom properties + selectors.
 */

/* ============================================================ TOKENS */
:root {
  /* palette — ink is primary; green is reserved for save/success */
  --ink: #0f1d0e;
  --ink-hover: #1c2e1a;
  --muted: #5d685d;
  --faint: #abb4ab;
  --border: #dee1de;
  --border-soft: #eaecea;
  --divider: #f2f3f1;
  --surface: #f7f8f7;
  --page: #fbfbfa;
  --card: #fff;
  --map: #efefea;
  --ok: #20813e;
  --ok-tint: #ebfaf0;
  --ok-border: #b7e2c4;
  --warn: #b8860b;
  --warn-tint: #fef8e8;
  --warn-border: #f9dd8a;
  --bad: #df0c0e;
  --bad-tint: #fef2f2;
  --bad-border: #f7c5c5;
  --blue: #0a71d2;
  --blue-tint: #e1effd;
  --blue-border: #b6d7f7;
  --purple: #9244e3;

  /* shape */
  --r-pill: 9999px;
  --r-card: 12px;
  --r-card-lg: 16px;
  --r-phone: 28px;
  --r-input: 8px;
  --r-seg: 10px;
  --r-tile: 9px;
  --shadow-card: 0 1px 3px rgba(0, 0, 0, 0.08);
  --shadow-float: 0 -4px 16px rgba(0, 0, 0, 0.06);
  --shadow-ctrl: 0 1px 4px rgba(0, 0, 0, 0.1);

  /* type */
  --font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

  /* rail */
  --rail-w: 220px;
  --rail-w-collapsed: 66px;

  /* ---- Bootstrap remap ---- */
  --bs-body-font-family: var(--font);
  --bs-body-color: var(--ink);
  --bs-body-color-rgb: 15, 29, 14;
  --bs-body-bg: var(--page);
  --bs-emphasis-color: var(--ink);
  --bs-secondary-color: var(--muted);
  --bs-tertiary-color: var(--faint);
  --bs-border-color: var(--border);
  --bs-border-radius: 10px;
  --bs-border-radius-sm: 8px;
  --bs-border-radius-lg: var(--r-card);
  --bs-primary: var(--ink);
  --bs-primary-rgb: 15, 29, 14;
  --bs-success: var(--ok);
  --bs-success-rgb: 32, 129, 62;
  --bs-danger: var(--bad);
  --bs-danger-rgb: 223, 12, 14;
  --bs-warning: var(--warn);
  --bs-warning-rgb: 184, 134, 11;
  --bs-link-color: var(--ink);
  --bs-link-color-rgb: 15, 29, 14;
  --bs-link-hover-color: #000;
  /* Bootstrap's "primary subtle" trio defaults to light *blue* (from its blue primary) and
   * drives things like the accordion active header and row highlights — retint to a light
   * ink/green-grey so those surfaces match the palette. */
  --bs-primary-bg-subtle: #eef1ee;
  --bs-primary-border-subtle: #d5dbd5;
  --bs-primary-text-emphasis: var(--ink);
  /* One canvas colour: pages use bg-body-tertiary in a few places, and Bootstrap's bg
   * utilities read the *-rgb variants — so align both with --page (251,251,250) to keep
   * every non-card surface the same off-white. Cards stay pure white so they float. */
  --bs-tertiary-bg: var(--page);
  --bs-tertiary-bg-rgb: 251, 251, 250;
  --bs-secondary-bg: var(--page);
  --bs-secondary-bg-rgb: 251, 251, 250;
  --bs-card-bg: #fff;
}

/* ============================================================ BASE */
body {
  font-family: var(--font);
  color: var(--ink);
  background: var(--page);
  /* Absorb any element that's a hair wider than the viewport so the page can't drift
   * sideways. `clip` (not `hidden`) keeps overflow-y visible, so it doesn't turn body
   * into a scroll container and break `position: sticky`. */
  overflow-x: clip;
}
/* Nested scroll regions shouldn't chain their momentum into the page (the "bounce" you
 * feel when a list/table hits its end). The table wrappers drop their nested scroll on
 * mobile (see each page), but this still helps desktop trackpad scrolling. */
.cov-table-wrap,
.prog-table-wrap,
.feed-wrap,
.stations-wrap,
.table-responsive,
#addr-list,
#street-suggest {
  overscroll-behavior: contain;
}
h1, h2, h3, h4, h5, .h1, .h2, .h3, .h4, .h5 {
  font-weight: 700;
  letter-spacing: -0.01em;
}
a {
  text-decoration: none;
}
/* inline icons sit on the text baseline; flex contexts (rail/buttons) ignore this */
.bs-ico {
  vertical-align: -3px;
}

/* ============================================================ BUTTONS (pills) */
.btn {
  --bs-btn-font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  border-radius: var(--r-pill);
  white-space: nowrap;
}
.btn svg {
  flex: none;
}
/* comfortable tap targets on touch devices — full-size buttons and choice chips get 44px;
 * small utility buttons (btn-sm: add-address, status pills) stay compact so they don't
 * balloon next to their labels. */
@media (pointer: coarse) {
  .btn:not(.btn-sm),
  .chip {
    min-height: 44px;
  }
  .btn-sm {
    min-height: 38px;
  }
}
.btn:focus-visible {
  box-shadow: 0 0 0 3px rgba(15, 29, 14, 0.22);
}
.btn-primary {
  --bs-btn-bg: var(--ink);
  --bs-btn-border-color: var(--ink);
  --bs-btn-hover-bg: var(--ink-hover);
  --bs-btn-hover-border-color: var(--ink-hover);
  --bs-btn-active-bg: #000;
  --bs-btn-active-border-color: #000;
  --bs-btn-disabled-bg: var(--ink);
  --bs-btn-disabled-border-color: var(--ink);
}
.btn-success {
  --bs-btn-bg: var(--ok);
  --bs-btn-border-color: var(--ok);
  --bs-btn-hover-bg: #1a6d34;
  --bs-btn-hover-border-color: #1a6d34;
  --bs-btn-active-bg: #175f2d;
  --bs-btn-active-border-color: #175f2d;
  --bs-btn-disabled-bg: var(--ok);
  --bs-btn-disabled-border-color: var(--ok);
}
.btn-danger {
  --bs-btn-bg: var(--bad);
  --bs-btn-border-color: var(--bad);
  --bs-btn-hover-bg: #c30a0c;
  --bs-btn-hover-border-color: #c30a0c;
}
.btn-outline-primary,
.btn-outline-secondary {
  --bs-btn-color: var(--ink);
  --bs-btn-border-color: var(--border);
  --bs-btn-hover-bg: var(--surface);
  --bs-btn-hover-border-color: var(--faint);
  --bs-btn-hover-color: var(--ink);
  --bs-btn-active-bg: var(--surface);
  --bs-btn-active-border-color: var(--faint);
  --bs-btn-active-color: var(--ink);
}

/* ============================================================ CARDS / FORMS */
.card {
  /* Bootstrap sets --bs-card-bg: var(--bs-body-bg) on .card itself, so a :root override
   * won't reach it — pin white here so cards float on the off-white canvas. */
  --bs-card-bg: #fff;
  background-color: #fff;
  border-color: var(--border);
  border-radius: var(--r-card);
  box-shadow: var(--shadow-card);
}
/* Accordion: retint the active header + expand icon off Bootstrap's
 * blue. active-bg/color inherit the retinted primary-subtle/text-emphasis above; the icon
 * and focus ring are their own vars, so recolour them to ink here. */
.accordion {
  --bs-accordion-active-bg: var(--bs-primary-bg-subtle);
  --bs-accordion-active-color: var(--ink);
  --bs-accordion-btn-focus-box-shadow: 0 0 0 3px rgba(15, 29, 14, 0.12);
  --bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%230f1d0e'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");
  --bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%230f1d0e'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");
}

.form-control,
.form-select {
  border-radius: var(--r-input);
  border-color: var(--border);
}
.form-control:focus,
.form-select:focus {
  border-color: var(--ink);
  box-shadow: 0 0 0 3px rgba(15, 29, 14, 0.12);
}
/* Bootstrap compiles a literal blue into checked checkboxes/radios (not the --bs-primary
 * var), so recolour them to ink explicitly. Covers plain checks, radios and switches. */
.form-check-input:checked {
  background-color: var(--ink);
  border-color: var(--ink);
}
.form-check-input:focus {
  border-color: var(--ink);
  box-shadow: 0 0 0 3px rgba(15, 29, 14, 0.12);
}
/* uppercase micro-label for form fields (draft pattern) */
.field-label {
  display: block;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 6px;
}

/* ============================================================ STAT TILE (KPI) */
.stat-tile {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  padding: 13px 15px;
}
.stat-tile .stat-label {
  font-size: 12px;
  color: var(--muted);
}
.stat-tile .stat-value {
  font-size: 26px;
  font-weight: 700;
  color: var(--ink);
  margin-top: 4px;
  line-height: 1.1;
}
.stat-tile .stat-sub {
  font-size: 11px;
  color: var(--muted);
}

/* ============================================================ CHIP (choice pill) */
.chip {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  min-height: 40px;
  padding: 8px 14px;
  border-radius: var(--r-pill);
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--muted);
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  user-select: none;
  transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.chip:hover {
  border-color: var(--faint);
}
.chip.is-selected {
  background: var(--ink);
  border-color: var(--ink);
  color: #fff;
  font-weight: 700;
}
/* Hidden native control that the chip/seg <label> wraps for form semantics. It stays
 * keyboard-focusable and — crucially — must NOT be pointer-events:none: on a wrapped
 * (implicitly-associated) input that blocks Chromium's label→control click forwarding,
 * so tapping the pill text wouldn't toggle it. Kept 1px + clipped instead of hidden. */
.tap-input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
  margin: 0;
  clip: rect(0, 0, 0, 0);
}

/* ============================================================ SEGMENTED CONTROL */
.seg {
  display: flex;
  gap: 7px;
}
.seg-item {
  position: relative;
  flex: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 10px 8px;
  border-radius: var(--r-seg);
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--muted);
  font-size: 14px;
  font-weight: 500;
  text-align: center;
  cursor: pointer;
  user-select: none;
  transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.seg-item:hover {
  border-color: var(--faint);
}
.seg-item.is-selected {
  background: var(--ink);
  border-color: var(--ink);
  color: #fff;
  font-weight: 700;
}
/* scale variant: wraps, every step keeps a >=44px tap target */
.seg-scale {
  flex-wrap: wrap;
}
.seg-scale .seg-item {
  flex: 1 1 44px;
  min-width: 44px;
  font-weight: 700;
}

/* ============================================================ STATUS TILE (address) */
.status-tile {
  width: 34px;
  height: 34px;
  flex: none;
  border-radius: var(--r-tile);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  font-weight: 700;
}
.status-tile.st-ok {
  background: var(--ok-tint);
  color: var(--ok);
}
.status-tile.st-bad {
  background: var(--bad-tint);
  color: var(--bad);
}
.status-tile.st-partial {
  background: var(--warn-tint);
  color: var(--warn);
}
.status-tile.st-next {
  background: var(--ink);
  color: #fff;
}
.status-tile.st-pending {
  border: 1.5px solid var(--border);
  color: var(--faint);
}

/* ============================================================ SOFT BADGES */
.badge-soft {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  padding: 3px 9px;
  border-radius: var(--r-pill);
  white-space: nowrap;
}
.badge-soft-ok {
  color: var(--ok);
  background: var(--ok-tint);
}
.badge-soft-warn {
  color: var(--warn);
  background: var(--warn-tint);
}
.badge-soft-neutral {
  color: var(--muted);
  background: var(--border-soft);
}
.badge-soft-live {
  color: var(--ok);
  background: var(--ok-tint);
}
/* Plan-lifecycle badge variants (draft→neutral, test→warn, active→ok already above).
   planned reads as "scheduled/upcoming" (blue); done as "closed" (solid muted). */
.badge-soft-info {
  color: var(--blue);
  background: var(--blue-tint);
}
.badge-soft-done {
  color: #fff;
  background: var(--muted);
}
.badge-soft-live .status-dot {
  animation: bs-pulse 1.6s ease-in-out infinite;
}
@keyframes bs-pulse {
  50% {
    opacity: 0.35;
  }
}

/* ============================================================ PROGRESS STRIP + RING */
.progress-strip {
  height: 6px;
  border-radius: 4px;
  background: var(--border-soft);
  overflow: hidden;
}
.progress-strip > span {
  display: block;
  height: 100%;
  border-radius: 4px;
  background: var(--ok);
}
/* circular progress donut — set --ring-p (0..100) inline */
.ring {
  position: relative;
  width: var(--ring-size, 46px);
  height: var(--ring-size, 46px);
  border-radius: 50%;
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  background: conic-gradient(
    var(--ring-color, var(--ok)) calc(var(--ring-p, 0) * 1%),
    var(--border-soft) 0
  );
}
.ring::after {
  content: "";
  position: absolute;
  inset: var(--ring-thick, 5px);
  background: var(--card);
  border-radius: 50%;
}
.ring .ring-label {
  position: relative;
  z-index: 1;
  font-size: 12px;
  font-weight: 700;
  color: var(--ink);
  line-height: 1;
}

/* ============================================================ STICKY BARS + DOTS */
.sticky-head {
  position: sticky;
  top: 0;
  z-index: 1020;
  background: var(--page);
  border-bottom: 1px solid var(--border);
}
.sticky-actions {
  position: sticky;
  bottom: 0;
  z-index: 1020;
  background: var(--card);
  border-top: 1px solid var(--border);
  box-shadow: var(--shadow-float);
}
.status-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex: none;
  display: inline-block;
}
.status-dot.on {
  background: var(--ok);
}
.status-dot.off {
  background: var(--warn);
}
.map-ctrl {
  width: 36px;
  height: 36px;
  border-radius: 9px;
  background: var(--card);
  border: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ink);
  box-shadow: var(--shadow-ctrl);
}

/* ============================================================ SIDE RAIL / DRAWER
 * topbar.js renders (for a logged-in user) a mobile top bar with a hamburger, the
 * .app-rail side menu, and a .rail-backdrop. At >=lg the rail is a fixed left column
 * and body content is inset. Below lg the rail is an off-canvas drawer that slides in
 * when body.rail-open is set (hamburger), dimming the page with the backdrop.
 */
.app-rail,
.app-topbar,
.rail-backdrop {
  display: none;
}

/* --- mobile top bar (hamburger) --- */
@media (max-width: 991.98px) {
  body.has-rail .app-topbar {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    height: 52px;
    padding: 0 0.7rem;
    /* fixed, not sticky: #topbar is only as tall as this bar (the rail/backdrop are
     * position:fixed, out of flow), so a sticky bar would scroll away with #topbar and
     * leave a gap above the page's own sticky header. Fixed pins it to the viewport. */
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 1035;
    background: var(--card);
    border-bottom: 1px solid var(--border);
  }
  /* the fixed bar is out of flow — inset the page so content starts below it */
  body.has-rail {
    padding-top: 52px;
  }
}
.app-burger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  flex: none;
  border: none;
  background: transparent;
  color: var(--ink);
  border-radius: 9px;
}
.app-burger:hover {
  background: var(--border-soft);
}
.app-topbar-brand {
  display: flex;
  align-items: center;
  gap: 9px;
  font-weight: 700;
  color: var(--ink);
}

/* --- rail: fixed column (desktop) --- */
@media (min-width: 992px) {
  body.has-rail .app-rail {
    display: flex;
    flex-direction: column;
    gap: 3px;
    position: fixed;
    left: 0;
    top: 0;
    bottom: 0;
    width: var(--rail-w);
    padding: 18px 14px;
    background: var(--surface);
    border-right: 1px solid var(--border);
    overflow: auto;
    z-index: 1030;
    transition: width 0.2s ease, padding 0.2s ease;
  }
  body.has-rail {
    padding-left: var(--rail-w);
    transition: padding-left 0.2s ease;
  }

  /* collapsed: an icon-only strip. Text labels hide, icons center, the toggle flips. */
  body.has-rail.rail-collapsed .app-rail {
    width: var(--rail-w-collapsed);
    padding-left: 8px;
    padding-right: 8px;
  }
  body.has-rail.rail-collapsed {
    padding-left: var(--rail-w-collapsed);
  }
  body.rail-collapsed .app-rail .rail-brand-name,
  body.rail-collapsed .app-rail .rail-link span,
  body.rail-collapsed .app-rail .rail-group-label,
  body.rail-collapsed .app-rail .rail-user > div,
  body.rail-collapsed .app-rail .rail-logout span {
    display: none;
  }
  body.rail-collapsed .app-rail .rail-brand-link {
    display: none;
  }
  body.rail-collapsed .app-rail .rail-brand {
    justify-content: center;
    padding: 0 0 18px;
  }
  body.rail-collapsed .app-rail .rail-collapse-btn {
    transform: rotate(180deg);
  }
  body.rail-collapsed .app-rail .rail-link,
  body.rail-collapsed .app-rail .rail-logout,
  body.rail-collapsed .app-rail .rail-user {
    justify-content: center;
    padding-left: 0;
    padding-right: 0;
  }
}

/* --- rail: off-canvas drawer (mobile) --- */
@media (max-width: 991.98px) {
  body.has-rail .app-rail {
    display: flex;
    flex-direction: column;
    gap: 3px;
    position: fixed;
    left: 0;
    top: 0;
    bottom: 0;
    width: min(82vw, 300px);
    padding: 18px 14px;
    background: var(--surface);
    border-right: 1px solid var(--border);
    overflow: auto;
    z-index: 1045;
    transform: translateX(-100%);
    transition: transform 0.22s ease;
  }
  body.has-rail.rail-open .app-rail {
    transform: translateX(0);
    box-shadow: 2px 0 24px rgba(0, 0, 0, 0.18);
  }
  body.has-rail .rail-backdrop {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 1044;
    background: rgba(0, 0, 0, 0.42);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s ease;
  }
  body.has-rail.rail-open .rail-backdrop {
    opacity: 1;
    pointer-events: auto;
  }
  body.has-rail.rail-open {
    overflow: hidden;
  }
  /* page-level sticky headers sit below the hamburger bar */
  body.has-rail .sticky-head {
    top: 52px;
  }
}

.app-rail .rail-brand {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 9px;
  padding: 0 6px 18px;
}
.app-rail .rail-brand-link {
  display: flex;
  align-items: center;
  gap: 9px;
  min-width: 0;
}
.app-rail .rail-collapse-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  flex: none;
  border: none;
  border-radius: 8px;
  background: transparent;
  color: var(--muted);
  transition: transform 0.2s ease, background 0.15s ease, color 0.15s ease;
}
.app-rail .rail-collapse-btn:hover {
  background: var(--border-soft);
  color: var(--ink);
}
/* the collapse toggle is a desktop-only affordance; the mobile drawer hides it */
@media (max-width: 991.98px) {
  .app-rail .rail-collapse-btn {
    display: none;
  }
}
.app-rail .rail-logo,
.app-topbar .rail-logo {
  width: 26px;
  height: 26px;
  border-radius: 7px;
  background: var(--ink);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 13px;
  flex: none;
}
.app-rail .rail-link {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 10px;
  border-radius: 9px;
  font-size: 13px;
  font-weight: 500;
  color: var(--muted);
}
.app-rail .rail-link:hover {
  background: var(--border-soft);
  color: var(--ink);
}
.app-rail .rail-link.active {
  background: var(--ink);
  color: #fff;
  font-weight: 700;
}
.app-rail .rail-group-label {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--faint);
  padding: 14px 10px 4px;
}
/* bottom section: current user + a clearly-separated, red logout */
.app-rail .rail-foot {
  margin-top: auto;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}
.app-rail .rail-user {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 2px 6px 10px;
  /* It's an <a> to the profile — strip the link chrome so it still reads as the footer
     identity block, not a nav item. */
  text-decoration: none;
  color: inherit;
  border-radius: var(--r-sm, 6px);
}
.app-rail .rail-user:hover {
  background: var(--border-soft);
}
.app-rail .rail-avatar {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--border);
  color: var(--muted);
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  font-size: 12px;
  font-weight: 700;
}
.app-rail .rail-logout {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 9px 10px;
  border: none;
  border-radius: 9px;
  background: transparent;
  color: var(--bad);
  font-size: 13px;
  font-weight: 600;
  text-align: left;
}
.app-rail .rail-logout:hover {
  background: var(--bad-tint);
}

/* page header row inside the main content area */
.page-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}
.page-head .page-title {
  font-size: 20px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--ink);
}

/* ── Onboarding coach-mark tour (tour.js) ─────────────────────────────────────
   A dim overlay spotlights one element at a time; a bubble carries the copy + nav.
   The dark is painted by the spotlight's huge box-shadow, so the target shows through
   its transparent "hole"; a separate transparent backdrop swallows clicks during the
   tour. When a step has no visible target the spotlight is hidden and the bubble centers. */
.tour-overlay {
  position: fixed;
  inset: 0;
  z-index: 3000;
}
.tour-backdrop {
  position: absolute;
  inset: 0;
  z-index: 1;
}
.tour-spotlight {
  position: fixed;
  z-index: 2;
  border-radius: 10px;
  box-shadow: 0 0 0 9999px rgba(15, 29, 14, 0.55);
  pointer-events: none;
  /* The spotlight snaps to its target — no position/size transition. A transition here lags a
     target that resizes (an accordion opening) or a smooth-scroll that restarts it every frame,
     leaving the cut-out stuck on the previous step's element. */
}
.tour-spotlight[hidden] {
  display: none;
}
/* No spotlight (centered step): the backdrop itself carries the dim. */
.tour-overlay:has(.tour-spotlight[hidden]) .tour-backdrop {
  background: rgba(15, 29, 14, 0.55);
}
/* Modal step: a Bootstrap modal is open beneath the overlay and provides its own dim, so the
   tour backdrop stays transparent (the modal shows through bright). It still catches clicks so
   the modal is display-only while the tour drives it; the bubble sits above both. */
.tour-overlay.tour-modal-step .tour-backdrop {
  background: transparent;
}
.tour-bubble {
  position: fixed;
  z-index: 3;
  width: min(340px, calc(100vw - 24px));
  background: var(--card);
  color: var(--ink);
  border-radius: var(--r-card);
  box-shadow: 0 12px 32px rgba(15, 29, 14, 0.28);
  padding: 16px 18px 14px;
}
.tour-bubble.tour-centered {
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
.tour-close {
  position: absolute;
  top: 6px;
  right: 10px;
  border: 0;
  background: none;
  font-size: 22px;
  line-height: 1;
  color: var(--faint);
  cursor: pointer;
}
.tour-close:hover {
  color: var(--muted);
}
.tour-step-count {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--faint);
  margin-bottom: 4px;
}
.tour-title {
  font-size: 16px;
  font-weight: 700;
  color: var(--ink);
  margin: 0 0 6px;
}
.tour-body {
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--muted);
  margin-bottom: 12px;
}
.tour-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.tour-nav-right {
  display: flex;
  gap: 8px;
  margin-left: auto;
}
.tour-skip {
  padding-left: 0;
  color: var(--muted);
}
.tour-cta {
  margin-bottom: 10px;
}

/* ============================================================ PUBLIC-PAGE BRIDGE
 * The public pages (index, voters, map) moved into the app shell. Their content
 * stylesheets (reports.css, map.css, the voters table) predate app.css and name their
 * design tokens the old public.css way (--text, --panel, --accent, …). Alias those onto
 * the app palette so they inherit the app's colours with no per-rule rewrite. Only the
 * names app.css does NOT already define are aliased (--border/--muted stay app's).
 */
:root {
  --bg: var(--page);
  --panel: var(--card);
  --text: var(--ink);
  /* `--accent` je NOSILAC RADNJE, ne boja: dugmad, linkovi i izabran red na javnim stranama
     idu kroz njega. Zato je to mastilo, isto kao `.btn-primary` i aktivna stavka u levoj
     traci — javne strane su u istoj ljusci kao ostatak sajta i ne smeju da imaju svoju
     plavu dugmad. `--accent-soft` je isto što i lebdenje u traci (`--border-soft`).
     Plava (`--blue`/`--blue-tint`) ostaje samo za obaveštenja (`badge-soft-info`,
     `alert-info`, `.list-notice.info`) — tamo znači „da se zna”, a ne „klikni”. */
  --accent: var(--ink);
  --accent-hover: var(--ink-hover);
  --accent-soft: var(--border-soft);
  --row-alt: var(--surface);
  --disabled: var(--faint);
}
