{"id":6492,"date":"2025-11-02T23:00:23","date_gmt":"2025-11-02T22:00:23","guid":{"rendered":"https:\/\/toppenafdanmark.dk\/?page_id=6492"},"modified":"2025-11-20T05:38:24","modified_gmt":"2025-11-20T04:38:24","slug":"book-hoteller","status":"publish","type":"page","link":"https:\/\/toppenafdanmark.dk\/de\/book-hoteller\/","title":{"rendered":"Book hoteller"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"6492\" class=\"elementor elementor-6492\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-03e3e4b e-con-full e-flex e-con e-child\" data-id=\"03e3e4b\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e716a42 elementor-widget elementor-widget-html\" data-id=\"e716a42\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<head>\n  <title>Oplevelser i Nordjylland | Toppen af Danmark <\/title>\n  <meta name=\"description\" content=\"Kort over oplevelser i Nordjylland: gallerier, antik, genbrug og kunsth\u00e5ndv\u00e6rk i Vendsyssel\">\n  <script type=\"application\/ld+json\">\n  {\n    \"@context\": \"https:\/\/schema.org\",\n    \"@type\": \"WebPage\",\n    \"name\": \"Oplevelser i Nordjylland\",\n    \"description\": \"Kort over oplevelser i Nordjylland: gallerier, genbrugsbutikker, antik & kunsth\u00e5ndv\u00e6rk i Vendsyssel\",\n    \"hasMap\": \"https:\/\/slowguide.dk\/\u2026\"\n  }\n  <\/script>\n<\/head>\n\n\n<!-- \n<div id=\"search-container\" style=\"position:absolute; top:4rem; left:1rem; transform:none; z-index:2000; width:calc(100% - 2rem); max-width:400px;\">\n  <div class=\"flex items-center bg-white rounded shadow\">\n    <input id=\"search-input\" type=\"text\" class=\"flex-1 p-3 outline-none\" placeholder=\"S\u00f8g\u2026\" \/>\n    <button id=\"search-btn\" class=\"p-3\"><i class=\"fa fa-search\"><\/i><\/button>\n  <\/div>\n  <ul id=\"search-results\" class=\"bg-white rounded-b overflow-auto max-h-60 hidden\"><\/ul>\n<\/div>\n-->\n<!-- Map -->\n<div id=\"map\"><\/div>\n\n<!-- Info panel -->\n<div id=\"info-panel\"><\/div>\n\n\n\n<!-- Tailwind for styling (optional) -->\n<script src=\"https:\/\/cdn.tailwindcss.com\"><\/script>\n\n<!-- FontAwesome -->\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=Poppins&display=swap\" rel=\"stylesheet\">\n\n<link rel=\"stylesheet\" href=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/font-awesome\/6.5.0\/css\/all.min.css\" integrity=\"sha512-...\" crossorigin=\"anonymous\" referrerpolicy=\"no-referrer\" \/>\n\n<!-- Style-->\n<style>\n\/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 MAP \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n#map {\n  height: 50svh;\n  padding-bottom: 80px;\n  box-sizing: border-box;\n  width: 100%;\n}\n\n\n\n\n\/* Mobile override for map height *\/\n@media (max-width: 1024px) {\n  #map {\n    height: 100svh;\n  }\n}\n\n\n\/* Mobile override for map height *\/\n@media (max-width: 768px) {\n  #map {\n    height: 70svh;\n  }\n}\n\n\/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 INFO PANEL \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n\n\/* MOBILE (bottom pop-up) *\/\n#info-panel {\n  position: fixed;\n  bottom: 250%;\n  left: 50%;\n  transform: translateX(-50%);\n  width: 90%;\n  max-width: 400px;\n  height: 200px;\n  background: white;\n  padding: 1rem;\n  border-radius: 20px 20px 0 0;\n  box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.25);\n  overflow-y: auto;\n  transition: bottom 0.3s ease;\n  z-index: 2000;\n}\n\n#info-panel.open {\n  bottom: 200px;\n  padding-bottom: 220px;\n}\n\n\/* DESKTOP (side panel) *\/\n@media (min-width: 780px) {\n  #info-panel {\n    top: 40%;\n    bottom: 80px;\n    left: -400px;\n    transform: none;\n    width: 360px;\n    height: 600px;\n    max-height: calc(100vh - 160px);\n    \n    border-radius: 0px 20px 20px 0px;  \/* \u2190 fixes your screenshot issue *\/\n    box-shadow: 4px 0 16px rgba(0, 0, 0, 0.25);\n    overflow-y: auto;\n    transition: left 0.3s ease;\n    scrollbar-gutter: stable;\n  }\n\n  #info-panel.open {\n    left: 0;\n  }\n\n  #info-panel::-webkit-scrollbar {\n    width: 8px;\n  }\n\n  #info-panel::-webkit-scrollbar-thumb {\n    background: rgba(0, 0, 0, 0.3);\n    border-radius: 4px;\n  }\n}\n\n\n\/* add at the bottom of your <style> block *\/\n\n#info-panel img {\n  width: 100%;\n  height: 180px;        \/* fixed height *\/\n  object-fit: cover;    \/* crop to fill *\/\n  border-top-left-radius: 20px;\n  border-top-right-radius: 20px;\n}\n\n#info-panel .category-badge {\n  position: absolute;\n  top: 1rem;\n  right: 1rem;\n  display: flex;\n  align-items: center;\n  background: rgba(255,255,255,0.9);\n  padding: 0.25rem 0.5rem;\n  border-radius: 1rem;\n  font-size: 0.875rem;\n}\n\n#info-panel .category-badge img {\n  width: 1rem;\n  height: 1rem;\n  margin-left: 0.3rem;\n}\n\n\n\n\n\/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 MOBILE CHAT POSITION \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n@media (max-width: 767px) {\n  #chat-toggle-btn {\n    position: absolute;\n    top: 10rem;\n    right: 0.5rem;\n    bottom: auto;\n    left: auto;\n    transform: none;\n    z-index: 3000;\n  }\n\n  \n}\n\n\/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 MAP MARKER LABEL (OPTIONAL) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n.marker-label {\n  background: rgba(0, 0, 0, 0.7);\n  padding: 2px 6px;\n  border-radius: 4px;\n  transform: translateY(-10px);\n  white-space: nowrap;\n}\n\n\/* \u2500\u2500\u2500 MOBIL: st\u00f8rre \u00e5bent POI-panel + swipe-hint \u2500\u2500\u2500\u2500\u2500 *\/\n@media (max-width: 767px) {\n  \/* Tillad auto-h\u00f8jde op til 50vh, s\u00e5 titel og tekst ogs\u00e5 vises *\/\n  #info-panel {\n    height: auto;\n    max-height: 50vh;\n  }\n  #info-panel.open {\n    bottom: 0;\n    height: auto;\n    max-height: 50vh;\n  }\n\n\n \/* only show when panel has overflow *\/\n#info-panel.has-overflow::after {\n  content: '\u2b06\ufe0f Swipe for mere';\n  position: absolute;\n  bottom: 8px;\n  left: 50%;\n  transform: translateX(-50%);\n  background: rgba(255,255,255,0.9);\n  padding: 4px 8px;\n  border-radius: 12px;\n  font-size: 0.75rem;\n  pointer-events: none;\n}\n\n  \/* G\u00f8r X-knappen lettere at ramme *\/\n  #info-panel .close-btn {\n    width: 32px;\n    height: 32px;\n    padding: 8px;\n    font-size: 1.75rem;\n  }\n    \/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 POI LABEL STYLING \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n  .poi-label {\n    transform: translateY(-25px);\n    white-space: nowrap;\n    text-shadow: 0 0 2px rgba(0,0,0,0.6);\n  }\n}\n\n#chat-input-wrapper {\n  background: #fff;\n}\n\n#chat-input-wrapper input {\n  \/* fjern browser-specifik margin\/padding p\u00e5 mobil *\/\n  margin: 0;\n}\n\n#chat-send-btn {\n  border-top-left-radius: 0;\n  border-bottom-left-radius: 0;\n}\n<\/style>\n\n\n<style>\n\/* Scoped search bar styling *\/\n#search-container {\n  position: absolute !important;\n  top: 2rem !important;\n  left: 1rem !important;\n  width: calc(100% - 2rem) !important;\n  max-width: 400px !important;\n  transform: none !important;\n  z-index: 2000 !important;\n}\n\n\n\/* Mobile override for map height *\/\n@media (max-width: 768px) {\n #search-container {\n  top: 2rem !important;\n\n}\n}\n\n#search-container .flex.items-center {\n  background: white !important;\n  border: none !important;\n  box-shadow: 0 2px 8px rgba(0,0,0,0.1) !important;\n}\n#search-container #search-input {\n  flex: 1 !important;\n  padding: 0.75rem !important;\n  outline: none !important;\n  border: none !important;\n  box-sizing: border-box !important;\n}\n#search-container #search-btn {\n  padding: 0.75rem !important;\n  border: none !important;\n  background: none !important;\n  cursor: pointer !important;\n}\n#search-container #search-results {\n  background: white !important;\n  border: 1px solid #ddd !important;\n  border-top: none !important;\n  max-height: 60vh !important;\n  overflow: auto !important;\n  margin: 0 !important;\n  padding: 0 !important;\n  list-style: none !important;\n}\n#search-container #search-results.hidden {\n  display: none !important;\n}\n#search-container #search-results li {\n  padding: 0.5rem 1rem !important;\n  cursor: pointer !important;\n}\n#search-container #search-results li:hover {\n  background: #f0f0f0 !important;\n}\n<\/style>\n\n<style>\n@media (max-width: 768px) {\n  #search-container {\n    top: 2rem;\n    left: 1rem;\n    right: auto;\n    width: calc(100% - 2rem);\n    max-width: none;\n    transform: none;\n  }\n}\n<\/style>\n\n\n\n<style>\n\/* Carousel slides *\/\n.info-carousel, .review-carousel {\n  position: relative;\n  overflow: hidden;\n  border-radius: 12px;\n  margin-bottom: 1rem;\n}\n.carousel-slide {\n  display: none;\n  width: 100%;\n}\n.carousel-slide.active {\n  display: block;\n}\n.carousel-nav {\n  position: absolute;\n  top: 50%;\n  transform: translateY(-50%);\n  font-size: 1.5rem;\n  background: rgba(255,255,255,0.8);\n  border-radius: 50%;\n  width: 32px;\n  height: 32px;\n  text-align: center;\n  line-height: 32px;\n  cursor: pointer;\n}\n.carousel-nav.prev { left: 8px; }\n.carousel-nav.next { right: 8px; }\n\n\/* Hide arrows on the review carousel *\/\n.review-carousel .carousel-nav {\n  display: none;\n}\n\n\/* Icon buttons *\/\n.btn-route, .btn-website {\n  width: 40px; height: 40px; border-radius: 50%;\n  display: inline-flex; justify-content: center; align-items: center;\n  margin-right: 0.5rem; cursor: pointer; border: none;\n}\n.btn-route { background: #cceeff; color: #0077cc; }\n.btn-website { background: #ffddee; color: #cc0066; }\n\n\/* Opening hours list spacing *\/\n.opening-hours li {\n  font-size: 0.875rem;\n  line-height: 1.4;\n  color: #333;\n  margin-bottom: 0.25rem;\n}\n\n\/* More breathing room under section headings *\/\n.p-4 h2 {\n  margin-bottom: 1rem;\n}\n\/* Rating buttons *\/\n.rating { margin-top: 0.5rem; display: flex; gap: 0.5rem; }\n.rate-btn { background: transparent; border: none; font-size: 1.2rem; cursor: pointer; }\n<\/style>\n\n\n\n<script>\n    const categories = [\n  \n  \n  \n \n  \n  \n  \n  {\n    id: \"hotel\",\n    label: \"Hotel\",\n    items: [\n     {\n        \"name\": \"BB Hotels Frederikshavn (turisthotellet)\",\n        \"categoryId\": \"hotel\",\n        \"lat\": 57.4351225,\n        \"lng\": 10.5323018,\n        \"addr\": \"Margrethevej 5, 9900 Frederikshavn\"\n    },\n    \n    \n    \n    {\n        \"name\": \"Plesner Badehotel\",\n        \"categoryId\": \"hotel\",\n        \"lat\": 57.7222914,\n        \"lng\": 10.5880961,\n        \"addr\": \"Holstvej 8, 9990 Skagen\"\n    },\n    \n    \n   \n    \n    {\n        \"name\": \"Aalb\u00e6k Badehotel\",\n        \"categoryId\": \"hotel\",\n        \"lat\": 57.5940764,\n        \"lng\": 10.4113993,\n        \"addr\": \"Skagensvej 42, \u00c5lb\u00e6k By, 9982 \u00c5lb\u00e6k\"\n    },\n    {\n      \"name\": \"Strandby Badehotel\",\n      \"categoryId\": \"hotel\",\n      \"lat\": 57.49414340870556,\n      \"lng\": 10.498784285833919,\n      \"addr\": \"Havnevej 11, 9970 Strandby, Denmark\",\n      \"link\": \"https:\/\/visitvendsyssel.dk\/strandby-badehotel\/\"\n    },\n    {\n      \"name\": \"Danhostel Frederikshavn\",\n      \"categoryId\": \"hotel\",\n      \"lat\": 57.43669255371079,\n      \"lng\": 10.535033688037927,\n      \"addr\": \"L\u00e6s\u00f8gade 18, 9900 Frederikshavn\",\n      \"link\": \"https:\/\/visitvendsyssel.dk\/danhostel-frederikshavn-city\/\"\n    },\n    {\n      \"name\": \"Quality Hotel The Reef\",\n      \"categoryId\": \"hotel\",\n      \"lat\": 57.439003155510285,\n      \"lng\": 10.53693045513972,\n      \"addr\": \"Tordenskjoldsgade 14, 9900 Frederikshavn\",\n      \"link\": \"https:\/\/visitvendsyssel.dk\/quality-hotel-the-reef\/\"\n    },\n    {\n      \"name\": \"Color Hotel Skagen\",\n      \"categoryId\": \"hotel\",\n      \"lat\": 57.72329789856428,\n      \"lng\": 10.556616964793267,\n      \"addr\": \"Gl. Landevej 39, 9990 Skagen\",\n      \"link\": \"https:\/\/visitvendsyssel.dk\/color-hotel-skagen\/\"\n    },\n    {\n      \"name\": \"Langagergaard\",\n      \"categoryId\": \"hotel\",\n      \"lat\": 57.65604839323597,\n      \"lng\": 10.446817882483456,\n      \"addr\": \"Kandestedvej 76, Hulsig Skagen\",\n      \"link\": \"https:\/\/visitvendsyssel.dk\/langagergaard\/\"\n    },\n    {\n      \"name\": \"Br\u00f8ndums Hotel\",\n      \"categoryId\": \"hotel\",\n      \"lat\": 57.72477832189682,\n      \"lng\": 10.598362838523878,\n      \"addr\": \"Anchersvej 3, 9990 Skagen\",\n      \"link\": \"https:\/\/visitvendsyssel.dk\/broendums-hotel\/\"\n    },\n    {\n      \"name\": \"Danhostel Skagen\",\n      \"categoryId\": \"hotel\",\n      \"lat\": 57.72179842360213,\n      \"lng\": 10.568323786423312,\n      \"addr\": \"Rolighedsvej 2, 9990 Skagen\",\n      \"link\": \"https:\/\/visitvendsyssel.dk\/danhostel-skagen\/\"\n    },\n    {\n      \"name\": \"Foldens Hotel\",\n      \"categoryId\": \"hotel\",\n      \"lat\": 57.7231028983197,\n      \"lng\": 10.59174909002715,\n      \"addr\": \"Sct. Laurentii Vej 41, 9990 Skagen\",\n      \"link\": \"https:\/\/visitvendsyssel.dk\/foldens-hotel\/\"\n    },\n    {\n      \"name\": \"Aalb\u00e6k Badehotel\",\n      \"categoryId\": \"hotel\",\n      \"lat\": 57.594081062064205,\n      \"lng\": 10.413978559183695,\n      \"addr\": \"Skagensvej 42, 9982 Aalb\u00e6k\",\n      \"link\": \"https:\/\/visitvendsyssel.dk\/aalbaek-badehotel\/\"\n    },\n    {\n      \"name\": \"Hjorths Badehotel\",\n      \"categoryId\": \"hotel\",\n      \"lat\": 57.66010902043799,\n      \"lng\": 10.389861672516261,\n      \"addr\": \"Kandebakkevej 17, 9990 Skagen\",\n      \"link\": \"https:\/\/visitvendsyssel.dk\/hjorths-badehotel\/\"\n    },\n    {\n      \"name\": \"H\u00f8jengran Time Share\",\n      \"categoryId\": \"hotel\",\n      \"lat\": 57.72154061327354,\n      \"lng\": 10.528941853481173,\n      \"addr\": \"Flagbakkevej 28, 9990 Skagen\",\n      \"link\": \"https:\/\/visitvendsyssel.dk\/hoejengran-time-share\/\"\n    },\n    {\n      \"name\": \"Plesners Badehotel\",\n      \"categoryId\": \"hotel\",\n      \"lat\": 57.72238597429572,\n      \"lng\": 10.59300991300038,\n      \"addr\": \"Holstvej 4-8, 9990 Skagen\",\n      \"link\": \"https:\/\/visitvendsyssel.dk\/plesners-badehotel\/\"\n    },\n    {\n      \"name\": \"Ruths Hotel\",\n      \"categoryId\": \"hotel\",\n      \"lat\": 57.7271250722674,\n      \"lng\": 10.521350859509994,\n      \"addr\": \"Hans Ruths Vej 1, 9990 Skagen\",\n      \"link\": \"https:\/\/visitvendsyssel.dk\/ruths-hotel\/\"\n    },\n    {\n      \"name\": \"Skagen Hotel\",\n      \"categoryId\": \"hotel\",\n      \"lat\": 57.723524973427246,\n      \"lng\": 10.592762194146266,\n      \"addr\": \"Sct. Laurentii Vej 35, 9990 Skagen\",\n      \"link\": \"https:\/\/visitvendsyssel.dk\/skagen-hotel\/\"\n    },\n    {\n      \"name\": \"Hotel Inger\",\n      \"categoryId\": \"hotel\",\n      \"lat\": 57.6583774642392,\n      \"lng\": 10.461128538000253,\n      \"addr\": \"Hulsigvej 17, 9990 Skagen\",\n      \"link\": \"https:\/\/visitvendsyssel.dk\/hotel-inger\/\"\n    },\n    {\n      \"name\": \"Hotel Marie\",\n      \"categoryId\": \"hotel\",\n      \"lat\": 57.72046795090024,\n      \"lng\": 10.589085073890962,\n      \"addr\": \"Havneplads 6, 9990 Skagen\",\n      \"link\": \"https:\/\/visitvendsyssel.dk\/hotel-marie\/\"\n    },\n    {\n      \"name\": \"Hotel Tannishus\",\n      \"categoryId\": \"hotel\",\n      \"lat\": 57.59323968383357,\n      \"lng\": 10.184604021861302,\n      \"addr\": \"Tannisbugtvej 123, Tversted Strand, 9881 Bindslev\",\n      \"link\": \"https:\/\/visitvendsyssel.dk\/hotel-tannishus\/\"\n    },\n    {\n      \"name\": \"Skagen Strand Feriecenter\",\n      \"categoryId\": \"hotel\",\n      \"lat\": 57.66052217344832,\n      \"lng\": 10.465401440105477,\n      \"addr\": \"Tranevej 108, Hulsig, 9990 Skagen\",\n      \"link\": \"https:\/\/visitvendsyssel.dk\/skagen-strand-feriecenter\/\"\n    },\n    {\n      \"name\": \"Skagen Harbour Hotel\",\n      \"categoryId\": \"hotel\",\n      \"lat\": 57.71759557882314,\n      \"lng\": 10.582007185929974,\n      \"addr\": \"Vestre Strandvej 28, 9990 Skagen\",\n      \"link\": \"https:\/\/visitvendsyssel.dk\/skagen-harbour-hotel\/\"\n    },\n    {\n      \"name\": \"Skagen Motel\",\n      \"categoryId\": \"hotel\",\n      \"lat\": 57.722254790773704,\n      \"lng\": 10.573531315863042,\n      \"addr\": \"Frederikshavnsvej 8, 9990 Skagen\",\n      \"link\": \"https:\/\/visitvendsyssel.dk\/skagen-motel\/\"\n    }\n  \n    ]\n  },\n  \n  \n\n  \n  \n  ];\n\n<\/script>\n\n\n\n<script>\n\/\/ \u2190 Add at the very top of your main script block\nlet userPosition = null;\n\n\/\/ Haversine distance (kilometres) \u2013 needed for proximity sorting\nfunction haversine(lat1, lon1, lat2, lon2) {\n  const toRad = v => v * Math.PI \/ 180;\n  const R = 6371;           \/\/ Earth radius in km\n  const dLat = toRad(lat2 - lat1);\n  const dLon = toRad(lon2 - lon1);\n  const a =\n    Math.sin(dLat \/ 2) ** 2 +\n    Math.cos(toRad(lat1)) *\n      Math.cos(toRad(lat2)) *\n      Math.sin(dLon \/ 2) ** 2;\n  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));\n  return R * c;\n}\n\n\/\/ Geolocation is now handled in initMap.\n<\/script>\n\n\n<script>\n  \/\/ \u2500\u2500 Chat widget element \u2500\u2500\n  const chatEl = document.getElementById('chat-widget');\n\n  \/* ---------- default map position (top of Denmark) -------------- *\/\n  const MAP_CENTER   = { lat: 57.73, lng: 10.59 };   \/\/ Skagen \/ Grenen\n  const IS_MOBILE    = window.innerWidth < 768;\n  const DEFAULT_ZOOM = IS_MOBILE ? 11 : 10;\n  \/* --------------------------------------------------------------- *\/\n\n  \/\/ Build a POI list for system instructions (if you use OpenAI functions)\n  const poiListText = categories\n    .flatMap(c => c.items.map(i => `${i.name} (${c.id}): ${i.lat},${i.lng}`))\n    .join(\"\\n\");\n\n  const systemInstructions = `POI LIST:\n  ${poiListText}\n\n  ===============  CORE RULES  ===============\n  1. Language\n     \u2013 Detect the user\u2019s language from their first message  \n     \u2013 Reply ONLY in that language  \n  2. POI focus \u2026\n  ===========================================`;\n\n  let chatHistory = [{ role: \"system\", content: systemInstructions }];\n\n\/\/ === Globals ===\nlet map, placesService, markers = [], dirService, dirRenderer;\n\/\/ Cache for category icons\nconst iconCache = {};\n\n\n\n\/\/ === initMap ===\nfunction initMap() {\n  const fallbackCenter = { lat: 57.55, lng: 10.00 }; \/\/ Vendsyssel\n  const zoomFallback = IS_MOBILE ? 6 : 8;\n  createMap(fallbackCenter, zoomFallback); \/\/ Show full region first\n\n  navigator.geolocation.getCurrentPosition(\n    pos => {\n      const userPos = {\n        lat: pos.coords.latitude,\n        lng: pos.coords.longitude\n      };\n      \/\/ Animate to user location after a short delay\n      setTimeout(() => {\n        map.panTo(userPos);\n        map.setZoom(12);\n      }, 1000);\n    },\n    err => {\n      console.warn(\"Geolocation failed:\", err.message);\n      \/\/ Do nothing, stays in fallback\n    },\n    {\n      enableHighAccuracy: true,\n      timeout: 5000,\n      maximumAge: 0\n    }\n  );\n  \/\/ --- Postnummer search (Google Maps) ---\n  const input   = document.getElementById('search-input');\n  const btn     = document.getElementById('search-btn');\n  const results = document.getElementById('search-results');\n\n  \/\/ Only Danish 4-digit postnumre\n  const isPostnr = q => \/^\\s*\\d{4}\\s*$\/.test(q);\n\n  \/\/ Layer to draw postnummer polygons\n  const postnrData = new google.maps.Data({ map });\n  postnrData.setStyle({\n    strokeColor: '#0b68ff',\n    strokeWeight: 2,\n    fillColor: '#0b68ff',\n    fillOpacity: 0.08\n  });\n\n  function clearPostnr() {\n    const feats = [];\n    postnrData.forEach(f => feats.push(f));\n    feats.forEach(f => postnrData.remove(f));\n  }\n\n  let abortCtrl;\n  async function suggestPostnr(q) {\n    try {\n      if (abortCtrl) abortCtrl.abort();\n      abortCtrl = new AbortController();\n      const url = `https:\/\/api.dataforsyningen.dk\/postnumre?nr=${encodeURIComponent(q)}`;\n      const res = await fetch(url, { signal: abortCtrl.signal });\n      if (!res.ok) return [];\n      const arr = await res.json(); \/\/ [{nr:\"9300\", navn:\"S\u00e6by\"}, ...]\n      return arr.map(p => ({ nr: p.nr, navn: p.navn }));\n    } catch {\n      return [];\n    }\n  }\n\n  function renderResults(items) {\n    if (!items.length) {\n      results.classList.add('hidden');\n      results.innerHTML = '';\n      return;\n    }\n    results.innerHTML = items\n      .map(it => `<li data-nr=\"${it.nr}\">Postnummer ${it.nr} \u2013 ${it.navn}<\/li>`)\n      .join('');\n    results.classList.remove('hidden');\n  }\n\n  async function zoomToPostnr(nr) {\n    const url = `https:\/\/api.dataforsyningen.dk\/postnumre\/${encodeURIComponent(nr)}?format=geojson`;\n    const res = await fetch(url);\n    if (!res.ok) { alert('Kunne ikke hente omr\u00e5det for postnummeret.'); return; }\n    const feature = await res.json(); \/\/ GeoJSON Feature\n\n    clearPostnr();\n    const added = postnrData.addGeoJson(feature); \/\/ array of features\n\n    \/\/ Fit bounds to geometry\n    const bounds = new google.maps.LatLngBounds();\n    added.forEach(f => f.getGeometry().forEachLatLng(latlng => bounds.extend(latlng)));\n    if (!bounds.isEmpty()) map.fitBounds(bounds, { padding: 30 });\n  }\n\n  \/\/ ---- Wire up UI ----\n  let lastQ = '';\n  input.addEventListener('input', async () => {\n    const q = input.value.trim();\n    if (q === lastQ) return;\n    lastQ = q;\n    if (isPostnr(q) || \/^\\d{1,4}$\/.test(q)) {\n      renderResults(await suggestPostnr(q));\n    } else {\n      results.classList.add('hidden');\n      results.innerHTML = '';\n    }\n  });\n\n  results.addEventListener('click', async (e) => {\n    const li = e.target.closest('li[data-nr]');\n    if (!li) return;\n    const nr = li.dataset.nr;\n    results.classList.add('hidden');\n    input.value = `Postnummer ${nr}`;\n    await zoomToPostnr(nr);\n  });\n\n  async function handleSubmit() {\n    const q = input.value.trim();\n    if (isPostnr(q)) {\n      const nr = q.match(\/\\d{4}\/)[0];\n      await zoomToPostnr(nr);\n    } else {\n      \/\/ TODO: call your existing non-postnr search here if you have one\n      \/\/ existingSearch(q);\n    }\n  }\n\n  btn.addEventListener('click', handleSubmit);\n  input.addEventListener('keydown', (e) => { if (e.key === 'Enter') handleSubmit(); });\n\n  \/\/ Optional niceties\n  document.addEventListener('click', (e) => {\n    if (!results.contains(e.target) && e.target !== input) {\n      results.classList.add('hidden');\n    }\n  });\n  input.addEventListener('blur', () => { if (!input.value.trim()) clearPostnr(); });\n\n  if (input && !input.placeholder.includes('postnr')) {\n    input.placeholder = 'S\u00f8g\u2026 (steder, postnr)';\n  }\n  \/\/ --- end Postnummer search ---\n}\n\n\nfunction createMap(center, zoom) {\n  map = new google.maps.Map(document.getElementById(\"map\"), {\n    center,\n    zoom,\n    mapTypeId: \"hybrid\",\n    gestureHandling: IS_MOBILE ? \"greedy\" : \"cooperative\",\n    streetViewControl: false,\n    fullscreenControl: false,\n    mapTypeControl: false,\n    styles: [\n      {\n        featureType: \"poi\",\n        stylers: [{ visibility: \"off\" }]\n      }\n    ]\n  });\n\n  dirService   = new google.maps.DirectionsService();\n  dirRenderer  = new google.maps.DirectionsRenderer({ map });\n  placesService = new google.maps.places.PlacesService(map);\n\n  \/\/ Wait until the map is fully loaded before adding markers\n  google.maps.event.addListenerOnce(map, 'idle', showAll);\n}\n\n\/\/ Fetch Google Place details by name and location\nfunction fetchPlaceDetails(name, lat, lng, callback) {\n  \/\/ First find the place via a nearby text search\n  const searchRequest = {\n    location: new google.maps.LatLng(lat, lng),\n    radius: 100,           \/\/ search within 100m of the marker\n    query: name\n  };\n  placesService.textSearch(searchRequest, (results, status) => {\n    if (status === google.maps.places.PlacesServiceStatus.OK && results[0]) {\n      const placeId = results[0].place_id;\n      \/\/ Now request detailed fields\n      const detailRequest = {\n        placeId: placeId,\n        fields: [\n          'photos',\n          'opening_hours',\n          'reviews',\n          'rating',\n          'user_ratings_total',\n          'formatted_address',\n          'formatted_phone_number',\n          'website'\n        ]\n      };\n      placesService.getDetails(detailRequest, (place, status2) => {\n        if (status2 === google.maps.places.PlacesServiceStatus.OK) {\n          callback(place);\n        } else {\n          console.warn('getDetails failed:', status2);\n        }\n      });\n    } else {\n      console.warn('textSearch failed:', status);\n    }\n  });\n}\n  \/\/ Build category buttons (if you have <div id=\"cat-bar\">)\n  function buildButtons() {\n    const bar = document.getElementById(\"cat-bar\");\n    categories.forEach(c => {\n      const btn = document.createElement(\"button\");\n      btn.className = \"px-3 py-1 rounded bg-red-600 text-white text-sm\";\n      btn.innerText = c.label;\n      btn.onclick = () => showCategory(c.id);\n      bar.appendChild(btn);\n    });\n    const all = document.createElement(\"button\");\n    all.className = \"px-3 py-1 rounded border text-sm\";\n    all.innerText = \"Vis alle\";\n    all.onclick = showAll;\n    bar.appendChild(all);\n  }\n\n\n\n  \/\/ Clear all markers and directions\n  function clearMarkers() {\n    markers.forEach(m => m.setMap(null));\n    markers = [];\n    dirRenderer.set(\"directions\", null);\n  }\n\n  \/\/ Show only one category\n  async function showCategory(id) {\n    clearMarkers();\n    \/\/ Preload icon for this category\n    await makeCategoryIcon(id);\n    const cat = categories.find(c => c.id === id);\n    await Promise.all(cat.items.map(i => addMarker(i)));\n    if (cat.items.length) {\n      const bounds = new google.maps.LatLngBounds();\n      cat.items.forEach(i => bounds.extend({ lat: i.lat, lng: i.lng }));\n      map.fitBounds(bounds);\n    } else {\n      map.setCenter({ lat: 57.55, lng: 10.00 });\n      map.setZoom(10);\n    }\n    panel.classList.remove(\"open\");\n  }\n\n  \/\/ Show all POIs\n  async function showAll() {\n    clearMarkers();\n    \/\/ Preload icons for all categories before adding markers\n    const categoryIds = [...new Set(categories.map(c => c.id))];\n    await Promise.all(categoryIds.map(id => makeCategoryIcon(id)));\n    await Promise.all(categories.flatMap(c => c.items).map(i => addMarker(i)));\n    panel.classList.remove(\"open\");\n  }\n\n\/\/ after opening, check if the content overflows\nsetTimeout(() => {\n  if (panel.scrollHeight > panel.clientHeight) {\n    panel.classList.add('has-overflow');\n  } else {\n    panel.classList.remove('has-overflow');\n  }\n}, 50);\n\n\n\n  \/\/ TranslatePress helper\n  function trpWrap(txt) {\n    const safe = txt.replace(\/\"\/g,'&quot;');\n    return `<span data-trpgettextoriginal=\"${safe}\">${txt}<\/span>`;\n  }\n\/\/ Info-panel container\nconst panel = document.getElementById(\"info-panel\");\n\n\/\/ TranslatePress dynamic scan\nfunction trpTranslateDynamic(node) {\n  if (window.trp?.translateNode)          \n    trp.translateNode(node);\n  else if (window.TRPMOFunction?.translateDomStrings) \n    TRPMOFunction.translateDomStrings(node);\n  else \n    window.dispatchEvent(new CustomEvent('trp_translate_dynamic_content',{detail:node}));\n}\n\n\/\/ \u2500\u2500\u2500 Open POI info panel \u2500\u2500\u2500\nasync function openPanel(i) {\n  \/\/ 1) Load icon definition\n  const iconDef = await makeCategoryIcon(i.categoryId);\n  \/\/ Always use .url, fallback.svg if none\n  const iconUrl = iconDef.url;\n\n  \/\/ 2) category labels\n  const labels = {\n    kunstgalleri:     'Kunstgalleri',\n    galleri:          'Kunstgalleri',\n    antik:             'Antik',\n    genbrug:           'Genbrug',\n    oplevelser:        'Oplevelser',\n    museer:            'Museer',\n    restauranter:      'Restauranter',\n    natteliv:          'Natteliv',\n    butikker:          'Butikker',\n    hotel:             'Hotel',\n    camping:           'Camping',\n    feriehuse:         'Feriehuse',\n    kunsthandvaerk:    'Kunsth\u00e5ndv\u00e6rk'\n  };\n  const label = labels[i.categoryId] || i.categoryId;\n\n  \/\/ 3) Build HTML with carousel and icon buttons\n  panel.innerHTML = `\n    <div id=\"close-panel\" style=\"position:absolute; top:1rem; right:1rem; font-size:1.75rem; cursor:pointer; z-index:10; padding:0.5rem;\">&times;<\/div>\n    <div style=\"position:relative;\">\n      <div class=\"info-carousel\">\n        ${i.photo ? `<div class=\"carousel-slide active\"><img decoding=\"async\" src=\"${i.photo}\" alt=\"${i.name}\" style=\"width:100%;\"\/><\/div>` : ''}\n        <div id=\"google-photos\"><\/div>\n        <div class=\"carousel-nav prev\">&#10094;<\/div>\n        <div class=\"carousel-nav next\">&#10095;<\/div>\n      <\/div>\n      <div class=\"category-badge\">\n        ${label}\n        <img decoding=\"async\" src=\"${iconUrl}\" alt=\"${label}\">\n      <\/div>\n    <\/div>\n    <div class=\"p-4\">\n      <h2 class=\"text-xl font-semibold mb-1\">${i.name}<\/h2>\n      <p class=\"text-sm text-gray-600 mb-4\">\n        <i class=\"fa fa-map-marker-alt\"><\/i> ${i.addr}\n      <\/p>\n      ${i.desc ? `<p class=\"text-sm mb-4\">${i.desc}<\/p>` : ''}\n      <div class=\"mb-4 flex items-center\">\n        <button class=\"btn-route\" onclick=\"routeTo(${i.lat}, ${i.lng}, '${i.addr.replace(\/'\/g,\"\\\\'\")}')\">\n          <i class=\"fa fa-directions\"><\/i>\n        <\/button>\n        ${i.link\n          ? `<button class=\"btn-website\" onclick=\"window.open('${i.link}','_blank')\">\n               <i class=\"fa fa-external-link-alt\"><\/i>\n             <\/button>`\n          : ``\n        }\n      <\/div>\n      <div id=\"google-info\" class=\"mb-6\"><\/div>\n      <div id=\"review-carousel\" class=\"review-carousel mt-4\"><\/div>\n    <\/div>\n  `;\n  \/\/ attach close handler\n  panel.querySelector('#close-panel').onclick = () => {\n    panel.classList.remove('open');\n    const VENDS_CENTER = { lat: 57.55, lng: 10.00 };\n    const FALLBACK_ZOOM = IS_MOBILE ? 8 : 10;\n    map.panTo(VENDS_CENTER);\n    map.setZoom(FALLBACK_ZOOM);\n  };\n\n  \/\/ 5) Show it\n  panel.classList.add('open');\n  map.panTo({ lat: i.lat, lng: i.lng });\n  map.setZoom(13);\n  trpTranslateDynamic(panel);\n\n  \/\/ fetch and inject Google data (robust: show panel even if fetch fails)\n  try {\n    fetchPlaceDetails(i.name, i.lat, i.lng, (place) => {\n      let html = '';\n\n      \/\/ Rating & total reviews\n      if (place.rating != null) {\n        html += `<div class=\"text-sm mb-2\"><strong>Bed\u00f8mmelse:<\/strong> ${place.rating} \u2b50 (${place.user_ratings_total || 0} anmeldelser)<\/div>`;\n      }\n\n      \/\/ Phone number\n      if (place.formatted_phone_number) {\n        html += `<div class=\"text-sm mb-1\"><strong>Telefon:<\/strong> ${place.formatted_phone_number}<\/div>`;\n      }\n\n      \/\/ Opening hours\n      if (place.opening_hours) {\n        html += `<div class=\"text-sm mb-2\"><strong>\u00c5bningstider:<\/strong><br>${place.opening_hours.weekday_text.join('<br>')}<\/div>`;\n      }\n\n      \/\/ inject Google photos into #google-photos carousel\n      if (place.photos) {\n        place.photos.forEach((p, idx) => {\n          const url = p.getUrl({ maxWidth:400 });\n          document.getElementById('google-photos').insertAdjacentHTML('beforeend',\n            `<div class=\"carousel-slide${idx? '' : ' active'}\"><img decoding=\"async\" src=\"${url}\" style=\"width:100%;\"\/><\/div>`);\n        });\n      }\n\n      document.getElementById('google-info').innerHTML = html;\n\n      \/\/ Reviews in carousel\n      if (place.reviews) {\n        place.reviews.slice(0,5).forEach((r, idx) => {\n          const snippet = r.text.length > 100 ? r.text.slice(0,100) + '...' : r.text;\n          document.getElementById('review-carousel').insertAdjacentHTML('beforeend',\n            `<div class=\"carousel-slide${idx? '' : ' active'}\">\n               <p><strong>${r.author_name}<\/strong> \u2b50${r.rating}<\/p>\n               <p>${snippet} ${r.text.length > 100 ? '<a href=\"#\" class=\"read-more\">Read more<\/a><span class=\"full-text\" style=\"display:none;\">' + r.text + '<\/span>' : ''}<\/p>\n             <\/div>`);\n        });\n        \/\/ add nav\n        const rc = document.getElementById('review-carousel');\n        rc.insertAdjacentHTML('beforeend','<div class=\"carousel-nav prev\">&#10094;<\/div><div class=\"carousel-nav next\">&#10095;<\/div>');\n        \/\/ initialize carousels dynamically now that content is injected\n        initCarousel(panel.querySelector('.info-carousel'));\n        initCarousel(rc);\n      }\n    });\n  } catch (e) {\n    console.error('Places fetch failed:', e);\n  }\n}\n\n\/\/ \u2500\u2500\u2500 Category icon loader (fixed) \u2500\u2500\u2500\nasync function makeCategoryIcon(categoryId) {\n  if (iconCache[categoryId]) return iconCache[categoryId];\n\n  console.log('[Debug] makeCategoryIcon called for categoryId:', categoryId);\n\n  \/\/ \u2705 Use correct WordPress upload path\n  const baseUrl = window.location.origin + '\/wp-content\/uploads\/2025\/09\/';\n  const fallback = baseUrl + 'fallback.svg';\n\n  const fileMap = {\n    galleri: 'Kunstgalleril-1.svg',\n    kunstgalleri: 'Kunstgalleril-1.svg',\n    antik: 'Antikl.svg',\n    genbrug: 'Genbrugsbutikkerl.svg',\n    oplevelser: 'Oplevelserl.svg',\n    museer: 'Museerl.svg',\n    restauranter: 'Restauranterl.svg',\n    feriehuse: 'Feriehusel.svg',\n    kunsthandvaerk: 'kunsthandvaerk.svg',\n    butikker: 'Butikkerl.svg',\n    camping: 'Campingl.svg',\n    hotel: 'Hotell.svg',\n    natteliv: 'Nattelivl.svg',\n    \/\/ absolute URL left as-is\n    gratisoplevelser: 'https:\/\/toppenafdanmark.dk\/wp-content\/uploads\/2025\/09\/gratisoplevelserl.svg'\n  };\n\n  \/\/ normalize key: lower-case + remove spaces\/diacritics -> safe lookup\n  function normalizeKey(k) {\n    return String(k || '')\n      .toLowerCase()\n      .normalize('NFKD')            \/\/ decompose accents\n      .replace(\/[\\u0300-\\u036f]\/g, '') \/\/ remove diacritic marks\n      .replace(\/[^a-z0-9]\/g, '');  \/\/ keep only alphanumerics\n  }\n\n  function getIconUrl(rawKey) {\n    const key = normalizeKey(rawKey);\n    const icon = fileMap[key] || null;\n    if (!icon) {\n      console.warn('[Debug] no mapping for key -> using fallback:', rawKey, 'normalized:', key);\n      return fallback;\n    }\n    return icon.startsWith('http') ? icon : baseUrl + icon;\n  }\n\n  const url = getIconUrl(categoryId);\n  console.log('[Debug] resolved icon url:', url);\n\n  \/\/ preload image to observe network \/ errors\n  const cssSize = window.innerWidth >= 768 ? 40 : 30;\n  const realPx = Math.round(cssSize * (window.devicePixelRatio || 1));\n\n  const dbgImg = new Image();\n  dbgImg.onload = () => console.log('[Debug] icon image loaded for', categoryId, url, 'size:', realPx);\n  dbgImg.onerror = (e) => console.error('[Debug] icon image failed to load for', categoryId, url, e);\n  dbgImg.src = url; \/\/ triggers network request\n\n  const iconObj = {\n    url,\n    size: new google.maps.Size(realPx, realPx),\n    scaledSize: new google.maps.Size(cssSize, cssSize),\n    anchor: new google.maps.Point(cssSize \/ 2, cssSize \/ 2),\n    optimized: false\n  };\n\n  iconCache[categoryId] = iconObj;\n  return iconObj;\n}\n\n\/\/ \u2500\u2500 Add a POI marker with hover\u2010bounce \u2500\u2500\nasync function addMarker(item) {\n  console.log('[Debug] addMarker called for item:', item.name, item.lat, item.lng);\n  const icon = await makeCategoryIcon(item.categoryId);\n  const m = new google.maps.Marker({\n    position: { lat: item.lat, lng: item.lng },\n    map: map,\n    title: item.name,\n    icon: icon,\n    optimized: false\n  });\n  \/\/ Ensure the loaded icon is applied\n  m.setIcon(icon);\n  console.log('[Debug] Marker created:', m, 'with icon:', icon);\n\n  \/\/ Hover\u2010effect: bounce on mouseover, stop on mouseout\n  m.addListener('mouseover', () => {\n    m.setAnimation(google.maps.Animation.BOUNCE);\n  });\n  m.addListener('mouseout', () => {\n    m.setAnimation(null);\n  });\n\n  \/\/ Click to open the info panel\n  m.addListener('click', () => openPanel(item));\n\n  markers.push(m);\n}\n\n\/\/ Optional: redraw on window resize\nwindow.addEventListener('resize', () => { clearMarkers(); showAll(); });\n\n\/\/ Open route in external Google Maps\nfunction routeTo(lat, lng, addr = null) {\n  const dest = addr ? encodeURIComponent(addr) : `${lat},${lng}`;\n  window.open(`https:\/\/www.google.com\/maps\/dir\/?api=1&destination=${dest}`, \"_blank\");\n}\n\n\/\/ \u2014\u2014 Search functionality \u2014\u2014 \nconst allPlaces = categories.flatMap(c => c.items);\nconst searchInput = document.getElementById('search-input');\nconst searchBtn = document.getElementById('search-btn');\nconst resultsList = document.getElementById('search-results');\nfunction renderResults(results) {\n  resultsList.innerHTML = results.map(r => `<li>${r.name}<\/li>`).join('');\n  resultsList.classList.toggle('hidden', results.length === 0);\n}\nsearchInput.addEventListener('input', () => {\n  const q = searchInput.value.trim().toLowerCase();\n  if (!q) { return renderResults([]); }\n  const matched = allPlaces.filter(p => p.name.toLowerCase().includes(q));\n  renderResults(matched.slice(0, 10));\n});\nresultsList.addEventListener('click', (e) => {\n  if (e.target.tagName === 'LI') {\n    const name = e.target.textContent;\n    const place = allPlaces.find(p => p.name === name);\n    if (place) {\n      openPanel(place);\n      map.panTo({ lat: place.lat, lng: place.lng });\n    }\n    renderResults([]);\n  }\n});\nsearchBtn.addEventListener('click', () => {\n  const q = searchInput.value.trim().toLowerCase();\n  const matched = allPlaces.filter(p => p.name.toLowerCase().includes(q));\n  if (matched[0]) {\n    openPanel(matched[0]);\n    map.panTo({ lat: matched[0].lat, lng: matched[0].lng });\n  }\n  renderResults([]);\n});\n\n<\/script>\n\n<script>\ndocument.addEventListener('DOMContentLoaded', () => {\n  \/\/ Global pendingPlaces for chat selection logic\n  let pendingPlaces = [];\n  \/\/ \u2500\u2500\u2500 Element refs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  const chatToggleBtn = document.getElementById('chat-toggle-btn');\n  const chatWidget    = document.getElementById('chat-widget');\n  const chatSendBtn   = document.getElementById('chat-send-btn');\n  const chatInput     = document.getElementById('chat-input');\n\n  \/\/ \u2500\u2500\u2500 UI helper \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  function appendMsg(side, txt) {\n    const log = document.getElementById('chat-log');\n    const d = document.createElement('div');\n    d.className = `msg ${side}`;\n    d.innerHTML = `<span>${txt}<\/span>`;\n    log.appendChild(d);\n    log.scrollTop = log.scrollHeight;\n  }\n\n  \/\/ \u2500\u2500\u2500 Helper to append AI message with rating UI \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  function appendAIMessage(text) {\n    const log = document.getElementById('chat-log');\n    const container = document.createElement('div');\n    container.className = 'msg ai';\n    container.innerHTML = `<span>${text}<\/span>\n      <div class=\"rating\">\n        <button class=\"rate-btn\" data-rating=\"1\">\ud83d\udc4d<\/button>\n        <button class=\"rate-btn\" data-rating=\"0\">\ud83d\udc4e<\/button>\n      <\/div>`;\n    log.appendChild(container);\n    log.scrollTop = log.scrollHeight;\n  }\n\n  \/\/ \u2500\u2500\u2500 AI Proxy helper \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  async function callChatAPI(messages) {\n    const res = await fetch('\/api\/chat', {\n      method: 'POST',\n      headers: {'Content-Type':'application\/json'},\n      body: JSON.stringify({ messages })\n    });\n    if (!res.ok) throw new Error(await res.text());\n    const { choices } = await res.json();\n    return choices[0].message.content;\n  }\n\n  \/\/ Custom system prompt for ChatGPT\n  const systemInstructions = `Du er en venlig, hj\u00e6lpsom AI-assistent. Hvis brugeren skriver med grammatiske fejl, fort\u00e6l venligt, at du ikke forstod, og bed om pr\u00e6cisering. Hvis du ikke har information lige nu, sig: \"Jeg har desv\u00e6rre ikke den information lige nu, men arbejder p\u00e5 at finde den.\" Stil opklarende sp\u00f8rgsm\u00e5l, n\u00e5r det er n\u00f8dvendigt. Svar altid p\u00e5 dansk i et klart og im\u00f8dekommende sprog.`;\n\n  \/\/ \u2500\u2500\u2500 Main chat function with local category\/search logic \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  async function sendChat() {\n    const raw = chatInput.value.trim();\n    if (!raw) return;\n    appendMsg('user', raw);\n    chatInput.value = '';\n    const q = raw.toLowerCase();\n\n    \/\/ --- Check if the user picked a pending place ---------------------\n    const numericChoice = parseInt(q, 10);\n    if (pendingPlaces.length && (!isNaN(numericChoice) || q.length > 2)) {\n      let chosen = null;\n      if (!isNaN(numericChoice) && numericChoice >= 1 && numericChoice <= pendingPlaces.length) {\n        chosen = pendingPlaces[numericChoice - 1];\n      } else {\n        chosen = pendingPlaces.find(p => p.name.toLowerCase().startsWith(q));\n      }\n      if (chosen) {\n        openPanel(chosen);\n        appendAIMessage(`Viser ${chosen.name} p\u00e5 kortet.`);\n        pendingPlaces = [];\n        return;\n      }\n    }\n\n    \/\/ 1) Exact category match or keyword-mapped category --------------\n    const allCats = Object.fromEntries(categories.map(c => [c.id, c]));\n    const keywordCategoryMap = {\n      fisk: 'restauranter', seafood: 'restauranter', restaurant: 'restauranter', caf\u00e9: 'restauranter',\n      kunst: 'galleri', gallery: 'galleri', oplevelse: 'oplevelser', museum: 'museer'\n    };\n    \/\/ try to resolve the user's query to a category id\n    let resolvedCatId = null;\n    if (allCats[q]) {\n      resolvedCatId = q;\n    } else if (Object.values(allCats).find(c => c.label.toLowerCase() === q)) {\n      resolvedCatId = Object.values(allCats).find(c => c.label.toLowerCase() === q).id;\n    } else {\n      resolvedCatId = keywordCategoryMap[Object.keys(keywordCategoryMap).find(k => q.includes(k))];\n    }\n\n    if (resolvedCatId) {\n      const cat = allCats[resolvedCatId];\n      \/\/ sort by distance if we know where the user is\n      let sorted = cat.items.slice();\n      if (userPosition) {\n        sorted = sorted\n          .map(it => ({ it, d: haversine(userPosition.lat, userPosition.lng, it.lat, it.lng) }))\n          .sort((a, b) => a.d - b.d)\n          .map(o => o.it);\n      }\n      pendingPlaces = sorted; \/\/ remember full list for follow-up\n      const top3 = sorted.slice(0, 3);\n      const bullets = top3.map((p, i) => {\n        let distTxt = '';\n        if (userPosition) {\n          const meters = haversine(userPosition.lat, userPosition.lng, p.lat, p.lng) * 1000;\n          distTxt = meters < 1000\n            ? ` \u2013 ${Math.round(meters)}\u202fm`\n            : ` \u2013 ${(meters \/ 1000).toLocaleString('da-DK', { minimumFractionDigits: 1, maximumFractionDigits: 1 })}\u202fkm`;\n        }\n        return `\u2022 ${p.name}${distTxt}`;\n      }).join('<br>');\n      appendAIMessage(\n        `Jeg fandt ${cat.items.length} ${cat.label.toLowerCase()} i n\u00e6rheden. Her er de 3 t\u00e6tteste:<br>${bullets}<br>` +\n        `Skriv navnet eller tallet p\u00e5 det sted du vil se, eller skriv \u201calle\u201d for hele listen.`\n      );\n      showCategory(cat.id);  \/\/ keep map in sync\n      return;\n    }\n\n    \/* 1\u2011bis) \u2014\u2014 City \/ location search \u2014\u2014 *\/\n    const queryTokens = q.split(\/\\s+\/).filter(t => t.length >= 3);   \/\/ ignore very short words\n    let locMatches = categories.flatMap(c => c.items)\n      .filter(item =>\n        item.addr && queryTokens.some(tok => item.addr.toLowerCase().includes(tok)));\n    if (locMatches.length) {\n      if (userPosition) {\n        locMatches = locMatches\n          .map(it => ({ it, d: haversine(userPosition.lat, userPosition.lng, it.lat, it.lng) }))\n          .sort((a, b) => a.d - b.d)\n          .map(o => o.it);\n      }\n      pendingPlaces = locMatches;                 \/\/ remember for follow\u2011ups\n      const top3 = locMatches.slice(0, 3);\n      const bullets = top3.map(p => `\u2022 ${p.name}`).join('<br>');\n      appendAIMessage(\n        `Jeg fandt ${locMatches.length} steder i omr\u00e5det. Her er de 3 t\u00e6tteste:<br>${bullets}<br>` +\n        `Skriv navnet eller tallet p\u00e5 det sted du vil se, eller skriv \u201calle\u201d for hele listen.`\n      );\n\n      \/\/ Show only these matches on the map\n      clearMarkers();\n      await Promise.all(locMatches.map(addMarker));\n      \/\/ --- Fit map to the matched POIs so the user instantly sees them ----\n      if (locMatches.length) {\n        const bounds = new google.maps.LatLngBounds();\n        locMatches.forEach(p => bounds.extend({ lat: p.lat, lng: p.lng }));\n        map.fitBounds(bounds);\n        \/\/ If all matches share the same coordinate, fallback to a sensible zoom\n        if (bounds.getNorthEast().equals(bounds.getSouthWest())) {\n          map.setZoom(13);\n        }\n      }\n      return;\n    }\n\n    \/\/ 2) Fuzzy search in names\/descriptions ---------------------------\n    let matches = categories.flatMap(c => c.items)\n      .filter(item =>\n        item.name.toLowerCase().includes(q) ||\n        (item.desc && item.desc.toLowerCase().includes(q))\n      );\n    if (userPosition) {\n      matches = matches\n        .map(item => ({ item, d: haversine(userPosition.lat, userPosition.lng, item.lat, item.lng) }))\n        .sort((a, b) => a.d - b.d)\n        .map(o => o.item);\n    }\n    if (matches.length) {\n      const pick = matches[0];\n      openPanel(pick);\n      appendAIMessage(`Jeg fandt \"${pick.name}\". Viser detaljer nu.`);\n      return;\n    }\n\n    \/\/ 3) Fallback to AI\n    try {\n      const reply = await callChatAPI([\n        { role: 'system', content: systemInstructions },\n        { role: 'user', content: raw }\n      ]);\n      appendAIMessage(reply);\n    } catch (err) {\n      appendAIMessage('Jeg forstod desv\u00e6rre ikke helt. Kan du pr\u00f8ve at sp\u00f8rge p\u00e5 en anden m\u00e5de?');\n      console.error(err);\n    }\n  }\n\n  \/\/ expose to inline onkeydown handler\n  window.sendChat = sendChat;\n\n  \/\/ \u2500\u2500\u2500 Wire events \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  chatToggleBtn.addEventListener('click', ()=>chatWidget.classList.toggle('open'));\n  chatSendBtn.addEventListener('click', sendChat);\n  chatInput.addEventListener('keydown', e => { if (e.key==='Enter') sendChat(); });\n});\n\n\/\/ \u2500\u2500\u2500 Feedback rating listener \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ndocument.addEventListener('click', e => {\n  if (e.target.matches('.rate-btn')) {\n    const rating = e.target.dataset.rating;\n    const msgEl = e.target.closest('.msg.ai');\n    const message = msgEl.querySelector('span').innerText;\n    fetch('\/api\/feedback', {\n      method: 'POST',\n      headers: { 'Content-Type':'application\/json' },\n      body: JSON.stringify({ message, rating })\n    });\n    msgEl.querySelector('.rating').innerHTML = '<em>Tak for din feedback!<\/em>';\n  }\n});\n<\/script>\n\n\n\n<script async defer\n        src=\"https:\/\/maps.googleapis.com\/maps\/api\/js?key=AIzaSyDCQ71JkJwYHfEm3us6JUxpOEDMnZbokzU&libraries=places&callback=initMap\">\n<\/script>\n\n<script>\nfunction initCarousel(container) {\n  let idx = 0;\n  const slides = container.querySelectorAll('.carousel-slide');\n  function show(i) {\n    slides.forEach((s, j)=> s.classList.toggle('active', j===i));\n  }\n  show(idx);\n  container.querySelector('.prev').onclick = ()=> { idx = (idx-1+slides.length)%slides.length; show(idx); };\n  container.querySelector('.next').onclick = ()=> { idx = (idx+1)%slides.length; show(idx); };\n  const navNext = container.querySelector('.next');\n  \/\/ auto-advance every 5 seconds\n  setInterval(() => navNext.click(), 5000);\n  \/\/ attach read-more handlers\n  container.querySelectorAll('.read-more').forEach(link => {\n    link.onclick = e => {\n      e.preventDefault();\n      const full = link.nextElementSibling;\n      link.style.display = 'none';\n      full.style.display = 'inline';\n    };\n  });\n}\ndocument.addEventListener('DOMContentLoaded',()=>{\n  document.querySelectorAll('.info-carousel').forEach(initCarousel);\n  document.querySelectorAll('.review-carousel').forEach(initCarousel);\n});\n<\/script>\n\n\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-d5a59f8 e-flex e-con-boxed e-con e-parent\" data-id=\"d5a59f8\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e8e8a75 elementor-widget elementor-widget-spacer\" data-id=\"e8e8a75\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"spacer.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-spacer\">\n\t\t\t<div class=\"elementor-spacer-inner\"><\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-d4a84f0 elementor-widget elementor-widget-heading\" data-id=\"d4a84f0\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Book dit ophold<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-9789892 e-con-full e-flex e-con e-child\" data-id=\"9789892\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-5dafb2b e-con-full e-flex e-con e-child\" data-id=\"5dafb2b\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-62e4bf5 elementor-widget elementor-widget-image\" data-id=\"62e4bf5\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;none&quot;}\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"https:\/\/toppenafdanmark.dk\/foldens-hotel\/\">\n\t\t\t\t\t\t\t<img fetchpriority=\"high\" decoding=\"async\" data-attachment-id=\"3933\" data-permalink=\"https:\/\/toppenafdanmark.dk\/de\/vinterbaderfestival\/foldens-hotel-1024x1024-2\/\" data-orig-file=\"https:\/\/i0.wp.com\/toppenafdanmark.dk\/wp-content\/uploads\/2025\/08\/Foldens-Hotel-1024x1024-1.jpg?fit=1024%2C1024&amp;ssl=1\" data-orig-size=\"1024,1024\" data-comments-opened=\"0\" data-image-meta=\"{&quot;aperture&quot;:&quot;10&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;SLT-A58&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;1405950817&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;20&quot;,&quot;iso&quot;:&quot;100&quot;,&quot;shutter_speed&quot;:&quot;0.003125&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;1&quot;}\" data-image-title=\"Foldens Hotel 1024&amp;#215;1024\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/toppenafdanmark.dk\/wp-content\/uploads\/2025\/08\/Foldens-Hotel-1024x1024-1.jpg?fit=800%2C800&amp;ssl=1\" width=\"800\" height=\"800\" src=\"https:\/\/i0.wp.com\/toppenafdanmark.dk\/wp-content\/uploads\/2025\/08\/Foldens-Hotel-1024x1024-1.jpg?fit=800%2C800&amp;ssl=1\" class=\"attachment-large size-large wp-image-3933\" alt=\"Foldens Hotel tilbyder Vinterbaderophold\" srcset=\"https:\/\/i0.wp.com\/toppenafdanmark.dk\/wp-content\/uploads\/2025\/08\/Foldens-Hotel-1024x1024-1.jpg?w=1024&amp;ssl=1 1024w, https:\/\/i0.wp.com\/toppenafdanmark.dk\/wp-content\/uploads\/2025\/08\/Foldens-Hotel-1024x1024-1.jpg?resize=300%2C300&amp;ssl=1 300w, https:\/\/i0.wp.com\/toppenafdanmark.dk\/wp-content\/uploads\/2025\/08\/Foldens-Hotel-1024x1024-1.jpg?resize=150%2C150&amp;ssl=1 150w, https:\/\/i0.wp.com\/toppenafdanmark.dk\/wp-content\/uploads\/2025\/08\/Foldens-Hotel-1024x1024-1.jpg?resize=768%2C768&amp;ssl=1 768w, https:\/\/i0.wp.com\/toppenafdanmark.dk\/wp-content\/uploads\/2025\/08\/Foldens-Hotel-1024x1024-1.jpg?resize=12%2C12&amp;ssl=1 12w\" sizes=\"(max-width: 800px) 100vw, 800px\" data-attachment-id=\"3933\" data-permalink=\"https:\/\/toppenafdanmark.dk\/vinterbaderfestival\/foldens-hotel-1024x1024-2\/\" data-orig-file=\"https:\/\/i0.wp.com\/toppenafdanmark.dk\/wp-content\/uploads\/2025\/08\/Foldens-Hotel-1024x1024-1.jpg?fit=1024%2C1024&amp;ssl=1\" data-orig-size=\"1024,1024\" data-comments-opened=\"0\" data-image-meta=\"{&quot;aperture&quot;:&quot;10&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;SLT-A58&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;1405950817&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;20&quot;,&quot;iso&quot;:&quot;100&quot;,&quot;shutter_speed&quot;:&quot;0.003125&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;1&quot;}\" data-image-title=\"Foldens Hotel 1024&amp;#215;1024\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/toppenafdanmark.dk\/wp-content\/uploads\/2025\/08\/Foldens-Hotel-1024x1024-1.jpg?fit=800%2C800&amp;ssl=1\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-c6c9d61 e-con-full e-flex e-con e-child\" data-id=\"c6c9d61\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-513bc6d elementor-widget elementor-widget-heading\" data-id=\"513bc6d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\"><a href=\"https:\/\/toppenafdanmark.dk\/foldens-hotel\/\">Foldens Hotel<\/a><\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-edac7aa elementor-widget elementor-widget-button\" data-id=\"edac7aa\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"button.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<div class=\"elementor-button-wrapper\">\n\t\t\t\t\t<a class=\"elementor-button elementor-button-link elementor-size-sm\" href=\"https:\/\/fold-bookyourstay.bookyourstay.eu\/booking\/fold\/rate?priceCalculationRateCode=SHHJ\" target=\"_blank\" rel=\"noopener\">\n\t\t\t\t\t\t<span class=\"elementor-button-content-wrapper\">\n\t\t\t\t\t\t\t\t\t<span class=\"elementor-button-text\">Book Nu<\/span>\n\t\t\t\t\t<\/span>\n\t\t\t\t\t<\/a>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-1438f04 e-con-full e-flex e-con e-child\" data-id=\"1438f04\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e7e5cb4 elementor-widget elementor-widget-image\" data-id=\"e7e5cb4\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"https:\/\/toppenafdanmark.dk\/aalbaek-badehotel\/\">\n\t\t\t\t\t\t\t<img decoding=\"async\" data-attachment-id=\"4251\" data-permalink=\"https:\/\/toppenafdanmark.dk\/de\/aalbaek-badehotel\/1024x1024-aalbaek-badehotel-2\/\" data-orig-file=\"https:\/\/i0.wp.com\/toppenafdanmark.dk\/wp-content\/uploads\/2025\/08\/1024x1024-aalbaek-badehotel-2.webp?fit=1024%2C1024&amp;ssl=1\" data-orig-size=\"1024,1024\" data-comments-opened=\"0\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"1024&amp;#215;1024 aalb\u00e6k badehotel 2\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/toppenafdanmark.dk\/wp-content\/uploads\/2025\/08\/1024x1024-aalbaek-badehotel-2.webp?fit=800%2C800&amp;ssl=1\" width=\"800\" height=\"800\" src=\"https:\/\/i0.wp.com\/toppenafdanmark.dk\/wp-content\/uploads\/2025\/08\/1024x1024-aalbaek-badehotel-2.webp?fit=800%2C800&amp;ssl=1\" class=\"attachment-large size-large wp-image-4251\" alt=\"\" srcset=\"https:\/\/i0.wp.com\/toppenafdanmark.dk\/wp-content\/uploads\/2025\/08\/1024x1024-aalbaek-badehotel-2.webp?w=1024&amp;ssl=1 1024w, https:\/\/i0.wp.com\/toppenafdanmark.dk\/wp-content\/uploads\/2025\/08\/1024x1024-aalbaek-badehotel-2.webp?resize=300%2C300&amp;ssl=1 300w, https:\/\/i0.wp.com\/toppenafdanmark.dk\/wp-content\/uploads\/2025\/08\/1024x1024-aalbaek-badehotel-2.webp?resize=150%2C150&amp;ssl=1 150w, https:\/\/i0.wp.com\/toppenafdanmark.dk\/wp-content\/uploads\/2025\/08\/1024x1024-aalbaek-badehotel-2.webp?resize=768%2C768&amp;ssl=1 768w, https:\/\/i0.wp.com\/toppenafdanmark.dk\/wp-content\/uploads\/2025\/08\/1024x1024-aalbaek-badehotel-2.webp?resize=12%2C12&amp;ssl=1 12w\" sizes=\"(max-width: 800px) 100vw, 800px\" data-attachment-id=\"4251\" data-permalink=\"https:\/\/toppenafdanmark.dk\/aalbaek-badehotel\/1024x1024-aalbaek-badehotel-2\/\" data-orig-file=\"https:\/\/i0.wp.com\/toppenafdanmark.dk\/wp-content\/uploads\/2025\/08\/1024x1024-aalbaek-badehotel-2.webp?fit=1024%2C1024&amp;ssl=1\" data-orig-size=\"1024,1024\" data-comments-opened=\"0\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"1024&amp;#215;1024 aalb\u00e6k badehotel 2\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/toppenafdanmark.dk\/wp-content\/uploads\/2025\/08\/1024x1024-aalbaek-badehotel-2.webp?fit=800%2C800&amp;ssl=1\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-35528ec e-con-full e-flex e-con e-child\" data-id=\"35528ec\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-37e5c38 elementor-widget elementor-widget-heading\" data-id=\"37e5c38\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\"><a href=\"https:\/\/toppenafdanmark.dk\/aalbaek-badehotel\/\">Aalb\u00e6k Badehotel<\/a><\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-208556c elementor-widget elementor-widget-button\" data-id=\"208556c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"button.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<div class=\"elementor-button-wrapper\">\n\t\t\t\t\t<a class=\"elementor-button elementor-button-link elementor-size-sm\" href=\"https:\/\/secure.guestcentric.net\/api\/bg\/book.php?&#038;apikey=aa77b857d8fefd3c056f5a2d45bbb20b&#038;url=https:\/\/aalbaek-badehotel.dk\/&#038;channelKey=&#038;_ga=2.157123451.1742726598.1618915090-385578528.1568709374\" target=\"_blank\" rel=\"noopener\">\n\t\t\t\t\t\t<span class=\"elementor-button-content-wrapper\">\n\t\t\t\t\t\t\t\t\t<span class=\"elementor-button-text\">Book Nu<\/span>\n\t\t\t\t\t<\/span>\n\t\t\t\t\t<\/a>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-85ae76a e-con-full e-flex e-con e-child\" data-id=\"85ae76a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-a2337c2 elementor-widget elementor-widget-image\" data-id=\"a2337c2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"https:\/\/toppenafdanmark.dk\/color-hotel-skagen\/\">\n\t\t\t\t\t\t\t<img decoding=\"async\" data-attachment-id=\"3294\" data-permalink=\"https:\/\/toppenafdanmark.dk\/de\/color-hotel-skagen\/1024x1024-color-hotel-skagen-skilt\/\" data-orig-file=\"https:\/\/i0.wp.com\/toppenafdanmark.dk\/wp-content\/uploads\/2025\/07\/1024x1024-Color-Hotel-Skagen-skilt.jpg?fit=1024%2C1024&amp;ssl=1\" data-orig-size=\"1024,1024\" data-comments-opened=\"0\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;1&quot;}\" data-image-title=\"1024&amp;#215;1024 Color Hotel Skagen skilt\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/toppenafdanmark.dk\/wp-content\/uploads\/2025\/07\/1024x1024-Color-Hotel-Skagen-skilt.jpg?fit=800%2C800&amp;ssl=1\" width=\"800\" height=\"800\" src=\"https:\/\/i0.wp.com\/toppenafdanmark.dk\/wp-content\/uploads\/2025\/07\/1024x1024-Color-Hotel-Skagen-skilt.jpg?fit=800%2C800&amp;ssl=1\" class=\"attachment-large size-large wp-image-3294\" alt=\"Velkommen til Color Hotel Skagen - Det 4-stjernede hotel med n\u00e6rhed, kvalitet og b\u00e6redygtighed i centrum\" srcset=\"https:\/\/i0.wp.com\/toppenafdanmark.dk\/wp-content\/uploads\/2025\/07\/1024x1024-Color-Hotel-Skagen-skilt.jpg?w=1024&amp;ssl=1 1024w, https:\/\/i0.wp.com\/toppenafdanmark.dk\/wp-content\/uploads\/2025\/07\/1024x1024-Color-Hotel-Skagen-skilt.jpg?resize=300%2C300&amp;ssl=1 300w, https:\/\/i0.wp.com\/toppenafdanmark.dk\/wp-content\/uploads\/2025\/07\/1024x1024-Color-Hotel-Skagen-skilt.jpg?resize=150%2C150&amp;ssl=1 150w, https:\/\/i0.wp.com\/toppenafdanmark.dk\/wp-content\/uploads\/2025\/07\/1024x1024-Color-Hotel-Skagen-skilt.jpg?resize=768%2C768&amp;ssl=1 768w, https:\/\/i0.wp.com\/toppenafdanmark.dk\/wp-content\/uploads\/2025\/07\/1024x1024-Color-Hotel-Skagen-skilt.jpg?resize=12%2C12&amp;ssl=1 12w\" sizes=\"(max-width: 800px) 100vw, 800px\" data-attachment-id=\"3294\" data-permalink=\"https:\/\/toppenafdanmark.dk\/color-hotel-skagen\/1024x1024-color-hotel-skagen-skilt\/\" data-orig-file=\"https:\/\/i0.wp.com\/toppenafdanmark.dk\/wp-content\/uploads\/2025\/07\/1024x1024-Color-Hotel-Skagen-skilt.jpg?fit=1024%2C1024&amp;ssl=1\" data-orig-size=\"1024,1024\" data-comments-opened=\"0\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;1&quot;}\" data-image-title=\"1024&amp;#215;1024 Color Hotel Skagen skilt\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/toppenafdanmark.dk\/wp-content\/uploads\/2025\/07\/1024x1024-Color-Hotel-Skagen-skilt.jpg?fit=800%2C800&amp;ssl=1\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-d98cd34 e-con-full e-flex e-con e-child\" data-id=\"d98cd34\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-d0dc2be elementor-widget elementor-widget-heading\" data-id=\"d0dc2be\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\"><a href=\"https:\/\/toppenafdanmark.dk\/color-hotel-skagen\/\">Color Hotel Skagen<\/a><\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4589bac elementor-widget elementor-widget-button\" data-id=\"4589bac\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"button.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<div class=\"elementor-button-wrapper\">\n\t\t\t\t\t<a class=\"elementor-button elementor-button-link elementor-size-sm\" href=\"https:\/\/app.mews.com\/distributor\/85190b7a-2914-4a2f-9e53-b10700e3da23?_gl=1*usb0br*_gcl_aw*R0NMLjE3NjM2MTEyNzMuQ2p3S0NBaUE4dlhJQmhBdEVpd0FmM0ItZzg3SDBjYjA4TDdtbXhWamltUkhvaXllb1BhSmFITEFCRC0wYU5Dak5PLW03UHZPWlVnT01ob0NHSThRQXZEX0J3RQ..*_gcl_au*MTc3ODc4NzE0OS4xNzYzNjExMjcx*_ga*MTE0ODc0MDYxOC4xNzYzNjExMjcz*_ga_1W6W89V5DH*czE3NjM2MTEyNzIkbzEkZzAkdDE3NjM2MTEyNzIkajYwJGwwJGgxNDMxMjQ3NTQy\" target=\"_blank\" rel=\"noopener\">\n\t\t\t\t\t\t<span class=\"elementor-button-content-wrapper\">\n\t\t\t\t\t\t\t\t\t<span class=\"elementor-button-text\">Book Nu<\/span>\n\t\t\t\t\t<\/span>\n\t\t\t\t\t<\/a>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Oplevelser i Nordjylland | Toppen af Danmark Book dit ophold Foldens Hotel Book Nu Aalb\u00e6k Badehotel Book Nu Color Hotel Skagen Book Nu<\/p>","protected":false},"author":266444214,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_crdt_document":"","footnotes":""},"folder":[],"class_list":["post-6492","page","type-page","status-publish","hentry"],"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/PgDlef-1GI","_links":{"self":[{"href":"https:\/\/toppenafdanmark.dk\/de\/wp-json\/wp\/v2\/pages\/6492","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/toppenafdanmark.dk\/de\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/toppenafdanmark.dk\/de\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/toppenafdanmark.dk\/de\/wp-json\/wp\/v2\/users\/266444214"}],"replies":[{"embeddable":true,"href":"https:\/\/toppenafdanmark.dk\/de\/wp-json\/wp\/v2\/comments?post=6492"}],"version-history":[{"count":100,"href":"https:\/\/toppenafdanmark.dk\/de\/wp-json\/wp\/v2\/pages\/6492\/revisions"}],"predecessor-version":[{"id":6969,"href":"https:\/\/toppenafdanmark.dk\/de\/wp-json\/wp\/v2\/pages\/6492\/revisions\/6969"}],"wp:attachment":[{"href":"https:\/\/toppenafdanmark.dk\/de\/wp-json\/wp\/v2\/media?parent=6492"}],"wp:term":[{"taxonomy":"folder","embeddable":true,"href":"https:\/\/toppenafdanmark.dk\/de\/wp-json\/wp\/v2\/folder?post=6492"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}