/* PrettyWellFit Entrance — house entrance motion.
 * Values arrive as custom properties from Settings > Motion Elements,
 * one block per device band (inlined after this file); the ones below
 * are fallbacks only.
 * The hidden state engages only once the head script has confirmed
 * live JS (html.pwf-js) and never under reduced motion; without either,
 * every element is simply visible. The delay is pure CSS:
 * (order - 1) x step, start to start, from the element's own trigger.
 */

:root {
	--pwf-ent-distance: 22px;
	--pwf-ent-dur: 700ms;
	--pwf-ent-ease: cubic-bezier(0.16, 1, 0.3, 1);
	--pwf-ent-step: 120ms;
	--pwf-ent-g: 1;
}

/* Live factor per element: the device's global switch (--pwf-ent-g,
 * set per breakpoint band) times the element's own Play setting
 * (--pwf-ent-e, written per breakpoint by Elementor). At 0 the hidden
 * state equals the landed state, so the element simply sits in place.
 * --pwf-ent-e resets on every opted-in element so a skipped parent
 * never silences a nested child that plays. */
.pwf-entrance {
	--pwf-ent-e: 1;
	--pwf-ent-live: calc(var(--pwf-ent-g, 1) * var(--pwf-ent-e, 1));
}

/* PrettyWellFit Entrance owns the element: any native Elementor entrance on
 * the same wrapper (animate.css keyframes) is disabled outright, and
 * the native pre-animation hidden state is defeated so a stray native
 * setting can never strand or double-animate an opted-in element. */
.pwf-entrance {
	animation: none !important;
}

.pwf-entrance.elementor-invisible {
	visibility: visible !important;
}

@media (prefers-reduced-motion: no-preference) {
	html.pwf-js .pwf-entrance {
		opacity: calc(1 - var(--pwf-ent-live, 1));
		transform: translateY(calc(var(--pwf-ent-distance) * var(--pwf-ent-live, 1)));
	}

	html.pwf-js .pwf-entrance.sw-in {
		opacity: 1;
		transform: none;
		transition:
			opacity var(--pwf-ent-dur) var(--pwf-ent-ease),
			transform var(--pwf-ent-dur) var(--pwf-ent-ease);
		transition-delay: calc((var(--pwf-ent-order, 1) - 1) * var(--pwf-ent-step));
	}

	/* Entered and settled: the stagger delay and entrance duration
	 * stop governing the element, so later state changes (hover
	 * fades and the like) react immediately. */
	html.pwf-js .pwf-entrance.sw-in.sw-settled {
		transition-duration: 300ms;
		transition-delay: 0ms;
	}

	/* Blur-aware entrance: an element carrying (or containing) a
	 * Background Blur container must never animate opacity — a group
	 * mid-fade seals its backdrop and the blur cannot sample until it
	 * lands. These elements hide with visibility instead and rise in
	 * with the same motion; the blur is live from the first visible
	 * pixel. */
	html.pwf-js .pwf-entrance.pwf-bgblur,
	html.pwf-js .pwf-entrance:has(.pwf-bgblur) {
		opacity: 1;
		visibility: hidden;
	}

	html.pwf-js .pwf-entrance.sw-in.pwf-bgblur,
	html.pwf-js .pwf-entrance.sw-in:has(.pwf-bgblur) {
		visibility: visible;
	}
}

/* ---- Frames ----
 * A container marked data-pwf-frame claims the .pwf-entrance elements
 * inside it: the engine never observes them, and the frame's own
 * timeline states reveal them instead, with the same motion and the
 * same (order - 1) x step stagger. Inside a pinned stage, viewport
 * entry happens long before the frame is visible, so the timeline is
 * the only correct trigger. Owner blocks below map each frame widget's
 * broadcast states onto the house entrance.
 */

