/* ==========================================================================
   Coast House Churches — site stylesheet
   Direction: "Coastal & calm". Typography-led, no photography, no logo.
   Everything is driven by the custom properties in :root below.
   ========================================================================== */

/* --------------------------------------------------------------------------
   0. Fonts — self-hosted
   Mirrors exactly what Google Fonts used to serve, with local files. Kept
   self-hosted on purpose: loading these from fonts.googleapis.com told Google
   the IP address of every visitor, and it was the only request this site made
   off its own origin. The Content-Security-Policy in public/_headers now
   forbids external loads outright, so putting the <link> tags back would
   silently break the fonts.

   Both families are VARIABLE fonts: one file covers several weights, which is
   why the same .woff2 appears more than once below. The unicode-range lines
   are what stop a visitor downloading latin-ext unless the page actually uses
   it — /contact/ does, for the macron in Whangaparāoa.

   To re-subset or add a weight, refetch from Google Fonts with a modern
   browser User-Agent and mirror the output here again. Don't hand-edit ranges.
   -------------------------------------------------------------------------- */

/* latin-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/inter-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* latin */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/inter-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* latin-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/assets/fonts/inter-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* latin */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/assets/fonts/inter-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* latin-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/assets/fonts/inter-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* latin */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/assets/fonts/inter-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* latin-ext */
@font-face {
  font-family: 'Source Serif 4';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/source-serif-4-italic-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* latin */
@font-face {
  font-family: 'Source Serif 4';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/source-serif-4-italic-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* latin-ext */
@font-face {
  font-family: 'Source Serif 4';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/source-serif-4-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* latin */
@font-face {
  font-family: 'Source Serif 4';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/source-serif-4-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* latin-ext */
@font-face {
  font-family: 'Source Serif 4';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/assets/fonts/source-serif-4-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* latin */
@font-face {
  font-family: 'Source Serif 4';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/assets/fonts/source-serif-4-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */

:root {
  /* Ground & ink */
  --paper:        #FBF9F5;
  --paper-raised: #F5F1E8;
  --ink:          #1F2321;
  --ink-soft:     #3A403C;
  --muted:        #6B6B63;

  /* Accents */
  --sea:          #1F4E4A;
  --sea-deep:     #163936;
  --sea-tint:     #E4EDEB;
  /* Clay is used for small text (eyebrows, Scripture times, required marks) as
     well as rules, so it has to clear 4.5:1 on both paper and paper-raised.
     #A15C37 = 4.85:1 on paper, 4.53:1 on raised. */
  --clay:         #A15C37;
  --clay-deep:    #82492C;
  --sand:         #E8E0D2;
  --line:         #DED7C8;

  /* Focus */
  --focus:        #A15C37;

  /* Type */
  --serif: "Source Serif 4", "Iowan Old Style", Georgia, "Times New Roman", serif;
  --sans:  "Inter", system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

  /* Measure & rhythm */
  --wrap:    1120px;
  --measure: 68ch;
  --gutter:  clamp(1.25rem, 4vw, 2.5rem);
  /* The floor here lands on phones. 3.5rem was desktop-scale spacing applied to
     a 390px screen and left ~180px of dead air between blocks. */
  --section: clamp(2.5rem, 7vw, 6rem);
  --space-s: clamp(1.25rem, 3vw, 2rem);
  --space-m: clamp(1.75rem, 4vw, 2.5rem);

  /* Fluid type scale */
  --t-hero: clamp(2.35rem, 1.55rem + 3.4vw, 4rem);
  --t-h1:   clamp(2rem, 1.5rem + 2.2vw, 3.15rem);
  --t-h2:   clamp(1.5rem, 1.28rem + 1vw, 2.1rem);
  --t-h3:   clamp(1.16rem, 1.08rem + 0.4vw, 1.4rem);
  --t-lede: clamp(1.1rem, 1.02rem + 0.42vw, 1.32rem);
  --t-body: 1.0625rem;
  --t-small: 0.875rem;
  --t-micro: 0.78rem;

  --radius: 3px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --paper:        #0F1413;
    --paper-raised: #171D1C;
    --ink:          #E9E7DF;
    --ink-soft:     #C8C6BC;
    --muted:        #96968C;

    --sea:          #86C2B8;
    --sea-deep:     #A9D6CE;
    --sea-tint:     #172523;
    --clay:         #DE9264;
    --clay-deep:    #EFA97F;
    --sand:         #232A28;
    --line:         #2C3432;

    --focus:        #DE9264;
  }
}

/* --------------------------------------------------------------------------
   2. Reset & base
   -------------------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 6rem;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--t-body);
  line-height: 1.72;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4 {
  font-family: var(--serif);
  font-weight: 600;
  line-height: 1.18;
  color: var(--sea);
  margin: 0 0 0.6em;
  letter-spacing: -0.011em;
  text-wrap: balance;
}

h1 { font-size: var(--t-h1); }
h2 { font-size: var(--t-h2); margin-top: 2.4em; }
h3 { font-size: var(--t-h3); margin-top: 2em; color: var(--ink); }
h4 { font-size: 1.02rem; margin-top: 1.8em; color: var(--ink); font-family: var(--sans); font-weight: 600; }

h2:first-child, h3:first-child, h4:first-child { margin-top: 0; }

p { margin: 0 0 1.25em; }
p:last-child { margin-bottom: 0; }

a {
  color: var(--sea);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
  text-decoration-color: color-mix(in srgb, var(--sea) 38%, transparent);
  transition: color .15s ease, text-decoration-color .15s ease;
}
a:hover { color: var(--clay); text-decoration-color: var(--clay); }

:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
  border-radius: 2px;
}

strong { font-weight: 600; color: var(--ink); }
em { font-style: italic; }

ul, ol { margin: 0 0 1.35em; padding-left: 1.25em; }
li { margin-bottom: 0.5em; }
li:last-child { margin-bottom: 0; }

hr {
  border: 0;
  border-top: 1px solid var(--line);
  margin: var(--section) 0;
}

::selection { background: var(--sand); color: var(--ink); }

/* --------------------------------------------------------------------------
   3. Layout helpers
   -------------------------------------------------------------------------- */

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.prose { max-width: var(--measure); }

/* Spacing utilities. These replace the ad-hoc inline style="margin-top:…"
   attributes that were scattered through the pages, so the vertical rhythm
   comes from tokens rather than from whatever number was typed that day. */
/* Visually hidden, still announced. Not display:none, which removes it from
   the accessibility tree too. .hp is the contact honeypot's own copy of this
   and stays where it is: it is hidden for a different reason. */
.vh {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.tight { margin-top: 0; }
.mt-s { margin-top: var(--space-s); }
.mt-m { margin-top: var(--space-m); }
.stack-s > * + * { margin-top: var(--space-s); }

.section { padding-block: var(--section); }
.section + .section { padding-top: 0; }

/* On the Hebrews 13:17 notes the band sits in a grid column beside the index
   and is widened back to full width by a border-image: .layout-index--parts,
   section 11. */
.section--tint {
  background: var(--paper-raised);
  border-block: 1px solid var(--line);
}
/* The collapse rule above (.section + .section) is fine for sections that share
   the page background, but a section with its own band makes the missing top
   padding visible: content sat hard against the top edge with ~90px of void
   underneath it. Anything with a background keeps symmetric padding. */
.section.section--tint { padding-top: var(--section); }
.section--tint + .section { padding-top: var(--section); }

/* Hairline between two untinted sections, for where a band change would be too
   loud but running the page on with no break at all loses the seam. Margin-free
   on purpose: the padding of the sections either side supplies the air, so this
   never doubles up on the rhythm the tokens already set. */
.section-break {
  border: 0;
  border-top: 1px solid var(--line);
  margin: 0;
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--sea);
  color: var(--paper);
  padding: 0.75rem 1.25rem;
  z-index: 100;
  font-weight: 600;
  text-decoration: none;
}
.skip:focus {
  left: 0.5rem;
  top: 0.5rem;
}

/* --------------------------------------------------------------------------
   4. Masthead & navigation
   -------------------------------------------------------------------------- */

.masthead {
  position: sticky;
  top: 0;
  z-index: 50;
  /* Opaque. At 92% the body text scrolled visibly through the bar and read as a
     rendering fault rather than as translucency. */
  background: var(--paper);
  border-bottom: 1px solid var(--line);
}

.masthead__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  min-height: 4.35rem;
}

.wordmark {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-family: var(--serif);
  font-weight: 600;
  font-size: 1.06rem;
  letter-spacing: 0.055em;
  text-transform: uppercase;
  color: var(--sea);
  text-decoration: none;
  line-height: 1.2;
  white-space: nowrap;
}
.wordmark:hover { color: var(--clay); }

/* The toggle only exists when JS is running. Without it the nav simply wraps
   below the wordmark on small screens — always reachable, never trapped. */
.nav-toggle { display: none; }
.js .nav-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  background: none;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--ink);
  font: inherit;
  font-size: var(--t-small);
  padding: 0.45rem 0.75rem;
  cursor: pointer;
}
.nav-toggle:hover { border-color: var(--sea); color: var(--sea); }

.nav { align-self: stretch; }

.nav__list {
  display: flex;
  align-items: stretch;
  flex-wrap: wrap;
  gap: clamp(1rem, 2.2vw, 1.9rem);
  height: 100%;
  margin: 0;
  padding: 0;
  list-style: none;
}
.nav__item { position: relative; display: flex; align-items: center; margin: 0; }

.nav__list > .nav__item > a {
  display: inline-flex;
  align-items: center;
  gap: 0.34rem;
  min-height: 44px;
  font-size: 0.925rem;
  font-weight: 500;
  color: var(--ink-soft);
  text-decoration: none;
  border-bottom: 2px solid transparent;
  white-space: nowrap;
}
.nav__list > .nav__item > a:hover { color: var(--sea); border-bottom-color: var(--sand); }
.nav__list > .nav__item > a[aria-current="page"],
.nav__list > .nav__item > a[aria-current="true"] {
  color: var(--sea);
  border-bottom-color: var(--clay);
}

/* Chevron marking a parent that has a submenu */
.has-menu > a::after {
  content: "";
  width: 0.34rem;
  height: 0.34rem;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-0.15em) rotate(45deg);
  transition: transform .15s ease;
}
.has-menu:hover > a::after,
.has-menu:focus-within > a::after { transform: translateY(0.05em) rotate(225deg); }

/* Submenu. Opens on hover and on keyboard focus, so it works with no JS at
   all — :focus-within reveals it as soon as the parent link is tabbed to,
   which puts the child links in the natural tab order straight after it. */
.nav__menu {
  position: absolute;
  top: 100%;
  left: -0.75rem;
  z-index: 60;
  min-width: 15rem;
  margin: 0;
  padding: 0.35rem;
  list-style: none;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 18px 36px -24px rgba(0,0,0,.5);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: opacity .14s ease, transform .14s ease, visibility .14s;
}
.has-menu:hover > .nav__menu,
.has-menu:focus-within > .nav__menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}
/* The last dropdown opens from the right edge of its parent instead of the
   left. Every menu is a fixed 15rem outdented 0.75rem, and the nav sits hard
   against the right of the wrap, so the final one runs off the page: at a
   1000px window it ended 25px past the viewport and gave every page 25px of
   horizontal scroll. Anchored right, its edge can never pass its parent's, and
   its parent can never pass the nav's.

   Selected as "a menu item with no menu item after it" rather than by
   position, because Contact is a plain link with no dropdown of its own: the
   last nav item and the last one carrying a menu are not the same element.
   Structural rather than nth-child also means adding or removing a section can
   never leave this anchoring the wrong menu. Resources is the one it catches
   today, and it is doing real work -- the nav had 7px of headroom before that
   item existed, and this is what is spending it. */
.nav__item.has-menu:not(:has(~ .nav__item.has-menu)) > .nav__menu {
  left: auto;
  right: -0.75rem;
}

/* Set by Escape; lets the parent link keep focus with the menu shut. */
.has-menu.is-suppressed > .nav__menu {
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
}
.has-menu.is-suppressed > a::after { transform: translateY(-0.15em) rotate(45deg); }
.nav__menu li { margin: 0; }
.nav__menu a {
  display: flex;
  align-items: center;
  min-height: 44px;
  padding: 0.5rem 0.75rem;
  border-radius: 2px;
  font-size: 0.9rem;
  font-weight: 500;
  line-height: 1.35;
  color: var(--ink-soft);
  text-decoration: none;
}
.nav__menu a:hover { background: var(--paper-raised); color: var(--sea); }
.nav__menu a[aria-current="page"] {
  color: var(--sea);
  background: color-mix(in srgb, var(--clay) 8%, transparent);
  box-shadow: inset 2px 0 0 0 var(--clay);
}

/* Mobile nav.
   No hover here: the whole tree is laid out in the panel so every page in the
   site is one tap away. */
