/* Digital Citizen portal — official design system (light "civic paper" look).
   Tokens reproduced verbatim from the DC design pack: colors, type, radius,
   elevation, spacing, motion. Plain CSS, zero dependencies, self-hosted fonts.
   No glassmorphism, no glow, no gradient orbs, no backdrop-filter. */

/* ---------------------------------------------------------------- fonts */
@font-face {
  font-family: "Manrope";
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url("/assets/fonts/Manrope-variable.woff2") format("woff2");
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url("/assets/fonts/JetBrainsMono-variable.woff2") format("woff2");
}

/* ---------------------------------------------------------------- tokens */
:root {
  /* Edge gutters. viewport-fit=cover lets the WebView paint edge-to-edge (so the
     navy header can sit under the status bar), which means EVERY horizontal inset
     must add the device's safe-area insets or content slides under the rounded
     corners on device — invisible in a desktop browser, obvious on an iPhone. */
  --dc-gutter: 20px;
  --dc-gutter-left: calc(var(--dc-gutter) + env(safe-area-inset-left, 0px));
  --dc-gutter-right: calc(var(--dc-gutter) + env(safe-area-inset-right, 0px));
  /* Explicit negatives. Do NOT write calc(-1 * var(--dc-gutter-left)) instead: that nests a
     calc() containing env() inside another calc(), which WKWebView does not resolve — the
     declaration is dropped while the matching padding still applies, leaving a bleed row 40px
     wider than its container. It renders correctly in every desktop browser and blows the
     layout out only in the app, which is the worst way to find a bug. */
  --dc-gutter-left-neg: calc(-1 * var(--dc-gutter) - env(safe-area-inset-left, 0px));
  --dc-gutter-right-neg: calc(-1 * var(--dc-gutter) - env(safe-area-inset-right, 0px));

  /* base ramps */
  --dc-navy-900: #0A2450;
  --dc-navy-700: #123B7A;
  --dc-navy-500: #2E5CA8;
  --dc-navy-300: #8FA7CD;
  --dc-navy-100: #E4EBF6;
  --dc-teal-600: #009E89;
  --dc-teal-500: #00C2A8;
  --dc-teal-300: #7FE0D3;
  --dc-teal-100: #D9F7F1;
  --dc-orange-600: #E03616;
  --dc-orange-500: #FF4D2E;
  --dc-orange-100: #FFE6E0;
  --dc-amber-600: #E09400;
  --dc-amber-500: #FFB020;
  --dc-amber-100: #FFF1D6;
  --dc-paper: #FFF7F2;
  --dc-white: #FFFFFF;
  --dc-ink: #0B0F19;
  --dc-ink-muted: #6B7280;
  --dc-border: #E9E2DC;

  /* semantic */
  --dc-bg-page: var(--dc-paper);
  --dc-bg-header: var(--dc-navy-700);
  --dc-surface-card: var(--dc-white);
  --dc-surface-sunken: #F6EFEA;
  --dc-surface-inverse: var(--dc-navy-900);
  --dc-text-heading: var(--dc-navy-700);
  --dc-text-body: var(--dc-ink);
  --dc-text-muted: var(--dc-ink-muted);
  --dc-text-on-navy: var(--dc-white);
  --dc-text-on-navy-muted: #B9C7DF;
  --dc-action-primary: var(--dc-teal-500);
  --dc-action-primary-hover: var(--dc-teal-600);
  --dc-on-action-primary: #062E28;
  --dc-action-secondary: var(--dc-navy-700);
  --dc-action-secondary-hover: var(--dc-navy-900);
  --dc-focus-ring: var(--dc-navy-500);
  --dc-state-alert: var(--dc-orange-500);
  --dc-state-alert-bg: var(--dc-orange-100);
  --dc-state-progress: var(--dc-amber-500);
  --dc-state-progress-bg: var(--dc-amber-100);
  --dc-state-live: var(--dc-teal-500);
  --dc-state-live-bg: var(--dc-teal-100);
  --dc-state-neutral: var(--dc-navy-500);
  --dc-state-neutral-bg: var(--dc-navy-100);
  --dc-amber-ink: #8A5A00;
  /* Text-safe shades (17 Oct audit, M32, WCAG 1.4.3): the -600 teal and orange read at 3.0–4.5:1 on
     their own tints and on white, under the 4.5:1 text needs. These are at least 5:1 on every
     surface they sit on, and white on --dc-orange-ink is 6.4:1. A control's edge, a switch track
     and the focus ring need 3:1 against what is behind them (WCAG 1.4.11): --dc-border-control
     is 3.4–3.9:1 on the page, card and sunken grounds. */
  --dc-teal-ink: #00745F;
  --dc-orange-ink: #B42B10;
  --dc-orange-ink-hover: #962410;
  --dc-border-control: #8A7F76;
  --dc-border-subtle: var(--dc-border);
  --dc-border-strong: #D6CBC2;
  --dc-border-on-navy: rgba(255,255,255,.18);

  /* type */
  --dc-font-core: "Manrope", system-ui, -apple-system, "Segoe UI", sans-serif;
  --dc-font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  --dc-size-title-1: 34px;
  --dc-size-title-2: 26px;
  --dc-size-headline: 20px;
  --dc-size-body-lg: 17px;
  --dc-size-body: 15px;
  --dc-size-label: 13px;
  --dc-size-caption: 12px;
  --dc-size-micro: 12px; /* P40: nothing a resident must read is smaller than 12 px */

  /* radius */
  --dc-radius-sm: 10px;
  --dc-radius-md: 12px;
  --dc-radius-lg: 16px;
  --dc-radius-pill: 999px;
  --dc-radius-tile: 20px;

  /* elevation — navy-tinted, low contrast */
  --dc-shadow-1: 0 1px 2px rgba(10,36,80,.06);
  --dc-shadow-2: 0 2px 8px rgba(10,36,80,.08);
  --dc-shadow-3: 0 8px 24px rgba(10,36,80,.12);

  /* spacing / motion */
  --dc-section-gap: 28px;
  --dc-card-padding: 16px;
  --dc-card-gap: 12px;
  --dc-ease: cubic-bezier(.2,.6,.2,1);
  --dc-fast: 140ms;
  --dc-instant: 90ms;

  /* Previously used but never declared. A var() that resolves to nothing makes the WHOLE
     declaration invalid, not just that value — so `font: var(--dc-weight-bold) …` was
     dropping the entire font shorthand on .signin-tag (the sign-in gate) and .news-more a,
     and `border-radius: var(--dc-radius-card)` was leaving .wo-muni-rows square. Values
     chosen to match the siblings that hardcode them: 700 weight, .2em eyebrow tracking
     (styles.css:232), 16px card radius. */
  --dc-weight-bold: 700;
  --dc-weight-medium: 500;
  --dc-tracking-eyebrow: 0.2em;
  --dc-radius-card: var(--dc-radius-lg);
  --dc-text-link: var(--dc-navy-700);
  --dc-text-link-hover: var(--dc-ink);
}

/* ---------------------------------------------------------------- base */
* { box-sizing: border-box; margin: 0; padding: 0; }
html { -webkit-text-size-adjust: 100%; }
body {
  background: var(--dc-bg-page);
  color: var(--dc-text-body);
  font: 400 var(--dc-size-body)/1.45 var(--dc-font-core);
  /* On iOS, swiping a nested horizontal scroller past its end chains the gesture
     to the page and pans the whole layout sideways — the shell gutters go with it,
     so content appears to bleed off both edges. Refusing the pan here (and
     containing it at each scroller) keeps the gutters where they were painted. */
  overscroll-behavior-x: none;
  overflow-x: clip;
}
button { font: inherit; color: inherit; }
.hidden { display: none !important; }
:focus-visible { outline: 3px solid var(--dc-focus-ring); outline-offset: 2px; }
.icon { display: inline-block; width: 24px; height: 24px; vertical-align: middle; }
.icon svg { display: block; width: 100%; height: 100%; }
.mono { font-family: var(--dc-font-mono); letter-spacing: -0.01em; }

/* ---------------------------------------------------------------- loading bar */
.loadbar { position: fixed; top: 0; left: 0; right: 0; height: 3px; z-index: 50; overflow: hidden; background: transparent; }
.loadbar-fill { height: 100%; width: 40%; background: var(--dc-teal-500); border-radius: var(--dc-radius-pill); animation: loadslide 1.1s var(--dc-ease) infinite; }
@keyframes loadslide { from { transform: translateX(-100%); } to { transform: translateX(350%); } }

/* ---------------------------------------------------------------- header band (navy) */
/* M32 (WCAG 2.4.7, 1.4.11): on the navy header the focus ring is white (10.9:1); the navy ring
   was 1.66:1 there. */
header.site :focus-visible { outline-color: var(--dc-white); }
header.site {
  background: var(--dc-bg-header);
  color: var(--dc-text-on-navy);
  /* Safe area: keep the lockup clear of notches/Dynamic Island in the wrapped app. */
  padding: calc(16px + env(safe-area-inset-top, 0px)) var(--dc-gutter-right) 24px var(--dc-gutter-left);
}
.header-inner {
  max-width: 1100px; margin: 0 auto;
  display: flex; flex-wrap: wrap; align-items: flex-start; gap: 20px;
}
.header-brandrow { flex: 1 1 420px; min-width: 0; display: flex; flex-direction: column; gap: 18px; }
.brand-lockup { height: 34px; width: auto; display: block; }
.greeting h1 {
  font: 800 var(--dc-size-title-1)/1.2 var(--dc-font-core);
  letter-spacing: -0.02em; color: var(--dc-text-on-navy);
}
.greeting .sub { font: 500 var(--dc-size-body)/1.45 var(--dc-font-core); color: var(--dc-text-on-navy-muted); margin-top: 4px; }
.header-side { display: flex; flex-direction: column; align-items: flex-end; gap: 12px; margin-left: auto; }
/* Header action row: temperature left · SOS centred · session action right. */
/* Header action row: temperature left · SOS centred · session action right.
   A 3-column grid (not auto margins) so the SOS sits on the TRUE centre line
   regardless of how wide the side items are. */
.who.header-row {
  /* minmax(0,·) on the side tracks, not 1fr. A bare 1fr is minmax(auto,1fr), so
     the wider side (bell + Log out) claims extra track and drags the SOS off the
     page centre line. Equal side tracks put it back on true centre; the tighter
     phone paddings below keep both side groups inside their share. */
  display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center; gap: 10px; width: 100%;
}
.who.header-row > :first-child { justify-self: start; }
.who.header-row > .sos-chip { justify-self: center; }
.who.header-row > :last-child { justify-self: end; }
.who { display: flex; align-items: center; gap: 12px; }
.who .email { font: 500 var(--dc-size-caption)/1 var(--dc-font-core); color: var(--dc-text-on-navy-muted); }

/* weather card inside the header band */
.weather-card {
  background: var(--dc-surface-inverse);
  border: 1px solid var(--dc-border-on-navy);
  border-radius: var(--dc-radius-lg);
  padding: 14px 16px;
  color: var(--dc-text-on-navy);
  min-width: 250px;
}
.weather-now { display: flex; align-items: center; gap: 12px; }
.weather-now .w-icon { color: var(--dc-amber-500); }
.weather-now .w-icon .icon { width: 32px; height: 32px; }
.weather-temp { font: 700 30px/1 var(--dc-font-mono); letter-spacing: -0.01em; }
.weather-cond { display: flex; flex-direction: column; gap: 2px; }
.weather-cond .c-label { font: 700 var(--dc-size-label)/1.2 var(--dc-font-core); }
.weather-cond .c-meta { font: 500 var(--dc-size-caption)/1.2 var(--dc-font-core); color: var(--dc-text-on-navy-muted); }
.weather-days { display: flex; gap: 8px; margin-top: 12px; }
.weather-day {
  flex: 1; display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: 8px 4px; border-radius: var(--dc-radius-sm);
  background: rgba(255,255,255,.06);
  font: 500 var(--dc-size-caption)/1.2 var(--dc-font-core); color: var(--dc-text-on-navy-muted);
}
.weather-day .d-icon { color: var(--dc-text-on-navy); }
.weather-day .d-icon .icon { width: 18px; height: 18px; }
.weather-day .d-max { font: 700 var(--dc-size-caption)/1.2 var(--dc-font-mono); color: var(--dc-text-on-navy); }
.weather-empty { font: 500 var(--dc-size-caption)/1.4 var(--dc-font-core); color: var(--dc-text-on-navy-muted); }

