/**
 * Videre Productions redesign.
 *
 * Values mirror the approved design canvas (Videre Productions.dc.html).
 * Loaded only on template-videre-*.php pages; Avada's stylesheet is dequeued
 * there so these rules need no !important to win.
 */

:root {
	--vp-bg: #100e0c;
	--vp-bg-raised: #17140f;
	--vp-ink: #f5efe6;
	--vp-ink-dim: #9a9088;
	--vp-ink-faint: #6f6862;
	--vp-accent: #b8865a;
	--vp-rule: rgba(245, 239, 230, 0.14);
	--vp-rule-soft: rgba(245, 239, 230, 0.1);

	--vp-sans: 'Archivo', Helvetica, Arial, sans-serif;
	--vp-mono: 'IBM Plex Mono', ui-monospace, monospace;

	--vp-gutter: clamp(16px, 4vw, 56px);
	--vp-max: 1400px;

	/* Logo is 673x378 (16:9). A fixed height keeps the fixed header the same
	 * depth at every width — 80px logo + 2x12px padding = 104px header. The
	 * footer mark can be larger, where the artwork's small print has room to
	 * read. */
	--vp-logo-h: 80px;
	--vp-logo-h-footer: 96px;
}

/* Reset ---------------------------------------------------------------- */

.vp-body {
	margin: 0;
	background: var(--vp-bg);
	color: var(--vp-ink);
	font-family: var(--vp-sans);
	-webkit-font-smoothing: antialiased;
	text-wrap: pretty;
	overflow-x: hidden;
}

.vp-body * {
	box-sizing: border-box;
}

.vp-body a {
	color: var(--vp-ink);
	text-decoration: none;
}

.vp-body a:hover {
	color: var(--vp-accent);
}

/* Keyboard focus uses the design's accent rather than the browser default. */
.vp-body a:focus-visible,
.vp-body button:focus-visible {
	outline: 2px solid var(--vp-accent);
	outline-offset: 3px;
}

.vp-body img {
	max-width: 100%;
	height: auto;
	display: block;
}

/* Header --------------------------------------------------------------- */

/* The bar spans the viewport; its contents are constrained by
 * .vp-header__inner so the logo and nav align with the page content below. */
.vp-header {
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	z-index: 40;
	padding: 12px var(--vp-gutter);
}

.vp-header__inner {
	max-width: var(--vp-max);
	margin: 0 auto;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 24px;
}

/* The blur lives on a pseudo-element, not on .vp-header itself.
 * backdrop-filter on the header would make it a containing block for its
 * position:fixed descendants, which collapses the mobile drawer to the
 * header's own height instead of the viewport's. */
.vp-header::before {
	content: '';
	position: absolute;
	inset: 0;
	z-index: -1;
	background: rgba(16, 14, 12, 0.72);
	backdrop-filter: blur(14px);
	border-bottom: 1px solid var(--vp-rule-soft);
}

.vp-logo {
	display: flex;
	align-items: center;
	flex-shrink: 0;
}

/* The <img> sits inside a <picture>, which is inline by default. */
.vp-logo picture {
	display: block;
	line-height: 0;
}

/* Sized by height so the 16:9 artwork scales predictably; the width/height
 * attributes on the <img> reserve the aspect ratio before the file loads.
 * Selectors are compound (.vp-logo .vp-logo__img) to outrank the
 * `.vp-body img { height: auto }` reset, which is declared later. */
.vp-logo .vp-logo__img {
	height: var(--vp-logo-h);
	width: auto;
}

.vp-logo--footer {
	margin-bottom: 18px;
}

.vp-logo--footer .vp-logo__img {
	height: var(--vp-logo-h-footer);
}

/* Pushed to the right by the inner wrapper's space-between, and centred
 * against the full height of the logo beside it. */
.vp-nav {
	display: flex;
	align-items: center;
	gap: clamp(14px, 2.4vw, 34px);
}

.vp-nav__link {
	display: flex;
	align-items: center;
	gap: 7px;
	font-family: var(--vp-mono);
	font-size: 11px;
	letter-spacing: 0.18em;
	text-transform: uppercase;
}

.vp-dot {
	width: 5px;
	height: 5px;
	background: var(--vp-accent);
	border-radius: 50%;
}

.vp-nav__cta {
	padding: 9px 18px;
	border: 1px solid rgba(245, 239, 230, 0.28);
	border-radius: 999px;
	font-family: var(--vp-mono);
	font-size: 11px;
	letter-spacing: 0.18em;
	text-transform: uppercase;
}

.vp-nav__cta:hover {
	background: var(--vp-accent);
	border-color: var(--vp-accent);
	color: var(--vp-bg);
}

/* Skip link — visible only once focused. */

.vp-skip {
	position: absolute;
	left: -9999px;
	top: 0;
	z-index: 60;
}

.vp-skip:focus {
	left: var(--vp-gutter);
	top: 10px;
	padding: 10px 16px;
	background: var(--vp-accent);
	color: var(--vp-bg);
	font-family: var(--vp-mono);
	font-size: 11px;
	letter-spacing: 0.16em;
	text-transform: uppercase;
}

/* Hamburger + drawer -------------------------------------------------- */

/* Hidden above the breakpoint; the desktop nav is the default state. */
.vp-burger {
	display: none;
}

.vp-nav__social {
	display: none;
}

.vp-scrim {
	display: none;
}

