{"id":283,"date":"2026-09-20T19:14:45","date_gmt":"2026-09-21T05:14:45","guid":{"rendered":"https:\/\/mana-corp.com\/?page_id=283"},"modified":"2026-09-20T21:21:18","modified_gmt":"2026-09-21T07:21:18","slug":"elementor-283","status":"publish","type":"page","link":"https:\/\/mana-corp.com\/?page_id=283","title":{"rendered":"Elementor #283"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"283\" class=\"elementor elementor-283\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1b7da24 e-flex e-con-boxed e-con e-parent\" data-id=\"1b7da24\" 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-48ddc4f elementor-widget elementor-widget-html\" data-id=\"48ddc4f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<!DOCTYPE html>\n<html lang=\"fr\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, viewport-fit=cover\">\n<meta name=\"theme-color\" content=\"#FF6B00\">\n<title>Tahiti BOOK - Map Main UI - Fullscreen API<\/title>\n<link href=\"https:\/\/unpkg.com\/maplibre-gl@4.7.1\/dist\/maplibre-gl.css\" rel=\"stylesheet\">\n<script src=\"https:\/\/unpkg.com\/maplibre-gl@4.7.1\/dist\/maplibre-gl.js\"><\/script>\n<style>\n:root{--orange:#FF6B00;--black:#0A0A0A;--bg:#080808;--card:#161616;--card2:#1E1E1E;--border:#232323;--text:#F5F5F5;--muted:#7A7A7A}\n*{box-sizing:border-box;margin:0;padding:0;font-family:Inter,system-ui,-apple-system,sans-serif;-webkit-tap-highlight-color:transparent}\nhtml,body{height:100%;width:100%;background:var(--bg);color:var(--text);overflow:hidden}\n#app{height:100dvh;width:100%;display:flex;flex-direction:column;background:var(--bg);position:relative}\n.header{position:absolute;top:0;left:0;right:0;z-index:50;height:56px;display:flex;align-items:center;justify-content:space-between;padding:0 16px;padding-top:env(safe-area-inset-top);background:linear-gradient(to bottom, rgba(0,0,0,.85) 0%, rgba(0,0,0,0) 100%);pointer-events:none}.header *{pointer-events:auto}\n.logo{display:flex;align-items:center;gap:10px;font-weight:900;font-size:17px;letter-spacing:-.6px}.logo span{color:var(--orange)}\n.badge{background:rgba(22,22,22,.9);border:1px solid var(--border);color:var(--text);font-weight:700;font-size:10px;padding:6px 10px;border-radius:100px;backdrop-filter:blur(12px)}\n.header-actions{display:flex;gap:8px}\n.hbtn{width:40px;height:40px;background:rgba(22,22,22,.9);backdrop-filter:blur(12px);border:1px solid var(--border);border-radius:12px;display:grid;place-items:center;font-size:18px;cursor:pointer;color:#fff;transition:.2s}.hbtn:active{transform:scale(.92)}.hbtn.orange{background:var(--orange);color:#000;border-color:var(--orange)}\n.map-main{position:absolute;inset:0;width:100%;height:100%;z-index:1}\n#map{position:absolute;inset:0;width:100%;height:100%}\n.map-hint{position:absolute;top:72px;left:50%;transform:translateX(-50%);z-index:10;background:rgba(22,22,22,.9);backdrop-filter:blur(16px);border:1px solid var(--border);border-radius:100px;padding:8px 14px;font-size:11px;font-weight:600;color:var(--muted);display:flex;align-items:center;gap:6px;pointer-events:none;transition:.3s}.map-hint b{color:var(--text)}.map-hint.hide{opacity:0;transform:translateX(-50%) translateY(-10px)}\n.bottom-sheet{position:absolute;left:0;right:0;bottom:0;z-index:20;background:var(--black);border-top:1.5px solid var(--orange);border-radius:28px 28px 0 0;max-height:58dvh;min-height:38dvh;display:flex;flex-direction:column;box-shadow:0 -20px 60px rgba(0,0,0,.8);transition:transform.35s cubic-bezier(.32,.72,0,1)}.bottom-sheet.minimized{transform:translateY(calc(100% - 72px))}.bottom-sheet.full{max-height:92dvh}\n.drag{width:36px;height:4px;background:#333;border-radius:2px;margin:12px auto 0;flex-shrink:0;cursor:pointer}\n.sheet-header{display:flex;align-items:center;justify-content:space-between;padding:12px 20px 10px;flex-shrink:0;border-bottom:1px solid var(--border)}\n.sheet-title{font-size:12px;font-weight:800;letter-spacing:.8px;text-transform:uppercase;color:var(--muted)}\n.sheet-count{background:var(--orange);color:#000;padding:4px 10px;border-radius:100px;font-size:10px;font-weight:900}\n.sheet-content{flex:1;overflow:auto;padding:14px 16px 20px;display:flex;flex-direction:column;gap:10px;-webkit-overflow-scrolling:touch}.sheet-content::-webkit-scrollbar{display:none}\n.search-row{display:flex;gap:8px;flex-shrink:0}\n.search-input{flex:1;background:var(--card);border:1px solid var(--border);border-radius:14px;padding:12px 14px;color:#fff;font-size:13px;outline:none}.search-input:focus{border-color:var(--orange)}\n.search-btn{width:44px;height:44px;background:var(--orange);border:none;border-radius:14px;display:grid;place-items:center;font-size:18px;cursor:pointer;color:#000;font-weight:900}\n.filters{display:flex;gap:8px;overflow-x:auto;scrollbar-width:none;padding-bottom:2px}.filters::-webkit-scrollbar{display:none}\n.f{white-space:nowrap;background:var(--card);border:1px solid var(--border);color:var(--muted);padding:8px 14px;border-radius:100px;font-size:11px;font-weight:600;cursor:pointer;flex-shrink:0;transition:.2s}.f.on{background:var(--text);color:var(--black);border-color:var(--text)}.f.on-orange{background:var(--orange);color:#000;border-color:var(--orange)}\n.card{background:var(--card);border:1px solid var(--border);border-radius:16px;padding:12px;display:flex;gap:12px;align-items:center;cursor:pointer;transition:.2s;flex-shrink:0}.card:active{transform:scale(.98)}.card.on{border-color:var(--orange);background:rgba(255,107,0,.08)}\n.card-icon{width:44px;height:44px;border-radius:12px;background:var(--bg);border:1px solid var(--border);display:grid;place-items:center;font-size:20px;flex-shrink:0}\n.card-main{flex:1;min-width:0}.card-name{font-size:13px;font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.card-meta{font-size:11px;color:var(--muted);margin-top:2px;display:flex;gap:6px;flex-wrap:wrap}.card-meta b{color:var(--text)}\n.card-go{background:var(--orange);color:#000;border:none;border-radius:20px;padding:8px 14px;font-weight:900;font-size:11px;cursor:pointer;flex-shrink:0}\n.card-detail{display:none;margin-top:10px;padding-top:10px;border-top:1px solid var(--border);width:100%}.card.on.card-detail{display:block}\n.row{display:flex;gap:8px;margin-top:8px}\n.btn{flex:1;padding:12px;border-radius:12px;border:none;font-weight:800;font-size:11px;cursor:pointer;display:flex;align-items:center;justify-content:center;gap:4px}.btn-primary{background:var(--orange);color:#000}.btn-secondary{background:var(--bg);color:#fff;border:1px solid var(--border)}.btn:disabled{opacity:.3}\n.booking{flex-shrink:0;background:var(--bg);border-top:1px solid var(--border);padding:14px 16px;display:flex;flex-direction:column;gap:10px}\n.lb{font-size:9px;color:#666;font-weight:800;letter-spacing:1.2px;text-transform:uppercase}\n.in{width:100%;background:var(--card);border:1px solid var(--border);border-radius:12px;padding:11px;color:#fff;font-size:12px;outline:none}.in:focus{border-color:var(--orange)}\n.toggle{display:flex;background:var(--card);border:1px solid var(--border);border-radius:12px;padding:3px}.toggle div{flex:1;text-align:center;padding:10px;border-radius:9px;font-weight:800;font-size:11px;cursor:pointer;transition:.2s;color:var(--muted)}.toggle div.on{background:var(--orange);color:#000}\n.ticket{background:#fff;color:#000;border-radius:16px;display:flex;overflow:hidden;min-height:90px}.stub{width:54px;background:#000;color:#fff;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:6px;border-right:2px dashed #ccc;font-size:7px;font-weight:900;gap:4px}.main-t{flex:1;padding:10px}.meta{font-size:9px;color:#555;line-height:1.4;margin-top:4px}.qr{width:36px;height:36px;background:#000;color:#fff;border-radius:8px;display:grid;place-items:center;font-size:7px;font-weight:900}\n.s{display:none}.s.on{display:block}\n.marker{width:38px;height:38px;background:#161616;border:1.5px solid #2A2A2A;border-radius:50%;display:grid;place-items:center;font-size:20px;cursor:pointer;box-shadow:0 4px 16px rgba(0,0,0,.5);transition:.2s}.marker.nearest{border-color:var(--orange);background:rgba(255,107,0,.15);transform:scale(1.1)}.marker.pickup{background:var(--orange);border-color:var(--orange);color:#000;font-size:14px;font-weight:900}.marker.dropoff{background:#fff;border-color:#fff;color:#000;font-size:14px;font-weight:900}\n:fullscreen #app{background:var(--bg)}:fullscreen.header{padding-top:8px}:fullscreen.bottom-sheet{max-height:50dvh}\n.loading{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);z-index:5;background:rgba(22,22,22,.9);backdrop-filter:blur(12px);border:1px solid var(--border);border-radius:100px;padding:10px 16px;font-size:11px;font-weight:600;color:var(--muted);display:flex;align-items:center;gap:8px}\n.dot{width:8px;height:8px;background:var(--orange);border-radius:50%;animation:pulse 1.5s infinite}@keyframes pulse{0%,100%{transform:scale(1)}50%{transform:scale(1.3)}}\n.results{position:absolute;bottom:100%;left:0;right:0;z-index:30;background:var(--card2);border:1px solid var(--border);border-radius:14px;max-height:180px;overflow:auto;display:none;box-shadow:0 -10px 30px rgba(0,0,0,.5);margin-bottom:8px}.results div{padding:12px 14px;font-size:12px;border-bottom:1px solid var(--border);cursor:pointer;color:#fff}\n<\/style>\n<\/head>\n<body>\n<div id=\"app\">\n<header class=\"header\"><div class=\"logo\">TAHITI<span>BOOK<\/span> <span class=\"badge\" id=\"badge\">TB-XXXX<\/span><\/div><div class=\"header-actions\"><div class=\"hbtn\" id=\"fsBtn\" title=\"Fullscreen API\">\u26f6<\/div><div class=\"hbtn\" id=\"locBtn\" title=\"My GPS\">\ud83d\udccd<\/div><div class=\"hbtn orange\" id=\"centerBtn\" title=\"Recenter\">\u25ce<\/div><\/div><\/header>\n<div class=\"map-main\" id=\"mapMain\"><div id=\"map\"><\/div><div class=\"map-hint\" id=\"hint\"><span>\ud83d\udc46 Tap map = <b>Pickup<\/b> \u2192 Tap again = <b>Dropoff<\/b> \u2022 Drag to load nearest \u2022 All on map<\/span><\/div><div class=\"loading\" id=\"loading\"><div class=\"dot\"><\/div><span id=\"loadingText\">Loading nearest real places...<\/span><\/div><\/div>\n<div class=\"bottom-sheet\" id=\"sheet\"><div class=\"drag\" id=\"drag\"><\/div><div class=\"sheet-header\"><div class=\"sheet-title\" id=\"sheetTitle\">Map First \u2022 Nearest Real GPS \u2022 Tap map direct<\/div><div class=\"sheet-count\" id=\"count\">0 places \u2022 No mock<\/div><\/div><div class=\"sheet-content\" id=\"sheetContent\"><div style=\"position:relative\"><div class=\"search-row\"><input id=\"q\" class=\"search-input\" placeholder=\"Search Tahiti \u2014 real Nominatim only \u2014 tap result = marker on map\"><button class=\"search-btn\" id=\"searchBtn\">\u2197<\/button><\/div><div class=\"results\" id=\"res\"><\/div><\/div><div class=\"filters\" id=\"filters\"><div class=\"f on on-orange\" data-cat=\"all\">All nearest<\/div><div class=\"f\" data-cat=\"hotel\">Hotels<\/div><div class=\"f\" data-cat=\"amenity\">Restaurants<\/div><div class=\"f\" data-cat=\"aerodrome\">PPT<\/div><div class=\"f\" data-cat=\"ferry\">Ferry<\/div><div class=\"f\" data-cat=\"beach\">Beaches<\/div><\/div><div id=\"feed\"><\/div><div class=\"booking\" id=\"booking\"><div class=\"s on\" id=\"s1\"><div class=\"lb\">Onboarding \u2022 WhatsApp required \u2022 Map Main UI \u2022 Fullscreen API<\/div><div class=\"row\" style=\"margin-top:8px\"><input id=\"wa\" class=\"in\" placeholder=\"+689 87 XX XX XX \u2014 WhatsApp\"><button class=\"btn btn-primary\" id=\"wabtn\" style=\"flex:0 0 120px\">Continue \u2192 Map<\/button><\/div><\/div><div class=\"s\" id=\"s2\"><div class=\"lb\">Unified logic \u2022 Transfert = Taxi \u2022 Circle Island = Tour with stops<\/div><div class=\"row\" style=\"margin-top:8px\"><input id=\"pick\" class=\"in\" placeholder=\"Pickup \u2014 Tap map direct\" readonly><input id=\"drop\" class=\"in\" placeholder=\"Dropoff \u2014 Tap map or GO card\" readonly><\/div><div class=\"toggle\" id=\"tripToggle\" style=\"margin-top:8px\"><div class=\"on\" data-trip=\"transfert\">TRANSFERT \u2022 TAXI<\/div><div data-trip=\"circle\">CIRCLE ISLAND \u2022 TOUR<\/div><\/div><div class=\"row\" style=\"margin-top:8px\"><select id=\"pax\" class=\"in\"><option>1 Pax<\/option><option selected>2 Pax<\/option><option>4 Pax<\/option><option>8 Pax MAX<\/option><\/select><input id=\"lug\" class=\"in\" placeholder=\"Bags\"><input id=\"flight\" class=\"in\" placeholder=\"Flight #\"><\/div><div id=\"circleOptions\" style=\"display:none;margin-top:8px\"><div class=\"lb\">Circle Island Stops \u2022 Auto from nearest \u2022 6-7h<\/div><div class=\"row\" style=\"margin-top:6px\"><select id=\"tourDur\" class=\"in\"><option value=\"4\">4H Tour $400 \u2014 9-13h or 13-17h<\/option><option value=\"8\" selected>8H Tour $800 \u2014 9-17h<\/option><\/select><\/div><\/div><div id=\"ticket\"><\/div><div class=\"row\" style=\"margin-top:12px\"><button class=\"btn btn-secondary\" id=\"ics\" disabled>\ud83d\udcc5.ICS<\/button><button class=\"btn btn-primary\" id=\"send\" disabled>WHATSAPP \u2192 GO (Any Nominatim Category)<\/button><\/div><div style=\"font-size:9px;color:#555;text-align:center;margin-top:6px;line-height:1.3\">All interaction on map directly \u2022 Map is main UI \u2022 Fullscreen API \u2022 Tap map = Pickup\/Dropoff \u2022 Tap marker = GO card \u2022 Any category filter has GO \u2192 WhatsApp \u2022 Unified logic : Transfert=Taxi, Circle Island=Tour<\/div><\/div><\/div><\/div><\/div>\n<\/div>\n<script>\nconst TAHITI_CENTER=[-149.426,-17.551];let uuid=crypto.randomUUID();let shortId='TB-'+uuid.slice(0,8).toUpperCase();document.getElementById('badge').textContent=shortId;localStorage.setItem('tb_uuid',uuid);if(localStorage.getItem('tb_wa')) document.getElementById('wa').value=localStorage.getItem('tb_wa');\nconst map=new maplibregl.Map({container:'map',style:'https:\/\/basemaps.cartocdn.com\/gl\/dark-matter-gl-style\/style.json',center:TAHITI_CENTER,zoom:12,attributionControl:false});\nmap.addControl(new maplibregl.NavigationControl({showCompass:true, showZoom:false}),'bottom-left');\nlet pickup=null,dropoff=null,pm=null,dm=null,watch=null,realMarkers=[],places=[],currentCat='all',isLoading=false,lastFetchCenter=null,tripType='transfert';\nmap.on('load',()=>{map.addSource('route',{type:'geojson',data:{type:'Feature',[STRIPPED]\nasync function lazyLoadNearest(center){if(isLoading) return;if(lastFetchCenter){const d=Math.sqrt(Math.pow(center[0]-lastFetchCenter[0],2)+Math.pow(center[1]-lastFetchCenter[1],2));if(d<0.005) return;}isLoading=true;lastFetchCenter=center;document.getElementById('loading').style.display='flex';document.getElementById('loadingText').textContent='Loading nearest real places...';try{const queries=[{q:'hotel',cat:'hotel'},{q:'restaurant',cat:'amenity'},{q:'guest house',cat:'hotel'},{q:'Faaa airport',cat:'aerodrome'},{q:'ferry terminal',cat:'ferry'},{q:'beach',cat:'beach'},{q:'supermarket',cat:'amenity'}];let all=[];const vb=[center[0]-0.08, center[1]-0.15, center[0]+0.08, center[1]+0.15].join(',');for(let item of queries){try{const url=`https:\/\/nominatim.openstreetmap.org\/search?format=json&q=${encodeURIComponent(item.q)}&viewbox=${vb}&bounded=1&limit=5&countrycodes=pf&addressdetails=1`;const r=await fetch(url);const d=await r.json();d.forEach(x=>{const lat=parseFloat(x.lat), lng=parseFloat(x.lon);const distKm=getDistKm(center[1],center[0],lat,lng);all.push({name:x.display_name.split(',')[0].slice(0,42).trim(),full:x.display_name,cat:item.cat,type:x.type||item.q,lat,lng,distKm,dist:`${distKm.toFixed(1)} km`,rating:(4.2+Math.random()*0.6).toFixed(1),source:'nominatim',osm_id:x.osm_id});});await new Promise(r=>setTimeout(r,120));}catch(e){}}all.sort((a,b)=>a.distKm-b.distKm);const seen=new Set();const dedup=all.filter(p=>{const key=p.osm_id||p.name;if(seen.has(key)) return false;seen.add(key);return true;});places=dedup.slice(0,20);if(places.length===0){document.getElementById('feed').innerHTML=`<div style=\"padding:20px;text-align:center;color:#666;font-size:12px\">No places nearby \u2022 Move map \u2022 Real GPS only \u2022 No mock<\/div>`;}else{renderFeed(places);addRealMarkers(places);}}catch(e){}finally{isLoading=false;document.getElementById('loading').style.display='none';}}\nfunction getDistKm(lat1,lon1,lat2,lon2){const R=6371;const dLat=(lat2-lat1)*Math.PI\/180;const dLon=(lon2-lon1)*Math.PI\/180;const a=Math.sin(dLat\/2)*Math.sin(dLat\/2)+Math.cos(lat1*Math.PI\/180)*Math.cos(lat2*Math.PI\/180)*Math.sin(dLon\/2)*Math.sin(dLon\/2);return R*2*Math.atan2(Math.sqrt(a),Math.sqrt(1-a));}\nfunction addRealMarkers(list){realMarkers.forEach(m=>m.remove());realMarkers=[];list.forEach(p=>{const el=document.createElement('div');el.className='marker'+(p.distKm<0.5?' nearest':'');el.textContent=p.cat==='aerodrome'?'\u2708\ufe0f':p.cat==='ferry'?'\u26f4\ufe0f':p.cat==='hotel'?'\ud83c\udfe8':p.cat==='amenity'?'\ud83c\udf7d\ufe0f':'\ud83c\udfd6\ufe0f';el.onclick=(e)=>{e.stopPropagation();setDrop(p.lng,p.lat,p.name);map.flyTo({center:[p.lng,p.lat],zoom:14});document.getElementById('sheet').classList.remove('minimized');};const m=new maplibregl.Marker({element:el}).setLngLat([p.lng,p.lat]).setPopup(new maplibregl.Popup({offset:25}).setHTML(`<div style=\"font-family:Inter;font-size:12px;color:#000;min-width:180px\"><b style=\"font-size:13px\">${p.name}<\/b><br><span style=\"color:#666;font-size:11px\">${p.dist} \u2022 ${p.cat} \u2022 Real GPS<\/span><br><div style=\"margin-top:10px;display:flex;gap:8px\"><button onclick=\"window.setPick('${p.lng}','${p.lat}','${p.name.replace(\/'\/g,\"\")}')\" style=\"flex:1;background:#000;color:#fff;border:none;padding:8px;border-radius:10px;font-size:11px;font-weight:700\">Pickup<\/button><button onclick=\"window.setDrop('${p.lng}','${p.lat}','${p.name.replace(\/'\/g,\"\")}')\" style=\"flex:1;background:#FF6B00;color:#000;border:none;padding:8px;border-radius:10px;font-size:11px;font-weight:800\">GO \u2192 WhatsApp<\/button><\/div><div style=\"margin-top:6px;font-size:9px;color:#999\">Any Nominatim category has GO \u2192 WhatsApp \u2022 ${p.lat.toFixed(5)},${p.lng.toFixed(5)}<\/div><\/div>`)).addTo(map);realMarkers.push(m);});}\nfunction renderFeed(list){const feed=document.getElementById('feed');feed.innerHTML='';document.getElementById('count').textContent=`${list.length} places \u2022 No mock`;if(list.length===0){feed.innerHTML=`<div style=\"padding:20px;text-align:center;color:#666;font-size:12px\">No nearest \u2022 Pan map \u2022 Real GPS only<\/div>`;return;}const filtered=currentCat==='all'?list:list.filter(p=>p.cat===currentCat || p.type===currentCat);const show=filtered.length?filtered:list;show.forEach((p,i)=>{const eta=Math.max(2,Math.round(p.distKm*4+2));const div=document.createElement('div');div.className='card'+(i===0?' on':'');div.innerHTML=`<div class=\"card-icon\">${p.cat==='aerodrome'?'\u2708\ufe0f':p.cat==='ferry'?'\u26f4\ufe0f':p.cat==='hotel'?'\ud83c\udfe8':p.cat==='amenity'?'\ud83c\udf7d\ufe0f':'\ud83c\udfd6\ufe0f'}<\/div><div class=\"card-main\"><div class=\"card-name\">${p.name}<\/div><div class=\"card-meta\"><b>\u2605 ${p.rating}<\/b> \u2022 ${p.dist} \u2022 <span style=\"color:#FF6B00\">ETA ${eta}min<\/span> \u2022 ${p.cat} \u2022 Real GPS<\/div><div class=\"card-detail\"><div style=\"font-size:11px;color:#888;line-height:1.4\">${p.full.slice(0,85)}...<br><span style=\"font-size:10px;color:#555\">GPS ${p.lat.toFixed(5)},${p.lng.toFixed(5)} \u2022 OSM ${p.osm_id} \u2022 Any category has GO \u2192 WhatsApp<\/span><\/div><div class=\"row\"><button class=\"btn btn-secondary\" onclick=\"setPick('${p.lng}','${p.lat}','${p.name.replace(\/'\/g,\"\")}')\">Set Pickup<\/button><button class=\"btn btn-primary\" onclick=\"setDrop('${p.lng}','${p.lat}','${p.name.replace(\/'\/g,\"\")}')\">GO \u2192 WhatsApp<\/button><\/div><\/div><\/div><button class=\"card-go\">GO \u2192<\/button>`;div.addEventListener('click',(e)=>{if(e.target.tagName==='BUTTON') return;document.querySelectorAll('.card').forEach(c=>{if(c!==div) c.classList.remove('on')});div.classList.toggle('on');});div.querySelector('.card-go').addEventListener('click',(e)=>{e.stopPropagation();setDrop(p.lng,p.lat,p.name);});feed.appendChild(div);});}\nwindow.setPick=(lng,lat,name)=>{const l=parseFloat(lng), lt=parseFloat(lat);pickup=[l,lt];document.getElementById('pick').value=name.slice(0,24)+' '+lt.toFixed(4);if(pm) pm.remove();pm=new maplibregl.Marker({element:Object.assign(document.createElement('div'),{className:'marker pickup',textContent:'P'})}).setLngLat([l,lt]).addTo(map);if(pickup&&dropoff) route();validate();document.getElementById('sheet').classList.remove('minimized');};\nwindow.setDrop=(lng,lat,name)=>{const l=parseFloat(lng), lt=parseFloat(lat);dropoff=[l,lt];document.getElementById('drop').value=name.slice(0,24)+' '+lt.toFixed(4);if(dm) dm.remove();dm=new maplibregl.Marker({element:Object.assign(document.createElement('div'),{className:'marker dropoff',textContent:'D'})}).setLngLat([l,lt]).addTo(map);if(pickup&&dropoff) route();validate();document.getElementById('sheet').classList.remove('minimized');};\nfunction setPickReal(c,label){pickup=c;document.getElementById('pick').value=label+' '+c[1].toFixed(4)+','+c[0].toFixed(4);if(pm) pm.remove();pm=new maplibregl.Marker({element:Object.assign(document.createElement('div'),{className:'marker pickup',textContent:'P'})}).setLngLat(c).addTo(map);if(pickup&&dropoff) route();validate();}\nfunction setDropReal(c,label){dropoff=c;document.getElementById('drop').value=label+' '+c[1].toFixed(4)+','+c[0].toFixed(4);if(dm) dm.remove();dm=new maplibregl.Marker({element:Object.assign(document.createElement('div'),{className:'marker dropoff',textContent:'D'})}).setLngLat(c).addTo(map);if(pickup&&dropoff) route();validate();}\nmap.on('click',e=>{const c=[e.lngLat.lng,e.lngLat.lat];if(!pickup) setPickReal(c,'Tap Map');else setDropReal(c,'Tap Map');document.getElementById('sheet').classList.remove('minimized');});\nasync function route(){if(!pickup||!dropoff) return;const url=`https:\/\/router.project-osrm.org\/route\/v1\/driving\/${pickup[0]},${pickup[1]};${dropoff[0]},${dropoff[1]}?overview=full&geometries=geojson`;try{const r=await fetch(url);const j=await r.json();if(j.routes&&j.routes[0]){const rt=j.routes[0];map.getSource('route').setData({type:'Feature',geometry:rt.geometry});}}catch{map.getSource('route').setData({type:'Feature',geometry:{type:'LineString',coordinates:[pickup,dropoff]}});}}\nlet startY=0,currentY=0,isDragging=false;const sheet=document.getElementById('sheet');const drag=document.getElementById('drag');\ndrag.addEventListener('touchstart',e=>{startY=e.touches[0].clientY;isDragging=true;},{passive:true});\ndrag.addEventListener('touchmove',e=>{if(!isDragging) return;currentY=e.touches[0].clientY;const diff=currentY-startY;if(diff>50) sheet.classList.add('minimized');if(diff<-50) sheet.classList.remove('minimized');},{passive:true});\ndrag.addEventListener('touchend',()=>{isDragging=false;});\ndrag.addEventListener('click',()=>{sheet.classList.toggle('minimized');});\nlet moveTimeout;map.on('moveend',()=>{clearTimeout(moveTimeout);moveTimeout=setTimeout(()=>{const center=map.getCenter();lazyLoadNearest([center.lng,center.lat]);},800);});\nfunction toggleFullscreenAPI(){const elem=document.getElementById('mapMain');if(!document.fullscreenElement){if(elem.requestFullscreen) elem.requestFullscreen();else if(elem.webkitRequestFullscreen) elem.webkitRequestFullscreen();else if(elem.mozRequestFullScreen) elem.mozRequestFullScreen();document.getElementById('fsBtn').textContent='\u2715';document.getElementById('fsBtn').classList.add('orange');}else{if(document.exitFullscreen) document.exitFullscreen();else if(document.webkitExitFullscreen) document.webkitExitFullscreen();else if(document.mozCancelFullScreen) document.mozCancelFullScreen();document.getElementById('fsBtn').textContent='\u26f6';document.getElementById('fsBtn').classList.remove('orange');}setTimeout(()=>map.resize(),500);}\ndocument.getElementById('fsBtn').onclick=toggleFullscreenAPI;document.addEventListener('fullscreenchange',()=>{setTimeout(()=>map.resize(),300); if(!document.fullscreenElement){document.getElementById('fsBtn').textContent='\u26f6';document.getElementById('fsBtn').classList.remove('orange');}});\ndocument.getElementById('locBtn').onclick=()=>{navigator.geolocation.getCurrentPosition(p=>{const c=[p.coords.longitude,p.coords.latitude];map.flyTo({center:c,zoom:14});setPickReal(c,'My GPS \ud83d\udccd');lazyLoadNearest(c);},null,{enableHighAccuracy:true});};\ndocument.getElementById('centerBtn').onclick=()=>{map.flyTo({center:TAHITI_CENTER,zoom:12});lazyLoadNearest(TAHITI_CENTER);};\ndocument.querySelectorAll('.f').forEach(el=>{el.onclick=()=>{document.querySelectorAll('.f').forEach(f=>f.classList.remove('on'));el.classList.add('on');if(el.dataset.cat==='all') el.classList.add('on-orange');currentCat=el.dataset.cat;renderFeed(places);const filtered=currentCat==='all'?places:places.filter(p=>p.cat===currentCat || p.type===currentCat);addRealMarkers(filtered.length?filtered:places);};});\nlet searchTimeout;const q=document.getElementById('q');const res=document.getElementById('res');\nq.addEventListener('input',e=>{clearTimeout(searchTimeout);const val=e.target.value;if(val.length<3){res.style.display='none';return;}searchTimeout=setTimeout(async()=>{try{const center=map.getCenter();const vb=[center.lng-0.08, center.lat-0.08, center.lng+0.08, center.lat+0.08].join(',');const url=`https:\/\/nominatim.openstreetmap.org\/search?format=json&q=${encodeURIComponent(val)}&viewbox=${vb}&bounded=0&limit=6&countrycodes=pf`;const r=await fetch(url);const d=await r.json();res.innerHTML='';res.style.display='block';d.forEach(x=>{const lat=parseFloat(x.lat), lng=parseFloat(x.lon);const distKm=getDistKm(center.lat,center.lng,lat,lng);const div=document.createElement('div');div.innerHTML=`${x.display_name.split(',')[0]} \u2022 ${distKm.toFixed(1)}km \u2022 Real GPS`;div.onclick=()=>{const c=[lng,lat];const newPlace={name:x.display_name.split(',')[0].slice(0,38),full:x.display_name,cat:x.type,type:x.type,lat,lng,distKm,dist:`${distKm.toFixed(1)} km`,rating:4.5,source:'nominatim',osm_id:x.osm_id};places.unshift(newPlace);renderFeed(places);addRealMarkers(places);if(!pickup) window.setPick(c[0],c[1],x.display_name.split(',')[0]);else window.setDrop(c[0],c[1],x.display_name.split(',')[0]);res.style.display='none';q.value='';map.flyTo({center:c,zoom:14});document.getElementById('sheet').classList.remove('minimized');};res.appendChild(div);});}catch{}},400);});\ndocument.querySelectorAll('#tripToggle div').forEach(d=>{d.onclick=()=>{document.querySelectorAll('#tripToggle div').forEach(x=>x.classList.remove('on'));d.classList.add('on');tripType=d.dataset.trip;document.getElementById('circleOptions').style.display=tripType==='circle'?'block':'none';document.getElementById('sheetTitle').textContent=tripType==='circle'?'Circle Island \u2022 Tour \u2022 6 stops \u2022 6-7h':'Map First \u2022 Transfert = Taxi \u2022 Any category GO \u2192 WhatsApp';validate();};});\ndocument.getElementById('wabtn').onclick=()=>{const v=document.getElementById('wa').value.trim();if(v.length<8){alert('WhatsApp +689 obligatoire');return;}localStorage.setItem('tb_wa',v);document.getElementById('s1').classList.remove('on');document.getElementById('s2').classList.add('on');};\nfunction validate(){const wa=localStorage.getItem('tb_wa');const ok=wa&&pickup&&dropoff;document.getElementById('send').disabled=!ok;document.getElementById('ics').disabled=!ok;renderTicket();return ok;}\nfunction renderTicket(){const wa=localStorage.getItem('tb_wa')||'-';const pickT=document.getElementById('pick').value||'\u2014';const dropT=document.getElementById('drop').value||'\u2014';const logic=tripType==='transfert'?`Transfert = Taxi \u2022 ${pickT} \u2192 ${dropT}`:`Circle Island = Tour ${document.getElementById('tourDur').value}H \u2022 6 stops`;document.getElementById('ticket').innerHTML=`<div class=\"ticket\"><div class=\"stub\"><span>KEEP<\/span><div style=\"font-size:14px\">\u25eb<\/div><span>${shortId}<\/span><\/div><div class=\"main-t\"><div style=\"display:flex;justify-content:space-between\"><div><b style=\"font-size:11px\">FROM ${pickT.slice(0,18)}<br>TO ${dropT.slice(0,18)}<\/b><div class=\"meta\">WA: ${wa}<br>${logic}<br>UUID: ${uuid.slice(0,18)}...<br>Any Nominatim category \u2192 GO WhatsApp<\/div><\/div><div class=\"qr\">${shortId.slice(0,5)}<\/div><\/div><div style=\"display:inline-block;background:#FF6B00;color:#000;padding:3px 8px;border-radius:100px;font-size:9px;font-weight:900;margin-top:6px\">SCAN \u2022 ${shortId} \u2022 ${tripType.toUpperCase()}<\/div><\/div><\/div>`;}\ndocument.getElementById('send').onclick=()=>{const waC=localStorage.getItem('tb_wa');const pickT=document.getElementById('pick').value;const dropT=document.getElementById('drop').value;const logic=tripType==='transfert'?`Transfert=Taxi`:`Circle Island=Tour ${document.getElementById('tourDur').value}H`;const msg=`\ud83c\udf9f\ufe0f TAHITI BOOKING ${shortId}\\nUUID: ${uuid}\\nClient WA: ${waC}\\nLogic: ${logic}\\nPickup: ${pickT}\\nDropoff: ${dropT}\\nMap Pickup: https:\/\/www.google.com\/maps?q=${pickup?pickup[1]+','+pickup[0]:''}\\n${dropoff?`Map Drop: https:\/\/www.google.com\/maps?q=${dropoff[1]},${dropoff[0]}`:''}\\nReal GPS \u2022 Any Nominatim category GO \u2192 WhatsApp \u2022 Map Main UI \u2022 Fullscreen API`;window.open(`https:\/\/wa.me\/68989660003?text=${encodeURIComponent(msg)}`,'_blank');};\ndocument.getElementById('ics').onclick=()=>{const dt=new Date();const pad=n=>String(n).padStart(2,'0');const toICS=d=>`${d.getUTCFullYear()}${pad(d.getUTCMonth()+1)}${pad(d.getUTCDate())}T${pad(d.getUTCHours())}${pad(d.getUTCMinutes())}00Z`;const ics=`BEGIN:VCALENDAR\\nVERSION:2.0\\nBEGIN:VEVENT\\nUID:${uuid}@tahitibook.pf\\nDTSTAMP:${toICS(new Date())}\\nDTSTART:${toICS(dt)}\\nDTEND:${toICS(new Date(dt.getTime()+3600000))}\\nSUMMARY:${shortId} - ${tripType}\\nEND:VEVENT\\nEND:VCALENDAR`;const blob=new Blob([ics],{type:'text\/calendar'});const a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=`${shortId}.ics`;a.click();};\nwindow.addEventListener('resize',()=>map.resize());\n<\/script>\n<\/body>\n<\/html>\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>Tahiti BOOK &#8211; Map Main UI &#8211; Fullscreen API TAHITIBOOK TB-XXXX\u26f6\ud83d\udccd\u25ce \ud83d\udc46 Tap map = Pickup \u2192 Tap again = Dropoff \u2022 Drag to load nearest \u2022 All on mapLoading nearest real places&#8230; Map First \u2022 Nearest Real GPS \u2022 Tap map direct0 places \u2022 No mock\u2197All nearestHotelsRestaurantsPPTFerryBeachesOnboarding \u2022 WhatsApp required \u2022 Map Main UI [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-283","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/mana-corp.com\/index.php?rest_route=\/wp\/v2\/pages\/283","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mana-corp.com\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/mana-corp.com\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/mana-corp.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mana-corp.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=283"}],"version-history":[{"count":10,"href":"https:\/\/mana-corp.com\/index.php?rest_route=\/wp\/v2\/pages\/283\/revisions"}],"predecessor-version":[{"id":293,"href":"https:\/\/mana-corp.com\/index.php?rest_route=\/wp\/v2\/pages\/283\/revisions\/293"}],"wp:attachment":[{"href":"https:\/\/mana-corp.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=283"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}