/**
 * Shellac Galleries — front-end and editor styles.
 *
 * Hand-written (no build step). Two features:
 *   1. the "Masonry" gallery block style, and
 *   2. a self-contained lightbox for gallery images (see lightbox.js).
 *
 * The JS-enhanced masonry state is scoped to `.shellac-gal-js` (set in <head>
 * by the plugin) so it applies only when the layout script will run. The
 * lightbox is deliberately theme-neutral (a dark backdrop, its own controls),
 * depending on no theme colours or on core's lightbox.
 */

/* --- Masonry gallery -------------------------------------------------------
 * A CSS grid whose items pack vertically WITHOUT cropping while keeping their
 * source order — grid auto-placement without `dense` preserves it. masonry.js
 * sets each item's row span from its rendered height against a 1px row unit.
 * Without JS — and in the block editor, where the JS does not run — it degrades
 * to a plain aligned grid (order preserved, ragged bottoms).
 */
.wp-block-gallery.is-style-masonry {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 0.9rem 0.75rem;
	align-items: start;
	/* Keep the last row clear of whatever follows (e.g. a comment form). */
	margin-block-end: 2.5rem;
}

.wp-block-gallery.is-style-masonry.columns-1 { grid-template-columns: repeat(1, 1fr); }
.wp-block-gallery.is-style-masonry.columns-2 { grid-template-columns: repeat(2, 1fr); }
.wp-block-gallery.is-style-masonry.columns-3 { grid-template-columns: repeat(3, 1fr); }
.wp-block-gallery.is-style-masonry.columns-4 { grid-template-columns: repeat(4, 1fr); }
.wp-block-gallery.is-style-masonry.columns-5 { grid-template-columns: repeat(5, 1fr); }
.wp-block-gallery.is-style-masonry.columns-6 { grid-template-columns: repeat(6, 1fr); }
.wp-block-gallery.is-style-masonry.columns-7 { grid-template-columns: repeat(7, 1fr); }
.wp-block-gallery.is-style-masonry.columns-8 { grid-template-columns: repeat(8, 1fr); }

/* Two columns at most on phones, whatever the block's column setting. */
@media (max-width: 33.9375rem) {
	.wp-block-gallery.is-style-masonry:not(.columns-1) {
		grid-template-columns: repeat(2, 1fr);
	}
}

/* Core sizes the nested figures with flex (`figure.wp-block-image`, one notch
 * more specific than a plain class), collapsing each to its image's width. The
 * doubled class outranks that so the grid can own the width. */
.wp-block-gallery.is-style-masonry .wp-block-image.wp-block-image {
	display: block;
	margin: 0;
	/* Fill the grid column. !important is required, not lazy: core sizes gallery
	 * figures with `figure.wp-block-image:not(#individual-image)`, whose :not()
	 * injects ID-level specificity specifically to resist theme overrides. */
	width: 100% !important;
	max-width: none;
}

/* Natural aspect always. Core's "Crop images" option (is-cropped) forces
 * object-fit:cover + height:100% on gallery images via a
 * `figure.wp-block-image:not(#individual-image) img` rule whose :not(#…) injects
 * an ID's worth of specificity (1,3,1) — unbeatable by class selectors — so we
 * need !important, not more classes. Without this, cropped galleries defeat the
 * masonry (uniform heights) AND feed a height loop that blows tiles up huge. */
.wp-block-gallery.is-style-masonry .wp-block-image.wp-block-image img {
	width: 100% !important;
	height: auto !important;
	max-width: none !important;
	object-fit: initial !important;
	flex: 0 0 auto !important;
}

/* JS pending: hide the gallery to suppress the first-paint reflow, but keep the
 * safe plain grid (auto rows) underneath. align-self:start lets each figure size
 * to its content so masonry.js can measure its true height. The keyframe is a
 * failsafe — if the script never runs (or dies mid-layout) it still reveals the
 * gallery after 2s. Crucially the 1px row unit is NOT applied here: without it,
 * that failsafe reveals a plain aligned grid rather than a heap of images
 * collapsed into overlapping 1px rows. */
.shellac-gal-js .wp-block-gallery.is-style-masonry {
	opacity: 0;
	animation: shellac-gal-masonry-reveal 0s linear 2s forwards;
}

.shellac-gal-js .wp-block-gallery.is-style-masonry .wp-block-image.wp-block-image {
	align-self: start;
}

/* JS-ready: the 1px row unit the span math targets is applied ONLY once the
 * script has assigned every item's grid-row span and added this class, so the
 * figures can never sit in collapsed 1px rows before their spans exist. The
 * vertical gap is folded into the span math, so the row gap collapses here. */
.shellac-gal-js .wp-block-gallery.is-style-masonry.is-masonry-ready {
	grid-auto-rows: 1px;
	row-gap: 0;
	opacity: 1;
	animation: none;
	transition: opacity 0.3s ease;
}

@keyframes shellac-gal-masonry-reveal {
	to {
		opacity: 1;
	}
}

