/* ============================================================================
   overlay.css — the shared full-screen shell (pairs with js/overlay.js) plus
   the per-overlay content styling. One shell, seven instances.

   Added alongside the prescribed file split: overlay chrome is not "section
   layout", so it does not belong in home.css.
   ========================================================================== */

/* ── Shell ────────────────────────────────────────────────────────────────── */
.ov {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  flex-direction: column;
  background: var(--bg);
}
.ov[hidden] { display: none; }

/* Backdrop — INERT BY DESIGN, and deliberately kept.
   The panel below is full-bleed white with no scrim, so this element is
   completely covered and can never receive a click. ESC and the × are the
   live close paths. It is not dead code: the shell's one close handler
   already treats it as a close target, so insetting .ov__panel over a scrim
   makes backdrop-click work with zero JS change. Do not delete it to "clean
   up" — deleting it is what makes that future change a rewrite. */
.ov__backdrop {
  position: absolute;
  inset: 0;
  background: var(--scrim);
}

/* ── dialog mode ────────────────────────────────────────────────────────────
   Opted into with overlay.register(id, {dialog:true}). The default sheet stays
   exactly as it was for the menu and the Fetch+ panel.

   ⚠ THE SCRIM IS THE POINT, NOT DECORATION. This is a conversion surface: the
   argument for Fetch+ is the forecast sitting behind the locked day, and the
   map behind the locked tick. An opaque panel hides the thing being sold. The
   map's paywall has always done this (css/map.css .paywall, a 0.45 scrim over
   a centred card); these numbers are ITS numbers, so the two read as one
   product rather than as two designers.

   ⚠ AND THE PANEL IS SIZED BY ITS CONTENT. The dead space came from
   width/height:100% on a panel holding two paragraphs and two buttons — a
   percentage box underfilled, which is the defect the Daily Report sheet had
   at 0.88. height:auto + max-width is what makes it roughly square at this
   copy length and smaller when the copy is shorter, rather than padded to fit
   a fraction of the screen. */
.ov--dialog { background: transparent; display: grid; place-items: center; }
.ov--dialog .ov__backdrop { background: rgba(10, 22, 40, 0.45); }
.ov--dialog .ov__panel {
  width: min(27rem, calc(100vw - 2 * var(--sp-4, 16px)));
  height: auto;
  max-height: calc(100vh - 2 * var(--sp-6, 32px));
  margin: auto;
  border-radius: var(--r-lg, 14px);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.28);
  overflow: hidden;
}
/* The bar is chrome for a sheet; in a dialog it is just the ×, so it must not
   reserve a sheet's height and reintroduce the dead space. */
.ov--dialog .ov__bar { min-height: 0; padding: var(--sp-3, 12px) var(--sp-4, 16px) 0; }
.ov--dialog .ov__body { padding: var(--sp-4, 16px) var(--sp-5, 20px) var(--sp-5, 20px); overflow: auto; }

.ov__panel {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  background: var(--bg);
  animation: ov-in var(--dur) var(--ease);
}
@keyframes ov-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

.ov__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  flex: 0 0 auto;
  min-height: var(--nav-h);
  padding: var(--sp-4) var(--sp-6);
  border-bottom: 1px solid var(--line);
}
.ov__title {
  font-size: var(--fs-h3);
  font-weight: var(--fw-display);
  letter-spacing: var(--tracking-tight);
}

/* Black ×, per spec. */
.ov__x {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  color: var(--ov-x-ink);
  border-radius: var(--r-pill);
  transition: background var(--dur-fast) var(--ease);
}
.ov__x:hover { background: var(--surface-sunken); }
.ov__x svg { width: 22px; height: 22px; }

.ov__body {
  flex: 1 1 auto;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding: var(--sp-8) var(--sp-6) var(--sp-16);
}
.ov__inner {
  width: 100%;
  max-width: 880px;
  margin-inline: auto;
}
.ov__inner--wide { max-width: var(--maxw); }

.ov__lede {
  max-width: var(--maxw-text);
  color: var(--text-secondary);
  font-size: var(--fs-body-lg);
}

