/* ============================================================
   HOLY LIGHT — Components
   ============================================================ */

/* ---------- Page curtain (transitions) ---------- */
.curtain {
  position: fixed; inset: 0; z-index: var(--z-overlay);
  background: var(--base);
  display: grid; place-items: center;
  pointer-events: none;
}
.curtain__mark { width: 54px; height: 54px; opacity: .9; animation: pulse 1.6s var(--ease-inout) infinite; }
@keyframes pulse { 0%,100% { opacity:.45; transform: scale(.94);} 50% { opacity:1; transform: scale(1);} }

/* ---------- Buttons ---------- */
.btn {
  --btn-bg: transparent;
  --btn-fg: var(--text);
  --btn-bd: var(--line-strong);
  position: relative;
  display: inline-flex; align-items: center; justify-content: center; gap: .55rem;
  font-family: var(--font-display); font-weight: 600; font-size: .95rem;
  letter-spacing: .01em;
  padding: .95rem 1.7rem;
  border-radius: var(--radius-pill);
  background: var(--btn-bg); color: var(--btn-fg);
  border: 1px solid var(--btn-bd);
  overflow: hidden; isolation: isolate;
  transition: transform var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast), color var(--dur-fast);
  white-space: nowrap;
}
.btn::after {                       /* sheen sweep */
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(120deg, transparent 20%, rgba(255,255,255,.22), transparent 80%);
  transform: translateX(-120%);
  transition: transform .7s var(--ease-out);
}
.btn:hover { transform: translateY(-2px); }
.btn:hover::after { transform: translateX(120%); }
.btn:active { transform: translateY(0); }

.btn--gold  { --btn-bg: var(--accent); --btn-fg: var(--btn-gold-text); --btn-bd: var(--accent);
              box-shadow: 0 8px 30px rgba(200,162,75,.28); }
.btn--gold:hover { --btn-bg: var(--accent-hi); --btn-bd: var(--accent-hi); }
.btn--ghost { --btn-bg: transparent; --btn-fg: var(--text); }
.btn--ghost:hover { --btn-bd: var(--accent); --btn-fg: var(--accent); }
.btn--solid { --btn-bg: var(--surface-2); --btn-bd: var(--line); }
.btn--sm    { padding: .6rem 1.15rem; font-size: .85rem; }

/* ---------- Top strip ---------- */
.topbar {
  background: var(--base-2);
  border-bottom: 1px solid var(--line);
  font-size: var(--fs-micro);
  color: var(--text-muted);
  position: relative; z-index: 2;
}
.topbar .wrap-wide { display: flex; justify-content: space-between; align-items: center;
  gap: 1rem; padding-block: .55rem; }
.topbar a:hover { color: var(--accent); }
.topbar__social { display: flex; gap: .55rem; align-items: center; }
.topbar__social a {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: 50%;
  color: var(--text-muted);
  transition: color var(--dur-fast), background var(--dur-fast);
}
.topbar__social a:hover { color: var(--accent); background: rgba(255,255,255,.06); }
.topbar__social svg { width: 15px; height: 15px; display: block; }

/* ---------- Header / nav ---------- */
.header {
  position: sticky; top: 0; z-index: var(--z-nav);
  background: transparent;
  transition: background-color var(--dur) var(--ease-out),
              border-color var(--dur), transform var(--dur) var(--ease-out),
              backdrop-filter var(--dur);
  border-bottom: 1px solid transparent;
}
.header.is-stuck {
  background: var(--header-bg);
  backdrop-filter: blur(16px) saturate(140%);
  -webkit-backdrop-filter: blur(16px) saturate(140%);
  border-bottom-color: var(--line);
}
.header.is-hidden { transform: translateY(-100%); }
.header__inner { display: flex; align-items: center; justify-content: space-between;
  gap: 1.5rem; padding-block: 1rem; }

/* Official logo lock-up */
.brand { display: inline-flex; align-items: center; }
.brand__logo { height: 52px; width: auto; }
.footer .brand__logo { height: 74px; }

.menu { display: flex; align-items: center; gap: 1.6rem; list-style: none; }
.menu > li { position: relative; }
.menu a, .menu__toggle {
  position: relative; display: inline-flex; align-items: center; gap: .32rem;
  font-family: var(--font-display); font-weight: 600;
  font-size: .82rem; letter-spacing: .04em; text-transform: uppercase;
  color: var(--text); padding-block: .35rem;
  transition: color var(--dur-fast);
}
.menu > li > a::after, .menu__toggle::after {
  content: ""; position: absolute; left: 0; bottom: 0;
  width: 0; height: 1.5px; background: var(--accent);
  transition: width .35s var(--ease-out);
}
.menu a:hover, .menu__toggle:hover { color: var(--accent); }
.menu > li > a:hover::after,
.menu > li > a.is-active::after,
.menu__toggle:hover::after,
.has-sub.is-open .menu__toggle::after { width: 100%; }
.has-sub.is-open .menu__toggle svg { transform: rotate(180deg); }
.menu__toggle svg { transition: transform var(--dur-fast) var(--ease-out); }

/* Dropdown */
.submenu {
  position: absolute; top: calc(100% + .9rem); left: -1rem;
  min-width: 250px; list-style: none;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow);
  padding: .5rem; opacity: 0; visibility: hidden;
  transform: translateY(-8px);
  transition: opacity var(--dur-fast) var(--ease-out),
              transform var(--dur-fast) var(--ease-out), visibility var(--dur-fast);
}
.submenu::before {            /* small purple hairline at the top */
  content: ""; position: absolute; top: 0; left: 1.2rem; right: 1.2rem; height: 2px;
  background: linear-gradient(90deg, var(--purple-glow), var(--accent));
  border-radius: 2px;
}
.has-sub:hover .submenu,
.has-sub.is-open .submenu { opacity: 1; visibility: visible; transform: translateY(0); }
.submenu a {
  display: block; width: 100%; padding: .6rem .8rem; border-radius: var(--radius-sm);
  font-size: .78rem; text-transform: none; letter-spacing: .01em; font-weight: 500;
  color: var(--text-muted);
}
.submenu a:hover { background: var(--surface-2); color: var(--accent); }

.header__cta { display: flex; align-items: center; gap: .6rem; }

/* Hamburger */
.hamburger { display: none; width: 44px; height: 44px; position: relative; }
.hamburger span {
  position: absolute; left: 11px; width: 22px; height: 2px; border-radius: 2px;
  background: var(--text); transition: transform .35s var(--ease-out), opacity .2s;
}
.hamburger span:nth-child(1) { top: 16px; }
.hamburger span:nth-child(2) { top: 21px; }
.hamburger span:nth-child(3) { top: 26px; }
.hamburger.is-open span:nth-child(1) { transform: translateY(5px) rotate(45deg); }
.hamburger.is-open span:nth-child(2) { opacity: 0; }
.hamburger.is-open span:nth-child(3) { transform: translateY(-5px) rotate(-45deg); }

/* ---------- HERO ---------- */
.hero {
  position: relative; min-height: 100svh;
  display: grid; align-items: center;
  overflow: hidden;
  background: var(--base);
}
.hero__bg { position: absolute; inset: 0; z-index: 0; }
.hero__bg::after { content: ""; position: absolute; inset: 0; background: var(--glow-hero); }
.hero__img,
.hero__video {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover;
}
/* Still holds the frame until the video can play.
   The leadership banner is a light-background graphic, so it needs darkening
   and desaturating to sit inside the dark hero rather than blowing it out. */
.hero__img {
  opacity: .42;
  filter: brightness(.5) contrast(1.06) saturate(.8);
  object-position: 68% center;      /* favour the portraits, not the baked-in text */
  transition: opacity 1.2s var(--ease-out);
}
.hero__video { opacity: 0;  transition: opacity 1.2s var(--ease-out); }

/* ...then they cross-fade. The still MUST go to 0 — leaving both at 50%
   blends them into a double exposure. */
.hero__bg.is-video .hero__img { opacity: 0; }
.hero__video.is-ready         { opacity: .5; }
.hero__scrim { position: absolute; inset: 0; background: var(--scrim); z-index: 1; }
/* Embers sit above the scrim so they read as light, below the text.
   Strength is a token — this should whisper, not compete with the headline. */
.hero__embers {
  position: absolute; inset: 0; width: 100%; height: 100%;
  display: block; pointer-events: none; z-index: 2;
  opacity: var(--embers-strength, .8);
  /* Softens the points into glowing motes rather than sharp dots */
  filter: blur(var(--embers-blur, 2px));
}
.hero__grain { z-index: 2; }
.hero__grain {
  position: absolute; inset: 0; opacity: .16; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E");
}
/* The hero is already min-height:100svh — this padding was stacking on top
   of a full screen, pushing the scroll cue off the bottom on laptops. */
.hero__inner { position: relative; z-index: 2; padding-block: clamp(3.5rem, 9vh, 6rem); }
.hero__title {
  font-size: var(--fs-hero); line-height: var(--lh-tight);
  letter-spacing: -.045em; font-weight: 700; margin-block: 1.2rem .9rem;
  text-wrap: balance;
}
.hero__title em { font-style: normal; color: var(--accent); }
.hero__sub { font-size: clamp(1.05rem, 1.7vw, 1.3rem); color: var(--text-muted); max-width: 46ch; }
.hero__actions { display: flex; flex-wrap: wrap; gap: .8rem; margin-top: 2.2rem; }

.hero__meta {
  display: flex; flex-wrap: wrap; gap: 2.5rem;
  margin-top: 3.4rem; padding-top: 1.8rem;
  border-top: 1px solid var(--line);
}
.hero__meta div strong {
  display: block; font-family: var(--font-display); font-size: 1.05rem; color: var(--text);
}
.hero__meta div span { font-size: var(--fs-small); color: var(--text-muted); }

.scroll-cue {
  position: absolute; bottom: 2rem; left: 50%; transform: translateX(-50%);
  z-index: 3; display: flex; flex-direction: column; align-items: center; gap: .55rem;
  font-size: var(--fs-micro); letter-spacing: var(--tracking-wide);
  text-transform: uppercase; color: var(--text-dim);
}
.scroll-cue__line { width: 1px; height: 46px; background: linear-gradient(var(--accent), transparent); }

