/**
 * QuickStream — motion and hover effects.
 *
 * Every effect here is switched on per block from the "Motion & effects"
 * panel in the editor sidebar, which adds the qs-* classes below at render
 * time. Timing comes from theme.json (settings.custom.motion) and colours,
 * shadows and radii from the Global Styles presets, so nothing here needs
 * editing to restyle an effect.
 *
 * Rules of the road:
 * - Only transform and opacity animate, so the browser can composite
 *   without layout or repaint work.
 * - Content is never hidden unless the page script is running (html.qs-motion),
 *   so with JavaScript off, or in the editor, everything is visible.
 * - prefers-reduced-motion: everything lands in its final state, instantly.
 */

@property --qs-angle {
	syntax: "<angle>";
	inherits: false;
	initial-value: 0turn;
}

/* ---------------------------------------------------------------------------
 * Entrance on scroll
 * ------------------------------------------------------------------------ */
.qs-anim {
	--qs-from: translate3d(0, var(--wp--custom--motion--distance), 0);
}
.qs-anim--fade-in { --qs-from: none; }
.qs-anim--fade-down { --qs-from: translate3d(0, calc(-1 * var(--wp--custom--motion--distance)), 0); }
.qs-anim--slide-left { --qs-from: translate3d(calc(2 * var(--wp--custom--motion--distance)), 0, 0); }
.qs-anim--slide-right { --qs-from: translate3d(calc(-2 * var(--wp--custom--motion--distance)), 0, 0); }
.qs-anim--zoom-in { --qs-from: scale(0.94); }

@keyframes qs-enter {
	from {
		opacity: 0;
		transform: var(--qs-from);
	}
	to {
		opacity: 1;
		transform: none;
	}
}

/* Single element. */
.qs-motion .qs-anim:not(.qs-stagger):not(.is-inview) {
	opacity: 0;
	transform: var(--qs-from);
}
.qs-motion .qs-anim:not(.qs-stagger).is-inview {
	animation: qs-enter var(--qs-duration, var(--wp--custom--motion--duration)) var(--wp--custom--motion--easing) var(--qs-delay, 0ms) backwards;
}

/* Children one after another. The script numbers the children (--qs-i). */
.qs-motion .qs-anim.qs-stagger:not(.is-inview) > * {
	opacity: 0;
	transform: var(--qs-from);
}
.qs-motion .qs-anim.qs-stagger.is-inview > * {
	animation: qs-enter var(--qs-duration, var(--wp--custom--motion--duration)) var(--wp--custom--motion--easing) backwards;
	animation-delay: calc(var(--qs-delay, 0ms) + var(--qs-i, 0) * var(--wp--custom--motion--stagger));
}

/* ---------------------------------------------------------------------------
 * Hover effects
 * Glass cards, highlighted cards, flat cards and chips lift and glow by
 * default, as on the reference design. Pick "None" in the panel to turn it
 * off for one block, or another effect to replace it.
 * ------------------------------------------------------------------------ */
:is(.is-style-card, .is-style-card-flat, .is-style-card-highlight, .is-style-chip, .qs-hover--lift, .qs-hover--glow, .qs-hover--lift-glow, .qs-hover--highlight) {
	transition:
		transform var(--wp--custom--transition),
		box-shadow 420ms var(--wp--custom--motion--easing),
		border-color var(--wp--custom--transition),
		background-color var(--wp--custom--transition);
}

:is(.is-style-card, .is-style-card-flat, .is-style-card-highlight, .is-style-chip, .qs-hover--glow, .qs-hover--lift-glow):not(.qs-hover--none, .qs-hover--lift, .qs-hover--zoom, .qs-hover--highlight, .qs-hover--sweep):is(:hover, :focus-within) {
	border-color: var(--wp--preset--color--line-strong);
	box-shadow: var(--wp--preset--shadow--glow-soft), var(--wp--preset--shadow--inner-line);
}

.qs-hover--highlight:is(:hover, :focus-within) {
	background-color: var(--wp--preset--color--glass);
}

.qs-hover--highlight {
	border-radius: var(--wp--preset--border-radius--sm);
}

.qs-hover--zoom {
	overflow: hidden;
}
.qs-hover--zoom img {
	transition: transform 700ms var(--wp--custom--motion--easing);
}

@media (hover: hover) and (prefers-reduced-motion: no-preference) {
	:is(.is-style-card, .is-style-card-flat, .is-style-card-highlight, .is-style-chip, .qs-hover--lift, .qs-hover--lift-glow):not(.qs-hover--none, .qs-hover--glow, .qs-hover--zoom, .qs-hover--highlight, .qs-hover--sweep):is(:hover, :focus-within) {
		transform: translate3d(0, var(--wp--custom--motion--lift), 0);
	}

	.qs-hover--zoom:hover img {
		transform: scale(1.05);
	}

	/* Buttons rise a touch, like the reference CTAs. */
	.wp-element-button,
	.wp-block-button__link {
		transition: transform var(--wp--custom--transition), box-shadow 420ms var(--wp--custom--motion--easing), background-color var(--wp--custom--transition), border-color var(--wp--custom--transition);
	}
	.wp-element-button:hover,
	.wp-block-button__link:hover {
		transform: translate3d(0, -2px, 0);
	}
}

