/**
 * MCN Animations — Cards
 *
 * Rebuilt from:
 *   Julien Sulpis,   "3D Cards Flip"          (codepen.io/jsulpis/pen/VwBNoEb, MIT)
 *   Aaron Iker,      "Card hover effect"      (codepen.io/aaroniker/pen/yLEPJXj, MIT)
 *   Chris Smith,     "Responsive animated info card" (codepen.io/BlogFire/pen/mdXNMVX, MIT)
 *   Tobias Bogliolo, "CSS Flipping Card Split"(codepen.io/tobiasdev/pen/XjyaKr, MIT)
 *   Amit Sheen,      "House of CSS cards"     (codepen.io/amit_sheen/pen/QWGjRKR, MIT)
 *
 * FLIP CARDS AND ACCESSIBILITY: the thing everyone gets wrong
 * A hover flip hides one face with backface-visibility, but that face is
 * still in the accessibility tree and still focusable. The two usual patches
 * each fail a keyboard user. Flipping on :focus-within turns the card away
 * from a front-face control the moment it takes focus. Hiding the resting
 * face with `visibility` takes the back face out of the tab order entirely,
 * so its links can never be reached.
 *
 * The rule here is simpler: keyboard focus decides the face.
 *   - Both faces stay in the tab order and the accessibility tree, so Tab
 *     reaches every control and a screen reader hears the whole card.
 *   - Whichever face holds :focus-visible is the face shown, over hover and
 *     over data-flipped, so the focused control is never turned away.
 *   - It is :focus-visible rather than :focus-within, so a mouse click on a
 *     control never turns the card out from under the pointer.
 *   - A button with data-anim-flip turns the card for touch and keyboard
 *     users, and the runtime hands focus to the face it reveals.
 *
 * <div class="anim-card-3d">
 *   <div class="anim-card-3d__inner">
 *     <div class="anim-card-3d__face anim-card-3d__face--front">
 *       ... <button type="button" data-anim-flip>Details</button>
 *     </div>
 *     <div class="anim-card-3d__face anim-card-3d__face--back">
 *       ... <button type="button" data-anim-flip>Flip back</button>
 *     </div>
 *   </div>
 * </div>
 *
 * @package MCN_Animations
 */

/* --------------------------------------------------------------------------
 * Shared card shell
 * ----------------------------------------------------------------------- */

.anim-card-3d {
	--card-dur: var(--anim-duration-slow);
	--anim-flip: 0;
	position: relative;
	perspective: 1200px;
}

.anim-card-3d__inner {
	position: relative;
	width: 100%;
	height: 100%;
	transform-style: preserve-3d;
	transform: rotateY(calc(var(--anim-flip) * 180deg));
	transition: transform var(--card-dur) var(--anim-ease);
}

.anim-card-3d__face {
	position: absolute;
	inset: 0;
	display: grid;
	backface-visibility: hidden;
	-webkit-backface-visibility: hidden;
	border-radius: inherit;
	overflow: hidden;
}

.anim-card-3d__face--back {
	transform: rotateY(180deg);
}

/* Pointer: hover turns the card. data-flipped pins it either way, so a
   "flip back" button still works while the pointer rests on the card. */
.anim-card-3d:hover,
.anim-card-3d[data-flipped="true"] {
	--anim-flip: 1;
}

.anim-card-3d[data-flipped="false"] {
	--anim-flip: 0;
}

/* Keyboard: the face holding focus is the face shown. These outrank the
   pointer rules on specificity. Each stays in its own rule so a browser
   without :has() drops only these, never the hover flip above. */
.anim-card-3d:has(.anim-card-3d__face--back:focus-visible, .anim-card-3d__face--back :focus-visible) {
	--anim-flip: 1;
}

.anim-card-3d:has(.anim-card-3d__face--front:focus-visible, .anim-card-3d__face--front :focus-visible) {
	--anim-flip: 0;
}

/* A face the runtime focused (its face had no control to hand focus to). */
.anim-card-3d__face:focus-visible {
	outline: var(--anim-focus-width) solid var(--anim-focus-color);
	outline-offset: calc(var(--anim-focus-offset) * -1);
}

/* Flip buttons need the runtime; without it they would do nothing. */
html:not(.js-anim) .anim-card-3d [data-anim-flip] {
	display: none;
}

/* --------------------------------------------------------------------------
 * Split flip — the two halves rotate away from a centre seam
 * ----------------------------------------------------------------------- */

.anim-card-split {
	position: relative;
	display: grid;
	grid-template-columns: 1fr 1fr;
	perspective: 1400px;
	overflow: hidden;
	border-radius: inherit;
}

.anim-card-split__half {
	position: relative;
	backface-visibility: hidden;
	transition: transform var(--anim-duration-slow) var(--anim-ease);
}

.anim-card-split__half--l { transform-origin: left center; }
.anim-card-split__half--r { transform-origin: right center; }

.anim-card-split:hover .anim-card-split__half--l,
.anim-card-split:focus-within .anim-card-split__half--l {
	transform: rotateY(-180deg);
}

.anim-card-split:hover .anim-card-split__half--r,
.anim-card-split:focus-within .anim-card-split__half--r {
	transform: rotateY(180deg);
}

