/* ==========================================================================
   VistaVoyages — main stylesheet
   1. Tokens
   2. Reset and base
   3. Typography
   4. Layout primitives
   5. Buttons and links
   6. Header
   7. Footer
   8. Cards and grids
   9. Page components
   10. Forms
   11. Prose
   12. Utilities
   ========================================================================== */

/* 1. Tokens ---------------------------------------------------------------- */

:root {
	/* Palette. Hex first as a fallback; oklch wins wherever it is understood. */
	--vv-cream: #faf5ec;
	--vv-cream: oklch(97% 0.018 85);
	--vv-ink: #0d1f20;
	--vv-ink: oklch(18% 0.03 190);
	--vv-deep: #103330;
	--vv-deep: oklch(28% 0.055 190);
	--vv-deep-fg: #fbf6ea;
	--vv-deep-fg: oklch(97% 0.02 90);
	--vv-coral: #f4835e;
	--vv-coral: oklch(72% 0.17 35);
	--vv-coral-fg: #0b1c1d;
	--vv-coral-fg: oklch(16% 0.03 190);
	--vv-jade: #2e8168;
	--vv-jade: oklch(55% 0.11 165);

	--vv-bg: var(--vv-cream);
	--vv-fg: var(--vv-ink);
	/* Raised surfaces — cards, fields, panels. Warm rather than pure white:
	   #fff is the only cold tone on a cream page and reads as a foreign object
	   sitting on top of it. Still lighter than the background, so a card is
	   plainly lifted off it. */
	--vv-surface: #fdfaf4;
	--vv-surface: oklch(99.2% 0.007 85);
	--vv-muted: #f1ebe1;
	--vv-muted: oklch(94% 0.015 85);
	--vv-muted-fg: #5b6b70;
	--vv-muted-fg: oklch(45% 0.02 200);
	--vv-border: #ddd5c8;
	--vv-border: oklch(87% 0.02 85);
	--vv-danger: #c63a2c;
	--vv-danger: oklch(55% 0.22 25);

	--vv-accent: var(--vv-coral);
	--vv-primary: var(--vv-deep);
	--vv-primary-fg: var(--vv-deep-fg);

	/* Type */
	--vv-font-serif: "Fraunces", ui-serif, Georgia, "Times New Roman", serif;
	--vv-font-sans: "Manrope", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
	--vv-font-mono: ui-monospace, "JetBrains Mono", SFMono-Regular, Menlo, monospace;

	/* Rhythm */
	--vv-container: 82rem;
	--vv-gutter: 1.5rem;
	--vv-radius: 0.25rem;
	/* Standalone imagery — the hero, editorial banners and the package shot.
	   Cards keep the tighter --vv-radius of the box they sit in. */
	--vv-radius-media: 10px;
	--vv-section-y: 4rem;
	--vv-section-y-lg: 5rem;

	--vv-ease: cubic-bezier(0.4, 0, 0.2, 1);
	--vv-transition: 0.15s var(--vv-ease);

	/* Uppercase labels — eyebrows, definition terms, button text. Held at 12px:
	   below that, wide letter-spacing stops helping and starts hurting. */
	--vv-label-size: 0.75rem;

	/* Smallest comfortable target for a finger. */
	--vv-tap: 44px;
}

/* 2. Reset and base -------------------------------------------------------- */

*,
*::before,
*::after {
	box-sizing: border-box;
}

* {
	margin: 0;
}

html {
	-webkit-text-size-adjust: 100%;
	scroll-behavior: smooth;
	/* Nothing in the design is meant to scroll sideways; `clip` keeps position:
	   sticky working, which `hidden` would break. */
	overflow-x: clip;
}

@media (prefers-reduced-motion: reduce) {
	html {
		scroll-behavior: auto;
	}

	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
	}
}

body {
	position: relative;
	background-color: var(--vv-bg);
	color: var(--vv-fg);
	font-family: var(--vv-font-sans);
	font-size: 1rem;
	line-height: 1.6;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	text-rendering: optimizeLegibility;
}

/* A fine grain over the whole page. Flat cream reads as a blank screen; a
   little tooth makes it read as paper. Inline SVG, so no request and no weight
   worth measuring. */