@media (max-width: 560px) {
  .ov__bar  { padding: var(--sp-3) var(--sp-4); }
  .ov__body { padding: var(--sp-6) var(--sp-4) var(--sp-12); }
}

/* ── Search ───────────────────────────────────────────────────────────────── */
.search-field {
  position: relative;
  max-width: 640px;
}
.search-field__icon {
  position: absolute;
  left: var(--sp-4);
  top: 50%;
  transform: translateY(-50%);
  width: 20px;
  height: 20px;
  color: var(--text-muted);
  pointer-events: none;
}
.search-field .field { padding-left: 46px; font-size: var(--fs-body-lg); }

.results { margin-top: var(--sp-8); }
.results__group + .results__group { margin-top: var(--sp-8); }
.results__label {
  padding-bottom: var(--sp-2);
  border-bottom: 1px solid var(--line);
  font-size: var(--fs-xs);
  font-weight: var(--fw-label);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.result {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  width: 100%;
  padding: var(--sp-3) var(--sp-3);
  text-align: left;
  border-radius: var(--r-md);
  transition: background var(--dur-fast) var(--ease);
}
.result:hover { background: var(--surface); }
.result__ic {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 36px;
  height: 36px;
  background: var(--accent-tint);
  color: var(--accent);
  border-radius: var(--r-sm);
}
.result__ic svg { width: 19px; height: 19px; }
.result__text { min-width: 0; }
/* Both are spans inside a flex item, so they stay inline and run together
   ("Banzai PipelinePūpūkea · Honolulu County") without this. */
.result__name,
.result__sub { display: block; }
.result__name {
  font-weight: var(--fw-medium);
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.result__sub {
  font-size: var(--fs-sm);
  color: var(--text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.results__status {
  padding: var(--sp-6) 0;
  color: var(--text-muted);
}

/* Rows live in a real <ul>/<li>: role="listitem" on the <a> itself would
   override the link role and stop screen readers announcing it as a link. */
.results__rows { display: grid; gap: 2px; min-width: 0; }

/* min-width:0 down the whole chain, or the ellipsis never fires.
   Grid and flex items default to min-width:auto, which is min-CONTENT — so a
   nowrap 67-character spot name pushes the <li> to its full text width and the
   row overflows instead of truncating. Measured on Morocco at 390px before
   this: list clientWidth 358, scrollWidth 722, rows extending to x=738, and
   textOverflow:ellipsis never engaging because nothing was ever constrained.
   It hid from the viewport-overflow sweep because .fc__list sets
   overflow-y:auto, which computes overflow-x to auto — so the row looked
   deliberately scrollable rather than broken. */
.results__rows > li,
.result { min-width: 0; }

/* ── Listbox (js/listbox.js) ──────────────────────────────────────────────── */
.lb { position: relative; }

.lb__trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  width: 100%;
  min-height: 46px;
  padding: 12px var(--sp-4);
  background: var(--bg);
  color: var(--text);
  font: inherit;
  font-size: var(--fs-body);
  text-align: left;
  border: 1.5px solid var(--line-strong);
  border-radius: var(--r-md);
  transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
.lb__trigger:hover:not(:disabled) { border-color: var(--text-muted); }
.lb__trigger[aria-expanded="true"],
.lb__trigger:focus-visible {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-ring);
  outline: none;
}
.lb__trigger:disabled { background: var(--surface-sunken); color: var(--text-muted); cursor: not-allowed; }
.lb__value { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lb__value--empty { color: var(--text-muted); }
.lb__chev { flex: 0 0 auto; width: 18px; height: 18px; color: var(--text-secondary); }
.lb__trigger[aria-expanded="true"] .lb__chev { transform: rotate(180deg); }

.lb__panel {
  position: absolute;
  z-index: 5;
  top: calc(100% + 6px);
  left: 0;
  right: 0;
  max-height: min(46vh, 380px);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--sp-2);
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-lg);
}
.lb__panel[hidden] { display: none; }

.lb__group + .lb__group { margin-top: var(--sp-2); }
.lb__grouplabel {
  padding: var(--sp-2) var(--sp-3) var(--sp-1);
  font-size: var(--fs-xs);
  font-weight: var(--fw-label);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.lb__option {
  padding: 9px var(--sp-3);
  border-radius: var(--r-sm);
  font-size: var(--fs-sm);
  color: var(--text);
  cursor: pointer;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.lb__option.is-active { background: var(--surface); }
.lb__option[aria-selected="true"] {
  background: var(--accent-tint);
  color: var(--accent-text);
  font-weight: var(--fw-label);
}

/* ── Forecast ─────────────────────────────────────────────────────────────── */
.fc__modes { margin-bottom: var(--sp-8); }
.fc__selects {
  display: grid;
  gap: var(--sp-5);
  max-width: 560px;
}
.fc__hint {
  margin-top: var(--sp-4);
  font-size: var(--fs-sm);
  color: var(--text-muted);
}

/* ── County chips (admin_area) ────────────────────────────────────────────
   The county level on the touch surface. The desktop tab menu drills into it;
   this narrows one list in place, because the overlay is one level deep and a
   second level competes with dismissing it.

   WRAPS rather than scrolls sideways: a horizontal scroller hides its own tail,
   and a reader who cannot see that more exist does not swipe for them.

   ⚠ THIS COMMENT FIRST CLAIMED "the busiest region here is 20 counties" AND
   THAT NUMBER WAS NEVER MEASURED — it was written from the 5 the development
   region happens to have. Counted over the full catalogue (7,541 rows, 87
   regions, 2026-08-27) the real spread is much wider:

       Caribbean            46      Ireland / UK         30
       Morocco              39      Spain Mediterranean  29
       Italy                37

   So the widest row is 47 chips including "All", not 21, and .fc__counties is
   capped and scrolls VERTICALLY past that — see max-height below. A wrap with
   no cap would have pushed the spot list off a 390px screen entirely, which is
   the failure the cap exists to prevent.

   `[hidden]` is !important in base.css, so this flex cannot defeat it — the
   exact bug that left the region listbox on screen in Weather mode. */
.fc__counties {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  /* No margin: it is a grid item of .fc__selects, which owns the rhythm with
     its own `gap`. A margin here would double the space on one side only. */
  /* The cap is in rem so it tracks text size rather than pinning a pixel
     count of rows, and it only bites on the wide regions — 5 chips never
     reach it. overscroll-behavior keeps a flick inside the chips from
     scrolling the panel behind them, same as .fc__list. */
  max-height: 7.5rem;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.chip {
  display: inline-flex;
  align-items: baseline;
  gap: 0.4em;
  padding: 6px 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--text-secondary);
  font: inherit;
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  line-height: 1.2;
  cursor: pointer;
  transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.chip:hover { border-color: var(--line-strong); color: var(--text); }
/* ⚠ --accent-pressed, NOT --accent, AND THE REASON IS MEASURED. --text-on-dark
   on --accent is 4.02:1 — under the 4.5 floor, and axe called it serious with
   the overlay open. The darker token takes the same pairing to 6.61:1. The
   selected chip is the one state a reader must be able to read at a glance,
   so it cannot be the one that fails. */
.chip[aria-pressed='true'] {
  background: var(--accent-pressed);
  border-color: var(--accent-pressed);
  color: var(--text-on-dark);
}
/* ⚠ NO OPACITY ON THE COUNT, AND THAT WAS A CORRECTION. Dimming it to 0.65
   read as tasteful and measured 2.58:1 on the selected chip and 3.15:1 on an
   unselected one in light — both failing, the count being exactly the part
   carrying the information ("which chip is worth opening"). Hierarchy here
   comes from SIZE AND WEIGHT instead, which costs no legibility: at full
   contrast the count inherits the label's 6.61 / 7.28 / 7.42. */
.chip__n {
  font-size: 0.85em;
  font-weight: var(--fw-body);
  font-variant-numeric: tabular-nums;
  color: inherit;
}
@media (prefers-reduced-motion: reduce) { .chip { transition: none; } }

/* Scrollable spot list. Capped rather than page-length: the largest region is
   689 rows, and letting that extend the panel body would bury the region
   select under a kilometre of scroll. */
.fc__list {
  max-height: min(52vh, 520px);
  margin-top: var(--sp-3);
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}
.fc__list:not(:empty) {
  padding-right: var(--sp-2);
  border-top: 1px solid var(--line);
  padding-top: var(--sp-3);
}
@media (max-width: 560px) {
  .fc__list { max-height: 46vh; }
}

/* ── Maps ─────────────────────────────────────────────────────────────────── */
.modes-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: var(--sp-4);
}
.mode-tile {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--sp-3);
  padding: var(--sp-5);
  text-align: left;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  transition: border-color var(--dur) var(--ease),
              transform var(--dur) var(--ease),
              box-shadow var(--dur) var(--ease);
}
.mode-tile:hover {
  border-color: var(--accent);
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}
.mode-tile__ic {
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  background: var(--accent-tint);
  color: var(--accent);
  border-radius: var(--r-md);
}
.mode-tile__ic svg { width: 22px; height: 22px; }
.mode-tile__name {
  font-size: var(--fs-sm);
  font-weight: var(--fw-label);
  color: var(--text);
  line-height: 1.25;
}

@media (max-width: 1000px) { .modes-grid { grid-template-columns: repeat(4, 1fr); } }
@media (max-width: 760px)  { .modes-grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 480px)  {
  .modes-grid { grid-template-columns: repeat(2, 1fr); gap: var(--sp-3); }
  .mode-tile { padding: var(--sp-4); }
}

/* ── Menu (mobile nav, shell instance) ────────────────────────────────────── */
.menu-list { display: grid; gap: var(--sp-1); }
.menu-list__item {
  display: block;
  width: 100%;
  padding: var(--sp-4) var(--sp-3);
  text-align: left;
  font-size: 1.25rem;
  font-weight: var(--fw-label);
  letter-spacing: var(--tracking-tight);
  border-radius: var(--r-md);
  transition: background var(--dur-fast) var(--ease);
}
.menu-list__item:hover { background: var(--surface); }
.menu-list__rule { height: 1px; margin: var(--sp-4) 0; background: var(--line); }

/* ── Fetch+ paywall ───────────────────────────────────────────────────────── */
.plus { display: grid; justify-items: center; text-align: center; }
.plus__lockup {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}
.plus__lockup img { width: 44px; height: auto; }
.plus__wordmark {
  font-size: 1.75rem;
  font-weight: var(--fw-display);
  letter-spacing: var(--tracking-tight);
  color: var(--text);
}
.plus__motto {
  margin-top: var(--sp-6);
  max-width: 16ch;
  font-size: clamp(1.75rem, 4.6vw, 2.5rem);
  font-weight: var(--fw-display);
  line-height: 1.1;
  letter-spacing: var(--tracking-tight);
}
/* Solid accent — see the note in home.css on why this is not the gradient. */
.plus__motto em {
  font-style: normal;
  color: var(--accent);
}

.plus__toggle { margin-top: var(--sp-8); }

/* ── Download overlay: store list ─────────────────────────────────────────── */
.stores {
  display: grid;
  gap: var(--sp-3);
  width: 100%;
  max-width: 420px;
  margin-top: var(--sp-8);
  padding: 0;
  list-style: none;
}
.store {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  padding: var(--sp-4) var(--sp-5);
  background: var(--bg);
  border: 1.5px solid var(--line-strong);
  border-radius: var(--r-lg);
  text-align: left;
  transition: border-color var(--dur-fast) var(--ease),
              background var(--dur-fast) var(--ease),
              transform var(--dur-fast) var(--ease);
}
.store:hover {
  border-color: var(--accent);
  background: var(--accent-tint);
  transform: translateY(-1px);
}
.store__ic {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  color: var(--text);
}
.store__ic svg { width: 26px; height: 26px; }
.store__text { display: grid; min-width: 0; }
.store__name {
  font-size: var(--fs-body-lg);
  font-weight: var(--fw-label);
  color: var(--text);
  line-height: 1.2;
}
.store__platform { font-size: var(--fs-sm); color: var(--text-muted); }

.plus__plans {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-4);
  width: 100%;
  max-width: 560px;
  margin-top: var(--sp-6);
}
.plan {
  position: relative;
  display: grid;
  gap: var(--sp-1);
  padding: var(--sp-5) var(--sp-4);
  text-align: left;
  background: var(--bg);
  border: 1.5px solid var(--line-strong);
  border-radius: var(--r-lg);
  transition: border-color var(--dur-fast) var(--ease),
              background var(--dur-fast) var(--ease);
}
.plan:hover { border-color: var(--text-muted); }
.plan[aria-checked="true"] {
  border-color: var(--accent);
  background: var(--accent-tint);
  box-shadow: 0 0 0 3px var(--accent-ring);
}
.plan__term {
  font-size: var(--fs-xs);
  font-weight: var(--fw-label);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.plan__price {
  font-size: 1.5rem;
  font-weight: var(--fw-display);
  letter-spacing: var(--tracking-tight);
  color: var(--text);
}
.plan__price small {
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  color: var(--text-muted);
}
.plan__note { font-size: var(--fs-sm); color: var(--text-secondary); }
.plan__trial {
  justify-self: start;
  margin-top: var(--sp-2);
  padding: 3px var(--sp-3);
  background: var(--accent-tint-deep, var(--accent-tint));
  color: var(--accent-text);
  font-size: var(--fs-xs);
  font-weight: var(--fw-label);
  border-radius: var(--r-pill);
}
.plan__save {
  position: absolute;
  top: calc(-1 * var(--sp-3));
  right: var(--sp-4);
  padding: 3px var(--sp-3);
  background: var(--accent);
  color: var(--on-accent);
  font-size: var(--fs-xs);
  font-weight: var(--fw-label);
  border-radius: var(--r-pill);
}

.plus__benefits {
  display: grid;
  gap: var(--sp-4);
  width: 100%;
  max-width: 560px;
  margin-top: var(--sp-10);
  text-align: left;
}
.benefit { display: flex; gap: var(--sp-3); align-items: flex-start; }
.benefit svg {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  margin-top: 3px;
  color: var(--accent);
}
.benefit strong { font-weight: var(--fw-label); color: var(--text); }
.benefit span { color: var(--text-secondary); font-size: var(--fs-sm); }

.plus__cta {
  width: 100%;
  max-width: 560px;
  margin-top: var(--sp-10);
}
.plus__fineprint {
  max-width: 44ch;
  margin-top: var(--sp-4);
  font-size: var(--fs-xs);
  color: var(--text-muted);
}

/* The iPhone-trial pointer / Android app-availability note. Reads as prose
   rather than as a warning: it is a fact about the other platform, not a
   problem with this one. */
.plus__alt {
  max-width: 44ch;
  margin-top: var(--sp-3);
  font-size: var(--fs-xs);
  color: var(--text-secondary);
}
.plus__alt a { color: var(--accent-text); }

/* ⚠ TEST MODE MUST NOT LOOK LIKE FINEPRINT. A sandbox key produces a checkout
   that succeeds, mails a receipt and grants the entitlement while taking no
   money — so on the one surface where that matters this is styled as an alert,
   not as a footnote. --danger-text is defined in BOTH themes (theme-tokens.css
   lines 30 and 79); a colour with only one definition would render this
   invisible in the other, which on this element is the whole point lost. */
.plus__testmode {
  max-width: 44ch;
  margin-top: var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--danger-text);
  border-radius: var(--radius-sm, 6px);
  font-size: var(--fs-xs);
  font-weight: var(--fw-label);
  color: var(--danger-text);
}

@media (max-width: 480px) {
  .plus__plans { grid-template-columns: 1fr; }
  .plan__save { top: var(--sp-4); }
}

/* ── Brandfield: the default overlay background ───────────────────────────────
   Every panel carries the isobar treatment (instances in index.html; the auth
   modal injects its own). The SVG is never edited per surface — the deploy
   drift gate depends on the symbol being identical everywhere — so all tuning
   is CSS on the instance: --bf-opacity per overlay below.

   Readability comes from the CONTENT's own fills, checked per overlay rather
   than asserted: .lb__trigger/.lb__panel, .mode-tile, .plan and the search
   input were already opaque (var(--bg)/var(--surface)); the pieces that sat
   directly on the panel — search results, the forecast spot list, the menu
   items — gain solid fills below. axe's wcag2aa contrast pass over every
   overlay is the check that this held. */
.ov__panel { position: relative; }
.ov__panel > .brandfield {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  background:
    radial-gradient(120% 100% at 12% 0%, rgba(61, 224, 196, 0.14), rgba(61, 224, 196, 0) 58%),
    linear-gradient(180deg, var(--bf-top) 0%, var(--bf-bot) 72%);
}
.ov__panel > .brandfield .brandfield__svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: var(--bf-opacity, 0.75);
}
.ov__bar,
.ov__body {
  position: relative;
  z-index: 1;
}

/* Busy list surfaces keep the field quieter; near-empty pages let it show. */
#ov-search,
#ov-forecast { --bf-opacity: 0.55; }

/* Search results: rows sat directly on the panel and must stay scannable —
   a solid card when populated, nothing when empty (no white box pre-query). */
#ov-search .results:not(:empty) {
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: var(--sp-4) var(--sp-5);
}

