
/* =========================================================
   DEMO GALLERY
========================================================= */

.demo-gallery {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 20px;
}

.demo-gallery__item {
    position: relative;
    overflow: hidden;
    cursor: pointer;
}

.demo-gallery__item img {
    display: block;
    width: 100%;
    aspect-ratio: 1 / 1.1;
    object-fit: cover;

    transition:
        transform .8s cubic-bezier(.22,.61,.36,1);
}

.demo-gallery__item:hover img {
    transform: scale(1.04);
}


/* =========================================================
   BODY LOCK
========================================================= */

html.gallery-is-open,
body.gallery-is-open {
    overflow: hidden;
}


/* =========================================================
   LIGHTBOX
========================================================= */

.gallery-lightbox {
    position: fixed;

    inset: 0;

    width: 100%;
    height: 100%;

    z-index: 999999;

    visibility: hidden;
    opacity: 0;

    pointer-events: none;

    background: #111;

    transition:
        opacity .6s ease,
        visibility .6s ease;
}

.gallery-lightbox.is-open {
    visibility: visible;
    opacity: 1;

    pointer-events: auto;
}


/* =========================================================
   BACKGROUND

   A second Swiper instance, full-bleed, blurred + darkened.
   It shows the SAME photo as the main slider and is kept in
   sync with it via Swiper's "controller" module (wired up in
   js/scripts.js) — so dragging/changing the main photo
   crossfades this background live, in the same motion.

   The outer .gallery-lightbox__bg is clipped exactly to the
   viewport; the swiper itself is oversized (inset: -8%) so the
   blur never shows a hard edge.
========================================================= */

.gallery-lightbox__bg {
    position: absolute;

    inset: 0;

    overflow: hidden;

    opacity: 0;

    transition: opacity .8s cubic-bezier(.22,.61,.36,1);
}

.gallery-lightbox.is-open
.gallery-lightbox__bg {
    opacity: 1;
}


.gallery-lightbox__bg-swiper {
    position: absolute;

    inset: -8%;

    width: 116%;
    height: 116%;
}

.gallery-lightbox__bg-swiper
.swiper-wrapper {
    height: 100%;
}


.gallery-lightbox__bg-image {
    width: 100%;
    height: 100%;

    background-position: center;
    background-size: cover;
    background-repeat: no-repeat;

    filter: blur(4px);

    /*
     * A slow, continuous "Ken Burns" style zoom, so the
     * background never sits perfectly still — it keeps
     * gently stretching for as long as a photo is showing.
     */

    animation:
        galleryBgSlowZoom
        14s
        ease-in-out
        infinite
        alternate;
}


@keyframes galleryBgSlowZoom {

    from {
        transform: scale(1.06);
    }

    to {
        transform: scale(1.18);
    }

}


.gallery-lightbox__bg-overlay {
    position: absolute;

    inset: 0;

    background:
        rgba(0, 0, 0, .4);

    /*
     * Swiper's own base CSS gives .gallery-lightbox__bg-swiper
     * (the .swiper root) an implicit z-index:1. An element with
     * an explicit positive z-index always paints above a sibling
     * left at z-index:auto, no matter the DOM order — so without
     * an explicit z-index here, this overlay was silently being
     * painted BELOW the background swiper and the dark scrim
     * never showed up. Giving it z-index:2 fixes that for good.
     */

    z-index: 2;
}


/* =========================================================
   MAIN SWIPER
========================================================= */

.gallery-lightbox__slider {
    position: absolute;
    left: 50%;
    transform: translateX(-50%) !important;
    bottom: 20vh;
    width: min(80vw, 900px);
    height: min(72vh, 760px);
    overflow: visible;
    z-index: 5;
}


.gallery-lightbox__slider-swiper {
    width: 100%;
    height: 100%;
}


/* =========================================================
   SLIDES

   IMPORTANT: we deliberately do NOT set our own position/
   transform/opacity on .swiper-slide here. Swiper's "creative"
   effect (configured in js/scripts.js) owns all of that — it
   adds its own base CSS (via the swiper-creative class on the
   root element) and animates each slide's transform/opacity
   itself. Overriding it with custom absolute-positioning CSS
   is what caused slides to go invisible/mispositioned before:
   it broke Swiper's internal geometry (every slide reported
   the same offset), so its own effect math produced garbage
   values. Let Swiper own the slide box; we only style what's
   INSIDE each slide (the image) below.
========================================================= */

