/* ============================================================================
   Find confession — parity with the iOS client's Find Confession tab.

   Structure the brief asks for: persistent chrome (search bar + filter chips)
   over a purple brand band, and the results on a large rounded paper card that
   rises into it. Everything below is tokens (INV-10); the three service accents
   are normative and never substituted, and they always run
   Confession → Mass → Adoration.
   ========================================================================== */

.find {
  --c-conf: var(--purple);
  --c-mass: var(--blue);
  --c-ador: var(--orange);
  /* The confidence ramp's middle step is a flag glyph, so it is a mark and
     owes 3:1 (ADR-034's severity ramp, ADR-094's threshold). */
  --warn: var(--orange-mark);
  --warn-soft: color-mix(in oklab, var(--orange) 55%, var(--paper));
  /* WAS `#908A9F` in light and `#9C93AE` in dark — two hand-copied values of
     `--ink-3`, in the file whose header says everything below is tokens. They
     stopped agreeing with the contract the moment ADR-092 deepened it, and
     nothing could have caught that: a copy is a copy of a value, not of a
     token, so it drifts silently. Both themes come from the token now. */
  --muted: var(--ink-3);
}

:root {
  /* The band is the page's brand device, but it is not the same object in both
     themes. In light mode a deep purple slab across the top third made the
     page read as a dark page with a white card stuck to it; here it is a
     luminous lavender field the paper card still rises out of. In dark mode
     the deep band is the right answer and stays. Everything painted ON the
     band — ink, chips, segment track — therefore has to be a token, not a
     literal moon. */
  --band-1: #F7F2FD;
  --band-2: #E8DCF8;
  --band-glow: color-mix(in oklab, var(--purple) 17%, transparent);
  --band-ink: var(--ink);
  --band-ink-2: var(--ink-2);
  --band-em: var(--purple);
  --band-chip-bg: var(--surface);
  --band-chip-hover: color-mix(in oklab, var(--purple) 6%, var(--surface));
  --band-chip-line: var(--hairline-2);
  --band-chip-ink: var(--ink);
  --band-seg-track: color-mix(in oklab, var(--purple) 9%, var(--surface));
  --band-seg-ink: var(--ink-2);
}

/* The generic dark tokens now live in styles.css, keyed off `data-theme` so the
   reader's Light / Dark / Match-system pick can override the OS. Only the band
   and the things that read off it are find-specific. */
:root[data-theme="dark"] {
  --band-1: #17082F;
  --band-2: #35108A;
  --band-glow: color-mix(in oklab, var(--purple) 44%, transparent);
  --band-ink: var(--moon);
  --band-ink-2: color-mix(in oklab, var(--moon) 72%, var(--band-1));
  --band-em: color-mix(in oklab, var(--orange) 72%, var(--moon));
  --band-chip-bg: color-mix(in oklab, var(--moon) 12%, transparent);
  --band-chip-hover: color-mix(in oklab, var(--moon) 20%, transparent);
  --band-chip-line: color-mix(in oklab, var(--moon) 18%, transparent);
  --band-chip-ink: var(--moon);
  --band-seg-track: color-mix(in oklab, var(--moon) 12%, transparent);
  --band-seg-ink: color-mix(in oklab, var(--moon) 74%, var(--band-2));
}

[data-theme="dark"] .site-header.is-scrolled {
  background: color-mix(in oklab, var(--paper) 88%, transparent);
}

/* Over the band the button has no paper to sit on, so it borrows moon the way
   the wordmark and nav links beside it do. Dark theme only — the light band is
   pale, and the header's ordinary ink is what reads on it. */
[data-theme="dark"] .site-header:not(.is-scrolled) .site-nav:not(.is-open) .appear__btn {
  color: color-mix(in oklab, var(--moon) 76%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--moon) 26%, transparent);
}
[data-theme="dark"] .site-header:not(.is-scrolled) .site-nav:not(.is-open) .appear__btn:hover,
[data-theme="dark"] .site-header:not(.is-scrolled) .site-nav:not(.is-open) .appear__btn[aria-expanded="true"] {
  color: var(--moon);
  box-shadow: inset 0 0 0 1.5px color-mix(in oklab, var(--moon) 55%, transparent);
}

/* ---------- brand band ----------------------------------------------------
   In DARK mode the fixed header sits over a deep band until the reader
   scrolls, so its ink has to invert while it is there. In light mode the band
   is pale and the header's ordinary ink is correct, so none of this applies —
   hence the theme gate. `:not(.is-open)` keeps the mobile menu overlay, which
   paints its own paper background, out of it. */

[data-theme="dark"] .site-header:not(.is-scrolled) .wordmark,
[data-theme="dark"] .site-header:not(.is-scrolled) .site-nav:not(.is-open) a:not(.btn) { color: var(--moon); }
[data-theme="dark"] .site-header:not(.is-scrolled) .site-nav:not(.is-open) a:not(.btn):hover { color: white; }
[data-theme="dark"] .site-header:not(.is-scrolled) .site-nav:not(.is-open) .nav-n { color: color-mix(in oklab, var(--orange) 60%, var(--moon)); }
[data-theme="dark"] .site-header:not(.is-scrolled) .site-nav:not(.is-open) a:not(.btn)::after { background: var(--moon); }
[data-theme="dark"] .site-header:not(.is-scrolled) .nav-div { background: color-mix(in oklab, var(--moon) 32%, transparent); }
[data-theme="dark"] .site-header:not(.is-scrolled) .nav-toggle { box-shadow: inset 0 0 0 1.5px color-mix(in oklab, var(--moon) 38%, transparent); }
[data-theme="dark"] .site-header:not(.is-scrolled) .nav-toggle:not(.is-open) span,
[data-theme="dark"] .site-header:not(.is-scrolled) .nav-toggle:not(.is-open) span::before,
[data-theme="dark"] .site-header:not(.is-scrolled) .nav-toggle:not(.is-open) span::after { background: var(--moon); }

.band {
  /* The glow is a background layer, not a pseudo-element: an overflowing
     `::before` forced `overflow: hidden` on the band, and that clipped the
     desktop search dropdown, which has to hang below it. Background layers are
     clipped to the element for free. */
  background:
    radial-gradient(38rem 34rem at 86% -34%, var(--band-glow) 0%, transparent 64%),
    linear-gradient(168deg, var(--band-1), var(--band-2));
  color: var(--band-ink);
  padding-top: calc(var(--space-hero) - 1rem);
  padding-bottom: 5.5rem;
  position: relative;
}

.band__inner { position: relative; }

.band__h1 {
  font-size: clamp(2.4rem, 5.6vw, 4rem);
  color: var(--band-ink);
  margin-bottom: 0.6rem;
}
.band__h1 em { color: var(--band-em); font-weight: 400; }

.band__sub {
  color: var(--band-ink-2);
  font-weight: 300;
  margin-bottom: 2rem;
  max-width: 34rem;
}

/* ---------- search bar (a button; typing happens on the search page) ------- */

/* ---------- search bar ----------------------------------------------------
   On desktop this IS the field: the reader types into it and picks from a
   dropdown. The full-screen search page stays for phones, and for the Route
   and Map modes, which need more room than a bar.  */

