/**
 * International Parcel Selector — Map Popup Engine
 * Full interactive map for parcel locker selection
 * 
 * @version 3.0.9
 * @author Peter Chrumkacz
 * @website https://parcelselector.com/
 * @created 2026-01-18
 * 
 * Features:
 * - Poland InPost Paczkomaty map
 * - Custom logo support (store branding)
 * - Full-text fuzzy search
 * - Responsive modal popup
 * - Remote API + local fallback data source
 */

(function() {
    'use strict';

    // =====================================================================================
    // 🔧 IPS DEBUG SYSTEM — Full F12 Console Debugging
    // =====================================================================================
    const IPS_DEBUG = (typeof parcselectCacheConfig !== 'undefined' && parcselectCacheConfig.debug === true); // Controlled by INPOST_DEBUG PHP constant
    const IPS = {
        log: function(area, msg, ...args) {
            if (!IPS_DEBUG) return;
            window.PS_DEBUG&&console.log(`%c[IPS:${area}]%c ${msg}`, 'color:#FF6600;font-weight:bold', 'color:inherit', ...args);
        },
        warn: function(area, msg, ...args) {
            if (!IPS_DEBUG) return;
            window.PS_DEBUG&&console.warn(`%c[IPS:${area}]%c ${msg}`, 'color:#FFA500;font-weight:bold', 'color:inherit', ...args);
        },
        error: function(area, msg, ...args) {
            window.PS_DEBUG&&console.error(`%c[IPS:${area}]%c ${msg}`, 'color:#FF0000;font-weight:bold', 'color:inherit', ...args);
        },
        group: function(label) {
            if (!IPS_DEBUG) return;
            console.group(`%c[IPS] ${label}`, 'color:#FF6600;font-weight:bold;font-size:12px');
        },
        groupEnd: function() {
            if (!IPS_DEBUG) return;
            console.groupEnd();
        },
        table: function(data) {
            if (!IPS_DEBUG) return;
            console.table(data);
        }
    };

    // Splash banner
    window.PS_DEBUG&&console.log(
        '%c International Parcel Selector v3.0.9 %c by Peter Chrumkacz %c parcelselector.com ',
        'background:#FF6600;color:white;font-weight:bold;padding:4px 8px;border-radius:4px 0 0 4px',
        'background:#333;color:white;padding:4px 8px',
        'background:#1a1a1a;color:#FF6600;padding:4px 8px;border-radius:0 4px 4px 0'
    );

    IPS.group('System Init');
    IPS.log('INIT', 'Plugin version: 3.0.1');
    IPS.log('INIT', 'Debug mode: ENABLED (IPS_DEBUG=true)');
    IPS.log('INIT', 'Timestamp:', new Date().toISOString());
    IPS.log('INIT', 'User Agent:', navigator.userAgent.substring(0, 80));

    // Data source diagnostics
    const _cacheConfig = window.parcselectCacheConfig || null;
    if (_cacheConfig) {
        IPS.log('DATA', 'Data mode:', _cacheConfig.dataMode || 'unknown');
        IPS.log('DATA', 'Base URL:', _cacheConfig.baseUrl);
        IPS.log('DATA', 'Source:', _cacheConfig.source);
        IPS.log('DATA', 'DANE_API exists:', _cacheConfig.daneApiExists ? 'YES (local files)' : 'NO (remote API)');
        IPS.log('DATA', 'Remote API URL:', _cacheConfig.remoteApiUrl || 'https://parcelselector.com/api/');
        IPS.log('DATA', 'Version:', _cacheConfig.version);
    } else {
        IPS.warn('DATA', 'parcselectCacheConfig NOT FOUND — will use country.api URLs as fallback');
    }

    // Library checks
    const _leafletReady = typeof L !== 'undefined';
    const _fuseReady = typeof Fuse !== 'undefined';
    IPS.log('LIBS', 'Leaflet:', _leafletReady ? 'OK (' + (L.version || '?') + ')' : 'MISSING');
    IPS.log('LIBS', 'Fuse.js:', _fuseReady ? 'OK' : 'will load on demand');
    IPS.log('LIBS', 'jQuery:', typeof jQuery !== 'undefined' ? 'OK (' + jQuery.fn.jquery + ')' : 'MISSING');
    IPS.log('LIBS', 'ParcelLockerSelector:', typeof window.ParcelLockerSelector !== 'undefined' ? 'OK' : 'loading...');

    if (!_leafletReady) {
        IPS.error('LIBS', 'CRITICAL: Leaflet.js not loaded! Map will NOT work.');
    }

    IPS.groupEnd();

    // =====================================================================================
    // 📦 InPostPopupData — SINGLE SOURCE OF TRUTH
    // Centralna funkcja zwracająca dane wpisane w popupach INTRO_1
    // Używana przez: confirmAndSave(), pre-map-popup, blocks-paczkomat-inject, debugging
    // Zawsze zwraca dane z najlepszego dostępnego źródła (multi-source fallback)
    // =====================================================================================
    window.InPostPopupData = {
        _customer: {},
        _paczkomat: {},

        /** Zapisz dane klienta (pre-map-popup.handleFormSubmit / confirmAndSave) */
        setCustomer: function(data) {
            this._customer = Object.assign({}, this._customer, data);
        },

        /** Zapisz dane paczkomatu (confirmAndSave) */
        setPaczkomat: function(data) {
            this._paczkomat = Object.assign({}, data);
        },

        /**
         * Pobierz dane klienta — MULTI-SOURCE FALLBACK:
         * 1. Wewnętrzny store (_customer) — setCustomer()
         * 2. DOM: formularz intro-popup (id="inpostFirstName" etc.)
         * 3. DOM: formularz pre-map-popup (id="preFirstName" etc.)
         * 4. window.inpostUserData (legacy — set by pre-map-popup)
         * 5. window.inpostPrePopupData (legacy backup)
         * ZAWSZE zwraca obiekt (pusty {} gdy brak danych)
         */
        getCustomer: function() {
            // Source 1: Internal store
            if (this._customer && this._customer.firstName) {
                return Object.assign({}, this._customer);
            }
            // Source 2: DOM intro-popup form
            var fn = document.getElementById('inpostFirstName');
            var ln = document.getElementById('inpostLastName');
            var em = document.getElementById('inpostEmail');
            var ph = document.getElementById('inpostPhone');
            var pp = document.getElementById('inpostPhonePrefix');
            if (fn && fn.value && fn.value.trim()) {
                var phoneNum = ph ? ph.value.trim() : '';
                return {
                    firstName: fn.value.trim(),
                    lastName: ln ? ln.value.trim() : '',
                    email: em ? em.value.trim() : '',
                    phone: phoneNum ? ((pp ? pp.value : '+48') + ' ' + phoneNum) : '',
                    phonePrefix: pp ? pp.value : '+48',
                    phoneNumber: phoneNum
                };
            }
            // Source 3: DOM pre-map-popup form
            var pfn = document.getElementById('preFirstName');
            var pln = document.getElementById('preLastName');
            var pem = document.getElementById('preEmail');
            var pph = document.getElementById('prePhone');
            var ppp = document.getElementById('prePhonePrefix');
            if (pfn && pfn.value && pfn.value.trim()) {
                var pPhoneNum = pph ? pph.value.trim() : '';
                return {
                    firstName: pfn.value.trim(),
                    lastName: pln ? pln.value.trim() : '',
                    email: pem ? pem.value.trim() : '',
                    phone: pPhoneNum ? ((ppp ? ppp.value : '+48') + ' ' + pPhoneNum) : '',
                    phonePrefix: ppp ? ppp.value : '+48',
                    phoneNumber: pPhoneNum
                };
            }
            // Source 4: window.inpostUserData (set by pre-map-popup)
            if (window.inpostUserData && window.inpostUserData.firstName) {
                return Object.assign({}, window.inpostUserData);
            }
            // Source 5: window.inpostPrePopupData (backup)
            if (window.inpostPrePopupData && window.inpostPrePopupData.firstName) {
                return Object.assign({}, window.inpostPrePopupData);
            }
            return {};
        },

        /** Pobierz dane paczkomatu */
        getPaczkomat: function() {
            return Object.assign({}, this._paczkomat);
        },

        /** Pobierz WSZYSTKIE dane (klient + paczkomat) */
        getAll: function() {
            return { customer: this.getCustomer(), paczkomat: this.getPaczkomat() };
        },

        /** Debug — wypisz wszystkie źródła */
        debug: function() {
            if (window.PS_DEBUG) {
                window.PS_DEBUG&&console.log('[InPostPopupData] === DEBUG ===');
                window.PS_DEBUG&&console.log('  _customer:', JSON.stringify(this._customer));
                window.PS_DEBUG&&console.log('  _paczkomat:', JSON.stringify(this._paczkomat));
                window.PS_DEBUG&&console.log('  window.inpostUserData:', JSON.stringify(window.inpostUserData || {}));
                window.PS_DEBUG&&console.log('  window.inpostPrePopupData:', JSON.stringify(window.inpostPrePopupData || {}));
                window.PS_DEBUG&&console.log('  → getCustomer():', JSON.stringify(this.getCustomer()));
                window.PS_DEBUG&&console.log('  → getPaczkomat():', JSON.stringify(this.getPaczkomat()));
                window.PS_DEBUG&&console.log('[InPostPopupData] === /DEBUG ===');
            }
        }
    };
    if (window.PS_DEBUG) console.log('[INTRO Popup] InPostPopupData initialized');

    // ⚡ FAST MODE - Wyłącza wszystkie animacje i opóźnienia dla maksymalnej szybkości
    // true = maksymalna szybkość (wszystkie setTimeout wyłączone, bez animacji)
    // false = normalne działanie z animacjami i opóźnieniami
    const FAST_MODE = false;

    // ⏱️ PERFORMANCE TIMING - Śledzenie czasów dla każdego etapu
    const performanceTiming = {
        popupOpened: null,       // Kliknięcie w przycisk otwierający mapę
        mapInitialized: null,    // Mapa Leaflet zainicjalizowana
        pointsLoaded: null,      // Punkty pobrane z API
        markersRendered: null,   // Markery dodane do mapy
        pointSelected: null,     // Użytkownik wybrał paczkomat (kliknął)
        confirmed: null          // Użytkownik potwierdził wybór
    };

    // ====================
    // KONFIGURACJA KRAJÓW
    // STATUS: ✅ WYODRĘBNIONY → countries.js (window.IPS_COUNTRIES)
    // FIX 2026-03-03: Kraje wyodrębnione do INTRO_1/countries.js
    // Inline definicja jest FALLBACK — jeśli countries.js się załadował,
    // window.IPS_COUNTRIES nadpisze ten obiekt.
    // ====================
    const COUNTRIES = window.IPS_COUNTRIES || {
        pl: {
            name: 'Polska',
            flag: '🇵🇱',
            flagCode: 'PL',
            flagSvg: 'pl.png',
            center: [52.0, 19.0],
            zoom: 6,
            api: 'https://parcelselector.com/api/points/pl',
            color: '#FF6600',
            apiType: 'remote',
            instructions: 'Jak znaleźć swój Paczkomat? • Wpisz w wyszukiwarce nazwę miasta lub kod pocztowy • Użyj scrolla myszy lub gestów dwoma palcami (zoom in/out) • Kliknij pinezkę aby wybrać'
        },
    };

    // ====================
    // SYSTEM TŁUMACZEŃ MULTILANGUAGE
    // STATUS: ✅ WYODRĘBNIONY → translations.js (window.IPS_TRANSLATIONS)
    // UŻYCIE: getTranslation('key') - zwraca tekst w języku aktywnego kraju
    // FALLBACK: Jeśli brak tłumaczenia dla kraju → zwraca polską wersję
    // FIX 2026-03-03: Tłumaczenia wyodrębnione do INTRO_1/translations.js
    // ====================
    const TRANSLATIONS = window.IPS_TRANSLATIONS || {
        pl: {
            // === WYSZUKIWARKA ===
            searchPlaceholder: "🔍 Szukaj punktu...",
            searchEmptyTitle: "Zacznij pisać, aby wyszukać paczkomat",
            searchEmptyHint: "lub kliknij na mapie aby zobaczyć szczegóły",
            // === PRZYCISKI / AKCJE ===
            closeButton: "Zamknij",
            selectPoint: "Wybierz ten punkt",
            changeLocker: "Zmień Paczkomat",
            accept: "Zaakceptuj",
            // === MARKER TOOLTIP ===
            markerSelect: "WYBIERZ",
            markerClickHint: "kliknij w pinezkę",
            // === DANE PUNKTU ===
            address: "Adres",
            coordinates: "Koordynaty",
            // === FORMULARZ DOSTAWY ===
            deliveryData: "Dane do dostawy",
            formHint: "Wypełnij dane aby potwierdzić wybór paczkomatu",
            firstName: "Imię",
            lastName: "Nazwisko",
            email: "Email",
            phone: "Numer telefonu",
            firstNamePlaceholder: "Jan",
            lastNamePlaceholder: "Kowalski",
            emailPlaceholder: "jan.kowalski@example.com",
            phonePlaceholder: "123456789",
            required: "*",
            // === STATUS / ŁADOWANIE ===
            loadingMap: "Ładowanie mapy...",
            loadingPoints: "Ładowanie punktów...",
            loadingData: "Ładowanie danych...",
            loadingWait: "Chwila moment...",
            foundPoints: "Znaleziono:",
            status: "Status:",
            loading: "Ładowanie...",
            statusReady: "Gotowe",
            statusError: "Błąd",
            pointsCount: "punktów",
            pointsLocal: "punktów (local)",
            // === WYNIKI WYSZUKIWANIA ===
            noResultsTitle: "Nie znaleziono paczkomatów",
            noResultsFor: "Nie znaleziono punktów dla:",
            noResults: "Brak wyników",
            trySearch: "Spróbuj wpisać:",
            city: "Miasto:",
            lockerCode: "Kod paczkomatu:",
            postalCode: "Kod pocztowy:",
            street: "Ulica:",
            morePoints: "więcej (użyj wyszukiwarki)",
            noPointsNearby: "Brak punktów InPost w okolicy",
            tryOtherLocation: "Spróbuj wyszukać inną lokalizację",
            // === LIMITY / OSTRZEŻENIA ===
            markerLimitWarning: "Wyświetlono",
            markerLimitOf: "z",
            markerLimitLockers: "paczkomatów",
            markerLimitHint: "Użyj bardziej szczegółowego wyszukiwania (np. dodaj ulicę lub kod pocztowy)",
            // === BŁĘDY ===
            errorLoadingPoints: "Błąd ładowania punktów",
            errorUnknown: "Nieznany błąd",
            errorCheckConsole: "Sprawdź konsolę przeglądarki (F12) dla szczegółów",
            errorSave: "Błąd zapisu. Spróbuj ponownie.",
            errorConnection: "Błąd połączenia z serwerem.",
            // === SUKCES ===
            successTitle: "Paczkomat wybrany!",
            successSubtitle: "Zapisano jako punkt odbioru",
            successCountdown: "Okienko zostanie zamknięte za",
            successSeconds: "sekund",
            successPanelTitle: "Paczkomat wybrany!",
            successDeliveryLabel: "Szacowany czas dostawy:",
            successBtnChange: "Zmień paczkomat",
            successBtnClose: "Zamknij teraz"
        },
        it: {
            searchPlaceholder: "🔍 Cerca punto...",
            searchEmptyTitle: "Inizia a digitare per cercare un locker",
            searchEmptyHint: "oppure clicca sulla mappa per vedere i dettagli",
            closeButton: "Chiudi",
            selectPoint: "Seleziona questo punto",
            changeLocker: "Cambia Locker",
            accept: "Accetta",
            markerSelect: "SELEZIONA",
            markerClickHint: "clicca sul segnaposto",
            address: "Indirizzo",
            coordinates: "Coordinate",
            deliveryData: "Dati di consegna",
            formHint: "Compila i dati per confermare la selezione del locker",
            firstName: "Nome",
            lastName: "Cognome",
            email: "Email",
            phone: "Numero di telefono",
            firstNamePlaceholder: "Mario",
            lastNamePlaceholder: "Rossi",
            emailPlaceholder: "mario.rossi@example.com",
            phonePlaceholder: "123456789",
            required: "*",
            loadingMap: "Caricamento mappa...",
            loadingPoints: "Caricamento punti...",
            loadingData: "Caricamento dati...",
            loadingWait: "Un momento...",
            foundPoints: "Trovati:",
            status: "Stato:",
            loading: "Caricamento...",
            statusReady: "Pronto",
            statusError: "Errore",
            pointsCount: "punti",
            pointsLocal: "punti (locale)",
            noResultsTitle: "Nessun locker trovato",
            noResultsFor: "Nessun punto trovato per:",
            noResults: "Nessun risultato",
            trySearch: "Prova a inserire:",
            city: "Città:",
            lockerCode: "Codice locker:",
            postalCode: "Codice postale:",
            street: "Via:",
            morePoints: "altri (usa la barra di ricerca)",
            noPointsNearby: "Nessun punto InPost nelle vicinanze",
            tryOtherLocation: "Prova a cercare un'altra posizione",
            markerLimitWarning: "Visualizzati",
            markerLimitOf: "di",
            markerLimitLockers: "locker",
            markerLimitHint: "Usa una ricerca più specifica (aggiungi via o CAP)",
            errorLoadingPoints: "Errore caricamento punti",
            errorUnknown: "Errore sconosciuto",
            errorCheckConsole: "Controlla la console del browser (F12) per dettagli",
            errorSave: "Errore di salvataggio. Riprova.",
            errorConnection: "Errore di connessione al server.",
            successTitle: "Grazie per aver scelto il Locker!",
            successSubtitle: "È stato salvato come metodo di consegna",
            successCountdown: "La finestra si chiuderà tra",
            successSeconds: "secondi",
            successPanelTitle: "Locker selezionato!",
            successDeliveryLabel: "Tempo di consegna stimato:",
            successBtnChange: "Cambia locker",
            successBtnClose: "Chiudi ora"
        },
        fr: {
            searchPlaceholder: "🔍 Rechercher un point...",
            searchEmptyTitle: "Commencez à taper pour rechercher un point",
            searchEmptyHint: "ou cliquez sur la carte pour voir les détails",
            closeButton: "Fermer",
            selectPoint: "Sélectionner ce point",
            changeLocker: "Changer de Consigne",
            accept: "Accepter",
            markerSelect: "CHOISIR",
            markerClickHint: "cliquez sur le marqueur",
            address: "Adresse",
            coordinates: "Coordonnées",
            deliveryData: "Données de livraison",
            formHint: "Remplissez les données pour confirmer la sélection de la consigne",
            firstName: "Prénom",
            lastName: "Nom",
            email: "Email",
            phone: "Numéro de téléphone",
            firstNamePlaceholder: "Jean",
            lastNamePlaceholder: "Dupont",
            emailPlaceholder: "jean.dupont@example.com",
            phonePlaceholder: "123456789",
            required: "*",
            loadingMap: "Chargement de la carte...",
            loadingPoints: "Chargement des points...",
            loadingData: "Chargement des données...",
            loadingWait: "Un instant...",
            foundPoints: "Trouvés:",
            status: "Statut:",
            loading: "Chargement...",
            statusReady: "Prêt",
            statusError: "Erreur",
            pointsCount: "points",
            pointsLocal: "points (local)",
            noResultsTitle: "Aucune consigne trouvée",
            noResultsFor: "Aucun point trouvé pour:",
            noResults: "Aucun résultat",
            trySearch: "Essayez de saisir:",
            city: "Ville:",
            lockerCode: "Code de consigne:",
            postalCode: "Code postal:",
            street: "Rue:",
            morePoints: "de plus (utilisez la recherche)",
            noPointsNearby: "Aucun point InPost à proximité",
            tryOtherLocation: "Essayez de chercher un autre lieu",
            markerLimitWarning: "Affichés",
            markerLimitOf: "sur",
            markerLimitLockers: "consignes",
            markerLimitHint: "Utilisez une recherche plus précise (ajoutez rue ou code postal)",
            errorLoadingPoints: "Erreur de chargement des points",
            errorUnknown: "Erreur inconnue",
            errorCheckConsole: "Vérifiez la console du navigateur (F12) pour les détails",
            errorSave: "Erreur d'enregistrement. Réessayez.",
            errorConnection: "Erreur de connexion au serveur.",
            successTitle: "Merci d'avoir choisi la Consigne!",
            successSubtitle: "Elle a été enregistrée comme méthode de livraison",
            successCountdown: "La fenêtre se fermera dans",
            successSeconds: "secondes",
            successPanelTitle: "Consigne choisie!",
            successDeliveryLabel: "Délai de livraison estimé:",
            successBtnChange: "Changer de consigne",
            successBtnClose: "Fermer maintenant"
        },
        es: {
            searchPlaceholder: "🔍 Buscar punto...",
            searchEmptyTitle: "Empieza a escribir para buscar una taquilla",
            searchEmptyHint: "o haz clic en el mapa para ver detalles",
            closeButton: "Cerrar",
            selectPoint: "Seleccionar este punto",
            changeLocker: "Cambiar Taquilla",
            accept: "Aceptar",
            markerSelect: "ELEGIR",
            markerClickHint: "haz clic en el marcador",
            address: "Dirección",
            coordinates: "Coordenadas",
            deliveryData: "Datos de entrega",
            formHint: "Complete los datos para confirmar la selección de la taquilla",
            firstName: "Nombre",
            lastName: "Apellido",
            email: "Email",
            phone: "Número de teléfono",
            firstNamePlaceholder: "Juan",
            lastNamePlaceholder: "García",
            emailPlaceholder: "juan.garcia@example.com",
            phonePlaceholder: "123456789",
            required: "*",
            loadingMap: "Cargando mapa...",
            loadingPoints: "Cargando puntos...",
            loadingData: "Cargando datos...",
            loadingWait: "Un momento...",
            foundPoints: "Encontrados:",
            status: "Estado:",
            loading: "Cargando...",
            statusReady: "Listo",
            statusError: "Error",
            pointsCount: "puntos",
            pointsLocal: "puntos (local)",
            noResultsTitle: "No se encontraron taquillas",
            noResultsFor: "No se encontraron puntos para:",
            noResults: "Sin resultados",
            trySearch: "Intenta ingresar:",
            city: "Ciudad:",
            lockerCode: "Código de taquilla:",
            postalCode: "Código postal:",
            street: "Calle:",
            morePoints: "más (usa el buscador)",
            noPointsNearby: "No hay puntos InPost cerca",
            tryOtherLocation: "Intenta buscar otra ubicación",
            markerLimitWarning: "Mostrados",
            markerLimitOf: "de",
            markerLimitLockers: "taquillas",
            markerLimitHint: "Usa una búsqueda más específica (agrega calle o código postal)",
            errorLoadingPoints: "Error al cargar puntos",
            errorUnknown: "Error desconocido",
            errorCheckConsole: "Revisa la consola del navegador (F12) para más detalles",
            errorSave: "Error al guardar. Inténtalo de nuevo.",
            errorConnection: "Error de conexión con el servidor.",
            successTitle: "¡Gracias por elegir la Taquilla!",
            successSubtitle: "Se ha guardado como método de entrega",
            successCountdown: "La ventana se cerrará en",
            successSeconds: "segundos",
            successPanelTitle: "¡Casillero elegido!",
            successDeliveryLabel: "Tiempo estimado de entrega:",
            successBtnChange: "Cambiar casillero",
            successBtnClose: "Cerrar ahora"
        },
        uk: {
            searchPlaceholder: "🔍 Search point...",
            searchEmptyTitle: "Start typing to search for a locker",
            searchEmptyHint: "or click on the map to see details",
            closeButton: "Close",
            selectPoint: "Select this point",
            changeLocker: "Change Locker",
            accept: "Accept",
            markerSelect: "SELECT",
            markerClickHint: "click the marker",
            address: "Address",
            coordinates: "Coordinates",
            deliveryData: "Delivery data",
            formHint: "Fill in the data to confirm the locker selection",
            firstName: "First Name",
            lastName: "Last Name",
            email: "Email",
            phone: "Phone Number",
            firstNamePlaceholder: "John",
            lastNamePlaceholder: "Smith",
            emailPlaceholder: "john.smith@example.com",
            phonePlaceholder: "123456789",
            required: "*",
            loadingMap: "Loading map...",
            loadingPoints: "Loading points...",
            loadingData: "Loading data...",
            loadingWait: "Just a moment...",
            foundPoints: "Found:",
            status: "Status:",
            loading: "Loading...",
            statusReady: "Ready",
            statusError: "Error",
            pointsCount: "points",
            pointsLocal: "points (local)",
            noResultsTitle: "No lockers found",
            noResultsFor: "No points found for:",
            noResults: "No results",
            trySearch: "Try entering:",
            city: "City:",
            lockerCode: "Locker code:",
            postalCode: "Postal code:",
            street: "Street:",
            morePoints: "more (use the search bar)",
            noPointsNearby: "No InPost points nearby",
            tryOtherLocation: "Try searching another location",
            markerLimitWarning: "Showing",
            markerLimitOf: "of",
            markerLimitLockers: "lockers",
            markerLimitHint: "Use a more specific search (add street or postal code)",
            errorLoadingPoints: "Error loading points",
            errorUnknown: "Unknown error",
            errorCheckConsole: "Check the browser console (F12) for details",
            errorSave: "Save error. Please try again.",
            errorConnection: "Server connection error.",
            successTitle: "Thank you for choosing the Locker!",
            successSubtitle: "It has been saved as your delivery method",
            successCountdown: "The window will close in",
            successSeconds: "seconds",
            successPanelTitle: "Locker selected!",
            successDeliveryLabel: "Estimated delivery time:",
            successBtnChange: "Change locker",
            successBtnClose: "Close now"
        },
        de: {
            searchPlaceholder: "🔍 Punkt suchen...",
            searchEmptyTitle: "Beginnen Sie zu tippen, um ein Schließfach zu suchen",
            searchEmptyHint: "oder klicken Sie auf die Karte für Details",
            closeButton: "Schließen",
            selectPoint: "Diesen Punkt wählen",
            changeLocker: "Schließfach ändern",
            accept: "Akzeptieren",
            markerSelect: "WÄHLEN",
            markerClickHint: "Klicken Sie auf den Marker",
            address: "Adresse",
            coordinates: "Koordinaten",
            deliveryData: "Lieferdaten",
            formHint: "Füllen Sie die Daten aus, um die Schließfachauswahl zu bestätigen",
            firstName: "Vorname",
            lastName: "Nachname",
            email: "Email",
            phone: "Telefonnummer",
            firstNamePlaceholder: "Hans",
            lastNamePlaceholder: "Müller",
            emailPlaceholder: "hans.mueller@example.com",
            phonePlaceholder: "123456789",
            required: "*",
            loadingMap: "Karte wird geladen...",
            loadingPoints: "Punkte werden geladen...",
            loadingData: "Daten werden geladen...",
            loadingWait: "Einen Moment...",
            foundPoints: "Gefunden:",
            status: "Status:",
            loading: "Laden...",
            statusReady: "Bereit",
            statusError: "Fehler",
            pointsCount: "Punkte",
            pointsLocal: "Punkte (lokal)",
            noResultsTitle: "Keine Schließfächer gefunden",
            noResultsFor: "Keine Punkte gefunden für:",
            noResults: "Keine Ergebnisse",
            trySearch: "Versuchen Sie einzugeben:",
            city: "Stadt:",
            lockerCode: "Schließfachcode:",
            postalCode: "Postleitzahl:",
            street: "Straße:",
            morePoints: "weitere (Suchleiste nutzen)",
            noPointsNearby: "Keine InPost-Punkte in der Nähe",
            tryOtherLocation: "Versuchen Sie einen anderen Standort",
            markerLimitWarning: "Angezeigt",
            markerLimitOf: "von",
            markerLimitLockers: "Schließfächern",
            markerLimitHint: "Verwenden Sie eine genauere Suche (Straße oder PLZ hinzufügen)",
            errorLoadingPoints: "Fehler beim Laden der Punkte",
            errorUnknown: "Unbekannter Fehler",
            errorCheckConsole: "Prüfen Sie die Browser-Konsole (F12) für Details",
            errorSave: "Speicherfehler. Bitte versuchen Sie es erneut.",
            errorConnection: "Verbindungsfehler zum Server.",
            successTitle: "Vielen Dank für die Auswahl des Lockers!",
            successSubtitle: "Es wurde als Liefermethode gespeichert",
            successCountdown: "Das Fenster schließt sich in",
            successSeconds: "Sekunden",
            successPanelTitle: "Paketbox ausgewählt!",
            successDeliveryLabel: "Voraussichtliche Lieferzeit:",
            successBtnChange: "Paketbox ändern",
            successBtnClose: "Jetzt schließen"
        },
        be: {
            searchPlaceholder: "🔍 Zoek punt...",
            searchEmptyTitle: "Begin te typen om een locker te zoeken",
            searchEmptyHint: "of klik op de kaart voor details",
            closeButton: "Sluiten",
            selectPoint: "Selecteer dit punt",
            changeLocker: "Locker wijzigen",
            accept: "Accepteren",
            markerSelect: "KIES",
            markerClickHint: "klik op de markering",
            address: "Adres",
            coordinates: "Coördinaten",
            deliveryData: "Leveringsgegevens",
            formHint: "Vul de gegevens in om de lockerselectie te bevestigen",
            firstName: "Voornaam",
            lastName: "Achternaam",
            email: "Email",
            phone: "Telefoonnummer",
            firstNamePlaceholder: "Jan",
            lastNamePlaceholder: "Janssens",
            emailPlaceholder: "jan.janssens@example.com",
            phonePlaceholder: "123456789",
            required: "*",
            loadingMap: "Kaart laden...",
            loadingPoints: "Punten laden...",
            loadingData: "Gegevens laden...",
            loadingWait: "Even geduld...",
            foundPoints: "Gevonden:",
            status: "Status:",
            loading: "Laden...",
            statusReady: "Klaar",
            statusError: "Fout",
            pointsCount: "punten",
            pointsLocal: "punten (lokaal)",
            noResultsTitle: "Geen lockers gevonden",
            noResultsFor: "Geen punten gevonden voor:",
            noResults: "Geen resultaten",
            trySearch: "Probeer in te voeren:",
            city: "Stad:",
            lockerCode: "Lockercode:",
            postalCode: "Postcode:",
            street: "Straat:",
            morePoints: "meer (gebruik de zoekbalk)",
            noPointsNearby: "Geen InPost-punten in de buurt",
            tryOtherLocation: "Probeer een andere locatie te zoeken",
            markerLimitWarning: "Weergegeven",
            markerLimitOf: "van",
            markerLimitLockers: "lockers",
            markerLimitHint: "Gebruik een specifiekere zoekopdracht (voeg straat of postcode toe)",
            errorLoadingPoints: "Fout bij laden van punten",
            errorUnknown: "Onbekende fout",
            errorCheckConsole: "Controleer de browserconsole (F12) voor details",
            errorSave: "Opslagfout. Probeer opnieuw.",
            errorConnection: "Verbindingsfout met server.",
            successTitle: "Dank u voor het kiezen van de Locker!",
            successSubtitle: "Het is opgeslagen als bezorgmethode",
            successCountdown: "Het venster sluit over",
            successSeconds: "seconden",
            successPanelTitle: "Locker geselecteerd!",
            successDeliveryLabel: "Geschatte levertijd:",
            successBtnChange: "Locker wijzigen",
            successBtnClose: "Nu sluiten"
        },
        nl: {
            searchPlaceholder: "🔍 Zoek punt...",
            searchEmptyTitle: "Begin te typen om een locker te zoeken",
            searchEmptyHint: "of klik op de kaart voor details",
            closeButton: "Sluiten",
            selectPoint: "Selecteer dit punt",
            changeLocker: "Locker wijzigen",
            accept: "Accepteren",
            markerSelect: "KIES",
            markerClickHint: "klik op de markering",
            address: "Adres",
            coordinates: "Coördinaten",
            deliveryData: "Leveringsgegevens",
            formHint: "Vul de gegevens in om de lockerselectie te bevestigen",
            firstName: "Voornaam",
            lastName: "Achternaam",
            email: "Email",
            phone: "Telefoonnummer",
            firstNamePlaceholder: "Pieter",
            lastNamePlaceholder: "de Vries",
            emailPlaceholder: "pieter.devries@example.com",
            phonePlaceholder: "123456789",
            required: "*",
            loadingMap: "Kaart laden...",
            loadingPoints: "Punten laden...",
            loadingData: "Gegevens laden...",
            loadingWait: "Even geduld...",
            foundPoints: "Gevonden:",
            status: "Status:",
            loading: "Laden...",
            statusReady: "Klaar",
            statusError: "Fout",
            pointsCount: "punten",
            pointsLocal: "punten (lokaal)",
            noResultsTitle: "Geen lockers gevonden",
            noResultsFor: "Geen punten gevonden voor:",
            noResults: "Geen resultaten",
            trySearch: "Probeer in te voeren:",
            city: "Stad:",
            lockerCode: "Lockercode:",
            postalCode: "Postcode:",
            street: "Straat:",
            morePoints: "meer (gebruik de zoekbalk)",
            noPointsNearby: "Geen InPost-punten in de buurt",
            tryOtherLocation: "Probeer een andere locatie te zoeken",
            markerLimitWarning: "Weergegeven",
            markerLimitOf: "van",
            markerLimitLockers: "lockers",
            markerLimitHint: "Gebruik een specifiekere zoekopdracht (voeg straat of postcode toe)",
            errorLoadingPoints: "Fout bij laden van punten",
            errorUnknown: "Onbekende fout",
            errorCheckConsole: "Controleer de browserconsole (F12) voor details",
            errorSave: "Opslagfout. Probeer opnieuw.",
            errorConnection: "Verbindingsfout met server.",
            successTitle: "Bedankt voor het kiezen van de Locker!",
            successSubtitle: "Het is opgeslagen als bezorgmethode",
            successCountdown: "Het venster sluit over",
            successSeconds: "seconden",
            successPanelTitle: "Locker geselecteerd!",
            successDeliveryLabel: "Geschatte levertijd:",
            successBtnChange: "Locker wijzigen",
            successBtnClose: "Nu sluiten"
        },
        pt: {
            searchPlaceholder: "🔍 Procurar ponto...",
            searchEmptyTitle: "Comece a digitar para procurar um cacifo",
            searchEmptyHint: "ou clique no mapa para ver detalhes",
            closeButton: "Fechar",
            selectPoint: "Selecionar este ponto",
            changeLocker: "Mudar Cacifo",
            accept: "Aceitar",
            markerSelect: "ESCOLHER",
            markerClickHint: "clique no marcador",
            address: "Endereço",
            coordinates: "Coordenadas",
            deliveryData: "Dados de entrega",
            formHint: "Preencha os dados para confirmar a seleção do cacifo",
            firstName: "Nome",
            lastName: "Sobrenome",
            email: "Email",
            phone: "Número de telefone",
            firstNamePlaceholder: "João",
            lastNamePlaceholder: "Silva",
            emailPlaceholder: "joao.silva@example.com",
            phonePlaceholder: "123456789",
            required: "*",
            loadingMap: "Carregando mapa...",
            loadingPoints: "Carregando pontos...",
            loadingData: "Carregando dados...",
            loadingWait: "Um momento...",
            foundPoints: "Encontrados:",
            status: "Estado:",
            loading: "Carregando...",
            statusReady: "Pronto",
            statusError: "Erro",
            pointsCount: "pontos",
            pointsLocal: "pontos (local)",
            noResultsTitle: "Nenhum cacifo encontrado",
            noResultsFor: "Nenhum ponto encontrado para:",
            noResults: "Sem resultados",
            trySearch: "Tente inserir:",
            city: "Cidade:",
            lockerCode: "Código do cacifo:",
            postalCode: "Código postal:",
            street: "Rua:",
            morePoints: "mais (use a barra de pesquisa)",
            noPointsNearby: "Nenhum ponto InPost nas proximidades",
            tryOtherLocation: "Tente pesquisar outra localização",
            markerLimitWarning: "Exibidos",
            markerLimitOf: "de",
            markerLimitLockers: "cacifos",
            markerLimitHint: "Use uma pesquisa mais específica (adicione rua ou código postal)",
            errorLoadingPoints: "Erro ao carregar pontos",
            errorUnknown: "Erro desconhecido",
            errorCheckConsole: "Verifique a consola do navegador (F12) para detalhes",
            errorSave: "Erro ao guardar. Tente novamente.",
            errorConnection: "Erro de ligação ao servidor.",
            successTitle: "Obrigado por escolher o Locker!",
            successSubtitle: "Foi guardado como método de entrega",
            successCountdown: "A janela fechará em",
            successSeconds: "segundos",
            successPanelTitle: "Armário selecionado!",
            successDeliveryLabel: "Prazo estimado de entrega:",
            successBtnChange: "Mudar cacifo",
            successBtnClose: "Fechar agora"
        },
        at: {
            searchPlaceholder: "🔍 Punkt suchen...",
            searchEmptyTitle: "Beginnen Sie zu tippen, um ein Schließfach zu suchen",
            searchEmptyHint: "oder klicken Sie auf die Karte für Details",
            closeButton: "Schließen",
            selectPoint: "Diesen Punkt wählen",
            changeLocker: "Schließfach ändern",
            accept: "Akzeptieren",
            markerSelect: "WÄHLEN",
            markerClickHint: "Klicken Sie auf den Marker",
            address: "Adresse",
            coordinates: "Koordinaten",
            deliveryData: "Lieferdaten",
            formHint: "Füllen Sie die Daten aus, um die Schließfachauswahl zu bestätigen",
            firstName: "Vorname",
            lastName: "Nachname",
            email: "Email",
            phone: "Telefonnummer",
            firstNamePlaceholder: "Franz",
            lastNamePlaceholder: "Schmidt",
            emailPlaceholder: "franz.schmidt@example.com",
            phonePlaceholder: "123456789",
            required: "*",
            loadingMap: "Karte wird geladen...",
            loadingPoints: "Punkte werden geladen...",
            loadingData: "Daten werden geladen...",
            loadingWait: "Einen Moment...",
            foundPoints: "Gefunden:",
            status: "Status:",
            loading: "Laden...",
            statusReady: "Bereit",
            statusError: "Fehler",
            pointsCount: "Punkte",
            pointsLocal: "Punkte (lokal)",
            noResultsTitle: "Keine Schließfächer gefunden",
            noResultsFor: "Keine Punkte gefunden für:",
            noResults: "Keine Ergebnisse",
            trySearch: "Versuchen Sie einzugeben:",
            city: "Stadt:",
            lockerCode: "Schließfachcode:",
            postalCode: "Postleitzahl:",
            street: "Straße:",
            morePoints: "weitere (Suchleiste nutzen)",
            noPointsNearby: "Keine InPost-Punkte in der Nähe",
            tryOtherLocation: "Versuchen Sie einen anderen Standort",
            markerLimitWarning: "Angezeigt",
            markerLimitOf: "von",
            markerLimitLockers: "Schließfächern",
            markerLimitHint: "Verwenden Sie eine genauere Suche (Straße oder PLZ hinzufügen)",
            errorLoadingPoints: "Fehler beim Laden der Punkte",
            errorUnknown: "Unbekannter Fehler",
            errorCheckConsole: "Prüfen Sie die Browser-Konsole (F12) für Details",
            errorSave: "Speicherfehler. Bitte versuchen Sie es erneut.",
            errorConnection: "Verbindungsfehler zum Server.",
            successTitle: "Danke für die Auswahl des Lockers!",
            successSubtitle: "Es wurde als Liefermethode gespeichert",
            successCountdown: "Das Fenster schließt sich in",
            successSeconds: "Sekunden",
            successPanelTitle: "Paketbox ausgewählt!",
            successDeliveryLabel: "Voraussichtliche Lieferzeit:",
            successBtnChange: "Paketbox ändern",
            successBtnClose: "Jetzt schließen"
        },
        hu: {
            searchPlaceholder: "🔍 Pont keresése...",
            searchEmptyTitle: "Kezdjen el gépelni a csomagautomata kereséséhez",
            searchEmptyHint: "vagy kattintson a térképre a részletekért",
            closeButton: "Bezár",
            selectPoint: "Válassza ki ezt a pontot",
            changeLocker: "Automata módosítása",
            accept: "Elfogad",
            markerSelect: "VÁLASZT",
            markerClickHint: "kattintson a jelölőre",
            address: "Cím",
            coordinates: "Koordináták",
            deliveryData: "Szállítási adatok",
            formHint: "Töltse ki az adatokat a csomagautomata kiválasztásának megerősítéséhez",
            firstName: "Keresztnév",
            lastName: "Vezetéknév",
            email: "Email",
            phone: "Telefonszám",
            firstNamePlaceholder: "János",
            lastNamePlaceholder: "Nagy",
            emailPlaceholder: "janos.nagy@example.com",
            phonePlaceholder: "123456789",
            required: "*",
            loadingMap: "Térkép betöltése...",
            loadingPoints: "Pontok betöltése...",
            loadingData: "Adatok betöltése...",
            loadingWait: "Egy pillanat...",
            foundPoints: "Találatok:",
            status: "Állapot:",
            loading: "Betöltés...",
            statusReady: "Kész",
            statusError: "Hiba",
            pointsCount: "pont",
            pointsLocal: "pont (helyi)",
            noResultsTitle: "Nem található csomagautomata",
            noResultsFor: "Nem található pont a következőhöz:",
            noResults: "Nincs találat",
            trySearch: "Próbálja meg beírni:",
            city: "Város:",
            lockerCode: "Csomagautomata kód:",
            postalCode: "Irányítószám:",
            street: "Utca:",
            morePoints: "további (használja a keresőt)",
            noPointsNearby: "Nincs InPost pont a közelben",
            tryOtherLocation: "Próbáljon meg másik helyet keresni",
            markerLimitWarning: "Megjelenítve",
            markerLimitOf: "/",
            markerLimitLockers: "csomagautomata",
            markerLimitHint: "Használjon pontosabb keresést (utca vagy irányítószám)",
            errorLoadingPoints: "Hiba a pontok betöltésekor",
            errorUnknown: "Ismeretlen hiba",
            errorCheckConsole: "Ellenőrizze a böngésző konzolját (F12) a részletekért",
            errorSave: "Mentési hiba. Próbálja újra.",
            errorConnection: "Szerver kapcsolati hiba.",
            successTitle: "Köszönjük a Locker választását!",
            successSubtitle: "Elmentve szállítási módként",
            successCountdown: "Az ablak bezárul",
            successSeconds: "másodperc múlva",
            successPanelTitle: "Csomagautomata kiválasztva!",
            successDeliveryLabel: "Becsült szállítási idő:",
            successBtnChange: "Automata módosítása",
            successBtnClose: "Bezárás"
        },
        cz: {
            searchPlaceholder: "🔍 Hledat bod...",
            searchEmptyTitle: "Začněte psát pro vyhledání ParcelBoxu",
            searchEmptyHint: "nebo klikněte na mapu pro zobrazení detailů",
            closeButton: "Zavřít",
            selectPoint: "Vybrat tento bod",
            changeLocker: "Změnit ParcelBox",
            accept: "Potvrdit",
            markerSelect: "VYBRAT",
            markerClickHint: "klikněte na špendlík",
            address: "Adresa",
            coordinates: "Souřadnice",
            deliveryData: "Údaje pro doručení",
            formHint: "Vyplňte údaje pro potvrzení výběru ParcelBoxu",
            firstName: "Jméno",
            lastName: "Příjmení",
            email: "Email",
            phone: "Telefonní číslo",
            firstNamePlaceholder: "Jan",
            lastNamePlaceholder: "Novák",
            emailPlaceholder: "jan.novak@example.com",
            phonePlaceholder: "123456789",
            required: "*",
            loadingMap: "Načítání mapy...",
            loadingPoints: "Načítání bodů...",
            loadingData: "Načítání dat...",
            loadingWait: "Moment prosím...",
            foundPoints: "Nalezeno:",
            status: "Stav:",
            loading: "Načítání...",
            statusReady: "Připraveno",
            statusError: "Chyba",
            pointsCount: "bodů",
            pointsLocal: "bodů (místní)",
            noResultsTitle: "Nebyl nalezen žádný ParcelBox",
            noResultsFor: "Nebyly nalezeny body pro:",
            noResults: "Žádné výsledky",
            trySearch: "Zkuste zadat:",
            city: "Město:",
            lockerCode: "Kód ParcelBoxu:",
            postalCode: "PSČ:",
            street: "Ulice:",
            morePoints: "dalších (použijte vyhledávač)",
            noPointsNearby: "V okolí nebyl nalezen žádný bod InPost",
            tryOtherLocation: "Zkuste hledat jinou lokaci",
            markerLimitWarning: "Zobrazeno",
            markerLimitOf: "/",
            markerLimitLockers: "ParcelBoxů",
            markerLimitHint: "Použijte přesnější vyhledávání (ulice nebo PSČ)",
            errorLoadingPoints: "Chyba při načítání bodů",
            errorUnknown: "Neznámá chyba",
            errorCheckConsole: "Zkontrolujte konzoli prohlížeče (F12) pro podrobnosti",
            errorSave: "Chyba při ukládání. Zkuste to znovu.",
            errorConnection: "Chyba připojení k serveru.",
            successTitle: "Děkujeme za výběr ParcelBoxu!",
            successSubtitle: "Uloženo jako způsob doručení",
            successCountdown: "Okno se zavře za",
            successSeconds: "sekund",
            successPanelTitle: "ParcelBox vybrán!",
            successDeliveryLabel: "Odhadovaná doba doručení:",
            successBtnChange: "Změnit ParcelBox",
            successBtnClose: "Zavřít nyní"
        },
        sk: {
            searchPlaceholder: "🔍 Hľadať bod...",
            searchEmptyTitle: "Začnite písať pre vyhľadanie ParcelBoxu",
            searchEmptyHint: "alebo kliknite na mapu pre zobrazenie detailov",
            closeButton: "Zavrieť",
            selectPoint: "Vybrať tento bod",
            changeLocker: "Zmeniť ParcelBox",
            accept: "Potvrdiť",
            markerSelect: "VYBRAŤ",
            markerClickHint: "kliknite na špendlík",
            address: "Adresa",
            coordinates: "Súradnice",
            deliveryData: "Údaje pre doručenie",
            formHint: "Vyplňte údaje pre potvrdenie výberu ParcelBoxu",
            firstName: "Meno",
            lastName: "Priezvisko",
            email: "Email",
            phone: "Telefónne číslo",
            firstNamePlaceholder: "Ján",
            lastNamePlaceholder: "Novák",
            emailPlaceholder: "jan.novak@example.com",
            phonePlaceholder: "123456789",
            required: "*",
            loadingMap: "Načítavanie mapy...",
            loadingPoints: "Načítavanie bodov...",
            loadingData: "Načítavanie dát...",
            loadingWait: "Moment prosím...",
            foundPoints: "Nájdené:",
            status: "Stav:",
            loading: "Načítavanie...",
            statusReady: "Pripravené",
            statusError: "Chyba",
            pointsCount: "bodov",
            pointsLocal: "bodov (miestne)",
            noResultsTitle: "Nebol nájdený žiadny ParcelBox",
            noResultsFor: "Neboli nájdené body pre:",
            noResults: "Žiadne výsledky",
            trySearch: "Skúste zadať:",
            city: "Mesto:",
            lockerCode: "Kód ParcelBoxu:",
            postalCode: "PSČ:",
            street: "Ulica:",
            morePoints: "ďalších (použite vyhľadávač)",
            noPointsNearby: "V okolí nebol nájdený žiadny bod InPost",
            tryOtherLocation: "Skúste hľadať inú lokáciu",
            markerLimitWarning: "Zobrazené",
            markerLimitOf: "/",
            markerLimitLockers: "ParcelBoxov",
            markerLimitHint: "Použite presnejšie vyhľadávanie (ulica alebo PSČ)",
            errorLoadingPoints: "Chyba pri načítavaní bodov",
            errorUnknown: "Neznáma chyba",
            errorCheckConsole: "Skontrolujte konzolu prehliadača (F12) pre podrobnosti",
            errorSave: "Chyba pri ukladaní. Skúste to znova.",
            errorConnection: "Chyba pripojenia k serveru.",
            successTitle: "Ďakujeme za výber ParcelBoxu!",
            successSubtitle: "Uložené ako spôsob doručenia",
            successCountdown: "Okno sa zavrie za",
            successSeconds: "sekúnd",
            successPanelTitle: "ParcelBox vybraný!",
            successDeliveryLabel: "Odhadovaný čas doručenia:",
            successBtnChange: "Zmeniť ParcelBox",
            successBtnClose: "Zavrieť teraz"
        }
    };

    // ====================
    // FUNKCJA POBIERANIA TŁUMACZENIA
    // STATUS: ✅ NOWY
    // ====================
    function getTranslation(key) {
        return TRANSLATIONS[currentCountry]?.[key] || TRANSLATIONS['pl'][key] || key;
    }

    // ✅ AKTUALIZACJA TŁUMACZEŃ UI BEZ PRZEBUDOWY HTML
    // Wywoływane przy switchCountry() - odświeża teksty footer stats, wyszukiwarki, loadera
    function updateUITranslations() {
        // Footer stats labels
        const statLabels = document.querySelectorAll('.stat-label');
        if (statLabels.length >= 2) {
            statLabels[0].textContent = getTranslation('foundPoints');
            statLabels[1].textContent = getTranslation('status');
        }
        // Wyszukiwarka placeholder
        const searchInput = document.getElementById('inpostSearchInput');
        if (searchInput) {
            searchInput.placeholder = getTranslation('searchPlaceholder');
        }
        // Map loader
        const mapLoadingText = document.querySelector('#inpostMapLoading p');
        if (mapLoadingText) {
            mapLoadingText.textContent = getTranslation('loadingMap');
        }
        // Status - resetuj przy zmianie
        const loadStatus = document.getElementById('inpostLoadStatus');
        if (loadStatus) {
            loadStatus.textContent = getTranslation('loading');
        }
    }

    // ====================
    // FUNKCJA ZWRACAJĄCA SVG FLAGĘ
    // STATUS: ✅ DZIAŁA - Zwraca inline SVG flag dla 11 krajów
    // DLACZEGO SVG: Emoji nie działają poprawnie na Windows
    // WYMIARY: 26x20px z border-radius 3px
    // ====================
    function getFlagSvg(countryCode) {
        const svgFlags = {
            pl: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 480" style="width:26px;height:20px;border-radius:3px;"><rect width="640" height="240" fill="#fff"/><rect y="240" width="640" height="240" fill="#dc143c"/></svg>',
            it: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 480" style="width:26px;height:20px;border-radius:3px;"><rect width="213.3" height="480" fill="#009246"/><rect x="213.3" width="213.3" height="480" fill="#fff"/><rect x="426.6" width="213.4" height="480" fill="#ce2b37"/></svg>',
            fr: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 480" style="width:26px;height:20px;border-radius:3px;"><rect width="213.3" height="480" fill="#002395"/><rect x="213.3" width="213.3" height="480" fill="#fff"/><rect x="426.6" width="213.4" height="480" fill="#ed2939"/></svg>',
            es: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 480" style="width:26px;height:20px;border-radius:3px;"><rect width="640" height="120" fill="#c60b1e"/><rect y="120" width="640" height="240" fill="#ffc400"/><rect y="360" width="640" height="120" fill="#c60b1e"/></svg>',
            uk: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 480" style="width:26px;height:20px;border-radius:3px;"><path fill="#012169" d="M0 0h640v480H0z"/><path fill="#FFF" d="M75 0l244 181L562 0h78v62L400 241l240 178v61h-80L320 301 81 480H0v-60l239-178L0 64V0h75z"/><path fill="#C8102E" d="M424 281l216 159v40L369 281h55zm-184 20l6 35L54 480H0l240-179zM640 0v3L391 191l2-44L590 0h50zM0 0l239 176h-60L0 42V0z"/><path fill="#FFF" d="M241 0v480h160V0H241zM0 160v160h640V160H0z"/><path fill="#C8102E" d="M0 193v96h640v-96H0zM273 0v480h96V0h-96z"/></svg>',
            de: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 480" style="width:26px;height:20px;border-radius:3px;"><rect width="640" height="160" fill="#000"/><rect y="160" width="640" height="160" fill="#D00"/><rect y="320" width="640" height="160" fill="#FFCE00"/></svg>',
            be: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 480" style="width:26px;height:20px;border-radius:3px;"><rect width="213.3" height="480" fill="#000"/><rect x="213.3" width="213.3" height="480" fill="#FAE042"/><rect x="426.6" width="213.4" height="480" fill="#ED2939"/></svg>',
            nl: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 480" style="width:26px;height:20px;border-radius:3px;"><rect width="640" height="160" fill="#21468B"/><rect y="160" width="640" height="160" fill="#FFF"/><rect y="320" width="640" height="160" fill="#AE1C28"/></svg>',
            lu: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 480" style="width:26px;height:20px;border-radius:3px;"><rect width="640" height="160" fill="#ed2939"/><rect y="160" width="640" height="160" fill="#fff"/><rect y="320" width="640" height="160" fill="#00a1de"/></svg>',
            pt: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 480" style="width:26px;height:20px;border-radius:3px;"><rect width="256" height="480" fill="#060"/><rect x="256" width="384" height="480" fill="#D52B1E"/></svg>',
            at: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 480" style="width:26px;height:20px;border-radius:3px;"><rect width="640" height="160" fill="#ED2939"/><rect y="160" width="640" height="160" fill="#FFF"/><rect y="320" width="640" height="160" fill="#ED2939"/></svg>',
            hu: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 480" style="width:26px;height:20px;border-radius:3px;"><rect width="640" height="160" fill="#CD2A3E"/><rect y="160" width="640" height="160" fill="#FFF"/><rect y="320" width="640" height="160" fill="#436F4D"/></svg>',
            cz: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 480" style="width:26px;height:20px;border-radius:3px;"><rect width="640" height="480" fill="#fff"/><rect y="240" width="640" height="240" fill="#d7141a"/><path d="M0 0l320 240L0 480z" fill="#11457e"/></svg>',
            sk: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 480" style="width:26px;height:20px;border-radius:3px;"><rect width="640" height="160" fill="#fff"/><rect y="160" width="640" height="160" fill="#0b4ea2"/><rect y="320" width="640" height="160" fill="#ee1c25"/></svg>'
        };
        return svgFlags[countryCode] || '';
    }

    // ====================================================================================
    // STAN GLOBALNY - Zmienne globalne używane przez cały system
    // ====================================================================================
    // OPIS DLA AI:
    // Te zmienne trzymają aktualny stan aplikacji. Są aktualizowane przy każdej zmianie kraju,
    // wyszukiwaniu, wyborze punktu etc. Zawsze sprawdzaj czy są zdefiniowane przed użyciem!
    // ====================================================================================
    let currentCountry = 'pl';      // Kod aktywnego kraju (pl, it, fr, es, uk, de, be, nl, pt, at, hu)
    let map = null;                 // Instancja mapy Leaflet.js (inicjalizowana w initializeMap())
    let markers = [];               // Tablica markerów Leaflet na mapie (czyszczona przy zmianie kraju)
    let allPoints = [];             // WSZYSTKIE punkty z API dla aktywnego kraju (pełna lista)
    let filteredPoints = [];        // Punkty przefiltrowane przez wyszukiwarkę (podzbiór allPoints)
    let displayedPoints = [];       // Punkty AKTUALNIE wyświetlane na liście (viewport culling)
    let selectedPoint = null;       // Aktualnie wybrany punkt (null = brak wyboru)
    let currentZoomLevel = 6;       // Aktualny poziom zoomu mapy (6 = kraj, 14 = miasto, 18 = ulica)
    let _customPickupMarker = null; // Marker punktu odbioru osobistego (PS_CUSTOM_PICKUP)
    let fuseInstance = null;        // Instancja Fuse.js (fuzzy search) - inicjalizowana przy załadowaniu punktów
    
    // Epic Zoom - pulse circles (globalne referencje do usunięcia po animacji)
    let epicZoomPulseCircle = null;  // Główny pulse circle
    let epicZoomEcho1 = null;        // Echo circle 1
    let epicZoomEcho2 = null;        // Echo circle 2
    let epicZoomEcho3 = null;        // Echo circle 3

    // TIMEOUT TRACKER - śledzi wszystkie setTimeout aby anulować przy zamknięciu popup
    let pendingTimeouts = [];
    function safeTimeout(fn, delay) {
        const id = setTimeout(() => {
            pendingTimeouts = pendingTimeouts.filter(t => t !== id);
            if (map || document.getElementById('inpost-universal-popup')) {
                fn();
            }
        }, delay);
        pendingTimeouts.push(id);
        return id;
    }
    function cancelAllPendingTimeouts() {
        pendingTimeouts.forEach(id => clearTimeout(id));
        pendingTimeouts = [];
        window.PS_DEBUG&&console.log('[INTRO Popup] Anulowano wszystkie pending timeouty');
    }

    // ====================================================================================
    // KONFIGURACJA Z PANELU ADMINA WORDPRESS
    // ====================================================================================
    // OPIS DLA AI:
    // adminConfig może być nadpisany przez WordPress (wp_localize_script w PHP).
    // Jeśli WordPress nie nadpisuje, używane są poniższe domyślne wartości.
    // Mergowanie odbywa się w funkcji loadAdminConfig() wywoływanej przy starcie.
    // ====================================================================================
    // STATUS: ⚠️ BACKEND GOTOWY (class-popup-admin.php), FRONTEND ZINTEGROWANY
    // DZIAŁA: Mergowanie z inpostPopupConfig (loadAdminConfig)
    // NIE DZIAŁA: Zapisywanie do wp_options (brak WordPress admin panel UI - DO ZROBIENIA!)
    // ====================================================================================
    let adminConfig = {
        // === LOGO ===
        logoInpost: '/wp-content/plugins/parcel-selector/assets/images/Parcel_Selector_Com.jpg',
        logoShop: '',
        logoSwap: false,

        // === INSTRUKCJE ===
        instructions: {},         // Custom instrukcje dla każdego kraju (np. {pl: 'Tekst', it: 'Testo'})
        showCountryName: true,    // Pokazywać nazwę kraju w headerze (true/false)
        
        // === WYDAJNOŚĆ ===
        initialPointsLimit: 750,  // ✅ DZIAŁA - Limit punktów na start (oszczędność RAM!)
        lazyLoadOnZoom: true,     // ✅ DZIAŁA - Ładowanie przy zoomie (smooth UX)
        viewportCulling: true,    // ✅ DZIAŁA - Tylko widoczne markery (mega boost!)
        
        // === MULTIJĘZYCZNOŚĆ ===
        enabledCountries: ['pl'], // Free version: InPost / Poland only
        customInstructions: {},   // Niestandardowe instrukcje per kraj
        
        // === PARCEL LOCKER SELECTOR (v2.30.0) ===
        // Moduł wyboru paczkomatu (parcel-locker-selector.js)
        parcelLockerSelector: {
            successMessage: 'Dziękujemy za wybranie paczkomatu! Twoja paczka zostanie wysłana po opłaceniu zamówienia.',
            deliveryTime: '2-3 dni robocze',  // Czas dostawy w success panelu
            countdownSeconds: 10,             // Auto-close countdown (sekundy)
            autoClose: true                   // Czy auto-zamykać popup
        },

        // === FUSE.JS FUZZY SEARCH (NOWE 2026-02-15) ===
        // Inteligentna wyszukiwarka z tolerancją na błędy, różne formaty, typos
        // Dlaczego? Rozwiązuje problemy: "00-001" vs "00001", "Kraków" vs "Krakow", etc.
        fuseSearch: {
            enabled: true,
            threshold: 0.6,
            distance: 1000,
            minMatchCharLength: 2,
            includeScore: true,
            useExtendedSearch: false,
            ignoreLocation: true,
            keys: [
                { name: '_searchable', weight: 0.5 },
                { name: 'address_details.city', weight: 0.4 },
                { name: 'name', weight: 0.3 },
                { name: 'address_details.street', weight: 0.2 },
                { name: 'address_details.post_code', weight: 0.1 }
            ]
        }
    };

    // ====================
    // HISTORIA KLIKNIĘĆ
    // STATUS: ✅ DZIAŁA - Pokazuje się automatycznie w pustym polu wyszukiwania
    // ====================
    // Przechowuje ostatnie kliknięte punkty (max 10)
    // Najnowsze kliknięcie jest ZAWSZE pierwsze w tablicy
    let clickedPointsHistory = [];
    const MAX_HISTORY = 10;
    
    // Funkcja wyświetlająca historię kliknięć gdy pole wyszukiwania puste
    function showClickHistory() {
        const pointsList = document.getElementById('inpostPointsList');
        if (!pointsList) return;
        
        // Jeśli brak historii, pokaż komunikat zachęcający
        if (clickedPointsHistory.length === 0) {
            pointsList.innerHTML = `
                <div style="padding: 40px 20px; text-align: center; color: #999; font-size: 14px;">
                    <div style="font-size: 48px; margin-bottom: 16px;">📍</div>
                    <div style="font-weight: 500; margin-bottom: 8px;">${getTranslation('searchEmptyTitle')}</div>
                    <div>${getTranslation('searchEmptyHint')}</div>
                </div>
            `;
            return;
        }
        
        // Pokaż historię kliknięć (bez nagłówka "Ostatnio oglądane")
        pointsList.innerHTML = '';
        
        clickedPointsHistory.forEach((point, index) => {
            const div = document.createElement('div');
            div.className = 'inpost-point-item';
            if (selectedPoint && selectedPoint.name === point.name) {
                div.classList.add('active');
            }
            
            // ✅ CHECKBOX dla Parcel Locker Selector (także w historii!)
            const checkboxHtml = typeof ParcelLockerSelector !== 'undefined'
                ? ParcelLockerSelector.createListCheckbox(point)
                : '<div class="list-checkbox"><span class="checkbox-icon">☐</span></div>';
            
            div.innerHTML = `
                ${checkboxHtml}
                <div class="point-content">
                    <div class="point-name">📍 ${point.name}</div>
                    <div class="point-address">${(point.address_details && point.address_details.city) || ''}, ${(point.address_details && point.address_details.street) || ''}</div>
                </div>
            `;
            
            div.onclick = () => {
                const marker = markers.find(m => m.pointData && m.pointData.name === point.name);
                if (marker) {
                    selectPointOnMap(point, marker);
                }
            };
            
            pointsList.appendChild(div);
        });
        
        window.PS_DEBUG&&console.log('[INTRO Popup] ✅ Pokazano historię:', clickedPointsHistory.length, 'punktów');
    }

    // ====================
    // INICJALIZACJA
    // ====================
    function init() {
        window.PS_DEBUG&&console.log('[INTRO Popup] Inicjalizacja uniwersalnego systemu map');
        
        // Ładowanie konfiguracji z WordPress (jeśli dostępna)
        loadAdminConfig();
        
        // Nasłuchiwanie na otwarcie popupu
        document.addEventListener('inpost-open-map', function(e) {
            const country = e.detail?.country || currentCountry;
            openMapPopup(country);
        });
        
        window.PS_DEBUG&&console.log('[INTRO Popup] System gotowy. Obsługiwane kraje:', Object.keys(COUNTRIES).join(', '));
    }

    // ====================
    // ŁADOWANIE KONFIGURACJI Z WORDPRESS
    // STATUS: ✅ DZIAŁA - Mergowanie konfiguracji spread operatorem
    // WAŻNE: inpostPopupConfig (WordPress) NADPISUJE adminConfig (domyślny)
    // PRIORYTET: inpostPopupConfig > adminConfig
    // UWAGA: NIE wstawiać logoInpost w inpostPopupConfig jeśli chcesz domyślne logo!
    // ====================
    function loadAdminConfig() {
        // Sprawdzenie czy istnieje obiekt konfiguracyjny z WordPressa
        if (typeof inpostPopupConfig !== 'undefined') {
            window.PS_DEBUG&&console.log('[INTRO Popup] Ładowanie konfiguracji z WordPress');
            // SPREAD OPERATOR: {...adminConfig, ...inpostPopupConfig}
            // Oznacza: inpostPopupConfig nadpisuje wartości z adminConfig
            adminConfig = {...adminConfig, ...inpostPopupConfig};
        } else {
            window.PS_DEBUG&&console.log('[INTRO Popup] Brak konfiguracji WordPress - używam domyślnych wartości');
        }
        
        // DEBUG - sprawdzenie logo
        window.PS_DEBUG&&console.log('[INTRO Popup] Logo InPost:', adminConfig.logoInpost);
        window.PS_DEBUG&&console.log('[INTRO Popup] Logo Sklep:', adminConfig.logoShop);
    }

    // ====================
    // TWORZENIE HTML POPUPU
    // STATUS: ✅ DZIAŁA - Generuje pełną strukturę HTML modal popup
    // ZAWIERA: Header z logo, flagi krajów, instrukcje, mapa, search, footer
    // LOGO SYSTEM: Obsługuje logoSwap (zamiana miejsc), fallback obrazy
    // GRADIENT BACKGROUND: Żółto-pomarańczowy gradient w headerze instrukcji
    // ====================
    function createPopupHTML() {
        // Sprawdzenie czy popup już istnieje
        if (document.getElementById('inpost-universal-popup')) {
            window.PS_DEBUG&&console.log('[INTRO Popup] Popup już istnieje');
            return;
        }

        window.PS_DEBUG&&console.log('[INTRO Popup] Tworzenie struktury HTML popup');

        // Sprawdzenie czy swap logo
        const logoSwap = adminConfig.logoSwap || adminConfig.logo_swap || false;
        
        // DEBUG - sprawdzenie wartości
        window.PS_DEBUG&&console.log('[INTRO Popup] adminConfig.logoInpost:', adminConfig.logoInpost);
        window.PS_DEBUG&&console.log('[INTRO Popup] adminConfig.logoShop:', adminConfig.logoShop);
        window.PS_DEBUG&&console.log('[INTRO Popup] logoSwap:', logoSwap);

        const logoLeftContent = logoSwap ?
            (adminConfig.logoShop ? `<img src="${adminConfig.logoShop}" alt="Sklep" class="shop-logo-img">` : '') :
            (adminConfig.logoInpost ? `<img src="${adminConfig.logoInpost}" alt="InPost" class="inpost-logo-img">` : '');

        const logoRightContent = logoSwap ?
            (adminConfig.logoInpost ? `<img src="${adminConfig.logoInpost}" alt="InPost" class="inpost-logo-img">` : '') :
            (adminConfig.logoShop ? `<img src="${adminConfig.logoShop}" alt="Sklep" class="shop-logo-img">` : '');

        const popupHTML = `
            <!-- UNIWERSALNY POPUP INPOST -->
            <div class="inpost-popup-overlay" id="inpost-universal-popup" style="display: none;">
                <div class="inpost-popup-container" id="inpostPopupContainer">
                    
                    <!-- HEADER Z LOGO I FLAGAMI -->
                    <div class="inpost-popup-header">
                        <!-- GÓRNY WIERSZ: Logo + Flagi + Logo + Zamknij -->
                        <div class="inpost-popup-header-top">
                            <!-- LOGO LEWY (dynamiczny - może być InPost lub Sklep) -->
                            <div class="inpost-popup-logo-left">
                                ${logoLeftContent}
                            </div>
                            
                             <!-- FLAGI KRAJÓW (Centrum) -->
                             <div class="inpost-popup-flags-container">
                                 <button class="ps-flag-arrow left" onclick="IntroPopup.scrollFlags(-100)">&#10094;</button>
                                 <div class="inpost-popup-flags" id="inpostCountryFlags">
                                     ${adminConfig.enabledCountries.filter(code => COUNTRIES[code]).map(code => {
                                         const country = COUNTRIES[code];
                                         return `
                                             <button class="inpost-flag-btn ${code === currentCountry ? 'active' : ''}" 
                                                     data-country="${code}" 
                                                     title="${country.name}"
                                                     onclick="IntroPopup.switchCountry('${code}')">
                                                 ${getFlagSvg(code)}
                                             </button>
                                         `;
                                     }).join('')}
                                 </div>
                                 <button class="ps-flag-arrow right" onclick="IntroPopup.scrollFlags(100)">&#10095;</button>
                             </div>
                            
                            <!-- LOGO PRAWY (dynamiczny - może być Sklep lub InPost) + PRZYCISK ZAMKNIJ -->
                            <div class="inpost-popup-logo-right">
                                ${logoRightContent}
                                <!-- PRZYCISK ZAMKNIJ -->
                                <button class="inpost-popup-close" onclick="IntroPopup.close()">&times;</button>
                            </div>
                        </div>
                        
                        <!-- DOLNY WIERSZ: Flaga + Instrukcje (nazwa kraju opcjonalna) -->
                        <div class="inpost-popup-header-bottom">
                            <div class="inpost-popup-instructions-row" id="inpostPopupInstructions">
                                <span class="instructions-flag">${getFlagSvg(currentCountry)}</span>
                                ${adminConfig.showCountryName ? `<span class="instructions-country">${COUNTRIES[currentCountry].name}</span>` : ''}
                                <span class="instructions-text">${getInstructionsForCountry(currentCountry)}</span>
                            </div>
                        </div>
                    </div>
                    
                    <!-- GŁÓWNA TREŚĆ -->
                    <div class="inpost-popup-body">
                        <!-- SIDEBAR -->
                        <div class="inpost-popup-sidebar">
                            <!-- WYSZUKIWARKA -->
                            <div class="inpost-search-box">
                                <input type="text" 
                                       id="inpostSearchInput" 
                                       class="inpost-search-input" 
                                       placeholder="${getTranslation('searchPlaceholder')}"
                                       autocomplete="off"
                                       autofocus
                                       oninput="IntroPopup.search(this.value)">
                                <div class="inpost-map-status" id="inpostMapStatus" style="display:none;">
                                    <span class="map-spinner"></span>
                                    <span class="map-status-text">Aktualizacja mapy...</span>
                                </div>
                            </div>
                            
                            <!-- LISTA PUNKTÓW -->
                            <div class="inpost-points-list" id="inpostPointsList">
                                <div class="loading-spinner">Ładowanie punktów...</div>
                            </div>
                        </div>
                        
                        <!-- MAPA -->
                        <div class="inpost-popup-map-container">
                            <div id="inpostMap" class="inpost-map"></div>
                            <!-- Floating Lupa - Restore search panel on mobile -->
                            <button class="ps-mobile-restore-search" onclick="IntroPopup.restoreSearchPanel()">&#128269;</button>
                        </div>
                    </div>
                    
                    <!-- FOOTER -->
                    <div class="inpost-popup-footer">
                        <!-- STATYSTYKI NA DOLE -->
                        <div class="inpost-stats">
                            <div class="inpost-stat">
                                <span class="stat-label">${getTranslation('foundPoints')}</span>
                                <span class="stat-value" id="inpostPointsCount">0</span>
                            </div>
                            <div class="inpost-stat">
                                <span class="stat-label">${getTranslation('status')}</span>
                                <span class="stat-value" id="inpostLoadStatus">${getTranslation('loading')}</span>
                            </div>
                            <div class="inpost-stat">
                                <span class="stat-label">🔍 Wyszukiwarka</span>
                                <span class="stat-value" id="inpostSearchEngine" style="font-size:11px;">⏳</span>
                            </div>
                        </div>

                        <!-- ⚡ PERFORMANCE TIMING - czasy ładowania + live timer -->
                        <div id="inpostPerformanceTiming" style="font-size:10px;color:#666;padding:4px 8px;border-top:1px solid #eee;display:block;">
                            <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:2px;">
                                <span style="font-weight:600;">⚡ Performance:</span>
                                <span id="inpostLiveTimer" style="font-family:monospace;font-size:11px;font-weight:700;color:#FF6600;letter-spacing:0.5px;">0.0s</span>
                            </div>
                            <div id="inpostTimingDetails" style="display:grid;grid-template-columns:auto 1fr;gap:2px 8px;font-family:monospace;"></div>
                        </div>

                        <!-- Version info (no attribution link — WP.org Guideline 10) -->
                        <div class="inpost-footer-version" style="text-align:right;font-size:11px;color:#999;padding:4px 8px;">
                            ParcelSelector.com ver 3.0.9
                        </div>
                    </div>
                </div>
            </div>
        `;

        // Dodanie do kontenera root lub body
        const root = document.getElementById('ps-popup-root') || document.body;
        root.insertAdjacentHTML('beforeend', popupHTML);
        window.PS_DEBUG&&console.log('[INTRO Popup] Struktura HTML utworzona w kontenerze:', root.id || 'body');
    }

    // ====================
    // POBIERANIE INSTRUKCJI DLA KRAJU
    // STATUS: ✅ DZIAŁA - Zwraca instrukcje z priorytetem
    // PRIORYTET: adminConfig.customInstructions[kraj] > COUNTRIES[kraj].instructions
    // UŻYCIE: updateHeaderForCountry() używa tej funkcji przy zmianie kraju
    // ====================
    function getInstructionsForCountry(countryCode) {
        const country = COUNTRIES[countryCode];
        if (!country) return '';
        
        // 1. Priorytet: Niestandardowa instrukcja z adminConfig
        if (adminConfig.customInstructions && adminConfig.customInstructions[countryCode]) {
            return adminConfig.customInstructions[countryCode];
        }
        
        // 2. Domyślna instrukcja z obiektu COUNTRIES (multijęzyczna)
        return country.instructions || '';
    }

    // ====================
    // PERFORMANCE TIMING - UPDATE DISPLAY
    // ====================
    function updatePerformanceTiming() {
        const timingEl = document.getElementById('inpostPerformanceTiming');
        const detailsEl = document.getElementById('inpostTimingDetails');

        if (!timingEl || !detailsEl) return;

        // Oblicz czasy względne (od otwarcia popupu)
        const start = performanceTiming.popupOpened;
        if (!start) return;

        const timings = [];

        if (performanceTiming.mapInitialized) {
            const time = ((performanceTiming.mapInitialized - start) / 1000).toFixed(3);
            timings.push({ label: '🗺️ Mapa:', value: `${time}s` });
        }

        if (performanceTiming.pointsLoaded) {
            const time = ((performanceTiming.pointsLoaded - start) / 1000).toFixed(3);
            timings.push({ label: '📦 Punkty:', value: `${time}s` });
        }

        if (performanceTiming.markersRendered) {
            const time = ((performanceTiming.markersRendered - start) / 1000).toFixed(3);
            timings.push({ label: '📍 Markery:', value: `${time}s` });
        }

        if (performanceTiming.pointSelected) {
            const time = ((performanceTiming.pointSelected - start) / 1000).toFixed(3);
            timings.push({ label: '👆 Wybór:', value: `${time}s` });
        }

        if (performanceTiming.confirmed) {
            const time = ((performanceTiming.confirmed - start) / 1000).toFixed(3);
            timings.push({ label: '✅ Potw:', value: `${time}s`, highlight: true });
        }

        if (timings.length > 0) {
            detailsEl.innerHTML = timings.map(t =>
                `<span style="${t.highlight ? 'font-weight:bold;color:#10b981;' : ''}">${t.label}</span>` +
                `<span style="${t.highlight ? 'font-weight:bold;color:#10b981;' : ''}">${t.value}</span>`
            ).join('');
            timingEl.style.display = 'block';
        }

        window.PS_DEBUG&&console.log('[INTRO Popup] ⏱️ Performance Timing:', timings.map(t => `${t.label} ${t.value}`).join(', '));
    }

    // ====================
    // OTWARCIE POPUPU
    // FIX 2026-01-19: 🎯 AUTOFOCUS przy otwarciu - kursor od razu w wyszukiwarce
    // ====================
    function openMapPopup(countryCode) {
        window.PS_DEBUG&&console.log('[INTRO Popup] Otwieranie popupu dla kraju:', countryCode);

        // ⏱️ START TIMING
        performanceTiming.popupOpened = performance.now();
        performanceTiming.mapInitialized = null;
        performanceTiming.pointsLoaded = null;
        performanceTiming.markersRendered = null;
        performanceTiming.pointSelected = null;
        performanceTiming.confirmed = null;
        
        // Ustawienie aktywnego kraju
        currentCountry = countryCode || 'pl';
        
        // Utworzenie HTML jeśli nie istnieje
        createPopupHTML();
        
        // Aktualizacja interfejsu
        updateHeaderForCountry(currentCountry);
        
        // Pokazanie popupu
        const popup = document.getElementById('inpost-universal-popup');
        popup.style.display = 'flex';

        // Zablokowanie scrolla body
        document.body.style.overflow = 'hidden';

        // ⏱️ Performance timer – czas od otwarcia mapy (live counter w footerze)
        window._inpostMapOpenTime = performance.now();
        window._inpostSelectionTime = null; // reset poprzedniego wyboru

        // Uruchom live timer w footerze (tyka co 100ms)
        if (window._inpostLiveTimerInterval) {
            clearInterval(window._inpostLiveTimerInterval);
        }
        window._inpostLiveTimerInterval = setInterval(function() {
            var el = document.getElementById('inpostLiveTimer');
            if (!el) { clearInterval(window._inpostLiveTimerInterval); return; }
            var elapsed = (performance.now() - window._inpostMapOpenTime) / 1000;
            if (window._inpostSelectionTime) {
                // Po wyborze – pokaż czas do wyboru (zamrożony) + etykieta
                var sel = (window._inpostSelectionTime - window._inpostMapOpenTime) / 1000;
                el.textContent = sel.toFixed(1) + 's';
                el.style.color = '#10b981';
                el.title = 'Czas od otwarcia mapy do wyboru paczkomatu';
            } else {
                el.textContent = elapsed.toFixed(1) + 's';
                el.style.color = elapsed > 30 ? '#ef4444' : elapsed > 15 ? '#f59e0b' : '#FF6600';
                el.title = 'Czas od otwarcia mapy';
            }
        }, 100);

        // 🔄 Reset wyboru paczkomatu przy każdym nowym otwarciu mapy
        // (np. kliknięcie "Zmień paczkomat" z poziomu checkout otwiera mapę od nowa)
        if (typeof ParcelLockerSelector !== 'undefined') {
            // Anuluj wszystkie oczekujące timery z poprzedniej sesji (displaySuccessPanel, ps-selection-mode)
            if (ParcelLockerSelector._pendingTimers && ParcelLockerSelector._pendingTimers.length) {
                ParcelLockerSelector._pendingTimers.forEach(function(t) { clearTimeout(t); });
                ParcelLockerSelector._pendingTimers = [];
            }

            ParcelLockerSelector.selectedLocker = null;

            if (ParcelLockerSelector._countdownInterval) {
                clearInterval(ParcelLockerSelector._countdownInterval);
                ParcelLockerSelector._countdownInterval = null;
            }
            if (ParcelLockerSelector._stopwatchInterval) {
                clearInterval(ParcelLockerSelector._stopwatchInterval);
                ParcelLockerSelector._stopwatchInterval = null;
            }
        }

        // Usuń ps-selection-mode z poprzedniej sesji + wyczyść wizualne zaznaczenie
        var _popupEl = document.getElementById('inpost-universal-popup');
        if (_popupEl) _popupEl.classList.remove('ps-selection-mode');
        document.querySelectorAll('.inpost-point-item.selected-item').forEach(function(el) {
            el.classList.remove('selected-item');
        });
        document.querySelectorAll('.list-checkbox.checked').forEach(function(el) {
            el.classList.remove('checked');
            var icon = el.querySelector('.checkbox-icon');
            if (icon) icon.textContent = '\u2610'; // unchecked box
        });

        // 🎬 SIDEBAR SLIDE-IN: ukryj sidebar, po 200ms mapa widoczna, po 800ms wjedź z lewej
        const sidebar = document.querySelector('.inpost-popup-sidebar');
        if (sidebar && !FAST_MODE) {
            sidebar.classList.add('sidebar-hidden');
            sidebar.style.transition = 'none';
            setTimeout(function() {
                sidebar.style.transition = '';
                sidebar.classList.remove('sidebar-hidden');
                sidebar.classList.add('sidebar-visible');
                setTimeout(function() {
                    sidebar.classList.remove('sidebar-visible');
                }, 700);
            }, 800);
        }

        // 🎵 DO-RE-MI: Animacja flag – CZYSTY CSS, niezależny od JS thread
        // Jeden requestAnimationFrame żeby popup był wyrenderowany, potem CSS rządzi całym timingiem.
        // Nie blokuje się przy ładowaniu punktów ani renderowaniu mapy.
        requestAnimationFrame(() => {
            const flagsWrap = document.querySelector('.inpost-popup-flags');
            if (flagsWrap) {
                flagsWrap.classList.add('flags-wave-init');
                // Usuń klasę po zakończeniu ostatniej animacji (13 × 130ms + 650ms = ~2350ms)
                setTimeout(() => flagsWrap.classList.remove('flags-wave-init'), 2500);
            }
        });
        
        // 🎹 KEYBOARD NAVIGATION
        setupKeyboardNavigation();
        
        // 🎯 FIX: AUTOFOCUS - Kursor automatycznie w wyszukiwarce przy otwarciu
        const autofocusDelay = FAST_MODE ? 0 : 400;
        setTimeout(() => {
            const searchInput = document.getElementById('inpostSearchInput');
            if (searchInput) {
                searchInput.focus();
                window.PS_DEBUG&&console.log('[INTRO Popup] ✅ Autofocus do wyszukiwarki' + (FAST_MODE ? ' (FAST MODE - instant)' : ''));
            }
        }, autofocusDelay);
        
        // Inicjalizacja mapy (jeśli jeszcze nie istnieje)
        const initDelay = FAST_MODE ? 0 : 150;
        setTimeout(() => {
            if (!map) {
                initializeMap();
            } else {
                // Przeładowanie dla nowego kraju
                loadPointsForCountry(currentCountry);
            }
        }, initDelay);
    }
    
    // ====================
    // KEYBOARD NAVIGATION - ESC, Arrow keys
    // ====================
    let keyboardHandler = null;
    
    function setupKeyboardNavigation() {
        // Usuń poprzedni handler jeśli istnieje
        if (keyboardHandler) {
            document.removeEventListener('keydown', keyboardHandler);
        }
        
        keyboardHandler = function(e) {
            const popup = document.getElementById('inpost-universal-popup');
            if (!popup || popup.style.display === 'none') return;
            
            // ESC - zamknij popup
            if (e.key === 'Escape') {
                closePopup();
                e.preventDefault();
                return;
            }
            
            // Arrow keys - nawigacja po liście
            const activeItem = document.querySelector('.inpost-point-item.active');
            const allItems = Array.from(document.querySelectorAll('.inpost-point-item'));
            
            if (allItems.length === 0) return;
            
            if (e.key === 'ArrowDown') {
                e.preventDefault();
                if (!activeItem) {
                    // Zaznacz pierwszy
                    allItems[0].click();
                } else {
                    const currentIndex = allItems.indexOf(activeItem);
                    if (currentIndex < allItems.length - 1) {
                        allItems[currentIndex + 1].click();
                    }
                }
            } else if (e.key === 'ArrowUp') {
                e.preventDefault();
                if (!activeItem) {
                    // Zaznacz ostatni
                    allItems[allItems.length - 1].click();
                } else {
                    const currentIndex = allItems.indexOf(activeItem);
                    if (currentIndex > 0) {
                        allItems[currentIndex - 1].click();
                    }
                }
            } else if (e.key === 'Enter') {
                // Enter - wybierz aktywny punkt
                if (activeItem && selectedPoint) {
                    confirmSelectPoint();
                }
            }
        };
        
        document.addEventListener('keydown', keyboardHandler);
    }

    // ====================
    // ZAMKNIĘCIE POPUPU - INTRO VERSION
    // STATUS: ✅ POPRAWIONE - COMPLETE CLEANUP
    // FIXES:
    // - Całkowite usunięcie popup z DOM (nie tylko display:none)
    // - Usunięcie wszystkich overlay/iframe/modal elementów
    // - Czyszczenie event listenerów
    // - Przywracanie scroll
    // - Cleanup map instance
    // ISSUE FIXED: Overlay pozostający na stronie po zamknięciu
    // ====================
    function closePopup() {
        window.PS_DEBUG&&console.log('[INTRO Popup] 🚀 Rozpoczynam COMPLETE CLEANUP...');

        // Zatrzymaj live timer
        if (window._inpostLiveTimerInterval) {
            clearInterval(window._inpostLiveTimerInterval);
            window._inpostLiveTimerInterval = null;
        }

        // 1. USUŃ POPUP Z DOM NATYCHMIAST — użytkownik widzi zamknięcie od razu
        const popup = document.getElementById('inpost-universal-popup');
        if (popup) {
            popup.remove();
            window.PS_DEBUG&&console.log('[INTRO Popup] Usunięto główny popup z DOM (natychmiast)');
        }

        // 2. ANULUJ WSZYSTKIE PENDING TIMEOUTY (Epic Zoom, animacje etc.)
        cancelAllPendingTimeouts();

        // 3. ZNISZCZ MAP INSTANCE (w tle — użytkownik już nie widzi loadingu)
        if (map) {
            try {
                markers.forEach(marker => {
                    try { map.removeLayer(marker); } catch(e) {}
                    marker.pointData = null;
                });
                markers = [];
                if (_customPickupMarker) { try { _customPickupMarker.remove(); } catch(e) {} _customPickupMarker = null; }
                map.remove();
                window.PS_DEBUG&&console.log('[INTRO Popup] Zniszczono map instance');
            } catch (e) {
                window.PS_DEBUG&&console.warn('[INTRO Popup] Nie można zniszczyć mapy:', e);
            }
            map = null;
        }

        // 4. USUŃ WSZYSTKIE DETALE MODALS
        document.querySelectorAll('.inpost-detail-modal-overlay').forEach(modal => {
            modal.remove();
        });

        // 5. USUŃ WSZYSTKIE SUCCESS PANELS
        document.querySelectorAll('.inpost-success-overlay').forEach(panel => {
            panel.remove();
        });

        // 6. USUŃ WSZYSTKIE IFRAMES (jeśli istnieją)
        document.querySelectorAll('iframe[id*="inpost"], iframe[src*="ENTRANCE"]').forEach(iframe => {
            iframe.remove();
        });

        // 7. USUŃ WSZYSTKIE OVERLAY ELEMENTY
        document.querySelectorAll('[class*="inpost-"][class*="overlay"], [id*="inpost"][id*="overlay"]').forEach(overlay => {
            overlay.remove();
        });

        // 8. PRZYWRÓĆ SCROLL
        document.body.style.overflow = '';
        document.body.style.position = '';
        document.body.style.width = '';
        document.documentElement.style.overflow = '';

        // 9. USUŃ KEYBOARD HANDLER
        if (keyboardHandler) {
            document.removeEventListener('keydown', keyboardHandler);
            keyboardHandler = null;
        }

        // 10. RESET STANU
        selectedPoint = null;
        if (window.lastSearchType !== undefined) {
            delete window.lastSearchType;
        }

        window.PS_DEBUG&&console.log('[INTRO Popup] ✅ COMPLETE CLEANUP ZAKOŃCZONY');

        // 11. POWRÓT DO WORDPRESS (jeśli punkt został wybrany)
        if (typeof window.ParcelLockerSelector !== 'undefined' &&
            window.ParcelLockerSelector.getSelectedLocker()) {
            window.PS_DEBUG&&console.log('[INTRO Popup] Paczkomat wybrany - scroll do formularza');
            setTimeout(() => {
                const checkoutForm = document.querySelector('form.checkout, form.woocommerce-checkout, .woocommerce-checkout');
                if (checkoutForm) {
                    checkoutForm.scrollIntoView({ behavior: 'smooth', block: 'start' });
                }
            }, 100);
        }
    }

    // ====================
    // PRZEŁĄCZANIE KRAJU
    // STATUS: ✅ DZIAŁA - Zmienia kraj po kliknięciu flagi
    // WYWŁUJE: updateHeaderForCountry(), updateCountryFlags(), loadPointsForCountry()
    // RESETUJE: Pole wyszukiwania (clear value)
    // UŻYCIE: onclick="IntroPopup.switchCountry('pl')" na fladze
    // FIX 2026-01-19: 🎯 AUTOFOCUS - Kursor automatycznie przeskakuje do wyszukiwarki po kliknięciu flagi
    // ====================
    function switchCountry(countryCode) {
        window.PS_DEBUG&&console.log('[INTRO Popup] Przełączanie na kraj:', countryCode);
        
        if (!COUNTRIES[countryCode]) {
            window.PS_DEBUG&&console.error('[INTRO Popup] Nieznany kod kraju:', countryCode);
            return;
        }
        
        // 🔥 CZYSZCZENIE PAMIĘCI - usuń dane poprzedniego kraju
        window.PS_DEBUG&&console.log('[INTRO Popup] Czyszczenie pamięci przed załadowaniem nowego kraju...');
        allPoints = [];
        filteredPoints = [];
        displayedPoints = [];
        // ✅ BEZWZGLĘDNE czyszczenie historii kliknięć przy zmianie kraju
        clickedPointsHistory = [];
        selectedPoint = null;

        // 🧹 Resetuj stan wyboru paczkomatu (czyści ps-selection-mode, sidebar, footer)
        if (typeof ParcelLockerSelector !== 'undefined' && ParcelLockerSelector.selectedLocker) {
            ParcelLockerSelector.clearSelection();
        }
        window.PS_DEBUG&&console.log('[INTRO Popup] Historia kliknięć wyczyszczona (zmiana kraju)');
        if (map && markers.length > 0) {
            clearMarkers();
        }
        // Anuluj pending timeouty z poprzedniego kraju (np. Epic Zoom animacja)
        cancelAllPendingTimeouts();

        // ======================================================================
        // 🧹 FIX 2026-03-03: NATYCHMIASTOWE CZYSZCZENIE UI PRZY ZMIANIE KRAJU
        // Użytkownik klika flagę → wszystko z poprzedniego kraju MUSI zniknąć
        // ======================================================================
        
        // 1. USUŃ formularz danych klienta (jeśli był widoczny)
        const customerForm = document.getElementById('inpostCustomerForm');
        if (customerForm) {
            customerForm.remove();
            window.PS_DEBUG&&console.log('[INTRO Popup] 🧹 Formularz danych klienta usunięty (zmiana kraju)');
        }
        
        // 2. ZAMKNIJ modal szczegółów punktu (jeśli był otwarty)
        const detailModal = document.getElementById('inpostDetailModal');
        if (detailModal) {
            detailModal.remove();
            window.PS_DEBUG&&console.log('[INTRO Popup] 🧹 Modal szczegółów zamknięty (zmiana kraju)');
        }
        
        // 3. PRZYWRÓĆ wyszukiwarkę i listę punktów (mogły być ukryte przez hideListShowForm)
        const pointsList = document.getElementById('inpostPointsList');
        const searchContainer = document.querySelector('.inpost-search-container');
        if (pointsList) pointsList.style.display = 'block';
        if (searchContainer) searchContainer.style.display = 'block';
        
        // 4. WYCZYŚĆ dane klienta z window globals (stare dane z poprzedniego kraju)
        if (window.inpostCustomerData) {
            delete window.inpostCustomerData;
            window.PS_DEBUG&&console.log('[INTRO Popup] 🧹 window.inpostCustomerData wyczyszczone');
        }
        
        // 5. WYCZYŚĆ pola WooCommerce checkout (natychmiast, bez czekania)
        clearWooCommerceCheckoutFields();
        
        // 6. WYCZYŚĆ listę punktów w DOM (stara lista z poprzedniego kraju)
        if (pointsList) {
            pointsList.innerHTML = '';
        }
        
        // ======================================================================
        
        // Aktualizacja stanu
        currentCountry = countryCode;

        // Aktualizacja UI
        updateHeaderForCountry(countryCode);
        updateCountryFlags(countryCode);

        // 🎵 POTWIERDZENIE KLIKNIĘCIA: dyndnięcie wybranej flagi
        setTimeout(() => {
            const activeBtn = document.querySelector(`.inpost-flag-btn[data-country="${countryCode}"]`);
            if (activeBtn) {
                activeBtn.classList.add('wave-confirm');
                activeBtn.addEventListener('animationend', () => activeBtn.classList.remove('wave-confirm'), { once: true });
            }
        }, 80);

        // ✅ AKTUALIZACJA TŁUMACZEŃ UI (footer stats, wyszukiwarka, loader)
        updateUITranslations();
        window.PS_DEBUG&&console.log('[INTRO Popup] Tłumaczenia zaktualizowane dla:', countryCode.toUpperCase());
        
        // 🎬 EPIC ZOOM przy zmianie kraju (jeśli włączony)
        const epicZoomEnabled = window.parcselectCacheConfig && window.parcselectCacheConfig.epicZoomEnabled;
        if (epicZoomEnabled && map) {
            window.PS_DEBUG&&console.log('[INTRO Popup] 🎬 Epic Zoom przy zmianie kraju na:', countryCode);
            startEpicZoomAnimation(countryCode); // Uruchom animację Epic Zoom
        } else {
            // Zwykły zoom bez animacji
            const country = COUNTRIES[countryCode];
            if (map) {
                map.setView(country.center, country.zoom);
            }
            loadPointsForCountry(countryCode);
        }
        
        // Reset wyszukiwarki
        const searchInput = document.getElementById('inpostSearchInput');
        searchInput.value = '';
        
        // 🎯 FIX: AUTOFOCUS - Kursor przeskakuje do wyszukiwarki i miga
        setTimeout(() => {
            searchInput.focus();
            window.PS_DEBUG&&console.log('[INTRO Popup] ✅ Autofocus do wyszukiwarki po zmianie kraju');
        }, 300);
    }

    // ====================
    // AKTUALIZACJA HEADERA DLA KRAJU
    // STATUS: ✅ DZIAŁA - Dynamiczna zmiana flagi, nazwy kraju i instrukcji
    // UŻYWANE PRZEZ: switchCountry() przy kliknięciu flagi
    // REGENERUJE: Cały HTML wiersza instrukcji z SVG flagą
    // ZMIENIA: Kolor lewego bordera headera (country.color)
    // ====================
    function updateHeaderForCountry(countryCode) {
        const country = COUNTRIES[countryCode];
        
        // Aktualizacja całego wiersza instrukcji (nowy compact layout z SVG flagą)
        const instructionsRow = document.getElementById('inpostPopupInstructions');
        if (instructionsRow) {
            instructionsRow.innerHTML = `
                <span class="instructions-flag">${getFlagSvg(countryCode)}</span>
                ${adminConfig.showCountryName ? `<span class="instructions-country">${country.name}</span>` : ''}
                <span class="instructions-text">${getInstructionsForCountry(countryCode)}</span>
            `;
        }
        
        // Aktualizacja koloru headera
        const header = document.querySelector('.inpost-popup-header');
        if (header) {
            header.style.borderLeftColor = country.color;
        }
    }

    // ====================
    // AKTUALIZACJA FLAG
    // ====================
    function updateCountryFlags(activeCountry) {
        const flags = document.querySelectorAll('.inpost-flag-btn');
        flags.forEach(flag => {
            const code = flag.getAttribute('data-country');
            if (code === activeCountry) {
                flag.classList.add('active');
            } else {
                flag.classList.remove('active');
            }
        });
    }

    // ====================================================================================
    // EPIC ZOOM ANIMATION - Start animacji (używane przy zmianie kraju)
    // ====================================================================================
    function startEpicZoomAnimation(countryCode) {
        if (!map) {
            window.PS_DEBUG&&console.error('[INTRO Popup] Map nie istnieje - nie można uruchomić Epic Zoom');
            return;
        }
        
        const country = COUNTRIES[countryCode];
        window.PS_DEBUG&&console.log('[INTRO Popup] 🎬 Uruchamiam Epic Zoom animation dla:', countryCode.toUpperCase());
        
        // Usuń stare pulse circles jeśli istnieją
        const oldOverlay = document.getElementById('epicZoomPulseOverlay');
        if (oldOverlay) {
            oldOverlay.remove();
            window.PS_DEBUG&&console.log('[INTRO Popup] 🗑️ Usunięto stary pulse overlay');
        }
        
        // KLUCZOWE: Mapa zaczyna WYCENTROWANA NA KRAJU z ZOOM 7 (bardzo blisko!)
        // Potem zoom OUT do Europy, potem zoom IN do kraju - pulse ZAWSZE w centrum!
        map.setView(country.center, 7); // Centrum NA KRAJU, zoom 7 (BARDZO blisko)
        window.PS_DEBUG&&console.log('[INTRO Popup] 🎯 Widok wycentrowany NA KRAJU:', country.center, 'zoom: 7 (BARDZO blisko)');
        
        // 🟡 CSS OVERLAY - ZAWSZE W CENTRUM EKRANU (nie Leaflet circle!)
        const mapContainer = document.getElementById('inpostMap');
        const pulseOverlay = document.createElement('div');
        pulseOverlay.id = 'epicZoomPulseOverlay';
        pulseOverlay.className = 'epic-zoom-pulse-overlay';
        pulseOverlay.innerHTML = `
            <div class="epic-zoom-pulse-circle"></div>
            <div class="epic-zoom-pulse-echo1"></div>
            <div class="epic-zoom-pulse-echo2"></div>
            <div class="epic-zoom-pulse-echo3"></div>
        `;
        mapContainer.appendChild(pulseOverlay);
        window.PS_DEBUG&&console.log('[INTRO Popup] 🟡 CSS Pulse overlay dodany - ZAWSZE w centrum ekranu!');
        
        // 🚀 START ŁADOWANIA PUNKTÓW ASAP
        loadPointsForCountry(countryCode, null);
        
        // 🎬 5-STOPNIOWA ANIMACJA (Przyspieszona v3.1.7: ~2s zamiast 6s)
        // ✅ safeTimeout - anulowane automatycznie przy closePopup()
        safeTimeout(() => {
            if (!map) return;
            map.flyTo(country.center, 6, { duration: 0.4, easeLinearity: 0.1 });
            window.PS_DEBUG&&console.log('[INTRO Popup] 🎬 Krok 1: Zoom OUT 7→6');
            safeTimeout(() => {
                if (!map) return;
                map.flyTo(country.center, 5, { duration: 0.4, easeLinearity: 0.15 });
                window.PS_DEBUG&&console.log('[INTRO Popup] 🎬 Krok 2: Zoom OUT 6→5');
                safeTimeout(() => {
                    if (!map) return;
                    map.flyTo(country.center, 4, { duration: 0.5, easeLinearity: 0.2 });
                    window.PS_DEBUG&&console.log('[INTRO Popup] 🎬 Krok 3: Zoom OUT 5→4 (szeroka Europa)');
                    safeTimeout(() => {
                        if (!map) return;
                        map.flyTo(country.center, 5, { duration: 0.4, easeLinearity: 0.25 });
                        window.PS_DEBUG&&console.log('[INTRO Popup] 🎬 Krok 4: Zoom IN 4→5');
                        safeTimeout(() => {
                            if (!map) return;
                            map.flyTo(country.center, country.zoom, { duration: 0.5, easeLinearity: 0.3 });
                            window.PS_DEBUG&&console.log('[INTRO Popup] 🎬 Krok 5: Zoom IN 5→', country.zoom, '(FINAL)');
                            currentZoomLevel = country.zoom;

                            safeTimeout(() => {
                                const pulseOverlay = document.getElementById('epicZoomPulseOverlay');
                                if (pulseOverlay) {
                                    pulseOverlay.remove();
                                    window.PS_DEBUG&&console.log('[INTRO Popup] 🟡 CSS Pulse overlay usunięty po animacji');
                                }
                            }, 400);
                        }, 500);
                    }, 500);
                }, 600);
            }, 500);
        }, 300);
    }

    // ====================
    // INICJALIZACJA MAPY LEAFLET
    // ====================
    function initializeMap() {
        window.PS_DEBUG&&console.log('%c[INTRO MAP] ═══ INICJALIZACJA MAPY LEAFLET ═══', 'color: #2196F3; font-weight: bold');
        const mapInitStart = performance.now();

        // ═══ PRE-FLIGHT CHECK ═══
        // 1. Leaflet dostępny?
        if (typeof L === 'undefined' || typeof L.map !== 'function') {
            window.PS_DEBUG&&console.error('[INTRO MAP] ❌ KRYTYCZNY: Leaflet.js NIE JEST ZAŁADOWANY! Mapa nie może wystartować.');
            return;
        }
        window.PS_DEBUG&&console.log('[INTRO MAP] ✅ Leaflet:', L.version);

        // 2. Kontener DOM istnieje?
        const mapContainer = document.getElementById('inpostMap');
        if (!mapContainer) {
            window.PS_DEBUG&&console.error('[INTRO MAP] ❌ KRYTYCZNY: Brak kontenera #inpostMap w DOM!');
            return;
        }
        const containerSize = mapContainer.getBoundingClientRect();
        window.PS_DEBUG&&console.log('[INTRO MAP] ✅ Kontener #inpostMap:', Math.round(containerSize.width) + 'x' + Math.round(containerSize.height) + 'px');
        if (containerSize.width === 0 || containerSize.height === 0) {
            window.PS_DEBUG&&console.warn('[INTRO MAP] ⚠️ Kontener ma zerowe wymiary! Mapa może być niewidoczna.');
        }

        // 3. Kraj prawidłowy?
        const country = COUNTRIES[currentCountry];
        if (!country) {
            window.PS_DEBUG&&console.error('[INTRO MAP] ❌ KRYTYCZNY: Nieznany kraj:', currentCountry);
            return;
        }
        window.PS_DEBUG&&console.log('[INTRO MAP] Kraj:', currentCountry.toUpperCase(), '(' + country.name + '), centrum:', country.center, ', zoom:', country.zoom);

        // 4. Źródło danych
        const cacheEnabled = window.parcselectCacheConfig && window.parcselectCacheConfig.enabled === true;
        const countryMode = window.parcselectCacheConfig && window.parcselectCacheConfig.countryModes
            ? window.parcselectCacheConfig.countryModes[currentCountry] : 'api';
        const dataSource = (cacheEnabled && countryMode === 'local') ? 'LOKALNE API' : 'ZEWNĘTRZNE parcelselector.com API';
        window.PS_DEBUG&&console.log('[INTRO MAP] Źródło danych:', dataSource, '(cache:', cacheEnabled ? 'ON' : 'OFF', ', mode:', countryMode, ')');

        // 5. Jeśli mapa już istnieje (reopen), zniszcz ją najpierw
        if (map) {
            window.PS_DEBUG&&console.log('[INTRO MAP] Poprzednia instancja mapy istnieje - niszczę...');
            try { map.remove(); } catch(e) {}
            map = null;
        }

        try {
        // Check if Epic Zoom Animation enabled in admin panel
        const epicZoomEnabled = !FAST_MODE && window.parcselectCacheConfig && window.parcselectCacheConfig.epicZoomEnabled;
        window.PS_DEBUG&&console.log('[INTRO Popup] Epic Zoom:', epicZoomEnabled ? 'ENABLED ⚡' : (FAST_MODE ? 'FAST MODE - wyłączony' : 'disabled'));

        if (epicZoomEnabled) {
            window.PS_DEBUG&&console.log('[INTRO Popup] 🌍 Epic Zoom: Start z zoom 6 (kraj widoczny), potem OUT→IN');

            const mapLoader = document.getElementById('inpostMapLoading');
            if (mapLoader) {
                mapLoader.style.display = 'none';
            }

            map = L.map('inpostMap').setView(country.center, 7);
            window.PS_DEBUG&&console.log('[INTRO Popup] 🎯 Mapa wycentrowana NA:', country.name, country.center, 'zoom: 7');

            // Dodanie tiles OpenStreetMap z error handling
            var tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
                attribution: '&copy; OpenStreetMap contributors',
                maxZoom: 19,
                errorTileUrl: '',
                keepBuffer: 4,
                updateWhenIdle: false,
                updateWhenZooming: true,
                crossOrigin: true
            }).addTo(map);
            tileLayer.on('tileerror', function(e) {
                var tile = e.tile;
                var retries = parseInt(tile.dataset.retries || '0', 10);
                if (retries < 3) {
                    tile.dataset.retries = retries + 1;
                    setTimeout(function() { tile.src = tile.src.split('?')[0] + '?r=' + Date.now(); }, 1000 * (retries + 1));
                    window.PS_DEBUG&&console.warn('[INTRO Popup] Tile retry ' + (retries + 1) + '/3:', tile.src);
                } else {
                    window.PS_DEBUG&&console.warn('[INTRO Popup] Tile failed after 3 retries:', tile.src);
                }
            });
            // Fix: invalidateSize po ujawnieniu kontenera — Leaflet musi znać prawdziwy rozmiar
            setTimeout(function() {
                if (map) { map.invalidateSize({ animate: false, pan: false }); }
            }, 250);
            
            // 🟡 CSS OVERLAY - ZAWSZE W CENTRUM EKRANU (nie Leaflet circle!)
            const mapContainer = document.getElementById('inpostMap');
            const pulseOverlay = document.createElement('div');
            pulseOverlay.id = 'epicZoomPulseOverlay';
            pulseOverlay.className = 'epic-zoom-pulse-overlay';
            pulseOverlay.innerHTML = `
                <div class="epic-zoom-pulse-circle"></div>
                <div class="epic-zoom-pulse-echo1"></div>
                <div class="epic-zoom-pulse-echo2"></div>
                <div class="epic-zoom-pulse-echo3"></div>
            `;
            mapContainer.appendChild(pulseOverlay);
            window.PS_DEBUG&&console.log('[INTRO Popup] 🟡 CSS Pulse overlay dodany - ZAWSZE w centrum ekranu!');
            
            // Nasłuchiwanie zoomend dla lazy loading
            if (adminConfig.lazyLoadOnZoom) {
                map.on('zoomend', onMapViewChange);
                window.PS_DEBUG&&console.log('[INTRO Popup] Lazy loading włączony (tylko przy zoomie)');
            }
            
            window.PS_DEBUG&&console.log('[INTRO Popup] 🚫 Viewport culling WYŁĄCZONY (pokazuj wszystkie punkty)');
            
            // 🚀 START ŁADOWANIA PUNKTÓW NATYCHMIAST (ASAP - niezależnie od animacji!)
            window.PS_DEBUG&&console.log('[INTRO Popup] 🚀 Rozpoczynam ładowanie punktów ASAP (niezależnie od animacji)...');
            loadPointsForCountry(currentCountry, null); // NIE przekazujemy pulseCircle - zostaje do końca animacji!
            
            // 🎬 ZOOM ANIMATION: Zoom OUT 7→6→5→4 (Europa), potem Zoom IN 4→5→kraj (6 sekund)
            // ODSEPAROWANE od ładowania punktów - punkty nie czekają!
            // WSZYSTKIE flyTo NA country.center - pulse NIE UCIEKA!
            // ✅ safeTimeout - anulowane automatycznie przy closePopup()
            safeTimeout(() => {
                if (!map) return;
                window.PS_DEBUG&&console.log('[INTRO Popup] 🎯 Krok 1/5: zoom OUT 7 → 6');
                map.flyTo(country.center, 6, { duration: 1.0, easeLinearity: 0.1 });

                safeTimeout(() => {
                    if (!map) return;
                    window.PS_DEBUG&&console.log('[INTRO Popup] 🎯 Krok 2/5: zoom OUT 6 → 5');
                    map.flyTo(country.center, 5, { duration: 1.0, easeLinearity: 0.15 });

                    safeTimeout(() => {
                        if (!map) return;
                        window.PS_DEBUG&&console.log('[INTRO Popup] 🎯 Krok 3/5: zoom OUT 5 → 4 (szeroka Europa)');
                        map.flyTo(country.center, 4, { duration: 1.2, easeLinearity: 0.2 });

                        safeTimeout(() => {
                            if (!map) return;
                            window.PS_DEBUG&&console.log('[INTRO Popup] 🎯 Krok 4/5: zoom IN 4 → 5');
                            map.flyTo(country.center, 5, { duration: 1.0, easeLinearity: 0.25 });

                            safeTimeout(() => {
                                if (!map) return;
                                window.PS_DEBUG&&console.log('[INTRO Popup] 🎯 Krok 5/5: finalny zoom');
                                map.flyTo(country.center, country.zoom, { duration: 1.0, easeLinearity: 0.3 });
                                currentZoomLevel = country.zoom;

                                // Po zakończeniu animacji zoom - usuń pulse overlay
                                safeTimeout(() => {
                                    window.PS_DEBUG&&console.log('[INTRO Popup] ✅ Animacja zoom zakończona (6 sekund)');

                                    const pulseOverlay = document.getElementById('epicZoomPulseOverlay');
                                    if (pulseOverlay) {
                                        pulseOverlay.remove();
                                        window.PS_DEBUG&&console.log('[INTRO Popup] 🟡 CSS Pulse overlay usunięty po animacji');
                                    }
                                }, 800);
                            }, 1200);
                        }, 1200);
                    }, 1200);
                }, 1200);
            }, 400);
            
        } else {
            // ⚡ FAST MODE: Bez animacji, bezpośredni zoom do kraju
            window.PS_DEBUG&&console.log('[INTRO Popup] ⚡ Fast mode: Bez animacji, bezpośredni zoom');

            map = L.map('inpostMap').setView(country.center, country.zoom);

            // Dodanie tiles OpenStreetMap z error handling
            var tileLayer2 = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
                attribution: '&copy; OpenStreetMap contributors',
                maxZoom: 19,
                errorTileUrl: '',
                keepBuffer: 4,
                updateWhenIdle: false,
                updateWhenZooming: true,
                crossOrigin: true
            }).addTo(map);
            tileLayer2.on('tileerror', function(e) {
                var tile = e.tile;
                var retries = parseInt(tile.dataset.retries || '0', 10);
                if (retries < 3) {
                    tile.dataset.retries = retries + 1;
                    setTimeout(function() { tile.src = tile.src.split('?')[0] + '?r=' + Date.now(); }, 1000 * (retries + 1));
                    window.PS_DEBUG&&console.warn('[INTRO Popup] Tile retry ' + (retries + 1) + '/3:', tile.src);
                } else {
                    window.PS_DEBUG&&console.warn('[INTRO Popup] Tile failed after 3 retries:', tile.src);
                }
            });
            // Fix: invalidateSize po ujawnieniu kontenera — Leaflet musi znać prawdziwy rozmiar
            setTimeout(function() {
                if (map) { map.invalidateSize({ animate: false, pan: false }); }
            }, 250);

            if (adminConfig.lazyLoadOnZoom) {
                map.on('zoomend', onMapViewChange);
                window.PS_DEBUG&&console.log('[INTRO Popup] Lazy loading włączony (tylko przy zoomie)');
            }

            window.PS_DEBUG&&console.log('[INTRO Popup] 🚀 Rozpoczynam ładowanie punktów NATYCHMIAST...');
            loadPointsForCountry(currentCountry, null);

            currentZoomLevel = country.zoom;
            window.PS_DEBUG&&console.log('[INTRO Popup] ✅ Mapa zainicjalizowana w FAST MODE');
        }

        // ═══ POST-INIT AUTOTEST ═══
        const mapInitTime = Math.round(performance.now() - mapInitStart);
        window.PS_DEBUG&&console.log('%c[INTRO MAP] ═══ AUTOTEST MAPY ═══', 'color: #4CAF50; font-weight: bold');
        window.PS_DEBUG&&console.log('[INTRO MAP] Instancja L.map:', map ? '✅ UTWORZONA' : '❌ BRAK');
        if (map) {
            const center = map.getCenter();
            const zoom = map.getZoom();
            window.PS_DEBUG&&console.log('[INTRO MAP] Centrum:', center.lat.toFixed(2) + ', ' + center.lng.toFixed(2));
            window.PS_DEBUG&&console.log('[INTRO MAP] Zoom:', zoom);
            window.PS_DEBUG&&console.log('[INTRO MAP] Tile layer: ✅ OpenStreetMap dodany');
        }
        window.PS_DEBUG&&console.log('[INTRO MAP] Czas inicjalizacji:', mapInitTime + 'ms');
        window.PS_DEBUG&&console.log('[INTRO MAP] Źródło danych:', dataSource);
        window.PS_DEBUG&&console.log('%c[INTRO MAP] ═══ MAPA GOTOWA ═══', 'color: #4CAF50; font-weight: bold');

        // ⏱️ PERFORMANCE TIMING
        performanceTiming.mapInitialized = performance.now();
        updatePerformanceTiming();

        } catch (error) {
            window.PS_DEBUG&&console.error('%c[INTRO MAP] ❌❌❌ KRYTYCZNY BŁĄD initializeMap()', 'color: red; font-weight: bold');
            window.PS_DEBUG&&console.error('[INTRO MAP] Error:', error.message);
            window.PS_DEBUG&&console.error('[INTRO MAP] Stack:', error.stack);
            map = null;
        }
    }

    // ====================================================================================
    // ŁADOWANIE PUNKTÓW DLA KRAJU (Główna funkcja pobierania danych z parcelselector.com API)
    // ====================================================================================
    // OPIS DLA AI:
    // To jest KLUCZOWA funkcja całego systemu! Pobiera wszystkie paczkomaty z parcelselector.com API
    // dla wybranego kraju i zapisuje je w zmiennej globalnej `allPoints`.
    // 
    // FLOW:
    // 1. Pobierz URL API z obiektu COUNTRIES[countryCode]
    // 2. Wyślij GET request (fetch)
    // 3. Parsuj JSON response - struktura zależy od typu API (dedicated vs global)
    // 4. Zapisz do `allPoints` (globalna tablica)
    // 5. Zastosuj limit punktów (initialPointsLimit) dla wydajności
    // 6. Wyświetl markery na mapie i listę w sidebar
    // 7. Jeśli użytkownik już coś wpisał - automatyczne wyszukiwanie
    // 
    // TYPY API:
    // - "dedicated" (PL, IT): Response.items (tablica)
    // - "global" (FR, ES, UK, DE, etc): Response jest bezpośrednio tablicą
    // 
    // OPTYMALIZACJE:
    // - initialPointsLimit (domyślnie 750) zamiast wszystkich 32000 punktów!
    // - Viewport culling - tylko widoczne markery na mapie
    // - Lazy loading - doładowanie przy zoomie
    // 
    // WYWOŁANA PRZEZ:
    // - initializeMap() (pierwsze załadowanie)
    // - switchCountry() (zmiana kraju po kliknięciu flagi)
    // 
    // WYWOŁUJE:
    // - displayMarkers() (rysowanie markerów Leaflet)
    // - displayPointsList() (lista w sidebar)
    // - performSearchAsync() (jeśli użytkownik już wpisał query)
    // ====================================================================================
    /**
     * =================================================================================
     * FUNKCJA NAPRAWCZA: ensurePopupDOMExists()
     * =================================================================================
     * 
     * PROBLEM: Często elementy DOM nie istnieją gdy loadPointsForCountry() jest wywoływana.
     * To powoduje że punkty się nie ładują.
     * 
     * ROZWIĄZANIE: Funkcja która:
     * 1. Sprawdza czy elementy DOM istnieją
     * 2. Jeśli nie - próbuje utworzyć je ponownie (createPopupHTML)
     * 3. Jeśli nadal nie - czeka i próbuje ponownie (retry)
     * 
     * WNIOSKI:
     * - Timing issue - createPopupHTML() może nie zdążyć utworzyć DOM
     * - Retry mechanism jest konieczny dla niezawodności
     * - Sprawdzanie DOM PRZED wywołaniem loadPointsForCountry() zapobiega błędom
     */
    function ensurePopupDOMExists(retryCount = 0) {
        const maxRetries = 5;
        const retryDelay = 200; // 200ms między próbami
        
        const loadStatusEl = document.getElementById('inpostLoadStatus');
        const pointsListEl = document.getElementById('inpostPointsList');
        const popupEl = document.getElementById('inpost-universal-popup');
        
        // Sprawdź czy wszystkie elementy istnieją
        if (loadStatusEl && pointsListEl && popupEl) {
            window.PS_DEBUG&&console.log('[INTRO Popup] ✅ Wszystkie elementy DOM istnieją');
            return true;
        }
        
        // Jeśli nie istnieją i nie przekroczono limitu prób
        if (retryCount < maxRetries) {
            window.PS_DEBUG&&console.warn(`[INTRO Popup] ⚠️ Elementy DOM nie istnieją (próba ${retryCount + 1}/${maxRetries})`);
            window.PS_DEBUG&&console.warn(`[INTRO Popup] ⚠️ inpostLoadStatus: ${!!loadStatusEl}, inpostPointsList: ${!!pointsListEl}, popup: ${!!popupEl}`);
            
            // Spróbuj utworzyć HTML ponownie jeśli popup nie istnieje
            if (!popupEl) {
                window.PS_DEBUG&&console.log('[INTRO Popup] 🔧 Próbuję utworzyć popup HTML ponownie...');
                createPopupHTML();
            }
            
            // Retry po krótkim opóźnieniu
            setTimeout(() => {
                ensurePopupDOMExists(retryCount + 1);
            }, retryDelay);
            
            return false;
        } else {
            // Przekroczono limit prób - krytyczny błąd
            window.PS_DEBUG&&console.error('[INTRO Popup] ❌❌❌ KRYTYCZNY BŁĄD: Elementy DOM nie istnieją po ' + maxRetries + ' próbach!');
            window.PS_DEBUG&&console.error('[INTRO Popup] ❌ Popup HTML może nie być utworzony. Sprawdź czy createPopupHTML() została wywołana.');
            window.PS_DEBUG&&console.error('[INTRO Popup] ❌ Możliwe przyczyny:');
            window.PS_DEBUG&&console.error('[INTRO Popup] ❌ 1. createPopupHTML() nie została wywołana');
            window.PS_DEBUG&&console.error('[INTRO Popup] ❌ 2. Timing issue - zbyt szybkie wywołanie loadPointsForCountry()');
            window.PS_DEBUG&&console.error('[INTRO Popup] ❌ 3. Konflikt z innymi skryptami');
            return false;
        }
    }

    /**
     * Normalize point from compact API format {n, lat, lng, a, t}
     * to full format {name, location, address_details, type} expected by UI code.
     * If point already has .name it's returned as-is (idempotent).
     */
    function normalizePoint(p) {
        if (!p) return p;
        if (p.name && p.location) return p; // already full format

        // ─── ENCODING SAFETY LAYER (v3.0.6) ───
        // Sanitize ALL string fields against encoding corruption:
        //   NBSP (U+00A0) → space
        //   FFFD (replacement char) → remove
        //   ZWSP (U+200B) → remove
        //   BOM  (U+FEFF) → remove
        //   Control chars (U+0000-U+001F except \t\n\r) → remove
        //   Double-encoded UTF-8 → decode (Ã¡ → á pattern)
        function sanitize(s) {
            if (typeof s !== 'string') return s;
            // Remove problematic Unicode chars
            s = s.replace(/\u00a0/g, ' ')
                 .replace(/\ufffd/g, '')
                 .replace(/\u200b/g, '')
                 .replace(/\ufeff/g, '')
                 .replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f]/g, '');
            // Fix double-encoded UTF-8 (mojibake):
            // Pattern: Ã followed by char in 0x80-0xBF range = double-encoded 2-byte UTF-8
            try {
                // Detect common double-encoding: bytes C0-DF followed by 80-BF
                // In double-encoded form: Ã (C3) + second byte appears as Latin-1
                if (/[\u00c0-\u00df][\u0080-\u00bf]/.test(s)) {
                    const bytes = [];
                    for (let i = 0; i < s.length; i++) {
                        const c = s.charCodeAt(i);
                        if (c < 128) { bytes.push(c); }
                        else if (c < 256) { bytes.push(c); }
                        else { // Real Unicode char, encode as UTF-8
                            if (c < 0x800) { bytes.push(0xc0 | (c >> 6), 0x80 | (c & 0x3f)); }
                            else { bytes.push(0xe0 | (c >> 12), 0x80 | ((c >> 6) & 0x3f), 0x80 | (c & 0x3f)); }
                        }
                    }
                    const decoded = new TextDecoder('utf-8', { fatal: false }).decode(new Uint8Array(bytes));
                    if (decoded && !decoded.includes('\ufffd') && decoded.length <= s.length) {
                        s = decoded;
                    }
                }
            } catch (e) { /* keep original if decoding fails */ }
            // Trim excess whitespace
            return s.replace(/\s{2,}/g, ' ').trim();
        }

        // Sanitize ALL string properties on the point
        for (const key of Object.keys(p)) {
            if (typeof p[key] === 'string') {
                p[key] = sanitize(p[key]);
            }
        }

        // Parse compact address string "line1, postcode city" into object
        let addrObj = p.address_details || {};
        if (typeof p.a === 'string' && p.a.length > 0) {
            const parts = p.a.split(',').map(s => s.trim());
            if (parts.length >= 2) {
                const street = parts[0];
                const rest = parts.slice(1).join(', ').trim();
                // rest = "21-412 Adamów" or "17438 Wolgast" etc.
                const m = rest.match(/^(\S+)\s+(.+)$/);
                addrObj = {
                    street: street,
                    post_code: m ? m[1] : '',
                    city: m ? m[2] : rest
                };
            } else {
                addrObj = { street: p.a, city: '', post_code: '' };
            }
        } else if (typeof addrObj !== 'object' || addrObj === null) {
            addrObj = {};
        }

        return {
            name: p.n || p.name || 'Unknown',
            location: p.location || { latitude: p.lat, longitude: p.lng },
            location_description: p.l || p.location_description || '',
            address_details: addrObj,
            type: Array.isArray(p.t) ? p.t : (p.type || []),
            status: p.s || p.status || '',
            opening_hours: p.oh || p.opening_hours || '',
            // preserve any extra fields
            ...(p.lat !== undefined ? { lat: p.lat, lng: p.lng } : {})
        };
    }

    function normalizePoints(arr) {
        if (!Array.isArray(arr)) return [];
        return arr.map(normalizePoint);
    }

    async function loadPointsForCountry(countryCode, pulseCircleToRemove = null) {
        window.PS_DEBUG&&console.log('[INTRO Popup] 🚀 loadPointsForCountry() wywołana dla:', countryCode);
        
        const country = COUNTRIES[countryCode];
        if (!country) {
            window.PS_DEBUG&&console.error('[INTRO Popup] ❌ Nieznany kod kraju:', countryCode);
            return;
        }
        
        // ✅ NAPRAWIONE: Użyj funkcji naprawczej zamiast prostego sprawdzenia
        if (!ensurePopupDOMExists()) {
            window.PS_DEBUG&&console.error('[INTRO Popup] ❌ Nie można załadować punktów - elementy DOM nie istnieją');
            // Funkcja ensurePopupDOMExists() sama wywoła retry, więc tutaj tylko logujemy błąd
            return;
        }
        
        // Sprawdzenie czy elementy DOM istnieją (dodatkowe zabezpieczenie)
        const loadStatusEl = document.getElementById('inpostLoadStatus');
        const pointsListEl = document.getElementById('inpostPointsList');
        if (!loadStatusEl || !pointsListEl) {
            window.PS_DEBUG&&console.error('[INTRO Popup] ❌ Elementy DOM nadal nie istnieją po ensurePopupDOMExists()!');
            window.PS_DEBUG&&console.error('[INTRO Popup] ❌ To nie powinno się zdarzyć - sprawdź ensurePopupDOMExists()');
            return;
        }
        
        window.PS_DEBUG&&console.log('[INTRO Popup] ✅ Elementy DOM potwierdzone - kontynuuję ładowanie punktów');
        
        // Pokazanie loadera punktów (SKELETONS)
        loadStatusEl.textContent = getTranslation('loading');
        showSkeletonList(8);
        
        // Reset markerów
        clearMarkers();
        
        try {
            // ===============================================================================
            // DATA SOURCE: parcelselector.com Remote API
            // Wszystkie dane pobierane z naszego serwera parcelselector.com
            // API zwraca kompletne dane dla kraju w jednym zapytaniu
            // Format: {country, count, fetched_at, points: [{n, lat, lng, a, t}]}
            // ===============================================================================
            const apiUrl = country.api; // np. https://parcelselector.com/api/points/pl
            window.PS_DEBUG&&console.log(`[INTRO Popup] ✅ ${countryCode.toUpperCase()}: Loading from ${apiUrl}`);
            
            // Ładowanie danych z API z retry mechanism
            window.PS_DEBUG&&console.log('[INTRO Popup] ⚡ Ładowanie danych:', apiUrl);
            const loadStart = performance.now();
            
            /**
             * fetchWithRetry - pobiera dane z retry + exponential backoff
             * Timeout 120s (serwer może potrzebować czasu na pierwsze pobranie)
             * Brak Content-Type header = simple CORS request (bez preflight)
             */
            async function fetchWithRetry(url, retryCount = 0, maxRetries = 3) {
                try {
                    const controller = new AbortController();
                    const timeoutId = setTimeout(() => controller.abort(), 120000); // 120s timeout
                    
                    const response = await fetch(url, {
                        signal: controller.signal,
                        headers: { 'Accept': 'application/json' }
                    });
                    
                    clearTimeout(timeoutId);
                    
                    // FIX 2026-03-03: Graceful 404 — kraj bez danych (LU, CZ, SK)
                    // Zamiast crash + retry → zwróć pustą odpowiedź z komunikatem
                    if (response.status === 404) {
                        window.PS_DEBUG&&console.warn('[INTRO Popup] ⚠️ HTTP 404 — brak danych dla tego kraju (jeszcze nie dostępne)');
                        return {
                            ok: true,
                            status: 404,
                            _empty: true,
                            json: async () => ({ points: [], count: 0, message: 'Dane dla tego kraju nie są jeszcze dostępne / Data not yet available' })
                        };
                    }
                    
                    if (response.status === 403) {
                        var _body403 = {};
                        try { _body403 = await response.clone().json(); } catch(e) {}
                        var _err403 = new Error('HTTP 403');
                        _err403.noRetry = true;
                        _err403.isLicenseInactive = !!(_body403 && _body403.data && _body403.data.code === 'LICENSE_INACTIVE');
                        throw _err403;
                    }

                    if (!response.ok) {
                        throw new Error(`HTTP ${response.status} - ${response.statusText}`);
                    }

                    return response;
                } catch (error) {
                    if (!error.noRetry && retryCount < maxRetries) {
                        const delay = Math.min(1000 * Math.pow(2, retryCount), 5000);
                        window.PS_DEBUG&&console.warn(`[INTRO Popup] ⚠️ Retry ${retryCount + 1}/${maxRetries}:`, error.message);
                        await new Promise(resolve => setTimeout(resolve, delay));
                        return fetchWithRetry(url, retryCount + 1, maxRetries);
                    }
                    window.PS_DEBUG&&console.error('[INTRO Popup] ❌ Failed after ' + maxRetries + ' retries:', url);
                    throw error;
                }
            }
            
            const response = await fetchWithRetry(apiUrl);
            const responseData = await response.json();
            const loadTime = ((performance.now() - loadStart) / 1000).toFixed(2);

            // ─── ENCODING GUARD: validate response data integrity ───
            // Check for encoding corruption indicators in the raw JSON
            try {
                const rawSample = JSON.stringify(responseData).slice(0, 5000);
                const mojibakePatterns = /\ufffd|(\u00c3[\u0080-\u00bf])|(\u00c4[\u0080-\u00bf])|(\u00c5[\u0080-\u00bf])/g;
                const mojibakeCount = (rawSample.match(mojibakePatterns) || []).length;
                if (mojibakeCount > 5) {
                    window.PS_DEBUG&&console.warn(`[INTRO Popup] ⚠️ ENCODING: detected ${mojibakeCount} potential mojibake patterns in response — sanitize will clean`);
                }
            } catch (e) { /* guard only, don't break flow */ }

            const quickPoints = normalizePoints(responseData.points || responseData.items || (Array.isArray(responseData) ? responseData : []));
            
            if (quickPoints.length === 0) {
                window.PS_DEBUG&&console.warn('[INTRO Popup] ⚠️ 0 points received! URL:', apiUrl);
                window.PS_DEBUG&&console.warn('[INTRO Popup] ⚠️ Response keys:', Object.keys(responseData));
            }
            
            window.PS_DEBUG&&console.log(`[INTRO Popup] ✅ API: ${quickPoints.length} points loaded in ${loadTime}s`);

            // ⏱️ PERFORMANCE TIMING
            performanceTiming.pointsLoaded = performance.now();
            updatePerformanceTiming();

            // KROK 2: Ustaw początkowe dane (dla natychmiastowego renderowania)
            allPoints = [...quickPoints];
            filteredPoints = [...allPoints];

            window.allPoints = allPoints; // ✅ Eksportuj dane dla testów w konsoli

            // PERFORMANCE: build the Fuse.js index AFTER the map is interactive.
            // Indexing ~32k points synchronously froze the UI on load. Deferred build
            // lets markers render immediately; until the index is ready searchPoints()
            // falls back to manual search (fuseInstance guard in performSearchOnDataV1).
            fuseInstance = null;
            window.fuseInstance = null;
            const searchEngineEl = document.getElementById('inpostSearchEngine');
            if (searchEngineEl) {
                searchEngineEl.textContent = '⚠️ Manual';
                searchEngineEl.style.color = '#ffaa00';
            }
            const buildFuseDeferred = function () {
                const fuseStart = performance.now();
                fuseInstance = initializeFuse(allPoints);
                window.fuseInstance = fuseInstance;
                window.PS_DEBUG&&console.log(`[INTRO Popup] 🔎 Fuse.js index built (deferred) in ${((performance.now() - fuseStart) / 1000).toFixed(2)}s`);
                if (searchEngineEl && fuseInstance && adminConfig.fuseSearch.enabled) {
                    searchEngineEl.textContent = '✅ Fuse.js';
                    searchEngineEl.style.color = '#00cc00';
                }
                // If the user typed a query while the index was building, re-run it now.
                const si = document.getElementById('inpostSearchInput');
                if (si && si.value && si.value.trim() !== '') {
                    performSearchAsync(si.value);
                }
            };
            if (typeof window.requestIdleCallback === 'function') {
                window.requestIdleCallback(buildFuseDeferred, { timeout: 2000 });
            } else {
                setTimeout(buildFuseDeferred, 200);
            }

            window.PS_DEBUG&&console.log(`[INTRO Popup] 🎬 Rozpoczynam NATYCHMIASTOWE renderowanie...`);
            
            // 🚀 RENDERUJ WSZYSTKO CO PRZYSZŁO (respektuj initialPointsLimit)
            let renderLimit;
            if (adminConfig.initialPointsLimit === 0) {
                renderLimit = quickPoints.length; // 0 = wszystkie
            } else {
                renderLimit = Math.min(adminConfig.initialPointsLimit, quickPoints.length);
            }
            
            const pointsToRender = filteredPoints.slice(0, renderLimit);
            
            window.PS_DEBUG&&console.log(`[INTRO Popup] 📊 Renderuję ${pointsToRender.length} z ${quickPoints.length} punktów (initialPointsLimit: ${adminConfig.initialPointsLimit})`);
            
            // Ukrycie loadera mapy (punkty zaczną się renderować)
            const mapLoader = document.getElementById('inpostMapLoading');
            if (mapLoader) {
                mapLoader.style.display = 'none';
            }
            
            // UWAGA: Pulse circle NIE jest usuwany tutaj!
            // W Epic Zoom mode: pulse circle zostaje do końca animacji (6s)
            // Usuwany jest w initializeMap() po zakończeniu animacji zoom
            if (pulseCircleToRemove) {
                window.PS_DEBUG&&console.log('[INTRO Popup] 🟡 Pulse circle przekazany, ale NIE usuwam (zostaje do końca animacji)');
                // map.removeLayer(pulseCircleToRemove); // WYŁĄCZONE - nie usuwaj!
            }
            
            // 🚀 RENDEROWANIE - małe batche dla płynności (200 punktów co 10ms)
            window.PS_DEBUG&&console.log(`[INTRO Popup] 🚀 Dodaję ${pointsToRender.length} markerów w małych batch'ach...`);
            const renderStart = performance.now();
            
            const batchSize = 200;
            let currentIndex = 0;
            displayedPoints = [];
            
            const renderBatch = () => {
                if (currentIndex >= pointsToRender.length) {
                    const renderTime = ((performance.now() - renderStart) / 1000).toFixed(2);
                    window.PS_DEBUG&&console.log(`[INTRO Popup] ✅ ${pointsToRender.length} markerów dodanych w ${renderTime}s`);

                    // ⏱️ PERFORMANCE TIMING
                    performanceTiming.markersRendered = performance.now();
                    updatePerformanceTiming();

                    // Aktualizacja UI
                    const pointsCountEl = document.getElementById('inpostPointsCount');
                    const loadStatusEl = document.getElementById('inpostLoadStatus');
                    if (pointsCountEl) pointsCountEl.textContent = allPoints.length;
                    if (loadStatusEl) loadStatusEl.textContent = '✓ ' + getTranslation('statusReady');
                    displayPointsList(displayedPoints);
                    
                    // ✅ Jeśli użytkownik już coś wpisał - wyszukaj
                    const searchInput = document.getElementById('inpostSearchInput');
                    if (searchInput && searchInput.value.trim()) {
                        window.PS_DEBUG&&console.log('[INTRO Popup] 🔄 Auto-wyszukiwanie:', searchInput.value);
                        performSearchAsync(searchInput.value);
                    } else {
                        window.PS_DEBUG&&console.log('[INTRO Popup] 📌 Pokazuję historię');
                        showClickHistory();
                    }
                    // Inject custom pickup marker after all regular markers are rendered
                    injectClassicCustomPickup();
                    return;
                }
                
                const batch = pointsToRender.slice(currentIndex, currentIndex + batchSize);
                addMarkers(batch);
                displayedPoints = [...displayedPoints, ...batch];
                currentIndex += batchSize;

                // Następny batch (FAST MODE: instant, normal: 10ms dla płynności)
                const batchDelay = FAST_MODE ? 0 : 10;
                setTimeout(renderBatch, batchDelay);
            };
            
            renderBatch();
            
            // API parcelselector.com zwraca kompletne dane — nie potrzeba drugiego fetcha
            window.PS_DEBUG&&console.log(`[INTRO Popup] ✅ All ${allPoints.length} points loaded and ready`);
            const finalLoadStatusEl = document.getElementById('inpostLoadStatus');
            if (finalLoadStatusEl) {
                finalLoadStatusEl.textContent = `✓ ${allPoints.length} ${getTranslation('pointsCount')}`;
            }
            
        } catch (error) {
            window.PS_DEBUG&&console.error('[INTRO Popup] ❌ Błąd ładowania punktów:', error);
            window.PS_DEBUG&&console.error('[INTRO Popup] ❌ Stack trace:', error.stack);
            
            // Ukryj loader mapy nawet przy błędzie
            const mapLoader = document.getElementById('inpostMapLoading');
            if (mapLoader) {
                mapLoader.style.display = 'none';
            }
            
            // UWAGA: Pulse circle NIE usuwamy nawet przy błędzie
            // Zostanie usunięty automatycznie po zakończeniu animacji w initializeMap()
            if (pulseCircleToRemove) {
                window.PS_DEBUG&&console.log('[INTRO Popup] ⚠️ Błąd ładowania, ale pulse circle zostaje (zostanie usunięty po animacji)');
                // map.removeLayer(pulseCircleToRemove); // WYŁĄCZONE
            }
            
            const loadStatusEl = document.getElementById('inpostLoadStatus');
            const pointsListEl = document.getElementById('inpostPointsList');

            if (error.isLicenseInactive) {
                // Show activation overlay on the map itself
                var mapEl = document.getElementById('inpostMap');
                if (mapEl) {
                    mapEl.style.position = 'relative';
                    var overlay = document.createElement('div');
                    overlay.style.cssText = 'position:absolute;inset:0;z-index:1000;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:32px;background:rgba(255,255,255,0.97);border-radius:8px;';
                    overlay.innerHTML = '<div style="font-size:52px;margin-bottom:16px;">🔐</div>'
                        + '<h3 style="margin:0 0 10px;font-size:20px;color:#1f2937;font-weight:800;">Activate ParcelSelector</h3>'
                        + '<p style="color:#6b7280;font-size:14px;line-height:1.6;margin:0 0 20px;max-width:320px;">Go to the WordPress Admin Panel and complete the activation wizard to enable the parcel locker map.</p>'
                        + '<a href="' + ((window.parcselectCacheConfig && parcselectCacheConfig.activatorUrl) ? parcselectCacheConfig.activatorUrl : '/wp-admin/admin.php?page=parcelselector-settings&tab=activator') + '" style="background:#f97316;color:#fff;text-decoration:none;padding:12px 24px;border-radius:8px;font-weight:700;font-size:14px;">🚀 Activate Plugin</a>';
                    mapEl.appendChild(overlay);
                }
                if (loadStatusEl) {
                    loadStatusEl.textContent = '🔐 Plugin not activated';
                }
                if (pointsListEl) {
                    pointsListEl.innerHTML = '<div style="padding:20px;text-align:center;color:#92400e;font-size:13px;"><strong>Plugin not activated</strong><br>Activate ParcelSelector in the WordPress admin panel.</div>';
                }
            } else {
                if (loadStatusEl) {
                    loadStatusEl.textContent = '✗ ' + getTranslation('statusError');
                }
                if (pointsListEl) {
                    pointsListEl.innerHTML = `
                        <div class="error-message">
                            <p>${getTranslation('errorLoadingPoints')}</p>
                            <p>${error.message || getTranslation('errorUnknown')}</p>
                            <p style="font-size: 0.8em; color: #666;">${getTranslation('errorCheckConsole')}</p>
                        </div>
                    `;
                }
            }
        }
    }

    // ====================
    // CZYSZCZENIE MARKERÓW
    // ====================
    function clearMarkers() {
        window.PS_DEBUG&&console.log('[INTRO Popup] Usuwanie', markers.length, 'markerów z mapy...');

        markers.forEach(marker => {
            try {
                if (map) map.removeLayer(marker);
            } catch(e) {}
            marker.pointData = null;
        });

        markers = [];
        window.PS_DEBUG&&console.log('[INTRO Popup] Markery wyczyszczone');
    }

    // ====================
    // WYŚWIETLANIE MARKERÓW NA MAPIE
    // ====================
    function displayMarkers(points) {
        window.PS_DEBUG&&console.log(`[INTRO Popup] Wyświetlanie ${points.length} markerów`);
        
        clearMarkers();
        addMarkers(points);
        
        // Po dodaniu markerów, zastosuj viewport culling
        if (adminConfig.viewportCulling) {
            setTimeout(() => updateVisibleMarkers(), 100);
        }
    }

    // ====================
    // PROGRESYWNE DODAWANIE MARKERÓW (BEZ CZYSZCZENIA)
    // Używane dla sukcesywnego renderowania podczas animacji
    // ====================
    function addMarkersProgressive(points) {
        if (!points || points.length === 0) return;
        
        window.PS_DEBUG&&console.log(`[INTRO Popup] 🔄 Progresywne dodawanie ${points.length} markerów...`);
        
        // Dodaj markery (addMarkers sam sprawdza duplikaty)
        addMarkers(points);
        
        // Zastosuj viewport culling jeśli włączony
        if (adminConfig.viewportCulling) {
            updateVisibleMarkers();
        }
        
        window.PS_DEBUG&&console.log(`[INTRO Popup] ✅ Łącznie markerów na mapie: ${markers.length}`);
    }

    // ====================
    // DODAWANIE NOWYCH MARKERÓW (BEZ CZYSZCZENIA)
    // ====================
    function addMarkers(points) {
        if (!points || points.length === 0) return;
        if (!map) {
            window.PS_DEBUG&&console.warn('[INTRO Popup] addMarkers: mapa nie istnieje, pomijam');
            return;
        }

        const country = COUNTRIES[currentCountry];
        let addedCount = 0;
        
        points.forEach(point => {
            if (!point.location || !point.location.latitude || !point.location.longitude) {
                return;
            }
            
            // Sprawdź czy marker już istnieje
            const exists = markers.some(m => 
                m.pointData && m.pointData.name === point.name
            );
            if (exists) return;
            
            // Utworzenie ikony markera
            const icon = createMarkerIcon(country.color);
            
            // Utworzenie markera
            const marker = L.marker(
                [point.location.latitude, point.location.longitude],
                { icon: icon }
            );
            
            // Zapisz dane punktu w markerze
            marker.pointData = point;
            
            // 🖱️ KLIKNIĘCIE w pinezkę → wybór punktu
            marker.on('click', () => {
                window.PS_DEBUG&&console.log('[INTRO Popup] 🖱️ Kliknięto w pinezkę:', point.name);
                selectPointOnMap(point, marker);
            });
            
            // 🚀 LAZY BIND: Tooltip i Popup dodawane TYLKO przy pierwszym hover!
            let initialized = false;
            marker.on('mouseover', function() {
                if (initialized) return;
                initialized = true;
                
                // Tooltip z danymi Paczkomatu
                const _ad = point.address_details || {};
                const _city = _ad.city || '';
                const _postCode = _ad.post_code || '';
                const _street = _ad.street || '';
                const _building = _ad.building_number || '';
                const _streetLine = [_street, _building].filter(Boolean).join(' ');
                const _cityLine = [_postCode, _city].filter(Boolean).join(' ');
                const _addrHtml = [_streetLine, _cityLine].filter(Boolean).join('<br>');

                marker.bindTooltip(
                    `<div class="inpost-mtt">
                        <div class="inpost-mtt-name">&#128230; ${point.name}</div>
                        ${_addrHtml ? `<div class="inpost-mtt-address">${_addrHtml}</div>` : ''}
                        <div class="inpost-mtt-hint">&#9660; ${getTranslation('markerClickHint')}</div>
                    </div>`,
                    {
                        direction: 'top',
                        offset: [0, -30],
                        className: 'inpost-marker-select-tooltip'
                    }
                );
                
                // Popup z przetlumaczonym przyciskiem WYBIERZ
                if (typeof ParcelLockerSelector !== 'undefined') {
                    const popupContent = ParcelLockerSelector.createMarkerPopup(point, {
                        selectLabel: getTranslation('markerSelect'),
                        selectedLabel: getTranslation('accept')
                    });
                    marker.bindPopup(popupContent, {
                        maxWidth: 180,
                        minWidth: 160,
                        className: 'inpost-marker-popup',
                        autoPan: true,
                        autoPanPadding: [80, 80],
                        closeButton: true,
                        autoClose: false
                    });
                }
                
                // Pokaż tooltip teraz
                marker.openTooltip();
            });
            
            // Dodanie do mapy
            marker.addTo(map);
            markers.push(marker);
            addedCount++;
        });
        
        window.PS_DEBUG&&console.log(`[INTRO Popup] +${addedCount} nowych markerów (łącznie: ${markers.length})`);
    }

    // ====================
    // CUSTOM PICKUP POINT — PS_CUSTOM_PICKUP marker injection
    // ====================
    function injectClassicCustomPickup() {
        var PS = window.PS_CUSTOM_PICKUP;
        if (!PS || !PS.enabled || !PS.lat || !PS.lng || !map) return;

        // Remove previous marker
        if (_customPickupMarker) {
            _customPickupMarker.remove();
            _customPickupMarker = null;
        }

        var iconBg = PS.highlight ? '#16a34a' : '#f97316';
        var svgHome = '<svg viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2.5" width="18" height="18">' +
            '<path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>' +
            '<polyline points="9 22 9 12 15 12 15 22"/></svg>';
        var iconHtml = '<div style="background:' + iconBg + ';width:38px;height:38px;border-radius:50%;' +
            'border:3px solid white;box-shadow:0 3px 16px rgba(0,0,0,0.4);' +
            'display:flex;align-items:center;justify-content:center;cursor:pointer;">' + svgHome + '</div>';

        var customIcon = L.divIcon({
            html: iconHtml,
            className: 'custom-pickup-marker-icon',
            iconSize: [38, 38],
            iconAnchor: [19, 19]
        });

        _customPickupMarker = L.marker([PS.lat, PS.lng], { icon: customIcon, zIndexOffset: 1000 });

        _customPickupMarker.on('click', function() {
            // Build tooltip
            var tipLines = [PS.name || 'Punkt odbioru osobistego'];
            if (PS.hours) tipLines.push('&#x23F0; ' + PS.hours);
            if (PS.label) tipLines.push('<em>' + PS.label + '</em>');
            _customPickupMarker.bindPopup(
                '<div style="min-width:160px;">' +
                '<div style="font-weight:700;color:' + iconBg + ';margin-bottom:4px;">&#x1F3E0; ' + (PS.name || 'Punkt odbioru') + '</div>' +
                (PS.street ? '<div style="font-size:12px;color:#555;">' + PS.street + ', ' + (PS.postal || '') + ' ' + (PS.city || '') + '</div>' : '') +
                (PS.hours ? '<div style="font-size:12px;color:#888;margin-top:2px;">&#x23F0; ' + PS.hours + '</div>' : '') +
                (PS.desc  ? '<div style="font-size:12px;color:#333;margin-top:4px;">' + PS.desc + '</div>' : '') +
                '<button onclick="window.parcselectClassicConfirmPickup()" style="margin-top:8px;width:100%;padding:6px;' +
                'background:' + iconBg + ';color:#fff;border:none;border-radius:6px;cursor:pointer;font-weight:700;">' +
                '&#x2713; Wybierz ten punkt</button>' +
                '</div>',
                { maxWidth: 220, className: 'inpost-marker-popup' }
            ).openPopup();
        });

        // Confirm handler (accessible from inline button onclick)
        window.parcselectClassicConfirmPickup = function() {
            document.dispatchEvent(new CustomEvent('inpost-point-selected', {
                detail: {
                    point: {
                        name: PS.name || 'Punkt odbioru osobistego',
                        address_details: {
                            street:    PS.street || '',
                            city:      PS.city   || '',
                            post_code: PS.postal || ''
                        },
                        location: { latitude: PS.lat, longitude: PS.lng },
                        _isCustomPickup: true
                    },
                    country:     currentCountry,
                    countryName: (COUNTRIES[currentCountry] || {}).name || currentCountry.toUpperCase()
                }
            }));
            closePopup();
        };

        _customPickupMarker.addTo(map);

        // show_first: prepend custom pickup card to sidebar list
        if (PS.show_first) {
            var listEl = document.getElementById('inpostPointsList');
            if (listEl) {
                var iconBgList = PS.highlight ? '#16a34a' : '#f97316';
                var card = document.createElement('div');
                card.className = 'inpost-point-item';
                card.id = 'ps-custom-pickup-list-item';
                card.style.cssText = 'border-left:4px solid ' + iconBgList + ';background:#f0fdf4;margin-bottom:4px;';
                card.innerHTML = '<div class="point-content" style="padding:4px 0;">' +
                    '<div class="point-name" style="color:' + iconBgList + ';font-weight:700;">&#x1F3E0; ' +
                    (PS.name || 'Punkt odbioru osobistego') + '</div>' +
                    '<div class="point-address">' + (PS.label || 'Odbierz lokalnie') + '</div>' +
                    '</div>';
                card.onclick = function() {
                    if (map) map.flyTo([PS.lat, PS.lng], 15, { duration: 1.0 });
                    if (_customPickupMarker) _customPickupMarker.openPopup();
                };
                // Remove previous card if exists, then prepend
                var prev = document.getElementById('ps-custom-pickup-list-item');
                if (prev && prev !== card) prev.remove();
                listEl.insertBefore(card, listEl.firstChild);
            }
        }

        // Zoom mode
        if (PS.zoom_mode === 'direct') {
            map.setView([PS.lat, PS.lng], 14);
        } else if (PS.zoom_mode === 'from_poland') {
            setTimeout(function() { if (map) map.flyTo([PS.lat, PS.lng], 14, { duration: 1.2 }); }, 1200);
        }

        window.PS_DEBUG&&console.log('[INTRO Popup] \uD83C\uDFE0 Custom pickup marker injected:', PS.name);
    }

    // ====================
    // TWORZENIE IKONY MARKERA - PROSTY KOD Z DZIAŁAJĄCEGO BACKUPU
    // ====================
    function createMarkerIcon(color) {
        const svg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 36" width="24" height="36"><path fill="' + color + '" stroke="#FFFFFF" stroke-width="1.5" d="M12 0C7.0 0 3 4.0 3 9c0 7 9 18 9 18s9-11 9-18c0-5-4-9-9-9z"/><circle cx="12" cy="9" r="4" fill="#FFFFFF"/></svg>';
        
        return L.icon({
            iconUrl: 'data:image/svg+xml;charset=UTF-8,' + encodeURIComponent(svg),
            iconSize: [24, 36],
            iconAnchor: [12, 36],
            popupAnchor: [0, -36]
        });
    }

    // ====================
    // WYŚWIETLANIE LISTY PUNKTÓW - Z THROTTLED HOVER
    // ====================
    let hoverThrottle = null;

    /**
     * Renders animated skeleton placeholders in the points list.
     * Used during search and initial data loading to improve perceived performance.
     */
    function showSkeletonList(count = 5) {
        const listEl = document.getElementById('inpostPointsList');
        if (!listEl) return;
        
        let skeletonHtml = '';
        for (let i = 0; i < count; i++) {
            skeletonHtml += `
                <div class="ps-skeleton-item">
                    <div class="ps-skeleton-title"></div>
                    <div class="ps-skeleton-text"></div>
                </div>
            `;
        }
        listEl.innerHTML = skeletonHtml;
    }
    
    function displayPointsList(points) {
        const listEl = document.getElementById('inpostPointsList');
        listEl.innerHTML = '';
        
        window.PS_DEBUG&&console.log(`[displayPointsList] 📋 Wyświetlam ${Math.min(points.length, 100)} z ${points.length} punktów`);
        
        // Limit do 100 dla wydajności
        const displayPoints = points.slice(0, 100);
        
        displayPoints.forEach(point => {
            const ad = point.address_details || {};
            const city = ad.city || point.city || '';
            const street = ad.street || point.street || '';
            const buildingNumber = ad.building_number || point.building_number || '';
            const postCode = ad.post_code || point.post_code || '';
            
            // Złóż pełny adres ulicy z numerem
            const fullStreet = street ? (buildingNumber ? `${street} ${buildingNumber}` : street) : '';
            
            const div = document.createElement('div');
            const isSelected = typeof ParcelLockerSelector !== 'undefined'
                && ParcelLockerSelector.selectedLocker
                && ParcelLockerSelector.selectedLocker.name === point.name;
            div.className = 'inpost-point-item' + (isSelected ? ' selected-item' : '');

            // ✅ CHECKBOX dla Parcel Locker Selector
            const checkboxHtml = typeof ParcelLockerSelector !== 'undefined'
                ? ParcelLockerSelector.createListCheckbox(point)
                : '<div class="list-checkbox"><span class="checkbox-icon">☐</span></div>';
            
            div.innerHTML = `
                ${checkboxHtml}
                <div class="point-content">
                    <div class="point-name">${point.name}</div>
                    <div class="point-address">
                        <strong>🏙️ ${city}</strong>${postCode ? ' • ' + postCode : ''}${fullStreet ? ' • ' + fullStreet : ''}
                    </div>
                </div>
            `;
            
            // Kliknięcie - wybór punktu (nie blokuj kliknięcia w checkbox)
            div.onclick = (e) => {
                if (e.target.closest('.list-checkbox')) return;
                const marker = markers.find(m => m.pointData.name === point.name);
                if (marker && point.location) {
                    map.setView([point.location.latitude, point.location.longitude], 15);
                    const selectDelay = FAST_MODE ? 0 : 500;
                    setTimeout(() => selectPointOnMap(point, marker), selectDelay);
                }
            };

            // 🚀 THROTTLED HOVER - nie wykonuj zbyt często (max 1x na 100ms)
            // STATUS: ✅ DZIAŁA - Optymalizacja wydajności hover efektów
            // FUNKCJA: Delikatny zoom +2 na paczkomat przy hover (max zoom 15)
            // THROTTLE: 100ms - zapobiega lagom przy szybkim przesuwaniu myszką
            div.onmouseenter = () => {
                if (hoverThrottle) return; // Throttle aktywny
                
                hoverThrottle = setTimeout(() => {
                    hoverThrottle = null;
                }, 100); // 100ms throttle
                
                const marker = markers.find(m => m.pointData.name === point.name);
                if (marker && point.location) {
                    highlightPointOnMap(point, marker);
                    
                    // 🎯 DELIKATNY ZOOM NA PACZKOMAT (hover effect)
                    const currentZoom = map.getZoom();
                    if (currentZoom < 15) {
                        // Jeśli zoom daleki - zbliż się delikatnie
                        map.flyTo(
                            [point.location.latitude, point.location.longitude],
                            Math.min(currentZoom + 2, 15), // +2 zoom, max 15
                            {
                                duration: 0.8,
                                easeLinearity: 0.3
                            }
                        );
                        window.PS_DEBUG&&console.log(`[HOVER ZOOM] Delikatny zoom na ${point.name} (${currentZoom} → ${Math.min(currentZoom + 2, 15)})`);
                    } else {
                        // Jeśli zoom już bliski - tylko pan (przesunięcie)
                        map.panTo([point.location.latitude, point.location.longitude], {
                            duration: 0.5,
                            easeLinearity: 0.3
                        });
                    }
                }
            };
            
            // Zjechanie myszką - usunięcie podświetlenia
            div.onmouseleave = () => {
                unhighlightPointOnMap();
            };
            
            listEl.appendChild(div);
        });
        
        if (points.length > 100) {
            const moreDiv = document.createElement('div');
            moreDiv.className = 'more-points-info';
            moreDiv.textContent = `... i ${points.length - 100} więcej (użyj wyszukiwarki)`;
            listEl.appendChild(moreDiv);
        }
    }

    // ====================
    // PODŚWIETLENIE PUNKTU NA MAPIE (HOVER)
    // ====================
    let hoveredMarker = null;
    let hoveredCircle = null;
    
    function highlightPointOnMap(point, marker) {
        if (!map || !marker) return;
        
        window.PS_DEBUG&&console.log('[INTRO Popup] Hover na punkcie:', point.name);
        
        // Usunięcie poprzedniego podświetlenia
        unhighlightPointOnMap();
        
        hoveredMarker = marker;
        
        // Zwiększenie rozmiaru i zmiana koloru markera
        const originalIcon = marker.getIcon();
        const hoverIcon = L.divIcon({
            className: 'inpost-marker-hover',
            html: '<div style="font-size: 36px; line-height: 36px;">📍</div>',
            iconSize: [36, 36],
            iconAnchor: [18, 36]
        });
        marker.setIcon(hoverIcon);
        
        // Zapisanie oryginalnej ikony
        marker._originalIcon = originalIcon;
        
        // Dodanie okręgu 10km (promień widoczności)
        if (point.location) {
            hoveredCircle = L.circle([point.location.latitude, point.location.longitude], {
                radius: 10000, // 10km w metrach
                color: '#FF6600',
                fillColor: '#FF6600',
                fillOpacity: 0.1,
                weight: 2,
                dashArray: '5, 5'
            }).addTo(map);
            
            // Wyśrodkowanie mapy na punkcie
            map.setView([point.location.latitude, point.location.longitude], 12, {
                animate: true,
                duration: 0.5
            });
        }
    }
    
    function unhighlightPointOnMap() {
        // Przywrócenie normalnego markera
        if (hoveredMarker && hoveredMarker._originalIcon) {
            hoveredMarker.setIcon(hoveredMarker._originalIcon);
            hoveredMarker = null;
        }
        
        // Usunięcie okręgu
        if (hoveredCircle) {
            map.removeLayer(hoveredCircle);
            hoveredCircle = null;
        }
    }

    // ====================
    // KOMUNIKATY "BRAK WYNIKÓW"
    // ====================
    function showNoResultsMessage(query) {
        const listEl = document.getElementById('inpostPointsList');
        if (!listEl) return;
        
        const existingMsg = document.getElementById('inpostNoResults');
        if (existingMsg) return; // Już pokazany
        
        const noResultsDiv = document.createElement('div');
        noResultsDiv.id = 'inpostNoResults';
        noResultsDiv.className = 'inpost-no-results';
        noResultsDiv.innerHTML = `
            <div class="no-results-icon">🔍</div>
            <div class="no-results-title">${getTranslation('noResultsTitle')}</div>
            <div class="no-results-query">"${query}"</div>
            <div class="no-results-hints">
                <p>${getTranslation('trySearch')}</p>
                <ul>
                    <li>🏙️ <strong>${getTranslation('city')}</strong> "wroclaw", "warszawa", "krakow"</li>
                    <li>📦 <strong>${getTranslation('lockerCode')}</strong> "WRO01", "WAW12", "KRA05"</li>
                    <li>📮 <strong>${getTranslation('postalCode')}</strong> "50-138", "50138", "00-001"</li>
                    <li>🛣️ <strong>${getTranslation('street')}</strong> "krzycka", "marszalkowska", "florianska"</li>
                </ul>
            </div>
        `;
        
        listEl.innerHTML = '';
        listEl.appendChild(noResultsDiv);
    }
    
    function hideNoResultsMessage() {
        const existingMsg = document.getElementById('inpostNoResults');
        if (existingMsg) {
            existingMsg.remove();
        }
    }

    // ====================
    // WYBÓR PUNKTU NA MAPIE
    // STATUS: ✅ DZIAŁA - Zaznacza punkt i dodaje do historii
    // HISTORIA: clickedPointsHistory[] - max 50 punktów (MAX_HISTORY)
    // FUNKCJE: Aktywuje przycisk "Wybierz punkt", zoom do punktu (level 16)
    // REFRESH: Wywołuje refreshListWithHistory() aby pokazać historię na górze listy
    // ====================
    function selectPointOnMap(point, marker) {
        window.PS_DEBUG&&console.log('[INTRO Popup] Wybrano punkt:', point.name);

        // ⏱️ PERFORMANCE TIMING
        performanceTiming.pointSelected = performance.now();
        updatePerformanceTiming();

        selectedPoint = point;
        
        // 📌 DODAJ DO HISTORII KLIKNIĘĆ (na początek)
        // Usuń punkt jeśli już istnieje w historii (żeby nie było duplikatów)
        clickedPointsHistory = clickedPointsHistory.filter(p => p.name !== point.name);
        // Dodaj na początek
        clickedPointsHistory.unshift(point);
        // Ogranicz do MAX_HISTORY
        if (clickedPointsHistory.length > MAX_HISTORY) {
            clickedPointsHistory = clickedPointsHistory.slice(0, MAX_HISTORY);
        }
        window.PS_DEBUG&&console.log('[INTRO Popup] 📌 Historia kliknięć:', clickedPointsHistory.length, 'punktów');
        
        // 🎯 ODŚWIEŻ LISTĘ Z HISTORIĄ NA GÓRZE
        refreshListWithHistory();
        
        // ZOOM do punktu na mapie
        if (point.location && map) {
            let lat = point.location.latitude;
            let lng = point.location.longitude;
            
            // FIX 2026-03-02: Centrowanie na mobile (z offsetem pionowym)
            // Na mobile panel szczegółów zajmuje dolną część ekranu (ok. 45% wysokości)
            // Przesuwamy punkt widzenia w górę (czyli zmniejszamy lat), aby marker był widoczny nad panelem.
            if (window.PS_MOBILE && !window.PS_MOBILE.isDesktop) {
                // Na zoom 16 to przesunięcie ok. 0.0025 stopnia jest optymalne
                lat -= 0.0025; 
            }

            if (FAST_MODE) {
                // FAST MODE: instant zoom
                map.setView([lat, lng], 16);
            } else {
                // Normal mode: animated flyTo
                map.flyTo(
                    [lat, lng],
                    16,
                    {
                        duration: 1.0,
                        easeLinearity: 0.25
                    }
                );
            }
        }
    }
    
    // ====================================================================================
    // ODŚWIEŻENIE LISTY Z HISTORIĄ KLIKNIĘĆ NA GÓRZE
    // ====================================================================================
    function refreshListWithHistory() {
        const pointsList = document.getElementById('inpostPointsList');
        if (!pointsList) return;
        
        // Usuń poprzednie podświetlenie
        document.querySelectorAll('.inpost-point-item').forEach(item => {
            item.classList.remove('active');
        });
        
        // Wyczyść tylko sekcję historii (jeśli istnieje)
        const existingHistory = pointsList.querySelectorAll('.inpost-point-item.history-item');
        existingHistory.forEach(item => item.remove());
        
        // Dodaj historię kliknięć NA POCZĄTKU listy
        clickedPointsHistory.forEach((point, index) => {
            const ad = point.address_details || {};
            const city = ad.city || point.city || '';
            const street = ad.street || point.street || '';
            const buildingNumber = ad.building_number || point.building_number || '';
            const postCode = ad.post_code || point.post_code || '';
            const fullStreet = street ? (buildingNumber ? `${street} ${buildingNumber}` : street) : '';
            
            const div = document.createElement('div');
            div.className = 'inpost-point-item history-item';

            // Checkbox (tak samo jak w displayPointsList)
            const checkboxHtml = typeof ParcelLockerSelector !== 'undefined'
                ? ParcelLockerSelector.createListCheckbox(point)
                : '<div class="list-checkbox"><span class="checkbox-icon">&#9744;</span></div>';

            div.innerHTML = `
                ${checkboxHtml}
                <div class="point-content">
                    <div class="point-name">${point.name}</div>
                    <div class="point-address">
                        <strong>${city}</strong>${postCode ? ' &bull; ' + postCode : ''}${fullStreet ? ' &bull; ' + fullStreet : ''}
                    </div>
                </div>
            `;

            // Kliknięcie w div (nie w checkbox) - centrum mapy
            div.onclick = (e) => {
                // Nie przeszkadzaj kliknięciu w checkbox
                if (e.target.closest('.list-checkbox')) return;
                const marker = markers.find(m => m.pointData.name === point.name);
                if (marker && point.location) {
                    map.setView([point.location.latitude, point.location.longitude], 15);
                    const selectDelay = FAST_MODE ? 0 : 500;
                    setTimeout(() => selectPointOnMap(point, marker), selectDelay);
                }
            };
            
            // Wstaw na POCZĄTEK listy
            pointsList.insertBefore(div, pointsList.firstChild);
        });
        
        // Scroll do góry listy
        pointsList.scrollTop = 0;
        
        window.PS_DEBUG&&console.log('[INTRO Popup] ✅ Lista odświeżona z historią:', clickedPointsHistory.length, 'punktów');
    }
    
    // ====================================================================================
    // NOWY FLOW: UKRYJ LISTĘ, POKAŻ FORMULARZ
    // ====================================================================================
    // Po kliknięciu punktu:
    //   1. Lista punktów znika
    //   2. Wyszukiwarka znika
    //   3. Mapa zoomuje do MAX (18) na wybranym paczkomacie
    //   4. Formularz danych pojawia się po prawej
    // ====================================================================================
    function hideListShowForm(point) {
        window.PS_DEBUG&&console.log('[INTRO Popup] 🎯 Przejście do formularza dla punktu:', point.name);
        
        // 1. UKRYJ listę punktów
        const pointsList = document.getElementById('inpostPointsList');
        const searchContainer = document.querySelector('.inpost-search-container');
        if (pointsList) pointsList.style.display = 'none';
        if (searchContainer) searchContainer.style.display = 'none';
        
        // 2. ZOOM DO MAX na wybranym paczkomacie
        if (point.location && map) {
            const latlng = [point.location.latitude, point.location.longitude];
            const isMobile = window.PS_MOBILE && !window.PS_MOBILE.isDesktop;
            
            if (isMobile) {
                // Na mobile używamy fitBounds z paddingiem, aby wycentrować marker nad panelem dolnym
                map.fitBounds([latlng, latlng], {
                    maxZoom: 18,
                    paddingBottomRight: [0, 320], // Offset dla panelu dolnego (ok. 320px)
                    animate: true,
                    duration: 1.5
                });
                window.PS_DEBUG&&console.log('[INTRO Popup] 📍 Mobile Center (with offset) na:', point.name);
            } else {
                map.flyTo(
                    latlng,
                    18, // MAX ZOOM
                    {
                        duration: 1.5,
                        easeLinearity: 0.1
                    }
                );
                window.PS_DEBUG&&console.log('[INTRO Popup] 📍 MAX ZOOM na:', point.name);
            }
        }
        
        // 3. POKAŻ formularz danych
        showCustomerDataForm(point);
    }
    
    // ====================================================================================
    // FORMULARZ DANYCH KLIENTA (PRAWY PANEL)
    // ====================================================================================
    // Tworzy formularz z danymi klienta:
    //   - Nagłówek z nazwą i adresem wybranego paczkomatu
    //   - Pola: Imię*, Nazwisko*, Email*, Telefon (opcjonalny)
    //   - Auto-fill z WordPress (jeśli użytkownik zalogowany)
    //   - Przyciski: "Zmień Paczkomat" | "Zaakceptuj"
    // ====================================================================================
    function showCustomerDataForm(point) {
        const ad = point.address_details || {};
        const city = ad.city || point.city || '';
        const street = ad.street || point.street || '';
        const buildingNumber = ad.building_number || point.building_number || '';
        const postCode = ad.post_code || point.post_code || '';
        const fullAddress = `${street} ${buildingNumber}, ${postCode} ${city}`.trim();
        
        // Pobierz dane użytkownika z WordPressa (jeśli zalogowany)
        const userData = window.inpostUserData || {};
        const firstName = userData.firstName || '';
        const lastName = userData.lastName || '';
        const email = userData.email || '';
        // FIX 2026-03-02: Strip prefix z phone bo input ma osobny <select> z prefixem
        // Bez tego: klient widzi "+48" w select PLUS "+48 123..." w input = podwójny prefix
        const phone = stripPhonePrefix(userData.phone || '');
        const phonePrefix = getPhonePrefixByCountry(currentCountry);
        
        const formHTML = `
            <div class="inpost-customer-form" id="inpostCustomerForm">
                <div class="form-header">
                    <h3>📦 Wybrany Paczkomat</h3>
                    <div class="selected-point-info">
                        <strong>${point.name}</strong><br>
                        <span class="point-address-small">📍 ${fullAddress}</span>
                    </div>
                </div>
                
                <div class="form-body">
                    <h4>${getTranslation('deliveryData')}</h4>
                    <p class="form-hint">${getTranslation('formHint')}</p>
                    
                    <div class="form-group">
                        <label for="inpostFirstName">${getTranslation('firstName')} <span class="required">${getTranslation('required')}</span></label>
                        <input type="text" id="inpostFirstName" value="${firstName}" placeholder="${getTranslation('firstNamePlaceholder')}" required>
                        <span class="error-msg" id="errorFirstName"></span>
                    </div>
                    
                    <div class="form-group">
                        <label for="inpostLastName">${getTranslation('lastName')} <span class="required">${getTranslation('required')}</span></label>
                        <input type="text" id="inpostLastName" value="${lastName}" placeholder="${getTranslation('lastNamePlaceholder')}" required>
                        <span class="error-msg" id="errorLastName"></span>
                    </div>
                    
                    <div class="form-group">
                        <label for="inpostEmail">${getTranslation('email')} <span class="required">${getTranslation('required')}</span></label>
                        <input type="email" id="inpostEmail" value="${email}" placeholder="${getTranslation('emailPlaceholder')}" required>
                        <span class="error-msg" id="errorEmail"></span>
                    </div>
                    
                    <div class="form-group">
                        <label for="inpostPhone">${getTranslation('phone')}</label>
                        <div class="phone-input-group">
                            <select id="inpostPhonePrefix" class="phone-prefix">
                                <option value="+48" selected>🇵🇱 +48</option>
                            </select>
                            <input type="tel" id="inpostPhone" value="${phone}" placeholder="${getTranslation('phonePlaceholder')}">
                        </div>
                        <span class="error-msg" id="errorPhone"></span>
                    </div>
                </div>
                
                <div class="form-footer">
                    <button class="inpost-btn inpost-btn-change" onclick="IntroPopup.changeParcelLocker()">
                        🔄 ${getTranslation('changeLocker')}
                    </button>
                    <button class="inpost-btn inpost-btn-confirm" onclick="IntroPopup.confirmAndSave()">
                        ✓ ${getTranslation('accept')}
                    </button>
                </div>
            </div>
        `;
        
        // Dodaj formularz do głównego kontenera (prawy panel)
        const container = document.getElementById('inpostPopupContainer');
        if (!container) return;
        
        // Usuń stary formularz jeśli istnieje
        const oldForm = document.getElementById('inpostCustomerForm');
        if (oldForm) oldForm.remove();
        
        // Wstaw nowy formularz
        container.insertAdjacentHTML('beforeend', formHTML);
        
        window.PS_DEBUG&&console.log('[INTRO Popup] ✅ Formularz danych wyświetlony');
    }
    
    // ====================================================================================
    // POBIERZ PREFIX TELEFONU WEDŁUG KRAJU
    // ====================================================================================
    function getPhonePrefixByCountry(country) {
        const prefixes = {
            'pl': '+48'
        };
        return prefixes[country] || '+48';
    }

    /**
     * FIX 2026-03-02: Usuwa prefix kraju z numeru telefonu
     * Potrzebne bo phone z inpostUserData/WC może zawierać prefix (+48 123456789)
     * a input telefonu ma osobny <select> z prefixem
     * @param {string} phone - numer z lub bez prefixu
     * @returns {string} - numer bez prefixu (sam numer)
     */
    function stripPhonePrefix(phone) {
        if (!phone) return '';
        phone = phone.trim();
        // Sprawdź każdy znany prefix (od najdłuższego — +420 przed +4)
        const allPrefixes = ['+420', '+421', '+380', '+351', '+352', '+48', '+49', '+44', '+43', '+39', '+36', '+34', '+33', '+32', '+31'];
        for (const prefix of allPrefixes) {
            if (phone.startsWith(prefix)) {
                return phone.substring(prefix.length).trim();
            }
        }
        // Jeśli zaczyna się od + ale nieznany prefix — usuń cały prefix
        if (phone.startsWith('+')) {
            const match = phone.match(/^\+\d{1,4}\s*(.*)$/);
            if (match) return match[1].trim();
        }
        return phone;
    }

    // ====================
    // MODAL SZCZEGÓŁÓW PUNKTU (z Francji/Włoch)
    // ====================
    function showPointDetailsModal(point) {
        const ad = point.address_details || {};
        const city = ad.city || point.city || '';
        const street = ad.street || point.street || '';
        const buildingNumber = ad.building_number || point.building_number || '';
        const postCode = ad.post_code || point.post_code || '';
        
        const modalHTML = `
            <div class="inpost-detail-modal-overlay" id="inpostDetailModal" onclick="IntroPopup.closeDetailModal(event)">
                <div class="inpost-detail-modal" onclick="event.stopPropagation()">
                    <div class="detail-modal-header">
                        <button class="detail-modal-close" onclick="IntroPopup.closeDetailModal()">&times;</button>
                        <h3>${point.name}</h3>
                        <p>${city}</p>
                    </div>
                    <div class="detail-modal-body">
                        <div class="detail-section">
                            <div class="detail-row">
                                <div class="detail-icon">📍</div>
                                <div class="detail-content">
                                    <div class="detail-label">${getTranslation('address')}</div>
                                    <div class="detail-value">${street} ${buildingNumber}, ${postCode} ${city}</div>
                                </div>
                            </div>
                            <div class="detail-row">
                                <div class="detail-icon">🌍</div>
                                <div class="detail-content">
                                    <div class="detail-label">${getTranslation('coordinates')}</div>
                                    <div class="detail-value">${point.location.latitude.toFixed(6)}, ${point.location.longitude.toFixed(6)}</div>
                                </div>
                            </div>
                        </div>
                    </div>
                    <div class="detail-modal-footer">
                        <button class="inpost-btn inpost-btn-secondary" onclick="IntroPopup.closeDetailModal()">${getTranslation('closeButton')}</button>
                        <button class="inpost-btn inpost-btn-primary" onclick="IntroPopup.confirmSelectPoint()">${getTranslation('selectPoint')}</button>
                    </div>
                </div>
            </div>
        `;
        
        // Usunięcie starego modala jeśli istnieje
        const oldModal = document.getElementById('inpostDetailModal');
        if (oldModal) {
            oldModal.remove();
        }
        
        // Dodanie nowego
        document.body.insertAdjacentHTML('beforeend', modalHTML);
    }

    // ====================
    // ZAMKNIĘCIE MODALA SZCZEGÓŁÓW
    // ====================
    function closeDetailModal(event) {
        if (event && event.target.id !== 'inpostDetailModal' && !event.target.classList.contains('detail-modal-close')) {
            return;
        }
        
        const modal = document.getElementById('inpostDetailModal');
        if (modal) {
            modal.remove();
        }
    }

    // ====================
    // POTWIERDZENIE WYBORU PUNKTU
    // ====================
    /**
     * POTWIERDZENIE WYBORU PUNKTU - PROSTA WERSJA DZIAŁAJĄCA
     *
     * JAK TO DZIAŁA (jak oryginalny kod):
     * 1. Wywołuje event 'inpost-point-selected' - paczkomat-modal.js nasłuchuje tego eventu
     * 2. Wywołuje callback window.onInPostPointSelected
     * 3. Zamyka popup natychmiast - processPointSelection w paczkomat-modal.js zapisze dane i przeładuje stronę CART
     *
     * WAŻNE: Popup zamyka się natychmiast, a paczkomat-modal.js przeładuje stronę CART po zapisaniu danych.
     * To jest najprostsze i najbardziej niezawodne rozwiązanie - jak w oryginalnym kodzie.
     *
     * PRZEKAZYWANE DANE (od 2026-02-15):
     * - point: obiekt z danymi paczkomatu (nazwa, adres, koordynaty)
     * - country: kod kraju (np. 'pl', 'it', 'fr')
     * - countryName: nazwa kraju w języku ojczystym (np. 'Polska', 'Italia', 'France')
     *
     * Dlaczego countryName?
     * Użytkownik powinien widzieć nazwę kraju w języku, którym posługuje się w danym kraju.
     * countryName jest automatycznie wyciągane z obiektu COUNTRIES[currentCountry].name
     */
    function confirmSelectPoint() {
        window.PS_DEBUG&&console.log('[INTRO Popup] 🔵🔵🔵 confirmSelectPoint() WYWOŁANE! ===');
        window.PS_DEBUG&&console.log('[INTRO Popup] selectedPoint:', selectedPoint);
        
        if (!selectedPoint) {
            window.PS_DEBUG&&console.error('[INTRO Popup] ❌❌❌ BRAK selectedPoint - NIE MOŻNA PRZEKAZAĆ DANYCH! ===');
            return;
        }
        
        // Pobierz nazwę kraju w języku ojczystym z obiektu COUNTRIES
        const countryName = COUNTRIES[currentCountry] ? COUNTRIES[currentCountry].name : currentCountry.toUpperCase();

        // ⏱️ PERFORMANCE TIMING
        performanceTiming.confirmed = performance.now();
        updatePerformanceTiming();

        window.PS_DEBUG&&console.log('[INTRO Popup] ✅ Potwierdzono wybór punktu:', selectedPoint.name);
        window.PS_DEBUG&&console.log('[INTRO Popup] 📤 Przekazuję dane do CART - popup zamknie się, strona się przeładuje ===');
        window.PS_DEBUG&&console.log('[INTRO Popup] Point data:', JSON.stringify(selectedPoint, null, 2));
        window.PS_DEBUG&&console.log('[INTRO Popup] Country CODE:', currentCountry);
        window.PS_DEBUG&&console.log('[INTRO Popup] Country NAME (native):', countryName);
        
        // Zamknięcie modala szczegółów
        closeDetailModal();
        window.PS_DEBUG&&console.log('[INTRO Popup] ✅ Modal szczegółów zamknięty ===');
        
        // Event dla WooCommerce/WordPress - paczkomat-modal.js nasłuchuje tego eventu
        window.PS_DEBUG&&console.log('[INTRO Popup] 🚀🚀🚀 Wysyłam event inpost-point-selected ===');
        const event = new CustomEvent('inpost-point-selected', {
            detail: {
                point: selectedPoint,
                country: currentCountry,        // Kod kraju (np. 'pl', 'it')
                countryName: countryName        // Nazwa w języku ojczystym (np. 'Polska', 'Italia')
            }
        });
        window.PS_DEBUG&&console.log('[INTRO Popup] Event created:', event);
        window.PS_DEBUG&&console.log('[INTRO Popup] Event detail:', event.detail);
        
        document.dispatchEvent(event);
        window.PS_DEBUG&&console.log('[INTRO Popup] ✅✅✅ Event inpost-point-selected WYSŁANY! ===');
        
        // Callback jeśli zdefiniowany - dodatkowa metoda przekazania danych
        if (typeof window.onInPostPointSelected === 'function') {
            window.PS_DEBUG&&console.log('[INTRO Popup] ✅ Wywołuję window.onInPostPointSelected callback ===');
            window.onInPostPointSelected(selectedPoint, currentCountry, countryName);
        } else {
            window.PS_DEBUG&&console.log('[INTRO Popup] ⚠️ window.onInPostPointSelected nie jest funkcją');
        }
        
        // ZAMKNIJ POPUP NATYCHMIAST - processPointSelection w paczkomat-modal.js 
        // zapisze dane do sesji i przeładuje stronę CART (jak oryginalny kod)
        window.PS_DEBUG&&console.log('[INTRO Popup] 🔴 Zamykam popup ===');
        closePopup();
        window.PS_DEBUG&&console.log('[INTRO Popup] ✅ Popup zamknięty - paczkomat-modal.js przeładuje stronę CART po zapisaniu danych ===');
    }

    // ====================
    // GEOCODING FALLBACK - ZNAJDŹ MIASTO NA MAPIE I POKAŻ NAJBLIŻSZE PUNKTY
    // STATUS: ✅ DZIAŁA - Używa OpenStreetMap Nominatim API
    // FUNKCJA: Konwersja nazwy miejscowości → współrzędne GPS → zoom do lokalizacji
    // PROMIEŃ: 20km wokół znalezionej lokalizacji
    // BEZPIECZEŃSTWO: Anulowanie starych wyników (searchId), timeout 10s
    // ====================
    // ====================================================================================
    // GEOCODING - Konwersja nazwy miejscowości na współrzędne GPS
    // ====================================================================================
    // Używa API OpenStreetMap Nominatim do znalezienia lokalizacji w Polsce
    // Następnie znajduje punkty InPost w promieniu 20km i zoomuje mapę
    // 
    // PARAMETRY:
    //   cityName - nazwa miejscowości wpisana przez użytkownika (np. "Warszawa", "Stoczek Łukowski")
    //   searchId - unikalny ID wyszukiwania (do anulowania starych wyników)
    //
    // DZIAŁANIE:
    //   1. Wysyła zapytanie do Nominatim API → dostaje współrzędne (lat, lon)
    //   2. Sprawdza czy to wyszukiwanie jest nadal aktualne (currentSearchId)
    //   3. Zoomuje mapę BEZPOŚREDNIO do wpisanej lokalizacji (map.flyTo)
    //   4. Znajduje punkty InPost w promieniu 20km
    //   5. Wyświetla je na liście i na mapie
    //
    // BEZPIECZEŃSTWO:
    //   - Sprawdza searchId po każdej async operacji (anuluje stare wyniki)
    //   - Timeout na API: 10 sekund
    //   - Try-catch na wszystkie błędy
    // ====================================================================================
    async function geocodeAndShowNearby(cityName, searchId) {
        try {
            window.PS_DEBUG&&console.log(`[Geocoding #${searchId}] 🌍 Szukam lokalizacji: "${cityName}"`);
            
            // Użyj Nominatim API OpenStreetMap do geokodowania
            const searchQuery = encodeURIComponent(cityName + ', Poland');
            const url = `https://nominatim.openstreetmap.org/search?q=${searchQuery}&format=json&limit=1`;
            
            const response = await fetch(url, {
                headers: {
                    'User-Agent': 'InPostSelector/1.0'
                }
            });
            
            // ⚡ CHECK: Czy to wyszukiwanie jest jeszcze aktualne?
            if (searchId !== currentSearchId) {
                window.PS_DEBUG&&console.log(`[Geocoding #${searchId}] ⏭️ SKIP: Nowsze wyszukiwanie (current: ${currentSearchId})`);
                return;
            }
            
            const results = await response.json();
            
            // ⚡ CHECK ponownie po async operacji
            if (searchId !== currentSearchId) {
                window.PS_DEBUG&&console.log(`[Geocoding #${searchId}] ⏭️ SKIP: Nowsze wyszukiwanie (current: ${currentSearchId})`);
                return;
            }
            
            if (results && results.length > 0) {
                const location = results[0];
                const lat = parseFloat(location.lat);
                const lon = parseFloat(location.lon);
                
                window.PS_DEBUG&&console.log(`[Geocoding #${searchId}] ✅ Znaleziono: ${location.display_name} (${lat}, ${lon})`);
                
                // 🎯 KLUCZOWE: Najpierw ZOOMUJ DO WPISANEJ LOKALIZACJI!
                map.flyTo([lat, lon], 12, {
                    duration: 1.5,
                    easeLinearity: 0.1
                });
                window.PS_DEBUG&&console.log(`[Geocoding #${searchId}] 🎯 ZOOM do lokalizacji: ${cityName} (${lat}, ${lon})`);
                
                const nearbyPoints = findPointsNearLocation(lat, lon, 20);

                let filteredNearby = nearbyPoints;
                const cityTokens = normalizePolishChars(normalizeText(cityName))
                    .split(' ')
                    .filter(t => t.length > 0);
                if (cityTokens.length > 0) {
                    filteredNearby = nearbyPoints.filter(p => {
                        const rawCity = (p.address_details && p.address_details.city) || p.city || '';
                        const cityNorm = normalizePolishChars(normalizeText(rawCity));
                        return cityTokens.every(t => cityNorm.includes(t));
                    });
                }
                
                if (filteredNearby.length > 0) {
                    window.PS_DEBUG&&console.log(`[Geocoding #${searchId}] 📍 Znaleziono ${filteredNearby.length} punktów w mieście "${cityName}"`);
                    
                    // 🔥 UPEWNIJ SIĘ ŻE LISTA I WYSZUKIWARKA SĄ WIDOCZNE!
                    const pointsList = document.getElementById('inpostPointsList');
                    const searchContainer = document.querySelector('.inpost-search-container');
                    if (pointsList) pointsList.style.display = 'block';
                    if (searchContainer) searchContainer.style.display = 'block';
                    
                    displayPointsList(filteredNearby);
                    
                    // Wyczyść i dodaj markery
                    clearMarkers();
                    addMarkers(filteredNearby);
                    
                    window.PS_DEBUG&&console.log(`[Geocoding #${searchId}] ✅ Pokazano ${filteredNearby.length} punktów dla "${cityName}"`);
                } else {
                    window.PS_DEBUG&&console.log(`[Geocoding #${searchId}] ⚠️ Brak punktów w promieniu 20km od "${cityName}"`);

                    if (!allPoints || allPoints.length === 0) {
                        const listEl = document.getElementById('inpostPointsList');
                        if (listEl) {
                            listEl.innerHTML = `
                                <div style="padding:15px;background:#FFF8E1;border-radius:8px;margin-bottom:10px;">
                                    <strong>⏳ Dane punktów jeszcze się ładują</strong><br>
                                    <small>Poczekaj chwilę aż mapa załaduje wszystkie paczkomaty i wpisz "${cityName}" ponownie.</small>
                                </div>
                            `;
                        }
                    } else {
                        const cityFallbackTokens = normalizePolishChars(normalizeText(cityName))
                            .split(' ')
                            .filter(t => t.length > 0);
                        const cityResults = allPoints.filter(p => {
                            const rawCity = (p.address_details && p.address_details.city) || p.city || '';
                            const cityNorm = normalizePolishChars(normalizeText(rawCity));
                            return cityFallbackTokens.every(t => cityNorm.includes(t));
                        });

                        if (cityResults.length > 0) {
                            window.PS_DEBUG&&console.log(`[Geocoding #${searchId}] 🔁 Fallback city filter: znaleziono ${cityResults.length} punktów dla "${cityName}"`);
                            filteredPoints = cityResults;
                            displayPointsList(filteredPoints);
                            clearMarkers();
                            addMarkers(filteredPoints);
                            centerMapOnResults(filteredPoints, null);
                        } else {
                            const listEl = document.getElementById('inpostPointsList');
                            if (listEl) {
                                listEl.innerHTML = `
                                    <div style="padding:15px;background:#ffebee;border-radius:8px;margin-bottom:10px;">
                                        <strong>⚠️ Brak punktów InPost w okolicy "${cityName}"</strong><br>
                                        <small>Spróbuj wyszukać inną lokalizację</small>
                                    </div>
                                `;
                            }
                        }
                    }
                }
                
            } else {
                window.PS_DEBUG&&console.log(`[Geocoding #${searchId}] ❌ Nie znaleziono lokalizacji dla "${cityName}"`);
            }
        } catch (error) {
            window.PS_DEBUG&&console.error(`[Geocoding #${searchId}] ❌ Błąd geocoding:`, error);
        } finally {
            const mapStatus = document.getElementById('inpostMapStatus');
            if (mapStatus) {
                mapStatus.style.display = 'none';
            }
        }
    }
    
    // ====================================================================================
    // ZNAJDŹ PUNKTY W OKOLICY - Haversine distance search
    // ====================================================================================
    // Filtruje wszystkie punkty InPost i znajduje te w określonym promieniu od lokalizacji
    // Sortuje wyniki według odległości (najbliższe najpierw)
    //
    // PARAMETRY:
    //   lat, lon - współrzędne GPS środka (z geocoding lub kliknięcie mapy)
    //   radiusKm - promień wyszukiwania w kilometrach (domyślnie 20km)
    //
    // ZWRACA:
    //   Array punktów posortowanych według odległości (najbliższe na początku)
    //
    // UŻYWA:
    //   calculateDistance() - wzór Haversine do obliczania odległości na kuli ziemskiej
    // ====================================================================================
    function findPointsNearLocation(lat, lon, radiusKm) {
        return allPoints.filter(p => {
            if (!p.location) return false;
            const distance = calculateDistance(lat, lon, p.location.latitude, p.location.longitude);
            return distance <= radiusKm;
        }).sort((a, b) => {
            // Sortuj po odległości
            const distA = calculateDistance(lat, lon, a.location.latitude, a.location.longitude);
            const distB = calculateDistance(lat, lon, b.location.latitude, b.location.longitude);
            return distA - distB;
        });
    }
    
    // ====================================================================================
    // OBLICZ ODLEGŁOŚĆ - Haversine Formula
    // ====================================================================================
    // Oblicza rzeczywistą odległość między dwoma punktami GPS na kuli ziemskiej
    // Uwzględnia krzywiznę Ziemi (dokładniejsze niż proste lat/lon)
    //
    // PARAMETRY:
    //   lat1, lon1 - współrzędne pierwszego punktu (np. lokalizacja z geocoding)
    //   lat2, lon2 - współrzędne drugiego punktu (np. parcel locker)
    //
    // ZWRACA:
    //   Odległość w kilometrach (float)
    //
    // MATEMATYKA:
    //   Wzór Haversine - standardowy w geolokalizacji
    //   R = 6371 km (średni promień Ziemi)
    // ====================================================================================
    // Oblicz odległość między dwoma punktami (Haversine formula)
    function calculateDistance(lat1, lon1, lat2, lon2) {
        const R = 6371; // Promień Ziemi w km
        const dLat = (lat2 - lat1) * Math.PI / 180;
        const dLon = (lon2 - lon1) * Math.PI / 180;
        const a = Math.sin(dLat/2) * Math.sin(dLat/2) +
                  Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
                  Math.sin(dLon/2) * Math.sin(dLon/2);
        const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
        return R * c;
    }

    // ====================
    // CENTROWANIE MAPY NA WYNIKI WYSZUKIWANIA - EPICKIE I PLASTYCZNE! 🎬
    // ====================
    async function centerMapOnResults(points, searchType) {
        if (!points || points.length === 0) return;
        
        // searchType: 'CITY', 'CITY+STREET', 'OTHER', null, lub legacy: 1=MIASTO, 2=NAZWA, 3=KOD, 4=ULICA
        const isCity = (
            searchType === 1 ||
            searchType === 'CITY' ||
            searchType === 'CITY_ONLY' ||
            searchType === 'CITY_POSTAL'
        );
        const isPostCode = (
            searchType === 3 ||
            searchType === 'POSTAL_ONLY' ||
            searchType === 'CITY_POSTAL'
        );
        const isStreet = (
            searchType === 4 ||
            searchType === 'CITY+STREET' ||
            searchType === 'CITY_STREET' ||
            searchType === 'STREET_ONLY'
        );
        
        // 🎬 EPIC ZOOM ANIMATION: zoom out → zoom in (TYLKO dla samego miasta bez ulicy!)
        // NIE dla CITY+STREET - tam chcemy normalny zoom
        if (isCity && !isStreet && points.length > 10) {
            window.PS_DEBUG&&console.log(`[ANIMATION] 🎬 Epic zoom dla miasta - zoom out → zoom in`);
            
            // KROK 1: Płynny zoom out - czas na wczytanie mapy (800ms)
            map.flyTo(
                [52.0, 19.5], // Centrum Polski
                6, // Zoom out - cała Polska widoczna
                {
                    duration: 0.8, // Wolniej - czas na wczytanie
                    easeLinearity: 0.15 // Bardzo płynne (niższe = płynniejsze)
                }
            );
            
            // KROK 2: Po 1000ms - majestatyczny zoom in na miasto (2000ms)
            setTimeout(() => {
                const bounds = L.latLngBounds(
                    points.map(p => [p.location.latitude, p.location.longitude])
                );
                
                // Dopasowany zoom - wszystkie punkty widoczne, mało pustej przestrzeni
                let maxZoom;
                if (points.length <= 10) {
                    maxZoom = 14; // Małe miasto
                } else if (points.length <= 50) {
                    maxZoom = 13; // Średnie miasto
                } else if (points.length <= 200) {
                    maxZoom = 12; // Duże miasto (Wrocław)
                } else {
                    maxZoom = 11; // Bardzo duże miasto (Warszawa)
                }
                
                map.flyToBounds(bounds, {
                    padding: [30, 30], // Mały padding - skupienie na punktach
                    duration: 2.0, // Wolniej - majestatyczny efekt + czas na wczytanie
                    easeLinearity: 0.1, // Bardzo płynne - wzrok nadąża
                    maxZoom: maxZoom,
                    animate: true
                });
                
                window.PS_DEBUG&&console.log(`[ANIMATION] ✅ Zoom zakończony (${points.length} paczkomatów, zoom: ${maxZoom})`);
            }, 1000); // Czekaj 1000ms po zoom out - mapa zdąży się wczytać
            
            return; // Exit - animacja async
        }
        
        if (points.length === 1) {
            // 🎯 Pojedynczy punkt → zoom bliski (ulica)
            const point = points[0];
            const latlng = [point.location.latitude, point.location.longitude];
            const isMobile = window.PS_MOBILE && !window.PS_MOBILE.isDesktop;

            if (isMobile) {
                // Na mobile używamy fitBounds z paddingiem
                map.fitBounds([latlng, latlng], {
                    maxZoom: 16,
                    paddingBottomRight: [0, 240], // Mniejszy offset dla listy wyników niż dla formularza
                    animate: true,
                    duration: 1.5
                });
            } else {
                map.flyTo(
                    latlng,
                    16, // Bliższy zoom dla pojedynczego punktu
                    { 
                        duration: 1.5,
                        easeLinearity: 0.25
                    }
                );
            }
        } else {
            // 🗺️ Wiele punktów → pokaż WSZYSTKIE w ramce
            const bounds = L.latLngBounds(
                points.map(p => [p.location.latitude, p.location.longitude])
            );
            
            // 🏙️ SPECJALNY TRYB DLA MIASTA - zoom optymalny do scrollowania
            let padding, maxZoom;
            
            if (isCity) {
                // Dla miasta: mały padding, zoom zbliżony (ZOPTYMALIZOWANY!)
                padding = [30, 30]; // Mniejszy padding = mniej pustej mapy
                
                if (points.length <= 10) {
                    maxZoom = 14; // Małe miasto - bliżej (BYŁO 13)
                } else if (points.length <= 50) {
                    maxZoom = 13; // Średnie miasto (BYŁO 12)
                } else if (points.length <= 200) {
                    maxZoom = 12; // Duże miasto - np. Wrocław (BYŁO 11)
                } else {
                    maxZoom = 11; // Bardzo duże miasto - np. Warszawa (BYŁO 10)
                }
                
                window.PS_DEBUG&&console.log(`[MIASTO] ${points.length} paczkomatów, zoom: ${maxZoom}, padding: [${padding}]`);
                
            } else {
                // Dla kodu pocztowego, ulicy, nazwy - dynamiczny zoom (ZBLIŻONY, mniej pustej mapy!)
                
                // Oblicz optymalny padding na podstawie liczby punktów (ZMNIEJSZONY!)
                if (points.length <= 3) {
                    padding = [50, 50]; // Mniej miejsca - skupienie na punktach
                } else if (points.length <= 10) {
                    padding = [40, 40]; // Mały padding
                } else if (points.length <= 50) {
                    padding = [30, 30]; // Minimalny padding
                } else {
                    padding = [20, 20]; // Bardzo mały padding dla wielu punktów
                }
                
                // Oblicz odpowiedni maxZoom na podstawie bounds (ZWIĘKSZONY ZOOM!)
                const boundsSize = bounds.getNorthEast().distanceTo(bounds.getSouthWest());
                
                if (boundsSize < 500) {
                    maxZoom = 18; // Bardzo blisko (ta sama ulica) - BYŁO 17
                } else if (boundsSize < 2000) {
                    maxZoom = 16; // Dzielnica/osiedle - BYŁO 15
                } else if (boundsSize < 10000) {
                    maxZoom = 14; // Miasto/kod pocztowy - BYŁO 13
                } else {
                    maxZoom = 12; // Region/województwo - BYŁO 11
                }
            }
            
            // 🎬 EPIC FLY TO BOUNDS - płynna animacja pokazująca wszystkie punkty
            map.flyToBounds(bounds, {
                padding: padding,
                duration: 1.8, // Dłuższa, bardziej epicka animacja
                easeLinearity: 0.2, // Bardzo smooth
                maxZoom: maxZoom,
                animate: true
            });
            
            // 💫 Dodatkowy efekt - lekkie pulsowanie markerów po zakończeniu animacji
            setTimeout(() => {
                if (window.markerClusterGroup) {
                    // Refresh cluster aby pokazać animację
                    markerClusterGroup.refreshClusters();
                }
            }, 1900); // Po zakończeniu animacji
        }
    }

    // ====================
    // WYSZUKIWARKA - Z PRIORYTETYZACJĄ + DEBOUNCE + ASYNC + CHUNKING
    // ====================
    let searchDebounceTimer = null;
    let isSearching = false;
    let currentSearchId = 0; // ID dla anulowania poprzednich wyszukiwań
    
    // ====================================================================================
    // FUSE.JS INICJALIZACJA - Inteligentna wyszukiwarka
    // ====================================================================================
    /**
     * Inicjalizuje Fuse.js fuzzy search engine
     *
     * Dlaczego Fuse.js?
     * - Toleruje typos: "Krakow" znajduje "Kraków"
     * - Różne formaty: "00-001" = "00001" = "00 001"
     * - Priorytetyzacja: nazwa > miasto > ulica > kod
     * - Szybkość: 100k rekordów w <100ms
     *
     * Wywoływana po załadowaniu allPoints dla danego kraju.
     *
     * @param {Array} points - Tablica punktów do przeszukiwania
     * @returns {Fuse|null} - Instancja Fuse lub null jeśli wyłączone/błąd
     * @since 2026-02-15 Dodano fuzzy search dla wyszukiwarki
     */
    function initializeFuse(points) {
        if (!adminConfig.fuseSearch.enabled) {
            window.PS_DEBUG&&console.log('[INTRO Popup] Fuse.js WYŁĄCZONY - używam starej wyszukiwarki');
            return null;
        }

        if (typeof Fuse === 'undefined') {
            window.PS_DEBUG&&console.error('[INTRO Popup] ❌ Fuse.js nie załadowany! Sprawdź wp_enqueue_script');
            return null;
        }

        if (!points || points.length === 0) {
            window.PS_DEBUG&&console.log('[INTRO Popup] Brak punktów - pomijam inicjalizację Fuse.js');
            return null;
        }

        try {
            const fuseOptions = {
                threshold: adminConfig.fuseSearch.threshold,
                distance: adminConfig.fuseSearch.distance,
                minMatchCharLength: adminConfig.fuseSearch.minMatchCharLength,
                includeScore: adminConfig.fuseSearch.includeScore,
                useExtendedSearch: adminConfig.fuseSearch.useExtendedSearch,
                ignoreLocation: adminConfig.fuseSearch.ignoreLocation,
                keys: adminConfig.fuseSearch.keys,
                // ✅ NORMALIZUJ WSZYSTKIE znaki diakrytyczne (działa dla WSZYSTKICH krajów!)
                // Polski: Ą→a, Ć→c, Ę→e, Ł→l, Ń→n, Ó→o, Ś→s, Ź→z, Ż→z
                // Francuski: À→a, È→e, É→e, Ê→e, Ç→c, Ù→u, etc.
                // Hiszpański: Á→a, É→e, Í→i, Ñ→n, Ó→o, Ú→u
                // Czeski: Č→c, Ř→r, Š→s, Ž→z
                // i wszystkie inne języki europejskie!
                getFn: (obj, path) => {
                    // ✅ WIRTUALNE POLE _searchable - łączy wszystkie dane dla kombinacji (np. "warszawa gorczewska")
                    if (path === '_searchable') {
                        const city = obj.address_details?.city || '';
                        const street = obj.address_details?.street || '';
                        const buildingNumber = obj.address_details?.building_number || '';
                        let postCode = obj.address_details?.post_code || '';
                        const name = obj.name || '';

                        // Normalizuj kod pocztowy (usuń separatory!)
                        postCode = postCode.replace(/[-\s.,:]/g, '');

                        // Połącz wszystkie pola w jeden ciąg (z normalizacją!)
                        const combined = `${name} ${city} ${street} ${buildingNumber} ${postCode}`;
                        let normalized = normalizeText(combined);
                        normalized = normalizePolishChars(normalized);
                        // Usuń podwójne spacje
                        normalized = normalized.replace(/\s+/g, ' ').trim();

                        return normalized;
                    }

                    // Standardowa normalizacja dla innych pól
                    const value = Fuse.config.getFn(obj, path);
                    if (typeof value === 'string') {
                        // ✅ UŻYWAMY TEJ SAMEJ normalizacji co STARA WYSZUKIWARKA (która DZIAŁAŁA!)
                        let normalized = normalizeText(value);      // lowercase, trim, spacje
                        normalized = normalizePolishChars(normalized); // ą→a, ł→l, ó→o, etc.

                        // ✅ DLA KODÓW POCZTOWYCH: usuń kreski, spacje, kropki
                        // "02-495" → "02495", "02 495" → "02495"
                        if (path === 'address_details.post_code' || path === 'post_code') {
                            normalized = normalized.replace(/[-\s.,:]/g, '');
                        }

                        return normalized;
                    }
                    return value;
                }
            };

            // ✅ DODAJ _searchable bezpośrednio do obiektów (Fuse.js nie wspiera wirtualnych pól w getFn!)
            const pointsWithSearchable = points.map(item => {
                const city = item.address_details?.city || '';
                const street = item.address_details?.street || '';
                const buildingNumber = item.address_details?.building_number || '';
                let postCode = item.address_details?.post_code || '';
                const name = item.name || '';

                // Normalizuj kod pocztowy
                postCode = postCode.replace(/[-\s.,:]/g, '');

                // Połącz wszystkie pola
                const combined = `${name} ${city} ${street} ${buildingNumber} ${postCode}`;
                let normalized = normalizeText(combined);
                normalized = normalizePolishChars(normalized);
                normalized = normalized.replace(/\s+/g, ' ').trim();

                return {
                    ...item,
                    _searchable: normalized  // ← Dodaj jako właściwe pole!
                };
            });

            const fuse = new Fuse(pointsWithSearchable, fuseOptions);
            window.PS_DEBUG&&console.log(`[INTRO Popup] ✅ Fuse.js initialized: ${points.length} points, threshold=${fuseOptions.threshold}`);
            window.PS_DEBUG&&console.log(`[INTRO Popup] ✅ Fuse.js NORMALIZACJA: WŁĄCZONA dla WSZYSTKICH krajów (Ą→a, Ó→o, É→e, Ñ→n, Č→c, etc.)`);
            return fuse;
        } catch (error) {
            window.PS_DEBUG&&console.error('[INTRO Popup] ❌ Błąd inicjalizacji Fuse.js:', error);
            return null;
        }
    }

    function searchPoints(query) {
        // ✅ INSTANT - Input działa natychmiast bez blokowania
        const searchInput = document.getElementById('inpostSearchInput');
        
        // Ukryj loading inputa (bo już wpisano)
        if (searchInput) {
            searchInput.classList.remove('searching');
        }
        
        // Pokaż status mapy OSOBNO
        const mapStatus = document.getElementById('inpostMapStatus');
        if (mapStatus) {
            mapStatus.style.display = 'flex';
        }

        // 🎨 SKELETON LOADERS - Natychmiastowe czyszczenie listy i pokazanie "myślenia"
        showSkeletonList(6);
        
        // 📌 PUSTE POLE → POKAŻ HISTORIĘ KLIKNIĘĆ (zamiast wszystkich punktów)
        if (!query || query.trim() === '') {
            window.PS_DEBUG&&console.log('[INTRO Popup] 📌 Puste pole - pokazuję historię kliknięć');
            showClickHistory();
            if (mapStatus) mapStatus.style.display = 'none';
            return;
        }
        
        // ====================================================================================
        // DEBOUNCE - Czekaj na zakończenie pisania
        // ====================================================================================
        // Użytkownik pisze "Stoczek Łukowski" - każda litera wywołuje ten handler
        // Bez debounce = 18 zapytań (każda litera)
        // Z debounce 500ms = 1 zapytanie (dopiero jak przestanie pisać)
        //
        // DZIAŁANIE:
        //   1. clearTimeout() - anuluje poprzedni timer
        //   2. setTimeout() - ustawia nowy timer na 500ms
        //   3. Jeśli użytkownik pisze dalej → timer się resetuje
        //   4. Jeśli przestanie na 500ms → wykonuje wyszukiwanie
        //
        // WARTOŚĆ: 500ms
        //   - Wystarczająco krótko dla responsywności
        //   - Wystarczająco długo żeby dokończyć pisanie
        //   - Zmniejsza liczbę API calls do Nominatim
        // ====================================================================================
        // Debounce - czekaj 500ms po przestaniu pisać
        clearTimeout(searchDebounceTimer);
        
        searchDebounceTimer = setTimeout(() => {
            performSearchAsync(query);
        }, 500); // 500ms debounce - daj czas na dokończenie pisania
    }
    
    // ==================== ADVANCED TEXT NORMALIZATION ====================
    
    function normalizeText(text) {
        if (!text) return '';
        let normalized = text.toLowerCase();
        normalized = normalized.replace(/\s+/g, ' '); // Usuń wielokrotne spacje
        normalized = normalized.trim();
        normalized = normalized.replace(/[–—―]/g, '-'); // Normalizuj myślniki
        return normalized;
    }
    
    function normalizePolishChars(text) {
        const map = {
            'ą': 'a', 'ć': 'c', 'ę': 'e', 'ł': 'l', 'ń': 'n',
            'ó': 'o', 'ś': 's', 'ź': 'z', 'ż': 'z'
        };
        return text.replace(/[ąćęłńóśźż]/g, char => map[char] || char);
    }
    
    function createSearchTokens(query) {
        const normalized = normalizeText(query);
        const tokens = normalized.split(' ').filter(t => t.length > 0);
        return {
            original: query,
            normalized: normalized,
            tokens: tokens,
            ascii: normalizePolishChars(normalized),
            tokensAscii: normalizePolishChars(normalized).split(' ').filter(t => t.length > 0)
        };
    }
    
    // ==================== NOWA LOGIKA: MIASTO → ZOOM → ULICA ====================
    
    function extractCityAndStreet(query) {
        // 🔍 KROK 0: Wykryj i usuń kod pocztowy (XX-XXX format)
        const postcodeRegex = /\b\d{2}[-\s]?\d{3}\b/g;
        const postcodMatch = query.match(postcodeRegex);
        let queryWithoutPostcode = query.replace(postcodeRegex, ' ').trim();
        
        // 🔍 KROK 1: Sprawdź czy w oryginalnym query jest separator (przecinek, "ul", myślnik, itp.)
        const hasSeparator = /[,;|\-]/.test(queryWithoutPostcode) || /(ul\.|ulica|al\.|aleja)/i.test(queryWithoutPostcode);
        
        // 🔍 KROK 2: Usuń 'ul.' i znormalizuj
        let cleaned = queryWithoutPostcode.replace(/(ul\.|ulica|al\.|aleja)\s*/gi, '');
        cleaned = normalizeText(cleaned);
        
        // 🔍 KROK 3: Usuń przecinki, myślniki, pipe, średniki
        cleaned = cleaned.replace(/[,;|\-]/g, ' ');
        cleaned = cleaned.replace(/\s+/g, ' ').trim();
        
        const tokens = cleaned.split(' ').filter(t => t.length > 0);
        
        // Heurystyka: pierwsze 1-3 tokeny to miasto, reszta to ulica
        let cityTokens = [];
        let streetTokens = [];
        
        if (tokens.length === 1) {
            // "Wrocław" → tylko miasto
            cityTokens = tokens;
        } else if (tokens.length === 2) {
            // ⚠️ KLUCZOWA HEURYSTYKA:
            // Najpierw sprawdź czy to znane dwuczłonowe miasto (np. "Zielona Góra")
            const combined = tokens.join(' ');
            const knownTwoWordCities = ['zielona gora', 'nowy sacz', 'bielsko biala', 
                                        'gorzow wielkopolski', 'biala podlaska', 'nowa sol',
                                        'stara wies', 'kolonia chylice', 'nowa huta', 'stare miasto',
                                        'piotrkow trybunalski', 'tomaszow mazowiecki', 'zielona gora',
                                        'jelenia gora', 'walbrzych stary', 'legnica stare',
                                        'ostrow wielkopolski', 'grudziadz stare', 'grodzisk mazowiecki'];
            const isKnownCity = knownTwoWordCities.some(city => 
                normalizePolishChars(combined).includes(normalizePolishChars(city))
            );
            
            if (isKnownCity) {
                // "Zielona Góra" lub "Zielona Góra ul." → miasto dwuczłonowe
                cityTokens = tokens;
            } else if (hasSeparator) {
                // Jest separator (przecinek, myślnik, "ul") → pierwszy=miasto, drugi=ulica
                cityTokens = [tokens[0]];  // "Wrocław, Grabiszyńska" → miasto: Wrocław
                streetTokens = [tokens[1]]; // ulica: Grabiszyńska
            } else {
                // Brak separatora i nie znane miasto → domyślnie miasto+ulica
                // "Wrocław Grabiszyńska" → domyślnie miasto+ulica
                cityTokens = [tokens[0]];
                streetTokens = [tokens[1]];
            }
        } else if (tokens.length === 3) {
            // "Zielona Góra Dworcowa" → miasto: [Zielona, Góra], ulica: [Dworcowa]
            // lub "Wrocław Grabiszyńska 141" → miasto: [Wrocław], ulica: [Grabiszyńska, 141]
            // Sprawdź czy 2 pierwsze tokeny to znane dwuczłonowe miasto
            const first2 = tokens.slice(0, 2).join(' ');
            const commonCities = ['zielona góra', 'nowy sącz', 'bielsko-biała', 'gorzów wielkopolski', 
                                  'biała podlaska', 'nowa sól', 'stara wieś', 'jastrzębie-zdrój',
                                  'piotrków trybunalski', 'tomaszów mazowiecki', 'jelenia góra',
                                  'ostrów wielkopolski', 'grodzisk mazowiecki'];
            
            if (commonCities.some(city => normalizePolishChars(first2).includes(normalizePolishChars(city).replace(/\-/g, ' ')))) {
                cityTokens = tokens.slice(0, 2);
                streetTokens = tokens.slice(2);
            } else {
                cityTokens = [tokens[0]];
                streetTokens = tokens.slice(1);
            }
        } else {
            // 4+ tokeny
            // "Gorzów Wielkopolski Sikorskiego 95" → [Gorzów, Wielkopolski], [Sikorskiego, 95]
            // "Piotrków Trybunalski Dworcowa" → [Piotrków, Trybunalski], [Dworcowa]
            // "Wrocław ul Grabiszyńska 141" → [Wrocław], [Grabiszyńska, 141]
            const first2 = tokens.slice(0, 2).join(' ');
            const first2Ascii = normalizePolishChars(first2);
            const first3 = tokens.slice(0, 3).join(' ');
            
            // Lista dwuczłonowych miast do sprawdzenia w 4+ tokenach
            const twoWordCitiesFor4Plus = ['gorzow wielkopolski', 'piotrkow trybunalski', 
                                           'tomaszow mazowiecki', 'ostrow wielkopolski',
                                           'zielona gora', 'jelenia gora', 'nowy sacz', 'bielsko biala',
                                           'grodzisk mazowiecki'];
            
            const isTwoWordCity = twoWordCitiesFor4Plus.some(city => 
                first2Ascii.includes(normalizePolishChars(city))
            );
            
            if (isTwoWordCity) {
                cityTokens = tokens.slice(0, 2);
                streetTokens = tokens.slice(2);
            } else {
                cityTokens = [tokens[0]];
                streetTokens = tokens.slice(1);
            }
        }
        
        return {
            city: cityTokens.join(' '),
            street: streetTokens.join(' '),
            cityAscii: normalizePolishChars(cityTokens.join(' ')),
            streetAscii: normalizePolishChars(streetTokens.join(' ')),
            postcode: postcodMatch ? postcodMatch[0] : null // Zapisz wykryty kod pocztowy
        };
    }
    
    function matchScore(searchTokens, targetText) {
        if (!targetText) return 0;
        const target = normalizeText(targetText);
        const targetAscii = normalizePolishChars(target);
        let score = 0;
        
        // Exact match
        if (target === searchTokens.normalized) score += 1000;
        // Starts with
        if (target.startsWith(searchTokens.normalized)) score += 500;
        // All tokens match (CRITICAL dla dwuczłonowych nazw!)
        if (searchTokens.tokens.every(token => target.includes(token))) score += 100 * searchTokens.tokens.length;
        // ASCII version
        if (searchTokens.tokensAscii.every(token => targetAscii.includes(token))) score += 50 * searchTokens.tokensAscii.length;
        // Partial match
        if (searchTokens.tokens.some(token => target.includes(token))) score += 10;
        
        return score;
    }
    
    // ====================================================================================
    // SZYBKIE ZAPYTANIE DLA KODÓW PACZKOMATU (bez czekania na 32k)
    // ====================================================================================
    async function quickSearchAPIForCodes(query) {
        const country = COUNTRIES[currentCountry];
        if (!country) return null;
        
        try {
            // Dla kodów użyj tylko 500 punktów (wystarczy znaleźć 1-2 paczkomaty)
            const baseUrl = country.api.replace(/per_page=\d+/, 'per_page=500');
            
            window.PS_DEBUG&&console.log(`[Quick Search API] 🚀 Szybkie zapytanie dla kodu: ${baseUrl}`);
            const startTime = performance.now();
            
            const response = await fetch(baseUrl);
            const data = await response.json();
            const points = normalizePoints(data.points || data.items || (Array.isArray(data) ? data : []));
            
            const fetchTime = ((performance.now() - startTime) / 1000).toFixed(2);
            window.PS_DEBUG&&console.log(`[Quick Search API] ✅ Pobrano ${points.length} punktów w ${fetchTime}s`);
            
            return points;
        } catch (error) {
            window.PS_DEBUG&&console.error('[Quick Search API] ❌ Błąd:', error);
            return null;
        }
    }
    
    // ====================================================================================
    // GŁÓWNA FUNKCJA WYSZUKIWANIA - Async + Debounce + Performance Monitoring
    // ====================================================================================
    // Obsługuje wszystkie typy wyszukiwań: miasta, ulice, kody pocztowe, kody paczkomatu
    // Wykorzystuje geocoding (Nominatim) dla nazw miejscowości
    //
    // FLOW WYSZUKIWANIA:
    //   1. Sprawdza czy query wygląda jak kod (WAW01M lub 00-001)
    //      → Jeśli TAK: użyj normalnego wyszukiwania InPost (nazwy punktów/kody)
    //      → Jeśli NIE: użyj GEOCODING (Nominatim → współrzędne → zoom)
    //   
    //   2. GEOCODING ŚCIEŻKA (dla miast/miejscowości):
    //      - Wywołuje geocodeAndShowNearby()
    //      - Zoomuje mapę do lokalizacji
    //      - Pokazuje punkty w promieniu 20km
    //      - KONIEC (return - nie szuka dalej)
    //
    //   3. NORMALNE WYSZUKIWANIE (dla kodów):
    //      - Filtruje punkty po name/address/postcode
    //      - Sortuje wyniki (priorytet dla exact match)
    //      - Wyświetla na liście i mapie
    //      - Zoomuje do znalezionych punktów
    //
    // OPTYMALIZACJE:
    //   - Async/await dla płynnego UI
    //   - Performance marks dla diagnostyki
    //   - Chunking dla dużych zbiorów danych
    //   - Debounce 500ms w input handler
    //   - NOWE: Niezależne szybkie API dla wyszukiwania (natychmiastowe wyniki!)
    //
    // BEZPIECZEŃSTWO:
    //   - currentSearchId - anuluje stare wyszukiwania
    //   - isSearching flag - zapobiega równoległym searchom
    //   - Try-catch na wszystkie błędy
    // ====================================================================================
    async function performSearchAsync(query) {
        if (isSearching) {
            window.PS_DEBUG&&console.log('[Search] Poprzednie wyszukiwanie w toku - pomijam');
            return;
        }
        
        // 🚀 OPTYMALIZACJA: Wykryj typ wyszukiwania
        const q = normalizeText(query);
        const extracted = extractCityAndStreet(query);
        
        // Rozdziel: kod paczkomatu vs kod pocztowy
        const normalizedCompact = query.toUpperCase().replace(/\s/g, '');
        const looksLikeLockerCode = /^[A-Z]{3,6}\d/.test(normalizedCompact); // np. WAW01M
        const looksLikePostalCode = /^\d{2}[-\s]?\d{3}/.test(query);         // np. 02-495
        
        // ⚡ GŁÓWNE DANE SIĘ ŁADUJĄ - wybierz strategię:
        if (!allPoints || allPoints.length === 0) {
            window.PS_DEBUG&&console.log('[Search] ⚡ Główne dane się ładują...');
            
            // 🔧 FIX: Jeśli displayedPoints jest dostępne, użyj ich!
            if (displayedPoints && displayedPoints.length > 0) {
                window.PS_DEBUG&&console.log(`[Search] ✅ Użyję displayedPoints (${displayedPoints.length} punktów)`);
                await performSearchOnData(query, displayedPoints);
                return;
            }
            
            // STRATEGIA A: Miasto/ulica → GEOCODING (natychmiastowy!)
            if (!looksLikeLockerCode && !looksLikePostalCode && extracted.city && q.length > 2) {
                window.PS_DEBUG&&console.log('[Search] 🌍 GEOCODING dla miasta (bez czekania na API!)');
                isSearching = true;
                await geocodeAndShowNearby(query, ++currentSearchId);
                isSearching = false;
                return;
            }
            
            // STRATEGIA B: Kod paczkomatu → szybkie API (per_page=500)
            // UWAGA: TYLKO dla kodów paczkomatu, NIE dla kodów pocztowych!
            if (looksLikeLockerCode && !looksLikePostalCode) {
                window.PS_DEBUG&&console.log('[Search] 🚀 Szybkie API dla kodu paczkomatu (500 punktów)');
                
                const listEl = document.getElementById('inpostPointsList');
                if (listEl) {
                    listEl.innerHTML = `
                        <div style="padding:20px;text-align:center;color:#666;">
                            <div style="font-size:32px;margin-bottom:10px;">🔍</div>
                            <div style="font-size:16px;margin-bottom:10px;">Wyszukiwanie kodu...</div>
                        </div>
                    `;
                }
                
                const searchPoints = await quickSearchAPIForCodes(query);
                
                if (!searchPoints || searchPoints.length === 0) {
                    if (listEl) {
                        listEl.innerHTML = `
                            <div style="padding:20px;text-align:center;color:#999;">
                                <div style="font-size:32px;margin-bottom:10px;">⏳</div>
                                <div style="font-size:14px;">Czekaj na pełne dane...</div>
                            </div>
                        `;
                    }
                    return;
                }
                
                window.PS_DEBUG&&console.log(`[Search] ✅ Szybkie API: ${searchPoints.length} punktów`);
                await performSearchOnData(query, searchPoints);
                return;
            }
            
            // STRATEGIA C: Inne (czekaj)
            const listEl = document.getElementById('inpostPointsList');
            if (listEl) {
                listEl.innerHTML = `
                    <div style="padding:20px;text-align:center;color:#999;">
                        <div style="font-size:32px;margin-bottom:10px;">⏳</div>
                        <div style="font-size:14px;">Ładowanie danych...</div>
                        <div style="font-size:12px;margin-top:10px;">Chwila moment...</div>
                    </div>
                `;
            }
            return;
        }
        
        // Główne dane załadowane - użyj ich
        await performSearchOnData(query, allPoints);
    }
    
    const SEARCH_ENGINE_VERSION = 2;

    async function performSearchOnDataV1(query, dataPoints) {
        // Increment search ID - anuluje poprzednie wyszukiwania
        const searchId = ++currentSearchId;
        isSearching = true;

        // 🔬 PERFORMANCE MONITORING
        const perfStart = performance.now();
        performance.mark(`search-${searchId}-start`);

        try {
            const q = normalizeText(query);

            const isCityLikeQuery = /^[a-ząćęłńóśźż\s-]+$/i.test(q) && !/\d/.test(q);

            window.PS_DEBUG&&console.log(`[Search #${searchId}] 🔍 Query: "${query}" (cityLike=${isCityLikeQuery})`);
            window.PS_DEBUG&&console.log(`[Search #${searchId}] 📊 Total points: ${dataPoints.length}`);
            window.PS_DEBUG&&console.log(`[Search #${searchId}] 🔧 Using: ${fuseInstance ? 'Fuse.js (fuzzy search)' : 'Old manual search'}`);

            // ✅ NOWA LOGIKA: Użyj Fuse.js jeśli dostępne,
            //    ALE NIE dla zapytań typowo "miastowych" (np. "Warszawa")
            if (fuseInstance && adminConfig.fuseSearch.enabled && !isCityLikeQuery) {
                performance.mark(`search-${searchId}-filtering-start`);
                window.PS_DEBUG&&console.log(`[Search #${searchId}] 🚀 Fuse.js search started...`);

                // ==================================================================
                // 🛡️ SMART PRE-FILTER: Gdy query zawiera kod pocztowy lub miasto,
                // użyj DOKŁADNEGO filtrowania zamiast fuzzy (KULOODPORNE!)
                // Problemy które to rozwiązuje:
                //   "Warszawa, 02-495, " → BGCH01M z Boguchwałowic (fuzzy na cyfrach)
                //   "Piastów, 05-820" → losowe wyniki (fuzzy nie radzi sobie z przecinkami)
                // ==================================================================
                
                // 1. Wyczyść query z końcowych przecinków, spacji, separatorów
                let cleanQuery = query.replace(/[,;|\s]+$/g, '').trim();
                
                // 2. Wyodrębnij kod pocztowy (XX-XXX lub XXXXX)
                const postcodeMatch = cleanQuery.match(/\b(\d{2})[-\s]?(\d{3})\b/);
                let detectedPostcode = null;
                let detectedPostcodeNorm = null;
                if (postcodeMatch) {
                    detectedPostcode = postcodeMatch[0];
                    detectedPostcodeNorm = postcodeMatch[1] + postcodeMatch[2]; // "02495"
                }
                
                // 3. Wyodrębnij nazwę miasta (tekst bez cyfr, separatorów)
                let detectedCity = cleanQuery
                    .replace(/\b\d{2}[-\s]?\d{3}\b/g, '')  // usuń kod pocztowy
                    .replace(/[,;|]+/g, ' ')                 // przecinki → spacje
                    .replace(/\b(ul\.|ulica|al\.|aleja)\b/gi, '') // usuń "ul."
                    .replace(/\s+/g, ' ')
                    .trim()
                    .toLowerCase();
                let detectedCityAscii = normalizePolishChars(detectedCity);
                
                window.PS_DEBUG&&console.log(`[Search #${searchId}] 🛡️ Smart Pre-Filter: postcode="${detectedPostcode}", city="${detectedCity}"`);
                
                // 4. Jeśli mamy kod pocztowy lub miasto — DOKŁADNE filtrowanie
                if (detectedPostcode || (detectedCity && detectedCity.length >= 3)) {
                    let smartResults = dataPoints;
                    
                    // FILTR A: Kod pocztowy (dokładne dopasowanie)
                    if (detectedPostcodeNorm) {
                        const postcodeFiltered = smartResults.filter(p => {
                            const pc = (p.address_details?.post_code || p.post_code || '').replace(/[-\s.,:]/g, '');
                            return pc === detectedPostcodeNorm;
                        });
                        
                        if (postcodeFiltered.length > 0) {
                            smartResults = postcodeFiltered;
                            window.PS_DEBUG&&console.log(`[Search #${searchId}] 📮 Exact postcode ${detectedPostcode}: ${smartResults.length} punktów`);
                        } else {
                            // Fallback: prefix kodu (np. "02" → wszystkie 02-xxx)
                            const prefix = detectedPostcodeNorm.substring(0, 2);
                            const prefixFiltered = smartResults.filter(p => {
                                const pc = (p.address_details?.post_code || p.post_code || '').replace(/[-\s.,:]/g, '');
                                return pc.startsWith(prefix);
                            });
                            if (prefixFiltered.length > 0) {
                                smartResults = prefixFiltered;
                                window.PS_DEBUG&&console.log(`[Search #${searchId}] 📮 Postcode prefix ${prefix}-xxx: ${smartResults.length} punktów`);
                            }
                        }
                    }
                    
                    // FILTR B: Miasto (zawiera tokeny miasta)
                    if (detectedCity && detectedCity.length >= 3) {
                        const cityTokens = detectedCity.split(' ').filter(t => t.length >= 2);
                        
                        if (cityTokens.length > 0) {
                            const cityFiltered = smartResults.filter(p => {
                                const city = normalizeText(p.address_details?.city || p.city || '');
                                const cityAscii = normalizePolishChars(city);
                                return cityTokens.every(t => city.includes(t) || cityAscii.includes(normalizePolishChars(t)));
                            });
                            
                            if (cityFiltered.length > 0) {
                                smartResults = cityFiltered;
                                window.PS_DEBUG&&console.log(`[Search #${searchId}] 🏙️ City "${detectedCity}": ${smartResults.length} punktów`);
                            }
                        }
                    }
                    
                    // Jeśli smart filter znalazł wyniki — użyj ich zamiast Fuse.js!
                    if (smartResults.length > 0 && smartResults.length < dataPoints.length) {
                        window.PS_DEBUG&&console.log(`[Search #${searchId}] 🛡️ Smart Pre-Filter: ${smartResults.length} wyników (pominięto Fuse.js fuzzy)`);
                        filteredPoints = smartResults;
                        
                        // Sortuj: najpierw dokładny match kodu, potem miasto
                        filteredPoints.sort((a, b) => {
                            let aScore = 0, bScore = 0;
                            const aPC = (a.address_details?.post_code || '').replace(/[-\s.,:]/g, '');
                            const bPC = (b.address_details?.post_code || '').replace(/[-\s.,:]/g, '');
                            const aCity = normalizePolishChars(normalizeText(a.address_details?.city || ''));
                            const bCity = normalizePolishChars(normalizeText(b.address_details?.city || ''));
                            
                            // Exact postcode match
                            if (detectedPostcodeNorm && aPC === detectedPostcodeNorm) aScore += 1000;
                            if (detectedPostcodeNorm && bPC === detectedPostcodeNorm) bScore += 1000;
                            // City match
                            if (detectedCityAscii && aCity.includes(detectedCityAscii)) aScore += 500;
                            if (detectedCityAscii && bCity.includes(detectedCityAscii)) bScore += 500;
                            // Shorter name = more precise
                            aScore -= (a.name || '').length;
                            bScore -= (b.name || '').length;
                            
                            return bScore - aScore;
                        });
                        
                        performance.mark(`search-${searchId}-filtering-end`);
                        const searchTime = performance.now() - perfStart;
                        window.PS_DEBUG&&console.log(`[Search #${searchId}] ⏱️ Smart search: ${searchTime.toFixed(2)}ms, ${filteredPoints.length} results`);
                        performance.mark(`search-${searchId}-sorting-start`);
                        performance.mark(`search-${searchId}-sorting-end`);
                        
                        // >>> SKIP Fuse.js — przejdź do renderowania wyników <<<
                    } else {
                        window.PS_DEBUG&&console.log(`[Search #${searchId}] 🛡️ Smart Pre-Filter: brak wyników, fallback na Fuse.js`);
                        // Kontynuuj do Fuse.js poniżej (filteredPoints nie ustawione)
                        filteredPoints = null;
                    }
                } else {
                    filteredPoints = null; // Brak kodu/miasta — Fuse.js zdecyduje
                }
                
                // ==================================================================
                // FUSE.JS FUZZY SEARCH (tylko jeśli Smart Pre-Filter nie znalazł)
                // ==================================================================
                if (filteredPoints === null) {

                // 🔧 NORMALIZUJ query dla lepszego dopasowania
                // 1. Normalize text (lowercase, trim, spacje)
                // 2. Normalize polskie znaki (ą→a, ł→l etc.)
                // 3. Usuń separatory w kodach pocztowych (XX-XXX → XXXXX)

                let searchQuery = normalizeText(query);
                searchQuery = normalizePolishChars(searchQuery);

                // ✅ Usuń TYLKO skróty ulic: ul., al.
                // NIE usuwaj pełnych słów "aleje", "ulica" - mogą być częścią nazwy!
                // "ul. kościuszki" → "kościuszki"
                // "Aleje Jerozolimskie" → "Aleje Jerozolimskie" (bez zmian!)
                searchQuery = searchQuery.replace(/\b(ul\.|al\.)\s+/gi, '');

                // ✅ Normalizuj przecinki → spacje (dla separatorów)
                // "warszawa, kościuszki" → "warszawa kościuszki"
                searchQuery = searchQuery.replace(/,+/g, ' ').replace(/\s+/g, ' ').trim();

                // ✅ Normalizuj spacje → myślniki dla znanych dwuczłonowych nazw
                // "bielsko biała" → "bielsko-biała"
                const dwuczlonowe = [
                    'bielsko biala', 'jastrzebie zdroj', 'kedzierzyn kozle',
                    'skarzysko kamienna', 'czechowice dziedzice', 'busko zdroj',
                    'krynica zdroj', 'rabka zdroj', 'kudowa zdroj', 'ladek zdroj',
                    'polanica zdroj', 'swieradow zdroj', 'konstancin jeziorna',
                    'czerwionka leszczyny', 'jelcz laskowice', 'boguszow gorce',
                    'golub dobrzyn', 'goczalkowice zdroj', 'jedlnia letnisko',
                    'ilowo osada', 'polczyn zdroj'
                ];
                dwuczlonowe.forEach(nazwa => {
                    const withHyphen = nazwa.replace(/ /g, '-');
                    if (searchQuery.includes(nazwa)) {
                        searchQuery = searchQuery.replace(nazwa, withHyphen);
                    }
                });

                // ✅ Usuń separatory w kodach pocztowych (nawet w kombinacjach!)
                // "warszawa 02-495" → "warszawa 02495"
                searchQuery = searchQuery.replace(/(\d{2})[-\s.,:;](\d{3})/g, '$1$2');

                window.PS_DEBUG&&console.log(`[Search #${searchId}] 🔧 Query normalized: "${query}" → "${searchQuery}"`);

                // 🔴 PRIORYTET: EXACT MATCH dla ID paczkomatu - ZAWSZE PIERWSZY!
                // Jeśli query dokładnie matchuje ID (case-insensitive), zwróć tylko ten punkt
                const queryUpper = query.toUpperCase().trim();
                const exactMatch = allPoints.find(p => p.name && p.name.toUpperCase() === queryUpper);

                let fuseResults;
                if (exactMatch) {
                    window.PS_DEBUG&&console.log(`[Search #${searchId}] 🎯 EXACT MATCH dla ID: ${exactMatch.name} - PRIORYTET!`);
                    // Zwróć exact match jako pierwszy z score 0.000
                    fuseResults = [{ item: exactMatch, score: 0.000 }];
                } else {
                    // 🎯 TOKENIZACJA dla kombinacji (miasto + ulica)
                    // Jeśli query ma 2+ słowa (nie licząc kodów), użyj tokenizacji
                    const tokens = searchQuery.split(/\s+/).filter(t => t.length >= 2);
                    const hasMultipleWords = tokens.length >= 2;
                    const hasCity = tokens.some(t => t.length >= 4); // Zakładamy że miasta mają min 4 znaki

                    if (hasMultipleWords && hasCity) {
                        window.PS_DEBUG&&console.log(`[Search #${searchId}] 🔀 Tokenizacja: ${tokens.length} tokenów`);

                        // Szukaj z Fuse.js
                        fuseResults = fuseInstance.search(searchQuery);

                        // 🎯 RE-SCORE: AGRESYWNY boost dla punktów gdzie miasto dokładnie matchuje
                        const cityTokens = tokens.filter(t => t.length >= 4); // Potencjalne miasta

                        window.PS_DEBUG&&console.log(`[Search #${searchId}] 🏙️ City tokens:`, cityTokens);

                        fuseResults = fuseResults.map(result => {
                            const city = result.item.address_details?.city || '';
                            const cityNorm = normalizePolishChars(normalizeText(city));

                            // 🎯 MULTI-TOKEN MATCHING: Wspiera 4-słowne miejscowości
                            // Przykład: "Nowe Miasto nad Pilicą"
                            // tokens: ["nowe", "miasto", "pilica"]
                            // cityNorm: "nowe miasto nad pilica"

                            let cityMatch = false;
                            let matchType = '';

                            // 1️⃣ EXACT SINGLE TOKEN MATCH (dla 1-słownych: "Warszawa")
                            if (cityTokens.some(token => cityNorm === token)) {
                                cityMatch = true;
                                matchType = 'exact-single';
                            }

                            // 2️⃣ JOINED TOKENS MATCH (dla wielosłownych: "Nowe Miasto Pilicą")
                            // Sprawdź czy połączone tokeny matchują miasto
                            if (!cityMatch && cityTokens.length >= 2) {
                                const joinedTokens = cityTokens.join(' ');
                                if (cityNorm === joinedTokens ||
                                    cityNorm.startsWith(joinedTokens + ' ') ||
                                    joinedTokens.startsWith(cityNorm + ' ')) {
                                    cityMatch = true;
                                    matchType = 'joined-tokens';
                                }
                            }

                            // 3️⃣ ALL TOKENS PRESENT (dla częściowych: "Nowe", "Miasto", "Pilica" w "Nowe Miasto nad Pilicą")
                            // Wszystkie tokeny muszą być obecne w nazwie miasta
                            if (!cityMatch && cityTokens.length >= 2) {
                                const allTokensPresent = cityTokens.every(token =>
                                    cityNorm.includes(token)
                                );

                                // Dodatkowo: większość tokenów musi matchować (min 60%)
                                const matchedCount = cityTokens.filter(t => cityNorm.includes(t)).length;
                                const matchPercentage = matchedCount / cityTokens.length;

                                if (allTokensPresent && matchPercentage >= 0.6) {
                                    cityMatch = true;
                                    matchType = 'all-tokens-present';
                                }
                            }

                            if (cityMatch) {
                                window.PS_DEBUG&&console.log(`[Search #${searchId}] ✅ City match (${matchType}): tokens="${cityTokens.join(' ')}" → city="${cityNorm}" (${result.item.name})`);
                            }

                            if (cityMatch) {
                                // MEGA BOOST! 90% boost dla exact city match
                                return {
                                    ...result,
                                    score: result.score * 0.1, // 90% boost!
                                    boosted: true,
                                    cityMatched: city
                                };
                            }
                            return result;
                        });

                        // Re-sort po nowym score
                        fuseResults.sort((a, b) => a.score - b.score);

                        const boostedCount = fuseResults.filter(r => r.boosted).length;
                        window.PS_DEBUG&&console.log(`[Search #${searchId}] ✨ Re-scored: ${boostedCount} boosted`);

                        // Jeśli mamy boosted results, priorytetyzuj je
                        if (boostedCount > 0) {
                            window.PS_DEBUG&&console.log(`[Search #${searchId}] 🎯 Top 3 after boost:`,
                                fuseResults.slice(0, 3).map(r => ({
                                    name: r.item.name,
                                    city: r.item.address_details?.city,
                                    score: r.score.toFixed(3),
                                    boosted: r.boosted || false
                                }))
                            );
                        }
                    } else {
                        fuseResults = fuseInstance.search(searchQuery);
                    }
                }

                if ((!fuseResults || fuseResults.length === 0) && searchQuery && searchQuery.length >= 3) {
                    const fallbackResults = [];
                    const q = searchQuery;
                    for (let i = 0; i < allPoints.length; i++) {
                        const p = allPoints[i];
                        const city = p.address_details && p.address_details.city ? p.address_details.city : '';
                        const street = p.address_details && p.address_details.street ? p.address_details.street : '';
                        const name = p.name || '';
                        let postCode = p.address_details && p.address_details.post_code ? p.address_details.post_code : '';
                        postCode = postCode.replace(/[-\s.,:]/g, '');
                        let combined = name + ' ' + city + ' ' + street + ' ' + postCode;
                        combined = normalizePolishChars(normalizeText(combined)).replace(/\s+/g, ' ').trim();
                        if (combined.includes(q)) {
                            fallbackResults.push({ item: p, score: 0.5 });
                        }
                    }
                    fuseResults = fallbackResults;
                }

                window.PS_DEBUG&&console.log(`[Search #${searchId}] ✅ Fuse.js found ${fuseResults.length} results`);

                // Wyciągnij punkty z wyników Fuse (Fuse zwraca {item: punkt, score: ...})
                filteredPoints = fuseResults.map(r => r.item);

                // ✅ BRAK filtrowania po kraju - dane są już z country-specific API!

                performance.mark(`search-${searchId}-filtering-end`);
                const searchTime2 = performance.now() - perfStart;
                window.PS_DEBUG&&console.log(`[Search #${searchId}] ⏱️  Search completed: ${searchTime2.toFixed(2)}ms`);
                window.PS_DEBUG&&console.log(`[Search #${searchId}] 🎯 Results: ${filteredPoints.length} points`);

                // Dummy marks dla sorting (Fuse.js robi to automatycznie)
                performance.mark(`search-${searchId}-sorting-start`);
                performance.mark(`search-${searchId}-sorting-end`);
                
                } // END: if (filteredPoints === null) — Fuse.js fallback
                
            } else {
                // FALLBACK: Stara logika (jeśli Fuse.js nie dostępne)
                window.PS_DEBUG&&console.log(`[Search #${searchId}] ⚠️  Fuse.js not available - using old search`);

                // 🎯 WYODRĘBNIJ miasto i ulicę
                const extracted = extractCityAndStreet(query);

                window.PS_DEBUG&&console.log(`[Search #${searchId}] 🏙️  Extracted City: "${extracted.city}"`);
                window.PS_DEBUG&&console.log(`[Search #${searchId}] 🏠 Extracted Street: "${extracted.street}"`);
                window.PS_DEBUG&&console.log(`[Search #${searchId}] 📮 Extracted Postcode: "${extracted.postcode || 'none'}"`);

                // 🌍 GEOCODING PRIORYTET: Dla nazw miejsc (nie kodów) użyj Nominatim
                const looksLikeCode = /^[A-Z]{3,6}\d/.test(query.toUpperCase().replace(/\s/g, '')) || // WAW01M
                                      /^\d{2}[-\s]?\d{3}/.test(query); // 00-001

                if (!looksLikeCode && extracted.city && q.length > 2) {
                    window.PS_DEBUG&&console.log(`[Search #${searchId}] 🌍 Geocoding dla: "${query}"`);
                    await geocodeAndShowNearby(query, searchId);
                    isSearching = false;
                    return;
                }
                }

            // ✅ KONIEC LOGIKI FUSE.JS - pomiń stare filtrowanie
            if (!fuseInstance || !adminConfig.fuseSearch.enabled) {
                // Yield dla UI - pozwól interfejsowi się odświeżyć
                await new Promise(resolve => setTimeout(resolve, 0));

                const extracted = extractCityAndStreet(query); // Define extracted for old logic

                if (!q) {
                    // ⚡ OPTYMALIZACJA: nie pokazuj wszystkich punktów przy pustym query
                    filteredPoints = [];
                    window.PS_DEBUG&&console.log(`[Search #${searchId}] ⚪ Empty query - showing no points (optimization)`);
                    // Pokaż hint
                    const listEl = document.getElementById('inpostPointsList');
                    if (listEl) {
                        listEl.innerHTML = `
                            <div style="padding:20px;text-align:center;color:#666;">
                                <div style="font-size:32px;margin-bottom:10px;">🔍</div>
                                <div style="font-size:16px;margin-bottom:10px;">Rozpocznij wyszukiwanie</div>
                                <div style="font-size:13px;">Wpisz miasto, ulicę, kod pocztowy lub kod paczkomatu</div>
                            </div>
                        `;
                    }
                } else {
                    performance.mark(`search-${searchId}-filtering-start`);
                
                // 🎯 NOWA LOGIKA: MIASTO → ZOOM → ULICA
                
                // KROK 1: Znajdź wszystkie punkty w mieście
                let cityMatches = [];
                
                if (extracted.city) {
                    cityMatches = dataPoints.filter(p => {
                        const city = p.address_details?.city || p.city || '';
                        const cityNorm = normalizeText(city);
                        const cityAscii = normalizePolishChars(cityNorm);
                        
                        // Dopasowanie: zawiera wszystkie tokeny miasta
                        return extracted.city.split(' ').every(token => cityNorm.includes(token)) ||
                               extracted.cityAscii.split(' ').every(token => cityAscii.includes(token));
                    });
                    
                    window.PS_DEBUG&&console.log(`[Search #${searchId}] 🏙️  Found ${cityMatches.length} points in city "${extracted.city}"`);
                    
                    // KROK 1.5: Jeśli był kod pocztowy w query, filtruj dodatkowo po nim
                    if (extracted.postcode && cityMatches.length > 0) {
                        const normalizePostCode = (str) => str.replace(/[-\s:]/g, '');
                        const postcodeNormalized = normalizePostCode(extracted.postcode);
                        
                        const postcodeFiltered = cityMatches.filter(p => {
                            const postCode = p.address_details?.post_code || p.post_code || '';
                            const postCodeNormalized = normalizePostCode(postCode);
                            return postCodeNormalized === postcodeNormalized;
                        });
                        
                        if (postcodeFiltered.length > 0) {
                            cityMatches = postcodeFiltered;
                            window.PS_DEBUG&&console.log(`[Search #${searchId}] 📮 Filtered by postcode "${extracted.postcode}": ${cityMatches.length} points`);
                        }
                    }
                }
                
                // KROK 2: Jeśli jest ulica, filtruj po ulicy
                let finalMatches = cityMatches;
                
                if (extracted.street && cityMatches.length > 0) {
                    finalMatches = cityMatches.filter(p => {
                        const street = p.address_details?.street || p.street || '';
                        const streetNorm = normalizeText(street);
                        const streetAscii = normalizePolishChars(streetNorm);
                        
                        // Wyodrębnij tylko nazwę ulicy (bez numeru) z query
                        const streetTokens = extracted.street.split(' ').filter(t => !/^\d+$/.test(t)); // Usuń tokeny będące tylko liczbami
                        const streetQuery = streetTokens.join(' ');
                        const streetQueryAscii = normalizePolishChars(streetQuery);
                        
                        // Dopasowanie ulicy (ignoruj znaki, spacje, liczby)
                        // Sprawdź czy WSZYSTKIE tokeny ulicy z query są w nazwie ulicy (np. "Zaczarowanej Dorożki")
                        const matchesNormal = streetTokens.every(token => streetNorm.includes(token));
                        const matchesAscii = streetTokens.map(t => normalizePolishChars(t)).every(token => streetAscii.includes(token));
                        
                        return matchesNormal || matchesAscii;
                    });
                    
                    window.PS_DEBUG&&console.log(`[Search #${searchId}] 🏠 Filtered by street: ${finalMatches.length} points`);
                }
                
                // KROK 3: Jeśli nie znaleziono po mieście, spróbuj po kodzie pocztowym, nazwie lub ULICY
                if (cityMatches.length === 0) {
                    window.PS_DEBUG&&console.log(`[Search #${searchId}] 🔍 No city match, trying postcode/name/street...`);
                    
                    const normalizePostCode = (str) => str.replace(/[-\s:]/g, '');
                    const qNormalized = normalizePostCode(q);
                    
                    // Wyodrębnij tokeny z CAŁEGO query (może to być dwuczłonowa ulica jak "Szarchy Szeregów")
                    const queryTokens = query.replace(/(ul\.|ulica|al\.|aleja)\s*/gi, '') // Usuń "ul."
                                             .split(' ')
                                             .map(t => normalizeText(t))
                                             .filter(t => t.length > 0 && !/^\d+$/.test(t)); // Bez liczb
                    
                    window.PS_DEBUG&&console.log(`[Search #${searchId}] 🔍 Trying street tokens: [${queryTokens.join(', ')}]`);
                    
                    finalMatches = dataPoints.filter(p => {
                        const name = p.name || '';
                        const postCode = p.address_details?.post_code || p.post_code || '';
                        const postCodeNormalized = normalizePostCode(postCode);
                        const street = p.address_details?.street || p.street || '';
                        const streetNorm = normalizeText(street);
                        const streetAscii = normalizePolishChars(streetNorm);
                        
                        // Match po nazwie paczkomatu
                        const nameMatch = normalizeText(name).includes(q);
                        
                        // Match po kodzie pocztowym
                        const postcodeMatch = qNormalized && postCodeNormalized.includes(qNormalized);
                        
                        // Match po ulicy - wszystkie tokeny muszą być w nazwie ulicy
                        const streetMatch = queryTokens.length > 0 && 
                                          queryTokens.every(token => streetNorm.includes(token) || 
                                                                     streetAscii.includes(normalizePolishChars(token)));
                        
                        return nameMatch || postcodeMatch || streetMatch;
                    });
                    
                    window.PS_DEBUG&&console.log(`[Search #${searchId}] 📮 Found ${finalMatches.length} by postcode/name/street`);
                }
                
                // Sortowanie: jeśli jest ulica, priorytet dla dokładnego match ulicy
                if (extracted.street && finalMatches.length > 1) {
                    // 🔢 Usuń liczby z query ulicy (tak jak w matching)
                    const streetTokens = extracted.street.split(' ').filter(t => !/^\d+$/.test(t));
                    const streetQueryClean = streetTokens.join(' ');
                    const streetQueryCleanAscii = normalizePolishChars(streetQueryClean);
                    
                    window.PS_DEBUG&&console.log(`[Search #${searchId}] 🔢 Sortowanie po ulicy: "${streetQueryClean}" (${streetTokens.length} tokenów)`);
                    
                    finalMatches.sort((a, b) => {
                        const aStreet = normalizePolishChars(normalizeText(a.address_details?.street || a.street || ''));
                        const bStreet = normalizePolishChars(normalizeText(b.address_details?.street || b.street || ''));
                        
                        // SCORING: im więcej tokenów pasuje + im dokładniejsze dopasowanie, tym wyższy score
                        let aScore = 0;
                        let bScore = 0;
                        
                        // Sprawdź ile tokenów pasuje
                        const aMatchingTokens = streetTokens.filter(token => aStreet.includes(normalizePolishChars(token))).length;
                        const bMatchingTokens = streetTokens.filter(token => bStreet.includes(normalizePolishChars(token))).length;
                        
                        aScore += aMatchingTokens * 100; // Każdy pasujący token = +100
                        bScore += bMatchingTokens * 100;
                        
                        // Bonus za dokładne dopasowanie całej frazy
                        if (aStreet.includes(streetQueryCleanAscii)) aScore += 1000;
                        if (bStreet.includes(streetQueryCleanAscii)) bScore += 1000;
                        
                        // Bonus za krótszą nazwę (bardziej precyzyjna)
                        aScore += (100 - aStreet.length);
                        bScore += (100 - bStreet.length);
                        
                        return bScore - aScore; // Wyższy score na górze
                    });
                }
                
                // 🌍 FIX 2026-01-19: ZAWĘŻENIE DO KRAJU
                // Wyświetlaj TYLKO punkty z aktywnego kraju (np. PL w Polsce, ES w Hiszpanii)
                // To naprawia problem pokazywania polskich punktów na mapie Hiszpanii
                const currentCountryCode = COUNTRIES[currentCountry]?.flagCode;
                if (currentCountryCode) {
                    finalMatches = finalMatches.filter(point => {
                        // Sprawdź address_details.country_code (używane przez parcelselector.com API)
                        const pointCountry = point.address_details?.country_code || point.country;
                        return pointCountry === currentCountryCode;
                    });
                    window.PS_DEBUG&&console.log(`[Search #${searchId}] 🌍 Zawężono do kraju ${currentCountryCode}: ${finalMatches.length} punktów`);
                }
                
                filteredPoints = finalMatches;
                
                // Zapisz typ wyszukiwania
                if (extracted.street && finalMatches.length > 0) {
                    window.lastSearchType = 'CITY+STREET';
                } else if (extracted.city && finalMatches.length > 0) {
                    window.lastSearchType = 'CITY';
                } else {
                    window.lastSearchType = 'OTHER';
                }
                
                performance.mark(`search-${searchId}-filtering-end`);
                const filteringTime = performance.now() - perfStart;
                    window.PS_DEBUG&&console.log(`[Search #${searchId}] ⏱️ Filtering completed: ${Math.round(filteringTime)}ms`);
                    window.PS_DEBUG&&console.log(`[Search #${searchId}] 🎯 Results: ${filteredPoints.length} points`);
                    window.PS_DEBUG&&console.log(`[Search #${searchId}] 📍 Type: ${window.lastSearchType}`);
                }
            } // END: Old search logic (only if Fuse.js not available)

            // Check if cancelled
            if (searchId !== currentSearchId) {
                window.PS_DEBUG&&console.log(`[Search #${searchId}] ❌ CANCELLED before rendering`);
                return;
            }
            
            // Aktualizacja licznika
            performance.mark(`search-${searchId}-ui-update-start`);
            const countEl = document.getElementById('inpostPointsCount');
            if (countEl) {
                countEl.textContent = filteredPoints.length;
                countEl.style.animation = 'none';
                requestAnimationFrame(() => {
                    countEl.style.animation = 'countUpdate 0.3s ease';
                });
            }
            
            // "Brak wyników"
            if (filteredPoints.length === 0 && q) {
                showNoResultsMessage(query);
            } else {
                hideNoResultsMessage();
            }
            performance.mark(`search-${searchId}-ui-update-end`);
            
            // 🎨 BATCH RENDERING - renderuj listę i markery w porcjach
            performance.mark(`search-${searchId}-rendering-start`);
            await renderSearchResultsBatched(filteredPoints, searchId);
            performance.mark(`search-${searchId}-rendering-end`);
            
            // Check if cancelled
            if (searchId !== currentSearchId) {
                window.PS_DEBUG&&console.log(`[Search #${searchId}] ❌ CANCELLED before map centering`);
                return;
            }
            
            // Centruj mapę
            performance.mark(`search-${searchId}-map-center-start`);
            if (filteredPoints.length > 0) {
                centerMapOnResults(filteredPoints, window.lastSearchType || null);
            } else if (q) {
                // 🗺️ FALLBACK: Nic nie znaleziono
                window.PS_DEBUG&&console.log(`[Search #${searchId}] ⚠️ Brak wyników dla: "${query}"`);
                
                // Pokaż komunikat
                const listEl = document.getElementById('inpostPointsList');
                if (listEl) {
                    listEl.innerHTML = `
                        <div style="padding:20px;text-align:center;color:#666;">
                            <div style="font-size:32px;margin-bottom:10px;">🔍</div>
                            <div style="font-size:16px;margin-bottom:10px;">${getTranslation('noResults')}</div>
                            <div style="font-size:13px;">${getTranslation('noResultsFor')} "${query}"</div>
                        </div>
                    `;
                }
            }
            performance.mark(`search-${searchId}-map-center-end`);
            
            // 📊 FINAL PERFORMANCE SUMMARY
            const perfEnd = performance.now();
            const totalTime = Math.round(perfEnd - perfStart);
            
            performance.measure(`search-${searchId}-total`, `search-${searchId}-start`, `search-${searchId}-map-center-end`);
            performance.measure(`search-${searchId}-filtering`, `search-${searchId}-filtering-start`, `search-${searchId}-filtering-end`);
            performance.measure(`search-${searchId}-sorting`, `search-${searchId}-sorting-start`, `search-${searchId}-sorting-end`);
            performance.measure(`search-${searchId}-ui-update`, `search-${searchId}-ui-update-start`, `search-${searchId}-ui-update-end`);
            performance.measure(`search-${searchId}-rendering`, `search-${searchId}-rendering-start`, `search-${searchId}-rendering-end`);
            performance.measure(`search-${searchId}-map-center`, `search-${searchId}-map-center-start`, `search-${searchId}-map-center-end`);
            
            const measures = performance.getEntriesByName(`search-${searchId}-total`);
            if (measures.length > 0) {
                window.PS_DEBUG&&console.log(`[Search #${searchId}] ═══════════════════════════════`);
                window.PS_DEBUG&&console.log(`[Search #${searchId}] 📊 PERFORMANCE SUMMARY`);
                window.PS_DEBUG&&console.log(`[Search #${searchId}] ═══════════════════════════════`);
                window.PS_DEBUG&&console.log(`[Search #${searchId}] ⏱️  Total Time: ${totalTime}ms`);
                
                const breakdown = {};
                performance.getEntriesByType('measure').forEach(m => {
                    if (m.name.startsWith(`search-${searchId}`)) {
                        const name = m.name.replace(`search-${searchId}-`, '');
                        breakdown[name] = Math.round(m.duration);
                    }
                });
                
                window.PS_DEBUG&&console.log(`[Search #${searchId}]    ├─ Filtering: ${breakdown.filtering}ms (${Math.round(breakdown.filtering/totalTime*100)}%)`);
                window.PS_DEBUG&&console.log(`[Search #${searchId}]    ├─ Sorting: ${breakdown.sorting}ms (${Math.round(breakdown.sorting/totalTime*100)}%)`);
                window.PS_DEBUG&&console.log(`[Search #${searchId}]    ├─ UI Update: ${breakdown['ui-update']}ms (${Math.round(breakdown['ui-update']/totalTime*100)}%)`);
                window.PS_DEBUG&&console.log(`[Search #${searchId}]    ├─ Rendering: ${breakdown.rendering}ms (${Math.round(breakdown.rendering/totalTime*100)}%)`);
                window.PS_DEBUG&&console.log(`[Search #${searchId}]    └─ Map Center: ${breakdown['map-center']}ms (${Math.round(breakdown['map-center']/totalTime*100)}%)`);
                
                // Performance rating
                let rating = '🟢 EXCELLENT';
                if (totalTime > 1000) rating = '🔴 SLOW';
                else if (totalTime > 500) rating = '🟡 ACCEPTABLE';
                
                window.PS_DEBUG&&console.log(`[Search #${searchId}] 🎯 Rating: ${rating}`);
                window.PS_DEBUG&&console.log(`[Search #${searchId}] ═══════════════════════════════`);
                
                // Identify bottlenecks
                const bottleneck = Object.entries(breakdown).reduce((max, [key, val]) => 
                    val > max.val ? { key, val } : max, { key: '', val: 0 }
                );
                
                if (bottleneck.val > totalTime * 0.5) {
                    window.PS_DEBUG&&console.log(`[Search #${searchId}] ⚠️  BOTTLENECK DETECTED: ${bottleneck.key} (${bottleneck.val}ms)`);
                }
            }
            
            // Cleanup performance marks
            performance.clearMarks();
            performance.clearMeasures();
            
            window.PS_DEBUG&&console.log(`[Search #${searchId}] ✅ COMPLETED`);
            
        } catch (error) {
            window.PS_DEBUG&&console.error(`[Search #${searchId}] ❌ ERROR:`, error);
            window.PS_DEBUG&&console.error(`[Search #${searchId}] Stack:`, error.stack);
        } finally {
            isSearching = false;
            
            const mapStatus = document.getElementById('inpostMapStatus');
            if (mapStatus) {
                mapStatus.style.display = 'none';
            }
        }
    }

    async function performSearchOnData(query, dataPoints) {
        if (SEARCH_ENGINE_VERSION === 2 && window.InpostSearchEngine && typeof window.InpostSearchEngine.search === 'function') {
            const searchId = ++currentSearchId;
            isSearching = true;
            const perfStart = performance.now();
            performance.mark(`search-${searchId}-start`);
            try {
                const countryCode = COUNTRIES[currentCountry]?.flagCode || null;
                const result = window.InpostSearchEngine.search(dataPoints, query, {
                    countryCode: countryCode,
                    limit: 500
                });
                filteredPoints = result.results || [];
                const meta = result.meta || {};
                window.lastSearchType = meta.type || null;
                performance.mark(`search-${searchId}-filtering-end`);

                const countEl = document.getElementById('inpostPointsCount');
                if (countEl) {
                    countEl.textContent = filteredPoints.length;
                    countEl.style.animation = 'none';
                    requestAnimationFrame(() => {
                        countEl.style.animation = 'countUpdate 0.3s ease';
                    });
                }

                if (meta.conflict) {
                    const container = document.querySelector('.inpost-search-container');
                    if (container) {
                        let toast = container.querySelector('.inpost-search-conflict');
                        if (!toast) {
                            toast = document.createElement('div');
                            toast.className = 'inpost-search-conflict';
                            toast.style.position = 'relative';
                            toast.style.marginTop = '4px';
                            toast.style.fontSize = '11px';
                            toast.style.color = '#aa6600';
                            toast.style.textAlign = 'center';
                            container.appendChild(toast);
                        }
                        toast.textContent = 'Mamy sprzeczne informacje w zapytaniu. Podaj sam kod pocztowy lub nazwę miejscowości.';
                        setTimeout(() => {
                            if (toast && toast.parentNode) {
                                toast.parentNode.removeChild(toast);
                            }
                        }, 3000);
                    }
                }

                const q = normalizeText(query);
                if (filteredPoints.length === 0 && q) {
                    showNoResultsMessage(query);
                } else {
                    hideNoResultsMessage();
                }

                performance.mark(`search-${searchId}-rendering-start`);
                await renderSearchResultsBatched(filteredPoints, searchId);
                performance.mark(`search-${searchId}-rendering-end`);

                if (searchId !== currentSearchId) {
                    return;
                }

                performance.mark(`search-${searchId}-map-center-start`);
                if (filteredPoints.length > 0) {
                    centerMapOnResults(filteredPoints, window.lastSearchType || null);
                } else if (q) {
                    const listEl = document.getElementById('inpostPointsList');
                    if (listEl) {
                        listEl.innerHTML = `
                            <div style="padding:20px;text-align:center;color:#666;">
                                <div style="font-size:32px;margin-bottom:10px;">🔍</div>
                                <div style="font-size:16px;margin-bottom:10px;">${getTranslation('noResults')}</div>
                                <div style="font-size:13px;">${getTranslation('noResultsFor')} "${query}"</div>
                            </div>
                        `;
                    }
                }
                performance.mark(`search-${searchId}-map-center-end`);

                const perfEnd = performance.now();
                const totalTime = Math.round(perfEnd - perfStart);
                window.PS_DEBUG&&console.log(`[Search #${searchId}] Total time: ${totalTime}ms, results: ${filteredPoints.length}, type: ${window.lastSearchType || 'NONE'}`);
            } catch (error) {
                window.PS_DEBUG&&console.error('[Search V2] ERROR:', error);
            } finally {
                isSearching = false;
                const mapStatus = document.getElementById('inpostMapStatus');
                if (mapStatus) {
                    mapStatus.style.display = 'none';
                }
            }
            return;
        }
        return performSearchOnDataV1(query, dataPoints);
    }
    
    // 🎨 BATCH RENDERING - renderuj w małych porcjach
    async function renderSearchResultsBatched(points, searchId) {
        window.PS_DEBUG&&console.log(`[Render #${searchId}] Start batch rendering: ${points.length} punktów`);
        
        // LIMIT - maksymalnie 500 markerów dla wydajności
        const MAX_MARKERS = 500;
        const pointsToRender = points.slice(0, MAX_MARKERS);
        
        if (points.length > MAX_MARKERS) {
            window.PS_DEBUG&&console.log(`[Render #${searchId}] LIMIT: renderuję ${MAX_MARKERS} z ${points.length}`);
            
            // Pokaż info użytkownikowi
            const listEl = document.getElementById('inpostPointsList');
            if (listEl && listEl.firstChild) {
                const infoDiv = document.createElement('div');
                infoDiv.className = 'marker-limit-info';
                infoDiv.innerHTML = `
                    <div style="background: #FFF5F0; padding: 12px; margin: 10px; border-radius: 8px; border-left: 3px solid #FF6600; font-size: 13px;">
                        ⚠️ <strong>Uwaga:</strong> Wyświetlono ${MAX_MARKERS} z ${points.length} paczkomatów.<br>
                        <small>Użyj bardziej szczegółowego wyszukiwania (np. dodaj ulicę lub kod pocztowy)</small>
                    </div>
                `;
                listEl.insertBefore(infoDiv, listEl.firstChild);
            }
        }
        
        // Wyczyść markery
        clearMarkers();
        
        // Check if cancelled
        if (searchId !== currentSearchId) return;
        
        // Dodaj markery w porcjach
        const MARKER_CHUNK = 100; // 100 markerów na raz (zoptymalizowane)
        for (let i = 0; i < pointsToRender.length; i += MARKER_CHUNK) {
            if (searchId !== currentSearchId) return;
            
            const chunk = pointsToRender.slice(i, i + MARKER_CHUNK);
            addMarkers(chunk);
            
            // Yield co chunk
            await new Promise(resolve => setTimeout(resolve, 0));
        }
        
        // Yield
        await new Promise(resolve => setTimeout(resolve, 0));
        
        // Check if cancelled
        if (searchId !== currentSearchId) return;
        
        // Renderuj listę (limit 100)
        displayPointsList(points);
        
        window.PS_DEBUG&&console.log(`[Render #${searchId}] ✅ Batch rendering zakończony`);
    }

    // ====================
    // LAZY LOADING - ŁADOWANIE PUNKTÓW PRZY ZOOMIE
    // ====================
    function onMapViewChange() {
        if (!adminConfig.lazyLoadOnZoom) return;
        if (!map) return;
        
        const newZoom = map.getZoom();
        
        // Ładuj dodatkowe punkty TYLKO przy zbliżeniu (zoom IN), NIE przy scrollowaniu!
        if (newZoom > currentZoomLevel) {
            const bounds = map.getBounds();
            
            // 🔧 FIX: Użyj allPoints jeśli dostępne, jeśli nie - pomiń lazy loading
            const dataSource = allPoints && allPoints.length > 0 ? allPoints : [];
            
            if (dataSource.length === 0) {
                window.PS_DEBUG&&console.log(`[INTRO Popup] ⏸️ Lazy loading: brak allPoints (ładowanie w tle)`);
                currentZoomLevel = newZoom;
                return;
            }
            
            // Filtruj punkty w viewport
            const visiblePoints = dataSource.filter(point => {
                if (!point.location) return false;
                const lat = point.location.latitude;
                const lng = point.location.longitude;
                return bounds.contains([lat, lng]);
            });
            
            // Znajdź punkty które jeszcze nie są wyświetlone
            const newPoints = visiblePoints.filter(p => 
                !displayedPoints.some(dp => dp.name === p.name)
            );
            
            // LIMIT: Ładuj max 500 punktów na raz (żeby nie przeciążyć przeglądarki)
            const maxPerLoad = 500;
            const pointsToAdd = newPoints.slice(0, maxPerLoad);
            
            if (pointsToAdd.length > 0) {
                window.PS_DEBUG&&console.log(`[INTRO Popup] 🔥 Lazy load (ZOOM ${currentZoomLevel}→${newZoom}): dodaję ${pointsToAdd.length} z ${newPoints.length} nowych punktów (było: ${displayedPoints.length})`);
                
                // 🔧 FIX: Blokuj viewport culling podczas lazy loading
                isLazyLoadingInProgress = true;
                
                // Dodaj nowe punkty do wyświetlonych
                displayedPoints = [...displayedPoints, ...pointsToAdd];
                
                // OPTYMALIZACJA: Dodaj TYLKO nowe markery
                addMarkers(pointsToAdd);
                
                // 🔧 FIX: Odblokuj viewport culling po 500ms
                setTimeout(() => {
                    isLazyLoadingInProgress = false;
                    window.PS_DEBUG&&console.log('[INTRO Popup] ✅ Lazy loading zakończony - viewport culling odblokowany');
                }, 500);
                
                window.PS_DEBUG&&console.log(`[INTRO Popup] ✅ Teraz wyświetlam: ${displayedPoints.length} punktów (pozostało ${newPoints.length - pointsToAdd.length} ukrytych)`);
                
                // Aktualizuj listę (jeśli nie ma filtra)
                if (!document.getElementById('inpostSearchInput').value) {
                    displayPointsList(displayedPoints);
                }
            }
        }
        
        currentZoomLevel = newZoom;
    }

    // ====================
    // VIEWPORT CULLING - WYŚWIETLANIE TYLKO WIDOCZNYCH MARKERÓW
    // ====================
    let isZoomAnimationInProgress = false; // Flag: czy trwa animacja zoom
    let isLazyLoadingInProgress = false;   // Flag: czy trwa lazy loading
    
    function updateVisibleMarkers() {
        if (!adminConfig.viewportCulling) return;
        if (!map || markers.length === 0) return;
        
        // 🔧 FIX: NIE UKRYWAJ podczas animacji zoom!
        if (isZoomAnimationInProgress) {
            window.PS_DEBUG&&console.log('[INTRO Popup] ⏸️ Viewport culling wstrzymany (trwa animacja)');
            return;
        }
        
        // 🔧 FIX: NIE UKRYWAJ podczas lazy loading!
        if (isLazyLoadingInProgress) {
            window.PS_DEBUG&&console.log('[INTRO Popup] ⏸️ Viewport culling wstrzymany (trwa lazy loading)');
            return;
        }
        
        const bounds = map.getBounds();
        let visibleCount = 0;
        let hiddenCount = 0;
        
        markers.forEach(marker => {
            if (!marker.pointData || !marker.pointData.location) return;
            
            const lat = marker.pointData.location.latitude;
            const lng = marker.pointData.location.longitude;
            const isVisible = bounds.contains([lat, lng]);
            
            if (isVisible) {
                // Marker w viewport - pokaż
                if (!map.hasLayer(marker)) {
                    if (adminConfig.enableClustering && markerClusterGroup) {
                        markerClusterGroup.addLayer(marker);
                    } else {
                        marker.addTo(map);
                    }
                }
                visibleCount++;
            } else {
                // Marker poza viewport - ukryj
                if (map.hasLayer(marker)) {
                    if (adminConfig.enableClustering && markerClusterGroup) {
                        markerClusterGroup.removeLayer(marker);
                    } else {
                        map.removeLayer(marker);
                    }
                }
                hiddenCount++;
            }
        });
        
        window.PS_DEBUG&&console.log(`[INTRO Popup] 🎯 Viewport: ${visibleCount} widocznych, ${hiddenCount} ukrytych (z ${markers.length} total)`);
    }

    // ====================================================================================
    // ZMIEŃ PACZKOMAT - Wróć do widoku listy
    // ====================================================================================
    function changeParcelLocker() {
        window.PS_DEBUG&&console.log('[INTRO Popup] 🔄 Zmiana paczkomatu');
        
        // 1. Usuń formularz
        const form = document.getElementById('inpostCustomerForm');
        if (form) form.remove();
        
        // 2. Pokaż listę i wyszukiwarkę
        const pointsList = document.getElementById('inpostPointsList');
        const searchContainer = document.querySelector('.inpost-search-container');
        if (pointsList) pointsList.style.display = 'block';
        if (searchContainer) searchContainer.style.display = 'block';
        
        // 3. Zoom OUT do widoku miasta/regionu
        if (map && selectedPoint && selectedPoint.location) {
            map.flyTo(
                [selectedPoint.location.latitude, selectedPoint.location.longitude],
                12, // Zoom OUT (było 18)
                {
                    duration: 1.0,
                    easeLinearity: 0.1
                }
            );
        }
        
        // 4. Wyczyść selected point
        selectedPoint = null;
    }
    
    // ====================================================================================
    // WALIDACJA FORMULARZA
    // ====================================================================================
    function validateForm() {
        let isValid = true;
        
        // Imię
        const firstName = document.getElementById('inpostFirstName').value.trim();
        if (!firstName) {
            showError('errorFirstName', 'Imię jest wymagane');
            isValid = false;
        } else {
            hideError('errorFirstName');
        }
        
        // Nazwisko
        const lastName = document.getElementById('inpostLastName').value.trim();
        if (!lastName) {
            showError('errorLastName', 'Nazwisko jest wymagane');
            isValid = false;
        } else {
            hideError('errorLastName');
        }
        
        // Email
        const email = document.getElementById('inpostEmail').value.trim();
        const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
        if (!email) {
            showError('errorEmail', 'Email jest wymagany');
            isValid = false;
        } else if (!emailRegex.test(email)) {
            showError('errorEmail', 'Nieprawidłowy format email');
            isValid = false;
        } else {
            hideError('errorEmail');
        }
        
        return isValid;
    }
    
    function showError(elementId, message) {
        const errorEl = document.getElementById(elementId);
        if (!errorEl) return;
        const inputEl = errorEl.previousElementSibling;
        errorEl.textContent = message;
        errorEl.style.display = 'block';
        if (inputEl) inputEl.style.borderColor = '#dc3545';
    }
    
    function hideError(elementId) {
        const errorEl = document.getElementById(elementId);
        if (!errorEl) return;
        const inputEl = errorEl.previousElementSibling;
        errorEl.textContent = '';
        errorEl.style.display = 'none';
        if (inputEl) inputEl.style.borderColor = '#ddd';
    }
    
    // ====================================================================================
    // ZAAKCEPTUJ I ZAPISZ - Walidacja + AJAX do WooCommerce
    // ====================================================================================
    async function confirmAndSave() {
        window.PS_DEBUG&&console.log('[INTRO Popup] ✓ Zaakceptuj i zapisz');
        
        // 1. Walidacja
        if (!validateForm()) {
            window.PS_DEBUG&&console.log('[INTRO Popup] ❌ Walidacja nie przeszła');
            return;
        }
        
        // 2. Pobierz dane klienta — DOM FIRST, InPostPopupData FALLBACK
        // FIX 2026-03-02v5: Zawsze odczytaj dane z najlepszego źródła
        let firstName = '', lastName = '', email = '', fullPhone = '';
        const fnEl = document.getElementById('inpostFirstName');
        const lnEl = document.getElementById('inpostLastName');
        const emEl = document.getElementById('inpostEmail');
        const ppEl = document.getElementById('inpostPhonePrefix');
        const phEl = document.getElementById('inpostPhone');

        if (fnEl && fnEl.value && fnEl.value.trim()) {
            // PRIMARY: Dane z formularza intro-popup (klient je widzi i potwierdził)
            firstName = fnEl.value.trim();
            lastName = lnEl ? lnEl.value.trim() : '';
            email = emEl ? emEl.value.trim() : '';
            const phonePrefix = ppEl ? ppEl.value : '+48';
            const phone = phEl ? phEl.value.trim() : '';
            fullPhone = phone ? phonePrefix + ' ' + phone : '';
        } else {
            // FALLBACK: InPostPopupData.getCustomer() — dane z pre-map-popup lub inny source
            const pd = window.InPostPopupData ? window.InPostPopupData.getCustomer() : {};
            firstName = pd.firstName || '';
            lastName = pd.lastName || '';
            email = pd.email || '';
            fullPhone = pd.phone || '';
            window.PS_DEBUG&&console.log('[INTRO Popup] 📋 Dane klienta z InPostPopupData (fallback):', pd);
        }

        // Zapisz do InPostPopupData (single source of truth)
        if (window.InPostPopupData && firstName) {
            window.InPostPopupData.setCustomer({
                firstName: firstName,
                lastName: lastName,
                email: email,
                phone: fullPhone
            });
        }
        
        // 3. Przygotuj dane paczkomatu
        // POPRAWKA 2026-02-15: Użyj kraju Z PUNKTU, nie currentCountry!
        const pointCountry = selectedPoint.address_details?.country_code
            || selectedPoint.country_code
            || currentCountry;

        const addr = selectedPoint.address_details || {};
        const street = addr.street || '';
        const buildingNumber = addr.building_number || '';
        const city = addr.city || '';
        const postCode = addr.post_code || '';
        const flatNumber = addr.flat_number || '';
        const displayAddress = `${street} ${buildingNumber}`.trim();

        // Zapisz dane klienta w window globals (dostępne dla success popup)
        window.inpostCustomerData = {
            first_name: firstName,
            last_name: lastName,
            email: email,
            phone: fullPhone
        };

        // Zapisz paczkomat do InPostPopupData (centralized store)
        if (window.InPostPopupData) {
            window.InPostPopupData.setPaczkomat({
                name: selectedPoint.name || '',
                address: displayAddress,
                city: city,
                postCode: postCode,
                country: pointCountry,
                countryName: COUNTRIES[pointCountry] ? COUNTRIES[pointCountry].name : pointCountry.toUpperCase()
            });
        }

        // 4. AJAX do WordPress — użyj akcji set_paczkomat (tej samej co paczkomat-modal.js)
        // UWAGA: PHP oczekuje INDYWIDUALNYCH pól, nie JSON string!
        // Zmienna z PHP to paczkomat_ajax (NIE inpostAjax!)
        const ajaxVar = (typeof paczkomat_ajax !== 'undefined') ? paczkomat_ajax : null;
        const ajaxUrl = ajaxVar
            ? (ajaxVar.ajax_url || ajaxVar.ajaxurl)
            : (typeof ajaxurl !== 'undefined' ? ajaxurl : '/wp-admin/admin-ajax.php');
        const nonce = (typeof parcselectCacheConfig !== 'undefined' && parcselectCacheConfig.nonce) 
            ? parcselectCacheConfig.nonce 
            : (ajaxVar ? (ajaxVar.nonce || '') : '');

        if (ajaxUrl) {
            try {
                window.PS_DEBUG&&console.log('[INTRO Popup] 📡 Wysyłam AJAX set_paczkomat do:', ajaxUrl);
                const response = await fetch(ajaxUrl, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/x-www-form-urlencoded',
                    },
                    body: new URLSearchParams({
                        action: 'parcselect_save_selection',
                        locker_name: selectedPoint.name || '',
                        locker_address: displayAddress,
                        locker_city: city,
                        locker_post_code: postCode,
                        locker_country: pointCountry,
                        paczkomat_city: city,
                        paczkomat_street: street,
                        paczkomat_building_number: buildingNumber,
                        paczkomat_flat_number: flatNumber,
                        paczkomat_country: pointCountry,
                        paczkomat_country_name: COUNTRIES[pointCountry] ? COUNTRIES[pointCountry].name : pointCountry.toUpperCase(),
                        // Device tracking
                        device_type: window.PS_MOBILE ? window.PS_MOBILE.deviceType() : 'Desktop PC',
                        // Dane klienta — nowe pola
                        customer_first_name: firstName,
                        customer_last_name: lastName,
                        customer_email: email,
                        customer_phone: fullPhone,
                        // Security
                        security: nonce,
                        nonce: nonce
                    })
                });
                
                const resultText = await response.text();
                window.PS_DEBUG&&console.log('[INTRO Popup] 📥 Odpowiedź z serwera:', resultText);
                
                if (resultText.trim() === 'success') {
                    window.PS_DEBUG&&console.log('[INTRO Popup] ✅ Zapisano w WooCommerce session');
                    // Aktualizuj pola checkout jeśli dostępne
                    updateWooCommerceCheckoutFields(firstName, lastName, email, fullPhone);
                    showSuccessMessage();
                } else {
                    window.PS_DEBUG&&console.error('[INTRO Popup] ❌ Błąd zapisu:', resultText);
                    // Mimo błędu pokaż success (dane są w window globals)
                    showSuccessMessage();
                }
            } catch (error) {
                window.PS_DEBUG&&console.error('[INTRO Popup] ❌ Błąd AJAX:', error);
                // Mimo błędu pokaż success (dane zapisane lokalnie)
                showSuccessMessage();
            }
        } else {
            // Bez WordPress - pokaż success
            window.PS_DEBUG&&console.log('[INTRO Popup] ⚠️ Tryb standalone - brak AJAX');
            showSuccessMessage();
        }
    }

    /**
     * Aktualizuj pola formularza WooCommerce checkout jeśli istnieją na stronie
     * Dzięki temu dane z popupu automatycznie wypełniają formularz zamówienia
     * FIX 2026-03-02: Używa InPostFieldSync.pauseWatching() żeby nie triggerować
     *                 clear paczkomatu przez listener zmian pól
     */
    function updateWooCommerceCheckoutFields(firstName, lastName, email, phone) {
        // FIX 2026-03-02: Poinformuj listener żeby ignorował zmiany (to MY ustawiamy pola)
        if (window.InPostFieldSync && typeof window.InPostFieldSync.pauseWatching === 'function') {
            window.InPostFieldSync.pauseWatching();
        }
        
        // FIX 2026-03-02v2: PREFIX MUSI BYĆ W WARTOŚCI POLA billing_phone!
        // phone = "+48 123456789" (pełny z prefixem) — wpisujemy AS-IS do inputa
        // Wizualny <span> prefix ukrywamy żeby nie było podwójnie
        // Bo w WC checkout nie można zmienić kraju telefonu — prefix MUSI być w tekście
        
        const fields = {
            '#billing_first_name': firstName,
            '#billing_last_name': lastName,
            '#billing_email': email,
            '#billing_phone': phone,  // PEŁNY numer z prefixem: "+48 123456789"
            '#shipping_first_name': firstName,
            '#shipping_last_name': lastName,
        };

        let updated = 0;
        for (const [selector, value] of Object.entries(fields)) {
            const el = document.querySelector(selector);
            if (el && value) {
                el.value = value;
                // Trigger change event dla WooCommerce validation
                el.dispatchEvent(new Event('change', { bubbles: true }));
                el.dispatchEvent(new Event('input', { bubbles: true }));
                updated++;
            }
        }
        
        // FIX 2026-03-02v2: Ukryj wizualny <span> prefix — prefix jest teraz W wartości inputa
        // Bez tego klient widzi: [+48] [+48 123456789] = podwójny prefix wizualnie
        const prefixSpan = document.querySelector('#billing_phone_field .inpost-phone-prefix');
        if (prefixSpan && phone && phone.startsWith('+')) {
            prefixSpan.style.display = 'none';
            window.PS_DEBUG&&console.log('[INTRO Popup] 🔧 Ukryto wizualny prefix <span> — prefix jest w wartości inputa');
        }
        
        if (updated > 0) {
            window.PS_DEBUG&&console.log(`[INTRO Popup] 📝 Zaktualizowano ${updated} pól checkout (phone z prefixem: ${phone})`);
        }
        
        // FIX 2026-03-02: Wznów nasłuchiwanie zmian + zrób nowy snapshot
        if (window.InPostFieldSync && typeof window.InPostFieldSync.resumeWatching === 'function') {
            window.InPostFieldSync.resumeWatching();
        }
    }

    /**
     * 🧹 WYCZYŚĆ pola WooCommerce checkout — wywoływane przy ZMIANIE KRAJU
     * FIX 2026-03-03: Gdy użytkownik przełącza kraj, stare dane autofill
     * z poprzedniego kontekstu MUSZĄ zostać wyczyszczone natychmiast.
     * Dane klienta z WooCommerce nie są powiązane z konkretnym krajem,
     * ale paczkomat TAK — więc czyścimy wszystko żeby uniknąć niespójności.
     */
    function clearWooCommerceCheckoutFields() {
        // Poinformuj InPostFieldSync żeby ignorował zmiany (to MY czyścimy pola)
        if (window.InPostFieldSync && typeof window.InPostFieldSync.pauseWatching === 'function') {
            window.InPostFieldSync.pauseWatching();
        }

        const fieldsToReset = [
            '#billing_first_name',
            '#billing_last_name',
            '#billing_email',
            '#billing_phone',
            '#shipping_first_name',
            '#shipping_last_name'
        ];

        let cleared = 0;
        for (const selector of fieldsToReset) {
            const el = document.querySelector(selector);
            if (el && el.value) {
                el.value = '';
                el.dispatchEvent(new Event('change', { bubbles: true }));
                el.dispatchEvent(new Event('input', { bubbles: true }));
                cleared++;
            }
        }

        // Przywróć wizualny prefix <span> (mógł być ukryty przez updateWooCommerceCheckoutFields)
        const prefixSpan = document.querySelector('#billing_phone_field .inpost-phone-prefix');
        if (prefixSpan) {
            prefixSpan.style.display = '';
        }

        if (cleared > 0) {
            window.PS_DEBUG&&console.log(`[INTRO Popup] 🧹 Wyczyszczono ${cleared} pól WooCommerce checkout (zmiana kraju)`);
        }

        // Wznów nasłuchiwanie zmian
        if (window.InPostFieldSync && typeof window.InPostFieldSync.resumeWatching === 'function') {
            window.InPostFieldSync.resumeWatching();
        }
    }
    
    // ====================================================================================
    // KOMUNIKAT SUKCESU + AUTO-CLOSE
    // ====================================================================================
    /**
     * Wyświetla panel sukcesu po wyborze paczkomatu
     *
     * Panel zawiera:
     * - Nazwę wybranego paczkomatu
     * - Pełny adres (ulica, kod pocztowy, miasto)
     * - Nazwę kraju w języku ojczystym (np. 'Polska', 'Italia', 'France')
     * - Countdown do auto-zamknięcia
     *
     * Dlaczego nazwa kraju?
     * Użytkownik musi wiedzieć w jakim kraju jest wybrany paczkomat, szczególnie
     * dla międzynarodowych zamówień. Nazwa w języku ojczystym jest klarowna.
     *
     * @since 2026-02-15 Dodano nazwę kraju w języku ojczystym
     */
    function showSuccessMessage() {
        if (document.getElementById('inpostSuccessPanel')) return;
        // Usuń formularz
        const form = document.getElementById('inpostCustomerForm');
        if (form) form.remove();

        // POPRAWKA 2026-02-15: Pobierz kraj z WYBRANEGO PUNKTU, nie z currentCountry!
        // Punkt może być z innego kraju niż ten którym otwarliśmy mapę
        const pointCountryCode = selectedPoint.address_details?.country_code
            || selectedPoint.country_code
            || currentCountry;
        const countryName = COUNTRIES[pointCountryCode]
            ? COUNTRIES[pointCountryCode].name
            : pointCountryCode.toUpperCase();

        const city = selectedPoint.address_details?.city || selectedPoint.city || '';
        const street = selectedPoint.address_details?.street || selectedPoint.street || '';
        const buildingNumber = selectedPoint.address_details?.building_number || selectedPoint.building_number || '';
        const postCode = selectedPoint.address_details?.post_code || selectedPoint.post_code || '';
        const fullAddress = `${street} ${buildingNumber}, ${postCode} ${city}`.trim();

        // Pobierz dane klienta z window globals (zapisane przez confirmAndSave)
        const cust = window.inpostCustomerData || {};
        const custName = [cust.first_name, cust.last_name].filter(Boolean).join(' ');
        const custEmail = cust.email || '';
        const custPhone = cust.phone || '';

        // Pokaż success panel z PEŁNYMI danymi (paczkomat + klient)
        const successHTML = `
            <div class="inpost-success-panel" id="inpostSuccessPanel">
                <div class="success-icon">${InPostPopupConfig?.successIcon || '✅'}</div>
                <h3>${getTranslation('successTitle')}</h3>
                <p>${getTranslation('successSubtitle')}</p>

                <div class="success-point-info">
                    <strong>${selectedPoint.name}</strong>
                    <span>📍 ${fullAddress}</span>
                    <span>🌍 ${countryName}</span>
                </div>

                ${custName ? `
                <div class="success-customer-info">
                    <div class="success-customer-title">👤 Dane odbiorcy:</div>
                    <span>🙍 ${custName}</span>
                    ${custEmail ? `<span>📧 ${custEmail}</span>` : ''}
                    ${custPhone ? `<span>📱 ${custPhone}</span>` : ''}
                </div>
                ` : ''}

                <div class="countdown-text">
                    ${InPostPopupConfig?.successCountdownText || getTranslation('successCountdown')} <span id="countdownTimer">8</span> ${getTranslation('successSeconds')}
                </div>
            </div>
        `;
        
        const container = document.getElementById('inpostPopupContainer');
        if (container) {
            container.insertAdjacentHTML('beforeend', successHTML);
        }
        
        // Countdown
        let seconds = 8;
        const timerEl = document.getElementById('countdownTimer');
        
        const interval = setInterval(() => {
            seconds--;
            if (timerEl) timerEl.textContent = seconds;
            
            if (seconds <= 0) {
                clearInterval(interval);
                closePopup();
            }
        }, 1000);
    }
    
    // ====================
    // GREY_ME — Funkcja zaszarzania (np. dla przepełnionych paczkomatów)
    // ====================
    /**
     * Stosuje efekt zaszarzenia (grayscale) do markera lub elementu listy.
     * Wywoływana gdy paczkomat jest pełny lub niedostępny.
     */
    function GREY_ME(element, isGrey = true) {
        if (!element) return;
        if (isGrey) {
            element.style.filter = 'grayscale(100%) opacity(0.5)';
            element.style.pointerEvents = 'none'; // Blokujemy interakcję
            element.classList.add('ps-is-greyed');
        } else {
            element.style.filter = '';
            element.style.pointerEvents = '';
            element.classList.remove('ps-is-greyed');
        }
    }

    // ====================
    // REFRESH MARKERÓW - dla Parcel Locker Selector
    // ====================
    function refreshAllMarkers() {
        if (typeof ParcelLockerSelector === 'undefined') return;
        
        window.PS_DEBUG&&console.log('[INTRO Popup] 🔄 Odświeżanie popup na markerach');
        
        markers.forEach(marker => {
            if (marker.pointData && marker.getPopup()) {
                const popupContent = ParcelLockerSelector.createMarkerPopup(marker.pointData);
                marker.setPopupContent(popupContent);
            }
        });
    }

    // ====================
    // ====================
    // INTRO POPUP PUBLIC API - INDEPENDENT VERSION
    // Niezależne API bez konfliktów z starą wersją
    // Version: 3.0.0-INTRO (2026-01-23)
    // ====================
    window.IntroPopup = {
        open: openMapPopup,
        close: closePopup,
        switchCountry: switchCountry,
        closeDetailModal: closeDetailModal,
        confirmSelectPoint: confirmSelectPoint,
        selectPoint: confirmSelectPoint,
        search: searchPoints,
        scrollFlags: function(amount) {
            const container = document.getElementById('inpostCountryFlags');
            if (container) container.scrollBy({ left: amount, behavior: 'smooth' });
        },
        restoreSearchPanel: function() {
            const sidebar = document.querySelector('.inpost-popup-sidebar');
            const lupa = document.querySelector('.ps-mobile-restore-search');
            if (sidebar) {
                sidebar.style.display = 'flex';
                sidebar.style.transform = 'translateY(0)';
                if (lupa) lupa.style.display = 'none';
            }
        },
        GREY_ME: GREY_ME,
        changeParcelLocker: changeParcelLocker,
        confirmAndSave: confirmAndSave,
        getCurrentCountry: () => currentCountry,
        getSelectedPoint: () => selectedPoint,
        getCountries: () => COUNTRIES,
        getAllPoints: () => allPoints,
        getMarkers: () => markers,
        refreshMarkers: refreshAllMarkers,
        getConfig: () => adminConfig,
        getMap: () => map,
        /** Zwraca przetlumaczony tekst dla aktywnego jezyka */
        translate: (key) => getTranslation(key),
        /** Zwraca WSZYSTKIE dane wpisane w popupach (klient + paczkomat) */
        getPopupData: () => window.InPostPopupData ? window.InPostPopupData.getAll() : {},
        /** Zwraca dane klienta wpisane w popupach */
        getCustomerData: () => window.InPostPopupData ? window.InPostPopupData.getCustomer() : {},
        /** Zwraca dane paczkomatu wybranego w popupie */
        getPaczkomatData: () => window.InPostPopupData ? window.InPostPopupData.getPaczkomat() : {},
        version: '3.3.0'
    };

    // Backward compatibility
    window.InPostPopup = window.IntroPopup;

    IPS.log('API Loaded - Version:', window.IntroPopup.version);

    // ====================
    // AUTO-INICJALIZACJA
    // ====================
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }

})();
