/*
Theme Name:   TCF (Blocksy Child)
Theme URI:    https://tcfky.com
Description:  Trinity Christian Fellowship's child theme. All customisation lives
              here so Blocksy can be updated without losing work. Version
              controlled at github.com/forhisglory-llc/NewChurchSite under
              theme/tcf-child, and deployed with tools/deploy_theme.sh.
Author:       Trinity Christian Fellowship
Template:     blocksy
Version:      0.56.11
Text Domain:  tcf-child
*/

/* ---------------------------------------------------------------------------
   WEBFONTS

   This reverses an earlier decision, knowingly. The site shipped system stacks
   and zero font downloads on performance grounds; the design handoff (§1.2)
   requires self-hosted Newsreader and Public Sans, and the handoff is
   authoritative on design. Its own performance budget absorbs the change - six
   files, two preloaded, homepage under 900 KB (docs/handoff/05, §5.9).

   Self-hosted, never the Google Fonts CDN: a third-party connection on the
   critical path is both a render-blocking DNS+TLS round trip and a GDPR
   liability, and neither is worth it for a font we can serve ourselves.

   These are ordinary @font-face rules in the child stylesheet, NOT theme.json
   `fontFace` entries. Blocksy is a classic theme and a theme.json in a classic
   child changes how WordPress emits layout CSS - see HANDOFF_ADOPTION_PLAN.md
   §2. The src paths are relative to this file, so they resolve correctly both on
   the front end and inside the block editor, which loads this same stylesheet
   through add_editor_style().

   The unicode-range values are Google's own subset boundaries, copied verbatim.
   They are what makes the split worthwhile: a page of English prose fetches the
   `latin` files and nothing else, and the `latin-ext` and italic files stay on
   the server until something on the page actually needs them.

   The vietnamese subsets are deliberately absent. They are the third of the
   three subsets Google ships and nothing on this site will ever need them.

   Weights are declared as ranges because these are variable fonts - one file
   covers 300-400 for Newsreader and 400-700 for Public Sans. NEVER ask
   Newsreader for a weight above 400 (§1.2): the range stops there, so a `bold`
   heading gets a synthesised smear rather than a designed weight.

   Two faces are preloaded from functions.php - newsreader-latin and
   public-sans-latin, the pair used above the fold. The preload carries
   `crossorigin` because font fetches are always CORS-mode requests even
   same-origin; without it the preload does not match the later @font-face fetch
   and the browser downloads the file twice.
   --------------------------------------------------------------------------- */

/* Newsreader - display and headings. latin-ext first, latin second: order is
   irrelevant to matching (the browser picks by unicode-range) but reads in the
   same order as the comments in the source Google stylesheet. */
@font-face {
  font-family: "Newsreader";
  font-style: normal;
  font-weight: 300 400;
  font-display: swap;
  src: url("assets/fonts/newsreader-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;
}
@font-face {
  font-family: "Newsreader";
  font-style: normal;
  font-weight: 300 400;
  font-display: swap;
  src: url("assets/fonts/newsreader-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;
}

/* Italic Newsreader is for pull quotes and Scripture, and for nothing else. It
   is 98 KB that most pages never touch, which is exactly why it is a separate
   face rather than a synthesised slant.

   All four Newsreader files are INSTANCED to the 300-400 weight range these
   @font-face rules already declare. Shipped from Google Fonts they carry the
   full 200-800 axis, so three quarters of the weight data was being downloaded
   by every visitor and used by nothing - 141 KB across the four files, 85 KB of
   it on the home page alone, which is what put that page over the 900 KB budget
   in §5.9. The `opsz` axis is deliberately left whole: browsers derive optical
   size from font-size and clamping it risks clipping at sizes we do not control.

   If a font is ever re-downloaded from Google, re-run the instancing or the
   budget silently regresses:
     uv run --with fonttools --with brotli python -c "..."   (see SESSION_KNOWLEDGE.md)
   And if §1.2's ban on Newsreader at 500+ is ever lifted, these files must be
   regenerated FIRST - a heavier weight will otherwise clamp to 400 with no
   error anywhere. */
@font-face {
  font-family: "Newsreader";
  font-style: italic;
  font-weight: 300 400;
  font-display: swap;
  src: url("assets/fonts/newsreader-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;
}
@font-face {
  font-family: "Newsreader";
  font-style: italic;
  font-weight: 300 400;
  font-display: swap;
  src: url("assets/fonts/newsreader-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;
}

/* Public Sans - body, UI, labels, buttons. One file covers 400 through 700. */
@font-face {
  font-family: "Public Sans";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("assets/fonts/public-sans-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;
}
@font-face {
  font-family: "Public Sans";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("assets/fonts/public-sans-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;
}

/* ---------------------------------------------------------------------------
   DESIGN TOKENS

   The single place colour, type and spacing are decided. Every rule below
   references a token rather than a literal, so the look of the site can be
   changed here rather than hunted through a stylesheet.

   Full rationale, contrast measurements and usage guidance:
   docs/DESIGN_SYSTEM.md

   Direction: editorial, warm, photography-led, classical type leaning into the
   creeds - explicitly NOT the megachurch template. Blocksy ships a generic SaaS
   blue; everything here replaces it.

   Values come from the design handoff, docs/handoff/01-design-system.md. The
   token NAMES are the ones this theme already used, because ~950 lines of
   component CSS below reference them; the values underneath moved. Where a name
   and the handoff's vocabulary disagree, the handoff's word is in the comment:
   `--tcf-accent` is `brick`, `--tcf-surface` is `paper-alt`, and so on.
   --------------------------------------------------------------------------- */
:root {
  /* -- Colour ---------------------------------------------------------------
     Six colours, no secondary accent, no gradients anywhere (§1.1). Warm
     neutrals rather than the blue-greys Blocksy defaults to: photographs of a
     modest room in ordinary light sit badly on cool grey and sit well on warm
     off-white. The accent is a deep clay red - old, bookish and quiet, where a
     saturated blue would read as software.

     Ratios below are measured on `paper`, which is now the page colour. They
     were computed from relative luminance, not estimated; see DESIGN_SYSTEM.md
     for the full table and for the three places these values must stay in sync. */
  --tcf-accent:         #96412E;  /* brick     - buttons, links, eyebrows    6.41:1 on paper */
  --tcf-accent-strong:  #7A3324;  /* hover/active                            8.52:1 on paper */
  --tcf-ink:            #1A1714;  /* ink       - body text, dark bands      16.85:1 on paper */
  --tcf-muted:          #6B6259;  /* muted     - secondary text, metadata     5.64:1 on paper */
  --tcf-rule:           #E7E0D4;  /* rule      - hairlines, borders, dividers */
  --tcf-surface:        #F3EEE4;  /* paper-alt - alternating band, callouts */
  --tcf-surface-soft:   #FBF8F3;  /* paper     - kept as an alias of the page colour */
  --tcf-page:           #FBF8F3;  /* paper     - the page background is no longer white */

  /* `--tcf-body` is retired as a DECISION and kept as a NAME.

     The handoff sets body text to ink, so there is no longer a separate body
     colour to decide. But the token is referenced throughout the component CSS
     below, and deleting it would mean touching dozens of rules that are
     otherwise correct - each one an opportunity to get something wrong for no
     design gain. Pointing it at ink means every existing reference keeps
     working and quietly picks up the new value.

     Do not use it in new rules. Use `--tcf-ink`. */
  --tcf-body: var(--tcf-ink);

  /* Support tints. NOT editor-facing (§1.1) - these only ever appear as
     foreground on a coloured background, so offering them as swatches would
     invite text the same colour as the paper it sits on. */
  --tcf-on-ink-accent:   #E0B9A6;                  /* eyebrows on ink          9.91:1 */
  --tcf-on-ink-body:     #B8B0A4;                  /* body copy on ink         8.32:1 */
  --tcf-on-ink-muted:    #9B9284;  /* footer body on ink (§1.6) - 5.81:1 */
  --tcf-on-ink-quiet:    #D8D1C6;  /* utility bar (§1.1) - 11.78:1 */

  /* Two more values the canvas paints and §1.1's table does not list, found by
     measuring rather than reading. Recorded here so they are palette entries
     with contrast figures rather than literals scattered through the file.

     --tcf-nav is the top-level navigation label. Slightly lifted off ink, so
     the wordmark beside it stays the darkest thing in the header.
     --tcf-on-photo is the hero lede over the darkened photograph, a step down
     from paper so the headline above it keeps the emphasis. */
  --tcf-nav:             #3B3630;  /* nav labels (2a canvas)   - 11.29:1 on paper */
  --tcf-on-photo:        #DBD3C7;  /* hero lede on the scrim   - 12.31:1 on ink */
  --tcf-on-ink-rule:     rgba(251, 248, 243, 0.16);/* hairline on ink */
  --tcf-on-brick-accent: #F0CBBD;                  /* eyebrows on brick        4.52:1 */
  --tcf-on-brick-body:   #F2D6CB;                  /* body copy on brick       4.93:1 */
  --tcf-on-brick-rule:   rgba(251, 248, 243, 0.35);/* hairline on brick */
  --tcf-on-dark-border:  rgba(251, 248, 243, 0.4); /* secondary button on dark 3.68:1 */
  /* A photograph under the §2a.1 scrim is not a flat ink band, and the 3.68:1
     above is measured on one. The scrimmed hero sits nearer rgb(46,42,36), so
     the same 0.4 alpha yields 3.44:1 there and measured 3.31:1 on the real hero
     at 1440 and 2.31:1 at 390 - a 1.4.11 failure, and the reason the secondary
     hero button reads as plain text. 0.55 measures 4.99:1 at 1440 and 4.96:1 at
     390 over the corrected scrim, and costs the label nothing. Two tokens rather
     than one moved value: --tcf-on-dark-border is correct where it is used, and
     its other consumer is the scrub track's unplayed rail below, which was tuned
     against 3.68:1 on purpose. */
  --tcf-on-photo-border: rgba(251, 248, 243, 0.55);/* secondary button on photo 5.16:1 */

  /* Component neutrals (§1.1). Each of these is a single documented use; none
     of them is a general-purpose colour. */
  --tcf-photo-fill:      #EBE3D5;  /* dashed PHOTO SLOT fill */
  --tcf-photo-border:    #D5C9B6;  /* dashed PHOTO SLOT border */
  --tcf-link-underline:  #D7B4A8;  /* the underline under a body link, before hover */
  --tcf-button-border:   #918470;  /* secondary button border - 3.45:1, see below */
  --tcf-tertiary:        #8A8175;  /* tertiary label - 3.62:1, see the warning below */
  --tcf-numeral:         #B4AA98;  /* the big numerals in numbered lists - decorative only */

  /* Status. The handoff defines no error or success colour anywhere - it
     specifies six values and no secondary accent - yet §5.5 requires login
     errors to be announced and to describe the fix, and a form has to
     distinguish "sent" from "failed". Ruled 2026-08-08: error reuses brick
     rather than introducing a second red, and success gets one new value.

     Moss, not a notification green. At brick's own saturation a green reads
     grassy where a red reads earthy, so this is pulled back to 0.36 and sits
     at hue 88 - yellow-leaning, which is what keeps it warm. Measured 4.94:1
     on paper and 4.52:1 on paper-alt, so it clears AA as text and not merely
     as a border; 3.41:1 on ink if it is ever needed on a dark band.

     Neither carries meaning alone. Both blocks state their outcome in words,
     as §5.1 requires. */
  /* The adaptive hairline. Some components - the teaching player, the footer -
     sit on paper in one place and inside an ink band in another, so their rule
     is mixed from currentColor rather than pinned to a colour. 16% matches the
     handoff's documented on-ink hairline rgba(251,248,243,0.16) (§1.1), and on
     paper it lands within a shade of `rule`. One value, documented, rather than
     the 0.12 / 0.14 / 0.03 that had accumulated. */
  /* §1.3 and the reference: content is capped at 1280 and centred, with a 40px
     gutter; bands themselves run full-bleed and scale. The reference canvas is
     a fixed 1280 artboard, so there the band and the content width coincide -
     the gutter is what tells you they are different things. */
  --tcf-content-max: 1280px;
  --tcf-gutter: 40px;

  --tcf-hairline-alpha: 16%;

  /* The tinted panel a player or callout sits in, mixed from currentColor for
     the same reason. 7% matches the handoff's rgba(251,248,243,0.07) player bar
     on the dark teaching header (§2d). */
  --tcf-panel-alpha: 7%;

  /* The teaching row's play button. §2c names this in prose and §1.1 does not
     list it, the same omission as the status colours. It is a fill behind a
     brick glyph, not text, and brick on it measures 5.79:1. */
  --tcf-play-fill:      #F0E8DA;

  --tcf-status-error:   var(--tcf-accent);  /* brick - 6.41:1 on paper */
  --tcf-status-success: #587537;            /* moss  - 4.94:1 on paper */

  /* --tcf-button-border departs from the handoff, which specifies #C9BFAE.
     Measured, that is 1.72:1 against paper and 1.57:1 against paper-alt. A
     secondary button here is transparent with ink text, so the border is the
     only thing marking where the control is - and WCAG 1.4.11 wants 3:1 for
     exactly that. §1.4 and §5's "WCAG 2.2 AA, treat as a requirement" cannot
     both be satisfied, so the accessibility section wins, as it has everywhere
     else these two disagree.

     #918470 is the same hue (37.8deg), dropped in lightness until it clears 3:1
     on BOTH backgrounds a secondary button can sit on, with a little margin
     because a 1px border antialiases lighter than its nominal colour:
     3.45:1 on paper, 3.16:1 on paper-alt. The label was never the problem -
     that reads at 16.85:1 either way. Ruled 2026-08-08. */

  /* --tcf-tertiary is the one colour in this system that fails AA for body
     text: 3.62:1 on paper, measured. The handoff flags it too (§5.1). It is
     permitted ONLY on labels of 19px or larger at semibold, and only where the
     label repeats information available elsewhere. Anything that carries
     meaning uses --tcf-muted. On the photo-slot fill it drops to 3.01:1, so the
     PHOTO SLOT label is legible-but-marginal scaffolding and must not outlive
     the placeholders. */

  /* -- Type -----------------------------------------------------------------
     Two families and no more (§1.2). Newsreader carries the display and heading
     voice; Public Sans carries everything a person interacts with rather than
     reads. Georgia and system-ui are the fallbacks the swap period shows.

     The `serif` / `ui` names are what the component CSS below already asks for,
     so they stay as aliases. New rules should name the role, not the shape. */
  --tcf-font-display: "Newsreader", Georgia, "Times New Roman", serif;
  --tcf-font-body:    "Public Sans", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --tcf-font-serif:   var(--tcf-font-display);
  --tcf-font-ui:      var(--tcf-font-body);
  /* `sans` as well as `ui` and `body`, because all three names get reached for
     and a custom property that does not exist takes its whole declaration down
     with it - silently, leaving the element to inherit whatever its parent had.
     Seven rules in this file were referencing --tcf-font-sans and none of them
     was doing anything. Aliasing costs nothing and removes a trap that has now
     caught two people. */
  --tcf-font-sans:    var(--tcf-font-body);

  /* The scale is the handoff's (§1.2), with the fluid min/max pairs taken from
     docs/handoff/theme.json `settings.typography.fontSizes`. That file is an FSE
     starter this classic theme cannot use as a stylesheet, but it is the shipped
     source of the numbers, so the numbers come from it rather than from a
     reading of the table.

     THE HEADINGS ARE FLUID, and that is not decoration. A fixed scale meant a
     44px page title and 28px item titles on a 390px phone: on the teaching archive
     every title wrapped to three lines and four teachings filled the entire
     screen, which is what a list is supposed to save you from.

     THE BODY SIZES ARE NOT FLUID, and that is not laziness. §1.2 sets a floor of
     15px on every breakpoint, and the way to honour a floor is to not go near
     it: 17px prose and 15.5px card copy are fixed at every width. Shrinking body
     text on a small screen is the opposite of what a small screen needs. The two
     values below 15px - meta at 14 and eyebrow at 11.5 - are the handoff's own,
     and are labels and metadata rather than anything anyone reads a paragraph
     of. */
  --tcf-text-eyebrow: 0.71875rem;  /* 11.5px - uppercase, 700, 0.2em tracking */
  --tcf-text-meta:    0.875rem;    /* 14px   - dates, durations, captions */
  --tcf-text-ui:      0.9375rem;   /* 15px   - nav, buttons, chips */
  --tcf-text-body-sm: 0.96875rem;  /* 15.5px - card copy, list descriptions */
  --tcf-text-body:    1.0625rem;   /* 17px   - long-form prose */
  --tcf-text-lede:    clamp(1.0625rem, 1rem    + 0.25vw, 1.1875rem); /* 17 -> 19 */
  --tcf-text-stat:    clamp(1.4375rem, 1.25rem + 0.75vw, 1.6875rem); /* 23 -> 27 */
  --tcf-text-card:    clamp(1.5rem,    1.25rem + 1vw,    1.875rem);  /* 24 -> 30 */
  --tcf-text-section: clamp(1.75rem,   1rem    + 3vw,    2.5rem);    /* 28 -> 40 */
  --tcf-text-page:    clamp(2.125rem,  1.125rem + 4vw,   3.25rem);   /* 34 -> 52 */
  --tcf-text-display: clamp(2.5rem,    1rem    + 6vw,    4rem);      /* 40 -> 64 */

  /* The old size names, re-pointed at the steps above. They are what the
     component rules below ask for; the aliases are what let those rules pick up
     the new scale without being rewritten one at a time. */
  --tcf-text-xs:   var(--tcf-text-eyebrow);
  --tcf-text-sm:   var(--tcf-text-meta);
  --tcf-text-base: var(--tcf-text-body);
  --tcf-text-lg:   var(--tcf-text-lede);
  --tcf-text-xl:   var(--tcf-text-card);
  --tcf-text-2xl:  var(--tcf-text-section);
  --tcf-text-3xl:  var(--tcf-text-page);
  --tcf-text-4xl:  var(--tcf-text-display);

  /* Leading, per step. A 64px hero line and a 17px paragraph do not want the
     same ratio - the bigger the type, the less air a line needs between it and
     the next one. */
  --tcf-leading-display: 1.06;  /* display and page title */
  --tcf-leading-tight:   1.15;  /* section headings */
  --tcf-leading-card:    1.22;  /* card and panel headings */
  --tcf-leading-stat:    1.25;
  --tcf-leading-lede:    1.65;
  --tcf-leading-body:    1.75;  /* long-form prose */
  --tcf-leading-sm:      1.6;

  /* Tracking. §1.2 sets it by rendered size, not by element: -0.02em at 40px and
     above, -0.01em from 24 to 39px, 0 below 24. Because the heading sizes are
     fluid, the rules that apply these swap at the viewport width where each
     clamp crosses the boundary - see the heading section below. */
  --tcf-tracking-display: -0.02em;
  --tcf-tracking-heading: -0.01em;
  --tcf-tracking-eyebrow: 0.2em;

  /* -- Spacing --------------------------------------------------------------
     A 4px base (§1.3). The first four steps are the fine scale for padding and
     gaps inside a component; from 5 up they are the coarse section rhythm the
     handoff names - 28 / 40 / 56 / 72 / 88 - because a page's vertical rhythm
     wants a few widely-spaced values, not a smooth geometric run.

     Named by size, not by use, so the same token can serve a margin here and a
     gap there without lying about itself. */
  --tcf-space-1: 0.25rem;   /*  4px */
  --tcf-space-2: 0.5rem;    /*  8px */
  --tcf-space-3: 0.75rem;   /* 12px */
  --tcf-space-4: 1rem;      /* 16px */
  --tcf-space-5: 1.75rem;   /* 28px - grid gutter between cards */
  --tcf-space-6: 2.5rem;    /* 40px - page gutter, mobile section padding */
  --tcf-space-7: 3.5rem;    /* 56px - tablet section padding */
  --tcf-space-8: 4.5rem;    /* 72px - desktop section padding */
  --tcf-space-9: 5.5rem;    /* 88px - the largest section break */

  /* -- Rhythm ---------------------------------------------------------------
     UI_UX_BRIEF.md §5.7: the heading sizes came from the scale and the gaps
     between sections never did. They were made consistent - one value, 40px,
     nearly everywhere - rather than designed, and a page whose biggest break is
     20px SMALLER than the gap between a back link and a title has no hierarchy
     for a reader to use. Measured on the single teaching page, 2026-09-06: the
     change of surface from ink to paper was 60px and the gap between a back
     link and the title beneath it was 40px.

     Four steps, named for WHAT THEY DIVIDE rather than for how big they are. A
     gap grows with the rank of the boundary it marks:

       group    two items of the same kind        one list row to the next
       section  two groups inside one section     the back link to the title block
       band     two sections on one surface, and a band's own padding
       surface  a change of surface               ink to paper, paper to footer

     `surface` is the only one that reaches the top of the scale, and only at
     1280 and up: the largest gap on this site is reserved for a change of
     ground. Every value is an existing step of the coarse scale - space-3
     through space-8 - and no new number enters the system. Each rung is exactly
     one step above the rung below it AT EVERY BREAKPOINT, so the ladder never
     collapses at a narrow width.

     docs/reviews/DS_TEACHING_SINGLE.md §5. */
  --tcf-rhythm-group:   var(--tcf-space-3);   /* 12 */
  --tcf-rhythm-section: var(--tcf-space-4);   /* 16 */
  --tcf-rhythm-band:    var(--tcf-space-5);   /* 28 */
  --tcf-rhythm-surface: var(--tcf-space-6);   /* 40 */

  /* The teaching artwork, in one place instead of three. It is `alt=""`, it is
     the show cover rather than per-episode art, and it is byte-identical on all
     892 teaching pages - so its size is a decision about how much of a fold a
     decoration may claim, and that decision deserves a name. 120px is not a new
     number: it is the value this element already used below 768px. */
  --tcf-teaching-art: 120px;

  /* Page gutters (§1.3). Set here and stepped down at the breakpoints below, so
     nothing has to restate them. */
  --tcf-gutter: 2.5rem;     /* 40px desktop */

  --tcf-container: 1280px;  /* content max width */
  --tcf-measure: 68ch;      /* prose column */
  --tcf-measure-lede: 56ch; /* a lede is shorter on purpose - it is read at a glance */

  /* Radius is 2px EVERYWHERE (§1.4). Nearly square: a bookish edge, not an
     app's. The single exception is a chip, which is a toggle rather than a
     button and reads as one only if it is round. */
  --tcf-radius: 2px;
  --tcf-radius-chip: 24px;

  /* -- Fields ---------------------------------------------------------------
     The one thing this system had no vocabulary for. Seven rules across five
     files each invented a padding, a type size, a border and a width for the
     same control, and NONE of them rendered: Blocksy sets `height` on every form
     control from --theme-form-field-height, and with border-box that swallows
     the padding. Measured before this block existed, every text input on the
     site was 40px tall whatever its stylesheet said.

     Three facts every rule that consumes these tokens depends on, all measured
     in a browser rather than reasoned about:

       1. `height: auto` is what makes the rest visible. Without it, nothing here
          renders. It binds without !important, and so does `min-height`.
       2. `padding` and `max-width` need !important on every surface, because
          Blocksy emits its form settings as inline CSS after every stylesheet.
       3. box-sizing is border-box everywhere, so the measures below are outer
          widths.

     MEASURES, not widths. §1.3 already speaks this way - --tcf-measure is 68ch
     of prose - and a field is the same idea: as wide as the value it holds,
     never as wide as the box it sits in. When the two disagree, the container
     moves. Sized against the shipped Public Sans at 16px, where 1ch is 9.69px
     and a real email address averages 8.4px per character.

     The audit, the bands and the four questions for choosing between them:
     docs/reviews/DESIGN_SYSTEM_FIELDS.md. */
  --tcf-field-pad-x:      var(--tcf-space-4);   /* 16px inline */
  --tcf-field-pad-y:      var(--tcf-space-3);   /* 12px block  */

  /* NOT a step in the type scale, and that is why it is a token: below 16px
     iOS Safari zooms the whole page when a field takes focus. Two files had
     already ruled this independently. */
  --tcf-field-text:       1rem;                 /* 16px - the iOS zoom floor */

  /* §5.8's 44px as a floor, not a height: a field computes to 48.4px and this
     never binds. It is here so smaller type cannot fall under the target. */
  --tcf-field-min-h:      2.75rem;              /* 44px */

  --tcf-field-border-w:   1px;

  /* The three measures a single-line field is allowed to be; `md` is the answer
     unless the data has a reason. Anything longer than `lg` is prose and takes a
     textarea at --tcf-measure-lede. */
  --tcf-field-measure-sm: 10rem;                /* 160px - bounded short data  */
  --tcf-field-measure-md: 20rem;                /* 320px - the default         */
  --tcf-field-measure-lg: 24rem;                /* 384px - unbounded one-line  */

  /* The border and the label are the ONLY things a dark surface may move. The
     fill does not: paper on the sign-in card is 14.40:1, so it carries WCAG
     1.4.11 alone - which is why that card's border is transparent. */
  --tcf-field-fill:       var(--tcf-page);
  --tcf-field-border:     var(--tcf-button-border);  /* 3.45:1 on paper  */
  --tcf-field-label:      var(--tcf-ink);            /* 16.85:1 on paper */

  /* -- Motion ---------------------------------------------------------------
     §1.7 is a complete list, not a starting point. Button and link hover
     colour, card border hover, accordion max-height, the mobile drawer - and
     nothing else on this site animates at all. A chip changing state is
     instant, deliberately: it is reporting a fact, not performing one.

     Every duration drops to 0ms under prefers-reduced-motion, at the bottom of
     this file. That is why they are tokens rather than literals. */
  --tcf-motion-hover:     120ms;
  --tcf-motion-accordion: 150ms;
  --tcf-motion-drawer:    200ms;
  --tcf-ease: ease;
}

/* Gutters step down with the viewport (§1.3): 40px desktop, 32px tablet, 20px
   mobile. Nothing horizontally scrolls at 320px, ever. */
@media (max-width: 1279px) { :root { --tcf-gutter: 2rem; }    /* 32px */ }
@media (max-width: 767px)  { :root { --tcf-gutter: 1.25rem; } /* 20px */ }

/* The rhythm ladder steps with the viewport, and only `surface` reaches the top
   of the scale. Min-width rather than max-width, so the ladder above reads as
   the phone case and each breakpoint states what it raises. */
@media (min-width: 768px) {
  :root {
    --tcf-rhythm-group:   var(--tcf-space-4);   /* 16 */
    --tcf-rhythm-section: var(--tcf-space-5);   /* 28 */
    --tcf-rhythm-band:    var(--tcf-space-6);   /* 40 */
    --tcf-rhythm-surface: var(--tcf-space-7);   /* 56 */
  }
}
@media (min-width: 1280px) {
  :root { --tcf-rhythm-surface: var(--tcf-space-8); }  /* 72 */
}

/* ---------------------------------------------------------------------------
   Hand the tokens to Blocksy's palette slots.

   Blocksy paints everything - buttons, links, borders, menus - from eight
   palette slots, so redefining the slots is far better than chasing individual
   selectors: the theme's own components follow automatically, and so does
   anything added later.

   NOTE THE SELECTOR. It is `html:root`, not `:root`, and that is deliberate.
   Blocksy ships its blue defaults in a `:root` block inside its compiled
   stylesheet, which the browser applies after this file. Same specificity means
   the later one wins, so a plain `:root` here loses - measured in a browser, not
   assumed. `html:root` scores one higher and wins regardless of order.

   The theme_mod_colorPalette filter in functions.php sets the same values at
   source, which is what the Customizer reads, and the editor palette in the
   same file is what the block editor shows. All THREE carry the same colours;
   change them together. A mismatch does not error - it makes the editor lie
   about the site.

   EIGHT SLOTS, SIX COLOURS. The handoff has six; Blocksy insists on eight. The
   mapping below spends the two spare slots on duplicates rather than inventing
   colours to fill them:

     1  brick        accent - links, buttons, active states
     2  brick hover  the darker brick, for hover and active
     3  ink          body text. The handoff sets body text to ink (§1.1), so
                     this is no longer a separate value from slot 4
     4  ink          headings - same colour, different Blocksy job
     5  rule         borders and dividers
     6  paper-alt    the alternating band and callout surface
     7  paper        Blocksy's "lighter background". In the old palette this was
                     a near-white distinct from the page; now paper IS the page,
                     so 7 and 8 are the same value
     8  paper        THE PAGE COLOUR - and read the warning below before you
                     touch it

   `muted` deliberately gets no slot. It is a text colour only, and every slot
   Blocksy owns it can also paint as a background; handing it a slot risks the
   theme filling a panel with a mid-grey that was only ever meant for a date.

   SLOT 8 IS THE TRAP. Blocksy uses palette-color-8 for two unrelated things:
   the page background, and the link colour inside a nav dropdown, because its
   dropdown panel is dark by default. Under the old palette slot 8 was #ffffff
   and the desktop dropdown was therefore white text - which, once the child
   theme lightened that panel, was white on white. That is fixed further down
   this file with an !important override, and the fix is load-bearing: slot 8 is
   now #FBF8F3, still near-white, so removing the override brings the bug
   straight back. The mobile off-canvas panel is a separate element and stays
   dark, where near-white links are correct (16.85:1) - do not "fix" that one.
   UI_UX_BRIEF.md §6 has the full account.
   --------------------------------------------------------------------------- */
html:root {
  --theme-palette-color-1: var(--tcf-accent);
  --theme-palette-color-2: var(--tcf-accent-strong);
  --theme-palette-color-3: var(--tcf-ink);
  --theme-palette-color-4: var(--tcf-ink);
  --theme-palette-color-5: var(--tcf-rule);
  --theme-palette-color-6: var(--tcf-surface);
  --theme-palette-color-7: var(--tcf-surface-soft);
  --theme-palette-color-8: var(--tcf-page);

  /* Blocksy's own base font becomes Public Sans, not the display face. Its
     components are UI - menus, buttons, widgets - and §1.2 gives UI to Public
     Sans. Headings take Newsreader back below. */
  --theme-font-family: var(--tcf-font-body);
  --theme-border-radius: var(--tcf-radius);
}

/* Headings in Newsreader, tightly led, and NEVER above weight 400 (§1.2).
   The variable font's range stops at 400, so asking for bold does not get a
   bolder Newsreader - it gets the browser's synthetic emboldening, which smears
   the letterforms and is the single most visible way to make a self-hosted font
   look cheap. Blocksy's heading defaults are 600 and 700, so this is stated
   rather than inherited. */
h1, h2, h3, h4, h5, h6,
.entry-title {
  font-family: var(--tcf-font-display);
  font-weight: 400;
  line-height: var(--tcf-leading-tight);
  color: var(--tcf-ink);
  text-wrap: balance;
}

/* Sizes come from the type scale rather than from Blocksy.
   Blocksy's defaults rendered an h2 LARGER than the h1 above it, so a page title
   was outranked by its own first subheading - which is not a matter of taste,
   it misstates the structure of the page to anyone skimming it.

   The ladder is the handoff's: page-title, section, card-title, and then the
   lede size. There is deliberately no step between card-title (24-30) and lede
   (17-19) in §1.2 - `stat` at 27px is a value display, not a heading rank, and
   giving it to h4 would make h4 the same size as h3 and reintroduce exactly the
   problem the paragraph above describes. h4 therefore takes the lede size and
   earns its rank from Newsreader against the surrounding Public Sans. */
h1, .entry-title {
  font-size: var(--tcf-text-page);
  font-weight: 300;                       /* §1.2: page titles are the light weight */
  line-height: var(--tcf-leading-display);
  letter-spacing: var(--tcf-tracking-display);
}
h2 {
  font-size: var(--tcf-text-section);
  line-height: var(--tcf-leading-tight);
  letter-spacing: var(--tcf-tracking-heading);
}
h3 {
  font-size: var(--tcf-text-card);
  line-height: var(--tcf-leading-card);
  letter-spacing: var(--tcf-tracking-heading);
}
h4 {
  font-size: var(--tcf-text-lede);
  line-height: var(--tcf-leading-card);
  letter-spacing: 0;
}
h5, h6 {
  font-size: var(--tcf-text-body);
  line-height: var(--tcf-leading-card);
  letter-spacing: 0;
}

/* The hero display size, for a homepage h1 that is meant to fill the screen. */
.tcf-display {
  font-family: var(--tcf-font-display);
  font-weight: 300;
  font-size: var(--tcf-text-display);
  line-height: var(--tcf-leading-display);
  letter-spacing: var(--tcf-tracking-display);
  text-wrap: balance;
}

/* §1.2 sets tracking by RENDERED SIZE - -0.02em at 40px and above, -0.01em from
   24 to 39px, 0 below - and the heading sizes are fluid, so a single value per
   element cannot be right at every width. These two queries switch each heading
   at the viewport width where its own clamp crosses 40px:

     h1  clamp(34px, 18px + 4vw, 52px)  crosses 40px at a 550px viewport
     h2  clamp(28px, 16px + 3vw, 40px)  reaches   40px at an 800px viewport

   Both numbers are solved from the clamps above rather than guessed; change a
   clamp and these move with it. */
@media (max-width: 549px) {
  h1, .entry-title { letter-spacing: var(--tcf-tracking-heading); }
}
@media (min-width: 800px) {
  h2 { letter-spacing: var(--tcf-tracking-display); }
}

/* An eyebrow is a label, never a heading element (§1.2) - it carries no
   document structure, and marking one up as an h2 tells a screen-reader user
   the page has a section that does not exist. */
.tcf-eyebrow {
  font-family: var(--tcf-font-body);
  font-size: var(--tcf-text-eyebrow);
  font-weight: 700;
  line-height: 1;
  letter-spacing: var(--tcf-tracking-eyebrow);
  text-transform: uppercase;
  color: var(--tcf-accent);
}

/* Headings need room above them and little below - they belong to what follows,
   not to what precedes. */
h2, h3, h4 { margin-top: var(--tcf-space-7); margin-bottom: var(--tcf-space-3); }

/* A page's own title already sits in its own header area; it does not need the
   same top gap as a heading in running text. */
.entry-title { margin-top: 0; }

/* Footer headings are labels for three short columns, not page-level headings.
   At the full h2 size they shouted louder than the page title. */
.tcf-footer h2,
.tcf-footer h3 {
  font-size: var(--tcf-text-lg);
  margin-top: 0;
}

/* Prose gets Public Sans at 17/1.75 (§1.2) on paper, in ink.

   This is the second half of the type reversal. The site read as a serif
   document; it now reads as a serif-headed page of clean sans prose, which is
   what the handoff asks for and what holds up better at 17px on a phone than an
   old-style serif does. */
body {
  font-family: var(--tcf-font-body);
  font-size: var(--tcf-text-body);
  line-height: var(--tcf-leading-body);
  color: var(--tcf-ink);
  background-color: var(--tcf-page);
}

/* `pretty` on paragraphs and list items: it costs nothing and it stops the
   single-word last line that makes a short paragraph look broken. */
p, li, dd, figcaption, blockquote { text-wrap: pretty; }

/* A block quote is prose, so it is set at the prose step.

   It was not. Nothing in this theme gave `.wp-block-quote` a size, so it fell
   through to Blocksy's own `--theme-font-size` at 16px - a value §1.2 does not
   contain and nobody chose. On What We Believe that put both creeds a single
   pixel under the 17px paragraphs immediately above and below them, which is a
   font change a reader can see and cannot explain. Measured at 1280 before the
   fix: paragraph 17, creed 16, paragraph 17.

   The quote is already marked as a quote by its brick rule and its indent; it
   does not need to be marked a second time by being slightly smaller. The
   leading stays tighter than prose (1.6 against 1.75) so the block still reads
   as set apart.

   `:not(.is-style-pull)` because the pull quote is a different component - 40px
   italic Newsreader, §1.2's one italic - and owns its own size.

   Element+class, not `.entry-content ...`, because Blocksy emits its inline CSS
   after this file: a bare `.wp-block-quote` here would tie on specificity and
   lose on order. */
blockquote.wp-block-quote:not(.is-style-pull),
blockquote.wp-block-quote:not(.is-style-pull) > p {
  font-size: var(--tcf-text-body);
  line-height: var(--tcf-leading-sm);
}

/* THE LEDE IS BODY TEXT. 17px / 1.75, the same as the paragraphs around it.

   A lede is the paragraph that opens a page. It is read at a glance rather than
   settled into, and since 2026-09-07 the measure is what says so rather than
   the size.

   §1.2 draws a lede at 19/1.65 and the site shipped that. Jay reported the step
   on /life-together/home-groups/, where a 19px lede stood above two 17px
   paragraphs in the same column and read as one paragraph changing size
   halfway. That page was settled by taking the class off. On 2026-09-07 he
   ruled it for the whole site: "make all the ledes 17px for consistency".

   THE SIZE MOVES, NOTHING ELSE DOES. Each lede class keeps its measure, its
   margins and its colour - those are what make it a lede now. Stripping the
   classes would have taken the measure with the size and run these paragraphs
   the full width of their bands. `--tcf-text-lede` is NOT retuned either: it
   also sizes every h4 on the site, and retuning it would move headings nobody
   asked about.

   THE LEADING MOVES WITH IT. Measured on home groups at 1280 with the class
   put back: at 17/1.65 over 17/1.75 body the opening block is still visibly
   tighter than the two beneath it - the same defect one notch quieter. At
   17/1.75 the three paragraphs are one texture. See DECISIONS_TO_REVIEW.md
   §23a. */
.tcf-lede {
  font-size: var(--tcf-text-body);
  line-height: var(--tcf-leading-body);
  max-width: var(--tcf-measure-lede);
}

/* Small print, metadata and controls take the UI stack - which is now the same
   family the body uses, so this block no longer switches typeface. It stays
   because the rules below still name it, and because the day someone gives
   metadata a different face, this is the list of what "metadata" means. */
.tcf-teaching-meta,
.tcf-teaching-card__meta,
.tcf-latest-teaching__meta,
button, input, select, textarea {
  font-family: var(--tcf-font-ui);
}

/* ---------------------------------------------------------------------------
   Links

   §1.1: "Define `a` and `a:hover` globally - do not leave defaults." So the base
   treatment is on the bare element rather than only inside .entry-content, and
   the underline is a real colour of its own: brick text with a 1px #D7B4A8
   underline, which on hover darkens to #7A3324 with the underline coming up to
   full brick. The underline strengthening is the point - it means the hover is
   legible to someone who cannot tell the two reds apart.

   A bare `a` selector is (0,0,1), so every rule further down this file that
   gives a link its own colour still wins, and so does Blocksy's `.ct-menu-link`.
   That is deliberate: this sets the default for prose links and does not fight
   anything that has already decided.

   The underline is never removed in running text. Removing it would leave colour
   as the only signal, which fails for anyone who cannot distinguish it. */
a {
  color: var(--tcf-accent);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--tcf-link-underline);
  text-underline-offset: 0.15em;
  transition:
    color var(--tcf-motion-hover) var(--tcf-ease),
    text-decoration-color var(--tcf-motion-hover) var(--tcf-ease);
}
a:hover {
  color: var(--tcf-accent-strong);
  text-decoration-color: currentColor;
}

.entry-content a:not(.wp-block-button__link):not(.wp-element-button):not(.tcf-teaching-card a):not(.tcf-latest-teaching a):not(.tcf-selector__tab):not(.tcf-selector__cta):not(.tcf-hero-teaching__title):not(.tcf-hero-teaching__play):not(.tcf-whats-on a):not(.tcf-dir a):not(.tcf-cal a) {
  color: var(--tcf-accent);
  text-decoration: underline;
  text-decoration-color: var(--tcf-link-underline);
  text-underline-offset: 0.15em;
}

/* Cards carry their own link treatment. Inside .entry-content - which is where
   the latest-teaching block sits on the home page - the prose underline rule was
   also catching the card's title, series label and metadata, so the same card
   looked different on the home page and in the archive. */
.tcf-teaching-card a,
.tcf-latest-teaching a { text-decoration: none; }
.tcf-teaching-card a:hover,
.tcf-latest-teaching__more a:hover { text-decoration: underline; }
.entry-content a:not(.wp-block-button__link):not(.wp-element-button):not(.tcf-teaching-card a):not(.tcf-latest-teaching a):not(.tcf-selector__tab):not(.tcf-selector__cta):not(.tcf-hero-teaching__title):not(.tcf-hero-teaching__play):not(.tcf-whats-on a):not(.tcf-dir a):not(.tcf-cal a):hover {
  color: var(--tcf-accent-strong);
}

/* ---------------------------------------------------------------------------
   Focus

   §5.4: a 2px brick outline at 2px offset, on EVERY focusable element, and
   never `outline: none` without a replacement. One rule rather than a per
   component one, because the failure mode of per-component focus styling is a
   control somebody adds later that quietly has none.

   `html :is(...)` rather than a bare list: Blocksy sets its own focus styling,
   and one extra element in the selector is what wins without reaching for
   !important. This is the same trick as the palette and the header height - see
   the note above html:root. It has not been measured in a browser yet; if a
   control turns up with a dashed blue ring, that is Blocksy still winning and
   the fix is more specificity, not a different colour.

   :focus-visible rather than :focus, so a mouse click on a button does not leave
   a ring behind it - but keyboard focus always shows. */
html :is(a, button, input, select, textarea, summary, details, [tabindex], [contenteditable]):focus-visible {
  outline: 2px solid var(--tcf-accent);
  outline-color: var(--tcf-accent);
  outline-offset: 2px;
}

/* ---------------------------------------------------------------------------
   Motion

   The complete permitted list (§1.7) is four transitions:

     button and link hover colour   120ms ease   (on `a` above, and on buttons)
     card border hover              120ms ease
     accordion open/close           150ms ease   on max-height
     mobile drawer                  200ms ease   on transform

   A chip changing state is instant, deliberately. Everything else on this site
   is static, and "everything else" includes the box-shadow fades and 150ms
   easings that were here before this section existed - they have been removed
   rather than retimed.

   If you are adding an animation, the question is not how long it should run.
   It is which of the four lines above it is, and if it is none of them it does
   not ship.
   --------------------------------------------------------------------------- */

.tcf-accordion__panel {
  overflow: hidden;
  transition: max-height var(--tcf-motion-accordion) var(--tcf-ease);
}

.tcf-drawer {
  transition: transform var(--tcf-motion-drawer) var(--tcf-ease);
}

/* ---------------------------------------------------------------------------
   Stated preferences

   Two media queries, both required by §5.6, and both implemented by moving
   TOKENS rather than by restating rules. That is the whole reason the durations
   and the two neutrals are tokens in the first place.
   --------------------------------------------------------------------------- */

/* Reduce motion: every duration in the list above goes to 0ms. The blanket rule
   underneath it is not redundant - it catches Blocksy's own transitions and any
   animation a plugin brings with it, which our tokens cannot reach. Durations
   go to 0.01ms rather than 0 in the blanket rule so that transitionend and
   animationend still fire and any script waiting on one does not hang. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --tcf-motion-hover: 0ms;
    --tcf-motion-accordion: 0ms;
    --tcf-motion-drawer: 0ms;
  }

  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* More contrast: `rule` strengthens and `muted` collapses into ink (§5.6).
   Because the palette slots above are declared as var(--tcf-rule) rather than as
   literals, slot 5 follows this automatically and so does every Blocksy border
   painted from it.

   Worth knowing what this does and does not buy. Muted going to ink takes
   secondary text from 5.64:1 to 16.85:1, which is a real gain. Rule going to
   #C9BFAE takes a hairline from 1.24:1 to 1.72:1 against paper, which is
   visibly stronger but still nowhere near the 3:1 WCAG asks of a meaningful UI
   boundary. Hairlines here are decorative separators, so that is defensible;
   a border that is the ONLY thing marking a control is not, and needs its own
   answer. See DESIGN_SYSTEM.md. */
@media (prefers-contrast: more) {
  :root {
    --tcf-rule: #C9BFAE;
    --tcf-muted: var(--tcf-ink);
  }
}

/* ---------------------------------------------------------------------------
   Measure

   The site is prose. A paragraph running the full 1290px container is around
   130 characters per line, roughly twice what anyone reads comfortably - the eye
   loses its place coming back to the start of the next line.

   THE PART THAT IS EASY TO GET WRONG, because a first attempt got it wrong:

   `.entry-content` is NOT a container. It spans the full viewport with no
   padding. Its children only appear to sit in a gutter because WordPress's
   constrained layout gives each of them `max-width: <container>` plus
   `margin-left/right: auto !important`, which centres them. The gutter is a
   side effect of that centring, not a property of the parent.

   So narrowing the children while left-aligning them - the obvious move - puts
   the prose hard against the edge of the window, because there was never a
   gutter to keep. It has to be done in two steps:

     1. give `.entry-content` the same container width the page title already
        has, so the gutter belongs to the parent and survives on its own
     2. only then constrain the children and align them left, where left now
        means the container's edge rather than the window's

   Both steps are required. Either alone is broken.
   --------------------------------------------------------------------------- */

/* Step 1: entry-content becomes a real container, matching .entry-header so the
   prose lines up with the page title above it.

   This reproduces Blocksy's own container formula rather than hard-coding a
   width, because the container is not a fixed number - it is the smaller of the
   maximum width and a percentage of the viewport, and the percentage itself
   changes on small screens (90vw down to 88vw). A fixed 1290px matched only at
   desktop and left the prose against the window edge at every width below it.
   Using both of Blocksy's variables tracks all of that automatically, including
   any future change made in the Customizer. */
.entry-content {
  width: min(
    var(--theme-normal-container-max-width, 1290px),
    var(--theme-container-edge-spacing, 90vw)
  );
  max-width: 100%;
  margin-left: auto;
  margin-right: auto;
}

/* Step 2: text-level blocks take the measure and align to that container's edge.
   The !important is needed to beat WordPress's own !important auto margins;
   without it the blocks re-centre inside the container and drift away from the
   title. */
.entry-content > p,
.entry-content > ul,
.entry-content > ol,
.entry-content > blockquote,
.entry-content > h2,
.entry-content > h3,
.entry-content > h4,
.entry-content > .tcf-draft,
.tcf-prose > p,
.tcf-prose > ul,
.tcf-prose > ol,
.tcf-prose > blockquote {
  max-width: var(--tcf-measure);
  margin-left: 0 !important;
  margin-right: auto !important;
}

/* Images, the map and anything the editor widened are meant to be wide; they
   keep the container width and stay centred. */
.entry-content > figure,
.entry-content > .wp-block-image,
.entry-content > .tcf-map,
.entry-content > .alignwide,
.entry-content > .aligncenter {
  max-width: none;
  margin-left: auto !important;
  margin-right: auto !important;
}

/* Full-bleed blocks - the home page hero - must still reach both edges of the
   window. Now that the parent is 1290px rather than the viewport, they need the
   standard break-out rather than relying on the parent already being full width. */
.entry-content > .alignfull {
  width: 100vw;
  max-width: 100vw;
  margin-left: calc(50% - 50vw) !important;
  margin-right: calc(50% - 50vw) !important;
}

/* ---------------------------------------------------------------------------
   Teachings

   Structural only - rhythm, alignment, hit areas. No colour or type decisions
   beyond inheriting Blocksy's, because the design direction is not chosen yet
   (punch list Part Three). Everything here should survive that decision.
   --------------------------------------------------------------------------- */

/* Metadata on a single teaching: a definition-style list that stays legible when
   a teaching has one facet or all four. */
.tcf-teaching-meta {
  list-style: none;
  margin: 0 0 1.75rem;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 2rem;
}
.tcf-teaching-meta__item { display: flex; flex-direction: column; gap: 0.15rem; }
/* An eyebrow, so it takes the eyebrow tokens. The `opacity: 0.65` this used to
   carry is gone: opacity produces a colour nothing has measured, and a contrast
   table that does not know about it is a contrast table that is wrong. --tcf-muted
   is 5.64:1 on paper and is in the table. */
.tcf-teaching-meta__label {
  font-size: var(--tcf-text-eyebrow);
  font-weight: 700;
  letter-spacing: var(--tcf-tracking-eyebrow);
  text-transform: uppercase;
  color: var(--tcf-muted);
}
.tcf-teaching-meta__value { font-size: var(--tcf-text-body-sm); }

.tcf-teaching-player { margin: 0 0 2rem; }
.tcf-teaching-player__download { margin: 0.5rem 0 0; font-size: var(--tcf-text-meta); }
.tcf-teaching-noaudio { margin: 0 0 2rem; opacity: 0.75; font-style: italic; }

.tcf-teaching-series-nav,
.tcf-teaching-back { margin-top: 2.5rem; }

/* Browse panel. The whole point of splitting the old overloaded category into
   four taxonomies, so it gets prominence at the top of the archive. */
/* ---------------------------------------------------------------------------
   Teaching filters

   One row of dropdowns rather than three open lists. The open version ran 127px
   on a desktop and 356px on a phone, pushing the first teaching below the fold on
   an archive that exists to show teachings.

   <details> does the opening and closing, so this works with JavaScript off. The
   active filter is named on its own button, so the state is readable without
   opening anything.
   --------------------------------------------------------------------------- */
.tcf-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--tcf-space-2);
  margin: 0 0 var(--tcf-space-5);
  /* No `padding-bottom` either: it was holding the controls off the bottom rule
     that is now gone, so it was buying nothing and it was 16px of the height the
     count line needed. Measured at 1440 the row is 60px with it and 44px
     without, which is the search field plus nothing. */
  padding: 0;
  /* No `border-bottom`. `.tcf-teaching-list` already draws a top rule 28px
     below this one, so the page carried two parallel hairlines with nothing
     between them at every width: measured at 1440, y=504.3 and y=533.3. The
     list's rule is the structural one - it is the top edge of the row set and
     matches the `border-bottom` on every `.tcf-teaching-row` - so this is the
     one that goes, and the count line now sits in the gap it opened. */
  font-family: var(--tcf-font-ui);
  font-size: var(--tcf-text-sm);
}

.tcf-filter { position: relative; }

.tcf-filter__toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
  padding: 0.45em 0.85em;
  border: 1px solid var(--tcf-rule);
  /* The one exception to the 2px rule (§1.4). A chip is a toggle rather than a
     button and only reads as one if it is round. */
  border-radius: var(--tcf-radius-chip);
  background: var(--tcf-page);
  color: var(--tcf-body);
  cursor: pointer;
  list-style: none;          /* Firefox */
  white-space: nowrap;
}
.tcf-filter__toggle::-webkit-details-marker { display: none; }
.tcf-filter__toggle:hover { border-color: var(--tcf-accent); color: var(--tcf-accent); }
.tcf-filter__toggle:focus-visible { outline: 2px solid var(--tcf-accent); outline-offset: 2px; }

/* A filter in force names itself, so the state is legible without opening it. */
.tcf-filter.is-active .tcf-filter__toggle {
  border-color: var(--tcf-accent);
  background: var(--tcf-accent);
  color: var(--tcf-page);
}
.tcf-filter__chosen { font-weight: 600; }
.tcf-filter.is-active .tcf-filter__label { opacity: 0.75; }
.tcf-filter__label::after { content: ":"; }
.tcf-filter:not(.is-active) .tcf-filter__label::after { content: ""; }

.tcf-filter__caret {
  width: 0; height: 0;
  border-style: solid;
  border-width: 4px 4px 0 4px;
  border-color: currentColor transparent transparent transparent;
  opacity: 0.7;
}
.tcf-filter[open] .tcf-filter__caret { transform: rotate(180deg); }

.tcf-filter__panel {
  position: absolute;
  z-index: 20;
  top: calc(100% + 6px);
  left: 0;
  min-width: 15rem;
  max-height: 60vh;
  overflow-y: auto;
  padding: var(--tcf-space-2);
  background: var(--tcf-page);
  border: 1px solid var(--tcf-rule);
  border-radius: var(--tcf-radius);
}
.tcf-filter__list { list-style: none; margin: 0; padding: 0; }
.tcf-filter__link {
  display: flex;
  justify-content: space-between;
  gap: var(--tcf-space-4);
  padding: 0.4em 0.6em;
  border-radius: var(--tcf-radius);
  color: var(--tcf-body);
  text-decoration: none;
}
.tcf-filter__link:hover { background: var(--tcf-surface); color: var(--tcf-accent); }
.tcf-filter__link.is-current { color: var(--tcf-accent); font-weight: 600; }
.tcf-filter__count { color: var(--tcf-muted); font-variant-numeric: tabular-nums; }

.tcf-filters__clear { color: var(--tcf-muted); text-decoration: underline; padding: 0.45em 0.3em; }
.tcf-filters__clear:hover { color: var(--tcf-accent); }

/* On a phone the panel is anchored to the row rather than to its chip, so it
   cannot open off the edge of the screen: a 15rem panel hung off the Series
   chip at x=206.6 would run to 446.6 in a 330px viewport.

   `.tcf-filters` MUST carry `position: relative` for that to work. Without it
   the panel's containing block resolved all the way up to an unclassed Blocksy
   wrapper measuring 3,717px, and `top: calc(100% + 6px)` computed against that:
   measured at 375 on 2026-09-07, the panel opened at y=3722.8 against a toggle
   whose bottom edge was y=616.6. 3,106px below its own button, on every phone,
   which made the filters look like they simply did nothing. 3717 + 6 = 3723.

   And no `overflow` on this element. `overflow-x: auto` computes `overflow-y`
   to `auto` as well, which makes the row a scroll container - and a scroll
   container clips an absolutely positioned descendant whose containing block is
   inside it. So the sideways-scrolling row and the row-anchored panel cannot
   both be had on this markup, and the panel wins: a filter you cannot see is a
   filter that does not exist.

   The row therefore wraps, and the sideways-scroll rules that used to sit here
   are gone rather than overridden. They had already been dead for some time -
   `@media (max-width: 767px)` below restores `flex-wrap: wrap` and is later in
   this file at equal specificity, so `nowrap` never applied. Two blocks that
   silently fought; now they do not overlap at all. See
   docs/reviews/PUNCHLIST_LAYOUT.md §1.1 for the height arithmetic and why the
   documented 56px row is not recoverable (it predates the search form). */
@media (max-width: 600px) {
  .tcf-filters { position: relative; }
  .tcf-filter { position: static; }
  .tcf-filter__panel { left: 0; right: 0; min-width: 0; }
}

/* Listing. `.tcf-teaching-list`'s own reset (list-style/margin/padding) is
   declared under "Teaching cards" below and again in the archive row section;
   the copy that used to sit here restated the same three values and rendered
   nothing. */
.tcf-teaching-list__item + .tcf-teaching-list__item {
  margin-top: 2rem;
  padding-top: 2rem;
  border-top: 1px solid currentColor;
  border-color: color-mix(in srgb, currentColor var(--tcf-hairline-alpha), transparent);
}
/* ---------------------------------------------------------------------------
   Teaching cards

   The archive is the most-used part of this site and the part most likely to be
   browsed rather than read. A card therefore has to answer four questions at a
   glance - what is it, who preached it, when, and how long - and then let
   someone start listening without going anywhere.

   Structure: artwork left, everything else right, actions last. The artwork is
   the podcast cover unless a teaching has its own image; repeated down a list it
   reads as a set rather than as a gap, which is the point.
   --------------------------------------------------------------------------- */
.tcf-teaching-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--tcf-space-4);
}
/* Blocksy and the block-library list styles both put margin on list items, and
   an article inside one picks up its own. Together they added 67px between
   cards on top of the grid gap, which read as a separator rule rather than as
   spacing. The grid owns the gap; nothing else should contribute to it. */