.sbarwrap { position: relative; width: min(100%, 40rem); }

/* The same segmented vocabulary as the List/Map switch, set above the bar so
   the bar keeps its own width and shadow. It wears the chip capsule itself
   rather than borrowing `.chip2`, so the canvas's markup ports as drawn. */
.smodeseg {
  display: inline-flex;
  align-items: center;
  border-radius: 999px;
  margin-bottom: 0.7rem;
  width: max-content;
  max-width: 100%;
  background: var(--band-chip-bg);
  box-shadow: inset 0 0 0 1px var(--band-chip-line);
}
.smodeseg button {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  background: none;
  border: 0;
}
.smodeseg button svg { flex: none; }
.smodeseg button.is-on svg { color: var(--purple); }
/* Never the full width of a phone: a three-option switch is as wide as its
   three options, and it wraps onto a second line before it stretches. */
.smodeseg { flex-wrap: wrap; row-gap: 2px; }
.smodeseg button { flex: 0 0 auto; }

/* The mode panels stand where the bar stands, and each one fades and lifts
   into place when it is chosen. Nothing moves except the panel itself. */
@keyframes smIn {
  from { opacity: 0; transform: translateY(-6px) scale(0.995); }
  to   { opacity: 1; transform: none; }
}
.sbarinline { display: grid; gap: 0.6rem; }
.sbarinline[hidden] { display: none; }
.sbar[hidden] { display: none; }
.sbarinline .rtcard, .sbarinline .sp__pickmap { box-shadow: var(--shadow-md); }
.sbarinline .sp__pickmap { height: 20rem; border-radius: var(--r-lg); }
.is-smanim { animation: smIn 260ms var(--ease-out) both; }
.sdrop--inline { top: calc(100% + 0.5rem); }
@media (prefers-reduced-motion: reduce) { .is-smanim { animation: none; } }

/* The results switch carries symbols too, so the two switches read as the
   same kind of control. The chosen segment is brand-filled, so its glyph takes
   the segment's own ink — purple on purple was no glyph at all. */
.segchip button svg { flex: none; }

.sbar {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  width: 100%;
  text-align: left;
  cursor: text;
  background: var(--surface);
  border-radius: 999px;
  padding: 0.7rem 0.85rem 0.7rem 1.15rem;
  box-shadow: var(--shadow-md);
  transition: transform 220ms var(--ease-out), box-shadow 220ms var(--ease-out);
}
.sbar:hover { transform: translateY(-1px); box-shadow: var(--shadow-lg); }
.sbar.is-typing { transform: none; box-shadow: var(--shadow-lg), 0 0 0 3px color-mix(in oklab, var(--purple) 40%, transparent); }

.sbar__ic {
  flex-shrink: 0;
  width: 40px; height: 40px;
  border-radius: 999px;
  display: grid; place-items: center;
  background: color-mix(in oklab, var(--purple) 10%, var(--surface));
  color: var(--purple);
}

.sbar__txt { flex: 1 1 auto; min-width: 0; display: grid; gap: 0.1rem; }

.sbar__lbl {
  font-size: 0.62rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}

.sbar__val {
  font-size: 0.98rem;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sbar__val small { color: var(--muted); font-size: 0.84em; }
/* The empty state is a HINT when there is nothing to show, and a VALUE when
   "Current Location" is the answer — so it is not styled the same way. */
.sbar.is-hint .sbar__val { color: var(--muted); }

.sbar__clear {
  flex-shrink: 0;
  width: 34px; height: 34px;
  border-radius: 999px;
  display: grid; place-items: center;
  color: var(--muted);
  font-size: 1.2rem;
  line-height: 1;
  cursor: pointer;
}
.sbar__clear:hover { background: var(--paper-3); color: var(--ink); }
.sbar__clear[hidden] { display: none; }

/* The location offer (ADR-129). Deliberately the quiet control next to the
   field rather than the loud one in front of it: it is one way to answer
   "where?", and the field is the other. */
.sbar__geo {
  flex-shrink: 0;
  /* 44, not the 34 the clear affordance uses beside it: that one is hidden
     until there is something to clear, and the tap-target sweep never measures
     it. This one is on screen from load. */
  width: 44px; height: 44px;
  border-radius: 999px;
  display: grid; place-items: center;
  color: var(--muted);
  cursor: pointer;
}
.sbar__geo:hover { background: var(--paper-3); color: var(--purple); }
.sbar__geo[disabled] { opacity: 0.5; cursor: default; }

.sbar__input {
  display: none;
  width: 100%;
  border: 0; background: none; outline: none; padding: 0;
  font-size: 0.98rem;
  color: var(--ink);
}
.sbar__input::placeholder { color: var(--muted); }
.sbar__input::-webkit-search-cancel-button { -webkit-appearance: none; }
.sbar.is-typing .sbar__val { display: none; }
.sbar.is-typing .sbar__input { display: block; }

.sdrop {
  position: absolute;
  top: calc(100% + 0.5rem);
  left: 0; right: 0;
  z-index: 60;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-lg);
  padding: 0.35rem;
  max-height: 26rem;
  overflow-y: auto;
}
.sdrop[hidden] { display: none; }

/* A geocoder answer. One row per candidate place, and the reader picks —
   ADR-129 forbids choosing the first one for them, because "Springfield" is
   the case this list exists for. */
.sdrop__row {
  display: block;
  width: 100%;
  text-align: left;
  padding: 0.6rem 0.7rem;
  border-radius: var(--r-sm);
  font: inherit; font-size: 0.9rem; color: var(--ink);
  cursor: pointer;
}
.sdrop__row:hover, .sdrop__row:focus-visible { background: var(--paper-2); }
.sdrop__hd {
  padding: 0.35rem 0.7rem 0.45rem;
  font-size: 0.78rem;
  color: var(--muted);
}

.sdrop__foot {
  display: flex;
  gap: 0.3rem;
  margin-top: 0.35rem;
  padding-top: 0.4rem;
  border-top: 1px solid var(--hairline);
}
.sdrop__foot button {
  flex: 1 1 0;
  display: flex; align-items: center; gap: 0.55rem;
  padding: 0.55rem 0.7rem;
  border-radius: var(--r-sm);
  font: inherit; font-size: 0.84rem; color: var(--ink-2);
  cursor: pointer;
}
.sdrop__foot button:hover { background: var(--paper-2); color: var(--ink); }
.sdrop__foot svg { color: var(--purple); flex-shrink: 0; }

/* ---------- filter chips -------------------------------------------------- */

.chiprow {
  display: flex;
  gap: 0.45rem;
  margin-top: 1rem;
  overflow-x: auto;
  scrollbar-width: none;
  padding-bottom: 0.2rem;
}
.chiprow::-webkit-scrollbar { display: none; }

.chip2 {
  position: relative;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  height: 38px;
  padding: 0 0.85rem;
  border-radius: 999px;
  font-size: 0.82rem;
  font-weight: 500;
  color: var(--band-chip-ink);
  background: var(--band-chip-bg);
  box-shadow: inset 0 0 0 1px var(--band-chip-line);
  cursor: pointer;
  white-space: nowrap;
}
.chip2:hover { background: var(--band-chip-hover); }
.chip2 .dot2 { width: 8px; height: 8px; border-radius: 999px; background: currentColor; }
.chip2 .chev { opacity: 0.65; }

