/*
Theme Name: Vorezan
Theme URI: https://vorezan.com/
Author: Vorezan
Author URI: https://vorezan.com/
Description: Vorezan is a standalone WordPress block theme (FSE) built for a B2B knowledge platform about Ukrainian agricultural products, markets, logistics and standards. It ships a full design system in theme.json, self-hosted Noto Sans (Latin, Latin Extended, Cyrillic, Cyrillic Extended, Arabic) for multilingual use, and templates for the vz_* custom post types provided by ACF.
Requires at least: 6.6
Tested up to: 6.9
Requires PHP: 8.1
Version: 1.6.1
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: vorezan
Tags: full-site-editing, block-patterns, custom-colors, custom-logo, custom-menu, editor-style, featured-images, rtl-language-support, translation-ready, wide-blocks, block-styles, template-parts

Vorezan WordPress Theme, (C) 2026 Vorezan.
Vorezan is distributed under the terms of the GNU GPL v2 or later.

Noto Sans and Noto Sans Arabic are licensed under the SIL Open Font License 1.1
(see assets/fonts/README.md).
*/

/* -------------------------------------------------------------------------
 * Almost every visual decision lives in theme.json. This stylesheet only
 * carries what theme.json cannot express: base normalisation, accessibility
 * helpers and a few low-level primitives that block patterns reuse.
 * ---------------------------------------------------------------------- */

/* --- 1. Base --------------------------------------------------------- */

html {
	-webkit-text-size-adjust: 100%;
	text-size-adjust: 100%;
}

@media (prefers-reduced-motion: no-preference) {
	html {
		scroll-behavior: smooth;
	}
}

body {
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	text-rendering: optimizeLegibility;
	font-synthesis-weight: none; /* variable font: never fake bold */
}

/* Anchor targets sit below the sticky header. */
:target {
	scroll-margin-top: 6rem;
}

/* --- 2. Accessibility ------------------------------------------------ */

:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
	outline: 2px solid var(--wp--preset--color--primary);
	outline-offset: 2px;
	border-radius: var(--wp--custom--radius--xs);
}

.screen-reader-text {
	border: 0;
	clip-path: inset(50%);
	height: 1px;
	margin: -1px;
	overflow: hidden;
	padding: 0;
	position: absolute;
	width: 1px;
	word-wrap: normal !important;
}

.screen-reader-text:focus {
	background-color: var(--wp--preset--color--base);
	box-shadow: var(--wp--preset--shadow--dropdown);
	clip-path: none;
	color: var(--wp--preset--color--primary);
	display: block;
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	height: auto;
	left: 1rem;
	line-height: normal;
	padding: 0.75rem 1.25rem;
	text-decoration: none;
	top: 1rem;
	width: auto;
	z-index: 100000;
}

/* --- 3. Media -------------------------------------------------------- */

img,
video {
	max-width: 100%;
	height: auto;
}

figure {
	margin: 0;
}

/* --- 4. Pattern primitives ------------------------------------------- */

/* Card surface: hover lift used by product / guide / question cards. */
.vz-card {
	transition: box-shadow var(--wp--custom--transition--base),
		transform var(--wp--custom--transition--base),
		border-color var(--wp--custom--transition--base);
}

.vz-card:hover,
.vz-card:focus-within {
	border-color: var(--wp--preset--color--outline-strong);
	box-shadow: var(--wp--preset--shadow--card-hover);
}

@media (prefers-reduced-motion: no-preference) {
	.vz-card--lift:hover,
	.vz-card--lift:focus-within {
		transform: translateY(-2px);
	}
}

/* Whole-card link: the first link inside stretches over the card. */
.vz-card--linked {
	position: relative;
}

.vz-card--linked a::after {
	content: "";
	position: absolute;
	inset: 0;
}

/* Truncate long excerpts to keep card grids aligned. */
.vz-clamp-1,
.vz-clamp-2,
.vz-clamp-3 {
	display: -webkit-box;
	-webkit-box-orient: vertical;
	overflow: hidden;
}

.vz-clamp-1 {
	-webkit-line-clamp: 1;
	line-clamp: 1;
}

.vz-clamp-2 {
	-webkit-line-clamp: 2;
	line-clamp: 2;
}

.vz-clamp-3 {
	-webkit-line-clamp: 3;
	line-clamp: 3;
}

/* Sticky sidebar column (product / market / route pages). */
.vz-sticky {
	position: sticky;
	top: 6rem;
}

/* Horizontally scrollable in-page tab bar (Overview | Specifications | ...). */
.vz-scroll-x {
	overflow-x: auto;
	overscroll-behavior-x: contain;
	scrollbar-width: none;
	-ms-overflow-style: none;
	flex-wrap: nowrap !important;
}

.vz-scroll-x::-webkit-scrollbar {
	display: none;
}

.vz-scroll-x > * {
	flex-shrink: 0;
}

/* Eyebrow / label above titles: "KNOWLEDGE", "MARKET", "CATEGORY". */
.vz-eyebrow {
	font-size: var(--wp--preset--font-size--x-small);
	font-weight: 600;
	letter-spacing: var(--wp--custom--typography--letter-spacing--wide);
	text-transform: uppercase;
}

/* Taxonomy chip: the small tinted label on cards and result rows. */
.vz-tag {
	display: inline-flex;
	align-items: center;
	gap: 0.35rem;
	width: fit-content;
	padding: 0.2rem 0.5rem;
	border-radius: var(--wp--custom--radius--xs);
	background-color: var(--wp--preset--color--surface-accent);
	font-size: var(--wp--preset--font-size--x-small);
	font-weight: 600;
	letter-spacing: var(--wp--custom--typography--letter-spacing--wide);
	line-height: 1.4;
	text-transform: uppercase;
}

.vz-tag a {
	text-decoration: none;
}

/* --- 5. Editor / RTL niceties ---------------------------------------- */

/* Keep decorative arrows pointing the right way in RTL locales. */
html[dir="rtl"] .vz-flip-rtl {
	transform: scaleX(-1);
}

/* --- 6. Site header --------------------------------------------------
 * The header part is built from three stacked constrained groups:
 * .vz-topbar (dark utility bar) → .vz-header (brand + search + actions)
 * → .vz-navbar (main navigation). Everything below is chrome that
 * theme.json cannot express: icon clusters, the search pill, the badge on
 * "Saved" and the underline on the current navigation item.
 * ------------------------------------------------------------------- */

.vz-topbar {
	font-size: var(--wp--preset--font-size--x-small);
	line-height: 1.4;
}

/* Links on the dark bar inherit the bar colour instead of the brand green. */
.vz-topbar a,
.vz-topbar .wp-block-navigation-item__content {
	color: inherit;
	text-decoration: none;
}

.vz-topbar a:hover,
.vz-topbar a:focus-visible,
.vz-topbar .wp-block-navigation-item__content:hover,
.vz-topbar .wp-block-navigation-item__content:focus-visible {
	color: inherit;
	text-decoration: underline;
}

.vz-topbar .vz-icon {
	flex: none;
	opacity: 0.75;
}

.vz-trust {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.25rem 1rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

.vz-trust__item {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
}

.vz-trust__item + .vz-trust__item {
	border-inline-start: 1px solid rgb(255 255 255 / 18%);
	padding-inline-start: 1rem;
}

/* Utility nav + language switcher cluster: never squeezed by the claim. */
.vz-topbar__meta {
	flex: none;
}

.vz-lang {
	display: inline-flex;
	align-items: center;
}

.vz-lang__toggle {
	display: inline-flex;
	align-items: center;
	gap: 0.3rem;
	font-weight: 600;
}

.vz-lang__toggle .vz-icon--chevron {
	opacity: 0.55;
}

.vz-header {
	position: relative;
	z-index: 20;
}

/* Brand lockup: logo + wordmark + descriptor, tight vertical rhythm. */
.vz-brand .wp-block-site-logo {
	flex: none;
	line-height: 0;
}

.vz-brand__text {
	gap: 0;
	min-width: 0;
}

.vz-brand__name a:hover,
.vz-brand__name a:focus-visible {
	text-decoration: none;
}

.vz-brand__tagline {
	margin: 0;
	white-space: nowrap;
}

/* Search pill (core search block, button-inside + icon). */
.vz-search {
	flex: 1 1 20rem;
	min-width: 0;
	max-width: 40rem;
}

.vz-search .wp-block-search__inside-wrapper {
	gap: 0.25rem;
	padding: 0.25rem;
	border: 1px solid var(--wp--preset--color--outline);
	border-radius: var(--wp--custom--radius--pill);
	background-color: var(--wp--preset--color--base);
	transition: border-color var(--wp--custom--transition--base),
		box-shadow var(--wp--custom--transition--base);
}

.vz-search:focus-within .wp-block-search__inside-wrapper {
	border-color: var(--wp--preset--color--primary);
	box-shadow: 0 0 0 3px rgb(51 122 69 / 12%);
}

.vz-search .wp-block-search__input {
	min-width: 0;
	padding: 0.5rem 0.5rem 0.5rem 1rem;
	border: 0;
	background-color: transparent;
	font-size: var(--wp--preset--font-size--small);
}

.vz-search .wp-block-search__input:focus {
	outline: none;
}

.vz-search .wp-block-search__button {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 2.75rem;
	padding: 0.5rem 1rem;
	border: 0;
	border-radius: var(--wp--custom--radius--pill);
	background-color: var(--wp--preset--color--primary);
	color: var(--wp--custom--on-brand);
	transition: background-color var(--wp--custom--transition--base);
}

.vz-search .wp-block-search__button:hover,
.vz-search .wp-block-search__button:focus-visible {
	background-color: var(--wp--preset--color--primary-dark);
}

.vz-search .wp-block-search__button svg {
	fill: currentColor;
}

/* Full width variant used on the search results and 404 templates. */
.vz-search--page {
	flex-basis: auto;
	max-width: none;
}

/* Icon + label actions: "Business Inquiry", "Saved". */
.vz-action {
	display: inline-flex;
	align-items: center;
	gap: 0.6rem;
	color: var(--wp--preset--color--contrast);
	text-decoration: none;
}

.vz-action:hover,
.vz-action:focus-visible {
	color: var(--wp--preset--color--primary);
	text-decoration: none;
}

.vz-action__icon {
	position: relative;
	display: inline-flex;
	flex: none;
	align-items: center;
	justify-content: center;
	width: 2.5rem;
	height: 2.5rem;
	border: 1px solid var(--wp--preset--color--outline);
	border-radius: var(--wp--custom--radius--md);
	color: var(--wp--preset--color--primary);
}

.vz-action--saved .vz-action__icon {
	width: auto;
	height: auto;
	border: 0;
	color: inherit;
}

.vz-action__text {
	display: flex;
	flex-direction: column;
	line-height: 1.3;
}

.vz-action__label {
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
}

.vz-action__label--sm {
	font-size: var(--wp--preset--font-size--x-small);
	font-weight: 600;
}

.vz-action__hint {
	color: var(--wp--preset--color--contrast-subtle);
	font-size: var(--wp--preset--font-size--x-small);
}

/* Populated by the saved-items script; stays hidden while empty. */
.vz-action__count {
	position: absolute;
	inset-block-start: -0.4rem;
	inset-inline-end: -0.6rem;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 1.125rem;
	height: 1.125rem;
	padding: 0 0.25rem;
	border-radius: var(--wp--custom--radius--pill);
	background-color: var(--wp--preset--color--primary);
	color: var(--wp--custom--on-brand);
	font-size: 0.625rem;
	font-weight: 700;
	line-height: 1;
}

.vz-action__count[hidden] {
	display: none;
}

/* Primary call to action keeps its width even when the row wraps. */
.vz-cta {
	flex: none;
}

/* The navigation bar must be the topmost header layer. Its stacking context
 * traps the z-index of everything inside it, and it holds both the desktop
 * dropdowns and the mobile overlay dialog (a fixed-position panel that core
 * gives z-index 100000 — a value that only applies *within* this context). */
.vz-navbar {
	position: relative;
	z-index: 30;
}

.vz-mainnav {
	width: 100%;
}

/* Desktop navigation: tab-like items with a current-page underline.
 * 600px is where core swaps the navigation block's overlay menu for the
 * inline list, so the desktop chrome has to start at exactly that width. */
@media (min-width: 600px) {
	.vz-navbar .wp-block-navigation__container > .wp-block-navigation-item {
		display: flex;
		align-items: center;
		padding-inline: 0.75rem;
		border-block-end: 2px solid transparent;
	}

	.vz-navbar .wp-block-navigation__container > .wp-block-navigation-item > .wp-block-navigation-item__content {
		padding-block: 0.875rem;
		font-weight: 500;
	}

	.vz-navbar .wp-block-navigation__container > .current-menu-item,
	.vz-navbar .wp-block-navigation__container > .current-menu-parent,
	.vz-navbar .wp-block-navigation__container > .current-menu-ancestor,
	.vz-navbar .wp-block-navigation__container > .wp-block-navigation-item:hover {
		border-block-end-color: var(--wp--preset--color--primary);
	}

	.vz-navbar .wp-block-navigation__container > .current-menu-item > .wp-block-navigation-item__content,
	.vz-navbar .wp-block-navigation__container > .current-menu-parent > .wp-block-navigation-item__content,
	.vz-navbar .wp-block-navigation__container > .current-menu-ancestor > .wp-block-navigation-item__content {
		color: var(--wp--preset--color--primary);
	}

	.vz-navbar .wp-block-navigation__submenu-container {
		padding: 0.375rem;
		border-color: var(--wp--preset--color--outline);
		border-radius: var(--wp--custom--radius--md);
		background-color: var(--wp--preset--color--base);
		box-shadow: var(--wp--preset--shadow--dropdown);
	}

	/* Core keeps a closed submenu at 0x0 and only sizes it once it opens.
	 * An unscoped min-width would therefore give every closed dropdown a
	 * real width and push a horizontal scrollbar onto the page. */
	.vz-navbar .has-child:hover > .wp-block-navigation__submenu-container,
	.vz-navbar .has-child:focus-within > .wp-block-navigation__submenu-container,
	.vz-navbar .has-child .wp-block-navigation-submenu__toggle[aria-expanded="true"] ~ .wp-block-navigation__submenu-container {
		min-width: 15rem;
	}

	/* Anchor the right-most dropdown to its item's right edge so it cannot
	 * hang off the viewport on narrow desktop widths. */
	.vz-navbar .wp-block-navigation__container > .wp-block-navigation-item:last-child .wp-block-navigation__submenu-container {
		left: auto;
		right: 0;
	}

	.vz-navbar .wp-block-navigation__submenu-container .wp-block-navigation-item__content {
		padding: 0.5rem 0.75rem;
		border-radius: var(--wp--custom--radius--sm);
	}

	.vz-navbar .wp-block-navigation__submenu-container .wp-block-navigation-item__content:hover,
	.vz-navbar .wp-block-navigation__submenu-container .wp-block-navigation-item__content:focus-visible {
		background-color: var(--wp--preset--color--surface);
		color: var(--wp--preset--color--primary);
	}
}

/* Compact header on narrow viewports. */
@media (max-width: 1180px) {
	.vz-actions .vz-action__text {
		display: none;
	}
}

@media (max-width: 1023px) {
	.vz-trust__item:not(.vz-trust__item--claim) {
		display: none;
	}
}

@media (max-width: 781px) {
	/* Search drops to its own row instead of being hidden. */
	.vz-search {
		order: 3;
		flex-basis: 100%;
		max-width: none;
	}

	.vz-actions .vz-action {
		display: none;
	}
}

/* Below core's navigation breakpoint the utility links move into the
 * overlay menu. Two classes are needed to outrank the `body .is-layout-flex`
 * rule that global styles emits for every flex-layout block. */
@media (max-width: 599px) {
	.vz-topbar .vz-topbar__nav {
		display: none;
	}
}

/* Mobile overlay menu: full-height panel with comfortable tap targets. */
.vz-navbar .wp-block-navigation__responsive-container.is-menu-open {
	padding: var(--wp--preset--spacing--50);
	background-color: var(--wp--preset--color--base);
}

.vz-navbar .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item__content {
	padding-block: 0.375rem;
}

/* Core flattens submenus into the panel, which leaves every entry looking
 * alike. Restore the hierarchy: top-level entries act as section titles,
 * separated by hairlines, with their children set smaller and muted. */
.vz-navbar .is-menu-open .wp-block-navigation__container > .wp-block-navigation-item > .wp-block-navigation-item__content {
	font-size: var(--wp--preset--font-size--large);
	font-weight: 600;
	color: var(--wp--preset--color--contrast);
}

.vz-navbar .is-menu-open .wp-block-navigation__container > .wp-block-navigation-item + .wp-block-navigation-item {
	margin-top: var(--wp--preset--spacing--30);
	padding-top: var(--wp--preset--spacing--30);
	border-top: var(--wp--custom--border--hairline);
}

.vz-navbar .is-menu-open .wp-block-navigation__submenu-container .wp-block-navigation-item__content {
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--contrast-muted);
}

/* --- 7. Site footer -------------------------------------------------- */

/* The footer is the last thing on every page, so it owns the bottom margin
 * collapse and keeps its own top rule visible even on tinted pages. */
.vz-footer {
	margin-block-start: auto;
}

/* Link columns wrap to two-up on tablets before stacking entirely; the brand
 * column is allowed to keep more width than the flex-basis attribute asks for
 * once the columns start wrapping. */
.vz-footer__main.wp-block-columns {
	flex-wrap: wrap;
}

.vz-footer__main > .wp-block-column {
	flex-basis: auto;
	flex-grow: 1;
	min-inline-size: 9rem;
}

.vz-footer__brand {
	min-inline-size: 16rem;
}

.vz-footer__brand p {
	color: var(--wp--preset--color--contrast-muted);
}

@media (max-width: 781px) {
	.vz-footer__main > .wp-block-column,
	.vz-footer__brand {
		flex-basis: 100%;
	}
}

/* The newsletter band puts copy and form side by side, stacking when narrow. */
.vz-newsletter-band > .wp-block-group {
	flex: 1 1 24rem;
	min-width: 0;
}

.vz-newsletter-band .wp-block-heading {
	margin-block: 0;
	letter-spacing: var(--wp--custom--typography--letter-spacing--heading);
}

/* Link column headings are labels, not article headings. */
.vz-footer__links .wp-block-heading {
	margin-block: 0;
	letter-spacing: var(--wp--custom--typography--letter-spacing--heading);
}

.vz-footer__bottom > p {
	margin-block: 0;
}

/* Core forces `color: inherit` on navigation links through a deliberately
 * doubled class selector, so a resting colour has to be set on the
 * navigation container and inherited down to the links. */
.vz-footer__nav {
	color: var(--wp--preset--color--contrast-muted);
}

.vz-footer__legal {
	color: var(--wp--preset--color--contrast-subtle);
}

.vz-footer__nav .wp-block-navigation-item__content:hover,
.vz-footer__nav .wp-block-navigation-item__content:focus-visible,
.vz-footer__legal .wp-block-navigation-item__content:hover,
.vz-footer__legal .wp-block-navigation-item__content:focus-visible {
	color: var(--wp--preset--color--primary);
	text-decoration: underline;
}

.vz-social .wp-social-link {
	border-radius: var(--wp--custom--radius--pill);
}

/* Newsletter form: connect the action to an ESP or newsletter plugin. */
.vz-newsletter {
	display: flex;
	flex: 1 1 20rem;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.5rem;
	max-width: 28rem;
}

.vz-newsletter__input {
	min-width: 14rem;
	flex: 1 1 14rem;
	padding: 0.7rem 0.9rem;
	border: 1px solid var(--wp--preset--color--outline);
	border-radius: var(--wp--custom--radius--sm);
	background-color: var(--wp--preset--color--base);
	color: var(--wp--preset--color--contrast);
	font-family: inherit;
	font-size: var(--wp--preset--font-size--small);
}

.vz-newsletter__input:focus {
	border-color: var(--wp--preset--color--primary);
	box-shadow: 0 0 0 3px rgb(51 122 69 / 12%);
	outline: none;
}

.vz-newsletter__submit {
	border: 0;
	cursor: pointer;
}

/* --- 8. Listings, cards and pagination ------------------------------- */

/* Clips a flush featured image to the rounded card corners. */
.vz-card--clip {
	overflow: hidden;
}

.vz-card--clip .wp-block-post-featured-image {
	margin-block: 0;
}

/* theme.json gives core/post-title display-sized tracking for single views;
 * card and result titles are much smaller and need normal heading tracking. */
.vz-card .wp-block-post-title {
	margin-block: 0;
	letter-spacing: var(--wp--custom--typography--letter-spacing--heading);
}

/* Card titles read as headings first, links second. */
.vz-card .wp-block-post-title a {
	color: var(--wp--preset--color--contrast);
}

.vz-card .wp-block-post-title a:hover,
.vz-card .wp-block-post-title a:focus-visible {
	color: var(--wp--preset--color--primary);
	text-decoration: underline;
}

/* Search results read as list rows rather than tiles in a grid. */
.vz-result .wp-block-post-terms,
.vz-result .wp-block-post-date {
	margin-block: 0;
}

.vz-pagination {
	gap: 0.5rem;
}

.vz-pagination .wp-block-query-pagination-numbers {
	display: flex;
	gap: 0.5rem;
	margin: 0;
}

