/**
 * SKF motion.
 *
 * Layered on top of the approved design: nothing here changes a colour, a
 * size, a position or a layout. Every rule either animates transform and
 * opacity, or restores the element to exactly where the static stylesheet
 * already put it.
 *
 * The at-rest state is the approved design. Elements are only hidden for a
 * reveal once JavaScript has confirmed it can show them again — the
 * `skf-motion` class on <html> is the switch — so a script failure, an old
 * browser or a blocked file leaves the page fully visible.
 *
 * @package skf-elementor
 */

:root {
	/* Micro interactions: buttons, arrows, overlays. */
	--skf-motion-micro: 240ms;

	/* Entrance: content arriving in the viewport. */
	--skf-motion-enter: 780ms;

	/*
	 * Distance a revealing element travels. Far enough to read as movement
	 * during an ordinary scroll; 16px was close enough to instantaneous
	 * that the reveal went unnoticed.
	 */
	--skf-motion-rise: 28px;

	/*
	 * Two rhythms. The three parts of a section head arrive in sequence,
	 * so the gap between them is long enough to read as an order. Grid
	 * items are more numerous, so theirs is shorter and capped.
	 */
	--skf-motion-step-head: 100ms;
	--skf-motion-step-item: 80ms;

	/* Default for anything not explicitly one or the other. */
	--skf-motion-step: var(--skf-motion-step-item);

	--skf-motion-ease: cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* ==========================================================================
   REVEAL
   ========================================================================== */

/*
 * Scoped to .skf-motion, which JavaScript adds to <html> before paint. No
 * script, no hiding: the content simply renders as it always has.
 */
.skf-motion [data-skf-reveal] {
	opacity: 0;
	transform: translate3d(0, var(--skf-motion-rise), 0);
	transition:
		opacity var(--skf-motion-enter) var(--skf-motion-ease),
		transform var(--skf-motion-enter) var(--skf-motion-ease);
	transition-delay: calc(var(--skf-motion-i, 0) * var(--skf-motion-step));
}

.skf-motion [data-skf-reveal].skf-in {
	opacity: 1;
	transform: none;
}

/* The reading sequence inside a section head. */
.skf-motion .skf-section-head [data-skf-reveal] {
	transition-delay: calc(var(--skf-motion-i, 0) * var(--skf-motion-step-head));
}

/*
 * There is deliberately no timed failsafe here.
 *
 * An earlier version un-hid every element four seconds after load, which
 * meant anything below the fold had already appeared before the visitor
 * scrolled to it — the reveal was running, just never where it could be
 * seen. The script now guarantees visibility instead: it reveals
 * everything if the observer cannot be created, and again if setup throws.
 */

/* ==========================================================================
   MARQUEE AND DRIFT
   Seamless because the track holds two identical runs and travels exactly
   half its own width. Duplicates carry aria-hidden, set in markup.
   ========================================================================== */

.skf-marquee {
	display: flex;
	width: max-content;
	will-change: transform;
	animation: skf-marquee-left var(--skf-marquee-duration, 60s) linear infinite;
}

.skf-marquee--right { animation-name: skf-marquee-right; }

@keyframes skf-marquee-left {
	from { transform: translate3d(0, 0, 0); }
	to   { transform: translate3d(-50%, 0, 0); }
}

@keyframes skf-marquee-right {
	from { transform: translate3d(-50%, 0, 0); }
	to   { transform: translate3d(0, 0, 0); }
}

/* --- Proverb drift -------------------------------------------------------
   Each existing row becomes its own track. Alternating directions and
   mismatched durations keep the rows from sliding as one rigid sheet.
   Nothing about the type, colour, opacity, spacing or clipping changes.
   ------------------------------------------------------------------------ */

/*
 * Scoped to .skf-motion because the runs inside a row only exist once the
 * script has built them. Without it the rows keep exactly the clipping and
 * flow they have today.
 */
.skf-motion .skf-texture > span { overflow: hidden; }

/*
 * The track is the one animated element. It holds two identical runs and
 * travels -50% of its own width, which is exactly one run, so the second
 * run arrives where the first started: no seam, no gap, no overlap.
 *
 * How many times the text repeats inside a run is decided at runtime by
 * measurement, because a short proverb in a wide row would otherwise run
 * out mid-journey and leave a blank stretch behind it.
 */
.skf-motion .skf-track {
	display: flex;
	width: max-content;
	will-change: transform;
	animation: skf-marquee-left var(--skf-drift, 60s) linear infinite;
}

/* The runs themselves never move; they are carried. */
.skf-motion .skf-track__run {
	display: block;
	flex: 0 0 auto;
	white-space: nowrap;
}

.skf-motion .skf-texture > span:nth-child(even) .skf-track { animation-name: skf-marquee-right; }

.skf-motion .skf-texture > span:nth-child(4n+1) .skf-track { --skf-drift: 55s; }
.skf-motion .skf-texture > span:nth-child(4n+2) .skf-track { --skf-drift: 70s; }
.skf-motion .skf-texture > span:nth-child(4n+3) .skf-track { --skf-drift: 45s; }
.skf-motion .skf-texture > span:nth-child(4n+4) .skf-track { --skf-drift: 65s; }

/*
 * Widget textures receive their final duration from motion.js after their
 * rendered run width is measured. This normalizes pixels-per-second against
 * the approved 75s footer wordmark instead of assigning unrelated fixed
 * durations to tracks of different physical lengths.
 */

/* ==========================================================================
   KINETIC HEADING — SKF UTTALANDE
   The real foreground heading moves. Same text, same face, same size, same
   colour: only its position changes, and only when an editor asks for it.
   ========================================================================== */

.skf-motion [data-skf-kinetic] .skf-statement__text > span {
	display: block;
	overflow: hidden;
}

/* Slow enough to read as editorial typography rather than a ticker. */
.skf-motion [data-skf-kinetic="left"] .skf-statement__text .skf-track {
	--skf-drift: 65s;
	animation-name: skf-marquee-left;
}

.skf-motion [data-skf-kinetic="right"] .skf-statement__text .skf-track {
	--skf-drift: 65s;
	animation-name: skf-marquee-right;
}

/* The editor's off switch, carried on the section wrapper. */
.skf-drift-off .skf-texture .skf-track,
.skf-motion .skf-drift-off .skf-texture .skf-track { animation: none; }

/* ==========================================================================
   MICRO INTERACTIONS
   Added only where the element has no transform of its own already.
   ========================================================================== */

.skf-link .skf-arrow,
.skf-btn .skf-arrow {
	transition: transform var(--skf-motion-micro) var(--skf-motion-ease);
}

.skf-link:hover .skf-arrow,
.skf-link:focus-visible .skf-arrow,
.skf-btn:hover .skf-arrow,
.skf-btn:focus-visible .skf-arrow {
	transform: translate3d(4px, 0, 0);
}

.skf-icon--external {
	transition: transform var(--skf-motion-micro) var(--skf-motion-ease);
}

a:hover .skf-icon--external,
a:focus-visible .skf-icon--external,
.skf-media-card:hover .skf-icon--external,
.skf-media-row:hover .skf-icon--external {
	transform: translate3d(2px, -2px, 0);
}

/*
 * A restrained lift on card imagery. Applied to the frame's image, inside
 * the existing clipped frame, so no geometry moves.
 */
.skf-media-card__frame img,
.skf-media-row__frame img,
.skf-gallery-card__frame img,
.skf-venue__media img,
.skf-mosaic__item img,
.skf-edition__media img {
	transition: transform 600ms var(--skf-motion-ease);
}

.skf-media-card:hover .skf-media-card__frame img,
.skf-media-row:hover .skf-media-row__frame img,
.skf-gallery-card:hover .skf-gallery-card__frame img,
.skf-venue:hover .skf-venue__media img,
.skf-mosaic__item:hover img,
.skf-edition:hover .skf-edition__media img {
	transform: scale(1.03);
}

/* ==========================================================================
   SQUIGGLE
   The existing orange line draws itself once, when it comes into view.
   The SVG is untouched: the same path, the same stroke, the same colour.
   Only the dash offset animates, and it finishes at zero — which is the
   line exactly as it is drawn today.
   ========================================================================== */

/*
 * This also supersedes the load-triggered draw on .skf-squiggle--draw.
 * That fired on a timer after page load, so a line further down the page
 * had already finished drawing before anyone scrolled to it.
 */
.skf-motion .skf-squiggle[data-skf-draw] path {
	stroke-dasharray: 300;
	stroke-dashoffset: 300;
	animation: none;
	transition: stroke-dashoffset 900ms var(--skf-motion-ease);
}

.skf-motion .skf-squiggle[data-skf-draw].skf-in path { stroke-dashoffset: 0; }

/* ==========================================================================
   STEPS
   The connecting rule draws downwards as the sequence arrives, because the
   progression is part of what the component means.
   ========================================================================== */

.skf-motion .skf-steps--timeline .skf-steps__step::before {
	transform: scaleY(0);
	transform-origin: top;
	transition: transform 700ms var(--skf-motion-ease);
	transition-delay: calc(var(--skf-motion-i, 0) * var(--skf-motion-step));
}

.skf-motion .skf-steps--timeline .skf-steps__step.skf-in::before { transform: scaleY(1); }

/* ==========================================================================
   REDUCED MOTION
   Everything stops; nothing hides. Content and function are unaffected.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {

	.skf-motion [data-skf-reveal] {
		opacity: 1;
		transform: none;
		transition: none;
		animation: none;
	}

	.skf-marquee,
	.skf-motion .skf-track {
		animation: none;
		transform: none;
	}

	.skf-link .skf-arrow,
	.skf-btn .skf-arrow,
	.skf-icon--external,
	.skf-media-card__frame img,
	.skf-media-row__frame img,
	.skf-gallery-card__frame img,
	.skf-venue__media img,
	.skf-mosaic__item img,
	.skf-edition__media img { transition: none; }

	.skf-link:hover .skf-arrow,
	.skf-btn:hover .skf-arrow,
	a:hover .skf-icon--external,
	.skf-media-card:hover .skf-media-card__frame img,
	.skf-media-row:hover .skf-media-row__frame img,
	.skf-gallery-card:hover .skf-gallery-card__frame img,
	.skf-venue:hover .skf-venue__media img,
	.skf-mosaic__item:hover img,
	.skf-edition:hover .skf-edition__media img { transform: none; }

	.skf-motion .skf-steps--timeline .skf-steps__step::before {
		transform: scaleY(1);
		transition: none;
	}

	/* The line is simply there, fully drawn. */
	.skf-motion .skf-squiggle[data-skf-draw] path {
		stroke-dashoffset: 0;
		transition: none;
	}
}