/* ---------------------------------------------------------------- layout */
main { display: block; }
.shell {
  max-width: 1100px; margin: 0 auto;
  padding: 24px 20px 48px;
  display: flex; flex-direction: column; gap: var(--dc-section-gap);
}
@media (min-width: 720px) {
  .shell { padding: 28px calc(32px + env(safe-area-inset-right, 0px)) 64px calc(32px + env(safe-area-inset-left, 0px)); }
}

.section-title {
  display: flex; align-items: center; gap: 10px;
  margin-bottom: 12px;
}
.section-title .eyebrow {
  font: 700 13px/1.2 var(--dc-font-core);
  letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--dc-text-heading);
}
.section-title .spacer { flex: 1; }

/* ---------------------------------------------------------------- cards */
.card {
  background: var(--dc-surface-card);
  border: 1px solid var(--dc-border-subtle);
  border-radius: var(--dc-radius-lg);
  box-shadow: var(--dc-shadow-2);
  padding: var(--dc-card-padding);
}
.card.flush { padding: 0; overflow: hidden; }
.card-head { display: flex; align-items: center; gap: 10px; padding-bottom: 10px; }
.card.flush .card-head { padding: var(--dc-card-padding) var(--dc-card-padding) 4px; }
.card-head h2 { font: 700 var(--dc-size-headline)/1.2 var(--dc-font-core); color: var(--dc-text-heading); flex: 1; min-width: 0; }
.hint { font: 500 var(--dc-size-caption)/1.45 var(--dc-font-core); color: var(--dc-text-muted); }
.card > .hint { margin-bottom: 10px; }
.card.flush > .hint { margin: 0; padding: 0 var(--dc-card-padding) 10px; }
.dimmed { opacity: 0.55; }
.empty { font: 500 var(--dc-size-caption)/1.45 var(--dc-font-core); color: var(--dc-text-muted); padding: 10px 0; }
.card.flush .empty { padding: 12px var(--dc-card-padding); }

/* navy inverse card (Near you) */
.card-navy {
  background: var(--dc-navy-700);
  color: var(--dc-text-on-navy);
  border: none;
  border-radius: var(--dc-radius-lg);
  box-shadow: var(--dc-shadow-2);
  padding: var(--dc-card-padding);
  display: flex; align-items: flex-start; gap: 12px;
}
.card-navy .n-icon { color: var(--dc-amber-500); flex: none; margin-top: 1px; }
.card-navy .n-icon .icon { width: 20px; height: 20px; }
.card-navy .n-body { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.card-navy .n-title { font: 700 var(--dc-size-body)/1.3 var(--dc-font-core); }
.card-navy .n-caption { font: 500 var(--dc-size-caption)/1.45 var(--dc-font-core); color: var(--dc-text-on-navy-muted); }

/* ---------------------------------------------------------------- buttons */
.btn, button.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: 44px; padding: 0 18px;
  font: 700 var(--dc-size-body)/1 var(--dc-font-core); letter-spacing: -0.01em;
  border: 2px solid transparent; border-radius: var(--dc-radius-pill);
  cursor: pointer;
  background: var(--dc-action-primary); color: var(--dc-on-action-primary);
  transition: background-color var(--dc-fast) var(--dc-ease), color var(--dc-fast) var(--dc-ease), border-color var(--dc-fast) var(--dc-ease), transform var(--dc-instant) var(--dc-ease);
  -webkit-tap-highlight-color: transparent;
}
.btn:hover:not(:disabled) { background: var(--dc-action-primary-hover); }
.btn:active:not(:disabled) { transform: scale(.97); }
.btn:disabled { opacity: .4; cursor: not-allowed; }
.btn.secondary { background: var(--dc-action-secondary); color: var(--dc-white); }
.btn.secondary:hover:not(:disabled) { background: var(--dc-action-secondary-hover); }
.btn.outline { background: transparent; color: var(--dc-navy-700); border-color: var(--dc-navy-700); }
.btn.outline:hover:not(:disabled) { background: var(--dc-navy-100); }
.btn.ghost { background: transparent; color: var(--dc-navy-700); }
.btn.ghost:hover:not(:disabled) { background: var(--dc-navy-100); }
.btn.ghost-navy { background: transparent; color: var(--dc-white); border-color: var(--dc-border-on-navy); }
.btn.ghost-navy:hover:not(:disabled) { background: rgba(255,255,255,.1); }
.btn.danger { background: var(--dc-orange-ink); color: var(--dc-white); }
.btn.danger:hover:not(:disabled) { background: var(--dc-orange-ink-hover); }
.btn.small { height: 36px; padding: 0 14px; font-size: var(--dc-size-label); }
.actions { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-top: 12px; }

.link-action {
  background: none; border: none; padding: 0; cursor: pointer;
  font: 700 var(--dc-size-label)/1 var(--dc-font-core);
  color: var(--dc-navy-700); text-decoration: underline; text-underline-offset: 3px;
}

/* ---------------------------------------------------------------- forms */
form label { display: block; font: 600 var(--dc-size-label)/1.3 var(--dc-font-core); color: var(--dc-text-heading); margin-top: 12px; }
form label:first-child { margin-top: 0; }
input, textarea, select {
  display: block; width: 100%; margin-top: 6px;
  padding: 10px 12px;
  font: 500 var(--dc-size-body)/1.4 var(--dc-font-core);
  color: var(--dc-text-body);
  background: var(--dc-white);
  border: 1px solid var(--dc-border-control);
  border-radius: var(--dc-radius-md);
}
input.mono { font-family: var(--dc-font-mono); letter-spacing: -0.01em; }
input:focus, textarea:focus, select:focus { outline: 3px solid var(--dc-focus-ring); outline-offset: 0; border-color: var(--dc-navy-500); }
.msg { font: 600 var(--dc-size-label)/1.4 var(--dc-font-core); margin-top: 10px; color: var(--dc-text-muted); }
.msg.ok { color: var(--dc-teal-ink); }
.msg.error { color: var(--dc-orange-ink); }
.meta { font: 500 var(--dc-size-caption)/1.4 var(--dc-font-core); color: var(--dc-text-muted); }

/* segmented control (composer type selector) */
.segmented {
  display: flex; gap: 4px; padding: 4px;
  background: var(--dc-surface-sunken);
  border-radius: var(--dc-radius-md);
}
.segmented button {
  flex: 1; height: 38px; padding: 0 10px;
  font: 700 var(--dc-size-label)/1.1 var(--dc-font-core);
  color: var(--dc-text-muted);
  background: transparent; border: none; border-radius: var(--dc-radius-sm);
  cursor: pointer;
  transition: background-color var(--dc-fast) var(--dc-ease), color var(--dc-fast) var(--dc-ease);
}
.segmented button.active { background: var(--dc-white); color: var(--dc-text-heading); box-shadow: var(--dc-shadow-1); }

/* ---------------------------------------------------------------- service tiles */
.tile-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--dc-card-gap); }
@media (min-width: 860px) { .tile-grid { grid-template-columns: repeat(4, 1fr); } }
.service-tile {
  position: relative;
  display: flex; flex-direction: column; align-items: flex-start; gap: 12px;
  min-height: 108px; padding: 16px; text-align: left;
  background: var(--dc-surface-card);
  border: 1px solid var(--dc-border-subtle);
  border-radius: var(--dc-radius-tile);
  box-shadow: var(--dc-shadow-1);
  cursor: pointer;
  transition: box-shadow 200ms var(--dc-ease), transform var(--dc-instant) var(--dc-ease);
  -webkit-tap-highlight-color: transparent;
}
.service-tile:hover { box-shadow: var(--dc-shadow-2); }
.service-tile:active { transform: scale(.97); }
.tone-chip {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 44px; height: 44px; border-radius: var(--dc-radius-md);
}
.tone-chip .icon { width: 22px; height: 22px; }
.tone-chip.sm { width: 36px; height: 36px; border-radius: var(--dc-radius-sm); }
.tone-chip.sm .icon { width: 18px; height: 18px; }
.tone-navy { background: var(--dc-navy-100); color: var(--dc-navy-700); }
.tone-teal { background: var(--dc-teal-100); color: var(--dc-teal-600); }
.tone-orange { background: var(--dc-orange-100); color: var(--dc-orange-600); }
.tone-amber { background: var(--dc-amber-100); color: var(--dc-amber-600); }
.service-tile .t-label { font: 700 var(--dc-size-body)/1.2 var(--dc-font-core); color: var(--dc-text-heading); }
.service-tile .t-sub { font: 500 var(--dc-size-caption)/1.3 var(--dc-font-core); color: var(--dc-text-muted); margin-top: 2px; }
.service-tile .t-badge {
  position: absolute; top: 12px; right: 12px;
  display: inline-flex; align-items: center; height: 22px; padding: 0 9px;
  background: var(--dc-state-alert); color: var(--dc-white);
  font: 700 var(--dc-size-micro)/1 var(--dc-font-core); letter-spacing: .06em;
  border-radius: var(--dc-radius-pill);
}

/* ---------------------------------------------------------------- banners */
.banners { display: flex; flex-direction: column; gap: 10px; }
.banners:empty { display: none; }
.banner {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 16px; border-radius: var(--dc-radius-md);
}
/* "Show N more alerts" — reveals the banners held back below the fold cap. */
.banner-more {
  display: block; width: 100%; padding: 10px 12px; cursor: pointer;
  background: transparent; border: 1px dashed var(--dc-border-strong);
  border-radius: var(--dc-radius-md);
  font: 700 var(--dc-size-label)/1 var(--dc-font-core); color: var(--dc-text-heading);
}
.banner-more:hover { background: var(--dc-surface-sunken); }
.banner .b-icon { flex: none; margin-top: 1px; }
.banner .b-icon .icon { width: 20px; height: 20px; }
.banner .b-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.banner .b-title { font: 700 var(--dc-size-body)/1.3 var(--dc-font-core); }
.banner .b-text { font: 400 var(--dc-size-body)/1.45 var(--dc-font-core); color: var(--dc-text-body); }
.banner .b-action { align-self: flex-start; margin-top: 4px; background: none; border: none; padding: 0; font: 700 var(--dc-size-label)/1 var(--dc-font-core); color: inherit; text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }
.banner .dismiss { flex: none; background: none; border: none; padding: 0; color: inherit; opacity: .6; cursor: pointer; }
.banner .dismiss .icon { width: 18px; height: 18px; }
.banner .dismiss:hover { opacity: 1; }
.banner-alert { background: var(--dc-state-alert-bg); color: var(--dc-orange-ink); }
.banner-progress { background: var(--dc-state-progress-bg); color: var(--dc-amber-ink); }
.banner-live { background: var(--dc-state-live-bg); color: var(--dc-teal-ink); }
.banner-neutral { background: var(--dc-navy-100); color: var(--dc-navy-700); }

/* ---------------------------------------------------------------- status pills */
.pill {
  display: inline-flex; align-items: center; gap: 6px; height: 26px; padding: 0 10px;
  border-radius: var(--dc-radius-pill);
  font: 700 var(--dc-size-caption)/1 var(--dc-font-core); white-space: nowrap;
  background: var(--dc-state-neutral-bg); color: var(--dc-navy-700);
}
.pill .icon { width: 13px; height: 13px; }
.pill-neutral { background: var(--dc-state-neutral-bg); color: var(--dc-navy-700); }
.pill-amber { background: var(--dc-state-progress-bg); color: var(--dc-amber-ink); }
.pill-navy { background: var(--dc-navy-700); color: var(--dc-white); }
.pill-teal { background: var(--dc-state-live-bg); color: var(--dc-teal-ink); }
.pill-orange { background: var(--dc-state-alert-bg); color: var(--dc-orange-ink); }
.pill-on-navy { background: rgba(255,255,255,.12); color: var(--dc-white); }

/* ---------------------------------------------------------------- list rows */
.rows { list-style: none; }
.list-row {
  display: flex; align-items: center; gap: 12px;
  min-height: 60px; padding: 12px 16px;
  border-bottom: 1px solid var(--dc-border-subtle);
  transition: background-color var(--dc-fast) var(--dc-ease);
}
.rows > li:last-child > .list-row { border-bottom: none; }
/* Label-and-value rows (indigent review, status and checklist; staff clusters). The markup always
   assumed a flex row (the member editor sets flex:1 on its child), but no rule existed, so
   "Applied2026-10-02" ran together and buttons sat against their labels. */