/* ---------- Broadcast player ---------- */
.player {
  border-radius: var(--radius-lg); overflow: hidden;
  background: var(--surface); border: 1px solid var(--line);
  box-shadow: var(--shadow);
}
.player__bar {
  display: flex; align-items: center; gap: .7rem; flex-wrap: wrap;
  padding: .85rem 1.1rem;
  background: linear-gradient(90deg, var(--ember-deep), var(--surface-2));
  border-bottom: 1px solid var(--line);
}
.player__tab {
  display: inline-flex; align-items: center; gap: .4rem;
  font-family: var(--font-display); font-weight: 600; font-size: .8rem;
  color: #E8D9CC; background: rgba(255,255,255,.07);
  border: 1px solid rgba(255,255,255,.14);
  padding: .45rem .95rem; border-radius: var(--radius-pill);
  transition: all var(--dur-fast);
}
.player__tab:hover { color: #fff; background: rgba(255,255,255,.15); }
.player__tab.is-active { background: var(--accent); color: var(--btn-gold-text); border-color: var(--accent); }
.player__note { margin-left: auto; font-size: .78rem; color: #C2B3A6; }

/* Resting state: a label, not a claim.
   This badge was hardcoded red with a blinking dot, so the site announced
   "LIVE" every hour of every day. player.js already tracks the real state and
   puts .is-onair on the tab — the styling simply never used it, which meant
   the one week it mattered looked identical to a Tuesday afternoon. */
.live-badge {
  display: inline-flex; align-items: center; gap: .4rem;
  background: rgba(255,255,255,.10); color: var(--text-muted);
  font-size: .68rem; font-weight: 700;
  letter-spacing: .08em; padding: .2rem .55rem; border-radius: 5px;
  transition: background var(--dur-fast), color var(--dur-fast);
}
.live-dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: currentColor; opacity: .55;
}

/* Actually on air. Only now does it earn the red and the pulse. */
.player__tab.is-onair .live-badge { background: #d92d20; color: #fff; }
.player__tab.is-onair .live-dot   { opacity: 1; animation: blink 1.4s infinite; }
@keyframes blink { 50% { opacity: .25; } }
@media (prefers-reduced-motion: reduce) {
  .player__tab.is-onair .live-dot { animation: none; }
}

.player__frame { position: relative; aspect-ratio: 16/9; background: #06040a; cursor: pointer; }
.player__poster {
  position: absolute; inset: 0; display: grid; place-content: center; justify-items: center;
  gap: 1.1rem; text-align: center;
  background:
    radial-gradient(620px 320px at 50% 38%, rgba(243,111,39,.34), transparent 70%),
    linear-gradient(160deg, #2A1710, #0A0705);
}
/* The logo, watermarked behind the play button.
   YouTube's own thumbnail was tried first and dropped: the stream's graphic
   is a purple/blue gradient, and it fought the flame palette every week.
   A fixed mark is quieter, always on-brand, and needs no network request. */
.player__poster::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  /* Filling the frame. Opacity comes down as the size goes up — the same
     30% that read as a faint mark at 420px would be a wall of logo at this
     scale, and the play button still has to be the first thing seen. */
  background: url("../img/logo-dark.png") center 42% / min(88%, 880px) auto no-repeat;
  opacity: .22;
}
.player__poster > * { position: relative; z-index: 1; }
.player__date { color: var(--accent); font-weight: 600; }

.player__play {
  width: 84px; height: 84px; border-radius: 50%; background: var(--accent);
  display: grid; place-items: center; box-shadow: 0 12px 40px rgba(249,155,39,.42);
  transition: transform var(--dur-fast) var(--ease-out), background var(--dur-fast);
}
.player__frame:hover .player__play { transform: scale(1.08); background: var(--accent-hi); }
.player__label { font-family: var(--font-display); font-weight: 600; color: #fff; }
.player__small { font-size: .84rem; color: #D9C8BA; }
.player__frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* Off-air state — shown instead of YouTube's "this live event has ended" */
.player__poster--offair { cursor: default; gap: 1.3rem; padding: 1.5rem; }
.player__offair-icon {
  width: 62px; height: 62px; border-radius: 50%;
  display: grid; place-items: center;
  color: var(--accent);
  border: 1px solid rgba(255,255,255,.16);
  background: rgba(255,255,255,.05);
}
.player__offair-actions {
  display: flex; gap: .6rem; flex-wrap: wrap; justify-content: center;
}
/* Live tab gets a gentle nudge when a service actually starts */
.player__tab.is-onair { box-shadow: 0 0 0 3px rgba(217,45,32,.28); }
.player__foot {
  display: flex; justify-content: space-between; align-items: center; gap: 1rem;
  flex-wrap: wrap; padding: .85rem 1.1rem;
  background: var(--surface-2); font-size: .84rem; color: var(--text-muted);
  border-top: 1px solid var(--line);
}
.player__foot a { color: var(--accent); font-family: var(--font-display); font-weight: 600; }
.player__foot a:hover { color: var(--accent-hi); }

/* ---------- Giving bar ---------- */
.give {
  margin-top: 1.4rem; padding: 1.6rem;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-sm);
}
.give__head { text-align: center; margin-bottom: 1.3rem; }
.give__head h3 { font-size: 1.35rem; }
.give__head p { color: var(--text-muted); font-size: .92rem; margin-top: .25rem; }
.give__grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: .7rem; }
.give__grid--3 { grid-template-columns: repeat(3, 1fr); max-width: 620px; margin-inline: auto; }
.give__grid--5 { grid-template-columns: repeat(5, 1fr); gap: 1rem; }

/* Larger cards for the dedicated Give page */
.give__btn--lg { padding: 1.7rem 1rem 1.5rem; gap: .55rem; }
.give__btn--lg .give__icon { width: 46px; height: 46px; font-size: .95rem; border-radius: 13px; }
.give__btn--lg b { font-size: 1rem; }
.give__btn--lg small { font-size: .78rem; line-height: 1.4; color: var(--accent); }
.give__note-sm {
  font-size: .72rem; color: var(--text-dim); line-height: 1.45; margin-top: .35rem;
}
/* "By Mail" has no link, so it must not look clickable */
.give__btn--static { cursor: default; }
.give__btn--static:hover { transform: none; border-color: var(--line); box-shadow: none; }

/* Zelle: copied, not linked — you type the address into your own bank app */
.give__btn--copy { cursor: pointer; }
.give__copy {
  margin-top: .5rem; font-size: .68rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--accent);
  border: 1px solid var(--line-strong); border-radius: var(--radius-pill);
  padding: .28rem .7rem; transition: all var(--dur-fast);
}
.give__btn--copy:hover .give__copy { border-color: var(--accent); }
.give__btn--copy.is-copied { border-color: var(--accent); }
.give__btn--copy.is-copied .give__copy {
  background: var(--accent); color: var(--btn-gold-text); border-color: var(--accent);
}

@media (max-width: 1000px) { .give__grid--5 { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 620px)  { .give__grid--5 { grid-template-columns: repeat(2, 1fr); } }
.give__btn {
  display: flex; flex-direction: column; align-items: center; gap: .45rem;
  padding: 1.05rem .5rem; text-align: center;
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--radius); transition: all var(--dur-fast) var(--ease-out);
}
.give__btn:hover {
  border-color: var(--accent); transform: translateY(-4px);
  box-shadow: 0 12px 30px rgba(0,0,0,.3);
}
.give__icon {
  width: 38px; height: 38px; border-radius: 11px; display: grid; place-items: center;
  font-family: var(--font-display); font-weight: 700; font-size: .82rem; color: #fff;
}
/* White tile behind each brand mark. These logos were drawn to sit on white —
   Zelle's purple and PayPal's navy both disappear against our near-black, and
   recolouring someone else's trademark is not ours to do. */
.give__icon--logo { background: #fff; padding: 5px; }
.give__icon--logo img { width: 100%; height: 100%; object-fit: contain; display: block; }
.give__btn b { font-family: var(--font-display); font-size: .87rem; color: var(--text); }
.give__btn small { font-size: .7rem; color: var(--text-muted); }
.give__note { text-align: center; margin-top: 1.1rem; font-size: .82rem; color: var(--text-muted); }
.give__note b { color: var(--accent); }

/* ---------- Sticky scroll story ---------- */
.story { position: relative; }
.story__sticky {
  position: sticky; top: 0; height: 100svh;
  display: grid; place-items: center; overflow: hidden;
}
/* Each panel MUST be opaque: they are consecutive sticky siblings that pin at
   the same offset, so a transparent panel lets the previous one show through
   and the headlines visibly overlap. */
.story__media {
  position: absolute; inset: 0;
  background: var(--base);
}
/* These are generated stand-ins, not real photographs of the congregation.
   A slight blur keeps them atmospheric and stops them reading as documentary.
   The scale-up hides the soft/transparent edge that blur creates.
   Tune with --story-blur; set it to 0 once real photos are dropped in. */
.story__media img, .story__media video {
  width: 100%; height: 100%; object-fit: cover; opacity: .32;
  filter: blur(var(--story-blur, 14px));
  /* scale must grow with the blur, or the softened edge shows as a seam */
  transform: scale(var(--story-blur-scale, 1.14));
}
.story__media::after { content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(10,7,5,.55), rgba(10,7,5,.88)); }
/* Subtle tint per panel so the stack still reads as movement without photos */
.story__sticky:nth-child(1) .story__media { background:
  radial-gradient(900px 600px at 70% 20%, rgba(249,155,39,.10), transparent 65%), var(--base); }
.story__sticky:nth-child(2) .story__media { background:
  radial-gradient(900px 600px at 25% 70%, rgba(106,71,184,.14), transparent 65%), var(--base); }
.story__sticky:nth-child(3) .story__media { background:
  radial-gradient(900px 600px at 50% 40%, rgba(240,72,40,.12), transparent 65%), var(--base); }
.story__content { position: relative; z-index: 2; text-align: center; max-width: 44ch; }
/* Promo panels carry a CTA and a slightly stronger scrim, since event
   artwork is usually busier than the evergreen imagery. */
.story__sticky--promo .story__media::after {
  background: linear-gradient(180deg, rgba(10,7,5,.62), rgba(10,7,5,.92));
}
.story__cta { margin-top: .4rem; }
.story__num {
  font-family: var(--font-display); font-size: .78rem; letter-spacing: var(--tracking-wide);
  color: var(--accent); margin-bottom: 1rem;
  display: inline-flex; align-items: center; gap: .7rem;
}
.story__num::before {          /* small purple tick */
  content: ""; width: 22px; height: 2px; border-radius: 2px;
  background: var(--purple-glow);
}

/* ---------- Cards ---------- */
.cards { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.15rem; }
.card {
  position: relative; padding: 1.9rem 1.5rem 1.6rem;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-lg); overflow: hidden;
  transition: transform var(--dur) var(--ease-out), border-color var(--dur);
}
/* Each card carries the header of the page it leads to, so the tile is a
   glimpse of the destination rather than four identical dark rectangles.
   Kept dim: this is a backdrop for the words, and a card you cannot read is
   worse than a card with nothing behind it. It lifts on hover, which is the
   only moment the picture is what you are looking at. */
.card--bg { padding-top: 2.2rem; }
.card__bg {
  position: absolute; inset: 0; z-index: 0;
  width: 100%; height: 100%; object-fit: cover;
  opacity: .20; filter: saturate(.85);
  transition: opacity var(--dur) var(--ease-out), transform 1.1s var(--ease-out);
}
.card--bg:hover .card__bg { opacity: .34; transform: scale(1.06); }
/* Weighted to the bottom, where the text sits. */
.card--bg::after {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(180deg,
    rgba(21,16,12,.55) 0%, rgba(21,16,12,.80) 45%, rgba(21,16,12,.95) 100%);
}
.card--bg > *:not(.card__bg) { position: relative; z-index: 2; }

.card::before {
  content: ""; position: absolute; inset: 0;
  background: var(--glow-soft); opacity: 0;
  transition: opacity var(--dur) var(--ease-out); pointer-events: none;
}
.card:hover { transform: translateY(-8px); border-color: var(--line-strong); }
.card:hover::before { opacity: 1; }
/* Ember → purple: the small cool note that makes the flame icon read hotter */
.card__icon {
  width: 52px; height: 52px; border-radius: 15px; display: grid; place-items: center;
  background: linear-gradient(150deg, var(--ember) 0%, var(--purple-deep) 100%);
  border: 1px solid rgba(255,255,255,.10); margin-bottom: 1.15rem;
  transition: background var(--dur) var(--ease-out);
}
.card:hover .card__icon {
  background: linear-gradient(150deg, var(--ember) 0%, var(--purple) 100%);
}
.card h3 { font-size: 1.18rem; margin-bottom: .45rem; }
.card p  { font-size: .93rem; color: var(--text-muted); margin-bottom: 1.05rem; }
.card__more {
  font-family: var(--font-display); font-weight: 600; font-size: .87rem; color: var(--accent);
  display: inline-flex; align-items: center; gap: .4rem;
}
.card__more span { transition: transform var(--dur-fast) var(--ease-out); }
.card:hover .card__more span { transform: translateX(5px); }

/* ---------- Stat strip ---------- */
.stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; text-align: center; }
.stat__num {
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(2rem, 4.5vw, 3.4rem); color: var(--accent);
  letter-spacing: -.03em; line-height: 1;
}
.stat__label { font-size: var(--fs-small); color: var(--text-muted); margin-top: .5rem; }

