/*
Theme Name: Weave Blocks
Theme URI: https://weave.co.nz
Author: Weave Digital Studio
Author URI: https://weave.co.nz
Description: Native block theme (FSE) rebuild of weave.co.nz. Design tokens live in theme.json; this stylesheet holds only the small, commented set of rules that block supports cannot express yet.
Requires at least: 7.0
Tested up to: 7.0
Requires PHP: 8.1
Version: 0.2.0
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

Fonts: Recife Display Web (Luzi Type, commercial licence held by Weave, Regular only) and Bricolage Grotesque (SIL OFL) are self-hosted in assets/fonts/.
*/

/*
 * 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.
 * Phase 1: no rules yet.
 */

/* ------------------------------------------------------------------
 * Header (Phase 2a). Each rule names the core limitation it works around.
 * ------------------------------------------------------------------ */

/* H1. Core Navigation exposes no design controls for the dropdown panel
 *     (only the nav's own colours, inherited). Live: cream panel, 8px radius,
 *     soft shadow, 340px wide, 16px links. Selector carries .wp-block-navigation twice
 *     because core's ".wp-block-navigation:not(.has-background) .wp-block-navigation__submenu-container"
 *     sets white/bordered at (0,3,0). */
.weave-header .weave-header__nav.wp-block-navigation .wp-block-navigation__submenu-container {
	background-color: var(--wp--preset--color--tertiary);
	border: 0;
	border-radius: var(--wp--preset--border-radius--panel);
	box-shadow: var(--wp--preset--shadow--dropdown);
	padding: var(--wp--preset--spacing--10) 0;
	margin-top: var(--wp--preset--spacing--10);
}
/* H1c. The 10px gap above the panel is dead space for the pointer, so the menu closes while
 *      the mouse crosses it. Bridge the gap with an invisible pseudo-element that is part of
 *      the panel (hover stays on the item). Same problem the mega-menu probe hit (P4). */
.weave-header .weave-header__nav.wp-block-navigation .wp-block-navigation__submenu-container::before {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	bottom: 100%;
	height: var(--wp--preset--spacing--10);
}
.weave-header .weave-header__nav.wp-block-navigation .wp-block-navigation__submenu-container > .wp-block-navigation-item > .wp-block-navigation-item__content {
	font-size: 1rem;
	padding: var(--wp--preset--spacing--10) var(--wp--preset--spacing--20) var(--wp--preset--spacing--10) 3.25rem;
}

/* H1b. Core's open-state rule sets width:auto and min-width:200px on :hover / :focus-within /
 *      aria-expanded, so the 340px live width has to be set on the same states. */
.weave-header .weave-header__nav.wp-block-navigation .has-child:hover > .wp-block-navigation__submenu-container,
.weave-header .weave-header__nav.wp-block-navigation .has-child:focus-within > .wp-block-navigation__submenu-container,
.weave-header .weave-header__nav.wp-block-navigation .has-child .wp-block-navigation-submenu__toggle[aria-expanded="true"] ~ .wp-block-navigation__submenu-container {
	width: 340px;
	min-width: 340px;
}

/* H2. Decorative coloured corner marks on the six Services links (live draws them as
 *     pseudo-elements: 12px square, one full quarter-circle corner that rotates per item,
 *     a different palette colour each). No block can attach a decoration to a nav link. */
