/*
 * Sanctuary brand layer.
 *
 * Kadence carries the palette, type scale and spacing — configured in its own
 * settings and exported to config/kadence-theme-mods.json. This file holds ONLY
 * what Kadence cannot express: the letterspaced-caps treatment from the flyer,
 * the stained-glass rule, and a few accessibility guarantees.
 *
 * Colours reference --global-paletteN, which is what Kadence emits. Do NOT
 * reintroduce --wp--preset--color--<brand-slug>: those came from a child
 * theme.json that was removed because it stripped the colour off every Kadence
 * library pattern. See docs/SOP-kadence-theme-json.md.
 *
 * Palette sampled from Sanctuary_Logo_2025.png and Sanctuary-Flyer-5x7-1.jpg.
 * Every foreground/background pair used here passes WCAG AA for body text.
 */

:root {
	/* The five supporting hexes are defined ONCE, in
	   inc/supporting-colours.php, which appends them to the editor palette so
	   authors can pick them. WordPress emits them as presets; we consume those
	   rather than restating the values here. Two copies of a hex is one too many.

	   These --global-palette-* names are LOAD-BEARING, not a naming preference.
	   Kadence Blocks resolves a colour attribute by prefix: a value starting
	   `palette` becomes var(--global-<value>, #3182CE). So a block set to
	   `palette-butter` looks for exactly this variable, and if it is missing it
	   renders Kadence's stock BLUE rather than failing visibly.

	   That is why this block must stay in a stylesheet loaded in every context
	   these colours can render — front end AND the block editor. functions.php
	   registers it with add_editor_style() for precisely this reason. */
	--global-palette-butter: var(--wp--preset--color--palette-butter);
	--global-palette-sky: var(--wp--preset--color--palette-sky);
	--global-palette-mist: var(--wp--preset--color--palette-mist);
	--global-palette-greige: var(--wp--preset--color--palette-greige);
	--global-palette-sage: var(--wp--preset--color--palette-sage);

	/* Short aliases for the rules further down this file. */
	--sanctuary-butter: var(--global-palette-butter);
	--sanctuary-sky: var(--global-palette-sky);
	--sanctuary-mist: var(--global-palette-mist);
	--sanctuary-greige: var(--global-palette-greige);
	--sanctuary-sage: var(--global-palette-sage);

	/* The measure, as a length rather than as `ch`.
	   `p { max-width: 68ch }` further down is the canonical rule and resolves to
	   588px at the 18px body size — measured on the rendered page, not derived.
	   Headings need the SAME width to line up with it, and 68ch on a 40px
	   heading is 1300px, so a heading capped in `ch` would not align with the
	   paragraph under it. Hence a fixed rem value: 36.75rem = 588px. */
	--sanctuary-measure: 36.75rem;

	--sanctuary-rule: linear-gradient(
		90deg,
		var(--sanctuary-sky) 0%,
		var(--sanctuary-mist) 22%,
		var(--sanctuary-butter) 55%,
		var(--sanctuary-greige) 80%,
		var(--sanctuary-sage) 100%
	);
}

/* ---------------------------------------------------------------------------
   Eyebrow / tagline: letterspaced caps, as on the flyer under the wordmark.
   Apply by adding the class in the block editor's Advanced panel.
   --------------------------------------------------------------------------- */
.is-style-eyebrow,
.sanctuary-eyebrow {
	font-family: var(--global-body-font-family);
	font-size: var(--wp--preset--font-size--small);
	/* 600, not 500: Kadence only downloads the weights its font settings ask
	   for, and 500 is not among them — the browser was synthesising it. Any
	   weight used here must exist in wp-content/fonts/, or it is a fake. */
	font-weight: 600;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var(--global-palette6);
	margin-bottom: 0.35em;
}

/* On plum backgrounds the soft ink disappears — lift it.
   #colophon is in this list because the footer is a plum GROUND set in Kadence's
   own settings, so it never carries a has-theme-palette-N class. Measured: soft
   ink on plum is 1.42:1; peach is 8.10:1.

   **This rule was written correctly and matched nothing on a row layout.**
   Kadence emits TWO spellings of that class and the difference is one hyphen:
   blocks get `has-theme-palette-1-background-color`, row layouts get
   `has-theme-palette1-background-color`. Every plum band on this site is a row
   layout, so the eyebrow inside one kept the soft ink — measured 2026-09-02 on
   /programs/sanctuary-dnd/ at **1.79:1** against the 4.5 it needs.

   `.sanctuary-band-plum` is listed too, which is how `.sanctuary-meta` below has
   always handled the same ground. That is the belt: it is the site's own class,
   applied deliberately, and does not depend on guessing Kadence's spelling. The
   palette classes are the braces, for a band that gets the colour without the
   utility class. */
