/**
 * Husna Villas — home.css
 *
 * Home page only (front-page.php). Enqueued after main.css.
 *
 * Section rhythm: every section uses .wrap (main.css) for its inner width.
 * Below the hero/search, every section also uses .pad (main.css) for its
 * vertical padding — the same utility the villa detail page's .hv-
 * description/.hv-amenities already use, so this page shares one rhythm
 * with the rest of the site rather than inventing its own spacing scale.
 * Sections stay on --paper and are divided by a 1px --hair rule; .hv-
 * services is the one deliberate --bone shift, not a repeated alternation.
 *
 * Ported from reference/design/husna-villas-light.html, restructured
 * against reference/design/brochure-markup.html's rhythm and its
 * villa-head + two-col composition for the villa rows.
 *
 * @package HusnaVillas
 */

/* ==========================================================================
   1. Hero — reference/design/husna-hero-03-revised.html's <section class=
   "hero">, ported: cqw units → vw (no container context on the real page),
   the file's one @container(max-width:760px) → @media below. Its own <nav>
   is not here — header.php's .hv-header already does that job. Classes are
   .hv-hero__* rather than the reference's bare .nav/.stage/.h/etc., and it
   reuses .eyebrow/.btn/.btn-solid instead of introducing parallel .eb/.cta
   classes, since this theme already has both.
   ========================================================================== */

.hv-hero {
	position: relative;
	display: flex;
	flex-direction: column;
	color: var(--paper);
	/* min-height, not height, and unconditional — not dependent on the
	   flex content below actually filling the box. This is what stops the
	   section collapsing when no hero image is set, which is what used to
	   let .hv-search-section ride up underneath it and block clicks. */
	min-height: min(92vh, 860px);
}

/*
 * vh on a phone is the height with the browser chrome collapsed, so a
 * vh-based hero grows taller than the visible screen the moment the
 * address bar expands — the photo ends up looking twice as long as it
 * should. Fixed px sidesteps that below 900px; the 760px step matches the
 * reference's own single breakpoint, where the nav collapses to a burger
 * and the spec bar restacks.
 */
@media (max-width: 900px) {
	.hv-hero {
		min-height: 600px;
	}
}

@media (max-width: 760px) {
	.hv-hero {
		min-height: 700px;
	}
}

/*
 * THE PHONE HERO IS 83% OF THE SCREEN, AND svh IS WHY IT CAN BE.
 *
 * The note above says a vh-based hero grows taller than the visible screen the
 * moment the address bar expands, which is why every band from 900px down uses
 * fixed pixels. svh is the unit that did not exist when that was written: it is
 * the SMALL viewport height, measured with the browser chrome showing, so it
 * does not move when the chrome collapses. The failure the note describes
 * cannot happen with it.
 *
 * The vh line first is the fallback for anything without svh — the intended
 * size, with the old hazard, rather than a hero that collapses to its content.
 *
 * This makes the phone hero TALLER, and that is the point: the stage text and
 * spec bar are 451px at 390x844, so everything the rule adds above that goes
 * into the photograph and the spacing rather than into more content. At 390x844
 * the rule resolves to 700.5px against that 451px of content.
 *
 * 83 is an editorial choice, not a derived one — no measurement picks it. What
 * the arithmetic establishes is the one thing that has to hold: the rule is
 * still BINDING, 700px against 451px of content, so the box is set by this rule
 * rather than by whatever happens to be inside it. THAT is the invariant to
 * re-check when this figure next moves — a percentage that resolves below the
 * content height silently stops doing anything, and the hero looks unchanged
 * because the content is then setting the box.
 *
 * The verification browser has no address bar, so svh and vh agree there and the
 * figures above are the vh case. On a real phone svh is smaller by the height of
 * the chrome, which is the whole reason for the unit: the hero is 83% of what the
 * guest can actually see, not 83% of some larger figure.
 *
 * Confined to <=480px because the hero above that is min(92vh, 860px) and is not
 * changing — at 1366x768 that resolves to 706.56px while 83vh would be 637.44px,
 * so the two genuinely differ and the media query is the only thing keeping this
 * rule off desktop. It cannot be dropped on the grounds that the value looks
 * harmless above 480px.
 */
@media (max-width: 480px) {
	.hv-hero {
		min-height: 83vh;
		min-height: 83svh;
	}
}

.hv-hero__media {
	position: absolute;
	inset: 0;
}

/*
 * Darkest at the very top (behind the header) and the very bottom (behind
 * the stage text and spec bar), close to clear through the middle so the
 * photo itself still reads. From the reference design directly, not
 * re-tuned — its own five-stop gradient assumes a bright, fairly busy
 * frame the way the earlier three-zone version did.
 */
.hv-hero__scrim {
	position: absolute;
	inset: 0;
	background: linear-gradient(
		to bottom,
		rgba(11, 11, 11, .66) 0%,
		rgba(11, 11, 11, .12) 26%,
		rgba(11, 11, 11, .24) 46%,
		rgba(11, 11, 11, .82) 78%,
		rgba(11, 11, 11, .96) 100%
	);
	pointer-events: none;
}

/*
 * Horizontal inset is --wrap-pad, the same token the header and every
 * other section on the site uses — NOT a bare 4vw. 4vw is an unbounded
 * ramp: it matched nothing at any width and pulled further away the wider
 * the screen got, so the hero copy sat 8px right of the wordmark at 1400
 * and 50px right of it at 2560. One token means the wordmark, the hero
 * eyebrow, the hero title and the spec bar all share one left edge at
 * every viewport. Vertical padding is unchanged.
 */
.hv-hero__stage {
	position: relative;
	z-index: 3;
	flex: 1;
	display: flex;
	align-items: flex-end;
	padding: 0 var(--wrap-pad) 3vw;
}

/*
 * .hv-hero__stage bottom-aligns its content (base rule above) so it can
 * sit low over a tall photo with empty space above it. That assumption
 * breaks at 480px and under: the hero's own copy (eyebrow + 3-line title
 * + claim + button) is taller than .hv-hero's 460px min-height at this
 * width, so the box grows to fit it with no slack left over — the content
 * fills flush from the very top of .hv-hero__stage, landing directly
 * under the fixed transparent header instead of clear of it. Confirmed
 * via CDP: header renders 79px tall at this width, and without this
 * padding the eyebrow starts at y:8px, under it. padding-top reserves
 * that clearance directly, so the header still floats transparently over
 * the photo exactly as designed — only the hero's own text moves down to
 * stop colliding with it.
 *
 * !important, after two failed attempts at winning this on source order
 * alone: this file sets `padding` (the shorthand, which resets padding-top
 * too) on .hv-hero__stage at three different breakpoints — the unconditional
 * base rule above, this one, and another inside @media (max-width: 760px)
 * further down, added independently of this fix and also active at this
 * width. At equal specificity, whichever of those happens to sit last in
 * the file wins, regardless of which media query is narrower or was
 * clearly meant to be the more specific case — so this kept silently
 * losing no matter where in the file it was placed. !important makes the
 * win deterministic regardless of load order or any future breakpoint
 * added after it, matching the same reasoning already used for
 * .hv-hero__claim-second above and the datepick section of main.css.
 */
@media (max-width: 480px) {
	.hv-hero__stage {
		padding-top: 108px !important;
	}
}

.hv-hero__inner {
	width: 100%;
}

.hv-hero__stage .eyebrow {
	margin: 0 0 24px;
}

.hv-hero__title {
	font-weight: 200;
	letter-spacing: -.035em;
	line-height: .98;
	margin: 0;
	font-size: clamp(34px, 6vw, 92px);
	max-width: 15ch;
	overflow-wrap: break-word;
}

.hv-hero__claim {
	display: flex;
	align-items: flex-start;
	gap: 3vw;
	margin-top: 3.2vw;
	max-width: 62ch;
}

.hv-hero__claim-bar {
	width: 1px;
	background: var(--gold);
	align-self: stretch;
	flex: none;
}

/* A flex item's default min-width is auto, which for text content
   resolves to its unwrapped max-content width — without this, the claim
   text refuses to shrink below that width and overflows the page on
   narrow screens instead of wrapping. */
/*
 * ONE SLOT, TWO CLAIMS, ALTERNATING.
 *
 * Both lines are placed in the SAME grid cell, so the slot is always as tall
 * as the taller of them and the swap cannot move anything below it. That is a
 * structural guarantee rather than a tuned one: no height is measured, matched
 * or hardcoded, so the two can be reworded to different lengths and the hero
 * still will not jump.
 *
 * The hero carried both at once and was simply too much text at the moment a
 * guest is deciding whether to read on.
 */
.hv-hero__claim-body {
	min-width: 0;
	display: grid;
}

.hv-hero__claim-body > p {
	grid-area: 1 / 1;
}

/*
 * 12s round, so each line holds for a little over five seconds and crossfades
 * in under one. Long enough to finish a twelve-word sentence without hurrying;
 * short enough that a guest who scrolls at a normal pace still sees the second.
 *
 * Two keyframe sets rather than one with a delay: a negative delay would start
 * the second line mid-fade on the first paint, which reads as a flicker on
 * load rather than as an alternation.
 */
@keyframes hv-claim-first {
	0%, 43%  { opacity: 1; }
	50%, 93% { opacity: 0; }
	100%     { opacity: 1; }
}

@keyframes hv-claim-second {
	0%, 43%  { opacity: 0; }
	50%, 93% { opacity: 1; }
	100%     { opacity: 0; }
}

.hv-hero__claim-body > p:first-child {
	animation: hv-claim-first 12s ease-in-out infinite;
}

.hv-hero__claim-body > .hv-hero__claim-second {
	animation: hv-claim-second 12s ease-in-out infinite;
}

/*
 * NO MOTION, AND NO HALF-FADED LINE LEFT BEHIND. Turning the animation off
 * alone would leave the second line at its authored opacity of 1, stacked on
 * the first in the same cell — two sentences printed over each other. It is
 * removed from the flow instead, and the hero shows the first claim only.
 */
@media (prefers-reduced-motion: reduce) {
	.hv-hero__claim-body > p:first-child,
	.hv-hero__claim-body > .hv-hero__claim-second {
		animation: none;
	}

	.hv-hero__claim-second {
		display: none;
	}
}

.hv-hero__claim p {
	margin: 0;
	font-weight: 300;
	font-size: clamp(15px, 1.5vw, 20px);
	line-height: 1.55;
	color: var(--paper);
}

/*
 * THE SAME TREATMENT AS THE FIRST LINE, now that the two share a slot. It used
 * to be a smaller, dimmer second line UNDER the first, which is the right
 * treatment for a subordinate clause and the wrong one for a claim that takes
 * the primary position every twelve seconds — the slot would have changed size
 * and weight as it alternated.
 *
 * The margin-top went with it for the same reason: in a single grid cell it
 * would have offset the second line from the first by ten pixels, which is
 * exactly the layout shift this arrangement exists to prevent.
 */