@media (prefers-reduced-motion: no-preference) {
	/* Reveal Scroll Video end frame. Children stagger in when the
	 * timeline reveals the frame; when it unreveals, they ride the
	 * frame's own fast uniform 300ms fade back to hidden, so a reset
	 * is never visible. */
	html.pwf-js .pwf-reveal.is-end-revealed [data-pwf-frame] .pwf-entrance {
		opacity: 1;
		transform: none;
		transition:
			opacity var(--pwf-ent-dur) var(--pwf-ent-ease),
			transform var(--pwf-ent-dur) var(--pwf-ent-ease);
		transition-delay: calc((var(--pwf-ent-order, 1) - 1) * var(--pwf-ent-step));
	}

	html.pwf-js .pwf-reveal.is-end-unrevealing [data-pwf-frame] .pwf-entrance {
		transition: opacity 300ms ease, transform 300ms ease;
		transition-delay: 0ms;
	}

	/* Hero to Frame Video frames: same contract, keyed to the hero's
	 * own trigger classes. The End Frame arrives at the reveal trigger;
	 * the Intro Frame arrives when it is on screen (at load, or at the
	 * landing of a reversed journey) and retracts when scrolled past. */
	html.pwf-js .pwf-hero.is-revealed [data-pwf-frame="end"] .pwf-entrance,
	html.pwf-js .pwf-hero.is-intro-revealed [data-pwf-frame="intro"] .pwf-entrance {
		opacity: 1;
		transform: none;
		transition:
			opacity var(--pwf-ent-dur) var(--pwf-ent-ease),
			transform var(--pwf-ent-dur) var(--pwf-ent-ease);
		transition-delay: calc((var(--pwf-ent-order, 1) - 1) * var(--pwf-ent-step));
	}

	html.pwf-js .pwf-hero.is-unrevealing [data-pwf-frame="end"] .pwf-entrance,
	html.pwf-js .pwf-hero.is-intro-unrevealing [data-pwf-frame="intro"] .pwf-entrance {
		transition: opacity 300ms ease, transform 300ms ease;
		transition-delay: 0ms;
	}
}


/* ---- Entrance Blur ----
 * Optional (Settings > PrettyWellFit Elements): elements arrive soft and
 * resolve sharp with the same duration, ease, and stagger as the rise.
 * Gated by html.pwf-entblur so the feature costs nothing when off.
 * Background Blur carriers are excluded everywhere: a filter would make
 * them a backdrop root and wall their own blur off.
 */

@media (prefers-reduced-motion: no-preference) {
	html.pwf-js.pwf-entblur .pwf-entrance:not(.pwf-bgblur):not(:has(.pwf-bgblur)) {
		filter: blur(calc(var(--pwf-ent-blur, 0px) * var(--pwf-ent-live, 1)));
	}

	html.pwf-js.pwf-entblur .pwf-entrance.sw-in:not(.pwf-bgblur):not(:has(.pwf-bgblur)) {
		filter: blur(0);
		transition:
			opacity var(--pwf-ent-dur) var(--pwf-ent-ease),
			transform var(--pwf-ent-dur) var(--pwf-ent-ease),
			filter var(--pwf-ent-dur) var(--pwf-ent-ease);
		transition-delay: calc((var(--pwf-ent-order, 1) - 1) * var(--pwf-ent-step));
	}

	/* Settled, the blur is gone for good, not parked at zero: a filter
	 * of any value makes the element a containing block, which would
	 * capture anything pinned to the screen inside it (a stuck menu
	 * bar). */
	html.pwf-js.pwf-entblur .pwf-entrance.sw-in.sw-settled:not(.pwf-bgblur):not(:has(.pwf-bgblur)) {
		filter: none;
		transition-duration: 300ms;
		transition-delay: 0ms;
	}

	/* Frame-claimed elements resolve on their frame's own states. */
	html.pwf-js.pwf-entblur .pwf-reveal.is-end-revealed [data-pwf-frame] .pwf-entrance:not(.pwf-bgblur):not(:has(.pwf-bgblur)),
	html.pwf-js.pwf-entblur .pwf-hero.is-revealed [data-pwf-frame="end"] .pwf-entrance:not(.pwf-bgblur):not(:has(.pwf-bgblur)),
	html.pwf-js.pwf-entblur .pwf-hero.is-intro-revealed [data-pwf-frame="intro"] .pwf-entrance:not(.pwf-bgblur):not(:has(.pwf-bgblur)) {
		filter: blur(0);
		transition:
			opacity var(--pwf-ent-dur) var(--pwf-ent-ease),
			transform var(--pwf-ent-dur) var(--pwf-ent-ease),
			filter var(--pwf-ent-dur) var(--pwf-ent-ease);
		transition-delay: calc((var(--pwf-ent-order, 1) - 1) * var(--pwf-ent-step));
	}

	html.pwf-js.pwf-entblur .pwf-reveal.is-end-unrevealing [data-pwf-frame] .pwf-entrance:not(.pwf-bgblur):not(:has(.pwf-bgblur)),
	html.pwf-js.pwf-entblur .pwf-hero.is-unrevealing [data-pwf-frame="end"] .pwf-entrance:not(.pwf-bgblur):not(:has(.pwf-bgblur)),
	html.pwf-js.pwf-entblur .pwf-hero.is-intro-unrevealing [data-pwf-frame="intro"] .pwf-entrance:not(.pwf-bgblur):not(:has(.pwf-bgblur)) {
		transition: opacity 300ms ease, transform 300ms ease, filter 300ms ease;
		transition-delay: 0ms;
	}
}

