/* ==========================================================================
   DO SOMETHING WEEKEND -- style.css
   ==========================================================================
   Owner:  Bezalel (Visual Design, the Valley)
   Spec:   ../../design/bezalel-design-spec.md

   THE IDEA IN ONE LINE
       The page moves from night to day. Dark at the top where the map wakes
       up, cream through the middle where the work is described, dark again
       at the sign-up where the decision is made.

   HOW THIS FILE IS ORGANIZED
       1.  Tokens ................ every color, font, and spacing value
       2.  Reset and base ........ the minimum, not a framework
       3.  Typography ............ the display and body scale
       4.  Layout helpers ........ wrap, sections, reveals
       5.  Buttons
       6.  Navigation
       7.  Hero and the overture
       8.  The Story and stats
       9.  Photo bands
       10. The Map ............... the centerpiece
       11. Ways to Serve (bento)
       12. How It Works (steps)
       13. The Form
       14. Footer
       15. Reduced motion and print

   TO RESKIN THIS SITE
       Change the tokens in section 1. Nothing below section 1 contains a raw
       color value, so the whole page follows the tokens.

   BREAKPOINTS -- mobile first, min-width only
       480px  large phone
       768px  tablet
       1024px desktop
       1280px wide
   ========================================================================== */


/* ==========================================================================
   1. TOKENS
   ========================================================================== */

:root {

  /* ---- Brand green ------------------------------------------------------
     --green is sampled directly out of the supplied logo artwork
     (DSW_Graphic.jpg). It is the brand, not an approximation of it. */
  --green:        #79A238;
  --green-bright: #93BE4A;
  --green-pale:   #C7DFA0;
  --green-deep:   #46621F;
  --green-ink:    #2C3F14;

  /* ---- Night ------------------------------------------------------------ */
  --ink:      #0E1408;
  --ink-soft: #18210F;
  --ink-line: #2A3620;

  /* ---- Dawn, sampled from the dusk skyline photograph ------------------- */
  --dusk:      #241C3A;
  --dusk-warm: #4A3350;

  /* ---- Day -------------------------------------------------------------- */
  --cream:      #F6F4EC;
  --cream-deep: #EAE6D8;
  --cream-line: #DCD7C4;

  /* ---- Water. The ONLY blue on the site. Never a button, never a link. -- */
  --river: #5B93C8;

  /* ---- Pin red ----------------------------------------------------------
     The one red on the site, and it means exactly one thing: a hub site pin.
     A push pin is red the way a fire hydrant is red, and against a map made
     almost entirely of greens it is the fastest possible read.

     It is NOT an error color here. Form errors stay green on purpose, because
     now that red carries a meaning, borrowing it for validation would make
     two unrelated things look like the same thing. */
  --pin:      #E2402E;
  --pin-deep: #A8281A;

  /* ---- Text ------------------------------------------------------------- */
  --text-day:        #1B2110;
  --text-day-soft:   #4C5540;
  --text-night:      #E8EEDD;
  --text-night-soft: #9FAE8C;

  /* ---- Type ------------------------------------------------------------- */
  --font-display: "Bricolage Grotesque", "Arial Black", "Helvetica Neue", system-ui, sans-serif;
  --font-body:    Inter, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  /* ---- Spacing. An 8pt system. Nothing sits between these values. ------- */
  --s1: 8px;   --s2: 16px;  --s3: 24px;  --s4: 32px;
  --s5: 48px;  --s6: 64px;  --s7: 96px;  --s8: 128px;  --s9: 160px;

  --section-pad: clamp(80px, 12vh, 160px);
  --wrap:        1240px;
  --gutter:      24px;

  /* ---- Shape ------------------------------------------------------------ */
  --r-sm: 4px;
  --r-md: 16px;
  --r-lg: 28px;

  /* ---- Motion. One easing curve for travel, one for fades. ------------- */
  --ease:  cubic-bezier(.22, 1, .36, 1);
  --fast:  200ms;
  --mid:   300ms;
  --slow:  600ms;
}

@media (min-width: 768px) { :root { --gutter: 32px; } }


/* ==========================================================================
   2. RESET AND BASE
   Deliberately small. Everything here earns its place.
   ========================================================================== */

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

html {
  scroll-behavior: smooth;
  /* Sticky nav is 72px tall, so anchor targets stop below it, not under it. */
  scroll-padding-top: 88px;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--ink);
  color: var(--text-night);
  font-family: var(--font-body);
  font-size: 1.0625rem;
  line-height: 1.7;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img, svg { display: block; max-width: 100%; }
img { height: auto; }

/* The browser hides [hidden] by setting display:none, which any later
   display rule silently beats. Several things on this page are toggled with
   the hidden attribute and also carry a display value: the conditional
   organization field is display:grid, the map reset button is inline-flex.
   Without this line both of them show up when they should be closed. */
[hidden] { display: none !important; }

a { color: inherit; }

button, input, select, textarea { font: inherit; color: inherit; }

/* Focus. Visible everywhere, removed nowhere. */
:focus-visible {
  outline: 2px solid var(--green-bright);
  outline-offset: 2px;
  border-radius: 2px;
}

.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip-link {
  position: absolute; top: -100px; left: var(--s2); z-index: 200;
  background: var(--green); color: var(--ink);
  padding: var(--s2) var(--s3); border-radius: var(--r-sm);
  font-weight: 600; text-decoration: none;
  transition: top var(--fast) var(--ease);
}
.skip-link:focus { top: var(--s2); }


/* ==========================================================================
   3. TYPOGRAPHY
   ========================================================================== */

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 700;
  margin: 0;
  text-wrap: balance;
}

.display-l {
  font-size: clamp(2.2rem, 5.5vw, 4.2rem);
  line-height: .95;
  letter-spacing: -.02em;
  font-weight: 700;
}

.display-m {
  font-size: clamp(1.25rem, 2.2vw, 1.65rem);
  line-height: 1.15;
  letter-spacing: -.01em;
  font-weight: 700;
}

.eyebrow {
  font-family: var(--font-body);
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  line-height: 1;
  color: var(--green);
  margin: 0 0 var(--s3);
}

.lede {
  font-size: clamp(1.15rem, 2.1vw, 1.5rem);
  line-height: 1.55;
  max-width: 38ch;
  text-wrap: pretty;
}

/* Display headings carry no bottom margin, so a lede placed straight after
   one needs its own breathing room or the two collide. */
.display-l + .lede, h2 + .lede { margin-top: var(--s3); }

