/* ==========================================================================
   FOUNDATION — lifted verbatim from dev.char-bo.com (site.css v36).

   Design tokens, base, layout, buttons and the ENTIRE header: the sticky
   parchment bar, the brand logo, the nav and drawer, and the Vermont
   locator map. This block is a preserved contract — the header is the one
   part of the dev site being carried into the redesign unchanged, so edit
   it only to keep it in sync with dev, never to restyle it.

   Two upstream typos were repaired on dev before copying (a stray <p> tag
   inside .header-identity and an orphaned box-shadow after
   .lightbox-figure img). The --frame / --frame-gold photo-border tokens
   were dropped; the redesign frames no photographs.
   ========================================================================== */

/* ==========================================================================
   Char-Bo Campground, Derby, Vermont
   Pine and spruce greens with parchment-birch grounds, foliage gold, and
   maple red as the single bold spend. Built to sit under Kingdom photography
   without relying on fall-brown chrome.
   ========================================================================== */

:root {
	--cream:       #EEF1E6;
	--cream-deep:  #DCE4D4;
	--paper:       #F7F8F2;
	--header-wash: #FFF8EC;  /* parchment — midpoint of the header gradient */
	--header-wash-light: #FFFFFB;
	--header-wash-deep: #E8D9C0;
	--header-gradient: linear-gradient(180deg, var(--header-wash-light) 0%, var(--header-wash) 42%, var(--header-wash-deep) 100%);
	--bevel-surface-bg: #fff;
	--bevel-surface-border: color-mix(in srgb, var(--header-wash-deep) 50%, var(--pine) 50%);
	--bevel-surface-radius: 8px;
	--bevel-surface-shadow:
		0 2px 4px rgba(19, 38, 26, 0.14),
		inset 0 1px 0 rgba(255, 255, 255, 1),
		inset 0 -1px 0 rgba(0, 0, 0, 0.07);
	--bevel-surface-shadow-hover:
		0 3px 5px rgba(19, 38, 26, 0.16),
		inset 0 1px 0 rgba(255, 255, 255, 1),
		inset 0 -1px 0 rgba(0, 0, 0, 0.05);
	--bevel-surface-shadow-active:
		0 1px 2px rgba(19, 38, 26, 0.12),
		inset 0 1px 2px rgba(0, 0, 0, 0.1);
	--pine:        #3F704A;  /* lighter pine — most chrome */
	--spruce:      #1F3F2C;  /* darker spruce — hover, footer, overlays */
	--spruce-deep: #13261A;
	--barn:        var(--pine);   /* name kept for existing rules */
	--barn-deep:   var(--spruce-deep);
	--gold:        #C19E4C;
	--gold-bright: #E0B04A;
	--maple:       #C23018;
	--maple-deep:  #8D1E1E;
	--maple-soft:  #F8E2D6;
	--maple-light: color-mix(in srgb, var(--maple) 84%, #fff 16%);
	--spruce-light: color-mix(in srgb, var(--spruce) 78%, #fff 22%);
	--balsam:      #3A6B40;
	--balsam-deep: #1C3A1C;
	--balsam-soft: #DCE8D4;
	--lake:        #1E6A86;
	--lake-soft:   #D5E8EF;
	--ink:         #1A241D;
	--ink-soft:    #4A554C;
	--ink-faint:   #6E7A70;
	--rule:        #C9D2C4;
	--rule-dark:   #2C4733;

	--display: "Zilla Slab", "Bitter", Rockwell, Georgia, serif;
	--body: "Nunito", "Segoe UI", system-ui, sans-serif;

	/* Height of the bar once it has shrunk (.site-header.is-stuck). Anything
	   that has to sit clear of it while scrolling offsets by this. */
	--header-h-stuck: 74px;

	/* Corner of the soft glass surfaces. Generous enough to read as a rounded
	   pane rather than a boxed panel with the corners knocked off. */
	--glass-radius: 22px;

	--container: 1440px;
	--gutter: clamp(1.15rem, 4vw, 2.75rem);
	/* One vertical rhythm for the whole site: the space a band puts above and
	   below its content is the same everywhere, so the gap under the last line
	   of one section matches the gap under the last line of any other. */
	--band-y: clamp(2.1rem, 4.2vw, 3.4rem);
	--radius: 2px;
	--radius-lg: 4px;

	--fs-xs:   0.78rem;
	--fs-sm:   1.2rem;
	--fs-base: 1.0625rem;
	--fs-md:   1.2rem;
	--fs-lg:   clamp(1.35rem, 1.9vw, 1.65rem);
	--fs-xl:   clamp(1.7rem, 2.8vw, 2.35rem);
	--fs-2xl:  clamp(2.05rem, 3.8vw, 3.15rem);
	--fs-3xl:  clamp(2.55rem, 5.8vw, 4.5rem);

	--shadow-sm: 0 1px 2px rgba(19, 38, 26, .08), 0 3px 10px rgba(19, 38, 26, .06);
	--shadow-md: 0 3px 8px rgba(19, 38, 26, .10), 0 14px 32px rgba(19, 38, 26, .12);
	--shadow-lg: 0 8px 20px rgba(19, 38, 26, .16), 0 28px 60px rgba(19, 38, 26, .18);

}

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

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

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

body {
	margin: 0;
	background:
		radial-gradient(1200px 480px at 8% -10%, rgba(47, 90, 40, .16), transparent 60%),
		radial-gradient(900px 420px at 100% 8%, rgba(193, 158, 76, .12), transparent 55%),
		var(--cream);
	color: var(--ink);
	font-family: var(--body);
	font-size: var(--fs-base);
	line-height: 1.65;
	font-synthesis-weight: none;
	-webkit-font-smoothing: antialiased;
	overflow-x: hidden;
}

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

h1, h2, h3, h4 {
	font-family: var(--display);
	font-weight: 600;
	line-height: 1.12;
	letter-spacing: -0.018em;
	text-wrap: balance;
	margin: 0;
	color: var(--pine);
}

p { margin: 0; }

a { color: var(--maple); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--maple-deep); }

:focus-visible {
	outline: 3px solid var(--gold-bright);
	outline-offset: 3px;
}

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

.skip-link {
	position: absolute;
	left: -9999px;
	top: 0;
	z-index: 999;
	background: var(--maple);
	color: #fff;
	padding: .75rem 1.25rem;
	font-weight: 700;
}
.skip-link:focus { left: 0; color: #fff; }

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

/* ==========================================================================
   Layout
   ========================================================================== */

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

.wrap--narrow { max-width: 940px; }
.wrap--mid { max-width: 1180px; }

.band { padding-block: var(--band-y); }
/* Retained so existing markup keeps working; band spacing is now uniform, so
   this resolves to the same value as .band rather than a tighter one. */
.band--tight { padding-block: var(--band-y); }

/* Where two bands meet, the upper one's bottom padding and the lower one's top
   padding stack and the seam reads as twice the rhythm. The gap is already
   there, so the lower band drops its top padding. */
.band + .band { padding-top: 0; }
/* Unless the lower band paints its own background — then the colour starts at
   that edge and the content needs its own room inside it. */
.band + .band--warm,
.band + .band--white,
.band + .band--paper,
.band + .band--spruce,
.band + .band--barn,
.band + .band--balsam { padding-top: var(--band-y); }

/* Same problem from the other side: a plain band following one that paints its
   own background also sits at a colour change, and .band + .band has already
   taken its top padding away. Two class selectors so it outranks that rule,
   and it comes after it, which is what actually settles it. */
.band.band--top-gap { padding-top: var(--band-y); }
.band--birch { background: transparent; }
.band--warm {
	background:
		linear-gradient(180deg, rgba(220, 232, 212, .55), rgba(220, 232, 212, .92));
}
.band--paper { background: var(--paper); }
.band--white { background: #fff; }
.band--spruce,
.band--barn {
	background: var(--spruce);
	color: #E8F0E2;
}
.band--spruce h2, .band--spruce h3,
.band--barn h2, .band--barn h3 { color: #F3F7EE; }
.band--spruce a, .band--barn a { color: var(--gold-bright); }
.band--spruce a:hover, .band--barn a:hover { color: #fff; }

.band--balsam {
	background: var(--balsam-deep);
	color: #E5F0DC;
}
.band--balsam h2, .band--balsam h3 { color: #fff; }

.stack { display: flex; flex-direction: column; }
.stack > * + * { margin-top: var(--gap, 1rem); }

.eyebrow {
	font-family: var(--display);
	font-size: 1.2rem;
	font-weight: 600;
	font-style: italic;
	letter-spacing: .02em;
	text-transform: none;
	color: var(--maple);
	margin: 0 0 .7rem;
	display: flex;
	align-items: center;
	gap: .65rem;
}
.eyebrow::before {
	content: "";
	width: 1.6rem;
	height: 3px;
	background: var(--gold);
	border-radius: 2px;
}
.band--spruce .eyebrow,
.band--barn .eyebrow,
.cta-band .eyebrow { color: var(--gold-bright); }

.section-head { margin-bottom: clamp(1.8rem, 3.6vw, 3rem); }
.section-head h2 { font-size: var(--fs-2xl); }
/* :not(.eyebrow) — the eyebrow is a <p> in here as well, and this rule outranks
   its own margin:0, so it was adding 1rem above every section head. */
.section-head p:not(.eyebrow) {
	margin-top: 1rem;
	font-size: var(--fs-md);
	color: var(--ink-soft);
}
.band--spruce .section-head p,
.band--barn .section-head p { color: #C5D4C4; }

.lede {
	font-size: var(--fs-md);
	color: var(--ink-soft);
	max-width: 62ch;
}


/* ==========================================================================
   Buttons
   ========================================================================== */

.btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: .5rem;
	font-family: var(--body);
	font-size: .95rem;
	font-weight: 800;
	letter-spacing: .02em;
	text-transform: none;
	text-decoration: none;
	padding: .85rem 1.45rem;
	border: 2px solid transparent;
	border-radius: 999px;
	cursor: pointer;
	transition: background-color .16s ease, color .16s ease, border-color .16s ease, transform .16s ease, box-shadow .16s ease;
}
.btn:active { transform: translateY(1px); }

.btn--primary {
	background: var(--maple);
	color: #fff;
	border-color: var(--maple-deep);
	box-shadow: 0 3px 0 var(--maple-deep);
}
.btn--primary:hover {
	background: var(--maple-light);
	border-color: color-mix(in srgb, var(--maple) 72%, #fff 28%);
	color: #fff;
	box-shadow: 0 3px 0 color-mix(in srgb, var(--maple-deep) 62%, #fff 38%);
}

.btn--ghost {
	background: transparent;
	color: var(--barn);
	border-color: var(--barn);
}
.btn--ghost:hover {
	background: color-mix(in srgb, var(--pine) 18%, var(--cream) 82%);
	color: var(--spruce);
	border-color: var(--pine);
}

.btn--onDark {
	background: transparent;
	color: #F3F7EE;
	border-color: var(--gold);
}
.btn--onDark:hover { background: var(--gold); color: var(--barn-deep); border-color: var(--gold); }

.btn--gold {
	background: var(--gold);
	color: var(--barn-deep);
	border-color: #A88432;
	box-shadow: 0 3px 0 #8F6F28;
}
.btn--gold:hover { background: var(--gold-bright); color: var(--barn-deep); }

.btn--sm { padding: .55rem 1.05rem; font-size: .85rem; }

/* ==========================================================================
   Header
   ========================================================================== */

.site-header {
	position: sticky;
	top: 0;
	z-index: 100;
	background: var(--header-gradient); /* vertical parchment wash */
	border-bottom: 0;
	box-shadow:  0 1px 0 var(--pine), var(--shadow-sm);
	overflow: visible;
}
.site-header.is-stuck {
	box-shadow: 0 0 2px var(--pine), var(--shadow-sm);
}

.header-inner {
	display: flex;
	align-items: stretch;
	gap: clamp(.75rem, 2.2vw, 1.75rem);
	min-height: calc(clamp(92px, 13vw, 120px) + 10px);
	padding-block: 0;
	overflow: visible;
	transition: min-height .22s ease, padding .22s ease;
}
.site-header.is-stuck .header-inner {
	min-height: calc(64px + 10px);
	padding-block: 0;
}

.brand {
	display: flex;
	align-items: center;
	align-self: center;
	text-decoration: none;
	flex: 0 0 auto;
	min-width: 0;
	line-height: 0;
}
/* Until the logo's bytes arrive the browser paints its alt text in the box,
   which flashes a line of words behind the header on every load. Zeroing the
   font size leaves the alt attribute itself untouched — assistive technology
   still reads it — and only takes away the visible fallback. */
.brand-logo,
.footer-logo { font-size: 0; }
.brand-logo {
	display: block;
	height: clamp(92px, 13vw, 120px);
	width: auto;
	max-width: min(280px, 48vw);
	transition: height .22s ease, max-width .22s ease;
}
.site-header.is-stuck .brand-logo {
	height: 64px;
	max-width: 155px;
}

.header-identity {
	--vt-hang: calc(clamp(92px, 13vw, 120px) + 10px);
	display: flex;
	align-items: center;
	align-self: stretch;
	gap: clamp(.5rem, 1vw, .75rem);
	position: relative;
	z-index: 2;
	flex: 0 0 auto;
	min-width: 0;
}
.header-identity .brand { align-self: center; }

.vt-locator {
	flex: 0 0 auto;
	align-self: flex-start;
	height: calc(clamp(92px, 13vw, 120px) + 10px + var(--vt-hang));
	width: auto;
	aspect-ratio: 112 / 180;
	margin-bottom: calc(var(--vt-hang) * -1);
	pointer-events: none;
	transition: height .22s ease, margin-bottom .22s ease;
}
.vt-locator svg {
	display: block;
	height: 100%;
	width: auto;
	max-width: none;
	overflow: visible;
	filter: drop-shadow(0 1px 1px rgba(19, 38, 26, .2));
}
.vt-map .vt-halo {
	fill: none;
	stroke: #FFF8EC;
	stroke-width: 3.2;
	stroke-linejoin: round;
	stroke-linecap: round;
}
.vt-map .vt-rest {
	fill: url(#vt-gloss);
}
.vt-map .vt-gloss-hi {
	stop-color: color-mix(in srgb, color-mix(in srgb, var(--pine) 22%, var(--cream) 78%) 86%, #fff 14%);
}
.vt-map .vt-gloss-mid {
	stop-color: color-mix(in srgb, var(--pine) 36%, var(--cream) 64%);
}
.vt-map .vt-gloss-lo {
	stop-color: color-mix(in srgb, var(--pine) 46%, var(--cream) 54%);
}
.vt-map .vt-nek {
	fill: var(--pine);
	stroke: var(--pine);
	stroke-width: 1.15;
	stroke-linejoin: round;
}
.vt-map .vt-outline {
	fill: none;
	stroke: var(--spruce);
	stroke-width: 1.75;
	stroke-linejoin: round;
	stroke-linecap: round;
}
.vt-map .vt-star-glow {
	fill: var(--gold-bright);
	opacity: .38;
}
.vt-map .vt-star-mark {
	fill: #F2C94C;
	stroke: #7A5A18;
	stroke-width: .85;
	stroke-linejoin: round;
}
@media (prefers-reduced-motion: no-preference) {
	.vt-map .vt-star-glow {
		animation: vt-star-pulse 2.4s ease-in-out infinite;
	}
}
@keyframes vt-star-pulse {
	50% { opacity: .62; }
}
.site-header.is-stuck .header-identity { --vt-hang: 0px; }
.site-header.is-stuck .vt-locator {
	align-self: center;
	height: 64px;
	margin-bottom: 0;
	overflow: hidden;
}
.site-header.is-stuck .vt-locator svg {
	overflow: hidden;
	filter: none;
}

.header-tools {
	--header-stack: 13px;
	margin-left: auto;
	display: flex;
	flex-direction: column;
	align-items: flex-end;
	justify-content: flex-start;
	gap: calc(var(--header-stack) + 3px);
	padding-block: var(--header-stack);
	min-width: 0;
}
.site-header.is-stuck .header-tools {
	gap: 0;
	padding-block: var(--header-stack);
	justify-content: center;
}

.site-ribbon {
	background: var(--barn);
	color: var(--gold-bright);
	text-align: center;
	font-family: var(--display);
	font-style: italic;
	font-weight: 600;
	font-size: clamp(1.42rem, 1.5vw, .92rem);
	letter-spacing: .08em;
	padding: .48rem var(--gutter);
	margin: 0;
}

.nav { margin-left: 0; }
.nav-list {
	display: flex;
	align-items: stretch;
	flex-wrap: nowrap;
	justify-content: flex-end;
	gap: 0;
	list-style: none;
	margin: 0;
	padding: 0;
	background: var(--pine);
	border: 0;
	border-radius: 4px;
	box-shadow:
		1px 1px 1px rgba(255, 255, 255, 0.5),
		inset 1px 1px 1px rgba(0, 0, 0, 0.4);
	overflow: hidden;
}
.nav-list li {
	display: flex;
	flex: 0 1 auto;
}
.nav-list a {
	display: flex;
	align-items: center;
	justify-content: center;
	position: relative;
	font-family: var(--display);
	font-size: clamp(1.02rem, 1.25vw, 1.18rem);
	font-weight: 700;
	line-height: 1.15;
	letter-spacing: .01em;
	color: #F3F7EE;
	text-decoration: none;
	padding: .9rem 1.28rem;
	white-space: nowrap;
	border: 0;
	border-radius: 0;
	background: transparent;
	box-shadow: none;
	transition: background-color .16s ease, color .16s ease;
}
.nav-list a:hover {
	background: color-mix(in srgb, var(--pine) 90%, #000 10%);
	color: #F3F7EE;
}
.nav-list a[aria-current="page"] {
	background: var(--maple);
	color: #F3F7EE;
}
.nav-list a[aria-current="page"]:hover {
	background: var(--maple);
	color: #F3F7EE;
}
.nav-list a:hover::before,
.nav-list a[aria-current="page"]::before {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	top: 0;
	height: 2px;
	background: linear-gradient(180deg, rgba(0, 0, 0, 0.4), transparent);
	pointer-events: none;
}
.nav-list a:focus-visible {
	outline: 3px solid var(--gold-bright);
	outline-offset: -3px;
	z-index: 1;
}

.header-cta {
	display: flex;
	align-items: center;
	gap: 1.45rem;
	flex: 0 0 auto;
	order: -1;
	overflow: visible;
	max-height: 5rem;
	opacity: 1;
	transition: max-height .22s ease, opacity .18s ease, margin .22s ease;
}
.site-header.is-stuck .header-cta {
	overflow: hidden;
	max-height: 0;
	opacity: 0;
	margin: 0;
	pointer-events: none;
}
.header-cta .btn {
	line-height: 1.2;
	font-size: 1.05rem;
	padding: .62rem 1.2rem;
	background: var(--bevel-surface-bg);
	color: var(--barn);
	border: 1px solid var(--bevel-surface-border);
	border-radius: var(--bevel-surface-radius);
	box-shadow: var(--bevel-surface-shadow);
	transition: box-shadow .16s ease, transform .16s ease;
}
.header-cta .btn:hover {
	background: var(--bevel-surface-bg);
	color: var(--barn);
	border-color: var(--bevel-surface-border);
	box-shadow: var(--bevel-surface-shadow-hover);
}
.header-cta .btn:active {
	box-shadow: var(--bevel-surface-shadow-active);
}
.header-phone {
	display: inline-flex;
	align-items: center;
	gap: .45rem;
	font-family: var(--display);
	font-weight: 700;
	font-size: 1.08rem;
	color: var(--barn);
	text-decoration: none;
	white-space: nowrap;
}
.header-phone:hover { color: var(--maple); }
.header-phone:hover .header-cta-icon { color: var(--gold-bright); }
.header-cta-icon {
	width: 1.12em;
	height: 1.12em;
	flex-shrink: 0;
	margin-right: 4px;
	color: var(--gold);
}
.header-cta .btn .header-cta-icon {
	margin-left: -3px;
}

.nav-toggle {
	display: none;
	background: var(--bevel-surface-bg);
	border: 1px solid var(--bevel-surface-border);
	border-radius: var(--bevel-surface-radius);
	width: 46px; height: 42px;
	align-items: center; justify-content: center;
	cursor: pointer;
	color: var(--barn);
	margin-left: auto;
	flex-shrink: 0;
	box-shadow: var(--bevel-surface-shadow);
	transition: box-shadow .16s ease, transform .16s ease;
}
.nav-toggle:hover {
	box-shadow: var(--bevel-surface-shadow-hover);
}
.nav-toggle:active {
	transform: translateY(1px);
	box-shadow: var(--bevel-surface-shadow-active);
}
.nav-toggle svg { width: 22px; height: 22px; }
.nav-toggle .icon-close { display: none; }
.nav-toggle[aria-expanded="true"] .icon-open { display: none; }
.nav-toggle[aria-expanded="true"] .icon-close { display: block; }

@media (max-width: 1080px) {
	.header-tools {
		flex-direction: row;
		align-items: center;
		gap: .85rem;
	}
	.nav-toggle {
		display: flex;
		position: relative;
		z-index: 102;
		margin-left: 0;
	}
	.header-cta .btn { display: none; }
	.nav {
		position: fixed;
		inset: 0 0 0 auto;
		width: min(360px, 86vw);
		background: var(--header-gradient);
		padding: 6.5rem 0 2rem;
		transform: translateX(100%);
		visibility: hidden;
		transition: transform .28s cubic-bezier(.4, 0, .2, 1), visibility .28s;
		overflow-y: auto;
		box-shadow: var(--shadow-lg);
		margin-left: 0;
		z-index: 101;
	}
	.nav.is-open { transform: translateX(0); visibility: visible; }
	.nav-list {
		flex-direction: column;
		align-items: stretch;
		width: 100%;
		background: transparent;
		border-radius: 0;
		box-shadow: none;
		overflow: visible;
	}
	.nav-list li {
		width: 100%;
		flex: 1 1 auto;
	}
	.nav-list a {
		justify-content: flex-start;
		width: 100%;
		box-sizing: border-box;
		font-size: 1.18rem;
		padding: 1.05rem var(--gutter);
		color: var(--pine);
	}
	.nav-list a:hover {
		background: color-mix(in srgb, var(--header-wash-deep) 45%, transparent);
		color: var(--maple);
	}
	.nav-list a[aria-current="page"] {
		background: color-mix(in srgb, var(--maple) 14%, var(--header-wash) 86%);
		color: var(--maple);
	}
	.nav-list a[aria-current="page"]:hover {
		background: color-mix(in srgb, var(--maple) 18%, var(--header-wash) 82%);
		color: var(--maple);
	}
	.nav-list a:hover::before,
	.nav-list a[aria-current="page"]::before {
		display: none;
	}
	.nav-drawer-cta {
		margin-top: 2rem;
		padding-inline: var(--gutter);
		display: flex;
		flex-direction: column;
		gap: .9rem;
	}
	.nav-drawer-cta .btn { width: 100%; }
	.nav-drawer-cta .btn--onDark {
		background: var(--spruce);
		color: #fff;
		border-color: var(--spruce-deep);
		box-shadow: 0 3px 0 var(--spruce-deep);
	}
	.nav-drawer-cta .btn--onDark:hover {
		background: var(--pine);
		color: #fff;
		border-color: color-mix(in srgb, var(--pine) 72%, #fff 28%);
		box-shadow: 0 3px 0 color-mix(in srgb, var(--spruce) 70%, #fff 30%);
	}
	.nav-scrim {
		position: fixed; inset: 0;
		background: rgba(19, 38, 26, .55);
		opacity: 0; pointer-events: none;
		transition: opacity .28s ease;
		z-index: 99;
	}
	.nav-scrim.is-open { opacity: 1; pointer-events: auto; }
}
@media (min-width: 1081px) {
	.nav-drawer-cta, .nav-scrim { display: none; }
}
@media (max-width: 560px) {
	.header-cta { display: none; }
	.header-inner { min-height: calc(88px + 10px); }
	.brand-logo { height: 88px; }
	.header-identity { --vt-hang: calc(88px + 10px); }
	.vt-locator { height: calc(88px + 10px + var(--vt-hang)); }
	.site-header.is-stuck .header-inner { min-height: calc(52px + 10px); }
	.site-header.is-stuck .brand-logo { height: 52px; }
	.site-header.is-stuck .vt-locator { height: 52px; }
	.site-ribbon { letter-spacing: .04em; }
}


/* ==========================================================================
   REDESIGN — everything below the preserved header.

   The photography does the talking. Pictures are never framed, never tinted
   and never covered with type; the page earns its structure from whitespace,
   scale changes and the parchment/pine palette the header already owns.
   ========================================================================== */

:root {
	/* Sampled from the campground's own hand-painted road sign — the rust
	   ground and the pale teal lettering. Real brand colour, not invented. */
	--rust:          #A1562B;
	--rust-bright:   #C2734E;
	--sign-teal:     #7A9CA6;
	--sign-teal-soft:#98B9C4;

	/* Mirrors the header's own min-height in the foundation block, so the
	   hero can subtract it and stand exactly one screen tall. */
	--header-h: calc(clamp(92px, 13vw, 120px) + 10px);

	--measure: 64ch;

	/* Depth of the pennant string, and the padding its band gives back. The
	   artwork is 1200 x 49.25 in its own units, and preserveAspectRatio="meet"
	   only lets it reach both edges while the box is limited by width rather
	   than height — which needs height >= width / 24.4. 4.2vw clears that the
	   whole way up, and the 80px ceiling holds it past ~1900px. */
	--bunting-h: clamp(34px, 4.2vw, 80px);

	/* The hero's height, hoisted to a variable so the legend can size a square
	   against it. Still stated as a height and never as an aspect-ratio: the
	   three terms are the screen, the 1:1 cap, and a ceiling so a tall desktop
	   does not hand the hero the whole page. */
	--hero-h: min(calc(100vh - var(--header-h)), 100vw, 1100px);
}
@supports (height: 100svh) {
	:root { --hero-h: min(calc(100svh - var(--header-h)), 100vw, 1100px); }
}
@media (max-width: 560px) {
	:root { --header-h: calc(88px + 10px); }
}

/* ==========================================================================
   Vermont locator — pictorial relief

   Engraved-map peaks rather than abstract shading: each summit is two flat
   planes, a lit west face and a shadowed east face. No snow caps and no
   hatching, because the map is 40px tall in the header for all but the few
   seconds of the intro, and anything finer than two planes turns to mush.
   Positions come from real latitude and longitude — see the partial.
   ========================================================================== */

.vt-ranges g { stroke: #2E4633; stroke-width: .3; stroke-linejoin: round; }
.vt-peak-l { fill: #7C9A76; }   /* lit west face  */
.vt-peak-r { fill: #35543A; }   /* shadowed east face */

/* The Kingdom is filled dark, so its summits invert to stay legible. Flat
   class names rather than a `.vt-ranges--nek .vt-peak-l` descendant rule,
   which is what bled across when the peaks shared one symbol. */
.vt-peak-l-k { fill: #93B28C; }
.vt-peak-r-k { fill: #55764F; }

/* ==========================================================================
   Header overrides

   Kept here rather than in _foundation.css so that file stays a clean mirror
   of dev and the preserved-header contract remains auditable. These selectors
   match dev's exactly and win on source order alone.
   ========================================================================== */

/* The Vermont map is drawn slightly taller in the shrunken bar so it reads
   as the same height as the logo beside it. It needs a box taller than the
   logo to do that: the state outline only fills 88.12% of the viewBox height
   (the shape spans 2.39..161 of 180 units), so a 64px box drew a ~56px state
   next to a 64px logo. 73px of box gives 64px of Vermont.

   It stays fully inside the bar — no overhang — which is what dev did; only
   the height changes, and the drop shadow comes back because the relief
   needs a little separation from the parchment. */
.site-header.is-stuck .vt-locator {
	align-self: center;
	height: 70px;
	margin-bottom: 0;
	overflow: visible;
}
.site-header.is-stuck .vt-locator svg {
	overflow: visible;
	filter: drop-shadow(0 1px 1px rgba(19, 38, 26, .2));
}
@media (max-width: 560px) {
	/* 52px logo on small screens. */
	.site-header.is-stuck .vt-locator { height: 57px; }
}

/* Below 767px the logo sits centred on the header rather than tucked against
   the Vermont map, which leaves it stranded off to one side.

   Centred with auto margins and a stretched block, NOT with
   `transform: translate(-50%, -50%)`. The intro animation drives this same
   element's `transform`, and a centring transform would be overwritten the
   moment the slide began — the logo would jump out of place for the whole
   animation and only snap back at the end. Auto margins leave `transform`
   free. The intro needs no change: it measures the logo's resting position,
   so the slide simply ends at the centre instead of beside the map.

   Held back below 375px, where the map and a centred logo would overlap. */
@media (min-width: 375px) and (max-width: 767px) {
	.header-inner { position: relative; }

	/* dev gives .header-identity `position: relative`, which made *it* the
	   containing block for the absolutely positioned logo — so the logo
	   centred inside a 136px-wide box hard against the map instead of on the
	   header. Dropping it back to static hands that job to .header-inner.
	   Its z-index: 2 goes with it, which is harmless here: the drawer and the
	   hamburger carry z-index 101/102 and still sit above the map. */
	.header-identity { position: static; }

	.header-identity .brand {
		position: absolute;
		inset-block: 0;
		left: 0;
		right: 0;
		margin-inline: auto;
		width: fit-content;
	}
}

/* The phone number goes at the same breakpoint. Dev dropped it at 560px, which
   left it sitting beside a centred logo on a mid-size phone with nowhere
   sensible to be; it is still in the drawer and in the footer. */
@media (max-width: 767px) {
	.header-cta { display: none; }
}

/* Reloading a page that was already scrolled used to show the header at full
   size for a moment and then animate down to the stuck size, because the
   class is applied by script and the browser may not restore the scroll
   position until after first paint. `no-anim` holds every header transition
   until the page has settled, so any correction is instantaneous rather than
   a visible 220ms resize. The script removes it once that has happened. */
.site-header.no-anim,
.site-header.no-anim .header-inner,
.site-header.no-anim .brand-logo,
.site-header.no-anim .vt-locator,
.site-header.no-anim .header-cta,
.site-header.no-anim .header-tools {
	transition: none !important;
}

/* ---- the header controls ------------------------------------------------
   Restyled 2026-09-15 to the same language as the hero's scroll cue: pill,
   display face in letterspaced caps, mark on a disc. Both the phone and the
   reservations link are white pills — they are the two raised controls in the
   parchment bar and they read as a pair.

   Written here rather than in _foundation.css so that file stays dev's copy
   byte for byte — this is a deliberate divergence from the dev header, and the
   only one. The icons become discs through padding on the <svg> itself, which
   keeps the partial's markup untouched. */
.header-cta .btn,
.header-phone {
	display: inline-flex;
	align-items: center;
	gap: .55rem;
	padding: .42rem .5rem .42rem 1rem;
	background: #fff;
	border: 0;
	border-radius: 999px;
	font-family: var(--display);
	font-weight: 600;
	font-size: .85rem;
	letter-spacing: .085em;
	text-transform: uppercase;
	color: var(--spruce);
	box-shadow: 0 1px 3px rgba(19, 38, 26, .28);
	transition: color .16s ease, transform .16s ease;
}
.header-cta .btn:hover,
.header-phone:hover {
	background: #fff;
	color: var(--rust);
	box-shadow: 0 1px 3px rgba(19, 38, 26, .28);
}
.header-cta .btn:active,
.header-phone:active { transform: translateY(1px); }

/* The mark inside the disc. content-box, so the padding reads as the disc's
   radius rather than shrinking the glyph.

   13px in a 26px disc, not 15px: these are full-bleed square glyphs and a
   circle's inscribed square is only 18.4px of its 26px width, so at 15px the
   corners ran into the curve and read as clipped. The cue's chevron gets away
   with 15px because it is a wide, shallow mark that never reaches the corners.
   overflow guards the stroke, which sits a unit outside the path.

   Gold disc, spruce mark: cream on gold-bright is 1.75:1 and the glyph nearly
   disappears, where spruce on it is 5.80:1. The mark flips to cream on the rust
   hover, which is 4.73:1. */
.header-cta .btn .header-cta-icon,
.header-phone .header-cta-icon {
	box-sizing: content-box;
	width: 13px;
	height: 13px;
	margin: 0;
	padding: 6.5px;
	border-radius: 50%;
	overflow: visible;
	background: var(--gold-bright);
	color: var(--spruce);
	order: 1;                 /* the mark sits after the word, as on the cue */
	transition: background .16s ease, color .16s ease;
}
.header-cta .btn:hover .header-cta-icon,
.header-phone:hover .header-cta-icon {
	background: var(--rust);
	color: var(--cream);
}


/* ==========================================================================
   Hero — full-height photography, nothing on top of it
   ========================================================================== */

/* The hero is never taller than it is wide.

   A portrait-shaped box makes `object-fit: cover` scale these landscape
   photographs by their height, which throws most of their width off the
   sides — a wide view of the Kingdom reduced to a narrow vertical slice. At
   1:1 or wider they are scaled by width instead and the whole scene stays in
   frame. aspect-ratio supplies the height; max-height then clamps it to
   whatever the screen can actually show, so the box only ever gets *wider*
   than square, never taller. */
.hero {
	position: relative;
	/* Stated as a height, not an aspect-ratio. With `aspect-ratio: 1/1` plus a
	   max-height, the clamp pulled the *width* in with it — a 1440px viewport
	   rendered a 683px-wide hero. min() on three heights can only ever shorten
	   the box, never narrow it: the screen, the viewport width (the 1:1 cap),
	   and a ceiling so a tall desktop does not hand it the whole page. */
	height: var(--hero-h);
	overflow: hidden;
	background: var(--spruce-deep);
}

.hero-stage {
	position: absolute;
	inset: 0;
}

.hero-slide {
	position: absolute;
	inset: 0;
	margin: 0;
	opacity: 0;
	visibility: hidden;
	transition: opacity 1200ms ease, visibility 1200ms;
}
.hero-slide.is-active {
	opacity: 1;
	visibility: visible;
}
.hero-slide img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

/* A slow drift gives the stills some life: each photograph eases *outward*,
   opening the view rather than pushing into it.

   Driven by `.is-drifting`, which goes on at the moment the Vermont map
   begins its run for the header — so the map, the logo and the photograph
   all start moving on the same frame, rather than the photograph waiting for
   the intro to finish and starting alone.

   A transition, not keyframes, and the resting state is the zoomed end. As
   keyframes this jumped: the photograph sat at scale(1) through the intro and
   snapped to the animation's opening frame when the gate opened. Starting it
   already at 1.06 makes the motion a continuation of what is on screen.

   The transition lives on the base rule, not on the active one. Declared only
   under `.is-active`, it disappeared along with the class the moment a slide
   was replaced — so the outgoing photograph snapped from 1 back to 1.06 while
   still fully visible at the head of the crossfade.

   `.is-leaving` then carries the *target* through the crossfade. Without it the
   outgoing photograph reversed — easing back toward 1.06 while the incoming one
   eased out to 1 — and two opposed motions under a crossfade cancel: the zoom
   appeared to stop dead for the length of the fade. Holding the same target
   means both photographs travel the same way while they cross, and the drift
   reads as one continuous move. JS drops the class once the fade is over and
   snaps the scale back behind `.is-rewound`, with the transition off for that
   frame, while the slide is transparent. */
@media (prefers-reduced-motion: no-preference) {
	.hero-slide img {
		transform: scale(1.06);
		transition: transform 9s ease-out;
	}
	.hero.is-drifting .hero-slide.is-active img,
	.hero.is-drifting .hero-slide.is-leaving img {
		transform: scale(1);
	}
	.hero-slide.is-rewound img { transition: none; }
}

/* Per-image framing. Each photo has its own subject height, so the crop is
   tuned rather than left at "center" for all six. */
.hero-slide[data-frame="high"]   img { object-position: center 32%; }
.hero-slide[data-frame="low"]    img { object-position: center 68%; }
.hero-slide[data-frame="center"] img { object-position: center 50%; }

/* Where the scroll cue lands. The header shrinks once it is stuck, so the
   offset cannot be read off the header as it stands at the top of the page —
   this carries the *stuck* height, and scrollIntoView() honours it. Mirrors
   `.site-header.is-stuck .header-inner` in _foundation.css; re-sync if that
   moves. */
.hero + * { scroll-margin-top: calc(64px + 10px); }

/* ---- hero furniture -----------------------------------------------------
   Small parchment chips in the bottom margin. No scrim, no full-width bar,
   nothing that sits over the middle of the picture. */

.hero-bar {
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	display: flex;
	align-items: flex-end;
	justify-content: space-between;
	gap: 1rem;
	padding: clamp(.9rem, 2.2vw, 1.6rem) var(--gutter);
	pointer-events: none;
	opacity: 0;
	transition: opacity 600ms ease;
}
.hero.intro-done .hero-bar { opacity: 1; }
.hero-bar > * { pointer-events: auto; }

/* The scroll cue. Same parchment chip as the rest of the hero furniture, but
   lettered as a control rather than a caption — it is the one thing down here
   that asks to be pressed. */
.hero-scroll {
	display: inline-flex;
	align-items: center;
	gap: .5rem;
	margin: 0;
	padding: .46rem .5rem .46rem .95rem;
	border: 0;
	cursor: pointer;
	background: rgba(255, 248, 236, .90);
	backdrop-filter: blur(6px);
	-webkit-backdrop-filter: blur(6px);
	border-radius: 999px;
	font-family: var(--display);
	font-weight: 600;
	font-size: .8rem;
	letter-spacing: .085em;
	text-transform: uppercase;
	color: var(--spruce);
	box-shadow: 0 1px 3px rgba(19, 38, 26, .28);
	transition: background .16s ease, color .16s ease, transform .16s ease;
}
.hero-scroll:hover { background: #fff; color: var(--rust); }
.hero-scroll:active { transform: translateY(1px); }

.hero-scroll-arrow {
	flex: 0 0 auto;
	width: 26px;
	height: 26px;
	display: grid;
	place-items: center;
	border-radius: 50%;
	background: var(--spruce);
	color: var(--cream);
	transition: background .16s ease;
}
.hero-scroll:hover .hero-scroll-arrow { background: var(--rust); }
.hero-scroll-arrow svg { width: 15px; height: 15px; }

/* The nudge is on the arrow alone: the chip stays put, so the cue reads as an
   invitation rather than the whole control twitching. */
@media (prefers-reduced-motion: no-preference) {
	.hero-scroll-arrow svg { animation: hero-scroll-nudge 2.6s ease-in-out infinite; }
}
@keyframes hero-scroll-nudge {
	0%, 62%, 100% { transform: translateY(0); }
	31%           { transform: translateY(2.5px); }
}

.hero-nav {
	display: flex;
	align-items: center;
	gap: .5rem;
}

/* Same colouring as the scroll cue's chevron disc at the other end of the bar:
   spruce disc, cream mark, rust on hover. Opaque, so no backdrop-filter — it
   was only ever holding a translucent parchment fill legible over a photo. */
.hero-btn {
	width: 42px;
	height: 42px;
	display: grid;
	place-items: center;
	border: 0;
	border-radius: 50%;
	cursor: pointer;
	background: var(--spruce);
	color: var(--cream);
	box-shadow: 0 1px 3px rgba(19, 38, 26, .28);
	transition: background .16s ease, transform .16s ease, color .16s ease;
}
.hero-btn:hover { background: var(--rust); color: var(--cream); }
.hero-btn:active { transform: translateY(1px); }
.hero-btn svg { width: 19px; height: 19px; }

.hero-dots {
	display: flex;
	align-items: center;
	gap: .4rem;
	padding: 0 .5rem;
}
.hero-dot {
	width: 9px;
	height: 9px;
	padding: 0;
	border: 0;
	border-radius: 50%;
	cursor: pointer;
	background: rgba(255, 248, 236, .55);
	box-shadow: 0 1px 2px rgba(19, 38, 26, .35);
	transition: background .2s ease, transform .2s ease;
}
.hero-dot:hover { background: rgba(255, 248, 236, .85); }
.hero-dot[aria-current="true"] {
	background: var(--gold-bright);
	transform: scale(1.35);
}

@media (max-width: 720px) {
	/* Narrow: the chip drops to the arrow alone, so it cannot crowd the dots.
	   The button keeps its aria-label, so the name survives losing the text. */
	.hero-scroll-label { display: none; }
	.hero-scroll { padding: .46rem; }
}

/* ---- the intro reveal ---------------------------------------------------
   The Vermont map starts large over the photograph and flies home into its
   real header slot. The element that animates IS the header's locator, moved
   by a transform only, so it lands pixel-exact with no layout shift and no
   second copy to keep in sync. JS measures and drives it; these rules only
   handle stacking and the shadow that keeps it legible over a photo. */

/* Stacking is needed for the whole intro; the lift shadow is not. They were
   one class, so the shadow vanished the instant the map landed. Split apart,
   the shadow can be released at the start of the flight and fade out as the
   map descends — which is also how a real shadow behaves as something settles
   onto a surface. */
/* Before the intro owns the map — see the inline script in head.html. The
   locator is hidden rather than left in its header slot, so the first thing
   seen is not the end state of an animation that has not started. */
html.intro-pending .vt-locator { opacity: 0; }

.vt-locator.is-intro {
	z-index: 5;
}
.vt-locator.is-lifted {
	filter:
		drop-shadow(0 2px 3px rgba(19, 38, 26, .34))
		drop-shadow(0 18px 42px rgba(19, 38, 26, .40));
}

/* Nav hover pulse

   A quick swell and back so the bar feels reactive under the cursor. Run as a
   keyframe animation rather than a transition, because a transition can only
   hold the hovered state — it cannot go up and come back while the pointer
   stays put.

   It swells and returns, nothing more. An earlier version undershot to .994 on
   the way back for a bounce; at this size the dip read as a glitch at the end
   of the motion rather than as weight.

   The words move, not the panel. The animation is applied to .nav-label, an
   inner span, because the coloured hover panel and the ::before highlight
   both belong to the <a> — scaling the link took them along with it, growing
   the panel into its neighbours and stretching the 2px highlight. The panel
   now holds still and only the type swells inside it, which also means the
   `overflow: hidden` that .nav-list needs for its bevel never comes into it.

   Kept to 3%. Enough to register as a response to the cursor without the
   words looking like they are being pushed around.

   hover:hover keeps it off touch screens, where it would fire on every tap. */
/* Nav hover: the label tilts into an italic-looking slant and back off it,
   over the same 280ms the bounce used, eased out both ways.

   A transform, deliberately, not the real italic. `font-style` is a discrete
   property — it can be swapped but never eased — so a true italic face cannot
   tilt into place. Skewing the roman does, at the cost of being an oblique
   rather than Zilla Slab's drawn italic: same slant, same letterforms. The
   pivot sits near the baseline so the word leans from where it stands rather
   than pulling its bottom half left. */
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
	.nav-label {
		display: inline-block;
		transform-origin: 50% 82%;
		transition: transform 380ms cubic-bezier(.22, .8, .3, 1);
		/* The 1px hop at the end of the tilt is a compositing artefact, not
		   motion: skewX moves nothing vertically. Chrome promotes the label to
		   its own layer for the duration of the transform and snaps that layer
		   to whole device pixels — the nav sits at a fractional offset, so the
		   text lands up to a pixel off where it renders unpromoted, then jumps
		   back when the layer is discarded. will-change keeps it promoted, so
		   rest, motion and end all rasterise the same way. */
		will-change: transform;
	}
	.nav-list a:hover .nav-label { transform: skewX(-11deg); }
}

/* No panel on hover any more — the tilt is the whole signal. The current page
   keeps its maple block, which is state rather than hover feedback, and the
   top highlight goes with the panel it belonged to. */
.nav-list a:hover { background: transparent; }
.nav-list a:hover::before { content: none; }
.nav-list a[aria-current="page"]:hover::before { content: ""; }

/* ==========================================================================
   Hero legend

   The line that used to sit in a green strip under the hero. It now opens the
   intro: as the map sets off for the header the words are already arriving,
   swelling in from far beyond the edges of the hero and settling at size,
   where they stay for the rest of the slideshow.

   Timed off `.is-drifting`, the same signal that starts the map's flight and
   the photograph's zoom, so all three move together.

   The <p> fills the hero and centres its text with grid rather than a
   centring transform, which keeps `transform` free for the animation.
   It sits below the map (which lives in the header's stacking context) so the
   relief stays crisp while the type passes behind it.
   ========================================================================== */

.hero-legend {
	position: absolute;
	inset: 0;
	z-index: 1;
	margin: 0;
	display: grid;
	place-items: center;
	padding-inline: var(--gutter);
	pointer-events: none;
	opacity: 0;

	/* Settled opacity and shadow live here as variables because the keyframes
	   below have to arrive at exactly these values. */
	--legend-alpha: .82;
	--legend-shadow: 0 .015em .05em rgba(0, 0, 0, .30),
	                 0 .05em .30em rgba(0, 0, 0, .42);
	--legend-shadow-0: 0 .015em .05em rgba(0, 0, 0, 0),
	                   0 .05em .30em rgba(0, 0, 0, 0);

	/* Two shadows: a tight one for edge definition against pale sky, a wider
	   soft one to lift the words off the photograph. Both in em so they track
	   the type through the clamp. Declared here rather than on the span: the
	   keyframes animate text-shadow on this element and the span inherits it,
	   and a text-shadow of its own would beat that inherited value. The
	   font-size sits here too, for the same reason in reverse: the shadow's em
	   units resolve against *this* element's font, so at the <p>'s inherited
	   17px a .30em blur came out 5px instead of 30px. */
	/* The square's side. Governed by the hero's height rather than the
	   viewport's width, because the hero is wider than it is tall on every
	   desktop — sized off vw alone the block would not fit. */
	--legend-w: min(72vw, calc(var(--hero-h) * .72));

	/* Only the em basis for the shadow above; the lines set their own sizes.
	   5.3 is about the mean line width, so the shadow tracks the block. */
	font-size: calc(var(--legend-w) / 5.3);
	text-shadow: var(--legend-shadow);
}
/* Equal-width lines. Each line divides the block's width by its own width in
   ems, so they all render exactly one block wide at four different sizes.

   Line-height is 1.05 by Joshua's eye. 1.45 is what makes the ink literally
   square and it read as too airy; tighter stacks better. If a true square is
   ever wanted back it is 1.45 — nothing else needs to move.

   If Archivo Black fails to load the fallback's metrics will not match and the
   lines will only be roughly equal. That is the whole degradation. */
.hero-legend-block {
	display: block;
	width: var(--legend-w);
	line-height: 1.05;
	text-align: center;
	/* Archivo Black first; the fallbacks are the real thing where it exists. */
	font-family: "Archivo Black", "Helvetica Neue", Helvetica, Arial, sans-serif;
	font-weight: 400;      /* Archivo Black is black at 400 — never synthesise */
	letter-spacing: -.022em;
	color: #fff;
}
.hero-legend-line {
	display: block;
	font-size: calc(var(--legend-w) / var(--w));
	white-space: nowrap;
	/* Optical left alignment — see the note in the markup. Transform, so it
	   shifts the ink without touching the layout the widths depend on. */
	transform: translateX(calc(var(--legend-w) * var(--nudge, 0)));
}

/* "in" is a joiner, not part of the name — held back so the line reads as
   "Vermont's" with a small word leading into it. It sits on the same baseline;
   its size is part of what line two's --w measures, so change one and the
   other has to be measured again. */
.hero-legend-minor { font-size: .6em; }

@media (prefers-reduced-motion: no-preference) {
	.hero.is-drifting .hero-legend {
		/* Two animations over the same 3000ms rather than one: a keyframe's
		   timing function applies to every property in the segment, so scale
		   and opacity cannot ease differently inside a single rule. Split, the
		   scale keeps its ease-out landing while the fade runs evenly across
		   the whole duration. */
		animation: hero-legend-scale 3000ms cubic-bezier(.16, .84, .3, 1) both,
		           hero-legend-fade  3000ms linear both;
	}
}
/* No motion: the line is part of the composition, so show it outright. */
@media (prefers-reduced-motion: reduce) {
	.hero-legend { opacity: var(--legend-alpha); }
}

@keyframes hero-legend-scale {
	from { transform: scale(7); }
	to   { transform: scale(1); }
}

/* The words gather weight evenly the whole way in — the shadow arrives with
   them, starting transparent so it is not a 2em blur at scale(7). */
@keyframes hero-legend-fade {
	from { opacity: 0;                   text-shadow: var(--legend-shadow-0); }
	to   { opacity: var(--legend-alpha); text-shadow: var(--legend-shadow); }
}

/* ==========================================================================
   Photographs
   Bare edges, no border, no radius, no shadow. Separation comes from space.
   ========================================================================== */

.photo {
	display: block;
	width: 100%;
	height: auto;
	background: var(--cream-deep);
}
.photo--cover {
	height: 100%;
	object-fit: cover;
}

figure.shot { margin: 0; }
figure.shot figcaption {
	margin-top: .7rem;
	font-family: var(--display);
	font-style: italic;
	font-size: var(--fs-sm);
	color: var(--ink-faint);
}

/* Break the container and run to both edges of the viewport. */
.bleed {
	width: 100vw;
	margin-inline: calc(50% - 50vw);
	max-width: none;
}

.ratio-wide  { aspect-ratio: 16 / 9; }
.ratio-tall  { aspect-ratio: 4 / 5; }
.ratio-square{ aspect-ratio: 1 / 1; }
.ratio-pano  { aspect-ratio: 21 / 9; }
.ratio-wide img, .ratio-tall img, .ratio-square img, .ratio-pano img {
	width: 100%; height: 100%; object-fit: cover; display: block;
}

/* ==========================================================================
   Welcome
   ========================================================================== */

.welcome-grid {
	display: grid;
	grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
	gap: clamp(2rem, 5vw, 4.5rem);
	align-items: start;
}
@media (max-width: 900px) {
	.welcome-grid { grid-template-columns: 1fr; }
}

.welcome-body h2 { font-size: var(--fs-2xl); margin-bottom: 1.4rem; }
.welcome-body p {
	max-width: var(--measure);
	font-size: 1.2rem;
}

/* Paragraphs in this column run on with no gap, so a break has to be asked for.
   One em of the body leading = exactly one blank line, and it tracks the type
   size rather than being pinned to a pixel value. */
.para-break { margin-top: 1.65em; }

/* The season facts, as a plain list on parchment rather than a bordered card. */
/* The card is a pane of tinted glass laid on the page rather than a solid chip
   cut out of it. The page colour reads up through a translucent parchment
   gradient, a bright inset top edge catches the light, and the shadow is split
   into a tight contact layer and a wide ambient one so the card reads as
   floating a real distance above the band instead of being outlined on it. */
.season-facts {
	position: relative;
	isolation: isolate;
	padding: clamp(1.6rem, 3vw, 2.35rem);
	border-radius: var(--glass-radius);
	border: 1px solid rgba(255, 255, 255, .7);
	background:
		linear-gradient(
			180deg,
			rgba(255, 255, 255, .88) 0%,
			rgba(255, 248, 236, .74) 48%,
			rgba(232, 217, 192, .56) 100%
		);
	backdrop-filter: blur(20px) saturate(175%);
	-webkit-backdrop-filter: blur(20px) saturate(175%);
	box-shadow:
		0 1px 2px rgba(19, 38, 26, .05),
		0 10px 22px -8px rgba(19, 38, 26, .10),
		0 28px 55px -16px rgba(19, 38, 26, .16),
		inset 0 1px 0 rgba(255, 255, 255, .95);
}

/* Specular sheen across the top third — the give-away that a surface is glossy
   rather than matte. Sits above the fill, below the content. */
.season-facts::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	border-radius: inherit;
	pointer-events: none;
	background: linear-gradient(
		176deg,
		rgba(255, 255, 255, .6) 0%,
		rgba(255, 255, 255, .16) 26%,
		rgba(255, 255, 255, 0) 48%
	);
}

/* The card rides down with the text column and stops flush with the bottom of
   the grid row — which the taller left column sets, so it comes to rest level
   with the map link. The offset clears the shrunken sticky header. Only worth
   doing while the two columns sit side by side; stacked, there is nothing to
   travel alongside. */
@media (min-width: 901px) {
	.season-facts {
		position: sticky;
		top: calc(var(--header-h-stuck) + 1.25rem);
		align-self: start;
	}
}
.season-facts h3 {
	font-size: var(--fs-lg);
	margin: .6rem 0 1.2rem;
}
.season-facts dl {
	margin: 0;
	display: grid;
	gap: 0;
}
.season-facts dl > div {
	display: flex;
	justify-content: space-between;
	gap: 1rem;
	padding: .62rem 0;
	/* A hairline of shadow rather than a drawn rule — on a translucent surface a
	   solid divider reads as printed on top of the glass instead of in it. */
	border-bottom: 1px solid rgba(19, 38, 26, .07);
}
.season-facts dl > div:last-of-type { border-bottom: 0; }
.season-facts dt {
	font-size: var(--fs-sm);
	color: var(--ink-soft);
}
.season-facts dd {
	margin: 0;
	font-family: var(--display);
	font-weight: 600;
	font-size: 1.2rem;
	color: var(--spruce);
	text-align: right;
}
.season-facts .btn { margin-top: 1.5rem; width: 100%; }

/* The button is the same material a stop denser: the card is the glass, this is
   the lozenge sitting in it. Lit from above with a top-edge inset highlight and
   a shadow tinted with its own colour, so it reads as lifted rather than as a
   flat swatch with a hard ledge under it. Scoped to the card — the stacked
   button elsewhere on the site is untouched. */
.season-facts .btn--primary {
	border: 1px solid rgba(255, 255, 255, .22);
	background: linear-gradient(
		180deg,
		color-mix(in srgb, var(--maple) 86%, #fff 14%) 0%,
		var(--maple) 54%,
		color-mix(in srgb, var(--maple) 72%, var(--maple-deep) 28%) 100%
	);
	box-shadow:
		0 1px 2px rgba(141, 30, 30, .26),
		0 7px 16px -4px rgba(141, 30, 30, .34),
		inset 0 1px 0 rgba(255, 255, 255, .42),
		inset 0 -1px 0 rgba(0, 0, 0, .10);
	transition:
		transform .18s cubic-bezier(.22, .7, .3, 1),
		box-shadow .18s ease,
		filter .18s ease;
}
.season-facts .btn--primary:hover {
	border-color: rgba(255, 255, 255, .34);
	filter: saturate(107%) brightness(1.04);
	box-shadow:
		0 1px 2px rgba(141, 30, 30, .24),
		0 11px 24px -5px rgba(141, 30, 30, .40),
		inset 0 1px 0 rgba(255, 255, 255, .50),
		inset 0 -1px 0 rgba(0, 0, 0, .10);
}
/* Press reads on pointer-down, and as a squash into the surface rather than a
   nudge down a ledge. */
.season-facts .btn--primary:active {
	transform: scale(.975);
	box-shadow:
		0 1px 1px rgba(141, 30, 30, .22),
		0 3px 7px -2px rgba(141, 30, 30, .30),
		inset 0 1px 2px rgba(0, 0, 0, .16);
}

/* Translucency is a preference, not a requirement: go frosted-solid and drop
   the blur for anyone who has asked for less of it. */
@media (prefers-reduced-transparency: reduce) {
	.season-facts {
		background: var(--header-wash);
		backdrop-filter: none;
		-webkit-backdrop-filter: none;
	}
	.season-facts::before { display: none; }
}
/* Higher contrast wants a defined edge and a flat, opaque field. */
@media (prefers-contrast: more) {
	.season-facts {
		background: #fff;
		backdrop-filter: none;
		-webkit-backdrop-filter: none;
		border-color: var(--spruce);
		box-shadow: none;
	}
	.season-facts::before { display: none; }
	.season-facts dl > div { border-bottom-color: rgba(19, 38, 26, .3); }
}
@media (prefers-reduced-motion: reduce) {
	.season-facts .btn--primary { transition: box-shadow .18s ease, filter .18s ease; }
	.season-facts .btn--primary:active { transform: none; }
}

/* ==========================================================================
   The view — full-bleed panorama with the claim set beneath it
   ========================================================================== */

.view-figure { margin: 0; }
.view-figure img {
	width: 100%;
	height: clamp(340px, 58vh, 680px);
	object-fit: cover;
	object-position: center 58%;
	display: block;
}

.view-points {
	display: grid;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	gap: clamp(1.4rem, 3vw, 2.75rem);
	margin-top: clamp(2rem, 4vw, 3.25rem);
}
@media (max-width: 860px) { .view-points { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 460px) { .view-points { grid-template-columns: 1fr; } }

.view-point .mark {
	display: block;
	font-family: var(--display);
	font-style: italic;
	font-size: var(--fs-sm);
	color: var(--rust);
	margin-bottom: .35rem;
}
.view-point .value {
	display: block;
	font-family: var(--display);
	font-weight: 700;
	font-size: var(--fs-lg);
	color: var(--spruce);
	line-height: 1.05;
}
.view-point .note {
	display: block;
	margin-top: .45rem;
	font-size: var(--fs-sm);
	color: var(--ink-soft);
}

/* ==========================================================================
   Sites — deliberately uneven photo rhythm
   ========================================================================== */

.sites-mosaic {
	display: grid;
	grid-template-columns: repeat(12, 1fr);
	gap: clamp(.9rem, 2vw, 1.6rem);
	align-items: end;
}
.sites-mosaic .shot--a { grid-column: 1 / span 7; }
.sites-mosaic .shot--b { grid-column: 8 / span 5; }
.sites-mosaic .shot--c { grid-column: 1 / span 4; }
.sites-mosaic .shot--d { grid-column: 5 / span 8; }
@media (max-width: 780px) {
	.sites-mosaic { grid-template-columns: 1fr 1fr; }
	.sites-mosaic .shot--a,
	.sites-mosaic .shot--b,
	.sites-mosaic .shot--c,
	.sites-mosaic .shot--d { grid-column: auto; }
}

/* ==========================================================================
   Site map hook — the interactive lot map lands here
   ========================================================================== */

.map-hook {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	gap: clamp(2rem, 5vw, 4rem);
	align-items: center;
}
@media (max-width: 900px) { .map-hook { grid-template-columns: 1fr; } }

.map-hook-media img {
	width: 100%;
	height: auto;
	display: block;
	mix-blend-mode: multiply;
}

.lot-strip {
	display: grid;
	grid-auto-flow: column;
	grid-auto-columns: minmax(clamp(130px, 22vw, 200px), 1fr);
	gap: clamp(.6rem, 1.5vw, 1rem);
	overflow-x: auto;
	padding-bottom: .75rem;
	scroll-snap-type: x mandatory;
	overscroll-behavior-x: contain;
}
.lot-strip figure { scroll-snap-align: start; }
.lot-strip img { aspect-ratio: 3 / 2; object-fit: cover; }
.lot-strip figcaption {
	margin-top: .45rem;
	font-family: var(--display);
	font-weight: 600;
	font-style: normal;
	font-size: var(--fs-sm);
	color: var(--spruce);
}

/* ==========================================================================
   Amenities
   ========================================================================== */

.amenity-list {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
	gap: clamp(.85rem, 1.7vw, 1.25rem);
}
/* Eight cards, and at full width auto-fit would take five across and leave a
   ragged three underneath. Pin it to four so it reads as two even rows. */
@media (min-width: 1060px) {
	.amenity-list { grid-template-columns: repeat(4, 1fr); }
}

/* Same glass as the Plan-your-stay card, pitched a step lighter. These are
   small surfaces sitting eight-up, so they take less blur and a shallower
   shadow — a big pane reads thick, a chip reads thin, and stacking eight
   heavy ones would bury the section. */
.amenity {
	position: relative;
	isolation: isolate;
	display: grid;
	grid-template-columns: auto 1fr;
	align-items: center;
	column-gap: .8rem;
	padding: clamp(1.15rem, 2.2vw, 1.5rem);
	border-radius: var(--glass-radius);
	/* Tuned for the white band: a white border and a white-topped gradient both
	   disappeared against it, taking the top edge of every card with them. The
	   card is now warm against the white and the hairline is ink, not light. */
	border: 1px solid rgba(19, 38, 26, .08);
	background:
		linear-gradient(
			180deg,
			rgba(255, 253, 248, .97) 0%,
			rgba(253, 246, 233, .94) 48%,
			rgba(240, 230, 211, .82) 100%
		);
	backdrop-filter: blur(14px) saturate(160%);
	-webkit-backdrop-filter: blur(14px) saturate(160%);
	box-shadow:
		0 1px 2px rgba(19, 38, 26, .06),
		0 6px 14px -6px rgba(19, 38, 26, .11),
		0 18px 34px -16px rgba(19, 38, 26, .14),
		inset 0 1px 0 rgba(255, 255, 255, .95);
}
.amenity::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	border-radius: inherit;
	pointer-events: none;
	background: linear-gradient(
		176deg,
		rgba(255, 255, 255, .55) 0%,
		rgba(255, 255, 255, .14) 28%,
		rgba(255, 255, 255, 0) 52%
	);
}

/* The icon sits on its own small tile, a touch brighter than the card, so it
   reads as an inset chip in the glass rather than a sticker on top. It shares a
   row with the title and the two centre against each other, so a title that
   runs to two lines stays balanced against its icon. */
.amenity-icon {
	grid-column: 1;
	grid-row: 1;
	display: grid;
	place-items: center;
	width: 46px;
	height: 46px;
	border-radius: 14px;
	color: var(--pine);
	border: 1px solid rgba(255, 255, 255, .8);
	background: rgba(255, 255, 255, .55);
	box-shadow:
		inset 0 1px 0 rgba(255, 255, 255, .95),
		0 1px 2px rgba(19, 38, 26, .06);
}
.amenity-icon svg { width: 29px; height: 29px; }

.amenity h3 {
	grid-column: 2;
	grid-row: 1;
	font-size: 1.35rem;
	font-weight: 700;
	margin: 0;
	text-wrap: balance;
}
/* The copy runs the full width of the card rather than indenting under the
   title — at four cards across there is not enough room to give away. */
.amenity p {
	grid-column: 1 / -1;
	grid-row: 2;
	margin: .7rem 0 0;
	font-size: var(--fs-sm);
	color: var(--ink-soft);
}

@media (prefers-reduced-transparency: reduce) {
	.amenity {
		background: var(--header-wash);
		backdrop-filter: none;
		-webkit-backdrop-filter: none;
	}
	.amenity::before { display: none; }
}
@media (prefers-contrast: more) {
	.amenity {
		background: #fff;
		backdrop-filter: none;
		-webkit-backdrop-filter: none;
		border-color: var(--spruce);
		box-shadow: none;
	}
	.amenity::before { display: none; }
}

/* ==========================================================================
   Split feature — photo one side, copy the other
   ========================================================================== */

.split {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	gap: clamp(2rem, 5vw, 4.5rem);
	align-items: center;
}
.split--flip .split-media { order: 2; }
@media (max-width: 880px) {
	.split { grid-template-columns: 1fr; }
	.split--flip .split-media { order: 0; }
}
.split-body h2 { font-size: var(--fs-xl); }
.split-body p { color: var(--ink-soft); max-width: 52ch; }

/* ==========================================================================
   Duo — two short features side by side

   The compact form of .split: photo over copy rather than beside it, so a
   pair of secondary features occupies one band instead of two stacked ones.
   ========================================================================== */

.duo {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	gap: clamp(1.8rem, 4vw, 3.4rem);
	align-items: start;
}
@media (max-width: 780px) {
	.duo { grid-template-columns: 1fr; }
}
.duo-body { margin-top: clamp(.9rem, 1.8vw, 1.3rem); }
.duo-body h2 {
	font-size: var(--fs-lg);
	margin: 0 0 .6rem;
}
.duo-body p {
	margin: 0;
	font-size: var(--fs-sm);
	color: var(--ink-soft);
	/* No measure cap here: the card is already the narrow column, so the copy
	   should use all of it rather than being held in short of the photo edge. */
}
.duo-body .arrow-link { margin-top: .9rem; }

.arrow-link {
	display: inline-flex;
	align-items: center;
	gap: .5rem;
	margin-top: 1.1rem;
	font-family: var(--display);
	font-weight: 600;
	color: var(--rust);
	text-decoration: none;
	border-bottom: 2px solid color-mix(in srgb, var(--rust) 35%, transparent);
	padding-bottom: 2px;
	transition: color .16s ease, border-color .16s ease, gap .16s ease;
}
.arrow-link svg { width: 16px; height: 16px; }
.arrow-link:hover {
	color: var(--maple);
	border-color: var(--maple);
	gap: .8rem;
}

/* A small plan of the grounds standing in for a text link: the map is the
   invitation, the line under it is the label. Both live in one anchor, so
   hovering either one moves the arrow. */
/* Block, not inline-block: an inline-block sits on the parent's baseline and
   carries descender space under it, which read as extra room below the label.
   The max-width belongs to the picture alone so the line beneath it can run
   the full column and stay on one line. */
.map-link {
	display: block;
	/* A shade more than the blank line the copy above it uses (.para-break), so
	   the map reads as a separate element rather than another paragraph. */
	margin-top: 1.90em;
	text-decoration: none;
}
.map-link picture {
	display: block;
	max-width: 340px;
	margin-bottom: .7rem;
}
.map-link img {
	display: block;
	width: 100%;
	height: auto;
	background: var(--cream-deep);
}

/* Inline keeps the rule tight under the text and lets the arrow trail the last
   word rather than being stranded at the right edge if the line ever wraps. */
.map-link .arrow-link {
	display: inline;
	margin-top: 0;
	line-height: 1.35;
}
.map-link .arrow-link svg {
	display: inline-block;
	vertical-align: -2px;
	margin-left: .4rem;
	transition: transform .16s ease;
}
.map-link:hover .arrow-link {
	color: var(--maple);
	border-color: var(--maple);
}
.map-link:hover .arrow-link svg { transform: translateX(3px); }
@media (max-width: 780px) {
	.map-link picture { max-width: 62vw; }
}

/* ==========================================================================
   Closing call to action

   Originally this laid the headline over the photograph behind a parchment
   wash. That was the only tinted image on the site, it turned a blue sky
   lavender, and it contradicted the rule the rest of the page follows. The
   photograph is now clean and the words sit on parchment beneath it.
   ========================================================================== */

.closing-media img {
	display: block;
	width: 100%;
	height: clamp(260px, 42vh, 520px);
	object-fit: cover;
	object-position: center 62%;
}

.closing-inner {
	background: var(--header-wash);
	text-align: center;
	padding: clamp(2.5rem, 6vw, 4.5rem) var(--gutter);
}
.closing-inner > * { margin-inline: auto; }
.closing h2 {
	font-size: var(--fs-2xl);
	max-width: 20ch;
	margin-top: .35rem;
}
.closing p {
	margin-top: 1.1rem;
	max-width: 48ch;
	color: var(--ink-soft);
	font-size: var(--fs-md);
}
.closing-actions {
	margin-top: 2rem;
	display: flex;
	flex-wrap: wrap;
	gap: .9rem;
	justify-content: center;
}

/* ==========================================================================
   Footer

   Continues the closing parchment rather than dropping into a leftover
   dark directory. No sitemap column — the header already carries nav.
   ========================================================================== */

.site-footer {
	background: var(--header-gradient);
	color: var(--ink);
	padding-block: clamp(2.5rem, 5.5vw, 4.25rem) 0;
	font-size: var(--fs-sm);
	box-shadow: 0 0 2px var(--pine), var(--shadow-sm);
}
.footer-grid {
	display: grid;
	grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr) minmax(0, 1fr);
	gap: clamp(1.75rem, 4.5vw, 3.5rem);
	align-items: start;
	justify-items: center;
	text-align: center;
	padding-bottom: clamp(2rem, 4.5vw, 3.25rem);
}
/* Three across holds only while each column has real room. Below 1200px the
   brand, address and season blocks start wrapping into each other, so they
   stack for the whole of that range rather than being squeezed. */
@media (max-width: 1199px) {
	.footer-grid { grid-template-columns: 1fr; }
}

.footer-brand,
.footer-col {
	display: flex;
	flex-direction: column;
	align-items: center;
	width: 100%;
}

.footer-logo-link {
	display: inline-block;
	line-height: 0;
	color: inherit;
	text-decoration: none;
	transition: transform .16s ease, opacity .16s ease;
}
.footer-logo-link:active { transform: scale(0.97); }
@media (hover: hover) and (pointer: fine) {
	.footer-logo-link:hover { opacity: .88; }
}
.footer-logo {
	display: block;
	width: clamp(140px, 16vw, 188px);
	height: auto;
	margin-inline: auto;
}

.footer-note {
	margin: .85rem auto 0;
	max-width: 32ch;
	color: var(--ink-soft);
	text-wrap: pretty;
}

.footer-find-row {
	display: grid;
	grid-template-columns: auto auto;
	grid-template-rows: auto auto;
	align-items: start;
	justify-content: center;
	column-gap: 1.15rem;
	row-gap: .85rem;
}
.footer-vt {
	grid-column: 1;
	grid-row: 1;
	height: clamp(154px, 21vw, 204px);
	width: auto;
	aspect-ratio: 112 / 180;
	pointer-events: none;
	align-self: start;
	transform: translateY(-20px);
}
.footer-vt svg {
	display: block;
	height: 100%;
	width: auto;
	overflow: visible;
	filter: drop-shadow(0 1px 1px rgba(19, 38, 26, .2));
}
.footer-vt .vt-rest { fill: url(#footer-vt-gloss); }
.footer-find address {
	grid-column: 2;
	grid-row: 1;
	margin: 0;
	text-align: left;
}
.footer-find .footer-flags {
	grid-column: 1 / -1;
	grid-row: 2;
	justify-self: center;
	width: auto;
	margin-top: 0;
}
.site-footer .footer-nca-link:hover {
	text-decoration: none;
	opacity: .88;
}
.footer-nca-link:active { transform: scale(0.97); }

.footer-nca-link {
	line-height: 0;
	color: inherit;
}
.footer-hours-col {
	width: 100%;
}
.footer-hours-col .footer-nca-link {
	margin-top: 1.25rem;
}
.footer-hours {
	list-style: none;
	margin: 0;
	padding: 0;
	width: 100%;
	max-width: 28ch;
	overflow: hidden;
	border-radius: var(--bevel-surface-radius);
}
.footer-hours li {
	padding: .52rem .9rem;
	line-height: 1.35;
	color: var(--ink-soft);
	text-wrap: pretty;
}
.footer-hours li:nth-child(odd) {
	background: rgba(255, 255, 255, .72);
}
.footer-hours li:nth-child(even) {
	background: rgba(70, 76, 72, .08);
}
/* A grid rather than a flex row so the photo credit can sit under the two
   flags at exactly their combined width: the flags size the columns, and the
   credit spans both without contributing a width of its own. */
.footer-flags {
	display: grid;
	grid-template-columns: auto auto;
	justify-content: center;
	align-items: center;
	column-gap: .55rem;
	row-gap: .7rem;
	width: 100%;
	margin-top: .85rem;
	line-height: 0;
}
.footer-flags > img {
	display: block;
	height: 36px;
	width: auto;
	border-radius: 1px;
	box-shadow: 0 1px 2px rgba(19, 38, 26, .18);
}
.footer-photo-credit {
	grid-column: 1 / -1;
	margin-top: .75rem; /* on top of the row gap: about 23px under the flags */
	width: 0;
	min-width: 100%;
	transition: opacity .16s ease;
}
.footer-photo-credit img {
	display: block;
	width: 100%;
	height: auto;
}
.site-footer .footer-photo-credit:hover { opacity: .75; }
.site-footer a {
	color: var(--spruce);
	text-decoration: none;
	text-underline-offset: 3px;
	transition: color .16s ease;
}
.site-footer a:hover { color: var(--maple); text-decoration: underline; }
.site-footer address {
	font-style: normal;
	line-height: 1.7;
	color: var(--ink-soft);
}

.footer-base {
	background: var(--pine);
	color: #fff;
	padding: .55rem 0;
	font-size: var(--fs-xs);
}
.footer-base-inner {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 1rem 1.75rem;
}
.footer-base p { margin: 0; max-width: 48ch; color: #fff; }
@media (max-width: 820px) {
	.footer-base-inner {
		flex-direction: column;
		justify-content: center;
		align-items: center;
		text-align: center;
	}
	.footer-base p { max-width: none; }
}
.footer-nca {
	height: 72px;
	width: auto;
}
.footer-credit {
	display: inline-block;
	line-height: 0;
	transition: opacity .16s ease, transform .16s ease;
}
.site-footer .footer-credit:hover {
	text-decoration: none;
	opacity: .88;
}
.footer-credit:active { transform: scale(0.97); }
.footer-credit img {
	width: 250px;
	max-width: min(250px, 100%);
	height: auto;
	display: block;
}

/* ==========================================================================
   Scroll reveal
   ========================================================================== */

/* Hiding is gated on .reveal-on, which the script adds only once it has an
   IntersectionObserver in hand and is about to start observing. Keying this
   off the plain .js class meant any later error left the whole page blank,
   because everything below the hero was already at opacity 0 with nothing
   left running to bring it back. */
@media (prefers-reduced-motion: no-preference) {
	.reveal-on .reveal {
		opacity: 0;
		transform: translateY(18px);
		transition: opacity .7s ease, transform .7s cubic-bezier(.2, .6, .2, 1);
	}
	.reveal-on .reveal.is-in {
		opacity: 1;
		transform: none;
	}
}

/* ==========================================================================
   Utilities
   ========================================================================== */

.mt-0 { margin-top: 0; }
.mt-1 { margin-top: .75rem; }
.mt-2 { margin-top: 1.5rem; }
.mt-3 { margin-top: 2.25rem; }
.text-center { text-align: center; }
.mx-auto { margin-inline: auto; }

/* ==========================================================================
   Photo gallery — a scrollable band of photographs

   The track runs past the text column to the viewport edge on the right, so it
   reads as a strip that continues rather than a row that happens to end. Cards
   are a fixed height and scroll-snap; the whole thing is draggable, keyboard
   reachable, and each card opens a full-size viewer.
   ========================================================================== */

.gallery-stage {
	position: relative;
	margin-top: clamp(1.8rem, 3.5vw, 2.8rem);
	/* The track's own padding, declared here so the arrows can centre on the
	   photographs rather than on the padded box around them. */
	--track-pad-top: .35rem;
	--track-pad-bottom: 1.1rem;
}

.gallery-track {
	display: flex;
	gap: clamp(.7rem, 1.4vw, 1.1rem);
	overflow-x: auto;
	scroll-snap-type: x proximity;
	overscroll-behavior-x: contain;
	/* Start at the text column, run out to the viewport edge. */
	padding-inline: max(var(--gutter), calc(50vw - var(--container) / 2 + var(--gutter)));
	/* Snap positions have to account for that padding. Without this the first
	   card snaps its own edge to the scrollport edge, so the strip rests already
	   scrolled by the width of the padding and the left arrow is live before
	   anything has been moved. */
	scroll-padding-inline: max(var(--gutter), calc(50vw - var(--container) / 2 + var(--gutter)));
	padding-block: var(--track-pad-top) var(--track-pad-bottom);
	scrollbar-width: none;
	cursor: grab;
	/* Dragging the strip must not start a text selection across the cards. */
	user-select: none;
	-webkit-user-select: none;
}
.gallery-track::-webkit-scrollbar { display: none; }
.gallery-track.is-dragging {
	cursor: grabbing;
	scroll-snap-type: none;
	scroll-behavior: auto;
}
/* Snapping has to be off while the strip drifts: it would fight every
   one-pixel step, and the correction it applies would read as a person
   grabbing the strip and stop the drift dead. */
.gallery-track.is-drifting {
	scroll-snap-type: none;
	scroll-behavior: auto;
}
.gallery-track:focus-visible {
	outline: 3px solid var(--maple);
	outline-offset: 3px;
	border-radius: 4px;
}

.gallery-card,
.duo-shot {
	margin: 0;
	padding: 0;
	border: 0;
	background: none;
	cursor: pointer;
	border-radius: var(--glass-radius);
	overflow: hidden;
	/* The photograph is the whole card, so the lift on hover is the only chrome
	   it needs. Kept shallow on purpose: the track is a scroll container, so it
	   clips vertically, and a shadow reaching past the padding gets cut off
	   square along the bottom of the strip. */
	box-shadow:
		0 1px 2px rgba(19, 38, 26, .10),
		0 6px 14px -6px rgba(19, 38, 26, .18);
	transition: transform .22s cubic-bezier(.22, .7, .3, 1), box-shadow .22s ease;
}
/* Only the strip's cards are flex items that snap. */
.gallery-card { flex: 0 0 auto; scroll-snap-align: start; }
/* The duo photographs keep their own 16:9 box and fill the column. */
.duo-shot { display: block; width: 100%; }
.gallery-card img {
	display: block;
	width: clamp(240px, 34vw, 420px);
	height: clamp(180px, 23vw, 280px);
	object-fit: cover;
	background: var(--cream-deep);
	/* Without this the browser's own image drag starts the moment the pointer
	   moves, which cancels the pointer stream and kills grab-to-scroll. */
	-webkit-user-drag: none;
	user-select: none;
	-webkit-user-select: none;
}
.gallery-card:hover,
.gallery-card:focus-visible,
.duo-shot:hover,
.duo-shot:focus-visible {
	transform: translateY(-3px);
	box-shadow:
		0 2px 4px rgba(19, 38, 26, .12),
		0 10px 20px -8px rgba(19, 38, 26, .24);
}
.gallery-card:focus-visible,
.duo-shot:focus-visible { outline: 3px solid var(--maple); outline-offset: 3px; }
.gallery-card:active,
.duo-shot:active { transform: translateY(-1px) scale(.992); }
.is-dragging .gallery-card { transform: none; }

/* Arrows sit over the ends of the strip. Pointer-only: touch users drag, and a
   keyboard user has the track itself. Same button as the hero slider's — one
   control style for "step through photographs" across the page. */
.gallery-nav {
	position: absolute;
	/* Centre on the photographs, not the stage: the track is padded unevenly
	   (a hair above, room for the scroll shadow below), so a plain 50% sits low
	   by half the difference. */
	top: calc(50% - (var(--track-pad-bottom) - var(--track-pad-top)) / 2);
	transform: translateY(-50%);
	z-index: 2;
	display: grid;
	place-items: center;
	width: 42px;
	height: 42px;
	padding: 0;
	border: 0;
	border-radius: 50%;
	color: var(--cream);
	background: var(--spruce);
	box-shadow: 0 1px 3px rgba(19, 38, 26, .28);
	cursor: pointer;
	transition: background .16s ease, transform .16s ease, color .16s ease, opacity .18s ease;
}
.gallery-nav svg { width: 19px; height: 19px; }
.gallery-nav--prev { left: clamp(.5rem, 2vw, 1.4rem); }
.gallery-nav--next { right: clamp(.5rem, 2vw, 1.4rem); }
.gallery-nav:hover { background: var(--rust); color: var(--cream); }
.gallery-nav:active { transform: translateY(calc(-50% + 1px)); }
.gallery-nav[disabled] { opacity: 0; pointer-events: none; }
@media (hover: none) {
	.gallery-nav { display: none; }
}

/* --- viewer ------------------------------------------------------------- */

.gallery-viewer {
	position: fixed;
	inset: 0;
	z-index: 200;
	display: grid;
	place-items: center;
	padding: clamp(1rem, 4vw, 3rem);
	background: rgba(12, 22, 15, .82);
	backdrop-filter: blur(18px) saturate(130%);
	-webkit-backdrop-filter: blur(18px) saturate(130%);
	animation: gallery-viewer-in .22s ease both;
}
.gallery-viewer[hidden] { display: none; }
@keyframes gallery-viewer-in {
	from { opacity: 0; }
	to   { opacity: 1; }
}
.gallery-viewer figure {
	margin: 0;
	max-width: min(1400px, 100%);
	max-height: 100%;
	animation: gallery-figure-in .28s cubic-bezier(.22,.7,.3,1) both;
}
@keyframes gallery-figure-in {
	from { opacity: 0; transform: scale(.97); }
	to   { opacity: 1; transform: none; }
}
.gallery-viewer img {
	display: block;
	max-width: 100%;
	max-height: calc(100vh - 2 * clamp(1rem, 4vw, 3rem));
	width: auto;
	height: auto;
	border-radius: clamp(6px, 1vw, 12px);
	box-shadow: 0 30px 70px -20px rgba(0, 0, 0, .7);
}
.gallery-viewer-close,
.gallery-viewer-shift {
	position: absolute;
	z-index: 2;
	display: grid;
	place-items: center;
	width: 46px;
	height: 46px;
	padding: 0;
	border: 1px solid rgba(255, 255, 255, .22);
	border-radius: 999px;
	color: #fff;
	background: rgba(255, 255, 255, .13);
	backdrop-filter: blur(14px);
	-webkit-backdrop-filter: blur(14px);
	cursor: pointer;
	transition: background-color .18s ease, transform .18s cubic-bezier(.22,.7,.3,1);
}
.gallery-viewer-close svg,
.gallery-viewer-shift svg { width: 22px; height: 22px; }
.gallery-viewer-close { top: clamp(.8rem, 2.5vw, 1.6rem); right: clamp(.8rem, 2.5vw, 1.6rem); }
.gallery-viewer-shift--prev { left: clamp(.5rem, 2vw, 1.6rem); }
.gallery-viewer-shift--next { right: clamp(.5rem, 2vw, 1.6rem); }
.gallery-viewer-close:hover,
.gallery-viewer-shift:hover { background: rgba(255, 255, 255, .24); transform: scale(1.06); }
.gallery-viewer-close:active,
.gallery-viewer-shift:active { transform: scale(.95); }

@media (prefers-reduced-transparency: reduce) {
	/* .gallery-nav is solid already — nothing to flatten. */
	.gallery-viewer { background: rgba(12, 22, 15, .96); backdrop-filter: none; -webkit-backdrop-filter: none; }
}
@media (prefers-reduced-motion: reduce) {
	.gallery-card,
	.duo-shot,
	.gallery-nav,
	.gallery-viewer-close,
	.gallery-viewer-shift { transition: none; }
	.gallery-card:hover, .gallery-card:focus-visible,
	.duo-shot:hover, .duo-shot:focus-visible { transform: none; }
	.gallery-viewer, .gallery-viewer figure { animation: none; }
	/* The card still swaps to the white glass on hover, it just arrives
	   without the cross-fade. */
	.rate-card { transition: none; }
}

/* ===========================================================================
   Rates & reservations — an extension of the home-page season card
   ======================================================================== */

.rates-photo-ribbon {
	padding-block: clamp(1.25rem, 3vw, 2.3rem) clamp(.2rem, 1.2vw, .8rem);
	background: linear-gradient(180deg, var(--cream) 0%, color-mix(in srgb, var(--cream) 76%, var(--paper)) 100%);
}
.site-ribbon {
	display: grid;
	grid-template-columns: minmax(0, 1.58fr) minmax(13rem, .82fr);
	grid-template-rows: repeat(2, minmax(0, 1fr));
	gap: clamp(.65rem, 1.4vw, 1.15rem);
	height: clamp(22rem, 33vw, 31rem);
}
/* This photo grid shares its name with the small legacy announcement strip.
   Reset that strip's colored panel and inset so the photographs use the full
   content width, with whitespace—not a field of color—around the mosaic. */
.rates-photo-ribbon .site-ribbon {
	background: transparent;
	color: inherit;
	font: inherit;
	letter-spacing: normal;
	margin: 0;
	padding: 0;
	text-align: inherit;
}
.site-ribbon__frame,
.reservation-site-pair figure {
	position: relative;
	margin: 0;
	border-radius: var(--glass-radius);
	background: var(--cream-deep);
	overflow: hidden;
	box-shadow: var(--shadow-sm);
}
.site-ribbon__frame--wide { grid-row: span 2; }
.rates-photo-trigger {
	display: block;
	width: 100%;
	height: 100%;
	margin: 0;
	padding: 0;
	border: 0;
	border-radius: inherit;
	background: none;
	cursor: pointer;
}
/* The frame clips its contents for the photo treatment, so keep the keyboard
   ring just inside it rather than letting it be cut away outside the edge. */
.rates-photo-trigger:focus-visible { outline: 3px solid var(--maple); outline-offset: -3px; }
.site-ribbon picture,
.site-ribbon img,
.reservation-site-pair picture,
.reservation-site-pair img { display: block; width: 100%; height: 100%; }
.site-ribbon img,
.reservation-site-pair img {
	object-fit: cover;
	transition: transform .55s cubic-bezier(.22, .61, .36, 1);
}
@media (hover: hover) {
	.site-ribbon__frame:hover img,
	.reservation-site-pair figure:hover img { transform: scale(1.025); }
}

.rates-overview { overflow: hidden; }
/* Heading, then its copy directly beneath at the full width of the container.
   This was a two-column grid with the copy set beside the heading; the
   stacked form reads in one pass and gives the sentence the whole measure. */
.section-intro { margin-bottom: clamp(1.8rem, 4vw, 3.1rem); }
.section-intro h2 { margin-top: 0; font-size: var(--fs-xl); }
.section-intro > p {
	max-width: none;
	margin: .85rem 0 0;
	color: var(--ink-soft);
	font-size: var(--fs-md);
	line-height: 1.55;
}

.rate-grid {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: clamp(1rem, 2.5vw, 1.55rem);
}
/* The cards rest in the gold treatment and go to the white glass on hover —
   the reverse of the usual "one card is highlighted" arrangement. Pointing at
   a card is what lifts it out of the row, so the highlight follows the cursor
   instead of being spent on a card chosen in advance. */
.rate-card {
	position: relative;
	display: flex;
	flex-direction: column;
	min-height: 100%;
	padding: clamp(1.35rem, 2.7vw, 2rem);
	border: 1px solid rgba(193, 158, 76, .48);
	border-radius: var(--glass-radius);
	background: linear-gradient(155deg, rgba(255, 253, 246, .97), rgba(240, 234, 213, .89));
	box-shadow: var(--shadow-sm), inset 0 1px 0 rgba(255, 255, 255, .96);
	overflow: hidden;
	transition: background .3s ease, border-color .3s ease, box-shadow .3s ease;
}
.rate-card::before {
	content: "";
	position: absolute;
	inset: 0;
	pointer-events: none;
	background: linear-gradient(126deg, rgba(255, 255, 255, .46), transparent 34%);
}
/* Every card now carries the gold, so the middle one is marked by depth
   alone rather than by a colour the others no longer have. */
.rate-card--featured {
	border-color: rgba(193, 158, 76, .7);
	box-shadow: var(--shadow-md), inset 0 1px 0 rgba(255, 255, 255, .96);
}
/* :not(.rental-card) — the rental card is not one of a row being chosen
   between, and its photographs are buttons, so focus-within fired on every
   thumbnail a keyboard reached. It keeps the resting gold at all times. */
.rate-card:hover:not(.rental-card),
.rate-card:focus-within:not(.rental-card),
.rate-card.is-selected {
	border-color: rgba(255, 255, 255, .84);
	background: linear-gradient(155deg, rgba(255, 255, 255, .96), rgba(247, 248, 242, .86));
	box-shadow: var(--shadow-md), inset 0 1px 0 rgba(255, 255, 255, .93);
}
/* Hover and selection share the white, so the ring is what separates the card
   somebody has picked from the one their cursor happens to be crossing. */
.rate-card.is-selected {
	border-color: var(--maple);
	box-shadow: var(--shadow-md), inset 0 0 0 1px var(--maple), inset 0 1px 0 rgba(255, 255, 255, .93);
}
/* Only once the script is there to answer the click. */
.rate-grid.is-selectable .rate-card { cursor: pointer; }
.rate-card > * { position: relative; }
.rate-card__kicker {
	margin: 0 0 .65rem;
	font-family: var(--display);
	font-size: var(--fs-xs);
	font-weight: 700;
	letter-spacing: .1em;
	line-height: 1.2;
	text-transform: uppercase;
	color: var(--maple-deep);
}
.rate-card h3 { font-size: var(--fs-lg); color: var(--spruce); }
.rate-card__price {
	display: flex;
	align-items: baseline;
	gap: .45rem;
	margin: 1.25rem 0 .8rem;
	color: var(--maple-deep);
}
/* Nunito's dollar sign is an S with two small stubs at top and bottom — at
   this size it just reads as an S. Archivo Black strikes it with a full
   vertical stroke straight through, and it is already on the page: the hero
   legend uses it, so this costs no extra request. Its fallbacks are grotesques
   whose dollar is struck the same way. */
.rate-card__price span {
	font-family: "Archivo Black", "Helvetica Neue", Helvetica, Arial, sans-serif;
	font-size: clamp(2.75rem, 5vw, 4.25rem);
	font-weight: 400;      /* Archivo Black is black at 400 — never synthesise */
	letter-spacing: -.02em;
	line-height: .9;
}
.rate-card__price small {
	font-size: var(--fs-sm);
	font-weight: 700;
	color: var(--ink-soft);
}
/* Copy plus any note under it, reserved as one block so the rule above the
   rates starts at the same height in all three cards. The tallest is the
   middle one — three lines and a two-line note — and holding that in the other
   two only moves whitespace they already had: the grid stretches every card to
   the tallest anyway, so nothing here makes the row taller.

   The font size is restated so `em` resolves against the copy's size rather
   than the card's. Dropped to 0 on one column, where nothing lines up. */
.rate-card__body {
	font-size: var(--fs-sm);
	min-height: 7.75em;
}
.rate-card__copy {
	margin: 0;
	color: var(--ink-soft);
	font-size: var(--fs-sm);
	line-height: 1.45;
}
.rate-card__facts {
	margin: 1.35rem 0 0;
	border-top: 1px solid rgba(19, 38, 26, .1);
}
.rate-card__facts > div {
	display: flex;
	justify-content: space-between;
	gap: .8rem;
	padding: .55rem 0;
	border-bottom: 1px solid rgba(19, 38, 26, .08);
}
.rate-card__facts dt { color: var(--ink-soft); font-size: var(--fs-sm); }
.rate-card__facts dd {
	margin: 0;
	font-family: var(--display);
	font-size: var(--fs-md);
	font-weight: 700;
	color: var(--spruce);
	text-align: right;
}
/* The note sits directly under the card's copy and reads as a second sentence
   of it, so it takes the same size, colour and upright face rather than the
   small italic aside it was when it hung below the rates. */
.rate-card__note {
	margin: .55rem 0 0;
	font-size: var(--fs-sm);
	line-height: 1.45;
	color: var(--ink-soft);
}

/* ---- the rental card ----------------------------------------------------
   A .rate-card at the full width of the column: the gold glass, the price and
   the facts list all come from there, and everything here is about the second
   column. The copy keeps a readable measure on the left and the photographs
   fill the right, which is the only arrangement that does not leave a single
   card looking like a row that lost two of its three.

   .rate-card__body is deliberately not used — its min-height exists to line
   three cards up against each other, and there is nothing here to line up. */
.rental-card {
	display: grid;
	grid-template-columns: minmax(0, .92fr) minmax(0, 1.08fr);
	gap: clamp(1.4rem, 3.5vw, 3rem);
	align-items: start;
}
.rental-card h3 { margin-top: 0; }
.rental-card .rate-card__price { margin-top: .9rem; }
.rental-card .rate-card__copy { max-width: 46ch; }

.rental-specs {
	margin: 1.1rem 0 0;
	padding: 0;
	list-style: none;
	display: flex;
	flex-direction: column;
	gap: .42rem;
}
.rental-specs li {
	position: relative;
	padding-left: 1.4rem;
	font-size: var(--fs-sm);
	line-height: 1.45;
	color: var(--ink-soft);
}
/* A maple tick rather than a bullet: the list is what the cabin has in it. */
.rental-specs li::before {
	content: "";
	position: absolute;
	left: .15rem;
	top: .42em;
	width: .5rem;
	height: .28rem;
	border-left: 2px solid var(--maple);
	border-bottom: 2px solid var(--maple);
	transform: rotate(-45deg);
}

/* Seven photographs of one small building: portrait and landscape both, so
   every thumbnail is held to the same 4:3 window and the frame decides what
   is in it. The full-size photograph in the lightbox is uncropped.

   The first one leads, across the full width and wider in the frame. Two
   reasons: seven tiles divide badly into any row that is not one, and a grid
   of small squares alone gives no sense of the building they are all inside.
   Lead plus two rows of three also brings the column close to the height of
   the copy beside it, which four-across left a long way short. */
.rental-shots {
	margin: 0;
	padding: 0;
	list-style: none;
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: clamp(.45rem, 1.1vw, .7rem);
}
.rental-shots li { margin: 0; }
.rental-shots li.is-lead { grid-column: 1 / -1; }
.rental-shots li.is-lead .rental-shot img { aspect-ratio: 16 / 9; }
/* The same frame the reservation photographs above use: the glass radius, the
   cream behind it, one soft shadow and no border, with the photograph itself
   easing up a little under the cursor rather than the frame moving. */
.rental-shot {
	display: block;
	width: 100%;
	padding: 0;
	border: 0;
	border-radius: var(--glass-radius);
	background: var(--cream-deep);
	overflow: hidden;
	box-shadow: var(--shadow-sm);
	cursor: pointer;
}
.rental-shot img {
	display: block;
	width: 100%;
	aspect-ratio: 4 / 3;
	object-fit: cover;
	transition: transform .55s cubic-bezier(.22, .61, .36, 1);
}
@media (hover: hover) {
	.rental-shot:hover img { transform: scale(1.025); }
}
/* The frame clips its contents, so the keyboard ring goes just inside it. */
.rental-shot:focus-visible { outline: 3px solid var(--maple); outline-offset: -3px; }
@media (max-width: 860px) {
	/* One column, and the photographs go under the copy. Three across keeps
	   them big enough to tell a kitchen from a bathroom at a glance. */
	.rental-card { grid-template-columns: minmax(0, 1fr); }
	.rental-shots { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 420px) {
	.rental-shots { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.rates-details__grid {
	display: grid;
	grid-template-columns: minmax(0, .92fr) minmax(0, 1.08fr);
	gap: clamp(1.25rem, 4vw, 4rem);
	align-items: start;
}
.fee-card { position: static; }
/* The .6rem here cleared the eyebrow that used to sit above each heading.
   With the eyebrows gone the heading is the first thing in the card. */
.fee-card h2,
.deposit-card h2 { margin-top: 0; font-size: var(--fs-lg); }
/* The deposit card takes this gap from .deposit-list's own top margin; the
   fee list sits flush against its heading, so the space goes here instead. */
.fee-card h2 { margin-bottom: 1.6rem; }
.fee-card dd { font-size: var(--fs-sm); line-height: 1.35; }
.deposit-card { padding: clamp(.35rem, 1vw, .7rem) 0; }
.deposit-list { margin: 1.4rem 0 0; }
.deposit-list > div {
	display: grid;
	grid-template-columns: minmax(9rem, .8fr) minmax(0, 1.2fr);
	gap: 1rem;
	padding: .85rem 0;
	border-bottom: 1px solid var(--rule);
}
.deposit-list dt { font-family: var(--display); font-weight: 700; color: var(--spruce); }
.deposit-list dd { margin: 0; color: var(--ink-soft); }
.deposit-card__policy {
	margin: 1.4rem 0 0;
	padding: 1rem 1.15rem;
	border-radius: 0 var(--glass-radius) var(--glass-radius) 0;
	border-left: 3px solid var(--maple);
	background: var(--maple-soft);
	color: #56221d;
	font-family: var(--display);
	font-weight: 600;
	line-height: 1.45;
}
.deposit-card__fine { margin: 1rem 0 0; font-size: var(--fs-sm); color: var(--ink-faint); }

/* This band follows .band--paper, and .band + .band drops the top padding
   wherever two bands meet. That is right where one colour runs into the next,
   but here the photographs would start hard against the paper edge. */
.band.reservation-section { padding-top: var(--band-y); }
.reservation-section { scroll-margin-top: calc(var(--header-h-stuck) + 1rem); }
.reservation-site-pair {
	display: grid;
	grid-template-columns: minmax(0, 1.2fr) minmax(0, .8fr);
	gap: clamp(.75rem, 1.8vw, 1.25rem);
	height: clamp(15rem, 26vw, 22rem);
	margin-bottom: clamp(2rem, 4vw, 3.35rem);
}
/* The reservation anchor points here rather than at the section, whose first
   child is a row of photographs — "take me to the form" should land on the
   heading that introduces it, not a picture above it. */
.section-intro--reservation {
	margin-bottom: clamp(1.6rem, 3vw, 2.4rem);
	scroll-margin-top: calc(var(--header-h-stuck) + 1.4rem);
}
.reservation-form-shell {
	padding: clamp(1rem, 3.5vw, 2.6rem);
	border: 1px solid rgba(255, 255, 255, .78);
	border-radius: var(--glass-radius);
	background: linear-gradient(160deg, rgba(255, 255, 255, .91), rgba(247, 248, 242, .79));
	box-shadow: var(--shadow-md), inset 0 1px 0 rgba(255, 255, 255, .94);
}
/* EasyWeb's server-generated table remains the form contract. These rules
   replace its legacy table presentation with the page's same labelled-fact
   rhythm without changing EasyWeb's inputs, validation or dynamic fields. */
.reservation-form-shell #theForm { margin: 0 !important; }
.reservation-form-shell #theTable {
	width: 100% !important;
	border: 0 !important;
	border-collapse: collapse !important;
	background: transparent !important;
	color: var(--ink) !important;
}
.reservation-form-shell #theTable td,
.reservation-form-shell #theTable th {
	padding: .85rem 0 !important;
	border: 0 !important;
	border-bottom: 1px solid rgba(19, 38, 26, .1) !important;
	font-family: var(--body) !important;
	font-size: var(--fs-sm) !important;
	vertical-align: middle !important;
}
.reservation-form-shell #theTable tr > th:first-child,
.reservation-form-shell #theTable tr > td:first-child:not([colspan]) {
	width: 36%;
	padding-right: 1.5rem !important;
	font-family: var(--display) !important;
	font-weight: 700;
	color: var(--spruce);
}
/* A spacer row is a block of colour, not a labelled field: the field row's
   padding and bottom rule turned each one into a ~30px slab. The inline
   height/line-height EasyWeb writes on the cell is then what it stands at. */
.reservation-form-shell #theTable td[style*="#DCE4D4"] {
	padding: 0 !important;
	border-bottom: 0 !important;
	font-size: 0 !important;
}
.reservation-form-shell #theTable input:not([type="checkbox"]):not([type="radio"]),
.reservation-form-shell #theTable select,
.reservation-form-shell #theTable textarea {
	width: 100%;
	min-height: 2.7rem;
	padding: .55rem .7rem;
	border: 1px solid var(--rule) !important;
	border-radius: 8px;
	background: rgba(255, 255, 255, .92);
	color: var(--ink);
	font: inherit;
	box-shadow: inset 0 1px 2px rgba(19, 38, 26, .05);
}
.reservation-form-shell #theTable textarea { min-height: 7rem; resize: vertical; }
/* EasyWeb wraps a date's three selects in `.mailer_dateTime`. The standard
   full-width field rule is right for ordinary controls, but would make the
   three selects overflow when combined. Keep the generated controls intact
   and give their wrapper a compact, responsive grid. */
.reservation-form-shell #theTable .mailer_dateTime {
	display: grid !important;
	grid-template-columns: minmax(0, 1.35fr) minmax(3.5rem, .56fr) minmax(4.3rem, .69fr);
	align-items: center;
	gap: .5rem;
	width: 100%;
	white-space: normal !important;
}
.reservation-form-shell #theTable .mailer_dateTime select {
	width: 100% !important;
	min-width: 0;
}
.reservation-form-shell #theTable input:focus,
.reservation-form-shell #theTable select:focus,
.reservation-form-shell #theTable textarea:focus {
	border-color: var(--pine) !important;
	outline: 3px solid color-mix(in srgb, var(--gold-bright) 55%, transparent) !important;
	outline-offset: 1px;
}
.reservation-form-shell #theTable .radioTable {
	margin: 0;
	border-collapse: collapse !important;
	display: block !important;
}
.reservation-form-shell #theTable .radioTable tbody { display: block !important; }
.reservation-form-shell #theTable .radioTable tr {
	display: flex !important;
	align-items: center;
}
.reservation-form-shell #theTable .radioTable td {
	display: flex;
	align-items: center;
	padding: .3rem .7rem .3rem 0 !important;
	border: 0 !important;
	vertical-align: middle !important;
	line-height: 1.3;
}
/* The main table's 36% label-column rule must not apply inside EasyWeb's
   radio option tables. A fixed radio cell makes each option's text begin on
   the same vertical line. */
.reservation-form-shell #theTable .radioTable tr > td:first-child:not([colspan]) {
	width: 1rem;
	min-width: 1rem;
	padding-right: .6rem !important;
	font-family: var(--body) !important;
	font-weight: inherit;
	color: inherit;
}
.reservation-form-shell #theTable .radioTable input[type="radio"] {
	display: block;
	inline-size: 1rem;
	block-size: 1rem;
	margin: 0;
}
.reservation-form-shell #theTable .radioTable label {
	display: block;
	line-height: 1.3;
}
.reservation-form-shell #theTable input[type="radio"],
.reservation-form-shell #theTable input[type="checkbox"] { accent-color: var(--maple); }
.reservation-form-shell #theTable input[type="checkbox"] {
	display: block;
	inline-size: 1rem;
	block-size: 1rem;
	margin: 0;
}
/* Keep the multi-line request label and its textarea anchored to the same
   visual center, even if EasyWeb supplies a competing legacy valign value. */
.reservation-form-shell #theTable tr:has(textarea) > td { vertical-align: middle !important; }
.reservation-form-shell #theTable tr#submit td { padding-top: 1.45rem !important; border-bottom: 0 !important; }
.reservation-form-shell #mailer_submit {
	width: auto !important;
	min-height: 0 !important;
	padding: .78rem 1.35rem !important;
	border: 1px solid rgba(255, 255, 255, .25) !important;
	border-radius: 999px !important;
	background: linear-gradient(180deg, var(--maple-light), var(--maple), var(--maple-deep)) !important;
	color: #fff !important;
	font-family: var(--display) !important;
	font-size: 1rem !important;
	font-weight: 700 !important;
	box-shadow: 0 7px 16px -4px rgba(141, 30, 30, .34), inset 0 1px 0 rgba(255, 255, 255, .42) !important;
	cursor: pointer;
}
.reservation-form-shell #mailer_submit:hover { filter: saturate(108%) brightness(1.04); }
.reservation-form-shell #mailer_submit:disabled { cursor: wait; opacity: .72; }
.reservation-form-shell #theTable tr:has(.mailerNote) td { color: var(--ink-soft); line-height: 1.5; }
.reservation-form-shell #theTable tr:has(.mailerNote) strong { color: var(--spruce); }
.reservation-form-shell #theTable tr#formPrivacyTr { display: none; }

.reservation-thanks { min-height: min(62vh, 44rem); display: grid; align-content: center; }
.reservation-thanks__actions { display: flex; flex-wrap: wrap; align-items: center; gap: 1.2rem; margin: 1.8rem 0 0; }
.reservation-thanks .arrow-link { font-family: var(--display); font-weight: 700; }

@media (max-width: 860px) {
	.site-ribbon { height: clamp(30rem, 92vw, 40rem); grid-template-columns: 1fr 1fr; grid-template-rows: minmax(0, 1.16fr) minmax(0, .84fr); }
	.site-ribbon__frame--wide { grid-column: span 2; grid-row: auto; }
	.rates-details__grid { grid-template-columns: 1fr; }
	.rate-grid { grid-template-columns: 1fr; }
	.rate-card__body { min-height: 0; }
	.reservation-site-pair { height: clamp(19rem, 64vw, 28rem); }
	/* `.ns` is EasyWeb's own hook for the rows it means to keep out of sight —
	   the honeypot fields its spam trap depends on. It hides them with a bare
	   `.ns { display: none }`, which a selector carrying `#theTable` outranks
	   many times over, so stacking every `tr` here would put ~200 "Please
	   clear this field" rows on the page at phone widths. Stack only the rows
	   that are meant to be seen. */
	.reservation-form-shell #theTable tr:not(.ns) { display: block; }
	.reservation-form-shell #theTable td:not(.ns),
	.reservation-form-shell #theTable th:not(.ns) { display: block; width: 100% !important; }
	.reservation-form-shell #theTable tr > th:first-child,
	.reservation-form-shell #theTable tr > td:first-child:not([colspan]) { padding: .8rem 0 .2rem !important; }
	/* The desktop form uses right-aligned labels beside controls. Once a row
	   stacks on mobile, labels become a natural left-aligned reading column. */
	.reservation-form-shell #theTable > tbody > tr > th:first-child,
	.reservation-form-shell #theTable > tbody > tr > td:first-child:not([colspan]),
	.reservation-form-shell #theTable > tr > th:first-child,
	.reservation-form-shell #theTable > tr > td:first-child:not([colspan]) { text-align: left !important; }
	.reservation-form-shell #theTable .radioTable td { width: auto !important; }
	/* The stacking rule above makes every cell a block, radio cells included.
	   EasyWeb follows each radio with an &nbsp;, which then wraps onto a line
	   of its own under the button: the cell grows a line taller and the
	   centred row leaves the radio riding above its label. Keep the cells the
	   flex boxes they are on desktop. */
	.reservation-form-shell #theTable .radioTable td:not(.ns) { display: flex; }
	/* Options wrap at this width ("Cozy Camping Cabin (3 night minimum)"), and
	   a radio centred on a two-line label sits between the lines. Top-align
	   the row and make the radio cell exactly one label line tall, so the
	   button centres on the first line whatever the label's length. */
	.reservation-form-shell #theTable .radioTable tr { align-items: flex-start; }
	.reservation-form-shell #theTable .radioTable tr > td:first-child:not([colspan]) {
		width: 1rem !important;
		padding: .3rem .6rem .3rem 0 !important;
		box-sizing: content-box;
		height: 1.3em;
	}
	/* "I Agree to All Policies" follows the centred policy note, so centre the
	   label and its checkbox under it rather than leaving them on the left. */
	.reservation-form-shell #theTable > tbody > tr:has(input[type="checkbox"]) > td:not(.ns),
	.reservation-form-shell #theTable > tr:has(input[type="checkbox"]) > td:not(.ns) { text-align: center !important; }
	.reservation-form-shell #theTable input[type="checkbox"] { margin-inline: auto; }
}

@media (max-width: 560px) {
	/* Stacked, the five photographs ran to the better part of two screens
	   before the rates arrived. Each group becomes a swipe rail instead: one
	   photograph tall, with the next one peeking past the right edge, which
	   is the affordance — no arrows, no dots, no script. The frames are
	   already buttons into the photo viewer, so a tap still opens the full
	   picture; only the browsing changes. */
	.rates-photo-ribbon .site-ribbon,
	.reservation-site-pair {
		display: grid;
		grid-auto-flow: column;
		grid-auto-columns: 86%;
		grid-template-columns: none;
		grid-template-rows: none;
		height: auto;
		gap: .6rem;
		/* The rail runs to both screen edges, while the scroll padding keeps
		   each snap lined up with the text column above it. */
		margin-inline: calc(var(--gutter) * -1);
		padding-inline: var(--gutter);
		scroll-padding-inline: var(--gutter);
		/* A rail that scrolls on one axis stops being `visible` on the other,
		   so without this the frames' drop shadows would be shaved off. */
		padding-block: .4rem;
		overflow-x: auto;
		overscroll-behavior-x: contain;
		scroll-snap-type: x mandatory;
		-webkit-overflow-scrolling: touch;
		scrollbar-width: none;
		/* A finger scrolls the rail natively; a mouse has nothing to push, so
		   site.js adds dragging and this says so. */
		cursor: grab;
		/* Dragging the rail must not start a text selection across it. */
		user-select: none;
		-webkit-user-select: none;
	}
	/* Snapping has to be off while the rail is being dragged, or it fights
	   every one-pixel step of the way. It comes back on release, which is
	   what settles the rail on a photograph. */
	.rates-photo-ribbon .site-ribbon.is-dragging,
	.reservation-site-pair.is-dragging {
		cursor: grabbing;
		scroll-snap-type: none;
		scroll-behavior: auto;
	}
	.rates-photo-ribbon .site-ribbon::-webkit-scrollbar,
	.reservation-site-pair::-webkit-scrollbar { display: none; }
	.site-ribbon__frame,
	.reservation-site-pair figure {
		height: clamp(12.5rem, 58vw, 16.5rem);
		scroll-snap-align: start;
	}
	/* The wide frame led the mosaic; in a rail it is one photograph of many. */
	.site-ribbon__frame--wide { grid-column: auto; grid-row: auto; }
	/* The ribbon's bottom padding is nearly nothing by design: it sits above a
	   band that brings its own. That reads as too tight once the ribbon is a
	   rail the reader has to finish with, so give the top group its own gap.
	   The lower pair is left alone — it is already clear of the form. */
	.rates-photo-ribbon { padding-bottom: clamp(1.5rem, 5vw, 2rem); }
	.reservation-form-shell #theTable .mailer_dateTime {
		grid-template-columns: minmax(0, 1.2fr) minmax(3rem, .5fr) minmax(3.75rem, .62fr);
		gap: .38rem;
	}
}

@media (prefers-reduced-transparency: reduce), (prefers-contrast: more) {
	.reservation-form-shell { background: #fff; }
	/* Flat versions of the two card states, since the point of this block is
	   to drop the translucency, not the colour that tells them apart. */
	.rate-card { background: #F6F1E2; }
	.rate-card:hover,
	.rate-card:focus-within,
	.rate-card.is-selected { background: #fff; }
}


/* ==========================================================================
   ACTIVITIES

   The page has no new photography to lean on — the only shots that exist are
   six 250x175 snapshots carried over from the old site. Nothing here enlarges
   them, so the layout has to carry the page on type, rhythm and colour, and
   the photographs come in late and deliberately small.
   ========================================================================== */

/* ---- interior page head -------------------------------------------------
   No hero on the interior pages. The head picks the parchment up where the
   sticky bar leaves it and washes down into the cream the bands sit on, so
   the seam under the header never reads as a hard edge. */
.page-head {
	position: relative;
	overflow: hidden;
	padding-block: clamp(2.6rem, 5.5vw, 4.4rem) clamp(2rem, 4vw, 3.2rem);
	background: linear-gradient(180deg,
		var(--header-wash-deep) 0%,
		color-mix(in srgb, var(--header-wash-deep) 45%, var(--cream) 55%) 34%,
		var(--cream) 100%);
	border-bottom: 1px solid var(--rule);
}
/* The rule reads as a seam where the head's wash already fades into the
   ribbon's. Without it the head's own bottom padding is too generous: this
   brings the space above the photographs level with the space below them. */
body[data-page="rates"] .page-head {
	padding-bottom: clamp(1.5rem, 2.4vw, 1.9rem);
	border-bottom: 0;
}
.page-head h1 {
	font-size: var(--fs-2xl);
	max-width: 18ch;
	margin: 0;
	text-wrap: balance;
}
/* 18ch suits a heading meant to stack over two or three lines. This lifts the
   cap for one that is meant to hold a single line; it still wraps on a narrow
   phone, where no cap would have saved it. */
.page-head h1.h1--wide { max-width: none; }
.page-head .lede { margin-top: 1.1rem; max-width: none; }
/* A second paragraph under the lede, set to match it — same size, same
   colour. It is a continuation of the opening rather than a footnote to it. */
.page-head__note {
	margin-top: .9rem;
	max-width: none;
	color: var(--ink-soft);
	font-size: var(--fs-md);
}

/* The bunting hangs from the very top of the head, over the parchment and
   under nothing. Purely decorative: it is aria-hidden in the markup and the
   head reads the same with it switched off. */
/* Hangs from the very top edge of its band. .band--bunting adds the height
   back as padding so the heading underneath never runs into it. */
.band--bunting {
	position: relative;
	overflow: hidden;
}
/* .band + .band drops the lower band's top padding wherever two bands meet,
   and at (0,2,0) it outranks anything this class could say. The clearance the
   pennants need therefore goes on the wrap, which that rule cannot reach. */
.band--bunting > .wrap { padding-top: calc(var(--bunting-h) + .9rem); }
.page-bunting {
	display: block;
	width: 100%;
	height: var(--bunting-h);
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	pointer-events: none;
	opacity: .9;
}

/* ---- the season rail ----------------------------------------------------
   The old page listed the year's events as one run-on paragraph. The same
   facts laid on a timeline answer the question campers actually arrive with,
   which is "what will be happening the week we are there".

   Wide: the stops run across, ticks hanging off one horizontal rule.
   Narrow: the rule stands up and the months run down it. */
.season-rail {
	list-style: none;
	margin: 0;
	padding: 0;
	position: relative;
}
.season-month { position: relative; }
.season-month-name {
	font-family: var(--display);
	font-weight: 700;
	font-size: var(--fs-lg);
	color: var(--spruce);
	margin: 0 0 .75rem;
	line-height: 1.1;
}
.season-month ul {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: .5rem;
}
.season-month li {
	font-size: var(--fs-base);
	color: var(--ink-soft);
	line-height: 1.35;
}
/* The season's two fixed dates are facts, not events — they read as quieter
   type so the events stay the thing the eye lands on. */
.season-month li.is-marker {
	font-family: var(--display);
	font-style: italic;
	color: var(--ink-faint);
}
.season-tick {
	position: absolute;
	width: 13px;
	height: 13px;
	border-radius: 50%;
	background: var(--gold);
	box-shadow: 0 0 0 3px var(--cream);
}

@media (min-width: 900px) {
	/* Auto columns rather than a fixed count: months have been merged and
	   dropped as the client's calendar changed, and a hardcoded repeat(5)
	   left a blank column behind the moment the rail held four. However
	   many stops the markup has, they share the full width. */
	.season-rail {
		display: grid;
		grid-auto-flow: column;
		grid-auto-columns: minmax(0, 1fr);
		gap: clamp(1.1rem, 2vw, 2rem);
	}
	/* One rule behind them all, so the ticks sit on a line that genuinely
	   runs the width of the band rather than a row of stitched segments. */
	.season-rail::before {
		content: "";
		position: absolute;
		top: 6px;
		left: 0;
		right: 0;
		height: 2px;
		background: var(--rule);
	}
	.season-month { padding-top: 2.6rem; }
	.season-tick { top: 0; left: 0; }
}

@media (max-width: 899.98px) {
	.season-rail {
		display: flex;
		flex-direction: column;
		gap: clamp(1.6rem, 5vw, 2.2rem);
		padding-left: 1.9rem;
	}
	.season-rail::before {
		content: "";
		position: absolute;
		top: 6px;
		bottom: 0;
		left: 6px;
		width: 2px;
		background: var(--rule);
	}
	.season-tick { top: 0; left: -1.9rem; }
	/* The last month stops the rule under its own tick instead of letting it
	   run past the final event into empty space. */
	.season-month:last-child { padding-bottom: .2rem; }
}

/* ---- the snapshots ------------------------------------------------------
   Six photographs inherited from the old site, 250x175 apiece. They are laid
   in beside each section's copy rather than pooled in a gallery, and they are
   never enlarged: the frame is sized from the image instead of the image
   being stretched to fill a frame, so 250px is exactly what renders. A narrow
   column may shrink one; nothing can blow one up. */
.shot-pair {
	display: flex;
	flex-wrap: wrap;
	gap: clamp(1.1rem, 2.2vw, 1.7rem);
	margin: 0;
	padding: 0;
	list-style: none;
}
.snap {
	margin: 0;
	flex: 0 0 auto;
	max-width: 100%;
}
/* The figure's UA default is margin: 1em 40px. Left in, it padded 80px onto
   every frame and squeezed the photograph below its own 250px. */
.snap figure { margin: 0; }
.snap picture {
	display: block;
	width: max-content;
	max-width: 100%;
	background: #fff;
	padding: 8px;
	border: 1px solid var(--rule);
	box-shadow: var(--shadow-sm);
	/* A print laid down, not a tile in a grid. Small enough to read as placed
	   by hand rather than as a gimmick, and it alternates so the pair does
	   not lean the same way. */
	transform: rotate(-1.1deg);
	transition: transform .35s cubic-bezier(.22,.61,.36,1), box-shadow .35s ease;
}
.snap:nth-child(even) picture { transform: rotate(1.3deg); }
.snap:hover picture {
	transform: rotate(0deg) translateY(-3px);
	box-shadow: var(--shadow-md);
}
/* The one dimension that matters: the file's own width, never scaled up.
   max-width lets a phone shrink it; nothing lets anything stretch it. */
.snap img {
	display: block;
	width: 250px;
	max-width: 100%;
	height: auto;
	background: var(--cream-deep);
}
.snap figcaption {
	margin-top: .75rem;
	max-width: 272px;
	font-family: var(--display);
	font-style: italic;
	font-size: var(--fs-sm);
	line-height: 1.3;
	color: var(--ink-soft);
}

/* ---- copy beside the snapshots ------------------------------------------
   Content left, a pair of prints right. The photo column is sized by the
   prints themselves (two frames plus the gap), so the copy takes whatever is
   left rather than the pair being squeezed to a fraction. Below the
   breakpoint there is not enough width for both and the prints drop under
   the copy, where they centre. */
.has-shots { display: block; }
.has-shots-body { min-width: 0; }

@media (min-width: 1140px) {
	.has-shots {
		display: grid;
		grid-template-columns: minmax(0, 1fr) auto;
		gap: clamp(1.8rem, 3.4vw, 3.4rem);
		align-items: start;
	}
	.has-shots .shot-pair { flex-wrap: nowrap; }
	/* The rail needs the width more than the prints need to sit side by side:
	   stacked, the photo column is one frame wide and the five months get
	   room to set on one line apiece. */
	.shot-pair--stack { flex-direction: column; }
}
/* Four amenity cards. Beside the prints a squeezed column would make four
   slivers; on their own at these widths auto-fit takes three and leaves one
   stranded underneath. Two-by-two is right in both cases. */
@media (min-width: 620px) {
	.has-shots .amenity-list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* Under a full-width timeline rather than beside it, centred on the rail. */
.shot-pair--below {
	margin-top: clamp(1.9rem, 3.6vw, 3rem);
	justify-content: center;
}

@media (max-width: 1139.98px) {
	.has-shots .shot-pair {
		justify-content: center;
		margin-top: clamp(1.8rem, 4vw, 2.6rem);
	}
}

/* ---- the calendar -------------------------------------------------------
   Google's iframe cannot be restyled from here, so it is framed instead: a
   panel in the site's own furniture with the embed seated inside it. */
.embed-panel {
	background: #fff;
	border: 1px solid var(--rule);
	border-radius: var(--radius-lg);
	box-shadow: var(--shadow-md);
	overflow: hidden;
}
.embed-head {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	justify-content: space-between;
	gap: .6rem 1.2rem;
	padding: .95rem clamp(1rem, 2.4vw, 1.5rem);
	background: var(--spruce);
	color: #E8F0E2;
}
.embed-head h3 {
	margin: 0;
	font-size: var(--fs-sm);
	font-weight: 700;
	color: #fff;
	letter-spacing: .01em;
}
.embed-head p {
	margin: 0;
	font-family: var(--display);
	font-style: italic;
	font-size: var(--fs-sm);
	color: #B9CDB6;
}
.cal-frame {
	position: relative;
	/* Month grid needs the height or Google scrolls it internally; the agenda
	   view swapped in on narrow screens is comfortable a good deal shorter. */
	height: 640px;
	background: var(--paper);
}
@media (max-width: 760px) {
	.cal-frame { height: 480px; }
}
.cal-frame iframe {
	display: block;
	width: 100%;
	height: 100%;
	border: 0;
}
.cal-note {
	margin-top: 1rem;
	font-size: var(--fs-base);
	color: var(--ink-faint);
}

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


/* The locator hangs a full header's depth below the bar so that it overlaps
   the hero photograph — see --vt-hang on .header-identity. The secondary
   pages have no hero for it to overlap, and left alone it hangs into the
   first band's copy instead. There it sits inside the bar at rest, at exactly
   the header's own height. The stuck rules are untouched: from this point
   down the shrink behaves the same on every page. */
body:not([data-page="home"]) .header-identity { --vt-hang: 0px; }

/* At rest the bar draws a hard 1px pine line along its bottom edge, which is
   the seam between it and the hero photograph. The secondary pages have no
   hero for it to sit against, so they take the stuck treatment from the
   start: the line gives way to the same soft spread the bar carries once it
   has shrunk, and nothing changes underfoot when it does. */
body:not([data-page="home"]) .site-header {
	box-shadow: 0 0 2px var(--pine), var(--shadow-sm);
}

/* Unsticking the bar on a secondary page is the only thing moving on screen,
   and at .22s ease it read as a snap rather than a settle. Two changes:

   1. align-self is not an animatable property, so it was switching from
      flex-start to centre the instant the class flipped, while the height was
      still easing — a small jump part-way through the motion. At rest the
      locator is exactly as tall as the bar, which makes centre and flex-start
      identical, so holding it centred throughout costs nothing at either end
      and removes the jump.
   2. A longer duration and a real deceleration curve, applied to all three
      boxes that move together (bar, logo, map) so they stay in step.

   Scoped away from the home page, where the map hangs over the hero and its
   motion is tuned against the intro. */
body:not([data-page="home"]) .vt-locator { align-self: center; }

body:not([data-page="home"]) .header-inner,
body:not([data-page="home"]) .brand-logo,
body:not([data-page="home"]) .vt-locator {
	transition-duration: .42s;
	transition-timing-function: cubic-bezier(.22, .61, .36, 1);
}


/* ==========================================================================
   AREA ATTRACTIONS

   Ten places, and licensed photography exists for only five of them — the
   restaurants and the motocross track are businesses, not landmarks. A
   masonry wall is what makes that survivable: cards are free to be whatever
   height their content needs, so a card with a photograph and a card with
   only type sit together without either looking like a mistake.
   ========================================================================== */

.map-frame {
	position: relative;
	height: clamp(340px, 46vw, 520px);
	background: var(--paper);
}
.map-frame iframe { display: block; width: 100%; height: 100%; border: 0; }

/* ---- the directions themselves ---- */
/* Set to the list rather than to .lede: at the lede's 1.2rem this ran a word
   past the line and left "Route 105" stranded on its own. Same size, colour
   and leading as the steps it introduces. */
.route-intro {
	margin: 0;
	font-size: var(--fs-base);
	color: var(--ink-soft);
	line-height: 1.45;
	/* Keeps the browser from dropping a single short word onto the last line.
	   The road numbers are bound with non-breaking spaces in the markup as
	   well, since that is what was stranding "105." on its own. */
	text-wrap: pretty;
}

.route {
	list-style: none;
	margin: 1.4rem 0 0;
	padding: 0;
	display: grid;
	gap: .55rem;
}
.route li {
	position: relative;
	padding-left: 2.1rem;
	color: var(--ink-soft);
	line-height: 1.45;
}
.route li::before {
	counter-increment: route;
	content: counter(route);
	position: absolute;
	left: 0;
	top: .05rem;
	width: 1.45rem;
	height: 1.45rem;
	border-radius: 50%;
	background: var(--pine);
	color: #fff;
	font-family: var(--display);
	font-weight: 700;
	font-size: .82rem;
	display: grid;
	place-items: center;
}
.route { counter-reset: route; }

/* ---- the wall ----------------------------------------------------------
   Multi-column rather than grid: the cards differ in height by design and
   columns is the one masonry that needs no script and no fixed row unit. */
.attraction-wall {
	columns: 3;
	column-gap: clamp(1rem, 1.9vw, 1.6rem);
}
@media (max-width: 1100px) { .attraction-wall { columns: 2; } }
@media (max-width: 680px)  { .attraction-wall { columns: 1; } }

.attraction {
	break-inside: avoid;
	/* Safari still needs the older spelling to keep a card whole. */
	-webkit-column-break-inside: avoid;
	page-break-inside: avoid;
	margin: 0 0 clamp(1rem, 1.9vw, 1.6rem);
	background: #fff;
	border: 1px solid var(--rule);
	border-radius: var(--radius-lg);
	box-shadow: var(--shadow-sm);
	overflow: hidden;
	transition: box-shadow .3s ease, transform .3s cubic-bezier(.22,.61,.36,1);
}
.attraction:hover {
	box-shadow: var(--shadow-md);
	transform: translateY(-2px);
}
.attraction-media { display: block; background: var(--cream-deep); }
.attraction-media img {
	display: block;
	width: 100%;
	height: auto;
}
.attraction-body { padding: clamp(1rem, 1.9vw, 1.35rem); }
.attraction-body h3 {
	margin: .55rem 0 .5rem;
	font-size: var(--fs-lg);
	line-height: 1.15;
}
.attraction-body h3 a {
	color: var(--spruce);
	text-decoration: none;
	border-bottom: 2px solid color-mix(in srgb, var(--pine) 30%, transparent);
}
.attraction-body h3 a:hover { color: var(--rust); border-bottom-color: var(--rust); }
.attraction-body p {
	margin: 0;
	color: var(--ink-soft);
	font-size: var(--fs-base);
	line-height: 1.5;
}
.attraction-meta {
	margin-top: .8rem;
	font-family: var(--display);
	font-style: italic;
	font-size: var(--fs-sm);
	color: var(--ink-faint);
}

/* ---- category chips ----
   The old page sorted these under five headings. The headings would each
   have carried one to three items, so the grouping rides on the cards
   instead and the wall stays one piece. */
.chip {
	display: inline-block;
	margin: 0;
	padding: .2rem .6rem;
	border-radius: 999px;
	font-family: var(--display);
	font-weight: 600;
	font-size: .78rem;
	letter-spacing: .04em;
	text-transform: uppercase;
	background: color-mix(in srgb, var(--chip) 14%, #fff);
	color: color-mix(in srgb, var(--chip) 78%, #1A241D);
	border: 1px solid color-mix(in srgb, var(--chip) 28%, #fff);
}
.chip--outdoors { --chip: var(--lake); }
.chip--family   { --chip: var(--rust); }
.chip--events   { --chip: var(--maple); }
.chip--culture  { --chip: var(--pine); }
.chip--dining   { --chip: var(--spruce); }


/* ---- photograph credits ----
   CC BY and CC BY-SA both require the author and the licence to travel with
   the picture, so the credits are part of the page, not an optional extra. */
/* Attribution is a condition of the CC BY / CC BY-SA photographs, so it stays
   on the page — but as one quiet line rather than a bordered panel with its
   own heading. If those photographs are ever replaced with licensed or
   client-owned ones, this line goes with them. */
.credits-line {
	margin-top: clamp(1.6rem, 3vw, 2.4rem);
	font-size: .78rem;
	line-height: 1.55;
	color: var(--ink-faint);
	max-width: 88ch;
}
.credits-line a { color: inherit; }

.credits {
	margin-top: clamp(1.6rem, 3vw, 2.4rem);
	padding-top: 1.1rem;
	border-top: 1px solid var(--rule);
	font-size: .84rem;
	line-height: 1.5;
	color: var(--ink-faint);
}
.credits h3 {
	font-size: .84rem;
	text-transform: uppercase;
	letter-spacing: .08em;
	color: var(--ink-soft);
	margin: 0 0 .5rem;
}
.credits ul { margin: 0; padding: 0; list-style: none; }
.credits li { margin: 0 0 .25rem; }
.credits a { color: inherit; }

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

/* ==========================================================================
   SITE MAP & RULES

   The campground's own drawn map, at the full width of the container, with
   pins dropped on it at the coordinates of the real lots. The map itself is
   1650x1275, so every pin is stored as a percentage of that and the stage
   scales without anything being re-measured.

   The pins are generated from .sitemap-spots, which is the only place the
   content lives. Without JavaScript that list is the page: a wall of
   photographs with headings and captions. With it, the list becomes the
   source the map reads from, and the toggle underneath brings it back for
   anyone who would rather scroll than hunt.
   ========================================================================== */

/* This page has no interior head any more: the map section is the first thing
   under the bar, so it picks the parchment up where the header leaves it and
   washes into the white the map sits on, which is what .page-head does on the
   other interior pages. */
body[data-page="rules"] main > .band:first-child {
	padding-top: clamp(2.2rem, 4.5vw, 3.6rem);
	background:
		linear-gradient(180deg,
			var(--header-wash-deep) 0%,
			color-mix(in srgb, var(--header-wash-deep) 38%, #fff 62%) 40%,
			#fff 100%);
}
body[data-page="rules"] .section-head h1 { font-size: var(--fs-2xl); margin: 0; }

.sitemap {
	margin-top: clamp(1.4rem, 3vw, 2.2rem);
	/* The card is a sibling of the stage, not a child of it: on a phone the
	   stage is inside a horizontal scroller, and a card living in there would
	   slide off with the map. It anchors to this instead, and the script adds
	   the stage's own offset when it places it. */
	position: relative;
}

/* No scroller at all on a wide screen — the stage simply fills the column.
   Below 860px this becomes the thing that lets the map keep a width of its
   own on a 360px phone, which is what keeps the pins from sitting on top of
   one another. */
.sitemap-scroll { overflow: visible; }

.sitemap-stage {
	position: relative;
	/* The map is a drawing on a flat green ground; a rule and a soft shadow
	   stop it floating on the white band without boxing it in. */
	border: 1px solid var(--rule);
	border-radius: var(--radius-lg);
	box-shadow: var(--shadow-sm);
	background: #DFEBC8;
	overflow: hidden;
	/* Held before the image decodes so the pins never land on a collapsed
	   stage and then jump. 1650/1275. */
	aspect-ratio: 1650 / 1275;
}
.sitemap-stage img {
	width: 100%;
	height: 100%;
	display: block;
	object-fit: cover;
}

/* ---- pins ---------------------------------------------------------------
   A ring, not a marker. The map already says what each place is — the site
   number is printed on it, the pool says POOL, the office is a brown box with
   its name in it — so anything filled and opaque dropped on top hides the one
   piece of information the pin is pointing at. What is missing from a printed
   map is only the news that it can be clicked, and a ring says that without
   covering anything.

   Three rings to each pin: the button's own border, which is always there and
   is what a reader with reduced motion or a stalled animation still sees, plus
   a tight quick ping and a wide slow one. Positioned by two custom properties
   the script writes from the spot's data-x / data-y. */
.sitemap-pin {
	position: absolute;
	left: calc(var(--x) * 1%);
	top: calc(var(--y) * 1%);
	transform: translate(-50%, -50%);
	/* Sized to hug the site rectangle. The printed numbers sit right against
	   their rectangles — there is no radius that clears them entirely — so the
	   ring is kept just wide enough to enclose one and no wider, which leaves
	   the digits beside it legible. */
	width: clamp(26px, 1.9vw, 28px);
	height: clamp(26px, 1.9vw, 28px);
	padding: 0;
	border: 2px solid var(--maple);
	border-radius: 50%;
	/* Transparent, but still hit-tested: the whole disc is the target, the
	   number underneath included. */
	background: transparent;
	cursor: pointer;
	/* A thin maple ring alone disappears over a dark tree or a red site
	   rectangle. A hairline of white either side of it holds the edge against
	   every ground on the drawing. */
	box-shadow:
		0 0 0 1.5px rgba(255, 255, 255, .75),
		inset 0 0 0 1.5px rgba(255, 255, 255, .55);
	transition: transform .18s cubic-bezier(.2, .7, .3, 1.4),
		background-color .18s ease, border-color .18s ease;
	z-index: 2;
}

/* The store, the pool, the playground and the entrance sign mark a building or
   a lawn rather than one lot, so their rings open a little wider. */
.sitemap-pin--place {
	width: clamp(30px, 2.6vw, 38px);
	height: clamp(30px, 2.6vw, 38px);
}

/* The office and the pool are named on the drawing, inside a box and inside
   the water, and a ring the size of the others cuts straight through the
   lettering. These two are sized to go round the label rather than across it,
   as a percentage of the stage so they stay locked to the drawing at every
   width — hence aspect-ratio rather than a matching height, which would
   resolve against the stage's height instead. */
.sitemap-pin--wide {
	width: calc(var(--ring) * 1%);
	height: auto;
	aspect-ratio: 1;
	min-width: 34px;
}

.sitemap-pin:hover,
.sitemap-pin:focus-visible {
	transform: translate(-50%, -50%) scale(1.12);
	background: rgba(194, 48, 24, .16);
	z-index: 4;
}
.sitemap-pin.is-active {
	border-color: var(--gold-bright);
	background: rgba(224, 176, 74, .24);
	box-shadow:
		0 0 0 2px rgba(255, 255, 255, .95),
		0 2px 8px rgba(19, 38, 26, .35);
	z-index: 5;
}

@media (prefers-reduced-motion: no-preference) {
	.sitemap-pin::before,
	.sitemap-pin::after {
		content: "";
		position: absolute;
		/* -2px so the ping starts on the border box, not inside it, and the
		   first frame sits exactly on the static ring. */
		inset: -2px;
		border-radius: 50%;
		border: 2px solid var(--maple);
		pointer-events: none;
		animation: sitemap-ping 3.2s cubic-bezier(.2, .55, .3, 1) infinite;
	}
	/* The tight one. Shorter throw, thinner line, and half a beat behind, so
	   the pair reads as one pulse going out rather than two rings racing.
	   That half beat is the only offset left: the pins themselves were
	   staggered against each other until the client asked for one pulse
	   across the whole map, so every ring now starts on the same frame. */
	.sitemap-pin::after {
		border-width: 1.5px;
		animation-name: sitemap-ping-tight;
		animation-delay: .44s;
	}
	/* Once a pin is the one being read, its own pulse is noise. Hidden rather
	   than stopped: `animation: none` restarts the timeline from zero when the
	   card closes, which would leave that one pin beating out of step with the
	   other nineteen for good. Keyframes override `opacity`, so visibility is
	   what can hold it down while its animation keeps running underneath. */
	.sitemap-pin.is-active::before,
	.sitemap-pin.is-active::after { visibility: hidden; }
}
@keyframes sitemap-ping {
	0%   { opacity: .8; transform: scale(1); }
	55%  { opacity: 0;  transform: scale(2.4); }
	100% { opacity: 0;  transform: scale(2.4); }
}
@keyframes sitemap-ping-tight {
	0%   { opacity: .65; transform: scale(1); }
	34%  { opacity: 0;   transform: scale(1.5); }
	100% { opacity: 0;   transform: scale(1.5); }
}

/* ---- the card ----------------------------------------------------------
   Floats over the map, anchored to the pin. The script writes left/top in
   pixels after clamping it inside the stage, which is why there is no
   positioning arithmetic here. Below 860px it stops floating and becomes a
   panel under the map — see the block at the end of this section. */
.sitemap-card {
	position: absolute;
	z-index: 8;
	width: min(310px, 74%);
	background: #fff;
	border: 1px solid var(--rule);
	border-radius: var(--radius-lg);
	box-shadow: var(--shadow-md);
	overflow: hidden;
}
.sitemap-card[hidden] { display: none; }

.sitemap-card__close {
	position: absolute;
	top: 6px;
	right: 6px;
	z-index: 2;
	width: 30px;
	height: 30px;
	display: grid;
	place-items: center;
	border: 0;
	border-radius: 50%;
	background: rgba(31, 63, 44, .62);
	color: #fff;
	cursor: pointer;
}
.sitemap-card__close svg { width: 15px; height: 15px; stroke: currentColor; }
.sitemap-card__close:hover { background: var(--spruce); }

.sitemap-card__body figure { margin: 0; }
.sitemap-card__body img {
	width: 100%;
	aspect-ratio: 3 / 2;
	object-fit: cover;
}
/* The photo is a button in the source list so the existing viewer can pick it
   up; in here it has to lose every trace of being one. */
.sitemap-card__body .spot-shot {
	display: block;
	width: 100%;
	padding: 0;
	border: 0;
	background: none;
	cursor: zoom-in;
}
.sitemap-card__body figcaption {
	padding: .7rem .85rem .85rem;
	font-size: .92rem;
	line-height: 1.5;
	color: var(--ink-soft);
}
.sitemap-card__body h3 {
	font-size: 1.15rem;
	margin: 0 0 .2rem;
	color: var(--spruce);
}
.sitemap-card__body .spot-type {
	display: inline-block;
	margin: 0 0 .4rem;
	font-family: var(--body);
	font-size: .7rem;
	font-weight: 800;
	letter-spacing: .07em;
	text-transform: uppercase;
	color: var(--pine);
}
.sitemap-card__body .spot-zoom {
	display: block;
	margin-top: .5rem;
	font-size: .8rem;
	color: var(--ink-faint);
}

.sitemap-card__nav {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: .5rem;
	padding: .5rem .6rem;
	border-top: 1px solid var(--rule);
	background: var(--paper);
}
.sitemap-card__nav button {
	display: grid;
	place-items: center;
	width: 30px;
	height: 30px;
	border: 1px solid var(--rule);
	border-radius: var(--radius);
	background: #fff;
	color: var(--pine);
	cursor: pointer;
}
.sitemap-card__nav button:hover { background: var(--cream); color: var(--spruce); }
.sitemap-card__nav button svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.sitemap-card__count {
	font-size: .76rem;
	font-weight: 700;
	letter-spacing: .05em;
	text-transform: uppercase;
	color: var(--ink-faint);
}

/* Shown only where the map scrolls. */
.sitemap-swipe {
	display: none;
	margin: .5rem 0 0;
	font-size: .86rem;
	color: var(--ink-faint);
}

/* ---- the line under the map -------------------------------------------- */
.sitemap-foot {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: .8rem 1.4rem;
	margin-top: .9rem;
}
.sitemap-hint {
	font-size: .95rem;
	color: var(--ink-soft);
	margin: 0;
}
.sitemap-hint strong { color: var(--pine); font-weight: 800; }
.sitemap-actions { display: flex; flex-wrap: wrap; gap: .6rem; }
.sitemap-toggle,
.sitemap-pdf {
	font-family: var(--body);
	font-size: .86rem;
	font-weight: 700;
	padding: .45rem .9rem;
	border: 1px solid var(--rule);
	border-radius: var(--radius);
	background: #fff;
	color: var(--pine);
	text-decoration: none;
	cursor: pointer;
}
.sitemap-toggle:hover,
.sitemap-pdf:hover { background: var(--cream); color: var(--spruce); }

/* ---- the spot list -----------------------------------------------------
   The page without JavaScript, and the "browse all" panel with it. */
/* Every entry carries a photograph and a two-line caption, so the cells are
   all the same height and a grid keeps the reading order across rather than
   down a column. */
.sitemap-spots {
	list-style: none;
	margin: clamp(1.6rem, 3vw, 2.4rem) 0 0;
	padding: 0;
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
	gap: clamp(1rem, 2vw, 1.6rem);
	align-items: start;
}
.sitemap-spots[hidden] { display: none; }
.sitemap-spots > li { margin: 0; }
.sitemap-spots figure { margin: 0; }
.sitemap-spots .spot-shot {
	display: block;
	width: 100%;
	padding: 0;
	border: 0;
	background: none;
	cursor: zoom-in;
}
.sitemap-spots img {
	width: 100%;
	aspect-ratio: 3 / 2;
	object-fit: cover;
	border-radius: var(--radius);
}
.sitemap-spots figcaption { padding-top: .6rem; }
.sitemap-spots h3 { font-size: 1.15rem; color: var(--spruce); margin: 0 0 .15rem; }
.sitemap-spots .spot-type {
	display: block;
	font-family: var(--body);
	font-size: .7rem;
	font-weight: 800;
	letter-spacing: .07em;
	text-transform: uppercase;
	color: var(--pine);
	margin-bottom: .35rem;
}
.sitemap-spots .spot-zoom { display: none; }

/* ---- rules -------------------------------------------------------------- */
.rule-jump {
	display: flex;
	flex-wrap: wrap;
	gap: .5rem;
	margin: 0 0 clamp(1.6rem, 3vw, 2.4rem);
	padding: 0;
	list-style: none;
}
.rule-jump a {
	display: inline-block;
	padding: .35rem .8rem;
	border: 1px solid var(--rule);
	border-radius: 999px;
	background: #fff;
	font-size: .82rem;
	font-weight: 700;
	color: var(--pine);
	text-decoration: none;
}
.rule-jump a:hover { background: var(--pine); border-color: var(--pine); color: #fff; }

/* The rules as a list, not a wall of boxes: the topic in a column of its own
   and what it says beside it, which is the shape the old site used and the
   shape anybody scanning for one heading wants. A hairline between rows is the
   whole of the chrome. */
.rule-list { border-top: 1px solid var(--rule); }
.rule-row {
	display: grid;
	grid-template-columns: minmax(150px, 20%) minmax(0, 1fr);
	gap: clamp(.6rem, 3vw, 2.4rem);
	padding-block: clamp(1.1rem, 2.2vw, 1.6rem);
	border-bottom: 1px solid var(--rule);
	/* Anchored jumps have to clear the sticky bar. */
	scroll-margin-top: calc(var(--header-h-stuck) + 1rem);
}
.rule-row h3 {
	font-size: 1.18rem;
	color: var(--spruce);
	margin: 0;
	/* Optically level with the first line of the body beside it, which sits on
	   a looser line-height. */
	padding-top: .12rem;
}
.rule-row__body { color: var(--ink-soft); }
.rule-row__body p + p { margin-top: .7rem; }
.rule-row__body strong { color: var(--ink); }

/* Below this the two columns would each be too narrow to set well, so the
   heading sits over its text instead of beside it. */
@media (max-width: 640px) {
	.rule-row {
		grid-template-columns: 1fr;
		gap: .45rem;
	}
}

.rule-card {
	background: #fff;
	border: 1px solid var(--rule);
	border-radius: var(--radius-lg);
	padding: clamp(1.1rem, 2vw, 1.5rem);
	box-shadow: var(--shadow-sm);
	/* Anchored jumps have to clear the sticky bar. */
	scroll-margin-top: calc(var(--header-h-stuck) + 1rem);
}
.rule-card h3 {
	font-size: 1.28rem;
	color: var(--spruce);
	margin: 0 0 .6rem;
}
.rule-card p + p { margin-top: .6rem; }
.rule-card p, .rule-card li { color: var(--ink-soft); line-height: 1.6; }
.rule-card ul {
	margin: .6rem 0 0;
	padding-left: 1.05rem;
}
.rule-card li + li { margin-top: .4rem; }
.rule-card strong { color: var(--ink); }

/* The pet policy is the longest of them and the one people are sent here to
   read, so it runs the full width of the wall and gets the warmer ground. */
.rule-card--wide {
	margin-bottom: clamp(1.4rem, 2.6vw, 2.2rem);
	background: linear-gradient(180deg, #fff 0%, var(--paper) 100%);
	border-color: color-mix(in srgb, var(--pine) 28%, var(--rule) 72%);
}
.rule-card--wide .rule-card__cols {
	columns: 2;
	column-gap: clamp(1.6rem, 3vw, 2.8rem);
}
/* The list is the bulk of this card and is far taller than one column, so it
   has to be allowed to break. Holding the break on the items instead keeps the
   two columns level without stranding a bullet across the gap. */
.rule-card--wide .rule-card__cols > * { break-inside: auto; }
.rule-card--wide .rule-card__cols li,
.rule-card--wide .rule-card__cols p { break-inside: avoid; }
.rule-card--wide .rule-card__cols ul { margin-top: 0; }
/* The closing line sits directly under the last bullet otherwise, and reads as
   one more item that lost its marker. */
.rule-card--wide .rule-card__cols ul + p { margin-top: .9rem; }
@media (max-width: 720px) { .rule-card--wide .rule-card__cols { columns: 1; } }

.rule-alert {
	/* It opens its column and it is the hardest thing on the page to say, so it
	   gets room on both sides rather than being packed against the list that
	   follows it. */
	margin-block: 1.4rem 1.6rem;
	padding: 1rem 1.15rem;
	border-left: 4px solid var(--maple);
	background: var(--maple-soft);
	color: var(--maple-deep);
	font-weight: 700;
	line-height: 1.5;
}

/* ---- narrow ------------------------------------------------------------- */
@media (max-width: 860px) {
	/* The pins on a 350px-wide drawing would overlap, and the site numbers
	   under them would be four pixels tall. The map keeps a usable width and
	   the column scrolls sideways over it instead.

	   The width is set by the tightest run of pins rather than by the phone:
	   the ring is a fixed 26px at every size while the drawing scales, so the
	   closer two sites are printed, the wider the stage has to be before their
	   rings come apart. Sites 100 to 103 are the tightest on the map, and they
	   overlapped at the 820px this held while the rail ended at site 84. */
	.sitemap-scroll {
		overflow-x: auto;
		overscroll-behavior-x: contain;
		-webkit-overflow-scrolling: touch;
		padding-bottom: .4rem;
	}
	.sitemap-stage { width: 1100px; }
	.sitemap-swipe { display: block; }

	/* The card stops floating. On a phone a 310px panel over a map that is
	   itself only 340px wide covers the thing it is describing, and the pin
	   it points at is under your thumb. */
	.sitemap-card {
		position: static;
		width: auto;
		margin-top: .9rem;
		box-shadow: var(--shadow-sm);
	}
	.sitemap-card__body img { aspect-ratio: 16 / 9; }
	.sitemap-foot { margin-top: .8rem; }
}
