/* ==========================================================================
   goodbyepoliticians.movie — Styles v9 (July 11: five-section page)

   Page order: Watch → Reactions → Q&A → The bigger idea → Pass it on → ©.
   Structure of this file:
     1. Design tokens        — every color, size, and rhythm value lives here.
                               The single ~640px breakpoint re-maps tokens once,
                               so all components flip to mobile AS A SET.
     2. Reset + base
     3. Grain overlay        — page-global (fixed), runs over bands too
     4. Anchor bar           — sticky desktop; mobile hides on scroll-down (JS)
     5. Button system        — text buttons + icon buttons, all token-sized
     6. Hero (Watch)         — player fit-math, share rail/row, door button
     7. Section scaffolding  — tones, headings, rhythm; then per-section
                               blocks (Reactions · Pass it on panels ·
                               Q&A accordion · Bigger-idea prose + facade)
     8. Senja popup overrides (unchanged, settled)
     9. Legacy fallbacks     — pre-iOS-15 Safari
   ========================================================================== */

/* --------------------------------------------------------------------------
   0. Font — Montserrat, self-hosted (audit fix: Google's CSS was the one
   render-blocking cross-origin fetch on the page). Single variable-font
   woff2 covers both weights used (400, 600); declared as two fixed-weight
   faces for maximum old-Safari compatibility. Preloaded in index.html.
   -------------------------------------------------------------------------- */
@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('assets/fonts/montserrat-latin.woff2') format('woff2');
}
@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('assets/fonts/montserrat-latin.woff2') format('woff2');
}

/* --------------------------------------------------------------------------
   1. Design tokens
   -------------------------------------------------------------------------- */
:root {
  interpolate-size: allow-keywords; /* lets the Q&A accordion animate to auto */

  /* Palette (grayscale + accents, settled). Only tokens the page uses are
     defined — changing one changes the page. The FULL brand palette, for
     the record (currently unused on this page):
       red-bright #E9474A · blue-bright #3983C1 · off-white #F2F2F2
       grey-lightest #D8D8D8 · grey-silver #C0C0C0 · grey-dark #A1A1A1
     (The hero corner gradients use grey-lightest/silver as rgba literals —
     alpha variants can't be derived from hex tokens without color-mix(),
     which is off-limits for the pre-iOS-15 audience.) */
  --color-primary: #0C0C10;
  --color-red-core: #DE1317;   /* "pass it on" — Share-it icons only */
  --color-red-deep: #AE1114;   /* red hover */
  --color-blue-core: #0E6EAA;  /* the page's invitation */
  --color-blue-deep: #106198;  /* blue hover / link hover */
  --color-white: #FFFFFF;
  --color-utility: #333333;    /* share rail, Donate */
  --color-band: #E9E9E9;       /* section bands + bar frost — pure gray */

  --hairline: 1px solid rgba(12, 12, 16, 0.08);   /* band edges, panel borders */
  --hairline-mid: 1px solid rgba(12, 12, 16, 0.14); /* FAQ rows (M2) */

  /* Layout rhythm — fluid between the 390 and 1440 masters:
     side padding 20px → 64px, section vertical padding 64px → 112px,
     H2 24px → 32px. Tablet is interpolation by design, not accident. */
  --section-padding-x: clamp(20px, 5vw, 64px);
  --section-pad-y: clamp(64px, 46px + 4.6vw, 112px);
  --column-max: 680px;   /* the one content column (panels, FAQ, reel cap ~) */

  /* Type */
  --font-stack: 'Montserrat', system-ui, -apple-system, 'Segoe UI', Arial, sans-serif;
  --fs-h2: clamp(1.5rem, 1.3125rem + 0.77vw, 2rem); /* 24px → 32px */
  --fs-body: 16px;
  --lh-body: 1.7;

  /* Components — stepped tokens; the 640 breakpoint re-maps these */
  --bar-h: 44px;             /* anchor bar */
  --bar-link-fs: 14px;       /* matches the button type scale (Adam, July 9) */
  --bar-link-ls: 0.08em;
  --bar-gap: 44px;
  --btn-h: 46px;             /* text buttons (total height, border-box) */
  --btn-pad-x: 24px;
  --btn-fs: 14px;
  --btn-ls: 0.06em;
  --btn-gap: 10px;           /* label ↔ chevron in the door button */
  --chevron-size: 18px;
  --icon-btn: 44px;          /* rail/row share buttons (square) */
  --icon-size: 20px;
  --fs-h3: 20px;             /* panel block titles */
  --panel-pad: 36px 40px;
  --panel-gap: 20px;
  --panel-icon-w: 56px;      /* red Share-it buttons */
  --panel-icon-h: 52px;
  --panel-icon-size: 22px;
  --fs-q: 17px;              /* FAQ question */
  --lh-q: 1.5;
  --fs-a: 15.5px;            /* FAQ answer */
  --lh-a: 1.7;
  --glyph-fs: 26px;          /* FAQ +/− indicator */

  /* Hero fit-math: cap player width so the whole frame fits above the fold.
     Budget = door-button slot (46 + 28 gap, always reserved so the player
     never shifts when the button fades in) + proportional breathing
     (10vh above + 10vh below the player group) + the bar, which sits in
     normal flow again (two-state bar, July 11). One fluid formula.
     At 1440×900 → player ~1070px. */
  --chrome-height: calc(74px + 20vh + var(--bar-h));

  --radius: 3px;
  --embed-shadow: 0 8px 40px rgba(12, 12, 16, 0.22), 0 2px 6px rgba(12, 12, 16, 0.12);
  --btn-shadow: 0 4px 24px rgba(12, 12, 16, 0.1), 0 1px 3px rgba(12, 12, 16, 0.06);

  --ease-out: cubic-bezier(0.25, 0.46, 0.45, 0.94);
  --transition-fast: 150ms var(--ease-out);

  /* Stacking order (bottom → top):
     content < grain < video embeds < bar < third-party popups (Senja).
     The video embeds sit ABOVE the grain on purpose (Firefox fix): a
     playing cross-origin video is promoted to a hardware overlay surface,
     and the grain's mix-blend-mode can't composite against it — the raw
     noise paints over the video AND the blended layer eats clicks meant for
     the player. Lifting the embeds out from under the grain fixes both.
     The bar then has to clear the embeds too, or a reel scrolling past it
     would paint over the nav. Trade-off: grain no longer textures the bar
     itself — imperceptible on the 44px frost, and its backdrop-filter still
     blurs the grain sitting behind it. */
  --z-grain: 60;
  --z-embed: 61;   /* video surfaces — just above the grain */
  --z-bar: 70;     /* above the lifted embeds so a scroll-past never covers it */
}