body::before {
	content: "";
	position: fixed;
	inset: 0;
	z-index: 0;
	pointer-events: none;
	opacity: 0.035;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* Everything else sits above the grain. */
.site {
	position: relative;
	z-index: 1;
}

img,
picture,
video,
canvas,
svg {
	display: block;
	max-width: 100%;
	height: auto;
}

input,
button,
textarea,
select {
	font: inherit;
	color: inherit;
}

a {
	color: inherit;
	text-decoration-thickness: 1px;
	text-underline-offset: 0.25em;
}

ul,
ol {
	padding: 0;
	list-style: none;
}

hr {
	border: 0;
	border-top: 1px solid var(--vv-border);
	margin: 2.5rem 0;
}

/* `[tabindex="-1"]` is focused by script, not by the keyboard — WooCommerce
   does it to announce notices — so it should not draw a focus ring. */
:where(a, button, input, textarea, select, summary, [tabindex]):not([tabindex="-1"]):focus-visible {
	outline: 2px solid var(--vv-accent);
	outline-offset: 3px;
	border-radius: 2px;
}

.skip-link {
	position: absolute;
	left: -9999px;
	top: 0;
	z-index: 100;
	background: var(--vv-primary);
	color: var(--vv-primary-fg);
	padding: 0.75rem 1.25rem;
	font-size: 0.875rem;
}

.skip-link:focus {
	left: 1rem;
	top: 1rem;
}

.screen-reader-text {
	position: absolute !important;
	width: 1px;
	height: 1px;
	padding: 0;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

/* 3. Typography ------------------------------------------------------------ */

h1,
h2,
h3,
h4,
h5,
h6 {
	font-family: var(--vv-font-serif);
	font-optical-sizing: auto;
	font-weight: 400;
	letter-spacing: -0.02em;
	line-height: 1.15;
	text-wrap: balance;
}

.t-display {
	font-family: var(--vv-font-serif);
	/* Was floored at 36px, which put the hero headline on five lines at 360px.
	   The floor now tracks the viewport down to ~31px before it stops. */
	font-size: clamp(1.9rem, 1.25rem + 3.4vw, 3.75rem);
	line-height: 1.05;
	/* Headings default to `balance`, which evens the lines out and leaves the
	   first one visibly short. The hero headline fills each line instead. */
	text-wrap: pretty;
}

.t-h2 {
	font-family: var(--vv-font-serif);
	font-size: clamp(1.75rem, 1.4rem + 1.6vw, 2.25rem);
}

.t-h3 {
	font-family: var(--vv-font-serif);
	font-size: 1.25rem;
}

.t-lead {
	font-size: 1.125rem;
	color: var(--vv-muted-fg);
	max-width: 36rem;
	text-wrap: pretty;
}

.eyebrow {
	font-family: var(--vv-font-sans);
	font-size: var(--vv-label-size);
	font-weight: 700;
	letter-spacing: 0.28em;
	text-transform: uppercase;
	line-height: 1.4;
}

.eyebrow--accent {
	color: var(--vv-accent);
}

.t-muted {
	color: var(--vv-muted-fg);
}

.t-small {
	font-size: 0.875rem;
}

.t-xs {
	font-size: 0.8125rem;
}

.t-serif {
	font-family: var(--vv-font-serif);
}

/* 4. Layout primitives ----------------------------------------------------- */

.container {
	max-width: var(--vv-container);
	margin-inline: auto;
	padding-inline: var(--vv-gutter);
}

.container--narrow {
	max-width: 48rem;
}

/* Single-column pages: the whole page sits in one centred measure rather than
   hugging the left edge of a wide container. 48rem keeps body copy just inside
   a comfortable line length, so the prose can fill the column instead of
   sitting in a narrower block of its own. */
.is-column .container {
	max-width: 48rem;
}

/* The modifier sits on the header and on the section, so the header's own
   caps are cleared from inside it. */
.is-column .prose,
.is-column .page-hero__inner h1,
.is-column .page-hero__inner .t-lead {
	max-width: none;
}

/* One continuous column: the rule and the double padding between the header and
   the body belong to pages where the two are different kinds of block. */
.page-hero.is-column {
	border-bottom: 0;
}

.page-hero.is-column .page-hero__inner {
	padding-bottom: 0;
}

.section.is-column .section__inner {
	padding-top: 3.5rem;
}

.section {
	border-bottom: 1px solid var(--vv-border);
}

.section__inner {
	padding-block: var(--vv-section-y);
}

/* A muted band is lit slightly from the top so it reads as a surface rather
   than a flat fill. */
.section--muted {
	background-color: color-mix(in oklab, var(--vv-muted) 70%, var(--vv-bg));
	background-image: linear-gradient(
		to bottom,
		color-mix(in oklab, var(--vv-bg) 55%, transparent),
		transparent 42%
	);
}

.section--deep {
	background-color: var(--vv-primary);
	color: var(--vv-primary-fg);
	border-bottom-color: transparent;
}

.section--deep .t-muted,
.section--deep .t-lead {
	color: color-mix(in oklab, var(--vv-primary-fg) 72%, transparent);
}

.section__head {
	display: flex;
	flex-wrap: wrap;
	align-items: flex-end;
	justify-content: space-between;
	gap: 1rem 2rem;
	margin-bottom: 2.5rem;
}


.section__head > div {
	max-width: 40rem;
}

.section__head p {
	margin-top: 0.75rem;
}

/* Padding grows the hit area to 44px; the matching negative margin means the
   link still sits on its own baseline in the layout. */
.section__link {
	display: inline-flex;
	align-items: center;
	min-height: var(--vv-tap);
	margin-block: -0.7rem;
	font-size: 0.875rem;
	text-decoration: underline;
	text-underline-offset: 4px;
	white-space: nowrap;
}

.section__link:hover {
	color: var(--vv-accent);
}

.stack > * + * {
	margin-top: var(--vv-stack-gap, 1rem);
}

/* 5. Buttons and links ----------------------------------------------------- */

.btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.5rem;
	border: 1px solid transparent;
	border-radius: 999px;
	min-height: var(--vv-tap);
	padding: 0.75rem 1.5rem;
	font-size: 0.8125rem;
	font-weight: 600;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	text-decoration: none;
	line-height: 1.2;
	cursor: pointer;
	transition: opacity var(--vv-transition), background-color var(--vv-transition), color var(--vv-transition);
}

.btn--primary {
	background-color: var(--vv-primary);
	color: var(--vv-primary-fg);
}

.btn--primary:hover {
	opacity: 0.9;
}

.btn--accent {
	background-color: var(--vv-coral);
	color: var(--vv-coral-fg);
}

.btn--accent:hover {
	opacity: 0.9;
}

/* The border tone used for rules is too faint to read as a control on the
   cream background, so the outline button darkens it. */
.btn--outline {
	border-color: color-mix(in oklab, var(--vv-ink) 30%, var(--vv-border));
	background-color: transparent;
}

.btn--outline:hover {
	background-color: var(--vv-muted);
}

.section--deep .btn--outline {
	border-color: color-mix(in oklab, var(--vv-primary-fg) 35%, transparent);
	color: var(--vv-primary-fg);
}

.section--deep .btn--outline:hover {
	background-color: color-mix(in oklab, var(--vv-primary-fg) 12%, transparent);
}

/* The small pill keeps its compact look. On a touch screen an invisible
   extender brings the hit area up to 44px without changing the layout. */
.btn--sm {
	position: relative;
	min-height: 0;
	padding: 0.5rem 1rem;
	font-size: var(--vv-label-size);
	letter-spacing: 0.16em;
}

/* Applied at every width rather than behind a coarse-pointer query: touch
   laptops report a fine pointer, and a larger click area never hurt a mouse. */
.btn--sm::after,
.chip::after {
	content: "";
	position: absolute;
	top: 50%;
	left: 50%;
	width: 100%;
	height: var(--vv-tap);
	min-width: var(--vv-tap);
	transform: translate(-50%, -50%);
}

.btn-row {
	display: flex;
	flex-wrap: wrap;
	gap: 1rem;
	margin-top: 2rem;
}

.link-underline {
	display: inline-block;
	padding-block: 0.7rem;
	margin-block: -0.7rem;
	text-decoration: underline;
	text-underline-offset: 4px;
}

.link-underline:hover {
	color: var(--vv-accent);
}

/* 6. Header ---------------------------------------------------------------- */

.site-header {
	position: sticky;
	top: 0;
	z-index: 40;
	border-bottom: 1px solid color-mix(in oklab, var(--vv-border) 60%, transparent);
	background-color: color-mix(in oklab, var(--vv-bg) 90%, transparent);
	backdrop-filter: blur(10px);
	-webkit-backdrop-filter: blur(10px);
	transition: box-shadow var(--vv-transition), border-color var(--vv-transition);
}

/* Once the page has moved under it, the bar earns a hairline of separation. */
.is-scrolled .site-header {
	border-bottom-color: var(--vv-border);
	box-shadow: 0 10px 24px -22px rgba(0, 0, 0, 0.5);
}

.site-header__inner {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 0.75rem 1.5rem;
	padding-block: 0.75rem;
}

.brand {
	display: flex;
	align-items: baseline;
	gap: 0.5rem;
	min-width: 0;
	padding-block: 0.65rem;
	margin-block: -0.65rem;
	text-decoration: none;
}

.brand__name {
	font-family: var(--vv-font-serif);
	font-size: 1.25rem;
	letter-spacing: -0.02em;
}

.brand__name em {
	font-style: italic;
	color: var(--vv-accent);
}

.brand__tagline {
	display: none;
	font-size: 0.65rem;
	text-transform: uppercase;
	letter-spacing: 0.2em;
	color: var(--vv-muted-fg);
}

.brand img {
	max-height: 40px;
	width: auto;
}

.primary-nav {
	order: 3;
	width: 100%;
}

.primary-nav ul {
	display: flex;
	align-items: center;
	gap: 1.25rem;
	padding-block: 0.25rem;
	font-size: 0.875rem;
}

.primary-nav a {
	display: block;
	color: var(--vv-muted-fg);
	text-decoration: none;
	transition: color var(--vv-transition);
}

.primary-nav a:hover {
	color: var(--vv-fg);
}

/* The rule opens from the middle of the link out to its full width. One
   mechanism marks both hover and the current page, so there is never a second
   line under either. */
@media (min-width: 1160px) {
	.primary-nav a {
		position: relative;
	}

	.primary-nav a::after {
		content: "";
		position: absolute;
		left: 0;
		right: 0;
		bottom: -0.5rem;
		height: 1px;
		background: var(--vv-accent);
		transform: scaleX(0);
		transform-origin: center;
		transition: transform 0.3s var(--vv-ease);
	}

	.primary-nav a:hover::after,
	.primary-nav a:focus-visible::after,
	.primary-nav [aria-current="page"]::after,
	.primary-nav .current-menu-item > a::after,
	.primary-nav .current_page_parent > a::after {
		transform: scaleX(1);
	}

	/* The rule above replaces the text underline the current page carried.
	   Matched on the anchor as well, so this wins over the earlier rule that
	   sets the underline regardless of where it sits in the file. */
	.primary-nav a[aria-current="page"],
	.primary-nav .current-menu-item > a[href],
	.primary-nav .current_page_parent > a[href] {
		text-decoration: none;
	}
}

@media (prefers-reduced-motion: reduce) {
	.primary-nav a::after {
		transition: none;
	}
}

/* Current page: dark text with a coral rule under it. */
.primary-nav .current-menu-item > a,
.primary-nav .current-menu-ancestor > a,
.primary-nav .current_page_parent > a,
.primary-nav [aria-current="page"] {
	color: var(--vv-fg);
	text-decoration: underline;
	text-decoration-color: var(--vv-accent);
	text-decoration-thickness: 1px;
	text-underline-offset: 8px;
}

/* Menu button — only ever shown while the nav is collapsed. */
.nav-toggle {
	position: relative;
	display: none;
	align-items: center;
	gap: 0.55rem;
	padding: 0.5rem 0.85rem 0.5rem 0.7rem;
	border: 1px solid var(--vv-border);
	border-radius: 999px;
	background: transparent;
	font-size: var(--vv-label-size);
	font-weight: 700;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--vv-fg);
	cursor: pointer;
	transition: background-color var(--vv-transition);
}