.anim-card-split__reveal {
	position: absolute;
	inset: 0;
	z-index: -1;
	display: grid;
	place-items: center;
}

/* --------------------------------------------------------------------------
 * Shine tiles
 *
 * The original masks a conic gradient over a grid of tiles and animates their
 * opacity. We drive a single radial highlight from the pointer position, which
 * is one paint instead of N and reads identically.
 * ----------------------------------------------------------------------- */

.anim-card-shine {
	position: relative;
	isolation: isolate;
	overflow: hidden;
	transition:
		transform var(--anim-duration) var(--anim-ease),
		box-shadow var(--anim-duration) var(--anim-ease);
}

.anim-card-shine::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	pointer-events: none;
	opacity: 0;
	transition: opacity var(--anim-duration) var(--anim-ease);
	background: radial-gradient(
		circle 180px at var(--shine-x, 50%) var(--shine-y, 50%),
		rgb(255 255 255 / 0.22),
		transparent 60%
	);
}

/* A faint tile grid underneath, so the highlight reads as lighting a surface
   rather than a floating blob. */
.anim-card-shine::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 0;
	pointer-events: none;
	opacity: 0;
	transition: opacity var(--anim-duration) var(--anim-ease);
	background-image:
		linear-gradient(to right, rgb(255 255 255 / 0.06) 1px, transparent 1px),
		linear-gradient(to bottom, rgb(255 255 255 / 0.06) 1px, transparent 1px);
	background-size: 34px 34px;
	-webkit-mask-image: radial-gradient(circle 180px at var(--shine-x, 50%) var(--shine-y, 50%), #000, transparent 70%);
	mask-image: radial-gradient(circle 180px at var(--shine-x, 50%) var(--shine-y, 50%), #000, transparent 70%);
}

.anim-card-shine:hover::before,
.anim-card-shine:focus-within::before,
.anim-card-shine:hover::after,
.anim-card-shine:focus-within::after {
	opacity: 1;
}

.anim-card-shine:hover,
.anim-card-shine:focus-within {
	transform: translateY(-4px);
	box-shadow: 0 20px 44px -24px rgb(0 0 0 / 0.6);
}

/* --------------------------------------------------------------------------
 * Info slide panel
 *
 * 1.4.13 (AA): the panel is inside the card's own box, so it is hoverable and
 * persistent, and it overlays nothing outside the card.
 * ----------------------------------------------------------------------- */

.anim-card-info {
	position: relative;
	overflow: hidden;
	isolation: isolate;
}

.anim-card-info__panel {
	position: absolute;
	inset: auto 0 0 0;
	padding: 1.25rem;
	background: var(--anim-card-panel, rgb(16 24 32 / 0.94));
	color: #fff;
	transform: translateY(100%);
	transition: transform var(--anim-duration) var(--anim-ease);
}

.anim-card-info:hover .anim-card-info__panel,
.anim-card-info:focus-within .anim-card-info__panel {
	transform: none;
}

/* Sideways variant. */
.anim-card-info--side .anim-card-info__panel {
	inset: 0 0 0 auto;
	width: min(78%, 320px);
	transform: translateX(100%);
}

.anim-card-info--side:hover .anim-card-info__panel,
.anim-card-info--side:focus-within .anim-card-info__panel {
	transform: none;
}

/* --------------------------------------------------------------------------
 * Rotating tower
 *
 * WCAG 2.2.2 (Level A): this rotates forever, so it needs a pause control.
 * It stops on hover and focus-within, and .is-paused is toggled by a real
 * button that the JS wires up. Do not ship it without that button.
 * ----------------------------------------------------------------------- */

.anim-tower {
	--tower-count: 8;
	--tower-radius: 160px;
	position: relative;
	width: 100%;
	height: var(--tower-h, 340px);
	perspective: 1200px;
}

.anim-tower__stage {
	position: absolute;
	inset: 0;
	transform-style: preserve-3d;
	animation: anim-tower-spin var(--tower-speed, 26s) linear infinite;
}

.anim-tower:hover .anim-tower__stage,
.anim-tower:focus-within .anim-tower__stage,
.anim-tower.is-paused .anim-tower__stage {
	animation-play-state: paused;
}

.anim-tower__card {
	position: absolute;
	top: 50%;
	left: 50%;
	width: var(--tower-card-w, 120px);
	height: var(--tower-card-h, 170px);
	margin: calc(var(--tower-card-h, 170px) / -2) 0 0 calc(var(--tower-card-w, 120px) / -2);
	/* --i is the card's index; the ring is laid out by rotating each card
	   around Y then pushing it out along Z. */
	transform:
		rotateY(calc(360deg / var(--tower-count) * var(--i, 0)))
		translateZ(var(--tower-radius));
	backface-visibility: hidden;
}

@keyframes anim-tower-spin {
	to { transform: rotateY(360deg); }
}

@media (prefers-reduced-motion: reduce) {

	.anim-card-3d__inner,
	.anim-card-split__half,
	.anim-card-info__panel,
	.anim-card-shine,
	.anim-card-shine::before,
	.anim-card-shine::after {
		transition: none !important;
	}

	.anim-tower__stage {
		animation: none !important;
	}

	/* .anim-card-3d__inner above: the flip still happens, instantly, so the
	   face holding focus is still the face shown. */
}
