/* TBK Villas — one stylesheet, tokens at the top.
   Change a colour or a font here and it changes everywhere. */

:root {
	/* Dark surfaces and body text are a deep forest green rather than black — it sits with
	   the lime and the jungle in the photography, where flat black just looked like a
	   default. The whole palette stays in the green family. */
	--ink: #17291f;
	--ink-soft: #3c4d42;
	--lime: #c6d67b;
	--lime-deep: #9cb648;
	--sand: #f2ece1;
	--cream: #fffdf8;
	/* Accent is a deep olive, not terracotta — the palette stays entirely in the green
	   family the photography lives in. Dark enough to pass contrast on cream and sand. */
	--accent: #4f6b2f;
	--white: #fff;
	--muted: #77786d;
	--line: rgb(23 41 31 / 12%);

	/* Fraunces over Playfair: same editorial weight, none of the formal-Victorian
	   stiffness. Variable, so the optical-size axis keeps big headlines tight and small
	   text readable. */
	--serif: "Fraunces", Georgia, serif;
	--sans: "Karla", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;

	--fs-hero: clamp(3rem, 9vw, 7.5rem);
	--fs-display: clamp(2.25rem, 5.5vw, 4.5rem);
	--fs-h2: clamp(1.9rem, 4vw, 3.25rem);
	--fs-h3: clamp(1.15rem, 1.6vw, 1.45rem);
	--fs-body: clamp(1rem, 1.05vw, 1.1rem);
	--fs-small: 0.78rem;

	--gap: clamp(1rem, 2vw, 2rem);
	--section: clamp(4rem, 9vw, 8.5rem);
	--wrap: 1320px;
	--r: 14px;
	--r-lg: 28px;

	--ease: cubic-bezier(0.22, 1, 0.36, 1);
	--shadow: 0 24px 60px -20px rgb(23 41 31 / 28%);
}

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

html {
	scroll-behavior: smooth;
	scroll-padding-top: 90px;
}

body {
	margin: 0;
	font-family: var(--sans);
	font-size: var(--fs-body);
	line-height: 1.7;
	color: var(--ink);
	background: var(--cream);
	-webkit-font-smoothing: antialiased;
	overflow-x: hidden;
}

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

/* The UA sheet gives [hidden] display:none at the lowest possible specificity, so any
   component rule with a display (.villa-card{display:block}) silently beats it and the
   element stays on screen. That's why the villa filters appeared to do nothing. */
[hidden] {
	display: none !important;
}

a {
	color: inherit;
}

h1,
h2,
h3 {
	font-family: var(--serif);
	font-weight: 400;
	line-height: 1.06;
	margin: 0;
	letter-spacing: -0.015em;
}

.wrap {
	width: min(100% - 2.5rem, var(--wrap));
	margin-inline: auto;
}

.section {
	padding-block: var(--section);
	position: relative;
}

.section--paper {
	background: var(--sand);
}

.section--tight {
	padding-top: 0;
}

/* ---------- motion ----------
   Everything fades up on entry via IntersectionObserver (main.js adds .is-in).
   --d staggers siblings. All of it collapses under prefers-reduced-motion. */

/* Scoped to .js (set by an inline script in <head>): if JavaScript never runs, nothing
   is hidden and the page reads as plain static content rather than a blank screen. */
.js [data-reveal] {
	opacity: 0;
	transform: translateY(28px);
	transition: opacity 0.8s var(--ease), transform 0.8s var(--ease);
	transition-delay: var(--d, 0ms);
}

.js [data-reveal].is-in {
	opacity: 1;
	transform: none;
}

/* ---------- section heading ---------- */

.eyebrow {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	font-family: var(--sans);
	font-size: var(--fs-small);
	font-weight: 700;
	letter-spacing: 0.2em;
	text-transform: uppercase;
	color: var(--accent);
	margin: 0 0 1rem;
}

.eyebrow::before {
	content: "";
	inline-size: 26px;
	block-size: 1px;
	background: currentcolor;
	opacity: 0.5;
}

.eyebrow .ico {
	inline-size: 15px;
	block-size: 15px;
}

.h2 {
	font-size: var(--fs-h2);
	text-wrap: balance;
}

/* Opt-in balanced wrapping for headings that were breaking mid-phrase. */
.balance {
	text-wrap: balance;
}

/* Heading + intro block. Wide enough that short headings stay on one or two lines —
   the old ch-caps were forcing "Relaxed atmosphere for you." onto three. */
.head-block {
	max-width: 42ch;
	margin-bottom: 2.75rem;
}

.head-block .h2,
.head-block .display {
	text-wrap: balance;
}

.display {
	font-size: var(--fs-display);
}

/* Italic serif for the emphasised word in a headline. Used sparingly — on every heading
   it stops reading as emphasis and starts reading as a tic. */
.em {
	font-style: italic;
	color: var(--accent);
}

/* Heading on the left, a fact on the right — breaks the eyebrow/heading/paragraph
   rhythm that otherwise repeats down the whole page. */
.section-head {
	display: flex;
	align-items: flex-end;
	justify-content: space-between;
	gap: var(--gap);
	flex-wrap: wrap;
	margin-bottom: 2.75rem;
	padding-bottom: 1.5rem;
	border-bottom: 1px solid var(--line);
}

.section-head > div {
	max-width: 40ch;
}

.section-head__note {
	margin: 0;
	font-size: 0.85rem;
	letter-spacing: 0.02em;
	color: var(--muted);
}

/* ---------- buttons ---------- */

.btn {
	position: relative;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.6rem;
	padding: 1rem 2rem;
	border: 1px solid var(--ink);
	border-radius: 100px;
	background: var(--ink);
	color: var(--white);
	font-family: var(--sans);
	font-size: var(--fs-small);
	font-weight: 700;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	text-decoration: none;
	cursor: pointer;
	overflow: hidden;
	transition: color 0.4s var(--ease), border-color 0.4s var(--ease), transform 0.25s var(--ease);
}

/* Wipe fill on hover rather than a flat colour swap. */
.btn::after {
	content: "";
	position: absolute;
	inset: 0;
	background: var(--lime);
	transform: translateY(101%);
	transition: transform 0.45s var(--ease);
	z-index: -1;
}

.btn > * {
	position: relative;
	z-index: 1;
}

.btn:hover {
	color: var(--ink);
	border-color: var(--lime);
	transform: translateY(-2px);
}

.btn:hover::after {
	transform: none;
}

.btn .ico {
	inline-size: 17px;
	block-size: 17px;
	transition: transform 0.35s var(--ease);
}

.btn:hover .ico {
	transform: translateX(4px);
}

.btn--lime {
	background: var(--lime);
	border-color: var(--lime);
	color: var(--ink);
}

.btn--lime::after {
	background: var(--ink);
}

.btn--lime:hover {
	color: var(--white);
	border-color: var(--ink);
}

.btn--ghost {
	background: transparent;
	border-color: rgb(255 255 255 / 55%);
	color: var(--white);
}

.btn--ghost::after {
	background: var(--white);
}

.btn--ghost:hover {
	color: var(--ink);
	border-color: var(--white);
}

.btn--sm {
	padding: 0.65rem 1.3rem;
	font-size: 0.72rem;
}

/* ---------- header ----------
   A floating pill. The rail is the full-width sticky positioner; the pill inside it is
   what you see. Same treatment on every page, so no more white-on-white problem. */

