/* Gallery: the carousel inside a card and the fullscreen viewer.
   Everything positioned inside .gallery, plus the lightbox — they share the
   .nav class and the same logic for overlaying a photo.
   Page and card styling lives with the page. */

/* ---- carousel ---- */
.gallery { position:relative; background:var(--ink) }
/* overflow-y is spelled out: with overflow-x:auto the browser computes the
   other axis as auto rather than visible, and any vertical overflow turns into
   scrolling inside the carousel. */
/* overscroll-behavior-x:contain keeps an edge gesture from leaking out —
   otherwise the browser reads it as "back" or drags the whole page. */
.track { display:flex; overflow-x:auto; overflow-y:hidden;
  overscroll-behavior-x:contain;
  scroll-snap-type:x mandatory; scrollbar-width:none; aspect-ratio:9/16 }
.track::-webkit-scrollbar { display:none }
.track:focus-visible { outline:2px solid var(--accent); outline-offset:-2px }
/* overflow:hidden clips the enlarged blurred backdrop to the slide — without it
   the backdrop spills onto the neighbouring frame and inflates the track's
   scrollable area.
   scroll-snap-stop:always makes one swipe advance exactly one frame: without it
   inertia carries the track past several photos and snapping lands somewhere
   the finger never asked for. */
.slide { position:relative; flex:0 0 100%; scroll-snap-align:center;
  scroll-snap-stop:always; overflow:hidden }

/* ---- photo and blurred backdrop ---- */
/* The blurred copy of the photo (12×21, stretched over the slide) stays for
   good, not just until the photo loads. It does two jobs: before the photo
   arrives it shows its colours instead of emptiness; afterwards it fills the
   margins around it. scale(1.1) hides the translucent fringe that filter
   leaves at the edges. */
.backdrop { position:absolute; inset:0; background-size:cover; background-position:center;
  filter:blur(14px); transform:scale(1.1) }
/* contain, not cover: the photo is shown whole, in its own proportions.
   Cropping is out — listings carry portrait, landscape and square photos alike,
   and a crop would eat each of them differently. .backdrop fills the margins. */
.photo { position:relative; width:100%; height:100%; object-fit:contain; display:block;
  cursor:zoom-in }

/* ---- overlays on top of the photo ---- */
.badge, .tariff { position:absolute; top:8px; z-index:3; font-size:11px;
  padding:3px 8px; border-radius:99px; background:rgba(0,0,0,.62); color:var(--text-strong) }
.badge { left:8px }
.tariff { right:8px; background:var(--accent); color:#1a1d23; font-weight:600 }
/* 44×44 is the smallest tap target below which a finger starts missing.
   ::after adds another 8px of invisible margin: a miss would otherwise land on
   the photo and open the fullscreen viewer instead of paging.
   The visible circle is drawn by ::before and is markedly smaller than the tap
   target — still easy to hit, but it covers less of the photo. */
.nav { position:absolute; top:50%; transform:translateY(-50%); z-index:3;
  width:44px; height:44px; border:0; background:none; cursor:pointer;
  color:var(--text-strong); font-size:19px; line-height:1; text-shadow:0 1px 3px rgba(0,0,0,.45);
  display:flex; align-items:center; justify-content:center }
/* Light and translucent: blurring the backdrop keeps the arrow legible over a
   dark frame and a bright one alike — a flat fill would vanish on one of them. */
.nav::before { content:''; position:absolute; z-index:-1;
  top:50%; left:50%; transform:translate(-50%,-50%);
  width:30px; height:30px; border-radius:99px;
  background:rgba(255,255,255,.2); backdrop-filter:blur(6px) }
.nav::after { content:''; position:absolute; inset:-8px; border-radius:99px }
.nav:hover::before { background:rgba(255,255,255,.32) }
.prev { left:8px } .next { right:8px }
.dots { position:absolute; bottom:8px; left:0; right:0; z-index:3;
  display:flex; gap:5px; justify-content:center }
.dots i { width:6px; height:6px; border-radius:99px; background:rgba(255,255,255,.42) }
.dots i.on { background:var(--text-strong); width:16px }
/* A single photo has nothing to page through: arrows and dots only get in the
   way. Such a gallery carries the same markup and the style hides them, so the
   script needs no separate branch. */
.gallery:has(.slide:only-child) .nav,
.gallery:has(.slide:only-child) .dots { display:none }

/* ---- fullscreen viewer ---- */
.lightbox { position:fixed; inset:0; z-index:99; background:rgba(0,0,0,.95);
  display:none; align-items:center; justify-content:center; overflow:hidden;
  overscroll-behavior:contain }
.lightbox[open] { display:flex }
.lightbox img { max-width:96vw; max-height:92vh; object-fit:contain; touch-action:none;
  user-select:none; -webkit-user-drag:none; transform-origin:center; will-change:transform;
  cursor:zoom-in }
.lightbox.zoom-animate img { transition:transform .16s ease }
.lightbox.is-zoomed img { cursor:grab }
.lightbox.is-panning img { cursor:grabbing; transition:none }
.lightbox .nav { width:52px; height:52px; font-size:22px }
.lightbox .nav::before { width:38px; height:38px }
.lightbox .close, .lightbox .zoom { position:absolute; top:14px; z-index:4; width:38px; height:38px;
  border:0; border-radius:99px; background:rgba(255,255,255,.14); color:var(--text-strong);
  font-size:20px; cursor:pointer }
.lightbox .close { right:16px }
.lightbox .zoom { right:62px }
.lightbox button:focus-visible { outline:2px solid var(--text-strong); outline-offset:2px }
.lightbox .counter { position:absolute; top:18px; left:18px; color:var(--text-strong); font-size:13px;
  opacity:.75 }

/* Grow-from-thumbnail when the viewer opens */
::view-transition-old(photo), ::view-transition-new(photo) { animation-duration:.28s }

/* Paging in the fullscreen viewer: the frame leaves towards the direction of
   travel and the next one arrives from the opposite side — the same feel as the
   carousel in a card. The direction sits on the document root, where the
   transition pseudo-elements live; they cannot reach the viewer itself. */
@keyframes photo-out-left  { to   { transform:translateX(-7%); opacity:0 } }
@keyframes photo-in-right  { from { transform:translateX(7%);  opacity:0 } }
@keyframes photo-out-right { to   { transform:translateX(7%);  opacity:0 } }
@keyframes photo-in-left   { from { transform:translateX(-7%); opacity:0 } }

html[data-lb-dir=next]::view-transition-old(photo) { animation:photo-out-left  .3s cubic-bezier(.32,.72,0,1) both }
html[data-lb-dir=next]::view-transition-new(photo) { animation:photo-in-right  .3s cubic-bezier(.32,.72,0,1) both }
html[data-lb-dir=prev]::view-transition-old(photo) { animation:photo-out-right .3s cubic-bezier(.32,.72,0,1) both }
html[data-lb-dir=prev]::view-transition-new(photo) { animation:photo-in-left   .3s cubic-bezier(.32,.72,0,1) both }

/* Anyone bothered by motion gets the change of frame without it. */
@media (prefers-reduced-motion: reduce) {
  html[data-lb-dir]::view-transition-old(photo),
  html[data-lb-dir]::view-transition-new(photo) { animation-duration:1ms }
}