.hv-hero__claim-second {
	color: var(--paper);
}

/*
 * ONE CHILD. `gap` and `flex-wrap` are gone with the second control — both
 * only ever described a relationship between two items, and a gap on a
 * one-child flex container is a rule that reads as intent and does nothing.
 */
.hv-hero__actions {
	display: flex;
	align-items: center;
	margin-top: 3vw;
}

/* The primary ask sits on a photograph, and .btn-solid's border is --ink
   against an --ink fill, so the button has no edge of its own — where the
   picture goes dark behind it, it loses its shape. A paper border draws
   that edge back without touching the fill or the label.

   Held through :hover as well. .btn-solid:hover swaps the fill to
   --gold-deep and takes its border with it; letting the border follow
   would make the outline appear and disappear against the photo as the
   pointer moves. The border stays paper so only the fill changes.

   Scoped to .hv-hero__actions: the same "Request these dates" button
   appears further down the page on --paper and on --bone, where it has a
   real edge already and a white border would be invisible or wrong. */
.hv-hero__actions .btn-solid,
.hv-hero__actions .btn-solid:hover {
	border-color: var(--paper);
}

/*
 * .hv-hero__secondary IS GONE. Every rule for it went with the markup rather
 * than being left to match nothing.
 *
 * It had three treatments in turn — a quiet text link below 760, then a second
 * bordered button sharing the row, then an underlined link at every width —
 * and the control was removed outright rather than given a fourth. The hero
 * makes one ask.
 */

.hv-hero__specbar {
	position: relative;
	z-index: 4;
	border-top: 1px solid var(--gold);
	/* --wrap-pad horizontally, matching .hv-hero__stage above and the
	   header — the spec bar's first item lines up under the hero title. */
	padding: 1.6vw var(--wrap-pad);
	display: flex;
	align-items: center;
	gap: 2.6vw;
	flex-wrap: wrap;
}

.hv-hero__spec {
	font-size: 10px;
	font-weight: 600;
	letter-spacing: .24em;
	text-transform: uppercase;
	color: var(--paper);
	white-space: nowrap;
}

.hv-hero__spec--gold {
	color: var(--gold);
}

.hv-hero__spec-sep {
	width: 1px;
	height: 12px;
	background: rgba(255, 255, 255, .28);
	flex: none;
}

.hv-hero__spec--last {
	margin-left: auto;
	color: var(--dim-2);
}

@media (max-width: 760px) {
	.hv-hero__stage {
		/* --wrap-pad, not a hardcoded 22px: they agree at 390px (the clamp
		   floor) but diverge toward this breakpoint, where 3.4vw is ~26px
		   and the header would sit 4px inside the hero copy. */
		padding: 0 var(--wrap-pad) 26px;
	}

	.hv-hero__title {
		font-size: 39px;
		max-width: none;
	}

	.hv-hero__claim {
		gap: 14px;
		margin-top: 24px;
	}

	.hv-hero__claim p {
		font-size: 15px;
	}

	/*
	 * THE BUTTON KEEPS ITS OWN WIDTH ON A PHONE — no width: 100% here.
	 *
	 * It used to be full width because it was the primary of a pair and needed
	 * to outweigh the second control. Alone, full width makes it a black slab
	 * across the photograph and the hero reads like a form to complete. At its
	 * measured 239px it sits at 69% of the 346px column, left-aligned with the
	 * headline and the claim bar above it, and the picture continues past it.
	 *
	 * Both were rendered and compared before choosing; the difference is only
	 * ever visible below 760, since above that the button was never stretched.
	 *
	 * The text-link demotion and the stacked-pair fallback that used to live
	 * here are both gone with the second control.
	 */

	.hv-hero__specbar {
		/* --wrap-pad, not 22px — same reason as .hv-hero__stage above: the
		   two agree at 390px but not at this breakpoint's own top end. */
		padding: 14px var(--wrap-pad);
		gap: 10px 14px;
	}

	.hv-hero__spec {
		font-size: 8.5px;
		letter-spacing: .2em;
	}

	.hv-hero__spec-sep {
		display: none;
	}

	/*
	 * THE THIRD LINE WAS `width: 100%`, NOT THE TYPE.
	 *
	 * This item's TEXT is 183px; the declaration forced its box to the full
	 * 346px, so it always claimed a line of its own and the five specs above it
	 * wrapped into two more. Measured: 51 + 71 + 55 + 83 + 82 = 342px of glyphs
	 * plus four 14px gaps = 398 against 346 available, so the five can never
	 * share one line — but they were never the problem.
	 *
	 * Flowing normally, the bar wraps where it should:
	 *
	 *   2 houses  11 bedrooms  22 guests  Halal kitchen        302 of 346
	 *   Private beach  4 night minimum · every season           279 of 346
	 *
	 * margin-left: 0 stays — `auto` would push this to the far right of its
	 * line and reopen the gap. Tracking and size are untouched: an earlier
	 * attempt halved the letter-spacing to buy 42px, which was a real style
	 * change bought against the wrong cause, and it still left three lines
	 * because it did not account for the gaps.
	 *
	 * padding-top went with it. It existed to hold this item clear of the row
	 * above while it was a full-width line of its own; sharing a line with
	 * "Private beach" it only pushed this one 2px lower than its neighbour —
	 * which is also what kept the check reporting three rows after the fix,
	 * since two items on one line no longer had the same top.
	 */
	.hv-hero__spec--last {
		margin-left: 0;
	}
}

/*
 * THE 360–760 ONE-ROW BAND IS GONE, and everything in it went with the second
 * control rather than being left to describe a row that no longer exists.
 *
 * It existed for exactly one job: fitting TWO controls on one line at 390. Every
 * declaration in it served that job and nothing else —
 *
 *   gap: 8px                 the space BETWEEN two items
 *   flex: 1 1 auto           how surplus was SHARED between them
 *   letter-spacing: .12em    a tracking override bought because the pair needed
 *                            101px it did not have at --ls-cta
 *   padding: 15px 10px       side padding cut for the same reason
 *   white-space: nowrap      stopping the squeezed pair from wrapping
 *   width: auto              undoing the full-width primary of the stacked pair
 *   the 360 floor            the width below which the PAIR stopped fitting
 *
 * With one control none of it does anything a reader could see, and the floor
 * measures a boundary that cannot be crossed. So the button goes back to the
 * site's own CTA treatment — --ls-cta at .22em and .btn's own 15px 32px — and
 * needs 239px of the 346px available at 390, which is 107px of room it did not
 * have when there were two of them.
 *
 * The tracking override is the one worth naming: it was bought at a real cost
 * to buy space, and with the space no longer needed the hero's button now
 * matches every other button on the site instead of being the one exception.
 */

/* ==========================================================================
   2. Search section
   ========================================================================== */

/*
 * Always hidden — the modal (opened via the hero's "Request these dates")
 * is the only search entry point now; this section is no longer a second,
 * visible bar. It stays in the DOM (not removed) because it's the form's
 * one permanent home: the inline script in front-page.php relocates this
 * exact section's children into the dialog's slot on open and back again
 * on close, so there's only ever one MPHB.SearchForm JS instance and one
 * set of datepicker state. Deleting the section outright would null out
 * that script's `section` variable and silently disable the whole modal
 * via its own guard clause.
 *
 * The <noscript> block next to this section in front-page.php unhides it
 * when JS never runs, so the hero button's #hv-search-section anchor
 * fallback still lands on a real, visible form in that case.
 */
.hv-search-section {
	display: none;
	border-bottom: 1px solid var(--hair);
	background: var(--paper);
	padding: 24px 0;
}

/*
 * MotoPress's own [mphb_availability_search] markup, restyled in place.
 * The shortcode wraps its own output in a div carrying the "hv-search"
 * class passed via the shortcode's class attribute — see front-page.php.
 * Structure: form > p.mphb_sc_search-{field} (one per visible field, plus
 * hidden inputs and a required-fields tip with no visual footprint of
 * their own) > label + input|select.
 */
.hv-search .mphb_sc_search-form {
	display: flex;
	flex-wrap: wrap;
	border-left: 1px solid var(--hair);
	border-right: 1px solid var(--hair);
}

.hv-search .mphb_sc_search-form > p {
	flex: 1 1 200px;
	margin: 0;
	padding: 18px 24px;
	border-right: 1px solid var(--hair);
	border-bottom: 1px solid var(--hair);
	text-align: left;
}

.hv-search .mphb_sc_search-form label {
	display: block;
	font-size: 9px;
	letter-spacing: .26em;
	text-transform: uppercase;
	color: var(--gold-deep);
	font-weight: 600;
	margin-bottom: 8px;
}

.hv-search .mphb_sc_search-form label abbr {
	text-decoration: none;
}

.hv-search .mphb_sc_search-form br {
	display: none;
}

/*
 * Left deliberately WITHOUT a :not() exclusion for the guests control.
 *
 * Excluding it here reads as the obvious fix, and it silently breaks the
 * submit button: `:not(X)` contributes X's own specificity, so
 * `… .mphb_sc_search-form input:not(.hv-guests__input)` is (0,3,1) and
 * outranks `.hv-search input[type="submit"]` at (0,2,1) — which had been
 * winning only on source order. The SEARCH button lost its ink fill and
 * rendered as bare text. Measured, not theorised.
 *
 * The guests control overrides what it needs further down instead, where
 * the override is visible next to the rest of that component.
 */
.hv-search .mphb_sc_search-form input,
.hv-search .mphb_sc_search-form select {
	width: 100%;
	background: none;
	border: 0;
	padding: 0;
	color: var(--ink);
	font-family: var(--ui);
	font-size: 14.5px;
	font-weight: 500;
}

.hv-search .mphb_sc_search-form select {
	appearance: none;
	-webkit-appearance: none;
	cursor: pointer;
}

/*
 * Guests, in the search form's palette. Geometry is the component's own and
 * is not touched here — only the border colour, which drops from --ink to
 * the form's own --hair so the control reads as one of these field cells
 * rather than as the booking panel's heavier boxed control. Exactly the
 * precedent already set for the villa panel, whose comment in main.css
 * notes that its palette differs while its geometry does not.
 *
 * MotoPress's own <label> is left alone: the form's label rule above
 * already styles it, and adding .hv-guests__label would centre it while
 * every other label in this form is left-aligned.
 */
.hv-search .hv-guests {
	margin-bottom: 0;
}

.hv-search .hv-guests__stepper {
	border-color: var(--hair);
	background: none;
}

.hv-search .hv-guests__val {
	border-left-color: var(--hair);
	border-right-color: var(--hair);
	min-height: 44px;
}

.hv-search .hv-guests__nav {
	min-height: 44px;
	width: 44px;
}

