{"version":3,"file":"pdp-v2.js","names":["init","init","init","init","init","init","lgZoom"],"sources":["../resources/javascript/pdp/configurator/cylindo-zoom-controls.js","../resources/javascript/pdp/configurator/short-desktop-viewport.js","../resources/javascript/pdp/configurator/config-slider.js","../node_modules/photoswipe/dist/photoswipe-lightbox.esm.js","../resources/javascript/pdp/photoswipe-gallery.js","../resources/javascript/pdp/configurator/popover.js","../resources/javascript/pdp/configurator/goto-configurator.js","../resources/javascript/pdp/configurator/upsell.js","../resources/javascript/swatch/initSwatchButton.js","../resources/javascript/pdp/configurator/configurator-state.js","../resources/javascript/pdp/configurator/configuration-bar.js","../resources/javascript/pdp/configurator/dynamic-config-bar.js","../resources/javascript/pdp/lp-qty-chooser.js","../resources/javascript/pdp/v2-tracking.mjs","../resources/javascript/pdp/deferred-variant-content.js","../resources/javascript/pdp/product-grid-video.js","../resources/javascript/pdp/bump-light-gallery.js","../resources/javascript/pdp/inline-shack-search.js","../resources/javascript/pdp-v2.js"],"sourcesContent":["const zoomInSelector = '[data-hero-zoom-in]';\nconst zoomOutSelector = '[data-hero-zoom-out]';\nconst zoomActionsSelector = '[data-hero-zoom-actions]';\nconst viewerSelector = '[data-360-viewer]';\nconst defaultZoomLevel = 1;\nconst intermediateZoomLevel = '50%';\nconst maximumZoomLevel = '100%';\nconst zoomAnimationDuration = 320;\nconst zoomLayoutFadeDuration = 160;\nconst zoomLayoutExpandedAttribute = 'data-cylindo-zoom-expanded';\nconst zoomLayoutFadingAttribute = 'data-cylindo-zoom-fading';\n\n/**\n * Parses Cylindo zoom values which may be exposed as numbers or\n * percentage-like strings.\n *\n * @param {number|string|undefined|null} zoom\n * @returns {number}\n */\nconst parseZoomLevel = zoom => Number.parseFloat(zoom);\n\n/**\n * Keeps intermediate zoom values in the same shape as the target.\n *\n * @param {number} zoom\n * @param {'number'|'percentage'} format\n * @returns {number|string}\n */\nconst formatZoomLevel = (zoom, format) =>\n    format === 'percentage' ? `${zoom}%` : zoom;\n\n/**\n * Checks whether a zoom value is expressed as a percentage string.\n *\n * @param {number|string} zoom\n * @returns {boolean}\n */\nconst isPercentageZoom = zoom => typeof zoom === 'string' && zoom.includes('%');\n\n/**\n * Percentage zoom values and numeric Cylindo zoom values use different scales.\n *\n * @param {number|string} zoom\n * @returns {'number'|'percentage'}\n */\nconst getZoomFormat = zoom =>\n    isPercentageZoom(zoom) ? 'percentage' : 'number';\n\n/**\n * Smoothstep easing gives a gentle start and finish without overshooting.\n *\n * @param {number} progress\n * @returns {number}\n */\nconst easeZoomProgress = progress => progress * progress * (3 - 2 * progress);\n\n/**\n * Reads the Cylindo zoom level from an event, falling back to the viewer state.\n *\n * @param {CustomEvent|Event} event\n * @param {HTMLElement} viewer\n * @returns {number}\n */\nconst getEventZoom = (event, viewer) => {\n    const eventZoom = parseZoomLevel(event.detail?.zoom ?? event.detail);\n    const viewerZoom = parseZoomLevel(viewer.zoom);\n\n    if (Number.isFinite(eventZoom)) {\n        return eventZoom;\n    }\n\n    return Number.isFinite(viewerZoom) ? viewerZoom : defaultZoomLevel;\n};\n\n/**\n * Reads the active Cylindo item from an event, falling back to the viewer state.\n *\n * @param {CustomEvent|Event} event\n * @param {HTMLElement} viewer\n * @returns {object|null}\n */\nconst getEventItem = (event, viewer) =>\n    event.detail?.item ?? viewer.item ?? null;\n\n/**\n * Wires custom hero zoom controls to Cylindo's programmatic zoom API.\n */\nexport default class CylindoZoomControls {\n    /**\n     * @param {HTMLElement} root\n     */\n    constructor(root) {\n        this.root = root;\n        this.viewer = root.querySelector(viewerSelector);\n        this.actions = root.querySelector(zoomActionsSelector);\n        this.zoomInButton = root.querySelector(zoomInSelector);\n        this.zoomOutButton = root.querySelector(zoomOutSelector);\n        this.abortController = new AbortController();\n        this.isZoomable = true;\n        this.isViewerReady = false;\n        this.currentZoom = defaultZoomLevel;\n        this.currentZoomFormat = 'number';\n        this.requestedZoom = defaultZoomLevel;\n        this.zoomAnimationFrame = null;\n        this.zoomLayoutTransitionTimeout = null;\n        this.isZoomLayoutTransitioning = false;\n\n        this.init();\n    }\n\n    /**\n     * Finds the required DOM nodes and binds Cylindo zoom lifecycle listeners.\n     *\n     * @returns {void}\n     */\n    init() {\n        if (\n            !this.viewer ||\n            !this.actions ||\n            !this.zoomInButton ||\n            !this.zoomOutButton\n        ) {\n            return;\n        }\n\n        const { signal } = this.abortController;\n        this.setButtonsDisabled(true);\n\n        this.zoomInButton.addEventListener('click', this.handleZoomIn, {\n            signal,\n        });\n        this.zoomOutButton.addEventListener('click', this.handleZoomOut, {\n            signal,\n        });\n        this.viewer.addEventListener('zoom-change', this.handleZoomChange, {\n            signal,\n        });\n        this.viewer.addEventListener('item-change', this.handleItemChange, {\n            signal,\n        });\n\n        this.updateZoomState(\n            parseZoomLevel(this.viewer.zoom ?? this.currentZoom)\n        );\n        this.updateZoomAvailability(this.viewer.item ?? null);\n\n        customElements.whenDefined('cylindo-viewer').then(() => {\n            if (signal.aborted) {\n                return;\n            }\n\n            this.isViewerReady = true;\n            this.updateZoomState(\n                parseZoomLevel(this.viewer.zoom ?? this.currentZoom)\n            );\n            this.updateZoomAvailability(this.viewer.item ?? null);\n        });\n    }\n\n    handleZoomIn = () => {\n        if (\n            !this.isViewerReady ||\n            !this.isZoomable ||\n            this.isZoomLayoutTransitioning\n        ) {\n            return;\n        }\n\n        const zoomTarget =\n            parseZoomLevel(this.requestedZoom) > defaultZoomLevel\n                ? maximumZoomLevel\n                : intermediateZoomLevel;\n\n        this.transitionZoomLayout(true, () => this.animateZoomTo(zoomTarget));\n    };\n\n    handleZoomOut = () => {\n        if (!this.isViewerReady || this.isZoomLayoutTransitioning) {\n            return;\n        }\n\n        this.animateZoomTo(defaultZoomLevel, {\n            onComplete: () => {\n                if (typeof this.viewer.zoomStop === 'function') {\n                    this.viewer.zoomStop();\n                } else {\n                    this.viewer.zoom = defaultZoomLevel;\n                }\n\n                this.transitionZoomLayout(false);\n            },\n        });\n    };\n\n    handleZoomChange = event => {\n        this.updateZoomState(getEventZoom(event, this.viewer));\n    };\n\n    handleItemChange = event => {\n        this.updateZoomAvailability(getEventItem(event, this.viewer));\n    };\n\n    /**\n     * Stores the current Cylindo zoom level and toggles the zoom-out button.\n     *\n     * @param {number} zoom\n     * @returns {void}\n     */\n    updateZoomState(zoom) {\n        const requestedZoom = parseZoomLevel(this.requestedZoom);\n        const fallbackZoom = Number.isFinite(requestedZoom)\n            ? requestedZoom\n            : defaultZoomLevel;\n        const isZoomed =\n            (Number.isFinite(zoom) && zoom > defaultZoomLevel) ||\n            fallbackZoom > defaultZoomLevel;\n        this.currentZoom =\n            Number.isFinite(zoom) && zoom > defaultZoomLevel\n                ? zoom\n                : fallbackZoom;\n\n        this.zoomOutButton.toggleAttribute('hidden', !isZoomed);\n    }\n\n    /**\n     * Fades the viewer while swapping between padded and full-height layouts.\n     *\n     * @param {boolean} isExpanded\n     * @param {Function|null} onLayoutChanged\n     * @returns {void}\n     */\n    transitionZoomLayout(isExpanded, onLayoutChanged = null) {\n        if (\n            this.root.hasAttribute(zoomLayoutExpandedAttribute) === isExpanded\n        ) {\n            onLayoutChanged?.();\n            return;\n        }\n\n        this.clearZoomLayoutTransition();\n        this.isZoomLayoutTransitioning = true;\n        this.setButtonsDisabled(true);\n        this.root.toggleAttribute(zoomLayoutFadingAttribute, true);\n\n        this.zoomLayoutTransitionTimeout = window.setTimeout(() => {\n            this.zoomLayoutTransitionTimeout = null;\n\n            if (this.abortController.signal.aborted) {\n                return;\n            }\n\n            this.root.toggleAttribute(zoomLayoutExpandedAttribute, isExpanded);\n\n            window.requestAnimationFrame(() => {\n                if (this.abortController.signal.aborted) {\n                    return;\n                }\n\n                onLayoutChanged?.();\n                this.root.toggleAttribute(zoomLayoutFadingAttribute, false);\n                this.isZoomLayoutTransitioning = false;\n                this.setButtonsDisabled(\n                    !this.isViewerReady || !this.isZoomable\n                );\n            });\n        }, zoomLayoutFadeDuration);\n    }\n\n    /**\n     * Animates the known-working public Cylindo zoom property.\n     *\n     * @param {number|string} targetZoom\n     * @param {{onComplete?: Function}} options\n     * @returns {void}\n     */\n    animateZoomTo(targetZoom, { onComplete = null } = {}) {\n        this.cancelZoomAnimation();\n\n        if (typeof window.requestAnimationFrame !== 'function') {\n            this.viewer.zoom = targetZoom;\n            onComplete?.();\n            return;\n        }\n\n        const targetFormat =\n            targetZoom === defaultZoomLevel &&\n            getZoomFormat(this.requestedZoom) === 'percentage'\n                ? 'percentage'\n                : getZoomFormat(targetZoom);\n        const requestedZoom = parseZoomLevel(this.requestedZoom);\n        const viewerZoom = parseZoomLevel(this.viewer.zoom);\n        const canUseViewerZoom =\n            Number.isFinite(viewerZoom) &&\n            targetFormat === getZoomFormat(this.viewer.zoom);\n        const fromZoom = canUseViewerZoom\n            ? viewerZoom\n            : Number.isFinite(requestedZoom)\n              ? requestedZoom\n              : this.currentZoom;\n        const toZoom = parseZoomLevel(targetZoom);\n\n        if (!Number.isFinite(fromZoom) || !Number.isFinite(toZoom)) {\n            this.viewer.zoom = targetZoom;\n            onComplete?.();\n            return;\n        }\n\n        this.currentZoomFormat = targetFormat;\n        const startedAt = window.performance.now();\n\n        const step = timestamp => {\n            const elapsed = timestamp - startedAt;\n            const progress = Math.min(elapsed / zoomAnimationDuration, 1);\n            const easedProgress = easeZoomProgress(progress);\n            const nextZoom = fromZoom + (toZoom - fromZoom) * easedProgress;\n\n            if (progress < 1) {\n                this.currentZoom = nextZoom;\n                this.requestedZoom = formatZoomLevel(nextZoom, targetFormat);\n                this.viewer.zoom = this.requestedZoom;\n                this.zoomAnimationFrame = window.requestAnimationFrame(step);\n                return;\n            }\n\n            this.zoomAnimationFrame = null;\n            this.currentZoom = toZoom;\n            this.currentZoomFormat = targetFormat;\n            this.requestedZoom = targetZoom;\n            this.viewer.zoom = targetZoom;\n            onComplete?.();\n        };\n\n        this.zoomAnimationFrame = window.requestAnimationFrame(step);\n    }\n\n    /**\n     * Cancels any custom zoom animation currently in progress.\n     *\n     * @returns {void}\n     */\n    cancelZoomAnimation() {\n        if (this.zoomAnimationFrame === null) {\n            return;\n        }\n\n        window.cancelAnimationFrame(this.zoomAnimationFrame);\n        this.zoomAnimationFrame = null;\n    }\n\n    /**\n     * Cancels any pending padded/full-height layout transition.\n     *\n     * @returns {void}\n     */\n    clearZoomLayoutTransition() {\n        if (this.zoomLayoutTransitionTimeout !== null) {\n            window.clearTimeout(this.zoomLayoutTransitionTimeout);\n            this.zoomLayoutTransitionTimeout = null;\n        }\n\n        this.root.toggleAttribute(zoomLayoutFadingAttribute, false);\n        this.isZoomLayoutTransitioning = false;\n    }\n\n    /**\n     * Hides controls for Cylindo items that do not support zooming.\n     *\n     * @param {object|null} item\n     * @returns {void}\n     */\n    updateZoomAvailability(item) {\n        const canBeZoomedIn = item?.canBeZoomedIn;\n        this.isZoomable = canBeZoomedIn !== false;\n\n        this.actions.toggleAttribute('hidden', !this.isZoomable);\n        this.setButtonsDisabled(!this.isViewerReady || !this.isZoomable);\n\n        if (!this.isZoomable) {\n            this.handleZoomOut();\n        }\n    }\n\n    /**\n     * Keeps both zoom buttons aligned while the viewer is loading or unavailable.\n     *\n     * @param {boolean} isDisabled\n     * @returns {void}\n     */\n    setButtonsDisabled(isDisabled) {\n        this.zoomInButton.disabled = isDisabled;\n        this.zoomOutButton.disabled = isDisabled;\n    }\n\n    /**\n     * Removes listeners registered by this instance.\n     *\n     * @returns {void}\n     */\n    destroy() {\n        this.cancelZoomAnimation();\n        this.clearZoomLayoutTransition();\n        this.root.toggleAttribute(zoomLayoutExpandedAttribute, false);\n        this.abortController.abort();\n    }\n}\n","export const shortDesktopViewportHeight = 850;\nexport const shortDesktopViewportMinWidth = 1000;\n\nexport const shortDesktopViewportQuery =\n    `(max-height: ${shortDesktopViewportHeight}px) and ` +\n    `(min-width: ${shortDesktopViewportMinWidth}px)`;\n\nexport const isShortDesktopViewport = () =>\n    window.matchMedia(shortDesktopViewportQuery).matches;\n","/**\n * Configurator Hero Slider\n * A lightweight slider using native CSS scroll-snap and Intersection Observer\n */\n\nimport CylindoZoomControls from './cylindo-zoom-controls';\nimport { shortDesktopViewportMinWidth } from './short-desktop-viewport';\n\nconst configuratorSlideSelector = '.configurator-hero__slide--configurator';\nconst outletConfiguratorOptionsSelector =\n    '[data-configurator-options].configurator-options--outlet';\nconst configuratorSlideFadeClass = 'configurator-hero__slider--is-fading';\nconst configuratorViewerInteractingClass =\n    'configurator-hero__slides--viewer-interacting';\nconst configuratorSlideFadeDuration = 220;\nconst pairedSlidesHeroClass = 'configurator-hero--paired-slides';\nconst pairedSlidesStartClass = 'configurator-hero__slide--paired-start';\nconst pairedSlidesFullClass = 'configurator-hero__slide--paired-full';\nconst pairedSlidesViewportQuery = `(min-width: ${shortDesktopViewportMinWidth}px)`;\n\nexport default class ConfiguratorSlider {\n    constructor(element) {\n        this.slider =\n            element ?? document.querySelector('[data-configurator-hero]');\n        this.hero = this.slider.closest('.configurator-hero');\n        this.slidesContainer = this.slider.querySelector(\n            '.configurator-hero__slides'\n        );\n        this.slides = Array.from(\n            this.slider.querySelectorAll('.configurator-hero__slide')\n        );\n        this.prevButton = this.slider.querySelector('[data-hero-prev]');\n        this.nextButton = this.slider.querySelector('[data-hero-next]');\n        this.currentCounter = this.slider.querySelector('[data-hero-current]');\n        this.totalCounter = this.slider.querySelector('[data-hero-total]');\n        this.nav = this.slider.querySelector('.configurator-hero__nav');\n\n        this.currentIndex = 0;\n        this.totalSlides = this.slides.length;\n        this.configuratorSlideIndex = this.slides.findIndex(slide =>\n            slide.matches(configuratorSlideSelector)\n        );\n        this.configuratorSlideIndex =\n            this.configuratorSlideIndex > -1 ||\n            !document.querySelector(outletConfiguratorOptionsSelector)\n                ? this.configuratorSlideIndex\n                : this.totalSlides - 1;\n        this.lifestyleSlideTotal =\n            this.configuratorSlideIndex > 0\n                ? this.configuratorSlideIndex\n                : this.totalSlides;\n        this.lastLifestyleIndex = Math.max(this.lifestyleSlideTotal - 1, 0);\n        this.isLastSlide = false;\n        this.isConfiguratorSlideActive = false;\n        this.configuratorSlideFadeTimeout = null;\n        this.configuratorStateFrame = null;\n        this.isCylindoZoomed = false;\n        this.cylindoZoomControls = null;\n        this.cylindoInteractionReleaseTimeout = null;\n        this.pairedSlidesResizeFrame = null;\n        this.isPairedSlidesActive = this.hasPairedSlidesLayout();\n\n        this.init();\n    }\n\n    init() {\n        this.setupPairedSlidesMode();\n        this.updateCounter();\n\n        this.nav?.toggleAttribute('hidden', this.totalSlides <= 1);\n\n        // Set up Intersection Observer\n        this.setupIntersectionObserver();\n\n        // Set up navigation\n        this.setupNavigation();\n\n        // Keep configurator UI state in step with the final slide's snap position.\n        this.setupConfiguratorStateSync();\n\n        // Hide hero copy while the Cylindo viewer is zoomed.\n        this.setupCylindoZoomListener();\n\n        this.setupCylindoZoomControls();\n\n        // Let Cylindo own touch movement while the user is manipulating the viewer.\n        this.setupCylindoInteractionLock();\n\n        // Initial button state\n        this.updateButtonStates();\n\n        if (this.slidesContainer.hasAttribute('data-start-configurator')) {\n            this.goToSlide(this.totalSlides - 1, true);\n            this.handleSlideChange(this.totalSlides - 1);\n        } else {\n            this.handleSlideChange(this.currentIndex);\n        }\n    }\n\n    setupPairedSlidesMode() {\n        this.updatePairedSlideClasses();\n        this.syncPairedSlidesMode();\n\n        this._handlePairedSlidesResize = () => {\n            if (this.pairedSlidesResizeFrame) {\n                return;\n            }\n\n            this.pairedSlidesResizeFrame = window.requestAnimationFrame(() => {\n                this.pairedSlidesResizeFrame = null;\n                this.syncPairedSlidesMode();\n            });\n        };\n\n        window.addEventListener('resize', this._handlePairedSlidesResize, {\n            passive: true,\n        });\n\n        window.visualViewport?.addEventListener(\n            'resize',\n            this._handlePairedSlidesResize,\n            { passive: true }\n        );\n    }\n\n    syncPairedSlidesMode() {\n        const wasPaired = this.isPairedSlidesMode();\n        const shouldPairSlides = this.hasPairedSlidesLayout();\n\n        this.isPairedSlidesActive = shouldPairSlides;\n\n        const nextIndex = this.getNavigableSlideIndex(this.currentIndex);\n        const shouldRealignSlide =\n            wasPaired !== shouldPairSlides || nextIndex !== this.currentIndex;\n\n        this.currentIndex = nextIndex;\n\n        if (shouldRealignSlide) {\n            this.scrollSlideIntoPosition(this.currentIndex, true);\n        }\n\n        this.updateCounter();\n        this.updateButtonStates();\n        this.syncConfiguratorSlideState();\n    }\n\n    updatePairedSlideClasses() {\n        this.slides.forEach((slide, index) => {\n            const isLifestyleSlide = this.isLifestyleSlideIndex(index);\n            const isConfiguratorSlide = index === this.configuratorSlideIndex;\n            const isLastOddLifestyleSlide =\n                isLifestyleSlide &&\n                this.lifestyleSlideTotal % 2 === 1 &&\n                index === this.lastLifestyleIndex;\n\n            slide.classList.toggle(\n                pairedSlidesStartClass,\n                isConfiguratorSlide || (isLifestyleSlide && index % 2 === 0)\n            );\n            slide.classList.toggle(\n                pairedSlidesFullClass,\n                isConfiguratorSlide || isLastOddLifestyleSlide\n            );\n        });\n    }\n\n    /**\n     * Whether paired slides should use two-image desktop navigation.\n     *\n     * @returns {boolean}\n     */\n    hasPairedSlidesLayout() {\n        return (\n            this.hero.classList.contains(pairedSlidesHeroClass) &&\n            window.matchMedia(pairedSlidesViewportQuery).matches\n        );\n    }\n\n    isPairedSlidesMode() {\n        return this.isPairedSlidesActive;\n    }\n\n    isLifestyleSlideIndex(index) {\n        return index > -1 && index < this.lifestyleSlideTotal;\n    }\n\n    getLastNavigableLifestyleIndex() {\n        if (this.lifestyleSlideTotal <= 1) {\n            return 0;\n        }\n\n        return this.lifestyleSlideTotal % 2 === 0\n            ? this.lifestyleSlideTotal - 2\n            : this.lifestyleSlideTotal - 1;\n    }\n\n    getNavigableSlideIndex(index) {\n        if (\n            !this.isPairedSlidesMode() ||\n            index === this.configuratorSlideIndex ||\n            !this.isLifestyleSlideIndex(index)\n        ) {\n            return index;\n        }\n\n        const lastNavigableLifestyleIndex =\n            this.getLastNavigableLifestyleIndex();\n\n        if (index >= lastNavigableLifestyleIndex) {\n            return lastNavigableLifestyleIndex;\n        }\n\n        return index - (index % 2);\n    }\n\n    setupIntersectionObserver() {\n        const options = {\n            root: this.slidesContainer,\n            threshold: 0.95,\n            rootMargin: '0px',\n        };\n\n        this.observer = new IntersectionObserver(entries => {\n            entries.forEach(entry => {\n                if (entry.isIntersecting) {\n                    const slideIndex = this.slides.indexOf(entry.target);\n                    this.handleSlideChange(slideIndex);\n                }\n            });\n        }, options);\n\n        // Observe all slides\n        this.slides.forEach(slide => {\n            this.observer.observe(slide);\n        });\n    }\n\n    handleSlideChange(newIndex) {\n        newIndex = this.getNavigableSlideIndex(newIndex);\n\n        const previousIndex = this.currentIndex;\n        this.currentIndex = newIndex;\n\n        this.updateCounter();\n\n        // Update button states\n        this.updateButtonStates();\n\n        this.isLastSlide = this.currentIndex === this.totalSlides - 1;\n        this.hero.classList.toggle(\n            'configurator-hero--configurator-preview',\n            this.isLastSlide\n        );\n        this.syncConfiguratorSlideState();\n\n        const header = this.hero.querySelector('.configurator-hero__header');\n        const isCutout = this.slides[this.currentIndex].classList.contains(\n            'configurator-hero__slide--cutout'\n        );\n        if (header) {\n            header.classList.toggle(\n                'configurator-hero__header--cutout',\n                isCutout\n            );\n        }\n\n        // Dispatch general slide change event\n        this.slider.dispatchEvent(\n            new CustomEvent('slideChange', {\n                detail: {\n                    currentIndex: this.currentIndex,\n                    previousIndex: previousIndex,\n                    isLastSlide: this.isLastSlide,\n                    slide: this.slides[this.currentIndex],\n                },\n            })\n        );\n    }\n\n    dispatchConfiguratorEvent(action) {\n        this.slider.dispatchEvent(\n            new CustomEvent('configuratorSlide', {\n                detail: {\n                    action: action, // 'enter' or 'leave'\n                    slideIndex: this.currentIndex,\n                },\n            })\n        );\n\n        // Toggle configurator-visible class on the top-level hero element\n        if (this.hero) {\n            this.hero.classList.toggle(\n                'configurator-hero--configurator-visible',\n                action === 'enter'\n            );\n\n            document\n                .querySelector('[data-configurator-options]')\n                ?.classList.toggle(\n                    'configurator-options--visible',\n                    action === 'enter'\n                );\n        }\n\n        // Update parent wrapper state attribute for configurationBar & dynamicConfigBar\n        const wrapper = document.querySelector('[data-configurator-state]');\n        if (wrapper) {\n            wrapper.setAttribute(\n                'data-configurator-state',\n                action === 'enter' ? 'on-configurator' : 'exploring'\n            );\n        }\n    }\n\n    setupConfiguratorStateSync() {\n        this._handleConfiguratorStateScroll = () => {\n            if (this.configuratorStateFrame) {\n                return;\n            }\n\n            this.configuratorStateFrame = window.requestAnimationFrame(() => {\n                this.configuratorStateFrame = null;\n                this.syncConfiguratorSlideState();\n            });\n        };\n\n        this.slidesContainer.addEventListener(\n            'scroll',\n            this._handleConfiguratorStateScroll,\n            { passive: true }\n        );\n    }\n\n    syncConfiguratorSlideState() {\n        const configuratorSlide = this.getConfiguratorSlide();\n\n        if (!configuratorSlide) {\n            return;\n        }\n\n        const shouldBeActive = this.isConfiguratorSlideSnapped();\n\n        if (shouldBeActive === this.isConfiguratorSlideActive) {\n            return;\n        }\n\n        this.isConfiguratorSlideActive = shouldBeActive;\n        this.dispatchConfiguratorEvent(shouldBeActive ? 'enter' : 'leave');\n    }\n\n    /**\n     * Checks the displayed hero counter so panel visibility follows the slide\n     * state visible to the customer.\n     *\n     * @returns {boolean}\n     */\n    isDisplayedLastSlide() {\n        if (!this.currentCounter || !this.totalCounter) {\n            return this.isLastSlide;\n        }\n\n        return (\n            this.currentCounter.textContent.trim() ===\n            this.totalCounter.textContent.trim()\n        );\n    }\n\n    /**\n     * Returns true once the configurator slide is aligned in the scroll-snap\n     * container, not merely mostly visible.\n     *\n     * @returns {boolean}\n     */\n    isConfiguratorSlideSnapped() {\n        const configuratorSlide = this.getConfiguratorSlide();\n\n        if (!configuratorSlide) {\n            return false;\n        }\n\n        return (\n            Math.abs(\n                this.slidesContainer.scrollLeft - configuratorSlide.offsetLeft\n            ) <= 2\n        );\n    }\n\n    setupNavigation() {\n        this._handlePrev = () => this.goToPrevSlide();\n        this._handleNext = () => this.goToNextSlide();\n\n        if (this.prevButton) {\n            this.prevButton.addEventListener('click', this._handlePrev);\n        }\n\n        if (this.nextButton) {\n            this.nextButton.addEventListener('click', this._handleNext);\n        }\n\n        // Optional: Keyboard navigation\n        this.slider.addEventListener('keydown', e => {\n            if (e.key === 'ArrowLeft') {\n                this.goToPrevSlide();\n            } else if (e.key === 'ArrowRight') {\n                this.goToNextSlide();\n            }\n        });\n    }\n\n    setupCylindoZoomListener() {\n        this.cylindoViewer = this.slider.querySelector('[data-360-viewer]');\n\n        if (!this.cylindoViewer) {\n            return;\n        }\n\n        this._handleCylindoZoomChange = event => {\n            const eventZoom = Number.parseFloat(\n                event.detail?.zoom ?? event.detail\n            );\n            const viewerZoom = Number.parseFloat(this.cylindoViewer.zoom ?? 1);\n            const zoom = Number.isFinite(eventZoom) ? eventZoom : viewerZoom;\n            const isZoomed = zoom > 1;\n\n            if (isZoomed === this.isCylindoZoomed) {\n                return;\n            }\n\n            this.isCylindoZoomed = isZoomed;\n            this.slider.toggleAttribute('data-zoomed', isZoomed);\n        };\n\n        this.cylindoViewer.addEventListener(\n            'zoom-change',\n            this._handleCylindoZoomChange\n        );\n    }\n\n    setupCylindoZoomControls() {\n        this.cylindoZoomControls = new CylindoZoomControls(this.slider);\n    }\n\n    setupCylindoInteractionLock() {\n        const viewer = this.slider.querySelector('[data-360-viewer]');\n\n        if (!viewer) {\n            return;\n        }\n\n        const lock = () => {\n            window.clearTimeout(this.cylindoInteractionReleaseTimeout);\n            this.slidesContainer.classList.add(\n                configuratorViewerInteractingClass\n            );\n        };\n\n        const release = () => {\n            window.clearTimeout(this.cylindoInteractionReleaseTimeout);\n            this.cylindoInteractionReleaseTimeout = window.setTimeout(() => {\n                this.slidesContainer.classList.remove(\n                    configuratorViewerInteractingClass\n                );\n                this.syncConfiguratorSlideState();\n            }, 120);\n        };\n\n        this._handleCylindoInteractionStart = lock;\n        this._handleCylindoInteractionEnd = release;\n\n        viewer.addEventListener('pointerdown', lock, { passive: true });\n        viewer.addEventListener('touchstart', lock, { passive: true });\n        viewer.addEventListener('mousedown', lock);\n\n        window.addEventListener('pointerup', release, { passive: true });\n        window.addEventListener('pointercancel', release, { passive: true });\n        window.addEventListener('touchend', release, { passive: true });\n        window.addEventListener('touchcancel', release, { passive: true });\n        window.addEventListener('mouseup', release);\n    }\n\n    goToPrevSlide() {\n        const previousIndex = this.getPreviousSlideIndex();\n\n        if (previousIndex !== null) {\n            this.scrollToSlide(previousIndex);\n        }\n    }\n\n    goToNextSlide() {\n        const nextIndex = this.getNextSlideIndex();\n\n        if (nextIndex !== null) {\n            this.scrollToSlide(nextIndex);\n        }\n    }\n\n    getPreviousSlideIndex() {\n        if (!this.isPairedSlidesMode()) {\n            return this.currentIndex > 0 ? this.currentIndex - 1 : null;\n        }\n\n        if (this.currentIndex <= 0) {\n            return null;\n        }\n\n        if (this.currentIndex === this.configuratorSlideIndex) {\n            const lastNavigableLifestyleIndex =\n                this.getLastNavigableLifestyleIndex();\n\n            return lastNavigableLifestyleIndex === this.currentIndex\n                ? null\n                : lastNavigableLifestyleIndex;\n        }\n\n        return Math.max(this.currentIndex - 2, 0);\n    }\n\n    getNextSlideIndex() {\n        if (!this.isPairedSlidesMode()) {\n            return this.currentIndex < this.totalSlides - 1\n                ? this.currentIndex + 1\n                : null;\n        }\n\n        if (this.currentIndex === this.configuratorSlideIndex) {\n            return null;\n        }\n\n        const lastNavigableLifestyleIndex =\n            this.getLastNavigableLifestyleIndex();\n\n        if (this.currentIndex >= lastNavigableLifestyleIndex) {\n            return this.hasConfiguratorSlide()\n                ? this.configuratorSlideIndex\n                : null;\n        }\n\n        return Math.min(this.currentIndex + 2, lastNavigableLifestyleIndex);\n    }\n\n    scrollToSlide(index, instant = false) {\n        index = this.getNavigableSlideIndex(index);\n\n        if (index < 0 || index >= this.totalSlides) {\n            return;\n        }\n\n        if (\n            !instant &&\n            index === this.configuratorSlideIndex &&\n            index !== this.currentIndex\n        ) {\n            this.fadeToSlide(index);\n\n            return;\n        }\n\n        this.scrollSlideIntoPosition(index, instant);\n    }\n\n    /**\n     * Fades the slider while moving to a slide.\n     *\n     * @param {number} index\n     */\n    fadeToSlide(index) {\n        window.clearTimeout(this.configuratorSlideFadeTimeout);\n        this.slider.classList.add(configuratorSlideFadeClass);\n\n        this.configuratorSlideFadeTimeout = window.setTimeout(() => {\n            this.configuratorSlideFadeTimeout = null;\n            this.scrollSlideIntoPosition(index, true);\n            this.handleSlideChange(index);\n\n            window.requestAnimationFrame(() => {\n                this.slider.classList.remove(configuratorSlideFadeClass);\n            });\n        }, configuratorSlideFadeDuration);\n    }\n\n    /**\n     * Moves the slide container horizontally without changing page scroll.\n     *\n     * @param {number} index\n     * @param {boolean} instant\n     */\n    scrollSlideIntoPosition(index, instant = false) {\n        const slide = this.slides[index];\n\n        if (!slide) {\n            return;\n        }\n\n        if (instant) {\n            const currentScrollBehavior =\n                this.slidesContainer.style.scrollBehavior;\n\n            this.slidesContainer.style.scrollBehavior = 'auto';\n            this.slidesContainer.scrollTo({\n                left: slide.offsetLeft,\n                top: this.slidesContainer.scrollTop,\n                behavior: 'auto',\n            });\n            this.slidesContainer.style.scrollBehavior = currentScrollBehavior;\n\n            return;\n        }\n\n        this.slidesContainer.scrollTo({\n            left: slide.offsetLeft,\n            top: this.slidesContainer.scrollTop,\n            behavior: 'smooth',\n        });\n    }\n\n    updateButtonStates() {\n        if (this.prevButton) {\n            this.prevButton.disabled = this.getPreviousSlideIndex() === null;\n        }\n\n        if (this.nextButton) {\n            this.nextButton.disabled = this.getNextSlideIndex() === null;\n        }\n    }\n\n    updateCounter() {\n        if (this.currentCounter) {\n            this.currentCounter.textContent = this.getDisplayedSlideIndex();\n        }\n\n        if (this.totalCounter) {\n            this.totalCounter.textContent = this.getDisplayedSlideTotal();\n        }\n    }\n\n    getDisplayedSlideIndex() {\n        if (!this.isPairedSlidesMode()) {\n            return this.currentIndex + 1;\n        }\n\n        if (this.currentIndex === this.configuratorSlideIndex) {\n            return this.getDisplayedSlideTotal();\n        }\n\n        return Math.floor(this.currentIndex / 2) + 1;\n    }\n\n    getDisplayedSlideTotal() {\n        if (!this.isPairedSlidesMode()) {\n            return this.totalSlides;\n        }\n\n        const lifestyleSlideTotal = Math.ceil(this.lifestyleSlideTotal / 2);\n\n        return lifestyleSlideTotal + (this.hasConfiguratorSlide() ? 1 : 0);\n    }\n\n    hasConfiguratorSlide() {\n        return this.configuratorSlideIndex > -1;\n    }\n\n    getConfiguratorSlide() {\n        return this.hasConfiguratorSlide()\n            ? this.slides[this.configuratorSlideIndex]\n            : null;\n    }\n\n    // Public method to go to a specific slide\n    goToSlide(index, instant = false) {\n        this.scrollToSlide(index, instant);\n    }\n\n    // Public method to get current state\n    getState() {\n        return {\n            currentIndex: this.currentIndex,\n            totalSlides: this.totalSlides,\n            isLastSlide: this.isLastSlide,\n        };\n    }\n\n    // Cleanup\n    destroy() {\n        this.observer.disconnect();\n\n        if (this.prevButton) {\n            this.prevButton.removeEventListener('click', this._handlePrev);\n        }\n\n        if (this.nextButton) {\n            this.nextButton.removeEventListener('click', this._handleNext);\n        }\n\n        if (this._handleConfiguratorStateScroll) {\n            this.slidesContainer.removeEventListener(\n                'scroll',\n                this._handleConfiguratorStateScroll\n            );\n        }\n\n        if (this.configuratorStateFrame) {\n            window.cancelAnimationFrame(this.configuratorStateFrame);\n        }\n\n        window.clearTimeout(this.cylindoInteractionReleaseTimeout);\n        window.clearTimeout(this.configuratorSlideFadeTimeout);\n        this.slider.classList.remove(configuratorSlideFadeClass);\n        this.slidesContainer.classList.remove(\n            configuratorViewerInteractingClass\n        );\n\n        if (this._handlePairedSlidesResize) {\n            window.removeEventListener(\n                'resize',\n                this._handlePairedSlidesResize\n            );\n            window.visualViewport?.removeEventListener(\n                'resize',\n                this._handlePairedSlidesResize\n            );\n        }\n\n        if (this.pairedSlidesResizeFrame) {\n            window.cancelAnimationFrame(this.pairedSlidesResizeFrame);\n        }\n\n        if (this.cylindoViewer && this._handleCylindoZoomChange) {\n            this.cylindoViewer.removeEventListener(\n                'zoom-change',\n                this._handleCylindoZoomChange\n            );\n        }\n\n        const viewer = this.slider.querySelector('[data-360-viewer]');\n        if (\n            viewer &&\n            this._handleCylindoInteractionStart &&\n            this._handleCylindoInteractionEnd\n        ) {\n            viewer.removeEventListener(\n                'pointerdown',\n                this._handleCylindoInteractionStart\n            );\n            viewer.removeEventListener(\n                'touchstart',\n                this._handleCylindoInteractionStart\n            );\n            viewer.removeEventListener(\n                'mousedown',\n                this._handleCylindoInteractionStart\n            );\n\n            window.removeEventListener(\n                'pointerup',\n                this._handleCylindoInteractionEnd\n            );\n            window.removeEventListener(\n                'pointercancel',\n                this._handleCylindoInteractionEnd\n            );\n            window.removeEventListener(\n                'touchend',\n                this._handleCylindoInteractionEnd\n            );\n            window.removeEventListener(\n                'touchcancel',\n                this._handleCylindoInteractionEnd\n            );\n            window.removeEventListener(\n                'mouseup',\n                this._handleCylindoInteractionEnd\n            );\n        }\n\n        this.cylindoZoomControls?.destroy();\n        this.slider.removeAttribute('data-zoomed');\n    }\n}\n","/*!\n  * PhotoSwipe Lightbox 5.4.4 - https://photoswipe.com\n  * (c) 2024 Dmytro Semenov\n  */\n/** @typedef {import('../photoswipe.js').Point} Point */\n\n/**\r\n * @template {keyof HTMLElementTagNameMap} T\r\n * @param {string} className\r\n * @param {T} tagName\r\n * @param {Node} [appendToEl]\r\n * @returns {HTMLElementTagNameMap[T]}\r\n */\nfunction createElement(className, tagName, appendToEl) {\n  const el = document.createElement(tagName);\n\n  if (className) {\n    el.className = className;\n  }\n\n  if (appendToEl) {\n    appendToEl.appendChild(el);\n  }\n\n  return el;\n}\n/**\r\n * Get transform string\r\n *\r\n * @param {number} x\r\n * @param {number} [y]\r\n * @param {number} [scale]\r\n * @returns {string}\r\n */\n\nfunction toTransformString(x, y, scale) {\n  let propValue = `translate3d(${x}px,${y || 0}px,0)`;\n\n  if (scale !== undefined) {\n    propValue += ` scale3d(${scale},${scale},1)`;\n  }\n\n  return propValue;\n}\n/**\r\n * Apply width and height CSS properties to element\r\n *\r\n * @param {HTMLElement} el\r\n * @param {string | number} w\r\n * @param {string | number} h\r\n */\n\nfunction setWidthHeight(el, w, h) {\n  el.style.width = typeof w === 'number' ? `${w}px` : w;\n  el.style.height = typeof h === 'number' ? `${h}px` : h;\n}\n/** @typedef {LOAD_STATE[keyof LOAD_STATE]} LoadState */\n\n/** @type {{ IDLE: 'idle'; LOADING: 'loading'; LOADED: 'loaded'; ERROR: 'error' }} */\n\nconst LOAD_STATE = {\n  IDLE: 'idle',\n  LOADING: 'loading',\n  LOADED: 'loaded',\n  ERROR: 'error'\n};\n/**\r\n * Check if click or keydown event was dispatched\r\n * with a special key or via mouse wheel.\r\n *\r\n * @param {MouseEvent | KeyboardEvent} e\r\n * @returns {boolean}\r\n */\n\nfunction specialKeyUsed(e) {\n  return 'button' in e && e.button === 1 || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey;\n}\n/**\r\n * Parse `gallery` or `children` options.\r\n *\r\n * @param {import('../photoswipe.js').ElementProvider} [option]\r\n * @param {string} [legacySelector]\r\n * @param {HTMLElement | Document} [parent]\r\n * @returns HTMLElement[]\r\n */\n\nfunction getElementsFromOption(option, legacySelector, parent = document) {\n  /** @type {HTMLElement[]} */\n  let elements = [];\n\n  if (option instanceof Element) {\n    elements = [option];\n  } else if (option instanceof NodeList || Array.isArray(option)) {\n    elements = Array.from(option);\n  } else {\n    const selector = typeof option === 'string' ? option : legacySelector;\n\n    if (selector) {\n      elements = Array.from(parent.querySelectorAll(selector));\n    }\n  }\n\n  return elements;\n}\n/**\r\n * Check if variable is PhotoSwipe class\r\n *\r\n * @param {any} fn\r\n * @returns {boolean}\r\n */\n\nfunction isPswpClass(fn) {\n  return typeof fn === 'function' && fn.prototype && fn.prototype.goTo;\n}\n/**\r\n * Check if browser is Safari\r\n *\r\n * @returns {boolean}\r\n */\n\nfunction isSafari() {\n  return !!(navigator.vendor && navigator.vendor.match(/apple/i));\n}\n\n/** @typedef {import('../lightbox/lightbox.js').default} PhotoSwipeLightbox */\n\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\n\n/** @typedef {import('../photoswipe.js').DataSource} DataSource */\n\n/** @typedef {import('../ui/ui-element.js').UIElementData} UIElementData */\n\n/** @typedef {import('../slide/content.js').default} ContentDefault */\n\n/** @typedef {import('../slide/slide.js').default} Slide */\n\n/** @typedef {import('../slide/slide.js').SlideData} SlideData */\n\n/** @typedef {import('../slide/zoom-level.js').default} ZoomLevel */\n\n/** @typedef {import('../slide/get-thumb-bounds.js').Bounds} Bounds */\n\n/**\r\n * Allow adding an arbitrary props to the Content\r\n * https://photoswipe.com/custom-content/#using-webp-image-format\r\n * @typedef {ContentDefault & Record<string, any>} Content\r\n */\n\n/** @typedef {{ x?: number; y?: number }} Point */\n\n/**\r\n * @typedef {Object} PhotoSwipeEventsMap https://photoswipe.com/events/\r\n *\r\n *\r\n * https://photoswipe.com/adding-ui-elements/\r\n *\r\n * @prop {undefined} uiRegister\r\n * @prop {{ data: UIElementData }} uiElementCreate\r\n *\r\n *\r\n * https://photoswipe.com/events/#initialization-events\r\n *\r\n * @prop {undefined} beforeOpen\r\n * @prop {undefined} firstUpdate\r\n * @prop {undefined} initialLayout\r\n * @prop {undefined} change\r\n * @prop {undefined} afterInit\r\n * @prop {undefined} bindEvents\r\n *\r\n *\r\n * https://photoswipe.com/events/#opening-or-closing-transition-events\r\n *\r\n * @prop {undefined} openingAnimationStart\r\n * @prop {undefined} openingAnimationEnd\r\n * @prop {undefined} closingAnimationStart\r\n * @prop {undefined} closingAnimationEnd\r\n *\r\n *\r\n * https://photoswipe.com/events/#closing-events\r\n *\r\n * @prop {undefined} close\r\n * @prop {undefined} destroy\r\n *\r\n *\r\n * https://photoswipe.com/events/#pointer-and-gesture-events\r\n *\r\n * @prop {{ originalEvent: PointerEvent }} pointerDown\r\n * @prop {{ originalEvent: PointerEvent }} pointerMove\r\n * @prop {{ originalEvent: PointerEvent }} pointerUp\r\n * @prop {{ bgOpacity: number }} pinchClose can be default prevented\r\n * @prop {{ panY: number }} verticalDrag can be default prevented\r\n *\r\n *\r\n * https://photoswipe.com/events/#slide-content-events\r\n *\r\n * @prop {{ content: Content }} contentInit\r\n * @prop {{ content: Content; isLazy: boolean }} contentLoad can be default prevented\r\n * @prop {{ content: Content; isLazy: boolean }} contentLoadImage can be default prevented\r\n * @prop {{ content: Content; slide: Slide; isError?: boolean }} loadComplete\r\n * @prop {{ content: Content; slide: Slide }} loadError\r\n * @prop {{ content: Content; width: number; height: number }} contentResize can be default prevented\r\n * @prop {{ content: Content; width: number; height: number; slide: Slide }} imageSizeChange\r\n * @prop {{ content: Content }} contentLazyLoad can be default prevented\r\n * @prop {{ content: Content }} contentAppend can be default prevented\r\n * @prop {{ content: Content }} contentActivate can be default prevented\r\n * @prop {{ content: Content }} contentDeactivate can be default prevented\r\n * @prop {{ content: Content }} contentRemove can be default prevented\r\n * @prop {{ content: Content }} contentDestroy can be default prevented\r\n *\r\n *\r\n * undocumented\r\n *\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} imageClickAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} bgClickAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} tapAction can be default prevented\r\n * @prop {{ point: Point; originalEvent: PointerEvent }} doubleTapAction can be default prevented\r\n *\r\n * @prop {{ originalEvent: KeyboardEvent }} keydown can be default prevented\r\n * @prop {{ x: number; dragging: boolean }} moveMainScroll\r\n * @prop {{ slide: Slide }} firstZoomPan\r\n * @prop {{ slide: Slide | undefined, data: SlideData, index: number }} gettingData\r\n * @prop {undefined} beforeResize\r\n * @prop {undefined} resize\r\n * @prop {undefined} viewportSize\r\n * @prop {undefined} updateScrollOffset\r\n * @prop {{ slide: Slide }} slideInit\r\n * @prop {{ slide: Slide }} afterSetContent\r\n * @prop {{ slide: Slide }} slideLoad\r\n * @prop {{ slide: Slide }} appendHeavy can be default prevented\r\n * @prop {{ slide: Slide }} appendHeavyContent\r\n * @prop {{ slide: Slide }} slideActivate\r\n * @prop {{ slide: Slide }} slideDeactivate\r\n * @prop {{ slide: Slide }} slideDestroy\r\n * @prop {{ destZoomLevel: number, centerPoint: Point | undefined, transitionDuration: number | false | undefined }} beforeZoomTo\r\n * @prop {{ slide: Slide }} zoomPanUpdate\r\n * @prop {{ slide: Slide }} initialZoomPan\r\n * @prop {{ slide: Slide }} calcSlideSize\r\n * @prop {undefined} resolutionChanged\r\n * @prop {{ originalEvent: WheelEvent }} wheel can be default prevented\r\n * @prop {{ content: Content }} contentAppendImage can be default prevented\r\n * @prop {{ index: number; itemData: SlideData }} lazyLoadSlide can be default prevented\r\n * @prop {undefined} lazyLoad\r\n * @prop {{ slide: Slide }} calcBounds\r\n * @prop {{ zoomLevels: ZoomLevel, slideData: SlideData }} zoomLevelsUpdate\r\n *\r\n *\r\n * legacy\r\n *\r\n * @prop {undefined} init\r\n * @prop {undefined} initialZoomIn\r\n * @prop {undefined} initialZoomOut\r\n * @prop {undefined} initialZoomInEnd\r\n * @prop {undefined} initialZoomOutEnd\r\n * @prop {{ dataSource: DataSource | undefined, numItems: number }} numItems\r\n * @prop {{ itemData: SlideData; index: number }} itemData\r\n * @prop {{ index: number, itemData: SlideData, instance: PhotoSwipe }} thumbBounds\r\n */\n\n/**\r\n * @typedef {Object} PhotoSwipeFiltersMap https://photoswipe.com/filters/\r\n *\r\n * @prop {(numItems: number, dataSource: DataSource | undefined) => number} numItems\r\n * Modify the total amount of slides. Example on Data sources page.\r\n * https://photoswipe.com/filters/#numitems\r\n *\r\n * @prop {(itemData: SlideData, index: number) => SlideData} itemData\r\n * Modify slide item data. Example on Data sources page.\r\n * https://photoswipe.com/filters/#itemdata\r\n *\r\n * @prop {(itemData: SlideData, element: HTMLElement, linkEl: HTMLAnchorElement) => SlideData} domItemData\r\n * Modify item data when it's parsed from DOM element. Example on Data sources page.\r\n * https://photoswipe.com/filters/#domitemdata\r\n *\r\n * @prop {(clickedIndex: number, e: MouseEvent, instance: PhotoSwipeLightbox) => number} clickedIndex\r\n * Modify clicked gallery item index.\r\n * https://photoswipe.com/filters/#clickedindex\r\n *\r\n * @prop {(placeholderSrc: string | false, content: Content) => string | false} placeholderSrc\r\n * Modify placeholder image source.\r\n * https://photoswipe.com/filters/#placeholdersrc\r\n *\r\n * @prop {(isContentLoading: boolean, content: Content) => boolean} isContentLoading\r\n * Modify if the content is currently loading.\r\n * https://photoswipe.com/filters/#iscontentloading\r\n *\r\n * @prop {(isContentZoomable: boolean, content: Content) => boolean} isContentZoomable\r\n * Modify if the content can be zoomed.\r\n * https://photoswipe.com/filters/#iscontentzoomable\r\n *\r\n * @prop {(useContentPlaceholder: boolean, content: Content) => boolean} useContentPlaceholder\r\n * Modify if the placeholder should be used for the content.\r\n * https://photoswipe.com/filters/#usecontentplaceholder\r\n *\r\n * @prop {(isKeepingPlaceholder: boolean, content: Content) => boolean} isKeepingPlaceholder\r\n * Modify if the placeholder should be kept after the content is loaded.\r\n * https://photoswipe.com/filters/#iskeepingplaceholder\r\n *\r\n *\r\n * @prop {(contentErrorElement: HTMLElement, content: Content) => HTMLElement} contentErrorElement\r\n * Modify an element when the content has error state (for example, if image cannot be loaded).\r\n * https://photoswipe.com/filters/#contenterrorelement\r\n *\r\n * @prop {(element: HTMLElement, data: UIElementData) => HTMLElement} uiElement\r\n * Modify a UI element that's being created.\r\n * https://photoswipe.com/filters/#uielement\r\n *\r\n * @prop {(thumbnail: HTMLElement | null | undefined, itemData: SlideData, index: number) => HTMLElement} thumbEl\r\n * Modify the thumbnail element from which opening zoom animation starts or ends.\r\n * https://photoswipe.com/filters/#thumbel\r\n *\r\n * @prop {(thumbBounds: Bounds | undefined, itemData: SlideData, index: number) => Bounds} thumbBounds\r\n * Modify the thumbnail bounds from which opening zoom animation starts or ends.\r\n * https://photoswipe.com/filters/#thumbbounds\r\n *\r\n * @prop {(srcsetSizesWidth: number, content: Content) => number} srcsetSizesWidth\r\n *\r\n * @prop {(preventPointerEvent: boolean, event: PointerEvent, pointerType: string) => boolean} preventPointerEvent\r\n *\r\n */\n\n/**\r\n * @template {keyof PhotoSwipeFiltersMap} T\r\n * @typedef {{ fn: PhotoSwipeFiltersMap[T], priority: number }} Filter\r\n */\n\n/**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {PhotoSwipeEventsMap[T] extends undefined ? PhotoSwipeEvent<T> : PhotoSwipeEvent<T> & PhotoSwipeEventsMap[T]} AugmentedEvent\r\n */\n\n/**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {(event: AugmentedEvent<T>) => void} EventCallback\r\n */\n\n/**\r\n * Base PhotoSwipe event object\r\n *\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n */\nclass PhotoSwipeEvent {\n  /**\r\n   * @param {T} type\r\n   * @param {PhotoSwipeEventsMap[T]} [details]\r\n   */\n  constructor(type, details) {\n    this.type = type;\n    this.defaultPrevented = false;\n\n    if (details) {\n      Object.assign(this, details);\n    }\n  }\n\n  preventDefault() {\n    this.defaultPrevented = true;\n  }\n\n}\n/**\r\n * PhotoSwipe base class that can listen and dispatch for events.\r\n * Shared by PhotoSwipe Core and PhotoSwipe Lightbox, extended by base.js\r\n */\n\n\nclass Eventable {\n  constructor() {\n    /**\r\n     * @type {{ [T in keyof PhotoSwipeEventsMap]?: ((event: AugmentedEvent<T>) => void)[] }}\r\n     */\n    this._listeners = {};\n    /**\r\n     * @type {{ [T in keyof PhotoSwipeFiltersMap]?: Filter<T>[] }}\r\n     */\n\n    this._filters = {};\n    /** @type {PhotoSwipe | undefined} */\n\n    this.pswp = undefined;\n    /** @type {PhotoSwipeOptions | undefined} */\n\n    this.options = undefined;\n  }\n  /**\r\n   * @template {keyof PhotoSwipeFiltersMap} T\r\n   * @param {T} name\r\n   * @param {PhotoSwipeFiltersMap[T]} fn\r\n   * @param {number} priority\r\n   */\n\n\n  addFilter(name, fn, priority = 100) {\n    var _this$_filters$name, _this$_filters$name2, _this$pswp;\n\n    if (!this._filters[name]) {\n      this._filters[name] = [];\n    }\n\n    (_this$_filters$name = this._filters[name]) === null || _this$_filters$name === void 0 || _this$_filters$name.push({\n      fn,\n      priority\n    });\n    (_this$_filters$name2 = this._filters[name]) === null || _this$_filters$name2 === void 0 || _this$_filters$name2.sort((f1, f2) => f1.priority - f2.priority);\n    (_this$pswp = this.pswp) === null || _this$pswp === void 0 || _this$pswp.addFilter(name, fn, priority);\n  }\n  /**\r\n   * @template {keyof PhotoSwipeFiltersMap} T\r\n   * @param {T} name\r\n   * @param {PhotoSwipeFiltersMap[T]} fn\r\n   */\n\n\n  removeFilter(name, fn) {\n    if (this._filters[name]) {\n      // @ts-expect-error\n      this._filters[name] = this._filters[name].filter(filter => filter.fn !== fn);\n    }\n\n    if (this.pswp) {\n      this.pswp.removeFilter(name, fn);\n    }\n  }\n  /**\r\n   * @template {keyof PhotoSwipeFiltersMap} T\r\n   * @param {T} name\r\n   * @param {Parameters<PhotoSwipeFiltersMap[T]>} args\r\n   * @returns {Parameters<PhotoSwipeFiltersMap[T]>[0]}\r\n   */\n\n\n  applyFilters(name, ...args) {\n    var _this$_filters$name3;\n\n    (_this$_filters$name3 = this._filters[name]) === null || _this$_filters$name3 === void 0 || _this$_filters$name3.forEach(filter => {\n      // @ts-expect-error\n      args[0] = filter.fn.apply(this, args);\n    });\n    return args[0];\n  }\n  /**\r\n   * @template {keyof PhotoSwipeEventsMap} T\r\n   * @param {T} name\r\n   * @param {EventCallback<T>} fn\r\n   */\n\n\n  on(name, fn) {\n    var _this$_listeners$name, _this$pswp2;\n\n    if (!this._listeners[name]) {\n      this._listeners[name] = [];\n    }\n\n    (_this$_listeners$name = this._listeners[name]) === null || _this$_listeners$name === void 0 || _this$_listeners$name.push(fn); // When binding events to lightbox,\n    // also bind events to PhotoSwipe Core,\n    // if it's open.\n\n    (_this$pswp2 = this.pswp) === null || _this$pswp2 === void 0 || _this$pswp2.on(name, fn);\n  }\n  /**\r\n   * @template {keyof PhotoSwipeEventsMap} T\r\n   * @param {T} name\r\n   * @param {EventCallback<T>} fn\r\n   */\n\n\n  off(name, fn) {\n    var _this$pswp3;\n\n    if (this._listeners[name]) {\n      // @ts-expect-error\n      this._listeners[name] = this._listeners[name].filter(listener => fn !== listener);\n    }\n\n    (_this$pswp3 = this.pswp) === null || _this$pswp3 === void 0 || _this$pswp3.off(name, fn);\n  }\n  /**\r\n   * @template {keyof PhotoSwipeEventsMap} T\r\n   * @param {T} name\r\n   * @param {PhotoSwipeEventsMap[T]} [details]\r\n   * @returns {AugmentedEvent<T>}\r\n   */\n\n\n  dispatch(name, details) {\n    var _this$_listeners$name2;\n\n    if (this.pswp) {\n      return this.pswp.dispatch(name, details);\n    }\n\n    const event =\n    /** @type {AugmentedEvent<T>} */\n    new PhotoSwipeEvent(name, details);\n    (_this$_listeners$name2 = this._listeners[name]) === null || _this$_listeners$name2 === void 0 || _this$_listeners$name2.forEach(listener => {\n      listener.call(this, event);\n    });\n    return event;\n  }\n\n}\n\nclass Placeholder {\n  /**\r\n   * @param {string | false} imageSrc\r\n   * @param {HTMLElement} container\r\n   */\n  constructor(imageSrc, container) {\n    // Create placeholder\n    // (stretched thumbnail or simple div behind the main image)\n\n    /** @type {HTMLImageElement | HTMLDivElement | null} */\n    this.element = createElement('pswp__img pswp__img--placeholder', imageSrc ? 'img' : 'div', container);\n\n    if (imageSrc) {\n      const imgEl =\n      /** @type {HTMLImageElement} */\n      this.element;\n      imgEl.decoding = 'async';\n      imgEl.alt = '';\n      imgEl.src = imageSrc;\n      imgEl.setAttribute('role', 'presentation');\n    }\n\n    this.element.setAttribute('aria-hidden', 'true');\n  }\n  /**\r\n   * @param {number} width\r\n   * @param {number} height\r\n   */\n\n\n  setDisplayedSize(width, height) {\n    if (!this.element) {\n      return;\n    }\n\n    if (this.element.tagName === 'IMG') {\n      // Use transform scale() to modify img placeholder size\n      // (instead of changing width/height directly).\n      // This helps with performance, specifically in iOS15 Safari.\n      setWidthHeight(this.element, 250, 'auto');\n      this.element.style.transformOrigin = '0 0';\n      this.element.style.transform = toTransformString(0, 0, width / 250);\n    } else {\n      setWidthHeight(this.element, width, height);\n    }\n  }\n\n  destroy() {\n    var _this$element;\n\n    if ((_this$element = this.element) !== null && _this$element !== void 0 && _this$element.parentNode) {\n      this.element.remove();\n    }\n\n    this.element = null;\n  }\n\n}\n\n/** @typedef {import('./slide.js').default} Slide */\n\n/** @typedef {import('./slide.js').SlideData} SlideData */\n\n/** @typedef {import('../core/base.js').default} PhotoSwipeBase */\n\n/** @typedef {import('../util/util.js').LoadState} LoadState */\n\nclass Content {\n  /**\r\n   * @param {SlideData} itemData Slide data\r\n   * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance\r\n   * @param {number} index\r\n   */\n  constructor(itemData, instance, index) {\n    this.instance = instance;\n    this.data = itemData;\n    this.index = index;\n    /** @type {HTMLImageElement | HTMLDivElement | undefined} */\n\n    this.element = undefined;\n    /** @type {Placeholder | undefined} */\n\n    this.placeholder = undefined;\n    /** @type {Slide | undefined} */\n\n    this.slide = undefined;\n    this.displayedImageWidth = 0;\n    this.displayedImageHeight = 0;\n    this.width = Number(this.data.w) || Number(this.data.width) || 0;\n    this.height = Number(this.data.h) || Number(this.data.height) || 0;\n    this.isAttached = false;\n    this.hasSlide = false;\n    this.isDecoding = false;\n    /** @type {LoadState} */\n\n    this.state = LOAD_STATE.IDLE;\n\n    if (this.data.type) {\n      this.type = this.data.type;\n    } else if (this.data.src) {\n      this.type = 'image';\n    } else {\n      this.type = 'html';\n    }\n\n    this.instance.dispatch('contentInit', {\n      content: this\n    });\n  }\n\n  removePlaceholder() {\n    if (this.placeholder && !this.keepPlaceholder()) {\n      // With delay, as image might be loaded, but not rendered\n      setTimeout(() => {\n        if (this.placeholder) {\n          this.placeholder.destroy();\n          this.placeholder = undefined;\n        }\n      }, 1000);\n    }\n  }\n  /**\r\n   * Preload content\r\n   *\r\n   * @param {boolean} isLazy\r\n   * @param {boolean} [reload]\r\n   */\n\n\n  load(isLazy, reload) {\n    if (this.slide && this.usePlaceholder()) {\n      if (!this.placeholder) {\n        const placeholderSrc = this.instance.applyFilters('placeholderSrc', // use  image-based placeholder only for the first slide,\n        // as rendering (even small stretched thumbnail) is an expensive operation\n        this.data.msrc && this.slide.isFirstSlide ? this.data.msrc : false, this);\n        this.placeholder = new Placeholder(placeholderSrc, this.slide.container);\n      } else {\n        const placeholderEl = this.placeholder.element; // Add placeholder to DOM if it was already created\n\n        if (placeholderEl && !placeholderEl.parentElement) {\n          this.slide.container.prepend(placeholderEl);\n        }\n      }\n    }\n\n    if (this.element && !reload) {\n      return;\n    }\n\n    if (this.instance.dispatch('contentLoad', {\n      content: this,\n      isLazy\n    }).defaultPrevented) {\n      return;\n    }\n\n    if (this.isImageContent()) {\n      this.element = createElement('pswp__img', 'img'); // Start loading only after width is defined, as sizes might depend on it.\n      // Due to Safari feature, we must define sizes before srcset.\n\n      if (this.displayedImageWidth) {\n        this.loadImage(isLazy);\n      }\n    } else {\n      this.element = createElement('pswp__content', 'div');\n      this.element.innerHTML = this.data.html || '';\n    }\n\n    if (reload && this.slide) {\n      this.slide.updateContentSize(true);\n    }\n  }\n  /**\r\n   * Preload image\r\n   *\r\n   * @param {boolean} isLazy\r\n   */\n\n\n  loadImage(isLazy) {\n    var _this$data$src, _this$data$alt;\n\n    if (!this.isImageContent() || !this.element || this.instance.dispatch('contentLoadImage', {\n      content: this,\n      isLazy\n    }).defaultPrevented) {\n      return;\n    }\n\n    const imageElement =\n    /** @type HTMLImageElement */\n    this.element;\n    this.updateSrcsetSizes();\n\n    if (this.data.srcset) {\n      imageElement.srcset = this.data.srcset;\n    }\n\n    imageElement.src = (_this$data$src = this.data.src) !== null && _this$data$src !== void 0 ? _this$data$src : '';\n    imageElement.alt = (_this$data$alt = this.data.alt) !== null && _this$data$alt !== void 0 ? _this$data$alt : '';\n    this.state = LOAD_STATE.LOADING;\n\n    if (imageElement.complete) {\n      this.onLoaded();\n    } else {\n      imageElement.onload = () => {\n        this.onLoaded();\n      };\n\n      imageElement.onerror = () => {\n        this.onError();\n      };\n    }\n  }\n  /**\r\n   * Assign slide to content\r\n   *\r\n   * @param {Slide} slide\r\n   */\n\n\n  setSlide(slide) {\n    this.slide = slide;\n    this.hasSlide = true;\n    this.instance = slide.pswp; // todo: do we need to unset slide?\n  }\n  /**\r\n   * Content load success handler\r\n   */\n\n\n  onLoaded() {\n    this.state = LOAD_STATE.LOADED;\n\n    if (this.slide && this.element) {\n      this.instance.dispatch('loadComplete', {\n        slide: this.slide,\n        content: this\n      }); // if content is reloaded\n\n      if (this.slide.isActive && this.slide.heavyAppended && !this.element.parentNode) {\n        this.append();\n        this.slide.updateContentSize(true);\n      }\n\n      if (this.state === LOAD_STATE.LOADED || this.state === LOAD_STATE.ERROR) {\n        this.removePlaceholder();\n      }\n    }\n  }\n  /**\r\n   * Content load error handler\r\n   */\n\n\n  onError() {\n    this.state = LOAD_STATE.ERROR;\n\n    if (this.slide) {\n      this.displayError();\n      this.instance.dispatch('loadComplete', {\n        slide: this.slide,\n        isError: true,\n        content: this\n      });\n      this.instance.dispatch('loadError', {\n        slide: this.slide,\n        content: this\n      });\n    }\n  }\n  /**\r\n   * @returns {Boolean} If the content is currently loading\r\n   */\n\n\n  isLoading() {\n    return this.instance.applyFilters('isContentLoading', this.state === LOAD_STATE.LOADING, this);\n  }\n  /**\r\n   * @returns {Boolean} If the content is in error state\r\n   */\n\n\n  isError() {\n    return this.state === LOAD_STATE.ERROR;\n  }\n  /**\r\n   * @returns {boolean} If the content is image\r\n   */\n\n\n  isImageContent() {\n    return this.type === 'image';\n  }\n  /**\r\n   * Update content size\r\n   *\r\n   * @param {Number} width\r\n   * @param {Number} height\r\n   */\n\n\n  setDisplayedSize(width, height) {\n    if (!this.element) {\n      return;\n    }\n\n    if (this.placeholder) {\n      this.placeholder.setDisplayedSize(width, height);\n    }\n\n    if (this.instance.dispatch('contentResize', {\n      content: this,\n      width,\n      height\n    }).defaultPrevented) {\n      return;\n    }\n\n    setWidthHeight(this.element, width, height);\n\n    if (this.isImageContent() && !this.isError()) {\n      const isInitialSizeUpdate = !this.displayedImageWidth && width;\n      this.displayedImageWidth = width;\n      this.displayedImageHeight = height;\n\n      if (isInitialSizeUpdate) {\n        this.loadImage(false);\n      } else {\n        this.updateSrcsetSizes();\n      }\n\n      if (this.slide) {\n        this.instance.dispatch('imageSizeChange', {\n          slide: this.slide,\n          width,\n          height,\n          content: this\n        });\n      }\n    }\n  }\n  /**\r\n   * @returns {boolean} If the content can be zoomed\r\n   */\n\n\n  isZoomable() {\n    return this.instance.applyFilters('isContentZoomable', this.isImageContent() && this.state !== LOAD_STATE.ERROR, this);\n  }\n  /**\r\n   * Update image srcset sizes attribute based on width and height\r\n   */\n\n\n  updateSrcsetSizes() {\n    // Handle srcset sizes attribute.\n    //\n    // Never lower quality, if it was increased previously.\n    // Chrome does this automatically, Firefox and Safari do not,\n    // so we store largest used size in dataset.\n    if (!this.isImageContent() || !this.element || !this.data.srcset) {\n      return;\n    }\n\n    const image =\n    /** @type HTMLImageElement */\n    this.element;\n    const sizesWidth = this.instance.applyFilters('srcsetSizesWidth', this.displayedImageWidth, this);\n\n    if (!image.dataset.largestUsedSize || sizesWidth > parseInt(image.dataset.largestUsedSize, 10)) {\n      image.sizes = sizesWidth + 'px';\n      image.dataset.largestUsedSize = String(sizesWidth);\n    }\n  }\n  /**\r\n   * @returns {boolean} If content should use a placeholder (from msrc by default)\r\n   */\n\n\n  usePlaceholder() {\n    return this.instance.applyFilters('useContentPlaceholder', this.isImageContent(), this);\n  }\n  /**\r\n   * Preload content with lazy-loading param\r\n   */\n\n\n  lazyLoad() {\n    if (this.instance.dispatch('contentLazyLoad', {\n      content: this\n    }).defaultPrevented) {\n      return;\n    }\n\n    this.load(true);\n  }\n  /**\r\n   * @returns {boolean} If placeholder should be kept after content is loaded\r\n   */\n\n\n  keepPlaceholder() {\n    return this.instance.applyFilters('isKeepingPlaceholder', this.isLoading(), this);\n  }\n  /**\r\n   * Destroy the content\r\n   */\n\n\n  destroy() {\n    this.hasSlide = false;\n    this.slide = undefined;\n\n    if (this.instance.dispatch('contentDestroy', {\n      content: this\n    }).defaultPrevented) {\n      return;\n    }\n\n    this.remove();\n\n    if (this.placeholder) {\n      this.placeholder.destroy();\n      this.placeholder = undefined;\n    }\n\n    if (this.isImageContent() && this.element) {\n      this.element.onload = null;\n      this.element.onerror = null;\n      this.element = undefined;\n    }\n  }\n  /**\r\n   * Display error message\r\n   */\n\n\n  displayError() {\n    if (this.slide) {\n      var _this$instance$option, _this$instance$option2;\n\n      let errorMsgEl = createElement('pswp__error-msg', 'div');\n      errorMsgEl.innerText = (_this$instance$option = (_this$instance$option2 = this.instance.options) === null || _this$instance$option2 === void 0 ? void 0 : _this$instance$option2.errorMsg) !== null && _this$instance$option !== void 0 ? _this$instance$option : '';\n      errorMsgEl =\n      /** @type {HTMLDivElement} */\n      this.instance.applyFilters('contentErrorElement', errorMsgEl, this);\n      this.element = createElement('pswp__content pswp__error-msg-container', 'div');\n      this.element.appendChild(errorMsgEl);\n      this.slide.container.innerText = '';\n      this.slide.container.appendChild(this.element);\n      this.slide.updateContentSize(true);\n      this.removePlaceholder();\n    }\n  }\n  /**\r\n   * Append the content\r\n   */\n\n\n  append() {\n    if (this.isAttached || !this.element) {\n      return;\n    }\n\n    this.isAttached = true;\n\n    if (this.state === LOAD_STATE.ERROR) {\n      this.displayError();\n      return;\n    }\n\n    if (this.instance.dispatch('contentAppend', {\n      content: this\n    }).defaultPrevented) {\n      return;\n    }\n\n    const supportsDecode = ('decode' in this.element);\n\n    if (this.isImageContent()) {\n      // Use decode() on nearby slides\n      //\n      // Nearby slide images are in DOM and not hidden via display:none.\n      // However, they are placed offscreen (to the left and right side).\n      //\n      // Some browsers do not composite the image until it's actually visible,\n      // using decode() helps.\n      //\n      // You might ask \"why dont you just decode() and then append all images\",\n      // that's because I want to show image before it's fully loaded,\n      // as browser can render parts of image while it is loading.\n      // We do not do this in Safari due to partial loading bug.\n      if (supportsDecode && this.slide && (!this.slide.isActive || isSafari())) {\n        this.isDecoding = true; // purposefully using finally instead of then,\n        // as if srcset sizes changes dynamically - it may cause decode error\n\n        /** @type {HTMLImageElement} */\n\n        this.element.decode().catch(() => {}).finally(() => {\n          this.isDecoding = false;\n          this.appendImage();\n        });\n      } else {\n        this.appendImage();\n      }\n    } else if (this.slide && !this.element.parentNode) {\n      this.slide.container.appendChild(this.element);\n    }\n  }\n  /**\r\n   * Activate the slide,\r\n   * active slide is generally the current one,\r\n   * meaning the user can see it.\r\n   */\n\n\n  activate() {\n    if (this.instance.dispatch('contentActivate', {\n      content: this\n    }).defaultPrevented || !this.slide) {\n      return;\n    }\n\n    if (this.isImageContent() && this.isDecoding && !isSafari()) {\n      // add image to slide when it becomes active,\n      // even if it's not finished decoding\n      this.appendImage();\n    } else if (this.isError()) {\n      this.load(false, true); // try to reload\n    }\n\n    if (this.slide.holderElement) {\n      this.slide.holderElement.setAttribute('aria-hidden', 'false');\n    }\n  }\n  /**\r\n   * Deactivate the content\r\n   */\n\n\n  deactivate() {\n    this.instance.dispatch('contentDeactivate', {\n      content: this\n    });\n\n    if (this.slide && this.slide.holderElement) {\n      this.slide.holderElement.setAttribute('aria-hidden', 'true');\n    }\n  }\n  /**\r\n   * Remove the content from DOM\r\n   */\n\n\n  remove() {\n    this.isAttached = false;\n\n    if (this.instance.dispatch('contentRemove', {\n      content: this\n    }).defaultPrevented) {\n      return;\n    }\n\n    if (this.element && this.element.parentNode) {\n      this.element.remove();\n    }\n\n    if (this.placeholder && this.placeholder.element) {\n      this.placeholder.element.remove();\n    }\n  }\n  /**\r\n   * Append the image content to slide container\r\n   */\n\n\n  appendImage() {\n    if (!this.isAttached) {\n      return;\n    }\n\n    if (this.instance.dispatch('contentAppendImage', {\n      content: this\n    }).defaultPrevented) {\n      return;\n    } // ensure that element exists and is not already appended\n\n\n    if (this.slide && this.element && !this.element.parentNode) {\n      this.slide.container.appendChild(this.element);\n    }\n\n    if (this.state === LOAD_STATE.LOADED || this.state === LOAD_STATE.ERROR) {\n      this.removePlaceholder();\n    }\n  }\n\n}\n\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\n\n/** @typedef {import('../core/base.js').default} PhotoSwipeBase */\n\n/** @typedef {import('../photoswipe.js').Point} Point */\n\n/** @typedef {import('../slide/slide.js').SlideData} SlideData */\n\n/**\r\n * @param {PhotoSwipeOptions} options\r\n * @param {PhotoSwipeBase} pswp\r\n * @returns {Point}\r\n */\nfunction getViewportSize(options, pswp) {\n  if (options.getViewportSizeFn) {\n    const newViewportSize = options.getViewportSizeFn(options, pswp);\n\n    if (newViewportSize) {\n      return newViewportSize;\n    }\n  }\n\n  return {\n    x: document.documentElement.clientWidth,\n    // TODO: height on mobile is very incosistent due to toolbar\n    // find a way to improve this\n    //\n    // document.documentElement.clientHeight - doesn't seem to work well\n    y: window.innerHeight\n  };\n}\n/**\r\n * Parses padding option.\r\n * Supported formats:\r\n *\r\n * // Object\r\n * padding: {\r\n *  top: 0,\r\n *  bottom: 0,\r\n *  left: 0,\r\n *  right: 0\r\n * }\r\n *\r\n * // A function that returns the object\r\n * paddingFn: (viewportSize, itemData, index) => {\r\n *  return {\r\n *    top: 0,\r\n *    bottom: 0,\r\n *    left: 0,\r\n *    right: 0\r\n *  };\r\n * }\r\n *\r\n * // Legacy variant\r\n * paddingLeft: 0,\r\n * paddingRight: 0,\r\n * paddingTop: 0,\r\n * paddingBottom: 0,\r\n *\r\n * @param {'left' | 'top' | 'bottom' | 'right'} prop\r\n * @param {PhotoSwipeOptions} options PhotoSwipe options\r\n * @param {Point} viewportSize PhotoSwipe viewport size, for example: { x:800, y:600 }\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {number} index Slide index\r\n * @returns {number}\r\n */\n\nfunction parsePaddingOption(prop, options, viewportSize, itemData, index) {\n  let paddingValue = 0;\n\n  if (options.paddingFn) {\n    paddingValue = options.paddingFn(viewportSize, itemData, index)[prop];\n  } else if (options.padding) {\n    paddingValue = options.padding[prop];\n  } else {\n    const legacyPropName = 'padding' + prop[0].toUpperCase() + prop.slice(1); // @ts-expect-error\n\n    if (options[legacyPropName]) {\n      // @ts-expect-error\n      paddingValue = options[legacyPropName];\n    }\n  }\n\n  return Number(paddingValue) || 0;\n}\n/**\r\n * @param {PhotoSwipeOptions} options\r\n * @param {Point} viewportSize\r\n * @param {SlideData} itemData\r\n * @param {number} index\r\n * @returns {Point}\r\n */\n\nfunction getPanAreaSize(options, viewportSize, itemData, index) {\n  return {\n    x: viewportSize.x - parsePaddingOption('left', options, viewportSize, itemData, index) - parsePaddingOption('right', options, viewportSize, itemData, index),\n    y: viewportSize.y - parsePaddingOption('top', options, viewportSize, itemData, index) - parsePaddingOption('bottom', options, viewportSize, itemData, index)\n  };\n}\n\nconst MAX_IMAGE_WIDTH = 4000;\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\n\n/** @typedef {import('../photoswipe.js').Point} Point */\n\n/** @typedef {import('../slide/slide.js').SlideData} SlideData */\n\n/** @typedef {'fit' | 'fill' | number | ((zoomLevelObject: ZoomLevel) => number)} ZoomLevelOption */\n\n/**\r\n * Calculates zoom levels for specific slide.\r\n * Depends on viewport size and image size.\r\n */\n\nclass ZoomLevel {\n  /**\r\n   * @param {PhotoSwipeOptions} options PhotoSwipe options\r\n   * @param {SlideData} itemData Slide data\r\n   * @param {number} index Slide index\r\n   * @param {PhotoSwipe} [pswp] PhotoSwipe instance, can be undefined if not initialized yet\r\n   */\n  constructor(options, itemData, index, pswp) {\n    this.pswp = pswp;\n    this.options = options;\n    this.itemData = itemData;\n    this.index = index;\n    /** @type { Point | null } */\n\n    this.panAreaSize = null;\n    /** @type { Point | null } */\n\n    this.elementSize = null;\n    this.fit = 1;\n    this.fill = 1;\n    this.vFill = 1;\n    this.initial = 1;\n    this.secondary = 1;\n    this.max = 1;\n    this.min = 1;\n  }\n  /**\r\n   * Calculate initial, secondary and maximum zoom level for the specified slide.\r\n   *\r\n   * It should be called when either image or viewport size changes.\r\n   *\r\n   * @param {number} maxWidth\r\n   * @param {number} maxHeight\r\n   * @param {Point} panAreaSize\r\n   */\n\n\n  update(maxWidth, maxHeight, panAreaSize) {\n    /** @type {Point} */\n    const elementSize = {\n      x: maxWidth,\n      y: maxHeight\n    };\n    this.elementSize = elementSize;\n    this.panAreaSize = panAreaSize;\n    const hRatio = panAreaSize.x / elementSize.x;\n    const vRatio = panAreaSize.y / elementSize.y;\n    this.fit = Math.min(1, hRatio < vRatio ? hRatio : vRatio);\n    this.fill = Math.min(1, hRatio > vRatio ? hRatio : vRatio); // zoom.vFill defines zoom level of the image\n    // when it has 100% of viewport vertical space (height)\n\n    this.vFill = Math.min(1, vRatio);\n    this.initial = this._getInitial();\n    this.secondary = this._getSecondary();\n    this.max = Math.max(this.initial, this.secondary, this._getMax());\n    this.min = Math.min(this.fit, this.initial, this.secondary);\n\n    if (this.pswp) {\n      this.pswp.dispatch('zoomLevelsUpdate', {\n        zoomLevels: this,\n        slideData: this.itemData\n      });\n    }\n  }\n  /**\r\n   * Parses user-defined zoom option.\r\n   *\r\n   * @private\r\n   * @param {'initial' | 'secondary' | 'max'} optionPrefix Zoom level option prefix (initial, secondary, max)\r\n   * @returns { number | undefined }\r\n   */\n\n\n  _parseZoomLevelOption(optionPrefix) {\n    const optionName =\n    /** @type {'initialZoomLevel' | 'secondaryZoomLevel' | 'maxZoomLevel'} */\n    optionPrefix + 'ZoomLevel';\n    const optionValue = this.options[optionName];\n\n    if (!optionValue) {\n      return;\n    }\n\n    if (typeof optionValue === 'function') {\n      return optionValue(this);\n    }\n\n    if (optionValue === 'fill') {\n      return this.fill;\n    }\n\n    if (optionValue === 'fit') {\n      return this.fit;\n    }\n\n    return Number(optionValue);\n  }\n  /**\r\n   * Get zoom level to which image will be zoomed after double-tap gesture,\r\n   * or when user clicks on zoom icon,\r\n   * or mouse-click on image itself.\r\n   * If you return 1 image will be zoomed to its original size.\r\n   *\r\n   * @private\r\n   * @return {number}\r\n   */\n\n\n  _getSecondary() {\n    let currZoomLevel = this._parseZoomLevelOption('secondary');\n\n    if (currZoomLevel) {\n      return currZoomLevel;\n    } // 3x of \"fit\" state, but not larger than original\n\n\n    currZoomLevel = Math.min(1, this.fit * 3);\n\n    if (this.elementSize && currZoomLevel * this.elementSize.x > MAX_IMAGE_WIDTH) {\n      currZoomLevel = MAX_IMAGE_WIDTH / this.elementSize.x;\n    }\n\n    return currZoomLevel;\n  }\n  /**\r\n   * Get initial image zoom level.\r\n   *\r\n   * @private\r\n   * @return {number}\r\n   */\n\n\n  _getInitial() {\n    return this._parseZoomLevelOption('initial') || this.fit;\n  }\n  /**\r\n   * Maximum zoom level when user zooms\r\n   * via zoom/pinch gesture,\r\n   * via cmd/ctrl-wheel or via trackpad.\r\n   *\r\n   * @private\r\n   * @return {number}\r\n   */\n\n\n  _getMax() {\n    // max zoom level is x4 from \"fit state\",\n    // used for zoom gesture and ctrl/trackpad zoom\n    return this._parseZoomLevelOption('max') || Math.max(1, this.fit * 4);\n  }\n\n}\n\n/**\r\n * Lazy-load an image\r\n * This function is used both by Lightbox and PhotoSwipe core,\r\n * thus it can be called before dialog is opened.\r\n *\r\n * @param {SlideData} itemData Data about the slide\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance\r\n * @param {number} index\r\n * @returns {Content} Image that is being decoded or false.\r\n */\n\nfunction lazyLoadData(itemData, instance, index) {\n  const content = instance.createContentFromData(itemData, index);\n  /** @type {ZoomLevel | undefined} */\n\n  let zoomLevel;\n  const {\n    options\n  } = instance; // We need to know dimensions of the image to preload it,\n  // as it might use srcset, and we need to define sizes\n\n  if (options) {\n    zoomLevel = new ZoomLevel(options, itemData, -1);\n    let viewportSize;\n\n    if (instance.pswp) {\n      viewportSize = instance.pswp.viewportSize;\n    } else {\n      viewportSize = getViewportSize(options, instance);\n    }\n\n    const panAreaSize = getPanAreaSize(options, viewportSize, itemData, index);\n    zoomLevel.update(content.width, content.height, panAreaSize);\n  }\n\n  content.lazyLoad();\n\n  if (zoomLevel) {\n    content.setDisplayedSize(Math.ceil(content.width * zoomLevel.initial), Math.ceil(content.height * zoomLevel.initial));\n  }\n\n  return content;\n}\n/**\r\n * Lazy-loads specific slide.\r\n * This function is used both by Lightbox and PhotoSwipe core,\r\n * thus it can be called before dialog is opened.\r\n *\r\n * By default, it loads image based on viewport size and initial zoom level.\r\n *\r\n * @param {number} index Slide index\r\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox eventable instance\r\n * @returns {Content | undefined}\r\n */\n\nfunction lazyLoadSlide(index, instance) {\n  const itemData = instance.getItemData(index);\n\n  if (instance.dispatch('lazyLoadSlide', {\n    index,\n    itemData\n  }).defaultPrevented) {\n    return;\n  }\n\n  return lazyLoadData(itemData, instance, index);\n}\n\n/** @typedef {import(\"../photoswipe.js\").default} PhotoSwipe */\n\n/** @typedef {import(\"../slide/slide.js\").SlideData} SlideData */\n\n/**\r\n * PhotoSwipe base class that can retrieve data about every slide.\r\n * Shared by PhotoSwipe Core and PhotoSwipe Lightbox\r\n */\n\nclass PhotoSwipeBase extends Eventable {\n  /**\r\n   * Get total number of slides\r\n   *\r\n   * @returns {number}\r\n   */\n  getNumItems() {\n    var _this$options;\n\n    let numItems = 0;\n    const dataSource = (_this$options = this.options) === null || _this$options === void 0 ? void 0 : _this$options.dataSource;\n\n    if (dataSource && 'length' in dataSource) {\n      // may be an array or just object with length property\n      numItems = dataSource.length;\n    } else if (dataSource && 'gallery' in dataSource) {\n      // query DOM elements\n      if (!dataSource.items) {\n        dataSource.items = this._getGalleryDOMElements(dataSource.gallery);\n      }\n\n      if (dataSource.items) {\n        numItems = dataSource.items.length;\n      }\n    } // legacy event, before filters were introduced\n\n\n    const event = this.dispatch('numItems', {\n      dataSource,\n      numItems\n    });\n    return this.applyFilters('numItems', event.numItems, dataSource);\n  }\n  /**\r\n   * @param {SlideData} slideData\r\n   * @param {number} index\r\n   * @returns {Content}\r\n   */\n\n\n  createContentFromData(slideData, index) {\n    return new Content(slideData, this, index);\n  }\n  /**\r\n   * Get item data by index.\r\n   *\r\n   * \"item data\" should contain normalized information that PhotoSwipe needs to generate a slide.\r\n   * For example, it may contain properties like\r\n   * `src`, `srcset`, `w`, `h`, which will be used to generate a slide with image.\r\n   *\r\n   * @param {number} index\r\n   * @returns {SlideData}\r\n   */\n\n\n  getItemData(index) {\n    var _this$options2;\n\n    const dataSource = (_this$options2 = this.options) === null || _this$options2 === void 0 ? void 0 : _this$options2.dataSource;\n    /** @type {SlideData | HTMLElement} */\n\n    let dataSourceItem = {};\n\n    if (Array.isArray(dataSource)) {\n      // Datasource is an array of elements\n      dataSourceItem = dataSource[index];\n    } else if (dataSource && 'gallery' in dataSource) {\n      // dataSource has gallery property,\n      // thus it was created by Lightbox, based on\n      // gallery and children options\n      // query DOM elements\n      if (!dataSource.items) {\n        dataSource.items = this._getGalleryDOMElements(dataSource.gallery);\n      }\n\n      dataSourceItem = dataSource.items[index];\n    }\n\n    let itemData = dataSourceItem;\n\n    if (itemData instanceof Element) {\n      itemData = this._domElementToItemData(itemData);\n    } // Dispatching the itemData event,\n    // it's a legacy verion before filters were introduced\n\n\n    const event = this.dispatch('itemData', {\n      itemData: itemData || {},\n      index\n    });\n    return this.applyFilters('itemData', event.itemData, index);\n  }\n  /**\r\n   * Get array of gallery DOM elements,\r\n   * based on childSelector and gallery element.\r\n   *\r\n   * @param {HTMLElement} galleryElement\r\n   * @returns {HTMLElement[]}\r\n   */\n\n\n  _getGalleryDOMElements(galleryElement) {\n    var _this$options3, _this$options4;\n\n    if ((_this$options3 = this.options) !== null && _this$options3 !== void 0 && _this$options3.children || (_this$options4 = this.options) !== null && _this$options4 !== void 0 && _this$options4.childSelector) {\n      return getElementsFromOption(this.options.children, this.options.childSelector, galleryElement) || [];\n    }\n\n    return [galleryElement];\n  }\n  /**\r\n   * Converts DOM element to item data object.\r\n   *\r\n   * @param {HTMLElement} element DOM element\r\n   * @returns {SlideData}\r\n   */\n\n\n  _domElementToItemData(element) {\n    /** @type {SlideData} */\n    const itemData = {\n      element\n    };\n    const linkEl =\n    /** @type {HTMLAnchorElement} */\n    element.tagName === 'A' ? element : element.querySelector('a');\n\n    if (linkEl) {\n      // src comes from data-pswp-src attribute,\n      // if it's empty link href is used\n      itemData.src = linkEl.dataset.pswpSrc || linkEl.href;\n\n      if (linkEl.dataset.pswpSrcset) {\n        itemData.srcset = linkEl.dataset.pswpSrcset;\n      }\n\n      itemData.width = linkEl.dataset.pswpWidth ? parseInt(linkEl.dataset.pswpWidth, 10) : 0;\n      itemData.height = linkEl.dataset.pswpHeight ? parseInt(linkEl.dataset.pswpHeight, 10) : 0; // support legacy w & h properties\n\n      itemData.w = itemData.width;\n      itemData.h = itemData.height;\n\n      if (linkEl.dataset.pswpType) {\n        itemData.type = linkEl.dataset.pswpType;\n      }\n\n      const thumbnailEl = element.querySelector('img');\n\n      if (thumbnailEl) {\n        var _thumbnailEl$getAttri;\n\n        // msrc is URL to placeholder image that's displayed before large image is loaded\n        // by default it's displayed only for the first slide\n        itemData.msrc = thumbnailEl.currentSrc || thumbnailEl.src;\n        itemData.alt = (_thumbnailEl$getAttri = thumbnailEl.getAttribute('alt')) !== null && _thumbnailEl$getAttri !== void 0 ? _thumbnailEl$getAttri : '';\n      }\n\n      if (linkEl.dataset.pswpCropped || linkEl.dataset.cropped) {\n        itemData.thumbCropped = true;\n      }\n    }\n\n    return this.applyFilters('domItemData', itemData, element, linkEl);\n  }\n  /**\r\n   * Lazy-load by slide data\r\n   *\r\n   * @param {SlideData} itemData Data about the slide\r\n   * @param {number} index\r\n   * @returns {Content} Image that is being decoded or false.\r\n   */\n\n\n  lazyLoadData(itemData, index) {\n    return lazyLoadData(itemData, this, index);\n  }\n\n}\n\n/**\r\n * @template T\r\n * @typedef {import('../types.js').Type<T>} Type<T>\r\n */\n\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\n\n/** @typedef {import('../photoswipe.js').DataSource} DataSource */\n\n/** @typedef {import('../photoswipe.js').Point} Point */\n\n/** @typedef {import('../slide/content.js').default} Content */\n\n/** @typedef {import('../core/eventable.js').PhotoSwipeEventsMap} PhotoSwipeEventsMap */\n\n/** @typedef {import('../core/eventable.js').PhotoSwipeFiltersMap} PhotoSwipeFiltersMap */\n\n/**\r\n * @template {keyof PhotoSwipeEventsMap} T\r\n * @typedef {import('../core/eventable.js').EventCallback<T>} EventCallback<T>\r\n */\n\n/**\r\n * PhotoSwipe Lightbox\r\n *\r\n * - If user has unsupported browser it falls back to default browser action (just opens URL)\r\n * - Binds click event to links that should open PhotoSwipe\r\n * - parses DOM strcture for PhotoSwipe (retrieves large image URLs and sizes)\r\n * - Initializes PhotoSwipe\r\n *\r\n *\r\n * Loader options use the same object as PhotoSwipe, and supports such options:\r\n *\r\n * gallery - Element | Element[] | NodeList | string selector for the gallery element\r\n * children - Element | Element[] | NodeList | string selector for the gallery children\r\n *\r\n */\n\nclass PhotoSwipeLightbox extends PhotoSwipeBase {\n  /**\r\n   * @param {PhotoSwipeOptions} [options]\r\n   */\n  constructor(options) {\n    super();\n    /** @type {PhotoSwipeOptions} */\n\n    this.options = options || {};\n    this._uid = 0;\n    this.shouldOpen = false;\n    /**\r\n     * @private\r\n     * @type {Content | undefined}\r\n     */\n\n    this._preloadedContent = undefined;\n    this.onThumbnailsClick = this.onThumbnailsClick.bind(this);\n  }\n  /**\r\n   * Initialize lightbox, should be called only once.\r\n   * It's not included in the main constructor, so you may bind events before it.\r\n   */\n\n\n  init() {\n    // Bind click events to each gallery\n    getElementsFromOption(this.options.gallery, this.options.gallerySelector).forEach(galleryElement => {\n      galleryElement.addEventListener('click', this.onThumbnailsClick, false);\n    });\n  }\n  /**\r\n   * @param {MouseEvent} e\r\n   */\n\n\n  onThumbnailsClick(e) {\n    // Exit and allow default browser action if:\n    if (specialKeyUsed(e) // ... if clicked with a special key (ctrl/cmd...)\n    || window.pswp) {\n      // ... if PhotoSwipe is already open\n      return;\n    } // If both clientX and clientY are 0 or not defined,\n    // the event is likely triggered by keyboard,\n    // so we do not pass the initialPoint\n    //\n    // Note that some screen readers emulate the mouse position,\n    // so it's not the ideal way to detect them.\n    //\n\n    /** @type {Point | null} */\n\n\n    let initialPoint = {\n      x: e.clientX,\n      y: e.clientY\n    };\n\n    if (!initialPoint.x && !initialPoint.y) {\n      initialPoint = null;\n    }\n\n    let clickedIndex = this.getClickedIndex(e);\n    clickedIndex = this.applyFilters('clickedIndex', clickedIndex, e, this);\n    /** @type {DataSource} */\n\n    const dataSource = {\n      gallery:\n      /** @type {HTMLElement} */\n      e.currentTarget\n    };\n\n    if (clickedIndex >= 0) {\n      e.preventDefault();\n      this.loadAndOpen(clickedIndex, dataSource, initialPoint);\n    }\n  }\n  /**\r\n   * Get index of gallery item that was clicked.\r\n   *\r\n   * @param {MouseEvent} e click event\r\n   * @returns {number}\r\n   */\n\n\n  getClickedIndex(e) {\n    // legacy option\n    if (this.options.getClickedIndexFn) {\n      return this.options.getClickedIndexFn.call(this, e);\n    }\n\n    const clickedTarget =\n    /** @type {HTMLElement} */\n    e.target;\n    const childElements = getElementsFromOption(this.options.children, this.options.childSelector,\n    /** @type {HTMLElement} */\n    e.currentTarget);\n    const clickedChildIndex = childElements.findIndex(child => child === clickedTarget || child.contains(clickedTarget));\n\n    if (clickedChildIndex !== -1) {\n      return clickedChildIndex;\n    } else if (this.options.children || this.options.childSelector) {\n      // click wasn't on a child element\n      return -1;\n    } // There is only one item (which is the gallery)\n\n\n    return 0;\n  }\n  /**\r\n   * Load and open PhotoSwipe\r\n   *\r\n   * @param {number} index\r\n   * @param {DataSource} [dataSource]\r\n   * @param {Point | null} [initialPoint]\r\n   * @returns {boolean}\r\n   */\n\n\n  loadAndOpen(index, dataSource, initialPoint) {\n    // Check if the gallery is already open\n    if (window.pswp || !this.options) {\n      return false;\n    } // Use the first gallery element if dataSource is not provided\n\n\n    if (!dataSource && this.options.gallery && this.options.children) {\n      const galleryElements = getElementsFromOption(this.options.gallery);\n\n      if (galleryElements[0]) {\n        dataSource = {\n          gallery: galleryElements[0]\n        };\n      }\n    } // set initial index\n\n\n    this.options.index = index; // define options for PhotoSwipe constructor\n\n    this.options.initialPointerPos = initialPoint;\n    this.shouldOpen = true;\n    this.preload(index, dataSource);\n    return true;\n  }\n  /**\r\n   * Load the main module and the slide content by index\r\n   *\r\n   * @param {number} index\r\n   * @param {DataSource} [dataSource]\r\n   */\n\n\n  preload(index, dataSource) {\n    const {\n      options\n    } = this;\n\n    if (dataSource) {\n      options.dataSource = dataSource;\n    } // Add the main module\n\n    /** @type {Promise<Type<PhotoSwipe>>[]} */\n\n\n    const promiseArray = [];\n    const pswpModuleType = typeof options.pswpModule;\n\n    if (isPswpClass(options.pswpModule)) {\n      promiseArray.push(Promise.resolve(\n      /** @type {Type<PhotoSwipe>} */\n      options.pswpModule));\n    } else if (pswpModuleType === 'string') {\n      throw new Error('pswpModule as string is no longer supported');\n    } else if (pswpModuleType === 'function') {\n      promiseArray.push(\n      /** @type {() => Promise<Type<PhotoSwipe>>} */\n      options.pswpModule());\n    } else {\n      throw new Error('pswpModule is not valid');\n    } // Add custom-defined promise, if any\n\n\n    if (typeof options.openPromise === 'function') {\n      // allow developers to perform some task before opening\n      promiseArray.push(options.openPromise());\n    }\n\n    if (options.preloadFirstSlide !== false && index >= 0) {\n      this._preloadedContent = lazyLoadSlide(index, this);\n    } // Wait till all promises resolve and open PhotoSwipe\n\n\n    const uid = ++this._uid;\n    Promise.all(promiseArray).then(iterableModules => {\n      if (this.shouldOpen) {\n        const mainModule = iterableModules[0];\n\n        this._openPhotoswipe(mainModule, uid);\n      }\n    });\n  }\n  /**\r\n   * @private\r\n   * @param {Type<PhotoSwipe> | { default: Type<PhotoSwipe> }} module\r\n   * @param {number} uid\r\n   */\n\n\n  _openPhotoswipe(module, uid) {\n    // Cancel opening if UID doesn't match the current one\n    // (if user clicked on another gallery item before current was loaded).\n    //\n    // Or if shouldOpen flag is set to false\n    // (developer may modify it via public API)\n    if (uid !== this._uid && this.shouldOpen) {\n      return;\n    }\n\n    this.shouldOpen = false; // PhotoSwipe is already open\n\n    if (window.pswp) {\n      return;\n    }\n    /**\r\n     * Pass data to PhotoSwipe and open init\r\n     *\r\n     * @type {PhotoSwipe}\r\n     */\n\n\n    const pswp = typeof module === 'object' ? new module.default(this.options) // eslint-disable-line\n    : new module(this.options); // eslint-disable-line\n\n    this.pswp = pswp;\n    window.pswp = pswp; // map listeners from Lightbox to PhotoSwipe Core\n\n    /** @type {(keyof PhotoSwipeEventsMap)[]} */\n\n    Object.keys(this._listeners).forEach(name => {\n      var _this$_listeners$name;\n\n      (_this$_listeners$name = this._listeners[name]) === null || _this$_listeners$name === void 0 || _this$_listeners$name.forEach(fn => {\n        pswp.on(name,\n        /** @type {EventCallback<typeof name>} */\n        fn);\n      });\n    }); // same with filters\n\n    /** @type {(keyof PhotoSwipeFiltersMap)[]} */\n\n    Object.keys(this._filters).forEach(name => {\n      var _this$_filters$name;\n\n      (_this$_filters$name = this._filters[name]) === null || _this$_filters$name === void 0 || _this$_filters$name.forEach(filter => {\n        pswp.addFilter(name, filter.fn, filter.priority);\n      });\n    });\n\n    if (this._preloadedContent) {\n      pswp.contentLoader.addToCache(this._preloadedContent);\n      this._preloadedContent = undefined;\n    }\n\n    pswp.on('destroy', () => {\n      // clean up public variables\n      this.pswp = undefined;\n      delete window.pswp;\n    });\n    pswp.init();\n  }\n  /**\r\n   * Unbinds all events, closes PhotoSwipe if it's open.\r\n   */\n\n\n  destroy() {\n    var _this$pswp;\n\n    (_this$pswp = this.pswp) === null || _this$pswp === void 0 || _this$pswp.destroy();\n    this.shouldOpen = false;\n    this._listeners = {};\n    getElementsFromOption(this.options.gallery, this.options.gallerySelector).forEach(galleryElement => {\n      galleryElement.removeEventListener('click', this.onThumbnailsClick, false);\n    });\n  }\n\n}\n\nexport { PhotoSwipeLightbox as default };\n//# sourceMappingURL=photoswipe-lightbox.esm.js.map\n","import PhotoSwipeLightbox from 'photoswipe/lightbox';\n\nconst createLightbox = () => {\n    const lightbox = new PhotoSwipeLightbox({\n        gallery: '#pswp-gallery',\n        children: 'a',\n        bgOpacity: 1,\n        showHideAnimationType: 'fade',\n        pswpModule: () => import('photoswipe'),\n    });\n\n    lightbox.init();\n    return lightbox;\n};\n\nexport const init = () => {\n    let lightbox = createLightbox();\n\n    const gallery = document.querySelector('#pswp-gallery');\n    if (gallery) {\n        gallery.addEventListener('d3r.live.replaced', () => {\n            lightbox.destroy();\n            lightbox = createLightbox();\n        });\n    }\n};\n","const initCloseButtons = () => {\n    const closeButtons = document.querySelectorAll('[data-close-popover]');\n\n    closeButtons.forEach(button => {\n        button.addEventListener('click', () => {\n            const popover = button.closest('[popover]');\n\n            if (popover) {\n                popover.hidePopover();\n            }\n        });\n    });\n};\n\nconst initActiveStates = () => {\n    const popovers = document.querySelectorAll('[popover]');\n\n    popovers.forEach(popover => {\n        const triggerButton = document.querySelector(\n            `[popovertarget=\"${popover.id}\"]`\n        );\n\n        if (!triggerButton) {\n            return;\n        }\n\n        popover.addEventListener('toggle', event => {\n            if (event.newState === 'open') {\n                triggerButton.parentElement.classList.add(\n                    'configurator-options__group--active'\n                );\n            } else {\n                triggerButton.parentElement.classList.remove(\n                    'configurator-options__group--active'\n                );\n            }\n        });\n    });\n};\n\nconst initLivePagePopoverOpen = () => {\n    const pdp = document.getElementById('pdpV2');\n    if (!pdp) return;\n\n    let observer = null;\n    let livePageReplacedHandler = null;\n\n    const disconnectPendingOpen = () => {\n        if (observer) {\n            observer.disconnect();\n            observer = null;\n        }\n\n        if (livePageReplacedHandler) {\n            document.removeEventListener(\n                'd3r.live.replaced',\n                livePageReplacedHandler\n            );\n            livePageReplacedHandler = null;\n        }\n    };\n\n    const openPopover = popover => {\n        disconnectPendingOpen();\n\n        if (!popover.matches(':popover-open')) {\n            popover.showPopover();\n        }\n    };\n\n    // Closing via the trigger should not re-fetch/re-render the popover content.\n    document.addEventListener(\n        'click',\n        event => {\n            const trigger = event.target.closest('[popovertarget][lp-get]');\n            if (!trigger) return;\n\n            const popoverId = trigger.getAttribute('popovertarget');\n            const popover = document.getElementById(popoverId);\n            if (!popover || !popover.matches(':popover-open')) return;\n\n            event.preventDefault();\n            event.stopPropagation();\n            disconnectPendingOpen();\n            popover.hidePopover();\n        },\n        true\n    );\n\n    // Let live-page fetch when opening, but manually control the popover state\n    // because live-page prevents the browser's native popover target toggle.\n    document.addEventListener('click', event => {\n        const trigger = event.target.closest('[popovertarget][lp-get]');\n        if (!trigger) return;\n\n        const popoverId = trigger.getAttribute('popovertarget');\n        const popover = document.getElementById(popoverId);\n        if (!popover) return;\n\n        const popoverInner = popover.querySelector(\n            '.configurator-popover__inner'\n        );\n\n        disconnectPendingOpen();\n\n        livePageReplacedHandler = replaceEvent => {\n            if (\n                popoverInner &&\n                replaceEvent.target !== popoverInner &&\n                !popoverInner.contains(replaceEvent.target)\n            ) {\n                return;\n            }\n\n            openPopover(popover);\n        };\n\n        document.addEventListener('d3r.live.replaced', livePageReplacedHandler);\n\n        // Fallback for live-page swaps that do not dispatch/bubble the render event.\n        observer = new MutationObserver(() => {\n            openPopover(popover);\n        });\n\n        observer.observe(popoverInner || pdp, {\n            attributes: true,\n            childList: true,\n            characterData: true,\n            subtree: true,\n        });\n    });\n};\n\nconst initColourStyleFilters = () => {\n    document.addEventListener('click', event => {\n        const trigger = event.target.closest('[data-colour-style-select]');\n        if (!trigger) return;\n\n        const popover =\n            trigger.closest('.configurator-popover') ||\n            trigger.closest('[data-dynamic-config-step-content]') ||\n            trigger.closest('[data-dynamic-config-content]') ||\n            trigger.closest('[data-dynamic-config-bar]') ||\n            trigger.closest('#pdpV2');\n        const styleId = trigger.getAttribute('data-colour-style-select');\n        if (!popover || !styleId) return;\n\n        event.preventDefault();\n\n        popover\n            .querySelectorAll('[data-colour-style-select]')\n            .forEach(button => {\n                const isActive =\n                    button.getAttribute('data-colour-style-select') === styleId;\n                button.setAttribute(\n                    'aria-pressed',\n                    isActive ? 'true' : 'false'\n                );\n                button\n                    .closest('.configurator-popover__colour-swatch')\n                    ?.classList.toggle('is-active', isActive);\n            });\n\n        popover\n            .querySelectorAll(\n                '.configurator-popover__colour-swatch--large[data-style-ids]'\n            )\n            .forEach(swatch => {\n                const styleIds = swatch\n                    .getAttribute('data-style-ids')\n                    .split(',')\n                    .map(id => id.trim())\n                    .filter(Boolean);\n\n                swatch.hidden = !styleIds.includes(styleId);\n            });\n    });\n};\n\nexport const init = () => {\n    initCloseButtons();\n    initActiveStates();\n    initLivePagePopoverOpen();\n    initColourStyleFilters();\n};\n","/**\n * Go to Configurator Button Handler\n * Navigates to the last slide (configurator) when button is clicked.\n * Uses AbortController so init() can be safely re-called after a hero swap\n * without accumulating duplicate listeners on the same button element.\n */\n\nlet controller = new AbortController();\nlet hasCustomSelections = false;\n\nconst gotoConfiguratorSelector = '[data-goto-configurator]';\nconst dynamicConfiguratorSelector = '[data-dynamic-config-customise]';\nconst ctaSelector = `${gotoConfiguratorSelector}, ${dynamicConfiguratorSelector}`;\n\nconst getClosest = (event, selector) =>\n    event.target instanceof Element ? event.target.closest(selector) : null;\n\nconst isConfiguratorSelectionTrigger = trigger => {\n    const requestUrl = trigger.getAttribute('lp-get') ?? '';\n\n    return (\n        requestUrl.includes('/variant') &&\n        !requestUrl.includes('qty-only=1') &&\n        !trigger.matches('[data-qty-lp-trigger]') &&\n        !trigger.closest('.is-active') &&\n        Boolean(\n            trigger.closest('#configurator-hero, [data-dynamic-config-bar]')\n        )\n    );\n};\n\nconst updateCtaLabels = () => {\n    document.querySelectorAll(ctaSelector).forEach(button => {\n        const customiseLabel = button.dataset.labelCustomise ?? 'Customise';\n        const reviewLabel = button.dataset.labelReview ?? 'Review selections';\n\n        button.textContent = hasCustomSelections ? reviewLabel : customiseLabel;\n    });\n};\n\nexport const init = slider => {\n    controller.abort();\n    controller = new AbortController();\n\n    if (!slider) {\n        return;\n    }\n\n    updateCtaLabels();\n\n    document.addEventListener(\n        'click',\n        event => {\n            const selectionTrigger = getClosest(\n                event,\n                '[lp-get][lp-trigger=\"click\"]'\n            );\n\n            if (\n                selectionTrigger &&\n                isConfiguratorSelectionTrigger(selectionTrigger)\n            ) {\n                hasCustomSelections = true;\n                updateCtaLabels();\n                return;\n            }\n\n            const button = getClosest(event, ctaSelector);\n\n            if (!button) {\n                return;\n            }\n\n            const lastSlideIndex = slider.totalSlides - 1;\n            slider.goToSlide(lastSlideIndex);\n            window.scrollTo({ top: 0, behavior: 'smooth' });\n        },\n        { signal: controller.signal, capture: true }\n    );\n\n    document.addEventListener('d3r.live.replaced', updateCtaLabels, {\n        signal: controller.signal,\n        capture: true,\n    });\n};\n","/**\n * Quick Add Overlay\n * Opens a sidebar overlay for quick adding paired products\n */\n\nimport Dialog from 'dialog';\nimport { loadChooserOverlay } from '../chooser/chooser-helpers';\n\nlet initialised = false;\n\n/**\n * Handles click events on the quick add button\n *\n * @param {Event} event\n * @return {void}\n */\nconst handleButtonClick = event => {\n    if (!(event.target instanceof Element)) {\n        return;\n    }\n\n    const button = event.target.closest('[data-upsell]');\n\n    if (!(button instanceof HTMLElement)) {\n        return;\n    }\n\n    if (button.dataset.overlayUrl) {\n        event.preventDefault();\n        loadChooserOverlay(button.dataset.overlayUrl);\n        return;\n    }\n\n    Dialog.render('#upsell-overlay', {\n        modifiers: ['sidebar', 'upsell'],\n    });\n};\n\n/**\n * Initialises the upsell overlay functionality\n */\nexport const init = () => {\n    if (initialised) {\n        return;\n    }\n\n    initialised = true;\n    document.addEventListener('click', handleButtonClick);\n};\n","import {\n    addToLocalStorage,\n    handleLocalStorage,\n    MAX_BASKET_SWATCHES,\n} from './local-storage';\nimport { NabASwatch } from './NabASwatch';\n\nconst initialisedContainers = new WeakSet();\n\nexport const initSwatchButtons = container => {\n    const root = document;\n\n    if (initialisedContainers.has(root)) {\n        return;\n    }\n\n    initialisedContainers.add(root);\n\n    root.addEventListener(\n        'click',\n        async event => {\n            const target =\n                event.target instanceof Element\n                    ? event.target\n                    : event.target instanceof Node\n                      ? event.target.parentElement\n                      : null;\n\n            if (!target) {\n                return;\n            }\n\n            const btn = target.closest('[data-add-swatch-slide]');\n            if (!(btn instanceof HTMLElement)) {\n                return;\n            }\n\n            event.stopPropagation();\n\n            const colourGlobalCode = btn.dataset.colourGlobalCode;\n            const materialGlobalCode = btn.dataset.materialGlobalCode;\n            const sku = btn.dataset.stockitem;\n\n            let swatchObject = null;\n\n            if (colourGlobalCode && materialGlobalCode) {\n                try {\n                    const response = await fetch(\n                        `/swatches/resolve-swatch?colour_global=${encodeURIComponent(colourGlobalCode)}&material_global=${encodeURIComponent(materialGlobalCode)}`,\n                        { headers: { 'X-Requested-With': 'XMLHttpRequest' } }\n                    );\n                    const data = await response.json();\n\n                    if (data.result && data.payload?.swatch) {\n                        const swatch = data.payload.swatch;\n                        swatchObject = {\n                            value: JSON.stringify({ colour: swatch.urlname }),\n                            title: swatch.title,\n                            longTitle: swatch.material_global_name,\n                            backgroundCSS: swatch.hex_background_css,\n                            categoryClass: '',\n                            hex: swatch.hex,\n                            imageHtml: swatch.image_html,\n                            colourCode: colourGlobalCode,\n                            materialCode: materialGlobalCode,\n                        };\n                    }\n                } catch (e) {\n                    // Fall through; overlay will still open without pre-adding.\n                }\n            } else {\n                // Legacy fallback: build from data attributes (e.g. config bar)\n                swatchObject = {\n                    value: btn.dataset.optionValues,\n                    title: btn.dataset.title,\n                    longTitle: btn.dataset.longTitle,\n                    url: btn.dataset.url,\n                    hex: btn.dataset.hex,\n                    categoryClass: btn.dataset.categoryClass,\n                    backgroundCSS: btn.dataset.swatchBackground,\n                };\n            }\n\n            const swatches = JSON.parse(localStorage.getItem('swatches')) ?? [];\n\n            const openOverlay = () =>\n                new NabASwatch(colourGlobalCode, materialGlobalCode, sku);\n\n            document.addEventListener(\n                'loaf-swatch-exists',\n                () => {\n                    new NabASwatch(colourGlobalCode, materialGlobalCode, sku);\n                },\n                { once: true }\n            );\n\n            if (swatchObject) {\n                if (swatches.length >= MAX_BASKET_SWATCHES) {\n                    handleLocalStorage(\n                        swatchObject,\n                        'loaf-swatch-exists',\n                        openOverlay,\n                        true\n                    );\n                } else {\n                    addToLocalStorage(swatches, swatchObject);\n                    openOverlay();\n                }\n            } else {\n                openOverlay();\n            }\n        },\n        { capture: true }\n    );\n};\n","/**\n * Watch for changes to the [data-configurator-state] attribute and call\n * the provided callback with the new state value whenever it changes.\n * Also calls the callback immediately with the current state.\n *\n * @param {function(string|null): void} onChange\n */\nexport const watchConfiguratorState = onChange => {\n    const wrapper = document.querySelector('[data-configurator-state]');\n    if (!wrapper) return;\n\n    const observer = new MutationObserver(mutations => {\n        mutations.forEach(mutation => {\n            if (mutation.attributeName === 'data-configurator-state') {\n                onChange(wrapper.getAttribute('data-configurator-state'));\n            }\n        });\n    });\n\n    observer.observe(wrapper, {\n        attributes: true,\n        attributeFilter: ['data-configurator-state'],\n    });\n\n    onChange(wrapper.getAttribute('data-configurator-state'));\n};\n","import { initSwatchButtons } from '../../swatch/initSwatchButton';\nimport { setEditInCpUrl } from '../../util/url';\nimport { watchConfiguratorState } from './configurator-state';\nimport { isShortDesktopViewport } from './short-desktop-viewport';\n\nconst fixedClassName = 'configuration-bar--fixed';\nconst leavingClassName = 'configuration-bar--leaving';\nconst onConfiguratorClassName = 'configuration-bar--on-configurator';\nconst reducedClassName = 'configuration-bar--reduced';\nconst returningClassName = 'configuration-bar--returning';\n\nlet heroObserver;\nlet currentConfiguratorState = null;\nlet hasConfiguratorStateWatcher = false;\nlet reducedConfigBarResizeFrame = null;\nlet reducedConfigBarResizeController = null;\nlet configBarScrollDirectionController = null;\nlet configBarIsScrollingUp = false;\nlet lastConfigBarScrollY = window.scrollY;\n\nconst getConfigBar = () =>\n    document.querySelector('[data-configuration-bar-v2]');\n\nconst getConfiguratorWrapper = () =>\n    document.querySelector('[data-configurator-state]');\n\nconst isMainConfiguratorHero = () => {\n    const wrapper = getConfiguratorWrapper();\n\n    return (\n        wrapper?.dataset.configuratorStyle === 'main' ||\n        Boolean(\n            document.querySelector(\n                '#configurator-hero:not(.configurator-hero--with-panel)'\n            )\n        )\n    );\n};\n\nconst shouldReduceConfigBar = (state, configBar) =>\n    Boolean(configBar) &&\n    isMainConfiguratorHero() &&\n    isShortDesktopViewport() &&\n    state !== 'on-configurator' &&\n    !configBar.classList.contains(fixedClassName);\n\nconst syncConfigBarState = (\n    state = currentConfiguratorState,\n    configBar = getConfigBar()\n) => {\n    const actions = configBar?.querySelector('.configuration-bar__actions');\n\n    configBar?.classList.toggle(\n        onConfiguratorClassName,\n        state === 'on-configurator'\n    );\n    configBar?.classList.toggle(\n        reducedClassName,\n        shouldReduceConfigBar(state, configBar)\n    );\n    actions?.classList.toggle('is-addBasket', state === 'on-configurator');\n};\n\nconst scheduleConfigBarStateSync = () => {\n    if (reducedConfigBarResizeFrame) {\n        return;\n    }\n\n    reducedConfigBarResizeFrame = window.requestAnimationFrame(() => {\n        reducedConfigBarResizeFrame = null;\n        syncConfigBarState();\n    });\n};\n\nconst initReducedConfigBarViewportWatcher = () => {\n    if (reducedConfigBarResizeController) {\n        scheduleConfigBarStateSync();\n\n        return;\n    }\n\n    reducedConfigBarResizeController = new AbortController();\n\n    window.addEventListener('resize', scheduleConfigBarStateSync, {\n        passive: true,\n        signal: reducedConfigBarResizeController.signal,\n    });\n\n    window.visualViewport?.addEventListener(\n        'resize',\n        scheduleConfigBarStateSync,\n        {\n            passive: true,\n            signal: reducedConfigBarResizeController.signal,\n        }\n    );\n};\n\n// Watch for changes in the configurator state and update the configuration bar accordingly\nconst initConfiguratorStateWatcher = () => {\n    if (hasConfiguratorStateWatcher) {\n        syncConfigBarState();\n\n        return;\n    }\n\n    hasConfiguratorStateWatcher = true;\n\n    watchConfiguratorState(state => {\n        currentConfiguratorState = state;\n        syncConfigBarState(state);\n    });\n};\n\n/**\n * Show the fixed configuration bar and restart the entrance animation.\n */\nconst showConfigBar = configBar => {\n    if (\n        configBar.classList.contains(fixedClassName) &&\n        !configBar.classList.contains(leavingClassName)\n    ) {\n        return;\n    }\n\n    configBar.classList.remove(\n        fixedClassName,\n        leavingClassName,\n        returningClassName\n    );\n    void configBar.offsetWidth;\n    configBar.classList.add(fixedClassName);\n    syncConfigBarState(currentConfiguratorState, configBar);\n};\n\n/**\n * Hide the fixed configuration bar using its exit animation.\n */\nconst hideConfigBar = configBar => {\n    if (!configBar.classList.contains(fixedClassName)) return;\n\n    configBar.classList.remove(returningClassName, leavingClassName);\n    void configBar.offsetWidth;\n    configBar.classList.add(leavingClassName);\n};\n\n/**\n * Keep the animation end listener bound to the current configuration bar.\n */\nconst initConfigBarAnimationWatcher = configBar => {\n    configBar.removeEventListener('animationend', handleConfigBarAnimationEnd);\n    configBar.addEventListener('animationend', handleConfigBarAnimationEnd);\n};\n\n/**\n * Reset the configuration bar classes after fixed/returning animations finish.\n */\nconst handleConfigBarAnimationEnd = event => {\n    if (event.target !== event.currentTarget) return;\n\n    const configBar = event.currentTarget;\n\n    if (event.animationName === 'configuration-bar-slide-down') {\n        configBar.classList.remove(\n            fixedClassName,\n            leavingClassName,\n            returningClassName\n        );\n        syncConfigBarState(currentConfiguratorState, configBar);\n        void configBar.offsetWidth;\n        configBar.classList.add(returningClassName);\n        return;\n    }\n\n    if (event.animationName === 'configuration-bar-fade-in') {\n        configBar.classList.remove(returningClassName);\n    }\n};\n\nconst disconnectScrollWatchers = () => {\n    heroObserver?.disconnect();\n    configBarScrollDirectionController?.abort();\n\n    heroObserver = undefined;\n    configBarScrollDirectionController = null;\n};\n\n/**\n * Tracks whether the page is currently being scrolled upwards.\n */\nconst updateConfigBarScrollDirection = () => {\n    const scrollY = window.scrollY;\n\n    configBarIsScrollingUp = scrollY < lastConfigBarScrollY - 2;\n    lastConfigBarScrollY = scrollY;\n};\n\n/**\n * Starts scroll direction tracking for the fixed bar observer.\n */\nconst initConfigBarScrollDirectionWatcher = () => {\n    configBarScrollDirectionController?.abort();\n\n    configBarScrollDirectionController = new AbortController();\n    configBarIsScrollingUp = false;\n    lastConfigBarScrollY = window.scrollY;\n\n    window.addEventListener('scroll', updateConfigBarScrollDirection, {\n        passive: true,\n        signal: configBarScrollDirectionController.signal,\n    });\n};\n\n// Watch for the hero leaving the viewport to toggle the fixed configuration bar\nconst configBarScrollWatcher = () => {\n    disconnectScrollWatchers();\n\n    const configBar = document.querySelector('[data-configuration-bar-v2]');\n    const hero = document.querySelector('#configurator-hero');\n    if (!configBar || !hero) return;\n\n    initConfigBarScrollDirectionWatcher();\n    initConfigBarAnimationWatcher(configBar);\n\n    heroObserver = new IntersectionObserver(\n        ([entry]) => {\n            if (entry.isIntersecting) {\n                if (configBarIsScrollingUp) {\n                    hideConfigBar(configBar);\n                }\n\n                return;\n            }\n\n            showConfigBar(configBar);\n        },\n        { rootMargin: '-100px 0px 0px 0px' }\n    );\n\n    heroObserver.observe(hero);\n};\n\n// initialisation function to be called on page load\nexport const init = () => {\n    initConfiguratorStateWatcher();\n    initReducedConfigBarViewportWatcher();\n    configBarScrollWatcher();\n    initSwatchButtons(getConfigBar());\n};\n\nconst configBar = getConfigBar();\n\nconst syncEditInCpUrl = () => {\n    const bar =\n        getConfigBar() ?? document.querySelector('[data-dynamic-config-bar]');\n    if (bar) {\n        setEditInCpUrl(bar.dataset.stockItemId);\n    }\n};\n\nconfigBar?.addEventListener('d3r.live.replaced', () => {\n    initConfiguratorStateWatcher();\n    initReducedConfigBarViewportWatcher();\n    configBarScrollWatcher();\n    initSwatchButtons(getConfigBar());\n    syncEditInCpUrl();\n});\n\ndocument.addEventListener(\n    'd3r.live.replaced',\n    event => {\n        if (\n            event.target?.matches?.(\n                '[data-configuration-bar-v2], [data-dynamic-config-bar]'\n            )\n        ) {\n            syncEditInCpUrl();\n        }\n    },\n    { capture: true }\n);\n","import Dialog from 'dialog';\nimport { watchConfiguratorState } from './configurator-state.js';\nimport { isShortDesktopViewport } from './short-desktop-viewport.js';\n/**\n * Dynamic Config Bar\n * Mobile-only configuration bar with three view states:\n * 1. Initial: product info + \"Customise\" CTA\n * 2. Steps overview: callout buttons for each config option\n * 3. Step detail: inline option chooser with prev/next navigation\n *\n * Step content (colour/fabric/size choosers) loads on-demand via\n * OptionLpHandler when a step is opened. The step buttons carry\n * lp-get attributes so live-page handles the fetch and swap automatically.\n */\n\nconst shortDesktopLiteClass = 'dynamic-config-bar--short-lite';\n\nclass DynamicConfigBar {\n    constructor(element, slider) {\n        this.element = element;\n        this.slider = slider;\n        this.currentStep = element.getAttribute('data-auto-open-step');\n        this.isMTO = element.dataset.isMto === 'true';\n        this.isLitePdp = Boolean(\n            document.querySelector('#pdpV2[data-configurator-style=\"lite\"]')\n        );\n        this.isShortDesktopLite = false;\n        this.configuratorState = document\n            .querySelector('[data-configurator-state]')\n            ?.getAttribute('data-configurator-state');\n\n        this.availableSteps = this.discoverAvailableSteps();\n        this.stepLabels = this.buildStepLabels();\n        this.hasInteracted = false;\n        this.handleResize = () => {\n            this.syncShortDesktopLiteMode();\n        };\n\n        this.cacheElements();\n\n        this.bindEvents();\n        this.watchConfiguratorState();\n    }\n\n    cacheElements() {\n        this.header = this.element.querySelector(\n            '[data-dynamic-config-header]'\n        );\n        this.availability = this.element.querySelector(\n            '[data-dynamic-config-availability]'\n        );\n        this.stepsContainer = this.element.querySelector(\n            '[data-dynamic-config-steps]'\n        );\n        this.contentContainer = this.element.querySelector(\n            '[data-dynamic-config-content]'\n        );\n        this.ctaButton = this.element.querySelector(\n            '[data-dynamic-config-customise]'\n        );\n    }\n\n    discoverAvailableSteps() {\n        const stepElements = this.element.querySelectorAll(\n            '[data-dynamic-config-step-content]'\n        );\n        return Array.from(stepElements).map(\n            el => el.dataset.dynamicConfigStepContent\n        );\n    }\n\n    buildStepLabels() {\n        const labels = {};\n        const stepElements = this.element.querySelectorAll(\n            '[data-dynamic-config-step-content]'\n        );\n        stepElements.forEach(el => {\n            const step = el.dataset.dynamicConfigStepContent;\n            labels[step] = el.dataset.dynamicConfigStepLabel ?? step;\n        });\n        return labels;\n    }\n\n    bindEvents() {\n        this.element.addEventListener('click', event => {\n            const customiseButton = event.target.closest(\n                '[data-dynamic-config-customise]'\n            );\n            const stepCloseButton = event.target.closest(\n                '[data-dynamic-config-step-close]'\n            );\n            const stepButton = event.target.closest(\n                '[data-dynamic-config-step]'\n            );\n            const prevButton = event.target.closest(\n                '[data-dynamic-config-prev]'\n            );\n            const nextButton = event.target.closest(\n                '[data-dynamic-config-next]'\n            );\n            const inlineOptionInfoButton = event.target.closest(\n                '.dynamic-config-callout__option-info--inline'\n            );\n\n            const removeUpsellButton = event.target.closest(\n                '[data-dynamic-remove-upsell]'\n            );\n\n            if (inlineOptionInfoButton) {\n                this.openInlineOptionInfoDialog(inlineOptionInfoButton, event);\n                return;\n            } else if (removeUpsellButton) {\n                // LP handles the request via lp-trigger on the span; just prevent the\n                // parent step button from also opening the step chooser.\n                return;\n            } else if (customiseButton) {\n                this.showSteps();\n                this.goToConfiguratorSlide();\n            } else if (stepCloseButton) {\n                this.showSteps();\n            } else if (stepButton) {\n                // Inline callouts render their choices directly and contain their own\n                // live-page swatch buttons, so a click never needs to open a step —\n                // let the nested button handle the swap. This holds regardless of how\n                // many other steps exist alongside the inline callout.\n                if (this.isInlineStep(stepButton)) {\n                    return;\n                }\n\n                this.openStep(stepButton.dataset.dynamicConfigStep);\n            } else if (prevButton) {\n                this.navigateStep(-1);\n            } else if (nextButton) {\n                this.navigateStep(1);\n            }\n        });\n\n        // After a live-page morph the nav labels and basket-button state are reset\n        // to their server-rendered defaults. Re-sync both from the current JS state.\n        this.element.addEventListener('d3r.live.replaced', () => {\n            this.hasInteracted = true;\n            this.availableSteps = this.discoverAvailableSteps();\n            this.stepLabels = this.buildStepLabels();\n            this.cacheElements();\n            this.currentStep = this.element.getAttribute('data-auto-open-step');\n            this.syncShortDesktopLiteMode();\n            this.updateNavLabels();\n            this.syncBasketButtonState();\n        });\n\n        window.addEventListener('resize', this.handleResize);\n    }\n\n    /**\n     * Opens an inline option information dialog without allowing the click to\n     * bubble into the parent LivePage chooser trigger.\n     *\n     * @param {Element} button\n     * @param {Event} event\n     */\n    openInlineOptionInfoDialog(button, event) {\n        event.preventDefault();\n        event.stopPropagation();\n\n        const target = button.getAttribute('data-target');\n\n        if (!target) {\n            return;\n        }\n\n        const modifiers =\n            button.getAttribute('data-modifiers')?.split(',').filter(Boolean) ??\n            [];\n\n        Dialog.render(target, {\n            modifiers,\n            wait_for_scripts: true,\n        });\n    }\n\n    syncBasketButtonState() {\n        const actions = this.element.querySelector(\n            '.dynamic-config-bar__actions'\n        );\n\n        if (\n            this.configuratorState === 'on-configurator' ||\n            (this.isMTO && (this.hasInteracted || this.isShortDesktopLite))\n        ) {\n            actions?.classList.add('is-addBasket');\n        } else {\n            actions?.classList.remove('is-addBasket');\n        }\n    }\n\n    watchConfiguratorState() {\n        watchConfiguratorState(state => {\n            this.configuratorState = state;\n            this.syncShortDesktopLiteMode();\n\n            if (state === 'on-configurator') {\n                this.element?.classList.add('is-on-configurator');\n                if (!this.currentStep) {\n                    this.showSteps();\n                }\n            } else {\n                this.element?.classList.remove('is-on-configurator');\n                if (this.currentStep) {\n                    return;\n                } else if (this.isMTO && this.hasInteracted) {\n                    this.showSteps();\n                } else if (this.isShortDesktopLite) {\n                    this.showSteps();\n                } else {\n                    this.showInitial();\n                }\n            }\n\n            this.syncBasketButtonState();\n        });\n    }\n\n    syncShortDesktopLiteMode() {\n        const wasShortDesktopLite = this.isShortDesktopLite;\n        const isShortDesktop = isShortDesktopViewport();\n\n        this.isShortDesktopLite = this.isLitePdp && isShortDesktop;\n        this.element.classList.toggle(\n            shortDesktopLiteClass,\n            this.isShortDesktopLite\n        );\n\n        if (this.isShortDesktopLite) {\n            if (!this.currentStep) {\n                this.showSteps();\n            }\n        } else if (wasShortDesktopLite && !this.currentStep) {\n            if (\n                this.configuratorState === 'on-configurator' ||\n                (this.isMTO && this.hasInteracted)\n            ) {\n                this.showSteps();\n            } else {\n                this.showInitial();\n            }\n        }\n\n        this.syncBasketButtonState();\n    }\n\n    showInitial() {\n        this.currentStep = null;\n        this.header?.toggleAttribute('hidden', false);\n        // Non-MTO: always show steps, hide meta regardless of configurator slide state\n        this.availability?.toggleAttribute('hidden', !this.isMTO);\n        this.stepsContainer?.toggleAttribute('hidden', this.isMTO);\n        this.contentContainer?.toggleAttribute('hidden', true);\n        this.element.classList.remove(\n            'dynamic-config-bar--expanded',\n            'dynamic-config-bar--step-open'\n        );\n    }\n\n    showSteps() {\n        this.currentStep = null;\n        this.header?.toggleAttribute('hidden', false);\n        this.availability?.toggleAttribute('hidden', true);\n        this.stepsContainer?.toggleAttribute('hidden', false);\n        this.contentContainer?.toggleAttribute('hidden', true);\n\n        this.element.classList.add('dynamic-config-bar--expanded');\n        this.element.classList.remove('dynamic-config-bar--step-open');\n    }\n\n    openStep(stepName) {\n        if (!this.availableSteps.includes(stepName)) return;\n\n        this.currentStep = stepName;\n        this.header?.toggleAttribute('hidden', true);\n        this.availability?.toggleAttribute('hidden', true);\n        this.stepsContainer?.toggleAttribute('hidden', true);\n        this.contentContainer?.toggleAttribute('hidden', false);\n\n        const stepContents = this.element.querySelectorAll(\n            '[data-dynamic-config-step-content]'\n        );\n\n        stepContents.forEach(el => {\n            el.toggleAttribute(\n                'hidden',\n                el.dataset.dynamicConfigStepContent !== stepName\n            );\n        });\n\n        this.updateNavLabels();\n        this.element.classList.add(\n            'dynamic-config-bar--expanded',\n            'dynamic-config-bar--step-open'\n        );\n    }\n\n    isInlineStep(stepButton) {\n        return stepButton.dataset.dynamicConfigInline === 'true';\n    }\n\n    navigateStep(direction) {\n        if (!this.currentStep) return;\n\n        const currentIndex = this.availableSteps.indexOf(this.currentStep);\n        let newIndex = currentIndex + direction;\n\n        if (newIndex < 0) {\n            newIndex = this.availableSteps.length - 1;\n        } else if (newIndex >= this.availableSteps.length) {\n            newIndex = 0;\n        }\n\n        const nextStepName = this.availableSteps[newIndex];\n        const stepButton = this.element.querySelector(\n            `[data-dynamic-config-step=\"${nextStepName}\"]`\n        );\n\n        if (stepButton) {\n            stepButton.click();\n        } else {\n            this.openStep(nextStepName);\n        }\n    }\n\n    updateNavLabels() {\n        if (!this.currentStep) return;\n\n        const currentIndex = this.availableSteps.indexOf(this.currentStep);\n        const prevIndex =\n            currentIndex > 0\n                ? currentIndex - 1\n                : this.availableSteps.length - 1;\n        const nextIndex =\n            currentIndex < this.availableSteps.length - 1\n                ? currentIndex + 1\n                : 0;\n\n        const prevLabel = this.element.querySelector('[data-step-prev-label]');\n        const nextLabel = this.element.querySelector('[data-step-next-label]');\n\n        if (prevLabel) {\n            prevLabel.textContent = `Choose ${\n                this.stepLabels[this.availableSteps[prevIndex]]\n            }`;\n        }\n        if (nextLabel) {\n            nextLabel.textContent = `Choose ${\n                this.stepLabels[this.availableSteps[nextIndex]]\n            }`;\n        }\n    }\n\n    goToConfiguratorSlide() {\n        if (!this.slider) return;\n\n        const lastSlideIndex = this.slider.totalSlides - 1;\n        this.slider.goToSlide(lastSlideIndex);\n    }\n}\n\nexport const init = slider => {\n    const bar = document.querySelector('[data-dynamic-config-bar]');\n\n    if (bar) {\n        new DynamicConfigBar(bar, slider);\n    }\n};\n","export const init = () => {\n    // Step up/down via delegated clicks — no QuantityStepper instances needed\n    document.addEventListener('click', e => {\n        const btn = e.target.closest(\n            '[data-qty-variant-trigger] [data-quantity]'\n        );\n        if (!btn) return;\n\n        const container = btn.closest('[data-qty-variant-trigger]');\n        const input = container.querySelector('input[type=\"number\"]');\n        if (!input) return;\n\n        if (btn.dataset.quantity === 'increase') {\n            input.stepUp();\n        } else if (btn.dataset.quantity === 'decrease') {\n            input.stepDown();\n        }\n\n        input.dispatchEvent(new Event('change', { bubbles: true }));\n    });\n\n    // Debounced variant reload on change\n    document.addEventListener('change', e => {\n        const container = e.target.closest('[data-qty-variant-trigger]');\n        if (!container) return;\n\n        const bar = container.closest(\n            '[data-configuration-bar-v2], [data-dynamic-config-bar], [data-config-panel]'\n        );\n        if (!bar) return;\n\n        const qty = parseInt(\n            container.querySelector('input[type=\"number\"]')?.value ?? '1',\n            10\n        );\n        const qtyUrlname = container.dataset.qtyUrlname;\n\n        clearTimeout(container._qtyDebounce);\n        container._qtyDebounce = setTimeout(() => {\n            triggerVariantReload(container, qtyUrlname, qty);\n        }, 250);\n    });\n};\n\nconst triggerVariantReload = (container, qtyUrlname, qty) => {\n    const lpTrigger = container.querySelector('[data-qty-lp-trigger]');\n    if (!lpTrigger) return;\n\n    const [url, searchParams] = lpTrigger\n        .closest('[data-qty-variant-trigger]')\n        .getAttribute('data-qty-url')\n        .split('?');\n    const params = new URLSearchParams(searchParams);\n    params.set(qtyUrlname, qty);\n\n    console.log(url);\n    console.log(params.toString());\n    console.log(`${url}?${params.toString()}`);\n\n    lpTrigger.setAttribute('lp-get', `${url}?${params.toString()}`);\n    lpTrigger.click();\n};\n","const legacyPdpTabTracking = Object.freeze({\n    materials: {\n        category: 'pdp/need-to-know',\n        action: 'Link Click',\n        label: 'Product',\n    },\n    dimensions: {\n        category: 'pdp/dimensions',\n        action: 'Link Click',\n        label: 'Product',\n    },\n});\n\nconst trackedOptionKinds = Object.freeze([\n    'colour',\n    'colour-global',\n    'finish',\n    'fragrance',\n    'material',\n    'material-global',\n    'option',\n    'size',\n    'variant',\n]);\n\n/**\n * Get the tracking action for the current PDP configurator style.\n *\n * @param {string} action\n * @param {Document|HTMLElement} root\n * @returns {string}\n */\nconst getPdpStyleAction = (action, root = null) => {\n    const selector =\n        '#pdpV2[data-configurator-style], .product-details[data-configurator-style]';\n    const pdp = root?.matches?.(selector)\n        ? root\n        : root?.querySelector?.(selector);\n\n    return pdp?.dataset?.configuratorStyle === 'lite'\n        ? `${action}-lite`\n        : action;\n};\n\n/**\n * Get the legacy PDP tracking payload for a PDP v2 tab slug.\n *\n * @param {string} tabSlug\n * @returns {object|null}\n */\nexport const getLegacyPdpTabTracking = tabSlug => {\n    const tracking = legacyPdpTabTracking[tabSlug];\n\n    return tracking ? { ...tracking } : null;\n};\n\n/**\n * Get the legacy PDP chooser event payload for a PDP v2 LivePage option URL.\n *\n * @param {string} requestUrl\n * @param {object} options\n * @param {Document|HTMLElement} options.root\n * @returns {object|null}\n */\nexport const getLegacyPdpOptionSelectTracking = (\n    requestUrl,\n    { root = typeof document !== 'undefined' ? document : null } = {}\n) => {\n    const url = new URL(requestUrl, 'https://www.loaf.test');\n    const match = url.pathname.match(\n        /^\\/_\\/api\\/v2\\/product\\/[^/]+\\/variant\\/([^/]+)$/\n    );\n    const optionKind = match ? decodeURIComponent(match[1]) : null;\n\n    if (!optionKind || !trackedOptionKinds.includes(optionKind)) {\n        return null;\n    }\n\n    const optionValue = url.searchParams.get(optionKind);\n\n    if (!optionValue) {\n        return null;\n    }\n\n    return {\n        category: 'pdp/chooser',\n        action: getPdpStyleAction('select configure', root),\n        label: optionKind,\n        value: optionValue,\n    };\n};\n\n/**\n * Get the legacy PDP chooser open event payload for a PDP v2 LivePage popover URL.\n *\n * @param {string} requestUrl\n * @param {object} options\n * @param {Document|HTMLElement} options.root\n * @returns {object|null}\n */\nexport const getLegacyPdpOptionOpenTracking = (\n    requestUrl,\n    { root = typeof document !== 'undefined' ? document : null } = {}\n) => {\n    const url = new URL(requestUrl, 'https://www.loaf.test');\n    const match = url.pathname.match(\n        /^\\/_\\/api\\/v2\\/product\\/[^/]+\\/variant\\/([^/]+)$/\n    );\n    const optionKind = match ? decodeURIComponent(match[1]) : null;\n\n    if (!optionKind) {\n        return null;\n    }\n\n    return {\n        category: 'pdp/chooser-open',\n        action: getPdpStyleAction('open', root),\n        label: optionKind,\n    };\n};\n\n/**\n * Get the legacy PDP upsell event payload from PDP v2 tracking attributes.\n *\n * @param {HTMLElement|null} element\n * @returns {object|null}\n */\nexport const getLegacyPdpUpsellTracking = element => {\n    if (\n        !element?.dataset ||\n        !('pdpV2UpsellTracking' in element.dataset)\n    ) {\n        return null;\n    }\n\n    const { pdpV2UpsellAction, pdpV2UpsellLabel, pdpV2UpsellValue } =\n        element.dataset;\n\n    if (!pdpV2UpsellAction || !pdpV2UpsellLabel || !pdpV2UpsellValue) {\n        return null;\n    }\n\n    return {\n        category: 'pdp/upsell',\n        action: pdpV2UpsellAction,\n        label: pdpV2UpsellLabel,\n        value: pdpV2UpsellValue,\n    };\n};\n\n/**\n * Get the PDP v2 Customise event payload from tracking attributes.\n *\n * @param {HTMLElement|null} element\n * @returns {object|null}\n */\nexport const getPdpV2CustomiseTracking = element => {\n    if (\n        !element?.dataset ||\n        !('pdpV2CustomiseTracking' in element.dataset)\n    ) {\n        return null;\n    }\n\n    const { pdpV2CustomiseItemCategory, pdpV2CustomiseItemId } =\n        element.dataset;\n\n    if (!pdpV2CustomiseItemCategory || !pdpV2CustomiseItemId) {\n        return null;\n    }\n\n    return {\n        category: 'pdp/customise',\n        action: 'click',\n        label: pdpV2CustomiseItemCategory,\n        value: pdpV2CustomiseItemId,\n    };\n};\n\n/**\n * Find the clicked element matching a selector.\n *\n * @param {Event} event\n * @param {string} selector\n * @returns {HTMLElement|null}\n */\nconst getClickedElement = (event, selector) => {\n    const target = event.target;\n\n    if (!target || typeof target.closest !== 'function') {\n        return null;\n    }\n\n    return target.closest(selector);\n};\n\n/**\n * Initialise PDP v2-specific tracking events that map new UI controls to\n * legacy PDP event payloads.\n *\n * @param {object} options\n * @param {Document|HTMLElement} options.root\n * @param {(event: object) => void} options.trackEvent\n * @returns {void}\n */\nexport const initPdpV2Tracking = ({\n    root = document,\n    trackEvent,\n} = {}) => {\n    if (!root || typeof trackEvent !== 'function') {\n        return;\n    }\n\n    root.addEventListener('click', event => {\n        const upsellTracking = getLegacyPdpUpsellTracking(\n            getClickedElement(event, '[data-pdp-v2-upsell-tracking]')\n        );\n\n        if (upsellTracking) {\n            trackEvent(upsellTracking);\n            return;\n        }\n\n        const customiseTracking = getPdpV2CustomiseTracking(\n            getClickedElement(event, '[data-pdp-v2-customise-tracking]')\n        );\n\n        if (customiseTracking) {\n            trackEvent(customiseTracking);\n            return;\n        }\n\n        const tabButton = getClickedElement(event, '[data-tab-button]');\n        const tabTracking = tabButton?.dataset?.tabButton\n            ? getLegacyPdpTabTracking(tabButton.dataset.tabButton)\n            : null;\n\n        if (tabTracking) {\n            trackEvent(tabTracking);\n            return;\n        }\n\n        const popoverButton = getClickedElement(\n            event,\n            '[popovertarget][lp-get]'\n        );\n        const openTracking = popoverButton?.getAttribute('lp-get')\n            ? getLegacyPdpOptionOpenTracking(\n                  popoverButton.getAttribute('lp-get'),\n                  { root }\n              )\n            : null;\n\n        if (openTracking) {\n            trackEvent(openTracking);\n            return;\n        }\n\n        const livePageButton = getClickedElement(event, '[lp-get]');\n        const optionTracking = livePageButton?.getAttribute('lp-get')\n            ? getLegacyPdpOptionSelectTracking(\n                  livePageButton.getAttribute('lp-get'),\n                  { root }\n              )\n            : null;\n\n        if (optionTracking) {\n            trackEvent(optionTracking);\n        }\n    });\n};\n","import Request, { Options } from 'live-page/request';\n\nconst LOAD_PARAM = 'load';\nconst LOAD_TOP = 'top';\nconst LOAD_BOTTOM = 'bottom';\nconst SCROLL_THRESHOLD = 8;\nconst SWAP_MODES = [\n    'innerHTML',\n    'outerHTML',\n    'beforebegin',\n    'afterend',\n    'afterbegin',\n    'beforeend',\n    'morph:innerHTML',\n    'morph:outerHTML',\n];\n\nlet pendingBottomUrl = null;\nlet scrollStart = 0;\nlet bottomRequest = null;\n\nconst getVariantUrl = element => {\n    if (!(element instanceof Element)) {\n        return null;\n    }\n\n    const requestUrl = element.getAttribute('lp-get') ?? '';\n\n    if (\n        !requestUrl.includes('/variant') ||\n        requestUrl.includes('/variant/qty') ||\n        requestUrl.includes('qty-only=1') ||\n        element.matches('[data-apply-fabric-btn]') ||\n        element.matches('[data-qty-lp-trigger]')\n    ) {\n        return null;\n    }\n\n    const url = new URL(requestUrl, window.location.origin);\n\n    if (url.searchParams.get(LOAD_PARAM) === LOAD_BOTTOM) {\n        return null;\n    }\n\n    return url;\n};\n\nconst stopWaitingForScroll = () => {\n    window.removeEventListener('scroll', loadPendingBottomContent);\n};\n\nconst getSwapMode = target => {\n    const swap = target.getAttribute('lp-swap');\n\n    if (swap && SWAP_MODES.includes(swap)) {\n        return swap;\n    }\n\n    if (swap) {\n        console.error('Invalid lp-swap mode: ' + swap);\n    }\n\n    return 'innerHTML';\n};\n\nconst morphSwap = async (target, html, type) => {\n    const { Idiomorph } = await import('idiomorph@0.7');\n\n    Idiomorph.morph(target, html, {\n        morphStyle: type,\n    });\n};\n\nconst swapTarget = async (target, html, mode) => {\n    try {\n        if (mode === 'morph:innerHTML') {\n            await morphSwap(target, html, 'innerHTML');\n            return;\n        }\n\n        if (mode === 'morph:outerHTML') {\n            await morphSwap(target, html, 'outerHTML');\n            return;\n        }\n    } catch (error) {\n        mode = mode.replace('morph:', '');\n        console.error(\n            'Morph failed, falling back to ' + mode + ' swap.',\n            error\n        );\n    }\n\n    if (mode === 'outerHTML') {\n        target.outerHTML = html;\n        return;\n    }\n\n    if (['beforebegin', 'afterend', 'afterbegin', 'beforeend'].includes(mode)) {\n        target.insertAdjacentHTML(mode, html);\n        return;\n    }\n\n    target.innerHTML = html;\n};\n\n/**\n * Get the connected element that should receive post-swap lifecycle events.\n *\n * @param {Element} target Original swap target.\n * @returns {Element} Connected replacement target.\n */\nconst getConnectedSwapTarget = target => {\n    if (target.isConnected) {\n        return target;\n    }\n\n    const swapId = target.getAttribute('lp-swap-id');\n\n    if (!swapId) {\n        return target;\n    }\n\n    return document.querySelector(`[lp-swap-id=\"${swapId}\"]`) ?? target;\n};\n\nconst replaceSwapTarget = async (target, html) => {\n    const event = new CustomEvent('d3r.live.replace', {\n        cancelable: true,\n        detail: {\n            html,\n            mode: getSwapMode(target),\n        },\n    });\n\n    target.dispatchEvent(event);\n\n    if (event.defaultPrevented) {\n        return;\n    }\n\n    target.classList.toggle('lp-swapping', true);\n    await swapTarget(target, event.detail.html, event.detail.mode);\n    const connectedTarget = getConnectedSwapTarget(target);\n    connectedTarget.classList.toggle('lp-swapping', false);\n    connectedTarget.dispatchEvent(\n        new CustomEvent('d3r.live.replaced', { bubbles: true })\n    );\n    connectedTarget.classList.toggle('lp-settling', true);\n    setTimeout(() => {\n        connectedTarget.classList.toggle('lp-settling', false);\n        connectedTarget.dispatchEvent(\n            new CustomEvent('d3r.live.settled', { bubbles: true })\n        );\n    }, 20);\n};\n\nconst performSwaps = async payload => {\n    const root = document.querySelector('#pdpV2');\n\n    if (!root || !payload?.swaps) {\n        return;\n    }\n\n    for (const [swapId, html] of Object.entries(payload.swaps)) {\n        if (swapId === 'default') {\n            continue;\n        }\n\n        const target = root.querySelector(`[lp-swap-id=\"${swapId}\"]`);\n\n        if (target) {\n            await replaceSwapTarget(target, html);\n        }\n    }\n};\n\nconst cancelBottomRequest = () => {\n    bottomRequest?.cancel();\n    bottomRequest = null;\n};\n\nconst loadPendingBottomContent = () => {\n    if (!pendingBottomUrl || window.scrollY <= scrollStart + SCROLL_THRESHOLD) {\n        return;\n    }\n\n    const url = pendingBottomUrl;\n    pendingBottomUrl = null;\n    stopWaitingForScroll();\n\n    const options = new Options(url.pathname + url.search);\n    const request = new Request(options);\n    bottomRequest = request;\n    request\n        .fire(async json => performSwaps(json.payload))\n        .catch(() => {})\n        .finally(() => {\n            if (bottomRequest === request) {\n                bottomRequest = null;\n            }\n        });\n};\n\nexport const initDeferredVariantContent = () => {\n    // Keep variant selection fast by loading below-the-fold variant content only after scroll.\n    document.addEventListener(\n        'd3r.live.requesting',\n        event => {\n            const url = getVariantUrl(event.target);\n\n            if (!url) {\n                return;\n            }\n\n            cancelBottomRequest();\n\n            event.detail.options.url = withLoadParam(url, LOAD_TOP);\n            url.searchParams.set(LOAD_PARAM, LOAD_BOTTOM);\n            pendingBottomUrl = url;\n            scrollStart = window.scrollY;\n\n            stopWaitingForScroll();\n            window.addEventListener('scroll', loadPendingBottomContent, {\n                passive: true,\n            });\n        },\n        { capture: true }\n    );\n};\n\nconst withLoadParam = (url, load) => {\n    const scopedUrl = new URL(url, window.location.origin);\n    scopedUrl.searchParams.set(LOAD_PARAM, load);\n\n    return scopedUrl.pathname + scopedUrl.search;\n};\n","import VideoPlayer from '../../../vendor/d3r/cloudinary/resources/javascript/src/video-player';\n\nconst initialisedVideos = new WeakSet();\nconst videoSelector = '[data-product-grid-video], .product-grid__video';\n\n/**\n * Initialise Cloudinary video players inside the PDP detail-shot grid.\n */\nexport const initProductGridVideos = () => {\n    initVideos(document);\n\n    document.addEventListener('d3r.live.replaced', event => {\n        if (!(event.target instanceof Element)) {\n            return;\n        }\n\n        initVideos(event.target);\n    });\n};\n\n/**\n * Initialise unprocessed videos within a DOM scope.\n *\n * @param {ParentNode} scope\n */\nconst initVideos = scope => {\n    scope.querySelectorAll(videoSelector).forEach(container => {\n        const video = container.querySelector('.cld-video-player');\n\n        if (!video || initialisedVideos.has(video)) {\n            return;\n        }\n\n        initialisedVideos.add(video);\n        forceAutoplay(video);\n        video.addEventListener(\n            'canplay',\n            () => container.classList.add('product-grid__video--ready'),\n            { once: true }\n        );\n        new VideoPlayer(video);\n    });\n};\n\n/**\n * Force product grid videos to use the autoplay behaviour expected for this slot.\n *\n * @param {HTMLVideoElement} video\n */\nconst forceAutoplay = video => {\n    video.autoplay = true;\n    video.controls = false;\n    video.loop = true;\n    video.muted = true;\n\n    video.setAttribute('autoplay', '');\n    video.setAttribute('data-cld-autoplay', 'true');\n    video.setAttribute('data-cld-controls', 'false');\n    video.setAttribute('loop', '');\n    video.setAttribute('data-cld-loop', 'true');\n    video.setAttribute('muted', '');\n    video.setAttribute('data-cld-muted', 'true');\n\n    const sources = JSON.parse(video.dataset.sources || '{}');\n\n    Object.values(sources).forEach(options => {\n        options.autoplay = true;\n        options.controls = false;\n        options.loop = true;\n        options.muted = true;\n    });\n\n    video.dataset.sources = JSON.stringify(sources);\n};\n","import lightGallery from 'lightgallery';\nimport lgZoom from 'lightgallery/plugins/zoom';\n\nlet bumpGallery = null;\nlet bumpGalleryElement = null;\n\n/**\n * Initialise delegated bump image lightbox handling.\n *\n * PDP v2 can replace the hero and hidden gallery through live swaps, so the\n * gallery instance is created lazily from the current hidden gallery element.\n *\n * @return {void}\n */\nexport const initBumpLightGallery = () => {\n    document.addEventListener('click', event => {\n        const target =\n            event.target instanceof Element\n                ? event.target\n                : event.target?.parentElement;\n        const trigger = target?.closest('[data-lightgallery-bump-button]');\n\n        if (!trigger) {\n            return;\n        }\n\n        const currentGalleryElement = document.querySelector(\n            '[data-lightgallery-bump]'\n        );\n\n        if (!currentGalleryElement) {\n            return;\n        }\n\n        event.preventDefault();\n\n        if (bumpGalleryElement !== currentGalleryElement) {\n            bumpGallery?.destroy();\n            bumpGalleryElement = currentGalleryElement;\n            bumpGallery = lightGallery(bumpGalleryElement, {\n                plugins: [lgZoom],\n                speed: 250,\n                selector: '.lightgallerybump',\n            });\n        }\n\n        bumpGallery.openGallery();\n    });\n};\n","import Dialog from 'dialog';\nimport {\n    initializeShackOverlay,\n    sortShowroomsByPostcode,\n} from './shack-overlay';\n\nlet hasSearchedForShack = false;\nlet lastSearchedShackPostcode = '';\n\nconst openShackOverlay = (url, { postcode = '', geolocate = false } = {}) => {\n    if (!url) {\n        return;\n    }\n\n    Dialog.load(url, {\n        modifiers: ['sidebar', 'product-info'],\n        transition_duration: 100,\n        callback: function (dialog) {\n            const root = dialog?.content ?? this?.content ?? document;\n            const { showroomsArray, showroomLookupForm } =\n                initializeShackOverlay(root);\n\n            showroomLookupForm?.addEventListener('submit', () => {\n                const value = showroomLookupForm\n                    .querySelector('input[name=\"postcode\"]')\n                    ?.value.trim();\n\n                if (value) {\n                    lastSearchedShackPostcode = value;\n                }\n            });\n\n            if (postcode) {\n                const input = showroomLookupForm?.querySelector(\n                    'input[name=\"postcode\"]'\n                );\n\n                if (input) {\n                    input.value = postcode;\n                }\n\n                window.requestAnimationFrame(() => {\n                    sortShowroomsByPostcode(\n                        showroomLookupForm,\n                        showroomsArray,\n                        root\n                    );\n                });\n            } else if (geolocate) {\n                window.requestAnimationFrame(() => {\n                    root.querySelector('button[data-geolocation]')?.click();\n                });\n            }\n        },\n        stack: true,\n    });\n};\n\nconst setShackSearchCompleted = (postcode = '') => {\n    hasSearchedForShack = true;\n\n    if (postcode) {\n        lastSearchedShackPostcode = postcode;\n    }\n\n    updateInlineShackSearchState();\n};\n\nconst updateInlineShackSearchState = (root = document) => {\n    root.querySelectorAll('[data-inline-shack-search-container]').forEach(\n        container => {\n            container\n                .querySelector('[data-inline-shack-search]')\n                ?.toggleAttribute('hidden', hasSearchedForShack);\n            container\n                .querySelector('[data-inline-shack-searched-button]')\n                ?.toggleAttribute('hidden', !hasSearchedForShack);\n        }\n    );\n};\n\nconst runInlineShackSearch = search => {\n    const input = search.querySelector('input[name=\"postcode\"]');\n    const postcode = input?.value.trim();\n\n    if (!postcode) {\n        input?.focus();\n        return;\n    }\n\n    setShackSearchCompleted(postcode);\n    openShackOverlay(search.dataset.url, { postcode });\n};\n\nconst handleInlineShackSubmitClick = event => {\n    if (!(event.target instanceof Element)) {\n        return;\n    }\n\n    const button = event.target.closest('[data-inline-shack-submit]');\n\n    if (!button) {\n        return;\n    }\n\n    const search = button.closest('[data-inline-shack-search]');\n\n    if (search) {\n        runInlineShackSearch(search);\n    }\n};\n\nconst handleInlineShackKeydown = event => {\n    if (!(event.target instanceof Element)) {\n        return;\n    }\n\n    const search = event.target.closest('[data-inline-shack-search]');\n\n    if (!search || event.key !== 'Enter') {\n        return;\n    }\n\n    event.preventDefault();\n    runInlineShackSearch(search);\n};\n\nconst handleInlineShackReopenClick = event => {\n    if (!(event.target instanceof Element)) {\n        return;\n    }\n\n    const button = event.target.closest('[data-inline-shack-searched-button]');\n\n    if (!button) {\n        return;\n    }\n\n    const url = button.dataset.url;\n\n    if (!url) {\n        return;\n    }\n\n    openShackOverlay(url, { postcode: lastSearchedShackPostcode });\n};\n\nconst handleInlineShackGeolocationClick = event => {\n    if (!(event.target instanceof Element)) {\n        return;\n    }\n\n    const button = event.target.closest('[data-inline-shack-geolocation]');\n\n    if (!button) {\n        return;\n    }\n\n    const search = button.closest('[data-inline-shack-search]');\n\n    if (!search) {\n        return;\n    }\n\n    setShackSearchCompleted();\n    openShackOverlay(search.dataset.url, { geolocate: true });\n};\n\nconst handleInlineShackFragmentReplace = event => {\n    const root =\n        typeof event.target?.querySelectorAll === 'function'\n            ? event.target\n            : document;\n\n    updateInlineShackSearchState(root);\n};\n\nexport const initInlineShackSearch = () => {\n    updateInlineShackSearchState();\n\n    document.removeEventListener('click', handleInlineShackSubmitClick);\n    document.addEventListener('click', handleInlineShackSubmitClick);\n\n    document.removeEventListener('keydown', handleInlineShackKeydown);\n    document.addEventListener('keydown', handleInlineShackKeydown);\n\n    document.removeEventListener('click', handleInlineShackReopenClick);\n    document.addEventListener('click', handleInlineShackReopenClick);\n\n    document.removeEventListener('click', handleInlineShackGeolocationClick);\n    document.addEventListener('click', handleInlineShackGeolocationClick);\n\n    document.removeEventListener(\n        'd3r.live.replaced',\n        handleInlineShackFragmentReplace\n    );\n    document.addEventListener(\n        'd3r.live.replaced',\n        handleInlineShackFragmentReplace\n    );\n};\n","// @ts-check\n\nimport { onDOMContentLoaded } from './util/loaded';\nimport { setEditInCpUrl } from './util/url';\nimport ConfiguratorSlider from './pdp/configurator/config-slider';\nimport { initDimensions } from './pdp/dimensions';\nimport { initCylindo } from './pdp/cylindo';\nimport {\n    initGalleryCylindoViewer,\n    initCylindoLiveReplace,\n} from './pdp/gallery/cylindo';\nimport { init as initPhotoSwipe } from './pdp/photoswipe-gallery';\nimport { init as initPopover } from './pdp/configurator/popover';\nimport { init as initGotoConfigurator } from './pdp/configurator/goto-configurator';\nimport { init as initUpsellOverlay } from './pdp/configurator/upsell';\nimport { init as initConfigurationBar } from './pdp/configurator/configuration-bar';\nimport { init as initDynamicConfigBar } from './pdp/configurator/dynamic-config-bar';\nimport { initSwatchButtons } from './swatch/initSwatchButton';\nimport { init as initLpQtyChooser } from './pdp/lp-qty-chooser';\nimport { initQuickAddBar } from './pdp/quick-add-overlay';\nimport { initFinance } from './pdp/finance/index';\nimport { initPayPalMessaging } from './pdp/paypal-messaging.mjs';\nimport { initBasketFormDelegation } from './features/basket';\nimport { initInfo } from './pdp/info-overlays';\nimport { initTracking } from './pdp/tracking';\nimport { initPdpV2Tracking } from './pdp/v2-tracking.mjs';\nimport { initDeferredVariantContent } from './pdp/deferred-variant-content';\nimport { initProductGridVideos } from './pdp/product-grid-video';\nimport { initBumpLightGallery } from './pdp/bump-light-gallery';\nimport { initInlineShackSearch } from './pdp/inline-shack-search';\nimport { trackD3REvent } from './util/tracking';\n\n// Initialise bits when the DOM and deferred scripts have loaded.\nonDOMContentLoaded(() => {\n    let slider = new ConfiguratorSlider();\n    let pendingVariantSelection = null;\n    let heroReplacementFrame = null;\n    let shouldReturnToFinalSlide = false;\n    let shouldScrollToPageTop = false;\n    let shouldSkipScrollToPageTop = false;\n    let shouldReinitialiseHeroSlider = false;\n    let heroLiveReplacementController = null;\n\n    const getLivePageVariantSelectionContext = trigger => {\n        const requestUrl = trigger.getAttribute('lp-get') ?? '';\n\n        if (\n            !requestUrl.includes('/variant') ||\n            requestUrl.includes('/variant/qty') ||\n            requestUrl.includes('qty-only=1') ||\n            new URL(requestUrl, window.location.origin).searchParams.get(\n                'load'\n            ) === 'bottom' ||\n            trigger.matches('[data-qty-lp-trigger]') ||\n            trigger.closest('.is-active')\n        ) {\n            return null;\n        }\n\n        return {\n            usesMobileCallout: Boolean(\n                trigger.closest('[data-dynamic-config-bar]')\n            ),\n        };\n    };\n\n    document.addEventListener(\n        'd3r.live.requesting',\n        event => {\n            if (!(event.target instanceof Element)) {\n                return;\n            }\n\n            const context = getLivePageVariantSelectionContext(event.target);\n\n            if (context) {\n                pendingVariantSelection = context;\n            }\n        },\n        { capture: true }\n    );\n\n    const schedulePostVariantSelectionUpdate = ({\n        reinitialiseHeroSlider = false,\n    } = {}) => {\n        const variantSelection = pendingVariantSelection;\n\n        shouldReturnToFinalSlide =\n            shouldReturnToFinalSlide ||\n            slider.getState().isLastSlide ||\n            Boolean(variantSelection);\n        shouldScrollToPageTop =\n            shouldScrollToPageTop || shouldReturnToFinalSlide;\n        shouldSkipScrollToPageTop =\n            shouldSkipScrollToPageTop ||\n            Boolean(variantSelection?.usesMobileCallout);\n        shouldReinitialiseHeroSlider =\n            shouldReinitialiseHeroSlider || reinitialiseHeroSlider;\n\n        if (heroReplacementFrame) {\n            window.cancelAnimationFrame(heroReplacementFrame);\n        }\n\n        heroReplacementFrame = window.requestAnimationFrame(() => {\n            heroReplacementFrame = null;\n\n            if (shouldReinitialiseHeroSlider) {\n                slider.destroy();\n                slider = new ConfiguratorSlider();\n                initGotoConfigurator(slider);\n                bindHeroLiveReplacementListeners();\n            }\n\n            const replacedHero = document.querySelector('#configurator-hero');\n            initSwatchButtons(replacedHero);\n\n            if (shouldReturnToFinalSlide && replacedHero) {\n                const finalSlideIndex = slider.totalSlides - 1;\n\n                slider.goToSlide(finalSlideIndex, true);\n                slider.handleSlideChange(finalSlideIndex);\n            }\n\n            if (shouldScrollToPageTop && !shouldSkipScrollToPageTop) {\n                window.scrollTo({ top: 0, behavior: 'smooth' });\n            }\n\n            const configBar = document.querySelector(\n                '[data-configuration-bar-v2]'\n            );\n            if (configBar) {\n                setEditInCpUrl(configBar.dataset.stockItemId);\n            }\n\n            pendingVariantSelection = null;\n            shouldReturnToFinalSlide = false;\n            shouldScrollToPageTop = false;\n            shouldSkipScrollToPageTop = false;\n            shouldReinitialiseHeroSlider = false;\n        });\n    };\n\n    /**\n     * Bind direct LivePage replacement listeners for hero swaps that do not bubble.\n     */\n    const bindHeroLiveReplacementListeners = () => {\n        heroLiveReplacementController?.abort();\n        heroLiveReplacementController = new AbortController();\n\n        const options = {\n            signal: heroLiveReplacementController.signal,\n        };\n        const hero = document.querySelector('#configurator-hero');\n        const slides = document.querySelector(\n            '[lp-swap-id=\"configuratorHeroSlides\"]'\n        );\n\n        hero?.addEventListener(\n            'd3r.live.replaced',\n            () => {\n                schedulePostVariantSelectionUpdate({\n                    reinitialiseHeroSlider: true,\n                });\n            },\n            options\n        );\n\n        slides?.addEventListener(\n            'd3r.live.replaced',\n            () => {\n                schedulePostVariantSelectionUpdate({\n                    reinitialiseHeroSlider: true,\n                });\n            },\n            options\n        );\n    };\n\n    const isConfiguratorHeroSlideListReplacement = target =>\n        target instanceof Element &&\n        (target.matches('[lp-swap-id=\"configuratorHeroSlides\"]') ||\n            Boolean(target.closest('[lp-swap-id=\"configuratorHeroSlides\"]')));\n\n    document.addEventListener(\n        'd3r.live.replaced',\n        event => {\n            if (!pendingVariantSelection) {\n                return;\n            }\n\n            schedulePostVariantSelectionUpdate({\n                reinitialiseHeroSlider: isConfiguratorHeroSlideListReplacement(\n                    event.target\n                ),\n            });\n        },\n        { capture: true }\n    );\n\n    document.addEventListener(\n        'd3r.live.error',\n        event => {\n            if (!pendingVariantSelection) {\n                return;\n            }\n\n            const error = event.detail?.error;\n            const isPostSwapLivePageError =\n                error instanceof ReferenceError &&\n                error.message.includes('e is not defined');\n\n            if (isPostSwapLivePageError) {\n                schedulePostVariantSelectionUpdate();\n                return;\n            }\n\n            pendingVariantSelection = null;\n        },\n        { capture: true }\n    );\n\n    initBasketFormDelegation();\n    initCylindo();\n    initGalleryCylindoViewer();\n    initCylindoLiveReplace();\n    initPhotoSwipe();\n    initPopover();\n    initGotoConfigurator(slider);\n    initUpsellOverlay();\n    initConfigurationBar();\n    initDynamicConfigBar(slider);\n    initDimensions();\n    initLpQtyChooser();\n    initFinance();\n    initPayPalMessaging();\n    initTracking();\n    initPdpV2Tracking({ trackEvent: trackD3REvent });\n    initQuickAddBar();\n    initInfo();\n    initInlineShackSearch();\n    initDeferredVariantContent();\n    initProductGridVideos();\n    initBumpLightGallery();\n    /**\n     * Re-initialise the configurator slider when the hero content is replaced via D3R live, to ensure it continues to function correctly. If the user was on the last slide before replacement, keep them on the last slide after re-initialisation.\n     */\n    const hero = document.querySelector('#configurator-hero');\n    initSwatchButtons(hero);\n    bindHeroLiveReplacementListeners();\n});\n"],"x_google_ignoreList":[3],"mappings":"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"}