/**
 * Orbital Photo Feed.
 *
 * The whole ring is CSS 3D transforms inside a `perspective` container. Each
 * item's resting angle is printed server-side into `--sml-orbital-angle`; the
 * script only ever moves one variable on the ring itself, so a spin is a
 * single composited transform rather than fifteen style writes a frame.
 *
 * Everything below degrades in a defined way. With no JavaScript the ring is
 * static and the front photo is the active one — which is a gallery, and
 * therefore fine. With `prefers-reduced-motion` there is no ring at all.
 */

/**
 * The card is a query container, and the radius is capped against its width.
 *
 * The server computes an ideal radius from the photo count — fifteen photos
 * need a wider ring than three or they smear together. But "ideal" assumes
 * room. Dropped into a 280px grid cell or a 300px rail, that same radius threw
 * every neighbour clean off the stage and left one lonely photo in a tall
 * empty box.
 *
 * `min()` against a container-query width means the module adapts to the slot
 * it lands in rather than to the viewport — which is the actual constraint,
 * since the same module sits in a 1150px band on one layout and a narrow rail
 * on another at identical screen widths.
 */
.sml-pfe-orbital {
	container-type: inline-size;
	--sml-orbital-radius: 320px;
	--sml-orbital-turn: 0deg;
	--sml-orbital-height: 300px;
	--sml-orbital-side: 0.18;
	--sml-orbital-rear: 0.05;
	--sml-orbital-blur: 3px;
}

.sml-pfe-orbital.is-size-compact { --sml-orbital-height: 220px; }
.sml-pfe-orbital.is-size-medium  { --sml-orbital-height: 300px; }
.sml-pfe-orbital.is-size-tall    { --sml-orbital-height: 400px; }

/* The effective radius is defined HERE, not on the card, because the card is
   not where the server writes it. `--sml-orbital-radius` is an inline style on
   this element; a `min()` evaluated on the parent reads the stylesheet default
   instead and silently ignores the count-derived value — which looks fine with
   three photos and smears with fifteen. `cqw` still resolves against the card,
   which is the query container. */
.sml-pfe-orbital-stage {
	--sml-orbital-r: min(var(--sml-orbital-radius), 78cqw);
	position: relative;
	height: var(--sml-orbital-height);
	perspective: 1100px;
	perspective-origin: 50% 45%;
	overflow: hidden;
	/* The drag surface. `pan-y` keeps vertical page scrolling working on
	   touch while horizontal gestures come to us. */
	touch-action: pan-y;
	cursor: grab;
	user-select: none;
}

.sml-pfe-orbital-stage.is-dragging {
	cursor: grabbing;
}

.sml-pfe-orbital-ring {
	position: absolute;
	inset: 0;
	margin: 0;
	padding: 0;
	list-style: none;
	transform-style: preserve-3d;
	transform: translateZ(calc(var(--sml-orbital-r) * -1)) rotateY(var(--sml-orbital-turn));
	/* No transition: the script drives this every frame with rAF. A
	   transition here fights the animation and produces rubber-banding. */
	will-change: transform;
}

.sml-pfe-orbital-item {
	position: absolute;
	inset-block-start: 50%;
	inset-inline-start: 50%;
	/* Sized from the stage HEIGHT, not its width.
	   Width-based sizing looked fine at one breakpoint and then filled the
	   whole stage at another — the front photo cropped against
	   `overflow:hidden` and the neighbours were pushed out of frame, which
	   loses the orbit entirely. Deriving from height keeps the ring in view at
	   every size the member can pick. */
	width: auto;
	margin: 0;
	/* Variable-width items, each centred on its own box rather than on a
	   shared column width — otherwise a wide photo and a tall one sit at
	   different distances from the middle of the ring. */
	display: flex;
	flex-direction: column;
	align-items: center;
	transform:
		translate(-50%, -50%)
		rotateY(var(--sml-orbital-angle))
		translateZ(var(--sml-orbital-r));
	transform-style: preserve-3d;
	opacity: var(--sml-orbital-rear);
	transition: opacity 220ms ease, filter 220ms ease;
	pointer-events: none;
}

/* Item depth classes are set by the script from the live angle. They are
   classes rather than inline styles so the visual language stays here. */
