/* ====================================================================
   GALLERY PAGE — grid of photographs, and the viewer that opens them.

   Loaded only on the Gallery page template, and only when that page has
   photographs to show. Nothing here reaches the homepage, whose drag
   showcase is untouched.
   ==================================================================== */

.df-photos {
	padding-block: var(--df-sp-9);
}

.df-photos__grid {
	display: grid;
	/* Tiles find their own number of columns from about 600px up, so the
	   grid needs no breakpoint per screen size there. Phones are pinned to
	   two columns explicitly below -- auto-fill cannot do it, because a
	   220px floor plus the gutters never fits twice on a 375px screen and
	   every phone would get one photo per row. */
	grid-template-columns: repeat(auto-fill, minmax(min(220px, 100%), 1fr));
	gap: var(--df-sp-4);
	list-style: none;
	margin: 0;
	padding: 0;
}

.df-photos__cell { margin: 0; }

.df-photos__item {
	display: block;
	position: relative;
	width: 100%;
	aspect-ratio: 4 / 5;
	padding: 0;
	border: 1px solid var(--df-bg-line);
	border-radius: var(--df-radius);
	overflow: hidden;
	background: var(--df-bg-elevated);
	/* A tile is a button, and a button carries a font and a text colour it
	   does not want here. */
	font: inherit;
	color: inherit;
}

.df-photos__img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
	transition: transform 0.6s var(--df-ease-out);
}

.df-photos__item:hover .df-photos__img,
.df-photos__item:focus-visible .df-photos__img {
	transform: scale(1.05);
}

.df-photos__item:focus-visible {
	outline: 2px solid var(--df-gold);
	outline-offset: 3px;
}

/* Both the zoom cursor and the magnifier appear only once lightbox.js has
   marked the grid live, so a tile never invites a tap it cannot answer. */
.df-photos__grid--live .df-photos__item { cursor: zoom-in; }

.df-photos__zoom {
	display: none;
	position: absolute;
	right: 10px;
	bottom: 10px;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 34px;
	height: 34px;
	border-radius: 50%;
	background: rgba(0, 0, 0, 0.55);
	color: #fff;
	opacity: 0;
	transform: translateY(6px);
	transition: opacity 0.3s, transform 0.3s;
}

.df-photos__grid--live .df-photos__zoom { display: inline-flex; }

.df-photos__item:hover .df-photos__zoom,
.df-photos__item:focus-visible .df-photos__zoom {
	opacity: 1;
	transform: none;
}

/* On a touch screen there is no hover to reveal it, so it simply stays. */
@media (hover: none) {
	.df-photos__zoom { opacity: 1; transform: none; }
}

/* -------------------------------------------------------------- viewer */

/* The `hidden` attribute only sets `display: none` at the very bottom of the
   cascade, so ANY display declaration beats it -- and everything in this
   viewer has one. Without this rule the viewer is on screen from page load,
   a black slab over the top of the gallery with a close button in the corner.
   Caught by a screenshot; nothing about the markup or the CSS looks wrong.
   (home.css:1172 had to learn the same thing about .df-contact__fallback.) */
.df-lightbox[hidden],
.df-lightbox [hidden] {
	display: none !important;
}

.df-lightbox {
	position: fixed;
	inset: 0;
	/* On a phone 100vh is the viewport with the browser's address bar
	   hidden, which is taller than what is actually on screen. Pinning the
	   height to the DYNAMIC viewport is what keeps the close button and the
	   counter reachable while that bar is showing. vh first, for anything
	   that does not know dvh. */
	height: 100vh;
	height: 100dvh;
	z-index: 9999;
	display: flex;
	align-items: center;
	justify-content: center;
	gap: var(--df-sp-3);
	padding: clamp(12px, 3vw, 40px);
	background: rgba(8, 8, 10, 0.94);
	backdrop-filter: blur(6px);
	-webkit-backdrop-filter: blur(6px);
}

/* The page behind is pinned rather than merely overflow:hidden — on iOS
   that is the only thing that actually stops it scrolling underneath. */
body.df-lightbox-open {
	position: fixed;
	width: 100%;
	overflow: hidden;
}

.df-lightbox__stage {
	margin: 0;
	max-width: 100%;
	max-height: 100%;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: var(--df-sp-3);
	min-width: 0;
}

.df-lightbox__img {
	max-width: 100%;
	/* Room for the caption and the counter beneath it. Same dynamic
	   viewport reasoning as above: with 100vh the bottom of a tall photo
	   sits under the address bar. */
	max-height: calc(100vh - 140px);
	max-height: calc(100dvh - 140px);
	width: auto;
	height: auto;
	object-fit: contain;
	border-radius: var(--df-radius);
	display: block;
}

.df-lightbox__caption {
	margin: 0;
	max-width: 60ch;
	text-align: center;
	font-size: var(--df-fs-small);
	color: var(--df-fg-muted);
	line-height: var(--df-lh-normal);
}

.df-lightbox__close,
.df-lightbox__nav {
	flex-shrink: 0;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	border: 1px solid rgba(255, 255, 255, 0.16);
	background: rgba(255, 255, 255, 0.06);
	color: #fff;
	border-radius: 50%;
	cursor: pointer;
	transition: background 0.25s, border-color 0.25s;
}

.df-lightbox__close:hover,
.df-lightbox__nav:hover {
	background: rgba(255, 255, 255, 0.14);
	border-color: var(--df-gold);
}

.df-lightbox__close:focus-visible,
.df-lightbox__nav:focus-visible {
	outline: 2px solid var(--df-gold);
	outline-offset: 2px;
}

.df-lightbox__close {
	position: absolute;
	top: clamp(10px, 2vw, 24px);
	right: clamp(10px, 2vw, 24px);
	width: 44px;
	height: 44px;
	font-size: 26px;
	line-height: 1;
}

.df-lightbox__nav {
	width: 48px;
	height: 48px;
}

.df-lightbox__count {
	position: absolute;
	left: 0;
	right: 0;
	bottom: clamp(10px, 2vw, 20px);
	margin: 0;
	text-align: center;
	font-size: var(--df-fs-tiny);
	letter-spacing: var(--df-ls-wide);
	color: var(--df-fg-muted);
}

@media (max-width: 720px) {
	.df-photos { padding-block: var(--df-sp-7); }

	/* Two per row, always. minmax(0, 1fr) rather than 1fr: a bare 1fr has a
	   min track size of auto, so one wide photo would push the row past the
	   screen and scroll the whole page sideways. */
	.df-photos__grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: var(--df-sp-3);
	}

	/* The arrows would sit on top of the photograph on a narrow screen, and
	   a swipe does the same job better. The counter says which photo this
	   is, so nothing is lost by dropping them. */
	.df-lightbox__nav { display: none; }
	.df-lightbox__img {
		max-height: calc(100vh - 120px);
		max-height: calc(100dvh - 120px);
	}
}

/* A phone held sideways is short, not narrow: the caption and counter are
   what have to give, or the photograph is reduced to a strip. */
@media (max-height: 460px) and (orientation: landscape) {
	.df-lightbox__caption { display: none; }
	.df-lightbox__img {
		max-height: calc(100vh - 56px);
		max-height: calc(100dvh - 56px);
	}
}

@media (prefers-reduced-motion: reduce) {
	.df-photos__img,
	.df-photos__zoom { transition: none; }
	.df-photos__item:hover .df-photos__img { transform: none; }
}
