/* ============================================================
   THREE CREEKS CHURCH — DESIGN SYSTEM
   Token-based. Light + dark. One file, every page.
   See design-system.html for the living reference.
   ============================================================ */

/* ---- 1. TOKENS ------------------------------------------- */
:root{
  /* primitives — the brand palette, mode-independent */
  --sky:#A9C9DB;
  --mist:#C0DDEB;
  --steel:#7F98AA;
  /* the same steel taken to a ground: deep enough to carry white type at 7.8:1
     and still hold --sky above it at 4.5:1, which is what the mid-tone steel
     cannot do — white only reaches 3:1 on --steel itself. */
  --steel-deep:#3A5568;
  --lime:#D4DC70;
  --lime-deep:#C6CF60;

  /* Three Creeks Kids sub-brand — the two primitives the parent brand needs to
     know about, so a kids call-to-action can sit on any page on-brand. The full
     sub-brand (water, creatures, Luna) lives in css/kids.css and loads only on
     kids surfaces. See kids-brand.html. */
  /* the kids equivalent of --lime: the one action colour the sub-brand spends.
     Close to --k-seahorse in css/kids.css but not the same value and not a
     substitute for it — seahorse is a roster key, a mark that never sets type,
     and splash is tuned to carry ink at 9.9:1 as a pill ground. */
  --k-splash:#4CD4CF;
  --k-splash-deep:#33BDB8;
  --k-mint:#C6E7C3;         /* signature band — a fill colour, never text */
  --k-ground:#12303A;       /* deep water — the ground .kcta is quoted on, §11b */

  /* semantic — light */
  --bg:#FBFBFC;             /* page */
  --surface:#F1F3F5;        /* recessed panels, footer */
  --card:#FFFFFF;           /* raised cards */
  --tx:#16171B;             /* primary text */
  --tx-dim:#6E7079;         /* secondary text */
  --brand:#4F6E85;          /* steel accent, AA on --bg */
  --mark:#4F6E85;           /* nav wordmark — tracks brand in light, goes near-white in dark */
  --hair:rgba(22,23,27,.12);        /* rules + borders */
  --hair-soft:rgba(22,23,27,.08);   /* card borders */
  --press:rgba(22,23,27,.06);       /* hover/active wash */

  --stmt-bg:#16171B;        /* full-bleed statement panel */
  --stmt-tx:#FFFFFF;
  --stmt-accent:var(--sky);

  --pill-bg:var(--tx);      /* solid pill inverts the page */
  --pill-tx:#FFFFFF;
  --pill-bg-hover:#33343A;

  /* the bar's wash — the page's own colour, so over plain page it is invisible
     and only shows where content passes under the bar. That is also what makes
     the alpha a contrast floor and not a taste knob: blur keeps a dark thing
     dark, so this is the only reason --tx clears 4.5:1 over a .stmt band or a
     photo. Light can afford .60 (4.6:1 over pure black); dark is the tight one
     and sits near its floor at .70 (4.6:1 under a blown-out sky). Going lower
     either way fails AA — see §3a. */
  --nav-bg:rgba(251,251,252,.60);
  --scrim:rgba(18,20,24,.44);
  --shadow-card:0 1px 2px rgba(22,23,27,.06),0 12px 34px -20px rgba(22,23,27,.4);

  /* mobile menu — the one surface that leaves the page palette. In light it is
     a steel-blue ground carrying white type, the same figure/ground as the
     mission panel: opening the menu reads as stepping into the brand rather
     than onto another white panel. The ground has to be --steel-deep and not
     the mid-tone --steel the mood suggests, because white only manages 3:1 on
     --steel and most of this sheet is small text. Taken that deep, the ink and
     the overlays both go white and --sky can carry the accent. Dark keeps the
     page palette and only sinks the ground below --bg. */
  --m-bg:var(--steel-deep);
  --m-tx:#FFFFFF;           /* 7.8:1 on --m-bg */
  --m-tx-dim:#C3D5E0;       /* 5.2:1 */
  --m-accent:var(--sky);    /* 4.5:1 — the shallowest ground sky clears */
  --m-rule:rgba(255,255,255,.28);
  --m-hair:rgba(255,255,255,.18);
  --m-press:rgba(255,255,255,.10);

  /* type */
  --f:"Schibsted Grotesk",-apple-system,system-ui,sans-serif;
  --m:"DM Mono",monospace;

  /* shape — varied on purpose: frames are soft, cards firm, chips tight */
  --r-frame:clamp(20px,2.6vw,34px);
  --r-card:22px;
  --r-tile:24px;
  --r-chip:6px;
  --r-pill:980px;

  /* motion — two curves only: --ease decelerates for entrances,
     --spring overshoots a hair for things the user directly drives */
  --ease:cubic-bezier(.22,1,.36,1);
  --spring:cubic-bezier(.32,.72,0,1);

  /* layout — the nav is the only chrome the page has to reserve room for.
     One height, held the whole way down the page; body padding matches it,
     so nothing hides behind it at the top. */
  --nav-h:76px;

  color-scheme:light;
}

/* dark — warm near-black built from the brand ink, not purple-navy */
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]){
    --bg:#121316;
    --surface:#1A1B20;
    --card:#1E2026;
    --tx:#ECEDEF;
    --tx-dim:#9DA0A8;
    --brand:#8FB0C8;
    --mark:#F2F3F5;
    --hair:rgba(236,237,239,.15);
    --hair-soft:rgba(236,237,239,.09);
    --press:rgba(236,237,239,.07);

    --stmt-bg:#0B0C0E;
    --stmt-tx:#F4F5F6;

    --pill-bg:#ECEDEF;
    --pill-tx:#16171B;
    --pill-bg-hover:#CDCFD4;

    --nav-bg:rgba(18,19,22,.70);
    --scrim:rgba(0,0,0,.55);
    --shadow-card:0 1px 2px rgba(0,0,0,.4),0 12px 34px -20px rgba(0,0,0,.8);

    /* the sheet sits under the page here, not beside it */
    --m-bg:#0B0C0E;
    --m-tx:var(--tx);
    --m-tx-dim:var(--tx-dim);
    --m-accent:var(--brand);
    --m-rule:rgba(127,152,170,.5);
    --m-hair:var(--hair);
    --m-press:var(--press);

    color-scheme:dark;
  }
}
:root[data-theme="dark"]{
  --bg:#121316;
  --surface:#1A1B20;
  --card:#1E2026;
  --tx:#ECEDEF;
  --tx-dim:#9DA0A8;
  --brand:#8FB0C8;
  --mark:#F2F3F5;
  --hair:rgba(236,237,239,.15);
  --hair-soft:rgba(236,237,239,.09);
  --press:rgba(236,237,239,.07);

  --stmt-bg:#0B0C0E;
  --stmt-tx:#F4F5F6;

  --pill-bg:#ECEDEF;
  --pill-tx:#16171B;
  --pill-bg-hover:#CDCFD4;

  --nav-bg:rgba(18,19,22,.70);
  --scrim:rgba(0,0,0,.55);
  --shadow-card:0 1px 2px rgba(0,0,0,.4),0 12px 34px -20px rgba(0,0,0,.8);

  --m-bg:#0B0C0E;
  --m-tx:var(--tx);
  --m-tx-dim:var(--tx-dim);
  --m-accent:var(--brand);
  --m-rule:rgba(127,152,170,.5);
  --m-hair:var(--hair);
  --m-press:var(--press);

  color-scheme:dark;
}

/* ---- 2. BASE ---------------------------------------------- */
*,*::before,*::after{box-sizing:border-box}
/* Anything that has to clear the fixed chrome measures it the same way: the nav's
   own height plus whatever the announcement bar above it is taking, plus a little
   air. With no bar on the page --cta-h resolves to 0 and this is the offset it
   always was. Anchor landings get it as scroll padding, so a jump to #kids or
   Skip to content does not put the target under the bar. */
html{scroll-behavior:smooth;scroll-padding-top:calc(var(--nav-h) + var(--cta-h,0px) + 12px)}
body{margin:0;padding-top:calc(var(--nav-h) + var(--cta-h,0px));background:var(--bg);color:var(--tx);
  font-family:var(--f);font-size:17px;line-height:1.55;-webkit-font-smoothing:antialiased}
img{max-width:100%;display:block}
h1,h2,h3{margin:0;font-weight:800;line-height:1.02;letter-spacing:-.042em}
p{margin:0 0 1em}

/* No heading, subhead or label ends on a word by itself. balance evens the
   line lengths, which retires most widows on its own and gives the rag a
   deliberate shape; the widow guard in js/site.js binds the last two words
   for the rest, and for anything that lands here without balance support.
   Mirrored by WIDOW in js/site.js — edit both together. */
h1,h2,h3,h4,
.k,.rail__k,.point__k,.m-when__k,.mo,
.lede,.stage .l,.stmt .l,.rail__t,.foot__v,.m-when__t,
.rooms b,.vals b,.tl b,.tree b,.gcard b,.person b,.msg b,.pager b,.navsub__l span{text-wrap:balance}
a{color:inherit}
.wrap{width:min(1280px,90vw);margin-inline:auto}
.skip{position:absolute;left:-9999px}
.skip:focus{left:0;top:0;background:var(--tx);color:var(--bg);padding:.8rem 1.2rem;z-index:99}
:where(a,button):focus-visible{outline:2px solid var(--brand);outline-offset:4px;border-radius:6px}

/* eyebrow */
.k{font-family:var(--m);font-size:.7rem;letter-spacing:.16em;text-transform:uppercase;
  color:var(--brand);margin:0 0 1.1rem}

/* chip — small inline tag */
.chip{display:inline-block;font-family:var(--m);font-size:.58rem;letter-spacing:.12em;
  text-transform:uppercase;padding:.16rem .45rem;border-radius:var(--r-chip);
  border:.5px solid var(--hair);color:var(--tx-dim);vertical-align:middle}
