/*
Theme Name: Lychgate Funerals
Theme URI: https://weave.co.nz
Author: Weave Digital Studio
Author URI: https://weave.co.nz
Description: Lychgate Funerals block theme. Presentation only, site behaviour lives in the weave-site-functions plugin.
Requires at least: 7.0
Tested up to: 7.1
Requires PHP: 8.1
Version: 0.5.49
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: weave-blocks
Tags: block-patterns, full-site-editing, one-column, custom-colors, custom-logo, editor-style, wide-blocks
*/

/*
 * Custom CSS policy (CLAUDE.md hard rule 5): everything that can be a token or a block support lives in theme.json.
 * Each rule below names the block limitation it works around so it can be counted as FSE friction. Rule codes
 * (H1, Q1, CS3 and so on) match the weave-blocks reference theme, where each was measured and logged.
 */

/* ------------------------------------------------------------------
 * Site frame (stage 4): header, mega menus, mobile menu, footer. Spec docs/stage-4-spec.md, ported
 * from DEVORA's HD, MP and OV rules and re-skinned. "Top row" means the header navs' own list
 * (`.lychgate-header__nav ... -content > ul > li`), never the panel or overlay navs inside it.
 * Breakpoint: the desktop row from 1300px, the phone bar and overlay below it (LH5).
 * ------------------------------------------------------------------ */

/* LH1. Sticky header. Core's sticky works only on a Group at the root of a template; a part renders
 *      inside a <header class="wp-block-template-part"> wrapper, so sticky goes on the wrapper, below
 *      the admin bar. No overflow, transform or filter on it: they would clip the panels and trap
 *      core's fixed overlay. Anchors and focus land below the bar (WCAG 2.4.11). */
header.wp-block-template-part:has(> .lychgate-header) { position: sticky; top: var(--wp-admin--admin-bar--height, 0px); z-index: 20; }
html:has(header.wp-block-template-part > .lychgate-header) { scroll-padding-top: var(--wp--custom--header--height); }

/* LH2. A page that opens with a hero (stage 5 heroes carry .lychgate-hero) slides it up under the
 *      transparent header; markup cannot know what a page leads with. Without :has() the hero starts
 *      below the bar. The hero's own top padding clears the header. */
.wp-site-blocks:has(> main > .lychgate-hero:first-child, > main > .wp-block-post-content > .lychgate-hero:first-child) > header.wp-block-template-part { margin-block-end: calc(-1 * var(--wp--custom--header--height)); }

/* LH3. Transparent at the top of the page, solid white with the header shadow and shorter once
 *      scrolled (Figma 278:3106, Manu's pinned header). Core sticky has no scroll state, so this is a
 *      CSS scroll-driven animation; browsers without animation-timeline get a solid bar. While a mega
 *      panel is open the bar is white as Figma draws it (!important: an animated value outranks any
 *      normal declaration). The bar is the panels' containing block (LH8). */
.lychgate-header { position: relative; background-color: var(--wp--preset--color--surface); }
@supports (animation-timeline: scroll()) {
	.lychgate-header,
	.lychgate-logo > *,
	.lychgate-header__nav .wp-block-navigation__responsive-container-content > ul > li > .wp-block-navigation-item__content,
	.lychgate-header__links .wp-block-navigation-item__content { animation: linear both; animation-timeline: scroll(); animation-range: 0 160px; }
	.lychgate-header { background-color: transparent; animation-name: lychgate-header-stick; }
	@keyframes lychgate-header-stick {
		to {
			background-color: var(--wp--preset--color--surface);
			box-shadow: var(--wp--preset--shadow--header);
			padding-block: calc((var(--wp--custom--header--height-shrunk) - var(--wp--custom--header--logo-width-shrunk) * 1.1794) / 2);
		}
	}
}
.lychgate-header:has([aria-expanded="true"]:not(.wp-block-accordion-heading__toggle)) { background-color: var(--wp--preset--color--surface) !important; }

/* LH4. Logo swap: the full logo at the top, the mark once scrolled (Figma's scrolled variant). Both
 *      sit in one grid cell; the full logo shrinks to the mark's width as it hides, so the bar can shrink
 *      to its token height. visibility also takes the hidden one out of the tab order. */
.lychgate-logo { display: grid; align-items: center; justify-items: start; }
.lychgate-logo > * { grid-area: 1 / 1; margin: 0; }
.lychgate-logo__full { width: var(--wp--custom--header--logo-width); }
.lychgate-logo__full img { width: 100% !important; } /* follows the figure (LH5 narrows it on phones); the inline width is the block's */
.lychgate-logo__mark { visibility: hidden; }
@supports (animation-timeline: scroll()) {
	.lychgate-logo__full { animation-name: lychgate-logo-out; }
	.lychgate-logo__mark { animation-name: lychgate-logo-in; }
	@keyframes lychgate-logo-out { 0%, 60% { visibility: visible; } 61%, 100% { visibility: hidden; width: var(--wp--custom--header--logo-width-shrunk); } }
	@keyframes lychgate-logo-in { 0%, 60% { visibility: hidden; } 61%, 100% { visibility: visible; } }
}

/* LH5. The desktop row (eight items, search and the Call button beside the logo) needs 1379px at
 *      Figma's 30px gaps, and 1290 with LH10's fluid gaps, so the phone bar takes over below 1300
 *      (Manu switches at about 1340). Core's switch is hard-coded at 600; its two rules are restated
 *      for 600 to 1299. Below 1300 the bar is Figma 278:3342: call icon, centred logo, menu
 *      button; core has no per-breakpoint visibility for the row's other blocks. The bar keeps the part's
 *      20px padding (106 tall with the 100px logo token; Figma's 115 has a 117px logo) and shrinks
 *      to the 90px token with the mark. */
@media (min-width: 600px) and (max-width: 1299px) {
	.lychgate-header__nav .wp-block-navigation__responsive-container:not(.hidden-by-default):not(.is-menu-open) { display: none; }
	.lychgate-header__nav .wp-block-navigation__responsive-container-open:not(.always-shown) { display: flex; }
}
@media (max-width: 1299px) {
	.lychgate-header.wp-block-group { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); }
	@supports (animation-timeline: scroll()) {
		.lychgate-header { animation-name: lychgate-header-stick-phone; }
		@keyframes lychgate-header-stick-phone {
			to {
				background-color: var(--wp--preset--color--surface);
				box-shadow: var(--wp--preset--shadow--header);
				padding-block: calc((var(--wp--custom--header--height-mobile-shrunk) - var(--wp--custom--header--logo-width-shrunk) * 1.1794) / 2);
			}
		}
	}
	.lychgate-header .lychgate-logo { justify-items: center; }
	.lychgate-header .lychgate-logo__full { width: var(--wp--custom--header--logo-width-mobile); }
	.lychgate-header__row { justify-self: end; }
	.lychgate-header__row > :not(.lychgate-header__nav) { display: none; }
}
@media (min-width: 1300px) {
	.lychgate-header .lychgate-header__call-icon { display: none; }
}

/* LH6. Top row items: Manrope 500 in text-muted (block attributes), padded so each item is as tall as
 *      the logo row and the state bar (LH7) sits on its bottom edge, 20 above the bar's (Figma 960:3025).
 *      Core Navigation has no item padding control. Shrinks with the bar. */
.lychgate-header__nav .wp-block-navigation__responsive-container-content > ul > li > .wp-block-navigation-item__content,
.lychgate-header__links .wp-block-navigation-item__content { padding-block: calc((var(--wp--custom--header--logo-width) * 0.6592 - 1.5rem) / 2); white-space: nowrap; }
.lychgate-header__call .wp-block-button__link { white-space: nowrap; }
@supports (animation-timeline: scroll()) {
	.lychgate-header__nav .wp-block-navigation__responsive-container-content > ul > li > .wp-block-navigation-item__content,
	.lychgate-header__links .wp-block-navigation-item__content { animation-name: lychgate-item-shrink; }
	@keyframes lychgate-item-shrink { to { padding-block: calc((var(--wp--custom--header--logo-width-shrunk) * 1.1794 - 1.5rem) / 2); } }
}

