/**
 * Spark Media Optimizer — frontend LQIP blur-up reveal.
 *
 * The delivery layer paints a tiny, pre-blurred grayscale placeholder as the
 * <img>'s OWN background-image (set inline, server-side) so it appears instantly
 * with ZERO layout shift — the image keeps its intrinsic width/height. The real,
 * full-color bitmap decodes on top; once it has loaded, smo-frontend.js adds
 * `smo-lqip-loaded`, which removes the placeholder background so transparent PNGs
 * stay transparent and the real image is shown verbatim (no grey box behind it).
 *
 * Graceful degradation: if the script never runs, the decoded image still paints
 * over the background, so images always display correctly. The placeholder is a
 * static data-URI baked into the (cacheable) HTML, so it survives page caching.
 *
 * Class contract (set server-side by the frontend delivery class):
 *   img.smo-lqip          blurred-grey placeholder painted behind the image
 *   img.smo-lqip-loaded   added by JS once the real image has loaded → reveal
 */

:root {
	--smo-lqip-reveal: 0.4s;
}

/* Placeholder: cover the image box with the inline blurred-grey data-URI. */
.smo-lqip {
	background-repeat: no-repeat;
	background-size: cover;
	background-position: center;
}

/*
 * Revealed: smo-frontend.js clears the inline placeholder so transparency is
 * preserved and the real (color) image is shown exactly, with a short opacity
 * wash so the swap feels smooth. The fade is on the element, never a blur on
 * the real bitmap.
 */
.smo-lqip-loaded {
	background-image: none;
	animation: smo-lqip-in var(--smo-lqip-reveal) ease both;
}

@keyframes smo-lqip-in {
	from {
		opacity: 0.8;
	}

	to {
		opacity: 1;
	}
}

/* Respect reduced-motion: reveal instantly, no fade. */
@media (prefers-reduced-motion: reduce) {
	.smo-lqip-loaded {
		animation: none;
	}
}
