/* Gallery Grid 001 — fanned photo deck.
 *
 * ONE VARIABLE SIZES THE WHOLE THING. `--fan-card` is the card's width; the card
 * height comes from its aspect ratio, the spread and droop are expressed in
 * PERCENT (which resolve against the card's own box, so they scale with it), and
 * the deck's height is a multiple of the card. Change `--fan-card` and the entire
 * component resizes in proportion — no second number to keep in sync, and no
 * breakpoint to retune, because the clamp is already fluid.
 *
 * ONE TRANSFORM, DRIVEN BY VARIABLES. There is exactly one `transform` in this
 * file. Every state — resting, hovered, nudged aside by a hovered neighbour —
 * changes a custom property that the transform reads, never the transform itself.
 * That is what keeps the motion continuous: the browser interpolates between two
 * values of the same transform, so a card eases from wherever it is to wherever
 * it should be. Declaring a second, separate transform for the hover state is
 * what makes effects like this snap.
 *
 * THE CARD COUNT IS NOT WRITTEN DOWN ANYWHERE. Each card's place in the fan is
 * arithmetic on its index and on how many cards the deck actually holds, both read
 * from the DOM — so cards can be added and removed in the editor and the fan
 * re-centres itself, keeps its symmetry, and grows its own box to fit.
 */

/* At a phone width the opened fan can reach past the viewport, and a decorative
   section must never give the page a horizontal scrollbar. `overflow-x: clip` is
   the tool rather than `hidden`: it makes no scroll container, and it is the one
   pairing that still lets the vertical axis stay visible — which matters here,
   because the hovered card lifts OUT of the deck's box. */
.gallery-grid-001 {
	overflow-x: clip;
}

.gallery-grid-001__deck {
	/* THE one size. Fluid by default: small on a phone, capped on a wide screen.

	   The FLOOR is what keeps the deck inside a phone, and it is easy to raise by
	   accident when scaling the rest up. At five cards the fan is about 2.9
	   card-widths across before the hover spread is added, so a floor above ~6.5rem
	   runs off both edges at 390px — measured at an 8rem floor: the deck spanned
	   -28…399 in a 386px viewport, with 13px of document overflow. The middle and
	   ceiling are what make the cards bigger; the floor should only ever go down.
	   A deck of more than five is proportionally wider, so it wants a smaller card,
	   not the same one. */
	--fan-card: clamp(6.5rem, 20vw, 22rem);

	/* Resting geometry, measured from the reference. */
	--fan-angle: 12deg;   /* rotation per step out from the middle */
	--fan-shift: 50%;     /* horizontal offset per step, of the card's own width */
	--fan-droop: 3.3%;    /* vertical drop per step SQUARED, of the card's height */
	--fan-shrink: 0.06;   /* scale lost per step */

	/* Interaction. Deliberately gentle — this is a nudge, not a pop. */
	--fan-lift: -14%;     /* how far the hovered card rises, of its own height */
	--fan-pop: 1.08;      /* how much it grows, as a multiplier of its resting scale */
	--fan-spread: 36%;    /* how far the card NEXT to the hovered one shuffles away */

	/*
	 * HOW MANY CARDS THERE ARE. Counted from the DOM by the rules below, so the
	 * deck re-centres itself whenever one is added or removed in the editor —
	 * nothing in this file names a card count. The `1` here is the fallback for a
	 * deck with more cards than those rules cover; see the note there.
	 */
	--n: 1;
	/* The outermost card's distance from the middle — half the deck. */
	--fan-reach: calc((var(--n) - 1) / 2);

	position: relative;
	/*
	 * Derived, not cemented: room for a 2:3 card, the outer cards' droop, and the
	 * hover lift. The droop grows with the SQUARE of the reach, so the deck has to
	 * grow with it too or a seven-card fan hangs out of its own box — hence the
	 * reach² term rather than a constant.
	 *
	 * `0.065` starts from `--fan-droop` (3.3%) × the card's 3/2 height ratio ≈ 0.05
	 * and is rounded generously up. Two reasons it cannot be the bare ratio. The
	 * droop pushes the fan DOWN from the deck's mid-line while the box grows in
	 * BOTH directions, so the bottom edge runs out of room at twice the rate you
	 * would expect; and a card's bounding height grows as it rotates, which also
	 * scales with the reach. At the bare 0.05 a seven-card fan measured 6px past
	 * the bottom of its own box. Verified by measurement at every count from one to
	 * nine, not by the algebra alone.
	 *
	 * This is also the one place the droop is restated rather than read: the
	 * transform uses a percentage (which resolves against the card, which is the
	 * point), and calc() cannot multiply a length by a percentage. Retune it
	 * alongside `--fan-droop`, or not at all — slack here costs nothing but a
	 * little empty space.
	 */
	block-size: calc(var(--fan-card) * (2 + 0.065 * var(--fan-reach) * var(--fan-reach)));
	margin-inline: auto;
}

