/* WhatWay: whatway.org
 *
 * Implements the "Warm wayfinding" canvas: one hue, five steps. Nothing is
 * distinguished by colour alone; states and categories differ by lightness,
 * fill-vs-outline, and label.
 *
 * No inline style attributes anywhere in the markup: the Content-Security-
 * Policy is style-src 'self', which blocks them. Everything is a class.
 *
 * FONTS. Bricolage Grotesque over IBM Plex Sans, both OFL and self-hosted.
 * font-src stays 'self': loading them from Google would send every visitor's
 * IP to a third party from a page that promises we do not track them. The
 * files are copied out of @fontsource by scripts/sync-fonts.mjs and
 * committed, because wrangler uploads public/ from a checkout and must not
 * need node_modules first.
 */

/* One variable file covers every display weight we use, which is lighter
   than the two static cuts it replaces and leaves room to tune later. */
@font-face {
  font-family: "Bricolage Grotesque";
  src: url("/fonts/bricolage-wght.woff2") format("woff2");
  font-weight: 200 800; font-style: normal; font-display: swap;
}
@font-face { font-family:"IBM Plex Sans"; src:url("/fonts/plex-400.woff2") format("woff2"); font-weight:400; font-style:normal; font-display:swap; }
@font-face { font-family:"IBM Plex Sans"; src:url("/fonts/plex-600.woff2") format("woff2"); font-weight:600; font-style:normal; font-display:swap; }
/* unicode-range keeps the 42KB Arabic file off every Latin page load. It is
   fetched only once Arabic glyphs actually render, which matters on the
   metered phone connections this audience is reading from. */
@font-face {
  font-family: "IBM Plex Sans Arabic";
  src: url("/fonts/plex-arabic-400.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891,
    U+0898-08E1, U+08E3-08FF, U+FB50-FDFF, U+FE70-FEFF;
}

:root {
  --mist: #f1f7f3;
  --card: #fff;
  --ink: #10221b;
  --ink-body: #2e4239;
  --ink-muted: #4a5f55;
  --spruce: #0e6b54;
  --pine: #08432f;
  --fern: #2e9e6b;
  --mint: #7fd3a8;
  --tint: #d6ebe0;
  --band: #e3efe8;
  --edge: #dce9e1;
  --rule: #d3e3da;
  --control: #b9cfc3;
  --warning-bg: #fff6df;
  --warning-edge: #c38a16;
  --warning-ink: #5b3d00;

  --display: "Bricolage Grotesque", "Trebuchet MS", "Segoe UI", system-ui, sans-serif;
  --body: "IBM Plex Sans", "IBM Plex Sans Arabic", "Segoe UI", system-ui, sans-serif;

  --r-ctl: 14px;
  --r-card: 18px;
  --r-plate: 22px;

  --ease: cubic-bezier(0.32, 0.72, 0, 1);
  --fast: 140ms;
  --base: 220ms;
  --slow: 380ms;

  --gutter: clamp(20px, 5.5vw, 80px);
}

/* Arabic-script languages need their own typographic voice. Bricolage has
   no Arabic glyphs, so leaving it in charge made browsers fall back to a
   decorative system face (most visibly Urdu Nastaliq) and then synthesize
   an extra-heavy headline. The self-hosted Plex Arabic cut is deliberately
   plain, readable, and consistent across devices. */
html:lang(ar),
html:lang(fa),
html:lang(ps),
html:lang(ur) {
  --display: "IBM Plex Sans Arabic", "Noto Sans Arabic", Tahoma, sans-serif;
  --body: "IBM Plex Sans Arabic", "Noto Sans Arabic", Tahoma, sans-serif;
}

*, *::before, *::after { box-sizing: border-box; }

/* display:grid/flex on sections beats the browser's default [hidden] rule,
   so toggling the attribute from JS silently did nothing. */
[hidden] { display: none !important; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--mist);
  color: var(--ink);
  font-family: var(--body);
  font-size: 17px;
  line-height: 1.55;
}

h1, h2, h3 { font-family: var(--display); font-weight: 600; margin: 0; line-height: 1.1; letter-spacing: -0.022em; }
p, ul, ol { margin: 0; }
ul, ol { padding: 0; list-style: none; }
a { color: var(--spruce); text-underline-offset: 3px; }
a:hover { color: var(--pine); }

:focus-visible { outline: 3px solid var(--fern); outline-offset: 2px; border-radius: 4px; }

.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;
}

.skip-link {
  position: absolute; inset-inline-start: 50%; transform: translate(-50%, -140%);
  z-index: 100; background: var(--ink); color: var(--mist);
  padding: 12px 20px; border-radius: 0 0 var(--r-ctl) var(--r-ctl);
  text-decoration: none; font-weight: 600; transition: transform var(--base) var(--ease);
}
.skip-link:focus-visible { transform: translate(-50%, 0); color: var(--mist); }