.rows > li.row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 10px 0; border-bottom: 1px solid var(--dc-border-subtle);
}
.rows > li.row:last-child { border-bottom: none; }
.rows > li.row > span { flex: 1; min-width: 0; }
.rows > li.row > b { flex: none; max-width: 60%; text-align: right; overflow-wrap: break-word; }
.rows > li.row > button { flex: none; }
.list-row.clickable { cursor: pointer; }
/* M33 (WCAG 2.1.1): rows that open are links or buttons, so the keyboard reaches them. They keep
   the row's look; the focus ring sits inside the row, where no container clips it. */
a.list-row { color: inherit; text-decoration: none; }
button.list-row { width: 100%; text-align: left; background: none; border: 0; border-bottom: 1px solid var(--dc-border-subtle); font: inherit; color: inherit; }
.list-row:focus-visible { outline-offset: -3px; }
a.account-fact { color: inherit; text-decoration: none; }
.rows > li.row > button.moc-row { flex: 1; min-width: 0; display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 0; border: 0; background: none; font: inherit; color: inherit; text-align: left; cursor: pointer; }
.moc-row .moc-row-main { flex: 1; min-width: 0; }
.moc-row .hint { display: block; }
/* M35: each person in the household editor is a group with its own legend. */
.ind-person { flex: 1; min-width: 0; margin: 0; padding: 0; border: 0; }
.ind-person legend { padding: 0; font: 700 var(--dc-size-label)/1.3 var(--dc-font-core); color: var(--dc-text-heading); }
.ind-person label:first-of-type { margin-top: 6px; }
.list-row.clickable:hover { background: var(--dc-navy-100); }
.list-row .r-main { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; }
.list-row .r-title { font: 600 var(--dc-size-body)/1.3 var(--dc-font-core); color: var(--dc-text-body); }
.list-row .r-sub { font: 500 var(--dc-size-caption)/1.4 var(--dc-font-core); color: var(--dc-text-muted); overflow-wrap: anywhere; }
.list-row .r-ref { font: 500 var(--dc-size-label)/1.4 var(--dc-font-mono); letter-spacing: -0.01em; color: var(--dc-text-muted); }
.list-row .r-trailing { flex: none; }
.row-detail { padding: 0 16px 14px 72px; border-bottom: 1px solid var(--dc-border-subtle); }
.rows > li:last-child > .row-detail { border-bottom: none; }
.row-detail dl { margin: 0; }
.row-detail dt { font: 700 var(--dc-size-micro)/1.4 var(--dc-font-core); letter-spacing: .08em; text-transform: uppercase; color: var(--dc-text-muted); margin-top: 8px; }
.row-detail dd { margin: 1px 0 0; font: 400 var(--dc-size-body)/1.45 var(--dc-font-core); }
.row-detail .history { list-style: none; font: 500 var(--dc-size-caption)/1.5 var(--dc-font-core); color: var(--dc-text-muted); }

/* near-you grid */
.near-grid { display: grid; grid-template-columns: 1fr; gap: var(--dc-card-gap); }
@media (min-width: 860px) { .near-grid { grid-template-columns: 1fr 1fr; } }

/* account card facts */
.account-name { font: 700 var(--dc-size-headline)/1.2 var(--dc-font-core); color: var(--dc-text-heading); }
.account-fact { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 12px 0; border-bottom: 1px solid var(--dc-border-subtle); cursor: pointer; }
.account-fact:last-child { border-bottom: none; }
.account-fact span:first-child { font: 600 var(--dc-size-body)/1.3 var(--dc-font-core); }

/* two-column zone on desktop for account/planning etc. */
.grid-2 { display: grid; grid-template-columns: 1fr; gap: var(--dc-section-gap); align-items: start; }
@media (min-width: 860px) { .grid-2 { grid-template-columns: 1fr 1fr; } }

/* ---------------------------------------------------------------- footer */
footer.site {
  background: var(--dc-navy-900); color: var(--dc-text-on-navy-muted);
  font: 500 var(--dc-size-caption)/1.5 var(--dc-font-core);
  text-align: center; padding: 20px;
}

/* ---- Sign-in page (standalone gate; the Hub replaces it after login) ---- */
.signin-page { min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 24px; padding: 24px; background: var(--dc-bg-page); }
.signin-panel { background: var(--dc-bg-header); border-radius: var(--dc-radius-tile); padding: 28px 36px; display: flex; flex-direction: column; align-items: center; gap: 10px; box-shadow: var(--dc-shadow-3); width: min(420px, 100%); }
.signin-lockup { height: 34px; }
.signin-tag { font: var(--dc-weight-bold) var(--dc-size-label)/1.2 var(--dc-font-core); letter-spacing: var(--dc-tracking-eyebrow); text-transform: uppercase; color: var(--dc-text-on-navy-muted); }
.signin-card { width: min(420px, 100%); }
.signin-visitor { width: min(420px, 100%); }
/* Visitor mode: authed-only tiles dim, with a Sign in pill in the tile head. */
/* Dim the tile's CONTENT, not the tile — child opacity multiplies with the parent's,
   so a parent-level dim would drag the Sign in pill down with it. */
.mtile.locked > *:not(.mtile-head) { opacity: 0.55; }
.mtile.locked .mtile-head > *:not(.mtile-lock) { opacity: 0.55; }
.mtile.locked .mtile-lock { opacity: 1; }
.mtile-head .mtile-lock { margin-left: auto; }
.signin-foot { font: var(--dc-weight-medium) var(--dc-size-caption)/1.4 var(--dc-font-core); color: var(--dc-text-muted); }

/* External local-news link in the News card footer */
.news-more { display: flex; justify-content: flex-end; padding: 10px 16px; border-top: 1px solid var(--dc-border-subtle); }
.news-more a { font: var(--dc-weight-bold) var(--dc-size-label)/1.2 var(--dc-font-core); color: var(--dc-text-link); text-decoration: none; }
.news-more a:hover { color: var(--dc-text-link-hover); text-decoration: underline; }

/* ---------------------------------------------------------------- My account (full view) */
.acct-sub-head { display: flex; align-items: center; gap: 8px; margin: 14px 0 8px; }
.acct-sub-head h3 { font: 700 var(--dc-size-body)/1.2 var(--dc-font-core); color: var(--dc-text-heading); }
.balance-card {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  background: var(--dc-surface-sunken); border-radius: var(--dc-radius-md);
  padding: 12px 14px; margin-bottom: 8px;
}
.balance-card .b-label { font: 600 var(--dc-size-caption)/1.2 var(--dc-font-core); color: var(--dc-text-muted); }
.balance-card .b-amount { font: 700 22px/1 var(--dc-font-mono); letter-spacing: -0.01em; color: var(--dc-text-heading); }
.balance-card .b-amount.owing { color: var(--dc-orange-ink); }
.amount { font: 600 var(--dc-size-label)/1.2 var(--dc-font-mono); letter-spacing: -0.01em; white-space: nowrap; }

/* consumption charts */
.chart-block { margin-bottom: 16px; }
.chart-block .chart-title { display: flex; align-items: center; gap: 8px; font: 700 var(--dc-size-label)/1.2 var(--dc-font-core); color: var(--dc-text-heading); margin-bottom: 6px; }
.chart-block svg { display: block; width: 100%; height: auto; }
.chart-axis { font: 500 var(--dc-size-micro)/1 var(--dc-font-core); fill: var(--dc-text-muted); }
.chart-tabs { margin-bottom: 8px; }
.chart-legend { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 4px; font: 500 var(--dc-size-caption)/1.2 var(--dc-font-core); color: var(--dc-text-muted); }
.chart-legend .swatch { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 4px; vertical-align: baseline; }

/* APM success panel */
.apm-token-panel {
  background: var(--dc-teal-100); border-radius: var(--dc-radius-md);
  padding: 14px 16px; margin-top: 12px;
}
.apm-token-panel .tk-label { font: 700 var(--dc-size-micro)/1.4 var(--dc-font-core); letter-spacing: .08em; text-transform: uppercase; color: var(--dc-teal-600); }
.apm-token-panel .tk-value { font: 700 18px/1.4 var(--dc-font-mono); letter-spacing: -0.01em; color: var(--dc-text-heading); overflow-wrap: anywhere; }

/* More-services disclosure row (button-shaped list row) */
.list-row-btn { width: 100%; text-align: left; background: none; border: none; cursor: pointer; font: inherit; }
.list-row-btn:hover { background: var(--dc-surface-sunken); }

/* ---- Buy & pay: bundle picker (banking-app style price rows) ---- */
.apm-bundle-row {
  display: flex; align-items: center; gap: 12px; width: 100%; text-align: left;
  padding: 10px 4px; border: none; background: none; cursor: pointer;
  border-bottom: 1px solid var(--dc-border-subtle);
  font: 500 var(--dc-size-body)/1.3 var(--dc-font-core); color: var(--dc-text-body);
}
#apm-bundles > li:last-child > .apm-bundle-row { border-bottom: none; }
.apm-bundle-row:hover { background: var(--dc-navy-100); }
.apm-bundle-row .b-price { font-family: var(--dc-font-mono); font-weight: 700; min-width: 72px; }
.apm-bundle-row.selected { background: var(--dc-state-live-bg); border-radius: var(--dc-radius-sm); }
.apm-bundle-row .b-check { margin-left: auto; color: var(--dc-teal-ink); visibility: hidden; }
.apm-bundle-row.selected .b-check { visibility: visible; }

/* ---- Community fault map ---- */
.fault-map { height: 380px; border-radius: var(--dc-radius-md); border: 1px solid var(--dc-border-subtle); overflow: hidden; margin-top: 10px; background: var(--dc-surface-sunken); z-index: 0; }
.chip-row { display: flex; flex-wrap: wrap; gap: 8px; margin: 8px 0; }
.chip {
  border: 1px solid var(--dc-border-control); background: var(--dc-white); color: var(--dc-text-body);
  border-radius: var(--dc-radius-pill); padding: 5px 12px; cursor: pointer;
  font: 600 var(--dc-size-caption)/1.2 var(--dc-font-core);
  transition: background var(--dc-fast) var(--dc-ease);
}
.chip:hover { background: var(--dc-surface-sunken); }
.chip.active { background: var(--dc-navy-700); border-color: var(--dc-navy-700); color: var(--dc-text-on-navy); }
/* M35 (WCAG 1.4.1): the chosen chip carries a tick as well as its colour. The tick is not read out:
   aria-pressed already says it. */
.chip[aria-pressed="true"]::before { content: "\2713"; content: "\2713" / ""; margin-right: 5px; }
.map-controls { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.map-legend { display: flex; gap: 14px; margin-top: 8px; font: 500 var(--dc-size-caption)/1.2 var(--dc-font-core); color: var(--dc-text-muted); }
.map-legend .dot { display: inline-block; width: 10px; height: 10px; border-radius: 50%; margin-right: 5px; }
.leaflet-popup-content { font: 500 var(--dc-size-label)/1.5 var(--dc-font-core); }

/* ---- Your councillors ---- */
.avatar { font: 700 var(--dc-size-label)/1 var(--dc-font-core); letter-spacing: .02em; }
.councillor-card {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  background: var(--dc-navy-100); border-radius: var(--dc-radius-md); padding: 14px 16px; margin-top: 10px;
}
.leader-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 10px; margin-bottom: 12px; }
.leader-card { display: flex; align-items: center; gap: 10px; border: 1px solid var(--dc-border-subtle); border-radius: var(--dc-radius-md); padding: 10px 12px; }
.c-body { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1; }
.c-name { font: 700 var(--dc-size-body)/1.3 var(--dc-font-core); color: var(--dc-text-heading); }
.c-sub { font: 500 var(--dc-size-caption)/1.4 var(--dc-font-core); color: var(--dc-text-muted); }
#all-wards summary { cursor: pointer; margin: 8px 0; }
#sec-councillors .meta { margin-top: 10px; display: block; }

/* ---- Demo-data watermarks (portal-config demoMode) ---- */
.demo-pill {
  display: inline-block; background: var(--dc-amber-100); color: var(--dc-amber-ink);
  border: 1px solid var(--dc-amber-500); border-radius: var(--dc-radius-pill);
  font: 700 var(--dc-size-caption)/1.2 var(--dc-font-core); letter-spacing: .06em;
  padding: 2px 8px; margin-left: auto;
}
.balance-card { position: relative; }
.balance-card .demo-pill { position: absolute; top: 8px; right: 8px; margin: 0; }
.demo-svg { font: 700 34px/1 var(--dc-font-core); fill: var(--dc-amber-500); opacity: .18; letter-spacing: .2em; }