/*
 * COUNTING THE CARDS, in CSS.
 *
 * Each rule matches a deck that HAS an Nth card, and they run in ascending order,
 * so for a deck of five all of 2–5 match and the last one wins on source order.
 * That is the whole mechanism — no JS, and it works identically in the editor,
 * which matters because adding and removing cards is something you do there.
 *
 * `of .gallery-grid-001__card` is not decoration. Gutenberg renders a block
 * appender as the last child of a container in the canvas, so a plain
 * `:nth-child(5)` would count it as a sixth card and skew the whole fan while
 * editing — correct on the front end, wrong where you are working. Counting only
 * the cards makes both surfaces agree, and makes the deck immune to anything else
 * that ends up inside it.
 *
 * The list stops at nine. A tenth card falls back to `--n: 1` and lands on the
 * middle of the deck rather than breaking the layout; extend the list if a deck
 * ever genuinely needs more (a fan of ten is already wider than the container).
 */
.gallery-grid-001__deck:has(.gallery-grid-001__card:nth-child(2 of .gallery-grid-001__card)) { --n: 2; }
.gallery-grid-001__deck:has(.gallery-grid-001__card:nth-child(3 of .gallery-grid-001__card)) { --n: 3; }
.gallery-grid-001__deck:has(.gallery-grid-001__card:nth-child(4 of .gallery-grid-001__card)) { --n: 4; }
.gallery-grid-001__deck:has(.gallery-grid-001__card:nth-child(5 of .gallery-grid-001__card)) { --n: 5; }
.gallery-grid-001__deck:has(.gallery-grid-001__card:nth-child(6 of .gallery-grid-001__card)) { --n: 6; }
.gallery-grid-001__deck:has(.gallery-grid-001__card:nth-child(7 of .gallery-grid-001__card)) { --n: 7; }
.gallery-grid-001__deck:has(.gallery-grid-001__card:nth-child(8 of .gallery-grid-001__card)) { --n: 8; }
.gallery-grid-001__deck:has(.gallery-grid-001__card:nth-child(9 of .gallery-grid-001__card)) { --n: 9; }

/*
 * The class is DOUBLED for the trap this theme hit in `feature-grid-003`:
 * Gutenberg puts `.block-editor-block-list__block { position: relative }` on every
 * block in the canvas. That is a single class, so a bare `.gallery-grid-001__card`
 * would only TIE — and a tie falls to source order, which is reversed between the
 * front end and the editor. Left single, the cards drop out of the fan and stack
 * down the canvas: correct on the page, broken while editing.
 */
