/**
 * The product gallery viewer (gallery-viewer.js).
 *
 * A scroll surface: the column of photographs sits inside one scroller, and
 * zoom scales the strip while a sizer behind it keeps the scroll extents
 * honest — so panning a zoomed picture is the browser's own 2D scrolling
 * rather than anything hand-rolled.
 */

.ck-viewer-open {
	/* Hold the page still underneath. `position: fixed` on body would lose the
	   scroll position; hiding overflow on the root does not. */
	overflow: hidden;
}

.ck-viewer {
	position: fixed;
	inset: 0;
	z-index: 100000;
	background: #fafafa;
	display: flex;
	transition: opacity 220ms ease;
}

/* ── coming up ────────────────────────────────────────────────────────────
   Opened by a CLICK, the whole thing fades up: the page is there one moment
   and the photograph the next, and a hard cut reads as a jolt.

   ⚠️ Opened by a PINCH it must NOT fade, and that is not a detail. By then the
   copy is already standing on exactly this rectangle showing exactly this
   photograph, so fading the real one in over it superimposes two identical
   pictures for the length of the transition — the shimmer the whole handover
   exists to avoid, and the same trap that made the copy's removal a hard swap
   rather than a cross-fade.

   So there the picture arrives solid and only the CHROME fades in around it:
   the rail, the counter and the close button were never on screen a moment ago,
   and they are what makes the lightbox read as having opened.
   ------------------------------------------------------------------------ */
.ck-viewer.is-opening {
	opacity: 0;
}

/* ⚠️ On a handover the PICTURE must not fade, but the GROUND behind it should —
   that is the one backdrop transition, and it belongs to the lightbox. The pinch
   preview used to dim the page itself, which was a second fade competing with
   this one and starting well before the lightbox existed. Animating only
   `background-color` leaves the photograph and the strip untouched. */
.ck-viewer.is-handover {
	opacity: 1;
	transition: none;
}

@media (prefers-reduced-motion: no-preference) {
	.ck-viewer.is-handover {
		animation: ck-viewer-ground-in 260ms linear both;
	}

	/* ⚠️ …UNLESS THE BACKDROP IS ALREADY SOLID. A pinch let go past the
	   threshold brings the ground up over its own commit animation, so the page
	   is covered before this element exists; fading a second one in behind it
	   is the same transition run twice, and the second one starts after the
	   photograph has landed. `is-grounded` is written by open() off the
	   `ckPinchGroundAt` handshake. Only the ground is cancelled — the chrome
	   animation lives on the children and still runs, which is what makes the
	   lightbox read as having opened. */
	.ck-viewer.is-handover.is-grounded {
		animation: none;
	}

	@keyframes ck-viewer-ground-in {
		from {
			background-color: transparent;
		}
	}
}

/* Going away. ⚠️ The transition is restated here because `.is-handover` turned
   it off — a lightbox opened by a pinch must still fade when it closes. Keep
   CLOSE_MS in gallery-viewer.js in step with this duration. */
.ck-viewer.is-closing {
	opacity: 0;
	transition: opacity 200ms ease;
}

@media (prefers-reduced-motion: no-preference) {
	/* ⚠️ HELD AT NOTHING UNTIL THE COPY IS OFF. The pinch keeps an opaque copy
	   of the photograph over this element until the viewer's picture has
	   decoded, so an animation started when the viewer was BUILT ran where
	   nobody could see it and was all but finished by the time the copy
	   dropped — measured 0 -> 0.956 in one visible step. `is-uncovered` is
	   written by open() at once on a click, and by reveal() in
	   gallery-pinch-open.js on a handover, in the same breath as the copy goes.

	   ⚠️ BOTH HALVES LIVE INSIDE THIS MEDIA QUERY. With reduced motion there is
	   no animation to reveal them, so an unconditional `opacity: 0` would hide
	   the rail and the close button for good. */
	.ck-viewer.is-handover:not(.is-uncovered) .ck-viewer__rail,
	.ck-viewer.is-handover:not(.is-uncovered) .ck-viewer__counter,
	.ck-viewer.is-handover:not(.is-uncovered) .ck-viewer__close {
		opacity: 0;
	}

	.ck-viewer.is-handover.is-uncovered .ck-viewer__rail,
	.ck-viewer.is-handover.is-uncovered .ck-viewer__counter,
	.ck-viewer.is-handover.is-uncovered .ck-viewer__close {
		animation: ck-viewer-chrome-in 260ms ease both;
	}

	@keyframes ck-viewer-chrome-in {
		from {
			opacity: 0;
		}
	}
}

/* ── the scroller ─────────────────────────────────────────────────── */

