/*
 * Lightbox — a fullscreen <dialog> carousel for images.
 *
 * Opens in the shared viewer frame (assets/css/viewer.css), as a Video-width
 * wage/modal does, so images and video look the same.
 *
 * Ported from the PHP framework's includes/components/lightbox. Structure is
 * unchanged; every token is remapped to theme.json's presets so a child retunes
 * it with the rest of the system (radius, transition, spacing, colour).
 *
 * Rendered as a dependency by whichever block needs it (today: core's gallery
 * and image blocks, adopted in inc/lightbox.php),
 * never inserted on its own — see inc/lightbox.php for the markup.
 *
 * Column layout: a top bar (zoom, counter, close) over a flex-grow stage that
 * bounds the image. The stage holds a translated track, one slide per image;
 * assets/js/lightbox.js drives it.
 */

/*
 * Adopted core triggers.
 *
 * Core positions `.lightbox-trigger` from JS — `callbacks.setButtonStyles`
 * writes its top and right on load and on resize. That module is deregistered
 * (see inc/lightbox.php), so the button needs real CSS or it collapses to a
 * 12px icon in the figure's top-left corner, which is then the only clickable
 * spot. The image carries the index too, so the picture itself is the hit area
 * and this button is the keyboard affordance.
 */
.wp-lightbox-container [data-lightbox-index] {
	cursor: zoom-in;
}

.wp-lightbox-container .lightbox-trigger {
	position: absolute;
	top: var(--wp--preset--spacing--xs);
	right: var(--wp--preset--spacing--xs);
	display: grid;
	place-items: center;
	inline-size: 2rem;
	block-size: 2rem;
	padding: 0;
	border: 0;
	border-radius: var(--wp--preset--border-radius--s);
	background: rgb(0 0 0 / 0.5);
	opacity: 0;
	transition: opacity var(--wp--custom--transition--fast);
}

/*
 * Hidden until wanted, but never hidden from the keyboard: opacity keeps it
 * focusable, where display:none would take it out of the tab order and leave
 * the gallery openable by pointer only.
 */
.wp-lightbox-container:hover .lightbox-trigger,
.wp-lightbox-container .lightbox-trigger:focus-visible {
	opacity: 1;
}

.wp-lightbox-container .lightbox-trigger:focus-visible {
	outline: 2px solid currentColor;
	outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
	.wp-lightbox-container .lightbox-trigger {
		transition: none;
	}
}

/*
 * The frame, bar and buttons are the shared viewer (assets/css/viewer.css):
 * the dialog carries `viewer`, the bar `viewer-bar`, each button
 * `viewer-control`. This file adds only what is the lightbox's own.
 */

/*
 * Focus lands on the dialog itself on open (see the JS) so arrow-key nav works
 * without lighting up a control. It is a container, so no ring.
 */
.lightbox:focus {
	outline: none;
}

/* ── Top bar ────────────────────────────────────────────────── */

/*
 * Slide counter — the position indicator for swipe-only nav. flex:1 fills the
 * gap between the two equal-width buttons, so it lands dead centre.
 */
.lightbox__counter {
	flex: 1;
	display: flex;
	align-items: center;
	justify-content: center;
	margin: 0;
	color: var(--wp--preset--color--contrast);
	font-size: var(--wp--preset--font-size--large);
	font-weight: var(--wp--custom--font-weight--bold);
	font-variant-numeric: tabular-nums;
	letter-spacing: 0.02em;
	text-shadow: 0 1px 3px var(--wp--custom--lightbox--icon--outline);
	pointer-events: none;
}

.lightbox__counter[hidden] {
	display: none;
}

/* ── Stage ──────────────────────────────────────────────────── */

.lightbox__stage {
	position: relative;
	flex: 1 1 auto;
	min-height: 0;
	display: flex;
	overflow: clip; /* clips the off-screen carousel slides */
}

/*
 * The track is a row of full-width slides; the JS translates it on X.
 * touch-action:none because every gesture is hand-driven — there is no native
 * scroll here to cooperate with.
 */
.lightbox__track {
	display: flex;
	flex: 1;
	min-height: 0;
	width: 100%;
	touch-action: none;
	will-change: transform;
}

/* Each slide is exactly the stage width and centres its image. */
.lightbox__slide {
	flex: 0 0 100%;
	min-width: 0;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	cursor: default;
}