.has-theme-palette-1-background-color .is-style-eyebrow,
.has-theme-palette-1-background-color .sanctuary-eyebrow,
.has-theme-palette1-background-color .is-style-eyebrow,
.has-theme-palette1-background-color .sanctuary-eyebrow,
.has-theme-palette-2-background-color .is-style-eyebrow,
.has-theme-palette2-background-color .is-style-eyebrow,
.has-theme-palette2-background-color .sanctuary-eyebrow,
.sanctuary-band-plum .is-style-eyebrow,
.sanctuary-band-plum .sanctuary-eyebrow,
#colophon .is-style-eyebrow,
#colophon .sanctuary-eyebrow {
	color: var(--global-palette7);
}

/* ---------------------------------------------------------------------------
   Stained-glass rule — a thin echo of the logo window. Use between sections
   instead of a plain separator.
   --------------------------------------------------------------------------- */
.wp-block-separator.is-style-sanctuary-glass {
	border: 0;
	height: 3px;
	background: var(--sanctuary-rule);
	opacity: 1;
	max-width: 9rem;
	/* Start-aligned, not centred. `margin-inline:auto` put the rule in the middle
	   of a full-width column while the heading above it sat left — it read as a
	   stray mark rather than as a rule belonging to that heading. Centre it only
	   where the content around it is centred. */
	margin-inline: 0;
}

.has-text-align-center > .wp-block-separator.is-style-sanctuary-glass,
.wp-block-separator.is-style-sanctuary-glass.aligncenter {
	margin-inline: auto;
}

/* ---------------------------------------------------------------------------
   Section bands. The flyer alternates cream / peach / plum full-width bands;
   these give the same rhythm to full-width group blocks.
   --------------------------------------------------------------------------- */
.sanctuary-band-plum {
	background-color: var(--global-palette1);
	color: var(--global-palette8);
}

.sanctuary-band-plum :is(h1, h2, h3, h4, h5, h6) {
	color: var(--global-palette8);
}

/* A plum PANEL — the column form, not the band form — stretches to its
   neighbour's height because that is what makes it read as a panel rather than
   a tinted paragraph. Its content does not stretch with it: measured on the
   split band once the lighter half gained a photograph, the panel stood 633px
   tall around 337px of text, leaving ~296px of empty plum beneath.

   Centre the content in the panel. Scoped to the column so it cannot reach the
   plum band, which carries the same class on its row and is aligned by Kadence. */
.wp-block-kadence-column.sanctuary-band-plum {
	display: flex;
	flex-direction: column;
	justify-content: center;
}

.sanctuary-band-plum a:not(.wp-element-button) {
	color: var(--sanctuary-butter);
	text-decoration-thickness: 1px;
	text-underline-offset: 0.18em;
}

/* Buttons need to invert inside a plum band or they vanish into it. */
.sanctuary-band-plum .wp-element-button,
.sanctuary-band-plum .wp-block-button__link {
	background-color: var(--sanctuary-butter);
	color: var(--global-palette2);
}

.sanctuary-band-plum .wp-element-button:hover,
.sanctuary-band-plum .wp-block-button__link:hover {
	background-color: var(--global-palette8);
	color: var(--global-palette2);
}

/* ---------------------------------------------------------------------------
   Body copy comfort. EB Garamond runs small and light, so it needs a little
   more size and leading than a sans would at the same nominal scale.
   --------------------------------------------------------------------------- */
body {
	-webkit-font-smoothing: antialiased;
	text-rendering: optimizeLegibility;
}

p {
	max-width: 68ch; /* keeps long-form readable even in wide containers */
}

/* Lists take the same measure as the paragraphs they sit between. Without this
   they run the full content column while the prose around them stops at 68ch,
   so a long list item overshoots the text above it and the block reads as
   belonging to a different column.

   68ch, matching `p` above — NOT the fixed --sanctuary-measure. I swapped this
   to the fixed value once, on the strength of the lists measuring 718px against
   a paragraph measure of 588 that I remembered from the Programs page. Both
   numbers were right and the comparison was not: body type is 18px there and
   22px here, so 68ch is 588 on one page and 718 on the other. The lists had
   been matching their paragraphs exactly, and the fixed value is what broke
   them apart.

   `ch` tracks the type size; a rem constant cannot. The offset band uses the
   constant because it caps HEADINGS, where 68ch of a 40px face is far too
   wide — a different problem with a different answer. */
.entry-content ul.wp-block-list,
.entry-content ol.wp-block-list {
	max-width: 68ch;
}