/* The typed field, back to its own width. The generic field rule above
   sets width:100% on every input in this form, which would stretch the
   number across the whole cell and push the dropdown off the end. */
.hv-search .mphb_sc_search-form .hv-guests__input {
	width: 3.5ch;
	font-size: var(--fs-body);
	font-weight: 400;
}

/* Required-fields tip (mphb_sc_search_render_form_top) — kept in the DOM,
   set on its own row above the fields (not treated as a field itself), as a
   quiet single line rather than a full field-sized cell. */
.hv-search .mphb-required-fields-tip {
	flex-basis: 100%;
	order: -1;
	border: 0;
	border-bottom: 1px solid var(--hair);
	padding: 8px 24px;
	text-align: right;
}

.hv-search .mphb-required-fields-tip small {
	font-size: 10px;
	color: var(--grey);
}

.hv-search .mphb_sc_search-submit-button-wrapper {
	flex: 0 0 auto;
	display: flex;
	border-right: 0;
	padding: 0;
}

.hv-search input[type="submit"] {
	flex: 1;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	padding: 0 40px;
	background: var(--ink);
	color: var(--paper);
	font-family: var(--ui);
	font-size: 10.5px;
	font-weight: 600;
	letter-spacing: .24em;
	text-transform: uppercase;
	border: 1px solid var(--ink);
	cursor: pointer;
	transition: background .25s, border-color .25s;
}

.hv-search input[type="submit"]:hover {
	background: var(--gold-deep);
	border-color: var(--gold-deep);
}

@media (max-width: 900px) {
	.hv-search .mphb_sc_search-form > p {
		flex-basis: 45%;
	}

	.hv-search .mphb_sc_search-submit-button-wrapper {
		flex-basis: 100%;
		order: 98;
		padding: 18px 0 0;
	}

	.hv-search input[type="submit"] {
		width: 100%;
		padding: 18px;
	}
}

/*
 * The hero's "Request these dates" button relocates the search form above
 * into this <dialog> and back again on close — see the inline script in
 * front-page.php right after the dialog's markup. Without JS, this
 * dialog is never shown — it starts with no "open" attribute at all — so
 * nothing here needs a fallback appearance of its own.
 *
 * ============================================================
 * DO NOT CHANGE "position: fixed" BELOW. THE DATEPICKER READS IT.
 * ============================================================
 *
 * This is not merely how the dialog is anchored. jquery.datepick walks
 * the check-in field's ancestors looking for a position: fixed one
 * (vendors/kbwood/datepick/jquery.datepick.js, _checkOffset). Finding
 * this rule, it renders its calendar popup position: fixed too and
 * subtracts the scroll position itself, so the popup lands correctly at
 * any scroll depth with no help from us.
 *
 * Change this to absolute (or relative, or static) and datepick stops
 * self-correcting — it will place the calendar in document coordinates
 * inside a viewport-anchored box, and the calendar will fly off-screen by
 * however far the page is scrolled. That is a real regression this file
 * has already shipped once, in the opposite direction: a scroll
 * compensation in front-page.php's inline script, written when this rule
 * WAS position: absolute and correct then, kept subtracting scrollY after
 * the rule became fixed. The calendar ended up 11,569px above the
 * viewport when the modal was opened from the closing band on a phone,
 * and every call-to-action below the fold opened a search no guest could
 * complete. The compensation is gone; this rule is now what makes the
 * calendar correct, so it is load-bearing.
 *
 * If this ever has to change, fix the calendar's placement in the same
 * commit and verify it from every opener at a real scroll position, not
 * only from the hero at the top of the page — the hero is at scrollY 0,
 * which is exactly why it looked healthy while everything else was broken.
 */
/*
 * Scoped to [open], not the bare class — an author-stylesheet rule on
 * .hv-search-dialog alone would apply regardless of the dialog's open
 * state, silently overriding the browser's own default
 * dialog:not([open]) { display: none } and leaving an empty card
 * rendered, full-viewport, on every single page load. Confirmed via CDP
 * on a fresh, untouched load: dialog.open was false, but computed
 * display was still "flex" and the card painted at the center of the
 * viewport. Scoping to [open] lets the UA default handle the closed
 * state again; nothing else here needs to change, since none of it is
 * reachable while the element isn't rendered at all.
 */
.hv-search-dialog[open] {
	position: fixed;
	inset: 0;
	margin: auto;
	width: 100%;
	height: 100%;
	max-width: none;
	border: 0;
	padding: clamp(16px, 4vw, 40px);
	background: transparent;
	display: flex;
	align-items: center;
	justify-content: center;
}

.hv-search-dialog::backdrop {
	background: rgba(11, 11, 11, .78);
}

/*
 * All the dialog's visual chrome lives here, not on the dialog itself —
 * ink/paper, a single gold hairline as the card's accent edge (the same
 * "one gold rule, used once per screen" the hero's spec bar and the
 * villa page's estate rule already use; the field dividers below stay
 * plain --hair, matching husna-villas-light.html's own .sf treatment,
 * not gold on every line), zero border-radius (sitewide reset).
 *
 * MUST NOT receive position: relative or position: absolute, ever, for
 * any future styling reason — the dialog above is the only positioned
 * element in this whole subtree on purpose (see its own comment). Adding
 * positioning here would become a second, off-origin containing block
 * and silently break the datepicker's calendar placement again.
 */
.hv-search-dialog__card {
	background: var(--paper);
	border-top: 1px solid var(--gold);
	width: 100%;
	max-width: min(640px, 92vw);
	max-height: 100%;
	overflow: auto;
}

.hv-search-dialog__close-row {
	display: flex;
	justify-content: flex-end;
}

.hv-search-dialog__close-form {
	margin: 0;
}

.hv-search-dialog__close {
	width: 44px;
	height: 44px;
	font-size: 22px;
	line-height: 1;
	color: var(--ink);
	background: none;
	border: 0;
	cursor: pointer;
}

.hv-search-dialog__close:hover {
	color: var(--gold-deep);
}

.hv-search-dialog__slot {
	padding: 0 clamp(20px, 4vw, 32px) clamp(24px, 4vw, 40px);
}

/* ==========================================================================
   THE SEARCH RESULTS PANEL — inside the modal, below the form

   A sibling of the slot, never inside it: the slot holds the search form
   NODE, which is relocated in and out of the dialog, and anything placed in
   its subtree travels out with it. See front-page.php.

   Bone against the card's paper, with the gold top rule the card itself
   uses, so the panel reads as a second surface rather than more form.
   ========================================================================== */

.hv-search-results {
	padding: clamp(20px, 3.4vw, 30px) clamp(20px, 4vw, 32px) clamp(24px, 4vw, 36px);
	background: var(--bone);
	border-top: 1px solid var(--hair);
}

.hv-search-results__head {
	font-family: var(--display);
	font-weight: var(--disp-w);
	letter-spacing: var(--disp-ls);
	line-height: 1.15;
	font-size: clamp(22px, 2.6vw, 30px);
	color: var(--ink);
	margin: 10px 0 0;
}

.hv-search-results__sub {
	font-size: var(--fs-ms);
	font-weight: 300;
	line-height: 1.7;
	color: var(--grey);
	margin: 10px 0 0;
}

.hv-search-results__list {
	list-style: none;
	margin: clamp(16px, 2vw, 22px) 0 0;
	padding: 0;
	border-top: 1px solid var(--hair);
}

/* Full-width row, because the whole row is the target — a name-sized hit
   area inside a modal on a phone is the difference between choosing a house
   and missing it. */
.hv-search-results__villa {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 14px;
	width: 100%;
	padding: 15px 0;
	text-align: left;
	border-bottom: 1px solid var(--hair);
	background: none;
	transition: color .2s, padding-left .2s;
}

.hv-search-results__villa:hover,
.hv-search-results__villa:focus-visible {
	color: var(--gold-deep);
	padding-left: 6px;
}

/* The villa name at body size, its tier label in the same small-caps pair
   the status tag and the specs line use — so the modal and the page it
   sends the guest to speak the same type. */
.hv-search-results__name {
	font-size: var(--fs-body);
	color: inherit;
}

.hv-search-results__tier {
	flex: none;
	font-size: var(--fs-xs);
	font-weight: 600;
	letter-spacing: var(--ls-eyebrow);
	text-transform: uppercase;
	color: var(--grey);
}

.hv-search-results__ask {
	margin-top: clamp(18px, 2.2vw, 24px);
}

@media (max-width: 600px) {
	.hv-search-results__ask {
		display: block;
		width: 100%;
		text-align: center;
	}
}

/*
 * Vertical, one field per row, full width — keyed off where the form
 * currently sits (a descendant selector), not a class toggled in JS. The
 * same DOM node picks up this layout automatically while it's inside the
 * dialog and drops it automatically once moved back inline, because it's
 * literally a different ancestor chain, not a flag someone has to
 * remember to add and remove in sync with every move.
 *
 * Field captions need no override here — .hv-search .mphb_sc_search-form
 * label below already matches husna-villas-light.html's .sf span
 * (uppercase, tracked, gold-deep) and isn't scoped to "inline only", so
 * it already follows the form wherever it's relocated.
 */
/*
 * .hv-search included in every selector below, not just .hv-search-dialog
 * — three classes' worth of specificity (0,3,0), deliberately higher
 * than the existing @media (max-width:900px) two-column rules above
 * (0,2,0), so this wins at every viewport width regardless of source
 * order in the file.
 */
/*
 * A wrapping ROW, not a column.
 *
 * This was flex-direction: column with flex-wrap: nowrap, which stacked
 * every field including the two dates. The dates now sit side by side, the
 * same way they do on the villa panel, so the container has to be a row
 * again — and every field that is NOT one of the pair takes an explicit
 * 100% basis to hold its own line. That is the same mechanism .hv-price-panel
 * uses (main.css, section 17b): row wrap, 100% on the children, and only
 * the date pair given a narrower basis.
 *
 * The old comment here warned that flex-wrap: wrap under flex-direction:
 * column spills fields sideways into a second column. True, and the reason
 * nowrap was there — but it only applies to a column container. Back on a
 * row, wrapping is what makes the pair drop to two lines when they genuinely
 * cannot fit.
 */
.hv-search-dialog .hv-search .mphb_sc_search-form {
	display: flex;
	flex-flow: row wrap;
	border-left: 0;
	border-right: 0;
}

.hv-search-dialog .hv-search .mphb_sc_search-form > p {
	flex: 0 0 100%;
	min-width: 0;
	border-right: 0;
}

/*
 * The date pair. A basis plus wrap rather than a rigid two-column grid: a
 * grid would hold two columns however long the formatted dates get, and
 * this has to survive a locale whose date strings are far longer than
 * "09/07/2026". Same reasoning, same 44%, as the villa panel.
 *
 * Narrower horizontal padding than the other cells, because at 390px each
 * of the pair is about half of a 274px column and the placeholder has to
 * fit inside it without clipping.
 */
