/**
 * Animations — Keyframes and transition utilities.
 *
 * @package WEO
 */

/* ═══════════════════════════════════════════
   Resize transition guard
   ═══════════════════════════════════════════ */

/* While the user is actively resizing the window, kill all transitions
 * and animations. Without this, properties that swap at media-query
 * breakpoints (e.g. the events sidebar's transform / position at 960px)
 * animate visibly during the resize — the sidebar briefly slides off
 * screen. The .weo-resizing class is added by scroll-animations.js on
 * the resize event and removed 200ms after the last resize. */

.weo-resizing,
.weo-resizing *,
.weo-resizing *::before,
.weo-resizing *::after {
	transition: none !important;
	animation-duration: 0s !important;
	animation-delay: 0s !important;
}

/* ═══════════════════════════════════════════
   Keyframes
   ═══════════════════════════════════════════ */

/* Horizontal scrolling marquee */
@keyframes marquee {
	0% {
		transform: translateX(0);
	}

	100% {
		transform: translateX(-33.333%);
	}
}


/* Sparkle particle pulse */
@keyframes sparkle {
	0%,
	100% {
		opacity: 0;
		transform: scale(0.5);
	}

	50% {
		opacity: 1;
		transform: scale(1.2);
	}
}

/* Scroll-triggered fade in + slide up */
@keyframes fadeInUp {
	from {
		opacity: 0;
		transform: translateY(32px);
	}

	to {
		opacity: 1;
		transform: translateY(0);
	}
}

/* ───── Toast notifications ─────
   Slide-in from the right + countdown bar + slide-out. Used by the
   AR-page validation notice (css/attendee-registration.css) and by
   WC notices on account pages (css/woocommerce.css). Keyframes live
   here so they're loaded site-wide via the global animations bundle. */
@keyframes weoToastIn {
	from {
		opacity: 0;
		transform: translateX(16px);
	}
	to {
		opacity: 1;
		transform: translateX(0);
	}
}

@keyframes weoToastOut {
	0% {
		opacity: 1;
		transform: translateX(0);
		max-height: 500px;
		margin-bottom: 12px;
	}
	50% {
		opacity: 0;
		transform: translateX(16px);
		max-height: 500px;
		margin-bottom: 12px;
	}
	100% {
		opacity: 0;
		transform: translateX(16px);
		max-height: 0;
		margin-bottom: 0;
		padding-top: 0;
		padding-bottom: 0;
		pointer-events: none;
	}
}

@keyframes weoToastProgress {
	from {
		transform: scaleX(1);
	}
	to {
		transform: scaleX(0);
	}
}

/* Gentle float for decorative elements */
@keyframes float {
	0%,
	100% {
		transform: translateY(0);
	}

	50% {
		transform: translateY(-10px);
	}
}

/* ═══════════════════════════════════════════
   Scroll-Triggered Reveal
   ═══════════════════════════════════════════ */

/*
 * Elements start invisible. JS IntersectionObserver adds
 * .is-visible when element enters the viewport.
 */
.fade-in-up {
	opacity: 0;
	transform: translateY(32px);
	transition: opacity 0.8s cubic-bezier(0.16, 1, 0.3, 1),
	            transform 0.8s cubic-bezier(0.16, 1, 0.3, 1);
}

.fade-in-up.is-visible {
	opacity: 1;
	transform: translateY(0);
}

/* ─── Staggered delays for grid children ─── */
/* Cards 1-10 stagger linearly (0.08s steps; total 0.80s). Cards 11+
 * have no rule and fall back to no transition-delay — they fade in as
 * the IntersectionObserver fires `.is-visible` (effectively as soon as
 * they're seen). This caps the on-load stagger at ~1s rather than
 * dragging it out across all visible cards. */

.fade-in-up[data-delay="1"]  { transition-delay: 0.08s; }
.fade-in-up[data-delay="2"]  { transition-delay: 0.16s; }
.fade-in-up[data-delay="3"]  { transition-delay: 0.24s; }
.fade-in-up[data-delay="4"]  { transition-delay: 0.32s; }
.fade-in-up[data-delay="5"]  { transition-delay: 0.40s; }
.fade-in-up[data-delay="6"]  { transition-delay: 0.48s; }
.fade-in-up[data-delay="7"]  { transition-delay: 0.56s; }
.fade-in-up[data-delay="8"]  { transition-delay: 0.64s; }
.fade-in-up[data-delay="9"]  { transition-delay: 0.72s; }
.fade-in-up[data-delay="10"] { transition-delay: 0.80s; }

/* ═══════════════════════════════════════════
   Marquee Strip
   ═══════════════════════════════════════════ */

.marquee {
	overflow: hidden;
	padding: 12px 0;
	background: var(--accent);
	position: relative;
	z-index: 5;
}