/* Short enumerations — single words, many of them — in columns rather than one
   thin stack. The community covenant's fifteen protected characteristics ran as
   fifteen lines of two-thirds whitespace, which is hard to scan and buries the
   length of the list rather than showing it.

   Opt-in by class: this is wrong for any list whose items are sentences, and
   CSS cannot tell the difference. */
.sanctuary-list-columns {
	columns: 2;
	column-gap: 2.5rem;
}

.sanctuary-list-columns li {
	break-inside: avoid;
}

@media (max-width: 600px) {
	.sanctuary-list-columns {
		columns: 1;
	}
}

.entry-content p + p {
	margin-top: 1.15em;
}

/* Display serifs at large sizes want tighter tracking than at small sizes. */
h1,
.wp-block-post-title {
	letter-spacing: -0.015em;
}

/* ---------------------------------------------------------------------------
   Accessibility baselines. Kept in code deliberately: these are guarantees we
   want regardless of what the theme settings happen to be.
   --------------------------------------------------------------------------- */

/* Kadence's default focus ring is faint against cream. */
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
	outline: 3px solid var(--global-palette1);
	outline-offset: 2px;
}

/* Form controls get the ring again, and this one has to shout.

   Found 2026-09-02 by tabbing through the site with a keyboard. EVERY text
   input and textarea — the Contact Us form and the event register form alike —
   took keyboard focus with NO visible ring at all. `:focus-visible` matched, so
   the browser agreed it was keyboard focus; the outline was simply absent, and
   the only cue was the caret and a 1px border shifting from #cbd5e0 to #6a6675.

   The rule directly above was written to prevent exactly this and does nothing.
   `:where()` contributes ZERO specificity — that is its purpose — so anything
   at all outranks it. Links and buttons look fine only because Kadence supplies
   its own ring for those; nothing supplies one for a text input.

   **Why !important, which is otherwise not how this file works.** The override
   was measured, not assumed. Probes at (0,1,1), (0,1,2) and (0,1,3) all failed
   to restore the outline; only `!important` did. The computed baseline is
   `outline-width: 0px`, the signature of an `outline: 0` reset rather than a
   browser default. I could not find the rule responsible: it is not in the
   child theme, not in the served inline CSS, and the `!important` outline resets
   that do exist in Kadence and FluentCRM are all in admin, editor, WooCommerce
   or tabs stylesheets that this page never loads. Rather than assert a cause I
   have not proven, this states what was verified and takes the weight needed.

   `button` is included, and that was a correction. The first version of this
   rule left buttons out on the assumption their rings already worked — the
   Register button on an event page does show a white 3px ring. Tabbing through
   My Registrations disproved it: the Cancel buttons take focus with an outline
   of **zero width**, which is not a ring at all, and it is the control that
   gives up a member's place.

   Links are still left alone, and that distinction is real rather than
   squeamish. Footer links sit on the purple ground and Kadence rings them in
   cream; a brand-purple ring there would be purple on purple. Buttons are safe
   because `outline-offset: 2px` puts the ring on the page background rather
   than on the button, and every button reachable at desktop width sits on
   cream.

   NOT verified: a button on a dark ground — the mobile menu toggle is the one
   that matters. The browser here would not narrow its viewport below about
   2300px however it was resized, so 390px could not be reached. Whoever gets a
   working mobile viewport should check that toggle before assuming this is
   finished.

   Verified by keyboard and by eye on both forms after the change, not by
   reading the file back. */
input:not([type="hidden"]):focus-visible,
select:focus-visible,
textarea:focus-visible,
button:focus-visible {
	outline: 3px solid var(--global-palette1) !important;
	outline-offset: 2px !important;
}

/* The site logo's focus ring was purple on the purple header.

   Measured 2026-09-02, by keyboard: `.brand` took focus with a painted 3px ring
   in `rgb(92, 39, 95)` against the header's `rgb(105, 38, 109)` — **contrast
   1.10**, where SC 1.4.11 wants 3.0. A keyboard user tabbing into the site
   lands on the logo first and sees nothing happen.

   Pre-existing, and nothing to do with the form-control rule above: that one
   does not target links, and its purple is `#69266d`, not this colour.

   `.brand` only. The header's nav links beside it already ring cream at 8.76
   and the footer links likewise, so a blanket link rule would be a change in
   search of a problem — and would risk the very purple-on-purple this fixes.

   palette8 is the page cream, which is what Kadence already uses for the nav
   links on this ground. Measured after the change, not assumed. */
.brand:focus-visible,
.site-branding a:focus-visible {
	outline-color: var(--global-palette8) !important;
}

