/*	jl-experience — sky, parallax, day/night, seasons and all animations.
	Ported from CraftHemsida/web/assets/style.css (the animation part).

	Rewrites against the source:
	– State classes sit on <body> (set by the body_class filter in PHP):
	  `#page.day` → `body.day #page`, `.day + #group-1` → `body.day #group-1`,
	  `.spring ~ #group-1` → `body.spring #group-1`.
	– Sun/moon (the #stellar img) is now a CSS background on #header-deep so
	  that the fallback markup contains no raw Sun.png.
	– Everything in this file is an enhancement layer: without it the fallback
	  image is shown and all decor divs collapse. */

:root {
	--refraction-day-1: rgba(255,160,180,.5);
	--refraction-day-2: rgba(255,127,50,.75);
	--refraction-night-1: rgba(160,140,210,.25);
	--refraction-night-2: rgba(255,127,180,.25);
	}

/*	The block's wrapper must not affect the layout — the layers behave as they
	do in the source DOM (direct flow children). Without the plugin the wrapper
	is an ordinary div around the fallback image. */
.wp-block-jl-hero-hero {
	display: contents;
	}
	.wp-block-jl-hero-hero .jl-hero__fallback {
		display: none;
		}

@keyframes fade-in {
	0% { opacity: 0; }
	100% { opacity: 1; }
	}
@keyframes fade-out {
	0% { opacity: 1; }
	100% { opacity: 0; }
	}
@keyframes keep-alive {
	0% { opacity: 1; }
	100% { opacity: 1; }
	}

/*	—————————————————————
	The sky
	*/
#page {
	position: absolute;
	width: 100vw;
	height: 100vh;
	z-index: -1000;
	background-size: cover;
	background-size: 100vw 65vmax;
	background-repeat: no-repeat;
	animation: fade-in 3s 1;
	}
	body.day #page {
		background-image:
		linear-gradient(
			-180deg,
			rgba(100,200,250,.75) 0%,
			rgba(200,200,200,.5) 40%,
			rgba(255,220,150,.5) 60%,
			rgba(255,255,255,1) 100%
			);
		}
		body.day.refraction #page {
			background-image:
			linear-gradient(
				-180deg,
				rgba(255,220,50,.125) 0%,
				rgba(255,150,50,.75) 40%,
				rgba(255,50,50,.5) 60%,
				rgba(255,255,255,1) 100%
				);
			}
	body.night #page {
		background-image:
		linear-gradient(
			180deg,
			rgb(0,0,10) 0%,
			rgb(0,30,50) 20%,
			rgb(0,120,130) 60%,
			rgb(255,255,255) 100%);
		}
		body.night.refraction #page {
			background-image:
			linear-gradient(
				180deg,
				rgb(50,150,180) 0%,
				rgb(180,110,140) 40%,
				rgb(220,150,100) 60%,
				rgb(255,255,255) 100%);
			}

/*	—————————————————————
	Parallax structure
	*/
.group.parallax {
	position: relative;
	margin: 0 auto;
	width: calc(100vw + 2px);
	margin-left: -1px;
	min-height: calc(50vw + 2px);
	float: left;
	}
.layer {
	position: absolute;
	width: 100%;
	min-height: 50vw;
	height: calc(100% + 1px);
	}
	.fore, .base, .back, .deep {
		background-size: contain;
		background-repeat: no-repeat;
		background-position-x: center;
		transition: .1s transform ease;
		will-change: transform;
		transition-delay: 0;
		overflow: visible;
		}
		.fore {
			z-index: 10;
			animation: fade-in 5s;
			animation-iteration-count: 1;
			}
		.base {
			z-index: 0;
			}
		.back {
			z-index: -10;
			animation: fade-in 1s;
			animation-iteration-count: 1;
			}
		.deep {
			z-index: -100;
			animation: fade-in 3s 1, keep-alive .5s infinite;
			overflow: visible;
			}

	/*	Content groups: the decor layer hangs at the TOP of the section and ties
		the tree silhouette above to the roots below (#group-2 > .base =
		2_Base.png). The height is the source's 50vw; the background is drawn
		top-aligned.

		It MUST be absolutely positioned. The source let the layer flow and got
		away with it, because the text column floated out of its #welcome and
		left that wrapper 0px tall — so the layer ended up at the top anyway.
		When the column stopped floating (WP's constrained layout centres with
		auto margins, which floats ignore) #welcome gained real height and
		pushed the roots down below the content. The positioning must not depend
		on a wrapper happening to have no height. */
	.group.content > .base,
	.group.content > .layer {
		position: absolute;
		top: 0;
		left: 0;
		display: block;
		min-height: 50vw;
		height: auto;
		}