.tcf-teaching-list > .tcf-teaching-list__item,
.entry-content .tcf-teaching-list > .tcf-teaching-list__item {
  margin: 0;
  padding: 0;
}
.tcf-teaching-list > .tcf-teaching-list__item > .tcf-teaching-card {
  margin: 0;
}

.tcf-teaching-card {
  display: grid;
  grid-template-columns: 88px 1fr;
  gap: var(--tcf-space-4);
  align-items: start;
  padding: var(--tcf-space-4);
  background: var(--tcf-page);
  border: 1px solid var(--tcf-rule);
  border-radius: var(--tcf-radius);
  /* §1.4: a card hover moves its border and nothing else. The box-shadow that
     used to fade in here has gone rather than been retimed - cards in this
     system have no shadow at all, and a lifting card is a different design
     language from the one the handoff describes. */
  transition: border-color var(--tcf-motion-hover) var(--tcf-ease);
}
.tcf-teaching-card:hover {
  border-color: var(--tcf-accent);
}
/* `is-open` is the player being on screen at all, `is-playing` only while sound is
   coming out. A card whose teaching is paused is still the card you are listening
   to, so it keeps the highlight. */
.tcf-teaching-card.is-playing,
.tcf-teaching-card.is-open {
  border-color: var(--tcf-accent);
  background: var(--tcf-surface-soft);
}

.tcf-teaching-card__art {
  display: block;
  line-height: 0;
  border-radius: var(--tcf-radius);
  overflow: hidden;
  background: var(--tcf-surface);
}
.tcf-teaching-card__art img {
  width: 100%;
  height: auto;
  aspect-ratio: 1;
  object-fit: cover;
  display: block;
}

.tcf-teaching-card__body { min-width: 0; }   /* let long titles wrap, not overflow */

/* The series, as a quiet label above the title. Someone browsing an archive is
   usually looking for a series rather than a single talk. */
.tcf-teaching-card__eyebrow {
  margin: 0 0 var(--tcf-space-1);
  font-family: var(--tcf-font-body);
  font-size: var(--tcf-text-eyebrow);
  font-weight: 700;
  letter-spacing: var(--tcf-tracking-eyebrow);
  text-transform: uppercase;
  color: var(--tcf-muted);
}
.tcf-teaching-card__eyebrow a { color: inherit; text-decoration: none; }
.tcf-teaching-card__eyebrow a:hover { color: var(--tcf-accent); }

.tcf-teaching-card__title {
  margin: 0 0 var(--tcf-space-2);
  font-size: var(--tcf-text-lg);
  line-height: 1.25;
}
.tcf-teaching-card__title a { color: var(--tcf-ink); text-decoration: none; }
.tcf-teaching-card__title a:hover { color: var(--tcf-accent); }

.tcf-teaching-card__meta {
  margin: 0 0 var(--tcf-space-3);
  font-family: var(--tcf-font-ui);
  font-size: var(--tcf-text-sm);
  color: var(--tcf-muted);
}
.tcf-teaching-card__meta a { color: inherit; }
.tcf-teaching-card__meta a:hover { color: var(--tcf-accent); }
.tcf-teaching-card__sep { margin: 0 0.45em; opacity: 0.55; }
.tcf-teaching-card__length { white-space: nowrap; }

.tcf-teaching-card__excerpt {
  margin: 0 0 var(--tcf-space-3);
  font-size: var(--tcf-text-base);
  color: var(--tcf-body);
  max-width: var(--tcf-measure);
}

.tcf-teaching-card__actions {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--tcf-space-3);
  font-family: var(--tcf-font-ui);
  font-size: var(--tcf-text-sm);
}

/* Listen is the primary action and looks like one. Download is deliberately
   quiet - useful, but not what most people came to do. */
.tcf-teaching-card__play {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5em;
  /* §5.8's 44px floor, which Jay's 2026-08-08 AA ruling kept strict for media
     transports specifically: a transport is not a line of text that happens to
     be tappable, it is the object the page exists for and it is pressed with a
     thumb. `check_design.py` checks it separately for that reason
     (MIN_TRANSPORT_PX) and was failing this control at 83.4x39.1 on /members/ at
     every width - 24.5px of line plus 2 x 6.3px of padding plus the border. The
     padding is left alone so the label keeps its optical inset; the floor does
     the work, and 39.1 -> 44 costs 4.9px in one row of a card that is 300px
     tall.

     Why this survived every crawl the project has run, which is the interesting
     part: the card block renders on `/members/` and nowhere else, and `/members/`
     answers a stranger with the login form under an HTTP 200, so an anonymous
     checker measures the login form and reports the page clean. The one place
     the same class appears in public is the home hero, and that variant pins
     itself to 52px, so the floor never binds there and the class looked fine
     wherever anyone could see it. It took a signed-in measurement to find. */
  min-height: 44px;
  padding: 0.45em 1em 0.45em 0.85em;
  border: 1px solid var(--tcf-accent);
  border-radius: var(--tcf-radius);   /* a button, not a chip - 2px (§1.4) */
  color: var(--tcf-accent);
  text-decoration: none;
  font-weight: 600;
  transition:
    background-color var(--tcf-motion-hover) var(--tcf-ease),
    color var(--tcf-motion-hover) var(--tcf-ease);
}
.tcf-teaching-card__play:hover,
.tcf-teaching-card__play:focus-visible {
  background: var(--tcf-accent);
  color: var(--tcf-page);
}
.tcf-teaching-card__play-icon {
  width: 0; height: 0;
  border-style: solid;
  border-width: 5px 0 5px 8px;
  border-color: transparent transparent transparent currentColor;
}
/* Playing, the same span becomes the pause glyph: two bars drawn with the left and
   right borders of a box, the way the triangle is drawn with one border. §1.9
   permits exactly three glyphs and forbids an icon set, so no icon arrives here. */
.tcf-teaching-card.is-playing .tcf-teaching-card__play-icon {
  width: 9px; height: 10px;
  border-width: 0 3px;
  border-color: currentColor;
}

/* `display: inline-flex` above beats the browser's own `[hidden] {display:none}`,
   so the script could set hidden and the button stayed on screen next to the
   player it had just opened. Any element given an explicit display needs this
   said again. */
.tcf-teaching-card__play[hidden] { display: none; }

.tcf-teaching-card__download { color: var(--tcf-muted); text-decoration: none; }
.tcf-teaching-card__download:hover { color: var(--tcf-accent); text-decoration: underline; }

/* The inline timeline, once someone presses Listen.

   It no longer wraps and no longer needs to. The native <audio> that used to sit
   here would not shrink below about 200px in Chrome whatever min-width said, so
   in the member hub's 380px column it pushed Close past the card border; the
   range input has no such floor. */
.tcf-teaching-card__player {
  flex: 1 1 100%;
  /* No `order: -1` any more. It used to put the player where the Listen button
     had been, because the button was hidden the moment you pressed it. The button
     is now the play/pause control and stays, so the timeline belongs under it -
     which is also where the hero and the row have always put it. */
  margin-top: var(--tcf-space-3);
}

/* ---------------------------------------------------------------------------
   The teaching timeline

   One component for all three presentations - the hero's floating card, the
   archive row and the block's card - because two players behaving differently on
   one site is its own defect.

   It is a <input type="range">, which buys the slider role, the focus ring,
   arrows, Home, End and both Page keys for nothing, and leaves only the painting
   to us. The painting is a track and a thumb: a hairline in the rule colour with
   the played part filled in brick, and a small brick dot on it. §1.9 forbids an
   icon set and the design is flat, so there is no scrubber graphic and no shadow
   - this is the same 1px-rule vocabulary the card border uses.
   ------------------------------------------------------------------------ */
.tcf-scrub {
  display: flex;
  align-items: center;
  gap: var(--tcf-space-3);
  /* Without this the row's min-content floor is the clock's nowrap width plus
     the input's intrinsic width, and at 320px in the member hub's card the
     "0:02 / 21:06" was cut off by the card border. The clock keeps its width;
     the track gives way. */
  min-width: 0;
}

.tcf-scrub__bar {
  --tcf-scrub-pct: 0%;             /* the played fraction; the script sets it */
  flex: 1 1 auto;
  min-width: 0;
  /* 44px of input around a 4px line. The visible timeline is a hairline, but a
     hairline is not a tap target (§5.8) - so the control keeps its full height
     and the track is drawn centred inside it. `height` is stated rather than
     `auto` because Blocksy sizes every form control from --theme-form-field-height
     and would otherwise make this 40px; `padding` needs !important against the
     same sheet, which is why there is none. */
  height: 44px;
  margin: 0;
  border: 0;
  background: transparent;
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
}
/* The three painted parts are named rather than stated, so the same component
   can be moved onto a dark ground without being forked. The fallbacks ARE the
   paper values, so nothing on the archive, the member hub or the home hero
   changes: brick on the played part, the rule hairline behind it. The on-ink
   variant is set on `.tcf-teaching-hero .tcf-scrub` and nowhere else. */
.tcf-scrub__bar::-webkit-slider-runnable-track {
  height: 4px;
  border-radius: var(--tcf-radius);
  background:
    linear-gradient(var(--tcf-scrub-played, var(--tcf-accent)), var(--tcf-scrub-played, var(--tcf-accent)))
      left / var(--tcf-scrub-pct) 100% no-repeat,
    var(--tcf-scrub-track, var(--tcf-rule));
}
.tcf-scrub__bar::-moz-range-track {
  height: 4px;
  border-radius: var(--tcf-radius);
  background:
    linear-gradient(var(--tcf-scrub-played, var(--tcf-accent)), var(--tcf-scrub-played, var(--tcf-accent)))
      left / var(--tcf-scrub-pct) 100% no-repeat,
    var(--tcf-scrub-track, var(--tcf-rule));
}
.tcf-scrub__bar::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 12px;
  height: 12px;
  margin-top: -4px;                /* centre the dot on the 4px track */
  border: 0;
  border-radius: 50%;
  background: var(--tcf-scrub-thumb, var(--tcf-accent));
}
.tcf-scrub__bar::-moz-range-thumb {
  width: 12px;
  height: 12px;
  border: 0;
  border-radius: 50%;
  background: var(--tcf-scrub-thumb, var(--tcf-accent));
}
/* Between pressing play and the file reporting its length there is nothing to
   scrub to. Dimmed rather than hidden, so the row does not change shape. */
.tcf-scrub__bar:disabled { cursor: default; opacity: 0.45; }

.tcf-scrub__time {
  flex: none;
  font-family: var(--tcf-font-ui);
  font-size: var(--tcf-text-sm);
  font-variant-numeric: tabular-nums;   /* or the row twitches once a second */
  color: var(--tcf-scrub-clock, var(--tcf-muted));
  white-space: nowrap;
}

/* ---------------------------------------------------------------------------
   The transport

   The same 48px circle the archive row has always had: warm fill, a brick
   triangle drawn with borders because §1.9 permits three glyphs and forbids an
   icon set. Two bars while sound is coming out, a triangle when it is not.

   `.tcf-teaching-row__play` is the row's; `.tcf-player__play` is the single
   teaching page's, built by the script that replaces the browser's own bar.
   They are one control with two homes, which is the point - two players
   behaving differently on one site is its own defect.

   48px, not 44: it is above the §5.8 floor rather than exactly on it, and it is
   the reason this control exists at all. The native <audio controls> it replaces
   measured height 0 in Chromium at every viewport at or below 500px, 31px in
   WebKit and 40px in Firefox - so on a phone the page whose one job is to play a
   recording had nothing on it to press.
   ------------------------------------------------------------------------ */
