/*
 * emo2026, artefact floaters.
 *
 * The isolator glyphs drift faintly behind the large surfaces (home
 * hero, product-line hero, editorial pages, shop, footer), the way the
 * PlayStation home screen lets its symbols float: many small outlines at
 * different depths, slow drift, slow turn, a soft breathing fade.
 * Replaces the single static shapes of flair.css (2026-10-01).
 *
 * assets/js/artefact-floaters.js injects one aria-hidden layer per
 * surface and sets each glyph's geometry and timing as custom properties
 * (--a-size, --a-depth, --a-rot, --a-spin, --a-dx, --a-dy, --a-dur,
 * --a-breathe, --a-delay). This file paints and moves them. Glyph
 * files: assets/img/artefacts/, sources in design/glyphs/.
 *
 * Faint by rule: the layer sits behind the content (z-index -1 in the
 * surface's own stacking context) and the script keeps glyphs off the
 * copy. Motion is transform and opacity only, so it stays on the
 * compositor.
 */

/* Surfaces that paint their own background need a local stacking
 * context, or the z-index -1 layer would sink under that background. */
.has-artefacts { position: relative; }
.has-artefacts--isolated { isolation: isolate; }

/* The footer columns keep their place above the layer. */
.site-footer.has-artefacts .site-footer__inner {
	position: relative;
	z-index: 1;
}

.artefact-floaters {
	position: absolute;
	inset: 0;
	z-index: -1;
	overflow: hidden;
	pointer-events: none;
	/* Ink per tone, faintness per tone: the dark hero carries the lime
	 * accent, light surfaces the brand green barely above the ground. */
	--a-ink: var(--brand-emo-core);
	--a-alpha: 0.17;
}

.artefact-floaters--signal {
	--a-ink: var(--brand-emo-signal);
	--a-alpha: 0.24;
}

.artefact {
	position: absolute;
	width: var(--a-size);
	height: var(--a-size);
	background: var(--a-ink);
	/* Far glyphs (depth 0) at 60 percent of the tone's alpha, near ones
	 * at full: the depth cue without a blur filter on every element. */
	opacity: calc(var(--a-alpha) * (0.6 + 0.4 * var(--a-depth)));
	transform: rotate(var(--a-rot));
	-webkit-mask: var(--a-glyph) center / contain no-repeat;
	mask: var(--a-glyph) center / contain no-repeat;
	will-change: transform, opacity;
	animation:
		artefact-drift var(--a-dur) ease-in-out var(--a-delay) infinite alternate,
		artefact-breathe var(--a-breathe) ease-in-out var(--a-delay) infinite alternate;
}

.artefact--barrier   { --a-glyph: url("../img/artefacts/barrier.svg"); }
.artefact--coil      { --a-glyph: url("../img/artefacts/coil.svg"); }
.artefact--crossover { --a-glyph: url("../img/artefacts/crossover.svg"); }
.artefact--earth     { --a-glyph: url("../img/artefacts/earth.svg"); }
.artefact--plates    { --a-glyph: url("../img/artefacts/plates.svg"); }
.artefact--port      { --a-glyph: url("../img/artefacts/port.svg"); }
.artefact--pulse     { --a-glyph: url("../img/artefacts/pulse.svg"); }
.artefact--surge     { --a-glyph: url("../img/artefacts/surge.svg"); }

/* A gentle curve rather than a straight line: out along x, then down
 * along y, then back, mirrored by `alternate`. The turn rides along. */
@keyframes artefact-drift {
	0%   { transform: translate(0, 0) rotate(var(--a-rot)); }
	50%  { transform: translate(var(--a-dx), calc(var(--a-dy) * 0.35)) rotate(calc(var(--a-rot) + var(--a-spin) * 0.5)); }
	100% { transform: translate(calc(var(--a-dx) * 0.3), var(--a-dy)) rotate(calc(var(--a-rot) + var(--a-spin))); }
}

/* Breathing only lowers the glyph a little, never lifts it past the
 * tone's ceiling, so the faintness rule holds at every frame. */
@keyframes artefact-breathe {
	from { opacity: calc(var(--a-alpha) * (0.6 + 0.4 * var(--a-depth))); }
	to   { opacity: calc(var(--a-alpha) * (0.6 + 0.4 * var(--a-depth)) * 0.7); }
}

/* Pointer parallax, desktop only: the script sets --a-px / --a-py on
 * the layer from the mouse position, near glyphs follow further than
 * far ones. `translate` is its own property, so it adds to the drift's
 * transform instead of replacing it, and the transition smooths it. */
@media (hover: hover) and (pointer: fine) and (min-width: 1024px) {
	.artefact {
		translate: calc(var(--a-px, 0px) * (0.3 + var(--a-depth))) calc(var(--a-py, 0px) * (0.3 + var(--a-depth)));
		transition: translate 1200ms cubic-bezier(0.22, 1, 0.36, 1);
	}
}

/* Reduced motion. Owner exemption (2026-10-01), same as the logo
 * strip: on a desktop the drift keeps running at its normal pace,
 * because the owner's own machines report "reduce" (Windows animation
 * effects off over remote desktop) and the floaters are a faint
 * background, not content. Only the pointer parallax stops.
 *
 * A first version halved the speed here with calc() on the durations.
 * That was worse on both counts: Edge crawled at half speed, which the
 * owner found irritating rather than calm, and Firefox dropped the
 * calc()'d duration to 0s and showed no motion at all. No time maths
 * in this file for that reason. */
@media (prefers-reduced-motion: reduce) {
	.artefact {
		translate: none;
		transition: none;
	}
}

/* Phones, tablets, touch screens: under "reduce" the glyphs stand
 * still. Spelled as three plain queries, not a nested not(), so every
 * engine reads it the same way. */
@media (prefers-reduced-motion: reduce) and (max-width: 1023.98px),
	(prefers-reduced-motion: reduce) and (hover: none),
	(prefers-reduced-motion: reduce) and (pointer: coarse) {
	.artefact { animation: none; }
}

@media print {
	.artefact-floaters { display: none; }
}
