/*
 * Touch carousel — a Query Loop grid that becomes one scrolling row on a touch device.
 *
 * The case it exists for: three article cards in a Grid post template. Wide, the grid puts
 * them in a row; narrow, `auto-fill` collapses to one column and the section becomes three
 * full-width cards stacked ~500px each — a page and a half of scrolling to see a "latest
 * news" strip. A carousel says the same thing in one screen.
 *
 * **Touch only, and that is what makes it free.** A carousel driven by a pointer needs
 * arrows: a mouse has no way to fling a scrollport, and a visible scrollbar under a row of
 * cards is not a control anybody designed. A finger already has the gesture, so gated on
 * `@media (hover: none)` this is a layout with no arrows, no script and no state — which is
 * why it can be a block style at all. `term-carousel` is the other half of that argument:
 * it is a whole block, with a view module, because it has to work under a cursor.
 *
 * `(hover: none)` rather than `(pointer: coarse)`: the question is whether the device can
 * hover, not how precise it is. A touch laptop with a trackpad reports `hover: hover` and
 * keeps the grid, which is right — it has a cursor and the grid has room.
 *
 * ## It thresholds itself, so there is no breakpoint
 *
 * `flex: 1 0 <card>` is the whole mechanism. Below the width where the cards fit they keep
 * their basis, overflow, and the row scrolls; above it they *grow* to fill the row and there
 * is nothing to scroll, so the carousel renders as a plain row indistinguishable from the
 * grid. No media query had to guess where that line is, which matters because the line moves
 * with the card width and the gap — measured against the container, driving its width, with
 * three cards at the design's 320px minimum and 20px gap:
 *
 *     container  290px -> 320px cards, scrolls (a phone: one card, the next off the screen)
 *     container  720px -> 320px cards, scrolls (an iPad in portrait: about 2.2 cards)
 *     container  980px -> 320px cards, 20px of overflow  <- the imperfect band
 *     container 1080px -> 347px cards, no scroll (the same iPad in landscape)
 *     container 1340px -> 433px cards, no scroll - the design's card, identical to the grid
 *
 * The crossover is `3 x 320 + 2 x 20 = 1000px`, and just under it is that band: a container
 * between about 960 and 1000px overflows by **less than one gap**, so the row scrolls a few
 * tens of pixels for no useful reason. It is still fully scrollable, because the last card
 * snaps on the scrollport's end edge — see the note on snapping below.
 *
 * ## The card width and the gap both come from the block
 *
 * The gap is free: core emits `gap` for the Grid layout and a flex row honours the same
 * property, so the gutter set in the block's own Layout panel carries over untouched.
 *
 * The card width is `--kg-post-template-column-min`, which
 * `includes/blocks/post-template-touch-carousel.php` copies from the block's
 * `layout.minimumColumnWidth` at render time. It has to be published like that because CSS
 * cannot read a value back out of the `minmax()` core wrote it into, and because the
 * alternative — a number in this file — would silently stop matching the moment somebody
 * changed the column minimum in the editor. The `20rem` fallback is the design's own 320px,
 * so the style still works on a block that has no minimum set, and in the editor, where the
 * filter does not run.
 *
 * It is used **as it is**, with no cap of its own. An earlier version wrapped it in
 * `min(…, 85%)` so the next card would peek on a narrow screen; the bleed below is what
 * actually produces that peek, and it does it without putting a percentage into a value that
 * three different properties read — see the note on silent failure 13.
 *
 * ## The row runs off the screen rather than stopping at the container
 *
 * The same treatment `term-carousel` and `tabs-side-tabs` use, and the reason for it is that
 * a scroll container clips at its padding box: a row that ended at the container's edge would
 * cut the next card in half on a hard line 24px in from the screen, which reads as a broken
 * layout rather than as more content. Bleeding it means the card that is half visible is half
 * visible *because it is running off the screen*, which is what a carousel looks like.
 *
 * The negative inline margins take the scrollport out to the window on both sides, and the
 * padding puts the cards back inside the container on both: the first card starts on the
 * container's edge, in line with the heading above it, and scrolling to the end rests the
 * last card on the container's other edge rather than against the side of the window.
 * `scroll-padding-inline-start` repeats the start padding because snapping measures against
 * the scrollport and not the padding box — without it every snap lands one gutter out.
 *
 * **The bleed is derived from `--wp--style--global--wide-size`, never from `100%`.** That is
 * not a style choice; it is the theme's silent failure 13. A percentage resolves against the
 * containing block in `margin` and `padding` but against the **scrollport** in
 * `scroll-padding`, and the scrollport here is the bled track — so `(100vw - 100%) / 2`
 * computes to the gutter twice and to *zero* once, and the first card snaps flush to the
 * window instead of to its column. This expression has no percentage in it, so all three
 * properties agree. `max(0px, …)` keeps it sane if the block is ever placed in something
 * narrower than the wide size.
 *
 * `var(--screen-size, 100vw)` rather than a bare `100vw`: nothing in the theme sets
 * `--screen-size`, so the two are the same today, but it is the seam a site excluding the
 * scrollbar sets once — and every width in `theme.json` already reads it.
 *
 * **`max-inline-size: none` is what lets the bleed happen at all**, and without it the whole
 * treatment is silently a no-op: core's own `.wp-block-post-template` carries
 * `max-width: 100%` with `box-sizing: border-box`, so the negative margins widened nothing and
 * the 50px of padding came *out of* the cards' space instead — a row that ended exactly at the
 * container, 100px narrower inside, with every number in this file correct. It reads as the
 * bleed not working rather than as a max-width, which is what makes it expensive to find. Core
 * sets it at one class's worth, so the two-class selector here clears it.
 *
 * ## The lift is not clipped either, and it costs no layout
 *
 * A scroll container clips vertically as well, so the `Article card` shadow — `0 14px 24px`,
 * 38px of bottom extent — would be cut off at the bottom of the row. On a touch device that
 * shadow is a `:focus-within` state rather than a hover one, which is exactly the case a
 * keyboard on a tablet reaches, so it is worth keeping.
 *
 * `padding-block` reserves the room inside the scrollport and an equal negative `margin-block`
 * takes it back out of the layout, so nothing above or below the carousel moves: the same
 * margin/padding pair as the horizontal bleed, one axis over. The reserved band overlaps the
 * section's own vertical padding, which is empty space, so there is nothing to collide with.
 * `scrollHeight` still equals `clientHeight`, so no vertical scrollbar appears.
 *
 * ## One consequence worth knowing
 *
 * **A card's `min-height: 100%` stops meaning anything here** — a percentage minimum needs a
 * definite parent height and a flex line has none (silent failure 17). Equal heights come
 * from `align-items: stretch` instead, which is the flex equivalent and needs nothing from
 * the card.
 *
 * ## Snapping is `mandatory`, and the last card is what makes that safe
 *
 * `proximity` was the first choice, copied from `term-carousel`, and it is wrong here: it
 * aligns a scroll only when it *lands* near a boundary, so a swipe that ends mid-card stays
 * mid-card. What that feels like is cards that do not stick — which is the whole point of a
 * carousel with no arrows, because the snap is the only thing telling a finger where a card
 * ends.
 *
 * `mandatory` has a real trap and it is the reason `term-carousel` avoids it: every snap
 * position is an item's *start* edge, and the last item's start edge sits beyond the maximum
 * scroll offset whenever the item is narrower than the scrollport. A scroll container must
 * rest on a snap position, so the browser falls back to the previous one and **the last card
 * can never be brought fully into view**.
 *
 * `scroll-snap-align: end` on the last child is the fix, and it is one declaration. Its snap
 * position is measured from the *end* of the scrollport, so it is always exactly the maximum
 * scroll offset — reachable by construction, at any container width and any number of cards.
 * It also lands the last card on the container's far edge, which is where the design puts it.
 * Checked against the arithmetic at both ends: on a 290px container the three positions are 0,
 * 340 and 710 against a maximum of 710; in the 980px band they are 0, (290, unreachable) and
 * 20 against a maximum of 20 — so even there the 20px of the third card that the overflow
 * hides is scrollable to, which is what `proximity` was being kept for.
 *
 * `scroll-snap-stop: always` caps a fling at one card. Right for a three-card strip, which is
 * what this pattern is; a loop of twelve would be eleven swipes end to end, and that is the
 * one reason to drop it.
 *
 * `scroll-padding-inline` is set on **both** edges rather than only the start, because the end
 * alignment above measures against `scroll-padding-inline-end` — without it the last card
 * would rest against the side of the window instead of on the container's edge.
 */