/* The List/Map chip shows both labels always; the current one is filled with
   the brand, as iOS's segmented chip is. It is the chip capsule with 3px of it
   left showing round the segments. */
.segchip { padding: 3px; gap: 2px; cursor: default; }
.segchip:hover { background: var(--band-chip-bg); }
.segchip button {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  height: 32px;
  padding: 0 0.8rem;
  border-radius: 999px;
  font: inherit;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--band-seg-ink);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background 200ms, color 200ms;
}
.segchip button.is-on { background: var(--purple-fill); color: white; }

/* Fixed, not absolute: the chip row is a horizontal scroll container, and an
   absolutely positioned child of a scroller gets clipped by it. The open
   position is written by JS from the chip's rect. */
.menu {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 200;
  min-width: 12rem;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-lg);
  padding: 0.35rem;
  display: grid;
  gap: 1px;
}
.menu[hidden] { display: none; }
.menu button {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  width: 100%;
  padding: 0.55rem 0.7rem;
  border-radius: var(--r-sm);
  font: inherit;
  font-size: 0.88rem;
  color: var(--ink);
  text-align: left;
  cursor: pointer;
}
.menu button:hover { background: var(--paper-2); }
.menu .tick2 { margin-left: auto; color: var(--purple); opacity: 0; }
.menu button.is-on .tick2 { opacity: 1; }

/* ---------- the paper card ------------------------------------------------ */

.paper {
  background: var(--paper);
  border: 1px solid var(--hairline);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
  margin-top: -3.75rem;
  margin-bottom: 2rem;
  padding: 1.1rem clamp(0.9rem, 2.5vw, 1.6rem) 1.6rem;
  position: relative;
  z-index: 5;
}

/* ---------- day strip ----------------------------------------------------- */

.dayrow { display: flex; align-items: stretch; gap: 0.9rem; }

.daystrip {
  display: flex;
  gap: 0.35rem;
  overflow-x: auto;
  scrollbar-width: none;
  flex: 1 1 auto;
  min-width: 0;
  padding-bottom: 0.3rem;
}
/* The edge only fades when the strip actually scrolls — a chip cut clean off
   reads as a bug rather than as something to scroll, but a fade over a strip
   that fits reads as unexplained dimming. JS sets the class. */
.daystrip.is-scrollable {
  -webkit-mask-image: linear-gradient(90deg, transparent, black 2.5%, black 96%, transparent);
          mask-image: linear-gradient(90deg, transparent, black 2.5%, black 96%, transparent);
}
.daystrip::-webkit-scrollbar { display: none; }
/* With a banner beside it the strip gives up room rather than pushing it out. */
.dayrow.has-hd .daystrip { flex: 0 1 22rem; }

.day {
  /* iOS's date capsule (`dateView`, 46x80): the number heavy over a light
     weekday, a dot under both when chosen. Grows a little to fill the rail on
     a wide screen, so the strip does not trail dead space; a phone keeps 46. */
  flex: 1 0 2.875rem;
  position: relative;
  min-width: 2.875rem;
  max-width: 3.6rem;
  height: 5rem;
  padding: 0 0 0.6rem;
  border-radius: 999px;
  display: grid;
  align-content: center;
  gap: 0.2rem;
  justify-items: center;
  font: inherit;
  color: var(--ink-3);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background 220ms var(--ease-out), color 220ms;
}
.day:hover { color: var(--ink); }
.day .day__n { font-size: 1.375rem; font-weight: 800; line-height: 1; letter-spacing: -0.01em; }
.day .day__w { font-size: 0.6875rem; font-weight: 400; line-height: 1.1; white-space: nowrap; }
.day.is-on { background: var(--purple-fill); color: white; }

/* "Any day" (ADR-089). The strip's own pill, wearing the strip's own selected
   fill — it answers the same question, so it must not look like a different kind
   of control. Wider, because two words do not fit a date's column, and it never
   flexes: the dates share what is left. */
.day--any { flex: 0 0 3.625rem; min-width: 3.625rem; max-width: 3.625rem; }
.day--any .day__n { display: grid; place-items: center; height: 1.375rem; }
/* The one element in the strip that is not a date. Without the rule it reads as
   an eighth day with a strange label. */
.daystrip__rule {
  flex: 0 0 1px; align-self: center;
  width: 1px; height: 2.75rem;
  margin: 0 0.375rem;
  background: var(--hairline);
}
.day.is-on::after {
  content: "";
  position: absolute;
  bottom: 0.7rem; left: 50%;
  transform: translateX(-50%);
  width: 7px; height: 7px;
  border-radius: 999px;
  background: var(--surface);
}
.day .flag { position: absolute; top: 0.25rem; right: 0.3rem; line-height: 0; }
.day .flag--certain { color: var(--danger); }
.day .flag--likely { color: var(--warn); }
.day .flag--possible { color: var(--warn-soft); }
.day.is-on .flag { color: white; }

/* ---------- holy-day banner ----------------------------------------------- */

.hd {
  flex: 1 1 16rem;
  min-width: 0;
  align-self: center;
  border-radius: var(--r-md);
  padding: 0.6rem 0.85rem;
  border: 1px solid var(--hd-accent);
  background: color-mix(in oklab, var(--hd-accent) 10%, transparent);
}
.hd[hidden] { display: none; }
.hd--certain { --hd-accent: var(--danger); }
.hd--likely { --hd-accent: var(--warn); }
.hd--possible { --hd-accent: var(--warn-soft); }
.hd__head { display: flex; align-items: center; gap: 0.45rem; }
.hd__head svg { color: var(--hd-accent); flex-shrink: 0; }
.hd__name { font-family: var(--serif); font-size: 0.98rem; font-weight: 500; margin: 0; }
.hd__what { font-size: 0.82rem; color: var(--ink-2); margin: 0.2rem 0 0; }
.hd__note { font-size: 0.74rem; color: var(--muted); margin: 0.2rem 0 0; }

/* ---------- route preamble ------------------------------------------------ */

.rtpre { display: grid; gap: 0.5rem; margin: 0.9rem 0 0; }
.rtpre[hidden] { display: none; }
.rtpre p { margin: 0; }
.rtpre__title { font-family: var(--serif); font-size: 1.05rem; color: var(--ink); line-height: 1.35; overflow-wrap: anywhere; }
.rtpre__lbl {
  display: block; font-family: var(--sans);
  font-size: 0.62rem; font-weight: 600; letter-spacing: 0.16em; text-transform: uppercase; color: var(--muted);
}
.rtpre__direct {
  display: inline-flex; align-items: center; gap: 0.5rem;
  font-size: 0.9rem; color: var(--ink);
}
.rtpre__direct svg { color: var(--purple); }
.rtpre__warn {
  display: inline-flex; align-items: center; gap: 0.5rem;
  font-size: 0.8rem; color: color-mix(in oklab, var(--warn) 62%, var(--ink));
  background: color-mix(in oklab, var(--warn) 12%, transparent);
  border-radius: var(--r-sm);
  padding: 0.35rem 0.65rem;
  justify-self: start;
}