/* ---------------------------------------------------------------------------
 * Rotating gradient border — on hover (qs-hover--sweep) or always
 * (qs-loop--sweep). Colours follow the brand gradient presets.
 * ------------------------------------------------------------------------ */
:is(.qs-hover--sweep, .qs-loop--sweep) {
	position: relative;
	isolation: isolate;
}
:is(.qs-hover--sweep, .qs-loop--sweep)::after {
	content: "";
	position: absolute;
	inset: -1px;
	z-index: 2;
	border: 2px solid transparent;
	border-radius: var(--qs-sweep-radius, inherit);
	pointer-events: none;
	background: conic-gradient(from var(--qs-angle), transparent 78%, var(--wp--preset--color--primary), var(--wp--preset--color--secondary) 96%, transparent) border-box;
	-webkit-mask: linear-gradient(#000 0 0) padding-box, linear-gradient(#000 0 0);
	-webkit-mask-composite: xor;
	mask: linear-gradient(#000 0 0) padding-box exclude, linear-gradient(#000 0 0);
	opacity: 0;
	transition: opacity 420ms var(--wp--custom--motion--easing);
}
/* On an image the corners are rounded on the <img>, not on its <figure>, so
   the border takes its radius from a variable: the Large radius preset by
   default (what the Framed style uses), replaced by the script with the
   image's actual radius when one has been set on the block. */
.wp-block-image:is(.qs-hover--sweep, .qs-loop--sweep) {
	--qs-sweep-radius: var(--wp--preset--border-radius--lg);
}

/* The ring sits fully outside the image's own edge, so the two lines never
   overlap, and its corners are 2px rounder to stay parallel to the image's. */
.wp-block-image:is(.qs-hover--sweep, .qs-loop--sweep)::after {
	inset: -2px;
	border-radius: calc(var(--qs-sweep-radius) + 2px);
}

.qs-loop--sweep::after,
.qs-hover--sweep:is(:hover, :focus-within)::after {
	opacity: 1;
	animation: qs-border-rotate 3.2s linear infinite;
}
.qs-loop--sweep::after {
	animation-duration: 7s;
}
.qs-hover--sweep:is(:hover, :focus-within) {
	border-color: var(--wp--preset--color--line-strong);
	box-shadow: var(--wp--preset--shadow--glow-soft);
}

@keyframes qs-border-rotate {
	to { --qs-angle: 1turn; }
}

/* ---------------------------------------------------------------------------
 * Continuous effects
 * ------------------------------------------------------------------------ */
.qs-loop--pulse {
	animation: qs-pulse 1.6s ease-in-out infinite;
}
@keyframes qs-pulse {
	0%, 100% { opacity: 1; }
	50% { opacity: 0.35; }
}

.qs-loop--float {
	animation: qs-float 7s cubic-bezier(0.65, 0, 0.35, 1) infinite alternate;
}
@keyframes qs-float {
	from { transform: translate3d(0, 0, 0); }
	to { transform: translate3d(0, -12px, 0); }
}

.qs-loop--glow {
	position: relative;
}
.qs-loop--glow::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	border-radius: inherit;
	box-shadow: var(--wp--preset--shadow--glow-cyan);
	animation: qs-pulse 3.2s ease-in-out infinite;
	pointer-events: none;
}

/* ---------------------------------------------------------------------------
 * Drifting background glow — two soft fields behind the section's content,
 * tinted with the Primary, Secondary and Accent palette colours.
 * ------------------------------------------------------------------------ */
.qs-bg--drift {
	position: relative;
	isolation: isolate;
	overflow: clip;
}
.qs-bg--drift::before,
.qs-bg--drift::after {
	content: "";
	position: absolute;
	inset: -40%;
	z-index: -1;
	pointer-events: none;
	will-change: transform; /* own compositor layer: drifting never repaints */
}
.qs-bg--drift::before {
	background:
		radial-gradient(44% 44% at 20% 24%, color-mix(in srgb, var(--wp--preset--color--primary) 24%, transparent), transparent 68%),
		radial-gradient(38% 38% at 80% 66%, color-mix(in srgb, var(--wp--preset--color--secondary) 16%, transparent), transparent 70%);
	animation: qs-drift 36s cubic-bezier(0.65, 0, 0.35, 1) infinite alternate;
}
.qs-bg--drift::after {
	background:
		radial-gradient(34% 34% at 66% 16%, color-mix(in srgb, var(--wp--preset--color--secondary) 12%, transparent), transparent 72%),
		radial-gradient(40% 40% at 30% 82%, color-mix(in srgb, var(--wp--preset--color--accent) 18%, transparent), transparent 74%);
	animation: qs-drift-alt 54s cubic-bezier(0.65, 0, 0.35, 1) infinite alternate;
}
@keyframes qs-drift {
	from { transform: translate3d(-4%, -3%, 0) scale(1); }
	to { transform: translate3d(4%, 3%, 0) scale(1.18); }
}
@keyframes qs-drift-alt {
	from { transform: translate3d(5%, 2%, 0) scale(1.12); }
	to { transform: translate3d(-5%, -2%, 0) scale(1); }
}

/* ---------------------------------------------------------------------------
 * Marquee — a row of items that scrolls sideways and pauses on hover. The
 * script duplicates the items once so the loop is seamless.
 * ------------------------------------------------------------------------ */
.qs-marquee.is-running {
	flex-wrap: nowrap !important;
	justify-content: flex-start !important;
	overflow: hidden;
	-webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
	mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.qs-marquee__track {
	display: flex;
	flex: none;
	gap: inherit;
	align-items: center;
	animation: qs-marquee var(--qs-marquee-speed, var(--wp--custom--motion--marquee)) linear infinite;
}
.qs-marquee__track > * {
	flex: none;
	margin: 0;
	transition: color var(--wp--custom--transition);
}
.qs-marquee__track > *:hover {
	color: var(--wp--preset--color--secondary);
}
.qs-marquee:hover .qs-marquee__track,
.qs-marquee:focus-within .qs-marquee__track {
	animation-play-state: paused;
}
@keyframes qs-marquee {
	to { transform: translate3d(-50%, 0, 0); }
}

/* ---------------------------------------------------------------------------
 * Auto-highlight — a glowing band that glides between inner blocks. Colours
 * follow the Secondary palette colour.
 * ------------------------------------------------------------------------ */
.qs-cycle__marker {
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	z-index: 3;
	pointer-events: none;
	mix-blend-mode: screen;
	background: linear-gradient(90deg,
		color-mix(in srgb, var(--wp--preset--color--secondary) 0%, transparent) 0%,
		color-mix(in srgb, var(--wp--preset--color--secondary) 12%, transparent) 22%,
		color-mix(in srgb, var(--wp--preset--color--secondary) 20%, transparent) 50%,
		color-mix(in srgb, var(--wp--preset--color--secondary) 12%, transparent) 78%,
		color-mix(in srgb, var(--wp--preset--color--secondary) 0%, transparent) 100%);
	box-shadow: 0 0 40px color-mix(in srgb, var(--wp--preset--color--secondary) 18%, transparent);
}
.qs-cycle__marker::before,
.qs-cycle__marker::after {
	content: "";
	position: absolute;
	left: 8%;
	right: 8%;
	height: 1px;
	background: var(--wp--preset--gradient--hairline);
}
.qs-cycle__marker::before { top: 0; }
.qs-cycle__marker::after { bottom: 0; }
.qs-cycle.is-cycling > .qs-cycle__marker {
	transition: transform 700ms var(--wp--custom--motion--easing), height 700ms var(--wp--custom--motion--easing);
}
/* The marker already shows which block is active; no second hover tint. */
.qs-cycle > .qs-hover--highlight:is(:hover, :focus-within) {
	background-color: transparent;
}
@media (prefers-reduced-motion: reduce) {
	.qs-cycle.is-cycling > .qs-cycle__marker {
		transition: none;
	}
}

/* ---------------------------------------------------------------------------
 * Accordion answers ease in when opened.
 * ------------------------------------------------------------------------ */
.wp-block-accordion-item.is-open > .wp-block-accordion-panel {
	--qs-from: translate3d(0, -6px, 0);
	animation: qs-enter 420ms var(--wp--custom--motion--easing) both;
}
.wp-block-accordion-heading__toggle-icon {
	transition: transform var(--wp--custom--transition);
}

/* ---------------------------------------------------------------------------
 * Reduced motion: final state, no movement.
 * ------------------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
	.qs-motion .qs-anim,
	.qs-motion .qs-anim > * {
		opacity: 1 !important;
		transform: none !important;
		animation: none !important;
	}
	.qs-loop--pulse,
	.qs-loop--float,
	.qs-loop--glow::before,
	.qs-loop--sweep::after,
	.qs-hover--sweep::after,
	.qs-bg--drift::before,
	.qs-bg--drift::after,
	.qs-marquee__track,
	.wp-block-accordion-item.is-open > .wp-block-accordion-panel {
		animation: none !important;
	}
}

/* Logos in a marquee sit a little quieter and brighten under the pointer. */
.qs-marquee .wp-block-image {
	margin: 0;
	opacity: 0.72;
	transition: opacity var(--wp--custom--transition);
}
.qs-marquee .wp-block-image:hover {
	opacity: 1;
}
