/*
 * Block: acf/ticket-pro-support-messy
 *
 * Loaded only on pages that use this block (block.json "style"). Grid,
 * gutters and stacking are Bootstrap classes in render.php; this file is the
 * expanding-tile interaction and the brand details.
 *
 * Interaction model - no JavaScript:
 *   - From lg up the tiles share one flex row and every tile is compact by
 *     default. A tile expands while its list item is :hover or :focus-within
 *     (keyboard focus on the tile or its link counts), so it is not mouse-only.
 *     The expanded item gets a larger flex-grow, and because the row width is
 *     fixed its siblings narrow on their own. flex-grow is animatable, which is
 *     what makes it smooth.
 *   - Below lg, and on any device without hover, every tile simply rests in its
 *     expanded state. No content is locked behind an interaction, and a wrapped
 *     row - where an expanding tile has no siblings to take space from and can
 *     only push its own row taller - never has to animate at all.
 *
 * Why the description is laid out at a fixed measure:
 *   The tile's width is what animates, and the text inside it is laid out
 *   against that animating width - so the description rewrapped on almost
 *   every frame of the expansion (measured: 29-45 distinct text widths per
 *   hover, with the line count changing up to four times), which reads as the
 *   words shuffling between lines. Transitions cannot smooth that: a line
 *   break either happens or it does not.
 *
 *   So the text is not laid out against the animating width at all. The
 *   description gets a fixed measure - the width the expanded card ends at -
 *   so it is laid out once, in its final shape, from the first frame. It
 *   overhangs the card early in the expansion, which is invisible because the
 *   text is still transparent then, and fits exactly by the time it is seen.
 *   The title gets the same treatment as a max-width, capped at the compact
 *   card's measure: that is already the width it is laid out at when resting,
 *   so the resting design is untouched, and the expanded card can no longer
 *   pull it onto fewer lines.
 *
 *   Both measures assume the design's four tiles, so they are applied only to
 *   a row that has exactly four - :has() makes a row of any other length fall
 *   back to fluid text rather than overhanging a card that never gets that
 *   wide.
 *
 * Why the row's height is pinned, and where the pin has to go:
 *   Expanding must not make the card taller. A taller card moves the section
 *   below it, the page shifts under the cursor, the cursor falls out of the
 *   tile, the tile collapses - and a sweep across 01-04 shakes the page. So the
 *   space the description needs is paid for out of .tp-messy__media, the one
 *   part of the tile allowed to shrink.
 *
 *   That only works if the tile's height is *definite*. A flex column with an
 *   auto height has no free space to reclaim - it simply grows - so a
 *   min-height buys nothing here. The height therefore goes on the list item
 *   rather than on the tile: the tile carries Bootstrap's .h-100, which is
 *   height: 100% !important and beats anything this file can say about its own
 *   height, but 100% of a definite height is itself definite. Pinning the
 *   parent is what makes that utility resolve to a fixed number instead of to
 *   auto - the reason an earlier height on the tile itself did nothing.
 */

.tp-messy {
	/* How much wider the expanded tile grows relative to a compact one.
	   1.5 reproduces the proportions of the reference design. */
	--tp-messy-grow: 1.5;
	--tp-messy-speed: 0.5s;
	--tp-messy-ease: cubic-bezier(0.22, 0.8, 0.25, 1);

	background-color: var(--color-bg);

	/* Belt and braces: a scrollbar appearing for a single frame mid-transition
	   would resize every element on the page. clip, not hidden, so the section
	   never becomes a scroll container for anything inside it. */
	overflow-x: clip;
}


/*
 * The design sets a 32px gutter between the cards; Bootstrap's scale steps
 * from 24 straight to 48, so the row takes the value directly.
 *
 * gutter-x only from lg: a row's negative side margins are half its gutter,
 * and .container pads just 12px, so a wider gutter overflows the viewport on
 * mobile. gutter-y is safe at every width - it cannot push anything sideways.
 */
.tp-messy__tiles {
	--bs-gutter-y: 2rem;
}

@media (min-width: 992px) {
	.tp-messy__tiles {
		--bs-gutter-x: 2rem;
	}
}

/* -------------------------------------------------------------------------
   Tile - compact state
   ------------------------------------------------------------------------- */