/* The one primary breakpoint: mobile treatments flip as a set */
@media (max-width: 640px) {
  :root {
    --bar-h: 48px;
    --bar-link-fs: 11px;
    --bar-link-ls: 0.05em;
    --bar-gap: 14px;           /* five labels (July 11 nav spec) */
    --btn-h: 44px;
    --btn-pad-x: 20px;
    --btn-fs: 12.5px;
    --btn-ls: 0.05em;
    --btn-gap: 8px;
    --chevron-size: 16px;
    --fs-body: 15px;
    --lh-body: 1.65;
    --fs-h3: 17px;
    --panel-pad: 26px 22px;
    --panel-gap: 16px;
    --panel-icon-w: 52px;
    --panel-icon-h: 48px;
    --panel-icon-size: 20px;
    --fs-q: 16px;
    --lh-q: 1.45;
    --fs-a: 15px;
    --lh-a: 1.65;
    --glyph-fs: 24px;
  }
}

/* Small phones: five labels need a final squeeze — never wrap, never
   hamburger (spec). Measured: labels 277px + 4×10px gaps = 317px at 320. */
@media (max-width: 360px) {
  :root {
    --bar-gap: 10px;
    --bar-link-fs: 10.5px;
    --bar-link-ls: 0.04em;
  }
}

/* --------------------------------------------------------------------------
   2. Reset + base
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

/* Smooth in-page scrolling (anchor bar, door button) — motion-safe only */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: 0.01ms !important; }
}

body {
  font-family: var(--font-stack);
  font-weight: 400;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--color-primary);
  background-color: var(--color-white);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

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

/* Global link colors (buttons/nav override with their own) */
a { color: var(--color-blue-core); }
a:hover { color: var(--color-blue-deep); }

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

/* Focus indicators — WCAG AA */
:focus-visible {
  outline: 2px solid var(--color-blue-core);
  outline-offset: 2px;
}

/* Anchored sections land just below the sticky/revealed bar */
main section[id] { scroll-margin-top: var(--bar-h); }

/* --------------------------------------------------------------------------
   3. Grain overlay — page-global.
   Fixed + viewport-sized so the SVG turbulence filter rasterizes once,
   not over the whole document height. Sits above page content, but BELOW
   the video embeds and the bar (see the --z-embed note in :root) and below
   third-party popups. pointer-events: none throughout.
   -------------------------------------------------------------------------- */
.grain {
  position: fixed;
  inset: 0;
  background: var(--color-white);
  filter: url(#gggrain-filter);
  opacity: 0.38;
  mix-blend-mode: multiply;
  pointer-events: none;
  z-index: var(--z-grain);
}

/* --------------------------------------------------------------------------
   4. Anchor bar — two states (July 11 spec), one element, always in flow.
   State A "landing" (scrollY <= 4): transparent, no hairline, muted links,
   gray text-width underline on the current item. Quiet furniture over the
   theater.
   State B "scrolled": frost + hairline + blue underline (.anchor-bar--
   scrolled). Desktop: State B stays hidden (translated away) until half
   the hero, exactly as before; mobile: hide-on-scroll-down / reveal-on-up.
   JS adds .anchor-bar--js at boot to enable sticky + the state swap;
   without JS the bar is simply a static, visible State A in the flow —
   never hidden by CSS alone. The bar ALWAYS occupies its slot in layout
   (the hero fit-math accounts for it), so state changes never jump.
   -------------------------------------------------------------------------- */
.anchor-bar {
  position: static;              /* JS upgrades to sticky (--js) */
  top: 0;
  z-index: var(--z-bar);
  height: var(--bar-h);
  padding-top: env(safe-area-inset-top, 0px);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--bar-gap);
  background: transparent;       /* State A */
  border-bottom: 1px solid transparent;
  transition: transform 160ms var(--ease-out),
              background-color 160ms var(--ease-out),
              border-color 160ms var(--ease-out);
}

