/**
 * Provatic interactive template components — pure CSS (no JS, no security surface).
 * Each component's markup (emitted by Template_Importer) uses a `.pv-cmp-<key>`
 * scoped class; the customer edits the content, the interaction lives here.
 * Colors/spacing use Canvas theme.json presets so components inherit the palette.
 *
 * Grow this file when adding a component (see the canvas-templates skill).
 */

/* Shared motion tokens — a calm ease-out (no bounce/elastic), transform/opacity
   only so interactions stay off the layout/paint path. */
:root {
	--pv-ease-out: cubic-bezier(.22, 1, .36, 1);
	--pv-reveal-dur: .7s;

	/* The one content width, so a component band lines up with the header and footer
	   above and below it. These were 1140 while Header_Part_Writer::CONTENT_WIDTH and
	   the footer writer both use 1120, which put every component band 20px wider than
	   the chrome it sits between — visible as a hairline misalignment down the page.
	   Written once here because the same number was repeated in five places and one of
	   them was simply missing, which is how post-list ended up running edge to edge. */
	--pv-content-width: 1120px;

	/* Component typography, as three ROLES rather than three typefaces.
	 *
	 * Every component used to name `serif-display` and `space-mono` directly — twenty
	 * declarations between them — so an accordion or a marquee arrived in the same two
	 * faces no matter which template it was in. A template could restyle its own
	 * sections and then hit a component that quietly ignored its typography. That is a
	 * real part of why the catalogue reads as one designer.
	 *
	 * A template overrides whichever role it cares about; unset, each falls through to
	 * the same face it always used, so nothing published changes appearance:
	 *
	 *   .my-band { --pv-cmp-display: var(--wp--preset--font-family--archivo); }
	 *
	 * display — component headings and oversized display text (was serif-display)
	 * label   — eyebrows, numbers, meta, uppercase micro-labels (was space-mono)
	 * body    — component body/title copy (was grotesk)
	 *
	 * Deliberately NOT defined here: an unset custom property falls back to the second
	 * argument of its own var(), which keeps the historical face. Defining them at
	 * :root would make every template inherit one answer again. */
}