/* ---------- result cards -------------------------------------------------- */

.results[hidden], .cards[hidden], .mapwrap[hidden], .preview[hidden],
.mapempty[hidden], .stepper[hidden], .state[hidden], .routepill[hidden],
.mapsearch[hidden] { display: none; }

.cards { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0.7rem; margin-top: 1.1rem; }

.card {
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--r-md);
  padding: 0.95rem 1.05rem 0.7rem;
  cursor: pointer;
  transition: border-color 220ms var(--ease-out), box-shadow 220ms var(--ease-out);
}
.card:hover, .card:focus-visible { border-color: var(--hairline-2); box-shadow: var(--shadow-sm); }

.card__top { display: flex; align-items: flex-start; gap: 1rem; }
.card__when { flex: 1 1 auto; min-width: 0; }

.card__time {
  font-family: var(--serif);
  font-size: clamp(1.3rem, 2.6vw, 1.6rem);
  font-weight: 600;
  line-height: 1.15;
  color: var(--ink);
  letter-spacing: -0.01em;
}
.card__time.is-doubt { color: var(--ink-2); }

.card__name {
  font-size: 0.95rem;
  color: var(--ink-2);
  margin: 0.25rem 0 0;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* The directions pill is filled in the service accent — it is the one action
   the card is really offering. */
.pill {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  height: 34px;
  padding: 0 0.8rem;
  border-radius: 999px;
  background: var(--svc);
  color: white;
  font-size: 0.82rem;
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
  transition: filter 200ms;
}
.pill:hover { filter: brightness(1.08); }

.warnchip {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.6rem;
  padding: 0.3rem 0.65rem;
  border-radius: 999px;
  font-size: 0.75rem;
  color: color-mix(in oklab, var(--warn) 58%, var(--ink));
  background: color-mix(in oklab, var(--warn) 14%, transparent);
  text-decoration: none;
}

.tags { display: flex; flex-wrap: wrap; gap: 0.3rem; margin-top: 0.6rem; }
.tag {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.18rem 0.5rem;
  border-radius: var(--r-sm);
  font-size: 0.66rem;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted);
  background: var(--paper-2);
}
.tag--lang { color: var(--purple); background: color-mix(in oklab, var(--purple) 10%, transparent); }

.note {
  display: flex;
  gap: 0.5rem;
  margin-top: 0.65rem;
  padding: 0.55rem 0.7rem;
  border-radius: var(--r-sm);
  background: var(--paper-2);
  font-size: 0.82rem;
  line-height: 1.55;
  color: var(--ink-2);
}
.note svg { flex-shrink: 0; margin-top: 0.2rem; color: var(--muted); }
/* A parish's note is the one thing on the card the parish wrote itself, and a
   truncated one can change what it means ("no confession on first Fridays…").
   So it is never clamped: it wraps to as many lines as it takes. */
.note__txt { min-width: 0; overflow-wrap: anywhere; text-wrap: pretty; }

.bar {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-top: 0.75rem;
  padding-top: 0.6rem;
  border-top: 1px solid var(--hairline);
}

.svc {
  flex-shrink: 0;
  padding: 0.16rem 0.5rem;
  border-radius: var(--r-sm);
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  color: var(--svc);
  background: color-mix(in oklab, var(--svc) 12%, transparent);
}

/* The label carries both forms; the width picks one. */
.svc__s { display: none; letter-spacing: 0; }