.tcf-player__play {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  box-sizing: border-box;
  width: 48px;
  height: 48px;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 50%;
  /* Blocksy gives every button its own fill, radius and min-height from the
     theme's form variables; a bare `background` would lose to it on a page where
     the player sits inside .entry-content. Stated flat, and appearance reset. */
  -webkit-appearance: none;
  appearance: none;
  background-color: var(--tcf-play-fill);
  box-shadow: none;
  cursor: pointer;
  transition: background-color 120ms ease;
  font: inherit;
  /* Stated, and neither inherited nor left to the UA. The button's accessible
     name is a .screen-reader-text span inside it, which is real text sitting on
     the button's own fill - so its colour is measured whether or not anyone can
     see it. A <button>'s UA `color` is `buttontext`, pure black and off-palette;
     inheriting instead gives on-ink body, 1.76:1 against the warm fill. Ink is
     14.67:1 on the resting fill and 9.91:1 on the playing one, and passes in
     both states. It is clipped to a pixel, but "you cannot see it" is not the
     standard. */
  color: var(--tcf-ink);
}
.tcf-player__play-icon {
  width: 0;
  height: 0;
  margin-left: 3px;                        /* optical centring of a triangle */
  border-top: 6px solid transparent;
  border-bottom: 6px solid transparent;
  border-left: 10px solid var(--tcf-play-glyph, var(--tcf-accent));
}
.tcf-player__play:hover,
.tcf-player__play:focus-visible {
  background-color: var(--tcf-play-fill-hover, var(--tcf-rule));
}
.tcf-player.is-playing .tcf-player__play {
  background-color: var(--tcf-play-fill-on, var(--tcf-accent));
}
.tcf-player.is-playing .tcf-player__play-icon {
  width: 11px;
  height: 12px;
  margin-left: 0;                          /* the triangle's optical offset, undone */
  border-width: 0 3px;
  border-style: solid;
  border-color: var(--tcf-play-glyph-on, var(--tcf-page));
}

/* The timeline beside it. `.tcf-scrub` itself sets no flex - the row, the card
   and the home hero each place it their own way - so the single teaching page
   states its own. 10rem is the basis, not a floor: the track gives way and the
   clock keeps its width, which is what `min-width: 0` on .tcf-scrub buys. */
.tcf-player__scrub { flex: 1 1 10rem; }

/* With the script running the <audio> plays and no longer draws. `display` has
   to be said: `.tcf-player__audio` above sets `display: block`, which would
   otherwise leave a full-width flex item of no height in the middle of the bar.
   Without the script the element keeps `controls` and this class never lands. */
.tcf-player--js .tcf-player__audio { display: none; }

/* On a phone the artwork shrinks rather than disappearing - it is what makes the
   list scannable, and a column of text blocks is harder to scan than a column of
   pictures with text beside them. */
@media (max-width: 600px) {
  .tcf-teaching-card {
    grid-template-columns: 56px 1fr;
    gap: var(--tcf-space-3);
    padding: var(--tcf-space-3);
  }
}

.tcf-teaching-empty { opacity: 0.75; font-style: italic; }

@media (max-width: 600px) {
  .tcf-teaching-meta { gap: 0.75rem 1.25rem; }
  .tcf-teaching-browse { gap: 1.25rem; }
}

.tcf-teaching__header { margin: 0 0 1.5rem; }
.tcf-teaching__title { margin: 0; }
.tcf-teaching-archive__header { margin: 0 0 2rem; }
/* `.tcf-teaching-archive__title`'s margin is set with the rest of its type in
   the archive header section (canvas 2c); the copy that used to sit here was
   its only declaration and was restated there. */
.tcf-teaching-archive__intro { max-width: var(--tcf-measure); opacity: 0.8; }

.tcf-teaching-player__audio { width: 100%; display: block; }
.tcf-teaching-player__actions {
  margin: 0.6rem 0 0;
  display: flex;
  gap: 1.25rem;
  flex-wrap: wrap;
  font-size: var(--tcf-text-body-sm);
}

/* ---------------------------------------------------------------------------
   Player
   Artwork alongside the controls, the way podcast apps present an episode.
   The <audio> element is the browser's own - accessible and dependable.
   --------------------------------------------------------------------------- */
.tcf-player {
  display: flex;
  gap: 1.25rem;
  align-items: flex-start;
  margin: 0 0 2rem;
  padding: 1.1rem;
  border: 1px solid currentColor;
  border-color: color-mix(in srgb, currentColor var(--tcf-hairline-alpha), transparent);
  border-radius: var(--tcf-radius);
  background: color-mix(in srgb, currentColor var(--tcf-panel-alpha), transparent);
}
.tcf-player__art {
  width: 120px; height: 120px;
  flex: 0 0 auto;
  object-fit: cover;
  border-radius: var(--tcf-radius);
  display: block;
}
.tcf-player__body { flex: 1 1 auto; min-width: 0; margin: 0; }
.tcf-player__show {
  margin: 0;
  font-size: var(--tcf-text-eyebrow);
  font-weight: 700;
  letter-spacing: var(--tcf-tracking-eyebrow);
  text-transform: uppercase;
  color: var(--tcf-muted);
}
.tcf-player__title { margin: 0.15rem 0 0.2rem; font-weight: 600; line-height: 1.3; }
.tcf-player__meta { margin: 0 0 0.75rem; font-size: var(--tcf-text-meta); color: var(--tcf-muted); }
.tcf-player__audio { width: 100%; display: block; }
.tcf-player__actions {
  margin: 0.6rem 0 0;
  display: flex; gap: 1.25rem; flex-wrap: wrap;
  font-size: var(--tcf-text-body-sm);
}

@media (max-width: 560px) {
  .tcf-player { flex-direction: column; gap: 0.9rem; }
  .tcf-player__art { width: 96px; height: 96px; }
}

/* ---------------------------------------------------------------------------
   Home
   Service time and address first, because the commonest question a visitor has
   is whether they can turn up, and when.
   --------------------------------------------------------------------------- */
.tcf-home__welcome { margin: 0 0 2.5rem; }
.tcf-home__title { margin: 0 0 0.75rem; }
.tcf-home__when {
  margin: 0 0 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  font-size: var(--tcf-text-lede);
}
.tcf-home__service { font-weight: 600; }
.tcf-home__where { color: var(--tcf-muted); font-size: var(--tcf-text-body-sm); }
.tcf-home__cta { margin: 0; }
.tcf-home__cta-link {
  display: inline-block;
  padding: 0.7rem 1.5rem;
  border: 1px solid currentColor;
  border-radius: var(--tcf-radius);
  text-decoration: none;
  font-weight: 600;
}
.tcf-home__cta-link:hover,
.tcf-home__cta-link:focus-visible { text-decoration: underline; }

.tcf-home__photo { margin: 0 0 2.5rem; }
.tcf-home__photo img { width: 100%; height: auto; display: block; border-radius: var(--tcf-radius); }

/* A photo slot, per §1.4. The dashed box stays visible in staging on purpose:
   it names the shot the church still owes us, and a stock photograph dropped in
   here would quietly end that conversation. The label colour is --tcf-tertiary,
   which is 3.01:1 on this fill - marginal, and acceptable only because this is
   scaffolding that must not survive to launch. */
.tcf-home__photo-missing {
  margin: 0 0 2.5rem;
  padding: 1rem 1.25rem;
  border: 1px dashed var(--tcf-photo-border);
  border-radius: var(--tcf-radius);
  background: var(--tcf-photo-fill);
  color: var(--tcf-tertiary);
  font-size: var(--tcf-text-body-sm);
}

.tcf-home__intro { margin: 0 0 2.5rem; }
.tcf-home__section-title {
  font-size: var(--tcf-text-eyebrow);
  font-weight: 700;
  letter-spacing: var(--tcf-tracking-eyebrow);
  text-transform: uppercase;
  color: var(--tcf-muted);
  margin: 0 0 0.75rem;
}
.tcf-home__teaching {
  padding-top: 2rem;
  border-top: 1px solid currentColor;
  border-color: color-mix(in srgb, currentColor var(--tcf-hairline-alpha), transparent);
}
.tcf-home__teaching-title { margin: 0 0 0.3rem; }
.tcf-home__teaching-meta { margin: 0 0 1rem; font-size: var(--tcf-text-meta); color: var(--tcf-muted); }
.tcf-home__teaching-audio { width: 100%; display: block; }
.tcf-home__teaching-more { margin: 0.75rem 0 0; font-size: var(--tcf-text-body-sm); }

/* Church blocks - editable pages, dynamic values. */
.tcf-service-times { margin: 0 0 1.5rem; }
.tcf-service-times__when { margin: 0 0 0.2rem; font-size: var(--tcf-text-lede); font-weight: 600; }
.tcf-service-times__where { margin: 0; opacity: 0.8; }

.tcf-latest-teaching { margin: 0; }
.tcf-latest-teaching__label {
  font-size: var(--tcf-text-eyebrow); font-weight: 700;
  letter-spacing: var(--tcf-tracking-eyebrow); text-transform: uppercase;
  color: var(--tcf-muted); margin: 0 0 0.6rem;
}
.tcf-latest-teaching__title { margin: 0 0 0.3rem; }
.tcf-latest-teaching__meta { margin: 0 0 0.9rem; font-size: var(--tcf-text-meta); color: var(--tcf-muted); }
.tcf-latest-teaching__audio { width: 100%; display: block; }
.tcf-latest-teaching__more { margin: 0.75rem 0 0; font-size: var(--tcf-text-body-sm); }

/* ---------------------------------------------------------------------------
   Full-width hero
   When a page opens with an edge-to-edge Cover block, close the gap the theme
   would otherwise leave above it so the image reads as part of the page rather
   than a picture dropped into it.
   --------------------------------------------------------------------------- */
.tcf-has-hero .ct-container-full[data-vertical-spacing],
.tcf-has-hero .ct-container[data-vertical-spacing] { padding-top: 0; }
.tcf-has-hero .entry-content > .wp-block-cover.alignfull:first-child { margin-top: 0; }

/* Give wide images room to breathe without touching the text measure. */
.entry-content > .wp-block-image.alignwide { margin-top: 2rem; margin-bottom: 2rem; }
.wp-block-image figcaption { color: var(--tcf-muted); font-size: var(--tcf-text-meta); }

/* ---------------------------------------------------------------------------
   The header no longer sits on the hero

   There was a block here that made the header transparent and absolutely
   positioned over the homepage hero photograph, and whitened everything in it.
   The design moved on: the header is now an opaque paper band on every page,
   set by `html body.home header#header.ct-header` further down this file, which
   is both later and more specific. Every declaration in the old block lost.

   It was not merely dead. `.tcf-has-hero ... svg { color: var(--tcf-page) }`
   still matched, and nothing later re-inked it, so on the home page at mobile
   width the menu trigger was painted paper on a paper header - measured
   rgb(251,248,243) on rgb(251,248,243). The button was invisible, and the home
   page is the one a stranger arrives on. Interior pages were unaffected because
   they never carried .tcf-has-hero.

   Removed rather than repaired: restoring the effect means restoring the design
   decision, and that is a design call, not a CSS one. `.tcf-has-hero` is still
   applied to the body and still drives the hero's own spacing and scrim below.
   --------------------------------------------------------------------------- */

/* A soft top-down scrim so the header stays readable over a light photograph. */
.tcf-has-hero .entry-content > .wp-block-cover.alignfull:first-child::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 220px;
  background: linear-gradient(to bottom, rgba(0,0,0,.55), rgba(0,0,0,0));
  z-index: 1;
  pointer-events: none;
}
.tcf-has-hero .entry-content > .wp-block-cover.alignfull:first-child > .wp-block-cover__inner-container {
  position: relative;
  z-index: 2;
}

/* Clear the header so the hero's own words are not tucked underneath it. */
.tcf-has-hero .entry-content > .wp-block-cover.alignfull:first-child {
  padding-top: 9rem;
}

@media (max-width: 782px) {
  .tcf-has-hero .entry-content > .wp-block-cover.alignfull:first-child { padding-top: 7rem; }
}

/* Contact */
.tcf-contact { margin: 0; }
.tcf-contact__field { display: flex; flex-direction: column; gap: 0.3rem; margin: 0 0 1.1rem; }
.tcf-contact__field label {
  font-weight: 600;
  font-size: var(--tcf-text-ui);
  color: var(--tcf-field-label);
}
.tcf-contact__field input,
.tcf-contact__field textarea {
  width: 100%;
  /* `height: auto` first, and it is load-bearing: Blocksy sets `height` on
     every form control from --theme-form-field-height, and with border-box
     that swallows the padding whole. Without this line every declaration
     under it is decoration. */
  height: auto;
  min-height: var(--tcf-field-min-h);
  padding: var(--tcf-field-pad-y) var(--tcf-field-pad-x) !important;
  font-family: var(--tcf-font-ui);
  font-size: var(--tcf-field-text);
  line-height: 1.4;
  /* A field's border is the only thing marking where the control is, which is
     the same WCAG 1.4.11 case as the secondary button - and currentColor at 30%
     came to roughly 1.9:1 on paper. Same ruling, same value, now the token. */
  border: var(--tcf-field-border-w) solid var(--tcf-field-border);
  border-radius: var(--tcf-radius);
  /* Was `transparent`, which was the one field on the site with no fill of its
     own. On a paper page that computes to the same thing; dropped into a
     --tcf-surface band it made the field the colour of the band, losing the
     one cue that a field is a slot cut into the page rather than an outline
     drawn on it. */
  background: var(--tcf-field-fill);
  color: var(--tcf-ink);
}
/* A name and an email address are both `md` (§3.4): a name is unbounded at the
   top end, and the longest address anyone will realistically type is 31
   characters, 245px of glyphs. The field was uncapped, so on the contact page
   it would have run the full prose column. */
.tcf-contact__field input { max-width: var(--tcf-field-measure-md); }
.tcf-contact__field textarea {
  resize: vertical;
  min-height: 8rem;
  max-width: var(--tcf-measure-lede);
}
.tcf-contact__submit button {
  padding: 0.7rem 1.5rem; font: inherit; font-weight: 600; cursor: pointer;
  border: 1px solid currentColor; border-radius: var(--tcf-radius);
  background: transparent; color: inherit;
}
.tcf-contact__errors { margin: 0 0 1.25rem; padding: 0.75rem 1rem; border-left: 3px solid var(--tcf-status-error); }
.tcf-contact__errors ul { margin: 0; padding-left: 1.1rem; }
.tcf-contact__sent { padding: 1rem 1.25rem; border-left: 3px solid var(--tcf-status-success); }
.tcf-contact__sent p { margin: 0 0 0.4rem; }

/* Honeypot: away from people and from screen readers, without display:none,
   which some bots detect and skip. */
.tcf-contact__hp {
  position: absolute !important;
  left: -9999px !important;
  width: 1px; height: 1px; overflow: hidden;
}

.tcf-map { margin: 0 0 1.5rem; }
/* 3:2 - tall enough to be useful on a phone, not so tall it dominates a desktop
   page. TCF_MAP_ASPECT in the tcf-church plugin must match this; the plugin asks
   OpenStreetMap for an area of this shape, and a mismatch stretches the map. */
.tcf-map__frame {
  width: 100%;
  aspect-ratio: 3 / 2;
  border: 0;
  border-radius: var(--tcf-radius);
  display: block;
}
.tcf-map__link { margin: 0.5rem 0 0; font-size: var(--tcf-text-meta); }

.tcf-mailing { margin: 0 0 1.5rem; }
.tcf-mailing__heading { margin: 0 0 0.5rem; }
.tcf-mailing__address { font-style: normal; line-height: 1.6; }

.tcf-contact-details { margin: 0 0 1.5rem; }
.tcf-contact-details__heading { margin: 0 0 0.75rem; }
.tcf-contact-details__list { margin: 0; display: grid; grid-template-columns: auto 1fr; gap: 0.4rem 1.25rem; }
.tcf-contact-details__list dt { font-weight: 600; opacity: 0.75; }
.tcf-contact-details__list dd { margin: 0; }
.tcf-contact-details__list address { font-style: normal; line-height: 1.5; }
@media (max-width: 480px) {
  .tcf-contact-details__list { grid-template-columns: 1fr; gap: 0.15rem; }
  .tcf-contact-details__list dd { margin-bottom: 0.6rem; }
}

/* ---------------------------------------------------------------------------
   Footer
   When and where we meet, on every page - the question most visitors arrived
   with. Content comes from the Footer widget area, not from this stylesheet.
   --------------------------------------------------------------------------- */
.tcf-footer {
  border-top: 1px solid currentColor;
  border-color: color-mix(in srgb, currentColor var(--tcf-hairline-alpha), transparent);
  padding: 2.5rem 0 1rem;
}
/* `.tcf-footer__inner`'s grid is declared in FOOTER (§1.6) below and its padding
   again under "Footer vertical rhythm". The copy that used to sit here set the
   same display/grid-template-columns/gap and was overridden by both. */
.tcf-footer__title {
  font-size: var(--tcf-text-eyebrow);
  font-weight: 700;
  letter-spacing: var(--tcf-tracking-eyebrow);
  text-transform: uppercase;
  color: var(--tcf-muted);
  margin: 0 0 0.6rem;
}
/* `.tcf-footer p`'s margin is set in FOOTER (§1.6) below; the copy that used to
   sit here was its only declaration and was restated there. */
.tcf-footer ul { list-style: none; margin: 0; padding: 0; }
.tcf-footer li { margin-bottom: 0.3rem; }
/* The footer restates details already given above, so it is deliberately quieter. */
.tcf-footer .tcf-service-times__when { font-size: var(--tcf-text-body-sm); }
.tcf-footer .tcf-contact-details__list { grid-template-columns: 1fr; gap: 0.1rem; }
.tcf-footer .tcf-contact-details__list dt { font-size: var(--tcf-text-meta); }
.tcf-footer .tcf-contact-details__heading,
.tcf-footer .tcf-latest-teaching__label { display: none; }

/* ---------------------------------------------------------------------------
   Draft-content notice

   Deliberately loud. This marks text nobody at the church has written yet, and
   the failure mode it guards against is plausible-sounding placeholder copy
   going live because it read well enough that nobody questioned it. A quiet,
   tasteful notice would not do that job.
   --------------------------------------------------------------------------- */
.tcf-draft {
  border-left: 4px solid var(--tcf-accent);
  background: var(--tcf-surface);
  padding: var(--tcf-space-4) var(--tcf-space-5);
  margin: 0 0 var(--tcf-space-5);
  /* No max-width. Declaring one makes WordPress's constrained layout centre this
     block with auto margins, which left the notice adrift in the middle of the
     page while the prose beside it ran full width. Without one it simply flows
     like the paragraphs it sits among, which is what it should do. */
  font-family: var(--tcf-font-ui);
}
.tcf-draft__label {
  margin: 0;
  font-size: var(--tcf-text-sm);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--tcf-accent-strong);
}
.tcf-draft__needs {
  margin: var(--tcf-space-2) 0 0;
  font-size: var(--tcf-text-sm);
  color: var(--tcf-body);
}
.tcf-draft__who {
  margin: var(--tcf-space-2) 0 0;
  font-size: var(--tcf-text-meta);
  color: var(--tcf-muted);
}

/* ---------------------------------------------------------------------------
   Navigation dropdowns (desktop header only)

   Blocksy's default dropdown is a near-black panel - a leftover from its generic
   dark-blue theme, and it looks borrowed from another site next to a warm, light,
   photograph-led page.

   SCOPE MATTERS HERE, and a first attempt got it wrong. There are two menus in
   the document and both use `.sub-menu`:

     - `nav.header-menu-1`  the desktop dropdown, on a light page
     - `nav.mobile-menu`    inside Blocksy's dark off-canvas panel, where white
                            text on dark is correct

   Styling `.sub-menu` unscoped gave the mobile panel a white background while its
   text stayed white, i.e. invisible. It is scoped to the desktop menu for that
   reason. Leave the mobile menu alone.
   --------------------------------------------------------------------------- */
.header-menu-1 .sub-menu {
  background-color: var(--tcf-page);
  border: 1px solid var(--tcf-rule);
  border-radius: var(--tcf-radius);
}
/* Link colour has to be set through Blocksy's own variable, at its own
   specificity. Blocksy ships:

     [data-header*="type-1"] .ct-header [data-id="menu"] .sub-menu .ct-menu-link
       { --theme-link-initial-color: var(--theme-palette-color-8); }

   Palette slot 8 is the page colour - white - because the dropdown was designed
   to sit on a dark panel. Once this rule made the panel light, that produced
   white text on white. A plain `color` on a lower-specificity selector loses to
   it silently, which is exactly what happened twice before this comment existed.

   Matching Blocksy's specificity and loading later was NOT enough - the value is
   re-set on the element itself, so !important is genuinely required here rather
   than being a shortcut. Verified by measuring: 1.00:1 before, 11.85:1 after.

   Scoped to [data-id="menu"], which is the desktop header menu.
   [data-id="mobile-menu"] is a different element inside the dark off-canvas
   panel, where white text is correct and must stay. */
[data-header] .ct-header [data-id="menu"] .sub-menu .ct-menu-link {
  --theme-link-initial-color: var(--tcf-body) !important;
  --theme-link-hover-color: var(--tcf-accent) !important;
  color: var(--tcf-body) !important;
  font-family: var(--tcf-font-body);
  font-size: var(--tcf-text-ui);   /* §1.2: nav is `ui`, 15px */
  letter-spacing: 0;
  /* The top level is small caps; a list of page titles is not. */
  text-transform: none;
}

/* Its divider is a dashed white line, invisible on a light panel. */
[data-header] .ct-header [data-id="menu"] .sub-menu {
  --dropdown-divider: 1px solid var(--tcf-rule);
}

/* Blocksy opens dropdowns on hover. Without a visible ring, tabbing into one is
   invisible to a keyboard user. */
[data-header] .ct-header [data-id="menu"] .sub-menu .ct-menu-link:focus-visible {
  outline: 2px solid var(--tcf-accent);
  outline-offset: -2px;
}

/* ---------------------------------------------------------------------------
   Header height

   Blocksy's default middle row is 120px. The menu link fills that whole height,
   so the dropdown opens flush against it with a measured gap of zero - but the
   word you actually read sits centred at about 59px, leaving some 54px of empty
   space between the label and the panel. It reads as a broken dropdown floating
   away from its menu, which is what it was reported as.

   Nothing is wrong with the dropdown. The header is simply taller than the
   content in it, and on a site whose hero carries the title and nav over a
   photograph, that height is also spent screen space.

   88px keeps the logo comfortable and closes the apparent gap.
   --------------------------------------------------------------------------- */
/* Note the leading `html`. Blocksy emits this same selector in an inline <style>
   that the browser applies after this file, so an identical selector loses on
   source order and silently does nothing - the same trap as the colour palette.
   One extra element in the selector is enough to win. */
html [data-header*="type-1"] .ct-header [data-row*="middle"] {
  --height: 88px;
}

/* ---------------------------------------------------------------------------
   Draft scaffolding: writer's guidance and sized filler

   Two different things sit on an unwritten page and they must not look alike:

     .tcf-guide  instructions TO the writer - what this section is for
     .tcf-lorem  filler standing in for prose not yet written, at the length
                 the finished section should run to

   The filler is deliberately greyed. It is there so the page shows its true
   proportions before a word exists, and the one thing it must never do is get
   mistaken for content somebody wrote. Both disappear as the page is written;
   the launch check tracks what is left.
   --------------------------------------------------------------------------- */
.tcf-guide {
  display: block;
  border-left: 3px solid var(--tcf-rule);
  padding: var(--tcf-space-2) 0 var(--tcf-space-2) var(--tcf-space-4);
  margin: 0 0 var(--tcf-space-4);
  font-family: var(--tcf-font-ui);
  font-size: var(--tcf-text-sm);
  font-style: normal;
  color: var(--tcf-muted);
}
.tcf-guide strong { color: var(--tcf-accent-strong); white-space: nowrap; }

.tcf-lorem {
  /* Was a 55% mix of muted and page, which computes to #ACA69E - a colour the
     system does not own, and one the fidelity gate rightly reports. Mixing two
     approved values does not produce an approved value. Plain `muted` reads as
     secondary without inventing anything, and all of this goes away with the
     copy anyway. */
  color: var(--tcf-muted);
  font-style: italic;
}


/* ---------------------------------------------------------------------------
   Overrides for markup we do not own.

   Blocksy's off-canvas panels and WP-Members' login form both ship their own
   colours and timings. Neither is reachable through theme.json or a palette
   slot, so they are corrected here, scoped as tightly as each one allows.
   --------------------------------------------------------------------------- */

/* §1.7 permits exactly one duration for a sliding panel: 200ms. Blocksy ships
   0.25s on the search modal, the mobile drawer and the drawer's inner
   transform. The reduced-motion block later in this file zeroes all three. */
html #search-modal.ct-panel,
html #offcanvas.ct-panel,
html .ct-panel-inner,
html .ct-panel .ct-panel-inner {
  transition-duration: 200ms;
}

/* WP-Members renders the sign-in form with its own near-black text, white
   fields and hard black borders - the WordPress admin's palette, not ours. It
   hangs everything off ids (#wpmem_login, #wpmem_login_form), not the classes
   its documentation suggests. The member area proper is still to be built
   (§2i); this is the floor, so the page is not off-palette meanwhile. */
/* `:not(.tcf-mb-signin *)` on every one of these, and it is a live bug fix
   rather than hygiene. `#wpmem_login` is the wrapper div the plugin prints
   around the password-reset and username-reminder forms as well as the login
   form, and those two render inside the SIGN-IN CARD, which is #282521. Ink on
   that card is 1.15:1, so `Reset your password` was being drawn as a legend
   nobody could read - visible in a screenshot only as a slightly darker smear
   above the first label. Measured on the build site, 2026-08-09.

   The ink band re-points --tcf-field-label for exactly this reason; these
   colour declarations are the ones that were bypassing it. */
html #wpmem_login legend:not(.tcf-mb-signin *),
html #wpmem_login label:not(.tcf-mb-signin *),
html #wpmem_reg legend:not(.tcf-mb-signin *),
html #wpmem_reg label:not(.tcf-mb-signin *),
html #wpmem_restricted_msg:not(.tcf-mb-signin *),
html .link-text-forgot:not(.tcf-mb-signin *),
html .link-text-register:not(.tcf-mb-signin *) {
  color: var(--tcf-field-label);
}
/* `textarea` and `select` are in the list now, and that is the second live
   defect this block was carrying. The old list named three input types, so the
   profile form's Address textarea fell through to Blocksy's own
   `rgba(0,0,0,0.1)` border - measured 1.10:1 on paper, a 1.4.11 failure on the
   one field that holds a member's home address. Every other field on that form
   was 3.45:1, which is what made it invisible to review. */
html #wpmem_login input[type="text"],
html #wpmem_login input[type="password"],
html #wpmem_login input[type="email"],
html #wpmem_login input[type="tel"],
html #wpmem_login input[type="url"],
html #wpmem_login textarea,
html #wpmem_login select,
html #wpmem_reg input[type="text"],
html #wpmem_reg input[type="password"],
html #wpmem_reg input[type="email"],
html #wpmem_reg input[type="tel"],
html #wpmem_reg input[type="url"],
html #wpmem_reg textarea,
html #wpmem_reg select {
  background-color: var(--tcf-field-fill);
  color: var(--tcf-ink);
  /* Same 1.4.11 case as every other field on the site. */
  border: var(--tcf-field-border-w) solid var(--tcf-field-border);
  border-radius: var(--tcf-radius);
}
html #wpmem_login input.buttons,
html #wpmem_reg input.buttons {
  border-radius: var(--tcf-radius);
  background-color: var(--tcf-accent);
  color: var(--tcf-page);
  border: 1px solid var(--tcf-accent);
}

/* Core's button block keeps its own radius unless told otherwise. §1.4: 2px
   everywhere, chips excepted. */
html .wp-block-button__link,
html .wp-element-button,
html .wp-block-button__link.wp-element-button {
  border-radius: var(--tcf-radius);
}

/* ---------------------------------------------------------------------------
   BLOCK STYLES (§3.5)

   The ten variants registered in functions.php. Each is a named choice in the
   editor rather than a class somebody has to remember, which is what keeps a
   page a volunteer edited looking like the rest of the site.
   --------------------------------------------------------------------------- */

/* Eyebrow. A label above a heading, and never a heading itself - §1.2 is
   explicit that eyebrows carry no document structure. Brick, because §1.1
   assigns eyebrows to the accent along with buttons and links. */
.is-style-eyebrow {
  font-family: var(--tcf-font-ui);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.2em;
  line-height: 1;
  text-transform: uppercase;
  color: var(--tcf-accent);
  margin: 0 0 var(--tcf-space-4);
}

/* Headings. Newsreader never goes above 400 (§1.2), and the tracking tightens
   as the size grows. */
.is-style-section {
  font-family: var(--tcf-font-serif);
  font-weight: 400;
  font-size: var(--tcf-text-2xl);
  line-height: 1.15;
  letter-spacing: -0.01em;
}
.is-style-display {
  font-family: var(--tcf-font-serif);
  font-weight: 300;
  font-size: var(--tcf-text-3xl);
  line-height: 1.06;
  letter-spacing: -0.02em;
}

/* Pull quote. The one place italic Newsreader is used (§1.2). */
.is-style-pull {
  font-family: var(--tcf-font-serif);
  font-style: italic;
  font-weight: 400;
  font-size: var(--tcf-text-2xl);
  line-height: 1.28;
  border: 0;
  padding: 0;
  margin: 0 0 var(--tcf-space-5);
}
.is-style-pull cite {
  display: block;
  margin-top: var(--tcf-space-4);
  font: 500 15px/1.5 var(--tcf-font-ui);
  font-style: normal;
  color: var(--tcf-muted);
}

/* Bands. §1.1 allows at most two background colours per page beyond paper -
   one ink band and one paper-alt band - and the homepage alone may have three.
   Nothing here enforces that; it is a rule for whoever builds the page. */
.is-style-band-ink {
  background-color: var(--tcf-ink);
  color: var(--tcf-page);
  padding-block: var(--tcf-space-7);
}
.is-style-band-ink :is(h1, h2, h3, h4, h5, h6) { color: var(--tcf-page); }
.is-style-band-ink .is-style-eyebrow { color: var(--tcf-on-ink-accent); }
.is-style-band-ink p { color: var(--tcf-on-ink-body); }
.is-style-band-alt {
  background-color: var(--tcf-surface);
  padding-block: var(--tcf-space-7);
}

/* Card. §1.4: 1px rule, no radius, no shadow. A linked card moves its border
   on hover and nothing else - no lift, no scale. */
.is-style-card {
  background-color: var(--tcf-page);
  border: 1px solid var(--tcf-rule);
  border-radius: 0;
  box-shadow: none;
  padding: 26px;
}
.is-style-card:has(a:hover),
.is-style-card:has(a:focus-visible) {
  border-color: var(--tcf-accent);
}

/* Photo slot. Deliberately conspicuous: §1.8 says these stay visible in
   staging and are never filled with stock photography. If one of these reaches
   launch, that is the bug - not its contrast. */
.is-style-photo-slot {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--tcf-space-2);
  min-height: 260px;
  padding: var(--tcf-space-5);
  text-align: center;
  background-color: var(--tcf-photo-fill);
  border: 1px dashed var(--tcf-photo-border);
}
.is-style-photo-slot::before {
  content: "PHOTO SLOT";
  font: 700 11px/1 var(--tcf-font-ui);
  letter-spacing: 0.2em;
  color: var(--tcf-tertiary);
}
.is-style-photo-slot p {
  margin: 0;
  font-size: 15px;
  color: var(--tcf-muted);
}

/* Numbered list with rules. The numeral is decorative and large; the text
   carries the meaning (§5.1), so the list stays an <ol>. */
.is-style-numbered-rule {
  list-style: none;
  margin: 0;
  padding: 0;
  counter-reset: tcf-numbered;
}
/* NOT display:grid on the li.
   A list item's content is "<strong>Label</strong> - running text", and in a
   grid container that bare text node becomes an ANONYMOUS GRID ITEM. It landed
   in the 3rem numeral column and wrapped to one word per line. The numeral is
   positioned instead, so the content stays ordinary inline flow. */
.is-style-numbered-rule > li {
  counter-increment: tcf-numbered;
  position: relative;
  padding: var(--tcf-space-5) 0 var(--tcf-space-5) 3.5rem;
  border-top: 1px solid var(--tcf-rule);
}
/* `.is-style-numbered-rule > li:first-child { border-top: 0 }` is stated once,
   with the rest of the measured box, under CANVAS CORRECTIONS. The identical
   copy that used to sit here was a straight duplicate. */
.is-style-numbered-rule > li::before {
  position: absolute;
  left: 0;
  top: var(--tcf-space-5);
  content: counter(tcf-numbered, decimal-leading-zero);
  font-family: var(--tcf-font-serif);
  font-weight: 400;
  font-size: var(--tcf-text-xl);
  line-height: 1.1;
  color: var(--tcf-numeral);
}

/* ---------------------------------------------------------------------------
   Divided columns - the one §3.5 says matters most.

   The cells are separated by a 1px rule, NOT by a gap (§1.3). Below 768px they
   stack, and the vertical dividers have to become horizontal ones or the rows
   run together with nothing between them.

   :last-child rather than :not(:last-child) on the horizontal rule, because a
   wrapped flex row would otherwise leave a divider hanging off the end.
   --------------------------------------------------------------------------- */