.vz-pagination .page-numbers,
.vz-pagination .wp-block-query-pagination-previous,
.vz-pagination .wp-block-query-pagination-next {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 2.375rem;
	padding: 0.4rem 0.75rem;
	border: 1px solid var(--wp--preset--color--outline);
	border-radius: var(--wp--custom--radius--sm);
	color: var(--wp--preset--color--contrast-muted);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 500;
	text-decoration: none;
}

.vz-pagination .page-numbers:hover,
.vz-pagination .wp-block-query-pagination-previous:hover,
.vz-pagination .wp-block-query-pagination-next:hover {
	border-color: var(--wp--preset--color--outline-strong);
	color: var(--wp--preset--color--primary);
	text-decoration: none;
}

.vz-pagination .page-numbers.current {
	border-color: var(--wp--preset--color--primary);
	background-color: var(--wp--preset--color--primary);
	color: var(--wp--custom--on-brand);
}

.vz-pagination .page-numbers.dots {
	border-color: transparent;
}

/* Post / article meta row and prev-next links. */
.vz-meta,
.vz-postnav {
	font-size: var(--wp--preset--font-size--small);
}

.vz-postnav .wp-block-post-navigation-link a {
	font-weight: 600;
}

/* --- 9. Two-column entity layout -------------------------------------
   Product / market / route / standard / guide singles: main column plus a
   sticky sidebar that collapses to a single column on tablet.
   ------------------------------------------------------------------- */

.vz-layout {
	display: grid;
	grid-template-columns: minmax(0, 1fr) var(--wp--custom--layout--sidebar);
	gap: clamp(1.5rem, 3vw, 3rem);
	align-items: start;
}

/* Neutralise the core flow-layout gap: the grid gap above owns the spacing. */
.vz-layout.is-layout-flow > * + *,
.vz-layout.is-layout-constrained > * + * {
	margin-block-start: 0;
}

.vz-layout__main {
	min-width: 0;
}

.vz-layout__aside {
	min-width: 0;
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--40);
}

@media (max-width: 1023px) {
	.vz-layout {
		grid-template-columns: minmax(0, 1fr);
	}

	.vz-layout__aside .vz-sticky {
		position: static;
	}
}

/* Section rhythm inside the main column. */
.vz-layout__main > * + * {
	margin-block-start: var(--wp--preset--spacing--60);
}

.vz-section__title {
	margin-block: 0 0.6em;
	font-size: var(--wp--preset--font-size--x-large);
	letter-spacing: var(--wp--custom--typography--letter-spacing--heading);
	line-height: 1.25;
	scroll-margin-block-start: calc(var(--wp--custom--layout--header-height) + 4rem);
}

.vz-section__intro {
	margin-block: 0 1.25em;
	max-width: 68ch;
	color: var(--wp--preset--color--contrast-muted);
}

/* --- 10. Breadcrumbs -------------------------------------------------- */

.vz-crumbs {
	font-size: var(--wp--preset--font-size--x-small);
	color: var(--wp--preset--color--contrast-subtle);
}

.vz-crumbs__list {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.15rem 0.45rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

.vz-crumbs__item {
	display: inline-flex;
	align-items: center;
	gap: 0.45rem;
	margin: 0;
}

.vz-crumbs__item + .vz-crumbs__item::before {
	content: "/";
	color: var(--wp--preset--color--outline-strong);
}

.vz-crumbs__item a {
	color: inherit;
	text-decoration: none;
}

.vz-crumbs__item a:hover,
.vz-crumbs__item a:focus-visible {
	color: var(--wp--preset--color--primary);
	text-decoration: underline;
}

.vz-crumbs__item--current {
	color: var(--wp--preset--color--contrast);
	font-weight: 600;
}

/* --- 11. Fact strip -------------------------------------------------- */

.vz-facts {
	display: grid;
	/* Container-aware: tracks wrap when narrow instead of shrinking to zero. */
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
	gap: 1rem clamp(1rem, 2.5vw, 2rem);
	margin: 0;
	padding: 0;
	list-style: none;
}

.vz-facts__heading {
	margin-block: 0 0.75em;
	font-size: var(--wp--preset--font-size--small);
	font-weight: 700;
	letter-spacing: var(--wp--custom--typography--letter-spacing--wide);
	text-transform: uppercase;
	color: var(--wp--preset--color--contrast-subtle);
}

.vz-fact {
	display: flex;
	align-items: flex-start;
	gap: 0.65rem;
	margin: 0;
	min-width: 0;
}

.vz-fact__icon {
	display: inline-flex;
	flex: 0 0 auto;
	align-items: center;
	justify-content: center;
	inline-size: 2rem;
	block-size: 2rem;
	border-radius: var(--wp--custom--radius--sm);
	background-color: var(--wp--preset--color--surface-accent);
	color: var(--wp--preset--color--primary);
}

.vz-fact__body {
	display: flex;
	flex-direction: column;
	min-width: 0;
}

.vz-fact__label {
	font-size: var(--wp--preset--font-size--x-small);
	color: var(--wp--preset--color--contrast-subtle);
	line-height: 1.4;
}

.vz-fact__value {
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	line-height: 1.4;
	overflow-wrap: anywhere;
}

/* List variant: one fact per row, used inside the sidebar. */
.vz-facts--list {
	grid-template-columns: minmax(0, 1fr);
	gap: 0.85rem;
}

.vz-facts--list .vz-fact {
	padding-block-end: 0.85rem;
	border-block-end: var(--wp--custom--border--hairline);
}

.vz-facts--list .vz-fact:last-child {
	padding-block-end: 0;
	border-block-end: 0;
}

/* Stats variant: big number over a caption, used in market / standard heroes. */
.vz-facts--stats .vz-fact {
	flex-direction: column;
	gap: 0.2rem;
	padding: 1rem 1.15rem;
	border: 1px solid var(--wp--preset--color--outline);
	border-radius: var(--wp--custom--radius--md);
	background-color: var(--wp--preset--color--base);
}

.vz-facts--stats .vz-fact__icon {
	display: none;
}

.vz-facts--stats .vz-fact__value {
	order: -1;
	font-size: var(--wp--preset--font-size--x-large);
	font-weight: 700;
	color: var(--wp--preset--color--primary);
	letter-spacing: var(--wp--custom--typography--letter-spacing--heading);
}

@media (max-width: 781px) {
	.vz-facts {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (max-width: 480px) {
	.vz-facts,
	.vz-facts--stats {
		grid-template-columns: minmax(0, 1fr);
	}
}

/* --- 12. In-page tab bar --------------------------------------------- */

.vz-tabs {
	border-block-end: var(--wp--custom--border--hairline);
	background-color: var(--wp--preset--color--base);
}

.vz-tabs--sticky {
	position: sticky;
	/* Nothing is sticky above the tabs on desktop - the navbar only pins
	 * below 781px - so offsetting by the header height left a 72px gap
	 * that content scrolled through. The mobile rule keeps its 56px. */
	top: 0;
	z-index: 20;
}

.vz-tabs__track {
	display: flex;
	align-items: stretch;
	gap: clamp(0.75rem, 2vw, 1.75rem);
	scroll-snap-type: x proximity;
}

.vz-tabs__link {
	display: inline-flex;
	align-items: center;
	padding-block: 0.85rem;
	border-block-end: 2px solid transparent;
	color: var(--wp--preset--color--contrast-muted);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	white-space: nowrap;
	scroll-snap-align: start;
	text-decoration: none;
	transition: color var(--wp--custom--transition--base),
		border-color var(--wp--custom--transition--base);
}

.vz-tabs__link:hover,
.vz-tabs__link:focus-visible,
.vz-tabs__link--current {
	border-block-end-color: var(--wp--preset--color--primary);
	color: var(--wp--preset--color--primary);
	text-decoration: none;
}

/* --- 13. Card grids --------------------------------------------------- */

.vz-cards {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr));
	gap: clamp(0.85rem, 1.6vw, 1.25rem);
	margin: 0;
	padding: 0;
	list-style: none;
}

.vz-cards .vz-card {
	display: flex;
	flex-direction: column;
	gap: 0.7rem;
	margin: 0;
	min-width: 0;
}

.vz-card__body {
	display: flex;
	flex-direction: column;
	gap: 0.35rem;
	min-width: 0;
}

.vz-card__title {
	margin: 0;
	font-size: var(--wp--preset--font-size--small);
	font-weight: 700;
	line-height: 1.35;
}

.vz-card__text {
	margin: 0;
	font-size: var(--wp--preset--font-size--x-small);
	line-height: 1.6;
	color: var(--wp--preset--color--contrast-muted);
}

.vz-card__icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	inline-size: 2.5rem;
	block-size: 2.5rem;
	border-radius: var(--wp--custom--radius--sm);
	background-color: var(--wp--preset--color--surface-accent);
	color: var(--wp--preset--color--primary);
}

.vz-card__num {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	inline-size: 2rem;
	block-size: 2rem;
	border-radius: var(--wp--custom--radius--pill);
	background-color: var(--wp--preset--color--primary);
	color: var(--wp--custom--on-brand);
	font-size: var(--wp--preset--font-size--x-small);
	font-weight: 700;
}

.vz-card__media {
	margin: 0;
	overflow: hidden;
	border-radius: var(--wp--custom--radius--sm);
	background-color: var(--wp--preset--color--surface);
}

.vz-card__img,
.vz-card__media img {
	display: block;
	inline-size: 100%;
	block-size: auto;
	aspect-ratio: 4 / 3;
	object-fit: cover;
}

/* Variants. */
.vz-cards--icon .vz-card,
.vz-cards--bordered .vz-card,
.vz-cards--check .vz-card,
.vz-cards--numbered .vz-card {
	padding: clamp(0.9rem, 1.6vw, 1.25rem);
	border: 1px solid var(--wp--preset--color--outline);
	border-radius: var(--wp--custom--radius--md);
	background-color: var(--wp--preset--color--base);
}

.vz-cards--bordered .vz-card {
	border-inline-start: 3px solid var(--wp--preset--color--primary);
}

.vz-cards--plain .vz-card {
	padding: 0;
}

.vz-cards--check .vz-card {
	flex-direction: row;
	align-items: flex-start;
	gap: 0.65rem;
}

.vz-cards--check .vz-card__icon {
	flex: 0 0 auto;
	inline-size: 1.5rem;
	block-size: 1.5rem;
	border-radius: var(--wp--custom--radius--pill);
	background-color: var(--wp--preset--color--primary-light);
}

/* KPI variant: the figure is the title, the caption sits underneath. */
.vz-cards--kpi {
	gap: 0.9rem;
}

.vz-cards--kpi .vz-card {
	flex-direction: row;
	align-items: flex-start;
	gap: 0.7rem;
}

.vz-cards--kpi .vz-card__title {
	font-size: var(--wp--preset--font-size--large);
	font-weight: 700;
	color: var(--wp--preset--color--primary-dark);
	letter-spacing: var(--wp--custom--typography--letter-spacing--heading);
	white-space: nowrap;
}

.vz-cards--kpi .vz-card__body {
	gap: 0.1rem;
}

.vz-cards--kpi .vz-card__icon {
	inline-size: 2rem;
	block-size: 2rem;
}

@media (max-width: 1023px) {
	.vz-cards {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (max-width: 560px) {
	.vz-cards {
		grid-template-columns: minmax(0, 1fr);
	}
}

/* --- 14. Specification tables ---------------------------------------- */

.vz-tables {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: clamp(1rem, 2vw, 1.75rem);
}

.vz-tables--split {
	grid-template-columns: repeat(2, minmax(0, 1fr));
}

.vz-table {
	inline-size: 100%;
	border-collapse: collapse;
	border: 1px solid var(--wp--preset--color--outline);
	border-radius: var(--wp--custom--radius--md);
	overflow: hidden;
	font-size: var(--wp--preset--font-size--small);
	table-layout: fixed;
}

.vz-table__caption,
.vz-table caption {
	padding: 0.7rem 0.9rem;
	background-color: var(--wp--preset--color--surface-accent);
	color: var(--wp--preset--color--contrast);
	font-size: var(--wp--preset--font-size--x-small);
	font-weight: 700;
	letter-spacing: var(--wp--custom--typography--letter-spacing--wide);
	text-align: start;
	text-transform: uppercase;
}

.vz-table th,
.vz-table td {
	padding: 0.6rem 0.9rem;
	border-block-start: var(--wp--custom--border--hairline);
	text-align: start;
	vertical-align: top;
	overflow-wrap: anywhere;
}

.vz-table thead th {
	border-block-start: 0;
	background-color: var(--wp--preset--color--surface);
	font-size: var(--wp--preset--font-size--x-small);
	letter-spacing: var(--wp--custom--typography--letter-spacing--wide);
	text-transform: uppercase;
	color: var(--wp--preset--color--contrast-subtle);
}

.vz-table tbody th {
	inline-size: 45%;
	color: var(--wp--preset--color--contrast-muted);
	font-weight: 500;
}

.vz-table tbody tr:nth-child(even) {
	background-color: color-mix(in srgb, var(--wp--preset--color--surface) 55%, transparent);
}

.vz-table__strong {
	font-weight: 600;
}

.vz-table__ref,
.vz-table__note {
	display: block;
	margin-block-start: 0.2rem;
	font-size: var(--wp--preset--font-size--x-small);
	color: var(--wp--preset--color--contrast-subtle);
}

.vz-table__ref-cell,
.vz-table__note-cell {
	inline-size: 22%;
	color: var(--wp--preset--color--contrast-subtle);
	font-size: var(--wp--preset--font-size--x-small);
}

.vz-table--chapters tbody th {
	inline-size: 18%;
	color: var(--wp--preset--color--primary);
	font-weight: 700;
	white-space: nowrap;
}

.vz-table--packaging th,
.vz-table--packaging td {
	inline-size: auto;
}

@media (max-width: 781px) {
	.vz-tables--split {
		grid-template-columns: minmax(0, 1fr);
	}

	.vz-table {
		font-size: var(--wp--preset--font-size--x-small);
	}
}

/* --- 15. Process steps ----------------------------------------------- */

.vz-steps {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr));
	gap: clamp(0.75rem, 1.5vw, 1.1rem);
	margin: 0;
	padding: 0;
	list-style: none;
	counter-reset: vz-step;
}

.vz-step {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: 0.4rem;
	margin: 0;
	padding: clamp(0.85rem, 1.4vw, 1.1rem);
	border: 1px solid var(--wp--preset--color--outline);
	border-radius: var(--wp--custom--radius--md);
	background-color: var(--wp--preset--color--base);
	min-width: 0;
}

.vz-step__badge {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	inline-size: 1.75rem;
	block-size: 1.75rem;
	border-radius: var(--wp--custom--radius--pill);
	background-color: var(--wp--preset--color--surface-accent);
	color: var(--wp--preset--color--primary);
	font-size: var(--wp--preset--font-size--x-small);
	font-weight: 700;
}

.vz-step__title {
	margin: 0;
	font-size: var(--wp--preset--font-size--small);
	font-weight: 700;
	line-height: 1.3;
}

.vz-step__text {
	margin: 0;
	font-size: var(--wp--preset--font-size--x-small);
	line-height: 1.55;
	color: var(--wp--preset--color--contrast-muted);
}

.vz-step__meta {
	margin-block-start: auto;
	font-size: var(--wp--preset--font-size--x-small);
	font-weight: 600;
	color: var(--wp--preset--color--sky);
}

.vz-step__arrow {
	position: absolute;
	inset-inline-end: -0.95rem;
	inset-block-start: 50%;
	translate: 0 -50%;
	z-index: 1;
	display: inline-flex;
	color: var(--wp--preset--color--outline-strong);
}

.vz-step:last-child .vz-step__arrow {
	display: none;
}

