<div class="trip-overview-raw" style="display: none;"> <script> (function(){ try { var mapData = {"summary":{"title":"21-Day Portugal Family Trip","dates":"August 2026","travelers":"4 Travelers"},"weather":{"desc":"Warm and sunny","temp":"25-35°C"},"security":{"status":"Low Risk","tip":"Portugal is generally safe for families; stay aware of your surroundings."},"budget":{"total":"€1,695","items":[{"label":"Accommodations","val":"€945"},{"label":"Transport","val":"€200"},{"label":"Activities & Food","val":"€450"}]},"map":{"waypoints":[{"name":"Lisbon","lat":38.7223,"lon":-9.1393,"days":"Day 1-8","desc":"Explore the vibrant capital with family-friendly activities.","photo":"","highlights":["Tram 28 Ride","Pena Palace"]},{"name":"Lagos","lat":37.1022,"lon":-8.676,"days":"Day 8-14","desc":"Relax on stunning beaches and enjoy coastal adventures.","photo":"","highlights":["Ponta da Piedade","Slide & Splash Waterpark"]},{"name":"Porto","lat":41.1496,"lon":-8.6109,"days":"Day 15-21","desc":"Discover the rich culture and scenic views along the Douro.","photo":"","highlights":["Douro River Cruise","Livraria Lello"]}],"route":[0,1,2]},"days":[{"day_index":1,"day_title":"Arrival in Lisbon","image_query":"Lisbon Portugal","html_placeholder":"[DAY_IMAGE_01]"},{"day_index":2,"day_title":"Lisbon – Tram & Tile Adventure","image_query":"Lisbon Portugal","html_placeholder":"[DAY_IMAGE_02]"},{"day_index":3,"day_title":"Sintra Castles & Gardens","image_query":"Sintra Portugal","html_placeholder":"[DAY_IMAGE_03]"},{"day_index":4,"day_title":"Lisbon Oceanário & Park of Nations","image_query":"Lisbon Portugal","html_placeholder":"[DAY_IMAGE_04]"},{"day_index":5,"day_title":"Rest/Free Day – Lisbon Beaches","image_query":"Cascais Portugal","html_placeholder":"[DAY_IMAGE_05]"},{"day_index":6,"day_title":"Lisbon – Alfama & Fado","image_query":"Lisbon Portugal","html_placeholder":"[DAY_IMAGE_06]"},{"day_index":7,"day_title":"Lisbon – Free Day / Local Markets","image_query":"Lisbon Portugal","html_placeholder":"[DAY_IMAGE_07]"},{"day_index":8,"day_title":"Transfer to Algarve – Lagos","image_query":"Lagos Portugal","html_placeholder":"[DAY_IMAGE_08]"},{"day_index":9,"day_title":"Algarve – Ponta da Piedade & Beaches","image_query":"Lagos Portugal","html_placeholder":"[DAY_IMAGE_09]"},{"day_index":10,"day_title":"Algarve – Waterpark Adventure","image_query":"Lagos Portugal","html_placeholder":"[DAY_IMAGE_10]"},{"day_index":11,"day_title":"Algarve – Sagres & West Coast","image_query":"Sagres Portugal","html_placeholder":"[DAY_IMAGE_11]"},{"day_index":12,"day_title":"Algarve – Rest/Free Day","image_query":"Lagos Portugal","html_placeholder":"[DAY_IMAGE_12]"},{"day_index":13,"day_title":"Algarve – Silves Castle & Countryside","image_query":"Silves Portugal","html_placeholder":"[DAY_IMAGE_13]"},{"day_index":14,"day_title":"Algarve – Local Markets & Farewell","image_query":"Lagos Portugal","html_placeholder":"[DAY_IMAGE_14]"},{"day_index":15,"day_title":"Transfer to Porto","image_query":"Porto Portugal","html_placeholder":"[DAY_IMAGE_15]"},{"day_index":16,"day_title":"Porto – City & Bridges","image_query":"Porto Portugal","html_placeholder":"[DAY_IMAGE_16]"},{"day_index":17,"day_title":"Porto – Sea & Science","image_query":"Porto Portugal","html_placeholder":"[DAY_IMAGE_17]"},{"day_index":18,"day_title":"Porto – Douro Valley Day Trip","image_query":"Douro Valley Portugal","html_placeholder":"[DAY_IMAGE_18]"},{"day_index":19,"day_title":"Porto – Rest/Free Day","image_query":"Porto Portugal","html_placeholder":"[DAY_IMAGE_19]"},{"day_index":20,"day_title":"Porto – Markets & Parks","image_query":"Porto Portugal","html_placeholder":"[DAY_IMAGE_20]"},{"day_index":21,"day_title":"Departure from Porto","image_query":"Porto Portugal","html_placeholder":"[DAY_IMAGE_21]"}]}; var dayImages = {"day_index":1,"day_title":"Arrival in Lisbon","placeholder":"[DAY_IMAGE_01]","day_image_url":"https://images.unsplash.com/photo-1608208291890-dcaf52dc98e1?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxMaXNib24lMjBQb3J0dWdhbHxlbnwwfDB8fHwxNzY5Njg2OTA4fDA&ixlib=rb-4.1.0&q=80&w=1080","day_image_html":"<img src=\"https://images.unsplash.com/photo-1608208291890-dcaf52dc98e1?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxMaXNib24lMjBQb3J0dWdhbHxlbnwwfDB8fHwxNzY5Njg2OTA4fDA&ixlib=rb-4.1.0&q=80&w=1080\" width=\"640\" alt=\"Arrival in Lisbon\" style=\"display:block;margin:20px auto;border-radius:8px;\">"}, {"day_index":2,"day_title":"Lisbon – Tram & Tile Adventure","placeholder":"[DAY_IMAGE_02]","day_image_url":"https://images.unsplash.com/photo-1608208291890-dcaf52dc98e1?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxMaXNib24lMjBQb3J0dWdhbHxlbnwwfDB8fHwxNzY5Njg2OTA4fDA&ixlib=rb-4.1.0&q=80&w=1080","day_image_html":"<img src=\"https://images.unsplash.com/photo-1608208291890-dcaf52dc98e1?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxMaXNib24lMjBQb3J0dWdhbHxlbnwwfDB8fHwxNzY5Njg2OTA4fDA&ixlib=rb-4.1.0&q=80&w=1080\" width=\"640\" alt=\"Lisbon – Tram & Tile Adventure\" style=\"display:block;margin:20px auto;border-radius:8px;\">"}, {"day_index":3,"day_title":"Sintra Castles & Gardens","placeholder":"[DAY_IMAGE_03]","day_image_url":"https://images.unsplash.com/photo-1697050303652-0b228f3f83df?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxTaW50cmElMjBQb3J0dWdhbHxlbnwwfDB8fHwxNzY5Njg2OTA5fDA&ixlib=rb-4.1.0&q=80&w=1080","day_image_html":"<img src=\"https://images.unsplash.com/photo-1697050303652-0b228f3f83df?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxTaW50cmElMjBQb3J0dWdhbHxlbnwwfDB8fHwxNzY5Njg2OTA5fDA&ixlib=rb-4.1.0&q=80&w=1080\" width=\"640\" alt=\"Sintra Castles & Gardens\" style=\"display:block;margin:20px auto;border-radius:8px;\">"}, {"day_index":4,"day_title":"Lisbon Oceanário & Park of Nations","placeholder":"[DAY_IMAGE_04]","day_image_url":"https://images.unsplash.com/photo-1608208291890-dcaf52dc98e1?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxMaXNib24lMjBQb3J0dWdhbHxlbnwwfDB8fHwxNzY5Njg2OTA4fDA&ixlib=rb-4.1.0&q=80&w=1080","day_image_html":"<img src=\"https://images.unsplash.com/photo-1608208291890-dcaf52dc98e1?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxMaXNib24lMjBQb3J0dWdhbHxlbnwwfDB8fHwxNzY5Njg2OTA4fDA&ixlib=rb-4.1.0&q=80&w=1080\" width=\"640\" alt=\"Lisbon Oceanário & Park of Nations\" style=\"display:block;margin:20px auto;border-radius:8px;\">"}, {"day_index":5,"day_title":"Rest/Free Day – Lisbon Beaches","placeholder":"[DAY_IMAGE_05]","day_image_url":"https://images.unsplash.com/photo-1615672337780-6e19a28a5b39?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxDYXNjYWlzJTIwUG9ydHVnYWx8ZW58MHwwfHx8MTc2OTY4NjkwOXww&ixlib=rb-4.1.0&q=80&w=1080","day_image_html":"<img src=\"https://images.unsplash.com/photo-1615672337780-6e19a28a5b39?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxDYXNjYWlzJTIwUG9ydHVnYWx8ZW58MHwwfHx8MTc2OTY4NjkwOXww&ixlib=rb-4.1.0&q=80&w=1080\" width=\"640\" alt=\"Rest/Free Day – Lisbon Beaches\" style=\"display:block;margin:20px auto;border-radius:8px;\">"}, {"day_index":6,"day_title":"Lisbon – Alfama & Fado","placeholder":"[DAY_IMAGE_06]","day_image_url":"https://images.unsplash.com/photo-1608208291890-dcaf52dc98e1?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxMaXNib24lMjBQb3J0dWdhbHxlbnwwfDB8fHwxNzY5Njg2OTA4fDA&ixlib=rb-4.1.0&q=80&w=1080","day_image_html":"<img src=\"https://images.unsplash.com/photo-1608208291890-dcaf52dc98e1?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxMaXNib24lMjBQb3J0dWdhbHxlbnwwfDB8fHwxNzY5Njg2OTA4fDA&ixlib=rb-4.1.0&q=80&w=1080\" width=\"640\" alt=\"Lisbon – Alfama & Fado\" style=\"display:block;margin:20px auto;border-radius:8px;\">"}, {"day_index":7,"day_title":"Lisbon – Free Day / Local Markets","placeholder":"[DAY_IMAGE_07]","day_image_url":"https://images.unsplash.com/photo-1608208291890-dcaf52dc98e1?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxMaXNib24lMjBQb3J0dWdhbHxlbnwwfDB8fHwxNzY5Njg2OTA4fDA&ixlib=rb-4.1.0&q=80&w=1080","day_image_html":"<img src=\"https://images.unsplash.com/photo-1608208291890-dcaf52dc98e1?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxMaXNib24lMjBQb3J0dWdhbHxlbnwwfDB8fHwxNzY5Njg2OTA4fDA&ixlib=rb-4.1.0&q=80&w=1080\" width=\"640\" alt=\"Lisbon – Free Day / Local Markets\" style=\"display:block;margin:20px auto;border-radius:8px;\">"}, {"day_index":8,"day_title":"Transfer to Algarve – Lagos","placeholder":"[DAY_IMAGE_08]","day_image_url":"https://images.unsplash.com/photo-1627826676942-576ea238e0cc?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxMYWdvcyUyMFBvcnR1Z2FsfGVufDB8MHx8fDE3Njk2ODY5MTB8MA&ixlib=rb-4.1.0&q=80&w=1080","day_image_html":"<img src=\"https://images.unsplash.com/photo-1627826676942-576ea238e0cc?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxMYWdvcyUyMFBvcnR1Z2FsfGVufDB8MHx8fDE3Njk2ODY5MTB8MA&ixlib=rb-4.1.0&q=80&w=1080\" width=\"640\" alt=\"Transfer to Algarve – Lagos\" style=\"display:block;margin:20px auto;border-radius:8px;\">"}, {"day_index":9,"day_title":"Algarve – Ponta da Piedade & Beaches","placeholder":"[DAY_IMAGE_09]","day_image_url":"https://images.unsplash.com/photo-1627826676942-576ea238e0cc?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxMYWdvcyUyMFBvcnR1Z2FsfGVufDB8MHx8fDE3Njk2ODY5MTB8MA&ixlib=rb-4.1.0&q=80&w=1080","day_image_html":"<img src=\"https://images.unsplash.com/photo-1627826676942-576ea238e0cc?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxMYWdvcyUyMFBvcnR1Z2FsfGVufDB8MHx8fDE3Njk2ODY5MTB8MA&ixlib=rb-4.1.0&q=80&w=1080\" width=\"640\" alt=\"Algarve – Ponta da Piedade & Beaches\" style=\"display:block;margin:20px auto;border-radius:8px;\">"}, {"day_index":10,"day_title":"Algarve – Waterpark Adventure","placeholder":"[DAY_IMAGE_10]","day_image_url":"https://images.unsplash.com/photo-1627826676942-576ea238e0cc?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxMYWdvcyUyMFBvcnR1Z2FsfGVufDB8MHx8fDE3Njk2ODY5MTB8MA&ixlib=rb-4.1.0&q=80&w=1080","day_image_html":"<img src=\"https://images.unsplash.com/photo-1627826676942-576ea238e0cc?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxMYWdvcyUyMFBvcnR1Z2FsfGVufDB8MHx8fDE3Njk2ODY5MTB8MA&ixlib=rb-4.1.0&q=80&w=1080\" width=\"640\" alt=\"Algarve – Waterpark Adventure\" style=\"display:block;margin:20px auto;border-radius:8px;\">"}, {"day_index":11,"day_title":"Algarve – Sagres & West Coast","placeholder":"[DAY_IMAGE_11]","day_image_url":"https://images.unsplash.com/photo-1695199858472-c81a7444789d?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxTYWdyZXMlMjBQb3J0dWdhbHxlbnwwfDB8fHwxNzY5Njg2OTEwfDA&ixlib=rb-4.1.0&q=80&w=1080","day_image_html":"<img src=\"https://images.unsplash.com/photo-1695199858472-c81a7444789d?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxTYWdyZXMlMjBQb3J0dWdhbHxlbnwwfDB8fHwxNzY5Njg2OTEwfDA&ixlib=rb-4.1.0&q=80&w=1080\" width=\"640\" alt=\"Algarve – Sagres & West Coast\" style=\"display:block;margin:20px auto;border-radius:8px;\">"}, {"day_index":12,"day_title":"Algarve – Rest/Free Day","placeholder":"[DAY_IMAGE_12]","day_image_url":"https://images.unsplash.com/photo-1627826676942-576ea238e0cc?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxMYWdvcyUyMFBvcnR1Z2FsfGVufDB8MHx8fDE3Njk2ODY5MTB8MA&ixlib=rb-4.1.0&q=80&w=1080","day_image_html":"<img src=\"https://images.unsplash.com/photo-1627826676942-576ea238e0cc?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxMYWdvcyUyMFBvcnR1Z2FsfGVufDB8MHx8fDE3Njk2ODY5MTB8MA&ixlib=rb-4.1.0&q=80&w=1080\" width=\"640\" alt=\"Algarve – Rest/Free Day\" style=\"display:block;margin:20px auto;border-radius:8px;\">"}, {"day_index":13,"day_title":"Algarve – Silves Castle & Countryside","placeholder":"[DAY_IMAGE_13]","day_image_url":"https://images.unsplash.com/photo-1658696698923-ac63f551bb2d?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxTaWx2ZXMlMjBQb3J0dWdhbHxlbnwwfDB8fHwxNzY5Njg2OTExfDA&ixlib=rb-4.1.0&q=80&w=1080","day_image_html":"<img src=\"https://images.unsplash.com/photo-1658696698923-ac63f551bb2d?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxTaWx2ZXMlMjBQb3J0dWdhbHxlbnwwfDB8fHwxNzY5Njg2OTExfDA&ixlib=rb-4.1.0&q=80&w=1080\" width=\"640\" alt=\"Algarve – Silves Castle & Countryside\" style=\"display:block;margin:20px auto;border-radius:8px;\">"}, {"day_index":14,"day_title":"Algarve – Local Markets & Farewell","placeholder":"[DAY_IMAGE_14]","day_image_url":"https://images.unsplash.com/photo-1627826676942-576ea238e0cc?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxMYWdvcyUyMFBvcnR1Z2FsfGVufDB8MHx8fDE3Njk2ODY5MTB8MA&ixlib=rb-4.1.0&q=80&w=1080","day_image_html":"<img src=\"https://images.unsplash.com/photo-1627826676942-576ea238e0cc?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxMYWdvcyUyMFBvcnR1Z2FsfGVufDB8MHx8fDE3Njk2ODY5MTB8MA&ixlib=rb-4.1.0&q=80&w=1080\" width=\"640\" alt=\"Algarve – Local Markets & Farewell\" style=\"display:block;margin:20px auto;border-radius:8px;\">"}, {"day_index":15,"day_title":"Transfer to Porto","placeholder":"[DAY_IMAGE_15]","day_image_url":"https://images.unsplash.com/photo-1555881400-69a2384edcd4?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxQb3J0byUyMFBvcnR1Z2FsfGVufDB8MHx8fDE3Njk2ODY5MTF8MA&ixlib=rb-4.1.0&q=80&w=1080","day_image_html":"<img src=\"https://images.unsplash.com/photo-1555881400-69a2384edcd4?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxQb3J0byUyMFBvcnR1Z2FsfGVufDB8MHx8fDE3Njk2ODY5MTF8MA&ixlib=rb-4.1.0&q=80&w=1080\" width=\"640\" alt=\"Transfer to Porto\" style=\"display:block;margin:20px auto;border-radius:8px;\">"}, {"day_index":16,"day_title":"Porto – City & Bridges","placeholder":"[DAY_IMAGE_16]","day_image_url":"https://images.unsplash.com/photo-1555881400-69a2384edcd4?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxQb3J0byUyMFBvcnR1Z2FsfGVufDB8MHx8fDE3Njk2ODY5MTF8MA&ixlib=rb-4.1.0&q=80&w=1080","day_image_html":"<img src=\"https://images.unsplash.com/photo-1555881400-69a2384edcd4?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxQb3J0byUyMFBvcnR1Z2FsfGVufDB8MHx8fDE3Njk2ODY5MTF8MA&ixlib=rb-4.1.0&q=80&w=1080\" width=\"640\" alt=\"Porto – City & Bridges\" style=\"display:block;margin:20px auto;border-radius:8px;\">"}, {"day_index":17,"day_title":"Porto – Sea & Science","placeholder":"[DAY_IMAGE_17]","day_image_url":"https://images.unsplash.com/photo-1555881400-69a2384edcd4?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxQb3J0byUyMFBvcnR1Z2FsfGVufDB8MHx8fDE3Njk2ODY5MTF8MA&ixlib=rb-4.1.0&q=80&w=1080","day_image_html":"<img src=\"https://images.unsplash.com/photo-1555881400-69a2384edcd4?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxQb3J0byUyMFBvcnR1Z2FsfGVufDB8MHx8fDE3Njk2ODY5MTF8MA&ixlib=rb-4.1.0&q=80&w=1080\" width=\"640\" alt=\"Porto – Sea & Science\" style=\"display:block;margin:20px auto;border-radius:8px;\">"}, {"day_index":18,"day_title":"Porto – Douro Valley Day Trip","placeholder":"[DAY_IMAGE_18]","day_image_url":"https://images.unsplash.com/photo-1638664370752-8188076afbab?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxEb3VybyUyMFZhbGxleSUyMFBvcnR1Z2FsfGVufDB8MHx8fDE3Njk2ODY5MTJ8MA&ixlib=rb-4.1.0&q=80&w=1080","day_image_html":"<img src=\"https://images.unsplash.com/photo-1638664370752-8188076afbab?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxEb3VybyUyMFZhbGxleSUyMFBvcnR1Z2FsfGVufDB8MHx8fDE3Njk2ODY5MTJ8MA&ixlib=rb-4.1.0&q=80&w=1080\" width=\"640\" alt=\"Porto – Douro Valley Day Trip\" style=\"display:block;margin:20px auto;border-radius:8px;\">"}, {"day_index":19,"day_title":"Porto – Rest/Free Day","placeholder":"[DAY_IMAGE_19]","day_image_url":"https://images.unsplash.com/photo-1555881400-69a2384edcd4?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxQb3J0byUyMFBvcnR1Z2FsfGVufDB8MHx8fDE3Njk2ODY5MTF8MA&ixlib=rb-4.1.0&q=80&w=1080","day_image_html":"<img src=\"https://images.unsplash.com/photo-1555881400-69a2384edcd4?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxQb3J0byUyMFBvcnR1Z2FsfGVufDB8MHx8fDE3Njk2ODY5MTF8MA&ixlib=rb-4.1.0&q=80&w=1080\" width=\"640\" alt=\"Porto – Rest/Free Day\" style=\"display:block;margin:20px auto;border-radius:8px;\">"}, {"day_index":20,"day_title":"Porto – Markets & Parks","placeholder":"[DAY_IMAGE_20]","day_image_url":"https://images.unsplash.com/photo-1555881400-69a2384edcd4?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxQb3J0byUyMFBvcnR1Z2FsfGVufDB8MHx8fDE3Njk2ODY5MTF8MA&ixlib=rb-4.1.0&q=80&w=1080","day_image_html":"<img src=\"https://images.unsplash.com/photo-1555881400-69a2384edcd4?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxQb3J0byUyMFBvcnR1Z2FsfGVufDB8MHx8fDE3Njk2ODY5MTF8MA&ixlib=rb-4.1.0&q=80&w=1080\" width=\"640\" alt=\"Porto – Markets & Parks\" style=\"display:block;margin:20px auto;border-radius:8px;\">"}, {"day_index":21,"day_title":"Departure from Porto","placeholder":"[DAY_IMAGE_21]","day_image_url":"https://images.unsplash.com/photo-1555881400-69a2384edcd4?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxQb3J0byUyMFBvcnR1Z2FsfGVufDB8MHx8fDE3Njk2ODY5MTF8MA&ixlib=rb-4.1.0&q=80&w=1080","day_image_html":"<img src=\"https://images.unsplash.com/photo-1555881400-69a2384edcd4?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4NjAxNDN8MHwxfHNlYXJjaHwxfHxQb3J0byUyMFBvcnR1Z2FsfGVufDB8MHx8fDE3Njk2ODY5MTF8MA&ixlib=rb-4.1.0&q=80&w=1080\" width=\"640\" alt=\"Departure from Porto\" style=\"display:block;margin:20px auto;border-radius:8px;\">"} || []; var travelerName = "Hakim"; var destination = "Portugal"; function extractDays(dayRange) { if (!dayRange) return []; var match = dayRange.toString().match(/Day\s+(\d+)(?:-(\d+))?/); if (!match) return []; var start = parseInt(match[1]); var end = match[2] ? parseInt(match[2]) : start; var days = []; for (var i = start; i <= end; i++) { days.push(i); } return days; } function findImageForWaypoint(waypoint, dayImages) { var days = extractDays(waypoint.days); if (days.length === 0) return null; var firstDay = days[0]; for (var i = 0; i < dayImages.length; i++) { if (dayImages[i].day_index === firstDay) { return dayImages[i].day_image_url; } } return null; } if (mapData && mapData.map && mapData.map.waypoints) { for (var i = 0; i < mapData.map.waypoints.length; i++) { var wp = mapData.map.waypoints[i]; var imageUrl = findImageForWaypoint(wp, dayImages); if (imageUrl) { wp.photo = imageUrl; } } } window.TD_MAP_DATA_ENRICHED = mapData; window.travelerName = travelerName; window.destination = destination; } catch(e) { console.error('Error enriching map data:', e); window.TD_MAP_DATA_ENRICHED = {"summary":{"title":"21-Day Portugal Family Trip","dates":"August 2026","travelers":"4 Travelers"},"weather":{"desc":"Warm and sunny","temp":"25-35°C"},"security":{"status":"Low Risk","tip":"Portugal is generally safe for families; stay aware of your surroundings."},"budget":{"total":"€1,695","items":[{"label":"Accommodations","val":"€945"},{"label":"Transport","val":"€200"},{"label":"Activities & Food","val":"€450"}]},"map":{"waypoints":[{"name":"Lisbon","lat":38.7223,"lon":-9.1393,"days":"Day 1-8","desc":"Explore the vibrant capital with family-friendly activities.","photo":"","highlights":["Tram 28 Ride","Pena Palace"]},{"name":"Lagos","lat":37.1022,"lon":-8.676,"days":"Day 8-14","desc":"Relax on stunning beaches and enjoy coastal adventures.","photo":"","highlights":["Ponta da Piedade","Slide & Splash Waterpark"]},{"name":"Porto","lat":41.1496,"lon":-8.6109,"days":"Day 15-21","desc":"Discover the rich culture and scenic views along the Douro.","photo":"","highlights":["Douro River Cruise","Livraria Lello"]}],"route":[0,1,2]},"days":[{"day_index":1,"day_title":"Arrival in Lisbon","image_query":"Lisbon Portugal","html_placeholder":"[DAY_IMAGE_01]"},{"day_index":2,"day_title":"Lisbon – Tram & Tile Adventure","image_query":"Lisbon Portugal","html_placeholder":"[DAY_IMAGE_02]"},{"day_index":3,"day_title":"Sintra Castles & Gardens","image_query":"Sintra Portugal","html_placeholder":"[DAY_IMAGE_03]"},{"day_index":4,"day_title":"Lisbon Oceanário & Park of Nations","image_query":"Lisbon Portugal","html_placeholder":"[DAY_IMAGE_04]"},{"day_index":5,"day_title":"Rest/Free Day – Lisbon Beaches","image_query":"Cascais Portugal","html_placeholder":"[DAY_IMAGE_05]"},{"day_index":6,"day_title":"Lisbon – Alfama & Fado","image_query":"Lisbon Portugal","html_placeholder":"[DAY_IMAGE_06]"},{"day_index":7,"day_title":"Lisbon – Free Day / Local Markets","image_query":"Lisbon Portugal","html_placeholder":"[DAY_IMAGE_07]"},{"day_index":8,"day_title":"Transfer to Algarve – Lagos","image_query":"Lagos Portugal","html_placeholder":"[DAY_IMAGE_08]"},{"day_index":9,"day_title":"Algarve – Ponta da Piedade & Beaches","image_query":"Lagos Portugal","html_placeholder":"[DAY_IMAGE_09]"},{"day_index":10,"day_title":"Algarve – Waterpark Adventure","image_query":"Lagos Portugal","html_placeholder":"[DAY_IMAGE_10]"},{"day_index":11,"day_title":"Algarve – Sagres & West Coast","image_query":"Sagres Portugal","html_placeholder":"[DAY_IMAGE_11]"},{"day_index":12,"day_title":"Algarve – Rest/Free Day","image_query":"Lagos Portugal","html_placeholder":"[DAY_IMAGE_12]"},{"day_index":13,"day_title":"Algarve – Silves Castle & Countryside","image_query":"Silves Portugal","html_placeholder":"[DAY_IMAGE_13]"},{"day_index":14,"day_title":"Algarve – Local Markets & Farewell","image_query":"Lagos Portugal","html_placeholder":"[DAY_IMAGE_14]"},{"day_index":15,"day_title":"Transfer to Porto","image_query":"Porto Portugal","html_placeholder":"[DAY_IMAGE_15]"},{"day_index":16,"day_title":"Porto – City & Bridges","image_query":"Porto Portugal","html_placeholder":"[DAY_IMAGE_16]"},{"day_index":17,"day_title":"Porto – Sea & Science","image_query":"Porto Portugal","html_placeholder":"[DAY_IMAGE_17]"},{"day_index":18,"day_title":"Porto – Douro Valley Day Trip","image_query":"Douro Valley Portugal","html_placeholder":"[DAY_IMAGE_18]"},{"day_index":19,"day_title":"Porto – Rest/Free Day","image_query":"Porto Portugal","html_placeholder":"[DAY_IMAGE_19]"},{"day_index":20,"day_title":"Porto – Markets & Parks","image_query":"Porto Portugal","html_placeholder":"[DAY_IMAGE_20]"},{"day_index":21,"day_title":"Departure from Porto","image_query":"Porto Portugal","html_placeholder":"[DAY_IMAGE_21]"}]} || {}; window.travelerName = "Hakim"; window.destination = "Portugal"; } })(); </script> </div> <script> (function () { 'use strict'; console.log('[TD Map V8] Initializing...'); function loadLeaflet(callback) { if (typeof L !== 'undefined') { callback(); return; } console.log('[TD Map V8] Loading Leaflet libraries...'); var link = document.createElement('link'); link.rel = 'stylesheet'; link.href = 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.css'; document.head.appendChild(link); var script = document.createElement('script'); script.src = 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.js'; script.onload = function () { console.log('[TD Map V8] Leaflet loaded!'); callback(); }; script.onerror = function () { console.error('[TD Map V8] Failed to load Leaflet.'); var container = document.getElementById('td-map-v8-container'); if (container) container.innerHTML = 'Map Error: Could not load libraries.'; }; document.head.appendChild(script); } function decodeHTML(str) { var txt = document.createElement('textarea'); var decoded = str; var max = 5, i = 0; while ((decoded.includes('<') || decoded.includes('&')) && i < max) { txt.innerHTML = decoded; decoded = txt.value; i++; } return decoded; } function extractMapData(content) { var startMarkers = ['var mapData=', 'var mapData =', 'mapData=']; for (var m = 0; m < startMarkers.length; m++) { var startIdx = content.indexOf(startMarkers[m]); if (startIdx !== -1) { var braceStart = content.indexOf('{', startIdx); if (braceStart === -1) continue; var depth = 0, braceEnd = -1; for (var i = braceStart; i < content.length; i++) { if (content[i] === '{') depth++; if (content[i] === '}') depth--; if (depth === 0) { braceEnd = i; break; } } if (braceEnd !== -1) { var jsonStr = content.substring(braceStart, braceEnd + 1); try { return JSON.parse(jsonStr); } catch (e) { jsonStr = jsonStr.replace(/&/g, '&').replace(/\\"/g, '"'); try { return JSON.parse(jsonStr); } catch (e2) { } } } } } return null; } function extractVariable(content, varName) { var match = content.match(new RegExp('var\\s+' + varName + '\\s*=\\s*["\']([^"\']+)["\']')); return match ? match[1] : null; } function initMap() { var mapData = window.TD_MAP_DATA_ENRICHED; var travelerName = window.travelerName || 'Traveler'; var destination = window.destination || 'Destination'; if (!mapData) { var rawEl = document.querySelector('.trip-overview-raw') || document.querySelector('#trip-overview-raw'); if (!rawEl) { console.warn('[TD Map V8] No data element found.'); return; } var content = decodeHTML(rawEl.innerHTML || rawEl.textContent); rawEl.style.display = 'none'; mapData = extractMapData(content); if (!mapData) { console.error('[TD Map V8] JSON extraction failed.'); return; } travelerName = extractVariable(content, 'travelerName') || travelerName; destination = extractVariable(content, 'destination') || destination; } var container = document.getElementById('td-map-v8-container'); if (!container) { container = document.createElement('div'); container.id = 'td-map-v8-container'; container.style.width = '100%'; container.style.display = 'flex'; container.style.flexDirection = 'column'; var rawEl = document.querySelector('.trip-overview-raw'); if (rawEl && rawEl.parentNode) { rawEl.parentNode.insertBefore(container, rawEl.nextSibling); } else { document.body.appendChild(container); } } container.innerHTML = ''; buildMapUI(container, mapData, travelerName, destination); } function buildMapUI(container, mapData, travelerName, destination) { var waypoints = mapData.map.waypoints || []; if (waypoints.length === 0) return; // Préparer les données pour la STATS BAR var weatherTemp = mapData.weather ? mapData.weather.temp : ''; var weatherDesc = mapData.weather ? mapData.weather.desc : ''; var securityStatus = mapData.security ? mapData.security.status : ''; var securityTip = mapData.security ? mapData.security.tip : ''; var budgetTotal = mapData.budget ? mapData.budget.total : ''; container.innerHTML = '<div id="td-map-v8" style="font-family: \'Inter\', sans-serif; width: 100%; background: #fff; border-radius: 0.75rem; overflow: hidden; box-shadow: 0 4px 20px rgba(0,0,0,0.08);"><div style="background: #001427; padding: 1.1rem 1.5rem;"><div style="display: flex; justify-content: space-between; align-items: center;"><div><h2 style="margin: 0; font-family: \'Poppins\', sans-serif; font-size: 1.1rem; font-weight: 600; color: white;">' + travelerName + '\'s Journey</h2><p style="margin: 0.25rem 0 0; font-size: 0.8rem; color: rgba(255,255,255,0.7);">' + (mapData.summary ? mapData.summary.dates : '') + ' • ' + (mapData.summary ? mapData.summary.travelers : '') + '</p></div><div style="text-align: right;"><span style="display: block; font-size: 0.7rem; text-transform: uppercase; color: rgba(255,255,255,0.5); letter-spacing: 1px; font-weight: 600;">Est. Budget</span><span style="font-size: 1rem; font-weight: 700; color: #E98A15;">' + budgetTotal + '</span></div></div></div><div style="display: grid; grid-template-columns: 1fr 1fr; background: #f8f9fa; border-left: 1px solid #eef0f2; border-right: 1px solid #eef0f2; padding: 0.9rem 1.5rem;"><div style="border-right: 1px solid #eef0f2; padding-right: 0.9rem;"><span style="display: block; font-size: 0.65rem; text-transform: uppercase; color: #8898aa; font-weight: 700; letter-spacing: 0.5px; margin-bottom: 0.25rem;">Weather</span><div style="display: flex; align-items: center; gap: 0.5rem;"><span style="font-size: 1.1rem;">☀️</span><div><span style="display: block; font-size: 0.8rem; font-weight: 600; color: #001427;">' + weatherTemp + '</span><span style="display: block; font-size: 0.7rem; color: #525f7f;">' + weatherDesc + '</span></div></div></div><div style="padding-left: 0.9rem;"><span style="display: block; font-size: 0.65rem; text-transform: uppercase; color: #8898aa; font-weight: 700; letter-spacing: 0.5px; margin-bottom: 0.25rem;">Safety</span><div style="display: flex; align-items: center; gap: 0.5rem;"><span style="font-size: 1.1rem;">🛡️</span><div><span style="display: block; font-size: 0.8rem; font-weight: 600; color: #001427;">' + securityStatus + '</span><span style="display: block; font-size: 0.7rem; color: #525f7f; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 120px;">' + securityTip + '</span></div></div></div></div><div id="leaflet-map-v8" style="width: 100%; height: 25rem; background: #e7e0da; z-index: 1;"></div><div id="timeline-v8" style="background: #f8f9fa; padding: 1rem 1.25rem; border-top: 3px solid #e98a15; overflow-x: auto; white-space: nowrap; -webkit-overflow-scrolling: touch;"><div style="display: inline-flex; gap: 0.5rem; padding-bottom: 5px;"></div></div><div style="display: flex; justify-content: center; gap: 1.5rem; padding: 0.8rem; font-size: 0.75rem; color: #001427; font-weight: 500; border-top: 1px solid #eee;"><span style="display: flex; align-items: center; gap: 0.4rem;"><span style="width: 0.6rem; height: 0.6rem; background: #e98a15; border-radius: 50%;"></span> ' + destination + '</span><span style="display: flex; align-items: center; gap: 0.4rem;"><span>📷</span> Click markers for photos</span></div></div><style>.leaflet-popup-content-wrapper { border-radius: 0.75rem !important; padding: 0 !important; overflow: hidden; box-shadow: 0 10px 25px rgba(0,0,0,0.15) !important; }.leaflet-popup-content { margin: 0 !important; width: 280px !important; }.leaflet-container { font-family: \'Inter\', sans-serif !important; }.timeline-item-v8 { display: inline-flex; flex-direction: column; align-items: center; cursor: pointer; padding: 0.5rem 0.75rem; border-radius: 0.5rem; min-width: 4.5rem; transition: all 0.2s ease; border: 1px solid transparent; }.timeline-item-v8:hover { background: #fff; border-color: #ddd; transform: translateY(-2px); }.timeline-item-v8.active { background: #e98a15; color: white !important; box-shadow: 0 4px 12px rgba(233, 138, 21, 0.4); }.timeline-item-v8.active span { color: white !important; }#timeline-v8::-webkit-scrollbar { height: 6px; }#timeline-v8::-webkit-scrollbar-track { background: transparent; }#timeline-v8::-webkit-scrollbar-thumb { background: #ddd; border-radius: 10px; }#timeline-v8::-webkit-scrollbar-thumb:hover { background: #ccc; }</style>'; var map = L.map('leaflet-map-v8', { scrollWheelZoom: true, zoomControl: true }).setView([0, 0], 2); L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png', { maxZoom: 19, attribution: '© <a href="https://carto.com/">CARTO</a>' }).addTo(map); var markers = []; waypoints.forEach(function(wp, i) { var dayLabelRaw = wp.days ? wp.days.toString() : ""; var dayLabelClean = dayLabelRaw.split('-')[0]; var iconHtml = '<div style="background: linear-gradient(135deg, #e98a15, #d47710); color: white; width: 2.2rem; height: 2.2rem; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: 700; border: 3px solid white; box-shadow: 0 4px 15px rgba(233,138,21,0.5); font-size: 0.9rem;">' + (i + 1) + '</div>'; var icon = L.divIcon({ html: iconHtml, className: 'td-marker-v8', iconSize: [36, 36], iconAnchor: [18, 18], popupAnchor: [0, -24] }); var popupContent = '<div style="font-family: \'Inter\', sans-serif;"><div style="width: 100%; height: 9rem; background: #eee; overflow: hidden; position: relative;"><img src="' + (wp.photo || '') + '" style="width: 100%; height: 100%; object-fit: cover; display: block;" onerror="this.parentElement.style.display=\'none\'"></div><div style="padding: 1rem;"><span style="background: rgba(233,138,21,0.1); color: #d47710; padding: 0.25rem 0.6rem; border-radius: 2rem; font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px;">' + wp.days + '</span><h4 style="margin: 0.5rem 0 0.25rem; font-size: 1rem; color: #001427; font-weight: 700; line-height: 1.3;">' + wp.name + '</h4><p style="font-size: 0.8rem; color: #666; margin: 0; line-height: 1.4;">' + (wp.desc || '') + '</p></div></div>'; var marker = L.marker([wp.lat, wp.lon], { icon: icon }).bindPopup(popupContent).addTo(map); markers.push(marker); var tlItem = document.createElement('div'); tlItem.className = 'timeline-item-v8'; var timelineDayText = dayLabelClean; if (/^\d+$/.test(timelineDayText.trim())) { timelineDayText = "Day " + timelineDayText; } tlItem.innerHTML = '<span style="font-size: 0.65rem; color: #999; font-weight: 600; text-transform: uppercase;">' + timelineDayText + '</span><span style="font-size: 0.8rem; font-weight: 700; color: #001427;">' + wp.name + '</span>'; tlItem.onclick = function() { map.setView([wp.lat, wp.lon], 11, { animate: true }); marker.openPopup(); var allItems = document.querySelectorAll('.timeline-item-v8'); for (var j = 0; j < allItems.length; j++) { allItems[j].classList.remove('active'); } tlItem.classList.add('active'); tlItem.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' }); }; marker.on('click', function() { var allItems = document.querySelectorAll('.timeline-item-v8'); for (var j = 0; j < allItems.length; j++) { allItems[j].classList.remove('active'); } tlItem.classList.add('active'); tlItem.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' }); }); document.querySelector('#timeline-v8 > div').appendChild(tlItem); }); var route = waypoints.map(function(wp) { return [wp.lat, wp.lon]; }); L.polyline(route, { color: '#e98a15', weight: 4, dashArray: '10, 10', opacity: 0.8, lineCap: 'round' }).addTo(map); if (markers.length > 0) { map.fitBounds(L.latLngBounds(waypoints.map(function(wp) { return [wp.lat, wp.lon]; })).pad(0.1)); } } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', function() { loadLeaflet(initMap); }); } else { loadLeaflet(initMap); } })(); </script>