@media (max-width: 859px) {
	.vp-burger {
		display: flex;
		flex-direction: column;
		justify-content: center;
		gap: 6px;
		/* 44px minimum touch target. */
		width: 44px;
		height: 44px;
		margin-right: -10px;
		padding: 0;
		background: none;
		border: 0;
		cursor: pointer;
		z-index: 52;
	}

	.vp-burger__bar {
		display: block;
		width: 24px;
		height: 1px;
		background: var(--vp-ink);
		transition: transform 0.3s ease, opacity 0.2s ease;
	}

	/* Two bars cross into an X when open. */
	.vp-burger[aria-expanded='true'] .vp-burger__bar:first-child {
		transform: translateY(3.5px) rotate(45deg);
	}

	.vp-burger[aria-expanded='true'] .vp-burger__bar:last-child {
		transform: translateY(-3.5px) rotate(-45deg);
	}

	.vp-nav {
		position: fixed;
		top: 0;
		left: 0;
		bottom: 0;
		width: min(82vw, 380px);
		z-index: 51;

		flex-direction: column;
		align-items: flex-start;
		justify-content: flex-start;
		gap: 4px;

		/* Clears the 104px header so the first link is not tucked under it. */
		padding: 128px var(--vp-gutter) 40px;
		background: var(--vp-bg);
		border-right: 1px solid var(--vp-rule);

		transform: translateX(-100%);
		transition: transform 0.36s cubic-bezier(0.22, 0.61, 0.36, 1);
		overflow-y: auto;
		overscroll-behavior: contain;
	}

	.vp-nav.is-open {
		transform: translateX(0);
	}

	/* Links become large editorial type in the drawer. */
	.vp-nav__link {
		width: 100%;
		padding: 16px 0;
		font-family: var(--vp-sans);
		font-size: clamp(26px, 7vw, 34px);
		font-weight: 500;
		letter-spacing: -0.02em;
		text-transform: none;
		border-bottom: 1px solid var(--vp-rule-soft);
	}

	.vp-nav__cta {
		margin-top: 28px;
		padding: 15px 30px;
		background: var(--vp-accent);
		border-color: var(--vp-accent);
		color: var(--vp-bg);
		font-size: 12px;
	}

	.vp-nav__social {
		display: flex;
		gap: 16px;
		margin-top: 32px;
	}

	.vp-nav__social a {
		font-family: var(--vp-mono);
		font-size: 10px;
		letter-spacing: 0.18em;
		text-transform: uppercase;
		color: var(--vp-ink-dim);
	}

	/* :not([hidden]) is required, not decorative. The markup ships the scrim
	 * with the hidden attribute and videre.js clears it only while the drawer
	 * is open. A bare .vp-scrim rule outranks the UA stylesheet's [hidden]
	 * display:none, so the element would stay laid out at opacity 0 — an
	 * invisible full-viewport layer at z-index 50 swallowing every tap on the
	 * page. Verified with elementFromPoint, which returned .vp-scrim at the
	 * centre of a 390px viewport before this was scoped. */
	.vp-scrim:not([hidden]) {
		display: block;
		position: fixed;
		inset: 0;
		z-index: 50;
		background: rgba(16, 14, 12, 0.6);
		backdrop-filter: blur(2px);
		opacity: 0;
		transition: opacity 0.3s ease;
	}

	.vp-scrim.is-open {
		opacity: 1;
	}

	/* Locked while the drawer is open, so the page behind cannot scroll. */
	.vp-body.vp-nav-open {
		overflow: hidden;
	}
}

/* Respect reduced-motion: drawer appears without sliding. */
@media (max-width: 859px) and (prefers-reduced-motion: reduce) {
	.vp-nav,
	.vp-scrim,
	.vp-burger__bar {
		transition: none;
	}
}

/* Layout --------------------------------------------------------------- */

/* The floor is the value that matters: the header is position:fixed and
 * reserves no space, so this padding is the only thing keeping content clear
 * of it. 120px leaves 16px below the 104px header (80px logo + 2x12px). Do
 * not drop it further without shrinking the header — at 96px the eyebrow is
 * sliced by the header's bottom edge on every viewport under ~1156px, where
 * 9vw has not yet overtaken the floor. */
.vp-main {
	padding: clamp(120px, 9vw, 190px) var(--vp-gutter) clamp(72px, 10vw, 140px);
}

.vp-wrap {
	max-width: var(--vp-max);
	margin: 0 auto;
}

.vp-eyebrow {
	font-family: var(--vp-mono);
	font-size: 11px;
	letter-spacing: 0.2em;
	text-transform: uppercase;
	color: var(--vp-accent);
}

.vp-h1 {
	margin: 18px 0 0;
	font-size: clamp(40px, 8vw, 120px);
	line-height: 0.94;
	font-weight: 600;
	letter-spacing: -0.03em;
}

.vp-lede {
	margin: clamp(24px, 3vw, 40px) 0 0;
	max-width: 22ch;
	font-size: clamp(22px, 2.8vw, 40px);
	line-height: 1.14;
	font-weight: 500;
	letter-spacing: -0.02em;
}

/* Media + placeholder slots -------------------------------------------- */

.vp-media {
	position: relative;
	background: var(--vp-bg-raised);
	overflow: hidden;
	margin-top: clamp(36px, 5vw, 72px);
}

.vp-media--wide {
	aspect-ratio: 21 / 9;
}

.vp-media__img,
.vp-media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* Styled stand-in until the client supplies real stills. */
.vp-slot {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	background-image: repeating-linear-gradient(
		45deg,
		rgba(245, 239, 230, 0.04) 0 10px,
		transparent 10px 20px
	);
	border: 1px solid var(--vp-rule);
}

.vp-slot__label {
	font-family: var(--vp-mono);
	font-size: 11px;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--vp-ink-dim);
	text-align: center;
	padding: 0 16px;
}