.wp-block-columns.is-style-divided {
  gap: 0;
}
.wp-block-columns.is-style-divided > .wp-block-column {
  padding: var(--tcf-space-5) var(--tcf-space-6);
  border-right: 1px solid var(--tcf-rule);
}
.wp-block-columns.is-style-divided > .wp-block-column:last-child {
  border-right: 0;
}
/* The `:first-child { padding-left: 0 }` that used to sit here is stated
   identically under CANVAS CORRECTIONS, beside the measured cell padding it
   belongs with. */

@media (max-width: 767px) {
  .wp-block-columns.is-style-divided > .wp-block-column {
    padding: var(--tcf-space-5) 0;
    border-right: 0;
    border-bottom: 1px solid var(--tcf-rule);
  }
  .wp-block-columns.is-style-divided > .wp-block-column:last-child {
    border-bottom: 0;
    padding-bottom: 0;
  }
}

/* ---------------------------------------------------------------------------
   TEACHING ROWS (canvas 2c)

   Not cards. A rule hairline between rows, no border, no background, no
   artwork. Five columns on a desktop; a stacked block on a phone.

   The two fixed columns are the risk here. The designer's own six-row
   sample already wraps "36 min" onto a second line at 230px, and this archive
   holds 892 teachings with titles like "Sermon 4/21: Matthew 17.22-18.35:
   Community in the Shadow of the Cross". So the widths are minmax() rather
   than fixed: they hold the drawn proportions when the content allows and give
   way before they wrap, which a fixed track cannot do.
   --------------------------------------------------------------------------- */
.tcf-teaching-list {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--tcf-rule);
}
.tcf-teaching-row {
  display: grid;
  /* Measured, not drawn. The canvas puts these at 230px and 170px; against the
     real archive the metadata line wants 240px at its longest and the Scripture
     reference rarely exceeds 130px. So the metadata track is widened past the
     drawn value and the Scripture track narrowed, which keeps the row on one
     line without taking anything the reference needs. */
  grid-template-columns: 48px minmax(0, 1fr) minmax(11rem, 16.5rem) minmax(6rem, 10rem) auto;
  align-items: center;
  gap: var(--tcf-space-5);
  padding: var(--tcf-space-5) 0;
  border-bottom: 1px solid var(--tcf-rule);
}

/* The play button. 48px circle, warm fill, brick triangle drawn with a border
   rather than an icon font - §1.9 permits exactly three glyphs and forbids an
   icon set. */
.tcf-teaching-row__play {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background-color: var(--tcf-play-fill);
  transition: background-color 120ms ease;
}
.tcf-teaching-row__play-icon {
  width: 0;
  height: 0;
  margin-left: 3px;                        /* optical centring of a triangle */
  border-top: 6px solid transparent;
  border-bottom: 6px solid transparent;
  border-left: 10px solid var(--tcf-accent);
}
.tcf-teaching-row__play:hover,
.tcf-teaching-row__play:focus-visible {
  background-color: var(--tcf-rule);
}
/* 45 teachings have no recording. The column still holds its width so the rows
   stay aligned, but nothing is drawn - an empty circle would read as a broken
   control. */
.tcf-teaching-row__play.is-empty {
  background: none;
}

.tcf-teaching-row__eyebrow {
  margin: 0 0 0.35rem;
  font-family: var(--tcf-font-ui);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.2em;
  line-height: 1;
  text-transform: uppercase;
}
.tcf-teaching-row__eyebrow a { color: var(--tcf-accent); text-decoration: none; }
.tcf-teaching-row__eyebrow a:hover { text-decoration: underline; }

.tcf-teaching-row__title {
  margin: 0;
  font-family: var(--tcf-font-serif);
  font-weight: 400;
  font-size: var(--tcf-text-xl);
  line-height: 1.22;
  letter-spacing: -0.01em;
  text-wrap: balance;
}
.tcf-teaching-row__title a { color: var(--tcf-ink); text-decoration: none; }
.tcf-teaching-row__title a:hover { color: var(--tcf-accent); }

/* 14px is the `meta` step in §1.2 - "dates, durations, captions" - not the
   15.5px body-sm step. Getting that wrong cost 232px worth of column: at 15px
   every row in the archive wrapped its duration onto a second line, which is
   the same thing the designer's own six-row sample does at this width. */
.tcf-teaching-row__meta,
.tcf-teaching-row__scripture {
  margin: 0;
  font-size: 14px;
  line-height: 1.5;
  color: var(--tcf-muted);
}
.tcf-teaching-row__meta a { color: inherit; text-decoration: none; }
.tcf-teaching-row__meta a:hover { color: var(--tcf-accent); }
.tcf-teaching-row__sep { padding: 0 0.28em; }

.tcf-teaching-row__download {
  margin: 0;
  text-align: right;
  font-family: var(--tcf-font-ui);
  font-size: 15px;
  font-weight: 600;
}
.tcf-teaching-row__download a {
  color: var(--tcf-ink);
  text-decoration: underline;
  text-underline-offset: 4px;
}
.tcf-teaching-row__download a:hover { color: var(--tcf-accent); }

/* Below 768px the five columns become a block: the play button beside the
   title, everything else stacked under it. §1.10 says single column, and a
   five-track grid on a 320px screen is how horizontal scroll happens. */
@media (max-width: 767px) {
  .tcf-teaching-row {
    grid-template-columns: 48px minmax(0, 1fr);
    grid-template-areas:
      "play main"
      ".    meta"
      ".    scripture"
      ".    download";
    gap: 0.4rem var(--tcf-space-4);
    align-items: start;
    padding: var(--tcf-space-5) 0;
  }
  .tcf-teaching-row__play      { grid-area: play; }
  .tcf-teaching-row__main      { grid-area: main; }
  .tcf-teaching-row__meta      { grid-area: meta; }
  .tcf-teaching-row__scripture { grid-area: scripture; }
  .tcf-teaching-row__download  { grid-area: download; text-align: left; margin-top: 0.5rem; }
}

/* ---------------------------------------------------------------------------
   ACCORDION (§1.4, §3.6)

   Native <details>/<summary>. §3.6 is explicit: do not build a custom div and
   ARIA accordion. Native brings keyboard support and in-page find for free,
   and it stays readable with JavaScript off, which §5.10 requires.
   --------------------------------------------------------------------------- */
.tcf-accordion__item { border-bottom: 1px solid var(--tcf-rule); }
.tcf-accordion__item:first-child { border-top: 1px solid var(--tcf-rule); }

.tcf-accordion__summary {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--tcf-space-4);
  padding: 22px 2px;
  cursor: pointer;
  list-style: none;                       /* the default triangle */
  font-family: var(--tcf-font-sans);
  font-weight: 600;
  font-size: 1.1875rem;   /* 19px */
  line-height: 1.3;
  color: var(--tcf-ink);
}
.tcf-accordion__summary::-webkit-details-marker { display: none; }

/* §1.9 permits three glyphs on this site and this is one of them. Drawn from
   type rather than an icon, because there is no icon set and there will not be. */
.tcf-accordion__summary::after {
  content: "+";
  flex: none;
  font-family: var(--tcf-font-serif);
  font-weight: 400;
  font-size: 24px;
  line-height: 1;
  color: var(--tcf-accent);
}
.tcf-accordion__item[open] > .tcf-accordion__summary::after { content: "\2013"; }
.tcf-accordion__summary:hover { color: var(--tcf-accent); }

.tcf-accordion__panel { padding: 0 0 var(--tcf-space-5); max-width: var(--tcf-measure); }
.tcf-accordion__panel > :first-child { margin-top: 0; }
.tcf-accordion__panel > :last-child { margin-bottom: 0; }

/* ---------------------------------------------------------------------------
   VISITOR SELECTOR (§2a.3, §3.6)

   Ships as links above four visible panels; the script turns it into a
   tablist. Everything here is written so BOTH states look deliberate - the
   no-JavaScript version is a headed list of four answers, which is a perfectly
   good page, not a degraded one.
   --------------------------------------------------------------------------- */
.tcf-selector__nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--tcf-space-3);
  margin-bottom: var(--tcf-space-6);
}

/* Chips are the ONE exception to the 2px radius (§1.4) - they read as toggles
   rather than buttons. 44px minimum height is §5.8. */
.tcf-selector__tab {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 12px 20px;
  border: 1px solid var(--tcf-rule);
  border-radius: 24px;
  background: var(--tcf-page);
  color: var(--tcf-muted);
  font-family: var(--tcf-font-ui);
  font-size: 15px;
  font-weight: 500;
  text-decoration: none;
  cursor: pointer;
}
/* Active state differs in fill AND weight, not colour alone (§5.1). */
.tcf-selector__tab.is-current {
  background: var(--tcf-ink);
  border-color: var(--tcf-ink);
  color: var(--tcf-page);
  font-weight: 600;
}

/* The panel is a bordered card on paper, sitting inside the paper-alt band -
   read off the reference at 2a, where it is clearly a card rather than content
   lying on the band. */
.tcf-selector__panel {
  background: var(--tcf-page);
  border: 1px solid var(--tcf-rule);
  padding: 44px;
}
/* Only once the script has taken over do the panels stack behind one another;
   before that every one of them is on the page with its heading. */
.tcf-selector:not(.is-enhanced) .tcf-selector__panel + .tcf-selector__panel {
  margin-top: var(--tcf-space-6);
  padding-top: var(--tcf-space-6);
  border-top: 1px solid var(--tcf-rule);
}
.tcf-selector.is-enhanced .tcf-selector__heading { margin-top: 0; }

/* `.tcf-selector__heading`'s own type is now declared in exactly one place -
   MEASURED FROM design-reference.html, SCREEN 2a. The copy that used to sit
   here declared the same six properties and every one of them was restated
   there, so it rendered nothing. It still picks up the cross-cutting heading
   rules further down (balance, `text-wrap`, and the Newsreader-400 weight under
   TRACKING FOLLOWS RENDERED SIZE); those apply to a list of headings and are
   not this component's own rule. */
.tcf-selector__points {
  list-style: none;
  counter-reset: tcf-point;
  margin: var(--tcf-space-5) 0 0;
  padding: 0;
}
/* Two lines per point, not one. The reference sets the title in bold on its
   own line with the description beneath in muted - an em-dash run-on reads as
   a sentence where the design reads as a list. */
.tcf-selector__points > li {
  counter-increment: tcf-point;
  position: relative;
  padding: var(--tcf-space-4) 0;
  padding-left: 2.25rem;
  border-bottom: 1px solid var(--tcf-rule);
  font-size: 15.5px;
  line-height: 1.55;
}
/* The reference gives every point row 16px top padding, the first included. */
.tcf-selector__point-title {
  display: block;
  font-family: var(--tcf-font-ui);
  font-weight: 700;
  color: var(--tcf-ink);
}
.tcf-selector__point-desc {
  display: block;
  margin-top: 0.15rem;
  color: var(--tcf-muted);
}
/* A plain numeral, not zero-padded - the reference shows 1, 2, 3. */
.tcf-selector__points > li::before {
  position: absolute;
  left: 0;
  top: var(--tcf-space-4);
  content: counter(tcf-point);
  font-family: var(--tcf-font-ui);
  font-size: 14px;
  color: var(--tcf-numeral);
}
.tcf-selector__points > li:first-child::before { top: 16px; }

/* Chips are links, and .entry-content styles links. Without this they render
   as brick underlined text inside the chip, which reads as a link sitting in a
   button rather than as a toggle. */
.entry-content .tcf-selector__tab,
.entry-content .tcf-selector__tab:hover {
  color: var(--tcf-muted);
  text-decoration: none;
}
.entry-content .tcf-selector__tab.is-current,
.entry-content .tcf-selector__tab.is-current:hover { color: var(--tcf-page); }

@media (min-width: 768px) {
  /* Two columns, and the children are PLACED rather than auto-flowed.
     Auto-placement put the heading in column 1, the paragraph in column 2, the
     button back in column 1 and the numbered list in column 2 - so the list
     inherited a narrow track and its own 2.25rem + 1fr grid squeezed the text
     to one word per line. §2a.3 wants the title, paragraph and button on the
     left and the three points on the right. */
  .tcf-selector.is-enhanced .tcf-selector__panel {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    column-gap: 52px;
    align-items: start;
  }
  .tcf-selector.is-enhanced .tcf-selector__panel > :not(.tcf-selector__points) {
    grid-column: 1;
  }
  .tcf-selector.is-enhanced .tcf-selector__points {
    grid-column: 2;
    grid-row: 1 / span 20;
    margin-top: 0;
    min-width: 0;
  }
}
.tcf-selector__points > li > * { min-width: 0; }

/* ---------------------------------------------------------------------------
   UTILITY BAR (§1.4)

   A full-width ink strip above the header, on every page. 13.5px is below the
   15px body minimum on purpose - §1.2 gives the utility bar its own step, and
   §6.4's small-text check exempts it by class for that reason.
   --------------------------------------------------------------------------- */
.tcf-utility {
  background-color: var(--tcf-ink);
  color: var(--tcf-on-ink-quiet);
  font-family: var(--tcf-font-ui);
  font-size: 13.5px;
  line-height: 1.4;
}
.tcf-utility__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--tcf-space-5);
  /* Blocksy's own container formula, never a fixed pixel width - the container
     is viewport-relative below desktop and a hard number matches at one size
     only. This is documented in UI_UX_BRIEF.md §6. */
  width: min(var(--tcf-content-max), calc(100% - var(--tcf-gutter) * 2));
  margin-inline: auto;
  padding-block: 10px;
}
.tcf-utility p { margin: 0; }
.tcf-utility__sep { padding: 0 0.4em; }
.tcf-utility__links {
  display: flex;
  gap: var(--tcf-space-5);
  flex: none;
}
.tcf-utility a {
  color: var(--tcf-on-ink-quiet);
  text-decoration: none;
}
.tcf-utility a:hover { color: var(--tcf-page); text-decoration: underline; }
.tcf-utility a:focus-visible {
  outline: 2px solid var(--tcf-on-ink-accent);
  outline-offset: 2px;
}

/* §1.4: collapses on mobile to the meeting time only. The address is the part
   that goes - it is on Plan Your Visit, on Contact and in the footer, whereas
   the meeting time is the thing the package calls the most important fact on
   the site. */
@media (max-width: 767px) {
  .tcf-utility__inner { justify-content: center; padding-block: 8px; }
  .tcf-utility__sep,
  .tcf-utility__where,
  .tcf-utility__links { display: none; }
}

/* ---------------------------------------------------------------------------
   HEADER (§1.5)

   Blocksy paints the wordmark as a bold, underlined, brick 25px sans link and
   sets the top-level navigation in uppercase. The design asks for a Newsreader
   wordmark at 23px in ink, and sentence-case navigation - "About · Teachings ·
   Life Together", not "ABOUT · TEACHINGS".

   Every rule here is prefixed with `html` for the reason documented three times
   in UI_UX_BRIEF.md §6: Blocksy emits its Customizer settings as inline CSS
   AFTER this stylesheet, so an override at equal specificity loses silently.
   --------------------------------------------------------------------------- */
html .site-title,
html .site-title a {
  font-family: var(--tcf-font-serif);
  font-size: 23px;
  font-weight: 400;
  line-height: 1.05;        /* 24.15px on the canvas */
  letter-spacing: -0.01em;  /* -0.23px */
  color: var(--tcf-ink);
  text-decoration: none;
}
html .site-title a:hover { color: var(--tcf-accent); }
html .site-title a:focus-visible {
  outline: 2px solid var(--tcf-accent);
  outline-offset: 2px;
}

/* Sentence case, and the UI stack rather than the serif - §1.2 reserves
   Newsreader for display and headings. Only the top level: submenu items are
   already sentence case. */
html .ct-header [data-id="menu"] > .menu > .menu-item > .ct-menu-link {
  font-family: var(--tcf-font-ui);
  font-size: 15px;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
}

/* Plan your visit is the primary action, and the design draws it as the one
   button in the header. Targeted by destination rather than by a class, because
   menu items live in the database and a class typed into the Menus screen is
   one rename away from silently doing nothing. */
html .ct-header [data-id="menu"] > .menu > .menu-item:has( > a[href*="/plan-your-visit/"] ) {
  /* Last in the row, whatever order the Menus screen puts it in. The design
     draws the primary action to the right of the navigation, and a volunteer
     reordering the menu should not be able to move it. */
  order: 99;
  margin-left: var(--tcf-space-4);
  align-items: center;
}
html .ct-header [data-id="menu"] > .menu > .menu-item > a[href*="/plan-your-visit/"] {
  /* Blocksy stretches menu links to the full header height so the hover target
     fills the row. A button must not do that - it has its own height and sits
     centred in the row. */
  align-self: center;
  height: auto;
  min-height: 0;
  background-color: var(--tcf-accent);
  color: var(--tcf-page);
  border-radius: var(--tcf-radius);
  padding: 12px 22px;
  font-weight: 600;
  transition: background-color 120ms ease;
}
html .ct-header [data-id="menu"] > .menu > .menu-item > a[href*="/plan-your-visit/"]:hover {
  background-color: var(--tcf-accent-strong);
  color: var(--tcf-page);
}
html .ct-header [data-id="menu"] > .menu > .menu-item > a[href*="/plan-your-visit/"] .ct-menu-link-inner {
  color: inherit;
}

/* The header sits on paper with a hairline under it (§1.5), not a shadow. */
html .ct-header {
  background-color: var(--tcf-page);
  border-bottom: 1px solid var(--tcf-rule);
  box-shadow: none;
}


/* The header search is not in the design (§1.5 lists the wordmark, the nav and
   one button, and 2c draws exactly that). Hidden rather than removed, because
   the search results page and its copy do exist and the archive's own search
   is specified separately in §2c - this is about what the header carries.
   Recorded in DECISIONS_TO_REVIEW.md. */
html .ct-header [data-id="search"] { display: none; }

/* ---------------------------------------------------------------------------
   The front page must not use a transparent header.

   Blocksy overlays the header on the front page - position: absolute, top: 0,
   no background - so it floats over the hero. With a utility bar above it, both
   start at the same y and the navigation lands on top of "Member login".

   The design does not do this. 2a draws three stacked bands: the ink utility
   strip, the header on paper, then the photograph beneath. So the header goes
   back into the flow. The `html` prefix is required as ever - this is Blocksy's
   own inline CSS being overridden.
   --------------------------------------------------------------------------- */
html body.home header#header.ct-header,
html body.blog header#header.ct-header {
  position: static;
  background-color: var(--tcf-page);
  /* No rule under the nav on the home page: the hero's dark band is the edge,
     and a hairline above it reads as a seam. */
  border-bottom: 0;
}
/* Blocksy pulls the first section up under a transparent header; with the
   header back in the flow that offset would leave the hero overlapping it. */
html body.home .ct-header + * ,
html body.blog .ct-header + * {
  margin-top: 0;
}

/* And the colours have to come back with it.
   Blocksy's transparent header paints the wordmark and the top-level menu in
   `paper`, because they were sitting over a photograph. Put the header on a
   paper background and that is white on white - the exact failure this repo
   already documents twice, and one that looks like the elements have simply
   vanished rather than like a colour bug. Measured before fixing: computed
   colour rgb(251,248,243) on a rgb(251,248,243) background.

   The primary button is excluded: its text is paper ON brick and is correct. */
html body.home header#header [data-id="menu"] > .menu > .menu-item > .ct-menu-link:not([href*="/plan-your-visit/"]),
html body.blog header#header [data-id="menu"] > .menu > .menu-item > .ct-menu-link:not([href*="/plan-your-visit/"]) {
  color: #3B3630;                 /* measured from the reference, not ink */
}

/* The wordmark needs !important, and it is not superstition.
   Enumerating all 21 stylesheets finds NO rule that matches this anchor and
   sets `color` - the parent span computes to ink, there is no inline style, and
   the selector below matches - yet the anchor computed to paper (#FBF8F3, which
   is palette slot 8) with -webkit-text-fill-color following it. Blocksy is
   reaching it by a route that does not show up in cssRules enumeration.
   This is the second place slot 8 has done this; the dropdown link colour is
   the first and is already commented above as needing the same treatment.
   Both properties are set, because text-fill-color overrides color when
   painting and leaving it would keep the wordmark invisible. */
html body.home header#header .site-title a,
html body.blog header#header .site-title a {
  color: var(--tcf-ink) !important;
  -webkit-text-fill-color: var(--tcf-ink) !important;
}
html body.home header#header .site-title a:hover,
html body.blog header#header .site-title a:hover {
  color: var(--tcf-accent) !important;
  -webkit-text-fill-color: var(--tcf-accent) !important;
}

/* The dropdown carets are the third casualty of the same thing: an 8x8 SVG
   filled from slot 8, invisible on paper. Measured fill before the fix:
   rgb(251,248,243). */
html body.home header#header .ct-toggle-dropdown-desktop svg,
html body.blog header#header .ct-toggle-dropdown-desktop svg {
  fill: var(--tcf-ink);
  color: var(--tcf-ink);
}
html body.home header#header [data-id="menu"] > .menu > .current-menu-item > .ct-menu-link,
html body.home header#header [data-id="menu"] > .menu > .current-menu-ancestor > .ct-menu-link {
  color: var(--tcf-accent);
}
html body.home header#header .site-title a:hover,
html body.home header#header [data-id="menu"] > .menu > .menu-item > .ct-menu-link:not([href*="/plan-your-visit/"]):hover {
  color: var(--tcf-accent);
}

/* ---------------------------------------------------------------------------
   SINGLE TEACHING: the passage and the summary (§2d)
   --------------------------------------------------------------------------- */
.tcf-teaching__eyebrow {
  font-family: var(--tcf-font-ui);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.2em;
  line-height: 1;
  text-transform: uppercase;
  color: var(--tcf-accent);
  margin: 0 0 var(--tcf-space-4);
}
.tcf-teaching__passage { margin: var(--tcf-space-7) 0 var(--tcf-space-6); }

/* Italic Newsreader behind a 2px rule - the one other place §1.2 allows the
   italic, alongside pull quotes. */
.tcf-teaching__quote {
  margin: 0;
  padding: 0 0 0 var(--tcf-space-5);
  border-left: 2px solid var(--tcf-link-underline);
  font-family: var(--tcf-font-serif);
  font-style: italic;
  font-weight: 400;
  font-size: var(--tcf-text-lg);
  line-height: 1.5;
  color: var(--tcf-ink);
  max-width: var(--tcf-measure);
}
.tcf-teaching__quote p:last-of-type { margin-bottom: 0; }
.tcf-teaching__quote cite {
  display: block;
  margin-top: var(--tcf-space-4);
  font: 500 14px/1.5 var(--tcf-font-ui);
  font-style: normal;
  color: var(--tcf-muted);
}
.tcf-teaching__summary { margin: 0 0 var(--tcf-space-6); }

/* ---------------------------------------------------------------------------
   TEACHING ARCHIVE HEADER (§2c)

   Eyebrow, a display-sized title, a lede, and the podcast button pulled right.
   A term archive swaps the headline for the term - "Every teaching we have
   preached" is true of /teachings/ and false on /teachings/book/luke/.
   --------------------------------------------------------------------------- */
.tcf-teaching-archive__header {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--tcf-space-6);
  align-items: end;
  margin-bottom: var(--tcf-space-6);
}
.tcf-teaching-archive__eyebrow {
  font-family: var(--tcf-font-ui);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.2em;
  line-height: 1;
  text-transform: uppercase;
  color: var(--tcf-accent);
  margin: 0 0 var(--tcf-space-4);
}
.tcf-teaching-archive__title {
  font-family: var(--tcf-font-serif);
  font-weight: 300;
  font-size: var(--tcf-text-3xl);
  line-height: 1.06;
  letter-spacing: -0.02em;
  margin: 0;
  /* 28ch, not 20. The canvas sets this headline on two lines; at 20ch a
     44px display face takes three, which reads as a much heavier page. */
  max-width: 28ch;
  text-wrap: balance;
}
.tcf-teaching-archive__intro {
  margin-top: var(--tcf-space-4);
  max-width: 56ch;              /* §1.3 caps a lede at 56ch */
  color: var(--tcf-muted);
  font-size: var(--tcf-text-lg);
  line-height: 1.65;
}
.tcf-teaching-archive__intro p { margin: 0; }
.tcf-teaching-archive__podcast { margin: 0; }

/* The secondary button from §1.4: transparent, 1px border, ink text. The
   border colour is the 1.4.11 value ruled on in DESIGN_SYSTEM.md. */
.tcf-button-secondary {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 16px 30px;
  border: 1px solid var(--tcf-button-border);
  border-radius: var(--tcf-radius);
  background: transparent;
  color: var(--tcf-ink);
  font-family: var(--tcf-font-ui);
  font-size: 16px;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  transition: border-color 120ms ease, color 120ms ease;
}
.tcf-button-secondary:hover { border-color: var(--tcf-ink); color: var(--tcf-ink); }

/* Search, sitting in the filter toolbar.

   THE ONE DELIBERATE EXCEPTION to the field tokens. This is not a form field;
   it is a control in a row of chips, and its 15px/1/44px geometry is what makes
   it the same height as the chips beside it. Adopting --tcf-field-text (16px)
   and --tcf-field-pad-y (12px) would take it to 48.4px and break the toolbar
   row that the teaching-filter work measured at 56px flat. Recorded as a decision
   here so the next pass does not "finish the job" - DESIGN_SYSTEM_FIELDS.md
   §7.1 item 6. It does take --tcf-field-border, which is the same value it
   already had. */
.tcf-search { display: flex; gap: var(--tcf-space-2); }
.tcf-search input[type="search"] {
  min-height: 44px;
  padding: 0 var(--tcf-space-4);
  border: 1px solid var(--tcf-field-border);
  border-radius: var(--tcf-radius);
  background: var(--tcf-page);
  color: var(--tcf-ink);
  font: 400 15px/1 var(--tcf-font-ui);
  min-width: 12rem;
}
.tcf-search button {
  min-height: 44px;
  padding: 0 var(--tcf-space-4);
  border: 1px solid var(--tcf-field-border);
  border-radius: var(--tcf-radius);
  background: transparent;
  color: var(--tcf-ink);
  font: 600 15px/1 var(--tcf-font-ui);
  cursor: pointer;
}
.tcf-search button:hover { border-color: var(--tcf-ink); }
/* A statement about the list, directly above the list.
   Not `.tcf-filters__count` and not inside `.tcf-filters` any more: as a flex
   item it landed one gap after the last chip on a phone and read as a fifth
   filter, and `margin-left: auto` put it 500px from that filter at 1440. It
   sits in the 28px gap the filter row's own margin already opens, inside the
   frame that `.tcf-teaching-list`'s top rule draws. */
.tcf-teaching-count {
  margin: 0 0 var(--tcf-rhythm-section);
  font-family: var(--tcf-font-ui);
  font-size: var(--tcf-text-meta);
  color: var(--tcf-muted);
}

@media (max-width: 767px) {
  .tcf-teaching-archive__header { grid-template-columns: 1fr; align-items: start; }

  /* The search form gets a row to itself.
     `.tcf-filters` is a flex row, so without `flex-basis: 100%` the form stays
     beside the count and shares what is left. Measured at 320px before this
     rule: the form was 126px, and since `min-width: 0` let the input shrink
     below its content, the field itself came out at 34px - about two
     characters, on the width most likely to be used. `min-width: 0` is the
     right instinct in a flex row (it is what allows shrinking at all), but it
     needs a floor or the button simply wins.
     The button keeps its label rather than becoming an icon: 84px is affordable
     once the form has the full width, and "Search" cannot be misread.

     `flex-wrap: wrap` is the value the row actually uses at every width; it is
     restated here only because this block used to be undoing a `nowrap` set in
     the 600px block above. That rule is gone, so this line is now belt and
     braces rather than a fight. */
  .tcf-filters { flex-wrap: wrap; }
  .tcf-search { flex: 1 0 100%; width: 100%; }
  .tcf-search input[type="search"] { flex: 1 1 auto; min-width: 8rem; }

  /* Below the two-column header the podcast action has no slot. Measured at
     375: a 250.3x62 bordered box sitting 40px under the lede and 40px above the
     filter row, related to neither, duplicating the podcast band at the foot of
     the page and pointing at raw RSS. It becomes the site's ordinary arrow
     link, directly under the lede that has just mentioned the podcast. The
     route is kept and its rank is corrected; §1 of the brief asks for exactly
     this register ("Give as ordinary nav text").

     These declarations are `.tcf-arrow-link`'s own values (style.css §"The
     inline arrow link"). If the two ever diverge, that rule is the source of
     truth and this one is wrong. */
  .tcf-teaching-archive__podcast { margin-top: 0; }
  .tcf-teaching-archive__podcast .tcf-button-secondary {
    /* `inline-flex` with the 44px floor kept, not `inline`. Demoting this to a
       text link is a rank change, not a licence to shrink the target: measured
       at 375, `display: inline` gave it a 17px box, which is under the project's
       24px floor and well under Decision 3's literal 44. Borderless and
       backgroundless, so the 44px box is invisible and reads as one line of
       underlined text with comfortable air around it - which is also where the
       gap under the lede now comes from, hence `margin-top: 0` above. */
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0;
    border: 0;
    font-family: var(--tcf-font-ui);
    font-size: 15px;
    font-weight: 600;
    color: var(--tcf-accent);
    text-decoration: underline;
    text-underline-offset: 4px;
    white-space: normal;
  }
  .tcf-teaching-archive__podcast .tcf-button-secondary:hover { color: var(--tcf-accent-strong); }
}

/* ---------------------------------------------------------------------------
   FOOTER (§1.6)

   Ink, four columns, headings in paper at 600, body at #9B9284. Line-height
   1.85 is deliberate and §5.8 says not to tighten it on mobile - it is what
   gives the footer links their tap target.
   --------------------------------------------------------------------------- */
.tcf-footer {
  background-color: var(--tcf-ink);
  color: var(--tcf-on-ink-muted);
  font-family: var(--tcf-font-ui);
  font-size: 15px;
  line-height: 1.85;
}
.tcf-footer__inner {
  display: grid;
  grid-template-columns: 1.4fr repeat(3, 1fr);
  gap: var(--tcf-space-6);
  width: min(var(--tcf-content-max), calc(100% - var(--tcf-gutter) * 2));
  margin-inline: auto;
  padding-block: var(--tcf-space-7) var(--tcf-space-6);
}
.tcf-footer p { margin: 0 0 var(--tcf-space-3); }
.tcf-footer__name {
  font-family: var(--tcf-font-serif);
  font-size: var(--tcf-text-lg);
  color: var(--tcf-page);
  line-height: 1.2;
}
/* The canvas sets the whole brand block in one muted tone. Picking the meeting
   time out in the accent read as pink against the ink and made a line of
   address detail look like a call to action. */
.tcf-footer__when { color: var(--tcf-on-ink-muted); }
.tcf-footer__heading {
  margin: 0 0 var(--tcf-space-3);
  font-family: var(--tcf-font-ui);
  font-size: 15px;
  font-weight: 600;
  line-height: 1.85;
  color: var(--tcf-page);
  letter-spacing: 0;
}
.tcf-footer__list { list-style: none; margin: 0; padding: 0; }
.tcf-footer a { color: var(--tcf-on-ink-muted); text-decoration: none; }
.tcf-footer a:hover { color: var(--tcf-page); text-decoration: underline; }
.tcf-footer a:focus-visible {
  outline: 2px solid var(--tcf-on-ink-accent);
  outline-offset: 2px;
}
/* `.tcf-footer .tcf-footer__copyright`, not `.tcf-footer__copyright`. The
   paragraph reset above is `.tcf-footer p`, which scores (0,1,1) and beats a
   single class - so its `margin: 0 0 x` shorthand was zeroing the auto side
   margins and pinning the line to the left edge. */
.tcf-footer .tcf-footer__copyright {
  width: min(var(--tcf-content-max), calc(100% - var(--tcf-gutter) * 2));
  margin-inline: auto;
  padding-block: 14px;
  border-top: 0;
  /* 15px, not 14. §1.2 sets a floor on body copy and the copyright line is
     body copy - the meta/eyebrow steps that go below it are a different thing
     with a different job. */
  font-size: 15px;
}
/* Interior pages take the condensed line on its own (§2). */
.tcf-footer.is-condensed .tcf-footer__copyright {
  border-top: 0;
  padding-block: var(--tcf-space-5);
}
/* Blocksy's own copyright row would sit under ours saying the same thing. */
.ct-footer [data-row="bottom"],
.ct-footer-copyright { display: none; }

@media (max-width: 767px) {
  .tcf-footer__inner { grid-template-columns: 1fr; gap: var(--tcf-space-5); }
}

/* ---------------------------------------------------------------------------
   PODCAST BAND (§2c.4)

   The ink band that ends the teaching archive. Also what keeps the page obeying
   the cross-page rule in §2 - every page closes with a band, never with body
   text running into the footer.
   --------------------------------------------------------------------------- */
