/* The hero, on every page that has one.
 *
 * This lived in seven places: inline in index.html, sell.html, press.html,
 * properties.html, sold.html and the area-guide master, and in about.css.
 * Four of the six pinned copies were identical; the other two and the
 * homepage differed, so the same component looked slightly different
 * depending which page you were on. One definition now.
 *
 * TWO FAMILIES, and the difference is real rather than drift:
 *
 *   SCROLLS (the base rules below) — the homepage. The photo is in flow and
 *   moves up with the page. Larger type, and it is the family that carries
 *   the listing slideshow and the search bar.
 *
 *   PINNED ([data-hero-motion="pinned"]) — every other page. The photo is
 *   fixed and the page slides over it, the copy travelling up and fading as
 *   it goes. Smaller type, and a scroll cue at the foot.
 *
 * The attribute is emitted whenever the motion resolves to pinned, not only
 * when an owner has changed it — unlike data-section and data-header, where
 * absence means "the default". Two families genuinely exist here, and the
 * base had to be one of them.
 *
 * FRAMING is a setting, not a constant. --hero-focus and its two breakpoint
 * siblings are written as inline custom properties by hero_section_html();
 * the cascade below means a page that sets only the first gets that value at
 * every width, which is what the homepage has always done. The defaults are
 * the values four of the six pages already used.
 */

/* ══ Base: the hero that scrolls away ═════════════════════════════════════ */

.hero-section { margin: 0; padding: 0; overflow-x: hidden; }

.hero-bleed {
	position: relative;
	width: 100vw;
	left: 50%;
	right: 50%;
	margin-left: -50vw;
	margin-right: -50vw;
	height: 100vh;
	height: 100svh;
	/* --preview-vh is the dashboard's simulated viewport. The area guides
	   omitted it, which is why their hero mis-sized in the split preview. */
	height: var(--preview-vh, 100svh);
	min-height: 480px;
	overflow: hidden;
	background: #000;
}

.hero-bleed img,
.hero-bleed .hero-video {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: center var(--hero-focus, 55%);
}

/* 55/50/45 is what four of the six heroes already used, so it is the default
   and those four set nothing. The two that differ — About frames on the entry
   steps, Properties higher still — set all three, and the homepage sets only
   the middle one, because it has never had a 900px rule of its own. */
@media (max-width: 900px) {
	.hero-bleed img,
	.hero-bleed .hero-video { object-position: center var(--hero-focus-md, 50%); }
}
@media (max-width: 600px) {
	.hero-bleed { min-height: 420px; }
	.hero-bleed img,
	.hero-bleed .hero-video { object-position: center var(--hero-focus-sm, 45%); }
}

/* Listing slideshow. Every slide is stacked in the same place and cross-fades
   on .on; the layer itself fades in once the first photo has decoded, so the
   rotation never starts on a half-painted image. A long fade: this is a
   scenery change, not a cut. */
.hero-slides { position: absolute; inset: 0; opacity: 0; transition: opacity 1.2s ease; }
.hero-slides.on { opacity: 1; }
.hero-slides img { opacity: 0; transition: opacity 1.6s ease; }
.hero-slides img.on { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
	.hero-slides, .hero-slides img { transition: none; }
}

.hero-bleed::after {
	content: '';
	position: absolute;
	inset: 0;
	background: linear-gradient(to bottom, rgba(0,0,0,.4), rgba(0,0,0,.15) 40%, rgba(0,0,0,.45));
}

.hero-text {
	position: absolute;
	inset: 0;
	z-index: 1;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	text-align: center;
	padding: 0 1rem;
	/* The photo shows through; anything interactive opts back in. */
	pointer-events: none;
}

