/* ==========================================================================
   YOUTHBY — central landing page
   Design direction: "The Square System".
   The wordmark's period is a square, so squares are the brand's geometric
   unit — they carry the activity colors, mark the towns, and recur as a
   motif. Flat, confident, editorial; warm paper ground; purple leads.
   Type and geometry carry the page. The single exception is the Newton
   origin section at the foot of it, which shows two photographs because
   the guide's own history is the one thing here that is worth seeing.
   ========================================================================== */

:root {
  /* Brand — verified against the wordmark PNG itself */
  --purple:        #5929A7;
  --purple-dark:   #422080;
  --purple-tint:   #F2EAFA;
  --ink:           #231B34;
  --youth-ink:     #292139;
  --muted:         #6E6977;
  /* On lavender panels --muted only clears 4.5:1 by a hair; this holds ~6:1. */
  --muted-on-tint: #5D5766;
  --paper:         #FCFAF7;
  --surface:       #FFFFFF;
  --white:         #FFFFFF;
  --tint:          #F2EAFA;
  --deep:          #422080;
  --line:          #E5E0E8;
  --logo-period:   #C660B4;

  /* Activity accents — backgrounds only, never text */
  --peach:         #F8D5BD;
  --pink:          #F4C8DE;
  --mint:          #CFE7D9;
  --gold:          #F6D995;

  --radius-card:   16px;
  --radius-panel:  20px;
  --radius-chip:   999px;

  --shell:         1320px;
  --gutter:        clamp(22px, 5vw, 74px);
  --header-h:      80px;

  --ease:          cubic-bezier(.22, .68, .28, 1);
}

/* ---------- reset ---------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

/* scroll-padding clears the sticky header so a jump to #towns or #scope
   lands on the section, not on its heading tucked underneath the bar. */
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: calc(var(--header-h) + 18px); scrollbar-gutter: stable; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  background: var(--paper);
  color: var(--ink);
  font-family: "DM Sans", system-ui, sans-serif;
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

/* A whisper of paper grain so the flats read as printed, not flat-screen. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: .035;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)'/%3E%3C/svg%3E");
}

img { max-width: 100%; display: block; }
ul, ol { list-style: none; padding: 0; }
a { color: inherit; }

h1, h2, h3 {
  font-family: "Manrope", system-ui, sans-serif;
  font-weight: 800;
  line-height: 1.06;
  letter-spacing: -0.06em;
  color: var(--youth-ink);
  text-wrap: balance;
}

.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gutter);
  position: relative;
  z-index: 1;
}

/* ---------- focus ---------------------------------------------------- */
:where(a, button, [tabindex]):focus-visible {
  outline: 3px solid var(--purple);
  outline-offset: 3px;
  border-radius: 4px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  background: var(--purple);
  color: #fff;
  padding: 12px 18px;
  font-weight: 700;
  border-radius: 0 0 10px 0;
}
.skip-link:focus { left: 0; }

/* ---------- shared bits --------------------------------------------- */
.eyebrow {
  display: flex;
  align-items: center;
  gap: 9px;
  font-family: "DM Sans", sans-serif;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--purple);
}
.eyebrow-mark {
  width: 9px; height: 9px;
  background: var(--logo-period, #C660B4);
  flex: none;
}
.eyebrow-light { color: var(--purple-tint); }
.eyebrow-light .eyebrow-mark { background: var(--gold); }

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-family: "DM Sans", sans-serif;
  font-size: 14px;
  font-weight: 700;
  line-height: 1;
  text-decoration: none;
  padding: 14px 22px;
  border-radius: 10px;
  border: 1.5px solid transparent;
  cursor: pointer;
  transition: background-color .2s var(--ease), color .2s var(--ease),
              border-color .2s var(--ease), transform .2s var(--ease);
  white-space: nowrap;
}
.btn-lg { padding: 17px 28px; font-size: 15px; }
.btn-solid { background: var(--purple); color: #fff; }
.btn-solid:hover { background: var(--purple-dark); transform: translateY(-1px); }
.btn-quiet { color: var(--purple); border-color: var(--line); background: transparent; }
.btn-quiet:hover { border-color: var(--purple); background: var(--purple-tint); }

.section-head { max-width: 720px; }
.section-head h2 { font-size: clamp(25px, 3.4vw, 42px); margin: 18px 0 0; }
.section-lede { margin-top: 18px; color: var(--muted); font-size: 17px; line-height: 1.62; }
.section-lede strong { color: var(--ink); font-weight: 700; }
.on-dark { color: #fff; }
.section-lede.on-dark { color: rgba(255,255,255,.74); }

/* ==========================================================================
   COVERAGE STRIP
   ========================================================================== */
/* A band above the white bar, and the only part of the top of the page that
   scrolls away. It frames the header — the white bar reads as a deliberate
   piece of furniture rather than as wherever the paper happens to begin — and
   it carries the one sentence worth putting there: what is covered, and where
   to go to use it. Nothing about what is not covered yet.

   Deep plum rather than the brand purple. The brighter purple is spent on the
   headline's second line and on the search button, which are the two things on
   this screen a visitor is meant to act on; a strip in the same color would
   compete with both. --ink is the darkest thing in the palette and is what the
   owner picked off the design reference: dark enough that the strip reads as a
   frame around the page rather than as a second purple band. */
.coverage-strip {
  display: block;
  background: var(--ink);
  color: #fff;
  font-size: 13px;
  line-height: 1;
  letter-spacing: .1px;
  font-weight: 500;
}
.coverage-strip-inner {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 2px;
  /* 34px on a desktop: it is a strap, not a banner. */
  min-height: 34px;
  padding: 0 var(--gutter);
  text-align: center;
}
.coverage-strip-arrow { transition: transform .18s var(--ease); }
.coverage-strip:hover .coverage-strip-inner,
.coverage-strip:focus-visible .coverage-strip-inner { text-decoration: underline; text-underline-offset: 3px; }
.coverage-strip:hover .coverage-strip-arrow { transform: translateX(3px); }
.coverage-strip:focus-visible { outline: 2px solid #fff; outline-offset: -3px; }
/* On a phone the sentence is two lines whatever the type size, and a strap
   pinned to 34px would let them overlap. It is allowed to be as tall as the
   text needs and no taller — the recipe for the overlap is `line-height: 1`
   plus a fixed height, not the wrap itself. */
@media (max-width: 700px) {
  .coverage-strip-inner {
    min-height: 0;
    padding: 7px var(--gutter);
    line-height: 1.32;
  }
}

/* ==========================================================================
   HEADER + NAV
   Structure follows Glassdoor's signed-out bar: content pillars that open a
   promo panel on hover, an employer-side link, and a Sign In button. The
   panels deliberately contain no links to sub-pages — they are self-contained
   promos — so the nav is honest on a site that is still one page deep.
   ========================================================================== */
.site-header {
  position: sticky;
  top: 0;
  z-index: 60;
  border-bottom: 1px solid var(--line);
}
/* The frost lives on a child layer rather than the header itself. Putting
   backdrop-filter on .site-header would make it the containing block for
   every position:fixed descendant, which collapses the mobile drawer (its
   `inset` would resolve against an 80px-tall box) and drags the full-width
   menus into the header's overflow. */
.site-header::before {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(252,250,247,.88);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  backdrop-filter: saturate(180%) blur(14px);
}
.header-inner {
  height: var(--header-h);
  display: flex;
  align-items: center;
  gap: 22px;
}
.wordmark { display: block; flex: none; }
.wordmark img { width: 158px; height: auto; }

.main-nav {
  flex: 1;
  display: flex;
  align-items: center;
  min-width: 0;
}
.nav-list { display: flex; align-items: center; gap: 2px; }
.nav-item { position: relative; }

.nav-link {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-family: "DM Sans", sans-serif;
  font-size: 15px;
  font-weight: 600;
  color: var(--ink);
  background: none;
  border: 0;
  padding: 10px 10px;
  border-radius: 8px;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color .18s var(--ease), color .18s var(--ease);
}
/* All three are anchors, and an anchor brings the browser's own underline. */
a.nav-link { text-decoration: none; }
.nav-link:hover { background: var(--purple-tint); color: var(--purple); }

.nav-utility {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 2px;
}
.nav-providers {
  font-size: 15px;
  font-weight: 600;
  color: var(--ink);
  text-decoration: none;
  padding: 10px;
  border-radius: 8px;
  white-space: nowrap;
}
.nav-providers:hover { color: var(--purple); }
/* The plan a parent has built belongs in the bar, not two clicks away. It
   carries the tally of what is in it, because "My Calendar" with nothing
   behind it is a link that leads to an empty page. */
.nav-calendar {
  font-size: 15px;
  font-weight: 600;
  color: var(--ink);
  text-decoration: none;
  padding: 10px;
  border-radius: 8px;
  white-space: nowrap;
}
.nav-calendar:hover { color: var(--purple); }
.nav-calendar-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 20px;
  margin-left: 6px;
  border-radius: 999px;
  background: var(--purple-tint);
  color: var(--purple);
  font-size: 11.5px;
  font-weight: 800;
  flex: none;
}
.nav-signin {
  padding: 11px 20px; font-size: 15px; font-weight: 700; line-height: 1;
  /* A button does not inherit the page's typeface, and the default serif-free
     fallback here was Arial — so the same button was two different typefaces
     depending on which sheet the page loaded. */
  font-family: "DM Sans", system-ui, sans-serif;
  color: #fff; background: var(--purple); border: 1px solid transparent;
  border-radius: 10px; cursor: pointer; white-space: nowrap;
}
.nav-signin:hover { background: var(--deep); }
/* The Log in button and the signed-in avatar are different widths. Holding
   the slot's width steady is what stops For Providers and My Calendar
   sliding sideways as the header settles on a new page. */
@media (min-width: 1121px) {
  .nav-account { display: inline-flex; justify-content: flex-end; min-width: 44px; }
}

/* ---------- mobile --------------------------------------------------- */
.nav-toggle {
  display: none;
  align-items: center;
  gap: 9px;
  margin-left: auto;
  font-family: "DM Sans", sans-serif;
  font-size: 14px;
  font-weight: 700;
  color: var(--ink);
  background: none;
  border: 1.5px solid var(--line);
  border-radius: 9px;
  padding: 10px 14px;
  cursor: pointer;
}
.nav-toggle-bars { display: grid; gap: 4px; }
.nav-toggle-bars i { display: block; width: 18px; height: 2px; border-radius: 1px; background: currentColor; }

@media (max-width: 1120px) {
  /* A backdrop-filter makes the header the containing block for fixed
     descendants, which put the drawer at the header's own top instead of the
     viewport's. Solid paper at this width costs nothing and keeps the drawer
     fixed to the screen. */
  .site-header {
    background: var(--paper);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  .nav-toggle { display: inline-flex; }
  .main-nav {
    position: fixed;
    inset: var(--header-h) 0 0 0;
    z-index: 55;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    background: var(--paper);
    padding: 14px var(--gutter) 48px;
    overflow-y: auto;
    transform: translateX(100%);
    visibility: hidden;
    transition: transform .3s var(--ease), visibility .3s;
  }
  .main-nav.is-open { transform: none; visibility: visible; }
  .nav-list { flex-direction: column; align-items: stretch; gap: 0; }
  .nav-link {
    /* The anchor, not the list item, draws the separator: without a full
       width it is a line under the words only, shorter than the rows below. */
    display: flex;
    width: 100%;
    justify-content: space-between;
    font-size: 18px;
    font-weight: 600;
    padding: 16px 2px;
    border-radius: 0;
    border-bottom: 1px solid var(--line);
  }
  /* One row spec for every way through the site: the five links, For
     Providers, and Saved. The list runs unbroken into the utility rows, so
     the separators are evenly spaced and no row ends on a half-finished
     line. The button is the only thing below it. */
  .nav-utility {
    margin: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
  }
  .nav-providers, .nav-calendar {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 18px;
    font-weight: 600;
    padding: 16px 2px;
    border-radius: 0;
    border-bottom: 1px solid var(--line);
  }
  /* Saved is defined further down this sheet, so its drawer row lives there
     too; a rule here would lose the cascade to the desktop one. */
  .nav-signin { justify-content: center; margin-top: 18px; padding: 15px 20px; font-size: 18px; }
}

@media (max-width: 620px) {
  :root { --header-h: 64px; }
  .wordmark img { width: 132px; }
  .header-inner { gap: 12px; }
}

/* ==========================================================================
   SIGN IN DIALOG
   ========================================================================== */
.signin {
  /* The global `* { margin: 0 }` reset strips the dialog's native
     `margin: auto`, which is what centers it — put it back. */
  margin: auto;
  width: min(480px, calc(100vw - 32px));
  max-height: calc(100vh - 32px);
  overflow: auto;
  border: 1px solid var(--line);
  border-radius: 24px;
  padding: clamp(28px, 4vw, 40px) clamp(22px, 4vw, 38px) clamp(24px, 3vw, 32px);
  background: var(--surface);
  color: var(--ink);
  box-shadow: 0 40px 90px -40px rgba(35,27,52,.6);
  text-align: left;
}
.signin::backdrop {
  background: rgba(35,27,52,.5);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
}
.signin-close {
  position: absolute;
  top: 14px; right: 16px;
  width: 34px; height: 34px;
  display: grid;
  place-items: center;
  font-size: 22px;
  line-height: 1;
  color: var(--muted);
  background: none;
  border: 0;
  border-radius: 8px;
  cursor: pointer;
}
.signin-close:hover { background: var(--purple-tint); color: var(--purple); }
.signin-brand {
  display: inline-flex;
  align-items: flex-start;
  margin: 0 34px 0 0;
  font-family: "Manrope", "DM Sans", system-ui, sans-serif;
  font-size: 20px;
  font-weight: 800;
  letter-spacing: -.035em;
  line-height: 1;
  color: var(--ink);
}
.signin-brand span { color: var(--purple); }
.signin-brand i {
  display: inline-block;
  width: 7px; height: 7px;
  margin: 12px 0 0 2px;
  border-radius: 50%;
  background: var(--logo-period, #C660B4);
}
.signin-title {
  margin-top: 18px;
  font-size: clamp(24px, 3vw, 30px);
  line-height: 1.1;
  letter-spacing: -.03em;
}
.signin-text {
  margin-top: 10px;
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--muted);
}
.signin-email { display: grid; gap: 10px; margin-top: 24px; }
.signin-label { font-size: 12px; font-weight: 700; color: var(--ink); }
.signin-email input {
  width: 100%;
  height: 50px;
  padding: 0 14px;
  font: inherit;
  font-size: 15px;
  color: var(--ink);
  background: #fff;
  border: 1px solid #D9D2E3;
  border-radius: 10px;
}
.signin-email input:focus {
  outline: 2px solid #C9A9EA;
  outline-offset: 1px;
  border-color: #9B72C9;
}
.signin-continue {
  height: 50px;
  border: 0;
  border-radius: 10px;
  background: var(--purple);
  color: #fff;
  font: inherit;
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
}
.signin-continue:hover { background: var(--deep, #422080); }
.signin-continue:disabled { opacity: .6; cursor: default; }
.signin-error { margin: 2px 0 0; font-size: 12.5px; color: #9B2C2C; }
.signin-or {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 20px 0 14px;
  color: var(--muted);
  font-size: 12px;
}
.signin-or::before,
.signin-or::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--line);
}
.signin-provider {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  height: 50px;
  padding: 0 16px;
  border: 1px solid #D9D2E3;
  border-radius: 999px;
  background: #fff;
  color: var(--ink);
  font: inherit;
  font-size: 14.5px;
  font-weight: 600;
  cursor: pointer;
}
.signin-provider:hover { border-color: #B9A6D6; background: var(--purple-tint); }
.signin-provider + .signin-provider { margin-top: 12px; }
.signin-google-mark { flex: 0 0 auto; }
.signin-legal {
  margin: 18px 0 0;
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--muted);
  text-align: center;
}
.signin-legal a { color: inherit; text-decoration: underline; }
.signin-note {
  margin: 14px 0 0;
  padding: 10px 12px;
  border-radius: 10px;
  background: var(--purple-tint);
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--purple-dark);
}
.signin-note[hidden] { display: none; }
.signin-note.is-live { font-weight: 600; }
.signin-account { display: grid; gap: 8px; margin-top: 22px; }
.signin-account[hidden] { display: none; }
.signin-account-name { font-size: 16px; font-weight: 700; color: var(--ink); }
.signin-account-email { margin-bottom: 10px; font-size: 14px; color: var(--muted); }

/* ==========================================================================
   HERO
   ========================================================================== */
/* The copy stands alone now that the illustration lives in the footer, so the
   hero is one centered column rather than the two the headline used to share.
   Every dimension here is deliberately short: the map below is the thing a
   visitor came for, and each line of it that the hero takes is a line of the
   state that falls off the first screen. */
/* The opening of the home page — headline, search and the map. The picture
   belongs to the hero band — the headline, the search and the categories — and
   the map below has the paper.
   It used to be painted on `.home-top`, which holds the map too, so `cover`
   stretched the collage over a thousand pixels and a vertical wash was asked
   to keep both the headline and the map legible; the result was a photograph
   so evenly faded that nothing in it was recognizable at either edge. Framing
   it the other way round fixes that: the wash runs across, not down — clear at
   both edges, where the children are, and near-opaque cream in the middle
   third, where the words are. The activities read at the sides and the copy
   reads in the center, and neither is fighting the other.
   A short fade at the foot hands the band back to the paper so there is no
   hard edge where the map begins. */
.home-top {
  position: relative;
  background: var(--paper);
}
.home-top > * { position: relative; z-index: 1; }
/* The hero sits above the map, not beside it on the same layer. Its one
   overlay — the panel the where-chip opens — hangs below the search box, which
   is the map's top edge, and equal z-index means the later sibling wins: two
   1s had the map painting over the bottom half of an open panel, so the town
   buttons were measurable and invisible. Only the overlap changes; in the
   normal flow the two do not touch. */
.home-top > .home-photo { z-index: 2; }

.home-photo {
  position: relative;
  background-color: var(--paper);
}
/* The collage is painted on a fixed-height band, not on the whole hero. The
   hero grew when the five sources and the interest cards moved in, and `cover`
   on the taller box zoomed the picture until the children were cropped to
   shoulders. The band keeps the framing the photo had before: it scales to the
   band, and the wash hands its foot back to the paper. */
.home-photo::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 640px;
  background-image:
    linear-gradient(90deg,
      rgba(252,250,247,0) 3%,
      rgba(252,250,247,.35) 24%,
      rgba(252,250,247,.95) 37%,
      rgba(252,250,247,.95) 63%,
      rgba(252,250,247,.35) 76%,
      rgba(252,250,247,0) 97%),
    linear-gradient(180deg,
      rgba(252,250,247,0) 64%,
      rgba(252,250,247,.88) 90%,
      rgba(252,250,247,1) 100%),
    url("/assets/youthby-home-colors.webp");
  background-size: cover, cover, cover;
  background-position: center, center, center 30%;
  background-repeat: no-repeat, no-repeat, no-repeat;
  pointer-events: none;
}
.home-photo > * { position: relative; z-index: 1; }

/* A phone has no edges to put the activities in, so the same wash fails there
   for the opposite reason: a 390px box with cream from 25% to 75% leaves a
   photograph no wider than a thumbnail. The narrow case gets the picture as a
   band across the top instead and the copy on paper underneath, which is what
   the collage can actually carry at this width. */
@media (max-width: 700px) {
  /* The desktop collage is three times as wide as it is tall, and a phone box
     is not, so `cover` on that file showed a shoulder and a slice of grass
     with the children's heads above the top edge.
     The phone gets the owner's square collage instead — four activities, one
     per quadrant, cut square at 1080 so `cover` at this width loses only the
     outer edges. It runs behind the whole hero and the wash opens a white
     middle through the copy: the top of the collage is the picture band above
     the headline, the collage's own pale seam falls behind the search, and
     the lower half — the children at the tables and the dancers — shows again
     around the category chips and the count.
     The wash is not flat: the band is crisp at the very top, eases to paper
     as the copy begins, holds paper through the middle, then opens again to
     let the lower pictures show through the gaps around the chips before
     returning to paper at the foot. */
  .home-photo {
    background-image:
      linear-gradient(180deg,
        rgba(252,250,247,.06) 0%,
        rgba(252,250,247,.16) 8%,
        rgba(252,250,247,.72) 15%,
        rgba(252,250,247,.88) 21%,
        rgba(252,250,247,.96) 28%,
        rgba(252,250,247,.97) 36%,
        rgba(252,250,247,.97) 68%,
        rgba(252,250,247,.60) 76%,
        rgba(252,250,247,.46) 86%,
        rgba(252,250,247,.56) 94%,
        rgba(252,250,247,1) 100%),
      url("/assets/youthby-mobile-enhanced.webp");
    background-size: cover, cover;
    /* Anchored to the top so the upper band stays whole; the wash, not the
       crop, is what hands the bottom of the band back to the paper. */
    background-position: center top, center top;
    background-repeat: no-repeat, no-repeat;
  }
  .home-photo::before { content: none; }
  /* The band across the top holds the picture, and the copy starts under it
     rather than on it: the headline is the thing a parent reads first and it
     needs paper behind it, not two faces at 30% opacity. The gap is the top
     band's height. */
  .home-photo .hero { padding-top: 96px; }
  .home-photo .hero-title { font-size: clamp(29px, 9.4vw, 40px); }
  /* The wash alone still let a face sit behind the label and the small grey
     sentence, so the label gets its own slip of paper and the sentence darkens
     a step. The headline already clears comfortably. */
  .home-photo .eyebrow {
    width: fit-content;
    margin-left: auto;
    margin-right: auto;
    padding: 5px 12px;
    border-radius: 999px;
    background: rgba(252,250,247,.88);
  }
  .home-photo .hero-lede { font-size: 15px; color: #4B4555; }
}

.hero {
  padding: clamp(34px, 4.2vw, 60px) 0 clamp(10px, 1.2vw, 16px);
  position: relative;
}
/* A taller band than the one the headline used to sit in. The picture at the
   edges needs somewhere to be a picture, and the headline now has two lines and
   a sentence under it; below this the copy starts crowding the wash. */
.hero-tail { padding-bottom: clamp(26px, 3.2vw, 46px); }
.hero-grid {
  display: grid;
  grid-template-columns: 1fr;
  align-items: center;
}
/* The column is the full shell, because the finder below needs the width to sit
   on one line. The cap that keeps the headline from running a 1200px measure
   now lives on .hero-title itself rather than on the column holding it. */
.hero-copy { text-align: center; }
/* The eyebrow above the headline is a label, not a line of copy: it says who
   the guide is for in four words. It runs smaller than the section eyebrows
   further down the page, where the heading beneath is 25 to 42px and does not
   need the help — here the headline is the loudest thing on the screen and the
   label must not compete with it. */
.hero-copy .eyebrow {
  justify-content: center;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .14em;
}
.hero-title {
  font-size: clamp(34px, 5.4vw, 58px);
  line-height: 1.08;
  max-width: 900px;
  margin: 12px auto 0;
  letter-spacing: -.045em;
}
.hero-title-line { display: block; white-space: nowrap; }
/* "Brought Together" is the half of the headline the visitor is meant to feel,
   in the brand purple, on its own line under the first. <em> would otherwise
   italicise; the emphasis is the color, so the slant comes off. */
.hero-title em { display: block; font-style: normal; color: var(--purple); }
/* The supporting sentence: what the catalogue actually contains, one step
   quieter than the headline above it so the two do not compete. Muted ink, a
   measure short enough to sit under two centered lines without running wider
   than they do. */
.hero-lede {
  max-width: 46em;
  margin: 8px auto 0;
  font-size: clamp(14px, 1.2vw, 16.5px);
  line-height: 1.55;
  color: var(--muted);
  text-wrap: balance;
}
/* The five sources a town's programs come from, joined into one search.
   The pictures are crops of one sprite, so the whole row costs one request. */
.community { margin-top: 12px; text-align: center; }
.community-strip { max-width: 560px; margin: 0 auto; }
.community-sources {
  display: flex; justify-content: space-between; gap: 12px;
  margin: 0; padding: 0; list-style: none;
}
.community-sources li { flex: 1; min-width: 0; }
/* The source name under each picture. The two-line reserve keeps the five
   columns aligned when "Town recreation" wraps and "Camps" does not. */
.community-source-name {
  display: block;
  margin-bottom: 6px;
  min-height: 2.6em;
  font-family: "Manrope", system-ui, sans-serif;
  font-size: 11.5px;
  font-weight: 700;
  line-height: 1.3;
  color: var(--ink);
  text-wrap: balance;
}
.community-scene {
  display: block; width: 100%; aspect-ratio: 434.4 / 466;
  background-image: url("/assets/community-scenes.webp");
  background-repeat: no-repeat;
  background-size: 500% auto;
  background-position: calc(var(--source) * 25%) 56.2%;
}
/* The drawing sits above the five pictures now, because the search bar moved
   above them: the lines lead up into the bar rather than down out of it. */
.community-connections { display: block; width: 100%; height: 50px; margin-bottom: 8px; transform: scaleY(-1); }
@media (max-width: 680px) {
  .community-strip { max-width: 360px; }
  .community-sources { gap: 8px; }
  .community-source-name { font-size: 10.5px; margin-bottom: 5px; }
  .community-connections { height: 44px; margin-bottom: 6px; }
  /* The drawing is stretched to the strip's width, so without this the strokes
     thin to hairlines on a phone. */
  .community-connections path { vector-effect: non-scaling-stroke; }
}
/* ---------- the "good things grow" drawing ------------------------------
   A town marker at the center with four cards orbiting it — pick your town, a
   child's fit, the details, and the registration calendar. It has moved twice:
   it was the hero's illustration, then it closed the page above the footer on
   a desktop and sat under the map on a phone, and it now closes the page at
   every width, on the plate in the footer. It kept its own size rule each
   time rather than inheriting one; .footer-atlas is what sizes it now.
   --------------------------------------------------------------------- */
.hero-atlas {
  display: block;
  width: 100%;
  max-width: clamp(420px, 58vw, 760px);
  height: auto;
  /* Stated explicitly rather than relying on the engine to derive height from
     the viewBox — some WebKit builds collapse an auto-height inline SVG. */
  aspect-ratio: 1600 / 1450;
  margin-inline: auto;
}

/* ==========================================================================
   THE STRIP — what a town guide does, just past the map and the band
   ========================================================================== */
.strip {
  border-top: 1px solid var(--line);
  padding: clamp(32px, 3.6vw, 48px) 0 clamp(28px, 3.2vw, 42px);
}
.strip-title {
  font-size: clamp(14px, 1.3vw, 16px);
  letter-spacing: -0.02em;
  color: var(--muted);
  margin-bottom: 26px;
}
/* The six capabilities as the drawn journey. Both files are the same six
   steps, so the only decision here is which one a screen gets.

   The swap is at 900px, and it is set by legibility rather than by device: the
   wide file's body text is 30px at its 2172px width, so below about 900px of
   layout it falls under 12px and stops being readable. (It was cropped tighter
   from 2172x724 to 2172x497 since; the swap still lands on that reasoning.)
   The tall file is
   narrower than it is tall, so past 560px it would run to two and a half
   thousand pixels of scroll on a tablet — it is capped rather than stretched. */
.guide-path { display: block; }
.guide-path img {
  display: block;
  width: 100%;
  height: auto;
  /* Reserved before the file arrives, so the section does not jump. */
  aspect-ratio: 2172 / 497;
}

@media (max-width: 899px) {
  .guide-path img {
    max-width: 560px;
    margin-inline: auto;
    aspect-ratio: 724 / 2172;
  }
}

/* ==========================================================================
   WHAT'S COVERED — the four categories
   ========================================================================== */
/* No heading above the cards any more, so the section leans on the strip's
   own bottom padding for separation instead of adding a second gap. */
.covered { padding: clamp(20px, 2.4vw, 32px) 0 clamp(50px, 6vw, 84px); }
.covered-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 18px;
}
.covered-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  padding: clamp(20px, 2vw, 28px);
  transition: transform .25s var(--ease), box-shadow .25s var(--ease);
}
.covered-card:hover,
.covered-card:focus-within {
  transform: translateY(-3px);
  box-shadow: 0 16px 32px -22px rgba(35,27,52,.42);
}
/* Each card is a link to the hub that lists it, like a category tile rather
   than a badge. The whole card is the target; the name is what says where it
   goes, so the name is what underlines on hover. */
.covered-link {
  display: block;
  text-decoration: none;
  color: inherit;
}
.covered-card img { width: 84px; height: 84px; margin-bottom: 18px; }
.covered-card h3 {
  font-size: 19px;
  letter-spacing: -0.04em;
  margin-bottom: 9px;
}
.covered-link:hover h3,
.covered-link:focus-visible h3 { text-decoration: underline; text-underline-offset: 4px; }
.covered-body {
  display: block;
  color: var(--muted);
  font-size: 14.5px;
  line-height: 1.55;
}

/* The browse block under the search: a small heading line, four interest
   cards, then the narrower ways in beneath them. It replaces the row of
   category chips and says what each category actually contains. */
.browse-bar {
  margin-top: 26px;
  padding-top: 20px;
  border-top: 1px solid var(--line);
  text-align: left;
}
.bar-heading {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 20px; margin: 0 0 14px; font-size: 13px;
}
.bar-heading strong { color: var(--ink); font-size: 14px; }
.bar-heading p { margin: 0; color: var(--muted); font-size: 12px; }
.category-nav {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px;
}
.category-link {
  display: flex; align-items: center; gap: 14px; min-height: 86px;
  border: 1px solid var(--line); border-radius: 9px; padding: 9px 16px;
  background: var(--surface); color: var(--ink); text-decoration: none;
  transition: border-color .18s var(--ease), background-color .18s var(--ease);
}
.category-link:hover, .category-link:focus-visible {
  border-color: #b79bd1; background: #f8f3fc;
}
.category-link img { width: 57px; height: 57px; object-fit: contain; flex: none; }
.category-link span { font-size: 14px; font-weight: 700; }
.category-link small {
  display: block; font-size: 11px; color: var(--muted);
  font-weight: 400; margin-top: 2px;
}
.category-link .arrow {
  margin-left: auto; font-size: 20px; font-weight: 400; color: var(--purple);
}
.secondary-categories {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 12px 22px; font-size: 13px; margin-top: 17px;
}
.secondary-categories a {
  min-height: 32px; display: inline-flex; align-items: center;
  color: var(--ink); text-decoration: none;
}
.secondary-categories a:hover, .secondary-categories a:focus-visible {
  color: var(--purple); text-decoration: underline; text-underline-offset: 3px;
}
.secondary-categories .all { margin-right: auto; font-weight: 700; }
@media (max-width: 760px) {
  .browse-bar { margin-top: 20px; padding-top: 16px; }
  .bar-heading { font-size: 12px; margin-bottom: 12px; }
  .bar-heading strong { font-size: 13px; }
  .bar-heading p { font-size: 10px; }
  .category-nav { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 9px; }
  .category-link { min-height: 65px; padding: 8px 11px; gap: 10px; }
  .category-link img { width: 41px; height: 41px; }
  .category-link span { font-size: 12px; }
  .category-link small { display: none; }
  .secondary-categories { gap: 5px 19px; font-size: 11px; margin-top: 12px; }
}

.covered-note {
  margin-top: 24px;
  padding-left: 16px;
  border-left: 3px solid var(--purple);
  font-size: 14px;
  color: var(--muted);
}

@media (max-width: 1000px) { .covered-grid { grid-template-columns: repeat(2, 1fr); } }
/* Two up on a phone too: four stacked cards were 1,244px of scroll for four
   short paragraphs. The illustration still leads each card, at a size that
   reads at 390px wide. */
@media (max-width: 520px)  {
  .covered-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  .covered-card { padding: 14px 14px 16px; }
  .covered-card img { width: 52px; height: 52px; margin-bottom: 10px; }
  .covered-card h3 { font-size: 16px; margin-bottom: 6px; }
  .covered-body { font-size: 12.5px; line-height: 1.45; }
}

/* ==========================================================================
   TWELVE TABS — the problem, between the A–Z index and the capabilities
   ========================================================================== */
/* A band, not a section: it is the breath between two dense blocks, and it
   fills the gap a decorative drawing used to hold. It sits below the map on
   purpose — the map is what the hero hands a visitor, and this would delay it.
   The copy is a sibling of the artwork, not a caption under it: on a wide
   screen they read as one sentence and one picture; on a phone the picture
   drops below the words.

   The picture is decorative (alt=""), because every word it carries is either
   already in the copy, the caption, or the illustration's own small labels —
   and those labels are illegible at phone size by design. */
.one-place {
  background: var(--paper);
  padding: clamp(18px, 2.2vw, 28px) 0 clamp(12px, 1.8vw, 22px);
}
.one-place-inner {
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
  align-items: center;
  gap: clamp(24px, 4vw, 56px);
}
.one-place-title {
  font-size: clamp(30px, 3.1vw, 44px);
  line-height: 1.06;
  letter-spacing: -0.035em;
  color: var(--ink);
  text-wrap: balance;
}
.one-place-title em {
  color: var(--purple);
  font-style: normal;
}
.one-place-lede {
  margin-top: 13px;
  max-width: 34em;
  font-size: clamp(15px, 1.35vw, 18px);
  line-height: 1.5;
  color: var(--muted);
  text-wrap: pretty;
}
.one-place-figure { margin: 0; }
.one-place-figure img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1201 / 442;
}
.one-place-figure figcaption {
  margin-top: 8px;
  font-size: 12.5px;
  letter-spacing: 0.01em;
  color: var(--muted);
  text-align: center;
}

