/*
An emulation of block-step-size in CSS, via scroll-driven animations.

A view timeline has named ranges, and the distance between the starts of two of them equals the size of the subject. Reading that distance with two animations of a custom property turns the element's size into a length usable in calc().

The subject is the box's own pseudo-element, stretched over its whole padding-box. It removes the need for a wrapper around the content and also brings the block paddings into the measurement, which would otherwise have to be declared by hand.

The distance between the range starts equals the smaller of the two sizes, the subject's and the scrollport's. The pseudo-element is deliberately one pixel taller than the scrollport, so the smaller of the two is the scrollport, which is exactly the padding-box we need. The same extra pixel gives the scroll container a scroll range, without which the timeline is inactive, so no second probe pseudo-element is needed and ::after stays with the author.

Once the size is a length, round() rounds it up to the step and the difference goes into the margins, where block-step-insert: margin-box would put it. Which side gets it is decided by --bs-align: 0 puts the whole extra after the box, like block-step-align: start; 0.5 splits it evenly, like center. The hack does not understand keywords, because the share has to be multiplied by the length right inside calc().
*/

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

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

@keyframes --bs-start {
	from {
		--bs-start: 0;
	}

	to {
		--bs-start: 1;
	}
}

@keyframes --bs-end {
	from {
		--bs-end: 0;
	}

	to {
		--bs-end: 1;
	}
}

/* Parts of the outer size the timeline cannot see: the box's own block margins and borders. The page declares them on the boxes; registration keeps them computed in px. */
@property --own-margin-start {
	syntax: "<length>";
	inherits: false;
	initial-value: 0px;
}

@property --own-margin-end {
	syntax: "<length>";
	inherits: false;
	initial-value: 0px;
}

@property --own-border {
	syntax: "<length>";
	inherits: false;
	initial-value: 0px;
}

/* The derived lengths are registered to stay computed in px: calc() is cheaper that way, and the page can read the measurement back for diagnostics. */
@property --bs-measured {
	syntax: "<length>";
	inherits: false;
	initial-value: 0px;
}

@property --bs-outer {
	syntax: "<length>";
	inherits: false;
	initial-value: 0px;
}

@property --bs-extra {
	syntax: "<length>";
	inherits: false;
	initial-value: 0px;
}

@property --bs-add {
	syntax: "<length>";
	inherits: false;
	initial-value: 0px;
}

/* The share of the extra that goes before the box: 0 is like block-step-align: start, 0.5 is like center. */
@property --bs-align {
	syntax: "<number>";
	inherits: false;
	initial-value: 0;
}

.block-step {
	/* The window within which both readings are taken. */
	--bs-resolution: 10000px;
	/* The step: the equivalent of block-step-size. */
	--bs-size: var(--step, 1rlh);

	/* The measured padding-box: content together with block paddings. */
	--bs-measured: calc((var(--bs-start) - var(--bs-end)) * var(--bs-resolution));
	/* The outer size as block-step-size sees it: padding-box plus borders and own margins. */
	--bs-outer:
		calc(
			var(--bs-measured)
			+ var(--own-border)
			+ var(--own-margin-start)
			+ var(--own-margin-end)
		);
	/* The equivalent of the correction block-step-size would make. */
	--bs-extra: calc(round(up, var(--bs-outer), var(--bs-size)) - var(--bs-outer));
	/* min() is a guard here: when measuring is unavailable the measured size is zero, and multiplying it by a large factor keeps the extra at zero instead of rounding a size that was never read. */
	--bs-add: min(var(--bs-extra), var(--bs-measured) * 1000);

	animation:
		--bs-start linear both,
		--bs-end linear both;
	animation-range:
		0 var(--bs-resolution),
		contain contain var(--bs-resolution);
	animation-timeline: --bs-y, --bs-y;
	overflow: hidden;
	position: relative;
	timeline-scope: --bs-y;

	/* The extra is split between the sides by --bs-align. The box's own margins are added to it right here, which is why the page declares them as variables. */
	margin-block:
		calc(var(--own-margin-start) + var(--bs-add) * var(--bs-align))
		calc(var(--own-margin-end) + var(--bs-add) * (1 - var(--bs-align)));

	/* Without the required features the boxes simply keep their own margins. */
	@supports not (timeline-scope: --bs-y) {
		margin-block: var(--own-margin-start) var(--own-margin-end);
		overflow: visible;
	}

	/* The timeline subject: a pseudo-element over the whole padding-box and one pixel further down, so that the scroll container gets a scroll range. */
	&::before {
		content: "";
		inset-block: 0 -1px;
		inset-inline: 0;
		pointer-events: none;
		position: absolute;
		view-timeline: --bs-y block;
	}
}
