/**
 * The project gallery lightbox.
 *
 * Quiet on purpose. The photograph is the content; everything else is chrome
 * that should be findable and then forgotten, which is the same posture the
 * brochure viewer takes.
 *
 * Values are the design's own: ink #1C2A33 for the ground, cream #F5F2EC for
 * anything written on it, brass for focus. Zero border-radius, as everywhere.
 */

/* The gallery images only become controls once the script has said so, so a
   page whose JavaScript failed shows no affordance it cannot honour. */
.ks-lb-ready .ks-proj-gallery-item img {
	cursor: zoom-in;
}

.ks-lb-ready .ks-proj-gallery-item img:focus-visible {
	outline: 2px solid #B08D57;
	outline-offset: 4px;
}

/* Scroll lock. `overflow: hidden` on the root rather than on body, because body
   here is a flex context and hiding its overflow collapses the footer. */
.ks-lb-open {
	overflow: hidden;
}

.ks-lb[hidden] {
	display: none;
}

.ks-lb {
	position: fixed;
	inset: 0;
	/* Above the chat launcher, which renders inside a shadow root with a very
	   high z-index of its own. A photograph opened full-screen should not have
	   a chat bubble sitting on top of it; this is the one place on the site
	   that legitimately outranks it. */
	z-index: 2147483000;
	display: flex;
	align-items: center;
	justify-content: center;
}

.ks-lb-backdrop {
	position: absolute;
	inset: 0;
	/* Solid, not translucent. At 0.94 the page beneath stayed legible through it
	   — the sticky header's own hamburger read straight through the close
	   button, which is a confusing place to leave a second icon. A photograph
	   opened full-screen should have nothing behind it competing. */
	background: #141F26;
}

.ks-lb-stage {
	position: relative;
	width: 100%;
	height: 100%;
	display: flex;
	align-items: center;
	justify-content: center;
	overflow: hidden;
	/* The stage owns the gestures: without this a drag on the image becomes a
	   native image drag and the pan never starts. */
	touch-action: none;
	cursor: zoom-in;
}

.ks-lb-stage.is-zoomed {
	cursor: grab;
}

.ks-lb-stage.is-zoomed:active {
	cursor: grabbing;
}

.ks-lb-img {
	max-width: 92vw;
	max-height: 88vh;
	/* object-fit matters at the extremes: a 21:9 photograph and a 4:5 one both
	   have to land inside the same box without cropping. */
	object-fit: contain;
	transform-origin: center center;
	-webkit-user-select: none;
	user-select: none;
	-webkit-user-drag: none;
}

/* ------------------------------------------------------------- chrome -- */

.ks-lb-chrome {
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 20px;
	padding: 20px 24px;
	pointer-events: none;
}

.ks-lb-chrome > * {
	pointer-events: auto;
}

.ks-lb-count {
	margin: 0;
	font: 300 13px/1 Jost, sans-serif;
	letter-spacing: 0.12em;
	color: rgba(245, 242, 236, 0.72);
	font-variant-numeric: tabular-nums;
}

.ks-lb-tools {
	display: flex;
	gap: 8px;
}

.ks-lb-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	/* 44px, for the reason DES-05 gives about the menu button: this is the
	   control someone reaches for with a thumb on a photograph. */
	width: 44px;
	height: 44px;
	padding: 0;
	border: 1px solid rgba(245, 242, 236, 0.28);
	background: transparent;
	color: #F5F2EC;
	font: 300 20px/1 Jost, sans-serif;
	cursor: pointer;
	transition: background-color 0.18s ease, border-color 0.18s ease;
}

.ks-lb-btn:hover:not(:disabled) {
	background: rgba(245, 242, 236, 0.12);
	border-color: rgba(245, 242, 236, 0.6);
}

/* The colour has to be restated for hover and focus. style.css neutralises the
   parent reset's pink by forcing bare buttons to `color: inherit` in those
   states — correct globally, but here `inherit` resolves up to the page's ink
   and the glyph disappears against the dark overlay. Found by opening the
   lightbox and seeing the close button vanish. */