/* LH10. Top row gaps: Figma's 30 at 1440, closing to 20 at 1300 so the row still fits beside the
 *      logo. blockGap takes one spacing preset; none runs over this range. */
@media (min-width: 1300px) {
	.lychgate-header.wp-block-group,
	.lychgate-header__row.wp-block-group,
	.lychgate-header__nav .wp-block-navigation__responsive-container-content > .wp-block-navigation__container { gap: clamp(1.25rem, (100vw - 1300px) * 0.0714 + 1.25rem, 1.875rem); }
}

/* LH11. Desktop labels (Gareth, 28 Oct 2026): the site plan's full labels (Our Services, Our Venues,
 *      Pre-Planning, About Us) where the row has room, Figma's short ones (Services, Venues, Pre-plan,
 *      About us) from 1300 up to the width where the full row fits beside the logo, 1480 (the full row needs 1470; measured, decisions
 *      2026-10-28). One link or toggle per item: the short span is aria-hidden and the full span stays
 *      in the accessibility tree, visually hidden, so the name is the full label at every width. The
 *      phone and tablet overlay is its own part and always shows the full labels. */
.lychgate-nav-label__short { display: none; }
@media (min-width: 1300px) and (max-width: 1479.98px) {
	.lychgate-header__nav .lychgate-nav-label__short { display: inline; }
	.lychgate-header__nav .lychgate-nav-label__full { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }
}

/* LH7. Top row hover, focus, open and current: label accent-strong with Figma's 2px Aqua bar under the
 *      item. Core pins nav link colour to inherit at (0,3,0); Menu Designer gives a toggle no ancestor
 *      class, so a section lights from the page's body classes (children of Services 3, Venues 14,
 *      Resources 20, About Us 28; FAQs 22 is top level, Our Community is the posts page). Figma's Aqua
 *      label is 2.92:1 (decisions 2026-10-27, pending exception). */
.lychgate-header__nav .wp-block-navigation__responsive-container-content > ul > li > .wp-block-navigation-item__content:is(:hover, :focus-visible, [aria-expanded="true"]),
.lychgate-header__nav .wp-block-navigation__responsive-container-content > ul > li.current-menu-item > .wp-block-navigation-item__content,
.lychgate-header__links .wp-block-navigation-item__content:is(:hover, :focus-visible, [aria-current="page"]),
:is(.page-id-3, .parent-pageid-3) .lychgate-header__nav .wp-block-navigation__responsive-container-content > ul > li:has(> [aria-controls="mega-menu-1-dropdown"]) > .wp-block-navigation-item__content,
:is(.page-id-14, .parent-pageid-14) .lychgate-header__nav .wp-block-navigation__responsive-container-content > ul > li:has(> [aria-controls="mega-menu-2-dropdown"]) > .wp-block-navigation-item__content,
:is(.page-id-20, .parent-pageid-20, .page-id-22) .lychgate-header__nav .wp-block-navigation__responsive-container-content > ul > li:has(> [aria-controls="mega-menu-3-dropdown"]) > .wp-block-navigation-item__content,
:is(.page-id-28, .parent-pageid-28, .blog, .single-post) .lychgate-header__nav .wp-block-navigation__responsive-container-content > ul > li:has(> [aria-controls="mega-menu-4-dropdown"]) > .wp-block-navigation-item__content {
	color: var(--wp--preset--color--accent-strong);
	box-shadow: inset 0 calc(-1 * var(--wp--custom--menu--rule)) 0 var(--wp--preset--color--accent);
}

/* LH8. Mega toggle arrow: Menu Designer hard-codes a 12px stroked chevron that turns over when open;
 *      Figma draws a small filled triangle after the label, never rotated. */
.lychgate-header .wp-block-ollie-mega-menu__toggle.wp-block-navigation-item__content { display: inline-flex; align-items: center; gap: var(--wp--preset--spacing--10); }
.lychgate-header .wp-block-ollie-mega-menu__toggle .wp-block-ollie-mega-menu__toggle-icon {
	width: var(--wp--custom--menu--arrow);
	height: var(--wp--custom--menu--arrow);
	margin: 0;
	transform: none;
	background-color: currentColor;
	-webkit-mask: url("assets/images/caret-fill.svg") center / contain no-repeat;
	mask: url("assets/images/caret-fill.svg") center / contain no-repeat;
}
.lychgate-header .wp-block-ollie-mega-menu__toggle .wp-block-ollie-mega-menu__toggle-icon svg { display: none; }

/* HD12 (DEVORA). The panel hangs from the header, not from its menu item. Menu Designer sets an
 *      inline top, left and width it measures at load and on resize, which goes stale (DEVORA, iPad
 *      offset, 30 Sep). With the item, list and nav wrappers static on desktop, the containing block is
 *      the full-width .lychgate-header (LH3), so the panel sits at its bottom edge, full width,
 *      whatever the script measured, and follows the bar as it shrinks. */
@media (min-width: 1300px) {
	.lychgate-header .lychgate-header__row :is(.wp-block-navigation, .wp-block-navigation__responsive-container:not(.is-menu-open), .wp-block-navigation__responsive-dialog, .wp-block-navigation__container, .wp-block-ollie-mega-menu) { position: static; }
	.lychgate-header .wp-block-ollie-mega-menu__menu-container { top: 100% !important; left: 0 !important; width: 100% !important; max-width: none !important; margin: 0; }
}

/* HD7 (DEVORA). Menu Designer's panel close button fades in over a blurred white square with a black
 *      X whenever the pointer is over the panel. Figma draws none, so it shows for keyboard focus
 *      only, top right of the panel. */
.lychgate-header .wp-block-ollie-mega-menu__menu-container .menu-container__close-button {
	top: var(--wp--preset--spacing--20);
	right: var(--wp--custom--width--gutter);
	background-color: var(--wp--preset--color--surface);
	backdrop-filter: none;
}
.lychgate-header .wp-block-ollie-mega-menu__menu-container .menu-container__close-button:not(:focus-visible) { opacity: 0; }
.lychgate-header .wp-block-ollie-mega-menu__menu-container .menu-container__close-button svg { fill: var(--wp--preset--color--primary); }

/* HD13 (DEVORA). Reduced motion: Menu Designer's own rule drops only the slide and keeps its fade. */
@media (prefers-reduced-motion: reduce) {
	.lychgate-header .wp-block-ollie-mega-menu .wp-block-ollie-mega-menu__toggle[aria-expanded] ~ .wp-block-ollie-mega-menu__menu-container { transition: none; }
}

/* LH9. Header search (core Search, button only) and the phone bar's call icon: icon-only, 44px targets,
 *      no button fill. Core Search's button carries a grey border and padding at (0,1,0); the icon
 *      button style draws its glyph after the text, so the label is set to 0 size (it stays the
 *      accessible name). Phone icon Figma Aqua, built accent-strong (Aqua is 2.92:1, under 3:1 for UI). */
.lychgate-header__search .wp-block-search__button { width: var(--wp--custom--overlay--button); height: var(--wp--custom--overlay--button); align-items: center; padding: 0; border: 0; background: none; color: var(--wp--preset--color--text-muted); }
.lychgate-header__call-icon .wp-block-button__link.wp-element-button,
.lychgate-header__call-icon .wp-block-button__link.wp-element-button:is(:hover, :focus) { width: var(--wp--custom--overlay--button); height: var(--wp--custom--overlay--button); justify-content: center; padding: 0; font-size: 0; background: none; color: var(--wp--preset--color--accent-strong); }
.lychgate-header .lychgate-header__call-icon .is-style-icon-phone .wp-block-button__link::after { width: var(--wp--custom--overlay--icon); height: var(--wp--custom--overlay--icon); }

/* HD9 (DEVORA). Menu and close buttons: the theme's two-bar menu and X glyphs (Figma 278:3342) in a
 *      44 target, as masks over currentColor. Core's `menu` icon is three short bars. */