/* About body ----------------------------------------------------------- */

.vp-about-grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
	gap: clamp(28px, 5vw, 80px);
	margin-top: clamp(44px, 6vw, 90px);
}

.vp-about-meta {
	min-width: 0;
	font-family: var(--vp-mono);
	font-size: 11px;
	letter-spacing: 0.2em;
	text-transform: uppercase;
	color: var(--vp-ink-dim);
}

.vp-about-body {
	min-width: 0;
	grid-column: span 2;
	display: flex;
	flex-direction: column;
	gap: 24px;
	font-size: clamp(16px, 1.35vw, 19px);
	line-height: 1.62;
	color: rgba(245, 239, 230, 0.88);
	max-width: 68ch;
}

.vp-about-body p {
	margin: 0;
}

.vp-btn {
	align-self: flex-start;
	margin-top: 8px;
	padding: 15px 30px;
	background: var(--vp-accent);
	color: var(--vp-bg);
	border-radius: 999px;
	font-family: var(--vp-mono);
	font-size: 12px;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	font-weight: 500;
}

.vp-btn:hover {
	background: var(--vp-ink);
	color: var(--vp-bg);
}

/* Two-column feature row ----------------------------------------------- */

.vp-cols {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr));
	gap: clamp(16px, 2.4vw, 34px);
	margin-top: clamp(44px, 6vw, 90px);
}

.vp-col {
	min-width: 0;
	padding-top: 20px;
	border-top: 1px solid var(--vp-rule);
}

.vp-col__title {
	font-size: clamp(26px, 3vw, 44px);
	font-weight: 500;
	letter-spacing: -0.02em;
}

.vp-col__text {
	margin: 12px 0 0;
	font-size: 16px;
	line-height: 1.6;
	color: rgba(245, 239, 230, 0.7);
}

/* Home hero ------------------------------------------------------------- */

/* The home page's hero is full-bleed, so .vp-main's own padding would push it
 * below the header instead of behind it, and inset it from the edges. The
 * sections below the hero get their gutter back on .vp-wrap, which otherwise
 * inherits none and would run to the viewport edge. */
.vp-main--home {
	padding-top: 0;
	padding-left: 0;
	padding-right: 0;
}

.vp-main--home .vp-wrap {
	padding-left: var(--vp-gutter);
	padding-right: var(--vp-gutter);
}

/* Two columns at desktop: the showreel on the left, the copy on the right.
 * The reel is portrait footage inside a 16:9 upload, so a full-bleed
 * background would be mostly black bars — it gets its own column instead.
 * svh rather than vh so mobile browser chrome does not crop it. */
/* No left gutter: the reel runs to the edge of the viewport, which both makes
 * it full-bleed on that side and gives the column the width back. The right
 * gutter stays so the heading and buttons are not flush against the screen. */
.vp-hero {
	position: relative;
	display: grid;
	grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
	align-items: stretch;
	gap: clamp(28px, 4vw, 64px);
	min-height: 100svh;
	padding: 104px var(--vp-gutter) clamp(28px, 4vw, 56px) 0;
	overflow: hidden;
}

.vp-hero__media {
	position: relative;
	z-index: 0;
	overflow: hidden;
	background: var(--vp-bg-raised);
}

/* A YouTube iframe is locked to 16:9. To fill a taller box without
 * letterboxing it is sized off the larger of two ratios and centred — the
 * same trick as object-fit:cover, which does not apply to iframes. */
/* Sized off the hero's own box (100%), not the viewport: 100vw includes the
 * scrollbar, so a vw-based width came out ~15px narrower than the box it is
 * meant to overfill and left a sliver of background at one edge. The larger of
 * the two ratios wins, which is object-fit:cover by hand — it does not apply
 * to iframes. The extra 2px absorbs sub-pixel rounding. */
/* The embed is 16:9 but only its middle 720/1280 carries picture — the rest
 * is pillarbox. To fill the column with picture alone, the iframe is sized so
 * its CONTENT area covers the box, which means the iframe itself is
 * 1280/720 = 1.778x wider than the column. The overflow, all of it black
 * bars, is clipped by .vp-hero__media.
 *
 * --vp-reel-content is the fraction of the embed's width that is picture;
 * measured from the maxres thumbnail. Set it to 1 for a normal full-frame
 * video and this collapses to ordinary cover behaviour. */
.vp-hero__video {
	--vp-reel-content: 0.5625; /* 720 / 1280 */

	position: absolute;
	top: 50%;
	left: 50%;
	aspect-ratio: 16 / 9;
	/* Height first: the picture is as tall as the embed, so matching the
	 * column's height is enough vertically. */
	min-height: calc(100% + 2px);
	/* Width: the picture must span the column, so the embed is scaled up by
	 * the inverse of the content fraction. */
	min-width: calc((100% + 2px) / var(--vp-reel-content));
	transform: translate(-50%, -50%);
	pointer-events: none;
}

.vp-hero__video iframe {
	width: 100%;
	height: 100%;
	display: block;
	border: 0;
}

/* Sound toggle, bottom-left of the reel. Sits above the scrim, and is the one
 * interactive thing inside the media column — the iframe itself has
 * pointer-events:none. */
.vp-sound {
	position: absolute;
	left: clamp(12px, 1.6vw, 20px);
	bottom: clamp(12px, 1.6vw, 20px);
	z-index: 2;

	display: inline-flex;
	align-items: center;
	gap: 9px;
	/* 44px minimum touch height. */
	min-height: 44px;
	padding: 0 18px 0 14px;

	background: rgba(16, 14, 12, 0.62);
	backdrop-filter: blur(8px);
	border: 1px solid rgba(245, 239, 230, 0.18);
	border-radius: 999px;
	color: var(--vp-ink);

	font-family: var(--vp-mono);
	font-size: 11px;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	cursor: pointer;
	transition: background-color 0.2s ease, border-color 0.2s ease;
}

