/* =========================================================
   New Wakefield Church — Site stylesheet
   Design: colours sampled from the New Wakefield crest — purple + gold
   Signature: the arch (home hero)
   Fonts: Fraunces (display, SOFT 60 / WONK 1) + Hanken Grotesk (UI)
   Motion: enhanced by motion.dev (progressive enhancement)
   ========================================================= */
:root{
  /* Brand palette — exactly four colors, sampled off the church's own crest
     (purple OKLCH hue 308, gold hue 88) rather than mixed by eye. */
  --navy:#38164f;       /* Crest purple — deep surface + strongest text */
  --snow:#faf6ee;       /* Warm stock, tinted off the gold */
  --charcoal:#4e3a60;   /* Secondary ink */
  --cyan:#9b7d29;       /* Crest gold — the one accent */
  /* Semantic tokens derived only from the four above */
  /* Navy does two jobs: it is a dark surface, and it is the strongest text
     colour on a light one. Compline is the one dark theme, and it remaps
     --navy to near-black so the surfaces stay right - which left every
     heading and label that used it as text invisible. Text asks for this
     token instead, so the two jobs can part company where they must. */
  --ink-strong:var(--navy);
  /* The mirror of the same problem: text that sits ON a dark surface asks
     for a light colour, and in Compline the surface tokens went dark too. */
  --ink-invert:var(--paper);
  --ink-invert-soft:var(--cream);
  /* Card surfaces asked for var(--card,#fff) and nothing ever defined it, so
     they were white in every theme including the dark one. */
  --card:#fff;
  --slate:var(--charcoal);
  --paper:var(--snow);
  --cream:color-mix(in srgb,var(--navy) 4%,var(--snow));
  --cream-2:color-mix(in srgb,var(--navy) 8%,var(--snow));
  --teal:var(--cyan);
  --cyan-deep:color-mix(in srgb,var(--cyan) 60%,var(--navy));
  --bg:var(--cream);--ink:var(--navy);--ink-soft:color-mix(in srgb,var(--navy) 80%,white);
  /* 66%, not 52%. At 52% this landed on 3.20:1 against the page — below AA —
     and it is the color of every caption, date, byline and helper line on the
     site, so it was the single most-read failing thing here. 66% clears 4.9:1
     on the page and 4.7:1 on a cream panel while still reading as secondary. */
  --muted:color-mix(in srgb,var(--navy) 70%,white);--line:color-mix(in srgb,var(--navy) 14%,var(--snow));
  /* Type: Fraunces (display) + Hanken Grotesk (body, labels).
     Brief was Chobani. Chobani Serif is bespoke — Berton Hasebe at Commercial
     Type, drawn from soft, warm 1960s–70s serifs, owned by Chobani and never
     licensed. Fraunces is the closest thing that is free: it carries a SOFT
     axis for exactly those blunted, rounded serif ends, and a WONK axis for the
     period's slightly off-kilter shapes. Both are pinned in the font request
     (SOFT 60, WONK 1) rather than left variable, which keeps the download to
     one instance instead of the whole design space. */
  --font-display:"Fraunces",Georgia,serif;--font-body:"Hanken Grotesk",system-ui,sans-serif;
  --font-serif:"Fraunces",Georgia,serif;
  --font-head:"Fraunces",Georgia,serif;                   /* accent: italic display serif */
  --font-accent:"Hanken Grotesk",system-ui,sans-serif;                 /* labels, eyebrows, buttons */
  --space-2xs:4px;--space-xs:8px;--space-sm:12px;--space-md:16px;--space-lg:24px;--space-xl:32px;--space-2xl:48px;--space-3xl:64px;--space-4xl:96px;
  --radius:18px;--radius-sm:10px;--radius-lg:28px;
  /* The Invites card set the pair the rest of the site now follows: the card
     corner, and the corner of anything sitting inset within it. The 8px
     difference is the padding between them - concentric corners look wrong
     when the inner one is not tightened by exactly the gap. */
  --radius-card:30px;--radius-inset:22px;--maxw:1240px;
  --shadow-sm:0 1px 2px rgba(47,33,69,.07),0 2px 10px rgba(47,33,69,.05);
  --shadow-md:0 12px 36px rgba(47,33,69,.13),0 2px 8px rgba(47,33,69,.06);
  --shadow-lg:0 28px 70px rgba(47,33,69,.22);
  --ease-out:cubic-bezier(.22,1,.36,1);--ease-in-out:cubic-bezier(.65,0,.35,1);
}
*,*::before,*::after{box-sizing:border-box;}*{margin:0;}
/* Fluid base type: locked at 16px on anything ≥ ~389px wide (all normal phones,
   tablets, desktop are unchanged), then eases down to ~14px on small handsets so
   the whole rem-based UI scales to fit instead of overflowing. */
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%;text-size-adjust:100%;color-scheme:light;font-size:clamp(14px,3.6vw + 2px,16px);}

/* ---------------------------------------------------------------- dark mode
   Chosen, never assumed: the switch lives in the member's profile and this
   class is written before first paint, so the app never flashes white on the
   way to being dark.

   Only the signed-in surfaces follow it — the installed app and the members'
   area. The public pages are built on full-bleed photography and the brand
   navy, and inverting them would fight the artwork rather than help anybody.

   Defaults here are the Sanctuary dark ramp; picking a theme overrides them
   further down the file. */
html.dark{color-scheme:dark;}
html.dark body{
  --navy:#2b123e;--snow:#190b25;--charcoal:#c3cad4;--cyan:#b5943f;
  --paper:#190b25;--bg:#190b25;--cream:#210f2f;--cream-2:#261037;
  --ink:#fbf9f5;--ink-soft:#e3e8ef;--muted:#9aa2ad;
  --line:#3f2f4d;--cyan-deep:#c6a44d;
/* These four are derived tokens, and deriving them was the bug: --ink-strong
   is var(--navy), --ink-invert is var(--paper), and both of those move dark
   in this block. Text asking for "the strongest colour" got the surface
   colour and vanished. They have to be restated here, pointing the other way. */
--ink-strong:var(--ink);--ink-invert:var(--ink);--ink-invert-soft:var(--ink-soft);
/* Cards are a raised surface, so on a dark page they sit above the page
   rather than below it. Nothing defined this before and they stayed white. */
--card:#29113b;
  --shadow-sm:0 1px 2px rgba(0,0,0,.5),0 2px 10px rgba(0,0,0,.4);
  --shadow-md:0 12px 36px rgba(0,0,0,.55),0 2px 8px rgba(0,0,0,.4);
  --shadow-lg:0 28px 70px rgba(0,0,0,.65);
  background:var(--paper);color:var(--ink);
}

/* --- dark: the components that name light and dark directly -----------------
   Most of the site colours itself from the tokens above and follows without
   being asked. What does not follow is anything that spelled out "light fill,
   dark text": both halves invert together and the thing disappears into
   itself. The fix is always the same shape - the surface and the label have
   to move in opposite directions - and the components already expose the two
   variables that decide it, so only values change here, never structure.

   Measured rather than guessed: the primary button shipped at 1.13:1 in dark
   before this block existed, which is to say the label was not there. */
html.dark body .btn{--bg:var(--ink);--fg:var(--paper);}
html.dark body .btn--light{--bg:var(--ink);--fg:var(--paper);}
html.dark body .btn--member{--bg:var(--ink);--fg:var(--paper);box-shadow:inset 0 0 0 1.5px var(--ink);}
html.dark body .btn--ghost{--bg:transparent;--fg:var(--ink);box-shadow:inset 0 0 0 1.5px color-mix(in srgb,var(--ink) 34%,transparent);}
html.dark body .btn--ondark.btn--ghost{--fg:var(--ink);box-shadow:inset 0 0 0 1.5px color-mix(in srgb,var(--ink) 40%,transparent);}
/* White on the brand cyan needs the fill darkened to clear 4.5:1, which is
   what the light theme does. On a dark page the fill can go the other way
   instead - full-strength cyan with near-black on top reads 6.8:1, and a
   bright button is the right thing on a dark page anyway. */
html.dark body .btn--accent{--bg:var(--cyan);--fg:#190b25;}

/* --- dark: the calendar ------------------------------------------------------
   The month grid colours events two ways, and both of them broke the same way.

   The six category chips are a pale tint with saturated type on it. Neither
   half is a token, so in the dark both stayed exactly as they were: bright
   blocks on a dark page. Each pair is restated here with the roles swapped -
   a deep tint of the same hue, and the type lightened to sit on it. Every one
   measures above 7.7:1; the palest of them measured 4.36:1 before.

   The chips taken from an event poster get their colour inline from the
   artwork, so the tint follows the page down but the type cannot. The app
   theme already solved this one; the same answer applies here. */
html.dark body .ev-c1{background:#0c2b34;color:#7fd0e4;}
html.dark body .ev-c2{background:#2b0e40;color:#d095ff;}
html.dark body .ev-c3{background:#35131f;color:#f5a6c2;}
html.dark body .ev-c4{background:#31270f;color:#e0bd64;}
html.dark body .ev-c5{background:#102a19;color:#8ad6a1;}
html.dark body .ev-c6{background:#131f36;color:#a3c1f0;}
html.dark body .cal__ev--photo{color:var(--ink) !important;}
/* Today's date sits on the brand cyan. White on it measured 2.81:1 once the
   cyan brightened for the dark palette - the fill is light now, so what sits
   on it has to be dark. */
html.dark body .cal__cell.is-today .cal__num{color:#190b25;}

/* --- dark: the children's pages ---------------------------------------------
   These sections are painted a fixed coral, mint, amber or white, and the
   colour is the design rather than a surface. The first attempt pinned the
   whole page to its light values so it would at least be correct - but that
   left one page glowing white in the middle of a dark site, which is its own
   kind of wrong.

   So the paints go deep instead. Every section colour is a custom property and
   the waves between them take the same property through currentColor, so one
   set of values moves the panels and the joins together. Near-white type
   measures 12.9:1 or better on all four. */
html.dark .khero, html.dark .ksec, html.dark .kinvite{
  --kcoralbg:#4a1a15;
  --kmintbg:#0f3527;
  --ksunbg:#3d300e;
  --kplainbg:#190b25;
  /* Body copy inside the panels is darkened for the light theme; on the deep
     ones it has to travel the other way. */
  --ink-soft:#dfe6ef;
}
html.dark .khero a:not(.btn):not(.spl),
html.dark .ksec a:not(.btn):not(.spl),
html.dark .kinvite a:not(.btn):not(.spl){
  color:#f2dca9;
  text-decoration-color:color-mix(in srgb,#f2dca9 45%,transparent);
}

html.dark .kicklabel{
  color:#f4f8fc;
  background:color-mix(in srgb,var(--kc,var(--cyan)) 24%,#07121e);
  border-color:color-mix(in srgb,var(--kc,var(--cyan)) 52%,#07121e);
}
html.dark .ksec .spl{
  color:#f2dca9;
  text-decoration-color:color-mix(in srgb,#f2dca9 45%,transparent);
}

/* --- dark: the mobile menu ---------------------------------------------------
   The browser menu is a frosted sheet, and frost is built from literals: a pale
   gradient with white cards floating on it. The type on those cards asks for
   --ink-strong, which in the dark is near-white, so the menu arrived as white
   text on white cards and could not be read at all. Only the frost was wrong.

   The dots beside the folder items cycle through the brand blues, and two of
   those are navy - invisible on a dark card - so that cycle lightens too. */
/* Two faults in one line, both inherited: it was translucent, so the hero read
   straight through the menu — the exact bug the light theme was fixed for — and
   it was mixed from rgb(9,20,35), a navy from the previous build, sitting blue
   against this theme's deep purple paper. Opaque, and from the tokens. */
html.dark:not(.app-mode) .mobmenu{
  background:linear-gradient(180deg,var(--paper),var(--cream));
}
/* The drawer is a column of ruled type, not a stack of cards — the light theme
   stopped painting a box behind each row and dark should match. Those cards were
   load-bearing though: the row text resolves to the light theme's dark purple,
   which was only legible because it sat on a pale card. Without the card it has
   to be stated, or the menu is purple on purple at about 1:1. */
html.dark:not(.app-mode) .mobmenu .menu>li{background:none;}
html.dark:not(.app-mode) .mobmenu .menu>li>a,
html.dark:not(.app-mode) .mobmenu .menu>li>button,
html.dark:not(.app-mode) .mobmenu .dropdown a{color:oklch(95% 0.012 88)}
html.dark:not(.app-mode) .mobmenu .menu>li>a[aria-current="page"],
html.dark:not(.app-mode) .mobmenu .menu>li>button[aria-current="page"]{color:oklch(82% 0.104 88)}
html.dark:not(.app-mode) .mobmenu .menu>li>a[aria-current="page"]::before,
html.dark:not(.app-mode) .mobmenu .menu>li>button[aria-current="page"]::before{background:oklch(82% 0.104 88)}
html.dark:not(.app-mode) .mobmenu__now-when{color:oklch(95% 0.012 88)}
html.dark:not(.app-mode) .mobmenu__now-when b,
html.dark:not(.app-mode) .mobmenu__now-lab{color:oklch(82% 0.104 88)}
html.dark:not(.app-mode) .mobmenu__now-where,
html.dark:not(.app-mode) .mobmenu__now-call{color:oklch(78% 0.02 88)}
html.dark:not(.app-mode) .mobmenu__now-call b{color:oklch(95% 0.012 88)}
html.dark:not(.app-mode) .mobmenu__minor a{color:oklch(74% 0.026 308)}
html.dark:not(.app-mode) .mobmenu__me{color:oklch(86% 0.018 88)}
html.dark .mobmenu .dropdown li:nth-child(6n+1) a::before{background:oklch(82% 0.104 88)}
html.dark .mobmenu .dropdown li:nth-child(6n+2) a::before{background:oklch(72% 0.104 308)}
html.dark .mobmenu .dropdown li:nth-child(6n+3) a::before{background:oklch(90% 0.062 88)}
html.dark .mobmenu .dropdown li:nth-child(6n+4) a::before{background:oklch(62% 0.126 308)}
html.dark .mobmenu .dropdown li:nth-child(6n+5) a::before{background:oklch(70% 0.116 88)}
html.dark .mobmenu .dropdown li:nth-child(6n+6) a::before{background:oklch(80% 0.086 308)}

/* Photographs and logos shouldn't be dimmed — only the chrome around them. */
html.dark img,html.dark video,html.dark .fill{filter:none;}
body{font-family:var(--font-body);background:var(--bg);color:var(--ink);line-height:1.6;font-size:1.02rem;-webkit-font-smoothing:antialiased;overflow-x:hidden;}

/* Smooth cross-page transitions (View Transitions API — auto-ignored where unsupported).
   The page content fades + lifts; the nav/footer stay put via a quick root cross-fade. */
@view-transition{navigation:auto;}
/* installed app: view transitions stay OFF (they hard-cut on iOS home-screen apps).
   Instead the app uses its own JS push: the page slides out on tap and the next
   one slides in. Transform + opacity only — fully GPU-composited, no snapshots. */
@media (display-mode: standalone),(display-mode: fullscreen){
  @view-transition{navigation:none;}
}
/* will-change was here as a compositing hint, and it cost more than it bought:
   it makes `main` a permanent containing block for fixed-position descendants,
   so anything position:fixed inside a page — the giving modal, a loader — is
   positioned against the whole scrollable page rather than the viewport. That
   put people at the bottom of the giving iframe in the installed app.

   The animation is 0.3s at page load; the browser composites it perfectly well
   without being told to, and the moment it finishes there's no transform left
   to trap anything. */
html.app-mode main{animation:appPageIn .3s var(--ae-out,cubic-bezier(.16,1,.3,1)) both;}
html.app-mode.page-exit main{animation:appPageOut .13s ease both;}
@keyframes appPageIn{from{opacity:0;transform:translateY(16px);}}
/* Was fading all the way to 0, which uncovered the white body for a beat
   before the next page painted — clearly visible going into Documents. It now
   lifts and dims only part way, so there's never a fully blank frame. */
@keyframes appPageOut{to{opacity:.55;transform:translateY(-8px);}}
/* returning to a page this session: no dashboard cascade — just the quick page slide */
html.app-revisit .appdash>*,html.app-revisit .appdash .applist__row,html.app-revisit .appdash .appms__t{animation:none !important;}
@media(prefers-reduced-motion:reduce){
  html.app-mode main,html.app-mode.page-exit main{animation:none;}
}
main{view-transition-name:page-main;}
/* The fixed chrome stays part of the root surface (no view-transition-name). A
   view-transition-name isolates an element into its own snapshot surface, and a
   backdrop-filter inside that surface has no page content to sample — which makes the
   nav's frosted blur render against nothing. Keeping it in root lets the blur work. */
::view-transition-old(root),::view-transition-new(root){animation:none;mix-blend-mode:normal;}
::view-transition-old(page-main){animation:ptOut .26s var(--ease-out) both;}
::view-transition-new(page-main){animation:ptIn .38s var(--ease-out) both;}
::view-transition-old(root),::view-transition-new(root){animation-duration:.3s;}
@keyframes ptOut{to{opacity:0;transform:translateY(-8px);}}
@keyframes ptIn{from{opacity:0;transform:translateY(14px);}}
@media(prefers-reduced-motion:reduce){
  ::view-transition-group(*),::view-transition-old(*),::view-transition-new(*){animation:none !important;}
}
img{max-width:100%;display:block;}a{color:inherit;text-decoration:none;}button{font:inherit;cursor:pointer;}
/* Retuned for Fraunces. Vollkorn is a narrow, small-x-height Renaissance face
   and wanted 800 with -.02em to hold a line together. Fraunces is wider, with a
   much taller x-height and far more weight on the stem at the same number — 800
   reads as shouting, and -.02em closes the counters up. 600 with a gentler
   track is the same visual weight Vollkorn had at 800, and the extra leading is
   what the taller x-height needs to stop lines touching. */
h1,h2,h3,h4{font-family:var(--font-display);line-height:1.1;font-weight:600;letter-spacing:-.014em;color:var(--ink);}

/* A size for every heading level, because there wasn't one.
   The base rule above set family, weight and tracking but no font-size, so any
   heading without its own rule fell through to the browser default — h2 at
   1.5em. On the home page that put "Three times a week." at 24px next to a
   4.3rem hero, which is most of why the page read as unpolished rather than as
   a deliberate hierarchy. Steps are ~1.35 apart so each level is unmistakably
   a level; anything with its own size (.fsec h2, .head h2, .nwf__h, .pghead h1)
   still wins on specificity and is untouched. */
h1{font-size:clamp(2.3rem,5.2vw,3.6rem)}
h2{font-size:clamp(1.9rem,3.6vw,2.6rem)}
h3{font-size:clamp(1.3rem,2.1vw,1.65rem);line-height:1.2}
h4{font-size:1.08rem;line-height:1.3}
/* Headings are the display serif, not the UI sans. The scaffold paired a wide
   grotesk with a serif accent word; for a small traditional congregation the
   serif carries the whole heading and the accent word does its work by going
   italic instead. It also stops the hero (Fraunces) and the section headings
   (previously Inter 700) from reading as two different sites. */
h1,h2,h3{font-family:var(--font-display);font-weight:400;letter-spacing:-.015em;line-height:1.08;}
/* …and the accent words in the high-contrast display cut */
.serif{font-family:var(--font-head);font-weight:400;font-style:italic;
  font-size:1.06em;letter-spacing:0;}
.eyebrow{font-family:var(--font-body);text-transform:uppercase;letter-spacing:.28em;font-size:.7rem;font-weight:700;color:var(--cyan-deep);}
.wrap{width:100%;max-width:var(--maxw);margin-inline:auto;padding-inline:clamp(20px,5vw,52px);}
.section{padding-block:clamp(48px,6.5vw,92px);}
.section--tight{padding-block:clamp(40px,6vw,72px);}
/* when two same-tone sections stack, trim the seam so spacing stays even */
.section + .section,.band + .band,.band--cream + .band--cream{padding-top:clamp(8px,2vw,24px);}
.band + .band,.band--cream + .band--cream{padding-top:clamp(28px,5vw,68px);}
.lead{font-size:clamp(1.05rem,.97rem + .4vw,1.22rem);color:var(--ink-soft);max-width:62ch;line-height:1.65;}
.center{text-align:center;}.center .lead{margin-inline:auto;}

/* keyboard focus — consistent, visible ring for every interactive element (mouse clicks stay clean) */
a:focus-visible,button:focus-visible,[tabindex]:focus-visible,summary:focus-visible,
input:focus-visible,select:focus-visible,textarea:focus-visible{
  outline:2.5px solid var(--cyan);outline-offset:3px;border-radius:6px;
}
/* on cyan/navy-filled controls a white ring reads better against the fill */
.btn--accent:focus-visible,.btn--cyan:focus-visible,.mobtop__burger:focus-visible,
.botbar__item--give:focus-visible{outline-color:#fff;outline-offset:2px;}
/* form fields already show a soft inner ring — don't double it */
.field input:focus-visible,.field select:focus-visible,.field textarea:focus-visible{outline:none;}

/* buttons */
.btn{--bg:var(--navy);--fg:var(--paper);display:inline-flex;align-items:center;gap:.55em;background:var(--bg);color:var(--fg);padding:.9em 1.6em;border:none;border-radius:100px;font-family:var(--font-display);font-weight:600;font-size:.95rem;position:relative;overflow:hidden;transition:transform .4s var(--ease-out),box-shadow .4s var(--ease-out);box-shadow:var(--shadow-sm);}
.btn::after{content:"";position:absolute;inset:0;background:radial-gradient(120% 140% at 50% 120%,rgba(255,255,255,.22),transparent 60%);opacity:0;transition:opacity .4s;}
.btn:hover{transform:translateY(-2px);box-shadow:var(--shadow-md);}.btn:hover::after{opacity:1;}
.btn:active{transform:translateY(0) scale(.97);box-shadow:var(--shadow-sm);transition-duration:.1s;}
.btn .arrow{transition:transform .4s var(--ease-out);}.btn:hover .arrow{transform:translateX(4px);}
/* "Watch this message" is too long for a phone: it pushes the button beside it
   onto its own line. Below 560px the label shortens to "Watch", which is clear
   enough sitting directly under the sermon's title. The full wording stays on
   the element as aria-label, so a screen reader still hears all of it. */
@media (max-width:560px){ .btn__long{display:none;} }
/* White on the brand cyan measures 3.62:1 - under the 4.5 that normal-sized
   text needs to stay legible, and this is the primary call to action on every
   page ("Give", "Plan Your Visit", "Watch a Message"). Taken down to 88% of
   the same hue it measures 4.54:1 and passes. Mixed rather than hard-coded so
   each theme darkens its OWN accent instead of every theme inheriting this
   one's. The difference is close to invisible side by side; the difference in
   sunlight, on a phone, at arm's length, is not. */
.btn--accent{--bg:color-mix(in srgb,var(--cyan) 88%,#000);--fg:#fff;}
.btn--member{--bg:var(--navy);--fg:#fff;box-shadow:inset 0 0 0 1.5px var(--navy);}
.btn--member:hover{--bg:var(--cyan-deep);box-shadow:inset 0 0 0 1.5px var(--cyan-deep);}
.btn--ghost{--bg:transparent;--fg:var(--ink);box-shadow:inset 0 0 0 1.5px color-mix(in srgb,var(--navy) 30%,transparent);}
.btn--ghost:hover{box-shadow:inset 0 0 0 1.5px var(--cyan);color:var(--cyan-deep);}
.btn--light{--bg:var(--paper);--fg:var(--navy);}
.btn--ondark.btn--ghost{--fg:var(--paper);box-shadow:inset 0 0 0 1.5px rgba(255,255,255,.4);}
.btn--ondark.btn--ghost:hover{box-shadow:inset 0 0 0 1.5px #fff;color:#fff;}

/* =========================================================
   IMAGE FIGURE (image-forward placeholder w/ hover zoom)
   ========================================================= */
.img{position:relative;border-radius:var(--radius);overflow:hidden;background:var(--slate);box-shadow:var(--shadow-sm);isolation:isolate;}
.img>.fill{position:absolute;inset:0;background:linear-gradient(155deg,var(--c1,var(--teal)),var(--c2,var(--cyan-deep)));transition:transform .6s var(--ease-out);}
.img>.fill::after{content:"";position:absolute;inset:0;background:radial-gradient(60% 45% at 28% 22%,color-mix(in srgb,var(--cyan) 50%,transparent),transparent 60%),repeating-linear-gradient(125deg,rgba(255,255,255,.05) 0 3px,transparent 3px 13px);}
.img:hover>.fill{transform:scale(1.06);}
.img .tag{position:absolute;bottom:12px;left:12px;z-index:2;background:rgba(47,33,69,.55);color:var(--ink-invert-soft);font-size:.64rem;letter-spacing:.1em;text-transform:uppercase;font-weight:700;padding:5px 11px;border-radius:100px;backdrop-filter:blur(6px);}
.img .ico{position:absolute;top:12px;right:12px;z-index:2;width:30px;height:30px;border-radius:50%;display:grid;place-items:center;background:rgba(255,255,255,.18);color:#fff;backdrop-filter:blur(4px);}
.img.v-navy>.fill{background:linear-gradient(155deg,var(--slate),var(--navy));}
.img.v-cyan>.fill{background:linear-gradient(155deg,var(--cyan),var(--cyan-deep));}
.img.v-teal>.fill{background:linear-gradient(155deg,var(--teal),var(--cyan-deep));}
.img.v-deep>.fill{background:linear-gradient(155deg,var(--cyan-deep),var(--navy));}
.img.has-photo{background:var(--navy);}
.img.has-photo>.ph{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;transition:transform .6s var(--ease-out);}
.img.has-photo:hover>.ph{transform:scale(1.06);}
.hero__right>.ph{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;}
.ar-43{aspect-ratio:4/3;}.ar-11{aspect-ratio:1;}.ar-169{aspect-ratio:16/9;}.ar-34{aspect-ratio:3/4;}.ar-32{aspect-ratio:3/2;}

/* =========================================================
   HEADER / NAV
   ========================================================= */
/* Floating frosted "pill" nav — fixed overlay so header images reach the very top */
.navshell{position:fixed;left:0;right:0;top:14px;z-index:200;display:flex;justify-content:center;padding-inline:14px;pointer-events:none;transition:transform .5s var(--ease-out),opacity .4s ease;}
.navshell.hide{transform:translateY(-185%);}   /* slide only — fading opacity makes the backdrop blur snap */
.pillnav{pointer-events:auto;position:relative;display:flex;align-items:center;gap:4px;max-width:100%;background:transparent;border:0;border-radius:100px;padding:8px 9px;box-shadow:0 20px 50px rgba(7,20,38,.40),inset 0 1px 0 rgba(255,255,255,.09);}
/* Blur lives on a pseudo-element (not the pill itself) so the pill isn't a backdrop-filter
   ancestor of the dropdowns — that would stop each dropdown's own blur from sampling the page. */
.pillnav::before{content:"";position:absolute;inset:0;z-index:-1;border-radius:inherit;background:rgba(47,33,69,.70);backdrop-filter:blur(16px) saturate(1.5);-webkit-backdrop-filter:blur(16px) saturate(1.5);}

/* brand (base styles also used by footer) */
.brand{display:flex;align-items:center;gap:.7em;flex-shrink:0;color:var(--ink-strong);}
.brand__mark{width:46px;height:46px;flex-shrink:0;object-fit:contain;transition:transform .5s var(--ease-out);}
.brand:hover .brand__mark{transform:rotate(-4deg) scale(1.05);}
.brand__name{font-family:var(--font-display);font-weight:700;font-size:1.02rem;line-height:1.05;letter-spacing:-.01em;}
.brand__name span{display:block;font-family:var(--font-body);font-size:.6rem;letter-spacing:.24em;text-transform:uppercase;color:var(--muted);font-weight:600;margin-top:2px;}
/* pill-scoped brand */
.pillnav .brand{color:#fff;}
/* Circular knockout badge: navy circle, white mark, monogram shows the navy through */
.brand__logo{width:44px;height:44px;border-radius:50%;overflow:hidden;background:var(--navy);flex-shrink:0;display:grid;place-items:center;box-shadow:0 2px 8px rgba(47,33,69,.22);transition:transform .5s var(--ease-out);}
.brand:hover .brand__logo{transform:rotate(-4deg) scale(1.05);}
.brand__logo img{width:100%;height:100%;object-fit:contain;}
.pillnav .brand__name{display:none;}

.menu{position:relative;display:flex;align-items:center;gap:0;list-style:none;padding:0;margin:0 2px;}
.menu>li{position:relative;}
.menu>li>a,.menu>li>button{position:relative;z-index:1;display:inline-flex;align-items:center;gap:.32em;padding:.62em .92em;border-radius:100px;font-family:var(--font-display);font-weight:600;font-size:.9rem;color:rgba(244,238,225,.78);background:none;border:none;white-space:nowrap;transition:color .3s ease;}
.menu>li>a:hover,.menu>li>button:hover,.menu>li>a[aria-current="page"],.menu>li>button[aria-current="page"]{color:#fff;}
.menu .caret{width:9px;height:9px;opacity:.7;transition:transform .35s var(--ease-out);}
.menu>li:hover .caret,.menu>li:focus-within .caret{transform:rotate(180deg);}
.menu__pill{position:absolute;left:0;top:0;height:0;width:0;background:rgba(255,255,255,.16);border-radius:100px;z-index:0;opacity:0;pointer-events:none;}
.dropdown{position:absolute;top:calc(100% + 16px);left:50%;translate:-50% 0;min-width:230px;list-style:none;padding:8px;margin:0;background:rgba(47,33,69,.70);backdrop-filter:blur(16px) saturate(1.5);-webkit-backdrop-filter:blur(16px) saturate(1.5);border:0;border-radius:var(--radius);box-shadow:0 20px 50px rgba(7,20,38,.40),inset 0 1px 0 rgba(255,255,255,.09);opacity:0;visibility:hidden;transform:translateY(8px);transition:opacity .28s var(--ease-out),transform .28s var(--ease-out),visibility .28s;}
.dropdown::before{content:"";position:absolute;top:-16px;left:0;right:0;height:16px;}
/* Pointer devices only. On a touch screen Safari invents a hover on the first
   tap, and tapping a link inside the item also satisfies :focus-within - either
   one opened this desktop dropdown over the mobile UI and swallowed the tap, so
   you had to tap again to get anywhere. The mobile overlay opens its folders by
   a different route (.mobmenu .has-dropdown.open, driven by a real button and
   max-height), so it is unaffected by this guard. */
@media (hover: hover) {
  .menu>li:hover .dropdown,.menu>li:focus-within .dropdown{opacity:1;visibility:visible;transform:translateY(0);}
}
.dropdown a{display:block;padding:.6em .85em;border-radius:var(--radius-sm);font-size:.9rem;font-weight:500;color:rgba(249,250,253,.86);transition:background .2s,color .2s,padding-left .25s var(--ease-out);}
.dropdown a:hover{background:rgba(255,255,255,.10);color:#fff;padding-left:1.15em;}
.nav__links{display:flex;align-items:center;gap:6px;}
.nav__actions{display:flex;align-items:center;gap:6px;}
.nav__actions .btn{padding:.7em 1.25em;font-size:.88rem;box-shadow:none;}
.hamburger{display:none;width:42px;height:42px;border:none;background:rgba(255,255,255,.10);border-radius:50%;position:relative;flex-shrink:0;}
.hamburger span{position:absolute;left:12px;right:12px;height:2px;background:#fff;border-radius:2px;transition:transform .4s var(--ease-out),opacity .3s,top .3s;}
.hamburger span:nth-child(1){top:15px;}.hamburger span:nth-child(2){top:20px;}.hamburger span:nth-child(3){top:25px;}
body.menu-open .hamburger span:nth-child(1){top:20px;transform:rotate(45deg);}
body.menu-open .hamburger span:nth-child(2){opacity:0;}
body.menu-open .hamburger span:nth-child(3){top:20px;transform:rotate(-45deg);}

/* =========================================================
   HOME — HERO split
   ========================================================= */
.hero{position:relative;}
.hero__grid{display:grid;grid-template-columns:1fr 1fr;min-height:clamp(520px,78vh,760px);}
.hero__left{display:flex;flex-direction:column;justify-content:center;padding:clamp(104px,13vh,128px) clamp(20px,5vw,72px) clamp(28px,5vw,64px);}
.hero__left .eyebrow{margin-bottom:var(--space-lg);}
.hero h1{font-size:clamp(2.6rem,1.7rem + 3.6vw,4.6rem);font-weight:800;line-height:1.0;letter-spacing:-.03em;}
.hero h1 .serif{color:var(--cyan);font-weight:400;}
.hero__sub{margin-top:var(--space-lg);color:var(--ink-soft);max-width:42ch;}
.hero__cta{margin-top:var(--space-xl);display:flex;gap:var(--space-md);flex-wrap:wrap;}
.hero__quick{margin-top:var(--space-2xl);display:flex;gap:var(--space-xl);flex-wrap:wrap;}
.hero__quick div{display:flex;flex-direction:column;}
.hero__quick dt{font-size:.66rem;letter-spacing:.16em;text-transform:uppercase;color:var(--muted);font-weight:700;}
.hero__quick dd{font-family:var(--font-display);font-weight:700;font-size:1.05rem;color:var(--ink-strong);}
.hero__right{position:relative;background:linear-gradient(150deg,var(--teal),var(--cyan-deep));overflow:hidden;}
.hero__right .fill{position:absolute;inset:0;transition:transform 1s var(--ease-out);}
.hero__right .fill::after{content:"";position:absolute;inset:0;background:radial-gradient(70% 50% at 70% 20%,color-mix(in srgb,var(--cyan) 55%,transparent),transparent 60%),repeating-linear-gradient(125deg,rgba(255,255,255,.05) 0 3px,transparent 3px 13px);}
.hero__photo-tag{position:absolute;top:20px;right:20px;z-index:2;background:rgba(47,33,69,.5);color:var(--ink-invert-soft);font-size:.66rem;letter-spacing:.12em;text-transform:uppercase;font-weight:700;padding:6px 12px;border-radius:100px;backdrop-filter:blur(6px);}
.hero__card{position:absolute;bottom:26px;left:26px;right:26px;max-width:380px;z-index:2;background:var(--paper);border-radius:var(--radius);padding:var(--space-lg);box-shadow:var(--shadow-lg);display:flex;gap:var(--space-md);align-items:center;}
.hero__card .thumb{width:74px;height:74px;border-radius:var(--radius-sm);flex-shrink:0;background:linear-gradient(150deg,var(--cyan),var(--navy));}
.hero__card h3{font-size:1.05rem;}.hero__card p{font-size:.84rem;color:var(--muted);margin-top:2px;}
.hero__card .when{color:var(--cyan-deep);font-weight:700;font-size:.82rem;margin-top:4px;}

/* =========================================================
   INNER PAGE BANNER (image-forward hero)
   ========================================================= */
.banner{position:relative;overflow:hidden;color:var(--ink-invert);isolation:isolate;background:var(--navy);}
/* Shorter banner for pages that are mostly a form — the hero shouldn't be the
   tallest thing on a page whose job is to be filled in. */
.banner--short .banner__inner{padding-block:clamp(56px,9vw,96px);}
.banner--short .banner__card{max-width:640px;}
html.app-mode .banner--short .banner__inner{padding-top:calc(env(safe-area-inset-top,0px) + clamp(40px,8vw,64px));}
.banner .fill{position:absolute;inset:0;z-index:-2;background:linear-gradient(150deg,var(--c1,var(--slate)),var(--c2,var(--navy)));}
.banner .fill::after{content:"";position:absolute;inset:0;background:radial-gradient(70% 60% at 75% 15%,color-mix(in srgb,var(--teal) 50%,transparent),transparent 60%),radial-gradient(60% 55% at 12% 95%,color-mix(in srgb,var(--cyan) 45%,transparent),transparent 55%),repeating-linear-gradient(125deg,rgba(255,255,255,.04) 0 3px,transparent 3px 13px);}
/* real photos don't get the placeholder texture — only the gradient placeholders do */
.banner .fill[style*="background-image"]::after,
.img>.fill[style*="background-image"]::after,
.hero__right .fill[style*="background-image"]::after{background:linear-gradient(to top,rgba(47,33,69,.28),transparent 60%);}
.banner::after{content:"";position:absolute;inset:0;z-index:-1;background:linear-gradient(to top,rgba(47,33,69,.5),transparent 70%);}
.banner__inner{padding-top:clamp(120px,15vw,190px);padding-bottom:clamp(56px,9vw,104px);max-width:760px;}
.banner__photo{position:absolute;inset:0;z-index:-2;background-size:cover;background-position:center;}
.banner__scrim{position:absolute;inset:0;z-index:-1;background:linear-gradient(160deg,rgba(47,33,69,.82),rgba(47,33,69,.6) 55%,rgba(47,33,69,.86));}
.banner .crumb{margin-bottom:var(--space-md);}
.banner h1{color:var(--ink-invert);font-size:clamp(2.4rem,1.6rem + 3.6vw,4.4rem);line-height:1.0;letter-spacing:-.02em;}
.banner h1 .serif{color:var(--teal);}
.banner p{margin-top:var(--space-lg);color:rgba(244,238,225,.9);font-size:clamp(1.05rem,1rem + .4vw,1.25rem);max-width:54ch;}
.banner .btn{margin-top:var(--space-xl);}
.crumb{display:flex;gap:.5em;align-items:center;font-size:.78rem;font-weight:600;letter-spacing:.04em;color:rgba(244,238,225,.7);flex-wrap:wrap;}
.crumb a{color:rgba(244,238,225,.7);}.crumb a:hover{color:var(--teal);}
.crumb .sep{opacity:.5;}

/* =========================================================
   PROSE
   ========================================================= */
.prose{max-width:70ch;}
.prose h2{font-size:clamp(1.7rem,1.3rem + 1.8vw,2.5rem);margin-top:var(--space-2xl);margin-bottom:var(--space-md);}
.prose h2:first-child{margin-top:0;}
.prose h2 .serif{color:var(--cyan);}
.prose h3{font-size:1.3rem;margin-top:var(--space-xl);margin-bottom:var(--space-xs);}
.prose p{margin-bottom:var(--space-md);color:var(--ink-soft);}
.prose ul{margin:0 0 var(--space-md) 1.1em;color:var(--ink-soft);display:grid;gap:8px;}
.prose strong{color:var(--ink);}
.prose a:not(.btn){color:var(--cyan-deep);font-weight:600;border-bottom:1.5px solid color-mix(in srgb,var(--cyan) 40%,transparent);}

/* section heading block */
.head{margin-bottom:var(--space-2xl);}
.head h2{font-size:clamp(1.9rem,1.4rem + 2.2vw,3rem);max-width:18ch;}
.head h2 .serif{color:var(--cyan);}
.head.center h2{margin-inline:auto;}
.head p{margin-top:var(--space-md);}
.head--row{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--space-lg);flex-wrap:wrap;}

/* =========================================================
   SPLIT (image + text)
   ========================================================= */
.split{display:grid;grid-template-columns:1fr 1fr;gap:clamp(28px,5vw,72px);align-items:center;}
.split + .split{margin-top:clamp(40px,6vw,80px);}
.split .img{aspect-ratio:4/3;width:100%;}
.split.rev .split__media{order:2;}
.split__copy h2{font-size:clamp(1.7rem,1.3rem + 1.8vw,2.6rem);margin-bottom:var(--space-md);}
.split__copy h2 .serif{color:var(--cyan);}
.split__copy p{color:var(--ink-soft);}.split__copy p+p{margin-top:var(--space-md);}
.split__copy .btn{margin-top:var(--space-lg);}
.split__copy .eyebrow{margin-bottom:var(--space-sm);}

/* =========================================================
   GALLERY
   ========================================================= */
.gallery{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--space-md);grid-auto-rows:1fr;}
.gallery .img{aspect-ratio:1;}
.gallery .img.big{grid-column:span 2;grid-row:span 2;aspect-ratio:auto;}
.gallery .img.wide{grid-column:span 2;aspect-ratio:auto;}
.gallery--3{grid-template-columns:repeat(3,1fr);}
/* A placeholder tile that has had a photo uploaded to it shows the photo (and hides the gradient/icon). */
.img[style*="background-image"]{background-size:cover;background-position:center;}
.img[style*="background-image"]>.fill,.img[style*="background-image"]>.ico,.img[style*="background-image"]>.tag{display:none;}
/* photos set as figure backgrounds get the same hover zoom as <img> photos */
.img[style*="background-image"]::before{content:"";position:absolute;inset:0;background:inherit;background-size:cover;background-position:center;transition:transform .6s var(--ease-out);}
.img[style*="background-image"]:hover::before{transform:scale(1.06);}

/* Polaroid filmstrip — drag/swipe through photos (e.g. Our History) */
.filmstrip{position:relative;margin-top:clamp(28px,5vw,52px);}
/* overflow-x:auto clips the other axis too, and the polaroids' drop-shadow
   reaches 38px below the image (0 16px 22px) against 34px of padding — so the
   soft edge was being sliced off in a hard line just above the next section.
   The extra room is padding, pulled back by a negative margin, so the strip
   has somewhere to cast into without moving anything on the page. */
.filmstrip__track{display:flex;gap:clamp(18px,3vw,36px);overflow-x:auto;scroll-snap-type:x proximity;padding:18px clamp(20px,5vw,52px) 58px;margin-bottom:-24px;scrollbar-width:thin;-webkit-overflow-scrolling:touch;cursor:grab;}
.filmstrip__track.is-drag{cursor:grabbing;scroll-snap-type:none;}
.filmstrip__track.is-drag .polaroid{pointer-events:none;}
.polaroid{flex:none;scroll-snap-align:center;width:clamp(200px,26vw,280px);transform:rotate(var(--r,0deg));transition:transform .3s var(--ease-out);}
.polaroid:nth-child(odd){--r:-1.7deg;}
.polaroid:nth-child(even){--r:1.5deg;}
.polaroid:nth-child(3n){--r:.7deg;}
.polaroid:nth-child(5n){--r:-2.4deg;}
.polaroid img{display:block;width:100%;height:auto;filter:drop-shadow(0 16px 22px rgba(47,33,69,.28));transition:filter .3s var(--ease-out);}
.polaroid::after{display:none;}
.polaroid:hover{transform:rotate(0deg) translateY(-6px) scale(1.03);position:relative;z-index:2;}
.polaroid:hover img{filter:drop-shadow(0 24px 34px rgba(47,33,69,.34));}
.filmstrip__nav{position:absolute;top:calc(50% - 6px);transform:translateY(-50%);z-index:3;width:46px;height:46px;border-radius:50%;background:#fff;border:1px solid var(--line);box-shadow:0 6px 18px rgba(47,33,69,.16);color:var(--navy);font-size:1.7rem;line-height:1;display:grid;place-items:center;cursor:pointer;transition:background .2s,color .2s;}
.filmstrip__nav:hover{background:var(--navy);color:#fff;border-color:var(--navy);}
.filmstrip__nav--prev{left:max(8px,calc(50% - 620px));}
.filmstrip__nav--next{right:max(8px,calc(50% - 620px));}
@media(max-width:680px){.filmstrip__nav{display:none;}}

/* Scroll-velocity image marquee (legacy, unused) */
.velo-sec{overflow:hidden;}
.velo{display:flex;flex-direction:column;gap:clamp(12px,1.8vw,20px);margin-top:clamp(28px,5vw,52px);width:100%;}
.velo__row{overflow:hidden;}
.velo__track{display:flex;gap:clamp(12px,1.8vw,20px);width:max-content;will-change:transform;}
.velo__item{flex:none;height:clamp(150px,21vw,290px);margin:0;border-radius:var(--radius-card);overflow:hidden;background:var(--cream-2);box-shadow:var(--shadow-sm);}
.velo__item img{height:100%;width:auto;display:block;object-fit:cover;}
/* If motion is reduced, fall back to a normal swipeable strip with no auto-animation */
@media(prefers-reduced-motion:reduce){
  .velo__row{overflow-x:auto;scrollbar-width:thin;}
  .velo__track{transform:none !important;}
}

/* =========================================================
   FEATURE CARDS (image-top)
   ========================================================= */
/* Card rows: max 3 across, balanced so the last row is never a lone card (5→3+2, 4→2+2). */
.cards{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--space-lg);}
.cards:has(> :nth-child(2):last-child){grid-template-columns:repeat(2,minmax(0,1fr));}   /* exactly 2 */
.cards:has(> :nth-child(4):last-child){grid-template-columns:repeat(2,minmax(0,1fr));}   /* exactly 4 → 2+2 */
@media(max-width:900px){
  .cards,.cards:has(> :nth-child(2):last-child),.cards:has(> :nth-child(4):last-child){grid-template-columns:repeat(2,minmax(0,1fr));}
  .cards > :last-child:nth-child(odd){grid-column:1 / -1;}     /* lone trailing card spans the row instead of sitting alone */
}
@media(max-width:560px){
  .cards,.cards:has(> :nth-child(2):last-child),.cards:has(> :nth-child(4):last-child){grid-template-columns:1fr;}
  .cards > :last-child:nth-child(odd){grid-column:auto;}
}
.card{display:flex;flex-direction:column;background:var(--paper);border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;transition:transform .5s var(--ease-out),box-shadow .5s var(--ease-out);}
.card:hover{transform:translateY(-6px);box-shadow:var(--shadow-lg);}
.card .img{aspect-ratio:16/10;border-radius:0;box-shadow:none;}
.card__body{padding:var(--space-lg);display:flex;flex-direction:column;flex:1;}
.card .kicker{font-size:.66rem;letter-spacing:.14em;text-transform:uppercase;font-weight:700;color:var(--cyan-deep);}
.card h3{font-size:1.25rem;margin-top:4px;}
.card p{color:var(--ink-soft);font-size:.94rem;margin-top:var(--space-xs);}
.card .go{margin-top:var(--space-md);font-family:var(--font-display);font-weight:700;font-size:.88rem;color:var(--cyan-deep);display:inline-flex;gap:.4em;align-items:center;transition:gap .3s var(--ease-out);}
.card:hover .go{gap:.75em;}

/* YouTube video grid (real thumbnails) */
.vidgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:var(--space-lg);}
.vidcard{display:flex;flex-direction:column;background:var(--paper);border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;transition:transform .5s var(--ease-out),box-shadow .5s var(--ease-out);}
.vidcard:hover{transform:translateY(-6px);box-shadow:var(--shadow-lg);}
.vidcard__thumb{position:relative;aspect-ratio:16/9;overflow:hidden;background:var(--navy);}
.vidcard__thumb img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;transition:transform .6s var(--ease-out);}
.vidcard:hover .vidcard__thumb img{transform:scale(1.06);}
.vidcard__play{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:54px;height:54px;border-radius:50%;background:rgba(47,33,69,.66);color:#fff;display:grid;place-items:center;backdrop-filter:blur(2px);transition:background .3s,transform .3s var(--ease-out);}
.vidcard:hover .vidcard__play{background:var(--cyan);transform:translate(-50%,-50%) scale(1.08);}
.vidcard__play svg{margin-left:3px;}
.vidcard__title{font-family:var(--font-display);font-weight:600;font-size:1rem;color:var(--ink);padding:var(--space-md) var(--space-lg) 4px;line-height:1.3;}
.vidcard__date{padding:0 var(--space-lg) var(--space-lg);color:var(--muted);font-size:.82rem;}
.vidcard{cursor:pointer;}

/* ═══ media pages (Testimonies & Music): highlighted-video hero melting into navy,
       whole page carries the dark blue — same treatment as the Sermons page ═══ */
.mpage{background:var(--navy)}
.mpage .section{background:var(--navy)}
.mhero{position:relative;isolation:isolate;background:var(--navy);color:#fff;overflow:hidden;
  padding:clamp(96px,12vw,138px) 0 clamp(56px,8vw,92px);text-align:center}
.mhero__bg{position:absolute;inset:-50px;z-index:-2;background-size:cover;background-position:center 30%;
  filter:blur(42px) saturate(1.25) brightness(.85);transform:scale(1.12)}
.mhero__fade{position:absolute;inset:0;z-index:-1;
  background:linear-gradient(180deg,rgba(47,33,69,.30) 0%,rgba(47,33,69,.44) 34%,rgba(47,33,69,.62) 58%,rgba(47,33,69,.86) 80%,var(--navy) 100%)}
.mhero__kick{font-size:.7rem;font-weight:700;letter-spacing:.28em;text-transform:uppercase;color:#dfc17a;margin-bottom:16px}
.mhero__player{max-width:740px;margin-inline:auto}
.mhero__player .vidcard{background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.13);border-radius:var(--radius);padding:0;box-shadow:0 30px 70px rgba(0,0,0,.45)}
.mhero__player .vidcard:hover{border-color:rgba(127,214,234,.5)}
.mhero__player .vidcard__thumb{border-radius:0;box-shadow:none}
.mhero__title{font-size:clamp(1.6rem,3.4vw,2.6rem);letter-spacing:-.025em;line-height:1.08;color:#fff;max-width:26ch;margin:20px auto 0}
.mhero__cta{display:flex;gap:10px;justify-content:center;flex-wrap:wrap;margin-top:20px}
/* dark content below the fade */
.mpage .head .eyebrow{color:#dfc17a}
.mpage .head h2{color:#fff}
.mpage .head h2 .serif{color:#dfc17a}
.mpage .vidcard{background:rgba(255,255,255,.06);border-color:rgba(255,255,255,.13)}
.mpage .vidcard:hover{border-color:rgba(127,214,234,.5)}
.mpage .vidcard__title{color:#fff}
.mpage .vidcard__date{color:rgba(244,238,225,.62)}
.mpage .quote blockquote{color:#fff}
.mpage .quote cite{color:rgba(244,238,225,.7)}
.mpage .quote .hl{color:#dfc17a}
.mpage .split__copy .eyebrow{color:#dfc17a}
.mpage .split__copy h2{color:#fff}
.mpage .split__copy h2 .serif{color:#dfc17a}
.mpage .split__copy p,.mpage .split__copy .lead{color:rgba(249,250,253,.85)}
html.app-mode .mhero{padding-top:calc(env(safe-area-inset-top,0px) + clamp(52px,9vw,80px))}

/* In-site video player (lightbox) */
body.vplayer-open{overflow:hidden;}
.vplayer{position:fixed;inset:0;z-index:1000;display:none;align-items:center;justify-content:center;padding:clamp(14px,4vw,40px);}
.vplayer.open{display:flex;}
.vplayer__backdrop{position:absolute;inset:0;background:rgba(7,18,33,.78);backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);animation:vfade .25s var(--ease-out) both;}
.vplayer__box{position:relative;width:min(1040px,100%);animation:vrise .35s var(--ease-out) both;}
.vplayer__frame{position:relative;aspect-ratio:16/9;background:#000;border-radius:var(--radius);overflow:hidden;box-shadow:0 40px 120px rgba(0,0,0,.55);}
.vplayer__frame iframe{position:absolute;inset:0;width:100%;height:100%;border:0;}
.vplayer__title{margin-top:14px;color:var(--ink-invert);font-family:var(--font-display);font-weight:600;font-size:1.05rem;text-align:center;text-shadow:0 1px 12px rgba(0,0,0,.5);}
.vplayer__tags{display:flex;flex-wrap:wrap;gap:6px;justify-content:center;margin-top:10px;}
.vplayer__tags:empty{display:none;}
.vplayer__tags .vtag{color:#bfeefb;background:rgba(127,214,234,.13);border-color:rgba(127,214,234,.34);}
/* Close button floats on top of the video, top-right corner */
.vplayer__x{position:absolute;top:12px;right:12px;z-index:5;width:40px;height:40px;border-radius:50%;border:none;background:rgba(47,33,69,.55);color:#fff;display:grid;place-items:center;cursor:pointer;-webkit-backdrop-filter:blur(8px) saturate(1.4);backdrop-filter:blur(8px) saturate(1.4);box-shadow:0 6px 20px rgba(0,0,0,.4);transition:transform .25s var(--ease-out),background .25s;}
.vplayer__x:hover{transform:scale(1.08) rotate(90deg);background:var(--cyan);}
/* Sermon tag chips (used on cards and in the player) */
.vidcard__tags{display:flex;flex-wrap:wrap;gap:6px;padding:0 var(--space-lg) var(--space-lg);margin-top:auto;}
.vidcard:has(.vidcard__tags) .vidcard__date{padding-bottom:12px;}
.vidcard:has(.vidcard__tags):not(:has(.vidcard__date)) .vidcard__tags{padding-top:12px;}
.vtag{display:inline-block;font-size:.62rem;font-weight:700;letter-spacing:.03em;text-transform:uppercase;color:var(--cyan-deep,#0a6b86);background:color-mix(in srgb,var(--cyan,#9b7d29) 8%,transparent);border:1px solid color-mix(in srgb,var(--cyan,#9b7d29) 18%,transparent);border-radius:100px;padding:.44em .85em;line-height:1;white-space:nowrap;}
@keyframes vfade{from{opacity:0}to{opacity:1}}
@keyframes vrise{from{opacity:0;transform:translateY(16px) scale(.98)}to{opacity:1;transform:none}}
@media(prefers-reduced-motion:reduce){.vplayer__backdrop,.vplayer__box{animation:none;}}

/* =========================================================
   HORIZONTAL RAIL
   ========================================================= */
.railwrap{position:relative;}
.rail{display:flex;gap:var(--space-lg);overflow-x:auto;scroll-snap-type:x mandatory;padding-bottom:var(--space-sm);scrollbar-width:none;cursor:grab;}
.rail::-webkit-scrollbar{display:none;}
.rail.is-drag{cursor:grabbing;scroll-snap-type:none;scroll-behavior:auto;}
.rail.is-drag a{pointer-events:none;}
.rail__arrow{position:absolute;top:42%;transform:translateY(-50%);z-index:4;width:46px;height:46px;border-radius:50%;border:1px solid var(--line);background:#fff;color:var(--navy);display:grid;place-items:center;cursor:pointer;box-shadow:0 10px 26px rgba(47,33,69,.18);transition:transform .2s var(--ease-out),opacity .25s var(--ease-out),background .2s,color .2s;}
.rail__arrow:hover{background:var(--navy);color:#fff;transform:translateY(-50%) scale(1.07);}
.rail__arrow--prev{left:-10px;}
.rail__arrow--next{right:-10px;}
.rail__arrow[disabled]{opacity:0;pointer-events:none;}
@media(hover:none){.rail__arrow{display:none;}}
.rcard{scroll-snap-align:start;flex:0 0 clamp(240px,30vw,300px);}
.rcard .img{aspect-ratio:1.08;}
.rcard h3{margin-top:var(--space-md);font-size:1.15rem;}
.rcard .meta{color:var(--muted);font-size:.86rem;margin-top:2px;}
.rcard .meta b{color:var(--cyan-deep);}

/* =========================================================
   VLIST (sermons / events rows)
   ========================================================= */
.vlist{display:grid;gap:var(--space-md);}
.vrow{display:grid;grid-template-columns:auto 1fr auto;gap:var(--space-lg);align-items:center;background:var(--paper);border:1px solid var(--line);border-radius:var(--radius);padding:var(--space-md);transition:transform .4s var(--ease-out),box-shadow .4s var(--ease-out);}
.vrow:hover{transform:translateY(-3px);box-shadow:var(--shadow-md);}
.vrow .img{width:clamp(96px,14vw,150px);aspect-ratio:16/10;}
.vrow .play{position:absolute;inset:0;z-index:2;display:grid;place-items:center;color:#fff;}
.vrow .play svg{filter:drop-shadow(0 2px 8px rgba(0,0,0,.4));}
.vrow h3{font-size:1.12rem;}
.vrow .meta{color:var(--muted);font-size:.85rem;margin-top:2px;}
.vrow .tagline{color:var(--cyan-deep);font-weight:600;font-size:.8rem;text-transform:uppercase;letter-spacing:.08em;}
.vrow .when{text-align:center;font-family:var(--font-display);}
.vrow .when .d{font-size:1.6rem;font-weight:800;color:var(--ink-strong);line-height:1;}
.vrow .when .m{font-size:.7rem;text-transform:uppercase;letter-spacing:.1em;color:var(--cyan-deep);font-weight:700;}
@media(max-width:620px){.vrow{grid-template-columns:auto 1fr;}.vrow .when{display:none;}}

/* =========================================================
   ACCORDION (beliefs / FAQ)
   ========================================================= */
.acc{display:grid;gap:var(--space-sm);max-width:860px;}
.acc__item{background:var(--paper);border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;}
.acc__q{width:100%;display:flex;align-items:center;justify-content:space-between;gap:var(--space-md);padding:var(--space-lg);font-family:var(--font-display);font-weight:700;font-size:1.05rem;color:var(--ink-strong);background:none;border:none;text-align:left;cursor:pointer;-webkit-tap-highlight-color:transparent;}
.acc__q .pm{flex-shrink:0;width:24px;height:24px;position:relative;transition:transform .4s var(--ease-out);}
.acc__q .pm::before,.acc__q .pm::after{content:"";position:absolute;background:var(--cyan);border-radius:2px;}
.acc__q .pm::before{top:11px;left:3px;right:3px;height:2px;}
.acc__q .pm::after{left:11px;top:3px;bottom:3px;width:2px;transition:transform .4s var(--ease-out);}
.acc__item.open .pm::after{transform:scaleY(0);}
.acc__a{display:grid;grid-template-rows:0fr;transition:grid-template-rows .45s var(--ease-out);}
.acc__item.open .acc__a{grid-template-rows:1fr;}
.acc__a>div{overflow:hidden;transform:translateY(-10px);transition:transform .42s var(--ae-out,cubic-bezier(.16,1,.3,1));}
.acc__item.open .acc__a>div{transform:translateY(0);}
@media(prefers-reduced-motion:reduce){.acc__a>div{transition:none;transform:none;}}
.acc__a p{padding:0 var(--space-lg) var(--space-lg);color:var(--ink-soft);}
.acc__a a{color:var(--cyan-deep);font-weight:600;text-decoration:underline;text-underline-offset:2px;text-decoration-thickness:1px;transition:color .2s;}
.acc__a a:hover{color:var(--cyan);}

/* =========================================================
   TEAM
   ========================================================= */
/* Fixed-width people so every photo is the same size in every section, centered rows. */
.team{display:flex;flex-wrap:wrap;justify-content:center;gap:var(--space-lg);}
.team .person{flex:0 1 260px;max-width:260px;width:100%;}
.person .img{aspect-ratio:3/4;}
.person h3{font-size:1.12rem;margin-top:var(--space-md);}
.person .role{color:var(--cyan-deep);font-weight:600;font-size:.88rem;}
.person .bio{margin-top:8px;color:var(--ink-soft);font-size:.88rem;line-height:1.55;}
.team--bio .person{flex-basis:290px;max-width:290px;}
/* cap a section to 3 across so rows stay even (e.g. 6 pastors → 3 + 3) */
.team--cap3{max-width:calc(290px * 3 + var(--space-lg) * 2);margin-inline:auto;}

/* =========================================================
   STAT BAND / QUOTE
   ========================================================= */
.band{background:var(--navy);color:var(--ink-invert-soft);}
.band h2,.band h3{color:var(--ink-invert);}
.band--cream{background:var(--cream-2);color:var(--ink);}
.band--cream h2{color:var(--ink-strong);}
.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:var(--space-lg);text-align:center;}
.stat .n{font-family:var(--font-serif);font-style:italic;font-size:clamp(2.6rem,2rem + 2vw,4rem);color:var(--teal);line-height:1;}
.stat .l{margin-top:var(--space-xs);font-size:.85rem;color:rgba(244,238,225,.8);text-transform:uppercase;letter-spacing:.1em;font-weight:600;}
.quote{text-align:center;max-width:900px;margin-inline:auto;}
.quote blockquote{font-family:var(--font-serif);font-style:italic;font-size:clamp(1.7rem,1.2rem + 2.2vw,2.8rem);line-height:1.26;color:var(--ink-strong);}
.band .quote blockquote{color:var(--ink-invert);}
.quote .hl{color:var(--cyan);}.band .quote .hl{color:var(--teal);}
.quote cite{display:block;margin-top:var(--space-lg);font-family:var(--font-display);font-style:normal;font-weight:700;font-size:.9rem;letter-spacing:.06em;color:var(--muted);}
.band .quote cite{color:rgba(244,238,225,.7);}

/* times list */
/* contained navy gradient card (e.g. home "Plan your first Sunday") */
.homecard--navy{position:relative;overflow:hidden;color:var(--ink-invert-soft);border-radius:clamp(22px,3vw,32px);
  background:linear-gradient(145deg,var(--cyan-deep),var(--navy) 62%);
  padding:clamp(30px,5vw,60px);box-shadow:0 26px 64px rgba(7,20,38,.28);}
.homecard--navy h2{color:var(--ink-invert);}
.homecard--navy .btn{margin-top:var(--space-lg);}
.times__grid{display:grid;grid-template-columns:1.2fr 1fr;gap:clamp(28px,5vw,72px);align-items:center;}
.times__list{display:grid;gap:var(--space-sm);}
.times__list li{list-style:none;display:flex;justify-content:space-between;gap:var(--space-md);padding:var(--space-md) 0;border-bottom:1px solid rgba(255,255,255,.14);font-family:var(--font-display);}
.times__list .lab{color:var(--ink-invert-soft);font-weight:600;}
.times__list .val{color:var(--teal);font-weight:700;white-space:nowrap;}

/* find (search moment) */
.find{background:var(--paper);text-align:center;}
.find h2{font-size:clamp(2.2rem,1.6rem + 4vw,4.6rem);font-weight:800;color:color-mix(in srgb,var(--navy) 32%,var(--cream));letter-spacing:-.03em;}
.find h2 .serif{color:var(--cyan);-webkit-text-stroke:0;}
.find__bar{margin:var(--space-xl) auto 0;max-width:560px;display:flex;gap:var(--space-sm);background:var(--cream);border:1px solid var(--line);border-radius:100px;padding:8px 8px 8px 22px;align-items:center;box-shadow:var(--shadow-sm);}
.find__bar span{color:var(--muted);font-size:.95rem;text-align:left;flex:1;}
.findtags{margin-top:var(--space-lg);display:flex;gap:var(--space-sm);justify-content:center;flex-wrap:wrap;}
.findtags a{font-size:.86rem;font-weight:600;padding:.5em 1.1em;border-radius:100px;background:var(--cream);border:1px solid var(--line);color:var(--ink-soft);transition:background-color .2s ease,color .2s ease,border-color .2s ease;}
.findtags a:hover{background:var(--navy);color:var(--ink-invert);border-color:var(--navy);transform:translateY(-2px);}

/* CTA / invite */
.invite{background:var(--cream-2);text-align:center;}
.invite h2{font-size:clamp(2.2rem,1.6rem + 3vw,4rem);max-width:18ch;margin-inline:auto;}
.invite h2 .serif{color:var(--cyan);}
.invite p{margin-top:var(--space-lg);color:var(--ink-soft);font-size:1.18rem;max-width:44ch;margin-inline:auto;}
.invite__cta{margin-top:var(--space-2xl);display:flex;gap:var(--space-md);justify-content:center;flex-wrap:wrap;}
.invite--navy{background:var(--navy);}
.invite--navy h2{color:var(--ink-invert);}.invite--navy h2 .serif{color:var(--teal);}
.invite--navy p{color:rgba(244,238,225,.88);}

/* =========================================================
   FOOTER
   ========================================================= */
.footer{--footer-head:color-mix(in srgb,var(--cyan) 84%,#fff);background:var(--navy);color:rgba(244,238,225,.72);padding-block:var(--space-3xl) var(--space-xl);}
.footer__grid{display:grid;grid-template-columns:1.4fr repeat(3,1fr);gap:var(--space-2xl) var(--space-lg);}
.footer__brand .brand,.footer__brand .brand__mark{color:var(--ink-invert-soft);}
.footer__brand .brand__name{color:var(--ink-invert);}
.footer p{font-size:.94rem;margin-top:var(--space-md);max-width:32ch;line-height:1.6;}
.footer h4{color:var(--footer-head);font-family:var(--font-display);font-size:1.02rem;letter-spacing:.08em;text-transform:uppercase;margin-bottom:var(--space-md);font-weight:700;text-decoration:underline;text-underline-offset:5px;text-decoration-thickness:1.5px;}
.footer ul{list-style:none;padding:0;display:grid;gap:10px;}
.footer a{font-size:.94rem;transition:color .25s;}
.footer li a{display:inline-block;transition:color .25s,transform .25s var(--ease-out);}
.footer li a:hover{transform:translateX(4px);}
.footer__contact a{display:block;}
.footer__contact li a{display:block;}
.socials{display:flex;gap:var(--space-sm);margin-top:var(--space-lg);}
.socials a{width:40px;height:40px;display:inline-flex;border-radius:50%;transition:transform .3s var(--ease-out),filter .3s;}
.socials a img{width:100%;height:100%;display:block;}
.socials a:hover{transform:translateY(-3px) scale(1.05);filter:drop-shadow(0 5px 12px rgba(0,0,0,.35));}
.footer__bottom{margin-top:var(--space-3xl);padding-top:var(--space-lg);border-top:1px solid rgba(255,255,255,.1);display:flex;justify-content:space-between;flex-wrap:wrap;gap:var(--space-sm);font-size:.84rem;color:rgba(244,238,225,.62);}

/* =========================================================
   ANNOUNCEMENT BAR
   ========================================================= */
/* ---- service alert -------------------------------------------------------
   A Sunday that is not going ahead as usual. Deliberately NOT brand-coloured:
   it has to read as an exception to the normal chrome rather than part of it,
   and the cyan announcement bar directly below is the thing it must not be
   mistaken for. Amber rather than red - the service has changed, it is not an
   emergency, and a congregation that sees red for a bit of snow will discount
   red when it matters. Navy on this amber is about 8.7:1, so it holds up in
   sun on a phone in a car park, which is exactly where it gets read. */
.svcalert{background:#f2c14e;color:#38164f;}
.svcalert__in{display:flex;align-items:flex-start;justify-content:center;gap:10px;
  padding:11px clamp(16px,4vw,28px);text-align:left;font-size:.92rem;line-height:1.45;}
.svcalert__ic{flex:none;display:grid;place-items:center;width:20px;height:20px;margin-top:1px;}
.svcalert__ic svg{width:20px;height:20px;display:block;}
.svcalert__tx b{font-weight:800;}
.svcalert__note{opacity:.78;}
@media (max-width:640px){ .svcalert__in{font-size:.86rem;padding:10px 16px;} }
.announce{background:var(--cyan-deep);color:var(--ink-invert-soft);font-size:.92rem;}
.announce__in{display:flex;align-items:center;justify-content:center;gap:var(--space-md);padding:10px clamp(40px,5vw,52px);text-align:center;position:relative;flex-wrap:wrap;}
.announce a{font-weight:700;color:#fff;border-bottom:1.5px solid rgba(255,255,255,.5);}
.announce a:hover{border-color:#fff;}
.announce__x{position:absolute;right:12px;top:50%;transform:translateY(-50%);background:none;border:none;color:rgba(255,255,255,.8);width:30px;height:30px;border-radius:50%;font-size:1.1rem;line-height:1;display:grid;place-items:center;}
.announce__x:hover{background:rgba(255,255,255,.15);color:#fff;}
/* announcement bar designs (base .announce = the classic solid bar) */
.announce--bold{font-size:1.02rem;font-weight:700;letter-spacing:.01em;background:var(--navy);}
.announce--bold .announce__in{padding-top:14px;padding-bottom:14px;text-transform:none;}
.announce--soft{background:color-mix(in srgb,var(--cyan) 13%,#fff);color:var(--navy);}
.announce--soft a{color:var(--cyan-deep);border-bottom-color:color-mix(in srgb,var(--cyan-deep) 45%,transparent);}
.announce--soft a:hover{border-color:var(--cyan-deep);}
.announce--soft .announce__x{color:rgba(47,33,69,.55);}
.announce--soft .announce__x:hover{background:rgba(47,33,69,.1);color:var(--ink-strong);}
.announce--gradient{background:linear-gradient(90deg,var(--navy),var(--cyan-deep) 55%,var(--cyan));color:#fff;}
/* announcement bar fonts */
.announce--fserif{font-family:var(--font-display,Georgia,serif);}
.announce--frounded{font-family:'Trebuchet MS','Segoe UI',sans-serif;}
/* ===== Blurred-artwork hero — shared by Messages, series pages, and the CMS "hero" header type.
   (The sermons/series pages add their own extras inline; this is the reusable base.) ===== */
/* --- Adaptive header sizing wrapper (page-builder banners) --- */
.bnrbox{position:relative;--bnr-h:60vh;--bnr-w:100%;--bnr-r:0px;}
.bnrbox--h > .banner,.bnrbox--h > .smhero{min-height:var(--bnr-h);}
.bnrbox--inset{padding:clamp(12px,3vw,34px);}
.bnrbox--inset > .banner,.bnrbox--inset > .smhero{width:var(--bnr-w);max-width:100%;margin-inline:auto;border-radius:var(--bnr-r);overflow:hidden;}
@media(max-width:640px){.bnrbox--inset{padding:10px;}.bnrbox--inset > .banner,.bnrbox--inset > .smhero{width:100%;}}
/* header title/text alignment overrides */
.bnr-al-left .smhero,.bnr-al-left .smhero__wrap,.bnr-al-left .banner__inner,.bnr-al-left .banner__card{text-align:left;}
.bnr-al-left .smhero__crumb,.bnr-al-left .smhero__cta,.bnr-al-left .banner__cta{justify-content:flex-start;}
.bnr-al-center .smhero,.bnr-al-center .smhero__wrap,.bnr-al-center .banner__inner,.bnr-al-center .banner__card{text-align:center;}
.bnr-al-center .smhero__crumb,.bnr-al-center .smhero__cta,.bnr-al-center .banner__cta{justify-content:center;}
.bnr-al-center .banner__inner .eyebrow,.bnr-al-center .banner__card .eyebrow{margin-inline:auto;}
.bnr-al-right .smhero,.bnr-al-right .smhero__wrap,.bnr-al-right .banner__inner,.bnr-al-right .banner__card{text-align:right;}
.bnr-al-right .smhero__crumb,.bnr-al-right .smhero__cta,.bnr-al-right .banner__cta{justify-content:flex-end;}
.bnr-al-right .banner__inner .eyebrow,.bnr-al-right .banner__card .eyebrow{margin-left:auto;}

.smhero{position:relative;isolation:isolate;background:var(--navy,#38164f);color:#fff;overflow:hidden;padding:clamp(96px,12vw,138px) 0 clamp(48px,7vw,72px);text-align:center;}
.smhero__bg{position:absolute;inset:-50px;z-index:-2;background-size:cover;background-position:center 30%;filter:blur(42px) saturate(1.25) brightness(.85);transform:scale(1.12);}
.smhero__fade{position:absolute;inset:0;z-index:-1;background:linear-gradient(180deg,rgba(47,33,69,.30) 0%,rgba(47,33,69,.44) 34%,rgba(47,33,69,.62) 58%,rgba(47,33,69,.86) 80%,var(--navy,#38164f) 100%);}
.smhero__crumb{justify-content:center;display:flex;margin-bottom:14px;}
.smhero__crumb,.smhero__crumb a{color:rgba(249,250,253,.8);}
.smhero__kick{font-size:.7rem;font-weight:700;letter-spacing:.28em;text-transform:uppercase;color:#dfc17a;margin-bottom:14px;}
.smhero__title{font-size:clamp(1.9rem,4vw,2.9rem);letter-spacing:-.025em;line-height:1.08;color:#fff;max-width:22ch;margin:0 auto;}
.smhero__meta{color:rgba(244,238,225,.78);font-size:clamp(.92rem,1.2vw,1.04rem);margin:12px auto 0;max-width:54ch;}
.smhero__cta{display:flex;gap:10px;justify-content:center;flex-wrap:wrap;margin-top:22px;}
/* "Crisp top" variant: a sharp copy of the photo layered over the blurred one, masked so it
   fades out as it nears the transition line — the image starts sharp and gradually blurs down. */
.smhero--sharp .smhero__bg{z-index:-3;}
.smhero__sharp{position:absolute;inset:-50px;z-index:-2;background-size:cover;background-position:center 30%;transform:scale(1.12);
  -webkit-mask-image:linear-gradient(to bottom,#000 0%,#000 30%,rgba(0,0,0,.4) 55%,transparent 74%);
          mask-image:linear-gradient(to bottom,#000 0%,#000 30%,rgba(0,0,0,.4) 55%,transparent 74%);}
@media(max-width:700px){.smhero--cms{padding-top:clamp(84px,20vw,104px);}.smhero--cms .smhero__title{font-size:1.6rem;}}
/* ===== CMS page sections: stat row, FAQ accordion, pull quote ===== */
.cmsstats{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:24px;text-align:center;margin-top:var(--space-lg,28px);}
.cmsstat__n{display:block;font-family:var(--font-display,inherit);font-weight:800;font-size:clamp(2rem,4.5vw,3rem);color:var(--navy,#38164f);line-height:1;letter-spacing:-.02em;}
.cmsstat__l{display:block;margin-top:8px;font-size:.84rem;letter-spacing:.05em;text-transform:uppercase;color:var(--muted,#6d5f7b);font-weight:600;}
.cmsfaq{margin-top:var(--space-lg,28px);display:flex;flex-direction:column;gap:10px;}
.cmsfaq__it{border:1px solid var(--line,#ebe6ee);border-radius:12px;background:#fff;overflow:hidden;}
.cmsfaq__it summary{cursor:pointer;padding:15px 18px;font-weight:700;color:var(--navy,#38164f);list-style:none;display:flex;justify-content:space-between;align-items:center;gap:12px;}
.cmsfaq__it summary::-webkit-details-marker{display:none;}
.cmsfaq__it summary::after{content:"+";font-size:1.5rem;font-weight:400;line-height:1;color:var(--cyan-deep,#6d5719);transition:transform .2s;}
.cmsfaq__it[open] summary::after{transform:rotate(45deg);}
.cmsfaq__a{padding:0 18px 16px;color:#42505f;line-height:1.6;}
.cmsquote{max-width:760px;margin-inline:auto;text-align:center;}
.cmsquote blockquote{font-family:var(--font-display,Georgia,serif);font-size:clamp(1.3rem,2.6vw,1.9rem);line-height:1.32;color:var(--navy,#38164f);margin:0;font-style:italic;}
.cmsquote blockquote::before{content:"\201C";}
.cmsquote blockquote::after{content:"\201D";}
.cmsquote figcaption{margin-top:16px;font-size:.92rem;color:var(--muted,#6d5f7b);}
.cmsquote figcaption b{color:var(--navy,#38164f);}

/* --- Universal CMS section layout modifiers (alignment / spacing / width / dark band) --- */
.cmssec--al-center{text-align:center;}
.cmssec--al-center .wrap > *{margin-inline:auto;}
.cmssec--al-right{text-align:right;}
.cmssec--compact{padding-block:clamp(28px,4vw,52px);}
.cmssec--roomy{padding-block:clamp(72px,9vw,140px);}
.cmssec--narrow .wrap{max-width:760px;}
.cmssec--wide .wrap{max-width:1240px;}
.cmssec--dark{background:var(--navy)!important;color:#e7eefb;}
.cmssec--dark h2,.cmssec--dark h3,.cmssec--dark p,.cmssec--dark li,.cmssec--dark figcaption,.cmssec--dark blockquote{color:#e7eefb;}
.cmssec--dark .eyebrow{color:#9db4e0;}
.cmssec--dark .cmsstat b,.cmssec--dark .cmsstat span{color:#fff;}
.cmssec--dark .cmsfaq__it{background:rgba(255,255,255,.06);border-color:rgba(255,255,255,.16);}
.cmssec--dark .cmsfaq__it summary{color:#fff;}
.cmssec--dark .cmsfaq__a{color:#c6d3e6;}
.cmssec--dark a:not(.btn){color:#fff;text-decoration:underline;}

/* --- Free grid positioning of a block's content (opt-in; shared by sections + header) --- */
.cmpos--free{position:relative;}
.cmpos--free > .wrap{position:absolute;left:var(--px,50%);top:var(--py,50%);transform:translate(calc(var(--px,50%) * -1),calc(var(--py,50%) * -1));margin:0;width:fit-content;max-width:100%;}
.cmpos--flow{position:relative;}
.cmpos--flow > .wrap{position:relative;left:var(--px,50%);transform:translateX(calc(var(--px,50%) * -1));width:fit-content;max-width:100%;}
.section.cmpos-mh{min-height:var(--secmh);}
.section.cmpos--free{min-height:var(--secmh,45vh);}
.cmpos--free.banner,.cmpos--free.smhero{min-height:var(--bnr-h,45vh);}
@media(max-width:640px){
  /* keep positioned content readable on phones: recentre and return to normal flow */
  .cmpos--free > .wrap,.cmpos--flow > .wrap{position:static;left:auto;top:auto;transform:none;margin-inline:auto;}
  .section.cmpos--free{min-height:0;}
}

/* =========================================================
   FORMS
   ========================================================= */
/* Full-screen image stage behind the form */
.formstage{position:relative;isolation:isolate;overflow:hidden;padding-block:clamp(64px,13vh,150px);display:grid;place-items:center;}
/* opt-in multi-step forms — one section at a time, waiver-style */
.fwiz__bar{display:none;height:6px;border-radius:100px;background:rgba(255,255,255,.18);overflow:hidden;margin-bottom:24px}
.fwiz__fill{display:block;height:100%;width:0;border-radius:inherit;background:var(--cyan);transition:width .45s var(--ease-out)}
.fwiz__nav{display:none}
.fwiz-on .fwiz__bar{display:block}
.fwiz-on .fwslide{display:none}
.fwiz-on .fwslide.is-on{display:block;animation:fwIn .4s var(--ease-out) both}
@keyframes fwIn{from{opacity:0;transform:translateX(18px)}}
.fwiz-on .fwiz__nav{display:flex;gap:10px;justify-content:space-between;margin-top:22px}
.formstage__bg{position:absolute;inset:0;z-index:-2;background-size:cover;background-position:center;}
/* Placeholder "photo" gradients — replace with a real photo via background-image */
.formstage__bg--a{background:linear-gradient(150deg,var(--charcoal),var(--navy) 60%,var(--navy));}
.formstage__bg--b{background:linear-gradient(150deg,var(--navy),var(--charcoal) 70%,var(--navy));}
.formstage__bg--c{background:linear-gradient(150deg,color-mix(in srgb,var(--navy) 78%,var(--cyan)),var(--navy));}
.formstage__bg--d{background:linear-gradient(150deg,var(--charcoal),color-mix(in srgb,var(--navy) 82%,var(--cyan)));}
.formstage__bg::after{content:"";position:absolute;inset:0;background:radial-gradient(75% 55% at 50% 0%,rgba(160,122,42,.20),transparent 60%),radial-gradient(70% 70% at 82% 100%,rgba(88,157,166,.18),transparent 60%),repeating-linear-gradient(125deg,rgba(255,255,255,.025) 0 2px,transparent 2px 26px),linear-gradient(to bottom,rgba(6,18,31,.5),rgba(6,18,31,.74));}
.formstage .wrap{width:100%;display:flex;justify-content:center;}

/* Frosted glass form card */
.form{width:100%;max-width:560px;display:grid;gap:var(--space-md);text-align:left;position:relative;color:#fff;
  background:rgba(47,33,69,.55);backdrop-filter:blur(22px) saturate(1.4);-webkit-backdrop-filter:blur(22px) saturate(1.4);
  border:1px solid rgba(255,255,255,.12);border-radius:var(--radius-card);padding:clamp(24px,4vw,46px);
  box-shadow:0 40px 90px rgba(0,0,0,.45),inset 0 1px 0 rgba(255,255,255,.10);}
.form::before{content:"";position:absolute;inset:0;border-radius:var(--radius-card);background:radial-gradient(120% 55% at 50% 0%,rgba(255,255,255,.06),transparent 60%);pointer-events:none;}
.form__badge{width:62px;height:62px;border-radius:18px;margin:0 auto 4px;display:grid;place-items:center;color:#fff;background:linear-gradient(160deg,#26354a,#38164f);box-shadow:0 0 0 1px rgba(255,255,255,.18),0 0 30px 5px rgba(180,210,255,.32),inset 0 1px 0 rgba(255,255,255,.28);}
.form__title{text-align:center;color:#fff;font-size:clamp(1.5rem,1.2rem + 1vw,2rem);}
.form__title .serif{color:var(--teal);}
.form__sub{text-align:center;color:rgba(244,238,225,.72);font-size:.95rem;margin:-2px auto 4px;max-width:42ch;line-height:1.5;}
.form .row{display:grid;grid-template-columns:1fr 1fr;gap:var(--space-md);}
.field{display:grid;gap:6px;}
.field.full{grid-column:1/-1;}
.field label{font-family:var(--font-display);font-weight:600;font-size:.82rem;color:rgba(244,238,225,.92);}
.field .req{color:var(--cyan);}
.field input,.field select,.field textarea{font:inherit;font-size:.95rem;color:#fff;background:rgba(255,255,255,.06);border:1.5px solid rgba(255,255,255,.14);border-radius:14px;padding:.85em 1em;transition:border-color .25s,box-shadow .25s,background .25s;width:100%;}
.field input::placeholder,.field textarea::placeholder{color:rgba(244,238,225,.45);}
.field select{appearance:none;-webkit-appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%23a9c0d6' stroke-width='1.6' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 1em center;padding-right:2.4em;}
.field select option{color:#38164f;}
.field textarea{min-height:128px;resize:vertical;}
.field input:focus,.field select:focus,.field textarea:focus{outline:none;border-color:var(--cyan);box-shadow:0 0 0 3px rgba(160,122,42,.3);background:rgba(255,255,255,.10);}
/* Multi-select options render as toggle pills */
.checks{display:flex;flex-wrap:wrap;gap:9px;}

/* Checkbox groups are a <fieldset>/<legend> now, so the group's question is
   announced with each option instead of floating free. The reset is because a
   browser's default fieldset border and legend indent would otherwise break
   the form's layout. */
.checkgroup{border:0;margin:0;padding:0;min-width:0;}
.checkgroup>legend{display:block;padding:0;float:left;width:100%;
  font-family:var(--font-display);font-weight:600;font-size:.82rem;
  color:rgba(244,238,225,.92);margin-bottom:6px;}
.checkgroup>legend+.checks{clear:both;}
/* Visible marker when a required group was left empty. Color is not the only
   signal — the message below it says the same thing in words. */
.checkgroup.is-bad>legend{color:#ffb4a2;}
.checkgroup.is-bad .checks{outline:2px solid rgba(255,150,130,.55);outline-offset:6px;border-radius:10px;}
.checkgroup__err{margin:9px 0 0;font-size:.82rem;font-weight:600;color:#ffb4a2;}
.checkgroup__err[hidden]{display:none;}
/* The name field's group heading is a span, not a label — it names two inputs,
   so it can't legitimately point at either. */
.namefield>.lbl{display:block;font-family:var(--font-display);font-weight:600;
  font-size:.82rem;color:rgba(244,238,225,.92);margin-bottom:6px;}
/* Announced, never shown. */
.vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0;}
.checks label{display:inline-flex;align-items:center;cursor:pointer;padding:.5em .95em;border-radius:100px;border:1.5px solid rgba(255,255,255,.26);background:rgba(255,255,255,.05);font-family:var(--font-display);font-weight:600;font-size:.86rem;color:rgba(244,238,225,.9);transition:background .2s,border-color .2s,color .2s;}
.checks label:hover{border-color:rgba(255,255,255,.5);}
.checks input{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none;}
.checks label:has(input:checked){background:var(--cyan);border-color:var(--cyan);color:#fff;}
.checks label:has(input:focus-visible){outline:2.5px solid #fff;outline-offset:2px;}
/* The consent box used to be a native checkbox wearing the text inputs' fill, and a dark
   scheme paints that as a black square with a tick nobody can see - which is what it was
   doing on the CLC newsletter. Drawn properly here instead: our own box, a clip-path tick,
   and fixed colours rather than theme tokens, because the form stage is navy in light and
   dark alike and a token that flipped would be wrong in one of them. */
.inline-check input[type=checkbox]{accent-color:var(--cyan);appearance:none;-webkit-appearance:none;
  flex:none;margin:0;padding:0;box-sizing:border-box;width:20px;height:20px;min-width:0;border-radius:6px;
  border:1.5px solid rgba(255,255,255,.45);background:rgba(255,255,255,.08);
  display:inline-grid;place-content:center;cursor:pointer;
  transition:background .15s var(--ease-out),border-color .15s var(--ease-out);}
.inline-check input[type=checkbox]:hover{border-color:rgba(255,255,255,.72);}
.inline-check input[type=checkbox]::before{content:"";width:12px;height:12px;background:#fff;
  transform:scale(0);transition:transform .16s var(--ease-out);
  clip-path:polygon(14% 44%,0 65%,50% 100%,100% 16%,80% 0%,43% 62%);}
.inline-check input[type=checkbox]:checked{background:#9b7d29;border-color:#9b7d29;}
.inline-check input[type=checkbox]:checked::before{transform:scale(1);}
.inline-check input[type=checkbox]:focus-visible{outline:2px solid #fff;outline-offset:2px;}
/* First / Last name pair */
.namefield > label{margin-bottom:2px;}
.namefield .field label.sub{font-weight:500;font-size:.78rem;color:rgba(244,238,225,.62);}
.namefield .opt{font-weight:500;color:rgba(244,238,225,.62);}
.inline-check{display:inline-flex;align-items:center;gap:10px;font-size:.9rem;color:rgba(244,238,225,.82);font-weight:500;}
.form__send{width:100%;justify-content:center;padding:1em;font-size:1rem;margin-top:4px;}
.form .hint{font-size:.8rem;color:rgba(244,238,225,.55);text-align:center;}
.hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden;}
.formnote{border-radius:14px;padding:var(--space-md) var(--space-lg);font-weight:600;}
.formnote.ok{background:rgba(88,157,166,.22);color:#d6f1ee;border:1px solid rgba(88,157,166,.5);}
.formnote.err{background:rgba(214,75,74,.18);color:#ffd9d4;border:1px solid rgba(214,75,74,.45);}
.qlist{display:grid;gap:var(--space-sm);counter-reset:q;max-width:760px;}
.qlist li{list-style:none;display:flex;gap:var(--space-md);align-items:flex-start;background:var(--paper);border:1px solid var(--line);border-radius:var(--radius);padding:var(--space-lg);}
.qlist li::before{counter-increment:q;content:counter(q);font-family:var(--font-serif);font-style:italic;font-size:1.5rem;color:var(--cyan);line-height:1;flex-shrink:0;}
.sgpray{max-width:760px;margin-inline:auto;margin-top:var(--space-lg);background:var(--navy);color:#fff;border-radius:var(--radius);padding:var(--space-lg);}

/* Small-group week: opener, then the passage, then the questions. The opener
   is a light card; the passage is set larger with a rule down its left edge so
   it reads as scripture being quoted rather than more instruction. */
.sgopen{max-width:760px;margin-inline:auto;margin-top:var(--space-md);padding:var(--space-md) var(--space-lg);
  background:color-mix(in srgb,var(--cyan,#9b7d29) 8%,transparent);
  border-radius:var(--radius);}
.sgopen p:last-child{margin:4px 0 0;color:var(--ink,#38164f);}

/* The passage is a reference — book and chapter — so it's set like a heading
   somebody turns to, not a block quote of the verses. */
.sgref{max-width:760px;margin-inline:auto;margin-top:var(--space-lg);}
.sgref__b{margin-top:4px;font-family:var(--font-display,"Hanken Grotesk",sans-serif);
  font-size:clamp(1.25rem,1.05rem + .8vw,1.7rem);font-weight:700;line-height:1.2;
  color:var(--ink,#38164f);}
.sgref__b a{color:inherit;text-decoration:none;
  border-bottom:2px solid color-mix(in srgb,var(--cyan,#9b7d29) 45%,transparent);
  transition:border-color .16s,color .16s;}
.sgref__b a:hover{color:var(--cyan,#9b7d29);border-bottom-color:currentColor;}

/* The Sunday these questions belong to, sitting under the passage. */
.sgdate{margin-top:8px;font-size:.9rem;font-weight:600;letter-spacing:.02em;
  color:var(--muted);}
.head.center .sgdate{text-align:center;}

/* Questions folded away until asked for. A <details>, so it opens with a tap
   or the keyboard and needs no JavaScript. */
.sgcard{max-width:760px;margin-inline:auto;margin-top:var(--space-lg);border-radius:var(--radius);
  background:var(--card,#fff);
  border:1px solid color-mix(in srgb,var(--ink,#38164f) 11%,transparent);
  box-shadow:0 10px 30px -20px rgba(47,33,69,.35);
  overflow:hidden;transition:border-color .18s,box-shadow .18s;}
.sgcard[open]{border-color:color-mix(in srgb,var(--cyan,#9b7d29) 32%,transparent);
  box-shadow:0 16px 40px -22px rgba(47,33,69,.45);}

.sgcard__sum{display:flex;align-items:center;justify-content:space-between;gap:var(--space-md);
  padding:var(--space-md) var(--space-lg);cursor:pointer;list-style:none;
  -webkit-tap-highlight-color:transparent;}
.sgcard__sum::-webkit-details-marker{display:none;}
.sgcard__sum:hover{background:color-mix(in srgb,var(--cyan,#9b7d29) 5%,transparent);}
.sgcard__sum:focus-visible{outline:2.5px solid var(--cyan,#9b7d29);outline-offset:-3px;}

.sgcard__t{display:flex;flex-direction:column;gap:2px;min-width:0;}
.sgcard__lab{font-family:var(--font-display,"Hanken Grotesk",sans-serif);font-weight:700;
  font-size:.72rem;letter-spacing:.16em;text-transform:uppercase;color:var(--cyan,#9b7d29);}
.sgcard__n{font-size:1.02rem;font-weight:600;color:var(--ink,#38164f);}

.sgcard__btn{flex:none;display:inline-flex;align-items:center;gap:7px;
  font-family:var(--font-display,"Hanken Grotesk",sans-serif);font-weight:700;font-size:.85rem;
  color:var(--cyan,#9b7d29);padding:.5em .9em;border-radius:100px;
  background:color-mix(in srgb,var(--cyan,#9b7d29) 10%,transparent);}

/* The week's questions as a sheet of paper. The link sits beside the open/close
   control rather than inside the card, because whoever wants them printed tends
   to know that before they have read a word of them. Outlined rather than
   filled, so it never competes with the control that actually opens the card. */
.sgcard__acts{flex:none;display:inline-flex;align-items:center;gap:8px;}
.sgcard__dl{flex:none;display:inline-flex;align-items:center;gap:6px;
  font-family:var(--font-display,"Hanken Grotesk",sans-serif);font-weight:700;font-size:.85rem;
  color:var(--ink-soft,#38164f);text-decoration:none;
  padding:.5em .9em;border-radius:100px;
  border:1px solid color-mix(in srgb,var(--ink,#38164f) 17%,transparent);
  transition:color .18s,border-color .18s,background-color .18s;}
.sgcard__dl:hover{color:var(--cyan,#9b7d29);
  border-color:color-mix(in srgb,var(--cyan,#9b7d29) 45%,transparent);
  background:color-mix(in srgb,var(--cyan,#9b7d29) 7%,transparent);}
.sgcard__dl:focus-visible{outline:2.5px solid var(--cyan,#9b7d29);outline-offset:2px;}
.sgcard__dl svg{flex:none;transition:transform .3s var(--ae-spring,cubic-bezier(.22,1.14,.36,1));}
.sgcard__dl:hover svg{transform:translateY(2px);}
@media(prefers-reduced-motion:reduce){.sgcard__dl:hover svg{transform:none;}}
/* Only one of the two labels is ever shown, so the button reads correctly in
   both states without any script. */
.sgcard__hide{display:none;}
.sgcard[open] .sgcard__show{display:none;}
.sgcard[open] .sgcard__hide{display:inline;}
.sgcard__chev{transition:transform .42s var(--ae-spring,cubic-bezier(.22,1.14,.36,1));}
.sgcard[open] .sgcard__chev{transform:rotate(180deg);}

.sgcard__list{transform-origin:50% 0;margin:0;padding:0 var(--space-lg) var(--space-lg);
  border-top:1px solid color-mix(in srgb,var(--ink,#38164f) 8%,transparent);
  padding-top:var(--space-md);}
.sgcard[open] .sgcard__list{animation:sgOpen .5s var(--ae-spring,cubic-bezier(.22,1.14,.36,1)) both;}
/* A little overshoot on the way in — the house spring, not the classic back-ease
   that draws attention to itself. transform-origin at the top so it unfolds
   from the summary rather than growing out of its own middle. */
@keyframes sgOpen{
  0%  {opacity:0;transform:translateY(-10px) scaleY(.97);}
  60% {opacity:1;}
  100%{opacity:1;transform:none;}
}

/* The Small Groups variant holds the whole week — title, opener, passage,
   questions and prayer — behind one button, rather than only the questions. */
.sgcard--week .sgcard__n{font-family:var(--font-display,"Hanken Grotesk",sans-serif);
  font-size:1.2rem;font-weight:700;line-height:1.25;overflow-wrap:anywhere;}
.sgcard__meta{font-size:.86rem;color:var(--muted);margin-top:3px;}
.sgcard__body{transform-origin:50% 0;padding:0 var(--space-lg) var(--space-lg);
  border-top:1px solid color-mix(in srgb,var(--ink,#38164f) 8%,transparent);
  padding-top:var(--space-md);}
.sgcard[open] .sgcard__body{animation:sgOpen .5s var(--ae-spring,cubic-bezier(.22,1.14,.36,1)) both;}
/* Inside the card these sit flush — their own outer margins would double up. */
.sgcard__body .sgopen,
.sgcard__body .sgref,
.sgcard__body .sgpray{max-width:none;}
.sgcard__body .sgopen{margin-top:0;}
.sgcard__body .qlist{margin-top:6px;}
.sgcard__qlab{margin-top:var(--space-lg);}
.sgcard__more{margin-top:var(--space-lg);font-size:.9rem;font-weight:600;}
.sgcard__more a{color:var(--cyan,#9b7d29);text-decoration:none;}
.sgcard__more a:hover{text-decoration:underline;}

@media(max-width:560px){
  .sgcard__sum{flex-direction:column;align-items:flex-start;gap:10px;}
  .sgcard__acts{align-self:stretch;width:100%;}
  .sgcard__btn{flex:1 1 auto;align-self:stretch;justify-content:center;}
  .sgcard__dl{flex:none;}
  .sgcard__body{padding-left:var(--space-md);padding-right:var(--space-md);}
}
@media(prefers-reduced-motion:reduce){
  .sgcard[open] .sgcard__body{animation:none;}
}
/* The card's own height springs open too, where the browser can do it.
   A <details> normally snaps to full height and only the contents can be
   animated, which reads as a jump with a fade after it. interpolate-size lets
   height animate to and from `auto`, so the card unfolds. Everywhere else this
   block is simply ignored and the content animation above carries it. */
@supports (interpolate-size: allow-keywords){
  .sgcard{interpolate-size:allow-keywords;}
  .sgcard::details-content{
    block-size:0;overflow:hidden;
    transition:block-size .5s var(--ae-spring,cubic-bezier(.22,1.14,.36,1)),
               content-visibility .5s allow-discrete;}
  .sgcard[open]::details-content{block-size:auto;}
}

/* The questions arrive just behind the card, a few milliseconds apart, so the
   list settles rather than appearing all at once. */
.sgcard[open] .sgcard__list li{animation:sgQIn .42s var(--ae-spring,cubic-bezier(.22,1.14,.36,1)) both;}
.sgcard[open] .sgcard__list li:nth-child(1){animation-delay:.06s}
.sgcard[open] .sgcard__list li:nth-child(2){animation-delay:.10s}
.sgcard[open] .sgcard__list li:nth-child(3){animation-delay:.14s}
.sgcard[open] .sgcard__list li:nth-child(4){animation-delay:.18s}
.sgcard[open] .sgcard__list li:nth-child(5){animation-delay:.22s}
.sgcard[open] .sgcard__list li:nth-child(6){animation-delay:.26s}
.sgcard[open] .sgcard__list li:nth-child(n+7){animation-delay:.3s}
@keyframes sgQIn{from{opacity:0;transform:translateY(7px);}to{opacity:1;transform:none;}}

@media(prefers-reduced-motion:reduce){
  .sgcard__chev{transition:none;}
  .sgcard[open] .sgcard__list{animation:none;}
  .sgcard[open] .sgcard__list li{animation:none;}
  @supports (interpolate-size: allow-keywords){
    .sgcard::details-content{transition:none;}
  }
}
@media(max-width:600px){
  .sgtext__b{font-size:1rem;padding-left:var(--space-sm);}
}
.sgpray .eyebrow{color:var(--cyan);margin-bottom:6px;}
.sgpray p:last-child{margin:0;color:rgba(255,255,255,.9);line-height:1.6;}

/* Announcements — the church's news at the end of a small group evening.
   Deliberately not styled like the study sections above it: those are navy and
   full-bleed because they carry the evening, and this is a notice board. A
   quiet bordered card reads as "one more thing" rather than as a sixth part of
   the study. */
.sgann{max-width:760px;margin:clamp(26px,4vw,40px) auto 0;padding:clamp(20px,3vw,28px);
  background:color-mix(in srgb,var(--cyan) 5%,var(--cream));border:1px solid color-mix(in srgb,var(--cyan) 24%,var(--line));
  border-radius:var(--radius);}
.sgann .eyebrow{margin-bottom:10px;}
.sgann p{margin:0;color:var(--ink-soft);line-height:1.65;}
.sgann__l{margin:0;padding-left:1.15em;display:grid;gap:8px;color:var(--ink-soft);line-height:1.55;}
.sgann__l li::marker{color:var(--cyan-deep);}

/* ------------------------------------------------- an event on a ministry card
   A quiet strip at the foot of a card, only ever present when something is
   actually on. It reads as a footnote to the card rather than competing with
   the heading, because the card's job is still to describe the ministry — the
   event is the extra. */
.cardev{display:flex;flex-wrap:wrap;align-items:baseline;gap:.15em .6em;margin-top:14px;
  padding-top:12px;border-top:1px solid var(--line);text-decoration:none;color:inherit;}
.cardev__k{flex:0 0 100%;font-size:.66rem;font-weight:700;letter-spacing:.18em;
  text-transform:uppercase;color:var(--cyan-deep);}
/* secondary nudge inside the "Coming up" label - lighter and tighter so it
   reads as a hint rather than a second heading */
.cardev__hint{font-weight:600;letter-spacing:.09em;color:var(--muted);}
.cardev:hover .cardev__hint{color:var(--cyan-deep);}
.cardev__t{font-family:var(--font-display);font-weight:700;font-size:.95rem;color:var(--ink);
  line-height:1.3;}
.cardev__d{font-size:.85rem;color:var(--muted);font-variant-numeric:tabular-nums;white-space:nowrap;}
.cardev:hover .cardev__t{color:var(--cyan-deep);text-decoration:underline;text-underline-offset:2px;}
.cardev:focus-visible{outline:2.5px solid var(--cyan);outline-offset:3px;border-radius:6px;}

/* Community Life Center (staff page) */
.footer__clc{color:inherit;text-decoration:underline;text-underline-offset:2px;}

/* --- appearance switch ------------------------------------------------------
   The footer is navy in both schemes, so this is coloured against the footer
   rather than against the page. Theme tokens would invert underneath it and
   put near-black type on near-black - the literals here are the same literals
   the rest of the footer already uses, and for the same reason.

   Sized off the label rather than the text: the input covers the whole pill,
   so the target is the pill, not the four letters inside it. */
/* One pill that slides, rather than three that cross-fade. The highlight is a single
   ::before on the track and the choice only moves it, which is the honest picture of what
   the control is: one setting with three positions, not three independent buttons. The
   three columns are made equal so the travel is exact arithmetic and needs no measuring
   in script. :has() reads the checked radio, so nothing has to be told when it changes -
   keyboard, click and a value restored from storage all land the same way. */
.fsch{position:relative;display:inline-grid;grid-template-columns:repeat(3,1fr);align-items:center;gap:2px;padding:3px;border-radius:100px;
  border:1px solid rgba(244,238,225,.22);background:rgba(0,0,0,.18);}
.fsch::before{content:"";position:absolute;top:3px;left:3px;z-index:0;
  width:calc((100% - 10px) / 3);height:calc(100% - 6px);border-radius:100px;background:#f4eee1;
  transform:translateX(calc(var(--i,0) * (100% + 2px)));
  transition:transform .34s var(--ease-out),background .2s var(--ease-out);}
.fsch:has(input[value="light"]:checked){--i:0;}
.fsch:has(input[value="dark"]:checked){--i:1;}
.fsch:has(input[value="auto"]:checked){--i:2;}
.fsch:has(.fsch__o:hover input:checked)::before{background:#fff;}
.fsch__o{position:relative;z-index:1;display:inline-flex;}
.fsch__o input{position:absolute;inset:0;width:100%;height:100%;margin:0;opacity:0;cursor:pointer;}
.fsch__o span{display:inline-flex;align-items:center;justify-content:center;width:100%;
  min-height:40px;padding:0 1em;border-radius:100px;
  font-size:.82rem;font-weight:600;line-height:1;white-space:nowrap;
  color:rgba(244,238,225,.86);
  transition:background .22s var(--ease-out),color .22s var(--ease-out);}
.fsch__o:hover input:not(:checked)+span{color:#fff;background:rgba(244,238,225,.12);}
.fsch__o input:focus-visible+span{outline:2px solid var(--footer-head);outline-offset:3px;}
.fsch__o input:checked+span{color:#38164f;}
/* Without :has() there is no track to slide, so the old fill comes back and nothing is lost. */
@supports not (selector(:has(*))){
  .fsch::before{display:none;}
  .fsch__o input:checked+span{background:#f4eee1;}
}
@media (prefers-reduced-motion:reduce){.fsch__o span{transition:none;}}

.footer__clc:hover{opacity:1;}
.clcgate{max-width:420px;margin:0 auto;background:var(--card,#fff);border:1px solid var(--line);border-radius:var(--radius-lg);box-shadow:0 14px 40px rgba(47,33,69,.08);padding:clamp(26px,5vw,40px);text-align:center;}
.clcgate h2{font-size:clamp(1.5rem,1.2rem + 1.4vw,2rem);margin-bottom:8px;}
.clcgate p{color:var(--ink-soft);margin-bottom:20px;}
.clcgate form{display:grid;gap:12px;}
.clcgate input{width:100%;padding:.85em 1em;border:1.5px solid var(--line);border-radius:12px;font:inherit;text-align:center;letter-spacing:.08em;}
.clcgate input:focus{outline:none;border-color:var(--cyan);}
.clcgate__err{background:#fdecea;color:#c0392b;border-radius:10px;padding:.6em;font-size:.9rem;}
.clc__signout{margin-top:22px;font-size:.88rem;}
.clc__signout a{color:var(--muted);text-decoration:underline;text-underline-offset:2px;}

/* =========================================================================
   CLC volunteer schedule
   -------------------------------------------------------------------------
   Two ways to read the same rotation. The week list is what somebody standing
   at the desk on a phone wants — today first, big enough to read at arm's
   length. The month grid is the wall calendar, and is also what prints.

   Both are built from the same markup so the print rules below only have to
   understand one shape.
   ========================================================================= */



/* ===========================================================
   Community Life Center, on the Serve page
   ---------------------------------------------------------------------------
   The gym desk is the one thing on this page somebody can act on the same
   minute they read about it, so it sits above the two 'here are the sorts of
   things people do here' columns rather than under them.

   A panel and not another full-width band: the page already ends on a navy
   one, and two slabs in a row stop reading as emphasis and start reading as
   wallpaper. The cyan wash is mixed into --card, so the dark scheme gets a
   deep tinted panel from the same line without a second rule.

   Two doors, because there are two people standing at it: somebody already on
   the rota who wants the week, and somebody who has never done it and needs a
   human. The first would hit the passcode screen and think they'd been turned
   away if the second were the only way through. */
.clcpitch{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-lg);
  padding:var(--space-lg) clamp(20px,3.5vw,34px);border-radius:var(--radius);
  background:color-mix(in srgb,var(--cyan) 7%,var(--card,#fff));
  border:1px solid color-mix(in srgb,var(--cyan) 22%,transparent);
  margin-bottom:var(--space-2xl);}
.clcpitch__tx{flex:1 1 320px;min-width:0;}
.clcpitch__tx h2{margin:2px 0 8px;}
.clcpitch__tx p:last-child{margin:0;color:var(--ink-soft);max-width:52ch;}
.clcpitch__go{flex:0 0 auto;display:flex;flex-wrap:wrap;gap:10px;}
@media(max-width:640px){
  .clcpitch__go{width:100%;}
  .clcpitch__go .btn{flex:1 1 100%;justify-content:center;}
}



/* ===========================================================
   The Community Life Center month, on the public page
   ---------------------------------------------------------------------------
   A wall calendar on a laptop and a list of days on a phone. Seven columns of
   booking names at 390px is not a calendar, it is a wall — so below 640 the
   grid stops being a grid and becomes what it was always describing: the days
   that have something on, in order. Empty days drop out entirely; on a rota
   that is mostly evenings, a screenful of blanks is not information.

   Surfaces come from --card so the whole thing follows the scheme without a
   second set of rules underneath. */


/* Upcoming community engagement. A list, not cards: these are six lines of
   fact — what, when, where — and six boxes around six lines of fact is
   packaging, not design. The date sits in its own column so the eye can run
   down it and stop at the one that suits. */
/* Opening hours. A short list with a live status line, and it sits above the
   calendar because "are you open now" is the question somebody arrives with;
   the month is what they read second. The status is worked out on the server
   from the same numbers the list prints, so the two cannot drift apart. */

/* The gym chips carry a time as well as a name, which is the whole reason
   this calendar exists — so unlike the ones on /calendar they are allowed
   two lines rather than being cut off mid-word. Everything else about the
   chip is the site's own. */
.cal--clc .cal__ev--clc{white-space:normal;line-height:1.25;padding-top:5px;padding-bottom:5px;}
.cal--clc .cal__ev--clc b{display:block;font-weight:800;font-variant-numeric:tabular-nums;}

/* The opening hours, printed on every day that has any, as the first chip in the cell.
   Deliberately not styled like a booking: a quieter fill and the body ink rather than the
   cyan the activities use, so "1–7pm" reads as the state of the building and not as
   another thing on. Sundays get none, which is the honest answer for a Sunday. */
.cal--clc .cal__ev--hrs{background:color-mix(in srgb,var(--ink) 7%,transparent);color:var(--muted);font-weight:700;}
.dot--hrs{background:color-mix(in srgb,var(--ink) 22%,var(--paper));}

/* The day panel. The dialog itself is the site's own - .caldial, the same one /calendar
   opens - so all that is new here is what sits inside it and how it arrives. The rows
   stagger in 45ms apart, starting 70ms after the box, which is short enough that the last
   line has landed before the box has finished settling: it reads as one movement rather
   than a panel and then a list. Transform and opacity only, so it composites, and the
   sitewide prefers-reduced-motion reset already flattens all of it to nothing. */
.clcdial__hrs{margin:0 0 var(--space-md);font-weight:800;font-size:.9rem;}
.clcdial__hrs.is-open{color:var(--cyan-deep);}
.clcdial__hrs.is-shut{color:var(--muted);}
.clcdial__none{margin:0;color:var(--muted);}
.clcday{display:flex;align-items:baseline;gap:.75em;padding:.6em .85em;border-radius:12px;background:color-mix(in srgb,var(--cyan) 12%,transparent);}
.clcday__t{flex:none;font-weight:800;font-variant-numeric:tabular-nums;font-size:.92rem;color:var(--cyan-deep);}
.clcday__n{color:var(--ink);font-weight:600;}
.caldial--clc.is-open .clcday,.caldial--clc.is-open .clcdial__none{animation:clcdayin .34s var(--ease-out) backwards;}
@keyframes clcdayin{from{opacity:0;transform:translateY(9px);}to{opacity:1;transform:none;}}
/* Out at about 70% of the way in, so dismissing feels like a decision and not a wait.
   The script hides the dialog at 200ms, which lands just after this finishes. */
.caldial--clc:not(.is-open) .caldial__box,.caldial--clc:not(.is-open) .caldial__backdrop{transition-duration:.18s;}
.cal--clc .cal__cell[data-day]:focus-visible{outline:2px solid var(--cyan);outline-offset:2px;}

/* On a phone each day is about 43px across, which will not hold a time and an activity
   stacked. Rather than invent a second layout for this one page, the chips fold to a
   single line and clip exactly as /calendar's do; the hours chip above them carries the
   when. The full string stays in the title attribute for anything reading the markup. */
@media(max-width:620px){
  .cal--clc .cal__ev--clc{white-space:nowrap;padding-top:4px;padding-bottom:4px;}
  .cal--clc .cal__ev--clc b{display:none;}
}
.clchrs{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-md) var(--space-xl);
  padding:var(--space-md) clamp(16px,3vw,26px);border-radius:var(--radius);
  background:color-mix(in srgb,var(--cyan) 6%,var(--card,#fff));
  border:1px solid color-mix(in srgb,var(--cyan) 20%,transparent);}
.clchrs__head{display:flex;align-items:center;gap:.7em;flex:none;}
.clchrs__now{display:inline-flex;align-items:center;gap:.45em;font-size:.76rem;font-weight:800;
  letter-spacing:.06em;text-transform:uppercase;color:var(--muted);}
.clchrs__now::before{content:"";width:8px;height:8px;border-radius:50%;background:currentColor;flex:none;}
.clchrs__now.is-open{color:#1c7a46;}
html.dark .clchrs__now.is-open{color:#6ddba0;}
.clchrs__l{display:flex;flex-wrap:wrap;gap:var(--space-sm) var(--space-xl);margin:0;}
.clchrs__l div{display:flex;align-items:baseline;gap:.6em;}
.clchrs__l dt{font-weight:700;font-size:.94rem;}
.clchrs__l dd{margin:0;font-size:.94rem;color:var(--ink-soft);font-variant-numeric:tabular-nums;}
@media(max-width:560px){
  .clchrs{flex-direction:column;align-items:flex-start;gap:var(--space-sm);}
  .clchrs__l{flex-direction:column;gap:5px;}
}

.ceev{list-style:none;margin:var(--space-lg) 0 0;padding:0;display:grid;gap:1px;
  background:var(--line);border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;}
.ceev__i{display:flex;align-items:center;gap:var(--space-md);padding:14px 16px;background:var(--card,#fff);}
.ceev__d{flex:none;width:3.1em;text-align:center;line-height:1;}
.ceev__d b{display:block;font-family:var(--font-display);font-weight:800;font-size:1.32rem;
  letter-spacing:-.02em;font-variant-numeric:tabular-nums;}
.ceev__d span{display:block;margin-top:2px;font-size:.62rem;font-weight:800;
  letter-spacing:.14em;text-transform:uppercase;color:var(--cyan-deep);}
.ceev__x{display:grid;gap:2px;min-width:0;}
.ceev__x b{font-weight:700;font-size:1.02rem;line-height:1.3;}
.ceev__m{font-size:.85rem;color:var(--muted);line-height:1.35;}
@media(max-width:520px){
  .ceev__i{gap:var(--space-sm);padding:13px 14px;}
  .ceev__x b{font-size:.96rem;}
}

.clcal__bar{display:flex;flex-wrap:wrap;align-items:baseline;gap:10px;margin-bottom:var(--space-md);}
.clcal__label{font-family:var(--font-display);font-weight:800;letter-spacing:-.02em;
  font-size:clamp(1.2rem,1rem + .8vw,1.55rem);margin-right:auto;}
.clcal__note{font-size:.84rem;color:var(--muted);}

.clcal__grid{display:grid;grid-template-columns:repeat(7,1fr);gap:1px;
  background:var(--line);border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;}
.clcal__dow{background:var(--cream);padding:8px 6px;text-align:center;
  font-size:.66rem;font-weight:800;letter-spacing:.14em;text-transform:uppercase;color:var(--muted);}
.clcal__cell{background:var(--card,#fff);min-height:106px;padding:7px 8px;}
.clcal__cell.is-out{background:color-mix(in srgb,var(--ink) 4%,var(--card,#fff));}
/* A day already gone is not the same as a day with nothing on it. Same
   treatment as a day from the month either side — present, countable, and
   plainly behind you. */
.clcal__cell.is-past{background:color-mix(in srgb,var(--ink) 4%,var(--card,#fff));}
.clcal__cell.is-past .clcal__n{color:var(--muted);opacity:.55;}
.clcal__cell.is-today{background:color-mix(in srgb,var(--cyan) 9%,var(--card,#fff));}
.clcal__n{font-family:var(--font-display);font-weight:800;font-size:.9rem;line-height:1;
  margin-bottom:6px;font-variant-numeric:tabular-nums;}
.clcal__cell.is-out .clcal__n{color:var(--muted);opacity:.55;}
.clcal__cell.is-today .clcal__n{color:var(--cyan-deep);}
.clcal__dl{display:none;}
.clcal__it{font-size:.72rem;line-height:1.3;margin-bottom:5px;}
.clcal__it:last-child{margin-bottom:0;}
.clcal__t{display:block;font-weight:700;color:var(--cyan-deep);font-variant-numeric:tabular-nums;}
.clcal__w{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.clcal__empty{padding:var(--space-lg);text-align:center;color:var(--muted);
  background:var(--card,#fff);border:1px solid var(--line);border-radius:var(--radius);}

@media(max-width:900px){ .clcal__cell{min-height:90px;} .clcal__it{font-size:.68rem;} }

@media screen and (max-width:640px){
  .clcal__grid{display:block;background:none;border:0;border-radius:0;overflow:visible;}
  .clcal__dow{display:none;}
  .clcal__cell{display:none;}
  .clcal__cell.has-on{display:block;min-height:0;padding:11px 13px;margin-bottom:8px;
    border:1px solid var(--line);border-radius:14px;box-shadow:var(--shadow-sm);}
  .clcal__cell.is-out{display:none;}
  .clcal__cell.is-today{border-color:var(--cyan);
    box-shadow:0 0 0 2px color-mix(in srgb,var(--cyan) 22%,transparent);}
  .clcal__n{display:flex;align-items:baseline;gap:.5em;font-size:.92rem;
    margin-bottom:8px;padding-bottom:7px;border-bottom:1px solid var(--line);}
  .clcal__n>span:first-child{display:none;}   /* the bare number; the row says the date in full */
  .clcal__dl{display:inline;}
  .clcal__it{display:grid;grid-template-columns:5.6em 1fr;gap:10px;font-size:.86rem;margin-bottom:6px;}
  .clcal__w{white-space:normal;overflow:visible;text-overflow:clip;}
}

.vsch__bar{display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin-bottom:18px;}
.vsch__title{font-family:var(--font-display);font-weight:800;font-size:clamp(1.3rem,1.1rem + .9vw,1.8rem);letter-spacing:-.02em;margin-right:auto;}
.vsch__title em{font-family:var(--font-serif);font-style:italic;font-weight:400;color:var(--cyan-deep);}
.vsch__nav{display:flex;align-items:center;gap:4px;}
.vsch__nav a,.vsch__btn{display:inline-flex;align-items:center;justify-content:center;gap:.4em;
  min-height:42px;padding:0 .95em;border-radius:100px;border:1.5px solid var(--line);background:var(--card,#fff);
  color:var(--ink);font:inherit;font-size:.9rem;font-weight:600;cursor:pointer;text-decoration:none;
  transition:border-color .18s,color .18s,background .18s;}
.vsch__nav a:hover,.vsch__btn:hover{border-color:var(--cyan);color:var(--cyan-deep);}
.vsch__btn.is-on{background:var(--navy);border-color:var(--navy);color:#fff;}

/* --- dark: the CLC volunteer schedule -------------------------------------
   The surfaces above draw on --card now, so most of this page follows the
   scheme on its own. What is left is the handful of colours that only make
   sense one way round: a selected pill that would otherwise be navy on navy,
   a dashed blank drawn in navy, and an error chip mixed for white paper. */
html.dark .vsch__btn.is-on{
  background:var(--cyan-deep);
  border-color:var(--cyan-deep);
  color:#190b25;
}
html.dark .vopen__d{
  border-bottom-color:color-mix(in srgb,var(--ink) 26%,transparent);
}
html.dark .clcgate__err{
  background:#3a1512;
  color:#ffb3aa;
}
/* A past day is dimmed rather than hidden. On white .6 still leaves a name
   legible; on a deep card it does not, so the dark scheme dims less. */
html.dark .vday.is-past{opacity:.72;}

.vsch__arrow{min-width:42px;padding:0;font-size:1.1rem;}

/* Week A / Week B. Which half of the rotation a week belongs to is the single
   most confusing thing about a fortnightly rota, so it is stated rather than
   implied, everywhere a week appears. */
.vsch__cyc{display:inline-flex;align-items:center;gap:.4em;padding:.3em .8em;border-radius:100px;
  background:color-mix(in srgb,var(--cyan) 12%,var(--snow));color:var(--cyan-deep);
  font-size:.72rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase;}

/* ---- the week list ---- */
.vsch__days{display:grid;gap:12px;}
.vday{background:var(--card,#fff);border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;}
.vday.is-today{border-color:var(--cyan);box-shadow:0 0 0 3px color-mix(in srgb,var(--cyan) 16%,transparent);}
.vday.is-past{opacity:.6;}
/* The hairline between the week ahead and the week behind. It only ever
   prints when both halves exist, so it never labels an empty stretch. */
.vday__earlier{margin:var(--space-sm) 0 -2px;font-size:.7rem;font-weight:800;
  letter-spacing:.12em;text-transform:uppercase;color:var(--muted);}

.vday__h{display:flex;align-items:baseline;gap:.6em;padding:12px 16px;background:var(--cream);border-bottom:1px solid var(--line);}
.vday__dow{font-family:var(--font-display);font-weight:800;font-size:1.02rem;letter-spacing:-.01em;}
.vday__date{color:var(--muted);font-size:.86rem;font-weight:600;}
.vday__flag{margin-left:auto;font-size:.74rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--cyan-deep);}
.vday__empty{padding:14px 16px;color:var(--muted);font-size:.9rem;}

.vshift{display:grid;grid-template-columns:5.6em 1fr;gap:10px;padding:11px 16px;border-top:1px solid var(--line);}
.vshift:first-child{border-top:none;}
.vshift__t{font-family:var(--font-display);font-weight:700;font-size:.86rem;color:var(--cyan-deep);
  font-variant-numeric:tabular-nums;padding-top:.15em;}
.vshift__who{display:grid;gap:6px;min-width:0;}
.vname{display:flex;align-items:center;gap:.5em;font-weight:600;font-size:.98rem;min-width:0;}
.vname__x{font-size:.72rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  color:var(--cyan-deep);background:color-mix(in srgb,var(--cyan) 13%,var(--snow));
  padding:.15em .55em;border-radius:100px;flex:none;}
.vname--was{color:var(--muted);font-weight:500;font-size:.84rem;text-decoration:line-through;}
/* An unfilled slot has to look like a gap, not like a blank. It is the one
   thing on this page anybody is being asked to do something about. */
.vopen{display:flex;align-items:center;gap:.5em;font-size:.92rem;color:var(--muted);}
.vopen__d{flex:1;border-bottom:1.5px dashed color-mix(in srgb,var(--navy) 28%,var(--snow));}
.vclaim{border:1.5px solid var(--cyan);background:var(--card,#fff);color:var(--cyan-deep);border-radius:100px;
  padding:.35em 1em;font:inherit;font-size:.84rem;font-weight:700;cursor:pointer;flex:none;min-height:34px;}
.vclaim:hover{background:var(--cyan);color:#fff;}

/* ---- the month grid ---- */
.vmon{width:100%;border-collapse:collapse;table-layout:fixed;background:var(--card,#fff);
  border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;}
.vmon th{background:var(--cream);border-bottom:1px solid var(--line);padding:9px 6px;
  font-size:.7rem;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:var(--muted);}
.vmon td{border:1px solid var(--line);vertical-align:top;padding:6px 7px;height:112px;width:14.28%;}
.vmon td.is-out{background:color-mix(in srgb,var(--navy) 3%,var(--snow));}
.vmon td.is-today{background:color-mix(in srgb,var(--cyan) 8%,var(--snow));}
.vmon__n{font-family:var(--font-display);font-weight:800;font-size:.94rem;line-height:1;
  margin-bottom:5px;font-variant-numeric:tabular-nums;
  display:flex;align-items:baseline;justify-content:space-between;gap:6px;}
/* Week A / Week B, printed in the row's Sunday cell. Needs its own screen rule
   as well as the print one — without it the badge sits flush against the date
   number and reads as "26Week A". */
.vmon__dow{display:none;}
.vmon__wk{font-family:var(--font-body);font-size:.6rem;font-weight:700;letter-spacing:.1em;
  text-transform:uppercase;color:var(--cyan-deep);white-space:nowrap;}
.vmon td.is-out .vmon__n{color:var(--muted);opacity:.6;}
.vmon td.is-today .vmon__n{color:var(--cyan-deep);}
.vmon__s{display:grid;grid-template-columns:3.3em 1fr;gap:5px;margin-bottom:3px;font-size:.72rem;line-height:1.25;}
.vmon__t{font-weight:700;color:var(--cyan-deep);font-variant-numeric:tabular-nums;}
.vmon__p{min-width:0;}
.vmon__p span{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.vmon__p .is-open{color:var(--muted);font-style:italic;}
.vmon__p .is-chg{font-weight:700;color:var(--cyan-deep);}

/* ---- roster ---- */
/* The desk list is four rosters now — volunteers, substitutes, callers, prayer
   team — so each one gets a heading and its own table rather than one long run
   of names where the only clue to somebody's job was where they happened to sit. */
.vroster__h{margin:var(--space-lg) 0 var(--space-2xs);font-size:.7rem;font-weight:800;
  letter-spacing:.12em;text-transform:uppercase;color:var(--muted);
  display:flex;align-items:baseline;gap:.5em}
.vroster__h:first-of-type{margin-top:var(--space-sm)}
.vroster__h span{font-weight:700;letter-spacing:0;font-size:.72rem;
  color:var(--muted);opacity:.6;font-variant-numeric:tabular-nums}
.vroster + .vroster__h{margin-top:var(--space-xl)}
.vroster{width:100%;border-collapse:collapse;background:var(--card,#fff);border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;}
.vroster th{background:var(--cream);text-align:left;padding:10px 12px;font-size:.72rem;letter-spacing:.12em;text-transform:uppercase;color:var(--muted);border-bottom:1px solid var(--line);}
.vroster td{padding:10px 12px;border-top:1px solid var(--line);font-size:.94rem;}
.vroster td a{color:var(--cyan-deep);}
.vroster tr:first-child td{border-top:none;}

.vsch__legend{display:flex;flex-wrap:wrap;gap:14px;margin-top:14px;font-size:.82rem;color:var(--muted);}
.vsch__legend span{display:inline-flex;align-items:center;gap:.45em;}
.vsch__key{width:14px;height:14px;border-radius:4px;flex:none;}

@media(max-width:900px){
  .vmon td{height:auto;min-height:76px;}
  .vmon__s{grid-template-columns:3em 1fr;font-size:.66rem;}
}
@media(max-width:640px){
  .vsch__title{width:100%;margin-right:0;}
}

/* -- the month, on a phone ------------------------------------------------
   Seven columns of names at this width is unreadable, so the grid stops being
   a grid and becomes what it was always describing: a list of days, in order.
   Days with nothing on drop out — on a rota that is mostly Sundays, and a
   screenful of blanks is not information.

   Scoped to `screen`. The print sheet lays the month out at letter landscape,
   which is far wider than this, but an unscoped max-width query still applies
   to print on some engines and would quietly turn the wall calendar into a
   list. */
@media screen and (max-width:640px){
  .vmon{border-collapse:separate;border-spacing:0;table-layout:auto;background:none;
    border:0;box-shadow:none;}
  .vmon thead{display:none;}
  .vmon tbody,.vmon tr{display:contents;}
  .vmon td{display:none;}                       /* the empty ones, and the padding cells */
  .vmon td.has-on{display:block;width:auto;height:auto;min-height:0;
    border:1px solid var(--line);border-radius:14px;background:var(--card,#fff);
    padding:11px 13px;margin-bottom:8px;box-shadow:var(--shadow-sm);}
  .vmon td.is-out{opacity:.62;}                 /* a day from the month either side */
  .vmon td.is-today{border-color:var(--cyan);box-shadow:0 0 0 2px color-mix(in srgb,var(--cyan) 22%,transparent);}
  .vmon__n{display:flex;align-items:baseline;gap:.5em;font-size:.9rem;margin-bottom:7px;
    padding-bottom:6px;border-bottom:1px solid var(--line);}
  .vmon__n>span:first-child{display:none;}      /* the bare number; the list says the date in full */
  .vmon__dow{display:inline;font-family:var(--font-display);font-weight:800;
    letter-spacing:-.01em;color:var(--ink-strong);}
  .vmon td.is-today .vmon__dow{color:var(--cyan-deep);}
  .vmon__wk{margin-left:auto;}
  .vmon__s{grid-template-columns:4.6em 1fr;gap:9px;font-size:.86rem;margin-bottom:5px;}
  .vmon__s:last-child{margin-bottom:0;}
  .vmon__t{font-size:.8rem;}
  /* Names get their own line and stop being truncated — the whole reason the
     grid could not work here was that there was no room for them. */
  .vmon__p span{white-space:normal;overflow:visible;text-overflow:clip;}
  /* An unclaimed shift is a blank line in the grid, where the column keeps it
     aligned and a printed blank is somewhere to write a name. In a list it just
     looks like something failed to load, so here it says what it is. */
  .vmon__p .is-open{font-size:0;}
  .vmon__p .is-open::after{content:"open";font-size:.84rem;font-style:italic;color:var(--muted);}
}
@media(max-width:560px){.form .row{grid-template-columns:1fr;}.form{border-radius:22px;}}

/* =========================================================
   CALENDAR
   ========================================================= */
.cal{background:var(--paper);border:1px solid var(--line);border-radius:var(--radius-lg);overflow:hidden;box-shadow:0 14px 40px rgba(47,33,69,.06);}
.cal__bar{display:flex;align-items:center;gap:var(--space-md);padding:clamp(var(--space-md),2.4vw,var(--space-xl)) clamp(var(--space-md),3vw,var(--space-xl));}
.cal__navwrap{display:flex;gap:6px;}
.cal__nav{width:38px;height:38px;border-radius:12px;display:grid;place-items:center;border:1px solid var(--line);color:var(--ink-strong);font-size:1.3rem;line-height:1;transition:background .2s,color .2s,border-color .2s;}
.cal__nav:hover{background:var(--navy);color:#fff;border-color:var(--navy);}
.cal__title{font-family:var(--font-display);font-weight:800;font-size:clamp(1.2rem,1rem + 1vw,1.7rem);letter-spacing:-.01em;}
.cal__today{margin-left:auto;font-family:var(--font-display);font-weight:600;font-size:.85rem;color:var(--cyan-deep);border:1px solid var(--line);border-radius:100px;padding:.55em 1.2em;transition:background .2s,color .2s,border-color .2s;}
.cal__today:hover{background:var(--cyan);color:#fff;border-color:var(--cyan);}
.cal__dow{display:grid;grid-template-columns:repeat(7,1fr);padding:0 clamp(6px,1.4vw,12px);}
.cal__dow div{padding:6px;text-align:center;font-size:.68rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--muted);}
/* minmax(0,1fr): plain 1fr means minmax(auto,1fr), whose auto minimum is the
   max-content width of the day cell - a long nowrap event chip therefore made its
   column wider than 1/7 and pushed the rest of the row sideways. */
.cal__grid{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:6px;padding:clamp(6px,1.4vw,12px);}
.cal__cell{min-height:122px;min-width:0;border:1px solid transparent;border-radius:14px;padding:8px;display:flex;flex-direction:column;gap:4px;transition:background .2s;}
.cal__cell:not(.cal__cell--mute):hover{background:color-mix(in srgb,var(--cyan) 4%,var(--paper));}
.cal__cell--mute{background:transparent;opacity:.45;}
.cal__num{font-family:var(--font-display);font-weight:700;font-size:.82rem;color:var(--ink-soft);width:28px;height:28px;display:grid;place-items:center;border-radius:50%;margin-bottom:1px;}
.cal__cell.is-today{background:color-mix(in srgb,var(--cyan) 7%,var(--paper));}
.cal__cell.is-today .cal__num{background:var(--cyan);color:#fff;box-shadow:0 3px 10px rgba(160,122,42,.4);}
.cal__ev{display:block;font-size:.72rem;font-weight:600;line-height:1.25;padding:4px 8px;border-radius:8px;background:color-mix(in srgb,var(--cyan) 14%,var(--paper));color:var(--cyan-deep);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;text-decoration:none;max-width:100%;min-width:0;transition:transform .15s var(--ease-out),filter .2s;}
a.cal__ev:hover{transform:translateY(-1px);filter:brightness(.96);}
.cal__ev[hidden],.cal__more[hidden]{display:none !important;}
.cal__ev--rec{background:repeating-linear-gradient(45deg,color-mix(in srgb,var(--navy) 8%,var(--paper)) 0 6px,color-mix(in srgb,var(--navy) 12%,var(--paper)) 6px 12px);color:var(--ink-strong);}
/* event category palette */
.ev-c1{background:#dff1f6;color:#6d5719;}
.ev-c2{background:#f2e4ff;color:#7e2eb3;}
.ev-c3{background:#fde5ee;color:#bf3a6e;}
.ev-c4{background:#f9eed2;color:#9b7800;}
.ev-c5{background:#e1f3e4;color:#2c8048;}
.ev-c6{background:#e4edfb;color:#2d5cab;}
.cal__more{font-size:.68rem;color:var(--muted);font-weight:600;padding-left:4px;}
.cal__legend{display:flex;gap:var(--space-xl);padding:var(--space-md) clamp(var(--space-md),3vw,var(--space-xl)) clamp(var(--space-md),2.4vw,var(--space-xl));font-size:.82rem;color:var(--muted);flex-wrap:wrap;}
.cal__legend .dot{display:inline-block;width:11px;height:11px;border-radius:4px;margin-right:7px;vertical-align:-1px;}
.cal__legend .dot--ev{background:#9ad2e0;}
.cal__legend .dot--rec{background:repeating-linear-gradient(45deg,color-mix(in srgb,var(--navy) 25%,#fff) 0 4px,color-mix(in srgb,var(--navy) 40%,#fff) 4px 8px);}
@media(max-width:680px){
  .cal__grid{gap:3px;padding:6px;}
  .cal__cell{min-height:62px;padding:5px;gap:3px;border-radius:9px;}
  .cal__num{font-size:.76rem;width:22px;height:22px;}
  /* On a phone every event used to collapse to a 7px colored stub — the title
   was still in the markup, rendered at font-size:0, so the calendar showed a
   stack of unlabelled bars and people could not tell what was on. The text
   comes back. A seventh of a phone screen is only about six characters, so
   what does not fit fades out at the right edge rather than being cut with an
   ellipsis: a chip never leaves its own day, so nothing can ever overlap the
   day beside it. The fade is applied only to chips that actually overflow —
   see site.js — because masking one that fits would dim the end of a word
   that had every right to be there. */
.cal__more{font-size:.55rem;padding-left:2px;white-space:nowrap;}
  .cal__ev{font-size:.58rem;line-height:1.5;height:auto;padding:1px 4px;border-radius:5px;
  white-space:nowrap;overflow:hidden;text-overflow:clip;}
.cal__ev.is-cut{-webkit-mask-image:linear-gradient(to right,#000 calc(100% - 11px),transparent);
  mask-image:linear-gradient(to right,#000 calc(100% - 11px),transparent);}
  .cal__more{font-size:.58rem;}
  .cal__dow div{font-size:.58rem;padding:6px 2px;}
}

/* ===== Serve ROA opportunity grid ===== */
.srgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,290px),1fr));gap:18px;margin-top:var(--space-xl);}
.srcard{--ec:#9b7d29;position:relative;background:#fff;border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;box-shadow:0 8px 26px rgba(47,33,69,.05);transition:transform .3s var(--ease-out),box-shadow .3s;}
.srcard:hover{transform:translateY(-4px);box-shadow:0 18px 40px rgba(47,33,69,.12);}
.srcard__img{aspect-ratio:16/10;background:linear-gradient(150deg,color-mix(in srgb,var(--ec) 62%,#fff),var(--ec));background-size:cover;background-position:center;transition:transform .6s var(--ease-out);}
.srcard:hover .srcard__img{transform:scale(1.06);}
.srcard__in{position:relative;z-index:1;background:#fff;padding:16px 20px 20px;}
.srcard h3{display:flex;align-items:center;gap:.55em;font-size:1.12rem;color:var(--ink-strong);line-height:1.25;}
.srcard h3::before{content:"";flex:none;width:9px;height:9px;border-radius:50%;background:var(--ec);}
.srcard__body{margin-top:10px;color:var(--ink-soft);font-size:.92rem;line-height:1.6;}
/* lively accent palette, matching the calendar chips + menu dots */
.srgrid>article:nth-child(6n+1){--ec:#9b7d29;}
.srgrid>article:nth-child(6n+2){--ec:#7e2eb3;}
.srgrid>article:nth-child(6n+3){--ec:#2c8048;}
.srgrid>article:nth-child(6n+4){--ec:#d3a936;}
.srgrid>article:nth-child(6n+5){--ec:#bf3a6e;}
.srgrid>article:nth-child(6n+6){--ec:#2d5cab;}
.srreg{display:flex;flex-wrap:wrap;gap:12px;margin-top:var(--space-lg);}

/* ===== FLC Waiver wizard ===== */
.waiver{max-width:540px;margin-inline:auto;background:#fff;border:1px solid var(--line);border-radius:var(--radius-lg);box-shadow:0 18px 50px rgba(47,33,69,.1);padding:clamp(20px,5vw,34px);}
.waiver__bar{height:6px;border-radius:100px;background:color-mix(in srgb,var(--navy) 10%,#fff);overflow:hidden;margin-bottom:clamp(20px,5vw,30px);}
.waiver__fill{height:100%;width:0;border-radius:100px;background:var(--cyan);transition:width .45s var(--ease-out);}
.wslide{display:none;}
.wslide.is-active{display:block;animation:wslidein .4s var(--ease-out);}
@keyframes wslidein{from{opacity:0;transform:translateY(12px);}to{opacity:1;transform:none;}}
.wslide h2{font-size:clamp(1.4rem,1.2rem + 1.4vw,2rem);color:var(--ink-strong);letter-spacing:-.02em;line-height:1.15;}
.wsub{margin-top:8px;color:var(--ink-soft);font-size:.95rem;}
.waiver label{display:block;margin-top:16px;font-weight:600;font-size:.85rem;color:var(--ink-strong);}
.wopt-note{font-weight:400;color:var(--muted);}
.waiver label input[type=text],.waiver label input[type=email],.waiver label input[type=tel]{display:block;width:100%;margin-top:6px;padding:.85em 1em;border:1.5px solid var(--line);border-radius:12px;font:inherit;background:var(--snow);transition:border-color .2s,background .2s;}
.waiver label input:focus{outline:none;border-color:var(--cyan);background:#fff;}
.wrow2{display:grid;grid-template-columns:1fr 1fr;gap:14px;}
@media(max-width:460px){.wrow2{grid-template-columns:1fr;}}
.wchoice{display:grid;gap:14px;margin-top:clamp(20px,5vw,28px);}
.wopt{display:flex;flex-direction:column;align-items:flex-start;gap:3px;text-align:left;width:100%;padding:18px 20px;border:1.5px solid var(--line);border-radius:var(--radius-card);background:var(--snow);cursor:pointer;transition:border-color .2s,background .2s,transform .15s var(--ease-out);}
.wopt strong{font-size:1.1rem;color:var(--ink-strong);}
.wopt small{color:var(--muted);font-size:.85rem;}
.wopt:hover,.wopt:active{border-color:var(--cyan);background:#fff;transform:translateY(-2px);}
.wterms{margin-top:14px;max-height:300px;overflow-y:auto;padding:16px 18px;border:1px solid var(--line);border-radius:12px;background:var(--snow);font-size:.88rem;line-height:1.6;color:var(--ink-soft);-webkit-overflow-scrolling:touch;}
.wterms p{margin-bottom:10px;}
.wcheck{display:flex;align-items:flex-start;gap:10px;margin-top:18px;font-weight:500;font-size:.9rem;color:var(--ink-strong);cursor:pointer;}
.wcheck input{margin-top:2px;width:20px;height:20px;flex-shrink:0;accent-color:var(--cyan);}
.wsign{position:relative;margin-top:14px;border:1.5px solid var(--line);border-radius:14px;background:var(--snow);overflow:hidden;}
#sigpad{display:block;width:100%;height:200px;touch-action:none;cursor:crosshair;}
.wsign__clear{position:absolute;top:8px;right:8px;border:1px solid var(--line);background:#fff;color:var(--navy);font:600 .75rem/1 var(--font-display);padding:.5em .8em;border-radius:100px;cursor:pointer;}
.wslide[data-step=done]{text-align:center;}
.wdone{width:64px;height:64px;border-radius:50%;background:var(--cyan);color:#fff;display:grid;place-items:center;font-size:2rem;margin:6px auto 16px;}
.waiver__nav{display:flex;justify-content:space-between;gap:12px;margin-top:clamp(22px,5vw,30px);}
.waiver__nav .btn{flex:1;justify-content:center;}
.wmsg{margin-top:14px;color:#c0392b;font-weight:600;font-size:.9rem;min-height:1.2em;text-align:center;}

/* ===== Day modal ===== */
.cal__cell[data-day]{cursor:pointer;}
.cal__cell[data-day] .cal__ev{pointer-events:none;}
.caldial[hidden]{display:none;}
.caldial{position:fixed;inset:0;z-index:1000;display:grid;place-items:center;padding:20px;}
.caldial__backdrop{position:absolute;inset:0;background:rgba(7,18,33,.55);opacity:0;transition:opacity .22s var(--ease-out);}
/* Blur the page itself (real filter) — reliable where backdrop-filter misses
   compositing layers like animated cards. The dialog is moved out of <main>. */
main{transition:filter .24s var(--ease-out);}
html.caldial-open main{filter:blur(6px);}
.caldial.is-open .caldial__backdrop{opacity:1;}
.caldial__box{position:relative;width:min(440px,100%);max-height:84vh;overflow:auto;background:var(--paper);border-radius:var(--radius-card);box-shadow:0 40px 90px rgba(7,20,38,.42);padding:clamp(20px,3vw,30px);transform:translateY(14px) scale(.98);opacity:0;transition:transform .26s var(--ease-out),opacity .26s var(--ease-out);}
.caldial.is-open .caldial__box{transform:none;opacity:1;}
.caldial__x{position:absolute;top:14px;right:14px;width:34px;height:34px;border-radius:50%;border:none;background:color-mix(in srgb,var(--navy) 7%,var(--paper));color:var(--ink-strong);font-size:1.4rem;line-height:1;cursor:pointer;display:grid;place-items:center;transition:background .2s;}
.caldial__x:hover{background:color-mix(in srgb,var(--navy) 14%,var(--paper));}
.caldial__date{font-family:var(--font-display);font-weight:800;font-size:1.25rem;color:var(--ink-strong);letter-spacing:-.01em;margin-bottom:var(--space-md);padding-right:34px;}
.caldial__list{display:flex;flex-direction:column;gap:10px;}
.caldayev{display:grid;grid-template-columns:1fr auto;align-items:center;gap:5px 12px;text-decoration:none;border:1px solid var(--line);border-radius:14px;padding:12px 14px;transition:border-color .2s,background .2s,transform .15s var(--ease-out);}
.caldayev:not(.caldayev--static):hover{border-color:color-mix(in srgb,var(--cyan) 50%,var(--line));background:color-mix(in srgb,var(--cyan) 4%,var(--paper));}
.caldayev--static{cursor:default;}
.caldayev__chip{grid-column:1;justify-self:start;display:inline-block;font-weight:600;font-size:.82rem;line-height:1.3;padding:5px 11px;border-radius:9px;background:color-mix(in srgb,var(--cyan) 14%,var(--paper));color:var(--cyan-deep);}
.caldayev__meta{grid-column:1;font-size:.82rem;color:var(--muted);}
.caldayev__cat{grid-column:1;font-size:.64rem;letter-spacing:.1em;text-transform:uppercase;font-weight:700;color:var(--cyan-deep);}
.caldayev__go{grid-column:2;grid-row:1/span 3;align-self:center;color:var(--cyan-deep);font-size:1.15rem;}
.caldial__empty{color:var(--muted);padding:6px 0;}
.caldial__all{width:100%;justify-content:center;margin-top:var(--space-lg);}

/* ===== Event detail page ===== */
.eventpage{display:grid;grid-template-columns:1fr clamp(260px,30%,340px);gap:clamp(var(--space-lg),4vw,var(--space-3xl));align-items:start;}
.eventpage__body{white-space:normal;}
.eventpage__cta{display:flex;gap:var(--space-md);flex-wrap:wrap;margin-top:var(--space-xl);}
.eventcard{background:var(--paper);border:1px solid var(--line);border-radius:var(--radius-lg);padding:clamp(var(--space-lg),2.5vw,var(--space-xl));display:grid;gap:var(--space-lg);box-shadow:0 14px 40px rgba(47,33,69,.06);position:sticky;top:96px;}
.eventcard__row{display:flex;gap:14px;align-items:flex-start;}
.eventcard__ic{flex:none;width:40px;height:40px;border-radius:12px;display:grid;place-items:center;background:color-mix(in srgb,var(--cyan) 12%,var(--snow));color:var(--cyan-deep);}
.eventcard__ic svg{width:20px;height:20px;}
.eventcard__k{display:block;font-size:.68rem;letter-spacing:.12em;text-transform:uppercase;font-weight:700;color:var(--muted);margin-bottom:2px;}
.eventcard__row b{font-family:var(--font-display);font-weight:600;color:var(--ink-strong);font-size:.98rem;line-height:1.3;}
@media(max-width:760px){.eventpage{grid-template-columns:1fr;}.eventcard{position:static;order:-1;}}

/* =========================================================
   MOTION (progressive enhancement)
   Only hide pre-animation when JS marks <html class="motion">
   ========================================================= */
.motion [data-reveal]{opacity:0;}
.motion [data-reveal-group]>*{opacity:0;}
/* letter-assemble reveals: characters are split at runtime and animate in sequence */
.chw{display:inline-block;white-space:nowrap;}
.chr{display:inline-block;}
.motion [data-kenburns] .fill{transform:scale(1.12);}

/* =========================================================
   RESPONSIVE
   ========================================================= */
@media(max-width:960px){
  .hero__grid{grid-template-columns:1fr;}
  .hero__right{min-height:380px;}
  .split,.split.rev .split__media,.times__grid{grid-template-columns:1fr;}
  .split.rev .split__media{order:0;}
  .gallery{grid-template-columns:repeat(2,1fr);}
  .footer__grid{grid-template-columns:1fr 1fr;}
}
/* ===== Mobile bottom bar + full-menu overlay ===== */
/* The opacity here is load-bearing, not taste. iOS does not re-sample what is
   behind a fixed, backdrop-filtered element while the page is flinging, so the
   bar shows a STALE blur of where the page used to be — which is exactly what
   reads as it drifting or scrolling with the content. At .46 you were mostly
   looking at that stale copy; at .86 a dropped sample is just a solid bar. */
.botbar{display:none;position:fixed;left:50%;bottom:16px;transform:translateX(-50%);z-index:200;align-items:stretch;gap:2px;background:rgba(20,28,40,.86);backdrop-filter:blur(14px) saturate(1.35);-webkit-backdrop-filter:blur(14px) saturate(1.35);border:1px solid rgba(255,255,255,.18);border-radius:100px;padding:7px;box-shadow:0 18px 45px rgba(7,20,38,.34);transition:transform .45s var(--ease-out),opacity .4s;max-width:calc(100vw - 22px);}
.botbar.hide{transform:translateX(-50%) translateY(170%);}
/* Same journey as .hide, its own class: scrolling and the keyboard both want
   the bar gone, and sharing one class means whichever finishes second puts it
   back while the other still wants it away. */
.botbar.hide-kb{transform:translateX(-50%) translateY(170%);}   /* slide only — keeps the blur from snapping */
.botbar__item{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;min-width:60px;padding:8px 10px;border-radius:100px;border:none;background:none;color:rgba(244,238,225,.7);font-family:var(--font-display);font-weight:600;font-size:.64rem;letter-spacing:.02em;cursor:pointer;transition:color .25s,background .25s,transform .22s var(--ease-out);text-decoration:none;}
.botbar__item:active{transform:scale(.86);transition-duration:.1s;}
.botbar__item svg,.botbar__item span{position:relative;z-index:1;}
/* soft chip behind the active tab — one shared pill, positioned by JS, slides between tabs */
.botbar__pill{position:absolute;left:0;top:0;width:0;height:0;border-radius:100px;background:rgba(255,255,255,.16);
  border:1px solid rgba(255,255,255,.14);z-index:0;opacity:0;transform:translate(0,0);
  transition:transform .4s cubic-bezier(.65,0,.35,1),width .4s cubic-bezier(.65,0,.35,1),height .4s cubic-bezier(.65,0,.35,1);}
@media (prefers-reduced-motion:reduce){.botbar__pill{transition:none;}}
.botbar__item svg{width:23px;height:23px;}
.botbar__item span{line-height:1;}
.botbar__item:hover,.botbar__item.is-active{color:#fff;}
.botbar__item--give:hover{color:#fff;}
.botbar__more .ic-x{display:none;}
body.menu-open .botbar__more .ic-menu{display:none;}
body.menu-open .botbar__more .ic-x{display:block;}
body.menu-open .botbar__more{color:#fff;}
/* Narrow phones: let the five tabs share the width evenly instead of overflowing. */
@media(max-width:400px){
  html.app-mode .botbar,.botbar{width:calc(100vw - 20px);max-width:420px;gap:0;padding:6px;justify-content:space-between;}
  .botbar__item{flex:1 1 0;min-width:0;padding:8px 4px;font-size:.58rem;gap:2px;}
  .botbar__item svg{width:21px;height:21px;}
}
@media(max-width:340px){
  .botbar__item{font-size:.54rem;padding:8px 2px;}
  .botbar__item svg{width:20px;height:20px;}
}

.mobmenu{display:none;position:fixed;top:0;left:0;right:0;height:100vh;height:100dvh;z-index:190;background:var(--cream);flex-direction:column;padding:clamp(20px,6vw,40px) clamp(20px,6vw,40px) 116px;overflow-y:auto;-webkit-overflow-scrolling:touch;opacity:0;visibility:hidden;transform:translateY(14px);transition:opacity .35s var(--ease-out),transform .35s var(--ease-out),visibility .35s;}
body.menu-open .mobmenu{opacity:1;visibility:visible;transform:none;}
body.menu-open{overflow:hidden;}
/* staggered reveal of menu items */
.mobmenu .menu>li,.mobmenu__actions{opacity:0;transform:translateY(12px);transition:opacity .45s var(--ease-out),transform .45s var(--ease-out);}
body.menu-open .mobmenu .menu>li,body.menu-open .mobmenu__actions{opacity:1;transform:none;}
body.menu-open .mobmenu .menu>li:nth-child(1){transition-delay:.06s;}
body.menu-open .mobmenu .menu>li:nth-child(2){transition-delay:.10s;}
body.menu-open .mobmenu .menu>li:nth-child(3){transition-delay:.14s;}
body.menu-open .mobmenu .menu>li:nth-child(4){transition-delay:.18s;}
body.menu-open .mobmenu .menu>li:nth-child(5){transition-delay:.22s;}
body.menu-open .mobmenu .menu>li:nth-child(6){transition-delay:.26s;}
body.menu-open .mobmenu .menu>li:nth-child(7){transition-delay:.30s;}
body.menu-open .mobmenu__actions{transition-delay:.34s;}
@media(prefers-reduced-motion:reduce){.mobmenu .menu>li,.mobmenu__actions{transition:none;transform:none;opacity:1;}}
.mobmenu__head{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--space-md);}
html:not(.app-mode) .mobmenu__head{display:none;}       /* floating pill already shows the logo + close */
html:not(.app-mode) .mobmenu{padding-top:86px;}         /* clear the floating pill */
.mobmenu__head .brand__mark{box-shadow:0 2px 8px rgba(47,33,69,.14);}
.mobmenu__head .brand__name{color:var(--ink-strong);}
.mobmenu .menu{flex-direction:column;align-items:stretch;gap:0;width:100%;position:static;margin:0;}
.mobmenu .menu>li{border-bottom:1px solid var(--line);}
.mobmenu .menu>li>a,.mobmenu .menu>li>button{width:100%;justify-content:space-between;padding:.95em .3em;font-size:1.2rem;border-radius:var(--radius-sm);color:var(--ink-strong);font-weight:600;background:none;}
.mobmenu .menu>li>a[aria-current="page"],.mobmenu .menu>li>button[aria-current="page"]{color:var(--cyan-deep);}
.mobmenu .caret{margin-left:auto;width:11px;height:11px;}
.mobmenu .dropdown{position:static;translate:none;transform:none;opacity:1;visibility:visible;box-shadow:none;border:none;background:transparent;backdrop-filter:none;-webkit-backdrop-filter:none;padding:0 0 var(--space-sm) var(--space-md);min-width:0;max-height:0;overflow:hidden;transition:max-height .38s var(--ease-out),padding .38s var(--ease-out);}
.mobmenu .dropdown::before{display:none;}
.mobmenu .dropdown a{color:var(--ink-soft);}
.mobmenu .has-dropdown.open .dropdown{max-height:760px;}
.mobmenu .caret{transition:transform .35s var(--ease-out);}
.mobmenu .has-dropdown.open .caret{transform:rotate(180deg);}
/* folder items drift in with a gentle stagger once the folder is open */
.mobmenu .dropdown a{opacity:0;transform:translateX(-8px);transition:opacity .22s ease,transform .3s var(--ease-out),background .2s,color .2s;}
.mobmenu .has-dropdown.open .dropdown a{opacity:1;transform:none;}
.mobmenu .has-dropdown.open .dropdown li:nth-child(2) a{transition-delay:.03s;}
.mobmenu .has-dropdown.open .dropdown li:nth-child(3) a{transition-delay:.06s;}
.mobmenu .has-dropdown.open .dropdown li:nth-child(4) a{transition-delay:.09s;}
.mobmenu .has-dropdown.open .dropdown li:nth-child(5) a{transition-delay:.12s;}
.mobmenu .has-dropdown.open .dropdown li:nth-child(6) a{transition-delay:.15s;}
.mobmenu .has-dropdown.open .dropdown li:nth-child(7) a{transition-delay:.18s;}
.mobmenu .has-dropdown.open .dropdown li:nth-child(8) a{transition-delay:.21s;}
@media(prefers-reduced-motion:reduce){.mobmenu .dropdown,.mobmenu .dropdown a,.mobmenu .caret{transition:none !important;}}
.mobmenu__actions{margin-top:auto;padding-top:var(--space-lg);display:grid;gap:var(--space-sm);}
.mobmenu__actions .btn{width:100%;justify-content:center;}

/* ===== Mobile browser menu — full screen, one column of large type =====
   Not a frosted stack of cards: an opaque page of its own. The translucent
   version let the hero read straight through the menu, and on a phone held by
   somebody with reading glasses that is the difference between a menu and a
   smudge. */
html:not(.app-mode) .mobmenu{background:var(--paper);}
.mobmenu .menu{gap:0;}
.mobmenu .menu>li{border:0;border-radius:0;overflow:visible;background:none;}
.mobmenu a,.mobmenu button{-webkit-tap-highlight-color:transparent;}
.mobmenu .menu>li>a,
.mobmenu .menu>li>button{display:flex;align-items:center;gap:.45em;width:100%;justify-content:flex-start;
  font-family:var(--font-display);font-weight:400;letter-spacing:-.015em;
  font-size:clamp(2.05rem,8.5vw,2.7rem);line-height:1.16;padding:.12em .04em;
  color:var(--ink-strong);border-radius:0;background:none;}
/* direct-link items get a ">" chevron like the reference */
.mobmenu .menu>li:not(.has-dropdown)>a::after{content:none;}
.mobmenu .caret{width:14px;height:9px;color:var(--muted);}
/* expanded group: divider + indented list with colored dots */
.mobmenu .dropdown{padding:0 1.15em;}
.mobmenu .has-dropdown.open .dropdown{padding-top:.35em;padding-bottom:.7em;}
.mobmenu .dropdown a{display:flex;align-items:center;gap:.75em;padding:.6em 0;font-size:1.05rem;font-weight:700;color:var(--ink-strong);}
.mobmenu .dropdown a::before{content:"";width:9px;height:9px;border-radius:50%;flex-shrink:0;background:var(--muted);}
/* Dots alternate within the crest's two hues — purple 308 and gold 88. The last
   three used to be #2d5cab, #589da6 and #66b8d5, a blue family inherited from the
   previous build: three colours on this church's menu that are in neither hue. */
.mobmenu .dropdown li:nth-child(6n+1) a::before{background:oklch(78% 0.104 88)}
.mobmenu .dropdown li:nth-child(6n+2) a::before{background:oklch(33% 0.082 308)}
.mobmenu .dropdown li:nth-child(6n+3) a::before{background:oklch(88% 0.062 88)}
.mobmenu .dropdown li:nth-child(6n+4) a::before{background:oklch(52% 0.118 308)}
.mobmenu .dropdown li:nth-child(6n+5) a::before{background:oklch(64% 0.116 88)}
.mobmenu .dropdown li:nth-child(6n+6) a::before{background:oklch(43% 0.104 308)}
/* the desktop bar's hover fill reaches these rows too — see the note above */
html:not(.app-mode) .mobmenu .dropdown a:hover,
html:not(.app-mode) .mobmenu .dropdown a[aria-current="page"]{background:none}
/* springy, staggered pop when a group is expanded (liquid-glass feel) */
.mobmenu .dropdown li{opacity:0;transform:translateY(-8px) scale(.96);transform-origin:left center;transition:opacity .28s ease,transform .5s cubic-bezier(.22,1.14,.36,1);}
.mobmenu .has-dropdown.open .dropdown li{opacity:1;transform:none;}
.mobmenu .has-dropdown.open .dropdown li:nth-child(1){transition-delay:.05s;}
.mobmenu .has-dropdown.open .dropdown li:nth-child(2){transition-delay:.10s;}
.mobmenu .has-dropdown.open .dropdown li:nth-child(3){transition-delay:.15s;}
.mobmenu .has-dropdown.open .dropdown li:nth-child(4){transition-delay:.20s;}
.mobmenu .has-dropdown.open .dropdown li:nth-child(5){transition-delay:.25s;}
.mobmenu .has-dropdown.open .dropdown li:nth-child(6){transition-delay:.30s;}
.mobmenu .has-dropdown.open .dropdown li:nth-child(7){transition-delay:.35s;}
.mobmenu .has-dropdown.open .dropdown li:nth-child(8){transition-delay:.40s;}
/* the chevron gives a tiny spring overshoot too */
.mobmenu .has-dropdown>button .caret{transition:transform .24s var(--ae-out,cubic-bezier(.16,1,.3,1));}
@media(prefers-reduced-motion:reduce){.mobmenu .dropdown li{transition:none;transform:none;opacity:1;}}
/* actions: one prominent pill + a plain text link */
.mobmenu__actions{gap:8px;}
.mobmenu__actions .btn--accent{order:2;border-radius:100px;padding:1.05em;font-size:1.05rem;box-shadow:0 12px 30px rgba(160,122,42,.28);}
.mobmenu__actions .btn--member{order:1;border-radius:100px;padding:1.05em;font-size:1.05rem;box-shadow:0 12px 30px rgba(47,33,69,.26);}
.mobmenu__actions .btn--ghost{order:2;background:none;border:none;box-shadow:none;color:var(--ink-strong);font-weight:700;}

@media(max-width:1040px){
  .navshell{display:none;}
  .mobtop{display:flex;}            /* traditional top bar for the mobile browser */
  .mobmenu{display:flex;}
  .banner__inner{padding-top:clamp(82px,13vw,104px);}
  .hero__frame{padding-top:clamp(78px,12vw,108px);}
  .hero__left{padding-top:clamp(40px,8vw,72px);}
}
@media(max-width:560px){
  .footer__grid{grid-template-columns:1fr;}
  .gallery{grid-template-columns:1fr 1fr;}
  .gallery .img.big{grid-column:span 2;grid-row:span 1;}
  .hero__card{position:static;margin:18px;max-width:none;}
}
@media(prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms !important;transition-duration:.01ms !important;scroll-behavior:auto !important;}
  .motion [data-reveal]{opacity:1 !important;}
  .motion .img[data-kenburns] .fill{transform:none !important;}
}

/* =========================================================
   LARGE DISPLAYS — widen the content column and scale type up
   so the design fills big monitors instead of sitting tiny in
   the middle. rem-based sizing follows the html font-size bump.
   ========================================================= */
@media(min-width:1700px){
  :root{--maxw:1480px;--space-3xl:76px;--space-4xl:112px;}
  html{font-size:17.5px;}
}
@media(min-width:2200px){
  :root{--maxw:1720px;--space-2xl:60px;--space-3xl:88px;--space-4xl:132px;}
  html{font-size:19.5px;}
}
@media(min-width:2900px){   /* 4K and up */
  :root{--maxw:2080px;--space-2xl:72px;--space-3xl:108px;--space-4xl:160px;}
  html{font-size:22.5px;}
}
@media(min-width:3700px){   /* 5K / ultrawide */
  :root{--maxw:2400px;}
  html{font-size:25px;}
}

/* =========================================================
   REFINEMENTS — legibility, photo cleanup, varied hovers
   ========================================================= */
:root{
  /* a brighter cyan used only for text sitting on dark navy/photos */
  --cyan-bright:color-mix(in srgb,var(--cyan) 52%,white);
}

/* ---- 1. Legibility: brighten blue text & strengthen scrims on dark ---- */
.banner__scrim{background:linear-gradient(165deg,rgba(10,28,52,.88),rgba(10,28,52,.66) 50%,rgba(8,20,38,.92));}
.banner h1{text-shadow:0 2px 22px rgba(7,18,33,.5);}
.banner h1 .serif{color:var(--cyan-bright);}
.banner p{color:rgba(249,250,253,.96);text-shadow:0 1px 12px rgba(7,18,33,.4);}
.banner .eyebrow{color:var(--cyan-bright) !important;text-shadow:0 1px 10px rgba(7,18,33,.5);}
.banner .crumb,.banner .crumb a{color:rgba(249,250,253,.82);}
.banner .crumb a:hover{color:var(--cyan-bright);}
/* blue-on-navy text elsewhere */
.band .quote .hl,.invite--navy h2 .serif{color:var(--cyan-bright);}
.stat .n{color:var(--cyan-bright);}
.times__list .val{color:var(--cyan-bright);}
.footer a:hover{color:var(--cyan-bright);}

/* ---- 2. No badges over real photos ---- */
.img.has-photo .tag,.img.has-photo .ico{display:none !important;}

/* ---- 3. Varied hover micro-interactions ---- */
/* Feature cards: lighter lift + growing accent underline + image push-in */
.card{position:relative;transition:transform .45s var(--ease-out),box-shadow .45s var(--ease-out);}
.card::after{content:"";position:absolute;left:0;right:0;bottom:0;height:3px;background:var(--cyan);transform:scaleX(0);transform-origin:left;transition:transform .45s var(--ease-out);}
.card:hover{transform:translateY(-5px);box-shadow:var(--shadow-md);}
.card:hover::after{transform:scaleX(1);}
.card:hover h3{color:var(--cyan-deep);}
.card h3{transition:color .35s ease;}
.card:hover .img.has-photo>.ph{transform:scale(1.06);}

/* Rail cards: image zoom + title shifts to cyan (no shadow) */
.rcard .img{transition:transform .5s var(--ease-out);}
.rcard h3{transition:color .35s ease;}
.rcard:hover .img.has-photo>.ph{transform:scale(1.06);}
.rcard:hover h3{color:var(--cyan-deep);}

/* Video cards: outline highlight + image zoom instead of heavy shadow */
.vidcard{transition:transform .4s var(--ease-out),box-shadow .4s var(--ease-out),border-color .4s ease;}
.vidcard:hover{transform:translateY(-4px);box-shadow:var(--shadow-md);border-color:color-mix(in srgb,var(--cyan) 55%,transparent);}

/* Sermon/event rows: slide right + growing left accent bar */
.vrow{position:relative;overflow:hidden;transition:transform .4s var(--ease-out),box-shadow .4s var(--ease-out);}
.vrow::before{content:"";position:absolute;left:0;top:0;bottom:0;width:4px;background:var(--cyan);transform:scaleY(0);transform-origin:top;transition:transform .4s var(--ease-out);z-index:3;}
.vrow:hover{transform:translateX(6px);box-shadow:var(--shadow-md);}
.vrow:hover::before{transform:scaleY(1);}
.vrow h3{transition:color .35s ease;}
.vrow:hover h3{color:var(--cyan-deep);}

/* People: subtle image zoom + name shifts to cyan */
.person .img{overflow:hidden;}
.person .img.has-photo>.ph{transition:transform .6s var(--ease-out);}
.person:hover .img.has-photo>.ph{transform:scale(1.06);}
.person h3{transition:color .35s ease;}
.person:hover h3{color:var(--cyan-deep);}

/* Quick "go" link arrow already slides; add color deepen */
.card:hover .go{color:var(--cyan);}

@media(prefers-reduced-motion:reduce){
  .card:hover,.rcard:hover,.vrow:hover,.vidcard:hover{transform:none;}
  .card::after,.vrow::before{transition:none;}
}

/* =========================================================
   BATCH 2 — banner cards, home hero, accordion spring, etc.
   ========================================================= */

/* Full-color header photo (no tint) + frosted text card */
.banner--photo::after{display:none;}
.banner--photo .banner__photo{filter:none;}
.banner__inner{padding-top:clamp(132px,16vw,200px);}
.banner__card{
  max-width:660px;background:rgba(47,33,69,.44);
  backdrop-filter:blur(16px) saturate(1.4);-webkit-backdrop-filter:blur(16px) saturate(1.4);
  border:1px solid rgba(255,255,255,.18);border-radius:var(--radius-card);
  padding:clamp(22px,3vw,38px);box-shadow:0 30px 70px rgba(7,20,38,.34);
}
.banner__card .crumb,.banner__card .crumb a{color:rgba(249,250,253,.85);text-shadow:none;}
.banner__card .crumb a:hover{color:var(--cyan-bright);}
.banner__card .eyebrow{color:var(--cyan-bright);text-shadow:none;}
.banner__card h1{color:#fff;text-shadow:none;margin:0;}
.banner__card h1 .serif{color:var(--cyan-bright);}
.banner__card p{color:rgba(249,250,253,.93);text-shadow:none;margin-top:var(--space-md);}
.banner__cta{margin-top:var(--space-lg);display:flex;gap:var(--space-md);flex-wrap:wrap;}
.banner__cta .btn{margin-top:0;}
/* Face-aware card placement on desktop — card sits on the photo's clear side */
@media(min-width:1041px){
  .banner--card-right .banner__inner{max-width:none;}
  .banner--card-right .banner__card{margin-left:auto;}
  .banner--card-narrow .banner__card{max-width:430px;}
}

/* Home hero — full-width rounded image w/ white margin + overlay text card */
.hero__frame{padding:10px;}
.hero__media{position:relative;border-radius:clamp(18px,2.4vw,28px);overflow:hidden;
  min-height:clamp(540px,86vh,820px);background:var(--navy);display:flex;align-items:flex-end;isolation:isolate;}
/* On desktop the nav floats over the top of the image — anchor the card below it so they never overlap. */
@media(min-width:1041px){.hero__media{align-items:flex-start;padding-top:clamp(96px,11vh,132px);}}
.hero__media>.ph{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:-1;}
.hero__media::after{content:"";position:absolute;inset:0;z-index:-1;
  background:linear-gradient(to top,rgba(7,18,33,.45),transparent 55%);}
.hero__panel{position:relative;z-index:2;container-type:inline-size;margin:clamp(14px,2.4vw,30px);width:470px;max-width:100%;
  background:rgba(47,33,69,.46);backdrop-filter:blur(18px) saturate(1.4);-webkit-backdrop-filter:blur(18px) saturate(1.4);
  border:1px solid rgba(255,255,255,.18);border-radius:var(--radius-card);padding:clamp(20px,2.2vw,32px);
  color:var(--ink-invert);box-shadow:0 30px 70px rgba(7,20,38,.42);}
.hero__panel .eyebrow{color:var(--cyan-bright);margin-bottom:var(--space-md);}
/* font scales with the card width (cqw) so the headline holds ~3 lines at any size */
.hero__panel h1{color:#fff;font-size:clamp(1.5rem,10.3cqw,2.9rem);line-height:1.08;letter-spacing:-.03em;text-wrap:balance;}
.hero__panel h1 .serif{color:var(--cyan-bright);font-weight:400;}
.hero__panel .hero__sub{margin-top:var(--space-md);color:rgba(249,250,253,.92);max-width:46ch;}
.hero__panel .hero__cta{margin-top:var(--space-lg);}
.hero__panel .hero__quick{margin-top:var(--space-xl);gap:var(--space-lg) var(--space-xl);}
.hero__panel .hero__quick dt{color:rgba(249,250,253,.7);}
.hero__panel .hero__quick dd{color:#fff;}
@media(max-width:640px){
  /* A photo band reads as the header; a compact card tucks under its bottom edge and runs below. */
  .hero__media{display:block;overflow:visible;min-height:0;background:transparent;}
  .hero__scatter{position:relative;inset:auto;height:46vh;border-radius:clamp(18px,2.4vw,28px);}
  .hero__media::after{display:none;}
  .hero__panel{position:relative;z-index:5;margin:-7vh 14px 14px;width:auto;max-width:none;padding:18px 18px 20px;background:rgba(47,33,69,.93);}
  .hero__panel .eyebrow{margin-bottom:5px;font-size:.62rem;}
  .hero__panel .hero__sub{margin-top:8px;font-size:.92rem;}
  .hero__panel .hero__cta{margin-top:12px;gap:8px;}
  .hero__panel .hero__cta .btn{padding:.75em 1.15em;font-size:.85rem;}
  .hero__panel .hero__quick{margin-top:14px;gap:10px 20px;}
  /* show ~6 photos on phones so the band isn't cramped */
  .htile--desk,
  .htile:has([data-eimg="hero_tile_2"]),.htile:has([data-eimg="hero_tile_3"]),
  .htile:has([data-eimg="hero_tile_6"]),.htile:has([data-eimg="hero_tile_7"]),
  .htile:has([data-eimg="hero_tile_9"]),.htile:has([data-eimg="hero_tile_11"]){display:none;}
}

/* ===== Floating image scatter (home hero) ===== */
.hero__scatter{overflow:hidden;border-radius:inherit;z-index:0;}
@media(min-width:641px){.hero__scatter{position:absolute;inset:0;}}   /* phones use the relative 46vh band defined above */
/* default: a solid grainy navy (admin can swap this for a photo via the editor) */
.hero__bg{position:absolute;inset:0;z-index:0;background:radial-gradient(120% 100% at 28% 16%,#1a4571,var(--navy) 62%);}
/* grain is rendered at 600px and displayed at 200px (3x supersampled) so it stays
   crisp on retina phones — Safari rasterizes SVG backgrounds at intrinsic size */
.hero__bg::after{content:"";position:absolute;inset:0;pointer-events:none;mix-blend-mode:overlay;opacity:.14;
  background-size:200px 200px;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='600' height='600'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");}
.htile{position:absolute;z-index:1;border-radius:clamp(10px,1.2vw,16px);overflow:hidden;background:var(--navy);box-shadow:0 18px 44px rgba(7,18,33,.5);will-change:transform;transition:opacity .5s ease;}
/* Hidden until its photo can be painted (site.js gates on decode(), not load).
   The transition above carries the fade; nth-child gives a small stagger so
   thirteen tiles don't all arrive on the same frame. */
.htile.is-loading{opacity:0;}
.htile:nth-child(2){transition-delay:.04s}.htile:nth-child(3){transition-delay:.08s}
.htile:nth-child(4){transition-delay:.12s}.htile:nth-child(5){transition-delay:.16s}
.htile:nth-child(6){transition-delay:.2s} .htile:nth-child(7){transition-delay:.24s}
.htile:nth-child(8){transition-delay:.28s}.htile:nth-child(9){transition-delay:.32s}
.htile:nth-child(n+10){transition-delay:.36s}
.htile img{width:100%;height:100%;object-fit:cover;display:block;border-radius:inherit;}
.edit-mode .htile{overflow:visible;}   /* let the "Replace photo" button show on small tiles */
.hero__panel{z-index:3;}
/* ministry rail cards lift on hover */
.rcard{transition:transform .4s var(--ease-out);}
.rcard:hover{transform:translateY(-5px);}
.rcard:active{transform:translateY(-2px) scale(.99);}
/* text links: an underline wipes in on hover */
.lead a:not(.btn),.split__copy p a:not(.btn),.prose a:not(.btn),.crumb a{background-image:linear-gradient(currentColor,currentColor);background-repeat:no-repeat;background-position:0 100%;background-size:0% 1.5px;transition:background-size .35s var(--ease-out),color .2s;}
.lead a:not(.btn):hover,.split__copy p a:not(.btn):hover,.prose a:not(.btn):hover,.crumb a:hover{background-size:100% 1.5px;}

/* Accordion — springy open */
/* Deceleration, not overshoot. grid-template-rows is a layout property — an
   overshoot curve made the panel expand past its real height and snap back,
   reflowing everything beneath it on every frame of the bounce. */
.acc__a{transition:grid-template-rows .42s var(--ae-out,cubic-bezier(.16,1,.3,1));}
.acc__q .pm{transition:transform .28s var(--ae-out,cubic-bezier(.16,1,.3,1));}
.acc__item.open .acc__q .pm{transform:rotate(90deg);}
.acc__item.open{box-shadow:var(--shadow-md);}
.acc__item{transition:box-shadow .4s var(--ease-out);}

/* Partner logo grid (missions) */
.logos{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:var(--space-md);align-items:center;}
.logos figure{background:var(--navy);border:1px solid color-mix(in srgb,var(--navy) 55%,var(--snow));border-radius:var(--radius);aspect-ratio:3/2;display:grid;place-items:center;padding:22px;transition:transform .4s var(--ease-out),box-shadow .4s var(--ease-out);}
.logos figure:hover{transform:translateY(-4px);box-shadow:var(--shadow-md);}
.logos img{max-width:100%;max-height:100%;width:auto;height:auto;object-fit:contain;}

/* Single full-image form stage (connect page) — lighter scrim so the photo shows */
.formstage--solo .formstage__bg{background-size:cover;background-position:center;}
.formstage--solo .formstage__bg::after{background:linear-gradient(to bottom,rgba(6,18,31,.34),rgba(6,18,31,.56));}

/* Nav nudged down slightly */
.navshell{top:24px;}

/* Home: one off-white field; color reserved for the Plan-a-Visit band */
.page-home{background:var(--snow);}
.page-home .section{background:var(--snow);}
/* Creative section break — cross motif between hairlines (replaces color transitions) */
.pagebreak{display:flex;align-items:center;gap:clamp(14px,3vw,30px);max-width:720px;margin-inline:auto;padding-inline:clamp(20px,5vw,52px);padding-block:clamp(18px,3.5vw,40px);}

/* --- divider boundary -------------------------------------------------------
   Two systems separate sections on this site: a change of background (Give,
   Events - about 102px between sections) and this divider (the home page).
   The divider version came to 256px: 78px of section padding, a 100px divider,
   then 78px again - two and a half times the rest of the site for a boundary
   that is one hairline rule and a small mark.

   The ornament stays; the air around it comes in. The sections either side of a
   divider give up roughly a third of their padding, which lands the boundary
   near 170px - still plainly more generous than a background change, which is
   right, because a divider is a softer signal and needs the room to read as
   deliberate rather than accidental. */
/* The CMS drops <style> and <script> nodes between blocks, so a bare
   `+ .pagebreak` misses the sections that happen to have one after them - which
   left the boundaries uneven, 186px on some and 211px on others. Those nodes
   have no layout, so stepping over them explicitly is enough. */
.section:has(+ .pagebreak),
.section:has(+ :is(style,script) + .pagebreak),
.section:has(+ :is(style,script) + :is(style,script) + .pagebreak){
  padding-bottom:clamp(34px,4.4vw,62px);
}
.pagebreak + .section{padding-top:clamp(34px,4.4vw,62px);}
.pagebreak{padding-block:clamp(10px,2vw,22px);}

.pagebreak__rule{flex:1;height:1px;background:linear-gradient(to right,transparent,color-mix(in srgb,var(--navy) 20%,transparent),transparent);}
.pagebreak__mark{color:var(--cyan);display:grid;place-items:center;flex-shrink:0;opacity:.85;animation:pbspin 18s linear infinite;}
@keyframes pbspin{from{transform:rotate(0deg);}to{transform:rotate(360deg);}}
@media(prefers-reduced-motion:reduce){.pagebreak__mark{animation:none;transform:rotate(45deg);}}

/* =========================================================
   MOBILE BROWSER — traditional top bar
   ========================================================= */
/* Floating pill on the mobile browser — same glass treatment as the desktop nav, always visible */
.mobtop{display:none;position:fixed;top:12px;left:auto;right:12px;z-index:210;align-items:center;gap:6px;
  padding:6px 8px;background:rgba(47,33,69,.70);backdrop-filter:blur(16px) saturate(1.5);-webkit-backdrop-filter:blur(16px) saturate(1.5);
  border:1px solid rgba(255,255,255,.12);border-radius:100px;box-shadow:0 8px 22px rgba(7,20,38,.22),inset 0 1px 0 rgba(255,255,255,.09);}
.mobtop .brand{color:#fff;display:flex;align-items:center;overflow:hidden;max-width:80px;
  transition:max-width .42s var(--ease-out),opacity .26s var(--ease-out),transform .42s var(--ease-out),margin .42s var(--ease-out);}
.mobtop .brand__logo{width:40px;height:40px;}
/* scrolling down: the logo slides into the hamburger and disappears (returns on scroll up) */
.mobtop.is-min .brand{max-width:0;opacity:0;margin-right:-6px;transform:translateX(10px) scale(.4);}
.mobtop__burger{display:inline-flex;align-items:center;justify-content:center;width:44px;height:44px;border:none;background:transparent;color:#fff;cursor:pointer;border-radius:50%;-webkit-tap-highlight-color:transparent;transition:background .2s;}
.mobtop__burger:hover,.mobtop__burger:active{background:rgba(255,255,255,.12);}
.burger{position:relative;display:block;width:22px;height:14px;}
.burger span{position:absolute;left:0;right:0;height:2px;border-radius:2px;background:currentColor;transition:transform .35s var(--ease-out),top .35s var(--ease-out);}
.burger span:nth-child(1){top:3px;}
.burger span:nth-child(2){top:9px;}
body.menu-open .burger span{top:6px;}
body.menu-open .burger span:nth-child(1){transform:rotate(45deg);}
body.menu-open .burger span:nth-child(2){transform:rotate(-45deg);}

/* =========================================================
   INSTALLED APP (PWA standalone) — app chrome
   ========================================================= */
.apphead{display:none;position:fixed;top:0;left:0;right:0;z-index:200;align-items:center;justify-content:center;gap:.5em;
  padding:calc(env(safe-area-inset-top,0px) + 11px) 16px 11px;background:rgba(47,33,69,.94);backdrop-filter:blur(16px);
  -webkit-backdrop-filter:blur(16px);color:#fff;box-shadow:0 2px 16px rgba(7,20,38,.3);}
.apphead .brand__logo{width:30px;height:30px;}
.apphead__name{font-family:var(--font-display);font-weight:700;font-size:.95rem;letter-spacing:.01em;}
/* Members Portal shortcut — right side of the app bar */
.apphead__member{position:absolute;right:10px;bottom:7px;width:38px;height:38px;display:grid;place-items:center;border-radius:50%;color:#fff;background:rgba(255,255,255,.12);-webkit-tap-highlight-color:transparent;transition:background .2s,transform .25s var(--ease-out);}
.apphead__member svg{width:21px;height:21px;}
.apphead__member:active{transform:scale(.92);}
.apphead__member.is-in::after{content:none;}
/* Members icon in the app home greeting row (replaces the logo circle there) */
.appdash__avatar--member{position:relative;color:#fff;-webkit-tap-highlight-color:transparent;}
.appdash__avatar--member svg{width:23px;height:23px;}
.appdash__avatar--member:active{transform:scale(.93);}
.appdash__avatar--member.is-in::after{content:none;}

html.app-mode .navshell{display:none !important;}
html.app-mode .mobtop{display:none !important;}
/* Show the mobile-browser top bar (defined after the base .mobtop rule so source order can't hide it). */
@media(max-width:1040px){html:not(.app-mode) .mobtop{display:flex;}}
html.app-mode .announce{display:none;}            /* skip time-sensitive bar inside the app */
html.app-mode .apphead{display:none !important;}  /* no top banner — the app runs edge-to-top */
html.app-mode .botbar{display:flex;bottom:calc(env(safe-area-inset-bottom,0px) + 10px);}

/* --- status bar scrim ------------------------------------------------------
   The app runs with apple-mobile-web-app-status-bar-style: black-translucent so
   the page reaches the top of the screen. iOS then draws the clock, battery and
   signal in WHITE and gives no way to ask for dark — so a screen that is pale at
   the top loses them entirely. A script in the header measures the top of each
   page once it has rendered and sets .app-lighttop where it is needed.

   Height is exactly the safe-area inset, so a phone with no notch gets nothing at
   all, and the gradient fades to transparent so it reads as shading rather than
   as the very bar we just removed.
   The color comes from --scrim, so it does not have to be the site's navy on
   every screen. A page can name its own with 'scrim' => '#5a2036' in its $PAGE
   array; left alone, the same script that decides whether the shading is needed
   also tints it toward the color it measured at the top of that page, so a warm
   screen gets a warm shadow rather than a navy one laid over it. It takes the hue
   and holds the lightness at the 15% the navy already sat at, so every page's
   shading is about as dark as every other page's: a per-page color changes the
   temperature of the shading, never whether the white clock can be read. */
html.app-mode{--scrim:#38164f;}
html.app-mode.app-lighttop::before{
  content:'';position:fixed;top:0;left:0;right:0;z-index:400;pointer-events:none;
  height:env(safe-area-inset-top,0px);
  /* first declaration is the fallback for engines without color-mix() */
  background:linear-gradient(180deg,rgba(47,33,69,.62),rgba(47,33,69,.34) 62%,rgba(47,33,69,0));
  background:linear-gradient(180deg,
    color-mix(in srgb,var(--scrim) 62%,transparent),
    color-mix(in srgb,var(--scrim) 34%,transparent) 62%,
    transparent);
}
@media (prefers-reduced-transparency:reduce){
  html.app-mode.app-lighttop::before{
    background:rgba(47,33,69,.7);
    background:color-mix(in srgb,var(--scrim) 70%,transparent);
  }
}

html.app-mode body{padding-top:0;padding-bottom:calc(env(safe-area-inset-bottom,0px) + 86px);}
/* the iOS status icons float directly over the page — no strip behind them */
/* pull-to-refresh pill (installed app) */
.ptr{position:fixed;top:calc(env(safe-area-inset-top,0px) + 6px);left:50%;transform:translateX(-50%);z-index:420;
  width:40px;height:40px;border-radius:50%;display:grid;place-items:center;opacity:0;pointer-events:none;
  background:rgba(20,28,40,.6);backdrop-filter:blur(18px) saturate(1.5);-webkit-backdrop-filter:blur(18px) saturate(1.5);
  border:1px solid rgba(255,255,255,.22);box-shadow:0 10px 30px rgba(7,20,38,.35);transition:opacity .2s}
.ptr.show{opacity:1}
.ptr__spin{width:18px;height:18px;border-radius:50%;border:2.5px solid rgba(255,255,255,.28);border-top-color:#dfc17a;transition:transform .2s}
.ptr.ready .ptr__spin{transform:rotate(180deg);border-top-color:#fff}
.ptr.spin .ptr__spin{animation:ptrspin .7s linear infinite}
@keyframes ptrspin{to{transform:rotate(360deg)}}
/* The status bar now uses iOS's "default" style — black clock, battery and
   signal on the theme color — so the dark gradient that used to sit behind
   white icons is gone. The element stays in the markup (it's referenced
   elsewhere) but paints nothing. */
.appstatus{display:none;}
html.app-mode .appstatus{display:none;}
/* floating account button, tucked beside the notch (app only) */
.appuser{display:none;}
html.app-mode .appuser{position:fixed;top:calc(env(safe-area-inset-top,0px) + 8px);right:14px;z-index:390;
  display:grid;place-items:center;width:38px;height:38px;border-radius:50%;overflow:hidden;color:#fff;
  background:rgba(47,33,69,.55);border:1px solid rgba(255,255,255,.22);
  backdrop-filter:blur(16px) saturate(1.5);-webkit-backdrop-filter:blur(16px) saturate(1.5);
  box-shadow:0 8px 22px rgba(7,20,38,.35);-webkit-tap-highlight-color:transparent;transition:transform .25s var(--ease-out);}
html.app-mode .appuser:active{transform:scale(.92);}
html.app-mode .appuser svg{width:20px;height:20px;}
/* Signed out, the same button says so. A silhouette in a circle is a face, not
   an instruction, and the people most likely to need the portal are the least
   likely to work out that the little grey head is the way in. It keeps its
   place beside the notch and keeps its glass; it only gets wider. */
html.app-mode .appuser--out{width:auto;height:38px;grid-auto-flow:column;gap:.42em;
  padding:0 13px 0 11px;border-radius:100px;}
html.app-mode .appuser--out svg{width:16px;height:16px;}
.appuser__lbl{font-size:.78rem;font-weight:700;line-height:1;white-space:nowrap;}
/* Settings sheet — morphs open from the profile icon */
.setmodal{position:fixed;inset:0;z-index:600;display:flex}
.setmodal[hidden]{display:none}
.setmodal__scrim{position:absolute;inset:0;background:rgba(6,15,30,.55);-webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px);opacity:0;transition:opacity .32s ease}
.setmodal.is-open .setmodal__scrim{opacity:1}
/* Settings drops in from the top and settles on a spring.
   It used to inflate from a dot at the tapped icon, which is a lovely trick
   and the wrong one here: a settings panel isn't born out of the button, it
   comes down over the page like a drawer. Coming from above also means the
   thing you tapped stays visible underneath, so it's obvious what you're on
   top of and which way out is.

   The overshoot is small — it passes its resting place by a few pixels and
   comes back. Enough to feel like weight, not enough to read as a wobble. */
.setmodal__card{position:relative;margin:auto;width:min(600px,94vw);height:min(84vh,760px);max-height:calc(100vh - 40px);background:var(--snow,#faf7f1);
  border-radius:24px;overflow:hidden;display:flex;flex-direction:column;box-shadow:0 40px 90px rgba(6,15,30,.5);
  opacity:0;transform:translateY(-118%);
  transition:transform .52s var(--ae-spring,cubic-bezier(.22,1.14,.36,1)),opacity .22s ease}
.setmodal.is-open .setmodal__card{opacity:1;transform:translateY(0)}
/* Leaving is quicker and doesn't bounce — an exit that springs reads as
   indecision. */
.setmodal:not(.is-open) .setmodal__card{transition:transform .26s cubic-bezier(.4,0,1,1),opacity .2s ease}
@media (prefers-reduced-motion:reduce){
  .setmodal__card,.setmodal:not(.is-open) .setmodal__card{transition:opacity .2s ease;transform:none}
}
/* The card floats in the middle of the screen and never touches the top, so
   the safe-area inset it used to carry was pure dead space above the word. */
.setmodal__bar{flex:none;display:flex;align-items:center;justify-content:space-between;padding:14px 18px;border-bottom:1px solid var(--line);background:var(--asurf,var(--card,#fff))}
.setmodal__bar strong{font-family:var(--font-display);font-weight:700;font-size:1.05rem;color:var(--ink-strong)}
.setmodal__x{border:0;background:none;font-size:1.9rem;line-height:1;color:var(--muted);cursor:pointer;padding:0 6px;-webkit-tap-highlight-color:transparent}
.setmodal__frame{flex:1;width:100%;border:0;background:transparent}
body.set-open{overflow:hidden}
@media(prefers-reduced-motion:reduce){.setmodal__card{transition:opacity .2s}}
html.app-mode .appuser img{width:100%;height:100%;object-fit:cover;}
html.app-mode .appuser.is-in::after{content:none;}
/* the home dashboard already has its own member avatar — hide the floating one there */
html.app-mode body.page-home .appuser{display:none;}
/* ...except when there is nobody to be. The app home hides the floating button
   because it carries its own account control, and that control is only there
   for a member. Signed out that corner was simply empty, on the one screen the
   app opens to, so the way in was invisible to exactly the person looking for
   it. Only the signed-out pill comes back; a member sees no change. */
html.app-mode body.page-home .appuser--out{display:grid;}

/* App "More" = a bottom sheet that rises out of the tab bar (not a full-screen takeover) */
html.app-mode .mobmenu{
  inset:auto 0 0 0;top:auto;height:auto;max-height:80vh;
  border-radius:26px 26px 0 0;
  /* same frosted glass as the bottom bar, one notch lighter */
  --ai:#f7f9fb;
  --am:rgba(255,255,255,.88);
  --aline:rgba(255,255,255,.13);
  --aicobg:rgba(255,255,255,.13);
  --aac:rgba(168,228,245,.55);
  --aacd:#a8e4f5;
  color:#f7f9fb;
  background:
    linear-gradient(180deg,rgba(255,255,255,.13),rgba(255,255,255,.03) 42%,rgba(255,255,255,0) 72%),
    linear-gradient(180deg,rgba(20,28,40,.66),rgba(16,23,34,.72));
  backdrop-filter:blur(30px) saturate(1.9);
  -webkit-backdrop-filter:blur(30px) saturate(1.9);
  padding:8px clamp(18px,6vw,28px) calc(env(safe-area-inset-bottom,0px) + 96px);
  transform:translateY(103%);opacity:1;visibility:hidden;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.16), 0 -18px 55px rgba(7,20,38,.45), 0 0 0 100vmax rgba(7,20,38,0);
  transition:transform .44s var(--ease-out),visibility .44s,box-shadow .5s ease;
  will-change:transform;
}
html.app-mode body.menu-open .mobmenu{
  transform:translateY(0);visibility:visible;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.16), 0 -18px 55px rgba(7,20,38,.45), 0 0 0 100vmax rgba(7,20,38,.42);
}
/* the sheet is dark glass now, so its contents read light-on-dark */
html.app-mode .mobmenu .appsheet__h{color:rgba(255,255,255,.92)}
html.app-mode .mobmenu .appsheet__ic{box-shadow:inset 0 0 0 1px rgba(255,255,255,.10)}
html.app-mode .mobmenu .appsheet__go{opacity:.62}
html.app-mode .mobmenu .appsheet__n{background:#a8e4f5;color:#0b2136}
html.app-mode .mobmenu .appsheet__out--in{color:#e8f9ff;background:rgba(168,228,245,.14)}
html.app-mode .mobmenu__head{display:none}                 /* the grab handle stands in for the header */
html.app-mode .mobmenu::before{
  content:"";display:block;flex:none;width:42px;height:5px;border-radius:100px;
  background:rgba(255,255,255,.32);margin:2px auto 14px;
}
html.app-mode .mobmenu .menu>li>a,
html.app-mode .mobmenu .menu>li>button{font-size:1.08rem;padding:.95em 1.1em;}
/* in the app, page tops clear the notch (content flows under the status bar) */
html.app-mode .banner__inner{padding-top:calc(env(safe-area-inset-top,0px) + clamp(56px,10vw,84px));}
html.app-mode .hero__frame{padding-top:calc(env(safe-area-inset-top,0px) + clamp(52px,9vw,80px));}
html.app-mode .smhero,html.app-mode .khero{padding-top:calc(env(safe-area-inset-top,0px) + clamp(52px,9vw,80px));}
html.app-mode .shero__copy{padding-top:calc(env(safe-area-inset-top,0px) + clamp(56px,10vw,84px));}
html.app-mode .appdash{padding-top:calc(env(safe-area-inset-top,0px) + 12px);}
html.app-mode .ptl-banner .banner__inner{padding-top:calc(env(safe-area-inset-top,0px) + clamp(48px,9vw,72px));}

/* "Turn on notifications" — app dashboard card */
.apppush{display:flex;align-items:center;gap:13px;width:100%;text-align:left;cursor:pointer;
  margin-top:4px;padding:14px 16px;border-radius:var(--radius-card);border:1px solid rgba(160,122,42,.28);
  background:linear-gradient(135deg,rgba(160,122,42,.10),rgba(47,33,69,.05));color:var(--ink-strong);
  font-family:var(--font-display);transition:background .25s,border-color .25s,transform .15s;}
.apppush:active{transform:scale(.99);}
.apppush[data-state="on"]{border-color:rgba(34,150,90,.35);background:rgba(34,150,90,.08);}
.apppush[disabled]{opacity:.7;cursor:default;}
.apppush__ic{flex:none;display:grid;place-items:center;width:40px;height:40px;border-radius:12px;background:var(--cyan);color:#fff;}
.apppush__ic svg{width:21px;height:21px;}
.apppush[data-state="on"] .apppush__ic{background:#22965a;}
.apppush__tx{display:flex;flex-direction:column;gap:1px;line-height:1.2;}
.apppush__tx b{font-size:.96rem;font-weight:700;}
.apppush__tx small{font-size:.76rem;color:var(--ink-soft);font-weight:500;}

/* "Get notifications" — footer link/button */
.footpush{background:none;border:1px solid rgba(255,255,255,.28);color:inherit;cursor:pointer;
  font:inherit;font-size:.82rem;padding:.4em .9em;border-radius:100px;transition:background .25s,border-color .25s;}
.footpush:hover{background:rgba(255,255,255,.1);}
.footpush[data-state="on"]{border-color:rgba(120,210,160,.5);color:#bfe9cf;}
.footpush[disabled]{opacity:.6;cursor:default;}

/* app-only vs browser-only blocks */
.app-only{display:none;}
html.app-mode .app-only{display:block;}
html.app-mode .browser-only{display:none;}
/* keep buttons flowing as buttons when toggled by app/browser mode */
.btn.app-only{display:none;}
html.app-mode .btn.app-only{display:inline-flex;align-items:center;justify-content:center;}
html.app-mode .mobmenu__actions a.btn--member{display:flex;align-items:center;justify-content:center;}

/* =========================================================
   APP HOME DASHBOARD (app-mode home)
   ========================================================= */
.appdash{display:none;padding:14px clamp(16px,5vw,26px) clamp(28px,7vw,44px);flex-direction:column;gap:18px;}
html.app-mode .appdash{display:flex;}
/* On the app home we drop the slim header bar entirely so the page background runs to the top */
html.app-mode body.page-home .apphead{display:none;}
/* let the flex gap own all vertical rhythm — no element adds its own top margin */
.appdash > * { margin-top:0; }

/* ── PWA home entrance: springy staggered rise (replaces the plain fade) ──
   In app-mode the anim-* fade utilities inside the dash are neutralized and
   every dash block springs up with a slight overshoot, cascading top→bottom. */
html.app-mode .appdash .anim-fade-up.aa,html.app-mode .appdash .anim-card.aa,
html.app-mode .appdash .anim-fade-up.aa.is-in,html.app-mode .appdash .anim-card.aa.is-in{opacity:1;transform:none;transition:none;}
@keyframes appdashSpring{from{opacity:0;transform:translateY(38px) scale(.94);}to{opacity:1;transform:none;}}
html.app-mode .appdash>*{animation:appdashSpring .72s var(--ae-spring,cubic-bezier(.22,1.14,.36,1)) both;}
html.app-mode .appdash>*:nth-child(1){animation-delay:.04s;}
html.app-mode .appdash>*:nth-child(2){animation-delay:.12s;}
html.app-mode .appdash>*:nth-child(3){animation-delay:.2s;}
html.app-mode .appdash>*:nth-child(4){animation-delay:.26s;}
html.app-mode .appdash>*:nth-child(5){animation-delay:.32s;}
html.app-mode .appdash>*:nth-child(6){animation-delay:.62s;}
html.app-mode .appdash>*:nth-child(7){animation-delay:.68s;}
html.app-mode .appdash>*:nth-child(8){animation-delay:.74s;}
/* quick-link rows cascade individually instead of the whole list at once */
html.app-mode .appdash .applist{animation:none;}
html.app-mode .appdash .applist__row{animation:appdashSpring .6s var(--ae-spring,cubic-bezier(.22,1.14,.36,1)) both;}
html.app-mode .appdash .applist__row:nth-child(1){animation-delay:.32s;}
html.app-mode .appdash .applist__row:nth-child(2){animation-delay:.37s;}
html.app-mode .appdash .applist__row:nth-child(3){animation-delay:.42s;}
html.app-mode .appdash .applist__row:nth-child(4){animation-delay:.47s;}
html.app-mode .appdash .applist__row:nth-child(5){animation-delay:.52s;}
html.app-mode .appdash .applist__row:nth-child(6){animation-delay:.57s;}
/* the tiles cascade individually too, on the same clock as the rows */
html.app-mode .appdash .appms{animation:none;}
html.app-mode .appdash .appms__t{animation:appdashSpring .6s var(--ae-spring,cubic-bezier(.22,1.14,.36,1)) both;}
html.app-mode .appdash .appms__t:nth-child(1){animation-delay:.32s;}
html.app-mode .appdash .appms__t:nth-child(2){animation-delay:.37s;}
html.app-mode .appdash .appms__t:nth-child(3){animation-delay:.42s;}
html.app-mode .appdash .appms__t:nth-child(4){animation-delay:.47s;}
html.app-mode .appdash .appms__t:nth-child(5){animation-delay:.52s;}
html.app-mode .appdash .appms__t:nth-child(6){animation-delay:.57s;}
@media(prefers-reduced-motion:reduce){
  html.app-mode .appdash>*,html.app-mode .appdash .applist__row,html.app-mode .appdash .appms__t{animation:none;}
}
.appk{font-size:.62rem;letter-spacing:.18em;text-transform:uppercase;font-weight:700;}

/* greeting row */
.appdash__top{display:flex;align-items:center;justify-content:space-between;gap:14px;}
.appdash__kick{font-size:.64rem;letter-spacing:.18em;text-transform:uppercase;font-weight:700;color:var(--cyan-deep);}
.appdash__greet{font-family:var(--font-serif);font-style:italic;font-weight:400;font-size:clamp(1.9rem,1.4rem + 2.6vw,2.6rem);color:var(--ink-strong);line-height:1.05;margin-top:2px;}
.appdash__avatar{width:46px;height:46px;border-radius:50%;overflow:hidden;flex-shrink:0;background:var(--navy);display:grid;place-items:center;box-shadow:var(--shadow-sm);}
.appdash__avatar img{width:100%;height:100%;object-fit:contain;}

/* "This Sunday" hero card */
.appcard--sunday{display:block;text-decoration:none;border-radius:var(--radius-card);overflow:hidden;background:linear-gradient(155deg,var(--cyan-deep),var(--navy));color:#fff;padding:18px;box-shadow:0 16px 40px rgba(7,20,38,.28);position:relative;isolation:isolate;}
.appcard--sunday::after{content:"";position:absolute;inset:0;z-index:0;background:radial-gradient(70% 60% at 85% 0%,rgba(160,122,42,.45),transparent 60%);}
.appweek{position:relative;z-index:1;display:flex;justify-content:space-between;gap:4px;margin-bottom:16px;}
.appweek span{flex:1;display:flex;flex-direction:column;align-items:center;gap:4px;font-size:.6rem;font-weight:700;letter-spacing:.05em;color:rgba(255,255,255,.6);}
.appweek b{width:30px;height:30px;display:grid;place-items:center;border-radius:50%;font-size:.82rem;font-weight:700;color:rgba(255,255,255,.85);}
.appweek .is-today b{background:#fff;color:var(--navy);}
.appweek .is-sun{color:var(--cyan-bright);}
.appweek .is-sun b{box-shadow:inset 0 0 0 1.5px rgba(255,255,255,.5);}
.appcard__body{position:relative;z-index:1;}
.appcard__body .appk{color:var(--cyan-bright);}
.appcard__body h2{color:#fff;font-size:1.5rem;line-height:1.05;margin-top:3px;}
.appcard__body h2 .serif{color:var(--cyan-bright);}
.appcard__body p{color:rgba(255,255,255,.85);font-size:.86rem;margin-top:5px;}
.appweekly{position:relative;z-index:1;margin:12px 0 0;padding:0;list-style:none;display:flex;flex-direction:column;}
.appweekly li{display:flex;align-items:center;gap:12px;padding:9px 0;border-top:1px solid rgba(255,255,255,.14);}
.appweekly li:first-child{border-top:none;}
.appweekly b{width:44px;flex-shrink:0;font-size:.64rem;letter-spacing:.08em;text-transform:uppercase;font-weight:700;color:var(--cyan-bright);}
.appweekly span{flex:1;min-width:0;color:#fff;font-family:var(--font-display);font-weight:500;font-size:.92rem;}
.appweekly i{flex-shrink:0;color:rgba(255,255,255,.72);font-style:normal;font-size:.82rem;}
.appchip{display:inline-flex;align-items:center;gap:.4em;margin-top:16px;background:rgba(255,255,255,.16);color:#fff;font-weight:600;font-size:.82rem;padding:.5em 1em;border-radius:100px;}

/* latest-message media card */
.appfeature{position:relative;display:flex;align-items:flex-end;aspect-ratio:16/9;border-radius:var(--radius-card);overflow:hidden;text-decoration:none;background:var(--navy);box-shadow:var(--shadow-sm);isolation:isolate;}
.appfeature img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:0;}
.appfeature::after{content:"";position:absolute;inset:0;z-index:1;background:linear-gradient(to top,rgba(7,18,33,.92),rgba(7,18,33,.34) 45%,rgba(7,18,33,.04) 72%);}
.appfeature__body{position:relative;z-index:2;padding:16px;width:100%;}
.appfeature__body .appk{color:var(--cyan-bright);}
.appfeature__body h3{color:#fff;font-size:1.1rem;line-height:1.12;margin-top:3px;max-width:80%;}
.appfeature__play{position:absolute;z-index:2;right:16px;bottom:16px;width:42px;height:42px;border-radius:50%;background:rgba(255,255,255,.92);color:var(--ink-strong);display:grid;place-items:center;}
.appfeature__play svg{margin-left:2px;}

/* quick-links list card */
/* each quick link is its own rounded rectangle card, stacked with breathing room */
.applist{display:flex;flex-direction:column;gap:10px;}
.applist__row{display:flex;align-items:center;gap:14px;padding:14px 16px;text-decoration:none;color:var(--ink);
  background:var(--paper);border:1px solid var(--line);border-radius:18px;box-shadow:var(--shadow-sm);
  transition:background .2s,transform .18s var(--ease-out),box-shadow .2s;}
.applist__row:active{background:color-mix(in srgb,var(--cyan) 8%,var(--paper));transform:scale(.985);}
.applist__ico{width:44px;height:44px;flex-shrink:0;border-radius:13px;display:grid;place-items:center;background:color-mix(in srgb,var(--cyan) 12%,var(--snow));color:var(--cyan-deep);}
.applist__ico svg{width:22px;height:22px;}
.applist__row b{flex:1;font-family:var(--font-display);font-weight:600;font-size:1rem;color:var(--ink-strong);}
.applist__row small{color:var(--muted);font-size:.78rem;}
.applist__chev{color:var(--muted);width:18px;height:18px;flex-shrink:0;}

/* ================================================= home-screen tiles
   Replaces the row list (card + icon chip + chevron, eight times) that every
   destination shared. Two problems with that, and only one was styling: it is
   the stock settings-list pattern, and drawing all eight at identical weight
   left the eye nothing to land on.

   Three weights now. One gradient tile leads each block, using the SAME two
   stops as the Sunday card above so it reads as part of the screen rather
   than a second accent invented for it. Below that a full-width tint, then
   quiet outlined squares. Sizes are uneven on purpose — a strict grid of
   equal cards is the thing that reads as templated however it is styled.

   .appms__ico svg carries an explicit size. The icons are inline SVGs with a
   viewBox and no width attribute, so without it they expand to fill the tile
   and the screen turns into one enormous speech bubble. */
.appms{display:grid;grid-template-columns:1fr 1fr;gap:10px;}
.appms__t{display:flex;flex-direction:column;gap:5px;padding:15px;text-decoration:none;border-radius:var(--radius-card);
  min-height:104px;justify-content:flex-end;background:var(--paper);border:1px solid var(--line);
  color:var(--ink);transition:transform .18s var(--ease-out);}
.appms__t:active{transform:scale(.985);}
.appms__ico{width:26px;height:26px;margin-bottom:auto;color:var(--cyan-deep);}
.appms__ico svg{width:26px;height:26px;}
.appms__t b{font-family:var(--font-display);font-weight:600;font-size:.97rem;line-height:1.2;}
.appms__t small{color:var(--muted);font-size:.75rem;line-height:1.3;}
/* ══ photo tiles ═══════════════════════════════════════════════════════
   A square whose subject actually has a photograph. Only squares: the lead
   and wide tiles carry the church's own color and a picture behind those
   turns a brand banner into a stock slide.

   The image is a real <img> rather than a background, so it lazy-loads, is
   sized by the browser and costs nothing on a tile scrolled past. The label
   rides a bottom-up scrim — that gradient, not the photo, is what guarantees
   white text stays legible when somebody swaps a bright picture in later. */
.appms__t--photo{position:relative;overflow:hidden;isolation:isolate;
  min-height:132px;border-color:transparent;color:#fff;}
.appms__ph{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:-2;
  transition:transform .5s var(--ease-out);}
/* Measured against the brightest photo in the set: at .88/.52/.10 the small
   line under the title was washing out wherever the picture went pale. The
   scrim is the only thing guaranteeing contrast — the photograph itself is
   whatever somebody uploads next year — so it carries further up the tile and
   sits heavier at the bottom. The picture still reads; the words always win. */
.appms__t--photo::after{content:"";position:absolute;inset:0;z-index:-1;
  background:linear-gradient(to top,rgba(6,16,28,.94) 0%,rgba(6,16,28,.76) 30%,
    rgba(6,16,28,.42) 62%,rgba(6,16,28,.20) 100%);}
/* The picture moves inside its frame on press, not the whole tile — a tile
   that shrinks drags its neighbours' shadows with it. */
.appms__t--photo:active .appms__ph{transform:scale(1.04);}
.appms__t--photo .appms__ico{color:#fff;opacity:.92;
  filter:drop-shadow(0 1px 4px rgba(4,12,22,.55));}
.appms__t--photo b{color:#fff;text-shadow:0 1px 5px rgba(4,12,22,.45);}
.appms__t--photo small{color:rgba(255,255,255,.93);text-shadow:0 1px 4px rgba(4,12,22,.55);}
/* Themed app shells re-color every tile from their own tokens; a photo tile
   sets its own contrast, so it opts out of all of that. */
/* Doubling the class is not decoration. body[class*="ath-"] .appms__t small
   and body[class*="ath-"] .appms__t--photo small score identically — an
   attribute selector counts as a class, so both are (0,2,2) — and the themed
   rule is written later in this file, so it was quietly winning and painting
   the sub-line muted grey on top of a photograph. .appms__t.appms__t--photo
   takes it to (0,3,2) and settles it on specificity rather than on which of
   us edited the file last. */
body[class*="ath-"] .appms__t.appms__t--photo{background:transparent;border-color:transparent;color:#fff;}
body[class*="ath-"] .appms__t.appms__t--photo b{color:#fff;}
body[class*="ath-"] .appms__t.appms__t--photo small{color:rgba(255,255,255,.93);}
body[class*="ath-"] .appms__t.appms__t--photo .appms__ico{color:#fff;}
@media(prefers-reduced-motion:reduce){
  .appms__ph{transition:none;}
  .appms__t--photo:active .appms__ph{transform:none;}
}
.appms__t--wide{grid-column:1 / -1;min-height:92px;padding:17px 18px;
  background:color-mix(in srgb,var(--cyan) 12%,var(--snow));border-color:transparent;}
.appms__t--wide b{font-size:1.14rem;letter-spacing:-.01em;}
.appms__t--wide small{font-size:.8rem;}
.appms__t--lead{grid-column:1 / -1;min-height:96px;padding:18px;border:0;color:#fff;
  background:linear-gradient(150deg,var(--cyan-deep),var(--navy));box-shadow:0 12px 30px rgba(7,20,38,.2);}
.appms__t--lead .appms__ico{color:#fff;opacity:.92;width:28px;height:28px;}
.appms__t--lead .appms__ico svg{width:28px;height:28px;}
.appms__t--lead b{font-size:1.2rem;letter-spacing:-.015em;font-weight:700;}
.appms__t--lead small{color:#fff;opacity:.84;font-size:.82rem;}
@media(prefers-reduced-motion:reduce){
  .appms__t{transition:none !important;}
}
.appdash__foot{text-align:center;color:var(--muted);font-size:.72rem;letter-spacing:.04em;padding-top:4px;}
/* "Tonight" strip — shows only when an event is happening today */
.apptonight{display:flex;align-items:center;gap:12px;background:color-mix(in srgb,var(--cyan) 10%,#fff);
  border:1px solid color-mix(in srgb,var(--cyan) 32%,#fff);border-radius:var(--radius-card);padding:12px 14px;color:var(--navy);}
/* The serving strip is the one line on this screen that is about you
   personally, so it reads as a card you can press rather than another tinted
   notice. White needs help separating from the off-white page behind it —
   that is what the neutral hairline and the shallow shadow are for. The dot
   and the chevron keep their cyan, because those are the parts saying "live"
   and "there is more". */
.apptonight--serve{background:#fff;border-color:var(--line);
  box-shadow:0 1px 2px rgba(47,33,69,.05),0 8px 20px -12px rgba(47,33,69,.28);}
.apptonight--serve:active{transform:scale(.99)}
.apptonight__dot{flex:none;width:10px;height:10px;border-radius:50%;background:var(--cyan);position:relative;}
.apptonight__dot::after{content:"";position:absolute;inset:-4px;border-radius:50%;border:2px solid color-mix(in srgb,var(--cyan) 55%,transparent);animation:tnpulse 2.2s ease-out infinite;}
@keyframes tnpulse{0%{transform:scale(1);opacity:.75}100%{transform:scale(2.2);opacity:0}}
.apptonight__t{flex:1;min-width:0;display:flex;flex-direction:column;}
.apptonight__t b{font-family:var(--font-display);font-size:.92rem;}
.apptonight__t small{color:var(--ink-soft);font-size:.8rem;margin-top:1px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.apptonight__chev{flex:none;width:16px;height:16px;color:var(--cyan-deep);}

/* ═══ App home color themes — picked in the member profile; home screen only.
   Each theme sets a small palette; the overrides below repaint the dashboard. ═══ */
/* =========================================================================
   App color themes — eight palettes, each with a light and a dark set.

   Every value here is generated, not eyeballed, and the generator refuses to
   emit a palette whose text fails WCAG AA against every surface it can land
   on. That matters because the previous --muted shipped at 3.20:1 across 337
   uses; secondary text is now 4.8-5.5:1 in all sixteen combinations.

   Two accent roles, deliberately kept apart:
     --aac   a FILL. Only needs to be visible (3:1), so it stays saturated.
     --aacd  accent as TEXT. Needs 4.5:1, so it's deeper.
   Collapsing those two is what makes most dark modes look washed out.
   ========================================================================= */
/* =========================================================================
   App color themes.

   Every value is generated and contrast-checked, not eyeballed: the generator
   refuses to emit a palette whose text fails WCAG AA against any surface it
   can land on. Secondary text sits at 4.9-5.4:1 across all six, where the old
   --muted shipped at 3.20:1 over 337 uses.

   Two accent roles, deliberately separate:
     --aac   a FILL. Only needs to be visible (3:1), so it stays saturated.
     --aacd  accent as TEXT. Needs 4.5:1, so it's deeper.
   Collapsing those two is what makes a palette look washed out.

   Dark ramps are emitted too but nothing adds html.dark right now — see
   app_mode() in inc/portal.php.
   ========================================================================= */
body.ath-sanctuary{--ab:#f8f6fa;--ai:#38164f;--am:#586474;--ac1:#075676;--ac2:#38164f;--abr:#8ccedf;--aac:#9b7d29;--aacd:#007896;--aacink:#111111;--arow:#fbf9f5;--aline:#d5dae1;--aicobg:#cfe8f0;--asurf:#fcfdfe;--aglow:rgba(160,122,42,.42);}
html.dark body.ath-sanctuary{--ab:#190b25;--ai:#fbf9f5;--am:#7e838a;--ac1:#065c7c;--ac2:#2b123e;--abr:#9b7d29;--aac:#9b7d29;--aacd:#1a9dbe;--aacink:#0d0f12;--arow:#261037;--aline:#3f2f4d;--aicobg:#062f44;--asurf:#210f2f;--aglow:rgba(160,122,42,.42);}
body.ath-kashmir{--ab:#e6f1ef;--ai:#004b3d;--am:#40655e;--ac1:#0c6a58;--ac2:#004b3d;--abr:#abe1d6;--aac:#1a8f7a;--aacd:#167866;--aacink:#111111;--arow:#f4f9f8;--aline:#c6dad6;--aicobg:#c5e1dc;--asurf:#f8fbfb;--aglow:rgba(26,143,122,.42);}
html.dark body.ath-kashmir{--ab:#001c17;--ai:#f5f9f9;--am:#889896;--ac1:#0d6d5c;--ac2:#00382e;--abr:#48a595;--aac:#1a8f7a;--aacd:#5fb1a2;--aacink:#0d0f12;--arow:#003229;--aline:#254c45;--aicobg:#054136;--asurf:#002d25;--aglow:rgba(26,143,122,.42);}
body.ath-peonyblush{--ab:#ffe4e1;--ai:#830f42;--am:#8c435f;--ac1:#c42a69;--ac2:#ad1457;--abr:#ffe6f0;--aac:#e0447f;--aacd:#b33666;--aacink:#111111;--arow:#fff3f2;--aline:#f4c7ce;--aicobg:#facad1;--asurf:#fff7f7;--aglow:rgba(224,68,127,.42);}
html.dark body.ath-peonyblush{--ab:#420821;--ai:#fff4f3;--am:#bc9fa7;--ac1:#c62c6b;--ac2:#820f41;--abr:#eb87ad;--aac:#e24f87;--aacd:#ef9ebc;--aacink:#0d0f12;--arow:#740d3a;--aline:#802f50;--aicobg:#801945;--asurf:#680c34;--aglow:rgba(226,79,135,.42);}
body.ath-violetdusk{--ab:#f8f4e9;--ai:#4f256d;--am:#685975;--ac1:#653788;--ac2:#4f256d;--abr:#ccb7e1;--aac:#824bad;--aacd:#824bad;--aacink:#ffffff;--arow:#fcfaf5;--aline:#e0d8d4;--aicobg:#e8dad6;--asurf:#fdfcf9;--aglow:rgba(147,80,115,.42);}
html.dark body.ath-violetdusk{--ab:#1d0f29;--ai:#fcfbf6;--am:#958d8f;--ac1:#68388c;--ac2:#3b1c52;--abr:#a683c5;--aac:#8c5bb3;--aacd:#b091cc;--aacink:#ffffff;--arow:#35194a;--aline:#4e3c5d;--aicobg:#422458;--asurf:#2f1742;--aglow:rgba(156,94,126,.42);}
body.ath-sunset{--ab:#fae5b3;--ai:#722d08;--am:#7f4d2a;--ac1:#c24800;--ac2:#ac3d00;--abr:#fbf6ea;--aac:#dc5b12;--aacd:#a8460e;--aacink:#111111;--arow:#fcf3dd;--aline:#ead299;--aicobg:#edd396;--asurf:#fdf8ea;--aglow:rgba(220,91,18,.42);}
html.dark body.ath-sunset{--ab:#461b05;--ai:#fdf5e1;--am:#c2b8a0;--ac1:#d15410;--ac2:#8a360a;--abr:#f3a376;--aac:#ec6e26;--aacd:#f6bd9c;--aacink:#0d0f12;--arow:#7b3009;--aline:#854823;--aicobg:#87380e;--asurf:#6e2b08;--aglow:rgba(236,110,38,.42);}
body.ath-marple{--ab:#ffeade;--ai:#851a35;--am:#8f4856;--ac1:#d1334d;--ac2:#ba1144;--abr:#fff5f4;--aac:#e05b5a;--aacd:#b24847;--aacink:#111111;--arow:#fff6f0;--aline:#f8cfca;--aicobg:#fad3c9;--asurf:#fff9f6;--aglow:rgba(224,91,90,.42);}
html.dark body.ath-marple{--ab:#4d0f1f;--ai:#fff7f2;--am:#c9b1b2;--ac1:#e4485c;--ac2:#981e3d;--abr:#ff9594;--aac:#ff6766;--aacd:#ffb3b2;--aacink:#0d0f12;--arow:#871b36;--aline:#8e3a4d;--aicobg:#94283c;--asurf:#791831;--aglow:rgba(255,103,102,.42);}

html.dark body.ath-sanctuary{--paper:#190b25;--bg:#190b25;--ink:#fbf9f5;--ink-soft:#fbf9f5;--muted:#7e838a;--line:#3f2f4d;--cream:#210f2f;--cream-2:#261037;--snow:#190b25;}
html.dark body.ath-kashmir{--paper:#001c17;--bg:#001c17;--ink:#f5f9f9;--ink-soft:#f5f9f9;--muted:#889896;--line:#254c45;--cream:#002d25;--cream-2:#003229;--snow:#001c17;}
html.dark body.ath-peonyblush{--paper:#420821;--bg:#420821;--ink:#fff4f3;--ink-soft:#fff4f3;--muted:#bc9fa7;--line:#802f50;--cream:#680c34;--cream-2:#740d3a;--snow:#420821;}
html.dark body.ath-violetdusk{--paper:#1d0f29;--bg:#1d0f29;--ink:#fcfbf6;--ink-soft:#fcfbf6;--muted:#958d8f;--line:#4e3c5d;--cream:#2f1742;--cream-2:#35194a;--snow:#1d0f29;}
html.dark body.ath-sunset{--paper:#461b05;--bg:#461b05;--ink:#fdf5e1;--ink-soft:#fdf5e1;--muted:#c2b8a0;--line:#854823;--cream:#6e2b08;--cream-2:#7b3009;--snow:#461b05;}
html.dark body.ath-marple{--paper:#4d0f1f;--bg:#4d0f1f;--ink:#fff7f2;--ink-soft:#fff7f2;--muted:#c9b1b2;--line:#8e3a4d;--cream:#791831;--cream-2:#871b36;--snow:#4d0f1f;}

/* -- Quarry ---------------------------------------------------------------
   The seventh light theme, and the one the other six do not offer: nearly
   achromatic. Chroma stays under .03 everywhere, so it reads as stone rather
   than as a blue theme, for anyone who finds the rest too colorful. */
body.ath-quarry{--ab:#eef1f4;--ai:#2b333d;--am:#54595f;--ac1:#445568;--ac2:#2b333d;--abr:#bdc7d3;--aac:#546a83;--aacd:#4b5e74;--aacink:#111111;--arow:#fbfbfb;--aline:#d3d6da;--aicobg:#ccd3db;--asurf:#fdfdfd;--aglow:rgba(84,106,131,0.42);}

/* -- Compline -------------------------------------------------------------
   Dark as a palette you pick, not a mode that switches. There is no toggle,
   no class written before first paint and nothing to flash, because from the
   stylesheet's point of view this is just the eighth theme.

   Warm rather than blue-black: the point is evening reading, and a cool dark
   reads clinical. Amber because it is the one accent that holds AA on
   near-black without going neon. */
body.ath-compline{--ab:#170d20;--ai:#eef2f9;--am:#8f9db4;--ac1:#1c4b5a;--ac2:#141d2e;--abr:#f5e1b2;--aac:#dfc17a;--aacd:#f0d89e;--aacink:#170d20;--arow:#172032;--aline:#3d284e;--aicobg:#173341;--asurf:#111827;--aglow:rgba(127,214,234,.42);}

/* Where the light themes only repaint the app components, a dark one has to
   carry the site ramp as well — the tokens the others inherit from :root.
   Scoped to the installed app and to the theme preview, which is exactly what
   the picker promises ("how the app looks on your phone"). Public pages in a
   browser are untouched for everyone. */
html.app-mode body.ath-compline,
body.emb.ath-compline{
  color-scheme:dark;
  --navy:#0e1523;--snow:#170d20;--charcoal:#c6d0e0;--cyan:#dfc17a;--paper:#170d20;--bg:#170d20;--cream:#111827;--cream-2:#172032;--ink:#eef2f9;--ink-soft:#c6d0e0;--muted:#8f9db4;--ink-strong:var(--ink);--ink-invert:var(--ink);--ink-invert-soft:var(--ink-soft);--card:var(--cream);--line:#3d284e;--cyan-deep:#f0d89e;--cyan-bright:#f5e1b2;--shadow-sm:0 1px 2px rgba(0,0,0,.55),0 2px 10px rgba(0,0,0,.45);--shadow-md:0 12px 36px rgba(0,0,0,.6),0 2px 8px rgba(0,0,0,.45);--shadow-lg:0 28px 70px rgba(0,0,0,.7);
  background:var(--paper);color:var(--ink);
}
/* Buttons name the brand primitives directly: .btn is --bg:var(--navy) with
   --fg:var(--paper). In every light theme that reads "dark fill, light text".
   In a dark palette both are near-black, and the shipped button measured
   1.06:1 — the label was simply not there.

   The rule itself is fine; it already exposes the two variables that decide
   this, so only the values change. --aacink exists for exactly this job:
   whatever reads on the accent fill. */
html.app-mode body.ath-compline .btn,
body.emb.ath-compline .btn,
html.app-mode body.ath-compline .btn--accent,
body.emb.ath-compline .btn--accent{--bg:var(--aac);--fg:var(--aacink);}
html.app-mode body.ath-compline .btn--member,
body.emb.ath-compline .btn--member{--bg:var(--aac);--fg:var(--aacink);box-shadow:inset 0 0 0 1.5px var(--aac);}
html.app-mode body.ath-compline .btn--light,
body.emb.ath-compline .btn--light{--bg:var(--ink);--fg:var(--paper);}
html.app-mode body.ath-compline .btn--ghost,
body.emb.ath-compline .btn--ghost{box-shadow:inset 0 0 0 1.5px color-mix(in srgb,var(--ink) 34%,transparent);}
/* The old html.dark mode has the same shape of bug and would need the same
   block. It is left alone deliberately: nothing sets that class today, and a
   rule for a mode that never runs is a rule nobody will remember to test. */

/* Photographs and logos are not chrome — never dim them. */
html.app-mode body.ath-compline img,
html.app-mode body.ath-compline video,
html.app-mode body.ath-compline .fill{filter:none;}

html.app-mode body[class*="ath-"].page-home{background:var(--ab);}
body[class*="ath-"] .appdash__kick{color:var(--aacd);}
body[class*="ath-"] .appdash__greet{color:var(--ai);}
body[class*="ath-"] .appdash__avatar{background:var(--ac2);}
body[class*="ath-"] .appcard--sunday{background:linear-gradient(155deg,var(--ac1),var(--ac2));}
body[class*="ath-"] .appcard--sunday::after{background:radial-gradient(70% 60% at 85% 0%,var(--aglow),transparent 60%);}
body[class*="ath-"] .appweek .is-today b{color:var(--ac2);}
body[class*="ath-"] .appweek .is-sun{color:var(--abr);}
body[class*="ath-"] .appcard__body .appk,
body[class*="ath-"] .appcard__body h2 .serif,
body[class*="ath-"] .appweekly b{color:var(--abr);}
body[class*="ath-"] .appfeature__body .appk{color:var(--abr);}
body[class*="ath-"] .applist__row{background:var(--arow);border-color:var(--aline);}
body[class*="ath-"] .applist__row b{color:var(--ai);}
body[class*="ath-"] .applist__row small,body[class*="ath-"] .applist__chev{color:var(--am);}
body[class*="ath-"] .applist__ico{background:var(--aicobg);color:var(--aacd);}
/* the tiles, per theme — same var mapping the rows used */
body[class*="ath-"] .applist__lbl{color:var(--aacd);}
body[class*="ath-"] .appms__t{background:var(--arow);border-color:var(--aline);color:var(--ai);}
body[class*="ath-"] .appms__t small{color:var(--am);}
body[class*="ath-"] .appms__ico{color:var(--aacd);}
body[class*="ath-"] .appms__t--wide{background:var(--aicobg);border-color:transparent;}
body[class*="ath-"] .appms__t--lead{background:linear-gradient(150deg,var(--ac1),var(--ac2));color:#fff;border-color:transparent;}
body[class*="ath-"] .appms__t--lead .appms__ico{color:#fff;}
body[class*="ath-"] .appms__t--lead b{color:#fff;}
body[class*="ath-"] .appms__t--lead small{color:#fff;}
body[class*="ath-"] .apptonight{background:var(--aicobg);border-color:var(--aline);color:var(--ai);}
/* The strip was picking up --aicobg, which is the theme's tinted icon chip —
   that pale blue is Sanctuary's. The serving line is a card you press, not a
   chip, so it takes --arow: the same surface the member tiles and the push
   card already sit on. White on the seven light themes, and correctly dark
   on Compline, rather than a hardcoded #fff that would blind that one. */
body[class*="ath-"] .apptonight--serve{background:var(--arow);border-color:var(--aline);}
body[class*="ath-"] .apptonight__dot{background:var(--aac);}
body[class*="ath-"] .apptonight__dot::after{border-color:var(--aac);}
body[class*="ath-"] .apptonight__t small{color:var(--am);}
body[class*="ath-"] .apptonight__chev{color:var(--aacd);}
body[class*="ath-"] .apppush{background:var(--arow);border-color:var(--aline);}
body[class*="ath-"] .apppush__ic{background:var(--aac);}
body[class*="ath-"] .apppush__tx b{color:var(--ai);}
body[class*="ath-"] .apppush__tx small{color:var(--am);}
body[class*="ath-"] .appdash__foot{color:var(--am);}
/* the inline-styled cards on the home page need a nudge */
body[class*="ath-"] .appcontinue{background:var(--arow) !important;border-color:var(--aline) !important;}
body[class*="ath-"] .appcontinue__body .appk{color:var(--aacd) !important;}
body[class*="ath-"] .appcountdown{background:linear-gradient(160deg,var(--ac2),var(--ac1)) !important;}
body[class*="ath-"] .appcountdown__k{color:var(--abr) !important;}
/* ---- contrast repair (see §2b) --------------------------------------------
   .appweekly i and .appweek span were rgba(255,255,255,.72) and .60 over the
   Sunday card. On the warmer palettes that measured 3.2:1 and 2.6:1 — under
   AA for normal text. Size and weight already separate them from the titles,
   so the alpha was buying nothing but a legibility problem.

   .appchip was rgba(255,255,255,.16), which lightened the gradient beneath it
   and made white-on-chip the worst pairing on the card in every theme. Sunk
   into the card instead of floating on it, it now improves contrast rather
   than eroding it. */
.appweekly i{color:#fff;opacity:.96;}
.appweek span{color:rgba(255,255,255,.88);}
.appweek b{color:#fff;}
.appchip{background:rgba(0,0,0,.20);box-shadow:inset 0 0 0 1px rgba(255,255,255,.24);}


/* =========================================================
   EDITORIAL LAYER — typography craft, pull quotes, lead story
   ========================================================= */

/* Kicker rule — a short tick beside section eyebrows */
.head .eyebrow,.split__copy .eyebrow{display:inline-flex;align-items:center;gap:.7em;}
.head .eyebrow::before,.split__copy .eyebrow::before{content:"";width:26px;height:1.5px;background:currentColor;opacity:.55;}
.head.center .eyebrow{justify-content:center;}
.head.center .eyebrow::after{content:"";width:26px;height:1.5px;background:currentColor;opacity:.55;}

/* Lede — a larger, lighter standfirst paragraph */
.lede{font-size:clamp(1.16rem,1rem + .8vw,1.5rem);line-height:1.55;color:var(--ink-soft);font-weight:400;letter-spacing:-.01em;}

/* Drop cap — Fraunces initial on a lead paragraph */
.dropcap::first-letter{float:left;font-family:var(--font-serif);font-style:italic;font-weight:400;
  font-size:3.5em;line-height:.72;padding:.04em .1em 0 0;color:var(--cyan-deep);}

/* Pull quotes — refined cite with rule (decorative quote mark removed) */
.quote blockquote{position:relative;}
.quote cite{position:relative;display:inline-flex;align-items:center;gap:.7em;}
.quote cite::before{content:"";width:34px;height:1.5px;background:currentColor;opacity:.5;}

/* Numbered editorial badge (Who We Are pillars) */
.card__num{font-family:var(--font-serif);font-style:italic;font-size:1.9rem;line-height:1;
  color:var(--cyan-deep);display:block;margin-bottom:6px;}
.card .kicker + h3{margin-top:2px;}

/* Small-caps photo caption */
.figcap{margin-top:10px;font-size:.7rem;letter-spacing:.16em;text-transform:uppercase;
  color:var(--muted);font-weight:600;display:flex;align-items:center;gap:.6em;}
.figcap::before{content:"";width:18px;height:1.5px;background:var(--cyan);opacity:.7;}

/* Sermons lead story — magazine cover feature */
.leadstory{display:grid;grid-template-columns:1.5fr 1fr;gap:clamp(28px,5vw,64px);align-items:center;}
.leadstory__media .vidcard{box-shadow:var(--shadow-md);}
.leadstory__kicker{font-family:var(--font-body);text-transform:uppercase;letter-spacing:.22em;font-size:.72rem;font-weight:700;color:var(--cyan-deep);display:inline-flex;align-items:center;gap:.7em;}
.leadstory__kicker::before{content:"";width:26px;height:1.5px;background:currentColor;opacity:.6;}
.leadstory__title{font-family:var(--font-serif);font-style:italic;font-weight:400;
  font-size:clamp(2rem,1.4rem + 2.4vw,3.4rem);line-height:1.04;letter-spacing:-.01em;color:var(--ink);margin-top:var(--space-md);}
.leadstory__meta{margin-top:var(--space-sm);color:var(--muted);font-size:.92rem;font-weight:600;letter-spacing:.02em;}
.leadstory__copy .btn{margin-top:var(--space-lg);}
@media(max-width:860px){.leadstory{grid-template-columns:1fr;}}

/* Header (frosted) card text dialed down ~30% for a calmer, more refined header */
.banner__card{max-width:560px;padding:clamp(20px,2.4vw,32px);}
.banner__card h1{font-size:clamp(1.7rem,1.15rem + 2.4vw,3.05rem);}
.banner__card p{font-size:clamp(.9rem,.86rem + .26vw,1.02rem);margin-top:var(--space-sm);}
.banner__card .eyebrow{font-size:.6rem;}
.banner__card .crumb{font-size:.72rem;margin-bottom:var(--space-sm);}

/* Event row with a promo image (calendar + events list) */
.vrow__img{width:clamp(116px,16vw,184px);aspect-ratio:16/10;border-radius:var(--radius-sm);overflow:hidden;flex-shrink:0;background:var(--navy);align-self:stretch;}
.vrow__img img{width:100%;height:100%;object-fit:cover;transition:transform .6s var(--ease-out);}
.vrow--img:hover .vrow__img img{transform:scale(1.06);}
@media(max-width:620px){.vrow--img{grid-template-columns:auto 1fr;}.vrow__img{width:108px;height:auto;aspect-ratio:auto;align-self:center;background:transparent;}.vrow__img img{height:auto;object-fit:contain;}}

/* ===== Summer Chapel — dark page + floating photo gallery ===== */
.scpage{background:#0a1726;color:var(--ink-invert-soft);}
.scpage--deep{background:#060d16;}
.scpage h2{color:#fff;}
.scpage .head .eyebrow{color:var(--teal);}
.scpage .lead p{color:rgba(255,255,255,.84);}
.scpage .lead strong{color:var(--teal);}
.scfloat{position:relative;height:clamp(360px,48vw,560px);margin-top:var(--space-lg);}
.scfloat__t{position:absolute;border-radius:14px;overflow:hidden;background:#11243a;box-shadow:0 22px 48px rgba(0,0,0,.5);opacity:0;will-change:transform,opacity;}
.scfloat__t img{width:100%;height:100%;object-fit:cover;display:block;}
.scfloat__hint{text-align:center;margin-top:var(--space-md);color:rgba(255,255,255,.5);font-size:.82rem;letter-spacing:.04em;}
@media(hover:none){.scfloat__hint{display:none;}}
@media(max-width:640px){
  .scfloat{height:clamp(320px,92vw,440px);}
  .scfloat__t--desk{display:none;}
}
/* hold tiles still + visible while an admin is editing the page */
body.edit-mode .scfloat__t{opacity:1 !important;transform:none !important;}

/* ===== Custom builder pages: gallery + embed ===== */
.cmsgal{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,240px),1fr));gap:14px;margin-top:var(--space-lg);}
.cmsembed__v{position:relative;max-width:900px;margin:0 auto;aspect-ratio:16/9;border-radius:var(--radius);overflow:hidden;box-shadow:var(--shadow-md);background:var(--navy);}
.cmsembed__v iframe{position:absolute;inset:0;width:100%;height:100%;border:0;}

/* ===== Image lightbox (Creed / Covenant graphics, etc.) ===== */
.lightbox{position:fixed;inset:0;z-index:300;display:none;place-items:center;padding:24px;background:rgba(7,16,30,.88);backdrop-filter:blur(4px);}
.lightbox.is-open{display:grid;animation:lbfade .25s var(--ease-out);}
@keyframes lbfade{from{opacity:0;}to{opacity:1;}}
.lightbox img{max-width:min(620px,94vw);max-height:92vh;width:auto;height:auto;border-radius:12px;box-shadow:0 30px 90px rgba(0,0,0,.6);}
.lightbox__x{position:absolute;top:calc(env(safe-area-inset-top,0px) + 16px);right:16px;width:46px;height:46px;border-radius:50%;border:0;background:rgba(255,255,255,.16);color:#fff;font-size:1.5rem;line-height:1;cursor:pointer;display:grid;place-items:center;transition:background .2s,transform .2s var(--ease-out);}
.lightbox__x:hover{background:rgba(255,255,255,.28);transform:rotate(90deg);}
/* A labelled way out, top-left where a back control belongs — next to the cross
   rather than instead of it, because the person looking for a × and the person
   looking for the word "back" are not always the same person. */
.lightbox__back{position:absolute;top:calc(env(safe-area-inset-top,0px) + 16px);left:16px;min-height:46px;padding:0 18px 0 13px;
  border:0;border-radius:100px;background:rgba(255,255,255,.16);color:#fff;font:inherit;
  font-size:.95rem;font-weight:600;cursor:pointer;display:inline-flex;align-items:center;gap:7px;
  transition:background .2s;}
.lightbox__back:hover{background:rgba(255,255,255,.28);}
.lightbox__back svg{width:1.15em;height:1.15em;flex:none;}
/* A PDF read as pictures of its pages: one column that scrolls like anything
   else, rather than an iframe the phone will not let you move inside. The top
   padding is the room the Back control stands in. */
.lightbox--doc .lightbox__pages{width:min(980px,94vw);max-height:100vh;overflow:auto;overscroll-behavior:contain;
  -webkit-overflow-scrolling:touch;
  padding:calc(env(safe-area-inset-top,0px) + 76px) 0 calc(env(safe-area-inset-bottom,0px) + 28px);}
.lightbox--doc .lightbox__page{display:block;width:100%;height:auto;background:#fff;border-radius:6px;
  box-shadow:0 10px 30px rgba(0,0,0,.38);margin:0 auto 14px;}
.lightbox--doc .lightbox__page:last-child{margin-bottom:0;}
.lightbox__wait{color:#fff;opacity:.78;text-align:center;margin:0;padding:44px 0;font-size:.95rem;}
/* A PDF opened in the lightbox. An image sizes itself to its own dimensions; a
   document viewer has none of its own, so it is given a generous sheet of the
   viewport instead — tall, because these are pages of text meant to be read. */
.lightbox--doc{padding:16px;}
.lightbox__doc{width:min(900px,96vw);height:min(88vh,1100px);border:0;border-radius:var(--radius-inset);
  background:#fff;box-shadow:0 30px 90px rgba(0,0,0,.6);}
.lightbox__doc[hidden]{display:none;}
.lightbox--doc img{display:none;}
.lightbox__open{position:absolute;bottom:18px;left:50%;transform:translateX(-50%);
  color:#fff;font-size:.82rem;font-weight:600;letter-spacing:.02em;text-decoration:none;
  background:rgba(255,255,255,.16);padding:.55em 1.1em;border-radius:100px;transition:background .2s;}
.lightbox__open:hover{background:rgba(255,255,255,.3);}
.lightbox__open[hidden]{display:none;}
@media(max-width:640px){
  .lightbox--doc{padding:10px;}
  .lightbox__doc{width:100%;height:82vh;}
  .lightbox__open{bottom:10px;}
}

/* ===== Push notifications: friendly ask toast + "blocked" help sheet ===== */
.pushtoast{position:fixed;left:50%;bottom:calc(20px + env(safe-area-inset-bottom,0px));transform:translate(-50%,140%);z-index:240;display:flex;align-items:center;gap:16px;width:min(460px,calc(100vw - 28px));background:rgba(47,33,69,.86);backdrop-filter:blur(18px) saturate(1.5);-webkit-backdrop-filter:blur(18px) saturate(1.5);border:1px solid rgba(255,255,255,.16);border-radius:var(--radius-card);padding:14px 18px;box-shadow:0 24px 60px rgba(7,20,38,.45);transition:transform .5s var(--ease-out),opacity .4s;opacity:0;}
.pushtoast.is-in{transform:translate(-50%,0);opacity:1;}
html.app-mode .pushtoast{bottom:calc(96px + env(safe-area-inset-bottom,0px));}   /* clear the app bottom bar */
.pushtoast__txt{flex:1;min-width:0;color:rgba(249,250,253,.85);font-size:.82rem;line-height:1.4;}
.pushtoast__txt strong{display:block;color:#fff;font-family:var(--font-display);font-size:.92rem;margin-bottom:1px;}
.pushtoast__btns{display:flex;flex-direction:column;align-items:stretch;gap:6px;flex-shrink:0;}
.pushtoast__btns .btn{--bg:var(--cyan);padding:.55em 1.15em;font-size:.82rem;justify-content:center;}
.pushtoast__no{border:0;background:none;color:rgba(244,238,225,.6);font-family:var(--font-display);font-weight:600;font-size:.76rem;cursor:pointer;transition:color .2s;}
.pushtoast__no:hover{color:#fff;}

.pushhelp{position:fixed;inset:0;z-index:250;display:grid;place-items:end center;}
.pushhelp__backdrop{position:absolute;inset:0;background:rgba(7,18,33,.55);backdrop-filter:blur(3px);-webkit-backdrop-filter:blur(3px);opacity:0;transition:opacity .3s;}
.pushhelp.is-open .pushhelp__backdrop{opacity:1;}
.pushhelp__card{position:relative;width:min(480px,100vw);max-height:82vh;overflow:auto;background:var(--paper);border-radius:var(--radius-card) 24px 0 0;padding:26px 24px calc(26px + env(safe-area-inset-bottom,0px));box-shadow:0 -20px 60px rgba(7,20,38,.4);transform:translateY(30px);opacity:0;transition:transform .38s var(--ease-out),opacity .3s;}
@media(min-width:640px){.pushhelp{place-items:center;} .pushhelp__card{border-radius:var(--radius-card);padding-bottom:26px;}}
.pushhelp.is-open .pushhelp__card{transform:none;opacity:1;}
.pushhelp__card h3{font-size:1.3rem;letter-spacing:-.01em;}
.pushhelp__card p{color:var(--ink-soft);font-size:.92rem;margin-top:6px;}
.pushhelp__card ol{margin:14px 0 18px;padding-left:1.3em;display:grid;gap:8px;color:var(--ink-soft);font-size:.92rem;line-height:1.5;}
.pushhelp__card ol li::marker{color:var(--cyan-deep);font-weight:700;}
.pushhelp__card .btn{width:100%;justify-content:center;}
@media(prefers-reduced-motion:reduce){.pushtoast,.pushhelp__card,.pushhelp__backdrop{transition:none !important;}}

/* ===== Media request — "what happens next" ================================= */
.mrhelp{max-width:900px;}
.mrhelp h2{text-align:center;margin-bottom:28px;}
.mrsteps{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:20px;}
.mrstep{background:#fff;border:1px solid var(--line,#e3e8ef);border-radius:var(--radius-card);padding:24px 22px;
  box-shadow:0 1px 2px rgba(47,33,69,.06),0 4px 16px -8px rgba(47,33,69,.10);}
.mrstep__n{display:grid;place-items:center;width:32px;height:32px;border-radius:50%;
  background:color-mix(in srgb,var(--cyan,#9b7d29) 13%,#fff);
  color:color-mix(in srgb,var(--cyan,#9b7d29) 78%,var(--navy,#38164f));
  font-weight:800;font-size:.9rem;margin-bottom:12px;}
.mrstep strong{display:block;font-size:1.02rem;margin-bottom:6px;}
.mrstep p{color:var(--muted,#6d5f7b);font-size:.92rem;line-height:1.6;margin:0;}
.mrhelp__note{text-align:center;color:var(--muted,#6d5f7b);font-size:.92rem;max-width:56ch;margin:28px auto 0;}
@media(max-width:640px){.mrsteps{gap:14px;}.mrstep{padding:20px 18px;}}

/* ===== App launch splash ==================================================
   The home hero's photographs crossing a grainy navy wash around the church
   mark. Standalone (home-screen) launches only.

   THE ENTRANCE IS DRIVEN FROM JAVASCRIPT, NOT FROM HERE — deliberately.

   Three CSS attempts at this all failed the same way: the tiles would settle
   into place and then the animation would start over. A CSS animation begins
   the moment its rule matches, and there is no way to be certain that moment
   is after the photographs have decoded. Declaring it paused and unpausing via
   a class still leaves the browser free to run it during a style recalculation
   it does on its own schedule.

   So there is no @keyframes for the tiles at all. This file only describes
   where a tile SITS before anything happens: off screen and invisible. The
   controller in inc/header.php creates the animation with element.animate()
   once decode has finished. An animation that doesn't exist yet cannot start
   early, and cannot restart. */
.csplash{position:fixed;inset:0;z-index:99999;overflow:hidden;
  display:grid;place-items:center;background:transparent;}

/* Every opaque pixel is on this layer, so this leaving is what reveals the app. */
.csplash__bg{position:absolute;inset:0;background:#000;}
.csplash__bg::before{content:"";position:absolute;inset:0;opacity:0;
  background:radial-gradient(120% 100% at 28% 16%,#2f78b0 0%,#1a4571 38%,var(--navy,#38164f) 76%);}
/* The wash is the one thing still animated in CSS: it has no dependency on the
   photographs, so starting it at first paint is correct. */
.csplash.is-ready .csplash__bg::before{animation:csWashIn .7s ease both;}

/* Grain: a fine speckle over a coarser mottle, so a flat gradient doesn't read
   as digital. Stronger here than on the home page — no photography behind it. */
.csplash__bg::after{content:"";position:absolute;inset:0;pointer-events:none;
  mix-blend-mode:overlay;opacity:.5;
  background-size:170px 170px,340px 340px;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='600' height='600'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='600' height='600'%3E%3Cfilter id='m'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.35' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23m)'/%3E%3C/svg%3E");}
@keyframes csWashIn{ from{opacity:0} to{opacity:1} }

.csplash__scatter{position:absolute;inset:0;}

/* Resting state only. No animation, no keyframes — see the note above. */
.cstile{position:absolute;left:var(--l);top:var(--t);width:var(--w);aspect-ratio:var(--ar);
  border-radius:clamp(10px,2.6vw,16px);overflow:hidden;
  box-shadow:0 18px 44px rgba(0,0,0,.5);
  opacity:0;}
.cstile--l{transform:translate3d(-75vw,0,0);}
.cstile--r{transform:translate3d(75vw,0,0);}
/* Rotation lives on the image, which is never animated. */
.cstile img{width:100%;height:100%;object-fit:cover;display:block;
  transform:rotate(var(--r,0deg));}

.csplash__mark{position:relative;z-index:3;display:grid;place-items:center;opacity:0;}
.csplash__mark img{width:clamp(108px,30vw,168px);height:auto;display:block;
  filter:drop-shadow(0 12px 34px rgba(0,0,0,.55));}

/* Granted shortcuts in the app — the admin, a form, the CLC desk. Marked
   apart from the ordinary member rows with a tinted icon, so it reads as
   "something you've been given" rather than another menu item. */
.applist__row--extra .applist__ico{
  background:color-mix(in srgb,var(--cyan,#9b7d29) 15%,transparent);
  color:color-mix(in srgb,var(--cyan,#9b7d29) 82%,var(--ink,#38164f));}

/* ===== Members directory — households ====================================
   Modelled on the printed book: one photo, the family's name, then the people
   in it. Wide enough to read at a glance, dense enough that 312 families are
   still scannable. */
.pdirbar{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-bottom:var(--space-lg);}
.pdircount{color:var(--muted);font-size:.88rem;white-space:nowrap;}
.pdiraz{display:flex;flex-wrap:wrap;gap:4px;margin:0 0 var(--space-lg);position:sticky;top:0;z-index:4;
  background:var(--paper,#fff);padding:8px 0;}
.pdiraz a{display:inline-flex;align-items:center;justify-content:center;min-width:30px;height:30px;
  border-radius:8px;font-size:.82rem;font-weight:600;color:var(--muted);text-decoration:none;
  transition:background .14s,color .14s;}
.pdiraz a:hover{background:color-mix(in srgb,var(--cyan,#9b7d29) 14%,transparent);color:var(--navy,#38164f);}

.pdirltr{grid-column:1/-1;margin:var(--space-xl) 0 2px;font-size:.82rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--muted);font-weight:700;
  border-bottom:1px solid color-mix(in srgb,var(--ink,#38164f) 12%,transparent);padding-bottom:6px;}
.pdirltr:first-child{margin-top:0;}
.pdirltr[hidden]{display:none;}

.pdirhh{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:var(--space-md);align-items:start;}
.phh{display:flex;gap:14px;padding:14px;border-radius:var(--radius-card);background:var(--card,#fff);
  border:1px solid color-mix(in srgb,var(--ink,#38164f) 10%,transparent);
  transition:border-color .16s,box-shadow .16s,transform .16s;}
.phh:hover{border-color:color-mix(in srgb,var(--cyan,#9b7d29) 34%,transparent);
  box-shadow:0 10px 26px -14px rgba(47,33,69,.3);transform:translateY(-2px);}
.phh[hidden]{display:none;}

.phh__photo{flex:none;width:84px;aspect-ratio:4/5;border-radius:var(--radius-inset);overflow:hidden;
  background:color-mix(in srgb,var(--cyan,#9b7d29) 12%,transparent);
  display:flex;align-items:center;justify-content:center;}
.phh__photo img{width:100%;height:100%;object-fit:cover;display:block;}
.phh__initials{font-weight:700;font-size:1.15rem;color:var(--navy,#38164f);opacity:.62;letter-spacing:.02em;}

.phh__body{min-width:0;flex:1;}
.phh__name{margin:0;font-size:1.02rem;line-height:1.25;color:var(--ink,#38164f);
  overflow-wrap:anywhere;}
.phh__shared{margin:3px 0 0;font-size:.88rem;}
.phh__shared a{color:var(--muted);text-decoration:none;}
.phh__shared a:hover{color:var(--cyan,#9b7d29);text-decoration:underline;}

.phh__people{list-style:none;margin:8px 0 0;padding:0;display:grid;gap:6px;}
.phh__people li{font-size:.9rem;line-height:1.35;}
.phh__pn{display:block;font-weight:600;color:var(--ink,#38164f);}
.phh__pc{display:flex;flex-direction:column;gap:1px;margin-top:1px;}
.phh__pc a{color:var(--muted);text-decoration:none;font-size:.84rem;overflow-wrap:anywhere;}
.phh__pc a:hover{color:var(--cyan,#9b7d29);text-decoration:underline;}

@media(max-width:520px){
  .pdirhh{grid-template-columns:1fr;}
  .phh__photo{width:68px;}
}
/* The lift on hover is decoration, not information — the border still changes. */
@media(prefers-reduced-motion:reduce){
  .phh{transition:border-color .01s;}
  .phh:hover{transform:none;}
  .pdiraz a{transition:none;}
}

/* ------------------------------------------------- installed app: no footer
   The footer is a website's business card — address, socials, "add to home
   screen". Somebody already running the installed app has done all of that,
   so in standalone mode it's a long scroll to nothing.

   It's replaced by exactly the space the floating nav needs, so the last card
   on a page clears the bar instead of hiding behind it. Height is the bar
   (~62px) plus its 16px offset plus breathing room and the home indicator. */
html.app-mode .footer{display:none;}
html.app-mode main{padding-bottom:calc(env(safe-area-inset-bottom,0px) + 104px);}
/* The bar is only ever shown on small screens, so the reserve goes with it. */
@media (min-width:1041px){ html.app-mode main{padding-bottom:calc(env(safe-area-inset-bottom,0px) + 40px);} }

/* =========================================================================
   PRINTING
   -------------------------------------------------------------------------
   There was no print stylesheet on this site at all. Every page printed as a
   screenshot of a website: the navigation, the footer, the announcement bar,
   photographs bled to the edge, and the actual content squeezed into whatever
   was left. The CLC schedule is the first thing here anybody genuinely needs
   on paper — it goes on the wall behind the front desk and stays there for a
   month — so it gets a real one.

   The rule everything below follows: a printed page is a different document,
   not a photograph of a screen. Nothing that exists to be clicked survives.
   ========================================================================= */

@media print{
  /* Landscape, because a month is seven columns wide and nothing makes seven
     readable columns fit across a portrait page. */
  @page{ size:letter landscape; margin:11mm 10mm; }

  html,body{background:#fff !important;font-size:10pt;}
  body{overflow:visible;}

  /* Anything whose purpose is to be interacted with. A printed page has no
     hover, no tap and no next page — every one of these is either an
     instruction that can't be followed or ink spent on nothing. */
  .hdr,.header,.mobtop,.footer,.announce,.popup,.pop,.splash,.appnav,
  .banner,.crumb,.vsch__nav,.vsch__btn,.vclaim,.clc__signout,.vsch__actions,
  .skip,.js-push-enable,.footpush,[data-noprint]{ display:none !important; }

  /* Reveal the print-only masthead and footer, which never show on screen.
     Deliberately NOT !important: .vprint__head and .vprint__foot need to be
     flex, and an !important display:block here beats them and collapses both
     strips into one run-on line. The rule that hides these on screen is
     wrapped in @media screen instead, so there is nothing here to fight. */
  .vprint{ display:block; }

  main,.section,.wrap{ padding:0 !important;margin:0 !important;max-width:none !important; }
  section{ background:#fff !important; }

  /* Backgrounds carry meaning here — a closed day and an ordinary one differ
     only by their fill — so they must survive the browser's ink-saving. */
  .vmon,.vmon *,.vprint,.vprint *{ -webkit-print-color-adjust:exact;print-color-adjust:exact; }

  /* ---- the masthead ---- */
  .vprint__head{ display:flex;align-items:flex-end;gap:12pt;
    border-bottom:1.6pt solid #38164f;padding-bottom:4pt;margin-bottom:6pt; }
  .vprint__ttl{ margin-right:auto; }
  .vprint__eyebrow{ font-size:6.6pt;font-weight:700;letter-spacing:.22em;text-transform:uppercase;
    color:#9b7d29;margin-bottom:2pt; }
  .vprint__h{ font-family:"Hanken Grotesk",system-ui,sans-serif;font-size:17pt;font-weight:800;
    letter-spacing:-.02em;line-height:1;color:#38164f; }
  .vprint__h em{ font-family:"Fraunces",Georgia,serif;font-style:italic;font-weight:400; }
  .vprint__meta{ text-align:right;font-size:7.4pt;line-height:1.5;color:#3d4c5e; }
  .vprint__meta strong{ color:#38164f; }

  /* ---- the grid ---- */
  .vsch__mon{ display:block !important; }
  .vmon{ width:100%;border-collapse:collapse;table-layout:fixed;border:.8pt solid #a497b1;
    border-radius:0;box-shadow:none; }
  .vmon th{ background:#f2eef4 !important;border:.8pt solid #a497b1;padding:2.4pt 2pt;
    font-size:6.6pt;font-weight:700;letter-spacing:.16em;text-transform:uppercase;color:#41505f; }
  /* Six rows is the worst a month can be, so every cell is sized for six and
     a five-row month simply breathes. Sizing for the common case instead is
     how you get one month a year that silently loses its last line. */
  /* 23mm x 6 rows = 138mm, which leaves about 20mm of slack under the
     masthead and footer on Letter landscape. Sized with slack on purpose:
     browsers disagree by a millimetre or two about margins and font metrics,
     and "fits in Chrome" is not the same promise as "fits". */
  .vmon td{ border:.6pt solid #b9c4d0;vertical-align:top;padding:1.8pt 2.4pt;
    height:23mm;overflow:hidden; }
  .vmon td.is-out{ background:#f4f6f9 !important; }
  .vmon td.is-today{ background:#fff !important; }        /* "today" is a screen idea */

  .vmon__n{ font-family:"Hanken Grotesk",system-ui,sans-serif;font-size:9.2pt;font-weight:800;
    line-height:1;margin-bottom:2pt;color:#38164f;
    display:flex;align-items:baseline;justify-content:space-between;gap:3pt; }
  .vmon td.is-out .vmon__n{ color:#a497b1; }
  .vmon__wk{ font-size:5.8pt;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:#9b7d29; }

  .vmon__s{ display:grid;grid-template-columns:9mm 1fr;gap:1.6pt;margin-bottom:1.6pt; }
  .vmon__t{ font-size:6.4pt;font-weight:700;color:#9b7d29;line-height:1.15;padding-top:.3pt; }
  /* line-height carries a second job here. These spans are overflow:hidden so
     a long name can ellipsis, and at 1.16 the box ended exactly where the
     underline on a changed name sits — so the one mark that says "this is not
     the usual person" was being clipped away by the rule that shortens long
     names. 1.25 puts the descender space back and the underline inside the box. */
  .vmon__p span{ display:block;font-size:7.2pt;line-height:1.25;color:#38164f;font-weight:600;
    overflow:hidden;text-overflow:ellipsis;white-space:nowrap; }
  /* An open slot is the only thing on this sheet anybody has to act on, so on
     paper it is a rule to write on rather than the word "open" set in grey. */
  .vmon__p .is-open{ color:#887997;font-weight:400;font-style:normal;
    border-bottom:.5pt dotted #a497b1;min-height:7.2pt; }
  .vmon__p .is-chg{ color:#38164f;font-weight:800;text-decoration:underline;
    text-underline-offset:1pt;text-decoration-thickness:.5pt; }

  /* One page is the whole point. Nothing may push a seventh row onto a second
     sheet, and no row may be split across a fold. */
  .vmon tr,.vmon td{ break-inside:avoid;page-break-inside:avoid; }
  .vsch__mon{ break-after:avoid;page-break-after:avoid; }

  /* ---- the footer strip ---- */
  .vprint__foot{ display:flex;align-items:center;flex-wrap:wrap;gap:4pt 14pt;
    margin-top:5pt;padding-top:4pt;
    border-top:.8pt solid #b9c4d0;font-size:6.8pt;color:#41505f; }
  .vprint__foot strong{ color:#38164f; }
  .vprint__foot .sp{ margin-left:auto; }
  .vprint__k{ display:inline-block;width:7pt;height:7pt;border:.6pt solid #a497b1;
    vertical-align:-.5pt;margin-right:2.5pt; }
  .vprint__k--open{ background:#fff !important;border-bottom:1.2pt dotted #a497b1; }

  /* The week list and the roster are screen furniture on a month print. They
     have their own sheets — see the print=week and print=roster views. */
  body.printing-month .vsch__days,body.printing-month .vsch__roster{ display:none !important; }
  body.printing-roster .vsch__days,body.printing-roster .vsch__mon{ display:none !important; }

  /* ---- the roster sheet, when that is what's being printed ---- */
  .vroster{ border:.8pt solid #a497b1;box-shadow:none;border-radius:0; }
  .vroster th{ background:#f2eef4 !important;border-bottom:.8pt solid #a497b1;
    font-size:6.6pt;padding:3pt 4pt; }
  .vroster td{ border-top:.5pt solid #ccd4dd;font-size:8.4pt;padding:3pt 4pt;color:#38164f; }
  .vroster tr{ break-inside:avoid;page-break-inside:avoid; }
  .vroster td a{ color:#38164f;text-decoration:none; }

  /* Links elsewhere shouldn't print their href — this is a rota, not a
     bibliography, and "(https://…)" after every name would be noise. */
  a[href]::after{ content:none !important; }
}

/* The print masthead and footer exist in the markup on every schedule page so
   the browser's own print button produces the right document with nothing
   asked of anybody. They are simply never shown on a screen — and this is
   scoped to @media screen rather than left unscoped, so it cannot reach into
   the print rules above and undo them. */
@media screen{ .vprint{ display:none; } }


/* ══ Small groups: the message the questions came from ═══════════════════
   Sits between the prayer and the announcements, on the same 760px measure
   as every other block on that page so the column never wobbles. Built as a
   two-up rather than a stacked card: at reading width the thumbnail earns
   its place beside the title instead of pushing the announcements a whole
   screen further down. */
.sgserm{
  display:grid;grid-template-columns:minmax(0,196px) minmax(0,1fr);
  gap:clamp(15px,2.4vw,24px);align-items:center;
  max-width:760px;margin:var(--space-lg) auto 0;padding:14px;
  border-radius:var(--radius);background:var(--card,#fff);
  border:1px solid color-mix(in srgb,var(--ink,#38164f) 11%,transparent);
  box-shadow:0 10px 30px -20px rgba(47,33,69,.35);
  color:inherit;text-decoration:none;
  transition:box-shadow .3s cubic-bezier(.25,1,.5,1),border-color .3s cubic-bezier(.25,1,.5,1);
}
.sgserm:hover{border-color:color-mix(in srgb,var(--cyan) 45%,transparent);box-shadow:0 18px 44px -22px rgba(47,33,69,.5)}
.sgserm:focus-visible{outline:2px solid var(--cyan);outline-offset:3px}
.sgserm__thumb{position:relative;display:block;border-radius:calc(var(--radius) - 6px);overflow:hidden;background:var(--cream-2);aspect-ratio:16/9}
.sgserm__thumb img{width:100%;height:100%;object-fit:cover;display:block;
  transition:transform .55s cubic-bezier(.22,1,.36,1)}
/* The image moves, not the card. A card that lifts on hover nudges the
   announcements below it; scaling inside a clipped frame costs nothing. */
.sgserm:hover .sgserm__thumb img{transform:scale(1.045)}
.sgserm__play{position:absolute;inset:0;display:grid;place-items:center;color:#fff}
.sgserm__play svg{width:46px;height:46px;filter:drop-shadow(0 2px 10px rgba(7,20,38,.55));
  transition:transform .3s cubic-bezier(.25,1,.5,1)}
.sgserm:hover .sgserm__play svg{transform:scale(1.09)}
.sgserm__body{display:flex;flex-direction:column;gap:5px;min-width:0}
.sgserm__lab{font-family:var(--font-display);font-weight:800;font-size:.7rem;
  letter-spacing:.15em;text-transform:uppercase;color:var(--cyan)}
.sgserm__t{font-family:var(--font-display);font-weight:700;font-size:1.12rem;line-height:1.3;color:var(--ink-strong)}
.sgserm__m{font-size:.88rem;color:var(--muted)}
.sgserm__go{margin-top:4px;font-weight:600;font-size:.9rem;color:var(--cyan);display:inline-flex;align-items:center;gap:.4em}
.sgserm__go .arrow{transition:transform .3s cubic-bezier(.25,1,.5,1)}
.sgserm:hover .sgserm__go .arrow{transform:translateX(4px)}
@media(max-width:560px){
  .sgserm{grid-template-columns:1fr;gap:13px}
  .sgserm__t{font-size:1.05rem}
}
@media(prefers-reduced-motion:reduce){
  .sgserm,.sgserm__thumb img,.sgserm__play svg,.sgserm__go .arrow{transition:none}
  .sgserm:hover .sgserm__thumb img,.sgserm:hover .sgserm__play svg{transform:none}
}


/* ---- footer action row -----------------------------------------------------
   Members, Community Life Center, Get the App and the notifications button.
   All four used color:inherit, so they picked up the footer's 0.5-alpha body
   color — about 4.4:1 on the navy, under the 4.5:1 AA floor and dimmer than
   the ordinary nav links sitting above them. The most useful things in the
   footer were the hardest to see. They now read as buttons, reusing the pill
   shape .footpush already had so the row is one thing rather than three
   underlined links and a pill. */
.footer__clc,
.footpush{
  display:inline-flex;align-items:center;gap:.4em;
  color:rgba(244,238,225,.95);
  text-decoration:none;
  font-weight:600;
  font-size:.82rem;
  padding:.45em .95em;
  border:1px solid rgba(255,255,255,.3);
  border-radius:100px;
  background:rgba(255,255,255,.04);
  transition:background .25s,border-color .25s,color .25s;
}
.footer__clc:hover,
.footpush:hover{
  background:rgba(255,255,255,.12);
  border-color:rgba(255,255,255,.55);
  color:#fff;
}
.footer__clc:focus-visible,
.footpush:focus-visible{outline:2px solid #dfc17a;outline-offset:2px;}

/* "Get the App" carries .footer__app too, a button reset that lives in a later
   stylesheet and so wins on order at equal specificity. Two classes beats one
   wherever it sits, which keeps the row consistent without unpicking the reset. */
.footer__clc.footer__app{
  display:inline-flex;align-items:center;gap:.4em;
  color:rgba(244,238,225,.95);
  font-weight:600;
  font-size:.82rem;
  padding:.45em .95em;
  border:1px solid rgba(255,255,255,.3);
  border-radius:100px;
  background:rgba(255,255,255,.04);
}
.footer__clc.footer__app:hover{
  background:rgba(255,255,255,.12);
  border-color:rgba(255,255,255,.55);
  color:#fff;
}

/* The base .footer__clc underline is right for a text link and wrong once the
   thing is a pill — it was still showing under "Get the App". */
.footer__clc,.footer__clc:hover,.footer__clc.footer__app{text-decoration:none;}
/* Give the row room now that its items have borders, and keep them on one
   baseline when it wraps. */
.footer__bottom{display:flex;flex-wrap:wrap;align-items:center;gap:10px 12px;}

/* The three destinations group together; the service time is prose and should
   not sit in the same visual run as the buttons. */
.footer__acts{display:flex;flex-wrap:wrap;align-items:center;gap:10px;}
.footer__svc{opacity:.9;font-size:.9em;}

/* ---- desktop: shortcuts for signed-in members --------------------------
   The portal was reachable from the installed app and the footer, and nowhere
   else. Anyone at a desk had to go looking for it. This is the same set of
   links the app gives, sitting where a signed-in person expects to find them.
   Hover and focus-within only, no JS, so it cannot fall out of step with the
   pill animation the main menu runs. */
.navmem{position:relative;display:none;}
@media (min-width:1041px){ .navmem{display:block;} }
.navmem__btn{display:inline-flex;align-items:center;gap:.5em;padding:.4em .9em .4em .45em;
  border:1px solid rgba(255,255,255,.28);border-radius:100px;background:rgba(255,255,255,.06);
  /* The pill it sits in is always rgba(47,33,69,.7). Inheriting the page ink
     put navy on navy - the name was there, just unreadable. Every other item
     in the pill is paper; this is now the same. */
  color:var(--ink-invert,#faf7f1);text-decoration:none;font-weight:600;font-size:.84rem;white-space:nowrap;
  transition:background .25s,border-color .25s;}
.navmem__btn:hover{background:rgba(255,255,255,.13);border-color:rgba(255,255,255,.45);}
.navmem:focus-within .navmem__btn{background:rgba(255,255,255,.13);border-color:rgba(255,255,255,.45);}
.navmem__ava{width:24px;height:24px;border-radius:50%;flex:none;display:block;overflow:hidden;
  background:rgba(255,255,255,.18);}
.navmem__ava img{width:100%;height:100%;object-fit:cover;display:block;}
.navmem__ava svg{width:16px;height:16px;margin:4px;display:block;}
.navmem__menu{position:absolute;right:0;top:calc(100% + 10px);min-width:212px;background:#fff;
  border-radius:14px;padding:8px;border:1px solid rgba(47,33,69,.08);
  box-shadow:0 18px 44px rgba(7,20,38,.18);opacity:0;visibility:hidden;transform:translateY(-6px);
  transition:opacity .2s var(--ease-out),transform .2s var(--ease-out),visibility .2s;z-index:120;}
@media (hover:hover){ .navmem:hover .navmem__menu{opacity:1;visibility:visible;transform:translateY(0);} }
.navmem:focus-within .navmem__menu{opacity:1;visibility:visible;transform:translateY(0);}
.navmem__hd{padding:.35em .7em .5em;font-size:.72rem;letter-spacing:.08em;text-transform:uppercase;
  color:rgba(47,33,69,.5);font-weight:700;}
/* 14px popover, 8px padding over a 1px border: the item corner is what is
   left of the outer curve once the inset is taken off it. */
.navmem__menu a{display:block;padding:.55em .7em;border-radius:5px;color:#38164f;
  text-decoration:none;font-size:.88rem;font-weight:600;}
/* Access given to this person by name gets its own heading rather than being
   mixed into the portal list - "why can she see that?" should be answerable by
   looking. The icons are the same drawings the installed app uses for the same
   shortcuts, so one thing looks like one thing wherever you meet it. */
.navmem__hd--grant{margin-top:6px;padding-top:.62em;box-shadow:inset 0 1px 0 rgba(47,33,69,.1);}
.navmem__menu a.navmem__grant{display:flex;align-items:center;gap:.55em;}
.navmem__gic{flex:none;display:grid;place-items:center;width:18px;height:18px;
  color:var(--cyan-deep,#6a5417);}
.navmem__gic svg{width:16px;height:16px;display:block;}
.navmem__menu a:hover{background:rgba(47,33,69,.06);}
@media (prefers-reduced-motion:reduce){ .navmem__menu{transition:none;} }

/* ---- photo framing: zoom on background images ---------------------------
   <img> photos have had position and zoom for a while. The background layers
   only ever had position, which is the gap. The zoom arrives as --eiz rather
   than as an inline transform so that a layer already carrying a scale of its
   own composes with it instead of losing it: the blurred hero backdrops are
   scaled 1.12 to hide the soft edge left by the blur, and an inline transform
   would have quietly dropped that and shown a halo. */
.banner__photo,.formstage__bg{transform:scale(var(--eiz,1));transform-origin:var(--eix,50%) var(--eiy,50%);}
.mhero__bg,.smhero__bg,.smhero__sharp{transform:scale(calc(1.12 * var(--eiz,1)));transform-origin:var(--eix,50%) var(--eiy,50%);}

/* The reveal button on password boxes. Built by site.js, which wraps every
   input[type=password] on the site rather than each form doing it itself.
   Color is inherited so the same button reads correctly on the dark sign-in
   panels and the light admin ones. */
.pwfield{position:relative;display:block;}
.pwfield input{width:100%;padding-right:3em;}
.pwfield__t{position:absolute;top:50%;right:.5em;transform:translateY(-50%);
  display:grid;place-items:center;width:2.1em;height:2.1em;padding:0;
  border:0;background:transparent;cursor:pointer;border-radius:50%;
  color:inherit;opacity:.55;
  transition:opacity .18s,background-color .18s;}
.pwfield__t:hover{opacity:1;background:color-mix(in srgb,currentColor 12%,transparent);}
.pwfield__t:focus-visible{opacity:1;outline:2.5px solid var(--cyan,#9b7d29);outline-offset:1px;}
.pwfield__t svg{width:18px;height:18px;display:block;}
@media(prefers-reduced-motion:reduce){.pwfield__t{transition:none;}}

/* --- app themes: color the app, not the paper ----------------------------
   A theme was repainting the page itself — Sunset turned every white surface
   cream, Peony Blush turned it pink. The intent is that the color lands on
   the things that are already colored: accents, buttons, headings, icon
   chips. So the three surface tokens are pinned back to the church's own
   near-whites and everything else stays themed.

   Compline is excepted because it is the dark theme and dark paper is the
   whole point of it. Site dark mode is untouched for the same reason: there
   the surfaces are supposed to move. */
html:not(.dark) body[class*="ath-"]:not(.ath-compline){
  --ab:#f8f6fa;
  --arow:#fbf9f5;
  --asurf:#fcfdfe;
}

/* --- Compline: the swatch is the promise ----------------------------------
   The tile shows the theme before you pick it, so the two have to agree. The
   accent family here is the site accent, not a second one: app chrome and
   page share a single ice blue on obsidian. An earlier pass rebuilt this
   around a slate blue while the page was still rendering gold - the tile and
   the theme disagreed in both directions at once. */
body.ath-compline, html.dark body.ath-compline{
  --ac1:#1c4b5a;
  --ac2:#141d2e;
  --abr:#f5e1b2;
  --aac:#dfc17a;
  --aacd:#f0d89e;
  --aacink:#170d20;
  --aicobg:#173341;
  --aglow:rgba(127,214,234,.42);
}

/* --- tab bar: immediate answer to a press ------------------------------- */
.botbar__item{-webkit-tap-highlight-color:transparent;transition:transform .14s cubic-bezier(.22,1,.36,1),opacity .18s}
.botbar__item:active{transform:scale(.9)}
/* held from the tap until the next page paints, so the bar is never dead */
.botbar__item.is-going{opacity:.6}
@media (prefers-reduced-motion:reduce){.botbar__item{transition:none}.botbar__item:active{transform:none}}


/* ---------- Which way the page went ------------------------------------
   The installed app already slid one page out and the next one in, but both
   moved vertically, so every navigation looked the same: a lift and a fade,
   whether you were going somewhere or coming back. That is what made the
   conversations read as a cut - nothing in the movement said which
   direction you had travelled.

   header.php works that out before anything paints and leaves the answer on
   the html element. The first page of a session still lifts, because it did
   not come from anywhere. After that: onward from the right, back from the
   left, the way iOS has always done it. */
html.app-mode[data-nav="push"] main{animation:appPushIn .34s var(--ae-out,cubic-bezier(.16,1,.3,1)) both;}
html.app-mode[data-nav="pop"] main {animation:appPopIn  .34s var(--ae-out,cubic-bezier(.16,1,.3,1)) both;}
@keyframes appPushIn{from{opacity:0;transform:translate3d(26px,0,0);}}
@keyframes appPopIn {from{opacity:0;transform:translate3d(-20px,0,0);}}

/* The page leaves in the direction it is travelling, and only part way - it
   is still on screen when the next one is requested, so there is never a
   blank frame in between. Faster than the arrival, which is what stops the
   pair reading as a crossfade. */
/* The old page has to keep moving for as long as the next one takes to
   arrive, and nobody knows how long that is. A short animation finishes and
   then the page sits there, stopped, until the new document commits - and a
   thing that was moving and has stopped reads as stuck, which is worse than
   never having moved.

   So the movement is long and the timing is linear, with the easing written
   into the keyframes instead: a quick shove over the first fifth, then a
   slow drift that still has somewhere to go two seconds later. Whenever the
   next page paints it cuts this off mid-stride, which is the point. The
   navigation is requested immediately, so none of this is delay - it is
   what covers the wait that was always there. */
html.app-mode.page-exit[data-exit="push"] main{animation:appPushOut 2s linear both;}
html.app-mode.page-exit[data-exit="pop"] main {animation:appPopOut  2s linear both;}
@keyframes appPushOut{
  0%  {opacity:1;  transform:none;}
  10% {opacity:.82;transform:translate3d(-15px,0,0);}
  30% {opacity:.68;transform:translate3d(-27px,0,0);}
  100%{opacity:.42;transform:translate3d(-74px,0,0);}
}
@keyframes appPopOut{
  0%  {opacity:1;  transform:none;}
  10% {opacity:.82;transform:translate3d(15px,0,0);}
  30% {opacity:.68;transform:translate3d(27px,0,0);}
  100%{opacity:.42;transform:translate3d(74px,0,0);}
}

@media(prefers-reduced-motion:reduce){
  html.app-mode[data-nav] main,html.app-mode.page-exit[data-exit] main{animation:none;}
}


/* ---------- Page motion moves to script -------------------------------
   A CSS animation on a freshly loaded document starts its clock the moment
   the element is first rendered - which, in an installed iOS app, can be
   well before the compositor is allowed to show anything. Load a page that
   is already cached and the animation has finished before you ever see it,
   so the screen simply appears. That is the hard cut.

   Script can wait for the first frame the reader actually gets, so the
   entrance is started there instead. These rules stand down; site.js owns
   the movement now. */
html.app-mode main,
html.app-mode[data-nav] main,
html.app-mode.page-exit main,
html.app-mode.page-exit[data-exit] main,
html.msg-app main,
html.msg-app.page-exit main{animation:none !important;}

/* ---------- The tab pill ----------------------------------------------
   Four tenths of a second on an ease-in-out: it crept away from the old tab
   before committing, and was still settling long after the finger had gone.
   The pill is chasing a finger that has already arrived, so it wants no
   slow start at all - full speed immediately, then a decelerating landing. */
.botbar__pill{transition:transform .22s cubic-bezier(.22,1,.36,1),
                          width .22s cubic-bezier(.22,1,.36,1),
                          height .22s cubic-bezier(.22,1,.36,1),
                          opacity .16s linear;}
@media (prefers-reduced-motion:reduce){ .botbar__pill{transition:none;} }

/* A screen travelling the full width of the viewport is briefly outside it.
   The body already hides the overflow; the root needs telling too, or the
   page gains a scrollbar for a third of a second on the way past. */
html.app-mode{overflow-x:hidden;}

/* Where an arriving page starts.

   This has to be in CSS rather than in the animation, because it has to be
   true in the very first frame the compositor is allowed to show, and on an
   installed app that can be before any script has run. Setting it from
   script meant a cached page appeared in place and then hopped backwards to
   slide in - clearly visible in a recording, and worse than no animation.

   site.js takes over on the first animation frame: it creates the animation
   holding this same value, then removes the attribute, so nothing is ever
   painted in between. header.php clears the attribute after a second
   regardless, so a page can never be left parked off screen. */
html.app-mode[data-nav="push"] main{transform:translate3d(100%,0,0);}
html.app-mode[data-nav="pop"] main{transform:translate3d(-30%,0,0);}
@media (prefers-reduced-motion:reduce){
  html.app-mode[data-nav="push"] main,
  html.app-mode[data-nav="pop"] main{transform:none;}
}

/* Said out loud when a page catches itself up, because content that changes
   under a reader without saying so is worse than content that is a minute
   old. Sits above the tab bar, gone in under three seconds. */
.freshtip{position:fixed;left:50%;bottom:96px;transform:translateX(-50%);z-index:220;
  padding:9px 16px;border-radius:100px;font-size:.86rem;font-weight:600;
  background:rgba(47,33,69,.92);color:#faf7f1;
  -webkit-backdrop-filter:saturate(180%) blur(10px);backdrop-filter:saturate(180%) blur(10px);
  box-shadow:0 10px 30px rgba(7,20,38,.28);pointer-events:none;}
@media (min-width:1041px){ .freshtip{bottom:28px;} }


/* ── events that have already happened ────────────────────────────────────
   They stay on their month, sorted last and quietened. Muted colour rather
   than a dropped opacity: fading the whole row takes the title below a
   readable contrast, and a past event is still something somebody may be
   looking for. The hover lift goes, because there is nothing to anticipate. */
.vrow.is-past{background:var(--cream)}
.vrow.is-past:hover{transform:none;box-shadow:none}
.vrow.is-past h3{color:var(--muted)}
.vrow.is-past .tagline{color:var(--muted)}
.vrow.is-past .when .d,.vrow.is-past .when .m{color:var(--muted)}
.vrow.is-past .img img,.vrow.is-past .vrow__img img{filter:grayscale(1);opacity:.6}
.vlist__sep{margin:var(--space-lg) 0 var(--space-md);
  font-family:var(--font-display);font-weight:700;font-size:.72rem;
  text-transform:uppercase;letter-spacing:.1em;color:var(--muted)}

/* .........................................................
   EVENT LISTS - one shape for every card
   Two things happen here. Every card takes the height of the tallest in its
   list, so the column reads as a column rather than a ragged edge. And the
   blurb is held to two lines, so the tallest card is not simply the one whose
   description ran long. The full text is on the event's own page, which is
   where the Details link has always gone.
   Scoped to .vlist--even so sermon rows keep their natural height.
   ......................................................... */
.vlist--even{grid-auto-rows:1fr}
.vlist--even .vrow{align-content:center}
.vlist--even .vrow h3,
.vlist--even .vrow .meta,
.vlist--even .vrow__desc{display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden}
.vlist--even .vrow h3{-webkit-line-clamp:2}
.vlist--even .vrow .meta{-webkit-line-clamp:2}
.vlist--even .vrow__desc{-webkit-line-clamp:2}
.vrow__desc{color:var(--muted);font-size:.85rem;margin-top:2px}
/* Equal rows get a list its shape, but the calendar splits upcoming from past
   into two lists, and two lists can settle at two different heights. Reserving
   the clamped number of lines - 2lh is exactly two lines of this element - ties
   them together. Browsers without the lh unit fall back to the grid above,
   which is uniform within each list. */
.vlist--even .vrow__desc{min-height:2lh}
/* Calendar thumbnails come in whatever shape the artwork was made in, which
   left the rows sitting at slightly different heights. One ratio for all of
   them; the events page keeps its own larger treatment. */
/* 16:9, because that is the shape the artwork is actually made in - an event graphic is
   widescreen, and a near-square frame was cropping the top and bottom off every one of them.
   The height has to come off the ratio rather than the row, so align-self:center is part of
   the fix and not decoration: stretched to the row the frame was landing at 150x129 and the
   declared ratio was being quietly ignored. */
.vlist--even:not(.vlist--wide) .vrow__img{width:clamp(150px,19vw,232px);aspect-ratio:16/9;height:auto;align-self:center;overflow:hidden;border-radius:calc(var(--radius) - 6px);margin:0}
.vlist--even:not(.vlist--wide) .vrow__img img{width:100%;height:100%;object-fit:cover;display:block}
@media(max-width:860px){
  .vlist--even .vrow h3{min-height:2lh}
  .vlist--even .vrow .meta{min-height:2lh}
}
/* The category line was the last thing setting rows adrift: a short category
   sat on one line, a long one ran to three. Two lines for every card. The
   calendar leads with the date so a clamp can never take it. */
.vlist--even .vrow .tagline{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;min-height:2lh}
/* On a 320px phone the Details label wrapped in the one row that has no
   artwork, which pushed that card taller than its neighbours. */
.vlist--even .vrow .btn{white-space:nowrap}
.vrow.is-past .vrow__desc{color:var(--muted)}

/* .........................................................
   EVENT CARDS ON PHONES
   Artwork full width, the date and Details as frosted chips on top of it,
   the words underneath. Lifted out of the events page so the calendar can
   wear the same clothes. .vlist--wide is the desktop row treatment, which
   only the events page uses.
   ......................................................... */
.reg-open-tag{display:inline-block;margin-left:.5em;color:var(--cyan-deep);font-weight:700;font-size:.78em}
/* frosted chips live on the image in the mobile card layout only */
.evmob__pill,.evmob__cta{display:none}
/* desktop rows: artwork fills the card with a clean 5px inset */
@media(min-width:641px){
  .vlist--wide .vrow--img{padding:5px;gap:0 var(--space-lg)}
  .vlist--wide .vrow--img .vrow__img{width:clamp(210px,24vw,320px);aspect-ratio:16/9;height:auto;min-height:0;align-self:center;border-radius:calc(var(--radius) - 5px)}
  .vlist--wide .vrow--img>div{padding:var(--space-md) 0}
  .vlist--wide .vrow--img>.btn{margin-right:var(--space-md)}
}
@media(max-width:640px){
  .vlist--card{gap:var(--space-lg)}
  .vlist--card .vrow--img{display:block;padding:0;background:transparent;border:0;box-shadow:none;overflow:visible}
  .vlist--card .vrow--img::before{display:none}
  .vlist--card .vrow--img:hover{transform:none;box-shadow:none}
  .vlist--card .vrow--img .vrow__img{position:relative;width:100%;height:auto;aspect-ratio:16/9;border-radius:var(--radius-inset);overflow:hidden;background:var(--navy);box-shadow:0 16px 38px rgba(47,33,69,.2);align-self:auto}
  .vlist--card .vrow--img .vrow__img img{width:100%;height:100%;object-fit:cover}
  .vlist--card .vrow--img>div{padding:12px 8px 2px}
  .vlist--card .vrow--img .tagline{display:none}
  .vlist--card .vrow--img>.btn{display:none}
  .evmob__pill,.evmob__cta{display:inline-flex;align-items:center;position:absolute;top:12px;z-index:2;height:36px;padding:0 15px;border-radius:999px;
    font-size:.82rem;font-weight:700;letter-spacing:.02em;color:#fff;text-shadow:0 1px 4px rgba(0,0,0,.3);
    background:rgba(255,255,255,.16);border:1px solid rgba(255,255,255,.38);
    backdrop-filter:blur(14px) saturate(1.5);-webkit-backdrop-filter:blur(14px) saturate(1.5);
    box-shadow:0 6px 18px rgba(0,0,0,.14)}
  .evmob__pill{left:12px}
  .evmob__cta{right:12px}
}

/* .........................................................
   COMPLINE - surfaces the theme could not reach through a token
   Three components hard-code a light background, and the calendar paints its
   event chips with an inline colour worked out for a light grid. Nothing in
   the palette can reach any of them, so they are named here. The !important
   is aimed at an inline style, which is the only thing that outranks it.
   ......................................................... */
html.app-mode body.ath-compline .clcgate,
body.emb.ath-compline .clcgate{background:var(--cream)}
/* The children page paints its own sections a fixed coral, green, amber or
   white and lets the heading take the theme ink, which works while the ink
   is dark. Those four surfaces do not follow the theme, so on this one page
   the text does not either. */
html.app-mode body.ath-compline .ksec,
body.emb.ath-compline .ksec,
html.app-mode body.ath-compline .ksec h2,
body.emb.ath-compline .ksec h2,
html.app-mode body.ath-compline .ksec h3,
body.emb.ath-compline .ksec h3,
html.app-mode body.ath-compline .ksec p,
body.emb.ath-compline .ksec p{color:var(--navy)}
html.app-mode body.ath-compline .ksec .serif,
body.emb.ath-compline .ksec .serif{color:color-mix(in srgb,var(--cyan) 45%,#000)}
html.app-mode body.ath-compline .cal__ev--photo,
body.emb.ath-compline .cal__ev--photo{color:var(--ink) !important}


/* ---- small group directory -------------------------------------------------
   Photo-led, because the question somebody is really asking is "who are these
   people", and a face answers it faster than a paragraph.

   Everything here is on the site's own 4pt scale. The card has two zones and
   the spacing says so: the four lines that identify a group sit tight together,
   then a full step of air before the names you can actually click. No rule
   between them - a hairline would make this read like a table, which is the
   one thing a page of families in their living rooms should not do. */
.sgdir__list{display:grid;gap:var(--space-md);
  grid-template-columns:repeat(auto-fill,minmax(215px,1fr));margin-top:var(--space-lg)}
/* A card that behaves like a button should not behave like a paragraph:
   no blue flash on tap, no accidental text selection on a long press. */
.sgdir{position:relative;background:var(--card,#fff);border:1px solid var(--line);border-radius:var(--radius);
  -webkit-tap-highlight-color:transparent;-webkit-user-select:none;user-select:none;
  overflow:hidden;display:flex;flex-direction:column;
  transition:border-color .16s var(--ease-out),box-shadow .16s var(--ease-out),transform .16s var(--ease-out)}
.sgdir:hover{border-color:color-mix(in srgb,var(--cyan) 45%,var(--line));
  box-shadow:0 10px 26px rgba(47,33,69,.10);transform:translateY(-2px)}
.sgdir:active{transform:translateY(0)}
@media(prefers-reduced-motion:reduce){.sgdir,.sgdir:hover{transform:none}}
/* the whole card opens the panel; the button is the only tab stop in it */
.sgdir__go{font:inherit;color:inherit;background:none;border:0;padding:0;text-align:left;cursor:pointer;
  -webkit-tap-highlight-color:transparent}
.sgdir__go::after{content:"";position:absolute;inset:0;border-radius:inherit}
.sgdir:has(.sgdir__go:focus-visible){outline:2px solid var(--cyan);outline-offset:3px}
.sgdir__go:focus-visible{outline:none}
.sgdir__photo{margin:0;aspect-ratio:3/4;overflow:hidden;background:var(--cream)}
.sgdir__photo img{width:100%;height:100%;object-fit:cover;display:block}

.sgdir__body{padding:var(--space-sm) var(--space-md) var(--space-md);
  display:flex;flex-direction:column;flex:1}
.sgdir__body .kicker{font-size:.64rem;letter-spacing:.11em;text-transform:uppercase;
  font-weight:700;color:var(--cyan-deep)}
.sgdir__body h3{margin:var(--space-2xs) 0 0;font-size:1.125rem;line-height:1.22}
.sgdir__where{color:var(--muted);font-size:.8rem;margin:var(--space-2xs) 0 0;
  display:flex;align-items:center;gap:var(--space-xs);flex-wrap:wrap}
.sgtag{font-size:.6rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  color:var(--cyan-deep);background:color-mix(in srgb,var(--cyan) 12%,#fff);
  border-radius:999px;padding:var(--space-2xs) var(--space-xs);white-space:nowrap}
.sgdir__soon{margin:var(--space-xs) 0 0;font-size:.78rem;font-weight:600;color:var(--navy)}

/* auto pushes the names to the foot of the card, so a two-line group name and a
   one-line one still line their names up across a row */
.sgdir__who{margin:auto 0 0;padding-top:var(--space-md);font-size:.9rem;line-height:1.5}
.sgdir__amp{color:var(--muted)}
/* keeps "& Melissa Barrett" together, so an ampersand never ends a line */
.sgdir__pair{white-space:nowrap}
.sgdir__who{color:var(--navy);font-weight:600}

@media(max-width:600px){
  .sgdir__list{grid-template-columns:repeat(auto-fill,minmax(145px,1fr));gap:var(--space-sm)}
  .sgdir__body{padding:var(--space-sm)}
  .sgdir__body h3{font-size:1rem}
  .sgdir__who{padding-top:var(--space-sm);font-size:.85rem}
}

/* ---- the map ---------------------------------------------------------------
   Circles, not pins. A pin says "this house". A circle says "somewhere around
   here", which is the only thing this page is willing to tell you. */
.sgmap{margin-top:var(--space-lg)}
.sgmap__canvas{height:clamp(290px,44vw,430px);border-radius:var(--radius);overflow:hidden;
  border:1px solid var(--line);background:var(--cream);z-index:0}
.sgmap__note{color:var(--muted);font-size:.8rem;line-height:1.55;
  margin:var(--space-sm) auto 0;text-align:center;max-width:56ch}
.sgmap .leaflet-container{font:inherit;background:var(--cream)}
.sgmap .leaflet-control-attribution{font-size:.62rem;background:rgba(255,255,255,.82);color:var(--muted)}
.sgmap .leaflet-control-attribution a{color:var(--cyan-deep)}
.sgmap .leaflet-bar a{color:var(--navy);border-bottom-color:var(--line)}
.sgmap .leaflet-bar a:hover{background:var(--cream)}
.sgmap .leaflet-popup-content-wrapper{border-radius:var(--radius-sm);box-shadow:0 8px 26px rgba(47,33,69,.16)}
.sgmap .leaflet-popup-content{margin:var(--space-sm) var(--space-md);font-size:.86rem;line-height:1.45}
.sgmap .leaflet-popup-content strong{display:block;font-size:.95rem;color:var(--navy)}
.sgmap .leaflet-popup-content span{color:var(--muted);font-size:.8rem}
.sgpop__go{display:inline-block;margin-top:var(--space-xs);font-weight:600;color:var(--cyan-deep);
  cursor:pointer;text-decoration:underline;text-underline-offset:3px}

/* ---- the leader panel ------------------------------------------------------
   A modal, because the alternative - a page per leader - is eleven pages
   nobody links to. It behaves itself: escape closes it, tab stays inside, and
   focus returns to the name that opened it.

   Padding steps down as the panel gets smaller: --space-lg on a desktop panel
   that can afford the air, --space-md on a phone sheet where it cannot. */
.sgm[hidden]{display:none}
.sgm{position:fixed;inset:0;z-index:120;display:grid;place-items:center;padding:var(--space-md)}
/* Pinning the body is the only thing iOS actually honours. The JS records the
   scroll position, parks it in top, and puts it back on close. */
body.sgm-open{position:fixed;left:0;right:0;width:100%;overflow:hidden;overscroll-behavior:none}
.sgm__veil{position:absolute;inset:0;background:rgba(47,33,69,.52);backdrop-filter:blur(2px);
  animation:sgmFade .22s linear}
.sgm__panel{position:relative;width:min(520px,100%);max-height:min(88vh,760px);
  display:flex;flex-direction:column;background:#fff;border-radius:var(--radius-lg);
  box-shadow:0 26px 70px rgba(47,33,69,.3);overflow:hidden;
  animation:sgmRise .3s var(--ease-out-expo,cubic-bezier(.16,1,.3,1))}
.sgm__panel:focus{outline:none}
@keyframes sgmFade{from{opacity:0}to{opacity:1}}
@keyframes sgmVeilOut{to{opacity:0}}
@keyframes sgmRise{from{opacity:0;transform:translateY(18px) scale(.97)}to{opacity:1;transform:none}}
@keyframes sgmDrop{to{opacity:0;transform:translateY(10px) scale(.985)}}
/* the sheet comes up from the edge it lives on, which is where the thumb is */
@keyframes sgmSheetIn{from{transform:translateY(100%)}to{transform:none}}
@keyframes sgmSheetOut{to{transform:translateY(100%)}}
/* three parts arriving a beat apart - one orchestrated moment, not three animations */
@keyframes sgmPart{from{opacity:0;transform:translateY(9px)}to{opacity:1;transform:none}}
.sgm__head {animation:sgmPart .36s var(--ease-out-expo,cubic-bezier(.16,1,.3,1)) .04s backwards}
.sgm__scroll{animation:sgmPart .36s var(--ease-out-expo,cubic-bezier(.16,1,.3,1)) .09s backwards}
.sgm__foot {animation:sgmPart .36s var(--ease-out-expo,cubic-bezier(.16,1,.3,1)) .14s backwards}

/* leaving is quicker than arriving - about three quarters, and it accelerates
   away rather than easing out, which is what a thing being dismissed does */
.sgm.is-closing .sgm__panel{animation:sgmDrop .2s cubic-bezier(.4,0,1,1) forwards}
.sgm.is-closing .sgm__veil{animation:sgmVeilOut .18s linear forwards}
.sgm.is-closing .sgm__head,
.sgm.is-closing .sgm__scroll,
.sgm.is-closing .sgm__foot{animation:none}

@media(prefers-reduced-motion:reduce){
  .sgm__veil,.sgm__panel,.sgm__head,.sgm__scroll,.sgm__foot,
  .sgm.is-closing .sgm__panel,.sgm.is-closing .sgm__veil{animation:none;transform:none;opacity:1}
}

.sgm__x{position:absolute;top:var(--space-sm);right:var(--space-sm);z-index:2;
  width:34px;height:34px;display:grid;place-items:center;border:0;border-radius:50%;
  background:rgba(255,255,255,.86);color:var(--navy);cursor:pointer;
  transition:background .14s var(--ease-out),transform .14s var(--ease-out)}
.sgm__x svg{width:18px;height:18px}
.sgm__x:hover{background:#fff;transform:scale(1.06)}
.sgm__x:focus-visible{outline:2px solid var(--cyan);outline-offset:2px}

.sgm__head{display:flex;gap:var(--space-md);align-items:flex-end;
  padding:var(--space-lg) var(--space-lg) var(--space-md);
  background:var(--cream);border-bottom:1px solid var(--line)}
.sgm__photo{width:96px;height:128px;object-fit:cover;flex-shrink:0;background:var(--cream-2);
  border-radius:calc(var(--radius) - 4px)}
.sgm__id{min-width:0;padding-bottom:2px}
.sgm__group{font-size:.64rem;font-weight:700;letter-spacing:.11em;text-transform:uppercase;
  color:var(--cyan-deep);margin:0}
.sgm__panel h3{margin:var(--space-2xs) 0 0;font-size:1.3rem;line-height:1.2}
.sgm__where{margin:var(--space-xs) 0 0;font-size:.82rem;color:var(--muted);line-height:1.5}

.sgm__scroll{padding:var(--space-md) var(--space-lg) var(--space-lg);overflow-y:auto;
  /* keeps a flick at the end of the list from scrolling the page behind */
  overscroll-behavior:contain;-webkit-overflow-scrolling:touch}
.sgm__desc{margin:0 0 var(--space-md);font-size:.92rem;line-height:1.65;max-width:60ch}
.sgm__lbl{font-size:.64rem;font-weight:700;letter-spacing:.11em;text-transform:uppercase;
  color:var(--muted);margin:0 0 var(--space-xs)}
.sgm__weeks{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:var(--space-2xs)}
.sgm__weeks li{display:flex;gap:var(--space-sm);align-items:baseline;
  padding:var(--space-xs) var(--space-sm);border-radius:var(--radius-sm);
  background:var(--cream);font-size:.87rem}
.sgm__weeks li.is-off{color:var(--muted)}
.sgm__weeks li.is-plain{display:block;color:var(--muted);font-size:.85rem;line-height:1.5}
.sgm__weeks li.is-soon{display:block;background:color-mix(in srgb,var(--cyan) 11%,var(--card,#fff));
  color:var(--cyan-deep);font-weight:600;font-size:.83rem}
.sgm__wdate{flex:0 0 98px;font-weight:600;color:var(--ink);font-size:.8rem}
.sgm__weeks li.is-off .sgm__wdate{color:var(--muted)}
/* The dialogue predates the second palette, so one or two things in it name a
   colour rather than a role. The date column asked for --navy, which is the
   same ink in daylight but all but invisible on the dark surfaces at night, so
   it now asks for --ink and reads correctly under either. The close disc was a
   white scrim meant to sit over a photograph; in the dark it was the brightest
   thing on the panel, louder than the button people are meant to press. */
html.dark body .sgm__x,
html.app-mode body.ath-compline .sgm__x,
body.emb.ath-compline .sgm__x{background:color-mix(in srgb,var(--ink) 13%,transparent);color:var(--ink);}
html.dark body .sgm__x:hover,
html.app-mode body.ath-compline .sgm__x:hover,
body.emb.ath-compline .sgm__x:hover{background:color-mix(in srgb,var(--ink) 22%,transparent);}
.sgm__wtext{min-width:0}

.sgm__foot{padding:var(--space-md) var(--space-lg) calc(var(--space-md) + env(safe-area-inset-bottom,0px));border-top:1px solid var(--line);background:var(--card,#fff)}
.sgm__contact{width:100%;justify-content:center}

.sgm__form{margin-top:var(--space-lg);border-top:1px solid var(--line);padding-top:var(--space-md)}
.sgm__how{border:0;margin:0 0 var(--space-sm);padding:0;
  display:flex;gap:var(--space-md);align-items:center;flex-wrap:wrap}
.sgm__how legend{float:left;width:100%;font-size:.82rem;color:var(--muted);margin-bottom:var(--space-xs)}
.sgm__how label{display:flex;align-items:center;gap:var(--space-xs);font-size:.9rem;cursor:pointer}
.sgm__f{display:block;margin:0 0 var(--space-sm)}
.sgm__f span{display:block;font-size:.78rem;font-weight:600;color:var(--navy);margin-bottom:var(--space-2xs)}
.sgm__f input,.sgm__f textarea{font:inherit;font-size:16px;width:100%;background:var(--card,#fff);
  border:1.5px solid var(--line);border-radius:var(--radius-sm);padding:.55em .7em;color:var(--ink)}
.sgm__f textarea{resize:vertical;min-height:88px;line-height:1.55}
.sgm__f input:focus,.sgm__f textarea:focus{outline:none;border-color:var(--cyan);
  box-shadow:0 0 0 3px rgba(160,122,42,.16)}
.sgm__send{width:100%;justify-content:center;margin-top:var(--space-2xs)}
.sgm__err{margin:var(--space-sm) 0 0;font-size:.85rem;color:#a3242b;background:#fdeced;
  border-radius:var(--radius-sm);padding:var(--space-xs) var(--space-sm)}
.sgm__done{margin:var(--space-md) 0 0;font-size:.95rem;line-height:1.65;
  background:color-mix(in srgb,var(--cyan) 10%,#fff);border-radius:var(--radius-sm);
  padding:var(--space-sm) var(--space-md);color:var(--navy)}

@media(max-width:520px){
  .sgm{padding:0;place-items:end stretch}
  .sgm__panel{width:100%;max-height:92vh;border-radius:var(--radius-lg) var(--radius-lg) 0 0;
    animation:sgmSheetIn .34s var(--ease-out-expo,cubic-bezier(.16,1,.3,1))}
  .sgm.is-closing .sgm__panel{animation:sgmSheetOut .24s cubic-bezier(.4,0,1,1) forwards}
  @media(prefers-reduced-motion:reduce){
    .sgm__panel,.sgm.is-closing .sgm__panel{animation:none;transform:none}
  }
  .sgm__head{padding:var(--space-md) var(--space-md) var(--space-sm);gap:var(--space-sm)}
  .sgm__scroll{padding:var(--space-sm) var(--space-md) var(--space-md)}
  .sgm__foot{padding:var(--space-sm) var(--space-md)}
  .sgm__photo{width:78px;height:104px}
  .sgm__panel h3{font-size:1.15rem}
}

/* ===========================================================================
   App dock: four tabs in a pill, the plus on its own
   ---------------------------------------------------------------------------
   The plus is not a fifth tab. Tabs take you somewhere and stay lit; this one
   opens a drawer and shuts it again, and two different behaviours should not
   wear the same clothes. Detaching it says so before anything is tapped, and
   it puts the one control reachable from every screen under the thumb that is
   already resting there.

   Same fill as the bar, deliberately. An accent colour on a menu button reads
   as the most important thing on the screen, which is the one thing it is not.
   =========================================================================== */
html.app-mode .botbar,.botbar{background:none;border:0;box-shadow:none;padding:0;gap:10px;
  align-items:center;backdrop-filter:none;-webkit-backdrop-filter:none}
.botbar__tabs{position:relative;display:flex;align-items:stretch;gap:2px;
  /* Actual frosted glass rather than a dark panel with a hint of see-through.
     Three things make the difference: the fill comes down enough for the blur
     to have something to do, the blur goes up far enough to turn what is
     behind into colour instead of shapes, and a light catches the top edge.
     It does not come down further than this because the labels sit on it, and
     over a pale page a thinner fill takes them under 4.5:1. */
  background:linear-gradient(180deg,rgba(255,255,255,.13),rgba(255,255,255,.03) 42%,rgba(255,255,255,0) 72%),rgba(20,28,40,.72);
  backdrop-filter:blur(30px) saturate(1.9);
  -webkit-backdrop-filter:blur(30px) saturate(1.9);
  border:1px solid rgba(255,255,255,.18);border-radius:100px;padding:7px;
  box-shadow:0 18px 45px rgba(7,20,38,.34)}
.botbar__more{flex:none;width:58px;height:58px;min-width:0;padding:0;border-radius:50%;
  /* Actual frosted glass rather than a dark panel with a hint of see-through.
     Three things make the difference: the fill comes down enough for the blur
     to have something to do, the blur goes up far enough to turn what is
     behind into colour instead of shapes, and a light catches the top edge.
     It does not come down further than this because the labels sit on it, and
     over a pale page a thinner fill takes them under 4.5:1. */
  background:linear-gradient(180deg,rgba(255,255,255,.13),rgba(255,255,255,.03) 42%,rgba(255,255,255,0) 72%),rgba(20,28,40,.72);
  backdrop-filter:blur(30px) saturate(1.9);
  -webkit-backdrop-filter:blur(30px) saturate(1.9);
  border:1px solid rgba(255,255,255,.18);box-shadow:0 18px 45px rgba(7,20,38,.34);
  color:rgba(244,238,225,.92);display:grid;place-items:center;
  transition:transform .18s var(--ease-out),color .2s,background .25s}
.botbar__more svg{width:26px;height:26px;transition:transform .3s var(--ease-out)}
/* Idle labels were rgba(244,238,225,.7), which measured 5.7:1 on the old navy
   and 3.96:1 once the bar picked up Sunset. .76 puts the worst theme back over
   5:1 without closing the gap to the active tab, which is pure white and has a
   chip behind it as well. */
.botbar__item{color:rgba(244,238,225,.76)}
/* the label is for screen readers only — a lone plus is legible on sight */
.botbar__more span{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}
.botbar__more:active{transform:scale(.92)}
/* one glyph, turned a quarter turn: the plus becomes the close, so the drawer
   looks shut by the same control that opened it rather than by a stranger */
body.menu-open .botbar__more{color:#fff;background:rgba(47,33,69,.96)}
body.menu-open .botbar__more svg{transform:rotate(45deg)}
@media (prefers-reduced-motion:reduce){
  .botbar__more,.botbar__more svg{transition:none}
  .botbar__more:active{transform:none}
}
@media(max-width:400px){
  html.app-mode .botbar,.botbar{width:calc(100vw - 20px);max-width:440px;gap:9px;padding:0;
    justify-content:center}
  .botbar__tabs{flex:1 1 auto;min-width:0;gap:0;padding:6px;justify-content:space-between}
  .botbar__more{flex:none;width:54px;height:54px;padding:0}
  .botbar__more svg{width:24px;height:24px}
}
@media(max-width:340px){
  .botbar__more{width:50px;height:50px}
  .botbar__more svg{width:22px;height:22px}
}

/* --- what the plus opens --------------------------------------------------
   The sheet itself already exists further up: it rises out of the bar, keeps
   its grab handle and dims the screen behind. What changes here is only what
   is inside it. In the app it is no longer the website menu — About, Ministries
   and When You Visit are for somebody deciding whether to come, and whoever
   installed this decided a while ago. Those pages are still exactly what the
   hamburger opens on the mobile web, where that person actually is. */
html.app-mode .mobmenu{overscroll-behavior:contain}
html.app-mode .mobmenu__actions{display:none}
html.app-mode .appsheet{width:100%}


/* The lit edge that says glass. Separate rule so the shadows already on these
   two keep whatever they were doing. */
.botbar__tabs,.botbar__more{box-shadow:inset 0 1px 0 rgba(255,255,255,.16),0 10px 30px rgba(0,0,0,.28)}
.appsheet__h{margin:var(--space-lg) 0 var(--space-2xs);font-size:.64rem;font-weight:800;
  letter-spacing:.13em;text-transform:uppercase;color:var(--am,#6d5f7b)}
.appsheet__h:first-of-type{margin-top:var(--space-2xs)}
.appsheet__r{display:flex;align-items:center;gap:var(--space-sm);padding:var(--space-sm) 0;
  text-decoration:none;color:var(--ai,#38164f);-webkit-tap-highlight-color:transparent;
  transition:opacity .16s var(--ease-out),transform .16s var(--ease-out)}
.appsheet__r + .appsheet__r{border-top:1px solid var(--aline,#e7dfef)}
.appsheet__r:active{transform:scale(.985);opacity:.66}
.appsheet__ic{flex:none;width:44px;height:44px;border-radius:14px;
  background:var(--aicobg,#edf0f5);display:grid;place-items:center;color:var(--aacd,#007896)}
.appsheet__ic svg{width:22px;height:22px}
.appsheet__tx{min-width:0;flex:1 1 auto;display:flex;flex-direction:column;gap:1px}
.appsheet__tx b{font-size:.94rem;font-weight:700;line-height:1.25}
.appsheet__tx span{font-size:.76rem;color:var(--am,#6d5f7b);line-height:1.3}
/* How many have landed on that board since this person last opened it. The
   text block takes the slack instead of the chevron, so the count and the
   chevron sit together on the right and the label keeps the left. */
.appsheet__n{flex:none;display:grid;place-items:center;min-width:21px;height:21px;
  padding:0 6px;border-radius:100px;background:var(--cyan,#9b7d29);color:#fff;
  font-size:.7rem;font-weight:700;letter-spacing:.01em}
.appsheet__go{margin-left:auto;flex:none;color:var(--am,#6d5f7b);opacity:.5;display:grid;place-items:center}
.appsheet__go svg{width:17px;height:17px}
.appsheet__r.is-here{opacity:.45;pointer-events:none}
.appsheet__foot{margin-top:var(--space-xl);padding-top:var(--space-md);
  border-top:1px solid var(--aline,#e7dfef);display:flex;align-items:center;
  justify-content:space-between;gap:var(--space-sm)}
.appsheet__who{margin:0;font-size:.78rem;color:var(--am,#6d5f7b)}
.appsheet__who b{color:var(--ai,#38164f);font-weight:700}
.appsheet__out{font-size:.82rem;font-weight:700;color:var(--am,#6d5f7b);text-decoration:none;
  padding:var(--space-2xs) var(--space-sm);border-radius:99px;
  border:1px solid var(--aline,#e7dfef)}
.appsheet__out--in{margin-left:auto;color:var(--aacd,#007896);border-color:var(--aac,#9b7d29)}

/* --- the dock wears the theme the member picked --------------------------
   Every other surface in the app already reads --ab / --ai / --aac and shifts
   with the theme; the bar was the one thing still hard-coded navy, so anyone
   on Kashmir or Sunset had a strip of somebody else's app pinned to the bottom
   of theirs.

   --ac2 is each theme's deep end. Pulled a further step toward black it lands
   dark enough for white labels in all eight ramps — the saturated ones (Peony
   Blush, Marple, Sunset) need that step or the bar shouts louder than the page
   it is sitting on. The neutral rgba above stays as the answer for anything
   without color-mix, which is only iOS before 16.2 by now. */
@supports (color: color-mix(in srgb, red 50%, blue)){
  html.app-mode .botbar{--bot-ink:color-mix(in srgb, var(--ac2,#38164f) 56%, #0a0e14)}
  .botbar__tabs,.botbar__more{
    background:color-mix(in srgb, var(--bot-ink,#141c28) 90%, transparent);
    box-shadow:0 18px 45px color-mix(in srgb, var(--bot-ink,#141c28) 40%, transparent)}
  /* open: a shade deeper than the bar, so the button reads as pressed in */
  body.menu-open .botbar__more{background:color-mix(in srgb, var(--ac2,#38164f) 92%, #05080d)}
}

/* --- app home header: you, then the time of day, then what is waiting ------
   The avatar moved to the leading edge. It is the only personal thing in the
   row, and the thumb that opens settings now travels from the side it already
   rests on rather than across the phone. The greeting sits beside it, which
   costs the serif line about a third of its old size — worth it, because a
   greeting that takes two lines to say Good evening is a headline, and this
   is a hello. */
.appdash__top{display:flex;align-items:center;gap:var(--space-sm);justify-content:flex-start}
.appdash__hello{min-width:0;flex:1 1 auto}
.appdash__kick{margin:0}
.appdash__greet{margin:1px 0 0;font-size:clamp(1.12rem,1rem + 1.1vw,1.4rem);line-height:1.2;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.appdash__avatar{width:44px;height:44px}
.appdash__cog{flex:none;margin-left:auto;position:relative;width:40px;height:40px;border-radius:50%;
  display:grid;place-items:center;background:var(--asurf,#fff);border:1px solid var(--aline,var(--line));
  color:var(--ai,var(--navy));-webkit-tap-highlight-color:transparent;cursor:pointer;padding:0;
  transition:transform .16s var(--ease-out),background .2s}
.appdash__cog svg{width:19px;height:19px}
.appdash__cog:active{transform:scale(.92)}
/* The face is not a button any more, so it should stop behaving like one —
   a press state on something that does nothing is a promise it cannot keep. */
.appdash__avatar--member,.appdash__avatar--member:active{transform:none;cursor:default}
@media (prefers-reduced-motion:reduce){.appdash__cog{transition:none}.appdash__cog:active{transform:none}}

/* --- unread badge ---------------------------------------------------------
   Top-right of the icon, small, and ringed so it stays legible wherever the
   icon happens to sit — on the Messages tile that is a navy-to-cyan gradient,
   and a badge with no ring dissolves into the lighter end of it. */
.appms__ico{position:relative;overflow:visible}
.appms__n{position:absolute;top:-6px;left:calc(100% - 9px);min-width:20px;height:20px;padding:0 5px;
  border-radius:99px;background:#d2432f;color:#fff;border:2px solid #fff;
  font-family:var(--font-display);font-size:.66rem;font-weight:800;font-style:normal;
  line-height:16px;text-align:center;letter-spacing:0;box-shadow:0 2px 6px rgba(7,20,38,.28)}

/* --- small groups: the modal is the top layer while it is open -------------
   .mobtop is the floating logo-and-menu pill on mobile web, pinned at z-index
   210; the group modal opens at 120. The pill therefore landed exactly on the
   modal's close button, and once the sheet had grown tall enough to reach the
   top of the screen there was no way out of it at all. Caught on a screen
   recording rather than by reading the file, which is the honest version of
   how this was found. */
body.sgm-open .mobtop,body.sgm-open .navshell{display:none !important}
.sgm{z-index:220}

@media(max-width:520px){
  /* Leave a strip of the page showing above the sheet. 92vh was 92% of the
     LARGE viewport, so with Safari's toolbar on screen the sheet ran past the
     top and tucked its own header under the status bar. dvh measures what is
     actually visible, and the inset keeps it clear of the notch. */
  .sgm__panel{max-height:min(88dvh, calc(100dvh - env(safe-area-inset-top,0px) - 34px))}
  /* something to pull */
  .sgm__panel::before{content:"";position:absolute;top:7px;left:50%;transform:translateX(-50%);
    width:38px;height:4px;border-radius:99px;background:rgba(47,33,69,.16);z-index:3;pointer-events:none}
  .sgm__head{padding-top:calc(var(--space-md) + 6px)}
}

/* --- Coming up: a rail, not a headline -------------------------------------
   The single-event pill said what was next and nothing else, which is a
   smaller answer than the question. Five cards you push with a thumb say
   "here is the shape of the week" in the same strip of screen.

   The rail bleeds to both screen edges — a card half off the side is the only
   honest way of saying there is more, and it costs no label to say it. */
.appup{margin:0}
.appup__head{display:flex;align-items:baseline;justify-content:space-between;gap:var(--space-sm);
  margin:0 0 var(--space-xs)}
.appup__head h2{margin:0;font-size:1.05rem;letter-spacing:-.01em;color:var(--ai,var(--ink))}
.appup__head a{font-size:.78rem;font-weight:700;text-decoration:none;color:var(--aacd,var(--cyan-deep));
  -webkit-tap-highlight-color:transparent}
.appup__rail{display:flex;gap:var(--space-sm);overflow-x:auto;overscroll-behavior-x:contain;
  scroll-snap-type:x proximity;-webkit-overflow-scrolling:touch;scrollbar-width:none;
  padding:3px clamp(16px,5vw,26px) var(--space-2xs);
  margin-inline:calc(clamp(16px,5vw,26px) * -1);
  /* Without this the browser lines a snapped card up with the scrollport edge
     and ignores the padding — which it did on load, nudging the rail 20px and
     leaving the first card hanging off the screen while the heading above it
     sat properly indented. scroll-padding moves the snap line to where the
     text starts, so a card at rest and a card snapped to both land there. */
  scroll-padding-inline:clamp(16px,5vw,26px)}
.appup__rail::-webkit-scrollbar{display:none}

.appup__c{flex:0 0 172px;scroll-snap-align:start;display:flex;flex-direction:column;
  background:var(--asurf,var(--paper,#fff));border:1px solid var(--aline,var(--line));
  border-radius:var(--radius);overflow:hidden;text-decoration:none;color:var(--ai,var(--ink));
  -webkit-tap-highlight-color:transparent;transition:transform .18s var(--ease-out)}
.appup__c:active{transform:scale(.975)}
.appup__pic{display:block;height:92px;background:var(--aicobg,var(--cream-2,#edf0f5))}
.appup__pic img{width:100%;height:100%;object-fit:cover;display:block}
.appup__b{display:block;padding:10px var(--space-sm) var(--space-sm)}
.appup__k{display:block;font-size:.6rem;font-weight:800;letter-spacing:.09em;text-transform:uppercase;
  color:var(--aacd,var(--cyan-deep))}
.appup__c b{display:block;margin-top:4px;font-size:.87rem;font-weight:700;line-height:1.25;
  /* two lines, then stop — a rail of ragged card heights reads as broken */
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.appup__c small{display:block;margin-top:3px;font-size:.72rem;color:var(--am,var(--muted));
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* on now: the one card that is not about later */
/* Each card takes a wash of its own poster. The colour is read off the image
   in the browser (same-origin, so the canvas stays clean) and greys are thrown
   away first — an average that counts the white border of a flyer comes back
   beige for everything and the row loses the very variety this is for.

   7% is deliberately almost nothing. It should read as the cards having
   different temperatures, not as five coloured boxes. */
.appup__c.has-tint{background:rgb(var(--up-tint) / .07);
  border-color:rgb(var(--up-tint) / .28)}
.appup__c.is-live{border-color:color-mix(in srgb,var(--aac,#9b7d29) 55%,var(--aline,var(--line)))}
.appup__c.is-live .appup__k{color:#c0392b}

.appup__more{flex:0 0 106px;scroll-snap-align:end;display:flex;flex-direction:column;
  align-items:center;justify-content:center;gap:9px;text-decoration:none;
  border:1px dashed var(--aline,var(--line));border-radius:var(--radius);
  background:none;color:var(--am,var(--muted));font-size:.78rem;font-weight:700;
  -webkit-tap-highlight-color:transparent;transition:transform .18s var(--ease-out)}
.appup__more:active{transform:scale(.975)}
.appup__morec{width:34px;height:34px;border-radius:50%;display:grid;place-items:center;
  background:var(--aicobg,var(--cream-2,#edf0f5));color:var(--aacd,var(--cyan-deep))}
.appup__morec svg{width:16px;height:16px}
@media (prefers-reduced-motion:reduce){
  .appup__c,.appup__more{transition:none}
  .appup__c:active,.appup__more:active{transform:none}
}

/* the notifications row now lives in settings */
.ppanel .apppush{width:100%}
.pnote{margin:var(--space-sm) 0 0;font-size:.82rem;line-height:1.6;color:var(--am,var(--muted))}


/* --- printing from a dark page ----------------------------------------------
   The print rules already force white paper, which is right. What they could
   not know is that the ink tokens might have gone light on the way here, and
   near-white type on white paper prints as an empty page. Everything is put
   back to the light values for the duration of the print, and nothing else
   about the print layout is touched. */
@media print{
  html.dark body{
    --navy:#38164f;--snow:#faf7f1;--charcoal:#4e3a60;--cyan:#9b7d29;
    --paper:#faf7f1;--bg:#fff;--cream:#f2f4f8;--cream-2:#eaeef4;--card:#fff;
    --ink:#38164f;--ink-soft:#22344a;--muted:#3d4c5e;--line:#d6dbe3;
    --ink-strong:#38164f;--ink-invert:#faf7f1;--ink-invert-soft:#f2f4f8;
    --cyan-deep:#6d5719;
    background:#fff;color:#38164f;
  }
}


/* --- dark app themes: a theme is an accent, not a coat of paint --------------
   Every theme carries a dark block, and each of those blocks also restates the
   site palette - --bg, --paper, --snow, --cream. That was written for Compline,
   whose colours are already obsidian, so restating them there is harmless. For
   the coloured themes it is not: Sunset put #461b05 into --bg and --paper and
   the entire app went rust, page, cards, rows and all. The accent had become
   the paint.

   So the surfaces are handed back to the dark palette, and the theme keeps what
   it should have kept all along - --aac, --aacd, --abr, --ac1, --aglow. The app
   surfaces are rebuilt from near-black with a few percent of the theme mixed in,
   which is enough to feel like the theme without becoming it.

   Compline is excluded on purpose. It is the one theme designed dark from the
   start, and its own values are the right ones. */
html.dark body[class*="ath-"]:not(.ath-compline){
  /* the page, back to obsidian */
  --navy:#2b123e;--snow:#190b25;--paper:#190b25;--bg:#190b25;
  --cream:#210f2f;--cream-2:#261037;--card:#29113b;--charcoal:#c3cad4;
  --ink:#fbf9f5;--ink-soft:#e3e8ef;--muted:#9aa2ad;--line:#3f2f4d;
  --ink-strong:var(--ink);--ink-invert:var(--ink);--ink-invert-soft:var(--ink-soft);
  /* the app surfaces, near-black carrying a trace of the theme */
  --ab:color-mix(in srgb,var(--aac) 5%,#050b13);
  --asurf:color-mix(in srgb,var(--aac) 7%,#0a121c);
  --arow:color-mix(in srgb,var(--aac) 6%,#081019);
  /* The home card is a gradient from --ac1 to --ac2, and in every light theme
     --ac1 is a DEEP form of the accent, not the bright one - Sanctuary pairs a
     deep blue with navy, never the bright cyan. The dark blocks handed it the
     bright value, which is why the card arrived as a slab of orange. Deep here
     too, and the card reads as the theme without shouting it. */
  --ac1:color-mix(in srgb,var(--aac) 42%,#060c14);
  --ac2:color-mix(in srgb,var(--aac) 8%,#0a121c);
  --aline:color-mix(in srgb,var(--aac) 16%,#232c39);
  --aicobg:color-mix(in srgb,var(--aac) 20%,#0b1420);
  --ai:#f7f9fb;
  --am:color-mix(in srgb,var(--aac) 10%,#99a2ae);
}


/* --- app chrome yields to a sheet --------------------------------------------
   The tab bar carries a backdrop-filter, which puts it in its own composited
   layer, and a composited layer does not reliably lose to a plain z-index on a
   sibling. Measured, not assumed: with the leader sheet open and covering the
   whole viewport at z-index 220, a tap at the centre of the bar still landed on
   the bar at z-index 200. Forty pixels to the left it landed on the sheet.

   The profile avatar needs no such explanation - it sits at z-index 390 and was
   simply above the sheet.

   Raising numbers is a game nobody wins, and the answer here is the one the
   interface wanted anyway: a sheet is modal, so the chrome steps out while one
   is open, and comes back when it closes. The bar already carries a transition,
   so it leaves the way it arrived. */
html.app-mode body.sgm-open .botbar{
  opacity:0;
  transform:translateX(-50%) translateY(14px);
  pointer-events:none;
}
html.app-mode .appuser{transition:opacity .25s var(--ease-out),transform .25s var(--ease-out);}
html.app-mode body.sgm-open .appuser{
  opacity:0;
  transform:translateY(-10px);
  pointer-events:none;
}
@media (prefers-reduced-motion:reduce){
  html.app-mode body.sgm-open .botbar,
  html.app-mode body.sgm-open .appuser{transform:none;}
}

/* ---- extra tags on an event ------------------------------------------
   The category keeps its own eyebrow treatment; these sit quieter beside it,
   because a tag is a note about the event rather than the name of it. */
.evtags{display:flex;flex-wrap:wrap;gap:6px;margin:8px 0 0}
.evtag{display:inline-block;padding:.22em .6em;border-radius:999px;
  border:1px solid var(--line);background:var(--cream);color:var(--muted);
  font-size:.7rem;font-weight:700;letter-spacing:.04em;line-height:1.5;
  white-space:nowrap}
.evmeta .evtag{align-self:center}
html.dark .evtag{background:var(--cream-2);border-color:var(--line);color:var(--muted)}

/* =========================================================================
   NEW WAKEFIELD — home hero ("the arch")
   The signature moment: a single arched photograph with a second arch drawn
   just behind it in brass, and one slow sweep of light across the glass on
   arrival. It replaces the scaffold's photo scatter, which needs a dozen good
   photographs this church does not have.
   ========================================================================= */
.nwh{position:relative;overflow:clip;background:
   radial-gradient(90% 70% at 78% 18%, color-mix(in srgb,var(--cyan) 12%,transparent), transparent 62%),
   linear-gradient(180deg,var(--cream) 0%,var(--paper) 68%)}
.nwh__wrap{max-width:var(--maxw);margin-inline:auto;padding:clamp(56px,8vw,104px) clamp(20px,5vw,48px) clamp(28px,4vw,44px);
  display:grid;gap:clamp(30px,5vw,64px);align-items:center}
@media (max-width:979px){.nwh__wrap{padding-top:clamp(92px,20vw,120px)}}
@media (min-width:980px){.nwh__wrap{grid-template-columns:1.08fr .92fr}}

.nwh__eyebrow{font-family:var(--font-accent);font-size:.74rem;font-weight:600;letter-spacing:.16em;
  text-transform:uppercase;color:var(--cyan-deep);display:flex;align-items:center;gap:.6rem}
.nwh__eyebrow::before{content:"";width:26px;height:1px;background:currentColor;flex:none;opacity:.7}
.nwh h1{font-family:var(--font-display);font-weight:400;letter-spacing:-.015em;
  font-size:clamp(2.35rem,6vw,4.4rem);line-height:1.04;color:var(--ink-strong);margin:.6rem 0 0}
.nwh h1 .nwh__l{display:block}
.nwh h1 em{font-style:italic;color:var(--cyan-deep)}
.nwh__sub{margin-top:1.05rem;max-width:46ch;font-size:1.06rem;line-height:1.65;color:var(--ink-soft)}
.nwh__cta{display:flex;flex-wrap:wrap;gap:.7rem;margin-top:1.6rem}
.nwh__facts{margin:2.1rem 0 0;display:grid;grid-template-columns:repeat(3,1fr);gap:0}
@media (min-width:980px){.nwh__facts{grid-template-columns:repeat(3,auto);justify-content:start}}
.nwh__facts>div{padding:0 clamp(12px,2vw,22px);border-left:1px solid var(--line);min-width:0}
.nwh__facts>div:first-child{padding-left:0;border-left:0}
.nwh__facts dt{font-family:var(--font-accent);font-size:.68rem;font-weight:600;letter-spacing:.14em;
  text-transform:uppercase;color:var(--muted)}
.nwh__facts dd{margin:.25rem 0 0;font-family:var(--font-display);font-size:1.08rem;color:var(--ink-strong)}

/* ---- the arch ---- */
.nwh__art{position:relative;margin:0;justify-self:center;width:min(100%,306px)}
@media (min-width:620px){.nwh__art{width:min(100%,380px)}}
@media (min-width:980px){.nwh__art{justify-self:end;width:min(100%,470px)}}
.nwh__arch{position:relative;aspect-ratio:4/5;border-radius:999px 999px 22px 22px;overflow:hidden;
  box-shadow:var(--shadow-lg);background:var(--navy);isolation:isolate}
.nwh__arch img{width:100%;height:100%;object-fit:cover;display:block}
.nwh__arch::after{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--snow) 45%,transparent);
  background:linear-gradient(180deg,transparent 45%,color-mix(in srgb,var(--navy) 58%,transparent))}
/* the second arch, drawn behind and offset — the bit that makes it a mark */
.nwh__art::before{content:"";position:absolute;inset:20px -20px -20px 20px;border-radius:999px 999px 22px 22px;
  border:1px solid color-mix(in srgb,var(--cyan) 55%,transparent);z-index:-1}
/* one slow sweep of light on arrival */
.nwh__glint{position:absolute;inset:0;border-radius:inherit;pointer-events:none;z-index:2;overflow:hidden}
.nwh__glint::before{content:"";position:absolute;top:-30%;bottom:-30%;width:42%;left:-55%;
  background:linear-gradient(100deg,transparent,color-mix(in srgb,var(--snow) 26%,transparent),transparent);
  transform:skewX(-14deg);animation:nwhGlint 2.6s var(--ease-out) .55s both}
@keyframes nwhGlint{from{left:-55%}to{left:125%}}
.nwh__badge{position:absolute;left:-8px;bottom:24px;display:flex;align-items:center;gap:.7rem;
  background:var(--card);border-radius:var(--radius);padding:.7rem .95rem;box-shadow:var(--shadow-md);
  border:1px solid var(--line);text-align:left}
.nwh__badge b{display:block;font-family:var(--font-display);font-size:1.02rem;color:var(--ink-strong);line-height:1.2}
.nwh__badge small{display:block;font-size:.78rem;color:var(--muted)}
.nwh__pulse{width:9px;height:9px;border-radius:50%;background:var(--cyan);flex:none;
  box-shadow:0 0 0 0 color-mix(in srgb,var(--cyan) 60%,transparent);animation:nwhPulse 2.8s ease-out infinite}
@keyframes nwhPulse{70%{box-shadow:0 0 0 12px transparent}100%{box-shadow:0 0 0 0 transparent}}

/* ---- the three doors ---- */
.nwh__rail{max-width:var(--maxw);margin-inline:auto;padding:0 clamp(20px,5vw,48px) clamp(44px,6vw,76px);
  display:grid;gap:14px}
@media (min-width:720px){.nwh__rail{grid-template-columns:repeat(3,1fr)}}
.nwdoor{display:flex;align-items:center;gap:.95rem;padding:1.05rem 1.15rem;text-decoration:none;color:inherit;
  background:var(--card);border:1px solid var(--line);border-radius:var(--radius-card);
  box-shadow:var(--shadow-sm);transition:transform .3s var(--ease-out),box-shadow .3s var(--ease-out),border-color .3s}
.nwdoor:hover{transform:translateY(-3px);box-shadow:var(--shadow-md);border-color:color-mix(in srgb,var(--cyan) 40%,var(--line))}
.nwdoor:active{transform:translateY(-1px)}
.nwdoor__ic{flex:none;width:42px;height:42px;display:grid;place-items:center;border-radius:14px;
  background:color-mix(in srgb,var(--cyan) 12%,var(--snow));color:var(--cyan-deep)}
.nwdoor__ic svg{width:21px;height:21px}
.nwdoor__tx{flex:1;min-width:0}
.nwdoor__tx b{display:block;font-family:var(--font-display);font-size:1.1rem;color:var(--ink-strong);line-height:1.25}
.nwdoor__tx small{display:block;font-size:.83rem;color:var(--muted);margin-top:.1rem}
.nwdoor__arw{flex:none;color:var(--cyan-deep);transition:transform .3s var(--ease-out)}
.nwdoor:hover .nwdoor__arw{transform:translateX(4px)}

@media (prefers-reduced-motion:reduce){
  .nwh__glint::before,.nwh__pulse{animation:none}
  .nwdoor,.nwdoor__arw{transition:none}
}

/* ---- home: a Sunday here ---- */
.nwsun{background:var(--paper)}
.nwsun__wrap{display:grid;gap:clamp(28px,5vw,56px);align-items:start}
@media (min-width:900px){.nwsun__wrap{grid-template-columns:1.05fr .95fr}}
.nwsun__copy h2{margin-top:.4rem}
.nwsun__copy .lead{margin:1rem 0 1.5rem;max-width:48ch}
.nwsun__facts{display:grid;gap:0;margin:0;border-top:1px solid var(--line)}
.nwsun__facts>div{display:grid;grid-template-columns:minmax(90px,.4fr) 1fr;gap:16px;
  padding:16px 0;border-bottom:1px solid var(--line)}
.nwsun__facts dt{font-family:var(--font-accent);font-size:.7rem;font-weight:600;letter-spacing:.14em;
  text-transform:uppercase;color:var(--muted);padding-top:.25rem}
.nwsun__facts dd{margin:0;font-family:var(--font-display);font-size:1.15rem;color:var(--ink-strong);line-height:1.4}

/* ---- home: the course ---- */
/* The course used to sit on a floating rounded panel — the last card surface
   on a page that had otherwise become ruled sections. Now the section itself
   is the dark band, edge to edge, and the content sits in the same column
   grid as every other section. */
.nwbasics{position:relative;overflow:hidden;color:var(--ink-invert);
  background:linear-gradient(150deg,var(--navy),color-mix(in srgb,var(--navy) 70%,var(--cyan-deep)));
  padding-block:clamp(48px,7vw,96px)}
/* the arch, faint, as a watermark — the same mark the hero uses */
.nwbasics::before{content:"";position:absolute;right:-60px;bottom:-230px;width:340px;height:470px;
  border-radius:999px 999px 24px 24px;border:1px solid color-mix(in srgb,var(--cyan) 30%,transparent);
  pointer-events:none}
@media (max-width:899px){.nwbasics::before{display:none}}
.nwbasics__card{position:relative;z-index:1;display:grid;gap:clamp(26px,4vw,52px)}
@media (min-width:900px){.nwbasics__card{grid-template-columns:1.1fr .9fr;align-items:center}}
.nwbasics__copy .flab{color:color-mix(in srgb,var(--cyan) 62%,white)}
.nwbasics__copy h2{color:var(--ink-invert);margin-top:.5rem}
.nwbasics__copy h2 em{font-style:italic;color:color-mix(in srgb,var(--cyan) 70%,white)}
.nwbasics__copy .lead{color:color-mix(in srgb,var(--ink-invert) 82%,transparent);margin:1rem 0 1.6rem;max-width:46ch}
.nwbasics__cta{display:flex;align-items:center;gap:16px;flex-wrap:wrap}
.nwbasics__note{font-size:.82rem;color:color-mix(in srgb,var(--ink-invert) 62%,transparent)}
.nwbasics__list{list-style:none;margin:0;padding:0;position:relative;z-index:1;
  border-top:1px solid color-mix(in srgb,var(--ink-invert) 16%,transparent)}
.nwbasics__list li{display:flex;align-items:baseline;gap:16px;padding:14px 0;
  border-bottom:1px solid color-mix(in srgb,var(--ink-invert) 16%,transparent);
  font-family:var(--font-display);font-size:1.12rem;color:var(--ink-invert)}
.nwbasics__list li span{font-family:var(--font-accent);font-size:.72rem;font-weight:700;letter-spacing:.12em;
  color:color-mix(in srgb,var(--cyan) 62%,white);flex:none;min-width:2.2em}

/* =========================================================================
   NEW WAKEFIELD — the phone menu
   Full screen, editorial, one column of large type. Big targets for an older
   congregation, no hairline grid to read through, and the person's own name
   at the bottom so "am I signed in" is answered without opening the portal.
   ========================================================================= */
.mobmenu{background:var(--paper);justify-content:flex-start}
html:not(.app-mode) .mobmenu{padding:96px clamp(22px,7vw,40px) calc(28px + env(safe-area-inset-bottom,0px))}

/* the primary list sits low on the screen, within thumb reach. The auto margin
   above it now only takes up the slack the fact block leaves. */
html:not(.app-mode) .mobmenu .menu{margin-top:0}
/* The rows look generous because the type is large, but the anchor itself was
   only 34px tall — the visual air between them belonged to the line box, not to
   the target. An older congregation on a phone needs the box, not the look of
   one. Dropdown children were 42px, which is near enough to miss. */
html:not(.app-mode) .mobmenu .menu>li>a,
html:not(.app-mode) .mobmenu .menu>li>button{min-height:48px}
html:not(.app-mode) .mobmenu .dropdown a{min-height:44px}
/* The floating bar's selected chip is written as `.menu>li>a[aria-current]`, and
   the drawer reuses `.menu` — so the desktop tint and hover box were being drawn
   behind these rows too. On a bar a chip is the selection; in a column of ruled
   type it is the only rounded box on the screen, and the dot already says which
   page this is. Same for the hover fill, which a phone never shows anyway. */
html:not(.app-mode) .mobmenu .menu>li>a[aria-current="page"],
html:not(.app-mode) .mobmenu .menu>li>button[aria-current="page"],
html:not(.app-mode) .mobmenu .menu>li>a:hover,
html:not(.app-mode) .mobmenu .menu>li>button:hover{background:none;border-radius:0}
html:not(.app-mode) .mobmenu .menu>li>a[aria-current="page"],
html:not(.app-mode) .mobmenu .menu>li>button[aria-current="page"]{color:var(--cyan-deep)}
/* The dot used to exist only on the current item, which pushed its label 9px
   right of every other label — the one row that should look anchored was the
   one row out of line. Every item reserves the space; only the current one
   paints it. */
html:not(.app-mode) .mobmenu .menu>li>a::before,
html:not(.app-mode) .mobmenu .menu>li>button::before{
  content:"";width:9px;height:9px;border-radius:50%;background:transparent;flex:none;margin-right:.1em}
html:not(.app-mode) .mobmenu .menu>li>a[aria-current="page"]::before,
html:not(.app-mode) .mobmenu .menu>li>button[aria-current="page"]::before{background:var(--cyan)}
/* Keyboard users had nothing but the browser default, which is invisible on
   cream at this type size. */
html:not(.app-mode) .mobmenu a:focus-visible,
html:not(.app-mode) .mobmenu button:focus-visible{outline:2px solid var(--cyan-deep);
  outline-offset:4px;border-radius:6px}
html:not(.app-mode) .mobmenu .caret{width:13px;height:13px;margin-left:.15em;opacity:.45}
html:not(.app-mode) .mobmenu .dropdown{padding-left:.9rem}
html:not(.app-mode) .mobmenu .dropdown a{font-family:var(--font-body);font-size:1.02rem;padding:.5em .2em;color:var(--muted)}

/* ---- the fact block that holds the top of the drawer ---- */
.mobmenu__now{margin:0 0 auto}
.mobmenu__now p{margin:0}
.mobmenu__now-lab{font-family:var(--font-accent);font-size:.68rem;font-weight:600;letter-spacing:.16em;
  text-transform:uppercase;color:var(--cyan-deep)}
.mobmenu__now-when{font-family:var(--font-display);font-size:1.5rem;line-height:1.2;font-weight:400;
  color:var(--ink-strong);margin-top:.35rem !important}
.mobmenu__now-when b{font-weight:600;font-style:italic;color:var(--cyan-deep)}
.mobmenu__now-where{font-size:.9rem;color:var(--ink-soft);margin-top:.18rem !important}
/* the one row in the drawer somebody may need at speed, so it is a target, not a line */
.mobmenu__now-call{display:flex;align-items:baseline;gap:.5rem;min-height:44px;margin-top:.7rem;
  padding-top:.7rem;border-top:1px solid var(--line);text-decoration:none;
  font-family:var(--font-accent);font-size:.85rem;color:var(--ink-soft)}
.mobmenu__now-call b{font-weight:600;color:var(--ink-strong);letter-spacing:.01em}
.mobmenu__now-call:hover b,.mobmenu__now-call:focus-visible b{color:var(--cyan-deep)}

/* ---- the quieter second list ----
   It used to render at the same 16px/400 as the primary items in a different
   face, which is not quieter, only inconsistent. Smaller, letterspaced and
   muted reads as secondary; the padding keeps each target at 44px. */
.mobmenu__minor{list-style:none;margin:1.5rem 0 0;padding:0;display:grid;gap:0}
.mobmenu__minor a{display:flex;align-items:center;min-height:44px;padding:.1em .04em;
  font-family:var(--font-accent);font-size:.82rem;font-weight:600;letter-spacing:.11em;
  text-transform:uppercase;color:var(--muted);text-decoration:none;
  transition:color .25s var(--ease-out),transform .3s var(--ease-out)}
.mobmenu__minor a:hover,.mobmenu__minor a:focus-visible{color:var(--cyan-deep);transform:translateX(3px)}

/* A lone 150px pill floating at the left edge read as an orphan next to a column
   of full-width rows. Full width, and a lighter shadow now it is not hovering. */
.mobmenu__actions{margin-top:1.6rem;padding-top:0}
html:not(.app-mode) .mobmenu__actions{display:grid}
html:not(.app-mode) .mobmenu__actions .btn{width:100%;min-width:0}
html:not(.app-mode) .mobmenu__actions .btn--accent{box-shadow:0 6px 18px rgba(160,122,42,.22)}

/* whose phone this is */
.mobmenu__me{display:flex;align-items:center;gap:.7rem;margin-top:1.8rem;padding-top:1.3rem;
  border-top:1px solid var(--line);text-decoration:none;color:var(--ink-soft);font-size:.95rem}
.mobmenu__av{width:38px;height:38px;border-radius:50%;flex:none;object-fit:cover;
  display:grid;place-items:center;overflow:hidden;background:color-mix(in srgb,var(--cyan) 14%,var(--snow))}
.mobmenu__av--out{color:var(--cyan-deep)}
.mobmenu__me:hover{color:var(--cyan-deep)}

/* the staggered reveal already exists; extend it to the new rows */
.mobmenu__minor,.mobmenu__me{opacity:0;transform:translateY(12px);
  transition:opacity .45s var(--ease-out),transform .45s var(--ease-out)}
body.menu-open .mobmenu__minor{opacity:1;transform:none;transition-delay:.34s}
body.menu-open .mobmenu__me{opacity:1;transform:none;transition-delay:.42s}
@media(prefers-reduced-motion:reduce){.mobmenu__minor,.mobmenu__me{transition:none;opacity:1;transform:none}}

/* =========================================================================
   NEW WAKEFIELD — hero variant B: stadium masks
   The same words in the Renew arrangement: two pill-masked photographs
   flanking a centred headline, and one line at the bottom answering where,
   what-if-I'm-new, and when.
   ========================================================================= */
.nwp{position:relative;overflow:clip;background:
  radial-gradient(80% 60% at 50% 12%, color-mix(in srgb,var(--cyan) 10%,transparent), transparent 60%),
  linear-gradient(180deg,var(--cream) 0%,var(--paper) 70%)}
.nwp__wrap{max-width:var(--maxw);margin-inline:auto;
  padding:clamp(92px,13vw,124px) clamp(20px,5vw,48px) clamp(26px,4vw,40px)}
.nwp__eyebrow{font-family:var(--font-accent);font-size:.72rem;font-weight:600;letter-spacing:.16em;
  text-transform:uppercase;color:var(--cyan-deep);text-align:center}

.nwp__stage{position:relative;margin-top:clamp(22px,4vw,34px);
  display:grid;justify-items:center;align-items:center;gap:clamp(16px,3vw,0px)}
@media (min-width:900px){
  .nwp__stage{grid-template-columns:minmax(150px,1fr) auto minmax(150px,1fr);gap:0}
}
.nwp__h{font-family:var(--font-display);font-weight:400;letter-spacing:-.02em;
  font-size:clamp(2.5rem,7.4vw,5rem);line-height:1.04;color:var(--ink-strong);
  text-align:center;position:relative;z-index:2;order:2}
/* Only the three line wrappers become blocks. motion.js splits headline text
   into one span per character for its reveal, so a bare `span{display:block}`
   here sets every letter on its own line. */
.nwp__h .nwp__l1,.nwp__h .nwp__l2,.nwp__h .nwp__l3{display:block}
.nwp__h em{font-style:italic;color:var(--cyan-deep)}
/* the lines step outward so the photographs tuck under the ends of the type,
   the way the reference does it */
@media (min-width:900px){
  .nwp__h .nwp__l1{margin-right:2.2em}
  .nwp__h .nwp__l3{margin-left:1.4em}
}

.nwp__img{margin:0;overflow:hidden;border-radius:999px;box-shadow:var(--shadow-md);
  background:var(--navy);width:100%;max-width:340px}
.nwp__img img{width:100%;height:100%;object-fit:cover;display:block}
.nwp__img--l{aspect-ratio:16/9;order:1}
.nwp__img--r{aspect-ratio:16/9;order:3}
@media (min-width:900px){
  .nwp__img--l{justify-self:end;margin-right:-58px;margin-top:74px;z-index:1}
  .nwp__img--r{justify-self:start;margin-left:-58px;margin-bottom:88px;z-index:1}
}
@media (max-width:899px){
  .nwp__stage{grid-template-columns:1fr 1fr;grid-template-areas:"h h" "l r";gap:14px}
  .nwp__h{grid-area:h}
  .nwp__img--l{grid-area:l}
  .nwp__img--r{grid-area:r}
  .nwp__img{aspect-ratio:1/1;border-radius:999px}
}

.nwp__bar{margin-top:clamp(26px,4vw,44px);display:grid;gap:24px;align-items:center;text-align:center}
@media (min-width:760px){.nwp__bar{grid-template-columns:1fr auto 1fr;text-align:left}}
.nwp__side dt{font-family:var(--font-accent);font-size:.68rem;font-weight:600;letter-spacing:.14em;
  text-transform:uppercase;color:var(--muted)}
.nwp__side dd{margin:.3rem 0 0;font-size:.98rem;line-height:1.5;color:var(--ink-strong)}
.nwp__side dd b{font-family:var(--font-display);font-size:1.12rem;font-weight:400}
@media (min-width:760px){.nwp__side--r{text-align:right}}
.nwp__mid{display:grid;justify-items:center;gap:14px}
.nwp__cta{display:inline-flex;align-items:center;justify-content:center;min-width:168px;
  padding:.85em 1.7em;border-radius:999px;border:1px solid var(--ink-strong);
  font-family:var(--font-accent);font-weight:600;font-size:.84rem;letter-spacing:.08em;
  text-transform:uppercase;color:var(--ink-strong);text-decoration:none;
  transition:background .3s var(--ease-out),color .3s var(--ease-out),transform .3s var(--ease-out)}
.nwp__cta:hover{background:var(--ink-strong);color:var(--paper);transform:translateY(-2px)}
.nwp__social{display:flex;gap:14px;color:var(--muted)}
.nwp__social a{color:inherit;display:grid;place-items:center;transition:color .25s}
.nwp__social a:hover{color:var(--cyan-deep)}

/* the weekly schedule, four rows rather than four one-liners */
.nwsun__call{font-family:var(--font-accent);font-size:.72rem;font-weight:600;letter-spacing:.1em;
  text-transform:uppercase;color:var(--cyan-deep)}
/* This is the only way most of the congregation joins two of the four
   gatherings, and it was set in muted grey at .92rem — the least legible type
   on the page carrying the most operational information on it. */
/* No rule of its own: the schedule's last row already draws one, and the grid
   gap was leaving 70-odd pixels of nothing between the two. */
.nwsun__line{grid-column:1/-1;margin-top:calc(clamp(28px,5vw,56px) * -1 + 1.1rem);
  font-size:.97rem;line-height:1.7;color:var(--ink-soft);max-width:62ch}
.nwsun__line b{font-family:var(--font-display);font-weight:600;font-size:1.06rem;color:var(--ink-strong);
  white-space:nowrap;letter-spacing:.01em}
@media (min-width:900px){.nwsun__line{grid-column:2}}

/* =========================================================================
   NEW WAKEFIELD — the motion layer
   Feedback first, decoration second. Everything here is transform/opacity so
   it stays on the compositor, and all of it collapses under reduced motion.
   ========================================================================= */
.btn,.nwdoor,.viscard,.crsrow a,.lsndoc{will-change:auto}
.btn{transition:transform .2s var(--ease-out),box-shadow .26s var(--ease-out),
  background .2s,color .2s,border-color .2s}
.btn:hover{transform:translateY(-2px)}
.btn:active{transform:translateY(0) scale(.975)}
.nwdoor:active,.viscard:active,.lsndoc:active{transform:translateY(-1px) scale(.99)}

/* nav links grow an underline from the left rather than blinking one on */
.menu>li>a{position:relative}
.menu>li>a::after{content:"";position:absolute;left:.3em;right:.3em;bottom:.15em;height:1.5px;
  background:var(--cyan);transform:scaleX(0);transform-origin:left;
  transition:transform .32s var(--ease-out)}
.menu>li>a:hover::after{transform:scaleX(1)}
html:not(.app-mode) .mobmenu .menu>li>a::after{display:none}

/* Cross-document page transitions are already set up further up this file, and
   this block used to set up a second, conflicting one.

   Up there, `main` is pulled onto its own surface (view-transition-name:
   page-main) and the root surface is deliberately given `animation:none` — the
   comment beside it explains why: a backdrop-filter inside an isolated surface
   has no page content to sample, so the frosted nav renders against nothing
   unless the chrome stays part of root.

   This block then animated root anyway. Both fired, so on every navigation the
   page content was composited twice — once inside root's fade and once as its
   own page-main surface — and when root's .3s finished ahead of page-main's
   .38s the content jumped. That is the flash after the text finishes animating
   in. One transition, defined once, up there. */

@media (prefers-reduced-motion:reduce){
  .btn,.nwdoor,.viscard,.lsndoc{transition:none}
  .btn:hover,.btn:active,.nwdoor:active,.viscard:active{transform:none}
  .menu>li>a::after{display:none}
}

/* =========================================================================
   NEW WAKEFIELD — "The Fan": the home hero, and the site's signature
   Five doors dealt like a hand of cards.

   Redesign notes. The first pass gave each card a different pastel — yellow,
   green, lilac, peach, pink — which read as an Easter basket beside a gold-on-
   purple crest, and put three words and an arrow on each face, which is not a
   card but an empty tile. This pass fixes both. The faces are cut from the
   crest's own two hues (purple 308, gold 88) and laid out symmetrically by
   weight: plum at the ends, cream inside, gold at the centre for the card you
   are most meant to open. And every card now states a fact a visitor would
   otherwise have to open the page to learn.
   ========================================================================= */
:root{
  /* three faces, two hues, both sampled off the crest */
  --nwf-plum:oklch(33% 0.082 308);
  --nwf-plum-2:oklch(39% 0.078 308);      /* the inner rule on a plum face */
  --nwf-cream:oklch(93.5% 0.026 88);
  --nwf-gold:oklch(78% 0.104 88);
  --nwf-glow:oklch(90% 0.075 100);
}
.nwf{position:relative;overflow-x:clip;overflow-y:visible;text-align:center;
  padding-block:clamp(88px,11vw,124px) clamp(46px,5.5vw,78px);background:var(--paper)}
.nwf::before{content:"";position:absolute;inset:0 -10% 30%;pointer-events:none;
  background:radial-gradient(62% 62% at 50% 16%,var(--nwf-glow),transparent 72%);opacity:.55}
.nwf__in{position:relative}
.nwf__h{font-family:var(--font-display);font-weight:600;letter-spacing:-.016em;
  font-size:clamp(2.25rem,6vw,4.3rem);line-height:1.06;color:var(--ink-strong);margin:0}
.nwf__h .nwf__l{display:block}
.nwf__h em{font-style:italic;font-weight:600;color:var(--cyan)}
.nwf__sub{margin:var(--space-lg) auto 0;max-width:44ch;color:var(--ink-soft);font-size:1.04rem;line-height:1.55}
.nwf__act{margin-top:var(--space-lg);display:flex;justify-content:center;gap:var(--space-sm);flex-wrap:wrap}

/* The handwriting. Two notes, desktop only — at phone width they would sit on
   top of the headline. Each carries an up arrow and a down arrow; the
   placement decides which one is shown, so a note can point at the buttons
   above it or the hand below it without needing its own markup. */
.nwf__aside{position:absolute;display:none;font-family:var(--font-display);font-style:italic;
  font-size:.96rem;color:var(--cyan-deep);opacity:.9;align-items:center;gap:.4em;
  line-height:1.3;z-index:3}
/* the cap belongs to the words, not the row — on the row it was subtracting
   the 86px arrow and leaving one word per line */
.nwf__aside>span{flex:0 1 auto;max-width:15ch}
.nwf__aside svg{display:block;flex:none;stroke:var(--cyan);fill:none;stroke-width:1.6;stroke-linecap:round}

/* The notes write themselves, then do it again.

   Each note is a little piece of handwriting on a loop: the words appear left
   to right as if written, the arrow draws after them, the arrowhead after
   that, and the whole note holds for most of the cycle before fading so it can
   be written again. It is the page's one piece of personality, so it is the
   thing that keeps moving while the page is otherwise still — slowly, and
   with the two notes a couple of seconds apart so they never blink in step.

   Only once the hand has been dealt (so the first writing lands after the
   cards, not before), only while the hero is on screen, and not at all for
   anyone who has asked for less motion. The paths use pathLength="1", so the
   same 0→1 dash works for every stroke regardless of its real length. */
.is-dealt .nwf__aside>span{animation:nwfWrite 15s cubic-bezier(.45,.05,.3,1) 1.2s infinite both}
.is-dealt .nwf__aside path{stroke-dasharray:1;animation:nwfStroke 15s var(--ease-out) 1.2s infinite both}
.is-dealt .nwf__aside path+path{animation-name:nwfHead}
.nwf__fan.is-parked ~ .nwf__aside>span,.nwf__fan.is-parked ~ .nwf__aside path{animation-play-state:paused}
@keyframes nwfWrite{
  0%{clip-path:inset(-20% 100% -20% 0);opacity:1}
  11%{clip-path:inset(-20% 0 -20% 0);opacity:1}
  84%{clip-path:inset(-20% 0 -20% 0);opacity:1}
  93%,100%{clip-path:inset(-20% 0 -20% 0);opacity:0}}
@keyframes nwfStroke{
  0%,10%{stroke-dashoffset:1;opacity:1}
  18%{stroke-dashoffset:0;opacity:1}
  84%{stroke-dashoffset:0;opacity:1}
  93%,100%{stroke-dashoffset:0;opacity:0}}
@keyframes nwfHead{
  0%,18%{stroke-dashoffset:1;opacity:1}
  22%{stroke-dashoffset:0;opacity:1}
  84%{stroke-dashoffset:0;opacity:1}
  93%,100%{stroke-dashoffset:0;opacity:0}}

/* ---- the next gathering ---- */
.nwf__next{display:inline-flex;align-items:center;gap:.6em;margin:0 0 var(--space-md);
  font-family:var(--font-accent);font-size:.74rem;font-weight:600;letter-spacing:.14em;
  text-transform:uppercase;color:var(--cyan-deep)}
.nwf__next b{display:inline-block;font-weight:700;color:var(--ink-strong)}
/* a changed number rises into place; the words beside it don't move */
.nwf__next b.is-new{animation:nwfRoll .6s var(--ease-out) both}
@keyframes nwfRoll{from{opacity:0;transform:translateY(.55em)}}
/* the dot breathes — slow, like something at rest rather than an alert */
.nwf__dot{position:relative;width:7px;height:7px;border-radius:50%;background:var(--cyan);flex:none}
.nwf__dot::after{content:"";position:absolute;inset:0;border-radius:50%;background:var(--cyan);
  animation:nwfBreathe 3.2s ease-in-out infinite}
@keyframes nwfBreathe{0%,100%{transform:scale(1);opacity:.55}50%{transform:scale(2.6);opacity:0}}
/* during the service it quickens a little and turns plum: something is on */
.nwf__next.is-live .nwf__dot,.nwf__next.is-live .nwf__dot::after{background:var(--navy)}
.nwf__next.is-live .nwf__dot::after{animation-duration:1.8s}
/* Measured off the hand, not the headline: `bottom` puts them at the outer
   cards' own height so each arrow lands on the card beside it. They were
   previously pinned to the text block, which ends above the fan — no bottom
   value there could ever have reached a card. */
.nwf__aside--l{left:clamp(8px,2vw,34px);bottom:30%;transform:rotate(-7deg);text-align:right}
.nwf__aside--r{right:clamp(8px,2vw,34px);bottom:30%;transform:rotate(6deg)}
/* The threshold is arithmetic, not taste. The outer cards sit 336px off centre
   and are ~208px wide, so the hand's outer edge is about half the viewport
   plus 460px; a note needs ~200px beyond that plus a margin. Below ~1440px
   there is no margin left and the note lands on the Give card — which is
   exactly what 1080px was doing before the cards were widened. */
@media (min-width:1440px){.nwf__aside{display:flex}}

.nwf__fan{position:relative;margin-top:clamp(14px,1.8vw,26px);height:clamp(244px,23.5vw,284px)}
@media (max-width:759px){
  .nwf__fan{height:auto;display:flex;gap:var(--space-sm);overflow-x:auto;scroll-snap-type:x mandatory;
    padding:var(--space-xs) clamp(20px,5vw,44px) var(--space-xl);scrollbar-width:none}
  .nwf__fan::-webkit-scrollbar{display:none}
}

/* ---- the card ------------------------------------------------------------
   A playing card, not a web card: a tighter corner than the 20px default, a
   hairline drawn inside the edge the way a suit frame is, and a shadow that
   is directional and tight so the overlapping faces read as physical rather
   than as five divs with the same soft glow under them. */
.nwf__card{--rot:0deg;--lift:0px;--x:0px;position:relative;overflow:hidden;
  display:flex;flex-direction:column;text-align:left;text-decoration:none;
  border-radius:13px;padding:var(--space-md);isolation:isolate;
  box-shadow:0 2px 3px -1px color-mix(in oklch,var(--navy) 26%,transparent),
             0 16px 30px -18px color-mix(in oklch,var(--navy) 72%,transparent)}
/* the suit frame */
.nwf__card::after{content:"";position:absolute;inset:7px;border-radius:7px;
  border:1px solid currentColor;opacity:.16;pointer-events:none;z-index:2}

.nwf__card--plum{background:var(--nwf-plum);color:oklch(95% 0.018 88)}
.nwf__card--cream{background:var(--nwf-cream);color:var(--navy)}
.nwf__card--gold{background:var(--nwf-gold);color:oklch(28% 0.075 308)}

/* ---- the three bands: rule, body, rule ---- */
/* Number and label sit together at the LEFT. Right-aligned, the label slid
   under the neighbouring card — in a fan only the left edge of each face is
   reliably visible, so everything that must be read lives there. */
.nwf__hd{display:flex;align-items:baseline;gap:.62em;position:relative;z-index:1;
  padding-bottom:.58em;border-bottom:1px solid color-mix(in oklch,currentColor 22%,transparent)}
.nwf__num{font-family:var(--font-accent);font-size:.66rem;font-weight:700;letter-spacing:.16em;
  opacity:.55;flex:none}
.nwf__lab{font-family:var(--font-accent);font-size:.66rem;font-weight:600;
  letter-spacing:.13em;text-transform:uppercase;opacity:.78;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}

.nwf__body{position:relative;z-index:1;margin-top:auto;padding-bottom:.55em}
.nwf__body b{display:block;font-family:var(--font-display);font-weight:600;
  font-size:clamp(1.24rem,1.62vw,1.46rem);line-height:1.04;letter-spacing:-.018em}
.nwf__body small{display:block;margin-top:.38em;font-size:.81rem;line-height:1.38;opacity:.82}
/* In a fan every card but the last one is covered on its right by the next.
   The visible strip is the gap between card centres minus half a card — about
   150px here — so the copy is capped to it rather than to the card's own
   width, which was letting sentences run under the neighbour. */
@media (min-width:760px){.nwf__body small,.nwf__body b{max-width:128px}}

.nwf__go{position:relative;z-index:1;display:flex;align-items:center;gap:.4em;
  padding-top:.62em;border-top:1px solid color-mix(in oklch,currentColor 22%,transparent);
  font-family:var(--font-accent);font-size:.76rem;font-weight:600;letter-spacing:.02em}
.nwf__go span{transition:transform .3s var(--ease-out)}
.nwf__card:hover .nwf__go span{transform:translateX(5px)}

/* ---- the two cards that carry a photograph ---- */
/* 01: the congregation runs the full face, under a plum wash, so the card is
   a photograph rather than a photograph in a slot. */
.nwf__card.has-bg .nwf__pic{position:absolute;inset:0;z-index:0}
.nwf__card.has-bg .nwf__pic img{width:100%;height:100%;display:block}
.nwf__card.has-bg .nwf__pic::after{content:"";position:absolute;inset:0;
  background:linear-gradient(176deg,
    color-mix(in oklch,var(--nwf-plum) 46%,transparent) 0%,
    color-mix(in oklch,var(--nwf-plum) 72%,transparent) 52%,
    color-mix(in oklch,var(--nwf-plum) 95%,transparent) 100%)}
/* 03: a cut-out figure stands on the card's floor, out of the flex column so
   the copy keeps its full column width. */
/* The figure stands at the card's bottom-right. On the middle card that corner
   is exactly where the next card in the fan overlaps, so at 48%/80% the cut-out
   was half-covered and read as a smudge behind the copy rather than as a
   person. Smaller and tucked into the corner, it sits under the overlap instead
   of fighting it. */
.nwf__card:not(.has-bg) .nwf__pic{position:absolute;right:-6px;bottom:0;z-index:0;
  width:40%;height:62%;pointer-events:none;
  -webkit-mask-image:linear-gradient(to bottom,#000 82%,transparent);
  mask-image:linear-gradient(to bottom,#000 82%,transparent);
  transition:transform .5s var(--ease-out)}
.nwf__card:not(.has-bg) .nwf__pic img{width:100%;height:100%;display:block;object-position:bottom right}
/* only the card with a figure standing in it needs its copy reined in */
.nwf__card:not(.has-bg).has-img .nwf__body small{max-width:12ch}
.nwf__card:not(.has-bg):hover .nwf__pic{transform:translateY(-3px) scale(1.03)}

@media (min-width:760px){
  .nwf__card{position:absolute;left:50%;bottom:30px;
    width:clamp(176px,15.3vw,208px);height:clamp(208px,17.6vw,232px);
    transform:translateX(calc(-50% + var(--x) + var(--push,0px))) translateY(calc(var(--lift) + var(--dip,0px))) rotate(calc(var(--rot) + var(--tilt,0deg) + var(--lean,0deg)));
    /* `translate` is the pointer lean, written by JS on its own property so it
       composes with this transform instead of fighting it — and eased here, so
       the hand glides rather than snapping to every mouse jiggle. */
    transition:transform .42s var(--ease-out),box-shadow .42s var(--ease-out),
               translate .55s var(--ease-out)}
  /* The hand makes room.

     A hovered card used to rise 20px, grow 4.5% and slide over its neighbours,
     so picking one up meant covering the two beside it. Now the card lifts
     further — up toward the headline, which is the direction a hand offers a
     card — and relaxes half its tilt, while its neighbours ease apart and dip a
     little, as if the hand had opened to show it. The nearest neighbour moves
     most, the next one along less, so it reads as one movement travelling
     outward rather than four cards jumping.

     Straightening it fully is still out: that widens its footprint past what
     the neighbours can make room for. */
  .nwf__card:hover,.nwf__card:focus-visible{z-index:9;
    transform:translateX(calc(-50% + var(--x))) translateY(calc(var(--lift) - 38px)) rotate(calc(var(--rot) * .5 + var(--lean,0deg))) scale(1.03);
    box-shadow:0 3px 4px -1px color-mix(in oklch,var(--navy) 30%,transparent),
               0 30px 54px -22px color-mix(in oklch,var(--navy) 78%,transparent)}
  .nwf__card:active{transition-duration:.12s;
    transform:translateX(calc(-50% + var(--x))) translateY(calc(var(--lift) - 30px)) rotate(calc(var(--rot) * .5 + var(--lean,0deg))) scale(1.015)}
  /* neighbours: left of the card go left, right of it go right */
  .nwf__card:hover ~ .nwf__card,.nwf__card:focus-visible ~ .nwf__card{--push:18px;--dip:6px;--tilt:1.5deg}
  .nwf__card:hover + .nwf__card,.nwf__card:focus-visible + .nwf__card{--push:34px;--dip:10px;--tilt:2.5deg}
  .nwf__card:has(~ .nwf__card:hover),.nwf__card:has(~ .nwf__card:focus-visible){--push:-18px;--dip:6px;--tilt:-1.5deg}
  .nwf__card:has(+ .nwf__card:hover),.nwf__card:has(+ .nwf__card:focus-visible){--push:-34px;--dip:10px;--tilt:-2.5deg}
  /* deal the hand once the display face has landed */
  .nwf__card{opacity:0;transform:translateX(-50%) translateY(56px) rotate(0deg) scale(.94)}
  .is-dealt .nwf__card{opacity:1;
    transform:translateX(calc(-50% + var(--x) + var(--push,0px))) translateY(calc(var(--lift) + var(--dip,0px))) rotate(calc(var(--rot) + var(--tilt,0deg) + var(--lean,0deg)));
    transition:transform .72s cubic-bezier(.16,1,.3,1),opacity .5s ease-out,box-shadow .42s var(--ease-out),
               translate .55s var(--ease-out);
    transition-delay:var(--d)}
  /* Once dealt, the hand stops being staggered — otherwise the first hover
     after load waited out the deal's delay before the card would move. */
  .is-dealt .nwf__card:hover,.is-dealt .nwf__card:focus-visible{transition-delay:0s;
    transition:transform .3s var(--ease-out),box-shadow .3s var(--ease-out),translate .55s var(--ease-out)}
  .is-dealt .nwf__card:active{transition-delay:0s;transition-duration:.12s}
  .nwf__fan.is-settled .nwf__card{transition-delay:0s;
    transition:transform .5s cubic-bezier(.22,1,.36,1),box-shadow .42s var(--ease-out),translate .55s var(--ease-out)}
}
@media (max-width:759px){
  .nwf__card{flex:0 0 66vw;max-width:262px;height:216px;scroll-snap-align:center;
    transform:rotate(var(--lean,0deg));transition:transform .42s var(--ease-out)}
  .nwf__card:active{transform:rotate(var(--lean,0deg)) scale(.98);transition-duration:.12s}
}

/* ---- the hand breathes ----------------------------------------------------
   Two separate motions, on two separate properties, so neither has to know the
   other exists:

   The idle sway is a CSS animation on `rotate` — the standalone property, not
   the rotate() inside `transform`, which is already carrying the fan's layout,
   the deal and the hover. The browser composes translate → rotate → scale →
   transform, so this adds to the card's resting angle for free.

   The scroll lean is --lean, folded into that transform's rotate(). JS writes a
   target and the existing .42s transform transition does the damping, which is
   why there is no requestAnimationFrame loop for it.

   Amplitudes are largest at the ends of the fan and smallest at the middle —
   a held hand pivots about its centre — and the periods are deliberately
   unrelated (6.9s to 10.2s) so the five never fall into step and start looking
   like a machine. */
@keyframes nwfSway{
  0%,100%{rotate:calc(var(--sw,.6deg) * -1)}
  50%    {rotate:var(--sw,.6deg)}
}
.is-dealt .nwf__card{animation:nwfSway var(--swd,8s) ease-in-out var(--swdl,0s) infinite}
/* a card under the pointer is being held, so it stops moving */
.nwf__card:hover,.nwf__card:focus-visible{animation-play-state:paused}
/* and the whole hand rests while it is scrolled past. The class is added by
   the same observer that gates the scroll lean; without JS it never arrives,
   so the default has to be the moving state, not the parked one. */
.nwf__fan.is-parked .nwf__card{animation-play-state:paused}

@media (prefers-reduced-motion:reduce){
  .nwf__aside svg,.is-dealt .nwf__aside>span,.is-dealt .nwf__aside path{animation:none;stroke-dashoffset:0;clip-path:none;opacity:1}
  .nwf__dot::after,.nwf__next b.is-new{animation:none}
  .nwf__card{opacity:1!important;transition:none}
  .nwf__card:not(.has-bg) .nwf__pic,.nwf__go span{transition:none}
  .is-dealt .nwf__card{animation:none;rotate:none}
}

/* =========================================================================
   NEW WAKEFIELD — the masthead
   A white bar floating inside the page rather than a rule ruled across it:
   inset from all three edges, squared-off rounded corners, wordmark left,
   links centre, two actions right — quiet then loud.

   The shell is transparent and only the bar is opaque, which is what makes it
   read as floating — the page slides behind the gutter and under the bar's
   corners as you scroll.
   ========================================================================= */
/* setNavTop() writes an inline top of 24px for the scaffold's floating pill.
   This bar floats too, but by 10px, so the inline style still needs an
   !important to overrule — the alternative was editing shared scroll code. */
html:not(.app-mode) .navshell{position:sticky;top:10px !important;z-index:200;
  padding:10px clamp(10px,2.2vw,26px) 0;justify-content:stretch;
  background:none;border:0;backdrop-filter:none;-webkit-backdrop-filter:none}
html:not(.app-mode) .pillnav{width:100%;max-width:var(--maxw);margin-inline:auto;
  align-items:center;gap:clamp(8px,1.6vw,22px);
  padding:9px 9px 9px clamp(16px,1.8vw,22px);border-radius:18px;
  background:oklch(99.2% 0.007 88);
  border:1px solid color-mix(in srgb,var(--navy) 9%,transparent);
  box-shadow:0 1px 2px color-mix(in srgb,var(--navy) 6%,transparent),
             0 10px 26px -18px color-mix(in srgb,var(--navy) 48%,transparent);
  transition:box-shadow .32s ease}
html:not(.app-mode) .pillnav::before{display:none}
/* once the page has moved under it, the bar lifts a little further off */
html.nav-stuck:not(.app-mode) .pillnav{
  box-shadow:0 1px 2px color-mix(in srgb,var(--navy) 8%,transparent),
             0 16px 38px -20px color-mix(in srgb,var(--navy) 62%,transparent)}

/* ---- brand ---- */
html:not(.app-mode) .pillnav .brand{display:flex;align-items:center;gap:10px;
  color:var(--ink-strong);flex:none}
/* the crest carries its own gold ring — a navy disc behind it just muddies it */
html:not(.app-mode) .brand__logo{background:none;box-shadow:none;border-radius:0;
  width:clamp(34px,3vw,40px);height:clamp(34px,3vw,40px);flex:none}
html:not(.app-mode) .pillnav .brand__name{display:block;color:var(--ink-strong);
  font-family:var(--font-display);font-weight:700;letter-spacing:-.014em;
  font-size:clamp(1rem,1.25vw,1.12rem);line-height:1.04;white-space:nowrap}
html:not(.app-mode) .pillnav .brand__name>span{display:block;margin-top:.22em;
  font-family:var(--font-accent);font-weight:600;font-size:.58rem;letter-spacing:.2em;
  text-transform:uppercase;color:var(--muted)}

/* ---- links, centred in the bar ---- */
html:not(.app-mode) .nav__links{display:flex;align-items:center;flex:1;min-width:0}
html:not(.app-mode) .menu{margin-inline:auto;gap:clamp(0px,.4vw,6px)}
html:not(.app-mode) .menu>li>a,
html:not(.app-mode) .menu>li>button{position:relative;color:var(--ink-soft);
  font-family:var(--font-display);font-weight:500;font-size:.98rem;
  padding:.52em .8em;border-radius:10px;background:none;
  transition:color .25s,background .25s}
html:not(.app-mode) .menu>li>a:hover,
html:not(.app-mode) .menu>li>button:hover{color:var(--ink-strong);
  background:color-mix(in srgb,var(--navy) 5%,transparent)}
/* A section with children renders as a <button>, so About on /about was the
   one page that never marked itself current. */
html:not(.app-mode) .menu>li>a[aria-current="page"],
html:not(.app-mode) .menu>li>button[aria-current="page"]{color:var(--ink-strong);font-weight:600;
  background:color-mix(in srgb,var(--cyan) 17%,transparent)}
html:not(.app-mode) .menu__pill{display:none}

/* ---- the two actions ---- */
html:not(.app-mode) .nav__actions{margin-left:auto;flex:none;gap:7px}
html:not(.app-mode) .nav__actions .btn{padding:.6em 1.25em;font-family:var(--font-display);
  font-weight:600;font-size:.92rem;box-shadow:none;border-radius:11px}
/* quiet */
html:not(.app-mode) .nav__actions .btn--quiet{background:color-mix(in srgb,var(--navy) 6%,transparent);
  color:var(--ink-strong);border:1px solid transparent}
html:not(.app-mode) .nav__actions .btn--quiet:hover{background:color-mix(in srgb,var(--navy) 10%,transparent)}
/* loud — the crest's purple, which on a white bar reads harder than the gold did */
html:not(.app-mode) .nav__actions .btn--accent{background:var(--navy);color:var(--paper);
  border-color:var(--navy);font-weight:700}
html:not(.app-mode) .nav__actions .btn--accent:hover{background:color-mix(in oklch,var(--navy) 86%,black)}
html.dark:not(.app-mode) .nav__actions .btn--accent{background:var(--navy);color:#fdf9f2;border-color:var(--navy)}
html.dark:not(.app-mode) .nav__actions .btn--accent:hover{background:color-mix(in oklch,var(--navy) 80%,white)}

/* The bar is opaque and light in both schemes — it is a sheet of paper laid on
   the page, and a dark one would stop reading as one. */
html.dark:not(.app-mode) .pillnav{background:oklch(96% 0.012 88);
  border-color:color-mix(in srgb,#000 12%,transparent)}
html.dark:not(.app-mode) .pillnav .brand,
html.dark:not(.app-mode) .pillnav .brand__name,
html.dark:not(.app-mode) .menu>li>a,
html.dark:not(.app-mode) .menu>li>button{color:#3a1b52}
html.dark:not(.app-mode) .pillnav .brand__name>span{color:#7b5f8c}
html.dark:not(.app-mode) .nav__actions .btn--quiet{background:color-mix(in srgb,#3a1b52 8%,transparent);color:#3a1b52}

@media (prefers-reduced-motion:reduce){
  html:not(.app-mode) .pillnav,
  html:not(.app-mode) .menu>li>a,
  html:not(.app-mode) .menu>li>button{transition:none}
}

/* ---- out of the way -------------------------------------------------------
   Scroll down and the bar leaves; scroll up, even a little, and it comes back.
   The scaffold already did this and I had switched it off when the masthead
   sat in flow, where sliding a full-width rule off the top read as a glitch.
   A bar that floats can leave without anything looking broken.

   The travel is its own height plus the 10px gutter plus room for the shadow,
   so nothing is left peeking above the fold. Slide only, no fade: at this size
   a fading bar reads as a rendering fault rather than a decision. */
html:not(.app-mode) .navshell.hide{transform:translateY(calc(-100% - 22px))}
/* The dropdowns are position:absolute against their own <li>, so they ride
   along with the bar rather than being stranded — and the phone menu is a
   sibling of the bar, not a child, so it is unaffected either way. */
html:not(.app-mode) .nwf{padding-block:clamp(44px,5.6vw,84px) clamp(46px,5.5vw,78px)}
html:not(.app-mode) .pghead{padding-top:clamp(32px,4.6vw,58px)}

/* =========================================================================
   NEW WAKEFIELD — the section system
   One shape, used on every inner page: a small-caps label in a narrow left
   column, the content in a wide right one, and lists as ruled rows rather
   than cards. This is what replaces the scaffold's eyebrow + serif-accent
   heading over a grid of rounded boxes.
   ========================================================================= */
.fsec{border-top:1px solid var(--line);padding-block:clamp(44px,6.5vw,88px)}

/* ---- giving: the one route you can act on from this page ----
   Online giving was row 03 of a ruled list, weighted the same as "post us a
   cheque" — so the only thing on the page that actually does something looked
   like a footnote. The row stays (the list answers "what are my options"), and
   this is the answer to "so how do I give". */
.givecta{margin-top:var(--space-xl);display:flex;flex-direction:column;align-items:flex-start;gap:.7rem}
.btn--give{display:inline-flex;align-items:center;gap:.6em;padding:1.05em 1.7em;
  font-family:var(--font-display);font-size:1.08rem;font-weight:600;border-radius:100px}
.btn--give svg{flex:none}
.btn--give .arrow{transition:transform .34s var(--ease-out)}
.btn--give:hover .arrow{transform:translateX(4px)}
.givecta__s{font-size:.86rem;color:var(--muted);max-width:44ch}
/* the row above it can afford to be quieter now that it is not the only door */
.giverow .m{color:var(--cyan-deep)}
@media(prefers-reduced-motion:reduce){.btn--give .arrow{transition:none}}
@media(max-width:560px){.givecta{align-items:stretch}
  .btn--give{justify-content:center;width:100%}}

/* A photograph given the full width of the page, between two ruled sections.
   The church has very few photographs; the ones that exist get room rather than
   being shrunk into a column. Height is a ratio, not a fixed value, so a 4:3
   snapshot is never letterboxed into a cinematic strip on a phone. */
.fband{margin:0;border-top:1px solid var(--line)}
.fband__img{position:relative;overflow:hidden;aspect-ratio:4/3;max-height:70vh;background:var(--tint)}
@media (min-width:760px){.fband__img{aspect-ratio:21/9}}
.fband__img .fill{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  object-position:50% 38%;display:block}
.fband figcaption{padding:var(--space-sm) 0 0;text-align:center}
.fband figcaption::before{content:"";display:inline-block;width:18px;height:1px;
  background:var(--cyan);vertical-align:middle;margin-right:.6em}
.fsec:first-of-type{border-top:0}
.fsec--tint{background:var(--cream)}
.fsec__grid{display:grid;gap:clamp(22px,4vw,56px)}
@media (min-width:920px){.fsec__grid{grid-template-columns:.78fr 2fr;align-items:start}}
.flab{font-family:var(--font-accent);font-size:.72rem;font-weight:600;letter-spacing:.14em;
  text-transform:uppercase;color:var(--muted)}
.fsec h2{font-family:var(--font-display);font-weight:800;letter-spacing:-.025em;
  font-size:clamp(1.95rem,4.4vw,2.95rem);line-height:1.05;color:var(--ink-strong);
  margin:0 0 var(--space-md)}
.fsec h2 em,.fsec h2 .serif{font-style:italic;color:var(--cyan)}
.fsec__body>p,.fsec__body .lead{max-width:60ch;margin:0 0 1em;color:var(--ink-soft)}

/* ---- ruled rows ---- */
.frows{list-style:none;margin:var(--space-lg) 0 0;padding:0;border-top:1px solid var(--line)}
.frows>li{border-bottom:1px solid var(--line)}
.frows__in{display:flex;align-items:baseline;gap:var(--space-sm);padding-block:var(--space-md);
  position:relative;text-decoration:none;color:inherit;
  transition:padding-left .34s var(--ease-out)}
a.frows__in:hover{padding-left:var(--space-sm)}
.frows__in::before{content:"";position:absolute;left:0;top:0;bottom:0;width:0;z-index:-1;
  background:color-mix(in oklch,var(--cyan) 14%,transparent);
  transition:width .34s var(--ease-out)}
a.frows__in:hover::before{width:100%}
.frows .n{font-family:var(--font-accent);font-size:.72rem;font-weight:700;letter-spacing:.14em;
  color:var(--cyan-deep);min-width:3.4em;flex:none;padding-top:.15em}
.frows .t{font-family:var(--font-display);font-weight:600;font-size:1.2rem;line-height:1.3;
  color:var(--ink-strong)}
.frows .d{display:block;font-family:var(--font-body);font-weight:400;font-size:.92rem;
  color:var(--ink-soft);margin-top:.25rem;max-width:56ch}
.frows .m{margin-left:auto;padding-left:var(--space-md);font-family:var(--font-accent);
  font-size:.74rem;letter-spacing:.12em;text-transform:uppercase;color:var(--muted);
  white-space:nowrap;flex:none}
.frows .m.todo{font-style:italic;text-transform:none;letter-spacing:0;font-size:.86rem}

/* a portrait, cut out and standing rather than framed */
.fport{margin:0;display:block;max-width:330px;width:100%;justify-self:center}
.fport img{width:100%;height:auto;display:block;filter:drop-shadow(0 18px 30px color-mix(in oklch,var(--navy) 18%,transparent))}
@media (min-width:920px){.fport{justify-self:start}}

/* ---- The Fan: shared page head + pull quote -------------------------------
   Every inner page opened with its own inline copy of this block. One copy,
   here, so a change to the page head is one edit rather than six.            */
.pghead{padding:clamp(40px,6vw,72px) 0 clamp(20px,3vw,34px);background:var(--paper)}
.pghead__wrap{max-width:800px}
.pghead h1{font-family:var(--font-display);font-weight:800;letter-spacing:-.03em;
  font-size:clamp(2.4rem,6vw,4rem);line-height:1;color:var(--ink-strong);margin:.6rem 0 0}
.pghead h1 em{font-style:italic;color:var(--cyan)}
.pghead .lead{margin-top:1.1rem;max-width:52ch;color:var(--ink-soft)}

.fquote{margin:0;font-family:var(--font-display);font-weight:500;font-style:italic;
  font-size:clamp(1.3rem,2.6vw,1.85rem);line-height:1.35;color:var(--ink-strong);
  max-width:24ch;text-wrap:balance;position:relative;padding-left:var(--space-lg)}
.fquote::before{content:"";position:absolute;left:0;top:.28em;bottom:.2em;width:3px;
  background:var(--cyan);border-radius:3px}
@media (max-width:560px){.fquote{max-width:none;padding-left:var(--space-md)}}

/* A ruled row has three parts and a phone has room for two. Below 560px the
   right-hand marker drops under the title instead of squeezing it to four
   words a line. */
@media (max-width:560px){
  .frows__in{flex-wrap:wrap}
  .frows .t{flex:1 1 0}
  .frows .m{order:3;flex:1 0 100%;margin-left:0;margin-top:.45rem;
    padding-left:calc(3.4em + var(--space-sm));white-space:normal}
  .frows .n{padding-top:.05em}
}

/* the latest message, inside a ruled section rather than a split card */
.fvid{margin-top:var(--space-lg);max-width:620px}


/* =========================================================================
   NEW WAKEFIELD — the polish pass
   Small things, all of them hover or press feedback. The rule throughout: a
   row or a control acknowledges the pointer, and nothing moves that the
   pointer is not on.
   ========================================================================= */

/* A ruled row already washes gold left-to-right on hover. Now the marker on
   the right leans into the direction of travel and the number warms up, so
   the whole row reads as one object rather than a background effect. */
.frows .n,.frows .m{transition:color .28s ease,transform .32s var(--ease-out)}
a.frows__in:hover .n{color:var(--cyan)}
a.frows__in:hover .m{color:var(--ink-strong);transform:translateX(4px)}
a.frows__in:focus-visible{outline:2px solid var(--cyan);outline-offset:3px;border-radius:4px}
/* the title shifts a hair so the eye has something to follow into the row */
.frows .t{transition:transform .32s var(--ease-out)}
a.frows__in:hover .t{transform:translateX(3px)}

/* A section label earns a short rule that draws itself in when the section
   arrives — the one piece of motion on an otherwise still page of text. */
/* Both of these start drawn. Only when the motion layer has actually loaded
   (html.motion, the same switch the reveal system uses) do they retract and
   wait — so with JS off, or if the module fails to import, the page is simply
   correct rather than missing its rules. */
.fsec .flab{position:relative;padding-left:26px}
.fsec .flab::before{content:"";position:absolute;left:0;top:.52em;width:18px;height:1px;
  background:var(--cyan);transform-origin:left;
  transition:transform .6s var(--ease-out) .12s}
.motion .fsec .flab::before{transform:scaleX(0)}
.motion .fsec[data-seen] .flab::before{transform:scaleX(1)}
@media (max-width:919px){.fsec .flab{padding-left:0}.fsec .flab::before{display:none}}

/* The pull quote's gold bar grows from the top rather than simply being there. */
.fquote::before{transform-origin:top;transition:transform .7s var(--ease-out) .1s}
.motion .fquote::before{transform:scaleY(0)}
.motion .fsec[data-seen] .fquote::before{transform:scaleY(1)}

/* A cut-out portrait drifts a few pixels with the scroll — enough to separate
   it from the page, not enough to notice as an effect. */
.fport img{transition:transform .6s var(--ease-out)}
.fport:hover img{transform:translateY(-4px)}

@media (prefers-reduced-motion:reduce){
  .motion .fsec .flab::before,.fsec .flab::before{transform:scaleX(1);transition:none}
  .motion .fquote::before,.fquote::before{transform:scaleY(1);transition:none}
  .frows .n,.frows .m,.frows .t,.fport img{transition:none}
  a.frows__in:hover .m,a.frows__in:hover .t{transform:none}
}

/* The hand keeps its faces in dark mode — they are the crest's own colours and
   restyling them at night would make the hero a different site. Each face now
   sets its own ink explicitly rather than inheriting --ink-strong, so nothing
   is left to flip; only the plum face needs a nudge, because the page behind it
   is nearly the same colour and the card would otherwise dissolve into it. */
html.dark .nwf__card--plum{background:oklch(37% 0.086 308);
  box-shadow:0 2px 3px -1px rgba(0,0,0,.5),0 16px 30px -18px rgba(0,0,0,.8)}
/* the warm glow behind the hand belongs to the cream page, not the night one */
html.dark .nwf::before{opacity:.13}

/* =========================================================================
   NEW WAKEFIELD — the phone bar
   The desktop is a printed masthead now, so the phone can't stay a dark
   floating pill parked over the hero — that was the same generic language,
   and at 390px it was sitting on top of the "Sunday worship 11:00" chip.
   A slim cream bar on the top edge instead: crest and name left, burger
   right, one hairline under it. Same markup, same burger, same menu.
   ========================================================================= */
@media (max-width:1040px){
  html:not(.app-mode) .mobtop{position:sticky;top:0;left:0;right:0;width:100%;
    gap:10px;padding:8px clamp(14px,4vw,22px);border:none;border-radius:0;
    border-bottom:1px solid var(--line);box-shadow:none;
    background:color-mix(in srgb,var(--paper) 90%,transparent);
    backdrop-filter:blur(12px) saturate(1.2);-webkit-backdrop-filter:blur(12px) saturate(1.2)}
  html:not(.app-mode) .mobtop .brand{color:var(--ink-strong);max-width:none;gap:9px;margin-right:auto}
  html:not(.app-mode) .mobtop .brand__logo{width:38px;height:38px;background:none;box-shadow:none;border-radius:0}
  /* the name rides along on the phone too — the crest alone is not a masthead */
  html:not(.app-mode) .mobtop .brand::after{content:"New Wakefield";font-family:var(--font-display);
    font-weight:700;font-size:1.02rem;letter-spacing:-.01em;color:var(--ink-strong);white-space:nowrap}
  html:not(.app-mode) .mobtop__burger{color:var(--ink-strong)}
  html:not(.app-mode) .mobtop__burger:hover,
  html:not(.app-mode) .mobtop__burger:active{background:color-mix(in srgb,var(--navy) 9%,transparent)}
  /* The brand no longer shrinks into the burger on scroll — the whole bar goes
     instead, which is what a swipe up should do. The inner rule is neutralised
     so the wordmark is still there when the bar comes back. */
  html:not(.app-mode) .mobtop.is-min .brand{max-width:none;opacity:1;margin:0 auto 0 0;transform:none}
  html:not(.app-mode) .mobtop{transition:transform .34s var(--ease-out)}
  html:not(.app-mode) .mobtop.is-min{transform:translateY(-110%)}
  /* the hero no longer has to duck under an overlay */
  html:not(.app-mode) .nwf{padding-block:clamp(30px,8vw,48px) clamp(34px,7vw,52px)}
  html:not(.app-mode) .pghead{padding-top:clamp(26px,5vw,40px)}
}

/* Reduced motion still wants the bars out of the way — leaving is a layout
   change, not decoration — they just should not be watched travelling there.
   This lives at the end of the sheet on purpose: the phone bar's transition is
   declared inside a max-width block further down, and at equal specificity the
   later rule wins, so a neutraliser placed above it silently did nothing. */
@media (prefers-reduced-motion:reduce){
  html:not(.app-mode) .navshell,
  html:not(.app-mode) .mobtop{transition:none}
}

/* Engine pages' own colours, in New Wakefield's (sermons, series, app page, live pill). */
:root{--accent-pale:#dfc17a;--navy-rgb:47,33,69;--page-accent:#9b7d29;--live-box:#38164f}

/* ===== sign-in gate (engine markup, New Wakefield's quiet design) =====
   A centred column on the page's own stock with the crest above the heading:
   no photograph and no translucent card over it. */
html .gate-banner{min-height:100svh;display:grid;place-items:center;background:var(--paper);
  background-image:radial-gradient(ellipse 120% 62% at 50% 0%,color-mix(in srgb,var(--cyan) 11%,transparent),transparent 70%)}
html .gate-banner .banner__photo,html .gate-banner .banner__scrim{display:none}
html .gate-banner .banner__inner{padding:clamp(104px,14vw,152px) var(--space-md) clamp(48px,7vw,84px)}
html .gate-card{width:min(430px,100%);max-width:430px;margin:0 auto;text-align:center;background:none;border:0;box-shadow:none;
  backdrop-filter:none;-webkit-backdrop-filter:none;padding:0;color:var(--ink-strong)}
html .gate-card::before{content:"";display:block;width:78px;height:78px;margin:0 auto var(--space-md);
  background:url(/assets/img/nw/crest-512.webp) center/contain no-repeat;
  filter:drop-shadow(0 6px 16px color-mix(in oklch,var(--navy) 22%,transparent))}
html .gate-card .eyebrow{color:var(--navy)}
html .gate-card h1{font-size:clamp(2.2rem,6vw,2.9rem);line-height:1.04;margin:0 0 var(--space-sm);color:var(--ink-strong)}
html .gate-card h1 .serif{font-style:italic;color:var(--cyan-deep)}
html .gate-card h1::after{content:"";display:block;width:34px;height:1px;background:var(--cyan);margin:var(--space-sm) auto 0}
html .gate-card h1 + p{color:var(--ink-soft);line-height:1.62;margin:0 auto var(--space-lg);max-width:38ch}
html .gate__tabs{display:flex;justify-content:center;gap:26px;border-bottom:1px solid var(--line);background:none;border-radius:0;padding:0;margin:0 0 var(--space-lg)}
html .gate__tab{flex:0 0 auto;border:0;background:none;padding:0 0 .75rem;font-family:var(--font-accent);font-size:.78rem;font-weight:600;
  letter-spacing:.11em;text-transform:uppercase;color:var(--muted);border-bottom:2px solid transparent;margin-bottom:-1px;min-height:44px;border-radius:0;box-shadow:none}
html .gate__tab:hover{color:var(--ink-strong)}
html .gate__tab.on{background:none;color:var(--ink-strong);border-bottom-color:var(--cyan);box-shadow:none}
html .gate__pane{text-align:left}
html .gate__pane .field label{display:block;font-family:var(--font-accent);font-size:.68rem;font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:var(--muted);margin:0 0 .35rem}
html .gate__pane .field input{width:100%;padding:.85rem .1rem;border:0;border-radius:0;border-bottom:1px solid var(--line);background:none;
  font-family:var(--font-body);font-size:1rem;color:var(--ink-strong);box-shadow:none}
html .gate__pane .field input:focus{outline:none;border-bottom-color:var(--cyan)}
html .gate__hint{font-size:.83rem;color:var(--muted);margin-top:16px;line-height:1.6}
html .gate__hint a{color:var(--cyan-deep);text-decoration:underline;text-underline-offset:3px}
html .gate-card .pnote{text-align:left}