/* The footer's first column sat 14px lower than the other three.

   Kadence gives every footer HTML item `margin: 1em 0`, and the footer body
   type is 14px, so that first `em` is exactly the 14px gap. Its three
   neighbours are widgets — `section.widget`, no such margin — so the land
   acknowledgment's heading started at 959 while EXPLORE, GET INVOLVED and ABOUT
   started at 945. Measured, not guessed: all four columns' inner wrappers begin
   at the same y, so the offset is entirely this margin.

   The bottom margin is left alone; only the top one breaks the alignment.

   Kadence exposes no control for this, which is what makes it a CSS fix under
   SOP-theme-vs-code rather than a customizer setting. */
#colophon .footer-html {
	margin-top: 0;
}

/* Touch targets: 44px minimum, measured not assumed.

   The mobile menu toggle measured 42x25 with Kadence's padding set to 11px on
   every side — because the padding wraps a hamburger icon only about 3px tall,
   so vertical padding alone cannot reach 44 without distorting the header. A
   min-height with the existing flex centring does it without moving anything
   else.

   DESIGN.md: "Do keep touch targets at 44px or larger", and mobile is the front
   door here because the printed flyer carries a QR code. */
.mobile-toggle-open-container .menu-toggle-open,
.menu-toggle-open,
.drawer-toggle {
	min-width: 44px;
	min-height: 44px;
}

/* Content buttons were never covered by the rule above, which only ever named
   the menu toggles. Measured at 390px on /programs/: both buttons on the page
   rendered 43px tall — one pixel under, from 7.2px of vertical padding on an
   18px line. Not a rounding artefact of one button; it is every button on the
   site, because the padding comes from Kadence's own button settings.

   inline-flex rather than more padding: padding would also widen the button and
   change its proportions, and the height needs to come from the target size
   rather than from the text. */
.wp-block-button__link,
.wp-block-button .wp-element-button {
	min-height: 44px;
	display: inline-flex;
	align-items: center;
	justify-content: center;
}

/* The Give button inside the mobile drawer measured 60x35. `mobile_button_padding`
   looks like the setting for this and is NOT: the customizer registers it, and
   the styles component never reads it — the key appears nowhere in the CSS
   generator, so anything set there is silently discarded. Padding here instead. */
.mobile-header-button-wrap .mobile-header-button {
	padding: 0.85rem 1.4rem;
}

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

/* ---------------------------------------------------------------------------
   Primary nav: uppercase.

   Everything else about the nav — face, size, weight, tracking — is set in
   Kadence's own primary_navigation_typography setting, which is where it
   belongs. `textTransform` is the exception: the setting accepts the value and
   Kadence never emits it. `textTransform` appears zero times in the theme's
   entire styles component, so it is silently discarded.

   Caps matter here because the nav sits at 15px on a plum ground and the
   lowercase of a fine-stroked serif disappears at that size. This is why the
   nav is the system sans rather than the brand serif: it is interface
   furniture, not display type.
   --------------------------------------------------------------------------- */
.main-navigation .primary-menu-container > ul li.menu-item > a,
.secondary-navigation .secondary-menu-container > ul li.menu-item > a,
.mobile-navigation ul li {
	text-transform: uppercase;
}

/* ---------------------------------------------------------------------------
   Hairline list — what to reach for instead of cards.

   DESIGN.md forbids cards and forbids three identical ones. Several sibling
   items still need equal billing, and this is the answer: a hairline above each
   entry, no boxes, no shadows. It scales to twenty entries without becoming a
   tile grid, which a card row cannot.

   Used by the sanctuary/band-hairline-list pattern.
   --------------------------------------------------------------------------- */
/* Descendant, not direct child. WordPress wraps a group's children in
   .wp-block-group__inner-container, so `>` matched nothing and the hairlines
   silently never drew. */
.sanctuary-hairline-list :is(h2, h3, h4) {
	border-top: 1px solid color-mix(in srgb, var(--global-palette3) 22%, transparent);
	padding-top: 1.1rem;
	margin-top: 1.6rem;
}

.sanctuary-hairline-list :is(h2, h3, h4) + p {
	margin-top: 0.3rem;
	color: var(--global-palette5);
}

/* Deliberately NOT a grid.

   A two-column grid was tried and broke the pairing: h3 and its paragraph are
   siblings, not a wrapped unit, so the grid placed them in separate cells and
   the hairlines stopped reading as row separators. A stacked list is what this
   is — the point was never to save vertical space, it was to give sibling items
   equal billing without boxes. */
.sanctuary-hairline-list :is(h2, h3, h4):first-of-type {
	border-top: 0;
	padding-top: 0;
	margin-top: 0;
}

/* Band media: fill the column without distorting, and keep the 2px radius.
   A photograph in a band is aligned to the column, never overlapping the band
   boundary — DESIGN.md permits a single-edge bleed at this variance and nothing
   more acrobatic. */