.header-rail {
	position: sticky;
	inset: 0 0 auto;
	z-index: 60;
	padding: clamp(0.75rem, 1.5vw, 1.25rem) clamp(0.75rem, 3vw, 2rem);
	pointer-events: none;
}

.site-header {
	pointer-events: auto;
	width: min(100%, var(--wrap));
	margin-inline: auto;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: clamp(0.5rem, 1.5vw, 1.5rem);
	position: relative;
	padding: 0.5rem 0.5rem 0.5rem 1.25rem;
	color: var(--white);
}

/* The pill's surface lives on a pseudo-element, not on .site-header itself.
   backdrop-filter creates a containing block for position:fixed descendants — with it on
   the header, the villas panel anchored to the pill instead of the viewport and couldn't
   go full-bleed. Moving it here keeps the blur and frees the panel. */
.site-header::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	border-radius: 100px;
	background: rgb(23 41 31 / 90%);
	backdrop-filter: blur(14px);
	border: 1px solid rgb(255 255 255 / 10%);
	box-shadow: 0 10px 40px -12px rgb(23 41 31 / 45%);
	transition: background 0.4s var(--ease), box-shadow 0.4s var(--ease);
}

/* Pages that open with a hero: sit lightly over the image until you scroll. */
.has-hero .header-rail {
	position: fixed;
}

.has-hero .site-header::after {
	background: rgb(23 41 31 / 42%);
	box-shadow: none;
}

.has-hero .site-header.is-stuck::after {
	background: rgb(23 41 31 / 92%);
	box-shadow: 0 10px 40px -12px rgb(23 41 31 / 45%);
}

.brand {
	display: flex;
	align-items: center;
	flex: none;
	font-family: var(--serif);
	font-size: 1.05rem;
	letter-spacing: 0.12em;
	text-decoration: none;
	transition: opacity 0.3s;
}

.brand:hover {
	opacity: 0.75;
}

.brand img {
	height: 42px;
	width: auto;
}

.header-cta {
	flex: none;
}

.nav ul {
	display: flex;
	gap: clamp(0.9rem, 1.9vw, 2.1rem);
	margin: 0;
	padding: 0;
	list-style: none;
}

.nav a {
	position: relative;
	display: block;
	padding-block: 0.3rem;
	font-size: var(--fs-small);
	font-weight: 700;
	letter-spacing: 0.13em;
	text-transform: uppercase;
	text-decoration: none;
	opacity: 0.9;
	transition: opacity 0.25s;
}

/* Underline grows from the left instead of a hard text-decoration flick. */
.nav a::after {
	content: "";
	position: absolute;
	inset: auto 0 0 0;
	block-size: 1.5px;
	background: var(--lime);
	transform: scaleX(0);
	transform-origin: left;
	transition: transform 0.35s var(--ease);
}

.nav a:hover {
	opacity: 1;
}

.nav a:hover::after,
.nav .current-menu-item > a::after {
	transform: none;
}

/* ---------- villas dropdown ----------
   Replaces the old site's mega-menu, which was itself an Elementor build injected into
   every page twice. This is one panel, built from the villa post type, grouped by
   location and columned so 20 villas stay scannable. */

.nav li {
	position: relative;
}

.nav-chev {
	inline-size: 12px;
	block-size: 12px;
	rotate: 90deg;
	margin-inline-start: 0.3rem;
	transition: rotate 0.3s var(--ease);
}

.has-dropdown:hover .nav-chev,
.has-dropdown:focus-within .nav-chev {
	rotate: -90deg;
}

.has-dropdown > a {
	display: inline-flex;
	align-items: center;
}

/* Hover bridge — the gap between pill and panel shouldn't close the menu. */
.has-dropdown::after {
	content: "";
	position: absolute;
	inset: 100% 0 auto;
	block-size: 22px;
}

/* Full-bleed panel: anchored to the viewport, not the menu item, so all 20 villas fit
   across without scrolling. Fixed rather than absolute because the header pill is itself
   floating — anchoring to the item would drag the panel around with it. */
.submenu {
	position: fixed;
	inset: calc(var(--header-h, 84px) + 0.5rem) 1rem auto 1rem;
	z-index: 70;
	padding: 1.75rem 2rem 1.25rem;
	background: var(--cream);
	color: var(--ink);
	border-radius: 26px;
	box-shadow: 0 40px 90px -24px rgb(23 41 31 / 45%);
	border: 1px solid var(--line);
	/* Twenty large cards can run taller than the screen. Cap the panel to the viewport and
	   let it scroll inside its own rounded card rather than pushing the page down. */
	max-block-size: calc(100dvh - var(--header-h, 84px) - 1.5rem);
	overflow-y: auto;
	overscroll-behavior: contain;
	opacity: 0;
	visibility: hidden;
	transform: translateY(-10px);
	transition: opacity 0.3s var(--ease), transform 0.3s var(--ease), visibility 0.3s;
}

.has-dropdown:hover > .submenu,
.has-dropdown:focus-within > .submenu {
	opacity: 1;
	visibility: visible;
	transform: none;
}

/* Villa cards, image on top — one uniform grid across the full width. Five up on wide
   screens (20 villas = four clean rows), stepping down on narrower viewports. This is
   what lets the images read as cards rather than list thumbnails. */
.vgrid {
	display: grid;
	grid-template-columns: repeat(5, 1fr);
	gap: 1rem 1.1rem;
}

/* Hold five across as far down as it reads well (keeps 20 villas to four rows), then step
   down. */
@media (width <= 1180px) {
	.vgrid {
		grid-template-columns: repeat(4, 1fr);
	}
}

@media (width <= 900px) {
	.vgrid {
		grid-template-columns: repeat(3, 1fr);
	}
}

/* `.submenu .vcard` (not just `.vcard`) so it outweighs `.nav a`, which otherwise forces
   the card to display:block with uppercase/padding/reduced opacity meant for the top-nav
   links. */
.submenu .vcard {
	display: flex;
	flex-direction: column;
	padding: 0;
	opacity: 1;
	text-decoration: none;
	text-transform: none;
	color: var(--ink);
}

.vcard::after {
	display: none; /* no growing underline inside the panel */
}

/* The sand fill shows while the image lazy-loads (and permanently if a villa has no photo
   yet), so a card never collapses to nothing. */
.vcard__img {
	display: block;
	aspect-ratio: 16 / 10;
	border-radius: 13px;
	overflow: hidden;
	background: var(--sand);
}

.vcard__img img {
	inline-size: 100%;
	block-size: 100%;
	object-fit: cover;
	display: block;
	opacity: 0;
	transition: opacity 0.4s var(--ease), scale 0.5s var(--ease);
}

/* main.js adds .is-in once the deferred data-src has loaded. */
.vcard__img img.is-in {
	opacity: 1;
}

.vcard:hover .vcard__img img.is-in {
	scale: 1.06;
}

.vcard__nm {
	display: block; /* stack under the image even though `.nav a` blockifies the card */
	margin: 0.5rem 0 0.12rem;
	font-family: var(--serif);
	font-size: 1rem;
	font-weight: 400;
	line-height: 1.2;
	letter-spacing: 0;
	text-transform: none;
	color: var(--ink);
	transition: color 0.2s;
}

.vcard:hover .vcard__nm {
	color: var(--accent);
}

.vcard__cap {
	display: block;
	font-family: var(--sans);
	font-size: 0.62rem;
	font-weight: 700;
	letter-spacing: 0.09em;
	text-transform: uppercase;
	color: var(--muted);
	opacity: 1;
}

