/**
 * littleextra/stepper — front-end + editor-canvas styles (block.json "style").
 *
 * Model: each step is a positioned div. The connector is a thin BAR (a child
 * element, not a literal border, so its ends can round) pinned to the step's
 * leading edge — the left edge when vertical, the top edge when horizontal. The
 * fill is a `::before` over that bar. The marker is absolutely positioned on the
 * bar, anchored to the step edges. The content is normal-flow blocks in the step,
 * cleared by padding. Orbit reuses the same idea with the ring drawn as a
 * bordered circle (crisp) plus a conic fill arc.
 *
 * Vertical is the mobile-first base; `.is-horizontal` switches to a row at
 * >=782px. Colors come from tokens via custom properties (marker text/bg/border +
 * hover, connector line + fill); the marker renders the "-c" current colors,
 * which the fill engine (hover progression + loop) swaps to the hover colors.
 * Two structural dims are overridable: `--le-marker-size` (spacing token) and
 * `--le-connector-size` (bar thickness, also set from the Thickness control).
 */

@property --le-progress {
	syntax: "<number>";
	inherits: true;
	initial-value: 0;
}

.le-stepper {
	--le-marker-size: var(--wp--preset--spacing--70);
	--le-connector-size: 2px;
	--le-marker-border-size: 2px; /* marker outline — independent of connector thickness */
	--le-marker-gap: var(--wp--preset--spacing--40);
	--le-gap: var(--wp--preset--spacing--50);

	--le-mk-text: var(--wp--preset--color--ink);
	--le-mk-bg: var(--wp--preset--color--background);
	--le-mk-border: var(--wp--preset--color--hairline);
	--le-mk-text-hover: var(--le-mk-text);
	--le-mk-bg-hover: var(--le-mk-bg);
	--le-mk-border-hover: var(--le-mk-border);
	--le-mk-text-c: var(--le-mk-text);
	--le-mk-bg-c: var(--le-mk-bg);
	--le-mk-border-c: var(--le-mk-border);

	--le-line-color: var(--wp--preset--color--hairline);
	--le-fill-color: var(--wp--preset--color--primary);

	--le-rail: calc( var(--le-marker-size) + var(--le-marker-gap) );

	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--50);
	margin: 0;
	padding: 0;
	list-style: none;
}
.le-stepper.is-markertype-dot { --le-marker-size: var(--wp--preset--spacing--40); --le-mk-border: var(--wp--preset--color--text-muted); }
/* No marker: the rail collapses to just the line + a small indent. */
.le-stepper.is-markertype-none { --le-marker-size: 0px; --le-rail: var(--le-marker-gap); }

/* ================================================================== *
 * VERTICAL (base) — bar on the LEFT edge
 * ================================================================== */
.le-step {
	position: relative;
	padding-left: var(--le-rail);
	min-height: var(--le-marker-size);
}

/* Connector bar — vertical, centered on the rail, bridging the flex gap. */
.le-step__connector {
	position: absolute;
	top: 0;
	left: calc( var(--le-marker-size) / 2 );
	width: var(--le-connector-size);
	height: calc( 100% + var(--le-gap) );
	transform: translateX( -50% );
	background: var(--le-line-color);
	pointer-events: none;
}
.le-stepper.is-markertype-none .le-step__connector { left: calc( var(--le-connector-size) / 2 ); }

/* Outer connectors (vertical). "Remove outer" (is-no-outer) trims the line to
   the first/last markers. The last step is matched with :not(:has(~ .le-step))
   rather than :last-child so it works in the editor too, where the InnerBlocks
   appender is the real :last-child. */
.le-stepper.is-marker-left.is-no-outer .le-step:not( :has( ~ .le-step ) ) .le-step__connector,
.le-stepper.is-marker-right.is-no-outer .le-step:first-child .le-step__connector { display: none; }
.le-stepper.is-marker-center.is-no-outer:not( .is-horizontal ) .le-step:first-child .le-step__connector { top: 50%; }
.le-stepper.is-marker-center.is-no-outer:not( .is-horizontal ) .le-step:not( :has( ~ .le-step ) ) .le-step__connector { height: 50%; }

/* Fill — a ::before over the bar, grown by size (so rounded ends don't distort). */
.le-step__connector::before {
	content: "";
	position: absolute;
	left: 0;
	top: 0;
	width: 100%;
	height: calc( var(--le-c-fill, 0) * 100% );
	background: var(--le-fill-color);
	border-radius: inherit;
	pointer-events: none;
}
.le-stepper.is-fill-hover:hover .le-step__connector::before { transition: height 0.4s ease, width 0.4s ease; }

/* Rounded bar ends. */
.le-stepper.is-connector-rounded .le-step__connector { border-radius: 999px; }