.vp-sound:hover {
	background: rgba(16, 14, 12, 0.82);
	border-color: var(--vp-accent);
	color: var(--vp-accent);
}

.vp-sound__icon {
	display: flex;
}

.vp-sound__icon svg {
	width: 17px;
	height: 17px;
}

/* One icon per state: crossed-out speaker while muted, waves once audible.
 * Selected through .vp-sound__icon so these outrank the sizing rule above,
 * which would otherwise re-show both — it is the more specific selector. */
.vp-sound__icon .vp-sound__muted {
	display: block;
}

.vp-sound__icon .vp-sound__loud {
	display: none;
}

.vp-sound[aria-pressed='true'] .vp-sound__icon .vp-sound__muted {
	display: none;
}

.vp-sound[aria-pressed='true'] .vp-sound__icon .vp-sound__loud {
	display: block;
}

.vp-hero__media .vp-hero__poster {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* Darkens the footage enough for the copy to hold contrast, heaviest at the
 * bottom where the text sits and at the top behind the fixed header. */
/* pointer-events:none is required, not decorative. The scrim is positioned
 * with no z-index and comes AFTER the sound button in the DOM, so it paints
 * over it and would swallow every click — the button stays visible through
 * the gradient but is unreachable. z-index:1 keeps it above the video and
 * below the button's z-index:2. */
.vp-hero__scrim {
	position: absolute;
	inset: 0;
	z-index: 1;
	pointer-events: none;
	background: linear-gradient(
		180deg,
		rgba(16, 14, 12, 0.82) 0%,
		rgba(16, 14, 12, 0.35) 30%,
		rgba(16, 14, 12, 0.55) 68%,
		rgba(16, 14, 12, 0.92) 100%
	);
}

/* The right column. Takes the hero's full height so the copy centres against
 * the video while the meta strip stays pinned to the bottom as the scroll
 * cue. No longer overlaid, so it needs no max-width of its own — the grid
 * track sets its width. */
.vp-hero__inner {
	position: relative;
	z-index: 1;
	min-width: 0;
	display: flex;
	flex-direction: column;
}

/* Centred in the space above the meta strip. */
.vp-hero__copy {
	max-width: 1180px;
	margin-top: auto;
	margin-bottom: auto;
}

/* Sized against the column, not the viewport: at 6.4vw the heading ran to six
 * lines in the right-hand track. The ch cap is dropped for the same reason —
 * the track already limits the measure. */
.vp-hero__title {
	margin: 22px 0 0;
	font-size: clamp(30px, 3.4vw, 60px);
	line-height: 1.02;
	font-weight: 600;
	letter-spacing: -0.025em;
}

.vp-hero__actions {
	display: flex;
	align-items: center;
	gap: 20px;
	flex-wrap: wrap;
	margin-top: clamp(28px, 4vw, 44px);
}

/* The secondary action: a rule under the text rather than a second button. */
.vp-link-underline {
	font-family: var(--vp-mono);
	font-size: 12px;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	border-bottom: 1px solid rgba(245, 239, 230, 0.35);
	padding-bottom: 4px;
}

.vp-link-underline:hover {
	border-bottom-color: var(--vp-accent);
}

.vp-hero__meta {
	display: flex;
	justify-content: space-between;
	align-items: flex-end;
	gap: 18px;
	flex-wrap: wrap;
	margin-top: clamp(32px, 5vw, 70px);
	padding-top: 18px;
	border-top: 1px solid var(--vp-rule);
	font-family: var(--vp-mono);
	font-size: 10px;
	letter-spacing: 0.2em;
	text-transform: uppercase;
	color: var(--vp-ink-dim);
}

@media (prefers-reduced-motion: no-preference) {
	.vp-hero__scroll {
		animation: vp-scroll-hint 2.4s ease-in-out infinite;
	}
}

@keyframes vp-scroll-hint {
	0%,
	100% {
		transform: translateY(0);
		opacity: 0.35;
	}
	50% {
		transform: translateY(6px);
		opacity: 1;
	}
}

/* Mobile: the copy moves OUT of the video and sits beneath it.
 *
 * Overlaid text works at desktop width, where the heading has room beside the
 * footage. On a phone it covers most of the frame, so the section becomes two
 * stacked blocks — the reel at its native 16:9, uncropped, then the copy on
 * the page background. The scrim is dropped with the overlay, since nothing
 * needs to stay legible on top of the video any more. */
/* The hero stacks earlier than the rest of the site: two columns need real
 * width to be worth it, so tablets get the single-column treatment and only
 * desktop keeps the side-by-side layout. 1023px, not the 859px used for the
 * nav drawer and the other grids, which stay where they are. */
@media (max-width: 1023px) {
	/* display:block undoes the desktop grid, so the two columns stack: reel
	 * first, then the copy. The copy's auto margins and the meta strip's
	 * bottom pinning stop applying too. */
	.vp-hero {
		display: block;
		min-height: 0;
		/* Clears the fixed header; the video starts below it, not behind it. */
		padding: 104px 0 0;
	}

	/* Square, matching the reel's actual picture area rather than the 16:9
	 * embed — a 16:9 box here would be mostly pillarbox.
	 *
	 * No max-height: capping the height of a fixed-ratio box also caps its
	 * WIDTH, which left the reel short of the viewport edge on a tablet and
	 * clipped the sound button against the media box. Height is limited by
	 * flattening the ratio on wide-but-short viewports instead, which keeps
	 * the reel full-bleed either way. */
	.vp-hero__media {
		aspect-ratio: 1 / 1;
	}

	/* A square reel is taller than a tablet screen once it spans the width, so
	 * above ~700px it flattens to 4:3 — still far from the 16:9 embed, so the
	 * pillarbox stays cropped, but the copy below is reachable without a long
	 * scroll. */
	@media (min-width: 700px) {
		.vp-hero__media {
			aspect-ratio: 4 / 3;
		}
	}

	.vp-hero__scrim {
		display: none;
	}

	.vp-hero__inner {
		padding: clamp(28px, 7vw, 44px) var(--vp-gutter) 0;
	}

	/* Full width once stacked, so it can run larger than in the desktop column. */
	.vp-hero__title {
		font-size: clamp(30px, 5.2vw, 52px);
	}

	.vp-hero__meta {
		flex-direction: column;
		align-items: flex-start;
		gap: 10px;
	}
}

@media (max-width: 859px) {
	/* These sit in auto-fit grids that collapse to a single column here, where
	 * `span 2` asks for a track that does not exist. The browser creates an
	 * implicit second column and the text runs past the viewport edge. */
	.vp-statement__text,
	.vp-about-body {
		grid-column: auto;
	}
}

/* Home sections --------------------------------------------------------- */

.vp-statement {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
	gap: clamp(28px, 5vw, 80px);
	align-items: start;
	padding: clamp(72px, 11vw, 168px) 0;
}

.vp-statement__label {
	font-family: var(--vp-mono);
	font-size: 11px;
	letter-spacing: 0.2em;
	text-transform: uppercase;
	color: var(--vp-ink-dim);
}

.vp-statement__text {
	margin: 0;
	grid-column: span 2;
	min-width: 0;
	font-size: clamp(26px, 3.9vw, 58px);
	line-height: 1.1;
	font-weight: 500;
	letter-spacing: -0.02em;
}

.vp-services {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
	gap: clamp(28px, 5vw, 80px);
	padding: clamp(72px, 10vw, 150px) 0;
	border-top: 1px solid var(--vp-rule-soft);
}

.vp-services__intro {
	min-width: 0;
}

.vp-services__title {
	margin: 20px 0 0;
	font-size: clamp(24px, 3vw, 42px);
	line-height: 1.12;
	font-weight: 500;
	letter-spacing: -0.02em;
}

.vp-services__intro .vp-link-underline {
	display: inline-block;
	margin-top: 26px;
}

.vp-services__list {
	min-width: 0;
	display: flex;
	flex-direction: column;
}

.vp-services__row {
	display: flex;
	justify-content: space-between;
	gap: 16px;
	padding: 20px 0;
	border-top: 1px solid var(--vp-rule);
	font-size: clamp(17px, 1.5vw, 22px);
}

.vp-services__row:last-child {
	border-bottom: 1px solid var(--vp-rule);
}

.vp-services__num {
	font-family: var(--vp-mono);
	font-size: 10px;
	letter-spacing: 0.18em;
	color: var(--vp-ink-dim);
}

/* Portfolio grid -------------------------------------------------------- */

/* Three columns. The hero spans the first two of the top row, one tile sits
 * beside it, and the remaining tiles plus the Instagram cell fill the row
 * below. Rows are sized by the tiles' own aspect ratios rather than a fixed
 * height, so the hero keeps a 16:9 shape and the small tiles are 4:5. */
.vp-work-grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: clamp(12px, 1.6vw, 22px);
	margin-top: clamp(40px, 6vw, 86px);
}

