/* New Life Fellowship, "No past / every future"
   Light canvas, their footage as the dark moments, and the accent is
   structural only: their own swoosh, drawn. No colored headline words,
   no letterspaced eyebrow labels. */

:root {
  --bone: #f4f1ea;
  --bone-2: #ebe7de;
  --ink: #14130f;
  --ink-soft: #55514a;
  --film: #0b0b0c;
  --line: rgba(20, 19, 15, 0.13);
  /* The one soft accent. Hue 193 sampled from the baptism footage in the
     hero, then lightened and desaturated until it sits quietly next to bone.
     It is a tint of THEIR media, not a colour we picked for them, which is
     why it does not read as a stock brand palette. */
  --wash: #eef2f3;
  --wash-edge: #dfe8eb;
  --font: "Outfit", "Helvetica Neue", Arial, sans-serif;
  --pad: clamp(20px, 5vw, 84px);
  --max: 1420px;
}

* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  background: var(--bone);
  color: var(--ink);
  font-family: var(--font);
  font-weight: 400;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
img, video { display: block; max-width: 100%; }
a { color: inherit; }

/* the mark draws itself along its own two strokes, clipped to the exact
   logo silhouette, so the shape is the real artwork and only the
   painting-on is animated */
.nlmark { display: block; }
.nl-s {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
}
@keyframes draw { to { stroke-dashoffset: 0; } }

/* Keyboard users get out of the nav in one press. Visible only on focus. */
.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  background: var(--ink);
  color: var(--bone);
  padding: 12px 20px;
  border-radius: 0 0 8px 0;
  font-size: 14px;
  text-decoration: none;
}
.skip:focus { left: 0; }

/* Focus has to be visible on a light canvas and on film alike. */
a:focus-visible, button:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}
.come a:focus-visible, .band a:focus-visible, .stage a:focus-visible,
.in-portal .nav a:focus-visible { outline-color: #fff; }

/* ---------- nav ---------- */
.nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 20px var(--pad);
  transition: background 0.4s ease, padding 0.4s ease;
}
.nav.solid {
  background: rgba(244, 241, 234, 0.9);
  backdrop-filter: blur(10px);
  padding-top: 14px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--line);
}
.nav-mark img { height: 32px; width: auto; transition: filter 0.3s ease; }
.nav.solid .nav-mark img { filter: invert(1) brightness(0.18); }
.nav-links { display: flex; gap: 26px; }
.nav-links a {
  color: #fff;
  text-decoration: none;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.02em;
  transition: color 0.3s ease;
}
.nav.solid .nav-links a { color: var(--ink); }
.nav-links a:hover { opacity: 0.65; }

/* Five links plus the wordmark do not fit a phone in one row: they ran off
   the right edge. Stacked rather than hidden behind a hamburger, because
   this congregation should not have to hunt for "Give" or "Visit". */
@media (max-width: 620px) {
  .nav {
    flex-direction: column;
    gap: 12px;
    padding: 14px var(--pad);
  }
  .nav-mark img { height: 26px; }
  .nav-links { gap: clamp(14px, 4.4vw, 22px); }
  .nav-links a { font-size: 12px; }
}
/* While the portal cover is up the canvas behind the nav is bone, not film,
   so white links disappear into it. The nav follows the canvas, not the
   scroll position. */
.in-portal .nav-links a { color: var(--ink); }
.in-portal .nav-mark img { filter: invert(1) brightness(0.18); }

/* ---------- the pinned two-beat stage ---------- */
/* 280vh, split roughly in thirds: fly through, read beat one, read beat two.
   At 300vh with the portal taking 46% the pacing was upside down, giving the
   most scroll to a growing logo over a short loop and the least to the line
   people are meant to read. That taught a fast scroll, which then overshot
   the text. */
.stage { height: 280vh; position: relative; }
.stage-sticky {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
  /* Bone while the mark is still a window, so the page opens on the canvas
     with the film showing only inside the logo. It becomes film once we are
     through, so a letterboxed video never shows bone at the edges. */
  background: var(--film);
}
.in-portal .stage-sticky { background: var(--bone); }
.film {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 42%;
}
.film-two { opacity: var(--t, 0); }
/* Only as much scrim as the type actually needs, and only where it sits.
   The old flat overlay desaturated the whole frame to protect text that
   lives in one band. */
.film-scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(rgba(11, 11, 12, 0) 34%, rgba(11, 11, 12, 0.52) 62%, rgba(11, 11, 12, 0.66));
  opacity: var(--scrim, 0);
}

/* ---------- the portal ----------
   The transform lives on the clip path's group and is written in CSS pixels
   by site.js, because a clipPath with userSpaceOnUse shares the coordinate
   system of the element it clips. */