/* Forecast spot list: same reasoning, same card. The listbox trigger and its
   dropdown panel were ALREADY opaque (var(--bg)) — a dropdown with contours
   bleeding through reads as broken, and none do. */
#ov-forecast .fc__list:not(:empty),
#ov-forecast #fc-weather-results:not(:empty) {
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: var(--sp-3) var(--sp-4);
}

/* Menu: links were transparent until hover; over the field each becomes a
   solid pill so the tap target reads as a control, not floating text. Hover
   keeps its distinct var(--surface). */
#ov-menu .menu-list__item {
  background: var(--bg);
  border-radius: var(--r-md);
  border: 1px solid var(--line);
}
#ov-menu .menu-list__item + .menu-list__item { margin-top: var(--sp-2); }
#ov-menu .menu-list__item:hover { background: var(--surface); }
#ov-menu .menu-list__rule { background: transparent; }

/* Maps: tiles are already solid cards; the DISABLED ones dim by whole-tile
   opacity (home.css), which over the field lets contours show through the
   card — inspected and kept: translucency now reads as "not yet here", making
   disabled MORE distinct from enabled, not less. The label's contrast is
   axe-checked with the field behind it. */

/* ── DARK ────────────────────────────────────────────────────────────────────
   The overlay shell was already token-driven throughout — panel --bg, scrim
   --scrim, hairline --line — so it themes for free. ONE exception: the close
   button was a bare `color: #000`, which on a dark panel is an invisible
   glyph on every overlay, auth included. Tokenised at EXACTLY the value it
   was already rendering (#000, not --text's #0A1628, so light does not move)
   with dark reading the ink token. */