.tcf-podcast-band {
  background-color: var(--tcf-ink);
  color: var(--tcf-on-ink-body);
}
.tcf-podcast-band__inner {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 260px;
  gap: var(--tcf-space-7);
  align-items: center;
  width: min(var(--tcf-content-max), calc(100% - var(--tcf-gutter) * 2));
  margin-inline: auto;
  padding-block: var(--tcf-space-7);
}
.tcf-podcast-band__eyebrow {
  margin: 0 0 var(--tcf-space-4);
  font-family: var(--tcf-font-ui);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.2em;
  line-height: 1;
  text-transform: uppercase;
  color: var(--tcf-on-ink-accent);
}
.tcf-podcast-band__title {
  margin: 0 0 var(--tcf-space-4);
  font-family: var(--tcf-font-serif);
  font-weight: 400;
  font-size: var(--tcf-text-2xl);
  line-height: 1.15;
  letter-spacing: -0.01em;
  color: var(--tcf-page);
}
.tcf-podcast-band__lede {
  margin: 0 0 var(--tcf-space-5);
  max-width: 52ch;
  line-height: 1.65;
}
.tcf-podcast-band__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--tcf-space-3);
  margin: 0;
}
.tcf-podcast-band__primary,
.tcf-podcast-band__secondary {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 14px 26px;
  border-radius: var(--tcf-radius);
  font-family: var(--tcf-font-ui);
  font-size: 15px;
  font-weight: 600;
  text-decoration: none;
  transition: background-color 120ms ease, border-color 120ms ease;
}
.tcf-podcast-band__primary {
  background-color: var(--tcf-page);
  color: var(--tcf-ink);
  border: 1px solid var(--tcf-page);
}
.tcf-podcast-band__primary:hover { background-color: var(--tcf-surface); color: var(--tcf-ink); }
/* §1.4: a secondary button on a dark band is transparent with a paper border. */
.tcf-podcast-band__secondary {
  background: transparent;
  color: var(--tcf-page);
  border: 1px solid var(--tcf-on-dark-border);
}
.tcf-podcast-band__secondary:hover { border-color: var(--tcf-page); color: var(--tcf-page); }
.tcf-podcast-band__art img {
  display: block;
  width: 260px;
  height: auto;
  border-radius: var(--tcf-radius);
}

@media (max-width: 767px) {
  .tcf-podcast-band__inner {
    grid-template-columns: 1fr;
    gap: var(--tcf-space-5);
    padding-block: var(--tcf-space-6);
  }
  .tcf-podcast-band__art { order: -1; }
  .tcf-podcast-band__art img { width: 180px; }
}

/* Pagination, which was rendering as bare text under the last row. */
.tcf-teaching-archive .navigation.pagination { margin-top: var(--tcf-space-6); }
.tcf-teaching-archive .nav-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--tcf-space-2);
  align-items: center;
}
.tcf-teaching-archive .page-numbers {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  padding: 0 var(--tcf-space-3);
  border: 1px solid var(--tcf-rule);
  border-radius: var(--tcf-radius);
  color: var(--tcf-ink);
  font-family: var(--tcf-font-ui);
  font-size: 15px;
  text-decoration: none;
  transition: border-color 120ms ease;
}
.tcf-teaching-archive .page-numbers:hover { border-color: var(--tcf-ink); }
.tcf-teaching-archive .page-numbers.current {
  background-color: var(--tcf-ink);
  border-color: var(--tcf-ink);
  color: var(--tcf-page);
  font-weight: 600;
}
.tcf-teaching-archive .page-numbers.dots { border-color: transparent; }

/* ---------------------------------------------------------------------------
   SINGLE TEACHING (§2d)

   A dark band carrying the artwork, the title and the player, then the text on
   paper beneath it in two columns.
   --------------------------------------------------------------------------- */
.tcf-teaching-hero {
  background-color: var(--tcf-ink);
  color: var(--tcf-on-ink-body);
}
/* Blocksy's own container formula, not ours.
   The band and the paper page beneath it had never shared a left edge at any
   width the site supports - measured 3.4px out at 390, 6.4px at 768, 19.2px at
   1024, 5.0px the OTHER WAY at 1440 and 1920. Two container systems were in
   play: ours is min(1280px, 100% - gutter*2) with a fixed gutter, Blocksy's is
   min(1290px, 90vw), and they cannot agree by construction. The title in the
   band and the first heading below it were never on the same vertical line.
   UI_UX_BRIEF.md §6 already rules on this - "Use Blocksy's own formula, never a
   fixed number" - and this band did not follow it. Now it does. */
.tcf-teaching-hero__inner {
  width: min(
    var(--theme-normal-container-max-width, 1290px),
    var(--theme-container-edge-spacing, 90vw)
  );
  margin-inline: auto;
  padding-block: var(--tcf-rhythm-band);
}
/* The back link and the head are two groups inside one section, so the gap
   between them is `section`, not `band`. DS_TEACHING_SINGLE.md §5.3 carried the
   old 40 forward here without re-deriving it against its own ladder; this is
   that ladder applied. Worth 12px of fold at every width. */
.tcf-teaching-hero__back { margin: 0 0 var(--tcf-rhythm-section); font-size: 15px; }
.tcf-teaching-hero__back a { color: var(--tcf-on-ink-body); text-decoration: none; }
.tcf-teaching-hero__back a:hover { color: var(--tcf-page); text-decoration: underline; }

.tcf-teaching-hero__head {
  display: grid;
  grid-template-columns: var(--tcf-teaching-art) minmax(0, 1fr);
  gap: var(--tcf-space-6);
  align-items: start;
}
/* An explicit edge, because the boundary underneath it is not one the eye can
   use. The tile's slate ground is #1C2A37 and the band is #1A1714: 1.22:1, hue
   30deg against hue 209deg at near-identical value - a hue-only edge that reads
   as a colour-management fault rather than as a layer, and it was carrying more
   work at 120px than at 180. --tcf-on-dark-border composites to #74716D, which
   is 3.68:1 against the band and 3.01:1 against the tile: a 1px line separating
   two surfaces has to clear 3:1 in both directions, and this one does. Neither
   ground changes; the slate is a licensed exception for artwork only and must
   not walk into the palette. DS_TEACHING_SINGLE.md §2.4. */
.tcf-teaching-hero__art {
  display: block;
  width: var(--tcf-teaching-art);
  height: auto;
  border: 1px solid var(--tcf-on-dark-border);
  border-radius: var(--tcf-radius);
}
.tcf-teaching-hero__eyebrow {
  margin: 0 0 var(--tcf-space-3);
  font-family: var(--tcf-font-ui);
  font-size: var(--tcf-text-eyebrow);
  font-weight: 700;
  letter-spacing: var(--tcf-tracking-eyebrow);
  line-height: 1;
  text-transform: uppercase;
  color: var(--tcf-on-ink-accent);
}
/* Four literals, four tokens. The title was the one h1 on the site that opted
   out of its own tracking rule: `.tcf-teaching-hero__title` is (0,1,0) and the
   `h1` at max-width 549 that drops tracking to -0.01em is (0,0,1), so the class
   won at every width and the phone rendered a 34px title at -0.68px when the
   scale says -0.34px. Restating the media query here is what lets the token do
   its job. When a clamp moves, this moves with it. */
.tcf-teaching-hero__title {
  margin: 0 0 var(--tcf-space-4);
  font-family: var(--tcf-font-serif);
  font-weight: 300;
  font-size: var(--tcf-text-page);
  line-height: var(--tcf-leading-display);
  letter-spacing: var(--tcf-tracking-display);
  color: var(--tcf-page);
  text-wrap: balance;
}
@media (max-width: 549px) {
  .tcf-teaching-hero__title { letter-spacing: var(--tcf-tracking-heading); }
}
.tcf-teaching-hero__meta { margin: 0; font-size: var(--tcf-text-ui); line-height: var(--tcf-leading-sm); }
.tcf-teaching-hero__meta a { color: inherit; text-decoration: none; }
.tcf-teaching-hero__meta a:hover { color: var(--tcf-page); text-decoration: underline; }
.tcf-teaching-hero__sep { padding: 0 0.35em; }
.tcf-teaching-hero__bit { white-space: nowrap; }
.tcf-teaching-hero__noaudio {
  margin: var(--tcf-rhythm-section) 0 0;
  font-size: var(--tcf-text-ui);
  font-style: italic;
}

/* The player bar sits on a lighter panel inside the same dark band (§2d), and
   INSIDE the text column rather than beside it. That is what makes the text set
   the height of the band: measured before this change, the head row was 180.0px
   because the artwork was 180.0 and the whole text block beside it was 120.5,
   so 59.5px of the row was empty ink and a decorative square was dictating
   layout to content. With the player in the column, the column is the taller of
   the two at every width, whatever --tcf-teaching-art later becomes.
   The gap above it is `section`: the metadata and the transport are two groups
   inside the band, not two sections of the page. */
.tcf-teaching-hero .tcf-player {
  margin: var(--tcf-rhythm-section) 0 0;
  background: color-mix(in srgb, var(--tcf-page) var(--tcf-panel-alpha), transparent);
  color: var(--tcf-on-ink-body);
}

/* The ink-to-paper boundary, taken back from Blocksy.
   `.tcf-teaching-single` used to carry data-vertical-spacing="top:bottom", which
   Blocksy's own sheet reads to apply --theme-content-vertical-spacing - measured
   60px at >=768 and 50px below. That made the biggest hierarchy break on the
   page smaller than the gap between a back link and a title. Setting the custom
   property ON THE ELEMENT rather than out-specifying the attribute selector is
   the clean move: a property declared on an element always beats one inherited
   from :root, whatever the specificity or source order, so Blocksy's rule paints
   our number and no `!important` is needed. Kept even though the attribute is
   no longer emitted, because Blocksy's containers read the same variable. */
.tcf-teaching-single {
  --theme-content-vertical-spacing: var(--tcf-rhythm-surface);
  padding-block: var(--tcf-rhythm-surface);
}

.tcf-teaching-body {
  display: grid;
  /* minmax(0, …) and min-width: 0, not a bare 1.5fr/1fr. An fr track refuses to
     go below its content's min-content width, and Blocksy gives .entry-content
     the full container width - so the first track computed to 1290px and the
     aside was squeezed to 187px. This is the same class of problem as the
     constrained-layout note in UI_UX_BRIEF.md §6. */
  grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);   /* §2d */
  gap: var(--tcf-rhythm-band);
  align-items: start;
}
.tcf-teaching-body > * { min-width: 0; }

/* "More in {book}": a bordered box, no radius, no shadow (§1.4).
   The speaker card that used to share this rule is gone - it was a 64px dashed
   PHOTO circle, a name and a count in a box the auto-fit grid stretched to
   340.5px tall and 601-631px wide around roughly 146px of content, repeating a
   name that was already in the hero 444px above and linked to the same URL. It
   is one line now, `.tcf-teaching-context` below. */
.tcf-more-in {
  border: 1px solid var(--tcf-rule);
  padding: var(--tcf-space-5);
  margin-bottom: var(--tcf-space-5);
}

.tcf-more-in__list { list-style: none; margin: 0; padding: 0; }
/* The padding is on the link, not on the row. The row was 63.6px tall and the
   target inside it 24.7px - which clears the project's 24px floor by 0.7px, and
   that mattered less when this list was the last thing on the page than it does
   now that it IS the page. Same pixels, whole row hittable. */
.tcf-more-in__list li {
  padding: 0;
  border-top: 1px solid var(--tcf-rule);
}
.tcf-more-in__list li:first-child { border-top: 0; }
.tcf-more-in__list a {
  display: block;
  /* 24.7px of text plus 16 above and 4 below is 44.7 - the §5.8 floor, not the
     24px one this row used to clear by 0.7px. The 4px below stands in for the
     0.15rem margin the date used to carry, so nothing moves on screen. */
  padding: var(--tcf-rhythm-group) 0 4px;
  font-family: var(--tcf-font-serif);
  font-size: 1.05rem;
  line-height: 1.3;
  color: var(--tcf-ink);
  text-decoration: none;
}
.tcf-more-in__list a:hover { color: var(--tcf-accent); }
.tcf-more-in__when {
  display: block;
  padding-bottom: var(--tcf-rhythm-group);
  font-size: 14px;
  color: var(--tcf-muted);
}
.tcf-more-in__all { margin: var(--tcf-space-4) 0 0; font-size: var(--tcf-text-ui); }

/* The context rail. What is left of the speaker card, and the shape anything
   else of that rank takes if it is ever added: a line under a hairline, not a
   box. */
.tcf-teaching-context {
  display: flex;
  flex-wrap: wrap;
  gap: var(--tcf-rhythm-group) var(--tcf-space-6);
  margin: 0;
  padding-top: var(--tcf-space-4);
  border-top: 1px solid var(--tcf-rule);
  font-size: var(--tcf-text-ui);
  color: var(--tcf-muted);
}
.tcf-teaching-context a { color: var(--tcf-ink); }
/* Four items on one baseline. The 40px column gap IS the separator - these are
   peer facts in a rail, not a sentence - so each item is one unbreakable unit
   and nothing between them is punctuation. The rule above the rail separates it
   from "All of {term}"; it does not underline the page. */
.tcf-teaching-context__item { white-space: nowrap; }

/* Never rendered to a visitor - current_user_can( 'edit_posts' ) gates it in the
   template, so the bytes are not on the page at all. It is styled anyway so that
   the editor who does see it sees a note rather than a broken paragraph. */
.tcf-editor-note {
  margin: var(--tcf-space-5) 0 0;
  padding: var(--tcf-space-3) var(--tcf-space-4);
  border-left: 2px solid var(--tcf-photo-border);
  background: var(--tcf-photo-fill);
  font-size: var(--tcf-text-ui);
  color: var(--tcf-muted);
}

@media (max-width: 900px) {
  .tcf-teaching-body { grid-template-columns: 1fr; gap: var(--tcf-rhythm-band); }
}
/* The artwork does not survive the phone. It is alt="", it is the same square on
   all 892 pages, and at 120x120 plus its gap it was costing 136px - 16% - of the
   one fold where the play control is hardest to reach. Hiding it costs no reader
   anything by our own declaration, and it is a deliberate divergence from canvas
   §2d that wants a line in the decision register. It is invisible to
   check_canvas.py, which pairs elements by their text content and an <img> has
   none. */
@media (max-width: 767px) {
  .tcf-teaching-hero__head { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .tcf-teaching-hero__art  { display: none; }
}

/* The inline timeline, opened from a teaching row. Spans every column on a line
   of its own - it is not a sixth cell. Layout comes from `.tcf-scrub`; this only
   says where it sits in the grid. */
.tcf-teaching-row__player {
  grid-column: 1 / -1;
  gap: var(--tcf-space-4);
  margin-top: var(--tcf-space-4);
  padding-top: var(--tcf-space-4);
  border-top: 1px solid var(--tcf-rule);
}
/* The row that is playing keeps its button, marked - and the button IS the pause
   control, so the triangle becomes two bars while sound is coming out. Paused, it
   goes back to a triangle on the warm fill, which is what "press me to resume"
   looks like. */
.tcf-teaching-row.is-playing .tcf-teaching-row__play { background-color: var(--tcf-accent); }
.tcf-teaching-row.is-playing .tcf-teaching-row__play-icon {
  width: 11px; height: 12px;
  margin-left: 0;                          /* the triangle's optical offset, undone */
  border-width: 0 3px;
  border-style: solid;
  border-color: var(--tcf-page);
}

/* The player bar's download link sits on the dark band, so it takes the
   on-dark treatment rather than brick, and it must not wrap - "Download MP3"
   breaking after "Download" reads as two links. */
.tcf-teaching-hero .tcf-player {
  display: flex;
  /* Stated, and it matters. `.tcf-player` above turns itself into a column at
     560px for the standalone bar that has 120px of artwork beside its controls.
     This bar has no artwork, and inheriting that column was half of the zero-
     height defect below - it wraps instead. */
  flex-direction: row;
  align-items: center;
  gap: var(--tcf-space-5);
  padding: var(--tcf-space-4) var(--tcf-space-5);
  /* --tcf-on-dark-border, not --tcf-on-ink-rule. The 16% hairline composites to
     #3E3B38, 1.60:1 on the band. That was defensible while a 16.04:1 browser
     widget sat inside the panel and did the marking; it is not now that the
     panel is the boundary around our own transport. 40% paper composites to
     #74716D, 3.68:1, which is the 1.4.11 floor for a non-text boundary. Raising
     --tcf-hairline-alpha instead would need 34% to get there and would coarsen
     every hairline on the site, including the footer's.
     DS_TEACHING_SINGLE.md §2.3. */
  border: 1px solid var(--tcf-on-dark-border);
  border-radius: var(--tcf-radius);
}
/* ---------------------------------------------------------------------------
   The transport and the timeline ON INK

   `.tcf-scrub` was drawn against paper and cannot simply be moved here. Measured
   against the band (#1A1714) and against the panel it actually sits on (7% paper
   on ink, #2A2724):

     brick played track / thumb   2.63:1 on ink   FAILS WCAG 1.4.11 (3:1)
     brick play fill, playing     2.63:1 on ink   FAILS
     muted clock                  2.99:1 on ink   FAILS 1.4.3 as text

   The relationship inverts rather than changing: the played part stays the loud
   one and the unplayed track drops to the 3:1 floor, which is what an on-dark
   variant is for. Every value below is a token that already existed for this
   ground - no on-ink twins were invented.

     played / thumb  --tcf-on-ink-accent  #E0B9A6   9.91:1 on ink, 8.25:1 on panel
     track           --tcf-on-dark-border 40% paper 3.68:1 on ink, 3.06:1 on panel
     clock           --tcf-on-ink-body    #B8B0A4   8.32:1 on ink, 6.92:1 on panel
     play fill       --tcf-play-fill      #F0E8DA  14.67:1 on ink, 12.21:1 on panel
     glyph on it     --tcf-accent                   5.58:1 on the fill
     playing fill    --tcf-on-ink-accent            9.91:1 on ink
     bars on it      --tcf-ink                      9.91:1 on the fill

   The band's other foregrounds are untouched; they all pass AA today.
   --------------------------------------------------------------------------- */
.tcf-teaching-hero .tcf-scrub {
  --tcf-scrub-played: var(--tcf-on-ink-accent);
  --tcf-scrub-track:  var(--tcf-on-dark-border);
  --tcf-scrub-thumb:  var(--tcf-on-ink-accent);
  --tcf-scrub-clock:  var(--tcf-on-ink-body);
}
.tcf-teaching-hero .tcf-player {
  /* Hover keeps the brick glyph on a warm fill; `rule` is a paper hairline and
     is 13.61:1 here, so it stays legible on ink as well. Stated so the pair is
     visible in one place rather than inherited by accident. */
  --tcf-play-fill-hover: var(--tcf-rule);
  --tcf-play-fill-on:    var(--tcf-on-ink-accent);
  --tcf-play-glyph-on:   var(--tcf-ink);
}
.tcf-teaching-hero .tcf-player__play:focus-visible,
.tcf-teaching-hero .tcf-scrub__bar:focus-visible {
  outline: 2px solid var(--tcf-on-ink-accent);
  outline-offset: 2px;
}

.tcf-teaching-hero .tcf-player__audio { flex: 1 1 auto; min-width: 0; }
.tcf-teaching-hero .tcf-player__actions { margin: 0; flex: none; }
.tcf-teaching-hero .tcf-player__actions a {
  display: inline-block;
  white-space: nowrap;
  color: var(--tcf-page);
  font-family: var(--tcf-font-ui);
  font-size: 15px;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 4px;
}
.tcf-teaching-hero .tcf-player__actions a:hover { color: var(--tcf-on-ink-accent); }
.tcf-teaching-hero .tcf-player__actions a:focus-visible {
  outline: 2px solid var(--tcf-on-ink-accent);
  outline-offset: 2px;
}

@media (max-width: 767px) {
  .tcf-teaching-hero .tcf-player { flex-wrap: wrap; gap: var(--tcf-space-3); }
  /* `flex: none` + `width`, NOT `flex: 1 0 100%`. This was the other half of the
     zero-height defect, and it is worth writing down because the shorthand looks
     harmless: a flex-basis is a size on the MAIN axis, so the moment the rule
     above put this bar into a column, `100%` stopped meaning "take the whole
     line" and started meaning "be 100% of the container's height" - which for a
     container sized by its content is zero. Measured in Chromium: 600px viewport
     gave 502x54, 560px gave 462x0, and 560 is the breakpoint in the rule at
     .tcf-player, not a browser threshold. With `flex: none` the basis comes from
     `width`, which is a cross-axis size in a column and a main-axis one in a row,
     and the element is correct either way.
     This is the no-JavaScript path. With the script running the element draws
     nothing and is display:none, which also takes it out of the tab order - a
     focusable control with no pixels being worse than no control at all. */
  .tcf-teaching-hero .tcf-player__audio { flex: none; width: 100%; }
}

/* On a phone the transport and the timeline keep one line and Download takes
   its own beneath them. Measured: at a 320px viewport the panel's content box
   is 246px with this padding, the button is 48 and a track and a clock need
   150 - with the link on the same line it did not fit, and the timeline is the
   part that must not be squeezed to a stub. */
@media (max-width: 600px) {
  .tcf-teaching-hero .tcf-player--js { padding: var(--tcf-space-4); }
  .tcf-teaching-hero .tcf-player--js .tcf-player__actions { flex: 1 0 100%; }
}

/* ---------------------------------------------------------------------------
   NOTHING IS WRITTEN. This is the page, not a degraded version of one.

   Counted on the build site 2026-09-06 through tcf_teaching_summary(), over all
   892 published teachings: 16 render a summary, 26 render body prose, and 836
   have a recording and no written account at all. So this branch is 94% of the
   teaching pages on the site and it is designed for, not fallen back to.

   The empty state that used to sit here - "No summary has been written for this
   teaching yet" - is deleted, markup and rule together, on Jay's instruction. It
   reported the church's editorial state to a reader who had not been promised a
   summary and was not missing one until the page said so. Nothing replaces it on
   the public page; the note that replaces it is `.tcf-editor-note`, which no
   visitor ever receives.

   What is left is "More in {book}", and it becomes the page rather than the
   footnote: six items instead of three, in two columns from 900px up, which is
   the same vertical cost as three in one column for double the payload. The
   `.is-textless` aside no longer needs an auto-fit grid of its own, because
   there is only one card in it now that the speaker is a line.
   --------------------------------------------------------------------------- */
.tcf-teaching-body.is-textless { grid-template-columns: minmax(0, 1fr); }
.tcf-teaching-body.is-textless .tcf-more-in {
  border: 0;
  padding: 0;
  margin-bottom: var(--tcf-rhythm-band);
}
/* Two columns only where the list divides evenly into two.
   The list length is min(6, term_count - 1), and it is emitted as a modifier
   class by the template because CSS cannot count children into a column count.
   Five items in a fixed two-column grid left a 617x86.2 empty cell and a
   hairline that stopped a row early - measured at 1440 on the Proverbs page,
   which has 6 teachings and so renders 5. Read off the live archive: 10 of the
   57 series terms produce an odd list, and the 21 terms with seven or more
   teachings produce six items and are untouched by this.
   Odd lists are 1, 3 or 5 items and read fine in the one column they already
   get below 900px. Nothing is dropped to make the grid balance. */
@media (min-width: 900px) {
  .tcf-teaching-body.is-textless .tcf-more-in__list--n2,
  .tcf-teaching-body.is-textless .tcf-more-in__list--n4,
  .tcf-teaching-body.is-textless .tcf-more-in__list--n6 {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: var(--tcf-space-7);
  }
  /* Two columns means the first TWO items are top-of-column, not just the
     first. Without this the right column keeps a stray hairline above its
     first row. */
  .tcf-teaching-body.is-textless .tcf-more-in__list--n2 > li:nth-child(-n+2),
  .tcf-teaching-body.is-textless .tcf-more-in__list--n4 > li:nth-child(-n+2),
  .tcf-teaching-body.is-textless .tcf-more-in__list--n6 > li:nth-child(-n+2) {
    border-top: 0;
  }
}

/* ---------------------------------------------------------------------------
   MOBILE DRAWER (§1.5, §3.4, §5.4, §5.8)

   Ink panel, paper text, sliding from the right. Blocksy owns the open/close
   behaviour, including the focus trap and Escape.
   --------------------------------------------------------------------------- */

/* §5.8: the hamburger was 18x18. A tap target is 44x44 whatever the icon
   inside it measures. */
html .ct-header-trigger {
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

html #offcanvas.ct-panel {
  --theme-palette-color-8: var(--tcf-ink);
}
/* !important for the same reason as the wordmark: enumerating every readable
   stylesheet finds no rule matching this element with a background-color, there
   is no inline style, and it still computes to Blocksy's rgba(18,21,25,0.98) -
   a blue-grey, not our ink. Third time this pattern has appeared. */
html #offcanvas .ct-panel-inner {
  background-color: var(--tcf-ink) !important;
  color: var(--tcf-on-ink-body);
  display: flex;
  flex-direction: column;
}
html #offcanvas .ct-panel-content { flex: 1 1 auto; }
html #offcanvas .ct-menu-link,
html #offcanvas .ct-toggle-close {
  color: var(--tcf-page);
}
html #offcanvas .ct-menu-link {
  font-family: var(--tcf-font-ui);
  font-size: 17px;
  font-weight: 500;
  text-transform: none;
  letter-spacing: 0;
  min-height: 44px;
}
html #offcanvas .ct-menu-link:hover { color: var(--tcf-on-ink-accent); }
html #offcanvas .ct-toggle-close:focus-visible,
html #offcanvas .ct-menu-link:focus-visible {
  outline: 2px solid var(--tcf-on-ink-accent);
  outline-offset: 2px;
}
html #offcanvas .sub-menu .ct-menu-link { color: var(--tcf-on-ink-body); font-size: 15px; }

/* §1.5: the utility links and the primary button sit at the foot of the
   drawer, so the two things a visitor most often wants are reachable without
   scrolling past the whole navigation. */
.tcf-drawer-foot {
  margin-top: auto;
  padding: var(--tcf-space-5) 0 0;
  border-top: 1px solid var(--tcf-on-ink-rule);
}
.tcf-drawer-foot__links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--tcf-space-4);
  margin: 0 0 var(--tcf-space-3);
}
.tcf-drawer-foot__links a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--tcf-on-ink-body);
  font-family: var(--tcf-font-ui);
  font-size: 15px;
  text-decoration: none;
}
.tcf-drawer-foot__links a:hover { color: var(--tcf-page); text-decoration: underline; }
.tcf-drawer-foot__when {
  margin: 0 0 var(--tcf-space-4);
  color: var(--tcf-on-ink-accent);
  font-family: var(--tcf-font-ui);
  font-size: 14px;
}
.tcf-drawer-foot__cta {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 14px 24px;
  background-color: var(--tcf-accent);
  color: var(--tcf-page);
  border-radius: var(--tcf-radius);
  font-family: var(--tcf-font-ui);
  font-size: 16px;
  font-weight: 600;
  text-decoration: none;
}
.tcf-drawer-foot__cta:hover { background-color: var(--tcf-accent-strong); color: var(--tcf-page); }

/* ---------------------------------------------------------------------------
   THE HERO SCRIM (§2a.1, §5.2)

   §5.2 calls the overlay load-bearing and sets a floor of rgba(20,17,14,0.75)
   behind any text; §2a.1 draws it left-weighted, 0.88 falling to 0.22.

   Core's own overlay could not deliver it. `has-ink-background-color` is not a
   class core generates - our palette slugs are the `--tcf-*` names, not `ink` -
   so the overlay computed to rgba(0,0,0,0), and `has-background-dim-75` never
   applied either, leaving core's default 0.5. Measured on the page: the scrim
   was doing nothing at all and the text sat on the bare photograph.

   So the scrim is drawn here from our own tokens rather than depending on
   core's palette classes resolving. It is a gradient, per 2a, and the flat
   floor is the fallback for browsers without gradient support.
   --------------------------------------------------------------------------- */
.tcf-has-hero .wp-block-cover > .wp-block-cover__background,
.home .wp-block-cover > .wp-block-cover__background {
  /* The values §2a.1 actually specifies: 0.88 at the left falling to 0.22.
     An earlier attempt set a flat 0.75 AND this gradient, which composite -
     the photograph came out far darker than the reference, where the room is
     plainly visible on the right. Gradient only. */
  background-color: transparent;
  background-image: linear-gradient(
    95deg,
    rgba(20, 17, 14, 0.88) 0%,
    rgba(20, 17, 14, 0.80) 38%,
    rgba(20, 17, 14, 0.52) 62%,
    rgba(20, 17, 14, 0.22) 100%
  );
  opacity: 1;                 /* core sets 0.5 here; the alpha is in the colour */
}

/* The gradient above stops in PERCENTAGES of the cover. The text column is a
   fixed 740px. The two only line up at the width the drawing was made at.

   As the viewport narrows, the same text runs further into the falloff, and
   below about 900 the column goes full-bleed and reaches the 0.22 tail.
   Measured 2026-09-07, 8px-blur background, share of the lede's own box under
   4.5:1: 0.0% at 1440, 1280 and 1199; 3.6% at 1100; 6.9% at 1024; 18.9% at 900;
   26.4% at 768; 28.8% at 390, where the worst pixel reads 1.96:1. The eyebrow
   fails from 900 down. So this crosses the line on a laptop, not on a phone.

   §5.2 asks 0.75 behind ANY text and §2a.1 draws the scrim left-weighted. Both
   hold on a desktop and cannot both hold once the text spans the frame, so the
   scrim is ROTATED rather than deepened: a left weighting is meaningless when
   there is no right-hand side left for the room to show through. Measured on the
   same harness: 6.16:1 worst at 390 and 6.67:1 at 768, against 1.96 and 2.22,
   with 0.0% of either element's area under 4.5:1 at any width.

   A flat 0.75 was built and measured too, and lost on every axis: it clears the
   lede by less (5.74:1), keeps less of the photograph, and it pushes the
   secondary button's border DOWN to 2.97:1 where this lifts it to 3.31. The
   solved requirement either way was p95 alpha 0.59-0.62, max 0.69.

   Ruled by Jay 2026-09-07, with the trade stated: an AA failure on the site's
   most-seen page outranks matching §2a.1's single gradient. Above 1199 nothing
   changes and §2a.1's drawing still renders exactly as before.
   docs/reviews/PUNCHLIST_DESIGN_SYSTEM.md §3.2 has the full table. */
@media (max-width: 1199px) {
  .tcf-has-hero .wp-block-cover > .wp-block-cover__background,
  .home .wp-block-cover > .wp-block-cover__background {
    background-image: linear-gradient(
      180deg,
      rgba(20, 17, 14, 0.62) 0%,
      rgba(20, 17, 14, 0.82) 55%,
      rgba(20, 17, 14, 0.88) 100%
    );
  }
}

/* On a dark cover the eyebrow and the secondary button take their on-ink
   values (§1.1) - brick on a photograph is neither legible nor the spec. */
.wp-block-cover.is-dark .is-style-eyebrow { color: var(--tcf-on-ink-accent); }
.wp-block-cover.is-dark .wp-block-button.is-style-outline > .wp-block-button__link {
  color: var(--tcf-page);
  /* --tcf-on-photo-border, not --tcf-on-dark-border: this button sits on a
     photograph, and the shared token's 3.68:1 is measured on solid ink. See the
     token definition for the numbers. */
  border-color: var(--tcf-on-photo-border);
  background: transparent;
}
.wp-block-cover.is-dark .wp-block-button.is-style-outline > .wp-block-button__link:hover {
  border-color: var(--tcf-page);
}

/* ---------------------------------------------------------------------------
   [hidden] has to be restated wherever we set an explicit display.

   UI_UX_BRIEF.md §6 documents this and it caught us again: the visitor
   selector's script sets panel.hidden = true correctly, and the panels stayed
   on screen because `.tcf-selector.is-enhanced .tcf-selector__panel` sets
   `display: grid`, which wins over the user-agent `[hidden] { display: none }`.
   All four panels rendered at once.

   Stated once, globally, rather than per component - the next component to set
   a display should not have to rediscover this.
   --------------------------------------------------------------------------- */
[hidden] { display: none !important; }


/* The panel's call to action is a filled button in the reference, not a link. */
.tcf-selector__cta-wrap { margin: var(--tcf-space-5) 0 0; }
.entry-content a.tcf-selector__cta,
a.tcf-selector__cta {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 14px 26px;
  background-color: var(--tcf-accent);
  color: var(--tcf-page);
  border-radius: var(--tcf-radius);
  font-family: var(--tcf-font-ui);
  font-size: 15px;
  font-weight: 600;
  text-decoration: none;
  transition: background-color 120ms ease;
}
.entry-content a.tcf-selector__cta:hover,
a.tcf-selector__cta:hover { background-color: var(--tcf-accent-strong); color: var(--tcf-page); }

/* ---------------------------------------------------------------------------
   Links on a brick background.

   The global link hover goes to --tcf-accent-strong (#7A3324), which on brick
   (#96412E) is 1.5:1 - the text effectively vanishes. §1.1 gives brick its own
   tints for exactly this reason. On brick a link is paper, and hovers to paper
   with an underline rather than to a darker brick.
   --------------------------------------------------------------------------- */
.has-brick-background-color a,
.wp-block-column.has-brick-background-color a,
.is-style-band-brick a {
  color: var(--tcf-page);
  text-decoration-color: var(--tcf-on-brick-rule);
}
.has-brick-background-color a:hover,
.wp-block-column.has-brick-background-color a:hover,
.is-style-band-brick a:hover {
  color: var(--tcf-page);
  text-decoration: underline;
  text-decoration-color: var(--tcf-page);
}
.has-brick-background-color a:focus-visible,
.wp-block-column.has-brick-background-color a:focus-visible {
  outline: 2px solid var(--tcf-page);
  outline-offset: 2px;
}
.has-brick-background-color .is-style-eyebrow { color: var(--tcf-on-brick-accent); }
.has-brick-background-color p { color: var(--tcf-on-brick-body); }
.has-brick-background-color :is(h1,h2,h3,h4,h5,h6) { color: var(--tcf-page); }


