{
  "version": 3,
  "sources": ["../alpine-components/photo-modals.js", "../alpine-components/highlight-polygon.js", "../alpine-components/highlight-editor.js", "../alpine-components/batch.js", "../alpine-components/photo-upload.js", "../alpine-components/branding-logo-upload.js", "../alpine-components/estimated-progress.js", "../alpine-components/onboarding.js", "../alpine-components/guides.js", "../alpine-components/property-create.js", "../alpine-components/address.js", "../alpine-components/listing-form.js", "../public-upload.js"],
  "sourcesContent": ["document.addEventListener('alpine:init', () => {\n    const I18N = window.I18N || {};\n\n    Alpine.data('photoModals', () => ({\n        comparisonOpen: false,\n        retryOpen: false,\n        revisionOpen: false,\n        deleteOpen: false,\n        qaExplainOpen: false,\n        metadataOpen: false,\n        upscaleConfirmOpen: false,\n        rebaseOpen: false,\n        rebaseReturnToRetry: false,\n        rebaseRequestPending: false,\n        rebaseDismissedWhilePending: false,\n        rebaseSummaryRequest: null,\n        historyOpen: false,\n        deleting: false,\n        retryText: '',\n        refundText: '',\n        retryAction: '',\n        retryBodyCache: '',\n        revisionSrc: '',\n        revisionId: '',\n        revisionUrls: {},\n        menuOpen: false,\n        editorOpen: false,\n\n        init() {\n            const json = this.$el.dataset.revisionUrls;\n            if (json) {\n                try { this.revisionUrls = JSON.parse(json); } catch (e) { this.revisionUrls = {}; }\n            }\n\n            // The retry dialog closes itself once the server has swapped the\n            // page fragments it changed. The hint is cleared here and not in\n            // closeRetry(), so Escape keeps a draft but a sent hint is not\n            // re-sent when the next result is rejected too.\n            // The body now holds a dialog for the *new* active revision, so the\n            // cached choice step is stale: drop it and let the next open cache\n            // what the server just swapped in.\n            window.addEventListener('retry-done', () => { this.retryText = ''; this.refundText = ''; this.retryAction = ''; this.retryBodyCache = ''; this.closeRetry(); });\n        },\n\n        openComparison()  { this.comparisonOpen = true;  this.lockScroll(); },\n        closeComparison() { this.comparisonOpen = false; this.unlockScroll(); },\n        openRetry()       { this.cacheRetryBody(); this.retryOpen = true; this.lockScroll(); },\n        closeRetry() {\n            // A retry request can still be resolving its fast modal shell.\n            // Treat closing the retry sheet as declining that pending offer.\n            if (this.rebaseRequestPending && !this.rebaseOpen) {\n                this.rebaseDismissedWhilePending = true;\n            }\n            this.retryOpen = false;\n            this.unlockScroll();\n            // Without this the next open shows whatever the server last\n            // swapped in \u2014 the proposal of a result the user walked away\n            // from \u2014 and the other path is unreachable.\n            this.restoreRetryBody();\n        },\n        retryBody() { return document.getElementById('retry-dialog-body'); },\n        // The server swaps this body (proposal step, validation errors, the\n        // dialog for the next revision after an action). Cache the choice step\n        // the first time the dialog opens so closing it, or \"Zur\u00FCck\" inside the\n        // proposal step, can put that step back.\n        cacheRetryBody() {\n            const body = this.retryBody();\n            if (body && !this.retryBodyCache) this.retryBodyCache = body.innerHTML;\n        },\n        // Drop the proposal poll and its timer so neither can fire a retry the\n        // customer has stepped away from. An element htmx is posting right now\n        // is left in place; removing it would strand its own response.\n        stopSuggestionWait() {\n            const body = this.retryBody();\n            if (!body) return;\n            body.querySelectorAll('[data-suggestion-wait]:not(.htmx-request)')\n                .forEach((node) => node.remove());\n        },\n        restoreRetryBody() {\n            const body = this.retryBody();\n            if (!body || !this.retryBodyCache) return;\n            this.stopSuggestionWait();\n            body.innerHTML = this.retryBodyCache;\n            // Restored markup is new DOM to htmx: without this its forms fall\n            // back to native posts, the same trap teleported modals hit after\n            // an hx-boost navigation.\n            if (window.htmx) window.htmx.process(body);\n        },\n        backToRetryChoice() { this.restoreRetryBody(); },\n        // Only caller is the sidebar \"Versionen\" list, so the event measures\n        // that surface against the history modal opened from the \"Mehr\" menu.\n        showRevision(id)  { this.revisionSrc = this.revisionUrls[id] || ''; this.revisionId = String(id); this.revisionOpen = true; this.lockScroll(); window.trackEvent && window.trackEvent('revision_preview_open'); },\n        closeRevision()   { this.revisionOpen = false;   this.unlockScroll(); },\n        openHistory()     { this.historyOpen = true;  this.lockScroll(); window.trackEvent && window.trackEvent('revision_history_open'); },\n        closeHistory()    { this.historyOpen = false; this.unlockScroll(); },\n        openDelete()      { this.deleteOpen = true;      this.lockScroll(); },\n        closeDelete()     { this.deleteOpen = false;     this.unlockScroll(); },\n        openQaExplain()   { this.qaExplainOpen = true;   this.lockScroll(); },\n        closeQaExplain()  { this.qaExplainOpen = false;  this.unlockScroll(); },\n        openMetadata()        { this.metadataOpen = true;        this.lockScroll(); },\n        closeMetadata()       { this.metadataOpen = false;       this.unlockScroll(); },\n        openUpscaleConfirm()  { this.upscaleConfirmOpen = true;  this.lockScroll(); },\n        closeUpscaleConfirm() { this.upscaleConfirmOpen = false; this.unlockScroll(); },\n        prepareRebase() {\n            this.rebaseRequestPending = true;\n            this.rebaseDismissedWhilePending = false;\n            this.abortRebaseSummaryRequest();\n        },\n        openRebase() {\n            // The request can complete after the user closed the originating\n            // surface. Keep its prepared shell available, but do not reopen it.\n            if (this.rebaseDismissedWhilePending) {\n                this.rebaseRequestPending = false;\n                this.rebaseDismissedWhilePending = false;\n                return;\n            }\n            this.rebaseRequestPending = false;\n            this.showRebase();\n        },\n        showRebase() {\n            if (this.retryOpen) {\n                // Preserve the retry draft in photoModals. The rebase dialog\n                // replaces the sheet, so it is the only overlay on screen.\n                this.rebaseReturnToRetry = true;\n                this.retryOpen = false;\n            }\n            // The consolidation offer answers a retry posted from the proposal\n            // step and takes over the screen. Nothing behind it may still fire\n            // a retry, so the poll and the timer go now. The panel itself is\n            // rebuilt when the retry dialog comes back: this runs while htmx is\n            // still resolving the response that opened this modal, and pulling\n            // the requesting form out from under it breaks its retarget.\n            this.stopSuggestionWait();\n            if (!this.rebaseOpen) {\n                this.rebaseOpen = true;\n                this.lockScroll();\n            }\n        },\n        closeRebase() {\n            this.abortRebaseSummaryRequest();\n            if (this.rebaseRequestPending) this.rebaseDismissedWhilePending = true;\n            this.rebaseOpen = false;\n            if (this.rebaseReturnToRetry) {\n                this.rebaseReturnToRetry = false;\n                // The dialog underneath still shows the wait it was in when the\n                // offer interrupted it. That moment is over.\n                this.restoreRetryBody();\n                this.retryOpen = true;\n            }\n            this.unlockScroll();\n        },\n        finishRebase() {\n            this.rebaseRequestPending = false;\n            this.rebaseDismissedWhilePending = false;\n            this.rebaseReturnToRetry = false;\n            this.closeRebase();\n        },\n        setRebaseSummaryRequest(xhr) {\n            this.abortRebaseSummaryRequest();\n            this.rebaseSummaryRequest = xhr;\n        },\n        clearRebaseSummaryRequest(xhr) {\n            if (!xhr || this.rebaseSummaryRequest === xhr) {\n                this.rebaseSummaryRequest = null;\n            }\n        },\n        abortRebaseSummaryRequest() {\n            if (this.rebaseSummaryRequest) {\n                this.rebaseSummaryRequest.abort();\n                this.rebaseSummaryRequest = null;\n            }\n        },\n\n        get anyOpen() { return this.comparisonOpen || this.retryOpen || this.revisionOpen || this.deleteOpen || this.qaExplainOpen || this.metadataOpen || this.upscaleConfirmOpen || this.rebaseOpen || this.historyOpen; },\n        lockScroll()   { window._scrollLock.lock(); },\n        unlockScroll() { if (!this.anyOpen) window._scrollLock.unlock(); },\n    }));\n\n    Alpine.data('rebaseModal', () => ({\n        submitting: false,\n        summaryReady: false,\n        summaryLoading: false,\n        summaryRequestFailed: false,\n        rebaseBehavior: 'ask',\n\n        init() {\n            this.summaryLoading = this.$el.dataset.summaryLoading === 'true';\n            this.summaryReady = !this.summaryLoading;\n            const behavior = this.$el.dataset.rebaseBehavior;\n            this.rebaseBehavior = ['ask', 'always', 'never'].includes(behavior)\n                ? behavior\n                : 'ask';\n        },\n        startSummaryRequest(event) {\n            this.summaryLoading = true;\n            this.summaryRequestFailed = false;\n            this.$dispatch('rebase-summary-request-start', { xhr: event.detail.xhr });\n        },\n        finishSummaryRequest(event) {\n            const xhr = event.detail.xhr;\n            const successful = xhr.status >= 200 && xhr.status < 300;\n            this.summaryLoading = false;\n            this.summaryReady = successful;\n            this.summaryRequestFailed = !successful;\n            this.$dispatch('rebase-summary-request-finished', { xhr });\n        },\n    }));\n\n    Alpine.data('editForm', () => ({\n        activeTab: 'outdoor',\n        submitting: false,\n        duplicateWarningBypassed: false,\n        floorplanWarningBypassed: false,\n        floorplanWarningPending: false,\n        rebaseOfferPossible: false,\n        previousPresets: [],\n        // staging_outdoor stays unchecked by default and is deliberately\n        // excluded from saved-prefs application below\n        outdoor: { optimize: true, sunshine: true, declutter: true, staging_outdoor: false },\n        indoor: { optimize: true, declutter: true, details: true, staging: true },\n        replaceFurniture: false,\n        lockCameraAngle: true,\n        resolution4k: false,\n        nextEditCredits2k: 0,\n        nextEditCredits4k: 0,\n        roomType: '',\n        outdoorType: '',\n        furnitureStyle: '',\n        furnitureInstructions: '',\n        intensity: 'normal',\n        additionalGuidance: '',\n        roomOpen: false,\n        styleOpen: false,\n        // \"Passend zu diesem Foto\": a staged photo to match, pre-selected from\n        // the same room or picked in the modal from all staged photos.\n        matchReference: false,\n        referenceRemoved: false,\n        referenceId: '',\n        referenceUrl: '',\n        referenceStyle: '',\n        referenceRemoveUrl: '',\n        // Only a reference from this photo's own room can be taken out of it.\n        referenceSameRoom: false,\n        roomOptions: [\n            {v:'',l:'Auto'}, {v:'living_room',l:I18N.roomLivingRoom || 'Wohnzimmer'},\n            {v:'bedroom',l:I18N.roomBedroom || 'Schlafzimmer'}, {v:'kitchen',l:I18N.roomKitchen || 'K\u00FCche'},\n            {v:'bathroom',l:I18N.roomBathroom || 'Badezimmer'}, {v:'kids_room',l:I18N.roomKidsRoom || 'Kinderzimmer'},\n            {v:'dining_room',l:I18N.roomDiningRoom || 'Esszimmer'}, {v:'hallway',l:I18N.roomHallway || 'Flur'},\n            {v:'home_office',l:I18N.roomHomeOffice || 'Arbeitszimmer'},\n            {v:'office',l:I18N.roomOffice || 'B\u00FCro'}, {v:'garage',l:'Garage'},\n            {v:'basement',l:I18N.roomBasement || 'Keller'},\n            {v:'dressing_room',l:I18N.roomDressingRoom || 'Ankleide'},\n            {v:'attic',l:I18N.roomAttic || 'Dachboden'},\n        ],\n        styleOptions: [\n            {v:'',l:I18N.styleUnspecified || 'Keine Vorgabe'}, {v:'modern',l:'Modern'},\n            {v:'skandinavisch',l:I18N.styleScandinavian || 'Skandinavisch'}, {v:'klassisch',l:I18N.styleClassic || 'Klassisch'},\n            {v:'landhausstil',l:I18N.styleCountry || 'Landhausstil'}, {v:'industriell',l:I18N.styleIndustrial || 'Industriell'},\n        ],\n\n        init() {\n            this.nextEditCredits2k = Number(this.$el.dataset.nextEditCreditsStandard || 0);\n            this.nextEditCredits4k = Number(this.$el.dataset.nextEditCreditsHigh || 0);\n            this.floorplanWarningPending = this.$el.dataset.floorplanWarningPending === 'true';\n            this.rebaseOfferPossible = this.$el.dataset.rebaseOfferPossible === 'true';\n            // Apply saved preset preferences\n            const prefsJson = this.$el.dataset.presetPrefs;\n            if (prefsJson) {\n                try {\n                    const prefs = JSON.parse(prefsJson);\n                    if (prefs.outdoor) {\n                        this.outdoor.optimize = prefs.outdoor.includes('optimize');\n                        this.outdoor.sunshine = prefs.outdoor.includes('sunshine');\n                        this.outdoor.declutter = prefs.outdoor.includes('declutter');\n                    }\n                    if (prefs.indoor) {\n                        this.indoor.optimize = prefs.indoor.includes('optimize_indoor');\n                        this.indoor.declutter = prefs.indoor.includes('declutter_indoor');\n                        this.indoor.details = prefs.indoor.includes('details');\n                        this.indoor.staging = prefs.indoor.includes('staging');\n                    }\n                    if (typeof prefs.replace_furniture === 'boolean')\n                        this.replaceFurniture = prefs.replace_furniture;\n                    if (typeof prefs.lock_camera_angle === 'boolean')\n                        this.lockCameraAngle = prefs.lock_camera_angle;\n                    if (prefs.intensity === 'subtle')\n                        this.intensity = 'subtle';\n                    if (prefs.resolution === '4K')\n                        this.resolution4k = true;\n                    if (prefs.furniture_style)\n                        this.furnitureStyle = prefs.furniture_style;\n                    if (prefs.aspect_ratio) {\n                        const sel = this.$el.querySelector('#aspect-ratio');\n                        if (sel) sel.value = prefs.aspect_ratio;\n                    }\n                } catch (e) {}\n            }\n\n            // Parse previous presets for duplicate detection\n            try {\n                this.previousPresets = JSON.parse(this.$el.dataset.previousPresets || '[]');\n            } catch (e) { this.previousPresets = []; }\n\n            this.activeTab = this.$el.dataset.initialTab || 'outdoor';\n            this.isFloorplan = this.activeTab === 'floorplan';\n            this.roomType = this.$el.dataset.roomType || '';\n            this.outdoorType = this.$el.dataset.outdoorType || '';\n\n            // The metadata modal saves room and outdoor type without\n            // re-rendering this form. Pick the saved values up here, because\n            // the edit view persists whatever the form posts and would\n            // otherwise write the old values back on the next edit.\n            window.addEventListener('metadata-updated', (event) => {\n                const detail = event.detail || {};\n                if ('room_type' in detail) this.roomType = detail.room_type || '';\n                if ('outdoor_type' in detail) this.outdoorType = detail.outdoor_type || '';\n            });\n\n            // A staged photo of the same room: matching it is pre-selected and\n            // takes its furniture style. Another style cannot match, so picking\n            // one unticks the box; ticking it again restores the style. The\n            // same rule holds for a reference picked in the modal.\n            if (this.$el.dataset.hasReference === 'true') {\n                this.matchReference = true;\n                this.referenceId = this.$el.dataset.referenceId || '';\n                this.referenceUrl = this.$el.dataset.referenceUrl || '';\n                this.referenceStyle = this.$el.dataset.referenceStyle || '';\n                this.referenceRemoveUrl = this.$el.dataset.referenceRemoveUrl || '';\n                this.referenceSameRoom = true;\n                this.furnitureStyle = this.referenceStyle;\n            }\n            if (this.$el.dataset.hasCandidates === 'true') {\n                this.$watch('furnitureStyle', (value) => {\n                    if (value !== this.referenceStyle) this.matchReference = false;\n                });\n                this.$watch('matchReference', (value) => {\n                    if (value) this.furnitureStyle = this.referenceStyle;\n                });\n            }\n\n            // Construction subtype override (photo-specific > account preference)\n            const subtype = this.$el.dataset.sceneSubtype || '';\n            if (this.activeTab === 'indoor' && subtype === 'construction') {\n                this.indoor.declutter = false;\n                this.indoor.staging = false;\n                this.indoor.details = false;\n            }\n        },\n\n        switchTab(tab) {\n            this.activeTab = tab;\n            if (tab !== 'indoor') {\n                this.indoor.staging = false;\n                this.replaceFurniture = false;\n                this.roomType = '';\n                this.furnitureStyle = '';\n            }\n        },\n\n        // \"Passend zu diesem Foto\" is ticked: the edit becomes a set photo,\n        // always 2K in the source format.\n        get followActive() {\n            return this.matchReference && !!this.referenceId && !this.referenceRemoved\n                && this.activeTab === 'indoor' && this.indoor.staging;\n        },\n\n        get nextEditCredits() {\n            return this.resolution4k && !this.followActive ? this.nextEditCredits4k : this.nextEditCredits2k;\n        },\n\n        // \"Geh\u00F6rt nicht dazu\": the reference photo shows another room. A\n        // reference from this photo's own room leaves the room on the server\n        // and this photo is staged on its own. A reference picked from another\n        // room is only dropped: its own room is right.\n        removeReference() {\n            if (this.referenceRemoved) return;\n            this.referenceRemoved = true;\n            this.matchReference = false;\n            if (!this.referenceSameRoom) return;\n            const meta = document.querySelector('meta[name=\"csrf-token\"]');\n            fetch(this.referenceRemoveUrl, {\n                method: 'POST',\n                headers: { 'X-CSRFToken': meta ? meta.content : '', 'X-Requested-With': 'XMLHttpRequest' },\n            }).catch(err => console.error(err));\n        },\n\n        // \"Anderes Foto w\u00E4hlen\" opens the picker modal. It is teleported out of\n        // this form, so it gets the current reference and a callback through\n        // the modal store instead of reading this component's state.\n        openReferencePicker() {\n            Alpine.store('modal').show('reference-picker', {\n                current: this.referenceRemoved ? '' : this.referenceId,\n                choose: (button) => {\n                    this.chooseReference(button);\n                    Alpine.store('modal').close();\n                },\n            });\n        },\n\n        // A candidate from the picker becomes the reference, ticked, with its\n        // own furniture style.\n        chooseReference(button) {\n            const data = button.dataset;\n            this.referenceId = data.referenceCandidate;\n            this.referenceUrl = data.url;\n            this.referenceStyle = data.style || '';\n            this.referenceRemoveUrl = data.removeUrl;\n            this.referenceSameRoom = data.sameRoom === 'true';\n            this.referenceRemoved = false;\n            this.furnitureStyle = this.referenceStyle;\n            this.matchReference = true;\n        },\n\n        get showStagingOptions() {\n            return this.activeTab === 'indoor' && this.indoor.staging;\n        },\n\n        // GA4 funnel step: the customer asked for this edit. The onboarding\n        // demo edit reports itself with auto: true from its own partial.\n        trackEditStarted(propertyId) {\n            window.trackEvent('edit_started', {\n                property_id: propertyId,\n                preset: this.getSelectedPresets().join(','),\n                auto: false,\n            });\n        },\n\n        getSelectedPresets() {\n            if (this.activeTab === 'outdoor') {\n                return Object.entries(this.outdoor).filter(([, v]) => v).map(([k]) => k);\n            }\n            if (this.activeTab === 'indoor') {\n                var presets = [];\n                if (this.indoor.optimize) presets.push('optimize_indoor');\n                if (this.indoor.declutter) presets.push('declutter_indoor');\n                if (this.indoor.details) presets.push('details');\n                if (this.indoor.staging) presets.push(this.replaceFurniture ? 'staging_replace' : 'staging');\n                return presets;\n            }\n            if (this.activeTab === 'floorplan') {\n                // One floorplan preset: the checked 2D/3D radio for this plan type.\n                var inputs = this.$el.querySelectorAll('input[name=\"presets\"][value^=\"floorplan\"]');\n                for (var i = 0; i < inputs.length; i++) {\n                    var inp = inputs[i];\n                    if (inp.disabled) continue;\n                    if (inp.type === 'radio' && !inp.checked) continue;\n                    return [inp.value];\n                }\n                return [];\n            }\n            return [];\n        },\n\n        isDuplicatePresets() {\n            if (!this.previousPresets.length) return false;\n            if (this.additionalGuidance.trim()) return false;\n            var selected = this.getSelectedPresets();\n            if (!selected.length) return false;\n            return selected.every(function(p) { return this.previousPresets.indexOf(p) !== -1; }.bind(this));\n        },\n\n        // Pre-submit gates. handleConfirm walks this list and opens the\n        // first gate whose `needs()` returns true. Confirming a gate sets\n        // its `bypassed` flag and calls _resumeSubmit(), which re-walks the\n        // gates synchronously and either opens the next pending gate or\n        // fires the captured HTMX issueRequest.\n        gates() {\n            const self = this;\n            return [\n                {\n                    needs() {\n                        // Warning is for 3D outputs only. Any floorplan_2d_modern*\n                        // key (Grundriss/Ansicht/Schnitt) is a faithful redraw and\n                        // never warns.\n                        var has3d = self.getSelectedPresets().some(function(k) {\n                            return k.indexOf('floorplan') === 0 && k.indexOf('floorplan_2d_modern') !== 0;\n                        });\n                        return self.activeTab === 'floorplan'\n                            && self.floorplanWarningPending\n                            && !self.floorplanWarningBypassed\n                            && has3d;\n                    },\n                    open() {\n                        Alpine.store('modal').show('floorplan-warning', {\n                            onConfirm: () => self.confirmFloorplanWarning(),\n                        });\n                    },\n                },\n                {\n                    needs() {\n                        return self.activeTab !== 'custom'\n                            && !self.duplicateWarningBypassed\n                            && self.isDuplicatePresets();\n                    },\n                    open() {\n                        Alpine.store('modal').show('duplicate-warning', {\n                            onConfirm: () => self.confirmSubmit(),\n                        });\n                    },\n                },\n            ];\n        },\n\n        handleConfirm(event) {\n            for (const gate of this.gates()) {\n                if (gate.needs()) {\n                    event.preventDefault();\n                    this._issueRequest = event.detail.issueRequest;\n                    gate.open();\n                    return;\n                }\n            }\n        },\n\n        _resumeSubmit() {\n            // A bypassed gate may have unblocked the next one \u2014 walk the\n            // chain again before submitting. event.detail.issueRequest is\n            // the htmx:confirm completion callback and does NOT re-emit\n            // htmx:confirm, so the chain has to advance itself here.\n            for (const gate of this.gates()) {\n                if (gate.needs()) {\n                    gate.open();\n                    return;\n                }\n            }\n            this.submitting = true;\n            if (this._issueRequest) this._issueRequest();\n        },\n\n        confirmFloorplanWarning() {\n            Alpine.store('modal').close();\n            this.floorplanWarningBypassed = true;\n            this._resumeSubmit();\n        },\n\n        confirmSubmit() {\n            Alpine.store('modal').close();\n            this.duplicateWarningBypassed = true;\n            this._resumeSubmit();\n        },\n    }));\n\n});\n", "const MAX_POLYGON_POINTS = 64;\nconst MIN_POLYGON_AREA = 0.000001;\n\nfunction clamp(value, min, max) {\n    return Math.min(max, Math.max(min, value));\n}\n\nfunction orientation(a, b, c) {\n    return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);\n}\n\nfunction pointOnSegment(a, b, point) {\n    const epsilon = 1e-12;\n    return Math.abs(orientation(a, b, point)) <= epsilon\n        && point.x >= Math.min(a.x, b.x) - epsilon\n        && point.x <= Math.max(a.x, b.x) + epsilon\n        && point.y >= Math.min(a.y, b.y) - epsilon\n        && point.y <= Math.max(a.y, b.y) + epsilon;\n}\n\nfunction segmentsIntersect(a, b, c, d) {\n    const abC = orientation(a, b, c);\n    const abD = orientation(a, b, d);\n    const cdA = orientation(c, d, a);\n    const cdB = orientation(c, d, b);\n    const epsilon = 1e-12;\n    const crosses = (\n        ((abC > epsilon && abD < -epsilon) || (abC < -epsilon && abD > epsilon))\n        && ((cdA > epsilon && cdB < -epsilon) || (cdA < -epsilon && cdB > epsilon))\n    );\n    return crosses\n        || pointOnSegment(a, b, c)\n        || pointOnSegment(a, b, d)\n        || pointOnSegment(c, d, a)\n        || pointOnSegment(c, d, b);\n}\n\nfunction polygonArea(points) {\n    return Math.abs(points.reduce((sum, point, index) => {\n        const next = points[(index + 1) % points.length];\n        return sum + point.x * next.y - next.x * point.y;\n    }, 0)) / 2;\n}\n\nfunction polygonIsSimple(points) {\n    if (points.length < 3 || polygonArea(points) < MIN_POLYGON_AREA) return false;\n    for (let first = 0; first < points.length; first++) {\n        const firstNext = (first + 1) % points.length;\n        for (let second = first + 1; second < points.length; second++) {\n            const secondNext = (second + 1) % points.length;\n            if (firstNext === second || secondNext === first) continue;\n            if (segmentsIntersect(\n                points[first], points[firstNext], points[second], points[secondNext]\n            )) return false;\n        }\n    }\n    return true;\n}\n\nfunction openPathIsSimple(points) {\n    if (points.length < 4) return true;\n    const lastStart = points.length - 2;\n    const lastEnd = points.length - 1;\n    for (let index = 0; index < lastStart - 1; index++) {\n        if (segmentsIntersect(\n            points[index], points[index + 1], points[lastStart], points[lastEnd]\n        )) return false;\n    }\n    return true;\n}\n\n/** Polygon-specific Alpine methods mixed into the shared image editor state. */\nwindow.highlightPolygonEditorMethods = function() {\n    return {\n        selectHighlightShape(shape) {\n            if (!['rect', 'polygon'].includes(shape) || this.applying) return;\n            if (shape === this.highlightShape) return;\n            this.polygonError = '';\n            if (shape === 'polygon') {\n                if (this.highlightRect) {\n                    const rect = this.highlightRect;\n                    this.polygonPoints = [\n                        {x: rect.x, y: rect.y},\n                        {x: rect.x + rect.width, y: rect.y},\n                        {x: rect.x + rect.width, y: rect.y + rect.height},\n                        {x: rect.x, y: rect.y + rect.height},\n                    ];\n                    this.polygonClosed = true;\n                    this.highlightRect = null;\n                    this.guideVisible = true;\n                } else {\n                    this.polygonPoints = [];\n                    this.polygonClosed = false;\n                    this.guideVisible = false;\n                }\n                this.highlightShape = 'polygon';\n                return;\n            }\n            if (this.polygonPoints.length) {\n                this.shapeChangeOpen = true;\n                return;\n            }\n            this.highlightShape = 'rect';\n            this.guideVisible = Boolean(this.highlightRect);\n        },\n\n        cancelShapeChange() {\n            this.shapeChangeOpen = false;\n        },\n\n        confirmShapeChange() {\n            if (this.polygonClosed && this.polygonPoints.length >= 3) {\n                const xs = this.polygonPoints.map((point) => point.x);\n                const ys = this.polygonPoints.map((point) => point.y);\n                const left = Math.min(...xs);\n                const top = Math.min(...ys);\n                this.highlightRect = {\n                    x: left,\n                    y: top,\n                    width: Math.max(...xs) - left,\n                    height: Math.max(...ys) - top,\n                };\n            } else {\n                this.highlightRect = null;\n            }\n            this.polygonPoints = [];\n            this.polygonClosed = false;\n            this.polygonPointer = null;\n            this.polygonError = '';\n            this.highlightShape = 'rect';\n            this.shapeChangeOpen = false;\n            this.guideVisible = Boolean(this.highlightRect);\n        },\n\n        startPolygonPoint(event) {\n            if (this.pointerCount > 0) {\n                this.trackPointer(event);\n                this.beginPinchIfNeeded();\n                return;\n            }\n            this.trackPointer(event);\n            const point = this.imagePoint(event);\n            this._gesture = this.polygonClosed ? 'polygon-dismiss' : 'polygon-point';\n            this._gestureStart = {\n                point,\n                client: {x: event.clientX, y: event.clientY},\n                moved: false,\n            };\n            if (!this.polygonClosed) this.polygonPointer = point;\n            this.capturePointer(event);\n        },\n\n        startPolygonVertex(event, index) {\n            this.trackPointer(event);\n            if (this.pointerCount > 1) {\n                this.beginPinchIfNeeded();\n                return;\n            }\n            this.polygonError = '';\n            this.guideVisible = true;\n            this._gesture = !this.polygonClosed && index === 0 && this.polygonPoints.length >= 3\n                ? 'polygon-close'\n                : 'polygon-vertex';\n            this._gestureStart = {\n                index,\n                client: {x: event.clientX, y: event.clientY},\n                originalPoints: this.polygonPoints.map((point) => ({...point})),\n                moved: false,\n            };\n            this.capturePointer(event);\n        },\n\n        startPolygonMove(event) {\n            this.trackPointer(event);\n            if (this.pointerCount > 1) {\n                this.beginPinchIfNeeded();\n                return;\n            }\n            this.guideVisible = true;\n            this._gesture = 'polygon-move';\n            this._gestureStart = {\n                point: this.imagePoint(event),\n                originalPoints: this.polygonPoints.map((point) => ({...point})),\n            };\n            this.capturePointer(event);\n        },\n\n        markPolygonGestureMoved(event, threshold) {\n            if (!this._gestureStart || this._gestureStart.moved) return;\n            this._gestureStart.moved = Math.hypot(\n                event.clientX - this._gestureStart.client.x,\n                event.clientY - this._gestureStart.client.y\n            ) >= threshold;\n        },\n\n        finishPolygonGesture(event, gesture) {\n            const start = this._gestureStart;\n            const cancelled = event.type === 'pointercancel';\n            if (cancelled) {\n                if (start?.originalPoints) this.polygonPoints = start.originalPoints;\n            } else if (gesture === 'polygon-point' && !start?.moved) {\n                this.addPolygonPoint(this.imagePoint(event));\n            } else if (gesture === 'polygon-close' && !start?.moved) {\n                this.closePolygon();\n            } else if (gesture === 'polygon-vertex' && start?.moved) {\n                const valid = this.polygonClosed\n                    ? polygonIsSimple(this.polygonPoints)\n                    : openPathIsSimple(this.polygonPoints);\n                if (!valid) {\n                    const areaTooSmall = (\n                        this.polygonClosed\n                        && polygonArea(this.polygonPoints) < MIN_POLYGON_AREA\n                    );\n                    this.polygonPoints = start.originalPoints;\n                    this.polygonError = this.message(\n                        areaTooSmall ? 'polygonTooSmall' : 'polygonCrossed',\n                        areaTooSmall\n                            ? 'Die markierte Fl\u00E4che ist zu klein.'\n                            : 'Die Linien d\u00FCrfen sich nicht kreuzen.'\n                    );\n                }\n            } else if (gesture === 'polygon-dismiss' && !start?.moved) {\n                this.guideVisible = false;\n            }\n            this._gesture = null;\n            this._gestureStart = null;\n        },\n\n        addPolygonPoint(point) {\n            this.polygonError = '';\n            if (\n                this.polygonPoints.length >= 3\n                && this.pointScreenDistance(point, this.polygonPoints[0]) <= 28\n            ) {\n                this.closePolygon();\n                return;\n            }\n            if (this.polygonPoints.length >= MAX_POLYGON_POINTS) {\n                this.polygonError = this.message(\n                    'polygonMaxPoints', 'Die maximale Anzahl an Punkten ist erreicht.'\n                );\n                return;\n            }\n            const previous = this.polygonPoints[this.polygonPoints.length - 1];\n            if (previous && this.pointScreenDistance(point, previous) < 8) return;\n            const candidate = [...this.polygonPoints, point];\n            if (!openPathIsSimple(candidate)) {\n                this.polygonError = this.message(\n                    'polygonCrossed', 'Die Linien d\u00FCrfen sich nicht kreuzen.'\n                );\n                return;\n            }\n            this.polygonPoints = candidate;\n            this.polygonPointer = point;\n            this.guideVisible = true;\n        },\n\n        closePolygon() {\n            if (this.polygonPoints.length < 3) return;\n            if (polygonArea(this.polygonPoints) < MIN_POLYGON_AREA) {\n                this.polygonError = this.message(\n                    'polygonTooSmall', 'Die markierte Fl\u00E4che ist zu klein.'\n                );\n                return;\n            }\n            if (!polygonIsSimple(this.polygonPoints)) {\n                this.polygonError = this.message(\n                    'polygonCrossed', 'Die Linien d\u00FCrfen sich nicht kreuzen.'\n                );\n                return;\n            }\n            this.polygonClosed = true;\n            this.polygonPointer = null;\n            this.polygonError = '';\n            this.guideVisible = true;\n        },\n\n        undoPolygonPoint() {\n            if (!this.polygonPoints.length) return;\n            this.polygonClosed = false;\n            this.polygonPoints = this.polygonPoints.slice(0, -1);\n            this.polygonPointer = this.polygonPoints[this.polygonPoints.length - 1] || null;\n            this.polygonError = '';\n            this.guideVisible = Boolean(this.polygonPoints.length);\n        },\n\n        resetPolygon() {\n            this.polygonPoints = [];\n            this.polygonClosed = false;\n            this.polygonPointer = null;\n            this.polygonError = '';\n            this.guideVisible = false;\n        },\n\n        updatePolygonMove(point) {\n            const start = this._gestureStart;\n            const xs = start.originalPoints.map((item) => item.x);\n            const ys = start.originalPoints.map((item) => item.y);\n            const dx = clamp(point.x - start.point.x, -Math.min(...xs), 1 - Math.max(...xs));\n            const dy = clamp(point.y - start.point.y, -Math.min(...ys), 1 - Math.max(...ys));\n            this.polygonPoints = start.originalPoints.map((item) => ({\n                x: item.x + dx,\n                y: item.y + dy,\n            }));\n        },\n\n        pointScreenDistance(first, second) {\n            if (!this._viewportElement) return Infinity;\n            const viewport = this._viewportElement.getBoundingClientRect();\n            return Math.hypot(\n                (first.x - second.x) * viewport.width * this.zoom,\n                (first.y - second.y) * viewport.height * this.zoom\n            );\n        },\n    };\n};\n", "document.addEventListener('alpine:init', () => {\n    const EMPTY_RECT = null;\n    // Single source for the combined-strength mapping; the server stores the\n    // resolved blur/darken values, so preview and serialization must agree.\n    const STRENGTH_MAX_BLUR = 0.014;\n    const STRENGTH_MAX_DARKEN = 0.4;\n\n    function clamp(value, min, max) {\n        return Math.min(max, Math.max(min, value));\n    }\n\n    function rounded(value) {\n        return Math.round(value * 1000000) / 1000000;\n    }\n\n    function distance(a, b) {\n        return Math.hypot(a.x - b.x, a.y - b.y);\n    }\n\n    function midpoint(a, b) {\n        return {x: (a.x + b.x) / 2, y: (a.y + b.y) / 2};\n    }\n\n    function highlightOperation(operations) {\n        const list = operations && Array.isArray(operations.operations)\n            ? operations.operations\n            : [];\n        return list.find((operation) => (\n            operation.type === 'highlight_rect' || operation.type === 'highlight_polygon'\n        )) || null;\n    }\n\n    function cropOperation(operations) {\n        const list = operations && Array.isArray(operations.operations)\n            ? operations.operations\n            : [];\n        return list.find((operation) => operation.type === 'crop_rect') || null;\n    }\n\n    Alpine.data('highlightEditor', () => ({\n        editing: false,\n        applying: false,\n        discardOpen: false,\n        error: '',\n        config: {},\n        activeTool: 'highlight',\n        highlightShape: 'rect',\n        highlightRect: EMPTY_RECT,\n        polygonPoints: [],\n        polygonClosed: false,\n        polygonPointer: null,\n        polygonError: '',\n        cropRect: EMPTY_RECT,\n        guideVisible: false,\n        shapeChangeOpen: false,\n        cornerRadius: 8,\n        strength: 55,\n        borderWidth: 2,\n        borderColor: '#ffffff',\n        zoom: 1,\n        panX: 0,\n        panY: 0,\n        // Bumped when the viewport box changes (editor opened, window resized).\n        // Style getters measure the viewport via getBoundingClientRect, which\n        // is not reactive \u2014 reading this counter makes them re-evaluate.\n        viewportTick: 0,\n        _initialOperations: '{}',\n        _pointers: {},\n        _gesture: null,\n        _gestureStart: null,\n        _beforeUnloadHandler: null,\n        _htmxHandler: null,\n        _resizeHandler: null,\n        _pendingNavHref: null,\n        _viewportElement: null,\n\n        ...window.highlightPolygonEditorMethods(),\n\n        init() {\n            this._viewportElement = this.$el.querySelector('[data-highlight-stage]');\n            const configElement = this.$el.closest('[data-highlight-editor-config]');\n            try {\n                this.config = JSON.parse(configElement?.dataset.highlightEditorConfig || '{}');\n            } catch (_) {\n                this.config = {};\n            }\n            this.loadOperations(this.config.operations || {});\n            this._initialOperations = JSON.stringify(this.serializeOperations());\n\n            this._beforeUnloadHandler = (event) => {\n                if (!this.editing || !this.dirty) return;\n                event.preventDefault();\n                event.returnValue = '';\n            };\n            this._htmxHandler = (event) => {\n                if (!this.editing || !this.dirty || !event.detail.boosted) return;\n                event.preventDefault();\n                this._pendingNavHref = event.detail.elt?.getAttribute?.('href')\n                    || event.detail.requestConfig?.path\n                    || null;\n                this.discardOpen = true;\n            };\n            this._resizeHandler = () => {\n                if (this.editing) this.viewportTick++;\n            };\n            window.addEventListener('beforeunload', this._beforeUnloadHandler);\n            document.addEventListener('htmx:beforeRequest', this._htmxHandler);\n            window.addEventListener('resize', this._resizeHandler);\n        },\n\n        destroy() {\n            window.removeEventListener('beforeunload', this._beforeUnloadHandler);\n            document.removeEventListener('htmx:beforeRequest', this._htmxHandler);\n            window.removeEventListener('resize', this._resizeHandler);\n            this._viewportElement = null;\n        },\n\n        loadOperations(operations) {\n            const highlight = highlightOperation(operations);\n            const crop = cropOperation(operations);\n            const params = highlight?.params || {};\n            const rect = params.rect;\n            this.highlightShape = highlight?.type === 'highlight_polygon' ? 'polygon' : 'rect';\n            this.highlightRect = rect ? {\n                x: Number(rect.x),\n                y: Number(rect.y),\n                width: Number(rect.width),\n                height: Number(rect.height),\n            } : EMPTY_RECT;\n            this.polygonPoints = highlight?.type === 'highlight_polygon'\n                ? (params.points || []).map((point) => ({\n                    x: Number(point.x),\n                    y: Number(point.y),\n                }))\n                : [];\n            this.polygonClosed = this.polygonPoints.length >= 3;\n            this.polygonPointer = null;\n            this.polygonError = '';\n            const cropRect = crop?.params?.rect;\n            this.cropRect = cropRect ? {\n                x: Number(cropRect.x),\n                y: Number(cropRect.y),\n                width: Number(cropRect.width),\n                height: Number(cropRect.height),\n            } : EMPTY_RECT;\n            this.activeTool = highlight ? 'highlight' : (this.cropRect ? 'crop' : 'highlight');\n            this.cornerRadius = clamp(Math.round(Number(params.corner_radius_ratio ?? 0.08) * 100), 0, 40);\n            this.strength = clamp(Math.round((Number(params.outside?.darken ?? 0.22) / STRENGTH_MAX_DARKEN) * 100), 0, 100);\n            // Round to the slider's 0.5 steps so stored recipes survive a reload.\n            this.borderWidth = clamp(Math.round(Number(params.stroke?.width_ratio ?? 0.002) * 2000) / 2, 0, 12);\n            this.borderColor = /^#[0-9a-f]{6}$/i.test(params.stroke?.color || '')\n                ? params.stroke.color\n                : '#ffffff';\n            this.guideVisible = Boolean(this.rect || this.polygonClosed);\n        },\n\n        selectTool(tool) {\n            if (!['highlight', 'crop'].includes(tool) || this.applying) return;\n            this.activeTool = tool;\n            this.guideVisible = Boolean(\n                this.rect || (tool === 'highlight' && this.polygonClosed)\n            );\n            this._gesture = null;\n            this._gestureStart = null;\n        },\n\n        openEditor() {\n            if (this.config.aiBusy || !this.config.baseUrl || !this.config.applyUrl) return;\n            this.loadOperations(this.config.operations || {});\n            this._initialOperations = JSON.stringify(this.serializeOperations());\n            this.zoom = 1;\n            this.panX = 0;\n            this.panY = 0;\n            this.error = '';\n            this.editing = true;\n            this.$dispatch('highlight-editor-mode', {open: true});\n            // The viewport only gets real dimensions once x-show reveals it.\n            this.$nextTick(() => this.viewportTick++);\n        },\n\n        cancel() {\n            if (!this.editing || this.applying) return;\n            if (this.shapeChangeOpen) {\n                this.cancelShapeChange();\n                return;\n            }\n            if (this.discardOpen) return;\n            if (this.dirty) {\n                // Deferred: the modal shell's own window-escape handler runs\n                // later in the same keydown and would instantly re-close it.\n                this.$nextTick(() => { this.discardOpen = true; });\n                return;\n            }\n            this.closeEditor();\n        },\n\n        closeEditor() {\n            this.editing = false;\n            this.error = '';\n            this.shapeChangeOpen = false;\n            this.$dispatch('highlight-editor-mode', {open: false});\n        },\n\n        keepEditing() {\n            this.discardOpen = false;\n            this._pendingNavHref = null;\n        },\n\n        confirmDiscard() {\n            const target = this._pendingNavHref;\n            this._pendingNavHref = null;\n            this.discardOpen = false;\n            this.closeEditor();\n            if (target) window.location.href = target;\n        },\n\n        removeEdits() {\n            this.highlightRect = EMPTY_RECT;\n            this.polygonPoints = [];\n            this.polygonClosed = false;\n            this.polygonPointer = null;\n            this.polygonError = '';\n            this.cropRect = EMPTY_RECT;\n            this.guideVisible = false;\n            this.zoom = 1;\n            this.panX = 0;\n            this.panY = 0;\n        },\n\n        serializeOperations() {\n            const operations = [];\n            if (this.cropRect) {\n                operations.push({\n                    type: 'crop_rect',\n                    version: 1,\n                    params: {rect: this.serializedRect(this.cropRect)},\n                });\n            }\n            if (this.highlightRect) {\n                operations.push({\n                    type: 'highlight_rect',\n                    version: 1,\n                    params: {\n                        rect: this.serializedRect(this.highlightRect),\n                        corner_radius_ratio: rounded(this.cornerRadius / 100),\n                        outside: {\n                            blur_sigma_ratio: rounded((this.strength / 100) * STRENGTH_MAX_BLUR),\n                            darken: rounded((this.strength / 100) * STRENGTH_MAX_DARKEN),\n                        },\n                        stroke: {\n                            width_ratio: rounded(this.borderWidth / 1000),\n                            color: this.borderColor.toUpperCase(),\n                            opacity: 1,\n                        },\n                    },\n                });\n            } else if (this.polygonClosed && this.polygonPoints.length >= 3) {\n                operations.push({\n                    type: 'highlight_polygon',\n                    version: 1,\n                    params: {\n                        points: this.polygonPoints.map((point) => this.serializedPoint(point)),\n                        outside: {\n                            blur_sigma_ratio: rounded((this.strength / 100) * STRENGTH_MAX_BLUR),\n                            darken: rounded((this.strength / 100) * STRENGTH_MAX_DARKEN),\n                        },\n                        stroke: {\n                            width_ratio: rounded(this.borderWidth / 1000),\n                            color: this.borderColor.toUpperCase(),\n                            opacity: 1,\n                        },\n                    },\n                });\n            }\n            if (!operations.length) return {};\n            return {\n                schema_version: 1,\n                operations,\n            };\n        },\n\n        serializedRect(rect) {\n            return {\n                x: rounded(rect.x),\n                y: rounded(rect.y),\n                width: rounded(rect.width),\n                height: rounded(rect.height),\n            };\n        },\n\n        serializedPoint(point) {\n            return {x: rounded(point.x), y: rounded(point.y)};\n        },\n\n        removeCurrentTool() {\n            if (this.activeTool === 'highlight' && this.highlightShape === 'polygon') {\n                this.polygonPoints = [];\n                this.polygonClosed = false;\n                this.polygonPointer = null;\n                this.polygonError = '';\n            } else {\n                this.rect = EMPTY_RECT;\n            }\n            this.guideVisible = false;\n        },\n\n        async apply() {\n            if (!this.canApply) return;\n            this.applying = true;\n            this.error = '';\n            try {\n                const response = await fetch(this.config.applyUrl, {\n                    method: 'POST',\n                    credentials: 'same-origin',\n                    headers: {\n                        'Content-Type': 'application/json',\n                        'X-CSRFToken': this.csrfToken(),\n                        'Accept': 'application/json',\n                    },\n                    body: JSON.stringify({\n                        revision: this.config.revisionId || '',\n                        version: Number(this.config.version || 0),\n                        operations: this.serializeOperations(),\n                    }),\n                });\n                if (!response.ok) {\n                    let message = this.message('applyFailed', 'Die \u00C4nderungen konnten nicht angewendet werden.');\n                    try {\n                        const body = await response.json();\n                        if (body.error === 'ai_edit_active') {\n                            message = this.message('aiBusy', 'F\u00FCr dieses Foto l\u00E4uft gerade eine KI-Bearbeitung.');\n                        } else if (body.error === 'stale_version') {\n                            message = this.message('stale', 'Das Foto wurde zwischenzeitlich ge\u00E4ndert. Bitte laden Sie die Seite neu.');\n                        } else if (body.message) {\n                            message = body.message;\n                        }\n                    } catch (_) {}\n                    throw new Error(message);\n                }\n                const body = await response.json();\n                this.config.version = body.version;\n                this.config.operations = body.operations;\n                this.config.hasEdits = body.hasEdits;\n                this.loadOperations(body.operations);\n                this._initialOperations = JSON.stringify(this.serializeOperations());\n                this.updatePublishedImage(body);\n                this.$dispatch('revision-image-updated', {id: this.config.revisionId, url: body.imageUrl});\n                this.applying = false;\n                this.closeEditor();\n            } catch (error) {\n                this.error = error.message || this.message('applyFailed', 'Die \u00C4nderungen konnten nicht angewendet werden.');\n                this.applying = false;\n            }\n        },\n\n        updatePublishedImage(body) {\n            const image = document.getElementById('photo-image');\n            if (image) {\n                image.src = body.imageUrl;\n                const lightboxLink = image.closest('a');\n                if (lightboxLink) {\n                    lightboxLink.href = body.imageUrl;\n                    if (body.imageWidth && body.imageHeight) {\n                        lightboxLink.style.aspectRatio = body.imageWidth + '/' + body.imageHeight;\n                    }\n                }\n            }\n            document.querySelectorAll('[data-photo-current-image]').forEach((el) => {\n                el.src = body.imageUrl;\n            });\n            const id = this.config.revisionId;\n            if (!id) return;\n            document.querySelectorAll(`[data-manually-edited=\"${id}\"]`).forEach((el) => {\n                el.style.display = body.hasEdits ? '' : 'none';\n            });\n            document.querySelectorAll(`[data-revision-image=\"${id}\"]`).forEach((el) => {\n                el.src = body.imageUrl;\n            });\n            document.querySelectorAll(`[data-revision-link=\"${id}\"]`).forEach((el) => {\n                el.href = body.imageUrl;\n            });\n        },\n\n        message(key, fallback) {\n            return this.config.messages?.[key] || fallback;\n        },\n\n        csrfToken() {\n            return document.querySelector('meta[name=\"csrf-token\"]')?.content || '';\n        },\n\n        startDraw(event) {\n            if (this.activeTool === 'highlight' && this.highlightShape === 'polygon') {\n                this.startPolygonPoint(event);\n                return;\n            }\n            if (this.pointerCount > 0) {\n                this.trackPointer(event);\n                this.beginPinchIfNeeded();\n                return;\n            }\n            this.trackPointer(event);\n            const point = this.imagePoint(event);\n            this._gesture = 'draw';\n            this._gestureStart = {\n                point,\n                client: {x: event.clientX, y: event.clientY},\n                originalRect: this.rect ? {...this.rect} : null,\n                moved: false,\n            };\n            this.capturePointer(event);\n        },\n\n        startMove(event) {\n            this.trackPointer(event);\n            if (this.pointerCount > 1) {\n                this.beginPinchIfNeeded();\n                return;\n            }\n            this.guideVisible = true;\n            this._gesture = 'move';\n            this._gestureStart = {point: this.imagePoint(event), rect: {...this.rect}};\n            this.capturePointer(event);\n        },\n\n        startResize(event, handle) {\n            this.trackPointer(event);\n            if (this.pointerCount > 1) {\n                this.beginPinchIfNeeded();\n                return;\n            }\n            this.guideVisible = true;\n            this._gesture = 'resize';\n            this._gestureStart = {\n                point: this.imagePoint(event),\n                rect: {...this.rect},\n                handle: handle || 'br',\n            };\n            this.capturePointer(event);\n        },\n\n        pointerMove(event) {\n            if (!this._pointers[event.pointerId]) {\n                if (\n                    this.activeTool === 'highlight'\n                    && this.highlightShape === 'polygon'\n                    && !this.polygonClosed\n                    && this.polygonPoints.length\n                    && event.pointerType !== 'touch'\n                ) this.polygonPointer = this.imagePoint(event);\n                return;\n            }\n            this.trackPointer(event);\n            if (this.pointerCount > 1 || this._gesture === 'pinch') {\n                this.updatePinch();\n                return;\n            }\n            if (!this._gestureStart) return;\n            const point = this.imagePoint(event);\n            if (this._gesture === 'draw') this.updateDraw(event, point);\n            else if (this._gesture === 'move') this.updateMove(point);\n            else if (this._gesture === 'resize') this.updateResize(point);\n            else if (this._gesture === 'polygon-point') {\n                this.polygonPointer = point;\n                this.markPolygonGestureMoved(event, 8);\n            } else if (this._gesture === 'polygon-close') {\n                this.markPolygonGestureMoved(event, 8);\n            } else if (this._gesture === 'polygon-vertex') {\n                this.markPolygonGestureMoved(event, 3);\n                if (this._gestureStart.moved) {\n                    this.polygonPoints[this._gestureStart.index] = point;\n                }\n            } else if (this._gesture === 'polygon-move') {\n                this.updatePolygonMove(point);\n            }\n        },\n\n        pointerEnd(event) {\n            const gesture = this._gesture;\n            const wasDraw = this._gesture === 'draw';\n            const moved = this._gestureStart?.moved;\n            const originalRect = this._gestureStart?.originalRect;\n            delete this._pointers[event.pointerId];\n\n            if (this._gesture === 'pinch') {\n                if (this.pointerCount < 2) this._gestureStart = null;\n                if (this.pointerCount === 0) this._gesture = null;\n                return;\n            }\n            if (gesture?.startsWith('polygon-')) {\n                this.finishPolygonGesture(event, gesture);\n                return;\n            }\n            if (wasDraw && !moved) {\n                this.rect = originalRect;\n                this.guideVisible = false;\n            } else if (wasDraw && this.rect) {\n                // A straight-line drag yields a zero-size rect: invisible, yet\n                // it would enable Apply and be rejected by the server.\n                const minimum = this.minimumSelectionSize;\n                if (this.rect.width < minimum.x || this.rect.height < minimum.y) {\n                    this.rect = originalRect;\n                    this.guideVisible = Boolean(originalRect);\n                } else {\n                    this.guideVisible = true;\n                }\n            } else if (this.rect) {\n                this.guideVisible = true;\n            }\n            this._gesture = null;\n            this._gestureStart = null;\n        },\n\n        updateDraw(event, point) {\n            const distanceMoved = Math.hypot(\n                event.clientX - this._gestureStart.client.x,\n                event.clientY - this._gestureStart.client.y\n            );\n            if (!this._gestureStart.moved && distanceMoved < 5) return;\n            this._gestureStart.moved = true;\n            const start = this._gestureStart.point;\n            this.rect = {\n                x: clamp(Math.min(start.x, point.x), 0, 1),\n                y: clamp(Math.min(start.y, point.y), 0, 1),\n                width: Math.abs(point.x - start.x),\n                height: Math.abs(point.y - start.y),\n            };\n            this.guideVisible = true;\n        },\n\n        updateMove(point) {\n            const start = this._gestureStart;\n            const dx = point.x - start.point.x;\n            const dy = point.y - start.point.y;\n            this.rect = {\n                ...start.rect,\n                x: clamp(start.rect.x + dx, 0, 1 - start.rect.width),\n                y: clamp(start.rect.y + dy, 0, 1 - start.rect.height),\n            };\n        },\n\n        updateResize(point) {\n            const original = this._gestureStart.rect;\n            const handle = this._gestureStart.handle;\n            const minimum = this.minimumSelectionSize;\n            let left = original.x;\n            let top = original.y;\n            let right = original.x + original.width;\n            let bottom = original.y + original.height;\n            if (handle.includes('l')) left = clamp(point.x, 0, Math.max(0, right - minimum.x));\n            else if (handle.includes('r')) right = clamp(point.x, left + minimum.x, 1);\n            if (handle.includes('t')) top = clamp(point.y, 0, Math.max(0, bottom - minimum.y));\n            else if (handle.includes('b')) bottom = clamp(point.y, top + minimum.y, 1);\n            this.rect = {x: left, y: top, width: right - left, height: bottom - top};\n        },\n\n        trackPointer(event) {\n            this._pointers[event.pointerId] = {x: event.clientX, y: event.clientY};\n        },\n\n        capturePointer(event) {\n            try { this._viewportElement?.setPointerCapture(event.pointerId); } catch (_) {}\n        },\n\n        beginPinchIfNeeded() {\n            if (this.pointerCount < 2) return;\n            if (!this._viewportElement) return;\n            if (this._gestureStart?.originalPoints) {\n                this.polygonPoints = this._gestureStart.originalPoints;\n            }\n            this.polygonPointer = null;\n            const points = Object.values(this._pointers).slice(0, 2);\n            const viewport = this._viewportElement.getBoundingClientRect();\n            const mid = midpoint(points[0], points[1]);\n            this._gesture = 'pinch';\n            this._gestureStart = {\n                distance: Math.max(1, distance(points[0], points[1])),\n                midpoint: {x: mid.x - viewport.left, y: mid.y - viewport.top},\n                zoom: this.zoom,\n                panX: this.panX,\n                panY: this.panY,\n            };\n        },\n\n        updatePinch() {\n            if (this.pointerCount < 2) return;\n            if (this._gesture !== 'pinch') this.beginPinchIfNeeded();\n            if (!this._gestureStart || !this._viewportElement) return;\n            const points = Object.values(this._pointers).slice(0, 2);\n            const viewport = this._viewportElement.getBoundingClientRect();\n            const mid = midpoint(points[0], points[1]);\n            const currentMid = {x: mid.x - viewport.left, y: mid.y - viewport.top};\n            const nextZoom = clamp(\n                this._gestureStart.zoom * distance(points[0], points[1]) / this._gestureStart.distance,\n                1,\n                4\n            );\n            const anchorX = (this._gestureStart.midpoint.x - this._gestureStart.panX) / this._gestureStart.zoom;\n            const anchorY = (this._gestureStart.midpoint.y - this._gestureStart.panY) / this._gestureStart.zoom;\n            this.zoom = nextZoom;\n            this.panX = currentMid.x - anchorX * nextZoom;\n            this.panY = currentMid.y - anchorY * nextZoom;\n            this.clampPan();\n        },\n\n        clampPan() {\n            if (!this._viewportElement) return;\n            const viewport = this._viewportElement.getBoundingClientRect();\n            this.panX = clamp(this.panX, viewport.width * (1 - this.zoom), 0);\n            this.panY = clamp(this.panY, viewport.height * (1 - this.zoom), 0);\n        },\n\n        resetZoom() {\n            this.zoom = 1;\n            this.panX = 0;\n            this.panY = 0;\n        },\n\n        imagePoint(event) {\n            if (!this._viewportElement) return {x: 0, y: 0};\n            const viewport = this._viewportElement.getBoundingClientRect();\n            return {\n                x: clamp((event.clientX - viewport.left - this.panX) / (viewport.width * this.zoom), 0, 1),\n                y: clamp((event.clientY - viewport.top - this.panY) / (viewport.height * this.zoom), 0, 1),\n            };\n        },\n\n        get pointerCount() {\n            return Object.keys(this._pointers).length;\n        },\n\n        get rect() {\n            if (this.activeTool === 'crop') return this.cropRect;\n            return this.highlightShape === 'rect' ? this.highlightRect : EMPTY_RECT;\n        },\n\n        set rect(value) {\n            if (this.activeTool === 'crop') this.cropRect = value;\n            else this.highlightRect = value;\n        },\n\n        get dirty() {\n            const polygonDraft = (\n                this.highlightShape === 'polygon'\n                && this.polygonPoints.length > 0\n                && !this.polygonClosed\n            );\n            return polygonDraft\n                || JSON.stringify(this.serializeOperations()) !== this._initialOperations;\n        },\n\n        get canApply() {\n            const polygonInProgress = (\n                this.highlightShape === 'polygon'\n                && this.polygonPoints.length > 0\n                && !this.polygonClosed\n            );\n            return this.dirty && !this.applying && !polygonInProgress;\n        },\n\n        get hasHighlightSelection() {\n            return Boolean(\n                this.highlightRect\n                || (this.polygonClosed && this.polygonPoints.length >= 3)\n            );\n        },\n\n        get hasSavedEdits() {\n            return Boolean(this.config.hasEdits);\n        },\n\n        get viewportStyle() {\n            const width = Number(this.config.width) || 4;\n            const height = Number(this.config.height) || 3;\n            return 'aspect-ratio:' + width + '/' + height;\n        },\n\n        get stageStyle() {\n            return 'transform:translate(' + this.panX + 'px,' + this.panY + 'px) scale(' + this.zoom + ');transform-origin:top left';\n        },\n\n        get outsideImageStyle() {\n            if (this.activeTool !== 'highlight' || !this.hasHighlightSelection) return '';\n            this.viewportTick;\n            const viewport = this._viewportElement?.getBoundingClientRect();\n            const shortEdge = viewport ? Math.min(viewport.width, viewport.height) : 600;\n            const blur = (this.strength / 100) * STRENGTH_MAX_BLUR * shortEdge;\n            const brightness = 1 - (this.strength / 100) * STRENGTH_MAX_DARKEN;\n            return 'filter:blur(' + blur + 'px) brightness(' + brightness + ')';\n        },\n\n        get sharpClipStyle() {\n            if (this.activeTool !== 'highlight' || !this.hasHighlightSelection) return 'display:none';\n            if (this.highlightShape === 'polygon') {\n                return 'clip-path:polygon(' + this.polygonPoints.map((point) => (\n                    (point.x * 100) + '% ' + (point.y * 100) + '%'\n                )).join(',') + ')';\n            }\n            const top = this.highlightRect.y * 100;\n            const right = (1 - this.highlightRect.x - this.highlightRect.width) * 100;\n            const bottom = (1 - this.highlightRect.y - this.highlightRect.height) * 100;\n            const left = this.highlightRect.x * 100;\n            return 'clip-path:inset(' + top + '% ' + right + '% ' + bottom + '% ' + left + '% round ' + this.selectionRadiusPx + 'px)';\n        },\n\n        get selectionStyle() {\n            if (!this.rect) return 'display:none';\n            return 'left:' + (this.rect.x * 100) + '%;top:' + (this.rect.y * 100) + '%;width:' + (this.rect.width * 100) + '%;height:' + (this.rect.height * 100) + '%;border-radius:' + this.selectionRadiusPx + 'px';\n        },\n\n        get outputBorderStyle() {\n            return this.selectionStyle + ';border:' + this.outputBorderPx + 'px solid ' + this.borderColor;\n        },\n\n        get polygonSvgPoints() {\n            return this.polygonPoints.map((point) => (\n                (point.x * 100) + ',' + (point.y * 100)\n            )).join(' ');\n        },\n\n        get openPolygonSvgPoints() {\n            const points = [...this.polygonPoints];\n            if (!this.polygonClosed && this.polygonPointer && points.length) {\n                points.push(this.polygonPointer);\n            }\n            return points.map((point) => (\n                (point.x * 100) + ',' + (point.y * 100)\n            )).join(' ');\n        },\n\n        polygonHandleStyle(point) {\n            return 'left:' + (point.x * 100) + '%;top:' + (point.y * 100)\n                + '%;width:' + (44 / this.zoom) + 'px;height:' + (44 / this.zoom)\n                + 'px;transform:translate(-50%,-50%)';\n        },\n\n        get cropShadeStyle() {\n            return this.activeTool === 'crop' && this.cropRect\n                ? 'border:' + (1 / this.zoom) + 'px solid white;box-shadow:0 0 0 9999px rgba(0,0,0,0.62)'\n                : 'display:none';\n        },\n\n        get selectionRadiusPx() {\n            if (this.activeTool === 'crop' || !this.rect || !this._viewportElement) return 0;\n            this.viewportTick;\n            const viewport = this._viewportElement.getBoundingClientRect();\n            return (this.cornerRadius / 100) * Math.min(\n                this.rect.width * viewport.width,\n                this.rect.height * viewport.height\n            );\n        },\n\n        get outputBorderPx() {\n            if (!this._viewportElement) return 0;\n            this.viewportTick;\n            const viewport = this._viewportElement.getBoundingClientRect();\n            return (this.borderWidth / 1000) * Math.min(viewport.width, viewport.height);\n        },\n\n        get guideBorderPx() {\n            return 2 / this.zoom;\n        },\n\n        get handleStyle() {\n            return 'width:' + (36 / this.zoom) + 'px;height:' + (36 / this.zoom) + 'px';\n        },\n\n        get handleDotStyle() {\n            return 'width:' + (12 / this.zoom) + 'px;height:' + (12 / this.zoom) + 'px;border-width:' + (2 / this.zoom) + 'px';\n        },\n\n        get minimumSelectionSize() {\n            if (!this._viewportElement) return {x: 0.03, y: 0.03};\n            const viewport = this._viewportElement.getBoundingClientRect();\n            return {\n                x: Math.min(0.2, 32 / (viewport.width * this.zoom)),\n                y: Math.min(0.2, 32 / (viewport.height * this.zoom)),\n            };\n        },\n    }));\n});\n", "document.addEventListener('alpine:init', () => {\n    const I18N = window.I18N || {};\n\n    Alpine.data('batchOutdoorPresets', () => ({\n        outdoor: { optimize: true, sunshine: true, declutter: true },\n        init() {\n            const prefs = JSON.parse(this.$el.dataset.presetPrefs || '{}');\n            if (prefs.outdoor) {\n                this.outdoor.optimize = prefs.outdoor.includes('optimize');\n                this.outdoor.sunshine = prefs.outdoor.includes('sunshine');\n                this.outdoor.declutter = prefs.outdoor.includes('declutter');\n            }\n        },\n    }));\n\n    Alpine.data('batchIndoorPresets', () => ({\n        indoor: { optimize_indoor: true, declutter_indoor: true, details: true, staging: true },\n        replaceFurniture: false,\n        furnitureStyle: '',\n        furnitureInstructions: '',\n        styleOpen: false,\n        styleOptions: [\n            {v:'',l:I18N.styleUnspecified || 'Keine Vorgabe'}, {v:'modern',l:'Modern'},\n            {v:'skandinavisch',l:I18N.styleScandinavian || 'Skandinavisch'}, {v:'klassisch',l:I18N.styleClassic || 'Klassisch'},\n            {v:'landhausstil',l:I18N.styleCountry || 'Landhausstil'}, {v:'industriell',l:I18N.styleIndustrial || 'Industriell'},\n        ],\n        init() {\n            const prefs = JSON.parse(this.$el.dataset.presetPrefs || '{}');\n            if (prefs.indoor) {\n                this.indoor.optimize_indoor = prefs.indoor.includes('optimize_indoor');\n                this.indoor.declutter_indoor = prefs.indoor.includes('declutter_indoor');\n                this.indoor.details = prefs.indoor.includes('details');\n                this.indoor.staging = prefs.indoor.includes('staging');\n            }\n            if (typeof prefs.replace_furniture === 'boolean')\n                this.replaceFurniture = prefs.replace_furniture;\n            if (prefs.furniture_style)\n                this.furnitureStyle = prefs.furniture_style;\n        },\n    }));\n\n    // One \"Einheitlich m\u00F6blieren\" line in the batch modal: the photos of one\n    // room, staged as one set while ticked. A tap on a thumbnail takes that\n    // photo out of the room on the server too, so it is staged alone and the\n    // correction is recorded.\n    Alpine.data('roomSetLine', () => ({\n        checked: true,\n        photoIds: [],\n        removed: [],\n        countTemplate: '{n}',\n        removeUrlTemplate: '',\n\n        init() {\n            const data = this.$root.dataset;\n            this.photoIds = (data.photoIds || '').split(',').filter(Boolean);\n            this.countTemplate = data.countTemplate || '{n}';\n            this.removeUrlTemplate = data.removeUrlTemplate || '';\n        },\n\n        get activeIds() {\n            return this.photoIds.filter(id => !this.removed.includes(id));\n        },\n\n        get countText() {\n            return this.countTemplate.replace('{n}', this.activeIds.length);\n        },\n\n        remove(photoId) {\n            if (this.removed.includes(photoId)) return;\n            this.removed.push(photoId);\n            if (this.activeIds.length < 2) this.checked = false;\n            const url = this.removeUrlTemplate.replace('PHOTO_ID', photoId);\n            const meta = document.querySelector('meta[name=\"csrf-token\"]');\n            fetch(url, {\n                method: 'POST',\n                headers: { 'X-CSRFToken': meta ? meta.content : '', 'X-Requested-With': 'XMLHttpRequest' },\n            }).catch(err => console.error(err));\n        },\n    }));\n\n    Alpine.data('batchSelect', () => ({\n        selectedPhotos: {},\n        modalOpen: false,\n        loading: false,\n        modalUrl: '',\n        upscaleUrl: '',\n        downloadUrl: '',\n        deleteUrl: '',\n        csrf: '',\n\n        get count() { return Object.keys(this.selectedPhotos).length; },\n        get hasSelection() { return this.count > 0; },\n        get countLabel() {\n            return this.count === 1 ? (I18N.photoSelectedSingular || '1 Foto ausgew\u00E4hlt') : this.count + ' ' + (I18N.photosSelectedPlural || 'Fotos ausgew\u00E4hlt');\n        },\n\n        togglePhoto(id, checked) {\n            if (checked) this.selectedPhotos[id] = true;\n            else delete this.selectedPhotos[id];\n        },\n\n        isSelectableCheckbox(checkbox) {\n            return !checkbox.disabled && checkbox.offsetParent !== null;\n        },\n\n        // A group is a type section under \"Nach Bereich\" and a status group\n        // under \"Nach Status\". Only one arrangement renders at a time.\n        getGroupCheckboxes(groupKey) {\n            const selector = '.batch-select-checkbox[data-photo-group=\"' + groupKey + '\"]';\n            return Array.from(this.$root.querySelectorAll(selector))\n                .filter(cb => this.isSelectableCheckbox(cb));\n        },\n\n        isGroupFullySelected(groupKey) {\n            const checkboxes = this.getGroupCheckboxes(groupKey);\n            return checkboxes.length > 0 && checkboxes.every(cb => this.isSelected(cb.dataset.photoId));\n        },\n\n        isGroupPartiallySelected(groupKey) {\n            const checkboxes = this.getGroupCheckboxes(groupKey);\n            if (!checkboxes.length) return false;\n            const selectedCount = checkboxes.filter(cb => this.isSelected(cb.dataset.photoId)).length;\n            return selectedCount > 0 && selectedCount < checkboxes.length;\n        },\n\n        toggleGroup(groupKey, checked) {\n            this.getGroupCheckboxes(groupKey).forEach(cb => {\n                cb.checked = checked;\n                this.togglePhoto(cb.dataset.photoId, checked);\n            });\n        },\n\n        isSelected(id) { return !!this.selectedPhotos[id]; },\n\n        clearSelection() {\n            this.selectedPhotos = {};\n            this.$root.querySelectorAll('.batch-select-checkbox').forEach(cb => { cb.checked = false; });\n        },\n\n        openModal() {\n            if (!this.hasSelection || this.loading) return;\n            this.loading = true;\n            this.modalOpen = true;\n            const params = Object.keys(this.selectedPhotos).map(id => 'photos=' + encodeURIComponent(id)).join('&');\n            htmx.ajax('GET', this.modalUrl + '?' + params, { target: '#batch-modal-content', swap: 'innerHTML' })\n                .finally(() => { this.loading = false; });\n        },\n\n        openUpscaleModal() {\n            if (!this.hasSelection || this.loading) return;\n            this.loading = true;\n            this.modalOpen = true;\n            const params = Object.keys(this.selectedPhotos).map(id => 'photos=' + encodeURIComponent(id)).join('&');\n            htmx.ajax('GET', this.upscaleUrl + '?' + params, { target: '#batch-modal-content', swap: 'innerHTML' })\n                .finally(() => { this.loading = false; });\n        },\n\n        openDownloadModal() {\n            if (this.loading) return;\n            this.loading = true;\n            const params = Object.keys(this.selectedPhotos).map(id => 'photos=' + encodeURIComponent(id)).join('&');\n            const url = this.downloadUrl + (params ? '?' + params : '');\n            htmx.ajax('GET', url, { target: '#download-modal-container', swap: 'innerHTML' })\n                .finally(() => { this.loading = false; });\n        },\n\n        closeModal() { this.modalOpen = false; },\n        closeAndRefresh() { this.modalOpen = false; this.clearSelection(); htmx.trigger('#photo-grid', 'refresh'); },\n\n        openDeleteModal() {\n            const photoIds = Object.keys(this.selectedPhotos);\n            if (!photoIds.length) return;\n            Alpine.store('modal')?.show('batch-photo-delete', {\n                count: photoIds.length,\n                deleting: false,\n                onCancel: () => this.closeDeleteModal(),\n                onConfirm: () => this.submitDelete(photoIds),\n            });\n        },\n\n        closeDeleteModal() {\n            const modal = Alpine.store('modal');\n            if (modal?.context?.deleting) return;\n            modal?.close();\n        },\n\n        submitDelete(photoIds) {\n            const modal = Alpine.store('modal');\n            const context = modal?.context;\n            if (!photoIds?.length || context?.deleting) return;\n            context.deleting = true;\n            const url = this.deleteUrl;\n            const csrf = this.csrf;\n            const formData = new FormData();\n            photoIds.forEach(id => formData.append('photo_ids', id));\n            fetch(url, {\n                method: 'POST',\n                body: formData,\n                headers: { 'X-CSRFToken': csrf, 'X-Requested-With': 'XMLHttpRequest' },\n            })\n                .then(r => { if (!r.ok) throw new Error('Delete failed (' + r.status + ')'); })\n                .then(() => {\n                    Alpine.store('modal')?.close();\n                    this.clearSelection();\n                    htmx.trigger('#photo-grid', 'refresh');\n                })\n                .catch(err => {\n                    console.error(err);\n                    window.alert(I18N.deleteFailed || 'L\u00F6schen fehlgeschlagen. Bitte erneut versuchen.');\n                })\n                .finally(() => {\n                    if (modal?.context === context) context.deleting = false;\n                });\n        },\n\n        init() {\n            this.modalUrl = this.$root.dataset.modalUrl;\n            this.upscaleUrl = this.$root.dataset.upscaleUrl;\n            this.downloadUrl = this.$root.dataset.downloadUrl;\n            this.deleteUrl = this.$root.dataset.deleteUrl;\n            this.csrf = this.$root.dataset.csrf;\n\n            // Listen for batch clear events from HTMX-swapped partials\n            document.addEventListener('batch:clear', () => this.clearSelection());\n\n            // Re-check boxes after HTMX swaps photo cards or re-renders the\n            // whole grid (arrangement switch, completion refresh). Selection\n            // lives on this component, which sits outside #photo-grid.\n            this.$root.addEventListener('htmx:afterSwap', () => {\n                this.$root.querySelectorAll('.batch-select-checkbox').forEach(cb => {\n                    cb.checked = this.isSelected(cb.dataset.photoId);\n                });\n                // Force Alpine to recompute section header tri-state bindings.\n                this.selectedPhotos = { ...this.selectedPhotos };\n            });\n        },\n    }));\n\n});\n", "document.addEventListener('alpine:init', () => {\n    const I18N = window.I18N || {};\n\n    Alpine.data('photoUpload', () => ({\n        isOpen: false,\n        dragging: false,\n        hasUploads: false,\n        pendingUploads: 0,\n        // Photos stored since the last batch event, so one batch = one event.\n        uploadedInBatch: 0,\n        // URL import state\n        activeTab: 'device',\n        importUrl: '',\n        scraping: false,\n        importing: false,\n        scrapedImages: [],\n        scrapedMetadata: {},\n\n        open(files) {\n            this.isOpen = true;\n            this.lockScroll();\n            // The empty-state card is a drop target: it dispatches the open\n            // event with the dropped files so the modal starts uploading\n            // instead of asking for them again.\n            if (files && files.length) this.handleFiles(files);\n        },\n\n        close() {\n            if (this.pendingUploads > 0 || this.importing) return;\n            this.isOpen = false;\n            this.unlockScroll();\n            this.resetUrlImport();\n            if (this.hasUploads) htmx.trigger('#photo-grid', 'refresh');\n        },\n\n        // GA4 funnel step. Fires when the last upload of a batch lands, so a\n        // 12-photo drop reports once with count 12, not twelve times.\n        trackBatchComplete() {\n            if (this.pendingUploads > 0 || this.uploadedInBatch === 0) return;\n            window.trackEvent('photo_upload_complete', {\n                property_id: this.$root.dataset.propertyId || '',\n                count: this.uploadedInBatch,\n            });\n            this.uploadedInBatch = 0;\n        },\n\n        lockScroll()   { window._scrollLock.lock(); },\n        unlockScroll() { window._scrollLock.unlock(); },\n\n        openFilePicker() { this.$refs.fileInput?.click(); },\n\n        onFileSelect(e) {\n            this.handleFiles(e.target.files);\n            e.target.value = '';\n        },\n\n        onDrop(e) {\n            this.dragging = false;\n            this.handleFiles(e.dataTransfer.files);\n        },\n\n        handleFiles(files) {\n            Array.from(files).forEach(file => {\n                const rejection = this.rejectionReason(file);\n                if (rejection) {\n                    this.showRejected(file, rejection);\n                    return;\n                }\n                this.uploadFile(file);\n            });\n        },\n\n        rejectionReason(file) {\n            const maxSize = 20 * 1024 * 1024;\n            if (!this.hasAllowedType(file)) return I18N.invalidImageType || 'Bitte w\u00E4hlen Sie ein JPG, PNG oder WebP Bild.';\n            if (file.size > maxSize) return I18N.fileTooLarge || 'Datei zu gro\u00DF (max. 20 MB)';\n            return null;\n        },\n\n        hasAllowedType(file) {\n            const validTypes = ['image/jpeg', 'image/png', 'image/webp'];\n            // Some drag sources and Windows apps report an empty MIME type;\n            // fall back to the file extension instead of dropping the file.\n            if (!file.type) return /\\.(jpe?g|png|webp)$/i.test(file.name || '');\n            return validTypes.includes(file.type);\n        },\n\n        // Rejected before any request: the file never reaches the server, so\n        // the row is final and carries no retry button.\n        showRejected(file, msg) {\n            this.hasUploads = true;\n            const rowId = 'rejected-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9);\n            const uploadRows = this.$refs.uploadRows;\n            if (uploadRows) uploadRows.insertAdjacentHTML('beforeend', this.errorRowHtml(rowId, file.name, msg));\n        },\n\n        errorRowHtml(rowId, name, msg, retryId) {\n            return '<div id=\"' + rowId + '\" class=\"flex items-center gap-4 p-3 bg-red-50 rounded-lg border border-red-200\">' +\n                '<div class=\"w-16 h-12 bg-red-100 rounded flex items-center justify-center flex-shrink-0\">' +\n                '<svg class=\"w-5 h-5 text-red-500\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">' +\n                '<path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\"/>' +\n                '</svg></div>' +\n                '<div class=\"flex-1 min-w-0\">' +\n                '<p class=\"font-medium text-red-800 truncate text-sm\">' + this.escapeHtml(name) + '</p>' +\n                '<p class=\"text-sm text-red-600\">' + this.escapeHtml(msg) + '</p>' +\n                '</div>' +\n                (retryId ? '<button id=\"' + retryId + '\" class=\"px-3 py-1 text-xs font-medium text-red-700 bg-red-100 hover:bg-red-200 rounded transition-colors cursor-pointer flex-shrink-0\">' + (I18N.retry || 'Nochmal') + '</button>' : '') +\n                '</div>';\n        },\n\n        uploadFile(file) {\n            this.hasUploads = true;\n            this.pendingUploads++;\n\n            const tempId = 'temp-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9);\n            const previewUrl = URL.createObjectURL(file);\n            const uploadUrl = this.$root.dataset.uploadUrl;\n            const csrfToken = document.querySelector('meta[name=\"csrf-token\"]').content;\n            // Capture the ref now: `this.$refs` throws (_x_refs) once an hx-boost\n            // navigation tears the component down mid-upload.\n            const uploadRows = this.$refs.uploadRows;\n\n            const placeholderHtml = '<div id=\"' + tempId + '\" class=\"flex items-center gap-4 p-3 bg-soft rounded-lg border border-border\">' +\n                '<div class=\"w-16 h-12 bg-muted rounded overflow-hidden flex-shrink-0\">' +\n                '<img src=\"' + previewUrl + '\" class=\"w-full h-full object-cover\">' +\n                '</div>' +\n                '<div class=\"flex-1 min-w-0\">' +\n                '<p class=\"font-medium text-foreground truncate text-sm\">' + this.escapeHtml(file.name) + '</p>' +\n                '<div class=\"flex items-center gap-1.5 text-sm text-muted-foreground mt-0.5\">' +\n                '<svg class=\"w-4 h-4 animate-spin\" fill=\"none\" viewBox=\"0 0 24 24\">' +\n                '<circle class=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\"></circle>' +\n                '<path class=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z\"></path>' +\n                '</svg>' +\n                '<span>' + (I18N.uploading || 'Wird hochgeladen...') + '</span>' +\n                '</div></div></div>';\n            if (uploadRows) uploadRows.insertAdjacentHTML('beforeend', placeholderHtml);\n\n            const doUpload = () => {\n                const formData = new FormData();\n                formData.append('photo', file);\n                return fetch(uploadUrl, {\n                    method: 'POST',\n                    headers: { 'X-CSRFToken': csrfToken },\n                    body: formData\n                }).then(response => {\n                    if (!response.ok) return response.json().then(data => { throw new Error(data.error || I18N.uploadFailed || 'Upload fehlgeschlagen'); });\n                    return response.json();\n                });\n            };\n\n            const showError = (msg) => {\n                const placeholder = document.getElementById(tempId);\n                if (placeholder) {\n                    const retryId = tempId + '-retry';\n                    placeholder.outerHTML = this.errorRowHtml(tempId, file.name, msg, retryId);\n                    const retryBtn = document.getElementById(retryId);\n                    if (retryBtn) retryBtn.addEventListener('click', () => {\n                        const row = document.getElementById(tempId);\n                        if (row) row.outerHTML = placeholderHtml;\n                        this.pendingUploads++;\n                        doUpload().then(onSuccess).catch(e => showError(friendlyMsg(e))).finally(onDone);\n                    });\n                }\n            };\n\n            const friendlyMsg = (error) => {\n                if (error instanceof TypeError) return I18N.uploadFailedRetry || 'Upload fehlgeschlagen \u2014 bitte erneut versuchen';\n                return error.message || I18N.uploadFailed || 'Upload fehlgeschlagen';\n            };\n\n            const onSuccess = (data) => {\n                this.uploadedInBatch++;\n                const placeholder = document.getElementById(tempId);\n                if (placeholder && data.row_html) {\n                    placeholder.outerHTML = data.row_html;\n                    if (uploadRows) htmx.process(uploadRows);\n                }\n            };\n\n            const onDone = () => {\n                URL.revokeObjectURL(previewUrl);\n                this.pendingUploads--;\n                this.trackBatchComplete();\n            };\n\n            doUpload()\n            .then(onSuccess)\n            .catch(error => {\n                // Auto-retry once for transient errors (e.g. iOS Safari after photo picker)\n                if (error instanceof TypeError) {\n                    return new Promise(r => setTimeout(r, 500))\n                        .then(doUpload)\n                        .then(onSuccess)\n                        .catch(e => showError(friendlyMsg(e)));\n                }\n                showError(friendlyMsg(error));\n            })\n            .finally(onDone);\n        },\n\n        // --- URL Import ---\n\n        async startScrape() {\n            const url = this.importUrl.trim();\n            if (!url) return;\n\n            this.scraping = true;\n            this.scrapedImages = [];\n            // Capture the ref now, before any await \u2014 `this.$refs` throws (_x_refs)\n            // if an hx-boost navigation tears the component down mid-scrape.\n            const scrapeResults = this.$refs.scrapeResults;\n            if (scrapeResults) scrapeResults.innerHTML = '';\n\n            const scrapeUrl = this.$root.dataset.scrapeUrl;\n            const csrfToken = document.querySelector('meta[name=\"csrf-token\"]').content;\n\n            try {\n                const formData = new FormData();\n                formData.append('url', url);\n\n                const res = await fetch(scrapeUrl, {\n                    method: 'POST',\n                    headers: { 'X-CSRFToken': csrfToken },\n                    body: formData,\n                });\n\n                const html = await res.text();\n                if (scrapeResults) {\n                    scrapeResults.innerHTML = html;\n\n                    // Read image URLs and metadata from embedded JSON\n                    const dataEl = scrapeResults.querySelector('#scraped-image-data');\n                    if (dataEl) {\n                        try { this.scrapedImages = JSON.parse(dataEl.textContent); } catch(e) {}\n                    }\n                    const metaEl = scrapeResults.querySelector('#scraped-metadata');\n                    if (metaEl) {\n                        try { this.scrapedMetadata = JSON.parse(metaEl.textContent); } catch(e) {}\n                    }\n                }\n            } catch (e) {\n                if (scrapeResults) scrapeResults.innerHTML = '<p class=\"text-sm text-alert-error-foreground text-center py-4\">' + (I18N.connectionErrorRetry || 'Verbindungsfehler. Bitte erneut versuchen.') + '</p>';\n            } finally {\n                this.scraping = false;\n            }\n        },\n\n        resetUrlImport() {\n            this.scrapedImages = [];\n            this.scrapedMetadata = {};\n            this.importUrl = '';\n            this.scraping = false;\n            this.importing = false;\n            if (this.$refs.scrapeResults) this.$refs.scrapeResults.innerHTML = '';\n        },\n\n        async importSelectedUrls(selectedIndexes) {\n            if (this.importing) return;\n            const urls = selectedIndexes.map(i => this.scrapedImages[i]).filter(Boolean);\n            if (!urls.length) return;\n\n            this.importing = true;\n            this.hasUploads = true;\n            this.activeTab = 'device'; // Switch to show upload rows\n            // Capture refs now, before any await \u2014 `this.$refs` throws (_x_refs)\n            // if an hx-boost navigation tears the component down mid-import.\n            const scrapeResults = this.$refs.scrapeResults;\n            const uploadRows = this.$refs.uploadRows;\n            if (scrapeResults) scrapeResults.innerHTML = '';\n            this.scrapedImages = [];\n\n            const importUrl = this.$root.dataset.importUrl;\n            const csrfToken = document.querySelector('meta[name=\"csrf-token\"]').content;\n            let importedCount = 0;\n\n            // Show pending placeholders\n            const tempIds = urls.map((_, i) => {\n                const tempId = 'import-' + Date.now() + '-' + i;\n                const html = '<div id=\"' + tempId + '\" class=\"flex items-center gap-4 p-3 bg-soft rounded-lg border border-border\">' +\n                    '<div class=\"w-16 h-12 bg-muted rounded flex items-center justify-center flex-shrink-0\">' +\n                    '<svg class=\"w-5 h-5 text-muted-foreground\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M2.25 15.75l5.159-5.159a2.25 2.25 0 013.182 0l5.159 5.159m-1.5-1.5l1.409-1.409a2.25 2.25 0 013.182 0l2.909 2.909M3.75 21h16.5\"/></svg>' +\n                    '</div>' +\n                    '<div class=\"flex-1 min-w-0\">' +\n                    '<p class=\"font-medium text-foreground text-sm\">' + (I18N.photoOfCount || 'Foto {n} von {total}').replace('{n}', i + 1).replace('{total}', urls.length) + '</p>' +\n                    '<div class=\"flex items-center gap-1.5 text-sm text-muted-foreground mt-0.5\">' +\n                    '<svg class=\"w-4 h-4 animate-spin\" fill=\"none\" viewBox=\"0 0 24 24\">' +\n                    '<circle class=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\"></circle>' +\n                    '<path class=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z\"></path>' +\n                    '</svg><span>' + (I18N.importing || 'Wird importiert...') + '</span></div></div></div>';\n                if (uploadRows) uploadRows.insertAdjacentHTML('beforeend', html);\n                return tempId;\n            });\n\n            this.pendingUploads += urls.length;\n\n            try {\n                const res = await fetch(importUrl, {\n                    method: 'POST',\n                    headers: {\n                        'X-CSRFToken': csrfToken,\n                        'Content-Type': 'application/json',\n                    },\n                    body: JSON.stringify({ urls, metadata: this.scrapedMetadata }),\n                });\n\n                const data = await res.json();\n\n                // Replace placeholders with actual upload rows\n                (data.results || []).forEach((result, i) => {\n                    const placeholder = document.getElementById(tempIds[i]);\n                    if (placeholder && result.row_html) {\n                        placeholder.outerHTML = result.row_html;\n                    }\n                });\n\n                // Mark remaining placeholders as failed\n                const successCount = (data.results || []).length;\n                importedCount = successCount;\n                for (let i = successCount; i < tempIds.length; i++) {\n                    const placeholder = document.getElementById(tempIds[i]);\n                    if (placeholder) {\n                        placeholder.outerHTML = '<div class=\"flex items-center gap-4 p-3 bg-alert-error rounded-lg border border-alert-error-border\">' +\n                            '<div class=\"w-16 h-12 bg-alert-error rounded flex items-center justify-center flex-shrink-0\">' +\n                            '<svg class=\"w-5 h-5 text-alert-error-foreground\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">' +\n                            '<path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\"/></svg></div>' +\n                            '<div class=\"flex-1 min-w-0\"><p class=\"font-medium text-alert-error-foreground text-sm\">' + (I18N.importFailed || 'Import fehlgeschlagen') + '</p></div></div>';\n                    }\n                }\n\n                if (uploadRows) htmx.process(uploadRows);\n            } catch (e) {\n                // Network error \u2014 mark all as failed\n                tempIds.forEach(id => {\n                    const el = document.getElementById(id);\n                    if (el) el.querySelector('span').textContent = I18N.importFailed || 'Import fehlgeschlagen';\n                });\n            } finally {\n                this.pendingUploads -= urls.length;\n                this.importing = false;\n                this.uploadedInBatch += importedCount;\n                this.trackBatchComplete();\n            }\n        },\n\n        escapeHtml(text) {\n            const div = document.createElement('div');\n            div.textContent = text;\n            return div.innerHTML;\n        },\n    }));\n\n});\n", "document.addEventListener('alpine:init', () => {\n    Alpine.data('brandingLogoUpload', () => ({\n        dragging: false,\n        previewUrl: '',\n        fileName: '',\n        fileSize: '',\n        error: '',\n        helpOpen: false,\n\n        get hasSelection() {\n            return Boolean(this.previewUrl);\n        },\n\n        init() {\n            this.$watch('$store.modal.open', (openModal) => {\n                if (openModal === 'logo-upload') {\n                    this.$nextTick(() => this.$refs.dropzone?.focus());\n                } else {\n                    this.reset();\n                }\n            });\n        },\n\n        openFilePicker() {\n            this.$refs.fileInput?.click();\n        },\n\n        handleFileSelect(event) {\n            const file = event.target.files?.[0];\n            if (file) this.selectFile(file);\n        },\n\n        handleDrop(event) {\n            this.dragging = false;\n            const file = event.dataTransfer?.files?.[0];\n            if (!file) return;\n\n            this.$refs.fileInput.files = event.dataTransfer.files;\n            this.selectFile(file);\n        },\n\n        selectFile(file) {\n            const validExtension = /\\.(jpe?g|png|webp)$/i.test(file.name);\n            const validType = !file.type || [\n                'image/jpeg',\n                'image/png',\n                'image/webp',\n            ].includes(file.type);\n\n            if (!validExtension || !validType) {\n                this.clearSelection();\n                this.error = this.$root.dataset.invalidFormat;\n                return;\n            }\n            if (file.size > 5 * 1024 * 1024) {\n                this.clearSelection();\n                this.error = this.$root.dataset.fileTooLarge;\n                return;\n            }\n\n            if (this.previewUrl) URL.revokeObjectURL(this.previewUrl);\n            this.previewUrl = URL.createObjectURL(file);\n            this.fileName = file.name;\n            this.fileSize = file.size < 1024 * 1024\n                ? `${Math.max(1, Math.round(file.size / 1024))} KB`\n                : `${(file.size / (1024 * 1024)).toFixed(1)} MB`;\n            this.error = '';\n        },\n\n        clearSelection() {\n            if (this.previewUrl) URL.revokeObjectURL(this.previewUrl);\n            this.previewUrl = '';\n            this.fileName = '';\n            this.fileSize = '';\n            if (this.$refs.fileInput) this.$refs.fileInput.value = '';\n        },\n\n        reset() {\n            this.clearSelection();\n            this.dragging = false;\n            this.error = '';\n            this.helpOpen = false;\n        },\n\n        close() {\n            this.reset();\n            Alpine.store('modal')?.close();\n        },\n    }));\n});\n", "// Estimated progress for waits we cannot measure (scraping a listing page).\n// The bar runs fast at first and slows down near the end, reaching about 85%\n// at `expectedMs` and never passing 95% until the caller calls done().\n// Better than a spinner: the customer sees that the wait is finite.\n\nexport function estimateProgress(set, expectedMs) {\n    const started = Date.now();\n    const tau = expectedMs / 1.9; // 1 - e^-1.9 \u2248 0.85\n    set(3);\n    const timer = setInterval(() => {\n        const t = Date.now() - started;\n        set(Math.min(95, Math.round(95 * (1 - Math.exp(-t / tau)))));\n    }, 200);\n    return function done() {\n        clearInterval(timer);\n        set(100);\n    };\n}\n", "// Onboarding: listing link or photo upload, then the gallery page.\n// See docs/product/listing-gallery.md.\nimport { estimateProgress } from './estimated-progress.js';\n\n// Loading a listing: Firecrawl waits 5 s for the page to render, then we\n// download the title photo. Measured 2 to 11 s on staging (2026-09-24).\nconst LISTING_LOAD_MS = 12000;\n\nconst PARALLEL_UPLOADS = 3;\nconst VALID_TYPES = ['image/jpeg', 'image/png', 'image/webp'];\nconst MAX_BYTES = 20 * 1024 * 1024;\n\nfunction csrfToken() {\n    return document.querySelector('meta[name=\"csrf-token\"]').content;\n}\n\nasync function postForm(url, formData) {\n    const response = await fetch(url, {\n        method: 'POST',\n        headers: { 'X-CSRFToken': csrfToken() },\n        body: formData,\n    });\n    let data = {};\n    try { data = await response.json(); } catch (e) { data = {}; }\n    return { ok: response.ok && data.success, data, status: response.status };\n}\n\n// Server failure code for analytics: the view's `reason`, else the HTTP status\n// (a proxy timeout or a crash answers without JSON).\nfunction failureReason(data, status) {\n    return data.reason || `http_${status}`;\n}\n\nfunction hostOf(url) {\n    try { return new URL(url).hostname; } catch (e) { return ''; }\n}\n\n// Uploads files into the onboarding gallery. The first file creates the\n// gallery property unless `propertyId` is given; the rest follow in parallel.\nasync function uploadToGallery(uploadUrl, files, propertyId, onProgress) {\n    const I18N = window.I18N || {};\n    let done = 0;\n    let galleryUrl = '';\n    let lastError = '';\n    const send = async (file) => {\n        const formData = new FormData();\n        formData.append('photo', file);\n        if (propertyId) formData.append('property', propertyId);\n        let response;\n        try {\n            response = await postForm(uploadUrl, formData);\n        } catch (e) {\n            // A network error must not leave the upload hanging.\n            window.trackEvent?.('onboarding_error', { step: 'upload', reason: 'network' });\n            response = { ok: false, data: { error: I18N.connectionErrorTryAgain || 'Verbindungsfehler. Bitte versuchen Sie es erneut.' } };\n        }\n        const { ok, data } = response;\n        done += 1;\n        onProgress(done);\n        if (!ok) {\n            lastError = data.error || I18N.uploadFailed || 'Upload fehlgeschlagen';\n            return data;\n        }\n        propertyId = data.property_id;\n        galleryUrl = data.gallery_url;\n        return data;\n    };\n\n    const queue = [...files];\n    if (!propertyId && queue.length) {\n        const first = await send(queue.shift());\n        if (first.limit_reached || !propertyId) {\n            return { galleryUrl: '', error: lastError, limitReached: !!first.limit_reached };\n        }\n    }\n    const worker = async () => {\n        while (queue.length) await send(queue.shift());\n    };\n    await Promise.all(Array.from({ length: PARALLEL_UPLOADS }, worker));\n    return { galleryUrl, error: galleryUrl ? '' : lastError, limitReached: false };\n}\n\nfunction validFiles(fileList) {\n    return [...fileList].filter((f) => VALID_TYPES.includes(f.type) && f.size <= MAX_BYTES);\n}\n\ndocument.addEventListener('alpine:init', () => {\n    const I18N = window.I18N || {};\n\n    // The onboarding page (/app/start/). \"Sp\u00E4ter\" is a plain form post.\n    Alpine.data('onboarding', () => ({\n        step: 'welcome', // welcome | start | uploading | scraping | select | error\n        progress: 0,\n        dragging: false,\n        error: '',\n        limitReached: false,\n        importUrl: '',\n        total: 0,\n        done: 0,\n        candidates: [],\n        selected: [],\n        small: [],       // candidates under the import's 400 x 300 minimum\n        touched: false,  // the customer changed the preselection\n        maxPicks: 9,     // plus the title photo = the 10 gallery slots\n        firstUrl: '',\n        confirmUrl: '',\n        galleryUrl: '',\n\n        begin() {\n            this.track('begin');\n            this.step = 'start';\n            window.scrollTo({ top: 0 });\n        },\n\n        track(path) {\n            if (window.trackEvent) window.trackEvent('onboarding_path', { path });\n        },\n\n        openFilePicker() { this.$refs.fileInput?.click(); },\n\n        onFileSelect(e) { this.handleFiles(e.target.files); },\n\n        onDrop(e) {\n            this.dragging = false;\n            this.handleFiles(e.dataTransfer.files);\n        },\n\n        async handleFiles(fileList) {\n            const files = validFiles(fileList);\n            if (!files.length) {\n                this.error = I18N.invalidImageType || 'Bitte w\u00E4hlen Sie ein JPG, PNG oder WebP Bild.';\n                return;\n            }\n            this.error = '';\n            this.track('upload');\n            this.total = files.length;\n            this.done = 0;\n            this.step = 'uploading';\n            const result = await uploadToGallery(\n                this.$root.dataset.uploadUrl, files, '', (n) => { this.done = n; });\n            if (result.galleryUrl) {\n                window.trackEvent?.('photo_upload_complete', { count: this.done });\n                window.location.href = result.galleryUrl;\n                return;\n            }\n            this.showError(result.error, result.limitReached);\n        },\n\n        async startUrlImport() {\n            const url = this.importUrl.trim();\n            if (!url) return;\n            this.error = '';\n            this.step = 'scraping';\n            this.track('url');\n            const formData = new FormData();\n            formData.append('url', url);\n            const done = estimateProgress((v) => { this.progress = v; }, LISTING_LOAD_MS);\n            const host = hostOf(url);\n            let response;\n            try {\n                response = await postForm(this.$root.dataset.urlImportUrl, formData);\n            } catch (e) {\n                done();\n                window.trackEvent?.('listing_import_result', { result: 'error', reason: 'network', host });\n                this.step = 'start';\n                this.error = I18N.connectionErrorTryAgain || 'Verbindungsfehler. Bitte versuchen Sie es erneut.';\n                return;\n            }\n            done();\n            const { ok, data, status } = response;\n            if (!ok) {\n                window.trackEvent?.('listing_import_result', {\n                    result: 'error', reason: failureReason(data, status), host,\n                });\n                if (data.limit_reached) {\n                    this.showError(data.error, true);\n                } else {\n                    this.step = 'start';\n                    this.error = data.error || I18N.importFailed || 'Import fehlgeschlagen';\n                }\n                return;\n            }\n            window.trackEvent?.('listing_import_result', { result: 'ok', host });\n            window.trackEvent?.('photo_upload_complete', { property_id: data.property_id, count: 1 });\n            this.galleryUrl = data.gallery_url;\n            this.confirmUrl = data.confirm_url;\n            this.firstUrl = data.first_url;\n            this.candidates = data.candidates;\n            this.maxPicks = data.max_picks;\n            this.small = [];\n            this.touched = false;\n            if (!this.candidates.length) {\n                this.confirmSelection();\n                return;\n            }\n            this.step = 'select';\n        },\n\n        // Opt-in: the first usable photos are preselected until the customer\n        // changes the selection. Images the import would drop as too small\n        // never show, so no pick can silently vanish.\n        get visible() { return this.candidates.filter((u) => !this.small.includes(u)); },\n        get chosen() { return this.touched ? this.selected : this.visible.slice(0, this.maxPicks); },\n\n        isSelected(url) { return this.chosen.includes(url); },\n\n        toggle(url) {\n            if (!this.touched) {\n                this.selected = [...this.chosen];\n                this.touched = true;\n            }\n            if (this.selected.includes(url)) {\n                this.selected = this.selected.filter((u) => u !== url);\n            } else if (this.selected.length < this.maxPicks) {\n                this.selected = [...this.selected, url];\n            }\n        },\n\n        onCandidateLoad(event, url) {\n            const img = event.target;\n            if (img.naturalWidth < 400 || img.naturalHeight < 300) this.dropCandidate(url);\n        },\n\n        dropCandidate(url) {\n            if (!this.small.includes(url)) this.small = [...this.small, url];\n            this.selected = this.selected.filter((u) => u !== url);\n        },\n\n        async confirmSelection() {\n            const formData = new FormData();\n            this.chosen.forEach((u) => formData.append('selected', u));\n            this.step = 'scraping';\n            estimateProgress((v) => { this.progress = v; }, 2000);\n            // The gallery opens either way (it shows the title photo); a failed\n            // confirm only loses the picks, so report it instead of swallowing it.\n            try {\n                const { ok, data, status } = await postForm(this.confirmUrl, formData);\n                if (!ok) {\n                    window.trackEvent?.('onboarding_error', { step: 'confirm', reason: failureReason(data, status) });\n                }\n            } catch (e) {\n                window.trackEvent?.('onboarding_error', { step: 'confirm', reason: 'network' });\n            } finally {\n                window.location.href = this.galleryUrl;\n            }\n        },\n\n        showError(message, limitReached) {\n            this.step = 'error';\n            this.limitReached = !!limitReached;\n            this.error = message || I18N.uploadFailed || 'Upload fehlgeschlagen';\n        },\n\n        reset() { window.location.reload(); },\n    }));\n\n    // The gallery page. A photo click swaps the before/after comparison in\n    // place; the choice survives the 3 s refresh of #gallery-body, which\n    // re-renders the comparison on the first finished photo.\n    Alpine.data('galleryPage', () => ({\n        busy: false,\n        error: '',\n        progressText: '',\n        selectedId: '',\n        lightboxOpen: false,\n        lightboxBefore: '',\n        lightboxAfter: '',\n\n        init() {\n            window.addEventListener('htmx:afterSettle', () => this.show(this.selectedId));\n        },\n\n        // The comparison large, like \"Vergleichen\" on the photo page. Only\n        // once the after image exists.\n        openLightbox() {\n            const after = document.getElementById('compare-after');\n            if (!after || after.classList.contains('hidden')) return;\n            this.lightboxBefore = document.getElementById('compare-before').src;\n            this.lightboxAfter = after.src;\n            this.lightboxOpen = true;\n            window._scrollLock.lock();\n        },\n\n        closeLightbox() {\n            this.lightboxOpen = false;\n            window._scrollLock.unlock();\n        },\n\n        // The normal export dialog, with the account's watermark choices.\n        downloadShown() {\n            const url = document.getElementById('compare-download')?.dataset.url;\n            if (url) htmx.ajax('GET', url, { target: '#download-modal-container', swap: 'innerHTML' });\n        },\n\n        // Start the unlock from the comparison: submit the guide's unlock form\n        // (pack checkout or own credits), else take the customer to it.\n        unlockNow() {\n            const form = document.getElementById('gallery-unlock-form');\n            if (form) {\n                form.requestSubmit();\n                return;\n            }\n            document.querySelector('[data-testid=\"gallery-unlock\"]')?.scrollIntoView({ behavior: 'smooth', block: 'center' });\n        },\n\n        choose(id) {\n            this.selectedId = id;\n            this.show(id);\n            document.getElementById('gallery-compare-anchor')?.scrollIntoView({ behavior: 'smooth', block: 'start' });\n        },\n\n        show(id) {\n            if (!id) return;\n            const card = document.querySelector(`[data-gallery-card][data-photo-id=\"${id}\"]`);\n            const before = document.getElementById('compare-before');\n            if (!card || !before) return;\n            const d = card.dataset;\n            before.src = d.before;\n            const after = document.getElementById('compare-after');\n            if (d.after) after.src = d.after;\n            after.classList.toggle('hidden', !d.after);\n            document.getElementById('compare-pending').classList.toggle('hidden', !!d.after);\n            document.getElementById('compare-preview').classList.toggle('hidden', d.state !== 'locked');\n            document.getElementById('compare-label').textContent = d.label;\n            const download = document.getElementById('compare-download');\n            download.dataset.url = d.downloadUrl || '';\n            document.getElementById('compare-cta-done').classList.toggle('hidden', d.state !== 'done');\n            document.getElementById('compare-cta-locked').classList.toggle('hidden', d.state !== 'locked');\n            document.querySelectorAll('[data-gallery-card] [data-card-frame]').forEach((frame) => {\n                const selected = frame.closest('[data-gallery-card]') === card;\n                frame.classList.toggle('border-primary', selected);\n                frame.classList.toggle('border-transparent', !selected);\n            });\n        },\n\n        async upload(fileList) {\n            const files = validFiles(fileList);\n            if (!files.length) return;\n            this.busy = true;\n            this.error = '';\n            const total = files.length;\n            const label = I18N.uploadingOf || 'Wird hochgeladen';\n            this.progressText = `${label} 0 / ${total}`;\n            const result = await uploadToGallery(\n                this.$root.dataset.uploadUrl, files, this.$root.dataset.propertyId,\n                (n) => { this.progressText = `${label} ${n} / ${total}`; });\n            this.busy = false;\n            if (result.error) this.error = result.error;\n            htmx.ajax('GET', this.$root.dataset.gridUrl, { target: '#gallery-body', swap: 'outerHTML' });\n        },\n    }));\n});\n", "// In-app guides: carry out the server's auto-open decision and record state.\n//\n// The server decides which guide opens (dashboard/guides.py) and renders its\n// key into data-guide-key. This component only executes that decision, which\n// is what makes hx-boost navigation work for free: the swapped body carries a\n// fresh x-data root, Alpine initialises it, and init() opens the guide for the\n// page that was just navigated to \u2014 exactly as on a full load.\n//\n// State POSTs are fire-and-forget. Guide bookkeeping must never be the reason\n// a modal fails to open or close.\ndocument.addEventListener('alpine:init', () => {\n    const modalStore = () => window.Alpine && window.Alpine.store('modal');\n\n    function csrfToken() {\n        const meta = document.querySelector('meta[name=\"csrf-token\"]');\n        return meta ? meta.content : '';\n    }\n\n    function post(url, params) {\n        if (!url) return;\n        const body = new FormData();\n        Object.keys(params || {}).forEach(key => body.append(key, params[key]));\n        fetch(url, {\n            method: 'POST',\n            headers: { 'X-CSRFToken': csrfToken() },\n            body: body,\n            // A url-kind CTA navigates away in the same tick; keepalive stops\n            // the browser cancelling the dismissal on the way out.\n            keepalive: true,\n        }).catch(() => {});\n    }\n\n    function track(name, params) {\n        if (window.trackEvent) window.trackEvent(name, params);\n    }\n\n    // Called from the header help menu and the mobile menu, which are plain\n    // inline x-data dropdowns with no component of their own.\n    window.immopixGuides = {\n        open(key, seenUrl) {\n            const store = modalStore();\n            if (store) store.show('guide-' + key);\n            track('guide_shown', { guide: key, auto: false });\n            post(seenUrl, { reopen: '1' });\n        },\n    };\n\n    Alpine.data('guideAutoOpen', () => ({\n        init() {\n            const key = this.$el.dataset.guideKey;\n            if (!key) return;\n\n            const forced = this.$el.dataset.forced === '1';\n            const seenUrl = this.$el.dataset.seenUrl;\n\n            // $nextTick: the modal body is teleported into <body> by Alpine,\n            // and on a full load that clone may not be mounted yet when this\n            // root initialises. Showing after the tick keeps the first paint\n            // of the modal correct instead of relying on the store's\n            // reactivity to catch up.\n            this.$nextTick(() => {\n                const store = modalStore();\n                // A forced open (?guide=<key>) is a review aid, so it must not\n                // change what this user sees on their next visit. The flag\n                // rides along in the store context, which guideModal reads\n                // when it sees itself open.\n                if (store) store.show('guide-' + key, forced ? { forced: true } : {});\n                track('guide_shown', { guide: key, auto: true });\n                if (!forced) post(seenUrl, {});\n            });\n        },\n    }));\n\n    Alpine.data('guideModal', () => ({\n        // Guards one dismissal record per open. Reset every time this guide\n        // opens, set by whichever close path gets there first.\n        recorded: false,\n        forcedOpen: false,\n\n        init() {\n            // $el is the component root here; capture it instead of reading\n            // $root from the watcher, which fires during hx-boost teardown\n            // when magic properties can no longer resolve across the teleport\n            // boundary.\n            const el = this.$el;\n            const id = 'guide-' + el.dataset.guideKey;\n            const self = this;\n\n            // Every way out of the modal counts as \"understood\": Verstanden,\n            // Escape, the backdrop, the X, and navigating away (the\n            // htmx:beforeHistorySave hook closes the store). Escape and the\n            // backdrop are wired by the modal shell straight to\n            // $store.modal.close(), so watching the store is the only place\n            // that sees all of them.\n            this.$watch('$store.modal?.open', (value, previous) => {\n                if (value === id) {\n                    const store = modalStore();\n                    const context = (store && store.context) || {};\n                    self.recorded = false;\n                    self.forcedOpen = !!context.forced;\n                    return;\n                }\n                if (previous === id) self.record(el);\n            });\n        },\n\n        record(el) {\n            if (this.recorded || this.forcedOpen) return;\n            this.recorded = true;\n            track('guide_dismissed', { guide: el.dataset.guideKey });\n            post(el.dataset.dismissUrl, {});\n        },\n\n        dismiss() {\n            // Record before closing so the store watcher finds the guard set\n            // and does not post a second time.\n            this.record(this.$root);\n            const store = modalStore();\n            if (store) store.close();\n        },\n\n        mute() {\n            const el = this.$root;\n            // Muting is the recorded action for this click. Claiming the\n            // guard keeps the close from also firing a dismissal.\n            this.recorded = true;\n            const store = modalStore();\n            if (store) store.close();\n            track('guide_muted', { guide: el.dataset.guideKey });\n            post(el.dataset.muteUrl, {});\n        },\n    }));\n});\n", "import { estimateProgress } from './estimated-progress.js';\n\n// Scraping renders the page first (Firecrawl waits 5 s); the photo download\n// runs in parallel waves, roughly half a second per photo.\nconst SCRAPE_MS = 12000;\nconst IMPORT_BASE_MS = 2000;\nconst IMPORT_PER_PHOTO_MS = 500;\n\ndocument.addEventListener('alpine:init', () => {\n    const I18N = window.I18N || {};\n\n    Alpine.data('propertyCreate', () => ({\n        step: 'choice',  // choice | manual | url | scraping | results | importing\n        progress: 0,\n        importUrl: '',\n        scraping: false,\n        importing: false,\n        scrapedImages: [],\n        scrapedMetadata: {},\n        propertyName: '',\n        importError: '',\n\n        // Integration requests \u2014 the chip footer under the two choice cards.\n        integrationSources: ['onOffice', 'Propstack', 'FlowFact', 'Dropbox / Drive'],\n        integrationSelected: [],\n        integrationSent: [],\n        integrationOtherOpen: false,\n        integrationOther: '',\n        integrationThanks: false,\n        integrationSending: false,\n\n        get isOpen() { return !!Alpine.store('modal')?.is('property-create'); },\n\n        init() {\n            // The component lives inside the teleported modal body. Reset it\n            // no matter how the shared shell closes (button, Escape, backdrop,\n            // or hx-boost navigation).\n            this.$watch('isOpen', isOpen => {\n                if (!isOpen) this.reset();\n            });\n\n            // /app/?create=1 (trial guide + onboarding CTAs) opens the modal directly.\n            // The flag is server-rendered so it works for full loads and hx-boost swaps alike.\n            if (this.$root.dataset.autoOpen === '1') {\n                // Strip the param so refresh/back doesn't reopen the modal.\n                const url = new URL(window.location);\n                if (url.searchParams.has('create')) {\n                    url.searchParams.delete('create');\n                    window.history.replaceState(\n                        window.history.state,\n                        '',\n                        url.pathname + url.search + url.hash,\n                    );\n                }\n                this.$nextTick(() => this.openModal());\n            }\n        },\n\n        openModal() {\n            Alpine.store('modal')?.show('property-create');\n        },\n\n        closeModal() {\n            if (this.importing) return;\n            Alpine.store('modal')?.close();\n            this.reset();\n        },\n\n        reset() {\n            this.step = 'choice';\n            this.importUrl = '';\n            this.scraping = false;\n            this.importing = false;\n            this.scrapedImages = [];\n            this.scrapedMetadata = {};\n            this.propertyName = '';\n            this.importError = '';\n            this.integrationSelected = [];\n            this.integrationSent = [];\n            this.integrationOtherOpen = false;\n            this.integrationOther = '';\n            this.integrationThanks = false;\n            this.integrationSending = false;\n            if (this.$refs.scrapeResults) this.$refs.scrapeResults.innerHTML = '';\n        },\n\n        // Sent sources typed into \"Andere \u2026\" \u2014 rendered as extra success chips so\n        // the \"Andere \u2026\" chip itself stays available for a second suggestion.\n        get integrationSentCustom() {\n            return this.integrationSent.filter(s => !this.integrationSources.includes(s));\n        },\n\n        get showIntegrationSend() {\n            return this.integrationSelected.length > 0 || this.integrationOtherOpen;\n        },\n\n        toggleIntegrationChip(source) {\n            if (this.integrationSent.includes(source)) return;\n            const i = this.integrationSelected.indexOf(source);\n            if (i === -1) this.integrationSelected.push(source);\n            else this.integrationSelected.splice(i, 1);\n            this.integrationThanks = false;\n        },\n\n        toggleIntegrationOther() {\n            this.integrationOtherOpen = !this.integrationOtherOpen;\n            this.integrationThanks = false;\n            if (this.integrationOtherOpen) {\n                this.$nextTick(() => this.$refs.integrationOtherInput?.focus());\n            }\n        },\n\n        async sendIntegrationRequest() {\n            if (this.integrationSending) return;\n            const other = this.integrationOther.trim();\n            // Only \"Andere \u2026\" is open and nothing was typed \u2014 ask for the name\n            // instead of reporting an empty request.\n            if (!other && !this.integrationSelected.length) {\n                this.$refs.integrationOtherInput?.focus();\n                return;\n            }\n\n            // Dedupe against already-sent sources \u2014 a repeated custom name would\n            // otherwise render twice and break the x-for keys.\n            const sources = [...new Set([...this.integrationSelected, ...(other ? [other] : [])])]\n                .filter(s => !this.integrationSent.includes(s));\n            if (!sources.length) {\n                this.integrationOtherOpen = false;\n                this.integrationOther = '';\n                return;\n            }\n\n            const requestUrl = this.$root.dataset.integrationRequestUrl;\n            const csrfToken = document.querySelector('meta[name=\"csrf-token\"]').content;\n\n            this.integrationSending = true;\n            try {\n                const res = await fetch(requestUrl, {\n                    method: 'POST',\n                    headers: {\n                        'X-CSRFToken': csrfToken,\n                        'Content-Type': 'application/json',\n                    },\n                    body: JSON.stringify({ sources }),\n                });\n                // Leave the selection intact on failure so the user can retry.\n                if (!res.ok) return;\n            } catch (e) {\n                return;\n            } finally {\n                this.integrationSending = false;\n            }\n\n            // The modal may have closed (and reset) while the request ran \u2014\n            // don't resurrect success state onto a fresh component.\n            if (!this.isOpen) return;\n\n            this.integrationSent.push(...sources);\n            this.integrationSelected = [];\n            this.integrationOtherOpen = false;\n            this.integrationOther = '';\n            this.integrationThanks = true;\n        },\n\n        goManual() { this.step = 'manual'; },\n\n        goUrl() { this.step = 'url'; },\n\n        goBack() {\n            if (this.step === 'results') {\n                this.step = 'url';\n                this.scrapedImages = [];\n                this.scrapedMetadata = {};\n                this.propertyName = '';\n                this.importError = '';\n                if (this.$refs.scrapeResults) this.$refs.scrapeResults.innerHTML = '';\n            } else {\n                this.step = 'choice';\n            }\n        },\n\n        async startScrape() {\n            const url = this.importUrl.trim();\n            if (!url) return;\n\n            this.step = 'scraping';\n            const done = estimateProgress((v) => { this.progress = v; }, SCRAPE_MS);\n            this.scrapedImages = [];\n            this.importError = '';\n            // Capture the ref now, before any await. After an hx-boost navigation\n            // the component is torn down and `this.$refs` itself throws (_x_refs).\n            const scrapeResults = this.$refs.scrapeResults;\n            if (scrapeResults) scrapeResults.innerHTML = '';\n\n            const scrapeUrl = this.$root.dataset.scrapeUrl;\n            const csrfToken = document.querySelector('meta[name=\"csrf-token\"]').content;\n\n            try {\n                const formData = new FormData();\n                formData.append('url', url);\n\n                const res = await fetch(scrapeUrl, {\n                    method: 'POST',\n                    headers: { 'X-CSRFToken': csrfToken },\n                    body: formData,\n                });\n\n                const html = await res.text();\n                if (scrapeResults) {\n                    scrapeResults.innerHTML = html;\n\n                    // Read image URLs from embedded JSON\n                    const dataEl = scrapeResults.querySelector('#scraped-image-data');\n                    if (dataEl) {\n                        try { this.scrapedImages = JSON.parse(dataEl.textContent); } catch(e) {}\n                    }\n\n                    // Read metadata\n                    const metaEl = scrapeResults.querySelector('#scraped-metadata');\n                    if (metaEl) {\n                        try { this.scrapedMetadata = JSON.parse(metaEl.textContent); } catch(e) {}\n                    }\n                }\n\n                // Prefill property name from metadata\n                if (this.scrapedMetadata.name) {\n                    this.propertyName = this.scrapedMetadata.name;\n                }\n\n                done();\n                this.step = 'results';\n            } catch (e) {\n                done();\n                if (scrapeResults) {\n                    scrapeResults.innerHTML = '<p class=\"text-sm text-alert-error-foreground text-center py-4\">' + (I18N.connectionErrorRetry || 'Verbindungsfehler. Bitte erneut versuchen.') + '</p>';\n                }\n                this.step = 'results';\n            }\n        },\n\n        resetScrape() {\n            this.scrapedImages = [];\n            this.scrapedMetadata = {};\n            this.propertyName = '';\n            this.importUrl = '';\n            this.importError = '';\n            if (this.$refs.scrapeResults) this.$refs.scrapeResults.innerHTML = '';\n            this.step = 'url';\n        },\n\n        async createWithImport(selectedIndexes) {\n            if (this.importing) return;\n\n            const name = this.propertyName.trim();\n            if (!name) {\n                this.importError = I18N.nameRequired || 'Name ist erforderlich';\n                return;\n            }\n\n            const urls = selectedIndexes.map(i => this.scrapedImages[i]).filter(Boolean);\n            if (!urls.length) return;\n\n            this.importError = '';\n            this.step = 'importing';\n            this.importing = true;\n            estimateProgress((v) => { this.progress = v; }, IMPORT_BASE_MS + IMPORT_PER_PHOTO_MS * urls.length);\n\n            const createUrl = this.$root.dataset.createUrl;\n            const csrfToken = document.querySelector('meta[name=\"csrf-token\"]').content;\n\n            try {\n                const res = await fetch(createUrl, {\n                    method: 'POST',\n                    headers: {\n                        'X-CSRFToken': csrfToken,\n                        'Content-Type': 'application/json',\n                    },\n                    body: JSON.stringify({ name, urls, metadata: this.scrapedMetadata }),\n                });\n\n                const data = await res.json();\n\n                if (!res.ok) {\n                    this.importError = data.error || I18N.importFailed || 'Import fehlgeschlagen';\n                    this.step = 'results';\n                    this.importing = false;\n                    return;\n                }\n\n                // Redirect to new property\n                if (data.redirect_url) {\n                    window.location.href = data.redirect_url;\n                    return;\n                }\n            } catch (e) {\n                this.importError = I18N.connectionErrorRetry || 'Verbindungsfehler. Bitte erneut versuchen.';\n                this.step = 'results';\n            } finally {\n                this.importing = false;\n            }\n        },\n    }));\n\n});\n", "document.addEventListener('alpine:init', () => {\n\n    // Reusable address autocomplete via Google Places Autocomplete Data API\n    // Uses our own input + dropdown \u2014 no Google widget, no full-screen overlay on mobile\n    Alpine.data('addressAutocomplete', (initialStreet = '', initialPostalCode = '', initialCity = '', apiKey = '') => ({\n        street: initialStreet,\n        postalCode: initialPostalCode,\n        city: initialCity,\n        query: '',\n        suggestions: [],\n        showDropdown: false,\n        _debounceTimer: null,\n        _sessionToken: null,\n        _places: null,\n        _ready: false,\n        _els: null,\n\n        init() {\n            this.query = [this.street, this.postalCode, this.city].filter(Boolean).join(', ');\n            // Cache DOM refs now \u2014 they won't work after await in async methods\n            this._els = {\n                street: this.$refs.hiddenStreet,\n                postalCode: this.$refs.hiddenPostalCode,\n                city: this.$refs.hiddenCity,\n                root: this.$el,\n            };\n            if (apiKey) this._loadApi(apiKey);\n        },\n\n        async _loadApi(key) {\n            try {\n                // Dynamically load Google Maps API if not yet present.\n                // Done here instead of a <script> tag so it works with hx-boost navigation.\n                if (!window.google?.maps?.importLibrary) {\n                    await this._injectScript(key);\n                }\n                // Use the module reference from importLibrary directly to avoid\n                // instanceof mismatches when the API is loaded dynamically.\n                this._places = await google.maps.importLibrary('places');\n                this._sessionToken = new this._places.AutocompleteSessionToken();\n                this._ready = true;\n            } catch (e) {\n                console.error('Google Places API failed to load:', e);\n            }\n        },\n\n        _injectScript(key) {\n            // Deduplicate: reuse existing loading promise if another instance started it\n            if (window._gmapsLoading) return window._gmapsLoading;\n            window._gmapsLoading = new Promise((resolve, reject) => {\n                const cb = '__gmapsReady';\n                window[cb] = () => { delete window[cb]; resolve(); };\n                const s = document.createElement('script');\n                s.src = 'https://maps.googleapis.com/maps/api/js?key=' + key + '&loading=async&callback=' + cb;\n                s.async = true;\n                s.onerror = () => { window._gmapsLoading = null; reject(new Error('Google Maps script failed')); };\n                document.head.appendChild(s);\n            });\n            return window._gmapsLoading;\n        },\n\n        onInput() {\n            const q = this.query.trim();\n            if (q.length < 3 || !this._ready) {\n                this.suggestions = [];\n                this.showDropdown = false;\n                return;\n            }\n            clearTimeout(this._debounceTimer);\n            this._debounceTimer = setTimeout(() => this._fetchSuggestions(q), 250);\n        },\n\n        async _fetchSuggestions(input) {\n            try {\n                const { suggestions } = await this._places.AutocompleteSuggestion.fetchAutocompleteSuggestions({\n                    input,\n                    sessionToken: this._sessionToken,\n                    region: 'de',\n                    includedPrimaryTypes: ['street_address', 'route', 'premise', 'subpremise'],\n                    language: 'de',\n                });\n                this.suggestions = suggestions.map(s => ({\n                    text: s.placePrediction.text.text,\n                    mainText: s.placePrediction.mainText?.text || s.placePrediction.text.text,\n                    secondaryText: s.placePrediction.secondaryText?.text || '',\n                    place: s.placePrediction.toPlace(),\n                }));\n                this.showDropdown = this.suggestions.length > 0;\n            } catch (e) {\n                console.error('Address autocomplete error:', e);\n                this.suggestions = [];\n                this.showDropdown = false;\n            }\n        },\n\n        async selectSuggestion(suggestion) {\n            this.query = suggestion.text;\n            this.showDropdown = false;\n            this.suggestions = [];\n\n            try {\n                const place = suggestion.place;\n                await place.fetchFields({ fields: ['addressComponents'] });\n                if (place.addressComponents) {\n                    this._parsePlaceComponents(place.addressComponents);\n                } else {\n                    this.street = suggestion.mainText;\n                    this._syncAndNotify();\n                }\n            } catch (e) {\n                this.street = suggestion.mainText;\n                this._syncAndNotify();\n            }\n\n            this._sessionToken = new this._places.AutocompleteSessionToken();\n        },\n\n        onBlur() {\n            setTimeout(() => { this.showDropdown = false; }, 200);\n        },\n\n        _parsePlaceComponents(components) {\n            let route = '';\n            let streetNumber = '';\n            this.postalCode = '';\n            this.city = '';\n\n            for (const component of components) {\n                const type = component.types[0];\n                if (type === 'route') route = component.longText;\n                else if (type === 'street_number') streetNumber = component.longText;\n                else if (type === 'postal_code') this.postalCode = component.longText;\n                else if (type === 'locality') this.city = component.longText;\n                else if (type === 'sublocality_level_1' && !this.city) this.city = component.longText;\n            }\n\n            this.street = streetNumber ? `${route} ${streetNumber}` : route;\n            this.query = [this.street, this.postalCode, this.city].filter(Boolean).join(', ');\n            this._syncAndNotify();\n        },\n\n        _syncAndNotify() {\n            if (this._els.street) this._els.street.value = this.street;\n            if (this._els.postalCode) this._els.postalCode.value = this.postalCode;\n            if (this._els.city) this._els.city.value = this.city;\n\n            // Root may be detached if an hx-boost navigation tore the component\n            // down while a Places callback was in flight \u2014 guard the dispatch.\n            if (this._els.root && this._els.root.isConnected) {\n                this._els.root.dispatchEvent(new CustomEvent('address-changed', { bubbles: true }));\n            }\n        },\n    }));\n\n});\n", "document.addEventListener('alpine:init', () => {\n\n    Alpine.data('listingForm', function() {\n        return {\n            listingType: '',\n            propertyType: '',\n            hasParking: false,\n            hasProvision: false,\n            energyValue: '',\n            energySources: [],\n            energySourceLabels: {},\n            counts: {},\n            saleFields: ['property_type', 'condition', 'construction_year', 'street', 'living_area', 'rooms', 'price', 'buyer_commission', 'energy_cert_type', 'energy_value', 'energy_source', 'heating_type'],\n            rentalFields: ['property_type', 'condition', 'construction_year', 'street', 'living_area', 'rooms', 'cold_rent', 'utilities', 'deposit', 'energy_cert_type', 'energy_value', 'energy_source', 'heating_type'],\n            sections: {\n                basisdaten: ['property_type', 'condition', 'construction_year'],\n                adresse: ['street'],\n                flaechen: ['living_area', 'rooms'],\n                finanzen_sale: ['price', 'buyer_commission'],\n                finanzen_rental: ['cold_rent', 'utilities', 'deposit'],\n                energie: ['energy_cert_type', 'energy_value', 'energy_source', 'heating_type']\n            },\n            _saveTimer: null,\n            saveStatus: '',\n            _saveUrl: '',\n\n            init() {\n                const d = this.$el.dataset;\n                this.listingType = d.listingType || 'sale';\n                this.propertyType = d.propertyType || '';\n                this.hasParking = d.hasParking === 'true';\n                this.hasProvision = d.hasProvision === 'true';\n                this.energyValue = d.energyValue || '';\n                this._saveUrl = d.saveUrl || '';\n\n                try { this.energySources = JSON.parse(d.energySources || '[]'); } catch(e) { this.energySources = []; }\n                try { this.energySourceLabels = JSON.parse(d.energySourceLabels || '{}'); } catch(e) { this.energySourceLabels = {}; }\n\n                this.$nextTick(() => this.updateAll());\n            },\n\n            updateAll() {\n                for (const [key, fields] of Object.entries(this.sections)) {\n                    if (key === 'finanzen_sale' || key === 'finanzen_rental') continue;\n                    this.counts[key] = this._count(fields);\n                }\n                const finKey = this.listingType === 'sale' ? 'finanzen_sale' : 'finanzen_rental';\n                this.counts.finanzen = this._count(this.sections[finKey]);\n            },\n\n            _count(fields) {\n                let filled = 0;\n                for (const f of fields) {\n                    if (f === 'energy_source') { if (this.energySources.length > 0) filled++; continue; }\n                    const el = this.$el.querySelector('[name=\"' + f + '\"]');\n                    if (el && el.value && el.value.trim() !== '') filled++;\n                }\n                return { filled, total: fields.length };\n            },\n\n            filled(s) { return this.counts[s]?.filled || 0; },\n            total(s) { return this.counts[s]?.total || 0; },\n            pct(s) { const t = this.total(s); return t > 0 ? Math.round(this.filled(s) / t * 100) : 0; },\n            colorClass(s) { const p = this.pct(s); return p === 100 ? 'text-emerald-600' : p > 0 ? 'text-amber-600' : 'text-muted-foreground'; },\n            strokeClass(s) { const p = this.pct(s); return p === 100 ? 'stroke-emerald-500' : p > 0 ? 'stroke-amber-500' : 'stroke-muted-foreground/30'; },\n\n            computedWarmRent() {\n                const cold = parseFloat((this.$el.querySelector('[name=\"cold_rent\"]')?.value || '').replace(/\\./g, '').replace(',', '.'));\n                const util = parseFloat((this.$el.querySelector('[name=\"utilities\"]')?.value || '').replace(/\\./g, '').replace(',', '.'));\n                if (!isNaN(cold) && !isNaN(util)) return (cold + util).toLocaleString('de-DE', {minimumFractionDigits: 0, maximumFractionDigits: 2});\n                if (!isNaN(cold)) return cold.toLocaleString('de-DE', {minimumFractionDigits: 0, maximumFractionDigits: 2});\n                return '';\n            },\n\n            computedEnergyClass() {\n                const raw = (this.energyValue || '').replace(/\\./g, '').replace(',', '.');\n                const val = parseFloat(raw);\n                if (isNaN(val)) return '';\n                if (val <= 30) return 'A+';\n                if (val <= 50) return 'A';\n                if (val <= 75) return 'B';\n                if (val <= 100) return 'C';\n                if (val <= 130) return 'D';\n                if (val <= 160) return 'E';\n                if (val <= 200) return 'F';\n                if (val <= 250) return 'G';\n                return 'H';\n            },\n\n            autoSave() {\n                clearTimeout(this._saveTimer);\n                this._saveTimer = setTimeout(() => this._doSave(), 1500);\n            },\n\n            async _doSave() {\n                this.saveStatus = 'saving';\n                try {\n                    const formData = new FormData(this.$el);\n                    const res = await fetch(this._saveUrl, {\n                        method: 'POST',\n                        headers: {\n                            'X-Auto-Save': '1',\n                            'X-CSRFToken': formData.get('csrfmiddlewaretoken'),\n                        },\n                        body: formData,\n                    });\n                    const data = await res.json();\n                    this.saveStatus = data.ok ? 'saved' : '';\n                    if (data.expose_notice_changed) {\n                        window.dispatchEvent(new CustomEvent('expose-settings-changed'));\n                    }\n                } catch {\n                    this.saveStatus = '';\n                }\n                if (this.saveStatus === 'saved') {\n                    setTimeout(() => { if (this.saveStatus === 'saved') this.saveStatus = ''; }, 2000);\n                }\n            }\n        };\n    });\n\n});\n", "/**\n * Shared Alpine.js component for public upload forms.\n * Used by: free tool, foto check, landing pages.\n *\n * Config via data attributes on the x-data element:\n *   data-upload-url    \u2014 POST endpoint for the upload\n *   data-prefill-email \u2014 optional pre-filled email\n *   data-require-consent \u2014 if present, consent checkbox is required\n */\ndocument.addEventListener('alpine:init', () => {\n    const I18N = window.I18N || {};\n    Alpine.data('publicUpload', function() {\n        return {\n            step: 1,\n            dragOver: false,\n            file: null,\n            fileName: '',\n            fileSize: '',\n            previewUrl: '',\n            email: '',\n            consent: false,\n            error: '',\n            submitting: false,\n\n            init() {\n                this.email = this.$root.dataset.prefillEmail || '';\n            },\n\n            handleFileSelect(event) {\n                const file = event.target.files[0];\n                if (file) this.selectFile(file);\n            },\n\n            handleDrop(event) {\n                this.dragOver = false;\n                const file = event.dataTransfer.files[0];\n                if (file) this.selectFile(file);\n            },\n\n            selectFile(file) {\n                const validTypes = ['image/jpeg', 'image/png', 'image/webp'];\n                if (!validTypes.includes(file.type)) {\n                    this.error = I18N.invalidFileFormat || 'Ung\u00FCltiges Dateiformat. Bitte verwenden Sie JPG, PNG oder WebP.';\n                    return;\n                }\n                if (file.size > 20 * 1024 * 1024) {\n                    this.error = I18N.fileTooLargePublic || 'Datei zu gro\u00DF (max. 20 MB).';\n                    return;\n                }\n\n                this.file = file;\n                this.fileName = file.name;\n                this.fileSize = (file.size / (1024 * 1024)).toFixed(1) + ' MB';\n                this.previewUrl = URL.createObjectURL(file);\n                this.error = '';\n                this.step = 2;\n            },\n\n            reset() {\n                if (this.previewUrl) URL.revokeObjectURL(this.previewUrl);\n                this.step = 1;\n                this.file = null;\n                this.fileName = '';\n                this.fileSize = '';\n                this.previewUrl = '';\n                this.error = '';\n                this.consent = false;\n                const fileInput = this.$root.querySelector('input[type=file]');\n                if (fileInput) fileInput.value = '';\n            },\n\n            async submit() {\n                if (this.$root.dataset.requireConsent !== undefined && !this.consent) {\n                    this.error = 'Bitte stimmen Sie der \u00F6ffentlichen Anzeige zu.';\n                    return;\n                }\n\n                this.error = '';\n                this.submitting = true;\n\n                const formData = new FormData();\n                formData.append('image', this.file);\n                formData.append('email', this.email);\n\n                if (this.consent) {\n                    formData.append('consent_public', 'on');\n                }\n\n                // Turnstile token\n                const turnstileInput = this.$root.querySelector('[name=\"cf-turnstile-response\"]');\n                if (turnstileInput) {\n                    formData.append('cf-turnstile-response', turnstileInput.value);\n                }\n\n                const csrfToken = document.querySelector('meta[name=\"csrf-token\"]').content;\n                const uploadUrl = this.$root.dataset.uploadUrl;\n\n                try {\n                    const response = await fetch(uploadUrl, {\n                        method: 'POST',\n                        headers: { 'X-CSRFToken': csrfToken },\n                        body: formData,\n                    });\n\n                    const data = await response.json();\n\n                    if (!response.ok) {\n                        this.error = data.error || 'Ein Fehler ist aufgetreten.';\n                        const widget = this.$root.querySelector('.cf-turnstile');\n                        if (widget && typeof turnstile !== 'undefined') {\n                            turnstile.reset(widget);\n                        }\n                        this.submitting = false;\n                        return;\n                    }\n\n                    window.location.href = data.redirect_url;\n                } catch (e) {\n                    this.error = I18N.connectionErrorTryAgain || 'Verbindungsfehler. Bitte versuchen Sie es erneut.';\n                    this.submitting = false;\n                }\n            }\n        };\n    });\n});\n"],
  "mappings": "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",
  "names": ["I18N", "json", "body", "node", "id", "xhr", "behavior", "event", "successful", "prefsJson", "prefs", "sel", "detail", "value", "subtype", "tab", "meta", "err", "button", "data", "propertyId", "v", "k", "presets", "inputs", "i", "inp", "selected", "p", "self", "has3d", "gate", "clamp", "value", "min", "max", "orientation", "a", "b", "c", "pointOnSegment", "point", "segmentsIntersect", "d", "abC", "abD", "cdA", "cdB", "epsilon", "polygonArea", "points", "sum", "index", "next", "polygonIsSimple", "first", "firstNext", "second", "secondNext", "openPathIsSimple", "lastStart", "lastEnd", "shape", "rect", "xs", "ys", "left", "top", "event", "threshold", "gesture", "start", "areaTooSmall", "previous", "candidate", "item", "dx", "dy", "viewport", "clamp", "value", "min", "max", "rounded", "distance", "a", "b", "midpoint", "highlightOperation", "operations", "operation", "cropOperation", "configElement", "event", "_a", "_b", "_c", "_d", "_e", "_f", "_g", "highlight", "crop", "params", "rect", "point", "cropRect", "tool", "target", "response", "message", "body", "error", "image", "lightboxLink", "el", "id", "key", "fallback", "handle", "gesture", "wasDraw", "moved", "originalRect", "minimum", "distanceMoved", "start", "dx", "dy", "original", "left", "top", "right", "bottom", "points", "viewport", "mid", "currentMid", "nextZoom", "anchorX", "anchorY", "polygonInProgress", "width", "height", "shortEdge", "blur", "brightness", "I18N", "prefs", "data", "id", "photoId", "url", "meta", "err", "checked", "checkbox", "groupKey", "selector", "cb", "checkboxes", "selectedCount", "params", "_a", "photoIds", "modal", "context", "csrf", "formData", "r", "I18N", "files", "_a", "file", "rejection", "validTypes", "msg", "rowId", "uploadRows", "name", "retryId", "tempId", "previewUrl", "uploadUrl", "csrfToken", "placeholderHtml", "doUpload", "formData", "response", "data", "showError", "placeholder", "retryBtn", "row", "onSuccess", "e", "friendlyMsg", "onDone", "error", "r", "url", "scrapeResults", "scrapeUrl", "html", "dataEl", "metaEl", "selectedIndexes", "urls", "i", "importUrl", "importedCount", "tempIds", "_", "result", "successCount", "id", "el", "text", "div", "openModal", "_a", "event", "file", "_b", "validExtension", "validType", "estimateProgress", "set", "expectedMs", "started", "tau", "timer", "t", "LISTING_LOAD_MS", "PARALLEL_UPLOADS", "VALID_TYPES", "MAX_BYTES", "csrfToken", "postForm", "url", "formData", "response", "data", "failureReason", "status", "hostOf", "uploadToGallery", "uploadUrl", "files", "propertyId", "onProgress", "I18N", "done", "galleryUrl", "lastError", "send", "file", "_a", "ok", "queue", "first", "worker", "validFiles", "fileList", "f", "path", "result", "n", "_b", "_c", "_d", "estimateProgress", "v", "host", "u", "event", "img", "message", "limitReached", "after", "form", "id", "card", "before", "d", "download", "frame", "selected", "total", "label", "modalStore", "csrfToken", "meta", "post", "url", "params", "body", "key", "track", "name", "seenUrl", "store", "forced", "el", "id", "self", "value", "previous", "context", "SCRAPE_MS", "IMPORT_BASE_MS", "IMPORT_PER_PHOTO_MS", "I18N", "_a", "isOpen", "url", "s", "source", "i", "other", "sources", "requestUrl", "csrfToken", "done", "estimateProgress", "v", "scrapeResults", "scrapeUrl", "formData", "html", "dataEl", "metaEl", "selectedIndexes", "name", "urls", "createUrl", "res", "data", "initialStreet", "initialPostalCode", "initialCity", "apiKey", "key", "_a", "_b", "e", "resolve", "reject", "cb", "s", "q", "input", "suggestions", "suggestion", "place", "components", "route", "streetNumber", "component", "type", "d", "key", "fields", "finKey", "filled", "f", "el", "s", "_a", "t", "p", "_b", "cold", "util", "raw", "val", "formData", "data", "I18N", "event", "file", "fileInput", "formData", "turnstileInput", "csrfToken", "uploadUrl", "response", "data", "widget"]
}
