{"version":3,"file":"client.mjs","sources":["../app/teaser-rentalcar-es.client.ts"],"sourcesContent":["/**\n * Holding Teaser Web Component - Client Component\n *\n * Self-contained vanilla TypeScript component for displaying\n * a car rental search form teaser on holding's website.\n *\n * Uses a closed Shadow DOM with a default <slot> so published-widget checks pass\n * and light-DOM markup stays addressable for the interactive bundle (getElementById).\n * Shared styles are injected into the document head.\n *\n * @author CHECK24 Vergleichsportal Mietwagen GmbH\n */\n\n/// <reference path=\"../.check24-home/types/client.d.ts\" />\n\nimport type { HomeClientComponentElement, HomeClientComponentProps, UserInfo } from '@types/client';\nimport type { Language } from '@types/check24';\n\n// Portal IDs for React component mounting\nconst TEASER_PORTAL_DESTINATION_RADIOS = 'teaser-es-portal-destination-radios';\nconst TEASER_PORTAL_DATEPICKER = 'teaser-es-portal-datepicker';\nconst TEASER_PORTAL_AUTOCOMPLETER = 'teaser-es-portal-autocompleter';\nconst TEASER_PORTAL_TIMEPICKER_PICKUP = 'teaser-es-portal-timepicker-pickup-time';\nconst TEASER_PORTAL_TIMEPICKER_DROPOFF = 'teaser-es-portal-timepicker-dropoff-time';\nconst TEASER_PORTAL_DRIVERAGE = 'teaser-es-portal-driverage';\nconst TEASER_PORTAL_SUBMIT_BUTTON = 'teaser-es-portal-submit-button';\n\n// Production hostname for API calls\nconst HOSTNAME = 'alquiler-coches.check24.es';\n\n// Style ID for deduplication\nconst STYLE_ID = 'teaser-rentalcar-es-styles';\n\n/** Viewport width from which the search form is shown (aligns with CSS @media (min-width: 960px)). */\nconst TEASER_FORM_MIN_VIEWPORT_PX = 960;\n\n/** Headline typography only: mobile up to 768px, desktop from 769px. */\nconst TEASER_HEADLINE_MOBILE_MAX_PX = 768;\nconst TEASER_HEADLINE_DESKTOP_MIN_PX = 769;\n\n// Declare global window extensions\ndeclare global {\n    interface Window {\n        HoldingTeaserEsInteractive?: {\n            initializeInteractiveComponents?: (scope?: ParentNode) => void;\n        };\n        // Shared namespace used by the bundled SearchForm/React components\n        // (Shared/assets/shared/script/get-base-url.js) to resolve their AJAX base URL.\n        c24mw?: {\n            globals?: {\n                baseUrl?: string;\n            };\n        };\n    }\n}\n\n// IDs the hosted bundle looks up via document.getElementById. When the widget is\n// nested inside an external shadow DOM (e.g. check24.de test page), those lookups\n// return null and React never mounts. We patch document.getElementById to fall\n// back to any connected widget's light-DOM tree for these specific IDs.\n// This keeps the widget compatible with the current prod bundle (no scope support)\n// and is a no-op once the bundle ships the scope-aware version.\nconst OWNED_PORTAL_IDS: ReadonlySet<string> = new Set([\n    'teaser-es-react-root',\n    TEASER_PORTAL_DESTINATION_RADIOS,\n    TEASER_PORTAL_DATEPICKER,\n    TEASER_PORTAL_AUTOCOMPLETER,\n    TEASER_PORTAL_TIMEPICKER_PICKUP,\n    TEASER_PORTAL_TIMEPICKER_DROPOFF,\n    TEASER_PORTAL_DRIVERAGE,\n    TEASER_PORTAL_SUBMIT_BUTTON,\n]);\nconst teaserWidgetRegistry: Set<Element> = new Set();\nlet documentGetElementByIdPatched = false;\n\n// Track clicks we re-dispatch to bypass the shadow-retargeted event.target, so\n// our own document listener can skip them and avoid infinite recursion.\nconst teaserReplayedClicks: WeakSet<Event> = new WeakSet();\n\nfunction patchDocumentGetElementByIdOnce(): void {\n    if (documentGetElementByIdPatched) {\n        return;\n    }\n    documentGetElementByIdPatched = true;\n    const original = document.getElementById.bind(document);\n    document.getElementById = function patchedGetElementById(elementId: string): HTMLElement | null {\n        const direct = original(elementId);\n        if (direct) {\n            return direct;\n        }\n        if (!OWNED_PORTAL_IDS.has(elementId)) {\n            return null;\n        }\n        for (const widget of teaserWidgetRegistry) {\n            const found = widget.querySelector('#' + CSS.escape(elementId));\n            if (found instanceof HTMLElement) {\n                return found;\n            }\n        }\n        return null;\n    } as typeof document.getElementById;\n}\n\n\n// .holding-teaser-link {\n//     display: flex;\n//     flex-direction: column;\n//     align-items: baseline;\n  \n//     max-width: 1080px;\n//     width: auto;\n//     height: 258px;\n//     max-height: 258px;\n//     box-sizing: content-box;\n//     position: relative;\n  \n//     padding: 50px 20px 60px;\n  \n//     text-decoration: none;\n//     color: inherit;\n  \n//     @media (min-width: 769px) {\n//       padding-left: 40px;\n//       padding-right: 40px;\n//     }\n  \n//     @media (max-width: 768px) {\n//       max-height: 200px;\n//       padding-top: 16px;\n//       padding-bottom: 16px;\n//       padding-right: 184px;\n//     }\n  \n//     @media (min-width: 1024px) {\n//       display: none;\n//     }\n//   }\n\n\n\n// Component styles (injected into document head, not Shadow DOM)\nconst styles = `\n    .holding-teaser-wrapper {\n        position: relative;\n        height: 360px;\n        display: flex;\n        align-items: center;\n        justify-content: center;\n        padding: 40px 20px;\n        box-sizing: border-box;\n    }\n    \n    /* Headline only: mobile max-width 768px, desktop min-width 769px. Wrapper height stays body.device-mobile. */\n    .holding-teaser-wrapper .rentalcar-teaser-headline {\n        color: #ffffff;\n        height: 100%;\n        text-align: center;\n    }\n\n    @media (max-width: ${TEASER_HEADLINE_MOBILE_MAX_PX}px) {\n        .holding-teaser-wrapper .rentalcar-teaser-headline {\n            font-size: 20px;\n            line-height: 24px;\n            font-family: 'Inter', sans-serif;\n            text-align: left;\n        }\n        \n        .holding-teaser-wrapper {\n            align-items: baseline;\n            justify-content: unset;\n        }\n    }\n\n    @media (min-width: ${TEASER_HEADLINE_DESKTOP_MIN_PX}px) {\n        .holding-teaser-wrapper .rentalcar-teaser-headline {\n            margin-top: 10px;\n            font-size: 30px;\n            line-height: 40px;\n            font-family: 'Inter', sans-serif;\n        }\n    }\n    \n    .holding-teaser-background {\n        position: absolute;\n        top: 0;\n        left: 0;\n        right: 0;\n        bottom: 0;\n        background: transparent;\n        z-index: 1;\n    }\n    \n    .teaser-form {\n        position: absolute;\n        bottom: 60px;\n        z-index: 2;\n        width: 100%;\n        max-width: 960px;\n        padding: 16px 16px 0px 16px;\n        /* Reset text-align in case an external host page (e.g. check24.de wrapping\n           the widget in a shadow DOM under a centered hero section) inherits\n           text-align: center across the shadow boundary. */\n        text-align: left;\n    }\n    \n    .teaser-destinations {\n        display: flex;\n        gap: 24px;\n        margin-bottom: 8px;\n        align-items: center;\n        margin-left: 6px;\n        padding-right: 30px;\n    }\n    \n    .teaser-radio-label {\n        display: flex;\n        align-items: center;\n        gap: 8px;\n        cursor: pointer;\n        font-size: 14px;\n        color: #ffffff;\n        font-weight: 400;\n        position: relative;\n        font-family: 'Inter', sans-serif;\n        line-height: 1;\n    }\n    \n    .teaser-radio {\n        appearance: none;\n        -webkit-appearance: none;\n        -moz-appearance: none;\n        width: 20px;\n        height: 20px;\n        cursor: pointer;\n        margin: 0;\n        position: relative;\n        background: #ffffff;\n        border: 1px solid #cccccc;\n        border-radius: 50%;\n        outline: none;\n        transition: border-color 0.2s;\n    }\n    \n    .teaser-radio:hover {\n        border-color: #0066cc;\n    }\n    \n    .teaser-radio:checked {\n        border-color: #0066cc;\n        background: #ffffff;\n    }\n    \n    .teaser-radio:checked::after {\n        content: '';\n        position: absolute;\n        top: 50%;\n        left: 50%;\n        transform: translate(-50%, -50%);\n        width: 10px;\n        height: 10px;\n        background: #0066cc;\n        border-radius: 50%;\n    }\n    \n    .teaser-form-row {\n        border-radius: calc(infinity * 1px);\n        border: 3px solid #ffbb1c;\n        display: flex;\n        align-items: center;\n        gap: 4px;\n        height: 64px;\n        padding: 0 5px;\n        box-sizing: border-box;\n        background-color: #ffffff;\n    }\n    \n    .teaser-field-autocompleter {\n        flex: 1;\n        min-width: 25%;\n        display: flex;\n        flex-direction: column;\n        position: relative;\n        font-family: 'Inter', sans-serif;\n        justify-content: center;\n        align-self: center;\n    }\n\n    .teaser-field-autocompleter-skeleton {\n        padding: 0 12px;\n        border-right: 1px solid #e0e0e0;\n    }\n\n    .teaser-field-dropoff {\n        flex-direction: row;\n    }\n    \n    .teaser-form-footer {\n        display: flex;\n        justify-content: space-between;\n        align-items: center;\n        padding-top: 12px;\n        margin-top: 12px;\n    }\n    \n    .teaser-checkbox-label {\n        display: flex;\n        align-items: center;\n        gap: 8px;\n        cursor: pointer;\n        font-size: 14px;\n        color: #333333;\n    }\n    \n    .teaser-checkbox {\n        width: 18px;\n        height: 18px;\n        cursor: pointer;\n    }\n    \n    .teaser-cancellation-info {\n        display: flex;\n        align-items: center;\n        gap: 6px;\n        font-size: 14px;\n        color: #10b981;\n        font-weight: 500;\n    }\n    \n    .teaser-form-field {\n        display: flex;\n        flex-direction: column;\n        position: relative;\n        padding: 0 12px;                  \n        border-right: 1px solid #e0e0e0;\n        font-family: 'Inter', sans-serif;\n        justify-content: center;\n        align-self: center;\n    }\n    \n    .teaser-field-label {\n        font-size: 14px;\n        color: #666666;\n        margin-bottom: 4px;\n        display: block;\n        line-height: 1;\n    }\n    \n    .teaser-field-input-wrapper {\n        position: relative;\n        width: 100%;\n    }\n    \n    .teaser-field-input,\n    .teaser-field-select {\n        width: fit-content;\n        border: none;\n        outline: none;\n        background: transparent;\n        font-size: 16px;\n        color: #181818;\n        padding: 4px 0;\n        cursor: pointer;\n        line-height: 1.2;\n        font-family: 'Inter', sans-serif;\n    }\n\n    .teaser-field-select {\n        max-width: 100%;\n    }\n    \n    .teaser-field-input::placeholder {\n        color: #999999;\n    }\n    \n    .teaser-field-select {\n        appearance: none;\n        background-image: url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 14 7\"><polygon fill=\"%23333\" points=\"6.95 4.99 1.12 0 0 0.98 6.95 6.86 14 0.98 12.88 0 6.95 4.99\"/></svg>');\n        background-repeat: no-repeat;\n        background-size: 14px 7px;\n        background-position: right center;\n        padding-right: 24px;\n        font-family: 'Inter', sans-serif;\n    }\n    \n    .teaser-field-select option {\n        font-family: 'Inter', sans-serif;\n    }\n    \n    .teaser-field-select-static {\n        pointer-events: none;\n        cursor: default;\n    }\n    \n    .teaser-field-skeleton {\n        width: 100%;\n        padding: 4px 0;\n    }\n    \n    .teaser-skeleton {\n        height: 16px;\n        border-radius: 4px;\n        background-size: 300% 100%;\n        background-position: 100% 0;\n        background-image: linear-gradient(\n            90deg,\n            rgba(239, 239, 244, 0.7) 0%,\n            rgba(239, 239, 244, 0.7) 40%,\n            rgba(239, 239, 244, 0.4) 50%,\n            rgba(239, 239, 244, 0.7) 60%,\n            rgba(239, 239, 244, 0.7) 100%\n        );\n        animation: dummy-progress 1.5s infinite linear;\n    }\n    \n    @keyframes dummy-progress {\n        0% { background-position: 100% 0; }\n        100% { background-position: 0 0; }\n    }\n    \n    .teaser-daterange-display {\n        font-size: 16px;\n        color: #181818;\n        cursor: pointer;\n        margin: 4px 0;\n        line-height: 1.2;\n    }\n    \n    .teaser-form-section-times {\n        display: flex;\n        gap: 4px;\n    }\n    \n    .teaser-field-daterange {\n        max-width: 155px;\n        min-width: fit-content;\n    }\n    \n    .teaser-field-time {\n        flex: 1;\n        min-width: 80px;\n    }\n    \n    .teaser-field-age {\n        min-width: 80px;\n        border-right: none;\n    }\n    \n    .teaser-submit-button {\n        background: #0066cc;\n        color: #ffffff;\n        border: none;\n        border-radius: 50px;\n        padding: 13px 32px;\n        font-size: 16px;\n        font-family: 'Inter', sans-serif;\n        line-height: 1.2;\n        cursor: pointer;\n        transition: background-color 0.2s;\n        white-space: nowrap;\n        height: 48px;\n        flex-shrink: 0;\n        display: flex;\n        align-items: center;\n        justify-content: center;\n    }\n    \n    .teaser-submit-button:hover {\n        background: #0052a3;\n    }\n  \n    .teaser-submit-button:disabled {\n        cursor: not-allowed;\n        opacity: 0.8;\n    }\n\n    .teaser-submit-wrapper {\n        display: contents;\n    }\n    \n    .teaser-button-spinner {\n        width: 20px;\n        height: 20px;\n        border: 2px solid rgba(255, 255, 255, 0.3);\n        border-top-color: #ffffff;\n        border-radius: 50%;\n        animation: teaser-spin 0.8s linear infinite;\n        margin-left: 5px;\n    }\n            \n    @keyframes teaser-spin {\n        to {\n            transform: rotate(360deg);\n        }\n    }\n\n    body.device-mobile .holding-teaser-wrapper {\n        height: 230px;\n    }\n`;\n\n/**\n * Teaser Rentalcar Es Client Component\n *\n * Exports the class directly as expected by CHECK24 Home.\n * The host system will call customElements.define() with this class.\n *\n * NOTE: Does NOT use Shadow DOM because the React interactive bundle\n * needs to find portal elements via document.getElementById().\n */\nexport default class TeaserRentalcarEsClient extends HTMLElement implements HomeClientComponentElement {\n    // Props from HomeClientComponentProps\n    deviceOutput: 'desktop' | 'mobile' | 'tabletapp' | 'app' = 'desktop';\n    language: Language = 'es-ES';\n    platform: 'app' | 'web' = 'web';\n    user?: UserInfo;\n\n    // Hostname for API calls (can be overridden via attribute)\n    private hostname: string = HOSTNAME;\n\n    // Internal state\n    private isReactBundleLoaded = false;\n    private isCurrentlyMobile = false;\n    private bodyClassObserver: MutationObserver | null = null;\n    private shadowStyleMirrorObserver: MutationObserver | null = null;\n    private responsiveDebounceTimer: ReturnType<typeof setTimeout> | null = null;\n    private outsideClickForwarder: ((evt: Event) => void) | null = null;\n    private outsideClickHostRoot: ShadowRoot | null = null;\n    private autocompleterClickInterceptor: ((evt: Event) => void) | null = null;\n    private onViewportResize: (() => void) | null = null;\n\n    // Optional callbacks from HomeClientComponentElement\n    onStyleLoaded?: (style: string) => void;\n    onRender?: () => void;\n\n    constructor() {\n        super();\n\n        // Pipeline requires closed Shadow DOM. Project light-DOM children via <slot>\n        // so layout/visual checks see composed content; portal IDs stay in the light tree.\n        const shadow = this.attachShadow({ mode: 'closed' });\n        shadow.innerHTML = `\n            <style>\n                :host {\n                    display: block;\n                    width: 100%;\n                    min-height: 230px;\n                    box-sizing: border-box;\n                }\n            </style>\n            <slot></slot>\n        `;\n    }\n\n    static get observedAttributes(): string[] {\n        return ['device-output', 'language', 'platform', 'user', 'data-hostname'];\n    }\n\n    attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n        if (oldValue === newValue) return;\n\n        // Handle hostname attribute\n        if (name === 'data-hostname' && newValue) {\n            this.hostname = newValue;\n        }\n\n        // Validate and set attributes using C24Home helper\n        if (typeof C24Home !== 'undefined' && C24Home.validateAttributes) {\n            const validated = C24Home.validateAttributes<HomeClientComponentProps>(this.attributes);\n            this.deviceOutput = validated.deviceOutput;\n            this.language = validated.language;\n            this.platform = validated.platform;\n            this.user = validated.user;\n        }\n\n        this.render();\n    }\n\n    connectedCallback(): void {\n        // Register this instance so the patched document.getElementById can\n        // resolve our portal IDs even when we are nested under a shadow DOM.\n        teaserWidgetRegistry.add(this);\n        patchDocumentGetElementByIdOnce();\n\n        // Shadow-DOM aware \"click outside\" bridge for bundled React components.\n        //\n        // The datepicker attaches a document-level listener that walks\n        // parentNode from evt.target to decide \"inside vs outside\". When the\n        // widget is nested inside an external shadow root, native events get\n        // retargeted to that shadow's host element when they cross the\n        // boundary, so the walk never finds the datepicker container and\n        // every click (including ones inside the picker) is treated as\n        // \"outside\". Without a fix, selecting a day immediately closes it.\n        //\n        // Retargeting works in our favor for every other click: any click\n        // outside the datepicker but anywhere on the page will be seen by\n        // the document listener as \"outside\" and correctly close the picker.\n        // The only case we must intercept is a click that actually happened\n        // inside the datepicker portal. For those we stopPropagation at the\n        // custom-element boundary so the event never reaches document with\n        // a retargeted target.\n        const datepickerClickGuard = (evt: Event): void => {\n            const datepickerPortal = this.querySelector('#' + TEASER_PORTAL_DATEPICKER);\n            if (datepickerPortal === null) {\n                return;\n            }\n            if (evt.composedPath().includes(datepickerPortal)) {\n                evt.stopPropagation();\n            }\n        };\n        this.addEventListener('click', datepickerClickGuard);\n        this.addEventListener('mousedown', datepickerClickGuard);\n\n        // When nested inside an external shadow root, clicks outside the\n        // widget but inside that shadow may never reach document: host page\n        // code often stops propagation on its own components, and shadow\n        // retargeting can hide them from document listeners. Forward those\n        // clicks so open popups close correctly.\n        const hostRoot = this.getRootNode();\n        if (hostRoot instanceof ShadowRoot) {\n            this.outsideClickHostRoot = hostRoot;\n            this.outsideClickForwarder = (evt: Event): void => {\n                if (evt.composedPath().includes(this)) {\n                    return;\n                }\n                document.dispatchEvent(\n                    new Event(evt.type, { bubbles: true, cancelable: true })\n                );\n            };\n            // Capture phase so we see the event before the host page can swallow it.\n            hostRoot.addEventListener('click', this.outsideClickForwarder, true);\n            hostRoot.addEventListener('mousedown', this.outsideClickForwarder, true);\n\n            // Shadow-DOM workaround for the autocompleter \"click suggestion\"\n            // flow. The bundled autocompleter registers a document-capture click\n            // listener that closes the dropdown whenever\n            // `rootRef.current.contains(event.target)` returns false. When the\n            // widget is hosted inside an external shadow root, the event target\n            // gets retargeted to the outer shadow host on its way to document,\n            // so `contains()` always returns false and the dropdown closes mid\n            // click, before React can run the suggestion's onClick. Pressing\n            // Enter works because it calls handleSelectedItemChanged directly.\n            //\n            // We install a capture-phase interceptor on document BEFORE the\n            // autocompleter mounts (the React bundle loads asynchronously after\n            // connectedCallback). When a click originates inside our\n            // autocompleter portal, we stop the retargeted event and\n            // re-dispatch a fresh click on the real in-shadow target. The\n            // replay keeps `event.target` inside `rootRef`, so the\n            // autocompleter's contains() check returns true and the dropdown\n            // stays open long enough for React to fire the suggestion's\n            // onClick handler.\n            this.autocompleterClickInterceptor = (evt: Event): void => {\n                if (teaserReplayedClicks.has(evt)) {\n                    return;\n                }\n                const autocompleterPortal = this.querySelector(\n                    '#' + TEASER_PORTAL_AUTOCOMPLETER\n                );\n                if (autocompleterPortal === null) {\n                    return;\n                }\n                const path = evt.composedPath();\n                if (!path.includes(autocompleterPortal)) {\n                    return;\n                }\n                const realTarget = path[0];\n                if (!(realTarget instanceof Element)) {\n                    return;\n                }\n                const mouseEvt = evt as MouseEvent;\n                evt.stopImmediatePropagation();\n                evt.preventDefault();\n                const replay = new MouseEvent('click', {\n                    bubbles: true,\n                    cancelable: true,\n                    composed: true,\n                    clientX: mouseEvt.clientX,\n                    clientY: mouseEvt.clientY,\n                    screenX: mouseEvt.screenX,\n                    screenY: mouseEvt.screenY,\n                    button: mouseEvt.button,\n                    buttons: mouseEvt.buttons,\n                    ctrlKey: mouseEvt.ctrlKey,\n                    metaKey: mouseEvt.metaKey,\n                    shiftKey: mouseEvt.shiftKey,\n                    altKey: mouseEvt.altKey,\n                });\n                teaserReplayedClicks.add(replay);\n                realTarget.dispatchEvent(replay);\n            };\n            document.addEventListener(\n                'click',\n                this.autocompleterClickInterceptor,\n                true\n            );\n        }\n\n        // Read hostname from data attribute\n        const hostnameAttr = this.getAttribute('data-hostname');\n        if (hostnameAttr) {\n            this.hostname = hostnameAttr;\n        }\n\n        // The bundled SearchForm/React components resolve their AJAX base URL via\n        // getBaseUrl() (Shared/assets/shared/script/get-base-url.js), which falls back\n        // to a hardcoded mietwagen.check24.de when window.c24mw.globals.baseUrl isn't\n        // set — there is no Spain branch. Server-rendered pages set this global via PHP\n        // (see SearchFormApi's holding_search.phtml); this widget has no such rendering\n        // context (it's embedded standalone on Holding's own domain), so it must set it\n        // itself before the interactive bundle loads.\n        window.c24mw = window.c24mw || {};\n        window.c24mw.globals = window.c24mw.globals || {};\n        window.c24mw.globals.baseUrl = window.c24mw.globals.baseUrl || `https://${this.hostname}`;\n\n        // Initialize attributes\n        if (typeof C24Home !== 'undefined' && C24Home.validateAttributes) {\n            const validated = C24Home.validateAttributes<HomeClientComponentProps>(this.attributes);\n            this.deviceOutput = validated.deviceOutput;\n            this.language = validated.language;\n            this.platform = validated.platform;\n            this.user = validated.user;\n        }\n\n        // Inject styles into document head (only once)\n        this.applyStyles();\n        \n        // Render the component (light DOM, not Shadow DOM)\n        this.render();\n        this.setupResponsiveListener();\n\n        // Defer loading React bundle until after page load completes\n        if (document.readyState === 'complete') {\n            this.loadInteractiveComponents();\n        } else {\n            window.addEventListener('load', () => {\n                this.loadInteractiveComponents();\n            });\n        }\n\n        // Notify that component has rendered\n        if (typeof this.onRender === 'function') {\n            this.onRender();\n        }\n    }\n\n    disconnectedCallback(): void {\n        teaserWidgetRegistry.delete(this);\n        if (this.bodyClassObserver) {\n            this.bodyClassObserver.disconnect();\n            this.bodyClassObserver = null;\n        }\n        if (this.shadowStyleMirrorObserver) {\n            this.shadowStyleMirrorObserver.disconnect();\n            this.shadowStyleMirrorObserver = null;\n        }\n        if (this.outsideClickHostRoot && this.outsideClickForwarder) {\n            this.outsideClickHostRoot.removeEventListener('click', this.outsideClickForwarder, true);\n            this.outsideClickHostRoot.removeEventListener('mousedown', this.outsideClickForwarder, true);\n            this.outsideClickHostRoot = null;\n            this.outsideClickForwarder = null;\n        }\n        if (this.autocompleterClickInterceptor) {\n            document.removeEventListener('click', this.autocompleterClickInterceptor, true);\n            this.autocompleterClickInterceptor = null;\n        }\n        if (this.responsiveDebounceTimer) {\n            clearTimeout(this.responsiveDebounceTimer);\n        }\n        if (this.onViewportResize) {\n            window.removeEventListener('resize', this.onViewportResize);\n            this.onViewportResize = null;\n        }\n    }\n\n    /**\n     * Inject styles into document head (not Shadow DOM)\n     * This allows React components to work with the DOM elements\n     */\n    private applyStyles(): void {\n        if (!document.getElementById(STYLE_ID)) {\n            const styleElement = document.createElement('style');\n            styleElement.id = STYLE_ID;\n            styleElement.textContent = styles;\n            document.head.appendChild(styleElement);\n\n            // Notify if callback is set\n            if (typeof this.onStyleLoaded === 'function') {\n                this.onStyleLoaded(styles);\n            }\n        }\n\n        // If the widget is nested inside an external shadow root (e.g. check24.de\n        // test page), document-level styles do not cross the shadow boundary.\n        // Inject the same styles into the hosting shadow root so skeletons, layout\n        // and React-mounted components render correctly there too.\n        const hostRoot = this.getRootNode();\n        if (hostRoot instanceof ShadowRoot) {\n            if (!hostRoot.querySelector('#' + STYLE_ID)) {\n                const shadowStyleElement = document.createElement('style');\n                shadowStyleElement.id = STYLE_ID;\n                shadowStyleElement.textContent = styles;\n                hostRoot.appendChild(shadowStyleElement);\n            }\n            this.mirrorHeadStylesIntoShadow(hostRoot);\n        }\n    }\n\n    /**\n     * Mirror <style> and <link rel=\"stylesheet\"> nodes from document.head into\n     * the hosting shadow root. React components (datepicker, autocompleter, etc.)\n     * have their CSS injected by webpack's style-loader into document.head when\n     * the lazy chunk evaluates. Those rules do not cross the shadow boundary, so\n     * we clone what's there and watch for future additions.\n     */\n    private mirrorHeadStylesIntoShadow(hostRoot: ShadowRoot): void {\n        const cloneMarker = 'data-teaser-shadow-mirrored';\n        const cloneIntoShadow = (node: Node): void => {\n            const isStyle = node instanceof HTMLStyleElement;\n            const isStylesheetLink = node instanceof HTMLLinkElement && node.rel === 'stylesheet';\n            if (!isStyle && !isStylesheetLink) {\n                return;\n            }\n            const element = node as HTMLElement;\n            if (element.id === STYLE_ID) {\n                return;\n            }\n            const cloned = element.cloneNode(true) as HTMLElement;\n            cloned.setAttribute(cloneMarker, '');\n            hostRoot.appendChild(cloned);\n        };\n\n        document.head\n            .querySelectorAll<HTMLElement>('style, link[rel=\"stylesheet\"]')\n            .forEach((node) => cloneIntoShadow(node));\n\n        if (this.shadowStyleMirrorObserver) {\n            return;\n        }\n        this.shadowStyleMirrorObserver = new MutationObserver((mutations) => {\n            mutations.forEach((mutation) => {\n                mutation.addedNodes.forEach((node) => cloneIntoShadow(node));\n            });\n        });\n        this.shadowStyleMirrorObserver.observe(document.head, { childList: true });\n    }\n\n    private render(): void {\n        // Mirror the host body's responsive class onto the widget element so\n        // selectors like `body.device-*` still match when the widget is hosted\n        // inside an external shadow root (where `body` is not a CSS ancestor of\n        // the light-DOM content).\n        this.syncHostDeviceClass();\n\n        // Below 960px viewport: show headline + link only (no search form; matches @media (min-width: 960px))\n        if (this.isNarrowViewportForSearchForm()) {\n            this.innerHTML = this.getWrapperWithBackgroundRedirect();\n            this.isCurrentlyMobile = true;\n            return;\n        }\n\n        this.isCurrentlyMobile = false;\n\n        // Render in light DOM (not Shadow DOM) so React can find elements\n        this.innerHTML = this.getWrapperWithBackground();\n\n        // If React bundle is already loaded, remount components\n        if (this.isReactBundleLoaded) {\n            this.remountInteractiveComponents();\n        }\n    }\n\n    private syncHostDeviceClass(): void {\n        const bodyClasses = document.body.classList;\n        const deviceClasses = ['device-desktop', 'device-fluid', 'device-mobile'];\n        deviceClasses.forEach((deviceClass) => {\n            const shouldHave = bodyClasses.contains(deviceClass);\n            if (shouldHave && !this.classList.contains(deviceClass)) {\n                this.classList.add(deviceClass);\n            } else if (!shouldHave && this.classList.contains(deviceClass)) {\n                this.classList.remove(deviceClass);\n            }\n        });\n    }\n\n    private isNarrowViewportForSearchForm(): boolean {\n        return window.innerWidth < TEASER_FORM_MIN_VIEWPORT_PX;\n    }\n\n    private getWrapperWithBackgroundRedirect(): string {\n        return `\n            <div class=\"holding-teaser-wrapper\">\n                <a class=\"holding-teaser-background\" href=\"https://${this.hostname}\"></a>\n                <div class=\"rentalcar-teaser-headline\"><strong>Coches de Alquiler</strong><br>Mejor precio garantizado</div>\n            </div>\n        `;\n    }\n\n    private getWrapperWithBackground(): string {\n        return `\n            <div class=\"holding-teaser-wrapper\">\n            <div class=\"holding-teaser-background\"></div>\n            <div class=\"rentalcar-teaser-headline\"><strong>Coches de Alquiler</strong><br>Mejor precio garantizado</div>\n                ${this.getStaticSearchForm()}\n            </div>\n        `;\n    }\n\n    private getPickupField(): string {\n        return `\n            <div class=\"teaser-field-autocompleter teaser-field-autocompleter-skeleton\" id=\"${TEASER_PORTAL_AUTOCOMPLETER}\">\n                <label for=\"pickup-input\" class=\"teaser-field-label\">Lugar de recogida</label>\n                <div class=\"teaser-field-input-wrapper\">\n                    <input\n                        type=\"text\"\n                        id=\"pickup-input\"\n                        placeholder=\"Ciudad o aeropuerto\"\n                        class=\"teaser-field-input\"\n                        aria-label=\"Ciudad o aeropuerto\"\n                        role=\"combobox\"\n                        aria-expanded=\"false\"\n                        aria-autocomplete=\"list\"\n                    />\n                </div>\n            </div>\n        `;\n    }\n\n    private getDestinationRadios(): string {\n        return `\n            <div class=\"teaser-destinations\" id=\"${TEASER_PORTAL_DESTINATION_RADIOS}\">\n                <label class=\"teaser-radio-label\">\n                    <input type=\"radio\" name=\"return-location\" value=\"same\" class=\"teaser-radio\" checked />\n                    <span>Devolución en el mismo lugar</span>\n                </label>\n                <label class=\"teaser-radio-label\">\n                    <input type=\"radio\" name=\"return-location\" value=\"different\" class=\"teaser-radio\" />\n                    <span>Devolución en otro lugar</span>\n                </label>\n            </div>\n        `;\n    }\n\n    private getTimeField(id: string, label: string): string {\n        return `\n            <div class=\"teaser-form-field teaser-field-time\" id=\"${id}\">\n                <label for=\"${id}\" class=\"teaser-field-label\">${label}</label>\n                <div class=\"teaser-field-skeleton\">\n                    <div class=\"teaser-skeleton\"></div>\n                </div>\n            </div>\n        `;\n    }\n\n    private getDateRangeSection(): string {\n        return `\n            <div class=\"teaser-form-field teaser-field-daterange\" id=\"${TEASER_PORTAL_DATEPICKER}\">\n                <label for=\"daterange-input\" class=\"teaser-field-label\">Periodo de alquiler</label>\n                <div class=\"teaser-field-input-wrapper teaser-field-skeleton\">\n                    <div class=\"teaser-skeleton\"></div>\n                </div>\n            </div>\n            <div class=\"teaser-form-section-times\">\n                ${this.getTimeField(TEASER_PORTAL_TIMEPICKER_PICKUP, 'Recogida')}\n                ${this.getTimeField(TEASER_PORTAL_TIMEPICKER_DROPOFF, 'Devolución')}\n            </div>\n        `;\n    }\n\n    private getDriverAgeField(): string {\n        return `\n            <div class=\"teaser-form-field teaser-field-age\" id=\"${TEASER_PORTAL_DRIVERAGE}\">\n                <label for=\"driver-age\" class=\"teaser-field-label\">Edad</label>\n                <div class=\"teaser-field-skeleton\">\n                    <div class=\"teaser-skeleton\"></div>\n                </div>\n            </div>\n        `;\n    }\n\n    private getSubmitButton(): string {\n        return `\n            <div class=\"teaser-submit-wrapper\" id=\"${TEASER_PORTAL_SUBMIT_BUTTON}\">\n                <button type=\"submit\" class=\"teaser-submit-button teaser-submit-button-skeleton\">\n                    <span>Buscar</span>\n                </button>\n            </div>\n        `;\n    }\n\n    private getStaticSearchForm(): string {\n        return `\n            <form class=\"teaser-form\">\n                ${this.getDestinationRadios()}\n                <div class=\"teaser-form-row\">\n                    ${this.getPickupField()}\n                    ${this.getDateRangeSection()}\n                    ${this.getDriverAgeField()}\n                    ${this.getSubmitButton()}\n                </div>\n                <div id=\"teaser-es-react-root\" style=\"display: none;\"></div>\n            </form>\n        `;\n    }\n\n    private async loadInteractiveComponents(): Promise<void> {\n        if (this.isNarrowViewportForSearchForm() || this.isReactBundleLoaded) {\n            return;\n        }\n\n        try {\n            const apiUrl = `https://${this.hostname}/holding-teaser-es/api/assets`;\n            const response = await fetch(apiUrl);\n\n            if (!response.ok) {\n                throw new Error(`Failed to fetch assets: ${response.status}`);\n            }\n\n            const data = await response.json();\n\n            if (!data.success || !data.assets) {\n                throw new Error('Invalid API response');\n            }\n\n            const { main } = data.assets;\n\n            if (!main) {\n                throw new Error('Main bundle URL not found in API response');\n            }\n\n            await this.loadMainBundle(main);\n        } catch (error) {\n            console.error('Holding Teaser: Failed to load interactive components', error);\n        }\n    }\n\n    private remountInteractiveComponents(): void {\n        if (window.HoldingTeaserEsInteractive?.initializeInteractiveComponents) {\n            setTimeout(() => {\n                window.HoldingTeaserEsInteractive?.initializeInteractiveComponents?.(this);\n            }, 0);\n        }\n    }\n\n    private loadMainBundle(bundleUrl: string): Promise<void> {\n        // The bundle auto-runs initializeInteractiveComponents() on load.\n        // Our patched document.getElementById lets its lookups find our portal\n        // elements even when we are nested inside an external shadow DOM.\n        return this.loadScript(bundleUrl).then(() => {\n            this.isReactBundleLoaded = true;\n        });\n    }\n\n    private loadScript(url: string): Promise<void> {\n        return new Promise((resolve, reject) => {\n            const script = document.createElement('script');\n            script.src = url;\n            script.async = true;\n            script.onload = () => resolve();\n            script.onerror = () => reject(new Error(`Failed to load script: ${url}`));\n            document.head.appendChild(script);\n        });\n    }\n\n    private setupResponsiveListener(): void {\n        // Throttle render on rapid responsive class toggles (leading: fire immediately, then at most every 100ms)\n        let lastThrottledRenderAt = 0;\n        const throttledRender = (): void => {\n            const now = Date.now();\n            if (now - lastThrottledRenderAt < 100) {\n                return;\n            }\n            lastThrottledRenderAt = now;\n            this.render();\n        };\n\n        const onViewportNarrowStateMaybeChanged = (): void => {\n            const isNarrow = this.isNarrowViewportForSearchForm();\n            if (isNarrow) {\n                throttledRender();\n                return;\n            }\n            if (isNarrow !== this.isCurrentlyMobile) {\n                if (this.responsiveDebounceTimer) {\n                    clearTimeout(this.responsiveDebounceTimer);\n                }\n                this.responsiveDebounceTimer = setTimeout(() => {\n                    this.loadInteractiveComponents().then(() => {\n                        this.render();\n                    });\n                }, 150);\n            }\n        };\n\n        this.onViewportResize = onViewportNarrowStateMaybeChanged;\n        window.addEventListener('resize', this.onViewportResize);\n\n        this.bodyClassObserver = new MutationObserver((mutations) => {\n            mutations.forEach((mutation) => {\n                if (mutation.attributeName === 'class') {\n                    // Keep the host element's device-* class in sync so the\n                    // CSS rules scoped on `.device-desktop` / `.device-fluid`\n                    // keep matching when mirrored into an external shadow\n                    // root. This is cheap and safe regardless of whether we\n                    // end up re-rendering below.\n                    this.syncHostDeviceClass();\n                    // Holding sometimes clears/reapplies body classes in one turn;\n                    // re-sync on the next frame so we do not drop device-* from\n                    // this host for a visible frame (title flash; form uses @media).\n                    requestAnimationFrame(() => this.syncHostDeviceClass());\n                    onViewportNarrowStateMaybeChanged();\n                }\n            });\n        });\n\n        this.bodyClassObserver.observe(document.body, {\n            attributes: true,\n            attributeFilter: ['class'],\n        });\n    }\n}\n\n// Register the web component tag for environments that auto-detect it from the client bundle.\n// Guarded so it won't throw if the host already registered it. ()\nif (typeof window !== 'undefined' && 'customElements' in window) {\n    if (!customElements.get('esrsnrc-default-2026')) {\n        customElements.define('esrsnrc-default-2026', TeaserRentalcarEsClient);\n    }\n}\n"],"names":["TEASER_PORTAL_DESTINATION_RADIOS","TEASER_PORTAL_DATEPICKER","TEASER_PORTAL_AUTOCOMPLETER","TEASER_PORTAL_TIMEPICKER_PICKUP","TEASER_PORTAL_TIMEPICKER_DROPOFF","TEASER_PORTAL_DRIVERAGE","TEASER_PORTAL_SUBMIT_BUTTON","STYLE_ID","OWNED_PORTAL_IDS","Set","teaserWidgetRegistry","documentGetElementByIdPatched","teaserReplayedClicks","WeakSet","styles","TeaserRentalcarEsClient","HTMLElement","deviceOutput","language","platform","user","hostname","isReactBundleLoaded","isCurrentlyMobile","bodyClassObserver","shadowStyleMirrorObserver","responsiveDebounceTimer","outsideClickForwarder","outsideClickHostRoot","autocompleterClickInterceptor","onViewportResize","onStyleLoaded","onRender","constructor","super","this","attachShadow","mode","innerHTML","observedAttributes","attributeChangedCallback","name","oldValue","newValue","C24Home","validateAttributes","validated","attributes","render","connectedCallback","add","original","document","getElementById","bind","elementId","direct","has","widget","found","querySelector","CSS","escape","patchDocumentGetElementByIdOnce","datepickerClickGuard","evt","datepickerPortal","composedPath","includes","stopPropagation","addEventListener","hostRoot","getRootNode","ShadowRoot","dispatchEvent","Event","type","bubbles","cancelable","autocompleterPortal","path","realTarget","Element","mouseEvt","stopImmediatePropagation","preventDefault","replay","MouseEvent","composed","clientX","clientY","screenX","screenY","button","buttons","ctrlKey","metaKey","shiftKey","altKey","hostnameAttr","getAttribute","window","c24mw","globals","baseUrl","applyStyles","setupResponsiveListener","readyState","loadInteractiveComponents","disconnectedCallback","delete","disconnect","removeEventListener","clearTimeout","styleElement","createElement","id","textContent","head","appendChild","shadowStyleElement","mirrorHeadStylesIntoShadow","cloneIntoShadow","node","isStyle","HTMLStyleElement","isStylesheetLink","HTMLLinkElement","rel","element","cloned","cloneNode","setAttribute","querySelectorAll","forEach","MutationObserver","mutations","mutation","addedNodes","observe","childList","syncHostDeviceClass","isNarrowViewportForSearchForm","getWrapperWithBackgroundRedirect","getWrapperWithBackground","remountInteractiveComponents","bodyClasses","body","classList","deviceClass","shouldHave","contains","remove","innerWidth","getStaticSearchForm","getPickupField","getDestinationRadios","getTimeField","label","getDateRangeSection","getDriverAgeField","getSubmitButton","apiUrl","response","fetch","ok","Error","status","data","json","success","assets","main","loadMainBundle","error","console","HoldingTeaserEsInteractive","initializeInteractiveComponents","setTimeout","bundleUrl","loadScript","then","url","Promise","resolve","reject","script","src","async","onload","onerror","lastThrottledRenderAt","throttledRender","now","Date","onViewportNarrowStateMaybeChanged","isNarrow","attributeName","requestAnimationFrame","attributeFilter","customElements","get","define"],"mappings":"AAmBA,MAAMA,EAAmC,sCACnCC,EAA2B,8BAC3BC,EAA8B,iCAC9BC,EAAkC,0CAClCC,EAAmC,2CACnCC,EAA0B,6BAC1BC,EAA8B,iCAM9BC,EAAW,6BA+BXC,qBAA4CC,IAAI,CAClD,uBACAT,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,IAEEI,qBAAyCD,IAC/C,IAAIE,GAAgC,EAIpC,MAAMC,qBAA2CC,QAgEjD,MAAMC,EAAS,uuRAgXf,MAAqBC,UAAgCC,YAEjDC,aAA2D,UAC3DC,SAAqB,QACrBC,SAA0B,MAC1BC,KAGQC,SAzeK,6BA4eLC,qBAAsB,EACtBC,mBAAoB,EACpBC,kBAA6C,KAC7CC,0BAAqD,KACrDC,wBAAgE,KAChEC,sBAAuD,KACvDC,qBAA0C,KAC1CC,8BAA+D,KAC/DC,iBAAwC,KAGhDC,cACAC,SAEA,WAAAC,GACIC,QAIeC,KAAKC,aAAa,CAAEC,KAAM,WAClCC,UAAY,0RAWvB,CAEA,6BAAWC,GACP,MAAO,CAAC,gBAAiB,WAAY,WAAY,OAAQ,gBAC7D,CAEA,wBAAAC,CAAyBC,EAAcC,EAAyBC,GAC5D,GAAID,IAAaC,EAAjB,CAQA,GALa,kBAATF,GAA4BE,IAC5BR,KAAKd,SAAWsB,GAIG,oBAAZC,SAA2BA,QAAQC,mBAAoB,CAC9D,MAAMC,EAAYF,QAAQC,mBAA6CV,KAAKY,YAC5EZ,KAAKlB,aAAe6B,EAAU7B,aAC9BkB,KAAKjB,SAAW4B,EAAU5B,SAC1BiB,KAAKhB,SAAW2B,EAAU3B,SAC1BgB,KAAKf,KAAO0B,EAAU1B,IAC1B,CAEAe,KAAKa,QAhBsB,CAiB/B,CAEA,iBAAAC,GAGIvC,EAAqBwC,IAAIf,MArfjC,WACI,GAAIxB,EACA,OAEJA,GAAgC,EAChC,MAAMwC,EAAWC,SAASC,eAAeC,KAAKF,UAC9CA,SAASC,eAAiB,SAA+BE,GACrD,MAAMC,EAASL,EAASI,GACxB,GAAIC,EACA,OAAOA,EAEX,IAAKhD,EAAiBiD,IAAIF,GACtB,OAAO,KAEX,IAAA,MAAWG,KAAUhD,EAAsB,CACvC,MAAMiD,EAAQD,EAAOE,cAAc,IAAMC,IAAIC,OAAOP,IACpD,GAAII,aAAiB3C,YACjB,OAAO2C,CAEf,CACA,OAAO,IACX,CACJ,CAgeQI,GAmBA,MAAMC,EAAwBC,IAC1B,MAAMC,EAAmB/B,KAAKyB,cAAc,IAAM3D,GACzB,OAArBiE,GAGAD,EAAIE,eAAeC,SAASF,IAC5BD,EAAII,mBAGZlC,KAAKmC,iBAAiB,QAASN,GAC/B7B,KAAKmC,iBAAiB,YAAaN,GAOnC,MAAMO,EAAWpC,KAAKqC,cAClBD,aAAoBE,aACpBtC,KAAKP,qBAAuB2C,EAC5BpC,KAAKR,sBAAyBsC,IACtBA,EAAIE,eAAeC,SAASjC,OAGhCiB,SAASsB,cACL,IAAIC,MAAMV,EAAIW,KAAM,CAAEC,SAAS,EAAMC,YAAY,MAIzDP,EAASD,iBAAiB,QAASnC,KAAKR,uBAAuB,GAC/D4C,EAASD,iBAAiB,YAAanC,KAAKR,uBAAuB,GAqBnEQ,KAAKN,8BAAiCoC,IAClC,GAAIrD,EAAqB6C,IAAIQ,GACzB,OAEJ,MAAMc,EAAsB5C,KAAKyB,cAC7B,IAAM1D,GAEV,GAA4B,OAAxB6E,EACA,OAEJ,MAAMC,EAAOf,EAAIE,eACjB,IAAKa,EAAKZ,SAASW,GACf,OAEJ,MAAME,EAAaD,EAAK,GACxB,KAAMC,aAAsBC,SACxB,OAEJ,MAAMC,EAAWlB,EACjBA,EAAImB,2BACJnB,EAAIoB,iBACJ,MAAMC,EAAS,IAAIC,WAAW,QAAS,CACnCV,SAAS,EACTC,YAAY,EACZU,UAAU,EACVC,QAASN,EAASM,QAClBC,QAASP,EAASO,QAClBC,QAASR,EAASQ,QAClBC,QAAST,EAASS,QAClBC,OAAQV,EAASU,OACjBC,QAASX,EAASW,QAClBC,QAASZ,EAASY,QAClBC,QAASb,EAASa,QAClBC,SAAUd,EAASc,SACnBC,OAAQf,EAASe,SAErBtF,EAAqBsC,IAAIoC,GACzBL,EAAWP,cAAcY,IAE7BlC,SAASkB,iBACL,QACAnC,KAAKN,+BACL,IAKR,MAAMsE,EAAehE,KAAKiE,aAAa,iBAiBvC,GAhBID,IACAhE,KAAKd,SAAW8E,GAUpBE,OAAOC,MAAQD,OAAOC,OAAS,CAAA,EAC/BD,OAAOC,MAAMC,QAAUF,OAAOC,MAAMC,SAAW,CAAA,EAC/CF,OAAOC,MAAMC,QAAQC,QAAUH,OAAOC,MAAMC,QAAQC,SAAW,WAAWrE,KAAKd,WAGxD,oBAAZuB,SAA2BA,QAAQC,mBAAoB,CAC9D,MAAMC,EAAYF,QAAQC,mBAA6CV,KAAKY,YAC5EZ,KAAKlB,aAAe6B,EAAU7B,aAC9BkB,KAAKjB,SAAW4B,EAAU5B,SAC1BiB,KAAKhB,SAAW2B,EAAU3B,SAC1BgB,KAAKf,KAAO0B,EAAU1B,IAC1B,CAGAe,KAAKsE,cAGLtE,KAAKa,SACLb,KAAKuE,0BAGuB,aAAxBtD,SAASuD,WACTxE,KAAKyE,4BAELP,OAAO/B,iBAAiB,OAAQ,KAC5BnC,KAAKyE,8BAKgB,mBAAlBzE,KAAKH,UACZG,KAAKH,UAEb,CAEA,oBAAA6E,GACInG,EAAqBoG,OAAO3E,MACxBA,KAAKX,oBACLW,KAAKX,kBAAkBuF,aACvB5E,KAAKX,kBAAoB,MAEzBW,KAAKV,4BACLU,KAAKV,0BAA0BsF,aAC/B5E,KAAKV,0BAA4B,MAEjCU,KAAKP,sBAAwBO,KAAKR,wBAClCQ,KAAKP,qBAAqBoF,oBAAoB,QAAS7E,KAAKR,uBAAuB,GACnFQ,KAAKP,qBAAqBoF,oBAAoB,YAAa7E,KAAKR,uBAAuB,GACvFQ,KAAKP,qBAAuB,KAC5BO,KAAKR,sBAAwB,MAE7BQ,KAAKN,gCACLuB,SAAS4D,oBAAoB,QAAS7E,KAAKN,+BAA+B,GAC1EM,KAAKN,8BAAgC,MAErCM,KAAKT,yBACLuF,aAAa9E,KAAKT,yBAElBS,KAAKL,mBACLuE,OAAOW,oBAAoB,SAAU7E,KAAKL,kBAC1CK,KAAKL,iBAAmB,KAEhC,CAMQ,WAAA2E,GACJ,IAAKrD,SAASC,eAAe9C,GAAW,CACpC,MAAM2G,EAAe9D,SAAS+D,cAAc,SAC5CD,EAAaE,GAAK7G,EAClB2G,EAAaG,YAAcvG,EAC3BsC,SAASkE,KAAKC,YAAYL,GAGQ,mBAAvB/E,KAAKJ,eACZI,KAAKJ,cAAcjB,EAE3B,CAMA,MAAMyD,EAAWpC,KAAKqC,cACtB,GAAID,aAAoBE,WAAY,CAChC,IAAKF,EAASX,cAAc,IAAMrD,GAAW,CACzC,MAAMiH,EAAqBpE,SAAS+D,cAAc,SAClDK,EAAmBJ,GAAK7G,EACxBiH,EAAmBH,YAAcvG,EACjCyD,EAASgD,YAAYC,EACzB,CACArF,KAAKsF,2BAA2BlD,EACpC,CACJ,CASQ,0BAAAkD,CAA2BlD,GAC/B,MACMmD,EAAmBC,IACrB,MAAMC,EAAUD,aAAgBE,iBAC1BC,EAAmBH,aAAgBI,iBAAgC,eAAbJ,EAAKK,IACjE,IAAKJ,IAAYE,EACb,OAEJ,MAAMG,EAAUN,EAChB,GAAIM,EAAQb,KAAO7G,EACf,OAEJ,MAAM2H,EAASD,EAAQE,WAAU,GACjCD,EAAOE,aAZS,8BAYiB,IACjC7D,EAASgD,YAAYW,IAGzB9E,SAASkE,KACJe,iBAA8B,iCAC9BC,QAASX,GAASD,EAAgBC,IAEnCxF,KAAKV,4BAGTU,KAAKV,0BAA4B,IAAI8G,iBAAkBC,IACnDA,EAAUF,QAASG,IACfA,EAASC,WAAWJ,QAASX,GAASD,EAAgBC,QAG9DxF,KAAKV,0BAA0BkH,QAAQvF,SAASkE,KAAM,CAAEsB,WAAW,IACvE,CAEQ,MAAA5F,GAQJ,GAHAb,KAAK0G,sBAGD1G,KAAK2G,gCAGL,OAFA3G,KAAKG,UAAYH,KAAK4G,wCACtB5G,KAAKZ,mBAAoB,GAI7BY,KAAKZ,mBAAoB,EAGzBY,KAAKG,UAAYH,KAAK6G,2BAGlB7G,KAAKb,qBACLa,KAAK8G,8BAEb,CAEQ,mBAAAJ,GACJ,MAAMK,EAAc9F,SAAS+F,KAAKC,UACZ,CAAC,iBAAkB,eAAgB,iBAC3Cd,QAASe,IACnB,MAAMC,EAAaJ,EAAYK,SAASF,GACpCC,IAAenH,KAAKiH,UAAUG,SAASF,GACvClH,KAAKiH,UAAUlG,IAAImG,IACXC,GAAcnH,KAAKiH,UAAUG,SAASF,IAC9ClH,KAAKiH,UAAUI,OAAOH,IAGlC,CAEQ,6BAAAP,GACJ,OAAOzC,OAAOoD,WAn1Bc,GAo1BhC,CAEQ,gCAAAV,GACJ,MAAO,0HAEsD5G,KAAKd,4KAItE,CAEQ,wBAAA2H,GACJ,MAAO,4PAIG7G,KAAKuH,qDAGnB,CAEQ,cAAAC,GACJ,MAAO,iGAC+EzJ,4oBAgB1F,CAEQ,oBAAA0J,GACJ,MAAO,sDACoC5J,ghBAW/C,CAEQ,YAAA6J,CAAazC,EAAY0C,GAC7B,MAAO,sEACoD1C,oCACrCA,iCAAkC0C,+KAM5D,CAEQ,mBAAAC,GACJ,MAAO,2EACyD9J,uWAOtDkC,KAAK0H,aAAa1J,EAAiC,gCACnDgC,KAAK0H,aAAazJ,EAAkC,6CAGlE,CAEQ,iBAAA4J,GACJ,MAAO,qEACmD3J,0PAO9D,CAEQ,eAAA4J,GACJ,MAAO,wDACsC3J,0MAMjD,CAEQ,mBAAAoJ,GACJ,MAAO,6DAEGvH,KAAKyH,8FAEDzH,KAAKwH,yCACLxH,KAAK4H,8CACL5H,KAAK6H,4CACL7H,KAAK8H,wJAKvB,CAEA,+BAAcrD,GACV,IAAIzE,KAAK2G,kCAAmC3G,KAAKb,oBAIjD,IACI,MAAM4I,EAAS,WAAW/H,KAAKd,wCACzB8I,QAAiBC,MAAMF,GAE7B,IAAKC,EAASE,GACV,MAAM,IAAIC,MAAM,2BAA2BH,EAASI,UAGxD,MAAMC,QAAaL,EAASM,OAE5B,IAAKD,EAAKE,UAAYF,EAAKG,OACvB,MAAM,IAAIL,MAAM,wBAGpB,MAAMM,KAAEA,GAASJ,EAAKG,OAEtB,IAAKC,EACD,MAAM,IAAIN,MAAM,mDAGdnI,KAAK0I,eAAeD,EAC9B,OAASE,GACLC,QAAQD,MAAM,wDAAyDA,EAC3E,CACJ,CAEQ,4BAAA7B,GACA5C,OAAO2E,4BAA4BC,iCACnCC,WAAW,KACP7E,OAAO2E,4BAA4BC,kCAAkC9I,OACtE,EAEX,CAEQ,cAAA0I,CAAeM,GAInB,OAAOhJ,KAAKiJ,WAAWD,GAAWE,KAAK,KACnClJ,KAAKb,qBAAsB,GAEnC,CAEQ,UAAA8J,CAAWE,GACf,OAAO,IAAIC,QAAQ,CAACC,EAASC,KACzB,MAAMC,EAAStI,SAAS+D,cAAc,UACtCuE,EAAOC,IAAML,EACbI,EAAOE,OAAQ,EACfF,EAAOG,OAAS,IAAML,IACtBE,EAAOI,QAAU,IAAML,EAAO,IAAInB,MAAM,0BAA0BgB,MAClElI,SAASkE,KAAKC,YAAYmE,IAElC,CAEQ,uBAAAhF,GAEJ,IAAIqF,EAAwB,EAC5B,MAAMC,EAAkB,KACpB,MAAMC,EAAMC,KAAKD,MACbA,EAAMF,EAAwB,MAGlCA,EAAwBE,EACxB9J,KAAKa,WAGHmJ,EAAoC,KACtC,MAAMC,EAAWjK,KAAK2G,gCAClBsD,EACAJ,IAGAI,IAAajK,KAAKZ,oBACdY,KAAKT,yBACLuF,aAAa9E,KAAKT,yBAEtBS,KAAKT,wBAA0BwJ,WAAW,KACtC/I,KAAKyE,4BAA4ByE,KAAK,KAClClJ,KAAKa,YAEV,OAIXb,KAAKL,iBAAmBqK,EACxB9F,OAAO/B,iBAAiB,SAAUnC,KAAKL,kBAEvCK,KAAKX,kBAAoB,IAAI+G,iBAAkBC,IAC3CA,EAAUF,QAASG,IACgB,UAA3BA,EAAS4D,gBAMTlK,KAAK0G,sBAILyD,sBAAsB,IAAMnK,KAAK0G,uBACjCsD,SAKZhK,KAAKX,kBAAkBmH,QAAQvF,SAAS+F,KAAM,CAC1CpG,YAAY,EACZwJ,gBAAiB,CAAC,UAE1B,EAKkB,oBAAXlG,QAA0B,mBAAoBA,SAChDmG,eAAeC,IAAI,yBACpBD,eAAeE,OAAO,uBAAwB3L"}