.submenu__foot {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
	margin-top: 1.25rem;
	padding-top: 1rem;
	border-top: 1px solid var(--line);
}

.submenu__foot a {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	font-family: var(--sans);
	font-size: 0.7rem;
	font-weight: 700;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--accent);
	text-decoration: none;
}

.submenu__foot a::after {
	display: none;
}

.submenu__foot a .ico {
	inline-size: 14px;
	block-size: 14px;
	transition: transform 0.3s var(--ease);
}

.submenu__foot a:hover .ico {
	transform: translateX(4px);
}

.submenu__foot span {
	font-size: 0.72rem;
	color: var(--muted);
}

/* ---------- mobile nav ---------- */

.nav-toggle {
	display: none;
	flex: none;
	inline-size: 40px;
	block-size: 40px;
	border: 0;
	border-radius: 50%;
	background: rgb(255 255 255 / 12%);
	cursor: pointer;
	position: relative;
}

.nav-toggle span {
	position: absolute;
	left: 50%;
	inline-size: 16px;
	block-size: 1.5px;
	background: #fff;
	translate: -50% 0;
	transition: rotate 0.3s var(--ease), top 0.3s var(--ease);
}

.nav-toggle span:first-child {
	top: 16px;
}

.nav-toggle span:last-child {
	top: 22px;
}

.nav-toggle[aria-expanded="true"] span:first-child {
	top: 19px;
	rotate: 45deg;
}

.nav-toggle[aria-expanded="true"] span:last-child {
	top: 19px;
	rotate: -45deg;
}

@media (width <= 1040px) {
	.nav {
		position: fixed;
		inset: 0;
		background: var(--ink);
		display: grid;
		place-items: start center;
		padding: 6rem 1.5rem 2rem;
		overflow-y: auto;
		transform: translateX(100%);
		transition: transform 0.5s var(--ease);
	}

	.nav[data-open="true"] {
		transform: none;
	}

	.nav > ul {
		flex-direction: column;
		text-align: center;
		gap: 1.1rem;
		width: 100%;
	}

	.nav > ul > li > a {
		font-size: 1.15rem;
		justify-content: center;
	}

	.nav-toggle {
		display: block;
		z-index: 70;
	}

	/* Panel becomes an inline, scrollable list rather than a floating card. */
	.submenu {
		position: static;
		translate: none;
		inline-size: 100%;
		max-block-size: 44vh;
		overflow-y: auto;
		opacity: 1;
		visibility: visible;
		transform: none;
		box-shadow: none;
		border: 0;
		background: rgb(255 255 255 / 6%);
		color: var(--white);
		margin-top: 0.75rem;
		padding: 1rem;
	}

	/* Inside the dark mobile drawer: two cards across, light text. */
	.vgrid {
		grid-template-columns: repeat(2, 1fr);
		gap: 0.85rem 0.75rem;
	}

	.vcard__nm {
		color: var(--white);
		font-size: 0.92rem;
	}

	.vcard:hover .vcard__nm {
		color: var(--lime);
	}

	.vcard__cap {
		color: rgb(255 255 255 / 70%);
	}

	.nav-chev {
		display: none;
	}

	.header-cta {
		display: none;
	}
}

/* ---------- filters ---------- */

.filters {
	display: grid;
	gap: 0.75rem;
	margin-bottom: 2.5rem;
}

.filters__row {
	display: flex;
	align-items: center;
	gap: 1rem;
	flex-wrap: wrap;
}

.filters__label {
	inline-size: 4.5rem;
	flex: none;
	font-size: 0.66rem;
	font-weight: 700;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var(--muted);
}

.filters__set {
	display: flex;
	gap: 0.4rem;
	flex-wrap: wrap;
}

.chip {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	padding: 0.5rem 1rem;
	border: 1px solid var(--line);
	border-radius: 100px;
	background: transparent;
	color: var(--ink);
	font: inherit;
	font-size: 0.8rem;
	font-weight: 600;
	cursor: pointer;
	transition: background 0.25s, border-color 0.25s, color 0.25s;
}

.chip span {
	font-size: 0.66rem;
	opacity: 0.5;
}

.chip:hover {
	border-color: var(--ink);
}

.chip.is-on {
	background: var(--ink);
	border-color: var(--ink);
	color: var(--white);
}

.chip.is-on span {
	opacity: 0.6;
}

.filters__empty {
	padding: 3rem 0;
	text-align: center;
	color: var(--muted);
}

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

.hero {
	position: relative;
	min-height: clamp(560px, 92vh, 950px);
	display: grid;
	align-items: center;
	color: var(--white);
	overflow: hidden;
	background: var(--ink);
}

.hero__media {
	position: absolute;
	inset: 0;
	overflow: hidden;
}

/* Slow push-in. The photography is the product — let it breathe rather than sit still. */
.hero__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	transform: scale(1.06);
	animation: kenburns 18s var(--ease) forwards;
}

@keyframes kenburns {
	to {
		transform: scale(1);
	}
}

.hero__media::after {
	content: "";
	position: absolute;
	inset: 0;
	background:
		linear-gradient(to bottom, rgb(23 41 31 / 25%) 0%, rgb(23 41 31 / 0%) 40%, rgb(23 41 31 / 70%) 100%),
		radial-gradient(120% 80% at 20% 60%, rgb(23 41 31 / 35%), transparent 60%);
}

.hero__inner {
	position: relative;
	padding-block: 9rem 5rem;
	z-index: 2;
}

.hero__tagline {
	display: inline-flex;
	align-items: center;
	gap: 0.6rem;
	font-family: var(--sans);
	font-size: var(--fs-small);
	font-weight: 700;
	letter-spacing: 0.28em;
	text-transform: uppercase;
	margin: 0 0 1.1rem;
	padding: 0.5rem 1.1rem;
	border: 1px solid rgb(255 255 255 / 30%);
	border-radius: 100px;
	backdrop-filter: blur(6px);
	background: rgb(255 255 255 / 8%);
}

.hero__tagline .ico {
	inline-size: 15px;
	block-size: 15px;
	color: var(--lime);
}

.hero__title {
	font-size: var(--fs-hero);
	text-wrap: balance;
	text-shadow: 0 4px 40px rgb(23 41 31 / 40%);
	max-width: 15ch;
}

.hero__title .roman {
	display: block;
}

.hero__title .name {
	font-style: italic;
	color: var(--lime);
}

.hero__cta {
	margin-top: 2.25rem;
	display: flex;
	gap: 0.75rem;
	flex-wrap: wrap;
}

/* Scroll cue */
.hero__cue {
	position: absolute;
	inset: auto 0 1.75rem 0;
	z-index: 2;
	display: grid;
	justify-items: center;
	gap: 0.5rem;
	font-size: 0.62rem;
	font-weight: 700;
	letter-spacing: 0.3em;
	text-transform: uppercase;
	opacity: 0.75;
}

.hero__cue::after {
	content: "";
	inline-size: 1px;
	block-size: 42px;
	background: linear-gradient(to bottom, var(--lime), transparent);
	animation: cue 2.2s ease-in-out infinite;
}

@keyframes cue {
	0%,
	100% {
		transform: scaleY(0.35);
		transform-origin: top;
	}

	50% {
		transform: scaleY(1);
		transform-origin: top;
	}
}

@media (width <= 700px) {
	.hero__cue {
		display: none;
	}
}