.weave-header .weave-header__nav.wp-block-navigation .wp-block-navigation__submenu-container > .wp-block-navigation-item > .wp-block-navigation-item__content { position: relative; }
.weave-header .weave-header__nav.wp-block-navigation .wp-block-navigation__submenu-container > .wp-block-navigation-item > .wp-block-navigation-item__content::before {
	content: "";
	position: absolute;
	left: var(--wp--preset--spacing--20);
	top: 50%;
	width: 12px;
	height: 12px;
	margin-top: -6px;
	border-radius: var(--weave-mark-radius, 0 100% 0 0);
	background-color: var(--weave-mark, var(--wp--preset--color--secondary));
}
.weave-header .wp-block-navigation__submenu-container > li:nth-child(1) > a { --weave-mark: var(--wp--preset--color--secondary);       --weave-mark-radius: 0 100% 0 0; }
.weave-header .wp-block-navigation__submenu-container > li:nth-child(2) > a { --weave-mark: var(--wp--preset--color--maize);           --weave-mark-radius: 0 0 100% 0; }
.weave-header .wp-block-navigation__submenu-container > li:nth-child(3) > a { --weave-mark: var(--wp--preset--color--baby-blue-eyes);  --weave-mark-radius: 0 0 0 100%; }
.weave-header .wp-block-navigation__submenu-container > li:nth-child(4) > a { --weave-mark: var(--wp--preset--color--green-sheen);     --weave-mark-radius: 100% 0 0 0; }
.weave-header .wp-block-navigation__submenu-container > li:nth-child(5) > a { --weave-mark: var(--wp--preset--color--unbleached-silk); --weave-mark-radius: 0 100% 0 0; }
.weave-header .wp-block-navigation__submenu-container > li:nth-child(6) > a { --weave-mark: var(--wp--preset--color--coral);           --weave-mark-radius: 0 0 100% 0; }

/* H7. Navigation link hover colour. Core sets
 *     ".wp-block-navigation .wp-block-navigation-item__content.wp-block-navigation-item__content { color: inherit }"
 *     at (0,3,0), so neither theme.json (styles.blocks.core/navigation.elements.link:hover) nor a
 *     block-level link colour can change a nav link's colour on hover. Header and overlay hover to
 *     Blue Medium, footer hovers to white. */
.weave-header .wp-block-navigation .wp-block-navigation-item__content.wp-block-navigation-item__content:hover,
.weave-header .wp-block-navigation .wp-block-navigation-item__content.wp-block-navigation-item__content:focus-visible {
	color: var(--wp--preset--color--blue-medium);
}
.weave-footer .wp-block-navigation .wp-block-navigation-item__content.wp-block-navigation-item__content:hover,
.weave-footer .wp-block-navigation .wp-block-navigation-item__content.wp-block-navigation-item__content:focus-visible {
	color: var(--wp--preset--color--tertiary-light);
}

/* H3. Current page highlight. theme.json cannot target .current-menu-item. */
.weave-header .wp-block-navigation .current-menu-item > .wp-block-navigation-item__content.wp-block-navigation-item__content {
	color: var(--wp--preset--color--blue-medium);
}

/* H4. Two menus (left | logo | right) so the logo can sit centred with one source per
 *     link. On mobile the right nav owns the hamburger and the overlay part shows both
 *     menus, so the left nav must hide. Core has no per-breakpoint visibility. Logo 80px
 *     on mobile: Site Logo width is a single value. */
@media (max-width: 768px) {
	/* 3-column grid so the logo centres like live; left nav removed, logo and right nav pinned to columns 2 and 3 */
	.weave-header > .wp-block-group { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); }
	.weave-header .weave-header__nav--left { display: none; }
	.weave-header .weave-header__logo { grid-column: 2; }
	.weave-header .weave-header__nav--right { grid-column: 3; justify-self: end; }
	.weave-header__logo img { width: 80px; }
}

/* H6. Sticky header. Core's sticky position only works on a Group at the root of the
 *     template, but a header part renders inside a <header class="wp-block-template-part">
 *     wrapper the height of the header, so the Group can never stick. Sticky goes on the
 *     wrapper instead. */
header.wp-block-template-part:has(> .weave-header) {
	position: sticky;
	top: 0;
	z-index: 20;
}

/* H8. Core's Navigation "mobile" overlay breakpoint is hard-coded at 600px and not
 *     configurable. Live switches at 768px (six items plus a centred logo do not fit
 *     between 600 and 768). Re-state core's two switching rules for that band. */
@media (min-width: 600px) and (max-width: 768px) {
	.weave-header .wp-block-navigation__responsive-container:not(.hidden-by-default):not(.is-menu-open) { display: none; }
	.weave-header .wp-block-navigation__responsive-container-open:not(.always-shown) { display: flex; }
}