/* Grid items stretch to their row by default, which would pull the media box
 * taller than its aspect-ratio and leave the image sitting in dead space.
 * start keeps each tile its own intrinsic height. */
.vp-work {
	display: block;
	min-width: 0;
	align-self: start;
}

.vp-work--hero {
	grid-column: span 2;
}

/* The hero is 16:9 and spans two columns, so at three equal columns its media
 * box is (2 units wide) / (16/9) tall. The tile beside it is one unit wide and
 * must reach the same height to square off the row, which works out at 8:9.
 * The bottom row is then three equal 4:5 tiles.
 *
 * These are set as ratios rather than fixed heights so the row scales with the
 * viewport; the gap between columns makes the match approximate rather than
 * exact, which is why the top row uses align-items:stretch below.
 *
 * 16:9 throughout, matching the stills themselves (1.67–1.72) rather than the
 * canvas's 4:5 placeholder tiles. Forcing these landscape frames into portrait
 * boxes discarded over half the width of each one; at 16:9 they are shown
 * nearly whole, and the bottom row sits at its natural height instead of
 * towering over its content. */
.vp-work__media {
	position: relative;
	overflow: hidden;
	background: var(--vp-bg-raised);
	aspect-ratio: 16 / 9;
}

/* The tile beside the hero must reach the hero's height to square off the top
 * row. Rather than guessing a ratio — the column gap makes any fixed ratio an
 * approximation — the tile stretches to the row and its media box fills that
 * height, with the aspect-ratio dropped so it does not fight the stretch. */
.vp-work--tall {
	align-self: stretch;
	display: flex;
	flex-direction: column;
}

.vp-work--tall .vp-work__media {
	aspect-ratio: auto;
	flex: 1;
}

/* Pinned to the media box, and selected via .vp-work__media so it outranks the
 * `.vp-body img { height: auto }` reset near the top of this file. That reset
 * was collapsing every tile image to its intrinsic height — a 4:5 box 529px
 * tall held a 252px image, leaving the lower half of each tile empty.
 * Confirmed by isolating the pair: the pattern measures correctly on its own,
 * and reproduces the 529/252 split the moment the reset is added. */