.chip--lime{background:var(--lime);border-color:var(--lime);color:#16171B}
/* a label, not an action: outlined rather than filled, and in the eyebrow's own
   steel so the badge leads the line it sits on instead of being outshone by the
   date beside it. Filled chips are for states (open, this week); this one names
   what a thing is. */
.chip--brand{border-color:var(--brand);color:var(--brand)}
.k .chip{margin-right:.55rem}
.chip--kids{background:var(--k-mint);border-color:var(--k-mint);color:#16171B}

/* ---- 3. NAV ------------------------------------------------ */
/* Fixed, not sticky: the page runs under the glass rather than stopping at it,
   which is what the graduated blur in §3a is drawn for. body carries the
   matching top padding instead. The one thing that can sit above it is the
   announcement bar in §3c, which is why the top is a variable and not 0 —
   with no bar on the page it resolves to 0 and this is the rule it always was. */
.nav{position:fixed;top:var(--cta-h,0px);left:0;right:0;z-index:50}

/* ---- 3a. GLASS --------------------------------------------- *
 * Shared by .nav here and by .m-bar in §21 — the two fixed bars the page runs
 * under.
 *
 * FALLBACK, and it is the rule that comes first: one flat opaque pane inside
 * the bar's own box, with a hairline for its edge. That is what a browser
 * without backdrop-filter or without masks gets, it is legible, and everything
 * below is an upgrade layered on top of it.
 *
 * PROGRESSIVE, where both are supported: the bar stops having an edge and
 * starts having a gradient. A single pane of backdrop-filter ends in a hard
 * line, and the eye reads that line as the rim of a sheet of glass laid over
 * the page — two objects. The illusion worth having is the other one: the page
 * itself softening as it runs under the bar.
 *
 * Why six panes. Masking a pane of backdrop-filter fades how much of it you
 * get, not how wide its blur is: half an 18px pane is a sharp image with an
 * 18px ghost over it, not a 9px blur. Read that ghost and the ramp reads as
 * two sheets crossfading instead of one page softening — which is exactly what
 * too few panes, too far apart, looks like. So the strength has to climb by
 * handing off between panes near enough in radius that the handover cannot be
 * seen, and a step of about 1.8x is near enough. A pane also filters whatever
 * is already painted beneath it, so across the overlaps the radii compound:
 *
 *     order   pane              blur    solid to   gone by
 *       1     .nav::before      1.0px      70%       100%    + the tint
 *       2     .glass::before    1.8px      55%        82%
 *       3     .glass i::before  3.2px      42%        66%
 *       4     .glass i::after   5.6px      30%        52%
 *       5     .glass::after      10px      19%        38%
 *       6     .nav::after        18px       8%        25%
 *
 * which compounds to about 22px at the bar's own edge and nothing at the far
 * one. Percentages are of the band, not of the bar.
 *
 * The order in that table is paint order, and paint order here is just tree
 * order — a bar's ::before is its first child and its ::after its last, and
 * .glass sits between them wrapping the rest — so the sequence holds with no
 * z-index beyond the one that puts every pane behind the links. Reorder the
 * markup and the ramp inverts; there is nothing else holding it.
 *
 * .glass and its <i> are this file's one concession to markup: two empty
 * aria-hidden elements at the top of each bar, there because six panes need
 * three hosts and a bar brings only its own two pseudo-elements. They are
 * hosts and nothing else — no filter, no mask, no opacity, ever. Any of those
 * makes an element a BACKDROP ROOT, and a pane inside a backdrop root filters
 * the empty space within its host instead of the page: a dead pane that costs
 * exactly as much as a live one and shows nothing. That rule is also why the
 * ramp cannot be faded in on scroll, and why the menu below takes the whole
 * stack out in one move rather than dissolving it.
 *
 * --g-over is the reach past the bar's own box. The dissolve needs more room
 * than the bar has, and taking it into the page costs nothing but a promise
 * never to take a click there. --g-x is the axis: the header dissolves
 * downward, the mobile bar upward.
 *
 * The hairline is dropped in this branch on purpose. A hard rule under a soft
 * fade puts the edge back, and the fade is the edge now.
 * ------------------------------------------------------------ */
.nav::before,.m-bar::before{content:"";position:absolute;inset:0;z-index:-1;
  pointer-events:none;background:var(--bg)}
.nav::before{box-shadow:0 .5px 0 var(--hair)}
.m-bar::before{box-shadow:0 -.5px 0 var(--hair)}
.glass{display:none}

@supports ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px)))
      and ((mask-image:linear-gradient(#000,transparent)) or
           (-webkit-mask-image:linear-gradient(#000,transparent))){

  /* the hosts — geometry only, and the band is the same box for all of them */
  .glass{display:block;position:absolute;left:0;right:0;z-index:-1;
    pointer-events:none;height:calc(100% + var(--g-over))}
  .glass i{position:absolute;inset:0}
  .nav>.glass,.nav::before,.nav::after{--g-over:38px;--g-x:to bottom;top:0;bottom:auto}
  .m-bar>.glass,.m-bar::before,.m-bar::after{--g-over:30px;--g-x:to top;bottom:0;top:auto}

  /* the panes — 1 and 6 span the band off the bar, 2 to 5 off the hosts */
  .nav::before,.nav::after,.m-bar::before,.m-bar::after{
    content:"";position:absolute;left:0;right:0;z-index:-1;pointer-events:none;
    height:calc(100% + var(--g-over));background:none;box-shadow:none}
  .glass::before,.glass::after,.glass i::before,.glass i::after{
    content:"";position:absolute;inset:0}

  /* 1 — reaches the whole way and carries the tint, so colour and softness
         arrive on one axis. Its 1px is under the threshold of a visible edge,
         which is what lets the far end of the band simply stop.
         The tint is the legibility floor for the whole bar, not decoration:
         blur preserves luminance, so without it --tx over a .stmt band is
         1:1. Only pane 1 carries it, and it must stay solid past the links —
         44% of the band is 50px of 114, and the links sit at 28-48px. Move
         that stop or lower --nav-bg's alpha and the links go under 4.5:1. */
  .nav::before,.m-bar::before{
    backdrop-filter:saturate(150%) blur(1px);-webkit-backdrop-filter:saturate(150%) blur(1px);
    background:linear-gradient(var(--g-x),var(--nav-bg) 0 44%,transparent 94%);
    -webkit-mask-image:linear-gradient(var(--g-x),#000 0 70%,transparent);
    mask-image:linear-gradient(var(--g-x),#000 0 70%,transparent)}

  /* 2 */
  .glass::before{backdrop-filter:blur(1.8px);-webkit-backdrop-filter:blur(1.8px);
    -webkit-mask-image:linear-gradient(var(--g-x),#000 0 55%,transparent 82%);
    mask-image:linear-gradient(var(--g-x),#000 0 55%,transparent 82%)}

  /* 3 */
  .glass i::before{backdrop-filter:blur(3.2px);-webkit-backdrop-filter:blur(3.2px);
    -webkit-mask-image:linear-gradient(var(--g-x),#000 0 42%,transparent 66%);
    mask-image:linear-gradient(var(--g-x),#000 0 42%,transparent 66%)}

  /* 4 */
  .glass i::after{backdrop-filter:blur(5.6px);-webkit-backdrop-filter:blur(5.6px);
    -webkit-mask-image:linear-gradient(var(--g-x),#000 0 30%,transparent 52%);
    mask-image:linear-gradient(var(--g-x),#000 0 30%,transparent 52%)}

  /* 5 */
  .glass::after{backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
    -webkit-mask-image:linear-gradient(var(--g-x),#000 0 19%,transparent 38%);
    mask-image:linear-gradient(var(--g-x),#000 0 19%,transparent 38%)}

  /* 6 */
  .nav::after,.m-bar::after{
    backdrop-filter:blur(18px);-webkit-backdrop-filter:blur(18px);
    -webkit-mask-image:linear-gradient(var(--g-x),#000 0 8%,transparent 25%);
    mask-image:linear-gradient(var(--g-x),#000 0 8%,transparent 25%)}
}
.nav__in{display:flex;align-items:center;justify-content:space-between;gap:2rem;
  height:var(--nav-h);font-size:.83rem;font-weight:500}

/* One link, one mark, one size — the bar holds its height the whole way down
   the page, so the lockup never has to trade itself for a roundel. Sized off
   its own vars rather than the bar's, so the two can be tuned apart. */
.mark{--mark-w:71px;--mark-h:40px;
  position:relative;display:block;text-decoration:none;color:var(--mark);
  width:var(--mark-w);height:var(--mark-h)}
/* the brand SVG is applied as a mask so it takes currentColor in both themes */
.mark b{position:absolute;left:0;top:0;bottom:0;margin-block:auto;
  width:var(--mark-w);height:var(--mark-h);
  background:currentColor;transform-origin:left center;
  -webkit-mask:url("../assets/three-creeks_logo.svg") no-repeat center/contain;
  mask:url("../assets/three-creeks_logo.svg") no-repeat center/contain}
/* SCROLLED — the lockup hands off to the roundel once the page has moved.
   Both glyphs sit in the same box and the box keeps --mark-w and --mark-h the
   whole way, so nothing about the bar's height changes and the link row beside
   it never shifts: the swap is a cross-fade on opacity and nothing else. The
   roundel is square, so it takes --mark-h for its width and sits left in the
   box the lockup already occupied. .is-scrolled is set in js/site.js. */
.mark::before{content:"";position:absolute;left:0;top:0;bottom:0;margin-block:auto;
  width:var(--mark-h);height:var(--mark-h);background:currentColor;opacity:0;
  -webkit-mask:url("../assets/three-creeks_ico-solid.svg") no-repeat center/contain;
  mask:url("../assets/three-creeks_ico-solid.svg") no-repeat center/contain}
.mark b,.mark::before{transition:opacity .28s ease}
.nav.is-scrolled .mark b{opacity:0}
.nav.is-scrolled .mark::before{opacity:1}
/* The link row stretches to the full height of the bar rather than sitting at
   its own line height: a group's panel hangs off the bottom of its <li>, so a
   short <li> would drop the panel across the middle of the bar and leave a
   dead gap between link and panel for the pointer to fall through. */
.nav__l{display:flex;align-self:stretch;gap:1.5rem;list-style:none;margin:0;padding:0}
.nav__l>li{position:relative;display:flex;align-items:center}
.nav__l>li>a{display:inline-flex;align-items:center;gap:.22rem;white-space:nowrap;
  text-decoration:none;color:var(--tx);opacity:.82}
.nav__l>li>a:hover,.nav__l>li>a[aria-current="page"],.nav__l>li>a.is-here{opacity:1}
/* the current page carries extra weight and a rule beneath it — two signals, so
   the state never rests on colour alone. The bar sets the link row's full height,
   so the rule is placed off the text rather than the box: bottom is measured from
   the link's own baseline box, which keeps it the same distance under every item.
   .is-here is the same mark for a group whose panel holds the page you are on. */
.nav__l>li>a[aria-current="page"],.nav__l>li>a.is-here{font-weight:700;position:relative}
.nav__l>li>a[aria-current="page"]::after,.nav__l>li>a.is-here::after{
  content:"";position:absolute;left:0;right:0;bottom:-7px;height:3px;
  border-radius:var(--r-pill);background:var(--brand)}
.nav__end{display:flex;align-items:center;gap:.6rem}

/* ---- 3b. NAV GROUP — header dropdown ----------------------- *
 * A top item that is both a real page and the door to its family. It stays a
 * plain <a>: clicking it goes to the page, so the group is never a dead end,
 * and the panel opens on hover and on :focus-within — which is CSS, not
 * script, so every page in the group is still reachable with the JS blocked.
 * js/site.js only adds what CSS cannot: a truthful aria-expanded, Escape to
 * shut a panel without leaving it, arrow keys, and tap-to-open on a coarse
 * pointer, where there is no hover to open it with.
 * ------------------------------------------------------------ */
.nav__cv{flex:none;margin-top:1px;transition:transform .3s var(--spring)}
.nav__grp:hover .nav__cv,.nav__grp:focus-within .nav__cv,
.nav__grp.is-open .nav__cv{transform:rotate(180deg)}
.nav__grp.is-shut .nav__cv{transform:none}

/* the padding is the bridge: it puts clear air between bar and card without
   opening a gap the pointer can cross on its way down */
.navsub{position:absolute;top:100%;left:50%;z-index:5;padding-top:.5rem;
  opacity:0;visibility:hidden;pointer-events:none;transform:translate(-50%,-6px);
  transition:opacity .22s ease,transform .34s var(--spring),visibility 0s .34s}
.navsub__c{width:320px;padding:.4rem;border-radius:var(--r-card);background:var(--card);
  border:.5px solid var(--hair-soft);box-shadow:var(--shadow-card)}
.navsub__l{list-style:none;margin:0;padding:0}
.navsub__l a{display:block;padding:.55rem .7rem;border-radius:15px;
  text-decoration:none;color:var(--tx)}
.navsub__l a:hover{background:var(--press)}
.navsub__l b{display:block;font-size:.88rem;font-weight:700;letter-spacing:-.025em}
.navsub__l span{display:block;margin-top:.05rem;font-size:.77rem;line-height:1.35;
  color:var(--tx-dim);font-weight:400}
.navsub__l a[aria-current="page"]{background:var(--press)}
.navsub__l a[aria-current="page"] b{color:var(--brand)}

/* a short open delay keeps a pointer crossing the bar from flashing the panel;
   closing stays immediate */
.nav__grp:hover>.navsub,.nav__grp:focus-within>.navsub,.nav__grp.is-open>.navsub{
  opacity:1;visibility:visible;pointer-events:auto;transform:translate(-50%,0);
  transition-delay:.07s,.07s,0s}
/* last word: Escape and a second tap shut a panel the pointer is still inside */
.nav__grp.is-shut>.navsub{opacity:0;visibility:hidden;pointer-events:none;
  transform:translate(-50%,-6px);transition-delay:0s}

/* ---- 3c. ANNOUNCEMENT BAR ---------------------------------- */
/* Occasional and optional: Easter, a merged service, a Sunday with no gathering.
   It is not part of the site's furniture, so it does not live in the nav — it
   sits above it in the brand's own colour, and the page steps down to make room.
   One message, one action, one line. Anything that needs two sentences is not
   this component, it is a page.
 *
 * It is steel in both themes rather than a semantic token. Every other surface
 * here answers to the page's mode; this one has to read as an interruption in
 * both, and a band that goes near-black in dark mode reads as more furniture.
 * White clears 7.8:1 on --steel-deep and the lime action 6.4:1, so the contrast
 * holds without a second palette.
 *
 * The whole band is the link, which is why the action is a <span>: a link inside
 * a link is invalid, and the pill is the affordance, not a second destination.
 *
 * The space is reserved twice on purpose, and each way covers the other's
 * failure. :has() sets a nominal height from the stylesheet, so the layout is
 * right with the script blocked; js/site.js measures the bar and writes the real
 * height to the root, which is also what catches a message wrapping to two lines
 * on a narrow phone. A browser would have to be missing both to see the bar and
 * the nav in the same place. */
:root:has(.cta){--cta-h:46px}
.cta{position:fixed;top:0;left:0;right:0;z-index:60;
  display:flex;align-items:center;min-height:var(--cta-h,46px);
  background:var(--steel-deep);color:#FFF;text-decoration:none}
.cta__in{display:flex;align-items:center;justify-content:center;gap:.5rem .9rem;
  padding:.42rem 0}
/* the date or the season, when the message needs one — the same mono eyebrow
   the page uses for .k, taken to sky so it sits back from the message */
.cta__k{flex:none;font-family:var(--m);font-size:.64rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--sky)}
/* one line, always. The ellipsis is a guard rail, not a plan: write the message
   short enough that it never has to work. */
.cta__t{font-size:.86rem;font-weight:600;letter-spacing:-.012em;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cta__go{flex:none;display:inline-flex;align-items:center;gap:.32rem;
  padding:.3rem .85rem;border-radius:var(--r-pill);
  background:var(--lime);color:#16171B;font-size:.76rem;font-weight:700;
  transition:background .28s var(--ease)}
.cta__go::after{content:"→";display:inline-block;transition:transform .28s var(--ease)}
.cta:hover .cta__go{background:var(--lime-deep)}
.cta:hover .cta__go::after{transform:translateX(3px)}
/* the page's focus ring is drawn in --brand, which is a steel on a steel ground */
.cta:focus-visible{outline-color:var(--sky);outline-offset:-4px}

/* ---- 4. PILLS ---------------------------------------------- */
.pill{display:inline-flex;align-items:center;font-weight:600;font-size:.86rem;
  text-decoration:none;padding:.6rem 1.15rem;border-radius:var(--r-pill);cursor:pointer;
  background:var(--pill-bg);color:var(--pill-tx);border:1px solid var(--pill-bg);
  font-family:var(--f);
  transition:background-color .2s ease,border-color .2s ease,transform .25s var(--ease)}
.pill:hover{background:var(--pill-bg-hover);border-color:var(--pill-bg-hover);
  transform:translateY(-1px)}
.pill:active{transform:translateY(0);transition-duration:.06s}
.pill--lime{background:var(--lime);border-color:var(--lime);color:#16171B}
.pill--lime:hover{background:var(--lime-deep);border-color:var(--lime-deep)}
.pill--o{background:transparent;color:var(--tx);border-color:var(--hair)}
.pill--o:hover{background:var(--press);border-color:var(--hair)}
/* kids sub-brand action — same shape and weight as --lime, different water.
   Use it wherever the destination is Kids (pre-registration, the kids page,
   a kids event), on any page. One per view, like lime. */
.pill--kids{background:var(--k-splash);border-color:var(--k-splash);color:#16171B}
.pill--kids:hover{background:var(--k-splash-deep);border-color:var(--k-splash-deep)}

/* Give is a standing invitation, not the action of any one page, and it is in
   the chrome on every page — which is exactly what the single lime action is
   not. Lime is spent on the thing this view is asking for: plan a visit,
   pre-register, find a group. Giving gets the brand's other fill instead, so a
   page can hold both without the two competing. Ink on --sky is 11.4:1, and like
   --lime it is a primitive rather than a semantic token, so the pill is the same
   colour in both themes; --steel takes the hover a step down at 5.6:1. */
.pill--give{background:var(--sky);border-color:var(--sky);color:#16171B}
.pill--give:hover{background:var(--steel);border-color:var(--steel)}

/* ---- 5. STAGE — hero -------------------------------------- */
.stage{padding:clamp(5rem,13vw,10rem) 0 clamp(3rem,7vw,5rem);text-align:center}
/* floor is set by "Three Creeks" — the name is non-breaking, so the smallest
   screens must still fit it on one line with margin to spare */
.stage h1{font-size:clamp(2.6rem,9vw,7.4rem);max-width:14ch;margin:0 auto .9rem}
.stage h1 span{color:var(--brand)}
.stage .l{font-size:clamp(1.05rem,1.9vw,1.4rem);color:var(--tx-dim);max-width:44ch;margin:0 auto 2.2rem}
.stage__acts{display:flex;gap:.7rem;justify-content:center;flex-wrap:wrap}
/* subpage variant: shorter, still confident */
.stage--sub{padding:clamp(3.5rem,9vw,6.5rem) 0 clamp(2.5rem,5vw,4rem)}
.stage--sub h1{font-size:clamp(2.6rem,7vw,5.4rem)}

/* media frame */
.frame{position:relative;border-radius:var(--r-frame);overflow:hidden;background:var(--surface);
  margin-top:clamp(2.5rem,5vw,4rem)}
.frame img{width:100%;height:clamp(320px,58vh,620px);object-fit:cover}
.frame--short img{height:clamp(240px,42vh,460px)}
/* for photos whose subject won't survive a letterbox crop: full column width,
   height derived from the source's own 3:2 rather than a fixed crop */
.frame--3x2 img{height:auto;aspect-ratio:3/2}
/* inline evidence beside body copy, not a hero */
.frame--inline img{height:clamp(200px,26vw,300px)}
/* A caption laid into the foot of a frame: a line of record, not a headline.
   For the few photographs that carry a fact the page would otherwise have to
   stop and explain — a date, the people in it, the room it happened in.
   It is set on a scrim drawn out of the picture's own bottom edge rather than a
   panel: the photograph keeps its full bleed, and white still clears AA over
   whatever is underneath, which a plain overlay of text cannot promise. Nothing
   in it is interactive, so it takes no pointer events. */
/* left, always: a .stage centres its column, and a caption that follows it reads
   as a second subtitle instead of a note on the picture */
.frame__cap{position:absolute;left:0;right:0;bottom:0;z-index:2;pointer-events:none;text-align:left;
  padding:clamp(1.4rem,3vw,2.4rem) clamp(1.2rem,3vw,2.2rem) clamp(1.1rem,2.2vw,1.7rem);
  color:#FFF;
  background:linear-gradient(to top,rgba(11,12,14,.84),rgba(11,12,14,.52) 46%,transparent)}
.frame__cap b{display:block;margin-bottom:.4rem;font-family:var(--m);font-weight:500;
  font-size:.62rem;letter-spacing:.14em;text-transform:uppercase;color:var(--sky)}
.frame__cap p{margin:0;max-width:52ch;font-size:clamp(.92rem,1.4vw,1.05rem);
  font-weight:600;letter-spacing:-.015em;line-height:1.4}

/* three-up photo strip; pairs with .trio */
.frame--thumb img{height:clamp(180px,20vw,240px)}
/* rotating hero: one frame, a stack of photographs, a slow dissolve. There are
   no dots and no arrows because there is nothing to steer — it is weather, not
   navigation, and a control would invite work the picture doesn't need. The
   first photograph stays in flow so it still sets the frame's height from the
   rule above; the rest lie over it. The incoming one fades up over the outgoing
   one, which holds its ground until the fade is done: two symmetric fades would
   both pass through half opacity at the midpoint and let the frame's ground
   show between them. js/site.js carries the same 1.6s and stacks the z-index. */
.frame--gal img{opacity:0}
/* the first one stays in flow and keeps the height set above — the others take
   theirs from the box it opens, so the crop stays identical across the stack */
.frame--gal img:first-child{position:relative}
.frame--gal img+img{position:absolute;inset:0;height:100%}
.frame--gal img.is-on{opacity:1}
@media (prefers-reduced-motion:no-preference){
  .frame--gal img{transition:opacity 1.6s var(--ease)}
  /* Ken Burns, kept honest: a 4.5% drift over eleven seconds, which is slower
     than the eye tracks and longer than any one photograph is on top — so the
     movement is never seen to start or stop, only to be underway. It runs on
     whichever photograph is showing and restarts with each one, since the class
     is re-added on every turn. */
  .frame--gal.is-live img.is-on{animation:gal-drift 11s linear forwards}
  .frame--gal.is-held img.is-on{animation-play-state:paused}
}
@keyframes gal-drift{from{transform:scale(1)}to{transform:scale(1.045)}}

/* The clock, bottom right: a ring that fills across the hold and empties as the
   picture turns over. It is the only chrome in the frame and it is a read-out,
   not a control — there is nothing to press and no dots to count, so it can stay
   this small. It appears only once the rotation is actually running, which keeps
   it off a hero that is showing one still photograph. js/site.js runs the ring
   and the rotation off a single animation, so they cannot drift apart. */
.gal__tick{position:absolute;z-index:5;
  right:clamp(14px,1.6vw,20px);bottom:clamp(14px,1.6vw,20px);
  opacity:0;transition:opacity 1s var(--ease) .5s;
  filter:drop-shadow(0 1px 3px rgba(0,0,0,.45))}
.frame--gal.is-live .gal__tick{opacity:1}
.gal__tick circle{fill:none;stroke:#FFF;stroke-width:2.25}
.gal__trk{opacity:.3}
/* the arc starts at twelve o'clock and is drawn clockwise by js/site.js */
.gal__arc{opacity:.9;stroke-linecap:round;transform:rotate(-90deg);transform-origin:50% 50%}

/* ---- 6. SPLIT + STICKY RAIL -------------------------------- */
.split{display:grid;grid-template-columns:minmax(0,1fr) 380px;
  gap:clamp(2rem,5vw,5rem);align-items:start;padding:clamp(3rem,7vw,6rem) 0}
.rail{position:sticky;top:calc(var(--nav-h) + var(--cta-h,0px) + 12px)}
.rail__card{background:var(--card);border-radius:var(--r-card);padding:1.7rem 1.8rem;
  box-shadow:var(--shadow-card);border:.5px solid var(--hair-soft)}
.rail__k{font-family:var(--m);font-size:.65rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--brand);margin:0 0 .5rem}
.rail__t{font-size:2rem;font-weight:800;letter-spacing:-.045em;line-height:1;margin-bottom:.9rem}
.rail address{font-style:normal;font-size:.88rem;line-height:1.65;color:var(--tx-dim);margin-bottom:1.3rem}
.rail hr{border:none;border-top:.5px solid var(--hair);margin:1.2rem 0}
.rail__note{font-size:.82rem;color:var(--tx-dim);margin:0}

/* ---- 7. CONTENT BLOCKS ------------------------------------- */
.blk{padding-bottom:clamp(3rem,6vw,5rem);border-bottom:.5px solid var(--hair);
  margin-bottom:clamp(3rem,6vw,5rem)}
.blk:last-child{border-bottom:none;margin-bottom:0;padding-bottom:0}
.blk h2{font-size:clamp(1.9rem,4vw,3.2rem);margin-bottom:1.1rem;max-width:18ch}
/* not scoped to .blk — a full-width .sect opens with one too, and the reveal
   list already expects `section>.lede` */
.lede{font-size:1.1rem;color:var(--tx-dim);max-width:52ch}
/* Direct children only. As a descendant selector this reached every h3 nested
   inside the block — .ev rows, .doct entries, .point cards — and :first-of-type
   made it specific enough (0,2,1) to beat those components' own margins, so
   each of them wore an 1.8rem top margin it never asked for. A block styles its
   own subheads; a component inside it styles its own. */
.blk>h3{font-size:1.25rem;letter-spacing:-.025em;margin:2rem 0 .5rem}
.blk>h3:first-of-type{margin-top:1.8rem}
.blk .body{max-width:58ch;color:var(--tx-dim);font-size:.98rem}

/* section on its own page width */
.sect{padding:clamp(3rem,7vw,6rem) 0}
.sect--tight{padding:clamp(2rem,4vw,3rem) 0}
/* A full-width section that opens the way a .blk does — eyebrow, heading, lede —
   for collections that are too wide to live in the .split column. Direct
   children only, so the entrance reveals (which key off section>h2 and
   section>.lede) still see them. */
.sect--intro>h2{font-size:clamp(1.9rem,4vw,3.2rem);margin-bottom:1.1rem;max-width:24ch}
.sect--intro>.lede{font-size:1.1rem;color:var(--tx-dim);max-width:52ch;margin:0}

/* ---- 8. EVENT / FEED ROW ----------------------------------- */
.ev{display:grid;grid-template-columns:6.5rem 1fr auto;gap:.3rem 1.6rem;align-items:baseline;
  padding:1.1rem 0;border-top:.5px solid var(--hair)}
.ev:first-of-type{border-top:none}
.ev .d{font-family:var(--m);font-size:.76rem;color:var(--brand)}
.ev h3{font-size:1.06rem;font-weight:700;letter-spacing:-.02em;margin:0 0 .2rem}
.ev p{font-size:.92rem;color:var(--tx-dim);margin:0}
.ev>a{font-size:.85rem;font-weight:600;text-decoration:none;color:var(--brand);white-space:nowrap}
.ev>a:hover{text-decoration:underline;text-underline-offset:3px}
.ev>a::after,.msg>a::after{content:"→";display:inline-block;margin-left:.3em;
  transition:transform .28s var(--ease)}
.ev>a:hover::after,.msg>a:hover::after{transform:translateX(3px)}
.ev--now .d{color:var(--tx);font-weight:500}
.ev--now h3::after{content:"This week";font-family:var(--m);font-size:.58rem;letter-spacing:.12em;
  text-transform:uppercase;background:var(--lime);color:#16171B;padding:.16rem .45rem;
  border-radius:var(--r-chip);margin-left:.6rem;vertical-align:middle;font-weight:400}

/* Q&A: the same row with its marker column removed. A feed's left column
   carries a date — the one fact a question has no equivalent of, and a column
   of identical Qs is a label repeated four times where the question mark has
   already said it. The hairlines still separate one from the next, so nothing
   is lost by letting the question start at the margin. */
.ev--qa{grid-template-columns:1fr auto}
.ev--qa h3{margin-bottom:.3rem}
.ev--qa p{max-width:64ch}

/* month header inside a long feed */
.mo{font-family:var(--m);font-size:.66rem;letter-spacing:.16em;text-transform:uppercase;
  color:var(--tx-dim);margin:2.6rem 0 .4rem;padding-bottom:.5rem;border-bottom:.5px solid var(--hair)}
.mo:first-of-type{margin-top:1.6rem}

/* ---- 9. STATEMENT PANEL ------------------------------------ */
.stmt{background:var(--stmt-bg);color:var(--stmt-tx);padding:clamp(5rem,12vw,9rem) 0;
  text-align:center;margin:clamp(3rem,7vw,6rem) 0}
.stmt h2{font-size:clamp(2.2rem,6.4vw,5rem);max-width:15ch;margin:0 auto}
.stmt h2 span{color:var(--stmt-accent)}
.stmt .k{color:var(--steel)}
.stmt .l{font-size:1.05rem;color:var(--steel);max-width:52ch;margin:1.4rem auto 0}

/* ---- 10. TILES --------------------------------------------- */
.duo{display:grid;grid-template-columns:1fr 1fr;gap:clamp(1rem,2vw,1.4rem)}
.trio{display:grid;grid-template-columns:1fr 1fr 1fr;gap:clamp(1rem,2vw,1.4rem)}
.tile{border-radius:var(--r-tile);overflow:hidden;background:var(--surface);
  display:flex;flex-direction:column}
/* slow push-in reveals more of the photograph rather than just enlarging the card */
.tile img{width:100%;height:230px;object-fit:cover;transition:transform .9s var(--ease)}
.tile:hover img{transform:scale(1.04)}
.tile__b{padding:1.6rem 1.7rem;display:flex;flex-direction:column;flex:1}
.tile h3{font-size:1.5rem;margin:0 0 .3rem}
.tile address,.tile .sub{font-style:normal;font-family:var(--m);font-size:.76rem;
  color:var(--brand);margin:0 0 .8rem}
.tile p{font-size:.94rem;color:var(--tx-dim);margin-bottom:1.4rem}
.tile .pill{align-self:flex-start;margin-top:auto}
.tile--link{text-decoration:none;transition:background .2s}
.tile--link:hover{background:var(--press)}

/* ---- 10b. POINT — thumbnail + one labelled point ------------
   The compact sibling of .tile. Use it where a block makes two or three
   separate promises and each one deserves its own picture: two points carry a
   section better than a single oversized .frame carrying none of it.
   The photograph is inset and keeps its natural 4:3 rather than bleeding to
   the card edge — at this size a tall crop throws away the sides of the frame,
   and in our photography the sides of the frame are where the people are.
   Sized to sit inside the .split column; it is not a full-width component. */
.points{display:grid;gap:.8rem;margin-top:2rem}
.point{display:grid;grid-template-columns:clamp(150px,30%,210px) minmax(0,1fr);
  gap:clamp(1rem,2vw,1.4rem);align-items:center;background:var(--card);
  border:.5px solid var(--hair-soft);border-radius:var(--r-card);
  padding:clamp(.9rem,1.4vw,1.1rem)}
/* height:auto is load-bearing — the intrinsic height attribute on the markup
   would otherwise win and aspect-ratio would never get a say */
.point__ph{width:100%;height:auto;aspect-ratio:4/3;object-fit:cover;border-radius:14px;
  background:var(--surface)}
.point__b{display:flex;flex-direction:column;align-items:flex-start;padding-right:.4rem}
/* two label styles, one slot: __k when the point is an aside under a heading
   that already names it, __t when the point is itself a step in a walkthrough
   and needs to stay a real h3 in the outline */
.point__k{font-family:var(--m);font-size:.66rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--brand);margin:0 0 .45rem}
.point__t{font-size:1.06rem;font-weight:700;letter-spacing:-.02em;line-height:1.3;
  margin:0 0 .35rem}
/* classed, not a bare `p`, so the eyebrow above it never has to out-specify it */
.point__p{font-size:.92rem;color:var(--tx-dim);margin:0 0 1.1rem;max-width:46ch}
.point .pill{font-size:.8rem;padding:.5rem .95rem;margin-top:auto}

/* ---- 10c. WORK — one ministry, one card ---------------------
   The wide end of the media scale, and the only card that changes sides: a
   ministry gets its own picture (or its partner's mark), its name, what it
   actually does, and — where the numbers are worth printing — a .ledger.
   Cards alternate down the list automatically, so four of them read as one
   column with a rhythm rather than four identical rows.
   Sized for the full page width, not the .split column. Use it when each item
   is a programme that stands on its own: .point is evidence inside someone
   else's argument, .tile is a door, .work is the thing itself.
   ------------------------------------------------------------ */
.works{display:grid;gap:clamp(.9rem,1.8vw,1.4rem);margin-top:clamp(2rem,4vw,3rem)}
.work{display:grid;grid-template-columns:minmax(0,.92fr) minmax(0,1fr);
  gap:clamp(1.2rem,3vw,3rem);align-items:center;background:var(--card);
  border:.5px solid var(--hair-soft);border-radius:var(--r-card);
  padding:clamp(.9rem,1.4vw,1.2rem)}
/* Visual order only. The media stays first in the source, so a screen reader
   meets every card the same way round — picture, then what it is a picture of. */
.work:nth-of-type(even) .work__m{order:2}
.work__b{padding:clamp(.3rem,1.2vw,1rem) clamp(.3rem,1.2vw,.9rem)}
/* height:auto is load-bearing here for the same reason as .point__ph — the
   intrinsic height attribute would otherwise beat aspect-ratio */
.work__ph{width:100%;height:auto;aspect-ratio:4/3;object-fit:cover;border-radius:16px;
  background:var(--surface)}
/* A partner's own artwork instead of a photograph. These arrive as finished
   rectangles — a mark on its own plate, an illustrated scene — so the box takes
   the artwork's aspect ratio rather than imposing the photographs' 4:3: cropping
   to fit would cut the ends off someone else's wordmark, and neither the crop
   nor the colour is ours to change. Card heights vary as a result, which is the
   right trade. */
.work__art{border-radius:16px;overflow:hidden;background:#FFF;
  border:.5px solid var(--hair-soft)}
.work__art img{width:100%;height:auto}
.work__k{font-family:var(--m);font-size:.66rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--brand);margin:0 0 .55rem}
.work__t{font-size:clamp(1.45rem,2.6vw,2.05rem);margin:0 0 .7rem;max-width:19ch}
.work__p{font-size:.97rem;color:var(--tx-dim);margin:0 0 1.2rem;max-width:48ch}
.work__tags{display:flex;flex-wrap:wrap;gap:.35rem;margin:0 0 1.2rem}
.work .ledger{margin:0 0 .9rem}
.work .pill{align-self:start}
.work>:last-child>:last-child{margin-bottom:0}
/* Closing card: the list's own invitation, in the same rhythm as the ministries
   above it. Recessed rather than raised — it is the page talking, not another
   programme. */
.work--act{grid-template-columns:minmax(0,1fr) auto;background:var(--surface);
  border-color:var(--hair);padding:clamp(1.3rem,2.6vw,2rem)}
.work--act .work__b{padding:0}
.work--act .work__t{font-size:clamp(1.3rem,2.2vw,1.7rem);max-width:24ch}
.work--act .work__p{margin-bottom:0}
.work--act>.pill{align-self:center;justify-self:end}

/* ---- 11. ROOMS (kids classrooms) --------------------------- */
.rooms{list-style:none;margin:1.4rem 0 0;padding:0;display:grid;
  grid-template-columns:repeat(3,1fr);gap:.6rem}
.rooms li{background:var(--card);border:.5px solid var(--hair);border-radius:14px;padding:.85rem 1rem}
.rooms b{display:block;font-weight:700;font-size:1rem;letter-spacing:-.02em}
.rooms span{font-family:var(--m);font-size:.66rem;text-transform:uppercase;letter-spacing:.08em;color:var(--tx-dim)}

/* ---- 11b. KIDS BLOCK, ON A PARENT PAGE --------------------- *
 * The third exception in this file, and it is here for the same reason as
 * .pill--kids and .chip--kids: a parent page has to be able to speak for Kids
 * without loading the whole ocean to do it. css/kids.css is a page-level token
 * overlay; this is one block, on a page that is not a kids page, and it carries
 * exactly as much of the sub-brand as that is worth — the mark, the water, the
 * creature names, one action.
 *
 * It goes deep rather than mint. --k-mint is the sub-brand's signature, but it
 * is a fill and never a text ground, and a pale slab would have to be re-thought
 * for dark mode anyway. Deep water holds in both themes for the same reason
 * .stmt does, and it is the ground the mark was drawn for: white on --k-ground
 * is 13:1, the splash accent 8:1, so nothing here needs a second palette.
 *
 * The light on the water is a radial, not an asset — the bubbles and the wave
 * belong to the kids pages, and one borrowed gradient is the right amount of
 * ocean for a page that is mostly about something else.
 * ------------------------------------------------------------ */
.kcta{position:relative;isolation:isolate;overflow:hidden;
  margin-bottom:clamp(3rem,6vw,5rem);padding:clamp(1.8rem,3.4vw,2.8rem);
  border-radius:var(--r-card);background:var(--k-ground);color:#FFF}
.kcta:last-child{margin-bottom:0}
.kcta::before{content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:radial-gradient(120% 78% at 20% -34%,rgba(76,212,207,.34),transparent 62%)}
/* The lockup sits across from the words rather than above them: it is the
   signature on this block, and a signature goes in the corner. A flex row and
   not an absolute corner, so a heading that wraps on a narrow panel pushes the
   mark rather than running under it — and so the same row can simply stack at
   the tablet step (§23), where a corner mark and a two-line heading start
   fighting over the same third of the panel. */
.kcta__hd{display:flex;align-items:flex-start;justify-content:space-between;
  gap:clamp(1rem,3vw,2.4rem)}
/* the mark is an alpha mask like every other lockup on the site, so it takes
   currentColor and needs no light or dark variant */
.kcta__mark{flex:none;display:block;width:clamp(88px,10vw,118px);aspect-ratio:600/578;
  margin:.15rem 0 0;background:currentColor;
  -webkit-mask:url("../assets/kids/kids-logo.png") no-repeat right top/contain;
  mask:url("../assets/kids/kids-logo.png") no-repeat right top/contain}
.kcta .k{color:var(--k-splash);margin-bottom:.9rem}
.kcta h2{font-size:clamp(1.9rem,4vw,3.2rem);max-width:18ch;margin-bottom:1.1rem}
.kcta .lede{color:rgba(255,255,255,.82);max-width:52ch}
/* The roster in deep water: the card is a lift out of the ground rather than a
   surface of its own, which is what keeps six of them from reading as a grid of
   buttons. Held here on purpose — the list is commented out in the markup, not
   deleted, so the block can carry the six rooms again without this being
   re-derived. */
.kcta .rooms li{background:rgba(255,255,255,.07);border-color:rgba(255,255,255,.17)}
.kcta .rooms b{color:#FFF}
.kcta .rooms span{color:var(--k-splash)}
/* the bubble field, at a volume the home page can carry. Same shapes, the same
   mask-on-currentColor and the same per-bubble properties as §6b of css/kids.css,
   so the two fields are one idea and not two implementations — this one just runs
   quieter: four shapes instead of ten, eight bubbles instead of twenty, a third of
   the opacity, and about twice as long to cross. On a page that is mostly about
   something else, the water should be noticed second, if at all.
   --x across, --s size, --o opacity, --d rise time, --sd/--sx the sway, --r a
   resting tilt, --p where in the trip it starts. Authored in the markup rather
   than random, so the field is the same on every load and can be judged. */
.kcta__bub{position:absolute;inset:0;z-index:-1;pointer-events:none;overflow:hidden}
.kcta__bub i{
  --bu:clamp(.62px,.5px + .036vw,1.05px);
  --bw:calc(var(--w) * var(--s) * var(--bu));
  --bh:calc(var(--h) * var(--s) * var(--bu));
  position:absolute;left:var(--x);margin-left:calc(var(--bw) / -2);
  bottom:calc(var(--bh) * -1);width:var(--bw);height:calc(100% + var(--bh));
  display:flex;align-items:flex-end;opacity:var(--o);
  transform:translateY(calc(var(--p) * -100%))}
.kcta__bub i::after{content:"";display:block;width:100%;height:var(--bh);
  background:currentColor;transform:rotate(var(--r));
  -webkit-mask:var(--b) no-repeat center/contain;
          mask:var(--b) no-repeat center/contain}
.kcta__bub .b2 {--w:64;--h:56;--b:url("../assets/kids/bubbles/b2.svg")}
.kcta__bub .b5 {--w:51;--h:47;--b:url("../assets/kids/bubbles/b5.svg")}
.kcta__bub .b9 {--w:37;--h:37;--b:url("../assets/kids/bubbles/b9.svg")}
.kcta__bub .b10{--w:33;--h:33;--b:url("../assets/kids/bubbles/b10.svg")}

.kcta .pill--o{border-color:rgba(255,255,255,.34);color:#FFF}
.kcta .pill--o:hover{background:rgba(255,255,255,.1);border-color:rgba(255,255,255,.5)}
.kcta :where(a,button):focus-visible{outline-color:var(--k-splash)}

@media (prefers-reduced-motion:no-preference){
  /* linear, because a bubble does not accelerate and easing at the ends would
     read as the loop restarting. Both delays are negative and scaled by --p, so
     the field is already mid-drift on the first frame instead of starting as a
     row along the bottom edge; the sway runs against a different multiple of --p
     so the two never fall into step. Only the top of the trip fades — the bottom
     edge of the panel does that job at the other end. With motion off, --p is
     simply where each bubble parks, and the field is still a field. */
  @keyframes kcta-rise{
    0%  {transform:translateY(0);     opacity:var(--o)}
    86% {                             opacity:var(--o)}
    100%{transform:translateY(-100%); opacity:0}
  }
  @keyframes kcta-sway{
    from{transform:translateX(calc(var(--sx) * -1)) rotate(calc(var(--r) - 4deg))}
    to  {transform:translateX(var(--sx))            rotate(calc(var(--r) + 4deg))}
  }
  .kcta__bub i{
    animation:kcta-rise var(--d) linear calc(var(--p) * var(--d) * -1) infinite}
  .kcta__bub i::after{
    animation:kcta-sway var(--sd) ease-in-out calc(var(--p) * var(--sd) * -3)
              infinite alternate}
}

/* ---- 12. VALUES — typographic ledger, not icon cards ------- */
.vals{list-style:none;margin:1.8rem 0 0;padding:0}
.vals li{display:grid;grid-template-columns:minmax(9rem,14rem) 1fr;gap:1.5rem;align-items:baseline;
  padding:1.5rem 0;border-top:.5px solid var(--hair)}
.vals b{font-size:clamp(1.7rem,3.4vw,2.6rem);font-weight:800;letter-spacing:-.04em;line-height:1}
.vals p{margin:0;color:var(--tx-dim);max-width:46ch}

/* ---- 13. TIMELINE ------------------------------------------ */
.tl{list-style:none;margin:1.6rem 0 0;padding:0}
.tl li{display:grid;grid-template-columns:6.5rem 1fr;gap:1.6rem;align-items:baseline;
  padding:1.1rem 0;border-top:.5px solid var(--hair)}
.tl li:first-child{border-top:none}
.tl .d{font-family:var(--m);font-size:.76rem;color:var(--brand)}
.tl b{display:block;font-size:1.06rem;font-weight:700;letter-spacing:-.02em;margin-bottom:.15rem}
.tl p{font-size:.92rem;color:var(--tx-dim);margin:0}

/* ---- 14. FAMILY TREE (church planting lineage) -------------- *
 * One card per church, read left to right, with the lineage drawn as a rail
 * across the row above them: node, line, node. The rail lives in the li's top
 * padding rather than on the card, so the line can cross the gap between two
 * cards and land dead centre on the next node.
 *
 * The old .lin was a stacked list living inside the .split column, which gave
 * each plant one line of type and no room for its mark. Four churches are the
 * point of that page, so they get the page's full width and a card each.
 * ------------------------------------------------------------ */
.tree{--tg:.8rem;
  list-style:none;margin:2.6rem 0 0;padding:0;
  display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--tg)}
.tree li{position:relative;display:flex;padding-top:2.1rem}
.tree li::before{content:"";position:absolute;left:50%;top:0;z-index:1;
  width:11px;height:11px;margin-left:-5.5px;border-radius:50%;background:var(--brand)}
/* runs from this node to the next one: one card plus one gap */
.tree li::after{content:"";position:absolute;left:50%;top:5px;
  width:calc(100% + var(--tg));height:.5px;background:var(--hair)}
.tree li:last-child::after{display:none}
.tree li.is-us::before{background:var(--lime);
  box-shadow:0 0 0 4px color-mix(in srgb,var(--lime) 25%,transparent)}

.tree__c{flex:1;display:flex;flex-direction:column;background:var(--card);
  border:.5px solid var(--hair);border-radius:var(--r-card);padding:1.3rem 1.4rem 1.4rem}
/* our own card is the one a visitor is looking for — the lime carries over
   from the node so the eye lands in the same place twice */
.tree li.is-us .tree__c{border-color:color-mix(in srgb,var(--lime) 60%,var(--hair))}
/* mark and generation sit on one line: the brand on the left, where it is in
   every other lockup, and the position in the family on the right */
.tree__t{display:flex;align-items:center;justify-content:space-between;
  gap:.8rem;margin-bottom:1.05rem}
.tree__g{font-family:var(--m);font-size:.64rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--tx-dim)}
.tree b{display:block;font-size:1.22rem;font-weight:800;letter-spacing:-.032em;line-height:1.1}
.tree__w{font-family:var(--m);font-size:.72rem;color:var(--brand);margin:.35rem 0 0}
.tree__p{font-size:.9rem;color:var(--tx-dim);margin:.75rem 0 1.1rem}
/* the relationship label — and the link that stands in for it on the other
   cards — is the payoff of the whole list, so it sits on a shared baseline
   across the row. Auto margin absorbs the ragged copy above; flex-start keeps
   the pill its own width instead of stretching to the card as a flex item. */
.tree .chip,.tree .pill{align-self:flex-start;margin-top:auto}

/* church marks — every plant in the family tree is a different brand, so the
   only way they sit together quietly is to strip them all to one silhouette.
   The PNGs are alpha-only masks: they take currentColor and work in both
   themes, exactly like the Three Creeks mark in the nav. */
.cmark{flex:none;width:26px;height:26px;background:currentColor;opacity:.42;
  transition:opacity .25s ease}
.tree .cmark{width:34px;height:34px}
.tree li:hover .cmark{opacity:.7}
.tree li.is-us .cmark{color:var(--brand);opacity:.85}
.cmark--movement{-webkit-mask:url("../img/logos/movement-church.png") no-repeat center/contain;
  mask:url("../img/logos/movement-church.png") no-repeat center/contain}
.cmark--three-creeks{-webkit-mask:url("../img/logos/three-creeks.png") no-repeat center/contain;
  mask:url("../img/logos/three-creeks.png") no-repeat center/contain}
.cmark--contrast{-webkit-mask:url("../img/logos/contrast-church.png") no-repeat center/contain;
  mask:url("../img/logos/contrast-church.png") no-repeat center/contain}
.cmark--bright-city{-webkit-mask:url("../img/logos/bright-city-church.png") no-repeat center/contain;
  mask:url("../img/logos/bright-city-church.png") no-repeat center/contain}
/* line art against three filled marks — it needs the extra weight to read as
   the same size on the page */
.tree li .cmark--bright-city{opacity:.58}
.tree li:hover .cmark--bright-city{opacity:.85}

/* ---- 15. DIRECTORY (leadership) ---------------------------- */
.dir{display:grid;grid-template-columns:repeat(3,1fr);gap:.8rem;margin-top:1.6rem}
/* Everyone in the directory has a bio behind them, so the card itself is the
   button — a small "read more" link inside an otherwise clickable card gives
   one action two targets. */
/* Column flex, not block: roles run one to three lines, and the grid stretches
   every card in a row to the tallest one. Without it the prompt floats at
   whatever height the role happens to end at, so a row of three has them at
   three different heights. */
.person{display:flex;flex-direction:column;align-items:flex-start;
  width:100%;text-align:left;font:inherit;color:inherit;cursor:pointer;
  background:var(--card);border:.5px solid var(--hair);border-radius:14px;
  padding:1.15rem 1.25rem 1.05rem;transition:background .2s}
.person:hover{background:var(--press)}
.person b{display:block;font-weight:700;font-size:1.02rem;letter-spacing:-.02em}
/* block, or the role and the prompt set on one line with nothing between them */
.person span{display:block;font-size:.84rem;color:var(--tx-dim)}
/* margin-top:auto pins it to the bottom of the stretched card; the padding is
   the floor, for the tallest card in the row where auto resolves to nothing */
.person .person__more{margin-top:auto;padding-top:.7rem;
  font-family:var(--m);font-size:.72rem;color:var(--brand)}
.person:hover .person__more{text-decoration:underline;text-underline-offset:3px}
/* Photos are the real thing, not generated avatars: they bleed to the card
   edge and are cropped high, because these are family shots where the faces
   sit above centre. The name is right below, so alt stays empty. */
/* One ratio for the whole grid — the source frames run anywhere from 16:9 to
   square, and a fixed pixel height cropped each of them differently. 16:9 is
   the widest of them, so it is the one crop no photo has to be invented for. */
/* max-width:none is load-bearing — the base img rule would otherwise cap this
   at the card's content box and undo the bleed */
.person__ph{width:calc(100% + 2.5rem);max-width:none;aspect-ratio:16/9;height:auto;
  object-fit:cover;object-position:center 32%;
  margin:-1.15rem -1.25rem 1rem;border-radius:13px 13px 0 0}

/* ---- 15b. MODALS (bio, directions) ------------------------- */
/* Every <dialog> on the site opens with .is-on a frame after showModal(), so
   the closed state has been painted and the transition has something to run
   from — same trick as .m-sheet. Shell, scrim and page lock are shared; the
   two dialogs differ only in width and in what fills them. */
.bio,.dirs{max-height:min(88dvh,46rem);padding:0;
  background:var(--card);color:var(--tx);border:.5px solid var(--hair);
  border-radius:var(--r-card);box-shadow:var(--shadow-card);overflow:auto;
  opacity:0;transform:translateY(14px) scale(.99);
  transition:opacity .28s var(--ease),transform .28s var(--spring)}
.bio.is-on,.dirs.is-on{opacity:1;transform:none}
/* ::backdrop sits outside the cascade in older engines, so the scrim is
   spelled out here rather than taken from --scrim */
.bio::backdrop,.dirs::backdrop{background:rgba(18,20,24,.44);opacity:0;
  transition:opacity .28s var(--ease)}
.bio.is-on::backdrop,.dirs.is-on::backdrop{opacity:1}
.modal-open{overflow:hidden}

.bio{width:min(30rem,calc(100vw - 2rem))}
/* height:auto is load-bearing: the height attribute on the img is a
   presentational hint, and aspect-ratio is ignored while both sides are set */
.bio__ph{display:block;width:100%;aspect-ratio:16/9;height:auto;
  object-fit:cover;object-position:center 32%}
.bio__x{position:absolute;top:.75rem;right:.75rem;z-index:2;
  width:34px;height:34px;display:grid;place-items:center;cursor:pointer;
  border-radius:var(--r-pill);border:.5px solid rgba(255,255,255,.4);
  background:rgba(18,20,24,.5);color:#fff}
.bio__x:hover{background:rgba(18,20,24,.75)}
.bio__b{padding:1.5rem 1.6rem 1.7rem}
.bio__b h2{font-size:1.5rem;letter-spacing:-.025em;margin:0}
.bio__role{font-family:var(--m);font-size:.72rem;letter-spacing:.06em;text-transform:uppercase;
  color:var(--brand);margin:.4rem 0 0}
.bio__p{font-size:.95rem;line-height:1.7;color:var(--tx-dim);margin:1rem 0 1.35rem}

/* ---- 15c. DIRECTIONS DIALOG -------------------------------- */
/* The church has two addresses, so a Directions control that jumped straight
   to a map would be guessing which one you meant. Every one of them opens
   this dialog instead: pick the place, then pick your map app. The controls
   keep a map href underneath, so without JS they still land somewhere sane. */
.dirs{width:min(34rem,calc(100vw - 2rem))}
.dirs__b{padding:1.6rem 1.6rem 1.7rem}
/* the close button sits over this corner */
.dirs__b .k{margin-bottom:.55rem;padding-right:2.6rem}
.dirs__b h2{font-size:1.5rem;letter-spacing:-.025em;margin:0;padding-right:2.6rem}
.dirs__x{position:absolute;top:.9rem;right:.9rem;z-index:2;
  width:34px;height:34px;display:grid;place-items:center;cursor:pointer;
  border-radius:var(--r-pill);border:.5px solid var(--hair);
  background:var(--card);color:var(--tx-dim)}
.dirs__x:hover{background:var(--press);color:var(--tx)}
.dirs__l{list-style:none;margin:1.5rem 0 0;padding:0;display:grid;gap:.7rem}
/* recessed against the card, so each place reads as its own object */
.dirs__l li{display:grid;grid-template-columns:92px 1fr;gap:1rem;
  background:var(--bg);border:.5px solid var(--hair-soft);
  border-radius:16px;padding:.9rem}
.dirs__ph{width:92px;height:100%;min-height:92px;border-radius:12px;object-fit:cover}
.dirs__n{display:block;font-weight:700;font-size:1.02rem;letter-spacing:-.02em}
.dirs__w{font-family:var(--m);font-size:.72rem;color:var(--brand);margin:.15rem 0 .4rem}
.dirs address{font-style:normal;font-size:.88rem;line-height:1.5;color:var(--tx-dim)}
.dirs__go{display:flex;flex-wrap:wrap;gap:.4rem;margin-top:.85rem}
/* on --bg, an outline pill needs the card fill to stay a raised control */
.dirs__go .pill{font-size:.8rem;padding:.45rem .9rem;background:var(--card)}
.dirs__go .pill:hover{background:var(--press)}
/* the photo stays beside the copy rather than stacking on top of it: both
   places, and so both pairs of map buttons, have to fit the dialog without a
   scroll on a phone. It shrinks to a thumbnail and sits at the top of the row,
   level with the name it belongs to. */
@media (max-width:430px){
  .dirs__b{padding:1.35rem 1.15rem 1.4rem}
  .dirs__l li{grid-template-columns:56px 1fr;gap:.7rem;padding:.7rem}
  .dirs__ph{width:56px;height:56px;min-height:0;align-self:start;border-radius:10px}
  /* the two map buttons split the copy column instead of sizing to their own
     labels — a fixed pair of halves keeps them on one line down to the
     narrowest phones, and a card that fits on one line is what keeps both
     places on screen without a scroll */
  .dirs__go{display:grid;grid-template-columns:1fr 1fr;gap:.4rem;margin-top:.7rem}
  .dirs__go .pill{justify-content:center;white-space:nowrap;
    font-size:.74rem;padding:.42rem .4rem}
}

/* ---- 16. GROUP FINDER -------------------------------------- */
.fbar,.tbar{display:flex;flex-wrap:wrap;gap:.45rem;margin:1.6rem 0 1.8rem}
.fbtn{font-family:var(--m);font-size:.72rem;letter-spacing:.06em;text-transform:uppercase;
  padding:.45rem .85rem;border-radius:var(--r-pill);cursor:pointer;
  background:transparent;color:var(--tx-dim);border:.5px solid var(--hair)}
.fbtn:hover{background:var(--press);color:var(--tx)}
.fbtn[aria-selected="true"]:hover{background:var(--tx);color:var(--bg)}
.fbtn[aria-pressed="true"],
/* the same control doing the same job under tab semantics — see .mtabs, §17b */
.fbtn[aria-selected="true"]{background:var(--tx);border-color:var(--tx);color:var(--bg)}
.fbar .sep{width:.5px;background:var(--hair);margin:.2rem .4rem}
.gwrap{display:grid;grid-template-columns:1fr 1fr;gap:.8rem}
.gcard{background:var(--card);border:.5px solid var(--hair);border-radius:16px;
  padding:1.3rem 1.4rem;display:flex;flex-direction:column;gap:.15rem}
.gcard b{font-size:1.1rem;font-weight:700;letter-spacing:-.02em}
.gcard .meta{font-family:var(--m);font-size:.72rem;color:var(--brand);margin:.15rem 0 .4rem}
.gcard p{font-size:.88rem;color:var(--tx-dim);margin:0 0 .9rem}
.gcard .row{display:flex;gap:.4rem;align-items:center;margin-top:auto;flex-wrap:wrap}
.gcard .row a{margin-left:auto;font-size:.85rem;font-weight:600;color:var(--brand);
  text-decoration:none;white-space:nowrap}
.gcard .row a:hover{text-decoration:underline;text-underline-offset:3px}
.gcard.is-full{opacity:.55}
.gempty{padding:2.5rem 0;color:var(--tx-dim);font-size:.95rem;display:none}

/* ---- 17. MESSAGES — featured message + feed ------------------- */
/* A page that leads with content rather than a hero still needs to name
   itself — for a reader landing cold, and for a crawler reading the outline.
   .pghd is that: the eyebrow-and-headline idiom at hero weight minus one,
   sitting above the first section instead of replacing it. */
.pghd{padding:clamp(3rem,7vw,5rem) 0 0}
.pghd h1{font-size:clamp(2.1rem,5vw,3.4rem);max-width:20ch}
.feat{display:grid;grid-template-columns:minmax(0,1.35fr) 1fr;gap:clamp(1.5rem,4vw,3.5rem);
  align-items:center;padding:clamp(2rem,5vw,4rem) 0}
.feat .frame{margin-top:0}
.feat .frame img{height:clamp(260px,38vw,430px)}
/* the title leads and the series follows it: the line someone came for first,
   the shelf it sits on second. The margins are tightened either side of the
   handover so the two read as one block rather than as two starts. */
.feat h2{font-size:clamp(1.9rem,4vw,3rem);margin:.2rem 0 .45rem}
.feat .meta{margin:0 0 1.1rem}
.feat p{color:var(--tx-dim);max-width:46ch}
.msg{display:grid;grid-template-columns:6.5rem 1fr auto;gap:.3rem 1.6rem;align-items:baseline;
  padding:1.05rem 0;border-top:.5px solid var(--hair)}
.msg .d{font-family:var(--m);font-size:.76rem;color:var(--brand)}
.msg b{font-size:1.04rem;font-weight:700;letter-spacing:-.02em}
.msg .who{display:block;font-size:.86rem;color:var(--tx-dim);margin-top:.15rem}
.msg>a{font-size:.85rem;font-weight:600;text-decoration:none;color:var(--brand);white-space:nowrap}
.msg>a:hover{text-decoration:underline;text-underline-offset:3px}

/* ---- 17b. MESSAGE SINGLE + SERIES --------------------------- */
/* The two templates behind the archive: one message, and one series. Both are
   built out of §17's own pieces — .pghd for the head, .feat for the series
   hero, .msg rows for the list — so what is new here is only the four things a
   single record needs and a collection does not: the video well, the record
   itself, the passage it is about, and the way out to the next one. */

/* A trail, not a label. The eyebrow over a single record names the shelf it came
   off (Messages / Honest to God), and a shelf is only useful if it is clickable.
   The link keeps the eyebrow's own colour and buys its affordance from the
   underline on hover — a second colour inside a coloured label would put two
   accents on one line and neither would lead. Scoped to .pghd, which is where a
   page head lives: an eyebrow anywhere else is a label and a link inside it is
   prose, and prose keeps its underline. */
.pghd .k a{color:inherit;text-decoration:none}
.pghd .k a:hover{text-decoration:underline;text-underline-offset:3px}
.pghd .k i{font-style:normal;opacity:.45;margin:0 .4rem}

/* The record line under a heading: series, passage, speaker, date. It was
   written inside .feat and is promoted here, because a message single needs
   exactly the same line under an h1 that the featured message has under its h2.
   .feat keeps only the margins, which are its own — but it has to keep its
   selector in this rule too: `.feat p` sets the body colour of everything else
   in that column at (0,1,1), which a bare `.meta` at (0,1,0) would lose to. */
.meta,.feat .meta{font-family:var(--m);font-size:.76rem;color:var(--brand)}
/* under a .pghd headline it needs the air an h1 does not carry itself: h1's
   line-height is 1.02, so a following line sits on the descenders. */
.pghd .meta{margin:.85rem 0 0}

/* THE MESSAGE ITSELF.
   A 16:9 well that holds a still until someone asks for the video. YouTube's
   embed pulls about half a megabyte and its cookies on load, before anyone has
   decided to watch, so what ships in the markup is a photograph and a link to
   the video, and js/site.js swaps the iframe in on the press. The control is a
   real link either way — with no JavaScript the press goes to YouTube and the
   message still plays — so the well never dead-ends on a dead button.
   Radius and ground are .frame's: to the page this is the same object, a
   picture the width of the column. */
.player{position:relative;aspect-ratio:16/9;border-radius:var(--r-frame);overflow:hidden;
  background:#0B0C0E}
.player img,.player iframe{position:absolute;inset:0;width:100%;height:100%;border:0;display:block}
.player img{object-fit:cover}
/* the whole well is the control. 648px of picture is already the target, and
   asking for a circle inside it is a needless act of aim; the circle is there
   to say so, not to be hit. The wash is what keeps a white play mark legible
   over a bright frame of a stage, and it deepens rather than appears on hover
   so nothing flashes under the pointer. */
.player__go{position:absolute;inset:0;width:100%;height:100%;display:grid;place-items:center;
  border:0;padding:0;cursor:pointer;color:#FFF;text-decoration:none;
  background:linear-gradient(to top,rgba(11,12,14,.5),rgba(11,12,14,.1) 55%,rgba(11,12,14,.28));
  transition:background .3s var(--ease)}
.player__go:hover{background:linear-gradient(to top,rgba(11,12,14,.62),rgba(11,12,14,.2) 55%,rgba(11,12,14,.38))}
.player__go i{display:grid;place-items:center;width:clamp(60px,6.5vw,84px);aspect-ratio:1;
  border-radius:50%;background:rgba(251,251,252,.94);color:#16171B;
  transition:transform .35s var(--spring),background .2s ease}
.player__go:hover i{transform:scale(1.05);background:#FFF}
/* a triangle's mass sits left of its bounding box; the nudge puts its weight
   on the circle's centre instead of its geometry */
.player__go svg{margin-left:.1em}
/* the brand outline is a steel on a near-black ground — inside the well the
   ring has to be the light one, and inset so it is not clipped by the radius */
.player__go:focus-visible{outline:2px solid #FFF;outline-offset:-6px}
/* the one fact worth carrying on the picture */
.player__len{position:absolute;right:.85rem;bottom:.85rem;z-index:2;pointer-events:none;
  font-family:var(--m);font-size:.68rem;letter-spacing:.06em;color:#FFF;
  background:rgba(11,12,14,.62);padding:.2rem .48rem;border-radius:var(--r-chip)}
.player__note{font-size:.82rem;color:var(--tx-dim);margin:.85rem 0 0}

/* WATCH OR LISTEN.
   One record, two ways in. The control is the .fbtn from the archive's filter
   bar, because it is the same job — a small set of exclusive states, each named
   in full — but these are tabs and not filters, so they carry role="tab" and
   aria-selected, and §16's rule was widened to answer to both spellings.

   The listening panel is the same 16:9 box as the video, not a bar the height of
   its own controls. Two reasons, and the first is enough: swapping 648px of
   video for 90px of scrubber moves every word on the page under the reader's
   cursor. The second is that a photograph is better company for forty minutes
   than a strip of grey — so the still stays, and the controls sit on a scrim
   drawn out of its bottom edge, the way .frame__cap does. */
.mtabs{display:flex;gap:.45rem;margin:0 0 .9rem}

.aud{position:relative;aspect-ratio:16/9;border-radius:var(--r-frame);overflow:hidden;
  background:#0B0C0E;display:flex;align-items:flex-end}
/* the display:flex above outranks the UA's [hidden]{display:none}, same as the
   mobile sheet in §21 — the panel that is not showing has to be told twice */
.aud[hidden]{display:none}
/* held back off the near-black ground rather than shown at full strength: it is
   atmosphere for forty minutes of listening, not the thing being watched, and
   the dimming is also what lets white controls clear AA over a blown-out frame
   of a lit stage — the scrim alone cannot promise that on every photograph */
.aud>img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:.7}
/* No JavaScript, no custom bar. The element keeps the `controls` attribute it
   ships with and is laid over the foot of the still — plain, but playing. Once
   js/site.js takes the attribute off, the UA's own audio:not([controls]) rule
   removes the element from the layout and the bar below is the only player.
   .js is set pre-paint in every page head, so neither state ever flashes. */
.aud>audio{position:relative;z-index:2;width:calc(100% - 1.8rem);margin:0 .9rem .9rem}
html:not(.js) .aud__c{display:none}
.aud__c{position:relative;z-index:2;width:100%;display:grid;
  grid-template-columns:auto auto minmax(0,1fr) auto;align-items:center;
  gap:clamp(.6rem,1.6vw,1rem);color:#FFF;
  padding:clamp(2.2rem,6vw,4rem) clamp(.9rem,2.2vw,1.5rem) clamp(.9rem,1.8vw,1.3rem);
  background:linear-gradient(to top,rgba(11,12,14,.9),rgba(11,12,14,.8) 45%,
    rgba(11,12,14,.3) 80%,transparent)}

/* the same white circle as the video well, one size down: it is the same
   promise — press here and it starts — and it should not read as a different
   control because the medium changed */
.aud__go{display:grid;place-items:center;width:clamp(46px,4.6vw,56px);aspect-ratio:1;
  border:0;padding:0;border-radius:50%;background:rgba(251,251,252,.94);color:#16171B;
  cursor:pointer;transition:transform .35s var(--spring),background .2s ease}
.aud__go:hover{transform:scale(1.05);background:#FFF}
/* a triangle's mass sits left of its box; two bars are symmetric and want none */
.aud__go svg{margin-left:.08em}
.aud[data-on] .aud__go svg{margin-left:0}

.aud__b{position:relative;display:grid;grid-auto-flow:column;place-items:center;gap:.22rem;
  height:38px;min-width:38px;padding:0 .55rem;
  border:0;border-radius:var(--r-pill);background:rgba(255,255,255,.2);color:#FFF;cursor:pointer;
  font-family:var(--m);font-size:.68rem;letter-spacing:.02em;
  transition:background .2s ease}
.aud__b:hover{background:rgba(255,255,255,.3)}
/* 38px keeps the controls off the photograph; the hit area is the 44 it owes */
.aud__b::after{content:"";position:absolute;inset:-3px -4px}
.aud__rate{padding:0 .55rem}

.aud__bar{display:grid;gap:.4rem;min-width:0}
/* --p is the played fraction, written by js/site.js — one custom property doing
   the work a second stacked element would otherwise do */
.aud__rng{-webkit-appearance:none;appearance:none;width:100%;height:4px;padding:0;border:0;
  border-radius:var(--r-pill);cursor:pointer;
  background:linear-gradient(to right,#FFF var(--p,0%),rgba(255,255,255,.32) 0)}
.aud__rng::-webkit-slider-thumb{-webkit-appearance:none;width:13px;height:13px;border:0;
  border-radius:50%;background:#FFF;box-shadow:0 1px 3px rgba(0,0,0,.45)}
.aud__rng::-moz-range-thumb{width:13px;height:13px;border:0;border-radius:50%;background:#FFF;
  box-shadow:0 1px 3px rgba(0,0,0,.45)}
.aud__t{display:flex;justify-content:space-between;gap:1rem;margin:0;
  font-family:var(--m);font-size:.68rem;letter-spacing:.04em;color:rgba(255,255,255,.82)}
/* white ring: the brand steel is a mid-tone against a photograph under a scrim */
.aud :where(button,input):focus-visible{outline:2px solid #FFF;outline-offset:3px}

/* THE RECORD, as a record: series, part, passage, speaker, date.
   A definition list because that is what it is, and stacked rather than in two
   columns because the values do not fit one — "Habakkuk 1:5–11" and
   "Sun Aug 9, 2026" both outrun a label column in a 380px rail, and a value
   wrapping under a right-aligned label reads as two facts instead of one. */
.facts{margin:0;display:grid;gap:.9rem}
.facts>div{display:grid;gap:.1rem}
.facts dt{font-family:var(--m);font-size:.62rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--tx-dim)}
.facts dd{margin:0;font-size:.95rem;font-weight:600;letter-spacing:-.015em}
.facts dd a{text-decoration:none;border-bottom:.5px solid var(--hair)}
.facts dd a:hover{border-bottom-color:currentColor}

/* SCRIPTURE, quoted at length.
   Deliberately not a .stmt: that band is the church speaking, and this is the
   page standing aside for the text it is about. So no ground, no centring, a
   rule down the left, and the reference set small underneath as a citation
   rather than large above it as a headline. */
.vs{margin:1.9rem 0 0;padding:.1rem 0 .1rem 1.4rem;border-left:2px solid var(--brand);
  max-width:54ch}
.vs p{font-size:clamp(1.05rem,1.7vw,1.26rem);line-height:1.58;letter-spacing:-.015em;
  margin:0 0 .75rem}
.vs cite{display:block;font-family:var(--m);font-style:normal;font-size:.7rem;
  letter-spacing:.1em;text-transform:uppercase;color:var(--tx-dim)}

/* WHERE TO GO WHEN IT ENDS.
   Two cells, each of them the whole target. Direction is carried by the label
   and the column is set explicitly, so the first or last message in a series
   can drop one side without the other sliding across to take its place. */
.pager{display:grid;grid-template-columns:1fr 1fr;gap:clamp(.9rem,2vw,1.4rem);
  margin-top:clamp(2.5rem,5vw,4rem)}
.pager a{display:block;text-decoration:none;padding:1.25rem 1.5rem;border-radius:var(--r-card);
  border:.5px solid var(--hair);background:var(--card);
  transition:background .2s ease,border-color .2s ease}
.pager a:hover{background:var(--press)}
.pager__p{grid-column:1}
.pager__n{grid-column:2;text-align:right}
.pager .d{display:block;font-family:var(--m);font-size:.66rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--brand);margin-bottom:.5rem}
.pager b{display:block;font-size:1.05rem;font-weight:700;letter-spacing:-.02em}
.pager .who{display:block;font-size:.85rem;color:var(--tx-dim);margin-top:.2rem}

/* ---- 17c. SEARCH ------------------------------------------- */
/* The results page. In production this is server-side — WordPress answers ?s=
   from search.php and renders the rows — so what is new here is the field, the
   count, and the mark on a hit. The rows themselves are .msg, grouped under
   .mo, with .gempty for the nothing-found line: a result is a feed row that
   happens to have been asked for.

   The type filter is .tbar and not .fbar on purpose. The generic filter in
   js/site.js binds to every .fbar that has rows at load, and once search is
   server-rendered the results WILL be there at load — two handlers on one bar,
   each undoing the other. Same shape, different name, no collision. */
.srch{display:flex;align-items:center;gap:.75rem;max-width:640px;margin:1.7rem 0 0;
  padding:0 .35rem 0 1.15rem;background:var(--card);border:.5px solid var(--hair);
  border-radius:var(--r-pill);box-shadow:var(--shadow-card);
  transition:border-color .2s ease}
/* the ring goes on the field, not the input: the input has no edge of its own,
   and an outline drawn inside the pill reads as a second, smaller box */
.srch:focus-within{border-color:var(--brand);outline:2px solid var(--brand);outline-offset:2px}
.srch>svg{flex:none;color:var(--tx-dim)}
.srch input{flex:1;min-width:0;padding:.95rem 0;border:0;background:none;color:var(--tx);
  font-family:var(--f);font-size:1.05rem;letter-spacing:-.015em;
  -webkit-appearance:none;appearance:none}
.srch input:focus{outline:none}
.srch input::placeholder{color:var(--tx-dim)}
/* Safari draws its own clear button on type=search and it is not ours */
.srch input::-webkit-search-decoration,
.srch input::-webkit-search-cancel-button{-webkit-appearance:none}
.srch__x{flex:none;display:grid;place-items:center;width:36px;height:36px;padding:0;
  border:0;border-radius:50%;background:transparent;color:var(--tx-dim);cursor:pointer;
  transition:background .2s ease,color .2s ease}
.srch__x:hover{background:var(--press);color:var(--tx)}
.srch__x[hidden]{display:none}

/* the count, and the line that says what was searched. aria-live, so a screen
   reader hears the number change as the list under it does */
.srch__n{font-family:var(--m);font-size:.72rem;letter-spacing:.06em;color:var(--tx-dim);
  margin:1.1rem 0 0;min-height:1.2em}

/* a hit. --lime carries ink at 14:1 and is a brand primitive, so it is the same
   mark in both themes — the one highlight on the site that does not swap */
mark{background:var(--lime);color:#16171B;padding:.05em .18em;border-radius:3px}

/* ---- 18. LEDGER (impact milestones) ------------------------ */
.ledger{list-style:none;margin:1.6rem 0 0;padding:0;max-width:560px}
.ledger li{display:flex;justify-content:space-between;gap:1.5rem;align-items:baseline;
  padding:.85rem 0;border-top:.5px solid var(--hair)}
.ledger li:first-child{border-top:none}
.ledger b{font-family:var(--m);font-weight:500;font-size:1.05rem;white-space:nowrap}
.ledger span{font-size:.92rem;color:var(--tx-dim);text-align:right}

/* ---- 18b. PARTNER MARKS ------------------------------------ *
 * Other organisations' logos are full colour and mostly drawn for a white
 * page, so they get a light plate that holds in dark mode instead of being
 * recoloured — recolouring someone else's mark is not ours to do.
 * ------------------------------------------------------------ */
.pmark{display:inline-flex;align-items:center;justify-content:center;background:#FFF;
  border:.5px solid var(--hair-soft);border-radius:16px;padding:.9rem 1.3rem;margin:0 0 1.3rem}
.pmark img{height:clamp(28px,3.6vw,40px);width:auto}

/* ---- 19. DOCTRINE (beliefs) -------------------------------- */
.doct{padding:1.9rem 0;border-top:.5px solid var(--hair)}
.doct:first-of-type{border-top:none}
.doct h3{font-size:1.35rem;letter-spacing:-.028em;margin:0 0 .55rem}
.doct p{font-size:.97rem;color:var(--tx-dim);max-width:60ch;margin:0 0 .8em}
.doct .refs{font-family:var(--m);font-size:.72rem;line-height:1.8;color:var(--brand);margin:0}

/* ---- 20. FOOTER -------------------------------------------- */
.foot{background:var(--surface);padding:clamp(3rem,6vw,4.5rem) 0 1.6rem;
  border-top:.5px solid var(--hair);font-size:.86rem}
/* Four columns, and the fourth is the theme control's own. Absolutely
   positioning it over the end of the Offices column put it a hair off that
   column's last line with nothing between them; given a column it gets the same
   2.5rem of air as everything else. The mission line's column comes down from
   1.5fr to pay for it, which also closes the gap that had Sunday gathering
   sitting a long way from the sentence it belongs to. */
.foot__g{position:relative;display:grid;grid-template-columns:1.2fr 1fr 1fr auto;gap:2.5rem;
  padding-bottom:2.4rem}
.foot h4{font-family:var(--m);font-size:.64rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--brand);margin:0 0 .8rem;font-weight:500}
.foot address{font-style:normal;line-height:1.85;color:var(--tx-dim)}
.foot a{color:inherit}
.foot__v{font-size:clamp(1.5rem,2.8vw,2.1rem);font-weight:800;letter-spacing:-.04em;
  line-height:1.06;max-width:13ch}
/* the solid roundel above the mission line — small, so it signs the statement
   rather than restating the nav lockup. Masked to currentColor like the nav
   mark, then dimmed toward --brand so it sits behind the type it introduces. */
.foot__v::before{content:"";display:block;width:30px;height:30px;margin:0 0 1.1rem;
  background:var(--brand);opacity:.85;
  -webkit-mask:url("../assets/three-creeks_ico-solid.svg") no-repeat center/contain;
  mask:url("../assets/three-creeks_ico-solid.svg") no-repeat center/contain}
.foot__v span{color:var(--brand)}
/* the stamp under the sentence — a mark of record, so it takes the column
   heads' mono and tracking but not their brand colour, and sits back */
.foot__since{font-family:var(--m);font-size:.64rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--tx-dim);margin:1rem 0 0}
.foot__b{border-top:.5px solid var(--hair);padding-top:1.3rem;
  font-family:var(--m);font-size:.66rem;letter-spacing:.05em;color:var(--tx-dim);
  display:flex;flex-wrap:wrap;align-items:center;gap:.5rem 1.4rem;
  justify-content:space-between}
/* The theme control sits at the top right of the footer, its top edge on the
   line of the column headings — a preference, not a way through the site, so it
   lives here rather than in the nav next to Give. In the stacked layout there is
   no fourth column to sit in, so it goes back to being pinned beside the mission
   line, which is short enough to clear it. Pages without the column grid (the
   spec sheets) keep it on the colophon line, where the auto margin takes the
   whole of the free space so the two runs of small print read as one block on
   the left. */
.foot__g .seg{align-self:start;justify-self:end}
.foot__b .seg{margin-left:auto;flex:none}

/* theme toggle — three-state segmented control, footer only: light, system,
   dark, in that order, so System reads as the neutral middle and the thumb
   travels the way the two extremes sit. Icons are Lucide (ISC), inlined;
   match their 24px grid and 2px stroke if you add more. */
.seg{position:relative;display:inline-flex;align-items:center;padding:2px;cursor:pointer;
  border:.5px solid var(--hair);border-radius:var(--r-pill);background:transparent;
  -webkit-tap-highlight-color:transparent}
.seg__t{position:absolute;top:2px;left:2px;width:30px;height:30px;border-radius:var(--r-pill);
  background:var(--card);border:.5px solid var(--hair-soft)}
.seg.is-live .seg__t{transition:transform .42s var(--spring)}
/* the thumb follows the chosen mode, not the theme in force — System has to
   look like a choice of its own rather than snapping to whichever end the OS
   happens to be on */
.seg[data-mode="system"] .seg__t{transform:translateX(30px)}
.seg[data-mode="dark"] .seg__t{transform:translateX(60px)}
.seg__b{position:relative;z-index:1;width:30px;height:30px;padding:0;border:none;
  background:transparent;cursor:pointer;border-radius:var(--r-pill);color:var(--tx-dim);
  display:inline-flex;align-items:center;justify-content:center;
  -webkit-tap-highlight-color:transparent}
/* invisible hit area — keeps the control visually small next to 11px colophon
   type without handing a thumb a 30px tap target */
.seg__b::after{content:"";position:absolute;inset:-8px -2px}
.seg__b:hover,.seg__b[aria-pressed="true"]{color:var(--tx)}
/* the icon being handed control turns toward you and fills in; the others step back
   and return to outline. CSS beats the fill="none" attribute on the <svg>, but not
   one set on a child — which is how the monitor keeps its outline and fills only
   the inner screen, so the three icons gain roughly the same weight when chosen.
   The sun's rays and the monitor's stand are open paths and take no fill. */
.seg__b svg{fill:currentColor;fill-opacity:0;
  transition:transform .42s var(--spring),opacity .3s ease,fill-opacity .3s ease}
.seg__b[aria-pressed="true"] svg{fill-opacity:1}
.seg__b[aria-pressed="false"] svg{opacity:.5;transform:scale(.82)}
.seg.is-live [data-theme-set="light"][aria-pressed="false"] svg{transform:scale(.82) rotate(-60deg)}
.seg.is-live [data-theme-set="dark"][aria-pressed="false"] svg{transform:scale(.82) rotate(35deg)}
/* a sun and a moon can rotate on their way out; a screen cannot, so the system
   icon only steps back in scale */

/* ---- 21. MOBILE MENU --------------------------------------- */
/* The burger is the only close affordance: while the sheet is open it floats
   above it (the bars are already an X), so the nav is lifted over the sheet
   and everything else in the bar steps aside. */
.m-burger{display:none;position:relative;z-index:1;width:44px;height:44px;border:none;
  background:transparent;cursor:pointer;border-radius:12px;color:inherit;
  -webkit-tap-highlight-color:transparent}
.m-burger:hover{background:var(--press)}
.m-burger i{position:absolute;left:12px;width:20px;height:1.7px;background:currentColor;
  border-radius:2px;transition:transform .34s cubic-bezier(.4,0,.2,1)}
.m-burger i:nth-of-type(1){top:18px}
.m-burger i:nth-of-type(2){top:25px}
.m-burger[aria-expanded="true"] i:nth-of-type(1){transform:translateY(3.5px) rotate(45deg)}
.m-burger[aria-expanded="true"] i:nth-of-type(2){transform:translateY(-3.5px) rotate(-45deg)}

/* nav rides above the sheet so the X stays on top and stays clickable; its
   own chrome is dropped because the scrim, not the bar, is the backdrop now */
.menu-open .nav{z-index:90;pointer-events:none}
/* the glass cannot fade — see §3a — so it goes in one blink, held back just
   long enough for the scrim to be most of the way in and cover the moment */
.menu-open .nav::before,.menu-open .nav::after,.menu-open .nav>.glass{
  visibility:hidden;transition:visibility 0s .18s}
.menu-open .nav__in>:not(.nav__end),
.menu-open .nav__end>:not(.m-burger){opacity:0}
/* the X floats over the sheet, so while the menu is open it belongs to the
   sheet's palette, not the bar's */
.menu-open .m-burger{pointer-events:auto;color:var(--m-tx)}
.menu-open .m-burger:hover{background:var(--m-press)}
.nav__in>*,.nav__end>*{transition:opacity .28s ease}

.m-scrim{position:fixed;inset:0;z-index:70;background:var(--scrim);
  backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);
  opacity:0;transition:opacity .32s ease}
.m-scrim.is-on{opacity:1}

/* Two different motions, because opening and closing are not the same act.
 * Opening is a reveal: the sheet arrives on a soft ease-out and its leading
 * edge starts as a half-ellipse that flattens into a straight edge as it
 * lands — the panel reads as something that swings in rather than a rectangle
 * that slides. Closing is a dismissal: a hard ease-in that barely creeps for
 * the first half, then leaves. Same distance, opposite feel.
 * --m-io is the entrance curve, --m-oo the exit; both are set here rather than
 * on :root because nothing outside the sheet uses them. */
.m-sheet{--m-io:cubic-bezier(.45,.9,.55,1);--m-oo:cubic-bezier(.65,0,.85,.35);
  --m-bulge:38px;
  position:fixed;top:0;right:0;bottom:0;z-index:80;width:min(410px,89vw);
  background:var(--m-bg);color:var(--m-tx);display:flex;flex-direction:column;
  transform:translateX(102%);border-radius:0;
  /* the section rules inside run the full width, so while the leading edge is
     still curved they would hang off it — clipping to the sheet's own shape is
     what keeps the silhouette clean. Scrolling still happens in .m-body. */
  overflow:clip;
  transition:transform .44s var(--m-oo);
  box-shadow:-30px 0 70px -34px rgba(0,0,0,.7);overscroll-behavior:contain}
/* the display:flex above outranks the UA's [hidden]{display:none}, which would
   leave the closed sheet parked off-screen with its left-hand shadow still
   bleeding onto the right edge of every page. Put the hiding back. */
.m-sheet[hidden]{display:none}

/* the armed state is the start frame of the entrance, painted with transitions
   off so nothing animates into it. It only exists between show() and the next
   frame; on the way out the sheet passes through the flat resting state above,
   which is why the exit is a plain slide with no shape morph. */
.m-sheet.is-armed{transform:translateX(102%);
  border-radius:var(--m-bulge) 0 0 var(--m-bulge) / 50% 0 0 50%;
  transition:none}

.m-sheet.is-on{transform:none;border-radius:0;
  transition:transform .55s var(--m-io),border-radius .55s var(--m-io)}

/* Each row drifts the last few pixels in on its own, top of the sheet first,
   so the menu assembles instead of arriving pre-built. Rows share an index
   where they read as one line — the two-column list moves a pair at a time,
   because staggering left and right cells separately looks like a glitch.
   No fade: the rows are already opaque when the sheet's edge passes them, and
   fading would only muddy type at display size. */
.m-sheet.is-armed :where(.m-top .mark,.m-prime li,.m-div,.m-sec li,.m-when,.m-foot){
  transform:translateX(40px);transition:none}
.m-sheet.is-on :where(.m-top .mark,.m-prime li,.m-div,.m-sec li,.m-when,.m-foot){
  transform:none;transition:transform .46s var(--m-io) calc(60ms + var(--i,0) * 32ms)}
.m-prime li:nth-child(1){--i:1}
.m-prime li:nth-child(2){--i:2}
.m-prime li:nth-child(3){--i:3}
.m-prime li:nth-child(4){--i:4}
.m-div{--i:5}
.m-sec li{--i:6}
.m-sec li:nth-child(n+5){--i:7}
.m-when{--i:8}
.m-foot{--i:9}

/* height matches the nav bar at rest so the mark lands on the same baseline as
   the one it replaces; the right padding is the room the floating burger needs */
/* The sheet is fixed to the top of the viewport, but the bar it has to line up
   with is not: with an announcement running, the header starts at --cta-h and so
   does the lockup in it. The block takes that height as padding and carries it in
   its min-height too, which keeps the sheet's lockup on the same centre line as
   the one behind it — and the burger, which never left the header. With no bar
   --cta-h is 0 and this is the block it always was. */
.m-top{display:flex;align-items:center;gap:1rem;
  min-height:calc(var(--nav-h) + var(--cta-h,0px));
  padding:calc(.5rem + var(--cta-h,0px)) calc(5vw + 52px) .5rem 1.4rem}
/* the wordmark is a mask taking currentColor, so this is all it needs; --mark
   is the page's steel and would sink into the sheet's own ground */
.m-top .mark{color:var(--m-tx)}
/* --brand sits a shade off the sheet's ground in light mode, so the default
   ring would all but vanish exactly where keyboard users need it most */
.m-sheet :where(a,button):focus-visible{outline-color:var(--m-accent)}

.m-body{flex:1;overflow-y:auto;-webkit-overflow-scrolling:touch}

.m-when{padding:1.4rem;border-top:.5px solid var(--m-hair)}
.m-when__k{margin:0 0 .45rem;font-family:var(--m);font-size:.62rem;letter-spacing:.16em;
  text-transform:uppercase;color:var(--m-accent)}
.m-when__t{margin:0 0 .5rem;font-size:1.65rem;font-weight:800;letter-spacing:-.04em;line-height:1}
.m-when__a{margin:0 0 .9rem;font-size:.88rem;line-height:1.55;color:var(--m-tx-dim)}
.m-when__go{font-size:.88rem;font-weight:600;text-decoration:none;
  border-bottom:1.5px solid var(--m-accent);padding-bottom:1px}

/* Two tiers, as on the live site: the four things a visitor actually opens the
   menu for, at display size — then a rule, then a two-column index of
   everything else, which reads row-major (Home | Coming up, About | ...). */
.m-nav{padding:1.5rem 1.4rem .4rem}
.m-nav ul{list-style:none;margin:0;padding:0}
.m-nav a{text-decoration:none;color:var(--m-tx);-webkit-tap-highlight-color:transparent}
.m-nav a[aria-current="page"]{color:var(--m-accent)}

.m-prime{display:flex;flex-direction:column}
.m-prime a{display:block;padding:.3rem 0;font-size:clamp(1.75rem,8.3vw,2.2rem);
  font-weight:800;letter-spacing:-.045em;line-height:1.16}

.m-div{height:2px;margin:1.5rem 0 1.35rem;border:0;background:var(--m-rule)}

.m-sec{display:grid;grid-template-columns:1fr 1fr;gap:.5rem 1rem}
.m-sec a{display:block;padding:.42rem 0;font-size:1.02rem;font-weight:700;
  letter-spacing:-.025em;line-height:1.3}

/* the sheet's calls to action live in the fixed bar at the bottom of the page,
   not in here — the footer is just the contact line */
.m-foot{padding:1rem 1.4rem calc(1rem + env(safe-area-inset-bottom));
  border-top:.5px solid var(--m-hair)}
.m-call{margin:0;text-align:center;font-family:var(--m);font-size:.74rem;color:var(--m-tx-dim)}
.m-call a{color:inherit}

/* the bar itself paints nothing: its ground is the glass in §3a, which it
   shares with the header and takes upward instead of down */
.m-bar{display:none;position:fixed;left:0;right:0;bottom:0;z-index:60;
  gap:.5rem;padding:.55rem .8rem calc(.55rem + env(safe-area-inset-bottom))}
.m-bar a{flex:1;display:flex;align-items:center;justify-content:center;min-height:46px;
  font-size:.88rem;font-weight:600;text-decoration:none;border-radius:var(--r-pill);
  border:1px solid var(--hair)}
.m-bar a.is-cta{background:var(--lime);border-color:var(--lime);color:#16171B}
/* the giving page's bar asks for the one thing the lime is never spent on */
.m-bar a.is-give{background:var(--sky);border-color:var(--sky);color:#16171B}

/* ---- 22. MOTION -------------------------------------------- *
 * Entrance reveals are opt-in: only the selectors listed below move, and
 * that list is mirrored by REVEAL in js/site.js — edit both together.
 * The hidden state is CSS, not a JS-applied class, so it is in force at
 * first paint and content never flashes. It is also gated twice: on the
 * .js root class (set pre-paint in each page head) so a failed or blocked
 * script leaves everything visible, and on no-preference so reduced-motion
 * users get the finished state immediately. :where() keeps the list at zero
 * specificity, which is what lets the plain .is-in rule below win.
 * ------------------------------------------------------------ */
@media (prefers-reduced-motion:no-preference){
  .js :where(
    .stage .k,.stage h1,.stage .l,.stage__acts,.frame,
    .pghd h1,
    .stmt .k,.stmt h2,.stmt .l,
    .feat p,.feat h2,.feat .stage__acts,
    section>.k,section>h2,section>h3,section>.lede,section>.body,
    section>p:not(.gempty),
    .rail__card,.fbar,.player,.vs,.pager a,
    .tile,.point,.work,.gcard,.person,.rooms li,.vals li,.tl li,.tree li,.ev,.msg,.doct,.ledger li,
    .demo,.sw,.ty-row
  ){opacity:0;transform:translateY(14px);
    transition:opacity .75s var(--ease),transform .75s var(--ease)}

  .js .is-in{opacity:1;transform:none}

  /* the headline carries more weight, so it travels further and slower */
  .js :where(.stage h1){transform:translateY(22px);transition-duration:.95s}
  /* photography settles into place instead of sliding */
  .js :where(.frame,.player){transform:scale(1.015)}

  /* the family tree draws itself: node, then the line to the next generation.
     Horizontal here; the stacked breakpoint below turns it on its side. */
  .js :where(.tree li)::before{transform:scale(0);transition:transform .5s var(--spring) .1s}
  .js .tree li.is-in::before{transform:scale(1)}
  .js :where(.tree li)::after{transform:scaleX(0);transform-origin:left;
    transition:transform .65s var(--ease) .2s}
  .js .tree li.is-in::after{transform:scaleX(1)}
}

/* ---- 23. RESPONSIVE ---------------------------------------- */
/* Four across is the whole idea, so it holds as long as it can. The floor is
   set by "Three Creeks Church" — the name is non-breaking, so the card has to
   fit it on one line, and it stops fitting at about 1116px. Stacking at 1160
   leaves that a little air. There is no honest two-up step in between: a
   horizontal rail cannot cross from the end of one row to the start of the
   next, so the tree goes straight to a stack and stands the rail on its side. */
@media(max-width:1160px){
  .tree{grid-template-columns:1fr;gap:0;max-width:620px}
  .tree li{padding:0 0 1rem 1.9rem}
  .tree li:last-child{padding-bottom:0}
  .tree li::before{left:0;top:1.5rem;margin-left:0}
  /* runs under the next node rather than up to it — the node has z-index and
     paints over the overlap, so the joint stays closed at any font size */
  .tree li::after{left:5px;top:2.2rem;bottom:-1.7rem;width:.5px;height:auto}
}
/* the draw-in follows it round */
@media(max-width:1160px) and (prefers-reduced-motion:no-preference){
  .js :where(.tree li)::after{transform:scaleY(0);transform-origin:top}
  .js .tree li.is-in::after{transform:scaleY(1)}
}
@media(max-width:1000px){
  /* the lockup leads instead of signing. It keeps the corner only while there is
     a corner to keep: below this the panel goes full width, the heading takes the
     line it wants, and a mark held out to the right reads as a stray. Stacked, it
     goes first — a signature at the foot of a block someone is still reading is
     not a signature, it is a stray line of art. */
  .kcta__hd{display:flex;flex-direction:column}
  .kcta__mark{order:-1;margin:0 0 1rem}
  .split{grid-template-columns:1fr}
  .rail{position:static;order:-1}
  /* except on search, where the rail is not a sidebar but a fallback: someone
     who has just typed a query wants the results, and "ask an actual person"
     is what they want only after those have failed */
  [data-search] .rail{order:0}
  .duo,.foot__g{grid-template-columns:1fr}
  .foot__g .seg{position:absolute;top:0;right:0}
  .trio{grid-template-columns:1fr}
  .rooms{grid-template-columns:1fr 1fr}
  .dir{grid-template-columns:1fr 1fr}
  .gwrap{grid-template-columns:1fr}
  .feat{grid-template-columns:1fr}
  .vals li{grid-template-columns:1fr;gap:.3rem}
}
@media(max-width:900px){
  /* Two columns of roughly 380px is where a .work stops being a card and starts
     being a squeeze — the heading breaks over four lines before the picture
     gives anything back. It stacks a step earlier than the other grids. */
  .work,.work--act{grid-template-columns:1fr;gap:1.1rem}
  .work:nth-of-type(even) .work__m{order:0}
  .work__ph{aspect-ratio:16/9}
  .work__b{padding:.1rem .5rem .5rem}
  .work--act .work__b{padding:0}
  .work--act>.pill{justify-self:start}
  /* the whole row goes, groups and panels with it — the sheet is the menu now */
  .nav__l{display:none}
  .nav__end .pill{display:none}
  .m-burger{display:block}
  /* the bar is shorter here — a phone has less screen to give away before the
     first line of content */
  :root{--nav-h:66px}
  /* the lockup steps down with it, but only just: at 62px it read as an
     afterthought beside a 44px burger. 67×38 keeps the mark's 130.61:73.86
     ratio, so nothing letterboxes inside the mask. */
  .mark{--mark-w:67px;--mark-h:38px}
}
@media(max-width:760px){
  .m-bar{display:flex}
  /* the fixed bar covers the last stretch of the page, so the footer buys that
     height back as its own bottom padding — its ground then runs behind the
     bar's glass instead of the bar landing on a strip of --bg, and the last
     line of the footer clears the bar once the page is scrolled all the way
     down. Height of the bar: 46px control + .55rem of padding either side,
     plus whatever the device reserves below it. */
  body{padding-bottom:0}
  .foot{padding-bottom:calc(1.6rem + 64px + env(safe-area-inset-bottom))}
  .dir{grid-template-columns:1fr}
}
@media(max-width:560px){
  /* the announcement gets the whole width here: the date goes, and the message
     is allowed the second line it cannot have on a desktop. This is what the
     measured --cta-h in js/site.js is for — the bar grows and the page steps
     down with it. Two lines is the ceiling; a third means the message is a page. */
  .cta__k{display:none}
  .cta__in{gap:.7rem}
  /* the action goes down to its arrow. The label is the first thing that can go
     here: the message is the announcement, the whole band is the link, and a
     circle buys the message the better part of a line back — which on a phone is
     the difference between the place fitting and being cut off. */
  .cta__go{width:34px;height:34px;padding:0;gap:0;border-radius:50%;justify-content:center}
  .cta__go span{display:none}
  .cta__t{white-space:normal;line-height:1.25;
    display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
  .ev,.msg{grid-template-columns:1fr}
  .ev>a,.msg>a{justify-self:start}
  /* the audio well is about 190px tall here, and its controls cannot have half
     of that: the skip and speed keys keep their hit areas and lose their boxes,
     and the scrim tightens up behind them */
  .aud__c{gap:.55rem;padding-top:1.6rem}
  .aud__b{height:34px;min-width:34px}
  .aud__t{font-size:.64rem}
  /* stacked, "next" is simply the one below — the right-hand alignment that
     told them apart side by side now only pulls one card out of the margin */
  .pager{grid-template-columns:1fr}
  .pager__p,.pager__n{grid-column:1}
  .pager__n{text-align:left}
  /* a 150px photo column would leave the copy about 25 characters wide, so the
     note stacks and the picture takes a landscape crop instead */
  .point{grid-template-columns:1fr;gap:.9rem}
  .point__ph{aspect-ratio:16/9}
  .point__b{padding:0 .2rem .2rem}
}
@media(prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *{transition:none!important}
  .m-sheet,.m-scrim,.m-burger i{transition:none}
}

/* ---- 22. MESSAGE LIBRARY ------------------------------------
   The full archive: every message, as cover art, with search,
   filters and paging.

   WHY NEW CLASSES AND NOT .msg / .fbar.
   js/site.js filters `FROW='.gcard,.msg'` inside every `.fbar`, writing
   style.display directly, and js/live-search.js layers a data-q facet on
   top of that. Three writers on one property is how a filter and a pager
   start undoing each other. This screen owns its own visibility, so it
   stays out of those two selectors — and reuses .fbtn, .srch, .gempty and
   every token unchanged, so it still looks like the same site.

   .mlib__card is a .tile that had to survive being 247 of itself: a
   fixed 16:9 well instead of a 230px one, tighter body, and no hover
   zoom below a mouse.  */
.mlib__tools{margin:1.6rem 0 0}
.mlib__facets{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem 1.4rem;margin:1.2rem 0 0}
.mlib__bar{display:flex;flex-wrap:wrap;gap:.45rem}

/* A facet with more options than you can read at a glance becomes a menu.
   Same state, same tokens, one line of height however far the archive grows. */
.mlib__sel{display:flex;align-items:center;gap:.5rem;margin:0}
.mlib__sel label{font-family:var(--m);font-size:.7rem;letter-spacing:.1em;text-transform:uppercase;
  color:var(--tx-dim)}
.mlib__sel select{font-family:var(--m);font-size:.74rem;max-width:16rem;
  padding:.5rem 2rem .5rem .8rem;color:var(--tx);background:var(--card);
  border:.5px solid var(--hair);border-radius:var(--r-pill);cursor:pointer;
  -webkit-appearance:none;appearance:none;
  background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%236E7079' stroke-width='2.5' stroke-linecap='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right .7rem center}
.mlib__sel select:hover{background-color:var(--press)}
.mlib__sel select:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
.mlib__bar .fbtn{max-width:22rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mlib__count{font-family:var(--m);font-size:.72rem;letter-spacing:.06em;text-transform:uppercase;
  color:var(--tx-dim);margin:1.5rem 0 .2rem}

.mlib__grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(15.5rem,1fr));
  gap:clamp(1rem,2vw,1.5rem);margin-top:1rem;padding:0;list-style:none}

.mlib__card{display:flex;flex-direction:column;height:100%;margin:0;
  border-radius:var(--r-tile);overflow:hidden;background:var(--card);
  border:.5px solid var(--hair-soft);text-decoration:none;color:inherit;
  transition:background .2s ease,border-color .2s ease}
.mlib__card:hover{background:var(--press);border-color:var(--hair)}
.mlib__card:focus-visible{outline:2px solid var(--brand);outline-offset:2px}

/* the well is 16:9 whatever the file is, so a grid of 247 stills cannot
   go ragged on one badly cropped upload */
.mlib__ph{position:relative;aspect-ratio:16/9;background:var(--surface);overflow:hidden}
.mlib__ph img{width:100%;height:100%;object-fit:cover;display:block}
@media (prefers-reduced-motion:no-preference){
  .mlib__ph img{transition:transform .9s var(--ease)}
  .mlib__card:hover .mlib__ph img{transform:scale(1.04)}
}
/* duration sits on the art, the way it does in the player */
.mlib__len{position:absolute;right:.5rem;bottom:.5rem;padding:.2rem .45rem;
  border-radius:var(--r-pill);background:rgba(22,23,27,.78);color:#fff;
  font-family:var(--m);font-size:.66rem;letter-spacing:.04em}

.mlib__b{display:flex;flex-direction:column;flex:1;padding:1rem 1.05rem 1.15rem}
.mlib__d{font-family:var(--m);font-size:.7rem;letter-spacing:.1em;text-transform:uppercase;
  color:var(--brand)}
.mlib__t{font-size:1.02rem;font-weight:700;letter-spacing:-.02em;margin:.35rem 0 0;
  line-height:1.28}
.mlib__who{font-size:.83rem;color:var(--tx-dim);margin:.4rem 0 0}
.mlib__s{font-family:var(--m);font-size:.68rem;letter-spacing:.06em;color:var(--tx-dim);
  margin:.75rem 0 0;padding-top:.6rem;border-top:.5px solid var(--hair-soft)}

/* paging — a row of pills, not the prev/next .pager, which is a
   two-cell adjacency control and means something else */
.mlib__pager{display:flex;flex-wrap:wrap;gap:.4rem;align-items:center;justify-content:center;
  margin-top:clamp(2rem,4vw,3rem)}
.mlib__pg{font-family:var(--m);font-size:.74rem;min-width:2.4rem;padding:.5rem .7rem;
  border:.5px solid var(--hair);border-radius:var(--r-pill);background:var(--card);
  color:var(--tx);cursor:pointer;transition:background .2s ease}
.mlib__pg:hover{background:var(--press)}
.mlib__pg[aria-current="page"]{background:var(--tx);border-color:var(--tx);color:var(--bg)}
.mlib__pg[disabled]{opacity:.4;cursor:default}
.mlib__pg[disabled]:hover{background:var(--card)}
.mlib__gap{color:var(--tx-dim);padding:0 .15rem}

/* .blk:last-child drops its bottom padding because on every other page the
   block that matches is followed by something — a rail, a band — and the
   padding would double up. The library is the one page where the last .blk
   IS the last thing before the footer, so the pager ends up welded to it.
   Put the padding back, here only. */
.wrap > .blk.mlib:last-child{padding-bottom:clamp(3rem,6vw,5rem)}

/* Without JavaScript every card is present and visible — the pager, the count
   and the filter bar are the only parts that assume a script, so they stay
   hidden until one arrives rather than offering a control that cannot work.
   The component reveals its own, on itself: there is no global `.js` class on
   this site and inventing one here would be a convention of exactly one user. */
.mlib__pager,.mlib__count,.mlib__facets{display:none}
.mlib.is-live .mlib__pager,.mlib.is-live .mlib__facets{display:flex}
.mlib.is-live .mlib__count{display:block}

@media(max-width:560px){
  .mlib__grid{grid-template-columns:repeat(auto-fill,minmax(13rem,1fr));gap:.9rem}
  .mlib__b{padding:.85rem .9rem 1rem}
}

/* ---- 23. NOTICE PANEL ---------------------------------------
   Stands in for a listing that is deliberately not showing yet —
   registration closed, a season between terms. It is NOT .gempty:
   that line answers "your filter matched nothing" and is a muted
   aside, which is the wrong register for "come back on the 1st".

   Built from parts that already exist — the mono eyebrow, a lime
   chip, a pill — so it reads as the same site rather than as a
   plugin's idea of an empty state.  */
.notice{text-align:center;background:var(--card);
  border:.5px solid var(--hair-soft);border-radius:var(--r-card);
  padding:clamp(2.4rem,5.5vw,4.2rem) clamp(1.4rem,4vw,3rem);
  box-shadow:var(--shadow-card)}
.notice .k{color:var(--brand);margin:0}
/* the date is the message; it gets the one piece of colour in the block */
.notice__d{display:inline-block;margin:1.15rem 0 0}
.notice h3{font-size:clamp(1.55rem,3.6vw,2.35rem);letter-spacing:-.022em;
  line-height:1.12;margin:.85rem auto 0;max-width:19ch}
.notice h3 span{color:var(--brand)}
.notice p{color:var(--tx-dim);max-width:46ch;margin:1rem auto 0}
.notice .pill{margin-top:1.7rem}

@media(max-width:560px){
  .notice{padding:2.1rem 1.25rem}
  .notice h3{max-width:none}
}