/* H5. Header is transparent over the hero at the top of the page and turns cream with a
 *     shadow and shrinks once scrolled (live: absolute, then fixed). Core sticky position
 *     has no scroll-state styling, so this is a CSS scroll-driven animation. Browsers
 *     without animation-timeline get an always-cream sticky header. */
.weave-header { background-color: var(--wp--preset--color--tertiary); }
@supports (animation-timeline: scroll()) {
	.weave-header {
		background-color: transparent;
		animation: weave-header-stick linear both;
		animation-timeline: scroll();
		animation-range: 0 160px;
	}
	.weave-header__logo img {
		animation: weave-header-logo linear both;
		animation-timeline: scroll();
		animation-range: 0 160px;
	}
	@keyframes weave-header-stick {
		to {
			background-color: var(--wp--preset--color--tertiary);
			box-shadow: var(--wp--preset--shadow--header);
			padding-top: var(--wp--preset--spacing--10);
			padding-bottom: var(--wp--preset--spacing--10);
		}
	}
	@keyframes weave-header-logo {
		to { width: var(--wp--custom--header--logo-width-shrunk); }
	}
}

/* ------------------------------------------------------------------
 * Footer (Phase 2a)
 * ------------------------------------------------------------------ */

/* F1. The two utility links (Accounts Login, Support Request) are paragraphs so they can sit
 *     beside an Icon block; block-level link styles expose colour but not text-decoration,
 *     and elements.link on the root underlines every link. */
.weave-footer .wp-block-paragraph a { text-decoration: none; }

/* ------------------------------------------------------------------
 * Hero (Phase 3, section 01)
 * ------------------------------------------------------------------ */

/* H9. Animated gradient. Live overlays the mesh JPG with a blurred, slowly rotating pill filled
 *     with a conic gradient of six palette colours. Core has no motion or pseudo-layer controls,
 *     so this is a scoped pseudo-element with palette tokens. Guarded by prefers-reduced-motion
 *     (live has no guard). A pure-CSS gradient with no image is a Phase 5b candidate. */
.weave-hero {
	position: relative;
	overflow: hidden;
	isolation: isolate;
}
.weave-hero::before, .weave-contact::before {
	content: "";
	position: absolute;
	z-index: -1;
	left: 0;
	top: 0;
	width: 50%;
	height: 60%;
	border-radius: 1000px;
	background: conic-gradient(
		var(--wp--preset--color--secondary),
		var(--wp--preset--color--tertiary),
		var(--wp--preset--color--tertiary),
		var(--wp--preset--color--unbleached-silk),
		var(--wp--preset--color--baby-blue-eyes),
		var(--wp--preset--color--coral)
	);
	filter: blur(60px);
	opacity: 0.7;
	transform-origin: 50% 50%;
	animation: weave-hero-blob 10s linear infinite;
}
@keyframes weave-hero-blob {
	0%   { transform: translate(-10%, -10%) rotate(0deg)   scale(2.2); opacity: 0.6; }
	50%  { transform: translate(10%, 20%)   rotate(180deg) scale(2.6); opacity: 0.8; }
	100% { transform: translate(-10%, -10%) rotate(360deg) scale(2.2); opacity: 0.6; }
}
@media (prefers-reduced-motion: reduce) {
	.weave-hero::before, .weave-contact::before { animation: none; }
}

/* H10. Scroll cue is hidden at 768 and below on live. Core has no per-breakpoint visibility. */
@media (max-width: 768px) {
	.weave-hero .weave-hero__scroll-cue.wp-block-image { display: none; } /* (0,3,0) to beat core .wp-block-image.aligncenter { display: table } */
}

/* 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); }
}

/* ------------------------------------------------------------------
 * Services ticker (Phase 3, section 03)
 * ------------------------------------------------------------------ */

/* M1. Marquee. Core has no marquee block: two identical paragraphs in a nowrap row translate
 *     left by half the row (one copy) on a 60s linear loop, like live. Separators are inline
 *     images sized to the text (25px at 50px type). Reduced motion pauses the loop. */