.gallery-grid-001__card.gallery-grid-001__card {
	/* The three state variables. Every rule below moves the card by changing one
	   of these, never by redeclaring the transform. */
	--push: 0;    /* -1 shuffle left, +1 shuffle right, 0 stay put */
	--lift: 0%;   /* rise out of the deck */
	--pop: 1;     /* grow, relative to the resting scale */

	/*
	 * WHERE THIS CARD SITS IN THE FAN — arithmetic, not a lookup table.
	 *
	 * `--k` is the card's 1-based index (set below); `--n` is the deck's count
	 * (inherited). Everything else falls out of the two:
	 *
	 *   --i   signed offset from the middle. Negative left, positive right, 0 dead
	 *         centre. An ODD count puts one card upright; an EVEN count straddles
	 *         the middle with a ±0.5 pair, which is the correct fan either way.
	 *   --d   its distance from the middle, i.e. |--i|, which drives the droop and
	 *         the shrink. `max(x, -x)` rather than `abs()` — same result, and
	 *         supported everywhere this site runs.
	 *
	 * These used to be five hand-written :nth-child rules holding -2…+2, which
	 * silently encoded "this deck has exactly five cards": remove two in the editor
	 * and the survivors kept their old offsets, so the fan sat off to one side
	 * instead of re-centring. Deriving them costs one line and removes the coupling.
	 */
	--k: 1;
	--i: calc(var(--k) - (var(--n) + 1) / 2);
	--d: max(var(--i), calc(-1 * var(--i)));

	position: absolute;
	inset-block-start: 50%;
	inset-inline-start: 50%;
	inline-size: var(--fan-card);
	aspect-ratio: 2 / 3;

	/* Order matters. The first translate centres the card on the deck's midpoint;
	   the fan offsets then apply in the card's own coordinate space, so rotate()
	   last swings the card about its own centre rather than the deck's. */
	transform:
		translate(-50%, -50%)
		translateX(calc(var(--i) * var(--fan-shift) + var(--push) * var(--fan-spread)))
		translateY(calc(var(--d) * var(--d) * var(--fan-droop) + var(--lift)))
		scale(calc((1 - var(--d) * var(--fan-shrink)) * var(--pop)))
		rotate(calc(var(--i) * var(--fan-angle)));

	/*
	 * The stacking is FIXED — nearer the middle sits higher, and it stays that way
	 * on hover. z-index cannot be interpolated, so raising a card on hover makes it
	 * jump in front in a single frame while everything else eases; that one
	 * discrete change is what reads as "sharp" no matter how smooth the transform
	 * around it is. The card rises out of the top of the deck instead, which is
	 * legible without reordering anything.
	 */
	z-index: calc(20 - var(--d));

	/* Radius but NOT `overflow: hidden` — the clipping lives on the photo instead.
	   The card has to stay unclipped so the hit area below can reach outside it;
	   the radius is kept here only so the shadow matches the rounded picture. */
	border-radius: var(--radius);
	box-shadow: 0 1.2rem 2.5rem -1rem color-mix(in srgb, var(--color-text) 35%, transparent);

	/* The reference's own easing: fast to start, settling at the end. */
	transition: transform 0.5s cubic-bezier(0.2, 0.8, 0.2, 1);
	will-change: transform;
}

/* Each card's index. The only per-card value in the file — its position in the
   fan is computed from this and the count, above. Same nine-card ceiling, same
   `of` qualifier, for the same reasons. */
.gallery-grid-001__card:nth-child(1 of .gallery-grid-001__card) { --k: 1; }
.gallery-grid-001__card:nth-child(2 of .gallery-grid-001__card) { --k: 2; }
.gallery-grid-001__card:nth-child(3 of .gallery-grid-001__card) { --k: 3; }
.gallery-grid-001__card:nth-child(4 of .gallery-grid-001__card) { --k: 4; }
.gallery-grid-001__card:nth-child(5 of .gallery-grid-001__card) { --k: 5; }
.gallery-grid-001__card:nth-child(6 of .gallery-grid-001__card) { --k: 6; }
.gallery-grid-001__card:nth-child(7 of .gallery-grid-001__card) { --k: 7; }
.gallery-grid-001__card:nth-child(8 of .gallery-grid-001__card) { --k: 8; }
.gallery-grid-001__card:nth-child(9 of .gallery-grid-001__card) { --k: 9; }

/* The hovered card rises and grows a little, keeping its angle and its place in
   the stack. */
.gallery-grid-001__card:hover,
.gallery-grid-001__card:focus-within {
	--lift: var(--fan-lift);
	--pop: var(--fan-pop);
}

/*
 * …and the deck opens around it, the displacement DECAYING with distance: the
 * card right beside the hovered one gets out of the way hardest, the next one
 * less, and the far end barely stirs. `--push` is a signed MULTIPLIER of
 * `--fan-spread`, not a raw distance: 1 · 0.65 · 0.4 · 0.22.
 *
 * The direction of the decay is the whole point and easy to get backwards. Growing
 * outward (1 · 1.35 · 1.65 · 1.9) makes the entire deck fly apart — every card
 * moves, the far ones most, and the gesture stops reading as "room being made
 * beside this card". Decaying keeps the motion local: the effect is clearly about
 * the card you are pointing at, and the outer cards only acknowledge it.
 *
 * The chains are exact, not cumulative: `:hover + card + card` matches only the
 * card two along, so every card matches exactly one rule and no specificity
 * tie-breaking is involved. `:is(:hover, :focus-within)` keeps that readable —
 * it contributes the specificity of a single pseudo-class, so it changes nothing
 * about how these resolve.
 *
 * `:has(+ …)` is what makes the leftward half possible at all: CSS has no
 * previous-sibling combinator, so "the card whose next-but-N sibling is hovered"
 * is the only way to select backwards.
 */