/*
 * Bounded by the stage height, so it never reaches up under the bar — and by
 * the file's own width. With `sizes="100vw"` the browser reports every image as
 * viewport-wide whatever the file really is, so without that second bound a
 * 400px image would be stretched to fill the stage.
 */
.lightbox__img {
	max-width: min(90vw, var(--lightbox-full-width, 100vw));
	max-height: 100%;
	object-fit: contain;
	border-radius: var(--wp--preset--border-radius--m);

	/*
	 * Zoom transform, driven by the JS: --lightbox-zoom scales and
	 * --lightbox-pan-x/y translate. The defaults are the resting state.
	 */
	transform: translate(var(--lightbox-pan-x, 0px), var(--lightbox-pan-y, 0px)) scale(var(--lightbox-zoom, 1));
	transition: transform var(--wp--custom--transition--fast);
	touch-action: none;
	-webkit-user-drag: none;
	cursor: zoom-in;
}

/* Zoomed → open hand (it can be dragged to pan); closed hand while dragging. */
.lightbox__img--zoomed {
	cursor: grab;
}

/*
 * While actively dragging or pinching, kill the transition so the image tracks
 * the finger 1:1 instead of lagging behind it.
 */
.lightbox__img--grabbing {
	transition: none;
	cursor: grabbing;
}

.lightbox__caption {
	margin-top: var(--wp--preset--spacing--s);
	color: var(--wp--custom--contrast--muted);
	font-size: var(--wp--preset--font-size--small);
	text-align: center;
}

/* ── Controls ───────────────────────────────────────────────── */

/*
 * Chevrons fill far less of their box than the X and magnifier, so the arrows
 * render larger to match the others' visible size.
 */
.lightbox__nav :where(svg) {
	inline-size: calc(var(--wp--custom--lightbox--icon--size) * 1.4);
	block-size: calc(var(--wp--custom--lightbox--icon--size) * 1.4);
}

/*
 * Prev/next arrows — desktop only, since touch navigates by swipe. Centred over
 * the stage sides, above the track.
 */
.lightbox__nav {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	z-index: 1;
}

.lightbox__nav--prev {
	left: var(--wp--preset--spacing--s);
}

.lightbox__nav--next {
	right: var(--wp--preset--spacing--s);
}

/* No prev on the first slide, no next on the last (the JS sets `hidden` when
   the lightbox doesn't loop). Restated because display: flex above beats the
   UA's [hidden] rule. */
.lightbox__nav[hidden] {
	display: none;
}

@media (hover: none) and (pointer: coarse) {
	.lightbox__nav {
		display: none;
	}
}

/*
 * The zoom button swaps glyph by state — magnifier-plus normally, minus once
 * zoomed (the JS toggles .is-zoomed). Class-only selectors, so cascade order
 * decides rather than a type selector.
 */
.lightbox__zoom-in {
	display: flex;
}

.lightbox__zoom-out {
	display: none;
}

.lightbox.is-zoomed .lightbox__zoom-in {
	display: none;
}

.lightbox.is-zoomed .lightbox__zoom-out {
	display: flex;
}

/*
 * Image already shown at or near its actual size — there is nothing to zoom
 * into, so the control goes (the JS toggles .is-unzoomable).
 *
 * Hidden rather than removed: `display: none` collapses the button's 3rem slot,
 * and since the counter between the two buttons is `flex: 1`, it then re-centres
 * across the reclaimed space. The counter visibly jumped sideways on every slide
 * whose image was too small to zoom. `visibility` keeps the slot, and takes the
 * button out of the tab order just as `display: none` did.
 */
.lightbox.is-unzoomable .lightbox__zoom {
	visibility: hidden;
}

.lightbox.is-unzoomable .lightbox__img {
	cursor: default;
}

@media (prefers-reduced-motion: reduce) {
	.lightbox__img {
		transition: none;
	}
}

/*
 * Phone and small screens — the image goes full-bleed width, and the stage's
 * flex still keeps it under the bar. A slide gap gives breathing space while
 * swiping between differently-sized images; the JS reads it for the translate
 * step, so it must stay a real column-gap.
 */
@media (width <= 48rem) {
	.lightbox__img {
		max-width: 100vw;
		border-radius: 0;
	}

	.lightbox__track {
		column-gap: var(--wp--preset--spacing--s);
	}
}