.weave-ticker { overflow: hidden; }
.weave-ticker__track {
	width: max-content;
	white-space: nowrap;
	animation: weave-ticker-loop 60s linear infinite;
}
.weave-ticker__track > p { margin: 0; padding-right: 0.25em; }
.weave-ticker__sep {
	width: 0.5em !important; /* the inline-image format writes width:25px inline; scale with the fluid type instead */
	height: 0.5em;
	vertical-align: baseline;
	margin: 0 0.25em;
}
@keyframes weave-ticker-loop {
	from { transform: translateX(0); }
	to   { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
	.weave-ticker__track { animation: none; }
}

/* ------------------------------------------------------------------
 * Services accordion (Phase 3, section 04). Core Accordion block (WP 7.0).
 * ------------------------------------------------------------------ */

/* S1. Title colours. Headings inherit the theme's heading colour (Prussian Blue); on the navy
 *     band live shows closed titles white and the open title Blue Medium. The block has one colour
 *     setting with no open/closed state, and a preset colour class would be !important, so both
 *     states are set here, scoped to this accordion. */
.weave-services__accordion .wp-block-accordion-heading { color: var(--wp--preset--color--tertiary-light); transition: color .15s ease-out; }
.weave-services__accordion .wp-block-accordion-item.is-open > .wp-block-accordion-heading,
.weave-services__accordion .wp-block-accordion-heading:has(.wp-block-accordion-heading__toggle:hover),
.weave-services__accordion .wp-block-accordion-heading:has(.wp-block-accordion-heading__toggle:focus-visible) { color: var(--wp--preset--color--blue-medium); }

/* S2. Icon. Core renders a literal "+" glyph; live uses an arrow that points right when closed
 *     and down when open. Replace the glyph with a masked SVG arrow in currentColor, sized to the
 *     title, and rotate it. Core also underlines the title on hover; live does not. */
.weave-services__accordion .wp-block-accordion-heading__toggle { padding: 0; }
.weave-services__accordion .wp-block-accordion-heading__toggle-icon {
	font-size: 0;
	flex: none;
	width: calc(var(--wp--preset--font-size--small-heading) * 0.85);
	height: calc(var(--wp--preset--font-size--small-heading) * 0.85);
	margin-right: calc(var(--wp--preset--font-size--small-heading) * 0.3);
	background-color: currentColor;
	-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M4 12h14M12 5l7 7-7 7' fill='none' stroke='%23000' stroke-width='1.5'/%3E%3C/svg%3E") center / contain no-repeat;
	mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M4 12h14M12 5l7 7-7 7' fill='none' stroke='%23000' stroke-width='1.5'/%3E%3C/svg%3E") center / contain no-repeat;
	transition: transform .3s ease-out;
}
.weave-services__accordion .wp-block-accordion-item.is-open .wp-block-accordion-heading__toggle-icon { transform: rotate(90deg); }
.weave-services__accordion .wp-block-accordion-heading__toggle:hover .wp-block-accordion-heading__toggle-title { text-decoration: none; }
@media (prefers-reduced-motion: reduce) { .weave-services__accordion .wp-block-accordion-heading__toggle-icon { transition: none; } }

/* S3. Row layout. Each item is a wrapping flex row: heading (basis 340px from the block) beside a
 *     panel sized min(1020px, 100%). Core's child sizing offers fixed or fill, not "fixed basis
 *     that grows", so the heading gets flex-grow here: 340 wide when the panel is open, full width
 *     when it is closed, and its own line on narrow screens. */
.weave-services__accordion .wp-block-accordion-heading { flex-grow: 1; }

/* S4. Eased reveal. Core hides a closed panel with display:none, which cannot animate. Keep the
 *     panel in a collapsed grid row instead (0fr to 1fr, plus opacity), and delay the wrap-to-
 *     full-width until the collapse has finished so the closed heading still gets the row. The
 *     panel stays inert while closed, so it is out of the tab order and the accessibility tree. */
.weave-services__accordion .wp-block-accordion-panel {
	display: grid;
	grid-template-rows: 1fr;
	opacity: 1;
	transition: grid-template-rows .4s cubic-bezier(.4, 0, .2, 1), opacity .3s ease-out, flex-basis 0s 0s;
}
.weave-services__accordion .wp-block-accordion-panel > * { min-height: 0; overflow: hidden; }
.weave-services__accordion .wp-block-accordion-panel[inert] {
	display: grid;
	grid-template-rows: 0fr;
	opacity: 0;
	flex-basis: 100%;
	transition: grid-template-rows .4s cubic-bezier(.4, 0, .2, 1), opacity .25s ease-out, flex-basis 0s .4s;
}
@media (prefers-reduced-motion: reduce) {
	.weave-services__accordion .wp-block-accordion-panel,
	.weave-services__accordion .wp-block-accordion-panel[inert],
	.weave-services__accordion .wp-block-accordion-heading { transition: none; }
}

/* ------------------------------------------------------------------
 * Our work (Phase 3, section 05)
 * ------------------------------------------------------------------ */

/* 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 Coral 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--coral); }
.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, rgba(3, 30, 41, 0) 40%, rgba(3, 30, 41, 0.35) 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 (Phase 3, section 08).
 * ------------------------------------------------------------------ */

/* 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 Weave-Icons glyph as a currentColor mask, so the outline style's hover and
 *     focus (navy fill, white text) invert the arrow too. Live: 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 (Phase 3, section 09).
 * ------------------------------------------------------------------ */

/* 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 Weave-Icons arrow-up-right after the
 *     label as a currentColor mask; it inverts with the style's hover / focus from theme.json.
 *     Live: 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;
}

/* ------------------------------------------------------------------
 * Dark-page header (Phase 8). Service and other navy pages use the header-dark part
 * (white text, white logo image instead of the Site Logo block, which has one image).
 * ------------------------------------------------------------------ */

/* H11. Same scroll behaviour as H5 but the scrolled bar turns navy, not cream, because the
 *      page behind it is navy; text stays white throughout (live: header-dark-bg Themer layout). */
.weave-header--dark { background-color: var(--wp--preset--color--primary); }
@supports (animation-timeline: scroll()) {
	.weave-header--dark { background-color: transparent; animation-name: weave-header-stick-dark; }
	@keyframes weave-header-stick-dark {
		to {
			background-color: var(--wp--preset--color--primary);
			box-shadow: var(--wp--preset--shadow--header);
			padding-top: var(--wp--preset--spacing--10);
			padding-bottom: var(--wp--preset--spacing--10);
		}
	}
}

/* ------------------------------------------------------------------
 * Service pages (Phase 8).
 * ------------------------------------------------------------------ */

/* 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);
 *      live 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--tertiary-light); }

/* 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-primary-background-color :focus-visible { outline-color: var(--wp--preset--color--tertiary-light); } /* descendants only: the ring sits on the surface behind the element, so a navy button on a light band keeps the navy ring */
.has-primary-background-color .has-tertiary-light-background-color :focus-visible,
.has-primary-background-color .has-tertiary-background-color :focus-visible,
.has-primary-background-color .has-secondary-light-background-color :focus-visible { outline-color: var(--wp--preset--color--primary); } /* a light panel inside a navy band */

/* ------------------------------------------------------------------
 * Case studies (Phase 8): archive, taxonomy archives, single project.
 * ------------------------------------------------------------------ */

/* CS1. Term filter lists. The Terms List (Categories) block renders a bulleted <ul>; live 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 Coral, as live. 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--coral); }
.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 live (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; live shows
 *      parchment pills (radius 50, 0.4em / 1em). The block exposes no per-link styling. Text is
 *      live's secondary-dark, which fails AA on parchment; flagged for Gareth (see decisions). */
.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--secondary-light); color: var(--wp--preset--color--secondary-dark); 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 live. 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 (Phase 8): 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>; live 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 36px Recife
 *     Prussian Blue, h3 30.88px Recife) 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-light); }