.vp-work__media .vp-work__img {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
	transition: transform 0.6s cubic-bezier(0.22, 0.61, 0.36, 1);
}

.vp-work:hover .vp-work__media .vp-work__img {
	transform: scale(1.04);
}

.vp-work__meta {
	display: flex;
	justify-content: space-between;
	gap: 12px;
	margin-top: 12px;
	font-family: var(--vp-mono);
	font-size: 10px;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var(--vp-ink-dim);
	transition: color 0.2s ease;
}

.vp-work:hover .vp-work__meta {
	color: var(--vp-ink);
}

/* The Instagram cell fills what would otherwise be a gap at the end of the
 * bottom row. It is a call to action, not a photograph, so it is outlined
 * rather than filled — four stills plus one solid block would read as an
 * error. */
.vp-work__media--more {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 14px;
	padding: 20px;
	text-align: center;
	background: none;
	border: 1px solid var(--vp-rule);
	transition: border-color 0.2s ease, background-color 0.2s ease;
}

.vp-work--more:hover .vp-work__media--more {
	border-color: var(--vp-accent);
	background: rgba(184, 134, 90, 0.06);
}

.vp-work__icon {
	display: block;
	color: var(--vp-ink-dim);
	transition: color 0.2s ease;
}

.vp-work__icon .vp-icon {
	width: 28px;
	height: 28px;
}

.vp-work--more:hover .vp-work__icon {
	color: var(--vp-accent);
}

.vp-work__more-text {
	max-width: 14ch;
	font-family: var(--vp-mono);
	font-size: 11px;
	line-height: 1.5;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--vp-ink-dim);
}

/* Closing row under the grid. */
.vp-work-foot {
	display: flex;
	justify-content: space-between;
	align-items: baseline;
	gap: 20px;
	flex-wrap: wrap;
	margin-top: clamp(40px, 6vw, 86px);
	padding-top: 26px;
	border-top: 1px solid var(--vp-rule);
}

.vp-work-foot__link {
	font-size: clamp(20px, 2.6vw, 36px);
	font-weight: 500;
	letter-spacing: -0.02em;
}

.vp-work-foot__link:hover {
	color: var(--vp-accent);
}

.vp-work-foot__cta {
	font-family: var(--vp-mono);
	font-size: 11px;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var(--vp-ink-dim);
}

.vp-work-foot__cta:hover {
	color: var(--vp-accent);
}

/* Below the breakpoint three columns are too narrow to read. Two columns,
 * with the hero spanning both so it stays the lead image. */
@media (max-width: 859px) {
	.vp-work-grid {
		grid-template-columns: repeat(2, 1fr);
	}

	.vp-work--hero {
		grid-column: span 2;
	}
}

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

.vp-footer {
	padding: clamp(48px, 6vw, 80px) var(--vp-gutter) 30px;
	border-top: 1px solid var(--vp-rule-soft);
}

.vp-footer__grid {
	max-width: var(--vp-max);
	margin: 0 auto;
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr));
	gap: clamp(28px, 4vw, 60px);
}

.vp-footer__col {
	min-width: 0;
}

.vp-footer__contact {
	font-size: 15px;
	line-height: 1.8;
	color: rgba(245, 239, 230, 0.7);
}

.vp-footer__social {
	display: flex;
	gap: 10px;
	margin-top: 18px;
}

/* Brand marks, not text. The colour is set explicitly rather than inherited:
 * the marks are drawn with fill:currentColor, so an ancestor that sets no
 * colour would render them in the browser's default link blue. */
.vp-footer__social a {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 34px;
	height: 34px;
	border: 1px solid var(--vp-rule);
	border-radius: 50%;
	color: var(--vp-ink-dim);
	transition: color 0.2s ease, border-color 0.2s ease;
}

.vp-footer__social a:hover {
	color: var(--vp-ink);
	border-color: var(--vp-ink-dim);
}

.vp-footer__social .vp-icon {
	width: 15px;
	height: 15px;
}

.vp-footer__heading {
	font-family: var(--vp-mono);
	font-size: 10px;
	letter-spacing: 0.2em;
	text-transform: uppercase;
	color: var(--vp-ink-dim);
	margin-bottom: 16px;
}

.vp-footer__list {
	display: flex;
	flex-direction: column;
	gap: 9px;
	font-size: 15px;
}

.vp-footer__list span {
	color: rgba(245, 239, 230, 0.7);
}

.vp-footer__legal {
	max-width: var(--vp-max);
	margin: clamp(36px, 5vw, 64px) auto 0;
	padding-top: 22px;
	border-top: 1px solid var(--vp-rule-soft);
	font-family: var(--vp-mono);
	font-size: 10px;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--vp-ink-faint);
}

/* Once the footer columns stack they read as one centred block, matching the
 * contact details above. text-align handles the text, but the logo, the social
 * icons and the link lists are flex containers whose children need their own
 * centring. Same 859px breakpoint as the nav and the contact grid. */
@media (max-width: 859px) {
	.vp-footer {
		text-align: center;
	}

	.vp-logo--footer {
		display: flex;
		justify-content: center;
	}

	.vp-footer__social,
	.vp-footer__list {
		align-items: center;
	}

	.vp-footer__social {
		justify-content: center;
	}
}

/* Contact --------------------------------------------------------------- */

.vp-contact-grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
	gap: clamp(32px, 5vw, 80px);
	margin-top: clamp(44px, 6vw, 90px);
}

