/* ─── Entrance Animation ──────────────────────────────────────────────── */
.xtool-motion {
	opacity: 0;
	will-change: opacity, transform, filter;
	transition-property: opacity, transform, filter;
	transition-timing-function: ease-out;
}

.xtool-motion.is-visible {
	opacity: 1;
	transform: none;
	filter: none;
}

.xtool-motion[data-xtool-effect='fade-up'] {
	transform: translateY(30px);
}

.xtool-motion[data-xtool-effect='fade-down'] {
	transform: translateY(-30px);
}

.xtool-motion[data-xtool-effect='fade-left'] {
	transform: translateX(-40px);
}

.xtool-motion[data-xtool-effect='fade-right'] {
	transform: translateX(40px);
}

.xtool-motion[data-xtool-effect='zoom-in'] {
	transform: scale(0.85);
}

.xtool-motion[data-xtool-effect='zoom-out'] {
	transform: scale(1.15);
}

.xtool-motion[data-xtool-effect='flip-in'] {
	transform: perspective(800px) rotateX(80deg);
	transform-origin: top center;
}

.xtool-motion[data-xtool-effect='rotate-in'] {
	transform: rotate(-12deg) scale(0.9);
}

.xtool-motion[data-xtool-effect='bounce-in'] {
	transform: scale(0.4);
	transition-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1);
}

@media (prefers-reduced-motion: reduce) {
	.xtool-motion {
		opacity: 1 !important;
		transform: none !important;
		filter: none !important;
		transition: none !important;
	}
}

/* ─── Scrolling Effects (parallax) ───────────────────────────────────────── */
.xtool-scrollfx {
	will-change: transform, opacity, filter;
}

@media (prefers-reduced-motion: reduce) {
	.xtool-scrollfx {
		transform: none !important;
		opacity: 1 !important;
		filter: none !important;
	}
}

/* ─── Mouse Effects ───────────────────────────────────────────────────── */
.xtool-mousefx--track {
	will-change: transform;
	transition: transform 0.15s ease-out;
}

.xtool-mousefx--tilt {
	will-change: transform;
	transition: transform 0.15s ease-out;
	transform-style: preserve-3d;
}

@media (prefers-reduced-motion: reduce) {
	.xtool-mousefx--track,
	.xtool-mousefx--tilt {
		transform: none !important;
	}
}

/* ─── Sticky ──────────────────────────────────────────────────────────── */
.xtool-motion-sticky--top {
	position: sticky;
	top: var(--xtool-sticky-offset, 0px);
	z-index: 100;
}

.xtool-motion-sticky--bottom {
	position: sticky;
	bottom: var(--xtool-sticky-offset, 0px);
	z-index: 100;
}

.xtool-motion-sticky--shadow.is-stuck {
	box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
	transition: box-shadow 0.2s ease;
}

/* Whole Page scope — position:fixed instead of sticky, so it is never
   constrained by any ancestor's height (see initStickyFixed() in
   motion-effects.js for why plain sticky alone can't always reach full-
   page range — usually the active theme's own <header> markup, which
   Xtool has no control over). Only applied once JS adds .is-pinned,
   *not* unconditionally — confirmed live that pinning from the very
   first frame covers whatever sits above the element in normal flow
   (e.g. a promo bar row before a nav row); starting in normal flow and
   switching to fixed only once scrolled past its own natural position
   avoids that entirely, at the cost of needing JS (a pure-CSS
   :has()-free fallback isn't possible for "detect scroll position").
   width/left are deliberately NOT set here — initStickyFixed() measures
   and sets them inline per-instance instead (same technique Elementor
   Pro's own sticky JS uses). A blind width:100%;left:0 here would
   stretch/snap anything that isn't already a full-width, left-aligned
   element (e.g. a Button widget centered in a column) to the far edge
   of the viewport the moment it pins — confirmed live. */
.xtool-motion-sticky--fixed.xtool-motion-sticky--top.is-pinned {
	position: fixed;
	top: var(--xtool-sticky-offset, 0px);
	z-index: 100;
}

.xtool-motion-sticky--fixed.xtool-motion-sticky--bottom.is-pinned {
	position: fixed;
	bottom: var(--xtool-sticky-offset, 0px);
	z-index: 100;
}

.xtool-motion-sticky--fixed.xtool-motion-sticky--shadow.is-pinned {
	box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
	transition: box-shadow 0.2s ease;
}