.portal {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 2;
}
.portal.gone { display: none; }
.portal-g {
  transform: translate(50px, 30px) scale(var(--portal, 1)) translate(-50px, -30px);
  transform-origin: 0 0;
  transform-box: view-box;
}
.stage-type {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  text-align: center;
  padding: 0 var(--pad);
}
/* the roll masks a full line box, so the line-height has to be tall
   enough to contain descenders (the y in "everyone") on its own */
.beats {
  color: #fff;
  font-weight: 300;
  font-size: clamp(2.4rem, 7.2vw, 6.6rem);
  /* Tight leading and negative tracking: at display size this is the first
     thing anyone sees, and airy settings read as tentative. The floor is set
     by ink, not by the font box. Outfit's box is 1.26em but its actual ink
     here measures 0.906em (0.708 above the baseline, 0.198 below), so 1.02
     still clears the p and y descenders.

     The three values below MUST stay identical. A rolling mask cannot use
     padding to clear descenders, because the extra room would reveal the
     next line, so line-height, mask height and translate distance move
     together or the roll drifts. */
  /* 1.14 is the FLOOR, not a taste choice. Outfit sits its baseline at
     (L - 1.26)/2 + 1.0 from the top of the line box, so the p in "past"
     reaches L/2 + 0.568. Below 1.136 that descender pokes out of its own
     box, and the roll then parks the stray fragment at the top of the
     window: a mystery dot above the u in "future".

     1.136 is the mathematical floor and is NOT good enough. It leaves 0.002em
     of headroom, which is a fifth of a pixel at this size, and antialiasing
     renders a fraction of that as a faint sliver. Clearance has to be worth
     whole pixels, so this sits at 1.22 with ~4px to spare. */
  line-height: 1.22;
  letter-spacing: -0.032em;
  opacity: var(--beats, 0);
}
.beat-mask { display: block; overflow: hidden; height: 1.22em; }
/* The visible gap is closed here instead, so the type still reads at 1.02
   while every line box stays tall enough to hold its own descender. The
   overlap only ever falls in the empty band above the next line's ascender
   (its ink starts 0.232em in), so nothing collides. */
.beat-mask + .beat-mask { margin-top: -0.20em; }
.beat-track {
  display: block;
  transform: translateY(calc(var(--swap, 0) * -1.22em));
  will-change: transform;
}
.beat-line { display: block; height: 1.22em; }

.stage-cue {
  position: absolute;
  bottom: 30px;
  left: 50%;
  transform: translateX(-50%);
  width: 1px;
  height: 52px;
  overflow: hidden;
  opacity: var(--cue, 1);
}
.stage-cue span {
  display: block;
  width: 1px;
  height: 100%;
  background: linear-gradient(#fff, transparent);
  animation: cue 2.2s cubic-bezier(0.65, 0, 0.35, 1) infinite;
}
@keyframes cue {
  0% { transform: translateY(-100%); }
  60%, 100% { transform: translateY(100%); }
}

/* ---------- shared type motion ----------
   the mask has to reach below the baseline or it crops descenders
   (the g in "Loving", the y in "everyone"); the negative margin keeps
   that extra room from adding layout space between lines */
.rise {
  display: block;
  overflow: hidden;
  padding-bottom: 0.2em;
  margin-bottom: -0.2em;
}
.rise > span {
  display: block;
  transform: translateY(118%);
  transition: transform 0.9s cubic-bezier(0.19, 1, 0.22, 1);
}
.rise.in > span { transform: none; }
.rise:nth-child(2) > span { transition-delay: 0.08s; }
.rise:nth-child(3) > span { transition-delay: 0.16s; }

.reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 0.8s ease, transform 0.8s cubic-bezier(0.19, 1, 0.22, 1);
}
.reveal.in { opacity: 1; transform: none; }

/* the accent, drawn: same mark, painted on when it scrolls into view */
.mark { display: block; color: var(--ink); margin-bottom: 28px; }
.mark .nl-s { transition: stroke-dashoffset 0.72s cubic-bezier(0.55, 0, 0.4, 1); }
.mark.in .nl-s { stroke-dashoffset: 0; }
.mark.in .nl-s2 { transition-delay: 0.3s; }

/* ---------- who they are ---------- */
/* The statement sits against their own mark, blown up and bled off the
   right edge. The empty half of this section was reading as unfinished
   rather than as confident space, and filling it with brand beats filling
   it with a stock photo. The mark is the site's structural device: it opens
   the page as the portal, anchors this section, and rules the footer. */