.vp-contact-details {
	min-width: 0;
	display: flex;
	flex-direction: column;
	gap: 30px;
	/* Details are shorter than the form (Fusion 1610 has five fields to the
	 * canvas's three), so they sit at the top of the row rather than being
	 * stretched down its full height. */
	align-self: start;
}

/* Full ink rather than the canvas's dim tone: at 10px mono, uppercase and
 * letter-spaced, the dim colour and the light weight compound into something
 * hard to read. The colour on its own was not the problem. */
.vp-contact-item__label {
	margin-bottom: 10px;
	font-family: var(--vp-mono);
	font-size: 10px;
	letter-spacing: 0.2em;
	text-transform: uppercase;
	color: var(--vp-ink);
}

.vp-contact-item__value {
	display: inline-block;
	font-weight: 500;
	letter-spacing: -0.02em;
	line-height: 1.25;
}

/* Phone and email are set at different sizes in the canvas: the number is the
 * larger of the two, and the address steps down so it still fits its column. */
.vp-contact-item__value--phone {
	font-size: clamp(22px, 2.4vw, 34px);
}

.vp-contact-item__value--email {
	font-size: clamp(18px, 1.9vw, 28px);
	/* Long addresses must not force a horizontal scrollbar on narrow screens. */
	word-break: break-word;
}

.vp-contact-item__value:hover {
	color: var(--vp-accent);
}

.vp-contact-item__links {
	display: flex;
	flex-wrap: wrap;
	gap: 14px;
}

/* Social links are bordered pills here, unlike the plain text links used in
 * the footer. */
.vp-pill {
	padding: 11px 20px;
	border: 1px solid rgba(245, 239, 230, 0.24);
	border-radius: 999px;
	font-family: var(--vp-mono);
	font-size: 11px;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	transition: border-color 0.2s ease, color 0.2s ease;
}

.vp-pill:hover {
	border-color: var(--vp-accent);
	color: var(--vp-accent);
}

/* Inlined brand marks. Size is set per context; this only fixes the box so
 * the SVG does not inherit a text line-height. */
.vp-icon {
	display: block;
}

.vp-contact-fallback {
	margin: 0 0 22px;
	font-size: 16px;
	line-height: 1.6;
	color: rgba(245, 239, 230, 0.7);
}

/* Once the two columns stack, the page header and the details read as one
 * centred block above the form. The form itself stays left-aligned — centred
 * field labels would be harder to scan. Same 859px breakpoint as the nav.
 *
 * Scoped to the contact template via .vp-main[data-screen-label="Contact"]
 * so the shared .vp-eyebrow / .vp-h1 rules are untouched on other pages. */
@media (max-width: 859px) {
	.vp-main[data-screen-label="Contact"] .vp-eyebrow,
	.vp-main[data-screen-label="Contact"] .vp-h1 {
		text-align: center;
	}

	.vp-contact-details {
		text-align: center;
	}

	.vp-contact-item__links {
		justify-content: center;
	}
}

/* Fusion Form 1610 ------------------------------------------------------ */

/* The form is rendered by Fusion Core. Rather than out-specifying its rules
 * one by one, this sets the CSS custom properties they already read from
 * (fusion-builder/assets/css/fusion-form.min.css): Fusion's own selectors
 * resolve --awb-form-* and --awb-label-typo-* off the wrapper, so redefining
 * them here restyles the form through its own mechanism. Its defaults chain up
 * to Avada's global theme options (--form_bg_color, --body_typography-*),
 * which do not exist once Avada's stylesheet is dequeued — hence the flat,
 * unstyled fields. */

/* The canvas puts the form in a raised, bordered panel — it is what balances
 * the contact details in the left column. Inputs are then the page background,
 * one step darker than the panel they sit in. */
.vp-contact-form {
	min-width: 0;
	padding: clamp(20px, 3vw, 36px);
	background: var(--vp-bg-raised);
	border: 1px solid var(--vp-rule);
}

.vp-contact-form .fusion-form-form-wrapper,
.vp-contact-form .fusion-column-wrapper {
	/* Fields */
	--awb-form-bg-color: var(--vp-bg);
	--awb-form-text-color: var(--vp-ink);
	--awb-form-placeholder-color: var(--vp-ink-faint);
	--awb-form-font-size: 16px;
	/* Fusion sets a fixed height on inputs, which wins over padding on a less
	 * specific rule; an explicit height is set here instead of fighting it.
	 * The textarea is exempted below — it must stay free to grow. */
	--awb-form-input-height: 48px;
	--awb-form-border-color: rgba(245, 239, 230, 0.18);
	--awb-form-focus-border-color: var(--vp-accent);
	--awb-form-border-width-top: 1px;
	--awb-form-border-width-right: 1px;
	--awb-form-border-width-bottom: 1px;
	--awb-form-border-width-left: 1px;
	/* Square corners, per the canvas. */
	--awb-form-border-radius: 0;

	/* Labels */
	--awb-form-label-color: var(--vp-ink);
	--awb-label-typo-font-family: var(--vp-mono);
	--awb-label-font-size: 10px;
	--awb-label-typo-font-weight: 400;
	--awb-label-typo-line-height: 1.4;
	--awb-label-typo-letter-spacing: 0.2em;
	--awb-label-typo-text-transform: uppercase;

	/* Row rhythm */
	--awb-field-margin-top: 0;
	--awb-field-margin-bottom: 18px;
}

/* Fusion sets border WIDTH and COLOR from the variables above but never
 * border-style — it inherits that from Avada's reset, which is dequeued here,
 * so without this the fields render borderless. */