.bar__where {
  font-size: 0.8rem;
  color: var(--muted);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.bar__acts { margin-left: auto; display: flex; gap: 0.15rem; flex-shrink: 0; }

.iconbtn {
  width: 34px; height: 34px;
  border-radius: 999px;
  display: grid; place-items: center;
  color: var(--muted);
  cursor: pointer;
  transition: background 180ms, color 180ms;
}
.iconbtn:hover { background: var(--paper-2); color: var(--ink); }
.iconbtn.is-fav { color: var(--orange-mark); }   /* the favourited state IS the information (ADR-094) */

/* ---------- route cards --------------------------------------------------- */

.card--route .card__top { align-items: center; }
.card--route .card__right { display: grid; gap: 0.35rem; justify-items: end; }
.detour {
  display: inline-flex; align-items: center; gap: 0.3rem;
  font-size: 0.74rem; font-weight: 600;
  color: color-mix(in oklab, var(--warn) 58%, var(--ink));
  background: color-mix(in oklab, var(--warn) 13%, transparent);
  border-radius: 999px; padding: 0.15rem 0.5rem;
}

/* ---------- "now" marker -------------------------------------------------- */

.now { display: flex; align-items: center; gap: 0.6rem; margin: 0.5rem 0 0.1rem; }
.now__dot {
  width: 9px; height: 9px; border-radius: 999px; background: var(--purple);
  flex-shrink: 0;
  animation: now-pulse 2.4s ease-out infinite;
}
@keyframes now-pulse {
  0% { box-shadow: 0 0 0 0 color-mix(in oklab, var(--purple) 45%, transparent); }
  70%, 100% { box-shadow: 0 0 0 12px transparent; }
}
.now__t {
  font-family: var(--serif); font-size: 1.05rem; font-weight: 600; color: var(--purple);
}
.now__rule { flex: 1 1 auto; height: 1px; background: color-mix(in oklab, var(--purple) 30%, transparent); }

/* ---------- stepper ------------------------------------------------------- */

.stepper {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  margin-top: 1.3rem;
  padding-top: 1rem;
  border-top: 1px solid var(--hairline);
}
.stepper__t { font-family: var(--serif); font-size: 1rem; font-weight: 500; }
.stepper__c { font-size: 0.8rem; color: var(--muted); }
.stepper__btns { margin-left: auto; display: flex; gap: 0.4rem; }
.stepper__b {
  width: 38px; height: 38px;
  border-radius: 999px;
  display: grid; place-items: center;
  border: 1px solid var(--hairline-2);
  background: var(--surface);
  color: var(--ink-2);
  font-size: 1.05rem;
  line-height: 1;
  cursor: pointer;
}
.stepper__b:hover:not(:disabled) { border-color: var(--purple); color: var(--purple); }
.stepper__b:disabled { opacity: 0.35; cursor: default; }

/* ---------- states -------------------------------------------------------- */

.state { padding: 2.6rem 1rem 2rem; text-align: center; display: grid; justify-items: center; gap: 0.7rem; }
.state h2 { font-family: var(--serif); font-size: clamp(1.3rem, 3vw, 1.7rem); font-weight: 500; }
.state p { font-size: 0.92rem; color: var(--ink-2); max-width: 30rem; line-height: 1.6; }
.state .fine { font-size: 0.8rem; color: var(--muted); }
.state .btn { margin-top: 0.4rem; }
.state__spin {
  width: 28px; height: 28px; border-radius: 999px;
  border: 2.5px solid var(--hairline-2);
  border-top-color: var(--purple);
  animation: fx-spin 0.85s linear infinite;
}
@keyframes fx-spin { to { transform: rotate(360deg); } }
.state__warn { color: var(--danger-ink); }

/* Illustrations are drawn from the brand's own arch-and-light vocabulary
   rather than stock art — they are placeholders for the iOS artwork. */
.illus {
  width: 108px; height: 126px;
  border-radius: var(--r-arch);
  background:
    radial-gradient(70% 55% at 40% 26%, color-mix(in oklab, var(--purple) 34%, transparent) 0%, transparent 62%),
    radial-gradient(60% 50% at 76% 70%, color-mix(in oklab, var(--blue) 22%, transparent) 0%, transparent 58%),
    radial-gradient(60% 50% at 24% 82%, color-mix(in oklab, var(--orange) 20%, transparent) 0%, transparent 58%),
    var(--paper-2);
  border: 1px solid var(--hairline);
  position: relative;
  margin-bottom: 0.3rem;
}
.illus::after {
  content: "";
  position: absolute;
  left: 50%; top: 26%;
  transform: translateX(-50%);
  width: 26px; height: 34px;
  background:
    linear-gradient(currentColor, currentColor) 50% 0 / 3px 34px no-repeat,
    linear-gradient(currentColor, currentColor) 0 32% / 26px 3px no-repeat;
  color: color-mix(in oklab, var(--purple) 55%, var(--paper));
}
.illus--denied::after, .illus--notfound::after { color: color-mix(in oklab, var(--ink-3) 70%, var(--paper)); }

/* ---------- map ----------------------------------------------------------- */

.mapwrap { position: relative; margin-top: 1.1rem; }
.map {
  position: relative;
  height: 62vh;
  min-height: 22rem;
  border-radius: var(--r-md);
  border: 1px solid var(--hairline);
  overflow: hidden;
}
.mapwrap.is-full { position: fixed; inset: 0; z-index: 250; background: var(--paper); padding: 0.6rem; margin: 0; }
.mapwrap.is-full .map { height: 100%; }
body.fx-noscroll { overflow: hidden; }

.mapctl { position: absolute; top: 0.8rem; right: 0.8rem; z-index: 500; display: grid; gap: 0.4rem; }
.mapbtn {
  width: 40px; height: 40px;
  border-radius: 999px;
  display: grid; place-items: center;
  background: var(--surface);
  border: 1px solid var(--hairline);
  box-shadow: var(--shadow-sm);
  color: var(--ink-2);
  cursor: pointer;
}
.mapbtn:hover { color: var(--purple); border-color: var(--purple); }

/* Top-CENTRE: the left corner is Leaflet's zoom control and the right is
   `.mapctl`. The centre is free over a route, because "Search this area",
   which owns it on a nearby search, is never offered over one (ADR-088 rule 6). */
.routepill {
  position: absolute; top: 0.8rem; left: 50%; transform: translateX(-50%); z-index: 500; margin: 0;
  white-space: nowrap;
  display: inline-flex; align-items: center; gap: 0.45rem;
  background: var(--surface); border: 1px solid var(--hairline);
  border-radius: 999px; padding: 0.4rem 0.85rem;
  font-size: 0.8rem; color: var(--ink-2); box-shadow: var(--shadow-sm);
}
.routepill svg { color: var(--purple); }

/* "Search this area" (ADR-088). A SOLID purple fill — the primary-button pair —
   not the map chrome's surface: pressing it asks the directory a question, and on
   a white pill it blended into the map (iOS reference, spec/screens/find-confession.md).
   Pill radius and size are unchanged. */
.mapsearch {
  position: absolute; left: 50%; top: 0.8rem; transform: translateX(-50%);
  z-index: 500;
  display: inline-flex; align-items: center; gap: 0.4rem;
  background: var(--purple-fill); border: 1px solid var(--purple-fill);
  border-radius: 999px; padding: 0.45rem 0.95rem;
  font: inherit; font-size: 0.82rem; font-weight: 600;
  color: white; box-shadow: var(--shadow-md);
  cursor: pointer; white-space: nowrap; max-width: calc(100% - 6rem);
}
.mapsearch:hover:not([disabled]) { box-shadow: var(--shadow-lg); }
.mapsearch[disabled] { opacity: 0.6; cursor: default; }

.mapempty {
  position: absolute; left: 50%; bottom: 1.2rem; transform: translateX(-50%);
  z-index: 500; margin: 0;
  background: var(--surface); border: 1px solid var(--hairline);
  border-radius: 999px; padding: 0.5rem 1.1rem;
  font-size: 0.85rem; color: var(--ink-2); box-shadow: var(--shadow-sm);
  white-space: nowrap; max-width: calc(100% - 2rem);
}

/* Map surface. Leaflet is not loaded in this build, so the tile layer is drawn
   from tokens and pins are projected from the same coordinates the list uses. */
.stub { position: absolute; inset: 0; overflow: hidden; }
.stub__field {
  position: absolute; inset: 0;
  background:
    radial-gradient(110% 85% at 22% 12%, color-mix(in oklab, var(--purple) 7%, transparent) 0%, transparent 62%),
    radial-gradient(95% 80% at 80% 88%, color-mix(in oklab, var(--blue) 6%, transparent) 0%, transparent 58%),
    var(--paper-2);
}
.stub__grid {
  position: absolute; inset: -8%;
  background-image:
    linear-gradient(var(--hairline) 1px, transparent 1px),
    linear-gradient(90deg, var(--hairline) 1px, transparent 1px);
  background-size: 2.1rem 2.1rem;
  opacity: 0.7;
}
.stub__block { position: absolute; background: var(--paper-3); opacity: 0.75; }
.stub__road { position: absolute; background: var(--surface); box-shadow: 0 0 0 1px var(--hairline); }
.stub__route {
  position: absolute; height: 4px; border-radius: 999px;
  background: color-mix(in oklab, var(--purple) 55%, transparent);
  transform-origin: 0 50%;
}
.stub__you {
  position: absolute; width: 15px; height: 15px; border-radius: 999px;
  background: var(--blue); border: 3px solid var(--surface);
  transform: translate(-50%, -50%);
  animation: you-pulse 2.6s ease-out infinite;
}
@keyframes you-pulse {
  0% { box-shadow: 0 0 0 0 color-mix(in oklab, var(--blue) 35%, transparent); }
  70%, 100% { box-shadow: 0 0 0 16px transparent; }
}
.stub__note {
  position: absolute; left: 0.75rem; bottom: 0.75rem; margin: 0;
  font-size: 0.66rem; letter-spacing: 0.07em; text-transform: uppercase; color: var(--muted);
  background: color-mix(in oklab, var(--paper) 88%, transparent);
  border-radius: var(--r-sm); padding: 0.25rem 0.55rem;
}

.pin {
  position: absolute;
  transform: translate(-50%, -100%);
  display: flex; flex-direction: column; align-items: center;
  cursor: pointer;
}
.pin__body {
  display: grid; gap: 0.02rem; justify-items: flex-start;
  line-height: 1.2;
  background: var(--svc); color: white;
  border: 1px solid rgba(255,255,255,0.85);
  border-radius: var(--r-sm);
  padding: 0.22rem 0.45rem;
  box-shadow: var(--shadow-sm);
  white-space: nowrap;
}
.pin__when { font-size: 0.74rem; font-weight: 600; }
.pin__far { font-size: 0.66rem; opacity: 0.9; }
.pin__name { font-size: 0.72rem; font-weight: 700; white-space: normal; max-width: 10rem; }
.pin.is-sel { z-index: 3; }
.pin.is-sel .pin__body { background: var(--surface); color: var(--ink); border-color: var(--svc); }
.pin.is-sel .pin__when { color: var(--svc); }
.pin.is-sel .pin__far { color: var(--muted); }
.pin__stem { width: 2px; height: 6px; background: var(--svc); }
.pin__tip { width: 7px; height: 7px; border-radius: 999px; background: var(--svc); border: 1.5px solid var(--surface); }

/* Cluster chip: what coincident parishes collapse into, since this map has no
   zoom to pull them apart with. Tapping it lists the group. */
.pinc {
  position: absolute;
  transform: translate(-50%, -100%);
  display: flex; flex-direction: column; align-items: center;
  cursor: pointer;
}
.pinc__body {
  display: flex; align-items: center; gap: 0.35rem;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--hairline-2); border-radius: 999px;
  padding: 0.22rem 0.55rem 0.22rem 0.25rem;
  box-shadow: var(--shadow-sm);
  font-size: 0.74rem; font-weight: 600; white-space: nowrap;
}
.pinc__n {
  display: grid; place-items: center;
  min-width: 19px; height: 19px; padding: 0 4px;
  border-radius: 999px; background: var(--purple-fill); color: white;
  font-size: 0.66rem;
}
.pinc__stem { width: 2px; height: 6px; background: var(--hairline-2); }
.pinc__tip { width: 7px; height: 7px; border-radius: 999px; background: var(--purple); border: 1.5px solid var(--surface); }
.pinc.is-open { z-index: 4; }
.pinc.is-open .pinc__body { border-color: var(--purple); box-shadow: var(--shadow-md); }