.nav-toggle:hover {
	background: var(--vv-muted);
}

/* A 44px hit area at every width, without making the sticky header taller. */
.nav-toggle::after {
	content: "";
	position: absolute;
	top: 50%;
	left: 50%;
	width: 100%;
	min-width: var(--vv-tap);
	height: var(--vv-tap);
	transform: translate(-50%, -50%);
}

/* An 18×14 box holding three 2px bars at y = 0, 6 and 12. Every offset is a
   whole pixel, so no bar lands on a half-pixel and renders heavier than its
   neighbours. */
.nav-toggle__icon {
	position: relative;
	display: block;
	flex: none;
	width: 18px;
	height: 14px;
}

.nav-toggle__bar,
.nav-toggle__bar::before,
.nav-toggle__bar::after {
	position: absolute;
	left: 0;
	width: 100%;
	height: 2px;
	background: currentColor;
}

.nav-toggle__bar {
	top: 6px;
	transition: background-color var(--vv-transition);
}

.nav-toggle__bar::before,
.nav-toggle__bar::after {
	content: "";
	transition: transform var(--vv-transition), top var(--vv-transition);
}

.nav-toggle__bar::before {
	top: -6px;
}

.nav-toggle__bar::after {
	top: 6px;
}

/* Open state is marked by colour as well as by the cross, so it reads on touch
   where there is no hover to fall back on. */
.nav-toggle[aria-expanded="true"] {
	color: var(--vv-accent);
}

.nav-toggle[aria-expanded="true"] .nav-toggle__bar {
	background: transparent;
}

.nav-toggle[aria-expanded="true"] .nav-toggle__bar::before {
	top: 0;
	transform: rotate(45deg);
}

.nav-toggle[aria-expanded="true"] .nav-toggle__bar::after {
	top: 0;
	transform: rotate(-45deg);
}

/* Collapsed navigation. Scoped to .has-js so a scriptless browser keeps the
   links on the page instead of hiding them behind a button that cannot open. */
@media (max-width: 1159px) {
	.has-js .nav-toggle {
		display: inline-flex;
	}

	.has-js .primary-nav {
		position: absolute;
		top: 100%;
		left: 0;
		right: 0;
		width: auto;
		max-height: calc(100svh - 100%);
		overflow-y: auto;
		overscroll-behavior: contain;
		background: var(--vv-bg);
		border-bottom: 1px solid var(--vv-border);
		box-shadow: 0 16px 32px -24px rgba(0, 0, 0, 0.35);
		opacity: 0;
		visibility: hidden;
		transform: translateY(-0.5rem);
		transition: opacity var(--vv-transition), transform var(--vv-transition), visibility var(--vv-transition);
	}

	.has-js .primary-nav.is-open {
		opacity: 1;
		visibility: visible;
		transform: none;
	}

	.has-js .primary-nav ul {
		flex-direction: column;
		align-items: stretch;
		gap: 0;
		max-width: var(--vv-container);
		margin-inline: auto;
		padding: 0.5rem var(--vv-gutter) 1.25rem;
		font-size: 1rem;
	}

	.has-js .primary-nav li + li {
		border-top: 1px solid color-mix(in oklab, var(--vv-border) 70%, transparent);
	}

	.has-js .primary-nav a {
		padding-block: 0.9rem;
		font-family: var(--vv-font-serif);
		font-size: 1.125rem;
		letter-spacing: -0.01em;
		color: var(--vv-fg);
	}

	/* In the drawer the current item is already marked by colour, so the rule
	   under it would only add noise. */
	.has-js .primary-nav .current-menu-item > a,
	.has-js .primary-nav .current_page_parent > a,
	.has-js .primary-nav [aria-current="page"] {
		color: var(--vv-accent);
		text-decoration: none;
	}

	/* While the menu is open the page behind it should not scroll, and it is
	   dimmed so the panel reads as the only thing in play. */
	.nav-open,
	.nav-open body {
		overflow: hidden;
	}

	.has-js .nav-scrim {
		position: fixed;
		inset: 0;
		z-index: 30;
		background: color-mix(in oklab, var(--vv-ink) 45%, transparent);
		opacity: 0;
		visibility: hidden;
		transition: opacity var(--vv-transition), visibility var(--vv-transition);
	}

	.has-js.nav-open .nav-scrim {
		opacity: 1;
		visibility: visible;
	}
}

