/* ============================================================
   Michael Ankenmann for Huntsville & Chaffey
   Muskoka-inspired theme: calming blue/turquoise, water & topo motifs
   ============================================================ */

:root {
  /* Water — calming blue with a slight turquoise tint */
  --water: #2b8ca6;
  --water-deep: #14586b;
  --water-dark: #0d3f4d;
  --water-light: #e3f0f3;
  --water-mist: #f3f9fa;

  /* Muskoka accents */
  --pine: #2f5d4f;        /* forest green */
  --granite: #6b7178;     /* rock grey */
  --sand: #d8cbb4;        /* warm shoreline */
  --sun: #e2a54c;         /* subtle warm highlight */
  --sun-deep: #8a5311;    /* readable text weight of --sun */
  --sun-light: #fbf0dc;   /* sun tint, pairs with --water-light */

  /* Ink & surfaces */
  --ink: #16262c;
  --ink-soft: #45575d;
  --muted: #6a7a80;
  --line: #dde7e9;
  --bg: #ffffff;
  --bg-alt: #f3f9fa;

  --radius: 14px;
  --radius-lg: 22px;
  --max: 1120px;
  --peek: clamp(90px, 15vh, 170px); /* how much of the video peeks above the fold */
  --wave-h: clamp(48px, 6vw, 88px);  /* wave divider height = section overlap amount */
  --map-pos: 50% 59%;   /* map texture framing: pushed past centre so Brunel ward,
                           which sits low in the SVG, stays in frame */
  --shadow: 0 10px 30px -12px rgba(13, 63, 77, 0.28);
  --shadow-sm: 0 4px 14px -8px rgba(13, 63, 77, 0.30);
  --font: "Segoe UI", system-ui, -apple-system, Roboto, Helvetica, Arial, sans-serif;
  --font-display: "Georgia", "Times New Roman", serif;
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  font-family: var(--font);
  color: var(--ink);
  background: var(--bg);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

.container {
  width: 100%;
  max-width: var(--max);
  margin: 0 auto;
  padding: 0 1.4rem;
}

h1, h2, h3, h4 {
  font-family: var(--font-display);
  line-height: 1.15;
  letter-spacing: -0.01em;
  margin: 0 0 0.5em;
  color: var(--water-dark);
}
h1 { font-size: clamp(2.1rem, 5.2vw, 3.4rem); }
h2 { font-size: clamp(1.55rem, 3.2vw, 2.4rem); }
h3 { font-size: clamp(1.15rem, 2vw, 1.4rem); }

p { margin: 0 0 1rem; }
a { color: var(--water-deep); }

.eyebrow {
  display: inline-block;
  font-family: var(--font);
  text-transform: uppercase;
  letter-spacing: 0.14em;
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--water);
  margin-bottom: 0.6rem;
}

.lead { font-size: 1.18rem; color: var(--ink-soft); }

.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; left: -999px; top: 0; z-index: 100;
  background: var(--water-dark); color: #fff;
  padding: 0.6rem 1rem; border-radius: 0 0 8px 0;
}
.skip-link:focus { left: 0; }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; gap: 0.5rem;
  background: var(--water); color: #fff;
  padding: 0.8rem 1.5rem; border-radius: 999px;
  text-decoration: none; font-weight: 600; font-family: var(--font);
  border: 2px solid var(--water); cursor: pointer;
  transition: transform 0.06s ease, background 0.15s ease, box-shadow 0.15s ease;
  box-shadow: var(--shadow-sm);
}
/* Hover fills the middle and leaves the border where it is. Darkening both at
   once made the whole button lurch a shade on hover; holding the edge steady
   keeps the shape put and reads as the inside lighting up. Applies to every
   variant below, so none of them should set border-color on hover either. */