.gallery-grid-001__card:has(+ .gallery-grid-001__card:is(:hover, :focus-within)) { --push: -1; }
.gallery-grid-001__card:has(+ .gallery-grid-001__card + .gallery-grid-001__card:is(:hover, :focus-within)) { --push: -0.65; }
.gallery-grid-001__card:has(+ .gallery-grid-001__card + .gallery-grid-001__card + .gallery-grid-001__card:is(:hover, :focus-within)) { --push: -0.4; }
.gallery-grid-001__card:has(+ .gallery-grid-001__card + .gallery-grid-001__card + .gallery-grid-001__card + .gallery-grid-001__card:is(:hover, :focus-within)) { --push: -0.22; }

.gallery-grid-001__card:is(:hover, :focus-within) + .gallery-grid-001__card { --push: 1; }
.gallery-grid-001__card:is(:hover, :focus-within) + .gallery-grid-001__card + .gallery-grid-001__card { --push: 0.65; }
.gallery-grid-001__card:is(:hover, :focus-within) + .gallery-grid-001__card + .gallery-grid-001__card + .gallery-grid-001__card { --push: 0.4; }
.gallery-grid-001__card:is(:hover, :focus-within) + .gallery-grid-001__card + .gallery-grid-001__card + .gallery-grid-001__card + .gallery-grid-001__card { --push: 0.22; }

.gallery-grid-001__photo {
	margin: 0;
	block-size: 100%;
	/* The clip that used to be on the card. The figure already gets
	   `overflow: hidden` from the theme's "Fill" style (main.css §8a), so it only
	   needs the corner to round the photograph. */
	border-radius: var(--radius);
}

/*
 * A HIT AREA THAT DOES NOT MOVE.
 *
 * The hovered card rises, so it leaves the pointer, which ends the hover, which
 * drops it back under the pointer — a flicker loop. The first attempt at this
 * simply extended the card's box downward, which FAILED for a subtle reason worth
 * keeping: the extension is a child, so it rose with the card too. Its lower edge
 * retreated by exactly the lift, and any pointer in the strip it vacated fell out
 * — the loop just moved a few pixels down the page. Making the extension bigger
 * only moves the flickering band, it never removes it.
 *
 * The fix is to COUNTER-TRANSFORM the layer by the same amount the card moves, so
 * it stays pinned to the card's resting footprint no matter what the card does.
 * A hit area that never moves cannot lose the pointer, so the loop is impossible
 * rather than merely unlikely.
 *
 * `inset: 0` deliberately: the layer is exactly the card's own rectangle, never
 * larger. Hover therefore starts and ends on the card's real footprint — the
 * position it occupies when you approach it — and not on an invisible margin
 * around it. The trade is that the top strip of a RAISED card is not itself
 * hoverable; moving up into it simply ends the hover once and the card settles,
 * which is stable rather than a loop.
 *
 * The counter-transform carries the same transition as the card, so the two stay
 * in step through the animation instead of drifting apart mid-flight.
 */
.gallery-grid-001__card::after {
	content: "";
	position: absolute;
	inset: 0;
	transform:
		translateY(calc(-1 * var(--lift)))
		scale(calc(1 / var(--pop)));
	transition: transform 0.5s cubic-bezier(0.2, 0.8, 0.2, 1);
}

/*
 * Reduced motion: the deck holds completely still. Because every state is a
 * variable, this only has to reset the three of them — the single transform then
 * resolves to the resting fan on its own, with no risk of a stale hover rule
 * leaving a card somewhere unexpected.
 */
@media (prefers-reduced-motion: reduce) {
	/* Zeroing the three knobs on the DECK is enough: the cards inherit them, so
	   every `calc()` above resolves to the resting fan no matter which `--push`
	   the cascade has set. Resetting the cascade rule by rule would mean matching
	   eight selectors' specificity — this cannot fall out of sync with them. */
	.gallery-grid-001__deck {
		--fan-spread: 0%;
		--fan-lift: 0%;
		--fan-pop: 1;
	}

	.gallery-grid-001__card.gallery-grid-001__card {
		transition: none;
	}
}