@media (max-width: 899px) {
  .one-place { padding: clamp(22px, 5vw, 30px) 0 clamp(14px, 4vw, 22px); }
  .one-place-inner { grid-template-columns: minmax(0, 1fr); gap: 18px; }
  .one-place-title { font-size: clamp(26px, 8vw, 34px); }
  .one-place-lede { margin-top: 9px; font-size: 15px; }
  .one-place-figure img { max-width: 560px; margin-inline: auto; }
  .one-place-figure figcaption { margin-top: 8px; font-size: 12px; }
}

/* ==========================================================================
   TOWNS
   ========================================================================== */
.towns {
  background: var(--paper);
  color: var(--ink);
  /* Less above than below: the gap under the hero only has to separate two
     sections, while the one below the A–Z index has to separate the map from
     the band that follows it. The band carries no spacing of its own, so this
     is the whole of the gap above it. */
  padding: clamp(4px, 0.5vw, 6px) 0 clamp(58px, 7vw, 100px);
}
.towns .section-head h2 { color: var(--ink); }
/* The map is the second of the page's two offerings, and until now it had no
   heading at all — a legend and a view toggle, arriving straight off the
   hero. Naming it is what tells a parent that finding programs right now and
   reading a town's guide are two different things they can do here. The ruled
   line belongs to .map-bar and becomes the divider under this block. */
/* Padding, not margin. A margin on the first child collapses out of the
   section and becomes space the hero's own background still paints, so the
   heading ended up flush against the bottom of the photograph. */
.towns-head { padding-top: clamp(30px, 4vw, 52px); margin-bottom: clamp(4px, 1vw, 12px); }
.towns-head .section-lede { margin-top: 12px; }
/* ==========================================================================
   TOWN FINDER — the map
   --------------------------------------------------------------------------
   Every Massachusetts municipality is drawn, and the 66 with a guide are
   filled with that guide's own color, so the map and the town page agree.
   The shapes are inline SVG: they carry the 66 guide links, and a link a
   crawler cannot see is not a link. Greater Boston is drawn a second time at
   roughly twice the scale and clipped to a panel, because at state scale most
   of the covered towns are a few pixels across and cannot be pointed at.
   Hover names the town, brings it forward and previews it in the card; a click
   opens the guide.
   ========================================================================== */
/* The section's own heading, and one sentence under it. There was a flex row
   here — heading copy on the left, a town search and its tally on the right —
   until the finder above took over the job: its place field searches a town and
   its count already names how many there are. What is left is a heading and a
   line of prose, so it is a block. */
.towns .section-lede { max-width: 62ch; }