.sanctuary-band-media {
	margin: 0;
}

.sanctuary-band-media img {
	display: block;
	width: 100%;
	height: 100%;
	min-height: 18rem;
	object-fit: cover;
	border-radius: 2px;
}

/* The other treatment: an image sitting UNDER copy inside a column rather than
   being the column. It keeps its aspect ratio and never crops.

   The rule above cannot do this job. Its 18rem min-height plus object-fit:cover
   is what makes a photograph fill a band column, and applied to a 207px-wide
   column at 390px it turned a 4:3 image portrait and cropped a letter off each
   end of every line. Correct for one case, wrong for the other. */
.sanctuary-band-figure {
	margin: 1.75rem 0 0;
}

.sanctuary-band-figure img {
	display: block;
	width: 100%;
	height: auto;
	border-radius: 2px;
}

/* ---------------------------------------------------------------------------
   HOME MASTHEAD.

   Home only: a slim plum eyebrow carrying the nav, over the full lockup at hero
   size on cream, with the stained-glass roundel breaking UP through the
   plum/cream boundary. Every other page keeps the compact plum header.

   Kadence free has no per-page header — that is Kadence Elements, which is Pro.
   So there is ONE header with two navigation elements, and this switches which
   parts show by body class. Secondary nav lives in the top row, primary in the
   main row; each page hides the one it does not use. Both are in the markup
   everywhere, and display:none does take the hidden one out of the
   accessibility tree, but it is still markup. Worth knowing rather than
   discovering later.

   Selectors are the rendered ones, read off the page rather than guessed:
   .site-top-header-wrap and .site-main-header-wrap are what Kadence emits, from
   `site-<row>-header-wrap` in template-parts/header/header-row.php.

   EVERYTHING IS SCOPED TO #main-header. Kadence renders TWO headers into every
   page — #main-header and #mobile-header — and shows one per breakpoint. They
   use the SAME row class names, so an unscoped `.site-main-header-wrap` rule
   hits both. Measured at 390px before the scoping went in: the mobile logo took
   the hero sizing, fell back to its intrinsic 2091px, and blew the mobile
   header out to 624px tall with the drawer toggle pushed off it.

   The scoping is also why there is no mobile media query here. #main-header is
   display:none below Kadence's switch width, so none of this can reach a phone.
   --------------------------------------------------------------------------- */

/* The eyebrow is built globally so it can be styled in the customizer, and
   hidden everywhere it is not wanted. */
body:not(.home) #main-header .site-top-header-wrap {
	display: none;
}

/* THE NAV MUST OUTRANK THE LOGO, or the menu does not work.

   The lockup is lifted into the eyebrow by a negative margin, and `position:
   relative` on .site-branding puts it in the positioned paint layer — above the
   nav, which is not positioned. The artwork is transparent up there so it looks
   fine, but an <img> takes pointer events across its whole rectangle, and this
   one spans the full content width. Measured before: all six top-level items
   returned IMG.custom-logo from elementFromPoint. Every link dead, and nothing
   about the render said so.

   RAISE THE NAV, NOT THE ROW. The first attempt lifted .site-top-header-wrap,
   on the strength of having measured that element's own background as
   transparent and concluding the plum came from an ancestor. It does not: it
   comes from .site-header-row-container-inner, a CHILD of the row. Lifting the
   row took that plum panel up with it and sliced the top off the roundel — the
   clip is flat and obvious once looked at, and no measurement of the logo's box
   showed it, because nothing was clipping the box.

   .secondary-navigation carries no background of its own, so raising it lifts
   the links and nothing else. Both constraints have to hold at once: six of six
   reachable AND the roundel uncut. */
body.home #main-header .site-top-header-wrap .secondary-navigation {
	position: relative;
	z-index: 3;
}

/* ...and on home the main row gives up its nav and button to the eyebrow, so
   the row holds nothing but the logo. */
body.home #main-header .site-main-header-wrap .main-navigation,
body.home #main-header .site-main-header-wrap .header-button-wrap {
	display: none;
}

/* Cream ground under the lockup. The logo swaps to the dark lockup here —
   inc/home-masthead.php does that, because it needs the attachment URL at
   render time and this file cannot know it. */
body.home #main-header .site-main-header-wrap {
	background: var(--global-palette8);
}