/* Captions below the image, in normal flow. Core styles nested-gallery captions
 * as an absolute, scrollable overlay pinned over the image (position:absolute;
 * bottom:0; max-height:100%; overflow:auto) with a gradient ::before. That hides
 * most of a long caption AND — being out of flow — leaves it out of the figure
 * height the masonry span is measured from, so long captions spill into the next
 * row. For a caption-rich photo archive we want the caption fully visible under
 * the image and counted in the tile height. Core's selector is (0,3,2); adding
 * .has-nested-images makes ours (0,4,2) so it wins without !important. */
.wp-block-gallery.is-style-masonry.has-nested-images figure.wp-block-image figcaption {
	position: static;
	max-height: none;
	overflow: visible;
	margin: 0;
	/* Small left inset so the text doesn't sit hard against the column edge. */
	padding: 0.5em 0 0 3px;
	color: inherit;
	text-align: start;
	text-shadow: none;
}

/* Drop core's gradient scrim, which only makes sense behind an overlay caption. */
.wp-block-gallery.is-style-masonry.has-nested-images figure.wp-block-image:has(figcaption)::before {
	content: none;
}

/* --- Self-contained gallery lightbox ---------------------------------------
 * A theme-neutral overlay (see lightbox.js). Dark backdrop, its own controls,
 * no dependence on theme colours or on core's lightbox. */
/* Only advertise the zoom affordance where the lightbox JS is actually running
 * to service it (mirrors the masonry `.shellac-gal-js` scoping), so a no-JS or
 * script-stripped page doesn't promise an enlarge that never happens. */
.shellac-gal-js .wp-block-gallery figure.wp-block-image img {
	cursor: zoom-in;
}

.shellac-gal-lightbox {
	position: fixed;
	inset: 0;
	z-index: 2147483000; /* Above sticky headers, cookie bars, etc. */
	display: flex;
	/* flex-start (not center) + auto margins on the figure: the figure centres
	 * when there's room but, when a tall image + long caption exceed the
	 * viewport, the overflow stays scrollable instead of being clipped equally
	 * top and bottom (a caption-rich archive routinely hits this). */
	align-items: flex-start;
	justify-content: center;
	overflow: auto;
	padding: 3rem 1.25rem;
	background: rgba(0, 0, 0, 0.92);
	opacity: 0;
	transition: opacity 0.2s ease;
}

.shellac-gal-lightbox.is-open {
	opacity: 1;
}

.shellac-gal-lightbox[hidden] {
	display: none;
}

.shellac-gal-lightbox-figure {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 1rem;
	/* auto margins centre the figure within the scrollable overlay while it
	 * fits, and collapse to allow scrolling once it doesn't (see overlay note). */
	margin: auto;
	max-width: 100%;
}

.shellac-gal-lightbox-figure img {
	display: block;
	width: auto;
	height: auto;
	max-width: 92vw;
	max-height: 82vh;
	object-fit: contain;
	box-shadow: 0 6px 30px rgba(0, 0, 0, 0.5);
}

/* Reserve foot room when a caption shows so image and caption are both clear. */
.shellac-gal-lightbox.has-caption .shellac-gal-lightbox-figure img {
	max-height: 74vh;
}

.shellac-gal-lightbox-caption {
	max-width: min(90vw, 62ch);
	margin: 0;
	text-align: center;
	font-style: italic;
	font-size: 0.95rem;
	line-height: 1.5;
	color: #f2f2f2;
}

.shellac-gal-lightbox-caption[hidden] {
	display: none;
}

/* Controls: translucent chips with a light glyph — legible over any image.
 * Pinned to the viewport (not absolute) so they stay put when the overlay
 * scrolls a tall image + long caption — the overlay is a full-viewport fixed
 * element, so the offsets below land in the same place either way. */
.shellac-gal-lightbox-close,
.shellac-gal-lightbox-nav {
	position: fixed;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 3rem;
	height: 3rem;
	padding: 0;
	border: 0;
	border-radius: 50%;
	/* 0.62 (not 0.55) so the light glyph clears the 3:1 non-text contrast floor
	 * even at rest over a bright image region; hover/focus firms it up further. */
	background: rgba(20, 20, 20, 0.62);
	cursor: pointer;
	transition: background 0.15s ease, transform 0.1s ease;
}

/* Force neutral controls, overriding any colour the theme puts on buttons/SVGs.
 * elsie2 fills buttons with its puce accent on hover/focus/active — and the
 * close button takes focus the moment the overlay opens, so it shows at once.
 * Pin the background, glyph colour, border and focus glow across ALL states so
 * each control stays a dark chip with a light glyph. The overlay is always dark,
 * so a near-white glyph reads in both the site's light and dark modes; the
 * doubled overlay class + !important beat the theme's rules regardless of their
 * specificity. */