.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--secondary-dark); 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); }

/* ------------------------------------------------------------------
 * Contact (Phase 8). The biggest custom block in the theme so far, and the evidence it carries is
 * simple: theme.json cannot reach inside a third-party plugin's markup. Gravity Forms renders its
 * own wrapper, grid, labels and button; block supports and style variations stop at the block.
 * ------------------------------------------------------------------ */

/* G1. Field chrome: underline-only fields as live (transparent, 1px Soft Amber bottom border, no radius). */
.weave-contact__form .gform_wrapper.gravity-theme input:not([type=submit]):not([type=button]),
.weave-contact__form .gform_wrapper.gravity-theme textarea,
.weave-contact__form .gform_wrapper.gravity-theme select,
.weave-contact__form .gform_wrapper input:not([type=submit]):not([type=button]),
.weave-contact__form .gform_wrapper textarea,
.weave-contact__form .gform_wrapper select {
	background: transparent;
	border: 0;
	border-bottom: 1px solid var(--wp--preset--color--secondary);
	border-radius: 0;
	color: var(--wp--preset--color--primary);
	font-family: var(--wp--preset--font-family--bricolage-grotesque);
	font-size: var(--wp--preset--font-size--medium);
	font-weight: 300;
	line-height: var(--wp--custom--line-height--body);
	padding: 0.3em 0;
}
.weave-contact__form .gform_wrapper textarea { min-height: 18rem; }
/* G2. Labels at large-body 300, sub-labels small. Required mark in the error colour. */
.weave-contact__form .gform_wrapper.gravity-theme .gfield_label, .weave-contact__form .gform_wrapper .gfield_label { font-size: var(--wp--preset--font-size--body); /* fluid 15.3 to 20, live 16 / 20 */ font-weight: 300; color: var(--wp--preset--color--primary); }
.weave-contact__form .gform_wrapper .gform-field-label--type-sub { font-size: var(--wp--preset--font-size--small); padding-top: 5px; }
.weave-contact__form .gform_wrapper .gfield_required_asterisk, .weave-contact__form .gform_wrapper .gfield_required_text { color: var(--wp--preset--color--error); }
/* G3. Placeholders at Primary 60% (live's Soft Amber on cream is 1.4:1). */
.weave-contact__form .gform_wrapper ::placeholder { color: var(--wp--preset--color--primary-60); opacity: 1; }
/* G4. Focus: a visible ring and the bottom border to Primary (live removes the outline). */
.weave-contact__form .gform_wrapper input:focus-visible, .weave-contact__form .gform_wrapper textarea:focus-visible, .weave-contact__form .gform_wrapper select:focus-visible { outline: 2px solid var(--wp--preset--color--blue-medium); outline-offset: 2px; border-bottom-color: var(--wp--preset--color--primary); }
/* G5. Submit button as the theme's default (Parchment pill, large), hover navy, since the plugin's
 *     <button> is outside the Button block's reach. */