/*
 * `> p.class`, not `.class`. The rule above it is
 * `… .mphb_sc_search-form > p` — (0,3,1), because of the type selector —
 * so a plain `… .mphb_sc_search-check-in-date` at (0,3,0) LOSES to it and
 * the pair silently keeps its 100% basis. Measured: both cells still
 * rendered 481px wide and stacked. Matching the type selector here is what
 * makes this win.
 */
.hv-search-dialog .hv-search .mphb_sc_search-form > p.mphb_sc_search-check-in-date,
.hv-search-dialog .hv-search .mphb_sc_search-form > p.mphb_sc_search-check-out-date {
	flex: 1 1 44%;
	padding-left: 14px;
	padding-right: 14px;
}

/* One hairline divides the pair. The outer edges stay open, like every
   other cell in this card. Only applied while they are actually side by
   side — once they wrap, a right-hand border would hang off a full-width
   cell. */
.hv-search-dialog .hv-search .mphb_sc_search-form > p.mphb_sc_search-check-in-date {
	border-right: 1px solid var(--hair);
}

/*
 * Narrow screens. The pair still sits side by side — that is the point of
 * the change — but at 390px each cell is only ~137px, and MotoPress's own
 * "Check-out Date" placeholder is the longest string either field ever
 * shows. It clipped mid-word at the padding the wider layout uses. Padding
 * comes in, and the value drops a step, so the placeholder fits inside the
 * cell rather than running under its edge.
 *
 * The placeholder is the worst case on purpose: once a date is chosen the
 * field shows "09/25/2026", which is far shorter. Sizing for the empty
 * state means the filled state can never clip either.
 */
@media (max-width: 480px) {
	.hv-search-dialog .hv-search .mphb_sc_search-form > p.mphb_sc_search-check-in-date,
	.hv-search-dialog .hv-search .mphb_sc_search-form > p.mphb_sc_search-check-out-date {
		padding-left: 10px;
		padding-right: 10px;
		/* A LENGTH basis below this width, not 44%. A percentage always
		   fits two abreast however narrow the card gets, so the pair never
		   wraps and the placeholder clips instead. 8.5rem is the point
		   below which they genuinely cannot both hold "Check-out Date":
		   measured, the pair sits side by side at 390px (117px of box for
		   104px of text) and wraps to one per row at 360px, where it would
		   otherwise have clipped. This is what "a flex row that wraps"
		   buys, and why the wrap is left to do its job. */
		flex: 1 1 8.5rem;
	}

	.hv-search-dialog .hv-search .mphb_sc_search-check-in-date input,
	.hv-search-dialog .hv-search .mphb_sc_search-check-out-date input {
		font-size: 13px;
	}
}

/* Once the pair has wrapped, the dividing hairline would hang off the
   right edge of a full-width cell. Matched to the wrap crossover above. */
@media (max-width: 374px) {
	.hv-search-dialog .hv-search .mphb_sc_search-form > p.mphb_sc_search-check-in-date {
		border-right: 0;
	}
}

.hv-search-dialog .hv-search .mphb_sc_search-submit-button-wrapper {
	flex: 0 0 100%;
	padding: 18px 0 0;
}

.hv-search-dialog .hv-search input[type="submit"] {
	width: 100%;
	padding: 18px;
}

/* ==========================================================================
   3. Statement (.hv-statement)
   The product's positioning line, once — reference/design/
   husna-hero-03-revised.html's section 02 (.stmt), added back in after
   initially being scoped out ("sections 02 through the footer" always
   included it). Centered, no photo, no CTA. Padding comes from .pad.
   ========================================================================== */

.hv-statement {
	border-bottom: 1px solid var(--hair);
	text-align: center;
}

.hv-statement__title {
	font-weight: 200;
	font-size: clamp(30px, 5.4vw, 72px);
	max-width: 22ch;
	margin: 14px auto 0;
}

.hv-statement__lead {
	font-size: clamp(15px, 1.5vw, 19px);
	color: var(--grey);
	max-width: 56ch;
	margin: 24px auto 0;
}

.hv-statement__rule {
	width: 60px;
	height: 1px;
	background: var(--gold);
	margin: clamp(34px, 4vw, 56px) auto 0;
}

/* ==========================================================================
   4. The equation (.hv-equation) — reference's section 03. Was
   .hv-two-houses, a side-by-side teaser of the two houses that never
   mentioned the estate; it is now Casa del Agua + Zacil Na = Puerto Estate,
   counts only. Renamed rather than extended because the old name described
   something that stopped being true, and the block had exactly two
   consumers (front-page.php and this file). --bone background, matching the
   reference's .sec.bone.
   ========================================================================== */

.hv-equation {
	background: var(--bone);
	border-bottom: 1px solid var(--hair);
}

/*
 * THE SEARCH VERDICT BLOCK — the failure case.
 *
 * First child of this section because #villas is where the search form
 * redirects, so a guest whose search found nothing lands directly on it.
 * Rendered by template-parts/home/no-availability.php as
 * .hv-verdict .hv-verdict--none.
 *
 * There was briefly a --free sibling here for the success case (a57cb51).
 * The results now appear inside the search modal instead, and a guest who
 * picks a house is navigated straight to that section, so the success case
 * needs nothing at this point in the page. The base/modifier split stays:
 * the modal's own failure panel is styled from the same type scale below,
 * and the naming keeps that relationship visible.
 *
 * PAPER, not bone. .hv-equation is itself --bone, so a bone panel would
 * dissolve into the section and the message would read as body copy rather
 * than as an answer to the search. The coloured left edge is the same
 * device the hero's claim block uses to mark a statement the house is
 * making.
 */
.hv-verdict {
	background: var(--paper);
	border: 1px solid var(--hair);
	border-left: 2px solid var(--gold);
	padding: clamp(24px, 3.4vw, 40px);
	margin-bottom: clamp(34px, 4.5vw, 56px);
}

.hv-verdict__title {
	font-size: clamp(1.5rem, 3vw, 2.25rem);
	max-width: 20ch;
	margin: 14px 0 0;
}

/* The reason line carries the actual answer, so it is the one thing here
   set at body size rather than note size — a guest who reads only one line
   after the headline must read this one. */
.hv-verdict__reason {
	font-size: var(--fs-body);
	font-weight: 400;
	color: var(--ink);
	margin: 16px 0 0;
}

.hv-verdict__body {
	font-size: var(--fs-ms);
	font-weight: 300;
	line-height: 1.75;
	color: var(--grey);
	max-width: 46ch;
	margin: 12px 0 0;
}

.hv-verdict .btn {
	margin-top: clamp(20px, 2.4vw, 28px);
}

@media (max-width: 600px) {
	.hv-verdict .btn {
		display: block;
		text-align: center;
	}
}

/* ==========================================================================
   THE STATUS TAG — one component, both verdicts

   "Available from {dates}" and "Too small for your party." are the same
   thing said two ways, and they used to get two different treatments in
   two different class families (.hv-villa-detail__status-price /
   -unavailable, .hv-band__status-price / -unavailable), both buried at the
   bottom of the copy panel. Now one tag, sitting above the villa's eyebrow
   where it is the first thing read.

   TOKENS, and why these ones.

   --fs-xs at weight 600 is this site's tracked-utility-label pair — what
   .eyebrow itself uses. The tag sits directly above the eyebrow and should
   read as the same rank of element, told apart by the fill rather than by
   size. Bigger or heavier would make it out-shout the villa name, which is
   the display face at weight 200; that is the exact bug being fixed here,
   so reintroducing it one line higher would be no improvement. 600 is
   already the heaviest weight on the site.

   --ls-label rather than --ls-eyebrow, and this was MEASURED, not chosen
   by eye. At 390px the copy column is 346px. The longest real string,
   "AVAILABLE FROM NOV 23 – NOV 27, 2026", renders 360px at --ls-eyebrow
   (.36em) and overflows by 14px; at --ls-label (.26em) it is 325px with
   21px to spare. The obvious "identical to the eyebrow" choice is the one
   that breaks. Widen this tracking again and the tag wraps on a phone.
   ========================================================================== */

/*
 * BLOCK, shrink-wrapped — not inline-block.
 *
 * .eyebrow is a <span>, so an inline-block tag flows onto the same line as
 * it whenever the column is wide enough. At 390px it never was and the tag
 * looked correct; at 1400px "AVAILABLE FROM NOV 23 – NOV 27, 2026" and
 * "PLACE OF LIGHT" sat side by side, touching. Every measurement passed
 * while that was true — one rendered line, inside the column, no page
 * overflow — because nothing about it is measurably wrong. It is wrong
 * only NEXT TO the eyebrow, and only a look at the screenshot found it.
 *
 * width:fit-content keeps the ink fill wrapped to the words rather than
 * stretched across the column, which is what display:block alone would do;
 * max-width:100% makes an unusually long string wrap inside the column
 * instead of pushing out of it.
 *
 * THE TOP MARGIN BELONGS TO THE TAG, not to the three places it appears.
 * At 390px the estate band's tag sat at exactly 0 from the top of the
 * photograph, flush against its edge, because that band has no padding-top
 * and its content is taller than its min-height there. Putting the space on
 * the component fixes all three sections at once and keeps them agreeing.
 *
 * The margin cannot escape and drag the section down with it: the tag's
 * container is a grid item (.hv-villa-detail__copy) in the house sections
 * and a flex item (.hv-band__inner) in the estate band, and both establish
 * an independent formatting context, so there is nothing for a first
 * child's top margin to collapse into. Verified by measuring the band's own
 * top edge before and after rather than trusting the rule.
 */
.hv-status-tag {
	display: block;
	width: fit-content;
	max-width: 100%;
	margin: clamp(18px, 2.4vw, 28px) 0 14px;
	padding: 7px 14px;
	background: var(--ink);
	color: var(--paper);
	font-size: var(--fs-xs);
	font-weight: 600;
	letter-spacing: var(--ls-label);
	line-height: 1.4;
	text-transform: uppercase;
}

/*
 * The estate band is a photograph under an ink scrim, so the default ink
 * fill would sink into it. Inverted rather than given its own rule set:
 * same size, same tracking, same weight, same padding — only the two
 * colours swap, which is what keeps the two sections' tags reading as one
 * component.
 */
.hv-status-tag--invert {
	background: var(--paper);
	color: var(--ink);
}

.hv-equation__title {
	font-size: clamp(1.75rem, 3.6vw, 2.75rem);
	max-width: 19ch;
	margin: 14px 0 0;
}

/*
 * Five cells: term, operator, term, operator, term. The operators are auto
 * width and the three terms share the rest equally — an equation whose two
 * operands and result carry the same weight, because that is what is being
 * claimed. The old vertical .hv-two-houses__seam is gone; the operators are
 * the separator now, and they mean something the hairline did not.
 */