/* ---------------------------------------------------------------- hub mosaic + pages */
/* Slim page header shown on every dedicated page (never the Hub). */
.page-header { display: flex; align-items: center; gap: 14px; }
.page-header h2 { font: 700 var(--dc-size-title-2)/1.2 var(--dc-font-core); letter-spacing: -0.01em; color: var(--dc-text-heading); }
.page-header .spacer { flex: 1; }
.page-back {
  display: inline-flex; align-items: center; gap: 6px;
  font: 700 var(--dc-size-label)/1 var(--dc-font-core);
  color: var(--dc-navy-700); text-decoration: none;
}
.page-back:hover { text-decoration: underline; text-underline-offset: 3px; }
.page-back .icon { width: 18px; height: 18px; }

/* Mosaic grid: 6 columns desktop, 2 tablet, 1 mobile; varied tile spans. */
.mosaic { display: grid; grid-template-columns: repeat(6, 1fr); grid-auto-rows: minmax(120px, auto); grid-auto-flow: dense; gap: var(--dc-card-gap); }
.span-4x2 { grid-column: span 4; grid-row: span 2; }
.span-3x1 { grid-column: span 3; }
.span-4x1 { grid-column: span 4; }
.span-2x2 { grid-column: span 2; grid-row: span 2; }
.span-2x1 { grid-column: span 2; }
@media (max-width: 1023px) {
  .mosaic { grid-template-columns: repeat(2, 1fr); }
  .span-4x2, .span-4x1, .span-3x1, .span-2x2, .span-2x1 { grid-column: span 2; grid-row: auto; }
  .span-2x2 { grid-column: span 1; }
}
/* Phone: two columns rather than one. A single column turned the hub into a long
   scroll once the adoption tiles landed; paired tiles halve that. Only the account
   hero keeps full width — it carries a balance line and a sparkline that do not
   read at half width. */
@media (max-width: 639px) {
  /* minmax(0,·), not 1fr: a plain 1fr track refuses to shrink below its widest
     child, so one long balance or label widens the whole grid past the shell and
     the tiles run under the right gutter. */
  .mosaic { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .span-4x1, .span-3x1, .span-2x2, .span-2x1 { grid-column: span 1; grid-row: auto; }
  .span-4x2 { grid-column: span 2; grid-row: auto; }
  .mosaic .mtile { padding: 14px 12px; }
  .mosaic .mtile-go { margin-top: auto; }
  /* Half-width columns: the headline sizes were set for a full-width tile and
     wrap to three lines here, which is what made the hub scroll so far. */
  .mosaic .mtile-big { font-size: var(--dc-size-body-lg); line-height: 1.25; }
  .mosaic .mtile-label { font-size: var(--dc-size-micro); letter-spacing: .08em; }
  .mosaic .span-4x2 .mtile-balance { font-size: 30px; }
  .mosaic .mtile:not(.span-4x2) .mtile-balance { font-size: 24px; }
  /* Two lines of summary is enough at this width; the tile links to the detail. */
  .mosaic .mtile:not(.span-4x2) .mtile-sub {
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden;
  }
}

/* Mosaic tile — a clickable summary card. */
.mtile {
  position: relative; display: flex; flex-direction: column; gap: 8px;
  padding: 16px; cursor: pointer;
  min-width: 0;  /* let the tile shrink with its grid track */
  background: var(--dc-surface-card);
  border: 1px solid var(--dc-border-subtle);
  border-radius: var(--dc-radius-tile);
  box-shadow: var(--dc-shadow-1);
  transition: box-shadow 200ms var(--dc-ease), transform var(--dc-instant) var(--dc-ease);
  -webkit-tap-highlight-color: transparent;
}
.mtile:hover { box-shadow: var(--dc-shadow-2); }
.mtile:active { transform: scale(.98); }
.mtile-head { display: flex; align-items: center; gap: 10px; }
.mtile-label { font: 700 var(--dc-size-label)/1.2 var(--dc-font-core); letter-spacing: .12em; text-transform: uppercase; color: var(--dc-text-heading); }
.mtile-balance { font: 700 34px/1.1 var(--dc-font-mono); letter-spacing: -0.01em; color: var(--dc-text-heading); }
.mtile-big { font: 700 var(--dc-size-headline)/1.2 var(--dc-font-core); color: var(--dc-text-heading); }
.mtile-title { font: 700 var(--dc-size-body-lg)/1.3 var(--dc-font-core); color: var(--dc-text-body); }
.mtile-sub { font: 500 var(--dc-size-caption)/1.4 var(--dc-font-core); color: var(--dc-text-muted); overflow-wrap: anywhere; }
.mtile-sub .pill { vertical-align: middle; }
.mtile-go { margin-top: auto; font: 700 var(--dc-size-label)/1 var(--dc-font-core); color: var(--dc-navy-700); }
.mtile-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.mtile-actions a {
  border: 1px solid var(--dc-border-control); background: var(--dc-white); color: var(--dc-text-body);
  border-radius: var(--dc-radius-pill); padding: 5px 12px; text-decoration: none;
  font: 600 var(--dc-size-caption)/1.2 var(--dc-font-core);
}
.mtile-actions a:hover { background: var(--dc-surface-sunken); }
.hub-spark svg { display: block; width: min(220px, 100%); height: 34px; }
.mtile-glyph { color: var(--dc-navy-300); align-self: center; }
.mtile-glyph .icon { width: 56px; height: 56px; }

/* Tile accents */
.mtile-orange { border-top: 4px solid var(--dc-orange-500); }
.mtile-teal { border-top: 4px solid var(--dc-teal-500); }
.mtile-quiet { background: var(--dc-surface-sunken); box-shadow: none; }
.mtile-navy { background: var(--dc-navy-700); border-color: var(--dc-navy-700); }
.mtile-navy .mtile-label, .mtile-navy .mtile-go { color: var(--dc-text-on-navy); }
.mtile-navy .mtile-sub { color: var(--dc-text-on-navy-muted); }

/* Full-height community map on its dedicated page */
.fault-map-page { height: 62vh; min-height: 380px; }

/* ---------------------------------------------------------------- municipal skins */
/* ---------------------------------------------------------------- buy again */
.buy-again { display: flex; flex-direction: column; gap: 10px; }
.buy-again-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.buy-again-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.buy-again-title { font: var(--dc-weight-bold) var(--dc-size-body)/1.3 var(--dc-font-core); color: var(--dc-text-heading); }
.buy-again-sub { font: var(--dc-weight-medium) var(--dc-size-label)/1.35 var(--dc-font-core); color: var(--dc-text-muted); }
.buy-again .btn { min-height: 44px; flex: none; }

/* ---------------------------------------------------------------- report wizard */
.fault-wiz { display: flex; flex-direction: column; gap: 14px; }
.wiz-progress { display: flex; gap: 6px; }
.wiz-pip { flex: 1; height: 4px; border-radius: var(--dc-radius-pill); background: var(--dc-border); }
.wiz-pip.on { background: var(--dc-action-primary); }
.wiz-step-of { margin: 0; font: 600 var(--dc-size-caption)/1.2 var(--dc-font-core); color: var(--dc-text-muted); }
.wiz-step { display: flex; flex-direction: column; gap: 12px; }
.wiz-step h2 { margin: 0; font: var(--dc-weight-bold) var(--dc-size-title-2)/1.15 var(--dc-font-core);
  letter-spacing: -0.02em; color: var(--dc-text-heading); text-wrap: balance; }
.wiz-lede { margin: 0; font: 400 var(--dc-size-body)/1.5 var(--dc-font-core); color: var(--dc-text-muted); }
.wiz-wide, .wiz-next { width: 100%; min-height: 44px; }
#wiz-to-2, #wiz-send, #wiz-to-3 { min-height: 52px; }
.wiz-foot { display: flex; gap: 8px; align-items: stretch; }
.wiz-foot .btn.ghost { flex: none; min-height: 44px; }
.wiz-foot .wiz-next { flex: 1; }

/* Step 1 — categories. Each states its real SLA, so the citizen is not guessing at
   urgency and we are not promising something the depot has not agreed. */
.wiz-cats { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; }
.wiz-cat {
  display: flex; flex-direction: column; align-items: flex-start; gap: 4px;
  min-height: 104px; padding: 14px; text-align: left; cursor: pointer;
  background: var(--dc-surface-card); border: 1px solid var(--dc-border-subtle);
  border-radius: var(--dc-radius-tile); font: inherit; color: inherit;
  transition: border-color var(--dc-fast) var(--dc-ease), box-shadow var(--dc-fast) var(--dc-ease);
}
.wiz-cat:hover { border-color: var(--dc-border-strong); }
.wiz-cat:focus-visible { outline: 3px solid var(--dc-focus-ring); outline-offset: 2px; }
.wiz-cat.is-on { border: 2px solid var(--dc-navy-700); box-shadow: var(--dc-shadow-2); padding: 13px; }
.wiz-cat-ico { display: block; width: 22px; height: 22px; color: var(--dc-navy-700); margin-bottom: 4px; }
.wiz-cat-ico .icon svg { width: 100%; height: 100%; }
.wiz-cat-label { font: var(--dc-weight-bold) var(--dc-size-body)/1.25 var(--dc-font-core); color: var(--dc-text-heading); }

/* Step 2 — where. The map surface is a labelled placeholder until Leaflet is wired here;
   the live map already exists on #/map and is lazy-initialised there. */
.wiz-map {
  height: 200px; border-radius: var(--dc-radius-md);
  background: var(--dc-surface-sunken); border: 1px solid var(--dc-border-subtle);
  display: grid; place-items: center;
  font: var(--dc-weight-medium) var(--dc-size-label)/1.2 var(--dc-font-core); color: var(--dc-text-muted);
}
.wiz-gps-status { margin: 0; font: var(--dc-weight-medium) var(--dc-size-label)/1.4 var(--dc-font-core); color: var(--dc-text-muted); }

/* Step 3 — photos and the review. */
.wiz-photos { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 10px; }
.wiz-photo, .wiz-photo-add {
  min-height: 104px; border-radius: var(--dc-radius-md); padding: 10px;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; text-align: center;
}
.wiz-photo { background: var(--dc-surface-sunken); border: 1px solid var(--dc-border-subtle); position: relative; }
.wiz-photo-name { font-size: var(--dc-size-micro); color: var(--dc-text-muted); word-break: break-all; }
.wiz-photo-x {
  position: absolute; top: 4px; right: 4px; width: 28px; height: 28px; border-radius: var(--dc-radius-pill);
  border: 0; background: var(--dc-surface-card); color: var(--dc-text-muted); cursor: pointer; font-size: 16px;
}
.wiz-photo-add {
  background: var(--dc-surface-card); border: 2px dashed var(--dc-border-strong); cursor: pointer;
  font: var(--dc-weight-bold) var(--dc-size-label)/1.2 var(--dc-font-core); color: var(--dc-text-heading);
}
.wiz-photo-add .icon svg { width: 22px; height: 22px; }
.wiz-review { background: var(--dc-surface-sunken); border-radius: var(--dc-radius-md); padding: var(--dc-card-padding);
  display: flex; flex-direction: column; gap: 8px; }
.wiz-review-list { margin: 0; display: grid; grid-template-columns: 96px 1fr; gap: 6px 12px; }
.wiz-review-list dt { font: 600 var(--dc-size-label)/1.4 var(--dc-font-core); color: var(--dc-text-muted); }
.wiz-review-list dd { margin: 0; font: 400 var(--dc-size-body)/1.4 var(--dc-font-core); color: var(--dc-text-body); }

/* Sent. */
.wiz-done-card { border-top: 3px solid var(--dc-state-live); display: flex; flex-direction: column; gap: 8px; }
.wiz-done-card h2 { margin: 0; font: var(--dc-weight-bold) var(--dc-size-title-2)/1.15 var(--dc-font-core); color: var(--dc-text-heading); }
.wiz-done-ref { margin: 0; font: 400 var(--dc-size-body-lg)/1.4 var(--dc-font-core); color: var(--dc-text-body); }
.wiz-done-sla { margin: 0; font: 400 var(--dc-size-body)/1.5 var(--dc-font-core); color: var(--dc-text-body); }
.wiz-done-note { margin: 0; font: 400 var(--dc-size-label)/1.45 var(--dc-font-core); color: var(--dc-text-muted); }

/* ---------------------------------------------------------------- request detail */
.req-head { display: flex; flex-direction: column; gap: 8px; }
.req-head-top { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.req-ref { font-size: var(--dc-size-label); color: var(--dc-text-muted); font-variant-numeric: tabular-nums; }
.req-head h2 { margin: 0; font: var(--dc-weight-bold) var(--dc-size-headline)/1.25 var(--dc-font-core); color: var(--dc-text-heading); }
.req-desc { margin: 0; font: 400 var(--dc-size-body)/1.5 var(--dc-font-core); color: var(--dc-text-body); }
.req-meta { margin: 0; display: flex; align-items: center; gap: 8px;
  font: var(--dc-weight-medium) var(--dc-size-label)/1.4 var(--dc-font-core); color: var(--dc-text-muted); }

.req-track { display: flex; flex-direction: column; gap: 10px; }
.req-steps { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0; }
.req-step { display: flex; align-items: flex-start; gap: 12px; padding: 8px 0; position: relative; }
/* The connecting rail. Drawn on the item, not between them, so a pending step still shows
   its place in the sequence. */
.req-step::before {
  content: ''; position: absolute; left: 11px; top: 30px; bottom: -8px; width: 2px;
  background: var(--dc-border); 
}
.req-step:last-child::before { display: none; }
.req-dot {
  flex: none; width: 24px; height: 24px; border-radius: var(--dc-radius-pill);
  display: grid; place-items: center;
  border: 2px solid var(--dc-border-strong); background: var(--dc-surface-card);
}
.req-step.is-done .req-dot { border-color: var(--dc-state-live); background: var(--dc-state-live); color: var(--dc-ink); }
.req-step.is-done .req-dot .icon svg { width: 14px; height: 14px; }
.req-step-text { display: flex; flex-direction: column; gap: 1px; }
.req-step-label { font: 600 var(--dc-size-body)/1.3 var(--dc-font-core); color: var(--dc-text-heading); }
.req-step.is-pending .req-step-label { color: var(--dc-text-muted); }
.req-step-sub { font: var(--dc-weight-medium) var(--dc-size-label)/1.35 var(--dc-font-core); color: var(--dc-text-muted); }
.req-note { margin: 0; font: 400 var(--dc-size-label)/1.5 var(--dc-font-core); color: var(--dc-text-muted); }

.req-facts { display: flex; flex-direction: column; gap: 10px; }
.req-facts-list { margin: 0; display: grid; grid-template-columns: minmax(96px, auto) 1fr; gap: 6px 14px; }
.req-facts-list dt { font: 600 var(--dc-size-label)/1.4 var(--dc-font-core); color: var(--dc-text-muted); }
.req-facts-list dd { margin: 0; font: 400 var(--dc-size-body)/1.4 var(--dc-font-core); color: var(--dc-text-body); }
.req-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 4px; }
.req-actions .btn { min-height: 44px; }
.req-actions .btn[disabled] { opacity: .4; cursor: not-allowed; }

/* ---------------------------------------------------------------- visitor lock
   A private screen a visitor opened. The page's own content is hidden rather than
   removed, so signing in restores it with no re-render of the markup. */
.page.locked-mode > *:not(.page-lock) { display: none !important; }
.page-lock { display: flex; flex-direction: column; align-items: flex-start; gap: 10px; }
.page-lock h3 { margin: 0; font: var(--dc-weight-bold) var(--dc-size-headline)/1.25 var(--dc-font-core); color: var(--dc-text-heading); }
.page-lock p { margin: 0; max-width: 62ch; font: 400 var(--dc-size-body)/1.55 var(--dc-font-core); color: var(--dc-text-body); }
.page-lock .btn { min-height: 44px; margin-top: 4px; }

/* ---------------------------------------------------------------- Home
   Three questions: what you owe, what is happening now, what you reported. Plus one
   "do something" grid. The catalogue lives on #/services. */

.home-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: var(--dc-card-gap); }
.home-block { display: flex; flex-direction: column; gap: var(--dc-card-gap); }

