/* ============================================================
   AlertCommunities — Accra Flood Intelligence Platform
   Palette (map profile):
     paper/bg  #F1EBE4 · #E2DCD3      tan accent  #BC8A52
     water     #95B1AA                panel grad  #A2AEA1→#7B988C→#4F8577
     accent    #618D7C (interactive)  near-white  #F3F4F1
     track     #ADC3B9 (borders)      ink         #2C3B36
   Station status colors (preserved):
     active #1FA97A · deploying #2D6CDF · planned #E8A33D · impact #C0392B
   ============================================================ */

:root{
  --cream:     #F1EBE4;
  --land:      #E2DCD3;
  --tan:       #BC8A52;
  --tan-light: #DEC29A;
  --water:     #95B1AA;
  --sage1:     #A2AEA1;
  --sage2:     #7B988C;
  --deep:      #4F8577;
  --deep-2:    #3F6E62;
  --accent:    #618D7C;
  --paper:     #F3F4F1;
  --track:     #ADC3B9;
  --ink:       #2C3B36;
  --ink-soft:  #5C6E66;
  --mintbg:    #E7EDE6;

  /* station status colors — do not change */
  --st-active:      #1FA97A;
  --st-deploying:   #2D6CDF;
  --st-planned:     #8C959A;   /* grey */
  --st-impact:      #C0392B;
  --st-maintenance: #1F262B;   /* black */

  /* legacy aliases (old palette names used inline in HTML) */
  --navy:  #2C3B36;
  --blue:  #618D7C;
  --amber: #BC8A52;
  --red:   #C0392B;
  --green: #1FA97A;
  --gray:  #5C6E66;
  --mint:  #E7EDE6;
  --line:  #ADC3B9;
  --bg:    #F1EBE4;

  --shadow:    0 8px 30px rgba(44,59,54,.16);
  --shadow-sm: 0 3px 12px rgba(44,59,54,.10);
  --radius:    14px;
  --font: Calibri, "Segoe UI", "Helvetica Neue", Arial, sans-serif;
  --header-h: 64px;
  /* Round-142 (motion P0): ONE motion vocabulary. Every duration and easing in the app comes
     from here; feature CSS references tokens, never literals, so the whole app speeds up, slows
     down or goes still together. dur-1 = a press, dur-2 = a page or panel, dur-3 = a card
     arriving, dur-4 = the longest anything is allowed to take. */
  --dur-1: 120ms;
  --dur-2: 180ms;
  --dur-3: 260ms;
  --dur-4: 420ms;
  --ease-out: cubic-bezier(.2, .7, .2, 1);
  --ease-in: cubic-bezier(.4, 0, 1, 1);
  --ease-spring: cubic-bezier(.34, 1.4, .64, 1);
  --skel-period: 1.4s;
  --skel-hi: rgba(255,255,255,.55);
  --panel-grad: linear-gradient(180deg, #7B988C 0%, #5C8A7B 55%, #4F8577 100%);
  --hero-grad:  linear-gradient(180deg, #A2AEA1 0%, #7B988C 48%, #4F8577 100%);
}

*{ box-sizing:border-box; margin:0; padding:0; }
html{ scroll-behavior:smooth; }

/* Round-142 (motion P0): the reduced-motion SAFETY NET. Until now every animated rule had to
   remember its own @media block (thirteen did; a dozen did not), so a person who asked their OS
   for less motion still got the composer sliding, the pin pulsing and the map sweeping. This
   finishes every animation and transition in a frame — END states are kept, so a one-shot
   entrance lands on its resting frame and a shimmer becomes a flat block — which is what
   "reduce" means, as opposed to `aqua-lowpower`'s blanket `none` for a phone that must last. */
@media (prefers-reduced-motion: reduce){
  *, ::before, ::after{
    animation-duration:.01ms !important; animation-iteration-count:1 !important;
    transition-duration:.01ms !important; scroll-behavior:auto !important;
  }
}
body{
  font-family:var(--font);
  color:var(--ink);
  background:var(--cream);
  line-height:1.55;
  -webkit-font-smoothing:antialiased;
}
img{ max-width:100%; display:block; }
a{ color:var(--deep); text-decoration:none; }
a:hover{ text-decoration:underline; }

/* ---------- Sign-up bar (round-69b): signed-out visitors, above both headers ----------
   Visibility is driven by html.signup-bar-on (set by site.js after the dismiss check) so
   Blazor DOM patches can't resurrect a dismissed bar. When on, --header-h grows to
   64px + bar height, which shifts every offset that hangs off it (page padding, map
   islands, side panels) without touching those rules. */
#signupBar{ display:none; }
/* --signup-h starts at the one-line height; site.js overwrites it with the bar's real
   measured height after reveal and on resize, so the sentence may wrap on phones and
   the headers still sit exactly below it */
html.signup-bar-on{ --signup-h: 46px; --header-h: calc(64px + var(--signup-h)); }
/* no entry animation: a transform keyframe replayed by Blazor's enhanced-nav DOM patches
   (or held at its first frame) parked the bar off-screen, leaving a blank strip above the
   header — the bar simply appears in place */
html.signup-bar-on #signupBar{
  display:flex; align-items:center; gap:10px;
  /* min-height is a CONSTANT, never var(--signup-h): the JS writes the bar's measured
     height into --signup-h, and deriving min-height from it fed the measurement back
     into itself — every resize event ratcheted the bar taller, ending in a full-screen
     white sheet that buried the map's service chips */
  position:fixed; top:0; left:0; right:0; min-height:40px; z-index:1200;
  padding:7px 12px; color:var(--ink);
  background:#fff;
  border-bottom:1px solid var(--track);
  box-shadow:0 2px 12px rgba(44,59,54,.14);
}
/* desktop: single line anyway — slim vertical padding so the bar stays unobtrusive */
@media (min-width: 768px){
  html.signup-bar-on #signupBar{ min-height:32px; padding:3px 12px; }
}
#signupBar .sb-ico{ flex:0 0 auto; display:inline-flex; color:#E8A33D; /* weather amber */ }
#signupBar .sb-ico svg{ width:20px; height:20px; }
#signupBar .sb-text{
  flex:1 1 auto; min-width:0;
  font-size:.9rem; line-height:1.35;
}
#signupBar .sb-text b{ font-weight:800; }
#signupBar .sb-link{
  color:#4F8577; font-weight:800; text-decoration:underline; text-underline-offset:2px;
  white-space:nowrap;
}
#signupBar .sb-link:hover{ color:#2C3B36; }
#signupBar .sb-short{ display:none; }
@media (max-width: 720px){
  #signupBar .sb-msg{ display:none; }
  #signupBar .sb-short{ display:inline; }
}
#signupBar .sb-close{
  flex:0 0 auto; align-self:flex-start; background:transparent; border:0; color:inherit;
  opacity:.55; font-size:1rem; cursor:pointer; padding:4px 8px;
}
#signupBar .sb-close:hover{ opacity:1; }