/* ---------------------------------------------------------------------------
   HOMEPAGE HERO (2a)

   Content in a left column, not the full width - the reference sets the H1 on
   three lines in roughly the left 45% with the room visible beside it.
   --------------------------------------------------------------------------- */
/* The band bleeds to the viewport edge; its text still starts on the same
   column as every band under it. */
.home .wp-block-cover__inner-container {
  max-width: 740px;
  margin-left: max(var(--tcf-gutter), calc(50vw - (var(--tcf-content-max) / 2)));
  margin-right: auto;
  padding-block: var(--tcf-space-7);
}
.home .wp-block-cover { position: relative; }
/* Core gives the inner container position: relative, which made it the
   containing block for the absolutely positioned card - so `right: 0` put the
   card at the right edge of the 740px text column, on top of the buttons,
   rather than at the right edge of the hero. */
.home .wp-block-cover > .wp-block-cover__inner-container { position: static; }

/* On a photograph the primary button inverts: paper fill, ink text. Brick on a
   darkened photograph is the one combination the reference does not use. */
.wp-block-cover.is-dark .wp-block-button:not(.is-style-outline) > .wp-block-button__link {
  background-color: var(--tcf-page);
  color: var(--tcf-ink);
}
.wp-block-cover.is-dark .wp-block-button:not(.is-style-outline) > .wp-block-button__link:hover {
  background-color: var(--tcf-surface);
  color: var(--tcf-ink);
}

/* The floating latest-teaching card, bottom right of the hero (2a.1).

   WIDTH IS A CONTRACT, NOT A CONSEQUENCE OF CONTENT.
   ---------------------------------------------------
   `width` below is `min(420px, 92%)` - a fixed cap clamped only by the
   viewport, never by what the teaching is called. It is NOT fit-content or
   max-content, on purpose: the archive has 900+ titles ranging from "The
   Sluggard" to "Sermon 2/17: Ordination Class: Summary of Dru Johnson's
   Principles of Reading Biblical Law" (92 characters, currently the longest),
   and the card's footprint must be identical for all of them. A later rule
   (§ CONTAINER METRICS, below) raises the desktop cap to 460px - still a fixed
   number, still content-independent - and wins by source order.

   That leaves height as the only axis a long title can still grow, since the
   title is allowed to wrap. `.tcf-hero-teaching__title` below caps that at two
   lines with `-webkit-line-clamp` (all engines TCF supports understand it -
   see MDN's browser-compat table for `-webkit-line-clamp`), with `max-height`
   as the fallback for the hypothetical engine that does not: two lines then
   clip cleanly with no third line poking out, rather than reading as broken.
   Proven against the 92-character title above and against a deliberately
   absurd ~230-character one - both hold the card to the same two-line height
   as today's short title; see docs/SESSION_KNOWLEDGE.md for the measurements.
   `.tcf-hero-teaching__meta` gets the matching one-line treatment: it carries
   the speaker name(s), and a long name or several joined by commas is exactly
   the same shape of bug as the title, just on one line instead of two. */
.tcf-hero-teaching-slot { margin: 0; }
.tcf-hero-teaching {
  position: absolute;
  right: max(var(--tcf-gutter), calc(50vw - (var(--tcf-content-max) / 2)));
  bottom: var(--tcf-space-6);
  z-index: 2;
  display: flex;
  align-items: center;
  gap: var(--tcf-space-4);
  width: min(420px, 92%);
  padding: var(--tcf-space-4);
  background: rgba(251, 248, 243, 0.97);
  border-radius: var(--tcf-radius);
}
.tcf-hero-teaching__art { flex: none; }
.tcf-hero-teaching__art img { display: block; width: 74px; height: 74px; border-radius: var(--tcf-radius); }
/* flex-basis 0%, not auto: this is the whole fix for the layout-mode flip.

   `flex-wrap: wrap` below exists for the audio player row (`__player`,
   `flex: 1 0 100%`), which must always drop to its own line. But wrap is
   decided per LINE, and the browser computes each item's hypothetical size
   for that decision from its flex-basis - with `auto`, that basis is the
   title's own max-content (unwrapped) width. A short title's max-content
   width fit beside the 74px art and 52px play button inside the 460px card;
   "Men's Breakfast 9/5: Purity in Proverbs" and longer did not, so THIS row
   itself wrapped: art, then body, then play stacked, and the card's whole
   shape flipped from a 114px row to a 271px stack purely on title length.

   Fixing that means the body's contribution to the wrap decision must not
   be its content size at all. `flex: 1 1 0%` reports a hypothetical size of
   zero for wrapping purposes - art (74) + body (0) + play (52) + two 16px
   gaps never approaches the 420px content box, so this row can never wrap on
   its own - then flex-grow:1 hands the body whatever space is left (262px at
   460px card width, every time), and the title wraps *inside* that fixed
   column instead of the column changing size. Proven at five breakpoints
   with five title lengths from "The Sluggard" to the 92-character archive
   title; see docs/SESSION_KNOWLEDGE.md. */