.ck-viewer__scroll {
	flex: 1 1 auto;
	overflow: auto;
	overscroll-behavior: contain;
	-webkit-overflow-scrolling: touch;
	/* Let the browser scroll on both axes but never hand the gesture back to
	   the page, and never let it treat a pinch as page zoom. */
	touch-action: pan-x pan-y;
	scrollbar-width: none;
}

.ck-viewer__scroll::-webkit-scrollbar {
	display: none;
}

.ck-viewer__sizer {
	position: relative;
	/* ⚠️ NO auto margin. It used to centre the column while it was narrower than
	   the scroller, which mattered when the column was capped at 900 and there
	   was always space around it. Now the column takes the room it is given
	   (`columnWidth()`), so any leftover is a sliver — and centring it made the
	   picture's left edge move with the viewport, which both `restRect()` and
	   the pinch copy then had to model. Flush to the scroller is one less thing
	   that can disagree. */
}

.ck-viewer__strip {
	transform-origin: 0 0;
	display: flex;
	flex-direction: column;
	/* NO auto margin. The strip is scaled from its top-left, and the sizer
	   behind it is set to the SCALED size — so once zoomed the sizer is wider
	   than the strip's own layout box and `margin: 0 auto` centred that box,
	   displacing the scaled content by half the difference. The sizer's own
	   auto margin is what centres the column; this one only fought it. */
	margin: 0;
	/* No spacing above the first photograph or below the last — the column runs
	   to the screen edges (Marek, 2026-08-29). ⚠️ PAD_TOP / PAD_BOTTOM in
	   gallery-viewer.js mirror this so predict() can stack the figures before
	   the viewer exists; change them together or the pinch handover lands on
	   the wrong scroll offset. */
	padding: 0;
	box-sizing: content-box;
	/* ⚠️ NO `will-change: transform` here. It is applied by the JS only while the
	   zoom is actually moving and dropped ~120ms after it settles — see apply()
	   in gallery-viewer.js. Left on permanently it promises Chrome the transform
	   is about to change again, so it keeps the texture it has and stretches it
	   on the GPU instead of re-rasterising at the scale being viewed. On a strip
	   that is the whole column — 900px wide by ~8100px of photographs — that is
	   a soft picture at every zoom level, no matter how many pixels the file
	   has. Same failure the lightbox hit and fixed (lightbox-gestures.js,
	   RASTER_MS). */
}

.ck-viewer__item {
	margin: 0;
	width: 100%;
	background: #f0efed;
	overflow: hidden;
}

/* Paula's viewfinder over the photographs (css/base.css), as on the page's
   gallery. The thumbnail rail keeps its pointer — it navigates, it does not
   zoom. */
@media (hover: hover) and (pointer: fine) {
	.ck-viewer .ck-viewer__item {
		cursor: var(--ck-cursor-zoom, zoom-in);
	}
}

.ck-viewer__media {
	display: block;
	width: 100%;
	height: auto;
	user-select: none;
	-webkit-user-drag: none;
}

/* ⚠️ A PHOTOGRAPH IS A <canvas> HERE (see paint() in gallery-viewer.js), and it
   cannot take `height: auto`. A canvas's intrinsic ratio comes from its BACKING
   STORE, which is 0x0 until it is painted and 0x0 again once the window
   releases it — so `auto` resolves to a zero-height box, the column measures
   short and every scroll offset below it is wrong. The figure carries the
   aspect-ratio from the file's own dimensions and the canvas fills it, which is
   what keeps the box reserved whether or not there are pixels in it. */
canvas.ck-viewer__media {
	height: 100%;
}

/* ── chrome ───────────────────────────────────────────────────────── */

/* ⚠️ EVERY control in here needs TWO classes.
   Elementor's kit styles `.elementor-kit-7 button` — (0,1,1) — which outranks a
   single `.ck-viewer__close` (0,1,0) and was pushing `background:#3F3F3F` and
   `padding:12px 24px` into the viewer's own buttons. That padding is what made
   the close glyph sit off-centre and the thumbnails render as a small image in a
   grey slab. `.ck-viewer .ck-viewer__x` is (0,2,0) and wins. */
.ck-viewer .ck-viewer__close {
	position: absolute;
	top: 12px;
	right: 16px;
	z-index: 2;
	width: 44px;
	height: 44px;
	border: 0;
	padding: 0;
	background: transparent;
	/* Centred by flex rather than line-height: the glyph's own metrics are not
	   symmetrical, so line-height alone left it sitting high. */
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 34px;
	line-height: 1;
	cursor: pointer;
	color: var(--ck-ink);
}