/* Dashed / chevron. */
.le-stepper.is-connector-dashed .le-step__connector {
	background: repeating-linear-gradient( to bottom, var(--le-line-color) 0 6px, transparent 6px 12px );
}
/* Chevron: discrete arrows in the gap between steps — no line, no fill bar. The
   connector box is stretched to the whole (invisible) step so the arrow can sit on
   the marker rail ("markers") or down over the content ("content"). Only a step
   that has a following step gets an arrow — matched with :has( ~ .le-step ) so the
   editor's InnerBlocks appender (the real :last-child) never adds a stray one. The
   arrow tints line -> fill with the step's own fill so it still reads as active. */
.le-stepper.is-connector-chevron .le-step__connector {
	inset: 0;
	width: auto;
	height: auto;
	transform: none;
	background: none;
}
.le-stepper.is-connector-chevron .le-step__connector::before { display: none; }
.le-stepper.is-connector-chevron .le-step {
	--le-chev-color: var(--le-line-color);
	--le-chev-color: color-mix( in srgb, var(--le-fill-color) calc( var(--le-c-fill, 0) * 100% ), var(--le-line-color) );
}
.le-stepper.is-connector-chevron .le-step:has( ~ .le-step ) .le-step__connector::after {
	content: "";
	position: absolute;
	left: calc( var(--le-marker-size) / 2 );
	bottom: calc( -0.5 * var(--le-gap) );
	width: 0.5rem;
	height: 0.5rem;
	border-right: var(--le-connector-size) solid var(--le-chev-color);
	border-bottom: var(--le-connector-size) solid var(--le-chev-color);
	transform: translate( -50%, 50% ) rotate( 45deg );
}
/* "Between step content": drop the arrow onto the content column. */
.le-stepper.is-connector-chevron.is-chevron-content .le-step:has( ~ .le-step ) .le-step__connector::after {
	left: 50%;
}

/* Marker — absolute on the left rail, anchored to the edges. */
.le-step__marker {
	position: absolute;
	left: 0;
	box-sizing: border-box;
	width: var(--le-marker-size);
	height: var(--le-marker-size);
	border-radius: 50%;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	overflow: hidden;
	z-index: 1;
	background: var(--le-mk-bg-c);
	border: var(--le-marker-border-size) var(--le-marker-border-style, solid) var(--le-mk-border-c);
	color: var(--le-mk-text-c);
	font-family: var(--wp--preset--font-family--heading);
	line-height: 1;
}
.le-stepper.is-marker-left .le-step__marker { top: 0; }
.le-stepper.is-marker-center .le-step__marker { top: 50%; transform: translateY( -50% ); }
.le-stepper.is-marker-right .le-step__marker { top: auto; bottom: 0; }
.le-stepper.is-markertype-none .le-step__marker { display: none; }

/* Content region. A full-height flex COLUMN: a single (locked) group child
   stretches to fill the step — across a horizontal row that means every step's
   content lines up, and the group can push its own contents apart (e.g. a
   bottom-aligned CTA) with its vertical layout. The column direction matters:
   loose, ungrouped blocks (older patterns put a heading + paragraphs straight in
   the step) keep stacking vertically instead of going side-by-side, and only a
   LONE child is stretched, so multi-block loose content flows naturally. Orbit +
   alternating opt out below (they position the content themselves). */
.le-step__content {
	min-width: 0;
	display: flex;
	flex-direction: column;
	align-items: stretch;
	height: 100%;
	/* The step's own font size (Styles tab) is routed to the marker text, not the
	   content — reset to the body default (medium) so a step font size can't cascade
	   into the content blocks. (This equals the body size, so it's a no-op today.) */
	font-size: var(--wp--preset--font-size--medium);
}
.le-step__content > :only-child { flex: 1 1 auto; }
.le-step__content > * { min-width: 0; }
.le-step__content > :first-child { margin-top: 0; }
.le-step__content > :last-child { margin-bottom: 0; }

/* ================================================================== *
 * Marker visuals (colors + text/dot/image/icon)
 * ================================================================== */
.le-step__marker {
	color: var(--le-mk-text-c);
	color: color-mix( in srgb, var(--le-mk-text-hover) calc( var(--le-m-lit, 0) * 100% ), var(--le-mk-text) );
	background: var(--le-mk-bg-c);
	background: color-mix( in srgb, var(--le-mk-bg-hover) calc( var(--le-m-lit, 0) * 100% ), var(--le-mk-bg) );
	border-color: var(--le-mk-border-c);
	border-color: color-mix( in srgb, var(--le-mk-border-hover) calc( var(--le-m-lit, 0) * 100% ), var(--le-mk-border) );
	/* Subtle ease between normal and hover/active state — both directions (the
	   earlier :hover-gated rule only eased on the way in, so it snapped back out). */
	transition: color 0.25s ease, background-color 0.25s ease, border-color 0.25s ease;
}
/* Crisp during the running loop — a color transition would smear the per-frame
   sweep. When the loop is hovered it pauses, so :hover re-enables the ease. */