/* What you owe. The amber top rule is the platform's "money owed" semantic — it is one
   of the tokens a municipal skin deliberately does not repaint. */
.home-money { border-top: 3px solid var(--dc-state-progress); display: flex; flex-direction: column; gap: 6px; }
.home-amount {
  font: var(--dc-weight-bold) var(--dc-size-title-1)/1.05 var(--dc-font-mono);
  letter-spacing: -0.03em; word-spacing: -0.22em; color: var(--dc-text-heading);
  font-variant-numeric: tabular-nums;
}
.home-money-sub { margin: 0; font: 400 var(--dc-size-body)/1.45 var(--dc-font-core); color: var(--dc-text-body); }
.home-money-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 6px; }
.home-money-actions .btn { min-height: 44px; }

/* Visitor: says what an account is for, not a screen of em-dashes. */
.home-locked { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }
.home-locked h3 { margin: 0; font: var(--dc-weight-bold) var(--dc-size-headline)/1.25 var(--dc-font-core); color: var(--dc-text-heading); }
.home-locked p { margin: 0; font: 400 var(--dc-size-body)/1.5 var(--dc-font-core); color: var(--dc-text-body); }
.home-locked .btn { min-height: 44px; margin-top: 4px; }

/* What is happening now — the whole card navigates. */
.home-now {
  background: var(--dc-surface-inverse); color: var(--dc-text-on-navy);
  display: flex; flex-direction: column; gap: 6px; cursor: pointer;
  transition: box-shadow var(--dc-fast) var(--dc-ease);
}
.home-now:hover { box-shadow: var(--dc-shadow-2); }
.home-now:focus-visible { outline: 3px solid var(--dc-focus-ring); outline-offset: 2px; }
.home-now .eyebrow { color: var(--dc-text-on-navy-muted); }
.home-now h3 { margin: 0; font: var(--dc-weight-bold) var(--dc-size-headline)/1.25 var(--dc-font-core); color: var(--dc-text-on-navy); }
.home-now p { margin: 0; font: 400 var(--dc-size-body)/1.45 var(--dc-font-core); color: var(--dc-text-on-navy); }
.home-now-go { margin-top: auto; padding-top: 8px; font: var(--dc-weight-bold) var(--dc-size-body)/1.2 var(--dc-font-core); color: var(--dc-text-on-navy); }

/* Do something. */
.home-do { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: var(--dc-card-gap); }
.do-tile {
  display: flex; flex-direction: column; gap: 4px; min-height: 116px;
  padding: var(--dc-card-padding);
  background: var(--dc-surface-card); border: 1px solid var(--dc-border-subtle);
  border-radius: var(--dc-radius-tile); cursor: pointer;
  transition: box-shadow var(--dc-fast) var(--dc-ease), border-color var(--dc-fast) var(--dc-ease);
}
.do-tile:hover { box-shadow: var(--dc-shadow-2); border-color: var(--dc-border-strong); }
.do-tile:focus-visible { outline: 3px solid var(--dc-focus-ring); outline-offset: 2px; }
.do-tile .tone-chip { margin-bottom: 6px; }
.do-label { font: var(--dc-weight-bold) var(--dc-size-body)/1.25 var(--dc-font-core); color: var(--dc-text-heading); }
.do-sub { font: var(--dc-weight-medium) var(--dc-size-caption)/1.35 var(--dc-font-core); color: var(--dc-text-muted); }
.do-tile.locked { opacity: .55; }

/* Open requests. */
.home-req-card { padding: 0; overflow: hidden; }
.home-req-row {
  display: flex; align-items: center; gap: 12px; width: 100%;
  padding: 12px var(--dc-card-padding); min-height: 44px;
  background: none; border: 0; border-top: 1px solid var(--dc-border-subtle);
  text-align: left; cursor: pointer; font: inherit; color: inherit;
}
.home-req-row:first-child { border-top: 0; }
.home-req-row:hover { background: var(--dc-surface-sunken); }
.home-req-row:focus-visible { outline: 3px solid var(--dc-focus-ring); outline-offset: -3px; }
.home-req-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.home-req-title { font: 600 var(--dc-size-body)/1.3 var(--dc-font-core); color: var(--dc-text-heading);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.home-req-sub { font: var(--dc-weight-medium) var(--dc-size-label)/1.35 var(--dc-font-core); color: var(--dc-text-muted); }
.home-req-empty { padding: var(--dc-card-padding); font: 400 var(--dc-size-body)/1.45 var(--dc-font-core); color: var(--dc-text-muted); }

/* ---------------------------------------------------------------- persistent navigation
   Phone tab bar below 720px, desktop left rail above it. Both are rendered by app.js into
   #view-hub, so they hide with the signed-in shell on the sign-in gate and survive every
   re-render (nothing writes #view-hub's innerHTML).

   Shipped here rather than as the handoff's /tab-bar.css: dc-api serves an exact-path
   allowlist (server.mjs:860-885) and 404s every other file-shaped GET, so a new stylesheet
   is unreachable by construction.

   Safe-area note: every env() below sits in a SINGLE-level calc(). Never fold
   --dc-gutter-left/right in here — those are themselves calc() containing env(), and
   WKWebView drops a calc() that nests env() inside another calc() with no error at all
   (see the warning at the top of this file). */

.dc-nav { display: none; }
.dc-nav a { text-decoration: none; -webkit-tap-highlight-color: transparent; }
.dc-nav a:focus-visible { outline: 3px solid var(--dc-focus-ring); outline-offset: -3px; }
.dc-nav .dc-nav-ico { display: block; flex: none; }
.dc-nav .dc-nav-ico .icon svg { display: block; width: 100%; height: 100%; }
/* The design asks for a 2.4px stroke on the active nav icon; I() hard-codes 2, so it is
   overridden here rather than by minting a second icon set. */
.dc-nav a[aria-current="page"] .dc-nav-ico .icon svg { stroke-width: 2.4; }
/* Visitor: a private destination is dimmed and carries a lock, matching the mosaic tiles
   rather than silently dropping the visitor back to the gate. */
.dc-nav a.locked { opacity: .55; }
.dc-nav .dc-nav-lock { flex: none; margin-left: auto; font-size: 11px; }

/* -- phone tab bar -- */
.dc-tabbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  align-items: stretch;
  height: calc(56px + env(safe-area-inset-bottom, 0px));
  padding-bottom: env(safe-area-inset-bottom, 0px);
  padding-left: env(safe-area-inset-left, 0px);
  padding-right: env(safe-area-inset-right, 0px);
  background: var(--dc-surface-card);
  border-top: 1px solid var(--dc-border-subtle);
}
.dc-tabbar a {
  flex: 1; min-width: 0; min-height: 44px;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  color: var(--dc-text-muted);
  transition: color var(--dc-fast) var(--dc-ease);
}
.dc-tabbar .dc-nav-ico { width: 22px; height: 22px; position: relative; }
.dc-tabbar .dc-nav-lbl {
  font: var(--dc-weight-medium) var(--dc-size-micro)/1 var(--dc-font-core);
  white-space: nowrap; max-width: 100%; overflow: hidden; text-overflow: ellipsis;
}
.dc-tabbar a[aria-current="page"] { color: var(--dc-navy-700); }
.dc-tabbar a[aria-current="page"] .dc-nav-lbl { font-weight: 700; }
.dc-tabbar a.locked .dc-nav-lock { position: absolute; top: -3px; right: -6px; margin: 0; }

/* -- desktop rail -- */
.dc-rail {
  position: fixed; top: 0; bottom: 0; left: 0; z-index: 30;
  width: 236px; overflow-y: auto;
  flex-direction: column; gap: 4px;
  padding: 16px 12px calc(16px + env(safe-area-inset-bottom, 0px));
  padding-left: calc(12px + env(safe-area-inset-left, 0px));
  background: var(--dc-surface-card);
  border-right: 1px solid var(--dc-border-subtle);
}
.dc-rail a {
  display: flex; align-items: center; gap: 12px;
  min-height: 44px; padding: 0 12px; border-radius: var(--dc-radius-md);
  color: var(--dc-text-body);
  font: var(--dc-weight-medium) var(--dc-size-body)/1.2 var(--dc-font-core);
  transition: background var(--dc-fast) var(--dc-ease), color var(--dc-fast) var(--dc-ease);
}
.dc-rail a:hover { background: var(--dc-navy-100); }
.dc-rail .dc-nav-ico { width: 20px; height: 20px; }
.dc-rail a[aria-current="page"] {
  background: var(--dc-navy-100); color: var(--dc-navy-700); font-weight: 700;
}
.dc-rail .dc-rail-div { height: 1px; background: var(--dc-border-subtle); margin: 12px 4px 8px; }
.dc-rail .dc-rail-eyebrow {
  font: var(--dc-weight-bold) var(--dc-size-micro)/1.4 var(--dc-font-core);
  letter-spacing: var(--dc-tracking-eyebrow); text-transform: uppercase;
  color: var(--dc-text-muted); padding: 0 12px 4px;
}