.weave-contact .weave-contact__form .gform_wrapper.gravity-theme .gform_footer input[type=submit],
.weave-contact .weave-contact__form .gform_wrapper .gform_button {
	background: var(--wp--preset--color--secondary-light);
	color: var(--wp--preset--color--primary);
	border: 0;
	border-radius: var(--wp--preset--border-radius--pill);
	font-family: var(--wp--preset--font-family--bricolage-grotesque);
	font-size: var(--wp--custom--button--large-font-size);
	font-weight: 400;
	padding: var(--wp--custom--button--large-padding-y) var(--wp--custom--button--large-padding-x);
	transition: var(--wp--custom--motion--fast);
	cursor: pointer;
	white-space: nowrap;
	line-height: var(--wp--custom--button--line-height) !important; /* GF's mobile input rule is (0,6,1) with its :not() chain */
}
.weave-contact__form .gform_wrapper.gravity-theme .gform_footer input[type=submit]:hover, .weave-contact__form .gform_wrapper.gravity-theme .gform_footer input[type=submit]:focus-visible, .weave-contact__form .gform_wrapper .gform_button:hover, .weave-contact__form .gform_wrapper .gform_button:focus-visible { background: var(--wp--preset--color--primary); color: var(--wp--preset--color--tertiary-light); }
/* G6. Grid rhythm: live's row gap equals the body line height, column gap 2%, footer 2.5em above. */
.weave-contact__form .gform_wrapper .gform_fields { row-gap: var(--wp--preset--spacing--30); column-gap: 2%; }
.weave-contact__form .gform_wrapper .gform_footer { margin-top: 2.5em; padding: 1em 0; }
/* G8. Validation state: GF's default paints an off-palette red box and pink fill on fields that are
 *     otherwise underlines. Keep the underline, colour it and the message with the error token. */