.le-stepper.is-fill-loop:not(:hover) .le-step__marker { transition: none; }

/* The STEP block's own Text color (Styles tab) drives its marker text — and the
   prefix, which inherits from the marker. With no text color set, the container's
   marker colors (+ the fill lighting) apply as before. */
.le-step.has-text-color .le-step__marker { color: inherit; }

.le-step__prefix { font-size: var(--wp--preset--font-size--xs); font-weight: 600; text-transform: uppercase; opacity: 0.85; line-height: 1.1; }
.le-step__value { font-size: var(--wp--preset--font-size--medium); font-weight: 600; }
.le-step__marker.has-prefix .le-step__value { font-size: var(--wp--preset--font-size--small); }
/* The STEP's own font size (Styles tab) is taken by the marker VALUE (only when a
   size is actually set — else the defaults above stand). The prefix keeps its own
   size, so it gets the color but not the typography, as intended. */
.le-step[style*="font-size"] .le-step__value,
.le-step[class*="font-size"] .le-step__value {
	font-size: inherit;
}

.le-stepper.is-markertype-image .le-step__marker { padding: 0; }
.le-step__marker-img { width: 100%; height: 100%; object-fit: cover; display: block; }

.le-step__value--icon { display: inline-flex; width: 55%; height: 55%; line-height: 0; }
.le-step__value--icon svg { width: 100%; height: 100%; display: block; }

.le-stepper.is-markertype-dot .le-step__prefix,
.le-stepper.is-markertype-dot .le-step__value { display: none; }
.le-stepper.is-dot-filled .le-step__marker {
	background: var(--le-mk-border-c);
	background: color-mix( in srgb, var(--le-mk-border-hover) calc( var(--le-m-lit, 0) * 100% ), var(--le-mk-border) );
}

/* ================================================================== *
 * Fill engine — hover progression + loop (shared by all orientations)
 * ================================================================== *
 *
 * Both hover and loop drive two per-step factors, 0..1:
 *   --le-m-lit  : marker "lit" amount (color-mixes base -> hover)
 *   --le-c-fill : connector fill amount (the ::before length)
 *
 * A marker sits at a fraction of its step — --le-mk-frac: 0 (left / start),
 * 0.5 (center), 1 (right / end) — and each step's connector spans the whole
 * step, so the fill reaches a marker only once its own connector has filled past
 * that fraction. The loop expresses this as a single fill "front" (0..count):
 * connector i fills as the front sweeps its step, and marker i lights exactly
 * when the front reaches i + --le-mk-frac. That makes the timing geometric and
 * correct for every alignment (left assumed no longer). --le-fill-w is how much
 * of a step the fill takes to cross: < 1 pauses at each marker (stepped, the
 * default), 1 is one continuous sweep (Smooth fill — best when there's no gap so
 * the connectors read as a single line). */

/* Marker position within its step (drives when the fill reaches it). */
.le-stepper.is-marker-center { --le-mk-frac: 0.5; }
.le-stepper.is-marker-right  { --le-mk-frac: 1; }

/* Fill window: stepped by default, continuous when "Smooth fill" is on. */
.le-stepper { --le-fill-w: 0.45; }
.le-stepper.is-smooth { --le-fill-w: 1; }

/* Hover — the hovered step's marker always lights; its own connector fills just
   to its marker (--le-mk-frac), so the fill stops exactly at the active marker. */
.le-stepper.is-fill-hover .le-step:hover {
	--le-m-lit: 1;
	--le-c-fill: var(--le-mk-frac, 0);
}
/* Default mode ("fill up to the active step"): every earlier step also lights and
   fills fully. Suppressed in "active step only" mode (is-hover-single), where the
   earlier steps stay inactive. */
.le-stepper.is-fill-hover:not(.is-hover-single) .le-step:has( ~ .le-step:hover ) {
	--le-m-lit: 1;
	--le-c-fill: 1;
}
/* The active step's OWN connector fills fully (not just to its marker) when there
   is no marker to read as the stop point, when a left-aligned track keeps its
   outer connectors (nothing trims the trailing bar), or in "active only" mode
   where the filled bar IS the indicator. Center/right already stop at the marker
   correctly, so they're untouched. */
.le-stepper.is-fill-hover.is-markertype-none .le-step:hover,
.le-stepper.is-fill-hover.is-marker-left:not( .is-no-outer ) .le-step:hover,
.le-stepper.is-fill-hover.is-hover-single .le-step:hover {
	--le-c-fill: 1;
}
/* Center align: a middle step fills to its marker (mk-frac = 0.5, the marker sits
   at 50% of a full-width connector). The LAST step has no next, so its connector
   is either trimmed to the half ending at the marker (remove-outer on → needs a
   full fill to reach the marker) or a full bar with a trailing section past the
   marker (remove-outer off → needs a full fill to complete it). Either way the
   hovered last step fills all the way. (:not(:has(~ .le-step)) = true last step,
   works in the editor where the appender is the real :last-child.) */
