/**
 * masterE Loop Skeleton — v0.21.0
 *
 * Shimmer loading veil for Elementor Pro's NATIVE Loop Carousel + Loop Grid
 * widgets (we don't own them — controls are injected by
 * MFK_Loop_Skeleton_Controls). While a card's content is still loading, an
 * opaque shimmer covers it; the veil fades out per card when the card's
 * images have settled and (for carousels) Swiper has initialized. The veil
 * is a ::after OVERLAY on each .e-loop-item — the real content is
 * server-rendered underneath, so there is zero layout shift and nothing to
 * clean up.
 *
 * Gating (every rule requires the per-widget opt-in class `mfk-lskel-on`,
 * written by the injected SWITCHER's prefix_class — nothing generic is ever
 * styled):
 *   - LIVE:   html.mfk-lskel-js (set by a tiny wp_head bootstrap; absent =
 *             JS off = no veil ever) + body:not(.elementor-editor-active).
 *             The editor exclusion is REQUIRED, not belt-and-braces: the
 *             bootstrap also runs in the canvas iframe, and the lifecycle JS
 *             bails there, so without it the canvas would veil permanently.
 *   - CANVAS: body.elementor-editor-active + the "Preview skeleton in
 *             editor" switch (`mfk-lskel-preview-on`) — CSS-only, so Hagai
 *             can style the shimmer live; never matches on the live site.
 *
 * The shimmer recipe is the MVS house skeleton ("skeleton, never a spinner")
 * on `--mfk-lskel-*` vars; the fallbacks ARE the shipped look.
 *
 * SHAPE MARKERS (v0.22.0): the designer may add the class `mfk-skel`
 * (Elementor: Advanced → CSS Classes) to inner containers/widgets of the
 * loop template. When a card contains marked elements, the whole-item veil
 * stands down (`:has()` — decided at first paint) and each marked element
 * carries its own shimmer veil instead; unmarked content is
 * visibility-hidden until the card reveals (true-skeleton look, layout
 * preserved — zero CLS; Hagai's 2026-07-23 decision). Shape veils default
 * to `border-radius: inherit` — the container's own designed corners — and
 * the radius control overrides. No marks = the 0.21.0 whole-item veil,
 * byte-identical. Legacy browsers without `:has()` keep the whole-item
 * veil alongside the shape veils (cosmetic only, self-heals on reveal).
 *
 * DO NOT add a transform to any reveal/entrance animation here. A
 * fill-mode-persisted transform (even translateY(0)) makes the slide a
 * containing block that traps position:fixed descendants — the MVS 2.9.0
 * lesson. The reveal is opacity-only BY DESIGN.
 */

/* Positioning context for the veil. :where() keeps specificity at zero so
 * any loop-template rule on the item always wins. */
:where(.mfk-lskel-on) .e-loop-item,
:where(.mfk-lskel-on) .mfk-skel {
	position: relative;
}

/* ── Pre-init layout emulation (v0.24.0) ─────────────────────────────────── */

/* Kills the "one card, then the rest pop up" flash: before Swiper boots,
 * Loop Carousel slides have no carousel sizing (one slide fills the
 * container; the rest appear only when Swiper stamps inline widths). PHP
 * (MFK_Loop_Skeleton_Controls::stamp_layout_vars) stamps the widget's own
 * Slides-to-show / spacing as inline `-d/-t/-m` vars on the wrapper; they
 * resolve HERE per breakpoint — the consumed names are set only in this
 * stylesheet because inline vars can't be overridden by media queries.
 * Elementor DEFAULT breakpoints (1024/767) — an approximation; the real
 * layout takes over at init. The emulation self-resolves the moment Swiper
 * adds its init class; with JS off it leaves a clean static N-column strip
 * (better than the one-giant-card fallback). Fallback chains mirror
 * Elementor's breakpoint inheritance (mobile ← tablet ← desktop). */