p { margin: 0 0 var(--s3); max-width: 62ch; text-wrap: pretty; }
p:last-child { margin-bottom: 0; }

.caption {
  font-size: .85rem;
  line-height: 1.5;
  color: var(--text-day-soft);
  max-width: 60ch;
}


/* ==========================================================================
   4. LAYOUT HELPERS
   ========================================================================== */

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.wrap--narrow { max-width: 720px; }

/* Scroll reveal. js/main.js adds .is-in when the element enters the viewport.
   The element is fully readable without JS: see the no-js fallback below. */
.reveal {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity var(--slow) var(--ease), transform var(--slow) var(--ease);
}
.reveal.is-in { opacity: 1; transform: none; }

/* If the observer never runs (JS off, old browser), show everything. */
.no-js .reveal { opacity: 1; transform: none; }


/* ==========================================================================
   5. BUTTONS
   ========================================================================== */

.btn {
  --btn-pad-y: 16px;
  --btn-pad-x: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s1);
  padding: var(--btn-pad-y) var(--btn-pad-x);
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  font-family: var(--font-body);
  font-weight: 600;
  font-size: .98rem;
  letter-spacing: .01em;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--fast) var(--ease),
              border-color var(--fast) var(--ease),
              color var(--fast) var(--ease),
              transform var(--fast) var(--ease);
}
.btn:active { transform: translateY(1px); }

.btn--primary {
  background: var(--green);
  border-color: var(--green);
  color: var(--ink);
}
.btn--primary:hover { background: var(--green-bright); border-color: var(--green-bright); }

.btn--ghost {
  background: transparent;
  border-color: currentColor;
  color: var(--green);
}
.btn--ghost:hover { background: var(--green); border-color: var(--green); color: var(--ink); }

/* On cream sections the ghost button needs the darker green to clear 4.5:1. */
.mapsec .btn--ghost, .serve .btn--ghost, .how .btn--ghost { color: var(--green-ink); }
.mapsec .btn--ghost:hover, .serve .btn--ghost:hover, .how .btn--ghost:hover {
  background: var(--green-ink); border-color: var(--green-ink); color: var(--cream);
}

.btn--sm { --btn-pad-y: 11px; --btn-pad-x: 20px; font-size: .9rem; }
.btn--lg { --btn-pad-y: 19px; --btn-pad-x: 40px; font-size: 1.05rem; width: 100%; }
/* justify-self as well as width: the form is a grid, and a grid item stretches
   to its column no matter what width:auto says. */
@media (min-width: 768px) { .btn--lg { width: auto; justify-self: start; } }

/* Submit spinner. Hidden until .is-busy is set by js/main.js. */
.btn__spinner { display: none; width: 16px; height: 16px; border-radius: 50%;
  border: 2px solid currentColor; border-top-color: transparent;
  animation: spin 700ms linear infinite; }
.btn.is-busy .btn__spinner { display: block; }
.btn.is-busy { pointer-events: none; opacity: .75; }
@keyframes spin { to { transform: rotate(360deg); } }


/* ==========================================================================
   6. NAVIGATION
   Hidden until past the hero, then slides down. js/main.js toggles .is-visible.
   ========================================================================== */

.nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 100;
  background: rgba(14, 20, 8, .88);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--ink-line);
  transform: translateY(-100%);
  transition: transform var(--mid) var(--ease);
}
.nav.is-visible { transform: none; }

.nav__inner {
  max-width: var(--wrap);
  margin-inline: auto;
  padding: 0 var(--gutter);
  height: 72px;
  display: flex;
  align-items: center;
  gap: var(--s4);
}

.nav__mark { flex: none; }
.nav__mark img { height: 34px; width: auto; }

.nav__links { display: none; margin-left: auto; gap: var(--s4); }
.nav__links a {
  text-decoration: none;
  font-size: .93rem;
  font-weight: 500;
  color: var(--text-night-soft);
  transition: color var(--fast) var(--ease);
}
.nav__links a:hover { color: var(--green-bright); }

.nav .btn { margin-left: auto; }
@media (min-width: 900px) {
  .nav__links { display: flex; }
  .nav .btn { margin-left: 0; }
}


/* ==========================================================================
   7. HERO AND THE OVERTURE
   The map sits behind the type. js/map.js renders it into .hero__map and runs
   the draw-in. Everything here is layout; the animation lives in section 10
   with the rest of the map.
   ========================================================================== */

.hero {
  position: relative;
  min-height: 100svh;
  display: grid;
  place-items: center;
  overflow: hidden;
  padding: 120px var(--gutter) var(--s7);
  isolation: isolate;
}

/* The map behind the headline.
   Two rules matter here and they pull against each other. The city's outline
   is the most recognizable thing on the page, so the whole silhouette has to
   be visible rather than cropped. But it is the backdrop, not the subject, so
   it sits well below the type in contrast. The mask does the second job: the
   map fades out toward the left edge, which is exactly where the wordmark
   and the lede sit. */
