`).join('');
setupAutoJump();
}
function getWpDec(i){
const ld=document.getElementById('wp'+i+'_latD'); if(!ld) return null;
const la=dmsToDec(ld.value,document.getElementById('wp'+i+'_latM').value,document.getElementById('wp'+i+'_latS').value,document.getElementById('wp'+i+'_latH').value);
const lo=dmsToDec(document.getElementById('wp'+i+'_lonD').value,document.getElementById('wp'+i+'_lonM').value,document.getElementById('wp'+i+'_lonS').value,document.getElementById('wp'+i+'_lonH').value);
if(isNaN(la)||isNaN(lo)) return null;
return {lat:la,lon:lo};
}
function toRad(d){return d*Math.PI/180}function toDeg(r){return r*180/Math.PI}
function dmsToDec(d,m,s,h){if(d===''||d===null)return NaN;let dd=parseFloat(d||0)+parseFloat(m||0)/60+parseFloat(s||0)/3600;if(h==='S'||h==='W')dd=-dd;return dd}
function decToDms(dec,isLat){let abs=Math.abs(dec);let d=Math.floor(abs);let mf=(abs-d)*60;let m=Math.floor(mf);let s=(mf-m)*60;let h=isLat?(dec>=0?'N':'S'):(dec>=0?'E':'W');return{deg:d,min:m,sec:s,hem:h}}
function haversineNM(a,b,c,d){const R=6371.0088;const dLat=toRad(c-a);const dLon=toRad(d-b);const x=Math.sin(dLat/2)**2+Math.cos(toRad(a))*Math.cos(toRad(c))*Math.sin(dLon/2)**2;return (R*2*Math.atan2(Math.sqrt(x),Math.sqrt(1-x)))/1.852}
function initBearing(a,b,c,d){const y=Math.sin(toRad(d-b))*Math.cos(toRad(c));const x=Math.cos(toRad(a))*Math.sin(toRad(c))-Math.sin(toRad(a))*Math.cos(toRad(c))*Math.cos(toRad(d-b));return (toDeg(Math.atan2(y,x))+360)%360}
function finalBearing(a,b,c,d){return (initBearing(c,d,a,b)+180)%360}
function fillDMS(lat,lon,acc){
const la=decToDms(lat,true);const lo=decToDms(lon,false);
document.getElementById('curLatD').value=la.deg;document.getElementById('curLatM').value=la.min;document.getElementById('curLatS').value=la.sec.toFixed(3);document.getElementById('curLatH').value=la.hem;
document.getElementById('curLonD').value=lo.deg;document.getElementById('curLonM').value=lo.min;document.getElementById('curLonS').value=lo.sec.toFixed(3);document.getElementById('curLonH').value=lo.hem;
document.getElementById('posBadge').textContent='Live GPS ±'+Math.round(acc)+'m';document.getElementById('posBadge').style.background='#dff0e4';
document.getElementById('gpsAcc').textContent='Fix: '+acc.toFixed(1)+'m';
const now=new Date();const iso=new Date(now.getTime()-now.getTimezoneOffset()*60000).toISOString().slice(0,16);
document.getElementById('timeObtained').value=iso;updateTimePreview();
lastGPS={lat,lon,acc};
}
function useLiveGPS(){
const b=document.getElementById('gpsBtn');const err=document.getElementById('err');
err.style.display='block';err.textContent='Requesting GPS...';
if(!navigator.geolocation){err.textContent='No GPS support';return;}
b.textContent='Locating...';
navigator.geolocation.getCurrentPosition(p=>{fillDMS(p.coords.latitude,p.coords.longitude,p.coords.accuracy);b.textContent='Live GPS ✓';err.style.display='none';plotCurrentOnly();},e=>{
let msg='GPS Error: '+e.message;if(e.code===1)msg='Permission DENIED - Settings > Chrome > Location > Allow';if(e.code===2)msg='GPS unavailable - Turn ON Location';if(e.code===3)msg='Timeout - Go open deck';err.textContent=msg;b.textContent='Live GPS';},{enableHighAccuracy:true,timeout:20000,maximumAge:0});
}
function toggleWatchGPS(){
const b=document.getElementById('watchBtn');const err=document.getElementById('err');
if(watchId!==null){navigator.geolocation.clearWatch(watchId);watchId=null;b.textContent='Watch OFF';b.classList.remove('watch-on');err.style.display='none';return;}
if(!navigator.geolocation){err.style.display='block';err.textContent='No GPS';return;}
b.textContent='Watch ON...';b.classList.add('watch-on');err.style.display='block';err.textContent='Watch ON - Tracking...';
watchId=navigator.geolocation.watchPosition(p=>{fillDMS(p.coords.latitude,p.coords.longitude,p.coords.accuracy);b.textContent='Watch ON ('+Math.round(p.coords.accuracy)+'m) LIVE';err.textContent='Watch LIVE ±'+Math.round(p.coords.accuracy)+'m';plotCurrentOnly();},e=>{err.textContent='Watch Error: '+e.message;},{enableHighAccuracy:true,maximumAge:1000,timeout:20000});
}
function showErr(m){const er=document.getElementById('err');er.textContent=m;er.style.display='block';setTimeout(()=>er.style.display='none',6000);}
function initMap(){if(map)return;try{map=L.map('map',{zoomControl:false}).setView([11.7,43.2],5);L.control.zoom({position:'bottomright'}).addTo(map);L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{maxZoom:18}).addTo(map);document.getElementById('mapInfo').textContent='OSM Ready (Offline)';}catch(e){document.getElementById('map').innerHTML='
OFFLINE MODE
';}setTimeout(()=>{if(map)try{map.invalidateSize()}catch(e){}},500);}
function initGMap(){if(gmap)return;try{gmap=L.map('gmap',{zoomControl:false}).setView([11.7,43.2],5);L.control.zoom({position:'bottomright'}).addTo(gmap);L.tileLayer('https://{s}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}',{maxZoom:20,subdomains:['mt0','mt1','mt2','mt3']}).addTo(gmap);document.getElementById('gmapInfo').textContent='Google Map ready (online)';}catch(e){document.getElementById('gmap').innerHTML='
Google Map needs internet
';}}
function toggleGMap(){const w=document.getElementById('gmapWrap');const b=document.getElementById('gToggle');if(!gVisible){w.style.display='block';b.textContent='Hide Google Map';gVisible=true;initGMap();setTimeout(()=>{if(gmap)gmap.invalidateSize();if(window.lastRoute)plotBothGMulti(window.lastRoute,window.lastDist);},300);}else{w.style.display='none';b.textContent='Show Google Map';gVisible=false;}}
function centerMap(){if(curMarker&&map)map.setView(curMarker.getLatLng(),10);}
function centerGMap(){if(gCurMarker&&gmap)gmap.setView(gCurMarker.getLatLng(),10);}
function plotCurrentOnly(){initMap();const lat=dmsToDec(curLatD.value,curLatM.value,curLatS.value,curLatH.value);const lon=dmsToDec(curLonD.value,curLonM.value,curLonS.value,curLonH.value);if(isNaN(lat)||isNaN(lon))return;if(typeof L==='undefined')return;if(curMarker)map.removeLayer(curMarker);curMarker=L.marker([lat,lon],{icon:L.divIcon({html:'',iconSize:[18,18],className:''})}).addTo(map);map.setView([lat,lon],9);}
function plotBothGMulti(route,totalDist){
if(!gmap)return;try{
if(gCurMarker)gmap.removeLayer(gCurMarker);if(gDestMarker)gmap.removeLayer(gDestMarker);if(gLine)gmap.removeLayer(gLine);gWpMarkers.forEach(m=>{try{gmap.removeLayer(m)}catch(e){}});gWpMarkers=[];
let latlngs=route.map(r=>[r.lat,r.lon]);gLine=L.polyline(latlngs,{color:'#ff7a00',weight:3,dashArray:'8,8'}).addTo(gmap);
route.forEach((r,i)=>{let col=i===0?'#c23c2a':(i===route.length-1?'#0b2540':'#ff7a00');let mk=L.marker([r.lat,r.lon],{icon:L.divIcon({html:'',iconSize:[14,14],className:''})}).addTo(gmap);if(i===0)gCurMarker=mk;else if(i===route.length-1)gDestMarker=mk;else gWpMarkers.push(mk);});
gmap.fitBounds(latlngs,{padding:[30,30]});}catch(e){}
}
function plotBothMulti(route,totalDist){
initMap();if(typeof L==='undefined')return;
if(curMarker)map.removeLayer(curMarker);if(destMarker)map.removeLayer(destMarker);if(line)map.removeLayer(line);wpMarkers.forEach(m=>{try{map.removeLayer(m)}catch(e){}});wpMarkers=[];
let latlngs=route.map(r=>[r.lat,r.lon]);line=L.polyline(latlngs,{color:'#c23c2a',weight:3,dashArray:'8,8'}).addTo(map);
route.forEach((r,i)=>{let col=i===0?'#c23c2a':(i===route.length-1?'#0b2540':'#ff7a00');let lab=r.label;let mk=L.marker([r.lat,r.lon],{icon:L.divIcon({html:'
'+lab+'
',iconSize:[16,24],className:''})}).addTo(map);if(i===0)curMarker=mk;else if(i===route.length-1)destMarker=mk;else wpMarkers.push(mk);});
map.fitBounds(latlngs,{padding:[40,40]});setTimeout(()=>{if(map)map.invalidateSize()},200);window.lastRoute=route;window.lastDist=totalDist;if(gVisible){initGMap();plotBothGMulti(route,totalDist);}
}
function openInPsyberia(){const a=dmsToDec(curLatD.value,curLatM.value,curLatS.value,curLatH.value);const b=dmsToDec(curLonD.value,curLonM.value,curLonS.value,curLonH.value);const c=dmsToDec(destLatD.value,destLatM.value,destLatS.value,destLatH.value);const d=dmsToDec(destLonD.value,destLonM.value,destLonS.value,destLonH.value);if(isNaN(a)){alert('Enter Current');return;}if(!isNaN(c))window.location.href='geo:'+a+','+b+'?q='+c+','+d+'(DEST)&z=8';else window.location.href='geo:'+a+','+b+'?q='+a+','+b+'(CUR)&z=12';}
function updateClock(){const el=document.getElementById('utcLocal');if(el)el.textContent='UTC:'+new Date().toISOString().substring(11,19)+' | LT:'+new Date().toLocaleTimeString('en-GB',{timeZone:'Africa/Nairobi'});}setInterval(updateClock,1000);updateClock();
function calculateETA(){
const a=dmsToDec(curLatD.value,curLatM.value,curLatS.value,curLatH.value);
const b=dmsToDec(curLonD.value,curLonM.value,curLonS.value,curLonH.value);
const c=dmsToDec(destLatD.value,destLatM.value,destLatS.value,destLatH.value);
const d=dmsToDec(destLonD.value,destLonM.value,destLonS.value,destLonH.value);
const sog=parseFloat(document.getElementById('sog').value);
const timeObt=document.getElementById('timeObtained').value;
let dep=timeObt?new Date(timeObt):new Date();
if([a,b,c,d,sog].some(v=>isNaN(v))){showErr('Fill all DD MM SS.s + SOG');return;}
let route=[];route.push({lat:a,lon:b,label:'CUR'});
let wpValid=[];for(let i=0;i'+note+' Total Dist: '+totalDist.toFixed(2)+' NM GC + '+((dist/totalDist-1)*100).toFixed(1)+'% = '+dist.toFixed(2)+' NM Departure LT: '+ltDep+' | UTC: '+utcDep;
if(legs.length>1){subHtml+='