.anchor-bar--js { position: sticky; }

/* State B — the frost bar */
.anchor-bar--scrolled {
  background: rgba(233, 233, 233, 0.92);
  border-bottom: 1px solid rgba(12, 12, 16, 0.1);
}

@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .anchor-bar--scrolled {
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
  }
}

/* Mobile scrolled-state hide (scroll-direction driven, as built) */
.anchor-bar--hidden {
  transform: translateY(calc(-100% - 1px)); /* -1px clears the hairline */
}

/* Desktop: State B stays away until half the hero (existing behavior);
   focus reveals it so keyboard users never focus invisible links */
@media (min-width: 641px) {
  .anchor-bar--js.anchor-bar--scrolled {
    transform: translateY(calc(-100% - 1px));
  }
  .anchor-bar--scrolled.anchor-bar--shown,
  .anchor-bar--js.anchor-bar--scrolled:focus-within {
    transform: translateY(0);
  }
}

.anchor-link {
  position: relative;
  display: inline-flex;
  align-items: center;
  height: 100%;
  font-weight: 600;
  font-size: var(--bar-link-fs);
  letter-spacing: var(--bar-link-ls);
  text-transform: uppercase;
  color: rgba(12, 12, 16, 0.4);         /* State A inactive (lightened July 11) */
  text-decoration: none;
  transition: color var(--transition-fast);
}

.anchor-link:hover,
.anchor-link:focus-visible { color: rgba(12, 12, 16, 0.55); }

/* Underline: text-width, flush to the link's bottom edge (both states) */
.anchor-link::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: transparent;
  transition: background-color 160ms var(--ease-out);
}

.anchor-link.is-current { color: rgba(12, 12, 16, 0.55); }        /* State A */
.anchor-link.is-current::after { background: rgba(12, 12, 16, 0.22); }

/* State B link colors + the blue underline */
.anchor-bar--scrolled .anchor-link { color: rgba(12, 12, 16, 0.65); }
.anchor-bar--scrolled .anchor-link:hover,
.anchor-bar--scrolled .anchor-link:focus-visible,
.anchor-bar--scrolled .anchor-link.is-current { color: var(--color-primary); }
.anchor-bar--scrolled .anchor-link.is-current::after { background: var(--color-blue-core); }

/* --------------------------------------------------------------------------
   5. Button system
   Text buttons: 46px desktop / 44px mobile TOTAL height (border-box),
   uppercase 600. Icon buttons: 44×44 gray squares (rail/row).
   Hero buttons float on texture and carry shadows; in-band buttons (M2)
   sit flat without them.
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--btn-gap);
  /* min-height is a FLOOR, not a size: single-line labels render exactly
     46/44px tall (12px padding + one line still sits under the floor and
     flex-centers). A label that wraps on a narrow phone grows the button
     naturally instead of cramming against a hard-coded height
     (iPhone-mini finding, July 11). */
  min-height: var(--btn-h);
  padding: 12px var(--btn-pad-x);
  text-align: center;      /* wrapped second line centers, not ragged-left */
  border: none;
  border-radius: var(--radius);
  font-family: var(--font-stack);
  font-weight: 600;
  font-size: var(--btn-fs);
  line-height: 1.35;       /* air between wrapped lines (was 1.2) */
  letter-spacing: var(--btn-ls);
  text-transform: uppercase;
  color: var(--color-white);
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--transition-fast);
}
.btn:hover, .btn:visited { color: var(--color-white); }

.btn--blue { background: var(--color-blue-core); }
.btn--blue:hover,
.btn--blue:focus-visible { background: var(--color-blue-deep); }

.btn--gray { background: var(--color-utility); }
.btn--gray:hover,
.btn--gray:focus-visible { background: var(--color-blue-core); }

/* Square icon buttons — hero share rail/row */
.share-btn--icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--icon-btn);
  height: var(--icon-btn);
  flex-shrink: 0;
  border: none;
  border-radius: var(--radius);
  background: var(--color-utility);
  box-shadow: var(--btn-shadow);
  color: var(--color-white);
  cursor: pointer;
  transition: background-color var(--transition-fast);
}
.share-btn--icon:hover,
.share-btn--icon:focus-visible {
  background: var(--color-blue-core);
  color: var(--color-white);
}
.share-btn--icon:visited { color: var(--color-white); }

.share-btn--icon svg {
  width: var(--icon-size);
  height: var(--icon-size);
  display: block;
}

.share-btn--copy.is-copied { background: var(--color-blue-core); }

/* Red Share-it buttons (participation panel) — the page's only red.
   Flat: in-band buttons carry no shadow. */
.share-btn--red {
  width: var(--panel-icon-w);
  height: var(--panel-icon-h);
  background: var(--color-red-core);
  box-shadow: none;
}
.share-btn--red:hover,
.share-btn--red:focus-visible {
  background: var(--color-red-deep);
}
.share-btn--red svg {
  width: var(--panel-icon-size);
  height: var(--panel-icon-size);
}
.share-btn--red.is-copied { background: var(--color-red-deep); }