.btn:hover { background: var(--water-deep); }
.btn:active { transform: translateY(1px); }
.btn-sm { padding: 0.5rem 1.1rem; font-size: 0.9rem; box-shadow: none; }
.btn-lg { padding: 0.95rem 1.9rem; font-size: 1.05rem; }
.btn-outline { background: transparent; color: var(--water-deep); box-shadow: none; }
.btn-outline:hover { background: var(--water); color: #fff; }
.btn-ghost { background: rgba(255,255,255,0.12); color: #fff; border-color: rgba(255,255,255,0.5); box-shadow: none; }
.btn-ghost:hover { background: #fff; color: var(--water-deep); border-color: #fff; }
.btn-sun { background: var(--sun); border-color: var(--sun); color: var(--ink); }
.btn-sun:hover { background: #d0942f; }

/* ---------- Header ---------- */
.site-header {
  position: fixed; top: 0; left: 0; right: 0; z-index: 50;
  background: transparent;
  transition: background 0.3s ease, box-shadow 0.3s ease;
}
/* Semitransparent over the hero image at the top of the page */
.site-header:not(.scrolled) {
  background: linear-gradient(to bottom, rgba(13,63,77,0.42), rgba(13,63,77,0.10));
  backdrop-filter: saturate(1.2) blur(3px);
}
.site-header:not(.scrolled) .brand,
.site-header:not(.scrolled) .brand-text strong { color: #fff; }
.site-header:not(.scrolled) .nav-links a { color: rgba(255,255,255,0.92); }
.site-header:not(.scrolled) .nav-links a:hover,
.site-header:not(.scrolled) .nav-links a[aria-current="page"] { color: #fff; }
.site-header:not(.scrolled) .nav-links a[aria-current="page"]::after { background: #fff; }
.site-header:not(.scrolled) .nav-toggle span { background: #fff; }
.site-header:not(.scrolled) .brand-mark { box-shadow: 0 0 0 2px rgba(255,255,255,0.8); }

/* Solid once the user scrolls, or while the mobile menu is open */
.site-header.scrolled,
.site-header:has(.nav-links.open) {
  background: rgba(255,255,255,0.96);
  backdrop-filter: saturate(1.4) blur(8px);
  box-shadow: var(--shadow-sm);
}
/* When the menu is open over a transparent (unscrolled) header, use dark marks */
.site-header:not(.scrolled):has(.nav-links.open) .brand,
.site-header:not(.scrolled):has(.nav-links.open) .brand-text strong { color: var(--ink); }
.site-header:not(.scrolled):has(.nav-links.open) .nav-toggle span { background: var(--ink); }
.site-header:not(.scrolled):has(.nav-links.open) .brand-mark { box-shadow: 0 0 0 2px rgba(255,255,255,0.55); }
.nav { display: flex; align-items: center; justify-content: space-between; min-height: 68px; }
.brand { display: flex; align-items: center; gap: 0.6rem; text-decoration: none; color: var(--ink); }
.brand-mark {
  width: 30px; height: 30px; border-radius: 50%; flex: none;
  object-fit: cover; display: block;
  background: var(--water-light);
  /* Ring sits on top of the photo, so it has to be a separate shadow layer
     rather than the inset shadow a background-only mark could use. */
  box-shadow: 0 0 0 2px rgba(255,255,255,0.55);
}
.brand-text { font-family: var(--font-display); font-size: 1.15rem; letter-spacing: -0.01em; }
.brand-text strong { color: var(--water-deep); }

.nav-links { display: flex; align-items: center; gap: 1.6rem; list-style: none; margin: 0; padding: 0; }
.nav-links a {
  color: var(--ink-soft); text-decoration: none; font-weight: 500;
  padding: 0.3rem 0; position: relative;
}
.nav-links a:hover { color: var(--water-deep); }
.nav-links a[aria-current="page"] { color: var(--water-deep); }
.nav-links a[aria-current="page"]::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -2px;
  height: 2px; background: var(--water); border-radius: 2px;
}

.nav-toggle {
  display: none; flex-direction: column; gap: 5px;
  background: none; border: 0; cursor: pointer; padding: 8px;
}
.nav-toggle span { display: block; width: 24px; height: 2px; background: var(--ink); border-radius: 2px; transition: 0.2s; }

/* ---------- Map texture (real OSM shorelines: Lake Vernon, Fairy Lake, etc.) --- */
.topo-bg { position: relative; }
.topo-bg::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: url("/assets/img/map-huntsville.svg") var(--map-pos) / cover no-repeat;
  opacity: var(--topo-opacity, 0.2);
  mix-blend-mode: multiply;
}
.topo-bg > * { position: relative; z-index: 1; }
/* Push the shorelines further back where a section is carrying a big block of
   copy rather than a heading and some cards — at the default weight the
   linework runs straight through the text and costs real legibility. */
.topo-soft { --topo-opacity: 0.09; }

/* ---------- Hero ---------- */
/* Solid water-tint gradient; the OSM lake/map texture (below, via ::before) is
   the only imagery. To use a real Muskoka photo later, layer it in here. */
.hero {
  position: relative; overflow: hidden; color: #fff;
  background: linear-gradient(165deg, var(--water) 0%, var(--water-deep) 55%, var(--water-dark) 100%);
}
.hero::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: url("/assets/img/map-huntsville-light.svg") var(--map-pos) / cover no-repeat;
  opacity: 0.22;
}
.hero-inner {
  position: relative; z-index: 1; max-width: 760px;
  padding-top: clamp(2.5rem, 6vw, 4.5rem);
  padding-bottom: clamp(3.5rem, 7vw, 5.5rem);
}
.hero h1 { color: #fff; }
.hero .lead { color: rgba(255,255,255,0.94); }
.hero-office {
  display: inline-block; max-width: 100%;
  background: rgba(255,255,255,0.14); border: 1px solid rgba(255,255,255,0.3);
  padding: 0.4rem 0.9rem; border-radius: 999px; font-size: 0.9rem; margin-bottom: 1.1rem;
}
.hero-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 0.9rem; margin-top: 1.6rem; }
.hero-office-pill {
  display: inline-flex; align-items: center; max-width: 100%;
  margin: 0.2rem 0 1.2rem;
  background: rgba(255,255,255,0.12); border: 1px solid rgba(255,255,255,0.28);
  color: rgba(255,255,255,0.92); border-radius: 999px;
  padding: 0.5rem 1.05rem; font-size: 0.92rem; line-height: 1.3;
}

/* Fullscreen home hero. The copy area fills (100dvh − peek) so the video,
   which lives in the SAME section, peeks above the fold — with the hero's
   tint + map background continuous behind everything (no seam, no color band). */
.hero-full { display: flex; flex-direction: column; }
.hero-copy-area {
  min-height: calc(100dvh - var(--peek));
  display: grid; grid-template-columns: minmax(0, 1fr); align-content: center;
}
.hero-full .hero-inner { padding-top: clamp(5rem, 12vh, 8rem); }
.hero-video-wrap {
  position: relative; z-index: 1;
  padding-bottom: clamp(2.5rem, 6vw, 4rem);
  scroll-margin-top: 84px; /* clear the fixed header when "Learn More" scrolls here */
}
/* Keep the announcement video from feeling oversized on wide screens. */
.hero-video-wrap .video { max-width: 820px; margin-inline: auto; }

/* Big screens. The type ramp above and the 820px video cap are tuned for a
   laptop; on a 27"+ display they leave the headline small and marooned in a lot
   of empty water with the video smaller than the room available.
   The breakpoint starts at 1600px ON PURPOSE — a 13" MacBook Air reports
   1440–1470 CSS px, and that size is already right. Anything at or under a
   laptop must come through here unchanged, so do not lower this.
   Only the hero's own type and the video grow; the container is left alone so
   the hero copy stays aligned with the header above it. */
@media (min-width: 1600px) {
  .hero-full .hero-inner { max-width: 56rem; }
  .hero-full h1 { font-size: clamp(3.4rem, 3.2vw, 4.8rem); }
  .hero-full .lead { font-size: clamp(1.18rem, 1.1vw, 1.5rem); }
  /* Room is there, so let the video use the full container. 80vw keeps it short
     enough to still clear the fold on a wide but shallow screen. */
  .hero-video-wrap .video { max-width: min(1080px, 80vw); }
}

/* Genuinely large displays. Past this point the fix isn't the hero alone — the
   whole 1120px column reads as an island. --max is raised globally instead, so
   the header, hero, and every section widen together and stay aligned with each
   other. Kept well clear of any laptop size for the reason above. */
@media (min-width: 1900px) {
  :root { --max: 1320px; }
  .hero-video-wrap .video { max-width: min(1280px, 80vw); }
}

/* Compact interior page header — bigger type + accent rule */
.page-hero { min-height: 38vh; display: grid; grid-template-columns: minmax(0, 1fr); align-content: center; }
.page-hero .page-hero-inner {
  padding-top: clamp(7.5rem, 16vh, 11rem);
  padding-bottom: clamp(1.5rem, 3.5vw, 2.3rem);
  position: relative; z-index: 1;
}
.page-hero h1 { color: #fff; max-width: 20ch; font-size: clamp(2.4rem, 5.5vw, 3.6rem); }
.page-hero .lead { color: rgba(255,255,255,0.94); max-width: 60ch; }
.page-hero-cta { margin-top: 1.4rem; margin-bottom: 0; }
.page-hero-rule {
  display: block; width: 64px; height: 4px; margin-top: 1.4rem;
  background: var(--sun); border-radius: 4px;
}

/* Release header. A press release goes darker than any other page — the water
   ramp taken past --water-dark — so it reads as an announcement before a word
   of it is. The news index keeps the standard header; it's a listing, not a
   release. The map texture lifts slightly to stay legible on the deeper base. */
.page-hero-news {
  background: linear-gradient(165deg, var(--water-deep) 0%, var(--water-dark) 55%, #072b36 100%);
}
.page-hero-news::before { opacity: 0.26; }

/* The copy sits in a light frosted panel — the visual equivalent of a masthead
   block, and near-white against the darkest background on the site. Because the
   panel is light, everything inside it flips back to ink; .page-hero's white
   type is for copy sitting straight on the gradient. */
.page-hero-news .page-hero-panel {
  position: relative;
  max-width: 46rem;
  padding: clamp(1.4rem, 3vw, 2rem) clamp(1.3rem, 3vw, 2.2rem);
  border: 1px solid rgba(255, 255, 255, 0.45);
  border-radius: var(--radius-lg);
  /* Genuinely translucent: the shoreline linework has to stay READABLE through
     the panel, which is what makes it look like glass. A heavy blur defeats
     that — it smears the map into flat colour and the panel just reads solid —
     so the blur is only enough to soften, not erase. At 0.72 the composite
     lands near #bdcbcf, which is why the type inside drops to --ink /
     --water-dark below; --ink-soft would only clear 4.2:1 here. */
  background: rgba(255, 255, 255, 0.72);
  -webkit-backdrop-filter: blur(3px) saturate(1.15);
          backdrop-filter: blur(3px) saturate(1.15);
  box-shadow: 0 22px 50px -26px rgba(0, 0, 0, 0.6);
}
.page-hero-news .page-hero-panel h1 { color: var(--water-dark); }
.page-hero-news .page-hero-panel .lead { color: var(--ink); }
.page-hero-news .page-hero-panel .eyebrow { color: var(--water-dark); }
.page-hero-news .page-hero-panel .news-dot { color: rgba(13, 63, 77, 0.45); }
/* Rationed --sun, same 64x4 rule as .page-hero-rule, moved to the panel edge. */
.page-hero-news .page-hero-panel::before {
  content: ""; position: absolute; top: -1px; left: clamp(1.3rem, 3vw, 2.2rem);
  width: 64px; height: 4px; border-radius: 0 0 4px 4px; background: var(--sun);
}
.page-hero-news .page-hero-panel > :first-child { margin-top: 0.4rem; }
.page-hero-news .page-hero-panel > :last-child { margin-bottom: 0; }
.page-hero-news .eyebrow { margin-bottom: 0.7rem; }
/* Release headlines are sentences, not two-word page titles, so they get a
   smaller, tighter setting than .page-hero h1 — otherwise a long one runs to
   five display-sized lines and pushes the release itself off the fold. */
.page-hero-news h1 {
  max-width: 26ch;
  font-size: clamp(1.75rem, 3.4vw, 2.5rem);
  line-height: 1.15;
}
.page-hero-news .lead { font-size: 1.05rem; max-width: 54ch; }


/* Video facade */
.video { position: relative; }
.video-facade {
  display: flex; flex-direction: column; justify-content: flex-end;
  width: 100%; aspect-ratio: 16 / 9; border: 0; cursor: pointer;
  border-radius: var(--radius-lg); overflow: hidden;
  background-size: cover; background-position: center;
  box-shadow: var(--shadow); color: #fff; text-align: left;
  padding: 1rem 1.2rem;
}
.video-placeholder { cursor: default; }
.video-facade::before {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(13,63,77,0.55), rgba(13,63,77,0.05) 55%);
}
.video-play {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: 74px; height: 74px; border-radius: 50%;
  background: rgba(255,255,255,0.92); box-shadow: var(--shadow);
  transition: transform 0.15s ease;
}
.video-play::after {
  content: ""; position: absolute; top: 50%; left: 54%; transform: translate(-50%, -50%);
  border-style: solid; border-width: 13px 0 13px 21px;
  border-color: transparent transparent transparent var(--water-deep);
}
.video-facade:hover .video-play { transform: translate(-50%, -50%) scale(1.06); }
.video-label { position: relative; font-weight: 600; }
.video iframe { width: 100%; aspect-ratio: 16 / 9; border: 0; border-radius: var(--radius-lg); display: block; }

/* Background-warmed player (main.js adds .is-warm). The iframe loads behind the
   poster, so the facade becomes an overlay and .video has to hold the box open
   itself — the facade is no longer in flow to do it. On click the poster fades
   off a player that's already there. */
.video.is-warm { aspect-ratio: 16 / 9; overflow: hidden; border-radius: var(--radius-lg); }
.video.is-warm iframe { position: absolute; inset: 0; height: 100%; aspect-ratio: auto; }
.video.is-warm .video-facade {
  position: absolute; inset: 0; z-index: 3;
  transition: opacity 0.3s ease;
}
.video.is-warm.is-playing .video-facade { opacity: 0; pointer-events: none; }

/* Custom player chrome. YouTube's own is off (controls=0) so the title and
   share overlay go with it, which means everything below has to stand in for
   it — see the note at the top of the video block in main.js. */

/* Click target over the iframe: play/pause, and double-click for full screen.
   It also stops stray clicks reaching YouTube's player underneath. */
.video-stage { position: absolute; inset: 0; z-index: 1; cursor: pointer; }

.video-controls {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  display: flex; align-items: center; gap: 0.5rem;
  padding: 1.6rem 0.75rem 0.6rem;
  background: linear-gradient(to top, rgba(13, 63, 77, 0.88), rgba(13, 63, 77, 0));
  opacity: 0; pointer-events: none;
  transition: opacity 0.16s ease;  /* leaving: quick, so they're gone off the edge */
}
/* Hidden by default — including on first play, so the video starts clean. The
   pointer moving over the video brings them up (main.js adds .is-hot); they go
   again after a pause, or the moment the pointer leaves. */
.video.is-playing.is-hot .video-controls {
  opacity: 1; pointer-events: auto;
  transition-duration: 0.22s;  /* arriving: a touch softer than leaving */
}
/* Keyboard focus must always win: controls that vanish while being tabbed
   through are unusable. */
.video-controls:focus-within { opacity: 1 !important; pointer-events: auto; }

.vc-btn {
  flex: none; display: grid; place-items: center;
  width: 34px; height: 34px; padding: 0;
  border: 0; border-radius: 50%; background: transparent;
  color: #fff; cursor: pointer;
  transition: background-color 0.15s ease, transform 0.15s ease;
}
.vc-btn svg { width: 21px; height: 21px; fill: currentColor; display: block; }
.vc-btn:hover { background: rgba(255, 255, 255, 0.18); }
.vc-btn:active { transform: scale(0.94); }
.vc-btn:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.vc-yt:hover { background: rgba(255, 255, 255, 0.18); color: #fff; }

.vc-time {
  flex: none; font-size: 0.78rem; font-variant-numeric: tabular-nums;
  color: rgba(255, 255, 255, 0.92); user-select: none;
}
.vc-sep { opacity: 0.6; }

/* Track is painted with a gradient driven by --progress, which main.js updates;
   the thumb rides on top of it. */
.vc-seek {
  -webkit-appearance: none; appearance: none;
  flex: 1 1 auto; min-width: 0; height: 4px; margin: 0;
  border-radius: 999px; cursor: pointer; background: linear-gradient(
    to right,
    var(--sun) var(--progress, 0%),
    rgba(255, 255, 255, 0.35) var(--progress, 0%)
  );
}
.vc-seek::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 13px; height: 13px; border: 0; border-radius: 50%;
  background: #fff; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.45);
}
.vc-seek::-moz-range-thumb {
  width: 13px; height: 13px; border: 0; border-radius: 50%;
  background: #fff; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.45);
}
.vc-seek:focus-visible { outline: 2px solid #fff; outline-offset: 4px; }

/* Full screen: the wrapper goes fullscreen rather than the iframe, so these
   controls come along instead of being left behind on the page. */
.video.is-fullscreen {
  aspect-ratio: auto; width: 100%; height: 100%;
  max-width: none;  /* beats the 820px cap .hero-video-wrap puts on it */
  border-radius: 0; background: #000;
}
.video.is-fullscreen iframe { border-radius: 0; }

/* Room is tight on phones: the elapsed/total readout is the first thing to go. */
@media (max-width: 480px) {
  .video-controls { gap: 0.3rem; padding: 1.4rem 0.5rem 0.5rem; }
  .vc-time { display: none; }
}

/* Touch: a 34px circle is under the 44px minimum, and with four controls in a
   row on a phone the misses land on the seek bar or on play/pause. The visible
   circle stays the same size; the tappable box around it grows. */
@media (pointer: coarse) {
  .video-controls { gap: 0.15rem; padding-bottom: 0.35rem; }
  .vc-btn { width: 44px; height: 44px; }
  .vc-btn:hover { background: transparent; }  /* no hover to leave stuck on */
  .vc-yt:hover { background: transparent; }
  /* A 4px track is hard to hit and easy to nudge; give it a real grab area. */
  .vc-seek { height: 5px; padding-block: 14px; background-clip: content-box; }
}

@media (prefers-reduced-motion: reduce) {
  .video.is-warm .video-facade,
  .video-controls { transition: none; }
  .vc-btn { transition: none; }
}

/* ---------- Water dividers ---------- */
/* The section overlaps the one above by a wave-height; its own top edge is cut
   into a wave with a mask, so the section's real background + map texture fill
   the peaks while the gaps reveal the textured section above (seamless). The
   mask is a sum-of-sines wave that is exactly periodic, so it tiles + loops with
   no seam/hitch; it drifts sideways so the shoreline moves. */
.section.has-wave {
  position: relative;
  margin-top: calc(-1 * var(--wave-h));
  padding-top: calc(clamp(3rem, 6vw, 5rem) + var(--wave-h));
  background: var(--bg);
  --wave-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 100' preserveAspectRatio='none'%3E%3Cpath fill='black' d='M0.0,60.0 L15.0,59.7 L30.0,59.4 L45.0,59.1 L60.0,58.8 L75.0,58.5 L90.0,58.3 L105.0,58.0 L120.0,57.8 L135.0,57.6 L150.0,57.4 L165.0,57.3 L180.0,57.2 L195.0,57.1 L210.0,57.0 L225.0,57.0 L240.0,57.0 L255.0,57.1 L270.0,57.2 L285.0,57.4 L300.0,57.6 L315.0,57.8 L330.0,58.1 L345.0,58.5 L360.0,58.8 L375.0,59.2 L390.0,59.6 L405.0,60.0 L420.0,60.5 L435.0,60.9 L450.0,61.3 L465.0,61.7 L480.0,62.0 L495.0,62.3 L510.0,62.6 L525.0,62.9 L540.0,63.2 L555.0,63.4 L570.0,63.6 L585.0,63.7 L600.0,63.9 L615.0,64.1 L630.0,64.2 L645.0,64.4 L660.0,64.6 L675.0,64.9 L690.0,65.2 L705.0,65.6 L720.0,66.0 L735.0,66.5 L750.0,67.1 L765.0,67.7 L780.0,68.5 L795.0,69.2 L810.0,70.1 L825.0,71.0 L840.0,71.9 L855.0,72.8 L870.0,73.8 L885.0,74.7 L900.0,75.6 L915.0,76.5 L930.0,77.3 L945.0,78.0 L960.0,78.6 L975.0,79.2 L990.0,79.6 L1005.0,79.8 L1020.0,80.0 L1035.0,80.0 L1050.0,79.8 L1065.0,79.5 L1080.0,79.1 L1095.0,78.6 L1110.0,77.9 L1125.0,77.2 L1140.0,76.3 L1155.0,75.4 L1170.0,74.4 L1185.0,73.3 L1200.0,72.3 L1215.0,71.2 L1230.0,70.1 L1245.0,69.1 L1260.0,68.1 L1275.0,67.1 L1290.0,66.2 L1305.0,65.3 L1320.0,64.5 L1335.0,63.7 L1350.0,63.0 L1365.0,62.4 L1380.0,61.8 L1395.0,61.3 L1410.0,60.8 L1425.0,60.4 L1440.0,60.0 L1440.0,100 L0,100 Z'/%3E%3C/svg%3E");
  -webkit-mask: var(--wave-mask) 0 0 / 1440px var(--wave-h) repeat-x, linear-gradient(#000 0 0) 0 100% / 100% calc(100% - var(--wave-h) + 1px) no-repeat;
          mask: var(--wave-mask) 0 0 / 1440px var(--wave-h) repeat-x, linear-gradient(#000 0 0) 0 100% / 100% calc(100% - var(--wave-h) + 1px) no-repeat;
  animation: wave-clip 26s linear infinite;
}
@keyframes wave-clip {
  from { -webkit-mask-position: 0 0, 0 100%; mask-position: 0 0, 0 100%; }
  to   { -webkit-mask-position: 1440px 0, 0 100%; mask-position: 1440px 0, 0 100%; }
}
.section-alt.has-wave { background: var(--bg-alt); }
.cta.has-wave { background: var(--pine); }

/* Preceding section: relative (for the accent wave) + room for the overlap. */
.hero:has(+ .section.has-wave),
.section:has(+ .section.has-wave),
.endorse-band:has(+ .section.has-wave) { position: relative; }
.hero:has(+ .section.has-wave) { padding-bottom: calc(var(--wave-h) + 0.5rem); }
.section:has(+ .section.has-wave) { padding-bottom: calc(clamp(3rem, 6vw, 5rem) + var(--wave-h)); }
.endorse-band:has(+ .section.has-wave) { padding-bottom: calc(clamp(2rem, 4vw, 3rem) + var(--wave-h)); }

/* One accent wave behind the shoreline, drawn in the section ABOVE (so the front
   mask doesn't clip it), drifting the opposite way via a cheap GPU transform. It
   is a solid --accent colour behind a wave-shaped mask, so the tint is easy to
   change per transition.
   HOW TO USE / IMPORTANT: --accent must be a colour that works for BOTH sides —
   it has to be visible against the section it SITS in (the one above) and still
   read sensibly against the section below. Semi-transparent white reads as foam
   on the dark hero, but over a LIGHT section (e.g. the light section just before
   the pine "Let's talk about your priorities" CTA) white is invisible, so those
   are tinted instead. Set --accent per preceding section below.
   It is over-sized (left/right: -1500px) so the transform loop never runs past
   the element edge and glitches — it always covers the viewport. */
.hero:has(+ .section.has-wave)::after,
.section:has(+ .section.has-wave)::after,
.endorse-band:has(+ .section.has-wave)::after {
  content: ""; position: absolute; left: -1500px; right: -1500px;
  bottom: calc(-0.15 * var(--wave-h)); /* tuck it down, more under the main wave */
  height: calc(var(--wave-h) * 1.9); pointer-events: none; will-change: transform;
  --accent: rgba(255, 255, 255, 0.22); /* default: sits over the dark hero */
  background: var(--accent);
  --accent-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 100' preserveAspectRatio='none'%3E%3Cpath fill='black' d='M0.0,61.5 L15.0,61.5 L30.0,61.5 L45.0,61.6 L60.0,61.8 L75.0,62.0 L90.0,62.3 L105.0,62.6 L120.0,63.0 L135.0,63.5 L150.0,64.0 L165.0,64.6 L180.0,65.2 L195.0,65.9 L210.0,66.7 L225.0,67.5 L240.0,68.3 L255.0,69.1 L270.0,70.0 L285.0,70.9 L300.0,71.8 L315.0,72.7 L330.0,73.6 L345.0,74.5 L360.0,75.3 L375.0,76.1 L390.0,76.9 L405.0,77.6 L420.0,78.3 L435.0,78.9 L450.0,79.5 L465.0,79.9 L480.0,80.4 L495.0,80.7 L510.0,80.9 L525.0,81.1 L540.0,81.2 L555.0,81.2 L570.0,81.1 L585.0,81.0 L600.0,80.8 L615.0,80.5 L630.0,80.1 L645.0,79.7 L660.0,79.3 L675.0,78.7 L690.0,78.2 L705.0,77.6 L720.0,77.0 L735.0,76.4 L750.0,75.7 L765.0,75.1 L780.0,74.4 L795.0,73.8 L810.0,73.1 L825.0,72.5 L840.0,71.9 L855.0,71.3 L870.0,70.8 L885.0,70.3 L900.0,69.8 L915.0,69.3 L930.0,68.9 L945.0,68.5 L960.0,68.2 L975.0,67.9 L990.0,67.6 L1005.0,67.3 L1020.0,67.0 L1035.0,66.8 L1050.0,66.6 L1065.0,66.4 L1080.0,66.2 L1095.0,66.0 L1110.0,65.9 L1125.0,65.7 L1140.0,65.5 L1155.0,65.3 L1170.0,65.1 L1185.0,64.9 L1200.0,64.7 L1215.0,64.5 L1230.0,64.3 L1245.0,64.0 L1260.0,63.8 L1275.0,63.5 L1290.0,63.3 L1305.0,63.0 L1320.0,62.8 L1335.0,62.5 L1350.0,62.3 L1365.0,62.1 L1380.0,61.9 L1395.0,61.7 L1410.0,61.6 L1425.0,61.5 L1440.0,61.5 L1440.0,100 L0,100 Z'/%3E%3C/svg%3E");
  -webkit-mask: var(--accent-mask) 0 bottom / 1440px 100% repeat-x;
          mask: var(--accent-mask) 0 bottom / 1440px 100% repeat-x;
  animation: drift-accent 34s linear infinite;
}
/* A light section above -> tint the wave so it is actually visible. */
.section:has(+ .section.has-wave)::after,
.endorse-band:has(+ .section.has-wave)::after { --accent: rgba(43, 140, 166, 0.34); }
/* ...but when the section BELOW is the green CTA, tint the wave green so it
   makes sense leading into it (must stay visible on the light section above). */
.section:has(+ .cta.has-wave)::after { --accent: rgba(47, 93, 79, 0.5); }
@keyframes drift-accent { from { transform: translateX(0); } to { transform: translateX(-1440px); } }

/* ---------- Sections ---------- */
.section { padding: clamp(3rem, 6vw, 5rem) 0; }
.section-alt { background: var(--bg-alt); }
.section-tight { padding: clamp(2rem, 4vw, 3rem) 0; }
.section-head { max-width: 62ch; margin-bottom: 2rem; }
.section p { color: var(--ink-soft); }
.narrow { max-width: 720px; margin-inline: auto; }

/* ---------- Endorsement marquee ---------- */
/* Extra head room over the standard .section-tight step: the band follows a
   full-width section of body copy, and without it the heading sits too close to
   the paragraph above to read as the start of something new. */
.endorse-band {
  background: var(--water-mist); overflow: hidden;
  padding-top: clamp(2.75rem, 5vw, 3.9rem);
}
.marquee {
  display: flex; flex-direction: column; gap: 4rem; overflow: hidden;
  /* Grab-to-scrub (main.js). pan-y leaves vertical scrolling to the browser
     while horizontal drags come to us as pointer events. */
  cursor: grab; touch-action: pan-y;
  /* Selection off entirely. The quotes are moving targets, so a drag across
     them highlights half a sentence and leaves a selection stranded on screen
     — and on iOS a long press pops the selection callout, which is exactly the
     gesture the mobile hint asks people to use to pause. The full text of every
     endorsement is selectable on /endorse/, which is where anyone actually
     wanting to copy one would go. */
  -webkit-user-select: none; user-select: none;
  -webkit-touch-callout: none;
}
.marquee.is-dragging { cursor: grabbing; }
/* Paused while being dragged, and latched off by a click (main.js adds
   .is-paused) so a quote can be read without chasing it across the screen. */
.marquee.is-dragging .marquee-row,
.marquee.is-paused .marquee-row { animation-play-state: paused; }

/* The pause gesture differs by input, so the hint does too: a mouse click
   latches the pause on and off, while a touch pauses only while held (see the
   pointerType check in main.js). Gated on pointer capability rather than on
   width — what matters is what the visitor is pointing with, not how wide their
   screen is. Touch is the default branch so a device reporting neither still
   gets the gesture that works there. */
.marquee-hint { margin: 0.15rem 0 0; font-size: 0.8rem; color: var(--muted); }
.marquee-hint .hint-pointer { display: none; }
@media (hover: hover) and (pointer: fine) {
  .marquee-hint .hint-pointer { display: inline; }
  .marquee-hint .hint-touch { display: none; }
}
.marquee img { -webkit-user-drag: none; }
.marquee-row {
  display: flex; gap: 4.5rem; width: max-content;
  animation: marquee 90s linear infinite;
  /* Own GPU layer so the drifting accent wave overlapping the band can't force
     the row to repaint each frame (that was jittering the second row). */
  will-change: transform;
  backface-visibility: hidden;
}
/* Use a forward animation with reversed keyframes rather than
   animation-direction: reverse — the latter drops the row off the compositor
   in Chromium and jitters. */
.marquee-row.reverse { animation-name: marquee-reverse; }
@keyframes marquee-reverse {
  from { transform: translateX(-50%); }
  to   { transform: translateX(0); }
}
@keyframes marquee {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
.bubble {
  flex: none; max-width: 320px; margin: 0; /* reset <figure> default 1em 40px */
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius-lg);
  padding: 0.9rem 1.1rem; box-shadow: var(--shadow-sm);
}
/* Endorse page: masonry columns so bubbles pack naturally (no stretch/squish) */
.endorse-list { columns: 270px 4; column-gap: 1rem; }
.endorse-list .bubble { width: 100%; max-width: none; margin: 0 0 1rem; break-inside: avoid; }
.endorse-note { text-align: center; color: var(--muted); font-size: 0.9rem; margin-top: 1.5rem; }

.bubble p { margin: 0 0 0.5rem; font-size: 0.98rem; color: var(--ink); }
.bubble .who {
  display: flex; align-items: flex-start; gap: 0.6rem;
  font-size: 0.85rem; line-height: 1.4; color: var(--muted);
}
/* Top-align so a wrapping name/role flows below the avatar rather than
   centring the whole block against it; the nudge re-centres the *first* line
   on the avatar. Keep in sync with the avatar height below. */
.bubble .who > :last-child {
  flex: 1; min-width: 0; padding-top: calc((30px - 1.4em) / 2);
}
.bubble .role::before { content: "·"; padding: 0 0.35rem; }
/* Long role: its own line, so the separator goes and the name stands alone. */
.bubble .who.stacked .role { display: block; }
.bubble .who.stacked .role::before { content: none; }
.bubble .avatar {
  width: 30px; height: 30px; border-radius: 50%; flex: none;
  background: linear-gradient(150deg, var(--water) 0%, var(--pine) 100%);
  color: #fff; display: grid; place-items: center; font-weight: 700; font-size: 0.8rem;
}

/* ---------- Cards / feature grid ---------- */
.grid { display: grid; gap: 1.4rem; }
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
/* Four summary cards: 4 across on desktop, 2x2 on tablets, stacked on phones.
   Explicit steps rather than auto-fit so it never lands on an orphaned 3+1 row. */
.grid-4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 1000px) { .grid-4 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px)  { .grid-4 { grid-template-columns: 1fr; } }
.card {
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius);
  padding: 1.6rem; box-shadow: var(--shadow-sm);
  /* Column flex so a trailing .card-more link can be pushed to the card floor. */
  display: flex; flex-direction: column;
}
.card h3 { color: var(--water-deep); }
.card p { margin: 0; }
.card-icon {
  width: 44px; height: 44px; border-radius: 12px; margin-bottom: 0.9rem;
  background: var(--water-light); display: grid; place-items: center; color: var(--water-deep);
}
/* Numbered variant used for the four platform priorities. Same rounded-square
   box; only the glyph changes, set in the display face so the numeral reads as
   a marker rather than as body copy. */
.card-icon-num {
  font-family: var(--font-display); font-size: 1.3rem; font-weight: 700; line-height: 1;
}

/* "Read more" jump link at the bottom of a platform summary card. Pinned to the
   card's baseline so links line up across cards of differing copy length. */
.card-more { margin: auto 0 0; padding-top: 1.1rem; font-weight: 600; }
.card-more a { text-decoration: none; }
.card-more a::after { content: " →"; }
.card-more a:hover { text-decoration: underline; }

/* ---------- Full platform ---------- */
.platform-block + .platform-block { margin-top: 2.8rem; padding-top: 2.4rem; border-top: 1px solid var(--line); }
/* Offset anchor targets so the fixed header doesn't cover the heading. */
.platform-block { scroll-margin-top: 6rem; }
.platform-block h3 { color: var(--water-deep); margin-bottom: 0.8rem; }
.platform-list { margin: 0; padding-left: 1.15rem; color: var(--ink-soft); }
.platform-list li { margin-bottom: 0.9rem; }
.platform-list li:last-child { margin-bottom: 0; }
.platform-list li::marker { color: var(--water); }
.platform-list strong { color: var(--ink); }

/* Plain-language summary at the top of the privacy policy. Visually set off
   from the policy text so it reads as an on-ramp, not as the policy itself. */
.policy-summary {
  background: var(--water-light); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 1.6rem 1.8rem; margin-bottom: 2.4rem;
}
.policy-summary h2 { margin-top: 0; color: var(--water-deep); }
.policy-summary ul { margin-bottom: 1rem; }
.policy-summary > :last-child { margin-bottom: 0; }

/* ---------- About / split ---------- */
.split { display: grid; grid-template-columns: 0.85fr 1.15fr; gap: 2.5rem; align-items: center; }
.portrait {
  border-radius: var(--radius-lg); overflow: hidden; box-shadow: var(--shadow);
  aspect-ratio: 4 / 5; background: var(--water-light);
}
.portrait img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Contact page photo, under the copy and alongside the form.
   Desktop: the full portrait at its own proportions, in the left column. */
.contact-portrait {
  margin: 1.8rem 0 0; max-width: 380px;
  border-radius: var(--radius-lg); overflow: hidden; box-shadow: var(--shadow);
}
.contact-portrait img { width: 100%; height: auto; display: block; }

/* Phones: .split has collapsed to one column, so the photo sits between the
   copy and the form. The source is a landscape frame, so at full column width
   it's only ~200px tall and the form stays in reach — no cap, no crop, and no
   floating it beside the copy, all of which this needed back when the photo was
   a portrait. See the note in scripts/gen-images.js. */
@media (max-width: 860px) {
  .contact-portrait { max-width: none; }
}

/* Copy that only makes sense once .split has collapsed to one column — a "below"
   pointing at the form, which on desktop is beside the text, not under it. Tied
   to the same 860px breakpoint as .split; if that moves, this has to move with
   it or the word starts lying. */
.when-stacked { display: none; }
@media (max-width: 860px) {
  .when-stacked { display: inline; }
}

/* ---------- CTA band ---------- */
.cta {
  position: relative; overflow: hidden; color: #fff; text-align: center;
  background: var(--pine);
}
/* Texture here is a real photo — sunset over the water — rather than the map
   linework used everywhere else, so the closing band feels like a place
   instead of another diagram. It is pushed a long way back: at 0.2 over solid
   --pine nothing in it is legible as a subject, which is the point. The desat
   keeps the sunset's orange from fighting the green base.
   The band is far shorter than the photo, so `cover` throws away most of the
   height and the only real decision is which slice survives. 62% lands on the
   horizon and the water below it; top-anchoring was tried and gives up too
   much of that to empty sky. */
.cta::before {
  content: ""; position: absolute; inset: 0;
  background: url("/assets/img/sunset-1800.jpg") center 62% / cover no-repeat;
  opacity: 0.2;
  filter: saturate(0.75);
}
/* Desktop the band is wider, so `cover` scales the photo up and crops more off
   the vertical. Easing the slice back up the frame drops the image lower in the
   band, which keeps the horizon off the copy at that width. */
@media (min-width: 721px) {
  .cta::before { background-position: center 35%; }
}
.cta .container { position: relative; z-index: 1; }
.cta h2 { color: #fff; }
.cta p { color: rgba(255,255,255,0.9); }

/* ---------- Forms / embeds ---------- */
.form-embed {
  position: relative;
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm); overflow: hidden;
}
/* GoHighLevel's form_embed.js sets the iframe's inline height once the form
   renders. We give it an explicit starting height + a height transition, so it
   smoothly grows/shrinks to the loaded size instead of snapping. */
.form-embed .ghl-form { width: 100%; height: 480px; border: 0; display: block; }

/* Graceful load: main.js adds .is-loading (JS present) which shows the spinner
   and hides the iframe; on iframe load it's removed and the form fades in.
   Without JS the class is never added, so the form just shows normally. */
.form-embed .ghl-form { transition: opacity 0.45s ease, height 0.55s ease; }
.form-embed.is-loading .ghl-form { opacity: 0; }
.form-loading {
  position: absolute; inset: 0; z-index: 1; background: #fff;
  display: grid; place-items: center;
  opacity: 0; visibility: hidden; transition: opacity 0.3s ease, visibility 0.3s ease;
}
.form-embed.is-loading .form-loading { opacity: 1; visibility: visible; }
.spinner {
  width: 34px; height: 34px; border-radius: 50%;
  border: 3px solid var(--line); border-top-color: var(--water);
  animation: spin 0.8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
.form-placeholder {
  border: 2px dashed var(--water); border-radius: var(--radius-lg);
  background: var(--water-mist); padding: 2.5rem 1.5rem; text-align: center; color: var(--ink-soft);
}
.form-placeholder code { background: #fff; padding: 0.15rem 0.4rem; border-radius: 6px; border: 1px solid var(--line); }

/* ---------- Floating "Get updates" button + modal ---------- */
.fab {
  position: fixed; right: 1.2rem; bottom: 1.2rem; z-index: 45;
  display: inline-flex; align-items: center; gap: 0.5rem;
  background: var(--sun); color: var(--ink); border: 0; border-radius: 999px;
  padding: 0.8rem 1.3rem; font-family: var(--font); font-weight: 700; font-size: 0.98rem;
  cursor: pointer; box-shadow: var(--shadow);
  transition: transform 0.12s ease, background 0.15s ease;
}
.fab:hover { background: #d0942f; transform: translateY(-2px); }
.fab svg { flex: none; }

/* Secondary page-specific FAB on the opposite corner. Mobile only — on wider
   screens the page's own in-flow buttons are visible without scrolling. */
.fab-left {
  right: auto; left: 1.2rem;
  background: var(--water-deep); color: #fff; text-decoration: none;
}
.fab-left:hover { background: var(--water-dark); }
@media (min-width: 721px) { .fab-left { display: none; } }

.modal {
  width: min(460px, 92vw); max-height: 90vh; overflow: auto;
  padding: 0; border: 0; border-radius: var(--radius-lg); color: var(--ink);
  background: #fff; box-shadow: 0 30px 80px -20px rgba(13, 63, 77, 0.55);
}
.modal::backdrop { background: rgba(13, 63, 77, 0.5); backdrop-filter: blur(2px); }
.modal[open] { animation: modal-in 0.2s ease; }
@keyframes modal-in { from { opacity: 0; transform: translateY(10px) scale(0.98); } to { opacity: 1; transform: none; } }
.modal-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; padding: 1.2rem 1.3rem 0.2rem; }
.modal-head h2 { margin: 0; font-size: 1.3rem; }
.modal-close {
  background: none; border: 0; font-size: 1.9rem; line-height: 1; color: var(--muted);
  cursor: pointer; padding: 0 0.2rem; margin: -0.2rem -0.2rem 0 0;
}
.modal-close:hover { color: var(--ink); }
.modal-sub { padding: 0 1.3rem; margin: 0 0 0.9rem; color: var(--muted); font-size: 0.92rem; }
.modal .form-embed { margin: 0 1.1rem 1.1rem; border-radius: var(--radius); }
/* Start compact so the modal opens small, then animates up to the loaded size. */
.modal .form-embed .ghl-form { height: 240px; }

@media (max-width: 520px) {
  .fab { right: 0.9rem; bottom: 0.9rem; padding: 0.72rem 1.05rem; font-size: 0.92rem; }
  .fab-left { right: auto; left: 0.9rem; }
}

/* ---------- Footer ---------- */
.site-footer { position: relative; background: var(--water-dark); color: #cfe0e4; padding-top: 2.6rem; }
.footer-topo { position: absolute; inset: 0; background: url("/assets/img/map-huntsville-light.svg") var(--map-pos) / cover no-repeat; opacity: 0.14; pointer-events: none; }
.footer-inner { position: relative; display: grid; grid-template-columns: 1.4fr 1fr; gap: 2rem; padding-bottom: 1.8rem; }
.footer-name { font-family: var(--font-display); font-size: 1.3rem; color: #fff; margin: 0 0 0.2rem; }
.footer-role { margin: 0 0 1rem; color: #a9c6cd; font-size: 0.92rem; }
.footer-heading { text-transform: uppercase; letter-spacing: 0.12em; font-size: 0.75rem; color: #8fb2ba; margin: 0 0 0.6rem; }
.footer-nav ul { list-style: none; margin: 0; padding: 0; columns: 2; }
.footer-nav a { color: #cfe0e4; text-decoration: none; display: inline-block; padding: 0.25rem 0; }
.footer-nav a:hover { color: #fff; }
.footer-legal { position: relative; border-top: 1px solid rgba(255,255,255,0.12); padding-top: 1rem; padding-bottom: 1.6rem; }
.footer-legal p { margin: 0; font-size: 0.82rem; color: #9fbdc4; }
.footer-legal .fine-print { opacity: 0.8; }

/* ---------- Button rows ---------- */
.button-row { display: flex; flex-wrap: wrap; gap: 0.9rem; justify-content: center; }

/* ---------- Split button (Instagram / Facebook) ---------- */
.split-btn {
  display: inline-flex; border: 1px solid rgba(255,255,255,0.4);
  border-radius: 999px; overflow: hidden;
}
.split-btn-half {
  display: inline-flex; align-items: center; gap: 0.5rem;
  padding: 0.55rem 1.15rem; color: #fff; text-decoration: none;
  font-weight: 600; font-size: 0.9rem; background: rgba(255,255,255,0.08);
  transition: background 0.15s ease, color 0.15s ease;
}
/* Divider between joined halves. General sibling, not adjacent: the
   .split-btn-break span sits between Facebook and YouTube (it forces the
   two-pill wrap on narrow phones), so an adjacent selector skips YouTube and
   leaves that seam undrawn. */
.split-btn-half ~ .split-btn-half { border-left: 1px solid rgba(255,255,255,0.4); }
.split-btn-half:hover { background: #fff; color: var(--water-deep); }
.split-btn-half svg { flex: none; }

.split-btn-break { display: none; }

/* Narrow phones: three labelled halves are wider than the viewport. The labels
   stay — they're what make the buttons scannable, and the icons alone are a
   guessing game — so the group breaks into two pills instead: Instagram +
   Facebook keep the joined treatment, YouTube drops underneath on its own.
   Because the group is no longer one continuous shape, the border and the
   corner clipping move off the container and onto the halves.
   480px is where the three stop fitting at the narrowest container padding;
   above it they fit comfortably and the group stays a single pill. */
@media (max-width: 480px) {
  .split-btn {
    display: flex; flex-wrap: wrap;
    border: 0; border-radius: 0; overflow: visible;
    row-gap: 0.55rem;
  }
  .split-btn-break { display: block; flex-basis: 100%; height: 0; }
  .split-btn-half {
    border: 1px solid rgba(255,255,255,0.4);
    border-radius: 999px;
  }
  /* Halves that are still directly adjacent stay welded: square the corners
     where they meet and collapse the shared edge. Stated as "is followed by /
     follows another half" rather than by position, so it holds for whichever
     networks site.json actually has switched on — the break element sits
     between, so the pair either side of it is never welded. */
  .split-btn-half:has(+ .split-btn-half) {
    border-top-right-radius: 0; border-bottom-right-radius: 0;
  }
  .split-btn-half + .split-btn-half {
    border-left: 0;
    border-top-left-radius: 0; border-bottom-left-radius: 0;
  }
}

/* ---------- News & press releases ---------- */

/* Listing: stacked boxes, newest first. Numbered <ol> semantically (it's an
   ordered archive) but the markers are dropped — the dates carry the order. */
.news-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 1.2rem; }

.news-item {
  position: relative;
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius);
  padding: 1.5rem 1.7rem; box-shadow: var(--shadow-sm);
  transition: transform 0.12s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}
.news-item:hover {
  transform: translateY(-2px);
  border-color: var(--water);
  box-shadow: var(--shadow);
}
/* Whole box is clickable, but the anchor stays on the heading so the link text
   and target stay meaningful to screen readers and the browser status bar. */
.news-item h2 {
  font-size: clamp(1.25rem, 2.4vw, 1.6rem);
  margin: 0 0 0.5rem;
}
.news-item h2 a { color: var(--water-dark); text-decoration: none; }
.news-item h2 a::after {
  content: ""; position: absolute; inset: 0; border-radius: var(--radius);
}
.news-item:hover h2 a { color: var(--water-deep); }
/* The overlay swallows the anchor's own outline, so put focus on the box. */
.news-item h2 a:focus-visible { outline: none; }
.news-item:has(h2 a:focus-visible) {
  outline: 3px solid var(--water); outline-offset: 3px;
}

.news-meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem;
  margin: 0 0 0.6rem;
  font-size: 0.82rem; color: var(--muted);
}
.news-kind {
  text-transform: uppercase; letter-spacing: 0.12em;
  font-weight: 700; font-size: 0.72rem; color: var(--water);
}
/* On the listing the kind becomes a coloured pill, so press releases and
   statements are tellable apart at a glance. The detail page keeps the plain
   text version above: it sits on the dark hero, where a tinted chip would fight
   the background. Unknown kinds fall through to the blue default. */
.news-item .news-kind {
  padding: 0.15rem 0.55rem; border-radius: 999px;
  font-size: 0.68rem;
  color: var(--water-deep); background: var(--water-light);
}
.news-item .news-kind-statement {
  color: var(--sun-deep); background: var(--sun-light);
}
.news-dot { color: var(--line); }
.news-tag-pdf {
  border: 1px solid var(--line); border-radius: 999px;
  padding: 0.05rem 0.5rem; font-size: 0.7rem; font-weight: 700;
  letter-spacing: 0.06em; color: var(--ink-soft); background: var(--water-mist);
}
.news-summary { color: var(--ink-soft); margin: 0; }
.news-more {
  margin: 0.9rem 0 0; font-weight: 600; font-size: 0.92rem;
  color: var(--water-deep);
}
.news-more::after { content: " →"; }

.news-empty, .news-feed-link { color: var(--ink-soft); }
.news-feed-link {
  margin-top: 2.2rem; padding-top: 1.4rem; border-top: 1px solid var(--line);
  font-size: 0.92rem; text-align: center;
}

/* Single release. Shorter hero than the other interior pages: the headline is
   the content here, so the body should start close to the fold. The "All news"
   link takes over clearing the fixed header, so the usual .page-hero-inner
   top padding would only double it up. */
.page-hero-tight { min-height: 0; }
.page-hero-tight .page-hero-inner { padding-top: 0; }
.news-back { margin: 0 0 1.2rem; padding-top: clamp(6.5rem, 14vh, 9rem); }
.news-back a {
  color: rgba(255,255,255,0.9); text-decoration: none;
  font-size: 0.9rem; font-weight: 600;
}
/* Back arrow, on both the header and footer instances. In CSS rather than in
   the markup so the two can't drift apart, and mirroring how .card-more and
   .news-more attach their forward arrows. Without it "All news" sitting alone
   above the headline reads as a label for what follows rather than as the way
   back out of the release. */
.news-back a::before { content: "←"; padding-right: 0.45rem; }
.news-back a:hover { color: #fff; text-decoration: underline; }
.news-back-foot { margin: 2.4rem 0 0; }
.news-back-foot a { color: var(--water-deep); }

.page-hero .eyebrow { color: rgba(255,255,255,0.85); }
.page-hero .eyebrow .news-dot { color: rgba(255,255,255,0.5); }

.news-dateline { color: var(--ink-soft); margin-bottom: 0.4rem; }
.news-dateline strong { color: var(--ink); }
.news-pdf-inline { font-size: 0.92rem; }
.news-pdf { margin: 2rem 0 0; }

.news-contact {
  margin-top: 2.4rem;
  background: var(--water-light); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 1.4rem 1.7rem;
}
.news-contact h2 { margin: 0 0 0.4rem; font-size: 1.15rem; color: var(--water-deep); }
.news-contact p { margin: 0; }

/* Body copy rendered from markdown — the one place on the site where headings
   and lists come from an author rather than from a template, so it needs its
   own vertical rhythm. */
.prose { color: var(--ink-soft); }
.prose > :first-child { margin-top: 0; }
.prose > :last-child { margin-bottom: 0; }
.prose p { margin: 0 0 1.15rem; }
.prose h2 { font-size: clamp(1.35rem, 2.6vw, 1.7rem); margin: 2.2rem 0 0.7rem; }
.prose h3 { margin: 1.8rem 0 0.6rem; color: var(--water-deep); }
.prose ul, .prose ol { padding-left: 1.15rem; margin: 0 0 1.15rem; }
.prose li { margin-bottom: 0.7rem; }
.prose li::marker { color: var(--water); }
.prose strong { color: var(--ink); }
.prose blockquote {
  margin: 1.6rem 0; padding: 0.2rem 0 0.2rem 1.2rem;
  border-left: 3px solid var(--water); color: var(--ink);
  font-family: var(--font-display); font-size: 1.1rem;
}
.prose blockquote p:last-child { margin-bottom: 0; }
.prose hr { border: 0; border-top: 1px solid var(--line); margin: 2.2rem 0; }
.prose img { max-width: 100%; height: auto; border-radius: var(--radius); }
.prose a { color: var(--water-deep); }

@media (max-width: 520px) {
  .news-item { padding: 1.25rem 1.3rem; }
}

/* ---------- Responsive ---------- */
@media (max-width: 860px) {
  .split { grid-template-columns: 1fr; }
  .split .portrait { max-width: 340px; }
}
@media (max-width: 720px) {
  .nav-toggle { display: flex; }
  .nav-links {
    position: absolute; top: 100%; left: 0; right: 0;
    flex-direction: column; align-items: flex-start; gap: 0;
    background: #fff; border-bottom: 1px solid var(--line);
    padding: 0.5rem 1.4rem 1rem; display: none; box-shadow: var(--shadow);
  }
  .nav-links.open { display: flex; }
  .nav-links li { width: 100%; padding: 0.55rem 0; }
  /* Menu panel is white even when the header is transparent — keep links dark */
  .site-header:not(.scrolled) .nav-links.open a { color: var(--ink-soft); }
  .site-header:not(.scrolled) .nav-links.open a[aria-current="page"] { color: var(--water-deep); }
  .footer-inner { grid-template-columns: 1fr; }
}

/* ---------- Overflow / mobile margins ---------- */
html, body { overflow-x: hidden; }

/* Scroll lock while a modal is open. <dialog>.showModal() takes the page out of
   the tab order and blocks interaction, but it does NOT stop the document
   behind the backdrop from scrolling — a wheel or trackpad gesture still runs
   the page under the dialog, which is disorienting and, on the home page, scrolls
   the hero out from under the modal. main.js adds this on open and removes it on
   close. It has to sit on both elements: html carries the scrollbar here, and
   body would otherwise keep its own. The modal does its own scrolling
   internally (max-height + overflow: auto), so nothing becomes unreachable. */
html.modal-open, html.modal-open body { overflow: hidden; }
/* Phones get MORE side margin than the desktop 1.4rem, not less: with the
   content edge-to-edge there's nothing separating a card or a paragraph from
   the bezel, and the page reads as cramped. This is the one gutter value for
   the whole site — .container is on every section — so changing it here moves
   every page together. */
@media (max-width: 520px) {
  .container { padding-left: 2rem; padding-right: 2rem; }
  .split { gap: 1.6rem; }
}
/* Smallest phones (iPhone SE at 320px): give some of it back, or the gutters
   start eating the line length rather than protecting it. */
@media (max-width: 360px) {
  .container { padding-left: 1.55rem; padding-right: 1.55rem; }
}

/* ---------- Motion safety ---------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .marquee-row,
  .section.has-wave,
  .hero:has(+ .section.has-wave)::after,
  .section:has(+ .section.has-wave)::after,
  .endorse-band:has(+ .section.has-wave)::after { animation: none !important; }
  * { transition-duration: 0.01ms !important; }
}