/* The quiet gate: off-stage cards in a rail arrive already settled —
   the finished state applies with no motion at all, then the gate
   lifts so later interactions behave normally. */
html.pwf-js .pwf-entrance.sw-quiet {
	transition: none !important;
	animation: none !important;
}


/* ---- Text in pieces ----
 * An element set to animate By line, By word or By letter carries
 * data-pwf-split. The runtime wraps its text on the front end: each
 * word (or letter) becomes a piece, an outer box (.pwf-ent-p) around
 * the part that moves (.pwf-ent-pi); leaf media (an image, an icon)
 * inside the element is a piece on its own. Whitespace between pieces
 * stays as real text, so the browser wraps exactly as it would
 * unsplit. The element itself never moves: it stays hidden only until
 * the split has landed (.pwf-split-ready), then its pieces play the
 * house motion inside the element's own order slot, one piece step
 * apart. --pwf-ent-i is each piece's beat (its line, word or letter
 * number) and --pwf-ent-pstep the step for that mode, both written by
 * the runtime for the device in play.
 */

.pwf-ent-w,
.pwf-ent-p,
span.pwf-ent-pi {
	display: inline-block;
	text-decoration: inherit;
}

.pwf-ent-w,
.pwf-ent-p {
	vertical-align: baseline;
}

/* A link's underline travels with the moving part of each piece
 * instead of sitting at rest under text that has not landed yet. */
.pwf-entrance[data-pwf-split] :is(a, u, ins, s, del) {
	text-decoration-color: transparent;
}

.pwf-entrance[data-pwf-split] span.pwf-ent-pi {
	text-decoration-color: currentColor;
}

.pwf-ent-sr {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip: rect(0 0 0 0);
	white-space: nowrap;
}