/* --------------------------------------------------------------------------
   6. Hero (Watch)
   Desktop: fills the viewport minus the bar; player sized by the fit-math;
   share rail floats beside the player when there's room (JS adds .hero--rail).
   Mobile: hugs content — bar → 24px → full-bleed player → 20px → share row
   → 20px → door button → 40px.
   -------------------------------------------------------------------------- */
.hero {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  /* The hero slides up under the transparent State-A bar so its texture
     (gradients, capitol, vignette) is what shows through — otherwise the
     bar's flow slot exposes plain body-white and reads as a white strip
     (Adam, July 11). Padding compensates: content geometry unchanged. */
  margin-top: calc(-1 * var(--bar-h));
  padding: calc(var(--bar-h) + 24px) 0 40px;  /* mobile rhythm (master @390) */
  /* corner gradients: grey-lightest (#D8D8D8) / grey-silver (#C0C0C0)
     at alpha — literals by necessity, see palette note in :root */
  background:
    linear-gradient(200deg, rgba(216, 216, 216, 0.5) 0%, transparent 55%),
    linear-gradient(25deg, rgba(192, 192, 192, 0.4) 0%, transparent 50%),
    var(--color-white);
}

@media (min-width: 641px) {
  .hero {
    /* Full viewport: the hero includes the bar's band behind it now */
    min-height: 100vh;
    padding: calc(var(--bar-h) + 40px) var(--section-padding-x) 40px;
    background:
      linear-gradient(200deg, rgba(216, 216, 216, 0.5) 0%, transparent 50%),
      linear-gradient(25deg, rgba(192, 192, 192, 0.4) 0%, transparent 45%),
      var(--color-white);
  }
  @supports (height: 100dvh) {
    .hero { min-height: 100dvh; }
  }
}

/* Desktop (above tablet) always keeps the share rail beside the player
   (Adam, July 11): cap the player so the rail + gutters (260px) always
   fit — on tall viewports the fit-math yields to this cap and the video
   scales down instead of the buttons stacking below. 262 not 260: 2px
   slack so the JS measurement can never lose to rounding. */
@media (min-width: 1025px) {
  .movie-wrap { max-width: calc(100vw - 262px); }
}

/* Faded Capitol — lower-right at every size */
.section-bg-img {
  position: absolute;
  pointer-events: none;
  z-index: 0;
  max-width: none;
}

.bg-capitol-hero {
  right: -40px;
  bottom: -50px;
  width: 250px;
  height: auto;
  opacity: 0.5;   /* +0.1 July 11 — deepened vignette was swallowing it */
}

@media (min-width: 641px) {
  .bg-capitol-hero {
    right: -2%;
    bottom: -10%;
    width: clamp(320px, 44vw, 760px);
    opacity: 0.6;   /* +0.1 July 11 — deepened vignette was swallowing it */
  }
}

/* Vignette — "the lights going down". Deepened on desktop, lighter mobile. */
.hero::after {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(
    ellipse at center,
    transparent 30%,
    rgba(12, 12, 16, 0.1) 60%,
    rgba(12, 12, 16, 0.3) 100%
  );
  pointer-events: none;
  z-index: 1;
}

@media (min-width: 641px) {
  .hero::after {
    background: radial-gradient(
      ellipse at center,
      transparent 22%,
      rgba(12, 12, 16, 0.12) 44%,
      rgba(12, 12, 16, 0.3) 66%,
      rgba(12, 12, 16, 0.52) 100%
    );
  }
}

/* Content sits above the capitol (0) and vignette (1), and above the grain
   (--z-embed): the hero player is one of the video surfaces that must not
   have the blend-mode grain composited over it in Firefox. Lifting the whole
   content group also lifts the share rail + door above the grain, which is
   harmless (grain over solid UI is imperceptible). */