.say {
  position: relative;
  overflow: hidden;
  max-width: var(--max);
  margin: 0 auto;
  padding: clamp(80px, 11vw, 150px) var(--pad) clamp(70px, 10vw, 130px);
}
.say > *:not(.mark) { position: relative; z-index: 1; }
.say .mark {
  position: absolute;
  top: 50%;
  right: -14%;
  width: min(62vw, 820px);
  transform: translateY(-46%);
  /* Solid colour, and the transparency applied to the whole element. Tinting
     the strokes themselves doubles their alpha where they cross, which reads
     as two overlapping shapes rather than one mark. */
  color: var(--ink);
  opacity: 0.055;
  pointer-events: none;
}
.say .mark svg { width: 100%; height: auto; }
/* the mark draws on when the section arrives, same gesture as the intro */
.say .mark .nl-s { animation: none; stroke-dashoffset: 1; }
.say .mark.in .nl-s { animation: draw 1.5s cubic-bezier(0.55, 0, 0.4, 1) forwards; }
.say .mark.in .nl-s2 { animation-delay: 0.5s; }
@media (max-width: 860px) {
  .say .mark { right: -30%; width: 110vw; transform: translateY(-40%); }
}
.say-head {
  max-width: 13ch;
  font-weight: 300;
  font-size: clamp(2.4rem, 6.6vw, 6rem);
  line-height: 1.02;
  letter-spacing: -0.024em;
}
.say-body {
  margin-top: 34px;
  max-width: 46ch;
  font-size: clamp(1.08rem, 1.5vw, 1.35rem);
  color: var(--ink-soft);
}

/* ---------- life: three of their own moments ---------- */
.life {
  max-width: var(--max);
  margin: 0 auto;
  padding: 0 var(--pad) clamp(80px, 12vw, 150px);
}
.life-title {
  font-weight: 300;
  font-size: clamp(1.5rem, 3vw, 2.5rem);
  letter-spacing: -0.015em;
  margin-bottom: 34px;
}
.life-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(12px, 1.6vw, 22px);
}
.lf { position: relative; }
.lf video {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: 12px;
  background: var(--film);
}
.lf:nth-child(2) { transform: translateY(clamp(18px, 3vw, 46px)); }
.lf figcaption {
  margin-top: 12px;
  font-size: 14px;
  font-weight: 600;
  color: var(--ink-soft);
}
.lf:nth-child(2) { transition-delay: 0.1s; }
.lf:nth-child(3) { transition-delay: 0.2s; }

/* ---------- the pastors, at work: spans the pastor grid ---------- */
.pastor-pair {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(12px, 1.6vw, 22px);
  margin-top: clamp(6px, 1.5vw, 18px);
}
.pastor-pair img {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: 12px;
  background: var(--film);
  display: block;
}
.pastor-pair img.walk { object-position: center bottom; }
.pastor-pair figcaption {
  margin-top: 12px;
  font-size: 14px;
  font-weight: 600;
  color: var(--ink-soft);
}

/* ---------- we connect: three of their own frames ---------- */
.connect-strip {
  max-width: var(--max);
  margin: 0 auto;
  padding: 0 var(--pad) clamp(40px, 6vw, 70px);
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(12px, 1.6vw, 22px);
}
.cp img {
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  border-radius: 12px;
  background: var(--film);
  display: block;
}
.cp:nth-child(2) { transform: translateY(clamp(18px, 3vw, 46px)); transition-delay: 0.1s; }
.cp:nth-child(3) { transition-delay: 0.2s; }
.kids-room { object-position: center 68%; }
.room-full { object-position: center 58%; }
.serving { object-position: center 40%; }
.cp img.lift { object-position: center 25%; }

/* ---------- focus on the home ---------- */
.home {
  max-width: var(--max);
  margin: 0 auto;
  padding: 0 var(--pad) clamp(80px, 12vw, 150px);
}
.home-head {
  font-weight: 300;
  font-size: clamp(2rem, 4.4vw, 3.9rem);
  line-height: 1.03;
  letter-spacing: -0.02em;
}
.home-line {
  margin: 18px 0 40px;
  font-size: clamp(1.05rem, 1.4vw, 1.3rem);
  color: var(--ink-soft);
  max-width: 44ch;
}
.home-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(12px, 1.6vw, 22px);
}
.hp img {
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  border-radius: 12px;
  background: var(--film);
  display: block;
}
.hp:nth-child(1) { transform: translateY(clamp(18px, 3vw, 46px)); }
.hp:nth-child(3) { transform: translateY(clamp(18px, 3vw, 46px)); }
.hp:nth-child(2) { transition-delay: 0.1s; }
.hp:nth-child(3) { transition-delay: 0.2s; }