.weave-contact__form .gform_wrapper.gravity-theme .gfield_error input:not([type=submit]),
.weave-contact__form .gform_wrapper.gravity-theme .gfield_error textarea,
.weave-contact__form .gform_wrapper.gravity-theme .gfield_error select { border: 0; border-bottom: 2px solid var(--wp--preset--color--error); background: transparent; }
.weave-contact__form .gform_wrapper.gravity-theme .gfield_error .gfield_label { color: var(--wp--preset--color--primary); }
.weave-contact__form .gform_wrapper.gravity-theme .gfield_validation_message,
.weave-contact__form .gform_wrapper.gravity-theme .validation_message { background: transparent; border: 0; padding: 0.25em 0 0; color: var(--wp--preset--color--error); font-size: var(--wp--preset--font-size--small); }
.weave-contact__form .gform_wrapper.gravity-theme .gform_validation_errors { background: transparent; border: 0; box-shadow: none; padding: 0 0 1em; color: var(--wp--preset--color--error); }
.weave-contact__form .gform_wrapper.gravity-theme .gform_validation_errors:focus { outline-color: var(--wp--preset--color--primary); outline-offset: 4px; } /* GF focuses the summary and outlines it in its own red */
.weave-contact__form .gform_wrapper.gravity-theme .gform_validation_errors > h2 { padding-left: 0; }
.weave-contact__form .gform_wrapper.gravity-theme .gform_validation_errors .gform-icon { position: static; display: inline-block; margin-right: 0.4em; vertical-align: -0.1em; }
.weave-contact__form .gform_wrapper.gravity-theme .gform_validation_errors > h2 { font-family: var(--wp--preset--font-family--bricolage-grotesque); font-size: var(--wp--preset--font-size--body); font-weight: 400; color: var(--wp--preset--color--error); }
/* G7. The hero's decorative glow (H9) also sits behind the contact band, recoloured: live's contact blob
 *     is a cool blue / lilac wash centred behind the H1, not the homepage's warm conic. */
.weave-contact { position: relative; overflow: hidden; isolation: isolate; }
.weave-contact::before {
	left: 25%;
	width: 50%;
	height: 50%;
	background: radial-gradient(closest-side, var(--wp--preset--color--baby-blue-eyes), var(--wp--preset--color--baby-blue-eyes-light) 55%, transparent);
	opacity: 0.8;
	animation-name: weave-contact-blob;
}
@keyframes weave-contact-blob {
	0%   { transform: translate(-6%, 0) scale(2.0); opacity: 0.6; }
	50%  { transform: translate(6%, 10%) scale(2.4); opacity: 0.8; }
	100% { transform: translate(-6%, 0) scale(2.0); opacity: 0.6; }
}

/* ------------------------------------------------------------------
 * About (Phase 8).
 * ------------------------------------------------------------------ */

/* AW1. Award screenshot reveal: a Deep Teal rounded panel (design walkthrough; the colour is the
 *      brand sheet's #0d3a4d, now the deep-teal token) holds a 347:408 window clipping a full-length
 *      page screenshot that scrolls up over 8s on hover or focus-within, as live (PowerPack "image
 *      scroll"). Core has no clip-and-reveal control. The window sits flush to the panel bottom, so
 *      the panel clips it with its own radius; the travel is the image height minus the window height
 *      (container units, right at every card width). Reduced motion shows the top of the page and
 *      never scrolls. The focus ring is drawn inside the clip box so it stays visible. */