@media (prefers-reduced-motion: no-preference) {
	/* The element holds still and shows once split; the pieces do the
	 * moving. Before the split lands it stays hidden, so unsplit text
	 * never flashes. */
	html.pwf-js .pwf-entrance[data-pwf-split] {
		transform: none;
	}

	html.pwf-js .pwf-entrance[data-pwf-split].pwf-split-ready,
	html.pwf-js.pwf-entblur .pwf-entrance[data-pwf-split].pwf-split-ready:not(.pwf-bgblur):not(:has(.pwf-bgblur)) {
		opacity: 1;
		transform: none;
		filter: none;
		transition: none;
	}

	html.pwf-js .pwf-entrance[data-pwf-split] .pwf-ent-pi {
		opacity: calc(1 - var(--pwf-ent-live, 1));
		transform: translateY(calc(var(--pwf-ent-distance) * var(--pwf-ent-live, 1)));
	}

	/* Fade only: the pieces stay put and simply fade in. */
	html.pwf-js .pwf-entrance.pwf-split--fade .pwf-ent-pi {
		transform: none;
	}

	/* Rise from the line: each piece box clips, and the moving part
	 * starts fully below the box so the type lifts into view with
	 * nothing showing beneath it. Leaf media keeps the plain rise. */
	html.pwf-js .pwf-entrance.pwf-split--clip .pwf-ent-p {
		clip-path: inset(-0.2em 0 -0.2em 0);
	}

	html.pwf-js .pwf-entrance.pwf-split--clip .pwf-ent-p > .pwf-ent-pi {
		opacity: 1;
		transform: translateY(calc((100% + 0.2em) * var(--pwf-ent-live, 1)));
	}

	html.pwf-js .pwf-entrance[data-pwf-split].sw-in .pwf-ent-pi,
	html.pwf-js .pwf-reveal.is-end-revealed [data-pwf-frame] .pwf-entrance[data-pwf-split] .pwf-ent-pi,
	html.pwf-js .pwf-hero.is-revealed [data-pwf-frame="end"] .pwf-entrance[data-pwf-split] .pwf-ent-pi,
	html.pwf-js .pwf-hero.is-intro-revealed [data-pwf-frame="intro"] .pwf-entrance[data-pwf-split] .pwf-ent-pi {
		opacity: 1;
		transform: none;
		transition:
			opacity var(--pwf-ent-dur) var(--pwf-ent-ease),
			transform var(--pwf-ent-dur) var(--pwf-ent-ease);
		transition-delay: calc((var(--pwf-ent-order, 1) - 1) * var(--pwf-ent-step) + var(--pwf-ent-i, 0) * var(--pwf-ent-pstep, 0ms));
	}

	html.pwf-js .pwf-entrance[data-pwf-split].sw-in.sw-settled .pwf-ent-pi {
		transition-duration: 300ms;
		transition-delay: 0ms;
	}

	html.pwf-js .pwf-reveal.is-end-unrevealing [data-pwf-frame] .pwf-entrance[data-pwf-split] .pwf-ent-pi,
	html.pwf-js .pwf-hero.is-unrevealing [data-pwf-frame="end"] .pwf-entrance[data-pwf-split] .pwf-ent-pi,
	html.pwf-js .pwf-hero.is-intro-unrevealing [data-pwf-frame="intro"] .pwf-entrance[data-pwf-split] .pwf-ent-pi {
		transition: opacity 300ms ease, transform 300ms ease;
		transition-delay: 0ms;
	}

	/* Entrance Blur rides the pieces the same way it rides elements. */
	html.pwf-js.pwf-entblur .pwf-entrance[data-pwf-split]:not(.pwf-bgblur):not(:has(.pwf-bgblur)) .pwf-ent-pi {
		filter: blur(calc(var(--pwf-ent-blur, 0px) * var(--pwf-ent-live, 1)));
	}

	html.pwf-js.pwf-entblur .pwf-entrance[data-pwf-split].sw-in:not(.pwf-bgblur):not(:has(.pwf-bgblur)) .pwf-ent-pi,
	html.pwf-js.pwf-entblur .pwf-reveal.is-end-revealed [data-pwf-frame] .pwf-entrance[data-pwf-split]:not(.pwf-bgblur):not(:has(.pwf-bgblur)) .pwf-ent-pi,
	html.pwf-js.pwf-entblur .pwf-hero.is-revealed [data-pwf-frame="end"] .pwf-entrance[data-pwf-split]:not(.pwf-bgblur):not(:has(.pwf-bgblur)) .pwf-ent-pi,
	html.pwf-js.pwf-entblur .pwf-hero.is-intro-revealed [data-pwf-frame="intro"] .pwf-entrance[data-pwf-split]:not(.pwf-bgblur):not(:has(.pwf-bgblur)) .pwf-ent-pi {
		filter: blur(0);
		transition:
			opacity var(--pwf-ent-dur) var(--pwf-ent-ease),
			transform var(--pwf-ent-dur) var(--pwf-ent-ease),
			filter var(--pwf-ent-dur) var(--pwf-ent-ease);
		transition-delay: calc((var(--pwf-ent-order, 1) - 1) * var(--pwf-ent-step) + var(--pwf-ent-i, 0) * var(--pwf-ent-pstep, 0ms));
	}

	html.pwf-js.pwf-entblur .pwf-entrance[data-pwf-split].sw-in.sw-settled:not(.pwf-bgblur):not(:has(.pwf-bgblur)) .pwf-ent-pi {
		transition-duration: 300ms;
		transition-delay: 0ms;
	}

	html.pwf-js.pwf-entblur .pwf-reveal.is-end-unrevealing [data-pwf-frame] .pwf-entrance[data-pwf-split]:not(.pwf-bgblur):not(:has(.pwf-bgblur)) .pwf-ent-pi,
	html.pwf-js.pwf-entblur .pwf-hero.is-unrevealing [data-pwf-frame="end"] .pwf-entrance[data-pwf-split]:not(.pwf-bgblur):not(:has(.pwf-bgblur)) .pwf-ent-pi,
	html.pwf-js.pwf-entblur .pwf-hero.is-intro-unrevealing [data-pwf-frame="intro"] .pwf-entrance[data-pwf-split]:not(.pwf-bgblur):not(:has(.pwf-bgblur)) .pwf-ent-pi {
		transition: opacity 300ms ease, transform 300ms ease, filter 300ms ease;
		transition-delay: 0ms;
	}
}

/* Off-stage cards in a rail arrive settled: pieces too. */
html.pwf-js .pwf-entrance.sw-quiet .pwf-ent-pi {
	transition: none !important;
}