@media (max-width: 900px) {
  /* No-JS: the masthead stacks and the nav wraps onto its own row. */
  .masthead__inner { flex-wrap: wrap; padding-block: 0.85rem; }
  .nav { width: 100%; align-self: auto; }
  .nav__list { flex-direction: column; align-items: stretch; gap: 0; height: auto; }
  .nav__item { display: block; }

  .has-menu > a::after { display: none; }

  /* With no JS the panel can't collapse, so it sits open above the content on
     every page. Show the five top-level links only — the section pages and the
     footer still reach everything. (Desktop keeps its full CSS dropdowns.) */
  .no-js .nav__menu { display: none; }

  /* Submenus are always shown, indented under their parent. */
  .nav__menu {
    position: static;
    opacity: 1;
    visibility: visible;
    transform: none;
    min-width: 0;
    margin: 0 0 0.35rem 0.9rem;
    padding: 0;
    border: 0;
    border-left: 1px solid var(--line);
    border-radius: 0;
    background: none;
    box-shadow: none;
    transition: none;
  }
  .nav__menu a {
    min-height: 40px;
    padding: 0.42rem 0 0.42rem 0.9rem;
    font-size: 0.92rem;
    color: var(--muted);
  }
  .nav__menu a[aria-current="page"] { box-shadow: inset 2px 0 0 0 var(--clay); background: none; }

  .nav__list > .nav__item > a {
    padding: 0.7rem 0;
    font-size: 1rem;
    border-bottom: 0;
  }

  /* With JS: collapse the panel behind the Menu button. */
  .js .nav {
    display: none;
    position: absolute;
    inset-inline: 0;
    top: 100%;
    width: auto;
    background: var(--paper);
    border-bottom: 1px solid var(--line);
    padding: 0.5rem var(--gutter) 1.25rem;
    box-shadow: 0 18px 32px -24px rgba(0,0,0,.4);
    max-height: calc(100dvh - 4.35rem);
    overflow-y: auto;
  }
  .js .masthead__inner { flex-wrap: nowrap; padding-block: 0; }
  .js .nav.is-open { display: block; }
}

@media (min-width: 901px) {
  .js .nav-toggle { display: none; }
}

/* --------------------------------------------------------------------------
   5. Typographic components
   -------------------------------------------------------------------------- */

.eyebrow {
  display: block;
  font-family: var(--sans);
  font-size: var(--t-micro);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--clay);
  margin-bottom: 0.6rem;
}

/* An eyebrow is a kicker: it belongs to the heading directly beneath it.
   Because the eyebrow is the first child, the heading is not :first-child and
   so picked up its full 2.4em top margin — leaving the label stranded ~80px
   above its own heading, reading as though it belonged to the block before. */
.eyebrow + h1,
.eyebrow + h2,
.eyebrow + h3,
.eyebrow + h4 { margin-top: 0; }

.lede {
  font-size: var(--t-lede);
  line-height: 1.62;
  color: var(--ink-soft);
}

/* Short clay rule used as a quiet divider under headings */
.rule {
  width: 3rem;
  height: 2px;
  background: var(--clay);
  border: 0;
  margin: 1.75rem 0;
}

/* Scripture reference — never a link, always quiet.
   These must wrap: a long multi-reference string is easily wider than a phone,
   and an unwrappable one drags the whole grid column out with it. */
.ref {
  font-size: var(--t-small);
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.ref--block {
  display: block;
  margin-top: 0.4em;
}

/* Pull-quote for Scripture */
.quote {
  margin: 2.5rem 0;
  padding: 0.35rem 0 0.35rem 1.6rem;
  border-left: 2px solid var(--clay);
  font-family: var(--serif);
  font-size: clamp(1.15rem, 1.05rem + 0.5vw, 1.45rem);
  line-height: 1.55;
  color: var(--ink);
}
.quote p { margin-bottom: 0.9em; }
.quote cite {
  display: block;
  font-family: var(--sans);
  font-style: normal;
  font-size: var(--t-small);
  color: var(--muted);
  letter-spacing: 0.02em;
}

/* Apparatus note sitting in the prose rather than on a quote — used to say
   which translation a page quotes. Same sans/small treatment as .quote__note
   so the two read as the same kind of aside. */
.note {
  font-family: var(--sans);
  font-size: var(--t-small);
  line-height: 1.5;
  color: var(--muted);
}

/* Footnote link hanging off a quote — used where a rendering is Glenn's own
   translation and there are notes behind it. Sans and small so it reads as
   apparatus rather than as part of the quotation; the .arrow inside supplies
   the 44px tap target. */
.quote__note {
  margin: 0.55rem 0 0;
  font-family: var(--sans);
  font-size: var(--t-small);
  line-height: 1.5;
}

/* Footnote marker in the running text. Sourced pages carry a numbered note
   rather than an inline citation, so the argument keeps its line and the
   reference waits at the foot of the page. Scripture and classical references
   stay inline as .ref; these are for books.

   Raised by `top` rather than by the browser's own `vertical-align: super`,
   which grows the line box: a single marker would otherwise prise open one
   line in the middle of a paragraph, the same problem inline .greek avoids by
   keeping the paragraph's line-height. */
.fn {
  font-family: var(--sans);
  font-size: 0.7em;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  line-height: 0;
  position: relative;
  top: -0.45em;
  vertical-align: baseline;
}
.fn a {
  color: var(--clay);
  text-decoration: none;
  /* Padding, not margin: it widens the tap target without opening a gap the
     following punctuation would fall away from. */
  padding: 0 0.2em;
}
.fn a:hover { color: var(--clay-deep); text-decoration: underline; }

/* The notes themselves. Sans and small, like the rest of the apparatus, and
   numbered by a counter rather than by the <ol> marker so the digit can be
   clay and hang in the margin, matching the marker it answers to. */
.notes {
  list-style: none;
  counter-reset: note;
  /* Not `margin: 0`. This rule sits below the .mt-s utility in the file and at
     the same weight, so a blanket zero here silently won the cascade and the
     list ran flush into the paragraph introducing it. The gap belongs to the
     list either way, so it is set here and the utility is left to agree. */
  margin: var(--space-s) 0 0;
  padding: 0;
  max-width: var(--measure);
  font-family: var(--sans);
  font-size: var(--t-small);
  line-height: 1.62;
  color: var(--ink-soft);
}
.notes > li {
  counter-increment: note;
  position: relative;
  padding-left: 2.6rem;
  /* Was 1.05rem/16.8px. The longest notes are split into paragraphs, and the
     bare `p` rule gives them 1.25em, which inside .notes (14px) is 17.5px —
     *wider* than the old gap between notes, so one note ran into the next with
     no boundary left but the hanging numeral. The two gaps are set here as a
     pair: 24px between notes against 12.6px between paragraphs within one. */
  margin-bottom: 1.5rem;
}
.notes > li:last-child { margin-bottom: 0; }
.notes p { margin-bottom: 0.9em; }
/* The back-arrow must stay inside the final <p> of a split note. Left as a bare
   sibling it stops that <p> being :last-child, so the paragraph keeps its
   bottom margin and the arrow drops onto a line of its own. */
.notes > li::before {
  content: counter(note) ".";
  position: absolute;
  left: 0;
  top: 0;
  width: 2rem;
  text-align: right;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--clay);
}
/* Jumped to from the text: tint the one that was asked for, so the reader can
   tell which of thirteen they landed on. The tint is spread by a box-shadow
   rather than by padding, which would shift the hanging number out of line. */
.notes > li:target { background: var(--sea-tint); box-shadow: 0 0 0 0.5rem var(--sea-tint); }

/* Back to the marker. Quiet, and never the only way home — the browser's own
   back button already works, since the jump down was a link. */
.notes__back {
  color: var(--clay);
  text-decoration: none;
  padding: 0 0.35em;
  white-space: nowrap;
}
.notes__back:hover { color: var(--clay-deep); }

/* Greek. Neither self-hosted family carries it: the woff2 subsets in section 0
   stop at latin-ext, so every Greek glyph falls through to whatever the system
   has. Naming the fallbacks here picks faces with real POLYTONIC coverage —
   breathings, circumflexes, iota subscript — instead of letting the browser
   land on a monotonic face that drops half the accents into tofu. */
.greek {
  font-family: "Palatino Linotype", "Book Antiqua", Palatino, "Gentium Plus",
               "New Athena Unicode", Cambria, "Times New Roman", serif;
}
/* Block-level Greek only. Those accents sit above the cap line and touch the
   line above at the body's leading. Inline .greek deliberately keeps the
   paragraph's own line-height, or one Greek word would prise open a single
   line mid-paragraph. */
p.greek { line-height: 1.85; }

/* Pronunciation gloss following a Greek word. Quiet and small like .ref,
   because it is apparatus rather than argument, and set in the serif because
   that is the only family here with a REAL italic: Inter is self-hosted
   upright only, so var(--sans) in italic would be a synthesised slant. The
   macrons marking the long vowels sit in latin-ext, which is why this page is
   now the second one (with /contact/) to pull that subset. */
.translit {
  font-family: var(--serif);
  font-style: italic;
  font-size: var(--t-small);
  color: var(--muted);
}

/* In the glance table the gloss sits under its word rather than beside it.
   The Greek column is too narrow to hold both on one line, and once it is on
   a line of its own the brackets that fence it off from running prose have
   nothing left to fence it off from, so they go. */
.translit--block {
  display: block;
  margin-top: 0.15rem;
}

/* A quiet feature block — used for the Vision statement */
.feature {
  background: var(--sea);
  color: #F4F1EA;
  padding: clamp(2.5rem, 6vw, 4.5rem) 0;
}
.feature h2, .feature h3 { color: #FFFFFF; }
.feature .eyebrow { color: #E7B492; }
.feature .ref { color: rgba(244, 241, 234, .62); }
.feature a { color: #FFFFFF; text-decoration-color: rgba(255,255,255,.5); }
.feature a:hover { color: var(--sand); text-decoration-color: var(--sand); }
.feature__text {
  font-family: var(--serif);
  font-size: clamp(1.35rem, 1.1rem + 1.3vw, 2.1rem);
  line-height: 1.42;
  max-width: 24ch;
  /* A <p> that behaves as a heading, so it takes the heading's 0.6em rather
     than the paragraph 1.25em. The reference below it is a citation of this
     line and belongs close to it; on 1.25em of a clamped display size the gap
     grew with the viewport and read as a break. This is the same spacing the
     identical block gets under its <h2> on /about/. */
  margin-bottom: 0.6em;
}
@media (prefers-color-scheme: dark) {
  .feature { background: var(--sea-tint); color: var(--ink); border-block: 1px solid var(--line); }
  .feature h2, .feature h3 { color: var(--sea); }
  .feature .eyebrow { color: var(--clay); }
  .feature .ref { color: var(--muted); }
  .feature a { color: var(--sea); text-decoration-color: color-mix(in srgb, var(--sea) 40%, transparent); }
  .feature a:hover { color: var(--clay); text-decoration-color: var(--clay); }
}

/* --------------------------------------------------------------------------
   6. Buttons
   -------------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  background: var(--sea);
  color: var(--paper);
  font-family: var(--sans);
  font-size: 0.97rem;
  font-weight: 600;
  padding: 0.85rem 1.6rem;
  border: 1px solid var(--sea);
  border-radius: var(--radius);
  text-decoration: none;
  cursor: pointer;
  transition: background .15s ease, border-color .15s ease, transform .15s ease;
}
.btn:hover {
  background: var(--sea-deep);
  border-color: var(--sea-deep);
  color: var(--paper);
  transform: translateY(-1px);
}
@media (prefers-color-scheme: dark) {
  .btn { color: #0F1413; }
  .btn:hover { color: #0F1413; }
}

.btn--ghost {
  background: transparent;
  color: var(--sea);
  border-color: var(--line);
}
.btn--ghost:hover {
  background: transparent;
  color: var(--clay);
  border-color: var(--clay);
}

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.9rem;
  margin-top: 2rem;
}

/* Arrow link — the main "go deeper" affordance, so it gets a real target area.
   The underline is the ordinary one set on `a` above, so it follows the text.
   Two things it must not go back to:

   1. Drawing the line as an inset box-shadow. A shadow paints on the bottom
      edge of the *box*, and min-height makes that box 44px around 20px of
      text, so the line stranded ~13px below the words and read as a stray
      rule rather than as a link.
   2. Leaving the chevron as a flex item. A propagated text-decoration is
      painted by each flex item from its own baseline, and the chevron's
      1.15em font puts its line lower than the text's — two underlines at two
      heights. Taking it out of flow leaves one flex item, so one line.

   Out of flow also means the chevron is not underlined, which is why the
   padding is on the box: it reserves the chevron's column outside the text,
   and the line stops where the words do. */
.arrow {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding-right: 0.85em;
  font-weight: 500;
  /* Sits lower than the 0.18em every other link gets. This is the one link on
     a page that is meant to be spotted rather than read past, and the extra
     air also clears the descenders instead of the underline breaking around
     them. Measured from the baseline, so it scales with the context. */
  text-underline-offset: 0.45em;
}
.arrow::after {
  content: "\203A";
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  font-size: 1.15em;
  line-height: 1;
}

/* --------------------------------------------------------------------------
   7. Hero
   -------------------------------------------------------------------------- */

.hero {
  padding-block: clamp(2.5rem, 9vw, 7rem) clamp(2rem, 6vw, 4.5rem);
}
.hero h1 {
  font-size: var(--t-hero);
  margin-bottom: 0;
}
/* The 15ch cap squeezed the h1 into 288px of a 332px column on a phone and
   produced a badly ragged four-line break. Only cap it once there's room. */
@media (min-width: 640px) {
  .hero h1 { max-width: 15ch; }
}
.hero .lede {
  max-width: 46ch;
  margin-top: 1.6rem;
}

/* --------------------------------------------------------------------------
   8. Cards & grids
   -------------------------------------------------------------------------- */

.grid {
  display: grid;
  gap: 1.5rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15.5rem), 1fr));
}
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr)); }