/* ── marquee-hero — auto-scrolling row of words (seamless loop) ───────────── */
.pv-cmp-marquee {
	overflow: hidden;
	border-block: 1px solid var(--wp--preset--color--border, #e4e4e7);
	padding-block: var(--wp--preset--spacing--30, 1rem);
}
.pv-cmp-marquee__track {
	display: inline-flex;
	align-items: center;
	gap: 2.5rem;
	white-space: nowrap;
	will-change: transform;
	animation: pv-marquee var(--pv-marquee-speed, 30s) linear infinite;
}
.pv-cmp-marquee:hover .pv-cmp-marquee__track { animation-play-state: paused; }
.pv-cmp-marquee__item {
	font-family: var(--pv-cmp-display, var(--wp--preset--font-family--serif-display, Georgia, serif));
	font-size: clamp(1.25rem, 3.4vw, 1.75rem);
	color: var(--wp--preset--color--contrast-3, #78766e);
	font-weight: 400;
}
.pv-cmp-marquee__sep {
	color: var(--wp--preset--color--border, #cbc9c1);
	font-size: clamp(1.25rem, 3.4vw, 1.75rem);
}
@keyframes pv-marquee {
	from { transform: translateX(0); }
	to   { transform: translateX(-50%); }
}

/* ── hover-index-list — numbered rows, faded big number reveals on hover ──── */
.pv-cmp-index { border-top: 1px solid var(--wp--preset--color--border, #e4e4e7); }
.pv-cmp-index__row {
	position: relative;
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 1.5rem;
	padding-block: var(--wp--preset--spacing--50, 2rem);
	border-bottom: 1px solid var(--wp--preset--color--border, #e4e4e7);
	overflow: hidden;
	text-decoration: none;
	color: inherit;
}
.pv-cmp-index__ghost {
	position: absolute;
	right: 0;
	top: 50%;
	transform: translateY(-50%);
	font-size: 6rem;
	font-weight: 700;
	line-height: 1;
	color: var(--wp--preset--color--base-3, #f4f4f5);
	opacity: 0;
	transition: opacity .25s ease;
	pointer-events: none;
	z-index: 0;
	margin: 0;
}
.pv-cmp-index__row:hover .pv-cmp-index__ghost { opacity: 1; }
.pv-cmp-index__row > :not(.pv-cmp-index__ghost) { position: relative; z-index: 1; }
.pv-cmp-index__num {
	font-size: var(--wp--preset--font-size--small, 0.9rem);
	color: var(--wp--preset--color--contrast-3, #71717a);
	min-width: 2.5rem;
	flex: 0 0 auto;
}
.pv-cmp-index__title {
	font-size: var(--wp--preset--font-size--x-large, 2rem);
	color: var(--wp--preset--color--contrast, #18181b);
	font-weight: 600;
	letter-spacing: -0.015em;
	flex: 1 1 auto;
	margin: 0;
}
.pv-cmp-index__meta {
	font-size: var(--wp--preset--font-size--small, 0.9rem);
	color: var(--wp--preset--color--contrast-2, #52525b);
}
.pv-cmp-index__year {
	font-size: var(--wp--preset--font-size--small, 0.9rem);
	color: var(--wp--preset--color--contrast-3, #71717a);
	flex: 0 0 auto;
}

/* ── globe (data-pv-globe, powered by header-extras.js) ────────────────────
   A globe of the real continents that turns on its own and can be dragged. The land is
   a bitmask of Natural Earth's 110m outline baked into the script; the canvas projects
   it orthographically each frame, so it is a genuine sphere — the dots crowd and vanish
   round the limb because they are going round the back, not because a gradient says so.

   Markup (a section may write this by hand; the behaviour binds to the attribute):
     <div class="pv-globe" data-pv-globe data-pv-globe-speed="26" data-pv-globe-lat="37.57" data-pv-globe-lon="126.98">
       <div class="pv-globe__map"></div>
     </div>
   The optional lat/lon marks a place: it is a real point ON the sphere, so it turns with
   the globe and goes round the back, which is the honest behaviour for a marker.

   `.pv-globe__map` is the NO-JS fallback only — a plain turning dot grid. When the
   script binds it inserts a canvas, hides the map, and owns the motion from there. An
   earlier version drew the whole globe in CSS with one background layer per latitude;
   it could fake the crowding at the poles but never the continents, so canvas replaced
   it and the elaborate CSS went with it.

   Every colour is a token so a template can theme it per light/dark mode without
   touching this file.

   It is pointer-only on purpose. The globe carries no information — the place is in the
   heading next to it — so it is decoration that rewards a drag, not a control. A
   focusable widget that only a mouse can operate would be the worse choice. */
.pv-globe {
	position: relative;
	width: 100%;
	max-width: var(--pv-globe-size, 240px);
	aspect-ratio: 1;
	margin-inline: auto;
	border-radius: 50%;
	overflow: hidden;
	background: var(--pv-globe-bg, #eeedf8);
	box-shadow:
		inset -22px -26px 48px var(--pv-globe-shade, rgba(0, 0, 0, .26)),
		inset 14px 16px 30px var(--pv-globe-sheen, rgba(255, 255, 255, .55));
	/* Vertical page scroll still wins on touch; only sideways drag turns the globe. */
	touch-action: pan-y;
	cursor: grab;
	user-select: none;
	-webkit-user-select: none;
}
.pv-globe.is-dragging { cursor: grabbing; }
.pv-globe__canvas {
	position: absolute;
	inset: 0;
	display: block;
	width: 100%;
	height: 100%;
}
.pv-globe__map {
	position: absolute;
	inset: 0;
	background-image: radial-gradient(circle, var(--pv-globe-dot, rgba(90, 60, 220, .62)) 1.2px, transparent 1.75px);
	background-size: 13px 13px;
	animation: pv-globe-spin var(--pv-globe-speed, 26s) linear infinite;
}
.pv-globe.is-live .pv-globe__map { display: none; }
.pv-globe::after {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: 50%;
	pointer-events: none;
	/* A bright rim so the edge catches light, the limb falling away into shadow, and a
	   highlight on the shoulder the light comes from. */
	background:
		radial-gradient(circle at 50% 50%, transparent 0 95%, var(--pv-globe-rim, rgba(255, 255, 255, .6)) 97%, transparent 100%),
		radial-gradient(circle at 38% 32%, transparent 0 30%, var(--pv-globe-limb, rgba(0, 0, 0, .16)) 76%, var(--pv-globe-limb-edge, rgba(0, 0, 0, .5)) 100%),
		radial-gradient(circle at 32% 24%, var(--pv-globe-glow, rgba(255, 255, 255, .6)) 0%, transparent 44%);
}
/* 260px = 20 cells of the fallback grid, so its loop closes and never steps. */
@keyframes pv-globe-spin {
	from { background-position-x: 0; }
	to   { background-position-x: -260px; }
}
@media (prefers-reduced-motion: reduce) {
	/* Nothing drifts unasked. A drag still turns it — that motion is the visitor's. */
	.pv-globe__map { animation: none; }
}

/* ── header live clock (data-pv-clock, powered by header-extras.js) ────────── */
.pv-header-clock {
	font-family: var(--pv-cmp-label, var(--wp--preset--font-family--space-mono, monospace));
	font-size: 0.72rem;
	letter-spacing: 0.14em;
	color: var(--wp--preset--color--contrast-3, #78766e);
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
}
@media (max-width: 781px) {
	.pv-header-clock { display: none; }
}

/* ── accordion-list — click a row to reveal its detail panel (Interactivity) ── */
.pv-cmp-accordion {
	max-width: var(--pv-content-width);
	margin-inline: auto;
	padding-inline: var(--wp--preset--spacing--40, 1.5rem);
	border-top: 1px solid var(--wp--preset--color--border, #e4e4e7);
}
.pv-cmp-accordion__row { border-bottom: 1px solid var(--wp--preset--color--border, #e4e4e7); }
.pv-cmp-accordion__head {
	width: 100%;
	background: none;
	border: 0;
	cursor: pointer;
	text-align: left;
	display: flex;
	align-items: baseline;
	gap: 1.5rem;
	padding-block: var(--wp--preset--spacing--50, 2rem);
	color: inherit;
	transition: transform .3s var(--pv-ease-out, cubic-bezier(.22, 1, .36, 1));
}
.pv-cmp-accordion__head:hover { transform: translateX(.6rem); }
.pv-cmp-accordion__num {
	flex: 0 0 auto;
	min-width: 2.5rem;
	font-family: var(--pv-cmp-label, var(--wp--preset--font-family--space-mono, monospace));
	font-size: var(--wp--preset--font-size--small, .9rem);
	color: var(--wp--preset--color--contrast-3, #71717a);
}
.pv-cmp-accordion__title {
	flex: 1 1 auto;
	font-family: var(--pv-cmp-body, var(--wp--preset--font-family--grotesk, sans-serif));
	font-size: var(--wp--preset--font-size--large, 1.375rem);
	font-weight: 500;
	color: var(--wp--preset--color--contrast, #18181b);
}
.pv-cmp-accordion__tags,
.pv-cmp-accordion__year {
	flex: 0 0 auto;
	font-family: var(--pv-cmp-label, var(--wp--preset--font-family--space-mono, monospace));
	font-size: var(--wp--preset--font-size--small, .9rem);
	color: var(--wp--preset--color--contrast-3, #71717a);
}
.pv-cmp-accordion__tags { letter-spacing: .06em; text-transform: uppercase; }
.pv-cmp-accordion__marker { flex: 0 0 auto; position: relative; width: 1rem; height: 1rem; align-self: center; }
.pv-cmp-accordion__marker::before,
.pv-cmp-accordion__marker::after {
	content: "";
	position: absolute;
	top: 50%;
	left: 50%;
	translate: -50% -50%;
	background: var(--wp--preset--color--contrast, #18181b);
	transition: opacity .3s ease;
}
.pv-cmp-accordion__marker::before { width: 1rem; height: 1px; }
.pv-cmp-accordion__marker::after { width: 1px; height: 1rem; }
.pv-cmp-accordion__row.is-open .pv-cmp-accordion__marker::after { opacity: 0; }
.pv-cmp-accordion__panel {
	display: grid;
	grid-template-rows: 0fr;
	transition: grid-template-rows .4s cubic-bezier(.16, 1, .3, 1);
}
.pv-cmp-accordion__row.is-open .pv-cmp-accordion__panel { grid-template-rows: 1fr; }
.pv-cmp-accordion__inner {
	overflow: hidden;
	/* A closed row used to render 32px of its own answer — one clipped line of body
	   text sitting under every shut question. Two separate reasons, both measured:
	   `grid-template-rows: 0fr` does not collapse a grid item on its own (the item's
	   automatic minimum size floors it at min-content), and this element's own
	   padding-bottom is outside its content box, so its own `overflow: hidden` never
	   clipped it — 32px was exactly that padding. min-height:0 fixes the first; the
	   bottom spacing moves onto the children, which ARE clipped, to fix the second.
	   Shipped the day the accordion did and stayed invisible until Foundry became the
	   first template to use the component. */
	min-height: 0;
	display: flex;
	flex-wrap: wrap;
	gap: 2.5rem;
}
.pv-cmp-accordion__body { flex: 1 1 420px; padding-bottom: var(--wp--preset--spacing--50, 2rem); }
.pv-cmp-accordion__side { flex: 0 1 300px; padding-bottom: var(--wp--preset--spacing--50, 2rem); }
.pv-cmp-accordion__p { margin: 0 0 1rem; color: var(--wp--preset--color--contrast-2, #52525b); line-height: 1.6; }
.pv-cmp-accordion__side-label {
	display: block;
	margin-bottom: .75rem;
	font-family: var(--pv-cmp-label, var(--wp--preset--font-family--space-mono, monospace));
	font-size: var(--wp--preset--font-size--small, .9rem);
	letter-spacing: .08em;
	text-transform: uppercase;
	color: var(--wp--preset--color--contrast-3, #71717a);
}
.pv-cmp-accordion__list { list-style: none; margin: 0; padding: 0; }
.pv-cmp-accordion__list li {
	padding-block: .45rem;
	border-top: 1px solid var(--wp--preset--color--border, #e4e4e7);
	font-size: var(--wp--preset--font-size--small, .9rem);
	color: var(--wp--preset--color--contrast-2, #52525b);
}

/* ── filter-index — chip-filtered index table (Interactivity) ─────────────── */
.pv-cmp-filter {
	max-width: var(--pv-content-width);
	margin-inline: auto;
	padding-inline: var(--wp--preset--spacing--40, 1.5rem);
}
.pv-cmp-filter__chips { display: flex; flex-wrap: wrap; gap: .6rem; margin-bottom: var(--wp--preset--spacing--50, 2rem); }
.pv-cmp-filter__chip {
	font-family: var(--pv-cmp-label, var(--wp--preset--font-family--space-mono, monospace));
	font-size: var(--wp--preset--font-size--small, .9rem);
	letter-spacing: .06em;
	text-transform: uppercase;
	padding: .55rem 1.1rem;
	border-radius: 100px;
	border: 1px solid var(--wp--preset--color--border, #e4e4e7);
	background: transparent;
	color: var(--wp--preset--color--contrast-3, #71717a);
	cursor: pointer;
	transition: color .25s ease, background .25s ease, border-color .25s ease;
}
.pv-cmp-filter__chip:hover { color: var(--wp--preset--color--contrast, #18181b); border-color: var(--wp--preset--color--contrast, #18181b); }
.pv-cmp-filter__chip.is-active {
	background: var(--wp--preset--color--contrast, #18181b);
	color: var(--wp--preset--color--base, #fff);
	border-color: var(--wp--preset--color--contrast, #18181b);
}
.pv-cmp-filter__list { border-top: 1px solid var(--wp--preset--color--border, #e4e4e7); }
.pv-cmp-filter__row {
	display: flex;
	align-items: baseline;
	gap: 1.5rem;
	padding-block: var(--wp--preset--spacing--30, 1rem);
	border-bottom: 1px solid var(--wp--preset--color--border, #e4e4e7);
	transition: background .25s ease;
}
.pv-cmp-filter__row > * { transition: transform .25s var(--pv-ease-out, cubic-bezier(.22, 1, .36, 1)); }
.pv-cmp-filter__row:hover { background: var(--wp--preset--color--base-2, #fafafa); }
.pv-cmp-filter__row:hover > * { transform: translateX(.6rem); }
.pv-cmp-filter__row.is-hidden { display: none; }
.pv-cmp-filter__num {
	flex: 0 0 auto;
	min-width: 2.5rem;
	font-family: var(--pv-cmp-label, var(--wp--preset--font-family--space-mono, monospace));
	font-size: var(--wp--preset--font-size--small, .9rem);
	color: var(--wp--preset--color--contrast-3, #71717a);
}
.pv-cmp-filter__title {
	flex: 1 1 auto;
	font-family: var(--pv-cmp-body, var(--wp--preset--font-family--grotesk, sans-serif));
	font-size: var(--wp--preset--font-size--medium, 1.0625rem);
	color: var(--wp--preset--color--contrast, #18181b);
}
.pv-cmp-filter__cat {
	flex: 0 0 auto;
	font-family: var(--pv-cmp-label, var(--wp--preset--font-family--space-mono, monospace));
	font-size: var(--wp--preset--font-size--small, .9rem);
	letter-spacing: .05em;
	text-transform: uppercase;
	color: var(--wp--preset--color--contrast-3, #71717a);
}
.pv-cmp-filter__date {
	flex: 0 0 auto;
	min-width: 6rem;
	text-align: right;
	font-family: var(--pv-cmp-label, var(--wp--preset--font-family--space-mono, monospace));
	font-size: var(--wp--preset--font-size--small, .9rem);
	color: var(--wp--preset--color--contrast-3, #71717a);
}

/* ── cursor-index — clickable rows; giant ghost number follows the cursor ──── */
.pv-cmp-cursor {
	max-width: var(--pv-content-width);
	margin-inline: auto;
	padding-inline: var(--wp--preset--spacing--40, 1.5rem);
	border-top: 1px solid var(--wp--preset--color--border, #e4e4e7);
}
.pv-cmp-cursor__row {
	position: relative;
	display: flex;
	align-items: baseline;
	gap: 1.5rem;
	padding-block: var(--wp--preset--spacing--50, 2rem);
	border-bottom: 1px solid var(--wp--preset--color--border, #e4e4e7);
	overflow: hidden;
	text-decoration: none;
	color: inherit;
}
.pv-cmp-cursor__row > :not(.pv-cmp-cursor__ghost) { position: relative; z-index: 1; }
/* Slide the text content on hover (the arrow keeps its own entrance motion). */
.pv-cmp-cursor__row > :not(.pv-cmp-cursor__ghost):not(.pv-cmp-cursor__arrow) {
	transition: transform .3s var(--pv-ease-out, cubic-bezier(.22, 1, .36, 1));
}
.pv-cmp-cursor__row:hover > :not(.pv-cmp-cursor__ghost):not(.pv-cmp-cursor__arrow) { transform: translateX(1rem); }
.pv-cmp-cursor__num {
	flex: 0 0 auto;
	min-width: 3rem;
	font-family: var(--pv-cmp-label, var(--wp--preset--font-family--space-mono, monospace));
	font-size: var(--wp--preset--font-size--small, .9rem);
	color: var(--wp--preset--color--contrast-3, #71717a);
}
.pv-cmp-cursor__title {
	flex: 1 1 auto;
	font-family: var(--pv-cmp-display, var(--wp--preset--font-family--serif-display, Georgia, serif));
	font-size: var(--wp--preset--font-size--x-large, 2rem);
	color: var(--wp--preset--color--contrast, #18181b);
}
.pv-cmp-cursor__meta,
.pv-cmp-cursor__year {
	flex: 0 0 auto;
	font-family: var(--pv-cmp-label, var(--wp--preset--font-family--space-mono, monospace));
	font-size: var(--wp--preset--font-size--small, .9rem);
	color: var(--wp--preset--color--contrast-3, #71717a);
}
.pv-cmp-cursor__meta { letter-spacing: .05em; text-transform: uppercase; }
.pv-cmp-cursor__arrow {
	flex: 0 0 auto;
	opacity: 0;
	translate: -10px 0;
	transition: opacity .3s ease, translate .3s ease;
	color: var(--wp--preset--color--contrast, #18181b);
}
.pv-cmp-cursor__row:hover .pv-cmp-cursor__arrow { opacity: 1; translate: 0 0; }
.pv-cmp-cursor__ghost {
	position: absolute;
	left: 50%;
	top: 50%;
	translate: -50% -50%;
	font-family: var(--pv-cmp-display, var(--wp--preset--font-family--serif-display, Georgia, serif));
	font-weight: 400;
	font-size: clamp(5rem, 14vw, 11rem);
	line-height: 1;
	color: var(--wp--preset--color--contrast, #18181b);
	opacity: 0;
	transition: opacity .25s ease;
	pointer-events: none;
	z-index: 0;
}
.pv-cmp-cursor__row:hover .pv-cmp-cursor__ghost { opacity: .07; }
@media (hover: none) { .pv-cmp-cursor__ghost { display: none; } }

/* ── split — reusable two-column band (text + media) ──────────────────────── */
.pv-cmp-split {
	max-width: var(--pv-content-width);
	margin-inline: auto;
	padding-inline: var(--wp--preset--spacing--40, 1.5rem);
	padding-block: var(--wp--preset--spacing--80, 5rem);
	display: grid;
	grid-template-columns: 1.1fr 0.9fr;
	gap: 3.5rem;
	align-items: start;
}
.pv-cmp-split--reverse .pv-cmp-split__col--media { order: -1; }
.pv-cmp-split__eyebrow {
	margin: 0;
	font-family: var(--pv-cmp-label, var(--wp--preset--font-family--space-mono, monospace));
	font-size: var(--wp--preset--font-size--small, .9rem);
	letter-spacing: .08em;
	text-transform: uppercase;
	color: var(--wp--preset--color--contrast-3, #78766e);
}
.pv-cmp-split__eyebrow--right { text-align: right; }
.pv-cmp-split__kicker {
	margin: 1.75rem 0 0;
	font-family: var(--pv-cmp-label, var(--wp--preset--font-family--space-mono, monospace));
	font-size: var(--wp--preset--font-size--small, .9rem);
	letter-spacing: .12em;
	text-transform: uppercase;
	color: var(--wp--preset--color--contrast-2, #4a4a4e);
}
.pv-cmp-split__heading {
	margin: .5rem 0 0;
	font-family: var(--pv-cmp-display, var(--wp--preset--font-family--serif-display, Georgia, serif));
	font-weight: 400;
	font-size: clamp(3.5rem, 10vw, 8.5rem);
	line-height: .9;
	letter-spacing: -.02em;
	color: var(--wp--preset--color--contrast, #1a1a1e);
}
.pv-cmp-split__heading em { font-style: italic; }
.pv-cmp-split__lead {
	max-width: 34rem;
	margin: 1.75rem 0 0;
	font-size: var(--wp--preset--font-size--large, 1.375rem);
	line-height: 1.5;
	color: var(--wp--preset--color--contrast-2, #4a4a4e);
}
.pv-cmp-split__cta { display: flex; gap: 1rem; flex-wrap: wrap; margin-top: 2rem; }
.pv-cmp-split__btn {
	display: inline-block;
	padding: .85rem 1.6rem;
	border-radius: 100px;
	font-family: var(--pv-cmp-label, var(--wp--preset--font-family--space-mono, monospace));
	font-size: var(--wp--preset--font-size--small, .9rem);
	letter-spacing: .04em;
	text-transform: uppercase;
	text-decoration: none;
	transition: opacity .25s ease, border-color .25s ease;
}
.pv-cmp-split__btn--solid { background: var(--wp--preset--color--contrast, #1a1a1e); color: var(--wp--preset--color--base, #f3f1ec); }
.pv-cmp-split__btn--solid:hover { opacity: .85; }
.pv-cmp-split__btn--ghost { border: 1px solid var(--wp--preset--color--border, #d8d5cb); color: var(--wp--preset--color--contrast, #1a1a1e); }
.pv-cmp-split__btn--ghost:hover { border-color: var(--wp--preset--color--contrast, #1a1a1e); }
.pv-cmp-split__figure {
	margin: 0;
	width: 100%;
	overflow: hidden;
	/* Consistent image rounding across the whole template — a template can retune it
	   once via `--pv-img-radius` and every image (hero + sections) follows. */
	border-radius: var(--pv-img-radius, 14px);
}
/* Show the image at its NATURAL aspect — never force a fixed aspect-ratio + cover,
   which crops the photo and can reveal the background "mat" if it under-fills. */
.pv-cmp-split__figure img { width: 100%; height: auto; display: block; }
.pv-cmp-split__cap {
	margin: .6rem 0 0;
	font-family: var(--pv-cmp-label, var(--wp--preset--font-family--space-mono, monospace));
	font-size: var(--wp--preset--font-size--small, .9rem);
	color: var(--wp--preset--color--contrast-3, #78766e);
}
@media (max-width: 781px) {
	.pv-cmp-split { grid-template-columns: 1fr; gap: 2rem; }
	.pv-cmp-split__eyebrow--right { text-align: left; }
	.pv-cmp-split--reverse .pv-cmp-split__col--media { order: 0; }
}

@media (max-width: 781px) {
	.pv-cmp-accordion__tags,
	.pv-cmp-accordion__year,
	.pv-cmp-filter__cat,
	.pv-cmp-filter__date,
	.pv-cmp-cursor__meta,
	.pv-cmp-cursor__year { display: none; }
	.pv-cmp-cursor__title { font-size: var(--wp--preset--font-size--large, 1.375rem); }
}

/* ── scroll reveal — opt-in fade + rise as an element enters the viewport ────
   Progressive enhancement: header-extras.js adds `pv-reveal-ready` to <html>
   only when it will actually animate, so with JS disabled (or reduced motion)
   the content is simply visible. Add `data-pv-reveal` to any section or block;
   set `--pv-reveal-delay` inline to stagger siblings. */
.pv-reveal-ready [data-pv-reveal] {
	opacity: 0;
	transform: translateY(1.25rem);
	transition: opacity var(--pv-reveal-dur, .7s) var(--pv-ease-out, ease),
	            transform var(--pv-reveal-dur, .7s) var(--pv-ease-out, ease);
	transition-delay: var(--pv-reveal-delay, 0s);
	will-change: opacity, transform;
}
.pv-reveal-ready [data-pv-reveal].is-in { opacity: 1; transform: none; }

/* ── staggered content reveal — the DIRECT children of `[data-pv-stagger]` rise in
   one-by-one as the section enters the viewport. Uses `animation` (not transition)
   with a per-child `--pv-reveal-delay` set by header-extras.js, so it never touches
   the children's own hover transitions. */
.pv-reveal-ready [data-pv-stagger] > * { opacity: 0; }
.pv-reveal-ready [data-pv-stagger].is-in > * {
	animation: pv-rise var(--pv-reveal-dur, .7s) var(--pv-ease-out, cubic-bezier(.22, 1, .36, 1)) both;
	animation-delay: var(--pv-reveal-delay, 0s);
}
@keyframes pv-rise {
	from { opacity: 0; transform: translateY(1.75rem); }
	to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
	/* The marquee is a decorative brand ticker (pauses on hover) — keep it moving
	   to match the approved design; disable only the interaction transitions. */
	.pv-cmp-accordion__panel { transition: none; }
	.pv-cmp-cursor__ghost { transition: none; }
	.pv-reveal-ready [data-pv-reveal] { opacity: 1; transform: none; transition: none; }
	.pv-reveal-ready [data-pv-stagger] > *,
	.pv-reveal-ready [data-pv-stagger].is-in > * { opacity: 1; animation: none; }
}

/* ── post head: a post's title, date and lead image ───────────────────────────
 * `Template_Preview::post_head_markup()` has always emitted this markup, and until
 * now NO stylesheet anywhere claimed it — not the plugin, and not eight of the nine
 * templates. So a post page showed a title and a photograph pinned to the window
 * edge above a body sitting on the template's own inset: three content boxes on one
 * page, which is exactly what §2 of template-studio exists to prevent. It was only
 * ever right in Gunnerup, because Gunnerup wrote the rules itself.
 *
 * A renderer owns the styles for the markup it emits. The default below is therefore
 * the plugin's, and it is built to land on the TEMPLATE's grid rather than impose one:
 *
 *   --pv-post-inset  →  falls back to `--x-inset`, the inset token template-studio §2
 *                       already tells every template to define. Four templates define
 *                       it and line up for free; the rest get a centred 1120 column,
 *                       which is the Canvas content grid and a reasonable answer.
 *
 * Everything is in `:where()` (zero specificity), so a template restyles any of it
 * with one class and no `!important`.
 *
 * NOTE the padding is on the HEADER and the cap is in the padding, not a max-width on
 * the same box — a box carrying both needs its `box-sizing` stated or the same number
 * means two different widths (template-studio §2, rule 5). There is no inner wrapper
 * in this markup to put a cap on, so the inset does the whole job. */
:where(.pv-post-head) {
	padding-inline: var(--pv-post-inset, var(--x-inset, max(var(--wp--preset--spacing--40), calc((100% - 1120px) / 2))));
	padding-block: var(--pv-post-top, var(--wp--preset--spacing--60)) 0;
}
/* The title keeps the heading face the template's globalStyles already set — the fix
   here is where it sits, not what it looks like. */
:where(.pv-post-title) { margin: 0; }
:where(.pv-post-meta) {
	margin: var(--wp--preset--spacing--20) 0 0;
	color: var(--wp--preset--color--contrast-3);
	font-size: var(--wp--preset--font-size--small);
}
:where(.pv-post-figure) { margin: var(--pv-post-figure-gap, var(--wp--preset--spacing--50)) 0 0; }
:where(.pv-post-figure img) {
	display: block;
	width: 100%;
	height: auto;
	border-radius: var(--pv-post-figure-radius, 0);
}

/* ── light/dark theme toggle (header) ─────────────────────────────────────────
 * Geometry is four custom properties, not four literals. A template sets them in
 * its own header CSS — `.pv-theme-toggle { --pv-toggle-size: 34px;
 * --pv-toggle-radius: 8px }` — so a squared-off technical header and a soft pill
 * header stop sharing one 40px circle. Nothing to add to the payload schema and
 * nothing for the header sanitizer to strip, which is the whole reason to express
 * it this way: a new config key has to be added in five places or the next header
 * save deletes it. The defaults below are what every existing template had. */
.pv-theme-toggle {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: var(--pv-toggle-size, 40px);
	height: var(--pv-toggle-size, 40px);
	padding: 0;
	border: var(--pv-toggle-border, 1px solid var(--wp--preset--color--border));
	border-radius: var(--pv-toggle-radius, 999px);
	background: transparent;
	color: var(--wp--preset--color--contrast);
	cursor: pointer;
	-webkit-appearance: none;
	appearance: none;
	transition: border-color .2s ease, background .2s ease, color .2s ease;
}
.pv-theme-toggle:hover { border-color: var(--wp--preset--color--contrast); }
.pv-theme-toggle:focus-visible {
	outline: none;
	border-color: var(--wp--preset--color--contrast);
	box-shadow: 0 0 0 1px var(--wp--preset--color--contrast);
}
.pv-theme-toggle svg { width: var(--pv-toggle-icon, 18px); height: var(--pv-toggle-icon, 18px); }
/* Light mode shows the moon (click → dark); dark mode shows the sun (click → light).
   Display is set on the icon classes only (not on `svg`) so the [data-theme="dark"]
   overrides — same class specificity, +1 attribute — actually win. */
.pv-theme-toggle__moon { display: block; }
.pv-theme-toggle__sun { display: none; }
:root[data-theme="dark"] .pv-theme-toggle__sun { display: block; }
:root[data-theme="dark"] .pv-theme-toggle__moon { display: none; }

/* ── Header appearance: transparent / sticky / overlay ────────────────────────
 * Header_Part_Writer::build_config_markup emits these classes from header.config.
 * They live here rather than in the theme so the editor preview, the marketplace
 * preview and the applied site all paint the header identically — the same reason
 * the mobile extras overlay below is plugin CSS. */
/* On its own this removes nothing: the bar is emitted with no background, so it is
   already see-through and this rule changes not one pixel. It exists to beat a
   palette background the template set earlier. What makes a header LOOK transparent
   is the overlap below — which is why Header_Part_Writer turns it on with this. */
.provatic-header--transparent {
	background: transparent !important;
}

/* Three coherent states, from two independent switches:
     overlap  sticky   position   what you get
     –        yes      sticky     opaque bar pinned to the top
     yes      –        absolute   bar over the hero, scrolls away with the page
     yes      yes      fixed      bar over the hero AND pinned
   `sticky` cannot do the overlapping ones: a sticky box still occupies its place in
   the flow, so the section below starts *after* it and there is nothing to overlap.
   `fixed` is the right answer for overlap+pinned and needs no scroll listener — an
   earlier comment here claimed otherwise and was simply wrong. */
.provatic-header--sticky {
	position: sticky;
	top: 0;
	/* Above section content and the scroll-reveal transforms, below the nav's own
	   full-screen overlay (core uses 100000 for that). */
	z-index: 100;
}
.provatic-header--overlay {
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	z-index: 100;
}
.provatic-header--overlay.provatic-header--sticky {
	position: fixed;
}
/* A pinned header starts below the WordPress admin bar, not under it. Without this a
   logged-in owner (the person most likely to be looking) sees the top 32px of every
   pinned header cut off. Above 600px only: below that the admin bar scrolls away with
   the page, so a header pinned 46px down would hang in mid-air. */
@media ( min-width: 601px ) {
	body.admin-bar .provatic-header--sticky,
	body.admin-bar .provatic-header--overlay {
		top: var( --wp-admin--admin-bar--height, 32px );
	}
}

/* Transparent over the hero, solid once you have scrolled past it. header-extras.js
   toggles `is-solid`; the colours stay the template's business, so all this does is
   make the change a fade rather than a jump. */
[data-pv-header-solidify] {
	transition: background-color 0.22s ease, color 0.22s ease, border-color 0.22s ease;
}
@media ( prefers-reduced-motion: reduce ) {
	[data-pv-header-solidify] { transition-duration: 0.01ms; }
}
/* No clearance rule for the band underneath, on purpose — sections carry generous
   vertical padding by contract (spacing 80/90), which is already more than a bar,
   and a band that deliberately runs to the edge is the whole point of an overlay
   header. Padding "the first section" would also mean guessing at the DOM, which
   differs between the preview (header + <main>) and an applied FSE site. */

/* ── Collapsed header: CTA + toggle move INTO the hamburger overlay ───────────
 * Whenever the menu is a hamburger, the bar is just logo + hamburger: hide the
 * header extras cluster (CTA, light/dark toggle) and re-show it INSIDE the open
 * overlay, pinned below the menu. WP marks the open state with `is-menu-open` on
 * the nav's responsive container (and `has-modal-open` on <html>) — we react to
 * either. Layout: the CTA is the PRIMARY action → a prominent full-width button;
 * the light/dark toggle is a small secondary utility on its own line below it (a
 * button-sized toggle next to the CTA looks awkward).
 *
 * 900px, not 600. It has to match the width at which the nav actually collapses,
 * and base.css folds `.provatic-header-nav` at ≤900 (core's own 600px overlayMenu
 * was overridden long ago). At 600-900 the two disagreed, and the result was a CTA
 * that existed at no width at all: base.css hides `.provatic-header-auth` there for
 * header-nav.js to relocate, but that script looks for it as a direct child of the
 * nav's parent and the config header nests it inside this cluster — so it never
 * moved, and this block stopped before it could compensate. Measured at 700 and
 * 850: hidden in the bar, still hidden with the menu open.
 *
 * `[data-pv-header-extras]` is the same contract for a `markup`-mode header, which
 * emits its own classes and so is reached by none of the platform's selectors. It
 * is opt-in: a template that wants the platform's collapsed-header behaviour marks
 * its CTA cluster with the attribute. */
@media (max-width: 900px) {
	.provatic-header-extras,
	[data-pv-header-extras] { display: none !important; }
	html.has-modal-open .provatic-header-extras,
	html.has-modal-open [data-pv-header-extras],
	.provatic-header-nav:has(.wp-block-navigation__responsive-container.is-menu-open) ~ .provatic-header-extras,
	.provatic-header-nav:has(.wp-block-navigation__responsive-container.is-menu-open) ~ [data-pv-header-extras] {
		display: flex !important;
		/* IN FLOW, at the end of the menu — not pinned to the viewport.
		 *
		 * This was `position: fixed; bottom: …`, which put the CTA over the menu rather
		 * than after it: scroll a long menu and the button sat across the middle of the
		 * items, covering whichever one happened to be behind it. The clearance hack that
		 * went with it (12rem of padding under the last item) was the giveaway — space
		 * reserved for something floating above the content.
		 *
		 * header-extras.js already MOVES this cluster into the open overlay's content, as
		 * the last child, so in normal flow it lands exactly where it belongs: below the
		 * last menu item. No JS, no overlay, no rule — core needs JS to open the drawer at
		 * all, so the un-relocated case cannot arise. */
		position: static;
		width: 100%;
		margin-top: 2.25rem;
		flex-direction: column;
		align-items: center;
		gap: 1.25rem;
	}
	/* CTA = prominent full-width primary action. Both the theme (≤900) and the
	   template's own CSS hide these in the collapsed bar, so force them visible and
	   full-width once inside the open overlay — otherwise they read as "missing".
	   `!important` is what beats those two, and is the reason 390 worked while the
	   rest of the collapsed range did not. */
	.provatic-header-extras .wp-block-buttons,
	[data-pv-header-extras] > * {
		display: flex !important;
		width: 100%;
		max-width: 420px;
		justify-content: center;
	}
	.provatic-header-extras .wp-block-button { width: 100%; }
	/* A markup header writes its own buttons, so reach them by role rather than by
	   core's block classes — `[data-pv-header-extras] a` would also catch a plain
	   text link, which is why the link case is listed explicitly alongside them. */
	.provatic-header-extras .wp-block-button__link,
	.provatic-header-extras .wp-element-button,
	[data-pv-header-extras] > a,
	[data-pv-header-extras] > button:not(.pv-theme-toggle),
	[data-pv-header-extras] > * > a {
		display: block;
		width: 100%;
		box-sizing: border-box;
		text-align: center;
		padding-top: .95em;
		padding-bottom: .95em;
		font-size: var(--wp--preset--font-size--medium, 1rem);
	}
	/* light/dark toggle = small utility, on its own line BELOW the CTA, and never
	   stretched to full width by the rules above. */
	.provatic-header-extras .pv-theme-toggle,
	[data-pv-header-extras] .pv-theme-toggle { order: 2; }
	[data-pv-header-extras] > .pv-theme-toggle {
		display: flex !important;
		/* Not `width: auto` — that collapsed the button onto its 18px icon and the
		   toggle rendered as a 20x40 slot. It has to be told the size it already had,
		   because the full-width rule above has already overridden it. */
		flex: 0 0 auto;
		width: var(--pv-toggle-size, 40px);
		height: var(--pv-toggle-size, 40px);
		max-width: none;
		padding: 0;
	}
}

/* ── mega menu (Nav_Mega) ─────────────────────────────────────────────────────
 * payload menus[].items[].mega/group/desc. The submenu of a `mega` item renders as
 * `li.pv-nav-mega > ul.wp-block-navigation__submenu-container > li.pv-nav-mega__col`
 * (one per group: `.pv-nav-mega__title` + `ul.pv-nav-mega__list`). Core still opens
 * and closes it (hover / focus-within / its toggle button), so there is no JS here.
 * The panel layout is desktop-only: at ≤900 the nav is core's drawer and the same
 * markup reads as an indented list with small column titles. Type uses the
 * component role tokens, so a template can restyle it like any other component. */
.pv-nav-mega__list {
	list-style: none;
	margin: 0;
	padding: 0;
}
.pv-nav-mega__title {
	display: block;
	font-family: var(--pv-cmp-label, var(--wp--preset--font-family--space-mono, monospace));
	font-size: 0.7rem;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	opacity: 0.6;
	padding: 0.75rem 0 0.25rem;
}
.pv-nav__desc {
	display: block;
	font-family: var(--pv-cmp-body, inherit);
	font-size: 0.8rem;
	font-weight: 400;
	line-height: 1.35;
	opacity: 0.65;
	margin-top: 0.15rem;
	white-space: normal;
}
@media (max-width: 900px) {
	/* In the drawer a mega menu is a long list: drop the description lines. The 12rem of
	   padding that used to sit here was clearance for a CTA pinned over the menu; the CTA
	   is in flow at the end now, so the clearance is just dead space. */
	.pv-nav-mega .pv-nav__desc { display: none; }

	/* ── A submenu in the drawer opens when you ask it to ──────────────────────
	 *
	 * Core forces every submenu open in the overlay and hides the chevron with it:
	 *
	 *   .wp-block-navigation__responsive-container.is-menu-open:where(…)
	 *     .…-content .has-child .wp-block-navigation__submenu-container
	 *         { position: static; visibility: visible; height: auto }
	 *   .…-content .wp-block-navigation__submenu-icon { display: none }
	 *
	 * So a nav with groups arrived as one flat wall of every link the site has — on
	 * provatic.com, two mega menus expanded at once — with no affordance to collapse any
	 * of it, because the control that would do it was hidden.
	 *
	 * ⚠️ SPECIFICITY. The forced-open rule counts FIVE classes: `:where()` adds nothing,
	 * but the container contributes two on its own (`…__responsive-container.is-menu-open`).
	 * The first attempt at this matched five as well — a tie, decided by source order, and
	 * core's block stylesheet prints after ours, so nothing changed on screen while a test
	 * that compared against a hand-written "4" passed. `:not(.disable-default-overlay)`
	 * takes these to six: a real margin, and true for exactly the overlays core's rule is.
	 *
	 * The open state is OURS (`data-pv-sub`, written by header-extras.js), not core's
	 * aria-expanded. One owner: whatever core's Interactivity API decides to do with its
	 * own attribute in the drawer, what is on screen and what the chevron shows agree. */
	.wp-block-navigation__responsive-container.is-menu-open:not(.disable-default-overlay)
		.wp-block-navigation__responsive-container-content
		.has-child > .wp-block-navigation__submenu-container {
		display: none;
	}
	.wp-block-navigation__responsive-container.is-menu-open:not(.disable-default-overlay)
		.wp-block-navigation__responsive-container-content
		.has-child[data-pv-sub="open"] > .wp-block-navigation__submenu-container {
		display: flex;
		flex-basis: 100%; /* its own line, under the row it belongs to */
	}
	/* Label and chevron on ONE row. Core lays every item out as a column, which put the
	   chevron on its own line under the label, centred, reading as a divider rather than
	   as the control for the row above it. */
	.wp-block-navigation__responsive-container.is-menu-open:not(.disable-default-overlay)
		.wp-block-navigation__responsive-container-content
		.has-child {
		flex-direction: row;
		flex-wrap: wrap;
		align-items: center;
	}
	/* Give the chevron back: it is the toggle, and core hid it. */
	.wp-block-navigation__responsive-container.is-menu-open:not(.disable-default-overlay)
		.wp-block-navigation__responsive-container-content
		.wp-block-navigation__submenu-icon {
		display: inline-flex;
		align-items: center;
		justify-content: center;
		flex: none;
		/* A thumb target, not a 0.8em glyph — this is the only way to open a group. */
		width: 2.75rem;
		height: 2.75rem;
		margin-left: auto;
	}
	.wp-block-navigation__responsive-container.is-menu-open:not(.disable-default-overlay)
		.wp-block-navigation__responsive-container-content
		.wp-block-navigation__submenu-icon > svg {
		width: 1em;
		height: 1em;
		transition: transform 0.15s ease;
	}
	/* Rotate on OUR state, and stop core rotating on its own — two sources would
	   contradict each other the moment they disagreed. */
	.wp-block-navigation__responsive-container.is-menu-open:not(.disable-default-overlay)
		.has-child > .wp-block-navigation-submenu__toggle[aria-expanded="true"] > svg {
		transform: none;
	}
	.wp-block-navigation__responsive-container.is-menu-open:not(.disable-default-overlay)
		.has-child[data-pv-sub="open"] > .wp-block-navigation__submenu-icon > svg {
		transform: rotate(180deg);
	}
	/* The label keeps the rest of the row, and keeps being a link to its own page. */
	.wp-block-navigation__responsive-container.is-menu-open:not(.disable-default-overlay)
		.wp-block-navigation__responsive-container-content
		.has-child > .wp-block-navigation-item__content {
		flex: 0 1 auto;
	}
}
@media (min-width: 901px) {
	/* Out-ranks core's `.items-justified-right … .has-child .wp-block-navigation__submenu-container` (0,5,0). */
	.wp-block-navigation .wp-block-navigation__container .wp-block-navigation-item.pv-nav-mega.has-child > .wp-block-navigation__submenu-container {
		flex-direction: row;
		gap: 2rem;
		/* Centred on its menu item by default, which is right for a nav that sits in the
		   middle or at the right of the bar. A nav pinned to the LEFT edge puts half the
		   panel off screen, so the anchor is a variable a template can move:
		   `--pv-mega-left: 0; --pv-mega-shift: 0` anchors it to the item's left edge. */
		left: var( --pv-mega-left, 50% );
		right: auto; /* core pins submenus of a right-justified nav with right:0 */
		transform: translateX( var( --pv-mega-shift, -50% ) );
		max-width: min(760px, calc(100vw - 2rem));
		padding: 1.25rem 1.5rem;
		border: 1px solid color-mix(in srgb, var(--wp--preset--color--contrast, #111) 12%, transparent);
		border-radius: 14px;
		background: var(--wp--preset--color--base, #fff);
		color: var(--wp--preset--color--contrast, #111);
		box-shadow: 0 18px 40px -20px rgba(0, 0, 0, 0.28);
	}
	.wp-block-navigation .pv-nav-mega__col {
		display: flex;
		flex-direction: column;
		min-width: 13rem;
	}
	.wp-block-navigation .pv-nav-mega__title {
		padding: 0 0.75rem 0.5rem;
	}
	.wp-block-navigation .pv-nav-mega__list .wp-block-navigation-item {
		min-width: 0;
	}
	.wp-block-navigation .pv-nav-mega__list .wp-block-navigation-item__content {
		display: block;
		padding: 0.5rem 0.75rem;
		border-radius: 8px;
	}
	.wp-block-navigation .pv-nav-mega__list .wp-block-navigation-item__content:hover,
	.wp-block-navigation .pv-nav-mega__list .wp-block-navigation-item__content:focus-visible {
		background: color-mix(in srgb, var(--wp--preset--color--contrast, #111) 6%, transparent);
		opacity: 1;
	}
}

/* ── site header links — no underline; a very faint hover instead ─────────── */
.pv-site-header a {
	text-decoration: none;
	transition: opacity 0.2s ease;
}
.pv-site-header a:hover,
.pv-site-header a:focus {
	text-decoration: none;
	opacity: 0.55;
}

/* ── slideshow — one image at a time, slow auto crossfade (no arrows/dots) ───
 * Reusable: any container with .pv-cmp-slideshow holding figure > img
 * slides. Frame size = --pv-slideshow-aspect (default 4/5, matches a portrait).
 * header-extras.js counts the slides from the DOM (so editor-added slides join
 * the cycle) and toggles .is-active; pre-JS the first slide shows. */
.pv-cmp-slideshow {
	position: relative;
	width: 100%;
	aspect-ratio: var(--pv-slideshow-aspect, 4 / 5);
	overflow: hidden;
	background: var(--wp--preset--color--base-3, #f4f4f5);
}
.pv-cmp-slideshow > figure {
	position: absolute;
	inset: 0;
	margin: 0;
	opacity: 0;
}
.pv-cmp-slideshow > figure:first-child { opacity: 1; } /* pre-JS fallback */
.pv-cmp-slideshow img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* JS took over → opacity is driven by .is-active (overrides :first-child). */
.pv-cmp-slideshow.is-js > figure { opacity: 0; transition: opacity 1.2s ease; }
.pv-cmp-slideshow.is-js > figure.is-active { opacity: 1; }
/* An unfilled "+ Add photo" placeholder is not a real slide on the live site (backstop to
 * the JS filter); in the editor it's hidden too (never .is-active), and the author fills/
 * manages slots via the inspector's Slideshow panel. */
body:not(.is-tpl-editing) .pv-cmp-slideshow > figure:has(img[src*="slot-placeholder"]) { display: none; }

/* In the editor the slideshow renders WYSIWYG — the same single-slide 4/5 frame as live,
 * with the auto-cycle paused (header-extras.js pauses on is-tpl-editing). Slides are added/
 * removed/uploaded through the inspector's Slideshow panel, not on the canvas — so no grid
 * override here (a side-by-side grid made the narrow hero column look broken). */

@media (prefers-reduced-motion: reduce) {
	.pv-cmp-slideshow.is-js > figure { transition: none; }
}

/* Section drop-slot — an empty container you drop elements INTO. On the live site an empty
 * one collapses; in the editor it shows a dashed drop zone with a hint until filled. */
body.is-tpl-editing .pv-slot {
	min-height: 72px;
	border: 1px dashed var(--wp--preset--color--border, #d4d4d8);
	border-radius: 6px;
}
body.is-tpl-editing .pv-slot:empty::before {
	content: "Drop elements here";
	display: block;
	text-align: center;
	color: var(--wp--preset--color--contrast-3, #a1a1aa);
	font-size: 13px;
	padding: 26px 8px;
}

/* ═════════════════════════════════════════════════════════════════════════════
 * Sidebar shell — the LEFT NAV RAIL (Sidebar_Rail).
 *
 * MODEL: the rail and the header are SEPARATE regions. A `layout.shell="sidebar"`
 * site still renders header + sections + footer in the content column; the rail is
 * an extra fixed column carrying ONLY the brand mark + the navigation (CTAs stay in
 * the header). Collapsing (button at the BOTTOM of the rail) shrinks it to a MINI
 * ICON RAIL — it never disappears. Tablet and below it becomes an off-canvas drawer
 * opened by a top-right hamburger.
 *
 * Lives in the PLUGIN (not the theme) because the rail markup is plugin-rendered:
 * one source of truth for the applied site, the editor preview, the marketplace
 * preview and a published native project.
 * ═════════════════════════════════════════════════════════════════════════════ */
:root {
	--pv-rail-w: 248px;
	--pv-rail-w-mini: 76px;
	--pv-rail-topbar-h: 64px;
}

/* Offset the content column by the rail width (the rail is fixed = out of flow).
   `display:flex` also neutralises the pre-10 theme build's sidebar grid.

   This and the `width` transition on .pv-rail below animate LAYOUT properties, which
   a design linter will flag and which is usually right to flag. Kept deliberately:
   a rail that collapses from 248px to 64px has to reserve different space, and the
   transform-based alternatives all trade the reflow for a worse bug — translating the
   content column pushes it off the right edge, and animating the rail alone leaves the
   text jumping at the end. It is a discrete, click-triggered 220ms change on one
   containing block, not something running on scroll, and it is already switched off
   under prefers-reduced-motion (see the block near the end of this file). Decided
   2026-09-16 after this was raised several times; change it only with a measurement
   showing the reflow actually costs frames. */
body.provatic-shell-sidebar:not(.wp-custom-template-page-app):not(.page-template-page-app) .wp-site-blocks {
	display: flex;
	flex-direction: column;
	padding-left: var(--pv-rail-w);
	transition: padding-left .22s var(--pv-ease-out);
}
body.provatic-shell-collapsed.provatic-shell-sidebar:not(.wp-custom-template-page-app):not(.page-template-page-app) .wp-site-blocks {
	padding-left: var(--pv-rail-w-mini);
}

/* The header STAYS a top bar (it is NOT the rail). Undo the pre-10 Canvas build's
   "header becomes the rail" rules so an older theme cannot fight this layout. */
body.provatic-shell-sidebar .wp-site-blocks > header {
	position: static !important;
	width: auto !important;
	height: auto !important;
	max-height: none !important;
	overflow: visible !important;
	transform: none !important;
	border-right: 0 !important;
	z-index: auto !important;
	grid-column: auto !important;
	grid-row: auto !important;
}
body.provatic-shell-sidebar .wp-site-blocks > header > .wp-block-group {
	flex-direction: row;
	align-items: center;
	height: auto;
}
body.provatic-shell-sidebar .wp-site-blocks > header .wp-block-navigation,
body.provatic-shell-sidebar .wp-site-blocks > header .wp-block-navigation__container {
	flex-direction: row;
}
body.provatic-shell-sidebar .wp-site-blocks > header .provatic-header-auth {
	flex-direction: row;
	align-items: center;
	margin-top: 0;
}
/* Brand + menu live in the RAIL, so the header shows neither — only its CTAs (or
   whatever the owner puts there) remain. header-extras.js hides the whole bar when
   nothing visible is left (the default sidebar header is empty). */
body.provatic-shell-sidebar .wp-site-blocks > header .wp-block-site-logo,
body.provatic-shell-sidebar .wp-site-blocks > header .wp-block-site-title,
body.provatic-shell-sidebar .wp-site-blocks > header .wp-block-navigation {
	display: none;
}
body.provatic-shell-sidebar .wp-site-blocks > header .wp-block-group.alignwide {
	justify-content: flex-end;
}
body.provatic-shell-sidebar.pv-header-empty .wp-site-blocks > header {
	display: none;
}

/* ── the rail ─────────────────────────────────────────────────────────────── */
.pv-rail {
	display: none;                       /* only a sidebar shell shows it */
	position: fixed;
	top: 0;
	left: 0;
	width: var(--pv-rail-w);
	height: 100vh;
	box-sizing: border-box;
	flex-direction: column;
	gap: 4px;
	padding: 20px 14px 14px;
	background: var(--wp--preset--color--base, #fff);
	border-right: 1px solid var(--wp--preset--color--border, #e4e4e7);
	z-index: 30;
	overflow: hidden auto;
	/* `width` is a layout property on purpose — see the note on .wp-site-blocks above. */
	transition: width .22s var(--pv-ease-out), transform .22s var(--pv-ease-out);
}
body.provatic-shell-sidebar .pv-rail { display: flex; }
body.admin-bar .pv-rail {
	top: var(--wp-admin--admin-bar--height, 32px);
	height: calc(100vh - var(--wp-admin--admin-bar--height, 32px));
}
.pv-rail__brand {
	display: flex;
	align-items: center;
	min-height: 44px;
	padding: 0 8px 14px;
}
.pv-rail__brand-link,
.pv-rail__brand .custom-logo-link {
	display: inline-flex;
	align-items: center;
	text-decoration: none;
}
.pv-rail__logo,
.pv-rail__brand img {
	display: block;
	width: auto;
	max-width: 100%;
	max-height: 34px;
}

/* The preview’s logo default — and nothing more than a default.
 *
 * This used to be an inline style on the <img>, which is the second-strongest origin
 * in the cascade. A template that wanted to size its own logo could therefore only
 * win by shouting `!important`, and !important goes on one property at a time:
 * Kijulee said `height:34px!important`, that beat the inline height, the inline
 * `width:34px` kept the width, and a customer’s 793×162 wordmark rendered as a
 * 34×34 square. Two parties each won one axis of the same box.
 *
 * :where() contributes zero specificity, so ANY author rule — one class is enough —
 * beats this outright, on both axes, with no !important anywhere. A config header,
 * which ships no CSS of its own, still gets its size from --pv-logo-w. */
:where(.wp-block-site-logo img.custom-logo) {
	width: var(--pv-logo-w, 48px);
	height: auto;
}

.pv-rail__nav { flex: 1 1 auto; }
.pv-rail__list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 2px;
}
.pv-rail__list--sub {
	margin: 2px 0 6px 16px;
	padding-left: 10px;
	border-left: 1px solid var(--wp--preset--color--border, #e4e4e7);
}
.pv-rail__link,
.pv-rail__collapse {
	display: flex;
	align-items: center;
	gap: 10px;
	width: 100%;
	box-sizing: border-box;
	padding: 9px 10px;
	border: 0;
	border-radius: 8px;
	background: transparent;
	color: var(--wp--preset--color--contrast-2, #52525b);
	font-family: inherit;
	font-size: 15px;
	line-height: 1.2;
	text-align: left;
	text-decoration: none;
	cursor: pointer;
	transition: background-color .15s var(--pv-ease-out), color .15s var(--pv-ease-out);
}
.pv-rail__link:hover,
.pv-rail__collapse:hover {
	background: var(--wp--preset--color--base-2, #fafafa);
	color: var(--wp--preset--color--contrast, #18181b);
}
.pv-rail__link.is-current {
	background: var(--wp--preset--color--base-3, #f4f4f5);
	color: var(--wp--preset--color--contrast, #18181b);
}
.pv-rail__ico {
	display: inline-flex;
	flex: 0 0 auto;
	width: 20px;
	height: 20px;
	align-items: center;
	justify-content: center;
}
.pv-rail__txt {
	flex: 1 1 auto;
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
/* Collapse toggle — pinned to the BOTTOM of the rail (never beside the logo). */
.pv-rail__foot {
	margin-top: auto;
	padding-top: 10px;
	border-top: 1px solid var(--wp--preset--color--border, #e4e4e7);
}
.pv-rail__chev { transition: transform .22s var(--pv-ease-out); }

/* ── collapsed = MINI ICON RAIL (icons + symbol logo stay visible) ─────────── */
body.provatic-shell-collapsed .pv-rail { width: var(--pv-rail-w-mini); }
body.provatic-shell-collapsed .pv-rail .pv-rail__txt { display: none; }
body.provatic-shell-collapsed .pv-rail .pv-rail__link,
body.provatic-shell-collapsed .pv-rail .pv-rail__collapse,
body.provatic-shell-collapsed .pv-rail .pv-rail__brand {
	justify-content: center;
	padding-inline: 0;
}
body.provatic-shell-collapsed .pv-rail .pv-rail__list--sub {
	margin-left: 0;
	padding-left: 0;
	border-left: 0;
}
body.provatic-shell-collapsed .pv-rail .pv-rail__chev { transform: rotate(180deg); }

/* ── tablet ↓ : off-canvas drawer + a TOP-RIGHT hamburger ─────────────────── */
.pv-rail-burger {
	display: none;
	position: fixed;
	top: 14px;
	right: 14px;
	width: 40px;
	height: 40px;
	align-items: center;
	justify-content: center;
	box-sizing: border-box;
	padding: 0;
	border: 1px solid var(--wp--preset--color--border, #e4e4e7);
	border-radius: 10px;
	background: var(--wp--preset--color--base, #fff);
	color: var(--wp--preset--color--contrast, #18181b);
	cursor: pointer;
	z-index: 40;
}
body.admin-bar .pv-rail-burger { top: calc(14px + var(--wp-admin--admin-bar--height, 32px)); }
.pv-rail-scrim {
	display: none;
	position: fixed;
	inset: 0;
	background: rgba(0, 0, 0, .35);
	z-index: 29;
}

/* When nothing in the menu resolves to a meaningful icon, drop the icon column
   rather than lining up identical dots — but keep it in the collapsed mini rail,
   where an icon is the only thing left to click. */
.pv-rail__list--noicons .pv-rail__ico { display: none; }
.pv-rail__list--noicons .pv-rail__link { gap: 0; }
body.provatic-shell-collapsed .pv-rail .pv-rail__list--noicons .pv-rail__ico { display: inline-flex; }

/* Tablet ↓ brand bar: the rail is off-canvas there, so the logo lives here
   (top-left) with the hamburger at the top-right. Hidden on desktop. */
.pv-rail-topbar {
	display: none;
	position: fixed;
	inset: 0 0 auto 0;
	height: var(--pv-rail-topbar-h);
	align-items: center;
	box-sizing: border-box;
	padding: 0 64px 0 16px;   /* right side clears the hamburger */
	background: var(--wp--preset--color--base, #fff);
	border-bottom: 1px solid var(--wp--preset--color--border, #e4e4e7);
	z-index: 35;              /* above the scrim (29), below the burger (40) */
}
.pv-rail-topbar__brand { display: flex; align-items: center; min-width: 0; }
.pv-rail-topbar img,
.pv-rail-topbar .pv-rail__logo { display: block; width: auto; max-height: 32px; }
body.admin-bar .pv-rail-topbar { top: var(--wp-admin--admin-bar--height, 32px); }
@media (max-width: 782px) {
	body.provatic-shell-sidebar:not(.wp-custom-template-page-app):not(.page-template-page-app) .wp-site-blocks,
	body.provatic-shell-collapsed.provatic-shell-sidebar:not(.wp-custom-template-page-app):not(.page-template-page-app) .wp-site-blocks {
		padding-left: 0;
		padding-top: var(--pv-rail-topbar-h);   /* clear the fixed brand bar */
	}
	body.provatic-shell-sidebar .pv-rail-topbar { display: flex; }
	/* The drawer opens BELOW the bar so the brand stays visible while navigating. */
	body.provatic-shell-sidebar .pv-rail,
	body.provatic-shell-collapsed.provatic-shell-sidebar .pv-rail {
		width: min(84vw, var(--pv-rail-w));
		top: var(--pv-rail-topbar-h);
		height: calc(100vh - var(--pv-rail-topbar-h));
		transform: translateX(-100%);
		box-shadow: 0 0 40px rgba(0, 0, 0, .12);
	}
	body.admin-bar.provatic-shell-sidebar .pv-rail {
		top: calc(var(--pv-rail-topbar-h) + var(--wp-admin--admin-bar--height, 32px));
		height: calc(100vh - var(--pv-rail-topbar-h) - var(--wp-admin--admin-bar--height, 32px));
	}
	body.provatic-shell-sidebar .pv-rail-scrim { top: var(--pv-rail-topbar-h); }
	body.admin-bar.provatic-shell-sidebar .pv-rail-scrim { top: calc(var(--pv-rail-topbar-h) + var(--wp-admin--admin-bar--height, 32px)); }
	/* The brand now sits in the bar — don't repeat it at the top of the drawer. */
	body.provatic-shell-sidebar .pv-rail__brand { display: none; }
	/* The hamburger sits inside the bar: no border of its own, optically centred. */
	body.provatic-shell-sidebar .pv-rail-burger { top: 12px; right: 12px; border: 0; background: transparent; }
	body.admin-bar.provatic-shell-sidebar .pv-rail-burger { top: calc(12px + var(--wp-admin--admin-bar--height, 32px)); }
	/* The drawer always shows full labels, even if the desktop rail was collapsed. */
	body.provatic-shell-collapsed.provatic-shell-sidebar .pv-rail .pv-rail__txt { display: block; }
	body.provatic-shell-collapsed.provatic-shell-sidebar .pv-rail .pv-rail__link,
	body.provatic-shell-collapsed.provatic-shell-sidebar .pv-rail .pv-rail__brand {
		justify-content: flex-start;
		padding-inline: 10px;
	}
	body.provatic-shell-sidebar.pv-rail-open .pv-rail { transform: none; }
	body.provatic-shell-sidebar.pv-rail-open .pv-rail-scrim { display: block; }
	body.provatic-shell-sidebar .pv-rail-burger { display: inline-flex; }
	/* Collapse is a desktop affordance — the drawer closes via hamburger/scrim. */
	body.provatic-shell-sidebar .pv-rail__foot { display: none; }
	/* The rail owns navigation on this shell, so the header's own hamburger is out. */
	body.provatic-shell-sidebar .wp-site-blocks > header .wp-block-navigation__responsive-container-open { display: none; }
}
@media (prefers-reduced-motion: reduce) {
	.pv-rail,
	.pv-rail__chev,
	body.provatic-shell-sidebar .wp-site-blocks { transition: none; }
}

/* ---------------------------------------------------------------------------
 * post-list — cards built from real posts. The draft preview and the deployed
 * site emit identical markup, so this one block styles both.
 * ------------------------------------------------------------------------- */

/* The band never constrains its content — wrap_band() says so explicitly, and every
 * other inset component carries its own width. This one had no base rule at all: the
 * block below started at __heading, so the heading sat hard against the viewport edge
 * and the cards ran the full width while every other section on the page was inset. */
.pv-postlist {
	max-width: var(--pv-content-width);
	margin-inline: auto;
	padding-inline: var(--wp--preset--spacing--40, 1.5rem);
}
.pv-postlist__heading {
	margin: 0 0 2rem;
	font-size: clamp(2rem, 4vw, 3.5rem);
	line-height: 1.2;
}
.pv-postlist__grid {
	display: grid;
	grid-template-columns: repeat(var(--pv-postlist-cols, 3), minmax(0, 1fr));
	gap: 2rem;
}
.pv-postlist__card {
	display: flex;
	flex-direction: column;
	gap: 1rem;
	color: inherit;
	text-decoration: none;
}
.pv-postlist__media {
	display: block;
	overflow: hidden;
	aspect-ratio: var(--pv-postlist-aspect, 3/2);
	background: var(--wp--preset--color--surface, #f4f4f5);
	border-radius: 4px;
}
.pv-postlist__media img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform .5s cubic-bezier(.2, .7, .2, 1);
}
.pv-postlist__card:hover .pv-postlist__media img { transform: scale(1.03); }
.pv-postlist__body { display: flex; flex-direction: column; gap: .5rem; }
.pv-postlist__cat {
	font-size: .75rem;
	letter-spacing: .08em;
	text-transform: uppercase;
	color: var(--wp--preset--color--muted, #71717a);
}
.pv-postlist__title { font-size: 1.25rem; line-height: 1.35; }
.pv-postlist__excerpt {
	font-size: .9375rem;
	line-height: 1.6;
	color: var(--wp--preset--color--muted, #71717a);
}
.pv-postlist__date { font-size: .8125rem; color: var(--wp--preset--color--muted, #71717a); }
.pv-postlist__empty { color: var(--wp--preset--color--muted, #71717a); }

/* list — a stacked row per post; overlay — text over the image; wide — one big card. */
.pv-postlist--list .pv-postlist__grid { grid-template-columns: 1fr; gap: 1.5rem; }
.pv-postlist--list .pv-postlist__card { flex-direction: row; align-items: center; gap: 1.5rem; }
.pv-postlist--list .pv-postlist__media { flex: 0 0 clamp(120px, 22%, 260px); }
.pv-postlist--overlay .pv-postlist__card { position: relative; }
.pv-postlist--overlay .pv-postlist__body {
	position: absolute;
	inset: auto 0 0 0;
	padding: 1.25rem;
	color: #fff;
	background: linear-gradient(to top, rgba(0, 0, 0, .65), transparent);
}
.pv-postlist--overlay .pv-postlist__cat,
.pv-postlist--overlay .pv-postlist__excerpt,
.pv-postlist--overlay .pv-postlist__date { color: rgba(255, 255, 255, .85); }
.pv-postlist--wide .pv-postlist__grid { grid-template-columns: 1fr; }
.pv-postlist--wide .pv-postlist__title { font-size: clamp(1.5rem, 3vw, 2.25rem); }

@media (max-width: 960px) {
	.pv-postlist__grid { grid-template-columns: repeat(min(var(--pv-postlist-cols, 3), 2), minmax(0, 1fr)); }
}
@media (max-width: 640px) {
	.pv-postlist__grid { grid-template-columns: 1fr; }
	.pv-postlist--list .pv-postlist__card { flex-direction: column; align-items: stretch; }
}