/* ==========================================================================
   FOOTER WORDMARK
   The existing oversized festival name, set in motion. Nothing about its
   type, colour, size or position changes — only where it sits on its line.
   ========================================================================== */

.skf-motion [data-skf-wordmark] { overflow: hidden; }

.skf-motion [data-skf-wordmark="left"] .skf-track {
	--skf-drift: 75s;
	animation-name: skf-marquee-left;
}

.skf-motion [data-skf-wordmark="right"] .skf-track {
	--skf-drift: 75s;
	animation-name: skf-marquee-right;
}

/* ==========================================================================
   DECORATIVE BAND
   Optional oversized type behind a section. Rendered only when an editor
   fills the control in, so no existing section's appearance changes.
   ========================================================================== */

.skf-decor {
	position: absolute;
	inset: 0;
	z-index: -1;
	display: flex;
	align-items: center;
	overflow: hidden;
	font-family: var(--font-display);
	font-size: clamp(4rem, 13vw, 12rem);
	line-height: 1;
	letter-spacing: var(--skf-track-display);
	text-transform: uppercase;
	color: currentColor;
	opacity: 0.06;
	pointer-events: none;
	user-select: none;
}

.skf-decor__track {
	/* Slow enough to read as atmosphere rather than a ticker. */
	--skf-marquee-duration: 48s;
}

.skf-decor__run {
	display: block;
	flex: 0 0 auto;
	white-space: nowrap;
	padding-right: 0.25em;
}

@media (prefers-reduced-motion: reduce) {
	.skf-decor__track { animation: none; }
}