/* ---------- the week ---------- */
.week {
  max-width: var(--max);
  margin: 0 auto;
  padding: clamp(60px, 9vw, 120px) var(--pad);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(30px, 5vw, 84px);
  align-items: center;
}
.week-head {
  font-weight: 300;
  font-size: clamp(2rem, 4.4vw, 3.9rem);
  line-height: 1.03;
  letter-spacing: -0.02em;
  margin-bottom: 34px;
}
.week-list { list-style: none; }
.week-list li {
  display: grid;
  grid-template-columns: 116px 1fr;
  align-items: baseline;
  gap: 8px 18px;
  padding: 20px 0;
  border-top: 1px solid var(--line);
}
.week-list li:last-child { border-bottom: 1px solid var(--line); }
.wl-day { font-size: 14px; font-weight: 600; color: var(--ink-soft); }
.wl-time { font-size: clamp(1.5rem, 2.3vw, 2rem); font-weight: 300; letter-spacing: -0.015em; }
.wl-note { grid-column: 2; font-size: 14px; color: var(--ink-soft); margin-top: -4px; }
.week-photo { overflow: hidden; border-radius: 14px; }
.week-photo img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  object-position: 50% 60%;
  transform: scale(var(--ken, 1));
  transition: transform 0.6s linear;
}

/* ---------- pastor ---------- */
.pastor {
  max-width: var(--max);
  margin: 0 auto;
  padding: clamp(60px, 9vw, 120px) var(--pad) clamp(90px, 13vw, 170px);
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  gap: clamp(30px, 5vw, 84px);
  align-items: start;
}

/* He is talking to you rather than posing. The clip was shot on a neutral
   grey seamless, which sits quietly against the bone canvas, so this reads
   as a portrait rather than as a video embed. Portrait crop because the
   source frames him centre-left with room above his head. */
.pastor-film { overflow: hidden; border-radius: 14px; background: var(--bone-2); }
.pastor-film video {
  width: 100%;
  /* Let the shot keep the framing it was composed with. Cropping a 16:9
     medium shot to portrait magnifies his face into an extreme close-up,
     which lands on whatever syllable he happens to be mid-way through. At
     its native ratio he reads as a person talking to you. */
  aspect-ratio: 16 / 9;
  object-fit: cover;
  object-position: 46% 34%;
}
.pastor-family { margin-top: 30px; max-width: 400px; }
.pastor-family img {
  width: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  object-position: 50% 30%;
  border-radius: 10px;
}
.pastor-family figcaption {
  margin-top: 10px;
  font-size: 13px;
  color: var(--ink-soft);
}
.pastor-head {
  font-weight: 300;
  font-size: clamp(1.9rem, 4vw, 3.4rem);
  line-height: 1.04;
  letter-spacing: -0.02em;
  margin-bottom: 22px;
}
.pastor-body { max-width: 52ch; font-size: clamp(1.05rem, 1.4vw, 1.25rem); color: var(--ink-soft); }

/* ---------- come: the dark close ---------- */
.come {
  position: relative;
  min-height: 92vh;
  display: grid;
  place-items: center;
  overflow: hidden;
  background: var(--film);
  text-align: center;
}
.come-media { position: absolute; inset: 0; }
.come-film {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scale(var(--comeScale, 1.12));
  transition: transform 0.5s linear;
}
.come-scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(rgba(11, 11, 12, 0.62), rgba(11, 11, 12, 0.5) 45%, rgba(11, 11, 12, 0.82));
}
.come-type {
  position: relative;
  z-index: 2;
  color: #fff;
  padding: clamp(100px, 14vw, 170px) var(--pad);
  max-width: 900px;
}
.come-head {
  font-weight: 300;
  font-size: clamp(2.4rem, 6.4vw, 5.6rem);
  line-height: 1.02;
  letter-spacing: -0.024em;
}
.come-body {
  margin: 26px auto 0;
  max-width: 50ch;
  font-size: clamp(1.05rem, 1.4vw, 1.25rem);
  color: rgba(255, 255, 255, 0.88);
}
.come-actions { margin-top: 34px; display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }
.come-times { margin-top: 26px; font-size: 14px; color: rgba(255, 255, 255, 0.7); }