@media (max-width: 1023px) {
	.vz-steps {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

@media (max-width: 640px) {
	.vz-steps {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}

	.vz-step__arrow {
		display: none;
	}
}

@media (max-width: 400px) {
	.vz-steps {
		grid-template-columns: minmax(0, 1fr);
	}
}

/* --- 16. FAQ accordion ----------------------------------------------- */

.vz-faq {
	display: flex;
	flex-direction: column;
	gap: 0.6rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

.vz-faq__item {
	margin: 0;
	border: 1px solid var(--wp--preset--color--outline);
	border-radius: var(--wp--custom--radius--md);
	background-color: var(--wp--preset--color--base);
	overflow: hidden;
}

.vz-faq__item[open] {
	border-color: var(--wp--preset--color--primary-light);
}

.vz-faq__q {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
	padding: 0.9rem 1.1rem;
	cursor: pointer;
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	line-height: 1.45;
	list-style: none;
}

.vz-faq__q::-webkit-details-marker {
	display: none;
}

.vz-faq__q:hover {
	color: var(--wp--preset--color--primary);
}

.vz-faq__marker {
	flex: 0 0 auto;
	display: inline-flex;
	color: var(--wp--preset--color--contrast-subtle);
	transition: rotate var(--wp--custom--transition--base);
}

.vz-faq__item[open] .vz-faq__marker {
	rotate: 180deg;
	color: var(--wp--preset--color--primary);
}

.vz-faq__a {
	padding: 0 1.1rem 1.1rem;
	font-size: var(--wp--preset--font-size--small);
	line-height: 1.7;
	color: var(--wp--preset--color--contrast-muted);
}

.vz-faq__a > :first-child {
	margin-block-start: 0;
}

.vz-faq__a > :last-child {
	margin-block-end: 0;
}

/* --- 17. Chips ------------------------------------------------------- */

.vz-chips {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

.vz-chip {
	margin: 0;
}

.vz-chip__link,
.vz-chip > span {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	padding: 0.4rem 0.75rem;
	border: 1px solid var(--wp--preset--color--outline);
	border-radius: var(--wp--custom--radius--pill);
	background-color: var(--wp--preset--color--base);
	color: var(--wp--preset--color--contrast);
	font-size: var(--wp--preset--font-size--x-small);
	font-weight: 500;
	line-height: 1.4;
	text-decoration: none;
	transition: border-color var(--wp--custom--transition--base),
		background-color var(--wp--custom--transition--base),
		color var(--wp--custom--transition--base);
}

.vz-chip__link:hover,
.vz-chip__link:focus-visible {
	border-color: var(--wp--preset--color--primary);
	background-color: var(--wp--preset--color--surface-accent);
	color: var(--wp--preset--color--primary-dark);
	text-decoration: none;
}

.vz-chip__icon {
	display: inline-flex;
	flex: 0 0 auto;
	color: var(--wp--preset--color--primary);
}

.vz-chips--flag .vz-chip__icon {
	font-size: 1.05em;
	line-height: 1;
}

.vz-chips--icon .vz-chip__link,
.vz-chips--icon .vz-chip > span {
	padding-inline: 0.65rem;
	border-radius: var(--wp--custom--radius--sm);
}

.vz-chip--more .vz-chip__link {
	border-style: dashed;
	color: var(--wp--preset--color--primary);
	font-weight: 600;
}

.vz-chip__label {
	display: inline-block;
	min-width: 0;
	overflow-wrap: anywhere;
}

.vz-chip .vz-termcard__count {
	padding: 0;
	border: 0;
	background: none;
	color: var(--wp--preset--color--contrast-subtle);
	font-size: 0.85em;
	font-weight: 400;
}

/* --- 18. Related entities -------------------------------------------- */

.vz-relgrid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
	gap: clamp(0.85rem, 1.6vw, 1.25rem);
	margin: 0;
	padding: 0;
	list-style: none;
}

.vz-relcard {
	margin: 0;
	min-width: 0;
	border: 1px solid var(--wp--preset--color--outline);
	border-radius: var(--wp--custom--radius--md);
	background-color: var(--wp--preset--color--base);
	overflow: hidden;
	transition: border-color var(--wp--custom--transition--base),
		box-shadow var(--wp--custom--transition--base);
}

.vz-relcard:hover,
.vz-relcard:focus-within {
	border-color: var(--wp--preset--color--primary-light);
	box-shadow: var(--wp--preset--shadow--card-hover);
}

.vz-relcard__link {
	display: flex;
	flex-direction: column;
	gap: 0.6rem;
	block-size: 100%;
	color: inherit;
	text-decoration: none;
}

.vz-relcard__media {
	margin: 0;
	background-color: var(--wp--preset--color--surface);
}

.vz-relcard__img,
.vz-relcard__media img {
	display: block;
	inline-size: 100%;
	block-size: auto;
	aspect-ratio: 4 / 3;
	object-fit: cover;
}

.vz-relcard__placeholder {
	display: flex;
	align-items: center;
	justify-content: center;
	aspect-ratio: 4 / 3;
	background-color: var(--wp--preset--color--surface-accent);
	color: var(--wp--preset--color--primary);
}

.vz-relcard__title {
	display: block;
	padding: 0 0.9rem 0.9rem;
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	line-height: 1.4;
}

.vz-relcard__link:hover .vz-relcard__title {
	color: var(--wp--preset--color--primary);
}

.vz-rellist {
	display: flex;
	flex-direction: column;
	gap: 0.6rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

.vz-rellist__item {
	margin: 0;
}

.vz-rellist__link {
	display: flex;
	align-items: flex-start;
	gap: 0.8rem;
	padding: 0.85rem 1rem;
	border: 1px solid var(--wp--preset--color--outline);
	border-radius: var(--wp--custom--radius--md);
	background-color: var(--wp--preset--color--base);
	color: inherit;
	text-decoration: none;
	transition: border-color var(--wp--custom--transition--base),
		background-color var(--wp--custom--transition--base);
}

.vz-rellist__link:hover,
.vz-rellist__link:focus-visible {
	border-color: var(--wp--preset--color--primary-light);
	background-color: var(--wp--preset--color--surface);
	text-decoration: none;
}

.vz-rellist__icon {
	display: inline-flex;
	flex: 0 0 auto;
	align-items: center;
	justify-content: center;
	inline-size: 2rem;
	block-size: 2rem;
	border-radius: var(--wp--custom--radius--sm);
	background-color: var(--wp--preset--color--surface-accent);
	color: var(--wp--preset--color--primary);
}

.vz-rellist__body {
	display: flex;
	flex-direction: column;
	gap: 0.15rem;
	min-width: 0;
	flex: 1 1 auto;
}

.vz-rellist__title {
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	line-height: 1.4;
}

.vz-rellist__text {
	font-size: var(--wp--preset--font-size--x-small);
	line-height: 1.55;
	color: var(--wp--preset--color--contrast-muted);
}

.vz-rellist__arrow {
	display: inline-flex;
	flex: 0 0 auto;
	align-self: center;
	color: var(--wp--preset--color--outline-strong);
}

.vz-rellist__link:hover .vz-rellist__arrow {
	color: var(--wp--preset--color--primary);
}

@media (max-width: 1023px) {
	.vz-relgrid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (max-width: 480px) {
	.vz-relgrid {
		grid-template-columns: minmax(0, 1fr);
	}
}

/* --- 19. Sidebar cards ------------------------------------------------ */

.vz-layout__aside > .wp-block-group,
.vz-layout__aside > section,
.vz-layout__aside > div {
	min-width: 0;
}

/* Sidebar card chrome, so templates only need the class name. */
.vz-aside__card {
	padding: clamp(1rem, 1.8vw, 1.35rem);
	border: 1px solid var(--wp--preset--color--outline);
	border-radius: var(--wp--custom--radius--md);
	background-color: var(--wp--preset--color--base);
}

/* Hide sidebar cards whose dynamic block rendered nothing. `:empty` alone
   misses wrappers that still contain whitespace/newline text nodes, so also
   match cards with no element children. */
.vz-aside__card:empty,
.vz-aside__card:not(:has(> *)) {
	display: none;
}

/* Tinted variant, used for the "Market potential" card. */
.vz-aside__card--accent {
	border-color: var(--wp--preset--color--primary-light);
	background-color: var(--wp--preset--color--surface-accent);
}

/* Quick-links list: the section nav rendered vertically inside a card. */
.vz-tabs.vz-tabs--aside {
	border-block-end: 0;
	background-color: transparent;
}

.vz-tabs--aside .vz-tabs__track {
	flex-direction: column;
	gap: 0;
	overflow: visible;
}

.vz-tabs--aside .vz-tabs__link {
	justify-content: space-between;
	padding-block: 0.5rem;
	border-block-end: var(--wp--custom--border--hairline);
	color: var(--wp--preset--color--contrast);
	white-space: normal;
}

.vz-tabs--aside .vz-tabs__link::after {
	content: "\203A";
	color: var(--wp--preset--color--outline-strong);
	font-size: 1.15em;
	line-height: 1;
}

.vz-tabs--aside .vz-tabs__link:last-child {
	border-block-end: 0;
}

.vz-tabs--aside .vz-tabs__link:hover,
.vz-tabs--aside .vz-tabs__link:focus-visible {
	color: var(--wp--preset--color--primary);
}

.vz-aside__card > * + * {
	margin-block-start: var(--wp--preset--spacing--30);
}

.vz-aside__title {
	margin-block: 0 0.8em;
	font-size: var(--wp--preset--font-size--medium);
	font-weight: 700;
	letter-spacing: var(--wp--custom--typography--letter-spacing--heading);
	line-height: 1.3;
}

.vz-aside__intro {
	margin-block: 0 0.8em;
	font-size: var(--wp--preset--font-size--x-small);
	color: var(--wp--preset--color--contrast-muted);
}

.vz-aside__list {
	display: flex;
	flex-direction: column;
	gap: 0.1rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

.vz-aside__item {
	margin: 0;
}

.vz-aside__link {
	display: flex;
	align-items: flex-start;
	gap: 0.55rem;
	padding: 0.5rem 0;
	border-block-end: var(--wp--custom--border--hairline);
	color: inherit;
	font-size: var(--wp--preset--font-size--x-small);
	line-height: 1.55;
	text-decoration: none;
}

.vz-aside__item:last-child .vz-aside__link {
	border-block-end: 0;
}

.vz-aside__link:hover,
.vz-aside__link:focus-visible {
	color: var(--wp--preset--color--primary);
	text-decoration: none;
}

.vz-aside__icon {
	display: inline-flex;
	flex: 0 0 auto;
	margin-block-start: 0.1rem;
	color: var(--wp--preset--color--primary);
}

.vz-aside__label {
	min-width: 0;
	overflow-wrap: anywhere;
}

/* Certification / partner logo grid. */
.vz-logos {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
	gap: 0.6rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

.vz-logo {
	margin: 0;
}

.vz-logo__link,
.vz-logo > span {
	display: flex;
	align-items: center;
	justify-content: center;
	min-block-size: 56px;
	padding: 0.5rem;
	border: 1px solid var(--wp--preset--color--outline);
	border-radius: var(--wp--custom--radius--sm);
	background-color: var(--wp--preset--color--base);
	text-align: center;
	text-decoration: none;
	transition: border-color var(--wp--custom--transition--base);
}

.vz-logo__link:hover {
	border-color: var(--wp--preset--color--primary);
	text-decoration: none;
}

.vz-logo__img {
	max-inline-size: 100%;
	block-size: auto;
	object-fit: contain;
}

.vz-logo__text {
	font-size: var(--wp--preset--font-size--x-small);
	font-weight: 700;
	letter-spacing: var(--wp--custom--typography--letter-spacing--wide);
	color: var(--wp--preset--color--contrast);
	text-transform: uppercase;
	line-height: 1.3;
}

/* --- 20. Sources & evidence ------------------------------------------ */

.vz-srcs {
	display: flex;
	flex-direction: column;
	gap: 0.7rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

.vz-src {
	display: flex;
	align-items: flex-start;
	gap: 0.6rem;
	margin: 0;
	font-size: var(--wp--preset--font-size--x-small);
	line-height: 1.55;
}

.vz-src__icon {
	display: inline-flex;
	flex: 0 0 auto;
	margin-block-start: 0.1rem;
	color: var(--wp--preset--color--contrast-subtle);
}

.vz-src__body {
	display: flex;
	flex-direction: column;
	gap: 0.1rem;
	min-width: 0;
}

.vz-src__title {
	font-weight: 600;
	overflow-wrap: anywhere;
}

.vz-src__title a {
	color: inherit;
	text-decoration: none;
}

.vz-src__title a:hover {
	color: var(--wp--preset--color--primary);
	text-decoration: underline;
}

.vz-src__meta,
.vz-src__note {
	color: var(--wp--preset--color--contrast-subtle);
}

.vz-srcs--full .vz-src {
	padding-block-end: 0.7rem;
	border-block-end: var(--wp--custom--border--hairline);
	font-size: var(--wp--preset--font-size--small);
}

.vz-srcs--full .vz-src:last-child {
	padding-block-end: 0;
	border-block-end: 0;
}

.vz-srcs__confidence {
	display: inline-flex;
	align-items: center;
	gap: 0.35rem;
	margin-block-start: 0.9rem;
	padding: 0.25rem 0.6rem;
	border-radius: var(--wp--custom--radius--pill);
	background-color: var(--wp--preset--color--surface-accent);
	color: var(--wp--preset--color--primary-dark);
	font-size: var(--wp--preset--font-size--x-small);
	font-weight: 600;
}

/* --- 21. Inquiry call to action ------------------------------------- */

.vz-cta {
	display: flex;
	gap: 1rem;
}

.vz-cta__icon {
	display: inline-flex;
	flex: 0 0 auto;
	align-items: center;
	justify-content: center;
	inline-size: 2.5rem;
	block-size: 2.5rem;
	border-radius: var(--wp--custom--radius--sm);
	background-color: var(--wp--preset--color--base);
	color: var(--wp--preset--color--primary);
}

.vz-cta__body {
	display: flex;
	flex-direction: column;
	gap: 0.45rem;
	min-width: 0;
}

.vz-cta__title {
	margin: 0;
	font-size: var(--wp--preset--font-size--medium);
	font-weight: 700;
	line-height: 1.3;
}

.vz-cta__text {
	margin: 0;
	font-size: var(--wp--preset--font-size--x-small);
	line-height: 1.6;
	color: var(--wp--preset--color--contrast-muted);
}

.vz-cta__btn {
	align-self: flex-start;
	margin-block-start: 0.35rem;
}

/* Sidebar variant: compact tinted card. */
.vz-cta--sidebar {
	flex-direction: column;
	padding: clamp(1rem, 1.8vw, 1.35rem);
	border: 1px solid var(--wp--preset--color--primary-light);
	border-radius: var(--wp--custom--radius--md);
	background-color: var(--wp--preset--color--surface-accent);
}

/* Band variant: full-width dark section at the bottom of a page. */
.vz-cta--band {
	flex-direction: column;
	align-items: center;
	padding: clamp(1.75rem, 4vw, 3.25rem) var(--wp--custom--layout--gutter);
	border-radius: var(--wp--custom--radius--lg);
	background-color: var(--wp--preset--color--deep);
	color: var(--wp--custom--on-dark);
	text-align: center;
}

.vz-cta--band .vz-cta__body {
	align-items: center;
	max-inline-size: 60ch;
}

.vz-cta--band .vz-cta__title {
	font-size: var(--wp--preset--font-size--x-large);
}

.vz-cta--band .vz-cta__text {
	font-size: var(--wp--preset--font-size--medium);
	color: color-mix(in srgb, var(--wp--preset--color--base) 78%, transparent);
}

.vz-cta--band .vz-cta__icon {
	background-color: color-mix(in srgb, var(--wp--preset--color--base) 14%, transparent);
	color: var(--wp--custom--on-dark);
}

.vz-cta--band .vz-cta__btn {
	align-self: center;
	background-color: var(--wp--preset--color--base);
	color: var(--wp--preset--color--primary-dark);
}

.vz-cta--band .vz-cta__btn:hover {
	background-color: var(--wp--preset--color--surface-accent);
	color: var(--wp--preset--color--primary-dark);
}

/* Inline variant: a single row inside the article flow. */
.vz-cta--inline {
	align-items: center;
	flex-wrap: wrap;
	padding: clamp(0.9rem, 1.6vw, 1.25rem);
	border: 1px solid var(--wp--preset--color--outline);
	border-inline-start: 3px solid var(--wp--preset--color--primary);
	border-radius: var(--wp--custom--radius--md);
	background-color: var(--wp--preset--color--surface);
}

.vz-cta--inline .vz-cta__body {
	flex: 1 1 18rem;
}

/* Buttons. */
.vz-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.45rem;
	padding: 0.65rem 1.15rem;
	border: 1px solid transparent;
	border-radius: var(--wp--custom--radius--sm);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	line-height: 1.3;
	text-decoration: none;
	transition: background-color var(--wp--custom--transition--base),
		color var(--wp--custom--transition--base),
		border-color var(--wp--custom--transition--base);
}

.vz-btn--primary {
	background-color: var(--wp--preset--color--primary);
	color: var(--wp--custom--on-brand);
}

.vz-btn--primary:hover,
.vz-btn--primary:focus-visible {
	background-color: var(--wp--preset--color--primary-dark);
	color: var(--wp--custom--on-brand);
	text-decoration: none;
}

/* "View all ..." link under a section. */
.vz-more {
	margin-block-start: 1rem;
}

.vz-more__link {
	display: inline-flex;
	align-items: center;
	gap: 0.35rem;
	color: var(--wp--preset--color--primary);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	text-decoration: none;
}

.vz-more__link:hover {
	text-decoration: underline;
}

/* --- 22. Disclaimer / review note ------------------------------------ */

.vz-note {
	display: flex;
	align-items: flex-start;
	gap: 0.75rem;
	padding: clamp(0.9rem, 1.6vw, 1.25rem);
	border: 1px solid var(--wp--preset--color--outline);
	border-radius: var(--wp--custom--radius--md);
	background-color: var(--wp--preset--color--surface);
	font-size: var(--wp--preset--font-size--x-small);
	line-height: 1.65;
	color: var(--wp--preset--color--contrast-muted);
}

.vz-note__icon {
	display: inline-flex;
	flex: 0 0 auto;
	margin-block-start: 0.1rem;
	color: var(--wp--preset--color--sky);
}

.vz-note__text {
	margin: 0;
	min-width: 0;
}

.vz-note__meta {
	display: flex;
	flex-wrap: wrap;
	gap: 0.35rem 1rem;
	margin-block-start: 0.5rem;
}

.vz-note__date {
	font-weight: 600;
	color: var(--wp--preset--color--contrast);
}

.vz-note__link {
	color: var(--wp--preset--color--primary);
	font-weight: 600;
	text-decoration: none;
}

.vz-note__link:hover {
	text-decoration: underline;
}

/* --- 23. Media: gallery, figure, video, download -------------------- */

.vz-gallery {
	display: flex;
	flex-direction: column;
	gap: 0.6rem;
	margin: 0;
}

.vz-gallery__main {
	overflow: hidden;
	border: 1px solid var(--wp--preset--color--outline);
	border-radius: var(--wp--custom--radius--md);
	background-color: var(--wp--preset--color--surface);
}

.vz-gallery__img,
.vz-gallery__main img {
	display: block;
	inline-size: 100%;
	block-size: auto;
	aspect-ratio: var(--vz-media-ratio, 4 / 3);
	object-fit: cover;
}

.vz-gallery__thumbs {
	display: flex;
	gap: 0.5rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

.vz-gallery__thumb {
	margin: 0;
	inline-size: 72px;
	overflow: hidden;
	border: 1px solid var(--wp--preset--color--outline);
	border-radius: var(--wp--custom--radius--sm);
	background-color: var(--wp--preset--color--surface);
	transition: border-color var(--wp--custom--transition--base);
}

.vz-gallery__thumb:hover {
	border-color: var(--wp--preset--color--primary);
}

.vz-gallery__thumb-img,
.vz-gallery__thumb img {
	display: block;
	inline-size: 100%;
	block-size: auto;
	aspect-ratio: 1;
	object-fit: cover;
}

.vz-figure {
	margin: 0;
	overflow: hidden;
	border: 1px solid var(--wp--preset--color--outline);
	border-radius: var(--wp--custom--radius--md);
	background-color: var(--wp--preset--color--surface);
}

.vz-figure__img,
.vz-figure img {
	display: block;
	inline-size: 100%;
	block-size: auto;
	aspect-ratio: var(--vz-media-ratio, 4 / 3);
	object-fit: cover;
}

.vz-video {
	position: relative;
	overflow: hidden;
	border-radius: var(--wp--custom--radius--md);
	background-color: var(--wp--preset--color--deep);
}

.vz-video iframe,
.vz-video video {
	display: block;
	inline-size: 100%;
	aspect-ratio: 16 / 9;
	border: 0;
}

.vz-download {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 0.75rem;
	padding: clamp(0.8rem, 1.4vw, 1.1rem);
	border: 1px solid var(--wp--preset--color--outline);
	border-radius: var(--wp--custom--radius--md);
	background-color: var(--wp--preset--color--base);
}

.vz-download__icon {
	display: inline-flex;
	flex: 0 0 auto;
	align-items: center;
	justify-content: center;
	inline-size: 2.25rem;
	block-size: 2.25rem;
	border-radius: var(--wp--custom--radius--sm);
	background-color: var(--wp--preset--color--surface-accent);
	color: var(--wp--preset--color--primary);
}

.vz-download__body {
	display: flex;
	flex-direction: column;
	flex: 1 1 12rem;
	min-width: 0;
}

.vz-download__title {
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	line-height: 1.4;
	overflow-wrap: anywhere;
}

.vz-download__meta {
	font-size: var(--wp--preset--font-size--x-small);
	color: var(--wp--preset--color--contrast-subtle);
	text-transform: uppercase;
	letter-spacing: var(--wp--custom--typography--letter-spacing--wide);
}

/* --- 24. Icons ------------------------------------------------------- */

/* The SVG carries its own width/height/stroke attributes, so the rule below
   only handles alignment. Sizing stays in PHP (vorezan_icon( $slug, $size )). */
.vz-icon {
	display: inline-block;
	flex: 0 0 auto;
	vertical-align: middle;
}

/* Icons that sit next to text inherit the text size instead. */
.vz-icon--inherit {
	inline-size: 1em;
	block-size: 1em;
}

/* --- 25. Hero and panel surfaces ------------------------------------- */

.vz-hero {
	position: relative;
	padding-block: var(--wp--preset--spacing--60) var(--wp--preset--spacing--60);
	background-color: var(--wp--preset--color--surface);
	border-bottom: var(--wp--custom--border--hairline-width) solid var(--wp--preset--color--outline);
}

.vz-hero--plain {
	background-color: transparent;
	border-bottom: 0;
}

.vz-hero--deep {
	color: var(--wp--custom--on-dark);
	background-color: var(--wp--preset--color--deep);
	border-bottom: 0;
}

.vz-hero--deep a:not(.vz-btn) {
	color: inherit;
}

.vz-hero__eyebrow {
	display: inline-flex;
	align-items: center;
	gap: 0.4em;
	margin: 0 0 var(--wp--preset--spacing--20);
	font-size: var(--wp--preset--font-size--x-small);
	font-weight: 700;
	letter-spacing: var(--wp--custom--typography--letter-spacing--wide);
	text-transform: uppercase;
	color: var(--wp--preset--color--primary-dark);
}

.vz-hero--deep .vz-hero__eyebrow {
	color: var(--wp--preset--color--primary-light);
}

.vz-hero__title {
	margin: 0 0 var(--wp--preset--spacing--30);
	letter-spacing: var(--wp--custom--typography--letter-spacing--display);
}

.vz-hero__lead {
	max-width: 62ch;
	margin: 0 0 var(--wp--preset--spacing--40);
	font-size: var(--wp--preset--font-size--large);
	line-height: 1.6;
	color: var(--wp--preset--color--contrast-muted);
}

.vz-hero--deep .vz-hero__lead {
	color: var(--wp--preset--color--contrast-subtle);
}

.vz-hero__media img {
	display: block;
	width: 100%;
	height: auto;
	border-radius: var(--wp--custom--radius--lg);
	box-shadow: var(--wp--preset--shadow--card);
}

.vz-hero__actions {
	display: flex;
	flex-wrap: wrap;
	gap: var(--wp--preset--spacing--20);
	align-items: center;
}

/* Panel: a bordered, tinted block that groups two or more sub-sections. */

.vz-panel {
	padding: var(--wp--preset--spacing--50);
	background-color: var(--wp--preset--color--surface);
	border: var(--wp--custom--border--hairline-width) solid var(--wp--preset--color--outline);
	border-radius: var(--wp--custom--radius--lg);
}

.vz-panel--accent {
	background-color: var(--wp--preset--color--surface-accent);
	border-color: var(--wp--preset--color--outline-strong);
}

.vz-panel--flush {
	padding-inline: 0;
	background-color: transparent;
	border: 0;
}

.vz-panel > :first-child {
	margin-block-start: 0;
}

.vz-panel > :last-child {
	margin-block-end: 0;
}

.vz-panel__title {
	margin: 0 0 var(--wp--preset--spacing--20);
	font-size: var(--wp--preset--font-size--large);
	font-weight: 700;
	letter-spacing: var(--wp--custom--typography--letter-spacing--heading);
}

@media (max-width: 781px) {

	.vz-hero {
		padding-block: var(--wp--preset--spacing--50);
	}

	.vz-panel {
		padding: var(--wp--preset--spacing--40);
	}
}

/* --- 25b. Component variants added with the route and standard templates ---- */

.vz-card__badge {
	display: inline-flex;
	align-self: flex-start;
	align-items: center;
	margin-block-end: var(--wp--preset--spacing--20);
	padding: 0.2em 0.7em;
	font-size: var(--wp--preset--font-size--x-small);
	font-weight: 700;
	letter-spacing: var(--wp--custom--typography--letter-spacing--wide);
	text-transform: uppercase;
	/* primary-dark ink on primary-light measured 1.71:1 - far under the
	 * 4.5:1 AA floor for this x-small 700 label. Inverting the pair keeps
	 * the brand green and lands at 7.48:1. */
	color: var(--wp--custom--on-brand);
	background-color: var(--wp--preset--color--primary-dark);
	border-radius: var(--wp--custom--radius--pill);
}

.vz-card__note {
	margin: var(--wp--preset--spacing--20) 0 0;
	font-size: var(--wp--preset--font-size--x-small);
	color: var(--wp--preset--color--contrast-subtle);
}

.vz-card__text br + br {
	content: "";
	display: block;
	height: 0.4em;
}

.vz-note--accent {
	color: var(--wp--preset--color--contrast);
	background-color: var(--wp--preset--color--sky-light);
	border-color: var(--wp--preset--color--sky);
}

.vz-note--accent .vz-note__icon {
	color: var(--wp--preset--color--sky);
}

.vz-table--matrix {
	min-width: 42rem;
}

.vz-table--matrix thead th {
	white-space: nowrap;
}

.vz-table--matrix tbody th {
	font-weight: 700;
	color: var(--wp--preset--color--contrast);
}

.vz-table--matrix td {
	vertical-align: top;
	color: var(--wp--preset--color--contrast-muted);
}

/* --- 26. Long-form prose --------------------------------------------- */

.vz-prose {
	max-width: 72ch;
}

.vz-prose > * + * {
	margin-block-start: var(--wp--preset--spacing--30);
}

.vz-prose h2 {
	margin-block-start: var(--wp--preset--spacing--50);
	font-size: var(--wp--preset--font-size--x-large);
	letter-spacing: var(--wp--custom--typography--letter-spacing--heading);
}

.vz-prose h3 {
	margin-block-start: var(--wp--preset--spacing--40);
	font-size: var(--wp--preset--font-size--large);
}

.vz-prose ul,
.vz-prose ol {
	padding-inline-start: 1.25em;
}

.vz-prose li + li {
	margin-block-start: 0.4em;
}

.vz-prose blockquote {
	margin-inline: 0;
	padding-inline-start: var(--wp--preset--spacing--30);
	border-inline-start: 3px solid var(--wp--preset--color--primary);
	color: var(--wp--preset--color--contrast-muted);
	font-style: normal;
}

.vz-prose.vz-panel {
	max-width: none;
}

/* --- 27. Taxonomy term listings --------------------------------------- */

/*
 * Rendered by the `vorezan/terms` block. Four variants share one renderer:
 * `grid` uses the term cards below, while `chip`, `list` and `letters` reuse
 * the chip, relation-list and letter-index primitives.
 */

.vz-terms-wrap {
	display: flex;
	flex-direction: column;
	gap: clamp(0.85rem, 1.6vw, 1.35rem);
}

.vz-terms-wrap--grid {
	gap: clamp(0.85rem, 1.8vw, 1.5rem);
}

.vz-terms-wrap--chip,
.vz-terms-wrap--letters {
	gap: 0.75rem;
}

.vz-terms-wrap--list {
	gap: 0.65rem;
}

.vz-termcards {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
	gap: clamp(0.85rem, 1.6vw, 1.25rem);
	margin: 0;
	padding: 0;
	list-style: none;
}

.vz-termcard {
	margin: 0;
	min-width: 0;
}

.vz-termcard__link {
	display: flex;
	flex-direction: column;
	gap: 0.7rem;
	block-size: 100%;
	padding: 0;
	overflow: hidden;
	border: var(--wp--custom--border--hairline-width) solid var(--wp--preset--color--outline);
	border-radius: var(--wp--custom--radius--md);
	background-color: var(--wp--preset--color--base);
	color: inherit;
	text-decoration: none;
	transition: box-shadow var(--wp--custom--transition--base),
		transform var(--wp--custom--transition--base),
		border-color var(--wp--custom--transition--base);
}

.vz-termcard__link:hover,
.vz-termcard__link:focus-visible {
	border-color: var(--wp--preset--color--primary);
	box-shadow: var(--wp--preset--shadow--card-hover);
}

@media (prefers-reduced-motion: no-preference) {
	.vz-termcard__link:hover,
	.vz-termcard__link:focus-visible {
		transform: translateY(-2px);
	}
}

/* Fixed aspect ratio keeps a row of cards aligned whatever the image is. */
.vz-termcard__media {
	position: relative;
	margin: 0;
	aspect-ratio: 16 / 10;
	overflow: hidden;
	background-color: var(--wp--preset--color--surface);
}

.vz-termcard__img {
	display: block;
	inline-size: 100%;
	block-size: 100%;
	object-fit: cover;
	transition: transform var(--wp--custom--transition--slow);
}

@media (prefers-reduced-motion: no-preference) {
	.vz-termcard__link:hover .vz-termcard__img {
		transform: scale(1.04);
	}
}

/* Icon stands in for a missing term image, so cards never look broken. */
.vz-termcard__icon {
	display: flex;
	align-items: center;
	justify-content: center;
	inline-size: 2.75rem;
	block-size: 2.75rem;
	margin: clamp(0.9rem, 1.6vw, 1.15rem) clamp(0.9rem, 1.6vw, 1.15rem) 0;
	border-radius: var(--wp--custom--radius--sm);
	/* Same 1.71:1 pairing as the badge; the glyph is the only content of
	 * the tile, so it has to clear the 3:1 non-text floor. 6.55:1. */
	background-color: var(--wp--preset--color--surface-accent);
	color: var(--wp--preset--color--primary-dark);
}

.vz-termcard__body {
	display: flex;
	flex-direction: column;
	gap: 0.3rem;
	min-width: 0;
	padding: 0 clamp(0.9rem, 1.6vw, 1.15rem) clamp(0.9rem, 1.6vw, 1.15rem);
}

.vz-termcard__title {
	font-size: var(--wp--preset--font-size--medium);
	font-weight: 600;
	line-height: 1.35;
	letter-spacing: var(--wp--custom--typography--letter-spacing--heading);
	color: var(--wp--preset--color--contrast);
}

.vz-termcard__link:hover .vz-termcard__title,
.vz-termcard__link:focus-visible .vz-termcard__title {
	color: var(--wp--preset--color--primary-dark);
}

.vz-termcard__note {
	font-size: var(--wp--preset--font-size--small);
	line-height: 1.5;
	color: var(--wp--preset--color--contrast-muted);
}

.vz-termcard__count {
	align-self: flex-start;
	margin-block-start: 0.15rem;
	padding: 0.1rem 0.5rem;
	border-radius: var(--wp--custom--radius--pill);
	background-color: var(--wp--preset--color--surface);
	font-size: var(--wp--preset--font-size--x-small);
	font-weight: 600;
	color: var(--wp--preset--color--contrast-subtle);
}

/* Letter index used by the glossary hub. */
.vz-letters {
	display: flex;
	flex-wrap: wrap;
	gap: 0.4rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

.vz-letter {
	margin: 0;
}

.vz-letter__link {
	display: flex;
	align-items: center;
	justify-content: center;
	min-inline-size: 2.35rem;
	block-size: 2.35rem;
	padding: 0 0.4rem;
	border: var(--wp--custom--border--hairline-width) solid var(--wp--preset--color--outline);
	border-radius: var(--wp--custom--radius--sm);
	background-color: var(--wp--preset--color--base);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	line-height: 1;
	text-decoration: none;
	text-transform: uppercase;
	color: var(--wp--preset--color--contrast);
	transition: background-color var(--wp--custom--transition--base),
		border-color var(--wp--custom--transition--base),
		color var(--wp--custom--transition--base);
}

.vz-letter__link:hover,
.vz-letter__link:focus-visible {
	border-color: var(--wp--preset--color--primary);
	background-color: var(--wp--preset--color--primary);
	color: var(--wp--custom--on-brand);
}

@media (max-width: 1023px) {
	.vz-termcards {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (max-width: 560px) {
	.vz-termcards {
		grid-template-columns: minmax(0, 1fr);
	}
}

/* --- 28. Archive and hub post grids ---------------------------------- */

/*
 * Archives use the core Query Loop so pagination, sticky posts and the
 * editor's own controls keep working. These rules dress the core output
 * to match the hand-rolled card components above.
 */

.vz-postgrid .wp-block-post-template {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
	gap: clamp(1rem, 2vw, 1.6rem);
	margin: 0;
	padding: 0;
	list-style: none;
}

.vz-postgrid .wp-block-post {
	display: flex;
	flex-direction: column;
	gap: 0.7rem;
	margin: 0;
	min-width: 0;
	padding: clamp(0.9rem, 1.7vw, 1.2rem);
	border: var(--wp--custom--border--hairline-width) solid var(--wp--preset--color--outline);
	border-radius: var(--wp--custom--radius--md);
	background-color: var(--wp--preset--color--base);
	transition: box-shadow var(--wp--custom--transition--base),
		border-color var(--wp--custom--transition--base);
}

.vz-postgrid .wp-block-post:hover,
.vz-postgrid .wp-block-post:focus-within {
	border-color: var(--wp--preset--color--outline-strong);
	box-shadow: var(--wp--preset--shadow--card-hover);
}

.vz-postgrid .wp-block-post-featured-image {
	margin: calc(-1 * clamp(0.9rem, 1.7vw, 1.2rem));
	margin-block-end: 0.35rem;
	overflow: hidden;
	border-start-start-radius: var(--wp--custom--radius--md);
	border-start-end-radius: var(--wp--custom--radius--md);
}

.vz-postgrid .wp-block-post-featured-image img {
	display: block;
	inline-size: 100%;
	aspect-ratio: 16 / 10;
	object-fit: cover;
}

.vz-postgrid .wp-block-post-title {
	margin: 0;
	font-size: var(--wp--preset--font-size--medium);
	font-weight: 600;
	line-height: 1.35;
	letter-spacing: var(--wp--custom--typography--letter-spacing--heading);
}

.vz-postgrid .wp-block-post-title a {
	color: var(--wp--preset--color--contrast);
	text-decoration: none;
}

.vz-postgrid .wp-block-post-title a:hover,
.vz-postgrid .wp-block-post-title a:focus-visible {
	color: var(--wp--preset--color--primary-dark);
	text-decoration: underline;
}

.vz-postgrid .wp-block-post-excerpt {
	margin: 0;
}

.vz-postgrid .wp-block-post-excerpt__excerpt {
	font-size: var(--wp--preset--font-size--small);
	line-height: 1.6;
	color: var(--wp--preset--color--contrast-muted);
}

.vz-postgrid .wp-block-post-excerpt__more-text {
	margin-block-start: 0.35rem;
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
}

.vz-postgrid .wp-block-post-date,
.vz-postgrid .wp-block-post-terms {
	font-size: var(--wp--preset--font-size--x-small);
	color: var(--wp--preset--color--contrast-subtle);
}

/* Push the pagination clear of the last row. */
.vz-postgrid .wp-block-query-pagination {
	margin-block-start: clamp(1.5rem, 3vw, 2.5rem);
	gap: 0.4rem;
	font-size: var(--wp--preset--font-size--small);
}

.vz-postgrid .wp-block-query-pagination-numbers .page-numbers,
.vz-postgrid .wp-block-query-pagination-previous,
.vz-postgrid .wp-block-query-pagination-next {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-inline-size: 2.25rem;
	block-size: 2.25rem;
	padding: 0 0.6rem;
	border: var(--wp--custom--border--hairline-width) solid var(--wp--preset--color--outline);
	border-radius: var(--wp--custom--radius--sm);
	font-weight: 600;
	text-decoration: none;
	color: var(--wp--preset--color--contrast);
}

.vz-postgrid .wp-block-query-pagination-numbers .page-numbers.current {
	border-color: var(--wp--preset--color--primary);
	background-color: var(--wp--preset--color--primary);
	color: var(--wp--custom--on-brand);
}

.vz-postgrid .wp-block-query-no-results {
	padding: clamp(1.1rem, 2.2vw, 1.6rem);
	border: var(--wp--custom--border--hairline-width) dashed var(--wp--preset--color--outline-strong);
	border-radius: var(--wp--custom--radius--md);
	background-color: var(--wp--preset--color--surface);
	color: var(--wp--preset--color--contrast-muted);
}

/* Compact row layout for dense hubs such as questions and glossary. */
.vz-postgrid--rows .wp-block-post-template {
	grid-template-columns: minmax(0, 1fr);
	gap: 0.6rem;
}

.vz-postgrid--rows .wp-block-post {
	flex-direction: row;
	align-items: baseline;
	justify-content: space-between;
	gap: 1rem;
	padding-block: 0.85rem;
}

@media (max-width: 1023px) {
	.vz-postgrid .wp-block-post-template {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (max-width: 560px) {
	.vz-postgrid .wp-block-post-template {
		grid-template-columns: minmax(0, 1fr);
	}

	.vz-postgrid--rows .wp-block-post {
		flex-direction: column;
		align-items: flex-start;
		gap: 0.3rem;
	}
}

/* --- 29. Hub hero fact lists ----------------------------------------- */

/*
 * Hub heroes (Products, Markets, Guides, Questions, Glossary) carry a short
 * row of reassurance facts. Singular pages get the same row from the
 * `vorezan/fact-strip` block, but hubs have no ACF object to read, so this is
 * an ordinary core list. The check mark is a CSS mask, which keeps the block
 * plain and editable in the site editor while staying colour-token driven.
 */

.vz-hero__facts {
	display: flex;
	flex-wrap: wrap;
	gap: 0.4rem 1.5rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

.vz-hero__facts > li {
	display: flex;
	align-items: center;
	gap: 0.45rem;
	margin: 0;
	color: var(--wp--preset--color--contrast-muted);
}

.vz-hero__facts > li::before {
	content: "";
	flex: none;
	inline-size: 1.05rem;
	block-size: 1.05rem;
	background-color: var(--wp--preset--color--primary);
	-webkit-mask-image: var(--vz-check-mask);
	mask-image: var(--vz-check-mask);
	-webkit-mask-repeat: no-repeat;
	mask-repeat: no-repeat;
	-webkit-mask-position: center;
	mask-position: center;
	-webkit-mask-size: contain;
	mask-size: contain;
}

/*
 * Declared once on the root so the mask URL is not repeated, and so a child
 * theme can swap the marker for a different glyph in one place.
 */
:root {
	--vz-check-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
}

@media (max-width: 560px) {
	.vz-hero__facts {
		gap: 0.35rem 1rem;
	}
}

/* --- 30. Mobile UX hardening (2026 practice) --------------------------
 *
 * Measured against the live site at a 390x844 viewport with a coarse
 * pointer. The rules below implement four documented baselines:
 *
 *   1. Touch targets: 44x44 CSS px (Apple HIG) to 48x48 (Material 3) with
 *      >= 8px separation. WCAG 2.2 SC 2.5.8 only demands 24x24, which is a
 *      compliance floor rather than a usable size, so the theme targets 48.
 *   2. Type: 16px is the body floor. Anything below it triggers Safari's
 *      automatic form zoom and measurably hurts reading comfort, so the
 *      `small` and `x-small` presets are lifted on narrow viewports instead
 *      of being patched per component.
 *   3. Chrome budget: a sticky header must stay under ~25% of the viewport
 *      height. The three-tier desktop header is therefore reduced to a
 *      brand row plus a sticky 56px navigation bar on phones.
 *   4. Safe areas: `env(safe-area-inset-*)` keeps fixed and sticky chrome
 *      clear of notches and home indicators.
 *
 * Everything here is additive. No selector defined earlier in this file is
 * renamed or removed, so the markup contract of the dynamic blocks holds.
 */

/* 30.1 Global foundations ------------------------------------------------ */

/* Long unbroken tokens (HS codes, URLs, chemical names) are common in this
 * content set and used to push cards past the viewport edge. */
body {
	overflow-wrap: break-word;
}

/* Reduce ragged headings without the reflow cost of `balance` on body copy. */
h1,
h2,
h3,
.vz-hero__title,
.vz-section__title {
	text-wrap: balance;
}

.vz-hero__lead,
.vz-prose p {
	text-wrap: pretty;
}

/* Grey flash on tap reads as a rendering fault on a knowledge site; the
 * theme supplies its own :active feedback instead. */
a,
button,
summary,
[role="button"],
input,
select,
textarea {
	-webkit-tap-highlight-color: rgba(11, 42, 34, 0.08);
}

a,
button,
summary,
[role="button"] {
	touch-action: manipulation;
}

/* 30.2 Type floor on narrow viewports ----------------------------------- */

/* Redefining the presets is deliberate: every component consumes them, so a
 * single override lifts meta rows, excerpts, chips, captions and button
 * labels at once. `html:root` outranks the `:root` block that global styles
 * emits, which makes the override independent of stylesheet order. */
@media (max-width: 781px) {
	html:root {
		--wp--preset--font-size--x-small: 0.875rem;
		--wp--preset--font-size--small: 1rem;
	}
}

/* The x-small preset stays at 14px because it also drives eyebrows, table
 * headers, counts and dates, where 16px reads as shouting. Prose written to be
 * read - card copy, step copy, intros, CTA and disclaimer text - is promoted to
 * the 16px step instead, which is the floor the 2026 mobile guidance applies to
 * body copy specifically. */
@media (max-width: 781px) {
	.vz-card__text,
	.vz-step__text,
	.vz-rellist__text,
	.vz-aside__intro,
	.vz-cta__text,
	.vz-note__text,
	.vz-section__intro,
	.vz-hero__lead,
	.wp-block-post-excerpt__excerpt {
		font-size: var(--wp--preset--font-size--small);
		line-height: 1.6;
	}
}

/* Form controls never fall below 16px at any width: Safari zooms the page
 * when a focused field is smaller and the zoom is not reversed on blur. */
input:not([type="checkbox"]):not([type="radio"]),
select,
textarea {
	font-size: max(1rem, var(--wp--preset--font-size--small));
}

/* 30.3 Touch targets ---------------------------------------------------- */

/* Applied on coarse pointers and on narrow viewports. Either condition alone
 * is unreliable: a touch laptop reports a coarse pointer at desktop width, and
 * a phone browser in desktop-site mode reports a fine pointer at phone width.
 * The minimum is expressed with a custom property to keep it auditable. */
@media (pointer: coarse), (max-width: 781px) {
	html:root {
		--vz-touch-target: 48px;
	}

	.vz-btn,
	.wp-element-button,
	.wp-block-button__link,
	.vz-cta__btn,
	.vz-newsletter__submit,
	.wp-block-search__button {
		min-block-size: var(--vz-touch-target);
		padding-inline: 1.25rem;
	}

	/* Icon-only and inline controls get their hit area from padding so the
	 * visual size is untouched. */
	.vz-lang__toggle,
	.vz-more__link,
	.vz-crumbs__item a,
	.vz-table__ref a,
	.vz-footer__links a,
	.vz-footer__legal a {
		display: inline-flex;
		align-items: center;
		min-block-size: 44px;
	}

	.vz-chip__link,
	.vz-letters a,
	.vz-tag {
		min-block-size: 44px;
		padding-block: 0.6rem;
	}

	.vz-aside__link,
	.vz-rellist__link,
	.vz-termcard__link,
	.vz-relcard__link,
	.vz-faq__q,
	.vz-tabs__link {
		min-block-size: var(--vz-touch-target);
	}

	.vz-pagination .page-numbers {
		display: inline-flex;
		align-items: center;
		justify-content: center;
		min-inline-size: 44px;
		min-block-size: 44px;
	}

	.wp-block-social-links .wp-block-social-link {
		margin: 0.25rem;
	}

	.wp-block-social-link-anchor {
		min-inline-size: 44px;
		min-block-size: 44px;
		padding: 0.35rem;
	}

	/* Core renders the overlay trigger as a bare 24px icon button. */
	.wp-block-navigation__responsive-container-open,
	.wp-block-navigation__responsive-container-close {
		display: inline-flex;
		align-items: center;
		justify-content: center;
		min-inline-size: var(--vz-touch-target);
		min-block-size: var(--vz-touch-target);
	}

	/* Adjacent chips and tags must not touch: 8px is the documented floor
	 * for avoiding mis-taps between neighbouring targets. */
	.vz-chips,
	.vz-letters,
	.vz-hero__actions {
		gap: max(0.5rem, var(--wp--preset--spacing--20));
	}
}

/* Pressed feedback replaces the suppressed native tap highlight. */
@media (hover: none) {
	.vz-btn:active,
	.wp-element-button:active,
	.vz-chip__link:active,
	.vz-aside__link:active,
	.vz-rellist__link:active,
	.vz-termcard__link:active {
		transform: scale(0.985);
		filter: brightness(0.96);
	}
}

/* 30.4 Header budget on phones ------------------------------------------ */

@media (max-width: 781px) {
	/* The trust bar costs ~66px of a 844px viewport and repeats claims that
	 * the footer already carries. It returns at tablet width and up. */
	.vz-topbar {
		display: none;
	}

	.vz-header {
		padding-block: var(--wp--preset--spacing--20) !important;
	}

	.vz-header .alignwide {
		row-gap: var(--wp--preset--spacing--30) !important;
	}

	.vz-brand__name {
		font-size: 1.375rem !important;
	}

	/* 9px uppercase is unreadable at arm's length; the brand name already
	 * identifies the site on a phone. */
	.vz-brand__tagline {
		display: none;
	}

	.vz-actions {
		flex: 1 1 auto;
		justify-content: flex-end;
	}

	.vz-search {
		order: 3;
	}

	.vz-search .wp-block-search__input {
		min-block-size: 48px;
	}

	.vz-search .wp-block-search__button {
		min-inline-size: 48px;
		min-block-size: 48px;
	}

	/* Only the navigation strip follows the scroll. Brand and search leave
	 * the viewport, which keeps persistent chrome at 56px (6.6% of a 844px
	 * screen) instead of the 285px measured before this change. */
	.vz-navbar {
		position: sticky;
		top: 0;
		z-index: 40;
		padding-inline: 0;
		box-shadow: var(--wp--preset--shadow--card);
	}

	.vz-navbar > .alignwide,
	.vz-navbar .wp-block-group.alignwide {
		min-block-size: 56px;
		padding-inline: var(--wp--custom--layout--gutter);
	}

	/* Label the trigger: an unlabelled glyph measurably lowers task success
	 * against a labelled control. */
	.vz-navbar .wp-block-navigation__responsive-container-open {
		gap: 0.5rem;
		padding-inline: 0.75rem;
		border: 1px solid var(--wp--preset--color--outline-strong);
		border-radius: var(--wp--custom--radius--sm);
		background-color: var(--wp--preset--color--surface);
		color: var(--wp--preset--color--contrast);
		font-size: var(--wp--preset--font-size--small);
		font-weight: 600;
	}

	.vz-navbar .wp-block-navigation__responsive-container-open::after {
		content: attr(data-vz-label);
	}
}

/* Anchor jumps must clear the sticky strip. */
@media (max-width: 781px) {
	.wp-site-blocks [id] {
		scroll-margin-block-start: calc(56px + var(--wp--preset--spacing--40));
	}
}

/* 30.5 Overlay menu rows ------------------------------------------------ */

.vz-navbar .wp-block-navigation__responsive-container.is-menu-open {
	padding-block-start: max(var(--wp--preset--spacing--50), env(safe-area-inset-top));
	padding-block-end: max(var(--wp--preset--spacing--70), env(safe-area-inset-bottom));
	padding-inline: max(var(--wp--preset--spacing--50), env(safe-area-inset-left));
	overscroll-behavior: contain;
}

/* Core's flattened panel gave every entry a 23px row. Section headings and
 * child links now both clear 48px and read at 16px or more. */
.vz-navbar .is-menu-open .wp-block-navigation-item__content {
	display: flex;
	align-items: center;
	min-block-size: 48px;
	padding-block: 0.5rem;
}

.vz-navbar .is-menu-open .wp-block-navigation__container > .wp-block-navigation-item > .wp-block-navigation-item__content {
	font-size: var(--wp--preset--font-size--large);
	text-decoration: none;
}

.vz-navbar .is-menu-open .wp-block-navigation__submenu-container .wp-block-navigation-item__content {
	padding-inline-start: 0.75rem;
	border-inline-start: 2px solid var(--wp--preset--color--outline);
	font-size: 1rem;
	color: var(--wp--preset--color--contrast);
}

.vz-navbar .is-menu-open .wp-block-navigation__submenu-container .wp-block-navigation-item__content:active {
	border-inline-start-color: var(--wp--preset--color--primary);
	color: var(--wp--preset--color--primary);
}

/* The panel is a scrolling column on a phone, not a centred dialog. */
@media (max-width: 599px) {
	.vz-navbar .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-content {
		align-items: stretch;
		justify-content: flex-start;
	}

	.vz-navbar .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__submenu-container {
		gap: 0;
	}
}

/* 30.6 Primary actions fill the row on small phones --------------------- */

@media (max-width: 480px) {
	.vz-cta--band .vz-cta__btn,
	.vz-cta--sidebar .vz-cta__btn,
	.vz-hero__actions .vz-btn,
	.vz-hero__actions .wp-block-button,
	.vz-hero__actions .wp-block-button__link {
		inline-size: 100%;
		justify-content: center;
	}

	.vz-newsletter {
		flex-wrap: wrap;
	}

	.vz-newsletter__input,
	.vz-newsletter__submit {
		flex: 1 1 100%;
		inline-size: 100%;
	}
}

/* On a 360px screen the brand, the inquiry button and the search field wrapped
 * onto three separate rows, which pushed the header to 227px - 28% of the
 * viewport. An explicit two row grid keeps the brand and the primary action on
 * the same line and gives the search field the full width below them, which is
 * 58px shorter. Areas are placed explicitly so the result does not depend on
 * the source order of the template part. */
@media (max-width: 480px) {
	.vz-header > .wp-block-group {
		display: grid;
		grid-template-columns: minmax(0, 1fr) auto;
		align-items: center;
		column-gap: 0.75rem;
		row-gap: var(--wp--preset--spacing--30, 0.75rem);
	}

	.vz-header .vz-brand {
		grid-area: 1 / 1 / 2 / 2;
		min-inline-size: 0;
	}

	.vz-header .vz-actions {
		grid-area: 1 / 2 / 2 / 3;
		inline-size: auto;
		justify-content: flex-end;
	}

	.vz-header .vz-search {
		grid-area: 2 / 1 / 3 / -1;
	}

	/* The label is the widest part of the button; trimming the horizontal
	 * padding keeps the 48px height while freeing room for the brand. */
	.vz-header .vz-actions .wp-block-button__link {
		padding-inline: 0.875rem;
		white-space: nowrap;
	}
}

/* 30.7 In-page section navigation -------------------------------------- */

/* Stacking eight anchors as full-width rows pushed the first section below
 * the fold. A single snapping strip keeps the whole set reachable. */
@media (max-width: 781px) {
	.vz-tabs__track {
		display: flex;
		flex-wrap: nowrap;
		gap: 0.5rem;
		overflow-x: auto;
		scroll-snap-type: x proximity;
		-webkit-overflow-scrolling: touch;
		scrollbar-width: none;
		padding-block-end: 0.25rem;
	}

	.vz-tabs__track::-webkit-scrollbar {
		display: none;
	}

	.vz-tabs__link {
		flex: 0 0 auto;
		scroll-snap-align: start;
		white-space: nowrap;
		border-radius: var(--wp--custom--radius--pill);
	}

	.vz-tabs--sticky {
		position: sticky;
		top: 56px;
		z-index: 20;
		background-color: var(--wp--preset--color--base);
	}
}

/* 30.8 Wide tables ----------------------------------------------------- */

/* Specification and matrix tables cannot collapse without losing the row
 * relationship, so they scroll inside their own frame with a fade that
 * signals more content to the right. */
@media (max-width: 781px) {
	/* `display: block` on a <table> strips its implicit table role, so
	 * rows and headers stop being announced. The scroll frame belongs on
	 * the .vz-tables wrapper that already surrounds every table. */
	.vz-tables {
		overflow-x: auto;
		-webkit-overflow-scrolling: touch;
		overscroll-behavior-x: contain;
		background:
			linear-gradient(to right, var(--wp--preset--color--base) 30%, rgba(255, 255, 255, 0)) left center / 2.5rem 100% no-repeat,
			linear-gradient(to left, var(--wp--preset--color--base) 30%, rgba(255, 255, 255, 0)) right center / 2.5rem 100% no-repeat;
		background-attachment: local, local;
	}

	/* Was `.vz-table table`, which matched nothing - a table inside a
	 * table. The minimum belongs on the table itself. */
	.vz-table {
		min-inline-size: 34rem;
	}

	.vz-tables--split {
		grid-template-columns: minmax(0, 1fr);
	}
}

/* 30.9 Grid density ---------------------------------------------------- */

/* Every grid that reads its column count from --vz-cards-cols is pinned to
 * one or two tracks on a phone, whatever an editor set in the inspector. */
@media (max-width: 599px) {
	.vz-cards,
	.vz-termcards,
	.vz-postgrid,
	.vz-relgrid,
	.vz-steps,
	.vz-facts--stats {
		--vz-cards-cols: 1;
	}

	.vz-cards--kpi,
	.vz-facts--stats {
		--vz-cards-cols: 2;
	}

	.vz-layout,
	.vz-layout__main,
	.vz-layout__aside {
		min-inline-size: 0;
	}
}

@media (min-width: 600px) and (max-width: 781px) {
	.vz-cards,
	.vz-termcards,
	.vz-postgrid,
	.vz-relgrid,
	.vz-steps {
		--vz-cards-cols: 2;
	}
}

/* Full-bleed media inside a constrained column on a phone reads as an edge
 * to edge band rather than a card with awkward side gutters. */
@media (max-width: 599px) {
	.vz-hero__media img,
	.vz-gallery img {
		border-radius: var(--wp--custom--radius--sm);
	}
}

/* 30.10 Safe areas ----------------------------------------------------- */

@supports (padding: env(safe-area-inset-bottom)) {
	.vz-footer__bottom {
		padding-block-end: calc(var(--wp--preset--spacing--50) + env(safe-area-inset-bottom));
	}

	@media (max-width: 781px) {
		.vz-navbar > .alignwide,
		.vz-navbar .wp-block-group.alignwide {
			padding-inline-start: max(var(--wp--custom--layout--gutter), env(safe-area-inset-left));
			padding-inline-end: max(var(--wp--custom--layout--gutter), env(safe-area-inset-right));
		}
	}
}

/* 30.11 Focus visibility ----------------------------------------------- */

/* A 3:1 focus indicator is required for keyboard and switch access, and the
 * ring has to survive on both the light surfaces and the deep bands. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
	outline: 3px solid var(--wp--preset--color--focus);
	outline-offset: 2px;
	border-radius: var(--wp--custom--radius--xs);
}

.vz-topbar :focus-visible,
.vz-cta--band :focus-visible,
.vz-hero--deep :focus-visible,
.vz-footer :focus-visible {
	outline-color: var(--wp--preset--color--base);
}

/* 30.12 Motion and data preferences ------------------------------------ */

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

	.vz-btn:active,
	.wp-element-button:active {
		transform: none;
	}
}

/* --- 31. Contrast corrections ---------------------------------------- */

/* Global styles emit `h1,h2,...{color:contrast}` from theme.json, which
 * outranks the inherited colour of a dark surface. Every heading that sits
 * on `deep` therefore rendered near-black on near-black: the band CTA title
 * measured 1.05:1 against its background on the live site. These rules
 * restore the intended light-on-dark pairing. */
.vz-cta--band .vz-cta__title,
.vz-cta--band h1,
.vz-cta--band h2,
.vz-cta--band h3,
.vz-hero--deep h1,
.vz-hero--deep h2,
.vz-hero--deep h3,
.vz-hero--deep .vz-hero__title,
.vz-topbar h1,
.vz-topbar h2,
.vz-topbar h3 {
	color: var(--wp--custom--on-dark);
}

/* The same override, applied by background rather than by component, so an
 * editor who sets a dark background on any block from the inspector still gets
 * readable headings. `has-*-background-color` is the class core adds for a
 * palette background. */
.has-deep-background-color :is(h1, h2, h3, h4, h5, h6),
.has-contrast-background-color :is(h1, h2, h3, h4, h5, h6) {
	color: var(--wp--custom--on-dark);
}

.has-primary-background-color :is(h1, h2, h3, h4, h5, h6),
.has-primary-dark-background-color :is(h1, h2, h3, h4, h5, h6) {
	color: var(--wp--custom--on-brand);
}

/* Supporting copy on the deep band was mixed down to 78% of white, which is
 * legible but loses definition at small sizes on a phone screen. */
.vz-cta--band .vz-cta__text {
	color: color-mix(in srgb, var(--wp--preset--color--base) 88%, transparent);
}

/* `contrast-subtle` is the muted tone used for counts, dates and captions.
 * Its previous value measured 4.34:1 on the surface tint, just under the
 * 4.5:1 that WCAG 2.2 AA requires for text below 24px. The token itself has
 * been darkened in theme.json; this guard keeps the pairing correct when an
 * editor applies the colour to a tinted card. */
.vz-termcard__count,
.vz-fact__label,
.vz-crumbs__item {
	color: var(--wp--preset--color--contrast-muted);
}

/* --- 32. Layout hygiene ----------------------------------------------- */

/* Several templates wrap a dynamic block in a padded group: breadcrumbs on a
 * hub, the section tabs on a short page, the disclaimer on a page that has no
 * sources. When the block renders nothing the wrapper still occupied its
 * padding, which left 68px of dead space above the hero on the live site.
 * `:not(:has(> *))` matches a group with no element children, so only genuinely
 * empty wrappers collapse. */
main > .wp-block-group:not(:has(> *)),
.wp-site-blocks > .wp-block-group:not(:has(> *)),
.vz-crumbs-wrap:not(:has(> *)),
.vz-note-wrap:not(:has(> *)),
.vz-tabs-wrap:not(:has(> *)),
.vz-facts-wrap:not(:has(> *)),
.vz-cta-wrap:not(:has(> *)) {
	display: none;
}

/* A sidebar column with nothing in it should not reserve a grid track. */
.vz-layout__aside:not(:has(> *)) {
	display: none;
}

/* Long unbroken strings - HS codes, certificate numbers, URLs pasted into a
 * table cell - were the only source of horizontal overflow left. */
.vz-table td,
.vz-table th,
.vz-prose code,
.vz-source__link,
.vz-download__name {
	overflow-wrap: anywhere;
}

/* Images inside editorial prose keep their aspect ratio on narrow screens
 * instead of being stretched by an explicit width attribute. */
.vz-prose img,
.wp-block-post-content img {
	max-inline-size: 100%;
	block-size: auto;
}

/* --- 33. Component states and microinteractions ---------------------- */

/* Every interactive element in the theme gets four explicit states:
 * resting, :hover, :focus-visible and :active, plus a disabled state where
 * the element can be disabled. Motion is kept inside the 150-250ms window
 * from the 2026 guidance - fast enough to feel like direct manipulation,
 * slow enough to be readable - and is expressed through the transition
 * tokens in theme.json so timing stays consistent across components.
 *
 * Naming follows the BEM shape used throughout the theme:
 *   .vz-block            block
 *   .vz-block__element   element
 *   .vz-block--modifier  modifier
 * State is never baked into a class name; it comes from the real pseudo
 * class, so the markup carries no state bookkeeping.
 *
 * 30.12 already neutralises transitions under prefers-reduced-motion, so
 * nothing here needs to repeat that guard. */

/* 33.1 Motion contract -------------------------------------------------- */

/* Only compositor-friendly properties are animated: transform, opacity,
 * colour and shadow. No width/height/top/left transitions, so hover states
 * never trigger layout. */
:where(.vz-btn, .wp-element-button, .wp-block-button__link, .vz-tag,
	.vz-chip__link, .vz-card, .vz-bento__tile, .vz-crumbs__item a,
	.vz-pagination .page-numbers, .vz-footer__nav a, .vz-social a) {
	transition-property: background-color, border-color, color, box-shadow, transform, opacity;
	transition-duration: 190ms;
	transition-timing-function: cubic-bezier(0.2, 0, 0.2, 1);
}

/* 33.2 Buttons: primary / secondary / ghost ---------------------------- */

.vz-btn--primary:hover {
	background-color: var(--wp--preset--color--primary-dark);
	box-shadow: var(--wp--preset--shadow--card);
	transform: translateY(-1px);
}

.vz-btn--primary:active {
	background-color: var(--wp--preset--color--primary-dark);
	box-shadow: none;
	transform: translateY(0);
}

/* Secondary: quiet container, brand-coloured label. Border carries the
 * affordance, so it is held at 3:1 against the page in both schemes. */
.vz-btn--secondary {
	border: 1px solid var(--wp--preset--color--outline-strong);
	background-color: transparent;
	color: var(--wp--preset--color--primary-dark);
}

.vz-btn--secondary:hover {
	border-color: var(--wp--preset--color--primary);
	background-color: var(--wp--preset--color--surface-accent);
	transform: translateY(-1px);
}

.vz-btn--secondary:active {
	background-color: var(--wp--preset--color--surface-accent);
	transform: translateY(0);
}

/* Ghost: no container until interaction. Used for tertiary actions where a
 * third filled or outlined button would flatten the hierarchy. */
.vz-btn--ghost {
	border: 1px solid transparent;
	background-color: transparent;
	color: var(--wp--preset--color--primary-dark);
}

.vz-btn--ghost:hover {
	background-color: var(--wp--preset--color--surface-accent);
}

.vz-btn--ghost:active {
	background-color: var(--wp--preset--color--surface);
}

/* Disabled. `aria-disabled` is included because a link cannot be disabled
 * with the attribute and must stay focusable to be discoverable. */
.vz-btn:disabled,
.vz-btn[aria-disabled="true"],
.wp-element-button:disabled,
.wp-block-button__link:disabled,
.wp-block-button.is-disabled .wp-block-button__link {
	border-color: var(--wp--preset--color--outline);
	background-color: var(--wp--preset--color--surface);
	box-shadow: none;
	color: var(--wp--preset--color--contrast-subtle);
	cursor: not-allowed;
	transform: none;
}

.vz-btn:disabled:hover,
.vz-btn[aria-disabled="true"]:hover,
.wp-element-button:disabled:hover {
	background-color: var(--wp--preset--color--surface);
	transform: none;
}

/* Core buttons get the same lift so pattern-authored buttons and
 * theme-authored ones behave identically. */
.wp-element-button:hover,
.wp-block-button__link:hover {
	box-shadow: var(--wp--preset--shadow--card);
	transform: translateY(-1px);
}

.wp-element-button:active,
.wp-block-button__link:active {
	box-shadow: none;
	transform: translateY(0);
}

/* 33.3 Form fields ------------------------------------------------------ */

.vz-field {
	display: flex;
	flex-direction: column;
	gap: 0.375rem;
}

.vz-field__label {
	color: var(--wp--preset--color--contrast);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
}

.vz-field__hint {
	color: var(--wp--preset--color--contrast-subtle);
	font-size: var(--wp--preset--font-size--x-small);
}

.vz-field__error {
	color: var(--wp--custom--semantic--danger);
	font-size: var(--wp--preset--font-size--x-small);
	font-weight: 600;
}

input:not([type="checkbox"]):not([type="radio"]):not([type="submit"]),
select,
textarea,
.wp-block-search__input {
	border: 1px solid var(--wp--preset--color--outline-strong);
	border-radius: var(--wp--custom--radius--control);
	background-color: var(--wp--preset--color--base);
	color: var(--wp--preset--color--contrast);
	transition: border-color 150ms cubic-bezier(0.2, 0, 0.2, 1),
		box-shadow 150ms cubic-bezier(0.2, 0, 0.2, 1),
		background-color 150ms cubic-bezier(0.2, 0, 0.2, 1);
}

input:not([type="checkbox"]):not([type="radio"]):not([type="submit"]):hover,
select:hover,
textarea:hover {
	border-color: var(--wp--preset--color--primary-light);
}

/* Focus is doubled up: the outline from theme.json carries the visible ring,
 * the inset shadow thickens the field edge so the association between ring
 * and field survives on a busy background. */
input:not([type="checkbox"]):not([type="radio"]):not([type="submit"]):focus-visible,
select:focus-visible,
textarea:focus-visible,
.wp-block-search__input:focus-visible {
	border-color: var(--wp--preset--color--primary);
	box-shadow: inset 0 0 0 1px var(--wp--preset--color--primary);
}

/* Validity styling is opt-in via :user-invalid, not :invalid: a required
 * field must not turn red before the user has touched it. */
input:user-invalid,
select:user-invalid,
textarea:user-invalid {
	border-color: var(--wp--custom--semantic--danger);
	box-shadow: inset 0 0 0 1px var(--wp--custom--semantic--danger);
}

input:disabled,
select:disabled,
textarea:disabled {
	border-color: var(--wp--preset--color--outline);
	background-color: var(--wp--preset--color--surface);
	color: var(--wp--preset--color--contrast-subtle);
	cursor: not-allowed;
}

::placeholder {
	color: var(--wp--preset--color--contrast-subtle);
	opacity: 1;
}

/* Checkbox and radio: keep the native control, recolour it and give it a
 * real hit area through the label. */
input[type="checkbox"],
input[type="radio"] {
	accent-color: var(--wp--preset--color--primary);
	inline-size: 1.125rem;
	block-size: 1.125rem;
}

.vz-field--choice {
	flex-direction: row;
	align-items: center;
	gap: 0.625rem;
	min-block-size: 44px;
}

/* 33.4 Cards: post / product / CTA ------------------------------------- */

/* The whole card is the target, but the anchor stays the only focusable
 * node, so the ring is drawn on the card via :focus-within. */
.vz-card:focus-within {
	border-color: var(--wp--preset--color--primary);
	box-shadow: var(--wp--preset--shadow--card-hover);
}

.vz-card--lift:hover {
	transform: translateY(-2px);
}

.vz-card--lift:active {
	transform: translateY(0);
}

/* Media inside a clipped card creeps in slightly on hover. 1.03 is
 * deliberately small: anything larger reads as a slideshow effect. */
.vz-card--clip .wp-block-post-featured-image img,
.vz-card--clip .vz-card__media img {
	transition: transform 240ms cubic-bezier(0.2, 0, 0.2, 1);
}

.vz-card--clip:hover .wp-block-post-featured-image img,
.vz-card--clip:hover .vz-card__media img {
	transform: scale(1.03);
}

/* Title colour shift is the primary hover signal, because it survives
 * high-contrast mode and does not depend on shadow rendering. */
.vz-card:hover .wp-block-post-title a,
.vz-card:hover .vz-card__title a,
.vz-card:focus-within .wp-block-post-title a,
.vz-card:focus-within .vz-card__title a {
	color: var(--wp--preset--color--primary-dark);
	text-decoration: underline;
	text-underline-offset: 0.18em;
}

/* Meta row (date, reading time, terms) is pushed to the card floor so
 * cards of unequal body length still align their footers. */
.vz-card__meta {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.375rem 0.75rem;
	margin-block-start: auto;
	padding-block-start: var(--wp--preset--spacing--20);
	color: var(--wp--preset--color--contrast-subtle);
	font-size: var(--wp--preset--font-size--x-small);
	line-height: 1.4;
}

/* Separator dots are generated, never typed into the content. */
.vz-card__meta > * + *::before {
	margin-inline-end: 0.5rem;
	color: var(--wp--preset--color--outline-strong);
	content: "\00b7";
}

/* 33.5 Navigation ------------------------------------------------------- */

/* Desktop: an underline grows from the leading edge. The pseudo element is
 * scaled rather than sized so the animation stays off the layout thread. */
@media (min-width: 782px) {
	.vz-mainnav .wp-block-navigation-item__content {
		position: relative;
	}

	.vz-mainnav .wp-block-navigation-item__content::after {
		position: absolute;
		inset-block-end: -0.35rem;
		inset-inline-start: 0;
		display: block;
		inline-size: 100%;
		block-size: 2px;
		background-color: var(--wp--preset--color--primary);
		border-radius: 2px;
		content: "";
		transform: scaleX(0);
		transform-origin: left center;
		transition: transform 190ms cubic-bezier(0.2, 0, 0.2, 1);
	}

	.vz-mainnav .wp-block-navigation-item:hover > .wp-block-navigation-item__content::after,
	.vz-mainnav .wp-block-navigation-item__content:focus-visible::after,
	.vz-mainnav .wp-block-navigation-item.current-menu-item > .wp-block-navigation-item__content::after {
		transform: scaleX(1);
	}

	/* Submenus fade and settle instead of appearing instantly. */
	.vz-mainnav .wp-block-navigation__submenu-container {
		box-shadow: var(--wp--preset--shadow--dropdown);
		transition: opacity 190ms cubic-bezier(0.2, 0, 0.2, 1),
			transform 190ms cubic-bezier(0.2, 0, 0.2, 1);
	}
}

/* Mobile overlay rows: pressed feedback only, no hover, since a hover state
 * on touch sticks after the tap. */
@media (max-width: 781px) {
	.vz-mainnav .wp-block-navigation-item__content:active {
		background-color: var(--wp--preset--color--surface-accent);
	}
}

/* 33.6 Breadcrumbs ------------------------------------------------------ */

.vz-crumbs__item a:hover {
	color: var(--wp--preset--color--primary-dark);
	text-decoration: underline;
	text-underline-offset: 0.16em;
}

.vz-crumbs__item[aria-current="page"],
.vz-crumbs__current {
	color: var(--wp--preset--color--contrast);
	font-weight: 600;
}

/* 33.7 Pagination ------------------------------------------------------- */

.vz-pagination .page-numbers:not(.current):hover,
.vz-postgrid .wp-block-query-pagination-numbers .page-numbers:not(.current):hover {
	border-color: var(--wp--preset--color--primary);
	background-color: var(--wp--preset--color--surface-accent);
	color: var(--wp--preset--color--primary-dark);
}

.vz-pagination .page-numbers:not(.current):active {
	background-color: var(--wp--preset--color--surface);
}

.vz-pagination .page-numbers.current {
	cursor: default;
}

/* 33.8 Tags and badges -------------------------------------------------- */

.vz-tag:hover,
.vz-chip__link:hover {
	border-color: var(--wp--preset--color--primary);
	background-color: var(--wp--preset--color--surface-accent);
	color: var(--wp--preset--color--primary-dark);
}

.vz-tag:active,
.vz-chip__link:active {
	transform: translateY(1px);
}

/* Semantic badges. Text and background are picked so each pair clears AA in
 * both schemes; the border adds a non-colour cue for the colour-blind. */
.vz-badge {
	display: inline-flex;
	align-items: center;
	gap: 0.375rem;
	padding: 0.1875rem 0.5rem;
	border: 1px solid currentColor;
	border-radius: var(--wp--custom--radius--xs);
	font-size: var(--wp--preset--font-size--x-small);
	font-weight: 600;
	line-height: 1.4;
}

.vz-badge--success {
	background-color: var(--wp--preset--color--surface-accent);
	color: var(--wp--custom--semantic--success);
}

.vz-badge--warning {
	background-color: var(--wp--preset--color--amber-light);
	color: var(--wp--custom--semantic--warning);
}

.vz-badge--info {
	background-color: var(--wp--preset--color--sky-light);
	color: var(--wp--custom--semantic--info);
}

.vz-badge--danger {
	background-color: var(--wp--preset--color--danger-light);
	color: var(--wp--custom--semantic--danger);
}

/* 33.9 Quotes ----------------------------------------------------------- */

.wp-block-quote {
	position: relative;
	padding-inline-start: var(--wp--preset--spacing--50);
	border-inline-start: 3px solid var(--wp--preset--color--primary-light);
}

.wp-block-quote p {
	font-size: var(--wp--preset--font-size--large);
	line-height: 1.55;
}

.wp-block-pullquote {
	border-radius: var(--wp--custom--radius--panel);
	background-color: var(--wp--preset--color--surface-accent);
}

/* 33.10 Tables ---------------------------------------------------------- */

/* Row hover is a reading aid on wide specification tables. It is suppressed
 * on touch, where there is no pointer to follow. */
@media (hover: hover) and (min-width: 782px) {
	.wp-block-table tbody tr:hover,
	.vz-table tbody tr:hover {
		background-color: var(--wp--preset--color--surface);
	}
}

.wp-block-table th,
.vz-table th {
	position: relative;
}

/* Sticky header row for long tables. `background-clip` stops the cell
 * background bleeding over the border while scrolling. */
.vz-table--sticky-head thead th,
.is-style-vz-sticky-head thead th {
	position: sticky;
	inset-block-start: 0;
	z-index: 1;
	background-color: var(--wp--preset--color--surface);
	background-clip: padding-box;
}

/* 33.11 Footer ---------------------------------------------------------- */

.vz-footer__nav a:hover,
.vz-footer__legal a:hover {
	color: var(--wp--preset--color--primary);
	text-decoration: underline;
	text-underline-offset: 0.16em;
}

.vz-social a {
	border-radius: var(--wp--custom--radius--sm);
}

.vz-social a:hover {
	opacity: 1;
	transform: translateY(-2px);
}

/* 33.12 Forced colours -------------------------------------------------- */

/* Windows high contrast strips backgrounds and shadows, which removes every
 * hover cue that relies on them. Borders survive, so the states are restated
 * as border changes. */
@media (forced-colors: active) {
	.vz-btn,
	.wp-element-button,
	.wp-block-button__link,
	.vz-tag,
	.vz-card {
		border: 1px solid ButtonBorder;
	}

	.vz-btn:hover,
	.wp-element-button:hover,
	.vz-tag:hover,
	.vz-card:hover {
		border-color: Highlight;
	}

	:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
		outline: 3px solid Highlight;
		outline-offset: 2px;
	}
}

/* --- 34. Editorial hero and bento layout ----------------------------- */

/* Layout primitives for the 2026 patterns. All three are thin: the grid
 * itself comes from the native Group block in grid mode, so the structure
 * stays editable in the site editor and these rules only add rhythm,
 * containment and the parts CSS Grid cannot express in block attributes. */

/* 34.1 Editorial hero --------------------------------------------------- */

.vz-hero--editorial {
	padding-block: var(--wp--custom--rhythm--5) var(--wp--custom--rhythm--4);
}

/* The headline is the whole design here, so it gets the widest optical
 * treatment the type scale allows: tight tracking, tight leading, balanced
 * line breaks and a measure that stops it running past ~14 words a line. */
.vz-hero__display {
	max-inline-size: 20ch;
	font-size: var(--wp--preset--font-size--display-hero);
	line-height: 1.02;
	letter-spacing: -0.03em;
	text-wrap: balance;
}

.vz-hero__display em {
	color: var(--wp--preset--color--primary);
	font-style: normal;
}

.vz-hero__lead {
	max-inline-size: 48ch;
	color: var(--wp--preset--color--contrast-muted);
	text-wrap: pretty;
}

/* A hairline rail of figures beside the headline. Asymmetric by design: the
 * rail is deliberately not centred against the headline block. */
.vz-hero__rail {
	display: grid;
	gap: var(--wp--preset--spacing--40);
	align-content: end;
}

.vz-figure {
	padding-block-start: var(--wp--preset--spacing--30);
	border-block-start: 1px solid var(--wp--preset--color--outline);
}

.vz-figure__value {
	display: block;
	font-size: var(--wp--preset--font-size--xx-large);
	font-weight: 700;
	letter-spacing: -0.02em;
	line-height: 1.1;
	font-variant-numeric: tabular-nums;
}

.vz-figure__label {
	display: block;
	color: var(--wp--preset--color--contrast-subtle);
	font-size: var(--wp--preset--font-size--x-small);
	letter-spacing: 0.02em;
}

/* 34.2 Bento grid ------------------------------------------------------- */

/* The Group block in grid mode emits the columns and the spans; this adds
 * the tile skin and the collapse behaviour. Below 782px the explicit spans
 * from the block attributes are dropped so tiles stack in source order
 * instead of turning into slivers. */
.vz-bento {
	container-type: inline-size;
}

.vz-bento__tile,
.is-style-vz-tile {
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--30);
	padding: var(--wp--preset--spacing--50);
	border: 1px solid var(--wp--preset--color--outline);
	border-radius: var(--wp--custom--radius--panel);
	background-color: var(--wp--preset--color--base);
	box-shadow: var(--wp--preset--shadow--soft);
}

.vz-bento__tile--accent,
.is-style-vz-tile-accent {
	border-color: transparent;
	background-color: var(--wp--preset--color--surface-accent);
	box-shadow: none;
}

.vz-bento__tile--deep,
.is-style-vz-tile-deep {
	border-color: transparent;
	background-color: var(--wp--preset--color--deep);
	color: var(--wp--custom--on-dark);
}

.vz-bento__tile--deep :is(h1, h2, h3, h4, h5, h6),
.vz-bento__tile--deep p,
.is-style-vz-tile-deep :is(h1, h2, h3, h4, h5, h6),
.is-style-vz-tile-deep p {
	color: var(--wp--custom--on-dark);
}

.vz-bento__tile--deep .vz-bento__meta,
.is-style-vz-tile-deep .vz-bento__meta {
	color: var(--wp--custom--on-dark-muted);
}

.vz-bento__tile:hover,
.is-style-vz-tile:hover {
	border-color: var(--wp--preset--color--outline-strong);
	box-shadow: var(--wp--preset--shadow--card-hover);
	transform: translateY(-2px);
}

.vz-bento__tile:focus-within,
.is-style-vz-tile:focus-within {
	border-color: var(--wp--preset--color--primary);
	box-shadow: var(--wp--preset--shadow--card-hover);
}

.vz-bento__eyebrow {
	color: var(--wp--preset--color--primary);
	font-size: var(--wp--preset--font-size--x-small);
	font-weight: 700;
	letter-spacing: var(--wp--custom--typography--letter-spacing--wide);
	text-transform: uppercase;
}

.vz-bento__meta {
	margin-block-start: auto;
	color: var(--wp--preset--color--contrast-subtle);
	font-size: var(--wp--preset--font-size--x-small);
}

/* Collapse the asymmetry on small screens. The spans live in inline styles
 * emitted by the block, so they are overridden by an explicit declaration
 * rather than removed from the markup - the editor keeps its layout. */
@media (max-width: 781px) {
	.vz-bento > .vz-bento__tile,
	.vz-bento > .is-style-vz-tile {
		grid-column: 1 / -1 !important;
		grid-row: auto !important;
	}
}

/* 34.3 CTA panel -------------------------------------------------------- */

.vz-ctapanel,
.is-style-vz-panel {
	position: relative;
	overflow: hidden;
	border-radius: var(--wp--custom--radius--panel);
	background-color: var(--wp--preset--color--deep);
	color: var(--wp--custom--on-dark);
}

/* A single very soft radial wash instead of a layered gradient. It sits
 * behind the content and is invisible to assistive technology. */
.vz-ctapanel::before,
.is-style-vz-panel::before {
	position: absolute;
	inset-block-start: -40%;
	inset-inline-end: -10%;
	z-index: 0;
	inline-size: 60%;
	aspect-ratio: 1;
	background: radial-gradient(circle, rgba(79, 133, 82, 0.30) 0%, rgba(79, 133, 82, 0) 70%);
	content: "";
	pointer-events: none;
}

.vz-ctapanel > *,
.is-style-vz-panel > * {
	position: relative;
	z-index: 1;
}

.vz-ctapanel :is(h1, h2, h3, h4, h5, h6),
.is-style-vz-panel :is(h1, h2, h3, h4, h5, h6) {
	color: var(--wp--custom--on-dark);
}

.vz-ctapanel p,
.is-style-vz-panel p {
	color: var(--wp--custom--on-dark-muted);
}

/* --- 35. Backgrounds and depth (2026 refresh) ------------------------- */

/* The brief asks for "calm, intentional" depth: a pure base root, sections
 * that fade rather than switch, cards on one tinted surface, a hairline seam
 * instead of a frame, and a grain so faint it only shows up as the absence of
 * banding on large flat areas.
 *
 * Everything below is expressed through tokens, so the Dark scheme and the
 * three light variations inherit the whole treatment without one override. */

/* 35.1 Derived tokens --------------------------------------------------- */

html:root {
	/* Seam, not frame: the brief's "outline at 0.6 opacity". color-mix keeps
	 * it a token instead of a hardcoded rgba, so it follows the scheme. */
	--vz-outline-soft: color-mix(in srgb, var(--wp--preset--color--outline) 60%, transparent);

	/* Header scrim: translucent enough for the backdrop blur to be visible,
	 * opaque enough that body text scrolling underneath never shows through. */
	--vz-header-scrim: color-mix(in srgb, var(--wp--preset--color--base) var(--wp--custom--depth--scrim-alpha), transparent);

	/* Grain. A 120x120 fractal-noise tile inlined as SVG - no HTTP request, no
	 * raster asset, ~340 bytes, and it scales without artefacts. Opacity is a
	 * token so a variation can dial it down. */
	--vz-grain: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* 35.2 Section grounds -------------------------------------------------- */

/* Opt-in fade for a section band. Painted with the gradient token, so the
 * dark scheme swaps to its own dark-to-darker pair automatically. */
.vz-section--fade,
.vz-surface-fade,
.is-style-vz-section-fade {
	background-image: var(--wp--preset--gradient--surface-fade);
	background-repeat: no-repeat;
	background-size: 100% 100%;
}

/* Inverse fade, for a band that follows a tinted section and needs to resolve
 * back to base without a hard edge. */
.vz-section--fade-up {
	background-image: linear-gradient(180deg,
		var(--wp--preset--color--surface) 0%,
		var(--wp--preset--color--base) 100%);
	background-repeat: no-repeat;
}

/* 35.3 Cards and side panels ------------------------------------------- */

/* Sidebar cards move from base to surface-accent with the soft seam. This is
 * the single largest visual change of the refresh: the sidebar now reads as
 * one calm column instead of a stack of outlined boxes. */
.vz-aside__card {
	border-color: var(--vz-outline-soft);
	background-color: var(--wp--preset--color--surface-accent);
}

/* A card that already sits inside a tinted region keeps base so the two
 * surfaces do not collapse into each other. */
.vz-aside__card.vz-aside__card--plain,
.has-surface-accent-background-color .vz-aside__card {
	background-color: var(--wp--preset--color--base);
}

/* Content cards: radius pushed into the 12-16px window from the brief, seam
 * instead of frame. Radius is applied to the card and to its clipped media so
 * an image never squares off the corner. */
.vz-card,
.vz-termcard,
.vz-step,
.vz-bento__tile {
	border-radius: var(--wp--custom--radius--md);
	border-color: var(--vz-outline-soft);
}

.vz-card--feature,
.vz-card--panel {
	border-radius: var(--wp--custom--radius--lg);
}

.vz-card--clip {
	overflow: hidden;
}

/* 35.4 Grain on hero and footer ---------------------------------------- */

/* Applied through a pseudo element rather than a second background layer, so
 * the element keeps its own background-image slot free for a gradient or a
 * photograph. `mix-blend-mode: overlay` keeps the grain neutral on both light
 * and dark grounds. */
.vz-hero--deep::after,
.vz-hero--editorial::after,
.vz-ctapanel::after,
.vz-newsletter-band::after,
.vz-footer::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 0;
	background-image: var(--vz-grain);
	background-repeat: repeat;
	opacity: var(--wp--custom--depth--grain-opacity);
	mix-blend-mode: overlay;
	pointer-events: none;
}

/* The grain layer needs a positioned parent and content stacked above it. */
.vz-hero--deep,
.vz-hero--editorial,
.vz-newsletter-band,
.vz-footer {
	position: relative;
}

.vz-hero--deep > *,
.vz-hero--editorial > *,
.vz-newsletter-band > *,
.vz-footer > * {
	position: relative;
	z-index: 1;
}

/* Grain is decoration with zero information value: in forced-colours mode it
 * would only muddy the ground, so it is removed. */
@media (forced-colors: active) {
	.vz-hero--deep::after,
	.vz-hero--editorial::after,
	.vz-ctapanel::after,
	.vz-newsletter-band::after,
	.vz-footer::after {
		display: none;
	}
}

/* 35.5 Sticky header: blur and scrim ----------------------------------- */

/* The navbar is already sticky below 1023px (section 30). The refresh makes
 * the treatment scheme-aware and adds the frosted ground the brief asks for.
 *
 * `backdrop-filter` is behind an @supports gate: where it is unavailable the
 * fallback is a fully opaque background, which is the safe direction - text
 * stays readable, only the effect is lost. */
.vz-navbar {
	background-color: var(--wp--preset--color--base);
}

@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
	.vz-navbar {
		background-color: var(--vz-header-scrim);
		-webkit-backdrop-filter: blur(var(--wp--custom--depth--blur)) saturate(140%);
		backdrop-filter: blur(var(--wp--custom--depth--blur)) saturate(140%);
	}
}

/* Once the page has scrolled past the header the navbar gains a hairline and
 * a shadow, so it detaches from the content instead of floating ambiguously.
 * The `is-scrolled` class is set by assets/js/vorezan.js. */
.vz-navbar.is-scrolled {
	border-block-end: 1px solid var(--vz-outline-soft);
	box-shadow: var(--wp--preset--shadow--soft);
}


/* --- 36. Controls: buttons and fields (2026 refresh) ------------------ */

/* 36.1 Shared control geometry ----------------------------------------- */

/* One rule gives every button-shaped thing in the theme the same box: the
 * WCAG 2.2 SC 2.5.8 minimum height, centred label, non-shrinking text.
 * Padding and radius come from theme.json, so this only owns the geometry
 * that theme.json cannot express. */
.vz-btn,
.wp-element-button,
.wp-block-button__link,
.vz-search .wp-block-search__button {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.5rem;
	min-height: var(--wp--custom--control--height);
	border-radius: var(--wp--custom--radius--control);
	text-decoration: none;
	text-align: center;
}

/* Touch surfaces get the comfort height instead of the minimum. */
@media (pointer: coarse), (max-width: 781px) {
	.vz-btn,
	.wp-element-button,
	.wp-block-button__link {
		min-height: var(--wp--custom--control--height-large);
	}
}

/* 36.2 Calm hover ------------------------------------------------------ */

/* Section 33 lifted buttons by 1px and added a shadow on hover. The 2026
 * brief replaces that with a colour shift plus a 1% scale: the feedback is
 * immediate, but nothing moves in the layout and nothing casts a shadow, so a
 * dense page of buttons stays quiet. These selectors match section 33 exactly
 * and come later, so they win on source order. */
.vz-btn--primary:hover,
.wp-element-button:hover,
.wp-block-button__link:hover {
	box-shadow: none;
	transform: scale(1.01);
}

.vz-btn--primary:active,
.wp-element-button:active,
.wp-block-button__link:active {
	box-shadow: none;
	transform: scale(0.995);
}

.vz-btn--secondary:hover,
.vz-btn--secondary:active {
	transform: scale(1.01);
}

/* Ghost is text only: no container ever appears, so it cannot compete with
 * the secondary button. Underline is the whole hover signal. */
.vz-btn--ghost:hover,
.vz-btn--ghost:active {
	background-color: transparent;
	text-decoration: underline;
	text-decoration-thickness: var(--wp--custom--link--underline-thickness);
	text-underline-offset: var(--wp--custom--link--underline-offset);
	transform: none;
}

/* A 1% scale is still motion. Reduced-motion users get the colour shift only.
 * Section 30.12 already zeroes the transition; this removes the transform. */
@media (prefers-reduced-motion: reduce) {
	.vz-btn:hover,
	.vz-btn:active,
	.wp-element-button:hover,
	.wp-element-button:active,
	.wp-block-button__link:hover,
	.wp-block-button__link:active {
		transform: none;
	}
}

/* 36.3 Loading state --------------------------------------------------- */

/* Driven by `aria-busy="true"`, which is the accessible source of truth: a
 * screen reader announces the busy state from the same attribute that draws
 * the spinner, so the two can never disagree.
 *
 * The label is kept in place and dimmed rather than replaced, so the button
 * does not change width mid-interaction (no layout shift, no CLS). */
.vz-btn[aria-busy="true"],
.wp-element-button[aria-busy="true"],
.wp-block-button__link[aria-busy="true"] {
	cursor: progress;
	pointer-events: none;
}

.vz-btn[aria-busy="true"] > *,
.wp-element-button[aria-busy="true"] > * {
	opacity: 0.45;
}

.vz-btn[aria-busy="true"]::before,
.wp-element-button[aria-busy="true"]::before,
.wp-block-button__link[aria-busy="true"]::before {
	content: "";
	inline-size: 1em;
	block-size: 1em;
	flex: 0 0 auto;
	border: 2px solid currentColor;
	border-block-start-color: transparent;
	border-radius: 50%;
	animation: vz-spin 640ms linear infinite;
}

@keyframes vz-spin {
	to { transform: rotate(360deg); }
}

/* Reduced motion gets a pulse instead of a rotation: still a "working"
 * signal, no vestibular trigger. */
@media (prefers-reduced-motion: reduce) {
	.vz-btn[aria-busy="true"]::before,
	.wp-element-button[aria-busy="true"]::before,
	.wp-block-button__link[aria-busy="true"]::before {
		animation: vz-pulse 1.4s ease-in-out infinite;
	}

	@keyframes vz-pulse {
		0%, 100% { opacity: 0.35; }
		50%      { opacity: 1; }
	}
}

/* 36.4 Success state --------------------------------------------------- */

/* `data-vz-state="success"` is set by the script after a successful submit and
 * cleared on the next interaction. The checkmark is a border trick, so there
 * is no icon font and no SVG request. */
.vz-btn[data-vz-state="success"],
.wp-element-button[data-vz-state="success"] {
	background-color: var(--wp--custom--semantic--success);
	color: var(--wp--custom--on-brand);
}

.vz-btn[data-vz-state="success"]::before,
.wp-element-button[data-vz-state="success"]::before {
	content: "";
	inline-size: 0.45em;
	block-size: 0.8em;
	flex: 0 0 auto;
	border: solid currentColor;
	border-width: 0 2px 2px 0;
	transform: rotate(45deg) translateY(-0.1em);
}

/* 36.5 Fields: search and inputs --------------------------------------- */

/* The brief retires the pill on inputs. Search wrapper takes the field
 * radius, its inner button takes the control radius, so the two corners are
 * visibly different radii and the button reads as a separate affordance. */
.vz-search .wp-block-search__inside-wrapper {
	border-radius: var(--wp--custom--radius--field);
	border-color: var(--vz-outline-soft);
}

.vz-search .wp-block-search__button {
	border-radius: var(--wp--custom--radius--control);
}

.vz-search .wp-block-search__input,
.vz-field__input,
.vz-newsletter input[type="email"],
input[type="text"],
input[type="email"],
input[type="search"],
input[type="url"],
input[type="tel"],
input[type="number"],
textarea,
select {
	min-height: var(--wp--custom--control--height);
	border-radius: var(--wp--custom--radius--field);
}

/* The inner search input sits inside an already-rounded wrapper, so it must
 * not draw a second corner. */
.vz-search .wp-block-search__input {
	border-radius: calc(var(--wp--custom--radius--field) - 2px);
	min-height: auto;
}

textarea {
	min-height: calc(var(--wp--custom--control--height) * 2.5);
}

/* Focus: the same 3px ring as every other control, drawn with outline so it
 * follows the border radius and never affects layout. */
.vz-search .wp-block-search__inside-wrapper:focus-within {
	outline: var(--wp--custom--focus-ring--width) solid var(--wp--preset--color--focus);
	outline-offset: var(--wp--custom--focus-ring--offset);
}


/* --- 37. Links (2026 refresh) ----------------------------------------- */

/* The rule the refresh is built on: a link inside running text is always
 * underlined. theme.json now sets `textDecoration: underline` on the link
 * element, which covers every anchor on the page - including the ones that
 * must NOT look like body links. So this section does two jobs: it gives the
 * body link its exact signature, and it revokes the underline everywhere an
 * anchor is really a control, a card or a navigation item. */

/* 37.1 Body link signature --------------------------------------------- */

/* Thickness and offset are tokens, so every underlined thing in the theme
 * shares one visual weight. `text-decoration-skip-ink: auto` keeps descenders
 * legible in Cyrillic, where they are common. */
.vz-prose a,
.entry-content a:not(.wp-element-button),
.vz-aside__card p a,
.vz-src a,
.vz-faq__answer a {
	text-decoration: underline;
	text-decoration-thickness: var(--wp--custom--link--underline-thickness);
	text-underline-offset: var(--wp--custom--link--underline-offset);
	text-decoration-skip-ink: auto;
	transition: color var(--wp--custom--transition--fast),
		text-decoration-color var(--wp--custom--transition--fast);
}

.vz-prose a:hover,
.entry-content a:not(.wp-element-button):hover {
	color: var(--wp--custom--link--hover);
	text-decoration-thickness: 2px;
}

/* Visited is muted rather than the browser default purple, which would fight
 * the palette. It stays above 4.5:1 in every scheme (verified by the gate). */
.vz-prose a:visited,
.entry-content a:not(.wp-element-button):visited {
	color: var(--wp--custom--link--visited);
}

/* 37.2 Where an anchor is not a body link ------------------------------ */

/* Navigation, controls, cards, chips and pagination: colour and weight carry
 * the affordance, so the underline is revoked at rest and returns on hover
 * where it is a useful confirmation. :where() keeps specificity at zero so
 * any component rule can still override without an !important. */
:where(
	.wp-block-navigation a,
	.vz-navbar a,
	.vz-topbar a,
	.vz-footer__nav a,
	.vz-footer__legal a,
	.vz-social a,
	.vz-tabs__link,
	.vz-crumbs__item a,
	.vz-pagination a,
	.vz-chip__link,
	.vz-tag,
	.vz-card a,
	.vz-termcard,
	.vz-step a,
	.vz-btn,
	.wp-element-button,
	.wp-block-button__link,
	.wp-block-site-title a,
	.wp-block-post-title a,
	.vz-brand a
) {
	text-decoration: none;
}

/* Navigation items: colour shift at rest, underline only on hover and on the
 * current page, which is the brief's rule for nav. */
.wp-block-navigation a:hover,
.vz-navbar a:hover,
.vz-topbar a:hover,
.vz-footer__nav a:hover,
.vz-footer__legal a:hover {
	text-decoration: underline;
	text-decoration-thickness: var(--wp--custom--link--underline-thickness);
	text-underline-offset: var(--wp--custom--link--underline-offset);
}

/* Current page is marked with a permanent underline, so location is not
 * carried by colour alone (WCAG 2.2 SC 1.4.1). */
.wp-block-navigation .current-menu-item > a,
.wp-block-navigation-item.current-menu-item > a {
	text-decoration: underline;
	text-decoration-thickness: 2px;
	text-underline-offset: var(--wp--custom--link--underline-offset);
	font-weight: 600;
}

/* 37.3 Card titles ------------------------------------------------------ */

/* At rest a card title is body ink, not link ink: on a grid of twelve cards,
 * twelve coloured headlines is noise. The colour arrives with hover, which
 * section 33.4 already handles - this only guarantees the resting state. */
.vz-card .wp-block-post-title a,
.vz-card .vz-card__title a,
.vz-termcard__title a {
	color: var(--wp--preset--color--contrast);
}

/* 37.4 External links -------------------------------------------------- */

/* Marked by an explicit signal rather than by guessing at the hostname, which
 * cannot be done reliably in CSS: either the editor set target=_blank, or the
 * link carries rel="external", or a pattern applied the class. The glyph is a
 * masked SVG so it inherits currentColor in both schemes. */
.vz-prose a[target="_blank"]::after,
.vz-prose a[rel~="external"]::after,
.vz-src a[target="_blank"]::after,
a.vz-link--external::after {
	content: "";
	display: inline-block;
	inline-size: 0.7em;
	block-size: 0.7em;
	margin-inline-start: 0.3em;
	vertical-align: baseline;
	background-color: currentColor;
	-webkit-mask-image: var(--vz-icon-external);
	mask-image: var(--vz-icon-external);
	-webkit-mask-repeat: no-repeat;
	mask-repeat: no-repeat;
	-webkit-mask-size: contain;
	mask-size: contain;
}

html:root {
	--vz-icon-external: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6'/%3E%3Cpath d='M15 3h6v6'/%3E%3Cpath d='M10 14 21 3'/%3E%3C/svg%3E");
}

/* Where masks are unsupported the glyph would render as a filled square, so
 * it is suppressed entirely rather than shown broken. */
@supports not ((mask-image: none) or (-webkit-mask-image: none)) {
	.vz-prose a[target="_blank"]::after,
	.vz-prose a[rel~="external"]::after,
	.vz-src a[target="_blank"]::after,
	a.vz-link--external::after {
		display: none;
	}
}


/* --- 38. Chips, tags and card interaction (2026 refresh) ------------- */

/* Chips get the brief's "background darkens 8-10% on hover". color-mix against
 * `contrast` is scheme-safe: in the light scheme it darkens, in the dark
 * scheme `contrast` is light so the same expression lightens - which is the
 * correct direction for a dark ground. */
.vz-chip__link:hover,
.vz-tag:hover,
a.vz-tag:hover {
	background-color: color-mix(in srgb, var(--wp--preset--color--surface-accent) 91%, var(--wp--preset--color--contrast));
	border-color: var(--wp--preset--color--outline-strong);
}

.vz-chip__link:active,
a.vz-tag:active {
	background-color: color-mix(in srgb, var(--wp--preset--color--surface-accent) 84%, var(--wp--preset--color--contrast));
}

/* Card hover: border to outline-strong plus a barely-there ground shift, on
 * the brief's 190ms curve. The existing lift and title shift (section 33.4)
 * stay; this adds the two signals the brief names explicitly. */
.vz-card:hover,
.vz-termcard:hover,
.vz-bento__tile:hover {
	border-color: var(--wp--preset--color--outline-strong);
	background-color: color-mix(in srgb, var(--wp--preset--color--base) 96%, var(--wp--preset--color--primary));
}

/* A card that already sits on a tint shifts toward base instead, so the
 * direction of the change is always "toward the lighter surface". */
.vz-aside__card:hover {
	background-color: color-mix(in srgb, var(--wp--preset--color--surface-accent) 92%, var(--wp--preset--color--base));
}


/* --- 39. Vertical rhythm (2026 refresh) ------------------------------- */

/* The rhythm scale itself was widened ~12% in theme.json, which lifts every
 * section that already references `--wp--custom--rhythm--*`. These helpers
 * expose the scale to templates and patterns that currently hardcode a
 * spacing preset, so a section can be re-spaced without touching markup. */

.vz-section {
	padding-block: var(--wp--custom--rhythm--5);
}

.vz-section--tight {
	padding-block: var(--wp--custom--rhythm--3);
}

.vz-section--loose {
	padding-block: var(--wp--custom--rhythm--6);
}

/* Rhythm between stacked sections inside one column. `> * + *` keeps it to
 * direct children so nested groups do not compound. */
.vz-flow > * + * {
	margin-block-start: var(--wp--custom--rhythm--4);
}

.vz-flow--tight > * + * {
	margin-block-start: var(--wp--custom--rhythm--2);
}

/* Long-form measure. The brief's line-height and letter-spacing are set
 * globally in theme.json; this only caps the line length, which is the other
 * half of readable body copy. */
.vz-prose {
	max-inline-size: var(--wp--custom--typography--measure);
}

.vz-prose > * + * {
	margin-block-start: var(--wp--custom--rhythm--2);
}



/* --- 40. Contrast corrections (2026 refresh) -------------------------- */

/* Two rules from section 25 paint text on the always-dark hero using palette
 * slugs that are tuned for a light ground. Measured against `deep` in the
 * light scheme:
 *
 *   .vz-hero__lead     contrast-subtle #5C6B61   2.73:1   FAIL (needs 4.5)
 *   .vz-hero__eyebrow  primary-light   #4F8552   3.51:1   FAIL (x-small text)
 *
 * This is the same class of defect v1.3.0 fixed for headings, missed here
 * because the lead and eyebrow are set by component rather than by background.
 * The fix is the token that already exists for exactly this case: `on-dark`
 * and `on-dark-muted` are light inks in BOTH schemes, because the hero ground
 * is dark in both. Measured after, light scheme / Dark scheme:
 *   .vz-hero__lead     on-dark-muted            9.11:1 / 11.03:1
 *   .vz-hero__eyebrow  on-dark 72% + prim-light 10.14:1 / 13.62:1
 *
 * The eyebrow keeps a tint by mixing toward primary-light rather than using it
 * outright, so the brand accent survives without dropping below AA. */
.vz-hero--deep .vz-hero__lead {
	color: var(--wp--custom--on-dark-muted);
}

.vz-hero--deep .vz-hero__eyebrow {
	color: color-mix(in srgb, var(--wp--custom--on-dark) 72%, var(--wp--preset--color--primary-light));
}

/* Companion to the v1.3.0 heading fix. `contrast` is a near-black ground in
 * the light scheme but flips to a near-white one in Dark, so a fixed light ink
 * on it renders light-on-light at 1.06:1. `on-contrast` is the scheme-aware
 * token (light ink in light schemes, `deep` ink in Dark) added for this. */
.has-contrast-background-color :is(h1, h2, h3, h4, h5, h6),
.has-contrast-background-color p {
	color: var(--wp--custom--on-contrast);
}

/* --- 41. Automatic dark mode ------------------------------------------ */

/* GENERATED by tools/gen_dark_css.py from styles/dark.json - do not edit by
 * hand. Re-run the generator after changing the Dark palette.
 *
 * The theme ships two schemes from day one. The visitor gets whichever the
 * OS asks for, and can override it with the header toggle (section 42),
 * which sets `data-vz-scheme` on <html>.
 *
 * Only tokens are redeclared. Every rule in the theme reads its colour
 * through a token, so nothing else needs a dark-specific branch. */

/* 41.1 Follow the operating system ------------------------------------- */

@media (prefers-color-scheme: dark) {
	html:root:not([data-vz-scheme="light"]) {
		/* Tell the UA: form controls, scrollbars and the
		 * default canvas all follow the dark scheme. */
		color-scheme: dark;

		/* Palette */
		--wp--preset--color--base: #0F1613;
		--wp--preset--color--surface: #171F1B;
		--wp--preset--color--surface-accent: #1D2A23;
		--wp--preset--color--outline: #27342E;
		--wp--preset--color--outline-strong: #6B8177;
		--wp--preset--color--primary: #63C07E;
		--wp--preset--color--primary-dark: #8AD79F;
		--wp--preset--color--primary-light: #4A9B62;
		--wp--preset--color--deep: #070C0A;
		--wp--preset--color--contrast: #E9F1EB;
		--wp--preset--color--contrast-muted: #BCCCC2;
		--wp--preset--color--contrast-subtle: #9CB0A4;
		--wp--preset--color--amber: #F2B571;
		--wp--preset--color--amber-light: #2C2318;
		--wp--preset--color--sky: #86BCE2;
		--wp--preset--color--sky-light: #17242F;
		--wp--preset--color--focus: #9BD0F5;
		--wp--preset--color--danger: #F4939B;
		--wp--preset--color--danger-light: #2E1A1C;

		/* Gradients */
		--wp--preset--gradient--deep-green: linear-gradient(135deg, #070C0A 0%, #16261D 100%);
		--wp--preset--gradient--brand-green: linear-gradient(135deg, #2C6F44 0%, #40895A 100%);
		--wp--preset--gradient--surface-fade: linear-gradient(180deg, #0F1613 0%, #171F1B 100%);
		--wp--preset--gradient--image-scrim: linear-gradient(180deg, rgba(7,12,10,0) 0%, rgba(7,12,10,0.82) 100%);

		/* Shadows: heavier and more diffuse, because a dark
		 * ground swallows the light-scheme values. */
		--wp--preset--shadow--soft: 0 1px 1px rgba(0, 0, 0, 0.30), 0 4px 14px rgba(0, 0, 0, 0.34);
		--wp--preset--shadow--card: 0 1px 2px rgba(0, 0, 0, 0.34), 0 1px 3px rgba(0, 0, 0, 0.30);
		--wp--preset--shadow--card-hover: 0 6px 22px rgba(0, 0, 0, 0.46), 0 2px 6px rgba(0, 0, 0, 0.34);
		--wp--preset--shadow--dropdown: 0 12px 34px rgba(0, 0, 0, 0.56), 0 2px 8px rgba(0, 0, 0, 0.40);
		--wp--preset--shadow--float: 0 18px 52px rgba(0, 0, 0, 0.62);

		/* Ink-on-fill tokens. These are the two that cannot be
		 * derived: in Dark, `primary-dark` and `contrast` are
		 * both LIGHT, so ink on them has to become dark. */
		--wp--custom--on-brand: var(--wp--preset--color--deep);
		--wp--custom--on-contrast: var(--wp--preset--color--deep);
	}
}

/* 41.2 Explicit visitor choice ----------------------------------------- */

/* Same tokens, applied regardless of the OS preference. */
html:root[data-vz-scheme="dark"] {
	/* Tell the UA: form controls, scrollbars and the
	 * default canvas all follow the dark scheme. */
	color-scheme: dark;

	/* Palette */
	--wp--preset--color--base: #0F1613;
	--wp--preset--color--surface: #171F1B;
	--wp--preset--color--surface-accent: #1D2A23;
	--wp--preset--color--outline: #27342E;
	--wp--preset--color--outline-strong: #6B8177;
	--wp--preset--color--primary: #63C07E;
	--wp--preset--color--primary-dark: #8AD79F;
	--wp--preset--color--primary-light: #4A9B62;
	--wp--preset--color--deep: #070C0A;
	--wp--preset--color--contrast: #E9F1EB;
	--wp--preset--color--contrast-muted: #BCCCC2;
	--wp--preset--color--contrast-subtle: #9CB0A4;
	--wp--preset--color--amber: #F2B571;
	--wp--preset--color--amber-light: #2C2318;
	--wp--preset--color--sky: #86BCE2;
	--wp--preset--color--sky-light: #17242F;
	--wp--preset--color--focus: #9BD0F5;
	--wp--preset--color--danger: #F4939B;
	--wp--preset--color--danger-light: #2E1A1C;

	/* Gradients */
	--wp--preset--gradient--deep-green: linear-gradient(135deg, #070C0A 0%, #16261D 100%);
	--wp--preset--gradient--brand-green: linear-gradient(135deg, #2C6F44 0%, #40895A 100%);
	--wp--preset--gradient--surface-fade: linear-gradient(180deg, #0F1613 0%, #171F1B 100%);
	--wp--preset--gradient--image-scrim: linear-gradient(180deg, rgba(7,12,10,0) 0%, rgba(7,12,10,0.82) 100%);

	/* Shadows: heavier and more diffuse, because a dark
	 * ground swallows the light-scheme values. */
	--wp--preset--shadow--soft: 0 1px 1px rgba(0, 0, 0, 0.30), 0 4px 14px rgba(0, 0, 0, 0.34);
	--wp--preset--shadow--card: 0 1px 2px rgba(0, 0, 0, 0.34), 0 1px 3px rgba(0, 0, 0, 0.30);
	--wp--preset--shadow--card-hover: 0 6px 22px rgba(0, 0, 0, 0.46), 0 2px 6px rgba(0, 0, 0, 0.34);
	--wp--preset--shadow--dropdown: 0 12px 34px rgba(0, 0, 0, 0.56), 0 2px 8px rgba(0, 0, 0, 0.40);
	--wp--preset--shadow--float: 0 18px 52px rgba(0, 0, 0, 0.62);

	/* Ink-on-fill tokens. These are the two that cannot be
	 * derived: in Dark, `primary-dark` and `contrast` are
	 * both LIGHT, so ink on them has to become dark. */
	--wp--custom--on-brand: var(--wp--preset--color--deep);
	--wp--custom--on-contrast: var(--wp--preset--color--deep);
}

/* An explicit light choice only needs the UA hint: the light tokens are
 * already the document default, and 41.1 stops matching. */
html:root[data-vz-scheme="light"] {
	color-scheme: light;
}

/* 41.3 Optical weight compensation ------------------------------------- */

/* Light ink on a dark ground renders optically thinner than dark ink on a
 * light ground at the same nominal weight. The variable font lets us pay
 * that back with a fractional bump. This has to land on `body`, because
 * global styles set `body { font-weight: 400 }`,
 * which would otherwise beat an inherited value from the root. */

@media (prefers-color-scheme: dark) {
	html:root:not([data-vz-scheme="light"]) body {
		font-weight: 420;
	}
}

html:root[data-vz-scheme="dark"] body {
	font-weight: 420;
}


/* --- 42. Colour-scheme toggle ------------------------------------------ */

/* A two-state control in the utility bar. It is a real <button> with
 * `aria-pressed`, so screen readers announce the state, and it keeps
 * working (as an inert label) if JavaScript never loads - the OS
 * preference already drives section 41 on its own. */

.vz-scheme {
	display: inline-flex;
	align-items: center;
}

.vz-scheme__toggle {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.375rem;
	min-width: 44px;
	min-height: 32px;
	padding: 0.25rem 0.5rem;
	border: 1px solid color-mix(in srgb, currentColor 34%, transparent);
	border-radius: var(--wp--custom--radius--control);
	background: transparent;
	color: inherit;
	font-family: inherit;
	font-size: var(--wp--preset--font-size--x-small);
	font-weight: 600;
	letter-spacing: var(--wp--custom--typography--letter-spacing--wide);
	text-transform: uppercase;
	cursor: pointer;
	transition: background-color var(--wp--custom--transition--fast),
				border-color var(--wp--custom--transition--fast);
}

.vz-scheme__toggle:hover {
	background: color-mix(in srgb, currentColor 12%, transparent);
	border-color: color-mix(in srgb, currentColor 52%, transparent);
}

.vz-scheme__toggle:focus-visible {
	outline: var(--wp--custom--focus-ring--width) solid var(--wp--preset--color--focus);
	outline-offset: var(--wp--custom--focus-ring--offset);
}

.vz-scheme__icon {
	display: block;
	width: 15px;
	height: 15px;
	flex: none;
}

/* Only one of the two glyphs is ever shown: the sun advertises the
 * action available in dark, the moon the action available in light.
 * `aria-pressed` is the single source of truth for which. */
.vz-scheme__toggle .vz-scheme__icon--sun {
	display: none;
}

.vz-scheme__toggle[aria-pressed="true"] .vz-scheme__icon--sun {
	display: block;
}

.vz-scheme__toggle[aria-pressed="true"] .vz-scheme__icon--moon {
	display: none;
}

.vz-scheme__label {
	display: none;
}

@media (min-width: 600px) {
	.vz-scheme__label {
		display: block;
	}
}

/* The toggle is scripted; hide it until the script says otherwise so
 * nobody is offered a control that cannot act. */
.vz-scheme[hidden] {
	display: none;
}


/* --- 43. Sticky conversion bar ----------------------------------------- */

/* One global, dismissible bar that appears after the visitor has read
 * enough to have a question (scroll depth is set in assets/js/vorezan.js).
 * It carries exactly two actions - the commitment one and the low-cost
 * one - because a third choice measurably slows the decision. */

.vz-cta-sticky {
	position: fixed;
	z-index: 60;
	inset-inline: 0;
	bottom: 0;
	display: flex;
	justify-content: center;
	padding: 0.625rem var(--wp--custom--layout--gutter);
	padding-bottom: max(0.625rem, env(safe-area-inset-bottom));
	background: var(--wp--preset--color--base);
	border-top: 1px solid var(--wp--preset--color--outline);
	box-shadow: var(--wp--preset--shadow--dropdown);
	/* Hidden by default: the script adds `is-visible`. */
	visibility: hidden;
	opacity: 0;
	transform: translateY(100%);
	transition: opacity var(--wp--custom--transition--base),
				transform var(--wp--custom--transition--base),
				visibility var(--wp--custom--transition--base);
}

@supports (backdrop-filter: blur(1px)) {
	.vz-cta-sticky {
		background: var(--vz-header-scrim);
		backdrop-filter: blur(var(--wp--custom--depth--blur)) saturate(1.4);
	}
}

.vz-cta-sticky.is-visible {
	visibility: visible;
	opacity: 1;
	transform: translateY(0);
}

.vz-cta-sticky[hidden] {
	display: none;
}

.vz-cta-sticky__inner {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.5rem 1rem;
	inline-size: 100%;
	max-inline-size: var(--wp--custom--layout--wide);
}

.vz-cta-sticky__text {
	flex: 1 1 12rem;
	min-inline-size: 0;
	margin: 0;
	font-size: var(--wp--preset--font-size--small);
	line-height: 1.4;
	color: var(--wp--preset--color--contrast);
}

.vz-cta-sticky__text strong {
	display: block;
	font-weight: 600;
}

.vz-cta-sticky__hint {
	display: block;
	color: var(--wp--preset--color--contrast-muted);
	font-size: var(--wp--preset--font-size--x-small);
}

.vz-cta-sticky__actions {
	display: flex;
	flex: 0 0 auto;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.5rem;
}

/* Dismiss is deliberately quiet but a full touch target: an
 * undismissable bar reads as a trap and costs trust. */
.vz-cta-sticky__close {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	inline-size: 36px;
	block-size: 36px;
	flex: none;
	padding: 0;
	border: 1px solid transparent;
	border-radius: var(--wp--custom--radius--control);
	background: transparent;
	color: var(--wp--preset--color--contrast-muted);
	cursor: pointer;
	transition: background-color var(--wp--custom--transition--fast),
				color var(--wp--custom--transition--fast);
}

.vz-cta-sticky__close:hover {
	background: var(--wp--preset--color--surface-accent);
	color: var(--wp--preset--color--contrast);
}

.vz-cta-sticky__close:focus-visible {
	outline: var(--wp--custom--focus-ring--width) solid var(--wp--preset--color--focus);
	outline-offset: var(--wp--custom--focus-ring--offset);
}

/* Phones get the actions on their own full-width row: two 48px targets
 * side by side beat one wide button plus a cramped secondary. */
@media (max-width: 599px) {
	.vz-cta-sticky__text {
		flex-basis: 100%;
	}

	.vz-cta-sticky__hint {
		display: none;
	}

	.vz-cta-sticky__actions {
		flex: 1 1 100%;
	}

	.vz-cta-sticky__actions > .wp-block-buttons,
	.vz-cta-sticky__actions > .vz-btn {
		flex: 1 1 0;
	}

	.vz-cta-sticky__actions .wp-block-button {
		flex: 1 1 0;
	}

	.vz-cta-sticky__actions .wp-element-button,
	.vz-cta-sticky__actions .vz-btn {
		inline-size: 100%;
		justify-content: center;
	}
}

@media (prefers-reduced-motion: reduce) {
	.vz-cta-sticky {
		transition: none;
		transform: none;
	}
}

/* Keep the bar from covering the last line of the page. The script sets
 * `--vz-cta-sticky-h` from the measured height once the bar is shown. */
html:root {
	--vz-cta-sticky-h: 0px;
}

/* The footer group carries an inline `padding-bottom` from its block
 * attributes, and an inline style always beats a stylesheet rule, so the
 * reserved strip has to live on `body` instead. The bar is opaque and
 * exactly `--vz-cta-sticky-h` tall, so it covers the reserved strip and
 * the last line of the footer stays readable. Both the class and the
 * custom property are toggled together by the script, which means the
 * strip disappears again the moment the bar is hidden or dismissed. */
body.vz-has-sticky-cta {
	padding-block-end: var(--vz-cta-sticky-h);
}

/* Anchors and skip links must not land underneath the bar either. */
html:root {
	scroll-padding-block-end: calc(var(--vz-cta-sticky-h) + 1rem);
}


/* --- 44. Conversion components ----------------------------------------- */

/* 44.1 Trust bar --------------------------------------------------------
 * A proof strip that sits directly under the hero, above the fold. Four
 * short claims, no imagery: it answers "can I rely on this?" before the
 * visitor has to ask, which is what makes the first CTA credible. */

.vz-trustbar {
	display: grid;
	/* Fixed 1 / 2 / 4 steps rather than auto-fit. auto-fit would drop the fourth
	 * claim onto a row of its own at mid widths, and a trust bar with one orphan
	 * cell reads as broken layout, which costs more trust than it buys. */
	grid-template-columns: 1fr;
	gap: 1px;
	margin: 0;
	padding: 0;
	list-style: none;
	background: var(--wp--preset--color--outline);
	border: 1px solid var(--wp--preset--color--outline);
	border-radius: var(--wp--custom--radius--md);
	overflow: hidden;
}

@media (min-width: 37.5em) {
	.vz-trustbar {
		grid-template-columns: repeat(2, 1fr);
	}
}

@media (min-width: 62em) {
	.vz-trustbar {
		grid-template-columns: repeat(4, 1fr);
	}
}

.vz-trustbar__item {
	display: flex;
	align-items: flex-start;
	gap: 0.625rem;
	margin: 0;
	padding: 1rem 1.125rem;
	background: var(--wp--preset--color--base);
}

.vz-trustbar__icon {
	flex: none;
	display: block;
	inline-size: 20px;
	block-size: 20px;
	margin-block-start: 0.0625rem;
	color: var(--wp--preset--color--primary);
}

.vz-trustbar__value {
	display: block;
	/* medium, not large: the claim is supporting evidence for the hero, so it must
	 * not read as a second page heading and pull the eye off the primary action. */
	font-size: var(--wp--preset--font-size--medium);
	font-weight: 700;
	line-height: 1.1;
	letter-spacing: var(--wp--custom--typography--letter-spacing--heading);
	color: var(--wp--preset--color--contrast);
}

.vz-trustbar__label {
	display: block;
	margin-block-start: 0.125rem;
	font-size: var(--wp--preset--font-size--x-small);
	line-height: 1.35;
	color: var(--wp--preset--color--contrast-muted);
}

/* 44.2 Next best action ------------------------------------------------
 * Closes a section instead of the whole page. Peak-End: every reading
 * unit ends on a useful move rather than trailing off. */

.vz-nba {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.75rem 1.25rem;
	margin-block: var(--wp--custom--rhythm--3);
	padding: 1.125rem 1.25rem;
	background: var(--wp--preset--color--surface-accent);
	border: 1px solid var(--vz-outline-soft, var(--wp--preset--color--outline));
	border-inline-start: 3px solid var(--wp--preset--color--primary);
	border-radius: var(--wp--custom--radius--md);
}

.vz-nba__body {
	flex: 1 1 16rem;
	min-inline-size: 0;
}

.vz-nba__label {
	display: block;
	margin: 0 0 0.125rem;
	font-size: var(--wp--preset--font-size--x-small);
	font-weight: 600;
	letter-spacing: var(--wp--custom--typography--letter-spacing--wide);
	text-transform: uppercase;
	/* primary-light against surface-accent measures 3.82:1 in the default scheme and
	 * 4.37:1 in dark - both under SC 1.4.3 for this size. primary-dark clears it in
	 * every shipped scheme (6.55 to 9.18:1). */
	color: var(--wp--preset--color--primary-dark);
}

.vz-nba__title {
	margin: 0;
	font-size: var(--wp--preset--font-size--medium);
	font-weight: 600;
	line-height: 1.35;
	color: var(--wp--preset--color--contrast);
}

.vz-nba__hint {
	margin: 0.25rem 0 0;
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--contrast-muted);
}

.vz-nba__actions {
	flex: 0 0 auto;
}

/* 44.3 Card quick actions ----------------------------------------------
 * Two zero-commitment moves on the card itself, so a decision does not
 * require a page load. They sit after the card link so the title stays
 * the primary target for keyboard users. */

.vz-quickactions {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.375rem;
	margin-block-start: auto;
	padding-block-start: 0.75rem;
	border-block-start: 1px solid var(--vz-outline-soft, var(--wp--preset--color--outline));
}

.vz-quickaction {
	display: inline-flex;
	align-items: center;
	gap: 0.375rem;
	min-height: 36px;
	padding: 0.3125rem 0.625rem;
	border: 1px solid var(--wp--preset--color--outline);
	border-radius: var(--wp--custom--radius--sm);
	background: var(--wp--preset--color--base);
	color: var(--wp--preset--color--contrast-muted);
	font-size: var(--wp--preset--font-size--x-small);
	font-weight: 600;
	line-height: 1.2;
	text-decoration: none;
	cursor: pointer;
	transition: color var(--wp--custom--transition--fast),
				background-color var(--wp--custom--transition--fast),
				border-color var(--wp--custom--transition--fast);
}

.vz-quickaction:hover,
.vz-quickaction:focus-visible {
	color: var(--wp--preset--color--primary-dark);
	background: var(--wp--preset--color--surface-accent);
	border-color: var(--wp--preset--color--outline-strong);
}

.vz-quickaction:focus-visible {
	outline: var(--wp--custom--focus-ring--width) solid var(--wp--preset--color--focus);
	outline-offset: var(--wp--custom--focus-ring--offset);
}

.vz-quickaction__icon {
	flex: none;
	display: block;
	inline-size: 14px;
	block-size: 14px;
}

/* Saved is a toggle, so it reports state rather than just changing
 * colour: `aria-pressed` carries it for assistive tech, the fill
 * carries it visually. */
.vz-quickaction[aria-pressed="true"] {
	/* White on primary-light is 4.37:1 - short of AA for this x-small 600
	 * label. primary-dark carries the same "on" signal at 7.48:1. */
	color: var(--wp--custom--on-brand);
	background: var(--wp--preset--color--primary-dark);
	border-color: var(--wp--preset--color--primary-dark);
}

.vz-quickaction[aria-pressed="true"] .vz-quickaction__icon {
	fill: currentColor;
}

/* 44.4 Progressive disclosure on cards ---------------------------------
 * The card shows two lines; the rest is one keystroke away. Cognitive
 * Load Theory: a scannable grid beats a complete one. */

.vz-card__excerpt--clamp {
	display: -webkit-box;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 2;
	line-clamp: 2;
	overflow: hidden;
}

.vz-card__more {
	display: inline-flex;
	align-items: center;
	gap: 0.25rem;
	margin-block-start: 0.375rem;
	font-size: var(--wp--preset--font-size--x-small);
	font-weight: 600;
	color: var(--wp--preset--color--primary-dark);
	text-decoration: none;
}

.vz-card:hover .vz-card__more,
.vz-card:focus-within .vz-card__more {
	text-decoration: underline;
	text-underline-offset: var(--wp--custom--link--underline-offset);
}

/* 44.5 Sticky filter rail ----------------------------------------------
 * Archive search and facets stay reachable while the grid scrolls, so
 * refining never costs a scroll back to the top. */

.vz-filterbar {
	position: sticky;
	top: 0;
	z-index: 20;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.5rem 0.75rem;
	padding-block: 0.75rem;
	background: var(--wp--preset--color--base);
	border-block-end: 1px solid var(--wp--preset--color--outline);
}

@supports (backdrop-filter: blur(1px)) {
	.vz-filterbar {
		background: var(--vz-header-scrim);
		backdrop-filter: blur(var(--wp--custom--depth--blur)) saturate(1.4);
	}
}

.vz-filterbar > * {
	margin-block: 0;
}

.vz-filterbar__grow {
	flex: 1 1 14rem;
	min-inline-size: 0;
}

.vz-filterbar__count {
	flex: none;
	font-size: var(--wp--preset--font-size--x-small);
	color: var(--wp--preset--color--contrast-muted);
	font-variant-numeric: tabular-nums;
}

/* 44.6 Help block -----------------------------------------------------
 * "Cannot find it?" belongs where the dead end actually happens: the end
 * of an archive, an empty search, a 404 - not only in the footer. */

.vz-help {
	display: grid;
	gap: 0.75rem;
	padding: clamp(1.25rem, 3vw, 2rem);
	text-align: center;
	background: var(--wp--preset--color--surface-accent);
	border: 1px dashed var(--wp--preset--color--outline-strong);
	border-radius: var(--wp--custom--radius--lg);
}

.vz-help__title {
	margin: 0;
	font-size: var(--wp--preset--font-size--x-large);
	font-weight: 700;
	line-height: 1.2;
	letter-spacing: var(--wp--custom--typography--letter-spacing--heading);
	color: var(--wp--preset--color--contrast);
}

.vz-help__text {
	margin: 0 auto;
	max-inline-size: 52ch;
	color: var(--wp--preset--color--contrast-muted);
}

.vz-help__actions {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	justify-content: center;
}

/* --- 45. Scheme-safe ink ---------------------------------------------- */

/* Closing the findings of tools/audit_contrast_dom.py, which measures
 * rendered contrast in the real DOM once per colour scheme.
 *
 * The palette itself is sound in both schemes - the static token gate
 * proves that. What failed was markup and CSS naming a GROUND colour
 * where an INK colour was meant. `deep` and `base` are the two ends of
 * the page ground: they both go dark in the dark scheme, so either one
 * used as text lands at about 1.07:1.
 *
 * Six declarations were rewritten in place (deep -> contrast, see
 * sections 21 and 27) and three block attributes were dropped. What is
 * left is the top bar, whose ink cannot come from a palette slug at all:
 * it is always light, because its ground is always `deep`. That is
 * exactly the intent `--wp--custom--on-dark` encodes. */

.vz-topbar {
	color: var(--wp--custom--on-dark);
}

/* Secondary items on the bar step back without dropping below 4.5:1.
 * Measured on `deep`: 9.11:1 in light, 11.03:1 in dark. */
.vz-topbar__meta,
.vz-topbar .vz-trust__item:not(.vz-trust__item--claim) {
	color: var(--wp--custom--on-dark-muted);
}

/* House rule, for anyone extending the theme: `base` and `deep` are
 * grounds, never ink. Use `contrast` for strongest ink on a light
 * surface, `--wp--custom--on-dark` for light ink on a dark fill, and
 * `--wp--custom--on-brand` for ink on a primary fill. All three flip
 * with the scheme; the two palette slugs do not. */
/* --- 46. Saved shortlist and card read-more --- */

/*
 * Two loose ends of the architecture work, both of them conversion paths
 * rather than decoration:
 *
 *   1. The card read-more. Core's post-excerpt block emits its own more link,
 *      so the theme styles that class instead of inventing a second one. A
 *      clamped excerpt plus one explicit affordance scans faster than a full
 *      paragraph (Cognitive Load Theory) and gives the card a second, larger
 *      target for touch.
 *   2. The saved shortlist. It is a browser-local list, so it cannot be
 *      rendered on the server; assets/js/vorezan.js paints it into the
 *      `vorezan/cro-saved-list` pattern. The styles below therefore have to
 *      hold for both the empty state in the markup and the injected list.
 *
 * Commitment and Consistency: once a buyer has saved three products they have
 * already invested in the decision, and the shortlist page turns that into a
 * single inquiry instead of three separate ones.
 */

/* 46.1 Read-more on cards ----------------------------------------------- */

.vz-card .wp-block-post-excerpt__more-link,
.vz-card__more {
	display: inline-flex;
	align-items: center;
	gap: 0.25rem;
	margin-block-start: 0.375rem;
	font-size: var(--wp--preset--font-size--x-small);
	font-weight: 600;
	color: var(--wp--preset--color--primary-dark);
	text-decoration: none;
}

/* The card title is already the primary link, so the more link stays quiet
 * until the card is engaged. It is never the only affordance, which keeps it
 * clear of SC 1.4.1 (colour is not the sole carrier of meaning). */
.vz-card:hover .wp-block-post-excerpt__more-link,
.vz-card:focus-within .wp-block-post-excerpt__more-link {
	text-decoration: underline;
	text-underline-offset: var(--wp--custom--link--underline-offset);
}

/* Core prints the more link inline after the excerpt text. On a card it reads
 * as a separate action, so it gets its own line. */
.vz-card .wp-block-post-excerpt__excerpt {
	display: block;
}

.vz-card .wp-block-post-excerpt__more-link {
	display: block;
	width: fit-content;
}

/* Clamping the post-excerpt wrapper (what `.vz-clamp-3` does) would hide the
 * more link along with the overflowing text, because the link is a sibling
 * paragraph inside the same block. `.vz-card__excerpt` therefore clamps the
 * excerpt paragraph only and leaves the affordance visible. */
.vz-card__excerpt .wp-block-post-excerpt__excerpt {
	display: -webkit-box;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 3;
	line-clamp: 3;
	overflow: hidden;
}

.vz-card__excerpt .wp-block-post-excerpt__more-text {
	margin-block: 0.375rem 0;
}

/* 46.2 Saved shortlist -------------------------------------------------- */

.vz-saved {
	padding: var(--wp--preset--spacing--50);
	border: 1px solid var(--wp--preset--color--outline);
	border-radius: var(--wp--custom--radius--lg);
	background: var(--wp--preset--color--base);
}

.vz-saved__empty {
	margin: 0;
	max-width: 60ch;
}

.vz-savedlist {
	margin: 0;
	padding: 0;
	list-style: none;
	display: grid;
	gap: 1px;
	background: var(--vz-outline-soft, var(--wp--preset--color--outline));
}

.vz-savedlist__item {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 0.75rem;
	padding: 0.875rem 0;
	background: var(--wp--preset--color--base);
}

.vz-savedlist__link {
	flex: 1 1 16rem;
	color: var(--wp--preset--color--contrast);
	font-weight: 600;
	text-decoration: none;
}

.vz-savedlist__link:hover,
.vz-savedlist__link:focus-visible {
	color: var(--wp--custom--link--hover);
	text-decoration: underline;
	text-decoration-thickness: var(--wp--custom--link--underline-thickness);
	text-underline-offset: var(--wp--custom--link--underline-offset);
}

/* Destructive action, so it is deliberately the smaller target of the pair
 * while still clearing the 44px minimum. */
.vz-savedlist__remove {
	flex: none;
	min-height: var(--wp--custom--control--height);
	padding: 0.375rem 0.75rem;
	border: 1px solid var(--wp--preset--color--outline);
	border-radius: var(--wp--custom--radius--sm);
	background: transparent;
	color: var(--wp--preset--color--contrast-muted);
	font-size: var(--wp--preset--font-size--x-small);
	font-weight: 600;
	cursor: pointer;
	transition: color var(--wp--custom--transition--fast),
				border-color var(--wp--custom--transition--fast);
}

.vz-savedlist__remove:hover,
.vz-savedlist__remove:focus-visible {
	color: var(--wp--preset--color--contrast);
	border-color: var(--wp--preset--color--outline-strong);
}

.vz-savedlist__remove:focus-visible {
	outline: var(--wp--custom--focus-ring--width) solid var(--wp--preset--color--focus);
	outline-offset: var(--wp--custom--focus-ring--offset);
}

@media (max-width: 30em) {
	.vz-savedlist__item {
		flex-direction: column;
		align-items: flex-start;
	}
}

/* --- 47. Audit corrections (1.6.0) ----------------------------------- */

/* 47.1 Skip link -------------------------------------------------------
 * The header is three tiers of navigation before the first word of the
 * page, so keyboard and screen-reader users need a way past it (WCAG
 * 2.4.1). `.screen-reader-text:focus` already supplies the visible
 * treatment; the link only needs to escape any scrolled offset, which
 * absolute positioning cannot guarantee once the page has moved. */
.vz-skip-link:focus {
	position: fixed;
}

/* 47.2 Sticky CTA versus the mobile navigation overlay -----------------
 * `.vz-cta-sticky` is fixed at z-index 60, and `.vz-navbar` opens its own
 * stacking context at z-index 30/40, so core's overlay - z-index 100000
 * *inside* that context - still painted underneath the bar. Core marks the
 * body while the overlay is open, which is the only reliable hook. */
body.has-modal-open .vz-cta-sticky {
	display: none;
}

/* 47.3 Keyboard access to the scrolling table frames -------------------
 * A wrapper that scrolls has to be focusable or a keyboard-only user
 * cannot reach the overflowing columns (WCAG 2.1.1). The outline is
 * suppressed unless the focus actually came from the keyboard. */
@media (max-width: 781px) {
	.vz-tables:focus-visible {
		outline: var(--wp--custom--focus-ring--width) solid var(--wp--preset--color--focus);
		outline-offset: var(--wp--custom--focus-ring--offset);
	}
}