.hero > .hero-content {
  position: relative;
  z-index: var(--z-embed);
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* The player. 1080p 16:9. Width capped three ways: never wider than the
   container, never wider than 1400px, never so tall the frame leaves the
   fold (the --chrome-height budget). */
.movie-wrap {
  position: relative;
  width: 100%;
}

@media (min-width: 641px) {
  .movie-wrap {
    /* vh fallback first, dvh where supported (pre-iOS-15 order).
       1400px cap: 1080p source upscaled 1.3× — imperceptible for video,
       and large monitors deserve a prominent screen. */
    width: clamp(
      min(100%, 560px),
      calc((100vh - var(--chrome-height)) * 16 / 9),
      min(100%, 1400px)
    );
    width: clamp(
      min(100%, 560px),
      calc((100dvh - var(--chrome-height)) * 16 / 9),
      min(100%, 1400px)
    );
  }
}

/* Shared 16:9 embed container — hero player and reactions reel are one
   system. The dark fill holds each section's layout even if a content
   blocker blanks the iframe. */
.embed-16x9 {
  position: relative;
  z-index: var(--z-embed);   /* lift above the grain — Firefox video-overlay fix (see :root) */
  width: 100%;
  aspect-ratio: 16 / 9;
  background: var(--color-primary);
  overflow: hidden;
}

.embed-16x9 iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* Hero player frame: full-bleed on mobile (no radius, single-layer shadow) */
.movie-embed {
  border-radius: 0;
  box-shadow: 0 8px 40px rgba(12, 12, 16, 0.22);
}

@media (min-width: 641px) {
  .movie-embed {
    border-radius: var(--radius);
    box-shadow: var(--embed-shadow);
  }
}

/* Reel frame: framed at every width (contrast with the full-bleed hero) */
.reel-embed {
  border-radius: var(--radius);
  box-shadow: var(--embed-shadow);
}

/* Share buttons — one DOM node, two layouts.
   Default: centered row under the player (mobile + narrow desktop).
   .hero--rail (JS, space-keyed): floating column 28px right of the player,
   centered on its midline. The rail never compresses the player. */
.share-buttons {
  display: flex;
  justify-content: center;
  gap: 12px;
  margin-top: 20px;
}

.hero--rail .share-buttons {
  position: absolute;
  right: -72px;                 /* 44px button + 28px gutter */
  top: 50%;
  transform: translateY(-50%);
  flex-direction: column;
  margin-top: 0;
}

/* Door button — the page's invitation downward.
   Desktop: hidden at landing, fades in after 150s of accumulated real
   watching — seeks and pauses don't count (script.js).
   Its layout slot is ALWAYS reserved — the player never shifts. The hidden
   state exists only ≥641px and only after the Vimeo API is confirmed
   working; mobile and every failure path keep the button visible. */
.door-btn {
  margin-top: 20px;
  max-width: min(320px, calc(100% - 40px));
  box-shadow: var(--btn-shadow);
  transition: background-color var(--transition-fast), opacity 300ms ease;
}

@media (min-width: 641px) {
  .door-btn { margin-top: 28px; max-width: none; }

  .door-btn--waiting {
    opacity: 0;
    visibility: hidden;      /* out of tab order + screen readers */
    pointer-events: none;
  }
}

.door-btn svg {
  width: var(--chevron-size);
  height: var(--chevron-size);
  display: block;
  flex-shrink: 0;
}

/* --------------------------------------------------------------------------
   7. Section scaffolding — Reactions / Reach people / FAQ
   Bands are solid #E9E9E9 with 1px hairline edges; boundaries are hard
   lines on solid tone, never gradients or imagery.
   -------------------------------------------------------------------------- */
.section {
  position: relative;
  padding: var(--section-pad-y) var(--section-padding-x);
}

.band {
  background: var(--color-band);
  border-top: var(--hairline);
  border-bottom: var(--hairline);
}

.section-heading {
  font-weight: 600;
  font-size: var(--fs-h2);
  line-height: 1.3;
  color: var(--color-primary);
  text-align: center;
  /* Display-level uppercase (July 11): source strings stay sentence-case.
     Tracking opened for caps — large sizes need less than the small-caps
     buttons/nav (.06-.08em), and 0.04em reads as a heading, not a shout. */
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* ---- 2 · Reactions ------------------------------------------------------ */
#reactions { text-align: center; }

/* Framed video container — shared by the Reactions reel and The bigger
   idea's YouTube embed (inside .prose the column caps it at 680px).
   Reel: capped at 800px AND always subordinate to the hero player — on
   viewports where the fit-math makes the hero narrower than 860px, the
   reel tracks it at −60px (same formula, minus the subordination margin).
   Mobile: the section's side padding insets it (framed, not full-bleed). */
.reel-wrap {
  width: 100%;
  max-width: 800px;
  margin: 28px auto 0;
}

@media (min-width: 641px) {
  .reel-wrap {
    margin-top: 44px;
    width: clamp(
      min(100%, 500px),
      calc((100vh - var(--chrome-height)) * 16 / 9 - 60px),
      min(100%, 800px)
    );
    width: clamp(
      min(100%, 500px),
      calc((100dvh - var(--chrome-height)) * 16 / 9 - 60px),
      min(100%, 800px)
    );
  }
}

.reactions-invite {
  margin: 22px 0 0;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: rgba(12, 12, 16, 0.85);
}

.reactions-cta { margin-top: 18px; }

@media (min-width: 641px) {
  .reactions-invite { margin-top: 30px; }
  .reactions-cta { margin-top: 22px; }
}

/* ---- 5 · Pass it on panels ------------------------------------------------ */
/* Pass it on sits on the panel-gray tone; the panels flip to white
   (Adam, July 11 — trial treatment). #F4F4F4 = the old panel fill
   rgba(12,12,16,.045) flattened over white, kept as a solid so the
   grain multiplies evenly. Hairline top only — the page-end strip
   below brings its own. */
#reach-people {
  padding-bottom: calc(var(--section-pad-y) + 8px);
  background: #F4F4F4;
  border-top: var(--hairline);
}

/* Single fluid column; order carries the hierarchy, weight stays even.
   Mobile fully centered, desktop left-aligned. */
.panel-column {
  max-width: var(--column-max);
  margin: 36px auto 0;
  display: flex;
  flex-direction: column;
  gap: var(--panel-gap);
  text-align: center;
}

.panel {
  background: var(--color-white);
  border: var(--hairline);
  border-radius: var(--radius);
  padding: var(--panel-pad);
  /* no shadow — panels sit flat (settled) */
}

.panel-title {
  font-weight: 600;
  font-size: var(--fs-h3);
  line-height: 1.4;
  color: var(--color-primary);
}

.panel-body {
  margin-top: 8px;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: rgba(12, 12, 16, 0.85);
}
/* A second body paragraph reads as a paragraph break, not the tight
   title→body gap (Show it panel is the first to run two). */
.panel-body + .panel-body { margin-top: 14px; }

.panel-icons {
  display: flex;
  gap: 10px;
  margin-top: 18px;
  justify-content: center;
}

.panel .btn { margin-top: 16px; }

/* GET IN TOUCH — underlined text link (JS-assembled mailto) */
.skills-link {
  display: inline-block;
  margin-top: 14px;
  font-weight: 600;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(12, 12, 16, 0.6);
  text-decoration: underline;
  text-underline-offset: 0.2em;
  cursor: pointer;
}
.skills-link:hover,
.skills-link:focus-visible { color: var(--color-primary); }

@media (min-width: 641px) {
  .panel-column { margin-top: 52px; text-align: left; }
  .panel-body { margin-top: 10px; }
  .panel-icons { margin-top: 22px; justify-content: flex-start; }
  .panel .btn { margin-top: 22px; }
  .skills-link { margin-top: 18px; font-size: 13px; letter-spacing: 0.1em; }
}

/* Section intro lede (Pass it on) — centered under the heading;
   left-aligned on phones (guard-rule spirit: it runs several lines) */
.section-intro {
  max-width: var(--column-max);
  margin: 24px auto 0;
  text-align: left;   /* column centered, text left like all body copy */
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: rgba(12, 12, 16, 0.85);
}

/* Guard rule (spec, applied per final copy): a panel whose copy runs past
   ~3 rendered lines on a phone flips to left-aligned there — long centered
   text is hard to scan. Desktop is left-aligned regardless. */
@media (max-width: 640px) {
  .panel--left { text-align: left; }
}

/* Video facade — thumbnail + play affordance; the YouTube iframe is
   created only on click (script.js). The image is a finished asset with
   its text baked in. */
.video-facade {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  padding: 0;
  border: 0;
  background: var(--color-primary);
  cursor: pointer;
}

.video-facade img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.video-facade-play {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 68px;
  height: 68px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.92);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 12px rgba(12, 12, 16, 0.3);
  color: var(--color-utility);   /* triangle joins the icon family (Adam, July 11) */
  transition: transform var(--transition-fast);
}