.lychgate-header__nav .wp-block-navigation__responsive-container-open,
.lychgate-overlay__close.wp-block-navigation-overlay-close { width: var(--wp--custom--overlay--button); height: var(--wp--custom--overlay--button); align-items: center; justify-content: center; padding: 0; }
.lychgate-header__nav .wp-block-navigation__responsive-container-open { color: var(--wp--preset--color--accent-strong); }
.lychgate-header__nav .wp-block-navigation__responsive-container-open svg,
.lychgate-overlay__close svg { display: none; }
.lychgate-header__nav .wp-block-navigation__responsive-container-open::before,
.lychgate-overlay__close::before {
	content: "";
	width: var(--wp--custom--overlay--icon);
	height: var(--wp--custom--overlay--icon);
	background-color: currentColor;
	-webkit-mask: url("assets/icons/menu.svg") center / contain no-repeat;
	mask: url("assets/icons/menu.svg") center / contain no-repeat;
}
.lychgate-overlay__close::before { -webkit-mask-image: url("assets/icons/x.svg"); mask-image: url("assets/icons/x.svg"); width: calc(var(--wp--custom--overlay--icon) * 0.75); height: calc(var(--wp--custom--overlay--icon) * 0.75); }

/* MP1. Panel tiles (Figma 283:6065): one link per tile, the label, stretched over the photo so the
 *      whole tile is the target. White labels without an underline until hover; LK1 underlines links
 *      in a surface-inverse band at (0,1,0). Core Image cannot link and leave a single link. */
.lychgate-tile { position: relative; }
.lychgate-tile .wp-block-image img { width: 100%; } /* a portrait source in a landscape tile (About) is narrower than the tile at its medium size */
.lychgate-tile__label a { color: inherit; font-weight: var(--wp--custom--font-weight--body); text-decoration: none; }
.lychgate-tile__label a::after { content: ""; position: absolute; inset: 0; }
.lychgate-tile__label a:is(:hover, :focus-visible) { text-decoration: underline; }

/* MP2. Panel and footer menu links: white, no underline until hover, the hub row bold (Figma's Aqua
 *      hub is about 2.0:1 on the primary blue). Same LK1 reason as MP1; core pins nav colours. */
:is(.lychgate-mega, .lychgate-overlay, .lychgate-footer) .wp-block-navigation .wp-block-navigation-item__content { text-decoration: none; }
:is(.lychgate-mega, .lychgate-overlay, .lychgate-footer) .wp-block-navigation .wp-block-navigation-item__content:is(:hover, :focus-visible) { text-decoration: underline; }
:is(.lychgate-mega, .lychgate-overlay) .lychgate-nav-hub > .wp-block-navigation-item__content { font-weight: var(--wp--custom--font-weight--bold); }

/* OV1. Mobile menu (Figma 289:9410, Manu's overlay): the head centres the logo with the close button
 *      at the right edge, and the logo narrows to the phone width; core has no per-part logo size. */
.lychgate-overlay__head { position: relative; }
.lychgate-overlay__head .lychgate-overlay__close { position: absolute; right: 0; top: 0; }
.lychgate-overlay .lychgate-logo-reversed img { width: var(--wp--custom--header--logo-width-mobile) !important; }

/* OV2. Rows: each top-level row (a link list or an accordion heading) sits between faint rules,
 *      Figma's 1px lines; core Navigation and Accordion have no per-item border. Rows are full width,
 *      labels, plus and close in surface-raised (Manu's primary-subtle is 3.56:1 and the rows are under
 *      24px on phones; Figma's Aqua plus and close are 2.0:1). One line height for
 *      link rows and accordion rows, so every row is the same height. */
.lychgate-overlay__list > .lychgate-overlay__links .wp-block-navigation-item,
.lychgate-overlay__list .lychgate-overlay__accordion > .wp-block-accordion-item { border-bottom: 1px solid color-mix(in srgb, var(--wp--preset--color--border-default) 40%, transparent); }
.lychgate-overlay__list > .lychgate-overlay__links .wp-block-navigation-item__content,
.lychgate-overlay__accordion .wp-block-accordion-heading__toggle { padding-block: var(--wp--preset--spacing--10); }
.lychgate-overlay__list > .lychgate-overlay__links,
.lychgate-overlay__list > .lychgate-overlay__links .wp-block-navigation__container,
.lychgate-overlay__list > .lychgate-overlay__links .wp-block-navigation-item { width: 100%; align-items: stretch; }
.lychgate-overlay__accordion .wp-block-accordion-heading { margin: 0; font-weight: var(--wp--custom--font-weight--body); line-height: var(--wp--custom--line-height--body); }
.lychgate-overlay__accordion .wp-block-accordion-heading__toggle-icon { font-family: var(--wp--preset--font-family--body); font-weight: 300; }

/* FT1. Footer site links in three columns of three (Manu's build); core Navigation lays a list in one
 *      row or one column. Two columns on phones (Figma 289:8950). */
.lychgate-footer__nav .wp-block-navigation__container { display: grid; grid-template-columns: repeat(3, max-content); grid-template-rows: repeat(3, auto); grid-auto-flow: column; column-gap: var(--wp--preset--spacing--60); row-gap: var(--wp--preset--spacing--10); }
@media (max-width: 781px) {
	.lychgate-footer__nav .wp-block-navigation__container { grid-template-columns: repeat(2, max-content); grid-template-rows: none; grid-auto-flow: row; column-gap: var(--wp--preset--spacing--40); }
}

/* FT2. Footer details as drawn: venue links underlined (Figma 259:1782), the legal line's links in
 *      its own surface-raised colour, the Facebook glyph white rather than core's logos-only brand
 *      blue. The legal line takes the row's spare width and wraps inside it (Figma's one line has a
 *      single "Legal" link; the five legal pages do not fit beside the badges). */
.lychgate-footer__locations .wp-block-navigation-item__content.wp-block-navigation-item__content { text-decoration: underline; }
.lychgate-footer__legal a { color: inherit; }
.lychgate-footer__legal { flex: 1 1 0; min-width: min(100%, 37.5rem); }
.lychgate-footer .lychgate-footer__social.is-style-logos-only .wp-social-link { color: var(--wp--preset--color--text-inverse); }

/* FT3. Phones and tablets: the footer stacks and centres (Figma 289:8950). Columns stack at 782 but
 *      keep their left alignment, and the bottom row is a space-between flex row. */
@media (max-width: 781px) {
	.lychgate-footer__row > .wp-block-column,
	.lychgate-footer__bottom,
	.lychgate-footer__legal,
	.lychgate-footer__badges { justify-content: center; text-align: center; }
	.lychgate-footer__row .wp-block-navigation__container,
	.lychgate-footer__row .wp-block-navigation { justify-content: center; align-items: center; margin-inline: auto; }
}

/* T2. Live balances heading line breaks (text-wrap: balance on the H1, so "Transforming" sits
 *     alone on line one). theme.json has no text-wrap property. */
h1, h2, h3 { text-wrap: balance; }

/* T3. Live sets text-wrap: pretty on paragraphs (fewer orphans, slightly different line breaks in
 *     the quotes and the CTA prompt). theme.json has no text-wrap property. */
p { text-wrap: pretty; }

/* T1. Live headings use line-height 1.25 at 768px and below (1.1 above). theme.json line-height
 *     is a single value with no fluid form, so this is one media rule for all headings. */
@media (max-width: 768px) {
	h1, h2, h3, h4 { line-height: var(--wp--custom--line-height--heading-mobile); }
}

/* ------------------------------------------------------------------
 * Our work 
 * ------------------------------------------------------------------ */

/* W1. Bento spans. Post Template's grid layout is uniform and Query Loop has no per-item span, so
 *     live's 660 / 310 / 310 then 485-image / 660 arrangement is three nth-child rules on the
 *     four-column template. Below 768 the template is one column and these do nothing. */
@media (min-width: 769px) {
	.weave-work__grid .wp-block-post-template > li:nth-child(1),
	.weave-work__grid .wp-block-post-template > li:nth-child(4),
	.weave-work__grid .wp-block-post-template > li:nth-child(5) { grid-column: span 2; }
	.weave-work__grid .wp-block-post-template > li:nth-child(4) .wp-block-post-featured-image { max-width: 485px; }
}