.btn {
  display: inline-block;
  background: var(--bone);
  color: var(--ink);
  text-decoration: none;
  font-weight: 500;
  font-size: 14px;
  letter-spacing: 0.02em;
  padding: 15px 28px;
  border-radius: 999px;
  transition: transform 0.25s ease, background 0.25s ease;
}
.btn:hover { transform: translateY(-2px); background: #fff; }
.btn.ghost { background: transparent; color: #fff; border: 1px solid rgba(255, 255, 255, 0.4); }
.btn.ghost:hover { border-color: #fff; background: transparent; }

/* ---------- footer ---------- */
.foot {
  background: var(--bone-2);
  padding: clamp(60px, 8vw, 96px) var(--pad) 44px;
}
.foot-top { max-width: var(--max); margin: 0 auto 48px; }
.foot-mark { height: 38px; width: auto; }
.foot-tag { margin-top: 16px; color: var(--ink-soft); font-size: 15px; }
.foot-cols {
  max-width: var(--max);
  margin: 0 auto;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 28px;
  font-size: 15px;
  color: var(--ink-soft);
}
.foot-cols p { margin-bottom: 10px; }
.foot-cols a { text-decoration: none; }
.foot-cols a:hover { color: var(--ink); }
.foot-label { font-size: 13px; font-weight: 500; color: var(--ink); }
.foot-fine {
  max-width: var(--max);
  margin: 52px auto 0;
  font-size: 13px;
  color: rgba(20, 19, 15, 0.45);
}

/* ---------- mobile ---------- */
@media (max-width: 900px) {
  .stage { height: 260vh; }
  .life-grid { grid-template-columns: 1fr; gap: 18px; }
  .home-grid { grid-template-columns: 1fr; gap: 18px; }
  .pastor-pair { grid-template-columns: 1fr; gap: 18px; }
  .connect-strip { grid-template-columns: 1fr; gap: 18px; }
  .cp:nth-child(2) { transform: none; }
  .hp:nth-child(1), .hp:nth-child(3) { transform: none; }
  .lf:nth-child(2) { transform: none; }
  .lf video { aspect-ratio: 3 / 2; }
  .week, .pastor { grid-template-columns: 1fr; }
  .pastor-photo { order: -1; }
  .week-list li { grid-template-columns: 96px 1fr; }
  .foot-cols { grid-template-columns: 1fr; gap: 22px; }
  .nav-links { gap: 16px; }
  .nav-links a { font-size: 12px; }
}

/* ---------- reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .rise > span, .reveal { transform: none; opacity: 1; transition: none; }
  .mark .nl-s { stroke-dashoffset: 0; transition: none; }
  .stage { height: auto; }
  .stage-sticky { position: relative; height: 86vh; }
  .stage-cue { display: none; }
  .beat-track { transform: none; }
  .beat-mask:first-child .beat-track { transform: none; }
  .film, .come-film { display: none; }
  .stage-sticky { background: url("/assets/video/hero-poster.jpg") center/cover no-repeat; }
  .come { background: url("/assets/video/hero-poster.jpg") center/cover no-repeat; }
  .week-photo img, .come-film { transform: none; }
}

/* ---------- inner pages ----------
   Deliberately reuses the home page's section classes (.week, .pastor, .come,
   .btn, .say .mark) so the inner pages are consistent by construction rather
   than by discipline. Only what is genuinely new lives here. */

.phero {
  position: relative;
  overflow: hidden;
  max-width: var(--max);
  margin: 0 auto;
  padding: clamp(120px, 17vw, 220px) var(--pad) clamp(50px, 7vw, 90px);
}
.phero > * { position: relative; z-index: 1; }
.phero .mark {
  position: absolute;
  top: 46%;
  right: -16%;
  width: min(58vw, 760px);
  transform: translateY(-46%);
  color: var(--ink);
  opacity: 0.055;
  pointer-events: none;
  z-index: 0;
}
.phero .mark svg { width: 100%; height: auto; }
.phero .mark .nl-s { stroke-dashoffset: 1; animation: draw 1.5s cubic-bezier(0.55, 0, 0.4, 1) 0.2s forwards; }
.phero .mark .nl-s2 { animation-delay: 0.7s; }
.phero h1 {
  max-width: 15ch;
  font-weight: 300;
  font-size: clamp(2.6rem, 7vw, 5.6rem);
  line-height: 1.02;
  letter-spacing: -0.032em;
}
.phero .lead {
  margin-top: 26px;
  max-width: 46ch;
  font-size: clamp(1.08rem, 1.5vw, 1.35rem);
  color: var(--ink-soft);
}
@media (max-width: 860px) {
  .phero .mark { right: -34%; width: 115vw; }
}

/* a full-bleed band of their own footage between sections */
/* Every source photo is about 1.5:1. The band used to be 2.57:1, which threw
   away 42% of the image height and cut the tops of heads off. 2:1 keeps three
   quarters of the frame, and the per-image windows below are placed on the
   faces rather than trusting a centre crop. */
/* NEVER pair min-height with aspect-ratio here. The two together let the box
   satisfy the ratio by growing WIDER than its container, which pushed this to
   600px inside a 500px viewport and scrolled every inner page sideways on a
   phone. Change the ratio per breakpoint instead. */
.band {
  position: relative;
  overflow: hidden;
  aspect-ratio: 2 / 1;
  background: var(--film);
}
/* On a phone the band goes to the photos' native 3:2, so there is no crop at
   all and the subject is whole. */
@media (max-width: 760px) {
  .band { aspect-ratio: 3 / 2; }
  .band img { object-position: 50% 30%; }
}
.band video, .band img { width: 100%; height: 100%; object-fit: cover; }
/* faces sit in the upper third of both of these */
.band img[src*="gathering"] { object-position: 50% 14%; }
.band img[src*="food-pantry"] { object-position: 50% 16%; }

/* a list of real things: ministries, next steps */
.stack {
  max-width: var(--max);
  margin: 0 auto;
  padding: clamp(70px, 10vw, 130px) var(--pad);
}
.stack h2 {
  max-width: 16ch;
  font-weight: 300;
  font-size: clamp(2rem, 4.4vw, 3.6rem);
  line-height: 1.04;
  letter-spacing: -0.026em;
  margin-bottom: 44px;
}
.items { list-style: none; }
/* Each item sits on its own soft stripe. The fill replaces the hairlines
   rather than joining them: a rule and a filled block doing the same
   separating job at once reads as indecision. */
.items li {
  display: grid;
  grid-template-columns: minmax(170px, 0.9fr) 1.6fr;
  gap: 10px clamp(20px, 4vw, 60px);
  align-items: start;
  border-radius: 14px;
  padding: clamp(26px, 3vw, 40px) clamp(22px, 3vw, 44px);
  margin-bottom: 10px;
  transition: background 0.3s ease;
}
.items li:last-child { margin-bottom: 0; }

/* Green, blue, pink, purple (Martin's call). One per item, cycling on
   nth-child for longer lists. All four share a lightness and saturation so
   they read as a set, and each is light enough to keep body copy at full
   contrast against it. */
.items li:nth-child(4n+1) { background: #ecf5f0; }
.items li:nth-child(4n+1):hover { background: #deefe5; }
.items li:nth-child(4n+2) { background: #ecf0f5; }
.items li:nth-child(4n+2):hover { background: #dee5ef; }
.items li:nth-child(4n+3) { background: #f5ecef; }
.items li:nth-child(4n+3):hover { background: #efdee4; }
.items li:nth-child(4n+4) { background: #f1ecf5; }
.items li:nth-child(4n+4):hover { background: #e8deef; }

.items h3 { font-weight: 400; font-size: clamp(1.25rem, 2vw, 1.7rem); letter-spacing: -0.015em; }
.items p { color: var(--ink-soft); font-size: clamp(1rem, 1.3vw, 1.12rem); max-width: 54ch; }
.items .when { grid-column: 2; font-size: 14px; color: var(--ink); }
@media (max-width: 760px) {
  .items li { grid-template-columns: 1fr; gap: 8px; }
  .items .when { grid-column: 1; }
}

/* ---------- their three words, on their own people ----------
   Three beats, each roughly a third of the pinned scroll, per the pacing law:
   allocate scroll to what there is to take in. Crossfades rather than cuts,
   because a hard cut between two clips of the same room reads as a glitch. */
.faces { height: 320vh; position: relative; }
.faces-sticky {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
  background: var(--film);
}
.ff {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  will-change: opacity;
}
.ff1 { opacity: var(--f1, 1); object-position: 50% 38%; }
.ff2 { opacity: var(--f2, 0); object-position: 50% 42%; }
.ff3 { opacity: var(--f3, 0); object-position: 50% 46%; }
.faces-scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(rgba(11, 11, 12, 0.34), rgba(11, 11, 12, 0.16) 42%, rgba(11, 11, 12, 0.62));
}
.faces-type {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 0 var(--pad);
}
/* the words stack in one place and cross-dissolve, so the eye never travels */
.fw {
  grid-area: 1 / 1;
  color: #fff;
  font-weight: 300;
  font-size: clamp(2.6rem, 9vw, 7.4rem);
  letter-spacing: -0.034em;
  line-height: 1;
  text-align: center;
  will-change: opacity, transform;
}
.fw1 { opacity: var(--w1, 1); transform: translateY(calc((1 - var(--w1, 1)) * 14px)); }
.fw2 { opacity: var(--w2, 0); transform: translateY(calc((1 - var(--w2, 0)) * 14px)); }
.fw3 { opacity: var(--w3, 0); transform: translateY(calc((1 - var(--w3, 0)) * 14px)); }

@media (prefers-reduced-motion: reduce) {
  .faces { height: auto; }
  .faces-sticky { position: static; height: auto; }
  .ff { position: relative; opacity: 1; height: 56vh; }
  .faces-type { position: static; padding: 30px var(--pad); }
  .fw { grid-area: auto; opacity: 1; transform: none; color: var(--ink); }
  .faces-scrim { display: none; }
}


/* ---------- the mark as scroll position ---------- */
.scrollmark {
  position: fixed;
  right: clamp(18px, 2.2vw, 34px);
  bottom: clamp(18px, 2.2vw, 34px);
  width: 42px;
  z-index: 40;
  opacity: 0;
  transition: opacity 0.5s ease;
  pointer-events: none;
  /* This element floats over both the bone canvas and full-bleed film, so a
     fixed colour is invisible on one of them: ink vanished on the dark
     sections. `difference` against white inverts whatever is behind it, so
     the mark reads dark on bone and light on film with no state tracking. */
  color: #fff;
  mix-blend-mode: difference;
}
.scrollmark.lit { opacity: 1; }
.scrollmark svg { width: 100%; height: auto; display: block; }
.sm-track { opacity: 0.14; }
.sm-fill { stroke-dasharray: 1; }
.sm-fill.s1 { stroke-dashoffset: calc(1 - var(--s1, 0)); }
.sm-fill.s2 { stroke-dashoffset: calc(1 - var(--s2, 0)); }
@media (max-width: 700px) { .scrollmark { display: none; } }

/* ---------- live banner: a floating pill while they stream ---------- */
.livebar {
  position: fixed;
  left: 50%;
  bottom: 22px;
  transform: translateX(-50%);
  z-index: 60;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 11px 18px 11px 14px;
  border-radius: 999px;
  background: var(--ink);
  color: var(--bone);
  font-size: 14px;
  font-weight: 500;
  text-decoration: none;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.22);
  white-space: nowrap;
}
.livebar[hidden] { display: none; }
.livebar-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #e5484d;
  box-shadow: 0 0 0 0 rgba(229, 72, 77, 0.6);
  animation: livebar-pulse 1.8s ease-out infinite;
}
.livebar-cta { opacity: 0.7; }
.livebar:hover .livebar-cta { opacity: 1; }
@keyframes livebar-pulse {
  0% { box-shadow: 0 0 0 0 rgba(229, 72, 77, 0.6); }
  100% { box-shadow: 0 0 0 10px rgba(229, 72, 77, 0); }
}
@media (prefers-reduced-motion: reduce) { .livebar-dot { animation: none; } }

/* ---------- watch page ----------
   Their StreamSpot player, which stays up when YouTube or Facebook drops a
   stream (Matt Landin, 2026-09-22). The other platforms sit under it as
   buttons. */
.player { max-width: var(--max); margin: 0 auto; padding: 0 var(--pad) clamp(50px, 7vw, 90px); }
.player-frame { position: relative; aspect-ratio: 16 / 9; background: var(--film); border-radius: 14px; overflow: hidden; }
.player-frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.player-under { margin-top: 22px; display: flex; flex-wrap: wrap; gap: 14px 22px; align-items: center; justify-content: space-between; }
.player-countdown { width: 265px; height: 105px; border: 0; }
.player-actions { display: flex; flex-wrap: wrap; gap: 12px; }
.btn.ink { background: var(--ink); color: var(--bone); }
.btn.ink:hover { background: var(--ink-soft); }

/* ---------- a poster beside its facts (Dominion) ---------- */
.poster {
  max-width: var(--max);
  margin: 0 auto;
  padding: 0 var(--pad) clamp(60px, 8vw, 110px);
  display: grid;
  grid-template-columns: minmax(240px, 420px) 1fr;
  gap: clamp(28px, 5vw, 70px);
  align-items: start;
}
.poster figure { margin: 0; }
.poster img { width: 100%; height: auto; border-radius: 14px; display: block; }
.poster .facts { list-style: none; display: grid; gap: 22px; padding-top: 6px; }
.poster .facts strong { display: block; font-weight: 500; font-size: 0.9rem; letter-spacing: 0.01em; color: var(--ink-soft); margin-bottom: 4px; }
.poster .facts span, .poster .facts a { font-size: clamp(1.08rem, 1.5vw, 1.3rem); line-height: 1.4; }
@media (max-width: 760px) { .poster { grid-template-columns: 1fr; } }

/* ---------- a mark on its own (Life Academy) ---------- */
.plate { max-width: 560px; margin: 0 auto; padding: 0 var(--pad) clamp(60px, 8vw, 110px); }
.plate img { width: 100%; height: auto; display: block; }
/* the school photos are square or 4:5 in a 3:4 window; the faces sit here */
.cp img.la-teach { object-position: 22% 40%; }
.cp img.la-locker { object-position: 30% 45%; }

/* ---------- long reading (Statement of Faith) ---------- */
.prose { max-width: 72ch; margin: 0 auto; padding: 0 var(--pad) clamp(70px, 10vw, 130px); }
.prose h2 { font-weight: 400; font-size: clamp(1.4rem, 2.4vw, 1.9rem); letter-spacing: -0.02em; margin: 44px 0 14px; }
.prose p { margin-bottom: 18px; font-size: clamp(1rem, 1.25vw, 1.15rem); line-height: 1.6; }
.prose .prose-back { margin-top: 40px; }

/* ---------- staff ----------
   Studio portraits on a dark ground, one window each. The couples fill a 4:5
   frame as shot; the two landscape portraits are placed on the face. */
.staff { max-width: var(--max); margin: 0 auto; padding: 0 var(--pad) clamp(70px, 10vw, 130px); }
.staff-grid { list-style: none; display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: clamp(20px, 3vw, 40px) clamp(16px, 2.5vw, 30px); }
.staff-grid figure { margin: 0; }
.staff-photo { width: 100%; aspect-ratio: 4 / 5; object-fit: cover; object-position: 50% 22%; border-radius: 14px; background: var(--film); display: block; }
.staff-photo.wide { object-position: 50% 45%; }
.staff-grid h3 { margin-top: 14px; font-weight: 500; font-size: 1.12rem; letter-spacing: -0.01em; line-height: 1.25; }
.staff-grid p { margin-top: 3px; color: var(--ink-soft); font-size: 0.96rem; line-height: 1.4; }

/* ---------- live events inside the list ---------- */
.items li.live-event { grid-template-columns: minmax(170px, 0.9fr) 1.6fr; }
.items li.live-event .live-event-when { font-weight: 500; }
.items li.live-event .live-event-where { grid-column: 2; color: var(--ink-soft); font-size: 0.95rem; }

/* ---------- a prayer request, on the light page ---------- */
.ask .ask-lead { max-width: 60ch; margin: -18px 0 30px; color: var(--ink-soft); font-size: clamp(1.02rem, 1.4vw, 1.2rem); line-height: 1.55; }
.rsvp-form { max-width: 560px; display: grid; gap: 18px; }
.rsvp-form label { display: grid; gap: 8px; font-size: 0.95rem; color: var(--ink-soft); }
.rsvp-form input:not([name="website"]), .rsvp-form textarea {
  width: 100%; padding: 14px 16px; font: inherit; font-size: 1.02rem; color: var(--ink);
  background: #fff; border: 1px solid var(--line); border-radius: 12px;
}
.rsvp-form input:focus-visible, .rsvp-form textarea:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.rsvp-form .btn { justify-self: start; margin-top: 4px; }
.rsvp-done { font-size: 1.1rem; line-height: 1.55; }
.rsvp-fail { font-size: 1rem; line-height: 1.55; color: #8a2a2a; }
.week-photo img[src*="events-service"] { object-position: 50% 30%; }

/* The hidden attribute must beat any display rule, or a row that is meant
   to wait for its link (the bulletin, the prayer guides, where to stay)
   shows up empty. Bethel's events list shipped that way once. */
[hidden] { display: none !important; }

/* ---------- the newest service, from their YouTube channel ---------- */
.latest { max-width: var(--max); margin: 0 auto; padding: 0 var(--pad) clamp(50px, 7vw, 90px); }
.latest-card { display: grid; grid-template-columns: minmax(200px, 0.9fr) 1.6fr; gap: clamp(18px, 3vw, 40px); align-items: center; text-decoration: none; color: inherit; border-radius: 14px; background: var(--bone-2); padding: clamp(14px, 2vw, 22px); }
.latest-card img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; border-radius: 10px; background: var(--film); display: block; }
.latest-type { display: grid; gap: 6px; }
.latest-label { font-size: 0.9rem; color: var(--ink-soft); }
.latest-title { font-size: clamp(1.2rem, 2vw, 1.6rem); font-weight: 400; letter-spacing: -0.01em; line-height: 1.2; }
.latest-cta { font-size: 0.95rem; text-decoration: underline; text-underline-offset: 4px; }
@media (max-width: 640px) { .latest-card { grid-template-columns: 1fr; } }