.clist { display: grid; gap: 1px; margin-top: 0.55rem; }
.clist button {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: 0.5rem 0.6rem; border-radius: var(--r-sm);
  font: inherit; text-align: left; color: var(--ink); cursor: pointer;
}
.clist button:hover { background: var(--paper-2); }
.clist b { font-weight: 500; font-size: 0.9rem; }

.preview {
  position: absolute; left: 1rem; right: 1rem; bottom: 1rem; z-index: 500;
  background: var(--surface); border: 1px solid var(--hairline);
  border-radius: var(--r-md); padding: 0.85rem 1rem; box-shadow: var(--shadow-md);
}
.preview__head { display: flex; justify-content: space-between; align-items: flex-start; gap: 0.8rem; }
.preview__name { font-family: var(--serif); font-size: 1.02rem; font-weight: 500; margin: 0; }
.preview__meta { font-size: 0.78rem; color: var(--muted); margin: 0.15rem 0 0; }
.preview__x { font-size: 1.15rem; line-height: 1; color: var(--muted); padding: 0.1rem 0.35rem; cursor: pointer; }
.preview__times { display: flex; flex-wrap: wrap; gap: 0.3rem; margin-top: 0.6rem; }
.preview__acts { display: flex; gap: 0.45rem; margin-top: 0.75rem; }

.tcap {
  font-size: 0.76rem;
  border-radius: var(--r-sm);
  padding: 0.16rem 0.45rem;
  color: var(--svc);
  background: color-mix(in oklab, var(--svc) 11%, transparent);
}
.tcap--more { color: var(--muted); background: var(--paper-2); }

/* ---------- parish detail sheet ------------------------------------------- */

.sheet { position: fixed; inset: 0; z-index: 300; display: flex; align-items: flex-end; justify-content: center; }
.sheet[hidden] { display: none; }
.sheet__scrim {
  position: absolute; inset: 0;
  background: color-mix(in oklab, var(--purple-night) 46%, transparent);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}
.sheet__card {
  position: relative;
  width: min(100%, 42rem);
  max-height: 92vh;
  display: flex;
  flex-direction: column;
  background: var(--paper);
  border: 1px solid var(--hairline);
  border-bottom: none;
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  box-shadow: var(--shadow-lg);
  animation: sheet-in 340ms var(--ease-out);
}
@keyframes sheet-in { from { transform: translateY(24px); opacity: 0; } }
.sheet__handle {
  flex-shrink: 0;
  height: 26px;
  display: grid; place-items: center;
  cursor: pointer;
}
.sheet__handle::before {
  content: "";
  width: 42px; height: 4px; border-radius: 999px;
  background: var(--hairline-2);
}
.sheet__body {
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 0.4rem clamp(1.1rem, 3vw, 1.8rem) calc(2rem + env(safe-area-inset-bottom));
}

.d-head { display: flex; align-items: flex-start; gap: 0.85rem; }
.d-badge {
  flex-shrink: 0;
  width: 46px; height: 46px;
  border-radius: 14px;
  display: grid; place-items: center;
  color: var(--svc);
  background: color-mix(in oklab, var(--svc) 12%, transparent);
}
.d-name { font-family: var(--serif); font-size: 1.5rem; font-weight: 500; margin: 0; }
.d-kind { font-size: 0.82rem; color: var(--svc); margin: 0.15rem 0 0; }
.d-star { margin-left: auto; }

.d-seg { display: inline-flex; flex-wrap: wrap; row-gap: 3px; padding: 4px; gap: 3px; background: var(--paper-3); border-radius: 999px; margin-top: 1.1rem; }
.d-seg button {
  padding: 0.45rem 0.95rem; border-radius: 999px;
  font: inherit; font-size: 0.84rem; font-weight: 500; color: var(--ink-3); cursor: pointer;
}
.d-seg button.is-on { background: var(--surface); color: var(--ink); box-shadow: var(--shadow-sm); }
.d-seg button:disabled { opacity: 0.35; cursor: default; }

.d-h {
  font-size: 0.68rem; font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--muted); margin: 1.5rem 0 0.5rem;
}
.d-panel { background: var(--surface-2); border-radius: var(--r-md); padding: 0.2rem 1rem; }
.d-row { display: flex; gap: 1rem; padding: 0.7rem 0; border-top: 1px solid var(--hairline); }
.d-row:first-child { border-top: 0; }
.d-day { flex: 0 0 6.5rem; font-size: 0.82rem; color: var(--muted); }
.d-when { display: flex; flex-wrap: wrap; gap: 0.3rem 0.7rem; font-size: 0.88rem; }
.d-when span small { color: var(--muted); }
.d-none { font-size: 0.86rem; color: var(--muted); padding: 0.85rem 0; margin: 0; }

.d-addr { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 0.9rem 0; }
.d-street { font-size: 0.94rem; margin: 0; }
.d-loc { font-size: 0.82rem; color: var(--muted); margin: 0.12rem 0 0; }

.d-map { height: 12rem; border-radius: var(--r-md); border: 1px solid var(--hairline); overflow: hidden; position: relative; cursor: zoom-in; }