.ck-viewer__counter {
	position: absolute;
	top: 20px;
	left: 16px;
	z-index: 2;
	box-sizing: border-box;
	text-align: center;
	font-size: 10px;
	letter-spacing: 1px;
	pointer-events: none;
}

/* ⚠️ NOT SHOWN ON DESKTOP. The rail already answers "which one am I on", and
   answers it better — it shows the whole set with the current one lit. A count
   beside it was saying the same thing twice, and it cost the rail its top 48px.
   On a phone there IS no rail (`display: none` below 768), so there the counter
   is the only position there is and it stays. */
@media (min-width: 768px) {
	.ck-viewer__counter {
		display: none;
	}
}

/* ── the rail ─────────────────────────────────────────────────────── */

/* ⚠️ The reserved width is a TOKEN because two places need it and they must not
   drift: this rule lays the column out, and restRect() in gallery-viewer.js has
   to know it BEFORE the viewer exists, to tell the pinch preview where the
   photograph is going to land. It includes the rail's own padding, so it is the
   whole distance from the screen edge to the picture's left pan limit. Zero on a
   phone, where the rail is not shown at all. */
:root {
	--ck-viewer-rail: 120px;
}

@media (max-width: 767px) {
	:root {
		--ck-viewer-rail: 0px;
	}
}

.ck-viewer__rail {
	flex: 0 0 var(--ck-viewer-rail);
	overflow-y: auto;
	overflow-x: hidden;
	/* ⚠️ NO padding at all. The thumbnails run the full width of the reserved
	   column — touching the screen edge on one side and the photograph on the
	   other — and the strip runs from the top of the screen to the bottom.
	   Nothing is reserved for the counter because it is not shown here. */
	padding: 0;
	display: flex;
	flex-direction: column;
	/* ⚠️ NO gap. The rail is the photographs at one width and nothing else — a
	   continuous strip reads as the column it navigates, where spaced tiles read
	   as a list of cards. Same reasoning as GAP: 0 between the photographs
	   themselves. */
	gap: 0;
	scrollbar-width: none;
}

/* ⚠️ Centred when the strip is SHORTER than the screen, via auto margins rather
   than `justify-content: center`. On a scroll container, centring pushes any
   overflow out above the scroll origin, where it can never be reached again —
   the classic flexbox trap. Auto margins absorb the free space when there is
   some and collapse to zero when there is not, so a short set sits in the middle
   and a long one still scrolls from the top. They are outside the images, so the
   thumbnails still touch each other. */
.ck-viewer__thumb:first-child {
	margin-top: auto;
}

.ck-viewer__thumb:last-child {
	margin-bottom: auto;
}

.ck-viewer__rail::-webkit-scrollbar {
	display: none;
}

/* The thumbnails are the PICTURES, at one width — nothing else.
   No frame, no slab, no padding: the rail is a list of photographs and the only
   state it carries is which one you are on, in opacity. Equal width with the
   image's own height, so the strip reads as the column it navigates. */
.ck-viewer .ck-viewer__thumb {
	flex: 0 0 auto;
	display: block;
	width: 100%;
	height: auto;
	min-height: 0;
	padding: 0;
	border: 0;
	border-radius: 0;
	background: transparent;
	background-color: transparent;
	box-shadow: none;
	cursor: pointer;
	opacity: 0.45;
	transition: opacity 0.2s;
}

.ck-viewer .ck-viewer__thumb:hover {
	opacity: 0.8;
	background: transparent;
	background-color: transparent;
}

.ck-viewer .ck-viewer__thumb.is-active {
	opacity: 1;
}

.ck-viewer .ck-viewer__thumb img {
	display: block;
	width: 100%;
	height: auto;
}

.ck-viewer .ck-viewer__thumb:focus-visible {
	outline: 1px solid #000;
	outline-offset: 2px;
}

/* ── phone ────────────────────────────────────────────────────────── */

@media (max-width: 767px) {
	/* No rail: a column of thumbnails would eat a third of the width, and the
	   stack is short enough to scroll. The counter carries the position. */
	.ck-viewer__rail {
		display: none;
	}

	.ck-viewer__counter {
		width: auto;
		left: 16px;
		text-align: left;
	}

	/* The opening photograph must land exactly where the inline gallery had it,
	   which on mobile is directly below the sticky header. `--ckh-h` is published
	   on :root by inc/elementor-widgets/sticky-header-widget.php from its own
	   `height_mobile` setting — read it rather than hardcoding the 48px it
	   currently resolves to, because that number is a widget control someone can
	   change in the Elementor UI.
	   ⚠️ `topInset()` in gallery-viewer.js reads this padding straight off the
	   element, so the two cannot drift.

	   ⚠️ NOTHING at the bottom. The 64px there was breathing room for a counter
	   that no longer needs it, and it left a band of ground under the last
	   photograph that read as the column having stopped short. The last picture
	   now runs to the bottom edge, matching desktop. */
	.ck-viewer__strip {
		padding: var(--ckh-h, 48px) 0 0;
	}
}

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