@media (hover: none) {
	.wp-block-post-template.is-style-touch-carousel {
		/*
		 * The block's own column minimum, published by
		 * `includes/blocks/post-template-touch-carousel.php`. `20rem` is the design's
		 * 320px, for a block with no minimum set and for the editor canvas.
		 */
		--kg-touch-carousel-card: var(--kg-post-template-column-min, 20rem);

		/* How far the track reaches past its container on each side. */
		--kg-touch-carousel-bleed: max(
			0px,
			calc(
				(
						var(--screen-size, 100vw) -
							var(--wp--style--global--wide-size)
					) / 2
			)
		);

		/*
		 * The `Article card` lift's own extent: a 14px offset plus a 24px blur. Stated
		 * here rather than shared, because it is one number read off one other
		 * stylesheet — `group-article-card.css` — and a token for it would imply every
		 * card in the theme casts the same shadow.
		 */
		--kg-touch-carousel-lift: 2.375rem;

		display: flex;
		flex-wrap: nowrap;
		align-items: stretch;

		/* Core's own `max-width: 100%`, which the negative margins cannot beat. */
		max-inline-size: none;
		margin-inline: calc(-1 * var(--kg-touch-carousel-bleed));
		margin-block: calc(-1 * var(--kg-touch-carousel-lift));
		padding-inline: var(--kg-touch-carousel-bleed);
		padding-block: var(--kg-touch-carousel-lift);
		overflow-x: auto;
		overscroll-behavior-inline: contain;
		scroll-padding-inline: var(--kg-touch-carousel-bleed);
		scroll-snap-type: x mandatory;

		/* The card running off the screen is the affordance; the design draws no bar. */
		scrollbar-width: none;
	}

	.wp-block-post-template.is-style-touch-carousel::-webkit-scrollbar {
		display: none;
	}

	/*
	 * `flex-shrink: 0`, so the cards keep their width and the row overflows rather than
	 * three of them squashing into a phone. `flex-grow: 1` is what collapses the carousel
	 * back into a row once there is space for one.
	 */
	.wp-block-post-template.is-style-touch-carousel > li {
		flex: 1 0 var(--kg-touch-carousel-card);
		scroll-snap-align: start;
		scroll-snap-stop: always;
	}

	/*
	 * The last card aligns on the scrollport's *end*, so its snap position is the maximum
	 * scroll offset rather than a start edge beyond it — which is what stops `mandatory`
	 * from making the last card unreachable. See the note above.
	 */
	.wp-block-post-template.is-style-touch-carousel > li:last-child {
		scroll-snap-align: end;
	}
}