:root                    { --ov-x-ink: #000; }
:root[data-theme='dark'] { --ov-x-ink: var(--text); }

/* ── Settings in the menu ────────────────────────────────────────────────────
   The segmented control borrows the auth modal's tab language rather than
   inventing a second one, INCLUDING its dark answer: a channel cut below the
   surface with the selected option raised into it. That matters more here
   than it looks — the naive version (track lighter, selected darker) is what
   dark does to a light-designed control by default, and it reads as a hole
   punched in the group rather than a chosen option. See the note in
   css/auth.css for the elevation reasoning. */
.menu-set__h {
  margin: 0 0 var(--sp-3);
  font-size: var(--fs-sm);
  font-weight: var(--fw-label);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.menu-set__row {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-4); padding: var(--sp-2) var(--sp-3);
}
.menu-set__lbl { font-size: 1.05rem; font-weight: var(--fw-medium); color: var(--text); }
.seg {
  display: grid; grid-auto-flow: column; gap: 4px;
  padding: 4px; border-radius: 10px;
  background: var(--seg-track);
}
.seg__opt {
  border: 0; cursor: pointer;
  padding: 8px 18px; border-radius: 8px;
  font: var(--fw-label) 0.95rem/1 var(--font-sans, "Inter", system-ui, sans-serif);
  color: var(--text-secondary); background: transparent;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.seg__opt[aria-checked='true'] {
  background: var(--seg-on-bg);
  color: var(--text);
  box-shadow: var(--seg-on-shadow);
}
.seg__opt:focus-visible { outline: 2px solid var(--brand-teal-bright); outline-offset: 2px; }
:root {
  --seg-track:     var(--surface-sunken);
  --seg-on-bg:     var(--bg);
  --seg-on-shadow: 0 1px 3px rgba(10, 22, 40, 0.12);
}
:root[data-theme='dark'] {
  --seg-track:     rgba(0, 0, 0, 0.25);          /* cut BELOW the card */
  --seg-on-bg:     var(--surface-elevated);      /* raised into it */
  --seg-on-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.07);  /* a shadow does nothing on navy */
}

/* ⚠ THE SELECTED PLAN MOVES THE GROUND UNDER ITS OWN TEXT, and in dark that
   moves it the WRONG WAY for muted ink. --accent-tint is an opaque pale in
   light (#EAF4F3, darker than the card) but a translucent teal wash in dark,
   so selecting a plan makes its surface LIGHTER — #153540 — while the term
   label stays on --text-muted. Measured 3.85:1, the only pair under AA in
   the whole two-theme sweep.

   Corrected here rather than by re-deriving --text-muted, deliberately. That
   token is derived against the four dark GROUNDS (page, card, elevated,
   inset); adding the accent tint to the set pushes it to #8B9AA8, which is
   eight units off fetchDark.slate #93A6B6 — the muted tier would stop being
   distinguishable from the secondary one across the entire site to fix one
   label. The tint is a special surface used by one selected control, so the
   step up to --text-secondary (5.18:1) belongs on that control.

   ⚠ SCOPED TO THE SURFACE, NOT THE ELEMENT — and that distinction was earned.
   The first version of this rule named .plan__term, the one element the sweep
   had reported. Re-running it simply found the NEXT element on the same
   ground (.plan__price small, identical 3.85:1), because the fault was never
   about a label — it is about every muted glyph that sits on this tint.
   Rebinding the TOKEN on the surface fixes the class of bug rather than its
   first instance, and covers anything added to a selected plan later without
   anyone having to remember this note. */
:root[data-theme='dark'] .plan[aria-checked='true'] {
  --text-muted: var(--text-secondary);
}

/* ── Favorites, in the Forecast overlay ──────────────────────────────────── */
.fc__fav { display: grid; gap: var(--sp-3); }
.fc-fav__h {
  margin: var(--sp-4) 0 0;
  font-size: var(--fs-sm); font-weight: var(--fw-label);
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-muted);
}
.fc-fav__region {
  margin: var(--sp-3) 0 calc(var(--sp-1) * -1);
  font-size: var(--fs-sm); font-weight: var(--fw-label); color: var(--text-secondary);
}
.fc-fav__note { margin: 0; color: var(--text-secondary); font-size: var(--fs-sm); }