/* The roundel has to cross the boundary, which means the logo overflows its own
   row upward. Three things are needed and all three are load-bearing:

     - height:auto on the row, or the 80px header height crops the lockup
     - overflow:visible on both rows, or the plum row clips what crosses into it
     - the negative margin itself

   The logo is later in the document than the eyebrow and `position: relative`
   puts it in the positioned paint layer, so it paints over the plum without a
   z-index of its own — which is exactly why the nav above needs one, and why
   the nav's z-index must go on .secondary-navigation rather than on the row.
   See the note there; getting it wrong slices the top off this logo.

   The lockup is a PNG with a real alpha channel (verified — corner alpha 0), so
   the plum shows through around the roundel rather than the logo carrying a
   cream box up with it. */
body.home #main-header .site-top-header-wrap,
body.home #main-header .site-main-header-wrap,
body.home #main-header .site-main-header-wrap .site-header-row,
body.home #main-header .site-main-header-wrap .site-header-section {
	overflow: visible;
}

body.home #main-header .site-main-header-wrap {
	height: auto;
}

/* The right-hand header section holds the nav and button, both hidden here, but
   it still reserves ~170px of the row. Collapse it so the lockup can use the
   whole content width. */
body.home #main-header .site-main-header-wrap .site-header-section-right {
	display: none;
}

body.home #main-header .site-branding {
	/* The lockup's own artwork carries the composition: within the file, the
	   roundel rises well above the wordmark, so lifting the whole image lifts
	   the roundel into the plum while the wordmark stays on the cream. No
	   separate positioning of the two parts is needed — or possible, since it
	   is one image.

	   -3.375rem puts the roundel's top a few pixels below the top of the page,
	   crossing almost the whole 64px eyebrow — the proportion the mockup shows.
	   The lockup is TRIMMED to its artwork, so the image's top edge IS the top
	   of the roundel and the offset is simply 64px of row less the ~10px of
	   clearance wanted above it. The untrimmed file needed -4.5rem to reach the
	   same place, because 3.8% of its height was empty. */
	margin-top: -3.375rem;
	position: relative;
	width: 100%;
}

body.home #main-header .site-branding img.custom-logo {
	/* Plain 100%, now that the asset is trimmed to its own alpha bounding box.
	   The previous 129% / -7.2% existed only to cancel the untrimmed file's
	   transparent padding — 5.6% left, 16.8% right — which had to be scaled and
	   shifted back out to put the S on the content rail.

	   Same result on screen here, since the width was already compensated. The
	   gain is everywhere the box is capped by layout instead: at 260px in the
	   mobile header the trimmed file shows 260px of artwork where the untrimmed
	   one showed 207. */
	width: 100%;
	max-width: none;
	height: auto;
}

/* No mobile override block, deliberately. An earlier version had one, using
   `width: revert` and `content: normal` to undo the hero sizing below 1024px,
   and it was both unnecessary and broken: unnecessary because #main-header is
   already hidden there, and broken because `revert` on the width sent the logo
   to its intrinsic 2091px rather than to Kadence's 150px mobile setting, while
   `content: normal` lost to the inline swap that comes later in the cascade.
   Scoping the whole section to #main-header removes the need for any of it —
   the phone gets Kadence's mobile header untouched. */

/* ---------------------------------------------------------------------------
   Hairline list, part two: the right-hand meta.

   THE PROBLEM, measured on /programs/ at desktop: the hairline rules draw at
   the full content width of 1242px while the text under them stops at the
   588px measure. Every rule overran its own content by 654px into empty
   ground, so the list read as unfinished rather than as a set of rows.

   THE FIX is not to shorten the rule — a short rule stops separating rows —
   but to give its right end something to hold: a small caps label per row.

   Structurally this is the one thing the note above says broke last time, so
   it is done differently. That attempt put the h3 and its paragraph in
   separate grid cells, which split the pair. This wraps the h3 and its meta
   TOGETHER in a group and leaves the body paragraph a sibling of that group,
   so the heading/paragraph pairing is untouched and only the heading line
   becomes two-column.

   Both selectors are needed: core/group renders its children inside
   .wp-block-group__inner-container on this install (verified with do_blocks,
   not assumed), but that wrapper is a layout-support detail and has changed
   between WordPress versions. Styling both survives it changing back.
   --------------------------------------------------------------------------- */
.sanctuary-hairline-list .sanctuary-hairline-head {
	border-top: 1px solid color-mix(in srgb, var(--global-palette3) 22%, transparent);
	padding-top: 1.1rem;
	margin-top: 1.6rem;
}

.sanctuary-hairline-list .sanctuary-hairline-head,
.sanctuary-hairline-list .sanctuary-hairline-head > .wp-block-group__inner-container {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	justify-content: space-between;
	gap: 0.15rem 1.5rem;
}

/* When the inner container IS emitted it is the outer flex's only child, and
   without this it shrinks to its content and the meta stops reaching the right
   edge — the exact fault this section exists to fix. */