.le-stepper.is-marker-center.is-fill-hover .le-step:hover:not( :has( ~ .le-step ) ) {
	--le-c-fill: 1;
}

/* Loop: one front (0..count) sweeps the track; connector + marker derive from it. */
.le-stepper.is-fill-loop {
	animation: le-stepper-progress 5s linear infinite;
}
.le-stepper.is-fill-loop .le-step {
	/* The front sweeps 0 -> count as progress runs 0 -> 1. The tiny + 0.04
	   overshoot at the end lets it clear a right-aligned last marker under Smooth
	   fill (whose threshold sits exactly at count) so that marker still reaches
	   full lit, without shifting the empty start (front is still 0 at progress 0). */
	--le-front: calc( var(--le-progress, 0) * ( var(--le-count, 1) + 0.04 ) );
	--le-c-fill: clamp( 0, calc( ( var(--le-front) - var(--le-index, 0) ) / var(--le-fill-w, 0.45) ), 1 );
	--le-m-lit: clamp( 0, calc( ( var(--le-front) - var(--le-index, 0) - var(--le-mk-frac, 0) * var(--le-fill-w, 0.45) ) * 50 ), 1 );
}
.le-stepper.is-fill-loop.is-fill-hover:hover { animation: none; }

@keyframes le-stepper-progress {
	0%   { --le-progress: 0; }
	88%  { --le-progress: 1; }
	100% { --le-progress: 1; }
}

/* Per-step index (0-based) — the loop front + orbit geometry read it. */
.le-stepper .le-step:nth-child(1)  { --le-index: 0; }
.le-stepper .le-step:nth-child(2)  { --le-index: 1; }
.le-stepper .le-step:nth-child(3)  { --le-index: 2; }
.le-stepper .le-step:nth-child(4)  { --le-index: 3; }
.le-stepper .le-step:nth-child(5)  { --le-index: 4; }
.le-stepper .le-step:nth-child(6)  { --le-index: 5; }
.le-stepper .le-step:nth-child(7)  { --le-index: 6; }
.le-stepper .le-step:nth-child(8)  { --le-index: 7; }
.le-stepper .le-step:nth-child(9)  { --le-index: 8; }
.le-stepper .le-step:nth-child(10) { --le-index: 9; }

/* Center + remove-outer + Smooth loop — even the sweep speed. With centered
   markers the outer connectors are trimmed to HALF width (the first ends at
   marker 0, the last starts at the final marker). On the default schedule each
   still fills over a whole front unit, so those two halves fill at half the
   screen speed of the full-width middle connectors — the sweep visibly slows at
   the ends. Fix: run the front from marker 0 to the final marker (so the whole
   line maps linearly to progress, no half-width step eating a full unit), and
   fill the two half connectors over their own half unit. Constant screen speed.
   (Only smooth needs this — the stepped fill's pauses hide the difference; only
   remove-outer, since with outer connectors kept every connector is full width.) */
.le-stepper.is-marker-center.is-no-outer.is-smooth.is-fill-loop .le-step {
	--le-front: calc( 0.5 + var(--le-progress, 0) * ( var(--le-count, 1) - 1 + 0.04 ) );
}
.le-stepper.is-marker-center.is-no-outer.is-smooth.is-fill-loop .le-step:first-child {
	--le-c-fill: clamp( 0, calc( ( var(--le-front) - 0.5 ) / 0.5 ), 1 );
}
.le-stepper.is-marker-center.is-no-outer.is-smooth.is-fill-loop .le-step:not( :has( ~ .le-step ) ) {
	--le-c-fill: clamp( 0, calc( ( var(--le-front) - ( var(--le-count, 1) - 1 ) ) / 0.5 ), 1 );
}

/* Left + remove-outer + LOOP — restore the original staggered timing. By default a
   left step's outgoing bar fills the instant its own marker lights ([index, index +
   window]). Instead, hold at the marker with the bar empty, then fill that bar as
   the sweep reaches the NEXT marker ([index + 1 − window, index + 1]) — so the
   sequence reads marker, hold, bar, next marker. Only the connector fill shifts;
   the markers light unchanged, and this is LOOP-only (hover derives --le-c-fill from
   its own rules, and works already). Smooth fill is a no-op here: window = 1 makes
   the shifted range identical to the default, so a continuous sweep stays continuous. */
.le-stepper.is-marker-left.is-no-outer.is-fill-loop .le-step {
	--le-c-fill: clamp( 0, calc( ( var(--le-front) - var(--le-index, 0) - 1 + var(--le-fill-w, 0.45) ) / var(--le-fill-w, 0.45) ), 1 );
}

/* ================================================================== *
 * HORIZONTAL — bar on the TOP edge, at the breakpoint
 * ================================================================== */