.video-facade:hover .video-facade-play,
.video-facade:focus-visible .video-facade-play {
  transform: translate(-50%, -50%) scale(1.06);
}

.video-facade-play svg {
  width: 45px;
  height: 45px;
  margin-left: 5px;   /* optical centering of the triangle */
}

@media (max-width: 640px) {
  .video-facade-play { width: 52px; height: 52px; }
  .video-facade-play svg { width: 33px; height: 33px; margin-left: 4px; }
}

/* ---- 3 · Q&A accordion + 4 · Bigger-idea prose ---------------------------- */
#qa {
  overflow: hidden;          /* band edges crop the lottery image */
}

/* Long-form text column (The bigger idea) */
.prose {
  position: relative;        /* paints above the lottery image */
  max-width: var(--column-max);
  margin: 28px auto 0;
}

.prose strong { font-weight: 600; }

.prose p {
  margin-top: 16px;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: rgba(12, 12, 16, 0.85);
}
.prose p:first-child { margin-top: 0; }

.prose .reel-wrap { margin: 28px auto 0; }

.prose-subheading {
  margin-top: 40px;
  font-weight: 600;
  font-size: var(--fs-h3);
  line-height: 1.4;
  color: var(--color-primary);
}

@media (min-width: 641px) {
  .prose { margin-top: 36px; }
}

/* The FAQ block is centered like every other section's content; the text
   inside stays left-justified. (Adam, July 9 — supersedes the spec's
   left-of-container column.) */
.faq-inner {
  position: relative;        /* paints above the lottery image */
  max-width: var(--column-max);
  margin: 0 auto;
}

.faq-list {
  margin-top: 32px;
  border-top: var(--hairline-mid);
}

.faq-item { border-bottom: var(--hairline-mid); }

/* Opening an item must never yank the page: scroll anchoring re-pins the
   viewport to content BELOW the expansion, which reads as "my question
   jumped up". Disabling anchoring here keeps the clicked question exactly
   where it is; everything below simply moves down. */
.faq-list { overflow-anchor: none; }

/* Smooth expand — pure CSS (interpolate-size + ::details-content),
   Chrome/Edge 129+ and newer Safari; older browsers keep the instant
   open they have today. No JS. Reduced-motion kills it globally. */
.faq-item::details-content {
  block-size: 0;
  overflow-y: clip;
  transition: block-size 280ms var(--ease-out),
              content-visibility 280ms allow-discrete;
}
.faq-item[open]::details-content { block-size: auto; }