.d-travel { display: flex; align-items: center; gap: 1.6rem; padding: 0.9rem 0; flex-wrap: wrap; }
.d-fig { font-family: var(--serif); font-size: 1.3rem; font-weight: 500; margin: 0; }
.d-cap { font-size: 0.72rem; color: var(--muted); margin: 0.1rem 0 0; }
.d-travel .btn { margin-left: auto; }

.d-contact {
  display: flex; align-items: center; gap: 0.8rem;
  padding: 0.72rem 0; border-top: 1px solid var(--hairline);
  font-size: 0.9rem;
}
.d-contact:first-child { border-top: 0; }
.d-contact > span:first-child { flex: 0 0 5.2rem; color: var(--muted); font-size: 0.78rem; }
.d-contact a { color: var(--purple); text-decoration: none; }
.d-contact a:hover { text-decoration: underline; }

/* ---------- search page --------------------------------------------------- */

.searchpage {
  position: fixed; inset: 0; z-index: 320;
  background: var(--paper);
  display: flex; flex-direction: column;
  animation: sp-in 300ms var(--ease-out);
}
.searchpage[hidden] { display: none; }
@keyframes sp-in { from { transform: translateY(18px); opacity: 0; } }

.sp__bar {
  flex-shrink: 0;
  display: flex; align-items: center; gap: 0.8rem;
  padding: calc(0.8rem + env(safe-area-inset-top)) clamp(1rem, 3vw, 1.6rem) 0.8rem;
  border-bottom: 1px solid var(--hairline);
}
.sp__back {
  width: 40px; height: 40px; border-radius: 999px;
  display: grid; place-items: center;
  border: 1px solid var(--hairline); background: var(--surface); color: var(--ink-2);
  cursor: pointer; flex-shrink: 0;
}
.sp__back:hover { border-color: var(--purple); color: var(--purple); }

.sp__modes { display: inline-flex; padding: 4px; gap: 3px; background: var(--paper-3); border-radius: 999px; }
.sp__modes button {
  padding: 0.5rem 1.1rem; border-radius: 999px;
  font: inherit; font-size: 0.85rem; font-weight: 500; color: var(--ink-3); cursor: pointer;
}
.sp__modes button.is-on { background: var(--surface); color: var(--ink); box-shadow: var(--shadow-sm); }

.sp__body {
  flex: 1 1 auto; overflow-y: auto;
  padding: 1.1rem clamp(1rem, 3vw, 1.6rem) calc(2rem + env(safe-area-inset-bottom));
}
.sp__inputs { max-width: 42rem; margin-inline: auto; }
.sp__panel { max-width: 42rem; margin: 1.1rem auto 0; }

.sfield {
  display: flex; align-items: center; gap: 0.7rem;
  background: var(--surface); border: 1.5px solid var(--hairline-2);
  border-radius: var(--r-md); padding: 0.6rem 0.7rem 0.6rem 1rem;
}
.sfield:focus-within { border-color: var(--purple); box-shadow: 0 0 0 4px color-mix(in oklab, var(--purple) 12%, transparent); }
.sfield__lbl {
  flex-shrink: 0;
  font-size: 0.6rem; font-weight: 600; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--muted);
}
.sfield input {
  flex: 1 1 auto; min-width: 0; border: 0; background: none; outline: none;
  font-size: 1rem; color: var(--ink); padding-block: 0.55rem;
}
.sfield__x { width: 34px; height: 34px; border-radius: 999px; display: grid; place-items: center; color: var(--muted); cursor: pointer; }
.sfield__x:hover { background: var(--paper-2); }

/* FROM / TO card */
.rtcard { background: var(--surface); border: 1px solid var(--hairline); border-radius: var(--r-md); padding: 0.3rem 0.9rem; position: relative; }
.rtleg { display: flex; align-items: center; gap: 0.8rem; padding: 0.8rem 0; border-top: 1px solid var(--hairline); }
.rtleg:first-child { border-top: 0; }
.rtleg__dot { width: 10px; height: 10px; border-radius: 999px; flex-shrink: 0; }
.rtleg__dot--a { background: var(--blue); }
.rtleg__dot--b { background: var(--purple); }
.rtleg__txt { flex: 1 1 auto; min-width: 0; display: grid; gap: 0.05rem; }
.rtleg__lbl { font-size: 0.6rem; font-weight: 600; letter-spacing: 0.16em; text-transform: uppercase; color: var(--muted); }
.rtleg input {
  border: 0; background: none; outline: none; font-size: 0.98rem; color: var(--ink); width: 100%;
}
.rtleg input::placeholder { color: var(--muted); }
.rtswap {
  position: absolute; right: 0.8rem; top: 50%; transform: translateY(-50%);
  width: 38px; height: 38px; border-radius: 999px;
  display: grid; place-items: center;
  border: 1px solid var(--hairline); background: var(--paper); color: var(--ink-2); cursor: pointer;
}
.rtswap:hover { border-color: var(--purple); color: var(--purple); }
.rtnote { font-size: 0.84rem; color: var(--ink-2); margin-top: 0.8rem; line-height: 1.55; }
/* Room on the right for the swap control, which sits across both legs. */
.sbarinline .rtcard { padding-right: 3.6rem; }
.rtleg__geo {
  width: 44px; height: 44px; flex-shrink: 0; margin-block: -0.5rem;
  display: grid; place-items: center; border-radius: 999px;
  color: var(--ink-3); cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.rtleg__geo:hover { color: var(--purple); background: var(--paper-2); }
.rtswap { width: 44px; height: 44px; }
.rtswap:disabled { opacity: 0.45; cursor: default; }
.sdrop--inline { z-index: 60; }

/* The route's ends on the map: a labelled capsule over a brand dot, anchored
   on the dot. Not tappable — the pins are the parishes. */
.rtend { position: relative; transform: translate(-50%, calc(-100% + 7px)); display: grid; justify-items: center; gap: 4px; pointer-events: none; }
.rtend__lbl {
  max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 0.72rem; font-weight: 600; color: var(--ink);
  background: var(--surface); border: 1px solid var(--hairline);
  border-radius: 999px; padding: 0.2rem 0.55rem; box-shadow: var(--shadow-sm);
}
.rtend__dot { width: 14px; height: 14px; border-radius: 999px; background: var(--purple); box-shadow: 0 0 0 3px var(--surface); }
.rtend--a .rtend__dot { background: var(--blue); }
.rtend__lbl:empty { display: none; }

.sugcard { background: var(--surface); border: 1px solid var(--hairline); border-radius: var(--r-md); padding: 0.35rem; }
.sugh {
  font-size: 0.64rem; font-weight: 600; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--muted); padding: 0.7rem 0.75rem 0.4rem;
}
.sug {
  display: flex; align-items: center; gap: 0.75rem;
  width: 100%; padding: 0.65rem 0.75rem; border-radius: var(--r-sm);
  font: inherit; text-align: left; color: var(--ink); cursor: pointer;
}
.sug:hover { background: var(--paper-2); }
.sug__ic { flex-shrink: 0; color: var(--purple); display: grid; place-items: center; }
.sug__t { display: grid; gap: 0.05rem; min-width: 0; }
.sug__t b { font-weight: 500; font-size: 0.94rem; }
.sug__t span { font-size: 0.78rem; color: var(--muted); }
.sug--loc .sug__ic { color: var(--blue); }