@media (max-width: 719px) {
  .dc-tabbar { display: flex; }
  /* The bar is fixed, so the last card of a long page would sit under it. .shell already
     carries 48px of bottom padding; the footer is the sibling that actually needs the
     clearance, and it is scoped to the shell so the sign-in gate keeps its own spacing. */
  #view-hub:not(.hidden) ~ footer.site { padding-bottom: calc(72px + env(safe-area-inset-bottom, 0px)); }
}
@media (min-width: 720px) {
  .dc-rail { display: flex; }
  main { padding-left: 236px; }
  header.site { padding-left: calc(236px + var(--dc-gutter)); }
}

/* Theming layer over the DC token system. app.js sets <html data-brand="…"> from
   /portal-config (cached in sessionStorage so repeat loads skin before first paint).
   A skin swaps ONLY semantic tokens: inverse/header surfaces and action colors take
   the municipal palette; STATE COLORS STAY DC — alert/progress/live signal semantics
   must read identically across every skinned portal. */
/* A customer app's skin is its own: its colour tokens live in its repo and dc-api serves them
   per app at /app-skin.css, under html[data-brand="<app key>"]. The platform ships none. */

/* Powered-by caption (small reversed DC lockup + text) — shown only when the active
   brand's poweredBy flag is set (header + sign-in gate). */
.powered-by {
  display: flex; align-items: center; gap: 6px;
  font: 600 var(--dc-size-micro)/1.2 var(--dc-font-core);
  color: var(--dc-text-on-navy-muted); letter-spacing: .04em;
}
.powered-by img { height: 14px; width: auto; display: block; opacity: .85; }

/* ---------------------------------------------------------------- ward schedules */
.ward-sched-rows { display: flex; flex-direction: column; gap: 8px; }
.ward-sched-row { display: flex; align-items: center; gap: 10px; }
.ward-sched-row .s-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.ward-sched-row .s-title { font: 700 var(--dc-size-body)/1.3 var(--dc-font-core); }
.ward-sched-row .s-sub { font: 500 var(--dc-size-caption)/1.4 var(--dc-font-core); color: var(--dc-text-muted); }

/* ---------------------------------------------------------------- submit a reading */
.reading-form { margin-top: 10px; padding: 12px; border: 1px solid var(--dc-border-subtle); border-radius: var(--dc-radius-md); background: var(--dc-surface-sunken); }
.reading-form input.reading-value {
  font: 700 26px/1.2 var(--dc-font-mono); letter-spacing: .02em; width: 100%;
}

/* ---------------------------------------------------------------- toast */
.toast {
  /* Cleared above the phone tab bar (56px + inset). The bar is z-index 40 and the toast
     60, so a toast sitting at the old 22px covered primary navigation for its whole
     4.5-8s life with no pointer-events escape. */
  position: fixed; bottom: calc(78px + env(safe-area-inset-bottom, 0px)); left: 50%; transform: translateX(-50%);
  max-width: min(520px, calc(100vw - 32px));
  background: var(--dc-surface-inverse); color: var(--dc-text-on-navy);
  font: 600 var(--dc-size-label)/1.4 var(--dc-font-core);
  padding: 10px 18px; border-radius: var(--dc-radius-pill);
  box-shadow: var(--dc-shadow-3); z-index: 60;
}
.toast-amber { background: var(--dc-amber-100); color: var(--dc-amber-ink); }
.toast + .toast { bottom: calc(124px + env(safe-area-inset-bottom, 0px)); }

/* ---------------------------------------------------------------- municipal website connector */
/* Connector rows are outbound links to the municipality's own site — styled as ordinary
   list rows with an external-link glyph trailing. */
a.list-row.muni-link { text-decoration: none; color: inherit; }
a.list-row.muni-link:hover { background: var(--dc-navy-100); }
a.list-row.muni-link .r-trailing .icon { color: var(--dc-text-muted); }
.wo-muni-caption {
  margin-top: 12px; padding: 0 2px 6px;
  font: var(--dc-weight-bold) var(--dc-size-label)/1.2 var(--dc-font-core);
  letter-spacing: var(--dc-tracking-eyebrow); text-transform: uppercase;
  color: var(--dc-text-muted);
}
.wo-muni-rows { background: var(--dc-surface-card); border: 1px solid var(--dc-border-subtle); border-radius: var(--dc-radius-card); overflow: hidden; }

/* ---------------------------------------------------------------- fault evidence */
/* Staged evidence chips in the composer (image thumbnails, video name chips) and the
   read-only attachment rows in the My-requests expand. */