.shellac-gal-lightbox.shellac-gal-lightbox .shellac-gal-lightbox-close,
.shellac-gal-lightbox.shellac-gal-lightbox .shellac-gal-lightbox-close:hover,
.shellac-gal-lightbox.shellac-gal-lightbox .shellac-gal-lightbox-close:focus,
.shellac-gal-lightbox.shellac-gal-lightbox .shellac-gal-lightbox-close:focus-visible,
.shellac-gal-lightbox.shellac-gal-lightbox .shellac-gal-lightbox-close:active,
.shellac-gal-lightbox.shellac-gal-lightbox .shellac-gal-lightbox-nav,
.shellac-gal-lightbox.shellac-gal-lightbox .shellac-gal-lightbox-nav:hover,
.shellac-gal-lightbox.shellac-gal-lightbox .shellac-gal-lightbox-nav:focus,
.shellac-gal-lightbox.shellac-gal-lightbox .shellac-gal-lightbox-nav:focus-visible,
.shellac-gal-lightbox.shellac-gal-lightbox .shellac-gal-lightbox-nav:active {
	color: #f2f2f2 !important;
	background: rgba(20, 20, 20, 0.62) !important;
	border-color: transparent !important;
	box-shadow: none !important;
}

/* A slightly stronger chip on hover / keyboard focus, for feedback. */
.shellac-gal-lightbox.shellac-gal-lightbox .shellac-gal-lightbox-close:hover,
.shellac-gal-lightbox.shellac-gal-lightbox .shellac-gal-lightbox-close:focus-visible,
.shellac-gal-lightbox.shellac-gal-lightbox .shellac-gal-lightbox-nav:hover,
.shellac-gal-lightbox.shellac-gal-lightbox .shellac-gal-lightbox-nav:focus-visible {
	background: rgba(20, 20, 20, 0.82) !important;
}

/* Neutral, visible keyboard-focus ring in place of any accent-coloured one. */
.shellac-gal-lightbox.shellac-gal-lightbox .shellac-gal-lightbox-close:focus-visible,
.shellac-gal-lightbox.shellac-gal-lightbox .shellac-gal-lightbox-nav:focus-visible {
	outline: 2px solid #fff !important;
	outline-offset: 2px !important;
}

.shellac-gal-lightbox.shellac-gal-lightbox .shellac-gal-lightbox-close svg,
.shellac-gal-lightbox.shellac-gal-lightbox .shellac-gal-lightbox-close svg path,
.shellac-gal-lightbox.shellac-gal-lightbox .shellac-gal-lightbox-nav svg,
.shellac-gal-lightbox.shellac-gal-lightbox .shellac-gal-lightbox-nav svg path {
	fill: currentColor !important;
}

.shellac-gal-lightbox-close[hidden],
.shellac-gal-lightbox-nav[hidden] {
	display: none;
}

/* Boundary controls (first slide → Prev, last slide → Next) are aria-disabled,
 * not `disabled`, so they stay in the tab order and the focus trap can't drop
 * out through them; the dimmed look and inert cursor are keyed off that state. */
.shellac-gal-lightbox-nav[aria-disabled="true"] {
	opacity: 0.35;
	cursor: default;
}

.shellac-gal-lightbox-close {
	top: 1rem;
	right: 1rem;
}

.shellac-gal-lightbox-close:active {
	transform: scale(0.94);
}

.shellac-gal-lightbox-nav {
	top: 50%;
	transform: translateY(-50%);
}

.shellac-gal-lightbox-nav:active {
	transform: translateY(-50%) scale(0.94);
}

/* Logical insets so Prev/Next follow the reading direction on RTL sites (the
 * swipe direction is flipped to match in lightbox.js). */
.shellac-gal-lightbox-prev {
	inset-inline-start: 0.75rem;
}

.shellac-gal-lightbox-next {
	inset-inline-end: 0.75rem;
}

/* On phones the arrows drop to the bottom corners (thumb-reachable), clear of
 * the image, and grow a little for touch. */
@media (max-width: 33.9375rem) {
	.shellac-gal-lightbox-close,
	.shellac-gal-lightbox-nav {
		width: 3.25rem;
		height: 3.25rem;
	}

	.shellac-gal-lightbox-nav {
		top: auto;
		bottom: 1.25rem;
		transform: none;
	}

	.shellac-gal-lightbox-nav:active {
		transform: scale(0.94);
	}

	.shellac-gal-lightbox-prev {
		inset-inline-start: 1.25rem;
	}

	.shellac-gal-lightbox-next {
		inset-inline-end: 1.25rem;
	}
}

/* Honour a reduced-motion preference at the CSS level too (the JS already skips
 * the overlay fade reflow and close delay): drop the opacity fades and control
 * transitions so nothing animates for users who asked it not to. */
@media (prefers-reduced-motion: reduce) {
	.shellac-gal-js .wp-block-gallery.is-style-masonry.is-masonry-ready {
		transition: none;
	}

	.shellac-gal-lightbox,
	.shellac-gal-lightbox-close,
	.shellac-gal-lightbox-nav {
		transition: none;
	}
}