/* W2. Card hover: title to the accent colour and a soft dark gradient over the image, as on live. Post Title
 *     and Featured Image have no hover states of their own, and the "card" is a Post Template
 *     item, so this is one hover rule pair. Featured Image's overlay support is static, not hover. */
.weave-work__grid .wp-block-post-template > li .wp-block-post-title a { transition: color .15s ease-out; }
.weave-work__grid .wp-block-post-template > li:hover .wp-block-post-title a,
.weave-work__grid .wp-block-post-template > li:focus-within .wp-block-post-title a { color: var(--wp--preset--color--accent); }
.weave-work__grid .wp-block-post-featured-image { position: relative; overflow: hidden; border-radius: var(--wp--preset--border-radius--card); }
.weave-work__grid .wp-block-post-featured-image::after {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: inherit;
	background: linear-gradient(180deg, color-mix(in srgb, var(--wp--preset--color--black) 0%, transparent) 40%, color-mix(in srgb, var(--wp--preset--color--black) 35%, transparent) 100%);
	opacity: 0;
	transition: opacity .3s ease-out;
	pointer-events: none;
}
.weave-work__grid .wp-block-post-template > li:hover .wp-block-post-featured-image::after,
.weave-work__grid .wp-block-post-template > li:focus-within .wp-block-post-featured-image::after { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .weave-work__grid .wp-block-post-featured-image::after, .weave-work__grid .wp-block-post-title a { transition: none; } }

/* ------------------------------------------------------------------
 * Testimonials .
 * ------------------------------------------------------------------ */

/* Q1. Scroller. Core has no carousel block, so the track is a nowrap flex Group of 100%-wide
 *     slide Groups (child sizing from block attributes) that scrolls horizontally with scroll
 *     snap; Group has no overflow or scroll-snap controls. Works with no script (swipe, trackpad,
 *     keyboard scroll); the buttons and counter are wired by assets/js/testimonials.js, and the
 *     nav stays hidden until that script marks the section ready so a no-JS page shows no dead
 *     buttons. Live hides the scrollbar too. Slides carry selfStretch "fixed" / flexSize 100%
 *     from the block, but core's fixed child sizing sets flex-basis without flex-shrink: 0, so
 *     three slides still squeezed into one row; the flex shorthand here makes fixed mean fixed. */
.weave-testimonials__track {
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	overscroll-behavior-x: contain;
	scrollbar-width: none;
}
.weave-testimonials__track::-webkit-scrollbar { display: none; }
.weave-testimonials__track > * { flex: 0 0 100%; scroll-snap-align: start; }
.weave-testimonials:not(.is-ready) .weave-testimonials__nav { visibility: hidden; }

/* Q2. Icon-only prev / next. Core Button carries text only and the Icon block cannot be a
 *     button, so each control is a Button block (tagName button, outline style) whose visible
 *     label is pushed out of a 38px round box (text stays in the accessibility tree) and whose
 *     arrow is the icon set glyph as a currentColor mask, so the outline style's hover and
 *     focus (navy fill, white text) invert the arrow too. Reference: 38px glyph, 28px at 768 and below. */
.weave-testimonials__nav .wp-block-button__link {
	position: relative;
	width: 2.375rem;
	height: 2.375rem;
	padding: 0;
	overflow: hidden;
	white-space: nowrap;
	text-indent: 100%;
	border-radius: 50%;
}
.weave-testimonials__nav .wp-block-button__link::before {
	content: "";
	position: absolute;
	inset: 25%;
	background-color: currentColor;
	-webkit-mask: url("assets/images/icons/arrow-left.svg") center / contain no-repeat;
	mask: url("assets/images/icons/arrow-left.svg") center / contain no-repeat;
}
.weave-testimonials__next .wp-block-button__link::before {
	-webkit-mask-image: url("assets/images/icons/arrow-right.svg");
	mask-image: url("assets/images/icons/arrow-right.svg");
}
@media (max-width: 768px) {
	.weave-testimonials__nav .wp-block-button__link { width: 1.75rem; height: 1.75rem; }
}

/* ------------------------------------------------------------------
 * CTA .
 * ------------------------------------------------------------------ */

/* C1. Button arrow. Core Button carries text only (no icon slot; the Icon block cannot sit inside
 *     a button), so the "White with arrow" style draws the icon set arrow-up-right after the
 *     label as a currentColor mask; it inverts with the style's hover / focus from theme.json.
 *     Reference: 22px glyph 8px after a 20px label, label never wraps. */
.is-style-white-arrow .wp-block-button__link { white-space: nowrap; }
.is-style-white-arrow .wp-block-button__link::after {
	content: "";
	display: inline-block;
	width: 0.85em;
	height: 1.1em;
	margin-left: 0.4em;
	vertical-align: -0.2em;
	background-color: currentColor;
	-webkit-mask: url("assets/images/icons/arrow-up-right.svg") center / contain no-repeat;
	mask: url("assets/images/icons/arrow-up-right.svg") center / contain no-repeat;
}

/* ------------------------------------------------------------------
 * Service pages .
 * ------------------------------------------------------------------ */

/* C2. CTA text column. The column must shrink beside the button at desktop (so a long display line
 *     wraps to two lines rather than pushing the button under it) and drop below the button on
 *     mobile. Core's "fill" child sizing is flex: 1 1 auto, whose auto basis makes a wrapping row
 *     wrap first and shrink never; basis 0 plus a 600px floor (the prompt's width) does both. */
.weave-cta__panel > .wp-block-group:first-child { flex: 1 1 0; min-width: min(100%, 600px); }

/* SV1. FAQ accordion icon. Core renders the "+" at the heading's size and colour (32px Parchment);
 *      the reference shows a 20px white glyph. Two declarations; the glyph itself is core's. */
.weave-service__faq-list .wp-block-accordion-heading__toggle-icon { font-size: var(--wp--preset--font-size--body); color: var(--wp--preset--color--text-inverse); }

/* A1. Focus ring. Browsers' default focus-visible ring (blue, 1px) is 2.9:1 on the navy bands,
 *     under WCAG 1.4.11. theme.json has no focus-visible outline, so: a 2px ring in the text
 *     colour of the page, swapped to white inside any navy band. */
:focus-visible { outline: 2px solid var(--wp--preset--color--primary); outline-offset: 3px; }
.has-surface-inverse-background-color :focus-visible { outline-color: var(--wp--preset--color--text-inverse); } /* descendants only: the ring sits on the surface behind the element, so a navy button on a light band keeps the navy ring */
.has-surface-inverse-background-color .has-white-background-color :focus-visible,
.has-surface-inverse-background-color .has-surface-background-color :focus-visible,
.has-surface-inverse-background-color .has-surface-subtle-background-color :focus-visible,
.has-surface-inverse-background-color .has-surface-raised-background-color :focus-visible { outline-color: var(--wp--preset--color--primary); } /* a light panel inside a navy band */

/* A2. Forced colours (Windows high contrast). Every functional icon here is a mask over a
 *     currentColor background, and forced colours replace backgrounds with the system colour, so
 *     the glyph vanishes; Q2's icon-only buttons then show nothing at all. Opt each glyph out and
 *     paint it in the system colour of its own text: ButtonText on buttons, LinkText on links,
 *     CanvasText beside text. The only non-token colours in the theme, and the same fix as the
 *     dark mode toggle in weave-site-functions. WCAG 1.4.11. A masked icon defined later in this
 *     file carries its own one-line A2 block beside it, so the cascade order holds, and the icon
 *     block styles get theirs from weave_blocks_icon_block_style_css(). */
@media (forced-colors: active) {
	.weave-testimonials__nav .wp-block-button__link::before { forced-color-adjust: none; background-color: ButtonText; }
	.is-style-white-arrow .wp-block-button__link::after { forced-color-adjust: none; background-color: LinkText; }
}

/* ------------------------------------------------------------------
 * Case studies : archive, taxonomy archives, single project.
 * ------------------------------------------------------------------ */