/*	—————————————————————
	The hero group (#group-1)

	Every image below is a slot that can be swapped in the hero block's
	settings (#75). Each is read as
		var(--jl-experience-<slot>, url(<the original artwork>))
	where the custom property is set on the block's wrapper by the render
	callback, only for the slots that have been given an image. The fallback
	url() is the original, so an empty slot draws exactly what it always has.
	The slot list and these paths live in includes/hero-images.php as well -
	keep them in step.

	The fallbacks are ROOT-RELATIVE, unlike every other url() in this file,
	and must stay that way. A relative url() inside var() resolved against
	this stylesheet in Chrome (measured), but whether Safari does the same
	was not measurable here - and a Safari that resolved it against the page
	instead would lose the sun, the moon and every tree for all visitors, with
	no slot chosen at all. A root-relative path means the same thing to every
	engine, whichever base URL it picks.

	Masks use only an image's transparency; the colour comes from the gradient
	underneath. The colours in the seasonal PNGs are leftovers from before they
	became masks and never reach the screen.
	*/
#group-1 > * {
	background-position-y: bottom;
	}

/*	Not a slot: this applies only without a season class, and the plugin
	always sets one on the views that carry the hero. The same picture is the
	theme's fallback image, which is swapped in the block's settings. */
#group-1 > .base {
	background-image: url("../assets/1_Base.png");
	}
	body.spring #group-1 > .base,
	body.summer #group-1 > .base,
	body.autumn #group-1 > .base,
	body.winter #group-1 > .base {
		background-image: linear-gradient(
			180deg,
			rgb(100,100,100),
			rgb(50,50,50)
		);
		/*	ONLY -webkit-mask-* — exactly like the live CSS, which is proven to
			work in Safari. Standard longhands plus -webkit- in the same rule
			was the port's only deviation when the forest failed to appear in
			Safari 18. */
		-webkit-mask-size: contain;
		-webkit-mask-repeat: no-repeat;
		-webkit-mask-position: bottom;
	}
	body.spring #group-1 > .base {
		-webkit-mask-image: var(--jl-experience-base-spring, url("/wp-content/plugins/jl-experience/assets/seasons/1_Base-spring.png"));
		}
	body.summer #group-1 > .base {
		-webkit-mask-image: var(--jl-experience-base-summer, url("/wp-content/plugins/jl-experience/assets/seasons/1_Base-summer.png"));
		}
	body.autumn #group-1 > .base {
		-webkit-mask-image: var(--jl-experience-base-autumn, url("/wp-content/plugins/jl-experience/assets/seasons/1_Base-autumn.png"));
		}
	body.winter #group-1 > .base {
		-webkit-mask-image: var(--jl-experience-base-winter, url("/wp-content/plugins/jl-experience/assets/seasons/1_Base-winter.png"));
		}

#group-1 > .back {
	border-bottom: 10em solid rgb(77,77,77);
	background-image: linear-gradient(
		180deg,
		rgb(100,120,100),
		rgb(55,55,55)
	);
	-webkit-mask-size: contain;
	-webkit-mask-repeat: no-repeat;
	/*	Anchored to the hero's bottom, not centred (#127). Back and base share
		one canvas size, so the forests line up only while their canvases'
		bottoms keep a fixed relation. Centred in a box of hero + 10em border,
		the back followed half the hero's height: fine on desktop, where the
		hero is 50vw, but under 600px it is 50vh, and tall narrow windows got a
		band of sky under the back forest. "100% - 10em" is the hero's bottom
		(the box minus this border, in the same em); "+ 5vw" is the offset
		desktop always had. */
	-webkit-mask-position: 50% calc(100% - 10em + 5vw);
	-webkit-mask-image: var(--jl-experience-back, url("/wp-content/plugins/jl-experience/assets/seasons/1_Back-autumn.png"));
	}
	/*	Not a slot: the rain has never been enabled on the site and is
		unfinished (Jonas, 2026-09-12). It stays as it is, like the dormant
		bats and shimmer below, until the effect is ready. */
	body.rain #group-1 > .back {
		-webkit-mask-image: url("../assets/weather/rain.png");
		-webkit-mask-type: luminance;
		-webkit-mask-size: cover;
		mask-image: url("../assets/weather/rain.png");
		mask-type: luminance;
		mask-size: cover;
		animation: rain 2s linear infinite;
		}
		@keyframes rain {
			0% {
				-webkit-mask-position: 0 0;
				mask-position: 0 0;
				}
			50% {
				-webkit-mask-position: 0 1000px;
				mask-position: 0 1000px;
				}
			100% {
				-webkit-mask-position: 0 2500px;
				mask-position: 0 2500px;
				}
			}

	body.day #group-1 > .back {
		background-image: linear-gradient(
			180deg,
			rgb(160,200,220),
			rgb(55,55,55)
		);
	}
	body.day.refraction #group-1 > .back {
		background-image: linear-gradient(
			180deg,
			rgb(180,120,100),
			rgb(55,55,55)
		);
	}
	body.night #group-1 > .back {
		background-image: linear-gradient(
			180deg,
			rgb(60,120,140),
			rgb(55,55,55)
		);
	}
	body.night.refraction #group-1 > .back {
		background-image: linear-gradient(
			180deg,
			rgb(180,100,140),
			rgb(55,55,55)
		);
	}