.marquee__track {
	display: flex;
	/* Size to actual content. Without this the track inherits the parent's
	 * width (= viewport), so translateX(-33.333%) shifts by viewport/3
	 * instead of one full copy of the show list — causing (1) position
	 * discontinuity on loop restart ("jolt back to start") and (2) speed
	 * that varies with viewport width. With max-content the percentage is
	 * relative to the true content width, so -33.333% lands exactly on
	 * copy 2's start and pixels-per-second stays constant regardless of
	 * viewport size. */
	width: max-content;
	animation: marquee 45s linear infinite;
	/* Will-change for GPU acceleration */
	will-change: transform;
}

/* Slow (don't stop) on hover — handled in js/scroll-animations.js via the
 * Web Animations API playbackRate, which eases the speed down while keeping
 * the track's current position. (Changing animation-duration here instead
 * would recompute progress = elapsed/duration and visibly jump the strip.)
 * aria-hidden means the strip is decorative, so no focus-within counterpart
 * is needed (items aren't focusable). */

.marquee__item {
	display: inline-flex;
	align-items: center;
	gap: var(--space-xl);
	white-space: nowrap;
	padding: 0 var(--space-md);
	font-family: var(--font-display);
	font-weight: 700;
	font-size: var(--text-s);
	color: var(--white);
	letter-spacing: 0.08em;
	text-transform: uppercase;
	/* Prevent flex from shrinking items to fit a constrained track —
	 * partners with width: max-content on the parent. */
	flex-shrink: 0;
}

.marquee__separator {
	color: rgba(255, 255, 255, 0.4);
	font-size: var(--text-xs);
}

/* ═══════════════════════════════════════════
   Hero Load-In Animations
   ═══════════════════════════════════════════ */

/*
 * Hero elements start hidden, JS adds .is-loaded to
 * the hero section to trigger staggered entrance.
 */
.hero-animate {
	opacity: 0;
	transform: translateY(24px);
	transition: opacity 0.8s cubic-bezier(0.16, 1, 0.3, 1),
	            transform 0.8s cubic-bezier(0.16, 1, 0.3, 1);
}

.is-loaded .hero-animate {
	opacity: 1;
	transform: translateY(0);
}

.hero-animate--heading { transition-delay: 0.35s; }
.hero-animate--cta     { transition-delay: 0.7s; }
.hero-animate--hook    { transition-delay: 1s; opacity: 0; }
.is-loaded .hero-animate--hook { opacity: 0.8; }

/* ═══════════════════════════════════════════
   Atmospheric Effects (Hero / CTA)
   ═══════════════════════════════════════════ */

.atmospheric {
	position: absolute;
	inset: 0;
	overflow: hidden;
	pointer-events: none;
}

/* Sparkle particle (positioned via inline styles) */
.sparkle-particle {
	position: absolute;
	border-radius: 50%;
	opacity: 0;
}

/* ═══════════════════════════════════════════
   Reduced Motion
   ═══════════════════════════════════════════ */

/* ═══════════════════════════════════════════
   Testimonial Carousel Transitions
   ═══════════════════════════════════════════ */

.testimonial-enter {
	animation: fadeInUp 0.5s var(--ease-out-expo);
}

.testimonial-leave {
	animation: fadeInUp 0.3s var(--ease-out-expo) reverse;
}

/* ═══════════════════════════════════════════
   Floating Ticket Stubs (Hero)
   ═══════════════════════════════════════════ */

.hero__ticket {
	position: absolute;
	border-radius: var(--radius-sm);
	backdrop-filter: blur(4px);
	opacity: 0;
	transition: opacity 1.5s ease 0.8s;
	z-index: 1;
}

.is-loaded .hero__ticket {
	opacity: 0.6;
}

.hero__ticket--right {
	top: 12%;
	right: 8%;
	width: 80px;
	height: 120px;
	background: rgba(224, 64, 160, 0.08);
	border: 1px solid rgba(224, 64, 160, 0.12);
	transform: rotate(15deg);
}

.hero__ticket--left {
	bottom: 18%;
	left: 6%;
	width: 65px;
	height: 100px;
	background: rgba(64, 184, 224, 0.06);
	border: 1px solid rgba(64, 184, 224, 0.1);
	transform: rotate(-20deg);
	transition-delay: 1.2s;
}

.is-loaded .hero__ticket--left {
	opacity: 0.5;
}

.hero__ticket-tear {
	position: absolute;
	top: 30%;
	left: 0;
	right: 0;
	height: 1px;
}

.hero__ticket--right .hero__ticket-tear {
	border-top: 1px dashed rgba(224, 64, 160, 0.3);
}

.hero__ticket--left .hero__ticket-tear {
	border-top: 1px dashed rgba(64, 184, 224, 0.25);
}

.hero__ticket-text {
	display: block;
	padding: 6px 8px;
	font-family: var(--font-display);
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
}

.hero__ticket--right .hero__ticket-text {
	font-size: var(--text-xs);
	color: rgba(224, 64, 160, 0.5);
}

.hero__ticket--left .hero__ticket-text {
	font-size: var(--text-xs);
	color: rgba(64, 184, 224, 0.4);
}

@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}

	.fade-in-up {
		opacity: 1;
		transform: none;
	}

	.hero-animate {
		opacity: 1;
		transform: none;
	}

	.marquee__track {
		animation: none;
	}
}
