{"version":3,"file":"client.mjs","sources":["../app/teaser-rentalcar.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-portal-destination-radios';\nconst TEASER_PORTAL_DATEPICKER = 'teaser-portal-datepicker';\nconst TEASER_PORTAL_AUTOCOMPLETER = 'teaser-portal-autocompleter';\nconst TEASER_PORTAL_TIMEPICKER_PICKUP = 'teaser-portal-timepicker-pickup-time';\nconst TEASER_PORTAL_TIMEPICKER_DROPOFF = 'teaser-portal-timepicker-dropoff-time';\nconst TEASER_PORTAL_DRIVERAGE = 'teaser-portal-driverage';\nconst TEASER_PORTAL_SUBMIT_BUTTON = 'teaser-portal-submit-button';\n\n// Production hostname for API calls\nconst HOSTNAME = 'mietwagen.check24.de';\n\n// Style ID for deduplication\nconst STYLE_ID = 'teaser-ssd-rentalcar-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. Keep in sync with teaser-rentalcar.server.ts skeleton. */\nconst TEASER_HEADLINE_MOBILE_MAX_PX = 768;\nconst TEASER_HEADLINE_DESKTOP_MIN_PX = 769;\n\n/** Overlay images on mw-static CDN (same pattern as wm-deals / oster teasers). */\nconst SSD_CDN_BASE =\n    'https://static.mietwagen.check24.de/images/promotion/super-summer-deals/holding-teaser';\n\nconst TEASER_SSD_BACKGROUND_DESKTOP = `${SSD_CDN_BASE}/teaser-widget-ssd-desktop.jpg`;\nconst TEASER_SSD_BACKGROUND_MOBILE = `${SSD_CDN_BASE}/teaser-widget-ssd-mobile.jpg`;\n\nconst TEASER_SSD_LOGO_IMAGE = `${SSD_CDN_BASE}/teaser-ssd-logo-mietwagen.png`;\nconst TEASER_SSD_VEHICLE_IMAGE = `${SSD_CDN_BASE}/teaser-ssd-car.png`;\n\n/** Vehicle image sizing breakpoints (Holding layout). */\nconst TEASER_CARPLECTRUM_DESKTOP_MIN_PX = 1280;\nconst TEASER_CARPLECTRUM_WIDTH_DESKTOP_PX = 490;\nconst TEASER_CARPLECTRUM_HEIGHT_DESKTOP_PX = 370;\n\n// Declare global window extensions\ndeclare global {\n    interface Window {\n        HoldingTeaserInteractive?: {\n            initializeInteractiveComponents?: (scope?: ParentNode) => void;\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-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// 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    /* Promo title — aligned with Städtereise teaser-cmx_title-container. */\n    .ssd-teaser-promo {\n        position: relative;\n        width: 100%;\n        display: flex;\n        flex-direction: column;\n        align-items: flex-start;\n        z-index: 2;\n    }\n\n    .ssd-teaser-logo {\n        display: block;\n        height: auto;\n        object-fit: contain;\n    }\n\n    .ssd-teaser-logo-desktop {\n        display: none;\n        width: 380px;\n        margin-bottom: 104px;\n    }\n\n    .ssd-teaser-logo-mobile {\n        display: block;\n        width: 175px;\n        margin-left: -10px;\n    }\n\n    .ssd-teaser-vehicle {\n        position: absolute;\n        z-index: 2;\n        flex-shrink: 0;\n    }\n\n    .ssd-teaser-vehicle-img {\n        display: block;\n        width: 100%;\n        height: 100%;\n        object-fit: contain;\n    }\n\n    /* Mobile: up to 768px (single breakpoint; aligns with Holding device-mobile). */\n    @media (max-width: ${TEASER_HEADLINE_MOBILE_MAX_PX}px) {\n        .holding-teaser-wrapper {\n            height: 230px;\n            padding: 16px 10px 10px;\n            flex-direction: row;\n            justify-content: space-between;\n            align-items: stretch;\n        }\n\n        .holding-teaser-background {\n            z-index: 10;\n        }\n\n        .ssd-teaser-promo {\n            position: absolute;\n            left: 10px;\n            top: 7%;\n            width: auto;\n            max-width: calc(100% - 110px);\n            z-index: 3;\n            pointer-events: none;\n        }\n\n        .ssd-teaser-logo-mobile {\n            width: min(260px, calc(100vw - 120px));\n            max-width: 100%;\n            margin-left: -10px;\n        }\n\n        .ssd-teaser-vehicle {\n            right: 0;\n            width: min(200px, 42vw);\n            height: min(150px, 32vw);\n            text-align: center;\n            top: 12%;\n            pointer-events: none;\n        }\n    }\n\n    /* Narrow phones: keep logo clear of background sun (320px–480px support). */\n    @media (max-width: 480px) {\n        .ssd-teaser-logo-mobile {\n            width: min(220px, calc(100vw - 100px));\n        }\n\n        .ssd-teaser-vehicle {\n            width: min(160px, 38vw);\n            height: min(120px, 28vw);\n        }\n    }\n\n    @media (max-width: 375px) {\n        .ssd-teaser-logo-mobile {\n            width: min(195px, calc(100vw - 90px));\n        }\n\n        .ssd-teaser-vehicle {\n            width: 130px;\n            height: 100px;\n        }\n    }\n\n    @media (max-width: 320px) {\n        .ssd-teaser-logo-mobile {\n            width: min(175px, calc(100vw - 85px));\n        }\n\n        .ssd-teaser-vehicle {\n            width: 115px;\n            height: 88px;\n            top: 14%;\n        }\n    }\n\n    /* Tablet without form: 769px – 959px */\n    @media (min-width: ${TEASER_HEADLINE_DESKTOP_MIN_PX}px) and (max-width: ${TEASER_FORM_MIN_VIEWPORT_PX - 1}px) {\n        .holding-teaser-wrapper {\n            flex-direction: column;\n            justify-content: flex-start;\n            align-items: center;\n        }\n\n        .holding-teaser-background {\n            z-index: 10;\n        }\n\n        .ssd-teaser-promo {\n            position: relative;\n            top: 35px;\n            left: auto;\n            width: 100%;\n            pointer-events: none;\n        }\n\n        .ssd-teaser-logo-mobile {\n            width: 305px;\n            margin-left: 17%;\n        }\n\n        .ssd-teaser-vehicle {\n            top: 15%;\n            width: 250px;\n            height: 250px;\n            margin-left: 32%;\n            pointer-events: none;\n        }\n    }\n\n    /* Desktop with form: 960px+ */\n    @media (min-width: ${TEASER_FORM_MIN_VIEWPORT_PX}px) {\n        .ssd-teaser-promo {\n            top: 0;\n            padding-top: 20px;\n            align-items: center;\n            position: relative;\n            width: 100%;\n            left: auto;\n        }\n\n        .ssd-teaser-logo-desktop {\n            display: block;\n        }\n\n        .ssd-teaser-logo-mobile {\n            display: none;\n        }\n    }\n\n    @media (min-width: ${TEASER_FORM_MIN_VIEWPORT_PX}px) and (max-width: ${TEASER_CARPLECTRUM_DESKTOP_MIN_PX - 1}px) {\n        .ssd-teaser-vehicle {\n            position: absolute;\n            top: 6%;\n            margin-left: 63%;\n            width: 490px;\n            height: 370px;\n        }\n    }\n\n    @media (min-width: ${TEASER_CARPLECTRUM_DESKTOP_MIN_PX}px) {\n        .ssd-teaser-vehicle {\n            position: absolute;\n            top: 4%;\n            margin-left: 57%;\n            width: ${TEASER_CARPLECTRUM_WIDTH_DESKTOP_PX}px;\n            height: ${TEASER_CARPLECTRUM_HEIGHT_DESKTOP_PX}px;\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    /* Below 960px the background is a full-area link; keep it above decorative visuals. */\n    @media (max-width: ${TEASER_FORM_MIN_VIEWPORT_PX - 1}px) {\n        .holding-teaser-background {\n            z-index: 10;\n        }\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    /* WM holding: white page background — React bundle uses white label color from CSS modules */\n    .holding-teaser-wrapper #${TEASER_PORTAL_DESTINATION_RADIOS} label {\n        color: #333333 !important;\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: #333333;\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\n/**\n * Teaser Rentalcar 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 TeaserRentalcarClient extends HTMLElement implements HomeClientComponentElement {\n    // Props from HomeClientComponentProps\n    deviceOutput: 'desktop' | 'mobile' | 'tabletapp' | 'app' = 'desktop';\n    language: Language = 'de-DE';\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        // 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 getPromoVisuals(): string {\n        return `\n            <div class=\"ssd-teaser-promo\">\n                <img class=\"ssd-teaser-logo ssd-teaser-logo-mobile\" src=\"${TEASER_SSD_LOGO_IMAGE}\" alt=\"Super Summer Deals Mietwagen\">\n                <img class=\"ssd-teaser-logo ssd-teaser-logo-desktop\" src=\"${TEASER_SSD_LOGO_IMAGE}\" alt=\"Super Summer Deals Mietwagen\">\n            </div>\n            <div class=\"ssd-teaser-vehicle\">\n                <img class=\"ssd-teaser-vehicle-img\" src=\"${TEASER_SSD_VEHICLE_IMAGE}\" alt=\"Mietwagen Angebot\">\n            </div>\n        `;\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                ${this.getPromoVisuals()}\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            ${this.getPromoVisuals()}\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\">Abholort</label>\n                <div class=\"teaser-field-input-wrapper\">\n                    <input \n                        type=\"text\" \n                        id=\"pickup-input\"\n                        placeholder=\"Stadt oder Flughafen\" \n                        class=\"teaser-field-input\"\n                        aria-label=\"Stadt oder Flughafen\"\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>Rückgabe am selben Ort</span>\n                </label>\n                <label class=\"teaser-radio-label\">\n                    <input type=\"radio\" name=\"return-location\" value=\"different\" class=\"teaser-radio\" />\n                    <span>Rückgabe an anderem Ort</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\">Anmietzeitraum</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, 'Abholung')}\n                ${this.getTimeField(TEASER_PORTAL_TIMEPICKER_DROPOFF, 'Rückgabe')}\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\">Fahreralter</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>Suche</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-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/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.HoldingTeaserInteractive?.initializeInteractiveComponents) {\n            setTimeout(() => {\n                window.HoldingTeaserInteractive?.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('rentalcar-ssd-2026')) {\n        customElements.define('rentalcar-ssd-2026', TeaserRentalcarClient);\n    }\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","TEASER_FORM_MIN_VIEWPORT_PX","SSD_CDN_BASE","TEASER_SSD_LOGO_IMAGE","TEASER_SSD_VEHICLE_IMAGE","OWNED_PORTAL_IDS","Set","teaserWidgetRegistry","documentGetElementByIdPatched","teaserReplayedClicks","WeakSet","styles","TeaserRentalcarClient","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","applyStyles","setupResponsiveListener","readyState","loadInteractiveComponents","window","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","getPromoVisuals","getStaticSearchForm","getPickupField","getDestinationRadios","getTimeField","label","getDateRangeSection","getDriverAgeField","getSubmitButton","apiUrl","response","fetch","ok","Error","status","data","json","success","assets","main","loadMainBundle","error","console","HoldingTeaserInteractive","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":"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"}