svg { fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.mark-dot { fill: var(--fern); stroke: none; }
.mark-dot-light { fill: var(--mint); stroke: none; }

/* ---- buttons -------------------------------------------------------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  font: inherit; font-weight: 600; text-decoration: none; cursor: pointer;
  border: 0; border-radius: var(--r-ctl); min-height: 46px; padding: 0 20px;
  transition: background-color var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
.btn svg { width: 19px; height: 19px; flex: 0 0 auto; }
.btn-lg { min-height: 56px; padding: 0 28px; font-size: 17px; }
.btn-primary { background: var(--spruce); color: #fff; }
.btn-primary:hover { background: var(--pine); color: #fff; }
.btn-pine { background: var(--pine); color: #fff; }
.btn-pine:disabled { background: #3a4e45; color: #9bb5a8; cursor: not-allowed; }
.btn-ghost { background: transparent; color: var(--ink); border: 1.5px solid var(--control); }
.btn-ghost:hover { background: var(--band); color: var(--ink); }

.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 46px; height: 46px; flex: 0 0 auto; cursor: pointer;
  background: transparent; border: 1.5px solid var(--control);
  border-radius: var(--r-ctl); color: var(--ink);
  transition: background-color var(--fast) var(--ease);
}
.icon-btn:hover { background: var(--band); }
.icon-btn svg { width: 19px; height: 19px; }
.icon-btn-solid { background: var(--spruce); border-color: var(--spruce); color: #fff; }
.icon-btn-solid:hover { background: var(--pine); border-color: var(--pine); }
.icon-btn-lg { width: 54px; height: 54px; }

.pill-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; flex: 0 0 auto;
  border-radius: 999px; background: var(--tint); color: var(--pine);
}
.pill-icon svg { width: 21px; height: 21px; }
.pill-icon-lg { width: 56px; height: 56px; }
.pill-icon-lg svg { width: 27px; height: 27px; }

/* ---- header --------------------------------------------------------- */

.site-header {
  display: flex; align-items: center; gap: 18px; flex-wrap: wrap;
  padding: 16px var(--gutter); border-bottom: 1px solid var(--rule);
}
.brand {
  display: inline-flex; align-items: center; gap: 10px; text-decoration: none;
  color: var(--ink); font-family: var(--display); font-weight: 800;
  font-size: 22px; letter-spacing: -0.02em;
}
.brand-mark { width: 28px; height: 28px; stroke-width: 4; }
.site-header nav { margin-inline-start: auto; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.site-header nav > a {
  text-decoration: none; color: var(--ink); font-size: 15px; font-weight: 500;
  padding: 10px 14px; border-radius: var(--r-ctl);
  transition: background-color var(--fast) var(--ease);
}
.site-header nav > a:hover { background: var(--band); }
.nav-give { background: var(--pine); color: #fff; font-weight: 600; }
.nav-give:hover { background: var(--ink); color: #fff; }

.lang-switch { position: relative; display: inline-flex; max-width: 100%; }

/* ---- hero ----------------------------------------------------------- */

.hero {
  display: grid; grid-template-columns: minmax(0, 1.08fr) minmax(0, 1fr);
  gap: clamp(28px, 5vw, 56px); align-items: center;
  padding: clamp(36px, 6vw, 72px) var(--gutter);
}
#hero-title {
  font-size: clamp(38px, 6.4vw, 76px); font-weight: 800;
  letter-spacing: -0.04em; line-height: 1.0; min-height: 2.1em;
}
html:lang(ar) #hero-title,
html:lang(fa) #hero-title,
html:lang(ps) #hero-title,
html:lang(ur) #hero-title {
  font-size: clamp(34px, 5.2vw, 62px);
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1.2;
  min-height: 2.5em;
}
#hero-title .line { display: block; }
/* The thing being asked for is the only coloured word in the headline, so
   the eye lands on what changes. Spruce rather than fern: at this size
   fern clears 3:1 only just, and this is the first thing anyone reads. */
#hero-title .typed { color: var(--spruce); }
/* The answer stays put while the need rotates, so the promise reads as
   constant rather than as a second punchline. */
#hero-title .line-answer { color: var(--ink); }
.caret {
  display: inline-block; width: 4px; height: 0.74em; background: var(--fern);
  border-radius: 1px; margin-inline-start: 6px; vertical-align: baseline;
}
@media (prefers-reduced-motion: no-preference) {
  .caret.blink { animation: ww-blink 1s steps(1, end) infinite; }
}
@keyframes ww-blink { 0%, 50% { opacity: 1; } 50.01%, 100% { opacity: 0; } }

.hero-lede { margin-top: 20px; font-size: clamp(17px, 2vw, 20px); color: var(--ink-body); max-width: 44ch; }
.hero-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 26px; }
.reassure { display: flex; align-items: center; gap: 10px; margin-top: 20px; font-size: 15px; color: var(--ink-muted); }
.reassure svg { width: 18px; height: 18px; flex: 0 0 auto; }

.hero-stage { position: relative; display: flex; align-items: center; justify-content: center; min-height: 440px; }

/* Device frame: hardware only. No painted status bar, because on a real
   phone the system draws its own on top and a fake one reads as doubled. */
.phone {
  width: 286px; height: 496px; flex: 0 0 auto;
  background: var(--card); border-radius: 26px; padding: 9px;
  /* A 60px blur at 16% is the shadow every generated landing page puts under
     every mockup. One hairline and a shadow you have to look for keeps the
     device on the page instead of floating above it. */
  border: 1px solid var(--edge);
  box-shadow: 0 1px 2px rgba(16, 34, 27, 0.04);
}
/* The phone used to sit at -4deg. Rotating a container puts every glyph
   inside it off the pixel grid, and the thread is a block of addresses and
   phone numbers being read by someone in their second or third language.
   The jaunty angle cost legibility to buy nothing, so it is gone. */
.phone-screen {
  position: relative; height: 100%; border-radius: 32px; overflow: hidden;
  background: var(--band); display: flex; flex-direction: column;
}
.phone-header { display: flex; align-items: center; gap: 9px; padding: 16px 14px 13px; background: var(--spruce); color: #fff; }
.phone-avatar {
  width: 30px; height: 30px; flex: 0 0 auto; border-radius: 999px; background: var(--pine);
  display: flex; align-items: center; justify-content: center;
}
.phone-avatar svg { width: 17px; height: 17px; stroke: var(--mist); stroke-width: 5; }
.phone-id { display: grid; min-width: 0; }
.phone-id strong { font-size: 14px; font-weight: 600; }
.phone-id small { font-size: 11px; color: var(--mist); }
.phone-thread { flex: 1 1 auto; display: flex; flex-direction: column; gap: 8px; padding: 12px 11px; overflow: hidden; }
.bubble { padding: 8px 11px; font-size: 12.5px; line-height: 1.5; white-space: pre-line; max-width: 85%; }
/* Hidden only while motion is allowed; see setThread. With reduced motion
   the bubbles never get .is-in and this rule never applies, so the whole
   thread is visible from the first frame. */
@media (prefers-reduced-motion: no-preference) {
  .phone-thread .bubble {
    opacity: 0; transform: translateY(6px);
    transition: opacity var(--base) var(--ease), transform var(--base) var(--ease);
  }
  .phone-thread .bubble.is-in { opacity: 1; transform: none; }
}
.typing-bubble {
  align-self: flex-start; display: flex; align-items: center; gap: 4px;
  padding: 11px 13px; background: var(--card); border-radius: 13px 13px 13px 3px;
}
.typing-bubble span {
  width: 5px; height: 5px; border-radius: 999px; background: var(--ink-muted); opacity: 0.4;
}
@media (prefers-reduced-motion: no-preference) {
  .typing-bubble span { animation: ww-typing 1.1s var(--ease) infinite; }
  .typing-bubble span:nth-child(2) { animation-delay: 0.15s; }
  .typing-bubble span:nth-child(3) { animation-delay: 0.3s; }
}
@keyframes ww-typing {
  0%, 100% { opacity: 0.25; transform: translateY(0); }
  50% { opacity: 0.85; transform: translateY(-2px); }
}
.bubble:empty { display: none; }
.bubble-me { align-self: flex-end; background: var(--spruce); color: #fff; border-radius: 13px 13px 3px 13px; }
.bubble-them { align-self: flex-start; background: var(--card); border-radius: 13px 13px 13px 3px; }
.phone-composer {
  display: flex; align-items: center; gap: 7px; padding: 9px 11px 14px;
  width: 100%; font: inherit; text-align: start; cursor: pointer;
  background: transparent; border: 0; color: inherit;
}
.phone-composer > span:first-child {
  flex: 1 1 auto; height: 34px; display: flex; align-items: center; padding: 0 13px;
  background: var(--card); border-radius: 999px; font-size: 12px; color: var(--ink-muted);
}
.phone-send {
  width: 34px; height: 34px; flex: 0 0 auto; border-radius: 999px; background: var(--spruce);
  display: flex; align-items: center; justify-content: center; color: #fff;
}
.phone-send svg { width: 15px; height: 15px; stroke-width: 2.2; }

/* The real search, expanding from the button that opened it. */
.chat-panel {
  position: absolute; inset-inline-end: 0; bottom: 0; z-index: 5;
  width: min(420px, 100%); background: var(--card); border-radius: var(--r-plate);
  box-shadow: 0 24px 60px rgba(16,34,27,0.18), 0 2px 8px rgba(16,34,27,0.08);
  display: flex; flex-direction: column;
  transform-origin: 0% 100%;
  transition: opacity var(--slow) var(--ease), transform var(--slow) var(--ease), filter var(--slow) var(--ease);
}
.chat-panel.opening { opacity: 0; transform: scale(0.96) translateY(10px); filter: blur(4px); transition: none; }
.chat-panel.closing { opacity: 0; transform: scale(0.96) translateY(10px); filter: blur(4px); transition-duration: 200ms; }
.chat-head { display: flex; align-items: center; gap: 11px; padding: 16px 18px; border-bottom: 1px solid var(--edge); }
.chat-head h2 { flex: 1 1 auto; font-size: 15.5px; }
.chat-avatar {
  width: 32px; height: 32px; flex: 0 0 auto; border-radius: 999px; background: var(--spruce);
  display: flex; align-items: center; justify-content: center;
}
.chat-avatar svg { width: 18px; height: 18px; stroke: var(--mist); stroke-width: 5; }
/* The thread can outgrow the panel, so it scrolls rather than pushing the
   composer off the bottom. justify-items keeps bubbles at their text width. */
.chat-body {
  display: grid; gap: 10px; padding: 18px;
  justify-items: start; align-content: start;
  max-height: 340px; overflow-y: auto; overscroll-behavior: contain;
}
.chat-msg {
  max-width: 88%; padding: 10px 14px; font-size: 15px; line-height: 1.5;
  border-radius: var(--r-ctl);
}
.chat-me { justify-self: end; background: var(--spruce); color: #fff; }
.chat-them { background: var(--mist); color: var(--ink); border: 1px solid var(--edge); }
/* The message stays readable while a tiny route marker supplies the changing
   state. Pulsing the whole sentence made it harder to read on a slow search. */
.chat-pending { display: inline-flex; align-items: center; gap: 9px; color: var(--ink-muted); }

.chat-jump {
  justify-self: start; font: inherit; font-size: 14.5px; font-weight: 600;
  cursor: pointer; color: var(--spruce); background: transparent;
  border: 1.5px solid var(--control); border-radius: 999px;
  min-height: 42px; padding: 0 16px;
  transition: background-color var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
.chat-jump:hover { background: var(--band); border-color: var(--spruce); }

/* A quiet link, not a fourth button: reporting a problem is rare next to
   calling the place, and giving it button weight would say otherwise. */
.result-report {
  align-self: center; margin-inline-start: auto;
  font-size: 13.5px; color: var(--ink-muted); text-decoration: underline;
  text-underline-offset: 2px;
}
.result-report:hover { color: var(--spruce); }
.starter {
  text-align: start; font: inherit; font-size: 15px; font-weight: 500; cursor: pointer;
  color: var(--ink); background: var(--mist); border: 1px solid var(--edge);
  border-radius: var(--r-ctl); min-height: 46px; padding: 11px 15px;
  transition: background-color var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
.starter:hover { background: var(--band); border-color: var(--spruce); }
.chat-composer { display: flex; gap: 9px; padding: 0 18px 18px; }
.chat-composer input {
  flex: 1 1 auto; min-width: 0; font: inherit; font-size: 15.5px; color: var(--ink);
  background: var(--mist); border: 1.5px solid var(--control); border-radius: var(--r-ctl);
  height: 48px; padding: 0 14px;
}
.chat-composer input:focus-visible { border-color: var(--spruce); }

/* ---- partners ------------------------------------------------------- */

.partners {
  display: flex; align-items: center; gap: clamp(14px, 2.5vw, 32px);
  padding: 20px 0 20px var(--gutter); background: var(--card);
  border-block: 1px solid var(--rule); overflow: hidden;
}

/* The strip scrolls because there will be more partners than fit, and a
   wrapped two-row block of logos reads as clutter. It is the only looping
   motion on the page, so it earns its keep by being slow, pausing when
   anyone points at it, and stopping dead under reduced-motion. */
.marquee {
  position: relative; flex: 1 1 auto; min-width: 0;
  display: flex; gap: clamp(28px, 5vw, 64px);
  /* Fade both edges so logos enter and leave instead of being guillotined. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 48px, #000 calc(100% - 48px), transparent);
  mask-image: linear-gradient(90deg, transparent, #000 48px, #000 calc(100% - 48px), transparent);
}
.marquee-track {
  display: flex; align-items: center; gap: clamp(28px, 5vw, 64px);
  flex: 0 0 auto; margin: 0; padding: 0; list-style: none;
  animation: marquee-scroll 32s linear infinite;
}
.marquee:hover .marquee-track,
.marquee:focus-within .marquee-track { animation-play-state: paused; }

@keyframes marquee-scroll {
  from { transform: translateX(0); }
  /* Two identical tracks sit side by side, so moving one full track width
     lands exactly where it started and the seam never shows. */
  to { transform: translateX(calc(-100% - clamp(28px, 5vw, 64px))); }
}

@media (prefers-reduced-motion: reduce) {
  .marquee { flex-wrap: wrap; mask-image: none; -webkit-mask-image: none; }
  .marquee-track { animation: none; flex-wrap: wrap; }
  /* The duplicate exists only to make the loop seamless. With no loop it
     is just the same four logos twice. */
  .marquee-track[aria-hidden="true"] { display: none; }
}

.partner {
  position: relative;
  display: flex; align-items: center; justify-content: center;
  flex: 0 0 auto; min-height: 44px;
  /* Every mark to one cap height in one grey, so no partner outranks
     another and none of them fights the green. */
  filter: grayscale(1);
  opacity: 0.75;
  transition: opacity var(--fast) var(--ease), filter var(--fast) var(--ease);
}
.partner:hover { filter: grayscale(0); opacity: 1; }
/* The logo is invisible rather than display:none, so the browser still
   fetches it and we learn whether it exists. Once it loads, app.js swaps
   which of the two is shown. A broken-image icon next to clipped alt text
   is worse than simply printing the partner's name. */
/* One cap height across the set. Without the max-height a stacked mark
   (I.AIM puts its monogram above the wordmark) renders twice as tall as the
   single-line wordmarks beside it and reads as the senior partner. */
.partner img {
  position: absolute; opacity: 0; width: auto; object-fit: contain;
  max-height: 44px;
}
.partner.has-logo img { position: static; opacity: 1; }
.partner.has-logo .partner-name { display: none; }
/* Half the strip is a wordmark rather than a mark, so the type has to hold
   the same optical weight as a logo greyed to 75%: same family as the
   display face, same muted ink, no shouting. */
.partner-name {
  font-family: var(--display); font-size: 16px; font-weight: 600;
  color: var(--ink-muted); white-space: nowrap; letter-spacing: -0.015em;
}
.slot-wide img { max-width: 210px; }
.slot-mid img { max-width: 168px; }
/* A stacked mark needs height, not width, so it gets the smallest box. */
.slot-narrow img { max-width: 72px; }

@media (max-width: 860px) {
  .partners { flex-direction: column; align-items: flex-start; padding-inline: var(--gutter); }
  .partner { height: 36px; }
}

/* ---- coverage ------------------------------------------------------- */
/* The count is a claim, so it is set as a sentence you read, not a tile you
   scan. The three categories underneath are the action, so they are buttons
   that actually run a search. Giving both the same card treatment made the
   number decorative and the categories look clickable without being so. */

.coverage {
  display: grid; gap: 10px;
  padding: clamp(32px, 5vw, 52px) var(--gutter);
}
#coverage-heading {
  font-size: clamp(28px, 4.4vw, 46px); line-height: 1.05; max-width: 22ch;
}
#coverage-count {
  color: var(--spruce); font-weight: 800; font-variant-numeric: tabular-nums;
}
.coverage-sub {
  font-size: 17px; color: var(--ink-body); max-width: 58ch; margin-bottom: 14px;
}

.ways { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; }
.way {
  font: inherit; text-align: start; cursor: pointer; color: var(--ink);
  background: var(--card); border: 1.5px solid var(--edge); border-radius: var(--r-card);
  padding: 20px; display: grid; gap: 7px; align-content: start;
  transition: border-color var(--fast) var(--ease), background-color var(--fast) var(--ease);
}
.way:hover { border-color: var(--spruce); background: var(--band); }
.way strong { font-size: 17px; font-weight: 600; }
.way small { font-size: 14.5px; color: var(--ink-muted); line-height: 1.45; }

.contribute-actions { display: flex; flex-wrap: wrap; gap: 10px; }

/* ---- finder --------------------------------------------------------- */

.finder {
  display: grid; grid-template-columns: 340px minmax(0, 1fr); gap: clamp(24px, 4vw, 44px);
  padding: clamp(32px, 5vw, 56px) var(--gutter);
  background: var(--card); border-block: 1px solid var(--rule); align-items: start;
}
.finder-side { display: grid; gap: 18px; align-content: start; }
#finder-heading { font-size: clamp(26px, 3.4vw, 34px); }
.finder-lede { font-size: 17px; color: var(--ink-body); }
.zip-form { display: grid; gap: 8px; }
.zip-form label { font-size: 13.5px; font-weight: 600; }
.zip-row { display: flex; gap: 10px; }
.zip-row input {
  flex: 1 1 auto; min-width: 0; font: inherit; font-size: 17px; color: var(--ink);
  background: var(--mist); border: 1.5px solid var(--control); border-radius: var(--r-ctl);
  height: 54px; padding: 0 16px;
}
.zip-row input:focus-visible { border-color: var(--spruce); }

.quick-searches { display: flex; flex-wrap: wrap; gap: 8px; }
.quick-searches button {
  font: inherit; font-size: 14.5px; font-weight: 500; cursor: pointer; color: var(--ink);
  background: transparent; border: 1.5px solid var(--control); border-radius: 999px;
  min-height: 42px; padding: 0 15px;
  transition: background-color var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
.quick-searches button:hover { background: var(--band); border-color: var(--spruce); }

.legend { display: grid; gap: 10px; font-size: 15px; }
.legend li { display: flex; align-items: center; gap: 10px; }
.dot { width: 12px; height: 12px; border-radius: 999px; flex: 0 0 auto; }
.dot-health { background: var(--spruce); }
.dot-school { background: var(--mint); }
.dot-legal { background: transparent; border: 2px solid var(--pine); }

.finder-main { display: grid; gap: 16px; min-width: 0; }

.search-status { font-size: 15px; color: var(--ink-body); }
.search-status:empty { display: none; }
.search-status[data-tone="working"] { display: flex; align-items: center; gap: 10px; }
.search-status-copy { min-width: 0; }
.search-elapsed {
  margin-inline-start: auto; color: var(--ink-muted); font-size: 12.5px;
  font-variant-numeric: tabular-nums; opacity: 0;
  transition: opacity 180ms cubic-bezier(0.32, 0.72, 0, 1);
}
.search-elapsed.is-visible { opacity: 1; }
.thinking-mark {
  --thinking-travel: 22px;
  position: relative; display: inline-block; width: 32px; height: 14px;
  flex: 0 0 32px; color: var(--spruce);
}
html[dir="rtl"] .thinking-mark { --thinking-travel: -22px; }
.thinking-mark::before {
  content: ""; position: absolute; inset-inline: 4px; top: 6px; height: 2px;
  border-radius: 999px; background: var(--control);
}
.thinking-mark::after {
  content: ""; position: absolute; inset-inline-start: 2px; top: 3px;
  width: 8px; height: 8px; border-radius: 999px; background: currentColor;
}
@media (prefers-reduced-motion: no-preference) {
  .thinking-mark::after {
    animation: ww-route-think 900ms cubic-bezier(0.32, 0.72, 0, 1) infinite alternate;
  }
}
@keyframes ww-route-think { to { transform: translateX(var(--thinking-travel)); } }
/* A problem is stated, not alarmed: an ink rule, no red. A failed search is
   not an emergency and this audience has enough of those. */
.search-status[data-tone="problem"] { border-inline-start: 3px solid var(--pine); padding-inline-start: 14px; }
.search-status.has-alert {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center; gap: 12px; padding: 14px 16px;
  border: 1px solid var(--warning-edge); border-inline-start-width: 4px;
  border-radius: var(--r-ctl); background: var(--warning-bg); color: var(--warning-ink);
}
.search-alert-mark,
.site-notice-mark {
  display: grid; place-items: center; width: 26px; height: 26px;
  border: 2px solid currentColor; border-radius: 999px;
  font-weight: 800; line-height: 1;
}
.search-alert-copy { display: grid; gap: 2px; min-width: 0; }
.search-alert-title { color: var(--warning-ink); font-size: 15.5px; }
.search-alert-body { font-size: 14px; line-height: 1.45; }
.search-alert-action,
.site-notice-action {
  min-height: 42px; padding: 0 14px; border: 1.5px solid currentColor;
  border-radius: 999px; background: transparent; color: inherit;
  font: inherit; font-size: 14px; font-weight: 700; cursor: pointer;
}
.search-alert-action:hover,
.site-notice-action:hover { background: rgba(255,255,255,0.65); }

.site-notice {
  position: relative; z-index: 35; display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: 12px;
  padding: 12px var(--gutter); border-bottom: 1px solid var(--warning-edge);
  background: var(--warning-bg); color: var(--warning-ink);
}
.site-notice[data-tone="ok"] {
  border-color: var(--fern); background: var(--tint); color: var(--pine);
}
.site-notice-title { display: block; font-size: 15px; }
.site-notice-body { margin: 2px 0 0; font-size: 13.5px; line-height: 1.4; }

@media (max-width: 600px) {
  .search-status.has-alert,
  .site-notice { grid-template-columns: auto minmax(0, 1fr); }
  .search-alert-action,
  .site-notice-action { grid-column: 2; justify-self: start; }
}

.results-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
#result-summary { font-size: 15px; color: var(--ink-muted); }
.view-switch { display: inline-flex; gap: 4px; background: var(--band); border-radius: 999px; padding: 4px; }
.view-switch button {
  display: inline-flex; align-items: center; gap: 7px; font: inherit; font-size: 14px;
  font-weight: 600; cursor: pointer; border: 0; border-radius: 999px;
  min-height: 38px; padding: 0 14px; background: transparent; color: var(--ink-body);
  transition: background-color var(--fast) var(--ease), color var(--fast) var(--ease);
}
.view-switch button svg { width: 16px; height: 16px; }
.view-switch button.active { background: var(--spruce); color: #fff; }

.results { display: grid; gap: 14px; }
@media (min-width: 1100px) { .results { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.result-card {
  background: var(--mist); border: 1px solid var(--edge); border-radius: var(--r-card);
  padding: 20px 22px; display: grid; gap: 10px; align-content: start;
}
.result-card h3 { font-size: 19px; }
.result-identity {
  display: grid; grid-template-columns: auto 44px minmax(0, 1fr);
  align-items: center; gap: 12px; min-width: 0;
}
/* The position in the list, the way the prototype numbered them. Read by
   the eye and skipped by the ear: it says nothing a screen reader cannot
   get from the order it is already reading. */
.result-index {
  display: grid; place-items: center; min-width: 26px; height: 26px; padding: 0 6px;
  border-radius: 9px; background: var(--tint); color: var(--pine);
  font-family: var(--display); font-size: 13px; font-weight: 700; line-height: 1;
  font-variant-numeric: tabular-nums;
}
.org-mark {
  width: 44px; height: 44px; display: inline-flex; align-items: center; justify-content: center;
  overflow: hidden; border: 1px solid var(--rule); border-radius: 12px;
  background: var(--card); color: var(--spruce); font-family: var(--display);
  font-size: 13px; font-weight: 700; letter-spacing: 0.02em; line-height: 1;
  unicode-bidi: isolate;
}
.org-mark.has-image { width: 58px; padding: 7px; }
/* A picture of the thing, not the initials of a name nobody has read yet.
   Three tones so the three kinds of place are three different tiles at a
   glance, all inside the one hue the rest of the site uses. */
.org-mark.has-glyph { border: 0; }
.org-mark.has-glyph svg { width: 24px; height: 24px; stroke-width: 1.7; }
.org-mark.tone-care  { background: var(--tint); color: var(--pine); }
.org-mark.tone-learn { background: var(--band); color: var(--spruce); }
.org-mark.tone-help  { background: var(--spruce); color: #fff; }
.result-identity.has-logo { grid-template-columns: auto 58px minmax(0, 1fr); }
.org-mark img { display: block; width: 100%; height: 100%; object-fit: contain; }
.result-meta { font-size: 14.5px; color: var(--ink-body); line-height: 1.5; }
.badges { display: flex; flex-wrap: wrap; gap: 6px; }
/* Three treatments so a badge set survives greyscale. */
.badge { font-size: 13px; font-weight: 500; border-radius: 999px; padding: 5px 11px; }
.badge-a { background: var(--tint); color: var(--pine); }
.badge-b { background: var(--spruce); color: #fff; }
.badge-c { border: 1.5px solid var(--control); color: var(--ink); padding: 3.5px 10px; }
/* "+4", for the specialities that did not fit. The disclosure below holds
   them; this only says that there are more, so it is not a tag itself. */
.badge-more {
  color: var(--ink-muted); font-size: 12.5px; font-weight: 600;
  padding: 5px 2px; font-variant-numeric: tabular-nums;
}

/* The facts, always in this order and always with the same glyph: address,
   phone, website, languages, hours. Somebody comparing six clinics reads
   down the same line on every card, which is worth more than packing each
   card as tightly as its own contents would allow. */
.result-facts { list-style: none; margin: 0; padding: 0; display: grid; gap: 7px; }
.fact {
  display: grid; grid-template-columns: 17px minmax(0, 1fr); gap: 10px;
  align-items: start; font-size: 14.5px; line-height: 1.45; color: var(--ink-body);
}
.fact svg { width: 17px; height: 17px; margin-top: 2px; color: var(--fern); }
.fact-body { min-width: 0; overflow-wrap: anywhere; }
.fact a { color: var(--spruce); text-underline-offset: 2px; }
.fact a:hover { color: var(--pine); }

.result-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.result-actions .btn { flex: 1 1 auto; font-size: 15px; }

/* Everything that did not fit, behind a native disclosure: no script, it
   works with a keyboard, and it is shut to begin with so a list of twenty
   results stays a list of twenty. */
.result-footer {
  display: flex; flex-wrap: wrap; align-items: start; justify-content: space-between;
  gap: 10px 16px; border-top: 1px solid var(--rule); padding-top: 10px;
}
/* Open, the disclosure owns the row, so the report link stops trying to
   sit beside a block of text and goes under it. */
.result-footer:has(.result-more[open]) { flex-direction: column; align-items: start; }
.result-more { min-width: 0; }
.result-more summary {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
  font-size: 14px; font-weight: 600; color: var(--spruce);
  padding: 4px 0; list-style: none;
}
.result-more summary::-webkit-details-marker { display: none; }
.result-more summary:hover { color: var(--pine); }
.result-more summary svg {
  width: 15px; height: 15px; transition: transform var(--fast) var(--ease);
}
.result-more[open] summary svg { transform: rotate(180deg); }
.result-more .more-shut, .result-more[open] .more-open { display: none; }
.result-more[open] .more-shut { display: inline; }
.more-body {
  display: grid; gap: 8px; padding: 8px 0 2px;
  font-size: 14.5px; line-height: 1.55; color: var(--ink-body);
}
.more-body h4 {
  font-family: var(--body); font-size: 12.5px; font-weight: 700; margin: 4px 0 0;
  letter-spacing: 0.04em; text-transform: uppercase; color: var(--ink-muted);
}
.more-body p { margin: 0; }
.more-note { color: var(--ink-muted); }
.more-hours {
  display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 2px 14px; margin: 0;
}
.more-hours dt { font-weight: 600; color: var(--ink); }
.more-hours dd { margin: 0; font-variant-numeric: tabular-nums; }

.skeleton { position: relative; overflow: hidden; }
.skeleton .bar { background: var(--edge); border-radius: 5px; height: 14px; }
.skeleton .bar.title { height: 20px; width: 70%; }
.skeleton .bar.short { width: 45%; }
.skeleton::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(100deg, transparent 20%, rgba(255,255,255,0.72) 48%, transparent 76%);
  transform: translateX(-110%); pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
  .skeleton::after {
    animation: ww-skeleton 1.25s cubic-bezier(0.4, 0, 0.2, 1) infinite;
  }
}
@keyframes ww-skeleton { to { transform: translateX(110%); } }

/* An empty result is an invitation to act, so it carries the next step. */
.no-results { background: var(--mist); border: 1px solid var(--edge); border-radius: var(--r-card); padding: 24px; display: grid; gap: 14px; }
.no-results h3 { font-size: 20px; }
.no-results ul { display: grid; gap: 8px; }
.no-results a {
  display: block; text-decoration: none; color: var(--ink); font-weight: 500;
  background: var(--card); border: 1px solid var(--edge); border-radius: var(--r-ctl); padding: 12px 15px;
}
.no-results a:hover { background: var(--band); color: var(--ink); }

.map-view { display: grid; gap: 14px; }
@media (min-width: 900px) { .map-view { grid-template-columns: 280px minmax(0, 1fr); } }
.map-list { display: grid; gap: 8px; align-content: start; max-height: 460px; overflow-y: auto; }
.map-list button {
  text-align: start; font: inherit; font-size: 15px; cursor: pointer; display: grid; gap: 3px;
  background: var(--mist); border: 1px solid var(--edge); border-radius: var(--r-ctl); padding: 12px 14px;
  transition: border-color var(--fast) var(--ease);
}
.map-list button:hover { border-color: var(--spruce); }
.map-list button[aria-current="true"] { border-color: var(--spruce); border-width: 2px; }
.map-list strong { font-family: var(--display); font-weight: 600; font-size: 15.5px; }
.map-list small { color: var(--ink-muted); font-size: 13px; }
.map-frame-wrap { position: relative; min-height: 360px; border-radius: var(--r-card); overflow: hidden; background: var(--band); }
#map-frame { width: 100%; height: 100%; min-height: 360px; border: 0; display: block; }
#map-empty { position: absolute; inset: 0; display: grid; place-items: center; padding: 24px; text-align: center; font-size: 14px; color: var(--ink-muted); }

/* ---- how / privacy / whatsapp / contribute / give ------------------- */

.how { display: grid; gap: clamp(22px, 3.5vw, 32px); padding: clamp(36px, 5vw, 64px) var(--gutter); }
#how-heading { font-size: clamp(26px, 3.4vw, 34px); }
.how ol { display: grid; gap: 16px; }
@media (min-width: 760px) { .how ol { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.how li { background: var(--card); border: 1px solid var(--edge); border-radius: var(--r-card); padding: 20px; display: grid; gap: 8px; align-content: start; }
.how strong { font-size: 17.5px; }
.how small { font-size: 14.5px; color: var(--ink-muted); line-height: 1.5; }

.privacy { background: var(--ink); color: var(--mist); padding: clamp(36px, 5vw, 60px) var(--gutter); display: grid; gap: clamp(22px, 3.5vw, 36px); }
#privacy-heading { font-size: clamp(26px, 3.4vw, 34px); max-width: 22ch; }
.privacy ul { display: grid; gap: 24px; }
@media (min-width: 760px) { .privacy ul { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.privacy li { display: grid; gap: 8px; align-content: start; }
.privacy svg { width: 24px; height: 24px; stroke: var(--mint); }
.privacy strong { font-size: 16px; }
.privacy small { font-size: 14px; color: #c2d6cc; line-height: 1.45; }

.whatsapp { padding: clamp(32px, 5vw, 56px) var(--gutter); display: grid; gap: 14px; justify-items: start; background: var(--card); border-block: 1px solid var(--rule); }
#wa-heading { font-size: clamp(24px, 3.2vw, 32px); }
.whatsapp p:not(.status-pill) { max-width: 70ch; color: var(--ink-body); }
.status-pill {
  font-size: 13px; font-weight: 600;
  color: var(--pine); background: var(--tint); border-radius: 999px; padding: 6px 12px;
}

.contribute { display: flex; align-items: center; gap: clamp(16px, 3vw, 32px); flex-wrap: wrap; padding: clamp(28px, 4vw, 48px) var(--gutter); }
.contribute > div { flex: 1 1 320px; display: grid; gap: 6px; }
#add-heading { font-size: clamp(22px, 2.8vw, 28px); }
.contribute p { color: var(--ink-muted); max-width: 62ch; }

/* ---- footer --------------------------------------------------------- */

footer {
  background: var(--ink); color: #9bb5a8;
}
/* Links inherit the dark-on-mist link colour, which is unreadable here. */
footer a { color: var(--mint); }
footer a:hover { color: var(--mist); }
footer .foot-brand a {
  text-decoration: underline; display: inline-block; padding: 4px 0; min-height: 24px;
}
footer {
  padding: clamp(32px, 4vw, 48px) var(--gutter);
  display: grid; gap: 28px;
  grid-template-columns: minmax(0, 1.4fr) repeat(2, minmax(0, 1fr));
}
.foot-brand { display: grid; gap: 6px; align-content: start; }
.foot-brand .brand { color: var(--mist); font-size: 19px; }
.brand-mark-light { stroke: var(--mist); }
.foot-brand p { font-size: 13px; }
.foot-col { display: grid; gap: 9px; align-content: start; }
.foot-head { font-size: 13px; font-weight: 600; color: #c2d6cc; }
/* WCAG 2.2 asks for 24x24 on anything you have to hit. These were 21px
   tall, which is a miss on a phone and a miss for anybody whose hands
   are not steady. The padding does the work; the text stays the size it
   was, because a footer that shouts is a footer that competes with the
   page. */
.foot-col a {
  color: #9bb5a8; text-decoration: none; font-size: 13.5px;
  display: inline-block; padding: 4px 0; min-height: 24px;
}
.foot-col a:hover { color: var(--mint); text-decoration: underline; }
.foot-base {
  grid-column: 1 / -1; border-top: 1px solid #27362f; padding-top: 20px;
  display: flex; flex-wrap: wrap; align-items: baseline;
  gap: 10px clamp(16px, 4vw, 40px); justify-content: space-between;
}
.foot-legal { font-size: 12.5px; line-height: 1.6; max-width: 62ch; }
.foot-base-links { display: flex; flex-wrap: wrap; gap: 8px 20px; }
.foot-base-links a {
  font-size: 12.5px; text-decoration: none; white-space: nowrap;
  display: inline-block; padding: 5px 0; min-height: 24px;
}
.foot-base-links a:hover { text-decoration: underline; }

.svg-sprite { display: none; }

/* ---- rtl ------------------------------------------------------------ */



/* ---- responsive ----------------------------------------------------- */

@media (max-width: 1040px) {
  .ways { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .finder { grid-template-columns: 1fr; }
}
@media (max-width: 860px) {
  .site-header nav { width: 100%; margin-inline-start: 0; }
  .hero { grid-template-columns: 1fr; }
  .hero-stage { min-height: 0; order: -1; }
  .phone { width: 260px; height: 440px; }
  .chat-panel { position: static; width: 100%; margin-top: 16px; }
  footer { grid-template-columns: 1fr; }
  .partner-slot { height: 48px; font-size: 14px; }
  /* Fixed widths are for marks, which scale to fit them. A wordmark is
     nowrap text that needs whatever width it needs, and pinning it to the
     logo's box pushed "Northwestern University" straight through its
     neighbour. */
  .partner.has-logo.slot-wide { width: 200px; }
  .partner.has-logo.slot-narrow { width: 110px; }
}
@media (max-width: 560px) {
  .ways { grid-template-columns: 1fr; }
  .hero-actions .btn { width: 100%; }
  html:lang(ar) #hero-title,
  html:lang(fa) #hero-title,
  html:lang(ps) #hero-title,
  html:lang(ur) #hero-title {
    font-size: clamp(30px, 9vw, 36px);
    line-height: 1.24;
    min-height: 3.75em;
  }
}

/* ---- language picker & review banner -------------------------------- */

.lang-switch select {
  font: inherit; font-size: 14px; font-weight: 500; color: var(--ink);
  background: var(--card); border: 1px solid var(--control); border-radius: 999px;
  min-height: 42px; padding: 0 14px; cursor: pointer;
}
.lang-switch select:focus-visible { outline: 3px solid var(--fern); outline-offset: 2px; }
.lang-switch.is-enhanced select {
  display: none;
}
.lang-trigger {
  display: inline-flex; align-items: center; gap: 9px;
  min-height: 42px; max-width: min(210px, 100%); padding: 0 13px 0 12px;
  font: inherit; font-size: 14px; font-weight: 600; color: var(--ink);
  background: var(--card); border: 1px solid rgba(16,34,27,0.12); border-radius: 999px;
  box-shadow: 0 1px 2px rgba(8,67,47,0.06), 0 4px 12px rgba(8,67,47,0.04);
  cursor: pointer;
  transition: background-color var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}
.lang-trigger:hover { background: var(--band); }
.lang-trigger > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lang-trigger svg { width: 17px; height: 17px; flex: 0 0 auto; }
.lang-trigger .lang-chevron {
  width: 15px; height: 15px; margin-inline-start: 1px;
  transition: transform 180ms cubic-bezier(0.32, 0.72, 0, 1);
}
.lang-trigger[aria-expanded="true"] .lang-chevron { transform: rotate(180deg); }
.lang-menu {
  position: absolute; z-index: 45; inset-block-start: calc(100% + 8px); inset-inline-end: 0;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 4px;
  width: min(390px, calc(100vw - 32px)); max-height: min(70vh, 520px);
  padding: 8px; overflow-y: auto; overscroll-behavior: contain; scrollbar-width: thin;
  background: rgba(255,255,255,0.98); border-radius: 18px;
  box-shadow: 0 0 0 1px rgba(16,34,27,0.08), 0 12px 36px rgba(8,67,47,0.16);
  transform-origin: top right;
  transition: opacity 180ms cubic-bezier(0.32, 0.72, 0, 1),
    transform 180ms cubic-bezier(0.32, 0.72, 0, 1),
    filter 180ms cubic-bezier(0.32, 0.72, 0, 1);
}
html[dir="rtl"] .lang-menu { transform-origin: top left; }
.lang-switch.is-opening .lang-menu {
  opacity: 0; transform: translateY(-6px) scale(0.98); filter: blur(2px); transition: none;
}
.lang-switch.is-closing .lang-menu {
  opacity: 0; transform: translateY(-3px) scale(0.99); filter: blur(2px);
  transition-duration: 140ms; pointer-events: none;
}
.lang-option {
  display: grid; grid-template-columns: minmax(0, 1fr) 17px; align-items: center; gap: 8px;
  min-height: 42px; padding: 7px 10px; border: 0; border-radius: 11px;
  font: inherit; font-size: 15px; font-weight: 500; line-height: 1.25;
  color: var(--ink); background: transparent; cursor: pointer; text-align: start;
  transition: background-color var(--fast) var(--ease), color var(--fast) var(--ease);
}
.lang-option:hover, .lang-option:focus-visible { background: var(--band); }
.lang-option[aria-checked="true"] { background: var(--tint); color: var(--pine); font-weight: 600; }
.lang-option span { min-width: 0; unicode-bidi: isolate; }
.lang-option svg {
  width: 16px; height: 16px; opacity: 0; transform: scale(0.9);
  transition: opacity var(--fast) var(--ease), transform var(--fast) var(--ease);
}
.lang-option[aria-checked="true"] svg { opacity: 1; transform: scale(1); }
@media (max-width: 560px) {
  .lang-menu {
    position: fixed; inset: 72px 12px auto;
    width: auto; max-height: calc(100dvh - 88px); transform-origin: top center;
  }
  .lang-option { font-size: 14px; padding-inline: 8px; }
}
@media (prefers-reduced-motion: reduce) {
  .lang-trigger .lang-chevron, .lang-menu, .lang-option svg, .search-elapsed {
    transition: none;
  }
}

/* A language nobody has checked says so. Stated, not alarmed: this is
   information, and the page it sits above is still useful. */
.review-banner {
  margin: 0; padding: 10px var(--gutter);
  background: var(--band); color: var(--ink-body);
  font-size: 13.5px; line-height: 1.5;
  border-bottom: 1px solid var(--rule);
}

/* The count sits under the description as a quiet fact, not a badge. It is
   the only thing that differs between the three tiles, which is the point:
   the directory is not evenly spread and the tiles should not pretend it is. */
.way-count {
  margin-top: 2px; font-size: 13.5px; font-weight: 600; color: var(--spruce);
  font-variant-numeric: tabular-nums;
}

/* ---- result filters ---------------------------------------------------
   A subbar between the result count and the cards.

   Language and state are selects: twenty-eight languages and fifty states
   will not fit as chips, and when only the four commonest were offered, a
   Pashto speaker never saw Pashto and nobody could narrow a national
   search to one state at all. The select keeps its native control, so it
   opens as the platform's own picker on a phone and is reachable by
   keyboard and by voice without anything being reimplemented here.

   What is left as a chip is the one plain yes or no. */
.filters {
  display: grid; gap: 8px 12px; padding: 0 0 14px;
  grid-template-areas: "label label" "fields chips" "clear clear";
  grid-template-columns: auto 1fr; align-items: end;
}
.filters-label { grid-area: label; }
.filter-fields { grid-area: fields; }
.filter-chips { grid-area: chips; align-self: center; }
.filter-clear { grid-area: clear; justify-self: start; }
.filters-label { font-size: 13.5px; font-weight: 600; color: var(--ink); margin: 0; }
.filter-fields { display: flex; flex-wrap: wrap; gap: 8px 12px; }
.filter-field { display: grid; gap: 3px; margin: 0; }
.filter-field label { font-size: 12px; font-weight: 600; color: var(--ink-muted); }
.filter-field select {
  font: inherit; font-size: 14.5px; color: var(--ink); cursor: pointer;
  background: var(--card); border: 1.5px solid var(--control); border-radius: var(--r-ctl);
  min-height: 40px; max-width: 15rem; padding: 0 8px;
  transition: border-color var(--fast) var(--ease);
}
.filter-field select:hover { border-color: var(--spruce); }
.filter-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.chip {
  font: inherit; font-size: 14px; font-weight: 500; cursor: pointer; color: var(--ink);
  background: var(--card); border: 1.5px solid var(--control); border-radius: 999px;
  min-height: 40px; padding: 0 14px;
  transition: background-color var(--fast) var(--ease), border-color var(--fast) var(--ease),
    color var(--fast) var(--ease);
}
.chip:hover { border-color: var(--spruce); }
/* On state is fill plus weight, never colour alone: the palette is one hue
   and a green chip beside a white chip is not a difference everyone sees. */
.chip.is-on {
  background: var(--spruce); border-color: var(--spruce); color: #fff; font-weight: 600;
}
.filter-clear {
  font: inherit; font-size: 13.5px; cursor: pointer; color: var(--ink-muted);
  background: transparent; border: 0; padding: 6px 2px; min-height: 40px;
  text-decoration: underline; text-underline-offset: 2px;
}
.filter-clear:hover { color: var(--spruce); }
@media (max-width: 560px) {
  /* One control per row, each one full width and thumb-sized. A select
     squeezed next to another select is a select nobody hits. */
  .filters { grid-template-areas: "label" "fields" "chips" "clear"; grid-template-columns: 1fr; }
  .filter-fields { display: grid; grid-template-columns: 1fr; gap: 8px; }
  .filter-field select { max-width: none; width: 100%; min-height: 46px; }
  .chip { min-height: 46px; }
}

/* ---- coverage explorer -------------------------------------------------
   A grid cartogram rather than a geographic map, because no listing carries
   coordinates and a map-shaped thing invites people to read distance off it.
   Flat fills, one hairline, no shadow: the data is the only ornament. */
.atlas {
  padding: clamp(36px, 6vw, 72px) var(--gutter);
  background: var(--card); border-block: 1px solid var(--rule);
  display: grid; gap: clamp(20px, 3vw, 32px);
}
.atlas-intro { display: grid; gap: 8px; max-width: 60ch; }
#atlas-heading { font-size: clamp(26px, 3.4vw, 36px); }
.atlas-lede { font-size: 17px; color: var(--ink-body); }

.atlas-body { display: grid; gap: clamp(20px, 3vw, 40px); align-items: start; }
@media (min-width: 900px) { .atlas-body { grid-template-columns: minmax(0, 1fr) 280px; } }

.atlas-map { width: 100%; height: auto; display: block; }
.atlas-hint { font-size: 13.5px; color: var(--ink-muted); margin-top: 10px; }

.atlas-loading {
  grid-column: 1 / -1;
  display: grid; grid-template-columns: minmax(0, 1fr) 280px;
  gap: clamp(20px, 3vw, 40px); align-items: start;
}
.atlas-loading-map {
  min-height: clamp(220px, 42vw, 430px); padding: 8%;
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px;
  align-content: center;
}
.atlas-loading-map span {
  height: clamp(38px, 7vw, 70px); border-radius: 12px; background: var(--edge);
}
.atlas-loading-map span:nth-child(2) { transform: translateY(-22%); }
.atlas-loading-map span:nth-child(3) { transform: translateY(18%); }
.atlas-loading-map span:nth-child(4) { transform: translateY(-8%); }
.atlas-loading-map span:nth-child(5) { grid-column: 2 / 4; width: 72%; }
.atlas-loading-panel {
  min-height: 220px; padding: 22px; border: 1px solid var(--edge);
  border-radius: var(--r-card); background: var(--mist);
  display: grid; gap: 14px; align-content: start;
}
@media (max-width: 899px) {
  .atlas-loading { grid-template-columns: 1fr; }
  .atlas-loading-panel { display: none; }
}

.atlas-fallback {
  grid-column: 1 / -1;
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 16px; align-items: center;
  padding: clamp(18px, 3vw, 26px) 0;
  border-block: 1px solid var(--rule);
}
.atlas-fallback-icon {
  width: 44px; height: 44px; border-radius: 50%;
  display: grid; place-items: center; background: var(--mist); color: var(--spruce);
}
.atlas-fallback-icon svg {
  width: 22px; height: 22px; fill: none; stroke: currentColor;
  stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round;
}
.atlas-fallback strong { display: block; font-size: 16px; line-height: 1.35; }
.atlas-fallback p { margin-top: 4px; color: var(--ink-body); font-size: 14.5px; }
.atlas-fallback .btn { white-space: nowrap; }
.atlas-body > noscript { grid-column: 1 / -1; }
@media (max-width: 640px) {
  .atlas-fallback { grid-template-columns: auto 1fr; }
  .atlas-fallback .btn { grid-column: 1 / -1; justify-self: stretch; justify-content: center; }
}

/* Real state outlines. One hue, five steps, the same ramp as the rest of
   the site. Fern is deliberately absent from the fills: it is a mid-tone and
   a label on it measured 3.35:1 in pine and 3.38:1 in white, so nothing
   reads on it from either direction. It keeps its job as the focus ring,
   where it sits against paper. */
.state { fill: var(--mist); stroke: #fff; stroke-width: 1; stroke-linejoin: round; }
.state.step-1 { fill: var(--tint); }
.state.step-2 { fill: var(--mint); }
.state.step-3 { fill: var(--spruce); }
.state.step-4 { fill: var(--pine); }
.state.is-covered { cursor: pointer; }
.state.is-covered:hover { stroke: var(--pine); stroke-width: 2.5; }
.state.is-covered:focus-visible { outline: none; stroke: var(--fern); stroke-width: 3.5; }
.state.is-on { stroke: var(--ink); stroke-width: 3; }
/* The state somebody chose keeps a mark while the pointer is off looking
   at another one, so the panel's Search-in button still has an obvious
   owner on the map. */
.state.is-pinned { stroke: var(--ink); stroke-width: 2; stroke-dasharray: 5 3; }
.state.is-pinned.is-on { stroke-dasharray: none; }
@media (prefers-reduced-motion: no-preference) {
  .state { transition: fill var(--fast) var(--ease), stroke var(--fast) var(--ease); }
}

/* The label follows its fill rather than being one colour with a halo.
   A white label with a translucent outline looked fine on the dark states
   and measured 1.25:1 on the pale ones, which is not a label, it is a
   rumour of one. Dark ink on the two light steps, white on the two dark. */
.state-label {
  font-family: var(--display); font-size: 17px; font-weight: 700;
  text-anchor: middle; dominant-baseline: middle;
  pointer-events: none; user-select: none; fill: var(--pine);
  /* The SVG inherits a stroke from the icon rules, and with paint-order
     normal that stroke paints over the fill: California's label was white
     underneath and ink on top, which is just ink. */
  stroke: none;
}
.state-label.on-step-3, .state-label.on-step-4 { fill: #fff; }
.state-dot { fill: var(--fern); stroke: #fff; stroke-width: 2; pointer-events: none; }

.atlas-panel {
  display: grid; gap: 10px; align-content: start;
  padding: 22px; border: 1px solid var(--edge); border-radius: var(--r-card);
  background: var(--mist);
}
.atlas-panel-name { font-family: var(--display); font-size: 19px; font-weight: 600; color: var(--ink); }
.atlas-panel-total { font-size: 15px; color: var(--ink-muted); }
.atlas-panel-total #atlas-total {
  font-family: var(--display); font-size: 40px; font-weight: 800; color: var(--spruce);
  display: block; line-height: 1; letter-spacing: -0.03em; font-variant-numeric: tabular-nums;
}
.atlas-split { display: grid; gap: 1px; margin-top: 6px; }
.atlas-split-row {
  display: flex; justify-content: space-between; gap: 12px;
  padding: 9px 0; border-top: 1px solid var(--rule); font-size: 14.5px;
}
.atlas-split-row dt { color: var(--ink-body); }
.atlas-split-row dd { margin: 0; font-weight: 600; font-variant-numeric: tabular-nums; }
#atlas-search { margin-top: 6px; justify-content: center; }

/* ---- services grid ----------------------------------------------------
   Tiles as a way in, not as decoration: each one runs the search it names
   and carries the number of places behind it, so the grid cannot promise
   something the search would then fail to find.

   Flat on purpose. One hairline, no shadow, no lift on hover: a shadow
   under every tile is the thing that makes a grid look generated, and ten
   of them stacked reads as noise. */
.offer {
  padding: clamp(32px, 5vw, 56px) var(--gutter);
  display: grid; gap: 18px;
}
#offer-heading { font-size: clamp(22px, 2.8vw, 28px); }
.offer-grid {
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fit, minmax(168px, 1fr));
}
.offer-tile {
  font: inherit; text-align: start; cursor: pointer; color: var(--ink);
  background: var(--card); border: 1px solid var(--edge);
  border-radius: var(--r-card); padding: 18px;
  display: grid; gap: 7px; justify-items: start; align-content: start;
  transition: border-color var(--fast) var(--ease), background-color var(--fast) var(--ease);
}
.offer-tile:hover { border-color: var(--spruce); background: var(--band); }
.offer-tile svg {
  width: 24px; height: 24px; stroke: var(--spruce); stroke-width: 1.6;
  fill: none; stroke-linecap: round; stroke-linejoin: round;
}
.offer-tile strong { font-size: 16px; font-weight: 600; line-height: 1.25; }
.offer-tile small {
  font-size: 13.5px; color: var(--ink-muted); font-variant-numeric: tabular-nums;
}

/* ---- splash -----------------------------------------------------------
   The mark is a route that ends in a dot, so the animation is the route
   being drawn and the dot arriving. That is the product in one gesture:
   here is the way, and here is where it ends.

   It is also the most dangerous animation on the site. A splash fires on
   every single visit, and some of those visits are someone looking for a
   shelter bed tonight. So it is built to lose: 620ms of drawing, a hard
   900ms cap in app.js, dismissed the instant the page is ready, shown once
   per session, and skipped outright under reduced motion. It may never
   delay anyone. If it is ever in doubt, it goes. */
.splash {
  position: fixed; inset: 0; z-index: 60;
  display: grid; place-content: center; justify-items: center; gap: 18px;
  background: var(--mist);
}
.splash-mark { width: 84px; height: 84px; overflow: visible; }
.splash-path {
  fill: none; stroke: var(--spruce); stroke-width: 4;
  stroke-linecap: round; stroke-linejoin: round;
}
.splash-dot { fill: var(--fern); }
/* The light the dot comes on with. Invisible until the route reaches it. */
.splash-glow { fill: var(--mint); opacity: 0; transform-origin: 38px 11px; }
.splash-word {
  font-family: var(--display); font-size: 21px; font-weight: 600;
  letter-spacing: -0.02em; color: var(--ink);
}

@media (prefers-reduced-motion: no-preference) {
  /* 96 is a little over the path's own length, so the line is fully hidden
     before it starts and fully drawn when it ends. */
  .splash-path { stroke-dasharray: 96; stroke-dashoffset: 96; animation: ww-draw 620ms var(--ease) forwards; }
  /* 0.85, not 0.4. A small element scaling up from well under half its
     size pops rather than arrives, and on a 4.5px dot the travel was
     never the point: the opacity does the arriving and the bloom behind
     it does the lighting up. */
  .splash-dot { opacity: 0; transform: scale(0.85); transform-origin: 38px 11px; animation: ww-land 240ms var(--ease) 560ms forwards; }
  /* Starts exactly as the route reaches the dot and is done at 860ms,
     inside the 900ms cap, so a fast load never cuts it mid-expansion. */
  .splash-glow { animation: ww-glow 300ms var(--ease) 560ms forwards; }
  .splash-word { opacity: 0; animation: ww-fade 300ms var(--ease) 420ms forwards; }
  .splash.is-done { animation: ww-splash-out 260ms var(--ease) forwards; pointer-events: none; }
}
/* Under reduced motion the overlay is simply removed, never faded. */
@media (prefers-reduced-motion: reduce) {
  .splash { display: none; }
}

@keyframes ww-draw { to { stroke-dashoffset: 0; } }
@keyframes ww-land { to { opacity: 1; transform: scale(1); } }
/* Out and gone, once. A halo that pulses is a halo that has to be
   explained; this one just says the route arrived somewhere. */
@keyframes ww-glow {
  from { opacity: 0.5; transform: scale(1); }
  to   { opacity: 0; transform: scale(2.6); }
}
@keyframes ww-fade { to { opacity: 1; } }
@keyframes ww-splash-out { to { opacity: 0; visibility: hidden; } }

/* The query's reading, shown while the skeletons are up. Deliberately
   quiet and deliberately still: the skeletons already say "working", and a
   second moving thing on a screen somebody is waiting at is noise. */
.search-read {
  font-size: 13.5px; color: var(--ink-muted); line-height: 1.5;
  margin: -4px 0 10px;
}
/* Preserve source-critical names, addresses, and phone numbers inside RTL
   layouts without forcing their punctuation into the surrounding direction. */
[dir="auto"] { unicode-bidi: plaintext; }

/* Small states label off the coast with a hairline back to the shape. */
/* Eight leaders arrive at one column of labels, so they have to be
   followable rather than merely present. Darker than the borders they
   cross, an elbow so the last stretch is horizontal, and a stop at the
   state end so the line points at a place and not into a crowd. */
.state-leader {
  fill: none; stroke: var(--spruce); stroke-width: 1.4; opacity: 0.55;
  stroke-linecap: round; stroke-linejoin: round;
}
.state-leader-anchor { fill: var(--spruce); stroke: none; opacity: 0.55; }
.state-label.is-outset { fill: var(--ink); font-size: 15px; stroke: none; }

/* Save sits with the other result actions but reads as a state, not a
   command: a row of identical Save buttons tells you nothing about what
   you already kept. */
.result-save {
  font: inherit; font-size: 14px; font-weight: 600; cursor: pointer;
  color: var(--spruce); background: transparent;
  border: 1.5px solid var(--control); border-radius: var(--r-ctl);
  min-height: 46px; padding: 0 16px;
  transition: background-color var(--fast) var(--ease), border-color var(--fast) var(--ease), color var(--fast) var(--ease);
}
.result-save:hover { border-color: var(--spruce); background: var(--band); }
.result-save.is-on { background: var(--spruce); border-color: var(--spruce); color: #fff; }
.saved-count {
  display: inline-block; min-width: 20px; padding: 0 6px; margin-inline-start: 6px;
  border-radius: 999px; background: var(--tint); color: var(--pine);
  font-size: 12.5px; font-weight: 700; line-height: 20px; text-align: center;
  font-variant-numeric: tabular-nums;
}

/* ---- the assistant -----------------------------------------------------
   The search section is the assistant, so it wears the assistant's face:
   the same mark, name and line the phone shows. Everything else here is
   the composer, not a form. No theatre, because the people reading this
   are usually in a hurry and sometimes frightened. */
.assistant { display: flex; align-items: center; gap: 11px; }
.assistant-avatar {
  width: 40px; height: 40px; flex: 0 0 auto; border-radius: 999px;
  background: var(--spruce); display: flex; align-items: center; justify-content: center;
}
.assistant-avatar svg { width: 22px; height: 22px; stroke: var(--mist); stroke-width: 5; fill: none; }
.assistant-id { display: grid; min-width: 0; }
.assistant-id strong { font-family: var(--display); font-size: 17px; font-weight: 600; color: var(--ink); }
.assistant-id small { font-size: 13.5px; color: var(--ink-muted); }

/* A composer, not a search box: one pill, the send action inside it. */
.composer {
  display: flex; align-items: center; gap: 8px;
  background: var(--card); border: 1.5px solid var(--control);
  border-radius: 999px; padding: 5px 5px 5px 18px;
  transition: border-color var(--fast) var(--ease);
}
.composer:focus-within { border-color: var(--spruce); }
.composer input {
  flex: 1 1 auto; min-width: 0; font: inherit; font-size: 17px; color: var(--ink);
  background: transparent; border: 0; height: 48px; padding: 0;
}
.composer input:focus { outline: none; }
.composer-send {
  width: 46px; height: 46px; flex: 0 0 auto; border: 0; cursor: pointer;
  border-radius: 999px; background: var(--spruce);
  display: flex; align-items: center; justify-content: center;
  transition: background-color var(--fast) var(--ease), transform var(--fast) var(--ease);
}
.composer-send svg { width: 20px; height: 20px; stroke: #fff; stroke-width: 2; fill: none; stroke-linecap: round; stroke-linejoin: round; }
.composer-send:hover { background: var(--pine); }
.composer-send:active { transform: scale(0.96); }

/* The assistant asking where you are, after a category is chosen. */
.ask-where {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px;
  font-size: 15.5px; line-height: 1.5; color: var(--ink);
  padding: 12px 14px; background: var(--tint);
  border-inline-start: 4px solid var(--spruce);
  border-radius: 0 var(--r-ctl) var(--r-ctl) 0;
}
.ask-where strong { font-weight: 600; color: var(--pine); }
.ask-hint { color: var(--pine); }
.ask-skip {
  font: inherit; font-size: 14px; cursor: pointer; color: var(--pine);
  background: transparent; border: 0; padding: 4px 0; min-height: 32px;
  text-decoration: underline; text-underline-offset: 2px;
}
.ask-skip:hover { color: var(--ink); }
.quick-searches button.is-on {
  background: var(--spruce); border-color: var(--spruce); color: #fff;
}

/* ---- the WhatsApp mark -------------------------------------------------
   Next to the word wherever it names the channel: the hero's second
   action, the section on this page, and the WhatsApp heading in the
   privacy policy and the terms. Not inside running sentences, where a logo
   interrupts the line and a screen reader has nothing useful to say about
   it. The glyph is decorative in every one of those places, because the
   word it sits beside is already there. */
.has-mark { display: flex; align-items: center; gap: 10px; }
.wa-mark { width: 1.05em; height: 1.05em; flex: 0 0 auto; }

/* The last two chips: the rest of the directory, two specialities at a
   time. A dashed outline rather than a fill, so they read as "and these
   too" beside the four that never change.

   Out is quicker and smaller than in, both on the project's curve, and
   only opacity and transform move. The width is reserved in script from
   the longest label, so a longer word arriving never reflows the row. */
.quick-searches .chip-more {
  border-style: dashed;
  transition:
    opacity 140ms var(--ease),
    transform 140ms var(--ease),
    background-color var(--fast) var(--ease),
    border-color var(--fast) var(--ease),
    color var(--fast) var(--ease);
}
.quick-searches .chip-more.is-leaving {
  opacity: 0;
  transform: translateY(-4px);
}
.quick-searches .chip-more.is-arriving {
  animation: chip-arrive 200ms var(--ease) both;
}
@keyframes chip-arrive {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  /* Decorative, so the honest answer is to remove it rather than speed
     it up. The script does not rotate at all under this preference; this
     is here so a swap that does happen is a cut, not a fade. */
  .quick-searches .chip-more,
  .quick-searches .chip-more.is-leaving,
  .quick-searches .chip-more.is-arriving {
    opacity: 1; transform: none; animation: none; transition: none;
  }
}

/* ---- motion -----------------------------------------------------------
   Three moments, each tied to something that actually happened: the
   search is running, the answer arrived, the view changed. Nothing loops,
   nothing waits on anything, and every one of them is off entirely under
   prefers-reduced-motion. */

/* The search is running. A thin line travels the width of the composer
   that started it: the only moving thing on screen at that moment, and
   attached to the control responsible for it. */
.zip-form .composer { position: relative; }
.zip-form.is-searching .composer::after {
  content: ""; position: absolute; inset-inline: 10px; bottom: -3px; height: 2px;
  border-radius: 2px; background: var(--fern);
  transform-origin: left center;
  animation: composer-sweep 1.1s var(--ease) infinite;
}
@keyframes composer-sweep {
  0%   { transform: scaleX(0.08) translateX(0); opacity: 0.4; }
  50%  { transform: scaleX(0.55) translateX(70%); opacity: 1; }
  100% { transform: scaleX(0.08) translateX(1150%); opacity: 0.4; }
}

/* The answer arrived. Cards rise in sequence, 40ms apart, first six only. */
.is-arriving { animation: arrive 220ms var(--ease) both; animation-delay: var(--arrive-delay, 0ms); }
@keyframes arrive {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

/* A page arrived. The same rise, once, on the main column, so moving
   between About, Saved, Contact and the search reads as one site rather
   than four hard cuts. Opacity only below the fold-crossing threshold,
   because a document that slides is a document that feels slow. */
@media (prefers-reduced-motion: no-preference) {
  .doc, .finder-main { animation: page-in 260ms var(--ease) both; }
}
@keyframes page-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .zip-form.is-searching .composer::after { animation: none; transform: scaleX(1); opacity: 0.5; }
  .is-arriving { animation: none; }
}

/* ---- the chosen state --------------------------------------------------
   Picking a state on the map brings you here, to the composer, with the
   state already held and the question still yours to ask. The shape is
   the real outline, the numbers are the real counts.

   There are no dots on it. Not one of the 8,212 listings carries a
   coordinate, only an address, so a dot per location would be a position
   this project made up. */
.state-card {
  display: grid; gap: 10px; padding: 14px 16px;
  background: var(--card); border: 1px solid var(--edge); border-radius: var(--r-card);
}
.state-card-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
/* The map is the point of this panel now that there is something to put
   on it, so it gets the width rather than sitting beside the text as a
   58px thumbnail nobody could read a dot on. */
.state-card-map { width: 100%; height: auto; max-height: 230px; }
.state-card-shape { fill: var(--tint); stroke: var(--spruce); stroke-width: 1.2; }
/* One dot per place we know the position of. Small, and semi-opaque so a
   cluster reads as a cluster: in a city they overlap, and a solid fill
   would turn forty clinics into one blob. */
.state-card-dots circle { fill: var(--pine); fill-opacity: 0.55; stroke: none; }
.state-card-shown { margin: 0; font-size: 12.5px; color: var(--ink-muted); }
.state-card-name { margin: 0; font-family: var(--display); font-size: 17px; font-weight: 700; color: var(--ink); }
.state-card-total { margin: 0; font-size: 14px; color: var(--ink-body); }
.state-card-total span {
  font-family: var(--display); font-size: 22px; font-weight: 700; color: var(--spruce);
  font-variant-numeric: tabular-nums; margin-inline-end: 5px;
}
/* Two lists, two jobs. The three categories are the summary: bold, ruled,
   read as headline figures. The ten specifics below are the detail, and
   they are a chart rather than a table. */
.state-card-split { margin: 0; display: grid; gap: 2px; }
.state-card-row {
  position: relative;
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  font-size: 14px; color: var(--ink-body);
  border-top: 1px solid var(--rule); padding: 5px 0 4px;
}
.state-card-row dt { min-width: 0; }
.state-card-row dd {
  margin: 0; font-weight: 600; font-variant-numeric: tabular-nums;
  flex: 0 0 auto;
}

/* The specifics. Separated from the summary by space rather than another
   rule, because a fourth rule in a row of three makes thirteen things
   that look alike, which is what this list read as before. */
.state-card-detail { margin-top: 10px; gap: 1px; }
.state-card-detail .state-card-row {
  font-size: 13px; color: var(--ink-body); border-top: 0;
  padding: 4px 8px; border-radius: 6px;
}
.state-card-detail .state-card-row dd { font-weight: 600; color: var(--ink); }

/* The bar is a sibling behind the text, not a background on the row, so
   it respects writing direction without a second rule for RTL. Tint, so
   the number on top of it stays at full contrast. */
.state-card-bar {
  position: absolute; inset-block: 0; inset-inline-start: 0;
  background: var(--tint); border-radius: 6px; z-index: 0;
}
.state-card-detail .state-card-row dt,
.state-card-detail .state-card-row dd { position: relative; z-index: 1; }
.state-card-clear {
  font: inherit; font-size: 13.5px; cursor: pointer; color: var(--ink-muted);
  background: transparent; border: 0; padding: 4px 0; justify-self: start;
  text-decoration: underline; text-underline-offset: 2px;
}
.state-card-clear:hover { color: var(--spruce); }


/* ---- on a phone --------------------------------------------------------
   Most of the people this is for are holding a phone, often an old one,
   often one-handed on a bus. Everything that can be pressed is at least
   46px tall, the actions go two to a row instead of four, and nothing
   that matters hides behind a horizontal scroll. */
@media (max-width: 560px) {
  .result-card { padding: 16px 15px; }
  .result-identity { grid-template-columns: auto 46px minmax(0, 1fr); gap: 10px; }
  .result-identity.has-logo { grid-template-columns: auto 52px minmax(0, 1fr); }
  .org-mark { width: 46px; height: 46px; }
  .org-mark.has-glyph svg { width: 25px; height: 25px; }
  .org-mark.has-image { width: 52px; }
  .result-card h3 { font-size: 18px; line-height: 1.3; }
  .result-index { min-width: 24px; height: 24px; font-size: 12.5px; }

  /* Two to a row: a four-up row of buttons on a 360px screen is four
     buttons nobody can hit. Call keeps the full width because it is the
     one most people are reaching for. */
  .result-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
  .result-actions .btn, .result-save { min-height: 48px; font-size: 15.5px; }
  .result-actions .btn-primary { grid-column: 1 / -1; }

  .fact { font-size: 15px; }
  .result-footer { gap: 8px 12px; }

  /* The strip of logos is decoration. On a phone it is decoration that
     costs a loop of animation and a quarter of the screen. */
  .partners { padding-block: 14px; }
  .state-card-head { gap: 12px; }
}

/* Very narrow phones, where a two-up action row stops fitting at all.
   Not 380: a 375px iPhone holds two buttons comfortably and stacking
   them there turns one card into a whole screen of scrolling. */
@media (max-width: 340px) {
  .result-actions { grid-template-columns: 1fr; }
  .badges { gap: 5px; }
  .badge { font-size: 12.5px; padding: 5px 9px; }
}