.card {
  background: var(--paper-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.65rem 1.5rem;
}
.card h3 { margin-top: 0; margin-bottom: 0.55rem; font-size: 1.08rem; color: var(--sea); }
.card p { font-size: 0.965rem; color: var(--ink-soft); margin-bottom: 0; }

/* Doorway cards — clickable whole-card links */
.doorway {
  display: block;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.75rem 1.6rem;
  text-decoration: none;
  transition: border-color .16s ease, transform .16s ease, background .16s ease;
}
.doorway:hover {
  border-color: var(--sea);
  background: var(--paper-raised);
  transform: translateY(-2px);
}
.doorway h3 {
  margin: 0 0 0.5rem;
  font-size: 1.12rem;
  color: var(--sea);
}
.doorway h3::after { content: " \203A"; color: var(--clay); }
.doorway p { margin: 0; font-size: 0.95rem; color: var(--ink-soft); }

/* Homepage focus areas: names only. The full descriptions live on /about/, and
   having two differently-worded versions read as two competing explanations. */
.focuslist {
  list-style: none;
  counter-reset: fl;
  margin: 0;
  padding: 0;
  max-width: 40rem;
}
.focuslist li {
  counter-increment: fl;
  display: flex;
  align-items: baseline;
  gap: 1rem;
  padding: 0.85rem 0;
  margin: 0;
  border-top: 1px solid var(--line);
  font-family: var(--serif);
  font-size: clamp(1.05rem, 1rem + 0.35vw, 1.28rem);
  color: var(--sea);
}
.focuslist li:last-child { border-bottom: 1px solid var(--line); }
.focuslist li::before {
  content: counter(fl, decimal-leading-zero);
  flex: 0 0 auto;
  font-family: var(--sans);
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  color: var(--clay);
}

/* Numbered focus-area cards */
.numbered { counter-reset: n; }
.numbered .card { position: relative; padding-top: 3.1rem; }
.numbered .card::before {
  counter-increment: n;
  content: counter(n, decimal-leading-zero);
  position: absolute;
  top: 1.4rem;
  left: 1.5rem;
  font-family: var(--serif);
  font-size: 0.9rem;
  letter-spacing: 0.08em;
  color: var(--clay);
}

/* --------------------------------------------------------------------------
   9. Timeline (a typical Sunday)
   -------------------------------------------------------------------------- */

.timeline {
  list-style: none;
  margin: 2rem 0 0;
  padding: 0;
}
.timeline li {
  display: grid;
  grid-template-columns: 8.5rem 1fr;
  gap: 1.5rem;
  padding: 1.15rem 0;
  border-top: 1px solid var(--line);
  margin: 0;
}
.timeline li:last-child { border-bottom: 1px solid var(--line); }
/* .timelabel is used where the slot is a range — a <time> element can only
   carry a single datetime value, so a range gets a plain span. */
.timeline time,
.timeline .timelabel {
  font-family: var(--serif);
  font-size: 1rem;
  color: var(--clay);
  font-variant-numeric: tabular-nums;
  padding-top: 0.1em;
}
.timeline p { margin: 0; color: var(--ink-soft); }

@media (max-width: 560px) {
  .timeline li { grid-template-columns: 1fr; gap: 0.35rem; }
}

/* --------------------------------------------------------------------------
   10. Lists — commitments, steps, qualifications, glosses
   -------------------------------------------------------------------------- */

/* Tick list, used for the child-safety commitments */
.commitments {
  list-style: none;
  padding: 0;
  margin: 2rem 0 0;
}
.commitments li {
  position: relative;
  padding: 1rem 0 1rem 2.4rem;
  border-top: 1px solid var(--line);
  margin: 0;
}
.commitments li:last-child { border-bottom: 1px solid var(--line); }
.commitments li::before {
  content: "";
  position: absolute;
  left: 0.15rem;
  top: 1.45rem;
  width: 0.95rem;
  height: 0.5rem;
  border-left: 2px solid var(--clay);
  border-bottom: 2px solid var(--clay);
  transform: rotate(-45deg);
}

/* Numbered steps, used for Matthew 18 */
.steps {
  list-style: none;
  counter-reset: s;
  padding: 0;
  margin: 2rem 0 0 1.05rem;
}
.steps li {
  counter-increment: s;
  position: relative;
  padding: 0 0 1.75rem 3.4rem;
  margin: 0;
  border-left: 1px solid var(--line);
}
.steps li:last-child { border-left-color: transparent; padding-bottom: 0; }
.steps li::before {
  content: counter(s);
  position: absolute;
  left: -1.05rem;
  top: -0.15rem;
  width: 2.1rem;
  height: 2.1rem;
  display: grid;
  place-items: center;
  background: var(--paper);
  border: 1px solid var(--clay);
  border-radius: 50%;
  font-family: var(--serif);
  font-size: 0.92rem;
  color: var(--clay);
}

/* Qualification groups */
.qual {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.6rem 1.6rem 1.75rem;
  background: var(--paper-raised);
  margin-bottom: 1.25rem;
}
/* h2 too: the usage survey opens on a .qual box before its first section,
   so its label is the page's first heading after the h1 and has to be an h2
   for the outline to hold. It looks the same as every other .qual label. */
.qual > h3, .qual > h2 {
  margin: 0 0 0.35rem;
  font-family: var(--sans);
  font-size: var(--t-micro);
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--clay);
}
.qual > p { font-size: 0.95rem; color: var(--muted); margin-bottom: 1.2rem; }
.qual > p:last-child { margin-bottom: 0; }
.qual dl { margin: 0; }
.qual dt {
  font-weight: 600;
  color: var(--sea);
  margin-top: 1.05rem;
}
.qual dt:first-of-type { margin-top: 0; }
.qual dd {
  margin: 0.2rem 0 0;
  color: var(--ink-soft);
  font-size: 0.97rem;
}

/* Some entries in this group have no gloss in the charter. A <dl> rendered
   those as a visibly broken row, so this variant makes the description
   genuinely optional. */
.qual-list { list-style: none; margin: 0; padding: 0; }
.qual-list li { margin: 0 0 1.05rem; }
.qual-list li:last-child { margin-bottom: 0; }
.qual-list strong { color: var(--sea); font-weight: 600; }
.qual-list .ref { margin-left: 0.4rem; }
.qual-list p { margin: 0.2rem 0 0; color: var(--ink-soft); font-size: 0.97rem; }

/* Definition list used for elder authority, gifts, etc. */
.deflist { margin: 2rem 0 0; }
.deflist dt {
  font-family: var(--serif);
  font-size: 1.12rem;
  font-weight: 600;
  color: var(--sea);
  padding-top: 1.15rem;
  border-top: 1px solid var(--line);
  margin-top: 1.15rem;
}
.deflist dt:first-of-type { margin-top: 0; }
.deflist dd { margin: 0.45rem 0 0; color: var(--ink-soft); }
/* Closes a list with a rule under the last item, matching the dividers
   between them. */
.deflist--closed dd:last-of-type {
  padding-bottom: 1.15rem;
  border-bottom: 1px solid var(--line);
}

/* Gloss table — a Greek word beside the reason for the English chosen for it.
   The site's only <table>, and it earns the element: two columns of genuinely
   tabular data, so a header row with scope="col" is what a screen reader
   should hear. Rules sit between the rows and close under the last one, the
   same shape as .commands, so the two read as one family.

   Below 34rem the cells stack and the header row is hidden, because a fixed
   two-column grid on a 375px phone leaves the gloss about twelve characters
   wide. Nothing is lost by hiding the header there: with the Greek on top and
   the English under it, the columns label themselves. Stacking rather than
   scrolling sideways follows the same call made for .index-nav on mobile. */
.gloss {
  width: 100%;
  max-width: 52rem;
  margin: 1.75rem 0 0;
  border-collapse: collapse;
  font-size: 0.97rem;
}
.gloss th,
.gloss td {
  text-align: left;
  vertical-align: baseline;
  padding: 0.72rem 1.5rem 0.72rem 0;
  border-top: 1px solid var(--line);
}
.gloss th:last-child,
.gloss td:last-child { padding-right: 0; }
.gloss tbody tr:last-child td { border-bottom: 1px solid var(--line); }
.gloss thead th {
  border-top: 0;
  padding-top: 0;
  font-family: var(--sans);
  font-size: var(--t-micro);
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--clay);
}
/* Polytonic accents sit above the cap line, so the Greek column gets a little
   more leading than the gloss beside it. Same reason as p.greek. */
.gloss td:first-child { color: var(--sea); line-height: 1.7; }
.gloss td:last-child { color: var(--ink-soft); }
/* The same table led by a Scripture reference, with the Greek form beneath it
   (the short case on /leadership/elders/hebrews-13-17/). Teal there reads as a
   link, and references are never links on this site (see .ref). The Greek
   keeps the column's extra leading. */
.gloss.gloss--refs td:first-child { color: var(--ink); }
/* The Greek column runs to two lines now — the word, then how it sounds —
   while the rendering beside it is usually one. Baseline alignment hung that
   single line off the top of the row, level with the Greek and a line above
   its own centre, so the body cells are centred against each other instead.
   The header row sits on its rule. Where one label wraps (the short case's
   "The same Greek construction", on /leadership/elders/hebrews-13-17/),
   baseline hung the one-line labels level with its first line and left the
   second alone beneath them. Bottom alignment puts every label on one last line,
   right above its column. Where every label is one line, the two look the same. */
.gloss tbody td { vertical-align: middle; }
.gloss thead th { vertical-align: bottom; }

/* An entry ending in a table has already closed itself: .gloss draws a rule
   under its last row. The next entry's heading must not draw a second one a
   few dozen pixels below it — two parallel rules with a dead band between
   them read as one mistake, which is the same reason .theme carries no
   border-top under the command table above it. Only the line goes; the
   heading keeps its padding, so the space around the join matches every
   other section break on the page. Only an entry whose *last* child is the
   table: /leadership/elders/hebrews-13-17/ also carries one mid-entry, under
   "The two kinds of fence", and the heading after that entry keeps its rule. */
.entry:has(> .gloss:last-child) + .entry > h2 { border-top: 0; }

@media (max-width: 34rem) {
  .gloss, .gloss thead, .gloss tbody, .gloss tr, .gloss td { display: block; }
  /* Visually hidden, not display:none — the column labels still belong to the
     table for anyone listening to it. Same technique as .hp. */
  .gloss thead {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }
  .gloss tr {
    padding: 0.72rem 0;
    border-top: 1px solid var(--line);
  }
  .gloss tbody tr:last-child { border-bottom: 1px solid var(--line); }
  .gloss td { padding: 0; border-top: 0; }
  .gloss tbody tr:last-child td { border-bottom: 0; }
  .gloss td:first-child { margin-bottom: 0.2rem; }
}

/* The same table with more than two columns: a passage beside several
   versions' renderings of it, or an expositor beside the word kept and the
   sense given (both on /leadership/elders/hebrews-13-17/: the first in the
   short case, the second under "The two kinds of fence" in the full
   examination).
   The first column is a label, not Greek, so it takes ink; every column after
   it is a rendering, so all of them take the gloss colour, not only the last.

   It stacks at 48rem rather than 34rem: four columns at 34rem leave each about
   thirteen characters. Stacked, the columns no longer label themselves, so
   each cell after the first carries its column name as data-label and shows
   it, in the header's own style, before its text. The stacking rules repeat
   the two-column block above because a media query cannot share them. */
.gloss--grid td:first-child { color: var(--ink); }
.gloss--grid td + td { color: var(--ink-soft); }
/* A tag under the Greek for a row whose subject the reference alone does not
   give: James 3:3 is horses under a bit, and the rule the table shows turns on
   that. Quiet and small like .ref, because it is apparatus, not argument. */
.gloss__note {
  display: block;
  margin-top: 0.15rem;
  font-size: var(--t-small);
  color: var(--muted);
}

@media (max-width: 48rem) {
  .gloss--grid, .gloss--grid thead, .gloss--grid tbody, .gloss--grid tr, .gloss--grid td { display: block; }
  .gloss--grid thead {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }
  .gloss--grid tr {
    padding: 0.72rem 0;
    border-top: 1px solid var(--line);
  }
  .gloss--grid tbody tr:last-child { border-bottom: 1px solid var(--line); }
  .gloss--grid td { padding: 0; border-top: 0; }
  .gloss--grid tbody tr:last-child td { border-bottom: 0; }
  .gloss--grid td:first-child { margin-bottom: 0.2rem; }
  .gloss--grid td[data-label]::before {
    content: attr(data-label);
    margin-right: 0.6em;
    font-family: var(--sans);
    font-size: var(--t-micro);
    font-weight: 600;
    letter-spacing: 0.13em;
    text-transform: uppercase;
    color: var(--clay);
  }
}

/* --------------------------------------------------------------------------
   11. In-page index (sticky contents on long pages)
   -------------------------------------------------------------------------- */

.layout-index {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(2rem, 5vw, 4rem);
}
/* Grid items default to min-width:auto, which lets a long unbreakable string
   widen the column past the viewport. Opt out. */
.layout-index > * { min-width: 0; }
@media (min-width: 1000px) {
  .layout-index { grid-template-columns: 15rem minmax(0, 1fr); }
}

