/*
 * FLAT: motion layer (DESIGN.md §9).
 *
 * One system for the whole site, driven by motion.js:
 *   - arrival of the home hero (first page of a visit only);
 *   - entrances on scroll: headings rise line by line out of a mask,
 *     photos open like a shutter, text and controls fade up in a cascade;
 *   - header that steps aside while reading and comes back on scroll up;
 *   - press, hover and page-change feedback.
 *
 * Only transform, opacity and clip-path move. Everything waiting for its
 * entrance is hidden under html.f-motion only, which is never set with
 * prefers-reduced-motion and falls off by itself if the script fails.
 * Values come from the kit variables (DESIGN.md §2).
 */

:root {
	/* Strong ease-out: entrances, feedback. */
	--f-ease-out: cubic-bezier(0.23, 1, 0.32, 1);
	/* Expo out: long, calm entrances (text rising out of a mask). */
	--f-ease-expo: cubic-bezier(0.16, 1, 0.3, 1);
	/* In-out: things moving on screen (shutter, light coming up). */
	--f-ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
	/* Drawer: the header sliding away and back. */
	--f-ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);
	/* Cascade step between elements entering together. */
	--f-stagger: 80ms;
}

/* ------------------------------------------------------------------ *
 * 1. Hero wordmark, very large (home)
 * ------------------------------------------------------------------ */

/* FLAT spans the content width, capped by the screen height so the
   actions stay above the fold on a short laptop. 3.32em is the width of
   the four letters at this tracking; the negative end margin cancels the
   tracking after the T, so the word ends flush with the column. */
.elementor .f-hero-video p:has(+ h1) {
	--f-wm-track: 0.3em;
	font-size: min(calc((100vw - 2 * var(--gutter)) / 3.32), 40svh);
	font-weight: 300;
	letter-spacing: var(--f-wm-track);
	line-height: 0.8;
	margin-inline-end: calc(-1 * var(--f-wm-track));
	white-space: nowrap;
	overflow: clip;
	overflow-clip-margin: 0.04em;
	padding-block-start: 0.04em;
}

.f-wm__l {
	display: inline-block;
}

/* ------------------------------------------------------------------ *
 * 2. Arrival (html.f-arrive, first page of a visit)
 * ------------------------------------------------------------------ */

/* Light comes up on the video while it settles from slightly closer. */
.f-hero-video::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	pointer-events: none;
	background-color: var(--f-bg);
	opacity: 0;
}

html.f-arrive .f-hero-video::before {
	animation: f-veil 1800ms cubic-bezier(0.65, 0, 0.35, 1) 100ms both;
}

html.f-arrive .f-hero-video .e-background-video__media {
	animation: f-settle 3200ms var(--f-ease-expo) both;
}

/* Header drops in once the name is there. `backwards` only: after the
   entrance the header's own transform (step aside) takes over again. */
html.f-arrive .elementor-location-header > .e-con {
	animation: f-drop 1000ms var(--f-ease-expo) 900ms backwards;
}

@keyframes f-veil {
	from { opacity: 1; }
	to { opacity: 0; }
}

@keyframes f-settle {
	from { scale: 1.12; }
	to { scale: 1; }
}

@keyframes f-drop {
	from {
		opacity: 0;
		transform: translateY(-16px);
	}
}

/* Pieces of the hero, held until motion.js has split the words. */
html.f-arrive .f-hero-video:not(.is-armed):not(.is-arrived) .e-background-video__content [data-e-type="widget"],
html.f-arrive .f-hero-video:not(.is-armed):not(.is-arrived) .e-background-video__controls {
	opacity: 0;
}

/* Wordmark: letters rise out of the line, one after the other. */
.f-hero-video.is-armed .f-wm__l {
	transform: translateY(105%);
}

.f-hero-video.is-armed .f-hero__fade {
	opacity: 0;
	transform: translateY(16px);
}

.f-hero-video.is-armed .e-background-video__controls {
	opacity: 0;
}

.f-hero-video.is-arriving .f-wm__l {
	transform: none;
	transition: transform 1400ms var(--f-ease-expo);
	transition-delay: calc(250ms + var(--i, 0) * 90ms);
}

.f-hero-video.is-arriving .f-hero__fade {
	opacity: 1;
	transform: none;
	transition:
		opacity 900ms var(--f-ease-out),
		transform 1100ms var(--f-ease-expo);
	transition-delay: calc(950ms + var(--i, 0) * var(--f-stagger));
}