.tp-messy__tile {
	position: relative; /* anchors .stretched-link */
	gap: 1rem;
	min-height: 20rem;
	padding: 1.5rem;
	background-color: var(--color-light);
	border: 1px solid transparent;
	border-radius: var(--tp-radius-lg);
	transition:
		background-color 0.35s ease,
		border-color 0.35s ease,
		box-shadow 0.35s ease;
}

.tp-messy__tile:focus {
	outline: none;
}

.tp-messy__tile:focus-visible {
	outline: 2px solid var(--color-focus);
	outline-offset: 3px;
}

/*
 * In the fixed-height tile only the image area may give up space. Without
 * this, the text block shrinks first - the collapsing description reports a
 * zero minimum height - and the expanded description gets clipped.
 */
.tp-messy__number,
.tp-messy__body {
	flex-shrink: 0;
}

.tp-messy__number {
	font-family: var(--font-heading);
	font-size: var(--fs-h2);
	font-weight: var(--fw-regular);
	line-height: 1;
	letter-spacing: var(--ls-h2);
	color: var(--color-heading);
}

/*
 * Image area. Transparent while compact; becomes the grey panel when expanded.
 * It keeps its space even with no image, ready for one to be added.
 *
 * Both states share one grid cell, so the compact illustration and the
 * expanded image cross-fade in place and the tile never reflows mid-swap.
 *
 * This is also the tile's shock absorber: min-height 0 lets it surrender
 * whatever height the opening description asks for, which is what keeps the
 * tile - and so the row, and so the page - the same size throughout.
 */
.tp-messy__media {
	display: grid;
	min-height: 0;
	padding: 0;
	border-radius: var(--tp-radius-md);
	overflow: hidden;
	transition:
		background-color 0.35s ease,
		padding var(--tp-messy-speed) var(--tp-messy-ease);
}

.tp-messy__state {
	grid-area: 1 / 1;
	display: flex;
	align-items: center;
	justify-content: center;
	min-height: 0;
	transition: opacity 0.35s ease;
}

/* The expanded image waits behind the compact one. visibility keeps it out of
   the accessibility tree and off pointer events while hidden. */
.tp-messy__item--has-expanded .tp-messy__state--expanded {
	opacity: 0;
	visibility: hidden;
	transition:
		opacity 0.35s ease,
		visibility 0s linear 0.35s;
}

/* A tile given only an expanded image has nothing to fade from, so it shows
   that image in both states rather than an empty panel until hover. */
.tp-messy__item--has-expanded .tp-messy__state--expanded:only-child {
	opacity: 1;
	visibility: visible;
}

.tp-messy__img {
	display: block;
	width: auto;
	height: auto;
	max-width: 100%;
	max-height: 9rem;
}

/*
 * The compact illustration shrinks on hover by scaling rather than by dropping
 * its max-height: a transform is painted, not laid out, so the shrink cannot
 * feed back into the tile's size.
 *
 * min(9rem, 100%) is the floor that makes a pinned tile height safe at every
 * width - on a narrow two-column card the media panel can end up shorter than
 * 9rem once the description is open, and a taller image would then be cropped
 * by the panel's overflow.
 */
.tp-messy__img--compact {
	max-height: min(9rem, 100%);
	transform-origin: center;
	transition: transform var(--tp-messy-speed) var(--tp-messy-ease);
}

/*
 * Editors upload their own illustrations, so the image has to survive any
 * aspect ratio: the panel sets the box and the image is fitted inside it,
 * never scaled up past its own pixels and never able to stretch the card.
 */
.tp-messy__img--expanded {
	width: 100%;
	height: 100%;
	max-width: 100%;
	max-height: 100%;
	object-fit: contain;
	object-position: center;
}

/* Sentence case, as the design sets it - the tracking that went with the
   previous all-caps setting goes with it. */
.tp-messy__title {
	font-family: var(--font-heading);
	font-size: var(--fs-p2);
	font-weight: var(--fw-semibold);
	line-height: var(--lh-tight);
	color: var(--color-heading);
}

.tp-messy__link {
	color: inherit;
	text-decoration: none;
}

/*
 * The row still opens with the 0fr grid-row technique, but only to make space:
 * it is what lets the image panel give up its height smoothly, so the tile's
 * pinned height holds. The text stays in the accessibility tree throughout.
 *
 * The gap above the description is padding on the clipped child rather than a
 * margin on the grid, so the one animation opens both - no margin left to
 * animate, and nothing that can round to a different height than the row.
 */