@media ( min-width: 782px ) {
	.le-stepper.is-horizontal { flex-direction: row; }
	.le-stepper.is-horizontal > .le-step {
		flex: 1 1 0;
		min-width: 0;
		padding-left: 0;
		padding-top: var(--le-rail);
	}

	.le-stepper.is-horizontal .le-step__connector {
		top: calc( var(--le-marker-size) / 2 );
		left: 0;
		right: 0;
		width: auto;
		height: var(--le-connector-size);
		transform: translateY( -50% );
	}
	.le-stepper.is-horizontal.is-markertype-none .le-step__connector { top: calc( var(--le-connector-size) / 2 ); }

	/* Fill grows along the inline axis. */
	.le-stepper.is-horizontal .le-step__connector::before {
		height: 100%;
		width: calc( var(--le-c-fill, 0) * 100% );
	}

	.le-stepper.is-horizontal.is-connector-dashed .le-step__connector {
		background: repeating-linear-gradient( to right, var(--le-line-color) 0 6px, transparent 6px 12px );
	}
	/* Chevron connector box must beat the horizontal connector rule above, so
	   re-assert the full-step box here (extra class = higher specificity). */
	.le-stepper.is-horizontal.is-connector-chevron .le-step__connector {
		inset: 0; width: auto; height: auto; transform: none;
	}
	.le-stepper.is-horizontal.is-connector-chevron .le-step:has( ~ .le-step ) .le-step__connector::after {
		left: auto; right: calc( -0.5 * var(--le-gap) ); bottom: auto;
		top: calc( var(--le-marker-size) / 2 );
		transform: translate( 50%, -50% ) rotate( -45deg );
	}
	.le-stepper.is-horizontal.is-connector-chevron.is-chevron-content .le-step:has( ~ .le-step ) .le-step__connector::after {
		top: 50%;
	}

	/* Marker on the top rail; start / center / end along the inline axis. */
	.le-stepper.is-horizontal .le-step__marker { top: 0; transform: none; }
	.le-stepper.is-horizontal.is-marker-left .le-step__marker { left: 0; }
	.le-stepper.is-horizontal.is-marker-center .le-step__marker { left: 50%; transform: translateX( -50% ); }
	.le-stepper.is-horizontal.is-marker-right .le-step__marker { right: 0; left: auto; }

	/* Connector spans: left = marker → right edge; right = left edge → marker;
	   center = full width. */
	.le-stepper.is-horizontal.is-marker-left .le-step__connector { left: calc( var(--le-marker-size) / 2 ); right: 0; }
	.le-stepper.is-horizontal.is-marker-right .le-step__connector { left: 0; right: calc( var(--le-marker-size) / 2 ); }

	/* Remove-outer trims the ends (horizontal axis). */
	.le-stepper.is-horizontal.is-marker-center.is-no-outer .le-step:first-child .le-step__connector { left: 50%; }
	.le-stepper.is-horizontal.is-marker-center.is-no-outer .le-step:not( :has( ~ .le-step ) ) .le-step__connector { right: 50%; }

	/* (Centered fill timing is handled by the shared front model above.) */

	/* Centered, non-alternating reads best with centered content. */
	.le-stepper.is-horizontal.is-marker-center:not(.is-alternating) .le-step__content { text-align: center; }

	/* Alternating: content above/below a central bar. Uses a 3-row grid so the
	   axes align across steps (a plain edge bar can't center content both ways). */
	.le-stepper.is-horizontal.is-alternating .le-step {
		padding-top: 0;
		display: grid;
		grid-template-rows: 1fr var(--le-marker-size) 1fr;
		justify-items: stretch;
	}
	.le-stepper.is-horizontal.is-alternating .le-step__marker { top: 50%; transform: translate( -50%, -50% ); }
	.le-stepper.is-horizontal.is-alternating.is-marker-center .le-step__marker { left: 50%; }
	.le-stepper.is-horizontal.is-alternating.is-marker-left .le-step__marker { left: 0; transform: translateY( -50% ); }
	.le-stepper.is-horizontal.is-alternating.is-marker-right .le-step__marker { right: 0; left: auto; transform: translateY( -50% ); }
	/* Alternating hugs the content toward the centre line, so it opts out of the
	   full-height stretch (auto height lets align-self position it). */
	.le-stepper.is-horizontal.is-alternating .le-step__content { height: auto; }
	.le-stepper.is-horizontal.is-alternating .le-step:nth-child(odd) .le-step__content { grid-row: 1; align-self: end; }
	.le-stepper.is-horizontal.is-alternating .le-step:nth-child(even) .le-step__content { grid-row: 3; align-self: start; }
	/* The connector spans the middle band; center it vertically via 50%. */
	.le-stepper.is-horizontal.is-alternating .le-step__connector { top: 50%; }

	/* Optional stem (is-alt-stem): a short vertical connector from each marker to
	   its card, inheriting the connector width / color / fill / active state.
	   ::before is the base line; ::after is the fill, growing from the marker toward
	   the card as the marker lights (--le-m-lit) — same driver as the horizontal
	   connector. The card is pushed off the axis by the stem length to make room.
	   --le-stem-x tracks the marker's horizontal position. */
	.le-stepper.is-horizontal.is-alternating.is-alt-stem {
		--le-stem-length: var(--wp--preset--spacing--50);
		--le-stem-x: 50%;
	}
	.le-stepper.is-horizontal.is-alternating.is-alt-stem.is-marker-left  { --le-stem-x: calc( var(--le-marker-size) / 2 ); }
	.le-stepper.is-horizontal.is-alternating.is-alt-stem.is-marker-right { --le-stem-x: calc( 100% - var(--le-marker-size) / 2 ); }

	.le-stepper.is-horizontal.is-alternating.is-alt-stem .le-step:nth-child(odd) .le-step__content  { margin-bottom: var(--le-stem-length); }
	.le-stepper.is-horizontal.is-alternating.is-alt-stem .le-step:nth-child(even) .le-step__content { margin-top: var(--le-stem-length); }

	.le-stepper.is-horizontal.is-alternating.is-alt-stem .le-step::before,
	.le-stepper.is-horizontal.is-alternating.is-alt-stem .le-step::after {
		content: "";
		position: absolute;
		left: var(--le-stem-x);
		width: var(--le-connector-size);
		height: var(--le-stem-length);
		transform: translateX( -50% );
		pointer-events: none;
	}
	.le-stepper.is-horizontal.is-alternating.is-alt-stem .le-step::before { background: var(--le-line-color); }
	.le-stepper.is-horizontal.is-alternating.is-alt-stem .le-step::after  { background: var(--le-fill-color); height: calc( var(--le-m-lit, 0) * var(--le-stem-length) ); }

	/* Odd = card above (stem sits above the marker, fill grows up); even = below. */
	.le-stepper.is-horizontal.is-alternating.is-alt-stem .le-step:nth-child(odd)::before { top: calc( 50% - var(--le-marker-size) / 2 - var(--le-stem-length) ); }
	.le-stepper.is-horizontal.is-alternating.is-alt-stem .le-step:nth-child(odd)::after  { bottom: calc( 50% + var(--le-marker-size) / 2 ); }
	.le-stepper.is-horizontal.is-alternating.is-alt-stem .le-step:nth-child(even)::before,
	.le-stepper.is-horizontal.is-alternating.is-alt-stem .le-step:nth-child(even)::after  { top: calc( 50% + var(--le-marker-size) / 2 ); }

	.le-stepper.is-horizontal.is-alternating.is-alt-stem.is-fill-hover:hover .le-step::after { transition: height 0.3s ease; }
}