/* Scriptless fallback: the links sit on their own row under the brand. */
@media (max-width: 1159px) {
	html:not(.has-js) .primary-nav {
		overflow-x: auto;
		scrollbar-width: none;
	}

	html:not(.has-js) .primary-nav ul {
		white-space: nowrap;
	}

	html:not(.has-js) .primary-nav::-webkit-scrollbar {
		display: none;
	}
}

.header-actions {
	order: 2;
	display: flex;
	align-items: center;
	gap: 1rem;
	min-width: 0;
}

.header-actions__cta-name {
	display: none;
}

.header-actions__summary {
	position: relative;
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--vv-muted-fg);
	text-decoration: none;
}

.header-actions__summary:hover {
	color: var(--vv-fg);
}

/* Reduced to a 16px mark on phones, so it gets the same invisible extender as
   the menu button. */
.header-actions__summary::after {
	content: "";
	position: absolute;
	top: 50%;
	left: 50%;
	/* Above the neighbouring pill: where the two hit areas overlap, the smaller
	   target should win. */
	z-index: 1;
	width: 100%;
	min-width: var(--vv-tap);
	height: var(--vv-tap);
	transform: translate(-50%, -50%);
}

/* The bag mark only carries the link on phones, where the word is dropped. */
.header-actions__icon {
	display: none;
	flex: none;
}

.header-actions__count {
	display: inline-block;
	min-width: 1.25rem;
	padding: 0 0.25rem;
	margin-left: 0.35rem;
	border-radius: 999px;
	background: var(--vv-coral);
	color: var(--vv-coral-fg);
	text-align: center;
	font-size: 0.6875rem;
	line-height: 1.25rem;
}

/* The header bar stays on one row at every width by giving up its labels in
   order of how much room each one buys. Three tiers, widest first:
     ≥768px  everything spelled out
     560px   the basket drops to its mark
     <560px  the call to action shortens and the menu button drops its word */

@media (max-width: 767px) {
	.header-actions__summary-label {
		position: absolute;
		width: 1px;
		height: 1px;
		padding: 0;
		overflow: hidden;
		clip: rect(0, 0, 0, 0);
		white-space: nowrap;
		border: 0;
	}

	.header-actions__icon {
		display: block;
	}

	/* Sat on the mark rather than beside it: as a sibling it added its own width
	   to the bar and tipped the header onto a second row as soon as something
	   was in the summary. */
	.header-actions__count {
		position: absolute;
		top: -0.4rem;
		right: -0.55rem;
		min-width: 1rem;
		margin-left: 0;
		padding: 0 0.2rem;
		font-size: 0.625rem;
		line-height: 1rem;
	}
}

@media (min-width: 560px) {
	.header-actions__cta-name {
		display: inline;
	}
}

@media (max-width: 559px) {
	.site-header__inner {
		gap: 0.75rem 1rem;
	}

	.header-actions {
		gap: 0.65rem;
	}

	.brand__name {
		font-size: 1.125rem;
	}

	/* Without its word the button is just the mark, so the pill goes too. */
	.nav-toggle {
		position: relative;
		padding: 0.25rem;
		border-color: transparent;
		border-radius: var(--vv-radius);
	}

	.nav-toggle:hover {
		background: transparent;
		color: var(--vv-accent);
	}

	.nav-toggle__label {
		position: absolute;
		width: 1px;
		height: 1px;
		padding: 0;
		overflow: hidden;
		clip: rect(0, 0, 0, 0);
		white-space: nowrap;
		border: 0;
	}
}

/* The smallest phones still in use need the wordmark and the pill trimmed. */
@media (max-width: 380px) {
	.brand__name {
		font-size: 1.0625rem;
	}

	.header-actions__cta {
		padding-inline: 0.8rem;
	}

	.site-header__inner {
		gap: 0.75rem 0.75rem;
	}
}

/* 320px-class screens — the last tier before the bar would have to wrap. */
@media (max-width: 340px) {
	.brand__name {
		font-size: 1rem;
	}

	.header-actions {
		gap: 0.5rem;
	}

	.header-actions__cta {
		padding-inline: 0.65rem;
		letter-spacing: 0.06em;
	}
}

/* Full inline navigation once all seven items fit beside the brand and CTA. */
@media (min-width: 1160px) {
	.primary-nav {
		order: 2;
		width: auto;
		position: static;
	}

	.header-actions {
		order: 3;
	}

	.nav-toggle {
		display: none;
	}
}

@media (min-width: 1536px) {
	.brand__tagline {
		display: inline;
	}
}

/* 7. Footer ---------------------------------------------------------------- */

.site-footer {
	position: relative;
	background-color: var(--vv-primary);
	/* A slow lift towards the top edge keeps the block from reading as one flat
	   slab of ink, and a coral hairline ties it to the palette. */
	background-image: linear-gradient(
		to bottom,
		color-mix(in oklab, var(--vv-primary-fg) 5%, transparent),
		transparent 30%
	);
	color: var(--vv-primary-fg);
	padding-block: 3.5rem 2rem;
	margin-top: auto;
}

.site-footer::before {
	content: "";
	position: absolute;
	inset: 0 0 auto;
	height: 2px;
	background: linear-gradient(
		to right,
		var(--vv-accent),
		color-mix(in oklab, var(--vv-accent) 35%, transparent) 40%,
		transparent 75%
	);
}

.site-footer a {
	color: inherit;
	text-decoration: none;
}

.site-footer a:hover {
	color: var(--vv-coral);
	text-decoration: underline;
	text-underline-offset: 4px;
}

.site-footer__grid {
	display: grid;
	gap: 2.5rem;
	grid-template-columns: 1fr;
}

.site-footer__about p {
	margin-top: 0.75rem;
	max-width: 26rem;
	font-size: 0.875rem;
	color: color-mix(in oklab, var(--vv-primary-fg) 70%, transparent);
}

.site-footer h2 {
	font-family: var(--vv-font-sans);
	font-size: var(--vv-label-size);
	font-weight: 700;
	letter-spacing: 0.28em;
	text-transform: uppercase;
	color: var(--vv-coral);
	margin-bottom: 1rem;
}

.site-footer li + li {
	margin-top: 0.5rem;
}

.site-footer ul {
	font-size: 0.875rem;
}

.site-footer__identity li {
	color: color-mix(in oklab, var(--vv-primary-fg) 70%, transparent);
}

.site-footer__legal {
	margin-top: 3rem;
	padding-top: 1.5rem;
	border-top: 1px solid color-mix(in oklab, var(--vv-primary-fg) 15%, transparent);
	font-size: 0.8125rem;
	color: color-mix(in oklab, var(--vv-primary-fg) 65%, transparent);
}