.tp-messy__desc {
	display: grid;
	grid-template-rows: 0fr;
	transition: grid-template-rows var(--tp-messy-speed) var(--tp-messy-ease);
}

/*
 * The reveal itself is opacity and a short lift - painted, not laid out, so
 * nothing about it can move a line break. It is deliberately late: the text
 * arrives once the card has all but finished widening, so what is seen is a
 * settled card with its description landing in it, never text being reflowed.
 *
 * Leaving is the mirror of that and much quicker - 0.12s, so the text is gone
 * before the card has narrowed far enough to rewrap behind it.
 */
.tp-messy__desc > * {
	min-height: 0;
	padding-top: 0.75rem;
	overflow: hidden;
	opacity: 0;
	transform: translateY(0.375rem);
	transition:
		opacity 0.12s ease,
		transform 0.12s ease;
}

/* -------------------------------------------------------------------------
   Tile - expanded state (hover / keyboard focus)
   ------------------------------------------------------------------------- */

/*
 * Only from lg up, where the tiles share one row whose height is pinned, so the
 * description's space can be found inside the tile. Below lg the tiles wrap and
 * rest expanded instead (see the wrapped/touch section), so none of this
 * applies there and there is nothing that can push a row taller.
 */
@media (min-width: 992px) {
	.tp-messy__item:is(:hover, :focus-within) .tp-messy__tile {
		background-color: var(--color-white);
		border-color: var(--color-border-subtle);
		box-shadow: 0 12px 32px color-mix(in srgb, var(--color-primary) 8%, transparent);
	}

	.tp-messy__item:is(:hover, :focus-within) .tp-messy__media {
		padding: 1.25rem;
		background-color: var(--color-light);
	}

	/* Swap the illustrations: compact out, the tile's own expanded image in. */
	.tp-messy__item--has-expanded:is(:hover, :focus-within) .tp-messy__state--compact {
		opacity: 0;
		visibility: hidden;
		transition:
			opacity 0.35s ease,
			visibility 0s linear 0.35s;
	}

	.tp-messy__item--has-expanded:is(:hover, :focus-within) .tp-messy__state--expanded {
		opacity: 1;
		visibility: visible;
		transition:
			opacity 0.35s ease,
			visibility 0s linear 0s;
	}

	/* 0.78 is the old 7rem-from-9rem step, kept identical but drawn, not laid out. */
	.tp-messy__item:is(:hover, :focus-within) .tp-messy__img--compact {
		transform: scale(0.78);
	}

	.tp-messy__item:is(:hover, :focus-within) .tp-messy__desc {
		grid-template-rows: 1fr;
	}

	.tp-messy__item:is(:hover, :focus-within) .tp-messy__desc > * {
		opacity: 1;
		transform: none;
		transition:
			opacity 0.26s ease 0.38s,
			transform 0.3s var(--tp-messy-ease) 0.38s;
	}
}

/*
 * The stable text measures (see the file header). Each value is the inner
 * width the card actually ends at, taken from the rendered page rather than
 * computed: the flex share alone does not predict it, because the narrowing
 * siblings stop at their own content width and give back a few pixels.
 *
 *   desc  - the expanded card's inner width, a little under so that a
 *           sub-pixel difference can never clamp the text and rewrap it.
 *   title - the compact card's inner width, which is what the title is already
 *           laid out at when the card is resting.
 *
 * Only for the design's four tiles: with any other number the expanded card is
 * a different width and a fixed measure would overhang it, so :has() drops
 * both and the text goes back to being fluid.
 */
@media (min-width: 992px) and (hover: hover) {
	.tp-messy__tiles:has(> .tp-messy__item:nth-child(4):last-child) {
		--tp-messy-desc-measure: 15rem;
		--tp-messy-title-measure: 10.5rem;
	}

	.tp-messy__tiles:has(> .tp-messy__item:nth-child(4):last-child) .tp-messy__desc > * {
		width: var(--tp-messy-desc-measure);
	}

	/*
	 * max-width, not width: the narrowed siblings are thinner than the compact
	 * card, and they have to keep fitting their own cards.
	 */
	.tp-messy__tiles:has(> .tp-messy__item:nth-child(4):last-child) .tp-messy__title {
		max-width: var(--tp-messy-title-measure);
	}
}