.sanctuary-hairline-list .sanctuary-hairline-head > .wp-block-group__inner-container {
	flex: 1 1 100%;
}

/* The rule now belongs to the group, so the heading must not draw its own. */
.sanctuary-hairline-list .sanctuary-hairline-head :is(h2, h3, h4) {
	border-top: 0;
	padding-top: 0;
	margin: 0;
}

/* The heading and its body copy are separate blocks now, so WordPress puts a
   32px block gap between them — measured. That is wider than the gap BETWEEN
   rows once the hairline's own 1.6rem is counted, which made each paragraph
   look like it belonged to the row beneath it. Zero it and let the 0.3rem
   below do the spacing. */
.sanctuary-hairline-list .sanctuary-hairline-head {
	margin-bottom: 0;
}

.sanctuary-hairline-list .sanctuary-hairline-head:first-child {
	border-top: 0;
	padding-top: 0;
	margin-top: 0;
}

.sanctuary-hairline-list .sanctuary-hairline-head + p {
	margin-top: 0.3rem;
	color: var(--global-palette5);
}

/* A LINKED ROW MUST LOOK LINKED.

   Headings suppress the link treatment they inherit, so on Volunteer & Lead two
   of six rows were clickable and all six rendered identically — same plum, no
   underline, measured. A list where some rows are live and nothing says which
   is worse than one where none are: it teaches people the rows are not
   clickable, and they stop trying.

   DESIGN.md's link treatment, applied here rather than invented: plum,
   underlined, 1px at 0.18em offset, deepening on hover. */
.sanctuary-hairline-list .sanctuary-hairline-head :is(h2, h3, h4) a {
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 0.18em;
	color: inherit;
}

.sanctuary-hairline-list .sanctuary-hairline-head :is(h2, h3, h4) a:hover {
	color: var(--global-palette2);
}

/* On a plum ground the same rule goes butter, per DESIGN.md. */
.sanctuary-band-plum .sanctuary-hairline-list .sanctuary-hairline-head :is(h2, h3, h4) a:hover {
	color: var(--sanctuary-butter);
}

/* Mid ink rather than the eyebrow's soft ink: this sits at 14px in caps, and
   soft ink measured 4.88:1 on cream against mid ink's 5.87:1. AA passes at
   4.5, but DESIGN.md treats AA as the floor for small letterspaced type. */
.sanctuary-meta {
	font-family: var(--global-body-font-family);
	font-size: 0.8125rem;
	font-weight: 600;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--global-palette5);
	margin: 0;
	max-width: none; /* beats `p { max-width: 68ch }`, which would let it wrap */
	white-space: nowrap;
}

.has-theme-palette-1-background-color .sanctuary-meta,
.sanctuary-band-plum .sanctuary-meta {
	color: var(--global-palette7);
}

/* The plum ask puts its button in a right-justified second column, which is the
   whole point of the two-column layout at desktop. Once the columns stack there
   is no left column to sit opposite, so a right-justified button reads as
   knocked out of alignment under left-aligned copy. Return it to the rail. */
@media (max-width: 767px) {
	.sanctuary-band-plum .wp-block-buttons.is-content-justification-right {
		justify-content: flex-start;
	}
}

/* ---------------------------------------------------------------------------
   Offset measure — the same band, parked right of centre instead of left.

   Every band on the first Programs build put its 588px measure hard against
   the left edge of a 1290px column, so five sections in a row began at the
   same x. Correct line length, no composition. This is the counter-move:
   identical type, different position, so the page zig-zags down.

   Applies to the kadence/column wrapper, hence the .kt-inside-inner-col step.
   Every child needs the cap, not just the paragraphs: an uncapped h2 fills the
   column and auto margins then have nothing to push against.
   --------------------------------------------------------------------------- */
.sanctuary-offset .kt-inside-inner-col > * {
	max-width: var(--sanctuary-measure);
	margin-inline-start: auto;
	margin-inline-end: 0;
}

/* The stained-glass rule is 9rem, not a full measure, so `margin-inline-start:
   auto` pushed it to the far right of the column while the text it belongs to
   started 36.75rem short of that — the rule floated off on its own, which is
   the exact fault DESIGN.md already warned about for the centred case.
   Offset it by the same amount as everything else instead, so its left edge
   lands on the text's left edge. */
.sanctuary-offset .kt-inside-inner-col > .wp-block-separator {
	margin-inline-start: calc(100% - var(--sanctuary-measure));
	margin-inline-end: auto;
}

@media (max-width: 1024px) {
	/* Below the point where there is spare width to offset INTO, the offset is
	   just a ragged left edge. Return everything to the rail. */
	.sanctuary-offset .kt-inside-inner-col > *,
	.sanctuary-offset .kt-inside-inner-col > .wp-block-separator {
		margin-inline-start: 0;
	}
}