.mfk-lskel-on .swiper {
	--mfk-lskel-cols: var(--mfk-lskel-cols-d, 3);
	--mfk-lskel-gap: var(--mfk-lskel-gap-d, 0px);
}

@media (max-width: 1024px) {
	.mfk-lskel-on .swiper {
		--mfk-lskel-cols: var(--mfk-lskel-cols-t, var(--mfk-lskel-cols-d, 3));
		--mfk-lskel-gap: var(--mfk-lskel-gap-t, var(--mfk-lskel-gap-d, 0px));
	}
}

@media (max-width: 767px) {
	.mfk-lskel-on .swiper {
		--mfk-lskel-cols: var(--mfk-lskel-cols-m, var(--mfk-lskel-cols-t, var(--mfk-lskel-cols-d, 3)));
		--mfk-lskel-gap: var(--mfk-lskel-gap-m, var(--mfk-lskel-gap-t, var(--mfk-lskel-gap-d, 0px)));
	}
}

.mfk-lskel-on .swiper:not(.swiper-initialized):not(.swiper-container-initialized) .swiper-wrapper {
	display: flex;
	flex-wrap: nowrap;
	overflow: hidden;
	gap: var(--mfk-lskel-gap, 0px);
}

/* Swiper's own width formula ((container − gap×(N−1)) / N) → near-pixel
 * handoff when the real inline widths land at init. */
.mfk-lskel-on .swiper:not(.swiper-initialized):not(.swiper-container-initialized) .e-loop-item {
	flex: 0 0 auto;
	min-inline-size: 0;
	inline-size: calc((100% - (var(--mfk-lskel-cols, 3) - 1) * var(--mfk-lskel-gap, 0px)) / var(--mfk-lskel-cols, 3));
}

/* ── The veil ────────────────────────────────────────────────────────────── */