/* ---------- spec bar ----------
   The old villa pages never stated bedrooms or location anywhere on the page — only the
   nav menu knew. This renders straight from the fields, so it can't drift. */

.specbar {
	background: var(--ink);
	color: var(--white);
	position: relative;
}

.specbar ul {
	display: flex;
	flex-wrap: wrap;
	gap: clamp(1.25rem, 3vw, 3.5rem);
	align-items: center;
	margin: 0;
	padding: 1.75rem 0;
	list-style: none;
}

.specbar li {
	display: flex;
	align-items: center;
	gap: 0.85rem;
}

.specbar .ico {
	inline-size: 26px;
	block-size: 26px;
	color: var(--lime);
	flex: none;
}

.specbar .k {
	display: block;
	font-size: 0.63rem;
	font-weight: 700;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	opacity: 0.55;
}

.specbar .v {
	display: block;
	font-family: var(--serif);
	font-size: 1.35rem;
	line-height: 1.2;
}

.specbar .price {
	margin-inline-start: auto;
	padding-inline-end: 4.5rem;
}

.specbar .price .v {
	color: var(--lime);
}

@media (width <= 900px) {
	.specbar .price {
		margin-inline-start: 0;
		padding-inline-end: 0;
	}
}

/* ---------- prose ---------- */

.prose {
	max-width: 60ch;
	color: var(--ink-soft);
}

.prose p {
	margin: 0 0 1.15em;
}

.prose p:last-child {
	margin-bottom: 0;
}

/* Opening paragraph gets a lift — editorial rather than a wall of body copy. */
.prose--lead > p:first-of-type {
	font-family: var(--serif);
	font-size: clamp(1.2rem, 1.7vw, 1.55rem);
	line-height: 1.45;
	color: var(--ink);
}

/* ---------- layout ---------- */

.split {
	display: grid;
	gap: clamp(2rem, 5vw, 5rem);
	align-items: start;
	grid-template-columns: 1fr;
}

@media (width >= 900px) {
	.split {
		grid-template-columns: 1fr 1fr;
	}

	.split--narrow {
		grid-template-columns: 0.8fr 1fr;
	}

	.split--sticky > :first-child {
		position: sticky;
		top: 7rem;
	}
}

/* ---------- feature cards ---------- */

.cards {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 290px), 1fr));
	gap: var(--gap);
}

.card {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: 1rem;
	background: var(--cream);
	border: 1px solid var(--line);
	border-radius: var(--r-lg);
	padding: clamp(1.75rem, 3vw, 2.25rem);
	overflow: hidden;
	transition: transform 0.5s var(--ease), box-shadow 0.5s var(--ease), background 0.5s var(--ease);
}

/* First card is inverted — gives the row a focal point instead of three identical
   white rectangles. */
.card:first-child {
	background: var(--ink);
	color: var(--white);
	border-color: var(--ink);
}

.card:first-child p {
	color: rgb(255 255 255 / 70%);
}

.card:hover {
	transform: translateY(-8px);
	box-shadow: var(--shadow);
}

/* Icon in a disc, top of the card — not a watermark hiding in the corner. */
.card__ico {
	inline-size: 52px;
	block-size: 52px;
	padding: 13px;
	border-radius: 50%;
	background: var(--lime);
	color: var(--ink);
	flex: none;
	transition: rotate 0.5s var(--ease), scale 0.5s var(--ease);
}

.card:hover .card__ico {
	rotate: -8deg;
	scale: 1.06;
}

/* Big ghost numeral in the corner. */
.card__n {
	position: absolute;
	inset: auto 1.1rem 0.2rem auto;
	font-family: var(--serif);
	font-size: 5rem;
	line-height: 1;
	color: currentcolor;
	opacity: 0.07;
	pointer-events: none;
}

.card h3 {
	font-size: var(--fs-h3);
	margin: 0;
	position: relative;
}

.card p {
	margin: 0;
	color: var(--muted);
	font-size: 0.95rem;
	position: relative;
}

/* ---------- villa cards ---------- */

/* auto-fill, not auto-fit: with one villa in the grid, auto-fit collapses the empty
   tracks and stretches the single card to the full width — a 1280px-wide portrait card.
   auto-fill keeps the track size honest however many villas there are. */
.villa-grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(min(100%, 320px), 1fr));
	gap: clamp(1rem, 1.6vw, 1.5rem);
}

.villa-card {
	position: relative;
	display: block;
	overflow: hidden;
	border-radius: var(--r-lg);
	text-decoration: none;
	color: var(--white);
	aspect-ratio: 4 / 5;
	background: var(--ink);
	isolation: isolate;
}

.villa-card img {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform 1.1s var(--ease);
}

.villa-card:hover img {
	transform: scale(1.07);
}

.villa-card::after {
	content: "";
	position: absolute;
	inset: 0;
	background: linear-gradient(to top, rgb(23 41 31 / 88%) 0%, rgb(23 41 31 / 18%) 45%, transparent 70%);
	transition: opacity 0.5s;
}

.villa-card__body {
	position: absolute;
	inset: auto 0 0;
	z-index: 2;
	padding: 1.6rem;
}

.villa-card h3 {
	font-size: 1.6rem;
	margin-bottom: 0.4rem;
}

.villa-card .meta {
	display: flex;
	align-items: center;
	gap: 0.45rem;
	font-size: 0.75rem;
	font-weight: 700;
	letter-spacing: 0.13em;
	text-transform: uppercase;
	opacity: 0.85;
}

.villa-card .meta .ico {
	inline-size: 14px;
	block-size: 14px;
	color: var(--lime);
}

/* "View villa →" slides up on hover; hidden but present for keyboard users. */
.villa-card__go {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	margin-top: 0.9rem;
	font-size: 0.72rem;
	font-weight: 700;
	letter-spacing: 0.15em;
	text-transform: uppercase;
	color: var(--lime);
	opacity: 0;
	transform: translateY(10px);
	transition: opacity 0.45s var(--ease), transform 0.45s var(--ease);
}

.villa-card:hover .villa-card__go,
.villa-card:focus-visible .villa-card__go {
	opacity: 1;
	transform: none;
}

.villa-card__go .ico {
	inline-size: 15px;
	block-size: 15px;
}

/* Tag row, top-left: size first — it's what people filter on. */
.villa-card__tags {
	position: absolute;
	inset: 1rem auto auto 1rem;
	z-index: 2;
	display: flex;
	gap: 0.35rem;
	flex-wrap: wrap;
}

.villa-card__tag {
	padding: 0.34rem 0.8rem;
	border-radius: 100px;
	background: rgb(255 255 255 / 90%);
	color: var(--ink);
	font-size: 0.68rem;
	font-weight: 700;
	letter-spacing: 0.06em;
	backdrop-filter: blur(8px);
}

.villa-card__tag--price {
	background: var(--lime);
}

/* Make the first card in a grid span two columns on wide screens — breaks the monotony. */
@media (width >= 1100px) {
	.villa-grid--feature > .villa-card:first-child {
		grid-column: span 2;
		aspect-ratio: 16 / 11;
	}
}

/* ---------- amenities ---------- */

.amenities {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 230px), 1fr));
	/* Every row the same height as the tallest — otherwise a two-line label ("Bedroom and
	   laundry") makes its pill taller than its neighbours and the grid looks ragged. */
	grid-auto-rows: 1fr;
	gap: 0.6rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

