/*
Theme Name: The English Concert
Theme URI: https://englishconcert.co.uk
Description: GeneratePress child theme for The English Concert. Defines TEC's design tokens (colours, typography, container width) via theme.json and loads the Adobe Fonts Typekit kit.
Author: The English Concert
Template: generatepress
Version: 0.3.8
Text Domain: tec
*/

/* Hide page title on the front page only.
   Block-built homepages provide their own hero heading. */
body.home .entry-header {
	display: none;
}

/* Italic utility — replaces 6 inline `style="font-style:italic"` instances
   on no-results paragraphs across patterns. Added 2026-05-05 (Holt
   quick-win pass). Pure utility; no scoped contract. */
.tec-text-italic {
	font-style: italic;
}

/* Apply TEC font families to headings.
   theme.json registers the families and palette but GeneratePress's
   own stylesheet wins on element styles, so we re-state them here. */
body,
body p,
body li,
body .entry-content {
	font-family: "objektiv-mk1", "Objektiv Mk1", "Helvetica Neue", Arial, sans-serif;
	color: var(--wp--preset--color--charcoal, #31393C);
}

/* Re-assert body type scale at the child layer.
   GeneratePress parent ships `body { font-size: 17px; line-height: 1.5; }`
   which outranks WP's theme.json-generated body rule. Child stylesheet
   declares `generate-style` as a dependency so it loads after parent —
   source-order tiebreaker wins. Per Alfonso 2026-05-02. */
body {
	font-size: var(--wp--preset--font-size--medium);
	line-height: 1.6;
}

/* H1 stays at weight 400 (Orpheus Pro Regular master).
   H2 lifts to weight 500 (Orpheus Pro Medium master) to match prod's
   visual heaviness — the 500 woff2 is self-hosted in /assets/fonts/
   and declared in /assets/css/fonts.css. Splitting the rule prevents
   the H1/H2 shared declaration from stamping H2 back to 400 and beating
   theme.json's `:where(h2)` element style.
   Per Alfonso 2026-05-02. */
h1,
.entry-content h1,
.editor-styles-wrapper h1 {
	font-family: "orpheuspro", "Orpheus Pro", Georgia, serif;
	font-weight: 400;
	line-height: 1.15;
}

h2,
.entry-content h2,
.editor-styles-wrapper h2 {
	font-family: "orpheuspro", "Orpheus Pro", Georgia, serif;
	font-weight: 500;
	line-height: 1.15;
}

h3, h4, h5, h6,
.entry-content h3, .entry-content h4, .entry-content h5, .entry-content h6,
.editor-styles-wrapper h3, .editor-styles-wrapper h4,
.editor-styles-wrapper h5, .editor-styles-wrapper h6 {
	font-family: "objektiv-mk3", "Objektiv Mk3", "Helvetica Neue", Arial, sans-serif;
	font-weight: 700;
	line-height: 1.3;
}

/* H2/H3 size — pin to ramp tokens. GeneratePress parent ships
   `h1{font-size:42px} h2{font-size:35px} h3{font-size:29px}` in
   main.min.css which beats theme.json's `styles.elements.*`
   (parent's plain `h2`/`h3` selectors outrank the `:root :where(h2)`
   wrapper WP emits for element styles). H1 is in practice always
   wrapped in a class-bearing selector that wins, so we don't restate
   it. Restating h2/h3 here re-establishes the `x-large` (31px) and
   `large` (23px) Perfect Fourth tokens as the source of truth.
   Per Alfonso 2026-05-02. */
h2,
.entry-content h2,
.editor-styles-wrapper h2 {
	font-size: var(--wp--preset--font-size--x-large);
}
h3,
.entry-content h3,
.editor-styles-wrapper h3 {
	font-size: var(--wp--preset--font-size--large);
}

a {
	color: var(--wp--preset--color--accent-yellow, #C68F02);
}
a:hover {
	color: var(--wp--preset--color--navy, #052f67);
}

/* ---------------------------------------------------------------
   Single Musician template — structural CSS only.

   Per Alfonso 2026-05-01: visual polish is parked. The rules below
   exist so the template *renders sensibly* — they do not restyle
   buttons, eyebrows, or hero typography. Polish lands in a later pass.
   --------------------------------------------------------------- */

/* Header band — clean "chapter heading": eyebrow (voice/instrument) + H1.
 * The 3:4 portrait was relocated into the biography band on 2026-05-04
 * (Holt per Alfonso).
 *
 * Eyebrow update (Holt 2026-05-02 per Alfonso, taxonomy migration 2026-05-04):
 * the eyebrow is bound to the musician's `instrument` taxonomy via the
 * `tec/musician-instrument` block-binding source (legacy `voice_or_instrument`
 * ACF field removed 2026-05-04). When no terms are assigned the binding
 * resolves to an empty string; the rule below hides the resulting empty
 * paragraph so the H1 sits flush against the band's vertical centre rather
 * than offset by a dead eyebrow row. The previously-empty role paragraph
 * below the H1 has been removed from patterns/musician-header.php. */
.tec-musician-header .tec-eyebrow--header:empty {
	display: none;
}

/* Biography band — 67/33 columns. Bio prose left, 3:4 portrait right.
 * The outer band container is the content tier (1200px); prose inside
 * the 67% column is further pinned to --tec-width-prose by the rule
 * below so reading-line length stays comfortable.
 *
 * Empty featured image → portrait column collapses; prose then occupies
 * the full content width via :has() on the columns wrapper. */
.tec-musician-bio__columns {
	gap: var(--wp--preset--spacing--50, 2rem);
}
.tec-musician-bio__portrait .wp-block-post-featured-image:empty,
.tec-musician-bio__portrait .wp-block-post-featured-image:not(:has(img)) {
	display: none;
}
/* When the musician has no featured image, hide the portrait column so
 * the prose column expands to the full content tier. */
.tec-musician-bio__columns:has(.tec-musician-bio__portrait .wp-block-post-featured-image:empty) .tec-musician-bio__portrait,
.tec-musician-bio__columns:has(.tec-musician-bio__portrait .wp-block-post-featured-image:not(:has(img))) .tec-musician-bio__portrait {
	display: none;
}

/* 3:4 editorial portrait. Replaces the legacy circular crop per Linnea's
 * People Imagery audit (Alternative 1, sign-off Alfonso 2026-05-04).
 * Existing square photo masters fit the 3:4 frame via object-fit:cover;
 * re-cropping from originals is the editorial polish step (content
 * work, not dev scope). */
.tec-musician-portrait img {
	aspect-ratio: 3 / 4;
	object-fit: cover;
	inline-size: 100%;
	block-size: auto;
	display: block;
}

/* Mobile stack — portrait first, then prose. Visitor sees the musician
 * before reading the bio (programme-book convention). The `!important`
 * on flex-basis is load-bearing: core/column emits an inline
 * `style="flex-basis:66.66%"` from the JSON `width` attribute, so pure
 * CSS specificity loses to the inline declaration. The only reduction
 * path is to drop the column width entirely and own the desktop split
 * via CSS, which is a larger refactor (Holt 2026-05-02). */
@media (max-width: 766px) {
	.tec-musician-bio__columns {
		flex-wrap: wrap;
	}
	.tec-musician-bio__columns .wp-block-column {
		flex-basis: 100% !important;
	}
	.tec-musician-bio__portrait {
		order: -1;
	}
}

/* Hero min-height — single-source-of-truth via custom property.
 * Event hero is shorter (420px) than Work hero (480px) by intent —
 * Work pages need to absorb the additional meta line (composer · year ·
 * language · libretto). Both consume `--tec-hero-min-height`. */
.tec-event-header { --tec-hero-min-height: 420px; }
.tec-work-hero    { --tec-hero-min-height: 480px; }
.tec-event-header,
.tec-work-hero {
	min-height: var(--tec-hero-min-height);
}

/* Biography band — comfortable reading width inside the 67% prose column
 * (~800px at the 1200px content tier). Pin to the prose tier (680px) —
 * the bio is long-form single-column text. */
.tec-musician-bio .wp-block-post-content > p,
.tec-musician-bio > p {
	max-width: var(--tec-width-prose);
}

/* Events band — uses the canonical tec/event-card pattern (image right, text
 * left, top-aligned) wrapped in the same vertical-flex post-template grid as
 * /events/upcoming. Grid layout rule below extends .tec-events-archive-grid to
 * the musician-events context. Card-internal responsive behaviour (horizontal
 * at md+, vertical at sm-) is owned by the canonical .tec-event-card rules
 * further down in this file — no per-context overrides needed. */

/* ===================================================================
   Musicians archive — structural CSS only.

   Per Alfonso 2026-05-01: visual polish parked. Rules below exist so
   the archive renders sensibly across breakpoints. They do NOT restyle
   names, set custom colours, or polish the initials fallback beyond
   what's strictly needed to make it not look broken.
   =================================================================== */

/* Page-level wrapper — width comes from the canonical tec-band/tec-band-inner
 * primitives now; vertical rhythm comes from bands.css. The 2026-05-08 header
 * + filter sweep moved the H1 + intro into the navy header band rendered by
 * archive-musician.php, so the .tec-musicians-archive__title /
 * .tec-musicians-archive__intro hooks are no longer emitted by the pattern.
 * Their selectors were retired alongside that change. */
.tec-musicians-archive {
	width: 100%;
}

/* Grid responsive recipe owned by .tec-grid--4up in tokens.css.
 * The pattern emits .tec-grid + .tec-grid--4up alongside the legacy
 * .tec-musicians-archive__grid hook, and wp:post-template's columnCount=4
 * sets the desktop track count inline — no !important arms race. */

/* ----------------- Card ----------------- */
.tec-musician-card {
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
}

.tec-musician-card__portrait img,
.tec-musician-card .wp-block-post-featured-image img {
	width: 100%;
	height: auto;
	aspect-ratio: 3 / 4;
	object-fit: cover;
	display: block;
}

.tec-musician-card__name {
	margin-top: 0.5rem;
	margin-bottom: 0;
	color: var(--wp--preset--color--navy, #052f67);
	line-height: 1.15;
}

.tec-musician-card__voice {
	margin-top: 0;
	color: var(--wp--preset--color--ink-low-emphasis, #555);
	font-family: var(--wp--preset--font-family--sans-body, "objektiv-mk1", sans-serif);
	letter-spacing: 0.02em;
}

/* Hide voice line cleanly when the ACF field is empty. */
.tec-musician-card__voice:empty {
	display: none;
}

/* ----------------- Initials fallback (3:4) ----------------- */
.tec-musician-card__portrait-fallback {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	height: 100%;
	aspect-ratio: 3 / 4;
	background: var(--wp--preset--color--surface-low, #f3f3f0);
	overflow: hidden;
}

/* .tec-initials utility (tokens.css) owns the initials typography. */

/* ----------------- Pagination -----------------
 * Canonical archive pagination — single source of truth.
 * Applied to:
 *   - .wp-block-query-pagination (Query Loop: press-blog, musicians, events, home)
 *   - .tec-archive__pagination > .nav-links (PHP the_posts_pagination(): recordings)
 *   - .tec-musicians-archive__pagination (modifier; same rules apply)
 *
 * Treatment mirrors prod (Toolset Views .archive-pagination on Cornerstone):
 * pill links with a 1px accent-yellow border, gold fill on hover/focus, the
 * current page rendered as a quiet grey-on-white pill, ellipsis as plain text.
 * Mobile (≤766px) keeps the prev/next anchors on a top row and lets the
 * numbers wrap below — same pattern prod uses at ≤979px.
 *
 * The Query Loop renders prev/next as separate <a> elements outside the
 * .wp-block-query-pagination-numbers wrapper; the_posts_pagination() inlines
 * them inside .nav-links with .next / .prev classes. Both use .page-numbers
 * on every numeric item, which is the unifying hook below.
 *
 * Holt 2026-05-02 — replaces prior per-archive paginator rules (the old
 * .tec-posts-archive .wp-block-query-pagination block and the
 * .tec-musicians-archive__pagination gap override).
 * --------------------------------------------------------------- */

/* Container — flex row, centred, wraps on small screens.
 * Two surfaces:
 *   - .wp-block-query-pagination is a single <nav> that is itself the flex row.
 *   - the_posts_pagination() wraps a <div class="nav-links"> inside an outer
 *     <nav class="tec-archive__pagination">; the flex row lives on .nav-links,
 *     while the outer nav owns the top margin and centring. */
.wp-block-query-pagination,
.tec-archive__pagination .nav-links {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	align-items: center;
	gap: 0.5rem;
}
.wp-block-query-pagination,
.tec-archive__pagination {
	margin-block-start: var(--wp--preset--spacing--60, 2.5rem);
}

/* Items — pill links + current span + prev/next anchors */
.wp-block-query-pagination .page-numbers,
.wp-block-query-pagination .wp-block-query-pagination-previous,
.wp-block-query-pagination .wp-block-query-pagination-next,
.tec-archive__pagination .nav-links .page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	padding-block: 0.35em;
	padding-inline: 0.75em;
	border: 1px solid var(--wp--preset--color--accent-yellow, #C68F02);
	border-radius: 0.35em; /* one-off — no matching radius token; flagged */
	background-color: transparent;
	color: var(--wp--preset--color--near-black, #08101B);
	font-size: 1rem;
	font-weight: 400;
	line-height: 1.25;
	text-decoration: none;
}

/* Hover / focus — gold fill, white text */
.wp-block-query-pagination a.page-numbers:hover,
.wp-block-query-pagination a.page-numbers:focus-visible,
.wp-block-query-pagination a.wp-block-query-pagination-previous:hover,
.wp-block-query-pagination a.wp-block-query-pagination-previous:focus-visible,
.wp-block-query-pagination a.wp-block-query-pagination-next:hover,
.wp-block-query-pagination a.wp-block-query-pagination-next:focus-visible,
.tec-archive__pagination .nav-links a.page-numbers:hover,
.tec-archive__pagination .nav-links a.page-numbers:focus-visible {
	background-color: var(--wp--preset--color--accent-yellow, #C68F02);
	color: var(--wp--preset--color--white, #fff);
}

/* Current page — quiet grey-on-white pill (prod's distinct treatment) */
.wp-block-query-pagination span.page-numbers.current,
.tec-archive__pagination .nav-links span.page-numbers.current {
	border-color: var(--wp--preset--color--white, #fefefe);
	background-color: var(--wp--preset--color--white, #fefefe);
	color: var(--wp--preset--color--ink-low-emphasis, #555);
}

/* Dots / ellipsis — unframed, just spacing */
.wp-block-query-pagination span.page-numbers.dots,
.tec-archive__pagination .nav-links span.page-numbers.dots {
	border-color: transparent;
	background-color: transparent;
	color: var(--wp--preset--color--ink-low-emphasis, #555);
	padding-inline: 0.25em;
}

/* Disabled prev/next (Query Loop renders the disabled end as a span) */
.wp-block-query-pagination span.wp-block-query-pagination-previous,
.wp-block-query-pagination span.wp-block-query-pagination-next {
	border-color: #aaa; /* one-off — no matching neutral token at this lightness; flagged */
	color: #aaa;
	cursor: not-allowed;
}

/* Mobile — keep usable when 12+ pages would otherwise crowd the row */
@media (max-width: 766px) {
	.wp-block-query-pagination,
	.tec-archive__pagination .nav-links {
		gap: 0.5rem;
	}
	.wp-block-query-pagination .page-numbers,
	.wp-block-query-pagination .wp-block-query-pagination-previous,
	.wp-block-query-pagination .wp-block-query-pagination-next,
	.tec-archive__pagination .nav-links .page-numbers {
		padding-block: 0.3em;
		padding-inline: 0.6em;
		font-size: 0.9375rem;
	}
}
/* ============================================================
 * Events archive — /events/
 * Upcoming (Query Loop) + past (PHP-rendered, year-grouped).
 * Both use the shared tec/event-card pattern.
 * ============================================================ */

.tec-events-archive-main {
	padding: 0;
}

/* Band rhythm — token-driven padding-block for both archive bands.
 * Matches single-event tightening: --spacing--50 desktop / --spacing--40 mobile.
 * Replaces inline padding previously emitted on the upcoming pattern wrapper
 * and the past-band <section>. */
.tec-events-archive-upcoming,
.tec-events-archive-past {
	padding-block: var(--wp--preset--spacing--50, 2rem);
}

@media (max-width: 766px) {
	.tec-events-archive-upcoming,
	.tec-events-archive-past {
		padding-block: var(--wp--preset--spacing--40, 1.5rem);
	}
}

/* ---------- Upcoming — single column, full-width stacked cards ----------
 * Consumes --tec-width-wide (1200px) so the archive's upcoming band shares
 * the same horizontal constraint as the homepage upcoming band — both surfaces
 * use the shared tec/event-card pattern inside an alignwide Query Loop.
 * (Holt 2026-05-03; previously capped at 800px as a card-stack exception,
 * superseded by Alfonso's directive to align /events/ with / on width.) */
.tec-events-archive-upcoming .wp-block-post-template.tec-events-archive-grid,
.tec-musician-events .wp-block-post-template.tec-events-archive-grid,
.tec-work-future-events .wp-block-post-template.tec-events-archive-grid,
.tec-production-events .tec-events-archive-grid {
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--50, 2rem);
	list-style: none;
	padding: 0;
	margin: 0;
	max-width: var(--tec-width-wide);
}

/* Past-events grid layout owned by .tec-grid--3up in tokens.css. */

/* The PHP-rendered past band wraps each card in a top-level
 * .tec-event-card; the upcoming Query Loop wraps it in <li>. Reset
 * any list affordance that wp:post-template adds. */
.tec-events-archive-upcoming .wp-block-post-template.tec-events-archive-grid > li,
.tec-musician-events .wp-block-post-template.tec-events-archive-grid > li,
.tec-work-future-events .wp-block-post-template.tec-events-archive-grid > li {
	margin: 0;
	padding: 0;
}

/* ---------- Year heading inside past band ---------- */
.tec-events-archive-past__year {
	border-bottom: 1px solid rgba(5, 47, 103, 0.15);
	padding-bottom: 0.5rem;
}

/* ---------- Card structural baseline ----------
 * Default: horizontal at md+ (image 33% / text 67%, gap spacing-50).
 * Stacks vertical at sm- (≤766px) to match prod mobile.
 * Past-grid forces vertical regardless of viewport — owned by consumer
 * context, per Linnea 2026-05-01.
 */
.tec-event-card {
	display: flex;
	flex-direction: row-reverse; /* image-first DOM + row-reverse = image-RIGHT at desktop, matches prod (Alfonso 2026-05-02) */
	align-items: stretch;
	gap: var(--wp--preset--spacing--50, 2rem);
	height: 100%;
}

/* Image column — one third at md+; full width when stacked */
.tec-event-card > .tec-event-card__hero {
	flex: 0 0 33%;
	margin: 0;
}

/* Text column wrapper — fills remaining space, vertical stack so buttons pin.
 * margin-top:0 clears the WP is-layout-flow block-gap that core injects on
 * non-first siblings; the card itself is flex, so vertical sibling margin is
 * meaningless and was offsetting the date below the image top edge by 24px
 * (Alfonso 2026-05-02). */
.tec-event-card__body {
	flex: 1 1 auto;
	display: flex;
	flex-direction: column;
	min-width: 0;
	margin-top: 0;
}

/* Stack vertical at sm and below (≤766px) — matches prod mobile */
@media (max-width: 766px) {
	.tec-event-card {
		flex-direction: column;
		gap: 0.5rem;
	}
	.tec-event-card > .tec-event-card__hero {
		flex: 0 0 auto;
		width: 100%;
	}
}

/* Past-events 3-up grid: cards too narrow for the horizontal default —
 * force vertical regardless of viewport. Past treatment is the visual
 * signal for "archive, not actionable" (no Buy Tickets button on the
 * past pattern).
 *
 * Holt 2026-05-08 (correction): the See-it-live band on Single Production
 * was briefly joined here on 2026-05-08am — that was wrong. Per Alfonso,
 * upcoming events on Single Production must render as horizontal cards
 * with Buy Tickets, identical to the /events/ archive's upcoming band.
 * Removed `.tec-production-events__list .tec-event-card` from this rule;
 * Single Production's See-it-live now uses the same flex-column wrapper
 * the archive uses (see `.tec-production-events .tec-events-archive-grid`
 * above) which stacks horizontal cards full-width. */
.tec-events-archive-past__grid .tec-event-card {
	flex-direction: column;
	gap: 0.5rem;
}
.tec-events-archive-past__grid .tec-event-card > .tec-event-card__hero {
	flex: 0 0 auto;
	width: 100%;
}

/* Card-internal eyebrow treatment is owned by `.tec-eyebrow--card` in
 * eyebrow.css (Stage 3 hygiene refactor). Patterns emit the modifier
 * directly on the eyebrow element; no descendant override needed. */

/* Gold horizontal rule between the eyebrow and the post title — a 1px
 * accent-yellow separator that visually divides the meta line from the
 * headline. Implemented as border-top on the title (no extra DOM) and
 * a small padding-top for breathing room. Owned by `.is-style-tec-card`
 * so every card variant (event, post, recording, video, plus the
 * event-card-horizontal sibling) inherits a single rule. Per Alfonso
 * 2026-05-02; canonicalised onto the block style 2026-05-04. */
.is-style-tec-card .wp-block-post-title,
.is-style-tec-card .tec-video-card__title {
	border-top: 1px solid var(--wp--preset--color--accent-yellow);
	/* padding-top compensates for Objektiv Mk3's top-heavy font metrics:
	 * USE_TYPO_METRICS is OFF for Mk3 so the title's line-box reserves ~2px
	 * of invisible leading above the cap-top. To make the visible gap below
	 * the line match the 12px flex-gap above it, padding-top is 14px (12px
	 * target + 2px leading compensation) — measured empirically via
	 * scripts/audit/measure-separator.js: above-line and below-line visual
	 * gaps both resolve to 12px (Alfonso 2026-05-01).
	 *
	 * The pattern uses `core/heading` (not `core/post-title`) for the
	 * tec/video-card title because WP 6.9.4's bindings allowlist excludes
	 * `core/post-title.content`. The `tec-video-card__title` selector is
	 * paired here so the gold-rule + padding apply uniformly across every
	 * is-style-tec-card consumer (event-card, post-card, recording-card —
	 * post-title; video-card — heading). Without this pairing, video-card
	 * titles render flush against the eyebrow with no separator and read
	 * as meta lines rather than titles — this is what Alfonso flagged as
	 * "the Library filtered cards are missing titles" (2026-05-07): the
	 * title text was rendering, but the editorial weight was not.
	 * Holt 2026-05-07. */
	padding-top: 0.875rem;
	line-height: 1.25;
}

/* Button row pinned to card foot — owned by `.is-style-tec-card` so every
 * card surface inherits a single rule (event, post, recording, video).
 * Hygiene refactor Holt 2026-05-02; canonicalised 2026-05-04. */
.is-style-tec-card .wp-block-buttons {
	margin-top: auto;
}

/* Editorial card-actions slot (mu-plugin tec-card-actions.php). The pattern
 * emits an empty <div class="tec-card-actions-slot"> as the last flex child;
 * the render_block filter replaces it with a `.wp-block-buttons.tec-card-actions`
 * row when ACF `card_actions` has rows, or removes it entirely when empty.
 * Empty-state collapse: the wrapping pattern group has the
 * placeholder removed at render, so it never reaches the DOM. The
 * `.tec-card-actions` row inherits `margin-top:auto` via the rule above
 * (it carries the `.wp-block-buttons` class), pinning it to the card foot.
 * Holt 2026-05-07. */
.tec-card-actions {
	row-gap: 0.5rem;
}
.tec-card-actions .wp-block-button__link {
	min-width: 0;
}
@media (max-width: 599px) {
	.tec-card-actions {
		flex-wrap: wrap;
	}
	.tec-card-actions .wp-block-button {
		flex: 1 1 100%;
	}
}

/* Button min-width — keeps "Get Tickets" / "Learn More" CTAs visually
 * substantial and consistent across both card surfaces. */
.tec-event-card .wp-block-button__link {
	min-width: 128px;
}

/* Mobile: button row stacks rather than truncates.
 * The pattern emits `flexWrap:"wrap"` (no inline override fighting this),
 * so plain `flex-wrap: wrap` wins on specificity — Stage 4 hygiene removed
 * the inline `flexWrap:"nowrap"` from event-card.php (Alfonso 2026-05-02). */
@media (max-width: 599px) {
	.tec-event-card .wp-block-buttons {
		flex-wrap: wrap;
	}
	.tec-event-card .wp-block-buttons .wp-block-button {
		flex: 1 1 100%;
	}
}
/* ============================================================
 * Single Event template — single-tec-events.php
 * Header (cover band) + body (the_content) + cast band (card grid).
 * ============================================================ */

/* ---------- Hero header band ---------- */
.tec-event-header {
	color: #ffffff;
}

.tec-event-header .wp-block-cover__inner-container {
	width: 100%;
	/* Vertical: spacing--60. Horizontal: --tec-gutter so the H1 left edge
	 * matches every other band on the single-event page (body, programme,
	 * cast, related). Was a fixed 1.5rem which mismatched the gutter
	 * clamp on body/programme by ~8px at desktop 1440 (Holt 2026-05-02). */
	padding-block: var(--wp--preset--spacing--60, 2.5rem);
	padding-inline: var(--tec-gutter);
}

/* Event-header eyebrow treatment owned by `.tec-eyebrow--header`. */

/* Hero stack — Linnea audit §5.1, Holt 2026-05-02:
 *   eyebrow status (binding tec/event-status, hidden when empty)
 *   ↓
 *   date+time lockup (binding tec/event-datetime, Orpheus italic, large)
 *   ↓
 *   H1
 *   ↓
 *   venue line (medium sans, white)
 *   ↓
 *   Get Tickets CTA
 *
 * The eyebrow uses the existing tec-eyebrow--header treatment; an empty
 * binding result hides it via the :empty rule below (mirrors the
 * tec-musician-header pattern). */

/* Hide eyebrow + datetime paragraphs when their bindings resolve empty.
 * Without this rule the header has dead vertical space when an event
 * has no event_status set or no date_and_time captured. */
.tec-event-header .tec-eyebrow--header:empty,
.tec-event-header .tec-event-header__datetime:empty {
	display: none;
}

/* Date+time lockup — sits ABOVE the H1 per Linnea §5.1 (the fact above
 * the title; venue below as the place). Objektiv sans at the large preset
 * (~23px desktop / ~20px mobile), medium weight for editorial register.
 * White on solid navy passes AAA. Italic Orpheus retired 2026-05-02
 * (Alfonso): the serif italic clashed with the H1 register; sans medium
 * reads as a clean editorial fact-line above the title. */
.tec-event-header__datetime {
	margin: 0 0 0.5rem 0;
	font-weight: 500;
	letter-spacing: 0.01em;
	line-height: 1.3;
}

.tec-event-header__title {
	margin: 0 0 0.75rem 0;
	line-height: 1.1;
}

/* Venue: 17px sans-body (--medium), demoted below the H1. Single-line
 * editorial cap — no boxed chrome, no sidebar. */
.tec-event-header__venue {
	margin: 0 0 0.25rem 0;
	line-height: 1.4;
}

.tec-event-header__cta {
	margin-top: var(--wp--preset--spacing--40, 1.5rem);
}

/* ---------- Body / programme content ----------
 * Aligned 2026-05-02 (Alfonso) to the canonical tec-page-body model:
 * outer gutter, inner pinned to the content tier (1200) so its LEFT edge
 * matches the event-header's 1200 inner column AND the cast band / related
 * band below. Long-form prose (paragraphs, headings, lists, blockquotes)
 * is sub-constrained to 680px and LEFT-ANCHORED inside the 1200 column —
 * mirrors `.tec-page-body__inner > p, h*, ul, …` rule. Result: every band
 * on the single-event page shares the same content left edge at desktop. */
/* .tec-event-body band chrome migrated to universal `tec-band` per Phase 6
 * of band refactor 2026-05-06. The single-tec-events.php template now emits
 * `tec-event-body tec-band tec-band--white tec-band--editorial-sheet` on the
 * outer and `tec-event-body__inner tec-band-inner` on the inner; gutter,
 * vertical rhythm (--spacing--50), 1200px content cap, white surface, and
 * the editorial-sheet hairline (suppressed on first-of-type) all come from
 * assets/css/bands.css. The prose sub-flow rules below (680px cap on `> p`,
 * `> h*`, lists, quotes) stay — that's editorial sub-flow inside the
 * content-tier inner, not band-level chrome. */

.tec-event-body__inner > * + * {
	margin-top: 1rem;
}

.tec-event-body__inner > h2,
.tec-event-body__inner > h3 {
	margin-top: 2rem;
}

/* Prose sub-constraint — left-anchored at 680, so paragraphs sit flush
 * with the left edge of the 1200 layout column (same x-position as the
 * H1 in the header band, the H2 in the programme block, and the cast
 * band heading). Mirrors the `.tec-page-body__inner` contract. */
.tec-event-body__inner > p,
.tec-event-body__inner > h1,
.tec-event-body__inner > h2,
.tec-event-body__inner > h3,
.tec-event-body__inner > h4,
.tec-event-body__inner > h5,
.tec-event-body__inner > h6,
.tec-event-body__inner > ul,
.tec-event-body__inner > ol,
.tec-event-body__inner > blockquote,
.tec-event-body__inner > .wp-block-quote,
.tec-event-body__inner > pre,
.tec-event-body__inner > .wp-block-preformatted {
	max-width: var(--tec-width-prose);
	margin-inline: 0;
}

/* ---------- Cast band (card grid) ----------
 * Linnea single-event design pass 2026-05-02: editorial sheet is one
 * white surface from header-bottom to footer. Cast band's prior
 * transparent fill exposed the GP body grey `#f7f8f9` underneath — a
 * one-step luminance seam between programme (#fff) and cast that read
 * as accidental, not editorial. Set explicit white so programme + cast
 * + related compose as a single column of paper.
 *
 * Padding-block unified to --spacing--60 desktop / --spacing--50 mobile
 * across all four editorial bands (body / programme / cast / related)
 * per Linnea §R2 — alternating 48/72 had no editorial logic. */
/* Migrated to universal .tec-band per Phase 1 of band refactor 2026-05-06.
 * The cast partial now emits `tec-cast-band tec-band tec-band--white` on the
 * outer and `tec-cast-band__inner tec-band-inner` on the inner; padding-inline
 * (gutter), padding-block (--spacing--50) and 1200px content cap all come
 * from the universal rule in assets/css/bands.css. White background is now
 * provided by the `tec-band--white` surface modifier. The PM-14 hairline
 * (border-top: ink-divider) was deliberately not retained at the universal
 * level; if Phase 2+ work needs it back on single-event, opt in via the
 * `tec-band--editorial-sheet` modifier on the partial outer. */

.tec-cast-band__heading {
	font-family: var(--wp--preset--font-family--serif-heading, "orpheuspro", Georgia, serif);
	font-size: var(--wp--preset--font-size--x-large, 2rem);
	margin: 0 0 var(--wp--preset--spacing--40, 1.5rem) 0;
	color: var(--wp--preset--color--navy, #052f67);
}

/* Cast band segments (Conductor / Creative team / Cast / Ensemble).
 * Added 2026-05-08 alongside the `creative_team` role_type. Each segment
 * carries a quieter sub-heading than the band heading — same serif family,
 * smaller, with vertical breathing room above the next grid. */
.tec-cast-segment + .tec-cast-segment {
	margin-top: var(--wp--preset--spacing--50, 2rem);
}

.tec-cast-segment__heading {
	font-family: var(--wp--preset--font-family--serif-heading, "orpheuspro", Georgia, serif);
	font-size: var(--wp--preset--font-size--large, 1.375rem);
	font-weight: 500;
	margin: 0 0 var(--wp--preset--spacing--30, 1rem) 0;
	color: var(--wp--preset--color--navy, #052f67);
}

/* Cast grid layout owned by .tec-grid--4up in tokens.css. */

.tec-cast-card {
	margin: 0;
	padding: 0;
}

.tec-cast-card__link {
	display: flex;
	flex-direction: column;
	gap: 0.75rem;
	text-decoration: none;
	color: inherit;
	height: 100%;
}

.tec-cast-card__link:focus-visible {
	outline: 2px solid var(--wp--preset--color--accent-yellow, #c68f02);
	outline-offset: 2px;
}

.tec-cast-card__photo {
	display: block;
	aspect-ratio: 3 / 4;
	overflow: hidden;
	background: var(--wp--preset--color--surface-low, #f3f3f0);
	width: 100%;
}

.tec-cast-card__img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

.tec-cast-card__photo--fallback {
	display: flex;
	align-items: center;
	justify-content: center;
}

/* .tec-initials utility (tokens.css) owns the initials typography. */

.tec-cast-card__text {
	display: flex;
	flex-direction: column;
	gap: 0.25rem;
}

/* Editorial caption: name in Orpheus Pro (serif-heading), prominent;
 * role/instrument sublabel in Objektiv (sans-body), muted. Matches the
 * portrait-card register applied site-wide per Linnea's audit. */
.tec-cast-card__name {
	font-family: var(--wp--preset--font-family--serif-heading, "orpheuspro", Georgia, serif);
	font-size: var(--wp--preset--font-size--large, 1.4375rem);
	font-weight: 700;
	color: var(--wp--preset--color--navy, #052f67);
	line-height: 1.15;
}

.tec-cast-card__role {
	font-family: var(--wp--preset--font-family--sans-body, "objektiv-mk1", sans-serif);
	font-size: var(--wp--preset--font-size--small, 0.875rem);
	font-weight: 400;
	letter-spacing: 0.02em;
	color: var(--wp--preset--color--ink-low-emphasis, #555);
	line-height: 1.3;
}

.tec-cast-card--ensemble .tec-cast-card__photo {
	background: var(--wp--preset--color--navy, #052f67);
}
.tec-cast-card--ensemble .tec-cast-card__initials {
	color: #ffffff;
}

/* ============================================================
 * Single Event — Programme block (tec/event-programme)
 * Holt 2026-05-02 per Linnea audit §5.3 token map.
 *
 * Sits between the body prose and the cast band as one continuous
 * "performance details" zone (the cast band's cream fill is removed
 * for exactly this reason — see .tec-cast-band rule above).
 *
 * Layout: prose-tier width (680px) so the list sits in the body rhythm.
 * Each row is either a Work-link (composer · title, anchored to the
 * Single Work page) or a free-text label (italic for "Q&A …", italic
 * gold rule for "Interval"). Empty programme → pattern emits nothing.
 * ============================================================ */
/* .tec-event-programme band chrome migrated to universal `tec-band` per
 * Phase 6 of band refactor 2026-05-06. The pattern outer now carries
 * `tec-band tec-band--white tec-band--editorial-sheet`. Background, the
 * --spacing--50 padding-block, and the PM-14 ink-divider border-top all
 * come from bands.css — the prior explicit declarations here were duplicate
 * and have been removed. The mobile --40 tightener was an editorial
 * preference; its parity with the cast partial (which lost its mobile
 * tightener at Phase 1) keeps the editorial sheet rhythm uniform top-to-
 * bottom on both desktop and mobile. */

/* Heading + list: prose-cap (680), flush-left at the gutter — NOT centred.
 * The `.tec-event-programme__inner` wrapper carries the wide tier (1200)
 * via `.tec-band-inner--wide` (tokens.css). Heading + list sub-constrain
 * to prose, margin-inline:0 keeps them anchored to the inner's left edge
 * — same x-position as the body paragraph above and cast/related H2s
 * below. */
.tec-event-programme__inner > .wp-block-heading,
.tec-event-programme__inner > .wp-block-html {
	max-width: var(--tec-width-prose);
	margin-inline: 0;
}

.tec-event-programme__heading {
	color: var(--wp--preset--color--navy, #052f67);
	margin: 0 0 var(--wp--preset--spacing--30, 1rem) 0;
}

.tec-event-programme__list {
	list-style: none;
	margin: 0;
	padding: 0;
	max-width: var(--tec-width-prose);
}

/* Programme rows render as consecutive lines of a single paragraph
 * (Alfonso 2026-05-05): no per-item padding-block — consecutive works
 * sit exactly one line-height apart, the same vertical rhythm as wrapped
 * lines inside a <p>. Inter-row gap = line-height (1.4 × 17px ≈ 24px).
 * The Interval row keeps its own generous padding-block via the
 * --interval rule below (later in cascade). */
.tec-event-programme__item {
	margin: 0;
	padding-block: 0;
	font-family: var(--wp--preset--font-family--sans-body, "objektiv-mk1", system-ui, sans-serif);
	font-size: var(--wp--preset--font-size--medium, 1.0625rem);
	color: var(--wp--preset--color--navy, #052f67);
	line-height: 1.4;
}

/* Composer secondary, work-title primary (R5 / §7). Composer at weight
 * 500 — the loadable Objektiv medium. Prior weight 600 was browser-
 * synthesised from 700 (no 600 cut in the kit), inverting the editorial
 * hierarchy and making the composer heavier than the work title. */
.tec-event-programme__composer {
	font-weight: 500;
	color: var(--wp--preset--color--charcoal, #31393c);
}

.tec-event-programme__sep {
	color: var(--wp--preset--color--accent-yellow, #c68f02);
	padding-inline: 0.25em;
}

.tec-event-programme__work {
	font-weight: 400;
	color: var(--wp--preset--color--navy, #052f67);
}

/* Free-text rows that aren't "Interval" — slightly muted. Italic Orpheus
 * retired 2026-05-02 to match the sans-only register of the programme. */
.tec-event-programme__item--free {
	color: var(--wp--preset--color--ink-low-emphasis, #555);
}

/* Interval — small uppercase eyebrow-style label in Objektiv sans,
 * accent-gold colour, with extra vertical breathing room above and below.
 * Replaces the previous Orpheus italic centred treatment (Alfonso
 * 2026-05-02): the sans-uppercase register is the cleanest segment
 * marker once dividing rules between rows have been removed. */
.tec-event-programme__item--interval {
	font-family: var(--wp--preset--font-family--sans-body, "objektiv-mk1", system-ui, sans-serif);
	font-size: var(--wp--preset--font-size--small, 0.875rem);
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.12em;
	color: var(--wp--preset--color--accent-yellow, #c68f02);
	padding-block: var(--wp--preset--spacing--40, 1.25rem);
}

/* ============================================================
 * Single Event — Coming Up Next band (tec/event-related)
 * Holt 2026-05-02 — replaces the support-section that used to
 * sit at the foot of single-tec-events.php.
 *
 * Reuses the events-archive 3-up grid layout (.tec-events-archive-upcoming__grid)
 * and the canonical tec/event-card pattern. The band itself sits on the
 * white surface with the standard tec-band vertical rhythm. The H2 uses
 * the same Orpheus xx-large register as the cast band heading so the
 * three sections (programme / cast / coming-up-next) read as one
 * editorial cadence.
 * ============================================================ */
/* Linnea design pass 2026-05-02 (R3): cream `--surface-low` retired —
 * the editorial sheet stays white from header-bottom to footer. The
 * related-events grid carries its own card chrome (gold border, navy
 * shadow); cards on white read fine and the surface change between
 * cast (white) and related (cream) was a fourth surface decision the
 * page didn't need. Padding-block unified to --spacing--60 / --50. */
/* Surface (light-blue) and gutter migrated to universal `tec-band` +
 * `tec-band--light-blue` modifier per Phase 6 of band refactor 2026-05-06.
 * The padding-block here (--60 desktop / --50 mobile) is an editorial
 * override on top of the universal --50 default — slightly heavier rhythm
 * for the cross-sell band so the surface change reads as a deliberate
 * shift, not a continuation. */
.wp-block-group.tec-event-related {
	padding-block: var(--wp--preset--spacing--60, 2.5rem);
}

@media (max-width: 766px) {
	.wp-block-group.tec-event-related {
		padding-block: var(--wp--preset--spacing--50, 2rem);
	}
}

/* Heading colour + bottom margin only — the prior `max-width: wide;
 * margin-inline: auto` papered over the missing `tec-band-inner` wrapper.
 * Phase 6 restructured the pattern so the heading sits inside a proper
 * `tec-band-inner`; the cap is now structural, not heading-level. */
.tec-event-related__heading {
	color: var(--wp--preset--color--navy, #052f67);
	margin-block-end: var(--wp--preset--spacing--40, 1.5rem);
}

/* ============================================================
 * Single Event — Sticky mobile buy bar
 * Holt 2026-05-02 per Linnea audit §5.6.
 *
 * Visible only below the sm breakpoint (≤766px) and only on upcoming
 * events (the template's $tec_is_upcoming guard skips the wrapper
 * entirely on past events). Contains a compact date string and the
 * gold Buy tickets CTA. Fixed-positioned at the bottom of the
 * viewport so the buy action stays one tap away through the whole
 * scroll.
 * ============================================================ */
.tec-event-stickybar {
	display: none;
}

@media (max-width: 766px) {
	.tec-event-stickybar {
		display: block;
		position: fixed;
		inset-inline: 0;
		inset-block-end: 0;
		z-index: 50;
		background: #ffffff;
		border-block-start: 1px solid var(--wp--preset--color--ink-divider, #e5e5e5);
		box-shadow: 0 -2px 8px rgba(5, 47, 103, 0.08);
		padding-block: 0.625rem;
		padding-inline: var(--tec-gutter);
	}

	.tec-event-stickybar__inner {
		display: flex;
		align-items: center;
		justify-content: space-between;
		gap: 0.75rem;
		max-width: var(--tec-width-wide);
		margin-inline: auto;
	}

	.tec-event-stickybar__date {
		font-family: var(--wp--preset--font-family--sans, system-ui, sans-serif);
		font-size: var(--wp--preset--font-size--small, 0.875rem);
		font-weight: 600;
		color: var(--wp--preset--color--navy, #052f67);
		letter-spacing: 0.02em;
	}

	.tec-event-stickybar__cta {
		flex: 0 0 auto;
		min-height: 44px;
	}

	/* Add bottom padding to the body so the sticky bar doesn't cover
	 * the last related-events card when the user scrolls to the foot. */
	body.single-tec-events {
		padding-block-end: 4.5rem;
	}
}

/* ==========================================================================
   Single Post + Posts archive (Linnea inventory #11, #12, #14)
   Appended 2026-05-01 by Holt for the Single Post + Posts Archive build.
   ========================================================================== */

/* --- Single Post body + header meta ------------------------------------
 * Moved to assets/css/single-post.css (Linnea spec 2026-05-06, musician-
 * style layout). Body is now a two-column wp:columns band emitted by the
 * tec/single-post-body pattern; the legacy single-column reading-prose
 * rules below are superseded by per-column selectors in the new sheet.
 * Meta-line typography also moved to single-post.css and now uses
 * ink-low-emphasis (no raw hex). Selectors `.tec-single-post-body__inner`
 * still applies (inner now wraps the columns) but no inner typography
 * rules are needed — the_content() flow lives inside the prose column. */

/* --- Single Post header band rhythm ------------------------------------
 * Phase 6 (band refactor 2026-05-06): replaces the inline-style padding
 * the pattern used to emit. 4rem top / 2rem bottom is the editorial
 * preference for a header-into-body transition. The 1200px content cap
 * is provided by `.tec-band-inner` from bands.css (was 1000px under the
 * old pattern's `contentSize:1000px`; relaxed to the universal default
 * per Linnea spec Q1). */
.tec-single-post-header {
	padding-block: 4rem 2rem;
}

/* --- Single Post related band rhythm -----------------------------------
 * Phase 6 (band refactor 2026-05-06): replaces the inline-style padding
 * + background the related-band PHP function used to emit. Surface comes
 * from `tec-band--light-blue`; the 3rem top / 4rem bottom rhythm is the
 * cross-sell editorial preference. */
.tec-single-post-related {
	padding-block: 3rem 4rem;
}

/* === CANONICAL CARD CONTRACT =========================================
 *
 * `.is-style-tec-card` is the SHARED card chrome consumed by every
 * content-type card pattern in the theme: tec/event-card, tec/post-card,
 * tec/recording-card, tec/video-card. (The musician card uses the sibling
 * `.is-style-tec-portrait-card` — same chrome, 3:4 portrait differentiator.)
 *
 * SHARED across all card patterns (owned by this stylesheet block):
 *   - Surface: white bg, accent-yellow 1px border, 5px radius, navy soft
 *     shadow, 1rem padding. Tokens live in theme.json `custom.card.*`.
 *   - Interaction: hover lift (-2px), shadow swap, title→navy, focus-within
 *     mirror, gold focus ring on :has(:focus-visible). Reduced-motion safe.
 *   - Title chrome: 1px accent-yellow gold-rule above the post-title plus
 *     0.875rem padding-top + line-height 1.25 (single rule below).
 *   - Button row: pinned to card foot via margin-top:auto.
 *   - Eyebrow: every card pattern emits `tec-eyebrow tec-eyebrow--card`
 *     (near-black, wider tracking, margin 0). Defined in eyebrow.css.
 *
 * GENUINELY PER-CARD (owned by the per-pattern CSS section + block JSON):
 *   - Image aspect: events 16:10 (block attr), posts native, recordings
 *     1:1 (CSS), musicians 3:4 (portrait variant), videos 16:9 (block attr).
 *   - Eyebrow content: bound source differs (date|time, category, label·year,
 *     video_programme term).
 *   - CTA copy + presence: events have two buttons (Get Tickets / Learn
 *     More), posts/recordings/videos have a single outline CTA, musicians
 *     have no CTA.
 *
 * Change a shared rule HERE once and every card pattern updates. Per-pattern
 * CSS sections must NOT redeclare surface, hover, title chrome, or button
 * pinning — those belong to the shared layer.
 * ====================================================================
 */
.wp-block-group.is-style-tec-card {
	background: var(--wp--custom--card--background, var(--wp--preset--color--white));
	border: var(--wp--custom--card--border--width, 1px) solid var(--wp--custom--card--border--color, var(--wp--preset--color--accent-yellow));
	border-radius: var(--wp--custom--card--border--radius, 5px);
	box-shadow: var(--wp--custom--card--shadow, 0 0 8px 0 rgba(5, 47, 103, 0.25));
	padding: var(--wp--custom--card--padding, 1rem);
	transition: transform 180ms ease, box-shadow 180ms ease;
}

/* Hover lift + shadow swap, applied uniformly to every card composing the
 * variation (post-card, event-card, recording-card). Title shifts to navy
 * on card-hover via the heading colour; linked titles inherit, plain
 * titles (single-anchor recording-card) recolour directly. Suppressed
 * under prefers-reduced-motion. :focus-within mirrors hover so keyboard
 * users get the same affordance. */
@media (hover: hover) {
	.wp-block-group.is-style-tec-card:hover,
	.wp-block-group.is-style-tec-card:focus-within {
		transform: translateY(-2px);
		box-shadow: var(--wp--custom--card--shadow--hover, 0 4px 16px 0 rgba(5, 47, 103, 0.30));
	}
	.wp-block-group.is-style-tec-card:hover .wp-block-post-title,
	.wp-block-group.is-style-tec-card:focus-within .wp-block-post-title,
	.wp-block-group.is-style-tec-card:hover .tec-video-card__title,
	.wp-block-group.is-style-tec-card:focus-within .tec-video-card__title {
		color: var(--wp--preset--color--navy);
	}
}
@media (prefers-reduced-motion: reduce) {
	.wp-block-group.is-style-tec-card { transition: box-shadow 180ms ease; }
	.wp-block-group.is-style-tec-card:hover,
	.wp-block-group.is-style-tec-card:focus-within { transform: none; }
}

/* Gold focus ring when any focusable inside the card is keyboard-focused
 * (covers the whole-card-click affordance for all three card types). */
.wp-block-group.is-style-tec-card:has(:focus-visible) {
	outline: 2px solid var(--wp--preset--color--accent-yellow);
	outline-offset: 3px;
}

/* === SUPPORTER TIER CARDS (page 270 — `/support-us/become-a-friend-or-patron/`)
 * Composes `.is-style-tec-card` chrome with the per-page `.tec-tier-card`
 * modifier. The card chrome (surface, border, hover, focus ring) is owned by
 * the canonical card layer above; this block adds only what's specific to the
 * tier-card use:
 *   - column equalisation (cards stretch to row height, CTA pinned to foot)
 *   - price-line typography (Objektiv bold, slightly larger than body)
 * Three-up at desktop is owned by the `wp:columns` block (auto-collapses to
 * 1-up on mobile via core); no media query needed for the patron row.
 * Holt 2026-05-08 (restructured — no featured tier; Friend + Medici handled
 * as separate quieter bands above/below the matrix). */
.tec-tier-card { height: 100%; }
.tec-tier-card .wp-block-buttons { margin-top: auto; }
.tec-tier-card__price {
	font-family: var(--wp--preset--font-family--sans-heading);
	font-size: var(--wp--preset--font-size--medium);
	margin: 0 0 var(--wp--preset--spacing--30) 0;
	line-height: 1.35;
}

/* Comparison matrix — typography + mobile scroll affordance.
 * Right-edge gradient fade is the lightweight scroll cue (Wystan A2);
 * implemented at the canonical layer so it's reusable on any horizontally
 * scrolling table inside an editorial-sheet band. */
.tec-tier-matrix table { width: 100%; border-collapse: collapse; }
.tec-tier-matrix th, .tec-tier-matrix td {
	padding: 0.5rem 0.75rem;
	text-align: center;
	border-bottom: 1px solid rgba(5, 47, 103, 0.10);
	font-family: var(--wp--preset--font-family--sans-heading);
}
.tec-tier-matrix th:first-child, .tec-tier-matrix td:first-child {
	text-align: left;
}
.tec-tier-matrix thead th {
	font-family: var(--wp--preset--font-family--serif-heading);
	font-weight: 600;
	border-bottom: 2px solid var(--wp--preset--color--navy);
}
@media (max-width: 781px) {
	.tec-tier-matrix {
		overflow-x: auto;
		position: relative;
		/* Right-edge gradient fade tells the user the table scrolls. The
		 * fade is anchored to the scroll viewport so it sits above the
		 * table edge without participating in scroll. */
		background:
			linear-gradient(to right, rgba(255,255,255,0) calc(100% - 32px), rgba(255,255,255,0.92) 100%) right center / 32px 100% no-repeat,
			transparent;
	}
	.tec-tier-matrix table { min-width: 640px; }
}

/* Musicians archive page section — wrapped in tec-band (Holt 2026-05-08, parity
 * with /videos/ and /events/). Vertical breathing room owned by bands.css; the
 * earlier per-archive padding-block override was retired alongside the navy
 * header sweep. */

/* --- tec/post-card pattern --------------------------------------------- */
.tec-post-card {
	height: 100%;
	display: flex;
	flex-direction: column;
}

/* Featured image: NO forced aspect ratio. Square art (CD covers on
 * `recordings` posts) renders square; landscape art renders landscape.
 * Prod-faithful native aspect (Alfonso 2026-05-02).
 *
 * The figure itself must be width:100% — without it, the figure (a flex
 * item inside the vertical flex group whose core layout container sets
 * align-items:flex-start, not stretch) shrinks to the img's intrinsic
 * width. For lazy-loaded images that's harmless because intrinsic dims
 * aren't known at layout time so flex falls back to the available track.
 * For EAGER-loaded images (the first two cards in any Query Loop, which
 * skip loading="lazy"), the browser knows the natural dimensions
 * synchronously and the figure collapses to e.g. 100px — leaving the
 * first two cards visibly smaller than the rest. Setting figure width
 * to 100% (and the link wrapper to display:block) keeps the cross-axis
 * box at full track width regardless of intrinsic image size or load
 * timing. Diagnosed Alfonso 2026-05-02. */
.tec-post-card .wp-block-post-featured-image {
	margin: 0 0 0.5rem;
	width: 100%;
}
.tec-post-card .wp-block-post-featured-image a {
	display: block;
	width: 100%;
}
.tec-post-card .wp-block-post-featured-image img {
	width: 100%;
	height: auto;
	display: block;
}

/* Image-slot fallback for image-less posts on opt-in surfaces (currently
 * single-production.php Related reading band). Rendered by
 * tec-post-card-fallback.php via the post_thumbnail_html filter — a
 * <span> tile inside the core/post-featured-image figure's existing <a>
 * wrapper. Brand-tinted surface, 16:9 aspect (standardised for image-less
 * cards — real thumbnails keep their native aspect), category eyebrow
 * centred. Mirrors the .tec-musician-card__portrait-fallback convention. */
.tec-post-card__image-fallback {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	aspect-ratio: 16 / 9;
	background: var(--wp--preset--color--surface-low, #f3f3f0);
	overflow: hidden;
	padding: 1rem;
	box-sizing: border-box;
}

.tec-post-card__image-fallback-label {
	font-family: var(--wp--preset--font-family--sans-heading, "objektiv-mk3", "Objektiv Mk3", sans-serif);
	font-size: var(--wp--preset--font-size--small, 0.875rem);
	font-weight: 600;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--wp--preset--color--ink-low-emphasis, #555555);
	text-align: center;
	line-height: 1.3;
}

/* Eyebrow — uses shared .tec-eyebrow utility, recoloured to near-black inside
 * cards by the .tec-event-card / .tec-post-card .tec-eyebrow rule above.
 * Anchor link styling only — colour, weight, transform, tracking are owned
 * by .tec-eyebrow + the card-internal override (Alfonso 2026-05-02). */
.tec-post-card .wp-block-post-terms a {
	color: inherit;
	text-decoration: none;
}
.tec-post-card .wp-block-post-terms a:hover,
.tec-post-card .wp-block-post-terms a:focus-visible {
	color: var(--wp--preset--color--accent-yellow);
	text-decoration: underline;
}

/* Title — colour comes from `has-accent-yellow-color` (textColor on
 * wp:post-title). At-rest no-underline + hover navy treatment is shared
 * with .tec-event-card via .is-style-tec-card .wp-block-post-title a in
 * tokens.css + the global a:hover rule. No card-specific title rule
 * needed here (Alfonso 2026-05-02). */

/* Excerpt — body size token, charcoal. */
.tec-post-card .wp-block-post-excerpt,
.tec-post-card .wp-block-post-excerpt__excerpt {
	font-size: var(--wp--preset--font-size--medium);
	line-height: 1.5;
	color: var(--wp--preset--color--charcoal);
}

/* "Read more" button rule retired 2026-05-07 — post-card no longer ships
 * a default CTA (Alfonso, Wystan rec §3). Editorial card_actions render
 * via the shared `.tec-card-actions` rules above; no card-specific button
 * width override needed. */

/* Posts archive + homepage "latest" grid layout owned by .tec-grid--3up
 * in tokens.css (and .tec-latest-grid is aliased there until page 20613's
 * markup is updated). The posts-archive scope just bumps the gap to 2rem
 * to match the homepage rhythm. */
.tec-posts-archive { --tec-grid-gap: 2rem; }

/* Pagination footer styling lives in the canonical Pagination block above
 * (single source of truth). Per-archive paginator rules removed 2026-05-02. */

/* --- Related band ------------------------------------------------------
 * Layout owned by .tec-grid--3up in tokens.css; gap bumped to 2rem to
 * match the posts-archive rhythm. */
.tec-single-post-related__grid { --tec-grid-gap: 2rem; }

/* Body: constrained to 1000px (matches theme.json contentSize). Inner
 * blocks authored at default width inherit this; alignwide / alignfull
 * escape the prose column via the rules below (mirrors the single-post
 * escape contract).
 *
 * "Flush at top" rule: when the first child of __inner is alignfull
 * (the tec/page-header cover pattern is the canonical case), the body
 * wrapper drops its top padding AND its horizontal gutter so the cover
 * butts the site header and paints edge-to-edge. Bottom padding holds,
 * so the body still has rhythm before the Get Involved strip.
 * Holt 2026-05-02. */
.tec-page-body {
	padding-block: clamp(2.5rem, 6vw, 4rem) clamp(3rem, 6vw, 4.5rem);
	padding-inline: var(--tec-gutter);
}
.tec-page-body__inner {
	max-width: var(--tec-width-content);
	margin-inline: auto;
}
.tec-page-body__inner > .alignwide {
	width: min(var(--tec-width-wide), 100vw - 2rem);
	max-width: none;
	margin-left: 50%;
	transform: translateX(-50%);
}
.tec-page-body__inner > .alignfull {
	width: 100vw;
	max-width: none;
	margin-left: 50%;
	transform: translateX(-50%);
}
/* Alignfull-first override: when the first child is alignfull (the
 * tec/page-header cover pattern), drop the body's top padding so the
 * cover butts the site header. Horizontal gutter on the body wrapper
 * stays — the alignfull child uses the translateX(-50%) escape rule
 * above to break out of any parent constraint and reach 100vw. */
.tec-page-body:has(> .tec-page-body__inner > .alignfull:first-child) {
	padding-top: 0;
}
/* Alignfull-last override: symmetric counterpart to the rule above. When
 * the LAST in-flow child of __inner is alignfull (canonically the
 * tec/support-section navy donor band auto-rendered by page.php before
 * the footer, but applies to any alignfull tail band), drop the body's
 * bottom padding so the band butts the footer instead of leaving a
 * 72px off-white stripe between the band and the footer's near-black
 * signup band. Without this, page.php pages (education, about-us,
 * contact-us, etc.) painted a light gap between the navy support band
 * and the near-black footer that read as a structural break. CPT
 * singles and the home template were unaffected because their
 * support-section sits as a direct child of <main>, not inside
 * .tec-page-body. Holt 2026-05-05, Alfonso reported. */
.tec-page-body:has(> .tec-page-body__inner > .alignfull:last-child) {
	padding-bottom: 0;
}

/* Prose sub-constraint inside the page body.
 *
 * Architecture (Alfonso sign-off 2026-05-02):
 *   The default container tier on page.php is 1200px (theme.json
 *   contentSize=1200, wideSize=1200 — both resolve identically). Layout
 *   blocks (Columns, Media & Text, image, cover, etc.) authored at
 *   default alignment fill 1200. Long-form text — paragraphs, headings,
 *   lists, blockquotes, preformatted — is sub-constrained to 680px
 *   (--tec-width-prose) by the rule below. Prose is anchored to the
 *   LEFT edge of the 1200 container (margin-inline:0), not centred —
 *   this keeps top-level paragraphs flush with the left edge of layout
 *   blocks below them (Media & Text, Columns, full-width images), so
 *   the editorial flow reads as one column. The 680px cap lives on the
 *   right and preserves a comfortable line length (~78ch).
 *   `align:full` blocks still bleed to 100vw via the rule above.
 *   `align:wide` becomes a no-op (also resolves to 1200) but stays
 *   valid markup so existing patterns don't break.
 *
 * Scoping:
 *   `>` direct child only. Paragraphs/headings nested inside Columns,
 *   Media & Text, Cover (e.g. tec/page-header), or any other layout
 *   block are NOT direct children of __inner and therefore NOT
 *   constrained — they fill their parent layout block. Likewise blocks
 *   inside .tec-page-header (cover with bespoke inner-container
 *   wrappers) are unaffected.
 *
 * Specificity / source order:
 *   Selector specificity (0,2,1) beats core's layout-flow defaults
 *   without !important. The rule lives next to .tec-page-body__inner so
 *   future engineers see the contract in one place. */
.tec-page-body__inner > p,
.tec-page-body__inner > h1,
.tec-page-body__inner > h2,
.tec-page-body__inner > h3,
.tec-page-body__inner > h4,
.tec-page-body__inner > h5,
.tec-page-body__inner > h6,
.tec-page-body__inner > ul,
.tec-page-body__inner > ol,
.tec-page-body__inner > blockquote,
.tec-page-body__inner > .wp-block-quote,
.tec-page-body__inner > pre,
.tec-page-body__inner > .wp-block-preformatted {
	max-width: var(--tec-width-prose);
	margin-inline: 0;
}

/* =========================================================================
 * Phase 2.1 — Work + Video CPT scaffold
 * Minimum structural CSS. No visual polish.
 * ========================================================================= */

/* Single Work — hero min-height owned by `.tec-work-hero` rule above
 * (--tec-hero-min-height token, Stage 4 hygiene refactor). */
.tec-single-work .tec-work-hero__meta {
	gap: 16px;
	color: rgba(255,255,255,0.9);
}
.tec-single-work .tec-work-hero__meta p:empty {
	display: none;
}
/* Phase 5 (2026-05-06, Holt): Synopsis + Installment bands migrated to
 * Pattern B. Outer carries tec-band + tec-band--white +
 * tec-band--editorial-sheet; inner carries tec-band-inner (synopsis adds
 * --prose). The universal `.tec-band` rule in `assets/css/bands.css`
 * provides padding-inline / padding-block; the inner provides the content
 * cap; the editorial-sheet modifier provides the hairline (with
 * :first-of-type suppressing the top hairline on the first installment).
 * Per-band padding / border-top / max-width / margin-inline rules from
 * the prior PM-12 markup are deleted here.
 *
 * Only inner-content concerns remain: per-installment synopsis gets the
 * prose tier; the (legacy) __name muted treatment stays for now. */
.tec-single-work .tec-work-installment__synopsis {
	max-width: var(--tec-width-prose);
}

/* Single Video — header + embed are media-led (content tier, 1000px);
 * description + programme notes are prose-led editorial copy (prose tier,
 * 680px) by judgement (Holt 2026-05-02). */
/* Phase 3 (2026-05-06, Holt): single-video band refactor migrated to
 * Pattern B. The universal `.tec-band` rule in `assets/css/bands.css`
 * now provides padding-inline (var(--tec-gutter)), padding-block
 * (var(--wp--preset--spacing--50)), and the inner content cap via
 * `.tec-band-inner`. The previous band-and-cap rules (max-width +
 * margin-inline + padding-inline on each `.tec-video-*`) were deleted.
 * Per-class overrides retained below: header padding-block (48/24)
 * to preserve programme-book vertical rhythm; embed bottom margin
 * (32px) for the audition spacing; iframe aspect-ratio; breadcrumb
 * meta; about-work editorial card (NOT a band — exception per
 * Linnea's spec). */
.tec-single-video .tec-video-embed {
	margin-bottom: 32px;
}
.tec-single-video .tec-video-embed iframe {
	width: 100%;
	aspect-ratio: 16/9;
}

/* Works archive */
.tec-archive-work .tec-archive-hero {
	max-width: var(--tec-width-wide);
	margin-inline: auto;
	padding-block: 64px 32px;
	padding-inline: var(--tec-gutter);
	text-align: left;
}
.tec-archive-work .tec-works-filter,
.tec-archive-video .tec-videos-filter {
	max-width: var(--tec-width-wide);
	margin-inline: auto;
	margin-bottom: 32px;
	padding-inline: var(--tec-gutter);
}
.tec-filter-chips {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	list-style: none;
	margin: 0;
	padding: 0;
}
.tec-filter-chip {
	display: inline-block;
	padding: 6px 14px;
	border: 1px solid var(--wp--preset--color--navy, #052f67);
	border-radius: 999px;
	font-size: var(--wp--preset--font-size--small, 0.875rem);
	text-decoration: none;
}
.tec-filter-chip.is-active {
	background: var(--wp--preset--color--navy, #052f67);
	color: #fff;
}
@media (max-width: 766px) {
	.tec-filter-chips {
		flex-wrap: nowrap;
		overflow-x: auto;
		-webkit-overflow-scrolling: touch;
	}
}

/* --- /videos/ archive — Load more button -------------------------------
 * The Query Loop `wp:query-pagination-next` block emits a bare anchor
 * (`<a class="wp-block-query-pagination-next">`), not the canonical
 * `<div class="wp-block-button">…<a class="wp-block-button__link">` shell
 * the design-system buttons.css rules target. Rather than fork the canonical
 * button definitions (which would create two sources of truth for the
 * outline button look) we promote the bare anchor to the same chrome via
 * a thin alias selector. Mirrors `.wp-block-button.is-style-tec-outline >
 * .wp-block-button__link` exactly — values stay in sync because they pull
 * from the same custom properties. Holt 2026-05-08.
 *
 * Wrapping `wp:buttons` provides the centred flex layout and vertical rhythm.
 * Spacing above the button comes from the Query Loop's natural blockGap. */
.tec-videos-archive-loadmore,
.tec-musicians-archive-loadmore {
	margin-top: var(--wp--preset--spacing--50);
	margin-bottom: var(--wp--preset--spacing--40);
}
/* Last page: wp:query-pagination-next renders nothing → wrapper is empty.
 * Suppress the empty wrap (with its blockGap whitespace stripped) so we
 * don't ship a phantom margin between the grid's last row and the next
 * band. Holt 2026-05-08. Shared with /musicians/ load-more (parity sweep). */
.tec-videos-archive-loadmore:not(:has(.wp-block-query-pagination-next)),
.tec-musicians-archive-loadmore:not(:has(.wp-block-query-pagination-next)) {
	display: none;
}
.tec-videos-archive-loadmore .wp-block-query-pagination-next,
.tec-musicians-archive-loadmore .wp-block-query-pagination-next {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-height: 40px;
	padding: 3.5px 28px;
	border: 1px solid var(--wp--preset--color--near-black);
	border-radius: 4.9px;
	background-color: transparent;
	color: var(--wp--preset--color--near-black);
	font-family: var(--wp--preset--font-family--sans-body);
	font-size: var(--wp--preset--font-size--medium);
	font-weight: 700;
	line-height: 1.7;
	white-space: nowrap;
	text-decoration: none;
	transition: background-color 0.18s ease, color 0.18s ease, border-color 0.18s ease;
}
.tec-videos-archive-loadmore .wp-block-query-pagination-next:hover,
.tec-videos-archive-loadmore .wp-block-query-pagination-next:focus-visible,
.tec-musicians-archive-loadmore .wp-block-query-pagination-next:hover,
.tec-musicians-archive-loadmore .wp-block-query-pagination-next:focus-visible {
	background-color: var(--wp--preset--color--near-black);
	color: var(--wp--preset--color--white);
}

/* --- tec/video-card pattern --------------------------------------------
 * Consumes `.is-style-tec-card` chrome (surface, hover, title gold-rule,
 * button pinning) — see canonical contract above. The block-attribute
 * aspect-ratio of 16:9 lives on wp:post-featured-image (block JSON, not
 * CSS, per Alfonso's hub-card validation rule). The native flex column
 * layout is owned by core/group's flex orientation:vertical attribute,
 * so no display/flex rules here. tec-work-card is the related sibling
 * used by Single Work — same shared chrome. */
.tec-video-card,
.tec-work-card {
	height: 100%;
}
.tec-video-card .wp-block-post-featured-image {
	margin: 0;
	width: 100%;
}
.tec-video-card .wp-block-post-featured-image a {
	display: block;
	width: 100%;
	height: 100%;
}
.tec-video-card .wp-block-post-featured-image img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

/* Poster wrapper. Three load-bearing rules:
 *
 * 1. `position: relative` — anchors the absolutely-positioned
 *    `tec-video-card__badge` (parts count) inside the poster.
 *
 * 2. `width: 100%` + `aspect-ratio: 16 / 9` — together these make
 *    the poster's height deterministic from its column's layout
 *    width, not from intrinsic content. The figure inside has its
 *    own 16:9 aspect-ratio, but its *intrinsic* size — what the
 *    parent flex column uses when resolving `flex-basis: auto` — is
 *    derived from the img's intrinsic width (100px from the 100x66
 *    thumbnail src), giving a poster flex-basis of only ~56-64px.
 *    The figure then renders at 248×139.5 (correct) but overflows
 *    its 56-64px parent and visually covers the title slot beneath.
 *    Setting `width: 100%` on the poster pins its used inline-size
 *    independent of basis resolution; combined with `aspect-ratio`
 *    that gives a deterministic block-size of 248×0.5625 = 139.5px.
 *    Diagnosed Holt 2026-05-07. (`width: 100%` alone is insufficient
 *    on the figure because the figure's inline size in the cross-
 *    axis is computed AFTER its intrinsic main-axis size — the
 *    aspect-ratio applied to its parent breaks that circularity.)
 *
 * 3. `flex-shrink: 0` — defensive; with aspect-ratio doing the work
 *    of (2), shrink isn't strictly required, but pinning it stops
 *    the row stretch case from collapsing the poster again if a
 *    sibling card has a much taller meta block.
 *
 * The figure inside still carries its own aspect-ratio (canonical
 * `.tec-video-card__hero` rule) so single-surface usages outside
 * a flex column (if any) keep working.
 *
 * Vocabulary note (Holt 2026-05-10, M2 finish): this wrapper was
 * previously named `__poster` (the legacy class). Renamed to `__hero-frame` so
 * the card vocabulary is uniformly `__hero`-rooted across the pattern
 * family. The DOM split is load-bearing — the wrapper provides
 * `position: relative` (badge anchor) and the flex-basis fix, while
 * the inner figure (`__hero`) owns box rules — so collapsing the two
 * into one element is NOT safe. Two layers, two names. */
.tec-video-card__hero-frame {
	position: relative;
	width: 100%;
	aspect-ratio: 16 / 9;
	flex-shrink: 0;
}

/* Canonical poster/hero sizing — Holt 2026-05-07.
 * The 16:9 aspect-ratio is declared as a block attribute on the
 * featured-image (patterns/video-card.php), but WP emits it as an
 * inline style on the <figure>. Without an explicit display:block +
 * overflow:hidden + zero margins, the figure's intrinsic-height does
 * not propagate cleanly back to the parent .tec-video-card__hero-frame
 * group on every surface (HFA Highlights/Library/Lesser-known were
 * showing poster ~64px while figure ~140px — figure overflowing,
 * visually covering the title beneath). Was previously scoped to
 * .tec-production-videos__list only; lifted to the canonical class
 * so every consumer of tec/video-card gets correct sizing. The img
 * rule above (height:100%; object-fit:cover) needs the figure to be
 * a definite-height box, which the aspect-ratio + display:block
 * provides. */
.tec-video-card__hero {
	display: block;
	aspect-ratio: 16 / 9;
	overflow: hidden;
	margin: 0;
}

/* Card title — UI listing register, not editorial.
 * Objektiv Mk3 (sans-heading) bold at `medium` size, tight UI leading.
 * Pattern emits `has-medium-font-size` + `has-sans-heading-font-family`;
 * this rule pins font-weight 700 and line-height 1.25 so the heading
 * reads as a UI label across HFA library, /videos/ archive, single-
 * musician/production rails, and any other surface using tec/video-card.
 * Per Alfonso 2026-05-07: Orpheus Pro is reserved for editorial headings
 * (band H1/H2, page titles, section heads); repeated card-title positions
 * inside listings render in the functional UI register. */
.tec-video-card__title {
	margin: 0;
	font-weight: 700;
	line-height: 1.25;
}
/* Title link — colour-only affordance. No underline at any state.
 * Card-wide :hover/:focus-within rule (style.css:1102-1107) recolours
 * the title to navy on card-hover; the global a:hover rule recolours
 * the link itself to navy when the anchor is hovered directly — both
 * paths converge on the same colour. Underline removed per Alfonso
 * 2026-05-07: a link inside a card should declare itself through
 * colour shift, not a text-decoration line. */
.tec-video-card__title a,
.tec-video-card__title-link {
	color: inherit;
	text-decoration: none;
}
.tec-video-card__title a:hover,
.tec-video-card__title a:focus-visible,
.tec-video-card__title-link:hover,
.tec-video-card__title-link:focus-visible {
	text-decoration: none;
}

/* Eyebrow link affordance — mirrors the canonical .tec-post-card
 * .wp-block-post-terms a treatment (style.css:1171-1179): no underline
 * at rest, accent-yellow + underline on hover/focus-visible. Applies on
 * every surface where the video_programme eyebrow is rendered (everywhere
 * except the HFA term archive itself, where the eyebrow is suppressed
 * by the render_block_core/post-terms filter in functions.php).
 * Per Alfonso 2026-05-07: adopt the established single-post-card
 * convention rather than introduce a parallel affordance. */
.tec-video-card .wp-block-post-terms a,
.tec-video-card .tec-eyebrow a {
	color: inherit;
	text-decoration: none;
}
.tec-video-card .wp-block-post-terms a:hover,
.tec-video-card .wp-block-post-terms a:focus-visible,
.tec-video-card .tec-eyebrow a:hover,
.tec-video-card .tec-eyebrow a:focus-visible {
	color: var(--wp--preset--color--accent-yellow);
	text-decoration: underline;
}

/* ---- Canonical tec/video-card meta slots (badge + billing/filmed)
 * Lifted from hfa-library.css 2026-05-07 (Holt). The pattern is consumed
 * by /videos/ archive, single-musician videos band, single-production
 * videos rollup, video-related-band, and HFA library/highlights/lesser-
 * known — but hfa-library.css is enqueued only on the HFA archive, so
 * those rules were silently absent on every other surface. The badge,
 * left in flow with default block styling, contributed margin-block-start
 * and an empty box that pushed the poster's box past its aspect-ratio.
 * Moving these to style.css makes them surface-agnostic. The bindings
 * (billing/filmed/parts) return "" for missing data so the
 * `:empty {display:none}` rule collapses the slot cleanly without a
 * residual blockGap (flex `gap` ignores display:none children).
 * Duration slot retired 2026-05-10. */
.tec-video-card__badge {
	position: absolute;
	bottom: var(--wp--preset--spacing--20, 0.5rem);
	left:   var(--wp--preset--spacing--20, 0.5rem);
	margin: 0;
	padding: 0.15em 0.5em;
	font-family: var(--wp--preset--font-family--body, inherit);
	font-size: 0.75rem;
	line-height: 1.2;
	letter-spacing: 0.04em;
	background: rgba(0, 0, 0, 0.75);
	color: #fff;
	border-radius: 2px;
}
.tec-video-card__badge:empty { display: none; }

/* Card billing — full cast text remains in DOM (a11y / SEO); visually
   clamped to 2 lines to keep card heights consistent across a grid.
   Holt 2026-05-08. Per Alfonso post all-cast uncap: long casts (e.g.
   Garsington/Ulisse, 18 names) must not push a card taller than its
   siblings. Self-regulating across viewports — narrow shows fewer
   names, wide shows more. */
.tec-video-card__billing,
.tec-event-card__billing {
	margin: 0;
	color: var(--wp--preset--color--ink-soft, currentColor);
	font-family: var(--wp--preset--font-family--body, inherit);
	display: -webkit-box;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 2;
	line-clamp: 2;
	overflow: hidden;
}
.tec-video-card__billing:empty,
.tec-event-card__billing:empty { display: none; }

.tec-video-card__filmed {
	margin: 0;
	color: var(--wp--preset--color--ink-mute, var(--wp--preset--color--ink-soft, currentColor));
	font-family: var(--wp--preset--font-family--body, inherit);
	font-size: 0.8125rem;
	line-height: 1.4;
}
.tec-video-card__filmed:empty { display: none; }

/* H4A skin */
body.is-programme-handel-for-all .tec-archive-video {
	background: var(--wp--preset--color--light-blue, #eaf2fa);
}
/* Empty-state — installment approximate_duration.
 * Single Work renders this line conditionally in PHP, but the
 * `tec/work-installment-band` editor-preview pattern shell and any
 * future Block-Binding surface will emit `<p class="tec-meta-duration"></p>`
 * verbatim when the bound field is empty. Collapse it.
 */
.tec-meta-duration:empty {
	display: none;
}

/* =========================================================================
 * Production refactor — minimum structural CSS
 * ========================================================================= */

/* Single Production layout
 * Phase 4 (band refactor) deleted: .tec-single-production { padding-inline },
 * .tec-production-header { padding }, .tec-production-description { padding },
 * .tec-production-description__inner { max-width: prose },
 * and the shared { padding; border-top } block on videos/events/recordings.
 * Universal `.tec-band` + `.tec-band-inner` (bands.css) supplies gutter,
 * vertical rhythm, prose cap (via --prose modifier), and editorial-sheet
 * hairline. The rules below are inner-content concerns only. */
.tec-production-header__hero { margin: 12px 0; }
.tec-production-header__hero img { width: 100%; height: auto; display: block; }
.tec-production-title { margin: 12px 0 4px; }
/* .tec-production-breadcrumb retired 2026-05-08 — see runbook. */
.tec-production-meta { color: var(--wp--preset--color--ink-low-emphasis, #555555); font-size: 0.95em; }

.tec-production-videos__group { margin: 16px 0 24px; }
.tec-production-videos__group-heading { font-size: 1rem; text-transform: uppercase; letter-spacing: 0.04em; margin: 0 0 8px; }
.tec-production-videos__list,
.tec-production-events__list,
.tec-production-recordings__list { list-style: none; padding: 0; margin: 0; display: grid; gap: 16px; }
/* Grid columns owned by .tec-grid--4up in tokens.css (xl/lg=4, md=3,
 * sm=2, xs=1) — same cascade as .tec-cast-grid (musicians band) directly
 * above on Single Production. Switched from auto-fill minmax(220px,1fr)
 * to fixed 4-up so card width tracks the cast band and individual cards
 * read at musician-band scale. Holt 2026-05-07 (Alfonso review). */
.tec-production-videos__list .tec-video-card a { display: block; text-decoration: none; }
.tec-production-videos__list .tec-video-card__title { display: block; padding-top: 8px; }
/* font-weight removed 2026-05-07 — canonical .tec-video-card__title rule
 * owns weight 700 (Objektiv bold UI register).
 * Hero sizing (display:block; aspect-ratio:16/9; overflow:hidden) and the
 * img cover rule were lifted from this scope to the canonical
 * .tec-video-card__hero / .tec-video-card .wp-block-post-featured-image img
 * rules (style.css ~L1443-1475) on 2026-05-07 (Holt) so every surface
 * consuming tec/video-card gets correct poster sizing — HFA Highlights/
 * Library/Lesser-known were collapsing poster height while the figure
 * overflowed, hiding the title. */
/* Production card (used on archive + Single Work rollup) */
.tec-production-card { padding: 0; }
.tec-production-card__hero img { width: 100%; height: auto; display: block; aspect-ratio: 4/3; object-fit: cover; }
.tec-production-card__title { margin: 8px 0 4px; }
.tec-production-card__date,
.tec-production-card__venue { margin: 0; color: var(--wp--preset--color--ink-low-emphasis, #555555); }
.tec-production-card__date:empty,
.tec-production-card__venue:empty { display: none; }

/* Productions archive */
.tec-archive-production { max-width: var(--tec-width-wide); margin-inline: auto; padding-inline: var(--tec-gutter); }
.tec-productions-archive-grid { padding: 24px 0; }

/* Single Work — Productions rollup
 * Phase 5 (2026-05-06, Holt): the per-band `padding: 24px 0` + border-top
 * are removed — the universal `.tec-band` rule owns padding, and the
 * pattern can opt into the hairline via `tec-band--editorial-sheet` if
 * editorially desired (currently not applied — productions sits between
 * white bands and reads cleanly without an extra hairline). Only the
 * heading margin (inner-content concern) remains. */
.tec-work-productions-band__heading { margin: 0 0 16px; }
/* =========================================================================
   Phase 2.2A — Single Recording + Recordings archive + Cast table-row.
   Structural CSS only. No visual polish.
   ========================================================================= */

/* ---- Single Recording header ----
 * Width cap + flex layout owned by assets/css/single-recording.css
 * (canonical home for scoped recording surface rules). PM-5 (2026-05-05)
 * consolidated the prior duplicate `.tec-recording-header__inner` block
 * here — its grid layout was dead (overridden by single-recording.css's
 * flex), and its max-width is now reasserted in the canonical file.
 * Phase 2 of band refactor 2026-05-06: padding-block now owned by the
 * universal `.tec-band` rule (with PM-10 per-class guarantee in
 * single-recording.css). The prior `padding: 32px 0` line was removed. */
.tec-recording-header__cover { aspect-ratio: 1 / 1; overflow: hidden; }
.tec-recording-header__cover img { width: 100%; height: 100%; object-fit: cover; display: block; }
.tec-recording-header__cover-fallback {
	width: 100%; aspect-ratio: 1 / 1;
	background: var(--wp--preset--color--surface-low, #f3f3f0);
}
/* Recording-header eyebrow owned by .tec-eyebrow + .tec-eyebrow--header. */
.tec-recording-header__title {
	font-size: var(--wp--preset--font-size--xx-large, 2.5rem);
	margin: 0 0 12px; line-height: 1.1;
}
.tec-recording-header__metaline {
	font-size: var(--wp--preset--font-size--medium, 16px);
	color: var(--wp--preset--color--ink-low-emphasis, #555555);
	margin: 0 0 20px;
}
.tec-recording-header__cta { margin: 0; }

@media (max-width: 766px) {
	.tec-recording-header__cover { max-width: 320px; }
}

/* PM-7 (2026-05-05) → Phase 2 (2026-05-06): single-recording body band/inner
 * chrome now lives on the universal `.tec-band` / `.tec-band-inner` classes
 * applied to each band's outer/inner in `single-recording.php`. The PM-7
 * Pattern A `.tec-recording-body > *` / `> * > *` rules were retired.
 * See `assets/css/bands.css` and `Linnea_band_universal_refactor_spec.md`. */
.tec-recording-tracklist__body p,
.tec-recording-tracklist__body ol,
.tec-recording-tracklist__body ul { margin: 0 0 12px; }

/* Streaming row */
.tec-recording-streaming__row {
	list-style: none; padding: 0; margin: 0;
	display: flex; flex-wrap: wrap; gap: 12px;
}
/* .tec-recording-streaming__btn — REMOVED 2026-05-05 PM-3 (Holt, Linnea PM-2 §B.1).
 * This rule was scaffold debt: it applied a 1px border + padding directly to the
 * .wp-block-button wrapper that also carries .tec-recording-streaming__btn. The
 * inner .wp-block-button__link now owns the button chrome via is-style-tec-tertiary
 * / is-style-tec-outline (both supply their own 1px border), so the wrapper rule
 * was producing the double-frame visible at /recordings/handel-serse/. Stripped at
 * source per Alfonso's no-bandaid-CSS rule (2026-05-01); .tec-recording-streaming__btn
 * is retained as a markup hook only — no styling. */

/* --- tec/recording-card pattern ----------------------------------------
 * Visual parity with tec/post-card — same is-style-tec-card chrome,
 * same eyebrow/title/excerpt rhythm, same outline CTA. Two recording-
 * specific behaviours layered on top of post-card's recipe:
 *   1. Cover enforced to native 1:1 (recording covers are square art)
 *      via CSS, NOT via the wp:post-featured-image `aspectRatio` block
 *      attribute. Native aspect lives in the CSS per Alfonso's
 *      hub-card validation rule.
 *   2. Whole-card-click — the CTA's ::after stretches inset:0 over the
 *      card root. Single-anchor model: featured image is not a link,
 *      title is not a link. Only the CTA carries the anchor. Same
 *      validation-safe pattern as is-style-tec-hub-card.
 * Recordings archive grid layout owned by .tec-grid--4up in tokens.css. */
.tec-recording-card {
	height: 100%;
	display: flex;
	flex-direction: column;
	position: relative; /* anchor the CTA-link stretched ::after */
}

/* Cover — native 1:1 enforced here, not in the block attribute. The
 * post-featured-image figure (a flex item) needs explicit width:100%
 * for the same eager-load reason documented on .tec-post-card. */
.tec-recording-card .wp-block-post-featured-image {
	margin: 0 0 0.5rem;
	width: 100%;
	aspect-ratio: 1 / 1;
	overflow: hidden;
}
.tec-recording-card .wp-block-post-featured-image a,
.tec-recording-card .wp-block-post-featured-image {
	display: block;
}
.tec-recording-card .wp-block-post-featured-image img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

/* Excerpt — body size token, charcoal. Mirrors .tec-post-card. */
.tec-recording-card .wp-block-post-excerpt,
.tec-recording-card .wp-block-post-excerpt__excerpt {
	font-size: var(--wp--preset--font-size--medium);
	line-height: 1.5;
	color: var(--wp--preset--color--charcoal);
}

/* "Listen now" CTA + stretched-anchor rules retired 2026-05-07 — the
 * recording-card no longer ships a default CTA, and the click affordance
 * is now carried by the title link + image link (mirroring post-card /
 * production-card / work-card). Editorial card_actions render via the
 * shared `.tec-card-actions` rules earlier in this file. The
 * `.tec-recording-card__cta` className is no longer emitted by any
 * pattern. (Alfonso, Wystan rec §3.) */

/* Cast band — table-row variant CSS REMOVED 2026-05-05 PM-2 (Linnea respec).
 * Single Recording flipped to card-grid; table-row branch in cast-list.php has
 * no live caller. CSS retired per the standing rule against dead CSS
 * (Alfonso 2026-05-01). The PHP table-row branch is left in place as harmless
 * dead code for now; a follow-up cleanup will remove it. */

/* ===================================================================
 * Hub composition system — `/support-us` and `/what-we-do`
 *
 * Three patterns share one card chrome variation (`is-style-tec-hub-card`)
 * which is the sibling of `is-style-tec-card` — same surface tokens
 * (--wp--custom--card--*), three additional behaviours: whole-card-clickable,
 * hover lift, focus ring. Layout/grid recipes scoped to the consuming
 * patterns. Per Linnea hub composition spec v2 (2026-05-02), Holt build.
 * =================================================================== */

/* --- Hub-card chrome variation: is-style-tec-hub-card ----------------- */
.wp-block-group.is-style-tec-hub-card {
	background: var(--wp--custom--card--background, var(--wp--preset--color--white));
	border: var(--wp--custom--card--border--width, 1px) solid var(--wp--custom--card--border--color, var(--wp--preset--color--accent-yellow));
	border-radius: var(--wp--custom--card--border--radius, 5px);
	box-shadow: var(--wp--custom--card--shadow, 0 0 8px 0 rgba(5, 47, 103, 0.25));
	padding: var(--wp--custom--card--padding, 1rem);
	position: relative; /* anchor the CTA-link click overlay */
	transition: transform 180ms ease, box-shadow 180ms ease;
}

/* Reset block-gap-injected margins on title + summary without inline styles
 * (inline `style` attrs on core blocks fight Gutenberg's block validator). */
.wp-block-group.is-style-tec-hub-card .tec-hub-card__title,
.wp-block-group.is-style-tec-hub-card .tec-hub-feature-card__title,
.wp-block-group.is-style-tec-hub-card .tec-hub-card__summary,
.wp-block-group.is-style-tec-hub-card .tec-hub-feature-card__summary,
.wp-block-group.is-style-tec-hub-card .tec-hub-feature-card__eyebrow {
	margin-block: 0;
}

/* Whole-card-clickable: the CTA button's anchor stretches via ::after to
 * cover the entire card. Single-anchor model — no nested anchors, no
 * heading-wrapping anchors (which trip core/heading block validation).
 * The overlay is transparent (no fill), so the visible button label and
 * all card content remain visible underneath. Clicks anywhere on the
 * card hit the stretched ::after and fire the CTA link.
 *
 * The button anchor is `position: static` so its ::after resolves against
 * the card root (which carries `position: relative`). On the feature card
 * the *primary* CTA (first button) carries the stretch; the secondary CTA
 * stays scoped to its own button. */
.wp-block-group.is-style-tec-hub-card .tec-hub-card__cta .wp-block-button__link,
.wp-block-group.is-style-tec-hub-card .tec-hub-feature-card__ctas > .wp-block-button:first-child .wp-block-button__link {
	position: static;
}
.wp-block-group.is-style-tec-hub-card .tec-hub-card__cta .wp-block-button__link::after,
.wp-block-group.is-style-tec-hub-card .tec-hub-feature-card__ctas > .wp-block-button:first-child .wp-block-button__link::after {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: inherit;
}
/* Secondary CTA on the feature card must stay above the primary CTA's
 * stretched overlay, otherwise its click is swallowed. */
.wp-block-group.is-style-tec-hub-card .tec-hub-feature-card__ctas > .wp-block-button:not(:first-child) {
	position: relative;
	z-index: 1;
}

/* Hover lift + shadow swap. Suppressed under prefers-reduced-motion. */
@media (hover: hover) {
	.wp-block-group.is-style-tec-hub-card:hover {
		transform: translateY(-2px);
		box-shadow: var(--wp--custom--card--shadow--hover, 0 4px 16px 0 rgba(5, 47, 103, 0.30));
	}
}
@media (prefers-reduced-motion: reduce) {
	.wp-block-group.is-style-tec-hub-card { transition: box-shadow 180ms ease; }
	.wp-block-group.is-style-tec-hub-card:hover { transform: none; }
}

/* Gold focus ring when any descendant focuses (covers title anchor + CTA). */
.wp-block-group.is-style-tec-hub-card:has(:focus-visible) {
	outline: 2px solid var(--wp--preset--color--accent-yellow);
	outline-offset: 3px;
}

/* --- tec/hub-card-grid layout ----------------------------------------- *
 * Explicit 2-col ladder, NOT the default tec-grid--4up cascade (which
 * would step through 4 -> 3 -> 2 -> 1). Per Linnea spec §2: 2x2 from md
 * up; 1x4 below md.
 */
.tec-hub-card-grid {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: var(--wp--preset--spacing--40, 1.5rem);
}
@media (min-width: 1200px) { .tec-hub-card-grid { gap: 2rem; } }
@media (max-width: 766px)  { .tec-hub-card-grid { grid-template-columns: 1fr; gap: 1.25rem; } }
@media (max-width: 479px)  { .tec-hub-card-grid { gap: 1rem; } }

/* Card stretches to row height so all four bottoms align even when
 * summary copy length varies. */
.tec-hub-card {
	height: 100%;
}
.tec-hub-card__body {
	flex: 1 1 auto;
}
/* Push the CTA to the foot of the card. */
.tec-hub-card__cta { margin-top: auto; }

/* Image: respect the 3:2 aspect attribute; fill the card width. */
.tec-hub-card .wp-block-image,
.tec-hub-card .wp-block-image img {
	width: 100%;
	display: block;
}
.tec-hub-card .wp-block-image img {
	height: auto;
	object-fit: cover;
}

/* CTA full-width below xs. */
@media (max-width: 479px) {
	.tec-hub-card .wp-block-button,
	.tec-hub-card .wp-block-button__link { width: 100%; }
}

/* --- tec/hub-feature-card layout -------------------------------------- *
 * Horizontal at md+ (image left ~60% / body right ~40%); stacked below md.
 */
/* Default to stacked below md. The pattern's wp:group layout emits a
 * higher-specificity rule for horizontal flex (.wp-block-group + layout
 * scope). We match it via .wp-block-group.tec-hub-feature-card to win the
 * cascade tie cleanly without !important. */
.wp-block-group.tec-hub-feature-card {
	flex-direction: column;
}
.tec-hub-feature-card {
	gap: 0;
	padding: 0; /* image bleeds to the card edge; body owns its own padding */
	overflow: hidden; /* clip the image to the card's border-radius */
}
.tec-hub-feature-card .tec-hub-feature-card__image,
.tec-hub-feature-card .tec-hub-feature-card__image img {
	width: 100%;
	display: block;
	margin: 0;
}
.tec-hub-feature-card .tec-hub-feature-card__image img {
	height: 100%;
	object-fit: cover;
	/* Aspect ratio owned by CSS (not block JSON) so it can flip 3/2 (sm-)
	 * to 16/9 (md+) without an !important fight against an inline value. */
	aspect-ratio: 3 / 2;
}
@media (min-width: 767px) {
	.tec-hub-feature-card .tec-hub-feature-card__image img {
		aspect-ratio: 16 / 9;
	}
}
.tec-hub-feature-card__body {
	padding: var(--wp--preset--spacing--40, 1.5rem);
}

@media (min-width: 767px) {
	.wp-block-group.tec-hub-feature-card {
		flex-direction: row;
	}
	.tec-hub-feature-card .tec-hub-feature-card__image {
		flex: 0 0 55%;
		max-width: 55%;
	}
	.tec-hub-feature-card__body {
		flex: 1 1 45%;
		padding: var(--wp--preset--spacing--50, 2rem);
	}
}
@media (min-width: 979px) {
	.tec-hub-feature-card .tec-hub-feature-card__image {
		flex: 0 0 60%;
		max-width: 60%;
	}
	.tec-hub-feature-card__body {
		flex: 1 1 40%;
	}
}

/* Print: drop chrome bling on hub cards. Selector specificity matches the
 * background-paint rule (.wp-block-group.has-navy-background-color), no
 * !important needed. */
@media print {
	.wp-block-group.is-style-tec-hub-card {
		box-shadow: none;
		transform: none;
	}
	section.tec-support-section.has-navy-background-color {
		background: transparent;
		color: #000;
	}
}

/* ===================================================================
 * Accordion toggles (core/details)
 *
 * Replicates the prod (Cornerstone .x-acc-header) treatment for the
 * core/details block. Used on /about-us/our-history/ "Former musicians"
 * section and any future page that authors a core/details block.
 *
 * Spec sources: prod computed styles audited via
 * scripts/audit/measure-accordion-toggles.js (2026-05-02).
 *   summary closed: white bg, near-black text, sans-heading uppercase
 *                   weight 700 with 0.1em tracking, padding 15px 20px
 *   summary hover : accent-yellow bg, white text
 *   indicator     : "+" closed, "−" open, left of label
 *   transition    : color/background 0.3s ease
 *
 * Native <details>/<summary> behaviour is preserved (multiple open
 * allowed, keyboard accessible). The default browser disclosure
 * triangle is suppressed and replaced by a tokenised "+/−" pseudo.
 * =================================================================== */
/* Each <details> is a rounded pill/card. Border + radius live on the
 * parent so the summary row and (when expanded) the content panel
 * share one continuous rounded silhouette — overflow:hidden clips the
 * inner backgrounds to the parent's radius, which sidesteps the
 * "summary corner doesn't meet panel corner" problem on open.
 *
 * Sibling rhythm: do NOT set margin-block-end here. The parent layout
 * (Gutenberg is-layout-constrained) auto-injects
 * `margin-block-start: var(--wp--style--block-gap)` (24px default) on
 * every `> * + *`. An explicit margin-block-end on the toggle would
 * collapse against that and the larger value wins, masking the fix.
 * Instead, override the auto-injected sibling spacing directly with a
 * token from the TEC scale — see `.wp-block-details + .wp-block-details`
 * below. */
.wp-block-details {
	border: 1px solid var(--wp--preset--color--accent-yellow);
	border-radius: var(--wp--custom--card--border--radius, 5px);
	overflow: hidden;
	background-color: var(--wp--preset--color--white);
}
/* Tight related-items rhythm between consecutive toggle pills.
 * Beats Gutenberg's `is-layout-constrained > * + *` injected 24px
 * because this selector has the same specificity but appears later in
 * the cascade, AND uses a more specific element-type chain (details +
 * details) than the layout rule's universal sibling. */
.wp-block-details + .wp-block-details {
	margin-block-start: var(--wp--preset--spacing--20);
}
.wp-block-details > summary {
	list-style: none;          /* suppress default marker (FF) */
	cursor: pointer;
	display: flex;
	align-items: center;
	gap: 0.75rem;
	position: relative;        /* anchor for indicator pseudo-elements */
	padding-block: var(--wp--preset--spacing--30);
	padding-inline-start: var(--wp--preset--spacing--40);
	/* Reserve inline-end space so title text never collides with the
	 * absolutely-positioned indicator at the right edge. */
	padding-inline-end: calc(var(--wp--preset--spacing--40) + 0.85em + 0.5rem);
	background-color: var(--wp--preset--color--white);
	color: var(--wp--preset--color--near-black);
	font-family: var(--wp--preset--font-family--sans-heading);
	font-size: var(--wp--preset--font-size--medium);
	font-weight: 700;
	line-height: 1.3;
	text-transform: uppercase;
	letter-spacing: 0.1em;
	transition:
		color 0.3s cubic-bezier(0.4, 0, 0.2, 1),
		background-color 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.wp-block-details > summary::-webkit-details-marker { display: none; }
/* Indicator drawn as two crossing line pseudo-elements anchored at the
 * inline-end of the summary (right edge in LTR). Closed = "+" (both bars
 * visible). Open = "−" (vertical bar hidden via scaleY(0) on ::after).
 * Hover (any state) = "×" (both bars rotate 45deg, vertical bar
 * forced back visible). Both bars are absolutely positioned against
 * the summary, so transforms on each are independent. */
.wp-block-details > summary::before,
.wp-block-details > summary::after {
	content: "";
	position: absolute;
	inset-inline-end: var(--wp--preset--spacing--40);
	inset-block-start: 50%;
	background-color: currentColor;
	transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
.wp-block-details > summary::before {
	/* Horizontal bar — also the rotation carrier for the × state. */
	inline-size: 0.85em;
	block-size: 2px;
	margin-block-start: -1px;
	transform: translateX(0) rotate(0deg);
}
.wp-block-details > summary::after {
	/* Vertical bar — hidden when [open] to render "−". */
	inline-size: 2px;
	block-size: 0.85em;
	margin-inline-end: calc((0.85em - 2px) / 2);
	margin-block-start: calc(-0.85em / 2);
	transform: scaleY(1);
}
.wp-block-details[open] > summary::after { transform: scaleY(0); }
/* Hover (any state): show both bars and rotate the cross to ×. The
 * scaleY(1) on ::after wins over the [open] scaleY(0) via source order
 * since the hover rule comes after — same-specificity, later wins. */
.wp-block-details > summary:hover::before,
.wp-block-details > summary:focus-visible::before {
	transform: rotate(45deg);
}
.wp-block-details > summary:hover::after,
.wp-block-details > summary:focus-visible::after {
	transform: rotate(-45deg) scaleY(1);
}
/* Hover and open both render the gold/white treatment. Open + hover
 * naturally inherits via the [open] rule (no extra selector needed). */
.wp-block-details > summary:hover,
.wp-block-details > summary:focus-visible,
.wp-block-details[open] > summary {
	background-color: var(--wp--preset--color--accent-yellow);
	color: var(--wp--preset--color--white);
	outline: none;
}
/* Expanded content panel — white bg, near-black body type. */
.wp-block-details[open] > :not(summary) {
	padding-block: var(--wp--preset--spacing--30);
	padding-inline: var(--wp--preset--spacing--40);
	background-color: var(--wp--preset--color--white);
	color: var(--wp--preset--color--near-black);
	font-size: var(--wp--preset--font-size--small);
	line-height: 1.7;
	/* Zero own margin: the panel element (often a <p>) carries a default
	 * block-start margin from prose styles which compounds with the
	 * panel's padding-block, producing extra space at the top of the
	 * expanded region. Fix at the root. */
	margin-block-start: 0;
}
/* If the content panel is a wrapper (group/list), normalise its first
 * child's top margin too so wrapped paragraphs/lists don't reintroduce
 * the gap. */
.wp-block-details[open] > :not(summary) > :first-child {
	margin-block-start: 0;
}


/* ==========================================================================
   Portrait-card composition — is-style-tec-portrait-card
   --------------------------------------------------------------------------
   Sibling of `is-style-tec-card`. Same chrome (border, radius, shadow,
   padding, white bg) drawn from `--wp--custom--card--*`. Differentiator:
   the image inside renders 3:4 portrait via `object-fit: cover`, and the
   caption typography below uses Orpheus Pro for the name + Objektiv for
   the eyebrow / sublabel.

   Replaces the legacy social-circle treatment for people imagery
   (musicians archive, single musician hero, event cast cards, board /
   leadership). Per Linnea's People Imagery audit (Alternative 1),
   sign-off Alfonso 2026-05-04. Holt 2026-05-04.
   ========================================================================== */
.wp-block-group.is-style-tec-portrait-card {
	background: var(--wp--custom--card--background, var(--wp--preset--color--white));
	border: var(--wp--custom--card--border--width, 1px) solid var(--wp--custom--card--border--color, var(--wp--preset--color--accent-yellow));
	border-radius: var(--wp--custom--card--border--radius, 5px);
	box-shadow: var(--wp--custom--card--shadow, 0 0 8px 0 rgba(5, 47, 103, 0.25));
	padding: var(--wp--custom--card--padding, 1rem);
	transition: transform 180ms ease, box-shadow 180ms ease;
	height: 100%;
}

/* Portrait image: 3:4 frame, edge-to-edge inside the card (figure margin
 * zeroed), centred-crop via object-fit. Existing square photo masters
 * fit cleanly; tighter shoulder crops are acceptable interim — the
 * editorial polish step is re-cropping originals from photography
 * (content work, not dev scope). */
.wp-block-group.is-style-tec-portrait-card .wp-block-post-featured-image,
.wp-block-group.is-style-tec-portrait-card figure.wp-block-image {
	margin-block: 0 var(--wp--preset--spacing--30, 0.75rem);
	margin-inline: 0;
	width: 100%;
}
.wp-block-group.is-style-tec-portrait-card .wp-block-post-featured-image a,
.wp-block-group.is-style-tec-portrait-card figure.wp-block-image a {
	display: block;
	width: 100%;
}
.wp-block-group.is-style-tec-portrait-card .wp-block-post-featured-image img,
.wp-block-group.is-style-tec-portrait-card figure.wp-block-image img {
	width: 100%;
	height: auto;
	aspect-ratio: 3 / 4;
	object-fit: cover;
	display: block;
}

/* Hover lift + shadow swap, mirror of `.is-style-tec-card`. Suppressed
 * under prefers-reduced-motion. :focus-within mirrors hover for
 * keyboard users. */
@media (hover: hover) {
	.wp-block-group.is-style-tec-portrait-card:hover,
	.wp-block-group.is-style-tec-portrait-card:focus-within {
		transform: translateY(-2px);
		box-shadow: var(--wp--custom--card--shadow--hover, 0 4px 16px 0 rgba(5, 47, 103, 0.30));
	}
}
@media (prefers-reduced-motion: reduce) {
	.wp-block-group.is-style-tec-portrait-card { transition: box-shadow 180ms ease; }
	.wp-block-group.is-style-tec-portrait-card:hover,
	.wp-block-group.is-style-tec-portrait-card:focus-within { transform: none; }
}

.wp-block-group.is-style-tec-portrait-card:has(:focus-visible) {
	outline: 2px solid var(--wp--preset--color--accent-yellow);
	outline-offset: 3px;
}

/* ==========================================================================
   Band-stacked main wrappers — flush layout
   --------------------------------------------------------------------------
   GeneratePress parent ships:
       .separate-containers .site-main { margin: 20px; }
       .site-main > *                   { margin-bottom: 20px; }
       .tec-site-footer                 { margin-block-start: spacing-90; }
   Those rules assume a contained-article presentation (article centred in a
   max-width column with breathing room around it). On TEC's full-bleed
   single-musician / archive / single-{video,production,work,recording,event}
   templates the layout is band-stacked: each direct child of <main> is an
   alignfull section that owns its own padding-block and paints to the
   viewport edges. The parent rules introduce a 20px hairline above <main>
   (gap below the site nav), 20px gaps between every band, and a tall
   pre-footer void from the footer's spacing-90 margin-top.
   Fix at the root: any <main> whose first/any direct child is .alignfull
   (the band signature) becomes a band-stack — zero its outer margin and
   its children's vertical margins. The footer's margin-top is dropped
   site-wide because its preceding section (always a band on TEC pages
   that auto-render tec/support-section, or the post body otherwise)
   owns its own padding-block.
   Holt 2026-05-04. */
main#main:has(> .alignfull) {
	margin-block: 0;
}
main#main:has(> .alignfull) > * {
	margin-block-end: 0;
}
.tec-site-footer {
	margin-block-start: 0;
}