.tcf-hero-teaching__body { flex: 1 1 0%; min-width: 0; }
.tcf-hero-teaching__eyebrow {
  display: block;
  font-family: var(--tcf-font-ui);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--tcf-muted);
  /* Always the static word "LATEST TEACHING" today, but a label is still
     content once it comes from PHP rather than a literal in this file - one
     line, no wrap, so a future change here can't reopen this bug sideways. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.entry-content a.tcf-hero-teaching__title,
a.tcf-hero-teaching__title {
  display: -webkit-box;
  margin: 0.15rem 0 0.1rem;
  font-family: var(--tcf-font-serif);
  font-size: 22px;
  font-weight: 400;
  line-height: 1.2;
  color: var(--tcf-ink);
  text-decoration: none;
  /* Two lines, however long the title, with a graceful cut rather than a
     third line breaking the card open. `max-height` is the fallback for an
     engine that ignores line-clamp: it still clips at two lines, just without
     the ellipsis glyph - overflow stays hidden either way. */
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  overflow-wrap: anywhere;
  max-height: calc(1.2em * 2);
}
.entry-content a.tcf-hero-teaching__title:hover { color: var(--tcf-accent); }
.tcf-hero-teaching__meta {
  display: block;
  font-family: var(--tcf-font-ui);
  font-size: 14px;
  color: var(--tcf-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.entry-content a.tcf-hero-teaching__play,
a.tcf-hero-teaching__play {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  background: var(--tcf-accent);
  text-decoration: none;
  transition: background-color 120ms ease;
}
.entry-content a.tcf-hero-teaching__play:hover { background: var(--tcf-accent-strong); }
.tcf-hero-teaching__play-icon {
  width: 0; height: 0; margin-left: 3px;
  border-top: 7px solid transparent;
  border-bottom: 7px solid transparent;
  border-left: 11px solid var(--tcf-page);
}
/* Playing, the arrow becomes a pause glyph - this is the reported bug: the red
   arrow opened a player bar and then stayed an arrow, so the one control anybody
   presses on the home page looked inert while the teaching played underneath it. */
.tcf-hero-teaching.is-playing .tcf-hero-teaching__play-icon {
  width: 12px; height: 14px; margin-left: 0;
  border: 0;
  border-left: 4px solid var(--tcf-page);
  border-right: 4px solid var(--tcf-page);
}

@media (max-width: 900px) {
  /* §2a.1: below the hero as a full-width card on mobile. */
  .tcf-hero-teaching { position: static; width: 100%; margin-top: var(--tcf-space-5); }
  .home .wp-block-cover__inner-container { max-width: none; }
}

/* ===========================================================================
   MEASURED FROM design-reference.html, SCREEN 2a

   Every value below was read off the reference with getComputedStyle rather
   than inferred from the prose spec. Where the two disagree the reference
   wins, because it is what was approved.
   =========================================================================== */

/* Header ------------------------------------------------------------------ */
html .ct-header [data-id="menu"] > .menu > .menu-item > .ct-menu-link {
  color: #3B3630;                 /* not ink - the reference softens the nav */
}
html .ct-header [data-id="menu"] > .menu > .menu-item > a[href*="/plan-your-visit/"] {
  font-size: 15px;
  font-weight: 600;
}
.tcf-wordmark-tagline {
  display: block;
  margin-top: 4px;
  font-family: var(--tcf-font-ui);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.18em;
  line-height: 1.05;
  text-transform: uppercase;
  color: var(--tcf-accent);
}

/* Hero -------------------------------------------------------------------- */
.home .wp-block-cover .is-style-eyebrow {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.22em;
  color: var(--tcf-on-ink-accent);
  margin-bottom: 22px;
}
/* THIS WAS A FIXED 64px AT EVERY WIDTH, INCLUDING 320. Fixed 2026-08-10.
   Measured before the fix, on the live home page: the headline set at 64px on a
   390px phone, took SIX lines and 407px, covered the photograph it sits on, and
   pushed both hero buttons 153px below the fold. At 320 it was seven lines and
   the buttons were 486px down. Nothing overrode it - the only two other rules
   naming this selector set `text-wrap` and nothing else.
   That is a copy problem disguised as a stylesheet defect: it silently capped
   the headline at roughly 30 characters, and the cap was invisible to anyone
   writing copy on a laptop. It is why the hero headline was rewritten short.
   The clamp lands 64px from about 915px up (unchanged on every desktop) and 34px
   on a phone, which is the bottom of the type scale this file already uses. */
.home .wp-block-cover h1 {
  font-family: var(--tcf-font-serif);
  font-size: clamp(34px, 7vw, 64px);
  font-weight: 300;
  line-height: 1.06;
  letter-spacing: -0.02em;
  color: var(--tcf-page);
  margin: 0 0 26px;
}
.home .wp-block-cover .has-lede-font-size {
  font-size: 19px;
  font-weight: 400;
  line-height: 1.65;
  color: rgb(219, 211, 199);
  /* margin-inline: 0 explicitly. `.is-layout-constrained > *` sets
     margin-left/right: auto, so a max-width narrower than the container gets
     CENTRED - the lede sat indented from the headline above it. This is the
     constrained-layout trap in UI_UX_BRIEF.md §6. */
  /* !important because `.is-layout-constrained > *` sets the side margins with
     !important itself - UI_UX_BRIEF.md §6 records that overriding them is the
     only way to left-align a child that has its own max-width. */
  margin-left: 0 !important;
  margin-right: auto !important;
  margin-bottom: 32px;
  max-width: 56ch;
}
.wp-block-cover.is-dark .wp-block-button:not(.is-style-outline) > .wp-block-button__link {
  font-size: 16px;
  font-weight: 600;
}
.wp-block-cover.is-dark .wp-block-button.is-style-outline > .wp-block-button__link {
  font-size: 16px;
  font-weight: 500;
}

/* Floating teaching card ----------------------------------------------------- */
/* No `color` here. This rule used to carry `var(--tcf-tertiary)`, which is the
   one colour DESIGN_SYSTEM.md marks "fails body text" and which the handoff
   permits only for labels of 19px or larger at semibold. At 11px on the hero
   card it measured 3.43:1 against the panel. The class is declared twice in this
   file at equal specificity, so this later rule silently overrode the deliberate
   --tcf-muted set with the rest of the component above, and the correct value
   never rendered. Same shape as .is-style-section being pinned to a flat 36px.
   Deleting the declaration is the fix; the right value is already stated once. */
.tcf-hero-teaching__eyebrow { font-size: 11px; font-weight: 700; letter-spacing: 0.2em; }
.entry-content a.tcf-hero-teaching__title, a.tcf-hero-teaching__title { font-size: 22px; }
.tcf-hero-teaching__meta { font-size: 13.5px; color: var(--tcf-muted); }

/* When / Where / What to wear --------------------------------------------- */
.wp-block-columns.is-style-divided .is-style-eyebrow {
  font-size: 11.5px; font-weight: 700; letter-spacing: 0.2em; color: var(--tcf-accent);
  margin-bottom: 14px;
}
.wp-block-columns.is-style-divided h2,
.wp-block-columns.is-style-divided h4 {
  font-family: var(--tcf-font-serif);
  font-size: 27px; font-weight: 400; line-height: 1.25; letter-spacing: 0;
  color: var(--tcf-ink); margin: 0 0 12px;
}
.wp-block-columns.is-style-divided .has-small-font-size {
  font-size: 15px; line-height: 1.6; color: var(--tcf-muted); margin: 0;
}

/* Visitor selector --------------------------------------------------------- */
.tcf-selector-section .is-style-eyebrow,
.is-style-band-alt > .is-style-eyebrow {
  font-size: 11.5px; font-weight: 700; letter-spacing: 0.2em; color: var(--tcf-accent);
}
.is-style-band-alt > h2.is-style-section {
  font-family: var(--tcf-font-serif);
  font-size: 40px; font-weight: 400; line-height: 1.15; letter-spacing: -0.01em;
  color: var(--tcf-ink); margin: 0 0 28px;
}
.tcf-selector__tab { font-size: 15.5px; font-weight: 500; }
.tcf-selector__tab.is-current { font-weight: 600; }
/* No measure. The column is the measure - a 22ch cap came to about 370px and
   folded these headings onto three lines inside a 529px track. */
.tcf-selector__heading {
  font-family: var(--tcf-font-serif);
  font-size: 30px; font-weight: 400; line-height: 1.25; letter-spacing: 0;
  margin: 0 0 14px; max-width: none;
}
.tcf-selector__panel > p { font-size: 17px; line-height: 1.65; color: var(--tcf-muted); }
.entry-content a.tcf-selector__cta, a.tcf-selector__cta { font-size: 15.5px; font-weight: 600; }
.tcf-selector__points > li::before {
  font-family: var(--tcf-font-serif); font-size: 15px; font-weight: 400; color: var(--tcf-numeral);
}
.tcf-selector__point-title { font-size: 17px; font-weight: 600; color: var(--tcf-ink); }
.tcf-selector__point-desc { font-size: 15px; font-weight: 400; color: var(--tcf-muted); line-height: 1.6; }


/* WordPress marks its preset font-size classes !important, so
   `.has-small-font-size` beats any selector we can write. The reference sets
   this text at 15px; the preset is 13. Matched in kind rather than by
   restructuring the pattern away from a core class. */
.wp-block-columns.is-style-divided .has-small-font-size { font-size: 15px !important; }

/* The wordmark's second line.
   Blocksy exposes no hook around the logo - there is no
   blocksy:header:logo:after - so the text is carried in a custom property set
   from PHP and printed by the pseudo-element. It still reads from WordPress's
   own Site Tagline field, so it stays editable in Settings -> General. */
.site-title-container::after {
  content: var(--tcf-tagline, "");
  display: block;
  margin-top: 4px;
  font-family: var(--tcf-font-ui);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.18em;
  line-height: 1.05;
  text-transform: uppercase;
  color: var(--tcf-accent);
}

/* ---------------------------------------------------------------------------
   BRAND LOCKUP: the trinity mark, in the header and in the footer

   Sits here, after the tagline, because the two are the same mechanism solving
   the same problem: Blocksy exposes no hook around the logo, so both are
   pseudo-elements. Spec and every measurement: docs/LOGO_LOCKUP.md.

   Delivered as a background-image carrying its own two colours, NOT as a mask
   painted with currentColor. The first version was a mask, and it was wrong for
   one reason: the footer ground is ink (#1A1714), and a mask there takes the
   footer's paper text colour and paints the whole silhouette solid - a blob,
   not a mark. The artwork now carries explicit paper interiors, so it reads on
   paper, on ink and on a photograph without a single colour rule.

   The cost is that the mark no longer tints clay on hover with the wordmark.
   That is the correct trade: a logo should not take the colour of what it sits
   on, and no CSS property can repaint a background image by accident.
   --------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------
   Tokens

   Sizes are stated as the mark's HEIGHT, because height is the scarce dimension
   in an 88px header row. Width follows from the artwork's own viewBox, 1000 x
   964.

   --tcf-logo-lift is an optical correction, not a nudge to taste. The mark's
   centre of ink sits at 62.0% of its height, measured: a point at the top and
   two wide leaves at the bottom, so geometric centring reads low. Half of that
   error is corrected. Correcting all of it overshoots, because the point still
   counts for something in the silhouette.

   The image is a data URI rather than a file. The site's budget is 284 KB over
   7 requests; an eighth request for 6 KB is a worse trade than 2,670 gzipped
   bytes inside a stylesheet that is already being fetched.
   --------------------------------------------------------------------------- */
html:root {
  --tcf-logo-size:   48px;      /* mark height in the header, desktop */
  --tcf-logo-footer: 44px;      /* mark height in the footer - see below */
  --tcf-logo-ratio:  1.03734;   /* 1000 / 964, from the viewBox */
  /* The same mark with its interiors dropped and its line work painted paper:
     light line art for a dark ground. Used only by the footer. See the note on
     the footer rule for why the footer inverts and the podcast cover does not. */
  --tcf-logo-image-inverse: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1000 964'%3E%3Cg transform='translate(0.000000,964.000000) scale(0.200000,-0.200000)' fill='%23FBF8F3'%3E%3Cpath d='M2445 4806 c-360 -277 -607 -542 -801 -856 -196 -319 -344 -722 -382 -1042 -1 -11 -3 -26 -5 -33 -7 -37 -17 -183 -20 -295 -3 -106 -5 -128 -12 -134 -4 -4 -38 -26 -74 -49 -336 -211 -649 -549 -842 -909 -51 -95 -108 -217 -137 -293 -12 -32 -25 -65 -29 -75 -80 -201 -143 -522 -143 -733 l0 -116 17 -15 c37 -32 325 -137 501 -180 115 -29 215 -48 355 -67 69 -9 609 -9 677 0 131 18 295 53 396 84 193 59 407 150 527 223 19 11 35 11 55 0 119 -73 333 -164 526 -223 101 -31 265 -66 396 -84 68 -9 608 -9 678 0 74 10 220 34 260 44 175 40 299 78 464 143 73 29 121 51 131 60 l17 15 0 116 c0 211 -63 532 -143 733 -4 10 -17 43 -29 75 -29 76 -86 198 -137 293 -193 360 -506 698 -842 909 -36 23 -70 45 -74 49 -7 6 -9 28 -12 134 -3 112 -13 258 -20 295 -2 7 -4 22 -5 33 -35 293 -151 627 -333 960 -179 325 -495 674 -851 938 -27 20 -83 20 -109 0z m119 -180 c577 -439 977 -1126 1049 -1798 1 -17 4 -36 6 -43 5 -21 6 -450 1 -485 -2 -18 -8 -63 -13 -100 -17 -145 -86 -414 -134 -522 -4 -9 -14 -33 -23 -55 -35 -87 -118 -251 -166 -328 -125 -199 -232 -333 -395 -493 -91 -90 -75 -81 -165 -90 l-34 -3 3 -33 c2 -19 4 -37 5 -41 1 -4 1 -22 2 -40 0 -48 -1 -47 69 -40 60 5 61 5 84 -7 32 -16 106 -46 175 -70 82 -29 126 -42 215 -65 392 -99 943 -73 1328 63 45 16 56 32 52 76 -2 33 -27 167 -38 208 -3 10 -12 43 -20 75 -131 485 -423 916 -804 1183 -47 32 -45 16 -18 173 4 23 7 55 7 71 0 35 3 37 36 15 123 -84 159 -110 208 -150 301 -250 528 -556 686 -924 31 -72 93 -249 110 -315 31 -121 63 -278 73 -363 18 -156 19 -169 5 -177 -39 -26 -313 -119 -424 -145 -135 -31 -160 -36 -259 -50 -178 -25 -186 -25 -397 -25 -205 0 -229 1 -363 20 -242 35 -499 116 -717 226 -42 21 -77 38 -78 40 -1 1 -3 17 -4 35 0 18 -1 35 -1 37 0 2 -56 4 -125 4 -69 0 -125 -2 -125 -4 0 -2 -1 -19 -1 -37 -1 -18 -3 -34 -4 -35 -1 -2 -36 -19 -77 -40 -219 -110 -476 -191 -718 -226 -134 -19 -158 -20 -362 -20 -212 0 -220 0 -398 25 -99 14 -124 19 -259 50 -111 26 -385 119 -424 145 -14 8 -13 21 5 177 10 85 42 242 73 363 17 66 79 243 110 315 158 368 385 674 686 924 49 40 85 66 208 150 33 22 36 20 36 -15 0 -16 3 -48 7 -71 27 -157 29 -141 -18 -173 -381 -267 -673 -698 -804 -1183 -8 -32 -17 -65 -20 -75 -11 -41 -36 -175 -38 -208 -4 -44 7 -60 52 -76 385 -136 936 -162 1329 -63 88 23 132 36 215 65 68 24 142 54 174 70 23 12 24 12 84 7 70 -7 69 -8 69 40 1 18 1 36 2 40 1 4 3 22 5 41 l3 33 -34 3 c-90 9 -74 0 -165 90 -163 160 -270 294 -395 493 -48 77 -131 241 -166 328 -9 22 -19 46 -23 55 -48 108 -117 377 -134 522 -5 37 -11 82 -13 100 -5 35 -4 464 1 485 2 7 5 26 6 43 72 671 465 1348 1043 1794 75 58 64 57 134 4z m-1242 -2757 c35 -138 140 -401 204 -511 6 -11 28 -50 48 -85 117 -205 321 -466 456 -583 38 -34 41 -29 -41 -62 -354 -139 -730 -180 -1106 -120 -28 4 -64 10 -81 12 -85 13 -277 63 -281 74 -10 27 56 267 121 439 113 297 355 630 594 814 35 27 65 51 67 53 6 10 10 3 19 -31z m2392 17 c13 -11 46 -37 74 -58 222 -174 462 -509 570 -795 65 -172 131 -412 121 -439 -4 -11 -196 -61 -281 -74 -17 -2 -53 -8 -80 -12 -288 -46 -581 -32 -870 41 -88 23 -308 102 -308 111 0 2 14 15 30 30 135 117 339 378 456 583 20 35 42 74 48 85 64 110 169 373 204 511 5 20 10 36 11 36 1 0 12 -9 25 -19z'/%3E%3Cpath d='M2465 4356 c-244 -156 -612 -674 -736 -1036 -33 -96 -40 -118 -44 -132 -2 -9 -9 -33 -15 -55 -13 -46 -13 -49 -35 -150 -61 -291 -60 -635 3 -920 18 -80 24 -104 50 -180 115 -349 291 -639 529 -874 61 -60 88 -76 137 -83 17 -2 32 -6 34 -7 4 -4 3 -126 -1 -148 l-3 -16 116 0 116 0 -3 16 c-4 22 -5 144 -1 148 2 1 17 5 34 7 49 7 76 23 137 83 258 255 486 654 564 986 78 335 84 671 18 988 -22 101 -22 104 -35 150 -6 22 -13 46 -15 55 -4 14 -11 36 -44 132 -66 194 -196 433 -333 615 -146 194 -389 435 -438 435 -7 0 -23 -6 -35 -14z m153 -262 c128 -130 178 -190 274 -329 66 -96 148 -241 185 -330 8 -18 18 -41 23 -52 57 -131 99 -265 137 -445 7 -31 12 -62 26 -158 7 -44 8 -420 2 -472 -15 -129 -37 -235 -72 -355 -77 -266 -243 -563 -422 -758 l-26 -27 0 467 0 468 136 4 c75 2 168 3 207 3 l72 0 16 14 c21 20 23 36 24 244 0 248 22 223 -202 228 -94 2 -188 4 -210 5 l-40 2 -3 270 c-1 148 -5 274 -7 278 -11 23 -21 24 -238 24 -217 0 -227 -1 -238 -24 -2 -4 -6 -130 -7 -278 l-2 -270 -40 -2 c-22 -1 -117 -3 -211 -5 -224 -5 -202 20 -202 -228 1 -208 3 -224 24 -244 l16 -14 72 0 c39 0 132 -1 207 -3 l136 -4 0 -468 0 -467 -26 27 c-179 195 -345 492 -422 758 -23 76 -46 178 -57 245 -19 120 -21 153 -19 360 2 110 4 210 6 222 14 96 19 127 26 158 38 180 80 314 137 445 5 11 15 34 23 52 62 148 182 340 319 510 43 53 248 260 258 260 5 0 58 -50 118 -111z m-10 -1055 c3 -4 6 -126 7 -272 3 -289 2 -284 32 -297 6 -3 103 -7 216 -9 l205 -3 1 -106 1 -106 -19 -3 c-10 -1 -104 -3 -209 -3 l-191 0 -14 -12 c-21 -18 -21 -24 -22 -640 0 -491 -1 -580 -7 -603 -5 -15 -8 -35 -8 -44 l0 -16 -100 0 -100 0 0 16 c0 9 -3 29 -7 44 -7 23 -8 112 -8 603 -1 616 -1 622 -22 640 l-14 12 -191 0 c-105 0 -199 2 -209 3 l-19 3 1 106 2 106 205 3 c112 2 209 6 215 9 30 13 29 8 32 297 1 146 4 268 7 272 3 4 30 6 108 6 78 0 105 -2 108 -6z'/%3E%3C/g%3E%3C/svg%3E");
  --tcf-logo-gap:    14px;      /* mark to wordmark */
  --tcf-logo-lift:   0.06;      /* optical rise, as a fraction of the height */
  --tcf-logo-image:  url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1000.000000 964.000000'%3E%3Cg transform='translate(0.000000,964.000000) scale(0.200000,-0.200000)'%3E %3Cg fill='%23FBF8F3'%3E %3Cpath d='M2411 4766 c-322 -247 -566 -514 -767 -835 -246 -395 -385 -865 -397 -1344 -3 -140 -4 -146 -33 -162 -651 -366 -1140 -1166 -1207 -1972 -14 -176 -11 -185 61 -214 11 -4 36 -15 57 -23 88 -35 131 -51 181 -68 66 -22 204 -62 234 -68 12 -3 43 -9 68 -15 66 -15 87 -19 164 -30 39 -6 78 -11 88 -13 226 -34 660 -23 848 23 11 2 51 11 90 20 219 50 492 155 662 255 32 19 48 19 80 0 170 -100 443 -205 663 -255 38 -9 79 -18 90 -20 187 -46 621 -57 847 -23 10 2 49 7 88 13 77 11 98 15 165 30 24 6 55 12 67 15 30 6 168 46 234 68 50 17 93 33 181 68 21 8 47 19 58 23 71 29 74 38 60 214 -67 806 -556 1606 -1207 1972 -29 16 -30 22 -33 162 -11 456 -122 854 -353 1268 -77 139 -171 275 -287 415 -159 193 -557 550 -613 550 -17 0 -28 -7 -89 -54z'/%3E %3C/g%3E %3Cg fill='%231A1714'%3E %3Cpath d='M2445 4806 c-360 -277 -607 -542 -801 -856 -196 -319 -344 -722 -382 -1042 -1 -11 -3 -26 -5 -33 -7 -37 -17 -183 -20 -295 -3 -106 -5 -128 -12 -134 -4 -4 -38 -26 -74 -49 -336 -211 -649 -549 -842 -909 -51 -95 -108 -217 -137 -293 -12 -32 -25 -65 -29 -75 -80 -201 -143 -522 -143 -733 l0 -116 17 -15 c37 -32 325 -137 501 -180 115 -29 215 -48 355 -67 69 -9 609 -9 677 0 131 18 295 53 396 84 193 59 407 150 527 223 19 11 35 11 55 0 119 -73 333 -164 526 -223 101 -31 265 -66 396 -84 68 -9 608 -9 678 0 74 10 220 34 260 44 175 40 299 78 464 143 73 29 121 51 131 60 l17 15 0 116 c0 211 -63 532 -143 733 -4 10 -17 43 -29 75 -29 76 -86 198 -137 293 -193 360 -506 698 -842 909 -36 23 -70 45 -74 49 -7 6 -9 28 -12 134 -3 112 -13 258 -20 295 -2 7 -4 22 -5 33 -35 293 -151 627 -333 960 -179 325 -495 674 -851 938 -27 20 -83 20 -109 0z m119 -180 c577 -439 977 -1126 1049 -1798 1 -17 4 -36 6 -43 5 -21 6 -450 1 -485 -2 -18 -8 -63 -13 -100 -17 -145 -86 -414 -134 -522 -4 -9 -14 -33 -23 -55 -35 -87 -118 -251 -166 -328 -125 -199 -232 -333 -395 -493 -91 -90 -75 -81 -165 -90 l-34 -3 3 -33 c2 -19 4 -37 5 -41 1 -4 1 -22 2 -40 0 -48 -1 -47 69 -40 60 5 61 5 84 -7 32 -16 106 -46 175 -70 82 -29 126 -42 215 -65 392 -99 943 -73 1328 63 45 16 56 32 52 76 -2 33 -27 167 -38 208 -3 10 -12 43 -20 75 -131 485 -423 916 -804 1183 -47 32 -45 16 -18 173 4 23 7 55 7 71 0 35 3 37 36 15 123 -84 159 -110 208 -150 301 -250 528 -556 686 -924 31 -72 93 -249 110 -315 31 -121 63 -278 73 -363 18 -156 19 -169 5 -177 -39 -26 -313 -119 -424 -145 -135 -31 -160 -36 -259 -50 -178 -25 -186 -25 -397 -25 -205 0 -229 1 -363 20 -242 35 -499 116 -717 226 -42 21 -77 38 -78 40 -1 1 -3 17 -4 35 0 18 -1 35 -1 37 0 2 -56 4 -125 4 -69 0 -125 -2 -125 -4 0 -2 -1 -19 -1 -37 -1 -18 -3 -34 -4 -35 -1 -2 -36 -19 -77 -40 -219 -110 -476 -191 -718 -226 -134 -19 -158 -20 -362 -20 -212 0 -220 0 -398 25 -99 14 -124 19 -259 50 -111 26 -385 119 -424 145 -14 8 -13 21 5 177 10 85 42 242 73 363 17 66 79 243 110 315 158 368 385 674 686 924 49 40 85 66 208 150 33 22 36 20 36 -15 0 -16 3 -48 7 -71 27 -157 29 -141 -18 -173 -381 -267 -673 -698 -804 -1183 -8 -32 -17 -65 -20 -75 -11 -41 -36 -175 -38 -208 -4 -44 7 -60 52 -76 385 -136 936 -162 1329 -63 88 23 132 36 215 65 68 24 142 54 174 70 23 12 24 12 84 7 70 -7 69 -8 69 40 1 18 1 36 2 40 1 4 3 22 5 41 l3 33 -34 3 c-90 9 -74 0 -165 90 -163 160 -270 294 -395 493 -48 77 -131 241 -166 328 -9 22 -19 46 -23 55 -48 108 -117 377 -134 522 -5 37 -11 82 -13 100 -5 35 -4 464 1 485 2 7 5 26 6 43 72 671 465 1348 1043 1794 75 58 64 57 134 4z m-1242 -2757 c35 -138 140 -401 204 -511 6 -11 28 -50 48 -85 117 -205 321 -466 456 -583 38 -34 41 -29 -41 -62 -354 -139 -730 -180 -1106 -120 -28 4 -64 10 -81 12 -85 13 -277 63 -281 74 -10 27 56 267 121 439 113 297 355 630 594 814 35 27 65 51 67 53 6 10 10 3 19 -31z m2392 17 c13 -11 46 -37 74 -58 222 -174 462 -509 570 -795 65 -172 131 -412 121 -439 -4 -11 -196 -61 -281 -74 -17 -2 -53 -8 -80 -12 -288 -46 -581 -32 -870 41 -88 23 -308 102 -308 111 0 2 14 15 30 30 135 117 339 378 456 583 20 35 42 74 48 85 64 110 169 373 204 511 5 20 10 36 11 36 1 0 12 -9 25 -19z'/%3E %3Cpath d='M2465 4356 c-244 -156 -612 -674 -736 -1036 -33 -96 -40 -118 -44 -132 -2 -9 -9 -33 -15 -55 -13 -46 -13 -49 -35 -150 -61 -291 -60 -635 3 -920 18 -80 24 -104 50 -180 115 -349 291 -639 529 -874 61 -60 88 -76 137 -83 17 -2 32 -6 34 -7 4 -4 3 -126 -1 -148 l-3 -16 116 0 116 0 -3 16 c-4 22 -5 144 -1 148 2 1 17 5 34 7 49 7 76 23 137 83 258 255 486 654 564 986 78 335 84 671 18 988 -22 101 -22 104 -35 150 -6 22 -13 46 -15 55 -4 14 -11 36 -44 132 -66 194 -196 433 -333 615 -146 194 -389 435 -438 435 -7 0 -23 -6 -35 -14z m153 -262 c128 -130 178 -190 274 -329 66 -96 148 -241 185 -330 8 -18 18 -41 23 -52 57 -131 99 -265 137 -445 7 -31 12 -62 26 -158 7 -44 8 -420 2 -472 -15 -129 -37 -235 -72 -355 -77 -266 -243 -563 -422 -758 l-26 -27 0 467 0 468 136 4 c75 2 168 3 207 3 l72 0 16 14 c21 20 23 36 24 244 0 248 22 223 -202 228 -94 2 -188 4 -210 5 l-40 2 -3 270 c-1 148 -5 274 -7 278 -11 23 -21 24 -238 24 -217 0 -227 -1 -238 -24 -2 -4 -6 -130 -7 -278 l-2 -270 -40 -2 c-22 -1 -117 -3 -211 -5 -224 -5 -202 20 -202 -228 1 -208 3 -224 24 -244 l16 -14 72 0 c39 0 132 -1 207 -3 l136 -4 0 -468 0 -467 -26 27 c-179 195 -345 492 -422 758 -23 76 -46 178 -57 245 -19 120 -21 153 -19 360 2 110 4 210 6 222 14 96 19 127 26 158 38 180 80 314 137 445 5 11 15 34 23 52 62 148 182 340 319 510 43 53 248 260 258 260 5 0 58 -50 118 -111z m-10 -1055 c3 -4 6 -126 7 -272 3 -289 2 -284 32 -297 6 -3 103 -7 216 -9 l205 -3 1 -106 1 -106 -19 -3 c-10 -1 -104 -3 -209 -3 l-191 0 -14 -12 c-21 -18 -21 -24 -22 -640 0 -491 -1 -580 -7 -603 -5 -15 -8 -35 -8 -44 l0 -16 -100 0 -100 0 0 16 c0 9 -3 29 -7 44 -7 23 -8 112 -8 603 -1 616 -1 622 -22 640 l-14 12 -191 0 c-105 0 -199 2 -209 3 l-19 3 1 106 2 106 205 3 c112 2 209 6 215 9 30 13 29 8 32 297 1 146 4 268 7 272 3 4 30 6 108 6 78 0 105 -2 108 -6z'/%3E %3C/g%3E %3C/g%3E %3C/svg%3E");
}

/* ---------------------------------------------------------------------------
   The mark keeps its own colours, and that decides how it is delivered

   Ruled by the client: the mark is used as supplied. Black line art, and the
   white inside the line art stays white. It is not re-inked, not tinted brick,
   and not two-tone.

   In the supplied file those interiors are TRANSPARENT. They only look white
   because a white page is showing through, which is fine until the mark sits on
   anything else. Measured on the ink footer, #1A1714 line art on a #1A1714
   ground is 1.01:1 - the mark does not go faint, it ceases to exist. So the
   artwork now carries the interiors as real paper-coloured shapes underneath the
   strokes, and the mark brings its own figure and ground wherever it goes. That
   is the only change made to it, and it makes the supplied appearance TRUE
   rather than borrowed.

   Paper #FBF8F3 rather than #FFFFFF, and this was rendered before it was
   decided: a pure-white interior on the paper header is a visible bright patch
   around the mark. Paper is what this site's white IS.

   Delivered as a BACKGROUND IMAGE, which is the opposite of the previous
   version and for the opposite reason. A mask carries no colour, which is what
   you want when a mark must follow its surroundings and exactly what you must
   not have when it must not. A background image carries its own colours and
   there is no CSS property that can repaint it - not currentColor, not a fill
   rule, not a Customizer setting. The mark is therefore immune by construction
   rather than by defending against each thing in turn.
   --------------------------------------------------------------------------- */

/* Blocksy lays the header row out with flex, and a flex item will not shrink
   below its content unless it is told it may. Without this the lockup refuses
   to wrap and pushes the menu trigger off the right edge instead - which is how
   a wrap that is correct becomes an overflow that is not. */
html .site-branding { min-width: 0; }

html .site-branding .site-title-container {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  /* The box honestly contains the mark, so the row centres the lockup and not
     just the lines of type inside it. */
  min-height: var(--tcf-logo-size);
  padding-left: calc(var(--tcf-logo-size) * var(--tcf-logo-ratio) + var(--tcf-logo-gap));
}

/* Both lines are positioned by the container, so neither may establish a
   containing block of its own. */
html .site-branding .site-title { position: static; }

/* On the anchor, not the container, so the mark is inside the home link and
   clicking it goes home. Verified with elementFromPoint at the mark's centre:
   the element returned is the <a>.

   A pseudo-element because Blocksy exposes no hook around the logo - there is
   no blocksy:header:logo:after. The wordmark's second line reached the same
   conclusion for the same reason and is a ::after on the container above, so
   the precedent is already set in this file. It also means the mark is not in
   the accessibility tree, which is correct: beside the name it stands for it
   is decorative, and this makes it decorative by construction rather than by
   remembering an aria-hidden. */
html .site-branding .site-title a::before {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  translate: 0 calc(-50% - (var(--tcf-logo-size) * var(--tcf-logo-lift)));
  width:  calc(var(--tcf-logo-size) * var(--tcf-logo-ratio));
  height: var(--tcf-logo-size);
  background: var(--tcf-logo-image) left center / contain no-repeat;
}

/* ---------------------------------------------------------------------------
   Responsive

   The lockup is horizontal at every width. Stacking the mark above the name
   would make the branding block about 96px tall, and the middle row is 88px by
   a decision with reasons attached above.

   The wordmark keeps its settled 23px everywhere, and on a narrow phone it
   wraps to two lines rather than shrinking. Measured in Newsreader at 23px,
   against a 44px menu trigger and 24px edges:

     today, no mark      the wordmark holds one line down to 374px
     with a 44px mark    it holds one line down to 434px

   So on a 390px phone the mark does cost a line break, and it is still right.
   The header ALREADY wraps below 374px, so a wrapping branding block is a state
   the design has to handle regardless. And the ways out are worse: a 20px
   wordmark clears 390px by one pixel and wraps at 360px anyway; a 19px one
   clears it by five and also wraps at 360px. Both shrink the church's name
   permanently, on every phone, to buy one line across a 50px band of widths.

   The mark is then sized to the block it sits beside, not the other way round:

     >= 1280px   48px   one line of wordmark, and width to spare
     1000-1279   42px   the desktop nav is at its widest here relative to the
                        container; this is the only band where the two compete
     <= 999.98   44px   Blocksy's mobile header. No nav, the wordmark wraps to
                        two lines, and a 64px text block carries a larger mark
                        than a 40px one does

   Smallest in the middle and full size at both ends, which is the opposite of
   the usual "shrink it on phones" reflex and is what the measurements ask for.

   Nothing here depends on the length of the tagline. It is
   content: var(--tcf-tagline), sourced from the Site Tagline field, and can be
   edited to any string; the container is a column flexbox with a padding-left
   reservation, so a longer or shorter second line changes the block's height
   and width and changes nothing about the mark.
   --------------------------------------------------------------------------- */
@media (max-width: 1279.98px) {
  html:root { --tcf-logo-size: 42px; --tcf-logo-gap: 12px; }
}

@media (max-width: 999.98px) {
  html:root { --tcf-logo-size: 44px; --tcf-logo-gap: 14px; }
}

/* ---------------------------------------------------------------------------
   The footer

   To the LEFT of the identity block, tops aligned, exactly as in the header.

   It was above the name first, on the argument that the column is 1.4fr and the
   name is the widest thing in it, so a mark alongside would squeeze the name or
   widen the column. Measured, that argument does not hold: the column is 369.1px
   at desktop and 350px at 390, the widest line is the address at 270.4px, and
   the mark plus its gap costs 59.7px. 270.4 + 59.7 = 330.1, inside both. Nothing
   is squeezed and the column does not move.

   Jay's call, and the right one: the header sets the pattern for what this
   church's identity looks like, and the footer repeating it in a different
   arrangement reads as a second, unrelated lockup rather than the same one said
   quietly.

   Top-aligned rather than centred on the block. Centred was rendered and it
   drops the mark below the line the other three columns start on; top:0 keeps
   the mark's top on the same grid line as the Visit / Listen / Church headings.

   INVERTED HERE, NOT FILLED. This uses --tcf-logo-image-inverse: the mark's
   line work painted paper, interiors dropped, so the footer shows light line
   art on dark exactly as the header shows dark line art on light.

   The filled artwork also works on ink - its paper interiors carry the shape -
   but it reads as a different object. Figure and ground swap, so you get a
   solid badge with lines cut into it rather than line art, and measured at
   actual size it is the brightest thing in the identity block, brighter than
   the 21px wordmark beside it. A footer meant to restate the header quietly
   should not be louder than it at a smaller size.

   Rendered at 44px at 1x before choosing: the paper strokes hold at 1-2px and
   do not bloom into the 2.2px channels. Some segments antialias to mid-grey,
   visible at 6x and not at true size.

   The podcast cover deliberately does NOT follow. It is seen at 55-120px in a
   podcast app, out of context, on grounds nobody here controls, and thin line
   art goes faint at that size where the filled badge survives. Different
   problem, different answer.

   NOT filter: invert(1) on the existing image. It looks like it would save the
   2.3 KB and does not: it yields near-white lines on a #04070C plate, which is
   close to the ink ground but not it, so a faint dark rectangle shows behind
   the mark - and it flips the palette's warmth to cool.

   Only on the full footer. The condensed one is the copyright line by itself,
   with no identity column to sit in, so the selector cannot match it.
   --------------------------------------------------------------------------- */
/* 44px, not 40, and not just a smaller version of the header's 48.

   The mark's optical weight depends on its ground. On the paper header it is
   thin ink lines and reads light; on the ink footer it is a solid paper
   silhouette with lines cut into it, and reads as a filled object. So 44 here
   is genuinely quieter than 48 there rather than merely smaller.

   The ink lines are what fail first, so this was judged at 1x rather than 2x,
   rendered against the real footer: at 36 the cross is a blob and the knot's
   channels close; at 40 the cross stem fuses into the vesica; at 44 the cross
   reads and the three leaves separate. 52 reads too but starts competing with
   the header. */
html .tcf-footer__identity {
  position: relative;
  padding-left: calc(var(--tcf-logo-footer) * var(--tcf-logo-ratio) + var(--tcf-logo-gap));
}
html .tcf-footer__identity::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  width:  calc(var(--tcf-logo-footer) * var(--tcf-logo-ratio));
  height: var(--tcf-logo-footer);
  background: var(--tcf-logo-image-inverse) left top / contain no-repeat;
}

/* ---------------------------------------------------------------------------
   Forced colours, and print

   Both discard background images, so in both the mark disappears and the
   wordmark does not. That is a graceful loss - the wordmark carries the meaning
   - and it is written down rather than left to be discovered, so that nobody
   later "fixes" it into an <img> and loses the reason the mark is a background
   in the first place.

   Print can be argued with: print-color-adjust asks the browser to paint it
   anyway. Worth having, because a printed page with the mark on it is the
   church's letterhead.
   --------------------------------------------------------------------------- */
@media (forced-colors: active) {
  html .site-branding .site-title a::before,
  html .tcf-footer__identity::before { display: none; }
  html .tcf-footer__identity { padding-left: 0; }
  html .site-branding .site-title-container { padding-left: 0; min-height: 0; }

  /* In forced colours the ink band and the paper page become the same Canvas
     white and there is nothing between them - no border, no rule - so the
     teaching page loses its single most important structural boundary and reads
     as one continuous surface. Every foreground on the band survives (each one
     maps to a system colour and each is legible); it is only the boundary that
     goes, and this is how forced colours expects it back.
     DS_TEACHING_SINGLE.md §8. */
  .tcf-teaching-hero { border-bottom: 1px solid CanvasText; }
}

@media print {
  html .site-branding .site-title a::before,
  html .tcf-footer__identity::before {
    -webkit-print-color-adjust: exact;
            print-color-adjust: exact;
  }
}

/* The hero card's inline timeline: a full-width row inside the flex card.

   It fits on one line at 320px now, which the native bar never did - that bar
   carried its own play button, times, volume, an AirPlay control and a skip
   button, so on a phone the timeline inside it was squeezed to a stub and
   scrubbing was impossible. A track and a clock need 150px. */
.tcf-hero-teaching { flex-wrap: wrap; }
.tcf-hero-teaching__player {
  flex: 1 0 100%;
  margin-top: var(--tcf-space-3);
  padding-top: var(--tcf-space-3);
  border-top: 1px solid var(--tcf-rule);
}

/* ===========================================================================
   CONTAINER METRICS, MEASURED FROM THE REFERENCE (2a)

   Typography was matched first and the page still looked wrong, because the
   boxes around the type were not. These are the measured values.
   =========================================================================== */

/* Bands: 84px vertical inside the alternate band, 88px inside a plain section.
   §1.3 gives the range as 72-88; the reference sits at the top of it. */
.is-style-band-alt { padding-block: 84px; }
.is-style-band-ink { padding-block: 84px; }

/* Divided columns: 44px vertical, 40px horizontal per cell. */
.wp-block-columns.is-style-divided > .wp-block-column {
  padding: 44px 40px;
}
.wp-block-columns.is-style-divided > .wp-block-column:first-child { padding-left: 0; }
.wp-block-columns.is-style-divided > .wp-block-column:last-child { padding-right: 0; }

/* The floating teaching card: 460 wide, 20px padding, inset 40px from the hero's
   right and bottom edges rather than flush to them. */
.tcf-hero-teaching {
  width: min(460px, calc(100% - 80px));
  padding: 20px;
  right: 40px;
  bottom: 40px;
}

/* Selector: the panel's button, and its points at 16px vertical. */
.entry-content a.tcf-selector__cta, a.tcf-selector__cta { padding: 14px 26px; min-height: 46px; }
.tcf-selector__points > li { padding-top: 16px; padding-bottom: 16px; }

/* The distinctives: a 1px rule box, rows at 26px vertical. */
.is-style-numbered-rule {
  border: 1px solid var(--tcf-rule);
}
.is-style-numbered-rule > li {
  padding: 26px 4px 26px 3.5rem;
  border-top: 1px solid var(--tcf-rule);
}
.is-style-numbered-rule > li:first-child { border-top: 0; }
.is-style-numbered-rule > li::before { top: 26px; left: 1rem; }

@media (max-width: 767px) {
  .is-style-band-alt, .is-style-band-ink { padding-block: 44px; }
  .wp-block-columns.is-style-divided > .wp-block-column { padding: 24px 0; }
  .tcf-hero-teaching { width: 100%; padding: 16px; right: auto; bottom: auto; }
}

/* ---------------------------------------------------------------------------
   TWO PANELS (2a.7)

   Measured: the row is 387px tall, each panel padded 64/40, the right one on
   brick. They meet edge to edge with a 1px rule showing between them - the
   reference achieves that by letting the row's own background show through a
   gap, which is why the row is `rule` coloured rather than transparent.

   THE TOP EDGE IS A RULE FOR THE SAME REASON, added 2026-08-10.

   Jay: "the visual seperation between the row of home groups and kids and youth
   blends too well into the row above." Measured, and he was describing something
   exact rather than a vague unease. The paper panel is `--tcf-page` (#FBF8F3);
   the belief band directly above it is transparent, so it falls through to the
   body, which is ALSO #FBF8F3. Identical colour, no border, and `padding: 0` on
   the row. The left half of this row had no boundary at all - the only thing
   marking the seam was 64px of panel padding, which reads as space, not as an
   edge. The right half never had the problem because brick is brick.

   This is fallout from removing the brown events band. That band used to sit
   here and do the separating by colour; taking it out left two paper surfaces
   touching with nothing between them.

   The fix reuses the mechanism already in this component rather than inventing
   one: `padding-top: 1px` lets the row's own `--tcf-rule` background show as a
   hairline across the full width, exactly as the 1px `gap` already does between
   the two panels. Same colour, same idea, no new token, and the rule now turns
   the corner instead of stopping at the top of the gap.

   Deliberately NOT done: recolouring the paper panel to `--tcf-surface`. It
   would separate the row more strongly, but the alternation on this page is
   already correct top to bottom (paper, paper-alt, paper, THIS, paper-alt,
   paper) and tinting one half of one row would break the page's rhythm to fix a
   seam. If the hairline proves too quiet against a real photograph above it, the
   next move is a full-width band change, not a half-row tint.
   --------------------------------------------------------------------------- */
.tcf-two-panels {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1px;
  padding-top: 1px;
  background-color: var(--tcf-rule);
}
.tcf-two-panels__panel { padding: 64px 40px; }
.tcf-two-panels__panel--paper { background-color: var(--tcf-page); }
.tcf-two-panels__panel--brick { background-color: var(--tcf-accent); }
/* No measure on the heading. The canvas lets it run the full width of the
   panel (559px of 639) at weight 300; an 18ch cap was folding "The rest of the
   week happens in living rooms." onto three lines inside a panel with room for
   two. The body copy keeps a measure, and the canvas sets it in pixels. */
.tcf-two-panels__panel h3 {
  font-family: var(--tcf-font-serif);
  font-size: 34px;
  font-weight: 300;
  line-height: 1.22;
  letter-spacing: -0.01em;
  margin: 0 0 16px;
  max-width: none;
}
.tcf-two-panels__panel p { max-width: 420px; }
.tcf-two-panels__panel--brick h3 { color: var(--tcf-page); }
.tcf-two-panels__panel--brick p { color: var(--tcf-on-brick-body); }
.tcf-two-panels__panel--brick .is-style-eyebrow { color: var(--tcf-on-brick-accent); }

/* The inline arrow link (§1.4): brick, 600, underlined at 4px offset. */
.entry-content a.tcf-arrow-link, a.tcf-arrow-link {
  font-family: var(--tcf-font-ui);
  font-size: 15px;
  font-weight: 600;
  color: var(--tcf-accent);
  text-decoration: underline;
  text-underline-offset: 4px;
}
/* !important, and measured before reaching for it: the rule below is later and
   more specific than the brick default, and enumerating every readable
   stylesheet finds NO rule matching this anchor with a colour - yet it computed
   to brick on brick, invisible but for its underline. Same unfindable cascade
   as the wordmark and the drawer panel. */
.tcf-two-panels__panel--brick a.tcf-arrow-link,
.entry-content .tcf-two-panels__panel--brick a.tcf-arrow-link {
  color: var(--tcf-page) !important;
  -webkit-text-fill-color: var(--tcf-page) !important;
  text-decoration-color: var(--tcf-on-brick-rule);
}

@media (max-width: 767px) {
  .tcf-two-panels { grid-template-columns: 1fr; }
  .tcf-two-panels__panel { padding: 40px 24px; }
}

/* A plain section between bands takes 88px, measured from the reference's
   belief section. §1.3 gives 72-88; the reference sits at the top. */
.tcf-band-plain { padding-block: 88px; }
@media (max-width: 767px) { .tcf-band-plain { padding-block: 44px; } }


/* The panel row runs the full width in the reference, not inset in the content
   container. */
.tcf-two-panels {
  width: 100vw;
  max-width: 100vw;
  margin-left: calc(50% - 50vw) !important;
  margin-right: calc(50% - 50vw) !important;
}
/* The band is full-bleed but its CONTENTS align to the same inner gutter as
   every band above it, so the page keeps one left edge from the h1 down to the
   footer. The floor here used to be a literal 40px, which is only the gutter on
   a viewport of 1280 or wider. Measured on /life-together/home-groups/, the
   panel text sat 8px right of the intro and the cards at 768 and 1024, and 20px
   right of them at 375 - one edge for the top of the page and a second, nearly
   but not quite the same, for the bottom of it.

   `--tcf-gutter` is the same token the bands overhead resolve their inset from,
   so the two now move together by construction rather than by coincidence at
   one width. */
.tcf-two-panels__panel--paper { padding-left: max(var(--tcf-gutter), calc(50vw - (var(--tcf-content-max) / 2))); }
.tcf-two-panels__panel--brick { padding-right: max(var(--tcf-gutter), calc(50vw - (var(--tcf-content-max) / 2))); }

/* Stacked, both edges of both panels are the page edge, so both take the
   gutter. Without this the panels keep the 24px from the shorthand on one side
   and the gutter on the other, which is a 4px kink nobody asked for. The
   shorthand in the 767px block above cannot do this itself: the two rules
   directly overhead are unconditional and land after it. */
@media (max-width: 767px) {
  .tcf-two-panels__panel--paper,
  .tcf-two-panels__panel--brick { padding-inline: var(--tcf-gutter); }
}


/* ---------------------------------------------------------------------------
   Bands full-bleed, content capped and centred (§1.3)

   The blocks that carry a background colour break out to the viewport edge;
   what sits inside them is held to 1280 with a 40px gutter. Without the
   break-out a coloured band stops at the content width and reads as a card.
   --------------------------------------------------------------------------- */
.entry-content > .is-style-band-alt,
.entry-content > .is-style-band-ink,
.entry-content > .wp-block-columns.is-style-divided,
.entry-content > .tcf-band-plain {
  width: 100vw;
  max-width: 100vw;
  margin-left: calc(50% - 50vw) !important;
  margin-right: calc(50% - 50vw) !important;
}
.entry-content > .is-style-band-alt > *,
.entry-content > .is-style-band-ink > *,
.entry-content > .tcf-band-plain > * {
  width: min(var(--tcf-content-max), calc(100% - var(--tcf-gutter) * 2));
  margin-inline: auto;
}
.entry-content > .wp-block-columns.is-style-divided {
  width: min(var(--tcf-content-max), calc(100vw - var(--tcf-gutter) * 2));
  margin-inline: auto !important;
}

/* ---------------------------------------------------------------------------
   BAND-TO-BAND GAP IS ZERO (§1.3)

   "Bands butt together and are separated by colour or a rule hairline." The
   block editor gives every top-level block a vertical margin, which left ~25px
   of paper showing between each band - so a coloured band read as a floating
   slab rather than as one continuous page.

   Scoped to the top level of the content: margins inside a band are what give
   its prose its rhythm and are left alone.
   --------------------------------------------------------------------------- */
.entry-content > .is-style-band-alt,
.entry-content > .is-style-band-ink,
.entry-content > .tcf-band-plain,
.entry-content > .tcf-two-panels,
.entry-content > .wp-block-cover,
.entry-content > .wp-block-columns.is-style-divided,
.entry-content > .tcf-whats-on,
.entry-content > .tcf-closing {
  margin-block: 0 !important;
}

/* The divided facts row sits directly under the hero, so it needs its own
   breathing room rather than a margin that would open a gap. The hairline that
   separates its three columns carries on under the row, closing the block off
   against the band beneath it. */
.entry-content > .wp-block-columns.is-style-divided {
  padding-block: 0;
  border-bottom: 1px solid var(--tcf-rule);
}

/* ---------------------------------------------------------------------------
   FAQ (§2a.8) and CLOSING (§2a.9)
   --------------------------------------------------------------------------- */
/* Column split and gutter read off the canvas: 484.5 / 655.5 across 1140, with
   60px between them and 84px of band padding. */
.tcf-faq {
  display: grid;
  grid-template-columns: minmax(0, 0.425fr) minmax(0, 0.575fr);
  gap: 60px;
  align-items: start;
}
.tcf-faq__intro > h2 { margin-top: 0; }
.tcf-faq__intro .tcf-photo-slot { margin-top: var(--tcf-space-6); min-height: 220px; }
/* The real photograph took the slot's place (C5, 2026-08-10). It keeps the
   slot's top margin so the column below the email link is unchanged, and drops
   the 220px min-height, which existed to stop an EMPTY dashed box collapsing -
   a photograph brings its own height. 2px radius per the flat design. */
.tcf-faq__intro .tcf-faq__photo { margin-top: var(--tcf-space-6); }
.tcf-faq__intro .tcf-faq__photo img { width: 100%; height: auto; display: block; border-radius: 2px; }

.tcf-closing {
  display: grid;
  grid-template-columns: 1fr 1fr;
  /* The canvas butts the two panels together. A 1px rule between paper and
     #EFE9DD is invisible anyway, and it was costing a column of alignment. */
  gap: 0;
  width: 100vw;
  max-width: 100vw;
  margin-left: calc(50% - 50vw) !important;
  margin-right: calc(50% - 50vw) !important;
}
.tcf-closing__panel { padding: 76px 40px; }
.tcf-closing__panel--invite {
  background-color: var(--tcf-page);
  padding-left: max(40px, calc(50vw - (var(--tcf-content-max) / 2)));
}
/* #EFE9DD is the map panel's own colour in §2a.9 - a documented in-component
   neutral rather than a palette slot. */
.tcf-closing__panel--map {
  background-color: #EFE9DD;
  padding-right: max(40px, calc(50vw - (var(--tcf-content-max) / 2)));
}
.tcf-closing__panel h2 { margin-top: 0; margin-bottom: 16px; max-width: none; }
.tcf-closing__panel--invite > p { margin-bottom: 30px; }

/*
 * The venue and the street are two lines, not one address string: the building
 * belongs to another congregation, so its name is the thing a visitor is
 * looking for on the door and it carries the serif on its own line.
 */
.tcf-closing__venue {
  font-family: var(--tcf-font-serif);
  font-size: 1.625rem;   /* 26px */
  font-weight: 400;
  line-height: 1.35;
  color: var(--tcf-ink);
  margin-bottom: 0;
  max-width: none;
}
.tcf-closing__address {
  font-family: var(--tcf-font-sans);
  font-size: 1.0625rem;  /* 17px */
  font-weight: 400;
  line-height: 1.6;
  color: var(--tcf-muted);
  margin-top: 0;
  margin-bottom: 22px;
  max-width: none;
}

@media (max-width: 767px) {
  .tcf-faq { grid-template-columns: 1fr; gap: var(--tcf-space-6); }
  .tcf-closing { grid-template-columns: 1fr; }
  .tcf-closing__panel { padding: 40px 24px; }
}


/* The hero starts immediately under the header (§1.3: band-to-band gap is 0).
   Blocksy pads the content area away from the header, which opened a strip of
   paper above the photograph. */
/* Blocksy pads the content area away from both the header and the footer.
   §1.3 wants the bands butting against each other and against the footer, so
   both ends are closed. `.ct-container-full` is the one that carries the 60px
   at the bottom on this template. */
body.home .site-main,
body.home .ct-container,
body.home .ct-container-full,
body.home .entry-content { padding-top: 0 !important; margin-top: 0 !important; }
body.home .ct-container,
body.home .ct-container-full,
body.home .site-main,
body.home .entry-content { padding-bottom: 0 !important; margin-bottom: 0 !important; }
body.home .site-main > article > .entry-content > .wp-block-cover:first-child { margin-top: 0 !important; }
body.home [data-vertical-spacing] { padding-top: 0 !important; }

/* ---------------------------------------------------------------------------
   CANVAS CORRECTIONS, measured rather than estimated

   Every number below was read off the 2a canvas with getComputedStyle and
   compared against the same property on the live page. Where the two disagreed
   the canvas won.
   --------------------------------------------------------------------------- */

/* FAQ answers. The canvas sets them at 16.5px/28.05 in muted, and we were
   rendering 17px/29.75 in full-strength ink - which made every open answer
   read as heavy as the question above it. */
.tcf-accordion__panel,
.tcf-accordion__panel p {
  font-size: 1.03125rem;   /* 16.5px */
  font-weight: 400;
  line-height: 1.7;        /* 28.05px */
  color: var(--tcf-muted);
}

/* The map is 140px on the canvas.

   Capping .tcf-map alone did not work: the iframe inside it carries
   `aspect-ratio: 3 / 2`, so across a 600px panel it renders 400px tall and
   simply overflowed the box it had been given. The height has to go on the
   frame, and the aspect ratio has to be released for it to take effect.

   The plugin still asks OpenStreetMap for a 3:2 bounding box (TCF_MAP_ASPECT),
   and OSM fits that box into whatever frame it is handed - so a wide, short
   frame shows the same place with more of the street either side of it, rather
   than a stretched one. */
.tcf-closing__panel--map .tcf-map {
  margin-bottom: 0;
}
.tcf-closing__panel--map .tcf-map__frame {
  aspect-ratio: auto;
  height: 200px;
}

/* ---------------------------------------------------------------------------
   Links on brick

   A link inside a brick panel is paper at rest, and the global link-hover rule
   was turning it brick on hover - brick on brick, so it vanished under the
   pointer. On a coloured panel the hover cue is the underline, not the colour.
   --------------------------------------------------------------------------- */
.tcf-two-panels__panel--brick a,
.entry-content .tcf-two-panels__panel--brick a,
.is-style-band-ink a,
.entry-content .is-style-band-ink a,
[class*="--brick"] a,
.entry-content [class*="--brick"] a {
  color: var(--tcf-page);
}
.tcf-two-panels__panel--brick a:hover,
.tcf-two-panels__panel--brick a:focus-visible,
.entry-content .tcf-two-panels__panel--brick a:hover,
.entry-content .tcf-two-panels__panel--brick a:focus-visible,
.entry-content [class*="--brick"] a:hover,
.entry-content [class*="--brick"] a:focus-visible,
[class*="--brick"] a:hover,
[class*="--brick"] a:focus-visible {
  color: var(--tcf-page);
  -webkit-text-fill-color: var(--tcf-page);
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

/* ---------------------------------------------------------------------------
   Footer vertical rhythm (§1.6)

   The canvas footer is 243px tall: 56px above the columns, 40px below, and the
   brand block set solid at 27.75px leading. Ours was 394px, because the outer
   element carried 40px/16px of its own padding on top of the inner block's
   56px/40px, and the meeting time added a further 12px margin the canvas does
   not have.
   --------------------------------------------------------------------------- */
.tcf-footer { padding-top: 0; padding-bottom: 0; }
.tcf-footer__inner { padding: 40px 0 24px; }
.tcf-footer__name {
  font-size: 1.3125rem;   /* 21px */
  line-height: 1.3;
  margin-bottom: 10px;
}
.tcf-footer__when { margin-bottom: 0; }
.tcf-footer__identity p { margin-block: 0; }

/* Two panels butt together with a 2px seam on the canvas, not 1px. */
.tcf-two-panels { gap: 2px; }

/* ---------------------------------------------------------------------------
   WHAT'S ON (§2a)

   An ink band under the facts row. Numbers read off the canvas: 80px/40px band
   padding, a 32px gap under the head, cards at 28px/24px with the date set at
   34px in the serif over a 14px month in the sans.

   The canvas draws four cards butted together with a 1px gap, which on an ink
   band shows as nothing at all. This church has exactly three recurring
   gatherings, so the row is three columns and the seam is drawn as the
   on-ink hairline the rest of the site uses.
   --------------------------------------------------------------------------- */
.tcf-whats-on {
  background-color: var(--tcf-ink);
  /* The canvas sets 80px here for a four-card strip. Three cards need less
     room around them, and the band was reading as an interruption rather than
     as a shelf between two content bands. */
  padding-block: 52px;
  width: 100vw;
  max-width: 100vw;
  margin-left: calc(50% - 50vw) !important;
  margin-right: calc(50% - 50vw) !important;
}
/* The gutter is a floor, not an addition. Setting max-width AND padding put
   this band's content 40px inside every other band on the page. */
.tcf-whats-on__inner {
  width: min(100% - (var(--tcf-gutter) * 2), var(--tcf-content-max));
  margin-inline: auto;
}
.tcf-whats-on__head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--tcf-space-5);
  margin-bottom: 24px;
}
.tcf-whats-on__eyebrow {
  margin: 0 0 8px;
  font-family: var(--tcf-font-sans);
  font-size: 0.71875rem;   /* 11.5px */
  font-weight: 700;
  letter-spacing: 0.2em;   /* 2.3px */
  text-transform: uppercase;
  color: var(--tcf-on-ink-accent);
}
.tcf-whats-on__heading {
  margin: 0;
  font-family: var(--tcf-font-serif);
  font-size: 2.375rem;   /* 38px */
  font-weight: 300;
  line-height: 1;
  letter-spacing: -0.01em;
  color: var(--tcf-page);
}
.tcf-whats-on__all { margin: 0; }
.tcf-whats-on__all a,
.entry-content .tcf-whats-on__all a {
  font-family: var(--tcf-font-sans);
  font-size: 0.9375rem;   /* 15px */
  font-weight: 600;
  color: var(--tcf-on-ink-accent);
  text-decoration: none;
}
.tcf-whats-on__all a:hover,
.tcf-whats-on__all a:focus-visible,
.entry-content .tcf-whats-on__all a:hover,
.entry-content .tcf-whats-on__all a:focus-visible {
  color: var(--tcf-page);
  -webkit-text-fill-color: var(--tcf-page);
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

.tcf-whats-on__list {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0;
  margin: 0;
  padding: 0;
  list-style: none;
}
.tcf-whats-on__item {
  padding: 20px 24px;
  border: 1px solid var(--tcf-on-ink-rule);
  /* Collapse the shared edges so three cells read as one ruled strip rather
     than as three boxes with a double line between them. */
  margin-left: -1px;
}
.tcf-whats-on__item:first-child { margin-left: 0; }

.tcf-whats-on__date {
  margin: 0 0 10px;
  font-family: var(--tcf-font-serif);
  font-size: 2.125rem;   /* 34px */
  font-weight: 400;
  line-height: 1;
  color: var(--tcf-on-ink-accent);
}
.tcf-whats-on__month {
  margin-left: 0.35em;
  font-family: var(--tcf-font-sans);
  font-size: 0.875rem;   /* 14px */
  line-height: 1;
  color: var(--tcf-on-ink-muted);
}
.tcf-whats-on__title {
  margin: 0 0 6px;
  font-family: var(--tcf-font-sans);
  font-size: 1.1875rem;  /* 19px */
  font-weight: 600;
  line-height: 1.2;
  color: var(--tcf-page);
}
.tcf-whats-on__meta {
  margin: 0;
  font-family: var(--tcf-font-sans);
  font-size: 0.90625rem; /* 14.5px */
  font-weight: 400;
  line-height: 1.55;
  color: var(--tcf-on-ink-muted);
}

@media (max-width: 899px) {
  .tcf-whats-on { padding-block: 36px; }
  .tcf-whats-on__head { flex-direction: column; align-items: flex-start; }
  .tcf-whats-on__list { grid-template-columns: 1fr; }
  .tcf-whats-on__item {
    margin: -1px 0 0;
    padding: 24px;
  }
  .tcf-whats-on__item:first-child { margin-top: 0; }
}


/* ---------------------------------------------------------------------------
   HOME HERO, FULL BLEED

   Three things had to be corrected once the cover ran to the viewport edge.

   1. Core (and Blocksy) put 144px of top padding on an alignfull cover, which
      pushed the hero from 600px to 730px and dropped the headline down the
      frame. The band sets its own rhythm through the inner container.
   2. The inner container keeps `position: relative` from core, so it was the
      containing block for the teaching card - `right` measured from the right
      edge of the 740px text column instead of from the band.
   3. With that fixed the card anchors to the same content column as the text.
   --------------------------------------------------------------------------- */
body.home .entry-content > .wp-block-cover.alignfull {
  padding: 0 !important;
  position: relative;
}
body.home .entry-content > .wp-block-cover.alignfull > .wp-block-cover__inner-container {
  position: static !important;
}
body.home .tcf-hero-teaching {
  right: max(var(--tcf-gutter), calc(50vw - (var(--tcf-content-max) / 2))) !important;
}

@media (max-width: 899px) {
  body.home .tcf-hero-teaching { right: auto !important; }
}


/* ---------------------------------------------------------------------------
   BALANCED HEADINGS

   A display heading that wraps on its own breaks wherever the measure runs
   out, which left "Come this Friday. We / will save you a seat." - a line
   ending on a hanging pronoun, with the sentence boundary ignored. Balancing
   splits the two lines evenly, which here also puts the break at the full stop.

   Only on short headings: `balance` is capped at a handful of lines by the
   browser and is not meant for running text.
   --------------------------------------------------------------------------- */

/* Everything else fills its line before it wraps. */
.tcf-two-panels__panel h3,
.tcf-whats-on__heading,
.tcf-faq__intro > h2,
.home .wp-block-cover h1,
.tcf-selector__heading,
.is-style-section,
.is-style-display {
  text-wrap: wrap;
  text-wrap-style: auto;
}

/* ---------------------------------------------------------------------------
   NOTHING VANISHES UNDER THE POINTER

   Three separate controls have now lost their text on hover, each for the same
   reason: a body-copy link rule reaching a control that carries its own
   foreground, and repainting it in a colour that matched its background.

   Excluding them one at a time has not held, because the exclusion list has to
   be repeated on the hover rule and drifts. This is the backstop: anything with
   a filled background keeps its foreground through hover and focus, and the
   hover cue comes from the fill.
   --------------------------------------------------------------------------- */
.entry-content a.tcf-selector__cta,
a.tcf-selector__cta {
  background-color: var(--tcf-accent);
  color: var(--tcf-page);
  -webkit-text-fill-color: var(--tcf-page);
  text-decoration: none;
}
.entry-content a.tcf-selector__cta:hover,
.entry-content a.tcf-selector__cta:focus-visible,
a.tcf-selector__cta:hover,
a.tcf-selector__cta:focus-visible {
  background-color: var(--tcf-accent-strong);
  color: var(--tcf-page);
  -webkit-text-fill-color: var(--tcf-page);
  text-decoration: none;
}

/* Same guarantee for the two block-editor button styles, which sit on a fill
   for the same reason. */
.entry-content .wp-block-button__link:hover,
.entry-content .wp-element-button:hover {
  -webkit-text-fill-color: currentcolor;
}

/* ---------------------------------------------------------------------------
   OUTLINE BUTTONS KEEP THEIR TEXT ON HOVER

   Blocksy maps --theme-button-text-hover-color and
   --theme-button-background-hover-color to the same palette slot, so an outline
   button hovered to a solid fill painted its label in exactly the colour it had
   just filled itself with. "Listen to a teaching" disappeared on the hero.

   The rule below is deliberately last and deliberately explicit: a fill needs a
   foreground chosen against it, not one inherited from the link palette.
   --------------------------------------------------------------------------- */
.wp-block-button.is-style-outline > .wp-block-button__link:hover,
.wp-block-button.is-style-outline > .wp-block-button__link:focus-visible,
.entry-content .wp-block-button.is-style-outline > .wp-block-button__link:hover,
.entry-content .wp-block-button.is-style-outline > .wp-block-button__link:focus-visible {
  background-color: var(--tcf-accent-strong);
  border-color: var(--tcf-accent-strong);
  color: var(--tcf-page);
  -webkit-text-fill-color: var(--tcf-page);
}

/* On a photograph the pair inverts: the outline fills with paper and takes ink,
   because a brick fill on a darkened photograph is the one combination §1.1
   does not use. */
.wp-block-cover.is-dark .wp-block-button.is-style-outline > .wp-block-button__link:hover,
.wp-block-cover.is-dark .wp-block-button.is-style-outline > .wp-block-button__link:focus-visible,
.entry-content .wp-block-cover.is-dark .wp-block-button.is-style-outline > .wp-block-button__link:hover,
.entry-content .wp-block-cover.is-dark .wp-block-button.is-style-outline > .wp-block-button__link:focus-visible {
  background-color: var(--tcf-page);
  border-color: var(--tcf-page);
  color: var(--tcf-ink);
  -webkit-text-fill-color: var(--tcf-ink);
}

/* The primary (filled) button has the same failure mode as the outline one:
   Blocksy hovers the fill to the same slot it hovers the label to. */
.wp-block-button:not(.is-style-outline) > .wp-block-button__link:hover,
.wp-block-button:not(.is-style-outline) > .wp-block-button__link:focus-visible,
.entry-content .wp-block-button:not(.is-style-outline) > .wp-block-button__link:hover,
.entry-content .wp-block-button:not(.is-style-outline) > .wp-block-button__link:focus-visible {
  background-color: var(--tcf-accent-strong);
  color: var(--tcf-page);
  -webkit-text-fill-color: var(--tcf-page);
}
/* Except on a photograph, where the primary is paper-filled at rest (§1.1). */
.wp-block-cover.is-dark .wp-block-button:not(.is-style-outline) > .wp-block-button__link:hover,
.wp-block-cover.is-dark .wp-block-button:not(.is-style-outline) > .wp-block-button__link:focus-visible,
.entry-content .wp-block-cover.is-dark .wp-block-button:not(.is-style-outline) > .wp-block-button__link:hover,
.entry-content .wp-block-cover.is-dark .wp-block-button:not(.is-style-outline) > .wp-block-button__link:focus-visible {
  background-color: var(--tcf-surface);
  color: var(--tcf-ink);
  -webkit-text-fill-color: var(--tcf-ink);
}


/* ---------------------------------------------------------------------------
   MEASURES ARE PROPORTIONS, NOT PIXELS

   The canvas is a fixed 1280px mock, so every measure read off it is a pixel
   value sized for a column narrower than the one it lands in here. Copied
   literally they under-use the space and wrap the text a line early: the panel
   body copy was capped at 420px inside a 599px column, and the hero lede at
   651px inside 740px.

   Expressed as a share of the column, the canvas's proportion survives and the
   text uses the room it has. 420 of 559 is three quarters, which is what these
   keep.

   Eyebrows never take a measure at all - they are one short line by
   definition, and a cap on them does nothing but confuse the next reader of
   this file.
   --------------------------------------------------------------------------- */
/* Body copy keeps a measure at three quarters of the column, which is the
   canvas's proportion (420 of 559). Headings do not - they are pinned wider
   further down. */
.tcf-two-panels__panel p,
.tcf-closing__panel--invite > p {
  max-width: 75%;
}
.tcf-two-panels__panel .is-style-eyebrow,
.tcf-closing__panel .is-style-eyebrow,
.tcf-whats-on__eyebrow,
.entry-content > .is-style-eyebrow {
  max-width: none;
}

/* The lede is the one piece of the hero that keeps its own measure: it is read
   at a glance, and set to the full 740px column it runs longer than the eye
   wants to track under a 64px headline. The headline itself takes the column. */
.home .wp-block-cover .has-lede-font-size {
  max-width: var(--tcf-measure-lede);
}

/* The FAQ's left column is its own measure. */
.tcf-faq__intro > p { max-width: none; }


/* ---------------------------------------------------------------------------
   BELIEF BAND (§2a.4 and §2a.5), measured

   Pull quote 40/300 italic at 51.2 leading and -0.4px tracking; the paragraph
   beneath it 16.5/28 in muted; each distinctive a 19/600 title over a 15.5/25
   muted description. We had the quote at 400 upright, the paragraph at 17 in
   full-strength ink, and the titles and descriptions sharing one 17px style.
   --------------------------------------------------------------------------- */
.tcf-band-plain .is-style-pull,
.tcf-band-plain .is-style-pull p {
  font-family: var(--tcf-font-serif);
  font-size: 40px;
  font-weight: 300;
  font-style: italic;
  line-height: 1.28;
  letter-spacing: -0.01em;
  color: var(--tcf-ink);
}
/* Not the eyebrow. §1.2 makes eyebrows paragraphs on purpose - they carry no
   document structure - so a rule that styles "every paragraph in this column"
   catches them, and this one was rendering them at 16.5px with 0.2em of
   tracking against the 11.5px the scale specifies. */
.tcf-band-plain > .wp-block-columns > .wp-block-column > p:not(.is-style-eyebrow) {
  font-size: 1.03125rem;   /* 16.5px */
  line-height: 1.7;
  color: var(--tcf-muted);
}
.is-style-numbered-rule > li {
  font-size: 0.96875rem;   /* 15.5px */
  line-height: 1.6;
  color: var(--tcf-muted);
}
.is-style-numbered-rule > li > strong {
  display: block;
  font-size: 1.1875rem;    /* 19px */
  font-weight: 600;
  line-height: 1.3;
  color: var(--tcf-ink);
  margin-bottom: 4px;
}
/* The full stop after the title belonged to a single run of text; with the
   title on its own line it would sit alone at the start of the description. */
.is-style-numbered-rule > li > strong + br { display: none; }
.tcf-point__desc { display: block; }

/* ---------------------------------------------------------------------------
   HEADINGS FILL THEIR LINE

   `text-wrap: balance` evens the lines of a heading, which means deliberately
   leaving room at the end of the first one. On a page whose panels are already
   wider than the 1280px canvas they were drawn on, that reads as text wrapping
   early - because that is exactly what it is doing.

   Several earlier rules set it, on `.entry-title`, on the display and section
   heading styles, and on the teaching row and hero titles. Rather than unpick
   each one and have the next added rule reintroduce it, headings inside the
   homepage bands are pinned here.

   The one deliberate exception is the closing heading, which carries a glued
   "We will" so that its even split lands on the full stop. It is set after
   this block and keeps `balance`.
   --------------------------------------------------------------------------- */
.tcf-two-panels__panel h2,
.tcf-two-panels__panel h3,
.tcf-two-panels__panel h4,
.tcf-selector__heading,
.tcf-selector__panel h2,
.tcf-selector__panel h3,
.tcf-whats-on__heading,
.tcf-faq__intro > h2,
.tcf-band-plain h2,
.tcf-band-plain h3,
.is-style-band-alt > h2,
.home .wp-block-cover h1,
.entry-content > .is-style-band-alt > .is-style-section {
  text-wrap: wrap !important;
  text-wrap-style: auto !important;
  max-width: none !important;
}

/* The closing heading fills its line like every other heading on the page. It
   was briefly balanced, paired with a glued "We will" so the even split landed
   on the full stop - a neater break, but a visibly shorter first line, which is
   the thing this whole block exists to stop. */
.tcf-closing__panel h2 {
  text-wrap: wrap !important;
  text-wrap-style: auto !important;
  max-width: none !important;
}


/* The archive search field was falling through to the browser's own focus
   ring, which is black and not ours. §5.4 wants the brick ring everywhere it
   is legible, and this sits on paper. */
#tcf-teaching-q:focus-visible,
.tcf-teaching-search input[type="search"]:focus-visible {
  outline: 2px solid var(--tcf-accent);
  outline-offset: 2px;
  border-color: var(--tcf-accent);
}


/* ---------------------------------------------------------------------------
   ACCESSIBILITY CORRECTIONS (§5.4)
   --------------------------------------------------------------------------- */

/* A dark band has to state its own foreground. Without it the paragraph that
   wraps the calendar link inherited ink from the body rule and computed as ink
   on ink - the link inside it was legible, but the element carrying the text
   was not, which is the thing an audit measures and the thing that breaks the
   moment a second word is added beside the link. */
.tcf-whats-on {
  color: var(--tcf-on-ink-body);
}

/* The map iframe is a focus stop - it has to be, a keyboard user needs to
   reach the map controls - and it was taking no visible ring at all. */
/* An outline on a cross-origin iframe is drawn beneath the embedded document
   and is not reliably visible, so the indicator is a box-shadow, which paints
   over the frame's own edge. The container takes a ring too, for the case where
   focus lands on the frame rather than inside it - `.tcf-map:focus-within` is
   declared once, further down beside the map's own reserved space; the copy
   that used to sit here restated the same outline and offset. */
.tcf-map__frame:focus-visible,
.tcf-map__frame:focus {
  outline: 2px solid var(--tcf-accent);
  outline-color: var(--tcf-accent);
  outline-offset: 2px;
  box-shadow: 0 0 0 2px var(--tcf-page), 0 0 0 4px var(--tcf-accent);
}

/* Blocksy paints its own focus style over anything the plugin forms render, at
   a specificity our class selectors do not reach. Beating it needs `html` on
   the front and the id of the form, and even then the buttons carry Blocksy's
   3px ring, so those are stated outright.
   §5.4 is specific: 2px, brick, 2px offset. */
html #wpmem_login_form input:focus-visible,
html #wpmem_login_form select:focus-visible,
html #wpmem_register_form input:focus-visible,
html #wpmem_register_form select:focus-visible,
html form.form input:focus-visible,
html form.form select:focus-visible,
html input.username:focus-visible,
html input.password:focus-visible,
html input.textbox:focus-visible,
html input.buttons:focus-visible,
html #tcf-teaching-q:focus-visible,
html input[type="search"]:focus-visible,
html #wpmem_login_form input:focus,
html #wpmem_login_form select:focus,
html #wpmem_register_form input:focus,
html #wpmem_register_form select:focus,
html form.form input:focus,
html form.form select:focus,
html input.username:focus,
html input.password:focus,
html input.textbox:focus,
html input.buttons:focus,
html #tcf-teaching-q:focus,
html input[type="search"]:focus {
  outline: 2px solid var(--tcf-accent) !important;
  /* The longhand as well as the shorthand. Blocksy sets `outline-color` on
     focused form fields from --theme-form-field-border-focus-color, which is
     not defined here; the property then resolves to a transparent colour and
     the ring is drawn at the right width, in the right place, in nothing at
     all. Our shorthand was setting width and style and losing the colour to
     it. A ring you cannot see is the same as no ring. */
  outline-color: var(--tcf-accent) !important;
  outline-offset: 2px !important;
}

/* ---------------------------------------------------------------------------
   CLICK-TO-LOAD MAP (§3.10)

   The button stands in for the frame until somebody asks for it. It is drawn
   at the frame's size so nothing shifts when the map arrives, which is the
   whole point of reserving the space.
   --------------------------------------------------------------------------- */
.tcf-map__load {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  width: 100%;
  height: 200px;
  padding: var(--tcf-space-4);
  font-family: var(--tcf-font-ui);
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--tcf-ink);
  background-color: var(--tcf-surface);
  border: 1px dashed var(--tcf-rule);
  border-radius: var(--tcf-radius);
  cursor: pointer;
}
.tcf-map__load:hover {
  border-color: var(--tcf-accent);
  color: var(--tcf-accent);
}
.tcf-map__load:focus-visible {
  outline: 2px solid var(--tcf-accent);
  outline-color: var(--tcf-accent);
  outline-offset: 2px;
}
.tcf-map__load-note {
  font-size: 0.8125rem;
  font-weight: 400;
  color: var(--tcf-muted);
}
/* The glyph is drawn from type, like the other three the site permits (§1.9). */
.tcf-map__load-icon::before {
  content: "\25CE";
  font-size: 1.5rem;
  line-height: 1;
  color: var(--tcf-accent);
}