.gallery-lightbox__slider
.swiper-wrapper {
    height: 100%;
}


.gallery-lightbox__slider .swiper-slide:not(.swiper-slide-active) img {
    opacity: 0;
    transition: opacity 0.4s ease-in-out 0.4s;
}

/*
    The incoming slide must always render ON TOP of the
    outgoing one, for the whole transition, in either
    direction — that's what makes the new photo look like it
    "lands over" (нахльостується) the previous one instead of
    both crossfading together. Swiper's own per-frame z-index
    can briefly flip mid-transition, so we pin it via the
    stable "active" class instead, with !important to win over
    Swiper's inline z-index.
*/

.gallery-lightbox__slider
.swiper-slide-active {

    z-index: 10 !important;
}


/* =========================================================
   IMAGE
========================================================= */

.gallery-lightbox__image {
    position: relative;

    width: 100%;
    height: 100%;

    overflow: hidden;
}


.gallery-lightbox__image img {
    display: block;

    width: 100%;
    height: 100%;

    object-fit: contain;
}


/* =========================================================
   BOTTOM
========================================================= */

.gallery-lightbox__bottom {

    position: absolute;

    left: 50%;
    bottom: 12vh;
    transform: translateX(-50%) !important;
    display: flex;
    width: 900px;
    max-width: 100%;
    justify-content: space-between;
    align-items: flex-end;
    z-index: 20;

    /*
     * This box spans almost the full width (it used to also
     * hold the arrows), so its transparent area can sit over
     * the dots below the photo and swallow clicks meant for
     * them. It has no interactive children anymore (arrows
     * moved beside the photo), so it's safe to let clicks
     * pass through.
     */

    pointer-events: none;
}


/* =========================================================
   TEXT
========================================================= */

.gallery-lightbox__info {
    max-width: 650px;

    overflow: hidden;
}


.gallery-lightbox__title {

    color: #fff;

    font-size: clamp(
        24px,
        3.2vw,
        24px
    );

    font-weight: 400;

    line-height: .95;

    letter-spacing: -.03em;

    opacity: 0;

    transform: translateY(35px);

    transition:
        opacity .8s ease,
        transform .9s cubic-bezier(.22,.61,.36,1);
}


.gallery-lightbox__subtitle {

    margin-top: 6px;

    color:
        rgba(255,255,255,.6);

    font-size: 14px;

    line-height: 1.4;

    opacity: 0;

    transform: translateY(20px);

    transition:
        opacity .8s ease .08s,
        transform .9s cubic-bezier(.22,.61,.36,1) .08s;
}


/*
    Text active state
*/

.gallery-lightbox__text-active
.gallery-lightbox__title,
.gallery-lightbox__text-active
.gallery-lightbox__subtitle {

    opacity: 1;

    transform: translateY(0);

}


/* =========================================================
   ARROWS — positioned on the left/right sides of the
   main photo. They are children of .gallery-lightbox__slider,
   so they sit relative to the slider box itself.
========================================================= */

.gallery-lightbox__arrow {

    position: fixed;

    top: 50%;

    transform: translateY(-50%);

    display: flex;

    align-items: center;
    justify-content: center;

    width: 58px;
    height: 58px;

    padding: 0;

    border: 1px solid
        rgba(255,255,255,.3);

    border-radius: 50%;

    color: #fff;

    background:
        rgba(255,255,255,.08);

    backdrop-filter: blur(4px);

    cursor: pointer;

    z-index: 20;

    transition:
        background .35s ease,
        border-color .35s ease,
        transform .35s ease;
}


.gallery-lightbox__arrow--prev {

    left: 16px;

    transform: translateY(-50%);
}


.gallery-lightbox__arrow--next {

    right: 16px;

    transform: translateY(-50%);
}


.gallery-lightbox__arrow:hover {

    background:
        rgba(255,255,255,.12);

    border-color:
        rgba(255,255,255,.7);

    /* keep vertical centering (translateY) while adding the hover scale */
    transform: translateY(-50%) scale(1.05);
}