.amenities li {
	display: flex;
	align-items: center;
	gap: 0.8rem;
	min-block-size: 3.4rem;
	padding: 0.6rem 1.15rem;
	background: var(--cream);
	border: 1px solid var(--line);
	border-radius: 100px;
	font-size: 0.9rem;
	line-height: 1.3;
	transition: border-color 0.35s, transform 0.35s var(--ease);
}

.amenities li:hover {
	border-color: var(--lime-deep);
	transform: translateY(-3px);
}

.amenities .ico {
	inline-size: 21px;
	block-size: 21px;
	color: var(--accent);
	flex: none;
}

/* Highlights — bigger, on the tinted panel */
.highlights {
	display: grid;
	gap: 0.6rem;
	margin: 2rem 0 0;
	padding: 0;
	list-style: none;
}

.highlights li {
	display: flex;
	align-items: center;
	gap: 0.9rem;
	font-family: var(--serif);
	font-size: 1.1rem;
}

.highlights .ico {
	inline-size: 34px;
	block-size: 34px;
	padding: 7px;
	border-radius: 50%;
	background: var(--lime);
	color: var(--ink);
	flex: none;
}

/* ---------- gallery ----------
   Mosaic rather than a uniform grid: the drone shots deserve to be big, the details
   can be small. */

.gallery {
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	gap: 0.6rem;
}

.gallery a {
	position: relative;
	display: block;
	overflow: hidden;
	border-radius: var(--r);
	aspect-ratio: 1;
	background: var(--sand);
}

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

.gallery a::after {
	content: "";
	position: absolute;
	inset: 0;
	background: rgb(23 41 31 / 0%);
	transition: background 0.4s;
}

.gallery a:hover img {
	transform: scale(1.06);
}

.gallery a:hover::after {
	background: rgb(23 41 31 / 18%);
}

/* Rhythm: first big, then a run of squares, then a wide one. */
.gallery a:nth-child(1) {
	grid-column: span 2;
	grid-row: span 2;
	aspect-ratio: auto;
}

.gallery a:nth-child(6) {
	grid-column: span 2;
	aspect-ratio: auto;
}

.gallery a:nth-child(11) {
	grid-column: span 2;
	grid-row: span 2;
	aspect-ratio: auto;
}

@media (width <= 800px) {
	.gallery {
		grid-template-columns: repeat(2, 1fr);
	}

	.gallery a:nth-child(1),
	.gallery a:nth-child(6),
	.gallery a:nth-child(11) {
		grid-column: span 2;
		grid-row: auto;
		aspect-ratio: 4 / 3;
	}
}

/* ---------- lightbox ---------- */

.lightbox {
	position: fixed;
	inset: 0;
	z-index: 200;
	display: grid;
	place-items: center;
	background: rgb(10 18 13 / 95%);
	opacity: 0;
	pointer-events: none;
	transition: opacity 0.35s;
	backdrop-filter: blur(4px);
}

.lightbox[data-open="true"] {
	opacity: 1;
	pointer-events: auto;
}

.lightbox img {
	max-width: 92vw;
	max-height: 86vh;
	border-radius: var(--r);
	box-shadow: var(--shadow);
}

.lightbox__close,
.lightbox__nav {
	position: absolute;
	background: rgb(255 255 255 / 10%);
	border: 1px solid rgb(255 255 255 / 25%);
	color: #fff;
	inline-size: 46px;
	block-size: 46px;
	border-radius: 50%;
	display: grid;
	place-items: center;
	cursor: pointer;
	transition: background 0.25s, transform 0.25s;
}

.lightbox__close:hover,
.lightbox__nav:hover {
	background: rgb(255 255 255 / 22%);
	transform: scale(1.08);
}

.lightbox__close {
	inset: 1.5rem 1.5rem auto auto;
	font-size: 1.2rem;
	line-height: 1;
}

.lightbox__nav--prev {
	inset: 50% auto auto 1.5rem;
	translate: 0 -50%;
}

.lightbox__nav--next {
	inset: 50% 1.5rem auto auto;
	translate: 0 -50%;
}

.lightbox__count {
	position: absolute;
	inset: auto 0 1.5rem 0;
	text-align: center;
	color: rgb(255 255 255 / 70%);
	font-size: 0.8rem;
	letter-spacing: 0.15em;
}

/* ---------- testimonials ----------
   A continuous drift rather than a slideshow with dots: the track is duplicated in JS and
   translated by -50%, so it loops with no jump and no library. Hover or focus pauses it,
   and it can be dragged. */

.testimonials {
	background: var(--sand);
	overflow: hidden;
}

.carousel {
	position: relative;
	margin-inline: calc(50% - 50vw);
	padding-inline: calc(50vw - 50%);
	overflow: hidden;
	/* Fade the runway in and out at the edges instead of a hard cut. */
	mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
}

.carousel__track {
	display: flex;
	gap: var(--gap);
	width: max-content;
	animation: drift var(--dur, 60s) linear infinite;
}

.carousel:hover .carousel__track,
.carousel:focus-within .carousel__track,
.carousel[data-paused="true"] .carousel__track {
	animation-play-state: paused;
}

@keyframes drift {
	to {
		transform: translateX(-50%);
	}
}

.carousel .quote {
	inline-size: clamp(300px, 30vw, 420px);
	flex: none;
}

/* Second row drifts the other way — two rows moving in opposite directions reads as
   deliberate; two rows moving together reads as a bug. */
.carousel--rev .carousel__track {
	animation-direction: reverse;
}

.carousel--villas {
	padding-block: 0.5rem;
}

.carousel--villas + .carousel--villas {
	margin-top: 0.75rem;
}

.carousel--villas .villa-card {
	inline-size: clamp(260px, 24vw, 330px);
	flex: none;
	aspect-ratio: 3 / 4;
}

.quote {
	position: relative;
	background: var(--cream);
	border-radius: var(--r-lg);
	padding: 2.25rem 1.85rem 1.5rem;
	display: flex;
	flex-direction: column;
	gap: 1.1rem;
	height: auto;
	border: 1px solid var(--line);
	overflow: hidden;
	transition: transform 0.5s var(--ease), box-shadow 0.5s var(--ease);
}

/* A big soft quote glyph bled off the top-right corner. Sets the card apart from the
   villa cards without another coloured strip. */
.quote::after {
	content: "\201C";
	position: absolute;
	inset: -2.5rem -0.5rem auto auto;
	font-family: var(--serif);
	font-size: 11rem;
	line-height: 1;
	color: var(--lime);
	opacity: 0.5;
	pointer-events: none;
}

/* Every third card inverts, so a drifting row has rhythm. */
.quote:nth-child(3n + 2) {
	background: var(--ink);
	border-color: var(--ink);
	color: var(--white);
}

.quote:nth-child(3n + 2) blockquote {
	color: rgb(255 255 255 / 88%);
}

.quote:nth-child(3n + 2) figcaption {
	border-color: rgb(255 255 255 / 15%);
}

.quote:nth-child(3n + 2)::after {
	opacity: 0.22;
}

.quote:nth-child(3n + 2) .quote__avatar {
	background: rgb(255 255 255 / 10%);
	color: var(--lime);
}

.quote:nth-child(3n + 2) .where {
	color: rgb(255 255 255 / 50%);
}

.quote:hover {
	transform: translateY(-8px);
	box-shadow: var(--shadow);
}

.quote__stars {
	display: flex;
	gap: 3px;
	color: var(--lime-deep);
	position: relative;
}

.quote__stars .ico {
	inline-size: 15px;
	block-size: 15px;
	fill: currentcolor;
	stroke: none;
}