/* CS1. Term filter lists. The Terms List (Categories) block renders a bulleted <ul>; the reference shows a
 *      plain stack of term links beside the label. Block supports offer no list-style control. */
.weave-term-list { padding: 0; margin: 0; list-style: none; }
.weave-term-list li { margin: 0 0 var(--wp--preset--spacing--10); }
.weave-term-list a { color: inherit; text-decoration: none; }
.weave-term-list a:hover, .weave-term-list a:focus-visible { text-decoration: underline; }

/* CS2. Bento spans on the archive grid: the first card spans 4 of 8 columns and the rest span 2
 *      (same Post Template limitation as W1 on the homepage). One column below 768. */
@media (min-width: 769px) {
	.weave-project-grid--bento .wp-block-post-template > li { grid-column: span 2; }
	.weave-project-grid--bento .wp-block-post-template > li:first-child { grid-column: span 4; }
}

/* CS3. Card hover for every project grid (the homepage W2 rule covered only .weave-work__grid):
 *      image dims to 90% and the title turns the accent colour, as the reference. Featured Image and Post Title have
 *      no hover supports. */
.weave-project-grid .wp-block-post-title a { transition: color .15s ease-out; }
.weave-project-grid .wp-block-post-template > li:hover .wp-block-post-title a,
.weave-project-grid .wp-block-post-template > li:focus-within .wp-block-post-title a { color: var(--wp--preset--color--accent); }
.weave-project-grid .wp-block-post-featured-image img { transition: filter .15s ease-out; }
.weave-project-grid .wp-block-post-template > li:hover .wp-block-post-featured-image img,
.weave-project-grid .wp-block-post-template > li:focus-within .wp-block-post-featured-image img { filter: brightness(0.9); }
@media (prefers-reduced-motion: reduce) { .weave-project-grid .wp-block-post-title a, .weave-project-grid .wp-block-post-featured-image img { transition: none; } }

/* CS4. Single project summary: the service terms read as a bullet list (Post Terms renders inline
 *      links with separators), and on narrow screens the title column comes before the label
 *      column as the reference (core Columns stack in source order only; wrap-reverse flips the rows). */
.weave-project-summary__services a { color: inherit; display: list-item; list-style: disc inside; margin: 0 0 0.5rem; text-decoration: none; }
.weave-project-summary__services a:hover, .weave-project-summary__services a:focus-visible { text-decoration: underline; }
@media (max-width: 781px) { .wp-block-columns.weave-project-summary { flex-wrap: wrap-reverse !important; } } /* core's .wp-block-columns sets flex-wrap: wrap !important */

/* CS5. Industry term pills inside project bodies: Post Terms renders plain links; the reference shows
 *      accent pills (radius 50, 0.4em / 1em). The block exposes no per-link styling. Text is
 *      muted; check AA against the accent once the palette is real. */
.weave-term-pills { display: flex; flex-wrap: wrap; gap: var(--wp--preset--spacing--10); }
.weave-term-pills a { display: inline-block; background: var(--wp--preset--color--accent); color: var(--wp--preset--color--text-muted); border-radius: var(--wp--preset--border-radius--pill); padding: 0.4em 1em; text-decoration: none; font-weight: 400; }
.weave-term-pills a:hover, .weave-term-pills a:focus-visible { color: var(--wp--preset--color--primary); }

/* CS6. Project body bands: the label column keeps its 30% width but the stacked mobile order
 *      follows source (label first), as the reference. Quote bands use the theme quote styles. */
.weave-project-band .wp-block-quote { margin: 0; }
.weave-project-quote p { font-weight: 400; }
.weave-project-band h2 { font-weight: 300; }

/* ------------------------------------------------------------------
 * Insights : posts index, archives, single post.
 * ------------------------------------------------------------------ */

/* I1. The first card spans two of the three grid columns (live's featured treatment is
 *     positional). Post Template's grid is uniform, as on the homepage (W1). */
@media (min-width: 769px) { .weave-insights-grid .wp-block-post-template > li:first-child { grid-column: span 2; } }

/* I2. Category row. The Categories block renders a bulleted <ul>; the reference shows a centred wrapping
 *     row of links with no markers. No layout controls on the block. */
.weave-term-row { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--wp--preset--spacing--10) var(--wp--preset--spacing--40); padding: 0; margin: 0; list-style: none; }
.weave-term-row li { margin: 0; }
.weave-term-row a { color: inherit; text-decoration: none; }
.weave-term-row a:hover, .weave-term-row a:focus-visible, .weave-term-row .current-cat > a { text-decoration: underline; }

/* I3. Article body headings. Post Content on a post uses live's article scale (h2 at the subheading size, h3 at the small-heading size) while the global h2 / h3 are the homepage display sizes.
 *     theme.json's post-content element styles would also resize the homepage headings, so the
 *     override is scoped to the single post template. */
.weave-single-post .wp-block-post-content h2 { font-size: var(--wp--preset--font-size--subheading); color: var(--wp--preset--color--primary-strong); }
.weave-single-post .wp-block-post-content h3 { font-size: var(--wp--preset--font-size--small-heading); font-weight: 300; color: var(--wp--preset--color--primary); }
.weave-single-post .wp-block-post-content ul, .weave-single-post .wp-block-post-content ol { padding-left: var(--wp--preset--spacing--50); }
.weave-single-post .wp-block-post-content .wp-block-quote { font-size: var(--wp--preset--font-size--headline); font-weight: 500; color: var(--wp--preset--color--text-muted); line-height: 1.4; }

/* I4. Single header categories: Post Terms centres through textAlign but the separator is a space;
 *     give the links live's 40px visual gap. */
.weave-post-categories a { margin: 0 var(--wp--preset--spacing--20); }

/* S1: Sector feature list. Core List cannot hold a heading and a paragraph per item and has no icon
   marker control, so the ticked info list is a Group of "Feature" Groups (h3 + p) and the tick is a
   masked SVG pseudo-element in a 22px column, 22px from the text (live: icon set glyph, 22 x 22). */
.weave-tick-list__item {
	display: grid;
	grid-template-columns: 22px 1fr;
	column-gap: 22px;
}
.weave-tick-list__item > * { grid-column: 2; }
.weave-tick-list__item::before {
	content: "";
	grid-column: 1;
	grid-row: 1;
	width: 22px;
	height: 22px;
	margin-top: 0.25em;
	background-color: currentColor;
	-webkit-mask: url("assets/images/icons/check.svg") no-repeat center / contain;
	mask: url("assets/images/icons/check.svg") no-repeat center / contain;
}
@media (forced-colors: active) { .weave-tick-list__item::before { forced-color-adjust: none; background-color: CanvasText; } } /* A2 */

/* L1. Prose pages (legal): space above headings. Core's flow layout sets every child's margin to the
 *     block gap (20 here), so headings sit flush on the paragraph before them; the reference has 136 / 108
 *     above H2 / H3 at 1440 and 51 / 40 at 390. theme.json heading margins lose to that layout rule. */
.weave-page .entry-content > h2.wp-block-heading { margin-block-start: var(--wp--preset--spacing--grid-row); }
.weave-page .entry-content > h3.wp-block-heading { margin-block-start: var(--wp--preset--spacing--card-row); }

/* S2. Sector showcase panel: the one band that stops widening. Live caps it at 1400 and centres it at
 *     2000 while every other band follows the gutter; a Group has no max-width control of its own. */
.weave-sector-showcase.alignwide { max-width: min(100%, 1400px); margin-inline: auto; }

/* S3. Sector work cards: equal-height cards with the "View project" link on a common baseline (live's
 *     ragged bottoms were flagged not-to-reproduce). Post Template grid items stretch, the inner
 *     Groups do not. */
.weave-sector-work__grid .wp-block-post > .wp-block-group { height: 100%; display: flex; flex-direction: column; }
.weave-sector-work__grid .wp-block-post > .wp-block-group > .wp-block-group { flex: 1 1 auto; display: flex; flex-direction: column; }
.weave-sector-work__grid .wp-block-read-more { margin-block-start: auto; padding-block-start: var(--wp--preset--spacing--20); }

