/*
 * aard.burntwood-spoonies.css
 * Burntwood Spoonies Connect — colour theme for aardCSS
 *
 * Brand colours (from the live pre-Hugo site, extracted in full in
 * `_rebuild-prep/output-spoonies-A-css-teardown.md`, §1):
 *   cyan  #00c8e8 -> oklch(0.7662 0.1351 214.7)  — primary
 *   pink  #ff4da6 -> oklch(0.6942 0.2264 354.1)  — accent
 *   teal  #00b8a0 -> oklch(0.7007 0.1281 178.9)  — spark (directory filter/badge accent)
 *   navy  #040e1c -> oklch(0.1619 0.0343 254.3)  — the "deep ocean, not bruise" background
 *
 * Palette generated: 2026-08-07 (four-stage pipeline, colour-workflow.md)
 * WhoCanUse-equivalent check: 2026-08-07 — WCAG contrast computed directly via a
 *   standalone PHP sRGB<->OKLCH + relative-luminance script (whocanuse.com itself
 *   not reachable from this session; ratios below are the same maths it reports on,
 *   not run through its 11-condition CVD simulation — treat colourblind-safety as
 *   checked on the hue/lightness-separation heuristic, not independently verified).
 *
 * DARK MODE — the site's only mode until this rebuild — is a near-exact port of
 * the live site's existing palette, because it already checks out:
 *   - white  (#f0faff) on navy (#040e1c):  18.27:1  (AAA)
 *   - cyan   (#00c8e8) on navy:              9.61:1  (AAA)
 *   - pink   (#ff4da6) on navy:              6.33:1  (AA, short of AAA — kept as-is,
 *       it's the live site's real value and still comfortably passes AA)
 *   - grey   (#8fb8cc) on navy:              9.12:1  (AAA)
 *   - navy on cyan   (button label, e.g. .btn-cyan):  9.61:1  (AAA)
 *   - navy on pink   (button label, e.g. .btn-pink):  6.33:1  (AA)
 *   - navy on teal:                                   7.71:1  (AAA)
 *   IMPORTANT — do not put WHITE text on a cyan/pink/teal fill in dark mode:
 *     white on cyan fill = 1.90:1 (fail), white on pink fill = 2.89:1 (fail).
 *     This is why --aard-*-inverse below is navy, not white, in dark mode —
 *     if the pre-rebuild site ever used white button labels on these fills,
 *     that was a real contrast bug this theme fixes, not a regression.
 *
 * LIGHT MODE is new — the live site has never had one. Every text/interactive
 * colour below is a genuinely re-derived, darker point on the SAME hue+chroma
 * as the brand colour (not a lightened tint), searched for the nearest lightness
 * that clears AAA (7:1) against white, per colour-workflow.md's Stage 3 target:
 *   - primary  #005f7d (cyan hue 214.7, chroma 0.1351, L 0.430) on white: 7.16:1 (AAA)
 *   - accent   #ae0063 (pink hue 354.1, chroma 0.2264, L 0.470) on white: 7.05:1 (AAA)
 *   - spark    #008670 (teal hue 178.9, chroma 0.1281, L 0.540) on white: 4.52:1 (AA —
 *       AAA search pushed chroma/lightness into a muddy grey-green at this hue; AA
 *       accepted since spark is a badge/filter accent, never body text)
 *   - body text: the brand navy (#040e1c) reused as-is on white: 19.36:1 (AAA) —
 *       ties the two modes together (dark mode's background = light mode's text)
 *       rather than inventing an unrelated grey
 *   - muted text: #557c8f (grey's own hue 229.3, chroma 0.0524, L 0.565) on white:
 *       4.50:1 (AA — the live site's actual grey, #8fb8cc, only manages 2.12:1 on
 *       white and cannot be reused for light-mode muted text without darkening)
 *   - white text on primary fill (#005f7d): 7.16:1 (AAA) — white on accent fill
 *       (#ae0063): 7.05:1 (AAA) — so light mode's inverse IS white, the opposite
 *       of dark mode, because the light-mode fills are dark enough to take it.
 *
 * No overrides needed/accepted for this client — every role below clears at
 * least AA on its actual use (text vs UI-component), and every text role
 * clears AAA except spark (AA, decorative/badge use only, see above).
 */

