document.addEventListener('DOMContentLoaded', () => {
  const body = document.body;
  const isLoggedIn = body.dataset.auth === '1';
  const childGender = body.dataset.childGender || '';
  const locationPreference = body.dataset.locationPreference || 'prompt';
  const header = document.querySelector('.site-header');
  const headerSentinel = document.getElementById('headerSentinel');
  const matomoConfigNode = document.getElementById('matomoConfig');
  const consentStateKey = 'pkt_cookie_consent';
  let matomoLoaded = false;

  // Logo-Logik
  const pickLogo = (gender) => {
    if (gender === 'female') return 'logo_female.png';
    if (gender === 'male') return 'logo_male.png';
    return Math.random() < 0.5 ? 'logo_female.png' : 'logo_male.png';
  };
  const chosenLogo = pickLogo(childGender);
  document.querySelectorAll('[data-logo-img]').forEach(img => {
    img.src = `/assets/bilder/${chosenLogo}`;
  });

  // Header shrink via IntersectionObserver (no flicker around threshold)
  if (header && headerSentinel && 'IntersectionObserver' in window) {
    const observer = new IntersectionObserver(([entry]) => {
      header.classList.toggle('is-scrolled', !entry.isIntersecting);
    }, {
      rootMargin: '-1px 0px 0px 0px',
      threshold: 0,
    });
    observer.observe(headerSentinel);
  } else if (header) {
    // Fallback with simple threshold
    const limit = 120;
    const onScroll = () => header.classList.toggle('is-scrolled', window.scrollY > limit);
    onScroll();
    window.addEventListener('scroll', onScroll, { passive: true });
  }

  // Mobile Menü
  const mobileMenu = document.getElementById('mobileMenu');
  document.querySelectorAll('.menu-toggle').forEach(btn => {
    btn.addEventListener('click', () => {
      mobileMenu?.classList.toggle('open');
    });
  });
  const profileMenu = document.querySelector('[data-profile-menu]');
  const profileMenuTrigger = document.querySelector('[data-profile-menu-trigger]');
  profileMenuTrigger?.addEventListener('click', () => {
    const next = !profileMenu?.classList.contains('is-open');
    profileMenu?.classList.toggle('is-open', next);
    profileMenuTrigger.setAttribute('aria-expanded', next ? 'true' : 'false');
  });
  document.addEventListener('click', (event) => {
    if (!profileMenu || !profileMenuTrigger) return;
    if (profileMenu.contains(event.target)) return;
    profileMenu.classList.remove('is-open');
    profileMenuTrigger.setAttribute('aria-expanded', 'false');
  });

  // Scroll zu Events
  const scrollBtn = document.getElementById('scrollToEvents');
  if (scrollBtn) {
    scrollBtn.addEventListener('click', () => {
      document.getElementById('events')?.scrollIntoView({ behavior: 'smooth' });
    });
  }

  // Events from backend (injected on page); fallback to empty
  const events = Array.isArray(window.__events) ? window.__events : [];
  const threads = Array.isArray(window.__threads) ? window.__threads : [];
  const EVENTS_RADIUS_KM = 20;
  const LOCATION_STORAGE_KEY = 'pkt_user_location';
  const LOCATION_SESSION_STORAGE_KEY = 'pkt_user_location_session';
  const LOCATION_SESSION_PREFERENCE_KEY = 'pkt_user_location_session_preference';

  const el = {
    sliderTrack: document.getElementById('eventSlider'),
    sliderViewport: document.querySelector('.slider__viewport'),
    sliderPrev: document.querySelector('[data-slider-prev]'),
    sliderNext: document.querySelector('[data-slider-next]'),
    threadSliderTrack: document.getElementById('threadSlider'),
    threadSliderViewport: document.getElementById('threadSlider')?.closest('.slider__viewport') || null,
    threadSliderPrev: document.querySelector('[data-thread-slider-prev]'),
    threadSliderNext: document.querySelector('[data-thread-slider-next]'),
    modal: document.getElementById('eventModal'),
    modalBody: document.getElementById('eventModalBody'),
    modalTitle: document.getElementById('eventModalTitle'),
    quickForm: document.getElementById('quickSearchForm'),
    quickLoc: document.getElementById('qsLoc'),
    quickQuery: document.getElementById('qsQuery'),
    quickLat: document.getElementById('qsLat'),
    quickLng: document.getElementById('qsLng'),
    quickGeo: document.getElementById('quickGeo'),
    eventsSection: document.getElementById('events'),
    locationPreferenceModal: document.getElementById('locationPreferenceModal'),
    consentBanner: document.getElementById('cookieConsentBanner'),
    consentModal: document.getElementById('cookieConsentModal'),
    consentAnalytics: document.getElementById('consentAnalytics'),
    consentExternalServices: document.getElementById('consentExternalServices'),
  };
  let effectiveLocationPreference = locationPreference;
  let consentState = null;

  const fmtDate = (iso) => {
    const d = new Date(iso);
    return d.toLocaleDateString('de-DE', { weekday: 'short', day: '2-digit', month: 'short', hour: '2-digit', minute: '2-digit' });
  };

  const now = () => new Date();

  const deleteCookie = (name) => {
    document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; SameSite=Lax`;
  };

  const readConsent = () => {
    try {
      const raw = window.localStorage.getItem(consentStateKey);
      if (!raw) return null;
      const parsed = JSON.parse(raw);
      if (!parsed || typeof parsed !== 'object') return null;
      return {
        necessary: true,
        analytics: Boolean(parsed.analytics),
        external_services: Boolean(parsed.external_services),
        updatedAt: parsed.updatedAt || null,
      };
    } catch (err) {
      return null;
    }
  };

  const writeConsent = (nextState) => {
    consentState = {
      necessary: true,
      analytics: Boolean(nextState.analytics),
      external_services: Boolean(nextState.external_services),
      updatedAt: new Date().toISOString(),
    };
    try {
      window.localStorage.setItem(consentStateKey, JSON.stringify(consentState));
    } catch (err) {
      // ignore
    }
    window.PKTConsent = window.PKTConsent || {};
    window.PKTConsent.get = () => consentState;
    window.PKTConsent.has = (category) => {
      if (category === 'necessary') return true;
      return Boolean(consentState?.[category]);
    };
  };

  const closeConsentModal = () => {
    el.consentModal?.classList.remove('open');
  };

  const openConsentModal = () => {
    if (el.consentAnalytics) el.consentAnalytics.checked = Boolean(consentState?.analytics);
    if (el.consentExternalServices) el.consentExternalServices.checked = Boolean(consentState?.external_services);
    el.consentModal?.classList.add('open');
  };

  const deleteMatomoCookies = () => {
    ['_pk_id', '_pk_ses', '_pk_ref', '_pk_cvar', 'mtm_consent', 'mtm_consent_removed'].forEach((prefix) => {
      deleteCookie(prefix);
      const hostParts = window.location.hostname.split('.');
      while (hostParts.length > 1) {
        document.cookie = `${prefix}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=.${hostParts.join('.')}; SameSite=Lax`;
        hostParts.shift();
      }
    });
  };

  const loadMatomo = () => {
    if (matomoLoaded || !matomoConfigNode || !consentState?.analytics) return;
    try {
      const cfg = JSON.parse(matomoConfigNode.textContent || '{}');
      if (!cfg.url || !cfg.siteId) return;
      const _paq = window._paq = window._paq || [];
      _paq.push(['setDomains', Array.isArray(cfg.domains) ? cfg.domains : []]);
      _paq.push(['trackPageView']);
      _paq.push(['enableLinkTracking']);
      _paq.push(['setTrackerUrl', cfg.url + 'matomo.php']);
      _paq.push(['setSiteId', cfg.siteId]);
      const script = document.createElement('script');
      script.async = true;
      script.src = cfg.url + 'matomo.js';
      document.head.appendChild(script);
      matomoLoaded = true;
    } catch (err) {
      // ignore
    }
  };

  const showConsentBannerIfNeeded = () => {
    if (!consentState && el.consentBanner) {
      el.consentBanner.removeAttribute('hidden');
    }
  };

  const applyConsent = (nextState, options = {}) => {
    const previous = consentState;
    writeConsent(nextState);
    if (!consentState.external_services) {
      clearStoredLocation();
    }
    if (!consentState.analytics) {
      deleteMatomoCookies();
    } else {
      loadMatomo();
    }
    el.consentBanner?.setAttribute('hidden', 'hidden');
    closeConsentModal();

    if (previous && options.reloadOnChange !== false) {
      const analyticsChanged = previous.analytics !== consentState.analytics;
      const externalChanged = previous.external_services !== consentState.external_services;
      if (analyticsChanged || externalChanged) {
        window.location.reload();
      }
    }
  };

  const requireExternalServicesConsent = (message = 'Für diese Funktion werden externe Dienste benötigt.') => {
    if (consentState?.external_services) {
      return true;
    }
    alert(message);
    openConsentModal();
    return false;
  };

  const setCookie = (name, value, days = 30) => {
    const expires = new Date(Date.now() + (days * 86400000)).toUTCString();
    document.cookie = `${name}=${encodeURIComponent(value)}; expires=${expires}; path=/; SameSite=Lax`;
  };

  const parseCookie = (name) => {
    const prefix = `${name}=`;
    return document.cookie
      .split(';')
      .map(item => item.trim())
      .find(item => item.startsWith(prefix))
      ?.slice(prefix.length) || '';
  };

  const persistLocation = (location, mode = 'persistent') => {
    if (!location || !Number.isFinite(location.lat) || !Number.isFinite(location.lng)) return;
    const payload = {
      lat: Number(location.lat.toFixed(6)),
      lng: Number(location.lng.toFixed(6)),
      label: location.label || 'Mein Standort',
      savedAt: new Date().toISOString(),
    };
    if (mode === 'session') {
      try {
        window.sessionStorage.setItem(LOCATION_SESSION_STORAGE_KEY, JSON.stringify(payload));
      } catch (err) {
        // ignore
      }
    } else {
      try {
        window.localStorage.setItem(LOCATION_STORAGE_KEY, JSON.stringify(payload));
      } catch (err) {
        // ignore
      }
      setCookie('pkt_user_location', JSON.stringify(payload), 30);
    }
    if (el.quickLat) el.quickLat.value = payload.lat.toFixed(6);
    if (el.quickLng) el.quickLng.value = payload.lng.toFixed(6);
    if (el.quickLoc && (!el.quickLoc.value || el.quickLoc.value === 'Mein Standort')) {
      el.quickLoc.value = payload.label;
    }
  };

  const clearStoredLocation = () => {
    try {
      window.localStorage.removeItem(LOCATION_STORAGE_KEY);
    } catch (err) {
      // ignore
    }
    try {
      window.sessionStorage.removeItem(LOCATION_SESSION_STORAGE_KEY);
    } catch (err) {
      // ignore
    }
    deleteCookie('pkt_user_location');
    if (el.quickLat) el.quickLat.value = '';
    if (el.quickLng) el.quickLng.value = '';
    if (el.quickLoc) el.quickLoc.value = '';
  };

  const getStoredLocation = () => {
    const candidates = [];
    try {
      const session = window.sessionStorage.getItem(LOCATION_SESSION_STORAGE_KEY);
      if (session) candidates.push(session);
    } catch (err) {
      // ignore
    }
    try {
      const local = window.localStorage.getItem(LOCATION_STORAGE_KEY);
      if (local) candidates.push(local);
    } catch (err) {
      // ignore
    }
    const cookieValue = parseCookie('pkt_user_location');
    if (cookieValue) candidates.push(decodeURIComponent(cookieValue));

    for (const entry of candidates) {
      try {
        const parsed = JSON.parse(entry);
        if (parsed && Number.isFinite(parsed.lat) && Number.isFinite(parsed.lng)) {
          return {
            lat: Number(parsed.lat),
            lng: Number(parsed.lng),
            label: parsed.label || 'Mein Standort',
          };
        }
      } catch (err) {
        // ignore invalid payloads
      }
    }
    return null;
  };

  const haversineKm = (lat1, lng1, lat2, lng2) => {
    const toRad = (value) => value * Math.PI / 180;
    const earthRadiusKm = 6371;
    const dLat = toRad(lat2 - lat1);
    const dLng = toRad(lng2 - lng1);
    const a = Math.sin(dLat / 2) ** 2
      + Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLng / 2) ** 2;
    return earthRadiusKm * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
  };

  const smallTag = (label) => `<span class="badge">${label}</span>`;

  const getRankedEvents = (sourceEvents, location) => {
    const normalized = sourceEvents.map(item => {
      const startsAtDate = new Date(item.startsAt);
      const isFuture = startsAtDate >= now();
      const hasGeo = Number.isFinite(item.lat) && Number.isFinite(item.lng);
      const distanceKm = (location && hasGeo)
        ? haversineKm(location.lat, location.lng, item.lat, item.lng)
        : null;

      return {
        ...item,
        startsAtDate,
        isFuture,
        distanceKm,
      };
    });

    if (!location) {
      return normalized
        .filter(item => item.isFuture)
        .sort((a, b) => a.startsAtDate - b.startsAtDate)
        .slice(0, 10);
    }

    const nearby = normalized.filter(item => item.distanceKm !== null && item.distanceKm <= EVENTS_RADIUS_KM);
    const byDistanceThenDate = (a, b) => {
      if (a.distanceKm !== b.distanceKm) return a.distanceKm - b.distanceKm;
      return a.startsAtDate - b.startsAtDate;
    };

    const upcomingNearby = nearby
      .filter(item => item.isFuture)
      .sort(byDistanceThenDate);

    if (upcomingNearby.length) {
      return upcomingNearby.slice(0, 10);
    }

    const missedNearby = nearby
      .filter(item => !item.isFuture)
      .sort((a, b) => {
        if (a.distanceKm !== b.distanceKm) return a.distanceKm - b.distanceKm;
        return b.startsAtDate - a.startsAtDate;
      })
      .map(item => ({ ...item, missed: true }));

    if (missedNearby.length) {
      return missedNearby.slice(0, 10);
    }

    return normalized
      .filter(item => item.isFuture)
      .sort((a, b) => a.startsAtDate - b.startsAtDate)
      .slice(0, 10);
  };

  const renderCard = (item) => {
    const guest = !isLoggedIn;
    const kids = item.allowKids ? 'Mit Kindern' : 'Ohne Kinder';
    const distanceTag = Number.isFinite(item.distanceKm) ? smallTag(`${item.distanceKm.toFixed(1)} km`) : '';
    const missedTag = item.missed ? smallTag('Das hast du verpasst') : '';
    return `
    <article class="card event-card-small">
      <div class="muted small">${fmtDate(item.startsAt)}</div>
      <h3>${item.title}</h3>
      <p class="muted">${item.teaser}</p>
      <div class="muted small">📍 ${item.city || item.region || ''}</div>
      <div class="event__tags">${smallTag(kids)} ${item.visibility === 'public' ? smallTag('Öffentlich') : smallTag('Mitglieder')} ${distanceTag} ${missedTag}</div>
      <div class="flex gap-8" style="margin-top:8px;">
        <button class="btn ghost" data-event-detail="${item.id}">Details</button>
        ${guest || item.missed ? '' : '<button class="btn">Teilnehmen</button>'}
      </div>
    </article>`;
  };

  const renderSlider = (location = null) => {
    if (!el.sliderTrack) return;
    const rankedEvents = getRankedEvents(events, location);
    if (!rankedEvents.length) {
      el.sliderTrack.innerHTML = '<p class="muted">Keine Events vorhanden.</p>';
      return;
    }
    el.sliderTrack.innerHTML = rankedEvents.map(renderCard).join('');
    el.sliderTrack.querySelectorAll('[data-event-detail]').forEach(btn => {
      btn.addEventListener('click', () => {
        const id = parseInt(btn.getAttribute('data-event-detail'), 10);
        const ev = rankedEvents.find(e => e.id === id);
        if (!ev || !el.modal || !el.modalBody || !el.modalTitle) return;
        el.modalTitle.textContent = ev.title;
        el.modalBody.innerHTML = `
          <div class="muted small">${fmtDate(ev.startsAt)} · ${ev.region || ev.city || ''}</div>
          <p class="muted">${ev.teaser}</p>
          <p>${ev.description}</p>
          ${ev.locationLabel ? `<p><strong>Ort:</strong> ${ev.locationLabel}</p>` : ''}
          ${Number.isFinite(ev.distanceKm) ? `<p><strong>Entfernung:</strong> ${ev.distanceKm.toFixed(1)} km</p>` : ''}
          ${ev.missed ? '<p><strong>Hinweis:</strong> Das hast du verpasst.</p>' : ''}
          <p><strong>Kinder:</strong> ${ev.allowKids ? 'Mit Kindern' : 'Ohne Kinder'}</p>
          <p><strong>Sichtbarkeit:</strong> ${ev.visibility === 'public' ? 'Öffentlich' : 'Nur Mitglieder'}</p>
        `;
        el.modal.classList.add('open');
      });
    });
  };

  const renderThreadCard = (item) => {
    const preview = item.body.length > 170 ? `${item.body.slice(0, 170)}…` : item.body;
    return `
    <article class="card thread-card-small">
      <div class="muted small">${fmtDate(item.createdAt)}</div>
      <h3>${item.title}</h3>
      <p class="muted clamp-4">${preview}</p>
      <div class="event__meta">
        <span>${item.displayName}</span>
        <span>Antworten: ${item.answers}</span>
      </div>
      <div class="flex gap-8" style="margin-top:8px;">
        <a class="btn ghost" href="/community_thread?id=${item.id}">Beitrag öffnen</a>
      </div>
    </article>`;
  };

  const renderThreadSlider = () => {
    if (!el.threadSliderTrack) return;
    if (!threads.length) {
      el.threadSliderTrack.innerHTML = '<p class="muted">Noch keine Community-Beiträge vorhanden.</p>';
      return;
    }
    el.threadSliderTrack.innerHTML = threads.map(renderThreadCard).join('');
  };

  const scrollSlider = (viewport, dir) => {
    if (!viewport) return;
    const amount = dir === 'next' ? 320 : -320;
    viewport.scrollBy({ left: amount, behavior: 'smooth' });
  };

  el.sliderPrev?.addEventListener('click', () => scrollSlider(el.sliderViewport, 'prev'));
  el.sliderNext?.addEventListener('click', () => scrollSlider(el.sliderViewport, 'next'));
  el.threadSliderPrev?.addEventListener('click', () => scrollSlider(el.threadSliderViewport, 'prev'));
  el.threadSliderNext?.addEventListener('click', () => scrollSlider(el.threadSliderViewport, 'next'));

  const applyStoredLocationToForm = () => {
    const stored = getStoredLocation();
    if (!stored) return null;
    if (el.quickLat) el.quickLat.value = stored.lat.toFixed(6);
    if (el.quickLng) el.quickLng.value = stored.lng.toFixed(6);
    if (el.quickLoc && !el.quickLoc.value) el.quickLoc.value = stored.label || 'Mein Standort';
    return stored;
  };

  const requestLocation = (options = {}) => new Promise((resolve) => {
    if (!navigator.geolocation) {
      resolve(null);
      return;
    }
    navigator.geolocation.getCurrentPosition(
      (pos) => {
        const location = {
          lat: pos.coords.latitude,
          lng: pos.coords.longitude,
          label: 'Mein Standort',
        };
        persistLocation(location, options.persistMode || 'persistent');
        resolve(location);
      },
      () => resolve(null),
      {
        enableHighAccuracy: true,
        timeout: options.timeout || 10000,
        maximumAge: options.maximumAge || 300000,
      }
    );
  });

  const closeLocationPreferenceModal = () => {
    el.locationPreferenceModal?.classList.remove('open');
  };

  document.querySelectorAll('[data-location-pref-close]').forEach(btn => {
    btn.addEventListener('click', closeLocationPreferenceModal);
  });
  el.locationPreferenceModal?.addEventListener('click', (event) => {
    if (event.target === el.locationPreferenceModal) {
      closeLocationPreferenceModal();
    }
  });

  const saveLocationPreference = async (preference) => {
    effectiveLocationPreference = preference;
    if (!isLoggedIn) {
      try {
        window.localStorage.setItem('pkt_location_preference_guest', preference);
      } catch (err) {
        // ignore
      }
      return true;
    }

    try {
      const body = new URLSearchParams({ preference });
      const response = await fetch('/api/location-preference', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
        },
        body: body.toString(),
      });
      return response.ok;
    } catch (err) {
      return false;
    }
  };

  const getSessionPreference = () => {
    try {
      return window.sessionStorage.getItem(LOCATION_SESSION_PREFERENCE_KEY);
    } catch (err) {
      return null;
    }
  };

  const setSessionPreference = (value) => {
    try {
      if (!value) {
        window.sessionStorage.removeItem(LOCATION_SESSION_PREFERENCE_KEY);
      } else {
        window.sessionStorage.setItem(LOCATION_SESSION_PREFERENCE_KEY, value);
      }
    } catch (err) {
      // ignore
    }
  };

  const resolvePromptChoice = () => new Promise((resolve) => {
    if (!el.locationPreferenceModal) {
      resolve('disabled');
      return;
    }

    const buttons = el.locationPreferenceModal.querySelectorAll('[data-location-pref-choice]');
    const cleanup = () => {
      buttons.forEach(button => button.removeEventListener('click', handleClick));
      document.removeEventListener('keydown', handleKeydown);
    };
    const finish = (value) => {
      cleanup();
      closeLocationPreferenceModal();
      resolve(value);
    };
    const handleClick = (event) => {
      const value = event.currentTarget.getAttribute('data-location-pref-choice') || 'disabled';
      finish(value);
    };
    const handleKeydown = (event) => {
      if (event.key === 'Escape') {
        finish('disabled');
      }
    };

    buttons.forEach(button => button.addEventListener('click', handleClick));
    document.addEventListener('keydown', handleKeydown);
    el.locationPreferenceModal.classList.add('open');
  });

  const ensureEventsLocation = async () => {
    const sessionPreference = getSessionPreference();
    if (effectiveLocationPreference === 'disabled') {
      clearStoredLocation();
      renderSlider(null);
      return null;
    }
    if (!requireExternalServicesConsent('Für standortbezogene Treffen werden Standort- und Kartendienste erst nach deiner Einwilligung aktiviert.')) {
      renderSlider(null);
      return null;
    }

    const stored = applyStoredLocationToForm();
    if (stored && effectiveLocationPreference !== 'enabled' && sessionPreference !== 'session') {
      renderSlider(stored);
      return stored;
    }

    if (effectiveLocationPreference === 'prompt') {
      const choice = sessionPreference || await resolvePromptChoice();
      if (choice === 'session') {
        setSessionPreference('session');
        const location = await requestLocation({ persistMode: 'session' });
        renderSlider(location || stored);
        return location;
      }
      if (choice === 'disabled') {
        await saveLocationPreference('disabled');
        clearStoredLocation();
        renderSlider(null);
        return null;
      }
      if (choice === 'enabled') {
        await saveLocationPreference('enabled');
        effectiveLocationPreference = 'enabled';
      }
    }

    const location = await requestLocation({
      persistMode: effectiveLocationPreference === 'enabled' ? 'persistent' : 'session',
    });
    renderSlider(location || stored);
    return location;
  };

  // Quick search with geocoding
  const geocode = async (query) => {
    const url = 'https://nominatim.openstreetmap.org/search?format=jsonv2&limit=1&q=' + encodeURIComponent(query);
    const res = await fetch(url, { headers: { 'Accept-Language': 'de', 'User-Agent': 'papa-kind-treff/1.0' } });
    const data = await res.json();
    if (Array.isArray(data) && data[0]) {
      return { lat: parseFloat(data[0].lat), lng: parseFloat(data[0].lon) };
    }
    return null;
  };

  el.quickGeo?.addEventListener('click', () => {
    if (!requireExternalServicesConsent('Für die Standortermittlung benötigen wir deine Einwilligung zu externen Diensten und Standortfunktionen.')) {
      return;
    }
    if (!navigator.geolocation) {
      alert('Geolocation wird nicht unterstützt.');
      return;
    }
    navigator.geolocation.getCurrentPosition(
      (pos) => {
        persistLocation({
          lat: pos.coords.latitude,
          lng: pos.coords.longitude,
          label: 'Mein Standort',
        }, effectiveLocationPreference === 'enabled' ? 'persistent' : 'session');
        renderSlider(getStoredLocation());
      },
      () => alert('Standort konnte nicht ermittelt werden.')
    );
  });

  if (el.quickForm) {
    el.quickForm.addEventListener('submit', async (e) => {
      if (!el.quickLoc || !el.quickLat || !el.quickLng) return;
      const hasCoords = el.quickLat.value && el.quickLng.value;
      const locVal = (el.quickLoc.value || '').trim();
      if (hasCoords || locVal === '') return;
      e.preventDefault();
      try {
        const coords = await geocode(locVal);
        if (coords) {
          el.quickLat.value = coords.lat.toFixed(6);
          el.quickLng.value = coords.lng.toFixed(6);
        }
      } catch (err) {
        // ignore
      } finally {
        el.quickForm.submit();
      }
    });
  }

  // Close modal
  document.querySelectorAll('[data-event-modal-close]').forEach(btn => {
    btn.addEventListener('click', () => el.modal?.classList.remove('open'));
  });
  el.modal?.addEventListener('click', (e) => { if (e.target === el.modal) el.modal.classList.remove('open'); });
  document.querySelectorAll('[data-consent-open]').forEach(btn => {
    btn.addEventListener('click', openConsentModal);
  });
  document.querySelectorAll('[data-consent-close]').forEach(btn => {
    btn.addEventListener('click', closeConsentModal);
  });
  document.querySelectorAll('[data-consent-necessary]').forEach(btn => {
    btn.addEventListener('click', () => applyConsent({ analytics: false, external_services: false }));
  });
  document.querySelector('[data-consent-accept-all]')?.addEventListener('click', () => {
    applyConsent({ analytics: true, external_services: true });
  });
  document.querySelector('[data-consent-save]')?.addEventListener('click', () => {
    applyConsent({
      analytics: Boolean(el.consentAnalytics?.checked),
      external_services: Boolean(el.consentExternalServices?.checked),
    });
  });
  el.consentModal?.addEventListener('click', (e) => {
    if (e.target === el.consentModal) closeConsentModal();
  });
  document.addEventListener('pkt:open-consent', openConsentModal);

  const readAvatarValue = (form, field) => {
    const checked = form.querySelector(`[data-avatar-field="${field}"]:checked`);
    if (checked) return checked.value;
    const input = form.querySelector(`[data-avatar-field="${field}"]`);
    return input ? input.value : '';
  };

  const avatarComponentFieldMap = {
    avatar_lorelei_eyes_variant: 'eyesVariant',
    avatar_lorelei_eyebrows_variant: 'eyebrowsVariant',
    avatar_lorelei_mouth_variant: 'mouthVariant',
    avatar_lorelei_glasses_variant: 'glassesVariant',
    avatar_lorelei_hair_variant: 'hairVariant',
    avatar_lorelei_beard_variant: 'beardVariant',
    avatar_lorelei_earrings_variant: 'earringsVariant',
  };

  const avatarComponentFields = Object.keys(avatarComponentFieldMap);
  const avatarEndpoint = '/api/avatar';
  const avatarOptionalProbabilityMap = {
    avatar_lorelei_glasses_variant: 'glassesProbability',
    avatar_lorelei_hair_variant: 'hairProbability',
    avatar_lorelei_beard_variant: 'beardProbability',
    avatar_lorelei_earrings_variant: 'earringsProbability',
  };

  const buildAvatarParams = (form, overrides = {}) => {
    const seed = overrides.avatar_preset || readAvatarValue(form, 'avatar_preset');
    if (!seed) return null;

    const params = new URLSearchParams({ seed });
    avatarComponentFields.forEach((field) => {
      const value = Object.prototype.hasOwnProperty.call(overrides, field)
        ? overrides[field]
        : readAvatarValue(form, field);
      const param = avatarComponentFieldMap[field];
      const probabilityParam = avatarOptionalProbabilityMap[field];

      if (probabilityParam) {
        params.set(probabilityParam, value ? '100' : '0');
      }

      if (value && param) params.set(param, value);
    });

    return params;
  };

  const updateAvatarPreview = (form) => {
    const preview = form.querySelector('[data-avatar-preview] .pkt-avatar');
    if (!preview) return;
    const image = preview.querySelector('.pkt-avatar__img');
    if (!image) return;

    const params = buildAvatarParams(form);
    if (!params) return;

    const url = `${avatarEndpoint}?${params.toString()}`;
    if (!url) return;
    image.src = url;
  };

  const updateAvatarOptionPreviews = (form) => {
    form.querySelectorAll('[data-avatar-option-thumb]').forEach((image) => {
      const field = image.getAttribute('data-avatar-option-field') || '';
      const value = image.getAttribute('data-avatar-option-value') || '';
      const params = buildAvatarParams(form, { [field]: value });
      if (!params) return;

      image.src = `${avatarEndpoint}?${params.toString()}`;
    });
  };

  const renderAvatarSeedChoices = (form, seeds) => {
    const picker = form.querySelector('[data-avatar-seed-picker]');
    const grid = form.querySelector('[data-avatar-seed-picker-grid]');
    if (!picker || !grid) return;

    grid.innerHTML = '';
    seeds.forEach((seed, index) => {
      const params = buildAvatarParams(form, { avatar_preset: seed });
      if (!params) return;

      const card = document.createElement('button');
      card.type = 'button';
      card.className = 'avatar-seed-card';
      card.setAttribute('data-avatar-seed-option', seed);
      card.innerHTML = `
        <span class="avatar-seed-card__thumb">
          <img src="${avatarEndpoint}?${params.toString()}" alt="Grundvariante ${index + 1}">
        </span>
        <span class="avatar-seed-card__label">Variante ${index + 1}</span>
      `;
      card.addEventListener('click', () => {
        const seedField = form.querySelector('[data-avatar-field="avatar_preset"]');
        if (!(seedField instanceof HTMLInputElement)) return;
        seedField.value = seed;
        picker.hidden = true;
        updateAvatarPreview(form);
        updateAvatarOptionPreviews(form);
      });
      grid.appendChild(card);
    });

    picker.hidden = false;
  };

  document.querySelectorAll('[data-avatar-builder]').forEach((form) => {
    updateAvatarPreview(form);
    updateAvatarOptionPreviews(form);
    form.querySelectorAll('[data-avatar-field]').forEach((field) => {
      field.addEventListener('change', () => {
        updateAvatarPreview(form);
        updateAvatarOptionPreviews(form);
      });
      field.addEventListener('input', () => {
        updateAvatarPreview(form);
        updateAvatarOptionPreviews(form);
      });
    });

    const setActiveComponentPanel = (field) => {
      form.querySelectorAll('[data-avatar-component-tab]').forEach((button) => {
        const active = button.getAttribute('data-avatar-component-tab') === field;
        button.classList.toggle('is-active', active);
        button.setAttribute('aria-selected', active ? 'true' : 'false');
      });
      form.querySelectorAll('[data-avatar-component-panel]').forEach((panel) => {
        panel.classList.toggle('is-active', panel.getAttribute('data-avatar-component-panel') === field);
      });
    };

    form.querySelectorAll('[data-avatar-component-tab]').forEach((button) => {
      button.addEventListener('click', () => {
        const field = button.getAttribute('data-avatar-component-tab');
        if (field) setActiveComponentPanel(field);
      });
    });

    avatarComponentFields.forEach((field) => {
      form.querySelectorAll(`[data-avatar-field="${field}"]`).forEach((input) => {
        input.addEventListener('change', () => setActiveComponentPanel(field));
      });
    });

    const avatarPrefixes = [
      'abend', 'ahorn', 'anker', 'atlas', 'berg', 'blick', 'brise', 'echo',
      'eiche', 'fjord', 'fluss', 'fokus', 'hafen', 'herz', 'horizont', 'insel',
      'kiesel', 'kompass', 'kraft', 'linie', 'licht', 'lotse', 'mond', 'morgen',
      'nord', 'pfad', 'quelle', 'rauch', 'runde', 'sand', 'sommer', 'stein',
      'sturm', 'tal', 'ufer', 'wald', 'welle', 'wind', 'winkel', 'zeit',
    ];
    const avatarSuffixes = [
      'alpha', 'atlas', 'balu', 'bravo', 'caspar', 'dario', 'emil', 'felix',
      'fiete', 'finn', 'gerrit', 'hanno', 'ilan', 'joris', 'kian', 'leon',
      'linus', 'maik', 'malo', 'marlon', 'mats', 'mika', 'milan', 'noel',
      'ole', 'oskar', 'pepe', 'quinn', 'remo', 'sam', 'taro', 'timo',
      'veit', 'vito', 'yaro', 'yuri', 'zeno', 'zuri',
    ];
    const slugifySeed = (value) => value.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 64) || 'papa-kind-treff';
    const buildSeed = () => {
      const prefix = avatarPrefixes[Math.floor(Math.random() * avatarPrefixes.length)];
      const suffix = avatarSuffixes[Math.floor(Math.random() * avatarSuffixes.length)];
      const tail = Math.floor(Math.random() * 997);
      return slugifySeed(`${prefix}-${suffix}-${tail}`);
    };

    form.querySelector('[data-avatar-reroll]')?.addEventListener('click', () => {
      const seedField = form.querySelector('[data-avatar-field="avatar_preset"]');
      if (!(seedField instanceof HTMLInputElement)) return;
      const currentSeed = readAvatarValue(form, 'avatar_preset');
      const seeds = [];
      while (seeds.length < 8) {
        const candidate = buildSeed();
        if (candidate === currentSeed || seeds.includes(candidate)) continue;
        seeds.push(candidate);
      }

      renderAvatarSeedChoices(form, seeds);
    });

    form.querySelector('[data-avatar-seed-picker-close]')?.addEventListener('click', () => {
      const picker = form.querySelector('[data-avatar-seed-picker]');
      if (picker) picker.hidden = true;
    });
  });

  document.querySelectorAll('[data-nav-events]').forEach(link => {
    link.addEventListener('click', async () => {
      if (window.location.pathname === '/' && window.location.hash === '#events') {
        await ensureEventsLocation();
      }
    });
  });

  consentState = readConsent();
  if (consentState?.analytics) {
    loadMatomo();
  }
  showConsentBannerIfNeeded();

  try {
    if (!isLoggedIn) {
      const guestPreference = window.localStorage.getItem('pkt_location_preference_guest');
      if (guestPreference && ['disabled', 'prompt', 'enabled'].includes(guestPreference)) {
        effectiveLocationPreference = guestPreference;
      }
    }
  } catch (err) {
    // ignore
  }

  const initialLocation = effectiveLocationPreference === 'disabled' ? null : applyStoredLocationToForm();
  if (effectiveLocationPreference === 'disabled') {
    clearStoredLocation();
  }
  renderSlider(initialLocation);
  renderThreadSlider();

  if (effectiveLocationPreference === 'enabled' && window.location.pathname === '/' && consentState?.external_services) {
    ensureEventsLocation();
  } else if (window.location.hash === '#events' || window.location.hash === '#quicksearch') {
    ensureEventsLocation();
  }

  window.addEventListener('hashchange', () => {
    if (window.location.hash === '#events' || window.location.hash === '#quicksearch') {
      ensureEventsLocation();
    }
  });
});