.hero__map {
  position: absolute;
  inset: 4% 0 12% 0;
  z-index: -2;
  display: grid;
  place-items: center;
  opacity: .8;
  -webkit-mask-image: linear-gradient(to right, transparent 0%, rgba(0,0,0,.35) 22%, #000 55%);
          mask-image: linear-gradient(to right, transparent 0%, rgba(0,0,0,.35) 22%, #000 55%);
}
.hero__map svg { width: 100%; height: 100%; }

@media (min-width: 900px) {
  /* On wide screens the map moves to the right half and the type takes the
     left, which is the composition in the design spec. It still shows the
     whole city, only smaller and further over. */
  .hero { place-items: center start; }
  .hero__map {
    inset: 2% -2% 6% 30%;
    opacity: .95;
    -webkit-mask-image: linear-gradient(to right, transparent 0%, rgba(0,0,0,.5) 16%, #000 42%);
            mask-image: linear-gradient(to right, transparent 0%, rgba(0,0,0,.5) 16%, #000 42%);
  }
}

/* Veil. A wide, very soft pool of ink under the type, plus a fade into the
   next section at the bottom. Kept large and low contrast on purpose: a
   tighter radial reads as a visible dark box behind the wordmark. */
.hero__veil {
  position: absolute; inset: 0; z-index: -1;
  background:
    radial-gradient(150% 120% at 8% 50%, rgba(14,20,8,.92) 0%, rgba(14,20,8,.55) 45%, rgba(14,20,8,0) 78%),
    linear-gradient(to bottom, rgba(14,20,8,.9) 0%, rgba(14,20,8,0) 26%, rgba(14,20,8,0) 58%, var(--ink) 98%);
}

.hero__inner { position: relative; max-width: 660px; }

.hero__eyebrow { color: var(--green-bright); }

.hero__title { margin: 0 0 var(--s4); }
.hero__wordmark {
  width: clamp(260px, 42vw, 480px);
  height: auto;
  /* A soft green bloom so the brush mark reads as lit rather than pasted.
     Kept wide and faint. A tighter shadow draws a visible rectangle. */
  filter: drop-shadow(0 0 64px rgba(121, 162, 56, .28));
}

.hero__lede {
  font-size: clamp(1.1rem, 2.1vw, 1.45rem);
  line-height: 1.5;
  color: var(--text-night);
  max-width: 34ch;
  margin: 0 0 var(--s4);
}

.hero__actions { display: flex; flex-wrap: wrap; gap: var(--s2); margin-bottom: var(--s4); }

.hero__countdown {
  display: flex;
  align-items: baseline;
  gap: var(--s2);
  margin: 0 0 var(--s4);
  padding-top: var(--s3);
  border-top: 1px solid var(--ink-line);
  max-width: 36ch;
}
.hero__countdown-num {
  font-family: var(--font-display);
  font-size: 2.4rem;
  font-weight: 800;
  line-height: 1;
  color: var(--green);
  font-variant-numeric: tabular-nums;
}
.hero__countdown-label {
  font-size: .9rem;
  line-height: 1.35;
  color: var(--text-night-soft);
}

/* ---- Hero partner credits ---------------------------------------------
   Two marks side by side: the Living City Project lockup, which is already
   green and reads on the dark ground, and the City of Dayton, which is navy
   on transparent and therefore needs a cream chip to sit on. */
.hero__credits {
  display: flex;
  align-items: center;
  gap: var(--s3);
  flex-wrap: wrap;
}

.hero__credit { display: inline-flex; opacity: .78; transition: opacity var(--fast) var(--ease), transform var(--fast) var(--ease); }
.hero__credit:hover { opacity: 1; }
.hero__credit img { height: 40px; width: auto; }

.hero__credits-rule {
  width: 1px;
  height: 30px;
  background: var(--ink-line);
  flex: none;
}

.hero__credit--chip {
  align-items: center;
  padding: 8px 14px;
  background: var(--cream);
  border-radius: 12px;
  opacity: .95;
}
.hero__credit--chip:hover { opacity: 1; transform: translateY(-2px); }
.hero__credit--chip img { height: 30px; }

/* ---- Scroll cue --------------------------------------------------------
   This was a single travelling hairline. It was elegant and it was invisible,
   which is a failure: its whole job is to tell someone the page continues.
   It is now a labelled control. The word carries the meaning, the rule and
   the arrow carry the direction, and the whole thing bobs gently rather than
   relying on a fading line to be noticed. */

.hero__scroll {
  position: absolute;
  bottom: var(--s4);
  left: 50%;
  translate: -50% 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 8px 14px 10px;
  text-decoration: none;
  color: var(--green-bright);
  border-radius: 999px;
  transition: color var(--fast) var(--ease), transform var(--fast) var(--ease);
  animation: scrollbob 2.4s ease-in-out infinite;
}
.hero__scroll:hover { color: var(--cream); }

.hero__scroll-word {
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: .18em;
  text-transform: uppercase;
  line-height: 1;
}

.hero__scroll-line {
  width: 1px;
  height: 26px;
  background: linear-gradient(to bottom, currentColor, transparent);
}

.hero__scroll-arrow {
  width: 20px; height: 20px;
  margin-top: -14px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

@keyframes scrollbob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(7px); }
}

/* On a short laptop the hero is already tight, so the cue sheds the word and
   keeps the arrow, which is the part that carries the direction. */
@media (max-height: 780px) {
  .hero__scroll-word { display: none; }
  .hero__scroll-line { height: 18px; }
}

/* Phones. The hero was running to 900px inside an 844px viewport, which
   pushed the scroll cue past the fold and on top of the partner credits. The
   exact thing the cue exists to prevent. These reductions bring the hero back
   inside one screen and leave the cue room to sit below the credits. */
@media (max-width: 700px) {
  .hero { padding-top: 80px; padding-bottom: var(--s5); }
  .hero__lede { margin-bottom: var(--s3); }
  .hero__actions { margin-bottom: var(--s3); }
  .hero__countdown { margin-bottom: var(--s3); padding-top: var(--s2); }
  .hero__credit img { height: 32px; }
  .hero__credit--chip img { height: 26px; }
  .hero__scroll { bottom: var(--s2); padding-bottom: 6px; }
}

/* Small phones, where 740px of height has to hold the whole invitation. The
   wordmark gives up the most room for the least loss, because it is the one
   element that is still unmistakable at a smaller size. */
@media (max-width: 700px) and (max-height: 790px) {
  .hero { padding-top: 64px; }
  .hero__wordmark { width: clamp(200px, 56vw, 260px); }
  .hero__countdown-num { font-size: 2rem; }
  .hero__credit img { height: 28px; }
  .hero__credit--chip img { height: 23px; }
}

/* Short laptop screens. A 1440x900 browser window is the single most common
   desktop size and the hero must fit inside it without the credit lockup
   sliding under the fold. */
@media (min-width: 900px) and (max-height: 900px) {
  .hero { padding-top: 100px; }
  .hero__wordmark { width: clamp(240px, 32vw, 400px); }
  .hero__lede { font-size: 1.2rem; margin-bottom: var(--s3); }
  .hero__actions { margin-bottom: var(--s3); }
  .hero__countdown { margin-bottom: var(--s3); padding-top: var(--s2); }
  .hero__countdown-num { font-size: 2rem; }
  .hero__credit img { height: 32px; }
  .hero__credit--chip img { height: 25px; }
  .hero__credits { gap: var(--s2); }
}


/* ==========================================================================
   8. THE STORY AND STATS
   This is where the page turns from night to day. The gradient does the work.
   ========================================================================== */

.story {
  background: linear-gradient(to bottom,
    var(--ink) 0%,
    var(--dusk) 22%,
    var(--dusk-warm) 40%,
    var(--cream) 62%,
    var(--cream) 100%);
  color: var(--text-night);
  padding-top: var(--section-pad);
}

.story__grid { display: grid; gap: var(--s5); }
@media (min-width: 900px) {
  .story__grid { grid-template-columns: 1fr 1.15fr; gap: var(--s7); align-items: start; }
  .story__head { position: sticky; top: 120px; }
}

.story .display-l { color: var(--cream); }
.story__body p { color: rgba(246, 244, 236, .82); }
.story__body .lede { color: var(--cream); }

/* Stats sit on the cream half of the gradient, so their text flips to day. */
.stats {
  list-style: none;
  margin: var(--s8) 0 0;
  padding: var(--s5) 0 0;
  border-top: 1px solid var(--cream-line);
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--s5) var(--s3);
  color: var(--text-day);
}
@media (min-width: 768px) { .stats { grid-template-columns: repeat(4, 1fr); } }

/* The lead stat is the number of hub sites. It used to be set in --green,
   which lands on the dawn gradient's mauve band and measures about 2.4:1
   against it: unreadable, exactly as Bishop said. It now takes the same dark
   green as its siblings and is marked instead by a red pin, which ties the
   number straight to the four pins on the map. */
.stats__item--lead .stats__num { color: var(--green-ink); }
.stats__item--lead .stats__label { color: var(--text-day); font-weight: 600; }

/* EVERY stat reserves the pin's space, and only the lead one paints a pin in
   it. Putting the marker on the lead item alone pushed its number down and
   broke the baseline the four numbers share. */
.stats__num::before {
  content: "";
  display: block;
  width: 15px; height: 18px;
  margin-bottom: 10px;
}
.stats__item--lead .stats__num::before {
  background: var(--pin);
  clip-path: polygon(50% 100%, 38% 46%, 20% 34%, 26% 8%, 74% 8%, 80% 34%, 62% 46%);
}

.stats__num {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(2.6rem, 6vw, 4rem);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -.03em;
  color: var(--green-ink);
  font-variant-numeric: tabular-nums;
}
.stats__label {
  display: block;
  margin-top: var(--s1);
  font-size: .88rem;
  line-height: 1.4;
  color: var(--text-day-soft);
  max-width: 24ch;
}


/* ==========================================================================
   9. PHOTO BANDS
   ========================================================================== */

.band { position: relative; margin: 0; overflow: hidden; }
.band img { width: 100%; object-fit: cover; }

.band--skyline { margin-top: var(--section-pad); }
.band--skyline img { height: clamp(320px, 52vh, 560px); filter: brightness(.62) saturate(1.05); }

.band--neighborhood img { height: clamp(340px, 58vh, 620px); filter: brightness(.78) saturate(1.08); }

.band__quote {
  position: absolute;
  inset: auto 0 0 0;
  padding: var(--s6) var(--gutter) var(--s5);
  background: linear-gradient(to top, rgba(14,20,8,.92), rgba(14,20,8,0));
}
.band__quote p {
  max-width: var(--wrap);
  margin-inline: auto;
  font-family: var(--font-display);
  font-size: clamp(1.4rem, 3.4vw, 2.6rem);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -.02em;
  color: var(--cream);
}
.band__quote em { font-style: normal; color: var(--green-bright); }


/* ==========================================================================
   10. THE MAP  (the centerpiece)
   ==========================================================================
   Structure produced by js/map.js:

       <svg class="daymap">
         <g class="daymap__water">   lakes
         <g class="daymap__rivers">  four named waterways
         <g class="daymap__hoods">   65 <path class="hood" data-id data-board>
         <g class="daymap__labels">  neighborhood name, shown only when zoomed

   State classes set by js/map.js:
       .daymap.is-overture    the draw-in is running
       .daymap.is-zoomed      one neighborhood is selected
       .hood.is-active        the selected neighborhood
       .hood.is-dim           filtered out or not selected
   ========================================================================== */

.mapsec {
  background: var(--cream);
  color: var(--text-day);
  padding-block: var(--section-pad);
}

.mapsec__head { margin-bottom: var(--s5); }
.mapsec__head .display-l { color: var(--text-day); }
.mapsec__head .lede { color: var(--text-day-soft); max-width: 46ch; }
.mapsec__head .lede strong { color: var(--text-day); font-weight: 600; }

/* The beta note. Set apart from the lede by a green rule rather than a box,
   because a box would read as a warning and this is an invitation. */
.betanote {
  margin: var(--s4) 0 0;
  padding-left: var(--s3);
  border-left: 3px solid var(--green);
  font-size: .95rem;
  line-height: 1.65;
  color: var(--text-day-soft);
  max-width: 60ch;
}
.betanote__tag {
  display: inline-block;
  margin-right: 8px;
  padding: 3px 10px;
  background: var(--green-ink);
  color: var(--cream);
  border-radius: 999px;
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  vertical-align: 2px;
}

/* ---- Controls ---------------------------------------------------------- */

.mapsec__controls {
  display: flex;
  flex-direction: column;
  gap: var(--s3);
  margin-bottom: var(--s4);
}
@media (min-width: 900px) {
  .mapsec__controls { flex-direction: row; align-items: center; justify-content: space-between; }
}

.search { position: relative; width: 100%; max-width: 340px; }
.search__icon {
  position: absolute; left: 14px; top: 50%; translate: 0 -50%;
  width: 18px; height: 18px; pointer-events: none;
  fill: none; stroke: var(--text-day-soft); stroke-width: 2; stroke-linecap: round;
}
.search input {
  width: 100%;
  padding: 13px 40px 13px 42px;
  background: var(--cream-deep);
  border: 1px solid var(--cream-line);
  border-radius: var(--r-sm);
  color: var(--text-day);
  transition: border-color var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}
.search input::placeholder { color: var(--text-day-soft); }
.search input:focus {
  outline: none;
  border-color: var(--green);
  box-shadow: 0 0 0 3px rgba(121, 162, 56, .25);
}
.search__clear {
  position: absolute; right: 8px; top: 50%; translate: 0 -50%;
  width: 28px; height: 28px; display: grid; place-items: center;
  background: none; border: 0; border-radius: 50%;
  font-size: 1.3rem; line-height: 1; color: var(--text-day-soft); cursor: pointer;
}
.search__clear:hover { background: var(--cream-line); color: var(--text-day); }

.search__results {
  position: absolute; z-index: 20; inset: calc(100% + 6px) 0 auto 0;
  list-style: none; margin: 0; padding: 6px;
  max-height: 280px; overflow-y: auto;
  background: var(--cream);
  border: 1px solid var(--cream-line);
  border-radius: var(--r-sm);
  box-shadow: 0 18px 40px rgba(27, 33, 16, .16);
}
.search__results li {
  padding: 10px 12px; border-radius: var(--r-sm); cursor: pointer;
  font-size: .95rem; display: flex; justify-content: space-between; gap: var(--s2);
}
.search__results li:hover,
.search__results li[aria-selected="true"] { background: var(--green); color: var(--cream); }

.search__results .res-tag {
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  padding: 2px 8px;
  border-radius: 999px;
  flex: none;
}
.search__results li.is-hub .res-tag { background: var(--green); color: var(--cream); }
.search__results li.is-unavailable .res-tag { background: var(--cream-line); color: var(--text-day-soft); }
.search__results li.is-unavailable > span:first-child { opacity: .75; }
.search__results li:hover .res-tag,
.search__results li[aria-selected="true"] .res-tag { background: rgba(255,255,255,.25); color: var(--cream); }

/* ---- Hub site chips ----------------------------------------------------
   These used to filter by Priority Board. Now they ARE the four choices, so
   each one carries a small pin glyph and reads as a destination rather than
   as a filter. */

.chips { display: flex; flex-wrap: wrap; gap: var(--s1); }

.chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 9px 16px 9px 13px;
  background: var(--cream-deep);
  border: 1px solid var(--cream-line);
  border-radius: 999px;
  font-size: .88rem;
  font-weight: 600;
  color: var(--text-day);
  cursor: pointer;
  transition: background var(--fast) var(--ease),
              border-color var(--fast) var(--ease),
              color var(--fast) var(--ease),
              transform var(--fast) var(--ease);
}
.chip:hover { border-color: var(--green); transform: translateY(-1px); }
.chip[aria-pressed="true"] {
  background: var(--green-ink);
  border-color: var(--green-ink);
  color: var(--cream);
}

/* The pin glyph. Same object as the map pin, reduced to its silhouette. */
.chip__pin {
  width: 11px; height: 13px; flex: none;
  background: var(--pin);
  clip-path: polygon(50% 100%, 38% 46%, 20% 34%, 26% 8%, 74% 8%, 80% 34%, 62% 46%);
  transition: background var(--fast) var(--ease);
}
.chip[aria-pressed="true"] .chip__pin { background: #F4614F; }

/* ---- The stage --------------------------------------------------------- */

/* The tooltip and the detail panel are siblings of the map frame and are
   positioned against THIS box, so it has to be exactly the same size and
   place as the frame itself. Both carry the same width cap. */
.mapsec__stage {
  position: relative;
  width: 100%;
  max-width: calc(80vh * 1.0776);
  margin-inline: auto;
}

/* The map frame.
   aspect-ratio matches the data's own viewBox (1000 x 928) so the city never
   letterboxes inside its frame. max-width is what keeps the whole thing on
   screen: at full page width this box would stand about 1100px tall, taller
   than a laptop viewport, and the detail panel that opens at its foot would
   land below the fold. Capping the WIDTH against the viewport HEIGHT is what
   bounds the height, because the aspect ratio ties the two together. */
.mapstage {
  position: relative;
  width: 100%;
  aspect-ratio: 1000 / 928;         /* 1000 x 928 is the map data's own viewBox */
  background: var(--ink);
  border-radius: var(--r-lg);
  overflow: hidden;
  padding: clamp(12px, 2.5vw, 28px);
  /* A faint inner glow so the dark map panel reads as a lit object on cream. */
  box-shadow: inset 0 0 120px rgba(121, 162, 56, .10),
              0 24px 60px rgba(27, 33, 16, .18);
}
.mapstage .daymap { width: 100%; height: 100%; }

/* On a phone the map is the smallest it ever gets, so it takes the full
   width of the screen rather than sitting inside the page gutter. That is
   about fifteen percent more city for the same scroll. */
@media (max-width: 699px) {
  .mapsec__stage {
    margin-inline: calc(var(--gutter) * -1);
    max-width: none;
    width: calc(100% + var(--gutter) * 2);
  }
  .mapstage { border-radius: 0; padding: 8px; }
  .mappanel { margin-inline: var(--gutter); }
}
.mapstage__loading {
  margin: 0; padding: 80px 0; text-align: center;
  color: var(--text-night-soft); font-size: .95rem;
}

.daymap { width: 100%; height: auto; display: block; overflow: visible; }

/* ---- Neighborhood shapes ----------------------------------------------- */

/* ---- Neighborhood shapes, in two states --------------------------------
   October 2026 is the beta run. Four neighborhoods are open; the other
   sixty-one are drawn but cannot be chosen.

   The design carries that rule rather than leaving JavaScript to enforce it
   silently. The four are lit in full brand green and behave like controls.
   The sixty-one are recessive: dark, low contrast, no pointer cursor. They
   are still clearly THERE, because the whole city on the map is the promise
   that the whole city is coming, and a map showing only four shapes would
   make this look like a four neighborhood event instead of a first step. */

.hood {
  stroke: var(--ink);
  stroke-width: 1.1;
  stroke-linejoin: round;
  transition: fill var(--fast) var(--ease), opacity var(--fast) var(--ease);
}

/* The sixty-one. Board tint is kept so the city still has texture, but every
   value is pulled down close to the ground. */
.hood--quiet {
  cursor: default;
  opacity: .5;
}
.hood--quiet:hover { opacity: .72; }

.hood--quiet[data-i="0"] { fill: #1E2B10; }
.hood--quiet[data-i="1"] { fill: #223012; }
.hood--quiet[data-i="2"] { fill: #263614; }
.hood--quiet[data-i="3"] { fill: #2A3B16; }
.hood--quiet[data-i="4"] { fill: #2E4118; }
.hood--quiet[data-i="5"] { fill: #33471A; }
.hood--quiet[data-i="6"] { fill: #384D1D; }

/* The four. Full brand green, a pale edge so they lift off the field, and a
   soft outer glow so they read as lit rather than merely lighter. */
.hood--hub {
  fill: var(--green);
  cursor: pointer;
  stroke: var(--green-pale);
  stroke-width: 1.4;
  /* A green bloom around the four. This is what makes them read as LIT
     rather than merely a lighter shade of the same map. */
  filter: drop-shadow(0 0 10px rgba(147, 190, 74, .5));
}
.hood--hub:hover,
.hood--hub:focus-visible { fill: var(--green-bright); outline: none; }
.hood--hub:focus-visible { stroke: var(--cream); stroke-width: 2.4; }
.hood--hub.is-active { fill: var(--green-bright); stroke: var(--cream); stroke-width: 2; }

.hood.is-dim { opacity: .22; }

/* ---- The hero wireframe -------------------------------------------------
   The same 65 shapes, drawn as outlines rather than fills. This is the copy
   that sits behind the headline. An outlined city reads as a drawing of
   Dayton; a filled one reads as a green stain behind the type. The fill is
   kept just barely present so the shapes still catch the light. */

.daymap--ghost .hood {
  fill: rgba(121, 162, 56, .10);
  stroke: rgba(158, 201, 84, .85);
  /* 1.6 rather than 1: at the scale the hero draws this map, a 1 unit stroke
     lands on roughly one device pixel and antialiasing washes it out to a
     grey suggestion. The city has to read as drawn, not smudged. */
  stroke-width: 1.6;
  pointer-events: none;
}
.daymap--ghost .daymap__rivers path { stroke: rgba(91, 147, 200, .9); stroke-width: 3; }
.daymap--ghost .daymap__water path { fill: rgba(91, 147, 200, .55); }

/* ---- Water ------------------------------------------------------------- */

.daymap__water path { fill: var(--river); opacity: .85; }
.daymap__rivers path {
  fill: none;
  stroke: var(--river);
  stroke-width: 2.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: .9;
  pointer-events: none;
}

/* ---- Labels, only visible once zoomed in ------------------------------- */

.daymap__labels text {
  font-family: var(--font-body);
  font-size: 9px;
  font-weight: 600;
  fill: var(--cream);
  text-anchor: middle;
  paint-order: stroke;
  stroke: rgba(14, 20, 8, .8);
  stroke-width: 3px;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--mid) var(--ease);
}
.daymap.is-zoomed .daymap__labels text.is-shown { opacity: 1; }
/* The selected neighborhood's own name is set larger by js/map.js and picks
   up the brand green here, so the eye lands on it before its neighbors. */
.daymap__labels text.is-active { fill: var(--green-pale); font-weight: 700; }

/* ---- The overture ------------------------------------------------------
   Rivers draw first, then the neighborhoods bloom outward. js/map.js sets the
   per-shape --d (delay) custom property, so the stagger order is data driven
   rather than hard coded here. */

.daymap.is-overture .daymap__rivers path {
  stroke-dasharray: var(--len);
  stroke-dashoffset: var(--len);
  animation: draw 900ms var(--ease) forwards;
}
@keyframes draw { to { stroke-dashoffset: 0; } }

.daymap.is-overture .hood {
  opacity: 0;
  transform: scale(.94);
  transform-origin: center;
  transform-box: fill-box;
  animation: bloom 380ms var(--ease) forwards;
  animation-delay: var(--d, 0ms);
}
@keyframes bloom {
  to { opacity: 1; transform: none; }
}

/* ---- Hub site pins -----------------------------------------------------
   A literal push pin, stuck into the map at the hub's coordinate. The pin's
   POINT sits on the coordinate and the head stands above it, which is what
   makes it read as pushed in rather than printed on. js/map.js rescales the
   whole pin as the map zooms so it holds a constant size on screen.

   This is the only element on the map allowed to move on its own. Everything
   else is still until touched. */

.hubpin { cursor: pointer; }

/* A ring on the ground at the point, spreading outward. */
.hubpin__pulse {
  fill: none;
  stroke: var(--pin);
  stroke-width: 1.4;
  transform-origin: center;
  animation: hubpulse 2.8s var(--ease) infinite;
}
@keyframes hubpulse {
  0%   { transform: scale(.5);  opacity: .95; }
  70%  { transform: scale(2.4); opacity: 0; }
  100% { transform: scale(2.4); opacity: 0; }
}

/* A squashed shadow under the point, so the pin stands up off the map. */
.hubpin__shadow { fill: rgba(6, 10, 4, .55); }

/* The shaft. A tapered triangle, wide at the head and sharp at the point. */
.hubpin__needle {
  fill: var(--cream);
  stroke: var(--ink);
  stroke-width: .6;
  stroke-linejoin: round;
}

/* The grip, and the highlight that makes it a sphere instead of a circle. */
.hubpin__head {
  fill: var(--pin);
  stroke: var(--pin-deep);
  stroke-width: 1.6;
}
.hubpin__gloss { fill: rgba(255, 255, 255, .6); }

.hubpin:hover .hubpin__head,
.hubpin:focus-visible .hubpin__head { fill: #F4614F; }
.hubpin:focus-visible { outline: none; }
.hubpin:focus-visible .hubpin__head { stroke: var(--cream); stroke-width: 2.6; }

.hubpin__label {
  font-family: var(--font-body);
  font-size: 13px;
  font-weight: 700;
  fill: var(--cream);
  text-anchor: middle;
  paint-order: stroke;
  stroke: rgba(14, 20, 8, .88);
  stroke-width: 4px;
  pointer-events: none;
}

/* ---- Legend ------------------------------------------------------------ */

.legend {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  font-size: .88rem;
  color: var(--text-day-soft);
  max-width: none;
}
.legend strong { color: var(--text-day); font-weight: 600; }
.legend__dot {
  flex: none;
  width: 13px; height: 15px;
  background: var(--pin);
  clip-path: polygon(50% 100%, 38% 46%, 20% 34%, 26% 8%, 74% 8%, 80% 34%, 62% 46%);
}

/* ---- Hover tooltip ----------------------------------------------------- */

.maptip {
  position: absolute;
  z-index: 15;
  pointer-events: none;
  padding: 8px 13px;
  background: var(--cream);
  color: var(--text-day);
  border-radius: var(--r-sm);
  box-shadow: 0 10px 30px rgba(14, 20, 8, .35);
  translate: -50% calc(-100% - 12px);
  white-space: nowrap;
  line-height: 1.25;
}
.maptip__name { display: block; font-weight: 700; font-size: .95rem; }
.maptip__board { display: block; font-size: .76rem; color: var(--text-day-soft); }
/* A hub's tooltip says so in the brand green. The other sixty-one keep the
   muted grey, so the difference is legible before the words are read. */
.maptip.is-hub { border-left: 3px solid var(--green); }
.maptip.is-hub .maptip__board { color: var(--green-ink); font-weight: 600; }
/* Hover labels are noise on touch, where there is no hover to speak of. */
@media (hover: none) { .maptip { display: none !important; } }

/* ---- Detail panel ------------------------------------------------------ */

/* The panel sits BELOW the map on a phone and ON it from tablet up.
   On a narrow screen the map is only a few hundred pixels tall, so a panel
   floating over it would cover the thing the visitor just tapped. */
.mappanel {
  position: relative;
  z-index: 18;
  margin-top: var(--s2);
  padding: var(--s4);
  background: var(--cream);
  color: var(--text-day);
  border: 1px solid var(--cream-line);
  border-radius: var(--r-md);
  animation: panel-in var(--mid) var(--ease);
}
@media (min-width: 768px) {
  .mappanel {
    position: absolute;
    inset: auto auto var(--s4) var(--s4);
    width: 340px;
    margin-top: 0;
    border: 0;
    box-shadow: 0 24px 60px rgba(14, 20, 8, .45);
  }
}
@keyframes panel-in { from { opacity: 0; transform: translateY(12px); } }

/* The hub badge. Solid green, so it reads before the neighborhood name. */
.mappanel__badge {
  display: inline-block;
  margin: 0 0 var(--s2);
  padding: 5px 11px;
  background: var(--green-ink);
  color: var(--cream);
  border-radius: 999px;
  font-size: .74rem;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  max-width: none;
}
.mappanel.is-hub { border-top: 3px solid var(--green); }

/* The "not this year" panel. Same weight of presentation, different answer.
   Its badge drops the solid green fill so it does not read as an award. */
.mappanel.is-unavailable { border-top: 3px solid var(--cream-line); }
.mappanel.is-unavailable .mappanel__badge {
  background: transparent;
  color: var(--text-day-soft);
  border: 1px solid var(--cream-line);
}

.mappanel .eyebrow { color: var(--green-ink); margin-bottom: var(--s1); }
.mappanel .display-m { margin-bottom: var(--s2); }
.mappanel__note { font-size: .93rem; color: var(--text-day-soft); margin-bottom: var(--s3); }
.mappanel__close {
  position: absolute; top: 10px; right: 10px;
  width: 32px; height: 32px; display: grid; place-items: center;
  background: none; border: 0; border-radius: 50%;
  font-size: 1.5rem; line-height: 1; color: var(--text-day-soft); cursor: pointer;
}
.mappanel__close:hover { background: var(--cream-deep); color: var(--text-day); }

.mapsec__foot {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s3);
  margin-top: var(--s3);
  max-width: calc(80vh * 1.0776);
  margin-inline: auto;
}


/* ==========================================================================
   11. WAYS TO SERVE (bento)
   ========================================================================== */

.serve {
  background: var(--cream);
  color: var(--text-day);
  padding-bottom: var(--section-pad);
}
.serve__head { margin-bottom: var(--s5); }
.serve__head .display-l { color: var(--text-day); }

.bento {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: var(--s2);
  grid-template-columns: 1fr;
}
@media (min-width: 700px)  { .bento { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) {
  .bento { grid-template-columns: repeat(3, 1fr); }
  .bento__card--wide { grid-column: span 2; }
}

.bento__card {
  padding: var(--s4);
  background: var(--cream-deep);
  border: 1px solid var(--cream-line);
  border-radius: var(--r-md);
  transition: background var(--mid) var(--ease),
              border-color var(--mid) var(--ease),
              transform var(--mid) var(--ease);
}
.bento__card:hover {
  background: var(--ink);
  border-color: var(--ink);
  transform: translateY(-4px);
}
.bento__card:hover .display-m { color: var(--cream); }
.bento__card:hover p { color: var(--text-night-soft); }
.bento__card:hover .bento__icon { stroke: var(--green-bright); }

.bento__icon {
  width: 32px; height: 32px; margin-bottom: var(--s3);
  fill: none; stroke: var(--green-ink); stroke-width: 1.6;
  stroke-linecap: round; stroke-linejoin: round;
  transition: stroke var(--mid) var(--ease);
}
.bento__card .display-m { margin-bottom: var(--s2); transition: color var(--mid) var(--ease); }
.bento__card p { font-size: .97rem; color: var(--text-day-soft); transition: color var(--mid) var(--ease); }


/* ==========================================================================
   12. HOW IT WORKS
   ========================================================================== */

.how {
  background: var(--cream);
  color: var(--text-day);
  padding-bottom: var(--section-pad);
}
.how__head { margin-bottom: var(--s5); }
.how__head .display-l { color: var(--text-day); }

.steps { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s5); }
@media (min-width: 900px) { .steps { grid-template-columns: repeat(3, 1fr); gap: var(--s4); } }

.steps__item { padding-top: var(--s3); border-top: 2px solid var(--green); }
.steps__num {
  display: block;
  font-family: var(--font-display);
  font-size: 1rem; font-weight: 800; letter-spacing: .1em;
  color: var(--green-ink);
  margin-bottom: var(--s2);
  font-variant-numeric: tabular-nums;
}
.steps__item .display-m { margin-bottom: var(--s2); }
.steps__item p { font-size: .97rem; color: var(--text-day-soft); }


/* ==========================================================================
   13. THE FORM
   Night section. One column, always. Labels above inputs, always visible.
   ========================================================================== */

.signup {
  background: var(--ink);
  color: var(--text-night);
  padding-block: var(--section-pad);
}
.signup__head { margin-bottom: var(--s6); }
.signup__head .display-l { color: var(--cream); }
.signup__head .lede { color: var(--text-night-soft); max-width: 52ch; }

.form { display: grid; gap: var(--s4); }

/* Honeypot. Off screen rather than display:none, because some bots skip
   anything that is display:none. Hidden from assistive tech by aria-hidden
   on the wrapper in the HTML, and unreachable by tabindex="-1". */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.field { display: grid; gap: var(--s1); }
.field > label, .field legend {
  font-size: .88rem;
  font-weight: 600;
  letter-spacing: .01em;
  color: var(--text-night);
}
.req { color: var(--green); margin-left: 2px; }
.opt {
  font-weight: 400;
  font-size: .8rem;
  color: var(--text-night-soft);
  margin-left: 6px;
  text-transform: lowercase;
}

.field input, .field select, .field textarea {
  width: 100%;
  padding: 14px 16px;
  background: var(--ink-soft);
  border: 1px solid rgba(121, 162, 56, .3);
  border-radius: var(--r-sm);
  color: var(--text-night);
  transition: border-color var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}
.field textarea { resize: vertical; min-height: 110px; line-height: 1.6; }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none;
  border-color: var(--green);
  box-shadow: 0 0 0 3px rgba(121, 162, 56, .25);
}
.field input::placeholder, .field textarea::placeholder { color: #6E7C5C; }

/* Native select arrow, drawn rather than imported, so it follows the palette. */
.field select {
  appearance: none;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%2379A238' stroke-width='1.8' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 16px center;
  background-size: 12px;
  padding-right: 44px;
}
.field select option { background: var(--ink-soft); color: var(--text-night); }

.field__hint { font-size: .82rem; color: var(--text-night-soft); margin: 0; }

/* Errors are green, not red. Red appears nowhere else here, and one alien
   color reads as system failure rather than a correction. */
.field__err { font-size: .84rem; color: var(--green-bright); margin: 0; }
.field.has-error input,
.field.has-error select { border-color: var(--green-bright); }

.field--set { border: 0; padding: 0; margin: 0; }
.field--set legend { padding: 0; margin-bottom: var(--s2); }

.checks { display: grid; gap: var(--s1); }
@media (min-width: 600px) { .checks { grid-template-columns: repeat(2, 1fr); } }

.check {
  display: flex; align-items: center; gap: 10px;
  padding: 13px 15px;
  background: var(--ink-soft);
  border: 1px solid var(--ink-line);
  border-radius: var(--r-sm);
  font-size: .93rem;
  cursor: pointer;
  transition: border-color var(--fast) var(--ease), background var(--fast) var(--ease);
}
.check:hover { border-color: rgba(121, 162, 56, .5); }
.check input { width: 18px; height: 18px; accent-color: var(--green); flex: none; }
.check:has(input:checked) { border-color: var(--green); background: rgba(121, 162, 56, .1); }

.form__note { font-size: .85rem; color: var(--text-night-soft); margin: 0; }
.form__err {
  padding: var(--s2) var(--s3);
  background: rgba(147, 190, 74, .12);
  border: 1px solid var(--green-bright);
  border-radius: var(--r-sm);
  color: var(--green-bright);
  font-size: .92rem;
  margin: 0;
}

/* ---- Success panel ----------------------------------------------------- */

/* js/main.js moves focus here on success so a screen reader announces the
   confirmation. The panel is a container rather than a control, so the focus
   ring would only draw a box around the whole thing with nothing to act on.
   The focus move still happens; only the ring is suppressed. */
.done { text-align: center; padding: var(--s5) 0; }
.done:focus, .done:focus-visible { outline: none; }
.done__check {
  width: 64px; height: 64px; margin: 0 auto var(--s4);
  fill: none; stroke: var(--green); stroke-width: 2.5;
  stroke-linecap: round; stroke-linejoin: round;
}
.done__check circle, .done__check path {
  stroke-dasharray: 200; stroke-dashoffset: 200;
  animation: draw 700ms var(--ease) forwards;
}
.done__check path { animation-delay: 350ms; }
.done .display-l { color: var(--cream); margin-bottom: var(--s3); }
.done .lede { margin: 0 auto var(--s5); color: var(--text-night-soft); max-width: 44ch; }


/* ==========================================================================
   14. FOOTER
   ========================================================================== */

.foot {
  background: var(--ink);
  color: var(--text-night-soft);
  border-top: 1px solid var(--ink-line);
  padding-block: var(--s6) var(--s5);
  font-size: .92rem;
}

.foot__grid { display: grid; gap: var(--s5); }
@media (min-width: 768px) { .foot__grid { grid-template-columns: 1.4fr 1fr 1fr; gap: var(--s6); } }

.foot__brand img { height: 56px; width: auto; margin-bottom: var(--s2); }
.foot__brand p { margin: 0; font-size: .9rem; }

.foot__col ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.foot__col a { text-decoration: none; transition: color var(--fast) var(--ease); }
.foot__col a:hover { color: var(--green-bright); }

.foot__lockup { display: inline-block; opacity: .8; transition: opacity var(--fast) var(--ease); }
.foot__lockup:hover { opacity: 1; }
.foot__lockup img { height: 42px; width: auto; }

.foot__by { margin: var(--s2) 0 0; font-size: .85rem; line-height: 1.5; max-width: 28ch; }

/* ---- Partner mark ------------------------------------------------------
   The City of Dayton logo is navy, cyan, and green on a transparent ground.
   Dropped straight onto the dark footer the navy wordmark would disappear,
   so it sits on a cream chip. That is also how a partner mark should be
   presented: given its own clean space rather than tinted to match ours. */
.foot__partner-label { margin: var(--s5) 0 var(--s2); }

.foot__partner {
  display: inline-flex;
  align-items: center;
  padding: 12px 18px;
  background: var(--cream);
  border-radius: var(--r-md);
  transition: transform var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}
.foot__partner:hover {
  transform: translateY(-2px);
  box-shadow: 0 10px 26px rgba(0, 0, 0, .35);
}
.foot__partner img { height: 42px; width: auto; }
.foot__by a { color: var(--green); text-decoration: none; }
.foot__by a:hover { color: var(--green-bright); text-decoration: underline; }

.foot__legal {
  margin: var(--s6) 0 0;
  padding-top: var(--s3);
  border-top: 1px solid var(--ink-line);
  font-size: .8rem;
  line-height: 1.6;
  max-width: none;
  color: #74805F;
}
.foot__legal a { color: var(--text-night-soft); }
.foot__legal-sep { padding: 0 6px; }


/* ==========================================================================
   15. REDUCED MOTION AND PRINT
   ==========================================================================
   Reduced motion is not a lesser experience here. The map still draws itself
   into its finished state, the reveals still show, the countdown still counts.
   Only the travel is removed.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }

  /* Show every revealed element outright rather than waiting on the observer. */
  .reveal { opacity: 1 !important; transform: none !important; }

  /* The overture collapses to the finished map. */
  .daymap.is-overture .hood { opacity: 1; transform: none; animation: none; }
  .daymap.is-overture .daymap__rivers path { stroke-dashoffset: 0; animation: none; }

  .hero__scroll { animation: none; }

  /* The push pin stops pulsing but stays fully visible. The pin is
     information; the pulse was only emphasis. */
  .hubpin__pulse { animation: none; opacity: .5; transform: scale(1.6); }
}

@media print {
  .nav, .hero__scroll, .mapsec__controls, .mappanel, .maptip, .btn { display: none !important; }
  body { background: #fff; color: #000; }
  .story, .mapsec, .serve, .how, .signup, .foot { background: #fff !important; color: #000 !important; }
  .mapstage { background: #fff; box-shadow: none; }
}