.hv-equation__grid {
	display: grid;
	grid-template-columns: 1fr auto 1fr auto 1fr;
	align-items: start;
	gap: clamp(20px, 2.6vw, 40px);
	margin-top: clamp(34px, 4.5vw, 64px);
}

/* Centred against the whole term rather than against its first line, so the
   glyph sits with the photograph and not up beside the villa name.

   NOT --disp-w. Every other display element on this page is set at 200, and
   at that weight a "+" and an "=" render as hairlines — on the screenshot
   they were the faintest marks in the section despite being the one device
   the whole thing depends on. 400 is the lightest weight at which they read
   as operators rather than as stray rules. This is the exception that earns
   itself; the villa names beside them stay on the display weight. */
.hv-equation__op {
	align-self: center;
	text-align: center;
	font-family: var(--display);
	font-weight: 400;
	font-size: clamp(2rem, 3.4vw, 3rem);
	line-height: 1;
	color: var(--gold);
}

/* Name FIRST, then the photograph, then the counts — the reading order the
   diagram needs, and the reverse of the old teaser's photo-led order. */
.hv-equation__name {
	margin: 0;
	font-size: 1.6rem;
}

.hv-equation__photo {
	height: clamp(220px, 22vw, 320px);
	margin-top: clamp(14px, 1.6vw, 20px);
	background: var(--ink);
	overflow: hidden;
}

.hv-equation__photo img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.hv-equation__meta {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 0 10px;
	margin: 16px 0 0;
	padding-top: 14px;
	border-top: 1px solid var(--hair);
}

/* --fs-sm and --ls-nav are the tokens these two literals already equalled
   exactly (10px, .2em) — retired here as part of rewriting the block, so the
   change is provably no-op rather than a re-tuning smuggled in with it. */
.hv-equation__meta .spec {
	font-size: var(--fs-sm);
	font-weight: 600;
	letter-spacing: var(--ls-nav);
	text-transform: uppercase;
	color: var(--grey);
}

/* Drawn, not written into the markup, so the separator is not part of the
   accessible text — a screen reader reads three counts, not three counts
   and two middots. Gold ties it to the operators above. */
.hv-equation__meta .spec + .spec::before {
	content: "\00B7";
	margin-right: 10px;
	color: var(--gold);
}

/* Editors only — see the drift guard in front-page.php. Deliberately loud:
   it is reporting that the page is currently telling guests something
   arithmetically false, and it should not be mistakable for page copy. */
.hv-equation__drift {
	margin: clamp(24px, 3vw, 36px) 0 0;
	padding: 14px 18px;
	background: var(--paper);
	border-left: 2px solid var(--gold);
	font-size: var(--fs-ms);
	line-height: 1.7;
	color: var(--ink);
}

.hv-equation__drift strong {
	display: block;
	font-size: var(--fs-xs);
	font-weight: 600;
	letter-spacing: var(--ls-label);
	text-transform: uppercase;
	margin-bottom: 6px;
}

/*
 * MOBILE — the version that has to read well, since this is where the
 * diagram does its work.
 *
 * Source order is already term, op, term, op, term, so a single column puts
 * the + and = BETWEEN the blocks with no reordering and no grid-row
 * bookkeeping. The operators grow rather than shrink here: on one column
 * they are the only thing carrying the relationship, where on desktop the
 * side-by-side arrangement is already saying half of it.
 */
@media (max-width: 760px) {
	.hv-equation__grid {
		grid-template-columns: 1fr;
		gap: clamp(18px, 4vw, 28px);
	}

	.hv-equation__op {
		align-self: auto;
		font-size: 2.5rem;
	}
}

/* ==========================================================================
   5. Included (.hv-included) — reference's section 04, replacing the old
   "3. Value" services ledger. --ink background with 1px gaps between cells
   so --hair-dark shows through as grid lines, matching the reference's own
   bordered-grid treatment rather than a vertical list.
   ========================================================================== */

.hv-included {
	background: var(--ink);
	color: var(--paper);
}

.hv-included__title {
	font-size: clamp(1.75rem, 3.6vw, 2.75rem);
	max-width: 20ch;
	margin: 14px 0 0;
	color: var(--paper);
}

.hv-included__grid {
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	gap: 1px;
	background: var(--hair-dark);
	margin-top: clamp(34px, 4.5vw, 60px);
}

.hv-included__cell {
	background: var(--ink);
	padding: clamp(24px, 2.8vw, 38px) clamp(20px, 2.2vw, 30px);
}

.hv-included__num {
	font-family: var(--display);
	font-weight: 200;
	font-size: clamp(26px, 3.2vw, 42px);
	color: var(--gold);
}

.hv-included__cell h4 {
	font-family: var(--display);
	font-weight: var(--disp-w);
	font-size: 18px;
	margin: 14px 0 8px;
	color: var(--paper);
}

.hv-included__cell p {
	font-size: 13.5px;
	line-height: 1.7;
	color: var(--dim);
}

@media (max-width: 760px) {
	.hv-included__grid {
		grid-template-columns: 1fr 1fr;
	}
}

@media (max-width: 480px) {
	.hv-included__grid {
		grid-template-columns: 1fr;
	}
}

/* ==========================================================================
   6. Bands (.hv-band) — shared full-bleed photo component behind the
   Kitchen (05), Puerto Estate (08) and Closing (13) sections. One base
   rule + three modifiers, rather than three near-duplicate blocks — same
   bg-image/scrim/centered-content recipe .hv-hero already uses above.

   Mobile min-height is deliberately NOT uniform: --kitchen/--close keep
   ordinary flowed content with padding and cannot collapse, so they follow
   the reference's own mobile min-height:0 exactly. --estate is unchanged
   from the reference either way (a real 440px on mobile). Only .hv-hero
   itself ever needed a non-zero floor, because its content is bottom-
   aligned in a flex column over the same absolutely-positioned image
   pattern — a genuinely different layout, not the same rule repeated.
   ========================================================================== */

.hv-band {
	position: relative;
	overflow: hidden;
	display: flex;
	align-items: center;
	color: var(--paper);
	background: var(--ink);
	/*
	 * AN EMPTY IMAGE SLOT MUST NEVER COLLAPSE ITS SECTION.
	 *
	 * Every band today also sets its own taller min-height below
	 * (kitchen 600, estate 520, closing 540), so this floor changes nothing
	 * on the current page — which is exactly why it is worth stating. It is
	 * here for the band that gets added later without one, and for the case
	 * where a slot is emptied and the section has nothing but its own text
	 * holding it open. --ink underneath means an imageless band reads as a
	 * dark panel rather than as a seam between two sections.
	 */
	min-height: 320px;
}

.hv-band__media {
	position: absolute;
	inset: 0;
	/* Visible when a slot is empty: the band keeps a deliberate ground
	   rather than showing whatever is behind it. */
	background: var(--ink);
}

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

.hv-band__scrim {
	position: absolute;
	inset: 0;
	pointer-events: none;
}

.hv-band__inner {
	position: relative;
	z-index: 3;
	width: 100%;
}

.hv-band__title {
	font-size: clamp(1.75rem, 3.6vw, 2.75rem);
	margin: 14px 0 0;
	color: var(--paper);
}

.hv-band__lead {
	margin-top: clamp(16px, 2vw, 24px);
	max-width: 46ch;
	font-size: 1rem;
	color: var(--dim);
}

.hv-band__list {
	margin-top: clamp(20px, 2.6vw, 32px);
	max-width: 50ch;
}

.hv-band__list li {
	font-size: 14px;
	line-height: 1.7;
	color: var(--dim);
	padding: 10px 0;
	border-bottom: 1px solid var(--hair-dark);
}

.hv-band--kitchen {
	min-height: 600px;
	align-items: center;
}

.hv-band--kitchen .hv-band__scrim {
	background: linear-gradient(90deg, rgba(11, 11, 11, .82) 0%, rgba(11, 11, 11, .4) 60%, rgba(11, 11, 11, .15) 100%);
}

/*
 * padding-top is NOT redundant with .hv-status-tag's margin, and the reason
 * is the unsearched page: with no search there is no tag at all, and the
 * gold eyebrow becomes the first child and sits against the top edge on its
 * own. The band needs clearance that does not depend on a tag being there.
 */
.hv-band--estate {
	min-height: 520px;
	align-items: flex-end;
	padding-top: clamp(28px, 3.4vw, 48px);
	padding-bottom: clamp(40px, 5vw, 72px);
}

/*
 * THE SCRIM IS DARK AT BOTH ENDS, following .hv-hero__scrim above.
 *
 * It used to be `to top`: .9 at the bottom falling to .1 at the top. That is
 * upside down for this band, whose content is anchored to the BOTTOM but
 * overflows upward — at 390px the content is 557px tall against a 440px
 * min-height, so it fills the band and the eyebrow lands about 9% down,
 * where the old gradient was at .13. "Both houses, one party" in gold over
 * pale sky was close to unreadable, and adding padding could not fix it:
 * moving the eyebrow from 9% to 15% down took the scrim from .13 to .15,
 * which is a rounding error, not a fix.
 *
 * It is NOT a mobile-only defect. At 1400px the same eyebrow sits at .16.
 * That reads as acceptable only because the photograph happens to be darker
 * water there rather than sky, so the fix applies at every width.
 *
 * Still graduated, not a wash: it opens back to .30 through the middle,
 * where the photograph does its work. The .9 at the bottom is unchanged, so
 * the stats row and the button end exactly as before.
 *
 * These stops were measured, not eyeballed — sampled against the composited
 * pixels behind the eyebrow and checked as a contrast ratio, the same
 * standard the note above .hv-vhero__scrim in main.css sets. Re-measure
 * before softening any of them.
 */
.hv-band--estate .hv-band__scrim {
	background: linear-gradient(
		to bottom,
		rgba(11, 11, 11, .78) 0%,
		rgba(11, 11, 11, .55) 18%,
		rgba(11, 11, 11, .30) 42%,
		rgba(11, 11, 11, .62) 72%,
		rgba(11, 11, 11, .90) 100%
	);
}

.hv-band__row {
	display: flex;
	align-items: flex-end;
	justify-content: space-between;
	flex-wrap: wrap;
	gap: 20px;
	margin-top: clamp(26px, 3vw, 40px);
	padding-top: clamp(20px, 2.4vw, 28px);
	border-top: 1px solid var(--gold);
}

.hv-band__stats {
	display: flex;
	flex-wrap: wrap;
	gap: clamp(24px, 3.4vw, 52px);
}

.hv-band__stat-n {
	font-family: var(--display);
	font-weight: 200;
	font-size: clamp(24px, 3vw, 38px);
}

.hv-band__stat-l {
	font-size: 10px;
	font-weight: 600;
	letter-spacing: .2em;
	text-transform: uppercase;
	color: var(--dim);
	margin-top: 4px;
}