/* ---------- Wireframe city ("Find Us") ---------- */
.city-section {
  position: relative; overflow: hidden;
  min-height: 100svh; display: grid; align-items: center;
  background: var(--base);
}
.city { position: absolute; inset: 0; }
.city canvas,
.city__video { width: 100%; height: 100%; display: block; object-fit: cover; }

/* Satellite imagery is bright and busy — light text needs real help.
   Darkening the footage itself does more for legibility than any overlay,
   and it keeps the section consistent with the rest of the dark theme. */
.city__video { filter: brightness(var(--city-dim, .45)) contrast(1.08) saturate(.85); }

.city::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    /* heavy on the left where the copy sits, easing off over the church */
    linear-gradient(90deg,
      rgba(10,7,5,.96) 0%,
      rgba(10,7,5,.88) 30%,
      rgba(10,7,5,.55) 55%,
      rgba(10,7,5,.35) 75%,
      rgba(10,7,5,.6)  100%),
    /* vignette to pull the eye inward */
    radial-gradient(75% 70% at 60% 50%, transparent 25%, rgba(10,7,5,.65) 100%);
}
.city--fallback canvas { display: none; }
.city--fallback::before {            /* mobile / reduced-motion: real aerial */
  content: ""; position: absolute; inset: 0;
  background: url("../img/portsmouth.jpg") center/cover no-repeat;
  opacity: .55;
}
.city-section__content {
  position: relative; z-index: 2; max-width: 34ch;
  /* insurance: keeps text readable even if a bright frame slips through */
  text-shadow: 0 2px 18px rgba(0,0,0,.85), 0 1px 3px rgba(0,0,0,.6);
}
.city-section__addr {
  font-family: var(--font-display); font-size: 1.05rem;
  color: var(--text); margin-top: 1.2rem; line-height: 1.6;
}
.city-section__hours {
  margin-top: 1.4rem; padding-top: 1.2rem; border-top: 1px solid var(--line);
  display: flex; flex-direction: column; gap: .55rem;
  font-size: var(--fs-small); color: var(--text-muted);
}
.city-section__hours b { color: var(--text); font-family: var(--font-display); font-weight: 600; }
/* Imagery attribution — required by Google's Geo Guidelines.
   Must stay near the content, not relegated to the page footer. */
.city-attrib {
  position: absolute; left: 0; right: 0; bottom: 1rem; z-index: 3;
  text-align: center; font-size: .66rem; letter-spacing: .04em;
  color: rgba(255,255,255,.5); pointer-events: none;
}

.city-pin {
  display: inline-flex; align-items: center; gap: .5rem;
  font-size: var(--fs-micro); letter-spacing: var(--tracking-wide);
  text-transform: uppercase; color: var(--accent);
}
.city-pin::before {
  content: ""; width: 9px; height: 9px; border-radius: 50%;
  background: var(--accent); box-shadow: 0 0 0 4px rgba(249,155,39,.22);
  animation: pinPulse 2.2s var(--ease-inout) infinite;
}
@keyframes pinPulse {
  0%,100% { box-shadow: 0 0 0 4px rgba(249,155,39,.22); }
  50%     { box-shadow: 0 0 0 10px rgba(249,155,39,0); }
}
@media (max-width: 900px) {
  /* Copy is full-width here, so the scrim has to run vertically instead. */
  .city::after {
    background: linear-gradient(180deg,
      rgba(10,7,5,.55) 0%, rgba(10,7,5,.8) 45%, rgba(10,7,5,.95) 100%);
  }
  .city-section__content { max-width: none; }
}

/* ---------- Inner-page header ---------- */
.page-hero {
  position: relative; overflow: hidden;
  padding-block: clamp(4.5rem, 12vh, 8rem) clamp(3rem, 7vh, 5rem);
  background: var(--base);
  border-bottom: 1px solid var(--line);
  text-align: center;
}
.page-hero::before {
  content: ""; position: absolute; inset: 0;
  background: var(--glow-hero); opacity: .8; pointer-events: none;
}
.page-hero::after {                 /* faint grain, same as the home hero */
  content: ""; position: absolute; inset: 0; opacity: .12; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E");
  pointer-events: none;
}
.page-hero__inner { position: relative; z-index: 1; }
.page-hero h1 {
  font-size: clamp(2rem, 5vw, 3.6rem);
  margin-top: .8rem; text-wrap: balance;
}
.page-hero__sub {
  margin: 1.1rem auto 0; max-width: 56ch;
  color: var(--text-muted); font-size: clamp(1rem, 1.4vw, 1.12rem);
}

/* ---------- Inner-page header, photographic variant ----------
   The photographs are the old Gantry page headers, about 750px wide, so they
   are upscaled roughly 2x. The scrim earns its keep twice over: it buys
   contrast for the type, and it hides the softness. Do not lighten it much. */
.page-hero--banner {
  padding-block: clamp(6rem, 17vh, 10.5rem) clamp(4rem, 9vh, 6.5rem);
  text-align: left;
}
.page-hero__bg {
  position: absolute; inset: 0; z-index: 0;
  width: 100%; height: 100%;
  object-fit: cover; object-position: center 40%;
}
/* Above the photo, below the text. Weighted left so the heading always has
   ground under it while the right of the picture stays open. */
.page-hero--banner::before {
  z-index: 1;
  background:
    linear-gradient(90deg,
      rgba(10,7,5,.94) 0%, rgba(10,7,5,.86) 32%,
      rgba(10,7,5,.58) 64%, rgba(10,7,5,.42) 100%),
    linear-gradient(to bottom,
      rgba(10,7,5,.72) 0%, rgba(10,7,5,.20) 42%, rgba(10,7,5,.78) 100%);
  opacity: 1;
}
.page-hero--banner::after { z-index: 2; }
.page-hero--banner .page-hero__inner { z-index: 3; }
.page-hero--banner .page-hero__sub { margin-inline: 0; }

@media (max-width: 700px) {
  /* Narrow screens crop most of the picture away, so the gradient turns
     vertical — otherwise the heading lands on the one bright patch left. */
  .page-hero--banner::before {
    background:
      linear-gradient(to bottom,
        rgba(10,7,5,.66) 0%, rgba(10,7,5,.30) 38%, rgba(10,7,5,.92) 100%);
  }
  .page-hero__bg { object-position: center 32%; }
}