@media (min-width: 640px) {
	.site-footer__grid {
		grid-template-columns: repeat(2, 1fr);
	}
}

@media (min-width: 1024px) {
	.site-footer__grid {
		grid-template-columns: 2fr 1fr 1fr 1.6fr;
		gap: 3rem;
	}
}

/* 8. Cards and grids ------------------------------------------------------- */

.grid {
	display: grid;
	gap: 2rem;
	grid-template-columns: 1fr;
}

.grid--2 {
	--vv-cols: 2;
}

.grid--3 {
	--vv-cols: 3;
}

.grid--4 {
	--vv-cols: 4;
}

@media (min-width: 640px) {
	.grid--2,
	.grid--3,
	.grid--4 {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (min-width: 1024px) {
	.grid--3 {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}

	.grid--4 {
		grid-template-columns: repeat(4, minmax(0, 1fr));
	}
}

/* Numbered process step */
.step {
	border-top: 2px solid var(--vv-accent);
	padding-top: 1.25rem;
}

.step__num {
	font-family: var(--vv-font-serif);
	font-size: 1.875rem;
	color: var(--vv-accent);
	line-height: 1;
}

.step h3 {
	margin-top: 0.75rem;
	font-size: 1.25rem;
}

.step p {
	margin-top: 0.5rem;
	font-size: 0.875rem;
	color: var(--vv-muted-fg);
}

/* Media card — destinations, packages, notes */
.card {
	position: relative;
	display: flex;
	flex-direction: column;
	height: 100%;
	background: var(--vv-surface);
	border: 1px solid var(--vv-border);
	border-radius: var(--vv-radius);
	overflow: hidden;
	transition:
		border-color var(--vv-transition),
		transform 0.25s var(--vv-ease),
		box-shadow 0.25s var(--vv-ease);
}

/* A small lift on hover — enough to say the whole card is the target. */
.card:hover {
	border-color: color-mix(in oklab, var(--vv-accent) 55%, var(--vv-border));
	transform: translateY(-3px);
	box-shadow: 0 18px 30px -24px rgba(0, 0, 0, 0.45);
}

@media (prefers-reduced-motion: reduce) {
	.card:hover {
		transform: none;
	}
}

/* A wider crop suits the landscape photography and takes about 40px less
   height per card than 3:2 did. */
.card__media {
	position: relative;
	aspect-ratio: 16 / 9;
	background: var(--vv-muted);
	overflow: hidden;
}

.card__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform 0.4s var(--vv-ease);
}

.card:hover .card__media img {
	transform: scale(1.03);
}

/* The card is a dense summary rather than a reading surface, so it runs on
   tighter spacing and leading than the body copy around it. */
.card {
	container-type: inline-size;
}

.card__body {
	display: flex;
	flex-direction: column;
	flex: 1;
	padding: 1.125rem 1.25rem 1.25rem;
	line-height: 1.5;
}

.card__eyebrow {
	font-size: var(--vv-label-size);
	font-weight: 700;
	letter-spacing: 0.28em;
	text-transform: uppercase;
	color: var(--vv-accent);
}

.card__title {
	margin-top: 0.625rem;
	font-size: 1.25rem;
}

.card__title a {
	text-decoration: none;
}

/* The title link covers the whole card, so the target is the card rather than
   two lines of text. The button in the footer stays a separate target. */
.card__title a::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
}

.card:hover .card__title a,
.card__title a:focus-visible {
	text-decoration: underline;
	text-underline-offset: 4px;
}

.card__excerpt {
	margin-top: 0.625rem;
	font-size: 0.875rem;
	color: var(--vv-muted-fg);
	text-wrap: pretty;
}

.card__meta {
	margin-top: 0.75rem;
	font-size: 0.8125rem;
	color: var(--vv-muted-fg);
}

/* Price line that closes a card: the amount set large in the serif face, the
   terms trailing it in the body size. */
.card__pricing {
	font-size: 0.875rem;
	line-height: 1.4;
}

.card__pricing-amount {
	font-family: var(--vv-font-serif);
	font-size: 1.5rem;
}

.card__pricing-terms {
	color: var(--vv-muted-fg);
}

.card__foot {
	margin-top: auto;
	padding-top: 1rem;
}

/* Inside a card the fact strip is a compact spec block: three items on one row
   once the card is wide enough, and tighter gaps than the page-level version. */
.card .facts {
	gap: 0.85rem 1rem;
}

.card .facts dd {
	margin-top: 0.2rem;
}

/* "Delivery target" needs two lines in a third of a card while the other two
   labels need one. Reserving both lines keeps every value on the same baseline
   instead of stepping down the row. */
@container (min-width: 300px) {
	.card .facts dt {
		min-height: 2.8em;
	}
}