/* ================================================================== *
 * ORBIT — bordered-circle ring (crisp) + conic fill arc
 * ================================================================== */
.le-stepper.is-orbit {
	/* The fill arc starts at the "return" slice just before node 1 (so node 1's
	   incoming bar is always shown) and sweeps clockwise. --le-fill-frac is the
	   number of filled slices as a fraction of the circle: 1 slice at rest, N
	   slices (the whole ring) when the last node is active. */
	--le-slices: max( var(--le-count, 1), 1 );
	--le-fill-from: calc( ( var(--le-slices) - 1 ) / var(--le-slices) * 360deg );
	--le-fill-frac: calc( 1 / var(--le-slices) );
	display: block;
	position: relative;
	container-type: inline-size;
	aspect-ratio: 1;
	width: 100%;
	max-width: min( 92vw, 34rem );
	margin-inline: auto;
	gap: 0;
}
.le-stepper.is-orbit .le-step { --le-marker-size: clamp( 1.6rem, 13cqw, 3rem ); position: absolute; inset: 0; display: block; padding: 0; }
.le-stepper.is-orbit.is-markertype-dot .le-step { --le-marker-size: clamp( 0.7rem, 4cqw, 1.1rem ); }

/* Base ring — a crisp bordered circle. Fill arc — a conic ring over it. Both
   drawn once on the container. */