.weave-award__panel { overflow: hidden; }
.weave-award__window { aspect-ratio: 347 / 408; overflow: hidden; container-type: size; border-radius: var(--wp--preset--border-radius--small) var(--wp--preset--border-radius--small) 0 0; }
.weave-award__window img { display: block; width: 100%; height: auto; transition: transform 8s ease-in-out; }
.weave-award:hover .weave-award__window img, .weave-award:focus-within .weave-award__window img { transform: translateY(calc(100cqh - 100%)); }
.weave-award__window a:focus-visible { outline-offset: -4px; }
@media (prefers-reduced-motion: reduce) { .weave-award__window img { transition: none; } .weave-award:hover .weave-award__window img, .weave-award:focus-within .weave-award__window img { transform: none; } }

/* AW2. About page staggers: the middle award card and the second team column sit lower on desktop
 *      (live 186 / 120). Columns stack below 782px, so the offsets are CSS at that breakpoint rather
 *      than block margins, which would otherwise leave a void in the stacked mobile layout. */
@media (min-width: 782px) {
	.weave-award.weave-award--stagger { margin-top: calc(var(--wp--preset--spacing--70) + var(--wp--preset--spacing--50)); } /* doubled class: core's layout rule (> * { margin-block-start: 0 }) has the same specificity and loads later */
	.weave-team__stagger { padding-top: calc(var(--wp--preset--spacing--70) + var(--wp--preset--spacing--20)); } /* live 145 */
}

/* TM1. Team bios: live reveals each bio with a View bio / Hide toggle (Beaver Builder visibility
 *      toggler). Core Details gives the reveal natively; this styles its summary as the site's pill
 *      button, moves it below the bio when open (as live's Hide) and swaps the visible label. The
 *      accessible name stays "View bio"; the expanded state is native disclosure semantics. */
.weave-bio { border: 0; padding: 0; }
.weave-bio[open] { display: flex; flex-direction: column; gap: var(--wp--preset--spacing--20); }
.weave-bio > summary { list-style: none; cursor: pointer; display: inline-flex; align-items: center; width: fit-content; background: var(--wp--preset--color--secondary); color: var(--wp--preset--color--primary); border-radius: var(--wp--preset--border-radius--pill); padding: var(--wp--custom--button--padding-y) var(--wp--custom--button--padding-x); font-size: var(--wp--custom--button--font-size); line-height: var(--wp--custom--button--line-height); font-weight: 400; transition: var(--wp--custom--motion--fast); }
.weave-bio > summary::-webkit-details-marker { display: none; }
.weave-bio > summary::after { content: ""; width: 0.7em; height: 0.7em; margin-left: 0.5em; background: currentColor; -webkit-mask: url("assets/images/icons/arrow-up-right.svg") no-repeat center / contain; mask: url("assets/images/icons/arrow-up-right.svg") no-repeat center / contain; }
.weave-bio > summary:hover, .weave-bio > summary:focus-visible { background: var(--wp--preset--color--primary); color: var(--wp--preset--color--tertiary-light); }
.weave-bio[open] > summary { order: 2; font-size: 0; }
.weave-bio[open] > summary::before { content: "Hide"; font-size: var(--wp--custom--button--font-size); }
.weave-bio[open] > summary::after { content: none; }
@media (prefers-reduced-motion: reduce) { .weave-bio > summary { transition: none; } }

/* SI1. Services index collage: the office photo and the text column sit 200 below the phone photo on
 *      desktop (live 216), cleared when Columns stack below 782. */
@media (min-width: 782px) { .weave-services-intro__offset { padding-top: calc(var(--wp--preset--spacing--70) + var(--wp--preset--spacing--60)); } }

/* HP1. Hosting plan cards: the Details disclosure uses the site's "+" / "–" toggle instead of the
 *      browser's triangle, to match the FAQ accordion below it. */
.weave-plan__details > summary { list-style: none; cursor: pointer; display: flex; justify-content: space-between; align-items: center; }
.weave-plan__details > summary::-webkit-details-marker { display: none; }
.weave-plan__details > summary::after { content: "+"; font-size: 1.5em; line-height: 1; }
.weave-plan__details[open] > summary::after { content: "\2013"; }

/* 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: Weave-Icons 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;
}

/* 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; live 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); }