.quote blockquote {
	margin: 0;
	font-family: var(--serif);
	font-size: 1.08rem;
	line-height: 1.5;
	color: var(--ink);
	position: relative;
}

.quote blockquote p {
	margin: 0;
	display: -webkit-box;
	-webkit-line-clamp: 6;
	-webkit-box-orient: vertical;
	overflow: hidden;
}

.quote figcaption {
	margin-top: auto;
	padding-top: 1.1rem;
	border-top: 1px solid var(--line);
	display: flex;
	align-items: center;
	gap: 0.8rem;
	position: relative;
}

/* No photo? Show their initial rather than a broken gap. */
.quote__avatar {
	inline-size: 44px;
	block-size: 44px;
	border-radius: 50%;
	flex: none;
	display: grid;
	place-items: center;
	background: var(--sand);
	color: var(--accent);
	font-family: var(--serif);
	font-size: 1.15rem;
	overflow: hidden;
}

.quote__avatar img {
	inline-size: 100%;
	block-size: 100%;
	object-fit: cover;
}

.quote .who {
	font-family: var(--serif);
	font-size: 1.05rem;
	line-height: 1.2;
}

.quote .where {
	font-size: 0.74rem;
	color: var(--muted);
	letter-spacing: 0.03em;
}

/* ---------- faq ----------
   Native <details>, so it opens with no JavaScript at all. */

/* Two columns on wide screens: 17 questions in one 900px column was a very long, very
   narrow ribbon in a 1320px container. */
.faq {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 420px), 1fr));
	gap: 0.5rem;
	align-items: start;
}

.faq__item {
	background: var(--cream);
	border: 1px solid var(--line);
	border-radius: var(--r);
	overflow: hidden;
	transition: border-color 0.3s;
}

.faq__item[open] {
	border-color: var(--lime-deep);
}

.faq__item summary {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
	min-block-size: 4rem;
	padding: 1rem 1.4rem;
	cursor: pointer;
	list-style: none;
	font-family: var(--serif);
	font-size: 1.05rem;
	line-height: 1.3;
	transition: color 0.25s;
}

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

.faq__item summary:hover {
	color: var(--accent);
}

.faq__chev {
	inline-size: 18px;
	block-size: 18px;
	flex: none;
	color: var(--lime-deep);
	rotate: 90deg;
	transition: rotate 0.3s var(--ease);
}

.faq__item[open] .faq__chev {
	rotate: -90deg;
}

.faq__body {
	padding: 0 1.4rem 1.3rem;
	color: var(--ink-soft);
	font-size: 0.94rem;
}

.faq__body p {
	margin: 0;
}

/* ---------- contact ---------- */

.contact-list {
	display: grid;
	gap: 1.25rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

.contact-list li {
	display: flex;
	align-items: center;
	gap: 1rem;
}

.contact-list .ico {
	inline-size: 40px;
	block-size: 40px;
	padding: 9px;
	border-radius: 50%;
	background: var(--sand);
	color: var(--accent);
	flex: none;
}

.contact-list .k {
	display: block;
	font-size: 0.66rem;
	font-weight: 700;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--muted);
}

.contact-list .v {
	font-family: var(--serif);
	font-size: 1.2rem;
	text-decoration: none;
	transition: color 0.25s;
}

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

.contact-form {
	background: var(--sand);
	border-radius: var(--r-lg);
	padding: clamp(1.5rem, 3vw, 2.5rem);
}

.contact-form label {
	display: block;
	font-size: 0.7rem;
	font-weight: 700;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--muted);
	margin-bottom: 0.4rem;
}

.contact-form input,
.contact-form textarea {
	inline-size: 100%;
	padding: 0.85rem 1rem;
	border: 1px solid var(--line);
	border-radius: 10px;
	background: var(--cream);
	font: inherit;
	font-size: 0.95rem;
	color: var(--ink);
}

.contact-form textarea {
	resize: vertical;
}

.contact-form input:focus-visible,
.contact-form textarea:focus-visible {
	outline: 2px solid var(--lime-deep);
	outline-offset: 1px;
}

/* ---------- band ---------- */

.band {
	position: relative;
	background: var(--ink);
	color: var(--white);
	text-align: center;
	overflow: hidden;
}

/* Soft lime glow so the closing CTA isn't a flat black slab. */
.band::before {
	content: "";
	position: absolute;
	inset: -40% 20% auto;
	block-size: 420px;
	background: radial-gradient(closest-side, rgb(198 214 123 / 22%), transparent);
	pointer-events: none;
}

.band .wrap {
	position: relative;
}

.band h2 {
	font-size: var(--fs-h2);
	margin-bottom: 1rem;
}

.band p {
	max-width: 50ch;
	margin-inline: auto;
	opacity: 0.75;
}

/* ---------- brochure ---------- */

.brochure {
	background: var(--lime);
	position: relative;
	overflow: hidden;
}

.brochure__inner {
	position: relative;
	display: grid;
	gap: var(--gap);
	align-items: center;
	grid-template-columns: 1fr;
}

@media (width >= 900px) {
	.brochure__inner {
		grid-template-columns: 1fr auto;
	}
}

.brochure form {
	display: flex;
	gap: 0.5rem;
	flex-wrap: wrap;
}

.brochure input {
	flex: 1 1 170px;
	padding: 1rem 1.2rem;
	border: 1px solid rgb(23 41 31 / 18%);
	border-radius: 100px;
	background: rgb(255 255 255 / 75%);
	font: inherit;
	font-size: 0.95rem;
}

.brochure input:focus-visible {
	outline: 2px solid var(--ink);
	outline-offset: 1px;
	background: #fff;
}

/* ---------- sticky booking bar ----------
   Appears once the hero is out of view. The old site had a modal instead; this asks for
   the booking when you've actually seen the villa. */

.bookbar {
	position: fixed;
	inset: auto 0 0 0;
	z-index: 55;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
	padding: 0.85rem clamp(1rem, 3vw, 2rem);
	background: rgb(23 41 31 / 92%);
	backdrop-filter: blur(10px);
	color: var(--white);
	transform: translateY(110%);
	transition: transform 0.5s var(--ease);
	border-top: 1px solid rgb(255 255 255 / 12%);
}

.bookbar[data-show="true"] {
	transform: none;
}

.bookbar__name {
	font-family: var(--serif);
	font-size: 1.1rem;
}

.bookbar__meta {
	font-size: 0.72rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	opacity: 0.6;
}

@media (width <= 600px) {
	.bookbar__meta {
		display: none;
	}
}

/* ---------- footer ---------- */

.site-footer {
	position: relative;
	background: var(--ink);
	color: var(--white);
	padding-block: var(--section) 2rem;
	overflow: hidden;
}

/* Same line art as the pale sections, flipped and barely there. */
.site-footer .wrap {
	position: relative;
}

.footer-lead {
	padding-bottom: 3rem;
	margin-bottom: 3rem;
	border-bottom: 1px solid rgb(255 255 255 / 12%);
}

.footer-lead__eyebrow {
	margin: 0 0 0.75rem;
	font-size: 0.68rem;
	font-weight: 700;
	letter-spacing: 0.24em;
	text-transform: uppercase;
	color: var(--lime);
}

.footer-lead__line {
	margin: 0 0 2rem;
	font-family: var(--serif);
	font-size: clamp(1.9rem, 4.5vw, 3.4rem);
	line-height: 1.1;
	letter-spacing: -0.02em;
	max-width: 16ch;
	text-wrap: balance;
}