/* ---------------------------------------------------------------------------
   Pull quote — one line at display size, on greige.

   DESIGN.md: "Quotes and pullquotes — display serif, italic for quotes, plum
   text", and "set display type large, because the masthead serif has fine
   hairlines that disappear at small sizes."

   Greige is the third light ground and the reason this band exists twice over.
   Cream and peach differ by 1.08:1, so a cream/peach alternation carries almost
   no separation on a phone in daylight; greige sits 1.33 from cream and 1.23
   from peach. One greige band mid-page gives the eye a landmark that the
   cream/peach rhythm cannot.
   --------------------------------------------------------------------------- */
.sanctuary-pullquote {
	font-family: var(--global-heading-font-family);
	font-size: clamp(1.75rem, 1.15rem + 2.1vw, 2.75rem);
	line-height: 1.24;
	font-style: italic;
	color: var(--global-palette1);
	letter-spacing: -0.01em;
	/* 58rem, not the body measure. At 44px this is about 48 characters a line —
	   still comfortable for display type, which is read in glances rather than
	   tracked line by line, and it fills three quarters of the content column
	   instead of leaving the same empty right half every other band had. */
	max-width: 58rem;
	margin: 0;
	text-wrap: balance;
}

/* Deep ink, not mid ink. On greige mid ink measures 4.40:1 — under AA, and
   this is 13px letterspaced caps, the least forgiving thing on the page.
   Deep ink is 7.07:1 there and 9.43:1 on cream, so one value serves both. */
.sanctuary-pullquote-cite {
	font-family: var(--global-body-font-family);
	font-size: 0.8125rem;
	font-weight: 600;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--global-palette4);
	margin-top: 1.4rem;
}

/* Greige is darker than cream and Kadence has no inversion cascade for an
   appended colour, so the band states its own text colours rather than
   inheriting the page default and hoping.

   Measured against greige #decfc1: ink 9.30:1, deep ink 7.07:1, plum 6.57:1,
   mid ink 4.40:1. Mid ink is the one that fails, and it is the default for
   both the hairline-list body copy and the eyebrow — hence both overrides. */
.sanctuary-band-greige {
	color: var(--global-palette3);
}

.sanctuary-band-greige :is(.sanctuary-eyebrow, .is-style-eyebrow, .sanctuary-meta),
.sanctuary-band-greige .sanctuary-hairline-head + p {
	color: var(--global-palette4);
}

/* --- A page heading that is an h1 without looking like one -------------------

   Found 2026-09-02: 25 of the site's 33 pages had no `<h1>` at all — Home and
   the Accessibility page among them. Kadence's `page_title` is off, so the
   theme emits no `entry-title`, and every page opened with a Heading block set
   to H2. A page with no h1 gives screen-reader users nothing to jump to and
   tells search engines the page has no subject.

   The heading blocks were re-levelled to H1. That alone would have enlarged
   every page title by 60% (h1 is 64px against h2's 40px), which is a redesign,
   not an accessibility fix. These rules hold a *core* heading block at exactly
   the h2 metrics it already had, so the correction is inaudible to sighted
   readers and audible to everyone else.

   **Not scoped with `.entry-content >`.** The first version was, and it would
   have matched nothing: these headings sit six wrappers deep inside Kadence
   rowlayout and column divs, never as a direct child. The rule would have been
   served, looked right in review, and silently done nothing — leaving every
   page title at 64px. Checked against the rendered DOM, not assumed.

   `h1.wp-block-heading` is the core block's own class, so this cannot touch the
   theme's `h1.entry-title` on a post or event, which stays at full size. It
   also does not touch Kadence Advanced Heading blocks: those carry their own
   `font-size` in generated CSS keyed to their `kt-adv-heading*` class, so
   re-levelling one changes its tag and nothing else.

   Line-height is matched as well as size. Copying only `font-size` leaves the
   h1's tighter 1.12 in place and the heading's spacing shifts — small enough to
   miss on one page and obvious across thirty.

   Breakpoints are Kadence's own, read from the served CSS rather than assumed.
   Specificity beats Kadence's bare `h1` selector (0,1,1 against 0,0,1) inside
   each media query as well as outside it. */
h1.wp-block-heading {
	font-size: 40px;
	line-height: 1.15;
}

@media all and (max-width: 1024px) {
	h1.wp-block-heading {
		font-size: 34px;
		line-height: 1.18;
	}
}

@media all and (max-width: 767px) {
	h1.wp-block-heading {
		font-size: 27px;
		line-height: 1.2;
	}
}