@media (min-width: 1200px) and (hover: hover) {
	.tp-messy__tiles:has(> .tp-messy__item:nth-child(4):last-child) {
		--tp-messy-desc-measure: 18rem;
		--tp-messy-title-measure: 13rem;
	}
}

@media (min-width: 1400px) and (hover: hover) {
	.tp-messy__tiles:has(> .tp-messy__item:nth-child(4):last-child) {
		--tp-messy-desc-measure: 22rem;
		--tp-messy-title-measure: 16rem;
	}
}

/* -------------------------------------------------------------------------
   Desktop: one row, the expanded tile widens and its siblings narrow
   ------------------------------------------------------------------------- */

@media (min-width: 992px) {
	/*
	 * Overrides Bootstrap's row-cols-md-2 widths once the row stops wrapping
	 * (flex-lg-nowrap in the markup).
	 *
	 * min-width: 0 matters as much as the flex shorthand: a flex item will not
	 * shrink below its own content by default, so once the expanded tile had
	 * taken its extra share the siblings could refuse to give it back and push
	 * the row past the container - a horizontal scrollbar flickering in and
	 * out for the length of the transition.
	 */
	.tp-messy__tiles > .tp-messy__item {
		flex: 1 1 0;
		width: auto;
		min-width: 0;
		max-width: none;
		transition: flex-grow var(--tp-messy-speed) var(--tp-messy-ease);
	}

	.tp-messy__tiles > .tp-messy__item:is(:hover, :focus-within) {
		flex-grow: var(--tp-messy-grow);
	}

	.tp-messy__tile {
		min-height: 28rem;
	}

	/*
	 * Narrowed siblings can push a title onto a second line. Reserving two
	 * lines, with the text sitting on the bottom one, stops titles (and the
	 * image above them) from jumping while the row resizes.
	 */
	.tp-messy__title {
		display: flex;
		align-items: flex-end;
		min-height: calc(2em * var(--lh-tight));
	}
}

/*
 * The pin (see the file header): a definite height on the list item, which the
 * tile's .h-100 then resolves against. The value matches the tile's min-height,
 * so the resting row is exactly what it was - all this changes is that the
 * expanded tile now has a fixed box to find the description's space inside.
 *
 * Only where a tile can actually be hovered: with hover: none every tile is
 * already expanded and free to size to its own content, so a long description
 * can never be clipped.
 */
@media (min-width: 992px) and (hover: hover) {
	.tp-messy__tiles > .tp-messy__item {
		height: 28rem;
	}
}

/* -------------------------------------------------------------------------
   Wrapped rows and touch: nothing to hover into, so show every tile expanded
   ------------------------------------------------------------------------- */

/*
 * Two cases, one presentation: a device that cannot hover, and any width below
 * lg, where the row wraps. A wrapped tile has no siblings to take width from -
 * expanding it can only make its own row taller, which is the page movement
 * this block must not have - so it rests expanded rather than animating.
 */
@media (max-width: 991.98px), (hover: none) {
	/* Nothing animates here and no height is pinned - every tile is already
	   in its expanded state, so it is free to size to its own content and a
	   long description can never be clipped. */
	.tp-messy__tile {
		background-color: var(--color-white);
		border-color: var(--color-border-subtle);
	}

	.tp-messy__media {
		padding: 1.25rem;
		background-color: var(--color-light);
	}

	/* No hover to swap the art, so a tile with an expanded image shows it. */
	.tp-messy__item--has-expanded .tp-messy__state--compact {
		opacity: 0;
		visibility: hidden;
	}

	.tp-messy__item--has-expanded .tp-messy__state--expanded {
		opacity: 1;
		visibility: visible;
		transition: none;
	}

	.tp-messy__img--compact {
		transform: scale(0.78);
		transition: none;
	}

	.tp-messy__desc {
		grid-template-rows: 1fr;
	}

	.tp-messy__desc > * {
		opacity: 1;
		transform: none;
		transition: none;
	}

	.tp-messy__tiles > .tp-messy__item:is(:hover, :focus-within) {
		flex-grow: 1;
	}
}

@media (prefers-reduced-motion: reduce) {
	.tp-messy__item,
	.tp-messy__tile,
	.tp-messy__media,
	.tp-messy__state,
	.tp-messy__img,
	.tp-messy__desc,
	.tp-messy__desc > * {
		transition: none !important;
	}
}