.hv-band__cta--wht {
	background: var(--paper);
	color: var(--ink);
	border-color: var(--paper);
}

.hv-band__cta--wht:hover {
	background: var(--gold-deep);
	color: var(--paper);
	border-color: var(--gold-deep);
}

.hv-band--close {
	min-height: 540px;
	justify-content: center;
	text-align: center;
}

.hv-band--close .hv-band__scrim {
	background: rgba(11, 11, 11, .72);
}

.hv-band--close .hv-band__lead {
	margin-left: auto;
	margin-right: auto;
}

/*
 * THE CLOSING BAND'S EYEBROW CANNOT SET ON ONE LINE ON A PHONE.
 *
 * "Fatima Bay · Riviera Maya · Husna since 2013" wants 390px. At a 390px
 * viewport .wrap gives 346px of measure, so it wraps — and left to itself it
 * broke after "Husna", which reads as a third place name in the list and
 * strands "since 2013" on a line of its own.
 *
 * So the break is made deliberate instead: below the breakpoint the last
 * segment becomes its own line and the separator before it is hidden, giving
 * two clean lines with no dangling separator. Line 1 is 225px and line 2 is
 * 147px, both comfortably inside the 346px measure.
 *
 * NEW CLASSES, not a change to .eyebrow — that class is used site-wide, and
 * this is a problem only this one string has.
 *
 * The type size is NOT reduced to force one line. An eyebrow already sets at
 * 9.5px; there is nothing below it that stays legible.
 *
 * There is no desktop rule. The spans are inline by default and that is the
 * desktop behaviour, so writing display: inline out would be a line that can
 * never do anything.
 */
/*
 * WHERE THE BOUNDARY IS, AND WHY IT IS NOT WHERE IT WAS MEASURED.
 *
 * The one-line string measures 390.06px, and .wrap gives the viewport minus
 * 44px, so the line stops fitting at exactly 435px: at 435 there are 391px of
 * measure and it sets on one line, at 434 there are 390 and it wraps. Both
 * measured at 1px steps, not derived.
 *
 * THE BOUND SHIPPED IS 479.98px, NOT 434.98px. At 435 the line fits with
 * 0.94px to spare, which is not a margin — a fallback font, different
 * rounding, or one more character in a translation puts it back into the bad
 * break with no lockup to catch it. 479.98 leaves 46px of slack at the first
 * width that sets on one line.
 *
 * The cost is that 435-479px takes the two-line lockup when one line would
 * just have fitted. That is a tidy deliberate two lines rather than a defect,
 * and no phone is in that band: 360, 375, 390, 393, 412, 414, 428 and 430 are
 * all below 435 and take the lockup either way.
 *
 * .98 and not a round number because max-width fires AT its value, and 435 —
 * the width the measurement calls good — must fall on the one-line side.
 */
@media (max-width: 479.98px) {
	/* inline-block so the block child below centres within the eyebrow rather
	   than filling the wrap. */
	.hv-band__eyebrow {
		display: inline-block;
	}

	.hv-band__eyebrow-sep {
		display: none;
	}

	.hv-band__eyebrow-since {
		display: block;
	}
}

.hv-band--close .hv-band__cta--wht {
	display: inline-flex;
	margin-top: clamp(28px, 3.4vw, 40px);
}

/*
 * The closing band now carries two actions: search, and ask a person. The
 * row centres to match .hv-band--close's centred text and wraps on narrow
 * screens rather than letting two uppercase buttons squeeze into one line.
 *
 * The margin moves onto the row so the two buttons share one top offset —
 * .hv-band--close .hv-band__cta--wht sets its own above, which would
 * otherwise push only the first of them down.
 */
.hv-band__actions {
	display: flex;
	flex-wrap: wrap;
	gap: 14px;
	align-items: center;
	margin-top: clamp(28px, 3.4vw, 40px);
}

.hv-band--close .hv-band__actions {
	justify-content: center;
}

.hv-band--close .hv-band__actions .hv-band__cta--wht {
	margin-top: 0;
}

/*
 * Secondary action on a dark band: outlined in white rather than filled, so
 * "Request these dates" stays the primary. White at full strength, not a
 * tint — the closing band's scrim is rgba(11,11,11,.72) over a photograph,
 * and a dimmed border disappears against the lighter parts of the image.
 */
.hv-band__cta--ghost {
	background: none;
	color: var(--paper);
	border-color: var(--paper);
}

.hv-band__cta--ghost:hover,
.hv-band__cta--ghost:focus-visible {
	background: var(--paper);
	color: var(--ink);
	border-color: var(--paper);
}

@media (max-width: 760px) {
	.hv-band--kitchen {
		min-height: 0;
		padding: 60px 0;
	}

	/*
	 * THE GRADIENT TURNS; IT IS NOT DARKENED.
	 *
	 * The 90deg version above is right for the layout it was written for: two
	 * columns, copy on the left over the .82 end, photograph breathing on the
	 * right at .15. At this width .hv-band__row becomes flex-direction: column
	 * and the copy spans the full width — measured, the h2 and the lead run
	 * 22 to 368 of 390 — so its right half sits over the transparent end and
	 * white text on a bright photograph is unreadable.
	 *
	 * Vertical instead, the same move .hv-band--estate already makes for the
	 * same reason. Every line of type then sits over the same alpha wherever it
	 * falls on the x-axis, so the fix is not sensitive to how long a sentence
	 * is. A heavier wash would have worked too and would have cost the
	 * photograph its light side for nothing.
	 */
	/*
	 * Alphas chosen by measurement, not by eye. At .72/.68/.74 the worst point
	 * across 189 samples was 4.77:1 — a pass, with 0.27 of margin over AA,
	 * which is thin enough that swapping the photograph could put it under
	 * without anyone noticing. These raise the floor while staying below the
	 * .82 the original gradient already used at its dark end, so this is not
	 * the heavy wash the fix was told to avoid.
	 */
	.hv-band--kitchen .hv-band__scrim {
		background: linear-gradient(
			to bottom,
			rgba(11, 11, 11, .80) 0%,
			rgba(11, 11, 11, .76) 45%,
			rgba(11, 11, 11, .82) 100%
		);
	}

	.hv-band--estate {
		min-height: 440px;
	}

	.hv-band__row {
		flex-direction: column;
		align-items: flex-start;
	}

	.hv-band--close {
		min-height: 0;
		padding: 60px 0;
	}
}

/* ==========================================================================
   7. Villa detail (.hv-villa-detail-section / .hv-villa-detail) —
   sections 06/07, replacing the old "5. Villa rows" (villa-row.php,
   deleted). A photo (+ 2-photo strip) beside a copy column with a bordered
   fact grid, rather than a head band above a full-width body — matches
   the reference's .house/.hcopy/.hfacts shape.
   ========================================================================== */

.hv-villa-detail-section {
	border-bottom: 1px solid var(--hair);
	/*
	 * NO scroll-margin-top HERE, AND THAT IS THE FIX RATHER THAN AN OMISSION.
	 *
	 * There was 100px, for a home page header that floated. It does not: the
	 * header computes position:absolute and scrolls away with the page, and
	 * enumerating every element on this page at 390 returns no fixed or
	 * sticky node at all. So the allowance compensated for nothing, and a
	 * click from the search modal landed each villa 100px down the viewport
	 * with the previous section still showing above it — 148px at 390 and
	 * 182px at 1366 once the section's own top padding is counted.
	 *
	 * Deleted rather than reduced. A number tuned to a header that no longer
	 * floats is a number that will be wrong again the next time the header
	 * changes; nothing on the page now needs an offset, so nothing states one.
	 * #villas lands on .hv-equation, which never had this and has always
	 * landed flush — the same behaviour all four anchors now share.
	 */
}

.hv-villa-detail-section--bone {
	background: var(--bone);
}

.hv-villa-detail {
	display: grid;
	grid-template-columns: 1.08fr .92fr;
	gap: clamp(30px, 5vw, 88px);
	align-items: center;
}

/* Same order:2 approach villa-row.php's own --reverse modifier used,
   rather than a direction:rtl trick — .hv-villa-detail__gallery is always
   first in the DOM (so its own markup never needs an index-dependent
   branch), and this reorders it visually only. */
.hv-villa-detail--flip .hv-villa-detail__gallery {
	order: 2;
}

.hv-villa-detail__shot {
	height: clamp(320px, 40vw, 580px);
	background: var(--ink);
	overflow: hidden;
}

.hv-villa-detail__shot img,
.hv-place__photo img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.hv-villa-detail__strip {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 1px;
	margin-top: 1px;
}

.hv-villa-detail__strip-item {
	height: clamp(110px, 13vw, 180px);
	background: var(--ink);
	overflow: hidden;
}

.hv-villa-detail__strip-item img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.hv-villa-detail__name {
	font-size: clamp(1.75rem, 3.6vw, 2.75rem);
	margin: 6px 0 0;
}

.hv-villa-detail__desc {
	color: var(--grey);
	font-size: .95rem;
	line-height: 1.75;
	margin-top: 16px;
	max-width: 50ch;
}

.hv-villa-detail__facts {
	display: grid;
	grid-template-columns: 1fr 1fr;
	margin-top: clamp(28px, 3.2vw, 40px);
	border-top: 1px solid var(--hair);
}

.hv-villa-detail__fact {
	display: flex;
	justify-content: space-between;
	gap: 12px;
	padding: 12px 0;
	border-bottom: 1px solid var(--hair);
}

.hv-villa-detail__fact:nth-child(odd) {
	padding-right: 20px;
	border-right: 1px solid var(--hair);
}

.hv-villa-detail__fact:nth-child(even) {
	padding-left: 20px;
}

.hv-villa-detail__fact-k {
	font-size: 10px;
	font-weight: 600;
	letter-spacing: .18em;
	text-transform: uppercase;
	color: var(--grey);
}

.hv-villa-detail__fact-v {
	font-size: 13.5px;
	color: var(--ink);
}

.hv-villa-detail__status {
	margin-top: clamp(20px, 2.4vw, 28px);
}

/*
 * Retokenised. Was 11px / .32em, and neither was a token: .32em is not in
 * the tracking set at all, and 11px is --fs-note, whose role is hints and
 * reassurance rather than tracked utility labels. Both were near enough to
 * a real token to read as deliberate, which is exactly what made them worth
 * finding. This is now the same pair .eyebrow uses, which is what a tracked
 * small-caps label on this site is.
 */