.le-stepper.is-orbit::before,
.le-stepper.is-orbit::after {
	content: "";
	position: absolute;
	top: 50%;
	left: 50%;
	width: 82cqw;
	height: 82cqw;
	box-sizing: border-box; /* ring border draws inward, into the same band as the fill */
	transform: translate( -50%, -50% );
	border-radius: 50%;
	pointer-events: none;
}
.le-stepper.is-orbit::before {
	border: var(--le-connector-size) solid var(--le-line-color);
}
.le-stepper.is-orbit::after {
	background: conic-gradient( from var(--le-fill-from), var(--le-fill-color) 0deg calc( var(--le-fill-frac, 0) * 360deg ), transparent 0 );
	-webkit-mask: radial-gradient( circle closest-side, transparent calc( 100% - var(--le-connector-size) - 0.6px ), #000 calc( 100% - var(--le-connector-size) + 0.4px ) );
	mask: radial-gradient( circle closest-side, transparent calc( 100% - var(--le-connector-size) - 0.6px ), #000 calc( 100% - var(--le-connector-size) + 0.4px ) );
	transition: background 0.35s ease;
}
/* The per-step div connectors are unused in orbit. */
.le-stepper.is-orbit .le-step__connector { display: none; }

/* Only the markers capture pointer events — the steps are stacked over the whole
   container, so if they were hit targets, hovering anywhere would activate the
   topmost step. With the steps transparent, hovering a marker activates its own
   step (via the ancestor chain) and hovering empty space activates nothing. */
.le-stepper.is-orbit .le-step { pointer-events: none; }
.le-stepper.is-orbit .le-step__marker { pointer-events: auto; }

/* Node 1's marker is always active (the sequence starts there). */
.le-stepper.is-orbit .le-step:first-child { --le-m-lit: 1; }

/* Markers ring the circle by angle, kept upright. The ring (::before/::after) is
   a border-box circle with a fixed 82cqw OUTER edge, so a thicker connector grows
   inward and its centerline sits at 41cqw - connector/2. The marker radius tracks
   that centerline (not the outer 41cqw) so the marker stays centered on the ring
   at any thickness. */
.le-stepper.is-orbit .le-step__marker {
	top: 50%;
	left: 50%;
	--le-a: calc( var(--le-index, 0) * ( 360deg / max( var(--le-count, 1), 1 ) ) );
	transform:
		translate( -50%, -50% )
		rotate( var(--le-a) )
		translateY( calc( -41cqw + var(--le-connector-size, 2px) / 2 ) )
		rotate( calc( -1 * var(--le-a) ) )
		scale( var(--le-active-scale, 1) );
	transition: transform 0.3s ease, color 0.25s ease, background-color 0.25s ease, border-color 0.25s ease;
}

/* Center content; only the active step's shows. It's an absolutely-centred
   overlay here, so it opts out of the flex/full-height content box (block flow,
   auto height) — the group child just sits centred in the ring. */
.le-stepper.is-orbit .le-step__content {
	display: block;
	height: auto;
	position: absolute;
	top: 50%;
	left: 50%;
	width: 52cqw;
	max-width: 52cqw;
	transform: translate( -50%, -50% );
	text-align: center;
	opacity: 0;
	z-index: 1;
	pointer-events: none;
	transition: opacity 0.25s ease; /* for the hover crossfade; the loop overrides this */
}
.le-stepper.is-orbit .le-step:first-child .le-step__content { opacity: 1; z-index: 2; pointer-events: auto; }

/* Orbit fill arc + node lighting + center content scale with the step count so
   the loop sweep spans the whole cycle. --le-index comes from the shared
   nth-child rules above. */
.le-stepper.is-orbit.is-fill-loop { --le-fill-frac: calc( ( 1 + var(--le-progress, 0) * ( var(--le-slices) - 1 ) ) / var(--le-slices) ); }
.le-stepper.is-orbit.is-fill-loop .le-step {
	/* A node lights only once the arc actually reaches it: the fill covers
	   (--le-fill-frac * slices) slices from the return arc, and node i sits at
	   (i + 1) slices along — so light node i when the count of filled slices
	   reaches i + 1. (The old index/count threshold ignored the return slice, so
	   nodes lit a step too early.) The 0.98 (i.e. i + 1 - 0.02) is a hair of slack
	   so the LAST node — whose threshold falls exactly at progress 1 — still
	   reaches full lit at the end of the sweep instead of stalling at 0. */
	--le-m-lit: clamp( 0, calc( ( var(--le-fill-frac, 0) * var(--le-slices) - var(--le-index, 0) - 0.98 ) * 50 ), 1 );
	/* --le-win drives BOTH the center-content crossfade and the marker "rise", so
	   it must track the node-lighting reach — node i is reached at progress
	   index / (count-1), NOT index/count. (That mismatch was why the rise and the
	   content swap fired a step too early, out of sync with the corrected lighting.)
	   win-s/win-e sit one ramp-width (0.03) before each reach so the fade completes
	   exactly AT the reach: node i is full the instant it lights and gone the
	   instant node i+1 lights. The last node's win-e lands past 1, so it holds
	   through the end of the sweep. */
	--le-rr: max( calc( var(--le-count, 1) - 1 ), 1 );
	--le-win-s: calc( var(--le-index, 0) / var(--le-rr) - 0.03 );
	--le-win-e: calc( ( var(--le-index, 0) + 1 ) / var(--le-rr) - 0.03 );
	--le-win: calc(
		clamp( 0, calc( ( var(--le-progress, 0) - var(--le-win-s, -1) ) / 0.03 ), 1 )
		- clamp( 0, calc( ( var(--le-progress, 0) - var(--le-win-e, 2) ) / 0.03 ), 1 )
	);
}
/* Node 1 stays active through the whole loop (the sequence starts there) — this
   restates the always-on rule inside the loop context, where the per-step rule
   above would otherwise win at equal specificity. */
.le-stepper.is-orbit.is-fill-loop .le-step:first-child { --le-m-lit: 1; }
/* During the loop the boxcar (--le-win) is the sole opacity driver, so ONE step's
   content is up at a time with a brief, sharp crossfade. Killing the 0.25s ease
   here matters: with it, each fading-out content kept a ~0.3s tail, so around a
   boundary the previous, current, and next were all partly visible at once —
   which, with no background on the content, read as stacked/jumbled text. */
.le-stepper.is-orbit.is-fill-loop:not(:hover) .le-step__content {
	opacity: var(--le-win, 0);
	transition: none;
}
.le-stepper.is-orbit.is-fill-loop .le-step__content { opacity: var(--le-win, 0); }
.le-stepper.is-orbit.is-fill-loop:not(:hover) .le-step { --le-active-scale: calc( 1 + 0.18 * var(--le-win, 0) ); }

/* Hover node K: fill K slices (the return arc + every bar before node K); its
   content shows. Hovering node 1 stays at the base 1-slice. */
.le-stepper.is-orbit.is-fill-hover:has( .le-step:nth-child(2):hover )  { --le-fill-frac: calc( 2 / var(--le-slices) ); }
.le-stepper.is-orbit.is-fill-hover:has( .le-step:nth-child(3):hover )  { --le-fill-frac: calc( 3 / var(--le-slices) ); }
.le-stepper.is-orbit.is-fill-hover:has( .le-step:nth-child(4):hover )  { --le-fill-frac: calc( 4 / var(--le-slices) ); }
.le-stepper.is-orbit.is-fill-hover:has( .le-step:nth-child(5):hover )  { --le-fill-frac: calc( 5 / var(--le-slices) ); }
.le-stepper.is-orbit.is-fill-hover:has( .le-step:nth-child(6):hover )  { --le-fill-frac: calc( 6 / var(--le-slices) ); }
.le-stepper.is-orbit.is-fill-hover:has( .le-step:nth-child(7):hover )  { --le-fill-frac: calc( 7 / var(--le-slices) ); }
.le-stepper.is-orbit.is-fill-hover:has( .le-step:nth-child(8):hover )  { --le-fill-frac: calc( 8 / var(--le-slices) ); }
.le-stepper.is-orbit.is-fill-hover:has( .le-step:last-child:hover )    { --le-fill-frac: 1; }

.le-stepper.is-orbit.is-fill-hover:has( .le-step:hover ) .le-step:first-child:not(:hover) .le-step__content {
	opacity: 0; z-index: 1; pointer-events: none;
}
.le-stepper.is-orbit.is-fill-hover .le-step:hover .le-step__content { opacity: 1; z-index: 2; pointer-events: auto; }
.le-stepper.is-orbit.is-fill-hover .le-step:hover { --le-active-scale: 1.18; }

/* Editor selection (paired with editor.css !important). */
.le-stepper.is-orbit .le-step.is-orbit-selected .le-step__content { opacity: 1; z-index: 2; }
.le-stepper.is-orbit .le-step.is-orbit-selected { --le-active-scale: 1.12; }

/* Collapse orbit to the vertical list below the breakpoint. */
@media ( max-width: 781px ) {
	.le-stepper.is-orbit.is-collapse {
		display: flex; flex-direction: column; container-type: normal;
		aspect-ratio: auto; max-width: none; gap: var(--wp--preset--spacing--50);
	}
	.le-stepper.is-orbit.is-collapse::before,
	.le-stepper.is-orbit.is-collapse::after { display: none; }
	.le-stepper.is-orbit.is-collapse .le-step {
		--le-marker-size: var(--wp--preset--spacing--70);
		position: relative; inset: auto; display: block; padding-left: var(--le-rail);
	}
	.le-stepper.is-orbit.is-collapse.is-markertype-dot .le-step { --le-marker-size: var(--wp--preset--spacing--40); }
	.le-stepper.is-orbit.is-collapse .le-step__marker {
		top: 0; left: 0; transform: none; transition: none;
	}
	.le-stepper.is-orbit.is-collapse .le-step__content {
		position: static; top: auto; left: auto; width: auto; max-width: none;
		transform: none; text-align: start; opacity: 1; pointer-events: auto;
	}
	.le-stepper.is-orbit.is-collapse .le-step__connector {
		display: block; top: 0; left: calc( var(--le-marker-size) / 2 );
		width: var(--le-connector-size); height: calc( 100% + var(--le-gap) );
		transform: translateX( -50% ); background: var(--le-line-color);
	}
	.le-stepper.is-orbit.is-collapse .le-step:last-child .le-step__connector { display: none; }
}

/* ================================================================== *
 * Reduced motion
 * ================================================================== */
@media ( prefers-reduced-motion: reduce ) {
	.le-stepper.is-fill-loop { animation: none; }
}