/* ---------- Live bar (every page, while a service is on) ---------- */
.livebar {
  position: sticky; top: 0; z-index: 60;
  display: flex; align-items: center; justify-content: center;
  gap: .7rem; flex-wrap: wrap;
  padding: .6rem 1rem;
  background: linear-gradient(90deg, #B3231A, #F04828 55%, #F26428);
  color: #fff; font-size: .88rem; text-align: center;
}
.livebar strong { font-family: var(--font-display); letter-spacing: .04em; }
.livebar__name { opacity: .92; }
.livebar__dot {
  width: 9px; height: 9px; border-radius: 50%; background: #fff;
  box-shadow: 0 0 0 0 rgba(255,255,255,.7);
  animation: livepulse 1.9s ease-out infinite;
}
@keyframes livepulse {
  70%  { box-shadow: 0 0 0 9px rgba(255,255,255,0); }
  100% { box-shadow: 0 0 0 0 rgba(255,255,255,0); }
}
/* Amber rather than red before it starts — red says "happening now", and
   claiming that five minutes early is the sort of small lie people notice. */
.livebar--soon { background: linear-gradient(90deg, #8A4A12, #C4611A 55%, #F99B27); }
.livebar--soon .livebar__dot { animation: none; opacity: .85; }
.livebar__cta {
  background: rgba(0,0,0,.28); border: 1px solid rgba(255,255,255,.4);
  padding: .28rem .8rem; border-radius: var(--radius-pill);
  font-weight: 600; font-size: .82rem; color: #fff;
}
.livebar__cta:hover { background: #fff; color: #B3231A; }
@media (prefers-reduced-motion: reduce) { .livebar__dot { animation: none; } }

/* ---------- Live hero (home page) ---------- */
.livehero {
  background: #000; border-bottom: 1px solid var(--line);
  padding: clamp(1rem, 3vh, 2.5rem) 0 clamp(1.5rem, 4vh, 3rem);
}
.livehero__stage {
  width: min(1280px, 94vw); margin-inline: auto;
  aspect-ratio: 16 / 9; position: relative;
  border-radius: 14px; overflow: hidden;
  background: linear-gradient(160deg, #2A1710, #0A0705);
  display: grid; place-items: center;
}
.livehero__stage iframe {
  position: absolute; inset: 0; width: 100%; height: 100%; border: 0;
}
.livehero__soon { text-align: center; padding: 1.5rem; }
.livehero__kicker {
  font-family: var(--font-display); color: var(--accent);
  letter-spacing: .12em; text-transform: uppercase; font-size: .82rem;
}
.livehero__count {
  font-family: var(--font-display); font-weight: 700; line-height: 1;
  font-size: clamp(4rem, 14vw, 8rem); color: var(--text); margin: .5rem 0 .2rem;
}
.livehero__unit { color: var(--text-muted); font-size: .95rem; }
/* Used on Facebook nights in place of the countdown number, so the hero still
   reads as "something is happening now" without a number to show. */
/* Facebook blue, not the site palette. A platform mark is a wayfinding
   signal — recolouring it to match the page makes it stop working as one. */
.livehero__fb { margin: 0 0 .6rem; color: #1877F2; line-height: 0; }
.livehero__fb svg { display: inline-block; }
.livehero__live {
  margin: 0 0 .35rem; font-family: var(--font-display), serif;
  font-size: clamp(1.6rem, 4vw, 2.6rem); line-height: 1.1; color: #fff;
}
.livehero__note { margin-top: 1.4rem; font-size: .86rem; color: var(--text-muted); }
.livehero__note a { color: var(--accent); text-decoration: underline; }
/* Sits below the iframe, not over it — the whole point is that it stays
   reachable when YouTube is showing an error we cannot see or restyle. */
.livehero__note--under {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  margin: 0; padding: .6rem 1rem; text-align: center;
  background: linear-gradient(180deg, transparent, rgba(0,0,0,.82) 45%);
  color: rgba(255,255,255,.9);
}
.livehero__note--under .link { color: var(--accent); text-decoration: underline; }

/* ---------- Floating social ---------- */
.social-float {
  position: fixed; left: 50%; transform: translateX(-50%) translateY(14px);
  bottom: clamp(.9rem, 3vh, 1.6rem); z-index: 55;
  display: flex; gap: .35rem; padding: .4rem;
  background: rgba(22,16,12,.82); backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  border: 1px solid var(--line-strong); border-radius: var(--radius-pill);
  box-shadow: 0 12px 34px rgba(0,0,0,.5);
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .4s var(--ease-out), transform .4s var(--ease-out), visibility .4s;
}
.social-float.is-shown {
  opacity: 1; visibility: visible; pointer-events: auto;
  transform: translateX(-50%) translateY(0);
}
.social-float a {
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; border-radius: 50%;
  transition: color var(--dur-fast), background var(--dur-fast), transform var(--dur-fast);
}
.social-float a:hover { background: rgba(255,255,255,.10); transform: translateY(-2px); }
.social-float svg { width: 17px; height: 17px; display: block; }

.footer__social { display: flex; gap: .5rem; margin-bottom: .4rem; }
.footer__social a {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: 50%;
  border: 1px solid var(--line);
  transition: border-color var(--dur-fast), background var(--dur-fast);
}
.footer__social a:hover { background: rgba(255,255,255,.06); }
.footer__social svg { width: 17px; height: 17px; display: block; }

/* ---------- Social brand colours ----------
   The icons draw with currentColor, so setting colour on the anchor is all
   it takes. Selected by aria-label rather than position, so reordering the
   markup cannot quietly turn Facebook red.

   These are the platforms' own colours, not ours. That is the point: on a
   page this deliberately monotone, three small marks of real colour read as
   "these are other places we live" rather than as decoration. */
.footer__social a[aria-label="Facebook"],
.social-float  a[aria-label="Facebook"]  { color: #4A9BFF; }
.footer__social a[aria-label="Instagram"],
.social-float  a[aria-label="Instagram"] { color: #F0568F; }
.footer__social a[aria-label="YouTube"],
.social-float  a[aria-label="YouTube"]   { color: #FF4B45; }

/* Lifted off the true brand values — #1877F2 and #FF0000 sit too dark against
   #0A0705 to read at 17px. These are the same hues, raised until they do. */
.footer__social a[aria-label="Facebook"]:hover,
.social-float  a[aria-label="Facebook"]:hover  { color: #7FBAFF; border-color: #4A9BFF; }
.footer__social a[aria-label="Instagram"]:hover,
.social-float  a[aria-label="Instagram"]:hover { color: #FF7FAC; border-color: #F0568F; }
.footer__social a[aria-label="YouTube"]:hover,
.social-float  a[aria-label="YouTube"]:hover   { color: #FF7A75; border-color: #FF4B45; }

/* ---------- Promo panels (a featured event takes over a story panel) ----------
   The story panels blur their imagery to 32% opacity because those are
   atmospheric stand-ins — background, not content. A flyer is the opposite:
   it is the message, the church designed it, and every one of these overrides
   exists to undo a treatment that would bury it. */
.story__sticky--promo .story__media img {
  object-fit: contain;      /* whole flyer, never cropped */
  opacity: 1;               /* was .32 */
  filter: none;             /* was blur(14px) */
  transform: none;          /* was scale(1.14), which existed to hide blur edges */
  padding: clamp(2rem, 6vh, 4rem) 1rem clamp(11rem, 26vh, 15rem);
}
/* Scrim only under the text, so the flyer keeps its colour. */
.story__sticky--promo .story__media::after {
  background: linear-gradient(180deg,
    rgba(10,7,5,.30) 0%, rgba(10,7,5,0) 22%,
    rgba(10,7,5,0) 46%, rgba(10,7,5,.90) 78%, rgba(10,7,5,.97) 100%);
}
.story__sticky--promo .story__content {
  align-self: end; padding-bottom: clamp(2.5rem, 7vh, 4.5rem); text-align: center;
}
.story__sticky--promo .story__content h2 { text-wrap: balance; }

@media (min-width: 900px) {
  /* Wide screens: a 9:16 flyer contained in a 16:9 panel leaves a lot of empty
     ground either side. Put the flyer on the right and the words on the left
     and that space becomes the layout instead of a gap. */
  .story__sticky--promo .story__media img {
    object-position: 76% center;
    padding: clamp(2rem, 7vh, 5rem) 2rem;
  }
  .story__sticky--promo .story__media::after {
    background: linear-gradient(90deg,
      rgba(10,7,5,.94) 0%, rgba(10,7,5,.86) 30%,
      rgba(10,7,5,.30) 52%, rgba(10,7,5,0) 68%);
  }
  .story__sticky--promo .story__content {
    align-self: center; text-align: left;
    max-width: 46%; margin-right: auto; padding-bottom: 0;
  }
}

/* ---------- Holding page (HLCB, Store) ----------
   An "under construction" page still owes the visitor an answer. The phone
   number is the point of the page, so it is the largest thing on it after
   the heading — not a footnote. */
.holding { max-width: 62ch; margin-inline: auto; text-align: center; }
.holding h2 {
  font-family: var(--font-display);
  font-size: clamp(1.4rem, 3vw, 2rem); margin-bottom: 1.2rem;
}
.holding p { color: var(--text-muted); margin-bottom: 1.1rem; line-height: 1.7; }
.holding__seal { width: min(190px, 42vw); height: auto; margin: 0 auto 2rem; display: block; }
.holding__mark { color: var(--accent); font-size: 2rem; margin-bottom: 1.4rem; }
.holding__cta {
  margin-top: 2.6rem; padding: 2rem 1.5rem;
  background: var(--surface); border: 1px solid var(--line); border-radius: 14px;
}
.holding__lead { color: var(--text); margin-bottom: 1.3rem; }
.holding__cta .btn { font-size: 1.15rem; padding: 1rem 2.2rem; }

/* ---------- Events list ----------
   Cards are portrait because the flyers are. The church admin builds them at
   9:16, and a 16:9 card would crop the top and bottom off every one — which
   on a flyer is usually the date and the phone number. */
.evlist { list-style: none; padding: 0; margin: 0; display: grid; gap: 1.4rem;
          grid-template-columns: repeat(auto-fill, minmax(258px, 1fr)); }

.evcard {
  display: flex; flex-direction: column; height: 100%;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 14px; overflow: hidden;
}
.evcard:hover { border-color: var(--accent); }
.evcard__img { display: block; aspect-ratio: 9 / 16; background: var(--surface-2);
               overflow: hidden; position: relative; }
/* contain, not cover: a flyer is information, and cropping it loses some.
   The tinted backdrop fills whatever the aspect does not. */
.evcard__img img { width: 100%; height: 100%; object-fit: contain; display: block;
                   transition: transform .7s var(--ease-out); }
.evcard:hover .evcard__img img { transform: scale(1.03); }

/* No banner? Show the date instead — a card with an empty grey box on it
   reads as broken, a card with a date reads as deliberate. */
.evcard__date {
  position: absolute; inset: 0; display: grid; place-content: center; text-align: center;
  background: linear-gradient(150deg, var(--surface-3), var(--surface));
}
.evcard__date strong { font-family: var(--font-display); font-size: 2.6rem;
                       color: var(--accent); line-height: 1; display: block; }
.evcard__date small { font-size: .82rem; letter-spacing: .14em; text-transform: uppercase;
                      color: var(--text-muted); }

.evcard__meta { display: block; padding: 1.1rem 1.25rem 1.3rem; }
.evcard__cat { font-size: .7rem; letter-spacing: .12em; text-transform: uppercase;
               color: var(--accent); display: block; margin-bottom: .35rem; }
.evcard__meta strong { font-family: var(--font-display); font-size: 1.16rem;
                       display: block; margin-bottom: .3rem; text-wrap: balance; }
.evcard__meta small { color: var(--text-muted); font-size: .87rem; }
.evcard__file { display: block; margin-top: .6rem; font-size: .8rem; color: var(--text-dim); }

.evlist--past { grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: .8rem; }
.evlist--past .evcard__meta { padding: .9rem 1.1rem; }
.evlist--past .evcard__meta strong { font-size: 1rem; }

/* ---------- One event ---------- */
.ev { display: grid; gap: 2rem; grid-template-columns: minmax(0, 2fr) minmax(260px, 1fr); }
.ev__banner { grid-column: 1; border-radius: 14px; overflow: hidden;
              border: 1px solid var(--line); background: var(--surface);
              display: grid; place-items: center; }
/* Shown whole, never cropped — this is the flyer, and every corner of it is
   something the church meant to say. Capped by height so a 9:16 flyer does
   not run past a laptop screen and force a scroll to read the bottom. */
.ev__banner img { max-width: 100%; max-height: 78vh; width: auto; height: auto; display: block; }
.ev__side { grid-column: 2; grid-row: 1 / span 2; align-self: start;
            position: sticky; top: 6rem; }
.ev__body { grid-column: 1; max-width: none; }

.ev__facts { background: var(--surface); border: 1px solid var(--line);
             border-radius: 14px; padding: 1.4rem 1.5rem; margin: 0; }
.ev__facts dt { font-size: .72rem; letter-spacing: .12em; text-transform: uppercase;
                color: var(--accent); margin-bottom: .25rem; }
.ev__facts dd { margin: 0 0 1.2rem; color: var(--text); font-size: .96rem; line-height: 1.55; }
.ev__facts dd:last-child { margin-bottom: 0; }
.ev__map { display: block; margin-top: .3rem; color: var(--accent); font-size: .86rem; }

.ev__dl { width: 100%; margin-top: 1rem; justify-content: center; gap: .5rem; }
.ev__dl span { opacity: .75; font-weight: 400; font-size: .84rem; }

@media (max-width: 860px) {
  .ev { grid-template-columns: 1fr; }
  .ev__banner, .ev__side, .ev__body { grid-column: 1; }
  .ev__side { grid-row: auto; position: static; }
}

/* ---------- Photo gallery ---------- */
.albums, .shots { list-style: none; padding: 0; margin: 0; display: grid; }
.albums { gap: 1.6rem; grid-template-columns: repeat(auto-fill, minmax(288px, 1fr)); }
.shots  { gap: .85rem; grid-template-columns: repeat(auto-fill, minmax(212px, 1fr)); }

.album { display: block; border-radius: 14px; overflow: hidden; background: var(--surface); border: 1px solid var(--line); }
.album__img { display: block; aspect-ratio: 4 / 3; background: var(--surface-2); overflow: hidden; }
.album__img img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform .7s var(--ease-out);
}
.album:hover { border-color: var(--accent); }
.album:hover .album__img img { transform: scale(1.05); }
.album__meta { display: block; padding: 1rem 1.15rem 1.15rem; }
.album__meta strong { font-family: var(--font-display); font-size: 1.08rem; display: block; }
.album__meta small { color: var(--text-muted); font-size: .85rem; }

/* The tile is a button, not a link — it opens the lightbox rather than
   navigating, and a button is what a keyboard user expects to activate. */
.shot {
  display: block; width: 100%; padding: 0; border: 0; cursor: zoom-in;
  border-radius: 9px; overflow: hidden; background: var(--surface-2);
  aspect-ratio: 1; line-height: 0;
}
.shot img { width: 100%; height: 100%; object-fit: cover; transition: transform .6s var(--ease-out), opacity .3s; }
.shot:hover img { transform: scale(1.06); opacity: .88; }
.shot:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.shot__cap { display: block; font-size: .8rem; color: var(--text-muted); margin-top: .45rem; }

.link-back { color: var(--accent); font-size: .92rem; }

/* ---------- Lightbox ---------- */
.lightbox {
  position: fixed; inset: 0; z-index: 1000;
  background: rgba(6,4,3,.94);
  display: grid; place-items: center;
  padding: clamp(1rem, 5vw, 3.5rem);
}
.lightbox[hidden] { display: none; }
.lightbox__img {
  max-width: 100%; max-height: 82vh; object-fit: contain;
  border-radius: 6px; box-shadow: 0 30px 90px rgba(0,0,0,.7);
}
.lightbox__cap {
  position: absolute; left: 0; right: 0; bottom: clamp(.8rem, 3vw, 1.8rem);
  text-align: center; color: var(--text-muted); font-size: .9rem; padding-inline: 4rem;
}
.lightbox__close, .lightbox__nav {
  position: absolute; background: rgba(255,255,255,.07); border: 1px solid var(--line);
  color: var(--text); border-radius: 50%; cursor: pointer; line-height: 1;
  display: grid; place-items: center;
}
.lightbox__close { top: 1.1rem; right: 1.1rem; width: 42px; height: 42px; font-size: 1.5rem; }
.lightbox__nav   { top: 50%; transform: translateY(-50%); width: 48px; height: 48px; font-size: 2rem; }
.lightbox__nav--prev { left: clamp(.5rem, 2vw, 1.6rem); }
.lightbox__nav--next { right: clamp(.5rem, 2vw, 1.6rem); }
.lightbox__close:hover, .lightbox__nav:hover { background: var(--accent); color: #241002; border-color: var(--accent); }

@media (max-width: 620px) {
  .shots { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); }
  .lightbox__cap { padding-inline: 1rem; }
}

/* ---------- Memorial portrait ----------
   The source already carries its own gold ring with transparent corners, so
   this adds no frame of its own — a second ring would fight the first. It is
   a 300px scan, held to 200px so it stays sharp, and no larger. */
.memorial { margin: 0 auto 2.6rem; text-align: center; }
.memorial img {
  width: min(200px, 52vw); height: auto; display: block; margin: 0 auto;
  filter: drop-shadow(0 14px 34px rgba(0,0,0,.55));
}
.memorial figcaption {
  font-family: var(--font-display); font-size: .96rem;
  color: var(--text-muted); margin-top: 1rem;
}

/* ---------- Tribute: family list and descendant counts ---------- */
.legacy {
  list-style: none; margin: 2.4rem 0 0; padding: 0;
  display: grid; gap: 1px;
  background: var(--line);            /* gap shows through as hairlines */
  border: 1px solid var(--line); border-radius: 14px; overflow: hidden;
  grid-template-columns: repeat(auto-fit, minmax(258px, 1fr));
}
.legacy__item {
  background: var(--surface); padding: 1.5rem 1.6rem;
  display: flex; flex-direction: column; gap: .3rem;
}
.legacy__name {
  font-family: var(--font-display); font-size: 1.16rem; color: var(--text);
}
.legacy__role { font-size: .9rem; color: var(--text-muted); line-height: 1.5; }

.legacy__count {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: clamp(1.8rem, 6vw, 4.5rem); margin-top: 3rem; text-align: center;
}
.legacy__count > div { display: flex; flex-direction: column; gap: .2rem; }
.legacy__count strong {
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(2.2rem, 5vw, 3.1rem); color: var(--accent); line-height: 1;
}
.legacy__count span {
  font-size: .8rem; letter-spacing: .13em; text-transform: uppercase;
  color: var(--text-muted);
}

/* ---------- Long-form article body ---------- */
.prose { max-width: 68ch; margin-inline: auto; }
.prose > * + * { margin-top: 1.15rem; }
.prose p { color: var(--text-muted); }
.prose h2 {
  font-size: clamp(1.3rem, 2.4vw, 1.75rem);
  margin-top: 2.8rem; color: var(--text);
}
.prose h3 { font-size: 1.15rem; margin-top: 2rem; color: var(--text); }
.prose strong { color: var(--text); font-weight: 600; }
/* :not(.btn) matters more than it looks. ".prose a" is specificity (0,1,1)
   and ".btn" is (0,1,0), so without this every button inside a prose block
   loses its own text colour to the accent — which on a gold button is orange
   text on an orange background, i.e. invisible. It was doing exactly that on
   the Church Hours page. */
.prose a:not(.btn) {
  color: var(--accent); text-decoration: underline; text-underline-offset: 3px;
}
.prose a:hover { color: var(--accent-hi); }
.prose ul, .prose ol { padding-left: 1.3rem; color: var(--text-muted); }
.prose li + li { margin-top: .45rem; }
.prose blockquote {
  border-left: 2px solid var(--accent);
  padding: .3rem 0 .3rem 1.3rem; margin-left: 0;
  color: var(--text); font-family: var(--font-display);
  font-size: 1.08rem; line-height: 1.5;
}
.prose hr { border: 0; height: 1px; background: var(--line); margin-block: 2.4rem; }
.prose img { border-radius: var(--radius); margin-inline: auto; }

/* Portrait + intro pairing for the leadership pages */
.bio { display: grid; grid-template-columns: 300px 1fr; gap: 2.6rem; align-items: start; }
.bio__portrait {
  border-radius: var(--radius-lg); overflow: hidden;
  border: 1px solid var(--line); box-shadow: var(--shadow-sm);
  position: sticky; top: 100px;
}
.bio__role {
  font-family: var(--font-display); font-size: var(--fs-micro);
  letter-spacing: var(--tracking-wide); text-transform: uppercase;
  color: var(--accent); margin-top: 1rem; display: block; text-align: center;
}
@media (max-width: 860px) {
  .bio { grid-template-columns: 1fr; gap: 1.8rem; }
  .bio__portrait { position: static; max-width: 320px; margin-inline: auto; }
}

/* ---------- Ministries grid ---------- */
.min-group { margin-top: 2.6rem; }
.min-group h2 {
  font-size: 1.05rem; letter-spacing: var(--tracking-wide);
  text-transform: uppercase; color: var(--accent);
  padding-bottom: .7rem; border-bottom: 1px solid var(--line);
}
.min-list {
  list-style: none; padding: 0; margin-top: 1.1rem;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: .6rem 1.6rem;
}
.min-list li {
  color: var(--text-muted); font-size: .95rem;
  padding-left: 1.1rem; position: relative;
}
.min-list li::before {
  content: ""; position: absolute; left: 0; top: .62em;
  width: 5px; height: 5px; border-radius: 50%; background: var(--accent); opacity: .65;
}

/* ---------- Service times ---------- */
.times { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 1.1rem; }
.times__card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-lg); padding: 1.7rem 1.5rem;
}
.times__card h2 {
  font-size: .72rem; letter-spacing: var(--tracking-wide);
  text-transform: uppercase; color: var(--accent); margin-bottom: 1rem;
}
.times__row { display: flex; gap: .9rem; align-items: baseline; }
.times__row + .times__row { margin-top: .8rem; padding-top: .8rem; border-top: 1px solid var(--line); }
.times__when {
  font-family: var(--font-display); font-weight: 600; color: var(--text);
  white-space: nowrap; min-width: 5.4rem;
}
.times__what { color: var(--text-muted); font-size: .95rem; }

/* ---------- Service countdown ---------- */
.service {
  position: relative; overflow: hidden;
  background: var(--base-2);
  border-block: 1px solid var(--line);
  padding-block: 1.5rem;
}
.service::before {
  content: ""; position: absolute; inset: 0;
  background: var(--glow-soft); opacity: .5; pointer-events: none;
}
.service__inner {
  position: relative; z-index: 1;
  display: flex; align-items: center; justify-content: space-between;
  gap: 1.5rem 2rem; flex-wrap: wrap;
}

.service__status { display: flex; align-items: center; gap: .85rem; }
.service__dot {
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--text-dim); flex: 0 0 auto;
  transition: background var(--dur-fast);
}
.service__label {
  font-family: var(--font-display); font-size: var(--fs-micro);
  letter-spacing: var(--tracking-wide); text-transform: uppercase;
  color: var(--accent);
}
.service__name { font-size: .92rem; color: var(--text-muted); margin-top: .15rem; }

/* Live state — the dot pulses red and the label turns urgent */
.service.is-live .service__dot {
  background: #d92d20;
  animation: servicePulse 1.6s var(--ease-inout) infinite;
}
.service.is-live .service__label { color: #ff6a5c; }
@keyframes servicePulse {
  0%,100% { box-shadow: 0 0 0 0 rgba(217,45,32,.55); }
  70%     { box-shadow: 0 0 0 12px rgba(217,45,32,0); }
}

.service__clock { display: flex; align-items: flex-end; gap: .5rem; }
.service__unit { display: flex; flex-direction: column; align-items: center; min-width: 3.1rem; }
.service__unit b {
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(1.5rem, 3.2vw, 2.1rem); line-height: 1;
  color: var(--text); font-variant-numeric: tabular-nums;
}
.service__unit span {
  font-size: .62rem; letter-spacing: .16em; text-transform: uppercase;
  color: var(--text-dim); margin-top: .35rem;
}
.service__sep {
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(1.2rem, 2.6vw, 1.7rem);
  color: var(--accent); opacity: .5; padding-bottom: 1.1rem;
}
.service.is-live .service__clock { opacity: .35; }

@media (max-width: 780px) {
  .service__inner { justify-content: center; text-align: center; }
  .service__status { width: 100%; justify-content: center; }
  .service__clock  { width: 100%; justify-content: center; }
}

/* ---------- Year theme band ---------- */
.theme-year {
  position: relative; overflow: hidden;
  padding-block: clamp(2.8rem, 7vh, 5rem);
  background: var(--base-2);
  border-block: 1px solid var(--line);
  text-align: center;
}
.theme-year::before {
  content: ""; position: absolute; inset: 0;
  background: var(--glow-soft); pointer-events: none;
}
/* Words and portrait side by side once there is room. Below that the portrait
   drops underneath at a smaller size — a 333px source cannot carry a full
   column on a phone without going soft, and the words are the point. */
.theme-year__inner {
  position: relative; z-index: 1;
  display: grid; gap: clamp(1.5rem, 4vw, 3.5rem);
  align-items: center; justify-items: center;
}
.theme-year__words { min-width: 0; }

.theme-year__pastor { margin: 0; text-align: center; }
.theme-year__pastor img {
  /* Capped at the source width — upscaling a cut-out shows every soft edge
     the mask left behind. */
  width: min(333px, 62vw); height: auto; display: block; margin-inline: auto;
  filter: drop-shadow(0 22px 46px rgba(0,0,0,.6));
}
.theme-year__pastor figcaption {
  font-family: var(--font-display); font-size: .84rem;
  letter-spacing: .06em; color: var(--text-muted); margin-top: .9rem;
}

@media (min-width: 900px) {
  .theme-year__inner {
    grid-template-columns: minmax(0, 1fr) auto;
    justify-items: start; text-align: left;
  }
  .theme-year__words { text-align: left; }
  .theme-year__pastor img { width: 300px; }
}
.theme-year__label {
  font-family: var(--font-display); font-size: var(--fs-micro);
  letter-spacing: var(--tracking-wide); text-transform: uppercase;
  color: var(--accent); margin-bottom: 1.4rem;
}
.theme-year__quote {
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(1.9rem, 5.5vw, 4.2rem);
  line-height: 1.12; letter-spacing: var(--tracking-tight);
  max-width: 16ch; margin-inline: auto; color: var(--text);
}
.theme-year__quote em {
  font-style: normal;
  background: linear-gradient(100deg, var(--flame-amber), var(--flame-red));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
/* Sibling of the quote, so it needs its own width — the quote's 16ch would
   wrap this line badly. */
.theme-year__still {
  margin: .7rem auto 0;
  max-width: 24ch;
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(1.2rem, 3vw, 2.1rem);
  line-height: 1.15;
  letter-spacing: var(--tracking-tight);
  color: var(--accent);
}
.theme-year__scripture {
  margin-top: 1.8rem; color: var(--text-muted);
  font-size: var(--fs-small); letter-spacing: .04em;
}

/* ---------- Signature "living light" (WebGL) ---------- */
.orb-section {
  position: relative; overflow: hidden;
  min-height: 92svh; display: grid; place-items: center;
  background: var(--base);
}
.orb {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  pointer-events: none;
}
.orb canvas {
  width: 100%; height: 100%;
  display: block;
}
/* Fallback when WebGL is unavailable / reduced motion / mobile */
.orb--fallback canvas { display: none; }
.orb--fallback::before {
  content: "";
  position: absolute; inset: 0;
  background:
    radial-gradient(closest-side circle at 50% 50%, rgba(249,155,39,.55), transparent 60%),
    radial-gradient(closest-side circle at 50% 50%, rgba(240,72,40,.35),  transparent 78%);
  animation: orbBreathe 7s var(--ease-inout) infinite;
}
@keyframes orbBreathe {
  0%, 100% { transform: scale(.96); opacity: .82; }
  50%      { transform: scale(1.04); opacity: 1; }
}
.orb-section__content {
  position: relative; z-index: 2; text-align: center; max-width: 40ch;
}
.orb-section__content h2 { font-size: clamp(2rem, 5vw, 3.6rem); }

/* ---------- Verse band ---------- */
.verse {
  position: relative; text-align: center; overflow: hidden;
  padding-block: clamp(4rem, 10vh, 7rem);
  background: linear-gradient(165deg, var(--ember-deep) 0%, var(--purple-deep) 58%, var(--base) 100%);
}
.verse::after { content: ""; position: absolute; inset: 0; background: var(--glow-soft); }
.verse__inner { position: relative; z-index: 1; }
.verse p {
  font-family: var(--font-display); font-weight: 600;
  font-size: clamp(1.35rem, 3vw, 2.35rem); line-height: 1.32;
  max-width: 20ch; margin-inline: auto; color: #fff;
}
.verse cite { display: block; margin-top: 1.2rem; font-style: normal;
  color: var(--flame-soft); letter-spacing: .05em; font-size: .95rem; }

/* ---------- Marquee ---------- */
.marquee { overflow: hidden; padding-block: 1.6rem;
  border-block: 1px solid var(--line); background: var(--base-2); }
/* NOTE: spacing lives on the items, not as flex `gap`.
   With `gap`, duplicating the track adds one extra gap between the two copies,
   so one copy's width no longer equals half the total — which is exactly what
   makes the loop jump. Per-item padding keeps every copy identical. */
.marquee__track { display: flex; width: max-content; }
.marquee__track span {
  font-family: var(--font-display); font-weight: 600;
  font-size: clamp(1.1rem, 2.2vw, 1.7rem);
  color: var(--text-dim); display: inline-flex; align-items: center; gap: 3.5rem;
  white-space: nowrap;
  padding-right: 3.5rem;
}
.marquee__track span::after { content: "✦"; color: var(--accent); font-size: .8em; }

/* ---------- Footer ---------- */
.footer { background: var(--base-2); border-top: 1px solid var(--line);
  padding-block: 4rem 1.6rem; }
.footer__grid { display: grid; grid-template-columns: 1.6fr 1fr 1fr 1.2fr;
  gap: 2.5rem; margin-bottom: 3rem; }
.footer h4 { font-size: .78rem; letter-spacing: var(--tracking-wide);
  text-transform: uppercase; color: var(--accent); margin-bottom: 1.1rem; }
.footer__list { list-style: none; display: flex; flex-direction: column; gap: .6rem; font-size: .92rem; }
.footer__list a:not(.btn) { color: var(--text-muted); transition: color var(--dur-fast); }
.footer__list a:hover { color: var(--accent); }
.footer__bottom {
  border-top: 1px solid var(--line); padding-top: 1.4rem;
  display: flex; justify-content: space-between; gap: 1rem; flex-wrap: wrap;
  font-size: .8rem; color: var(--text-dim);
}

/* ============================================================
   Responsive
   ============================================================ */
@media (max-width: 1024px) {
  .cards { grid-template-columns: repeat(2, 1fr); }
  .footer__grid { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 900px) {
  .hamburger { display: block; }
  .header__cta .btn--ghost { display: none; }
  .menu {
    position: fixed; inset: 0; z-index: -1;
    flex-direction: column; justify-content: flex-start; gap: .3rem;
    padding: 6rem var(--gutter) 3rem;
    background: var(--base); opacity: 0; visibility: hidden;
    transition: opacity var(--dur) var(--ease-out), visibility var(--dur);
    /* A panel taller than the screen once a submenu is open, so it scrolls on
       its own. `contain` stops the drag continuing into the page behind it
       once the list reaches its end -- otherwise the last flick scrolls the
       article underneath and the menu appears to jump. */
    overflow-y: auto; overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
  }
  .menu.is-open { opacity: 1; visibility: visible; z-index: 1; }
  .menu > li { width: 100%; border-bottom: 1px solid var(--line); }
  .menu a, .menu__toggle { font-size: 1.05rem; padding-block: .95rem; width: 100%; }
  .menu__toggle { justify-content: space-between; }

  /* Mobile: submenus expand inline instead of floating */
  .submenu {
    position: static; opacity: 1; visibility: visible; transform: none;
    min-width: 0; background: none; border: 0; box-shadow: none;
    padding: 0 0 .6rem .8rem;
    display: none;
  }
  .submenu::before { display: none; }
  .has-sub.is-open .submenu { display: block; }
  .has-sub:hover .submenu { display: none; }
  .has-sub.is-open .submenu { display: block; }
  .submenu a { font-size: .95rem; padding-block: .55rem; }
  .give__grid { grid-template-columns: repeat(3, 1fr); }
  .stats { grid-template-columns: repeat(2, 1fr); gap: 2rem; }
  .topbar__contact { display: none; }
}

@media (max-width: 560px) {
  .cards, .footer__grid { grid-template-columns: 1fr; }
  .give__grid { grid-template-columns: repeat(2, 1fr); }
  .give { padding: 1.1rem; }
  .hero__meta { gap: 1.5rem; }
  .player__note { display: none; }
}

/* ============================================================
   PURPLE PASS

   The logo is flame on black and purple was always the secondary, but it had
   drifted almost entirely out of the build — ten uses across the whole
   stylesheet, most of them in one gradient. The page had gone monotone.

   Purple is used here as a second light source, never as text or a control
   colour. Flame stays the thing you act on; purple is the cool edge it is
   read against. That keeps the hierarchy intact — if both colours competed
   for attention, neither would mean anything.
   ============================================================ */

/* Alternating sections pick up a cool wash, so the page breathes between
   bands instead of running one flat tone top to bottom. */
.section--alt {
  background:
    radial-gradient(760px 420px at 82% 8%, rgba(106,71,184,.13), transparent 66%),
    radial-gradient(620px 380px at 8% 92%, rgba(75,46,131,.10), transparent 70%),
    var(--base-2);
}

/* Cards: purple at rest, flame on hover. The colour shift is what signals
   "this one is live" — more legible than a border alone. */
.card::before {
  background:
    radial-gradient(420px 260px at 50% 0%, rgba(106,71,184,.16), transparent 70%);
  opacity: 1;
}
.card:hover::before {
  background:
    radial-gradient(420px 260px at 50% 0%, rgba(249,155,39,.20), transparent 70%);
}

/* Page headers get the same counterpoint the home hero already had.
   :not() is load-bearing. This rule and .page-hero--banner::before have equal
   specificity, and this one comes later in the file — so without the guard it
   replaced the banner scrim entirely on every page that has a photographic
   header. The Give heading disappeared into its own background because of it. */
.page-hero:not(.page-hero--banner)::before {
  background:
    radial-gradient(680px 420px at 88% 10%, rgba(106,71,184,.24), transparent 64%),
    var(--glow-hero);
}

/* Banner headers get their purple mixed INTO the scrim rather than instead
   of it, so the photograph still has something to sit behind the type. */
.page-hero--banner::before {
  background:
    radial-gradient(700px 460px at 84% 12%, rgba(106,71,184,.30), transparent 62%),
    linear-gradient(90deg,
      rgba(10,7,5,.94) 0%, rgba(10,7,5,.86) 32%,
      rgba(10,7,5,.58) 64%, rgba(10,7,5,.42) 100%),
    linear-gradient(to bottom,
      rgba(10,7,5,.72) 0%, rgba(10,7,5,.20) 42%, rgba(10,7,5,.78) 100%);
}

/* Panels and the giving grid: a purple hairline along the top edge, echoing
   the one already on the dropdown menus. */
.panel-tint, .give__grid { position: relative; }
.give__grid::before {
  content: ""; position: absolute; top: -1px; left: 12%; right: 12%; height: 2px;
  background: linear-gradient(90deg, transparent, var(--purple-glow), var(--accent), transparent);
  border-radius: 2px; opacity: .7;
}

/* Footer sits deepest — the cool end of the page. */
.footer {
  background:
    radial-gradient(900px 500px at 15% 0%, rgba(75,46,131,.16), transparent 68%),
    var(--base-2);
}

/* The theme band already carried the year's words; giving it the strongest
   purple makes it read as the page's one still moment. */
.theme-year {
  background:
    radial-gradient(700px 460px at 20% 20%, rgba(106,71,184,.18), transparent 66%),
    radial-gradient(620px 400px at 84% 84%, rgba(240,72,40,.10), transparent 70%),
    var(--base-2);
}

/* ---------- More purple ----------
   Pushed further per the brief. Still never text and never a control — the
   flame has to stay the thing you act on. These are all atmosphere: edges,
   glows and grounds. */

/* Buttons pick up a purple rim on hover, so the ghost variant stops reading
   as a plain outline. */
.btn--ghost:hover { --btn-bd: var(--purple-glow); --btn-fg: #C9B3FF; }

/* Section headings get a purple-to-flame rule beneath them. */
.section__title::after {
  content: ""; display: block; width: 62px; height: 2px; margin: .9rem auto 0;
  background: linear-gradient(90deg, var(--purple-glow), var(--accent));
  border-radius: 2px;
}

/* Panels and cards sit on a cooler ground. */
.panel, .give__btn, .evcard, .album, .legacy__item {
  background:
    linear-gradient(160deg, rgba(75,46,131,.10), transparent 55%),
    var(--surface);
}

/* Album and event tiles glow purple on hover before the flame border lands. */
.album:hover, .evcard:hover {
  box-shadow: 0 18px 48px rgba(75,46,131,.30);
}

/* The broadcast panel — the most-looked-at block on the home page. */
.player { box-shadow: 0 24px 70px rgba(75,46,131,.24); }

/* Hairline dividers across the site pick up the two-colour gradient that was
   previously only on the dropdown menus. */
hr, .prose hr {
  border: 0; height: 1px;
  background: linear-gradient(90deg, transparent, var(--purple-glow), var(--accent), transparent);
  opacity: .5;
}

/* Blockquotes in prose get a purple spine. */
.prose blockquote {
  border-left: 3px solid var(--purple-glow);
  padding-left: 1.2rem; margin-left: 0;
}

/* ---------- Scan-to-give codes ----------
   On a white tile, always. A QR code is read by thresholding light against
   dark, and inverting or tinting one is the quickest way to make it
   unscannable on a phone that is already struggling in low light. */
.qr { margin-top: 3.6rem; text-align: center; }
.qr__grid {
  display: flex; justify-content: center; gap: clamp(1rem, 4vw, 2.4rem);
  flex-wrap: wrap; margin-top: 1.8rem;
}
.qr__card {
  margin: 0; background: var(--surface); border: 1px solid var(--line);
  border-radius: 14px; padding: 1rem 1rem 1.1rem; width: min(220px, 42vw);
}
.qr__card img {
  width: 100%; height: auto; display: block;
  background: #fff; border-radius: 8px; padding: 8px;
}
.qr__card figcaption { margin-top: .8rem; }
.qr__card strong {
  display: block; font-family: var(--font-display); font-size: 1rem; color: var(--text);
}
.qr__card small { color: var(--text-muted); font-size: .82rem; word-break: break-all; }
.qr__note {
  max-width: 46ch; margin: 1.6rem auto 0;
  font-size: .86rem; color: var(--text-muted); line-height: 1.6;
}

/* ---------- Back to top ----------
   Sits to the right of the floating social cluster and shares its show/hide,
   so the two appear and leave together rather than as two separate events.
   Bottom-right rather than centre: it is a utility, and the social links are
   the thing worth putting in front of someone. */
.to-top {
  position: fixed; right: clamp(1rem, 3vw, 1.8rem);
  bottom: clamp(.9rem, 3vh, 1.6rem); z-index: 55;
  width: 44px; height: 44px; border-radius: 50%; cursor: pointer;
  display: grid; place-items: center;
  background: rgba(22,16,12,.82); backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  border: 1px solid var(--line-strong); color: var(--text-muted);
  box-shadow: 0 12px 34px rgba(0,0,0,.5);
  opacity: 0; visibility: hidden; pointer-events: none;
  transform: translateY(14px);
  transition: opacity .4s var(--ease-out), transform .4s var(--ease-out),
              visibility .4s, color var(--dur-fast), border-color var(--dur-fast);
}
.to-top.is-shown {
  opacity: 1; visibility: visible; pointer-events: auto; transform: translateY(0);
}
.to-top:hover { color: var(--accent); border-color: var(--accent); }
.to-top svg { width: 19px; height: 19px; }

/* ============================================================
   FORMS — prayer, contact
   ============================================================ */

/* The honeypot. Moved off screen rather than display:none — the better bots
   check for that and skip the field, which is exactly what we do not want
   them to do. */
.trap {
  position: absolute; left: -9999px; width: 1px; height: 1px;
  overflow: hidden;
}

.formwrap { max-width: 62ch; margin: 3rem auto 0; }
.fld { display: block; margin-bottom: 1.1rem; }
.fld > input, .fld > textarea, .fld > select {
  display: block; width: 100%; margin-top: .45rem;
  padding: .85rem 1rem; border-radius: var(--radius-sm);
  background: var(--surface); border: 1px solid var(--line-strong);
  color: var(--text); font: 400 1rem/1.5 var(--font-body);
}
.fld > input:focus, .fld > textarea:focus {
  outline: 2px solid rgba(249,155,39,.55); outline-offset: 2px;
  border-color: var(--accent);
}
.fld > textarea { resize: vertical; min-height: 8rem; }
.fld { font-family: var(--font-display); font-size: .88rem; color: var(--text-muted); }
.req { color: var(--accent); }
.fld__note { font-size: .85rem; color: var(--text-dim); margin: -.4rem 0 1.2rem; line-height: 1.6; }

.fld--check {
  display: flex; gap: .7rem; align-items: flex-start;
  font-family: var(--font-body); font-size: .92rem;
  color: var(--text-muted); line-height: 1.6; margin-bottom: 1.6rem;
}
.fld--check input { margin-top: .25rem; flex: none; width: 18px; height: 18px; }

.field-pair { display: grid; gap: 0 1rem; grid-template-columns: 1fr 1fr; }
@media (max-width: 620px) { .field-pair { grid-template-columns: 1fr; } }

.formnote {
  padding: .8rem 1rem; border-radius: var(--radius-sm); margin-bottom: 1rem;
  font-size: .92rem; border: 1px solid;
}
.formnote--error {
  background: rgba(240,72,40,.10); border-color: rgba(240,72,40,.42); color: #ff9c85;
}

/* The state after sending. Given real weight rather than a one-line message —
   someone who has just written down something difficult should get more back
   than a grey toast. */
.formdone {
  max-width: 52ch; margin-inline: auto; text-align: center;
  padding: clamp(2.5rem, 7vw, 4rem) 1.5rem;
  background:
    radial-gradient(600px 320px at 50% 0%, rgba(106,71,184,.16), transparent 70%),
    var(--surface);
  border: 1px solid var(--line); border-radius: var(--radius-lg);
}
.formdone__mark {
  width: 62px; height: 62px; margin: 0 auto 1.3rem; border-radius: 50%;
  display: grid; place-items: center; font-size: 1.7rem;
  background: rgba(61,163,93,.16); color: #7fd89b; border: 1px solid rgba(61,163,93,.4);
}
.formdone h2 { font-family: var(--font-display); font-size: 1.7rem; margin-bottom: .8rem; }
.formdone p { color: var(--text-muted); margin-bottom: 1rem; }
.formdone .btn { margin-top: 1rem; }

/* ---------- Contact layout ---------- */
.contact { display: grid; gap: clamp(1.6rem, 4vw, 3rem); grid-template-columns: 1.35fr 1fr; }
@media (max-width: 860px) { .contact { grid-template-columns: 1fr; } }
.contact__form { min-width: 0; }
.contact__side { display: flex; flex-direction: column; gap: 1rem; }
.contact__card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 1.4rem 1.5rem;
}
.contact__card h3 {
  font-family: var(--font-display); font-size: 1.05rem; margin-bottom: .6rem;
}
.contact__card p { color: var(--text-muted); font-size: .95rem; line-height: 1.65; margin-bottom: .9rem; }
.contact__phone {
  font-family: var(--font-display); font-size: 1.25rem; color: var(--accent);
}

/* ---------- Long forms (scholarship) ---------- */
.formwrap--wide { max-width: 74ch; }
.fset {
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: 1.6rem 1.5rem 1.2rem; margin-bottom: 1.6rem;
  background: linear-gradient(160deg, rgba(75,46,131,.08), transparent 60%), var(--surface);
}
.fset > legend {
  font-family: var(--font-display); font-size: 1.05rem; color: var(--accent);
  padding: 0 .6rem; margin-left: -.6rem;
}
.fset__sub {
  font-family: var(--font-display); font-size: .95rem; color: var(--text);
  margin: 1.4rem 0 .8rem;
}
.fld__hint { display: block; margin-top: .3rem; font-size: .8rem; color: var(--text-dim); }
.radios-inline { border: 0; padding: 0; margin: 0 0 1.2rem; }
.radios-inline > legend {
  font-family: var(--font-display); font-size: .88rem;
  color: var(--text-muted); padding: 0; margin-bottom: .5rem;
}
.radios-inline label {
  display: inline-flex; align-items: center; gap: .4rem;
  margin-right: 1.2rem; font-size: .92rem; color: var(--text-muted); cursor: pointer;
}
.fld > input[type=file] {
  padding: .6rem; font-size: .88rem; background: var(--base);
}

/* ---------- HLCB current quarter ----------
   The flyer is purple and gold; these panels lean on the site's purple so the
   page reads as continuous with the printed piece the church is already
   handing out, without copying it. */
.quarter { text-align: center; max-width: 60ch; margin-inline: auto; }
.quarter__kicker {
  font-family: var(--font-display); font-size: var(--fs-micro);
  letter-spacing: var(--tracking-wide); text-transform: uppercase;
  color: var(--accent); margin-bottom: 1rem;
}
.quarter__title {
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(1.6rem, 4vw, 2.6rem); line-height: 1.15; text-wrap: balance;
}
.quarter__classes {
  display: flex; flex-direction: column; gap: .7rem;
  margin: 2.2rem auto 0; max-width: 34ch; text-align: left;
}
.quarter__class {
  display: grid; grid-template-columns: auto 1fr; gap: .2rem .8rem;
  align-items: center;
  padding: 1rem 1.2rem; border-radius: var(--radius);
  background: linear-gradient(135deg, rgba(75,46,131,.24), rgba(22,16,12,.5));
  border: 1px solid var(--line-strong);
}
.quarter__class strong { font-family: var(--font-display); font-size: 1.08rem; }
.quarter__class small {
  grid-column: 2; font-size: .78rem; color: var(--text-muted); font-style: italic;
}
.quarter__tick {
  grid-row: 1 / span 2; width: 26px; height: 26px; border-radius: 6px;
  display: grid; place-items: center; font-size: .85rem;
  background: var(--accent); color: var(--btn-gold-text);
}

.quarter__reg {
  display: grid; gap: 1.2rem; margin-top: 2.6rem;
  grid-template-columns: repeat(auto-fit, minmax(272px, 1fr));
  max-width: 64ch; margin-inline: auto;
}
.regcard {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 1.5rem 1.6rem; text-align: center;
}
.regcard h3 { font-family: var(--font-display); font-size: 1.1rem; margin-bottom: .3rem; }
.regcard__time { color: var(--accent); font-size: .9rem; margin-bottom: 1rem; }
.regcard__dates { list-style: none; padding: 0; margin: 0 0 1.2rem; }
.regcard__dates li {
  padding: .45rem 0; border-bottom: 1px solid var(--line);
  font-size: .95rem; color: var(--text);
}
.regcard__dates li:last-child { border-bottom: 0; }
.regcard__where { font-size: .9rem; color: var(--text-muted); margin-bottom: 1rem; }

/* A required disclosure, not a footnote we chose to add — so it is legible
   rather than tucked away at 10px. */
.disclosure {
  margin-top: 2.6rem; padding-top: 1.4rem; border-top: 1px solid var(--line);
  font-size: .82rem; color: var(--text-dim); line-height: 1.6; max-width: 56ch;
  margin-inline: auto;
}

/* ---------- Blog ---------- */
.postlist { list-style: none; padding: 0; margin: 0; display: grid; gap: 1.6rem;
            grid-template-columns: repeat(auto-fill, minmax(330px, 1fr)); }
.postcard {
  display: flex; flex-direction: column; height: 100%;
  background: linear-gradient(160deg, rgba(75,46,131,.10), transparent 55%), var(--surface);
  border: 1px solid var(--line); border-radius: 14px; overflow: hidden;
}
.postcard:hover { border-color: var(--accent); }
.postcard__img { display: block; aspect-ratio: 16 / 9; overflow: hidden; background: var(--surface-2); }
.postcard__img img { width: 100%; height: 100%; object-fit: cover; display: block;
                     transition: transform .7s var(--ease-out); }
.postcard:hover .postcard__img img { transform: scale(1.04); }
.postcard__meta { display: block; padding: 1.2rem 1.35rem 1.4rem; }
.postcard__scripture {
  display: block; font-size: .72rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--accent); margin-bottom: .4rem;
}
.postcard__meta strong {
  font-family: var(--font-display); font-size: 1.2rem; display: block;
  margin-bottom: .5rem; text-wrap: balance;
}
.postcard__excerpt { display: block; color: var(--text-muted); font-size: .93rem;
                     line-height: 1.6; margin-bottom: .8rem; }
.postcard__meta small { color: var(--text-dim); font-size: .82rem; }

.postimg { border-radius: 16px; overflow: hidden; border: 1px solid var(--line);
           margin-bottom: 2.6rem; max-width: 900px; margin-inline: auto; }
.postimg img { width: 100%; height: auto; display: block; }
/* Wider measure than .prose default — a blog post is read straight through,
   and 68ch of body text is the comfortable ceiling. */
.postbody { max-width: 68ch; margin-inline: auto; font-size: 1.06rem; }
.postbody p { margin-bottom: 1.3rem; line-height: 1.8; }

.postvideo { max-width: 900px; margin: 3.5rem auto 0; text-align: center; }
.postvideo__frame {
  position: relative; aspect-ratio: 16 / 9; margin-top: 1.5rem;
  border-radius: 14px; overflow: hidden; border: 1px solid var(--line); background: #000;
}
.postvideo__frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* ---------------------------------------------------------------- tribute --
   The First Lady's header. The three portraits arrive as one transparent PNG
   so the arrangement stays whatever was decided in Photoshop; everything else
   here — gradient, name, dates — is live so it can be corrected without
   reopening the artwork. */
.tribute {
  position: relative; isolation: isolate; overflow: hidden;
  display: flex; align-items: flex-end;
  min-height: clamp(360px, 44vw, 580px);
  border-bottom: 1px solid rgba(200, 162, 75, .32);
  background:
    radial-gradient(115% 88% at 74% 106%, rgba(255, 214, 140, .18) 0%, rgba(255, 214, 140, 0) 56%),
    linear-gradient(103deg, #150B24 0%, #2E1852 26%, #4B2E83 48%, #6B2059 76%, #8C1F3E 100%);
}
/* A cross, barely there. The only ornament — enough to say what this is
   without turning the header into a poster. */
.tribute__cross {
  position: absolute; inset: 0; z-index: 0; opacity: .055; transform: translateX(12%);
  background:
    linear-gradient(to right, transparent calc(50% - 9px), #fff calc(50% - 9px),
                    #fff calc(50% + 9px), transparent calc(50% + 9px)) no-repeat 0 0 / 100% 100%,
    linear-gradient(to bottom, transparent calc(27% - 9px), #fff calc(27% - 9px),
                    #fff calc(27% + 9px), transparent calc(27% + 9px)) no-repeat 0 0 / 100% 100%;
  -webkit-mask-image: radial-gradient(58% 68% at 50% 40%, #000 0%, transparent 72%);
          mask-image: radial-gradient(58% 68% at 50% 40%, #000 0%, transparent 72%);
}
/* Darkens the left so the name always has something to sit on, whatever the
   gradient is doing behind it. */
.tribute__scrim {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: radial-gradient(80% 118% at 14% 52%, rgba(11, 7, 16, .60) 0%, rgba(11, 7, 16, 0) 62%);
}
.tribute__inner {
  position: relative; z-index: 3; width: min(1240px, 92vw); margin: 0 auto;
  padding: clamp(2rem, 4.6vw, 3.2rem) 0 0;
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.16fr);
  align-items: end; gap: clamp(.5rem, 2vw, 1.5rem);
}
.tribute__type { padding-bottom: clamp(1.6rem, 4vw, 3rem); }

.tribute__eyebrow {
  margin: 0 0 1.05rem; font-size: .74rem; font-weight: 600;
  letter-spacing: .24em; text-transform: uppercase; color: var(--gold-light, #E4C478);
}
.tribute__eyebrow::after {
  content: ""; display: block; width: 54px; height: 2px; margin-top: .7rem;
  background: linear-gradient(90deg, #C8A24B, rgba(200, 162, 75, 0));
}
.tribute__name { margin: 0; font-family: var(--font-display, Cinzel), serif; line-height: .95; color: #fff; }
.tribute__pre {
  display: block; font-weight: 600; letter-spacing: .38em; margin-bottom: .5rem;
  font-size: clamp(.7rem, 1.3vw, .95rem); text-transform: uppercase; color: #CDBBE8;
}
.tribute__given {
  display: block; font-weight: 400; font-size: clamp(1.8rem, 4.4vw, 3.6rem);
  text-shadow: 0 2px 26px rgba(0, 0, 0, .45);
}
.tribute__sur {
  display: block; font-weight: 900; margin-top: .05em;
  font-size: clamp(2.4rem, 6.6vw, 5.6rem); letter-spacing: .012em;
  text-transform: uppercase;
  background: linear-gradient(178deg, #F6E3AE 4%, #E4C478 26%, #C8A24B 54%, #8C6B26 82%, #E9CE92 100%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
  filter: drop-shadow(0 3px 18px rgba(0, 0, 0, .5));
}
.tribute__meta {
  margin: 1.1rem 0 0; font-size: clamp(.72rem, 1.2vw, .9rem); font-weight: 500;
  letter-spacing: .16em; line-height: 1.75; text-transform: uppercase;
  color: rgba(255, 255, 255, .86);
}
/* Two deliberate lines. Left to wrap on its own it broke mid-phrase — and this
   is where her dates will go, which makes the line longer still. */
.tribute__meta span { display: block; }
.tribute__meta span + span { color: rgba(255, 255, 255, .62); }

/* Bleeds off the right edge so the group reads as standing in the banner
   rather than pasted into a box. */
.tribute__figures { display: block; align-self: end; margin-right: -1.5%; }
.tribute__figures img {
  display: block; width: 100%; height: auto;
  filter: drop-shadow(-6px 14px 40px rgba(0, 0, 0, .55));
  /* The artwork is cropped hard at its left edge -- a fifth of the image
     height is solid pixels running off the side, which reads as a severed
     arm. Fading that edge into the gradient turns a cut into a soft entry.
     Replace the artwork with an uncropped export and this line can go. */
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 8%);
          mask-image: linear-gradient(to right, transparent 0, #000 8%);
}

@media (max-width: 820px) {
  /* Plain stacking, not a grid.

     The grid was bottom-aligning its rows inside a flex container, and on a
     narrow screen the type block came out taller than the row it was given:
     it rode up 31px over the photograph, and its last line fell 11px past the
     section and was clipped away by overflow:hidden. Neither is a thing you
     can tune with padding -- the row height was the problem, so the row goes. */
  .tribute { display: block; min-height: 0; }
  /* Flex column, not block: the photograph has to come first, and order only
     means anything in a flex or grid context. */
  .tribute__inner {
    display: flex; flex-direction: column; width: auto; margin: 0; gap: 0;
    padding: 0 0 clamp(1.5rem, 6vw, 2.2rem);
  }
  .tribute__figures { order: -1; margin: 0 0 .9rem; }
  .tribute__type { padding: 0 4vw; }
  .tribute__scrim {
    background: linear-gradient(180deg, rgba(11, 7, 16, 0) 34%, rgba(11, 7, 16, .5) 82%);
  }
}