.footer-lead__line em {
	font-style: italic;
	color: var(--lime);
}

.footer-grid {
	display: grid;
	gap: 2rem var(--gap);
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr));
}

.footer-grid h3 {
	font-family: var(--sans);
	font-size: 0.66rem;
	font-weight: 700;
	letter-spacing: 0.2em;
	text-transform: uppercase;
	color: rgb(255 255 255 / 45%);
	margin-bottom: 1.1rem;
}

.footer-grid ul {
	margin: 0;
	padding: 0;
	list-style: none;
	display: grid;
	gap: 0.15rem;
}

.footer-grid a,
.footer-where {
	display: flex;
	align-items: center;
	gap: 0.55rem;
	padding: 0.35rem 0;
	font-family: var(--serif);
	font-size: 1rem;
	text-decoration: none;
	color: rgb(255 255 255 / 80%);
	transition: color 0.25s, translate 0.25s var(--ease);
}

.footer-grid a:hover {
	color: var(--lime);
	translate: 3px 0;
}

.footer-grid .ico {
	inline-size: 15px;
	block-size: 15px;
	flex: none;
	opacity: 0.5;
}

.footer-where {
	color: rgb(255 255 255 / 50%);
}

.footer-count {
	margin-inline-start: auto;
	font-family: var(--sans);
	font-size: 0.66rem;
	font-weight: 700;
	color: rgb(255 255 255 / 35%);
}

.footer-bottom {
	margin-top: 3.5rem;
	padding-top: 1.5rem;
	border-top: 1px solid rgb(255 255 255 / 12%);
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
	flex-wrap: wrap;
	font-size: 0.76rem;
	letter-spacing: 0.04em;
	color: rgb(255 255 255 / 45%);
}

.footer-credit {
	display: inline-flex;
	align-items: center;
	gap: 0.32rem;
	text-decoration: none;
	color: rgb(255 255 255 / 45%);
	transition: color 0.25s;
}

.footer-credit:hover {
	color: var(--lime);
	text-decoration: none;
}

/* The heart keeps its own colour — an emoji inherits nothing, but it would still get
   dimmed by the link's opacity-ish grey, so give it a gentle beat instead. */
.footer-credit__heart {
	display: inline-block;
	font-size: 0.8rem;
	animation: heartbeat 2.6s var(--ease) infinite;
}

@keyframes heartbeat {
	0%,
	14%,
	100% {
		transform: scale(1);
	}

	7% {
		transform: scale(1.22);
	}
}

@media (prefers-reduced-motion: reduce) {
	.footer-credit__heart {
		animation: none;
	}
}

/* ---------- whatsapp ---------- */

.wa {
	position: fixed;
	inset: auto 1.5rem 1.5rem auto;
	z-index: 45;
	inline-size: 56px;
	block-size: 56px;
	border-radius: 50%;
	background: #25d366;
	display: grid;
	place-items: center;
	box-shadow: 0 8px 28px rgb(23 41 31 / 30%);
	transition: transform 0.3s var(--ease);
}

.wa::before {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: 50%;
	border: 2px solid #25d366;
	animation: ping 2.6s var(--ease) infinite;
}

@keyframes ping {
	0% {
		transform: scale(1);
		opacity: 0.7;
	}

	70%,
	100% {
		transform: scale(1.7);
		opacity: 0;
	}
}

.wa:hover {
	transform: scale(1.06);
}

/* Label slides out on hover so the button says what it does. */
.wa__tip {
	position: absolute;
	inset: 50% calc(100% + 10px) auto auto;
	translate: 0 -50%;
	padding: 0.5rem 0.9rem;
	border-radius: 100px;
	background: var(--ink);
	color: var(--white);
	font-size: 0.72rem;
	font-weight: 600;
	letter-spacing: 0.04em;
	white-space: nowrap;
	opacity: 0;
	transform: translateX(8px);
	pointer-events: none;
	transition: opacity 0.3s var(--ease), transform 0.3s var(--ease);
}

.wa:hover .wa__tip,
.wa:focus-visible .wa__tip {
	opacity: 1;
	transform: none;
}

@media (width <= 700px) {
	.wa__tip {
		display: none;
	}
}

.wa svg {
	inline-size: 30px;
	block-size: 30px;
	fill: #fff;
}

/* Lift above the booking bar when it's showing. */
.bookbar[data-show="true"] ~ .wa {
	transform: translateY(-4.25rem);
}

/* ---------- a11y ---------- */

.screen-reader-text {
	position: absolute;
	inline-size: 1px;
	block-size: 1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}

.skip {
	position: absolute;
	left: -9999px;
	top: 0;
	z-index: 100;
	background: var(--ink);
	color: var(--white);
	padding: 0.75rem 1.25rem;
}

.skip:focus {
	left: 0;
}

:where(a, button, input, [tabindex]):focus-visible {
	outline: 2px solid var(--lime-deep);
	outline-offset: 3px;
}

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

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

	.js [data-reveal] {
		opacity: 1;
		transform: none;
	}
}

/* ---------- villa finder ----------
   The quiz. One box, steps swapped in place. Everything is sized so the box doesn't
   jump between steps (JS pins the min-height once it starts). */

.finder {
	background: var(--ink);
	color: var(--white);
	overflow: hidden;
	position: relative;
}

.finder__box {
	position: relative;
	display: grid;
	place-items: center;
	text-align: center;
	min-block-size: 30rem;
}

.finder__step {
	grid-area: 1 / 1;
	inline-size: 100%;
	opacity: 0;
	visibility: hidden;
	transform: translateY(14px);
	transition: opacity 0.45s var(--ease), transform 0.45s var(--ease), visibility 0.45s;
	pointer-events: none;
}

.finder__step.is-on {
	opacity: 1;
	visibility: visible;
	transform: none;
	pointer-events: auto;
}

.finder .eyebrow {
	color: var(--lime);
	justify-content: center;
}

.finder__count {
	margin: 0 0 0.75rem;
	font-size: 0.66rem;
	font-weight: 700;
	letter-spacing: 0.22em;
	text-transform: uppercase;
	color: rgb(255 255 255 / 40%);
}

.finder__q {
	font-family: var(--serif);
	font-size: clamp(1.75rem, 4vw, 3rem);
	line-height: 1.1;
	letter-spacing: -0.02em;
	margin: 0 auto;
	max-inline-size: 18ch;
	text-wrap: balance;
}

.finder__sub {
	margin: 1rem auto 0;
	max-inline-size: 46ch;
	color: rgb(255 255 255 / 60%);
	font-size: 0.95rem;
}

.finder__actions {
	margin-top: 2rem;
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 1.25rem;
	flex-wrap: wrap;
}

.finder__skip {
	font-size: 0.85rem;
	color: rgb(255 255 255 / 55%);
	text-decoration: underline;
	text-underline-offset: 4px;
	transition: color 0.25s;
}

.finder__skip:hover {
	color: var(--lime);
}

/* ---------- options ---------- */

.finder__opts {
	margin: 2.25rem auto 0;
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 190px), 1fr));
	gap: 0.75rem;
	max-inline-size: 900px;
}

.opt {
	display: grid;
	gap: 0.3rem;
	padding: 1.5rem 1rem;
	border: 1px solid rgb(255 255 255 / 18%);
	border-radius: 18px;
	background: rgb(255 255 255 / 5%);
	color: inherit;
	font: inherit;
	cursor: pointer;
	transition: background 0.25s, border-color 0.25s, transform 0.25s var(--ease);
}