.ks-lb-btn:hover,
.ks-lb-btn:focus,
.ks-lb-btn:focus-visible {
	color: #F5F2EC;
}

.ks-lb-btn:focus-visible,
.ks-lb-nav:focus-visible {
	outline: 2px solid #B08D57;
	outline-offset: 2px;
}

/* ---------------------------------------------------------- prev/next -- */

.ks-lb-nav {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	width: 56px;
	height: 56px;
	padding: 0;
	border: 0;
	background: transparent;
	cursor: pointer;
}

.ks-lb-nav::before {
	content: "";
	display: block;
	width: 18px;
	height: 18px;
	margin: 0 auto;
	border-left: 1px solid #F5F2EC;
	border-bottom: 1px solid #F5F2EC;
}

.ks-lb-nav.is-prev {
	left: 8px;
}

.ks-lb-nav.is-prev::before {
	transform: rotate(45deg);
}

.ks-lb-nav.is-next {
	right: 8px;
}

.ks-lb-nav.is-next::before {
	transform: rotate(-135deg);
}

/* Disabled rather than hidden at the ends of the set, so the control does not
   move about under the pointer as you step through. */
.ks-lb-nav:disabled {
	opacity: 0.25;
	cursor: default;
}

/* The announcement for screen readers, which should not be seen. */
.ks-lb-live {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip: rect(0 0 0 0);
	white-space: nowrap;
	border: 0;
}

@media (max-width: 767px) {
	.ks-lb-img {
		max-width: 100vw;
		max-height: 78vh;
	}

	/* Off the photograph's edges on a phone, where 56px of chevron either side
	   would otherwise sit on top of it. */
	.ks-lb-nav {
		top: auto;
		bottom: 16px;
		transform: none;
	}

	.ks-lb-nav.is-prev {
		left: 16px;
	}

	.ks-lb-nav.is-next {
		right: 16px;
	}
}

@media (prefers-reduced-motion: reduce) {
	.ks-lb-btn,
	.ks-lb-img {
		transition: none !important;
	}
}

/* ---------------------------------------------------------------------------
   Motion.

   Opening a photograph is the moment a visitor stops reading about a kitchen
   and starts looking at one, so it gets a settle rather than a cut. Everything
   here is opacity and transform only — the overlay is `position: fixed` and
   outside the flow, so none of it can shift the page behind it.
   --------------------------------------------------------------------------- */

.ks-lb:not([hidden]) .ks-lb-backdrop {
	animation: ks-lb-ground 200ms ease backwards;
}

@keyframes ks-lb-ground {
	from { opacity: 0; }
}

/* 0.985, not 0.9: the photograph settles into place, it does not zoom at you.
   The 40ms delay lets the ground arrive first, so the picture appears to land
   on something rather than materialise with it. */
.ks-lb:not([hidden]) .ks-lb-img {
	animation: ks-lb-photo 260ms cubic-bezier(0.2, 0, 0, 1) 40ms backwards;
}

@keyframes ks-lb-photo {
	from { opacity: 0; transform: scale(0.985); }
}

/* Stepping between photographs. The stage dims while the next file decodes off
   -DOM (see show() in the script) and comes back when it can paint in one go —
   which is what stops the counter describing a picture that is not on screen
   yet. Deliberately not a full fade to zero: at speed that reads as a flicker. */
.ks-lb-stage.is-changing .ks-lb-img {
	opacity: 0.15;
	transition: opacity 180ms ease;
}

.ks-lb-stage .ks-lb-img {
	transition: opacity 180ms ease;
}

@media (prefers-reduced-motion: reduce) {
	.ks-lb:not([hidden]) .ks-lb-backdrop,
	.ks-lb:not([hidden]) .ks-lb-img {
		animation: none;
	}

	.ks-lb-stage .ks-lb-img,
	.ks-lb-stage.is-changing .ks-lb-img {
		transition: none;
		opacity: 1;
	}
}