/*
 * LK1 Links in a plain surface-inverse band (starter only; weave-blocks decisions 2026-10-26).
 *     theme.json has one link colour for the page and none per background, so a link a client
 *     adds to a Group painted surface-inverse (Color, Background) kept the accent link colour:
 *     2.62:1 on the starter palette, under AA. Here it takes text-inverse with a visible underline.
 *     Scoped: buttons are left alone, and so is a link inside a painted block nested in the band
 *     (a light panel, a gradient or image background, a Cover, a Group paint style), which keeps
 *     that block's colours. :root :where() gives it global styles' specificity (0,1,0), so it
 *     beats the global link colour and its hover by order (this sheet prints after them), and a
 *     link colour set on a block (.wp-elements-*, 0,1,1) still wins: the footer keeps its own.
 *     Band: inverse sets its own link colours in theme.json. contrast-pairs.py reads this rule
 *     as link:surface-inverse. A build that adds a Group paint style adds it to the list. */
:root :where(.has-surface-inverse-background-color a:where(:not(.wp-element-button, .has-surface-inverse-background-color :is(.has-background, .wp-block-cover, .is-style-band-subtle, .is-style-band-inverse, .is-style-card, .is-style-card-raised) a))) {
	color: var(--wp--preset--color--text-inverse);
	text-decoration-line: underline;
}

/*
 * QL1 Quick-link cards (Figma 468:3292, Lychgate stage 3). While one Card: link is hovered or holds
 * focus, the other cards in the same row fade to custom.card.dimOpacity, the design's "static"
 * variant. theme.json has no :hover for blocks and no sibling selector, so this needs CSS.
 */
.is-style-card-link { transition: var(--wp--custom--motion--medium); }
:where(.wp-block-group, .wp-block-column):has(> .is-style-card-link:is(:hover, :focus-within)) > .is-style-card-link:not(:hover, :focus-within) { opacity: var(--wp--custom--card--dim-opacity); }
@media (prefers-reduced-motion: reduce) { .is-style-card-link { transition: none; } }

/* === Stage 5: Home sections (docs/stage-5-notes.md) ===
 * Tags: QL2 (quick-link card link), DB1 (focus ring on the deep gradient), CT1 (card titles), CR1 to CR3 (card
 * carousel, ported from DEVORA HM11 and HM13), TM1 (team portraits), PR1 (package price rows), VN1 (venue cards),
 * IN1 (image inset overlap), SP1 (split photo on phones). Each names what block supports cannot express. */

/* DB1. The deep gradient band (Band: deep) is a gradient, not the surface-inverse colour A1 keys on, so its focus
 *      ring stayed primary on blue. White inside it, primary again inside a light panel within it. */
.is-style-band-deep :focus-visible { outline-color: var(--wp--preset--color--text-inverse); }
.is-style-band-deep .has-surface-background-color :focus-visible { outline-color: var(--wp--preset--color--primary); }

/* QL2. Quick-link cards: core has no card link, so the title's link is stretched over the whole card (one link,
 *      one tab stop), the ring drawn round the card, and the photo kept square beside the title. Domaine ships
 *      Medium only, so the link keeps the heading's 500 (the global link element is 600). */
.is-style-card-link { position: relative; }
.is-style-card-link .lychgate-card-link a { font-weight: inherit; }
.is-style-card-link .lychgate-card-link a::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
.is-style-card-link:has(a:focus-visible) { outline: 2px solid var(--wp--preset--color--text-inverse); outline-offset: 3px; }
.is-style-card-link a:focus-visible { outline: none; }
.is-style-card-link > .wp-block-image { flex: 0 0 auto; margin: 0; }

/* CT1. Card titles (services and venues, Figma 303:1522, 184:362): Domaine italic, underlined, in the heading
 *      colour rather than the Aqua link colour, Aqua strong on hover. The link element is global; a block's own
 *      link colour attribute would have to be set on every card. */
.lychgate-card-title { font-style: italic; }
.lychgate-card-title a { color: var(--wp--preset--color--primary); font-weight: inherit; text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 0.15em; }
.lychgate-card-title a:where(:hover, :focus-visible) { color: var(--wp--preset--color--accent-strong); }

/* CR1. Card carousel track (patterns/carousel.php): Group has no overflow or scroll-snap control and its flex
 *      children have no per-viewport size, so the row scrolls and snaps here, four cards across from 1024, three
 *      from 600, two below (Figma mobile draws two). The track keeps a little padding so a focused card's ring is
 *      not cut by the scroller, and gives it back in its margins. Works without the script. */
.lychgate-carousel { --lychgate-per-view: 4; --lychgate-gap: var(--wp--preset--spacing--30); }
.lychgate-carousel__track.wp-block-group {
	gap: var(--lychgate-gap);
	margin-inline: calc(-1 * var(--wp--preset--spacing--10));
	padding: var(--wp--preset--spacing--10);
	overflow-x: auto;
	overscroll-behavior-x: contain;
	scroll-snap-type: x mandatory;
	scroll-padding-inline: var(--wp--preset--spacing--10);
	scrollbar-width: none;
}
.lychgate-carousel__track::-webkit-scrollbar { display: none; }
.lychgate-carousel__track > * {
	flex: 0 0 calc((100% - (var(--lychgate-per-view) - 1) * var(--lychgate-gap)) / var(--lychgate-per-view));
	min-width: 0;
	margin: 0;
	scroll-snap-align: start;
}
@media (width < 1024px) { .lychgate-carousel { --lychgate-per-view: 3; } }
@media (width < 600px) { .lychgate-carousel { --lychgate-per-view: 2; } }

/* CR2. Carousel buttons, from DEVORA HM13: square outline buttons with the arrow glyph as a currentColor mask
 *      (core Button carries text only, so the label is pushed out of the box and stays the button's name). The
 *      previous button takes the long left arrow, the right arrow's path flipped (Gareth, 28 Oct 2026). Hidden until the script marks the
 *      carousel ready (no dead controls without JavaScript) and while every card fits (is-static). At either end
 *      the button dims and stays focusable (aria-disabled). */
.lychgate-carousel:not(.is-ready) .lychgate-carousel__nav { visibility: hidden; }
.lychgate-carousel.is-static .lychgate-carousel__nav { display: none; }
.lychgate-carousel__nav .wp-block-button__link {
	position: relative;
	width: 3rem;
	height: 3rem;
	padding: 0;
	overflow: hidden;
	white-space: nowrap;
	text-indent: 100%;
	color: var(--wp--preset--color--accent-strong);
	border-color: currentColor;
	background-color: transparent;
}
.lychgate-carousel__nav .wp-block-button__link::before {
	content: "";
	position: absolute;
	inset: 0;
	width: 1.75rem;
	height: 1.75rem;
	margin: auto;
	background-color: currentColor;
	-webkit-mask: url("assets/icons/arrow-right.svg") center / contain no-repeat;
	mask: url("assets/icons/arrow-right.svg") center / contain no-repeat;
}
.lychgate-carousel__prev .wp-block-button__link::before { -webkit-mask-image: url("assets/icons/arrow-left.svg"); mask-image: url("assets/icons/arrow-left.svg"); }
.lychgate-carousel__nav .wp-block-button__link:where(:hover, :focus-visible):not([aria-disabled="true"]) { color: var(--wp--preset--color--text-inverse); background-color: var(--wp--preset--color--primary); border-color: var(--wp--preset--color--primary); }
.lychgate-carousel__nav .wp-block-button__link[aria-disabled="true"] { opacity: 0.3; cursor: default; }
/* CR3. The script-added Pause/Play control (is-autoplay carousels only) keeps a readable label. */
.lychgate-carousel__pause .wp-block-button__link { width: auto; padding-inline: var(--wp--preset--spacing--20); text-indent: 0; }
.lychgate-carousel__pause .wp-block-button__link::before { content: none; }
@media (forced-colors: active) { .lychgate-carousel__nav .wp-block-button__link::before { background-color: ButtonText; } }