.opt:hover {
	background: rgb(255 255 255 / 10%);
	border-color: var(--lime);
	transform: translateY(-4px);
}

.opt.is-picked {
	background: var(--lime);
	border-color: var(--lime);
	color: var(--ink);
	transform: scale(0.97);
}

.opt__big {
	font-family: var(--serif);
	font-size: 1.9rem;
	line-height: 1;
}

.opt__t {
	font-family: var(--serif);
	font-size: 1.1rem;
}

.opt__sub {
	font-size: 0.72rem;
	letter-spacing: 0.04em;
	color: rgb(255 255 255 / 45%);
}

.opt.is-picked .opt__sub {
	color: rgb(23 41 31 / 60%);
}

/* ---------- loader ---------- */

.finder__spinner {
	display: flex;
	justify-content: center;
	gap: 8px;
	margin-bottom: 1.75rem;
}

.finder__spinner span {
	inline-size: 10px;
	block-size: 10px;
	border-radius: 50%;
	background: var(--lime);
	animation: bounce 1.1s var(--ease) infinite;
}

.finder__spinner span:nth-child(2) {
	animation-delay: 0.14s;
}

.finder__spinner span:nth-child(3) {
	animation-delay: 0.28s;
}

@keyframes bounce {
	0%, 60%, 100% {
		transform: translateY(0);
		opacity: 0.35;
	}

	30% {
		transform: translateY(-12px);
		opacity: 1;
	}
}

.finder__loadmsg {
	margin: 0;
	font-family: var(--serif);
	font-size: clamp(1.3rem, 2.4vw, 1.8rem);
}

/* ---------- results ---------- */

.finder__results {
	text-align: left;
}

.finder__resulthead {
	display: flex;
	align-items: flex-end;
	justify-content: space-between;
	gap: var(--gap);
	flex-wrap: wrap;
	margin-bottom: 2rem;
}

.finder__results .eyebrow {
	justify-content: flex-start;
}

.finder__results .finder__q {
	margin: 0;
	max-inline-size: none;
}

.finder__results .finder__sub {
	margin: 0.6rem 0 0;
}

.finder__results .villa-grid {
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
}

.finder__foot {
	margin: 2.25rem 0 0;
	display: flex;
	align-items: center;
	gap: 1.25rem;
	flex-wrap: wrap;
}

@media (width <= 640px) {
	.finder__resulthead {
		flex-direction: column;
		align-items: flex-start;
	}
}

/* ---------- filtering state ----------
   The filter itself is instant; the images are not. Promoting a card from lazy to eager
   still means a round trip, so without this the cards snap in as empty rectangles and the
   page reads as broken. Two parts: a shimmer per card until its own photo lands, and a
   grid-level spinner for the moment the whole set is in flight.

   Scoped to [data-villa-grid] — the filterable archive — on purpose. Only that grid's JS
   adds .is-loaded, so applying the opacity:0 rule globally would leave the homepage
   carousels, the finder results and the 404 cards permanently blank. */

[data-villa-grid] .villa-card {
	background: var(--ink);
}

/* Shimmer sits under the image and shows through until .is-loaded fades the photo in. */
[data-villa-grid] .villa-card::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 0;
	background: linear-gradient(
		100deg,
		rgb(255 255 255 / 0%) 30%,
		rgb(255 255 255 / 8%) 50%,
		rgb(255 255 255 / 0%) 70%
	);
	background-size: 220% 100%;
	animation: shimmer 1.3s linear infinite;
	opacity: 1;
	transition: opacity 0.4s var(--ease);
	pointer-events: none;
}

[data-villa-grid] .villa-card.is-loaded::before {
	opacity: 0;
	animation: none;
}

@keyframes shimmer {
	to {
		background-position: -220% 0;
	}
}

/* Deliberately NO opacity gate on the image.
   An earlier version faded the photo in from opacity:0 once JS added .is-loaded — which
   meant any image that never fired `load` (a 404, a stalled request, JS not running) left
   the card blank forever. The shimmer already sits *behind* the image, so the photo simply
   covers it as it paints. Slower to look at, impossible to get stuck. */

/* Grid-level loader — only rendered while images are actually in flight. */
[data-villa-grid] {
	position: relative;
}

.grid-loader {
	position: absolute;
	inset: 0;
	z-index: 5;
	display: grid;
	place-items: center;
	background: rgb(255 253 248 / 70%);
	backdrop-filter: blur(2px);
	opacity: 0;
	visibility: hidden;
	transition: opacity 0.25s, visibility 0.25s;
	border-radius: var(--r-lg);
}

[data-villa-grid].is-filtering .grid-loader {
	opacity: 1;
	visibility: visible;
}

.grid-loader__inner {
	display: flex;
	align-items: center;
	gap: 0.75rem;
	padding: 0.8rem 1.4rem;
	border-radius: 100px;
	background: var(--ink);
	color: var(--white);
	font-size: 0.82rem;
	font-weight: 600;
	letter-spacing: 0.04em;
	box-shadow: var(--shadow);
	position: sticky;
	top: 40vh;
}

.grid-loader__dots {
	display: flex;
	gap: 4px;
}

.grid-loader__dots span {
	inline-size: 6px;
	block-size: 6px;
	border-radius: 50%;
	background: var(--lime);
	animation: bounce 1.1s var(--ease) infinite;
}

.grid-loader__dots span:nth-child(2) {
	animation-delay: 0.14s;
}

.grid-loader__dots span:nth-child(3) {
	animation-delay: 0.28s;
}

/* Chips shouldn't look clickable while a filter is resolving. */
.filters.is-busy .chip {
	pointer-events: none;
	opacity: 0.55;
}

@media (prefers-reduced-motion: reduce) {
	[data-villa-grid] .villa-card::before {
		animation: none;
	}
}

/* ---------- ambient artwork ----------
   The wave drawing, sitting full-bleed behind a section. Static — an earlier version
   drifted on scroll and it read as jerky, so the scroll handler is gone entirely.
   Renders nothing at all if the file isn't present (see tbk_art_layer). */

.art-host {
	position: relative;
	overflow: hidden;
	isolation: isolate;
}

.art-host > * {
	position: relative;
	z-index: 1;
}

.art-layer {
	position: absolute;
	inset: 0;
	z-index: 0;
	display: block;
	background-image: var(--art);
	background-repeat: no-repeat;
	background-position: center;
	background-size: cover;
	pointer-events: none;
}

/* Black drawing on the pale surfaces. */
.art-layer--ink {
	opacity: 0.08;
}

/* White drawing on the dark surfaces. */
.art-layer--white {
	opacity: 0.1;
}

/* The footer fills completely — the drawing covers the whole panel rather than sitting
   as a strip along the bottom. */
.site-footer .art-layer {
	background-position: center;
	background-size: cover;
	opacity: 0.05;
}

/* ---------- partner link ----------
   Aimed at villa owners, not guests, so it stays quieter than Book Now — a text link in
   the pill rather than a second competing button. */

.header-partner {
	flex: none;
	font-size: var(--fs-small);
	font-weight: 700;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	text-decoration: none;
	white-space: nowrap;
	color: rgb(255 255 255 / 70%);
	transition: color 0.25s;
}

.header-partner:hover {
	color: var(--lime);
}

@media (width <= 1180px) {
	.header-partner {
		display: none; /* lives in the footer and the mobile menu instead */
	}
}