.index-nav { align-self: start; }
@media (min-width: 1000px) {
  .index-nav { position: sticky; top: 6.25rem; }
}
.index-nav h2 {
  font-family: var(--sans);
  font-size: var(--t-micro);
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--clay);
  margin: 0 0 0.9rem;
}
.index-nav ol {
  list-style: none;
  margin: 0;
  padding: 0;
  border-left: 1px solid var(--line);
}
.index-nav li { margin: 0; }
.index-nav a {
  display: flex;
  align-items: center;
  min-height: 44px;
  padding: 0.3rem 0 0.3rem 1rem;
  margin-left: -1px;
  border-left: 2px solid transparent;
  font-size: 0.9rem;
  color: var(--ink-soft);
  text-decoration: none;
  line-height: 1.45;
  /* A label that wraps would otherwise strand its last word on the second
     line; balance evens the two, as it does for headings. It still reaches the
     text on a flex container: the text sits in an anonymous block, which
     inherits it. */
  text-wrap: balance;
}
.index-nav a:hover { color: var(--sea); border-left-color: var(--sand); }
.index-nav a.is-active { color: var(--sea); border-left-color: var(--clay); font-weight: 500; }

/* Nested lists (the Hebrews 13:17 notes, and the usage survey). No second
   rule: the nested link's -1px margin puts its active bar on the parent's
   rule, so levels differ only by indent. Only the lists holding the current
   entry are open, gated on .js so scripts-off shows every level. Keeping every
   level open, with the sidebar capped and scrolling inside itself, was tried
   and reverted: the accordion read better. The Hebrews sidebar is capped again
   below, but only as a net for short screens; the accordion still does the
   work. */
.index-nav ol ol { border-left: 0; }
.index-nav ol ol a { padding-left: 2rem; font-size: 0.84rem; }
.js .index-nav li:not(:has(.is-active)) > ol { display: none; }

/* Numbered entries (the Hebrews short case) read as a list: a label that wraps
   hangs its second line under the words, not under the number. The number is
   a span of its own, so the link can set it in a column beside the words. A
   grid, where every other link is a flex row: align-content keeps the row
   centred in the 44px target, and align-items holds the number on the words'
   first line rather than halfway down two. Tabular figures make every number
   the same width, so the words start at one edge all the way down the list,
   and the gap is the width of the space the column replaces. The phone
   sheet's links are clones of these. */
.index-nav a:has(> .index-nav__num),
.pagenav__sheet a:has(> .index-nav__num) {
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: 0.28em;
  align-content: center;
  align-items: baseline;
}
.index-nav__num { font-variant-numeric: tabular-nums; }

/* Parts (hebrews-13-17). That page is a short case and then the full
   examination, and its index says so: each li.index-nav__part is a heading
   link to the part's start holding the part's own list, so the accordion
   above folds whichever part is not being read, and a › marks it. Beneath a
   part, articles and subsections look as they do on a two-level index.
   Desktop only: below 1000px the chips are the two parts alone. The page
   menu's sheet restates these in section 19. */
@media (min-width: 1000px) {
  .index-nav ol:has(> .index-nav__part) { border-left: 0; }
  .index-nav .index-nav__part + .index-nav__part { margin-top: 0.75rem; }
  /* A heading row. 32px, not 44: clear of the 24px minimum target, and it
     buys back most of the height the second heading costs. */
  .index-nav .index-nav__part > a {
    min-height: 2rem;
    padding-block: 0.2rem;
    padding-left: 0;
    margin-left: 0;
    border-left: 0;
    font-weight: 600;
    color: var(--ink);
  }
  .index-nav .index-nav__part > a:hover,
  .index-nav .index-nav__part > a.is-active { color: var(--sea); }
  .index-nav .index-nav__part > ol { border-left: 1px solid var(--line); }
  .index-nav .index-nav__part > ol > li > a { padding-left: 1rem; font-size: 0.9rem; }
  /* The folded part. The second value keeps the chevron out of the link's
     name where content alt text is supported; the first is the fallback. The
     link is a flex box, so the gap has to be a margin, not a space. */
  .js .index-nav:has(.is-active) .index-nav__part:not(:has(.is-active)) > a::after {
    content: "\203A";
    content: "\203A" / "";
    margin-left: 0.35em;
    color: var(--clay);
  }
  /* site.js is deferred, so until its first pass nothing is active and the
     accordion would fold both parts. Hold the first one open meanwhile. */
  .js .index-nav:not(:has(.is-active)) .index-nav__part:first-child > ol { display: block; }
}

/* Below the sticky breakpoint this list is a jump menu sitting between the
   reader and the first sentence — 400px of it on /beliefs/. Lay it out as
   wrapped chips instead so it costs a third of the height. Once the chips have
   scrolled under the masthead, the page menu in section 19 takes over. */
@media (max-width: 999px) {
  .index-nav ol {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    border-left: 0;
  }
  .index-nav a {
    min-height: 0;
    padding: 0.42rem 0.7rem;
    margin-left: 0;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    font-size: 0.82rem;
    line-height: 1.35;
  }
  .index-nav a:hover,
  .index-nav a.is-active {
    border-color: var(--clay);
    color: var(--sea);
  }
  /* Chips stay one level; the parent chip stands in when the spy has marked
     a child that is hidden here. */
  .index-nav ol ol { display: none; }
  .index-nav li:has(> ol .is-active) > a {
    border-color: var(--clay);
    color: var(--sea);
  }
}

/* On the One Anothers page the theme grid already does this job at the top,
   so the sidebar is desktop-only there. */
.index-nav--desktop { display: none; }
@media (min-width: 1000px) { .index-nav--desktop { display: block; } }

/* The Hebrews 13:17 notes: one grid holds both parts, so the sidebar is beside
   the short case from its first line and stays to the end of the notes. */
@media (max-width: 999px) {
  /* Other index pages get this air above their chips from their section's
     top padding; the grid gap gives it below. */
  .layout-index--parts { padding-top: var(--section); }
}
@media (min-width: 1000px) {
  .layout-index--parts .index-nav {
    /* Level with the short case's eyebrow: the band's 1px rule plus its top
       padding. A margin, not padding, so it is gone once the sidebar sticks. */
    margin-top: calc(var(--section) + 1px);
    /* A net under the accordion, as on the survey. In the longest article the
       open list is taller than a 768px laptop leaves under the sticky top, and
       a sticky box taller than that loses its last entries with no way to
       reach them. site.js keeps the current row in view. */
    max-height: calc(100vh - 7.75rem);
    overflow-y: auto;
    overscroll-behavior: contain;
  }
  /* The scrolling box would clip the sitewide ring, which sits 3px outside
     these full-width rows. Draw it inside. */
  .layout-index--parts .index-nav a:focus-visible { outline-offset: -2px; }
}
/* The short case keeps its full-width band while sitting in the grid's
   content column. The band is drawn as a border-image pushed out 100vmax each
   side: an outset border-image is ink overflow, so it adds no sideways scroll,
   and it needs no wrapper or pseudo-element. The image is three solid thirds,
   rule / fill / rule, sliced at the thirds, so every slice is one flat colour
   and the two 1px edges are drawn from a whole third each. A gradient with
   1px rules at its ends was tried first: stretched down a band 6,000px tall,
   the rules were never drawn, on screen or in print. The borders keep their
   1px width; the image only replaces how they are drawn.

   The band must stay unpositioned, and must not get a layer of its own (no
   position, z-index, transform, opacity, filter or clip-path): as it is, it
   paints before the sticky sidebar, and the sidebar sits on top of it. */
.layout-index--parts .section--tint {
  border-image:
    linear-gradient(var(--line) 0 33.3333%, var(--paper-raised) 0 66.6667%, var(--line) 0)
    33.3333% 0 fill / 1px 0 / 0 100vmax;
}
/* A jump to either part. The sitewide .section[id] offset below lands a part's
   top 192px down the screen, which leaves a strip of whatever precedes it in
   view: the page's opening above the short case, the band's last stretch behind
   the stuck sidebar above the full examination. Land the eyebrow level with
   the sidebar's heading instead — where the short case's eyebrow already sits
   when the page opens at the top — and the section's top, and the band's end,
   go under the masthead at every width. 6.25rem is the sidebar's sticky top,
   6rem the scroll-padding this adds to, and the section's top padding is what
   sits above the eyebrow. */
.layout-index--parts .section[id] {
  scroll-margin-top: calc(6.25rem - 6rem - var(--section));
}

/* Long-form article sections.
   The rule between entries is a separator, so it needs comparable air on both
   sides. Previously all the space sat below it and the line hugged the last
   line of the preceding paragraph, reading as an underline of the section that
   had just ended rather than the start of the next one. The margin above and
   the padding below are deliberately the same value. */
.entry { scroll-margin-top: 6rem; }
/* Subsection headings with an id (hebrews-13-17) land level with the entries.
   scroll-padding on html and scroll-margin here add up, so without this an h3
   would land 6rem higher than the article it sits in. */
.prose h3[id] { scroll-margin-top: 6rem; }
/* Sections with an id are jump targets too, from the charter's links into
   /about/, /giving/ and /restoration/. Same offset as an entry, or the heading
   lands under the sticky masthead. */
.section[id] { scroll-margin-top: 6rem; }
.entry + .entry { margin-top: clamp(2.25rem, 5vw, 3.25rem); }
.entry > h2 {
  margin-top: 0;
  padding-top: clamp(2.25rem, 5vw, 3.25rem);
  border-top: 1px solid var(--line);
}
.entry:first-child > h2 { padding-top: 0; border-top: 0; }

/* --------------------------------------------------------------------------
   12. One Anothers — eight themes, scoped accent colours
   -------------------------------------------------------------------------- */

/* The icon sprite at the top of the page is width/height 0; taking it out of
   flow stops it affecting layout at all. This was a style="position:absolute"
   attribute until the Content-Security-Policy landed — `style-src 'self'`
   blocks inline style attributes, and CSP hashes do not cover them (that needs
   'unsafe-hashes', which is not worth weakening the policy for one rule).
   Keep it a class. */
.icon-sprite { position: absolute; }

/* No border-top here: each theme ends with its command table, and that table's
   own bottom rule already closes the block. A border on the theme landed 1px
   below it and rendered as a single 2px line. The table edge is the divider;
   this padding is just the gap after it. */
.theme {
  --accent: var(--sea);
  scroll-margin-top: 6rem;
  padding-top: clamp(2.75rem, 6vw, 4rem);
}
.theme:first-of-type { padding-top: 0; }

/* Fallback accent for the map cards below. This has to be declared ABOVE the
   .theme--* block: both are single-class selectors, so source order decides, and
   a fallback sitting after them would override all eight colours with --sea. */
.thememap__card { --accent: var(--sea); }

