{"version":3,"file":"kioskV2.js","names":["history"],"sources":["../resources/javascript/kioskV2/animate-index.js","../resources/javascript/kioskV2/search/hit.js","../resources/javascript/kioskV2/search.js","../resources/javascript/kioskV2/my-items.js","../resources/javascript/kioskV2/screensaver.js","../resources/javascript/kioskV2/pdp/page.js","../resources/javascript/kioskV2/pdp/chooser.js","../resources/javascript/kioskV2/cylindo.js","../resources/javascript/kioskV2/pdp/gallery-configure.js","../resources/javascript/kioskV2/pdp/item-chooser.js","../resources/javascript/kioskV2/pdp/sidebar-filter.js","../resources/javascript/kioskV2/pdp/product-config.js","../resources/javascript/kioskV2/pdp/family-popover.js","../resources/javascript/kioskV2/pdp/product-configurator.js","../resources/javascript/kioskV2/pdp/view-switcher.js","../resources/javascript/kioskV2/pdp.js","../resources/javascript/kioskV2/back-button.js","../resources/javascript/kioskV2.js"],"sourcesContent":["export const initAnimateIndex = () => {\n    const animateElements = document.querySelectorAll('[data-animate]');\n\n    animateElements.forEach(element => {\n        const delay = parseInt(element.dataset.delay) ?? 0;\n\n        setTimeout(() => {\n            element.classList.add('animate-in');\n        }, delay);\n    });\n};\n","import { formatGBP } from '../../util/price';\nimport { urlForEnvironment } from '../../util/url';\n\n// NB: self-closing tags must include the closing slash, to avoid teh template breaking.\nexport function itemTemplate(hit, { html }) {\n    const {\n        image,\n        price,\n        price_was,\n        product_title,\n        stock_item_url,\n        is_on_offer,\n    } = hit;\n\n    const url = urlForEnvironment(\n        stock_item_url.replace('/products/', '/kiosk-product-page/')\n    );\n\n    let showWasPrice = price_was && price_was > price;\n\n    const promotion_active = window.Loaf?.promotionActive ?? false;\n\n    let currentPrice = price;\n\n    if (is_on_offer && !promotion_active) {\n        showWasPrice = false;\n        currentPrice = price_was;\n    }\n\n    return html`\n        <a href=\"${url}\" class=\"configurator-item__link\">\n            <figure class=\"configurator-item__image\">\n                <img src=\"${image}\" alt=\"\" />\n            </figure>\n            <h3 class=\"configurator-item__title\">${product_title}</h3>\n            <div class=\"configurator-item__price\">\n                <div\n                    class=\"product-prices product-prices--small product-prices--short\"\n                >\n                    <span\n                        class=\"product-prices__price product-prices__price--now\"\n                    >\n                        ${formatGBP(currentPrice)}\n                    </span>\n                    ${showWasPrice\n                        ? html`\n                              <div class=\"product-prices__price--was--wrapper\">\n                                  <span\n                                      class=\"product-prices__price product-prices__price--was\"\n                                  >\n                                      ${formatGBP(price_was)}\n                                  </span>\n                              </div>\n                          `\n                        : undefined}\n                </div>\n            </div>\n        </a>\n    `;\n}\n\nexport function noResultsTemplate(_, { html }) {\n    const template = document.getElementById('no-results');\n\n    if (template instanceof HTMLTemplateElement) {\n        return template.innerHTML;\n    } else {\n        return html`<p>No results found</p>`;\n    }\n}\n","import Dialog from 'dialog';\nimport {\n    debouncedQueryHook,\n    getAlgoliaConfig,\n    getAlgoliaSearchClient,\n} from '../features/search/algolia';\nimport { history } from 'instantsearch.js/es/lib/routers';\nimport {\n    hits,\n    pagination,\n    searchBox,\n    stats,\n} from 'instantsearch.js/es/widgets';\nimport instantsearch from 'instantsearch.js';\nimport { pageTitle } from '../util/page';\nimport { itemTemplate, noResultsTemplate } from './search/hit';\nimport { iconArrowLeft, iconArrowRight } from '../components/svgs';\n\nexport const initSearchOverlay = () => {\n    const searchOverlayButton = document.querySelector('[data-open-search]');\n\n    searchOverlayButton?.addEventListener('click', e => {\n        e.preventDefault();\n\n        Dialog.load('/search', {\n            modifiers: ['takeover', 'search'],\n            callback: () => {\n                const input = document.querySelector('.search__input');\n\n                if (input instanceof HTMLInputElement) {\n                    input.focus();\n                }\n            },\n        });\n    });\n};\n\nexport const getSearchPageURL = ({ query, page }) => {\n    const url = new URL('/search/results', window.location.href);\n\n    if (query) url.searchParams.set('q', query);\n    if (Number.isInteger(page) && page !== 1)\n        url.searchParams.set('page', page);\n\n    return url;\n};\n\nexport const makeHits = (container, templates) =>\n    hits({\n        container,\n        templates: {\n            item: itemTemplate,\n            empty: noResultsTemplate,\n            ...templates,\n        },\n        cssClasses: {\n            list: ['configurator-content__listing'],\n            item: ['configurator-item'],\n        },\n    });\n\nexport const initialiseAlgoliaSearch = container => {\n    const { indexes } = getAlgoliaConfig();\n    const indexName = indexes.stockitems;\n    const searchClient = getAlgoliaSearchClient();\n\n    const search = instantsearch({\n        indexName,\n        searchClient,\n        routing: {\n            router: history({\n                windowTitle({ query }) {\n                    return pageTitle(\n                        query ? `Search results for \"${query}\"` : 'Search'\n                    );\n                },\n                createURL({ routeState }) {\n                    const { query, page } = routeState;\n\n                    const url = getSearchPageURL({ query, page });\n\n                    return url.toString();\n                },\n                parseURL({ location }) {\n                    const url = new URL(location);\n\n                    return {\n                        query: url.searchParams.get('q') ?? '',\n                        page: url.searchParams.get('page') ?? 1,\n                    };\n                },\n            }),\n            stateMapping: {\n                stateToRoute(uiState) {\n                    const indexUiState = uiState[indexName] ?? {};\n                    const { query, page } = indexUiState;\n\n                    return {\n                        query,\n                        page,\n                    };\n                },\n                routeToState({ query, page }) {\n                    return {\n                        [indexName]: {\n                            query,\n                            page,\n                        },\n                    };\n                },\n            },\n        },\n    });\n\n    const headerTitle = document.querySelector('.header__title');\n\n    const statsContainer = document.createElement('div');\n\n    if (headerTitle) {\n        headerTitle.appendChild(statsContainer);\n    }\n\n    const scrollToContainer = document.querySelector('main');\n\n    const hitsContainer = document.createElement('div');\n    container.appendChild(hitsContainer);\n\n    const paginationContainer = document.createElement('div');\n    container.appendChild(paginationContainer);\n\n    search.addWidgets([\n        stats({\n            container: statsContainer,\n            templates: {\n                text({ nbHits, query }, { html }) {\n                    return query\n                        ? html`\n                              <span id=\"search-stats\"\n                                  >Showing ${nbHits}\n                                  product${nbHits !== 1 ? 's' : ''}</span\n                              >\n                          `\n                        : '';\n                },\n            },\n        }),\n\n        searchBox({\n            container: container,\n            searchAsYouType: false,\n            showReset: false,\n            showSubmit: false,\n            showLoadingIndicator: false,\n            cssClasses: {\n                form: ['d3r-hidden'],\n            },\n            queryHook: debouncedQueryHook,\n        }),\n\n        makeHits(hitsContainer),\n\n        pagination({\n            container: paginationContainer,\n            showFirst: false,\n            showLast: false,\n            templates: {\n                previous() {\n                    return iconArrowLeft;\n                },\n                next() {\n                    return iconArrowRight;\n                },\n            },\n            cssClasses: {\n                root: ['listing__pagination'],\n                noRefinementRoot: ['listing__pagination--hidden'],\n                list: ['pagination'],\n                item: ['pagination__button'],\n                selectedItem: ['pagination__button--current'],\n                disabledItem: ['pagination__button--disabled'],\n            },\n            scrollTo: scrollToContainer,\n        }),\n    ]);\n\n    search.start();\n};\n","import { loadMyItemsOverlay } from '../features/kiosk-shortlist';\nimport { trackShortlistCompare } from './ga4-tracking';\n\nexport const initMyItemsOverlay = () => {\n    const button = document.querySelector('[data-open-my-items]');\n\n    button?.addEventListener('click', e => {\n        e.preventDefault();\n\n        loadMyItemsOverlay();\n    });\n\n    trackShortlistCompare();\n};\n","import Dialog from 'dialog';\nimport { trackSessionStart } from './ga4-tracking';\n\n/**\n * Kiosk Screensaver Module\n * Uses overlay system and simplified event handling\n * Supports both mouse and touch events for kiosk environments\n */\n\n// Module state\nlet state = {\n    options: {\n        inactivityTimeout: 300000, // 5 minutes default\n        countdownDuration: 59, // 59 seconds countdown\n        screensaverUrl: '/kiosk-inactivity',\n        redirectUrl: '/screen-saver',\n    },\n    isActive: false,\n    inactivityTimer: null,\n    countdownTimer: null,\n    countdownValue: 59,\n    overlayActive: false,\n    countdownElement: null,\n    abortController: null,\n};\n\n// Initialize the screensaver\nexport const initScreensaver = (options = {}) => {\n    // Don't initialize if we're already on the screensaver page\n    if (window.location.pathname === '/screen-saver') {\n        trackSessionStart();\n        return;\n    }\n\n    // Merge options\n    state.options = { ...state.options, ...options };\n    state.countdownValue = state.options.countdownDuration;\n\n    setupEventListeners();\n    resetInactivityTimer();\n};\n\n// Set up activity detection listeners\nconst setupEventListeners = () => {\n    // Activity detection using passive listeners and event delegation\n    const activityEvents = [\n        'pointerdown',\n        'pointermove',\n        'pointerup', // Modern pointer events cover mouse, touch, pen\n        'keydown',\n        'wheel',\n        'scroll',\n    ];\n\n    const controller = new AbortController();\n    state.abortController = controller;\n\n    activityEvents.forEach(event => {\n        document.addEventListener(event, handleActivity, {\n            passive: true,\n            capture: true,\n            signal: controller.signal,\n        });\n    });\n};\n\n// Handle clicks within the overlay\nconst handleOverlayClick = event => {\n    const action = event.target.dataset.action;\n\n    if (!action) {\n        return;\n    }\n\n    switch (action) {\n        case 'go-back':\n            hideScreensaver();\n            break;\n        case 'new-session':\n            startNewSession();\n            break;\n    }\n};\n\n// Handle user activity\nconst handleActivity = () => {\n    if (state.isActive) {\n        return; // Don't reset if screensaver is active\n    }\n\n    resetInactivityTimer();\n};\n\n// Reset the inactivity timer\nconst resetInactivityTimer = () => {\n    // Clear existing timer\n    if (state.inactivityTimer) {\n        clearTimeout(state.inactivityTimer);\n    }\n\n    // Set new timer\n    state.inactivityTimer = setTimeout(() => {\n        showScreensaver();\n    }, state.options.inactivityTimeout);\n};\n\n// Show the screensaver overlay\nconst showScreensaver = () => {\n    if (state.isActive || state.overlayActive) return;\n\n    state.isActive = true;\n    state.overlayActive = true;\n    state.countdownValue = state.options.countdownDuration;\n\n    // Load screensaver overlay\n    Dialog.load(state.options.screensaverUrl, {\n        modifiers: ['takeover', 'screensaver'],\n        callback: function () {\n            // Set up overlay event listeners\n            setupOverlayListeners(this.target);\n\n            // Start countdown\n            startCountdown();\n        },\n    });\n};\n\n// Hide the screensaver\nconst hideScreensaver = () => {\n    if (!state.isActive) {\n        return;\n    }\n\n    state.isActive = false;\n    state.overlayActive = false;\n\n    // Clear countdown\n    if (state.countdownTimer) {\n        clearInterval(state.countdownTimer);\n    }\n\n    Dialog.close();\n\n    // Reset activity timer\n    resetInactivityTimer();\n};\n\n// Set up listeners for overlay content\nconst setupOverlayListeners = overlayTarget => {\n    overlayTarget?.addEventListener('click', handleOverlayClick);\n\n    // Find countdown element in overlay\n    state.countdownElement = overlayTarget?.querySelector(\n        '.inactivity__countdown'\n    );\n};\n\n// Start the countdown timer\nconst startCountdown = () => {\n    state.countdownTimer = setInterval(() => {\n        state.countdownValue--;\n        updateCountdown();\n\n        if (state.countdownValue <= 0) {\n            handleCountdownExpired();\n        }\n    }, 1000);\n};\n\n// Update countdown display\nconst updateCountdown = () => {\n    if (state.countdownElement) {\n        state.countdownElement.textContent = state.countdownValue;\n    }\n};\n\n// Handle countdown expiration\nconst handleCountdownExpired = () => {\n    // Clear countdown\n    if (state.countdownTimer) {\n        clearInterval(state.countdownTimer);\n    }\n\n    // Redirect to screen-saver index page\n    redirectToScreensaver();\n};\n\n// Redirect to screensaver page\nconst redirectToScreensaver = () => {\n    // Clear any stored data\n    clearSession();\n\n    // Redirect to screen-saver index page\n    window.location.href = state.options.redirectUrl;\n};\n\n// Start a new session\nconst startNewSession = () => {\n    // Clear any stored data\n    clearSession();\n\n    // Hide screensaver\n    hideScreensaver();\n\n    // Redirect to home\n    if (window.location.pathname !== state.options.redirectUrl) {\n        window.location.href = state.options.redirectUrl;\n    }\n};\n\n// Clear session data\nconst clearSession = () => {\n    // Clear localStorage items related to kiosk session\n    const keysToRemove = [];\n\n    keysToRemove.forEach(key => {\n        try {\n            localStorage.removeItem(key);\n            sessionStorage.removeItem(key);\n        } catch (e) {\n            console.warn(`Failed to clear ${key}:`, e);\n        }\n    });\n};\n","export const pdpDataEvent = 'loaf-pdp-data';\n\nlet loadAbortController;\n\nexport const loadPageData = async pageUrl => {\n    loadAbortController?.abort();\n    loadAbortController = new AbortController();\n\n    const pathParts = pageUrl.pathname.split('/');\n    const productUrlname = pathParts[pathParts.length - 1];\n\n    const apiURL = new URL(\n        `/_/api/v1/product/${encodeURIComponent(productUrlname)}/variant`,\n        window.location.href\n    );\n    apiURL.searchParams.set('view', 'kiosk-pdp');\n\n    for (const [k, v] of pageUrl.searchParams) {\n        apiURL.searchParams.set(k, v);\n    }\n\n    // Sort query parameters, for increased cache-hit rate.\n    apiURL.searchParams.sort();\n\n    const response = await fetch(apiURL, {\n        redirect: 'error',\n        signal: loadAbortController.signal,\n    });\n\n    if (!response.ok) return;\n\n    const data = await response.json();\n\n    //Check if page url currently has a hash value, if so add it end of new URL before reload\n    if (pageUrl.hash) {\n        data.url = data.url + document.location.hash;\n    }\n\n    const newURL = new URL(data.url, window.location.href);\n    if (newURL.toString() !== window.location.href) {\n        history.pushState({}, undefined, newURL.toString());\n    }\n\n    document.body.dispatchEvent(\n        new CustomEvent(pdpDataEvent, {\n            detail: data,\n            bubbles: true,\n        })\n    );\n};\n","import { applyOptionsToUrl } from '../../pdp/chooser/chooser-helpers';\nimport { loadPageData } from './page';\n\nexport const initChoosers = () => {\n    const galleryApplyFabric = document.querySelector('[data-apply-fabric-js]');\n    const tryInStore = document.querySelector('[data-try-in-store-js]');\n\n    if (galleryApplyFabric instanceof HTMLElement) {\n        galleryApplyFabric.addEventListener('click', () => {\n            const colour = galleryApplyFabric.dataset.colour;\n            const url = new URL(window.location.href);\n            const options = {\n                colour: colour,\n            };\n\n            applyOptionsToUrl(url, options);\n            loadPageData(url);\n        });\n    }\n\n    if (tryInStore instanceof HTMLElement) {\n        tryInStore.addEventListener('click', () => {\n            const colour = tryInStore.dataset.colour;\n            const size = tryInStore.dataset.size;\n            const url = new URL(window.location.href);\n            const options = {\n                colour: colour,\n                size: size,\n            };\n\n            applyOptionsToUrl(url, options);\n            loadPageData(url);\n        });\n    }\n};\n","export const initCylindo = () => {\n    customElements.whenDefined('cylindo-viewer').then(() => {\n        const viewer = document.querySelector('[data-360-viewer-options]');\n\n        if (!viewer) {\n            return;\n        }\n\n        const features = JSON.parse(viewer.dataset.features);\n        let decodedFeatures = {};\n\n        for (const [key, feature] of Object.entries(features) ?? {}) {\n            decodedFeatures[key] = decodeURI(feature);\n        }\n\n        viewer.features = {\n            ...viewer.features,\n            ...decodedFeatures,\n        };\n    });\n};\n","// @ts-check\n\nimport { handleFragmentInit } from '../../pdp/fragments';\nimport { replaceElementHTML } from '../../pdp/replace';\nimport { initCylindo } from '../cylindo';\nimport { initialiseSwiper } from '../../swiper/swiper.js';\n\n/**\n * Initialise the configure gallery with cylindo on the kiosk PDP.\n */\nexport const initGalleryConfigure = () => {\n    handleFragmentInit(({ replace }) => {\n        if (replace?.galleryConfigure) {\n            replaceElementHTML(\n                '.product-viewer__image',\n                replace.galleryConfigure\n            );\n            initCylindo();\n\n            const carousels = document.querySelectorAll(\n                '.product-viewer__image .swiper'\n            );\n            // This is reasonable as we exit out if a swpier alreaddy exists. Though perhaps not ideal.\n            for (const carousel of carousels ?? []) {\n                initialiseSwiper(carousel);\n            }\n        }\n    });\n\n    initCylindo();\n};\n","// @ts-check\n\nimport { handleFragmentInit } from '../../pdp/fragments';\nimport { replaceElementHTML } from '../../pdp/replace';\n\n/**\n * Initialise the item chooser on the kiosk PDP.\n * AKA \"Add to my items\"\n */\nexport const initItemChooser = () => {\n    handleFragmentInit(({ replace }) => {\n        if (replace?.addToMyItems) {\n            replaceElementHTML('.item-chooser', replace.addToMyItems);\n            document\n                .querySelector('.item-chooser__icon')\n                ?.classList.add('no-animate');\n        }\n    });\n};\n","/**\n * SidebarFilter manages a multi-step sidebar filter UI for kioskV2.\n */\nclass SidebarFilter {\n    /**\n     * Initialises the SidebarFilter instance and sets up steps.\n     */\n    constructor() {\n        this.currentStep =\n            document\n                .querySelector('[data-step]:not([hidden])')\n                ?.getAttribute('data-step') || 'colours';\n        this.steps = ['colours', 'fabrics', 'swatches'];\n        this.choices = document.querySelectorAll('.js-choice');\n        this.colourStyle =\n            document\n                .querySelector('[data-colour-button][aria-current=\"true\"]')\n                ?.getAttribute('data-colour-style') || null;\n        this.colourCategory =\n            document\n                .querySelector('[data-fabric-button][aria-current=\"true\"]')\n                ?.getAttribute('data-colour-category') || null;\n        this.hex =\n            document\n                .querySelector('[data-colour-button][aria-current=\"true\"]')\n                ?.getAttribute('data-hex') || null;\n        this.fabricTitle =\n            document.querySelector(\n                '[data-fabric-button][aria-current=\"true\"] [data-fabric-title]'\n            )?.textContent || null;\n        this.init();\n    }\n\n    /**\n     * Initialises event bindings and displays the current step.\n     */\n    init() {\n        this.bindEvents();\n        this.showStep(this.currentStep);\n    }\n\n    /**\n     * Binds click events for colour, fabric, and back buttons.\n     */\n    bindEvents() {\n        // Colour button clicks\n        document.addEventListener('click', e => {\n            if (e.target.closest('[data-colour-button]')) {\n                const colourButton = e.target.closest('[data-colour-button]');\n                const colourButtons = document.querySelectorAll(\n                    '[data-colour-button]'\n                );\n                colourButtons.forEach(button => {\n                    button.removeAttribute('aria-current');\n                });\n                colourButton.setAttribute('aria-current', 'true');\n                this.colourStyle =\n                    colourButton.getAttribute('data-colour-style');\n                this.hex = colourButton.getAttribute('data-hex');\n                this.goToStep('fabrics');\n            }\n        });\n\n        // Fabric button clicks\n        document.addEventListener('click', e => {\n            if (e.target.closest('[data-fabric-button]')) {\n                const fabricButton = e.target.closest('[data-fabric-button]');\n                const fabricButtons = document.querySelectorAll(\n                    '[data-fabric-button]'\n                );\n                fabricButtons.forEach(button => {\n                    button.removeAttribute('aria-current');\n                });\n                fabricButton.setAttribute('aria-current', 'true');\n                const titleElement = fabricButton.querySelector(\n                    '[data-fabric-title]'\n                );\n                this.fabricTitle = titleElement\n                    ? titleElement.textContent\n                    : null;\n                this.colourCategory = fabricButton.getAttribute(\n                    'data-colour-category'\n                );\n                this.goToStep('swatches');\n            }\n        });\n\n        // Back button clicks\n        document.addEventListener('click', e => {\n            const backButton = e.target.closest('[data-back-to]');\n            const targetStep = backButton?.getAttribute('data-back-to');\n\n            if (targetStep === 'fabrics') {\n                this.colourCategory = null;\n            }\n\n            this.goToStep(targetStep);\n        });\n    }\n\n    /**\n     * Navigates to the specified step if valid.\n     * @param {string} step - The step to navigate to.\n     */\n    goToStep(step) {\n        if (this.steps.includes(step)) {\n            this.currentStep = step;\n            this.showStep(step);\n        }\n    }\n\n    /**\n     * Shows the specified step and hides others.\n     * @param {string} step - The step to show.\n     */\n    showStep(step) {\n        // Hide all steps\n        document.querySelectorAll('[data-step]').forEach(element => {\n            element.setAttribute('hidden', '');\n        });\n\n        // Show current step, apply styles if needed\n        const currentStepElement = document.querySelector(\n            `[data-step=\"${step}\"]`\n        );\n\n        if (\n            step === 'fabrics' &&\n            this.hex &&\n            currentStepElement instanceof HTMLElement\n        ) {\n            this.colourCategory = null;\n            currentStepElement.style.setProperty('--fabric-colour', this.hex);\n\n            document\n                .querySelectorAll('[data-fabric-button]')\n                .forEach(element => {\n                    const colourCategory = element.getAttribute(\n                        'data-colour-category'\n                    );\n                    const countElement = element.querySelector(\n                        '.fabric-chooser__fabric-count'\n                    );\n                    const filteredChoices = this.getFilteredChoices().filter(\n                        choice => {\n                            return (\n                                choice.getAttribute('data-colour-category') ===\n                                colourCategory\n                            );\n                        }\n                    );\n\n                    if (countElement instanceof HTMLElement) {\n                        countElement.textContent = `(${filteredChoices.length.toString()})`;\n                    }\n\n                    if (filteredChoices.length > 0) {\n                        element\n                            .closest('.fabric-chooser__fabric-item')\n                            .removeAttribute('hidden');\n                    } else {\n                        element\n                            .closest('.fabric-chooser__fabric-item')\n                            .setAttribute('hidden', '');\n                    }\n                });\n        }\n\n        if (\n            step === 'swatches' &&\n            this.fabricTitle &&\n            currentStepElement instanceof HTMLElement\n        ) {\n            const titleElement = currentStepElement.querySelector(\n                '.fabric-chooser__title'\n            );\n            if (titleElement) {\n                titleElement.textContent = `Choose your ${this.fabricTitle}`;\n            }\n\n            document\n                .querySelectorAll('.fabric-chooser__swatch-item')\n                .forEach(element => {\n                    element.setAttribute('hidden', '');\n                });\n\n            this.getFilteredChoices().forEach(choice => {\n                choice\n                    .closest('.fabric-chooser__swatch-item')\n                    .removeAttribute('hidden');\n            });\n        }\n\n        if (currentStepElement instanceof HTMLElement) {\n            currentStepElement.removeAttribute('hidden');\n        }\n    }\n\n    getFilteredChoices() {\n        return Array.from(this.choices).filter(choice => {\n            const colourStyles = choice\n                .getAttribute('data-colour-styles')\n                ?.split(',')\n                .map(style => style.trim());\n            const colourCategory = choice.getAttribute('data-colour-category');\n\n            return (\n                (!this.colourStyle ||\n                    colourStyles?.includes(this.colourStyle)) &&\n                (!this.colourCategory || colourCategory === this.colourCategory)\n            );\n        });\n    }\n}\n\n/**\n * Initialises the SidebarFilter and returns the instance.\n * @returns {SidebarFilter}\n */\nexport const initSidebarFilter = () => {\n    return new SidebarFilter();\n};\n","// @ts-check\n\nimport {\n    applyOptionsToUrl,\n    initChoosersForContainer,\n} from '../../pdp/chooser/chooser-helpers';\nimport { handleFragmentInit } from '../../pdp/fragments';\nimport { initSidebarFilter } from './sidebar-filter';\nimport { loadPageData } from './page';\nimport { replaceElementHTML } from '../../pdp/replace';\n\n/**\n * Initialise the product config on the kiosk PDP.\n */\nexport const initProductConfig = () => {\n    const productConfig = document.querySelector('.product-config');\n\n    handleFragmentInit(({ replace }) => {\n        if (replace?.kioskProductConfig) {\n            replaceElementHTML('.product-config', replace.kioskProductConfig);\n            initSidebarFilter();\n            initChoices();\n            initKioskPickers();\n        }\n    });\n\n    initSidebarFilter();\n    initChoices();\n    initKioskPickers();\n};\n\n/**\n * Extract a specific option urlname from a swatch card's data-options JSON.\n *\n * @param {HTMLElement} card\n * @param {string} optionName\n * @returns {string|null}\n */\nconst getSwatchOptionValue = (card, optionName) => {\n    try {\n        const opts = JSON.parse(card.dataset.options ?? '{}');\n        return opts[optionName] || null;\n    } catch {\n        return null;\n    }\n};\n\n/**\n * Resolve active kiosk swatch card for an option.\n *\n * Primary source is the rendered active class. Fallback is the current\n * URL query parameter so reloads still preserve availability state.\n *\n * @param {Element | null} picker\n * @param {string} optionName\n * @returns {HTMLElement | null}\n */\nconst getActiveKioskSwatchCard = (picker, optionName) => {\n    const activeCard = picker?.querySelector(\n        '.kiosk-picker__swatch-card--active'\n    );\n    if (activeCard instanceof HTMLElement) {\n        return activeCard;\n    }\n\n    const selectedUrlname = new URL(window.location.href).searchParams.get(\n        optionName\n    );\n    if (!picker || !selectedUrlname) {\n        return null;\n    }\n\n    for (const el of picker.querySelectorAll('.kiosk-picker__swatch-card')) {\n        const card = /** @type {HTMLElement} */ (el);\n        if (getSwatchOptionValue(card, optionName) === selectedUrlname) {\n            return card;\n        }\n    }\n\n    return null;\n};\n\n/**\n * Initialise kiosk picker toggle (overview button → detail panel).\n *\n * Uses a single delegated listener and a simple state function:\n * - setActivePicker('colour-global') → hides all buttons, shows that panel\n * - setActivePicker(null) → shows all buttons, hides all panels (overview)\n */\nconst initKioskPickers = () => {\n    const container = document.querySelector('.product-config__buttons');\n    if (!container) return;\n\n    const colourPicker = () =>\n        container.querySelector('[data-picker-kind=\"colour-global\"]');\n    const materialPicker = () =>\n        container.querySelector('[data-picker-kind=\"material-global\"]');\n\n    // Track whether the user has explicitly selected a restricted material.\n    // On first load the default material may have limited colours, but we\n    // should show all colours until the user actively picks a material.\n    let hasExplicitMaterialRestriction = false;\n\n    /** @param {string|null} pickerName */\n    const setActivePicker = pickerName => {\n        /** @type {NodeListOf<HTMLElement>} */\n        const pickers = container.querySelectorAll('.kiosk-picker');\n        pickers.forEach(picker => {\n            const trigger = picker.querySelector('[data-picker-trigger]');\n            const panel = picker.querySelector('[data-picker-panel]');\n\n            trigger?.toggleAttribute('hidden', !!pickerName);\n            panel?.toggleAttribute(\n                'hidden',\n                picker.dataset.pickerKind !== pickerName\n            );\n\n            // if data attribiute selected style exists find all swatch cards with that style and remove hidden attribute\n            if (pickerName === 'colour-global') {\n                const selectedStyle = trigger?.dataset.selectedStyle || 9; // defaults to natural colour style if not set\n                if (selectedStyle) {\n                    const dot = picker.querySelector(\n                        `.kiosk-picker__colour-dot[data-colour-style=\"${selectedStyle}\"]`\n                    );\n                    dot?.dispatchEvent(\n                        new MouseEvent('click', { bubbles: true })\n                    );\n                }\n            }\n        });\n    };\n\n    /** Clear any pending material state */\n    const clearPendingMaterial = () => {\n        delete (/** @type {HTMLElement} */ (container).dataset.pendingMaterial);\n    };\n\n    /**\n     * Whether a material card should trigger the restricted colour flow.\n     *\n     * @param {HTMLElement} materialCard\n     * @returns {boolean}\n     */\n    const materialUsesRestrictedColourFlow = materialCard => {\n        return materialCard.dataset.notAllColours === '1';\n    };\n\n    /**\n     * Clear material-driven colour restriction.\n     *\n     * @param {boolean} reapplyAvailability\n     */\n    const clearColourRestriction = (reapplyAvailability = false) => {\n        const picker = /** @type {HTMLElement | null} */ (colourPicker());\n        if (!picker) {\n            return;\n        }\n\n        delete picker.dataset.restrictedMaterialName;\n        delete picker.dataset.restrictedColours;\n\n        picker.querySelectorAll('.kiosk-picker__swatch-card').forEach(el => {\n            const card = /** @type {HTMLElement} */ (el);\n            card.classList.remove(\n                'kiosk-picker__swatch-card--material-restricted'\n            );\n            card.removeAttribute('hidden');\n        });\n\n        const note = picker.querySelector('[data-kiosk-colour-restriction]');\n        note?.setAttribute('hidden', '');\n\n        if (reapplyAvailability) {\n            markKioskAvailability(container);\n        }\n    };\n\n    /**\n     * Restrict colour cards to a material's available colours and show note.\n     *\n     * @param {string} materialName\n     * @param {string[]} availableColours\n     */\n    const applyColourRestriction = (materialName, availableColours) => {\n        const picker = /** @type {HTMLElement | null} */ (colourPicker());\n        if (!picker || availableColours.length === 0) {\n            return;\n        }\n\n        const availableSet = new Set(availableColours);\n        picker.dataset.restrictedMaterialName = materialName || 'This fabric';\n        picker.dataset.restrictedColours = availableColours.join(',');\n\n        picker.querySelectorAll('.kiosk-picker__swatch-card').forEach(el => {\n            const card = /** @type {HTMLElement} */ (el);\n            const code = getSwatchOptionValue(card, 'colour-global');\n            const isRestrictedOut = !!(code && !availableSet.has(code));\n\n            card.classList.toggle(\n                'kiosk-picker__swatch-card--material-restricted',\n                isRestrictedOut\n            );\n            card.classList.remove('kiosk-picker__swatch-card--unavailable');\n            card.toggleAttribute('hidden', isRestrictedOut);\n        });\n\n        const note = picker.querySelector('[data-kiosk-colour-restriction]');\n        const noteText = picker.querySelector(\n            '[data-kiosk-colour-restriction-text]'\n        );\n        const showAll = picker.querySelector('[data-kiosk-colour-show-all]');\n        if (note && noteText) {\n            const count = availableSet.size ?? 4;\n            const colourCopy = count === 1 ? 'colour' : 'colours';\n            noteText.textContent = `${materialName} is available in ${count} ${colourCopy}`;\n            note.removeAttribute('hidden');\n        }\n\n        if (showAll && !showAll.dataset.kioskRestrictionBound) {\n            showAll.dataset.kioskRestrictionBound = '1';\n            showAll.addEventListener('click', e => {\n                e.preventDefault();\n                clearColourRestriction(true);\n            });\n        }\n    };\n\n    /**\n     * Open colour picker with restriction based on currently active material.\n     */\n    const applyRestrictionFromActiveMaterial = () => {\n        if (!hasExplicitMaterialRestriction) {\n            return;\n        }\n\n        const materialCard = getActiveKioskSwatchCard(\n            materialPicker(),\n            'material-global'\n        );\n        if (!materialCard) {\n            clearColourRestriction(true);\n            return;\n        }\n\n        if (!materialUsesRestrictedColourFlow(materialCard)) {\n            hasExplicitMaterialRestriction = false;\n            clearColourRestriction(true);\n            return;\n        }\n\n        const availableColours = (materialCard.dataset.availableColours || '')\n            .split(',')\n            .filter(Boolean);\n\n        if (availableColours.length === 0) {\n            clearColourRestriction(true);\n            return;\n        }\n\n        applyColourRestriction(\n            materialCard.dataset.materialName ||\n                materialCard\n                    .querySelector('.kiosk-picker__swatch-name')\n                    ?.textContent?.trim() ||\n                'This fabric',\n            availableColours\n        );\n    };\n\n    container.addEventListener('click', e => {\n        const target = /** @type {HTMLElement} */ (e.target);\n        const trigger = target.closest('[data-picker-trigger]');\n        if (trigger) {\n            const pickerName =\n                /** @type {HTMLElement} */ (trigger).dataset.pickerTrigger ??\n                null;\n\n            clearPendingMaterial();\n            if (pickerName !== 'colour-global') {\n                clearColourRestriction();\n            }\n\n            setActivePicker(pickerName);\n\n            if (pickerName === 'colour-global') {\n                applyRestrictionFromActiveMaterial();\n            }\n            return;\n        }\n\n        if (target.closest('[data-picker-close]')) {\n            clearPendingMaterial();\n            clearColourRestriction();\n            setActivePicker(null);\n            return;\n        }\n\n        const pickerNav = target.closest('[data-picker-nav]');\n        if (pickerNav) {\n            clearPendingMaterial();\n            clearColourRestriction();\n            const picker = /** @type {HTMLElement} */ (\n                pickerNav.closest('.kiosk-picker')\n            );\n            const sibling = /** @type {HTMLElement|null} */ (\n                pickerNav.dataset.pickerNav === 'prev'\n                    ? picker.previousElementSibling\n                    : picker.nextElementSibling\n            );\n            if (sibling?.dataset?.pickerKind)\n                setActivePicker(sibling.dataset.pickerKind);\n            return;\n        }\n\n        // Colour style dot → filter swatch grid\n        const styleDot = target.closest('[data-colour-style]');\n        if (styleDot) {\n            const picker = styleDot.closest('.kiosk-picker');\n            if (!picker) return;\n\n            const styleId = /** @type {HTMLElement} */ (styleDot).dataset\n                .colourStyle;\n            const dots = picker.querySelectorAll('.kiosk-picker__colour-dot');\n            const cards = picker.querySelectorAll('.kiosk-picker__swatch-card');\n            const isAlreadyActive = styleDot.classList.contains(\n                'kiosk-picker__colour-dot--active'\n            );\n            const restrictedColours = new Set(\n                /** @type {HTMLElement} */ (\n                    picker.dataset.restrictedColours || ''\n                )\n                    .split(',')\n                    .filter(Boolean)\n            );\n\n            // Toggle: clicking active dot clears filter\n            dots.forEach(d =>\n                d.classList.remove('kiosk-picker__colour-dot--active')\n            );\n\n            if (isAlreadyActive) {\n                cards.forEach(el => {\n                    const card = /** @type {HTMLElement} */ (el);\n                    const code = getSwatchOptionValue(card, 'colour-global');\n                    const restrictedOut = !!(\n                        restrictedColours.size &&\n                        code &&\n                        !restrictedColours.has(code)\n                    );\n                    card.toggleAttribute('hidden', restrictedOut);\n                });\n            } else {\n                styleDot.classList.add('kiosk-picker__colour-dot--active');\n                cards.forEach(el => {\n                    const card = /** @type {HTMLElement} */ (el);\n                    const code = getSwatchOptionValue(card, 'colour-global');\n                    const restrictedOut = !!(\n                        restrictedColours.size &&\n                        code &&\n                        !restrictedColours.has(code)\n                    );\n                    const styles =\n                        card.getAttribute('data-colour-styles')?.split(',') ||\n                        [];\n                    card.toggleAttribute(\n                        'hidden',\n                        restrictedOut || !styles.includes(styleId)\n                    );\n                });\n            }\n            return;\n        }\n    });\n\n    // Capture-phase handler: intercepts swatch card clicks for availability\n    // logic before initChoices() reads data-options in the bubble phase.\n    container.addEventListener(\n        'click',\n        e => {\n            const card = /** @type {HTMLElement} */ (e.target).closest(\n                '.kiosk-picker__swatch-card'\n            );\n            if (!card) return;\n\n            const picker = card.closest('.kiosk-picker');\n            const kind = /** @type {HTMLElement} */ (picker)?.dataset\n                ?.pickerKind;\n            if (!kind) return;\n            const isColourPicker = kind === 'colour-global';\n            const isMaterialPicker = kind === 'material-global';\n            if (!isColourPicker && !isMaterialPicker) {\n                return;\n            }\n\n            const isUnavailable = card.classList.contains(\n                'kiosk-picker__swatch-card--unavailable'\n            );\n            const pendingMaterial = /** @type {HTMLElement} */ (container)\n                .dataset.pendingMaterial;\n\n            // Case: colour card clicked while a pending material is waiting.\n            // Merge the pending material into this colour's options so the\n            // navigation includes both values.\n            if (isColourPicker && pendingMaterial) {\n                try {\n                    const options = JSON.parse(card.dataset.options);\n                    options['material-global'] = pendingMaterial;\n                    card.dataset.options = JSON.stringify(options);\n                } catch {\n                    // ignore\n                }\n                clearPendingMaterial();\n                // Let the normal initChoices() click handler proceed\n                return;\n            }\n\n            try {\n                const options = JSON.parse(card.dataset.options);\n\n                if (isMaterialPicker) {\n                    const usesRestrictedColourFlow =\n                        materialUsesRestrictedColourFlow(card);\n                    const availableColours = (\n                        card.dataset.availableColours || ''\n                    )\n                        .split(',')\n                        .filter(Boolean);\n\n                    // Materials outside the restricted flow should still resolve to a valid\n                    // colour, but they should not open the restricted colour picker UI.\n                    if (!usesRestrictedColourFlow) {\n                        hasExplicitMaterialRestriction = false;\n                        clearPendingMaterial();\n                        clearColourRestriction();\n\n                        if (isUnavailable && availableColours.length > 0) {\n                            options['colour-global'] = availableColours[0];\n                            card.dataset.options = JSON.stringify(options);\n                        }\n\n                        return;\n                    }\n\n                    // No availability data — let the normal click proceed\n                    if (availableColours.length === 0) {\n                        hasExplicitMaterialRestriction = false;\n                        clearPendingMaterial();\n                        clearColourRestriction();\n                        return;\n                    }\n\n                    const activeColourCard = getActiveKioskSwatchCard(\n                        colourPicker(),\n                        'colour-global'\n                    );\n                    const activeColourCode = activeColourCard\n                        ? getSwatchOptionValue(\n                              activeColourCard,\n                              'colour-global'\n                          )\n                        : null;\n\n                    const isCompatibleWithSelectedColour = !!(\n                        activeColourCode &&\n                        availableColours.includes(activeColourCode)\n                    );\n\n                    // Keep the normal click flow for compatible selections so PDP loads\n                    // immediately. Restrict/open colour picker only when needed.\n                    if (isCompatibleWithSelectedColour) {\n                        hasExplicitMaterialRestriction = false;\n                        clearPendingMaterial();\n                        clearColourRestriction();\n                        return;\n                    }\n\n                    e.stopPropagation();\n\n                    const materialUrlname =\n                        options['material-global'] ||\n                        getSwatchOptionValue(card, 'material-global');\n                    if (materialUrlname) {\n                        /** @type {HTMLElement} */ (\n                            container\n                        ).dataset.pendingMaterial = materialUrlname;\n                    }\n\n                    hasExplicitMaterialRestriction = true;\n                    clearColourRestriction();\n                    setActivePicker('colour-global');\n                    const pickerEl = colourPicker();\n                    if (pickerEl) {\n                        pickerEl\n                            .querySelectorAll('.kiosk-picker__colour-dot')\n                            .forEach(d =>\n                                d.classList.remove(\n                                    'kiosk-picker__colour-dot--active'\n                                )\n                            );\n\n                        applyColourRestriction(\n                            card.dataset.materialName ||\n                                card\n                                    .querySelector('.kiosk-picker__swatch-name')\n                                    ?.textContent?.trim() ||\n                                'This fabric',\n                            availableColours\n                        );\n                    }\n\n                    return;\n                }\n\n                if (isColourPicker && isUnavailable) {\n                    // Clicking unavailable colour → add first available material\n                    const materials =\n                        card.dataset.availableMaterials?.split(',') ?? [];\n                    if (materials.length) {\n                        options['material-global'] = materials[0];\n                    }\n                    card.dataset.options = JSON.stringify(options);\n                }\n            } catch {\n                // ignore\n            }\n        },\n        true\n    );\n\n    markKioskAvailability(container);\n};\n\n/**\n * Mark kiosk colour/material swatches as unavailable based on\n * the other axis's current selection.\n *\n * @param {HTMLElement} container\n */\nconst markKioskAvailability = container => {\n    const colourPicker = container.querySelector(\n        '[data-picker-kind=\"colour-global\"]'\n    );\n    const materialPicker = container.querySelector(\n        '[data-picker-kind=\"material-global\"]'\n    );\n\n    /** @type {HTMLElement|null} */\n    const activeColour = getActiveKioskSwatchCard(\n        colourPicker,\n        'colour-global'\n    );\n    /** @type {HTMLElement|null} */\n    const activeMaterial = getActiveKioskSwatchCard(\n        materialPicker,\n        'material-global'\n    );\n\n    const availableMaterialsStr =\n        activeColour?.dataset?.availableMaterials || '';\n    const availableMaterials = availableMaterialsStr\n        ? new Set(availableMaterialsStr.split(','))\n        : null;\n\n    const availableColoursStr = activeMaterial?.dataset?.availableColours || '';\n    const availableColours = availableColoursStr\n        ? new Set(availableColoursStr.split(','))\n        : null;\n\n    // Mark unavailable materials (based on selected colour)\n    if (materialPicker) {\n        materialPicker\n            .querySelectorAll('.kiosk-picker__swatch-card')\n            .forEach(el => {\n                const card = /** @type {HTMLElement} */ (el);\n                const code = getSwatchOptionValue(card, 'material-global');\n                const unavailable = !!(\n                    availableMaterials &&\n                    code &&\n                    !availableMaterials.has(code)\n                );\n                card.classList.toggle(\n                    'kiosk-picker__swatch-card--unavailable',\n                    unavailable\n                );\n                // Show tag for all materials that have a badge element, not just unavailable ones\n                const hasTag = !!card.querySelector('.kiosk-picker__tag');\n                card.classList.toggle(\n                    'kiosk-picker__swatch-card--show-tag',\n                    hasTag\n                );\n            });\n    }\n\n    // Mark unavailable colours (based on selected material)\n    if (colourPicker) {\n        const hasRestriction = !!colourPicker.dataset.restrictedColours;\n        colourPicker\n            .querySelectorAll('.kiosk-picker__swatch-card')\n            .forEach(el => {\n                const card = /** @type {HTMLElement} */ (el);\n                const code = getSwatchOptionValue(card, 'colour-global');\n                card.classList.toggle(\n                    'kiosk-picker__swatch-card--unavailable',\n                    !hasRestriction &&\n                        !!(\n                            availableColours &&\n                            code &&\n                            !availableColours.has(code)\n                        )\n                );\n            });\n    }\n};\n\nconst initChoices = () => {\n    document.querySelectorAll('.js-choice').forEach(el => {\n        if (el.tagName === 'SELECT' || el.tagName === 'INPUT') {\n            el.addEventListener('change', () => {\n                const options = JSON.parse(el.dataset.options);\n                const url = new URL(window.location.href);\n\n                applyOptionsToUrl(url, options);\n                loadPageData(url);\n            });\n        } else {\n            el.addEventListener('click', () => {\n                const options = JSON.parse(el.dataset.options);\n                const url = new URL(window.location.href);\n\n                applyOptionsToUrl(url, options);\n                loadPageData(url);\n            });\n        }\n    });\n};\n","export const initFamilyPopover = () => {\n    const dialog = document.querySelector('#family-popover');\n    const trigger = document.querySelector('[data-family-popover]');\n    const close = document.querySelector('[data-family-popover-close]');\n\n    trigger?.addEventListener('click', () => {\n        dialog.showModal();\n    });\n\n    close?.addEventListener('click', () => {\n        dialog.close();\n    });\n\n    dialog?.addEventListener('click', event => {\n        if (event.target === dialog) {\n            dialog.close();\n        }\n    });\n};\n","// @ts-check\n\nimport { applyOptionsToUrl } from '../../pdp/chooser/chooser-helpers';\nimport { handleFragmentInit } from '../../pdp/fragments';\nimport { initFamilyPopover } from './family-popover';\nimport { loadPageData } from './page';\nimport { replaceElementHTML } from '../../pdp/replace';\n\n/**\n * Initialise the product configurator on the kiosk PDP.\n */\nexport const initProductConfigurator = () => {\n    handleFragmentInit(({ replace }) => {\n        if (replace?.productConfigurator) {\n            replaceElementHTML(\n                '.product-configurator',\n                replace.productConfigurator\n            );\n            initFamilyPopover();\n            initSizeButtons();\n        }\n    });\n\n    initFamilyPopover();\n    initSizeButtons();\n};\n\nconst initSizeButtons = () => {\n    document\n        .querySelectorAll('[data-product-configurator-size-js]')\n        .forEach(button => {\n            button.addEventListener('click', () => {\n                if (button instanceof HTMLElement) {\n                    const size = button.dataset.size;\n                    const url = new URL(window.location.href);\n                    const options = {\n                        size: size,\n                    };\n\n                    applyOptionsToUrl(url, options);\n                    loadPageData(url);\n                }\n            });\n        });\n};\n","import { pdpDataEvent } from './page';\n\n/**\n * Handles switching between different views in the kiosk interface.\n */\nclass ViewSwitcher {\n    /**\n     * Creates a new ViewSwitcher instance and initialises it.\n     */\n    constructor() {\n        this.activeView = 'viewer';\n        this.init();\n    }\n\n    /**\n     * Sets up event delegation for view toggle buttons.\n     */\n    init() {\n        document.addEventListener('click', event => {\n            const toggleButton = event.target.closest('[data-view-toggle]');\n\n            if (toggleButton) {\n                event.preventDefault();\n\n                const viewName = toggleButton?.dataset.viewToggle;\n\n                // If the button has data-apply-fabric-js attribute\n                // we want to wait for the fabric to be applied before switching views\n                if (\n                    toggleButton.hasAttribute('data-apply-fabric-js') ||\n                    toggleButton.hasAttribute('data-try-in-store-js')\n                ) {\n                    // wait until page has loaded the fragments\n                    document.addEventListener(pdpDataEvent, () => {\n                        this.switchView(viewName);\n                    });\n                } else {\n                    this.switchView(viewName);\n                }\n            }\n        });\n    }\n\n    /**\n     * Switches to the specified view if it is not already active.\n     * @param {string} viewName - The name of the view to switch to.\n     */\n    switchView(viewName) {\n        if (viewName === this.activeView || !viewName) {\n            return;\n        }\n\n        this.hideAllViews();\n\n        this.toggleViewVisibility(viewName, 'view-content');\n\n        this.toggleViewVisibility(viewName, 'sidebar-content');\n\n        this.updateActiveButton(viewName);\n\n        this.activeView = viewName;\n    }\n\n    /**\n     * Hides all view and sidebar content elements.\n     */\n    hideAllViews() {\n        const allViewContent = document.querySelectorAll('[data-view-content]');\n        const allSidebarContent = document.querySelectorAll(\n            '[data-sidebar-content]'\n        );\n\n        allViewContent.forEach(element => element.setAttribute('hidden', ''));\n\n        allSidebarContent.forEach(element =>\n            element.setAttribute('hidden', '')\n        );\n    }\n\n    /**\n     * Shows the specified view or sidebar content element.\n     * @param {string} viewName - The name of the view to show.\n     * @param {string} contentType - The type of content (e.g., 'view-content' or 'sidebar-content').\n     */\n    toggleViewVisibility(viewName, contentType) {\n        const elements = document.querySelectorAll(\n            `[data-${contentType}=\"${viewName}\"]`\n        );\n\n        elements.forEach(element => element.removeAttribute('hidden'));\n    }\n\n    /**\n     * Updates the active state of view toggle buttons.\n     * @param {string} activeViewName - The name of the currently active view.\n     */\n    updateActiveButton(activeViewName) {\n        // Remove active class from all buttons\n        const allButtons = document.querySelectorAll('[data-view-toggle]');\n\n        allButtons.forEach(button => {\n            button.classList.remove('button--active');\n        });\n\n        // Add active class to the current button\n        const activeButton = document.querySelector(\n            `[data-view-toggle=\"${activeViewName}\"]`\n        );\n\n        activeButton?.classList.add('button--active');\n    }\n}\n\n/**\n * Initialises the ViewSwitcher and returns the instance.\n * @returns {ViewSwitcher}\n */\nexport const initViewSwitcher = () => {\n    return new ViewSwitcher();\n};\n","// @ts-check\n\nimport { initChoosers } from './pdp/chooser';\nimport { initGalleryConfigure } from './pdp/gallery-configure';\nimport { initItemChooser } from './pdp/item-chooser';\nimport { initProductConfig } from './pdp/product-config';\nimport { initProductConfigurator } from './pdp/product-configurator';\nimport { initViewSwitcher } from './pdp/view-switcher';\n\n// Initialise bits when the DOM and deferred scripts have loaded.\nexport const initPDP = () => {\n    initChoosers();\n    initGalleryConfigure();\n    initItemChooser();\n    initProductConfig();\n    initProductConfigurator();\n    initViewSwitcher();\n};\n","/**\n * Back button functionality for the kiosk application.\n *  - This will go back to the last listing page, since history.back() will go back through changed options.\n *\n * @returns Back button\n */\n\nexport const initHistoryBack = () => {\n    // Store the last listing page visited in localStorage\n    if (document.body.classList.contains('listing2')) {\n        localStorage.setItem('kiosk-back-url', window.location.href);\n    }\n\n    const backButton = document.querySelector('button[data-history-back]');\n\n    if (!backButton) {\n        return;\n    }\n\n    // The first page usually will have an empty referrer\n    // This is to hide the back button if there is no history\n    if (document.referrer === '') {\n        backButton.classList.add('d3r-hidden');\n    }\n\n    backButton.addEventListener('click', () => {\n        const backurl = localStorage.getItem('kiosk-back-url');\n        localStorage.removeItem('kiosk-back-url');\n\n        // If no back URL is stored for some reason, fallback to history.back()\n        if (!backurl) {\n            history.back();\n            return;\n        }\n\n        // check if the current page is a listing page\n        // if so, redirect to the home page\n        // otherwise, redirect to the stored back URL\n        if (window.location.pathname.includes('/listing/')) {\n            window.location.href = '/';\n        } else {\n            window.location.href = backurl || '/';\n        }\n    });\n};\n","import { initAnimateIndex } from './kioskV2/animate-index';\nimport { initSearchOverlay, initialiseAlgoliaSearch } from './kioskV2/search';\nimport { initMyItemsOverlay } from './kioskV2/my-items';\nimport { initScreensaver } from './kioskV2/screensaver';\nimport { initPDP } from './kioskV2/pdp';\nimport { initHistoryBack } from './kioskV2/back-button';\nimport { trackSearchResults } from './kioskV2/ga4-tracking';\n\nwindow.addEventListener('DOMContentLoaded', () => {\n    initAnimateIndex();\n    initSearchOverlay();\n    initMyItemsOverlay();\n    initScreensaver({\n        inactivityTimeout: 120000, // 2 minutes\n        countdownDuration: 59, // 59 seconds\n    });\n    initPDP();\n    initHistoryBack();\n\n    const container = document.querySelector('#kiosk-search-page');\n    if (container instanceof HTMLElement) {\n        initialiseAlgoliaSearch(container);\n        trackSearchResults();\n    }\n});\n"],"mappings":"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"}