.f-hero-video.is-arriving .e-background-video__controls {
	opacity: 1;
	transition: opacity 900ms ease 1500ms;
}

/* ------------------------------------------------------------------ *
 * 3. Hero on scroll: the content lifts away, the road keeps rolling
 * ------------------------------------------------------------------ */

@supports (animation-timeline: scroll()) {
	.f-hero-video > .e-background-video__content {
		animation: f-lift linear both;
		animation-timeline: scroll(root);
		animation-range: 0 85svh;
	}

	.f-hero-video .e-background-video__media {
		animation: f-drift linear both;
		animation-timeline: scroll(root);
		animation-range: 0 100svh;
	}

	html.f-arrive .f-hero-video .e-background-video__media {
		animation:
			f-drift linear both,
			f-settle 3200ms var(--f-ease-expo) both;
		animation-timeline: scroll(root), auto;
		animation-range: 0 100svh, normal;
	}

	@keyframes f-lift {
		to {
			opacity: 0;
			transform: translateY(-10svh);
		}
	}

	@keyframes f-drift {
		to { translate: 0 22svh; }
	}
}

/* ------------------------------------------------------------------ *
 * 4. Entrances on scroll (set up by motion.js)
 * ------------------------------------------------------------------ */

/* Before motion.js has sorted the page, content waits invisible (the
   header stays). A few hundred milliseconds at most; 4 s failsafe. */
html.f-motion:not(.f-ready) .elementor:not(.elementor-location-header) [data-e-type="widget"]:not(.f-hero-video *),
html.f-motion:not(.f-ready) .elementor:not(.elementor-location-header) .elementor-widget:not(.f-hero-video *) {
	opacity: 0;
}

/* Fade up: paragraphs, buttons, lists, shortcode blocks. */
.f-rv[data-f-rv="fade"] {
	opacity: 0;
	transform: translateY(24px);
}

.f-rv[data-f-rv="fade"].is-in {
	opacity: 1;
	transform: none;
	transition:
		opacity 900ms var(--f-ease-out),
		transform 1100ms var(--f-ease-expo);
	transition-delay: var(--f-d, 0ms);
}

/* Headings: each line rises out of its own mask. */
.f-rv[data-f-rv="line"] {
	opacity: 0;
}

.f-rv[data-f-rv="line"].is-split {
	opacity: 1;
}

.f-line {
	display: block;
	overflow: clip;
	/* Room for descenders (ç, p, j) inside the mask. */
	padding-block-end: 0.2em;
	margin-block-end: -0.2em;
}

.f-line__in {
	display: block;
	transform: translateY(110%);
}

.is-in .f-line__in {
	transform: none;
	transition: transform 1200ms var(--f-ease-expo);
	transition-delay: calc(var(--f-d, 0ms) + var(--i, 0) * 90ms);
}

/* Photos and videos: a shutter opening upwards. A photo in its own frame
   also settles from slightly closer (the frame clips the overflow). */
.e-div-block-base:has(> img:only-child) {
	overflow: clip;
}

.f-rv[data-f-rv="media"] {
	clip-path: inset(100% 0 0 0);
}

.e-div-block-base > img.f-rv[data-f-rv="media"] {
	scale: 1.1;
}

.f-rv[data-f-rv="media"].is-in,
.e-div-block-base > img.f-rv[data-f-rv="media"].is-in {
	clip-path: inset(0 0 0 0);
	scale: 1;
	transition:
		clip-path 1300ms var(--f-ease-in-out),
		scale 1800ms var(--f-ease-expo);
	transition-delay: var(--f-d, 0ms);
}

/* ------------------------------------------------------------------ *
 * 5. Header: steps aside while reading, back on the way up
 * ------------------------------------------------------------------ */

/* The bar's own `sticky` (Elementor) cannot stick inside a <header> of
   exactly its height: the header itself sticks. The home hero pins it
   with `fixed` instead (hero-video.css). */
body:not(:has(.f-hero-video)) .elementor-location-header {
	position: sticky;
	inset-block-start: var(--wp-admin--admin-bar--height, 0px);
	z-index: 50;
}

.elementor-location-header > .e-con {
	transition: transform 500ms var(--f-ease-drawer);
}

body.f-header-away .elementor-location-header > .e-con {
	transform: translateY(-100%);
}