.theme--love        { --accent: #B03A2E; }
.theme--unity       { --accent: #8A6A1C; }
.theme--service     { --accent: #4F6B3C; }
.theme--patience    { --accent: #2F6E6A; }
.theme--encourage   { --accent: #35577E; }
.theme--teaching    { --accent: #624570; }
.theme--hospitality { --accent: #9B611F; }
.theme--refrain     { --accent: #5F5C58; }

@media (prefers-color-scheme: dark) {
  .theme--love        { --accent: #E8897C; }
  .theme--unity       { --accent: #D6B65E; }
  .theme--service     { --accent: #9CC182; }
  .theme--patience    { --accent: #71C0B9; }
  .theme--encourage   { --accent: #8CB2DC; }
  .theme--teaching    { --accent: #B99BC7; }
  .theme--hospitality { --accent: #E5AC6E; }
  .theme--refrain     { --accent: #ABA69F; }
}

.theme__head {
  display: flex;
  align-items: flex-start;
  gap: 1.15rem;
  margin-bottom: 1.25rem;
}
.theme__icon {
  flex: 0 0 auto;
  width: 2.9rem;
  height: 2.9rem;
  display: grid;
  place-items: center;
  border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent);
  border-radius: 50%;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 8%, transparent);
}
.theme__icon svg { width: 1.5rem; height: 1.5rem; display: block; }
.theme__titles { min-width: 0; }
.theme__count {
  display: block;
  font-size: var(--t-micro);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 0.3rem;
}
.theme h2 { margin: 0; color: var(--ink); }

.theme__intro { max-width: var(--measure); color: var(--ink-soft); }

.theme .quote { border-left-color: var(--accent); }

.commands {
  list-style: none;
  padding: 0;
  margin: 1.75rem 0 0;
  max-width: 52rem;
}
.commands li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.35rem 1.5rem;
  padding: 0.72rem 0;
  border-top: 1px solid var(--line);
  margin: 0;
}
.commands li:last-child { border-bottom: 1px solid var(--line); }
.commands span:first-child { flex: 1 1 18rem; }

/* Theme map — the overview at the top of the One Anothers page. Same eight themes
   as the articles below, four commands each. Built from type and rules rather than
   an image so the text stays selectable, searchable and reflowable — and so the
   .theme--* accents and their dark-mode block above carry it with no new colours. */
.thememap {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  margin-top: 2.25rem;
  padding: 0;
  list-style: none;
}
/* 1000px is the .layout-index breakpoint; reusing it keeps this page to one
   desktop threshold. Four across matches the deck this came from. */
@media (min-width: 1000px) {
  .thememap { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

.thememap__card {
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: 1.05rem 1.1rem 1.15rem;
  background: var(--paper-raised);
  border: 1px solid var(--line);
  border-top: 3px solid var(--accent);
  border-radius: var(--radius);
  transition: border-color .16s ease, background .16s ease;
}
/* The whole card is not a link — an overlay would block selecting the commands,
   which is the point of showing them. Hover is an affordance; the title is the target. */
.thememap__card:hover,
.thememap__card:focus-within {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 5%, var(--paper-raised));
}

.thememap__count {
  margin: 0 0 0.45rem;
  font-size: var(--t-micro);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
}

.thememap__title {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin: 0 0 0.9rem;
  font-family: var(--serif);
  font-size: 1.05rem;
  line-height: 1.25;
}
.thememap__title a {
  color: var(--ink);
  text-decoration: none;
  padding-block: 0.35rem;        /* keeps the target at the 44px floor */
}
.thememap__title a::after { content: " \203A"; color: var(--accent); }
.thememap__title a:hover { color: var(--accent); }

.thememap__icon {                /* .theme__icon at overview scale */
  flex: 0 0 auto;
  width: 1.9rem;
  height: 1.9rem;
  display: grid;
  place-items: center;
  border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent);
  border-radius: 50%;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 8%, transparent);
}
.thememap__icon svg { width: 1.05rem; height: 1.05rem; display: block; }

/* One rule separates the head from the list, and none between the lines — at this
   density a rule per row reads as hatching rather than as structure. */
.thememap__list {
  margin: 0;
  padding: 0.85rem 0 0;
  border-top: 1px solid var(--line);
  list-style: none;
}
.thememap__list li {
  margin: 0 0 0.7rem;
  font-size: 0.9rem;
  line-height: 1.45;
  color: var(--ink-soft);
}
.thememap__list li:last-child { margin-bottom: 0; }
.thememap__list .ref { display: block; }

/* Below 560px the map keeps its 4x2 shape and drops to title tiles. Eight full
   cards stacked would be four screens of scrolling before the first theme, at
   which point it has stopped being an overview. The commands are one tap away. */
@media (max-width: 560px) {
  .thememap__list { display: none; }
  .thememap__card { padding: 0.9rem 0.95rem 1rem; }
  /* The icon sits above the title rather than beside it. In a row it leaves the
     text about 87px of a 160px tile, which is narrower than the word
     "Encouragement" — one word, nothing to wrap at, so it ran past the border.
     Stacked, the title gets the full tile and the longest titles drop from three
     lines to two. */
  .thememap__title {
    display: block;
    margin-bottom: 0;
    font-size: 0.98rem;
  }
  .thememap__icon { margin-bottom: 0.55rem; }
  /* "Encouragement" is one word and wider than a tile even stacked, so there is
     nowhere to wrap and it ran past the border. Shortening the word beats
     breaking it: the tile reads "Encourage", the full word stays everywhere
     else. See .thememap__tail in the page markup. */
  .thememap__tail { display: none; }
}

/* --------------------------------------------------------------------------
   13. Forms
   -------------------------------------------------------------------------- */

/* Contact layout. On a phone the reassurance panels come first: someone deciding
   whether to contact a church that meets in private homes wants "what happens
   next" and "why there's no address" before they're asked for their name. */
.contact-layout {
  display: grid;
  align-items: start;
  gap: clamp(2rem, 5vw, 4rem);
  grid-template-columns: 1fr;
}
.contact-layout__aside { order: 1; }
.contact-layout__form  { order: 2; }
@media (min-width: 860px) {
  .contact-layout { grid-template-columns: 1fr 1fr; }
  .contact-layout__aside { order: 2; }
  .contact-layout__form  { order: 1; }
}

.form { max-width: 34rem; margin-top: 2.25rem; }

.field { margin-bottom: 1.35rem; }
.field label {
  display: block;
  font-size: 0.93rem;
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 0.4rem;
}
.field .hint {
  display: block;
  font-weight: 400;
  font-size: var(--t-small);
  color: var(--muted);
  margin-top: 0.15rem;
}
.field input,
.field textarea {
  width: 100%;
  font: inherit;
  font-size: 1rem;
  color: var(--ink);
  background: var(--paper-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0.7rem 0.85rem;
}
.field input:focus,
.field textarea:focus {
  outline: 2px solid var(--focus);
  outline-offset: 1px;
  border-color: transparent;
}
.field textarea { min-height: 9rem; resize: vertical; }
.field input:user-invalid,
.field textarea:user-invalid { border-color: #B03A2E; }

.req { color: var(--clay); font-weight: 400; }

/* Honeypot — visually hidden but not display:none, so bots still fill it */
.hp {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.form-note {
  font-size: var(--t-small);
  color: var(--muted);
  margin-top: 1.25rem;
  max-width: 34rem;
}
/* Required-field legend, shown above the fields rather than after the button. */
.form-legend {
  font-size: var(--t-small);
  color: var(--muted);
  margin: 0 0 1.5rem;
}

.callout {
  border: 1px solid var(--line);
  border-left: 2px solid var(--clay);
  background: var(--paper-raised);
  border-radius: var(--radius);
  padding: 1.4rem 1.5rem;
  margin: 2rem 0;
}
.callout h3 { margin-top: 0; font-size: 1.05rem; color: var(--sea); }
.callout > :last-child { margin-bottom: 0; }

/* --------------------------------------------------------------------------
   14. Charter hub index
   -------------------------------------------------------------------------- */

.hub { margin-top: 2.5rem; }
.hub__item {
  padding: 1.6rem 0;
  border-top: 1px solid var(--line);
  display: grid;
  gap: 0.4rem 2rem;
}
.hub__item:last-child { border-bottom: 1px solid var(--line); }
@media (min-width: 800px) {
  .hub__item { grid-template-columns: 15rem minmax(0, 1fr); }
}
.hub__item h3 { margin: 0; font-size: 1.1rem; color: var(--sea); }
.hub__item h3 a { text-decoration: none; }
.hub__item h3 a:hover { text-decoration: underline; }
.hub__item p { margin: 0; color: var(--ink-soft); font-size: 0.97rem; }
.hub__item ul {
  margin: 0.6rem 0 0;
  padding: 0;
  list-style: none;
  font-size: var(--t-small);
  color: var(--muted);
  columns: 2;
  column-gap: 2rem;
}
.hub__item ul li { margin-bottom: 0.25rem; break-inside: avoid; }
/* Each list item links into that page's section. Left undecorated, like the
   heading link above it, because ten cards of these underlined at once reads
   as a wall of rules rather than a contents list. */
.hub__item ul a { color: inherit; text-decoration: none; }
.hub__item ul a:hover { color: var(--sea); text-decoration: underline; }
@media (max-width: 560px) { .hub__item ul { columns: 1; } }

/* --------------------------------------------------------------------------
   15. Page header & prev/next
   -------------------------------------------------------------------------- */

.pagehead {
  padding-block: clamp(2.75rem, 7vw, 4.75rem) clamp(1.75rem, 4vw, 2.75rem);
  border-bottom: 1px solid var(--line);
}
.pagehead h1 { max-width: 20ch; margin-bottom: 0; }
.pagehead .lede { max-width: 52ch; margin-top: 1.35rem; }

/* Breadcrumbs are a <nav><ol>, not a <p>, so the trail Google is told about in
   BreadcrumbList JSON-LD is the same trail that's actually in the markup. The
   list is flattened back to a line of text — the semantics are for machines and
   screen readers, not something to look at. */
.crumbs {
  font-size: var(--t-small);
  color: var(--muted);
  margin-bottom: 1.1rem;
}
.crumbs ol {
  list-style: none;
  margin: 0;
  padding: 0;
}
.crumbs li { display: inline; }
.crumbs a {
  display: inline-block;
  padding-block: 0.5rem;
  color: var(--muted);
  text-decoration-color: color-mix(in srgb, var(--muted) 40%, transparent);
}
.crumbs a:hover { color: var(--clay); }
.crumbs span { padding-inline: 0.45rem; }

/* The closing row: two links onward, and nothing else. Contact used to sit here
   as a third, clay-tinted card on every page, and before that as a full-width
   CTA band. Both are gone. The site informs rather than recruits, so contact
   lives in the masthead and footer, where anyone who wants it will find it, and
   not in the body of a page. Two deliberate exceptions carry a contact link in
   the body: /privacy/, which should name a way to reach whoever holds your
   data, and /404.html, where the reader has hit a dead end. Don't add a third
   card here that asks for anything. */
.nextprev {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  margin-top: var(--section);
  padding-top: 2.5rem;
  border-top: 1px solid var(--line);
}

/* When the row is a section's only content, that section's own padding already
   supplies the space above it — the margin on top of it doubles the gap and
   leaves the rule floating in a void at the foot of the page. */
.section > .nextprev:only-child { margin-top: 0; }
.nextprev a {
  display: block;
  padding: 1.15rem 1.3rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  text-decoration: none;
  transition: border-color .16s ease;
}
.nextprev a:hover { border-color: var(--sea); }
.nextprev .eyebrow { margin-bottom: 0.35rem; }
.nextprev strong {
  display: block;
  font-family: var(--serif);
  font-size: 1.08rem;
  font-weight: 600;
  color: var(--sea);
}

.backtotop {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  gap: 0.4rem;
  font-size: var(--t-small);
  color: var(--muted);
  text-decoration: none;
}
.backtotop::before { content: "\2191"; }
.backtotop:hover { color: var(--clay); }

/* Floating back-to-top, mobile only — the site's first position:fixed element.
   It is a JavaScript-only control by nature: it has to know how far down the
   page we are to know whether it should exist at all. So it follows the
   .nav-toggle pattern — display:none, shown only under .js — rather than
   sitting in the markup doing nothing. The treatment is deliberately
   .nav-toggle's, hairline on --paper at --radius, so it reads as the same
   family of control as the Menu button and not as a floating app button.
   .backtotop above is its inline sibling at the foot of /one-anothers/; that
   one works with JavaScript off and stays. */
.totop { display: none; }

/* The declarations sit outside the media query and only `display` is gated,
   so the one page that needs this control at every width can switch it on
   without restating twenty-five properties. That page is the usage survey:
   130 screens on a desktop, and between 901px and 999px it had no wayfinding
   at all — too wide for this button, too narrow for the sticky index, which
   starts at 1000px. */
.js .totop {
  place-items: center;
  position: fixed;
  /* .wrap is padding-inline: var(--gutter), so this lands the button's right
     edge on the text column's right edge rather than floating loose. */
  right: var(--gutter);
  bottom: 1.25rem;
  /* Under the masthead (50) and the nav panel inside it (60), so an open menu
     covers the button instead of the button floating over the navigation. */
  z-index: 40;
  width: 44px;
  height: 44px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--muted);
  /* Inter, not the body serif: its latin subset is the one whose
     unicode-range carries U+2191 (section 0). */
  font-family: var(--sans);
  font-size: 1.05rem;
  line-height: 1;
  text-decoration: none;
  /* visibility rather than display, so it leaves the tab order while hidden
     and still gets a fade on the way out. Under prefers-reduced-motion the
     blanket transition-duration override in section 2 removes the fade. */
  opacity: 0;
  visibility: hidden;
  transform: translateY(4px);
  transition: opacity .18s ease, transform .18s ease, visibility .18s ease;
}
.totop::before { content: "\2191"; }
.js .totop.is-shown { opacity: 1; visibility: visible; transform: none; }
.totop:hover,
.totop:active { color: var(--clay); border-color: var(--clay); }

/* Mobile everywhere; every width on the usage survey. */
@media (max-width: 900px) {
  .js .totop { display: grid; }
}
html.js:has(.appendix) .totop { display: grid; }

/* Where site.js has built the page menu (section 19) its bar carries the
   arrow, so the loose button goes. Same specificity as the survey rule above,
   (0,3,1), and later, which is what wins — move it above and the survey keeps
   both. Scoped to the menu's own breakpoint: from 1000px the survey still
   wants this button at every width. */
@media (max-width: 999px) {
  html.js.has-pagenav .totop { display: none; }
}

/* --------------------------------------------------------------------------
   16. Footer
   -------------------------------------------------------------------------- */

.site-footer {
  border-top: 1px solid var(--line);
  padding-block: clamp(2.75rem, 6vw, 4rem) 2.25rem;
  font-size: 0.93rem;
}
.site-footer__grid {
  display: grid;
  gap: 2.25rem;
  /* 11rem, not 12rem: at the widest wrap there are five cells (the wordmark
     plus four link columns), and 12rem fits only four — which dropped the last
     column onto a row of its own with three empty cells beside it. */
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr));
}
.site-footer h2 {
  font-family: var(--sans);
  font-size: var(--t-micro);
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--clay);
  margin: 0 0 0.9rem;
}
.site-footer ul { list-style: none; margin: 0; padding: 0; }
.site-footer li { margin-bottom: 0; }
/* Footer links were 18px tall — under the WCAG 2.2 target-size floor once
   spacing is accounted for. */
.site-footer a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--ink-soft);
  text-decoration: none;
}
.site-footer a:hover { color: var(--clay); text-decoration: underline; }
/* Two overrides, both load-bearing.

   `white-space: normal` — the masthead wordmark is `nowrap`; the footer one
   must not be. At five cells of ~11rem, 20 characters of letter-spaced
   uppercase serif overflow the cell by 35px and the wordmark ends up touching
   the next column. Five cells is the footer today.

   `display: block` + `min-height: 0` — opting out of the 44px tap target that
   `.wordmark` and `.site-footer a` both set. That floor is for the link lists.
   Applied here it centres the wordmark inside a 44px box, which drops it 12.6px
   below the three column headings level with it, and pushes the blurb 16px
   below the first link in each list. That was the footer's "not quite aligned"
   look on desktop. It was milder rather than absent on mobile: at two columns
   the wordmark wraps to two lines and nearly fills the 44px box, so the
   centring offset falls from 12.6px to 3.2px. WCAG 2.2 target size is met by the masthead
   wordmark — same href, same page, 229x44 — under the equivalent-control
   exception.

   `width: fit-content` keeps the click area on the words rather than spanning
   the whole cell, without the inline-block line box, whose strut is taller than
   the wordmark and would push it back down. Browsers without it fall back to
   full-cell width, which is harmless. */
.site-footer .wordmark {
  display: block;
  width: fit-content;
  min-height: 0;
  font-size: 0.98rem;
  white-space: normal;
}
/* 1.2rem, not 0.85rem. A link column puts its first link's *text* 38.3px below
   the cell top — a 14.7px heading, 0.9rem of margin, then the centring inside
   the 44px row. The wordmark's line box is 18.8px, so 1.2rem lands the blurb's
   first line on that same line instead of 16px under it. Measured, not derived:
   the arithmetic misses by 3px because the heading and the links are set at
   different sizes. */
.site-footer__blurb { color: var(--muted); margin-top: 1.2rem; max-width: 26ch; font-size: 0.9rem; }

.colophon {
  margin-top: 2.75rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
  justify-content: space-between;
  /* The Privacy link inherits the footer's 44px tap target, so its box is
     taller than the plain text beside it. Centring the row puts all three
     on the same baseline; stretching drops "Privacy" 10px. */
  align-items: center;
  color: var(--muted);
  font-size: var(--t-small);
}
.colophon p { margin: 0; }

/* --------------------------------------------------------------------------
   17. Video list — click-to-play
   --------------------------------------------------------------------------
   The only third-party embeds on the site. Each video renders as an ordinary
   link to YouTube; site.js swaps in the iframe on click. That is why there is
   no thumbnail here, and no <img> anywhere — nothing is requested from Google
   until a reader presses play, and img-src in public/_headers stays 'self' to
   keep it that way. Counters rather than hand-written numbers, so reordering
   the list cannot desynchronise them.

   Two presentations of the same markup: the default numbered rows, used for
   the thirteen on /resources/leadership-series/, and --poster below. */

.video-list {
  list-style: none;
  counter-reset: v;
  margin: 0;
  padding: 0;
  max-width: 52rem;
}

.video {
  counter-increment: v;
  display: flex;
  align-items: flex-start;
  gap: 1rem;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--line);
}
.video:last-child { border-bottom: 1px solid var(--line); }

.video::before {
  content: counter(v, decimal-leading-zero);
  flex: 0 0 auto;
  padding-top: 1.15rem;
  font-family: var(--sans);
  font-size: var(--t-micro);
  letter-spacing: 0.08em;
  color: var(--clay);
}

/* The hover mirrors .doorway, but lifts to --paper because this list sits on a
   tinted band where --paper-raised is already the ground. */
.video__link {
  flex: 1 1 auto;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.3rem 1rem;
  padding: 0.9rem 0.9rem 0.9rem 0;
  border: 1px solid transparent;
  border-radius: var(--radius);
  text-decoration: none;
  transition: border-color .16s ease, background .16s ease;
}
.video__link:hover {
  border-color: var(--sea);
  background: var(--paper);
}

.video__title {
  font-family: var(--serif);
  font-size: clamp(1.05rem, 1rem + 0.35vw, 1.28rem);
  color: var(--sea);
}
.video__title::after { content: " \25B8"; color: var(--clay); }

.video__who {
  margin-left: auto;
  font-family: var(--sans);
  font-size: var(--t-micro);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Where a class was left, written in by site.js from what the player itself
   last reported. It only ever appears on a class that has been started, and
   it is what stops a resumed class reading as one that opened in the wrong
   place. --clay rather than --muted so it reads as a state, not a byline. */
.video__resume {
  font-family: var(--sans);
  font-size: var(--t-micro);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--clay);
}

/* What replaces a link once a class has been activated: a bar naming what is
   open and offering the way out, then the frame. Closing swaps the link back
   in, so this and .video__link occupy the same slot in the row and carry the
   same margins. On a poster list the bar is not built at all — see below — and
   the player is the frame alone. */
.video__player {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0.9rem 0.9rem 0.9rem 0;
}

.video__bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 1rem;
  margin-bottom: 0.6rem;
}

.video__playing {
  font-family: var(--serif);
  font-size: clamp(1.05rem, 1rem + 0.35vw, 1.28rem);
  color: var(--sea);
}

.video__close {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0.4rem 0.9rem;
  background: none;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--t-micro);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  cursor: pointer;
  transition: border-color .16s ease, color .16s ease;
}
.video__close:hover { border-color: var(--sea); color: var(--sea); }

/* The slot the player expands into. */
.video__frame {
  aspect-ratio: 16 / 9;
  background: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}
.video__frame iframe {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

/* -- .video-list--poster: one video, shown as a player ---------------------
   A single video reads as a lone row of a list that isn't there. This gives it
   the shape of the thing it becomes: a 16:9 panel the size of the player, with
   the title and channel sitting in it.

   The play button is drawn — a ring and a triangle from two pseudo-elements —
   rather than laid over a YouTube thumbnail. Fetching the thumbnail would mean
   widening img-src to i.ytimg.com, which tells Google about every visit to the
   page whether or not anyone presses play. That is the whole thing the
   click-to-play exists to prevent, and it would be given away by a picture.

   Built on --sea-tint rather than --ink: --ink inverts with the colour scheme,
   so a panel using it goes near-white in dark mode.

   This class is also what site.js reads to decide the player needs no bar and
   no Close. A single video has no list to return to, so pressing play swaps
   the poster for the frame and that is the end of it. */

.video-list--poster .video {
  display: block;
  border-top: 0;
}
.video-list--poster .video:last-child { border-bottom: 0; }
.video-list--poster .video::before { content: none; }

.video-list--poster .video__link {
  position: relative;
  flex-direction: column;
  flex-wrap: nowrap;
  align-items: flex-start;
  justify-content: flex-end;
  gap: 0.2rem;
  aspect-ratio: 16 / 9;
  padding: clamp(1rem, 3vw, 1.6rem);
  background: var(--sea-tint);
  border-color: var(--line);
}

/* The ring. Centred with a negative margin rather than a transform, so the
   whole-page transition-duration override in section 2 has nothing to undo. */
.video-list--poster .video__link::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 4.25rem;
  height: 4.25rem;
  margin: -2.125rem 0 0 -2.125rem;
  border: 1px solid var(--sea);
  border-radius: 50%;
  transition: background .16s ease;
}

/* The triangle, offset right of true centre so it looks centred in the ring. */
.video-list--poster .video__link::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  margin: -0.6rem 0 0 -0.4rem;
  border-style: solid;
  border-width: 0.6rem 0 0.6rem 1rem;
  border-color: transparent transparent transparent var(--sea);
  transition: border-color .16s ease;
}

/* Cancels the row version's lift to --paper: repainting a whole 16:9 panel on
   hover is a lot of movement for "this is a link". The ring filling says it. */
.video-list--poster .video__link:hover { background: var(--sea-tint); }
.video-list--poster .video__link:hover::before { background: var(--sea); }
.video-list--poster .video__link:hover::after { border-left-color: var(--paper-raised); }

/* The chevron after the title is what says "this opens" in the numbered list.
   Here the play button says it, and two of them is one too many. */
.video-list--poster .video__title::after { content: none; }

/* Both of these undo row-layout rules that mean something else in a column.
   `margin-left: auto` pushed the channel to the right-hand end of a row; here
   it would pin it to the right edge. `flex-basis: 100%` in the narrow-screen
   rule below made it a full-width second line; on a column the basis is the
   *height*, so it became a full-height block that shoved the title off the
   bottom of the poster and up against the top. */
.video-list--poster .video__who { margin-left: 0; flex-basis: auto; }

/* The row version insets the player to match the link it replaces. There is no
   inset to match here — the poster is already the full width of the list. */
.video-list--poster .video__player { margin: 0; }

@media (max-width: 33rem) {
  /* The teacher's name stops being a right-hand column and becomes a second line. */
  .video__who { margin-left: 0; flex-basis: 100%; }
}

/* --------------------------------------------------------------------------
   18. Data appendix — the Hebrews 13:17 usage survey
   --------------------------------------------------------------------------
   One page uses everything below: /leadership/elders/hebrews-13-17/appendix/,
   which prints every search hit behind the counts on the translation notes.
   It is the only page on the site carrying <blockquote>, <code>, or a table of
   seven columns, so all three are scoped to .appendix rather than added to the
   global type scale, where nothing else would ever use them.

   Two of the columns in those tables record a judgement — which word stood in
   the dative, and whether the setting was counsel or command — and the page
   says they are offered for correction. That is why site.js gives the tables a
   filter and sortable headers: a reader who wants to re-check one class of hit
   should be able to gather them in a few seconds rather than by scrolling. The
   controls are injected, so with JavaScript off the tables are still whole. */

/* html carries scroll-padding-top: 6rem so an anchor jump clears the sticky
   masthead. This page stacks a second sticky element under it, the filter, so
   a jump that cleared only the masthead would land the heading behind the
   filter bar. The extra is the stuck bar's height. */
html:has(.appendix) { scroll-padding-top: 10.5rem; }
/* .entry carries scroll-margin-top: 6rem for the rest of the site, and on this
   page it added to the scroll-padding above: a section heading landed 264px
   down, 147px of it dead air, while an h3 landed flush at 168px. The padding
   alone is right here, because here there are two sticky bars. */
.appendix .entry,
.appendix .prose h3[id],
.appendix .prose h4[id] { scroll-margin-top: 0; }

/* --wrap is 1120px everywhere, which is right for a 68ch measure and wrong for
   a seven-column table: minus the 15rem index and the gap it leaves a 736px
   content column, at 1440, at 1920 and at 2560 alike. The tables wanted 917 to
   1425px, so every one of the twenty-six scrolled sideways at every desktop
   width, with Setting and Note off the right edge. This page alone gets room;
   .prose still holds the running text to its own measure, so only the tables
   take the extra. */
.section.appendix { max-width: 87.5rem; }

/* And the in-page index sticks below both of them rather than behind the
   filter. 6.25rem elsewhere; here that is 42px inside the stuck bar.

   It also has to be able to run out of room. Fourteen sections with the
   classical corpus's nine word-forms open is taller than a laptop viewport,
   and a sticky box taller than the space it is given simply loses its last
   entries off the bottom with no way to reach them. */
@media (min-width: 1000px) {
  .appendix .index-nav {
    top: 10rem;
    max-height: calc(100vh - 11.5rem);
    overflow-y: auto;
    overscroll-behavior: contain;
  }
}

/* How big a section is, so a reader knows what a click costs: "The classical
   corpus / 524 hits" against "Philo / 10 hits". */
.index-nav__count {
  display: block;
  font-family: var(--sans);
  font-size: var(--t-micro);
  color: var(--muted);
}
@media (max-width: 999px) {
  /* On the chips it would double their height for a number nobody is choosing
     between at that size. */
  .index-nav__count { display: none; }
}
/* Under the entry's name, not beside it. The links are flex rows for their
   44px targets, and a flex row sets a display:block child alongside the text,
   so the count sat jammed against the name, or as a narrow second column where
   the name wrapped. Stacking the link keeps the target and puts the count on a
   line of its own. The phone sheet's links are the same flex rows. */
.index-nav a:has(> .index-nav__count),
.pagenav__sheet a:has(> .index-nav__count) {
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
}

/* Long prose quotations — the public-domain commentators, quoted at length.
   Deliberately not .quote: that is a Scripture pull-quote at display size, and
   a page of Chrysostom set in it would be unreadable. */
.appendix blockquote {
  margin: 1.4rem 0;
  padding: 0.15rem 0 0.15rem 1.25rem;
  border-left: 2px solid var(--line);
  color: var(--ink-soft);
  font-size: 0.97rem;
}
.appendix blockquote p { margin-bottom: 0.8em; }
.appendix blockquote p:last-child { margin-bottom: 0; }

/* Search strings, morphology codes and Internet Archive item ids: strings a
   reader may want to copy character for character. A mono face and a tint
   rather than a size change, which would break the line's rhythm. */
.appendix code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.88em;
  background: var(--paper-raised);
  border-radius: 3px;
  padding: 0.1em 0.32em;
  overflow-wrap: anywhere;
}

/* The survey tables. Up to seven columns, one of them a whole Greek clause, so
   they ignore .gloss's 52rem measure and stack far later than .gloss--grid:
   64rem rather than 48rem, because seven columns on a tablet leave each about
   nine characters. Above that they sit in .table-scroll. */
.gloss--data {
  max-width: none;
  font-size: 0.88rem;
}
.gloss--data th,
.gloss--data td { padding: 0.62rem 1rem 0.62rem 0; }
/* Baseline centring is right for a two-line Greek gloss beside a one-line
   rendering (see .gloss above). Here a cell can run to six lines beside a
   one-word classification, and centring floats that word in mid-air. */
.gloss--data tbody td { vertical-align: top; }
/* Their header labels stay on baseline, level with the top-aligned rows. */
.gloss--data thead th { vertical-align: baseline; }
.gloss--data td:first-child { color: var(--ink); line-height: 1.5; }
.gloss--data td + td { color: var(--ink-soft); }

/* A survey row is a quotation with a classification on it, not seven equal
   fields. Read as seven columns at the width this page can give them, the Greek
   clause got 205px and wrapped to eight lines while four one-word judgements
   held 489px between them, and the row stood 190px tall. The clause and its
   English gloss are one cell now, and the judgements are chips in another, so
   the reading matter gets the room and the row is about half as deep. */
/* Column widths belong to the table layout only. Below 64rem every cell is
   display:block, and a percentage there is a percentage of the screen: it held
   the Greek to 195px and drove the phone document from 285 screens to 420. */
@media (min-width: 64.01rem) {
  .gloss--data td:first-child { width: 8rem; }
  .gloss--data td[data-label="Text"] { width: 52%; }
  .gloss--data td[data-label="Note"] { width: 16%; }
}
.gloss--data td[data-label="Text"] .greek { display: block; }
.rowgloss {
  display: block;
  margin-top: 0.3rem;
  color: var(--ink-soft);
  font-size: 0.95em;
}
/* The chips wrap in a column so the eye reads down one kind of judgement at a
   time; each is its own word, so they must not run together into a sentence. */
.gloss--data td[data-label="Classification"] { line-height: 1.45; }
@media (min-width: 64.01rem) {
  .gloss--data td[data-label="Classification"] { width: 11rem; }
}
.chip {
  display: block;
  margin-bottom: 0.2rem;
  font-family: var(--sans);
  font-size: var(--t-micro);
  color: var(--ink-soft);
}
.chip:last-child { margin-bottom: 0; }

/* Stacked, the row is already one field per line, so three judgements on three
   more lines is three lines spent on six words. They run together on one. */
@media (max-width: 64rem) {
  .chip {
    display: inline;
    margin-bottom: 0;
  }
  .chip + .chip::before {
    content: " · ";
    color: var(--muted);
  }
}
.chip--dative { color: var(--ink); font-weight: 600; }
.chip--setting { color: var(--clay-deep); }

/* The same join .entry:has(> .gloss) + .entry > h2 already handles, one level
   deeper: an entry that ends in a scrolled table still closes itself with the
   table's own bottom rule, so the next section's heading must not draw a
   second one under it. The wrapper is what hides the table from that rule. */
.entry:has(> .table-scroll) + .entry > h2,
.entry:has(> .gloss--data:last-child) + .entry > h2 { border-top: 0; }

/* A table wider than its column scrolls rather than crushing. It is focusable
   and labelled, so it can be scrolled from the keyboard and is announced as
   what it is; that is the whole reason for the wrapper. */
.table-scroll {
  overflow-x: auto;
  margin-top: 1.75rem;
}
.table-scroll > .gloss { margin-top: 0; }

/* The longest table runs to 138 rows, so its headings are gone after one
   screen. They stick under the masthead and the stuck filter bar, which is the
   same 10.5rem that html:has(.appendix) uses for anchor landings. Only above
   the stacking breakpoint: below it the head is visually hidden anyway. */
@media (min-width: 64.01rem) {
  .gloss--data thead th {
    position: sticky;
    top: 9.4rem;
    z-index: 1;
    background: var(--paper);
    padding-top: 0.5rem;
    box-shadow: inset 0 -1px 0 var(--line);
  }
}
.table-scroll:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
}
/* There is no width floor any more. It was wrong in both directions: it forced
   a scrollbar onto the nine tables whose natural width is 74 to 727px — the
   Josephus string counts are 74px wide — while still not giving the wide ones
   enough. With the rows restructured, twenty-five of the twenty-six fit the
   narrowest desktop column and have left .table-scroll altogether; the
   commentaries comparison, at 720px of min-content, is the one that keeps it. */

/* Stacked. The rules repeat .gloss--grid's block because a media query cannot
   share them — the same reason given there. */
@media (max-width: 64rem) {
  .gloss--data,
  .gloss--data thead,
  .gloss--data tbody,
  .gloss--data tr,
  .gloss--data td { display: block; }
  /* Visually hidden, not display:none: the column labels still belong to the
     table for anyone listening to it. Same technique as .hp. */
  .gloss--data thead {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }
  .gloss--data tr {
    padding: 0.8rem 0;
    border-top: 1px solid var(--line);
  }
  .gloss--data tbody tr:last-child { border-bottom: 1px solid var(--line); }
  .gloss--data td { padding: 0; border-top: 0; }
  .gloss--data tbody tr:last-child td { border-bottom: 0; }
  .gloss--data td:first-child {
    margin-bottom: 0.25rem;
    font-weight: 600;
    color: var(--ink);
  }
  .gloss--data td[data-label]::before {
    content: attr(data-label);
    margin-right: 0.6em;
    font-family: var(--sans);
    font-size: var(--t-micro);
    font-weight: 600;
    letter-spacing: 0.13em;
    text-transform: uppercase;
    color: var(--clay);
  }
  /* An empty cell stacked would print its label over nothing. */
  .gloss--data td:empty { display: none; }
}

/* The heading's own link, injected by site.js. Quiet until the heading is
   hovered or the link is tabbed to, so eighty of them do not speckle the page,
   but never display:none -- a keyboard user has to be able to reach it. */
.headlink {
  margin-left: 0.4em;
  color: var(--muted);
  text-decoration: none;
  opacity: 0;
  transition: opacity .12s ease;
}
h2:hover > .headlink,
h3:hover > .headlink,
h4:hover > .headlink,
.headlink:focus-visible { opacity: 1; }
.headlink:hover { color: var(--clay); }

/* Sort control, injected into each header cell by site.js. With JavaScript off
   the header is plain text and nothing here applies. */
.sortbtn {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: inherit;
  cursor: pointer;
  text-align: left;
}
.sortbtn::after { content: "\2195"; opacity: 0.4; }
.sortbtn:hover { color: var(--sea); }
.sortbtn:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
th[aria-sort="ascending"] .sortbtn::after { content: "\2191"; opacity: 1; }
th[aria-sort="descending"] .sortbtn::after { content: "\2193"; opacity: 1; }
th[aria-sort] .sortbtn { color: var(--sea); }

/* The filter. It is built by site.js and inserted at the head of the tables,
   not in the index beside them: on a page of 743 rows a control nobody finds
   is a control nobody has. So it gets a panel of its own, a heading in plain
   words, a line saying what it searches, and examples that fill it on a click.

   It also sticks, because the row someone wants may be forty screens down.
   Stuck, it sheds the explanation and keeps the input — the reader who has
   scrolled that far has already read it. It is only sticky while stuck:
   site.js lets the whole panel scroll up under the masthead first, and
   sticks it once only a bar's depth of it is left showing, so the bar takes
   the place of that last strip. Sticky all along, it would pin at full height
   and the page would run on underneath it for 548px on a phone before it
   shrank. .tablefilter__sentinel is the marker above it, which site.js grows
   while it is stuck by what it gave up, so the page below keeps its place. */
.tablefilter {
  margin: 0 0 2.25rem;
  padding: 1.15rem 1.3rem 1rem;
  background: var(--paper-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.tablefilter__sentinel { height: 0; }

.tablefilter label {
  display: block;
  font-family: var(--sans);
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 0.35rem;
}
.tablefilter__hint {
  margin: 0 0 0.85rem;
  max-width: 46rem;
  font-family: var(--sans);
  font-size: var(--t-small);
  line-height: 1.5;
  color: var(--ink-soft);
}

.tablefilter__row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: center;
}
.tablefilter input {
  flex: 1 1 16rem;
  max-width: 26rem;
  min-width: 0;
  font: inherit;
  font-size: 1rem;
  color: var(--ink);
  /* Paper, not paper-raised: the panel is already raised, and an input the
     same colour as the panel it sits on does not read as a box to type in. */
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0.6rem 0.8rem;
}
.tablefilter input:focus {
  outline: 2px solid var(--focus);
  outline-offset: 1px;
  border-color: transparent;
}

.tablefilter__clear,
.tablefilter__eg {
  font-family: var(--sans);
  font-size: var(--t-small);
  color: var(--sea);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0.35rem 0.7rem;
  cursor: pointer;
}
.tablefilter__clear:hover,
.tablefilter__eg:hover { border-color: var(--sea); color: var(--sea-deep); }
.tablefilter__clear:focus-visible,
.tablefilter__eg:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.tablefilter__clear { padding: 0.55rem 0.9rem; }

.tablefilter__examples {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  margin: 0.75rem 0 0;
  font-family: var(--sans);
  font-size: var(--t-small);
  color: var(--muted);
}
/* The two judgement columns, as buttons. The whole page exists to answer
   "where is somebody told to follow a leader, and is it counsel or command?",
   and that was a guess at a substring before this. */
.tablefilter__facet {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.4rem;
  margin-top: 0.7rem;
}
.tablefilter__facetlabel {
  flex: 0 0 4.5rem;
  font-family: var(--sans);
  font-size: var(--t-micro);
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--clay);
}
.facet {
  font-family: var(--sans);
  font-size: var(--t-small);
  color: var(--ink-soft);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0.3rem 0.6rem;
  cursor: pointer;
}
.facet:hover { border-color: var(--sea); color: var(--sea); }
.facet:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.facet__n { color: var(--muted); }
.facet.is-on {
  background: var(--sea-tint);
  border-color: var(--sea);
  color: var(--sea-deep);
  font-weight: 600;
}
.facet.is-on .facet__n { color: inherit; }
/* Stuck, the bar is one line: the box and the count. The facets go with the
   explanation, as the examples already do. */
.tablefilter.is-stuck .tablefilter__facet { display: none; }

.tablefilter__count {
  display: block;
  margin-top: 0.7rem;
  font-family: var(--sans);
  font-size: var(--t-small);
  color: var(--muted);
}

/* Stuck: the heading goes on the same line as the box, and the explanation
   and the examples go, so the bar costs about one line of the screen. */
.tablefilter.is-stuck {
  position: sticky;
  /* Clear of the sticky masthead, which is 71px at every width. */
  top: 4.5rem;
  z-index: 20;
  padding: 0.6rem 1rem;
  border-radius: 0 0 var(--radius) var(--radius);
}
.tablefilter.is-stuck .tablefilter__hint,
.tablefilter.is-stuck .tablefilter__examples { display: none; }
.tablefilter.is-stuck label {
  font-size: var(--t-small);
  margin-bottom: 0;
  margin-right: 0.75rem;
}
.tablefilter.is-stuck .tablefilter__count { margin-top: 0.35rem; }
@media (min-width: 34rem) {
  .tablefilter.is-stuck {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0 0.75rem;
  }
  .tablefilter.is-stuck label { flex: 0 0 auto; }
  .tablefilter.is-stuck .tablefilter__row { flex: 1 1 14rem; }
  .tablefilter.is-stuck .tablefilter__count { flex: 0 0 auto; margin-top: 0; }
}
/* On a phone the three parts stack, and a bar a sixth of the screen deep is a
   tax on every screen of the page. Stuck, it keeps the box and the count; the
   heading goes to the screen reader only, where the input's label still needs
   it. Same visually-hidden technique as the stacked table headers above. */
@media (max-width: 33.999rem) {
  .tablefilter.is-stuck { padding: 0.5rem 1rem 0.55rem; }
  .tablefilter.is-stuck label {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }
  .tablefilter.is-stuck .tablefilter__count {
    margin-top: 0.3rem;
    font-size: var(--t-micro);
  }
}

/* A stacked row, collapsed to what identifies it: the reference, the first two
   lines of the Greek, and the classification. site.js only builds these while
   the stacked layout is in use, so above 64rem none of this applies. */
@media (max-width: 64rem) {
  .rowtoggle {
    display: flex;
    align-items: baseline;
    gap: 0.5em;
    width: 100%;
    min-height: 44px;
    padding: 0;
    font: inherit;
    font-weight: 600;
    color: var(--ink);
    text-align: left;
    background: none;
    border: 0;
    cursor: pointer;
  }
  .rowtoggle::before {
    content: "▸";
    flex: 0 0 auto;
    color: var(--clay);
    transition: transform .12s ease;
  }
  tr:not(.is-collapsed) > td:first-child > .rowtoggle::before { transform: rotate(90deg); }
  .rowtoggle:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }

  /* Collapsed, the summary is two lines, not four: the reference and the
     classification share the first, the Greek takes the second. Stacked one per
     line they cost 85px of a 188px row for two short strings. */
  tr.is-collapsed:has(td[data-label="Text"]) {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: 0.75rem;
    align-items: baseline;
  }
  tr.is-collapsed:has(td[data-label="Text"]) > td:first-child { grid-column: 1; }
  tr.is-collapsed:has(td[data-label="Text"]) > td[data-label="Classification"] {
    grid-column: 2;
    text-align: right;
  }
  tr.is-collapsed:has(td[data-label="Text"]) > td[data-label="Text"] {
    grid-column: 1 / -1;
  }
  /* The label is redundant once the two share a line. */
  tr.is-collapsed td[data-label="Classification"]::before,
  tr.is-collapsed td[data-label="Text"]::before { content: none; }

  /* Collapsed: the gloss and the note wait, and the Greek shows its first two
     lines. The classification stays -- it is what the reader is scanning. */
  tr.is-collapsed .rowgloss,
  tr.is-collapsed td[data-label="Note"] { display: none; }
  tr.is-collapsed td[data-label="Text"] .greek {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
}

/* Rows and whole tables the filter has ruled out.

   The stacked-table blocks above set `display: block` on `.gloss--data tr` and
   `.gloss--grid tr` — specificity (0,1,1), against this rule's (0,1,0). Media
   queries add nothing to specificity, so below 64rem those won. The filter went
   on reporting "39 rows in 11 tables" while 511 of them stayed on screen, on
   every phone, every tablet, and in print (a print page box is ~794px, so it is
   inside the same breakpoint). Whole tables still vanished, because their
   .table-scroll wrapper has no competing display — which is what made it look
   like the filter worked.

   Matching their specificity fixed it once and then lost again the moment the
   collapsed phone row arrived, because that is selected with :has() and no
   hand-written selector here can outrank it. This is the one rule on the site
   that earns !important: a row the filter has ruled out is not a row any other
   rule may put back, and every future layout for these tables would otherwise
   have to remember to lose to it. */
.is-filtered { display: none !important; }

/* --------------------------------------------------------------------------
   19. Mobile page menu (the in-page index's bar and sheet below 1000px)
   -------------------------------------------------------------------------- */

/* Built by site.js on every page whose .index-nav is not --desktop; none of
   it is in the HTML, so with scripts off a phone keeps the chips (section 11)
   and nothing else. Hidden until those chips have scrolled under the masthead,
   then shown the way .totop is (section 15), whose job it takes over here: the
   arrow sits in the bar, and the loose button is hidden under html.has-pagenav.

   Stacking: 40 closed, like .totop — under the masthead (50) and its panel
   (60), so an open site menu covers the bar. 70 open, so the scrim covers
   both. The root is never transformed: the scrim inside it is position:fixed,
   and a transformed ancestor would become its containing block and shrink it
   to the bar. The slide is on the sheet, the lift on the bar. */
.pagenav { display: none; }

@media (max-width: 999px) {
  .pagenav {
    display: block;
    position: fixed;
    inset-inline: 0;
    bottom: 0;
    z-index: 40;
    /* visibility as well as opacity, so the bar leaves the tab order while
       hidden — .totop's reasoning. Reduced motion is the section 2 blanket. */
    opacity: 0;
    visibility: hidden;
    transition: opacity .18s ease, visibility .18s ease;
  }
  .pagenav.is-shown { opacity: 1; visibility: visible; }
  .pagenav.is-open { z-index: 70; }

  /* The footer's last lines need the bar's height back. */
  .has-pagenav body { padding-bottom: 3.25rem; }

  .pagenav__scrim {
    position: fixed;
    inset: 0;
    z-index: 0;
    /* Not a token: the nav panel's shadow colour, a shade heavier so it still
       reads over dark-mode paper. */
    background: rgba(0, 0, 0, .45);
    opacity: 0;
    visibility: hidden;
    transition: opacity .22s ease, visibility .22s ease;
  }
  .pagenav.is-open .pagenav__scrim { opacity: 1; visibility: visible; }

  .pagenav__bar {
    position: relative;
    z-index: 2;
    display: flex;
    align-items: center;
    gap: 0.75rem;
    min-height: 3.25rem;
    padding: 0 var(--gutter);
    background: var(--paper);
    border-top: 1px solid var(--line);
    /* .totop's 4px lift on the way in. */
    transform: translateY(4px);
    transition: transform .18s ease;
  }
  .pagenav.is-shown .pagenav__bar { transform: none; }

  /* The pill on the bar's top edge, and the strip a finger can take hold of.
     The strip is the middle half only, so it never sits over the arrow, and it
     is the one place on the bar where touch-action is off — a finger here
     drags the sheet, never the page. A tap on it toggles, the same as the
     button under it. */
  .pagenav__handle {
    position: absolute;
    top: 0;
    left: 25%;
    right: 25%;
    height: 0.75rem;
    touch-action: none;
  }
  .pagenav__handle::before,
  .pagenav__grip::before {
    content: "";
    position: absolute;
    top: 0.3rem;
    left: 50%;
    width: 2.25rem;
    height: 0.25rem;
    margin-left: -1.125rem;
    border-radius: var(--radius);
    background: var(--line);
  }
  /* One pill at a time: the sheet's own takes over while it is open. */
  .pagenav.is-open .pagenav__handle::before { display: none; }

  .pagenav__toggle {
    position: relative;
    /* min-width: 0 is what lets the current line ellipsise instead of pushing
       the arrow off the edge. */
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    gap: 0.1rem;
    min-height: 44px;
    padding: 0.4rem 1.6rem 0.4rem 0;
    background: none;
    border: 0;
    font: inherit;
    color: var(--ink);
    text-align: left;
    cursor: pointer;
  }
  /* The dropdown chevron from section 4, pointing up: the sheet opens upward. */
  .pagenav__toggle::after {
    content: "";
    position: absolute;
    right: 0.4rem;
    top: 50%;
    width: 0.34rem;
    height: 0.34rem;
    border-right: 1.5px solid currentColor;
    border-bottom: 1.5px solid currentColor;
    color: var(--muted);
    transform: translateY(-30%) rotate(225deg);
    transition: transform .15s ease;
  }
  .pagenav.is-open .pagenav__toggle::after { transform: translateY(-70%) rotate(45deg); }

  /* The index's own heading, in its own dress (section 11). */
  .pagenav__eyebrow {
    font-family: var(--sans);
    font-size: var(--t-micro);
    font-weight: 600;
    letter-spacing: 0.13em;
    text-transform: uppercase;
    color: var(--clay);
    line-height: 1.2;
  }
  .pagenav__current {
    max-width: 100%;
    font-size: var(--t-small);
    line-height: 1.3;
    color: var(--ink);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  /* .totop's treatment (section 15), sitting in the flow of the bar. */
  .pagenav__top {
    display: grid;
    place-items: center;
    flex: 0 0 44px;
    width: 44px;
    height: 44px;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    color: var(--muted);
    font-family: var(--sans);
    font-size: 1.05rem;
    line-height: 1;
    text-decoration: none;
  }
  .pagenav__top::before { content: "\2191"; }
  .pagenav__top:hover,
  .pagenav__top:active { color: var(--clay); border-color: var(--clay); }

  .pagenav__sheet {
    position: absolute;
    inset-inline: 0;
    bottom: 100%;
    z-index: 1;
    max-height: 60dvh;
    overflow-y: auto;
    overscroll-behavior: contain;
    background: var(--paper);
    border-top: 1px solid var(--line);
    /* The nav panel's shadow (section 4), thrown upward. */
    box-shadow: 0 -18px 32px -24px rgba(0, 0, 0, .4);
    transform: translateY(100%);
    visibility: hidden;
    transition: transform .22s ease, visibility .22s ease;
  }
  .pagenav.is-open .pagenav__sheet { transform: none; visibility: visible; }
  /* While a finger has it, site.js sets the transform; nothing may animate. */
  .pagenav__sheet.is-dragging { transition: none; visibility: visible; }

  .pagenav__grip {
    position: sticky;
    top: 0;
    z-index: 1;
    height: 1.25rem;
    background: var(--paper);
    touch-action: none;
  }

  /* The list. Section 11's sidebar rules restated, because the clone lives
     outside .index-nav and would otherwise be a bare <ol>; and none of that
     section's chip or accordion rules reach it, which is the point — every
     level shows here, indented. */
  .pagenav__sheet ol {
    list-style: none;
    margin: 0 var(--gutter) 1rem;
    padding: 0;
    border-left: 1px solid var(--line);
  }
  .pagenav__sheet ol ol { margin: 0; border-left: 0; }
  .pagenav__sheet li { margin: 0; }
  .pagenav__sheet a {
    display: flex;
    align-items: center;
    min-height: 44px;
    padding: 0.3rem 0 0.3rem 1rem;
    margin-left: -1px;
    border-left: 2px solid transparent;
    font-size: 0.9rem;
    color: var(--ink-soft);
    text-decoration: none;
    line-height: 1.45;
    text-wrap: balance;
  }
  .pagenav__sheet ol ol a { padding-left: 2rem; font-size: 0.84rem; }
  .pagenav__sheet a:hover { color: var(--sea); border-left-color: var(--sand); }
  .pagenav__sheet a.is-active { color: var(--sea); border-left-color: var(--clay); font-weight: 500; }
  /* Section 18 hides the survey's counts on the chips; the sheet has room. */
  .pagenav__sheet .index-nav__count { display: block; }
  /* The two parts on the Hebrews notes, restated from section 11 the same
     way. Their rows keep 44px here: this list is for thumbs. */
  .pagenav__sheet ol:has(> .index-nav__part) { border-left: 0; }
  .pagenav__sheet .index-nav__part + .index-nav__part { margin-top: 0.5rem; }
  .pagenav__sheet .index-nav__part > a {
    padding-left: 0;
    margin-left: 0;
    border-left: 0;
    font-weight: 600;
    color: var(--ink);
  }
  .pagenav__sheet .index-nav__part > a:hover,
  .pagenav__sheet .index-nav__part > a.is-active { color: var(--sea); }
  .pagenav__sheet .index-nav__part > ol { border-left: 1px solid var(--line); }
  .pagenav__sheet .index-nav__part > ol > li > a { padding-left: 1rem; font-size: 0.9rem; }
}

/* --------------------------------------------------------------------------
   20. Print
   -------------------------------------------------------------------------- */

@media print {
  :root {
    --paper: #FFF; --paper-raised: #FFF; --ink: #000; --ink-soft: #222;
    --sea: #000; --clay: #444; --muted: #555; --line: #BBB;
  }
  .masthead, .nav, .nav-toggle, .skip, .nextprev, .backtotop, .totop, .pagenav,
  .index-nav, .site-footer__grid, .btn-row, .video__close { display: none !important; }
  body { font-size: 11pt; line-height: 1.5; }
  .layout-index { display: block; }
  /* No sidebar on paper, so the short case's band is full width without its
     border-image; plain borders print whatever the background setting. */
  .layout-index--parts .section--tint { border-image: none; }
  a { text-decoration: none; color: #000; }
  .entry > h2, .theme { break-inside: avoid-page; break-after: avoid-page; }
  .commands li, .commitments li, .qual { break-inside: avoid; }
  .notes > li { break-inside: avoid; }
  .notes__back { display: none !important; }
  /* The map is the summary sheet; it prints. Two columns keeps it to one page. */
  .thememap { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .thememap__card { break-inside: avoid; border-top-width: 2px; }
  .thememap__title a::after { content: none; }
  .quote { border-left-color: #999; }

  /* The survey. A print page box is about 794px, which is inside the 64rem
     stacking breakpoint, so it prints as the phone layout: every cell its own
     labelled line, and thead visually hidden, which means no column headings at
     all. Printing was only ever scoped to /beliefs/ and /one-anothers/; this
     makes the one page a reader would most want on paper printable too. */
  .appendix .tablefilter,
  .appendix .sortbtn::after,
  .appendix .headlink,
  .appendix .rowtoggle::before { display: none !important; }

  /* The contents is front matter, not chrome: a hundred pages of tables with no
     way into them is not a document. */
  .appendix .index-nav {
    display: block !important;
    position: static;
    max-height: none;
    overflow: visible;
    break-after: page;
  }
  .appendix .index-nav ol ol { display: block !important; }

  /* Print inside the stacking breakpoint, so undo the phone layout: with the
     rows restructured these tables are four columns, which fits a page. A real
     table also gets table-header-group, so the headings repeat on every sheet
     -- which is the thing the stacked layout cannot do at all. */
  .appendix .gloss--data { display: table; width: 100%; }
  .appendix .gloss--data thead {
    display: table-header-group;
    position: static;
    width: auto; height: auto;
    margin: 0; padding: 0;
    overflow: visible;
    clip: auto;
    clip-path: none;
    white-space: normal;
  }
  .appendix .gloss--data tbody { display: table-row-group; }
  /* !important because the collapsed-row layout is selected with :has(), which
     outranks anything written here on specificity alone. */
  .appendix .gloss--data tr { display: table-row !important; padding: 0; }
  .appendix .gloss--data td {
    display: table-cell !important;
    border-top: 1px solid #BBB;
    padding: 0.35rem 0.6rem 0.35rem 0;
    vertical-align: top;
  }
  .appendix .gloss--data td[data-label]::before { content: none; }
  .appendix .chip { display: block; }
  .appendix .chip + .chip::before { content: none; }

  /* Nothing is collapsed on paper, and no row is filtered out of it either. */
  .appendix tr.is-collapsed .rowgloss,
  .appendix tr.is-collapsed td[data-label="Note"] { display: block !important; }
  .appendix tr.is-collapsed td[data-label="Text"] .greek {
    display: block !important;
    overflow: visible;
  }
  .appendix .rowtoggle { font-weight: 600; }

  /* .table-scroll is overflow-x: auto, and an overflow box does not paginate --
     anything past the page edge is dropped with nothing to show for it. */
  .appendix .table-scroll { overflow: visible !important; }

  /* A classification must not be orphaned from the clause it classifies. */
  .appendix tbody tr,
  .appendix blockquote { break-inside: avoid; }
  .appendix thead { display: table-header-group; }

  /* On a page whose whole claim is that every source can be checked, a link
     that prints as plain black text is the one thing worth keeping. */
  .appendix a[href^="http"]::after {
    content: " (" attr(href) ")";
    font-size: 0.85em;
    color: #555;
    word-break: break-all;
  }
  .feature { background: #FFF !important; color: #000 !important; border: 1px solid #BBB; }
  .feature h2, .feature__text { color: #000 !important; }
}