#group-1 > .deep {
	will-change: opacity;
	background: rgba(255,255,255,0);
	mix-blend-mode: screen;
	background-blend-mode: screen;
	}
	/*	Sun/moon: in the source an <img id="stellar"> whose src is swapped
		server-side (Sun.png by day, Moon.png with stars by night — Moon.png
		exists only on the live server, downloaded from there). Here it is a
		background on the layer. Day: a glow gradient on top of the sun. */
	body #group-1 > .deep {
		background-image: var(--jl-experience-sun, url("/wp-content/plugins/jl-experience/assets/Sun.png"));
		background-size: contain;
		background-repeat: no-repeat;
		background-position-x: center;
		background-position-y: bottom;
		}
	body.day #group-1 > .deep {
		background-image:
		radial-gradient(
			circle at 51% 42.5%,
			rgba(255,255,50,.5) 15%,
			rgba(255,255,200,.5) 20%,
			rgba(255,255,200,.5) 28%,
			rgba(255,255,255,0) 35%
			),
		var(--jl-experience-sun, url("/wp-content/plugins/jl-experience/assets/Sun.png"));
		}
	body.night #group-1 > .deep {
		background-image: var(--jl-experience-moon, url("/wp-content/plugins/jl-experience/assets/Moon.png"));
		}

/*	—————————————————————
	Decorative backgrounds in the content groups
	*/
#group-2 > * {
	background-position-y: top;
	}
/*	The top decor - the roots by default - replaceable per page ("Dekor
	överst", #131; includes/ground-image.php). Root-
	relative fallback for the same reason as the hero's slots above. */
#group-2 > .base {
	background-image: var(--jl-experience-ground, url("/wp-content/plugins/jl-experience/assets/2_Base.png"));
	margin-top: -3px;
	}
#group-3 > * {
	background-position-y: top;
	}
/*	The paint splash is lifted inside its section (#129). 3_Base.png is a sheet
	in the dark surface's exact colour with holes for the white; its top 14.3vw
	(at its highest peak) to 34vw is solid, which read as too much space below
	the content once that content had moved up (#122).

	Everything moves inside #group-4: the image and the drips go up by the
	lift, and the section is shortened by it. Pulling the section itself up
	instead would lay the artwork's opaque top over the end of the text. The
	layer boxes keep their 50vw height, so the drips' percentage positions
	still land where they did on the artwork - which makes the layers reach
	the lift's depth past the section into #group-3, transparent there, hence
	no pointer events. */
#group-4 {
	--jl-experience-paint-lift: 8vw;
	min-height: calc(50vw + 2px - var(--jl-experience-paint-lift));
	}
#group-4 > * {
	background-position-y: calc(-1 * var(--jl-experience-paint-lift));
	}
#group-4 > .layer {
	pointer-events: none;
	}
	#group-4 .paint {
		margin-top: calc(-1 * var(--jl-experience-paint-lift));
		}
#group-4 > .base {
	background-image: url("../assets/3_Base.png");
	margin-top: -3px;
	}
#group-4 > .back {
	background-image: url("../assets/grid.png");
	margin-top: -3px;
	image-rendering: pixelated;
	background-size: contain;
	z-index: -1;
	}

.lazy-anchor {
	z-index: -10000;
	height: 1px;
	width: 1px;
	background: transparent;
	position: absolute;
	bottom: 0;
	left: calc(50% - .5px);
	}

/*	—————————————————————
	The eyes in the dark

	Placement, size, sprite and timing are GENERATED from the motif registry
	(includes/motifs.php, #139) and added inline after this file. Only the
	keyframes - the shape of each motion - live here.
	*/
@keyframes eyes-blink {
	0% { background-position: 0; }
	100% { background-position: -640px; }
}
@keyframes eyes-fade {
	0%, 18% { opacity: 1; }
	20%, 100% { opacity: 0; }
}
@keyframes eyes-scale {
	0% { transform: scale(1); }
	50% { transform: scale(.75); }
	100% { transform: scale(.5); }
}

/*	—————————————————————
	Running paint

	Generated from the motif registry like the eyes (#139). Keyframes only.
	*/
@keyframes dripping {
	0% { background-position: 0; }
	100% { background-position: -768px; }
}

/*	—————————————————————
	Bats (dormant — no markup renders them today)
	*/