/* ---------- Header / Nav ---------- */
.site-header{
  position:fixed; top:var(--signup-h, 0px); left:0; right:0; z-index:1100;
  height:64px;   /* literal: --header-h is header + sign-up bar when the bar shows */
  /* Round-146f (owner's call): solid white, no translucency — the paper tint at 95% read as
     "partially white" over a white page, and the blur is not needed on an opaque bar */
  background:#fff;
  color:var(--ink);
  display:flex; align-items:center;
  padding:0 20px;
  box-shadow:0 2px 14px rgba(44,59,54,.12);
  border-bottom:1px solid var(--track);
}
.brand{ display:flex; align-items:center; gap:10px; color:var(--ink); font-weight:700; font-size:1.25rem; letter-spacing:.3px; }
.brand:hover{ text-decoration:none; }
.brand svg{ width:36px; height:36px; flex:0 0 auto; }
.brand .tag{ display:block; font-size:.62rem; font-weight:400; color:var(--sage2); letter-spacing:1.6px; text-transform:uppercase; margin-top:-3px; }

.nav{ margin-left:auto; display:flex; align-items:center; gap:4px; }
.nav a{
  color:var(--ink-soft); padding:9px 13px; border-radius:8px; font-size:.98rem;
  transition:background .15s, color .15s;
}
.nav a:hover{ background:rgba(97,141,124,.12); color:var(--ink); text-decoration:none; }
.nav a.active{ color:var(--paper); background:var(--accent); }
.nav .btn{ margin-left:8px; }

.nav-toggle{
  display:none; margin-left:auto; background:none; border:0; color:var(--ink);
  width:44px; height:44px; cursor:pointer; font-size:1.5rem; line-height:1;
}