.faq-q {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 14px;
  padding: 18px 0;
  cursor: pointer;
  list-style: none;          /* hide the default disclosure triangle */
  font-weight: 600;
  font-size: var(--fs-q);
  line-height: var(--lh-q);
  color: var(--color-primary);
}
.faq-q::-webkit-details-marker { display: none; }

/* +/− text glyph */
.faq-q::after {
  content: '+';
  font-weight: 400;
  font-size: var(--glyph-fs);
  line-height: 1;
  color: rgba(12, 12, 16, 0.4);
  flex-shrink: 0;
}
.faq-item[open] .faq-q::after { content: '−'; }

.faq-a {
  margin-top: -8px;          /* Q row's bottom padding minus the 10px gap */
  padding-bottom: 20px;
  font-size: var(--fs-a);
  line-height: var(--lh-a);
  color: rgba(12, 12, 16, 0.78);
}

.faq-a p + p { margin-top: 12px; }

.faq-a a {
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

@media (min-width: 641px) {
  /* Heading stays centered like every other section (Adam, July 9);
     only the Q&A text inside the column is left-justified. */
  .faq-list { margin-top: 44px; }
  .faq-q { gap: 16px; padding: 22px 0; }
  .faq-a { margin-top: -10px; padding-bottom: 24px; }
}

/* Lottery machine — wide viewports only (mirrors the hero's Capitol).
   Master-scale (Adam, July 9: bold beats buffered). The image RECTANGLE
   may run under the centered column — its left side is a soft fade, and
   the dense machine body stays right/below the text; the reserved bottom
   padding keeps open accordion items above the balls. Cap = 1000px, the
   source's native resolution — displaying larger means upscaling soft.
   When the higher-res cutout exists (open task), only this cap changes. */
.bg-lottery {
  display: none;
  right: -40px;
  bottom: -60px;
  width: min(54vw, 1000px);
  opacity: 0.95;
}

/* ---- 6 · Page ending (no footer) ----------------------------------------- */
/* White strip, hairline above, © centered — every width (Adam, July 10) */
.page-end {
  padding: 32px var(--section-padding-x) 36px;
  text-align: center;
  border-top: var(--hairline);
}
.page-end p {
  font-size: var(--btn-fs);   /* same coherence rule as the band © */
  letter-spacing: 0.08em;
  color: rgba(12, 12, 16, 0.45);
}

/* Lottery image at wide viewports (bottom room reserved for it) */
@media (min-width: 1200px) {
  #qa { padding-bottom: 216px; }
  .bg-lottery { display: block; }
}

/* --------------------------------------------------------------------------
   7b. Donate modal — our own, styled in the Senja popup's family:
   blurred, slightly darkened overlay; plain white card, 3px radius,
   circular close X. Left: donation context + DAF info (copy slots).
   Right: Donorbox's standard iframe embed (loaded on first open).
   Replaces Donorbox's popup script, whose in-iframe overlay we can't style.
   -------------------------------------------------------------------------- */
.donate-modal {
  position: fixed;
  inset: 0;
  z-index: 100;              /* above bar + grain, below nothing else */
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}
.donate-modal[hidden] { display: none; }

.donate-modal-overlay {
  position: absolute;
  inset: 0;
  background: rgba(12, 12, 16, 0.4);   /* fallback: plain dim */
}
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .donate-modal-overlay {
    background: rgba(12, 12, 16, 0.15);
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
  }
}

.donate-modal-card {
  position: relative;
  width: min(960px, 100%);
  max-height: calc(100vh - 48px);
  max-height: calc(100dvh - 48px);
  overflow-y: auto;
  background: var(--color-white);
  border-radius: var(--radius);
  padding: 40px;
}

.donate-modal-close {
  position: absolute;
  top: 14px;
  right: 14px;
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid rgba(12, 12, 16, 0.15);
  border-radius: 50%;
  background: var(--color-white);
  color: rgba(12, 12, 16, 0.6);
  cursor: pointer;
  transition: color var(--transition-fast);
}
.donate-modal-close:hover,
.donate-modal-close:focus-visible { color: var(--color-primary); }
.donate-modal-close svg { width: 16px; height: 16px; }

/* Mobile/base: stacked, form first (embed precedes text in the DOM) */
.donate-grid { display: block; margin-top: 20px; }

.donate-info { margin-top: 28px; }