/* ── Bulk-add picker (Add more spots) ─────────────────────────────────────── */
.fc-fav__add { margin: 0 0 var(--sp-3); }
.fc-pick { display: flex; flex-direction: column; gap: var(--sp-3); min-height: 0; }
.fc-pick__bar { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3); }
.fc-pick__status { margin: 0; min-height: 1.2em; color: var(--text-muted); font-size: var(--fs-sm); }
.fc-pick__list {
  display: flex; flex-direction: column;
  max-height: min(48vh, 420px); overflow-y: auto; overscroll-behavior: contain;
  border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
}
.fc-pick__row {
  display: grid; grid-template-columns: 22px 1fr; grid-template-rows: auto auto;
  align-items: center; gap: 0 var(--sp-3); text-align: left;
  padding: var(--sp-3) var(--sp-2); border: 0; background: none; cursor: pointer;
  border-bottom: 1px solid var(--line);
}
.fc-pick__row:last-child { border-bottom: 0; }
.fc-pick__row:hover, .fc-pick__row:focus-visible { background: var(--surface-sunken, #F4F7FA); }
/* The selection circle — empty ring, fills accent when picked. */
.fc-pick__circle {
  grid-row: 1 / 3; width: 20px; height: 20px; border-radius: 50%;
  border: 2px solid var(--line-strong, #C4CDD6); box-sizing: border-box;
  transition: background-color .12s ease, border-color .12s ease;
}
.fc-pick__row[aria-pressed='true'] .fc-pick__circle {
  background: var(--accent); border-color: var(--accent);
  box-shadow: inset 0 0 0 3px var(--surface, #fff);
}
.fc-pick__name { font-weight: var(--fw-medium); color: var(--text); }
.fc-pick__sub { grid-column: 2; font-size: var(--fs-sm); color: var(--text-muted); }
.fc-pick__foot { display: flex; justify-content: flex-end; }

/* Browse rows (regions, counties) — a nav row with a chevron, distinct from a
   selectable spot row (which carries the circle). Back row is quieter. */
.fc-pick__nav {
  display: grid; grid-template-columns: 1fr auto; align-items: center;
  gap: 2px var(--sp-3); text-align: left;
  padding: var(--sp-3) var(--sp-2); border: 0; background: none; cursor: pointer;
  border-bottom: 1px solid var(--line);
}
.fc-pick__nav:hover, .fc-pick__nav:focus-visible { background: var(--surface-sunken, #F4F7FA); }
.fc-pick__nav .fc-pick__name { grid-column: 1; font-weight: var(--fw-medium); color: var(--text); }
.fc-pick__nav .fc-pick__sub { grid-column: 1; }
.fc-pick__chev { grid-column: 2; grid-row: 1 / 3; color: var(--text-muted); font-size: 1.1rem; }
.fc-pick__back {
  display: block; width: 100%; text-align: left;
  padding: var(--sp-2) var(--sp-2); border: 0; background: none; cursor: pointer;
  color: var(--accent-text, #0E7C6B); font-weight: var(--fw-medium);
  border-bottom: 1px solid var(--line);
}
.fc-pick__back:hover, .fc-pick__back:focus-visible { background: var(--surface-sunken, #F4F7FA); }

/* Add / Remove sit side by side above the saved lists. */
.fc-fav__actions { display: flex; gap: var(--sp-2); flex-wrap: wrap; }

/* Removal rows — the picker row with the verb inverted: the circle carries a
   minus, and a marked row reads as leaving (struck, muted) rather than chosen. */
.fc-pick__row--del .fc-pick__circle { position: relative; }
.fc-pick__row--del .fc-pick__circle::after {
  content: ''; position: absolute; left: 3px; right: 3px; top: 50%;
  height: 2px; margin-top: -1px; border-radius: 1px;
  background: var(--line-strong, #C4CDD6);
}
.fc-pick__row--del[aria-pressed='true'] .fc-pick__circle {
  background: var(--danger, #C0392B); border-color: var(--danger, #C0392B);
  box-shadow: none;
}
.fc-pick__row--del[aria-pressed='true'] .fc-pick__circle::after { background: #fff; }
.fc-pick__row--del[aria-pressed='true'] .fc-pick__name {
  text-decoration: line-through; color: var(--text-muted);
}
.fc-fav__empty {
  display: grid; justify-items: center; gap: var(--sp-3);
  padding: var(--sp-8) var(--sp-4); text-align: center;
}
.fc-fav__empty-h { margin: 0; font-size: 1.15rem; font-weight: var(--fw-label); color: var(--text); }