@container (min-width: 300px) {
	.card .facts {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

.card__price {
	font-family: var(--vv-font-serif);
	font-size: 1.375rem;
	color: var(--vv-fg);
}

.card__price small {
	display: block;
	font-family: var(--vv-font-sans);
	font-size: var(--vv-label-size);
	font-weight: 700;
	letter-spacing: 0.2em;
	text-transform: uppercase;
	color: var(--vv-muted-fg);
	margin-bottom: 0.25rem;
}

.card__list {
	margin-top: 0.75rem;
	font-size: 0.875rem;
	color: var(--vv-muted-fg);
}

.card__list li {
	position: relative;
	padding-left: 1.1rem;
}

.card__list li + li {
	margin-top: 0.3rem;
}

.card__list li::before {
	content: "—";
	position: absolute;
	left: 0;
	color: var(--vv-accent);
}

/* Principle card — no media, rule above */
.principle {
	border-top: 1px solid var(--vv-border);
	padding-top: 1.25rem;
}

/* In running content the rules read as underlines on the titles above them;
   the grid gap already separates the blocks. */
.principle--plain {
	border-top: 0;
	padding-top: 0;
}

.principle h3 {
	font-size: 1.125rem;
}

.principle p {
	margin-top: 0.5rem;
	font-size: 0.875rem;
	color: var(--vv-muted-fg);
	text-wrap: pretty;
}

/* Definition-list fact strip */
.facts {
	display: grid;
	gap: 1.5rem 2.5rem;
	grid-template-columns: 1fr;
	font-size: 0.875rem;
}

.facts dt {
	font-size: var(--vv-label-size);
	font-weight: 700;
	letter-spacing: 0.28em;
	text-transform: uppercase;
	color: var(--vv-accent);
}

.facts dd {
	max-width: 46ch;
	margin-top: 0.375rem;
	margin-left: 0;
	color: var(--vv-muted-fg);
	text-wrap: pretty;
}

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

@media (min-width: 1024px) {
	.facts--4 {
		grid-template-columns: repeat(4, minmax(0, 1fr));
	}

	.facts--3 {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

/* 9. Page components ------------------------------------------------------- */

.page-hero {
	border-bottom: 1px solid var(--vv-border);
}

.page-hero__inner {
	padding-block: 3.5rem 3rem;
}

.page-hero h1 {
	margin-top: 1.25rem;
	font-size: clamp(2rem, 1.4rem + 2.6vw, 3.25rem);
	/* Fill each line. `balance` — the default for headings — deliberately
	   shortens the first line, and the old 20ch cap broke it earlier still. */
	max-width: 48rem;
	text-wrap: pretty;
}


.page-hero .t-lead {
	margin-top: 1.5rem;
	max-width: 42rem;
}

/* The hero section carries a soft warm wash behind the headline and a pair of
   hairlines marking the reading column — structure you feel rather than read. */
.hero-section {
	position: relative;
	overflow: hidden;
}

.hero-section::before {
	content: "";
	position: absolute;
	top: -30%;
	left: -10%;
	width: 70%;
	height: 130%;
	pointer-events: none;
	background: radial-gradient(
		closest-side,
		color-mix(in oklab, var(--vv-accent) 9%, transparent),
		transparent
	);
}

.hero-section > * {
	position: relative;
}


.hero {
	display: grid;
	gap: 3rem;
	padding-block: var(--vv-section-y-lg);
}

.hero__copy h1 {
	margin-top: 1.5rem;
}

/* Headline and standfirst both run the full column width. */
.hero__copy .t-lead {
	margin-top: 2rem;
	max-width: none;
}

/* The headline is sized from its own column, not from the viewport. Between
   1024px and 1160px the column is half the screen while a viewport-based size
   is still near its maximum, which pushed the headline onto five tight lines. */
@supports (container-type: inline-size) {
	.hero__copy {
		container-type: inline-size;
	}

	.hero__copy .t-display {
		font-size: clamp(1.9rem, 9.6cqi, 3.75rem);
	}
}

.hero__figure figcaption {
	margin-top: 0.75rem;
	font-size: 0.75rem;
	color: var(--vv-muted-fg);
}

/* The image is clipped by its wrapper so it can be scaled without spilling
   past the rounded corners. */
.hero__media {
	overflow: hidden;
	border-radius: var(--vv-radius-media);
	aspect-ratio: 4 / 3;
}

.hero__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* The picture drifts a few pixels, with its shadow softening as it rises, so it
   reads as sitting slightly off the page. Transform and shadow only — nothing
   here can move the layout. The delay lets the entrance settle finish first. */
@media (prefers-reduced-motion: no-preference) {
	.hero__media {
		animation: vv-float 7s var(--vv-ease) 1.4s infinite alternate;
	}
}

@keyframes vv-float {
	from {
		transform: translateY(0);
		box-shadow: 0 14px 28px -22px rgba(0, 0, 0, 0.45);
	}

	to {
		transform: translateY(-10px);
		box-shadow: 0 30px 44px -28px rgba(0, 0, 0, 0.4);
	}
}

/* Two columns as soon as there is room for the picture beside the copy, so the
   right-hand side is never left empty. The headline is sized from its column
   rather than the viewport, so it keeps the same measure either side of the
   split instead of jumping. */
@media (min-width: 1024px) {
	.hero {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		align-items: center;
		gap: 3.5rem;
	}
}

/* With the picture below rather than beside it, the copy runs the full width and
   the actions sit centred under it. Alongside the picture they stay left, where
   they line up with the text. */
@media (max-width: 1023px) {
	.hero__copy .btn-row {
		justify-content: center;
	}
}

/* Calls to action do not fit side by side on a phone. Stacked full width they
   read as a deliberate list rather than a ragged pile. */
@media (max-width: 559px) {
	.btn-row {
		flex-direction: column;
		align-items: stretch;
		gap: 0.75rem;
	}
}

/* Hero entrance.
   Opacity is animated once, on the whole copy block, and it is over inside
   260ms — the standfirst is the Largest Contentful Paint element on a phone,
   and a staggered fade would have held it back by the length of the stagger.
   The sequence a reader actually notices comes from the rise, which is a
   transform and so costs nothing in paint time. */
@media (prefers-reduced-motion: no-preference) {
	.hero__copy {
		animation: vv-hero-fade 260ms var(--vv-ease) both;
	}

	.hero__copy > * {
		animation: vv-hero-rise 560ms var(--vv-ease) both;
	}

	.hero__copy > *:nth-child(2) {
		animation-delay: 70ms;
	}

	.hero__copy > *:nth-child(3) {
		animation-delay: 140ms;
	}

	.hero__copy > *:nth-child(4) {
		animation-delay: 210ms;
	}

	/* A long, almost imperceptible settle — the picture stops moving about the
	   time the reader reaches the end of the standfirst. */
	.hero__media img {
		animation: vv-hero-settle 1400ms var(--vv-ease) both;
	}
}

@keyframes vv-hero-fade {
	from {
		opacity: 0;
	}
}

@keyframes vv-hero-rise {
	from {
		transform: translateY(12px);
	}
}

@keyframes vv-hero-settle {
	from {
		transform: scale(1.06);
	}
}

/* Scroll reveal.
   Only ever applied by script, and only to blocks that start below the fold —
   nothing visible on load is hidden first, so there is no flash and no effect
   on the largest contentful paint. */
@media (prefers-reduced-motion: no-preference) {
	.has-js .reveal {
		opacity: 0;
		transform: translateY(14px);
		transition:
			opacity 520ms var(--vv-ease) var(--vv-reveal-delay, 0ms),
			transform 520ms var(--vv-ease) var(--vv-reveal-delay, 0ms);
	}

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

.hero-strip {
	border-top: 1px solid var(--vv-border);
}

.hero-strip .facts {
	padding-block: 2rem;
}

.breadcrumbs {
	padding-block: 1rem;
	font-size: 0.8125rem;
	color: var(--vv-muted-fg);
	border-bottom: 1px solid var(--vv-border);
}

.breadcrumbs ol {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
}

.breadcrumbs li::after {
	content: "/";
	margin-left: 0.5rem;
	color: var(--vv-border);
}

.breadcrumbs li:last-child::after {
	content: none;
}

.breadcrumbs a {
	text-decoration: none;
}

.breadcrumbs a:hover {
	text-decoration: underline;
	text-underline-offset: 3px;
}

/* Accordion — FAQ and package questions */
.accordion {
	border-top: 1px solid var(--vv-border);
}

.accordion__item {
	border-bottom: 1px solid var(--vv-border);
}

.accordion__item > summary {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: 1.5rem;
	padding-block: 1.125rem;
	cursor: pointer;
	list-style: none;
	font-family: var(--vv-font-serif);
	font-size: 1.0625rem;
	line-height: 1.35;
}

.accordion__item > summary::-webkit-details-marker {
	display: none;
}

.accordion__item > summary::after {
	content: "+";
	flex: none;
	font-family: var(--vv-font-sans);
	font-size: 1.25rem;
	line-height: 1;
	color: var(--vv-accent);
	transition: transform var(--vv-transition);
}

.accordion__item[open] > summary::after {
	content: "–";
}

.accordion__item > summary:hover {
	color: var(--vv-accent);
}

.accordion__panel {
	padding-bottom: 1.25rem;
	/* ~76 characters at this size. */
	max-width: 36rem;
	font-size: 0.9375rem;
	color: var(--vv-muted-fg);
	text-wrap: pretty;
}

.accordion__panel > * + * {
	margin-top: 0.75rem;
}

/* Two-column include / exclude lists */
.spec-pair {
	display: grid;
	gap: 1.75rem 2.5rem;
	grid-template-columns: 1fr;
}

@media (min-width: 640px) {
	.spec-pair {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

.spec-pair__title {
	margin-bottom: 0.75rem;
	font-family: var(--vv-font-sans);
	font-size: var(--vv-label-size);
	font-weight: 700;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--vv-muted-fg);
}

.spec-list li {
	position: relative;
	padding-left: 1.5rem;
	font-size: 0.9375rem;
	color: var(--vv-muted-fg);
}

.spec-list li + li {
	margin-top: 0.625rem;
}

.spec-list li::before {
	position: absolute;
	left: 0;
	top: 0;
	font-weight: 700;
}

.spec-list--yes li::before {
	content: "✓";
	color: var(--vv-jade);
}

.spec-list--no li::before {
	content: "✕";
	color: var(--vv-danger);
}

/* Process page — a rail linking numbered markers, so the steps read as one
   sequence rather than six separate blocks. */
.timeline {
	--vv-marker: 2.75rem;
}

.timeline__item {
	position: relative;
	display: grid;
	grid-template-columns: var(--vv-marker) minmax(0, 1fr);
	gap: 1.25rem;
	padding-bottom: 2.75rem;
}

.timeline__item:last-child {
	padding-bottom: 0;
}

/* The rail runs from under one marker to the top of the next. */
.timeline__item::before {
	content: "";
	position: absolute;
	top: var(--vv-marker);
	bottom: 0;
	left: calc(var(--vv-marker) / 2);
	width: 1px;
	background: color-mix(in oklab, var(--vv-accent) 40%, var(--vv-border));
	transform: translateX(-50%);
}

.timeline__item:last-child::before {
	content: none;
}

.timeline__marker {
	position: relative;
	z-index: 1;
	display: grid;
	place-items: center;
	width: var(--vv-marker);
	height: var(--vv-marker);
	border: 1px solid var(--vv-accent);
	border-radius: 999px;
	background: var(--vv-bg);
	font-family: var(--vv-font-serif);
	font-size: 1.125rem;
	line-height: 1;
	color: var(--vv-accent);
}

.timeline__body {
	padding-top: 0.4rem;
}

.timeline__title {
	font-size: 1.375rem;
}

.timeline__text {
	margin-top: 0.5rem;
	color: var(--vv-muted-fg);
	text-wrap: pretty;
}

@media (min-width: 768px) {
	.timeline {
		--vv-marker: 3rem;
	}

	.timeline__item {
		gap: 1.75rem;
		padding-bottom: 3.25rem;
	}

	.timeline__title {
		font-size: 1.5rem;
	}
}

/* Ordered "how it works" list */
.numbered {
	counter-reset: vv-step;
}

.numbered li {
	position: relative;
	counter-increment: vv-step;
	padding-left: 2.5rem;
	font-size: 0.9375rem;
	color: var(--vv-muted-fg);
}

.numbered li + li {
	margin-top: 1rem;
}

.numbered li::before {
	content: counter(vv-step, decimal-leading-zero);
	position: absolute;
	left: 0;
	top: 0;
	font-family: var(--vv-font-serif);
	font-size: 1rem;
	color: var(--vv-accent);
}

/* Closing call to action.
   A panel on the page background rather than a full-width dark band — the band
   sat directly above the footer and the two read as one dark block. */
.cta {
	padding-block: 4rem;
}

/* Warm muted fill rather than white: white is the only pure tone on the page
   and it read as a box dropped onto the cream instead of part of it. */
.cta__panel {
	position: relative;
	display: grid;
	gap: 2rem;
	padding: 2rem;
	border: 1px solid var(--vv-border);
	border-radius: var(--vv-radius-media);
	background: var(--vv-muted);
	/* A warm corner glow so the panel has a light source instead of a flat fill. */
	background-image: radial-gradient(
		120% 120% at 100% 0%,
		color-mix(in oklab, var(--vv-accent) 10%, transparent),
		transparent 55%
	);
	overflow: hidden;
}

.cta h2 {
	font-size: clamp(1.625rem, 1.3rem + 1.5vw, 2.125rem);
}

.cta p {
	margin-top: 0.875rem;
	color: var(--vv-muted-fg);
	text-wrap: pretty;
}

/* Stacked, the two actions share one width — ragged pill widths read as an
   accident rather than a pair. */
.cta__actions {
	display: flex;
	flex-direction: column;
	align-items: stretch;
	gap: 0.75rem;
}

@media (min-width: 768px) {
	/* Two thirds copy, one third actions — the proportions the reference uses. */
	.cta__panel {
		grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
		align-items: center;
		gap: 3rem;
		padding: 3rem;
	}

	.cta__actions {
		flex-direction: row;
		flex-wrap: wrap;
		align-items: center;
		justify-content: flex-end;
		gap: 1rem;
	}
}

/* Pagination */
.pagination {
	margin-top: 3rem;
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	font-size: 0.875rem;
}

.pagination .page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 2.5rem;
	height: 2.5rem;
	padding-inline: 0.75rem;
	border: 1px solid var(--vv-border);
	border-radius: 999px;
	text-decoration: none;
}

.pagination .page-numbers:hover {
	background: var(--vv-muted);
}

.pagination .page-numbers.current {
	background: var(--vv-primary);
	color: var(--vv-primary-fg);
	border-color: var(--vv-primary);
}

/* Notice / disclosure line used throughout the pricing copy */
.notice {
	margin-top: 1.5rem;
	padding: 0.875rem 1rem;
	border-left: 2px solid var(--vv-accent);
	background: var(--vv-muted);
	font-size: 0.8125rem;
	color: var(--vv-muted-fg);
	text-wrap: pretty;
}

/* Editorial banner image — always a wide crop, whatever the source aspect */
.figure-wide img {
	width: 100%;
	aspect-ratio: 3 / 2;
	object-fit: cover;
	border-radius: var(--vv-radius-media);
}

@media (min-width: 768px) {
	.figure-wide img {
		aspect-ratio: 21 / 9;
	}
}

/* Contact */
.contact-layout {
	display: grid;
	gap: 3rem;
	grid-template-columns: 1fr;
}

@media (min-width: 1024px) {
	.contact-layout {
		grid-template-columns: minmax(0, 20rem) minmax(0, 1fr);
		gap: 4rem;
		align-items: start;
	}

	.contact-details {
		position: sticky;
		top: 6rem;
	}
}

.contact-details .facts {
	gap: 1.5rem;
}

/* 10. Forms ---------------------------------------------------------------- */

.field {
	display: block;
}

.field + .field {
	margin-top: 1.25rem;
}

.field > label,
.field > .label {
	display: block;
	margin-bottom: 0.4rem;
	font-size: 0.75rem;
	font-weight: 700;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--vv-muted-fg);
}

input[type="text"],
input[type="email"],
input[type="tel"],
input[type="url"],
input[type="password"],
input[type="search"],
input[type="number"],
input[type="date"],
select,
textarea {
	width: 100%;
	min-height: var(--vv-tap);
	padding: 0.75rem 0.875rem;
	background: var(--vv-surface);
	border: 1px solid var(--vv-border);
	border-radius: var(--vv-radius);
	font-size: 1rem;
	transition: border-color var(--vv-transition);
}

/* iOS zooms the page in when a focused field is under 16px, so form text never
   drops below that. */
textarea {
	min-height: 9rem;
}

/* Fields carry no focus styling of their own: the shared focus ring is the
   indicator, and recolouring the border as well drew a second coral box a few
   pixels inside the first. */

textarea {
	min-height: 9rem;
	resize: vertical;
}

.field__hint {
	margin-top: 0.35rem;
	font-size: 0.8125rem;
	color: var(--vv-muted-fg);
}

.form-grid {
	display: grid;
	gap: 1.25rem;
	grid-template-columns: 1fr;
}

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

	.form-grid .field + .field {
		margin-top: 0;
	}
}

/* 11. Prose ---------------------------------------------------------------- */

.prose {
	/* ~72 characters a line at this size — the comfortable range for reading. */
	max-width: 40rem;
	font-size: 1.0625rem;
	line-height: 1.7;
	text-wrap: pretty;
}

.prose > * + * {
	margin-top: 1.25rem;
}

/* The section already sets the space above the first block. */
.prose > :first-child {
	margin-top: 0;
}

.prose h2 {
	margin-top: 2.75rem;
	font-size: 1.75rem;
}

.prose h3 {
	margin-top: 2rem;
	font-size: 1.3125rem;
}

.prose h2 + *,
.prose h3 + * {
	margin-top: 0.75rem;
}

.prose ul,
.prose ol {
	padding-left: 1.5rem;
}

.prose ul {
	list-style: disc;
}

.prose ol {
	list-style: decimal;
}

.prose li + li {
	margin-top: 0.5rem;
}

.prose li::marker {
	color: var(--vv-accent);
}

.prose a {
	color: inherit;
	text-decoration: underline;
	text-underline-offset: 3px;
	text-decoration-color: var(--vv-accent);
}

.prose a:hover {
	color: var(--vv-accent);
}

/* Contact addresses read as contact details, not as body copy. Scoped away
   from the footer, where everything is already a link on a dark ground. */
:where(.prose, .facts, .accordion__panel, .section) a[href^="mailto:"],
:where(.prose, .facts, .accordion__panel, .section) a[href^="tel:"] {
	color: var(--vv-accent);
	text-decoration: underline;
	text-decoration-color: currentColor;
	text-underline-offset: 3px;
}

.prose blockquote {
	border-left: 2px solid var(--vv-accent);
	padding-left: 1.25rem;
	font-family: var(--vv-font-serif);
	font-size: 1.25rem;
	line-height: 1.4;
}

.prose strong {
	font-weight: 600;
}

.prose code {
	font-family: var(--vv-font-mono);
	font-size: 0.9em;
	background: var(--vv-muted);
	padding: 0.15em 0.35em;
	border-radius: 3px;
}

.prose table {
	width: 100%;
	border-collapse: collapse;
	font-size: 0.9375rem;
}

.prose th,
.prose td {
	border: 1px solid var(--vv-border);
	padding: 0.625rem 0.875rem;
	text-align: left;
}

.prose th {
	background: var(--vv-muted);
	font-weight: 600;
}

.prose figcaption {
	margin-top: 0.5rem;
	font-size: 0.8125rem;
	color: var(--vv-muted-fg);
}

/* Buttons in editor content: the prose link rules would otherwise underline
   them and force the inherited text colour, leaving dark type on a dark pill. */
.prose .btn {
	text-decoration: none;
}

.prose .btn--primary {
	color: var(--vv-primary-fg);
}

.prose .btn--accent {
	color: var(--vv-coral-fg);
}

.prose .btn--outline {
	color: var(--vv-fg);
}

/* Theme components embedded in editor content keep their own styling rather
   than inheriting the prose list and heading rules. */
.prose .facts,
.prose .spec-list {
	list-style: none;
	padding-left: 0;
}

.prose .spec-list li {
	padding-left: 1.5rem;
}

.prose .spec-pair__title {
	margin-top: 0;
	margin-bottom: 0.75rem;
	font-size: var(--vv-label-size);
}

/* The prose heading rules would otherwise give these blocks a 2rem top margin
   and the wrong size, which breaks the grid's rhythm. */
.prose .principle h3 {
	margin-top: 0;
	font-size: 1.1875rem;
}

.prose .principle p {
	margin-top: 0.5rem;
	font-size: 0.9375rem;
	line-height: 1.6;
}

.prose .facts,
.prose .grid,
.prose .spec-pair {
	margin-top: 1.75rem;
}

/* In running content the labels sit alongside serif block titles, so they take
   the same ink rather than the accent used on the marketing panels. */
.prose .facts dt {
	color: var(--vv-fg);
}

.table-scroll {
	overflow-x: auto;
}

/* Article meta */
.entry-meta {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	align-items: center;
	font-size: 0.75rem;
	font-weight: 700;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--vv-muted-fg);
}

.entry-meta span::after {
	content: "·";
	margin-left: 0.5rem;
	color: var(--vv-border);
}

.entry-meta span:last-child::after {
	content: none;
}

/* 12. Utilities ------------------------------------------------------------ */

.site {
	display: flex;
	flex-direction: column;
	min-height: 100vh;
	min-height: 100svh;
}

.site-main {
	flex: 1;
}

.mt-0 { margin-top: 0; }
.mt-1 { margin-top: 0.5rem; }
.mt-2 { margin-top: 1rem; }
.mt-3 { margin-top: 1.5rem; }
.mt-4 { margin-top: 2rem; }
.mt-5 { margin-top: 2.5rem; }
.mt-6 { margin-top: 3rem; }

.measure {
	max-width: 44rem;
}

.is-hidden {
	display: none;
}

@media (min-width: 768px) {
	:root {
		--vv-section-y: 4.5rem;
	}
}

@media print {
	.site-header,
	.site-footer,
	.cta,
	.btn {
		display: none !important;
	}

	body {
		background: #fff;
		color: #000;
	}
}