.bat {
	width: 64px;
	height: 64px;
	background: url("../assets/Bat.png") left center;
	background-size: cover;
	animation: bat-fly .5s steps(10) infinite alternate, travel-horizon-right 15s infinite;
	will-change: transform;
	z-index: 10;
	position: absolute;
	opacity: 1;
	}
.bat:nth-of-type(1) {
	animation: bat-fly .5s steps(10) infinite,
	travel-horizon-right 30s infinite;
	}
.bat:nth-of-type(2) {
	animation: bat-fly .5s steps(10) infinite,
	travel-horizon-right-2 14s infinite;
	}
.bat:nth-of-type(3) {
	animation: bat-fly .5s steps(10) infinite,
	travel-horizon-right-3 12s infinite;
	}

@keyframes bat-fly {
	0% { background-position: 0; }
	100% { background-position: -640px; }
	}
@keyframes travel-horizon-right {
	0% { transform: translate(-80vw,50vmin) scale(1); }
	50% { transform: translate(200vw,40vmin) scale(.5); }
	75% { transform: translate(20vw,20vmin) scale(1); }
	100% { transform: translate(-80vw,50vmin) scale(2); }
	}
@keyframes travel-horizon-right-2 {
	0% { transform: translate(-40vw,70vmin) scale(1); }
	30% { transform: translate(20vw,30vmin) scale(.5); }
	100% { transform: translate(130vw,50vmin) scale(2); }
	}
@keyframes travel-horizon-right-3 {
	0% { transform: translate(-60vw,60vmin) scale(.5); }
	80% { transform: translate(95vw,30vmin) scale(.5); }
	100% { transform: translate(100vw,20vmin) scale(.125); }
	}

/*	—————————————————————
	Shimmer (dormant — no markup today)
	*/
.shimmer {
	z-index: 10000;
	pointer-events: none;
	position: fixed;
	width: 200%;
	height: 200%;
	top: -50%;
	left: -50%;
	animation: shimmer 10s infinite alternate;
	transform-origin: center;
	mix-blend-mode: overlay;
	opacity: .25;
	background: radial-gradient(
		rgba(0,255,0,0) 10%,
		rgba(0,255,0,1) 25%
	);
}
@keyframes shimmer {
	0%, 100% {
		transform: scale(1);
		background: radial-gradient(
			rgba(0,255,0,0) 10%,
			rgba(0,255,0,1) 25%
		);
		}
	50% {
		transform: scale(5);
		background: radial-gradient(
			rgba(0,255,0,0) 10%,
			rgba(0,255,0,1) 15%
		);
	}
}

.fade {
	opacity: 0;
}

/*	—————————————————————
	Motion off (#142)

	html.jl-motion-still is the signal the accessibility plugin sets when a
	visitor, or their system, has switched motion off, and that plugin then
	finishes every CSS animation and transition at once (#148). That covers
	the layers: their entrance fades end on the layer shown, and their
	parallax transitions snap. They used to be listed here by name.

	What this plugin still owns is a still state that differs from where the
	animation ends: the decor motifs', from the registry (includes/motifs.php,
	generated inline) - the eyes hide, the drips hold a frame. The parallax and
	smooth scrolling are JavaScript, out of CSS's reach, and are switched in
	js/ux.js and the inline SmoothScroll setup. */

/*	—————————————————————
	Mobile
	*/
@media only screen and (max-width: 600px) {
	.group.parallax {
		min-height: 50vw;
		}
	#group-1 {
		height: 50vh;
		}
		/*	The source's "#group-1 .deep img { margin-left:-52.5%; width:200% }"
			translated into a background: 200% width, 52.5% horizontal
			position. */
		#group-1 > .deep,
		body.day #group-1 > .deep,
		body.night #group-1 > .deep {
			background-size: 200% auto;
			background-position-x: 52.5%;
		}
		#group-2 > .base {
			background-position-y: 1em;
			box-shadow: inset 0 2em 0 0 rgb(50,50,50);
			}
	@keyframes eyes-scale {
		0% { transform: scale(.5); }
		50% { transform: scale(.35); }
		100% { transform: scale(.25); }
		}
	}

@media only screen and (min-width: 1280px) {
	.fore, .base, .back, .deep {
		transition: .25s transform ease;
		}
	}

/*	Note: prefers-reduced-motion is still not read HERE, and that is on purpose.
	The port used to ignore it entirely - a bare media-query guard made the
	parallax and animations feel broken rather than calm. Since #142 the system
	setting counts again, but through the accessibility plugin: it decides
	html.jl-motion-still (system first, the visitor's own choice overriding),
	and this file only draws what still looks like under that class - a
	composed state per motif rather than whatever each animation leaves behind.
	Without that plugin the site runs every animation, as the original does. */