/* ------------------------------------------------------------------ *
 * 6. Feedback
 * ------------------------------------------------------------------ */

/* Buttons answer the press at once; release is just as quick. */
body .elementor .f-btn {
	transition:
		background-color 200ms ease,
		color 200ms ease,
		transform 160ms var(--f-ease-out);
	-webkit-tap-highlight-color: transparent;
	touch-action: manipulation;
}

body .elementor .f-btn:active {
	transform: scale(0.97);
}

/* Text links: the underline sits back until the pointer comes. */
body .elementor .f-link,
body .elementor .f-link a {
	text-decoration-line: underline;
	text-decoration-thickness: 1px;
	text-decoration-color: color-mix(in srgb, currentColor 40%, transparent);
	text-underline-offset: 0.25em;
	transition:
		color 200ms ease,
		text-decoration-color 200ms ease,
		text-underline-offset 250ms var(--f-ease-out);
}

@media (hover: hover) and (pointer: fine) {
	body .elementor .f-link:hover,
	body .elementor .f-link a:hover {
		text-decoration-color: currentColor;
		text-underline-offset: 0.35em;
	}
}

body .elementor .f-link:focus-within,
body .elementor .f-link a:focus-visible {
	text-decoration-color: currentColor;
}

a,
button {
	-webkit-tap-highlight-color: transparent;
}

/* Linked photos (vehicles, loop cards): the picture leans in slowly under
   the pointer, inside its own frame. Pointer devices only. */
a[href] .e-div-block-base:has(> img) {
	overflow: clip;
}

@media (hover: hover) and (pointer: fine) {
	a[href] .e-div-block-base > img {
		transition: transform 1200ms var(--f-ease-out);
	}

	a[href]:hover .e-div-block-base > img {
		transform: scale(1.04);
	}
}

/* Photo strips (class f-strip): unequal panels edge to edge, their widths
   set locally by flex-grow. The panel under the pointer opens to its photo's
   own proportions (--f-ratio, read by motion.js), so the photo shows whole,
   never cropped; the others keep 120 px between them. A portrait photo still
   opens to 36 % at least, so the panel never shrinks under the pointer.
   A strip may set its own --f-strip-h locally (zero-specificity default). */
:where(.f-strip) {
	--f-strip-h: clamp(420px, 42vw, 680px);
}

@media (min-width: 768px) {
	body .elementor .f-strip {
		height: var(--f-strip-h);
	}

	body .elementor .f-strip > * {
		height: 100%;
		min-width: 0;
		overflow: hidden;
	}
}

@media (hover: hover) and (pointer: fine) and (min-width: 768px) {
	body .elementor .f-strip > * {
		transition:
			flex-grow var(--dur-base) var(--f-ease-out),
			flex-basis var(--dur-base) var(--f-ease-out);
	}

	body .elementor .f-strip > :is(:hover, :focus-visible) {
		flex: 0 0 clamp(36%, var(--f-strip-h) * var(--f-ratio, 1.5), 100% - 120px);
	}
}

/* List rows that are links (engine stock): the price leans towards the
   pointer, the row lights up one step. */
@media (hover: hover) and (pointer: fine) {
	.e-collection-loop-item > a[href] > p:last-child {
		transition: transform 300ms var(--f-ease-out);
	}

	.e-collection-loop-item > a[href]:hover > p:last-child {
		transform: translateX(-8px);
	}
}

/* ------------------------------------------------------------------ *
 * 7. Between pages: a short crossfade, the header stays put
 * ------------------------------------------------------------------ */

@view-transition {
	navigation: auto;
}

.elementor-location-header {
	view-transition-name: f-header;
}

::view-transition-old(root) {
	animation: 180ms ease both f-vt-out;
}

::view-transition-new(root) {
	animation: 380ms var(--f-ease-out) both f-vt-in;
}

@keyframes f-vt-out {
	to { opacity: 0; }
}

@keyframes f-vt-in {
	from {
		opacity: 0;
		transform: translateY(12px);
	}
}

/* ------------------------------------------------------------------ *
 * 8. Reduced motion: nothing moves, colour changes stay
 * ------------------------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
	@view-transition {
		navigation: none;
	}

	.f-hero-video > .e-background-video__content,
	.f-hero-video .e-background-video__media {
		animation: none;
	}

	body .elementor .f-btn:active {
		transform: none;
	}

	body .elementor .f-strip > * {
		transition: none;
	}
}