.gallery-lightbox__arrow:active {

    transform: translateY(-50%) scale(.95);

}


.gallery-lightbox__arrow.swiper-button-disabled {

    opacity: .25;

    pointer-events: none;

}


/* =========================================================
   DOTS — centered under the main photo. Children of
   .gallery-lightbox__slider, positioned just below its
   bottom edge (slider has overflow: visible).
========================================================= */

.gallery-lightbox__dots {

    position: absolute;

    left: 50%;

    bottom: -84px;

    transform: translateX(-50%);

    z-index: 20;

    display: flex;

    align-items: center;

    gap: 7px;
}


.gallery-lightbox__dot {

    width: 5px;
    height: 5px;

    padding: 0;

    border: 0;

    border-radius: 50%;

    background: #fff;

    opacity: .35;

    cursor: pointer;

    transition:
        width .45s cubic-bezier(.22,.61,.36,1),
        opacity .4s ease;
}


.gallery-lightbox__dot.is-active {

    width: 30px;

    border-radius: 10px;

    opacity: 1;
}


/* =========================================================
   CLOSE
========================================================= */

.gallery-lightbox__close {

    position: absolute;

    top: 30px;
    right: 35px;

    width: 50px;
    height: 50px;

    padding: 0;

    border: 0;

    background: transparent;

    cursor: pointer;

    z-index: 50;

    opacity: .8;

    transition:
        opacity .3s ease,
        transform .3s ease;
}


.gallery-lightbox__close:hover {

    opacity: 1;

    transform: rotate(90deg);

}


.gallery-lightbox__close span {

    position: absolute;

    top: 50%;
    left: 50%;

    width: 28px;
    height: 1px;

    background: #fff;

}


.gallery-lightbox__close span:first-child {

    transform:
        translate(-50%, -50%)
        rotate(45deg);

}


.gallery-lightbox__close span:last-child {

    transform:
        translate(-50%, -50%)
        rotate(-45deg);

}


/* =========================================================
   OPEN ANIMATION
========================================================= */

.gallery-lightbox.is-open
.gallery-lightbox__slider {

    animation:
        gallerySliderOpen
        1s
        cubic-bezier(.22,.61,.36,1)
        both;

}


@keyframes gallerySliderOpen {

    from {

        opacity: 0;

        transform:
            translate3d(0, 40px, 0)
            scale(.97);

    }

    to {

        opacity: 1;

        transform:
            translate3d(0, 0, 0)
            scale(1);

    }

}


/* =========================================================
   MOBILE
========================================================= */

@media (max-width: 767px) {

    .demo-gallery {

        grid-template-columns:
            repeat(2, 1fr);

        gap: 10px;

    }


    .gallery-lightbox__slider {


        bottom: 22vh;

        width: 90vw;

        height: 53vh;

    }


    .gallery-lightbox__bottom {
        max-width: 90vw;        
    }



    .gallery-lightbox__arrow {
        margin-top: -21px;
        width: 45px;
        height: 45px;

    }


    .gallery-lightbox__arrow--prev {

        left: 8px;

    }


    .gallery-lightbox__arrow--next {

        right: 8px;

    }


    .gallery-lightbox__close {

        top: 15px;
        right: 15px;

    }
    .gallery-lightbox__bottom {
        bottom: 20vh;
    }

    .gallery-lightbox__dots {


    }
    .gallery-lightbox__slider {

        bottom: 28vh;
    }
}


/* =========================================================
   SMALL MOBILE
========================================================= */

@media (max-width: 480px) {

    .gallery-lightbox__slider {

        bottom: 28vh;

        height: 50vh;

    }


    .gallery-lightbox__bottom {

        align-items: flex-end;

    }


    .gallery-lightbox__arrow {

        width: 40px;
        height: 40px;

    }
    .gallery-lightbox .gallery-lightbox__slider {
        left: 5vw !important;
        transform: none !important;
    }
}


/* =========================================================
   REDUCED MOTION
========================================================= */

@media (prefers-reduced-motion: reduce) {

    .gallery-lightbox *,
    .gallery-lightbox {

        animation-duration: .01ms !important;

        transition-duration: .01ms !important;

    }

}