/* ── zoomed ───────────────────────────────────────────────────────────────
   ⚠️ THE RAIL AND THE COUNTER DO NOT GO AWAY. They used to: `.is-zoomed` faded
   them and collapsed the rail's 104px column out of the flex row, so a zoomed
   photograph could use the whole width. That bought very little and cost a great
   deal — the scroller's box changed under every zoom, so `zoomTo()`, `focus()`
   and the pinch preview were all anchoring against a layout that was still
   moving, and the picture slid by half the rail. Three separate bug reports came
   out of it.

   Keeping the rail in the flex row means the scroller's box NEVER changes, which
   is what makes the zoom arithmetic trivially correct. The picture simply pans
   inside the space to the right of the rail — Marek, 2026-08-29: *"we don't have
   to hide thumbnail rail (and position indicator) at all: we can pan the image,
   so we just have to ensure that we can move image to the right of the rail"*.
   The scroller IS that space, so its own edges are the pan boundary and the
   browser enforces them for free.

   The close button still dims, because it sits over the picture rather than
   beside it. */
.ck-viewer.is-zoomed .ck-viewer__close {
	opacity: 0.35;
}

.ck-viewer.is-zoomed .ck-viewer__close:hover,
.ck-viewer.is-zoomed .ck-viewer__close:focus-visible {
	opacity: 1;
}

/* ⚠️ THE FOCUS RING GOES INSIDE, because this surface is flush. The site's ring
   is `1px solid #000` at `outline-offset: 2px` (css/base.css) and there is no
   2px of ground for it to sit in — `gap: 0` runs every tile into its neighbour
   and into the edges — so it was drawn over the ADJACENT picture or clipped
   away, leaving a keyboard visitor unable to tell which one they were on.
   `outline-offset: -1px` puts the line flush inside the tile instead, taking no
   layout and moving nothing. Same fix and same reason as the product gallery
   (inc/elementor-widgets/product-gallery-widget.php). */
.ck-viewer .ck-viewer__thumb.ck-viewer__thumb:focus-visible {
	outline: 1px solid #000;
	outline-offset: -1px;
}


/* ⚠️ NO HOVER ON THE RAIL WHERE THERE IS NO POINTER. iOS latches `:hover` after
   a tap, so the thumbnail the visitor last touched stayed lit as though it were
   the current one — competing with the `.is-active` state, which is the only
   thing that should say which photograph you are on. See css/base.css. */
@media (hover: none) {
	.ck-viewer .ck-viewer__thumb:hover {
		opacity: inherit;
	}
}

/* ⚠️ HALF A PIXEL OF OVERLAP, TO CLOSE A SEAM THAT ONLY iOS PAINTS —
   *"in lightbox, i see the same subpixel gap we eliminated from desktop product
   galery"* (Marek, 2026-09-02, iPad Air 5).

   The LAYOUT has no gap: measured at 820, `row-gap: 0`, `margin-bottom: 0`, and
   the distance between consecutive `.ck-viewer__item` boxes is **0.000 at every
   boundary**. What is fractional is the figures themselves — each is
   **1049.578px** tall, from an `aspect-ratio` over a fractional column — so
   every boundary after the first lands part-way through a device pixel and the
   engine has to choose which side of it to paint. iOS leaves the ground
   showing; Blink does not.

   ⚠️ IT DOES NOT REPRODUCE HERE, and that is stated rather than hidden. Scanned
   at dpr 2 and 3 across the darkest join in the set (a lookbook frame whose top
   edge reads luma 134, where the `#fafafa` ground would be unmistakable): rows
   go 188 -> 174 through the boundary with **no bright row at all**. So this is a
   mitigation for a reported artefact, not a fix for a measured one.

   ⚠️ It is safe in the way the flicker mitigation this file's JS declines is
   not: an overlap can only ever COVER a seam, never open one. Half a pixel of
   the previous photograph's last row is hidden by the next figure's first row —
   invisible at any density — and `figTops` reads `offsetTop` from layout, so
   the scroll offsets stay exact.
   ⚠️ Not on the FIRST item: it would pull the column up under the phone's
   `padding-top`, which `topInset()` is subtracted against. */
.ck-viewer__item + .ck-viewer__item {
  margin-top: -0.5px;
}