.vp-contact-form .fusion-form-input {
	box-sizing: border-box;
	border-style: solid;
	padding: 13px 14px;
	font-family: var(--vp-sans);
	line-height: 1.4;
	letter-spacing: 0;
	transition: border-color 0.2s ease;
}

.vp-contact-form .fusion-form-input:focus {
	outline: none;
	border-color: var(--vp-accent);
}

.vp-contact-form .fusion-form-input::placeholder {
	color: var(--vp-ink-faint);
}

/* Canvas uses rows="5"; Fusion prints rows="4", so the height is set here.
 * The height must be reset from the fixed input height set on the wrapper. */
.vp-contact-form textarea.fusion-form-input {
	height: auto;
	min-height: 132px;
	padding-top: 13px;
	padding-bottom: 13px;
	resize: vertical;
}

/* Select: the native arrow is hidden so Fusion's own SVG arrow is the only
 * one shown; it is positioned by .select-arrow below. */
.vp-contact-form .fusion-select-wrapper {
	position: relative;
}

.vp-contact-form select.fusion-form-input {
	appearance: none;
	padding-right: 44px;
	cursor: pointer;
}

.vp-contact-form .select-arrow {
	position: absolute;
	top: 50%;
	right: 16px;
	transform: translateY(-50%);
	display: flex;
	pointer-events: none;
}

/* Fusion's inline SVG arrow carries a hardcoded grey stroke. */
.vp-contact-form .select-arrow svg path {
	stroke: var(--vp-ink-dim);
}

/* The dropdown list itself is painted by the OS, not by this stylesheet, so
 * the options need their own colours to stay readable on a dark form. */
.vp-contact-form select.fusion-form-input option {
	background: var(--vp-bg-raised);
	color: var(--vp-ink);
}

/* Submit: Fusion prints .fusion-button with an inline --awb-margin-bottom.
 * The margin is overridden on the wrapper instead of fighting the inline
 * custom property on the button itself. */
.vp-contact-form .fusion-form-submit-field {
	margin-bottom: 0;
}

.vp-contact-form .fusion-button {
	display: inline-block;
	margin: 4px 0 0;
	padding: 15px 30px;
	background: var(--vp-accent);
	border: 0;
	border-radius: 999px;
	color: var(--vp-bg);
	font-family: var(--vp-mono);
	font-size: 12px;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	font-weight: 500;
	cursor: pointer;
	transition: background-color 0.2s ease, color 0.2s ease;
}

.vp-contact-form .fusion-button:hover {
	background: var(--vp-ink);
	color: var(--vp-bg);
}

/* Notices — BOTH the success and error alerts are present in the DOM from
 * page load; Avada's dequeued stylesheet is what normally hides them. Without
 * this rule the page shows "Thank you for your message" AND "There was an
 * error" stacked above the form before anything is submitted. Fusion's JS
 * reveals the relevant one by setting an inline display on submit, which
 * beats this rule. */
.vp-contact-form .fusion-form-response {
	display: none;
	margin-top: 20px;
	padding: 16px 18px;
	border: 1px solid var(--vp-rule);
	border-radius: 4px;
	font-size: 15px;
	line-height: 1.5;
}

.vp-contact-form .fusion-form-response-success {
	border-color: var(--vp-accent);
	color: var(--vp-ink);
}

.vp-contact-form .fusion-form-response-error {
	border-color: #c2553f;
	color: #e9a294;
}

.vp-contact-form .fusion-alert-content-wrapper {
	display: flex;
	align-items: center;
	gap: 10px;
}

/* The dismiss button is a bare glyph once Avada's button styling is gone. */
.vp-contact-form .fusion-alert .close {
	margin-left: auto;
	padding: 0 4px;
	background: none;
	border: 0;
	color: inherit;
	font-size: 18px;
	line-height: 1;
	cursor: pointer;
	opacity: 0.6;
}

.vp-contact-form .fusion-alert .close:hover {
	opacity: 1;
}

/* Avada's row wrapper carries its grid gutter hack inline:
 *
 *   style="width:104% !important; max-width:104% !important;
 *          margin-left: calc(-4% / 2); margin-right: calc(-4% / 2)"
 *
 * The negative margins are what pull the form past this panel's padding, and
 * they are plain inline styles, so zeroing them here wins on the cascade.
 *
 * width and max-width are deliberately NOT set: they are inline AND
 * !important, so no external stylesheet rule can override them. An earlier
 * version of this rule set width:auto and max-width:none, which could never
 * apply. Overriding them would require !important here too; the extra 4% has
 * shown no visible effect at 1440/820/390 once the margins are zeroed, so it
 * is left alone rather than met with a competing !important.
 *
 * box-sizing is set because Avada's reset supplied it and is dequeued here;
 * without it the column's own padding would widen the box. */
.vp-contact-form .fusion-builder-row,
.vp-contact-form .fusion-layout-column {
	box-sizing: border-box;
	margin-left: 0;
	margin-right: 0;
	padding-left: 0;
	padding-right: 0;
	float: none;
}

/* Scroll reveal -------------------------------------------------------- */

/* The hidden start state applies only once videre.js has marked the document
 * as JS-capable, so a script failure leaves the content visible rather than
 * blank. Reduced-motion users skip the animation entirely. */
@media (prefers-reduced-motion: no-preference) {
	.vp-js .vp-reveal {
		opacity: 0;
		transform: translateY(26px);
		transition: opacity 0.9s cubic-bezier(0.22, 0.61, 0.36, 1),
			transform 0.9s cubic-bezier(0.22, 0.61, 0.36, 1);
	}

	.vp-js .vp-reveal.is-visible {
		opacity: 1;
		transform: none;
	}
}