.donate-info a {
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

/* DAF details keep their exact line breaks — slightly tighter leading */
.donate-daf { line-height: 1.55; }

.donate-modal-title {
  font-weight: 600;
  font-size: var(--fs-h3);
  line-height: 1.4;
  color: var(--color-primary);
}

.donate-info h4 {
  margin-top: 24px;
  font-weight: 600;
  font-size: var(--fs-body);
  color: var(--color-primary);
}

.donate-info p {
  margin-top: 10px;
  font-size: var(--fs-a);
  line-height: var(--lh-a);
  color: rgba(12, 12, 16, 0.85);
}

/* .donate-embed is first in the DOM (form-first stack) — no top margin */
.donate-embed iframe { display: block; width: 100%; border: 0; }

@media (min-width: 900px) {
  .donate-grid {
    display: grid;
    grid-template-columns: 440px 1fr;   /* portal LEFT, text RIGHT */
    gap: 44px;
    align-items: start;
  }
  .donate-info { margin-top: 0; }
}

/* Small screens: the card becomes a full-height sheet */
@media (max-width: 640px) {
  .donate-modal { padding: 0; }
  .donate-modal-card {
    width: 100%;
    height: 100%;
    max-height: none;
    border-radius: 0;
    padding: 24px 20px;
  }
}

/* --------------------------------------------------------------------------
   7c. The bigger idea — "watch first" gate. NOT a modal: an in-flow overlay,
   the last child of .prose (which is already position: relative), that frosts
   the proposals until the movie has been watched (the shared 150s milestone)
   or the visitor opts to read anyway. Styled in the Senja/Donate family —
   blurred, lightly scrimmed backdrop, plain white card, 3px radius. Ships
   hidden; JS reveals it only after the player is confirmed ready, so every
   failure path (no-JS, blocked player, old browser) leaves the section
   ungated. z-index sits above the video facade (--z-embed) and below the bar.
   -------------------------------------------------------------------------- */
.idea-gate {
  position: absolute;
  inset: 0;
  z-index: 62;               /* above the facade (--z-embed 61), below the bar (70) */
  opacity: 0;
  transition: opacity var(--transition-fast);
}
.idea-gate.is-visible { opacity: 1; }
.idea-gate[hidden] { display: none; }

/* The frost is a PSEUDO-ELEMENT (so the card above stays perfectly crisp).
   It bleeds ~18px past the text column and feathers its left/right edges
   with a mask, so the blur has a soft margin instead of a hard rectangle —
   the fade sits out in the white gutter, never over the text. The blur is
   deliberately light: enough that the text can't be read, but you can still
   tell it's lines of text, not a smeared box. */
.idea-gate::before {
  content: "";
  position: absolute;
  inset: -16px -18px;
  background: rgba(255, 255, 255, 0.10);   /* fallback: faint scrim (no blur) */
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 18px, #000 calc(100% - 18px), transparent 100%);
          mask-image: linear-gradient(to right, transparent 0, #000 18px, #000 calc(100% - 18px), transparent 100%);
}
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .idea-gate::before {
    background: rgba(255, 255, 255, 0.06);
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
  }
}

.idea-gate-card {
  position: sticky;
  z-index: 1;                /* above the frost pseudo-element */
  top: clamp(96px, 22vh, 220px);
  width: min(440px, calc(100% - 32px));
  margin: 0 auto;
  background: var(--color-white);
  border: 1px solid rgba(12, 12, 16, 0.08);
  border-radius: var(--radius);
  box-shadow: var(--embed-shadow);
  padding: 30px 28px;
  text-align: center;
}

.idea-gate-title {
  font-weight: 600;
  font-size: var(--fs-h3);
  line-height: 1.4;
  color: var(--color-primary);
}

.idea-gate-text {
  margin-top: 10px;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: rgba(12, 12, 16, 0.85);
}

.idea-gate-actions {
  margin-top: 22px;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 10px;
}

/* Secondary action — a quiet ghost button, subordinate to the blue primary.
   Wrap treatment mirrors .btn: on the narrowest phones a label can take two
   lines (12px vertical padding + 1.35 leading, centered) instead of cramming. */
.idea-gate-skip {
  min-height: var(--btn-h);
  padding: 12px 18px;
  border: 1px solid rgba(12, 12, 16, 0.18);
  border-radius: var(--radius);
  background: none;
  font-family: var(--font-stack);
  font-weight: 600;
  font-size: var(--btn-fs);
  line-height: 1.35;
  letter-spacing: var(--btn-ls);
  text-transform: uppercase;
  text-align: center;
  color: var(--color-utility);
  cursor: pointer;
  transition: color var(--transition-fast), border-color var(--transition-fast);
}
.idea-gate-skip:hover,
.idea-gate-skip:focus-visible {
  color: var(--color-primary);
  border-color: rgba(12, 12, 16, 0.4);
}

/* --------------------------------------------------------------------------
   8. Senja collector popup overrides (settled — do not touch)
   Their script injects #collector-container into our page. Three fixes:
   1. Vertically center the card for any screen height.
   2. Remove their heavy shadow + near-white card so the form blends in.
   3. Match the site's 3px corner radius.
   NOTE: targets Senja's internal class names — brittle if they redesign.
   -------------------------------------------------------------------------- */
#collector-container .overflow-y-auto {
  display: flex;
  flex-direction: column;
}

#collector-container .overflow-y-auto > div {
  margin: auto;
}

#collector-container .shadow-2xl {
  box-shadow: none !important;
  background: transparent !important;
}

#collector-container #senja-iframe {
  border-radius: var(--radius) !important;
}

/* --------------------------------------------------------------------------
   9. Legacy fallbacks (pre-iOS-15 Safari)
   -------------------------------------------------------------------------- */
/* No aspect-ratio support: classic padded-box 16:9 */
@supports not (aspect-ratio: 16 / 9) {
  .embed-16x9 {
    height: 0;
    padding-top: 56.25%;
  }
}

/* Hero fit-math: no height tiers — --chrome-height is fluid (74px door
   slot + 20vh breathing); short screens tighten and tall screens relax
   proportionally from the one formula in :root. */