.sml-pfe-orbital-item.is-side {
	opacity: var(--sml-orbital-side);
}

.sml-pfe-orbital-item.is-active {
	opacity: 1;
	pointer-events: auto;
}

.sml-pfe-orbital.has-blur .sml-pfe-orbital-item {
	filter: blur(var(--sml-orbital-blur)) saturate(0.7);
}

.sml-pfe-orbital.has-blur .sml-pfe-orbital-item.is-active {
	filter: none;
}

/**
 * The image is shown WHOLE.
 *
 * `object-fit: cover` with a forced 4/5 box was cropping every photo to
 * portrait — a member who uploads a wide chart or a square logo was having the
 * edges cut off, which is the one thing a photo module must not do. Both
 * dimensions are now maxima and the intrinsic ratio decides the rest, so items
 * in the ring vary in shape. That is correct: they are different pictures.
 *
 * `width`/`height` attributes come from `wp_get_attachment_image()`, so the
 * browser knows each ratio before the bytes arrive and nothing shifts on load.
 */
.sml-pfe-orbital-img {
	display: block;
	width: auto;
	height: auto;
	max-height: calc(var(--sml-orbital-height) * 0.72);
	max-width: min(72cqw, 340px);
	object-fit: contain;
	border-radius: 14px;
	background: var(--sml-pfe-surface-2, #0d141d);
	box-shadow: 0 18px 44px rgba(0, 0, 0, 0.45);
}

.sml-pfe-orbital-item.is-active .sml-pfe-orbital-img {
	box-shadow: 0 22px 60px rgba(0, 0, 0, 0.6);
}

/**
 * Images that can carry transparency get no surface behind them.
 *
 * The server sets `is-alpha` from the mime type — everything except JPEG.
 * A PNG cut-out or a logo on a dark card is not "transparent", it is a picture
 * of a card, so the background, the rounded corners and the rectangular
 * box-shadow all have to go.
 *
 * `drop-shadow()` replaces `box-shadow` deliberately: it follows the alpha
 * channel, so a cut-out casts a shadow shaped like the subject instead of like
 * the rectangle it happens to be stored in. That single substitution is the
 * difference between "floating object" and "photo with the background
 * deleted".
 */
.sml-pfe-orbital-item.is-alpha .sml-pfe-orbital-img {
	background: none;
	border-radius: 0;
	box-shadow: none;
	filter: drop-shadow(0 12px 22px rgba(0, 0, 0, 0.5));
}

.sml-pfe-orbital-caption {
	margin-block-start: 8px;
	color: var(--sml-pfe-muted, #8aa6b8);
	font-size: 0.76rem;
	line-height: 1.35;
	text-align: center;
	opacity: 0;
	transition: opacity 220ms ease;
}

.sml-pfe-orbital-item.is-active .sml-pfe-orbital-caption {
	opacity: 1;
}

/* ---------------------------------------------------------------------------
 * Degenerate counts
 *
 * One photo is a photo. Two is a coin flip. Neither reads as an orbit, so they
 * are laid out flat and the script does not touch them.
 * ------------------------------------------------------------------------ */

.sml-pfe-orbital--single .sml-pfe-orbital-ring,
.sml-pfe-orbital--pair .sml-pfe-orbital-ring {
	position: static;
	display: flex;
	gap: 12px;
	align-items: center;
	justify-content: center;
	height: 100%;
	transform: none;
}

.sml-pfe-orbital--single .sml-pfe-orbital-item,
.sml-pfe-orbital--pair .sml-pfe-orbital-item {
	position: static;
	width: auto;
	max-width: 48%;
	transform: none;
	opacity: 1;
	filter: none;
	pointer-events: auto;
}

.sml-pfe-orbital--single .sml-pfe-orbital-item { max-width: 100%; }

.sml-pfe-orbital--single .sml-pfe-orbital-img,
.sml-pfe-orbital--pair .sml-pfe-orbital-img {
	width: auto;
	height: auto;
	max-width: 100%;
	max-height: 60vh;
}

@media (prefers-reduced-motion: reduce) {
	.sml-pfe-orbital-img {
		width: auto;
		height: auto;
		max-width: 100%;
		max-height: 40vh;
	}
}

.sml-pfe-orbital--single .sml-pfe-orbital-stage,
.sml-pfe-orbital--pair .sml-pfe-orbital-stage {
	perspective: none;
	cursor: default;
	overflow: visible;
	height: auto;
}

.sml-pfe-orbital--single .sml-pfe-orbital-caption,
.sml-pfe-orbital--pair .sml-pfe-orbital-caption {
	opacity: 1;
}

/* ---------------------------------------------------------------------------
 * Controls
 * ------------------------------------------------------------------------ */

.sml-pfe-orbital-controls {
	display: flex;
	gap: 10px;
	align-items: center;
	justify-content: center;
	margin-block-start: 10px;
}

.sml-pfe-orbital-nav {
	display: inline-grid;
	place-items: center;
	width: 34px;
	height: 34px;
	padding: 0;
	border: 1px solid var(--sml-pfe-line, rgba(255, 255, 255, 0.12));
	border-radius: 50%;
	background: var(--sml-pfe-surface-2, #0d141d);
	color: var(--sml-pfe-text, #eef4f8);
	font-size: 1.1rem;
	line-height: 1;
	cursor: pointer;
}

.sml-pfe-orbital-nav:hover,
.sml-pfe-orbital-nav:focus-visible {
	border-color: var(--sml-pfe-green, #35d07f);
	color: var(--sml-pfe-green, #35d07f);
}

.sml-pfe-orbital-counter {
	min-width: 4.5em;
	color: var(--sml-pfe-muted, #8aa6b8);
	font-size: 0.74rem;
	font-variant-numeric: tabular-nums;
	text-align: center;
}

/* ---------------------------------------------------------------------------
 * Mobile
 *
 * Shallower perspective and a smaller ring: the same radius that looks
 * cinematic at 1200px puts the neighbouring photos off-screen at 390px.
 * ------------------------------------------------------------------------ */

@media (max-width: 719px) {
	.sml-pfe-orbital-stage {
		perspective: 780px;
	}

	.sml-pfe-orbital-stage {
		--sml-orbital-r: min(calc(var(--sml-orbital-radius) * 0.62), 70cqw);
	}

	.sml-pfe-orbital-img {
		max-height: calc(var(--sml-orbital-height) * 0.66);
		max-width: 78cqw;
	}

	.sml-pfe-orbital-item.is-alpha .sml-pfe-orbital-img {
		/* drop-shadow is a filter, and filters are the expensive part on a
		   phone GPU. The image still sits on nothing, which is the point. */
		filter: none;
	}

	.sml-pfe-orbital.has-blur .sml-pfe-orbital-item {
		/* Blur is the single most expensive thing on this page for a phone
		   GPU, and it buys the least at this size. */
		filter: none;
	}
}

/* ---------------------------------------------------------------------------
 * Reduced motion
 *
 * Not "a slower orbit" — no orbit. Someone who has asked the OS to stop
 * animation does not want a carousel that spins on its own, and a ring that
 * only moves on demand is still a ring they did not ask for. They get the
 * photos, laid out flat and legible.
 * ------------------------------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
	.sml-pfe-orbital-stage {
		height: auto;
		perspective: none;
		overflow: visible;
		cursor: default;
	}

	.sml-pfe-orbital-ring {
		position: static;
		display: grid;
		grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
		gap: 10px;
		transform: none;
	}

	.sml-pfe-orbital-item {
		position: static;
		width: auto;
		transform: none !important;
		opacity: 1 !important;
		filter: none !important;
		pointer-events: auto;
		transition: none;
	}

	.sml-pfe-orbital-caption {
		opacity: 1;
	}

	.sml-pfe-orbital-controls {
		display: none;
	}
}

/* ---------------------------------------------------------------------------
 * Placement
 *
 * In the tiled lower grid the ring takes the full width. A carousel squeezed
 * into one 280px cell beside three other cards is not a smaller carousel, it
 * is a single photo in a tall empty box.
 * ------------------------------------------------------------------------ */

.sml-pfe-zone--grid-lower > .sml-pfe-orbital {
	grid-column: 1 / -1;
}

/* Browsers without container queries fall back to the viewport, which is the
   old behaviour and still correct in the wide slots. */
@supports not (container-type: inline-size) {
	.sml-pfe-orbital-stage {
		--sml-orbital-r: min(var(--sml-orbital-radius), 40vw);
	}
}