/* The two canvas colours now have names; the rules that were producing them by
   other means point at them. */
/* Plain nav labels only. The "Plan your visit" item is the primary button: it
   is brick-filled and its label is paper, and painting it in the nav colour put
   #3B3630 on #96412E, which is 1.9:1. The same exclusion is on the rule that
   sets the home-page nav colour, and it has to be on both. */
html body.home header#header [data-id="menu"] > .menu > .menu-item > .ct-menu-link:not([href*="/plan-your-visit/"]),
#header [data-id="menu"] > .menu > .menu-item > .ct-menu-link:not([href*="/plan-your-visit/"]) {
  color: var(--tcf-nav);
}
.home .wp-block-cover .has-lede-font-size {
  color: var(--tcf-on-photo);
}


/* The sign-in helper line is reader-facing body copy, so it takes the §1.2
   floor rather than the meta step. */
.tcf-mb-signin__reset { font-size: 15px; }

/* The block editor paints its buttons with pure white, which is not in the
   palette; paper is. Applied to the element the editor actually renders, since
   the theme's own button rules sit on the wrapper. */
.entry-content .wp-block-button__link,
.entry-content .wp-element-button,
.wp-block-button__link,
.wp-element-button {
  color: var(--tcf-page);
}
.wp-block-cover.is-dark .wp-block-button:not(.is-style-outline) > .wp-block-button__link,
.wp-block-button.is-style-outline > .wp-block-button__link {
  color: var(--tcf-ink);
}
.wp-block-cover.is-dark .wp-block-button.is-style-outline > .wp-block-button__link {
  color: var(--tcf-page);
}


/* The pull quote is a paragraph, and paragraphs keep `pretty` - it is what
   stops a one-word last line. The heading pin above was never meant to reach
   it; only the balance-versus-fill argument was, and that is about headings. */
.tcf-band-plain .is-style-pull,
.tcf-band-plain .is-style-pull p {
  text-wrap: pretty;
}


/* The map container is the focus surface. `tabindex` on the frame plus the ring
   on its parent means a keyboard user can see they have arrived, which an
   outline on a cross-origin iframe cannot promise. */
.tcf-map:focus-within {
  outline: 2px solid var(--tcf-accent);
  outline-color: var(--tcf-accent);
  outline-offset: 2px;
}


/* The map's reserved space, exactly the height the frame will be, so the block
   below it does not jump when the map arrives. Drawn as a quiet surface rather
   than left blank: on a slow connection an empty gap reads as a broken image. */
.tcf-map__reserve {
  height: 200px;
  border-radius: var(--tcf-radius);
  background-color: var(--tcf-surface);
}
/* These two restate the base value and exist so the phone override below has a
   hook. Contact is not in the list: its frame is 330px and its reserve is set
   beside its frame in interior-b.css, which is the file that owns that page. */
.tcf-closing__panel--map .tcf-map__reserve,
body.page-plan-your-visit .tcf-map__reserve { height: 200px; }

/* On a phone the OpenStreetMap attribution bar wraps to two lines and 40px.
   Measured inside the iframe at 375: 40px of a 200px frame, so a fifth of the
   map is a strip of 12px grey text. The bar cannot be styled - it is
   cross-origin content in OSM's own embed, and the "(c) OpenStreetMap
   contributors" line is an ODbL requirement that must not be removed anyway -
   so the only lever is the frame. 240px takes it from 20% to 16.7% and keeps
   the pin clear of the bar.

   The reserve moves with the frame in the same rule. Split them and this
   reintroduces exactly the layout shift the Contact fix removes. */
@media (max-width: 767px) {
  .tcf-closing__panel--map .tcf-map__frame,
  .tcf-closing__panel--map .tcf-map__reserve,
  body.page-plan-your-visit .tcf-map__reserve { height: 240px; }
}


/* ---------------------------------------------------------------------------
   THE EDITOR'S FONT-SIZE PRESETS

   `add_theme_support( 'editor-font-sizes' )` registers the sizes for the
   editor's UI. It does not reliably emit the `--wp--preset--font-size--*`
   custom properties or the `.has-*-font-size` rules on the front of a classic
   theme, and here it emitted neither: --wp--preset--font-size--lede computed
   empty, so anything set to Lede in the editor fell back to whatever it
   inherited. The homepage hero looked right only because a component rule was
   setting it directly.

   Declared from the same numbers as functions.php. If a size changes, it
   changes in both places, which is why each one carries its slug.
   --------------------------------------------------------------------------- */
:root {
  --wp--preset--font-size--small: 16px;
  --wp--preset--font-size--normal: 17px;
  --wp--preset--font-size--lede: 19px;
  --wp--preset--font-size--large: 30px;
  --wp--preset--font-size--xlarge: 40px;
  --wp--preset--font-size--page-title: 52px;
  --wp--preset--font-size--display: 64px;
}
.has-small-font-size      { font-size: var(--wp--preset--font-size--small); }
.has-normal-font-size     { font-size: var(--wp--preset--font-size--normal); }
.has-lede-font-size       { font-size: var(--wp--preset--font-size--lede); }
.has-large-font-size      { font-size: var(--wp--preset--font-size--large); }
.has-xlarge-font-size     { font-size: var(--wp--preset--font-size--xlarge); }
.has-page-title-font-size { font-size: var(--wp--preset--font-size--page-title); }
.has-display-font-size    { font-size: var(--wp--preset--font-size--display); }

/* ---------------------------------------------------------------------------
   NO-JS NAVIGATION (§6.6)

   Only ever rendered inside <noscript>, so this styles a thing most visitors
   never see. It still has to look like the site: someone reading with scripts
   off is usually doing so deliberately, and a raw list of blue links tells them
   the site does not care.

   Hidden above the mobile breakpoint, where the full navigation is in the
   header already and this would be a duplicate.
   --------------------------------------------------------------------------- */
.tcf-nojs-nav {
  background-color: var(--tcf-surface);
  border-bottom: 1px solid var(--tcf-rule);
  padding: var(--tcf-space-4) var(--tcf-gutter);
}
.tcf-nojs-nav__list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 1.25rem;
  max-width: var(--tcf-content-max);
  margin-inline: auto;
  padding: 0;
  list-style: none;
}
.tcf-nojs-nav__list .sub-menu {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 1rem;
  width: 100%;
  margin: 0.2rem 0 0;
  padding: 0 0 0 1rem;
  list-style: none;
}
.tcf-nojs-nav a {
  display: inline-block;
  /* 24px minimum plus its own spacing, per the tap-target ruling. */
  min-height: 24px;
  padding: 0.35em 0;
  font-family: var(--tcf-font-ui);
  font-size: 15px;
  font-weight: 500;
  color: var(--tcf-nav);
  text-decoration: none;
}
.tcf-nojs-nav a:hover { color: var(--tcf-accent); text-decoration: underline; }

@media (min-width: 1000px) {
  .tcf-nojs-nav { display: none; }
}

/* ---------------------------------------------------------------------------
   SINGLE TEACHING (§2d), measured against the canvas

   Every value below was read off section 2d with getComputedStyle and compared
   against the same property on the live page. Nine differed. The title, the
   three eyebrows and the date lines already matched and are not repeated here.
   --------------------------------------------------------------------------- */

/* The back link and Download sit a step below body copy on the canvas. */
.tcf-teaching-hero__back a,
.tcf-teaching-hero .tcf-player__actions a,
.tcf-player__actions a { font-size: 14.5px; }

/* The hero eyebrow reads heavier on ink than the same label does on paper, and
   the canvas answered that by dropping it half a pixel to 11px. Half a pixel is
   below the threshold at which anyone can see it, and it left a bare `11px` six
   lines under a --tcf-text-eyebrow token, which is a trap for the next person.
   The optical weight of a label on a dark ground lives in its TRACKING, not in
   its size, so it goes there: 11.5px at 0.22em reads a hair lighter than 11.5px
   at 0.2em on paper, and the size is a token again.
   DS_TEACHING_SINGLE.md §4.3. */
.tcf-teaching-hero__eyebrow { letter-spacing: 0.22em; }

/* The metadata line under the title was a full point and a half small, which
   made it read as a caption rather than as the answer to "who preached this". */
.tcf-teaching-hero__meta { font-size: 16.5px; }

/* "More in {book}". The canvas sets the titles at a flat 19px rather than the
   fluid card-title step, and the dates a shade lighter than muted. */
.tcf-more-in__list a { font-size: 19px; }
/* The canvas sets these dates in #8A8175, which is 3.62:1 at 14px and fails
   §5.1's 4.5:1. `muted` is 5.64:1 and reads a shade darker than drawn. The same
   ruling as the definition-list labels on Contact and the map-panel eyebrow:
   where the drawing and the contrast floor disagree, the floor wins. */
.tcf-more-in__when   { font-size: 14px; color: var(--tcf-muted); }

/* The passage and the summary. Neither is on any of the 892 imported teachings
   yet - the fields arrived with the upload form - so these are the styles the
   first teaching to carry them will land in, taken from the canvas rather than
   guessed at later. */
.tcf-teaching__quote,
.tcf-teaching__quote p {
  font-family: var(--tcf-font-serif);
  /* 26px sat between --tcf-text-stat (27 at desktop) and --tcf-text-card. A pull
     quote is a display value rather than a heading rank, which is what `stat` is
     for, and taking the token makes it fluid - 23px at 390, where it was fixed
     at 26 at every width. */
  font-size: var(--tcf-text-stat);
  font-weight: 300;
  line-height: 1.5;
  color: var(--tcf-ink);
}
/* The one paragraph a visitor came to read was the only body text on the site
   that was not --tcf-ink. --tcf-nav is the navigation label colour, lifted off
   ink on purpose so the wordmark stays the darkest thing in the header; using it
   here gave the site two body-text colours, which nothing in the design system
   permits - --tcf-body was retired as a decision and kept only as a name to stop
   exactly this. And 17.5/1.83 is not a step: --tcf-text-body is 17 and
   --tcf-leading-body is 1.75, and there is no argument for a summary being half
   a pixel larger and 0.08 looser than every other paragraph on the site.
   DS_TEACHING_SINGLE.md §7.2. */
.tcf-teaching__summary .tcf-prose,
.tcf-teaching__summary .tcf-prose p {
  font-size: var(--tcf-text-body);
  line-height: var(--tcf-leading-body);
  color: var(--tcf-ink);
}

/* The audio player's controls live in the browser's shadow DOM, so focus moves
   inside the element and an outline on the <audio> itself is unreliable - the
   same shape of problem as the map iframe. The ring goes on the bar around it,
   which is what a keyboard user actually sees.
   `:not(.tcf-player--js)` because this is a workaround for the browser's bar and
   nothing else. Once the script has replaced it, the transport and the timeline
   are our own elements with their own rings, and a ring around the whole panel
   as well would put two boxes round one focused control. */
.tcf-player:not(.tcf-player--js):focus-within {
  outline: 2px solid var(--tcf-accent);
  outline-color: var(--tcf-accent);
  outline-offset: 2px;
}
.tcf-teaching-hero .tcf-player:not(.tcf-player--js):focus-within {
  outline-color: var(--tcf-on-ink-accent);
}
.tcf-player__audio:focus-visible,
.tcf-player__audio:focus {
  outline: 2px solid var(--tcf-accent);
  outline-color: var(--tcf-accent);
  outline-offset: 2px;
}
.tcf-teaching-hero .tcf-player__audio:focus-visible,
.tcf-teaching-hero .tcf-player__audio:focus {
  outline-color: var(--tcf-on-ink-accent);
}


/* ---------------------------------------------------------------------------
   TRACKING FOLLOWS RENDERED SIZE (§1.2), INCLUDING THE ZERO

   "Letter-spacing -0.02em at 40px and above, -0.01em from 24-39px, 0 below."

   The rule was implemented for the first two bands and not the third, so
   anything in Newsreader under 24px was being tightened when it should have
   been left alone: the wordmark at 23px on every page, the two-panel headings,
   and the teaching title on the archive rows.

   The second design package agrees - it draws all of these at 0 - which is
   what settled it, because the first package drew the wordmark at -0.23px and
   that is where ours came from.

   Stated by component rather than with a :has() size query, because the size
   these render at is known and a query on rendered size is not something CSS
   can express.
   --------------------------------------------------------------------------- */
html .site-title a,                    /* wordmark, 23px */
.tcf-two-panels__panel h3,             /* panel headings, 34px -> see below */
.tcf-teaching-row__title,
.tcf-more-in__list a,                  /* 19px */
.tcf-closing__venue,                   /* 26px, over the line - kept for clarity */
.tcf-selector__heading {
  letter-spacing: 0;
}

/* Except the three that really are 24px and over, which take the middle band. */
.tcf-closing__venue,
.tcf-two-panels__panel h3,
.tcf-selector__heading {
  letter-spacing: -0.01em;
}


/* ---------------------------------------------------------------------------
   RECONCILED AGAINST §1.2 AND THE SECOND PACKAGE

   Where the two design packages disagree with each other, §1.2's stated scale
   is the tiebreaker: it is the only one of the three that gives numbers as a
   rule rather than as a rendering.
   --------------------------------------------------------------------------- */

/* An eyebrow is 11.5/0.2em wherever it lands. Stated once, last, so no
   component rule can quietly grow one again. */
.is-style-eyebrow,
.tcf-visit__panel p.is-style-eyebrow,
.tcf-closing__panel p.is-style-eyebrow {
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.2em;
  line-height: 1;
  text-transform: uppercase;
}

/* §1.6: footer column headings are 15px. Ours were 19, which made them compete
   with the church name above them.

   `.tcf-footer .tcf-footer__heading`, not the class alone: an earlier
   `.tcf-footer h2, .tcf-footer h3` scores (0,1,1) and beats a single class
   however far down the file it sits. */
.tcf-footer .tcf-footer__heading {
  font-size: 15px;
  line-height: 1.85;
}

/* The closing heading is 42/300 in both packages; ours had drifted to the
   section style's 40/400. */
.tcf-closing__panel h2 {
  font-size: 42px;
  font-weight: 300;
  line-height: 1.18;
  letter-spacing: -0.015em;
}

/* `.is-style-section` WAS PINNED HERE AND IS NOT ANY MORE. Changed 2026-08-10.

   This rule used to name `.is-style-section` too, justified as "§1.2 gives
   `section` as 36-40 and both packages draw 36". Being declared twice at equal
   specificity, the flat 36px beat `var(--tcf-text-2xl)` up at line 1971, so the
   documented fluid 28->40 section step NEVER RENDERED ANYWHERE ON THE SITE.

   Dropped on two grounds. The machine-readable handoff, `docs/handoff/theme.json`,
   gives `section` as {min: 28px, max: 40px}, and DESIGN_SYSTEM.md names that file
   as the source of the fluid pairs - so the pin was reading the prose over the
   data it is derived from. And it was measurably wrong on a phone: at 320 logged
   in, the page `h1` computed to 34px and every `h2` to 36px, so section headings
   rendered LARGER THAN THE PAGE TITLE, the exact inversion §1.2 exists to stop.

   The two drawn components keep their pins, because their drawings do want a
   fixed number.

   THIS CHANGE IS COUPLED - do not apply it alone. Restoring the fluid step takes
   both split headings on the member hub to 40px, and "The most recent teaching"
   then needs 417px, so `css/member-hub.css` §2's floor goes 25rem -> 27.5rem and
   §6's collapse 1119 -> 1279. Without those the hub's aside heading wraps to two
   lines between 1120 and 1290 and the two columns offset by ~46px. */
.tcf-faq__intro > h2,
.tcf-visit__runs h2 {
  font-size: 36px;
}

/* Panel headings sit between §1.2's `card-title` (26-30) and `section` (36-40)
   bands, in neither, so the drawing decides - and the drawing gives the two
   panel components different sizes: the homepage pair is 34, the Home Groups
   panel 32. They are different components and keep their own numbers.
   §1.2 puts headings at this size in Newsreader 400. */
.tcf-two-panels__panel h3 { font-size: 34px; font-weight: 400; }
.tcf-lt-panel h3          { font-size: 32px; font-weight: 400; }
.tcf-selector__heading    { font-weight: 400; }

/* §1.2's `ui` step is 15px at 500-600. The buttons were at the light end of
   the weight range; both packages draw the heavy end. */
.wp-block-button__link,
.wp-element-button {
  font-weight: 600;
}

/* The venue line on Plan Your Visit is the same component as the one in the
   closing block and takes the same 26px, not the body step. */
.tcf-visit__venue {
  font-family: var(--tcf-font-serif);
  font-size: 26px;
  font-weight: 400;
  line-height: 1.35;
  color: var(--tcf-ink);
}


/* Teaching archive (§2c), measured. */
.tcf-teaching-row__title            { font-size: 26px; }
.tcf-filter__option, .tcf-chip    { font-weight: 500; }
.tcf-podcast-band h2,
.tcf-podcast__heading             { font-size: 34px; font-weight: 300; }
.tcf-teaching-archive .wp-block-button__link { font-size: 15px; }

/* What We Believe: the cross-reference line is the `ui` step, not body. */
.tcf-believe__aside > p,
.tcf-believe__seealso,
.tcf-believe__seealso a           { font-size: 15px; line-height: 1.7; }

/* Photo-slot captions are 14px in both packages. */
.tcf-photo-slot__caption,
.tcf-lt-card figcaption,
.wp-element-caption               { font-size: 14px; line-height: 1.5; }