:root {
	/* ---- Primary (cyan) — links, logo, primary interactive colour ---- */
	--aard-primary:                  light-dark(#005f7d, #00c8e8);
	--aard-primary-hover:            light-dark(#00526f, #0099bb);
	--aard-primary-background:       light-dark(#e3f6fa, #00c8e8);
	--aard-primary-hover-background: light-dark(#cdecf3, #0099bb);
	--aard-primary-border:           var(--aard-primary-background);
	--aard-primary-hover-border:     var(--aard-primary-hover-background);
	--aard-primary-inverse:          light-dark(#fff, #040e1c);
	--aard-primary-focus:            light-dark(#005f7d, #00c8e8);
	--aard-primary-underline:        light-dark(rgba(0, 95, 125, 0.4), rgba(0, 200, 232, 0.4));

	/* ---- Accent (pink) — secondary CTA / highlight ---- */
	--aard-accent:                   light-dark(#ae0063, #ff4da6);
	--aard-accent-hover:             light-dark(#970051, #cc0066);
	--aard-accent-background:        light-dark(#ffe9f3, #ff4da6);
	--aard-accent-hover-background:  light-dark(#ffd6e8, #cc0066);
	--aard-accent-border:            var(--aard-accent-background);
	--aard-accent-hover-border:      var(--aard-accent-hover-background);
	--aard-accent-inverse:           light-dark(#fff, #040e1c);
	--aard-accent-focus:             light-dark(#ae0063, #ff4da6);
	--aard-accent-underline:         light-dark(rgba(174, 0, 99, 0.4), rgba(255, 77, 166, 0.4));

	/* ---- Spark (teal) — directory filter/badge accent only, never body text ---- */
	--aard-spark:                    light-dark(#008670, #00b8a0);
	--aard-spark-hover:              light-dark(#00735f, #009684);
	--aard-spark-background:         light-dark(#e0f5f1, #00b8a0);
	--aard-spark-hover-background:   light-dark(#c9ece5, #009684);
	--aard-spark-border:             var(--aard-spark-background);
	--aard-spark-hover-border:       var(--aard-spark-hover-background);
	--aard-spark-inverse:            light-dark(#fff, #040e1c);

	/* ---- Base surface — the "deep ocean, not bruise" identity ---- */
	--aard-background-color:         light-dark(#fff, #040e1c);
	--aard-color:                    light-dark(#040e1c, #f0faff);
	--aard-muted-color:              light-dark(#557c8f, #8fb8cc);
	--aard-card-background-color:    light-dark(#fff, #0d1f35);
	--aard-card-sectioning-background-color: light-dark(#f7fbfd, #0d1f35);

	/* ---- Type ---- */
	--aard-font-family:              'Nunito', sans-serif;

	/* ---- Fluid type scale, client-scoped ----
	 * Utopia-style clamp() ladder, pinned 320px -> 1536px (aardCSS's own xxl
	 * breakpoint, css/aard.grid.css) so the fluid range finishes exactly where
	 * the grid's last breakpoint fires, per the set.studio teardown
	 * (design-director/references/site-studies-css.md) — "pin the fluid range
	 * to the layout constant, don't invent a separate one". Kept modest
	 * (max ~3.25rem) rather than set.studio's own poster-scale top end, which
	 * is bespoke to their brand. One shared viewport pair for every step, so
	 * the ratio between steps stays constant at every width instead of
	 * drifting — the exact failure the teardown flagged in aardCSS's
	 * pre-existing three-unrelated-clamps draft in
	 * documentation/advanced-css-techniques.md §11 (never shipped, superseded
	 * by this file for this client).
	 * Steps generated at a ~1.25 ratio (min) / ~1.3 ratio (max), root 16px.
	 */
	--bs-step--1: clamp(0.9rem, 0.86rem + 0.19vw, 1rem);      /* small print, meta */
	--bs-step-0:  clamp(1.125rem, 1.06rem + 0.32vw, 1.3rem);  /* body */
	--bs-step-1:  clamp(1.35rem, 1.26rem + 0.45vw, 1.6rem);   /* h4 / card-title */
	--bs-step-2:  clamp(1.6rem, 1.46rem + 0.71vw, 2rem);      /* h3 / section-title */
	--bs-step-3:  clamp(1.95rem, 1.75rem + 1vw, 2.5rem);      /* h2 */
	--bs-step-4:  clamp(2.4rem, 2.1rem + 1.5vw, 3.25rem);     /* h1 */
	--bs-step-5:  clamp(2.9rem, 2.4rem + 2.5vw, 4.5rem);      /* hero-title */
}

/* ---- Heading scale ----
 * Fluid sizing from the ladder above, plus tight letter-spacing on the
 * larger steps — "highest ratio of looks-intentional to effort" per the
 * REFERENCE-TEARDOWNS principles cited in site-teardown-candidates.md.
 * Values taper from -0.03em at the top of the scale to 0 at body size,
 * since tight tracking on small text just hurts legibility.
 */
h1 { font-size: var(--bs-step-4); letter-spacing: -0.03em; line-height: 1.1; }
h2 { font-size: var(--bs-step-3); letter-spacing: -0.02em; line-height: 1.15; }
h3 { font-size: var(--bs-step-2); letter-spacing: -0.015em; line-height: 1.2; }
h4, h5, h6 { font-size: var(--bs-step-1); letter-spacing: -0.01em; }
small, .text-meta { font-size: var(--bs-step--1); }

/* ---- Focus, louder than hover ----
 * A solid, offset ring rather than the browser default thin outline — per
 * the usflags.design teardown ("focus is louder than hover, on purpose").
 * Applies site-wide, not just the Directory cards (which already had their
 * own focus-visible rule before this pass).
 */
a:focus-visible,
button:focus-visible,
.btn:focus-visible {
	outline: 3px solid var(--aard-primary);
	outline-offset: 3px;
	border-radius: 2px;
}

/* ---- Nav ----
 * Fixes from Paul's review of the first pass, 2026-08-08:
 *
 * 1. Current-page indicator. Pico's default aria-current treatment on nav
 *    links is a near-invisible colour shift, while "Contact" — styled as a
 *    .btn-primary CTA regardless of which page is active — reads as a
 *    permanent highlight that never moves. Give the actual current page a
 *    clear, distinct underline so wayfinding doesn't rely on the CTA button.
 * 2. Theme-toggle clipping. `nav ul:last-of-type` (aardCSS/Pico) pulls the
 *    whole trailing <ul> right by `-1 * --pico-nav-element-spacing-horizontal`
 *    so a plain <a>'s own compensating negative margin (on `nav li :where(a,
 *    [role=link])`) lands its text flush with the container edge. That
 *    compensating rule is scoped to `a`/`[role=link]` only, so the
 *    theme-toggle <button> never gets it and hangs off the right edge
 *    uncompensated — a generic aardCSS/Pico gap for anyone putting a plain
 *    <button> in nav, worth fixing upstream too, not just here.
 */
nav a[aria-current="page"] {
	position: relative;
	font-weight: 700;
	color: var(--aard-color);
}

nav a[aria-current="page"]::after {
	content: '';
	position: absolute;
	left: 0.6rem;
	right: 0.6rem;
	bottom: 0.15rem;
	height: 2px;
	border-radius: 1px;
	background: var(--aard-primary);
}

/* 2b. aardCSS's burger label (aard.component.nav.css) is sized for its own
 *     compact default spacing, which falls short of a 44px tap target here.
 *     Widen it on this site rather than in the shared component, since other
 *     aardCSS sites may rely on the smaller footprint. Scoped to the same
 *     max-width:639px range the component itself uses to show the burger,
 *     so this never overrides the component's desktop display:none. */
@media (max-width: 639px) {
	nav > .navbar-burger {
		min-width: 44px;
		min-height: 44px;
		display: flex;
		align-items: center;
		justify-content: center;
	}
}

/* ---- Footer nav ----
 * The footer's own separately-hardcoded link list (footer.html) is a plain
 * aardCSS/Pico nav — same non-wrapping flex row as the header, just with no
 * burger fallback since it's five plain links, not a CTA/dropdown/toggle
 * mix. Rather than duplicating the burger machinery for a secondary nav,
 * let it wrap: still no horizontal scroll, still all links reachable.
 */
footer nav ul {
	flex-wrap: wrap;
	justify-content: center;
	row-gap: 0.25rem;
}
footer nav ul:first-of-type,
footer nav ul:last-of-type {
	margin-inline: 0;
}

/* 44px round outline so the ☾/☀ glyph reads as a button. Without it,
 * `.btn-link` (no background, no border, underlined) makes it look like a
 * stray character. */
nav li #theme-toggle {
	margin: calc(var(--pico-nav-link-spacing-vertical, 0.5rem) * -1) calc(var(--pico-nav-link-spacing-horizontal, 0.5rem) * -1);
	padding: var(--pico-nav-link-spacing-vertical, 0.5rem) var(--pico-nav-link-spacing-horizontal, 0.5rem);
	min-width: 44px;
	min-height: 44px;
	border: 1px solid var(--aard-primary-border);
	border-radius: 50%;
	text-decoration: none;
}

nav li #theme-toggle:hover,
nav li #theme-toggle:focus-visible {
	border-color: var(--aard-primary);
	text-decoration: none;
}

/* 3. The nav CTA ("Contact") reads as a flat highlight, not a button.
 *    `nav li :where(a, [role=link])` (aardCSS/Pico) sets its own margin,
 *    padding and border-radius on every nav link, including `.btn-primary`
 *    — those values fight .btn's own box model and win (later/more
 *    specific), leaving a tight, square-cornered fill that reads as
 *    highlighted text rather than a button. Reset explicitly so the nav CTA
 *    keeps .btn's real shape. No tilt/marker treatment here deliberately —
 *    see .btn-marker below, which is for standalone page CTAs, not chrome. */
nav li a.btn {
	margin: 0;
	padding: 0.6rem 1.4rem;
	border-radius: 0.375rem;
}

/* ---- Marker / sticker button ----
 * A "highlighter sticker" treatment — solid fill, bold ink, slight tilt,
 * hand-drawn double outline — matching the marker/sticker look already
 * showing up in the group's own promo images. Reference: getcssscan.com
 * "Button 53". Adapted rather than copied: brand colours instead of
 * cyan-on-black, and the outline colour is var(--aard-color) rather than
 * currentColor, because the offset spills the outline out past the button
 * edge onto the page background — it needs to read against *that*, not
 * just against the button's own text colour. Combine with .btn and a
 * colour role, e.g. class="btn btn-primary btn-marker". Deliberately NOT
 * used in nav — a menu CTA needs to read as ordinary chrome, not a sticker,
 * hence the plain shape fix above instead. */
.btn-marker {
	position: relative;
	overflow: visible;
	border: none;
	font-weight: 800;
	transform: rotate(-2deg);
}

.btn-marker::after {
	content: '';
	position: absolute;
	inset: 0;
	border: 2px solid var(--aard-color);
	pointer-events: none;
	transform: translate(5px, 5px);
	transition: transform 0.15s ease;
}

.btn-marker:hover::after,
.btn-marker:focus-visible::after {
	transform: translate(2px, 2px);
}

.btn-marker:focus-visible {
	outline-offset: 6px;
}

/* Non-colour, brand-owned overrides go below the variable block. */

/* Highlighter-pen swipe for the key word or phrase in a heading: [square
 * brackets] in hero_title and section titles, plus the KOKO banner heading.
 * Echoes the .btn-marker look. The text keeps its normal colour; a
 * translucent accent smudge sits behind it in a ::before, with four
 * different corner radii plus rotate and skew so it reads as hand-drawn
 * rather than a rectangle. `inset` (not width/height) sizes it to the
 * element's own box, so it still covers a multi-line wrap.
 *
 * Don't turn this into a gradient clipped to the text: browsers without
 * light-dark() image support (before Chrome/Firefox 150, Safari 27) drop the
 * background but keep the transparent text fill, so the text vanishes.
 */
.highlight,
[class*="koko-text"] {
	position: relative;
	display: inline-block;
	padding: 0.05em 0.3em;
	color: var(--aard-color);
	z-index: 0;
}

.highlight::before,
[class*="koko-text"]::before {
	content: '';
	position: absolute;
	z-index: -1;
	inset: -0.05em -0.3em;
	background: light-dark(rgba(174, 0, 99, 0.65), rgba(255, 77, 166, 0.7));
	border-radius: 255px 15px 225px 15px / 15px 225px 15px 255px;
	transform: rotate(-2deg) skew(-3deg);
}

/* Righteous is the brand display face throughout the old site, not just the
 * hero — h1/h2/h3 covers real headings site-wide. hero-sub is deliberately
 * excluded (it's body copy under the hero title, not a heading). The
 * class list stays for non-heading elements that also want the display face
 * (.hero-title itself is an h1 so it's covered either way; kept for clarity
 * and in case a future non-heading element reuses it). */
.font-display,
h1, h2, h3,
.hero-title,
.section-title,
.card-title,
.nav-logo span {
	font-family: 'Righteous', cursive;
}

/* ---- Directory grid — flat, "let the gap do the work" cards ----
 * No border/background/padding on the cell itself; hover gets the "card"
 * treatment instead of the resting state. See
 * output-spoonies-B-directory-data.md §4.
 */
.directory-grid {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
	gap: calc(var(--aard-spacing, 1rem) * 2);
}

/* aard.css sets `ul li { list-style: square }` directly on <li> — a direct
   declaration on the element beats the parent's inherited list-style
   regardless of selector specificity, so the bullet must be killed here too. */
.directory-grid li,
.taxonomy-term-list li {
	list-style: none;
}

/* Border and surface only, no shadow: with 51 entries a flat list reads as
 * plain text, so each record needs a visible boundary. */
.directory-card {
	padding: 1.25rem;
	background: var(--aard-card-background-color);
	border: 1px solid var(--aard-primary-border);
	border-radius: var(--aard-border-radius, 0.25rem);
}

.directory-card a {
	display: block;
	text-decoration: none;
	color: inherit;
}

.directory-card-eyebrow {
	font-size: 0.75em;
	color: var(--aard-muted-color);
	margin: 0 0 0.25em;
}

.directory-card-name {
	font-weight: 700;
	color: var(--aard-color);
	margin: 0 0 0.35em;
}

.directory-card a:hover .directory-card-name {
	text-decoration: underline;
}

.directory-card a:hover .directory-card-name::after {
	content: " \2192";
}

.directory-card a:focus-visible {
	outline: 3px solid var(--aard-primary);
	outline-offset: 4px;
}

.directory-card-summary {
	font-size: 0.9em;
	color: var(--aard-muted-color);
	margin: 0 0 0.5em;
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
}

.directory-card-coverage {
	font-size: 0.75em;
	color: var(--aard-muted-color);
	margin: 0 0 0.5em;
}

/* Must be `a.directory-card-cta`, not `.directory-card-cta`: it has to match
 * `.directory-card a` above (one class + one type) so it wins on source
 * order, otherwise that rule's `text-decoration: none` and `color: inherit`
 * override it. Padding and min-height keep the tap target clear of the
 * card's own link above it. */
a.directory-card-cta {
	display: inline-block;
	min-height: 2rem;
	padding: 0.4em 0;
	font-weight: 600;
	color: var(--aard-spark);
	text-decoration: underline;
}

.directory-record-contact {
	list-style: none;
	margin: 1em 0;
	padding: 0;
}

.directory-record-contact li {
	margin-bottom: 0.35em;
}

.taxonomy-term-list {
	list-style: none;
	margin: 0 0 1.5em;
	padding: 0;
}

.taxonomy-term-list li {
	display: flex;
	justify-content: space-between;
	gap: 0.5em;
	padding: 0.4em 0;
	border-bottom: 1px solid var(--aard-primary-border);
}

.term-count {
	color: var(--aard-muted-color);
}

.directory-submission-cta,
.directory-disclaimer {
	margin: 2em 0;
}

/* Narrow-down control on category/coverage-area term pages — aardCSS's own
   details.dropdown component (see aard.css), just given a sensible width
   and pulled out of the default nav-flavoured spacing so it reads as a
   standalone control above the grid rather than a nav item. */
.directory-narrow-down {
	max-width: 22rem;
	margin: 0 0 2em;
}

.directory-narrow-down summary {
	color: var(--aard-color);
}

.directory-narrow-down ul {
	max-height: 20rem;
	overflow-y: auto;
}

.directory-narrow-down li strong {
	display: block;
	padding: 0.5em 1rem 0.25em;
	font-size: 0.75em;
	text-transform: uppercase;
	letter-spacing: 0.04em;
	color: var(--aard-muted-color);
}

/* ---- Spoonie Sessions (archive index, episode pages, guest/topic lists) ----
 * Palette and type are the homepage's: navy "deep ocean" ground with the
 * ambient glow, Righteous display, cyan / pink / teal as the three tile
 * colours. The date tile stands in for a poster image (episodes carry no
 * artwork), so it has to carry the page on its own. See
 * output-spoonies-C-livestream-archive-spec.md §5.
 */
.session-page {
	--session-ease: cubic-bezier(0.16, 1, 0.3, 1);
	--session-radius: 1.25rem;
	--session-line: color-mix(in srgb, var(--aard-muted-color) 38%, transparent);
	--session-shadow: light-dark(rgb(4 14 28 / 0.16), rgb(0 0 0 / 0.55));
}

.session-page ::selection {
	background: var(--aard-accent);
	color: var(--aard-accent-inverse);
}

/* Header of the archive index. */
.session-head {
	position: relative;
	z-index: 1;
	max-width: 46rem;
	padding: clamp(1.5rem, 4vw, 3rem) 0 clamp(1.5rem, 3vw, 2.5rem);
}
.session-head h1 {
	font-size: var(--bs-step-5);
	letter-spacing: -0.03em;
	line-height: 1.05;
	margin: 0 0 0.4em;
	text-wrap: balance;
}
.session-intro { font-size: var(--bs-step-1); color: var(--aard-muted-color); }
.session-intro p { margin: 0; }

/* The highlighter swipe draws itself in once, on arrival. The end state is
 * the resting state, so nothing is hidden if the animation never runs. */
@media (prefers-reduced-motion: no-preference) {
	.session-page .highlight::before {
		animation: session-swipe 0.8s var(--session-ease) 0.2s backwards;
	}
}
@keyframes session-swipe {
	from { clip-path: inset(0 100% 0 0); }
	to   { clip-path: inset(0 0 0 0); }
}

/* Date tile ("poster"). Sizes itself from its own width, so the same markup
 * is a thumbnail in a row, a badge on an episode page and a poster in the
 * feature panel. */
.session-cover {
	--tile: var(--aard-primary);
	--tile-on: var(--aard-primary-inverse);
	position: relative;
	display: grid;
	align-content: end;
	justify-items: start;
	container-type: inline-size;
	aspect-ratio: 1;
	overflow: hidden;
	border-radius: 0.9rem;
	background: var(--tile);
	color: var(--tile-on);
	line-height: 1;
}
.session-cover-accent { --tile: var(--aard-accent); --tile-on: var(--aard-accent-inverse); }
.session-cover-spark  { --tile: var(--aard-spark);  --tile-on: var(--aard-spark-inverse); }
.session-cover::before {
	content: "";
	position: absolute;
	inset: 0;
	background:
		radial-gradient(circle at 88% 8%, rgb(255 255 255 / 0.3), transparent 48%),
		repeating-linear-gradient(-45deg, transparent 0 0.85rem, color-mix(in srgb, var(--tile-on) 7%, transparent) 0 1.7rem);
}
/* The inset lives on the children, not the tile: a container's own cqi units
 * resolve against an ancestor container (here, the viewport), not the tile. */
.session-cover > :not(svg) { position: relative; margin-inline-start: 9cqi; }
.session-cover-month { margin-block-end: 9cqi; }
.session-cover-day {
	font-family: 'Righteous', cursive;
	font-size: 3rem;
	font-size: 52cqi;
	letter-spacing: -0.04em;
	line-height: 0.85;
}
.session-cover-month {
	margin-top: 0.3em;
	font-size: 0.8rem;
	font-size: 13cqi;
	font-weight: 800;
	letter-spacing: 0.08em;
	text-transform: uppercase;
}
.session-cover-month span { font-weight: 600; }
.session-cover-play {
	position: absolute;
	top: 9cqi;
	right: 9cqi;
	width: 24cqi;
	height: auto;
	fill: var(--tile-on);
	transition: transform 0.25s var(--session-ease);
}
.session-cover-play path { fill: var(--tile); }

/* Shared text pieces. */
.session-meta {
	display: flex;
	flex-wrap: wrap;
	gap: 0.15rem 0.6rem;
	margin: 0.4rem 0 0;
	color: var(--aard-muted-color);
	font-size: var(--bs-step--1);
}
/* The dot trails the item before it, so a wrapped line never starts with one. */
.session-meta > *:not(:last-child)::after { content: "\00b7" / ""; margin-inline-start: 0.6rem; }
.session-lede { max-width: 38rem; margin: 0.9rem 0 0; font-size: var(--bs-step-1); line-height: 1.5; text-wrap: pretty; }
.session-actions { display: flex; flex-wrap: wrap; gap: 0.75rem; margin: 1.4rem 0 0; }
.session-actions .btn { margin: 0; }
.session-empty { color: var(--aard-muted-color); }

a.session-chip,
span.session-chip {
	display: inline-flex;
	align-items: center;
	padding: 0.2em 0.8em;
	border: 1px solid var(--session-line);
	border-radius: 50rem;
	font-size: 0.9rem;
	font-weight: 700;
	color: var(--aard-color);
	text-decoration: none;
}
a.session-chip { min-block-size: var(--aard-tap-min, 2.75rem); transition: border-color 0.2s, color 0.2s; }
a.session-chip:hover { border-color: var(--aard-primary); color: var(--aard-primary); }

/* Latest session, large. */
.session-feature {
	position: relative;
	isolation: isolate;
	display: grid;
	gap: clamp(1.25rem, 3vw, 2.5rem);
	padding: clamp(1rem, 2.5vw, 1.75rem);
	border: 1px solid var(--session-line);
	border-radius: var(--session-radius);
	background: var(--aard-card-background-color);
	box-shadow: 0 28px 48px -28px var(--session-shadow);
}
.session-feature::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	border-radius: inherit;
	pointer-events: none;
	background:
		radial-gradient(60% 80% at 0% 0%, light-dark(rgb(0 95 125 / 0.09), rgb(0 200 232 / 0.16)), transparent 70%),
		radial-gradient(50% 70% at 100% 100%, light-dark(rgb(174 0 99 / 0.07), rgb(255 77 166 / 0.14)), transparent 70%);
}
.session-feature-cover { display: block; text-decoration: none; }
.session-feature-cover .session-cover { aspect-ratio: 4 / 3; border-radius: calc(var(--session-radius) - 0.4rem); }
.session-feature-body { align-self: center; padding: 0.25rem 0.25rem 0.5rem; }
.session-feature-body > p:first-child { margin: 0 0 0.9rem; }
.session-feature-title { margin: 0; font-size: var(--bs-step-4); line-height: 1.08; text-wrap: balance; }
.session-feature-title a,
.session-row-title a { color: inherit; text-decoration: none; }
.session-feature-title a:hover,
.session-row-title a:hover { text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 0.18em; text-decoration-color: var(--aard-accent); }
@media (min-width: 48rem) {
	.session-feature { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); }
}
.session-feature:hover .session-cover-play { transform: scale(1.12); }

.session-more { margin: clamp(2.5rem, 5vw, 3.5rem) 0 1rem; font-size: var(--bs-step-2); }

/* Month jump bar and month groups. Plain in-page anchors, no script. */
/* A <nav>, so aard.css makes it a flex row; the year rows must stack. */
.session-jump { display: block; }
.session-jump ul { list-style: none; display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem; margin: 0 0 0.5rem; padding: 0; }
.session-jump li { list-style: none; }
.session-jump-year { margin-inline-end: 0.15rem; font-family: 'Righteous', cursive; color: var(--aard-muted-color); }
.session-jump li:not(.session-jump-year) a {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-block-size: var(--aard-tap-min, 2.75rem);
	min-inline-size: var(--aard-tap-min, 2.75rem);
	padding: 0 0.8rem;
	border: 1px solid var(--session-line);
	border-radius: 50rem;
	font-weight: 700;
	color: var(--aard-color);
	text-decoration: none;
	transition: border-color 0.2s, color 0.2s;
}
.session-jump a:hover { border-color: var(--aard-primary); color: var(--aard-primary); }
.session-month { scroll-margin-top: 1rem; }
.session-month h3 { margin: 1.75rem 0 0.75rem; font-size: var(--bs-step-1); color: var(--aard-muted-color); scroll-margin-top: 1rem; }

/* Archive rows. The whole row is the link: the title's ::after covers it. */
.session-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.75rem; }
.session-list > li { list-style: none; }
.session-row {
	position: relative;
	display: grid;
	grid-template-columns: 4.75rem minmax(0, 1fr);
	gap: 1rem;
	align-items: center;
	padding: 0.75rem;
	border: 1px solid var(--session-line);
	border-radius: 1rem;
	background: var(--aard-card-background-color);
	transition: transform 0.25s var(--session-ease), box-shadow 0.25s var(--session-ease), border-color 0.2s;
}
.session-row .session-cover { border-radius: 0.65rem; }
.session-row-title { margin: 0; font-size: var(--bs-step-1); line-height: 1.2; }
.session-row-title a::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
.session-row-title a:focus-visible { outline: none; box-shadow: none; }
.session-row:has(a:focus-visible) { outline: 3px solid var(--aard-primary); outline-offset: 3px; }
.session-row-blurb {
	margin: 0.4rem 0 0;
	color: var(--aard-muted-color);
	font-size: var(--bs-step--1);
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
}
.session-topics { display: flex; flex-wrap: wrap; gap: 0.35rem; margin: 0.5rem 0 0; }
.session-topics span {
	padding: 0.05em 0.6em;
	border-radius: 50rem;
	background: light-dark(rgb(0 95 125 / 0.09), rgb(0 200 232 / 0.12));
	color: var(--aard-color);
	font-size: 0.8rem;
	font-weight: 700;
}
.session-row-arrow {
	display: none;
	width: 1.6rem;
	height: 1.6rem;
	fill: none;
	stroke: var(--aard-muted-color);
	stroke-width: 2;
	stroke-linecap: round;
	stroke-linejoin: round;
	transition: transform 0.25s var(--session-ease), stroke 0.2s;
}
@media (min-width: 40rem) {
	.session-row { grid-template-columns: 5.5rem minmax(0, 1fr) auto; padding: 0.9rem 1.25rem 0.9rem 0.9rem; gap: 1.25rem; }
	.session-row-arrow { display: block; }
}
@media (hover: hover) {
	.session-row:hover {
		border-color: var(--aard-primary);
		box-shadow: 0 18px 32px -20px var(--session-shadow);
	}
	.session-row:hover .session-row-arrow { stroke: var(--aard-primary); transform: translateX(4px); }
	.session-row:hover .session-cover-play { transform: scale(1.12); }
}
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
	.session-row:hover { transform: translateY(-2px); }
}

/* Episode page. */
.session-single-head {
	display: grid;
	gap: 1.25rem 2rem;
	align-items: center;
	padding: clamp(0.5rem, 2vw, 1.5rem) 0 0;
}
.session-single-head .session-cover { width: 6.5rem; }
.session-single-head h1 { margin: 0; line-height: 1.05; text-wrap: balance; }
.session-people { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; margin: 0.9rem 0 0; }
.session-people + .session-people { margin-top: 0.5rem; }
.session-people-label { color: var(--aard-muted-color); font-weight: 700; }
@media (min-width: 40rem) {
	.session-single-head { grid-template-columns: clamp(8rem, 18vw, 12rem) minmax(0, 1fr); }
	.session-single-head .session-cover { width: auto; border-radius: 1.1rem; }
}

.session-stage { position: relative; isolation: isolate; margin: clamp(1.75rem, 4vw, 2.75rem) 0 0; }
.session-stage::before {
	content: "";
	position: absolute;
	inset: 6% 0 -8%;
	z-index: -1;
	border-radius: var(--session-radius);
	filter: blur(2.5rem);
	opacity: 0.85;
	pointer-events: none;
	background:
		radial-gradient(60% 90% at 15% 20%, light-dark(rgb(0 95 125 / 0.2), rgb(0 200 232 / 0.3)), transparent 70%),
		radial-gradient(55% 90% at 85% 85%, light-dark(rgb(174 0 99 / 0.16), rgb(255 77 166 / 0.26)), transparent 70%);
}
.session-stage .video-wrap {
	margin: 0;
	border: 1px solid var(--session-line);
	border-radius: var(--session-radius);
	box-shadow: 0 32px 56px -28px var(--session-shadow);
}

.session-body { display: grid; gap: 2rem; margin-top: clamp(2rem, 5vw, 3.5rem); }
@media (min-width: 60rem) {
	.session-body-split { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: clamp(2rem, 4vw, 4rem); align-items: start; }
}
.session-notes { max-width: 65ch; font-size: var(--bs-step-0); }
.session-notes > :first-child { margin-top: 0; }

.session-tracks {
	max-width: 46rem;
	padding: 1.25rem clamp(0.75rem, 2vw, 1.25rem) 0.75rem;
	border: 1px solid var(--session-line);
	border-radius: var(--session-radius);
	background: var(--aard-card-background-color);
}
.session-tracks h2 { margin: 0 0 0.75rem 0.5rem; font-size: var(--bs-step-2); }
.tracklist { list-style: none; margin: 0; padding: 0; }
.tracklist li {
	list-style: none;
	position: relative;
	display: grid;
	grid-template-columns: 4.6rem minmax(0, 1fr);
	gap: 0.75rem;
	align-items: baseline;
	padding: 0.55rem 0.6rem;
	border-radius: 0.6rem;
	border-top: 1px solid var(--session-line);
}
.tracklist li:first-child { border-top-color: transparent; }
.tracklist li:not([data-at]) { grid-template-columns: minmax(0, 1fr); }
.tracklist time,
.track-seek {
	font-size: 0.9rem;
	font-variant-numeric: tabular-nums;
	color: var(--aard-muted-color);
}
.track-name strong { color: var(--aard-color); }
.track-name span { color: var(--aard-muted-color); }
.track-name span::before { content: "\2013\00a0" / ""; }

/* A marker row (a guest joins, an ad break): a labelled moment, not a song. */
.tracklist li.marker .marker-text { color: var(--aard-muted-color); font-style: italic; }

/* Click-to-seek, added by site.js when the page has a recording. */
.track-seek {
	justify-self: start;
	min-block-size: 2rem;
	padding: 0 0.6rem;
	border: 1px solid var(--session-line);
	border-radius: 50rem;
	background: transparent;
	font-family: inherit;
	font-weight: 700;
	cursor: pointer;
	transition: background 0.2s, color 0.2s, border-color 0.2s;
}
.track-seek:hover { border-color: var(--aard-primary); color: var(--aard-primary); }
.tracklist li.is-playing { background: light-dark(rgb(0 95 125 / 0.09), rgb(0 200 232 / 0.12)); }
.tracklist li.is-playing .track-seek { background: var(--aard-primary); border-color: var(--aard-primary); color: var(--aard-primary-inverse); }
.tracklist li.is-playing::after {
	content: "";
	position: absolute;
	top: 50%;
	right: 0.9rem;
	width: 1rem;
	height: 1rem;
	translate: 0 -50%;
	color: var(--aard-accent);
	background:
		linear-gradient(currentColor, currentColor) 0 100% / 0.25rem 70% no-repeat,
		linear-gradient(currentColor, currentColor) 50% 100% / 0.25rem 100% no-repeat,
		linear-gradient(currentColor, currentColor) 100% 100% / 0.25rem 45% no-repeat;
}
.tracklist li.is-playing .track-name { padding-right: 1.6rem; }
@media (max-width: 39.9375rem) {
	/* Narrow: the title takes its own line instead of wrapping after the dash. */
	.track-name span { display: block; }
	.track-name span::before { content: none; }
}
@media (prefers-reduced-motion: no-preference) {
	.tracklist li.is-playing.is-live::after { animation: session-eq 0.9s ease-in-out infinite alternate; }
}
@keyframes session-eq {
	to { background-size: 0.25rem 40%, 0.25rem 75%, 0.25rem 100%; }
}

/* Older / newer. */
.session-pager { display: grid; justify-content: normal; gap: 0.75rem; margin: clamp(2.5rem, 6vw, 4rem) 0 0; }
.session-pager a {
	display: block;
	padding: 1rem 1.25rem;
	border: 1px solid var(--session-line);
	border-radius: 1rem;
	background: var(--aard-card-background-color);
	color: var(--aard-color);
	font-family: 'Righteous', cursive;
	font-size: var(--bs-step-1);
	line-height: 1.2;
	text-decoration: none;
	transition: border-color 0.2s;
}
.session-pager a:hover { border-color: var(--aard-primary); }
.session-pager a span {
	display: block;
	margin-bottom: 0.25rem;
	color: var(--aard-muted-color);
	font-family: 'Nunito', sans-serif;
	font-size: var(--bs-step--1);
	font-weight: 700;
}
.session-pager-newer { text-align: end; }
@media (min-width: 40rem) {
	.session-pager { grid-template-columns: 1fr 1fr; }
	.session-pager-newer:only-child { grid-column: 2; }
}

/* Video embed — aspect-ratio on the wrapper, not hardcoded width/height on
 * the <video> tag itself, since real recording dimensions aren't
 * standardised yet. Deliberately backend-agnostic (see partials/video-embed.html).
 */
.video-wrap {
	aspect-ratio: 16 / 9;
	background: var(--aard-card-background-color);
	border-radius: var(--aard-border-radius, 0.25rem);
	overflow: hidden;
	margin: 1.5em 0;
}

.video-wrap video {
	width: 100%;
	height: 100%;
	display: block;
	object-fit: contain;
	background: #000;
}

.breadcrumb ul {
	list-style: none;
	display: flex;
	flex-wrap: wrap;
	margin: 0 0 1em;
	padding: 0;
	font-size: 0.85em;
	color: var(--aard-muted-color);
}

.directory-submission-form {
	display: grid;
	gap: 0.75em;
	max-width: 32rem;
}

/* ---- Forms (aardforms) ----
 * aardCSS draws field borders in a pale grey (about 1.3:1 on the page), under the
 * 3:1 a field's outline needs (WCAG 1.4.11). The muted text colour passes in both
 * modes. Labels wrap their fields, so the gap between fields comes from the label.
 * aardCSS's focus is a faint 0.3-alpha halo, so inputs get a solid ring as well. */
.aardform {
	--aard-form-element-border-color: var(--aard-muted-color);
	--aard-border-width: 2px;
	--form-error: light-dark(#b42318, #ff8a80);
}
.aardform :is(input, select, textarea) { font-size: inherit; margin-top: 0.25em; }
.aardform label { font-weight: 700; }
.aardform textarea { resize: vertical; }
.aardform :is(input, select, textarea):focus-visible {
	outline: 3px solid var(--aard-primary);
	outline-offset: 2px;
}
/* Only after the visitor has touched a field, so an untouched form isn't all red. */
.aardform :is(input, select, textarea):user-invalid { --aard-border-color: var(--form-error); border-color: var(--form-error); }
.aardform .form-notice,
.aardform .form-use { margin: 0; }
.aardform .form-use small { font-size: 0.875em; } /* --bs-step--1 caps at 1rem = body size on wide screens */
/* Turnstile takes no room unless it asks for a click (aardTurnstileAsk in form-end.html). */
.aardform .cf-turnstile:not(.is-asking) { height: 0; overflow: hidden; }
.aardform .cf-turnstile.is-asking { margin-block-end: 1em; }
.form-error { color: var(--form-error, light-dark(#b42318, #ff8a80)); font-weight: 700; }
.form-success { font-weight: 700; }
/* Success pop-up (aardforms.js): aardCSS's dialog > article, kept to a short card. */
.form-thanks > article { max-width: 26rem; text-align: center; }
.form-thanks > article > footer { text-align: center; }

/* ---- Hero ----
 * Ported from the live pre-Hugo site's homepage/directory hero
 * (output-spoonies-A-css-teardown.md §2, §4) — .hero-title/.hero-sub were
 * already declared above (in the .font-display rule) but had no markup
 * using them anywhere in the Hugo build until this pass.
 */
.hero {
	position: relative;
	padding: clamp(2.5rem, 5vw, 4.5rem) 0 clamp(2rem, 4vw, 3rem);
	z-index: 1;
	text-align: center;
}

/* ---- Flash (promo sticker) ----
 * Image sticker in the hero, driven by `flash` in data/homepage.yaml.
 * Static and centred on phones; from 48rem it sits in the hero's right-hand
 * side, vertically centred.
 *
 * `.hero` reserves a right-hand gutter the same width as the sticker (same
 * clamp() value), so the centred title and intro sit in a narrower box and
 * can't run under it at any viewport width. The hero text is therefore
 * centred within that column, slightly left of the full hero's centre.
 * Because horizontal overlap is impossible, the sticker's vertical position
 * is purely visual.
 *
 * The gutter is scoped with `.hero:has(.flash)` so it only exists while the
 * sticker is in the markup. `flash` in data/homepage.yaml stops rendering
 * after its `until` date, and the hero then returns to full-width centred
 * with no CSS changes.
 */
.flash {
	display: block;
	width: 9rem;
	margin: 0 auto 1.75rem;
	transform: rotate(-8deg);
	transition: transform 0.15s ease;
}

.flash img {
	display: block;
	width: 100%;
	height: auto;
}

.flash:hover,
.flash:focus-visible {
	transform: rotate(-3deg) scale(1.06);
}

/* `relative` anchors .flash-tag on phones; desktop's `absolute` below still
 * wins and anchors it just the same. */
.flash {
	position: relative;
}

/* ---- Flash ticket ----
 * "Tickets" stub hanging off the sticker's bottom-left, with a hand-drawn
 * cursor pointing up-right into the image. Sits on the LEFT so it can't run
 * off the hero's right edge (the sticker is flush right from 48rem).
 *
 * The notched ends are a mask on .flash-ticket only, so the cursor (a
 * sibling) isn't clipped by it. Teal fill is the dark-mode spark value used
 * in both modes: navy on #00b8a0 is 7.71:1, and a mid teal still has an
 * edge on the light-mode white, where --aard-spark-background wouldn't. */
.flash-tag {
	position: absolute;
	left: -1.25rem;
	bottom: -0.75rem;
	/* Counters most of .flash's -8deg so the stub sits near level. */
	rotate: 5deg;
}

.flash-ticket {
	--notch: 0.45rem;
	position: relative;
	display: block;
	padding: 0.35rem 1.1rem;
	background: #00b8a0;
	color: #040e1c;
	font-family: 'Righteous', cursive;
	font-size: 1rem;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	white-space: nowrap;
	mask:
		radial-gradient(circle at 0 50%, #0000 var(--notch), #000 calc(var(--notch) + 0.5px)) left / 51% 100% no-repeat,
		radial-gradient(circle at 100% 50%, #0000 var(--notch), #000 calc(var(--notch) + 0.5px)) right / 51% 100% no-repeat;
}

/* Inner printed border, like the mock-up's stub line. */
.flash-ticket::before {
	content: '';
	position: absolute;
	inset: 0.2rem 0.6rem;
	border: 1.5px solid currentColor;
	opacity: 0.45;
}

/* Drawn pointing up-left (a normal cursor), then mirrored to point up-right
 * at the sticker. Stroke is the page text colour so it reads in both modes. */
.flash-cursor {
	position: absolute;
	top: -2.2rem;
	right: -2.6rem;
	width: 3.2rem;
	height: 3.2rem;
	scale: -1 1;
	/* Brand cyan in both modes: pops against the red lips and navy, where
	   the old pale mint vanished into the sticker's white teeth. The hard
	   navy shadow echoes .btn-marker's offset outline. */
	fill: #00c8e8;
	stroke: var(--aard-color);
	stroke-width: 2.75;
	filter: drop-shadow(2px 2px 0 #040e1c);
	stroke-linejoin: round;
	stroke-linecap: round;
	overflow: visible;
}

.flash-cursor-spark {
	fill: none;
}

/* Nudge the ticket (not the sticker) a few times after load, then stop:
 * noticeable, not nagging. Off entirely under reduced motion. */
@media (prefers-reduced-motion: no-preference) {
	.flash-tag {
		animation: flash-nudge 5s ease-in-out 1.5s 3;
	}

	.flash:hover .flash-tag,
	.flash:focus-visible .flash-tag {
		animation: none;
	}
}

@keyframes flash-nudge {
	0%, 85%, 100% { rotate: 5deg; }
	89% { rotate: 12deg; }
	93% { rotate: -1deg; }
	97% { rotate: 8deg; }
}

@media (min-width: 48rem) {
	.hero:has(.flash) {
		padding-right: clamp(9rem, 16vw, 13rem);
	}

	.flash {
		position: absolute;
		top: 50%;
		right: 0;
		width: clamp(9rem, 16vw, 13rem);
		margin: 0;
		transform: translateY(-50%) rotate(-8deg);
	}

	.flash:hover,
	.flash:focus-visible {
		transform: translateY(-50%) rotate(-3deg) scale(1.06);
	}
}

/* ---- Background wordmark field ----
 * Replaces the old site's photographic hero banner with a CSS-only oversized
 * wordmark instead — no image, no extra request. Repeated down the whole
 * page (not just the hero), each instance positioned/rotated/coloured
 * differently by layouts/index.html — the standard smolweb/indie-web "giant
 * faint type as backdrop" trick; nothing in snippets-and-tools.md covers
 * this specific pattern (checked).
 *
 * overflow: clip here, not on individual sections — the text is wider
 * than the viewport by design (nowrap), and different `left` offsets per
 * instance are what let each repeat crop a different slice of it.
 *
 * z-index: -1 on .hero-bg-text sinks it below the page's real (static-flow)
 * content — a positioned element still paints above static siblings at the
 * same z-index otherwise, regardless of DOM order. .bg-text-field itself is
 * NOT given its own z-index, deliberately: it stays out of forming a new
 * stacking context so its children's -1 compares directly against
 * .has-ambient-bg::before's existing -1, in whatever context already
 * existed, rather than trapping either behind the other.
 */
.bg-text-field {
	position: relative;
	/* clip, not hidden: overflow-x:hidden forces overflow-y:auto, so the
	   parallax translateY overflowing the bottom made a scrollbar appear. */
	overflow: clip;
}

.hero-bg-text {
	position: absolute;
	z-index: -1;
	margin: 0;
	width: max-content;
	font-family: 'Righteous', cursive;
	font-size: clamp(3.5rem, 10vw, 8rem);
	line-height: 1;
	letter-spacing: 0.04em;
	white-space: nowrap;
	color: var(--aard-primary);
	opacity: 0.08;
	pointer-events: none;
	-webkit-user-select: none;
	user-select: none;
	/* base transform only — site.js overwrites this on scroll to add the
	   parallax offset and this element's own rotation (data-rot), keeping
	   this -50%/-50% centring on its top/left anchor point either way. */
	transform: translate(-50%, -50%);
}

/* Accent-coloured variant of .hero-bg-text, a bit stronger than the plain one. */
.hero-bg-text-gradient {
	color: var(--aard-accent);
	opacity: 0.16;
}

/* .hero h1 (aard.css's own hero component, specificity 0,1,1) beats a bare
 * .hero-title (0,1,0) and was quietly winning with its own smaller clamp()
 * — .hero-title's intended size never actually rendered. Matching the
 * selector shape (.hero h1.hero-title, 0,2,1) makes this override win. */
.hero h1.hero-title {
	font-size: var(--bs-step-5);
	letter-spacing: -0.03em;
	line-height: 1.05;
	margin: 0 0 0.5em;
}

.hero-sub {
	font-size: var(--bs-step-1);
	color: var(--aard-muted-color);
	max-width: 42rem;
	/* margin: 0 auto, not margin: 0 — .hero-sub has a max-width, so it needs
	   auto side margins to stay centred once the viewport is wider than the
	   max-width. Without this it just left-aligns at 42rem past that point,
	   which only looked centred by coincidence at typical review widths. */
	margin: 0 auto;
}

/* Ambient background — "deep ocean, not bruise" (teardown §4). Three fixed
 * radial gradients behind page content, cyan/pink/deep-blue. Dark mode is a
 * direct port of the live site's values (that's what they were tuned
 * against); light mode uses the same geometry at a much lower alpha so the
 * effect reads as texture, not murk, against a white page. Only on pages
 * that opt in via .has-ambient-bg (homepage, Directory index) — the live
 * site scoped it to index.html/directory.html only, not every page. */
.has-ambient-bg {
	position: relative;
}

.has-ambient-bg::before {
	content: '';
	position: fixed;
	inset: 0;
	background:
		radial-gradient(ellipse 80% 60% at 10% 20%, light-dark(rgba(0,95,125,0.05), rgba(0,200,232,0.12)) 0%, transparent 60%),
		radial-gradient(ellipse 60% 50% at 90% 80%, light-dark(rgba(174,0,99,0.04), rgba(255,77,166,0.10)) 0%, transparent 60%),
		radial-gradient(ellipse 50% 40% at 50% 50%, light-dark(rgba(0,95,125,0.03), rgba(0,100,160,0.08)) 0%, transparent 70%);
	pointer-events: none;
	z-index: -1;
}

/* ---- KOKO banner ----
 * "Keep On Keeping On" — the Wheely Happy MrsVark mantra. The heading gets
 * its highlighter swipe from the shared .highlight rule above.
 */
.koko-banner {
	text-align: center;
	padding: clamp(2.5rem, 5vw, 4rem) 1.5rem;
	/* Plain fallback first: browsers without light-dark() image support
	 * (before Chrome/Firefox 150, Safari 27) drop the gradient below as
	 * invalid and use this instead. */
	background: var(--aard-card-sectioning-background-color);
	background: light-dark(
		linear-gradient(135deg, rgba(0,95,125,0.05), rgba(174,0,99,0.05)),
		linear-gradient(135deg, rgba(0,200,232,0.08), rgba(255,77,166,0.08))
	);
	border-top: 1px solid var(--aard-primary-border);
	border-bottom: 1px solid var(--aard-primary-border);
	margin: clamp(2rem, 5vw, 3.5rem) 0;
}

.koko-text {
	font-size: var(--bs-step-4);
	letter-spacing: -0.02em;
	margin: 0 0 0.4em;
}

.koko-sub {
	color: var(--aard-muted-color);
	margin: 0;
}

/* ---- Hero/footer widgets — functional styling only ----
 * Hover-to-reveal tooltip and fixed-position scroll button are behavioural,
 * not cosmetic — without this CSS the widgets don't work as specced. Full
 * visual treatment is deferred to the post-launch style retrofit (see
 * day2-playbook-2026-09-04.md Step 1).
 */
.spoon-counter-wrap {
	position: relative;
	display: inline-block;
	cursor: default;
	margin-top: 1.5rem;
}

.spoon-counter-tooltip {
	position: absolute;
	bottom: 100%;
	left: 50%;
	transform: translateX(-50%);
	white-space: nowrap;
	padding: 0.5em 0.8em;
	background: var(--aard-primary-border);
	/* Brand navy on both fills: pale blue in light mode, bright cyan in dark.
	 * The inherited near-white text was 1.9:1 on the dark-mode cyan. */
	color: #040e1c;
	border-radius: 0.4em;
	opacity: 0;
	pointer-events: none;
	transition: opacity 0.15s ease;
}

.spoon-counter-wrap:hover .spoon-counter-tooltip {
	opacity: 1;
}

/* Messages run ~540-570px and the tooltip is centred on the counter, which
 * the hero's sticker column pushes off-centre between ~640 and ~1000px: they
 * clip on phones and at tablet width. Below 1024px let them wrap, capped at
 * 22rem so even the off-centre case stays on screen (1024px+ already fits,
 * left as it was). The explicit max-content width stops the absolutely-
 * positioned box shrinking to the narrow counter's width (left:50% leaves it
 * little room to size into). */
@media (max-width: 1023px) {
	.spoon-counter-tooltip {
		white-space: normal;
		width: max-content;
		max-width: min(90vw, 22rem);
	}
}

.scroll-top {
	position: fixed;
	right: 1.5rem;
	bottom: 1.5rem;
	z-index: 10;
	opacity: 0;
	pointer-events: none;
	transition: opacity 0.15s ease;
	border-radius: 50%;
	width: 2.75rem;
	height: 2.75rem;
	font-size: 1.3rem;
	line-height: 1;
}

.scroll-top.visible {
	opacity: 1;
	pointer-events: auto;
}

/* ---- Section label ----
 * The "kicker" line above each homepage section heading (Our Story, Find
 * Your People, etc). No purpose-built element for this in HTML or aardCSS —
 * `.text-meta` (small print) was being misused for it, which is both the
 * wrong semantic and renders smaller than body text, the opposite of what a
 * kicker needs. `<p class="section-label">` is the same pattern this
 * codebase already uses for a smaller-scoped eyebrow (.directory-card-eyebrow
 * above) — just sized for section level.
 */
.section-label {
	font-size: var(--bs-step--1);
	font-weight: 800;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--aard-accent);
	margin-bottom: 0.4em;
}

/* aardCSS gives any heading that follows a <p> (or article/blockquote/ul/etc)
 * extra top margin — sensible for a heading breaking up body text, wrong
 * here: the label and the heading it introduces should sit close together.
 * See aard.css: `:where(p, ...) ~ :is(h1, h2, ...) { margin-top: ... }`. */
.section-label + :is(h1, h2, h3, h4, h5, h6) {
	margin-top: 0;
}

/* Card icon — an inline stroke SVG (partials/icon.html) above a card title
 * (Join cards, Team cards). It takes its colour from `color`, so it themes
 * like text. Emoji don't work here: every OS draws them differently, and
 * some vanish in light mode. `.card-icon + h3` handles the same "heading
 * follows a <p>, aardCSS adds a big top margin" issue as .section-label
 * above, just for h3s inside cards. */
.card-icon {
	color: var(--aard-primary);
	margin-bottom: 0;
}

.card-icon svg {
	width: 2rem;
	height: 2rem;
}

/* The featured team-member intro uses a larger icon than card icons. */
.card-icon.icon-lg svg {
	width: 4rem;
	height: 4rem;
}

.card-icon + h3 {
	margin-top: 0;
}

/* ---- Our Story image frame ----
 * Rounded corners + a slow-drifting gradient border, in place of the old
 * site's plain square image. True `border-image` can't follow
 * `border-radius` (see snippets-and-tools.md, "Animated border-image
 * accents") — this gets the same "moving gradient ring" feel while staying
 * fully rounded, via a gradient background showing through padding instead
 * of an actual border-image. The member-count badge overlaps the bottom-right
 * corner, matching the old site's pill-on-image layout.
 */
.about-img-frame {
	/* align-self: center — without it, a CSS Grid item stretches to the row's
	   full height by default, so the frame grew to match the taller text
	   column and the gradient "border" background showed through as a solid
	   block wherever the image (sized to its own aspect ratio) didn't reach.
	   Centered rather than top-aligned so the frame sits mid-height against
	   the text column instead of pinned to its top edge. */
	align-self: center;
	position: relative;
	max-width: 26rem;
	margin: 0 auto;
	padding: 8px;
	border-radius: 1.25rem;
	background: linear-gradient(120deg, var(--aard-primary), var(--aard-accent), var(--aard-primary));
	background-size: 200% 200%;
	animation: about-img-border-flow 8s ease infinite;
}

@keyframes about-img-border-flow {
	0%, 100% { background-position: 0% 50%; }
	50%      { background-position: 100% 50%; }
}

.about-img-frame img {
	display: block;
	width: 100%;
	border-radius: calc(1.25rem - 8px);
}

.about-img-frame .badge {
	position: absolute;
	right: -0.75rem;
	bottom: -0.75rem;
}

/* Our Story grid — image column at roughly a third, not the default .grid
 * 50/50 split, so the text has more room. Falls back to .grid's own single
 * column below 768px. */
@media (min-width: 768px) {
	.about-grid {
		grid-template-columns: 1fr 2fr;
	}
}

/* ---- Support Hub image frame ----
 * Same stretch fix as .about-img-frame (grid items stretch to the row's
 * full height by default, which the image's own aspect ratio doesn't fill) —
 * but plain rounded corners + border here, no animated gradient/badge, this
 * image sits in an even 50/50 grid rather than the narrower Our Story one.
 */
.directory-img-frame {
	align-self: center;
	border-radius: 1rem;
	border: 1px solid var(--aard-primary-border);
	overflow: hidden;
}

.directory-img-frame img {
	display: block;
	width: 100%;
}

/* ---- Rocky Horror landing page (layouts/_default/rocky.html) ---- */
.rocky-hero {
	text-align: center;
	padding: clamp(2rem, 5vw, 4rem) 1rem;
	background: radial-gradient(ellipse at top, rgba(225, 6, 0, 0.25), transparent 70%);
}

.rocky-hero {
	position: relative;
}

/* Live text in Creepster, replacing the film's logo image. Fixed red in both
 * modes (the hero glow's own red): 4.9:1 on white, 3.9:1 on navy, which
 * clears AA for text this large. `width: 100%` keeps the box a full 50rem
 * so .rocky-star's offset below still lines up with its left edge. */
.rocky-title {
	width: 100%;
	max-width: 50rem;
	margin: 0 auto;
	font-family: 'Creepster', var(--aard-font-family);
	font-weight: 400;
	font-size: clamp(2.75rem, 9vw, 5.5rem);
	line-height: 1;
	letter-spacing: 0.02em;
	color: #e10600;
	text-wrap: balance;
}

.rocky-lips {
	display: block;
	width: 100%;
	height: auto;
}

.rocky-lips {
	max-width: 24rem;
	margin: 0 auto 1.5rem;
}

.rocky-star {
	width: clamp(6rem, 16vw, 11rem);
	height: auto;
	margin: 0 auto 0.5rem;
	transform: rotate(-8deg);
}

/* Between 60rem and 80rem, `right: calc(50% + 25rem + 1rem)` (below) still
   pins the star correctly relative to .rocky-title, but the hero itself
   isn't wide enough yet to hold both — the star's own left edge lands at a
   negative offset and it spills out past the container onto the page
   background (found by Paul, screenshotted at ~1024px). Rather than
   shrinking it further and squeezing it into an ever-smaller gap, hide it
   in that band: at this width there isn't really room for a corner
   decoration without crowding the title, so it's better absent than
   overflowing. */
@media (min-width: 60rem) and (max-width: 79.9375rem) {
	.rocky-star {
		display: none;
	}
}

@media (min-width: 80rem) {
	/* Was overlapping the "T" of the title image: positioned with left:0
	   relative to the whole hero, so it only cleared .rocky-title (max-width
	   50rem, centred) on viewports wide enough to leave a gutter bigger than
	   the star itself — not true at ~1366px, where the gutter is narrower
	   than the star's clamp() max. `right` pins the star's edge a fixed 1rem
	   outside the title's own left edge instead, which holds regardless of
	   how wide the hero itself is. Confirmed clear (star's own left edge
	   stays positive) from 80rem up. */
	.rocky-star {
		position: absolute;
		top: -0.5rem;
		right: calc(50% + 25rem + 1rem);
		width: clamp(5rem, 8vw, 7rem);
		margin: 0;
	}
}

.rocky-tagline {
	font-family: 'Barriecito', var(--aard-font-family);
	font-size: var(--bs-step-2);
	margin: 0.25em 0 1em;
}

.rocky-subtagline {
	color: var(--aard-muted-color);
	margin: -0.5em 0 1em;
}

.rocky-when {
	font-size: var(--bs-step-1);
	font-weight: 800;
	margin: 0;
}

.rocky-where {
	color: var(--aard-muted-color);
}

.rocky-badges {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	justify-content: center;
}

.rocky-cta {
	text-align: center;
	margin-top: 2rem;
}

/* The date, venue and ticket button need to be visible without scrolling on
   the first screen, at every width — but the original document order (star,
   title, tagline, lips, when, where, button) put the button below the fold
   at 360x640, 390x844 and even 1366x900, because the lips image sat between
   the tagline and the actual event facts. Reorder unconditionally (an
   absolutely-positioned .rocky-star at 60rem+ isn't part of flex flow, so
   this doesn't disturb its own positioning above) so the lips — decorative,
   not load-bearing information — drop after the button instead of before
   it, on every size. */
.rocky-hero {
	display: flex;
	flex-direction: column;
	align-items: center;
}
.rocky-star { order: 1; }
.rocky-title { order: 2; }
.rocky-tagline { order: 3; }
.rocky-subtagline { order: 4; }
.rocky-when { order: 5; }
.rocky-where { order: 6; }
.rocky-hero-cta { order: 7; }
.rocky-lips { order: 8; }
.rocky-badges { order: 9; }

/* Below 60rem, also shrink the star and the lips so the reordered stack is
   shorter, not just rearranged — phones don't have 1366px-worth of vertical
   room to spare even with the button moved up. */
@media (max-width: 59.9375rem) {
	.rocky-star {
		width: clamp(3rem, 12vw, 4.5rem);
		margin-bottom: 0.25rem;
	}
	.rocky-where {
		margin-bottom: 0.5rem;
	}
	.rocky-lips {
		max-width: 10rem;
		margin: 1.5rem auto 0;
	}
}

/* ---- Tap targets ----
 * Padding on the "Show QR code" <summary>, the AarDHD platform links and the
 * small-print footer links grows the tap target (WCAG 24px minimum) without
 * changing the visible text size.
 */
details summary {
	padding: 0.5em 0;
	min-height: 44px;
}

.alert-link {
	display: inline-block;
	padding: 0.5em 0.4em;
}

.footer-meta a,
.business-contact a {
	display: inline-block;
	padding: 0.5em 0.25em;
}

/* Mobile "Home" nav dropdown (see nav.html): aardCSS sizes the submenu to
 * its trigger ("Home"), which is too narrow for "What We Stand For". This
 * gives it room for its longest item. */
@media (max-width: 639px) {
	nav .navbar-menu details.dropdown > summary + ul {
		min-width: 14rem;
	}
}

/* Archive search page. */
.search-page input[type="search"] { width: 100%; max-width: 46rem; }
.search-count { color: var(--aard-muted-color); min-height: 1.5em; }
.search-results { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.6rem; max-width: 46rem; }
.search-results a {
	display: grid;
	gap: 0.2rem;
	padding: 0.8rem 1.25rem;
	min-height: 44px;
	border: 1px solid var(--session-line);
	border-radius: 1rem;
	background: var(--aard-card-background-color);
	color: inherit;
	text-decoration: none;
	transition: border-color 0.2s, box-shadow 0.25s var(--session-ease);
}
.search-results a:hover, .search-results a:focus-visible { border-color: var(--aard-primary); box-shadow: 0 18px 32px -20px var(--session-shadow); }
.search-results b { overflow-wrap: anywhere; }
.search-results time, .search-results small { color: var(--aard-muted-color); overflow-wrap: anywhere; }
.search-results time { font-size: 0.85rem; }
.session-search-link { margin: 0.9rem 0 0; font-weight: 700; }
.search-results > li { list-style: none; }
.search-page input[type="search"] { border-radius: 0.75rem; }
.session-search-link a { display: inline-block; padding-block: 0.6rem; }