/* TM1. Team portraits (Figma 184:487 to 184:495): Post Template's grid column count is one number for every
 *      width, so two across below 600 (core's own collapse to one column) is a media query, and the middle portrait of each row of three drops by a
 *      spacing step as drawn. The team link is white and underlined on the deep band, weight as the heading. */
@media (width >= 782px) { .lychgate-team__grid > li:nth-child(3n + 2) { margin-top: var(--wp--preset--spacing--40); } }
@media (width < 600px) { ul.lychgate-team__grid.lychgate-team__grid.wp-block-post-template { grid-template-columns: repeat(2, minmax(0, 1fr)); } } /* outranks core's one column below 600 */
.lychgate-team__grid .wp-block-post-featured-image { margin: 0; }
.lychgate-team__grid .wp-block-post-title,
.lychgate-team__grid p { margin-block: 0; }
.lychgate-team__link a { font-weight: inherit; text-decoration-thickness: 1px; }

/* PR1. Package prices (Figma 279:5939): the rows sit in one white panel with the middle row on surface-raised.
 *      Post Template has no alternating row colour, and the panel clips the row fills to its radius. */
.lychgate-prices-panel { overflow: hidden; }
.lychgate-prices__rows { margin: 0; }
.lychgate-prices__rows > li { margin: 0; }
.lychgate-prices__rows > li:nth-child(even) { background-color: var(--wp--preset--color--surface-raised); }
.lychgate-prices__row > * { margin: 0; }

/* VN1. Venue cards (Figma 184:362 to 184:370): every second card drops by a spacing step on wider screens; below
 *      782 the cards go two across with no drop (Grid's column count is one number for every width). */