.evidence-list { list-style: none; margin: 8px 0 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.evidence-item {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; border: 1px solid var(--dc-border-subtle);
  border-radius: var(--dc-radius-card); background: var(--dc-surface-card);
}
.evidence-thumb {
  width: 44px; height: 44px; object-fit: cover; flex: none;
  border-radius: 8px; border: 1px solid var(--dc-border-subtle);
}
.evidence-item .r-title { word-break: break-all; }
.attachment-list { list-style: none; margin: 0; padding: 0; }
.attachment-list li { display: flex; align-items: center; gap: 6px; padding: 2px 0; }
.attachment-list .icon { color: var(--dc-text-muted); }

/* Ward filter select in the map controls */
#map-ward { height: 36px; padding: 0 10px; border: 1px solid var(--dc-border-control); border-radius: var(--dc-radius-md); background: var(--dc-surface-card); font: 600 var(--dc-size-label)/1 var(--dc-font-core); color: var(--dc-text-body); }

/* ================================================================ mobile app density */
/* Under 720px the portal presents like an app: compact weather chip (card collapsed
   until tapped), horizontally scrolling tile rows on the Hub, tighter paddings and
   near-full-bleed cards. THE DESKTOP MOSAIC IS UNTOUCHED — everything below is either
   a mobile-only element (hidden here by default) or scoped to max-width: 719px. */

/* Mobile-only hub rows + weather chip: hidden on desktop. */
.mobile-only { display: none; }
/* The temperature chip is now part of the single header action row at every width
   (product direction: temp left · SOS centre · session action right). */
.weather-chip {
  display: inline-flex; align-items: center; gap: 8px; min-height: 40px;
  padding: 8px 14px; border-radius: var(--dc-radius-pill);
  background: rgba(255,255,255,.10); border: 1px solid var(--dc-border-on-navy);
  color: var(--dc-text-on-navy); cursor: pointer;
}

@media (max-width: 719px) {
  .header-side { width: 100%; align-items: stretch; }
  .who.header-row { width: 100%; }
  .mobile-only { display: block; }

  /* --- 1. weather: compact chip near the greeting; tap expands the full card --- */
  .weather-chip {
    display: inline-flex; align-items: center; gap: 6px;
    margin-top: 10px; padding: 5px 12px;
    background: rgba(255,255,255,.1);
    border: 1px solid var(--dc-border-on-navy);
    border-radius: var(--dc-radius-pill);
    color: var(--dc-text-on-navy); cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  .weather-chip .wc-icon { color: var(--dc-amber-500); }
  .weather-chip .wc-icon .icon { width: 18px; height: 18px; }
  .weather-chip .wc-temp { font: 700 var(--dc-size-body)/1 var(--dc-font-mono); letter-spacing: -0.01em; }
  .weather-card {
    width: 100%; min-width: 0;
    max-height: 0; overflow: hidden;
    padding-top: 0; padding-bottom: 0;
    border-color: transparent;
    transition: max-height 220ms var(--dc-ease), padding 220ms var(--dc-ease);
  }
  .weather-card.weather-open {
    max-height: 340px;
    padding: 14px 16px;
    border-color: var(--dc-border-on-navy);
  }
  .header-side { width: 100%; align-items: stretch; }
  .who { justify-content: flex-end; }

  /* --- 2. hub rows: horizontal scroll-snap tile rows --- */
  .hub-row-wrap { position: relative; }
  /* Edge fade hinting that more tiles wait off-screen. */
  .hub-row-wrap::after {
    content: ""; position: absolute; top: 24px; right: -10px; bottom: 0; width: 32px;
    background: linear-gradient(to left, var(--dc-bg-page) 15%, rgba(255,255,255,0));
    pointer-events: none;
  }
  .hub-row {
    display: flex; gap: 10px;
    /* Bleed to the shell edge and restore the page gutter as padding, so the first tile lines
       up with the cards above and the last tile stops on the same right margin they do.
       These MUST be the gutter variables, not a hardcoded 10px: the shell pads by
       --dc-gutter-left/right (which carry the safe-area insets), so a fixed bleed leaves the
       row 10px closer to the edge than every card on the page — visible as a right-hand
       buffer that does not line up, and wrong by a different amount again on a notched device
       in landscape, where the inset is non-zero. */
    margin: 0 var(--dc-gutter-right-neg) 0 var(--dc-gutter-left-neg);
    padding: 2px var(--dc-gutter-right) 8px var(--dc-gutter-left);
    /* Both sides: scroll-snap aligns a child to the snapport (the padding box inset by
       scroll-padding), so setting only the right pulls the first tile flush to the screen edge
       and cancels padding-left. */
    scroll-padding-left: var(--dc-gutter-left);
    scroll-padding-right: var(--dc-gutter-right);
    /* BOTH sides. scroll-snap aligns a child to the container's SNAPPORT, which is the padding
       box inset by scroll-padding — set only the right and the snap pulls the first tile flush
       to the border box, i.e. hard against the screen edge, undoing the padding-left above. */
    scroll-padding-left: var(--dc-gutter-left);
    scroll-padding-right: var(--dc-gutter-right);
    overflow-x: auto;
    overscroll-behavior-x: contain;  /* keep overscroll in the row, off the page */
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;           /* hide the scrollbar, keep scrollability */
  }
  .hub-row::-webkit-scrollbar { display: none; }
  .hub-row > * { flex: none; scroll-snap-align: start; }

  /* Small square single-function service tiles: icon over label. */
  .svc-tile {
    width: 124px; min-height: 124px;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 8px; padding: 10px 6px; text-align: center;
    background: var(--dc-surface-card);
    border: 1px solid var(--dc-border-subtle);
    border-radius: var(--dc-radius-lg);
    box-shadow: var(--dc-shadow-1);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  .svc-tile:active { transform: scale(.97); }
  .svc-tile .tone-chip { width: 40px; height: 40px; }
  .svc-tile .svc-label { font: 700 var(--dc-size-micro)/1.25 var(--dc-font-core); color: var(--dc-text-heading); }
  .svc-tile.locked { opacity: .55; }

  /* Compact "For you" summary cards. */
  .fy-card {
    width: 240px; min-height: 96px;
    display: flex; flex-direction: column; gap: 4px;
    padding: 12px 14px;
    background: var(--dc-surface-card);
    border: 1px solid var(--dc-border-subtle);
    border-radius: var(--dc-radius-lg);
    box-shadow: var(--dc-shadow-1);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  .fy-card:active { transform: scale(.98); }
  .fy-head { display: flex; align-items: center; gap: 8px; }
  .fy-head .mtile-lock { margin-left: auto; }
  .fy-label { font: 700 var(--dc-size-micro)/1.2 var(--dc-font-core); letter-spacing: .1em; text-transform: uppercase; color: var(--dc-text-heading); }
  .fy-big { font: 700 var(--dc-size-headline)/1.15 var(--dc-font-core); color: var(--dc-text-heading); }
  .fy-big.mono { font-family: var(--dc-font-mono); }
  .fy-sub { font: 500 var(--dc-size-caption)/1.35 var(--dc-font-core); color: var(--dc-text-muted); overflow: hidden; }
  .fy-card.locked .fy-big, .fy-card.locked .fy-sub { opacity: .55; }

  /* Mosaic tiles whose functions moved into the rows disappear on mobile;
     the rest (What's On, map teaser, News, Councillors) stack full-width, denser. */
  .m-hide { display: none !important; }
  .mtile { padding: 14px 16px; gap: 6px; border-radius: var(--dc-radius-lg); }
  .mtile-glyph .icon { width: 36px; height: 36px; }

  /* --- 3. page density: tighter paddings, title-2 headings, near-full-bleed cards --- */
  header.site {
    padding: calc(14px + env(safe-area-inset-top, 0px)) var(--dc-gutter-right) 20px var(--dc-gutter-left);
  }
  .greeting h1 { font-size: var(--dc-size-title-2); }
  :root { --dc-section-gap: 22px; }
  /* Product feedback: breathing room on the sides, larger tiles. */
  .shell { padding: 18px var(--dc-gutter-right) 44px var(--dc-gutter-left); }
  .page-header h2 { font-size: var(--dc-size-headline); }
  .card, .card-navy { border-radius: var(--dc-radius-md); }
  .section-title { margin-bottom: 8px; }
}

/* ---------------------------------------------------------------- Emergency SOS */
/* Header chip: prominent but SMALL — it only navigates to #/sos, never sends. */
.sos-chip {
  background: var(--dc-orange-ink); color: #fff; border: 0; border-radius: 999px;
  font: 800 16px/1 var(--dc-font-core); letter-spacing: .08em;
  padding: 13px 30px; min-height: 46px; cursor: pointer;
  box-shadow: 0 0 0 2px rgba(255,255,255,.35), 0 2px 10px rgba(224,54,22,.45);
}
.sos-chip:hover { background: var(--dc-orange-ink-hover); }
/* Phone: the icon-only side actions leave room, so the SOS takes it. */
@media (max-width: 419px) {
  .sos-chip { font-size: 17px; padding: 14px 34px; min-height: 50px; }
}
.sos-types { flex-wrap: wrap; margin: 10px 0; }
/* Hold-to-confirm button: a tap does nothing — the fill sweeps over 3 s of hold. */
.sos-hold {
  position: relative; overflow: hidden; width: 100%; margin-top: 8px;
  background: var(--dc-orange-ink); color: #fff; border: 0; border-radius: 16px;
  padding: 26px 16px; font-size: 18px; font-weight: 800; letter-spacing: .04em;
  cursor: pointer; touch-action: none; user-select: none; -webkit-user-select: none;
}
.sos-hold:disabled { background: var(--dc-border); color: var(--dc-text-muted); cursor: not-allowed; }
.sos-hold-fill {
  position: absolute; inset: 0; width: 0; background: rgba(0,0,0,.28); pointer-events: none;
}
.sos-hold.holding .sos-hold-fill { width: 100%; transition: width 3s linear; }
.sos-hold-label { position: relative; }
.sos-status:not(:empty) { margin-top: 12px; font-weight: 600; }
.sos-dispatch-box { margin-top: 12px; padding: 12px; border: 1px solid var(--dc-border); border-radius: 12px; background: var(--dc-surface-sunken); }
.sos-dispatch-box ul { margin: 8px 0 0; padding-left: 18px; }

/* ---------------------------------------------------------------- daily essentials (Today strip) */
/* Compact daily-habit chips above the hub content. Desktop: wrapping row atop the
   mosaic area. Mobile: horizontal scroll-snap row (same treatment as .hub-row). */
.today-wrap { margin-bottom: var(--dc-card-gap); }
.today-strip { scroll-padding-right: var(--dc-gutter-right); display: flex; flex-wrap: wrap; gap: 8px; }
.tchip {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 8px 14px; border-radius: 999px; cursor: pointer;
  background: var(--dc-surface-card); border: 1px solid var(--dc-border);
  box-shadow: 0 1px 2px rgba(11, 15, 25, .04);
}
.tchip:hover { border-color: var(--dc-navy-300); }
.tchip:active { transform: scale(.97); }
.tchip .icon svg { width: 18px; height: 18px; color: var(--dc-text-heading); }
.tchip .tc-main { font: 700 var(--dc-size-body)/1 var(--dc-font-core); color: var(--dc-text-heading); }
.tchip .tc-sub { font: 600 var(--dc-size-micro)/1.2 var(--dc-font-core); color: var(--dc-text-muted); }
.tchip .tc-hot { color: var(--dc-amber-600); }
/* Load-shedding stage pill: 0 green, 1-2 amber, 3+ red. */
.ls-pill { padding: 2px 10px; border-radius: 999px; font: 700 var(--dc-size-micro)/1.6 var(--dc-font-core); }
.ls-green { background: var(--dc-teal-100); color: var(--dc-teal-ink); }
.ls-amber { background: var(--dc-amber-100); color: var(--dc-amber-600); }
.ls-red { background: var(--dc-orange-100); color: var(--dc-orange-ink); }
/* Banner action link (daily-essentials banners deep-link). */
.banner .b-link { font: 700 var(--dc-size-caption)/1.4 var(--dc-font-core); color: var(--dc-navy-500); text-decoration: none; }
.banner .b-link:hover { text-decoration: underline; }
@media (max-width: 719px) {
  .today-strip {
    flex-wrap: nowrap; overflow-x: auto; scroll-snap-type: x mandatory;
    overscroll-behavior-x: contain;
    scrollbar-width: none; padding-bottom: 2px;
  }
  .today-strip::-webkit-scrollbar { display: none; }
  .today-strip > * { flex: none; scroll-snap-align: start; }
}

/* Full-width DEMO notice (the SOS pill was long enough to overlap its card title). */
.demo-note {
  display: block; margin: 0 0 10px;
  font: 700 var(--dc-size-label)/1.35 var(--dc-font-core);
  color: var(--dc-amber-ink); background: var(--dc-amber-100);
  border: 1px solid var(--dc-amber-500); border-radius: var(--dc-radius-sm);
  padding: 8px 12px;
}

/* ---- Jobs & vacancies (#/jobs) ---- */
/* The apply form lives inside the expanded vacancy row, so it inherits .row-detail's
   left inset. Cap the width: a 2000-character motivation box spanning a desktop card
   is unreadable to type into. */
.apply-form { max-width: 46rem; margin-top: 10px; }
.apply-form textarea { resize: vertical; min-height: 88px; }
.apply-form .hint { margin-top: 10px; }
.apply-done { max-width: 46rem; margin-top: 10px; }
.apply-done .r-ref {
  font: 700 var(--dc-size-body)/1.4 var(--dc-font-mono); letter-spacing: -0.01em;
  color: var(--dc-text-heading);
}
#sec-jobs .chip-row { margin-bottom: 0; }
#jobs-list .r-trailing .pill { white-space: nowrap; }

/* ---------------------------------------------------------------- My alerts (#/alerts) */
/* The right-hand header group: bell + session action live inside ONE grid child so the
   3-column action row keeps SOS centred (see .who.header-row above). */
/* nowrap: with the bell alongside it, "Log out" was breaking onto two lines and
   pulling the whole action row out of vertical alignment. */
.header-right { display: inline-flex; align-items: center; gap: 10px; white-space: nowrap; }
.header-right .btn { white-space: nowrap; }
.header-right .ico-only { display: none; }
/* Phone: the action row has no slack left once the bell is in it, so trim the
   two side groups rather than let them push the SOS off centre or overlap it.
   Log out drops to its glyph; the aria-label carries the name. */
@media (max-width: 419px) {
  .header-right { gap: 8px; }
  .header-right .btn.small { padding: 0; width: 36px; }
  .header-right .ico-only { display: inline-flex; }
  .header-right .ico-only .icon { width: 18px; height: 18px; }
  .header-right .lbl { display: none; }
  /* "Sign in" has no glyph, so it keeps its label and its padding. */
  .header-right #btn-header-signin { padding: 0 10px; width: auto; }
  .who.header-row .weather-chip { padding: 0 10px; gap: 6px; }
}
.bell-chip {
  position: relative; display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: 999px; cursor: pointer;
  background: rgba(255,255,255,.10); border: 1px solid var(--dc-border-on-navy);
  color: var(--dc-text-on-navy);
}
.bell-chip:hover { background: rgba(255,255,255,.18); }
.bell-chip .icon svg { width: 20px; height: 20px; }
/* Unread count. Orange, not red: this is a nudge, not an emergency — the SOS chip beside
   it owns that colour weight. */
.bell-badge {
  position: absolute; top: -4px; right: -4px; min-width: 18px; height: 18px; padding: 0 5px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 999px; background: var(--dc-orange-600); color: #fff;
  font: 800 var(--dc-size-micro)/1 var(--dc-font-core);
  box-shadow: 0 0 0 2px var(--dc-navy-700);
}
/* How these reach you. Deliberately NOT .demo-note: amber is reserved for DEMO DATA in this
   portal, and spending it on a delivery caveat would weaken the signal that matters most. */
.delivery-note {
  display: block; margin: 0 0 12px;
  font: 600 var(--dc-size-label)/1.5 var(--dc-font-core);
  color: var(--dc-navy-700); background: var(--dc-navy-100);
  border-left: 3px solid var(--dc-navy-500); border-radius: var(--dc-radius-sm);
  padding: 10px 12px;
}
/* Unread rows carry a left rule and a heavier title — emphasis, never a second colour. */
#alerts-list .list-row.unread { background: var(--dc-navy-100); box-shadow: inset 3px 0 0 var(--dc-navy-500); }
#alerts-list .list-row.unread .r-title { font-weight: 700; }
#alerts-list .r-sub .a-source { font-weight: 700; }
#alerts-list .r-trailing { display: flex; align-items: center; gap: 8px; }
/* Preference rows: label + hint on the left, a switch on the right. */
.pref-row {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 12px 0; border-bottom: 1px solid var(--dc-border);
}
.pref-row:last-of-type { border-bottom: none; }
.pref-row .p-main { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; }
.pref-row .p-title { font: 600 var(--dc-size-body)/1.3 var(--dc-font-core); color: var(--dc-text-body); }
.pref-row .p-hint { font: 500 var(--dc-size-caption)/1.4 var(--dc-font-core); color: var(--dc-text-muted); }
.pref-row .p-extra { margin-top: 8px; }
.pref-row select { max-width: 22rem; }
.switch { flex: none; display: inline-flex; align-items: center; cursor: pointer; }
.switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.switch .track {
  width: 46px; height: 26px; border-radius: 999px; background: var(--dc-border-control);
  position: relative; transition: background .15s ease;
}
.switch .track::after {
  content: ''; position: absolute; top: 3px; left: 3px; width: 20px; height: 20px;
  border-radius: 50%; background: var(--dc-white); box-shadow: var(--dc-shadow-1);
  transition: transform .15s ease;
}
.switch input:checked + .track { background: var(--dc-teal-ink); }
.switch input:checked + .track::after { transform: translateX(20px); }
.switch input:focus-visible + .track { outline: 2px solid var(--dc-navy-500); outline-offset: 2px; }
.switch input:disabled + .track { opacity: .5; cursor: not-allowed; }

/* ---- Local marketplace (#/marketplace) ---- */
/* Price sits in the row's trailing slot; the mono face keeps a column of prices aligned. */
#classified-list .pill.mono { font-family: var(--dc-font-mono); letter-spacing: -0.02em; }
#classified-list .link-action, #business-list a { align-self: flex-start; }
#business-list .r-sub a { color: var(--dc-navy-700); }
#market-tabs { margin-top: 4px; }

/* Staleness / caution notice — amber, distinct from .msg.error which means a failure. */
.msg.warn {
  background: var(--dc-state-progress-bg); color: var(--dc-amber-ink);
  border: 1px solid var(--dc-amber-500); border-radius: var(--dc-radius-md);
  padding: 10px 13px; font: 500 var(--dc-size-label)/1.45 var(--dc-font-core);
  margin-bottom: 12px;
}

/* A checkbox inside a form label row: the generic input rules give inputs full width. */
.check-row { display: flex; align-items: center; gap: 8px; font-weight: 500; }
.check-row input[type="checkbox"] { width: auto; margin: 0; flex: none; }

/* K10: the municipality's own channels under the alert switches. */
.pref-group { font: 600 var(--dc-size-body)/1.3 var(--dc-font-core); margin: 16px 0 4px; }

/* B16: the sign-in screen's own language picker, under 'Continue as visitor'. */
.lang-gate { display: block; width: auto; margin: 12px auto 0; }

/* B6: the period picker sits at the right of the card head, at its natural width. */
#clusters-days { width: auto; margin-left: auto; flex: none; }

/* iOS zooms the page when a field under 16px takes focus, and stays zoomed: after signing in, the
   hub was about 7% wider than the phone (16/15), cutting off sign-out and the Account tab. On touch
   screens every field is at least 16px. Last in the file so it wins over #map-ward; the meter
   reading's 26px field is more specific and keeps its size. */
@media (pointer: coarse), (max-width: 760px) {
  input, textarea, select, #map-ward { font-size: 16px; }
}

/* P07: an interruption's update trail */
.card-navy .n-trail { list-style: none; margin: 4px 0 0; padding: 0; display: grid; gap: 2px; }
.card-navy .n-overdue { color: var(--dc-amber, #f5a623); font-weight: 600; }

/* P08: a returned document, and the decision letter printed at the counter */
.ind-returned { color: var(--dc-amber-600); }
.print-letter { margin-top: 10px; padding: 16px; border: 1px solid var(--dc-border, #d0d7de); border-radius: 8px; display: grid; gap: 8px; }
@media print {
  body.printing-letter * { visibility: hidden; }
  body.printing-letter #moc-letter, body.printing-letter #moc-letter * { visibility: visible; }
  body.printing-letter #moc-letter { position: absolute; inset: 0 auto auto 0; border: 0; }
}

/* ---- P40: reach ------------------------------------------------------------------------- */
.skip-link { position: absolute; left: 8px; top: -60px; z-index: 1000; padding: 10px 14px; border-radius: 8px; background: var(--dc-navy-700, #0b2545); color: #fff; font-weight: 700; text-decoration: none; }
.skip-link:focus { top: 8px; }
main:focus { outline: none; }
/* Text size: the type tokens scale; layout stays in place. */
html[data-text-size="large"] { --dc-size-title-1: 38px; --dc-size-title-2: 29px; --dc-size-headline: 22px; --dc-size-body-lg: 19px; --dc-size-body: 17px; --dc-size-label: 15px; --dc-size-caption: 14px; --dc-size-micro: 13px; }
html[data-text-size="largest"] { --dc-size-title-1: 42px; --dc-size-title-2: 32px; --dc-size-headline: 25px; --dc-size-body-lg: 21px; --dc-size-body: 19px; --dc-size-label: 17px; --dc-size-caption: 16px; --dc-size-micro: 15px; }
/* Touch targets: at least 44 px on a touch screen. */
@media (pointer: coarse) { .btn, .chip, select, .link-action { min-height: 44px; } }
/* Reduced motion: nothing slides or sweeps; the SOS hold counts down in words instead. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; }
  .loadbar-fill { animation: none; width: 100%; opacity: .5; }
  .sos-hold.holding .sos-hold-fill { width: 0; }
}
/* Chart axis labels sit in a fixed viewBox: scaling them with the text size makes month labels
   run together, and the chart already scales with the screen. */
html[data-text-size] .chart-axis { font-size: 12px; }
/* The DEMO pill sits in the balance card's corner; leave room so it never covers the amount. */
.balance-card:has(.demo-pill) { padding-top: calc(var(--dc-size-caption) + 26px); }

/* P01: messages from the municipality on a request */
.req-replies { margin-top: 14px; display: grid; gap: 8px; }
.req-reply-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.req-reply { padding: 10px 12px; border-radius: var(--dc-radius-md); background: var(--dc-surface-sunken); }
.req-reply.from-you { background: var(--dc-teal-100); }
.req-reply p { margin: 4px 0 0; }

/* P19: polls */
.poll { display: grid; gap: 8px; padding-block: 6px; }
.poll h3 { margin: 0; }


/* ==================================================================== polish (Oct 2026 review) */
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }

/* Header: the greeting and weather belong to the Hub. On every other page the band goes slim
   (logo · SOS · session), so a page's own title is the first thing under it. */
html.on-page header.site .greeting,
html.on-page header.site .weather-card,
html.on-page header.site #weather-chip { display: none !important; }
html.on-page header.site { padding-bottom: 14px; }
html.on-page header.site .header-inner { align-items: center; }

/* Page title: takes the row. It was squeezed into a two-line column beside Back to Hub. */
.page-header h2 { flex: 1 1 auto; min-width: 0; margin: 0; text-wrap: balance; }
/* With the rail or the tab bar on screen, "Back to Hub" repeats the navigation. */
.page-back { display: none; }

/* Visitor locks. Opacity .55 put labels at about 2.4:1. Keep full-contrast ink; the lock
   glyph says it needs an account. */
.dc-nav a.locked { opacity: 1; color: var(--dc-text-muted); }
.dc-nav .dc-nav-lock { display: inline-flex; width: 14px; height: 14px; color: var(--dc-text-muted); }
.dc-nav .dc-nav-lock.hidden { display: none; }
.dc-nav .dc-nav-lock .icon, .dc-nav .dc-nav-lock svg { width: 14px; height: 14px; display: block; }
.dc-rail a .dc-nav-lbl { flex: 1; min-width: 0; }
.do-tile.locked, .svc-tile.locked { opacity: 1; }
.do-tile.locked .do-label, .svc-tile.locked .svc-label { color: var(--dc-text-body); }
.mtile.locked > *:not(.mtile-head), .mtile.locked .mtile-head > *:not(.mtile-lock) { opacity: 1; }
.fy-card.locked .fy-big, .fy-card.locked .fy-sub { opacity: 1; color: var(--dc-text-muted); }

/* Section rhythm: an eyebrow sat flush against the cards above it. */
.home-block + .home-block { margin-top: 28px; }

/* SOS on the band's centre line. The action row is a true-centre grid, but on tablet and
   desktop it lived inside .header-side — a right-hand column only as wide as its content — so
   the SOS was centred in that column, not the band. Let the side take the full row; the
   weather card stays right-aligned beneath it. */
@media (min-width: 720px) {
  .header-side { flex: 1 1 100%; margin-left: 0; }
  .header-side .who.header-row { width: 100%; }
  .header-side .weather-card { align-self: flex-end; }
}
.sos-chip { min-width: 112px; min-height: 48px; }

/* A feature this app does not have, or an estate feature for a resident outside an estate
   (dc-api features.mjs, /me/residence). Server truth; separate from .hidden so the two never fight. */
.feature-off { display: none !important; }

/* ---- Store (#/store, #/orders): the app's own products. Tokens only, so each app's skin applies. ---- */
.store-layout { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: var(--dc-section-gap, 20px); align-items: start; margin-top: 12px; }
.store-steps { display: grid; gap: var(--dc-section-gap, 20px); min-width: 0; }
.store-step .card-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.store-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 12px; margin-top: 12px; }
.store-item { display: flex; flex-direction: column; gap: 10px; padding: 14px; border: 1px solid var(--dc-border); border-radius: var(--dc-radius-md); background: var(--dc-surface-card); min-width: 0; }
.store-item.chosen { border-color: var(--dc-action-primary); box-shadow: 0 0 0 1px var(--dc-action-primary) inset; }
.store-item.out { opacity: .6; }
.store-item-ico { align-self: flex-start; }
.store-item-body { flex: 1; min-width: 0; }
.store-item h3 { margin: 0 0 4px; font-size: var(--dc-size-body-lg); color: var(--dc-text-heading); text-wrap: balance; }
.store-item .hint { margin: 0 0 8px; }
.store-price { font-size: var(--dc-size-headline); font-weight: 700; color: var(--dc-text-heading); font-variant-numeric: tabular-nums; }
.store-per { font-size: var(--dc-size-label); font-weight: 500; color: var(--dc-text-muted); margin-left: 2px; }
.store-price-tbc { font-size: var(--dc-size-body); color: var(--dc-text-muted); }
.store-terms { margin: 6px 0 0; font-size: var(--dc-size-label); color: var(--dc-text-muted); }
.store-basket { position: sticky; top: calc(env(safe-area-inset-top, 0px) + 16px); }
.store-lines li { display: flex; justify-content: space-between; gap: 12px; }
.store-lines li > span:first-child { min-width: 0; overflow-wrap: anywhere; }
.store-totals { display: grid; grid-template-columns: 1fr auto; gap: 4px 12px; margin: 12px 0; font-variant-numeric: tabular-nums; }
.store-totals dt { color: var(--dc-text-muted); }
.store-totals dd { margin: 0; text-align: right; font-weight: 700; }
.store-accept { margin: 12px 0; padding: 12px; border-radius: var(--dc-radius-sm); background: var(--dc-surface-sunken); }
.store-accept .check { display: flex; gap: 8px; align-items: flex-start; margin-top: 8px; cursor: pointer; }
.store-accept .check input { flex: none; width: auto; margin: 3px 0 0; }
.store-accept .check span { flex: 1; text-align: left; }
.store-intro { margin: 0; }
.store-basket .btn.block { width: 100%; margin-top: 8px; }
.store-order-row { display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap; color: inherit; text-decoration: none; }
@media (max-width: 860px) {
  .store-layout { grid-template-columns: minmax(0, 1fr); }
  .store-basket { position: static; }
}

/* ---- Visitors (#/visitors): invite a visitor, and the PIN to pass on. Tokens only. ---- */
#visitors-body { display: grid; gap: var(--dc-section-gap, 20px); }
.visit-form { display: grid; gap: 12px; }
.visit-form label { display: grid; gap: 4px; font-weight: 600; font-size: var(--dc-size-label); color: var(--dc-text-heading); }
.visit-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 12px; align-items: end; }
/* One height for every field, whatever its type: tel, email and datetime inputs differ by default. */
.visit-form input:not([type="hidden"]), .visit-form select { width: 100%; box-sizing: border-box; min-height: 44px; margin: 0; }
.visit-form .btn { justify-self: start; }
.visit-pin-card { border: 2px solid var(--dc-action-primary); }
.vehicle-list .plate { letter-spacing: .06em; }
.visit-pin-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.visit-qr { margin: 16px 0 12px; display: flex; flex-direction: column; align-items: center; gap: 8px; }
.visit-qr svg { width: min(240px, 100%); height: auto; border-radius: 8px; }
.visit-pin { font-size: 44px; font-weight: 700; letter-spacing: .18em; margin: 8px 0 12px; color: var(--dc-text-heading); font-variant-numeric: tabular-nums; }
.visit-list li { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; }
.visit-list li > div:first-child { display: grid; min-width: 0; }
.visit-actions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }

/* Promotions banner on Home (promotions.mjs). */
.home-promo { margin: 20px 0 28px; position: relative; border-radius: 14px; overflow: hidden; background: var(--dc-surface-sunken); }
.home-promo .promo-track { position: relative; aspect-ratio: 16 / 7; max-width: 100%; }
.home-promo .promo-slide { position: absolute; inset: 0; opacity: 0; transition: opacity .4s ease; pointer-events: none; display: block; }
.home-promo .promo-slide.on { opacity: 1; pointer-events: auto; }
.home-promo .promo-slide img { width: 100%; height: 100%; object-fit: cover; display: block; }
.home-promo .promo-pill { position: absolute; top: 8px; left: 8px; background: rgba(0, 0, 0, .6); color: #fff; font-size: 12px; }
/* M36 (WCAG 2.5.8): each dot is a 24 px target; the one on show is larger as well as whiter. */
.home-promo .promo-dots { position: absolute; bottom: 4px; left: 0; right: 0; display: flex; justify-content: center; gap: 2px; pointer-events: none; }
.home-promo .promo-dots button { pointer-events: auto; width: 24px; height: 24px; border: 0; padding: 0; background: none; cursor: pointer; display: grid; place-items: center; }
.home-promo .promo-dots button::before { content: ''; width: 9px; height: 9px; border-radius: 50%; background: rgba(255, 255, 255, .65); box-shadow: 0 0 0 1px rgba(0, 0, 0, .4); }
.home-promo .promo-dots button[aria-current="true"]::before { width: 13px; height: 13px; background: #fff; }
.home-promo .promo-pause { position: absolute; right: 8px; bottom: 6px; min-height: 24px; padding: 3px 10px; border: 0; border-radius: var(--dc-radius-pill); background: rgba(0, 0, 0, .65); color: #fff; font: 700 var(--dc-size-caption)/1.2 var(--dc-font-core); cursor: pointer; }
/* Over a picture the ring is white with a dark edge, so it shows on any image. */
.home-promo :focus-visible { outline: 3px solid #fff; outline-offset: 0; box-shadow: 0 0 0 5px rgba(10, 36, 80, .9); }
@media (prefers-reduced-motion: reduce) { .home-promo .promo-slide { transition: none; } }