.map-bar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 18px 24px; flex-wrap: wrap;
  margin: clamp(13px, 1.5vw, 20px) 0 12px;
  padding-top: clamp(13px, 1.5vw, 18px); border-top: 1px solid var(--line);
}
.map-legend { display: flex; gap: 24px; flex-wrap: wrap; margin: 0; }
.map-key {
  display: inline-flex; align-items: center; gap: 9px;
  font-size: 13.5px; color: var(--muted);
}
.map-swatch { width: 11px; height: 11px; border-radius: 50%; flex: none; }
.map-swatch-guide { background: var(--purple); }
.map-swatch-other { background: #EDE9E5; border: 1px solid #D4CDC8; }
/* Small screens get the two views as buttons instead of relying on type that
   has shrunk past reading; the map itself is unchanged. */
.map-views { display: none; gap: 8px; order: 3; width: 100%; }
.map-view {
  flex: 1; min-height: 44px; padding: 10px 14px; font: inherit; font-size: 14px;
  font-weight: 700; color: var(--purple); background: var(--surface);
  border: 1px solid var(--line); border-radius: 10px; cursor: pointer;
}
.map-view[aria-pressed="true"] {
  background: var(--purple); border-color: var(--purple); color: #fff;
}

/* The map bleeds out to the shell's edges — the extra 150px is what keeps the
   Greater Boston panel large enough to read, since its towns scale with the
   whole canvas. */
.map-main { margin-inline: calc(-1 * var(--gutter)); }
/* Clicking a town focuses the <svg> itself, and Chrome draws its default 5px
   ring around the whole drawing. The map is steered by the 94 links inside it,
   each of which keeps its own visible focus style, so the ring on the drawing
   is noise. :not(:focus-visible) keeps it for keyboard focus. */
.ma-svg:focus:not(:focus-visible) { outline: none; }
/* The sea. The state is drawn as its 351 towns and nothing else, so what shows
   between them is whatever is behind the drawing — which used to be the page's
   own paper, and made the whole map read as one flat sheet: no coast, no water,
   nothing for the land to sit on. A wash of water behind it costs one gradient
   and no tiles, and the towns become a coastline.

   It is deliberately pale and leans blue-violet rather than cyan so it belongs
   to the same palette as everything else on the page. */
.map-canvas {
  position: relative;
  border-radius: var(--radius-panel);
  overflow: hidden;
  background:
    radial-gradient(120% 90% at 78% 8%, rgba(255, 255, 255, .66) 0%, rgba(255, 255, 255, 0) 58%),
    linear-gradient(168deg, #DCE9F5 0%, #CCE0F1 44%, #BBD5EB 100%);
}
/* The land lifts off the water. One shadow under the whole landmass rather
   than one per town, so the coast reads as a coast and the seams between towns
   stay flat hairlines. */
.ma-state, .ma-inset { filter: drop-shadow(0 5px 9px rgba(28, 54, 84, .16)); }
.ma-svg { display: block; width: 100%; height: auto; }

/* The map: paper towns, hairline seams, and the 66 in their own color. The
   resting fill is a presentation attribute so these rules can outrank it. */
.ma-plain { fill: #EFE9DE; transition: fill .16s var(--ease); }
.ma-plain:hover { fill: #DED7C9; }
.ma-guide {
  stroke: #fff; stroke-width: 1.2; stroke-linejoin: round; cursor: pointer;
  transition: fill .18s var(--ease), stroke .18s var(--ease),
              stroke-width .18s var(--ease);
}
.ma-a { text-decoration: none; }
.ma-a:focus-visible { outline: none; }
.ma-a:focus-visible .ma-guide { stroke: var(--ink); stroke-width: 3.6; }
.ma-a:hover .ma-guide, .ma-guide.is-hot {
  stroke: var(--town-deep); stroke-width: 2.6; filter: url(#ma-hover);
}
/* The chosen town keeps a lighter fill, so the card below always has something
   on the map pointing at it. The class is set on the anchor, which is where the
   town's attributes live — the path does not carry them, so this has to hang
   off .ma-a, as the hover and focus rules above already do. */
.ma-a.is-selected .ma-guide {
  fill: var(--town-selected); stroke: var(--town-color); stroke-width: 2.4;
}
.ma-l {
  font-family: "Manrope", system-ui, sans-serif; font-weight: 700;
  fill: var(--youth-ink); paint-order: stroke; stroke: var(--paper);
  stroke-width: 3.4px; stroke-linejoin: round; pointer-events: none;
}
.ma-region {
  font-family: "Manrope", system-ui, sans-serif; font-weight: 700;
  font-size: 15px; letter-spacing: .18em; text-transform: uppercase;
  fill: #8695A8; pointer-events: none;
}
.ma-inset-title {
  font-family: "Manrope", system-ui, sans-serif; font-weight: 700;
  font-size: 15px; letter-spacing: .16em; text-transform: uppercase;
  fill: var(--purple);
}
.ma-leader {
  fill: none; stroke: #C6BDCE; stroke-width: 1.4; stroke-dasharray: 5 5;
  pointer-events: none;
}
.ma-north, .ma-scale { fill: none; stroke: #948C7E; stroke-width: 1.4; }
.ma-north text, .ma-scale text {
  font-family: "Manrope", system-ui, sans-serif; font-weight: 700;
  font-size: 14px; fill: #948C7E; stroke: none;
}
.ma-north text { font-size: 15px; letter-spacing: .12em; }

/* The foot of the map: the town-guide card, and — on a phone, where there is
   room for it — the example listing behind it. Stacked rather than set in
   columns, because a desktop shows one card and the phone shows two, and the
   desktop one is pulled back up over the map's empty quarter by the rule in
   the opening-screen block at the end of this file. */
.map-foot {
  display: grid;
  gap: 18px;
  margin-top: 18px;
}
.map-inset-note { margin: 0; font-size: 13px; color: var(--muted); }

/* The listing, lifted out of the guide so the map has something to show for
   itself. See the note on .map-example's margin below for why it is where it
   is; the rest is a card like the ones the guides are made of. */
.map-example {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-panel);
  /* Every measurement in this card is a little tighter than the eye would ask
     for on its own. The card hangs inside the map's empty quarter against a
     fixed 400px band, and the ten guides that wear a photograph strip need
     76px of room the band does not have to give — so the card pays for its own
     photographs out of its padding. Nothing the card says changes; see
     .map-example-photos below for what the 42px buys. */
  padding: clamp(18px, 1.5vw, 22px);
  box-shadow: 0 28px 56px -38px rgba(35,27,52,.5);
}
.map-example:empty { display: none; }
/* Every part of the card is optional — a record can have no fee, no venue, no
   site to visit — and the script hides what a town has none of. The browser's
   own [hidden] is a bare display:none, which the card's own rules outrank:
   without this the description stays on screen with no program behind it,
   and "Visit website" goes on offering the town before last. */
.map-example [hidden] { display: none; }

.map-example-tag {
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
  margin: 0;
  font-size: 11px; font-weight: 700; letter-spacing: .15em;
  text-transform: uppercase; color: var(--muted);
}
.map-example-swatch { width: 30px; height: 8px; border-radius: 4px; flex: none; }
/* The town's own color, which is the same color its shape is filled with on
   the map above — the one thing tying the card to the town it is describing. */
.map-example-town { color: var(--purple); }

/* The guide's own opening row, at the size a card can afford. Under the tag
   row rather than under the listing, because the town should say who it is
   before the program does.
   Four tracks whatever the row holds: lexington has three photographs and
   wellesley two, and their tiles should be the same size as everyone else's
   rather than stretching to fill. width/height on each img is the thumbnail's
   own 288x192, so the box is reserved before the file arrives and nothing on
   the page below moves when it does. */
.map-example-photos {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 8px;
  margin-top: 12px;
}
.map-example-photos img {
  display: block; width: 100%; height: auto;
  aspect-ratio: 3 / 2; object-fit: cover;
  border-radius: 9px;
}

.map-example-head {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: 10px 0 0;
}
.map-example-chip {
  font-size: 10.5px; font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase; color: var(--purple);
  background: var(--purple-tint); padding: 5px 10px; border-radius: var(--radius-chip);
}
.map-example-org { font-size: 12.5px; color: var(--muted); font-weight: 500; }

.map-example-name {
  margin: 8px 0 0; font-size: clamp(17px, 1.35vw, 20px);
  letter-spacing: -.035em; line-height: 1.24;
}
/* Clamped, both, and the card is the only place they are. A record's notes can
   run to three lines under one label — one venue is "Wednesday outdoor St
   Mark's Park and Thursday indoor Boston Ballet Studio, 1431 Beacon St" — and
   a card that grows with whichever town the pointer is over would not fit the
   space the map leaves it, nor stay still. The guide has the whole of it. */
.map-example-desc {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 4;
  overflow: hidden;
  margin: 7px 0 0; font-size: 13.5px; line-height: 1.55; color: var(--ink);
}
/* The ten guides wearing photographs pay for them with one line of this. Four
   lines is a generous excerpt and three is still one; the other fifty-six
   towns keep all four. */
.map-example.has-photos .map-example-desc { -webkit-line-clamp: 3; }

/* Two columns of label over value. Seven rows down one column is twice the
   height the space can hold; four rows of two fit where the card has to sit. */
.map-example-facts {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 18px;
  margin: 12px 0 0; padding: 0;
  border-top: 1px solid var(--line);
}
.map-example-facts > div {
  padding: 8px 0 9px;
  border-bottom: 1px solid var(--line);
  min-width: 0;
}
.map-example-facts dt {
  font-size: 10px; font-weight: 700; letter-spacing: .1em;
  text-transform: uppercase; color: var(--muted);
}
.map-example-facts dd {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3;
  overflow: hidden;
  margin: 4px 0 0; font-size: 13.5px; line-height: 1.4; color: var(--ink);
}

.map-example-actions {
  display: flex; flex-wrap: wrap; gap: 9px; margin-top: 12px;
}
.map-example-note {
  margin: 10px 0 0; font-size: 11.5px; line-height: 1.5; color: var(--muted);
}

/* Stacked, the column is the page: a listing stretched to 800px on its own
   line is a paragraph with a lot of white space beside it. */
@media (max-width: 1199px) {
  .map-example { max-width: 620px; }
}

/* The town-guide card. One card, and on a desktop it is the only thing under
   the map: a picture of the town on the left, and what the guide holds on the
   right. The picture is a third of the card rather than a banner across it,
   because the card has to stay short enough to sit inside the first screen
   with the map and the search box above and below it. */
.map-card {
  display: flex; align-items: flex-start; gap: clamp(13px, 1.4vw, 18px);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-panel); padding: 9px 15px 11px;
  box-shadow: 0 22px 52px -36px rgba(35,27,52,.55);
}
/* The box is reserved by these two -- the width here and the 3:2 the file is
   cut to -- so the card is already its final size before town-map.js has put a
   photograph in it, and the search box below does not move when one arrives.
   The tint is what shows in that moment, and behind a town with no picture. */
.map-card-photo {
  flex: none; width: 108px; aspect-ratio: 3 / 2; height: auto;
  object-fit: cover; border-radius: 11px; background: var(--purple-tint);
}
.map-card-body { min-width: 0; }
.map-card-tag {
  display: inline-flex; align-items: center; gap: 9px;
  font-size: 10.5px; font-weight: 700; letter-spacing: .15em;
  text-transform: uppercase; color: var(--muted);
}
.map-card-swatch { width: 38px; height: 8px; border-radius: 4px; flex: none; }
.map-card-name {
  margin: 3px 0 2px; color: var(--youth-ink); letter-spacing: -.045em;
  font-size: clamp(17px, 1.35vw, 20px);
}
.map-card-meta { margin: 0 0 8px; font-size: 13px; color: var(--muted); }
/* Inline, so the arrow follows the words: stretched across the card's
   width the arrow lands at the far edge and reads as a second, separate
   thing to press. */
.map-card-go {
  display: inline-flex; align-items: center; gap: 8px;
  font-weight: 700; font-size: 14px; text-decoration: none;
}
.map-card-go:hover { text-decoration: underline; }
.map-card-arrow { font-size: 19px; line-height: 1; }
/* A town without a guide keeps the button's slot, greyed rather than removed,
   so the card's height does not change under a finger on the map. */
.map-card.is-none .map-card-go {
  color: var(--muted) !important;
  cursor: default;
  pointer-events: none;
  text-decoration: none;
}
/* Off the desktop composition the card is a card again rather than the full
   width of the shell, and on a phone its photograph gives up a third of itself
   so the town's numbers still fit on one line beside it. */
@media (max-width: 1023px) { .map-card { max-width: 460px; } }
@media (max-width: 560px)  { .map-card-photo { width: 92px; } }

/* Close under the map's foot, and closer than it was: a sentence counting the
   towns used to sit above it, saying again what the search box says 90px
   earlier. Below it is the band the tallest listing needs to hang in, which no
   amount of margin makes shorter. */
.town-index-title {
  margin: clamp(24px, 2.8vw, 38px) 0 14px; font-size: 13px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--muted);
}
.town-index {
  display: flex; flex-wrap: wrap; gap: 5px 15px;
  margin: 0; padding: 0; list-style: none;
}
.town-index a { font-size: 13.5px; color: var(--muted); text-decoration: none; }
.town-index a:hover { color: var(--purple); text-decoration: underline; }
.map-credits {
  display: flex; flex-wrap: wrap; gap: 5px 22px;
  margin: 28px 0 0; font-size: 12px; color: #9B92A0;
}

/* The tooltip rides with the pointer, so it is fixed to the viewport rather
   than nested in the panel it is describing. */
.map-tip {
  position: fixed; z-index: 70; pointer-events: none;
  padding: 10px 15px; border-radius: 12px; background: var(--surface);
  border: 1px solid var(--line); color: var(--youth-ink);
  font-size: 15px; font-weight: 700; line-height: 1.25;
  box-shadow: 0 18px 40px -16px rgba(35,27,52,.42);
  transform: translate(-50%, -150%); white-space: nowrap;
}
.map-tip::before {
  content: ""; display: inline-block; width: 8px; height: 8px; margin-right: 9px;
  border-radius: 2px; background: var(--tip-color, var(--purple));
}
.map-tip small {
  display: block; margin-top: 3px; font-size: 12px; font-weight: 500;
  color: var(--muted);
}

/* The two view buttons are the phone's way of reading a canvas too narrow for
   its own labels, and 1024 is where the page stops being a phone: below it the
   map is framed one view at a time, above it the state and the panel are drawn
   together and the buttons would be switching between a thing already on
   screen. town-map.js frames the SVG at the same width. */
@media (max-width: 1023px) {
  .map-views { display: flex; }
}

/* ==========================================================================
   THE PHONE'S TOWN FINDER
   --------------------------------------------------------------------------
   Desktop keeps the map, the legend and the card exactly as they were. Below
   1024px the section gains a search, a List/Map switch, a list carrying the
   same photograph and counts as the card, and a compact legend under the map.
   The map drawing, its labels and its water are untouched.
   ========================================================================== */
.town-finder,
.town-list-panel,
.map-touch-note,
.town-browse { display: none; }
.towns [hidden] { display: none !important; }

@media (max-width: 1023px) {
  /* On a phone the town card is the answer to the search, so it moves above
     the map rather than sitting below it where a thumb has to scroll past the
     whole canvas to reach it. The map and its labels are untouched; only the
     order of the blocks around it changes. */
  .towns .shell { display: flex; flex-direction: column; }
  .towns .shell > * { min-width: 0; }
  .towns-head { order: 1; }
  .town-finder { order: 2; }
  .map-bar { order: 3; }
  .map-foot { order: 4; }
  .town-list-panel, .map-main { order: 5; }
  .map-touch-note, .map-inset-note { order: 6; }
  .town-browse { order: 7; }

  .finder-count { font-size: 13px; }

  .town-finder { display: block; margin-top: 14px; }
  .finder-search { position: relative; }
  .finder-search-icon {
    position: absolute; left: 17px; top: 50%; transform: translateY(-50%);
    display: flex; color: #6E6977; pointer-events: none;
  }
  .finder-search input {
    width: 100%; height: 54px; padding: 0 18px 0 51px;
    font: inherit; font-size: 16px; color: var(--ink);
    background: var(--surface); border: 1px solid var(--line);
    border-radius: 15px; appearance: none; -webkit-appearance: none;
  }
  .finder-search input::placeholder { color: #7C7486; opacity: 1; }
  .finder-search input:focus {
    outline: 2px solid #C9A9EA; outline-offset: 1px; border-color: #9B72C9;
  }

  .finder-search-menu {
    position: absolute; z-index: 90; left: 0; right: 0; top: calc(100% + 8px);
    background: var(--surface); border: 1px solid var(--line); border-radius: 16px;
    box-shadow: 0 26px 64px -22px rgba(35,27,52,.4);
    overflow: hidden; max-height: min(58vh, 430px); overflow-y: auto;
  }
  .town-sug {
    display: grid; grid-template-columns: 9px 1fr 58px 14px; align-items: center;
    gap: 11px; padding: 10px 13px; min-height: 62px;
    color: inherit; text-decoration: none; border-bottom: 1px solid var(--line);
  }
  .town-sug:last-child { border-bottom: 0; }
  .town-sug:hover, .town-sug.is-active { background: #F7F2FB; }
  .town-sug-swatch { width: 9px; height: 32px; border-radius: 5px; }
  .town-sug-copy { min-width: 0; }
  .town-sug-copy strong {
    display: block; font-size: 15.5px; line-height: 1.2; color: var(--ink);
  }
  .town-sug-copy span {
    display: block; margin-top: 2px; font-size: 12px; color: var(--muted);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .town-sug-thumb { width: 58px; height: 44px; border-radius: 9px; object-fit: cover; display: block; }
  .town-sug-arrow { color: #B4ABC0; font-size: 21px; line-height: 1; }
  .town-sug-empty { margin: 0; padding: 18px 14px; font-size: 14px; color: var(--muted); }

  .town-modes {
    display: grid; grid-template-columns: 1fr 1fr; gap: 4px;
    margin-top: 12px; padding: 4px; background: #EFEAF3;
    border: 1px solid var(--line); border-radius: 14px;
  }
  .town-mode {
    min-height: 46px; border: 0; border-radius: 10px; background: none;
    font: inherit; font-size: 15px; font-weight: 700; color: #5D5568; cursor: pointer;
  }
  .town-mode[aria-pressed="true"] {
    background: var(--purple); color: #fff;
    box-shadow: 0 8px 18px -10px rgba(89,41,167,.8);
  }

  /* The two map views become tabs rather than buttons. The map itself is not
     changed: this only styles the switch that frames it. */
  .towns .map-bar {
    display: block; margin: 10px 0 10px; padding: 0; border-top: 0;
  }
  .towns .map-legend { display: none; }
  .towns .map-views {
    display: flex; gap: 26px; width: 100%;
    border-bottom: 1px solid var(--line);
  }
  .towns .map-view {
    flex: 0 0 auto; min-height: 42px; padding: 0 2px 9px;
    border: 0; border-radius: 0; background: none;
    font-size: 14px; font-weight: 600; color: var(--muted);
    border-bottom: 2px solid transparent;
  }
  .towns .map-view[aria-pressed="true"] {
    background: none; border-color: transparent;
    border-bottom-color: var(--purple); color: var(--purple);
  }

  .map-touch-note {
    display: flex; align-items: center; justify-content: space-between;
    gap: 14px; margin: 10px 2px 0; font-size: 12.5px; color: var(--muted);
  }
  .map-touch-note .map-key { font-size: 12.5px; }
  .map-inset-note { display: none; }

  /* A compact card above the map: a small photograph, the town's numbers and
     the town-colored button. The example listing is gone on a phone — the
     card is the one thing a thumb needs before the canvas. */
  .map-foot { display: flex; flex-direction: column; gap: 10px; margin: 12px 0 14px; }
  .map-card {
    order: 1; display: flex; align-items: center; gap: 12px;
    max-width: none; padding: 10px; border-radius: 16px;
  }
  .map-card-photo {
    flex: none; width: 104px; height: 84px; aspect-ratio: auto;
    border-radius: 11px; object-fit: cover; display: block;
  }
  .map-card-body { flex: 1; min-width: 0; padding: 0; }
  .map-card-tag { gap: 7px; font-size: 9.5px; }
  .map-card-swatch { width: 26px; height: 7px; }
  .map-card-name { margin: 3px 0 1px; font-size: 21px; }
  .map-card-meta { margin-bottom: 0; font-size: 12.5px; }
  .map-card-go {
    display: inline-flex; align-items: center; justify-content: center; gap: 7px;
    width: auto; min-height: 38px; margin-top: 9px; padding: 8px 13px;
    border-radius: 9px; background: var(--town-color, var(--purple));
    color: #fff !important; font-size: 13px; font-weight: 700;
    text-decoration: none;
  }
  .map-card-go:hover { text-decoration: none; filter: brightness(1.06); }
  .map-card.is-none .map-card-go {
    background: #E9E2EF; color: #6E6977 !important; box-shadow: none;
  }
  .map-example { display: none; }

  .town-list-panel {
    display: block; margin-top: 10px; background: var(--surface);
    border: 1px solid var(--line); border-radius: 18px; overflow: hidden;
  }
  .town-list-status {
    margin: 0; padding: 13px 16px 10px;
    font-size: 11px; font-weight: 800; letter-spacing: .14em;
    text-transform: uppercase; color: var(--muted);
    border-bottom: 1px solid var(--line);
  }
  .town-list {
    list-style: none; margin: 0; padding: 0;
    max-height: min(64vh, 560px); overflow-y: auto;
  }
  .town-list li + li { border-top: 1px solid var(--line); }
  .town-row {
    display: grid; grid-template-columns: 9px 1fr 58px 14px;
    align-items: center; gap: 11px; padding: 11px 14px;
    min-height: 66px; color: inherit; text-decoration: none;
  }
  .town-row:hover { background: #F7F2FB; }
  .town-row-swatch { width: 9px; height: 34px; border-radius: 5px; }
  .town-row-copy { min-width: 0; }
  .town-row-name { display: block; font-size: 16px; font-weight: 700; line-height: 1.2; color: var(--ink); }
  .town-row-meta { display: block; margin-top: 2px; font-size: 12.5px; color: var(--muted); }
  .town-row-thumb { width: 58px; height: 44px; border-radius: 9px; object-fit: cover; display: block; }
  .town-thumb-mono {
    display: grid; place-items: center;
    background: var(--town-color, var(--purple)); color: #fff;
    font-size: 18px; font-weight: 800;
  }
  .town-row-arrow { color: #B4ABC0; font-size: 22px; line-height: 1; }
  .town-list-empty { padding: 20px 16px; color: var(--muted); font-size: 14px; }

  .town-browse { display: block; margin: 16px 0 0; text-align: center; }
  .town-browse a {
    display: inline-flex; align-items: center; gap: 8px;
    font-size: 15px; font-weight: 700; color: var(--purple);
    text-decoration: none;
  }
  .town-browse a:hover { text-decoration: underline; }
}
/* Under about 820px the canvas is 700-odd pixels wide and 22-unit labels land
   near 9px, which reads as grit. The state view drops them and the Greater
   Boston button becomes the way to read names. */
@media (max-width: 820px) {
  .towns[data-view="statewide"] .ma-labels { display: none; }
}
@media (max-width: 720px) {
  .map-foot { grid-template-columns: 1fr; }
}
@media (prefers-reduced-motion: reduce) {
  .ma-guide, .ma-plain { transition: none; }
}

.towns-note {
  margin-top: 26px;
  font-size: 14px;
  color: var(--muted);
}

/* ==========================================================================
   NEWTON — the origin
   The one section on the page that shows a session rather than describing
   one, so it is the one section that breaks the "no photography" rule the
   rest of this file keeps. The two cards overlap on a lavender panel, each
   turned a couple of degrees off true, and the smaller is a button: turning
   the pair over is the section's whole flourish.
   ========================================================================== */
/* No padding above: every section on this page butts against the last and
   takes its air from the one above's own foot, which is what the tinted panel
   this replaced used to do too. */
.newton-origin { padding: 0 0 clamp(58px, 7vw, 104px); }
.newton-origin-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
  align-items: center;
  gap: clamp(30px, 5vw, 68px);
}

.newton-origin-title {
  margin: 20px 0 22px;
  font-family: "Manrope", sans-serif;
  font-size: clamp(32px, 4.7vw, 50px);
  line-height: 1.12;
  font-weight: 800;
  letter-spacing: -1.9px;
  text-wrap: balance;
}
.newton-origin-title span { color: var(--purple); }
/* Darker than --muted on purpose: this is running prose, not a label, and
   --muted clears 4.5:1 by too little for a paragraph at this size. */
.newton-origin-story {
  max-width: 38ch;
  font-size: 16px;
  line-height: 1.75;
  color: #625B6D;
}
.newton-origin-story p + p { margin-top: 14px; }
.newton-origin-story strong { color: var(--ink); font-weight: 600; }
.newton-origin-actions {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 16px;
  margin-top: 28px;
}
.newton-origin-second {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 13px;
  color: #625B6D;
  text-underline-offset: 4px;
  text-decoration-color: #C8BBD9;
}
.newton-origin-second:hover { color: var(--purple); }

.newton-origin-art { min-width: 0; }
.newton-origin-photos { position: relative; min-width: 0; padding: 24px 28px 50px 0; }
.newton-origin-photos::before {
  content: "";
  position: absolute;
  right: 0; top: 0;
  width: 73%; height: 84%;
  border-radius: var(--radius-panel);
  background: var(--purple-tint);
}
.newton-origin-main {
  position: relative;
  width: 91%;
  padding: 8px 8px 0;
  background: var(--surface);
  border-radius: 13px;
  transform: rotate(-2deg);
  box-shadow: 0 12px 32px -22px rgba(41,33,57,.28);
}
.newton-origin-main img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  object-position: 62% 50%;
  border-radius: 7px;
}
.newton-origin-main figcaption {
  min-height: 36px;
  padding: 10px 6px;
  font-size: 11px;
  color: #625B6D;
}
.newton-origin-small {
  position: absolute;
  right: 0; bottom: 0;
  display: block;
  width: 43%;
  padding: 7px;
  border: 0;
  border-radius: 11px;
  background: var(--surface);
  transform: rotate(4deg);
  box-shadow: 0 10px 25px -14px rgba(41,33,57,.35);
  cursor: pointer;
  transition: transform .18s var(--ease);
}
.newton-origin-small img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1;
  object-fit: cover;
  object-position: 46% 42%;
  border-radius: 5px;
}
.newton-origin-small:hover { transform: rotate(2deg); }
.newton-origin-small:focus-visible { outline: 3px solid var(--purple); outline-offset: 4px; }
.newton-origin-hint {
  position: absolute;
  right: 15px; bottom: 15px;
  display: flex;
  padding: 5px;
  border-radius: 7px;
  color: var(--purple);
  background: var(--paper);
}
.newton-origin-place {
  position: relative;
  display: flex;
  align-items: center;
  gap: 7px;
  margin-top: 30px;
  font-size: 11px;
  color: #625B6D;
}
@media (max-width: 900px) {
  .newton-origin-grid { grid-template-columns: minmax(0, 1fr); gap: 30px; }
  .newton-origin-title { font-size: clamp(34px, 7vw, 46px); max-width: 14ch; }
  .newton-origin-story { max-width: 45ch; }
  .newton-origin-actions { flex-direction: row; flex-wrap: wrap; align-items: center; gap: 18px; margin-top: 24px; }
  .newton-origin-art { width: 100%; max-width: 520px; margin-inline: auto; }
  .newton-origin-photos { padding-right: 22px; }
  .newton-origin-main { width: 88%; }
  .newton-origin-main img { aspect-ratio: 3 / 2; }
}
@media (prefers-reduced-motion: reduce) {
  .newton-origin-small { transition: none; }
}

/* ==========================================================================
   FOOTER
   ========================================================================== */
.site-footer {
  background: var(--youth-ink);
  color: #fff;
  padding: clamp(44px, 5vw, 66px) 0 38px;
}
/* Brand on the left, four link groups on the right, then a full-width caution
   and the utility row. Two columns with the groups as a nested four-column
   grid, rather than five areas on one grid: it lets the groups reflow 4 → 2 → 1
   on their own while the brand block stays one thing. */
.footer-inner {
  display: grid;
  grid-template-columns: minmax(230px, 1.15fr) minmax(0, 2.6fr);
  gap: clamp(30px, 3.4vw, 52px) clamp(24px, 3vw, 56px);
  align-items: start;
}
.footer-brand { min-width: 0; }
.footer-groups {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 30px clamp(16px, 2vw, 32px);
}

/* A group heading is a label, not a sentence. The providers group's own
   heading is the only one that links anywhere — the landing it points at
   exists so that group is not three orphaned forms. */
.footer-group-title {
  font-family: "DM Sans", sans-serif;
  font-size: 12.5px;
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: #fff;
  margin: 0 0 14px;
}
.footer-group-title a {
  color: inherit; text-decoration: none;
  /* The heading is a label; the link inside it must not borrow the list's
     size, or one group's heading reads as a sentence beside the others. */
  font-size: inherit; font-weight: inherit; line-height: inherit;
  letter-spacing: inherit; text-transform: inherit;
}
.footer-group-title a:hover { text-decoration: underline; text-underline-offset: 3px; }
.footer-group ul { display: grid; gap: 11px; }
/* 15px rather than the 14 the three old links used: these are the only route to
   most of the site, and the brief asks for a directory, not fine print.
   .8 white on the footer ink is about 10:1, well past the 4.5 the brief sets. */
.footer-group a {
  color: rgba(255, 255, 255, .8);
  text-decoration: none;
  font-size: 15px;
  line-height: 1.45;
  transition: color .2s var(--ease);
}
.footer-group a:hover,
.footer-group a:focus-visible { color: #fff; text-decoration: underline; text-underline-offset: 3px; }

.footer-mark { width: 150px; height: auto; }
.footer-line {
  margin-top: 16px;
  font-size: 15px;
  line-height: 1.6;
  letter-spacing: normal;
  color: rgba(255,255,255,.72);
  max-width: 38ch;
}
.contact-direct {
  max-width: 70ch;
  margin: 0 auto 22px;
  font-size: 15px;
  line-height: 1.65;
  color: var(--ink);
}
.contact-direct a { color: var(--purple); font-weight: 700; text-decoration: underline; text-underline-offset: 3px; }

.footer-contact {
  margin-top: 10px;
  font-family: 'DM Sans', system-ui, sans-serif;
  font-size: 13.5px;
  font-weight: 400;
  letter-spacing: normal;
  color: rgba(255,255,255,.55);
}
.footer-contact a {
  color: rgba(255,255,255,.8);
  text-decoration: none;
  text-underline-offset: 3px;
}
.footer-contact a:hover { color: var(--brand-light, #c9a9ea); }
.footer-provenance {
  margin-top: 14px;
  font-size: 13.5px;
  letter-spacing: normal;
  color: rgba(255,255,255,.5);
}
.footer-provenance a { color: rgba(255,255,255,.72); text-decoration: none; text-underline-offset: 3px; }
.footer-provenance a:hover { color: #fff; }

/* The drawing, under the brand block.
   It is composed for paper — a light-lavender medallion, white streets, ink
   type, a #FCFAF7 page showing through its cards — and this is the darkest
   ground on the site, so it keeps its own background: a plate of the same
   paper the page above is printed on. A tinted rectangle would have been the
   other way to make it read, and it would have repainted a composition that
   was drawn once and should not be redrawn by CSS.
   The width is stated rather than left to the drawing: an inline SVG answers
   `width: 100%` against whatever box it is handed, and at footer scale the
   plate has to be what decides how big that is. Below about 150px the small
   card lettering stops resolving and the drawing is just a mark, which is the
   floor here. */
.footer-atlas {
  width: clamp(140px, 16vw, 205px);
  margin-top: clamp(26px, 3vw, 40px);
  padding: clamp(9px, 1.1vw, 15px);
  background: var(--paper);
  border-radius: 15px;
  box-shadow: 0 24px 54px -34px rgba(0, 0, 0, .9);
}
.footer-atlas .hero-atlas { max-width: 100%; margin-inline: 0; }

/* Above the utility row rather than below it: it is the one line a parent
   should read before acting, and under a copyright line it reads as an
   afterthought. The brief lists the two the other way round. */
.footer-note {
  grid-column: 1 / -1;
  margin-top: clamp(6px, 1vw, 14px);
  padding-top: 26px;
  border-top: 1px solid rgba(255,255,255,.14);
  font-size: 14px;
  color: rgba(255,255,255,.68);
}
.footer-utility {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 14px 28px;
  font-size: 13px;
}
.footer-utility-links { display: flex; flex-wrap: wrap; gap: 12px 22px; }
.footer-utility-links a {
  color: rgba(255,255,255,.62);
  text-decoration: none;
}
.footer-utility-links a:hover,
.footer-utility-links a:focus-visible { color: #fff; text-decoration: underline; text-underline-offset: 3px; }
.footer-copyright { color: rgba(255,255,255,.45); }

@media (max-width: 1080px) {
  .footer-groups { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 30px clamp(20px, 4vw, 44px); }
}
@media (max-width: 820px) {
  .footer-inner { grid-template-columns: 1fr; }
}
/* Two columns, not one. Five stacked groups were 1,799px of footer on a
   phone — two full screens of links under a page nobody had finished reading.
   Two columns halves it and still reads as a list of lists. */
@media (max-width: 520px) {
  .footer-groups { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 22px 16px; }
  .footer-utility { flex-direction: column; align-items: flex-start; }
}

/* ==========================================================================
   MOTION — one orchestrated entrance, then stillness
   ========================================================================== */
@media (prefers-reduced-motion: no-preference) {
  /* The copy only. The illustration left the hero for the footer, so it no
     longer arrives with the headline — and a drawing that fades in well below
     the fold was animating where nobody could see it. */
  .hero-copy > * {
    opacity: 0;
    transform: translateY(14px);
    animation: rise .68s var(--ease) forwards;
  }
  .hero-copy > *:nth-child(1) { animation-delay: .05s; }
  .hero-copy > *:nth-child(2) { animation-delay: .12s; }
  .hero-copy > *:nth-child(3) { animation-delay: .19s; }
  .hero-copy > *:nth-child(4) { animation-delay: .26s; }
  .hero-copy > *:nth-child(5) { animation-delay: .33s; }
}
@keyframes rise { to { opacity: 1; transform: none; } }

/* Scroll reveal — classes applied by app.js */
.reveal {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity .6s var(--ease), transform .6s var(--ease);
}
.reveal.is-in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; transition: none; }
}

/* Announced to assistive technology, not shown. Used for the search box's
   label, which the placeholder stands in for visually. */
.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;
}

/* ============================================================================
   THE FINDER
   One search bar: a pill with the two questions inside it and a round button
   at the end, and a line under it saying how much is behind the search. It has
   been three things. First two unrelated boxes — a borderless line over a
   bordered one, which read as a headline over a box and nothing on the card
   said "search". Then a labelled card of fields, which said "search" in the
   smallest possible voice and took two rows of page height. This one is a
   search bar: the shape a visitor already knows, with the magnifier where they
   reach for it and the suggestion turning over where they read.

   The labels are still in the document for a screen reader; the placeholders
   carry the meaning on the surface, which is what lets the pill be 62px tall
   instead of a label row plus a field row.
   ========================================================================== */
/* The form is the wrapper, and the bar is the pill inside it. They are two
   elements because the count sits under the bar and there is no way to put a
   footnote outside a background painted on the element it is inside. */
.finder {
  /* The entrance animation leaves a transform on this form, which makes it a
     stacking context of its own. Without a z-index here the place panel — a
     child of it — is confined to that context and paints beneath the category
     chips that follow the form, so the panel opened behind them. */
  position: relative;
  z-index: 30;
  margin: 10px auto 0;
  max-width: min(760px, 100%);
  text-align: left;
}

.search-bar {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "what go";
  align-items: center;
  background: var(--surface);
  /* A lavender edge, the one the owner picked from a reference: enough color
     to make the bar a drawn object on the photograph without turning the whole
     pill into a button. */
  border: 1px solid #CBB0E6;
  /* A pill, not a card. The radius has to clear half the height, or the round
     button inside it reads as a circle in a rectangle. */
  border-radius: 999px;
  padding: 7px;
  box-shadow: 0 0 0 3px rgba(203,176,230,.16), 0 26px 54px -40px rgba(35,27,52,.6);
  transition: border-color .18s var(--ease), box-shadow .18s var(--ease);
}
/* The whole bar lights up when either half is being typed in, rather than one
   half of it — it is one control, and a focus ring around half of it says
   otherwise. */
.search-bar:focus-within {
  border-color: var(--purple);
  box-shadow: 0 0 0 4px var(--purple-tint), 0 26px 54px -40px rgba(35,27,52,.6);
}
.search-what  { grid-area: what; }
.search-go    { grid-area: go; }

.search-field { min-width: 0; position: relative; display: flex; }
.search-field input {
  width: 100%;
  min-width: 0;
  font: inherit;
  font-size: 16px;
  color: var(--ink);
  line-height: 1.3;
  padding: 13px 18px;
  border: 0;
  border-radius: 999px;
  background: none;
}
.search-field input::placeholder { color: var(--muted); }
.search-field input:focus-visible { outline: none; }

/* ---------- the where ----------
   A chip, not a field. It sits under the bar rather than inside it because it
   is not a question the visitor has to answer — it states a scope the site
   worked out, and opens the control that changes it. Inside the pill it made
   the bar read as a form; here it reads as a footnote that happens to be
   clickable. */
/* Where and how old, side by side under the bar. They are one sentence — a
   nine-year-old in Newton — so they share a line and wrap only on a phone. */
.finder-scope {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: flex-start;
  gap: 2px;
  margin-top: 10px;
}
.finder-scope .finder-place { margin-top: 0; }

.finder-place {
  position: relative;
  display: flex;
  justify-content: center;
  margin-top: 10px;
}

.finder-place-chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  background: none;
  border: 1px solid transparent;
  border-radius: 999px;
  padding: 6px 13px 6px 11px;
  cursor: pointer;
  transition: color .16s var(--ease), background .16s var(--ease),
              border-color .16s var(--ease);
}
.finder-place-chip svg { width: 15px; height: 15px; flex: none; opacity: .75; }
.finder-place-chip:hover { color: var(--ink); background: var(--surface); border-color: var(--line); }
.finder-place-chip:focus-visible { outline: none; border-color: var(--purple); box-shadow: 0 0 0 4px var(--purple-tint); }
/* A town we are actually searching is worth more than a default, so it takes
   the brand color and stops reading as greyed-out helper text. */
.finder-place-chip.is-set { color: var(--purple); }
.finder-place-chip.is-set svg { opacity: 1; }
.finder-place-cue { opacity: .6; font-weight: 500; }

.finder-place-panel {
  position: absolute;
  top: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%);
  z-index: 40;
  width: min(420px, calc(100vw - 36px));
  padding: 12px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 16px;
  box-shadow: 0 18px 44px -22px rgba(35,27,52,.55);
  text-align: left;
}
.finder-place-panel[hidden] { display: none; }
.finder-place-panel input {
  width: 100%;
  font: inherit;
  font-size: 15px;
  color: var(--ink);
  padding: 10px 14px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--bg);
}
.finder-place-panel input:focus-visible { outline: none; border-color: var(--purple); box-shadow: 0 0 0 3px var(--purple-tint); }
.finder-place-panel input[aria-invalid="true"] { border-color: #C0392B; }

.finder-place-quick { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-top: 10px; }

/* The age list is the programs page's own control — the same checkboxes in
   the same grid, so a parent who has used one already knows the other. */
.finder-place-panel .multi-list { display: grid; gap: 2px 6px; margin-top: 10px; }
.finder-place-panel .multi-ages { grid-template-columns: repeat(5, 1fr); }
.finder-place-panel .multi-option {
  display: flex; align-items: center; justify-content: center; gap: 5px;
  font-size: 13.5px; padding: 6px 2px; border-radius: 8px; cursor: pointer;
}
.finder-place-panel .multi-option:hover { background: var(--purple-tint); }
.finder-place-panel .multi-option input {
  width: 15px; height: 15px; accent-color: var(--purple); flex: none;
}
.finder-place-panel .multi-panel-foot {
  display: flex; justify-content: space-between; gap: 8px;
  border-top: 1px solid var(--line); margin-top: 10px; padding-top: 9px;
}
.finder-place-panel .multi-clear {
  font: inherit; font-size: 12.5px; font-weight: 600;
  color: var(--purple); background: var(--purple-tint);
  border: 1px solid transparent; border-radius: 999px;
  padding: 5px 12px; cursor: pointer;
}
.finder-place-panel .multi-clear:hover { background: var(--purple); color: #fff; }
.finder-place-panel .multi-done { background: var(--purple); color: #fff; }
.finder-place-panel .multi-done:hover { background: var(--deep); }
@media (max-width: 520px) {
  .finder-place-panel .multi-ages { grid-template-columns: repeat(4, 1fr); }
}
.finder-place-hint { font-size: 12px; color: var(--muted); margin-right: 2px; }
.finder-place-pick {
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--purple);
  background: var(--purple-tint);
  border: 1px solid transparent;
  border-radius: 999px;
  padding: 5px 12px;
  cursor: pointer;
}
.finder-place-pick:hover { background: var(--purple); color: #fff; }
.finder-place-any { color: var(--muted); background: none; border-color: var(--line); }
.finder-place-any:hover { color: var(--ink); background: var(--surface); }

/* The suggestion that turns over. A real element rather than the placeholder
   attribute, because only a real element can cross-fade — and it is what
   carries the turn, so it fades out, the text changes behind it, and it fades
   back in. Hidden the moment there is anything to read, or anyone typing. */
.search-hint {
  position: absolute;
  left: 18px;
  right: 18px;
  top: 50%;
  transform: translateY(-50%);
  pointer-events: none;
  font-size: 16px;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  opacity: 0;
  transition: opacity .26s var(--ease);
}
.search-hint.is-on { opacity: 1; }
/* A caret, so an empty hint reads as a line about to be written rather than as
   nothing at all — and so the middle of a word reads as typing rather than as
   a half-printed placeholder. It is decoration on decoration: the label is what
   a screen reader has. */
.search-hint::after {
  content: "";
  display: inline-block;
  width: 1px;
  height: 1.05em;
  margin-left: 2px;
  vertical-align: -.16em;
  background: currentColor;
  animation: yb-caret 1.05s steps(1) infinite;
}
@keyframes yb-caret { 0%, 50% { opacity: 1; } 50.01%, 100% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .search-hint::after { animation: none; opacity: .4; }
}
.search-field:focus-within .search-hint,
.search-hint[hidden] { opacity: 0; }
/* The suggestion stands either way; only the fading is motion. */
@media (prefers-reduced-motion: reduce) { .search-hint { transition: none; } }

/* The button: a circle, and nothing in it but the magnifier. Its name for a
   screen reader is on the button; its name for everyone else is the shape. */
.search-go {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--purple);
  color: #fff;
  cursor: pointer;
  transition: background .18s var(--ease), transform .18s var(--ease);
}
.search-go svg { width: 21px; height: 21px; flex: none; }
.search-go:hover { background: var(--purple-dark); transform: scale(1.06); }
.search-go:focus-visible { outline: 3px solid var(--purple); outline-offset: 3px; }
@media (prefers-reduced-motion: reduce) {
  .search-go:hover { transform: none; }
}

/* What the bar is searching, and how much of it there is. A footnote under the
   control rather than a cell in its row: the row is the search. The numbers
   carry the ink and the labels stay muted, with a hairline between the two
   facts so the line reads as a measurement rather than a sentence. */
.finder-count {
  margin: 12px 0 0;
  text-align: center;
  font-size: 12.5px;
  color: var(--muted);
}

/* Under about 720 a pill long enough to hold both questions and a button is
   three cramped slots, and "Town or ZIP" is the one that breaks first. The bar
   keeps its shape and grows a second row instead — the radius comes off the
   pill because a 108px-tall 999px radius is a lozenge. */
@media (max-width: 719px) {
  /* The bar is one field and a button at every width now, so it keeps the
     pill and only the padding changes. */
  .search-bar { border-radius: 26px; padding: 8px; }
}

/* ---------- results ---------- */

.results { padding: clamp(40px, 5vw, 72px) 0 var(--gap-section, 56px); }
.results[hidden] { display: none; }
.sr-head h2 {
  font-size: clamp(20px, 2.2vw, 28px);
  line-height: 1.25;
  text-wrap: balance;
}
.sr-note { margin-top: 8px; color: var(--muted); font-size: 14px; }
/* Offered only when a search came back empty inside a town the site guessed
   at, so it is allowed to look like the way out that it is. */
.sr-widen {
  display: inline-block; margin-top: 6px;
  font: inherit; font-size: 13px; font-weight: 600;
  color: var(--purple);
  background: none; border: 0; padding: 0 0 0 2px;
  text-decoration: underline; cursor: pointer;
}
.sr-widen:hover { color: var(--ink); }

/* ==========================================================================
   RESULTS — filters, the ranked list, and the map
   --------------------------------------------------------------------------
   Wide screen: three columns, filters on the left, numbered results down the
   middle, and a map that stays put while the list scrolls past it. Narrow
   screen: one column, with the filters and the map as panels the visitor asks
   for, because there is nowhere else for them to go.

   The numbers do the work here. A result's rank is on the card and on the pin,
   so a parent moving down the list can see where each one is without reading
   a town name off every card.
   ========================================================================== */
/* Sticky, so the question stays reachable from anywhere in the answers. The
   frost is the header's — paper at the same opacity over the same blur — so
   the two bars read as one surface when the reader is deep in the list. */
.sr-head {
  position: sticky;
  top: var(--header-h);
  z-index: 30;
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 14px 24px; flex-wrap: wrap;
  padding-bottom: 14px;
  /* Near-solid rather than the header's .88: what passes under this bar is
     dense card text, not a hero, and at .88 the blur left two sentences
     legible on top of each other. */
  background: rgba(252, 250, 247, .975);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  backdrop-filter: saturate(180%) blur(14px);
}
.sr-head-main { min-width: 0; flex: 1 1 260px; }
.sr-head-views { display: none; gap: 8px; }

/* The hero's bar, brought down to the size of a bar. Same field, same button,
   same pill — a search box that looked different here would read as a
   different search. */
.sr-bar { flex: 0 1 380px; min-width: 240px; }
.sr-bar .search-bar { padding: 5px; box-shadow: none; }
.sr-bar .search-field input { font-size: 15px; padding: 10px 16px; }
.sr-bar .search-go { width: 40px; height: 40px; }
.sr-bar .search-go svg { width: 18px; height: 18px; }
.sr-bar .search-bar:focus-within { box-shadow: 0 0 0 4px var(--purple-tint); }
@media (max-width: 720px) {
  /* Full width once the head has wrapped, because a 240px field beside a
     two-line count is a field nobody can read what they typed in. */
  .sr-bar { flex: 1 1 100%; min-width: 0; }
}
.sr-view {
  font: inherit; font-size: 13.5px; font-weight: 700;
  color: var(--purple); background: var(--surface);
  border: 1px solid var(--line); border-radius: 10px;
  padding: 10px 16px; min-height: 44px; cursor: pointer;
}
.sr-view[aria-expanded="true"] { background: var(--purple); border-color: var(--purple); color: #fff; }

.sr-layout {
  margin-top: 24px;
  display: grid;
  /* A map wider than about 420px stops telling you anything the list has not
     already, and every pixel it takes comes off the card. */
  grid-template-columns: minmax(200px, 216px) minmax(0, 1fr) minmax(340px, 420px);
  gap: clamp(20px, 2.4vw, 34px);
  align-items: start;
}

/* Under the results head, which is sticky too. `--sr-head-h` is measured from
   the head itself by search.js, because its height depends on whether the count
   line has wrapped. The 92px fallback is the head at its shortest. */
.sr-rail {
  display: grid; gap: 22px; position: sticky;
  top: calc(var(--header-h) + var(--sr-head-h, 92px) + 18px);
}
.sr-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.sr-chip {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 7px 12px; border-radius: 999px;
  border: 1px solid var(--purple);
  background: var(--purple-tint);
  color: var(--purple-dark);
  font: inherit; font-size: 13px; font-weight: 600;
  cursor: pointer;
}
.sr-chip span { font-size: 15px; line-height: 1; opacity: .7; }
.sr-chip:hover { background: var(--purple); color: #fff; }
.sr-chip:hover span { opacity: 1; }
.sr-chip-none { font-size: 13px; color: var(--muted); }

/* One control per group, label above it, down the rail. The rule above each
   one is what makes it read as a section rather than a run of fields. */
.sr-filters { display: grid; gap: 16px; }
.sr-filters label {
  display: grid; gap: 7px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
  font-size: 11.5px; font-weight: 800; letter-spacing: .08em;
  text-transform: uppercase; color: var(--muted);
}
.sr-filters label:first-child { padding-top: 0; border-top: 0; }
.sr-filters select,
.sr-filters input {
  font: inherit; font-size: 14px; font-weight: 500;
  text-transform: none; letter-spacing: 0;
  color: var(--ink);
  width: 100%;
  padding: 10px 11px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface);
}
.sr-filters select:disabled { opacity: .5; }
.sr-filters input:focus-visible,
.sr-filters select:focus-visible { outline: none; border-color: var(--purple); box-shadow: 0 0 0 3px var(--purple-tint); }

/* A filter that takes more than one answer: the same section rule and the same
   field box as the selects, but it opens a list of checkboxes. The summary
   carries what is chosen, because a closed filter still has to say what it is
   doing — "Age · 6, 9" reads at a glance where a count does not. */
.sr-facet {
  padding-top: 14px;
  border-top: 1px solid var(--line);
}
.sr-facet:first-child { padding-top: 0; border-top: 0; }
.sr-facet > summary {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  font-size: 11.5px; font-weight: 800; letter-spacing: .08em;
  text-transform: uppercase; color: var(--muted);
  cursor: pointer; list-style: none;
  padding: 10px 11px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface);
}
.sr-facet > summary::-webkit-details-marker { display: none; }
.sr-facet > summary::after {
  content: ""; flex: none;
  width: 8px; height: 8px; margin-left: 2px;
  border-right: 2px solid var(--muted); border-bottom: 2px solid var(--muted);
  transform: rotate(45deg) translateY(-2px);
  transition: transform .18s var(--ease, ease);
}
.sr-facet[open] > summary { border-color: var(--purple); box-shadow: 0 0 0 3px var(--purple-tint); }
.sr-facet[open] > summary::after { transform: rotate(-135deg) translateY(-1px); }
.sr-facet-name { text-transform: uppercase; }
.sr-facet-val {
  margin-left: auto; min-width: 0;
  font-size: 11.5px; font-weight: 700; letter-spacing: .02em;
  text-transform: none; color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sr-facet.is-set > summary { color: var(--purple); }
.sr-facet.is-set .sr-facet-val { color: var(--purple); }
.sr-facet-body {
  display: grid; gap: 2px;
  max-height: 232px; overflow-y: auto;
  margin-top: 6px; padding: 6px;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--surface);
}
.sr-facet-group {
  margin: 6px 4px 2px;
  font-size: 10.5px; font-weight: 800; letter-spacing: .09em;
  text-transform: uppercase; color: var(--muted);
}
.sr-facet-group:first-child { margin-top: 2px; }
/* `.sr-filters label` dresses every label in the rail as a section heading —
   uppercase, a rule above it, a column. An option is a label inside one of
   those, so it has to undo all three, and it needs the specificity to do it. */
.sr-filters .sr-opt {
  display: flex; flex-direction: row; align-items: center; gap: 9px;
  padding: 6px 7px;
  border-top: 0;
  border-radius: 8px;
  font-size: 13.5px; font-weight: 500; letter-spacing: 0;
  text-transform: none; color: var(--ink);
  cursor: pointer;
}
.sr-filters .sr-opt:hover { background: var(--purple-tint); }
.sr-opt input {
  appearance: none; flex: none;
  width: 17px; height: 17px; margin: 0;
  border: 1.6px solid #CFC7D8; border-radius: 5px;
  background: #fff;
  display: grid; place-items: center;
  cursor: pointer;
}
.sr-opt input::after {
  content: ""; width: 9px; height: 9px; border-radius: 2px;
  background: #fff; transform: scale(0); transition: transform .12s var(--ease, ease);
}
.sr-opt input:checked { background: var(--purple); border-color: var(--purple); }
.sr-opt input:checked::after { transform: scale(1); }
.sr-opt input:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--purple-tint); }

/* ---------- the map ---------- */
.sr-mapcol {
  position: sticky; top: 92px;
  display: grid; gap: 10px;
}
.sr-map {
  height: min(72vh, 720px);
  min-height: 380px;
  border: 1px solid var(--line);
  border-radius: var(--radius-panel);
  overflow: hidden;
  background: var(--surface);
}
.sr-map.is-blank { display: grid; place-items: center; text-align: center; padding: 24px; }
.sr-map-note { color: var(--muted); font-size: 13.5px; line-height: 1.6; max-width: 34ch; }
.sr-maperr { color: var(--muted); font-size: 12.5px; }
.sr-mapfoot {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap;
}
.sr-mapsync {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 13px; font-weight: 600; color: var(--ink);
  cursor: pointer;
}
.sr-mapsync input { width: 16px; height: 16px; accent-color: var(--purple); }
.sr-mapcredit, .sr-mapcount { font-size: 12px; color: var(--muted); }

/* A pin carries its result's rank. It is a real button, so a pin can be
   reached by keyboard as well as by pointer.

   A disc with a point under it, not a rounded square rotated forty-five
   degrees: the old shape put the rank on a diagonal (the counter-rotation the
   number needed was easy to lose, and the tip was a corner rather than the
   bottom of the element, so pins sat slightly off their towns). The disc keeps
   the number upright and the tail hangs from the element's own bottom edge,
   which is where MapLibre's `anchor: 'bottom'` puts the coordinate — so the
   point of the pin is the place. */
.sr-pin {
  position: relative;
  appearance: none; border: 0; padding: 0;
  width: 30px; height: 30px;
  border-radius: 50%;
  background: var(--purple);
  color: #fff;
  font: inherit; font-size: 12.5px; font-weight: 800;
  display: grid; place-items: center;
  box-shadow: 0 2px 6px rgba(35, 27, 52, .34), 0 0 0 2px #fff;
  cursor: pointer;
  transition: background .15s var(--ease, ease), transform .15s var(--ease, ease);
}
/* A town pin carries a count, which is wider than a rank. */
.sr-pin.is-count { width: auto; min-width: 30px; padding: 0 7px; border-radius: 999px; }
.sr-pin::after {
  content: ""; position: absolute; left: 50%; top: 100%;
  width: 12px; height: 7px; margin-left: -6px;
  background: var(--purple);
  clip-path: polygon(0 0, 100% 0, 50% 100%);
  transition: background .15s var(--ease, ease);
}
.sr-pin:hover, .sr-pin.is-active {
  background: var(--logo-period, #C660B4);
  transform: scale(1.14);
  z-index: 3;
}
.sr-pin:hover::after, .sr-pin.is-active::after { background: var(--logo-period, #C660B4); }
.sr-pin.is-active { box-shadow: 0 3px 12px rgba(35, 27, 52, .45), 0 0 0 2px #fff; }

/* The popup a pin opens. This is the same 16:9 photograph and the same facts
   the card carries, because it is the same listing. */
.maplibregl-popup-content {
  font-family: inherit;
  padding: 14px 16px 15px !important;
  border-radius: 14px !important;
  box-shadow: 0 18px 40px -18px rgba(35, 27, 52, .5) !important;
  max-width: 268px;
}
.sr-pop-town {
  font-size: 11px; font-weight: 800; letter-spacing: .09em;
  text-transform: uppercase; color: var(--purple);
}
.sr-pop-name { margin: 4px 0 0; font-size: 15.5px; font-weight: 700; line-height: 1.28; color: var(--ink-deep); }
.sr-pop-org { margin-top: 3px; font-size: 12.5px; color: var(--muted); }
.sr-pop-facts { margin: 10px 0 0; display: grid; gap: 5px; font-size: 12.5px; color: var(--slate); }
.sr-pop-facts dt { display: inline; font-weight: 700; color: var(--muted); }
.sr-pop-facts dd { display: inline; margin: 0 0 0 5px; }
.sr-pop-go {
  display: inline-block; margin-top: 11px;
  font-size: 13px; font-weight: 700; color: var(--purple);
}
.sr-filters input[aria-invalid="true"] { border-color: #C0392B; }

/* One column, full width: the map is the other half of the page, and a result
   is read top to bottom — picture, rank, then the facts. */
.sr-list {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 14px;
}
.sr-card {
  display: flex; flex-direction: column; align-items: stretch; gap: 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-panel);
  padding: 0;
  overflow: hidden;
  transition: box-shadow .16s var(--ease, ease), border-color .16s var(--ease, ease);
}
.sr-card:hover { border-color: #D8D1EA; box-shadow: 0 10px 26px -18px rgba(35, 27, 52, .5); }
.sr-card { position: relative; }

/* Save, on the search card, in the same place and shape as the guide's. */
.sr-save {
  position: absolute; top: 12px; right: 12px; z-index: 2;
  width: 34px; height: 34px; display: grid; place-items: center;
  border: 1px solid rgba(255,255,255,.7); border-radius: 50%;
  background: rgba(255,255,255,.92); color: var(--muted);
  cursor: pointer; transition: color .15s, background .15s, border-color .15s;
  box-shadow: 0 2px 8px rgba(30,20,50,.12);
}
.sr-save svg { width: 15px; height: 15px; }
.sr-save:hover { color: var(--purple); border-color: #D8CCEE; }
.sr-save.is-saved { background: var(--purple); border-color: var(--purple); color: #fff; }
.sr-save.is-saved svg { fill: currentColor; }
.sr-card.no-thumb .sr-save { top: 10px; right: 10px; }

.sr-badges { display: flex; flex-wrap: wrap; align-items: center; gap: 5px; margin: 0 0 8px; }
.sr-badge {
  display: inline-flex; align-items: center;
  font-size: 10.5px; font-weight: 700; letter-spacing: .02em; line-height: 1.35;
  text-transform: capitalize; color: #5B5268; background: #F3EFF7;
  border-radius: 999px; padding: 3px 8px;
}
.sr-badge-cat { background: var(--purple-tint); color: var(--purple); }
.sr-badge-aid { background: #E8F3EA; color: #2F6B3D; }
.sr-badge-coed { background: #EAF0FA; color: #34527A; }
.sr-badge-girls { background: #FBEAF3; color: #8A2C60; }
.sr-badge-adaptive { background: #FFF2DD; color: #7A5314; }

.sr-desc {
  margin: 8px 0 0; font-size: 13px; line-height: 1.5; color: var(--muted);
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
.sr-term {
  margin: 10px 0 0; font-size: 12.5px; font-weight: 600; color: #3F3550;
  background: #F7F3FB; border-radius: 8px; padding: 7px 10px;
}
.sr-reg { background: #FFF7E8; color: #6B4B12; }
.sr-aid {
  margin: 8px 0 0; font-size: 12.5px; line-height: 1.5; color: #355B3D;
  background: #EEF7F0; border-radius: 8px; padding: 8px 10px;
}
.sr-aid a { color: #2F6B3D; font-weight: 600; }
.sr-review { margin-top: 11px; padding-top: 10px; border-top: 1px solid var(--line); }
.sr-save-toast {
  position: fixed; left: 50%; bottom: 24px; transform: translate(-50%, 16px);
  background: var(--ink); color: #fff; font-size: 13px; font-weight: 600;
  border-radius: 999px; padding: 10px 18px; opacity: 0; pointer-events: none;
  transition: opacity .2s, transform .2s; z-index: 90;
}
.sr-save-toast.is-on { opacity: 1; transform: translate(-50%, 0); }

/* The composer's confirmation. The homepage did not style this element at
   all, so a post that had been sent left the reader with nothing on screen. */
.toast {
  position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%);
  z-index: 120; max-width: min(460px, calc(100vw - 32px));
  padding: 13px 20px; border: 1px solid var(--line); border-radius: 12px;
  background: #fff; color: var(--ink); font-size: 13.5px; font-weight: 600;
  line-height: 1.45; text-align: center;
  box-shadow: 0 16px 44px rgba(40, 27, 58, .18);
}
.toast[hidden] { display: none; }

/* The picture. A card with no photograph has no slot at all, so a listing
   without one is a full-width text card rather than a card with a hole in it.
   Whether there is one is decided before the card is written — see card() in
   search.js — so the list never reflows as pictures arrive.

   Across the top, not down the side. The feed is about 470px wide — the rail
   and the map take the rest of the row — and a card's text is 300px tall, so a
   side column could show a 16:9 picture only 99px of the way down it and left
   the other 200px as blank card. Stretching the picture to the card's height
   instead would have cropped a landscape photograph to a third of its width,
   which is the crop the guides refuse photographs for. Across the top the
   picture keeps its own shape and there is nothing left over. It is also what
   the town guides and the narrow-screen layout already do. */
.sr-thumb {
  flex: none; width: 100%;
  aspect-ratio: 16 / 7;
  max-height: 240px;
  background: var(--paper);
}
.sr-thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }

.sr-card-main { flex: 1 1 auto; min-width: 0; padding: 16px 20px 15px; }
.sr-card-top {
  display: flex; align-items: center; gap: 10px; margin-bottom: 7px;
}
/* The rank, on the card and on the pin, so the two can be read together. */
.sr-rank {
  flex: none;
  min-width: 24px; height: 24px; padding: 0 6px;
  border-radius: 999px;
  background: var(--purple); color: #fff;
  font-size: 12.5px; font-weight: 800;
  display: inline-flex; align-items: center; justify-content: center;
}
.sr-card-top .sr-miles { margin-left: auto; }
.sr-town {
  font-size: 11.5px; font-weight: 700; letter-spacing: .1em;
  text-transform: uppercase; color: var(--purple);
}
.sr-miles { font-size: 12px; color: var(--muted); }
.sr-card h3 { font-size: 17px; line-height: 1.3; }
.sr-org { margin-top: 4px; font-size: 13px; color: var(--muted); }

.sr-why, .sr-caution { list-style: none; margin: 12px 0 0; padding: 0; }
.sr-why li {
  position: relative; padding-left: 20px; margin-bottom: 4px;
  font-size: 13.5px; line-height: 1.45; color: var(--ink);
}
.sr-why li::before {
  content: ""; position: absolute; left: 5px; top: 8px;
  width: 6px; height: 6px; border-radius: 50%; background: var(--purple);
}
.sr-caution li {
  position: relative; padding-left: 20px; margin-bottom: 4px;
  font-size: 12.5px; line-height: 1.45; color: var(--muted);
}
.sr-caution li::before {
  content: ""; position: absolute; left: 4px; top: 7px;
  width: 7px; height: 7px; border-radius: 50%;
  border: 1.5px solid var(--muted);
}
/* The price, on a card whose price could not be compared with the budget. It
   is a fact about the program rather than a reason it matched, so it reads as
   a label: a rule, a unit, no tick. */
.sr-why li.sr-price {
  font-weight: 700; color: var(--purple-dark);
}
.sr-why li.sr-price::before { background: var(--muted); border-radius: 50%; }

/* The line between the programs that fit a budget and the ones whose price
   could not be measured against it. It spans the grid, so it reads as a break
   in the list rather than as another card. */
.sr-group {
  grid-column: 1 / -1;
  margin-top: 10px;
  padding-top: 22px;
  border-top: 2px solid var(--line);
}
.sr-group h3 {
  font-size: 15px; font-weight: 800; letter-spacing: .02em;
  color: var(--ink); margin: 0;
}
.sr-group p {
  margin-top: 6px; max-width: 62ch;
  font-size: 13.5px; line-height: 1.5; color: var(--muted);
}

.sr-facts {
  margin: 14px 0 0; padding-top: 12px;
  border-top: 1px solid var(--line);
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px 16px;
}
.sr-facts dt {
  font-size: 10.5px; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--muted);
}
.sr-facts dd { margin: 3px 0 0; font-size: 13px; line-height: 1.4; }

.sr-card-foot {
  margin-top: 16px; padding-top: 12px;
  border-top: 1px solid var(--line);
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px;
}
.sr-go {
  font-size: 13.5px; font-weight: 700; color: var(--purple);
  text-decoration: none;
}
.sr-go:hover { text-decoration: underline; }
.sr-guide { font-size: 12.5px; color: var(--muted); text-decoration: none; }
.sr-guide:hover { color: var(--purple); }

.sr-empty, .sr-loading {
  grid-column: 1 / -1;
  text-align: center; padding: 40px 20px; color: var(--muted);
}
.sr-empty h3 { font-size: 19px; color: var(--ink); margin-bottom: 8px; }
.sr-empty a { color: var(--purple); }
.sr-more { margin: 26px auto 0; display: block; }
.sr-more[hidden] { display: none; }

/* Two results to a row on a phone, the same as a town guide's cards. The
   search result is a shorter card than the town guide's — no photograph — so
   the facts stack and the footer puts the link under the price. */
/* Below this there is no room for three columns, so the filters become a panel
   the visitor opens. The map keeps its column as long as it can. */
@media (max-width: 1120px) {
  .sr-layout { grid-template-columns: minmax(0, 1fr) minmax(300px, 40%); }
  .sr-head-views { display: flex; }
  .sr-rail { display: none; position: static; }
  .sr-rail.is-open { display: grid; grid-column: 1 / -1; padding-bottom: 4px; }
}
/* And below this there is not room for two, so the map becomes a panel as
   well. It is still built on demand and never on load. */
@media (max-width: 900px) {
  .sr-layout { grid-template-columns: minmax(0, 1fr); gap: 20px; }
  .sr-mapcol { display: none; position: static; }
  .sr-mapcol.is-open { display: grid; order: -1; }
  .sr-map { height: 320px; min-height: 0; }

  /* Two cards to a row on a phone, as a town guide does. The photograph is
     already across the top of every card at every width; on a phone it is a
     full 16:9, because there is no side column to buy the height back from. */
  .sr-list { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  .sr-thumb { aspect-ratio: 16 / 9; }
  .sr-card-main { padding: 12px 13px 12px; }
  .sr-card-top { margin-bottom: 6px; gap: 7px; }
  .sr-rank { min-width: 20px; height: 20px; font-size: 11px; }
  .sr-town { font-size: 10.5px; letter-spacing: .07em; }
  .sr-miles { font-size: 11px; }
  .sr-card h3 { font-size: 14.5px; }
  .sr-org { font-size: 12px; }
  .sr-why li { font-size: 12.5px; padding-left: 16px; }
  .sr-why li::before { left: 3px; top: 7px; width: 6px; height: 6px; }
  .sr-caution li { font-size: 11.5px; padding-left: 16px; }
  .sr-caution li::before { left: 3px; top: 6px; width: 6px; height: 6px; }
  .sr-facts { grid-template-columns: minmax(0, 1fr); gap: 7px; }
  .sr-facts dd { font-size: 12.5px; }
  .sr-card-foot { flex-direction: column; align-items: flex-start; gap: 6px; margin-top: 12px; padding-top: 10px; }
  .sr-go, .sr-guide { font-size: 12.5px; }
}

/* The nav is fixed and 70px tall, so anything scrolled to needs to keep its
   heading clear of it. */
.results, .towns, .scope { scroll-margin-top: 92px; }

/* ==========================================================================
   INFORMATION PAGES
   The program hubs, the parent guides, and the help, provider and policy
   pages. They share one shell — tools/shell.mjs, which builds them in the
   Worker and writes them from tools/make-info-pages.mjs — so they share this
   block too, and pick up the tokens and the footer above.
   ========================================================================== */

.info-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgba(252, 250, 247, .9);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  backdrop-filter: saturate(180%) blur(14px);
  border-bottom: 1px solid var(--line);
}
.info-header-inner {
  min-height: var(--header-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  flex-wrap: wrap;
  padding-block: 10px;
}
.info-brand img { width: 132px; height: auto; display: block; }
/* Seven links, so it wraps rather than overflowing: .info-header-inner already
   puts the nav on its own line on a narrow screen, and without this the row
   itself then ran off the right edge. */
.info-nav {
  display: flex; align-items: center; justify-content: flex-end;
  flex-wrap: wrap; gap: 2px;
}
.info-nav a {
  font-size: 14.5px;
  font-weight: 600;
  color: var(--ink);
  text-decoration: none;
  padding: 10px 12px;
  border-radius: 8px;
  white-space: nowrap;
}
.info-nav a:hover,
.info-nav a:focus-visible { background: var(--purple-tint); color: var(--purple); }
/* FAQs and Contact are the way out of the guide, not two more ways through it,
   so they sit past a rule and carry the lighter weight. */
.info-nav-sep { width: 1px; height: 18px; margin: 0 7px; background: var(--line); }
.info-nav .info-nav-secondary { font-weight: 500; color: var(--muted); }
.info-nav .info-nav-secondary:hover,
.info-nav .info-nav-secondary:focus-visible { color: var(--purple); }

.info-hero { padding: clamp(38px, 4.6vw, 68px) 0 clamp(16px, 2vw, 24px); }
.info-hero h1 { font-size: clamp(29px, 4.4vw, 52px); margin-top: 16px; max-width: 22ch; }
.info-hero-lede {
  margin-top: 18px;
  max-width: 64ch;
  font-size: 17.5px;
  line-height: 1.62;
  color: var(--muted);
}
.info-hero-lede strong { color: var(--ink); font-weight: 700; }

.info-body { padding: clamp(20px, 2.6vw, 36px) 0 clamp(54px, 6vw, 88px); }

/* One rhythm between the blocks a body is made of — prose, a form, a row of
   actions, the source list at the foot of a guide. Each body is written as a
   run of sibling blocks, so any block that leaned on its own top margin for
   space collided with whatever the page happened to put above it: the
   financial-aid guide's source list sat against its buttons because
   .info-actions had a margin above it and none below. */
.info-body > .shell > * + * { margin-top: clamp(30px, 3.6vw, 46px); }

/* Long-form prose. One measure, one rhythm — the pages carry the brief's own
   copy and it should read as an article, not as cards. */
.prose { max-width: 68ch; }
.prose > * + * { margin-top: 18px; }
.prose h2 { font-size: clamp(21px, 2.4vw, 27px); margin-top: clamp(32px, 4vw, 48px); }
.prose h2:first-child { margin-top: 0; }
.prose h3 { font-size: 18px; margin-top: 28px; }
.prose p, .prose li { font-size: 16.5px; line-height: 1.68; }
.prose .lead { font-size: 19px; line-height: 1.6; color: var(--muted); }
.prose ul { display: grid; gap: 10px; }
.prose ul li { position: relative; padding-left: 22px; }
.prose ul li::before {
  content: "";
  position: absolute;
  left: 0; top: .64em;
  width: 8px; height: 8px;
  background: var(--logo-period, #C660B4);
}
.prose a { color: var(--purple); text-decoration: underline; text-underline-offset: 3px; }
.prose a:hover { color: var(--purple-dark); }
.prose .source-line { font-size: 14px; color: var(--muted); }
.prose .callout {
  background: var(--purple-tint);
  border-radius: var(--radius-card);
  padding: 18px 22px;
  font-size: 16px;
}

.info-actions { display: flex; flex-wrap: wrap; gap: 12px; }
.info-actions .btn-quiet { border-color: var(--line); }
.info-cards { display: grid; gap: 16px; }
@media (min-width: 760px) { .info-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.info-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  padding: 20px 22px;
}
.info-card h3 { font-size: 17px; }
.info-card p { margin-top: 8px; font-size: 15px; color: var(--muted); line-height: 1.6; }

/* ---------- FAQ ---------- */
/* The first <details> in the repo. There was no accordion to reuse, and the
   nav panels' button + aria-expanded idiom would have meant a script for what
   the element already does. Answers are in the markup, not fetched. */
.faq-list { max-width: 76ch; display: grid; gap: 10px; }
.faq-list details {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
}
.faq-list details[open] { border-color: var(--purple); }
.faq-list summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: flex-start;
  gap: 14px;
  padding: 16px 20px;
  font-size: 16.5px;
  font-weight: 700;
  color: var(--ink);
}
.faq-list summary::-webkit-details-marker { display: none; }
.faq-list summary::after {
  content: "+";
  margin-left: auto;
  color: var(--purple);
  font-size: 20px;
  line-height: 1.1;
}
.faq-list details[open] summary::after { content: "\2013"; }
.faq-list summary:hover { color: var(--purple); }
.faq-list .faq-a { padding: 0 20px 20px; color: var(--muted); }
.faq-list .faq-a p { font-size: 16px; line-height: 1.66; }
.faq-list .faq-a a { color: var(--purple); text-decoration: underline; text-underline-offset: 3px; }

/* ---------- intake forms ---------- */
.form-card {
  max-width: 680px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-panel);
  padding: clamp(20px, 3vw, 34px);
}
.form-field { display: grid; gap: 6px; margin-top: 18px; }
.form-field:first-of-type { margin-top: 0; }
.form-field label { font-size: 14.5px; font-weight: 700; color: var(--ink); }
.form-field .hint { font-size: 13px; font-weight: 400; color: var(--muted); }
.form-field input,
.form-field select,
.form-field textarea {
  font: inherit;
  font-size: 15.5px;
  width: 100%;
  padding: 12px 14px;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 10px;
}
.form-field textarea { min-height: 140px; resize: vertical; }
.form-field :is(input, select, textarea):focus-visible {
  outline: none;
  border-color: var(--purple);
  box-shadow: 0 0 0 3px var(--purple-tint);
}
.form-actions { margin-top: 26px; display: flex; flex-wrap: wrap; align-items: center; gap: 14px; }
.form-note { margin-top: 18px; font-size: 13.5px; color: var(--muted); }
/* Only ever rendered when the form actually went somewhere: the pages read
   ?sent=1, which Web3Forms appends nothing to — it redirects, and the redirect
   target carries it. A submission that fails never reaches this page. */
.form-sent {
  max-width: 680px;
  padding: 16px 20px;
  background: var(--purple-tint);
  border: 1px solid var(--purple);
  border-radius: var(--radius-card);
}
.form-sent strong { color: var(--purple-dark); }
.form-sent p { margin-top: 4px; font-size: 15px; color: var(--ink); }

/* The same panel when the submission did not arrive. The provider pilot form
   is the only one that can fail in front of the reader — the others redirect —
   and a failure has to look like one without relying on color alone, hence
   the heading the script sets and the border. */
.form-sent.is-problem { background: #FCEFEF; border-color: #A3262C; }
.form-sent.is-problem strong { color: #8A1F24; }
.form-sent.is-problem a { color: #8A1F24; text-decoration: underline; text-underline-offset: 3px; }

/* The honeypot on the provider forms. Web3Forms discards any submission whose
   `botcheck` is set, and a bot has to be able to reach the field to set it —
   so it is moved out of view rather than display:none, which a chunk of them
   skip. It is out of the tab order and hidden from assistive technology in the
   markup. */
.yb-hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* ---------- program hubs ---------- */
.hub-switch { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding-top: 6px; }
.hub-switch-label {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
  margin-right: 6px;
}
.hub-switch-link {
  font-size: 14px;
  font-weight: 600;
  padding: 8px 15px;
  border: 1px solid var(--line);
  border-radius: var(--radius-chip);
  background: var(--surface);
  color: var(--ink);
  text-decoration: none;
}
.hub-switch-link:hover { border-color: var(--purple); color: var(--purple); }
.hub-switch-link[aria-current="page"] { background: var(--purple); border-color: var(--purple); color: #fff; }

.hub-filter { margin-top: 28px; display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.hub-filter label {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
}
.hub-filter input {
  font: inherit;
  font-size: 15px;
  min-width: 240px;
  padding: 10px 16px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-chip);
}
.hub-filter input:focus-visible { outline: none; border-color: var(--purple); box-shadow: 0 0 0 3px var(--purple-tint); }
.hub-filter-count { font-size: 13.5px; color: var(--muted); }

.hub-towns { margin-top: 24px; display: grid; gap: 14px; }
@media (min-width: 900px) { .hub-towns { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.hub-town {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  padding: 20px 22px 18px;
}
.hub-town h2 { font-size: 20px; }
.hub-town h2 a { color: var(--ink); text-decoration: none; }
.hub-town h2 a:hover { color: var(--purple); text-decoration: underline; text-underline-offset: 3px; }
.hub-count { margin-top: 3px; font-size: 13px; color: var(--muted); }
.hub-list { margin-top: 14px; display: grid; gap: 12px; }
.hub-list li { display: grid; gap: 3px; border-top: 1px solid var(--line); padding-top: 12px; }
.hub-list li:first-child { border-top: 0; padding-top: 0; }
.hub-name { font-size: 15.5px; font-weight: 700; }
.hub-name a { color: var(--purple-dark); text-decoration: none; }
.hub-name a:hover { text-decoration: underline; text-underline-offset: 3px; }
.hub-org, .hub-facts { font-size: 13.5px; color: var(--muted); line-height: 1.5; }
/* The aid badge, on the hub pages. It is defined inline on the town guides,
   which carry their own stylesheet; these pages link this one, and a parent
   meeting "Aid available" on a hub must see the same mark the guide shows. */
.badge-aid {
  display: inline-block; padding: 2px 8px; border-radius: 6px;
  background: #0f766e; color: #fff; font-size: 11px; font-weight: 800;
  letter-spacing: .04em; text-transform: uppercase; vertical-align: 1px;
}
.hub-aid { display: inline-block; margin-top: 4px; font-size: 13.5px; color: #0b5c56; }
.hub-more { margin-top: 14px; font-size: 14px; font-weight: 600; }
.hub-more a { color: var(--purple); text-decoration: none; }
.hub-more a:hover { text-decoration: underline; text-underline-offset: 3px; }
.hub-note { margin-top: 30px; max-width: 78ch; font-size: 14.5px; line-height: 1.62; color: var(--muted); }
.hub-note a { color: var(--purple); }
.hub-town[hidden] { display: none; }

/* ---------- the human sitemap ---------- */
.sitemap-group h2 { font-size: 15px; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.sitemap-group ul {
  margin-top: 14px;
  display: grid;
  gap: 8px 22px;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
}
.sitemap-group a { color: var(--ink); text-decoration: none; font-size: 15px; }
.sitemap-group a:hover { color: var(--purple); text-decoration: underline; text-underline-offset: 3px; }

@media (max-width: 560px) {
  .info-nav a { padding: 9px 9px; font-size: 14px; }
  .hub-filter input { min-width: 0; width: 100%; }
}

/* ==========================================================================
   THE OPENING SCREEN
   --------------------------------------------------------------------------
   The first screen is the whole pitch: what Youthby is, that it covers the
   state, what one guide actually holds, and the box to search it with. It
   used to spend that screen on a headline, a line of prose, the search box
   and a shortcut down to the map — so the map, the thing the site is for,
   began below the fold.

   The order is now headline, map, card, search, and all four have to land
   inside about 900px or the search box drops off a laptop screen. That budget
   is the whole of the design below: it is why the headline is one line rather
   than two, why the map is capped instead of run to the shell's full width,
   and why the card is pulled back up over the empty quarter of the canvas
   rather than standing under it.

   A phone keeps the order it had — the search box before the map — and none
   of this applies to it.
   ========================================================================== */
.towns-list {
  /* This is the padding .towns used to give the A–Z index and the credits that
     now sit in their own section below the fold. */
  padding: 0 0 clamp(30px, 4vw, 56px);
}

@media (min-width: 1024px) {
  /* The copy block sits down in the band rather than at its top edge: the
     photograph is washed at the sides and quiet in the middle, and a headline
     hung off the top of that reads as though it were falling out of the
     navigation. The gap above is what makes the middle of the picture feel
     like a place the page decided to put the words. */
  .hero { padding: clamp(26px, 4.4vh, 52px) 0 6px; }
  .hero-title { margin-top: 16px; }

  .towns.map-band { padding-top: 0; padding-bottom: clamp(28px, 3vw, 44px); }
  .map-bar { margin: 14px 0 8px; padding-top: 12px; }

  /* The map takes what is left of the screen rather than a fixed number,
     because the point of the composition is that the search box is on the
     first screen at every desktop height. 392px is the strip, the header, the
     eyebrow, the headline, the category row, the legend, the town card and the
     search box; it was 362 until the hero copy sat lower in its band and the
     headline grew to 62px, which cost the top of the page 30px and would
     otherwise have come out of the fold rather than out of the map. The canvas
     is 1.946 times as wide as it is tall. A 900px window gives it 508 — the
     full 1320 — and a 768px one 400, floored so the drawing keeps its labels
     above 10px.
     The constant covers the search box and the legend, not the map's own
     bottom edge: the last slice of the canvas is the ocean south of the Cape
     and the scale bar, and it runs a little past the fold rather than holding
     the drawing down to the size of the shortest window. */
  .towns.map-band {
    --map-h: clamp(400px, calc(100vh - 392px), 640px);
    --map-w: min(calc(var(--map-h) * 1.946), calc(100vw - 48px));
  }
  /* The map is the widest thing on the page and the column is not, so it is
     centered on the shell's own center line rather than held inside the shell's
     padding — 1245px at the cap against a 1176px column, which is the width
     the drawing needs to carry its 66 labels. The 100vw cap on --map-w is what
     keeps that from walking a narrow desktop sideways. */
  .map-main, .map-foot {
    position: relative;
    left: 50%;
    width: var(--map-w);
    margin-left: calc(var(--map-w) / -2);
    margin-right: 0;
  }
  /* Back up over the canvas: the state's ink stops well above its bottom-left
     corner — everything down there is the ocean south of Connecticut — so the
     card costs the composition nothing where it is.
     A share of the map rather than a fixed number of pixels, because the map
     is not the only thing on this screen that is fixed: the card is, and it
     has to keep its place in the drawing (and above the fold) as the drawing
     grows. 0.37 puts its top edge just under the ink at every map height. */
  /* The card floats over the water and takes up no room in the flow. It used
     to sit in it with a negative top margin, which meant its own height was
     part of the section's height — so a card with a longer name, or a town
     with a longer count beside it, grew the section and pushed the A–Z index
     down into the map. Empty, the section is the drawing, and the index below
     starts under the blue whatever the card says. */
  .map-foot { margin-top: 0; height: 0; }
  /* Set in from the map's left edge, where the drawing is all ocean: the card
     used to sit flush against it and read as though it had fallen off the
     page. A share of the map rather than a fixed inset, because the state is
     drawn to the same proportions at every map height, so the water the card
     floats in is the same water. The top is the 0.37 of the map the negative
     margin used to hold it at. */
  .map-foot .map-card {
    position: absolute;
    top: calc(var(--map-h) * -0.37);
    left: calc(var(--map-w) * 0.058);
    /* An absolute box is content-sized, and a grid item was not: without this
       the card would take the width of whatever town it happened to name, and
       it would jump as the pointer crossed the map. 430px is what it was. */
    width: 430px;
    max-width: 430px;
  }

  /* Kept in the document — a phone still opens on it — but the desktop has the
     card to say what a guide holds and no room to say it twice. */
  .map-example { display: none; }
  .map-inset-note { display: none; }

  /* The search now sits between the headline and the map, so the tail is
     spaced for that: a short gap under the headline, and enough under the card
     that the map bar's hairline reads as a separator rather than as an
     underline on the button above it. */
  .hero-tail { padding: 2px 0 4px; }
  /* The pill carries its own padding now; the form is only the wrapper. The
     category row and the search box read as one thing, so they stay close. */
  .finder { margin-top: 5px; }
}

/* The signed-in account control and its menu, shared with the programs pages. */
/* The signed-in account control and its menu. */
.nav-account{position:relative}
.nav-account-button{position:relative;display:inline-flex;align-items:center;justify-content:center;gap:9px;font:inherit;font-size:14px;font-weight:700;color:var(--ink);background:none;border:1px solid var(--line);border-radius:999px;padding:4px;cursor:pointer}
.nav-account-button:hover{border-color:#c9b3e0;background:var(--purple-tint)}
.nav-account-avatar{width:32px;height:32px;border-radius:50%;object-fit:cover;background:#F2EAFA;color:#5929A7;display:inline-flex;align-items:center;justify-content:center;font-size:13px;font-weight:800;flex:none}
.nav-account-name{max-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.nav-account-head a.nav-account-who{display:block;color:inherit;text-decoration:none}
.nav-account-caret{width:0;height:0;border-left:4px solid transparent;border-right:4px solid transparent;border-top:5px solid currentColor;opacity:.6}
.nav-account-button::after{content:attr(data-name);position:absolute;top:calc(100% + 8px);right:0;z-index:75;background:var(--ink);color:#fff;font-size:12px;font-weight:600;padding:6px 10px;border-radius:8px;white-space:nowrap;opacity:0;visibility:hidden;transform:translateY(-3px);transition:opacity .15s,transform .15s,visibility .15s;pointer-events:none;box-shadow:0 8px 20px rgba(35,27,52,.25)}
.nav-account-button:hover::after,.nav-account-button:focus-visible::after{opacity:1;visibility:visible;transform:none}
.nav-account-button[aria-expanded="true"]::after{opacity:0;visibility:hidden}
.verified-mark{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;margin-left:5px;color:var(--purple);flex:none;vertical-align:middle;transform:translateY(-1px)}
.verified-mark svg{width:100%;height:100%;display:block}
.nav-account-menu{position:absolute;right:0;top:calc(100% + 30px);z-index:70;width:280px;background:var(--white);border:1px solid var(--line);border-radius:16px;box-shadow:0 24px 60px -28px rgba(35,27,52,.55);padding:8px;text-align:left}
.nav-account-menu[hidden]{display:none}
.nav-account-head{padding:12px 12px 10px;border-bottom:1px solid var(--line);margin-bottom:6px}
.nav-account-head strong{display:flex;align-items:center;font-size:15px}
.nav-account-head span{display:block;font-size:12.5px;color:var(--muted);margin-top:2px;overflow:hidden;text-overflow:ellipsis}
.nav-account-stats{display:flex;gap:8px;margin-top:10px}
.nav-account-stat{flex:1;display:block;background:var(--tint);border-radius:10px;padding:7px 8px;text-align:center;color:inherit;text-decoration:none}
.nav-account-stat b{display:block;font-size:15px;color:var(--purple)}
.nav-account-stat small{display:block;font-size:10px;color:var(--muted);letter-spacing:.02em}
.nav-account-menu > a,.nav-account-menu button.nav-account-item{display:flex;align-items:center;gap:10px;width:100%;padding:9px 12px;border-radius:9px;font:inherit;font-size:13.5px;font-weight:600;color:var(--ink);text-decoration:none;background:none;border:0;cursor:pointer;text-align:left}
.nav-account-menu > a:hover,.nav-account-menu button.nav-account-item:hover{background:var(--purple-tint);color:var(--purple)}
.nav-account-menu .icon{width:17px;height:17px;flex:none;opacity:.75}
.nav-account-count{margin-left:auto;font-size:11.5px;font-weight:800;color:var(--purple);background:var(--purple-tint);border-radius:999px;padding:1px 7px}
.nav-account-sep{height:1px;background:var(--line);margin:6px 8px}
.nav-account-signout{color:#8a3b3b}
.nav-account-signout:hover{background:#fbeaea;color:#7a2f2f}


@media (max-width:1120px){
  .nav-account-button{justify-content:center;padding:6px;margin-top:8px}
  .nav-account-avatar{width:40px;height:40px;font-size:15px}
  .nav-account-menu{position:static;width:100%;box-shadow:none;border:1px solid var(--line);margin-top:8px}
}
.sr-card h3 a{color:inherit;text-decoration:none}
.sr-card h3 a:hover{color:var(--purple)}
.sr-suggest{display:inline-flex;align-items:center;gap:5px;font-size:11.5px;font-weight:700;color:var(--purple);background:var(--tint);border:1px solid #e4d9f0;border-radius:999px;padding:6px 10px;margin-right:auto;text-decoration:none;white-space:nowrap;line-height:1}
.sr-suggest:hover{background:#e9ddf7;color:var(--deep);text-decoration:none}

.signin-apple-mark{width:18px;height:18px;flex:none}
.signin-apple{gap:9px}
.signin-switch {
  margin: 2px 0 0;
  padding: 4px 2px;
  border: 0;
  background: none;
  color: var(--purple);
  font: inherit;
  font-size: 13px;
  font-weight: 700;
  text-align: left;
  cursor: pointer;
}
.signin-switch:hover { text-decoration: underline; }

/* The confirmation step after creating an account: the form and the identity
   buttons are gone, and this is the whole of the dialog. */
.signin-confirm { padding: 2px 0 0; }
.signin-confirm-title { margin: 0 0 8px; font-size: 17px; letter-spacing: -.01em; }
.signin-confirm-text { margin: 0 0 16px; font-size: 13.5px; line-height: 1.6; color: var(--muted, #6E6977); }
.signin-confirm-text strong { color: var(--ink, #231B34); }
.signin-confirm .signin-continue { width: 100%; }
.signin-confirm .signin-switch { display: block; margin-top: 10px; }
.signin-confirm[hidden] { display: none; }
.signin-email[hidden], .signin-or[hidden], .signin-provider[hidden], .signin-legal[hidden], .signin-google-slot[hidden] { display: none; }

/* --------------------------------------------------------------------------
   WHAT'S NEW, ON A PHONE
   Replaces the illustrated strip at the same place on the page, so a parent
   scrolling a phone meets the next few local dates rather than a diagram.
   -------------------------------------------------------------------------- */
.home-feed { display: none; }
@media (max-width: 899px) {
  body.has-home-feed .strip { display: none; }
  .home-feed { display: block; padding: 30px 0 8px; }
  .home-feed-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; margin-bottom: 14px; }
  .home-feed-head .eyebrow { margin-bottom: 8px; }
  .home-feed-head h2 { font-size: 27px; letter-spacing: -.045em; }
  .home-feed-more { flex: none; font-size: 12.5px; font-weight: 700; color: var(--purple); text-decoration: underline; text-underline-offset: 3px; }
  .home-feed-list { display: grid; gap: 10px; }
  .home-feed-card { display: grid; grid-template-columns: 92px minmax(0, 1fr); gap: 12px; align-items: center; border: 1px solid var(--line); border-radius: 14px; background: #fff; padding: 10px; text-decoration: none; color: inherit; }
  .home-feed-card img { width: 92px; height: 78px; object-fit: cover; border-radius: 10px; display: block; }
  .home-feed-card .home-feed-kicker { display: inline-flex; align-items: center; font-size: 9.5px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--purple); }
  .home-feed-card h3 { margin: 3px 0 0; font-size: 15px; line-height: 1.25; letter-spacing: -.02em; }
  .home-feed-card p { margin: 3px 0 0; font-size: 11.5px; color: var(--muted); }
  .home-feed-card .home-feed-when { font-weight: 700; color: var(--ink); }
  .home-feed-all { display: flex; align-items: center; justify-content: center; min-height: 46px; margin-top: 12px; border: 1px solid var(--purple); border-radius: 999px; color: var(--purple); font-size: 13.5px; font-weight: 700; text-decoration: none; }
  .home-feed-all:hover { background: var(--purple); color: #fff; }
}
@media (max-width: 899px) {
  .home-feed-card.no-photo { grid-template-columns: minmax(0, 1fr); }
}

/* The What's new section is not phone-only any more: the composer and a few
   dated items sit below the guide strip on a wide screen too. It carries the
   rose ground that used to sit under the town guides. */
.home-feed { display: block; padding: 34px 0 12px; background: linear-gradient(180deg, #FDF1F6 0%, #FBE7F0 55%, #FDF1F6 100%); }
/* The composer and the first card were touching: the feed read as part of the
   post box. They are two different things, so they get their own air. */
.home-feed-composer { margin-bottom: 16px; }
.home-feed-list { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
@media (max-width: 899px) {
  .home-feed-list { grid-template-columns: 1fr; }
}
/* The photograph is a window: the ribbon sits inside it and the picture
   warms up under the pointer, which is the whole invitation. */
.home-feed-card .home-feed-photo { position: relative; display: block; width: 92px; height: 78px; border-radius: 10px; overflow: hidden; flex: none; }
.home-feed-card .home-feed-photo img { width: 100%; height: 100%; object-fit: cover; border-radius: 0; display: block; transition: transform .35s ease; }
.home-feed-card { transition: transform .16s ease, box-shadow .16s ease, border-color .16s ease; text-align: left; }
/* The strip's section centers its heading; the cards inside it are left
   aligned, with the text column free to shrink so a long provider name wraps
   instead of pushing the photograph out of the row. */
.home-feed-card > div { min-width: 0; }
.home-feed-card .home-feed-kicker { text-align: left; }
.home-feed-card:hover { transform: translateY(-1px); border-color: #D9C4EA; box-shadow: 0 14px 28px -20px rgba(35,27,52,.55); }
.home-feed-card:hover .home-feed-photo img { transform: scale(1.05); }
.home-feed-ribbon { position: absolute; left: 6px; top: 6px; padding: 2px 7px; border-radius: 999px; background: linear-gradient(135deg, #C660B4 0%, #7C4DBF 100%); color: #fff; font-size: 9px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; box-shadow: 0 4px 10px rgba(35,27,52,.28); }
/* "New to the guide" is the one badge that is an invitation rather than a
   fact: it gets the sparkle and the warm gradient. */
.home-feed-card .home-feed-kicker.is-new { background: linear-gradient(135deg, #F9DCEB 0%, #E8D8FF 100%); color: #7A2154; gap: 5px; box-shadow: inset 0 0 0 1px rgba(198,96,180,.25); }
.home-feed-card .home-feed-kicker.is-new::before { content: "\2726"; font-size: 11px; line-height: 1; }
/* The four reasons to tap read differently at a glance: a deadline is warm,
   an opening is green, a review is amber. Without that, six cards all read as
   "a program" and the mix the strip is making invisible. */
.home-feed-card .home-feed-kicker.is-deadline { color: #A33223; }
.home-feed-card .home-feed-kicker.is-opening { color: #286B3D; }
.home-feed-card .home-feed-kicker.is-starts { color: #2B5B8A; }
.home-feed-card .home-feed-kicker.is-review { color: #8A5A12; }
.home-feed-card .home-feed-stars { margin-top: 2px; color: #B7791F; font-size: 12.5px; letter-spacing: .08em; }
.home-feed-card.is-review { border-color: #EBDCC8; }
/* The card rules were written for the phone version only, so on a wide screen
   the pictures fell back to their natural size and the cards lost their
   boxes. The same card, a little larger, at both widths. */
@media (min-width: 900px) {
  .home-feed-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; margin-bottom: 14px; }
  .home-feed-head .eyebrow { margin-bottom: 8px; }
  .home-feed-head h2 { font-size: 32px; letter-spacing: -.045em; }
  .home-feed-more { flex: none; font-size: 13px; font-weight: 700; color: var(--purple); text-decoration: underline; text-underline-offset: 3px; }
  .home-feed-card { display: grid; grid-template-columns: 116px minmax(0, 1fr); gap: 14px; align-items: center; border: 1px solid var(--line); border-radius: 16px; background: #fff; padding: 12px; text-decoration: none; color: inherit; }
  .home-feed-card img { width: 116px; height: 96px; object-fit: cover; border-radius: 11px; display: block; }
  .home-feed-card .home-feed-photo { width: 116px; height: 96px; border-radius: 11px; }
  .home-feed-card.no-photo { grid-template-columns: minmax(0, 1fr); }
  .home-feed-card .home-feed-kicker { display: inline-flex; align-items: center; padding: 3px 9px; border-radius: 999px; background: var(--tint); font-size: 10px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--purple); }
  .home-feed-card h3 { margin: 4px 0 0; font-size: 16.5px; line-height: 1.25; letter-spacing: -.02em; }
  .home-feed-card p { margin: 4px 0 0; font-size: 12.5px; color: var(--muted); }
  .home-feed-card .home-feed-when { font-weight: 700; color: var(--ink); }
  .home-feed-all { display: flex; align-items: center; justify-content: center; min-height: 46px; margin-top: 14px; border: 1px solid var(--purple); border-radius: 999px; color: var(--purple); font-size: 13.5px; font-weight: 700; text-decoration: none; }
  .home-feed-all:hover { background: var(--purple); color: #fff; }
}

/* --------------------------------------------------------------------------
   THE COMPOSER
   A short post from a parent, opened from What's new. The panel keeps the
   familiar shape — author, audience, words, comment setting — and returns the
   reader to the same scroll position when it closes.
   -------------------------------------------------------------------------- */
.composer{background:var(--white);border:1px solid var(--line);border-radius:16px;padding:14px}
.composer-top{display:flex;align-items:center;gap:12px}
.composer-avatar,.composer-avatar-lg{border-radius:50%;background:#F2EAFA;color:#5929A7;display:inline-flex;align-items:center;justify-content:center;font-weight:800;flex:none;object-fit:cover}
.composer-avatar{width:40px;height:40px;font-size:14px}
.composer-avatar-lg{width:46px;height:46px;font-size:16px}
.composer-start{flex:1;min-height:46px;padding:0 18px;text-align:left;border:1px solid var(--line);border-radius:999px;background:var(--paper);color:var(--muted);font:inherit;font-size:14px;font-weight:600;cursor:pointer}
.composer-start:hover{border-color:var(--purple);color:var(--purple)}

.composer-dialog{position:fixed;inset:0;margin:auto;width:min(560px,calc(100vw - 24px));height:max-content;max-height:calc(100vh - 24px);overflow:auto;padding:0;border:0;border-radius:18px;background:var(--white);color:var(--ink);box-shadow:0 30px 80px rgba(31,20,45,.34)}
.composer-dialog:not([open]){display:none}
.composer-dialog::backdrop{background:rgba(31,20,45,.32);-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}
.composer-panel{position:relative;padding:22px 24px 20px}
.composer-close{position:absolute;top:10px;right:12px;width:36px;height:36px;border-radius:50%;background:none;color:var(--muted);font-size:24px;line-height:1;cursor:pointer}
.composer-close:hover{background:var(--tint);color:var(--ink)}
.composer-title{font-size:19px;letter-spacing:-.02em;margin:0 36px 16px 0}
.composer-author{display:flex;align-items:center;gap:12px;margin-bottom:14px}
.composer-author strong{display:block;font-size:15px}
.composer-author span{font-size:12px;color:var(--muted)}
.composer-body{width:100%;min-height:132px;padding:0;border:0;background:none;color:var(--ink);font:inherit;font-size:16.5px;line-height:1.55;resize:vertical}
.composer-body:focus{outline:none}
.composer-body::placeholder{color:#9A93A4}
.composer-link{display:flex;align-items:center;gap:9px;margin:6px 0 0;padding:9px 12px;border:1px solid var(--line);border-radius:11px;background:var(--paper)}
.composer-link svg{width:17px;height:17px;flex:none;color:var(--muted)}
.composer-link input{flex:1;min-width:0;border:0;background:none;color:var(--ink);font:inherit;font-size:13.5px}
.composer-link input:focus{outline:none}
.composer-rule{margin:12px 0 0;padding:10px 12px;border-radius:10px;background:var(--tint);color:#51435f;font-size:12.5px;line-height:1.5}
.composer-rule strong{color:var(--ink);font-weight:700}
.composer-note{margin:8px 0 0;padding:9px 11px;border-radius:9px;background:#fbeaea;color:#7a2f2f;font-size:12.5px;line-height:1.5}
.composer-foot{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:14px}
.composer-count{font-size:11.5px;color:var(--muted)}
.composer-post{min-height:44px;padding:0 20px;border:0;border-radius:999px;background:var(--purple);color:#fff;font:inherit;font-size:13.5px;font-weight:700;cursor:pointer}
.composer-post:hover{background:var(--deep)}
.composer-post:disabled{opacity:.45;cursor:default}
@media(max-width:520px){.composer-panel{padding:18px 16px 16px}.composer-body{min-height:120px;font-size:16px}.composer-post{padding:0 16px}}

/* A parent's post in the feed. */
.feed-card.is-post{cursor:default}
.post-head{display:flex;align-items:center;gap:10px;margin-bottom:10px}
.post-avatar{width:38px;height:38px;border-radius:50%;background:#F2EAFA;color:#5929A7;display:inline-flex;align-items:center;justify-content:center;font-size:13px;font-weight:800;flex:none;object-fit:cover}
.post-head strong{display:block;font-size:14px}
.post-head span{display:block;font-size:11.5px;color:var(--muted)}
.composer-photos{display:flex;align-items:center;gap:10px;margin-top:10px}
.composer-photo-add{display:inline-flex;align-items:center;gap:7px;padding:8px 12px;border:1px solid var(--line);border-radius:10px;background:var(--paper);color:var(--muted);font:inherit;font-size:12.5px;font-weight:700;cursor:pointer}
.composer-photo-add:hover{border-color:var(--purple);color:var(--purple)}
.composer-photo-add[hidden]{display:none}
.composer-photo-add svg{width:17px;height:17px;flex:none}
.composer-photo-hint{font-size:11.5px;color:var(--muted)}
.composer-previews{display:flex;gap:8px;margin-top:10px}
.composer-previews:empty{display:none}
.composer-preview{position:relative;width:84px;height:84px;border-radius:10px;overflow:hidden;border:1px solid var(--line);flex:none}
.composer-preview img{width:100%;height:100%;object-fit:cover;display:block}
.composer-preview button{position:absolute;top:3px;right:3px;width:22px;height:22px;border:0;border-radius:50%;background:rgba(35,27,52,.72);color:#fff;font-size:15px;line-height:1;cursor:pointer}
.level-badge{display:inline-block;width:22px;height:22px;object-fit:contain;vertical-align:-5px;margin-left:4px}
.account-profile h2 .level-badge{width:34px;height:34px;vertical-align:middle}
.post-head .level-badge{width:22px;height:22px}
.post-images{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;margin-top:10px}
.post-images.one{grid-template-columns:1fr}
.post-images a{display:block;border-radius:10px;overflow:hidden;background:var(--tint)}
.post-images img{display:block;width:100%;height:120px;object-fit:cover}
.post-images.one img{height:auto;max-height:320px}
.post-head .guide-level-badge{display:inline-flex;align-items:center;font-size:9.5px;font-weight:800;letter-spacing:.04em;text-transform:uppercase;border-radius:999px;padding:2px 7px;margin-left:4px;background:var(--tint);color:var(--purple);vertical-align:middle;white-space:nowrap}
.post-link{display:inline-block;margin-top:10px;padding:7px 11px;border:1px solid var(--line);border-radius:9px;background:var(--paper);font-size:12.5px;font-weight:700;color:var(--purple);text-decoration:none;overflow-wrap:anywhere}
.post-link:hover{border-color:var(--purple)}
.post-body{margin:0;font-size:15px;line-height:1.6;color:#3B3446;white-space:pre-wrap}
.post-foot{display:flex;gap:12px;align-items:center;margin-top:12px;padding-top:10px;border-top:1px solid var(--line)}
.home-feed-post{border:1px solid var(--line);border-radius:14px;background:#fff;padding:14px;grid-column:1/-1}
.home-feed-post .post-body{font-size:14px}
.guide-level-badge{display:inline-flex;align-items:center;font-size:10.5px;font-weight:800;letter-spacing:.04em;text-transform:uppercase;border-radius:999px;padding:3px 9px;background:var(--tint);color:var(--purple);vertical-align:middle;white-space:nowrap}

.sr-suggest{display:inline-flex;align-items:center;gap:5px}
.sr-suggest svg{width:12px;height:12px;flex:none}
.home-feed-empty{margin:0;padding:16px 2px;font-size:13.5px;color:var(--muted)}
.home-feed-empty a{color:var(--purple);font-weight:700;text-decoration:underline;text-underline-offset:3px}
.home-feed-kicker{display:inline-flex;align-items:center;padding:3px 9px;border-radius:999px;background:var(--tint);color:var(--purple);font-size:10px;font-weight:800;letter-spacing:.07em;text-transform:uppercase}
.home-feed-kicker.is-deadline{background:#fde7e4;color:#a33223}
.home-feed-kicker.is-opening{background:#e4f2e6;color:#286b3d}
.home-feed-kicker.is-new{background:var(--tint);color:var(--purple)}

/* One header, one set of boxes: the utility row must not change size between
   the homepage and the program pages. */
@media (min-width: 1121px) {
  .home-header .nav-providers, .home-header .nav-calendar {
    display: inline-flex; align-items: center; height: 44px; padding: 0 6px; line-height: 1;
  }
  .home-header .nav-signin {
    display: inline-flex; align-items: center; justify-content: center;
    height: 44px; padding: 0 20px; line-height: 1;
  }
}

@media (min-width: 1121px) {
  .site-header .nav-providers, .site-header .nav-calendar {
    display: inline-flex; align-items: center; height: 44px; padding: 0 6px; line-height: 1;
    font-family: "DM Sans", sans-serif;
  }
  .site-header .nav-signin {
    display: inline-flex; align-items: center; justify-content: center;
    height: 44px; padding: 0 20px; line-height: 1; font-family: "DM Sans", sans-serif;
  }
  .site-header .nav-link { height: 44px; }
}

/* The returning-family band. Quiet, because it sits above the hero and its
   job is to answer "what did I keep?" in one line. */
.return-band{background:var(--tint);border-bottom:1px solid #e0d4ef}
.return-band[hidden]{display:none}
.return-band-inner{display:flex;flex-wrap:wrap;align-items:baseline;gap:8px 18px;max-width:var(--shell);margin:0 auto;padding:12px var(--gutter)}
.return-band p{margin:0;font-size:13px;color:var(--ink)}
.return-count{font-weight:700}
.return-count strong{color:var(--purple)}
.return-count a{color:var(--purple);font-weight:700;text-decoration:underline;text-underline-offset:3px}
.return-line{color:var(--ink)}
.return-note{color:var(--muted);font-size:12px;flex-basis:100%}
@media(max-width:640px){.return-band-inner{padding:10px var(--gutter);gap:4px 12px}.return-note{font-size:11.5px}}

/* The saved shortlist, beside the calendar: a parent who has saved something
   should not have to remember it exists. */
.nav-saved{display:inline-flex;align-items:center;gap:6px;font-size:15px;font-weight:600;color:var(--ink);text-decoration:none;padding:10px;border-radius:8px;white-space:nowrap}
.nav-saved::before{content:"";width:16px;height:16px;flex:none;background:currentColor;-webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20.8 4.6a5.5 5.5 0 0 0-7.8 0L12 5.7l-1.1-1.1a5.5 5.5 0 0 0-7.8 7.8l1.1 1.1L12 21l7.8-7.6 1-1.1a5.5 5.5 0 0 0 0-7.8z'/%3E%3C/svg%3E") center/contain no-repeat;mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20.8 4.6a5.5 5.5 0 0 0-7.8 0L12 5.7l-1.1-1.1a5.5 5.5 0 0 0-7.8 7.8l1.1 1.1L12 21l7.8-7.6 1-1.1a5.5 5.5 0 0 0 0-7.8z'/%3E%3C/svg%3E") center/contain no-repeat}
.nav-saved:hover{color:var(--purple)}
.nav-saved[hidden]{display:none}
.nav-saved-count{display:inline-flex;align-items:center;justify-content:center;min-width:22px;height:20px;padding:0 6px;border-radius:999px;background:var(--tint);color:var(--purple);font-size:11.5px;font-weight:800}
@media (min-width:1121px){.nav-saved{height:44px}}
/* In the phone drawer Saved is a row like the five links and For Providers:
   same type, same height, same separator. `:not([hidden])` keeps the
   `[hidden]` rule above in charge when there is no shortlist to show. */
@media (max-width:1120px){
  .main-nav .nav-saved:not([hidden]){display:flex;align-items:center;gap:10px;font-size:18px;font-weight:600;padding:16px 2px;border-radius:0;border-bottom:1px solid var(--line)}
  .main-nav .nav-saved::before{width:18px;height:18px}
  .main-nav .nav-saved-count{margin-left:auto}
}

/* The utility group sits a touch further right so it reads as one cluster with
   the login, and the login keeps one fixed width so the webfont settling can
   never nudge the links beside it. */
@media (min-width:1121px){
  .site-header .nav-utility,.home-header .nav-utility{margin-right:-6px}
}

/* My Calendar is a personal page and lives in the account menu now, so the
   bar does not carry it whether or not anyone is signed in. */
.nav-utility .nav-calendar{display:none}

/* A phone page never pans sideways; see programs/styles.css for why both
   values are declared. */
html{overflow-x:hidden}
@supports (overflow-x:clip){html{overflow-x:clip}}

/* Google's own button sits where our styled one was; the custom button stays
   as the fallback for when GIS cannot load, and is hidden when it can. */
.signin-google-slot,
.signin-google-slot:empty {
  /* The placeholder and Google's drawn button share this box, so the swap
     costs no height and the centred dialog does not jump when it arrives. */
  display: flex;
  align-items: center;
  justify-content: center;
  height: 50px;
  overflow: hidden;
  margin-bottom: 12px;
}
.signin-google-slot + .signin-provider { margin-top: 0; }
.signin-google-slot > .signin-provider { margin: 0; }
.signin-provider[hidden]{display:none}

/* The long tail of a result card: shown on a wide screen, folded behind one
   button on a phone, so a listing is a card and not a page. */
.sr-card-more{display:none}
.sr-long{display:block}
@media (max-width:720px){
  .sr-long{display:none}
  .sr-card.is-open .sr-long{display:block}
  .sr-card-more{display:inline-flex;align-items:center;gap:6px;margin:10px 0 0;padding:7px 12px;border:1px solid var(--line);border-radius:999px;background:var(--white);color:var(--purple);font:inherit;font-size:12.5px;font-weight:700;cursor:pointer}
  .sr-card-more::after{content:'\203A';font-size:15px;line-height:1;transition:transform .15s}
  .sr-card-more[aria-expanded="true"]::after{transform:rotate(90deg)}
  .sr-card{content-visibility:auto;contain-intrinsic-size:auto 420px}
}

/* A phone result card, measured: the photograph was a 16:9 banner, the facts
   stacked one per line, and the foot links stacked in a column. The
   photograph is now a strip, Ages and Cost share a row, Where and Season share
   the next, and the foot is one wrapping row. */
@media (max-width:720px){
  .sr-thumb{aspect-ratio:auto;height:130px}
  .sr-facts{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px 14px}
  .sr-card-foot{flex-direction:row;flex-wrap:wrap;align-items:center;gap:8px 14px}
}

/* The match notes are the first thing folded away on a phone. */
@media (max-width:720px){
  .sr-why,.sr-caution{display:none}
  .sr-card.is-open .sr-why,.sr-card.is-open .sr-caution{display:block}
}

/* A page whose body is one form does not need the gap an article needs
   between its lede and its first section. */
.info-page.is-form-page .info-hero{padding-bottom:clamp(8px,1vw,14px)}
.info-page.is-form-page .info-body{padding-top:clamp(8px,1vw,14px)}

/* On a phone the finder's list is the index. The A–Z list below it repeats
   ninety-four rows the reader has already been given, and the note under it
   explains a list they can no longer see. */
@media (max-width:1024px){
  .towns-list{display:none}
  /* The link points at a section that is no longer there. */
  .town-browse{display:none}
}

/* The Towns link should arrive at the section itself: the eyebrow and "Find
   your town" sit just under the sticky header, with the town search and the
   first guides already in view. The page's own 18px scroll padding is the
   only air above it. */
#towns{scroll-margin-top:0}

.yb-provider-check{display:inline-flex;align-items:center;justify-content:center;width:15px;height:15px;vertical-align:-2px}
.yb-provider-check svg{width:100%;height:100%}
.yb-provider-check.is-green{color:#1f7a3f}

/* While the menu is open the page behind it does not scroll. Without this a
   thumb on the drawer dragged the homepage up under it. */
html.nav-open,
html.nav-open body { overflow: hidden; }
html.nav-open body { touch-action: pan-y; }

/* The "See all 94 towns" row under the town list. It was a bare button in a
   bordered list; it is now the list's own last row, centred and quiet. */
.town-list-more { border-top: 1px solid var(--line); }
.town-list-more button {
  display: block;
  width: 100%;
  min-height: 50px;
  padding: 13px 16px;
  border: 0;
  background: none;
  font: inherit;
  font-size: 14px;
  font-weight: 700;
  color: var(--purple);
  cursor: pointer;
}
.town-list-more button:hover,
.town-list-more button:focus-visible { background: #F7F2FB; }

/* iOS zooms the whole page in when a field it focuses is smaller than 16px,
   and it does not zoom back out — so a search left the reader looking at a
   magnified page until they pinched. Every field is 16px on a phone. */
@media (max-width: 900px) {
  input[type="search"],
  input[type="text"],
  input[type="email"],
  input[type="password"],
  input[type="tel"],
  input[type="number"],
  input[type="date"],
  select,
  textarea { font-size: 16px; }
}

/* A way back, where a phone puts one: top left of the drawer, an arrow and the
   word. The Menu button in the header still closes the drawer; this is the
   control the rest of the phone has taught people to reach for, and a drawer
   that covers the page should offer it. */
.nav-back {
  display: none;
  align-items: center;
  gap: 7px;
  align-self: flex-start;
  margin: 0 0 8px;
  padding: 8px 12px 8px 6px;
  border: 0;
  border-radius: 9px;
  background: none;
  font: inherit;
  font-size: 15px;
  font-weight: 700;
  color: #5929A7;
  cursor: pointer;
}
.nav-back svg { width: 18px; height: 18px; flex: none; }
.nav-back:hover,
.nav-back:focus-visible { background: #F2EAFA; }
@media (max-width: 1120px) { .nav-back { display: inline-flex; } }
