/*
 * Lightbox.
 *
 * The chevrons are the cursor, not buttons on top of the picture. Colour is
 * decided in three steps, in this order:
 *
 *   1. sampled — JS reads the brightness of the patch under the pointer and
 *      adds .is-on-light, so the mark goes dark on a bright photograph;
 *   2. blended — when the media is cross-origin and cannot be sampled,
 *      .is-blend switches the mark to mix-blend-mode: difference, which
 *      inverts itself against whatever is behind it;
 *   3. haloed — a soft drop shadow is on in every case, which is what keeps
 *      the mark readable over mid greys, where both of the above are weakest.
 *
 * Loaded only on pages that contain media worth opening.
 */

/* Trigger state on the page itself. */

.to-lightbox-trigger {
	cursor: zoom-in;
}

/*
 * A cover that plays a video says so. The mark is drawn, not an image file,
 * and it sits over the picture without a plate behind it — the ring is enough
 * separation, and the drop shadow carries it over a bright frame.
 */
.to-has-play {
	position: relative;
	cursor: pointer;
}

.to-has-play::after {
	content: "";
	position: absolute;
	inset-block-start: 50%;
	inset-inline-start: 50%;
	width: clamp(3.5rem, 7vw, 5.5rem);
	aspect-ratio: 1;
	border: 2px solid var(--wp--preset--color--light, #fff);
	border-radius: 50%;
	background: color-mix(in srgb, var(--wp--preset--color--dark, #04121a) 25%, transparent);
	box-shadow: 0 4px 24px rgba(0, 0, 0, 0.35);
	transform: translate(-50%, -50%);
	transition: transform var(--wp--custom--duration--quick, 0.25s) var(--wp--custom--ease--out, ease),
		background-color var(--wp--custom--duration--quick, 0.25s) linear;
	pointer-events: none;
}

.to-has-play::before {
	content: "";
	position: absolute;
	inset-block-start: 50%;
	inset-inline-start: 50%;
	z-index: 1;
	width: clamp(0.9rem, 1.8vw, 1.4rem);
	aspect-ratio: 1;
	background: var(--wp--preset--color--light, #fff);
	clip-path: polygon(15% 0%, 100% 50%, 15% 100%);
	transform: translate(-40%, -50%);
	transition: transform var(--wp--custom--duration--quick, 0.25s) var(--wp--custom--ease--out, ease);
	pointer-events: none;
	filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.4));
}

.to-has-play:hover::after {
	transform: translate(-50%, -50%) scale(1.08);
	background-color: color-mix(in srgb, var(--wp--preset--color--dark, #04121a) 45%, transparent);
}

.to-has-play:hover::before {
	transform: translate(-40%, -50%) scale(1.08);
}

@media (prefers-reduced-motion: reduce) {
	.to-has-play::after,
	.to-has-play::before {
		transition: none;
	}
}

html.to-lightbox-open {
	overflow: hidden;
}

/* ------------------------------------------------------------------ Shell */

.to-lightbox {
	position: fixed;
	inset: 0;
	z-index: 9999;
	display: grid;
	grid-template-rows: 1fr auto;
	/* Dense enough that the page underneath stops competing with the picture. */
	background: color-mix(in srgb, var(--wp--preset--color--dark, #04121a) 96%, transparent);
	opacity: 0;
	transition: opacity var(--wp--custom--duration--base, 0.45s) var(--wp--custom--ease--out, ease);
}

.to-lightbox.is-open {
	opacity: 1;
}

.to-lightbox:focus {
	outline: none;
}

.to-lightbox__stage {
	display: grid;
	place-items: center;
	min-height: 0;
	padding: clamp(1rem, 4vw, 4rem);
}

.to-lightbox__figure {
	display: grid;
	gap: var(--wp--preset--spacing--30, 1.25rem);
	justify-items: center;
	margin: 0;
	max-width: 100%;
	max-height: 100%;
}

.to-lightbox__media {
	display: flex;
	max-width: 100%;
	min-height: 0;
}

.to-lightbox__image,
.to-lightbox__video {
	display: block;
	max-width: min(100%, 92vw);
	max-height: 82vh;
	width: auto;
	height: auto;
	border-radius: var(--wp--custom--radius--sm, 8px);
	box-shadow: 0 40px 80px -40px rgba(0, 0, 0, 0.7);
	opacity: 0;
	transform: scale(0.985);
	transition: opacity var(--wp--custom--duration--base, 0.45s) var(--wp--custom--ease--out, ease),
		transform var(--wp--custom--duration--base, 0.45s) var(--wp--custom--ease--out, ease);
}

.to-lightbox.is-loaded .to-lightbox__image,
.to-lightbox.is-video .to-lightbox__video {
	opacity: 1;
	transform: none;
}

.to-lightbox__video {
	width: min(92vw, 78rem);
	aspect-ratio: 16 / 9;
	max-height: 82vh;
	border: 0;
	background: #000;
}

iframe.to-lightbox__video {
	height: min(82vh, 44rem);
}

.to-lightbox__caption {
	max-width: 62ch;
	margin: 0;
	color: color-mix(in srgb, var(--wp--preset--color--light, #fff) 78%, transparent);
	font-size: var(--wp--preset--font-size--small, 0.9rem);
	text-align: center;
	text-wrap: pretty;
}

.to-lightbox__counter {
	margin: 0;
	padding-block-end: clamp(1rem, 3vw, 2.5rem);
	color: color-mix(in srgb, var(--wp--preset--color--light, #fff) 55%, transparent);
	font-family: var(--wp--preset--font-family--mono, ui-monospace, monospace);
	font-size: var(--wp--preset--font-size--x-small, 0.8rem);
	font-variant-numeric: tabular-nums;
	text-align: center;
}

/* -------------------------------------------------------- Pointer cursor */

/*
 * On a fine pointer the real cursor is hidden and this element follows it.
 * It is centred on the pointer, never intercepts events, and only one of its
 * three marks is visible at a time.
 */
.to-lightbox__cursor {
	position: fixed;
	top: 0;
	left: 0;
	display: none;

	/* Big enough to read as a gesture, not as a button. */
	width: clamp(2.5rem, 3.4vw, 3.75rem);
	height: clamp(3rem, 4.2vw, 4.5rem);
	color: var(--wp--preset--color--light, #fff);
	pointer-events: none;
	filter: drop-shadow(0 2px 10px rgba(0, 0, 0, 0.55));
	transition: color var(--wp--custom--duration--quick, 0.25s) linear;
	will-change: transform;
}

.to-lightbox__cursor > span {
	position: absolute;
	inset: 0;
	display: block;
	opacity: 0;
	transform: scale(0.85);
	transition: opacity var(--wp--custom--duration--quick, 0.25s) var(--wp--custom--ease--out, ease),
		transform var(--wp--custom--duration--quick, 0.25s) var(--wp--custom--ease--out, ease);
}

.to-lightbox__cursor svg {
	width: 100%;
	height: 100%;
}

.to-lightbox[data-zone="prev"] .to-lightbox__cursor-prev,
.to-lightbox[data-zone="next"] .to-lightbox__cursor-next,
.to-lightbox[data-zone="close"] .to-lightbox__cursor-close,
/*
 * Belt and braces: with the system cursor hidden, "no zone yet" must never
 * mean "no cursor at all". JS sets the zone on open, on every media change and
 * on load; if any path is ever missed, the cross still shows.
 */
.to-lightbox:not([data-zone]) .to-lightbox__cursor-close,
.to-lightbox[data-zone=""] .to-lightbox__cursor-close {
	opacity: 1;
	transform: none;
}

/* The mark goes dark on a bright patch of the picture. */
.to-lightbox.is-on-light .to-lightbox__cursor {
	color: var(--wp--preset--color--dark, #04121a);
	filter: drop-shadow(0 2px 10px rgba(255, 255, 255, 0.5));
}

/*
 * Cross-origin media cannot be sampled. Difference blending inverts the mark
 * against whatever is under it, which is not as precise but never invisible.
 */
.to-lightbox.is-blend .to-lightbox__cursor {
	color: #fff;
	mix-blend-mode: difference;
	filter: none;
}

@media (hover: hover) and (pointer: fine) {
	.to-lightbox:not(.is-video) {
		cursor: none;
	}

	.to-lightbox:not(.is-video) .to-lightbox__cursor {
		display: block;
	}

	/* Buttons are the touch and keyboard path; the cursor covers the mouse. */
	.to-lightbox:not(.is-touch) .to-lightbox__button.is-prev,
	.to-lightbox:not(.is-touch) .to-lightbox__button.is-next {
		opacity: 0;
		pointer-events: none;
	}

	.to-lightbox:not(.is-touch) .to-lightbox__button.is-close {
		opacity: 0;
		pointer-events: none;
	}

	/* Keyboard users get them back the moment they tab in. */
	.to-lightbox .to-lightbox__button:focus-visible {
		opacity: 1;
		pointer-events: auto;
	}
}

/* ----------------------------------------------------------- Real buttons */

.to-lightbox__button {
	position: absolute;
	display: grid;
	place-items: center;
	width: 4rem;
	height: 4rem;
	padding: 0;
	border: 0;
	background: none;
	color: var(--wp--preset--color--light, #fff);
	cursor: pointer;
	filter: drop-shadow(0 2px 10px rgba(0, 0, 0, 0.6));
	transition: opacity var(--wp--custom--duration--quick, 0.25s) linear;
}

.to-lightbox__button svg {
	width: 1.75rem;
	height: 2rem;
}

.to-lightbox__button.is-prev {
	inset-block-start: 50%;
	inset-inline-start: clamp(0.25rem, 2vw, 1.5rem);
	transform: translateY(-50%);
}

.to-lightbox__button.is-next {
	inset-block-start: 50%;
	inset-inline-end: clamp(0.25rem, 2vw, 1.5rem);
	transform: translateY(-50%);
}

.to-lightbox__button.is-close {
	inset-block-start: clamp(0.5rem, 2vw, 1.5rem);
	inset-inline-end: clamp(0.5rem, 2vw, 1.5rem);
}

.to-lightbox__button.is-close svg {
	width: 1.5rem;
	height: 1.5rem;
}

.to-lightbox.is-single .to-lightbox__button.is-prev,
.to-lightbox.is-single .to-lightbox__button.is-next {
	display: none;
}

/* A video needs its own controls reachable, so the cursor steps aside. */
.to-lightbox.is-video {
	cursor: default;
}

.to-lightbox.is-video .to-lightbox__cursor {
	display: none;
}

/*
 * A video keeps its real controls: the pointer has to reach the player, so the
 * cursor marks step aside and the buttons come back. Selectors are as specific
 * as the fine-pointer rules above, or those would keep them hidden.
 */
.to-lightbox.is-video .to-lightbox__button.is-close,
.to-lightbox.is-video .to-lightbox__button.is-prev,
.to-lightbox.is-video .to-lightbox__button.is-next {
	opacity: 1;
	pointer-events: auto;
}

@media (prefers-reduced-motion: reduce) {
	.to-lightbox,
	.to-lightbox__image,
	.to-lightbox__video,
	.to-lightbox__cursor,
	.to-lightbox__cursor > span {
		transition-duration: 0.01ms;
	}

	.to-lightbox__image,
	.to-lightbox__video {
		transform: none;
	}
}