@media (width >= 782px) { .lychgate-venues__grid > :nth-child(even) { margin-top: var(--wp--preset--spacing--50); } }
@media (width < 782px) { .lychgate-venues__grid.wp-block-group { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* IN1. Image inset (Figma 184:555 to 184:559): the photo rises out of the top of its dark panel and the panel
 *      overlaps the full-width photo below. Core has no overlap or negative spacing control. The panel is a flow
 *      root so the photo's negative margin cannot collapse through its zero top padding. */
.lychgate-inset__panel { display: flow-root; position: relative; z-index: 1; margin-bottom: calc(-1 * var(--wp--preset--spacing--60)); }
.lychgate-inset__panel > .lychgate-inset__photo.wp-block-image { margin-top: calc(-1 * var(--wp--preset--spacing--50)); margin-bottom: 0; }
.lychgate-inset__wide { margin-block: 0; }
.lychgate-inset__wide img { width: 100%; }

/* SP1. Split sections: once the columns stack (below 782) a kept photo is capped and centred rather than filling the
 *      width (a 2:3 photo 740 wide is over 1100 tall at 768). Column has no max-width control. */
@media (width < 782px) { .lychgate-split .wp-block-column > .wp-block-image { max-width: 24rem; margin-inline: auto; } }
/* === end Stage 5 === */

/* === Stage 6: inner page exemplars (docs/stage-6-notes.md) === */

/* HC1. Ticked lists (Figma's Aqua badge tick, 376:4159): the Icon: Check list style paints the glyph in
 *      currentColor, which is the text colour; the design draws it Aqua. Decorative, so Aqua is fine at 2.9:1.
 *      Figma spaces the rows 18px apart; core List has no item gap control. The icon CSS prints after style.css,
 *      so the selector carries the element to outrank it. */
ul.wp-block-list.lychgate-checks > li::before { background-color: var(--wp--preset--color--accent); }
.lychgate-checks > li + li { margin-top: var(--wp--preset--spacing--10); }

/* MC1. Photo and copy (patterns/media-copy.php): once the columns stack (below 782) the 2:3 photo is capped and
 *      turned 5:4 as Manu's phones show it (a 2:3 photo 740 wide is over 1100 tall). Column has no max-width. */
@media (width < 782px) {
	.lychgate-media-copy__photo { max-width: 24rem; margin-inline: auto; }
	.lychgate-media-copy__photo img { aspect-ratio: 5 / 4 !important; }
}

/* VM1. Venue map (patterns/venue-map.php): a colour venue photo standing in for map artwork shows in black and white
 *      (the brief's static map); the stored file is unchanged. Image has no filter control and the theme has no
 *      grey duotone preset. */
.lychgate-venue-map__map.is-mono img { filter: grayscale(1); }
.lychgate-venue-map__map img { width: 100%; }

/* AC1. Accordion rows (Figma 312:4612): each row a white rounded card with the label inset 32px. Accordion Item has
 *      no background support in 7.1. The panel's own bottom padding shows only while open (core hides it with
 *      hidden="until-found", which keeps the box, so the padding sits on the open state). */
.lychgate-accordion__rows > .wp-block-accordion-item { background-color: var(--wp--preset--color--surface); border-radius: var(--wp--preset--border-radius--card); padding-inline: var(--wp--preset--spacing--30); }
.lychgate-accordion__rows .wp-block-accordion-heading__toggle { padding-block: var(--wp--preset--spacing--30); }
.lychgate-accordion__rows .wp-block-accordion-panel:not([hidden]) { padding-bottom: var(--wp--preset--spacing--30); }

/* ST1. Step cards (Figma 367:3802): Figma's 7px pale border (Group border width is a raw length, so it lives here)
 *      and every second card a step lower on wide screens, as the frame staggers them. */
.lychgate-step { border: 7px solid var(--wp--preset--color--surface-subtle); }
@media (width >= 1024px) { .lychgate-steps__grid > :nth-child(even) { margin-top: var(--wp--preset--spacing--40); } }
/* HP1. Links inside the immediate help card (patterns/help-panel.php): the card is white inside Band: deep, whose
 *      element styles turn every link white, so the phone link vanished. Core cannot scope a link colour to a nested
 *      Group with a background; the card takes the site's own link colour back. */
.is-style-band-deep .lychgate-help-panel__card a { color: var(--wp--preset--color--accent); }

/* CR4. A carousel with fewer cards than fit (a venue gallery of three, Venue Options) centres its row from 1024, where
 *      four fit, instead of leaving an empty slot on the right. Only when there is no overflow: centring an
 *      overflowing flex row would push its first card out of reach. */
@media (width >= 1024px) { .lychgate-carousel__track:not(:has(> :nth-child(5))) { justify-content: center; } }
/* === end Stage 6 === */

/* === Review round 1 (28 Oct 2026) === */
/* BC1. SEOPress breadcrumbs in the inner page hero (Figma 312:4804): centred above the H1, Manrope 600 in Lychgate
 *      blue (block attributes), parent links underlined with Figma's pale rule, the current page in Aqua strong
 *      on a white hero (Figma draws Aqua #10A99E, 2.92:1; Aqua strong is 5.06 on white) and in Lychgate blue on the
 *      pale gradient, where Aqua strong measured 4.42 at the trail. The block has no text align support, and
 *      SEOPress prints its own list reset and the separator in the head. */
.lychgate-breadcrumbs { text-align: center; }
.lychgate-breadcrumbs a { text-decoration-color: var(--wp--preset--color--border-default); text-underline-offset: 0.2em; }
.lychgate-breadcrumbs [aria-current="page"] { color: var(--wp--preset--color--accent-strong); }
.is-style-band-pale .lychgate-breadcrumbs [aria-current="page"] { color: var(--wp--preset--color--primary); }

/* SP2. Split with phones 'header-first' (Manu's Home, intro and our story): once the columns stack, the icon and
 *      heading sit above the photo and the copy below it. Columns cannot reorder part of a column, so the copy
 *      column and its group step aside (display: contents) and their children take an order. The photo takes
 *      Manu's phone crop (5:4 intro, 3:4 story); the Image block's ratio is one value for every width. */
@media (width < 782px) {
	.lychgate-split--header-first .wp-block-columns { flex-direction: column; row-gap: 0; }
	.lychgate-split--header-first .wp-block-column:not(:has(> .wp-block-image)),
	.lychgate-split--header-first .wp-block-column:not(:has(> .wp-block-image)) > .wp-block-group { display: contents; }
	.lychgate-split--header-first .lychgate-split__icon { order: 1; }
	.lychgate-split--header-first .wp-block-column > .wp-block-group > .wp-block-heading { order: 2; }
	.lychgate-split--header-first .wp-block-column:has(> .wp-block-image) { order: 3; margin-block-start: var(--wp--preset--spacing--30); }
	.lychgate-split--header-first .wp-block-column > .wp-block-group > :not(.lychgate-split__icon, .wp-block-heading) { order: 4; }
	.lychgate-split--header-first .wp-block-column > .wp-block-image { max-width: 20rem; }
	.lychgate-split--crop-5-4 .wp-block-column > .wp-block-image img { aspect-ratio: 5 / 4 !important; }
	.lychgate-split--crop-3-4 .wp-block-column > .wp-block-image { max-width: 15rem; }
	.lychgate-split--crop-3-4 .wp-block-column > .wp-block-image img { aspect-ratio: 3 / 4 !important; }
	.lychgate-split--header-first .wp-block-buttons { flex-direction: column; align-items: center; }
}

/* TM2. Team portraits as Manu built them on Home: from 1280 one row of five beside the group photo, every first,
 *      third and fifth a step lower, all five in view (no moving strip, which would hide people and need a scroll
 *      region). The team link carries his long arrow after it (decorative). */
@media (width >= 1280px) {
	ul.lychgate-team__grid.lychgate-team__grid.wp-block-post-template { grid-template-columns: repeat(5, minmax(0, 1fr)); }
	.lychgate-team__grid > li:nth-child(3n + 2) { margin-top: 0; }
	.lychgate-team__grid > li:nth-child(odd) { margin-top: var(--wp--preset--spacing--40); }
}
.lychgate-team__link { display: flex; align-items: center; justify-content: space-between; gap: var(--wp--preset--spacing--30); }
.lychgate-team__link::after {
	content: "";
	flex: none;
	width: 3.25rem;
	height: 1.4rem;
	background-color: currentColor;
	-webkit-mask: url("assets/icons/arrow-right.svg") center / contain no-repeat;
	mask: url("assets/icons/arrow-right.svg") center / contain no-repeat;
}

/* SP3. Manu's small decoration on the photo's outer bottom corner (pricing heart, story flower), from 782 where the
 *      photo sits beside the copy. Image has no position control. Decorative, alt "". */
.lychgate-split .wp-block-column:has(> .lychgate-split__deco) { position: relative; }
.lychgate-split .lychgate-split__deco { position: absolute; bottom: -1.25rem; margin: 0; }
.lychgate-split--left .lychgate-split__deco { left: -1.25rem; }
.lychgate-split--right .lychgate-split__deco { right: -1.25rem; }
@media (width < 782px) { .lychgate-split .lychgate-split__deco { display: none; } }

/* IN2. The line of copy above the image inset (Manu's Home) clears the photo, which rises out of its panel (IN1). */
.lychgate-inset__lead { max-width: 41rem; margin-inline: auto; margin-block: 0 calc(var(--wp--preset--spacing--50) + var(--wp--preset--spacing--40)); }
/* === end Review round 1 === */

/* === Stage 6 rollout (28 Oct 2026; docs/stage-6-notes.md, rollout summary) === */
/* BC2. A left-set inner hero (patterns/inner-hero.php 'align' => 'left', Figma FAQs 312:3430): the breadcrumb trail
 *      follows the title to the left. The block has no text align support (BC1 centres it). */
.lychgate-inner-hero--left .lychgate-breadcrumbs { text-align: left; }

/* Venues and about family (docs/rollout-notes-venues-about.md): rules for the lychgate/venues-about-* patterns,
 * folded in from the family's assets/css/venues-about.css by the integration pass (decisions 2026-10-28). */
/* VA1. Heritage timeline (patterns/venues-about-timeline.php; Figma 308:2418, John Rhind's legacy section): a thin rule
 *      runs through the row of years and each year sits on it in a small rounded pill. Group has no pseudo-element
 *      or positioned-line control, and Paragraph has no inline-size (fit-content) setting for a pill. The photographs
 *      are archive prints, already black and white. */
.venues-about-timeline__card { position: relative; }
.venues-about-timeline__card::before {
	content: "";
	position: absolute;
	inset-inline: calc(-0.5 * var(--wp--preset--spacing--30));
	top: 0.8em;
	border-top: 1px solid var(--wp--preset--color--border-default);
	font-size: var(--wp--preset--font-size--small);
}
.venues-about-timeline__year {
	position: relative;
	width: fit-content;
	margin-inline: auto;
	padding: 0.1em 0.9em;
	border-radius: 999px;
	background-color: var(--wp--preset--color--primary);
	color: var(--wp--preset--color--text-inverse) !important; /* outranks the block's own has-primary-color */
}
.venues-about-timeline__photo figcaption { text-align: center; }

/* VA2. Staff grid (patterns/venues-about-staff.php; Figma 241:3862): the middle card of each row of three sits a
 *      step lower on wide screens, and "Read bio" reads as Figma's small Aqua link with the biography under it.
 *      Post Template's grid has one column count for every width and no per-item offset; Details has no summary
 *      colour or marker setting. */
@media (width >= 782px) { .venues-about-staff__grid > li:nth-child(3n + 2) { margin-top: var(--wp--preset--spacing--50); } }
.venues-about-staff__grid .wp-block-post-featured-image { margin: 0; }
.venues-about-staff__grid .wp-block-post-title,
.venues-about-staff__grid li > p { margin-block: 0; }
.venues-about-staff__bio summary { cursor: pointer; color: var(--wp--preset--color--accent-strong); font-weight: 600; text-decoration: underline; text-underline-offset: 0.2em; }
.venues-about-staff__bio[open] summary { margin-bottom: var(--wp--preset--spacing--20); }
.venues-about-staff__bio .wp-block-post-content > * + * { margin-top: var(--wp--preset--spacing--20); }

/* VA3. Comparison table (patterns/venues-about-compare.php; Figma 379:4611): a Lychgate blue header row with white
 *      column names, row names in Lychgate blue, a pale rule between rows, one rounded panel. Table has a header
 *      colour only through the Stripes style (which tints body rows) and no per-row border or radius setting. Below
 *      782 the table keeps its columns at a readable width and scrolls inside its own frame. */
.venues-about-compare__table { border-radius: var(--wp--preset--border-radius--small); border: 1px solid var(--wp--preset--color--border-default); overflow-x: auto; }
.venues-about-compare__table table { border-collapse: collapse; margin: 0; }
.venues-about-compare__table th,
.venues-about-compare__table td { border: 0; border-bottom: 1px solid var(--wp--preset--color--border-default); padding: var(--wp--preset--spacing--20) var(--wp--preset--spacing--30); text-align: left; vertical-align: top; color: var(--wp--preset--color--primary-strong); }
.venues-about-compare__table thead th { background-color: var(--wp--preset--color--primary); color: var(--wp--preset--color--text-inverse); border-bottom: 0; }
.venues-about-compare__table tbody tr:last-child td { border-bottom: 0; }
.venues-about-compare__table td:first-child { color: var(--wp--preset--color--primary); }
@media (width < 782px) { .venues-about-compare__table table { min-width: 40rem; } }

/* VA4. Contact form control text at 16px (patterns/venues-about-contact-form.php): Gravity Forms Orbital sets control
 *      text from its own --gf-font-size-primary custom property (14px), which iOS zooms into on focus; the form
 *      block has a label and description size setting but no control size setting, so the property is raised here. */
.venues-about-contact-form .gform-theme--framework { --gf-font-size-primary: 1rem; }

/* VA5. Package cards (patterns/venues-about-package-cards.php): the inclusions are the package's own content (a List
 *      and a Paragraph), so their spacing is set from the card; Post Content has no block gap setting. Cards in a
 *      row share one height. */
.venues-about-packages__grid > li { display: flex; }
.venues-about-packages__card { flex: 1; }
.venues-about-packages__includes > * + * { margin-top: var(--wp--preset--spacing--20); }
.venues-about-packages__includes ul { padding-left: 1.2em; }
.venues-about-packages__price { margin-block: 0; }
/* === end Stage 6 rollout === */