.hv-villa-detail__status-specs {
	font-size: var(--fs-xs);
	font-weight: 600;
	letter-spacing: var(--ls-eyebrow);
	text-transform: uppercase;
	color: var(--grey);
	margin: 0;
	/*
	 * The third segment grew from "4 Bedrooms" to "4 of 5 bedrooms open", and
	 * at 390 that wrapped to leave OPEN alone on a second line — measured, and
	 * the kind of thing that passes every check and still looks like a
	 * mistake. Balanced, the break lands after the second separator and the
	 * segment stays whole: "4 nights · 7 guests ·" / "4 of 5 bedrooms open".
	 *
	 * Where text-wrap is unsupported this falls back to that orphan rather
	 * than to anything broken, so it degrades to the state it improves on.
	 */
	text-wrap: balance;
}

/*
 * The line under the specs, answering "so who has the fifth bedroom?".
 *
 * THE SAME TREATMENT .villa-stats small ALREADY CARRIES for the same job on
 * the villa page — --fs-note, weight 300, no tracking, no uppercase, --grey.
 * That pairing (a tracked uppercase figure with a plain sentence beneath it)
 * is the pattern; repeating it here is what keeps the two surfaces reading as
 * one site rather than as two people's ideas of the same idea.
 */
.hv-villa-detail__status-note {
	font-size: var(--fs-note);
	font-weight: 300;
	letter-spacing: 0;
	text-transform: none;
	color: var(--grey);
	margin: 3px 0 0;
}

.hv-villa-detail__actions {
	display: flex;
	flex-wrap: wrap;
	gap: 14px;
	margin-top: clamp(28px, 3.2vw, 40px);
}

@media (max-width: 900px) {
	.hv-villa-detail {
		grid-template-columns: 1fr;
	}

	/* Same single-column reset villa-row.php's own --reverse modifier
	   used — photo always first, regardless of which villa this is. */
	.hv-villa-detail--flip .hv-villa-detail__gallery {
		order: 0;
	}
}

/* ==========================================================================
   8. The Place (.hv-place) — reference's section 09.
   ========================================================================== */

.hv-place {
	border-bottom: 1px solid var(--hair);
}

.hv-place__grid {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: clamp(30px, 5vw, 88px);
	align-items: center;
}

.hv-place__title {
	font-size: clamp(1.75rem, 3.6vw, 2.75rem);
	max-width: 16ch;
	margin: 14px 0 0;
}

.hv-place__lead {
	color: var(--grey);
	font-size: .95rem;
	line-height: 1.75;
	max-width: 42ch;
	margin-top: clamp(20px, 2.4vw, 28px);
}

.hv-place__list {
	margin-top: clamp(24px, 3.2vw, 40px);
}

.hv-place__list li {
	display: flex;
	justify-content: space-between;
	gap: 12px;
	padding: 12px 0;
	border-bottom: 1px solid var(--hair);
	font-size: 13.5px;
}

.hv-place__list-t {
	font-size: 10px;
	font-weight: 600;
	letter-spacing: .18em;
	text-transform: uppercase;
	color: var(--grey);
}

.hv-place__photo {
	height: clamp(320px, 40vw, 580px);
	background: var(--ink);
	overflow: hidden;
}

@media (max-width: 900px) {
	.hv-place__grid {
		grid-template-columns: 1fr;
	}
}

/* ==========================================================================
   8b. Rates (.hv-rates) — reference's section 10, ".sec.bone" + ".rates".

   Three cards in a 1px --hair grid, the last one inverted to --ink. The
   gap IS the rule: a 1px grid gap over a --hair background plus a --hair
   border draws every divider once, so no card carries its own border and
   the seams cannot double up where two cards meet. Same technique as the
   villa page's booking column seam.

   Card count is data-driven (a villa with no priced future night is
   dropped), so the grid is auto-fit rather than a fixed repeat(3) — two
   cards fill the row instead of leaving a hole.
   ========================================================================== */

.hv-rates {
	background: var(--bone);
	border-bottom: 1px solid var(--hair);
}

.hv-rates__title {
	font-size: var(--fs-disp-sm);
	max-width: 20ch;
	margin: 14px 0 0;
}

.hv-rates__lead {
	color: var(--grey);
	font-size: .95rem;
	line-height: 1.75;
	max-width: 52ch;
	margin-top: clamp(20px, 2.4vw, 28px);
}

.hv-rates__grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
	gap: 1px;
	background: var(--hair);
	border: 1px solid var(--hair);
	margin-top: clamp(34px, 4.5vw, 60px);
}

.hv-rates__card {
	background: var(--paper);
	padding: clamp(26px, 3vw, 40px);
	display: flex;
	flex-direction: column;
}

.hv-rates__card--feat {
	background: var(--ink);
	color: var(--paper);
}

.hv-rates__name {
	font-family: var(--display);
	font-size: clamp(20px, 2.4vw, 28px);
	font-weight: var(--disp-w);
	letter-spacing: var(--disp-ls);
	line-height: 1.1;
}

.hv-rates__spec {
	font-size: var(--fs-2xs);
	font-weight: 600;
	letter-spacing: var(--ls-label);
	text-transform: uppercase;
	color: var(--gold-deep);
	margin-top: 12px;
}

.hv-rates__card--feat .hv-rates__spec {
	color: var(--gold);
}

.hv-rates__rule {
	height: 1px;
	background: var(--hair);
	margin: 24px 0;
}

.hv-rates__card--feat .hv-rates__rule {
	background: var(--hair-dark);
}

.hv-rates__fig {
	font-family: var(--display);
	font-size: clamp(30px, 3.8vw, 48px);
	font-weight: var(--disp-w);
	letter-spacing: var(--disp-ls-lg);
	line-height: 1;
}

/* "From" rides the figure at label size rather than sitting on its own
   line: the number is a floor, and separating the two lets a skimming eye
   read the figure as a fixed price. */
.hv-rates__from {
	display: inline-block;
	font-family: var(--ui);
	font-size: var(--fs-2xs);
	font-weight: 600;
	letter-spacing: var(--ls-label);
	text-transform: uppercase;
	color: var(--grey);
	vertical-align: middle;
	margin-right: 10px;
}

.hv-rates__card--feat .hv-rates__from {
	color: var(--dim-2);
}

.hv-rates__figl {
	font-size: var(--fs-2xs);
	font-weight: 600;
	letter-spacing: var(--ls-nav);
	text-transform: uppercase;
	color: var(--grey);
	margin-top: 12px;
	line-height: 1.9;
}

.hv-rates__card--feat .hv-rates__figl {
	color: var(--dim-2);
}

.hv-rates__list {
	margin: 24px 0 0;
	padding: 0;
	list-style: none;
}

.hv-rates__list li {
	font-size: var(--fs-ms);
	font-weight: 300;
	color: var(--grey);
	padding: 8px 0 8px 22px;
	position: relative;
	line-height: 1.6;
}

.hv-rates__card--feat .hv-rates__list li {
	color: var(--dim);
}

.hv-rates__list li::before {
	content: "";
	position: absolute;
	left: 0;
	top: 17px;
	width: 10px;
	height: 1px;
	background: var(--gold);
}

.hv-rates__note {
	margin-top: 26px;
	font-size: 12.5px;
	font-weight: 300;
	color: var(--grey);
	max-width: 74ch;
}

.hv-rates__cta {
	margin-top: clamp(24px, 3vw, 36px);
}

/* ==========================================================================
   9. Steps (.hv-steps) — reference's section 11, "How it works".
   ========================================================================== */

.hv-steps {
	border-bottom: 1px solid var(--hair);
}

.hv-steps__title {
	font-size: clamp(1.6rem, 3.2vw, 2.4rem);
	max-width: 22ch;
	margin: 14px 0 0;
}

.hv-steps__grid {
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	gap: clamp(24px, 3.4vw, 56px);
	margin-top: clamp(34px, 4.5vw, 60px);
}

.hv-steps__num {
	font-family: var(--display);
	font-weight: 200;
	font-size: clamp(30px, 3.6vw, 46px);
	color: var(--gold-deep);
}

.hv-steps__rule {
	width: 32px;
	height: 1px;
	background: var(--gold);
	margin: 12px 0 18px;
}

.hv-steps__item h4 {
	font-family: var(--display);
	font-weight: var(--disp-w);
	font-size: 18px;
	margin-bottom: 8px;
}

.hv-steps__item p {
	font-size: 13.5px;
	line-height: 1.7;
	color: var(--grey);
}

/* The global reset zeroes every margin, so sibling paragraphs run together
   with no gap at all. Step 03 is the only step with two, and its second one
   carries the deposit terms, which must not read as part of the sentence
   above it. */
.hv-steps__item p + p {
	margin-top: 14px;
}

/* Four columns hold down to and including 1100px, measured against the real
   copy: at 1060px step 04's heading wraps. The floor is inclusive, hence
   1099.98 rather than 1100. Below it go straight to two, never three —
   three would leave the fourth step orphaned on a row of its own. */
@media (max-width: 1099.98px) {
	.hv-steps__grid {
		grid-template-columns: repeat(2, 1fr);
	}
}

@media (max-width: 760px) {
	.hv-steps__grid {
		grid-template-columns: 1fr;
	}
}

/* ==========================================================================
   10. FAQ (.hv-faq) — reference's section 12, "Before you ask".
   ========================================================================== */

.hv-faq {
	background: var(--ink);
	color: var(--paper);
}

.hv-faq__title {
	font-size: clamp(1.6rem, 3.2vw, 2.4rem);
	max-width: 16ch;
	margin: 14px 0 0;
	color: var(--paper);
}

/*
 * ONE column of questions and one of media, not two of questions plus a video.
 * Two reading columns beside a moving image is three things competing and the
 * moving one wins every time.
 *
 * The media track is a fixed 200px rather than a fraction: the video is a
 * phone held up, and a fraction would make it grow with the viewport until it
 * was demanding the screen instead.
 *
 * Column gap unchanged at clamp(30px, 5vw, 88px) — the same figure
 * .hv-place__grid and .hv-villa-detail already use, so the media column lands
 * on the rhythm every other two-column section on this page shares.
 */
.hv-faq__grid {
	display: grid;
	grid-template-columns: minmax(0, 1fr) 400px;
	gap: clamp(24px, 3.2vw, 40px) clamp(30px, 5vw, 88px);
	margin-top: clamp(30px, 4vw, 54px);
	align-items: start;
}

/*
 * The media column is FIRST in the DOM and moved right here, because on a
 * phone the video should come before the reading. Same order:2 approach
 * .hv-villa-detail--flip uses for its gallery rather than a direction:rtl
 * trick — see its comment above; the markup never needs a branch and this
 * reorders visually only.
 */
.hv-faq__media {
	order: 2;
}