/* ---------- Buttons ---------- */
.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:8px;
  padding:11px 20px; border-radius:10px; border:0; cursor:pointer;
  font-family:var(--font); font-size:1rem; font-weight:700; letter-spacing:.2px;
  transition:transform .12s, box-shadow .15s, background .15s;
  text-decoration:none !important;
}
.btn:active{ transform:translateY(1px); }
.btn svg{ width:18px; height:18px; flex:0 0 auto; }
.btn-amber{ background:var(--tan); color:#fff!important; }
.btn-amber:hover{ background:#c99a63; box-shadow:0 4px 16px rgba(188,138,82,.45); }
.btn-blue{ background:var(--accent); color:var(--paper); }
.btn-blue:hover{ background:#6d9b89; box-shadow:0 4px 16px rgba(97,141,124,.45); }
.btn-green{ background:var(--deep); color:var(--paper); }
.btn-green:hover{ background:#5b937f; box-shadow:0 4px 16px rgba(79,133,119,.4); }
.btn-outline{ background:transparent; color:var(--paper); border:2px solid rgba(243,244,241,.6); }
.btn-outline:hover{ border-color:var(--paper); background:rgba(243,244,241,.1); }
.btn-outline-dark{ background:transparent; color:var(--deep); border:2px solid var(--deep); }
.btn-outline-dark:hover{ background:var(--deep); color:var(--paper); }
.btn-red{ background:var(--st-impact); color:#fff; }
.btn-red:hover{ background:#d64536; }
.btn-grey{ background:#8C959A; color:#fff!important; }
.btn-grey:hover{ background:#7b858b; box-shadow:0 4px 16px rgba(140,149,154,.45); }
.btn-lg{ padding:15px 28px; font-size:1.1rem; border-radius:12px; }
.btn-sm{ padding:7px 14px; font-size:.88rem; }
.btn-block{ width:100%; }

/* ---------- Layout helpers ---------- */
.page{ padding-top:var(--header-h); }
.container{ max-width:1120px; margin:0 auto; padding:0 20px; }
.section{ padding:64px 0; }
.section.tint{ background:var(--paper); }
.section.navy{ background:var(--panel-grad); color:var(--paper); }
.section.mint{ background:var(--mintbg); }

.kicker{
  display:inline-block; font-size:.78rem; font-weight:700; letter-spacing:2.2px;
  text-transform:uppercase; color:var(--deep); margin-bottom:10px;
}
.section.navy .kicker, .hero-inner .kicker{ color:var(--tan-light); }
h1.display{ font-size:clamp(2rem,5vw,3.2rem); line-height:1.12; color:var(--ink); }
.section.navy h1.display, .section.navy h2{ color:var(--paper); }
h2.title{ font-size:clamp(1.5rem,3.4vw,2.2rem); color:var(--ink); margin-bottom:14px; }
h3{ color:var(--ink); }
.section.navy h3{ color:var(--paper); }
.lead{ font-size:1.13rem; color:var(--ink-soft); max-width:760px; }
.section.navy .lead{ color:#E3EAE2; }
.center{ text-align:center; }
.center .lead{ margin:0 auto; }

.grid{ display:grid; gap:22px; }
.grid-2{ grid-template-columns:repeat(2,1fr); }
.grid-3{ grid-template-columns:repeat(3,1fr); }
.grid-4{ grid-template-columns:repeat(4,1fr); }

.card{
  background:var(--paper); border-radius:var(--radius); padding:26px;
  box-shadow:var(--shadow-sm); border:1px solid var(--track);
}
.card h3{ margin-bottom:8px; font-size:1.12rem; }
.card p{ color:var(--ink-soft); font-size:.98rem; }
.card .icon{
  width:46px; height:46px; border-radius:12px; display:flex; align-items:center;
  justify-content:center; background:var(--mintbg); margin-bottom:14px;
}
.card .icon svg{ width:24px; height:24px; stroke:var(--accent); fill:none; stroke-width:2; stroke-linecap:round; stroke-linejoin:round; }

/* stat blocks (on deep panels) */
.stats-row{ display:grid; grid-template-columns:repeat(3,1fr); gap:18px; margin-top:34px; }
.stat{
  background:rgba(243,244,241,.10); border:1px solid rgba(243,244,241,.24);
  border-radius:var(--radius); padding:20px 22px; text-align:left;
}
.stat .num{ font-size:2rem; font-weight:800; color:var(--tan-light); line-height:1.1; }
.stat .lbl{ font-size:.92rem; color:#DCE5DD; margin-top:4px; }
.stat .lbl a{ color:var(--tan-light); }

/* ---------- Hero (inner pages) ---------- */
.hero-inner{
  background:var(--hero-grad);
  color:var(--paper); padding:72px 0 56px;
  position:relative; overflow:hidden;
}
.hero-inner::after{
  content:""; position:absolute; right:-120px; bottom:-160px; width:420px; height:420px;
  border-radius:50%; background:radial-gradient(circle, rgba(241,235,228,.22), transparent 65%);
  pointer-events:none; /* decorative: on phones it lay over the pricing Annual button and ate the tap */
}
.hero-inner .lead{ color:#E9EEE7; margin-top:12px; }
.hero-inner h1{ color:var(--paper); font-size:clamp(1.9rem,4.6vw,2.9rem); line-height:1.15; }
.hero-inner b{ color:#fff; }
.hero-cta{ display:flex; flex-wrap:wrap; gap:12px; margin-top:26px; position:relative; z-index:1; }

/* ---------- Tables ---------- */
.table-wrap{ overflow-x:auto; border-radius:var(--radius); box-shadow:var(--shadow-sm); }
table.pro{ width:100%; border-collapse:collapse; background:var(--paper); min-width:520px; }
table.pro th{
  background:var(--deep); color:var(--paper); text-align:left; padding:13px 16px;
  font-size:.92rem; letter-spacing:.4px;
}
table.pro td{ padding:12px 16px; border-bottom:1px solid #DCE3DC; font-size:.96rem; color:var(--ink); }
table.pro tr:nth-child(even) td{ background:#ECEFEA; }
table.pro td.good{ color:var(--deep); font-weight:700; }
table.pro td.bad{ color:var(--st-impact); }

/* ---------- Forms ---------- */
.form-card{ background:var(--paper); border-radius:var(--radius); padding:30px; box-shadow:var(--shadow); border:1px solid var(--track); }
.field{ margin-bottom:18px; }
.field label{ display:block; font-weight:700; color:var(--ink); margin-bottom:6px; font-size:.95rem; }
.field input, .field select, .field textarea{
  width:100%; padding:12px 14px; border:1.5px solid var(--track); border-radius:10px;
  font-family:var(--font); font-size:1rem; color:var(--ink); background:#FBFBF8;
  transition:border-color .15s, box-shadow .15s;
}
.field input:focus, .field select:focus, .field textarea:focus{
  outline:none; border-color:var(--accent); box-shadow:0 0 0 3px rgba(97,141,124,.18);
}
.field textarea{ min-height:120px; resize:vertical; }
.field .hint{ font-size:.83rem; color:var(--ink-soft); margin-top:5px; }
.form-note{
  background:var(--mintbg); border:1px solid #C4D4C8; color:#2F5B4C;
  padding:14px 16px; border-radius:10px; font-size:.93rem; margin-top:16px; display:none;
}
.form-note.show{ display:block; }

/* choice chips */
.chip-row{ display:flex; flex-wrap:wrap; gap:10px; }
.chip{
  padding:10px 18px; border-radius:999px; border:1.5px solid var(--track); background:var(--paper);
  cursor:pointer; font-family:var(--font); font-weight:700; font-size:.95rem; color:var(--ink);
  transition:all .15s;
}
.chip:hover{ border-color:var(--accent); }
.chip.sel{ background:var(--accent); border-color:var(--accent); color:var(--paper); }
.chip.sel-amber{ background:var(--tan); border-color:var(--tan); color:#fff; }
.chip.sel-red{ background:var(--st-impact); border-color:var(--st-impact); color:#fff; }

/* ---------- Status pills (status colors preserved) ---------- */
.pill{
  display:inline-flex; align-items:center; gap:7px; padding:4px 12px; border-radius:999px;
  font-size:.8rem; font-weight:700; letter-spacing:.4px; text-transform:uppercase;
}
.pill .dot{ width:9px; height:9px; border-radius:50%; }
.pill-active   { background:rgba(31,169,122,.14); color:#0d7d58; }
.pill-active   .dot{ background:var(--st-active); }
.pill-deploying{ background:rgba(45,108,223,.13); color:#1c4fb0; }
.pill-deploying .dot{ background:var(--st-deploying); }
.pill-planned  { background:rgba(232,163,61,.18); color:#996414; }
.pill-planned  .dot{ background:var(--st-planned); }
.pill-maintenance{ background:rgba(91,100,114,.15); color:#454d59; }
.pill-maintenance .dot{ background:var(--st-maintenance); }
.pill-impact{ background:rgba(192,57,43,.12); color:var(--st-impact); }
.pill-impact .dot{ background:var(--st-impact); }

/* ============================================================
   MAP PAGE (home)
   ============================================================ */
.map-page{ height:var(--app-h, 100vh); height:var(--app-h, 100dvh); overflow:hidden; }
#map{
  position:fixed; top:0; left:0; right:0; bottom:0; /* map runs under the transparent map nav */
  background:var(--land);
  z-index:1;
}
.leaflet-container{ font-family:var(--font); }

/* floating UI cards over map — "panel rising from the map" */
.map-ui{ position:fixed; z-index:900; }
.map-card{
  background:var(--panel-grad);
  border:1px solid rgba(243,244,241,.3); border-radius:14px;
  color:var(--paper); /* round-15c: box-shadow removed */
}

/* network stats — top left */
.net-stats{ top:calc(var(--header-h) + 14px); left:14px; width:250px; padding:16px 18px; }
.net-stats h2{ font-size:.8rem; letter-spacing:2px; text-transform:uppercase; color:var(--tan-light); margin-bottom:10px; }
.net-grid{ display:grid; grid-template-columns:1fr 1fr; gap:10px; }
.net-item .n{ font-size:1.5rem; font-weight:800; line-height:1.05; }
.net-item .l{ font-size:.74rem; color:#DCE5DD; letter-spacing:.3px; }
.n-active{ color:#8FF2CB; } .n-deploying{ color:#A9C6FF; } .n-planned{ color:#FFD9A0; } .n-impact{ color:#FFB1A6; }
.net-foot{ margin-top:12px; padding-top:10px; border-top:1px solid rgba(243,244,241,.25);
  font-size:.78rem; color:#DCE5DD; }

/* legend + filters — bottom left */
.legend{ bottom:18px; left:14px; padding:14px 16px; max-width:250px; }
.legend h3{ font-size:.75rem; letter-spacing:2px; text-transform:uppercase; color:#DCE5DD; margin-bottom:9px; }
.legend .row{
  display:flex; align-items:center; gap:9px; padding:5px 8px; border-radius:8px;
  cursor:pointer; font-size:.88rem; user-select:none; border:1px solid transparent; color:var(--paper);
}
.legend .row:hover{ background:rgba(243,244,241,.14); }
.legend .row.off{ opacity:.4; }
.legend .swatch{ width:14px; height:14px; border-radius:50%; border:2px solid #fff; flex:0 0 auto; }
.sw-active{ background:var(--st-active); } .sw-deploying{ background:var(--st-deploying); }
.sw-planned{ background:var(--st-planned); } .sw-maintenance{ background:var(--st-maintenance); }
.legend .impact-note{ display:flex; align-items:center; gap:9px; margin-top:8px; padding:6px 8px;
  font-size:.78rem; color:#FFC9C1; border-top:1px solid rgba(243,244,241,.25); }
.legend .impact-ring{ width:14px; height:14px; border-radius:50%; border:2.5px dashed var(--st-impact); flex:0 0 auto; background:rgba(255,255,255,.7); }

/* action buttons — top right */
/* Round-94: the container now carries ONLY the relocated zoom control. Bottom-left, above the
   legal strip — the one corner free on every width: the legend is top-left, the right rail is
   centred right (its expanded Layers card was colliding with the zoom on iPad landscape), and
   the time bands are centred bottom. */
.map-actions{ bottom:44px; left:14px; display:flex; flex-direction:column; gap:10px; align-items:flex-start; }
.map-actions .btn{ box-shadow:0 6px 20px rgba(44,59,54,.3); }

.leaflet-bottom.leaflet-right .leaflet-control-attribution{
  background:rgba(243,244,241,.85); color:var(--ink-soft);
}
.leaflet-control-attribution a{ color:var(--deep); }
.leaflet-control-zoom a{
  background:var(--deep) !important; color:var(--paper) !important;
  border-color:rgba(243,244,241,.35) !important;
}
.leaflet-control-zoom a:hover{ background:var(--deep-2) !important; }
/* Round-186: Leaflet's zoom buttons are <a href="#">, so the global `a:hover{ underline }` at
   the top of this file draws a line under the + and the −. On a touch screen the hover state
   sticks after a tap, so the line stays until something else is touched. Every map in the app
   uses this control, so the fix belongs here rather than beside one of them. */
.leaflet-control-zoom a:hover,
.leaflet-control-zoom a:active,
.leaflet-control-zoom a:focus{ text-decoration:none; }
/* zoom control is relocated into .map-actions by map-engine (below the quick actions) */
.map-actions .leaflet-control-zoom{ margin:0; }

/* station markers — status colors preserved */
.st-marker{
  width:22px; height:22px; border-radius:50%;
  border:2.5px solid #fff; box-shadow:0 2px 8px rgba(44,59,54,.45);
  position:relative;
}
.st-marker.impact::after{
  content:""; position:absolute; inset:-7px; border-radius:50%;
  border:2.5px dashed var(--st-impact);
}
.st-marker.active    { background:var(--st-active); }
.st-marker.deploying { background:var(--st-deploying); }
.st-marker.planned   { background:var(--st-planned); }
.st-marker.maintenance{ background:var(--st-maintenance); }
.st-marker.active .ping{
  content:""; position:absolute; inset:-4px; border-radius:50%;
  border:2px solid var(--st-active); animation:ping 2.2s ease-out infinite;
}
@keyframes ping{ 0%{ transform:scale(.7); opacity:.9; } 100%{ transform:scale(2.1); opacity:0; } }

.leaflet-tooltip.st-tip{
  background:var(--tip-bg, var(--deep)); color:var(--tip-fg, var(--paper)); border:1px solid rgba(243,244,241,.4);
  border-radius:8px; font-family:var(--font); font-weight:700; padding:6px 11px;
  box-shadow:0 4px 14px rgba(44,59,54,.35);
}
.leaflet-tooltip.st-tip::before{ border-top-color:var(--tip-bg, var(--deep)); }
.leaflet-tooltip-bottom.st-tip::before{ border-top-color:transparent; border-bottom-color:var(--tip-bg, var(--deep)); }
.leaflet-tooltip-left.st-tip::before{ border-top-color:transparent; border-left-color:var(--tip-bg, var(--deep)); }
.leaflet-tooltip-right.st-tip::before{ border-top-color:transparent; border-right-color:var(--tip-bg, var(--deep)); }

/* ---------- Station detail panel ---------- */
.station-panel{
  position:fixed; top:var(--header-h); right:0; bottom:0; width:400px; max-width:100%;
  background:var(--paper); z-index:1000; box-shadow:-12px 0 40px rgba(44,59,54,.3);
  transform:translateX(105%); transition:transform .3s cubic-bezier(.2,.8,.25,1);
  display:flex; flex-direction:column;
}
.station-panel.open{ transform:translateX(0); }
.sp-head{ background:var(--panel-grad); color:var(--paper); padding:20px 22px 18px; position:relative; }
.sp-head h2{ font-size:1rem; text-transform:uppercase; margin:8px 0 3px; color:var(--paper); }
.sp-head .sub{ color:#DCE5DD; font-size:.88rem; }
.sp-close{
  position:absolute; top:14px; right:14px; background:rgba(243,244,241,.2); color:var(--paper);
  border:0; width:34px; height:34px; border-radius:50%; font-size:1.15rem; cursor:pointer;
}
.sp-close:hover{ background:rgba(243,244,241,.35); }
.sp-body{ flex:1; overflow-y:auto; padding:20px 22px 30px; }
.sp-body h4{ font-size:.78rem; letter-spacing:1.8px; text-transform:uppercase; color:var(--sage2); margin:22px 0 10px; }
.sp-body h4:first-child{ margin-top:0; }

.sp-metrics{ display:grid; grid-template-columns:1fr 1fr; gap:12px; }
.sp-metric{ background:var(--mintbg); border:1px solid var(--track); border-radius:12px; padding:12px 14px; }
.sp-metric .v{ font-size:1.35rem; font-weight:800; color:var(--ink); line-height:1.1; }
.sp-metric .v small{ font-size:.8rem; font-weight:600; color:var(--ink-soft); }
.sp-metric .k{ font-size:.78rem; color:var(--ink-soft); margin-top:2px; }
.sp-metric.warn .v{ color:var(--st-impact); }

.sp-chart{ background:var(--mintbg); border:1px solid var(--track); border-radius:12px; padding:14px; }
.sp-chart svg{ width:100%; height:110px; display:block; }
.sp-chart .cap{ font-size:.78rem; color:var(--ink-soft); margin-top:6px; display:flex; justify-content:space-between; }

.sp-img{ border-radius:12px; overflow:hidden; border:1px solid var(--track); }
.sp-img img{ width:100%; height:190px; object-fit:cover; display:block; }
.sp-img .cap{ font-size:.78rem; color:var(--ink-soft); padding:8px 12px; background:var(--mintbg); }

.sp-kv{ font-size:.92rem; }
.sp-kv div{ display:flex; justify-content:space-between; gap:12px; padding:7px 0; border-bottom:1px dashed var(--track); }
.sp-kv .k{ color:var(--ink-soft); }
.sp-kv .v{ font-weight:700; color:var(--ink); text-align:right; }

.sp-alertbox{ border-radius:12px; padding:13px 15px; font-size:.92rem; margin-top:10px; }
.sp-alertbox.ok{ background:var(--mintbg); color:#2F5B4C; border:1px solid #C4D4C8; }
.sp-alertbox.warn{ background:#F3E9D8; color:#7A5A22; border:1px solid #DECBA4; }
.sp-alertbox.danger{ background:#F4E3E0; color:#8e2a1f; border:1px solid #E2BFB9; }

.sp-cta{ display:flex; gap:10px; margin-top:22px; }
.sp-cta .btn{ flex:1; }

/* ---------- Footer ---------- */
/* Round-142f (owner's call): the site footer is gone from every page. The rules below stay for
   the day it returns; the map keeps its small .map-legal strip (the privacy link Google's OAuth
   verification requires lives there). */
.site-footer{ display:none !important; }
.site-footer{ background:linear-gradient(180deg, var(--deep) 0%, var(--deep-2) 100%); color:#DCE5DD; padding:54px 0 26px; }
.site-footer h4{ color:var(--paper); font-size:1rem; margin-bottom:14px; letter-spacing:.5px; }
.foot-grid{ display:grid; grid-template-columns:2fr 1fr 1fr 1.4fr; gap:34px; }
.site-footer a{ color:#DCE5DD; display:block; padding:4px 0; font-size:.95rem; }
.site-footer a:hover{ color:#fff; }
.foot-brand{ display:flex; align-items:center; gap:10px; color:var(--paper); font-weight:700; font-size:1.2rem; margin-bottom:12px; }
.foot-brand svg{ width:32px; height:32px; }
.foot-note{ font-size:.9rem; color:#C9D6CB; max-width:340px; }
.foot-bottom{
  border-top:1px solid rgba(243,244,241,.22); margin-top:40px; padding-top:20px;
  display:flex; flex-wrap:wrap; gap:10px; justify-content:space-between; font-size:.85rem; color:#C9D6CB;
}
/* Round-84: the accent footer is DESKTOP-ONLY — on phones and tablets (and therefore inside
   the mobile app's WebView, which is always phone-width) it does not render at all. The two
   things that lived only there move surfaces on small screens: the language switcher goes to
   the nav grid menu (.grid-lang below), and the privacy link remains satisfied by the
   homepage's persistent legal strip. */
@media (max-width:1024px){
  .site-footer{ display:none; }
}
/* Round-85: SafeNet presence freshness. The colour IS the message — a glance must answer
   "is this where they are now?" without reading the words. */
.pres-dot{ display:inline-block; width:8px; height:8px; border-radius:50%; margin-right:6px;
           vertical-align:middle; background:var(--track, #ADC3B9); }
.pres-live{ background:#2E9E5B; box-shadow:0 0 0 3px rgba(46,158,91,.18); }
.pres-recent{ background:#8FB98C; }
.pres-stale{ background:#C9A227; }
.pres-paused{ background:#9AA3A0; }
.pres-none{ background:var(--track, #ADC3B9); }

/* Round-84 native-feel: app-scoped touch polish. html.in-app is set by site.js when the page
   runs inside the mobile app's WebView — browsers are untouched. */
.in-app *{ -webkit-tap-highlight-color: transparent; }
/* Round-97: this used to sit on `body` alone, which is why Android kept pull-to-refresh — unlike
   `overflow`, `overscroll-behavior` is NOT propagated from body to the viewport, so the root
   scroller never saw it and a downward drag on the map reloaded the page. It has to be on the
   root element. `contain` on the map shell stops a drag that starts inside a scrollable panel
   from chaining out to the document once that panel hits its end. */
html.in-app, .in-app body{ overscroll-behavior-y: none; }
html.in-app .leaflet-container, html.in-app .station-panel{ overscroll-behavior: contain; }

/* Round-97 keyboard contract. site.js publishes both of these whenever a soft keyboard opens:
     html.kb-open  — a keyboard is up;  --kb is its height in px
     html.kb-lock  — ...and the page underneath is a fixed full-screen surface, so the document
                     must not move. Set only for those surfaces: freezing an ordinary form page
                     would put half its fields out of reach while the user is typing.
   Anything that needs to sit above the keys can reserve space with var(--kb, 0px). */
html.kb-lock, html.kb-lock body{ overflow:hidden; }
/* Round-93b: an inline icon beside a heading. OutlineIcons.Svg carries no width/height on
   purpose (nav containers size it), so anywhere without a sized container must supply one or the
   SVG fills the line. */
.plat-ico{ width:22px; height:22px; flex:none; display:inline-flex; }
.plat-ico svg{ width:100%; height:100%; display:block; }

/* Anything that makes no sense INSIDE the app (e.g. "Get the app") carries .web-only. */
.in-app .web-only{ display:none !important; }
/* ...and its mirror: controls only the APP can honour (native sensing switches). */
.app-only{ display:none; }
.in-app .app-only{ display:block; }
/* Round-93b: platform-specific copy inside app-only content (the wizard's Settings steps name
   real OS toggles, and the two platforms name them differently). Default = Android wording, so
   an app build too old to set the platform class still reads something rather than nothing. */
.ios-only{ display:none; }
.plat-ios .ios-only{ display:revert; }
.plat-ios .android-only{ display:none !important; }
/* /get-app: the desktop→phone handoff QR. Phones don't need to scan themselves. */
.getapp-qr{ display:none; }
@media (min-width:1025px){
  .getapp-qr{ display:flex; align-items:center; gap:14px; margin-top:16px; }
  .getapp-qr img{ border-radius:10px; border:1px solid var(--track, #ADC3B9); }
}

/* Language row inside the nav grid menu. Round-84 gated it to small screens, where the footer
   was absent; round-142f hid the footer everywhere, so the menu is the switcher's home on every
   width now. grid-column 1/-1: .grid-menu is itself a 3-column tile grid, and without this the
   whole language block gets squeezed into a single tile cell (same trick as .grid-base). */
.grid-lang{ display:block; grid-column:1/-1; border-top:1px solid var(--track, #ADC3B9); margin-top:6px; padding-top:10px; }
.grid-lang-row{ display:grid; grid-template-columns:repeat(3, 1fr); gap:2px 8px; font-size:.82rem; margin:0; }
/* Override the tile styling .grid-menu a applies — these are compact text links, not tiles. */
.grid-lang-row a{ display:block; flex-direction:row; text-align:start; padding:6px 4px; font-weight:600; border-radius:8px; }
.sdg-row{ display:flex; gap:8px; margin-top:14px; flex-wrap:wrap; }
.sdg{
  width:75px; height:52px; border-radius:8px; color:#fff; font-weight:800;
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  font-size:.66rem; text-align:center; line-height:1.15; padding:3px;
}
.sdg b{ font-size:.95rem; }
.sdg-9 { background:#F36D25; } .sdg-11{ background:#F99D26; }
.sdg-13{ background:#3F7E44; } .sdg-17{ background:#19486A; }

/* partner logo strip */
.logo-strip{ display:flex; flex-wrap:wrap; gap:14px; align-items:center; justify-content:center; }
.logo-chip{
  background:#fff; border:1px solid var(--track); border-radius:12px; padding:14px 22px;
  font-weight:800; color:var(--ink); font-size:1rem; letter-spacing:.4px;
  box-shadow:var(--shadow-sm); display:flex; align-items:center; gap:12px;
}
.logo-chip small{ display:block; font-weight:600; color:var(--ink-soft); font-size:.72rem; letter-spacing:.2px; }
.logo-chip .mark{ width:38px; height:38px; border-radius:9px; display:flex; align-items:center; justify-content:center;
  background:var(--deep); color:var(--paper); font-size:.85rem; font-weight:900; flex:0 0 auto; }
.logo-chip img{ width:38px; height:38px; object-fit:contain; flex:0 0 auto; }

/* timeline */
.timeline{ position:relative; margin:26px 0; padding-left:26px; }
.timeline::before{ content:""; position:absolute; left:8px; top:6px; bottom:6px; width:3px; border-radius:3px;
  background:linear-gradient(var(--accent), var(--tan)); }
.tl-item{ position:relative; padding:0 0 24px 18px; }
.tl-item::before{ content:""; position:absolute; left:-25px; top:5px; width:15px; height:15px; border-radius:50%;
  background:var(--accent); border:3px solid var(--paper); box-shadow:0 0 0 2px var(--accent); }
.tl-item.amber::before{ background:var(--tan); box-shadow:0 0 0 2px var(--tan); }
.tl-item.red::before{ background:var(--st-impact); box-shadow:0 0 0 2px var(--st-impact); }
.tl-item.green::before{ background:var(--st-active); box-shadow:0 0 0 2px var(--st-active); }
.tl-item .t{ font-weight:800; color:var(--ink); font-size:1.02rem; }
.tl-item p{ color:var(--ink-soft); font-size:.96rem; margin-top:3px; }

/* architecture diagram */
.arch{ display:flex; flex-direction:column; align-items:center; gap:0; }
.arch-box{
  background:var(--paper); border:2px solid var(--accent); color:var(--ink); font-weight:700;
  border-radius:12px; padding:13px 26px; text-align:center; min-width:230px; box-shadow:var(--shadow-sm);
}
.arch-box small{ display:block; font-weight:600; color:var(--ink-soft); font-size:.8rem; }
.arch-box.amber{ border-color:var(--tan); }
.arch-box.green{ border-color:var(--deep); }
.arch-arrow{ color:var(--accent); font-size:1.3rem; line-height:1; padding:6px 0; font-weight:800; }

/* donation summary strip (on hero gradient) */
.impact-strip{ display:grid; grid-template-columns:repeat(3,1fr); gap:16px; margin-top:26px; position:relative; z-index:1; }
.impact-strip .box{ background:rgba(243,244,241,.14); border:1px solid rgba(243,244,241,.28);
  border-radius:12px; padding:16px; }
.impact-strip .n{ font-weight:800; font-size:1.5rem; color:var(--tan-light); }
.impact-strip .l{ font-size:.86rem; color:#E3EAE2; }

/* deploy tier cards */
.tier{ position:relative; display:flex; flex-direction:column; }
.tier .price{ font-size:2rem; font-weight:800; color:var(--ink); margin:6px 0 2px; }
.tier .price small{ font-size:.95rem; color:var(--ink-soft); font-weight:600; }
.tier ul{ list-style:none; margin:14px 0 20px; flex:1; }
.tier li{ padding:6px 0 6px 26px; position:relative; color:var(--ink-soft); font-size:.95rem; }
.tier li::before{ content:"✓"; position:absolute; left:0; color:var(--accent); font-weight:900; }
.tier.featured{ border:2.5px solid var(--tan); box-shadow:0 12px 34px rgba(188,138,82,.28); }
.tier .flag{ position:absolute; top:-13px; left:50%; transform:translateX(-50%);
  background:var(--tan); color:#fff; font-size:.72rem; font-weight:800; letter-spacing:1.4px;
  text-transform:uppercase; padding:4px 14px; border-radius:999px; }

/* FAQ */
details.faq{ background:var(--paper); border:1px solid var(--track); border-radius:12px; padding:0 20px; margin-bottom:12px; }
details.faq summary{ cursor:pointer; font-weight:700; color:var(--ink); padding:16px 0; list-style:none; position:relative; padding-right:30px; }
details.faq summary::after{ content:"+"; position:absolute; right:2px; top:12px; font-size:1.4rem; color:var(--accent); }
details.faq[open] summary::after{ content:"–"; }
details.faq p{ color:var(--ink-soft); padding-bottom:16px; font-size:.97rem; }

/* ============================================================
   Responsive
   ============================================================ */
@media (max-width: 900px){
  .grid-3, .grid-4{ grid-template-columns:repeat(2,1fr); }
  .foot-grid{ grid-template-columns:1fr 1fr; }
  .net-stats{ left:12px; top:calc(var(--header-h) + 12px); width:210px; padding:13px 14px; }
  .net-item .n{ font-size:1.25rem; }
}

@media (max-width: 720px){
  .nav{
    position:fixed; top:var(--header-h); right:0; left:0; z-index:1099;
    background:var(--deep); flex-direction:column; align-items:stretch; gap:2px;
    padding:12px 16px 18px; box-shadow:0 14px 24px rgba(44,59,54,.35);
    display:none;
  }
  .nav.open{ display:flex; }
  .nav a{ padding:13px 14px; font-size:1.05rem; color:#E3EAE2; }
  .nav a:hover{ background:rgba(243,244,241,.12); color:#fff; }
  .nav a.active{ background:rgba(243,244,241,.2); color:#fff; }
  .nav .btn{ margin-left:0; margin-top:8px; }
  .nav-toggle{ display:block; }

  .grid-2, .grid-3, .grid-4{ grid-template-columns:1fr; }
  .stats-row{ grid-template-columns:1fr; }
  .impact-strip{ grid-template-columns:1fr; }
  .foot-grid{ grid-template-columns:1fr; gap:24px; }
  .section{ padding:46px 0; }

  /* map UI on mobile */
  .net-stats{ width:auto; right:12px; }
  .net-grid{ grid-template-columns:repeat(4,1fr); gap:6px; }
  .net-item .l{ font-size:.62rem; }
  .net-foot{ display:none; }
  .map-actions{
    top:auto; bottom:14px; right:12px; left:12px;
    flex-direction:row; justify-content:stretch;
  }
  .map-actions .btn{ flex:1; padding:12px 8px; font-size:.9rem; }
  .map-actions .btn svg{ width:15px; height:15px; }
  .legend{ bottom:76px; left:12px; padding:10px 12px; max-width:170px; }
  .legend .row{ font-size:.8rem; padding:4px 6px; }
  .leaflet-top.leaflet-left .leaflet-control-zoom{ display:none; }

  /* Round-85: z-index above the header (1100) and the sign-up bar (1200), on MOBILE ONLY.
     On desktop the panel is a side drawer starting at top:var(--header-h), so it never reaches
     the header and 1000 is correct — the deliberate stacking noted at p4.css:541 (the map FAB at
     900 passing behind it) depends on that and is left alone.
     As a bottom sheet it is 78dvh tall, which on a short screen like an iPhone SE reaches into
     the header band — and the first thing to disappear under it is .sp-head, which carries the
     CLOSE BUTTON. A panel you cannot dismiss is worse than one you cannot fully read. */
  /* Round-97: full screen on a phone, where it used to be a 78dvh bottom sheet. At 78dvh the
     body below .sp-head was only ~300px on a short screen and the hero image, the meta rows and
     the comment thread all competed for it — while the map behind was unusable anyway with the
     sheet up. Full screen also retires the occlusion problem described above: the panel now
     covers the header rather than reaching into it, so .sp-head and its close button cannot be
     hidden by anything, and the z-index note stops mattering on this breakpoint.
     vh first, then --vvh: the var() fallback `100dvh` is a parse error pre-108 (G6), which drops
     that whole declaration and leaves the vh line standing — the round-95k pattern. */
  /* round-97h: top tracks the iOS visual-viewport pan; NOT transform — this panel animates its
     own transform, and driving a transitioned property per frame is the round-94 .asst-fab shake */
  .station-panel{ width:100%; top:var(--vvt, 0px); bottom:0; border-radius:0; z-index:1250;
    height:var(--app-h, 100vh);
    height:var(--vvh, var(--app-h, 100dvh));
    transform:translateY(100%); box-shadow:none; }
  .station-panel.open{ transform:translateY(0); }
  /* The head is now against the status bar, so it owns the top inset — its gradient runs up
     under the bar and the text starts below it, with no seam.
     --safe-top first, env() only as the fallback: Android's WebView never wires the system bars
     into env() (there is no cutout on most phones), so env() alone resolved to 0 and the clock
     and battery sat on top of the content. In the app --safe-top is filled from
     AquaNative.safeInsets(); the env() fallback is for mobile web on iOS. */
  .sp-head{ border-radius:0;
    padding-top:calc(20px + var(--safe-top, env(safe-area-inset-top, 0px))); }
}

/* ============================================================
   Blazor app additions
   ============================================================ */
/* Round-93c: the only reconnect UI left — a thin banner, shown solely when the device itself
   is offline. Silent reconnection needs no chrome, and inside the app the native offline panel
   owns this moment entirely. */
/* Round-142 (P3): the offline banner owns the very top of the screen — the strip the retired
   progress bar once shared. Its 3 px green edge is the motion system's accent. */
#reconBanner{
  position:fixed; top:0; left:0; right:0; z-index:2600;
  padding:calc(6px + var(--safe-top, env(safe-area-inset-top, 0px))) 14px 6px;
  background:#2C3B36; color:#F3F4F1; text-align:center;
  font-size:.85rem; font-weight:600;
  border-bottom:3px solid var(--green);
  animation:pgEnter var(--dur-2) var(--ease-out);
}
.in-app #reconBanner{ display:none !important; }

/* Round-142 (motion P1): there WAS a navigation progress bar here (3 px, green, after 150 ms).
   Retired 2026-09-05 at the owner's request — a line racing across the top of the nav read as
   noise, not feedback. aquaNav still fires aqua:navstart/aqua:navend and the page-enter. */

/* Round-142 (motion P1): the page-enter. Added by aquaNav on enhancedload only — never on a cold
   load (the app's launch veil must lift onto a settled page), never on the map (Leaflet lives
   under every enhancedload there), never on back/forward (back should feel instant). A one-shot
   keyframe with NO fill, so the rest state is the element's own; a class stripped mid-flight by
   a DOM patch leaves the page visible, never hidden — the trap at .adm-exp/acSheetIn/asetPaneIn. */
main.pg-enter{ animation:pgEnter var(--dur-2) var(--ease-out); }
/* Round-207 (effect 5): a fade and nothing else — the page no longer rises 4px into place. */
@keyframes pgEnter{ from{ opacity:0 } }

/* Round-93c: edge-to-edge, BOTH platforms. The app's WebView reaches the physical screen edges
   (iOS: UseSafeArea false + inset adjustment Never; Android: decorFitsSystemWindows false with
   transparent bars), so content shows through under the home bar/gesture bar — the transparent
   look — and the fixed chrome pads itself back out with these variables. iOS fills them from
   env() (viewport-fit=cover is on the meta tag); Android's WebView never wires system bars into
   env(), so the in-app bootstrap sets the SAME variables from AquaNative.safeInsets(). Browsers
   and old app builds resolve everything to 0 and are untouched. */
html.in-app{
  --safe-top:env(safe-area-inset-top, 0px);
  --safe-bottom:env(safe-area-inset-bottom, 0px);
  --safe-right:env(safe-area-inset-right, 0px);
}
/* Round-93d: no double-tap / pinch scale on app UI. Leaflet sets touch-action:none on its own
   container, which wins for the map — pan and pinch there are the map's, not the page's. */
html.in-app, html.in-app body{ touch-action:pan-x pan-y; }
/* Round-93f: no route to a Paystack checkout from inside the app — Play Billing / StoreKit
   rules treat credits as in-app digital goods. Credits are managed on the website. */
html.in-app .acct-tab[href="/account/top-up"]{ display:none; }
html.in-app #signupBar{ padding-top:calc(7px + var(--safe-top, 0px)); }
html.in-app:not(.signup-bar-on){ --header-h:calc(64px + var(--safe-top, 0px)); }
html.in-app:not(.signup-bar-on) .site-header{
  padding-top:var(--safe-top, 0px);
  height:calc(64px + var(--safe-top, 0px));
}
html.in-app .base-switch{ bottom:calc(18px + var(--safe-bottom, 0px)); }
/* The live map's transparent header sits at top:var(--signup-h); with no sign-up bar that is
   top:0 — under the clock and battery on an edge-to-edge phone. Same rule shape as .site-header. */
html.in-app:not(.signup-bar-on) .map-header{ top:var(--safe-top, 0px); }
/* Round-93c: the time-band strip (live map AND stories share .time-row) sat at 27px + the full
   home-bar inset — more than twice the gap it needs once content may run under the bar. Halved,
   at the product's request; the attribution text beneath is already tap-inert on phones. */
html.in-app .time-row{ bottom:calc((27px + var(--safe-bottom, 0px)) / 2); }
/* Ada's drawer is a full-height fixed panel: its dark header sat under the clock and battery on
   an edge-to-edge phone, and its composer under the home bar. Pad both ends with the insets. */
html.in-app .asst-drawer-head{ padding-top:calc(14px + var(--safe-top, 0px)); }
html.in-app .asst-drawer{ padding-bottom:var(--safe-bottom, 0px); }
html.in-app .asst-fab{ right:calc(16px + var(--safe-right, 0px)); }
html.in-app #blazor-error-ui{ padding-bottom:calc(12px + var(--safe-bottom, 0px)); }
html.in-app .map-actions{ bottom:calc(14px + var(--safe-bottom, 0px)); }

#blazor-error-ui{
  display:none; position:fixed; bottom:0; left:0; right:0; z-index:2000;
  background:#F3E9D8; color:#7A5A22; border-top:2px solid var(--tan);
  padding:12px 20px; font-size:.95rem;
}
#blazor-error-ui .dismiss{ float:right; cursor:pointer; font-weight:700; }
#blazor-error-ui .reload{ font-weight:700; margin-left:8px; }

.validation-message{ color:var(--st-impact); font-size:.85rem; margin-top:5px; display:block; }
.field input.invalid, .field select.invalid, .field textarea.invalid{ border-color:var(--st-impact); }
.field input.valid.modified, .field select.valid.modified, .field textarea.valid.modified{ border-color:var(--accent); }

/* social sign-in buttons */
.btn-google{ background:#fff; color:var(--ink); border:1.5px solid var(--track); }
.btn-google:hover{ border-color:var(--accent); box-shadow:var(--shadow-sm); }
.btn-facebook{ background:#1877F2; color:#fff; }
.btn-facebook:hover{ background:#2f86f6; box-shadow:0 4px 16px rgba(24,119,242,.4); }
.btn-google svg, .btn-facebook svg{ width:20px; height:20px; }

.auth-card{ max-width:440px; margin:0 auto; }
.auth-card .btn{ margin-bottom:12px; }
.auth-divider{ display:flex; align-items:center; gap:12px; color:var(--ink-soft); font-size:.85rem; margin:16px 0; }
.auth-divider::before, .auth-divider::after{ content:""; flex:1; height:1px; background:var(--track); }

/* ============================================================
   Map engine v2 — service pills, base switcher, incident markers
   ============================================================ */
.svc-wrap{
  /* Google-Maps style: chips row beside the map search box, inside the transparent nav.
     --signup-h keeps the row below the signed-out sign-up bar (0 when the bar is off).
     Round-137: right is 440px, not 370 — the header's right cluster (Report an Issue + icons)
     is ~426px wide and sits at z 1100 (above this row's 950), so an under-reserved row put its
     last chips UNDER the cluster, unclickable. The old scroll arrows masked it by shrinking
     the pills box 44px; with the arrows retired the reserve must be honest. Round-141g put
     arrows back on pointer devices — they shrink the pills box again, so KEEP 440 honest. */
  position:fixed; top:calc(13px + var(--signup-h, 0px)); left:calc(var(--msearch-w, 400px) + 42px); right:500px;   /* round-146g: the SIGNED-IN cluster (Report + 3 icons + avatar + grid) + a gap */
  z-index:950; display:flex; align-items:center;
}
.svc-pills{
  display:flex; gap:8px; flex-wrap:nowrap; justify-content:flex-start; width:100%;
  overflow-x:auto; scrollbar-width:none; padding-bottom:2px;
}
.svc-pills::-webkit-scrollbar{ display:none; }
.pill-svc{
  --svc: var(--accent);
  display:inline-flex; align-items:center; gap:6px;
  padding:8px 14px; border-radius:999px; cursor:pointer;
  font-family:var(--font); font-weight:700; font-size:.9rem;
  background:rgba(243,244,241,.92); color:var(--ink-soft);
  border:2px solid var(--track); backdrop-filter:blur(6px);
  box-shadow:0 4px 14px rgba(44,59,54,.18);
  transition:all .15s;
  opacity:.75;
}
.pill-svc svg{ width:16px; height:16px; color:var(--svc); flex:0 0 auto; }
.pill-svc:hover{ border-color:var(--svc); opacity:1; }
a.pill-svc{ text-decoration:none; }
a.pill-svc:hover{ text-decoration:none; }
.pill-svc.on{
  background:var(--accent); border-color:var(--accent); color:#fff; opacity:1;
}
/* icons keep their service color even when the chip is selected */
.pill-svc.on svg{ color:var(--svc); }

/* base map style switcher — bottom center */
.base-switch{
  position:fixed; bottom:18px; left:50%; transform:translateX(-50%);
  z-index:940; display:flex; gap:0; border-radius:999px; overflow:hidden;
  border:1px solid rgba(243,244,241,.3); box-shadow:0 6px 20px rgba(44,59,54,.3);
  background:#fff;
}
.base-switch button{
  padding:8px 14px; border:0; cursor:pointer; font-family:var(--font); font-weight:700; font-size:.82rem;
  background:var(--panel-grad); color:#DCE5DD;
}
.base-switch button + button{ border-left:1px solid rgba(243,244,241,.25); }
.base-switch button.on{ background:var(--paper); color:var(--deep); }

/* incident markers */
.inc-marker{
  width:30px; height:30px; border-radius:50% 50% 50% 4px;
  display:flex; align-items:center; justify-content:center;
  font-size:15px; border:2.5px solid #fff;
  box-shadow:0 3px 10px rgba(44,59,54,.45);
  transform:rotate(0deg);
}
.inc-marker.sev{ animation:sevpulse 1.6s ease-in-out infinite; }
@keyframes sevpulse{ 0%,100%{ box-shadow:0 3px 10px rgba(192,57,43,.45); } 50%{ box-shadow:0 0 0 10px rgba(192,57,43,0); } }

.legend-svc .row{ cursor:default; }
.legend-svc .row:hover{ background:transparent; }
.legend .swatch{ border-radius:50%; }

@media (max-width: 720px){
  .svc-pills{
    padding-bottom:4px;
  }
  .pill-svc{ flex:0 0 auto; font-size:.82rem; padding:7px 12px; }
  .net-stats{ top:calc(var(--header-h) + 56px); }
  .base-switch{ bottom:76px; left:12px; transform:none; }
  html.in-app .base-switch{ bottom:calc(76px + var(--safe-bottom, 0px)); }
  .map-actions{ bottom:14px; }
  .legend{ bottom:128px; }
}

/* ============================================================
   Engagement — incident reactions + comment thread
   ============================================================ */
.inc-react{ display:flex; align-items:center; gap:10px; margin-bottom:12px; }
.react-btn{
  padding:5px 7px; border-radius:0.7rem; border:1.5px solid var(--track); background:var(--paper);
  cursor:pointer; font-family:var(--font); font-weight:400; font-size:.8rem; color:var(--ink);
  transition:all .15s;
}
.react-btn:hover{ border-color:var(--accent); }
.react-btn.on{ background:var(--accent); border-color:var(--accent); color:#fff; }
/* round-57: when a react button is selected its background turns accent — force the emoji
   silhouette to white so the accent-coloured heart doesn't vanish into the accent fill. */
.react-btn.on .ico-t{ text-shadow:0 0 0 #F3F4F1 !important; }

.cmt-list{ display:flex; flex-direction:column; gap:12px; }
.cmt{ display:flex; gap:10px; }
.cmt-av{ width:32px; height:32px; border-radius:50%; object-fit:cover; flex:0 0 auto; border:1.5px solid var(--track); }
.cmt-av-fallback{
  display:flex; align-items:center; justify-content:center;
  background:var(--sage2); color:#fff; font-weight:800; font-size:.9rem;
}
.cmt-body{ background:var(--mintbg); border:1px solid var(--track); border-radius:4px 14px 14px 14px; padding:9px 13px; flex:1; }
.cmt-head{ display:flex; align-items:center; gap:8px; flex-wrap:wrap; font-size:.88rem; }
.cmt-badge{
  background:var(--deep); color:#fff; font-size:.68rem; font-weight:800; letter-spacing:.3px;
  padding:2px 8px; border-radius:999px;
}
.cmt-pts{ color:var(--tan); font-size:.75rem; font-weight:800; }
.cmt-body p{ font-size:.92rem; margin:4px 0; }
.cmt-actions{ display:flex; align-items:center; gap:10px; }
.cmt-actions small{ color:var(--ink-soft); font-size:.72rem; margin-left:auto; }
.cmt-btn{
  background:none; border:0; cursor:pointer; font-family:var(--font); font-size:.78rem;
  font-weight:700; color:var(--ink-soft); padding:2px 4px; border-radius:6px;
}
.cmt-btn:hover{ color:var(--deep); background:rgba(97,141,124,.12); }
.cmt-btn.on{ color:var(--deep); }
.cmt-btn.flagged{ color:var(--st-impact); }
.cmt-more{
  display:block; width:100%; text-align:center; background:none; border:0; cursor:pointer;
  font-family:var(--font); font-weight:700; font-size:.85rem; color:var(--deep);
  padding:8px 0; margin-bottom:4px;
}
.cmt-more:hover{ text-decoration:underline; }
.cmt-compose{ display:flex; gap:8px; margin-top:14px; align-items:flex-end; }
.cmt-compose textarea{
  flex:1; min-height:44px; max-height:120px; padding:10px 12px;
  border:1.5px solid var(--track); border-radius:12px; font-family:var(--font); font-size:.92rem;
  resize:vertical; background:#FBFBF8;
}
.cmt-compose textarea:focus{ outline:none; border-color:var(--accent); }

/* build r14b-2 */

/* Round-205y: the keyboard carry (see MainLayout). Focusable but invisible — NOT display:none
   or visibility:hidden, neither of which can take focus, and neither of which iOS will raise a
   keyboard for. 16px because iOS zooms the page to meet a focused control with a smaller face,
   and this one is 1px wide. pointer-events:none so it can never be tapped by accident. */
.kb-carry{
  position:fixed; top:0; left:0; width:1px; height:1px; padding:0; margin:0; border:0;
  opacity:0; z-index:-1; font-size:16px; background:transparent; color:transparent;
  pointer-events:none; -webkit-appearance:none; appearance:none; resize:none; overflow:hidden;
}