.hero-heading { margin: 0; font-family: var(--serif); font-size: clamp(32px,6.5vw,72px); font-weight: 300; letter-spacing: .04em; line-height: 1.05; color: #fff; text-shadow: 0 2px 14px rgba(0,0,0,.5); }
.hero-tagline { margin: .9em 0 0; font-size: clamp(14px,1.8vw,20px); font-weight: 300; letter-spacing: .14em; text-transform: uppercase; color: #fff; text-shadow: 0 2px 10px rgba(0,0,0,.5); }
/* A tagline that is a full SENTENCE rather than a short label. The base rule
   is uppercase and widely letterspaced, which is unreadable at sentence
   length — /properties/ has carried this modifier since it gained one. */
.hero-tagline--sentence { max-width: 34em; margin-inline: auto; letter-spacing: .02em; text-transform: none; line-height: 1.5; }

.hero-cta { pointer-events: auto; display: inline-block; margin-top: 1.6rem; padding: .85rem 2.6rem; border: 1.5px solid #fff; color: #fff; text-decoration: none; font-size: .72rem; letter-spacing: .2em; text-transform: uppercase; transition: .2s; }
.hero-cta:hover { background: #fff; color: #1c1c1c; }

/* ══ Hero search ══════════════════════════════════════════════════════════ */

.hsearch { pointer-events: auto; position: relative; width: min(620px,92vw); margin: 2.4rem auto 0; text-align: left; }
.hsearch-bar { display: flex; align-items: center; gap: .6rem; background: rgba(255,255,255,.97); border-radius: 2px; padding: .35rem .35rem .35rem 1rem; box-shadow: 0 12px 40px rgba(0,0,0,.28); }
.hsearch-icon { width: 19px; height: 19px; flex: none; color: #6b6b6b; }
.hsearch input { flex: 1; min-width: 0; border: none; background: none; font-family: var(--sans); font-size: .94rem; font-weight: 300; color: #1c1c1c; padding: .75rem 0; letter-spacing: .01em; cursor: pointer; }
.hsearch input::placeholder { color: #6f6c66; opacity: 1; }
.hsearch input:focus { outline: none; }
.hsearch-bar:focus-within { box-shadow: 0 12px 40px rgba(0,0,0,.28), 0 0 0 2px #1c1c1c; }
/* Safari paints its own clear button on type=search; ours is a plain field. */
.hsearch input::-webkit-search-decoration,
.hsearch input::-webkit-search-cancel-button { -webkit-appearance: none; }
.hsearch-go { flex: none; border: none; cursor: pointer; background: #1c1c1c; color: #fff; padding: .78rem 1.5rem; font-family: var(--sans); font-size: .66rem; letter-spacing: .18em; text-transform: uppercase; transition: background .2s; }
.hsearch-go:hover { background: #3a3a3a; }

/* No result styles here. This bar used to render its own inline dropdown,
   which meant two search UIs to keep in step — and they drifted. The bar is
   purely a trigger now; results are the overlay's job (.so-* in
   property.css), so there is one search to style and one to fix. */

@media (max-width: 600px) {
	.hsearch { margin-top: 1.8rem; }
	.hsearch-bar { padding-left: .8rem; }
	.hsearch-go { padding: .78rem 1rem; font-size: .6rem; }
	.hsearch input { font-size: 16px; }  /* iOS zooms the page below 16px */
}

/* ══ Pinned: the hero the page slides over ════════════════════════════════ */

.hero-section[data-hero-motion="pinned"] { height: var(--preview-vh, 100svh); overflow-x: visible; }

/* Out of flow, so the sections below scroll across it. The full-bleed
   centring the base rules use is unnecessary here — fixed positioning is
   already viewport-relative. */
.hero-section[data-hero-motion="pinned"] .hero-bleed {
	position: fixed;
	top: 0;
	left: 0;
	right: auto;
	z-index: 0;
	margin: 0;
	min-height: 0;
}

/* Once a full viewport has scrolled by, the page covers the hero completely —
   stop rendering it so it is not composited beneath everything down to the
   footer. visibility, not display: it keeps the decoded image around, so
   scrolling back up is instant rather than a re-decode. */
.hero-section[data-hero-motion="pinned"] .hero-bleed.is-passed { visibility: hidden; }

/* The photo stays pinned, but the words ride the page: --hero-scroll is the
   scroll offset and --hero-fade the matching 1->0 ramp, both written by
   hero.js. The ramp is sized so the text is fully gone before it would reach
   the header, rather than sliding under it. No transition on these: the
   scroll position IS the clock, and easing it would lag the page. */
.hero-section[data-hero-motion="pinned"] .hero-text {
	will-change: transform, opacity;
	transform: translate3d(0, calc(var(--hero-scroll, 0px) * -1), 0);
	opacity: var(--hero-fade, 1);
}
@media (prefers-reduced-motion: reduce) {
	/* Back to a plain pinned hero — no travel, no fade. */
	.hero-section[data-hero-motion="pinned"] .hero-text { transform: none; opacity: 1; }
}

/* These pages carry less copy over a photograph that has to keep working
   behind a whole page of content, so the type is a step down from the
   homepage's. */
.hero-section[data-hero-motion="pinned"] .hero-heading { font-size: clamp(28px,6vw,64px); }
.hero-section[data-hero-motion="pinned"] .hero-tagline { font-size: clamp(13px,1.6vw,17px); }

/* ══ Scroll cue ═══════════════════════════════════════════════════════════ */

/* Centred at the foot of the hero, and gone as soon as the page moves so it
   never sits on top of the content below. */
.hero-cue { position: absolute; left: 50%; bottom: 2.25rem; z-index: 2; translate: -50% 0; width: 26px; height: 42px; border: 1px solid rgba(255,255,255,.7); border-radius: 999px; opacity: .85; transition: opacity .3s ease; }
.hero-cue::after { content: ''; position: absolute; left: 50%; top: 9px; width: 2px; height: 7px; margin-left: -1px; background: #fff; border-radius: 1px; animation: heroCue 1.9s ease-in-out infinite; }
@keyframes heroCue { 0%,100% { transform: translateY(0); opacity: 0; } 35% { opacity: 1; } 70% { transform: translateY(13px); opacity: 0; } }
/* WCAG 2.2.2: heroCue runs forever and nothing on the page stops it, so it
   has to stop itself for anyone who has asked for less motion. The dot stays
   put and visible — the cue still reads as a cue. */
@media (prefers-reduced-motion: reduce) { .hero-cue::after { animation: none; opacity: 1 } }
.hero-section.is-scrolled .hero-cue { opacity: 0; }