/*
 * NO MEDIA COLUMN, NO TRACK FOR IT.
 *
 * The 400px track above is fixed, so with nothing in it the questions render
 * at 772px of a 1240px grid beside 400px of nothing. That is not theoretical:
 * it is what villa-site.husna.com does right now at 1366, because its FAQ
 * video option has never been set — measured, one grid child, columns still
 * "771.703px 400px".
 *
 * :has() rather than a modifier class written from PHP, because the condition
 * IS "did the media column render". A class would have to re-derive that from
 * the option AND from whether the viewer is an administrator (who gets the
 * note in that column), which is two copies of one fact waiting to disagree.
 * Asking the DOM cannot go out of step with the DOM.
 *
 * THE INVARIANT, not the conclusion. This rule is safe at ANY width, because
 * collapsing a two-column grid to one column can only ever give the questions
 * more room. That is a property of the rule itself and does not depend on where
 * it happens to fire.
 *
 * The previous comment here said "below 940 the grid is already 1fr, so this
 * only ever fires on desktop", which was a conclusion about where it runs
 * rather than about what it needs — and it was quietly read as covering the
 * pairing rule below too, which is NOT safe at any width and had no scope of
 * its own. See the note on that rule.
 */
.hv-faq__grid:not(:has(.hv-faq__media)) {
	grid-template-columns: minmax(0, 1fr);
}

/*
 * AND THE QUESTIONS PAIR UP TO USE IT. Collapsing the grid alone is not
 * enough: it hands the questions the full 1240px, and .hv-faq__item p is
 * capped at a readable measure (554px, for the reason recorded on that rule),
 * so every hairline rule then runs 686px past the end of its own answer.
 * Looked at rather than measured, that reads worse than the dead column it
 * replaced — the rules stop belonging to the text they sit above.
 *
 * Two columns of ~600px put the rule and the measure back within ~50px of
 * each other, which is the relationship the section has when the video is
 * there.
 *
 * THE INVARIANT THIS RULE DEPENDS ON, and why it carries its own query.
 *
 * Pairing the questions is only correct where the column is wide enough to
 * hold two readable measures. That is a condition about WIDTH, so it is stated
 * as a width — it cannot be inherited from the rule above, which is safe
 * everywhere for a different reason.
 *
 * It was written at top level and read as desktop-only because the comment on
 * the rule above said so. It is not: with the video unset it fired at every
 * width, and at 390 it produced two 158px columns — answers a third of the
 * width of the phone, three rows of them. Measured by removing the media
 * column, which is exactly what the PHP guard does when the option is empty,
 * rather than reasoned about from the selector.
 *
 * 940 is the same boundary the grid collapses at, so the questions pair up
 * exactly where there are two columns' worth of room and never below it.
 */
@media (min-width: 940px) {
	.hv-faq__grid:not(:has(.hv-faq__media)) .hv-faq__questions {
		display: grid;
		grid-template-columns: repeat(2, minmax(0, 1fr));
		column-gap: clamp(30px, 5vw, 88px);
		align-items: start;
	}
}

/*
 * The administrator-only note that stands in for a video nobody has chosen —
 * husnavillas_render_faq_video_note(). It carries .hv-faq__media as well, so
 * it takes that column and the grid keeps the shape it has when the video is
 * set; the questions do not jump width under an editor and read as a second
 * fault.
 *
 * Dashed, not solid, and gold rather than paper: it has to be legible without
 * ever being mistaken for something a guest is meant to see. A guest never
 * does — the PHP returns before printing any of this unless the viewer can
 * manage_options — but the treatment is the second signal, for the editor who
 * needs to know at a glance which of the two of them this is addressed to.
 */
.hv-editor-note {
	border: 1px dashed var(--gold);
	padding: 20px;
	color: var(--paper);
}

.hv-editor-note__head {
	font-family: var(--ui);
	font-size: var(--fs-2xs);
	font-weight: 600;
	letter-spacing: var(--ls-label);
	text-transform: uppercase;
	color: var(--gold);
	margin: 0 0 10px;
}

.hv-editor-note__body {
	font-size: var(--fs-ms);
	margin: 0 0 10px;
}

.hv-editor-note__body a {
	color: var(--gold);
	text-decoration: underline;
	text-underline-offset: 3px;
}

.hv-editor-note__foot {
	font-size: var(--fs-note);
	color: var(--dim);
	margin: 14px 0 0;
}

.hv-faq__video-box {
	position: relative;
	width: 400px;
	aspect-ratio: 9 / 16;
	overflow: hidden;
	/* Behind the video while the poster decodes, and behind the letterboxing
	   if a replacement file is ever not exactly 9:16. */
	background: #000;
}

.hv-faq__video {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/*
 * The unmute control. Over the video rather than under it, so it reads as
 * belonging to the video and not to the credit lines below — but on a solid
 * ink chip, not a hover-revealed overlay, because a hover affordance does not
 * exist on the phone this is mostly seen on.
 *
 * 44px is the minimum touch target, the same figure the guests dropdown was
 * corrected to. The chip is smaller than that visually; the padding carries
 * the rest.
 */
.hv-faq__sound {
	position: absolute;
	right: 8px;
	/* Top right, clear of the native controls the browser paints along the
	   bottom edge. Same 8px inset it had at the bottom. */
	top: 8px;
	/* Above the video's own control strip, which the UA paints in the
	   element's own stacking context. */
	z-index: 2;
	min-width: 44px;
	min-height: 44px;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	padding: 0 12px;
	border: 1px solid rgba(255, 255, 255, .34);
	border-radius: 0;
	background: rgba(11, 11, 11, .74);
	color: var(--paper);
	font-family: var(--ui);
	font-size: var(--fs-3xs);
	font-weight: 600;
	letter-spacing: var(--ls-label);
	text-transform: uppercase;
	cursor: pointer;
}

.hv-faq__sound:hover,
.hv-faq__sound:focus-visible {
	background: var(--ink);
	border-color: var(--gold);
	color: var(--gold);
}

/*
 * The credit lines, in the section's own utility-label treatment.
 *
 * --ls-label (.26em), NOT --ls-eyebrow (.36em). Not a taste call: the status
 * tag's own comment in this file records the measurement that settled it —
 * .36em overflowed a 346px column by 14px. This column is 200px and these
 * strings are longer, so .36em would be worse still.
 */
.hv-faq__credit {
	margin-top: 14px;
	font-size: var(--fs-xs);
	font-weight: 600;
	letter-spacing: var(--ls-label);
	line-height: 1.7;
	text-transform: uppercase;
	color: var(--gold);
}

.hv-faq__credit--us {
	margin-top: 8px;
	/* Quieter than the guest's credit. Whose film it is matters more than
	   whose account it is; ours is a footnote to theirs. */
	color: var(--dim);
}

.hv-faq__credit a {
	color: inherit;
	text-decoration: none;
	border-bottom: 1px solid rgba(202, 170, 97, .42);
}

.hv-faq__credit a:hover,
.hv-faq__credit a:focus-visible {
	color: var(--gold);
	border-bottom-color: var(--gold);
}

.hv-faq__item {
	padding: 18px 0;
	border-top: 1px solid var(--hair-dark);
}

.hv-faq__item h4 {
	font-family: var(--display);
	font-weight: var(--disp-w);
	font-size: 16px;
	margin-bottom: 8px;
	color: var(--paper);
}

.hv-faq__item p {
	font-size: 13.5px;
	line-height: 1.7;
	color: var(--dim);
	/*
	 * THE MEASURE, capped because the single question column is wide enough to
	 * ruin it. Going from two columns to one took the answer box from ~576px
	 * to 970px at 1400px, and the longest answer then set as ONE line of 137
	 * characters — roughly double a readable measure, and about what it was
	 * before is what this restores.
	 *
	 * Every structural check still passed while this was wrong: six items, one
	 * column, correct order. It is only visible by reading the rendered page,
	 * which is why the screenshot is not optional.
	 *
	 * The questions themselves need no cap — none is long enough to reach it.
	 */
	max-width: 62ch;
}

/*
 * STACKS AT 940px, NOT 760px — the video doubling to 400px moved this floor.
 *
 * Measured against the real content: at 940px the questions column is 414px,
 * still wider than the video beside it; at 920px it is 396px and the reading
 * column is narrower than the media, which reads as a thin ribbon of text
 * pinned beside a large video. Nothing overflowed and no heading wrapped at
 * any width down to 761 — the first floor check said "holds" all the way
 * down, because it was measuring overflow rather than proportion.
 *
 * 940 is the last GOOD width, so the query must not fire at it: 939.98px.
 */
@media (max-width: 939.98px) {
	.hv-faq__grid {
		grid-template-columns: 1fr;
	}

	/*
	 * VIDEO FIRST — ABOVE THE HEADING, NOT JUST ABOVE THE QUESTIONS.
	 *
	 * Someone who has scrolled this far on a phone should meet the proof
	 * before the reading, and then the heading introduces the questions,
	 * which is what it is for.
	 *
	 * WHY THIS NEEDS display: contents AND NOT JUST order. The heading pair
	 * are children of .wrap; the video is a GRANDCHILD, inside this grid.
	 * `order` only sorts siblings, so no combination of order values on the
	 * video can lift it past a heading in a different parent — measured on
	 * the rendered page, not assumed: eyebrow depth 2, media depth 3,
	 * siblings false.
	 *
	 * So the grid box is dissolved here rather than any node being moved.
	 * display: contents stops it generating a box, its two children become
	 * flex items of .wrap, and all four are then siblings for layout.
	 *
	 * The accessibility objection to display: contents is that it drops the
	 * element from the accessibility tree. That matters for anything
	 * carrying semantics; .hv-faq__grid is a presentational div with no
	 * role, so there is nothing to lose. Argued rather than assumed.
	 *
	 * And it degrades to TODAY's layout, not a broken one: without support
	 * the grid stays a grid, these order values still sort its two children,
	 * and the section renders exactly as it did before.
	 *
	 * A dissolved box contributes no margin, gap or padding, so the grid's
	 * own margin-top and its 24px row gap are reapplied as margins below.
	 */
	.hv-faq .wrap {
		display: flex;
		flex-direction: column;
	}

	.hv-faq__grid {
		display: contents;
	}

	.hv-faq__media {
		order: 1;
		/* Stands in for the grid's margin-top, which no longer applies. */
		margin-bottom: clamp(30px, 4vw, 54px);
	}

	/* The eyebrow is an inline span; as a flex item it would stretch to the
	   full column. align-self keeps its own 136px box, so the change is a
	   reorder and not also a resize. */
	.hv-faq .eyebrow {
		order: 2;
		align-self: flex-start;
	}

	.hv-faq__title {
		order: 3;
	}

	.hv-faq__questions {
		order: 4;
		/* Stands in for the grid's row gap, which no longer applies. */
		margin-top: clamp(30px, 4vw, 54px);
	}

	/* Doubled to 380px like the desktop box, but capped at the column: the
	   content column is 346px at 390px, so an uncapped 380 would overflow the
	   page. In practice this is 1.8x on a phone rather than 2x. */
	.hv-faq__video-box {
		width: min(380px, 100%);
		margin: 0 auto;
	}

	.hv-faq__credit {
		text-align: center;
	}
}