html.mfk-lskel-js body:not(.elementor-editor-active) .mfk-lskel-on .e-loop-item::after,
body.elementor-editor-active .mfk-lskel-on.mfk-lskel-preview-on .e-loop-item::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 99;
	/* Purely visual — a veil (even a stuck one) must never trap clicks. */
	pointer-events: none;
	border-radius: 6px;
	background: linear-gradient(
		90deg,
		var(--mfk-lskel-base, #ededee) 25%,
		var(--mfk-lskel-high, #f6f7f7) 50%,
		var(--mfk-lskel-base, #ededee) 75%
	);
	background-size: 200% 100%;
	animation: mfk-lskel-shimmer var(--mfk-lskel-speed, 1.4s) linear infinite;
	opacity: 1;
	/* visibility flips exactly when the fade (delay + duration) completes,
	 * removing the layer from paint. --mfk-lskel-delay is the JS-set
	 * per-card stagger. */
	transition:
		opacity var(--mfk-lskel-fade, 400ms) cubic-bezier(0.4, 0, 0.2, 1) var(--mfk-lskel-delay, 0ms),
		visibility 0s linear calc(var(--mfk-lskel-fade, 400ms) + var(--mfk-lskel-delay, 0ms));
}

/* ── Shape markers (v0.22.0) ─────────────────────────────────────────────── */

/* When the card declares shapes, the whole-item veil stands down. :has()
 * decides at FIRST PAINT (a JS-added class would flash the item veil
 * first); browsers without :has() simply keep both veils. */
html.mfk-lskel-js body:not(.elementor-editor-active) .mfk-lskel-on .e-loop-item:has(.mfk-skel)::after,
body.elementor-editor-active .mfk-lskel-on.mfk-lskel-preview-on .e-loop-item:has(.mfk-skel)::after {
	content: none;
}

/* Each marked element carries its own veil — the item-veil declaration
 * block, except the radius defaults to the container's OWN corners. */
html.mfk-lskel-js body:not(.elementor-editor-active) .mfk-lskel-on .e-loop-item .mfk-skel::after,
body.elementor-editor-active .mfk-lskel-on.mfk-lskel-preview-on .e-loop-item .mfk-skel::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 99;
	pointer-events: none;
	border-radius: inherit;
	background: linear-gradient(
		90deg,
		var(--mfk-lskel-base, #ededee) 25%,
		var(--mfk-lskel-high, #f6f7f7) 50%,
		var(--mfk-lskel-base, #ededee) 75%
	);
	background-size: 200% 100%;
	animation: mfk-lskel-shimmer var(--mfk-lskel-speed, 1.4s) linear infinite;
	opacity: 1;
	transition:
		opacity var(--mfk-lskel-fade, 400ms) cubic-bezier(0.4, 0, 0.2, 1) var(--mfk-lskel-delay, 0ms),
		visibility 0s linear calc(var(--mfk-lskel-fade, 400ms) + var(--mfk-lskel-delay, 0ms));
}

/* v0.23.0 — JS-mirrored radius: an mfk-skel mark on an IMAGE widget sits on
 * the widget wrapper (radius 0) while the rounding lives on the inner <img>
 * (pseudo-elements can't attach to a replaced element). The lifecycle JS
 * copies the img's computed corners onto the mark (class + var are always
 * set together, so the var can never be missing). The panel Radius control
 * overrides everything via its !important selector value. */
html.mfk-lskel-js body:not(.elementor-editor-active) .mfk-lskel-on .e-loop-item .mfk-skel.mfk-lskel-rmirror::after {
	border-radius: var(--mfk-lskel-shape-radius);
}

/* True-skeleton look: while a shaped card loads, unmarked content is
 * invisible (visibility preserves layout — zero CLS). The marked elements
 * re-enable themselves (visibility resets down the tree) and their own
 * children sit under the opaque shape veil. Restores the instant the JS
 * adds mfk-lskel-done — every 0.21.0 failsafe (8s bootstrap revoke, 7s
 * per-item force-reveal, JS-off = rule never matches) wraps this too. */
html.mfk-lskel-js body:not(.elementor-editor-active) .mfk-lskel-on .e-loop-item:has(.mfk-skel):not(.mfk-lskel-done) > *,
body.elementor-editor-active .mfk-lskel-on.mfk-lskel-preview-on .e-loop-item:has(.mfk-skel) > * {
	visibility: hidden;
}

html.mfk-lskel-js body:not(.elementor-editor-active) .mfk-lskel-on .e-loop-item:not(.mfk-lskel-done) .mfk-skel,
body.elementor-editor-active .mfk-lskel-on.mfk-lskel-preview-on .e-loop-item .mfk-skel {
	visibility: visible;
}

/* ── Reveal (JS adds the classes per card) ───────────────────────────────── */

html.mfk-lskel-js .mfk-lskel-on .e-loop-item.mfk-lskel-done::after,
html.mfk-lskel-js .mfk-lskel-on .e-loop-item.mfk-lskel-done .mfk-skel::after {
	opacity: 0;
	visibility: hidden;
}

/* Instant path — swiper loop-mode clones and off-viewport cards skip the
 * fade so they never flash shimmer. */
html.mfk-lskel-js .mfk-lskel-on .e-loop-item.mfk-lskel-instant::after,
html.mfk-lskel-js .mfk-lskel-on .e-loop-item.mfk-lskel-instant .mfk-skel::after {
	transition: none;
}

/* v0.24.1 — the wave sweeps RIGHT→LEFT (the RTL reading direction), flipped
 * at the KEYFRAME level together with every other masterE skeleton
 * (mvs-pe-shimmer / mvs-skel-shimmer in MVS 2.17.1 + mfk-tabs-shimmer) per
 * Hagai's 2026-07-23 direction decision — one global physical direction,
 * no [dir] rules, all skeletons stay matched. */
@keyframes mfk-lskel-shimmer {
	0% { background-position: -200% 0; }
	100% { background-position: 200% 0; }
}

@media (prefers-reduced-motion: reduce) {
	.mfk-lskel-on .e-loop-item::after,
	.mfk-lskel-on .mfk-skel::after {
		animation: none;
	}
}