.sp__pickmap { height: 22rem; border-radius: var(--r-md); border: 1px solid var(--hairline); overflow: hidden; position: relative; }
.sp__center {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -100%);
  color: var(--purple); z-index: 4; pointer-events: none;
}
.sp__area {
  position: absolute; left: 50%; bottom: 1rem; transform: translateX(-50%); z-index: 5;
}

/* ---------- first run ----------------------------------------------------- */

/* Part of the page, not a layer over it: no scrim, no shadow, no fixed
   position — it is the first thing inside the paper card and it scrolls with
   it. Everything else about it is unchanged. */
.firstrun { display: block; padding: 0.4rem 0 0; }
.firstrun[hidden] { display: none; }
.firstrun__card {
  position: relative;
  width: min(100%, 30rem);
  margin: 0 auto;
  background: var(--paper-2);
  border: 1px solid var(--hairline);
  border-radius: var(--r-lg);
  padding: clamp(1.4rem, 3.4vw, 2rem);
  text-align: center;
  display: grid;
  justify-items: center;
  gap: 0.7rem;
}
.firstrun__x {
  position: absolute; top: 0.7rem; right: 0.8rem;
  width: 34px; height: 34px; border-radius: 999px;
  color: var(--muted); font-size: 1.2rem; line-height: 1; cursor: pointer;
}
.firstrun__x:hover { background: var(--paper-2); color: var(--ink); }
.firstrun__t { font-family: var(--serif); font-size: 1.4rem; font-weight: 500; line-height: 1.2; }
.firstrun__p { font-size: 0.85rem; color: var(--muted); }
.firstrun__acts { display: flex; flex-wrap: wrap; gap: 0.6rem; margin-top: 0.6rem; width: 100%; }
.firstrun__acts .btn { flex: 1 1 10rem; justify-content: center; }

/* ---------- credit, tail, toast ------------------------------------------- */

.credit { font-size: 0.82rem; color: var(--muted); text-align: center; margin-bottom: 2.6rem; }
.credit a { color: var(--purple); }

.tail {
  border-top: 1px solid var(--hairline);
  padding: 2.4rem 0 3.5rem;
  display: grid;
  justify-items: center;
  gap: 1rem;
  text-align: center;
}
.tail__verse {
  font-family: var(--serif); font-style: italic;
  font-size: clamp(1.1rem, 2.4vw, 1.4rem);
  line-height: 1.45; color: var(--ink-2); max-width: 34rem;
}
.tail__verse cite {
  display: block; font-family: var(--sans); font-style: normal;
  font-size: 0.66rem; font-weight: 600; letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--purple); margin-top: 0.9rem;
}
.tail__ask { font-size: 0.86rem; color: var(--muted); }
.tail__ask a { color: var(--purple); }

/* The state preview this screen used to carry lived in `find.html` and shipped
   to production for every reader, on the one screen whose first impression is
   a permission prompt — a dashed "Preview a state" pill under the results, and
   no JS ever bound it, so it was inert in review too. A design affordance that
   reaches production is not a design affordance; rebuild it under `dev/`, which
   `firebase.json` does not deploy, never inline on the page it previews. */

.fxtoast {
  position: fixed;
  bottom: calc(1.4rem + env(safe-area-inset-bottom));
  left: 50%;
  transform: translate(-50%, 160%);
  opacity: 0;
  visibility: hidden;
  z-index: 400;
  background: var(--ink);
  color: var(--paper);
  font-size: 0.86rem; font-weight: 500;
  padding: 0.7rem 1.3rem;
  border-radius: 999px;
  box-shadow: var(--shadow-md);
  transition: transform 380ms var(--ease-out), opacity 240ms, visibility 0s linear 380ms;
  max-width: min(90vw, 26rem);
  text-align: center;
}
.fxtoast.is-shown { transform: translate(-50%, 0); opacity: 1; visibility: visible; transition-delay: 0s; }

/* ---------- phone --------------------------------------------------------- */

@media (max-width: 760px) {
  .band { padding-bottom: 5rem; }
  .band__h1 { font-size: clamp(2.1rem, 9.5vw, 2.9rem); }
  .band__sub { margin-bottom: 1.5rem; font-size: 0.95rem; }

  .sbar { padding: 0.6rem 0.65rem 0.6rem 0.9rem; gap: 0.7rem; }
  .sbar__ic { width: 38px; height: 38px; }
  /* The canvas sent a phone to a full-screen search page and hid the dropdown
     here. **This client has no search page** (ADR-129), so hiding it took the
     only place a geocoder answer could land — the reader typed, got an
     invisible list, and nothing happened. The list stays, shorter. */
  .sdrop { max-height: 18rem; }
  .sbarwrap { width: 100%; }

  /* One row that scrolls sideways, as iOS's filter bar does — wrapped, five
     chips stacked into a cloud two and three rows deep above the results. It
     runs to the screen's edges so a chip cut by the edge reads as "more". */
  .chiprow {
    margin-inline: calc(-1 * var(--gutter));
    padding-inline: var(--gutter);
    scroll-padding-inline: var(--gutter);
  }
  .day { flex: 0 0 2.875rem; }

  .paper { margin-top: -3.5rem; padding: 0.9rem 0.8rem 1.3rem; }

  /* A banner beside a scrolling day strip leaves neither enough room. */
  .dayrow { flex-direction: column; gap: 0.7rem; }
  .dayrow.has-hd .daystrip { flex: 1 1 auto; }
  .daystrip { margin-inline: -0.8rem; padding-inline: 0.8rem; }

  .card__time { font-size: 1.3rem; }
  /* The drive time is the card's one action and it holds the top-right corner at
     every width: wrapping it under the parish name buried it mid-card. */
  .card__top { flex-wrap: nowrap; gap: 0.7rem; }
  .pill { height: 38px; }

  /* One row, always. The service label goes to its initial and the action
     buttons close up rather than the row breaking in two. */
  .bar { flex-wrap: nowrap; }
  .bar__acts { margin-left: auto; gap: 0; }
  .iconbtn { width: 40px; height: 40px; }
  .svc__l { display: none; }
  .svc__s { display: inline; }

  .map { height: 56vh; min-height: 18rem; }
  .preview { left: 0.6rem; right: 0.6rem; bottom: 0.6rem; }

  .d-row { flex-direction: column; gap: 0.25rem; }
  .d-day { flex: none; font-weight: 500; color: var(--ink-2); }
  .d-travel .btn { margin-left: 0; width: 100%; justify-content: center; }
  .sheet__card { max-height: 94vh; }

  .stepper { flex-wrap: wrap; }
  .stepper__btns { margin-left: auto; }
  .stepper__b { width: 44px; height: 44px; }

  .sp__modes { flex: 0 1 auto; flex-wrap: wrap; row-gap: 3px; }
  .sp__modes button { flex: 0 0 auto; padding-inline: 0.85rem; }
}

@media (max-width: 420px) {
  .firstrun__acts .btn { flex: 1 1 100%; }
}
