@rr0/ufoathome 0.152.0 → 0.152.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1733,12 +1733,12 @@ canvas[data-cursor="rotate"] {
1733
1733
  pointer-events: none;
1734
1734
  white-space: nowrap;
1735
1735
  }
1736
- `;class Yo{static DEFAULT_FOCAL_MM=50;static FOCAL_RANGE_MM={minMm:14,maxMm:135};static BODIES=[{id:"eos-450d",name:"Canon EOS 450D (APS-C)",widthMm:22.2,heightMm:14.8,pixelUm:5.2,year:2008},{id:"eos-60da",name:"Canon EOS 60Da (APS-C)",widthMm:22.3,heightMm:14.9,pixelUm:4.3,year:2012},{id:"eos-70d",name:"Canon EOS 70D (APS-C)",widthMm:22.5,heightMm:15,pixelUm:4.1,year:2013},{id:"eos-80d",name:"Canon EOS 80D (APS-C)",widthMm:22.3,heightMm:14.9,pixelUm:3.7,year:2016},{id:"eos-7d",name:"Canon EOS 7D (APS-C)",widthMm:22.3,heightMm:14.9,pixelUm:4.1,year:2009},{id:"eos-7d-ii",name:"Canon EOS 7D Mark II (APS-C)",widthMm:22.4,heightMm:15,pixelUm:4.1,year:2014},{id:"eos-5d",name:"Canon EOS 5D (full frame)",widthMm:35.8,heightMm:23.9,pixelUm:8.2,year:2005},{id:"eos-5d-ii",name:"Canon EOS 5D Mark II (full frame)",widthMm:36,heightMm:24,pixelUm:6.4,year:2008},{id:"eos-5d-iii",name:"Canon EOS 5D Mark III (full frame)",widthMm:36,heightMm:24,pixelUm:6.25,year:2012},{id:"eos-5d-iv",name:"Canon EOS 5D Mark IV (full frame)",widthMm:36,heightMm:24,pixelUm:5.36,year:2016},{id:"eos-6d",name:"Canon EOS 6D (full frame)",widthMm:35.8,heightMm:23.9,pixelUm:6.55,year:2012},{id:"eos-6d-ii",name:"Canon EOS 6D Mark II (full frame)",widthMm:36,heightMm:24,pixelUm:5.77,year:2017},{id:"nikon-d3",name:"Nikon D3 / D700 (full frame)",widthMm:36,heightMm:23.9,pixelUm:8.44,year:2007},{id:"nikon-d7000",name:"Nikon D7000 (DX)",widthMm:23.6,heightMm:15.6,pixelUm:4.78,year:2010},{id:"nikon-d7100",name:"Nikon D7100 / D7200 (DX)",widthMm:23.5,heightMm:15.6,pixelUm:3.9,year:2013},{id:"nikon-d500",name:"Nikon D500 / D7500 (DX)",widthMm:23.5,heightMm:15.7,pixelUm:4.2,year:2016}];static instruments(){return Yo.BODIES.map(t=>({id:t.id,category:"dslr",name:t.name,projection:"rectilinear",frame:{widthMm:t.widthMm,heightMm:t.heightMm,focalLengthMm:Yo.DEFAULT_FOCAL_MM,focalRangeMm:Yo.FOCAL_RANGE_MM},fNumber:8,fNumberRange:{min:1.4,max:22},exposureSeconds:1/250,exposureRangeSeconds:{min:1/8e3,max:3600},years:{from:t.year},apertureBlades:7,detailUm:t.pixelUm,medium:{kind:"sensor",iso:100}}))}static names(){return Object.fromEntries(Yo.BODIES.map(t=>[t.id,t.name]))}}class Ts{static DEFAULT_EYEPIECE_MM=26;static DEFAULT_APPARENT_FIELD_DEG=52;static FIELD_STOP_MM=2*Ts.DEFAULT_EYEPIECE_MM*Math.tan(Ts.DEFAULT_APPARENT_FIELD_DEG*Math.PI/360);static RANGE={min:26/40*.63,max:26/6*3};static BINOCULARS=[{id:"binoculars-zeiss-6x30",name:"Carl Zeiss 6x30",magnification:6,apertureMm:30,trueFieldDeg:5,fromYear:1960},{id:"binoculars-zeiss-dialyt-10x40",name:"Carl Zeiss Dialyt 10x40 B T*",magnification:10,apertureMm:40,trueFieldDeg:6.3,fromYear:1975},{id:"binoculars-jenoptem-10x50",name:"Jenoptem 10x50 W",magnification:10,apertureMm:50,trueFieldDeg:7.3,fromYear:1960},{id:"binoculars-swarovski-7x50-habicht",name:"Swarovski 7x50 SL Habicht",magnification:7,apertureMm:50,trueFieldDeg:6.6,fromYear:1960},{id:"binoculars-swarovski-7x50-slc",name:"Swarovski 7x50 SLC",magnification:7,apertureMm:50,trueFieldDeg:7.1,fromYear:1990},{id:"binoculars-nikon-10x42-edg",name:"Nikon 10x42 EDG",magnification:10,apertureMm:42,trueFieldDeg:6.5,fromYear:2011},{id:"binoculars-canon-15x50-is",name:"Canon 15x50 IS All Weather",magnification:15,apertureMm:50,trueFieldDeg:4.5,fromYear:2008},{id:"binoculars-celestron-15x70",name:"Celestron 15x70 SkyMaster",magnification:15,apertureMm:70,trueFieldDeg:4.4,fromYear:1990},{id:"binoculars-miyauchi-25x141",name:"Miyauchi BR-141 Galaxy 45 25x141",magnification:25,apertureMm:141,trueFieldDeg:2.6,fromYear:2e3}];static TELESCOPES=[{id:"telescope-generic-60-700",name:"Telescope 60/700",apertureMm:60,focalLengthMm:700},{id:"telescope-generic-60-1000",name:"Telescope 60/1000",apertureMm:60,focalLengthMm:1e3},{id:"telescope-celestron-onyx-80edf",name:"Celestron Onyx 80EDF",apertureMm:80,focalLengthMm:500,fromYear:2010},{id:"telescope-celestron-c5",name:"Celestron C5 f/10",apertureMm:125,focalLengthMm:1250,fromYear:1970},{id:"telescope-celestron-c8",name:"Celestron C8 f/10",apertureMm:203,focalLengthMm:2032,fromYear:1970},{id:"telescope-celestron-c11",name:"Celestron C11 f/10",apertureMm:280,focalLengthMm:2800,fromYear:1970},{id:"telescope-celestron-c14",name:"Celestron C14 f/11",apertureMm:355.6,focalLengthMm:3910,fromYear:1970},{id:"telescope-meade-etx-80",name:"Meade ETX 80 f/5",apertureMm:80,focalLengthMm:400,fromYear:1996},{id:"telescope-meade-etx-90",name:"Meade ETX 90 f/13.8",apertureMm:90,focalLengthMm:1242,fromYear:1996},{id:"telescope-meade-etx-125",name:"Meade ETX 125 f/15",apertureMm:127,focalLengthMm:1900,fromYear:1996},{id:"telescope-meade-lx200-8",name:"Meade LX200 8 in f/10",apertureMm:200,focalLengthMm:2e3,fromYear:1992},{id:"telescope-meade-lx200-10",name:"Meade LX200 10 in f/10",apertureMm:250,focalLengthMm:2500,fromYear:1992},{id:"telescope-meade-lx200-12",name:"Meade LX200 12 in f/10",apertureMm:305,focalLengthMm:3048,fromYear:1992},{id:"telescope-meade-lx200-14",name:"Meade LX200 14 in f/10",apertureMm:355,focalLengthMm:3556,fromYear:1992},{id:"telescope-meade-lx200-16",name:"Meade LX200 16 in f/10",apertureMm:406,focalLengthMm:4064,fromYear:1992}];static instruments(){const t=Ts.BINOCULARS.map(n=>({id:n.id,category:"binoculars",name:n.name,projection:"rectilinear",visualAid:{apertureMm:n.apertureMm,magnification:n.magnification,trueFieldDeg:n.trueFieldDeg},...n.fromYear!==void 0?{years:{from:n.fromYear}}:{}})),e=Ts.FIELD_STOP_MM,i=Ts.TELESCOPES.map(n=>({id:n.id,category:"telescope",name:n.name,projection:"rectilinear",frame:{widthMm:e*16/9,heightMm:e,focalLengthMm:n.focalLengthMm,focalRangeMm:{minMm:n.focalLengthMm*Ts.RANGE.min,maxMm:n.focalLengthMm*Ts.RANGE.max}},visualAid:{apertureMm:n.apertureMm,eyepieceFocalMm:Ts.DEFAULT_EYEPIECE_MM},...n.fromYear!==void 0?{years:{from:n.fromYear}}:{}}));return[...t,...i]}static names(){return Object.fromEntries(Ts.instruments().map(t=>[t.id,t.name]))}}const nl=[{id:"eye",category:"eye",name:"Naked eye",projection:"equidistant",stabilization:.97},{id:"rectilinear-lens",category:"camera",name:"Camera, unknown device",projection:"rectilinear",fNumber:8,fNumberRange:{min:2,max:22},exposureSeconds:1/250,exposureRangeSeconds:{min:1/1e3,max:8},apertureBlades:6},{id:"roamer-1-120",category:"camera",name:"Roamer 1, 120 film",projection:"rectilinear",frame:{widthMm:74,heightMm:60,focalLengthMm:100},fNumber:11,exposureSeconds:1/50,years:{from:1930,to:1965},detailUm:40,medium:{kind:"negative",iso:125}},{id:"instamatic-126",category:"camera",name:"Instamatic, 126 film",projection:"rectilinear",frame:{widthMm:28,heightMm:28,focalLengthMm:43},fNumber:11,exposureSeconds:1/90,years:{from:1963,to:1988},apertureBlades:5,detailUm:20,medium:{kind:"negative",iso:64}},{id:"slr-35mm-50",category:"camera",name:"35 mm SLR, 50 mm lens",projection:"rectilinear",frame:{widthMm:36,heightMm:24,focalLengthMm:50},fNumber:8,fNumberRange:{min:2,max:16},exposureSeconds:1/250,exposureRangeSeconds:{min:1/1e3,max:3600},years:{from:1959},apertureBlades:6,detailUm:20,medium:{kind:"negative",iso:100}},{id:"slr-35mm-zoom",category:"camera",name:"35 mm SLR, 70-210 mm zoom",projection:"rectilinear",frame:{widthMm:36,heightMm:24,focalLengthMm:135,focalRangeMm:{minMm:70,maxMm:210}},fNumber:8,fNumberRange:{min:4,max:22},exposureSeconds:1/250,exposureRangeSeconds:{min:1/1e3,max:3600},apertureBlades:8,years:{from:1975},detailUm:20,medium:{kind:"negative",iso:100}},{id:"phone-landscape",category:"phone",name:"Phone, held sideways",projection:"rectilinear",frame:{widthMm:7.6,heightMm:5.7,focalLengthMm:5.7},fNumber:1.8,exposureSeconds:1/120,exposureRangeSeconds:{min:1/8e3,max:10},years:{from:2007},apertureBlades:void 0,detailUm:1.4,medium:{kind:"sensor",iso:100,autoExposure:!0,maxIso:3200,metering:"highlights",development:"computational"}},{id:"phone-portrait",category:"phone",name:"Phone, held upright",projection:"rectilinear",frame:{widthMm:5.7,heightMm:7.6,focalLengthMm:5.7},fNumber:1.8,exposureSeconds:1/120,exposureRangeSeconds:{min:1/8e3,max:10},years:{from:2007},apertureBlades:void 0,detailUm:1.4,medium:{kind:"sensor",iso:100,autoExposure:!0,maxIso:3200,metering:"highlights",development:"computational"}},{id:"dashcam",category:"video",name:"Dashcam",projection:"equidistant",frame:{widthMm:5.76,heightMm:3.24,focalLengthMm:3.2},fNumber:2,exposureSeconds:1/30,exposureRangeSeconds:{min:1/1e4,max:1/30},years:{from:2008},apertureBlades:void 0,detailUm:3,medium:{kind:"sensor",iso:100,autoExposure:!0,maxIso:1600,metering:"average",exposureFollowMs:500}},{id:"cctv",category:"video",name:"Security camera",projection:"rectilinear",frame:{widthMm:4.8,heightMm:3.6,focalLengthMm:3.6},fNumber:2,exposureSeconds:1/50,exposureRangeSeconds:{min:1/1e5,max:1/50},years:{from:1990},apertureBlades:void 0,detailUm:6,medium:{kind:"sensor",iso:100,autoExposure:!0,maxIso:1600,metering:"average",exposureFollowMs:500}},...Yo.instruments(),...Ts.instruments()];class Ii{static get default(){return nl[0]}static byId(t){return nl.find(e=>e.id===t)??this.default}static UNAIDED_FIELD_DEG=60;static UNAIDED_ASPECT=16/9;static fieldOfViewDeg(t){const e=t.frame;return e?Ii.fieldOf(t.projection,e.heightMm,e.focalLengthMm):t.visualAid?.trueFieldDeg??Ii.UNAIDED_FIELD_DEG}static fieldOf(t,e,i){return(t==="equidistant"?e/i:2*Math.atan(e/(2*i)))*180/Math.PI}static aspectOf(t){const e=t.frame;return e?e.widthMm/e.heightMm:Ii.UNAIDED_ASPECT}static frameWidthPx(t,e){return Math.round(e*Ii.aspectOf(t))}static CATEGORIES=["eye","camera","dslr","phone","video","binoculars","telescope"];static unavailability(t,e){const i=t.years;if(!(e===void 0||!i)){if(e<i.from)return{kind:"before",from:i.from};if(i.to!==void 0&&e>i.to)return{kind:"after",to:i.to}}}static availableAt(t){return t===void 0?nl:nl.filter(e=>!e.years||t>=e.years.from&&(e.years.to===void 0||t<=e.years.to))}static fieldOfViewDegAt(t,e){const i=t.frame;if(!(!i||e<=0))return Ii.fieldOf(t.projection,i.heightMm,e)}static focalLengthMmFor(t,e){const i=t.frame;if(!(!i||e<=0||e>=180))return t.projection==="equidistant"?i.heightMm/(e*Math.PI/180):i.heightMm/(2*Math.tan(e*Math.PI/360))}static bladesShowing(t,e){if(t.apertureBlades===void 0)return 0;const i=e??t.fNumber,n=t.fNumberRange?.min;if(i===void 0||n===void 0)return 1;const s=Math.max(0,Math.min(1,(i/n-1)/.3));return s*s*(3-2*s)}static starPointsOf(t,e){const i=t.apertureBlades;return i===void 0||i<3||Ii.bladesShowing(t,e)<.5?0:i%2===0?i:i*2}}class hc{constructor(t){this.points=t}static STATIONARY_M=5;static of(t){const e=[];for(const i of t.observerTrack.allKeyframes){const{lat:n,lng:s,headingDeg:a}=i.pose;n===void 0||s===void 0||e.push({t:i.t,lat:n,lng:s,headingDeg:a})}if(e.length===0){const i=t.event.place?.[0];if(!i)return;e.push({t:0,lat:i.lat,lng:i.lng})}return new hc(e)}static TRAVEL_M=50;get travels(){return this.spanM>hc.TRAVEL_M}get moved(){return this.spanM>hc.STATIONARY_M}get spanM(){const t=this.box,e=(t.south+t.north)/2,i=(t.west+t.east)/2;return Math.max(Math.abs(ae(e,t.east,e,t.west).x),Math.abs(ae(t.north,i,t.south,i).z))}get center(){const t=this.box;return{lat:(t.south+t.north)/2,lng:(t.west+t.east)/2}}boundsAround(t,e){const{lat:i,lng:n}=this.center,s=Math.max(this.spanM*(1+e),t)/2;return{north:Kn(0,-s,i,n).lat,south:Kn(0,s,i,n).lat,east:Kn(s,0,i,n).lng,west:Kn(-s,0,i,n).lng}}get box(){const t=this.points.map(i=>i.lat),e=this.points.map(i=>i.lng);return{south:Math.min(...t),north:Math.max(...t),west:Math.min(...e),east:Math.max(...e)}}}class ds{constructor(t,e){this.rotationPassed=t,this.scale=e}static SWAY_M=.012;static BREATH_M=.003;static DRIFT_YAW_DEG=.5;static DRIFT_PITCH_DEG=.4;static DRIFT_ROLL_DEG=.3;static GAZE_DRIFT_SHARE=.35;static HAND_HELD_S=.5;static HZ=[.11,.23,.17,.29,.37,.07];static of(t){const e=t.event.tags?.includes("paralysis")||(t.exposure??0)>ds.HAND_HELD_S,i=t.sway??(e?0:1);if(i>0)return new ds(Math.max(1-(t.instrument.stabilization??0),ds.GAZE_DRIFT_SHARE),i)}offsetAt(t){const e=t/1e3,i=this.scale,n=(u,d)=>Math.sin(2*Math.PI*u*e+d),[s,a,r,c,h,l]=ds.HZ;return{eastM:i*ds.SWAY_M*(.7*n(s,.3)+.3*n(c,1.9)),northM:i*ds.SWAY_M*(.6*n(r,2.2)+.4*n(h,.8)),upM:i*ds.BREATH_M*n(a,0),yawDeg:i*this.rotationPassed*ds.DRIFT_YAW_DEG*(.6*n(l,1.1)+.4*n(c,2.7)),pitchDeg:i*this.rotationPassed*ds.DRIFT_PITCH_DEG*(.5*n(a,1.6)+.5*n(r,.4)),rollDeg:i*this.rotationPassed*ds.DRIFT_ROLL_DEG*n(s,2.9)}}}class Ye{constructor(t,e){this.stretches=t,this.rotationPassed=e}static REFERENCE_SPEED_M_PER_S=1.4;static REFERENCE_STEP_HZ=1.9;static CADENCE_EXPONENT=.43;static RISE_M_PER_M_PER_S=.0175;static SWAY_M=.0175;static SLOWEST_WALK_M_PER_S=.2;static FASTEST_WALK_M_PER_S=2.2;static HEAD_ROLL_DEG=1.5;static HEAD_PITCH_DEG=1.25;static HEAD_YAW_DEG=1;static STOP_LURCH_M=.035;static STOP_PITCH_DEG=3;static START_LURCH_M=.015;static START_PITCH_DEG=1.2;static JOLT_HZ=1.4;static JOLT_DECAY_S=.35;static JOLT_LASTS_MS=1500;static STILL=Object.freeze({eastM:0,northM:0,upM:0,rollDeg:0,pitchDeg:0,yawDeg:0});static of(t){const e=hc.of(t);if(!e||e.points.length<2)return;const i=[];let n=0;for(let s=1;s<e.points.length;s++){const a=e.points[s-1],r=e.points[s],c=(r.t-a.t)/1e3;if(c<=0)continue;const h=ae(r.lat,r.lng,a.lat,a.lng),l=h.x,u=-h.z,d=Math.hypot(l,u),f=d/c,p=Ye.stepHzFor(f);i.push({startMs:a.t,endMs:r.t,speedMPerS:f,eastUnit:d>0?l/d:0,northUnit:d>0?u/d:0,stepHz:p,stepsBefore:n,rampsIn:!0,rampsOut:!0}),n+=p*c}for(let s=0;s<i.length;s++){const a=i[s-1],r=i[s+1];i[s].rampsIn=a===void 0||a.stepHz===0,i[s].rampsOut=r===void 0||r.stepHz===0}if(i.some(s=>s.stepHz>0))return new Ye(i,1-(t.instrument.stabilization??0))}static bodyAt(t,e,i=!1){const n=Ye.of(t)?.offsetAt(e)??Ye.STILL;return i?n:Ye.add(n,ds.of(t)?.offsetAt(e))}static stepHzFor(t){return t<Ye.SLOWEST_WALK_M_PER_S||t>Ye.FASTEST_WALK_M_PER_S?0:Ye.REFERENCE_STEP_HZ*Math.pow(t/Ye.REFERENCE_SPEED_M_PER_S,Ye.CADENCE_EXPONENT)}offsetAt(t){return Ye.add(this.cycleAt(t),this.joltAt(t))}joltAt(t){for(const e of this.stretches){if(e.stepHz===0)continue;const i=e.speedMPerS/Ye.REFERENCE_SPEED_M_PER_S,n=(r,c,h,l)=>{if(r<0||r>Ye.JOLT_LASTS_MS)return;const u=r/1e3,d=Math.exp(-u/Ye.JOLT_DECAY_S)*Math.sin(2*Math.PI*Ye.JOLT_HZ*u),f=l*c*i*d;return{eastM:f*e.eastUnit,northM:f*e.northUnit,upM:-Math.abs(f)*.3,rollDeg:0,pitchDeg:-l*h*i*d*this.rotationPassed,yawDeg:0}},s=e.rampsOut?n(t-e.endMs,Ye.STOP_LURCH_M,Ye.STOP_PITCH_DEG,1):void 0;if(s)return s;const a=e.rampsIn?n(t-e.startMs,Ye.START_LURCH_M,Ye.START_PITCH_DEG,-1):void 0;if(a)return a}}static add(t,e){return e?{eastM:t.eastM+e.eastM,northM:t.northM+e.northM,upM:t.upM+e.upM,rollDeg:t.rollDeg+e.rollDeg,pitchDeg:t.pitchDeg+e.pitchDeg,yawDeg:t.yawDeg+e.yawDeg}:t}cycleAt(t){const e=this.stretches.find(c=>t>=c.startMs&&t<=c.endMs);if(!e||e.stepHz===0)return Ye.STILL;const i=e.stepsBefore+e.stepHz*(t-e.startMs)/1e3,n=2*Math.PI*i,s=this.amplitudeAt(e,t),a=Ye.SWAY_M*s*Math.cos(n/2),r=s*this.rotationPassed*e.speedMPerS/Ye.REFERENCE_SPEED_M_PER_S;return{eastM:a*e.northUnit,northM:-a*e.eastUnit,upM:Ye.RISE_M_PER_M_PER_S*e.speedMPerS*s*Math.cos(n),rollDeg:Ye.HEAD_ROLL_DEG*r*Math.cos(n/2),pitchDeg:-1.25*r*Math.cos(n),yawDeg:Ye.HEAD_YAW_DEG*r*Math.cos(n/2)}}amplitudeAt(t,e){const i=1e3/t.stepHz,n=Math.min(i,(t.endMs-t.startMs)/2);if(n<=0)return 1;const s=e-t.startMs,a=t.endMs-e,r=Math.min(t.rampsIn?s/n:1,t.rampsOut?a/n:1,1);return(1-Math.cos(Math.PI*Math.max(r,0)))/2}}class dh{static ISO=/^P(?:(\d+(?:[.,]\d+)?)W)?(?:(\d+(?:[.,]\d+)?)D)?(?:T(?:(\d+(?:[.,]\d+)?)H)?(?:(\d+(?:[.,]\d+)?)M)?(?:(\d+(?:[.,]\d+)?)S)?)?$/;static seconds(t){const e=t.trim().toUpperCase(),i=dh.ISO.exec(e);if(!i||e==="P"||e.endsWith("T"))return;const[,n,s,a,r,c]=i,h=u=>u===void 0?0:Number(u.replace(",",".")),l=h(n)*604800+h(s)*86400+h(a)*3600+h(r)*60+h(c);return Number.isFinite(l)?l:void 0}static parse(t){let e=t.trim();if(e==="")return;const i=e.slice(-1),n="?~%".includes(i)?i:"";n!==""&&(e=e.slice(0,-1).trim());const s=e.split("/");if(s.length>2)return;const a=s.map(u=>dh.seconds(u));if(a.some(u=>u===void 0))return;const[r,c]=a,h=Math.min(r,c??r),l=Math.max(r,c??r);return{doubt:n,minSeconds:h,maxSeconds:l,chosenSeconds:(h+l)/2}}static isExact(t){const e=dh.parse(t);return e!==void 0&&e.doubt===""&&e.minSeconds===e.maxSeconds}static format(t){const e=Math.max(0,Math.round(t*10)/10),i=Math.floor(e/3600),n=Math.floor(e%3600/60),s=Math.round(e%60*10)/10;return`PT${`${i>0?`${i}H`:""}${n>0?`${n}M`:""}${s>0||i===0&&n===0?`${s}S`:""}`}`}static say(t){const e=Math.round(t*10)/10;if(e<60)return`${e} s`;const i=Math.floor(e/3600),n=Math.floor(e%3600/60),s=Math.round(e%60*10)/10,a=[];return i>0&&a.push(`${i} h`),n>0&&a.push(`${n} min`),s>0&&a.push(`${s} s`),a.join(" ")}}class Ze{static MOON_ANGULAR_WIDTH_DEG=.5237;static CANVAS_WIDTH_PX=640;static CANVAS_HEIGHT_PX=360;static angularWidthDeg(t){return 2*Math.atan(t.sizeM/(2*t.distanceM))*180/Math.PI}static inMoons(t){return t/Ze.MOON_ANGULAR_WIDTH_DEG}static lerpAngular(t,e,i){if(!(!t||!e))return{widthDeg:t.widthDeg+(e.widthDeg-t.widthDeg)*i,heightDeg:t.heightDeg+(e.heightDeg-t.heightDeg)*i}}static sizeMAt(t,e){return 2*t*Math.tan(e*Math.PI/360)}static distanceMAt(t,e){return t/(2*Math.tan(e*Math.PI/360))}}function jy(o,t,e){if(!o||!t)return e<1?o:t;const i=((t.azimuthDeg-o.azimuthDeg)%360+540)%360-180;return{azimuthDeg:((o.azimuthDeg+i*e)%360+360)%360,altitudeDeg:o.altitudeDeg+(t.altitudeDeg-o.altitudeDeg)*e}}function Qy(o,t,e){const{bounds:i}=o;return t>=i.x&&t<=i.x+i.width&&e>=i.y&&e<=i.y+i.height}function Vn(o,t,e){return o+(t-o)*e}function Zm(o){const t=/^#([0-9a-f]{6})$/i.exec(o);if(!t)return;const e=parseInt(t[1],16);return[e>>16&255,e>>8&255,e&255]}function tx(o){return`#${o.map(t=>Math.round(t).toString(16).padStart(2,"0")).join("")}`}function ex(o,t,e){const i=Zm(o),n=Zm(t);return!i||!n?e<1?o:t:tx([Vn(i[0],n[0],e),Vn(i[1],n[1],e),Vn(i[2],n[2],e)])}function ix(o,t,e){const i={x:Vn(o.bounds.x,t.bounds.x,e),y:Vn(o.bounds.y,t.bounds.y,e),width:Vn(o.bounds.width,t.bounds.width,e),height:Vn(o.bounds.height,t.bounds.height,e)},n=Vn(o.angle,t.angle,e),s=Vn(o.transparency,t.transparency,e),a=Vn(o.haloScale,t.haloScale,e),r=Vn(o.blur??0,t.blur??0,e),c=Vn(o.brightness??0,t.brightness??0,e),h=ex(o.color,t.color,e),l=Ze.lerpAngular(o.angular,t.angular,e),u=jy(o.aim,t.aim,e);return o.kind==="polygon"&&t.kind==="polygon"&&o.points.length===t.points.length?{...o,bounds:i,angle:n,transparency:s,haloScale:a,blur:r,brightness:c,color:h,angular:l,aim:u,points:o.points.map((d,f)=>({x:Vn(d.x,t.points[f].x,e),y:Vn(d.y,t.points[f].y,e)}))}:{...e<1?o:t,bounds:i,angle:n,transparency:s,haloScale:a,blur:r,brightness:c,color:h,angular:l,aim:u}}class ir{static DEFAULT_COLOR="#e8e6df";static complete(t,e=[]){const i=new Map;return t.map((n,s)=>({keyframe:n,index:s})).sort((n,s)=>n.keyframe.t-s.keyframe.t).map(({keyframe:n,index:s})=>({t:n.t,shapes:(n.shapes??[]).map((a,r)=>{const c=`timeline.keyframes.${s}.shapes.${r}.shape`,h=ir.completed(a,i.get(a.sourceId),c,e);return i.set(a.sourceId,h),{sourceId:a.sourceId,shape:h}})}))}static thin(t,e){const i=new Map,n=new Set;return t.map((s,a)=>({t:s.t,shapes:s.shapes.map(r=>{const c=i.get(r.sourceId);if(i.set(r.sourceId,r.shape),!c)return{sourceId:r.sourceId,shape:r.shape};const h=ir.thinned(r.shape,c);if(e){const l=h;e(a,r.sourceId)?(delete l.bounds,delete l.points,n.add(r.sourceId)):n.delete(r.sourceId)&&(l.bounds=r.shape.bounds,r.shape.kind==="polygon"&&(l.points=r.shape.points),r.shape.aim&&(l.aim=r.shape.aim),r.shape.angular&&(l.angular=r.shape.angular))}return{sourceId:r.sourceId,shape:h}})}))}static thinned(t,e){const i=e,n={};for(const[s,a]of Object.entries(t))(typeof a=="object"&&a!==null&&!Array.isArray(a)&&"value"in a||a!==i[s]&&JSON.stringify(a)!==JSON.stringify(i[s]))&&(n[s]=a);return"bounds"in n&&(t.aim&&(n.aim=t.aim),t.angular&&(n.angular=t.angular)),n}static completed(t,e,i,n){const s=t.shape??{},a=e??ir.firstAppearance(s,i,n),r={...a};s.bounds&&e&&(e.aim||e.angular)&&!s.aim&&!s.angular&&n.push({kind:"pixels-over-angles",path:i}),s.bounds&&(s.aim||delete r.aim,s.angular||delete r.angular);const c=s.kind??a.kind??"oval",h={...r,...s,kind:c};if(c==="polygon"&&!h.points){n.push({kind:"defaulted",path:`${i}.points`,expected:"rectangle"});const{width:l,height:u}=h.bounds;return{...h,points:[{x:0,y:0},{x:l,y:0},{x:l,y:u},{x:0,y:u}]}}return h}static firstAppearance(t,e,i){return t.kind||i.push({kind:"defaulted",path:`${e}.kind`,expected:'"oval"'}),t.color||i.push({kind:"defaulted",path:`${e}.color`,expected:`"${ir.DEFAULT_COLOR}"`}),!t.bounds&&!t.aim&&i.push({kind:"unplaced",path:e}),!t.bounds&&!t.angular&&i.push({kind:"unsized",path:e}),{kind:t.kind??"oval",bounds:{...ir.NEUTRAL_BOUNDS},color:ir.DEFAULT_COLOR,angle:0,transparency:0,haloScale:0,selected:!1}}static NEUTRAL_BOUNDS={x:Ze.CANVAS_WIDTH_PX/2,y:Ze.CANVAS_HEIGHT_PX/2,width:1,height:1}}class od{keyframes=[];order=[];groups=[];span=0;addKeyframe(t,e){const i=this.findInsertIndex(t);if(this.keyframes[i]?.t===t){const n=new Set(e.map(s=>s.sourceId));this.keyframes[i]={t,shapes:[...this.keyframes[i].shapes.filter(s=>!n.has(s.sourceId)),...e]}}else this.keyframes.splice(i,0,{t,shapes:[...e]});for(const n of e)this.order.includes(n.sourceId)||this.order.push(n.sourceId)}findInsertIndex(t){let e=0,i=this.keyframes.length;for(;e<i;){const n=e+i>>>1;this.keyframes[n].t<t?e=n+1:i=n}return e}getKeyframeAt(t){const e=this.findInsertIndex(t),i=this.keyframes[e];return i?.t===t?i:void 0}getShapeAt(t,e){return this.getKeyframeAt(t)?.shapes.find(i=>i.sourceId===e)?.shape}getLatestShapeAt(t,e){let i=this.findInsertIndex(t);for(this.keyframes[i]?.t!==t&&(i-=1);i>=0;i--){const n=this.keyframes[i].shapes.find(s=>s.sourceId===e);if(n)return n.shape}}getInterpolatedShapeAt(t,e){const i=this.findShapeAtOrBefore(t,e);if(i?.t===t)return i.shape;const n=this.findShapeAtOrAfter(t,e);return i?n?ix(i.shape,n.shape,(t-i.t)/(n.t-i.t)):i.shape:n?.shape}findShapeAtOrBefore(t,e){let i=this.findInsertIndex(t);for(this.keyframes[i]?.t!==t&&(i-=1);i>=0;i--){const n=this.keyframes[i].shapes.find(s=>s.sourceId===e);if(n)return{t:this.keyframes[i].t,shape:n.shape}}}findShapeAtOrAfter(t,e){for(let i=this.findInsertIndex(t);i<this.keyframes.length;i++){const n=this.keyframes[i].shapes.find(s=>s.sourceId===e);if(n)return{t:this.keyframes[i].t,shape:n.shape}}}hitTest(t,e,i,n){const s=this.sourceIds;for(let a=s.length-1;a>=0;a--){if(n?.has(s[a]))continue;const r=this.getInterpolatedShapeAt(t,s[a]);if(r&&Qy(r,e,i))return{sourceId:s[a],shape:r}}}removeSource(t){for(let e=this.keyframes.length-1;e>=0;e--){const i=this.keyframes[e].shapes.filter(n=>n.sourceId!==t);i.length===0?this.keyframes.splice(e,1):i.length!==this.keyframes[e].shapes.length&&(this.keyframes[e]={t:this.keyframes[e].t,shapes:i})}this.order=this.order.filter(e=>e!==t),this.removeFromGroup(t)}removeShapeAt(t,e){const i=this.findInsertIndex(t),n=this.keyframes[i];if(n?.t!==t)return;const s=n.shapes.filter(a=>a.sourceId!==e);s.length===0?this.keyframes.splice(i,1):s.length!==n.shapes.length&&(this.keyframes[i]={t,shapes:s})}group(t){if(!(t.length<2)){for(const e of t)this.removeFromGroup(e);this.groups.push([...t])}}ungroup(t){const e=this.groups.findIndex(i=>i.includes(t));e!==-1&&this.groups.splice(e,1)}groupMembers(t){return this.groups.find(e=>e.includes(t))}removeFromGroup(t){const e=this.groups.findIndex(n=>n.includes(t));if(e===-1)return;const i=this.groups[e].filter(n=>n!==t);i.length<2?this.groups.splice(e,1):this.groups[e]=i}bringToFront(t){const e=this.order.indexOf(t);e!==-1&&(this.order.splice(e,1),this.order.push(t))}sendToBack(t){const e=this.order.indexOf(t);e!==-1&&(this.order.splice(e,1),this.order.unshift(t))}get duration(){const t=this.keyframes.length===0?0:this.keyframes[this.keyframes.length-1].t;return Math.max(t,this.span)}get hasSpan(){return this.span>0}setSpan(t){this.span=Math.max(0,t)}get sourceIds(){return[...this.order]}get allKeyframes(){return this.keyframes}toJSON(){return this.span>0?{keyframes:this.keyframes,order:this.order,groups:this.groups,span:this.span}:{keyframes:this.keyframes,order:this.order,groups:this.groups}}static fromJSON(t,e){const i=new od;for(const n of ir.complete(t.keyframes??[],e))i.addKeyframe(n.t,n.shapes);if(t.span!==void 0&&t.span>0&&(i.span=t.span),t.order){const n=i.order.filter(s=>!t.order.includes(s));i.order=[...t.order,...n]}return t.groups&&(i.groups=t.groups.map(n=>n.filter(s=>i.order.includes(s))).filter(n=>n.length>=2)),i}}function nx(o,t,e){return Math.max(t,Math.min(e,o))}function sx(o,t,e){const i=((t-o)%360+540)%360-180;return((o+i*e)%360+360)%360}function po(o,t,e){return o+(t-o)*e}function ax(o,t,e){return{lat:o.lat===void 0||t.lat===void 0?void 0:po(o.lat,t.lat,e),lng:o.lng===void 0||t.lng===void 0?void 0:po(o.lng,t.lng,e),elevationM:po(o.elevationM,t.elevationM,e),headingDeg:o.headingDeg===void 0||t.headingDeg===void 0?void 0:sx(o.headingDeg,t.headingDeg,e),pitchDeg:po(o.pitchDeg,t.pitchDeg,e),rollDeg:po(o.rollDeg??0,t.rollDeg??0,e),fovDeg:po(o.fovDeg,t.fovDeg,e),fNumber:o.fNumber,focusDistanceM:o.focusDistanceM,filter:o.filter}}class vn{static at(t,e,i,n,s){const a=t[i],c=t[i+1]-a;if(c<=0)return e[i];const h=vn.tangent(t,e,i,s),l=vn.tangent(t,e,i+1,s),u=(n-a)/c,d=u*u,f=d*u;return(2*f-3*d+1)*e[i]+(f-2*d+u)*c*h+(-2*f+3*d)*e[i+1]+(f-d)*c*l}static SETTLE_MS=120;static ARRIVAL=.5;static gaze(t,e,i,n){const s=t[i],r=t[i+1]-s;if(r<=0)return e[i];const c=l=>l+1<e.length?e[l+1]===e[l]:!0,h=e[i+1]!==e[i];if(h&&c(i+1)){const l=vn.tangent(t,e,i,!0),u=vn.ARRIVAL*(e[i+1]-e[i])/r;return vn.hermite(e[i],l,e[i+1],u,r,(n-s)/r)}return!h&&i>0&&e[i-1]!==e[i]?e[i]+vn.settle(t,e,i,n-s,r):vn.at(t,e,i,n,!0)}static settle(t,e,i,n,s){const a=t[i]-t[i-1];if(a<=0||n<=0)return 0;const r=vn.ARRIVAL*(e[i]-e[i-1])/a,c=Math.min(vn.SETTLE_MS,.4*a),h=Number.isFinite(s)?(1-Math.min(1,n/s))**2:1;return r*n*Math.exp(-n/c)*h}static hermite(t,e,i,n,s,a){const r=a*a,c=r*a;return(2*c-3*r+1)*t+(c-2*r+a)*s*e+(-2*c+3*r)*i+(c-r)*s*n}static BRAKE_S=.8;static paced(t,e,i,n){if(!i&&!n)return t;const s=e>0?Math.min(.5,vn.BRAKE_S/e):.5;if(i&&n){const r=1/(1-s);return t<=s?r*t*t/(2*s):t>=1-s?1-r*(1-t)*(1-t)/(2*s):r*(t-s/2)}const a=r=>{const c=1/(1-s/2);if(r<=1-s)return c*r;const h=r-(1-s);return c*(1-s)+c*(h-h*h/(2*s))};return n?a(t):1-a(1-t)}static tangent(t,e,i,n){const s=t.length-1,a=f=>(e[f+1]-e[f])/(t[f+1]-t[f]||1);if(i===0)return n?0:a(0);if(i===s)return n?0:a(s-1);const r=a(i-1),c=a(i);if(r*c<=0)return 0;const h=t[i]-t[i-1],l=t[i+1]-t[i],u=2*l+h,d=l+2*h;return(u+d)/(u/r+d/c)}}class Nh{keyframes=[];addKeyframe(t,e){const i=this.findInsertIndex(t);this.keyframes[i]?.t===t?this.keyframes[i]={t,pose:e}:this.keyframes.splice(i,0,{t,pose:e})}clear(){this.keyframes.length=0}removeKeyframeAt(t){const e=this.findInsertIndex(t);this.keyframes[e]?.t===t&&this.keyframes.splice(e,1)}findInsertIndex(t){let e=0,i=this.keyframes.length;for(;e<i;){const n=e+i>>>1;this.keyframes[n].t<t?e=n+1:i=n}return e}getLatestPoseAt(t){let e=this.findInsertIndex(t);return this.keyframes[e]?.t!==t&&(e-=1),e>=0?this.keyframes[e].pose:void 0}getInterpolatedPoseAt(t){const e=this.findInsertIndex(t),i=this.keyframes[e]?.t===t?this.keyframes[e]:this.keyframes[e-1];if(i?.t===t)return i.pose;const n=this.keyframes[e]?.t===t?void 0:this.keyframes[e];if(!i)return n?.pose;if(!n)return this.settledAfterEnd(e-1,t);const s=ax(i.pose,n.pose,nx((t-i.t)/(n.t-i.t),0,1));return this.humanly(e-1,t,s)}settledAfterEnd(t,e){const i=this.keyframes[t];if(t<1)return i.pose;const n=this.keyframes[t-1],s=[n.t,i.t],a=(l,u)=>l===void 0||u===void 0?0:vn.settle(s,[l,u],1,e-i.t,1/0),r=n.pose.headingDeg===void 0||i.pose.headingDeg===void 0?void 0:((i.pose.headingDeg-n.pose.headingDeg)%360+540)%360-180,c=i.pose.headingDeg===void 0||r===void 0?i.pose.headingDeg:((i.pose.headingDeg+a(0,r))%360+360)%360,h=i.pose.pitchDeg+a(n.pose.pitchDeg,i.pose.pitchDeg);return c===i.pose.headingDeg&&h===i.pose.pitchDeg?i.pose:{...i.pose,headingDeg:c,pitchDeg:h}}humanly(t,e,i){const n=Math.max(0,t-1),s=Math.min(this.keyframes.length-1,t+2),a=this.keyframes.slice(n,s+1),r=t-n,c=a.map(v=>v.t),h=(v,w)=>{const b=a.map(_=>v(_.pose));if(!b.some(_=>_===void 0))return vn.at(c,b,r,e,w)},l=v=>{const w=a.map(b=>v(b.pose));if(!w.some(b=>b===void 0))return vn.gaze(c,w,r,e)},u=a.map(v=>v.pose.headingDeg);let d;if(u.every(v=>v!==void 0)){const v=[u[0]];for(let w=1;w<u.length;w++)v.push(v[w-1]+((u[w]-u[w-1])%360+540)%360-180);d=(vn.gaze(c,v,r,e)%360+360)%360}const f=this.keyframes[t],p=this.keyframes[t+1],g=(v,w)=>v.lat===w.lat&&v.lng===w.lng&&v.elevationM===w.elevationM,m=!g(f.pose,p.pose),M=m&&t>0&&g(this.keyframes[t-1].pose,f.pose),y=m&&t+2<this.keyframes.length&&g(p.pose,this.keyframes[t+2].pose);let x;if(M||y){const v=vn.paced((e-f.t)/(p.t-f.t),(p.t-f.t)/1e3,M,y),w=(b,_)=>b===void 0||_===void 0?void 0:b+(_-b)*v;x={lat:w(f.pose.lat,p.pose.lat),lng:w(f.pose.lng,p.pose.lng),elevationM:w(f.pose.elevationM,p.pose.elevationM)}}return{...i,lat:x?x.lat:h(v=>v.lat,!1)??i.lat,lng:x?x.lng:h(v=>v.lng,!1)??i.lng,elevationM:x?x.elevationM:h(v=>v.elevationM,!1)??i.elevationM,headingDeg:d??i.headingDeg,pitchDeg:l(v=>v.pitchDeg)??i.pitchDeg,rollDeg:h(v=>v.rollDeg??0,!0)??i.rollDeg,fovDeg:h(v=>v.fovDeg,!0)??i.fovDeg}}get duration(){return this.keyframes.length===0?0:this.keyframes[this.keyframes.length-1].t}get allKeyframes(){return this.keyframes}toJSON(){return{keyframes:this.keyframes}}static fromJSON(t){const e=new Nh;for(const i of t.keyframes)e.addKeyframe(i.t,i.pose);return e}}class nr{static MAX_CHANGE_PER_S=.05;points;followed;constructor(t){let e="none",i=0;this.points=t.map(({t:n,weather:s})=>(s.precipitationType!=="none"&&(e=s.precipitationType,i=s.precipitationIntensity),{t:n,lastFalling:e,lastFallingIntensity:i,intensity:s.precipitationType==="none"?0:s.precipitationIntensity,type:s.precipitationType})),this.followed=[];for(let n=0;n<this.points.length;n++){if(n===0){this.followed.push(this.points[0].intensity);continue}const s=this.points[n-1],a=this.points[n];this.followed.push(nr.follow(this.followed[n-1],s.intensity,a.intensity,(a.t-s.t)/1e3,(a.t-s.t)/1e3))}}at(t){if(this.points.length===0||t<this.points[0].t)return;let e=this.points.length-1;for(;e>0&&this.points[e].t>t;)e--;const i=this.points[e],n=this.points[e+1],s=n?nr.follow(this.followed[e],i.intensity,n.intensity,(n.t-i.t)/1e3,(t-i.t)/1e3):nr.follow(this.followed[e],i.intensity,i.intensity,1,(t-i.t)/1e3);return{type:nr.typeBetween(i,n,t,s),intensity:s,character:nr.characterBetween(i,n,t)}}static characterBetween(t,e,i){return t.type==="none"?e&&e.type!=="none"?e.intensity:t.lastFallingIntensity:!e||e.type==="none"?t.intensity:t.intensity+(e.intensity-t.intensity)*(i-t.t)/(e.t-t.t||1)}static typeBetween(t,e,i,n){return t.type==="none"?e&&e.type!=="none"&&i>t.t?e.type:n>0?t.lastFalling:"none":e&&e.type==="none"&&n<=0?"none":t.type}static follow(t,e,i,n,s){const a=nr.MAX_CHANGE_PER_S,r=n>0?(i-e)/n:0,c=u=>e+r*Math.min(Math.max(u,0),n);let h=t,l=0;for(let u=0;u<8&&l<s;u++){const d=c(l)-h;if(Math.abs(d)<1e-9){const x=l<n?r:0;if(Math.abs(x)<=a){const w=l<n?Math.min(s,n):s;h=c(w),l=w;continue}const v=Math.min(s,n);h+=Math.sign(x)*a*(v-l),l=v;continue}const f=Math.sign(d),p=l<n?r:0,g=a-f*p,m=g>0?l+Math.abs(d)/g:1/0,M=l<n?n:1/0,y=Math.min(s,m,M);h+=f*a*(y-l),l=y,y===m&&(h=c(l))}return Math.min(1,Math.max(0,h))}}function ui(o,t,e){return o+(t-o)*e}function Fp(o,t,e){const i=((t-o)%360+540)%360-180;return((o+i*e)%360+360)%360}function rx(o,t,e){return Math.max(t,Math.min(e,o))}function ox(o=[],t=[],e){if(!(!o.length&&!t.length))return[...new Set([...o.map(i=>i.id),...t.map(i=>i.id)])].map(i=>{const n=o.find(c=>c.id===i),s=t.find(c=>c.id===i),a=n??{...s,density:0},r=s??{...n,density:0};return{...a,eastM:ui(a.eastM,r.eastM,e),northM:ui(a.northM,r.northM,e),baseM:ui(a.baseM,r.baseM,e),thicknessM:ui(a.thicknessM,r.thicknessM,e),widthM:ui(a.widthM,r.widthM,e),depthM:ui(a.depthM,r.depthM,e),rotationDeg:Fp(a.rotationDeg,r.rotationDeg,e),density:ui(a.density,r.density,e),darkness:ui(a.darkness??0,r.darkness??0,e)}})}function cx(o,t,e){if(o.cloudLayers===void 0&&t.cloudLayers===void 0)return;const i=Tu(o),n=Tu(t);return e>=1?n.map(a=>({...a})):[...new Set([...i.map(a=>a.id),...n.map(a=>a.id)])].map(a=>{const r=i.find(u=>u.id===a),c=n.find(u=>u.id===a),h=r??{...c,coverage:0},l=c??{...r,coverage:0};return{...h,instances:ox(r?.instances,c?.instances,e),baseM:ui(h.baseM,l.baseM,e),thicknessM:ui(h.thicknessM,l.thicknessM,e),coverage:ui(h.coverage,l.coverage,e),sizeM:ui(h.sizeM,l.sizeM,e),density:ui(h.density,l.density,e),darkness:ui(h.darkness??o.cloudDarkness,l.darkness??t.cloudDarkness,e),iceCrystalAlignment:h.iceCrystalAlignment===void 0||l.iceCrystalAlignment===void 0?void 0:ui(h.iceCrystalAlignment,l.iceCrystalAlignment,e),windSpeed:h.windSpeed===void 0&&l.windSpeed===void 0?void 0:ui(h.windSpeed??o.windSpeed,l.windSpeed??t.windSpeed,e),windDirectionDeg:h.windDirectionDeg===void 0&&l.windDirectionDeg===void 0?void 0:Fp(h.windDirectionDeg??o.windDirectionDeg,l.windDirectionDeg??t.windDirectionDeg,e)}})}function hx(o,t,e){return{cloudLayers:cx(o,t,e),cloudCover:ui(o.cloudCover,t.cloudCover,e),cloudDarkness:ui(o.cloudDarkness,t.cloudDarkness,e),highCloudCover:o.highCloudCover===void 0||t.highCloudCover===void 0?void 0:ui(o.highCloudCover,t.highCloudCover,e),iceCrystalAlignment:o.iceCrystalAlignment===void 0||t.iceCrystalAlignment===void 0?void 0:ui(o.iceCrystalAlignment,t.iceCrystalAlignment,e),rareIceCrystals:o.rareIceCrystals===void 0||t.rareIceCrystals===void 0?void 0:ui(o.rareIceCrystals,t.rareIceCrystals,e),lowerCloudCover:o.lowerCloudCover===void 0||t.lowerCloudCover===void 0?void 0:ui(o.lowerCloudCover,t.lowerCloudCover,e),cloudBaseM:o.cloudBaseM===void 0||t.cloudBaseM===void 0?void 0:ui(o.cloudBaseM,t.cloudBaseM,e),relativeHumidity:o.relativeHumidity===void 0||t.relativeHumidity===void 0?void 0:ui(o.relativeHumidity,t.relativeHumidity,e),precipitationType:e<1?o.precipitationType:t.precipitationType,precipitationIntensity:ui(o.precipitationIntensity,t.precipitationIntensity,e),windDirectionDeg:Fp(o.windDirectionDeg,t.windDirectionDeg,e),windSpeed:ui(o.windSpeed,t.windSpeed,e),storm:e<1?o.storm:t.storm}}class Uh{keyframes=[];ramp;addKeyframe(t,e){this.ramp=void 0;const i=this.findInsertIndex(t);this.keyframes[i]?.t===t?this.keyframes[i]={t,weather:e}:this.keyframes.splice(i,0,{t,weather:e})}clear(){this.ramp=void 0,this.keyframes.length=0}removeKeyframeAt(t){this.ramp=void 0;const e=this.findInsertIndex(t);this.keyframes[e]?.t===t&&this.keyframes.splice(e,1)}findInsertIndex(t){let e=0,i=this.keyframes.length;for(;e<i;){const n=e+i>>>1;this.keyframes[n].t<t?e=n+1:i=n}return e}getLatestWeatherAt(t){let e=this.findInsertIndex(t);return this.keyframes[e]?.t!==t&&(e-=1),e>=0?this.keyframes[e].weather:void 0}getInterpolatedWeatherAt(t){const e=this.findInsertIndex(t),i=this.keyframes[e]?.t===t?this.keyframes[e]:this.keyframes[e-1];if(i?.t===t)return i.weather;const n=this.keyframes[e]?.t===t?void 0:this.keyframes[e];return i?n?hx(i.weather,n.weather,rx((t-i.t)/(n.t-i.t),0,1)):i.weather:n?.weather}getActualWeatherAt(t){const e=this.getInterpolatedWeatherAt(t);if(!e)return;const i=(this.ramp??=new nr(this.keyframes)).at(t);if(!i)return e;const{type:n,intensity:s,character:a}=i,r=a>0?Math.min(1,s/a):n==="none"?0:1;return{...e,precipitationType:n,precipitationIntensity:a,precipitationAmount:r}}get duration(){return this.keyframes.length===0?0:this.keyframes[this.keyframes.length-1].t}get allKeyframes(){return this.keyframes}toJSON(){return{keyframes:this.keyframes}}static fromJSON(t){const e=new Uh;for(const i of t.keyframes)e.addKeyframe(i.t,{...rd,...i.weather});return e}}class kh{keyframes=[];addKeyframe(t,e){const i=this.findInsertIndex(t);this.keyframes[i]?.t===t?this.keyframes[i]={t,sound:e}:this.keyframes.splice(i,0,{t,sound:e})}clear(){this.keyframes.length=0}removeKeyframeAt(t){const e=this.findInsertIndex(t);this.keyframes[e]?.t===t&&this.keyframes.splice(e,1)}getLatestSoundAt(t){let e=this.findInsertIndex(t);return this.keyframes[e]?.t!==t&&(e-=1),e>=0?this.keyframes[e].sound:void 0}getInterpolatedSoundAt(t){const e=this.findInsertIndex(t),i=this.keyframes[e]?.t===t?this.keyframes[e]:this.keyframes[e-1];if(i?.t===t)return i.sound;const n=this.keyframes[e]?.t===t?void 0:this.keyframes[e];if(!i)return n?.sound;if(!n)return i.sound;const s=(t-i.t)/(n.t-i.t);return this.lerp(i.sound,n.sound,Math.max(0,Math.min(1,s)))}get duration(){return this.keyframes.length===0?0:this.keyframes[this.keyframes.length-1].t}get allKeyframes(){return this.keyframes}toJSON(){return{keyframes:this.keyframes}}static fromJSON(t){const e=new kh;for(const i of t.keyframes)e.addKeyframe(i.t,i.sound);return e}lerp(t,e,i){return{kind:i<1?t.kind:e.kind,volume:t.volume+(e.volume-t.volume)*i,pitchHz:t.pitchHz+(e.pitchHz-t.pitchHz)*i,src:i<1?t.src:e.src}}findInsertIndex(t){let e=0,i=this.keyframes.length;for(;e<i;){const n=e+i>>>1;this.keyframes[n].t<t?e=n+1:i=n}return e}}const lx=100,ux={kind:"none",volume:0,pitchHz:lx};class gs{constructor(t){this.entries=t}static empty(){return new gs(new Map)}get size(){return this.entries.size}at(t){return this.entries.get(t)}paths(){return[...this.entries.keys()]}set(t,e){e.basis==="stated"&&e.rationale===void 0&&e.how===void 0?this.entries.delete(t):this.entries.set(t,e)}clear(t){for(const e of this.entries.keys())(e===t||e.startsWith(`${t}.`))&&this.entries.delete(e)}static strip(t){const e=new gs(new Map);return{recording:gs.stripValue(t,[],e),provenance:e}}static restore(t,e){if(e.size===0)return t;const i={...t},n=new Set([i]);for(const s of e.paths()){const a=e.at(s),r=s.split("."),c=gs.writableHolderOf(i,r,n);if(!c)continue;const h=r[r.length-1],l=c[h];l!==void 0&&(a.of!==void 0&&JSON.stringify(a.of)!==JSON.stringify(l)||(c[h]={value:l,...a.basis==="stated"?{}:{basis:a.basis},...a.rationale===void 0?{}:{rationale:a.rationale},...a.how===void 0?{}:{how:a.how}}))}return i}static isWrapper(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)&&"value"in t}static stripValue(t,e,i){return gs.isWrapper(t)?(i.set(e.join("."),{basis:t.basis??"stated",...t.rationale===void 0?{}:{rationale:t.rationale},...t.how===void 0?{}:{how:t.how},of:t.value}),gs.stripValue(t.value,e,i)):Array.isArray(t)?t.map((n,s)=>gs.stripValue(n,[...e,String(s)],i)):typeof t=="object"&&t!==null?Object.fromEntries(Object.entries(t).map(([n,s])=>[n,gs.stripValue(s,[...e,n],i)])):t}static writableHolderOf(t,e,i){let n=t;for(const s of e.slice(0,-1)){const a=n[s];if(typeof a!="object"||a===null)return;if(i.has(a)){n=a;continue}const r=Array.isArray(a)?[...a]:{...a};i.add(r),n[s]=r,n=r}return n}}function o0(o){if(o.year!==void 0)return Date.UTC(o.year,(o.month??1)-1,o.day??1,o.hour??0,o.minute??0,o.second??0)}function Jm(o){return(((o.day??0)*24+(o.hour??0))*60+(o.minute??0))*6e4+(o.second??0)*1e3}const dx=["year","month","day","hour","minute"],fx=["day","hour","minute"];function jm(o,t){return t.filter(e=>o[e]!==void 0).join(",")}function px(o){if(o.durationSeconds!==void 0)return o.durationSeconds*1e3;const t=o.durationText===void 0?void 0:dh.parse(o.durationText);if(t)return t.chosenSeconds*1e3;if(!o.time||!o.endTime)return;const e=o.time.year!==void 0&&o.endTime.year!==void 0,i=e?dx:fx,n=jm(o.time,i);if(!(n===""||n!==jm(o.endTime,i)))return e?o0(o.endTime)-o0(o.time):Jm(o.endTime)-Jm(o.time)}class cd{constructor(t,e,i,n,s,a,r,c,h=[],l,u,d,f=[],p=[],g=[],m=[]){this.event=t,this.timeline=e,this.observerTrack=i,this.weatherTrack=n,this.soundTrack=s,this.observer=a,this.id=r,this.weather=c,this.decor=h,this.weatherSource=l,this.instrumentId=u,this.exposureSeconds=d,this.milestones=f,this.references=p,this.roads=g,this.traces=m}provenance=gs.empty();loadIssues=[];account;sources;interpretation;variants=[];skyEvents;frozen;sway;lightPollution;observerMap;iso;metering;lens;vehicle;get observerCount(){return 1+this.decor.filter(t=>t.kind==="observer").length}get exposure(){return this.exposureSeconds??this.instrument.exposureSeconds}get instrument(){return Ii.byId(this.instrumentId)}static create(t,e,i){return new cd({eventType:"sighting",time:t,place:e},new od,new Nh,new Uh,new kh,i)}}const mx=0,gx=0;function Fe(o,t){const e=o.observerTrack.getInterpolatedPoseAt(t);if(e)return e;const i=o.event.place?.[0];if(i)return{lat:i.lat,lng:i.lng,elevationM:mx,headingDeg:void 0,pitchDeg:gx,fovDeg:Ii.fieldOfViewDeg(o.instrument)}}function Uc(o,t){return o.weatherTrack.getInterpolatedWeatherAt(t)??o.weather??rd}function kc(o,t){return o.weatherTrack.getActualWeatherAt(t)??o.weather??rd}function Mx(o,t){return o.soundTrack.getInterpolatedSoundAt(t)??ux}class vx{constructor(t,e){this.timeline=t,this.onFrame=e}rafId=null;state="stopped";currentT=0;lastWallTime=0;playbackRate=1;loop=!1;onEnded;durationOverrideMs=0;get seekableDuration(){return Math.max(this.timeline.duration,this.durationOverrideMs)}play(){if(this.state==="playing")return;this.currentT>=this.seekableDuration&&(this.currentT=0,this.resolveFrame(0)),this.state="playing",this.lastWallTime=performance.now();const t=()=>{if(this.state!=="playing")return;const e=performance.now();if(this.currentT+=(e-this.lastWallTime)*this.playbackRate,this.lastWallTime=e,this.currentT>=this.seekableDuration){if(this.loop&&this.seekableDuration>0){this.currentT%=this.seekableDuration,this.resolveFrame(this.currentT),this.rafId=requestAnimationFrame(t);return}this.currentT=this.seekableDuration,this.stop(),this.resolveFrame(this.currentT),this.onEnded?.();return}this.resolveFrame(this.currentT),this.rafId=requestAnimationFrame(t)};this.rafId=requestAnimationFrame(t)}pause(){this.state==="playing"&&(this.state="paused",this.rafId!==null&&(cancelAnimationFrame(this.rafId),this.rafId=null))}stop(){this.state="stopped",this.rafId!==null&&(cancelAnimationFrame(this.rafId),this.rafId=null)}seek(t){this.currentT=Math.max(0,Math.min(t,this.seekableDuration)),this.resolveFrame(this.currentT)}get playbackState(){return this.state}get time(){return this.currentT}resolveFrame(t){const e=new Map;for(const i of this.timeline.sourceIds){const n=this.timeline.getInterpolatedShapeAt(t,i);n&&e.set(i,n)}this.onFrame(t,e)}}const Mv=["nw","n","ne","e","se","s","sw","w"],yx=24,sl=8,xx=3,wx=8;function al(o,t,e){const i=o.x-t.x,n=o.y-t.y,s=Math.cos(e),a=Math.sin(e);return{x:t.x+i*s-n*a,y:t.y+i*a+n*s}}function Fc(o){return{x:o.x+o.width/2,y:o.y+o.height/2}}const Sx={nw:{left:!0,top:!0},n:{top:!0},ne:{right:!0,top:!0},e:{right:!0},se:{right:!0,bottom:!0},s:{bottom:!0},sw:{left:!0,bottom:!0},w:{left:!0}};class ss{static handlePointsFor(t){const{x:e,y:i,width:n,height:s}=t.bounds,a={nw:{x:e,y:i},n:{x:e+n/2,y:i},ne:{x:e+n,y:i},e:{x:e+n,y:i+s/2},se:{x:e+n,y:i+s},s:{x:e+n/2,y:i+s},sw:{x:e,y:i+s},w:{x:e,y:i+s/2},rotate:{x:e+n/2,y:i-yx}},r=Fc(t.bounds),c={};for(const h of Object.keys(a))c[h]=al(a[h],r,t.angle);return c}static hitTestHandle(t,e,i=8,n=[...Mv,"rotate"]){const s=ss.handlePointsFor(t);for(const a of n)if(Math.hypot(e.x-s[a].x,e.y-s[a].y)<=i)return a}static HANDLE_DIRECTION_DEG={e:0,se:45,s:90,sw:135,w:180,nw:225,n:270,ne:315};static resizeAxisFor(t,e){const n=((ss.HANDLE_DIRECTION_DEG[t]+e*180/Math.PI)%180+180)%180/45,s=["ew","nwse","ns","nesw"];return s[Math.round(n)%s.length]}static resizeBounds(t,e,i,n){const s=Fc(t),a=al(n,s,-e),{x:r,y:c,width:h,height:l}=t,u=Sx[i];let d=r,f=c,p=r+h,g=c+l;return u.left&&(d=Math.min(a.x,p-sl)),u.right&&(p=Math.max(a.x,d+sl)),u.top&&(f=Math.min(a.y,g-sl)),u.bottom&&(g=Math.max(a.y,f+sl)),{x:d,y:f,width:p-d,height:g-f}}static resizeShape(t,e,i){if(e==="rotate")throw new Error("resizeShape does not accept the rotate handle");const{width:n,height:s}=t.bounds,a=ss.resizeBounds(t.bounds,t.angle,e,i);if(t.kind==="oval")return{...t,bounds:a};const r=n===0?1:a.width/n,c=s===0?1:a.height/s;return{...t,bounds:a,points:t.points.map(h=>({x:h.x*r,y:h.y*c}))}}static rotateShape(t,e){const i=Fc(t.bounds),n=Math.atan2(e.y-i.y,e.x-i.x)+Math.PI/2;return{...t,angle:n}}static groupBoundsFor(t){const e=Math.min(...t.map(a=>a.x)),i=Math.min(...t.map(a=>a.y)),n=Math.max(...t.map(a=>a.x+a.width)),s=Math.max(...t.map(a=>a.y+a.height));return{x:e,y:i,width:n-e,height:s-i}}static vertexPointsFor(t){const e=Fc(t.bounds);return t.points.map(i=>al({x:t.bounds.x+i.x,y:t.bounds.y+i.y},e,t.angle))}static hitTestVertex(t,e,i=wx){const n=ss.vertexPointsFor(t);let s,a=i;return n.forEach((r,c)=>{const h=Math.hypot(e.x-r.x,e.y-r.y);h<=a&&(a=h,s=c)}),s}static toLocalPoint(t,e){const i=Fc(t.bounds),n=al(e,i,-t.angle);return{x:n.x-t.bounds.x,y:n.y-t.bounds.y}}static moveVertex(t,e,i){const n=t.points.map((u,d)=>d===e?ss.toLocalPoint(t,i):u),s=Math.min(...n.map(u=>u.x)),a=Math.min(...n.map(u=>u.y)),r=Math.max(...n.map(u=>u.x)),c=Math.max(...n.map(u=>u.y)),h={x:t.bounds.x+s,y:t.bounds.y+a,width:r-s,height:c-a},l=n.map(u=>({x:u.x-s,y:u.y-a}));return{...t,bounds:h,points:l}}static insertVertexNear(t,e){const i=ss.toLocalPoint(t,e),{points:n}=t;let s=n.length-1,a=1/0;for(let c=0;c<n.length;c++){const h=n[c],l=n[(c+1)%n.length],u=ss.distanceToSegment(i,h,l);u<a&&(a=u,s=c)}const r=[...n.slice(0,s+1),i,...n.slice(s+1)];return{...t,points:r}}static distanceToSegment(t,e,i){const n=i.x-e.x,s=i.y-e.y,a=n*n+s*s,r=a===0?0:Math.max(0,Math.min(1,((t.x-e.x)*n+(t.y-e.y)*s)/a)),c=e.x+r*n,h=e.y+r*s;return Math.hypot(t.x-c,t.y-h)}static deleteVertex(t,e){return t.points.length<=xx?t:{...t,points:t.points.filter((i,n)=>n!==e)}}}const c0=6,rl=c0/2,Qm=20,tg=24,eg=9,ig=6,ng=7,sg=6,Vs=4;class Sc{constructor(t){this.ctx=t}starPoints=0;roll=0;clear(t,e){this.ctx.clearRect(0,0,t,e)}static paintExtent(t){const{x:e,y:i,width:n,height:s}=t.bounds,a=e+n/2,r=i+s/2,c=t.angle%(2*Math.PI)!==0,h=Math.hypot(n,s)/2,l=c?h:n/2,u=c?h:s/2,d=Math.max(n,s)/2,f=t.brightness??0,p=f>0?Math.max(d*(1+eg*f),sg*f)-d:0,g=f>0?d*(1+ng*f)-d:0,m=3*tg*(t.blur??0)+1.5*Qm*t.haloScale,M=Math.max(p,g,0)+m+2;return{x:a-l-M,y:r-u-M,width:2*(l+M),height:2*(u+M)}}paintInto(t,e,i,n=!1){this.ctx.save(),this.ctx.scale(i,i),this.ctx.translate(-e.x,-e.y);const s=t.selected?{...t,selected:!1}:t;n?this.paintGhost(s,1.5):this.paintShape(s),this.ctx.restore()}paintShape(t){this.ctx.save(),this.ctx.globalAlpha=1-t.transparency;const e=t.blur??0;e>0&&(this.ctx.filter=`blur(${(tg*e).toFixed(2)}px)`);const i=t.brightness??0;i>0&&this.paintDazzle(t,i),t.haloScale>0&&this.paintHalo(t),this.paintBase(t),this.ctx.restore(),t.selected&&this.paintSelectionHandles(t)}setStarPoints(t){this.starPoints=Math.max(0,Math.floor(t))}setRoll(t){this.roll=t}paintDazzle(t,e){const{x:i,y:n,width:s,height:a}=t.bounds,r=i+s/2,c=n+a/2,h=Math.max(s,a)/2,l=Math.max(h*(1+eg*e),sg*e);if(l<=0)return;this.ctx.save(),this.ctx.globalCompositeOperation="lighter";const u=this.ctx.createRadialGradient(r,c,0,r,c,l);for(let d=0;d<=ig;d++){const f=d/ig,p=1/(1+24*f*f);this.ctx.globalAlpha=1,u.addColorStop(f,this.withAlpha(t.color,p*e*.55))}if(this.ctx.fillStyle=u,this.ctx.beginPath(),this.ctx.arc(r,c,l,0,2*Math.PI),this.ctx.fill(),this.starPoints>0){const d=h*(1+ng*e);this.ctx.lineWidth=Math.max(1,h*.12),this.ctx.lineCap="round";for(let f=0;f<this.starPoints;f++){const p=f/this.starPoints*Math.PI*2+this.roll,g=r+Math.cos(p)*d,m=c+Math.sin(p)*d,M=this.ctx.createLinearGradient(r,c,g,m);M.addColorStop(0,this.withAlpha(t.color,e*.55)),M.addColorStop(.35,this.withAlpha(t.color,e*.22)),M.addColorStop(1,this.withAlpha(t.color,0)),this.ctx.strokeStyle=M,this.ctx.beginPath(),this.ctx.moveTo(r,c),this.ctx.lineTo(g,m),this.ctx.stroke()}}this.ctx.restore()}dazzledFill(t,e){if(e<=0)return t.color;const i=/^#([0-9a-f]{6})$/i.exec(t.color.trim());if(!i)return t.color;const n=Number.parseInt(i[1],16),s=a=>Math.round(a+(255-a)*e);return`rgb(${s(n>>16&255)}, ${s(n>>8&255)}, ${s(n&255)})`}withAlpha(t,e){const i=Math.max(0,Math.min(1,e)),n=/^#([0-9a-f]{6})$/i.exec(t.trim());if(!n)return t;const s=Number.parseInt(n[1],16);return`rgba(${s>>16&255}, ${s>>8&255}, ${s&255}, ${i.toFixed(3)})`}paintBase(t){this.ctx.fillStyle=this.dazzledFill(t,t.brightness??0),this.tracePath(t),this.ctx.fill()}paintGhost(t,e){this.ctx.save(),this.tracePath(t),this.ctx.setLineDash([e*3,e*2]),this.ctx.lineWidth=e,this.ctx.strokeStyle=t.color,this.ctx.stroke(),this.ctx.restore()}tracePath(t){if(this.ctx.beginPath(),t.kind==="oval"){const{x:e,y:i,width:n,height:s}=t.bounds,a=n/2,r=s/2;this.ctx.ellipse(e+a,i+r,a,r,t.angle,0,2*Math.PI)}else{const{x:e,y:i,width:n,height:s}=t.bounds;this.ctx.save(),this.ctx.translate(e+n/2,i+s/2),this.ctx.rotate(t.angle),this.ctx.translate(-n/2,-s/2),t.points.forEach((a,r)=>{r===0?this.ctx.moveTo(a.x,a.y):this.ctx.lineTo(a.x,a.y)}),this.ctx.closePath(),this.ctx.restore()}}paintHalo(t){this.ctx.save(),this.ctx.shadowColor=t.color,this.ctx.shadowBlur=Qm*t.haloScale,this.paintBase(t),this.ctx.restore()}paintSelectionHandles(t){this.paintHandleFrame(ss.handlePointsFor(t),{includeRotate:!0}),t.kind==="polygon"&&this.paintVertexHandles(t)}paintVertexHandles(t){this.ctx.fillStyle="#39f";for(const e of ss.vertexPointsFor(t))this.ctx.beginPath(),this.ctx.ellipse(e.x,e.y,Vs,Vs,0,0,2*Math.PI),this.ctx.fill()}paintMemberOutline(t){this.paintOutline(ss.handlePointsFor(t))}paintSelectionOnly(t){this.paintSelectionHandles(t)}paintPictureFrame(t,e,i){const n=this.ctx;if(n.save(),t&&t.length===4){n.strokeStyle="#39f",n.lineWidth=1.5,n.setLineDash([6,4]),n.beginPath(),n.moveTo(t[0].x,t[0].y);for(const s of t.slice(1))n.lineTo(s.x,s.y);n.closePath(),n.stroke(),n.setLineDash([])}for(const s of e){const a=Sc.landmarkColour(s.residualDeg),r=s.selected?3:2;s.selected&&(n.strokeStyle="#fff",n.lineWidth=r+3,n.beginPath(),n.ellipse(s.picture.x,s.picture.y,Vs+2,Vs+2,0,0,2*Math.PI),n.stroke()),s.scene&&(n.strokeStyle=a,n.lineWidth=1,n.beginPath(),n.moveTo(s.picture.x,s.picture.y),n.lineTo(s.scene.x,s.scene.y),n.stroke(),n.fillStyle=a,n.beginPath(),n.ellipse(s.scene.x,s.scene.y,Vs,Vs,0,0,2*Math.PI),n.fill()),n.strokeStyle=a,n.lineWidth=r,n.beginPath(),n.ellipse(s.picture.x,s.picture.y,Vs+2,Vs+2,0,0,2*Math.PI),n.stroke(),this.paintLabel(s.label,s.picture.x+Vs+5,s.picture.y-Vs-2,a)}i&&this.paintLabel(i,8,8,"#fff",13),n.restore()}paintGhosts(t,e,i){const n=this.ctx;n.save();const s=(c,h,l,u=[])=>{n.setLineDash(u),n.lineWidth=l+2,n.strokeStyle="rgba(0, 0, 0, 0.6)",c(),n.lineWidth=l,n.strokeStyle=h,c(),n.setLineDash([])},a=(c,h)=>()=>{n.beginPath(),n.arc(c.x,c.y,h,0,2*Math.PI),n.stroke()},r=(c,h,l)=>()=>{const[u,d]=l?[h,h]:[h,0];n.beginPath(),n.moveTo(c.x-u,c.y-d),n.lineTo(c.x+u,c.y+d),n.moveTo(c.x+d,c.y-u),n.lineTo(c.x-d,c.y+u),n.stroke()};for(const c of t)s(()=>{n.beginPath(),n.moveTo(c.ghost.x,c.ghost.y),n.lineTo(c.light.x,c.light.y),n.stroke()},"rgba(255, 255, 255, 0.85)",1,[4,4]),s(a(c.light,7),"#ffffff",1.5),s(a(c.ghost,Math.max(9,c.ghostRadius)),"#ffd23f",2);e&&s(r(e,8,!1),"#ffd23f",2),i&&s(r(i,5,!0),"rgba(255, 255, 255, 0.7)",1),n.restore()}static landmarkColour(t){return t===void 0?"#ffb000":t<=1?"#3c3":t<=3?"#ffb000":"#f33"}paintLabel(t,e,i,n,s=11){const a=this.ctx;a.save(),a.font=`${s}px system-ui, sans-serif`,a.textBaseline="top";const r=a.measureText(t).width;a.fillStyle="rgba(0, 0, 0, 0.6)",a.fillRect(e-3,i-2,r+6,s+4),a.fillStyle=n,a.fillText(t,e,i),a.restore()}paintGroupHandles(t){this.paintHandleFrame(ss.handlePointsFor({bounds:t,angle:0}),{includeRotate:!0})}paintOutline(t){this.ctx.strokeStyle="lightgray",this.ctx.beginPath(),this.ctx.moveTo(t.nw.x,t.nw.y),this.ctx.lineTo(t.ne.x,t.ne.y),this.ctx.lineTo(t.se.x,t.se.y),this.ctx.lineTo(t.sw.x,t.sw.y),this.ctx.closePath(),this.ctx.stroke()}paintHandleFrame(t,{includeRotate:e}){this.paintOutline(t),this.ctx.fillStyle="lightgray";for(const i of Mv){const n=t[i];this.ctx.fillRect(n.x-rl,n.y-rl,c0,c0)}e&&(this.ctx.beginPath(),this.ctx.moveTo(t.n.x,t.n.y),this.ctx.lineTo(t.rotate.x,t.rotate.y),this.ctx.stroke(),this.ctx.beginPath(),this.ctx.ellipse(t.rotate.x,t.rotate.y,rl+1,rl+1,0,0,2*Math.PI),this.ctx.fill())}}const ag=.05,rg=.08,og=2,cg=3,bx=14,Ex=.02;class Ax{context;voice;voiceToken=0;buffers=new Map;noiseBuffer;crackleBuffer;requested;level=1;master;output(t){return this.master||(this.master=t.createGain(),this.master.gain.value=this.level,this.master.connect(t.destination)),this.master}setLevel(t){this.level=t,this.master&&(this.master.gain.value=t)}resume(){if(!this.context){if(typeof AudioContext>"u")return;try{this.context=new AudioContext}catch(t){console.warn("SightingAudio: Web Audio unavailable, the sighting stays silent:",t);return}}$r.unlock(this.context)}setSound(t){if(this.requested=t,!this.context)return;const e=this.keyFor(t);if(!e){this.silence();return}if(this.voice?.key!==e){this.stopVoice();const i=++this.voiceToken;e.startsWith("src:")?this.buildRecordedVoice(t.src,e,i):this.voice=this.buildSynthesizedVoice(t,e)}this.applyTo(this.voice,t)}silence(){this.voiceToken++,this.stopVoice()}dispose(){this.silence(),this.context?.close(),this.context=void 0,this.master=void 0,this.buffers.clear(),this.noiseBuffer=void 0,this.crackleBuffer=void 0}keyFor(t){if(!(t.volume<=0))return t.src?`src:${t.src}`:t.kind==="none"?void 0:t.kind}applyTo(t,e){const i=this.context;if(!t||!i)return;const n=i.currentTime;t.volumeParam.setTargetAtTime(Math.max(0,Math.min(1,e.volume))*t.gainScale,n,ag);for(const{param:s,ratio:a}of t.pitch)s.setTargetAtTime(Math.min(e.pitchHz*a,i.sampleRate/2-1),n,ag)}buildSynthesizedVoice(t,e){const i=this.context;if(i)switch(t.kind){case"hum":return this.buildHum(i,e);case"whistle":return this.buildWhistle(i,e);case"rumble":return this.buildRumble(i,e);case"crackle":return this.buildCrackle(i,e);default:return}}buildHum(t,e){const i=t.createOscillator();i.type="sawtooth";const n=t.createOscillator();n.type="sawtooth";const s=t.createBiquadFilter();s.type="lowpass",s.Q.value=1;const a=t.createGain();return a.gain.value=0,i.connect(s),n.connect(s),s.connect(a).connect(this.output(t)),i.start(),n.start(),{key:e,nodes:[s,a],sources:[i,n],volumeParam:a.gain,gainScale:.16,pitch:[{param:i.frequency,ratio:1},{param:n.frequency,ratio:1.006},{param:s.frequency,ratio:6}]}}buildWhistle(t,e){const i=t.createOscillator();i.type="sine";const n=t.createOscillator();n.type="sine",n.frequency.value=5;const s=t.createGain(),a=t.createGain();return a.gain.value=0,n.connect(s).connect(i.frequency),i.connect(a).connect(this.output(t)),i.start(),n.start(),{key:e,nodes:[s,a],sources:[i,n],volumeParam:a.gain,gainScale:.22,pitch:[{param:i.frequency,ratio:1},{param:s.gain,ratio:.012}]}}buildRumble(t,e){const i=t.createBufferSource();i.buffer=this.brownNoise(t),i.loop=!0;const n=t.createBiquadFilter();n.type="lowpass",n.Q.value=.8;const s=t.createGain();return s.gain.value=0,i.connect(n).connect(s).connect(this.output(t)),i.start(),{key:e,nodes:[n,s],sources:[i],volumeParam:s.gain,gainScale:1.4,pitch:[{param:n.frequency,ratio:1}]}}buildCrackle(t,e){const i=t.createBufferSource();i.buffer=this.whiteNoise(t),i.loop=!0;const n=t.createBiquadFilter();n.type="bandpass",n.Q.value=1.2;const s=t.createGain();s.gain.value=0;const a=t.createBufferSource();a.buffer=this.crackleEnvelope(t),a.loop=!0;const r=t.createGain();return r.gain.value=0,a.connect(r).connect(s.gain),i.connect(n).connect(s).connect(this.output(t)),i.start(),a.start(),{key:e,nodes:[n,s,r],sources:[i,a],volumeParam:r.gain,gainScale:.9,pitch:[{param:n.frequency,ratio:4}]}}async buildRecordedVoice(t,e,i){const n=this.context;if(!n)return;let s;try{s=await this.getBuffer(t)}catch(c){console.warn("SightingAudio: the recorded sound failed to load, staying silent:",c);return}if(i!==this.voiceToken||!this.context)return;const a=n.createBufferSource();a.buffer=s,a.loop=!0;const r=n.createGain();r.gain.value=0,a.connect(r).connect(this.output(n)),a.start(),this.voice={key:e,nodes:[r],sources:[a],volumeParam:r.gain,gainScale:1,pitch:[]},this.requested&&this.applyTo(this.voice,this.requested)}async getBuffer(t){const e=this.context;if(!e)throw new Error("SightingAudio: AudioContext not ready — resume() must be called first");let i=this.buffers.get(t);return i||(i=fetch(t).then(n=>{if(!n.ok)throw new Error(`Audio fetch failed (${n.status}): ${t}`);return n.arrayBuffer()}).then(n=>e.decodeAudioData(n)),this.buffers.set(t,i)),i}whiteNoise(t){if(!this.noiseBuffer){const e=t.createBuffer(1,Math.floor(t.sampleRate*og),t.sampleRate),i=e.getChannelData(0);for(let n=0;n<i.length;n++)i[n]=Math.random()*2-1;this.noiseBuffer=e}return this.noiseBuffer}brownNoise(t){const e=t.createBuffer(1,Math.floor(t.sampleRate*og),t.sampleRate),i=e.getChannelData(0);let n=0,s=0;for(let a=0;a<i.length;a++)n=(n+.02*(Math.random()*2-1))/1.02,i[a]=n,s=Math.max(s,Math.abs(n));if(s>0)for(let a=0;a<i.length;a++)i[a]/=s;return e}crackleEnvelope(t){if(!this.crackleBuffer){const e=t.createBuffer(1,Math.floor(t.sampleRate*cg),t.sampleRate),i=e.getChannelData(0),n=Math.max(1,Math.floor(Ex*t.sampleRate)),s=Math.round(cg*bx);for(let a=0;a<s;a++){const r=Math.floor(Math.random()*i.length),c=.4+Math.random()*.6;for(let h=0;h<n&&r+h<i.length;h++)i[r+h]=Math.max(i[r+h],c*(1-h/n))}this.crackleBuffer=e}return this.crackleBuffer}stopVoice(){const t=this.voice,e=this.context;if(this.voice=void 0,!t||!e)return;const i=e.currentTime;t.volumeParam.cancelScheduledValues(i),t.volumeParam.setTargetAtTime(0,i,rg/3);const n=i+rg;for(const s of t.sources){s.onended=()=>{s.disconnect();for(const a of t.nodes)a.disconnect()};try{s.stop(n)}catch{s.disconnect();for(const a of t.nodes)a.disconnect()}}}}class Zt{static svg(t){return`<svg viewBox="0 0 24 24" width="1.5em" height="1.5em" aria-hidden="true" focusable="false"><path d="${t}" fill="currentColor"/></svg>`}static outline(t){return`<svg viewBox="0 0 24 24" width="1.5em" height="1.5em" aria-hidden="true" focusable="false"><path d="${t}" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round" stroke-linecap="round"/></svg>`}static solid(t){return`<svg viewBox="0 0 24 24" width="1.5em" height="1.5em" aria-hidden="true" focusable="false"><path d="${t}" fill="currentColor" fill-rule="evenodd"/></svg>`}static BOOKMARK="M6 3.5h12a.5.5 0 0 1 .5.5v16.5L12 16.8l-6.5 3.7V4a.5.5 0 0 1 .5-.5z";static PICTURE="M5 4h14a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z";static PICTURE_HILLS="M4.5 17.5l4.5-6 3 4 2.5-3 5 5z";static PIN="M12 21.5s-6.5-5.7-6.5-10.8a6.5 6.5 0 0 1 13 0c0 5.1-6.5 10.8-6.5 10.8z";static PIN_HOLE="M12 8.4a2.4 2.4 0 1 0 0 4.8 2.4 2.4 0 0 0 0-4.8z";static MILESTONES_OFF=Zt.outline(Zt.BOOKMARK);static MILESTONES_ON=Zt.solid(Zt.BOOKMARK);static PICTURES_OFF=Zt.outline(`${Zt.PICTURE}${Zt.PICTURE_HILLS}`);static PICTURES_ON=Zt.solid(`${Zt.PICTURE}${Zt.PICTURE_HILLS}`);static TRACE_LINE="M3 19.5l2.2-2.2 1.4 1.4L4.4 20.9zM8 14.5l2.2-2.2 1.4 1.4-2.2 2.2zM13 9.5l2.2-2.2 1.4 1.4-2.2 2.2z";static TRACE_MARK="M18.5 2.5l3.5 3.5-3.5 3.5-3.5-3.5z";static TRACES_OFF=Zt.outline(`${Zt.TRACE_LINE}${Zt.TRACE_MARK}`);static TRACES_ON=Zt.solid(`${Zt.TRACE_LINE}${Zt.TRACE_MARK}`);static MAP_OFF=Zt.outline(`${Zt.PIN}${Zt.PIN_HOLE}`);static MAP_ON=Zt.solid(`${Zt.PIN}${Zt.PIN_HOLE}`);static SHARE=Zt.outline("M14 4l7 7-7 7v-4.2C8.6 13.8 5.4 15.6 3.5 19c.6-5.6 3.4-9.6 10.5-10.8V4z");static FOLDED=Zt.svg("M15.4 7.4 14 6l-6 6 6 6 1.4-1.4L10.8 12z");static UNFOLDED=Zt.svg("M8.6 16.6 10 18l6-6-6-6-1.4 1.4 4.6 4.6z");static PLAY=Zt.svg("M7.4 5v14l11-7z");static PAUSE=Zt.svg("M6 5h4v14H6zM14 5h4v14h-4z");static VOLUME=Zt.svg("M2 9.5v5h3.5l4.5 4.5V5L5.5 9.5H2zm12.5 2.5A4 4 0 0 0 12.5 8.5v7A4 4 0 0 0 14.5 12zM12.5 4.2v2.1a6.5 6.5 0 0 1 0 11.4v2.1a8.6 8.6 0 0 0 0-15.6z");static MUTED=Zt.svg("M2 9.5v5h3.5l4.5 4.5V5L5.5 9.5H2zM15 9.8l1.4-1.4 2.6 2.6 2.6-2.6 1.4 1.4-2.6 2.6 2.6 2.6-1.4 1.4-2.6-2.6-2.6 2.6-1.4-1.4 2.6-2.6z");static ENTER_FULLSCREEN=Zt.svg("M5 5h5v2H7v3H5V5zm9 0h5v5h-2V7h-3V5zM5 14h2v3h3v2H5v-5zm12 0h2v5h-5v-2h3v-3z");static EXIT_FULLSCREEN=Zt.svg("M8 5h2v5H5V8h3V5zm6 0h2v3h3v2h-5V5zM5 14h5v5H8v-3H5v-2zm9 0h5v2h-3v3h-2v-5z")}class js{static KINDS=["beams","launches","reentries"];static isEmpty(t){return!t||js.KINDS.every(e=>!t[e]?.length)}static written(t){if(js.isEmpty(t))return;const e={};for(const i of js.KINDS)t[i]?.length&&(e[i]=t[i]);return e}static read(t,e){const i=e,n={};for(const a of js.KINDS){const r=[...t?.[a]??[],...i?.[a]??[]];r.length>0&&(n[a]=r)}let s=e;if(i&&js.KINDS.some(a=>a in i)){const{beams:a,launches:r,reentries:c,...h}=i;s=js.isReading(h)?h:void 0}return{skyEvents:js.written(n),interpretation:s}}static isReading(t){return(t.bodies?.length??0)>0||t.title!==void 0||(t.smoke?.length??0)>0}}function fh(o){return[...o].sort((t,e)=>t.t-e.t)}function Rd(o,t){let e;for(const i of fh(o)){if(i.t>t)break;e=i}return e}const Id=Math.PI/180,ol=180/Math.PI;class ha{constructor(t,e,i){this.kind=t,this.canvasHeightPx=e,this.fovDeg=i;const n=i*Id/2;this.focalPx=t==="equidistant"?e/2/n:e/2/Math.tan(n)}focalPx;static of(t,e,i){return new ha(t.projection,e,i)}degToPx(t){const e=t*Id;return this.kind==="equidistant"?this.focalPx*e:2*this.focalPx*Math.tan(e/2)}pxToDeg(t){return this.kind==="equidistant"?t/this.focalPx*ol:2*Math.atan(t/(2*this.focalPx))*ol}angleDegToRadiusPx(t){const e=t*Id;return this.kind==="equidistant"?this.focalPx*e:this.focalPx*Math.tan(e)}halfWidthAngleDeg(t){return this.radiusPxToAngleDeg(this.canvasHeightPx*t/2)}radiusPxToAngleDeg(t){return this.kind==="equidistant"?t/this.focalPx*ol:Math.atan(t/this.focalPx)*ol}ofBounds(t){return{widthDeg:this.pxToDeg(t.width),heightDeg:this.pxToDeg(t.height)}}toBoundsSize(t){return{width:this.degToPx(t.widthDeg),height:this.degToPx(t.heightDeg)}}widthPx(t){return this.degToPx(Ze.angularWidthDeg(t))}}class wn{static fovOf(t,e){return Fe(t,e)?.fovDeg??Ii.fieldOfViewDeg(t.instrument)}static toAngular(t){this.eachKeyframe(t,(e,i)=>{const n=i.ofBounds(e.bounds);return e.angular?.widthDeg===n.widthDeg&&e.angular.heightDeg===n.heightDeg?e:{...e,angular:n}})}static toBounds(t){this.eachKeyframe(t,(e,i)=>this.sizedFromAngle(e,i))}static sizedFromAngle(t,e){if(!t.angular)return t;const{width:i,height:n}=e.toBoundsSize(t.angular),s={x:t.bounds.x+(t.bounds.width-i)/2,y:t.bounds.y+(t.bounds.height-n)/2,width:i,height:n};if(t.kind!=="polygon")return{...t,bounds:s};const a=t.bounds.width===0?1:i/t.bounds.width,r=t.bounds.height===0?1:n/t.bounds.height;return{...t,bounds:s,points:t.points.map(c=>({x:c.x*a,y:c.y*r}))}}static toAim(t){this.eachKeyframe(t,(e,i,n)=>{const s=e.aim&&this.positionOf(t,e.aim,e.bounds,i,n);if(s&&Math.abs(s.x-e.bounds.x)<wn.UNMOVED_PX&&Math.abs(s.y-e.bounds.y)<wn.UNMOVED_PX)return e;const a=this.aimFrom(t,i,n,e.bounds);return a?{...e,aim:a}:e})}static UNMOVED_PX=.01;static aimOf(t,e,i){const n=ha.of(t.instrument,Ze.CANVAS_HEIGHT_PX,this.fovOf(t,e));return this.aimFrom(t,n,Fe(t,e),i)}static aimFrom(t,e,i,n){if(i?.headingDeg===void 0)return;const s=this.frameCentre(t),a=e.radiusPxToAngleDeg(n.x+n.width/2-s.x),r=e.radiusPxToAngleDeg(s.y-(n.y+n.height/2));return{azimuthDeg:((i.headingDeg+a)%360+360)%360,altitudeDeg:i.pitchDeg+r}}static toPosition(t){this.eachKeyframe(t,(e,i,n)=>this.placedByAim(t,e,i,n))}static placedByAim(t,e,i,n){const s=e.aim&&this.positionOf(t,e.aim,e.bounds,i,n);return s?{...e,bounds:{...e.bounds,...s}}:e}static derivable(t){const e=new Set,i=new Map,n=new Map;return t.timeline.allKeyframes.forEach((s,a)=>{const r=Fe(t,s.t),c=ha.of(t.instrument,Ze.CANVAS_HEIGHT_PX,this.fovOf(t,s.t));for(const{sourceId:h,shape:l}of s.shapes){const u=n.get(h),d=i.get(h);if(n.set(h,l),!u||!d){i.set(h,l);continue}const f=Object.fromEntries(Object.entries(l).filter(([m,M])=>m!=="bounds"&&m!=="points"&&JSON.stringify(M)!==JSON.stringify(u[m]))),p={...d,...f},g=this.placedByAim(t,this.sizedFromAngle(p,c),c,r);wn.near(g,l)?(e.add(`${a}:${h}`),i.set(h,p)):i.set(h,l)}}),(s,a)=>e.has(`${s}:${a}`)}static SAME_PX=1e-6;static near(t,e){const i=(a,r)=>Math.abs(a-r)<=wn.SAME_PX*Math.max(1,Math.abs(r)),n=t.bounds,s=e.bounds;return!i(n.x,s.x)||!i(n.y,s.y)||!i(n.width,s.width)||!i(n.height,s.height)?!1:e.kind!=="polygon"||t.kind!=="polygon"?!0:t.points.length===e.points.length&&t.points.every((a,r)=>i(a.x,e.points[r].x)&&i(a.y,e.points[r].y))}static positionOf(t,e,i,n,s){if(s?.headingDeg===void 0)return;const a=this.frameCentre(t),r=this.shortestArc(e.azimuthDeg-s.headingDeg),c=e.altitudeDeg-s.pitchDeg;return{x:a.x+this.offAxisPx(n,r)-i.width/2,y:a.y-this.offAxisPx(n,c)-i.height/2}}static frameCentre(t){return{x:Ii.frameWidthPx(t.instrument,Ze.CANVAS_HEIGHT_PX)/2,y:Ze.CANVAS_HEIGHT_PX/2}}static shortestArc(t){return(t%360+540)%360-180}static offAxisPx(t,e){return Math.abs(e)>=wn.OFF_CANVAS_DEG?Math.sign(e)*wn.OFF_CANVAS_PX:t.angleDegToRadiusPx(e)}static OFF_CANVAS_DEG=89;static OFF_CANVAS_PX=1e5;static reproject(t,e,i){const n=Ii.frameWidthPx(e,Ze.CANVAS_HEIGHT_PX)/2,s=Ii.frameWidthPx(t.instrument,Ze.CANVAS_HEIGHT_PX)/2,a=Ze.CANVAS_HEIGHT_PX/2;for(const r of[...t.timeline.allKeyframes]){const c=this.fovOf(t,r.t),h=i?.get(r.t)??c,l=ha.of(e,Ze.CANVAS_HEIGHT_PX,h),u=ha.of(t.instrument,Ze.CANVAS_HEIGHT_PX,c);t.timeline.addKeyframe(r.t,r.shapes.map(d=>{const{bounds:f}=d.shape,p=f.x+f.width/2-n,g=f.y+f.height/2-a,m=Math.hypot(p,g),M=m===0?1:u.angleDegToRadiusPx(l.radiusPxToAngleDeg(m))/m,y={...f,x:s+p*M-f.width/2,y:a+g*M-f.height/2};return{...d,shape:{...d.shape,bounds:y}}}))}this.toBounds(t)}static eachKeyframe(t,e){const{timeline:i}=t;for(const n of[...i.allKeyframes]){const s=Fe(t,n.t),a=this.fovOf(t,n.t),r=ha.of(t.instrument,Ze.CANVAS_HEIGHT_PX,a);let c=!1;const h=n.shapes.map(l=>{const u=e(l.shape,r,s);return u===l.shape?l:(c=!0,{...l,shape:u})});c&&i.addKeyframe(n.t,h)}}}class Dn{static isRelative(t){return t!==void 0&&typeof t.eastM=="number"&&typeof t.northM=="number"}static isAbsolute(t){return t!==void 0&&typeof t.lat=="number"&&typeof t.lng=="number"}static referenceOf(t,e){return e.references.find(i=>(i.id??void 0)===(t.relativeTo??void 0))}static resolve(t,e){if(Dn.isRelative(t)){const i=Dn.referenceOf(t,e);return i?{eastM:i.eastM+t.eastM,northM:i.northM+t.northM}:void 0}return Dn.isAbsolute(t)&&e.origin?Dn.toLocal(t,e.origin):void 0}static restated(t,e,i){if(Dn.isRelative(t)){const s=Dn.referenceOf(t,i);return s?Dn.relative(e.eastM-s.eastM,e.northM-s.northM,t.relativeTo):void 0}if(!i.origin)return t;const n=Dn.toGeo(e,i.origin);return{lat:Dn.degrees(n.lat),lng:Dn.degrees(n.lng)}}static relative(t,e,i){const n={eastM:Dn.metres(t),northM:Dn.metres(e)};return i!==void 0&&(n.relativeTo=i),n}static toLocal(t,e){const i=ae(t.lat,t.lng,e.lat,e.lng);return{eastM:i.x,northM:-i.z}}static toGeo(t,e){return Kn(t.eastM,-t.northM,e.lat,e.lng)}static metres(t){return Math.round(t*100)/100}static degrees(t){return Math.round(t*1e7)/1e7}}class On{static restatedDecor(t){const e=On.originOf(t);return t.decor.map(i=>{let n=i;if(i.saidPosition){const s=On.restated(i.saidPosition,i,On.frameAt(t,0,e,i.id));JSON.stringify(s)!==JSON.stringify(i.saidPosition)&&(n={...i,saidPosition:s},s||delete n.saidPosition)}if(i.track?.some(s=>s.saidPosition)){const s=i.track.map(a=>{if(!a.saidPosition)return a;const r=On.restated(a.saidPosition,a,On.frameAt(t,a.t,e,i.id));if(JSON.stringify(r)===JSON.stringify(a.saidPosition))return a;const c={...a,saidPosition:r};return r||delete c.saidPosition,c});n={...n,track:s}}return n})}static restatedObserverTrack(t){const e=t.observerTrack.toJSON(),i=On.originOf(t);return!i||!e.keyframes.some(n=>n.pose.saidPosition)?e:{...e,keyframes:e.keyframes.map(n=>{const{pose:s}=n;if(!s.saidPosition||s.lat===void 0||s.lng===void 0)return n;const a=Dn.toLocal({lat:s.lat,lng:s.lng},i),r=On.restated(s.saidPosition,a,On.frameAt(t,n.t,i));if(JSON.stringify(r)===JSON.stringify(s.saidPosition))return n;const c={...s,saidPosition:r};return r||delete c.saidPosition,{...n,pose:c}})}}static restatedInterpretation(t){const e=t.interpretation;if(!e?.bodies.some(n=>n.track.some(s=>s.saidPosition)))return e;const i=On.originOf(t);return{...e,bodies:e.bodies.map(n=>n.track.some(s=>s.saidPosition)?{...n,track:n.track.map(s=>{if(!s.saidPosition)return s;const a=s.eastM!==void 0&&s.northM!==void 0?On.restated(s.saidPosition,{eastM:s.eastM,northM:s.northM},On.frameAt(t,s.t,i)):void 0;if(JSON.stringify(a)===JSON.stringify(s.saidPosition))return s;const r={...s,saidPosition:a};return a||delete r.saidPosition,r})}:n)}}static originOf(t){const e=t.observerTrack.getInterpolatedPoseAt(0),i=t.event.place?.[0],n=e?.lat??i?.lat,s=e?.lng??i?.lng;return typeof n=="number"&&typeof s=="number"?{lat:n,lng:s}:void 0}static frameAt(t,e,i,n){const s=[{label:"",eastM:0,northM:0},...t.decor.filter(a=>a.id!==n).map(a=>{const{eastM:r,northM:c}=fa(a,e);return{id:a.id,label:a.id,eastM:r,northM:c}})];return{origin:i,references:s}}static restated(t,e,i){return Dn.restated(t,{eastM:e.eastM,northM:e.northM},i)}}class _x extends Error{constructor(t,e,i){super(typeof e=="number"&&Number.isInteger(e)&&e>i?`This ${t} file is in version ${e} of its format; this UFO@home reads up to version ${i}. Read it with a newer UFO@home.`:`This ${t} file states ${JSON.stringify(e)} as its format version, which is not a version.`),this.format=t,this.found=e,this.supported=i,this.name="FormatVersionError"}said(t){return t.replace("{found}",typeof this.found=="number"?String(this.found):JSON.stringify(this.found)).replace("{supported}",String(this.supported))}}class Ko{static CURRENT={sighting:1,case:1,interview:1};static SCHEMA_BASE="https://ufoathome.org/schema";static schemaUrl(t,e=Ko.CURRENT[t]){return`${Ko.SCHEMA_BASE}/${e}/${t}.schema.json`}static of(t){if(typeof t!="object"||t===null)return 1;const e=t.version;return e===void 0?1:typeof e=="object"&&e!==null&&"value"in e?e.value:e}static check(t,e){const i=Ko.of(t),n=Ko.CURRENT[e];if(typeof i!="number"||!Number.isInteger(i)||i<1||i>n)throw new _x(e,i,n);return t}}function Tx(o){return gs.restore(Rx(o),o.provenance)}function Rx(o){return wn.toAngular(o),wn.toAim(o),{version:1,id:o.id,time:o.event.time,endTime:o.event.endTime,durationSeconds:o.event.durationSeconds,durationText:o.event.durationText,utcOffsetHours:o.event.utcOffsetHours,timeZone:o.event.timeZone,place:o.event.place,observer:o.observer,account:o.account,sources:o.sources?.length?o.sources:void 0,sway:o.sway,vehicle:o.vehicle,description:o.event.description,image:o.event.image,summary:o.event.summary,summaryTime:o.event.summaryTime,tags:o.event.tags,timeline:o.timeline.toJSON(),observerTrack:On.restatedObserverTrack(o),weatherTrack:o.weatherTrack.toJSON(),soundTrack:o.soundTrack.toJSON(),weather:o.weather,decor:On.restatedDecor(o),milestones:o.milestones.length>0?o.milestones:void 0,references:o.references.length>0?o.references:void 0,roads:o.roads.length>0?o.roads:void 0,traces:o.traces.length>0?o.traces:void 0,weatherSource:o.weatherSource,instrument:o.instrumentId,exposureSeconds:o.exposureSeconds,iso:o.iso,metering:o.metering,lens:o.lens,lightPollution:o.lightPollution,observerMap:o.observerMap,interpretation:On.restatedInterpretation(o),variants:o.variants.length>0?o.variants:void 0,skyEvents:js.written(o.skyEvents),frozen:o.frozen}}function Ix(o){Ko.check(o,"sighting");const{recording:t,provenance:e}=gs.strip(o),i=Dx(t);return i.provenance=e,i}function Dx(o){const t=[],e=new cd({eventType:"sighting",time:o.time,endTime:o.endTime,durationSeconds:o.durationSeconds,durationText:o.durationText,utcOffsetHours:o.utcOffsetHours,timeZone:o.timeZone,place:o.place,description:o.description,image:o.image,summary:o.summary,summaryTime:o.summaryTime,tags:o.tags},od.fromJSON(o.timeline,t),o.observerTrack?Nh.fromJSON(o.observerTrack):new Nh,o.weatherTrack?Uh.fromJSON(o.weatherTrack):new Uh,o.soundTrack?kh.fromJSON(o.soundTrack):new kh,o.observer&&{id:o.observer.id,title:o.observer.title,lastName:o.observer.lastName,firstNames:o.observer.firstNames},o.id,o.weather,(o.decor??[]).map(n=>{if(!n.facade?.plain)return n;const{plain:s,...a}=n.facade;return{...n,facade:{...a,openings:"plain"}}}),o.weatherSource,o.instrument,o.exposureSeconds??o.observerTrack?.keyframes.map(n=>n.pose.exposureSeconds).find(n=>n!==void 0),fh(o.milestones??[]),o.references??[],o.roads??[],o.traces??[]);e.account=o.account,e.sources=o.sources,e.sway=o.sway,e.iso=o.iso,e.metering=o.metering,e.lens=o.lens,e.lightPollution=o.lightPollution,e.observerMap=o.observerMap,e.vehicle=o.vehicle;const i=js.read(o.skyEvents,o.interpretation);return e.interpretation=i.interpretation,e.variants=Array.isArray(o.variants)?o.variants:[],e.skyEvents=i.skyEvents,e.frozen=o.frozen,e.loadIssues=t,wn.toBounds(e),wn.toPosition(e),e}class bc{static EN={"unknown-key":"{path}: unknown key, ignored","wrong-type":"{path}: expected {expected}, found {found}","not-in-list":"{path}: {found} is not one of {expected}",defaulted:"{path}: missing, {expected} used",unplaced:"{path}: no aim (and no bounds), drawn at the middle of the view",unsized:"{path}: no angular size (and no bounds), drawn one pixel wide","pixels-over-angles":"{path}: bounds restated without aim or angular, so the shape follows the pixels"};static text(t,e=bc.EN){return e[t.kind].replace("{path}",t.path).replace("{expected}",t.expected??"").replace("{found}",t.found??"")}static warn(t,e){if(t.length===0)return;const i=t.map(n=>` ${bc.text(n)}`);console.warn(`UFO@home: ${t.length} problem(s) in ${e??"this recording"}:
1736
+ `;class Yo{static DEFAULT_FOCAL_MM=50;static FOCAL_RANGE_MM={minMm:14,maxMm:135};static BODIES=[{id:"eos-450d",name:"Canon EOS 450D (APS-C)",widthMm:22.2,heightMm:14.8,pixelUm:5.2,year:2008},{id:"eos-60da",name:"Canon EOS 60Da (APS-C)",widthMm:22.3,heightMm:14.9,pixelUm:4.3,year:2012},{id:"eos-70d",name:"Canon EOS 70D (APS-C)",widthMm:22.5,heightMm:15,pixelUm:4.1,year:2013},{id:"eos-80d",name:"Canon EOS 80D (APS-C)",widthMm:22.3,heightMm:14.9,pixelUm:3.7,year:2016},{id:"eos-7d",name:"Canon EOS 7D (APS-C)",widthMm:22.3,heightMm:14.9,pixelUm:4.1,year:2009},{id:"eos-7d-ii",name:"Canon EOS 7D Mark II (APS-C)",widthMm:22.4,heightMm:15,pixelUm:4.1,year:2014},{id:"eos-5d",name:"Canon EOS 5D (full frame)",widthMm:35.8,heightMm:23.9,pixelUm:8.2,year:2005},{id:"eos-5d-ii",name:"Canon EOS 5D Mark II (full frame)",widthMm:36,heightMm:24,pixelUm:6.4,year:2008},{id:"eos-5d-iii",name:"Canon EOS 5D Mark III (full frame)",widthMm:36,heightMm:24,pixelUm:6.25,year:2012},{id:"eos-5d-iv",name:"Canon EOS 5D Mark IV (full frame)",widthMm:36,heightMm:24,pixelUm:5.36,year:2016},{id:"eos-6d",name:"Canon EOS 6D (full frame)",widthMm:35.8,heightMm:23.9,pixelUm:6.55,year:2012},{id:"eos-6d-ii",name:"Canon EOS 6D Mark II (full frame)",widthMm:36,heightMm:24,pixelUm:5.77,year:2017},{id:"nikon-d3",name:"Nikon D3 / D700 (full frame)",widthMm:36,heightMm:23.9,pixelUm:8.44,year:2007},{id:"nikon-d7000",name:"Nikon D7000 (DX)",widthMm:23.6,heightMm:15.6,pixelUm:4.78,year:2010},{id:"nikon-d7100",name:"Nikon D7100 / D7200 (DX)",widthMm:23.5,heightMm:15.6,pixelUm:3.9,year:2013},{id:"nikon-d500",name:"Nikon D500 / D7500 (DX)",widthMm:23.5,heightMm:15.7,pixelUm:4.2,year:2016}];static instruments(){return Yo.BODIES.map(t=>({id:t.id,category:"dslr",name:t.name,projection:"rectilinear",frame:{widthMm:t.widthMm,heightMm:t.heightMm,focalLengthMm:Yo.DEFAULT_FOCAL_MM,focalRangeMm:Yo.FOCAL_RANGE_MM},fNumber:8,fNumberRange:{min:1.4,max:22},exposureSeconds:1/250,exposureRangeSeconds:{min:1/8e3,max:3600},years:{from:t.year},apertureBlades:7,detailUm:t.pixelUm,medium:{kind:"sensor",iso:100}}))}static names(){return Object.fromEntries(Yo.BODIES.map(t=>[t.id,t.name]))}}class Ts{static DEFAULT_EYEPIECE_MM=26;static DEFAULT_APPARENT_FIELD_DEG=52;static FIELD_STOP_MM=2*Ts.DEFAULT_EYEPIECE_MM*Math.tan(Ts.DEFAULT_APPARENT_FIELD_DEG*Math.PI/360);static RANGE={min:26/40*.63,max:26/6*3};static BINOCULARS=[{id:"binoculars-zeiss-6x30",name:"Carl Zeiss 6x30",magnification:6,apertureMm:30,trueFieldDeg:5,fromYear:1960},{id:"binoculars-zeiss-dialyt-10x40",name:"Carl Zeiss Dialyt 10x40 B T*",magnification:10,apertureMm:40,trueFieldDeg:6.3,fromYear:1975},{id:"binoculars-jenoptem-10x50",name:"Jenoptem 10x50 W",magnification:10,apertureMm:50,trueFieldDeg:7.3,fromYear:1960},{id:"binoculars-swarovski-7x50-habicht",name:"Swarovski 7x50 SL Habicht",magnification:7,apertureMm:50,trueFieldDeg:6.6,fromYear:1960},{id:"binoculars-swarovski-7x50-slc",name:"Swarovski 7x50 SLC",magnification:7,apertureMm:50,trueFieldDeg:7.1,fromYear:1990},{id:"binoculars-nikon-10x42-edg",name:"Nikon 10x42 EDG",magnification:10,apertureMm:42,trueFieldDeg:6.5,fromYear:2011},{id:"binoculars-canon-15x50-is",name:"Canon 15x50 IS All Weather",magnification:15,apertureMm:50,trueFieldDeg:4.5,fromYear:2008},{id:"binoculars-celestron-15x70",name:"Celestron 15x70 SkyMaster",magnification:15,apertureMm:70,trueFieldDeg:4.4,fromYear:1990},{id:"binoculars-miyauchi-25x141",name:"Miyauchi BR-141 Galaxy 45 25x141",magnification:25,apertureMm:141,trueFieldDeg:2.6,fromYear:2e3}];static TELESCOPES=[{id:"telescope-generic-60-700",name:"Telescope 60/700",apertureMm:60,focalLengthMm:700},{id:"telescope-generic-60-1000",name:"Telescope 60/1000",apertureMm:60,focalLengthMm:1e3},{id:"telescope-celestron-onyx-80edf",name:"Celestron Onyx 80EDF",apertureMm:80,focalLengthMm:500,fromYear:2010},{id:"telescope-celestron-c5",name:"Celestron C5 f/10",apertureMm:125,focalLengthMm:1250,fromYear:1970},{id:"telescope-celestron-c8",name:"Celestron C8 f/10",apertureMm:203,focalLengthMm:2032,fromYear:1970},{id:"telescope-celestron-c11",name:"Celestron C11 f/10",apertureMm:280,focalLengthMm:2800,fromYear:1970},{id:"telescope-celestron-c14",name:"Celestron C14 f/11",apertureMm:355.6,focalLengthMm:3910,fromYear:1970},{id:"telescope-meade-etx-80",name:"Meade ETX 80 f/5",apertureMm:80,focalLengthMm:400,fromYear:1996},{id:"telescope-meade-etx-90",name:"Meade ETX 90 f/13.8",apertureMm:90,focalLengthMm:1242,fromYear:1996},{id:"telescope-meade-etx-125",name:"Meade ETX 125 f/15",apertureMm:127,focalLengthMm:1900,fromYear:1996},{id:"telescope-meade-lx200-8",name:"Meade LX200 8 in f/10",apertureMm:200,focalLengthMm:2e3,fromYear:1992},{id:"telescope-meade-lx200-10",name:"Meade LX200 10 in f/10",apertureMm:250,focalLengthMm:2500,fromYear:1992},{id:"telescope-meade-lx200-12",name:"Meade LX200 12 in f/10",apertureMm:305,focalLengthMm:3048,fromYear:1992},{id:"telescope-meade-lx200-14",name:"Meade LX200 14 in f/10",apertureMm:355,focalLengthMm:3556,fromYear:1992},{id:"telescope-meade-lx200-16",name:"Meade LX200 16 in f/10",apertureMm:406,focalLengthMm:4064,fromYear:1992}];static instruments(){const t=Ts.BINOCULARS.map(n=>({id:n.id,category:"binoculars",name:n.name,projection:"rectilinear",visualAid:{apertureMm:n.apertureMm,magnification:n.magnification,trueFieldDeg:n.trueFieldDeg},...n.fromYear!==void 0?{years:{from:n.fromYear}}:{}})),e=Ts.FIELD_STOP_MM,i=Ts.TELESCOPES.map(n=>({id:n.id,category:"telescope",name:n.name,projection:"rectilinear",frame:{widthMm:e*16/9,heightMm:e,focalLengthMm:n.focalLengthMm,focalRangeMm:{minMm:n.focalLengthMm*Ts.RANGE.min,maxMm:n.focalLengthMm*Ts.RANGE.max}},visualAid:{apertureMm:n.apertureMm,eyepieceFocalMm:Ts.DEFAULT_EYEPIECE_MM},...n.fromYear!==void 0?{years:{from:n.fromYear}}:{}}));return[...t,...i]}static names(){return Object.fromEntries(Ts.instruments().map(t=>[t.id,t.name]))}}const nl=[{id:"eye",category:"eye",name:"Naked eye",projection:"equidistant",stabilization:.97},{id:"rectilinear-lens",category:"camera",name:"Camera, unknown device",projection:"rectilinear",fNumber:8,fNumberRange:{min:2,max:22},exposureSeconds:1/250,exposureRangeSeconds:{min:1/1e3,max:8},apertureBlades:6},{id:"roamer-1-120",category:"camera",name:"Roamer 1, 120 film",projection:"rectilinear",frame:{widthMm:74,heightMm:60,focalLengthMm:100},fNumber:11,exposureSeconds:1/50,years:{from:1930,to:1965},detailUm:40,medium:{kind:"negative",iso:125}},{id:"instamatic-126",category:"camera",name:"Instamatic, 126 film",projection:"rectilinear",frame:{widthMm:28,heightMm:28,focalLengthMm:43},fNumber:11,exposureSeconds:1/90,years:{from:1963,to:1988},apertureBlades:5,detailUm:20,medium:{kind:"negative",iso:64}},{id:"slr-35mm-50",category:"camera",name:"35 mm SLR, 50 mm lens",projection:"rectilinear",frame:{widthMm:36,heightMm:24,focalLengthMm:50},fNumber:8,fNumberRange:{min:2,max:16},exposureSeconds:1/250,exposureRangeSeconds:{min:1/1e3,max:3600},years:{from:1959},apertureBlades:6,detailUm:20,medium:{kind:"negative",iso:100}},{id:"slr-35mm-zoom",category:"camera",name:"35 mm SLR, 70-210 mm zoom",projection:"rectilinear",frame:{widthMm:36,heightMm:24,focalLengthMm:135,focalRangeMm:{minMm:70,maxMm:210}},fNumber:8,fNumberRange:{min:4,max:22},exposureSeconds:1/250,exposureRangeSeconds:{min:1/1e3,max:3600},apertureBlades:8,years:{from:1975},detailUm:20,medium:{kind:"negative",iso:100}},{id:"phone-landscape",category:"phone",name:"Phone, held sideways",projection:"rectilinear",frame:{widthMm:7.6,heightMm:5.7,focalLengthMm:5.7},fNumber:1.8,exposureSeconds:1/120,exposureRangeSeconds:{min:1/8e3,max:10},years:{from:2007},apertureBlades:void 0,detailUm:1.4,medium:{kind:"sensor",iso:100,autoExposure:!0,maxIso:3200,metering:"highlights",development:"computational"}},{id:"phone-portrait",category:"phone",name:"Phone, held upright",projection:"rectilinear",frame:{widthMm:5.7,heightMm:7.6,focalLengthMm:5.7},fNumber:1.8,exposureSeconds:1/120,exposureRangeSeconds:{min:1/8e3,max:10},years:{from:2007},apertureBlades:void 0,detailUm:1.4,medium:{kind:"sensor",iso:100,autoExposure:!0,maxIso:3200,metering:"highlights",development:"computational"}},{id:"dashcam",mounted:!0,category:"video",name:"Dashcam",projection:"equidistant",frame:{widthMm:5.76,heightMm:3.24,focalLengthMm:3.2},fNumber:2,exposureSeconds:1/30,exposureRangeSeconds:{min:1/1e4,max:1/30},years:{from:2008},apertureBlades:void 0,detailUm:3,medium:{kind:"sensor",iso:100,autoExposure:!0,maxIso:1600,metering:"average",exposureFollowMs:500}},{id:"cctv",mounted:!0,category:"video",name:"Security camera",projection:"rectilinear",frame:{widthMm:4.8,heightMm:3.6,focalLengthMm:3.6},fNumber:2,exposureSeconds:1/50,exposureRangeSeconds:{min:1/1e5,max:1/50},years:{from:1990},apertureBlades:void 0,detailUm:6,medium:{kind:"sensor",iso:100,autoExposure:!0,maxIso:1600,metering:"average",exposureFollowMs:500}},...Yo.instruments(),...Ts.instruments()];class Ii{static get default(){return nl[0]}static byId(t){return nl.find(e=>e.id===t)??this.default}static UNAIDED_FIELD_DEG=60;static UNAIDED_ASPECT=16/9;static fieldOfViewDeg(t){const e=t.frame;return e?Ii.fieldOf(t.projection,e.heightMm,e.focalLengthMm):t.visualAid?.trueFieldDeg??Ii.UNAIDED_FIELD_DEG}static fieldOf(t,e,i){return(t==="equidistant"?e/i:2*Math.atan(e/(2*i)))*180/Math.PI}static aspectOf(t){const e=t.frame;return e?e.widthMm/e.heightMm:Ii.UNAIDED_ASPECT}static frameWidthPx(t,e){return Math.round(e*Ii.aspectOf(t))}static CATEGORIES=["eye","camera","dslr","phone","video","binoculars","telescope"];static unavailability(t,e){const i=t.years;if(!(e===void 0||!i)){if(e<i.from)return{kind:"before",from:i.from};if(i.to!==void 0&&e>i.to)return{kind:"after",to:i.to}}}static availableAt(t){return t===void 0?nl:nl.filter(e=>!e.years||t>=e.years.from&&(e.years.to===void 0||t<=e.years.to))}static fieldOfViewDegAt(t,e){const i=t.frame;if(!(!i||e<=0))return Ii.fieldOf(t.projection,i.heightMm,e)}static focalLengthMmFor(t,e){const i=t.frame;if(!(!i||e<=0||e>=180))return t.projection==="equidistant"?i.heightMm/(e*Math.PI/180):i.heightMm/(2*Math.tan(e*Math.PI/360))}static bladesShowing(t,e){if(t.apertureBlades===void 0)return 0;const i=e??t.fNumber,n=t.fNumberRange?.min;if(i===void 0||n===void 0)return 1;const s=Math.max(0,Math.min(1,(i/n-1)/.3));return s*s*(3-2*s)}static starPointsOf(t,e){const i=t.apertureBlades;return i===void 0||i<3||Ii.bladesShowing(t,e)<.5?0:i%2===0?i:i*2}}class hc{constructor(t){this.points=t}static STATIONARY_M=5;static of(t){const e=[];for(const i of t.observerTrack.allKeyframes){const{lat:n,lng:s,headingDeg:a}=i.pose;n===void 0||s===void 0||e.push({t:i.t,lat:n,lng:s,headingDeg:a})}if(e.length===0){const i=t.event.place?.[0];if(!i)return;e.push({t:0,lat:i.lat,lng:i.lng})}return new hc(e)}static TRAVEL_M=50;get travels(){return this.spanM>hc.TRAVEL_M}get moved(){return this.spanM>hc.STATIONARY_M}get spanM(){const t=this.box,e=(t.south+t.north)/2,i=(t.west+t.east)/2;return Math.max(Math.abs(ae(e,t.east,e,t.west).x),Math.abs(ae(t.north,i,t.south,i).z))}get center(){const t=this.box;return{lat:(t.south+t.north)/2,lng:(t.west+t.east)/2}}boundsAround(t,e){const{lat:i,lng:n}=this.center,s=Math.max(this.spanM*(1+e),t)/2;return{north:Kn(0,-s,i,n).lat,south:Kn(0,s,i,n).lat,east:Kn(s,0,i,n).lng,west:Kn(-s,0,i,n).lng}}get box(){const t=this.points.map(i=>i.lat),e=this.points.map(i=>i.lng);return{south:Math.min(...t),north:Math.max(...t),west:Math.min(...e),east:Math.max(...e)}}}class ds{constructor(t,e){this.rotationPassed=t,this.scale=e}static SWAY_M=.012;static BREATH_M=.003;static DRIFT_YAW_DEG=.5;static DRIFT_PITCH_DEG=.4;static DRIFT_ROLL_DEG=.3;static GAZE_DRIFT_SHARE=.35;static HAND_HELD_S=.5;static HZ=[.11,.23,.17,.29,.37,.07];static of(t){if(t.instrument.mounted)return;const e=t.event.tags?.includes("paralysis")||(t.exposure??0)>ds.HAND_HELD_S,i=t.sway??(e?0:1);if(i>0)return new ds(Math.max(1-(t.instrument.stabilization??0),ds.GAZE_DRIFT_SHARE),i)}offsetAt(t){const e=t/1e3,i=this.scale,n=(u,d)=>Math.sin(2*Math.PI*u*e+d),[s,a,r,c,h,l]=ds.HZ;return{eastM:i*ds.SWAY_M*(.7*n(s,.3)+.3*n(c,1.9)),northM:i*ds.SWAY_M*(.6*n(r,2.2)+.4*n(h,.8)),upM:i*ds.BREATH_M*n(a,0),yawDeg:i*this.rotationPassed*ds.DRIFT_YAW_DEG*(.6*n(l,1.1)+.4*n(c,2.7)),pitchDeg:i*this.rotationPassed*ds.DRIFT_PITCH_DEG*(.5*n(a,1.6)+.5*n(r,.4)),rollDeg:i*this.rotationPassed*ds.DRIFT_ROLL_DEG*n(s,2.9)}}}class Ye{constructor(t,e){this.stretches=t,this.rotationPassed=e}static REFERENCE_SPEED_M_PER_S=1.4;static REFERENCE_STEP_HZ=1.9;static CADENCE_EXPONENT=.43;static RISE_M_PER_M_PER_S=.0175;static SWAY_M=.0175;static SLOWEST_WALK_M_PER_S=.2;static FASTEST_WALK_M_PER_S=2.2;static HEAD_ROLL_DEG=1.5;static HEAD_PITCH_DEG=1.25;static HEAD_YAW_DEG=1;static STOP_LURCH_M=.035;static STOP_PITCH_DEG=3;static START_LURCH_M=.015;static START_PITCH_DEG=1.2;static JOLT_HZ=1.4;static JOLT_DECAY_S=.35;static JOLT_LASTS_MS=1500;static STILL=Object.freeze({eastM:0,northM:0,upM:0,rollDeg:0,pitchDeg:0,yawDeg:0});static of(t){const e=hc.of(t);if(!e||e.points.length<2)return;const i=[];let n=0;for(let s=1;s<e.points.length;s++){const a=e.points[s-1],r=e.points[s],c=(r.t-a.t)/1e3;if(c<=0)continue;const h=ae(r.lat,r.lng,a.lat,a.lng),l=h.x,u=-h.z,d=Math.hypot(l,u),f=d/c,p=Ye.stepHzFor(f);i.push({startMs:a.t,endMs:r.t,speedMPerS:f,eastUnit:d>0?l/d:0,northUnit:d>0?u/d:0,stepHz:p,stepsBefore:n,rampsIn:!0,rampsOut:!0}),n+=p*c}for(let s=0;s<i.length;s++){const a=i[s-1],r=i[s+1];i[s].rampsIn=a===void 0||a.stepHz===0,i[s].rampsOut=r===void 0||r.stepHz===0}if(i.some(s=>s.stepHz>0))return new Ye(i,1-(t.instrument.stabilization??0))}static bodyAt(t,e,i=!1){const n=Ye.of(t)?.offsetAt(e)??Ye.STILL;return i?n:Ye.add(n,ds.of(t)?.offsetAt(e))}static stepHzFor(t){return t<Ye.SLOWEST_WALK_M_PER_S||t>Ye.FASTEST_WALK_M_PER_S?0:Ye.REFERENCE_STEP_HZ*Math.pow(t/Ye.REFERENCE_SPEED_M_PER_S,Ye.CADENCE_EXPONENT)}offsetAt(t){return Ye.add(this.cycleAt(t),this.joltAt(t))}joltAt(t){for(const e of this.stretches){if(e.stepHz===0)continue;const i=e.speedMPerS/Ye.REFERENCE_SPEED_M_PER_S,n=(r,c,h,l)=>{if(r<0||r>Ye.JOLT_LASTS_MS)return;const u=r/1e3,d=Math.exp(-u/Ye.JOLT_DECAY_S)*Math.sin(2*Math.PI*Ye.JOLT_HZ*u),f=l*c*i*d;return{eastM:f*e.eastUnit,northM:f*e.northUnit,upM:-Math.abs(f)*.3,rollDeg:0,pitchDeg:-l*h*i*d*this.rotationPassed,yawDeg:0}},s=e.rampsOut?n(t-e.endMs,Ye.STOP_LURCH_M,Ye.STOP_PITCH_DEG,1):void 0;if(s)return s;const a=e.rampsIn?n(t-e.startMs,Ye.START_LURCH_M,Ye.START_PITCH_DEG,-1):void 0;if(a)return a}}static add(t,e){return e?{eastM:t.eastM+e.eastM,northM:t.northM+e.northM,upM:t.upM+e.upM,rollDeg:t.rollDeg+e.rollDeg,pitchDeg:t.pitchDeg+e.pitchDeg,yawDeg:t.yawDeg+e.yawDeg}:t}cycleAt(t){const e=this.stretches.find(c=>t>=c.startMs&&t<=c.endMs);if(!e||e.stepHz===0)return Ye.STILL;const i=e.stepsBefore+e.stepHz*(t-e.startMs)/1e3,n=2*Math.PI*i,s=this.amplitudeAt(e,t),a=Ye.SWAY_M*s*Math.cos(n/2),r=s*this.rotationPassed*e.speedMPerS/Ye.REFERENCE_SPEED_M_PER_S;return{eastM:a*e.northUnit,northM:-a*e.eastUnit,upM:Ye.RISE_M_PER_M_PER_S*e.speedMPerS*s*Math.cos(n),rollDeg:Ye.HEAD_ROLL_DEG*r*Math.cos(n/2),pitchDeg:-1.25*r*Math.cos(n),yawDeg:Ye.HEAD_YAW_DEG*r*Math.cos(n/2)}}amplitudeAt(t,e){const i=1e3/t.stepHz,n=Math.min(i,(t.endMs-t.startMs)/2);if(n<=0)return 1;const s=e-t.startMs,a=t.endMs-e,r=Math.min(t.rampsIn?s/n:1,t.rampsOut?a/n:1,1);return(1-Math.cos(Math.PI*Math.max(r,0)))/2}}class dh{static ISO=/^P(?:(\d+(?:[.,]\d+)?)W)?(?:(\d+(?:[.,]\d+)?)D)?(?:T(?:(\d+(?:[.,]\d+)?)H)?(?:(\d+(?:[.,]\d+)?)M)?(?:(\d+(?:[.,]\d+)?)S)?)?$/;static seconds(t){const e=t.trim().toUpperCase(),i=dh.ISO.exec(e);if(!i||e==="P"||e.endsWith("T"))return;const[,n,s,a,r,c]=i,h=u=>u===void 0?0:Number(u.replace(",",".")),l=h(n)*604800+h(s)*86400+h(a)*3600+h(r)*60+h(c);return Number.isFinite(l)?l:void 0}static parse(t){let e=t.trim();if(e==="")return;const i=e.slice(-1),n="?~%".includes(i)?i:"";n!==""&&(e=e.slice(0,-1).trim());const s=e.split("/");if(s.length>2)return;const a=s.map(u=>dh.seconds(u));if(a.some(u=>u===void 0))return;const[r,c]=a,h=Math.min(r,c??r),l=Math.max(r,c??r);return{doubt:n,minSeconds:h,maxSeconds:l,chosenSeconds:(h+l)/2}}static isExact(t){const e=dh.parse(t);return e!==void 0&&e.doubt===""&&e.minSeconds===e.maxSeconds}static format(t){const e=Math.max(0,Math.round(t*10)/10),i=Math.floor(e/3600),n=Math.floor(e%3600/60),s=Math.round(e%60*10)/10;return`PT${`${i>0?`${i}H`:""}${n>0?`${n}M`:""}${s>0||i===0&&n===0?`${s}S`:""}`}`}static say(t){const e=Math.round(t*10)/10;if(e<60)return`${e} s`;const i=Math.floor(e/3600),n=Math.floor(e%3600/60),s=Math.round(e%60*10)/10,a=[];return i>0&&a.push(`${i} h`),n>0&&a.push(`${n} min`),s>0&&a.push(`${s} s`),a.join(" ")}}class Ze{static MOON_ANGULAR_WIDTH_DEG=.5237;static CANVAS_WIDTH_PX=640;static CANVAS_HEIGHT_PX=360;static angularWidthDeg(t){return 2*Math.atan(t.sizeM/(2*t.distanceM))*180/Math.PI}static inMoons(t){return t/Ze.MOON_ANGULAR_WIDTH_DEG}static lerpAngular(t,e,i){if(!(!t||!e))return{widthDeg:t.widthDeg+(e.widthDeg-t.widthDeg)*i,heightDeg:t.heightDeg+(e.heightDeg-t.heightDeg)*i}}static sizeMAt(t,e){return 2*t*Math.tan(e*Math.PI/360)}static distanceMAt(t,e){return t/(2*Math.tan(e*Math.PI/360))}}function jy(o,t,e){if(!o||!t)return e<1?o:t;const i=((t.azimuthDeg-o.azimuthDeg)%360+540)%360-180;return{azimuthDeg:((o.azimuthDeg+i*e)%360+360)%360,altitudeDeg:o.altitudeDeg+(t.altitudeDeg-o.altitudeDeg)*e}}function Qy(o,t,e){const{bounds:i}=o;return t>=i.x&&t<=i.x+i.width&&e>=i.y&&e<=i.y+i.height}function Vn(o,t,e){return o+(t-o)*e}function Zm(o){const t=/^#([0-9a-f]{6})$/i.exec(o);if(!t)return;const e=parseInt(t[1],16);return[e>>16&255,e>>8&255,e&255]}function tx(o){return`#${o.map(t=>Math.round(t).toString(16).padStart(2,"0")).join("")}`}function ex(o,t,e){const i=Zm(o),n=Zm(t);return!i||!n?e<1?o:t:tx([Vn(i[0],n[0],e),Vn(i[1],n[1],e),Vn(i[2],n[2],e)])}function ix(o,t,e){const i={x:Vn(o.bounds.x,t.bounds.x,e),y:Vn(o.bounds.y,t.bounds.y,e),width:Vn(o.bounds.width,t.bounds.width,e),height:Vn(o.bounds.height,t.bounds.height,e)},n=Vn(o.angle,t.angle,e),s=Vn(o.transparency,t.transparency,e),a=Vn(o.haloScale,t.haloScale,e),r=Vn(o.blur??0,t.blur??0,e),c=Vn(o.brightness??0,t.brightness??0,e),h=ex(o.color,t.color,e),l=Ze.lerpAngular(o.angular,t.angular,e),u=jy(o.aim,t.aim,e);return o.kind==="polygon"&&t.kind==="polygon"&&o.points.length===t.points.length?{...o,bounds:i,angle:n,transparency:s,haloScale:a,blur:r,brightness:c,color:h,angular:l,aim:u,points:o.points.map((d,f)=>({x:Vn(d.x,t.points[f].x,e),y:Vn(d.y,t.points[f].y,e)}))}:{...e<1?o:t,bounds:i,angle:n,transparency:s,haloScale:a,blur:r,brightness:c,color:h,angular:l,aim:u}}class ir{static DEFAULT_COLOR="#e8e6df";static complete(t,e=[]){const i=new Map;return t.map((n,s)=>({keyframe:n,index:s})).sort((n,s)=>n.keyframe.t-s.keyframe.t).map(({keyframe:n,index:s})=>({t:n.t,shapes:(n.shapes??[]).map((a,r)=>{const c=`timeline.keyframes.${s}.shapes.${r}.shape`,h=ir.completed(a,i.get(a.sourceId),c,e);return i.set(a.sourceId,h),{sourceId:a.sourceId,shape:h}})}))}static thin(t,e){const i=new Map,n=new Set;return t.map((s,a)=>({t:s.t,shapes:s.shapes.map(r=>{const c=i.get(r.sourceId);if(i.set(r.sourceId,r.shape),!c)return{sourceId:r.sourceId,shape:r.shape};const h=ir.thinned(r.shape,c);if(e){const l=h;e(a,r.sourceId)?(delete l.bounds,delete l.points,n.add(r.sourceId)):n.delete(r.sourceId)&&(l.bounds=r.shape.bounds,r.shape.kind==="polygon"&&(l.points=r.shape.points),r.shape.aim&&(l.aim=r.shape.aim),r.shape.angular&&(l.angular=r.shape.angular))}return{sourceId:r.sourceId,shape:h}})}))}static thinned(t,e){const i=e,n={};for(const[s,a]of Object.entries(t))(typeof a=="object"&&a!==null&&!Array.isArray(a)&&"value"in a||a!==i[s]&&JSON.stringify(a)!==JSON.stringify(i[s]))&&(n[s]=a);return"bounds"in n&&(t.aim&&(n.aim=t.aim),t.angular&&(n.angular=t.angular)),n}static completed(t,e,i,n){const s=t.shape??{},a=e??ir.firstAppearance(s,i,n),r={...a};s.bounds&&e&&(e.aim||e.angular)&&!s.aim&&!s.angular&&n.push({kind:"pixels-over-angles",path:i}),s.bounds&&(s.aim||delete r.aim,s.angular||delete r.angular);const c=s.kind??a.kind??"oval",h={...r,...s,kind:c};if(c==="polygon"&&!h.points){n.push({kind:"defaulted",path:`${i}.points`,expected:"rectangle"});const{width:l,height:u}=h.bounds;return{...h,points:[{x:0,y:0},{x:l,y:0},{x:l,y:u},{x:0,y:u}]}}return h}static firstAppearance(t,e,i){return t.kind||i.push({kind:"defaulted",path:`${e}.kind`,expected:'"oval"'}),t.color||i.push({kind:"defaulted",path:`${e}.color`,expected:`"${ir.DEFAULT_COLOR}"`}),!t.bounds&&!t.aim&&i.push({kind:"unplaced",path:e}),!t.bounds&&!t.angular&&i.push({kind:"unsized",path:e}),{kind:t.kind??"oval",bounds:{...ir.NEUTRAL_BOUNDS},color:ir.DEFAULT_COLOR,angle:0,transparency:0,haloScale:0,selected:!1}}static NEUTRAL_BOUNDS={x:Ze.CANVAS_WIDTH_PX/2,y:Ze.CANVAS_HEIGHT_PX/2,width:1,height:1}}class od{keyframes=[];order=[];groups=[];span=0;addKeyframe(t,e){const i=this.findInsertIndex(t);if(this.keyframes[i]?.t===t){const n=new Set(e.map(s=>s.sourceId));this.keyframes[i]={t,shapes:[...this.keyframes[i].shapes.filter(s=>!n.has(s.sourceId)),...e]}}else this.keyframes.splice(i,0,{t,shapes:[...e]});for(const n of e)this.order.includes(n.sourceId)||this.order.push(n.sourceId)}findInsertIndex(t){let e=0,i=this.keyframes.length;for(;e<i;){const n=e+i>>>1;this.keyframes[n].t<t?e=n+1:i=n}return e}getKeyframeAt(t){const e=this.findInsertIndex(t),i=this.keyframes[e];return i?.t===t?i:void 0}getShapeAt(t,e){return this.getKeyframeAt(t)?.shapes.find(i=>i.sourceId===e)?.shape}getLatestShapeAt(t,e){let i=this.findInsertIndex(t);for(this.keyframes[i]?.t!==t&&(i-=1);i>=0;i--){const n=this.keyframes[i].shapes.find(s=>s.sourceId===e);if(n)return n.shape}}getInterpolatedShapeAt(t,e){const i=this.findShapeAtOrBefore(t,e);if(i?.t===t)return i.shape;const n=this.findShapeAtOrAfter(t,e);return i?n?ix(i.shape,n.shape,(t-i.t)/(n.t-i.t)):i.shape:n?.shape}findShapeAtOrBefore(t,e){let i=this.findInsertIndex(t);for(this.keyframes[i]?.t!==t&&(i-=1);i>=0;i--){const n=this.keyframes[i].shapes.find(s=>s.sourceId===e);if(n)return{t:this.keyframes[i].t,shape:n.shape}}}findShapeAtOrAfter(t,e){for(let i=this.findInsertIndex(t);i<this.keyframes.length;i++){const n=this.keyframes[i].shapes.find(s=>s.sourceId===e);if(n)return{t:this.keyframes[i].t,shape:n.shape}}}hitTest(t,e,i,n){const s=this.sourceIds;for(let a=s.length-1;a>=0;a--){if(n?.has(s[a]))continue;const r=this.getInterpolatedShapeAt(t,s[a]);if(r&&Qy(r,e,i))return{sourceId:s[a],shape:r}}}removeSource(t){for(let e=this.keyframes.length-1;e>=0;e--){const i=this.keyframes[e].shapes.filter(n=>n.sourceId!==t);i.length===0?this.keyframes.splice(e,1):i.length!==this.keyframes[e].shapes.length&&(this.keyframes[e]={t:this.keyframes[e].t,shapes:i})}this.order=this.order.filter(e=>e!==t),this.removeFromGroup(t)}removeShapeAt(t,e){const i=this.findInsertIndex(t),n=this.keyframes[i];if(n?.t!==t)return;const s=n.shapes.filter(a=>a.sourceId!==e);s.length===0?this.keyframes.splice(i,1):s.length!==n.shapes.length&&(this.keyframes[i]={t,shapes:s})}group(t){if(!(t.length<2)){for(const e of t)this.removeFromGroup(e);this.groups.push([...t])}}ungroup(t){const e=this.groups.findIndex(i=>i.includes(t));e!==-1&&this.groups.splice(e,1)}groupMembers(t){return this.groups.find(e=>e.includes(t))}removeFromGroup(t){const e=this.groups.findIndex(n=>n.includes(t));if(e===-1)return;const i=this.groups[e].filter(n=>n!==t);i.length<2?this.groups.splice(e,1):this.groups[e]=i}bringToFront(t){const e=this.order.indexOf(t);e!==-1&&(this.order.splice(e,1),this.order.push(t))}sendToBack(t){const e=this.order.indexOf(t);e!==-1&&(this.order.splice(e,1),this.order.unshift(t))}get duration(){const t=this.keyframes.length===0?0:this.keyframes[this.keyframes.length-1].t;return Math.max(t,this.span)}get hasSpan(){return this.span>0}setSpan(t){this.span=Math.max(0,t)}get sourceIds(){return[...this.order]}get allKeyframes(){return this.keyframes}toJSON(){return this.span>0?{keyframes:this.keyframes,order:this.order,groups:this.groups,span:this.span}:{keyframes:this.keyframes,order:this.order,groups:this.groups}}static fromJSON(t,e){const i=new od;for(const n of ir.complete(t.keyframes??[],e))i.addKeyframe(n.t,n.shapes);if(t.span!==void 0&&t.span>0&&(i.span=t.span),t.order){const n=i.order.filter(s=>!t.order.includes(s));i.order=[...t.order,...n]}return t.groups&&(i.groups=t.groups.map(n=>n.filter(s=>i.order.includes(s))).filter(n=>n.length>=2)),i}}function nx(o,t,e){return Math.max(t,Math.min(e,o))}function sx(o,t,e){const i=((t-o)%360+540)%360-180;return((o+i*e)%360+360)%360}function po(o,t,e){return o+(t-o)*e}function ax(o,t,e){return{lat:o.lat===void 0||t.lat===void 0?void 0:po(o.lat,t.lat,e),lng:o.lng===void 0||t.lng===void 0?void 0:po(o.lng,t.lng,e),elevationM:po(o.elevationM,t.elevationM,e),headingDeg:o.headingDeg===void 0||t.headingDeg===void 0?void 0:sx(o.headingDeg,t.headingDeg,e),pitchDeg:po(o.pitchDeg,t.pitchDeg,e),rollDeg:po(o.rollDeg??0,t.rollDeg??0,e),fovDeg:po(o.fovDeg,t.fovDeg,e),fNumber:o.fNumber,focusDistanceM:o.focusDistanceM,filter:o.filter}}class vn{static at(t,e,i,n,s){const a=t[i],c=t[i+1]-a;if(c<=0)return e[i];const h=vn.tangent(t,e,i,s),l=vn.tangent(t,e,i+1,s),u=(n-a)/c,d=u*u,f=d*u;return(2*f-3*d+1)*e[i]+(f-2*d+u)*c*h+(-2*f+3*d)*e[i+1]+(f-d)*c*l}static SETTLE_MS=120;static ARRIVAL=.5;static gaze(t,e,i,n){const s=t[i],r=t[i+1]-s;if(r<=0)return e[i];const c=l=>l+1<e.length?e[l+1]===e[l]:!0,h=e[i+1]!==e[i];if(h&&c(i+1)){const l=vn.tangent(t,e,i,!0),u=vn.ARRIVAL*(e[i+1]-e[i])/r;return vn.hermite(e[i],l,e[i+1],u,r,(n-s)/r)}return!h&&i>0&&e[i-1]!==e[i]?e[i]+vn.settle(t,e,i,n-s,r):vn.at(t,e,i,n,!0)}static settle(t,e,i,n,s){const a=t[i]-t[i-1];if(a<=0||n<=0)return 0;const r=vn.ARRIVAL*(e[i]-e[i-1])/a,c=Math.min(vn.SETTLE_MS,.4*a),h=Number.isFinite(s)?(1-Math.min(1,n/s))**2:1;return r*n*Math.exp(-n/c)*h}static hermite(t,e,i,n,s,a){const r=a*a,c=r*a;return(2*c-3*r+1)*t+(c-2*r+a)*s*e+(-2*c+3*r)*i+(c-r)*s*n}static BRAKE_S=.8;static paced(t,e,i,n){if(!i&&!n)return t;const s=e>0?Math.min(.5,vn.BRAKE_S/e):.5;if(i&&n){const r=1/(1-s);return t<=s?r*t*t/(2*s):t>=1-s?1-r*(1-t)*(1-t)/(2*s):r*(t-s/2)}const a=r=>{const c=1/(1-s/2);if(r<=1-s)return c*r;const h=r-(1-s);return c*(1-s)+c*(h-h*h/(2*s))};return n?a(t):1-a(1-t)}static tangent(t,e,i,n){const s=t.length-1,a=f=>(e[f+1]-e[f])/(t[f+1]-t[f]||1);if(i===0)return n?0:a(0);if(i===s)return n?0:a(s-1);const r=a(i-1),c=a(i);if(r*c<=0)return 0;const h=t[i]-t[i-1],l=t[i+1]-t[i],u=2*l+h,d=l+2*h;return(u+d)/(u/r+d/c)}}class Nh{keyframes=[];addKeyframe(t,e){const i=this.findInsertIndex(t);this.keyframes[i]?.t===t?this.keyframes[i]={t,pose:e}:this.keyframes.splice(i,0,{t,pose:e})}clear(){this.keyframes.length=0}removeKeyframeAt(t){const e=this.findInsertIndex(t);this.keyframes[e]?.t===t&&this.keyframes.splice(e,1)}findInsertIndex(t){let e=0,i=this.keyframes.length;for(;e<i;){const n=e+i>>>1;this.keyframes[n].t<t?e=n+1:i=n}return e}getLatestPoseAt(t){let e=this.findInsertIndex(t);return this.keyframes[e]?.t!==t&&(e-=1),e>=0?this.keyframes[e].pose:void 0}getInterpolatedPoseAt(t){const e=this.findInsertIndex(t),i=this.keyframes[e]?.t===t?this.keyframes[e]:this.keyframes[e-1];if(i?.t===t)return i.pose;const n=this.keyframes[e]?.t===t?void 0:this.keyframes[e];if(!i)return n?.pose;if(!n)return this.settledAfterEnd(e-1,t);const s=ax(i.pose,n.pose,nx((t-i.t)/(n.t-i.t),0,1));return this.humanly(e-1,t,s)}settledAfterEnd(t,e){const i=this.keyframes[t];if(t<1)return i.pose;const n=this.keyframes[t-1],s=[n.t,i.t],a=(l,u)=>l===void 0||u===void 0?0:vn.settle(s,[l,u],1,e-i.t,1/0),r=n.pose.headingDeg===void 0||i.pose.headingDeg===void 0?void 0:((i.pose.headingDeg-n.pose.headingDeg)%360+540)%360-180,c=i.pose.headingDeg===void 0||r===void 0?i.pose.headingDeg:((i.pose.headingDeg+a(0,r))%360+360)%360,h=i.pose.pitchDeg+a(n.pose.pitchDeg,i.pose.pitchDeg);return c===i.pose.headingDeg&&h===i.pose.pitchDeg?i.pose:{...i.pose,headingDeg:c,pitchDeg:h}}humanly(t,e,i){const n=Math.max(0,t-1),s=Math.min(this.keyframes.length-1,t+2),a=this.keyframes.slice(n,s+1),r=t-n,c=a.map(v=>v.t),h=(v,w)=>{const b=a.map(_=>v(_.pose));if(!b.some(_=>_===void 0))return vn.at(c,b,r,e,w)},l=v=>{const w=a.map(b=>v(b.pose));if(!w.some(b=>b===void 0))return vn.gaze(c,w,r,e)},u=a.map(v=>v.pose.headingDeg);let d;if(u.every(v=>v!==void 0)){const v=[u[0]];for(let w=1;w<u.length;w++)v.push(v[w-1]+((u[w]-u[w-1])%360+540)%360-180);d=(vn.gaze(c,v,r,e)%360+360)%360}const f=this.keyframes[t],p=this.keyframes[t+1],g=(v,w)=>v.lat===w.lat&&v.lng===w.lng&&v.elevationM===w.elevationM,m=!g(f.pose,p.pose),M=m&&t>0&&g(this.keyframes[t-1].pose,f.pose),y=m&&t+2<this.keyframes.length&&g(p.pose,this.keyframes[t+2].pose);let x;if(M||y){const v=vn.paced((e-f.t)/(p.t-f.t),(p.t-f.t)/1e3,M,y),w=(b,_)=>b===void 0||_===void 0?void 0:b+(_-b)*v;x={lat:w(f.pose.lat,p.pose.lat),lng:w(f.pose.lng,p.pose.lng),elevationM:w(f.pose.elevationM,p.pose.elevationM)}}return{...i,lat:x?x.lat:h(v=>v.lat,!1)??i.lat,lng:x?x.lng:h(v=>v.lng,!1)??i.lng,elevationM:x?x.elevationM:h(v=>v.elevationM,!1)??i.elevationM,headingDeg:d??i.headingDeg,pitchDeg:l(v=>v.pitchDeg)??i.pitchDeg,rollDeg:h(v=>v.rollDeg??0,!0)??i.rollDeg,fovDeg:h(v=>v.fovDeg,!0)??i.fovDeg}}get duration(){return this.keyframes.length===0?0:this.keyframes[this.keyframes.length-1].t}get allKeyframes(){return this.keyframes}toJSON(){return{keyframes:this.keyframes}}static fromJSON(t){const e=new Nh;for(const i of t.keyframes)e.addKeyframe(i.t,i.pose);return e}}class nr{static MAX_CHANGE_PER_S=.05;points;followed;constructor(t){let e="none",i=0;this.points=t.map(({t:n,weather:s})=>(s.precipitationType!=="none"&&(e=s.precipitationType,i=s.precipitationIntensity),{t:n,lastFalling:e,lastFallingIntensity:i,intensity:s.precipitationType==="none"?0:s.precipitationIntensity,type:s.precipitationType})),this.followed=[];for(let n=0;n<this.points.length;n++){if(n===0){this.followed.push(this.points[0].intensity);continue}const s=this.points[n-1],a=this.points[n];this.followed.push(nr.follow(this.followed[n-1],s.intensity,a.intensity,(a.t-s.t)/1e3,(a.t-s.t)/1e3))}}at(t){if(this.points.length===0||t<this.points[0].t)return;let e=this.points.length-1;for(;e>0&&this.points[e].t>t;)e--;const i=this.points[e],n=this.points[e+1],s=n?nr.follow(this.followed[e],i.intensity,n.intensity,(n.t-i.t)/1e3,(t-i.t)/1e3):nr.follow(this.followed[e],i.intensity,i.intensity,1,(t-i.t)/1e3);return{type:nr.typeBetween(i,n,t,s),intensity:s,character:nr.characterBetween(i,n,t)}}static characterBetween(t,e,i){return t.type==="none"?e&&e.type!=="none"?e.intensity:t.lastFallingIntensity:!e||e.type==="none"?t.intensity:t.intensity+(e.intensity-t.intensity)*(i-t.t)/(e.t-t.t||1)}static typeBetween(t,e,i,n){return t.type==="none"?e&&e.type!=="none"&&i>t.t?e.type:n>0?t.lastFalling:"none":e&&e.type==="none"&&n<=0?"none":t.type}static follow(t,e,i,n,s){const a=nr.MAX_CHANGE_PER_S,r=n>0?(i-e)/n:0,c=u=>e+r*Math.min(Math.max(u,0),n);let h=t,l=0;for(let u=0;u<8&&l<s;u++){const d=c(l)-h;if(Math.abs(d)<1e-9){const x=l<n?r:0;if(Math.abs(x)<=a){const w=l<n?Math.min(s,n):s;h=c(w),l=w;continue}const v=Math.min(s,n);h+=Math.sign(x)*a*(v-l),l=v;continue}const f=Math.sign(d),p=l<n?r:0,g=a-f*p,m=g>0?l+Math.abs(d)/g:1/0,M=l<n?n:1/0,y=Math.min(s,m,M);h+=f*a*(y-l),l=y,y===m&&(h=c(l))}return Math.min(1,Math.max(0,h))}}function ui(o,t,e){return o+(t-o)*e}function Fp(o,t,e){const i=((t-o)%360+540)%360-180;return((o+i*e)%360+360)%360}function rx(o,t,e){return Math.max(t,Math.min(e,o))}function ox(o=[],t=[],e){if(!(!o.length&&!t.length))return[...new Set([...o.map(i=>i.id),...t.map(i=>i.id)])].map(i=>{const n=o.find(c=>c.id===i),s=t.find(c=>c.id===i),a=n??{...s,density:0},r=s??{...n,density:0};return{...a,eastM:ui(a.eastM,r.eastM,e),northM:ui(a.northM,r.northM,e),baseM:ui(a.baseM,r.baseM,e),thicknessM:ui(a.thicknessM,r.thicknessM,e),widthM:ui(a.widthM,r.widthM,e),depthM:ui(a.depthM,r.depthM,e),rotationDeg:Fp(a.rotationDeg,r.rotationDeg,e),density:ui(a.density,r.density,e),darkness:ui(a.darkness??0,r.darkness??0,e)}})}function cx(o,t,e){if(o.cloudLayers===void 0&&t.cloudLayers===void 0)return;const i=Tu(o),n=Tu(t);return e>=1?n.map(a=>({...a})):[...new Set([...i.map(a=>a.id),...n.map(a=>a.id)])].map(a=>{const r=i.find(u=>u.id===a),c=n.find(u=>u.id===a),h=r??{...c,coverage:0},l=c??{...r,coverage:0};return{...h,instances:ox(r?.instances,c?.instances,e),baseM:ui(h.baseM,l.baseM,e),thicknessM:ui(h.thicknessM,l.thicknessM,e),coverage:ui(h.coverage,l.coverage,e),sizeM:ui(h.sizeM,l.sizeM,e),density:ui(h.density,l.density,e),darkness:ui(h.darkness??o.cloudDarkness,l.darkness??t.cloudDarkness,e),iceCrystalAlignment:h.iceCrystalAlignment===void 0||l.iceCrystalAlignment===void 0?void 0:ui(h.iceCrystalAlignment,l.iceCrystalAlignment,e),windSpeed:h.windSpeed===void 0&&l.windSpeed===void 0?void 0:ui(h.windSpeed??o.windSpeed,l.windSpeed??t.windSpeed,e),windDirectionDeg:h.windDirectionDeg===void 0&&l.windDirectionDeg===void 0?void 0:Fp(h.windDirectionDeg??o.windDirectionDeg,l.windDirectionDeg??t.windDirectionDeg,e)}})}function hx(o,t,e){return{cloudLayers:cx(o,t,e),cloudCover:ui(o.cloudCover,t.cloudCover,e),cloudDarkness:ui(o.cloudDarkness,t.cloudDarkness,e),highCloudCover:o.highCloudCover===void 0||t.highCloudCover===void 0?void 0:ui(o.highCloudCover,t.highCloudCover,e),iceCrystalAlignment:o.iceCrystalAlignment===void 0||t.iceCrystalAlignment===void 0?void 0:ui(o.iceCrystalAlignment,t.iceCrystalAlignment,e),rareIceCrystals:o.rareIceCrystals===void 0||t.rareIceCrystals===void 0?void 0:ui(o.rareIceCrystals,t.rareIceCrystals,e),lowerCloudCover:o.lowerCloudCover===void 0||t.lowerCloudCover===void 0?void 0:ui(o.lowerCloudCover,t.lowerCloudCover,e),cloudBaseM:o.cloudBaseM===void 0||t.cloudBaseM===void 0?void 0:ui(o.cloudBaseM,t.cloudBaseM,e),relativeHumidity:o.relativeHumidity===void 0||t.relativeHumidity===void 0?void 0:ui(o.relativeHumidity,t.relativeHumidity,e),precipitationType:e<1?o.precipitationType:t.precipitationType,precipitationIntensity:ui(o.precipitationIntensity,t.precipitationIntensity,e),windDirectionDeg:Fp(o.windDirectionDeg,t.windDirectionDeg,e),windSpeed:ui(o.windSpeed,t.windSpeed,e),storm:e<1?o.storm:t.storm}}class Uh{keyframes=[];ramp;addKeyframe(t,e){this.ramp=void 0;const i=this.findInsertIndex(t);this.keyframes[i]?.t===t?this.keyframes[i]={t,weather:e}:this.keyframes.splice(i,0,{t,weather:e})}clear(){this.ramp=void 0,this.keyframes.length=0}removeKeyframeAt(t){this.ramp=void 0;const e=this.findInsertIndex(t);this.keyframes[e]?.t===t&&this.keyframes.splice(e,1)}findInsertIndex(t){let e=0,i=this.keyframes.length;for(;e<i;){const n=e+i>>>1;this.keyframes[n].t<t?e=n+1:i=n}return e}getLatestWeatherAt(t){let e=this.findInsertIndex(t);return this.keyframes[e]?.t!==t&&(e-=1),e>=0?this.keyframes[e].weather:void 0}getInterpolatedWeatherAt(t){const e=this.findInsertIndex(t),i=this.keyframes[e]?.t===t?this.keyframes[e]:this.keyframes[e-1];if(i?.t===t)return i.weather;const n=this.keyframes[e]?.t===t?void 0:this.keyframes[e];return i?n?hx(i.weather,n.weather,rx((t-i.t)/(n.t-i.t),0,1)):i.weather:n?.weather}getActualWeatherAt(t){const e=this.getInterpolatedWeatherAt(t);if(!e)return;const i=(this.ramp??=new nr(this.keyframes)).at(t);if(!i)return e;const{type:n,intensity:s,character:a}=i,r=a>0?Math.min(1,s/a):n==="none"?0:1;return{...e,precipitationType:n,precipitationIntensity:a,precipitationAmount:r}}get duration(){return this.keyframes.length===0?0:this.keyframes[this.keyframes.length-1].t}get allKeyframes(){return this.keyframes}toJSON(){return{keyframes:this.keyframes}}static fromJSON(t){const e=new Uh;for(const i of t.keyframes)e.addKeyframe(i.t,{...rd,...i.weather});return e}}class kh{keyframes=[];addKeyframe(t,e){const i=this.findInsertIndex(t);this.keyframes[i]?.t===t?this.keyframes[i]={t,sound:e}:this.keyframes.splice(i,0,{t,sound:e})}clear(){this.keyframes.length=0}removeKeyframeAt(t){const e=this.findInsertIndex(t);this.keyframes[e]?.t===t&&this.keyframes.splice(e,1)}getLatestSoundAt(t){let e=this.findInsertIndex(t);return this.keyframes[e]?.t!==t&&(e-=1),e>=0?this.keyframes[e].sound:void 0}getInterpolatedSoundAt(t){const e=this.findInsertIndex(t),i=this.keyframes[e]?.t===t?this.keyframes[e]:this.keyframes[e-1];if(i?.t===t)return i.sound;const n=this.keyframes[e]?.t===t?void 0:this.keyframes[e];if(!i)return n?.sound;if(!n)return i.sound;const s=(t-i.t)/(n.t-i.t);return this.lerp(i.sound,n.sound,Math.max(0,Math.min(1,s)))}get duration(){return this.keyframes.length===0?0:this.keyframes[this.keyframes.length-1].t}get allKeyframes(){return this.keyframes}toJSON(){return{keyframes:this.keyframes}}static fromJSON(t){const e=new kh;for(const i of t.keyframes)e.addKeyframe(i.t,i.sound);return e}lerp(t,e,i){return{kind:i<1?t.kind:e.kind,volume:t.volume+(e.volume-t.volume)*i,pitchHz:t.pitchHz+(e.pitchHz-t.pitchHz)*i,src:i<1?t.src:e.src}}findInsertIndex(t){let e=0,i=this.keyframes.length;for(;e<i;){const n=e+i>>>1;this.keyframes[n].t<t?e=n+1:i=n}return e}}const lx=100,ux={kind:"none",volume:0,pitchHz:lx};class gs{constructor(t){this.entries=t}static empty(){return new gs(new Map)}get size(){return this.entries.size}at(t){return this.entries.get(t)}paths(){return[...this.entries.keys()]}set(t,e){e.basis==="stated"&&e.rationale===void 0&&e.how===void 0?this.entries.delete(t):this.entries.set(t,e)}clear(t){for(const e of this.entries.keys())(e===t||e.startsWith(`${t}.`))&&this.entries.delete(e)}static strip(t){const e=new gs(new Map);return{recording:gs.stripValue(t,[],e),provenance:e}}static restore(t,e){if(e.size===0)return t;const i={...t},n=new Set([i]);for(const s of e.paths()){const a=e.at(s),r=s.split("."),c=gs.writableHolderOf(i,r,n);if(!c)continue;const h=r[r.length-1],l=c[h];l!==void 0&&(a.of!==void 0&&JSON.stringify(a.of)!==JSON.stringify(l)||(c[h]={value:l,...a.basis==="stated"?{}:{basis:a.basis},...a.rationale===void 0?{}:{rationale:a.rationale},...a.how===void 0?{}:{how:a.how}}))}return i}static isWrapper(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)&&"value"in t}static stripValue(t,e,i){return gs.isWrapper(t)?(i.set(e.join("."),{basis:t.basis??"stated",...t.rationale===void 0?{}:{rationale:t.rationale},...t.how===void 0?{}:{how:t.how},of:t.value}),gs.stripValue(t.value,e,i)):Array.isArray(t)?t.map((n,s)=>gs.stripValue(n,[...e,String(s)],i)):typeof t=="object"&&t!==null?Object.fromEntries(Object.entries(t).map(([n,s])=>[n,gs.stripValue(s,[...e,n],i)])):t}static writableHolderOf(t,e,i){let n=t;for(const s of e.slice(0,-1)){const a=n[s];if(typeof a!="object"||a===null)return;if(i.has(a)){n=a;continue}const r=Array.isArray(a)?[...a]:{...a};i.add(r),n[s]=r,n=r}return n}}function o0(o){if(o.year!==void 0)return Date.UTC(o.year,(o.month??1)-1,o.day??1,o.hour??0,o.minute??0,o.second??0)}function Jm(o){return(((o.day??0)*24+(o.hour??0))*60+(o.minute??0))*6e4+(o.second??0)*1e3}const dx=["year","month","day","hour","minute"],fx=["day","hour","minute"];function jm(o,t){return t.filter(e=>o[e]!==void 0).join(",")}function px(o){if(o.durationSeconds!==void 0)return o.durationSeconds*1e3;const t=o.durationText===void 0?void 0:dh.parse(o.durationText);if(t)return t.chosenSeconds*1e3;if(!o.time||!o.endTime)return;const e=o.time.year!==void 0&&o.endTime.year!==void 0,i=e?dx:fx,n=jm(o.time,i);if(!(n===""||n!==jm(o.endTime,i)))return e?o0(o.endTime)-o0(o.time):Jm(o.endTime)-Jm(o.time)}class cd{constructor(t,e,i,n,s,a,r,c,h=[],l,u,d,f=[],p=[],g=[],m=[]){this.event=t,this.timeline=e,this.observerTrack=i,this.weatherTrack=n,this.soundTrack=s,this.observer=a,this.id=r,this.weather=c,this.decor=h,this.weatherSource=l,this.instrumentId=u,this.exposureSeconds=d,this.milestones=f,this.references=p,this.roads=g,this.traces=m}provenance=gs.empty();loadIssues=[];account;sources;interpretation;variants=[];skyEvents;frozen;sway;lightPollution;observerMap;iso;metering;lens;vehicle;get observerCount(){return 1+this.decor.filter(t=>t.kind==="observer").length}get exposure(){return this.exposureSeconds??this.instrument.exposureSeconds}get instrument(){return Ii.byId(this.instrumentId)}static create(t,e,i){return new cd({eventType:"sighting",time:t,place:e},new od,new Nh,new Uh,new kh,i)}}const mx=0,gx=0;function Fe(o,t){const e=o.observerTrack.getInterpolatedPoseAt(t);if(e)return e;const i=o.event.place?.[0];if(i)return{lat:i.lat,lng:i.lng,elevationM:mx,headingDeg:void 0,pitchDeg:gx,fovDeg:Ii.fieldOfViewDeg(o.instrument)}}function Uc(o,t){return o.weatherTrack.getInterpolatedWeatherAt(t)??o.weather??rd}function kc(o,t){return o.weatherTrack.getActualWeatherAt(t)??o.weather??rd}function Mx(o,t){return o.soundTrack.getInterpolatedSoundAt(t)??ux}class vx{constructor(t,e){this.timeline=t,this.onFrame=e}rafId=null;state="stopped";currentT=0;lastWallTime=0;playbackRate=1;loop=!1;onEnded;durationOverrideMs=0;get seekableDuration(){return Math.max(this.timeline.duration,this.durationOverrideMs)}play(){if(this.state==="playing")return;this.currentT>=this.seekableDuration&&(this.currentT=0,this.resolveFrame(0)),this.state="playing",this.lastWallTime=performance.now();const t=()=>{if(this.state!=="playing")return;const e=performance.now();if(this.currentT+=(e-this.lastWallTime)*this.playbackRate,this.lastWallTime=e,this.currentT>=this.seekableDuration){if(this.loop&&this.seekableDuration>0){this.currentT%=this.seekableDuration,this.resolveFrame(this.currentT),this.rafId=requestAnimationFrame(t);return}this.currentT=this.seekableDuration,this.stop(),this.resolveFrame(this.currentT),this.onEnded?.();return}this.resolveFrame(this.currentT),this.rafId=requestAnimationFrame(t)};this.rafId=requestAnimationFrame(t)}pause(){this.state==="playing"&&(this.state="paused",this.rafId!==null&&(cancelAnimationFrame(this.rafId),this.rafId=null))}stop(){this.state="stopped",this.rafId!==null&&(cancelAnimationFrame(this.rafId),this.rafId=null)}seek(t){this.currentT=Math.max(0,Math.min(t,this.seekableDuration)),this.resolveFrame(this.currentT)}get playbackState(){return this.state}get time(){return this.currentT}resolveFrame(t){const e=new Map;for(const i of this.timeline.sourceIds){const n=this.timeline.getInterpolatedShapeAt(t,i);n&&e.set(i,n)}this.onFrame(t,e)}}const Mv=["nw","n","ne","e","se","s","sw","w"],yx=24,sl=8,xx=3,wx=8;function al(o,t,e){const i=o.x-t.x,n=o.y-t.y,s=Math.cos(e),a=Math.sin(e);return{x:t.x+i*s-n*a,y:t.y+i*a+n*s}}function Fc(o){return{x:o.x+o.width/2,y:o.y+o.height/2}}const Sx={nw:{left:!0,top:!0},n:{top:!0},ne:{right:!0,top:!0},e:{right:!0},se:{right:!0,bottom:!0},s:{bottom:!0},sw:{left:!0,bottom:!0},w:{left:!0}};class ss{static handlePointsFor(t){const{x:e,y:i,width:n,height:s}=t.bounds,a={nw:{x:e,y:i},n:{x:e+n/2,y:i},ne:{x:e+n,y:i},e:{x:e+n,y:i+s/2},se:{x:e+n,y:i+s},s:{x:e+n/2,y:i+s},sw:{x:e,y:i+s},w:{x:e,y:i+s/2},rotate:{x:e+n/2,y:i-yx}},r=Fc(t.bounds),c={};for(const h of Object.keys(a))c[h]=al(a[h],r,t.angle);return c}static hitTestHandle(t,e,i=8,n=[...Mv,"rotate"]){const s=ss.handlePointsFor(t);for(const a of n)if(Math.hypot(e.x-s[a].x,e.y-s[a].y)<=i)return a}static HANDLE_DIRECTION_DEG={e:0,se:45,s:90,sw:135,w:180,nw:225,n:270,ne:315};static resizeAxisFor(t,e){const n=((ss.HANDLE_DIRECTION_DEG[t]+e*180/Math.PI)%180+180)%180/45,s=["ew","nwse","ns","nesw"];return s[Math.round(n)%s.length]}static resizeBounds(t,e,i,n){const s=Fc(t),a=al(n,s,-e),{x:r,y:c,width:h,height:l}=t,u=Sx[i];let d=r,f=c,p=r+h,g=c+l;return u.left&&(d=Math.min(a.x,p-sl)),u.right&&(p=Math.max(a.x,d+sl)),u.top&&(f=Math.min(a.y,g-sl)),u.bottom&&(g=Math.max(a.y,f+sl)),{x:d,y:f,width:p-d,height:g-f}}static resizeShape(t,e,i){if(e==="rotate")throw new Error("resizeShape does not accept the rotate handle");const{width:n,height:s}=t.bounds,a=ss.resizeBounds(t.bounds,t.angle,e,i);if(t.kind==="oval")return{...t,bounds:a};const r=n===0?1:a.width/n,c=s===0?1:a.height/s;return{...t,bounds:a,points:t.points.map(h=>({x:h.x*r,y:h.y*c}))}}static rotateShape(t,e){const i=Fc(t.bounds),n=Math.atan2(e.y-i.y,e.x-i.x)+Math.PI/2;return{...t,angle:n}}static groupBoundsFor(t){const e=Math.min(...t.map(a=>a.x)),i=Math.min(...t.map(a=>a.y)),n=Math.max(...t.map(a=>a.x+a.width)),s=Math.max(...t.map(a=>a.y+a.height));return{x:e,y:i,width:n-e,height:s-i}}static vertexPointsFor(t){const e=Fc(t.bounds);return t.points.map(i=>al({x:t.bounds.x+i.x,y:t.bounds.y+i.y},e,t.angle))}static hitTestVertex(t,e,i=wx){const n=ss.vertexPointsFor(t);let s,a=i;return n.forEach((r,c)=>{const h=Math.hypot(e.x-r.x,e.y-r.y);h<=a&&(a=h,s=c)}),s}static toLocalPoint(t,e){const i=Fc(t.bounds),n=al(e,i,-t.angle);return{x:n.x-t.bounds.x,y:n.y-t.bounds.y}}static moveVertex(t,e,i){const n=t.points.map((u,d)=>d===e?ss.toLocalPoint(t,i):u),s=Math.min(...n.map(u=>u.x)),a=Math.min(...n.map(u=>u.y)),r=Math.max(...n.map(u=>u.x)),c=Math.max(...n.map(u=>u.y)),h={x:t.bounds.x+s,y:t.bounds.y+a,width:r-s,height:c-a},l=n.map(u=>({x:u.x-s,y:u.y-a}));return{...t,bounds:h,points:l}}static insertVertexNear(t,e){const i=ss.toLocalPoint(t,e),{points:n}=t;let s=n.length-1,a=1/0;for(let c=0;c<n.length;c++){const h=n[c],l=n[(c+1)%n.length],u=ss.distanceToSegment(i,h,l);u<a&&(a=u,s=c)}const r=[...n.slice(0,s+1),i,...n.slice(s+1)];return{...t,points:r}}static distanceToSegment(t,e,i){const n=i.x-e.x,s=i.y-e.y,a=n*n+s*s,r=a===0?0:Math.max(0,Math.min(1,((t.x-e.x)*n+(t.y-e.y)*s)/a)),c=e.x+r*n,h=e.y+r*s;return Math.hypot(t.x-c,t.y-h)}static deleteVertex(t,e){return t.points.length<=xx?t:{...t,points:t.points.filter((i,n)=>n!==e)}}}const c0=6,rl=c0/2,Qm=20,tg=24,eg=9,ig=6,ng=7,sg=6,Vs=4;class Sc{constructor(t){this.ctx=t}starPoints=0;roll=0;clear(t,e){this.ctx.clearRect(0,0,t,e)}static paintExtent(t){const{x:e,y:i,width:n,height:s}=t.bounds,a=e+n/2,r=i+s/2,c=t.angle%(2*Math.PI)!==0,h=Math.hypot(n,s)/2,l=c?h:n/2,u=c?h:s/2,d=Math.max(n,s)/2,f=t.brightness??0,p=f>0?Math.max(d*(1+eg*f),sg*f)-d:0,g=f>0?d*(1+ng*f)-d:0,m=3*tg*(t.blur??0)+1.5*Qm*t.haloScale,M=Math.max(p,g,0)+m+2;return{x:a-l-M,y:r-u-M,width:2*(l+M),height:2*(u+M)}}paintInto(t,e,i,n=!1){this.ctx.save(),this.ctx.scale(i,i),this.ctx.translate(-e.x,-e.y);const s=t.selected?{...t,selected:!1}:t;n?this.paintGhost(s,1.5):this.paintShape(s),this.ctx.restore()}paintShape(t){this.ctx.save(),this.ctx.globalAlpha=1-t.transparency;const e=t.blur??0;e>0&&(this.ctx.filter=`blur(${(tg*e).toFixed(2)}px)`);const i=t.brightness??0;i>0&&this.paintDazzle(t,i),t.haloScale>0&&this.paintHalo(t),this.paintBase(t),this.ctx.restore(),t.selected&&this.paintSelectionHandles(t)}setStarPoints(t){this.starPoints=Math.max(0,Math.floor(t))}setRoll(t){this.roll=t}paintDazzle(t,e){const{x:i,y:n,width:s,height:a}=t.bounds,r=i+s/2,c=n+a/2,h=Math.max(s,a)/2,l=Math.max(h*(1+eg*e),sg*e);if(l<=0)return;this.ctx.save(),this.ctx.globalCompositeOperation="lighter";const u=this.ctx.createRadialGradient(r,c,0,r,c,l);for(let d=0;d<=ig;d++){const f=d/ig,p=1/(1+24*f*f);this.ctx.globalAlpha=1,u.addColorStop(f,this.withAlpha(t.color,p*e*.55))}if(this.ctx.fillStyle=u,this.ctx.beginPath(),this.ctx.arc(r,c,l,0,2*Math.PI),this.ctx.fill(),this.starPoints>0){const d=h*(1+ng*e);this.ctx.lineWidth=Math.max(1,h*.12),this.ctx.lineCap="round";for(let f=0;f<this.starPoints;f++){const p=f/this.starPoints*Math.PI*2+this.roll,g=r+Math.cos(p)*d,m=c+Math.sin(p)*d,M=this.ctx.createLinearGradient(r,c,g,m);M.addColorStop(0,this.withAlpha(t.color,e*.55)),M.addColorStop(.35,this.withAlpha(t.color,e*.22)),M.addColorStop(1,this.withAlpha(t.color,0)),this.ctx.strokeStyle=M,this.ctx.beginPath(),this.ctx.moveTo(r,c),this.ctx.lineTo(g,m),this.ctx.stroke()}}this.ctx.restore()}dazzledFill(t,e){if(e<=0)return t.color;const i=/^#([0-9a-f]{6})$/i.exec(t.color.trim());if(!i)return t.color;const n=Number.parseInt(i[1],16),s=a=>Math.round(a+(255-a)*e);return`rgb(${s(n>>16&255)}, ${s(n>>8&255)}, ${s(n&255)})`}withAlpha(t,e){const i=Math.max(0,Math.min(1,e)),n=/^#([0-9a-f]{6})$/i.exec(t.trim());if(!n)return t;const s=Number.parseInt(n[1],16);return`rgba(${s>>16&255}, ${s>>8&255}, ${s&255}, ${i.toFixed(3)})`}paintBase(t){this.ctx.fillStyle=this.dazzledFill(t,t.brightness??0),this.tracePath(t),this.ctx.fill()}paintGhost(t,e){this.ctx.save(),this.tracePath(t),this.ctx.setLineDash([e*3,e*2]),this.ctx.lineWidth=e,this.ctx.strokeStyle=t.color,this.ctx.stroke(),this.ctx.restore()}tracePath(t){if(this.ctx.beginPath(),t.kind==="oval"){const{x:e,y:i,width:n,height:s}=t.bounds,a=n/2,r=s/2;this.ctx.ellipse(e+a,i+r,a,r,t.angle,0,2*Math.PI)}else{const{x:e,y:i,width:n,height:s}=t.bounds;this.ctx.save(),this.ctx.translate(e+n/2,i+s/2),this.ctx.rotate(t.angle),this.ctx.translate(-n/2,-s/2),t.points.forEach((a,r)=>{r===0?this.ctx.moveTo(a.x,a.y):this.ctx.lineTo(a.x,a.y)}),this.ctx.closePath(),this.ctx.restore()}}paintHalo(t){this.ctx.save(),this.ctx.shadowColor=t.color,this.ctx.shadowBlur=Qm*t.haloScale,this.paintBase(t),this.ctx.restore()}paintSelectionHandles(t){this.paintHandleFrame(ss.handlePointsFor(t),{includeRotate:!0}),t.kind==="polygon"&&this.paintVertexHandles(t)}paintVertexHandles(t){this.ctx.fillStyle="#39f";for(const e of ss.vertexPointsFor(t))this.ctx.beginPath(),this.ctx.ellipse(e.x,e.y,Vs,Vs,0,0,2*Math.PI),this.ctx.fill()}paintMemberOutline(t){this.paintOutline(ss.handlePointsFor(t))}paintSelectionOnly(t){this.paintSelectionHandles(t)}paintPictureFrame(t,e,i){const n=this.ctx;if(n.save(),t&&t.length===4){n.strokeStyle="#39f",n.lineWidth=1.5,n.setLineDash([6,4]),n.beginPath(),n.moveTo(t[0].x,t[0].y);for(const s of t.slice(1))n.lineTo(s.x,s.y);n.closePath(),n.stroke(),n.setLineDash([])}for(const s of e){const a=Sc.landmarkColour(s.residualDeg),r=s.selected?3:2;s.selected&&(n.strokeStyle="#fff",n.lineWidth=r+3,n.beginPath(),n.ellipse(s.picture.x,s.picture.y,Vs+2,Vs+2,0,0,2*Math.PI),n.stroke()),s.scene&&(n.strokeStyle=a,n.lineWidth=1,n.beginPath(),n.moveTo(s.picture.x,s.picture.y),n.lineTo(s.scene.x,s.scene.y),n.stroke(),n.fillStyle=a,n.beginPath(),n.ellipse(s.scene.x,s.scene.y,Vs,Vs,0,0,2*Math.PI),n.fill()),n.strokeStyle=a,n.lineWidth=r,n.beginPath(),n.ellipse(s.picture.x,s.picture.y,Vs+2,Vs+2,0,0,2*Math.PI),n.stroke(),this.paintLabel(s.label,s.picture.x+Vs+5,s.picture.y-Vs-2,a)}i&&this.paintLabel(i,8,8,"#fff",13),n.restore()}paintGhosts(t,e,i){const n=this.ctx;n.save();const s=(c,h,l,u=[])=>{n.setLineDash(u),n.lineWidth=l+2,n.strokeStyle="rgba(0, 0, 0, 0.6)",c(),n.lineWidth=l,n.strokeStyle=h,c(),n.setLineDash([])},a=(c,h)=>()=>{n.beginPath(),n.arc(c.x,c.y,h,0,2*Math.PI),n.stroke()},r=(c,h,l)=>()=>{const[u,d]=l?[h,h]:[h,0];n.beginPath(),n.moveTo(c.x-u,c.y-d),n.lineTo(c.x+u,c.y+d),n.moveTo(c.x+d,c.y-u),n.lineTo(c.x-d,c.y+u),n.stroke()};for(const c of t)s(()=>{n.beginPath(),n.moveTo(c.ghost.x,c.ghost.y),n.lineTo(c.light.x,c.light.y),n.stroke()},"rgba(255, 255, 255, 0.85)",1,[4,4]),s(a(c.light,7),"#ffffff",1.5),s(a(c.ghost,Math.max(9,c.ghostRadius)),"#ffd23f",2);e&&s(r(e,8,!1),"#ffd23f",2),i&&s(r(i,5,!0),"rgba(255, 255, 255, 0.7)",1),n.restore()}static landmarkColour(t){return t===void 0?"#ffb000":t<=1?"#3c3":t<=3?"#ffb000":"#f33"}paintLabel(t,e,i,n,s=11){const a=this.ctx;a.save(),a.font=`${s}px system-ui, sans-serif`,a.textBaseline="top";const r=a.measureText(t).width;a.fillStyle="rgba(0, 0, 0, 0.6)",a.fillRect(e-3,i-2,r+6,s+4),a.fillStyle=n,a.fillText(t,e,i),a.restore()}paintGroupHandles(t){this.paintHandleFrame(ss.handlePointsFor({bounds:t,angle:0}),{includeRotate:!0})}paintOutline(t){this.ctx.strokeStyle="lightgray",this.ctx.beginPath(),this.ctx.moveTo(t.nw.x,t.nw.y),this.ctx.lineTo(t.ne.x,t.ne.y),this.ctx.lineTo(t.se.x,t.se.y),this.ctx.lineTo(t.sw.x,t.sw.y),this.ctx.closePath(),this.ctx.stroke()}paintHandleFrame(t,{includeRotate:e}){this.paintOutline(t),this.ctx.fillStyle="lightgray";for(const i of Mv){const n=t[i];this.ctx.fillRect(n.x-rl,n.y-rl,c0,c0)}e&&(this.ctx.beginPath(),this.ctx.moveTo(t.n.x,t.n.y),this.ctx.lineTo(t.rotate.x,t.rotate.y),this.ctx.stroke(),this.ctx.beginPath(),this.ctx.ellipse(t.rotate.x,t.rotate.y,rl+1,rl+1,0,0,2*Math.PI),this.ctx.fill())}}const ag=.05,rg=.08,og=2,cg=3,bx=14,Ex=.02;class Ax{context;voice;voiceToken=0;buffers=new Map;noiseBuffer;crackleBuffer;requested;level=1;master;output(t){return this.master||(this.master=t.createGain(),this.master.gain.value=this.level,this.master.connect(t.destination)),this.master}setLevel(t){this.level=t,this.master&&(this.master.gain.value=t)}resume(){if(!this.context){if(typeof AudioContext>"u")return;try{this.context=new AudioContext}catch(t){console.warn("SightingAudio: Web Audio unavailable, the sighting stays silent:",t);return}}$r.unlock(this.context)}setSound(t){if(this.requested=t,!this.context)return;const e=this.keyFor(t);if(!e){this.silence();return}if(this.voice?.key!==e){this.stopVoice();const i=++this.voiceToken;e.startsWith("src:")?this.buildRecordedVoice(t.src,e,i):this.voice=this.buildSynthesizedVoice(t,e)}this.applyTo(this.voice,t)}silence(){this.voiceToken++,this.stopVoice()}dispose(){this.silence(),this.context?.close(),this.context=void 0,this.master=void 0,this.buffers.clear(),this.noiseBuffer=void 0,this.crackleBuffer=void 0}keyFor(t){if(!(t.volume<=0))return t.src?`src:${t.src}`:t.kind==="none"?void 0:t.kind}applyTo(t,e){const i=this.context;if(!t||!i)return;const n=i.currentTime;t.volumeParam.setTargetAtTime(Math.max(0,Math.min(1,e.volume))*t.gainScale,n,ag);for(const{param:s,ratio:a}of t.pitch)s.setTargetAtTime(Math.min(e.pitchHz*a,i.sampleRate/2-1),n,ag)}buildSynthesizedVoice(t,e){const i=this.context;if(i)switch(t.kind){case"hum":return this.buildHum(i,e);case"whistle":return this.buildWhistle(i,e);case"rumble":return this.buildRumble(i,e);case"crackle":return this.buildCrackle(i,e);default:return}}buildHum(t,e){const i=t.createOscillator();i.type="sawtooth";const n=t.createOscillator();n.type="sawtooth";const s=t.createBiquadFilter();s.type="lowpass",s.Q.value=1;const a=t.createGain();return a.gain.value=0,i.connect(s),n.connect(s),s.connect(a).connect(this.output(t)),i.start(),n.start(),{key:e,nodes:[s,a],sources:[i,n],volumeParam:a.gain,gainScale:.16,pitch:[{param:i.frequency,ratio:1},{param:n.frequency,ratio:1.006},{param:s.frequency,ratio:6}]}}buildWhistle(t,e){const i=t.createOscillator();i.type="sine";const n=t.createOscillator();n.type="sine",n.frequency.value=5;const s=t.createGain(),a=t.createGain();return a.gain.value=0,n.connect(s).connect(i.frequency),i.connect(a).connect(this.output(t)),i.start(),n.start(),{key:e,nodes:[s,a],sources:[i,n],volumeParam:a.gain,gainScale:.22,pitch:[{param:i.frequency,ratio:1},{param:s.gain,ratio:.012}]}}buildRumble(t,e){const i=t.createBufferSource();i.buffer=this.brownNoise(t),i.loop=!0;const n=t.createBiquadFilter();n.type="lowpass",n.Q.value=.8;const s=t.createGain();return s.gain.value=0,i.connect(n).connect(s).connect(this.output(t)),i.start(),{key:e,nodes:[n,s],sources:[i],volumeParam:s.gain,gainScale:1.4,pitch:[{param:n.frequency,ratio:1}]}}buildCrackle(t,e){const i=t.createBufferSource();i.buffer=this.whiteNoise(t),i.loop=!0;const n=t.createBiquadFilter();n.type="bandpass",n.Q.value=1.2;const s=t.createGain();s.gain.value=0;const a=t.createBufferSource();a.buffer=this.crackleEnvelope(t),a.loop=!0;const r=t.createGain();return r.gain.value=0,a.connect(r).connect(s.gain),i.connect(n).connect(s).connect(this.output(t)),i.start(),a.start(),{key:e,nodes:[n,s,r],sources:[i,a],volumeParam:r.gain,gainScale:.9,pitch:[{param:n.frequency,ratio:4}]}}async buildRecordedVoice(t,e,i){const n=this.context;if(!n)return;let s;try{s=await this.getBuffer(t)}catch(c){console.warn("SightingAudio: the recorded sound failed to load, staying silent:",c);return}if(i!==this.voiceToken||!this.context)return;const a=n.createBufferSource();a.buffer=s,a.loop=!0;const r=n.createGain();r.gain.value=0,a.connect(r).connect(this.output(n)),a.start(),this.voice={key:e,nodes:[r],sources:[a],volumeParam:r.gain,gainScale:1,pitch:[]},this.requested&&this.applyTo(this.voice,this.requested)}async getBuffer(t){const e=this.context;if(!e)throw new Error("SightingAudio: AudioContext not ready — resume() must be called first");let i=this.buffers.get(t);return i||(i=fetch(t).then(n=>{if(!n.ok)throw new Error(`Audio fetch failed (${n.status}): ${t}`);return n.arrayBuffer()}).then(n=>e.decodeAudioData(n)),this.buffers.set(t,i)),i}whiteNoise(t){if(!this.noiseBuffer){const e=t.createBuffer(1,Math.floor(t.sampleRate*og),t.sampleRate),i=e.getChannelData(0);for(let n=0;n<i.length;n++)i[n]=Math.random()*2-1;this.noiseBuffer=e}return this.noiseBuffer}brownNoise(t){const e=t.createBuffer(1,Math.floor(t.sampleRate*og),t.sampleRate),i=e.getChannelData(0);let n=0,s=0;for(let a=0;a<i.length;a++)n=(n+.02*(Math.random()*2-1))/1.02,i[a]=n,s=Math.max(s,Math.abs(n));if(s>0)for(let a=0;a<i.length;a++)i[a]/=s;return e}crackleEnvelope(t){if(!this.crackleBuffer){const e=t.createBuffer(1,Math.floor(t.sampleRate*cg),t.sampleRate),i=e.getChannelData(0),n=Math.max(1,Math.floor(Ex*t.sampleRate)),s=Math.round(cg*bx);for(let a=0;a<s;a++){const r=Math.floor(Math.random()*i.length),c=.4+Math.random()*.6;for(let h=0;h<n&&r+h<i.length;h++)i[r+h]=Math.max(i[r+h],c*(1-h/n))}this.crackleBuffer=e}return this.crackleBuffer}stopVoice(){const t=this.voice,e=this.context;if(this.voice=void 0,!t||!e)return;const i=e.currentTime;t.volumeParam.cancelScheduledValues(i),t.volumeParam.setTargetAtTime(0,i,rg/3);const n=i+rg;for(const s of t.sources){s.onended=()=>{s.disconnect();for(const a of t.nodes)a.disconnect()};try{s.stop(n)}catch{s.disconnect();for(const a of t.nodes)a.disconnect()}}}}class Zt{static svg(t){return`<svg viewBox="0 0 24 24" width="1.5em" height="1.5em" aria-hidden="true" focusable="false"><path d="${t}" fill="currentColor"/></svg>`}static outline(t){return`<svg viewBox="0 0 24 24" width="1.5em" height="1.5em" aria-hidden="true" focusable="false"><path d="${t}" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round" stroke-linecap="round"/></svg>`}static solid(t){return`<svg viewBox="0 0 24 24" width="1.5em" height="1.5em" aria-hidden="true" focusable="false"><path d="${t}" fill="currentColor" fill-rule="evenodd"/></svg>`}static BOOKMARK="M6 3.5h12a.5.5 0 0 1 .5.5v16.5L12 16.8l-6.5 3.7V4a.5.5 0 0 1 .5-.5z";static PICTURE="M5 4h14a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z";static PICTURE_HILLS="M4.5 17.5l4.5-6 3 4 2.5-3 5 5z";static PIN="M12 21.5s-6.5-5.7-6.5-10.8a6.5 6.5 0 0 1 13 0c0 5.1-6.5 10.8-6.5 10.8z";static PIN_HOLE="M12 8.4a2.4 2.4 0 1 0 0 4.8 2.4 2.4 0 0 0 0-4.8z";static MILESTONES_OFF=Zt.outline(Zt.BOOKMARK);static MILESTONES_ON=Zt.solid(Zt.BOOKMARK);static PICTURES_OFF=Zt.outline(`${Zt.PICTURE}${Zt.PICTURE_HILLS}`);static PICTURES_ON=Zt.solid(`${Zt.PICTURE}${Zt.PICTURE_HILLS}`);static TRACE_LINE="M3 19.5l2.2-2.2 1.4 1.4L4.4 20.9zM8 14.5l2.2-2.2 1.4 1.4-2.2 2.2zM13 9.5l2.2-2.2 1.4 1.4-2.2 2.2z";static TRACE_MARK="M18.5 2.5l3.5 3.5-3.5 3.5-3.5-3.5z";static TRACES_OFF=Zt.outline(`${Zt.TRACE_LINE}${Zt.TRACE_MARK}`);static TRACES_ON=Zt.solid(`${Zt.TRACE_LINE}${Zt.TRACE_MARK}`);static MAP_OFF=Zt.outline(`${Zt.PIN}${Zt.PIN_HOLE}`);static MAP_ON=Zt.solid(`${Zt.PIN}${Zt.PIN_HOLE}`);static SHARE=Zt.outline("M14 4l7 7-7 7v-4.2C8.6 13.8 5.4 15.6 3.5 19c.6-5.6 3.4-9.6 10.5-10.8V4z");static FOLDED=Zt.svg("M15.4 7.4 14 6l-6 6 6 6 1.4-1.4L10.8 12z");static UNFOLDED=Zt.svg("M8.6 16.6 10 18l6-6-6-6-1.4 1.4 4.6 4.6z");static PLAY=Zt.svg("M7.4 5v14l11-7z");static PAUSE=Zt.svg("M6 5h4v14H6zM14 5h4v14h-4z");static VOLUME=Zt.svg("M2 9.5v5h3.5l4.5 4.5V5L5.5 9.5H2zm12.5 2.5A4 4 0 0 0 12.5 8.5v7A4 4 0 0 0 14.5 12zM12.5 4.2v2.1a6.5 6.5 0 0 1 0 11.4v2.1a8.6 8.6 0 0 0 0-15.6z");static MUTED=Zt.svg("M2 9.5v5h3.5l4.5 4.5V5L5.5 9.5H2zM15 9.8l1.4-1.4 2.6 2.6 2.6-2.6 1.4 1.4-2.6 2.6 2.6 2.6-1.4 1.4-2.6-2.6-2.6 2.6-1.4-1.4 2.6-2.6z");static ENTER_FULLSCREEN=Zt.svg("M5 5h5v2H7v3H5V5zm9 0h5v5h-2V7h-3V5zM5 14h2v3h3v2H5v-5zm12 0h2v5h-5v-2h3v-3z");static EXIT_FULLSCREEN=Zt.svg("M8 5h2v5H5V8h3V5zm6 0h2v3h3v2h-5V5zM5 14h5v5H8v-3H5v-2zm9 0h5v2h-3v3h-2v-5z")}class js{static KINDS=["beams","launches","reentries"];static isEmpty(t){return!t||js.KINDS.every(e=>!t[e]?.length)}static written(t){if(js.isEmpty(t))return;const e={};for(const i of js.KINDS)t[i]?.length&&(e[i]=t[i]);return e}static read(t,e){const i=e,n={};for(const a of js.KINDS){const r=[...t?.[a]??[],...i?.[a]??[]];r.length>0&&(n[a]=r)}let s=e;if(i&&js.KINDS.some(a=>a in i)){const{beams:a,launches:r,reentries:c,...h}=i;s=js.isReading(h)?h:void 0}return{skyEvents:js.written(n),interpretation:s}}static isReading(t){return(t.bodies?.length??0)>0||t.title!==void 0||(t.smoke?.length??0)>0}}function fh(o){return[...o].sort((t,e)=>t.t-e.t)}function Rd(o,t){let e;for(const i of fh(o)){if(i.t>t)break;e=i}return e}const Id=Math.PI/180,ol=180/Math.PI;class ha{constructor(t,e,i){this.kind=t,this.canvasHeightPx=e,this.fovDeg=i;const n=i*Id/2;this.focalPx=t==="equidistant"?e/2/n:e/2/Math.tan(n)}focalPx;static of(t,e,i){return new ha(t.projection,e,i)}degToPx(t){const e=t*Id;return this.kind==="equidistant"?this.focalPx*e:2*this.focalPx*Math.tan(e/2)}pxToDeg(t){return this.kind==="equidistant"?t/this.focalPx*ol:2*Math.atan(t/(2*this.focalPx))*ol}angleDegToRadiusPx(t){const e=t*Id;return this.kind==="equidistant"?this.focalPx*e:this.focalPx*Math.tan(e)}halfWidthAngleDeg(t){return this.radiusPxToAngleDeg(this.canvasHeightPx*t/2)}radiusPxToAngleDeg(t){return this.kind==="equidistant"?t/this.focalPx*ol:Math.atan(t/this.focalPx)*ol}ofBounds(t){return{widthDeg:this.pxToDeg(t.width),heightDeg:this.pxToDeg(t.height)}}toBoundsSize(t){return{width:this.degToPx(t.widthDeg),height:this.degToPx(t.heightDeg)}}widthPx(t){return this.degToPx(Ze.angularWidthDeg(t))}}class wn{static fovOf(t,e){return Fe(t,e)?.fovDeg??Ii.fieldOfViewDeg(t.instrument)}static toAngular(t){this.eachKeyframe(t,(e,i)=>{const n=i.ofBounds(e.bounds);return e.angular?.widthDeg===n.widthDeg&&e.angular.heightDeg===n.heightDeg?e:{...e,angular:n}})}static toBounds(t){this.eachKeyframe(t,(e,i)=>this.sizedFromAngle(e,i))}static sizedFromAngle(t,e){if(!t.angular)return t;const{width:i,height:n}=e.toBoundsSize(t.angular),s={x:t.bounds.x+(t.bounds.width-i)/2,y:t.bounds.y+(t.bounds.height-n)/2,width:i,height:n};if(t.kind!=="polygon")return{...t,bounds:s};const a=t.bounds.width===0?1:i/t.bounds.width,r=t.bounds.height===0?1:n/t.bounds.height;return{...t,bounds:s,points:t.points.map(c=>({x:c.x*a,y:c.y*r}))}}static toAim(t){this.eachKeyframe(t,(e,i,n)=>{const s=e.aim&&this.positionOf(t,e.aim,e.bounds,i,n);if(s&&Math.abs(s.x-e.bounds.x)<wn.UNMOVED_PX&&Math.abs(s.y-e.bounds.y)<wn.UNMOVED_PX)return e;const a=this.aimFrom(t,i,n,e.bounds);return a?{...e,aim:a}:e})}static UNMOVED_PX=.01;static aimOf(t,e,i){const n=ha.of(t.instrument,Ze.CANVAS_HEIGHT_PX,this.fovOf(t,e));return this.aimFrom(t,n,Fe(t,e),i)}static aimFrom(t,e,i,n){if(i?.headingDeg===void 0)return;const s=this.frameCentre(t),a=e.radiusPxToAngleDeg(n.x+n.width/2-s.x),r=e.radiusPxToAngleDeg(s.y-(n.y+n.height/2));return{azimuthDeg:((i.headingDeg+a)%360+360)%360,altitudeDeg:i.pitchDeg+r}}static toPosition(t){this.eachKeyframe(t,(e,i,n)=>this.placedByAim(t,e,i,n))}static placedByAim(t,e,i,n){const s=e.aim&&this.positionOf(t,e.aim,e.bounds,i,n);return s?{...e,bounds:{...e.bounds,...s}}:e}static derivable(t){const e=new Set,i=new Map,n=new Map;return t.timeline.allKeyframes.forEach((s,a)=>{const r=Fe(t,s.t),c=ha.of(t.instrument,Ze.CANVAS_HEIGHT_PX,this.fovOf(t,s.t));for(const{sourceId:h,shape:l}of s.shapes){const u=n.get(h),d=i.get(h);if(n.set(h,l),!u||!d){i.set(h,l);continue}const f=Object.fromEntries(Object.entries(l).filter(([m,M])=>m!=="bounds"&&m!=="points"&&JSON.stringify(M)!==JSON.stringify(u[m]))),p={...d,...f},g=this.placedByAim(t,this.sizedFromAngle(p,c),c,r);wn.near(g,l)?(e.add(`${a}:${h}`),i.set(h,p)):i.set(h,l)}}),(s,a)=>e.has(`${s}:${a}`)}static SAME_PX=1e-6;static near(t,e){const i=(a,r)=>Math.abs(a-r)<=wn.SAME_PX*Math.max(1,Math.abs(r)),n=t.bounds,s=e.bounds;return!i(n.x,s.x)||!i(n.y,s.y)||!i(n.width,s.width)||!i(n.height,s.height)?!1:e.kind!=="polygon"||t.kind!=="polygon"?!0:t.points.length===e.points.length&&t.points.every((a,r)=>i(a.x,e.points[r].x)&&i(a.y,e.points[r].y))}static positionOf(t,e,i,n,s){if(s?.headingDeg===void 0)return;const a=this.frameCentre(t),r=this.shortestArc(e.azimuthDeg-s.headingDeg),c=e.altitudeDeg-s.pitchDeg;return{x:a.x+this.offAxisPx(n,r)-i.width/2,y:a.y-this.offAxisPx(n,c)-i.height/2}}static frameCentre(t){return{x:Ii.frameWidthPx(t.instrument,Ze.CANVAS_HEIGHT_PX)/2,y:Ze.CANVAS_HEIGHT_PX/2}}static shortestArc(t){return(t%360+540)%360-180}static offAxisPx(t,e){return Math.abs(e)>=wn.OFF_CANVAS_DEG?Math.sign(e)*wn.OFF_CANVAS_PX:t.angleDegToRadiusPx(e)}static OFF_CANVAS_DEG=89;static OFF_CANVAS_PX=1e5;static reproject(t,e,i){const n=Ii.frameWidthPx(e,Ze.CANVAS_HEIGHT_PX)/2,s=Ii.frameWidthPx(t.instrument,Ze.CANVAS_HEIGHT_PX)/2,a=Ze.CANVAS_HEIGHT_PX/2;for(const r of[...t.timeline.allKeyframes]){const c=this.fovOf(t,r.t),h=i?.get(r.t)??c,l=ha.of(e,Ze.CANVAS_HEIGHT_PX,h),u=ha.of(t.instrument,Ze.CANVAS_HEIGHT_PX,c);t.timeline.addKeyframe(r.t,r.shapes.map(d=>{const{bounds:f}=d.shape,p=f.x+f.width/2-n,g=f.y+f.height/2-a,m=Math.hypot(p,g),M=m===0?1:u.angleDegToRadiusPx(l.radiusPxToAngleDeg(m))/m,y={...f,x:s+p*M-f.width/2,y:a+g*M-f.height/2};return{...d,shape:{...d.shape,bounds:y}}}))}this.toBounds(t)}static eachKeyframe(t,e){const{timeline:i}=t;for(const n of[...i.allKeyframes]){const s=Fe(t,n.t),a=this.fovOf(t,n.t),r=ha.of(t.instrument,Ze.CANVAS_HEIGHT_PX,a);let c=!1;const h=n.shapes.map(l=>{const u=e(l.shape,r,s);return u===l.shape?l:(c=!0,{...l,shape:u})});c&&i.addKeyframe(n.t,h)}}}class Dn{static isRelative(t){return t!==void 0&&typeof t.eastM=="number"&&typeof t.northM=="number"}static isAbsolute(t){return t!==void 0&&typeof t.lat=="number"&&typeof t.lng=="number"}static referenceOf(t,e){return e.references.find(i=>(i.id??void 0)===(t.relativeTo??void 0))}static resolve(t,e){if(Dn.isRelative(t)){const i=Dn.referenceOf(t,e);return i?{eastM:i.eastM+t.eastM,northM:i.northM+t.northM}:void 0}return Dn.isAbsolute(t)&&e.origin?Dn.toLocal(t,e.origin):void 0}static restated(t,e,i){if(Dn.isRelative(t)){const s=Dn.referenceOf(t,i);return s?Dn.relative(e.eastM-s.eastM,e.northM-s.northM,t.relativeTo):void 0}if(!i.origin)return t;const n=Dn.toGeo(e,i.origin);return{lat:Dn.degrees(n.lat),lng:Dn.degrees(n.lng)}}static relative(t,e,i){const n={eastM:Dn.metres(t),northM:Dn.metres(e)};return i!==void 0&&(n.relativeTo=i),n}static toLocal(t,e){const i=ae(t.lat,t.lng,e.lat,e.lng);return{eastM:i.x,northM:-i.z}}static toGeo(t,e){return Kn(t.eastM,-t.northM,e.lat,e.lng)}static metres(t){return Math.round(t*100)/100}static degrees(t){return Math.round(t*1e7)/1e7}}class On{static restatedDecor(t){const e=On.originOf(t);return t.decor.map(i=>{let n=i;if(i.saidPosition){const s=On.restated(i.saidPosition,i,On.frameAt(t,0,e,i.id));JSON.stringify(s)!==JSON.stringify(i.saidPosition)&&(n={...i,saidPosition:s},s||delete n.saidPosition)}if(i.track?.some(s=>s.saidPosition)){const s=i.track.map(a=>{if(!a.saidPosition)return a;const r=On.restated(a.saidPosition,a,On.frameAt(t,a.t,e,i.id));if(JSON.stringify(r)===JSON.stringify(a.saidPosition))return a;const c={...a,saidPosition:r};return r||delete c.saidPosition,c});n={...n,track:s}}return n})}static restatedObserverTrack(t){const e=t.observerTrack.toJSON(),i=On.originOf(t);return!i||!e.keyframes.some(n=>n.pose.saidPosition)?e:{...e,keyframes:e.keyframes.map(n=>{const{pose:s}=n;if(!s.saidPosition||s.lat===void 0||s.lng===void 0)return n;const a=Dn.toLocal({lat:s.lat,lng:s.lng},i),r=On.restated(s.saidPosition,a,On.frameAt(t,n.t,i));if(JSON.stringify(r)===JSON.stringify(s.saidPosition))return n;const c={...s,saidPosition:r};return r||delete c.saidPosition,{...n,pose:c}})}}static restatedInterpretation(t){const e=t.interpretation;if(!e?.bodies.some(n=>n.track.some(s=>s.saidPosition)))return e;const i=On.originOf(t);return{...e,bodies:e.bodies.map(n=>n.track.some(s=>s.saidPosition)?{...n,track:n.track.map(s=>{if(!s.saidPosition)return s;const a=s.eastM!==void 0&&s.northM!==void 0?On.restated(s.saidPosition,{eastM:s.eastM,northM:s.northM},On.frameAt(t,s.t,i)):void 0;if(JSON.stringify(a)===JSON.stringify(s.saidPosition))return s;const r={...s,saidPosition:a};return a||delete r.saidPosition,r})}:n)}}static originOf(t){const e=t.observerTrack.getInterpolatedPoseAt(0),i=t.event.place?.[0],n=e?.lat??i?.lat,s=e?.lng??i?.lng;return typeof n=="number"&&typeof s=="number"?{lat:n,lng:s}:void 0}static frameAt(t,e,i,n){const s=[{label:"",eastM:0,northM:0},...t.decor.filter(a=>a.id!==n).map(a=>{const{eastM:r,northM:c}=fa(a,e);return{id:a.id,label:a.id,eastM:r,northM:c}})];return{origin:i,references:s}}static restated(t,e,i){return Dn.restated(t,{eastM:e.eastM,northM:e.northM},i)}}class _x extends Error{constructor(t,e,i){super(typeof e=="number"&&Number.isInteger(e)&&e>i?`This ${t} file is in version ${e} of its format; this UFO@home reads up to version ${i}. Read it with a newer UFO@home.`:`This ${t} file states ${JSON.stringify(e)} as its format version, which is not a version.`),this.format=t,this.found=e,this.supported=i,this.name="FormatVersionError"}said(t){return t.replace("{found}",typeof this.found=="number"?String(this.found):JSON.stringify(this.found)).replace("{supported}",String(this.supported))}}class Ko{static CURRENT={sighting:1,case:1,interview:1};static SCHEMA_BASE="https://ufoathome.org/schema";static schemaUrl(t,e=Ko.CURRENT[t]){return`${Ko.SCHEMA_BASE}/${e}/${t}.schema.json`}static of(t){if(typeof t!="object"||t===null)return 1;const e=t.version;return e===void 0?1:typeof e=="object"&&e!==null&&"value"in e?e.value:e}static check(t,e){const i=Ko.of(t),n=Ko.CURRENT[e];if(typeof i!="number"||!Number.isInteger(i)||i<1||i>n)throw new _x(e,i,n);return t}}function Tx(o){return gs.restore(Rx(o),o.provenance)}function Rx(o){return wn.toAngular(o),wn.toAim(o),{version:1,id:o.id,time:o.event.time,endTime:o.event.endTime,durationSeconds:o.event.durationSeconds,durationText:o.event.durationText,utcOffsetHours:o.event.utcOffsetHours,timeZone:o.event.timeZone,place:o.event.place,observer:o.observer,account:o.account,sources:o.sources?.length?o.sources:void 0,sway:o.sway,vehicle:o.vehicle,description:o.event.description,image:o.event.image,summary:o.event.summary,summaryTime:o.event.summaryTime,tags:o.event.tags,timeline:o.timeline.toJSON(),observerTrack:On.restatedObserverTrack(o),weatherTrack:o.weatherTrack.toJSON(),soundTrack:o.soundTrack.toJSON(),weather:o.weather,decor:On.restatedDecor(o),milestones:o.milestones.length>0?o.milestones:void 0,references:o.references.length>0?o.references:void 0,roads:o.roads.length>0?o.roads:void 0,traces:o.traces.length>0?o.traces:void 0,weatherSource:o.weatherSource,instrument:o.instrumentId,exposureSeconds:o.exposureSeconds,iso:o.iso,metering:o.metering,lens:o.lens,lightPollution:o.lightPollution,observerMap:o.observerMap,interpretation:On.restatedInterpretation(o),variants:o.variants.length>0?o.variants:void 0,skyEvents:js.written(o.skyEvents),frozen:o.frozen}}function Ix(o){Ko.check(o,"sighting");const{recording:t,provenance:e}=gs.strip(o),i=Dx(t);return i.provenance=e,i}function Dx(o){const t=[],e=new cd({eventType:"sighting",time:o.time,endTime:o.endTime,durationSeconds:o.durationSeconds,durationText:o.durationText,utcOffsetHours:o.utcOffsetHours,timeZone:o.timeZone,place:o.place,description:o.description,image:o.image,summary:o.summary,summaryTime:o.summaryTime,tags:o.tags},od.fromJSON(o.timeline,t),o.observerTrack?Nh.fromJSON(o.observerTrack):new Nh,o.weatherTrack?Uh.fromJSON(o.weatherTrack):new Uh,o.soundTrack?kh.fromJSON(o.soundTrack):new kh,o.observer&&{id:o.observer.id,title:o.observer.title,lastName:o.observer.lastName,firstNames:o.observer.firstNames},o.id,o.weather,(o.decor??[]).map(n=>{if(!n.facade?.plain)return n;const{plain:s,...a}=n.facade;return{...n,facade:{...a,openings:"plain"}}}),o.weatherSource,o.instrument,o.exposureSeconds??o.observerTrack?.keyframes.map(n=>n.pose.exposureSeconds).find(n=>n!==void 0),fh(o.milestones??[]),o.references??[],o.roads??[],o.traces??[]);e.account=o.account,e.sources=o.sources,e.sway=o.sway,e.iso=o.iso,e.metering=o.metering,e.lens=o.lens,e.lightPollution=o.lightPollution,e.observerMap=o.observerMap,e.vehicle=o.vehicle;const i=js.read(o.skyEvents,o.interpretation);return e.interpretation=i.interpretation,e.variants=Array.isArray(o.variants)?o.variants:[],e.skyEvents=i.skyEvents,e.frozen=o.frozen,e.loadIssues=t,wn.toBounds(e),wn.toPosition(e),e}class bc{static EN={"unknown-key":"{path}: unknown key, ignored","wrong-type":"{path}: expected {expected}, found {found}","not-in-list":"{path}: {found} is not one of {expected}",defaulted:"{path}: missing, {expected} used",unplaced:"{path}: no aim (and no bounds), drawn at the middle of the view",unsized:"{path}: no angular size (and no bounds), drawn one pixel wide","pixels-over-angles":"{path}: bounds restated without aim or angular, so the shape follows the pixels"};static text(t,e=bc.EN){return e[t.kind].replace("{path}",t.path).replace("{expected}",t.expected??"").replace("{found}",t.found??"")}static warn(t,e){if(t.length===0)return;const i=t.map(n=>` ${bc.text(n)}`);console.warn(`UFO@home: ${t.length} problem(s) in ${e??"this recording"}:
1737
1737
  ${i.join(`
1738
1738
  `)}`)}}class Rs{constructor(t){this.format=t}issues(t){const e=[];return this.object(t,this.format,"",e),e}object(t,e,i,n){if(!Rs.isObject(t)){n.push({kind:"wrong-type",path:i||"(the file)",expected:"object",found:Rs.typeOf(t)});return}for(const[s,a]of Object.entries(t)){const r=i?`${i}.${s}`:s,c=e[s];c?this.field(a,c,r,n):n.push({kind:"unknown-key",path:r})}}field(t,e,i,n){if(Rs.isStated(t)){this.field(t.value,e,i,n);return}if(!(e.loose||t===void 0||t===null))switch(e.type){case"enum":(typeof t!="string"||!e.values?.includes(t))&&n.push({kind:"not-in-list",path:i,expected:(e.values??[]).map(s=>`"${s}"`).join(", "),found:JSON.stringify(t)});return;case"object":e.fields?this.object(t,e.fields,i,n):Rs.isObject(t)||n.push({kind:"wrong-type",path:i,expected:"object",found:Rs.typeOf(t)});return;case"array":Array.isArray(t)?e.fields&&t.forEach((s,a)=>{const r=Rs.isStated(s)?s.value:s;this.object(r,e.fields,`${i}.${a}`,n)}):n.push({kind:"wrong-type",path:i,expected:"array",found:Rs.typeOf(t)});return;default:typeof t!==e.type&&n.push({kind:"wrong-type",path:i,expected:e.type,found:Rs.typeOf(t)})}}static isObject(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}static isStated(t){return Rs.isObject(t)&&"value"in t&&Object.keys(t).every(e=>e==="value"||e==="basis"||e==="rationale")}static typeOf(t){return Array.isArray(t)?"array":t===null?"null":typeof t}}class Ps{static PIXELS_PER_INSTANT=2;static INSTANTS_PER_FLASH=2;static MAX_INSTANTS=512;static windowEndingAt(t,e){const i=Number.isFinite(e)?Math.max(0,e):0,n=Math.max(0,t-i*1e3),s=Math.max(0,t-n);return{fromMs:n,toMs:t,ms:s,seconds:s/1e3}}static instants(t,e,i,n,s){if(!(n>0))return 1;const a=s>0?Ps.travelDegOver(t,e,i,i+n*1e3)/s/Ps.PIXELS_PER_INSTANT:0,r=Ps.flashesOver(t,n)*Ps.INSTANTS_PER_FLASH,c=Math.ceil(Math.max(a,r));return c<2?1:Math.min(Ps.MAX_INSTANTS,c)}static travelDegOver(t,e,i,n){let s=0;for(const a of t){if(!a.track||a.track.length<2)continue;const r=Ps.directionAt(a,e,i),c=Ps.directionAt(a,e,n),h=Math.min(1,Math.max(-1,r.x*c.x+r.y*c.y+r.z*c.z));s=Math.max(s,Math.acos(h)*180/Math.PI)}return s}static flashesOver(t,e){let i=0;for(const n of t)for(const s of n.lights??[])s.pattern.kind==="flash"&&(i=Math.max(i,s.pattern.perMinute));return i/60*e}static directionAt(t,e,i){const n=fa(t,i),s=n.eastM,a=n.altitudeM-e,r=n.northM,c=Math.hypot(s,a,r);return c===0?{x:0,y:1,z:0}:{x:s/c,y:a/c,z:r/c}}}function vv(o,t){for(const e of o){const i=e.toLowerCase().split("-")[0];if(t.includes(i))return i}return"en"}class lc{static preferencesFor(t){const e=navigator.languages??[],i=this.declaredFor(t);return i?[i,...e]:e}static declaredFor(t){for(let e=t;e;){const i=e.closest("[lang]")?.getAttribute("lang")?.trim();if(i)return i;const n=e.getRootNode();e=n instanceof ShadowRoot?n.host:void 0}}}class Pa{constructor(t){this.preferences=t}read(t){if(t===void 0||typeof t=="string")return t===""?void 0:t;for(const i of this.preferences){const n=t[i]??t[Pa.base(i)];if(n)return n}const e=new Set(this.preferences.map(i=>Pa.base(i)));for(const[i,n]of Object.entries(t))if(n&&e.has(Pa.base(i)))return n;return Object.values(t).find(i=>i)??void 0}write(t,e,i){const n=e?.trim()?e.trim():void 0;if(t===void 0||typeof t=="string")return n;const s={...t},a=Object.keys(s).find(r=>r===i)??Object.keys(s).find(r=>Pa.base(r)===Pa.base(i))??i;return n===void 0?delete s[a]:s[a]=n,Object.keys(s).length===0?void 0:s}static base(t){return t.toLowerCase().split("-")[0]}}const yv=["en","fr","es","it"],Cx={en:()=>Mi(()=>Promise.resolve().then(()=>Lx),void 0,import.meta.url).then(o=>o.ufoMessages_en),fr:()=>Mi(()=>import("./UfoMessages_fr-Cs2GCHEt.js"),[],import.meta.url).then(o=>o.ufoMessages_fr),es:()=>Mi(()=>import("./UfoMessages_es-BRCWkzr3.js"),[],import.meta.url).then(o=>o.ufoMessages_es),it:()=>Mi(()=>import("./UfoMessages_it-B2hvjhgb.js"),[],import.meta.url).then(o=>o.ufoMessages_it)};function Ox(o){return Cx[o]()}function Px(o){switch(o){case"fr":return Mi(()=>import("./SceneNames_fr-D5foX9zZ.js"),[],import.meta.url).then(t=>t.sceneNames_fr);case"es":return Mi(()=>import("./SceneNames_es-DU-mbey8.js"),[],import.meta.url).then(t=>t.sceneNames_es);case"it":return Mi(()=>import("./SceneNames_it-CsSU00Qr.js"),[],import.meta.url).then(t=>t.sceneNames_it);default:return Promise.resolve(void 0)}}const xv={play:"Play",clickToPlay:"Click to play",pause:"Pause",noDuration:"No observation duration",currentPosition:"Current position",duration:"Duration",switchToElapsed:"click to show elapsed time",switchToClockTime:"click to show the time of day",fullscreen:"Fullscreen",exitFullscreen:"Exit fullscreen",mute:"Mute",unmute:"Unmute",noSound:"No sound recorded",moments:"Moments",moreControls:"More controls",fewerControls:"Fewer controls",showObserverMap:"Show where the observer was",hideObserverMap:"Hide where the observer was",mapImageryUnavailable:"Aerial imagery unavailable",zoomMapIn:"Zoom in",zoomMapOut:"Zoom out",fitMap:"Back to the whole path",placeObserverHere:"Put the observer here",showReferences:"Show the pictures of the place",hideReferences:"Hide the pictures of the place",showTraces:"Show the investigator's lines",hideTraces:"Hide the investigator's lines",referenceOpacity:"Picture opacity",referencesMenu:"Pictures of the place",showMilestones:"Show the account's moments",hideMilestones:"Hide the account's moments",observerHere:"The observer, here",decorHere:"Scenery",recordingIssues:"{count} problem(s) in this recording: it may not play as its author meant",issueTemplates:bc.EN},Lx=Object.freeze(Object.defineProperty({__proto__:null,ufoMessages_en:xv},Symbol.toStringTag,{value:"Module"})),wv=Math.PI/180,Nx=180/Math.PI,Ux=256,Sv=19,kx=1.25;function bv(o,t){return 156543.03392*Math.cos(o*wv)/2**t}function Ev(o,t){return bv(o,t)*Ux}function Fx(o,t){let e=0;for(;e<Sv&&Ev(o,e+1)>=t;)e++;return e}function Av(o,t){return Ev(o,t)}function zx(o,t){const e=t*kx;let i=0;for(;i<Sv&&bv(o,i)>e;)i++;return i}function uu(o){const t=o*wv;return(1-Math.log(Math.tan(t)+1/Math.cos(t))/Math.PI)/2}function _v(o,t,e){const i=2**e;return{x:(o+180)/360*i,y:uu(t)*i}}function Tv(o,t,e){const i=uu(o.north),n=uu(o.south);return{x:(t-o.west)/(o.east-o.west),y:(uu(e)-i)/(n-i)}}function Hx(o,t,e){const{x:i,y:n}=_v(o,t,e);return{x:Math.floor(i),y:Math.floor(n),z:e}}function Bx(o){const t=2**o.z,e=o.x/t*360-180,i=(o.x+1)/t*360-180,n=hg(o.y,t);return{south:hg(o.y+1,t),north:n,west:e,east:i}}function hg(o,t){const e=o/t;return Math.atan(Math.sinh(Math.PI*(1-2*e)))*Nx}function Rv(o,t,e,i){const n=Hx(o,t,e),s=Math.floor(i/2),a=[];for(let h=-s;h<=s;h++)for(let l=-s;l<=s;l++)a.push({x:n.x+l,y:n.y+h,z:e});const r=a.map(Bx),c={south:Math.min(...r.map(h=>h.south)),north:Math.max(...r.map(h=>h.north)),west:Math.min(...r.map(h=>h.west)),east:Math.max(...r.map(h=>h.east))};return{tiles:a,bounds:c}}const Gx="#2ec4ff";class Lr{constructor(t){this.ctx=t}static SCALE_STEPS_M=[5e3,2e3,1e3,500,200,100,50,20,10,5];static MARKER_RADIUS_PX=8.5;static ON_MARKER_M=3;targets=[];hitTest(t,e){let i,n=1/0;for(const s of this.targets){const a=Math.hypot(s.x-t,s.y-e);a>s.radius||a>n||(i=s,n=a)}return i}get width(){return this.ctx.canvas.width}get height(){return this.ctx.canvas.height}paint(t){const{ctx:e}=this;e.save(),this.targets=[],e.clearRect(0,0,this.width,this.height),this.paintGround(t),this.paintNight(t.nightFraction),this.paintPath(t),this.paintTraces(t),t.position?(this.paintCone(t,t.position),this.paintDecor(t),this.paintMarkers(t),this.paintObserver(t,t.position)):(this.paintDecor(t),this.paintMarkers(t)),this.paintNorth(),this.paintFooter(t.bounds,t.attribution),e.restore()}toCanvas(t,e,i){const n=Tv(t,i,e);return{x:n.x*this.width,y:n.y*this.height}}paintGround(t){const{ctx:e}=this;e.fillStyle="#1d2321",e.fillRect(0,0,this.width,this.height);const i=t.imagery;if(!i)return;const n=this.toCanvas(t.bounds,i.bounds.north,i.bounds.west),s=this.toCanvas(t.bounds,i.bounds.south,i.bounds.east);e.drawImage(i.source,n.x,n.y,s.x-n.x,s.y-n.y)}paintNight(t=0){if(t<=0)return;const{ctx:e}=this;e.save(),e.fillStyle=`rgba(6, 12, 30, ${Math.min(t,1)*.78})`,e.fillRect(0,0,this.width,this.height),e.restore()}paintDecor(t){const{ctx:e}=this;for(const i of t.decor){const n=this.toCanvas(t.bounds,i.lat,i.lng);if(i.label&&this.targets.push({kind:"decor",label:i.label,lat:i.lat,lng:i.lng,x:n.x,y:n.y,radius:7}),e.beginPath(),e.rect(n.x-3.5,n.y-3.5,7,7),e.fillStyle="rgba(120, 220, 255, 0.85)",e.fill(),e.lineWidth=1.5,e.strokeStyle="rgba(0, 0, 0, 0.7)",e.stroke(),i.headingDeg===void 0)continue;const s=(i.headingDeg-90)*Math.PI/180;e.beginPath(),e.moveTo(n.x,n.y),e.lineTo(n.x+Math.cos(s)*10,n.y+Math.sin(s)*10),e.lineWidth=3,e.strokeStyle="rgba(0, 0, 0, 0.6)",e.stroke(),e.lineWidth=1.5,e.strokeStyle="rgba(120, 220, 255, 0.9)",e.stroke()}}paintPath(t){if(!t.path.moved)return;const{ctx:e}=this,i=t.path.points.map(n=>this.toCanvas(t.bounds,n.lat,n.lng));e.beginPath(),e.moveTo(i[0].x,i[0].y);for(const n of i.slice(1))e.lineTo(n.x,n.y);e.lineJoin="round",e.lineCap="round",e.strokeStyle="rgba(0, 0, 0, 0.65)",e.lineWidth=5,e.stroke(),e.strokeStyle="rgba(255, 255, 255, 0.9)",e.lineWidth=2,e.stroke()}paintTraces(t){const{ctx:e}=this;for(const i of t.traces??[]){const n=i.points.map(a=>this.toCanvas(t.bounds,a.lat,a.lng));if(n.length===0)continue;const s=i.color??Gx;if(i.kind==="point")e.beginPath(),e.moveTo(n[0].x,n[0].y-6),e.lineTo(n[0].x+6,n[0].y),e.lineTo(n[0].x,n[0].y+6),e.lineTo(n[0].x-6,n[0].y),e.closePath(),e.fillStyle=s,e.fill(),e.lineWidth=1.5,e.strokeStyle="rgba(0, 0, 0, 0.8)",e.stroke();else{e.beginPath(),e.moveTo(n[0].x,n[0].y);for(const a of n.slice(1))e.lineTo(a.x,a.y);i.kind==="polygon"&&e.closePath(),e.lineJoin="round",e.setLineDash([]),e.strokeStyle="rgba(0, 0, 0, 0.65)",e.lineWidth=4.5,e.stroke(),e.setLineDash([9,5]),e.strokeStyle=s,e.lineWidth=2.5,e.stroke(),e.setLineDash([])}if(i.label){e.font="11px sans-serif",e.textAlign="left",e.textBaseline="middle";let a=n[0];if(i.kind==="line"&&t.position){const r=this.toCanvas(t.bounds,t.position.lat,t.position.lng);a=n.reduce((c,h)=>Math.hypot(h.x-r.x,h.y-r.y)>Math.hypot(c.x-r.x,c.y-r.y)?h:c)}this.paintOutlinedText(i.label,a.x+9,a.y-9)}}}paintCone(t,e){const{headingDeg:i,coneHalfAngleDeg:n}=t;if(i===void 0||n===void 0)return;const{ctx:s}=this,a=this.toCanvas(t.bounds,e.lat,e.lng),r=Math.hypot(this.width,this.height),c=(i-90)*Math.PI/180,h=n*Math.PI/180;s.save(),s.beginPath(),s.moveTo(a.x,a.y),s.arc(a.x,a.y,r,c-h,c+h),s.closePath();const l=s.createRadialGradient(a.x,a.y,0,a.x,a.y,r);l.addColorStop(0,"rgba(255, 224, 130, 0.55)"),l.addColorStop(.35,"rgba(255, 224, 130, 0.22)"),l.addColorStop(1,"rgba(255, 224, 130, 0)"),s.fillStyle=l,s.fill(),s.restore()}paintMarkers(t){const{ctx:e}=this;e.textAlign="center",e.textBaseline="middle",e.font="bold 10px sans-serif";for(const i of[...t.markers].sort((n,s)=>Number(n.current)-Number(s.current))){const n=this.toCanvas(t.bounds,i.lat,i.lng);this.targets.push({kind:"milestone",label:i.note?`${i.label} — ${i.note}`:i.label,lat:i.lat,lng:i.lng,t:i.t,x:n.x,y:n.y,radius:Lr.MARKER_RADIUS_PX}),e.beginPath(),e.arc(n.x,n.y,Lr.MARKER_RADIUS_PX,0,Math.PI*2),e.fillStyle=i.current?"rgba(255, 224, 130, 0.95)":"rgba(0, 0, 0, 0.55)",e.fill(),e.lineWidth=2,e.strokeStyle="rgba(255, 255, 255, 0.9)",e.stroke(),e.fillStyle=i.current?"#1d2321":"#fff",e.fillText(i.label,n.x,n.y)}}paintObserver(t,e){const{ctx:i}=this,n=this.toCanvas(t.bounds,e.lat,e.lng);t.observerLabel&&this.targets.push({kind:"observer",label:t.observerLabel,lat:e.lat,lng:e.lng,x:n.x,y:n.y,radius:8});const s=t.markers.some(a=>{if(!a.current)return!1;const r=ae(a.lat,a.lng,e.lat,e.lng);return Math.hypot(r.x,r.z)<=Lr.ON_MARKER_M});i.beginPath(),i.arc(n.x,n.y,s?Lr.MARKER_RADIUS_PX+2.5:5.5,0,Math.PI*2),s||(i.fillStyle="#ff5a3c",i.fill()),i.lineWidth=4,i.strokeStyle="rgba(0, 0, 0, 0.5)",i.stroke(),i.lineWidth=s?3:2.5,i.strokeStyle=s?"#ff5a3c":"#fff",i.stroke()}paintNorth(){const{ctx:t}=this,e=this.width-14,i=16;t.beginPath(),t.moveTo(e,i-9),t.lineTo(e-4.5,i+5),t.lineTo(e,i+2),t.lineTo(e+4.5,i+5),t.closePath(),t.fillStyle="rgba(255, 255, 255, 0.92)",t.strokeStyle="rgba(0, 0, 0, 0.6)",t.lineWidth=1,t.fill(),t.stroke(),t.font="bold 9px sans-serif",t.textAlign="center",t.textBaseline="top",t.strokeText("N",e,i+6),t.fillText("N",e,i+6)}paintFooter(t,e){const{ctx:i}=this;i.font="9px sans-serif",i.textBaseline="bottom";const n=e?this.wrap(e,this.width-20):[];let s=this.height-4;i.textAlign="right";for(const f of n.slice().reverse())this.paintOutlinedText(f,this.width-6,s),s-=11;const a=(t.south+t.north)/2,c=Math.abs(ae(a,t.east,a,t.west).x)/this.width,h=Lr.SCALE_STEPS_M.find(f=>f/c<=this.width/3);if(h===void 0)return;const l=h/c,u=8,d=s-3;i.lineWidth=3,i.strokeStyle="rgba(0, 0, 0, 0.6)",i.beginPath(),i.moveTo(u,d),i.lineTo(u+l,d),i.stroke(),i.lineWidth=1.5,i.strokeStyle="rgba(255, 255, 255, 0.95)",i.stroke(),i.textAlign="left",this.paintOutlinedText(h>=1e3?`${h/1e3} km`:`${h} m`,u,d-3)}paintOutlinedText(t,e,i){const{ctx:n}=this;n.lineWidth=3,n.strokeStyle="rgba(0, 0, 0, 0.75)",n.strokeText(t,e,i),n.fillStyle="#fff",n.fillText(t,e,i)}wrap(t,e){const i=[];let n="";for(const s of t.split(" ")){const a=n?`${n} ${s}`:s;n&&this.ctx.measureText(a).width>e?(i.push(n),n=s):n=a}return n&&i.push(n),i}}class ei{static MIN_ZOOM=.25;static MAX_ZOOM=64;static MIN_SPAN_M=400;static MARGIN=.6;static IMAGERY_PX=768;static fitted(t,e){return ei.including(t.boundsAround(ei.MIN_SPAN_M,ei.MARGIN),e)}zoom=1;centerX=.5;centerY=.5;get changed(){return this.zoom!==1||this.centerX!==.5||this.centerY!==.5}get zoomFactor(){return this.zoom}reset(){this.zoom=1,this.centerX=.5,this.centerY=.5}zoomAt(t,e,i){const n=Math.min(ei.MAX_ZOOM,Math.max(ei.MIN_ZOOM,this.zoom*i)),s=this.centerX+(t-.5)/this.zoom,a=this.centerY+(e-.5)/this.zoom;this.centerX=s-(t-.5)/n,this.centerY=a-(e-.5)/n,this.zoom=n}panBy(t,e){this.centerX-=t/this.zoom,this.centerY-=e/this.zoom}refit(t,e){if(!this.changed)return;const i=this.boundsWithin(t),n=ei.mercatorY01(e.north),s=ei.mercatorY01(e.south),a=ei.mercatorY01(i.north),r=ei.mercatorY01(i.south);this.zoom=(e.east-e.west)/(i.east-i.west),this.centerX=((i.west+i.east)/2-e.west)/(e.east-e.west),this.centerY=((a+r)/2-n)/(s-n)}keepInView(t,e,i){if(!this.changed)return!1;const n=this.boundsWithin(t),s=ei.mercatorY01(n.north),a=ei.mercatorY01(n.south),r=(e.lng-n.west)/(n.east-n.west),c=(ei.mercatorY01(e.lat)-s)/(a-s);return r>=i&&r<=1-i&&c>=i&&c<=1-i?!1:(this.panBy(.5-r,.5-c),!0)}boundsWithin(t){if(!this.changed)return t;const e=.5/this.zoom,i=ei.mercatorY01(t.north),n=ei.mercatorY01(t.south),s=t.east-t.west;return{west:t.west+(this.centerX-e)*s,east:t.west+(this.centerX+e)*s,north:ei.latitudeAt(i+(this.centerY-e)*(n-i)),south:ei.latitudeAt(i+(this.centerY+e)*(n-i))}}static including(t,e,i=3){const n=(t.north+t.south)/2,s=(t.east+t.west)/2,a=ae(n,t.east,n,s).x;let r=a;for(const c of e){const{x:h,z:l}=ae(c.lat,c.lng,n,s),u=Math.max(Math.abs(h),Math.abs(l));u<=a*i&&(r=Math.max(r,u*1.15))}return r<=a?t:{north:Kn(0,-r,n,s).lat,south:Kn(0,r,n,s).lat,east:Kn(r,0,n,s).lng,west:Kn(-r,0,n,s).lng}}static expand(t,e){const i=t.east-t.west,n=t.north-t.south;return{west:t.west-i*e,east:t.east+i*e,south:t.south-n*e,north:t.north+n*e}}static pointAt(t,e,i){const n=ei.mercatorY01(t.north),s=ei.mercatorY01(t.south);return{lat:ei.latitudeAt(n+i*(s-n)),lng:t.west+e*(t.east-t.west)}}static mercatorY01(t){const e=t*Math.PI/180;return(1-Math.log(Math.tan(e)+1/Math.cos(e))/Math.PI)/2}static latitudeAt(t){return Math.atan(Math.sinh(Math.PI*(1-2*t)))*180/Math.PI}}const ls=256,lg=3,Vx=32768;class Wx{fetchImpl;tileUrlTemplate;constructor(t={}){this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.tileUrlTemplate=t.tileUrlTemplate??"https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png"}async getElevationGrid(t,e){const i=(t.south+t.north)/2,n=(t.west+t.east)/2,s=Math.abs(ae(i,t.east,i,t.west).x),a=Math.abs(ae(t.north,n,t.south,n).z),r=Fx(i,Math.max(s,a)),{tiles:c}=Rv(n,i,r,lg),h=lg*ls,l=new Float32Array(h*h),u=c[0];await Promise.all(c.map(f=>this.decodeTileInto(f,u,l,h)));const d=new Float32Array(e.width*e.height);for(let f=0;f<e.height;f++){const p=t.north+(t.south-t.north)*(f/(e.height-1));for(let g=0;g<e.width;g++){const m=t.west+(t.east-t.west)*(g/(e.width-1));d[f*e.width+g]=this.sampleAt(p,m,r,u,l,h)}}return{heights:d,width:e.width,height:e.height,bounds:t}}async decodeTileInto(t,e,i,n){const s=this.tileUrlTemplate.replace("{z}",String(t.z)).replace("{x}",String(t.x)).replace("{y}",String(t.y)),a=await this.fetchImpl(s);if(!a.ok)throw new Error(`Elevation tile fetch failed (${a.status}): ${s}`);const r=await createImageBitmap(await a.blob()),c=document.createElement("canvas");c.width=ls,c.height=ls;const h=c.getContext("2d");if(!h)throw new Error("2D canvas context unavailable");h.drawImage(r,0,0);const{data:l}=h.getImageData(0,0,ls,ls),u=(t.x-e.x)*ls,d=(t.y-e.y)*ls;for(let f=0;f<ls;f++)for(let p=0;p<ls;p++){const g=(f*ls+p)*4,m=l[g]*256+l[g+1]+l[g+2]/256-Vx,M=u+p,y=d+f;i[y*n+M]=m}}sampleAt(t,e,i,n,s,a){const{x:r,y:c}=_v(e,t,i),h=(r-n.x)*ls,l=(c-n.y)*ls,u=Math.max(0,Math.min(a-1,Math.floor(h))),d=Math.max(0,Math.min(a-1,Math.floor(l))),f=Math.min(a-1,u+1),p=Math.min(a-1,d+1),g=h-u,m=l-d,M=s[d*a+u],y=s[d*a+f],x=s[p*a+u],v=s[p*a+f],w=M+(y-M)*g,b=x+(v-x)*g;return w+(b-w)*m}}class hd{constructor(t,e,i,n){this.width=t,this.height=e,this.samples=i,this.values=n}at(t,e,i=0){return this.values[(e*this.width+t)*this.samples+i]}static parse(t){const e=new DataView(t);if(t.byteLength<8||e.getUint16(0)!==18761||e.getUint16(2,!0)!==42)throw new Error("Not a little-endian TIFF");const i=e.getUint32(4,!0),n=e.getUint16(i,!0),s=new Map;for(let M=0;M<n;M++){const y=i+2+M*12;s.set(e.getUint16(y,!0),{type:e.getUint16(y+2,!0),count:e.getUint32(y+4,!0),value:e.getUint32(y+8,!0)})}const a=(M,y)=>{const x=s.get(M);if(x===void 0){if(y===void 0)throw new Error(`TIFF without tag ${M}`);return y}return x.type===3?x.value&65535:x.value},r=M=>{const y=s.get(M);if(y===void 0)throw new Error(`TIFF without tag ${M}`);const x=y.type===3?2:4,v=[];if(y.count*x<=4){const w=new DataView(new ArrayBuffer(4));w.setUint32(0,y.value,!0);for(let b=0;b<y.count;b++)v.push(x===2?w.getUint16(b*2,!0):w.getUint32(0,!0))}else for(let w=0;w<y.count;w++)v.push(x===2?e.getUint16(y.value+w*2,!0):e.getUint32(y.value+w*4,!0));return v};if(a(259,1)!==1)throw new Error("Compressed TIFF");if(s.has(322))throw new Error("Tiled TIFF");const c=a(256),h=a(257),l=a(277,1),u=r(258)[0],d=a(339,1)===3;if(!(d&&u===32||!d&&u===8))throw new Error(`Unsupported TIFF samples: ${u} bits`);const f=r(273),p=r(279),g=new Uint8Array(c*h*l*(u/8));let m=0;for(let M=0;M<f.length&&m<g.length;M++){const y=Math.min(p[M],g.length-m);g.set(new Uint8Array(t,f[M],y),m),m+=y}if(m<g.length)throw new Error("Truncated TIFF");return new hd(c,h,l,d?new Float32Array(g.buffer):g)}}class Xa extends Error{constructor(t,e){super(e),this.reason=t,this.name="SurroundingsUnavailableError"}}class Xx{constructor(t,e,i,n,s){this.heights=t,this.plants=e,this.buildings=i,this.size=n,this.metresPerPixel=s}structureAt(t,e){const i=Math.floor(t/this.metresPerPixel+this.size/2),n=Math.floor(this.size/2-e/this.metresPerPixel);if(i<0||n<0||i>=this.size||n>=this.size)return;const s=n*this.size+i;if(!(this.plants[s]||this.buildings[s]))return this.heights[s]}tallestStructureNear(t,e,i){let n;const s=Math.ceil(i/this.metresPerPixel);for(let a=-s;a<=s;a++)for(let r=-s;r<=s;r++){if(Math.hypot(r,a)*this.metresPerPixel>i)continue;const c=this.structureAt(t+r*this.metresPerPixel,e+a*this.metresPerPixel);c!==void 0&&(n===void 0||c>n)&&(n=c)}return n}}class Re{static covers(t,e){return t>=41.2&&t<=51.3&&e>=-5.4&&e<=9.8}static WMS="https://data.geopf.fr/wms-r/wms";static WFS="https://data.geopf.fr/wfs/ows";static HEIGHT_LAYER="IGNF_LIDAR-HD_MNH_ELEVATION.ELEVATIONGRIDCOVERAGE.LAMB93";static CLASS_LAYER="IGNF_LIDAR-HD_CLASS";static PHOTO_LAYER="ORTHOIMAGERY.ORTHOPHOTOS";static MAX_PHOTO_PIXELS=1e3;static METRES_PER_PIXEL=.5;static MAX_RADIUS_M=3e3;static MAX_LIDAR_RADIUS_M=150;static NO_DATA=-9999;static METRES_PER_DEGREE=111320;fetchImpl;wms;wfs;constructor(t={}){this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.wms=t.wmsEndpoint??Re.WMS,this.wfs=t.wfsEndpoint??Re.WFS}static radius(t){return Math.min(t,Re.MAX_RADIUS_M)}static lidarRadius(t){return Math.min(t,Re.MAX_LIDAR_RADIUS_M)}async lidar(t,e){const i=Re.lidarRadius(e),n=Math.ceil(2*i/Re.METRES_PER_PIXEL),[s,a]=await Promise.all([this.raster(t,i,n,Re.HEIGHT_LAYER),this.raster(t,i,n,Re.CLASS_LAYER)]);if(s.samples!==1||a.samples<3)throw new Xa("unreachable","The survey answered in a layout this does not read");const r=s.values;if(r.every(u=>u===Re.NO_DATA))throw new Xa("no-coverage","No LiDAR HD survey here yet");const c=new Uint8Array(n*n),h=new Uint8Array(n*n);for(let u=0;u<n*n;u++){const d=a.values[u*a.samples],f=a.values[u*a.samples+1],p=a.values[u*a.samples+2];c[u]=f>d&&f>p?1:0,h[u]=d>120&&f<90&&p<90?1:0}const l=2*i/n;return{size:n,metresPerPixel:l,heights:r,vegetation:c,building:h,structures:new Xx(r,c,h,n,l)}}async laserDate(t){return Re.latest(await this.dated("IGNF_LIDAR-HD_METADONNEE:metadata","geom","date_fin_acquisition",t))}async photoDate(t){return Re.latest(await this.dated("ORTHOIMAGERY.ORTHOPHOTOS.GRAPHE-MOSAIQUAGE:graphe_bdortho","geom","date_vol",t))}static latest(t){return t.map(i=>/^\d{4}-\d{2}-\d{2}/.exec(String(i??""))?.[0]).filter(i=>i!==void 0).sort().at(-1)}async dated(t,e,i,n){const a=[n.lng-1e-4,n.lat-1e-4,n.lng+1e-4,n.lat+1e-4].map(r=>r.toFixed(6)).join(",");try{return(await this.features(t,`BBOX(${e},${a},'EPSG:4326')`,i,20)).map(r=>r.properties[i])}catch{return[]}}async photo(t,e){const i=Re.radius(e),n=Math.min(Re.MAX_PHOTO_PIXELS,Math.ceil(2*i/Re.METRES_PER_PIXEL)),s=await this.raster(t,i,n,Re.PHOTO_LAYER);if(s.samples<3)throw new Xa("unreachable","The photograph came in a layout this does not read");return{size:n,metresPerPixel:2*i/n,samples:s.samples,values:s.values}}async vectors(t,e,i){const n=Re.radius(e),s=n/Re.METRES_PER_DEGREE,a=n/(Re.METRES_PER_DEGREE*Math.cos(t.lat*Math.PI/180)),c=`BBOX(geometrie,${[t.lng-a,t.lat-s,t.lng+a,t.lat+s].map(M=>M.toFixed(6)).join(",")},'EPSG:4326')`,[h,l,u,d,f,p]=await Promise.all([this.features("construction_lineaire",`${c} AND nature='Pont'`,"nature,geometrie"),this.features("troncon_de_route",`${c} AND position_par_rapport_au_sol>'0'`,"nature,largeur_de_chaussee,position_par_rapport_au_sol,nom_voie_ban_gauche,nom_voie_ban_droite,cpx_toponyme_route_nommee,geometrie"),this.features("troncon_de_voie_ferree",`${c} AND position_par_rapport_au_sol>'0'`,"position_par_rapport_au_sol,geometrie").catch(()=>[]),this.features("ligne_electrique",c,"voltage,geometrie"),i?this.features("batiment",c,Re.BUILDING_PROPERTIES,5e3):Promise.resolve([]),i?this.features("zone_d_activite_ou_d_interet",c,"toponyme,categorie,geometrie",100).catch(()=>[]):Promise.resolve([])]),g=i?await this.wholeWorship(p,f,[t.lng-a,t.lat-s,t.lng+a,t.lat+s]):[],m=[...f,...g];return{bridges:h,elevatedRoads:l,elevatedRailways:u,lines:d,buildings:m,zones:p,mapDate:Re.latest(m.map(M=>M.properties.date_modification))}}static BUILDING_PROPERTIES="cleabs,nature,usage_1,hauteur,nombre_d_etages,materiaux_des_murs,materiaux_de_la_toiture,date_d_apparition,date_modification,geometrie";static MAX_WHOLE_M=300;async wholeWorship(t,e,i){const[n,s,a,r]=i,c=Re.MAX_WHOLE_M/Re.METRES_PER_DEGREE;let h;for(const u of t){if(u.properties.categorie!=="Religieux")continue;const[d,f,p,g]=Re.extent(u);if(d>=n&&f>=s&&p<=a&&g<=r)continue;const m=[Math.max(d,n-c),Math.max(f,s-c),Math.min(p,a+c),Math.min(g,r+c)];h=h?[Math.min(h[0],m[0]),Math.min(h[1],m[1]),Math.max(h[2],m[2]),Math.max(h[3],m[3])]:m}if(!h)return[];const l=new Set(e.map(u=>u.properties.cleabs));try{return(await this.features("batiment",`BBOX(geometrie,${h.map(d=>d.toFixed(6)).join(",")},'EPSG:4326')`,Re.BUILDING_PROPERTIES,1e3)).filter(d=>!l.has(d.properties.cleabs))}catch{return[]}}static extent(t){let e=1/0,i=1/0,n=-1/0,s=-1/0;const a=r=>{Array.isArray(r)&&typeof r[0]=="number"?(e=Math.min(e,r[0]),n=Math.max(n,r[0]),i=Math.min(i,r[1]),s=Math.max(s,r[1])):Array.isArray(r)&&r.forEach(a)};return a(t.geometry.coordinates),[e,i,n,s]}async elevatedRoadLines(t){const e=`BBOX(geometrie,${[t.west,t.south,t.east,t.north].map(s=>s.toFixed(6)).join(",")},'EPSG:4326')`,i=await this.features("troncon_de_route",`${e} AND position_par_rapport_au_sol>'0'`,"geometrie",300),n=[];for(const s of i){const{type:a,coordinates:r}=s.geometry,c=a==="LineString"?[r]:a==="MultiLineString"?r:[];for(const h of c)n.push(h.map(l=>({lat:l[1],lng:l[0]})))}return n}async waterSurfaces(t){const e=`BBOX(geometrie,${[t.west,t.south,t.east,t.north].map(i=>i.toFixed(6)).join(",")},'EPSG:4326')`;return this.features("surface_hydrographique",`${e} AND position_par_rapport_au_sol='0' AND persistance='Permanent'`,"cleabs,nature,geometrie",500)}async roads(t){const e=`BBOX(geometrie,${[t.west,t.south,t.east,t.north].map(i=>i.toFixed(6)).join(",")},'EPSG:4326')`;return this.features("troncon_de_route",`${e} AND nature<>'Sentier' AND nature<>'Escalier' AND position_par_rapport_au_sol>='0'`,"cleabs,nature,largeur_de_chaussee,nombre_de_voies,sens_de_circulation,vitesse_moyenne_vl,urbain,nom_voie_ban_gauche,nom_voie_ban_droite,cpx_toponyme_route_nommee,geometrie",3e3)}async railways(t){const e=`BBOX(geometrie,${[t.west,t.south,t.east,t.north].map(i=>i.toFixed(6)).join(",")},'EPSG:4326')`;return this.features("troncon_de_voie_ferree",`${e} AND etat_de_l_objet='En service'`,"cleabs,nature,electrifie,largeur,nombre_de_voies,position_par_rapport_au_sol,cpx_toponyme,geometrie",3e3)}async raster(t,e,i,n){const s=e/Re.METRES_PER_DEGREE,a=e/(Re.METRES_PER_DEGREE*Math.cos(t.lat*Math.PI/180)),r=new URLSearchParams({SERVICE:"WMS",VERSION:"1.3.0",REQUEST:"GetMap",LAYERS:n,STYLES:"",CRS:"EPSG:4326",BBOX:[t.lat-s,t.lng-a,t.lat+s,t.lng+a].map(h=>h.toFixed(6)).join(","),WIDTH:String(i),HEIGHT:String(i),FORMAT:"image/geotiff"});let c;try{c=await this.fetchImpl(`${this.wms}?${r}`)}catch(h){throw new Xa("unreachable",h instanceof Error?h.message:String(h))}if(!c.ok)throw new Xa("unreachable",`The survey answered ${c.status}`);try{return hd.parse(await c.arrayBuffer())}catch(h){throw new Xa("unreachable",h instanceof Error?h.message:String(h))}}async features(t,e,i,n=200){const s=new URLSearchParams({SERVICE:"WFS",VERSION:"2.0.0",REQUEST:"GetFeature",TYPENAMES:t.includes(":")?t:`BDTOPO_V3:${t}`,SRSNAME:"EPSG:4326",OUTPUTFORMAT:"application/json",COUNT:String(n),CQL_FILTER:e,PROPERTYNAME:i});let a;try{a=await this.fetchImpl(`${this.wfs}?${s}`)}catch(c){throw new Xa("unreachable",c instanceof Error?c.message:String(c))}if(!a.ok)throw new Xa("unreachable",`The map answered ${a.status}`);return(await a.json()).features??[]}}class sr{static NEAR_M=15;static ALIGNED_DEG=30;static LONG_ENOUGH_M=15;static SAMPLE_M=5;static follows(t,e){if(t.length<2||e.length<2)return!1;const i=e[0],n=e.map(r=>ae(r.lat,r.lng,i.lat,i.lng)),s=t.map(r=>ae(r.lat,r.lng,i.lat,i.lng));let a=0;for(let r=0;r<s.length-1;r++){const c=s[r],h=s[r+1],l=Math.hypot(h.x-c.x,h.z-c.z);if(l<1e-6)continue;const u=Math.max(1,Math.ceil(l/sr.SAMPLE_M)),d=Math.atan2(h.x-c.x,-(h.z-c.z));for(let f=0;f<=u;f++){const p=f/u,g=sr.nearest(n,c.x+(h.x-c.x)*p,c.z+(h.z-c.z)*p);g.distanceM>sr.NEAR_M||sr.angleBetween(d,g.heading)<=sr.ALIGNED_DEG&&(a+=l/u)}}return a>=sr.LONG_ENOUGH_M}static nearest(t,e,i){let n={distanceM:1/0,heading:0};for(let s=0;s<t.length-1;s++){const a=t[s],r=t[s+1],c=r.x-a.x,h=r.z-a.z,l=c*c+h*h,u=l<1e-9?0:Math.max(0,Math.min(1,((e-a.x)*c+(i-a.z)*h)/l)),d=Math.hypot(e-(a.x+c*u),i-(a.z+h*u));d<n.distanceM&&(n={distanceM:d,heading:Math.atan2(c,-h)})}return n}static angleBetween(t,e){const i=Math.abs((t-e)*180/Math.PI%180);return Math.min(i,180-i)}}class Ae{static WMS="https://data.geopf.fr/wms-r/wms";static LAYERS=["IGNF_LIDAR-HD_MNT_ELEVATION.ELEVATIONGRIDCOVERAGE.LAMB93","ELEVATION.ELEVATIONGRIDCOVERAGE.HIGHRES"];static METRES_PER_PIXEL=4;static METRES_PER_DEGREE=111320;static CLASS_LAYER="IGNF_LIDAR-HD_CLASS";static SURFACE_LAYER="IGNF_LIDAR-HD_MNS_ELEVATION.ELEVATIONGRIDCOVERAGE.LAMB93";static DECK=[240,240,0];static NO_CLASS=[0,0,0];static DECK_END_PIXELS=3;static DECK_HALF_WIDTH_M=8;static DECK_APPROACH_M=10;static DECK_STRAIGHT_MAX_M=200;static MIN_PIXELS=8;static MAX_PIXELS=700;static NO_DATA_BELOW=-100;static COARSE_METRES_PER_PIXEL=20;static MESH_FROM_VERTICES=33;static FINE_SPACING_M=7;static MAX_SEGMENTS=256;static MAX_HOLE_SHARE=.05;static DEFAULT_TIMEOUT_MS=12e3;static MAX_WINDOW_M=50;fetchImpl;wms;timeoutMs;maxWindowM;geoplatform;constructor(t={}){this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.wms=t.wmsEndpoint??Ae.WMS,this.timeoutMs=t.timeoutMs??Ae.DEFAULT_TIMEOUT_MS,this.maxWindowM=t.maxWindowM??Ae.MAX_WINDOW_M,this.geoplatform=new Re({fetchImpl:this.fetchImpl,wmsEndpoint:this.wms,wfsEndpoint:t.wfsEndpoint})}async getElevationGrid(t,e,i){const n={lat:(t.south+t.north)/2,lng:(t.west+t.east)/2};if(!Re.covers(n.lat,n.lng))throw new Error("The IGN's relief covers France only");const s=Math.abs(ae(n.lat,t.east,n.lat,t.west).x),a=Math.abs(ae(t.north,n.lng,t.south,n.lng).z);e=this.finer(e,s,a);const r={x:s/Math.max(1,e.width-1),y:a/Math.max(1,e.height-1)},c={x:Math.min(r.x,this.maxWindowM),y:Math.min(r.y,this.maxWindowM)},h={south:t.south-c.y/Ae.METRES_PER_DEGREE,north:t.north+c.y/Ae.METRES_PER_DEGREE,west:t.west-c.x/(Ae.METRES_PER_DEGREE*Math.cos(n.lat*Math.PI/180)),east:t.east+c.x/(Ae.METRES_PER_DEGREE*Math.cos(n.lat*Math.PI/180))},l=g=>Math.min(Ae.MAX_PIXELS,Math.max(Ae.MIN_PIXELS,Math.ceil(g/Ae.METRES_PER_PIXEL))),u={width:l(s+2*c.x),height:l(a+2*c.y)},d={x:(s+2*c.x)/u.width,y:(a+2*c.y)/u.height};let f=new Error("No layer of the IGN's relief answered");const p=Math.max(d.x,d.y)>Ae.COARSE_METRES_PER_PIXEL;for(const g of p?[...Ae.LAYERS].reverse():Ae.LAYERS)try{const m=await this.heights(h,u,g);g===Ae.LAYERS[0]&&await this.layBridgeDecks(m,h,u,i?.route);const M=this.sample(m,e,t,h,d,r);if(M)return{heights:M,width:e.width,height:e.height,bounds:t};f=new Error(`${g} does not cover this place`)}catch(m){f=m}throw f}finer(t,e,i){if(t.width<Ae.MESH_FROM_VERTICES||t.height<Ae.MESH_FROM_VERTICES)return t;const n=(s,a)=>{const r=Math.ceil(s/Ae.FINE_SPACING_M),c=Math.max(a-1,Math.min(Ae.MAX_SEGMENTS,r));return c%2===0?c:c+1};return{width:n(e,t.width)+1,height:n(i,t.height)+1}}async raster(t,e,i){const n=new URLSearchParams({SERVICE:"WMS",VERSION:"1.3.0",REQUEST:"GetMap",LAYERS:i,STYLES:"",CRS:"EPSG:4326",BBOX:[t.south,t.west,t.north,t.east].map(a=>a.toFixed(6)).join(","),WIDTH:String(e.width),HEIGHT:String(e.height),FORMAT:"image/geotiff"}),s=await this.fetchImpl(`${this.wms}?${n}`,{signal:AbortSignal.timeout(this.timeoutMs)});if(!s.ok)throw new Error(`The IGN's relief answered ${s.status}`);return hd.parse(await s.arrayBuffer())}async heights(t,e,i){const n=await this.raster(t,e,i);if(n.samples!==1||!(n.values instanceof Float32Array))throw new Error("The IGN's relief came in a layout this does not read");return n}async layBridgeDecks(t,e,i,n){if(!(!n||n.length<2)&&!(!(t.values instanceof Float32Array)||!t.values.some(s=>s>Ae.NO_DATA_BELOW)))try{const s=(await this.geoplatform.elevatedRoadLines({west:e.west,south:e.south,east:e.east,north:e.north})).filter(r=>sr.follows(n,r));if(s.length===0)return;const a=Float32Array.from(t.values);await this.layClassifiedDecks(t,e,i,s),this.layRouteDecks(t,a,e,s)}catch{}}async layClassifiedDecks(t,e,i,n){try{const s=await this.raster(e,i,Ae.CLASS_LAYER);if(s.samples<3||s.width!==t.width||s.height!==t.height)return;const a=(m,[M,y,x])=>s.values[m*s.samples]===M&&s.values[m*s.samples+1]===y&&s.values[m*s.samples+2]===x,r=t.width,c=t.height,h=new Uint8Array(r*c);let l=!1;for(let m=0;m<h.length;m++)a(m,Ae.DECK)&&(h[m]=1,l=!0);if(!l)return;const u=Ae.DECK_END_PIXELS,d=[];for(let m=0;m<h.length;m++){if(h[m]!==1)continue;const M=m%r,y=(m-M)/r;for(let x=-u;x<=u;x++)for(let v=-u;v<=u;v++){const w=M+v,b=y+x;if(w<0||b<0||w>=r||b>=c)continue;const _=b*r+w;h[_]===0&&a(_,Ae.NO_CLASS)&&d.push(_)}}for(const m of d)h[m]=1;const f=this.paint(n,e,r,c),p=this.touching(h,f,r,c);if(p.every(m=>m===0))return;const g=await this.heights(e,i,Ae.SURFACE_LAYER);if(g.width!==r||g.height!==c)return;for(let m=0;m<p.length;m++){if(p[m]===0)continue;const M=g.values[m];Number.isFinite(M)&&M>Ae.NO_DATA_BELOW&&M>t.values[m]&&(t.values[m]=M)}}catch{}}layRouteDecks(t,e,i,n){const{width:s,height:a}=t,r=(i.north+i.south)/2,c=(i.east-i.west)*Ae.METRES_PER_DEGREE*Math.cos(r*Math.PI/180),h=(i.north-i.south)*Ae.METRES_PER_DEGREE,l=c/s,u=h/a,d=M=>({x:(M.lng-i.west)/(i.east-i.west)*c,y:(i.north-M.lat)/(i.north-i.south)*h}),f=(M,y)=>{const x=Math.floor(M/l),v=Math.floor(y/u);if(x<0||v<0||x>=s||v>=a)return;const w=e[v*s+x];return Number.isFinite(w)&&w>Ae.NO_DATA_BELOW?w:void 0},p=Ae.DECK_HALF_WIDTH_M,g=Ae.DECK_APPROACH_M,m=(M,y)=>{const x=Math.hypot(M.x-y.x,M.y-y.y)||1,v={x:(M.x-y.x)/x,y:(M.y-y.y)/x},w=[0,g/2,g].map(b=>f(M.x+v.x*b,M.y+v.y*b)).filter(b=>b!==void 0);return w.length>0?Math.max(...w):void 0};for(const M of Ae.chains(n.map(y=>y.map(d)))){const y=[0];for(let D=1;D<M.length;D++)y.push(y[D-1]+Math.hypot(M[D].x-M[D-1].x,M[D].y-M[D-1].y));const x=y[y.length-1];if(x<1||x>Ae.DECK_STRAIGHT_MAX_M)continue;const v=m(M[0],M[1]),w=m(M[M.length-1],M[M.length-2]);if(v===void 0||w===void 0)continue;const b=p+g,_=Math.max(0,Math.floor((Math.min(...M.map(D=>D.x))-b)/l)),S=Math.min(s-1,Math.ceil((Math.max(...M.map(D=>D.x))+b)/l)),A=Math.max(0,Math.floor((Math.min(...M.map(D=>D.y))-b)/u)),I=Math.min(a-1,Math.ceil((Math.max(...M.map(D=>D.y))+b)/u));for(let D=A;D<=I;D++)for(let C=_;C<=S;C++){const L=Ae.nearestAlong(M,y,{x:(C+.5)*l,y:(D+.5)*u});if(L.distance>p||L.s<-g||L.s>x+g)continue;const N=v+(w-v)*Math.min(1,Math.max(0,L.s/x)),P=D*s+C;e[P]>=N||(t.values[P]=N)}}}static chains(t){const e=t.filter(s=>s.length>=2).map(s=>[...s]),i=[],n=(s,a)=>Math.hypot(s.x-a.x,s.y-a.y)<=1;for(;e.length>0;){let s=e.shift(),a=!0;for(;a;){a=!1;for(let r=0;r<e.length;r++){const c=e[r],h=s[0],l=s[s.length-1];if(n(l,c[0]))s=[...s,...c.slice(1)];else if(n(l,c[c.length-1]))s=[...s,...[...c].reverse().slice(1)];else if(n(h,c[c.length-1]))s=[...c.slice(0,-1),...s];else if(n(h,c[0]))s=[...[...c].reverse().slice(0,-1),...s];else continue;e.splice(r,1),a=!0;break}}i.push(s)}return i}static nearestAlong(t,e,i){let n={s:0,distance:1/0};for(let s=0;s<t.length-1;s++){const a=t[s],r=t[s+1],c=r.x-a.x,h=r.y-a.y,l=c*c+h*h;if(l<1e-9)continue;let u=((i.x-a.x)*c+(i.y-a.y)*h)/l;s>0&&(u=Math.max(0,u)),s<t.length-2&&(u=Math.min(1,u));const d=Math.hypot(i.x-(a.x+c*u),i.y-(a.y+h*u));d<n.distance&&(n={s:e[s]+u*Math.sqrt(l),distance:d})}return n}paint(t,e,i,n){const s=new Uint8Array(i*n),a=c=>(c-e.west)/(e.east-e.west)*i,r=c=>(e.north-c)/(e.north-e.south)*n;for(const c of t)for(let h=0;h<c.length-1;h++){const l=a(c[h].lng),u=r(c[h].lat),d=a(c[h+1].lng),f=r(c[h+1].lat),p=Math.max(1,Math.ceil(Math.hypot(d-l,f-u)*2));for(let g=0;g<=p;g++){const m=Math.floor(l+(d-l)*g/p),M=Math.floor(u+(f-u)*g/p);for(let y=-1;y<=1;y++)for(let x=-1;x<=1;x++){const v=m+x,w=M+y;v>=0&&w>=0&&v<i&&w<n&&(s[w*i+v]=1)}}}return s}touching(t,e,i,n){const s=new Uint8Array(t.length),a=new Uint8Array(t.length);for(let r=0;r<t.length;r++){if(t[r]===0||a[r]===1)continue;const c=[],h=[r];a[r]=1;let l=!1;for(;h.length>0;){const u=h.pop();c.push(u),e[u]===1&&(l=!0);const d=u%i,f=(u-d)/i;for(let p=-1;p<=1;p++)for(let g=-1;g<=1;g++){const m=d+g,M=f+p;if(m<0||M<0||m>=i||M>=n)continue;const y=M*i+m;t[y]===1&&a[y]===0&&(a[y]=1,h.push(y))}}if(l)for(const u of c)s[u]=1}return s}sample(t,e,i,n,s,a){const{width:r,height:c}=e,h=new Float32Array(r*c),l=new Uint8Array(r*c),u=Math.min(a.x,this.maxWindowM)/s.x,d=Math.min(a.y,this.maxWindowM)/s.y;let f=0;for(let p=0;p<c;p++){const g=i.north+(i.south-i.north)*(c===1?.5:p/(c-1)),m=(n.north-g)/(n.north-n.south)*t.height-.5;for(let M=0;M<r;M++){const x=(i.west+(i.east-i.west)*(r===1?.5:M/(r-1))-n.west)/(n.east-n.west)*t.width-.5,v=u>1||d>1?this.tent(t,x,m,Math.max(1,u),Math.max(1,d)):this.bilinear(t,x,m),w=p*r+M;v===void 0?f++:(h[w]=v,l[w]=1)}}if(!(f===r*c||f/(r*c)>Ae.MAX_HOLE_SHARE))return this.fill(h,l,r,c),h}tent(t,e,i,n,s){let a=0,r=0,c=0;const h=Math.max(0,Math.ceil(i-s)),l=Math.min(t.height-1,Math.floor(i+s)),u=Math.max(0,Math.ceil(e-n)),d=Math.min(t.width-1,Math.floor(e+n));for(let f=h;f<=l;f++){const p=1-Math.abs(f-i)/s;if(!(p<=0))for(let g=u;g<=d;g++){const m=p*(1-Math.abs(g-e)/n);if(m<=0)continue;c+=m;const M=t.at(g,f);!Number.isFinite(M)||M<Ae.NO_DATA_BELOW||(a+=m*M,r+=m)}}return c>0&&r>=c*.5?a/r:void 0}bilinear(t,e,i){const n=Math.max(0,Math.min(t.width-1,Math.floor(e))),s=Math.max(0,Math.min(t.height-1,Math.floor(i))),a=Math.min(t.width-1,n+1),r=Math.min(t.height-1,s+1),c=Math.max(0,Math.min(1,e-n)),h=Math.max(0,Math.min(1,i-s)),l=t.at(n,s),u=t.at(a,s),d=t.at(n,r),f=t.at(a,r);for(const m of[l,u,d,f])if(!Number.isFinite(m)||m<Ae.NO_DATA_BELOW)return;const p=l+(u-l)*c,g=d+(f-d)*c;return p+(g-p)*h}fill(t,e,i,n){let s=e.reduce((a,r)=>a+(r?0:1),0);for(;s>0;){const a=[];for(let r=0;r<n;r++)for(let c=0;c<i;c++){const h=r*i+c;if(e[h])continue;let l=0,u=0;for(let d=-1;d<=1;d++)for(let f=-1;f<=1;f++){const p=r+d,g=c+f;p<0||g<0||p>=n||g>=i||!e[p*i+g]||(l+=t[p*i+g],u++)}u>0&&a.push([h,l/u])}if(a.length===0)return;for(const[r,c]of a)t[r]=c,e[r]=1;s-=a.length}}}class Yx{providers;constructor(...t){this.providers=t}async getElevationGrid(t,e,i){let n=new Error("No source of relief to ask");for(const s of this.providers)try{return await s.getElevationGrid(t,e,i)}catch(a){n=a}throw n}}const du=256,Kx=5;async function Iv(o,t,e,i){const n=(o.south+o.north)/2,s=(o.west+o.east)/2,a=Math.abs(ae(n,o.east,n,o.west).x),r=Math.abs(ae(o.north,s,o.south,s).z),c=Math.max(a,r),{zoom:h,gridSize:l}=$x(n,c,Math.max(t.width,t.height)),{tiles:u,bounds:d}=Rv(s,n,h,l),f=l*du,p=document.createElement("canvas");p.width=f,p.height=f;const g=p.getContext("2d");if(!g)throw new Error("2D canvas context unavailable");const m=u[0];await Promise.all(u.map(async v=>{const w=e(v),b=await i(w);if(!b.ok)throw new Error(`Imagery tile fetch failed (${b.status}): ${w}`);const _=await createImageBitmap(await b.blob());g.drawImage(_,(v.x-m.x)*du,(v.y-m.y)*du)}));const M=Math.min(Math.max(t.width,t.height),f);if(M===f)return{source:p,width:f,height:f,bounds:d};const y=document.createElement("canvas");y.width=M,y.height=M;const x=y.getContext("2d");if(!x)throw new Error("2D canvas context unavailable");return x.drawImage(p,0,0,f,f,0,0,M,M),{source:y,width:M,height:M,bounds:d}}function $x(o,t,e){let i=zx(o,t/Math.max(1,e)),n=ug(o,i,t);for(;n>Kx&&i>0;)i--,n=ug(o,i,t);return{zoom:i,gridSize:n,mPerPixel:Av(o,i)/du}}function ug(o,t,e){const i=Math.ceil(e/2/Av(o,t));return Math.max(3,2*i+1)}class Dv{attribution="Imagery © Esri, Maxar, Earthstar Geographics, and the GIS User Community";fetchImpl;tileUrlTemplate;constructor(t={}){this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.tileUrlTemplate=t.tileUrlTemplate??"https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}"}async getImageryTexture(t,e){return Iv(t,e,i=>this.tileUrlTemplate.replace("{z}",String(i.z)).replace("{y}",String(i.y)).replace("{x}",String(i.x)),this.fetchImpl)}}class Wn{static ENDPOINTS=["https://overpass-api.de/api/interpreter","https://overpass.kumi.systems/api/interpreter","https://overpass.private.coffee/api/interpreter"];static FRANCE_ENDPOINT="https://overpass.openstreetmap.fr/api/interpreter";static FRANCE={south:41.3,west:-5.2,north:51.1,east:9.6};static endpointsFor(t,e=Wn.ENDPOINTS){const i=/\((-?\d+(?:\.\d+)?),(-?\d+(?:\.\d+)?),(-?\d+(?:\.\d+)?),(-?\d+(?:\.\d+)?)\)/.exec(t);if(!i)return[...e];const[n,s,a,r]=i.slice(1).map(Number),c=(n+a)/2,h=(s+r)/2,l=Wn.FRANCE;return c>=l.south&&c<=l.north&&h>=l.west&&h<=l.east?[Wn.FRANCE_ENDPOINT,...e.filter(d=>d!==Wn.FRANCE_ENDPOINT)]:[...e]}fetchImpl;endpoints;constructor(t={}){this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.endpoints=t.endpoints}static queue=Promise.resolve();static HANG_MS=4e4;static RETRY_MS=4e3;query(t){return this.queued(()=>this.ask(t))}queued(t){const e=Wn.queue.then(t,t);return Wn.queue=e.catch(()=>{}),e}async ask(t){let e;for(const i of this.endpoints??Wn.endpointsFor(t))for(let n=0;n<2;n++){try{const s=await this.fetchImpl(`${i}?data=${encodeURIComponent(t)}`,{signal:AbortSignal.timeout(Wn.HANG_MS)});if(s.ok)return await s.json();if(e=new Error(`${new URL(i).host} refused (${s.status})`),s.status!==429&&s.status!==504)break}catch(s){e=new Error(`${new URL(i).host} unreachable (${String(s)})`);break}await new Promise(s=>setTimeout(s,Wn.RETRY_MS))}throw e??new Error("No Overpass instance answered")}}class ar{attribution="Roads © OpenStreetMap contributors, as surveyed today";contemporary=!0;static DRIVABLE=["motorway","trunk","primary","secondary","tertiary","unclassified","residential","service","track","motorway_link","trunk_link","primary_link","secondary_link","tertiary_link"];static WIDTH_M={motorway:11,trunk:9,primary:8,secondary:7,tertiary:6.5,unclassified:5.5,residential:5.5,service:4,track:3.5};static DEFAULT_WIDTH_M=5;client;constructor(t={}){this.client=new Wn(t)}async getRoads(t){const e=`${t.south},${t.west},${t.north},${t.east}`,i=`[out:json][timeout:30];way["highway"~"^(${ar.DRIVABLE.join("|")})$"](${e});out geom;`;return this.waysFrom(await this.client.query(i))}waysFrom(t){const e=[];for(const i of t.elements??[]){const n=i.geometry,s=i.tags;!s||!n||n.length<2||e.push({id:`osm-${i.id??e.length}`,name:s.name,surface:ar.surfaceOf(s),widthM:ar.widthOf(s),...ar.paintOf(s),points:n.map(a=>({lat:a.lat,lng:a.lon}))})}return e}static paintOf(t){const e=t.highway??"",i=t.junction==="roundabout"||t.junction==="circular",n=t.oneway,s=n==="yes"||n==="1"||n==="true"||n===void 0&&(e==="motorway"||i),a=n==="-1"||n==="reverse",r=Number.parseInt(t.lanes??"",10),c=Number.parseInt(t.maxspeed??"",10),h=i?"roundabout":e==="motorway"?"motorway":e.endsWith("_link")?"slip":(e==="trunk"||e==="primary")&&(s||a)?"dual":e?"road":void 0;return{...h?{kind:h}:{},...Number.isFinite(r)&&r>0?{lanes:r}:{},...n!==void 0||e==="motorway"||i?{direction:a?"backward":s?"forward":"both"}:{},...Number.isFinite(c)&&c>0?{speedKmh:c}:{}}}static widthOf(t){const e=Number.parseFloat(t.width??t.est_width??"");if(Number.isFinite(e)&&e>0)return e;const i=Number.parseInt(t.lanes??"",10);return Number.isFinite(i)&&i>0?i*3.5:ar.WIDTH_M[t.highway]??ar.DEFAULT_WIDTH_M}static surfaceOf(t){const e=t.surface;return e==="dirt"||e==="earth"||e==="mud"?"dirt":e==="gravel"||e==="fine_gravel"||e==="compacted"||e==="ground"||e==="sand"||e==="unpaved"?"gravel":e?"paved":t.highway==="track"?"gravel":"paved"}}const Dd="https://ufoathome.org/roads/index.json";class $o{attributionRead;contemporaryRead;fetchImpl;indexUrls;fallback;index;static shared=new Map;sharing;constructor(t={}){this.sharing=!t.fetchImpl,this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.indexUrls=t.indexUrls??$o.defaultIndexUrls(),this.fallback=t.fallback}get attribution(){return this.attributionRead??this.fallback?.attribution??"Roads © OpenStreetMap contributors"}get contemporary(){return this.contemporaryRead??this.fallback?.contemporary??!0}async getRoads(t){const e=await this.held(t);if(e)return e;if(!this.fallback)return[];const i=await this.fallback.getRoads(t);return this.attributionRead=this.fallback.attribution,this.contemporaryRead=this.fallback.contemporary,i}async held(t){let e;try{e=await this.load()}catch{return}const i=e.find(({entry:n})=>n.north>=t.north&&n.south<=t.south&&n.east>=t.east&&n.west<=t.west);if(i)try{const n=await this.fetchImpl(new URL(i.entry.file,i.indexUrl).href);if(!n.ok)return;const s=await n.json();return Array.isArray(s?.ways)?(this.attributionRead=s.attribution,this.contemporaryRead=s.contemporary,s.ways):void 0}catch{return}}load(){if(this.index)return this.index;if(!this.sharing)return this.index=this.fetchFirstAvailable();const t=this.indexUrls.join(`
1739
- `);let e=$o.shared.get(t);return e||(e=this.fetchFirstAvailable(),$o.shared.set(t,e),e.then(i=>{i.length===0&&$o.shared.delete(t)})),this.index=e}async fetchFirstAvailable(){for(const t of this.indexUrls)try{const e=await this.fetchImpl(t);if(!e.ok)continue;const i=await e.json();if(Array.isArray(i?.entries))return i.entries.map(n=>({entry:n,indexUrl:t}))}catch{}return[]}static defaultIndexUrls(){const t=`?v=${encodeURIComponent("0.152.0")}`,e=typeof location>"u"?void 0:new URL("/roads/index.json",location.href).href;return(e&&e!==Dd?[e,Dd]:[Dd]).map(i=>i+t)}}class hr{attribution="Roads © IGN, BD TOPO (Licence Ouverte 2.0), as drawn today";contemporary=!0;static BY_NATURE={"Type autoroutier":{surface:"paved",widthM:11},"Route à 2 chaussées":{surface:"paved",widthM:7},"Route à 1 chaussée":{surface:"paved",widthM:5.5},"Rond-point":{surface:"paved",widthM:6},Bretelle:{surface:"paved",widthM:5},"Route empierrée":{surface:"gravel",widthM:3.5},Chemin:{surface:"dirt",widthM:3},"Piste cyclable":{surface:"paved",widthM:2.5}};static DEFAULT={surface:"paved",widthM:5};static KINDS={"Type autoroutier":"motorway","Route à 2 chaussées":"dual","Route à 1 chaussée":"road","Rond-point":"roundabout",Bretelle:"slip"};static DIRECTIONS={"Double sens":"both","Sens direct":"forward","Sens inverse":"backward"};platform;constructor(t={}){this.platform=new Re(t)}static covers(t){return Re.covers((t.south+t.north)/2,(t.west+t.east)/2)}async getRoads(t){return(await this.platform.roads(t)).flatMap((i,n)=>hr.wayOf(i,n))}static wayOf(t,e){if(t.geometry.type!=="LineString")return[];const i=t.geometry.coordinates.map(([d,f])=>({lat:f,lng:d}));if(i.length<2)return[];const n=String(t.properties.nature??""),s=hr.BY_NATURE[n]??hr.DEFAULT,a=Number(t.properties.largeur_de_chaussee),r=Number(t.properties.nombre_de_voies),c=Number(t.properties.vitesse_moyenne_vl),h=hr.DIRECTIONS[String(t.properties.sens_de_circulation??"")],l=hr.KINDS[n],u=[t.properties.cpx_toponyme_route_nommee,t.properties.nom_voie_ban_gauche,t.properties.nom_voie_ban_droite].find(d=>typeof d=="string"&&d.length>0);return[{id:String(t.properties.cleabs??`ign-${e}`),...u?{name:u}:{},surface:s.surface,widthM:Number.isFinite(a)&&a>0?a:s.widthM,...t.properties.urbain===!0?{urban:!0}:{},...l?{kind:l}:{},...Number.isInteger(r)&&r>0?{lanes:r}:{},...h?{direction:h}:{},...Number.isFinite(c)&&c>0?{speedKmh:c}:{},points:i}]}}class qx{constructor(t,e){this.regional=t,this.worldwide=e}attribution="Roads © IGN, BD TOPO, in France; © OpenStreetMap contributors elsewhere, as drawn today";contemporary=!0;async getRoads(t){if(hr.covers(t))try{const e=await this.regional.getRoads(t);if(e.length>0)return e}catch{}return this.worldwide.getRoads(t)}}class Fh{attribution="Water © IGN, BD TOPO (Licence Ouverte 2.0)";platform;constructor(t={}){this.platform=new Re(t)}static covers(t){return Re.covers((t.south+t.north)/2,(t.west+t.east)/2)}async getWater(t){return(await this.platform.waterSurfaces(t)).flatMap((i,n)=>Fh.surfacesOf(i,n))}static surfacesOf(t,e){const{type:i,coordinates:n}=t.geometry,s=i==="Polygon"?[n]:i==="MultiPolygon"?n:[],a=String(t.properties.cleabs??`ign-water-${e}`);return s.flatMap((r,c)=>{const h=r.map(l=>Fh.open(l.map(u=>({lat:u[1],lng:u[0]})))).filter(l=>l.length>=3);return h.length>0?[{id:s.length>1?`${a}-${c}`:a,rings:h}]:[]})}static open(t){const e=t[0],i=t[t.length-1];return t.length>1&&e.lat===i.lat&&e.lng===i.lng?t.slice(0,-1):t}}class Nr{attribution="Water © OpenStreetMap contributors";client;constructor(t={}){this.client=new Wn(t)}async getWater(t){const e=`${t.south},${t.west},${t.north},${t.east}`,i=`[out:json][timeout:30];(way["natural"="water"](${e});way["waterway"="riverbank"](${e});)->.w;(relation["natural"="water"](${e});relation["waterway"="riverbank"](${e});)->.r;.w out geom;.r out body;way(r.r)(${e});out geom;`;return Nr.surfacesFrom(await this.client.query(i))}static surfacesFrom(t){const e=t.elements??[],i=new Map;for(const a of e)a.type==="way"&&a.id!==void 0&&a.geometry&&i.set(a.id,a.geometry.map(r=>({lat:r.lat,lng:r.lon})));const n=[],s=new Set;for(const a of e){if(a.type!=="relation")continue;const r=h=>(a.members??[]).filter(l=>l.type==="way"&&l.role===h&&l.ref!==void 0&&i.has(l.ref)).map(l=>(s.add(l.ref),i.get(l.ref))),c=Nr.rings(r("inner"));for(const[h,l]of Nr.rings(r("outer")).entries()){const u=c.filter(d=>Nr.contains(l,d[0]));n.push({id:`osm-r${a.id}-${h}`,rings:[l,...u]})}}for(const a of e)if(!(a.type!=="way"||!a.tags||a.id===void 0||s.has(a.id))&&!(a.tags.natural!=="water"&&a.tags.waterway!=="riverbank"))for(const r of Nr.rings([i.get(a.id)??[]]))n.push({id:`osm-w${a.id}`,rings:[r]});return n}static rings(t){const e=(s,a)=>s.lat===a.lat&&s.lng===a.lng,i=t.filter(s=>s.length>=2).map(s=>[...s]),n=[];for(;i.length>0;){let s=i.pop(),a=!0;for(;!e(s[0],s[s.length-1])&&a;){a=!1;for(let r=0;r<i.length;r++){const c=i[r],h=s[s.length-1];if(e(h,c[0]))s=[...s,...c.slice(1)];else if(e(h,c[c.length-1]))s=[...s,...[...c].reverse().slice(1)];else continue;i.splice(r,1),a=!0;break}}s.length>=4&&e(s[0],s[s.length-1])&&n.push(s.slice(0,-1))}return n}static contains(t,e){let i=!1;for(let n=0,s=t.length-1;n<t.length;s=n++){const a=t[n],r=t[s];a.lat>e.lat!=r.lat>e.lat&&e.lng<(r.lng-a.lng)*(e.lat-a.lat)/(r.lat-a.lat)+a.lng&&(i=!i)}return i}}class Zx{constructor(t,e){this.regional=t,this.worldwide=e}attribution="Water © IGN, BD TOPO, in France; © OpenStreetMap contributors elsewhere";async getWater(t){if(Fh.covers(t))try{const e=await this.regional.getWater(t);if(e.length>0)return e}catch{}return this.worldwide.getWater(t)}}const Cd="https://ufoathome.org/water/index.json";class qo{attributionRead;fetchImpl;indexUrls;fallback;index;static shared=new Map;sharing;constructor(t={}){this.sharing=!t.fetchImpl,this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.indexUrls=t.indexUrls??qo.defaultIndexUrls(),this.fallback=t.fallback}get attribution(){return this.attributionRead??this.fallback?.attribution??"Water © OpenStreetMap contributors"}async getWater(t){const e=await this.held(t);if(e)return e;if(!this.fallback)return[];const i=await this.fallback.getWater(t);return this.attributionRead=this.fallback.attribution,i}async held(t){const i=(await this.load().catch(()=>[])).find(({entry:n})=>n.north>=t.north&&n.south<=t.south&&n.east>=t.east&&n.west<=t.west);if(i)try{const n=await this.fetchImpl(new URL(i.entry.file,i.indexUrl).href);if(!n.ok)return;const s=await n.json();return Array.isArray(s?.surfaces)?(this.attributionRead=s.attribution,s.surfaces):void 0}catch{return}}load(){if(this.index)return this.index;if(!this.sharing)return this.index=this.fetchFirstAvailable();const t=this.indexUrls.join(`
1740
- `);let e=qo.shared.get(t);return e||(e=this.fetchFirstAvailable(),qo.shared.set(t,e),e.then(i=>{i.length===0&&qo.shared.delete(t)})),this.index=e}async fetchFirstAvailable(){for(const t of this.indexUrls)try{const e=await this.fetchImpl(t);if(!e.ok)continue;const i=await e.json();if(Array.isArray(i?.entries))return i.entries.map(n=>({entry:n,indexUrl:t}))}catch{}return[]}static defaultIndexUrls(){const t=`?v=${encodeURIComponent("0.152.0")}`,e=typeof location>"u"?void 0:new URL("/water/index.json",location.href).href;return(e&&e!==Cd?[e,Cd]:[Cd]).map(i=>i+t)}}class Bn{constructor(t){this.water=t}static CACHE_NAME="rr0-water";static MAX_AGE_MS=720*3600*1e3;static FORMAT=1;static MAX_STORED=400;static asked=new Map;get attribution(){return this.water.attribution}async getWater(t){const e=Bn.key(t);let i=Bn.asked.get(e);return i===void 0&&(i=this.recalled(e,t),Bn.asked.set(e,i),i.catch(()=>Bn.asked.delete(e))),structuredClone(await i)}static forget(){Bn.asked.clear()}static key(t){return`v${Bn.FORMAT}/${[t.north,t.south,t.east,t.west].map(e=>e.toFixed(5)).join("/")}`}async recalled(t,e){const i=await Bn.openCache(),n=Bn.request(t);if(i)try{const a=await i.match(n);if(a){const{savedAt:r,surfaces:c}=await a.json();if(Date.now()-r<Bn.MAX_AGE_MS&&Array.isArray(c))return c;await i.delete(n)}}catch{}const s=await this.water.getWater(e);return i&&Bn.store(i,n,s),s}static async store(t,e,i){try{const n={savedAt:Date.now(),surfaces:i};await t.put(e,new Response(JSON.stringify(n),{headers:{"Content-Type":"application/json"}}));const s=await t.keys();for(const a of s.slice(0,Math.max(0,s.length-Bn.MAX_STORED)))await t.delete(a)}catch{}}static async openCache(){try{return typeof caches>"u"?void 0:await caches.open(Bn.CACHE_NAME)}catch{return}}static request(t){const e=typeof location>"u"?"http://localhost":location.origin;return new Request(`${e}/__water__/${encodeURIComponent(t)}`)}}class lr{attribution="Railways © IGN, BD TOPO (Licence Ouverte 2.0), as drawn today";contemporary=!0;static BY_NATURE={"Voie ferrée principale":{kind:"rail"},LGV:{kind:"rail",highSpeed:!0},"Voie de service":{kind:"rail",service:!0},Métro:{kind:"subway"},Tramway:{kind:"tram"},"Transport urbain":{kind:"light_rail"},"Funiculaire ou crémaillère":{kind:"funicular"}};static GAUGE_MM={Normale:1435,Etroite:1e3,Étroite:1e3,Large:1668};static NO_ALTITUDE=-1e3;platform;constructor(t={}){this.platform=new Re(t)}static covers(t){return Re.covers((t.south+t.north)/2,(t.west+t.east)/2)}async getRailways(t){return(await this.platform.railways(t)).flatMap((i,n)=>lr.linesOf(i,n))}static linesOf(t,e){const{type:i,coordinates:n}=t.geometry,s=i==="LineString"?[n]:i==="MultiLineString"?n:[],a=lr.BY_NATURE[String(t.properties.nature??"")];if(!a)return[];const r=String(t.properties.cleabs??`ign-rail-${e}`),c=Number(t.properties.nombre_de_voies),h=Number(t.properties.position_par_rapport_au_sol),l=t.properties.cpx_toponyme,u=lr.GAUGE_MM[String(t.properties.largeur??"")]??1435,d=lr.electrificationOf(a.kind,u,t.properties.electrifie);return s.flatMap((f,p)=>{const g=f.map(m=>({lat:m[1],lng:m[0],...m.length>2&&Number.isFinite(m[2])&&m[2]>lr.NO_ALTITUDE?{altitudeM:m[2]}:{}}));return g.length<2?[]:[{id:s.length>1?`${r}-${p}`:r,...typeof l=="string"&&l.length>0?{name:l}:{},kind:a.kind,...a.service?{service:!0}:{},...a.highSpeed?{highSpeed:!0}:{},gaugeMm:u,tracks:Number.isInteger(c)&&c>0?c:1,...d?{electrification:d}:{},level:Number.isFinite(h)?h:0,points:g}]})}static electrificationOf(t,e,i){if(i===!1)return"none";if(i===!0){if(t==="subway")return"third_rail";if(!(t==="funicular"||e<1435))return"overhead"}}}class on{static NEAR_M=15;static ALIGNED_DEG=30;static SAMPLE_M=10;static ROUTES="train|subway|light_rail|tram|monorail";static KINDS="rail|light_rail|subway|tram|narrow_gauge|funicular|preserved";client;constructor(t={}){this.client=new Wn(t)}async named(t,e){if(t.length===0)return[...t];const i=`${e.south},${e.west},${e.north},${e.east}`,n=`[out:json][timeout:120];way["railway"~"^(${on.KINDS})$"](${i})->.w;.w out tags geom;rel(bw.w)["route"~"^(${on.ROUTES})$"];out body;`;return on.apply(t,await this.client.query(n),e)}static apply(t,e,i){const n={lat:(i.north+i.south)/2,lng:(i.east+i.west)/2},s=on.ways(e,n);return s.length===0?[...t]:t.map(a=>{const r=a.points.map(M=>ae(M.lat,M.lng,n.lat,n.lng)),c=new Map,h=new Map,l=new Map;let u=0;const d=s.filter(M=>M.service===!!a.service);for(const M of on.samples(r)){u++;const y=on.waysAt(d,M);if(y.length===0)continue;const[x]=y;x.name&&c.set(x.name,(c.get(x.name)??0)+1),x.voltageV&&h.set(x.voltageV,(h.get(x.voltageV)??0)+1);for(const v of new Set(y.flatMap(w=>w.services)))l.set(v,(l.get(v)??0)+1)}const f=M=>[...M.entries()].sort((y,x)=>x[1]-y[1])[0]?.[0],p=a.name??f(c),g=a.voltageV??(a.electrification==="none"?void 0:f(h)),m=[...l.entries()].filter(([,M])=>M*4>=u).sort((M,y)=>y[1]-M[1]||M[0].localeCompare(y[0])).map(([M])=>M);return{...a,...p?{name:p}:{},...g?{voltageV:g}:{},...m.length>0?{services:m}:{}}})}static serviceOf(t){const e=t.name?.split(" : ")[0].replace(/\s*\([^)]*\)\s*$/,"").trim();return e||[t.network,t.ref].filter(Boolean).join(" ")||void 0}static servicesByWay(t){const e=new Map;for(const i of t.elements??[]){if(i.type!=="relation"||!i.tags)continue;const n=on.serviceOf(i.tags);if(n)for(const s of i.members??[]){if(s.type!=="way"||s.ref===void 0)continue;const a=e.get(s.ref)??new Set;a.add(n),e.set(s.ref,a)}}return e}static voltageOf(t){const e=Number.parseInt((t.voltage??"").split(";")[0],10);return Number.isFinite(e)&&e>0?e:void 0}static ways(t,e){const i=on.servicesByWay(t),n=[];for(const s of t.elements??[]){if(s.type!=="way"||!s.geometry||s.geometry.length<2)continue;const a=s.tags??{},r=on.voltageOf(a);n.push({service:!!a.service||a.usage==="industrial",...a.name?{name:a.name}:{},...r?{voltageV:r}:{},services:[...i.get(s.id??-1)??[]],path:s.geometry.map(c=>ae(c.lat,c.lon,e.lat,e.lng))})}return n}static samples(t){const e=[];for(let i=0;i<t.length-1;i++){const n=Math.hypot(t[i+1].x-t[i].x,t[i+1].z-t[i].z);if(n<1e-6)continue;const s=(t[i+1].x-t[i].x)/n,a=(t[i+1].z-t[i].z)/n;for(let r=on.SAMPLE_M/2;r<n;r+=on.SAMPLE_M)e.push({x:t[i].x+s*r,z:t[i].z+a*r,dx:s,dz:a})}return e}static waysAt(t,e){const i=Math.cos(on.ALIGNED_DEG*Math.PI/180),n=[];for(const s of t){let a;for(let r=0;r<s.path.length-1;r++){const c=s.path[r],h=s.path[r+1],l=h.x-c.x,u=h.z-c.z,d=Math.hypot(l,u);if(d<1e-6||Math.abs((l*e.dx+u*e.dz)/d)<i)continue;const f=Math.max(0,Math.min(1,((e.x-c.x)*l+(e.z-c.z)*u)/(d*d))),p=Math.hypot(e.x-(c.x+l*f),e.z-(c.z+u*f));p<=on.NEAR_M&&(a===void 0||p<a)&&(a=p)}a!==void 0&&n.push({way:s,distance:a})}return n.sort((s,a)=>s.distance-a.distance).map(({way:s})=>s)}}class Zo{attribution="Railways © OpenStreetMap contributors, as surveyed today";contemporary=!0;static KINDS=["rail","light_rail","tram","subway","narrow_gauge","funicular","preserved"];client;constructor(t={}){this.client=new Wn(t)}async getRailways(t){const e=`${t.south},${t.west},${t.north},${t.east}`,i=`[out:json][timeout:25];way["railway"~"^(${Zo.KINDS.join("|")})$"](${e})->.w;.w out tags geom;rel(bw.w)["route"~"^(${on.ROUTES})$"];out body;`;return this.linesFrom(await this.client.query(i))}linesFrom(t){const e=[],i=on.servicesByWay(t);for(const n of t.elements??[]){const s=n.geometry,a=n.tags;if(n.type==="relation"||!a||!s||s.length<2)continue;const r=[...i.get(n.id??-1)??[]].sort(),c=on.voltageOf(a),h=Zo.kindOf(a),l=Number.parseInt((a.gauge??"").split(";")[0],10),u=Number.parseInt(a.tracks??"",10),d=Zo.electrificationOf(a.electrified),f=a.highspeed==="yes"||Number.parseInt(a.maxspeed??"",10)>=250;e.push({id:`osm-rail-${n.id??e.length}`,...a.name?{name:a.name}:{},...r.length>0?{services:r}:{},...c?{voltageV:c}:{},kind:h,...a.service||a.usage==="industrial"?{service:!0}:{},...f?{highSpeed:!0}:{},gaugeMm:Number.isFinite(l)&&l>300?l:a.railway==="narrow_gauge"?1e3:1435,tracks:Number.isFinite(u)&&u>0?u:1,...d?{electrification:d}:{},level:Zo.levelOf(a),points:s.map(p=>({lat:p.lat,lng:p.lon}))})}return e}static kindOf(t){switch(t.railway){case"tram":return"tram";case"subway":return"subway";case"light_rail":return"light_rail";case"funicular":return"funicular";default:return"rail"}}static electrificationOf(t){if(t!==void 0){if(t==="no")return"none";if(t==="contact_line"||t==="yes")return"overhead";if(t==="rail"||t==="4th_rail"||t==="ground-level_power_supply")return"third_rail"}}static levelOf(t){const e=Number.parseInt(t.layer??"",10);return t.tunnel&&t.tunnel!=="no"?Number.isFinite(e)&&e<0?e:-1:t.covered==="yes"&&t.location==="underground"?-1:t.bridge&&t.bridge!=="no"?Number.isFinite(e)&&e>0?e:1:0}}class Jx{constructor(t,e){this.regional=t,this.worldwide=e}attribution="Railways © IGN, BD TOPO, in France; © OpenStreetMap contributors elsewhere, as drawn today";contemporary=!0;async getRailways(t){if(!lr.covers(t))return this.worldwide.getRailways(t);let e;try{if(e=await this.regional.getRailways(t),e.length>0)return e}catch{}try{return await this.worldwide.getRailways(t)}catch(i){if(e)return e;throw i}}}class Wi{constructor(t,e=Date.now){this.railways=t,this.now=e}static CACHE_NAME="rr0-railways";static MAX_AGE_MS=720*3600*1e3;static FORMAT=1;static MAX_STORED=400;static RETRY_AFTER_MS=300*1e3;static asked=new Map;static failedAt=-1/0;get attribution(){return this.railways.attribution}get contemporary(){return this.railways.contemporary}async getRailways(t){const e=Wi.key(t);let i=Wi.asked.get(e)??Wi.containing(t);if(i===void 0){const n=this.recalled(e,t);i={bounds:t,answer:n},Wi.asked.set(e,i),n.catch(()=>Wi.asked.delete(e))}return structuredClone(await i.answer)}static forget(){Wi.asked.clear(),Wi.failedAt=-1/0}static key(t){return`v${Wi.FORMAT}/${[t.north,t.south,t.east,t.west].map(e=>e.toFixed(5)).join("/")}`}static containing(t){for(const e of Wi.asked.values()){const i=e.bounds;if(i.north>=t.north&&i.south<=t.south&&i.east>=t.east&&i.west<=t.west)return e}}async recalled(t,e){const i=await Wi.openCache(),n=Wi.request(t);let s;if(i)try{const r=await i.match(n);if(r){const{savedAt:c,lines:h}=await r.json();if(Array.isArray(h)){if(this.now()-c<Wi.MAX_AGE_MS)return h;s=h}}}catch{}if(this.now()-Wi.failedAt<Wi.RETRY_AFTER_MS){if(s)return s;throw new Error("The railway survey failed a moment ago: not asked again yet")}let a;try{a=await this.railways.getRailways(e)}catch(r){if(Wi.failedAt=this.now(),s)return s;throw r}return i&&Wi.store(i,n,{savedAt:this.now(),lines:a}),a}static async store(t,e,i){try{await t.delete(e),await t.put(e,new Response(JSON.stringify(i),{headers:{"Content-Type":"application/json"}}));const n=await t.keys();for(const s of n.slice(0,Math.max(0,n.length-Wi.MAX_STORED)))await t.delete(s)}catch{}}static async openCache(){try{return typeof caches>"u"?void 0:await caches.open(Wi.CACHE_NAME)}catch{return}}static request(t){const e=typeof location>"u"?"http://localhost":location.origin;return new Request(`${e}/__railways__/${encodeURIComponent(t)}`)}}const Od="https://ufoathome.org/railways/index.json";class Jo{contemporary=!0;attributionRead;fetchImpl;indexUrls;fallback;index;static shared=new Map;sharing;constructor(t={}){this.sharing=!t.fetchImpl,this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.indexUrls=t.indexUrls??Jo.defaultIndexUrls(),this.fallback=t.fallback}get attribution(){return this.attributionRead??this.fallback?.attribution??"Railways © OpenStreetMap contributors"}async getRailways(t){const e=await this.held(t);if(e)return e;if(!this.fallback)return[];const i=await this.fallback.getRailways(t);return this.attributionRead=this.fallback.attribution,i}async held(t){const i=(await this.load().catch(()=>[])).find(({entry:n})=>n.north>=t.north&&n.south<=t.south&&n.east>=t.east&&n.west<=t.west);if(i)try{const n=await this.fetchImpl(new URL(i.entry.file,i.indexUrl).href);if(!n.ok)return;const s=await n.json();return Array.isArray(s?.lines)?(this.attributionRead=s.attribution,s.lines):void 0}catch{return}}load(){if(this.index)return this.index;if(!this.sharing)return this.index=this.fetchFirstAvailable();const t=this.indexUrls.join(`
1741
- `);let e=Jo.shared.get(t);return e||(e=this.fetchFirstAvailable(),Jo.shared.set(t,e),e.then(i=>{i.length===0&&Jo.shared.delete(t)})),this.index=e}async fetchFirstAvailable(){for(const t of this.indexUrls)try{const e=await this.fetchImpl(t);if(!e.ok)continue;const i=await e.json();if(Array.isArray(i?.entries))return i.entries.map(n=>({entry:n,indexUrl:t}))}catch{}return[]}static defaultIndexUrls(){const t=`?v=${encodeURIComponent("0.152.0")}`,e=typeof location>"u"?void 0:new URL("/railways/index.json",location.href).href;return(e&&e!==Od?[e,Od]:[Od]).map(i=>i+t)}}function Cv(){return{elevation:jx(),imagery:Ov(),roads:Qx(),water:tw(),railways:ew()}}function jx(){return new Yx(new Ae,new Wx)}function Ov(){return new Dv}function Qx(){return new $o({fallback:new qx(new hr,new ar)})}function tw(){return new qo({fallback:new Bn(new Zx(new Fh,new Nr))})}function ew(){return new Jo({fallback:new Wi(new Jx(new lr,new Zo))})}const iw=new Set,uc="show-observer-map",dc="hide-milestones",Hr="minified";class Le extends HTMLElement{static get observedAttributes(){return["src",uc,dc,Hr]}shadow;stageElement;canvas;canvasRenderer;chromeCanvas;chromeRenderer;chromeResizeObserver=typeof ResizeObserver>"u"?void 0:new ResizeObserver(()=>{this.chromeDirty&&this.refresh()});chromeDirty=!1;tooltip;toolbar;issuesBox;issuesButton;issuesPanel;playPauseButton;fullscreenButton;cornerButtons;observerMapButton;referencesButton;tracesButton;tracesShownState=!0;referenceOpacityInput;referencesShownState=!0;accountHidden=!1;referenceViews=new Map;referencesMenu;referenceOpacityTouched=!1;milestonesButton;observerMapPanel;observerMapCanvas;observerMapRenderer;mapZoomInButton;mapZoomOutButton;mapFitButton;observerMapView=new ei;observerMapDrag;suppressObserverMapClick=!1;observerMapImageryTimer;observerPlacing=!1;seekInput;playbackFlash;milestoneMarks;milestoneCaption;timeStartLabel;timeEndLabel;timePill;muteButton;volumeInput;controlsRow;momentsBox;momentsButton;momentsCurrent;momentsMenu;moreButton;controlsRight;seekSegments;seekDot;playerTitleBox;seekPreview;seekPreviewCanvas;seekPreviewTitle;seekPreviewTime;observerPath;observerMapBounds;observerMapImagery;observerMapImageryBounds;observerMapImageryViewWidth=0;observerMapImageryLoading=!1;observerMapImageryCredit;observerMapImageryFailed=!1;creditShownExternally=!1;lookYawDeg=0;lookPitchDeg=0;milestonesShown=!0;currentSighting=cd.create();issues=[];issueCheck=0;sightingAudio=new Ax;soundPreview;player;loopEnabled=!1;playbackBeforeClick;highlightedSourceIds=new Set;paintsShapes=!0;steadyObserver=!1;static LIVE_BODY_MAX_RATE=2;get steadyBody(){return this.steadyObserver||this.player.playbackState!=="playing"||this.player.playbackRate>Le.LIVE_BODY_MAX_RATE}selectionShown=!0;overlayPainter;enableClickToPlay=!0;fullscreenTarget;messages=xv;realDurationMs;realStartMs;showClockTime=!0;handleFullscreenChange=()=>{this.updateFullscreenButton(),this.updateMuteButton(),this.resizeObserverMap()};controlsFitObserver=typeof ResizeObserver>"u"?void 0:new ResizeObserver(()=>this.fitControls());controlsMutations;fitControls(){const t=this.controlsRow,e=t.classList.contains("more-open"),i=()=>t.scrollWidth>t.clientWidth+1,n=!this.momentsMenu.hidden;if(this.momentsMenu.hidden=!0,t.classList.remove("narrow","more-open","nomoments","compact","tiny"),t.clientWidth>0&&i()){t.classList.add("narrow");for(const s of["nomoments","compact","tiny"]){if(!i())break;t.classList.add(s)}e&&t.classList.add("more-open")}this.momentsMenu.hidden=!n,this.updateMoreButton()}setControlsFolded(t){this.controlsRow.classList.toggle("more-open",!t),this.updateMoreButton()}updateMoreButton(){const t=this.controlsRow.classList.contains("more-open");Le.setIcon(this.moreButton,t?Zt.UNFOLDED:Zt.FOLDED);const e=t?this.messages.fewerControls:this.messages.moreControls;this.moreButton.title=e,this.moreButton.setAttribute("aria-label",e),this.moreButton.setAttribute("aria-expanded",String(t))}addControl(t){this.controlsRight.insertBefore(t,this.fullscreenButton.parentElement===this.controlsRight?this.fullscreenButton:null),this.fitControls()}observerMapResizeObserver=typeof ResizeObserver>"u"?void 0:new ResizeObserver(()=>this.resizeObserverMap());resizeObserverMap(){this.observerMapPanel.hidden||(this.sizeObserverMapCanvas(),this.paintObserverMap(this.currentTime))}simulatedFullscreen=!1;styleBeforeSimulatedFullscreen;bodyOverflowBeforeSimulatedFullscreen;handleSimulatedFullscreenKey=t=>{t.key==="Escape"&&this.exitSimulatedFullscreen()};handlePointerMove=t=>{const e=this.canvasPointFromEvent(t),i=e&&this.shapeAt(e.x,e.y),n=this.said.read(i?.shape.title);if(!n){this.tooltip.hidden=!0;return}this.tooltip.textContent=n,this.tooltip.hidden=!1;const s=this.stageElement.getBoundingClientRect();this.tooltip.style.left=`${t.clientX-s.left+12}px`,this.tooltip.style.top=`${t.clientY-s.top+12}px`};handleObserverMapPointerMove=t=>{if(this.dragObserverMap(t))return;const e=this.observerMapTargetFrom(t);if(!e){if(!this.observerPlacing){this.tooltip.hidden=!0,this.observerMapCanvas.style.cursor="grab";return}this.observerMapCanvas.style.cursor="crosshair",this.showObserverMapTooltip(t,this.messages.placeObserverHere);return}this.observerMapCanvas.style.cursor="pointer",this.showObserverMapTooltip(t,e.label)};showObserverMapTooltip(t,e){this.tooltip.textContent=e,this.tooltip.hidden=!1;const i=this.stageElement.getBoundingClientRect();this.tooltip.style.left=`${t.clientX-i.left+12}px`,this.tooltip.style.top=`${t.clientY-i.top+12}px`}handleObserverMapClick=t=>{if(this.suppressObserverMapClick){this.suppressObserverMapClick=!1;return}const e=this.observerMapTargetFrom(t);if(!e){this.observerPlacing&&this.placeObserverFrom(t);return}if(e.kind==="milestone"&&e.t!==void 0){this.player.seek(e.t);return}this.dispatchEvent(new CustomEvent("lookat",{detail:{lat:e.lat,lng:e.lng,kind:e.kind},bubbles:!0,composed:!0}))};observerMapTargetFrom(t){const e=this.observerMapCanvas.getBoundingClientRect();if(!(e.width===0||e.height===0))return this.observerMapRenderer.hitTest((t.clientX-e.left)/e.width*this.observerMapCanvas.width,(t.clientY-e.top)/e.height*this.observerMapCanvas.height)}handlePointerLeave=()=>{this.tooltip.hidden=!0};handleObserverMapPointerDown=t=>{t.button===0&&(this.suppressObserverMapClick=!1,this.observerMapDrag={pointerId:t.pointerId,startX:t.clientX,startY:t.clientY,lastX:t.clientX,lastY:t.clientY,moved:!1})};handleObserverMapPointerUp=t=>{const e=this.observerMapDrag;!e||e.pointerId!==t.pointerId||(this.observerMapDrag=void 0,this.observerMapCanvas.classList.remove("dragging"),e.moved&&(this.suppressObserverMapClick=!0,this.paintObserverMap(this.currentTime),this.observerMapCanvas.hasPointerCapture?.(t.pointerId)&&this.observerMapCanvas.releasePointerCapture(t.pointerId)))};dragObserverMap(t){const e=this.observerMapDrag;if(!e||e.pointerId!==t.pointerId)return!1;if(!e.moved){if(Math.hypot(t.clientX-e.startX,t.clientY-e.startY)<Le.OBSERVER_MAP_DRAG_PX)return!1;e.moved=!0,this.tooltip.hidden=!0,this.observerMapCanvas.classList.add("dragging"),this.observerMapCanvas.setPointerCapture?.(t.pointerId)}const i=this.observerMapCanvas.getBoundingClientRect();return i.width>0&&i.height>0&&(this.observerMapView.panBy((t.clientX-e.lastX)/i.width,(t.clientY-e.lastY)/i.height),this.observerMapViewChanged()),e.lastX=t.clientX,e.lastY=t.clientY,!0}static OBSERVER_MAP_DRAG_PX=4;handleObserverMapWheel=t=>{t.preventDefault();const e=this.observerMapCanvas.getBoundingClientRect();if(e.width===0||e.height===0)return;const i=t.deltaMode===0?t.deltaY:t.deltaY*40;this.zoomObserverMap((t.clientX-e.left)/e.width,(t.clientY-e.top)/e.height,Math.exp(-i*.002))};zoomObserverMap(t,e,i){this.observerMapView.zoomAt(t,e,i),this.observerMapViewChanged()}observerMapViewChanged(){this.mapFitButton.hidden=!this.observerMapView.changed,this.mapZoomInButton.disabled=this.observerMapView.zoomFactor>=ei.MAX_ZOOM,this.mapZoomOutButton.disabled=this.observerMapView.zoomFactor<=ei.MIN_ZOOM,this.paintObserverMap(this.currentTime),this.scheduleObserverMapImagery()}scheduleObserverMapImagery(){this.observerMapImageryTimer===void 0&&(this.observerMapImageryTimer=setTimeout(()=>{this.observerMapImageryTimer=void 0,this.loadObserverMapImagery()},Le.OBSERVER_MAP_IMAGERY_DELAY_MS))}static OBSERVER_MAP_FOLLOW_MARGIN=.1;static OBSERVER_MAP_IMAGERY_DELAY_MS=300;get observerMapViewBounds(){return this.observerMapBounds&&this.observerMapView.boundsWithin(this.observerMapBounds)}placeObserverFrom(t){const e=this.observerMapViewBounds,i=this.observerMapCanvas.getBoundingClientRect();if(!e||i.width===0||i.height===0)return;const n=ei.pointAt(e,(t.clientX-i.left)/i.width,(t.clientY-i.top)/i.height);this.dispatchEvent(new CustomEvent("observerplace",{detail:n,bubbles:!0,composed:!0}))}constructor(){super(),this.shadow=this.attachShadow({mode:"open"});const t=document.createElement("template");t.innerHTML=`<style>${Jy}</style>${Zy}`,this.shadow.appendChild(t.content.cloneNode(!0)),this.stageElement=this.shadow.getElementById("stage"),this.canvas=this.shadow.getElementById("canvas"),this.canvasRenderer=new Sc(this.canvas.getContext("2d")),this.chromeCanvas=this.shadow.getElementById("chrome"),this.tooltip=this.shadow.getElementById("tooltip"),this.toolbar=this.shadow.getElementById("toolbar"),this.issuesBox=this.shadow.getElementById("issues"),this.issuesButton=this.shadow.getElementById("issues-button"),this.issuesPanel=this.shadow.getElementById("issues-panel"),this.issuesButton.addEventListener("click",r=>{r.stopPropagation(),this.issuesPanel.hidden=!this.issuesPanel.hidden,this.issuesButton.setAttribute("aria-expanded",String(!this.issuesPanel.hidden))}),this.playPauseButton=this.shadow.getElementById("play-pause"),this.fullscreenButton=this.shadow.getElementById("fullscreen"),this.cornerButtons=this.shadow.getElementById("corner-buttons"),this.observerMapButton=this.shadow.getElementById("observer-map"),this.referencesButton=this.shadow.getElementById("references"),this.tracesButton=this.shadow.getElementById("traces"),this.referenceOpacityInput=this.shadow.getElementById("reference-opacity"),this.referencesMenu=this.shadow.getElementById("references-menu"),this.milestonesButton=this.shadow.getElementById("milestones"),this.observerMapPanel=this.shadow.getElementById("observer-map-panel"),this.observerMapCanvas=this.shadow.getElementById("observer-map-canvas"),this.observerMapRenderer=new Lr(this.observerMapCanvas.getContext("2d")),this.mapZoomInButton=this.shadow.getElementById("map-zoom-in"),this.mapZoomOutButton=this.shadow.getElementById("map-zoom-out"),this.mapFitButton=this.shadow.getElementById("map-fit"),this.seekInput=this.shadow.getElementById("seek"),this.playbackFlash=this.shadow.getElementById("playback-flash"),this.milestoneMarks=this.shadow.getElementById("milestone-marks"),this.milestoneCaption=this.shadow.getElementById("milestone-caption"),this.timeStartLabel=this.shadow.getElementById("time-start"),this.timeEndLabel=this.shadow.getElementById("time-end"),this.timePill=this.shadow.getElementById("time"),this.muteButton=this.shadow.getElementById("mute"),this.controlsRight=this.shadow.getElementById("controls-right"),this.seekSegments=this.shadow.getElementById("seek-segments"),this.seekDot=this.shadow.getElementById("seek-dot"),this.playerTitleBox=this.shadow.getElementById("player-title"),this.seekPreview=this.shadow.getElementById("seek-preview"),this.seekPreviewCanvas=this.shadow.getElementById("seek-preview-canvas"),this.seekPreviewTitle=this.shadow.getElementById("seek-preview-title"),this.seekPreviewTime=this.shadow.getElementById("seek-preview-time"),this.timePill.addEventListener("click",()=>this.toggleTimeDisplay()),this.timePill.addEventListener("keydown",r=>{r.key!=="Enter"&&r.key!==" "||(r.preventDefault(),this.toggleTimeDisplay())}),this.volumeInput=this.shadow.getElementById("volume"),this.controlsRow=this.shadow.querySelector(".controls"),this.momentsBox=this.shadow.getElementById("moments"),this.momentsButton=this.shadow.getElementById("moments-button"),this.momentsCurrent=this.shadow.getElementById("moments-current"),this.momentsMenu=this.shadow.getElementById("moments-menu"),this.momentsButton.addEventListener("click",()=>this.toggleMomentsMenu()),this.moreButton=this.shadow.getElementById("controls-more"),this.moreButton.addEventListener("click",()=>this.setControlsFolded(this.controlsRow.classList.contains("more-open"))),this.muteButton.addEventListener("click",()=>this.toggleMuted()),this.miniPlayed=this.shadow.getElementById("mini-played"),this.miniRemaining=this.shadow.getElementById("mini-remaining"),this.miniMuteButton=this.shadow.getElementById("mini-mute"),this.miniDot=this.shadow.getElementById("mini-dot"),this.miniScrubTime=this.shadow.getElementById("mini-scrub-time");const e=this.shadow.getElementById("mini-bar"),i=e.querySelector(".mini-track"),n=r=>{const c=i.getBoundingClientRect(),h=this.player.seekableDuration;if(c.width<=0||h<=0)return;const l=Math.min(Math.max((r.clientX-c.left)/c.width,0),1)*h;this.player.seek(l),this.miniScrubTime.textContent=this.formatElapsedAt(l),this.miniScrubTime.style.left=this.miniDot.style.left};let s=!1;e.addEventListener("pointerdown",r=>{r.button===0&&(r.stopPropagation(),e.setPointerCapture(r.pointerId),e.classList.add("scrubbing"),s=this.playRequested,this.pause(),this.miniScrubTime.hidden=!1,n(r))}),e.addEventListener("pointermove",r=>{e.hasPointerCapture(r.pointerId)&&n(r)});const a=r=>{e.classList.contains("scrubbing")&&(e.classList.remove("scrubbing"),e.hasPointerCapture(r.pointerId)&&e.releasePointerCapture(r.pointerId),this.miniScrubTime.hidden=!0,s&&this.play())};e.addEventListener("pointerup",a),e.addEventListener("pointercancel",a),e.addEventListener("click",r=>r.stopPropagation()),this.miniMuteButton.addEventListener("click",r=>{r.stopPropagation(),this.toggleMuted()}),this.stageElement.addEventListener("pointerenter",this.handleMinifiedEnter),this.stageElement.addEventListener("pointerleave",this.handleMinifiedLeave),this.volumeInput.addEventListener("input",()=>{this.setVolume(Number(this.volumeInput.value))}),this.fullscreenTarget=this.stageElement,this.playPauseButton.addEventListener("click",()=>this.togglePlayPause()),this.fullscreenButton.addEventListener("click",()=>this.toggleFullscreen()),this.addEventListener("keydown",this.handleFullscreenKey),this.observerMapButton.addEventListener("click",()=>this.toggleObserverMap()),this.referencesButton.addEventListener("click",()=>this.toggleReferences()),this.tracesButton.addEventListener("click",()=>this.toggleTraces()),this.referenceOpacityInput.addEventListener("input",()=>{this.referenceOpacityTouched=!0,this.dispatchReferenceView()}),this.milestonesButton.addEventListener("click",()=>this.toggleMilestones()),this.observerMapCanvas.addEventListener("pointermove",this.handleObserverMapPointerMove),this.observerMapCanvas.addEventListener("pointerleave",this.handlePointerLeave),this.observerMapCanvas.addEventListener("click",this.handleObserverMapClick),this.observerMapCanvas.addEventListener("pointerdown",this.handleObserverMapPointerDown),this.observerMapCanvas.addEventListener("pointerup",this.handleObserverMapPointerUp),this.observerMapCanvas.addEventListener("pointercancel",this.handleObserverMapPointerUp),this.observerMapCanvas.addEventListener("wheel",this.handleObserverMapWheel,{passive:!1}),this.mapZoomInButton.addEventListener("click",()=>this.zoomObserverMap(.5,.5,2)),this.mapZoomOutButton.addEventListener("click",()=>this.zoomObserverMap(.5,.5,.5)),this.mapFitButton.addEventListener("click",()=>{this.observerMapView.reset(),this.observerMapViewChanged()}),this.seekInput.addEventListener("input",()=>{this.player.seek(this.snapSeekToMark(Number(this.seekInput.value))),this.announceReveal()}),this.seekInput.addEventListener("pointerdown",r=>{this.suspendForScrub(),this.seekSnapArmed=!0,this.nameMarkUnder(r),this.beginTouchScrub(r)}),this.seekInput.addEventListener("pointerup",r=>{this.seekSnapArmed=!1,this.endTouchScrub(r)}),this.seekInput.addEventListener("pointercancel",r=>this.endTouchScrub(r)),this.seekInput.addEventListener("pointermove",r=>{this.nameMarkUnder(r),this.hoverSeek(r),this.touchScrub(r)}),this.seekInput.addEventListener("pointerleave",()=>{this.seekInput.removeAttribute("title"),this.leaveSeek()}),this.seekInput.addEventListener("keydown",this.handleSeekKey),this.stageElement.addEventListener("pointerdown",()=>{this.handlePointerDown(),this.touchedStage()},!0);for(const r of["touchend","click"])this.stageElement.addEventListener(r,()=>this.sightingAudio.resume(),!0);this.stageElement.addEventListener("pointermove",()=>this.touchedStage()),this.canvas.addEventListener("click",r=>{if(!(!this.enableClickToPlay||this.minified)){if(this.tapRevealedOnly){this.tapRevealedOnly=!1;return}r.detail<=1&&(this.playbackBeforeClick={state:this.playbackState,time:this.currentTime}),this.togglePlayPause()}}),this.canvas.addEventListener("dblclick",r=>{!this.enableClickToPlay||this.minified||(r.preventDefault(),this.restorePlayback(),this.toggleFullscreen())}),this.canvas.addEventListener("pointermove",this.handlePointerMove),this.canvas.addEventListener("pointerleave",this.handlePointerLeave),document.addEventListener("fullscreenchange",this.handleFullscreenChange),document.addEventListener("pointerdown",this.handleMomentsDismiss,!0),document.addEventListener("keydown",this.handleMomentsDismiss,!0),document.addEventListener("visibilitychange",this.handleVisibility),window.addEventListener("pagehide",this.handleHidden),document.addEventListener("pointerup",this.handlePointerRelease,!0),document.addEventListener("pointercancel",this.handlePointerRelease,!0),this.observerMapResizeObserver?.observe(this.observerMapPanel),this.chromeResizeObserver?.observe(this.chromeCanvas),this.controlsFitObserver?.observe(this.controlsRow),this.controlsFitObserver?.observe(this.controlsRow.querySelector(".controls-left")),typeof MutationObserver<"u"&&(this.controlsMutations=new MutationObserver(()=>this.fitControls()),this.controlsMutations.observe(this.controlsRight,{attributes:!0,attributeFilter:["hidden"],childList:!0,subtree:!0})),this.hostControls(void 0),this.player=this.createPlayer(),this.updateTimeLabels(),this.updatePlayPauseButton(),this.updateFullscreenButton(),this.updateMuteButton(),this.updateObserverMapButton(),this.updateReferencesButton(),this.updateTracesButton(),this.updateMilestonesButton(),this.refresh()}connectedCallback(){this.saidTexts=void 0,this.loadLocaleMessages();const t=this.getAttribute("src");t&&this.loadFromSrc(t)}disconnectedCallback(){document.removeEventListener("fullscreenchange",this.handleFullscreenChange),document.removeEventListener("pointerdown",this.handleMomentsDismiss,!0),document.removeEventListener("keydown",this.handleMomentsDismiss,!0),document.removeEventListener("visibilitychange",this.handleVisibility),window.removeEventListener("pagehide",this.handleHidden),document.removeEventListener("pointerup",this.handlePointerRelease,!0),document.removeEventListener("pointercancel",this.handlePointerRelease,!0),window.clearTimeout(this.controlsIdleTimer),this.observerMapResizeObserver?.disconnect(),this.chromeResizeObserver?.disconnect(),this.controlsFitObserver?.disconnect(),this.controlsMutations?.disconnect(),this.exitSimulatedFullscreen(),this.sightingAudio.dispose()}attributeChangedCallback(t,e,i){if(t==="src"&&i&&i!==e&&this.isConnected&&this.loadFromSrc(i),t===uc&&this.applyObserverMapDefault(),t===dc&&this.setMilestonesShown(!this.hasAttribute(dc)),t===Hr){const n=this.minified;this.stageElement.classList.toggle("minified",n),n&&e===null&&(this.muted=!0),this.updateStartState()}}get minified(){return this.hasAttribute(Hr)}miniPlayed;miniRemaining;miniMuteButton;handleMinifiedEnter=t=>{!this.minified||t.pointerType==="touch"||(this.minifiedHovered=!0,this.play())};minifiedHovered=!1;handleMinifiedLeave=t=>{!this.minified||t.pointerType==="touch"||(this.minifiedHovered=!1,this.pause(),this.dispatchEvent(new CustomEvent(Lv)))};started=!1;updateStartState(){this.playRequested&&(this.started=!0);const t=!this.started&&this.enableClickToPlay;this.stageElement.classList.toggle("unstarted",t),t&&!this.minified?this.canvas.title=this.messages.clickToPlay:this.canvas.removeAttribute("title")}async loadFromSrc(t){this.sightingData=await Lh.recording(t)}get sightingData(){return Tx(this.currentSighting)}set sightingData(t){this.player.stop(),this.soundPreview=void 0,this.sightingAudio.silence(),this.currentSighting=Ix(t),this.observerMapFrozenSource&&(this.observerMapFrozen=this.observerMapFrozenSource(this.currentSighting.frozen)),this.issuesPanel.hidden=!0,this.issuesButton.setAttribute("aria-expanded","false"),this.reportIssues(t,this.currentSighting),this.observerMapView.reset(),this.mapFitButton.hidden=!0,this.observerMapAsked=!1,this.player=this.createPlayer(),this.started=!1,this.syncPlayerTitle(),this.updateTimeLabels(),this.updatePlayPauseButton(),this.refresh(),this.applyObserverMapDefault(),this.minified&&this.minifiedHovered&&this.play()}set playerTitle(t){this.titleOverride=t,this.syncPlayerTitle()}titleOverride;syncPlayerTitle(){const t=this.said.read(this.titleOverride)??this.said.read(this.currentSighting.observer?.title)??"";this.playerTitleBox.textContent=t,this.playerTitleBox.hidden=t===""}get recordingIssues(){return this.issues}async reportIssues(t,e){const i=++this.issueCheck;let n=[];try{const{default:s}=await Mi(async()=>{const{default:a}=await import("./sightingSchema-Bc1JhWrZ.js");return{default:a}},[],import.meta.url);n=new Rs(s).issues(t)}catch{}i===this.issueCheck&&(this.issues=[...n,...e.loadIssues],bc.warn(this.issues,e.id),this.renderIssues(),this.dispatchEvent(new CustomEvent(nw,{detail:{issues:this.issues},bubbles:!0,composed:!0})))}renderIssues(){const t=this.issues.length;this.issuesBox.hidden=t===0,this.shadow.getElementById("issues-count").textContent=String(t);const e=this.messages.recordingIssues.replace("{count}",String(t));this.issuesButton.title=e,this.issuesButton.setAttribute("aria-label",e),this.shadow.getElementById("issues-title").textContent=e,this.shadow.getElementById("issues-list").replaceChildren(...this.issues.map(i=>{const n=document.createElement("li");return n.textContent=bc.text(i,this.messages.issueTemplates),n}))}get sighting(){return this.currentSighting}previewSound(t){this.soundPreview=t,this.sightingAudio.resume(),this.sightingAudio.setSound(t)}stopSoundPreview(){this.soundPreview=void 0,this.sightingAudio.silence()}get canvasElement(){return this.canvas}get renderer(){return this.canvasRenderer}get currentTime(){return this.player.time}set currentTime(t){this.player.seek(t)}get seekableDuration(){return this.player.seekableDuration}get autoReplayEnabled(){return this.loopEnabled}set autoReplayEnabled(t){t!==this.loopEnabled&&this.toggleLoop()}play(){if(!(this.player.seekableDuration<=0||this.playbackState==="playing")){if(this.clockHeld){this.playAfterHold=!0,this.announcePlayRequest();return}this.togglePlayPause()}}get playRequested(){return this.playbackState==="playing"||this.playAfterHold}announcePlayRequest(){this.announceReveal(),this.dispatchEvent(new CustomEvent("playrequest"))}announceReveal(){this.started=!0,this.updateStartState(),this.dispatchEvent(new CustomEvent("revealrequest"))}clockHeld=!1;playAfterHold=!1;holdClock(t){if(t!==this.clockHeld){if(this.clockHeld=t,t){if(this.playbackState!=="playing")return;this.playAfterHold=!0,this.player.pause(),this.soundPreview=void 0,this.sightingAudio.silence(),this.refresh(),this.updatePlayPauseButton();return}this.playAfterHold&&(this.playAfterHold=!1,!(this.player.seekableDuration<=0||this.playbackState==="playing")&&(this.sightingAudio.resume(),this.player.play(),this.updatePlayPauseButton()))}}pause(){this.playAfterHold=!1,this.playbackState==="playing"&&this.togglePlayPause()}get positionLabel(){return this.timeStartLabel.textContent??""}get durationLabel(){return this.timeEndLabel.textContent??""}get showingClockTime(){return this.canShowClockTime}get canSwitchTimeDisplay(){return this.realStartMs!==void 0}toggleTimeDisplay(){this.canSwitchTimeDisplay&&(this.showClockTime=!this.showClockTime,this.updateTimeLabels(),this.updateTimeLabelTitles(),this.dispatchEvent(new CustomEvent("timedisplaychange",{bubbles:!0,composed:!0})))}get canShowClockTime(){return this.realStartMs!==void 0&&this.showClockTime}set showToolbar(t){this.toolbar.classList.toggle("hidden",!t),t?this.controlsRight.appendChild(this.fullscreenButton):this.cornerButtons.appendChild(this.fullscreenButton)}get playbackState(){return this.player.playbackState}get selectedSourceIds(){return this.highlightedSourceIds}get durationSeconds(){return this.currentSighting.event.durationSeconds}set durationSeconds(t){this.currentSighting.event.durationSeconds=t,this.updateTimeLabels(),this.refresh(),this.updatePlayPauseButton()}set selectedSourceIds(t){const e=new Set(t);e.size===this.highlightedSourceIds.size&&[...e].every(n=>this.highlightedSourceIds.has(n))||(this.highlightedSourceIds=e,this.refresh())}hasVisibleShapeAt(t,e){return this.shapeAt(t,e)!==void 0}refresh(){this.applyFrameFormat(),this.updateMuteButton(),this.updateTimeLabels(),this.seekInput.max=String(this.player.seekableDuration),this.refreshMilestoneMarks(),this.updateMilestonesButton(),this.updateObserverMap(),this.updateReferences(),this.updateTracesButton(),this.player.seek(this.player.time)}repaintOverlay(){this.quietFrame=!0;try{this.player.seek(this.player.time)}finally{this.quietFrame=!1}}quietFrame=!1;hostControls(t){const e=[this.milestonesButton,this.referencesButton,this.referenceOpacityInput,this.tracesButton,this.observerMapButton];if(t)for(const i of e)t.appendChild(i);else{const i=this.fullscreenButton.parentElement===this.controlsRight?this.fullscreenButton:null;for(const n of e)this.controlsRight.insertBefore(n,i)}}get referencesShown(){return this.referencesShownState}get referenceOpacity(){return Number(this.referenceOpacityInput.value)}get severalReferences(){return this.currentSighting.references.length>1}toggleReferences(){if(this.severalReferences){this.toggleReferencesMenu();return}this.referencesShownState=!this.referencesShownState,this.updateReferencesButton(),this.dispatchReferenceView()}updateReferences(){const t=this.currentSighting.references;!this.referenceOpacityTouched&&t.length>0&&(this.referenceOpacityInput.value=String(t[0].opacity));for(const e of[...this.referenceViews.keys()])t.some(i=>i.id===e)||this.referenceViews.delete(e);this.severalReferences?this.referencesMenu.hidden||this.renderReferencesMenu():this.closeReferencesMenu(),this.updateReferencesButton(),this.severalReferences&&this.dispatchReferenceView()}viewOfReference(t){let e=this.referenceViews.get(t.id);return e||(e={shown:!0,opacity:t.opacity},this.referenceViews.set(t.id,e)),e}toggleReferencesMenu(){this.referencesMenu.hidden?this.openReferencesMenu():this.closeReferencesMenu()}openReferencesMenu(){this.renderReferencesMenu(),this.referencesMenu.hidden=!1,this.placeReferencesMenu(),this.referencesButton.setAttribute("aria-expanded","true"),document.addEventListener("pointerdown",this.handleReferencesMenuOutside,!0),document.addEventListener("keydown",this.handleReferencesMenuKey,!0)}closeReferencesMenu(){this.referencesMenu.hidden||(this.referencesMenu.hidden=!0,this.referencesButton.setAttribute("aria-expanded","false"),document.removeEventListener("pointerdown",this.handleReferencesMenuOutside,!0),document.removeEventListener("keydown",this.handleReferencesMenuKey,!0))}handleReferencesMenuOutside=t=>{const e=t.composedPath();e.includes(this.referencesMenu)||e.includes(this.referencesButton)||this.closeReferencesMenu()};handleReferencesMenuKey=t=>{t.key==="Escape"&&(this.closeReferencesMenu(),this.referencesButton.focus())};placeReferencesMenu(){const t=this.referencesButton.getBoundingClientRect(),e=this.referencesMenu,i=4;e.style.bottom=`${Math.max(i,window.innerHeight-t.top+i)}px`,e.style.top="auto";const n=e.getBoundingClientRect().width;e.style.left=`${Math.max(i,Math.min(t.left,window.innerWidth-n-i))}px`}renderReferencesMenu(){const t=this.currentSighting.references.map(e=>{const i=this.viewOfReference(e),n=this.said.read(e.title)??e.id,s=document.createElement("div");s.className="reference-row";const a=document.createElement("label"),r=document.createElement("input");r.type="checkbox",r.checked=i.shown;const c=document.createElement("span");c.textContent=n,c.title=n,a.append(r,c);const h=document.createElement("input");return h.type="range",h.min="0",h.max="1",h.step="0.05",h.value=String(i.opacity),h.title=this.messages.referenceOpacity,h.setAttribute("aria-label",`${this.messages.referenceOpacity}: ${n}`),h.disabled=!i.shown,r.addEventListener("change",()=>{i.shown=r.checked,h.disabled=!i.shown,this.updateReferencesButton(),this.dispatchReferenceView()}),h.addEventListener("input",()=>{i.opacity=Number(h.value),this.dispatchReferenceView()}),s.append(a,h),s});this.referencesMenu.setAttribute("aria-label",this.messages.referencesMenu),this.referencesMenu.replaceChildren(...t)}updateReferencesButton(){const t=this.currentSighting.references.length>0,e=this.severalReferences,i=e?this.currentSighting.references.some(s=>this.viewOfReference(s).shown):this.referencesShownState;this.referencesButton.hidden=!t,this.referenceOpacityInput.hidden=!t||!this.referencesShownState||e,this.referencesButton.setAttribute("aria-pressed",String(i)),e?this.referencesButton.setAttribute("aria-haspopup","true"):this.referencesButton.removeAttribute("aria-haspopup"),Le.setIcon(this.referencesButton,i?Zt.PICTURES_ON:Zt.PICTURES_OFF);const n=e?this.messages.referencesMenu:this.referencesShownState?this.messages.hideReferences:this.messages.showReferences;this.referencesButton.title=n,this.referencesButton.setAttribute("aria-label",n),this.referenceOpacityInput.title=this.messages.referenceOpacity,this.referenceOpacityInput.setAttribute("aria-label",this.messages.referenceOpacity)}get tracesShown(){return this.tracesShownState}toggleTraces(){this.tracesShownState=!this.tracesShownState,this.updateTracesButton(),this.updateObserverMap(),this.dispatchEvent(new CustomEvent("traceview",{detail:{shown:this.tracesShown}}))}updateTracesButton(){this.tracesButton.hidden=this.currentSighting.traces.length===0,this.tracesButton.setAttribute("aria-pressed",String(this.tracesShownState)),Le.setIcon(this.tracesButton,this.tracesShownState?Zt.TRACES_ON:Zt.TRACES_OFF);const t=this.tracesShownState?this.messages.hideTraces:this.messages.showTraces;this.tracesButton.title=t,this.tracesButton.setAttribute("aria-label",t)}dispatchReferenceView(){const t=this.severalReferences?Object.fromEntries(this.currentSighting.references.map(e=>[e.id,{...this.viewOfReference(e)}])):void 0;this.dispatchEvent(new CustomEvent("referenceview",{detail:{shown:this.referencesShown,opacity:this.referenceOpacity,views:t}}))}refreshMilestoneMarks(){const t=this.player.seekableDuration,e=t>0?fh(this.sighting.milestones):[];this.milestoneMarks.replaceChildren(...e.map(i=>{const n=document.createElement("button");n.type="button",n.className="milestone-mark",n.style.left=`${Math.min(Math.max(i.t/t,0),1)*100}%`;const s=this.said.read(i.label)??"",a=this.said.read(i.note),r=a?`${s} — ${a}`:s;return n.title=r,n.setAttribute("aria-label",r),n.dataset.t=String(i.t),n.addEventListener("click",()=>this.player.seek(i.t)),n})),this.refreshSeekSegments(t,e.map(i=>i.t)),this.refreshMomentsPicker(e)}refreshMomentsPicker(t){const e=this.milestonesShown&&t.length>0;this.momentsBox.hidden=!e,this.closeMomentsMenu(),this.momentsMenu.replaceChildren(...t.map(i=>{const n=document.createElement("li"),s=document.createElement("button");s.type="button",s.dataset.t=String(i.t);const a=this.said.read(i.label)??"",r=this.said.read(i.note);return s.textContent=r?`${a} — ${r}`:a,s.addEventListener("click",()=>{this.player.seek(i.t),this.closeMomentsMenu()}),n.appendChild(s),n})),this.momentsButton.title=this.messages.moments,this.showCurrentMoment(void 0)}showCurrentMoment(t){const i=(t?this.said.read(t.label)??"":"")||this.messages.moments;this.momentsCurrent.textContent!==i&&(this.momentsCurrent.textContent=i);for(const n of this.momentsMenu.querySelectorAll("button")){const s=t!==void 0&&Number(n.dataset.t)===t.t;n.getAttribute("aria-current")==="true"!==s&&n.setAttribute("aria-current",String(s))}}toggleMomentsMenu(){this.momentsMenu.hidden?(this.momentsMenu.hidden=!1,this.momentsButton.setAttribute("aria-expanded","true")):this.closeMomentsMenu()}closeMomentsMenu(){this.momentsMenu.hidden=!0,this.momentsButton.setAttribute("aria-expanded","false")}handleMomentsDismiss=t=>{if(!this.momentsMenu.hidden){if(t instanceof KeyboardEvent){t.key==="Escape"&&this.closeMomentsMenu();return}t.composedPath().some(e=>e===this.momentsMenu||e===this.momentsButton)||this.closeMomentsMenu()}};seekSegmentList=[];refreshSeekSegments(t,e){const n=[0,...this.milestonesShown&&t>0?[...new Set(e.filter(a=>a>0&&a<t))].sort((a,r)=>a-r):[],Math.max(t,0)];this.seekSegmentList=[];const s=[];for(let a=0;a<n.length-1;a++){const r=document.createElement("div");r.className="seek-segment",r.style.flexGrow=String(Math.max(n[a+1]-n[a],1));const c=document.createElement("i");c.className="seek-hover";const h=document.createElement("i");h.className="seek-played",r.append(c,h),s.push(r),this.seekSegmentList.push({start:n[a],end:n[a+1],element:r,played:h,hover:c})}this.seekSegments.replaceChildren(...s),this.paintSeekProgress(this.player.time)}static fillOf(t,e){const i=t.end-t.start,n=i>0?(e-t.start)/i:e>=t.end?1:0;return`${Math.min(Math.max(n,0),1)*100}%`}paintMiniProgress(t){const e=this.player.seekableDuration,i=`${e>0?Math.min(Math.max(t/e,0),1)*100:0}%`;this.miniPlayed.style.width=i,this.miniDot.style.left=i,this.miniRemaining.textContent=this.formatRemaining(t)}miniDot;miniScrubTime;paintSeekProgress(t){for(const i of this.seekSegmentList)i.played.style.width=Le.fillOf(i,t);const e=this.player.seekableDuration;this.seekDot.style.left=`${e>0?Math.min(Math.max(t/e,0),1)*100:0}%`}hoverSeek(t){const e=this.seekInput.getBoundingClientRect(),i=this.player.seekableDuration;if(e.width<=0||i<=0)return;const n=Math.min(Math.max((t.clientX-e.left)/e.width,0),1),s=n*i,a=this.seekSegmentList.length-1;this.seekSegmentList.forEach((f,p)=>{f.hover.style.width=Le.fillOf(f,s),f.element.classList.toggle("hovered",s>=f.start&&(s<f.end||p===a))});const r=this.milestonesShown?this.sighting.milestones:[],c=r.length>0?Rd(r,s):void 0,h=c?this.said.read(c.label)??"":"",l=c?this.said.read(c.note):void 0,u=l?`${h} — ${l}`:h;this.seekPreviewTitle.textContent=u,this.seekPreviewTime.textContent=this.formatPosition(s),this.seekPreview.hidden=!1;const d=this.seekPreview.offsetWidth;this.seekPreview.style.left=`${Math.min(Math.max(n*e.width-d/2,0),Math.max(e.width-d,0))}px`,this.paintSeekPreview(s)}leaveSeek(){for(const t of this.seekSegmentList)t.hover.style.width="0",t.element.classList.remove("hovered");this.seekPreview.hidden=!0}seekPreviewPainter;paintSeekPreview(t){const e=this.seekPreviewPainter;this.seekPreviewCanvas.hidden=e===void 0,e?.(t,this.seekPreviewCanvas)}paintChrome(t){const e=this.chromeCanvas.getContext("2d"),i=this.overlayPainter!==void 0||this.selectionShown;if(!i&&!this.chromeDirty)return;const n=this.chromeCanvas.clientWidth,s=this.chromeCanvas.clientHeight;if(!e||typeof e.setTransform!="function"||n===0||s===0){t(this.canvasRenderer);return}const a=window.devicePixelRatio||1,r=Math.max(1,Math.round(n*a)),c=Math.max(1,Math.round(s*a));this.chromeCanvas.width!==r&&(this.chromeCanvas.width=r),this.chromeCanvas.height!==c&&(this.chromeCanvas.height=c),e.setTransform(1,0,0,1,0,0),e.clearRect(0,0,r,c),this.chromeDirty=!1,i&&(e.setTransform(r/this.canvas.width,0,0,c/this.canvas.height,0,0),this.chromeRenderer??=new Sc(e),this.chromeDirty=!0,t(this.chromeRenderer))}chromeDraw;repaintChrome(){this.chromeDraw&&this.overlayPainter&&this.paintChrome(this.chromeDraw)}scrubbingPointer;beginTouchScrub(t){if(t.pointerType!=="mouse"){this.scrubbingPointer=t.pointerId;try{this.seekInput.setPointerCapture(t.pointerId)}catch{}this.seekToPointer(t)}}touchScrub(t){t.pointerId===this.scrubbingPointer&&this.seekToPointer(t)}endTouchScrub(t){t.pointerId===this.scrubbingPointer&&(this.scrubbingPointer=void 0,this.seekToPointer(t))}seekToPointer(t){const e=this.seekInput.getBoundingClientRect(),i=this.player.seekableDuration;if(e.width<=0||i<=0)return;const n=Math.min(Math.max((t.clientX-e.left)/e.width,0),1);this.player.seek(this.snapSeekToMark(n*i))}seekSnapArmed=!1;static MARK_SNAP_PX=6;markNear(t){const e=this.player.seekableDuration,i=this.seekInput.getBoundingClientRect().width;if(e<=0||i<=0)return;const n=Le.MARK_SNAP_PX/i*e;let s;for(const a of this.milestoneMarks.children){const r=Number(a.dataset.t);Math.abs(r-t)>n||(!s||Math.abs(r-t)<Math.abs(s.t-t))&&(s={t:r,name:a.title})}return s}snapSeekToMark(t){return this.seekSnapArmed?(this.seekSnapArmed=!1,this.markNear(t)?.t??t):t}nameMarkUnder(t){const e=this.seekInput.getBoundingClientRect(),i=this.player.seekableDuration;if(e.width<=0||i<=0)return;const n=(t.clientX-e.left)/e.width*i,s=this.markNear(n);s?this.seekInput.title=s.name:this.seekInput.removeAttribute("title")}showMilestoneAt(t){const e=this.milestonesShown&&this.sighting.milestones.length>0?Rd(this.sighting.milestones,t):void 0;if(this.milestoneCaption.hidden=e===void 0,this.showCurrentMoment(e),!e)return;const i=document.createElement("b");i.textContent=this.said.read(e.label)??"";const n=this.said.read(e.note),s=n?` — ${n}`:"";this.milestoneCaption.replaceChildren(i,document.createTextNode(s))}exposureInstants(t){const e=this.exposureTimes(t),i=1/e.length;return e.map(n=>({shapes:this.shapesAt(n),share:i}))}exposureTimes(t=this.currentTime){const e=Ps.windowEndingAt(t,this.currentSighting.exposure??0);if(e.ms<Le.SHORTEST_VISIBLE_EXPOSURE_MS)return[t];const i=Math.min(Le.MAX_EXPOSURE_STEPS,Math.max(2,Math.round(e.ms/Le.SHORTEST_VISIBLE_EXPOSURE_MS))),n=Math.ceil(this.travelPxOver(e.fromMs,e.ms)/Le.EXPOSURE_STEP_PX),s=Math.min(Le.MAX_TRAVEL_STEPS,Math.max(i,n)),a=[];for(let r=0;r<s;r++)a.push(e.fromMs+e.ms*r/(s-1));return a}travelPxOver(t,e){const i=this.shapesAt(t),n=this.shapesAt(t+e);let s=0;for(const[a,r]of i){const c=n.get(a);if(!c)continue;const h=c.bounds.x+c.bounds.width/2-(r.bounds.x+r.bounds.width/2),l=c.bounds.y+c.bounds.height/2-(r.bounds.y+r.bounds.height/2);s=Math.max(s,Math.hypot(h,l))}return s}shapeAt(t,e,i){if(!this.accountHidden)for(const n of this.exposureTimes()){const s=this.currentSighting.timeline.hitTest(n,t,e,i);if(s)return s}}shapesAt(t){const e=new Map;for(const i of this.currentSighting.timeline.sourceIds){const n=this.currentSighting.timeline.getInterpolatedShapeAt(t,i);n&&e.set(i,n)}return e}static SHORTEST_VISIBLE_EXPOSURE_MS=20;static MAX_EXPOSURE_STEPS=48;static EXPOSURE_STEP_PX=2;static MAX_TRAVEL_STEPS=320;applyFrameFormat(){const t=Ii.frameWidthPx(this.currentSighting.instrument,this.canvas.height);if(this.canvas.width===t)return;this.canvas.width=t,this.canvas.parentElement?.style.setProperty("--frame-aspect",`${t} / ${this.canvas.height}`)}canvasPointFromEvent(t){const e=this.canvas.getBoundingClientRect();if(!(e.width===0||e.height===0))return{x:(t.clientX-e.left)/e.width*this.canvas.width,y:(t.clientY-e.top)/e.height*this.canvas.height}}onFrame(t,e){this.canvasRenderer.clear(this.canvas.width,this.canvas.height);const i=this.playbackState!=="playing"?this.highlightedSourceIds:iw;this.canvasRenderer.setStarPoints(Ii.starPointsOf(this.sighting.instrument,Fe(this.sighting,t)?.fNumber));const n=(Fe(this.sighting,t)?.rollDeg??0)+this.gaitAt(t).rollDeg;this.canvasRenderer.setRoll(n*Math.PI/180);const s=this.exposureInstants(t),a=this.frameShift;if(this.paintsShapes)for(const c of s)for(const[,h]of c.shapes){const l=c.share,u=l===1?h:{...h,transparency:1-(1-h.transparency)*l};this.canvasRenderer.paintShape(this.shifted(u,a))}for(const[c,h]of s[0].shapes)!this.selectionShown||!i.has(c)||(this.paintsShapes?i.size===1?this.canvasRenderer.paintShape({...h,selected:!0}):this.canvasRenderer.paintMemberOutline(h):this.canvasRenderer.paintSelectionOnly(this.shifted(h,a)));const r=this.selectionShown&&i.size>1?ss.groupBoundsFor([...e].filter(([c])=>i.has(c)).map(([,c])=>c.bounds)):void 0;this.chromeDraw=c=>{r&&c.paintGroupHandles(r),this.overlayPainter?.(c)},this.paintChrome(this.chromeDraw),this.mapShapeBounds=s.flatMap(c=>[...c.shapes.values()].filter(h=>h.transparency<1).map(h=>this.shifted(h,a).bounds)),this.keepObserverMapClear(),this.seekInput.value=String(t),this.paintSeekProgress(t),this.minified&&this.paintMiniProgress(t),this.timeStartLabel.textContent=this.formatPosition(t),this.showMilestoneAt(t),this.paintObserverMap(t),this.playbackState==="playing"?(this.soundPreview=void 0,this.sightingAudio.setSound(Mx(this.currentSighting,t))):this.soundPreview?this.sightingAudio.setSound(this.soundPreview):this.sightingAudio.silence(),this.updatePlayPauseButton(),!this.quietFrame&&this.dispatchEvent(new CustomEvent("timeupdate",{detail:{time:t}}))}shifted(t,e){return e.x===0&&e.y===0?t:{...t,bounds:{...t.bounds,x:t.bounds.x+e.x,y:t.bounds.y+e.y}}}createPlayer(){const t=new vx(this.currentSighting.timeline,(e,i)=>this.onFrame(e,i));return t.loop=this.loopEnabled,t.onEnded=()=>{this.updatePlayPauseButton(),this.dispatchEvent(new CustomEvent("ended",{bubbles:!0,composed:!0}))},t}static SEEK_KEY_STEP_MS=5e3;handleFullscreenKey=t=>{t.key.toLowerCase()!=="f"||t.altKey||t.ctrlKey||t.metaKey||!this.enableClickToPlay||t.composedPath().some(i=>i instanceof HTMLElement&&(i.isContentEditable||["INPUT","TEXTAREA","SELECT"].includes(i.tagName)&&i.type!=="range"))||(t.preventDefault(),this.toggleFullscreen())};handleSeekKey=t=>{if(t.altKey||t.ctrlKey||t.metaKey)return;const e=t.key==="ArrowLeft"?-1:t.key==="ArrowRight"?1:0;if(e){t.preventDefault();const i=this.player.seekableDuration;this.player.seek(Math.min(i,Math.max(0,this.player.time+e*Le.SEEK_KEY_STEP_MS)))}else t.key===" "&&(t.preventDefault(),this.togglePlayPause())};togglePlayPause(){if(!(this.player.seekableDuration<=0)){if(this.player.playbackState==="playing")this.player.pause(),this.soundPreview=void 0,this.sightingAudio.silence(),this.refresh();else if(this.clockHeld){this.playAfterHold=!this.playAfterHold,this.playAfterHold&&this.announcePlayRequest();return}else this.announcePlayRequest(),this.sightingAudio.resume(),this.player.play();this.updatePlayPauseButton(),this.flashPlayback()}}flashPlayback(){const t=this.playbackFlash;t.innerHTML=this.player.playbackState==="playing"?Zt.PLAY:Zt.PAUSE,t.classList.remove("flashing"),t.offsetWidth,t.classList.add("flashing")}static icons=new WeakMap;static setIcon(t,e){Le.icons.get(t)!==e&&(Le.icons.set(t,e),t.innerHTML=e)}set captionHeld(t){this.stageElement.classList.toggle("caption-held",t)}set controlsHeld(t){this.stageElement.classList.toggle("controls-held",t)}static CONTROLS_IDLE_MS=3e3;controlsIdleTimer;wasPlaying=!1;quietControlsValue=!1;get quietControls(){return this.quietControlsValue}set quietControls(t){this.quietControlsValue=t,this.stageElement.classList.toggle("quiet",t)}tapRevealedOnly=!1;get hoverless(){return typeof matchMedia=="function"&&matchMedia("(hover: none)").matches}touchedStage(){if(!this.hoverless)return;this.player.playbackState==="playing"&&!this.stageElement.classList.contains("touched")&&(this.tapRevealedOnly=!0),this.revealControls()}pointerHeld=!1;handlePointerDown=()=>{this.pointerHeld=!0};resumeAfterScrub=!1;suspendForScrub(){this.player.playbackState==="playing"&&(this.resumeAfterScrub=!0,this.stopPlaying())}stopPlaying(){this.player.pause(),this.soundPreview=void 0,this.sightingAudio.silence(),this.refresh(),this.updatePlayPauseButton()}resumeFromScrub(){this.resumeAfterScrub&&(this.resumeAfterScrub=!1,this.sightingAudio.resume(),this.player.play(),this.updatePlayPauseButton())}handleHidden=()=>{this.player.playbackState==="playing"&&this.stopPlaying(),this.resumeAfterScrub=!1};handleVisibility=()=>{document.visibilityState==="hidden"&&this.handleHidden()};handlePointerRelease=()=>{this.resumeAfterScrub&&window.setTimeout(()=>this.resumeFromScrub(),0),this.pointerHeld&&(this.pointerHeld=!1,this.hoverless&&this.stageElement.classList.contains("touched")&&this.revealControls())};revealControls(){this.stageElement.classList.add("touched"),window.clearTimeout(this.controlsIdleTimer),this.player.playbackState==="playing"&&(this.pointerHeld||!this.momentsMenu.hidden||(this.controlsIdleTimer=window.setTimeout(()=>{this.stageElement.classList.remove("touched"),this.tapRevealedOnly=!1},Le.CONTROLS_IDLE_MS)))}updatePlayPauseButton(){const t=this.player.playbackState==="playing";this.stageElement.classList.toggle("paused",!t),t!==this.wasPlaying&&t&&this.hoverless&&(!this.quietControlsValue||this.stageElement.classList.contains("touched"))&&this.revealControls(),this.wasPlaying=t,this.updateStartState(),Le.setIcon(this.playPauseButton,t?Zt.PAUSE:Zt.PLAY);const e=this.player.seekableDuration>0;this.playPauseButton.disabled=!e;const i=e?t?this.messages.pause:this.messages.play:this.messages.noDuration;this.playPauseButton.title=i,this.playPauseButton.setAttribute("aria-label",i)}toggleLoop(){this.loopEnabled=!this.loopEnabled,this.player.loop=this.loopEnabled}restorePlayback(){const t=this.playbackBeforeClick;t&&(this.currentTime=t.time,t.state==="playing"?this.play():this.pause())}get canUseNativeFullscreen(){return typeof this.fullscreenTarget.requestFullscreen=="function"&&document.fullscreenEnabled}toggleFullscreen(){if(!this.canUseNativeFullscreen){this.simulatedFullscreen?this.exitSimulatedFullscreen():this.enterSimulatedFullscreen();return}document.fullscreenElement?document.exitFullscreen():this.fullscreenTarget.requestFullscreen().catch(t=>{console.error("<rr0-ufo>: requestFullscreen() failed —",t)})}enterSimulatedFullscreen(){const t=this.fullscreenTarget;this.styleBeforeSimulatedFullscreen=t.getAttribute("style")??"",this.bodyOverflowBeforeSimulatedFullscreen=document.body.style.overflow;const e=t.style;e.setProperty("position","fixed"),e.setProperty("inset","0"),e.setProperty("margin","0"),e.setProperty("max-width","none"),e.setProperty("max-height","none"),e.setProperty("aspect-ratio","auto"),e.setProperty("z-index","2147483647"),e.setProperty("background","#000"),e.setProperty("width","100vw"),e.setProperty("width","100dvw"),e.setProperty("height","100vh"),e.setProperty("height","100dvh"),document.body.style.overflow="hidden",this.simulatedFullscreen=!0,document.addEventListener("keydown",this.handleSimulatedFullscreenKey),this.updateFullscreenButton(),this.updateMuteButton()}exitSimulatedFullscreen(){if(!this.simulatedFullscreen)return;const t=this.fullscreenTarget;this.styleBeforeSimulatedFullscreen?t.setAttribute("style",this.styleBeforeSimulatedFullscreen):t.removeAttribute("style"),document.body.style.overflow=this.bodyOverflowBeforeSimulatedFullscreen??"",this.simulatedFullscreen=!1,document.removeEventListener("keydown",this.handleSimulatedFullscreenKey),this.updateFullscreenButton(),this.updateMuteButton()}toggleObserverMap(){const t=this.observerMapPanel.hidden;this.observerMapAsked=t,this.setObserverMapOpen(t),this.keepObserverMapClear(),this.dispatchEvent(new CustomEvent("observermapchange",{bubbles:!0,composed:!0,detail:{open:t}}))}get observerMapOpen(){return!this.observerMapPanel.hidden}get milestonesVisible(){return this.milestonesShown}observerMapAsked=!1;applyObserverMapDefault(){const t=this.getAttribute(uc),e=t===null?this.sighting.observerMap??this.observerPath?.travels===!0:t!=="false";this.setObserverMapOpen(e&&this.observerPath!==void 0)}setObserverMapOpen(t){this.observerMapPanel.hidden=!t,this.observerMapPanel.removeAttribute("title"),this.observerMapButton.setAttribute("aria-pressed",String(t)),this.updateObserverMapButton(),t&&(this.sizeObserverMapCanvas(),this.loadObserverMapImagery(),this.paintObserverMap(this.currentTime))}updateObserverMapButton(){const t=!this.observerMapPanel.hidden;Le.setIcon(this.observerMapButton,t?Zt.MAP_ON:Zt.MAP_OFF);const e=t?this.messages.hideObserverMap:this.messages.showObserverMap;this.observerMapButton.title=e,this.observerMapButton.setAttribute("aria-label",e);const i=[[this.mapZoomInButton,this.messages.zoomMapIn],[this.mapZoomOutButton,this.messages.zoomMapOut],[this.mapFitButton,this.messages.fitMap]];for(const[n,s]of i)n.title=s,n.setAttribute("aria-label",s)}updateObserverMap(){const t=this.observerPath!==void 0;if(this.observerPath=hc.of(this.currentSighting),this.observerMapButton.hidden=this.observerPath===void 0,!t&&this.observerPath&&this.applyObserverMapDefault(),!this.observerPath){this.setObserverMapOpen(!1),this.observerMapBounds=void 0;return}const e=this.tracesShownState?this.currentSighting.traces.flatMap(n=>n.points):[],i=ei.fitted(this.observerPath,e);(!this.observerMapBounds||!this.sameGround(this.observerMapBounds,i))&&(this.observerMapBounds&&this.observerMapView.refit(this.observerMapBounds,i),this.observerMapBounds=i,this.observerMapImagery=void 0,this.observerMapImageryCredit=void 0,this.observerMapImageryFailed=!1,this.observerMapImageryBounds=void 0,this.observerMapImageryLoading=!1,this.observerMapPanel.hidden||this.loadObserverMapImagery())}sameGround(t,e){const i=Math.abs(t.east-t.west)/20;return Math.abs(t.north-e.north)<i&&Math.abs(t.south-e.south)<i&&Math.abs(t.west-e.west)<i&&Math.abs(t.east-e.east)<i}async loadObserverMapImagery(){const t=this.observerMapViewBounds;if(!t||this.observerMapPanel.hidden||this.observerMapImageryLoading||(this.observerMapFrozenImagery?this.observerMapImageryBounds!==void 0:!this.observerMapImageryNeededFor(t)))return;const e=this.observerMapView.changed,i=e?ei.expand(t,Le.OBSERVER_MAP_IMAGERY_AHEAD):t,n=ei.IMAGERY_PX*(e?1+2*Le.OBSERVER_MAP_IMAGERY_AHEAD:1);this.observerMapImageryBounds=i,this.observerMapImageryViewWidth=t.east-t.west,this.observerMapImageryLoading=!0;const s=this.observerMapFrozenImagery,a=s?void 0:Ov();try{const r=a?await a.getImageryTexture(i,{width:n,height:n}):await s.getImagery();if(this.observerMapImageryBounds!==i)return;this.observerMapImagery=r,this.observerMapImageryCredit=(a??s).attribution,this.observerMapImageryFailed=!1}catch{if(this.observerMapImageryBounds!==i)return;this.observerMapImageryFailed=this.observerMapImagery===void 0}finally{this.observerMapImageryBounds===i&&(this.observerMapImageryLoading=!1)}this.paintObserverMap(this.currentTime),this.scheduleObserverMapImagery()}static OBSERVER_MAP_IMAGERY_AHEAD=.5;static OBSERVER_MAP_IMAGERY_LOOKAHEAD=.25;observerMapImageryNeededFor(t){const e=this.observerMapImageryBounds;if(!e)return!0;const i=this.observerMapImagery?.bounds??e,n=this.observerMapView.changed?ei.expand(t,Le.OBSERVER_MAP_IMAGERY_LOOKAHEAD):t,s=n.west>=i.west&&n.east<=i.east&&n.south>=i.south&&n.north<=i.north,a=t.east-t.west>this.observerMapImageryViewWidth/2;return!s||!a}get observerMapCredit(){return this.observerMapImageryCredit}set observerMapFrozen(t){t!==this.observerMapFrozenImagery&&(this.observerMapFrozenImagery=t,this.observerMapImagery=void 0,this.observerMapImageryCredit=void 0,this.observerMapImageryFailed=!1,this.observerMapImageryBounds=void 0,this.observerMapImageryLoading=!1,this.observerMapPanel.hidden||(this.loadObserverMapImagery(),this.paintObserverMap(this.currentTime)))}get observerMapFrozen(){return this.observerMapFrozenImagery}observerMapFrozenImagery;observerMapFrozenSource;get observerMapFooterLine(){return this.observerMapImageryFailed?this.messages.mapImageryUnavailable:this.creditShownExternally?void 0:this.observerMapImageryCredit}mapShapeBounds=[];mapSceneBounds=[];setMapSubjectBounds(t){this.mapSceneBounds=t.map(e=>({x:e.x*this.canvas.width,y:e.y*this.canvas.height,width:e.width*this.canvas.width,height:e.height*this.canvas.height})),this.keepObserverMapClear()}keepObserverMapClear(){if(this.observerMapPanel.hidden)return;const t=this.observerMapBoxPx;if(!t)return;const e=[...this.mapShapeBounds,...this.mapSceneBounds],i=(h,l,u)=>{for(const d of e)if(!(d.x+d.width<h-u||d.x>l+u)&&!(d.y>t.bottom+u||d.y+d.height<t.top-u))return!0;return!1},n=[this.canvas.width-t.width,this.canvas.width],s=[0,t.width],a=Le.OBSERVER_MAP_CLEARANCE_PX,r=i(...n,0),c=i(...s,0);if(this.observerMapPanel.classList.toggle("subject-overlap",r&&c&&!this.observerMapAsked),this.observerMapPanel.classList.contains("on-the-left")){!r&&(c||!i(n[0],n[1],a))&&this.observerMapPanel.classList.remove("on-the-left");return}i(n[0],n[1],0)&&!i(s[0],s[1],0)&&this.observerMapPanel.classList.add("on-the-left")}observerMapBoxPx;static OBSERVER_MAP_CLEARANCE_PX=24;sizeObserverMapCanvas(){const t=this.observerMapPanel.clientWidth;if(t===0)return;const e=Math.round(t*(globalThis.devicePixelRatio??1));this.measureObserverMapBox(),this.observerMapCanvas.width!==e&&(this.observerMapCanvas.width=e,this.observerMapCanvas.height=e)}measureObserverMapBox(){const t=this.observerMapPanel.getBoundingClientRect(),e=this.canvas.getBoundingClientRect();if(e.width===0||e.height===0)return;const i=this.canvas.width/e.width,n=this.canvas.height/e.height;this.observerMapBoxPx={width:t.width*i,top:(t.top-e.top)*n,bottom:(t.bottom-e.top)*n}}paintObserverMap(t){if(this.observerMapPanel.hidden||!this.observerPath||!this.observerMapBounds)return;const e=Fe(this.currentSighting,t);e?.lat!==void 0&&e.lng!==void 0&&!this.observerMapDrag?.moved&&this.observerMapView.keepInView(this.observerMapBounds,{lat:e.lat,lng:e.lng},Le.OBSERVER_MAP_FOLLOW_MARGIN)&&this.scheduleObserverMapImagery();const i=this.currentSighting.instrument,n=[],s=this.currentSighting.milestones.length>0?Rd(this.currentSighting.milestones,t):void 0;for(const a of this.milestonesShown?fh(this.currentSighting.milestones):[]){const r=Fe(this.currentSighting,a.t);r?.lat===void 0||r.lng===void 0||n.push({label:this.said.read(a.label)??"",note:this.said.read(a.note),t:a.t,lat:r.lat,lng:r.lng,current:a===s})}this.observerMapRenderer.paint({bounds:this.observerMapViewBounds,imagery:this.observerMapImagery,path:this.observerPath,position:e?.lat!==void 0&&e.lng!==void 0?{lat:e.lat,lng:e.lng}:void 0,headingDeg:e?.headingDeg===void 0?void 0:e.headingDeg+this.lookYawDeg,coneHalfAngleDeg:e?ha.of(i,this.canvas.height,e.fovDeg).halfWidthAngleDeg(Ii.aspectOf(i)):void 0,markers:n,traces:(this.tracesShownState?this.currentSighting.traces:[]).map(a=>({kind:a.kind,points:a.points,color:a.color,label:this.said.read(a.title)})),decor:this.observerMapDecorAt(t),observerLabel:this.said.read(this.currentSighting.observer?.title)??this.messages.observerHere,nightFraction:this.observerMapNightFraction,attribution:this.observerMapFooterLine})}toggleMilestones(){this.setMilestonesShown(!this.milestonesShown)}setMilestonesShown(t){this.milestonesShown=t,this.milestoneMarks.hidden=!t,this.momentsBox.hidden=!t||this.sighting.milestones.length===0,this.refreshSeekSegments(this.player.seekableDuration,fh(this.sighting.milestones).map(e=>e.t)),this.milestonesButton.setAttribute("aria-pressed",String(t)),this.updateMilestonesButton(),this.showMilestoneAt(this.currentTime),this.paintObserverMap(this.currentTime)}updateMilestonesButton(){this.milestonesButton.hidden=this.currentSighting.milestones.length===0,this.momentsButton.title=this.messages.moments,Le.setIcon(this.milestonesButton,this.milestonesShown?Zt.MILESTONES_ON:Zt.MILESTONES_OFF);const t=this.milestonesShown?this.messages.hideMilestones:this.messages.showMilestones;this.milestonesButton.title=t,this.milestonesButton.setAttribute("aria-label",t)}observerMapDecorAt(t){const e=Fe(this.currentSighting,0);return e?.lat===void 0||e.lng===void 0?[]:this.currentSighting.decor.filter(i=>i.kind!=="crop").map(i=>{const n=fa(i,t),{lat:s,lng:a}=Kn(n.eastM,-n.northM,e.lat,e.lng);return{lat:s,lng:a,headingDeg:n.headingDeg,label:this.said.read(i.title)??this.messages.decorHere}})}observerMapNightFraction;setSunAltitude(t){const e=t===void 0?void 0:Math.max(0,Math.min(1,-t/12));e!==this.observerMapNightFraction&&(this.observerMapNightFraction=e,this.paintObserverMap(this.currentTime))}setLookOffset(t,e){t===this.lookYawDeg&&e===this.lookPitchDeg||(this.lookYawDeg=t,this.lookPitchDeg=e,this.refresh())}get frameShiftPx(){return this.frameShift}get frameShift(){const t=this.gaitAt(this.currentTime),e=this.lookYawDeg+t.yawDeg,i=this.lookPitchDeg+t.pitchDeg;if(e===0&&i===0)return{x:0,y:0};const n=Fe(this.currentSighting,this.currentTime),s=ha.of(this.currentSighting.instrument,this.canvas.height,n?.fovDeg??60);return{x:-s.angleDegToRadiusPx(e),y:s.angleDegToRadiusPx(i)}}gaitAt(t){return Ye.bodyAt(this.currentSighting,t,this.steadyBody)}mutedState=!1;get muted(){return this.mutedState}set muted(t){t!==this.mutedState&&(this.mutedState=t,!t&&this.volumeState===0&&(this.volumeState=Le.RESTORED_VOLUME),this.applyLevel())}volumeState=1;static RESTORED_VOLUME=.5;get volume(){return this.volumeState}set volume(t){this.setVolume(t)}setVolume(t){this.volumeState=Math.min(Math.max(t,0),1),this.mutedState=this.volumeState===0,this.applyLevel()}get level(){return this.mutedState?0:this.volumeState}applyLevel(){this.sightingAudio.setLevel(this.level),this.updateMuteButton(),this.dispatchEvent(new CustomEvent("mutedchange",{bubbles:!0,composed:!0,detail:{muted:this.mutedState,volume:this.volumeState}}))}toggleMuted(){this.hasSound&&(this.muted=!this.mutedState)}ambientSound;get hasSound(){return this.currentSighting.soundTrack.allKeyframes.length>0||this.ambientSound?.(this.currentSighting)===!0}updateMuteButton(){const t=!this.hasSound;this.miniMuteButton.hidden=t,this.miniMuteButton.setAttribute("aria-pressed",String(this.mutedState)),Le.setIcon(this.miniMuteButton,this.mutedState?Zt.MUTED:Zt.VOLUME);const e=this.mutedState?this.messages.unmute:this.messages.mute;if(this.miniMuteButton.title=e,this.miniMuteButton.setAttribute("aria-label",e),this.muteButton.disabled=t,this.volumeInput.hidden=t,t){Le.setIcon(this.muteButton,Zt.MUTED),this.muteButton.title=this.messages.noSound,this.muteButton.setAttribute("aria-label",this.messages.noSound),this.muteButton.setAttribute("aria-pressed","true");return}Le.setIcon(this.muteButton,this.mutedState?Zt.MUTED:Zt.VOLUME);const i=this.mutedState?this.messages.unmute:this.messages.mute;this.muteButton.title=i,this.muteButton.setAttribute("aria-label",i),this.muteButton.setAttribute("aria-pressed",String(this.mutedState)),this.volumeInput.value=String(this.level)}updateFullscreenButton(){const t=this.simulatedFullscreen||document.fullscreenElement===this.fullscreenTarget;Le.setIcon(this.fullscreenButton,t?Zt.EXIT_FULLSCREEN:Zt.ENTER_FULLSCREEN),this.fullscreenButton.title=t?this.messages.exitFullscreen:this.messages.fullscreen,this.fullscreenButton.setAttribute("aria-label",this.fullscreenButton.title)}get said(){return this.saidTexts??=new Pa(lc.preferencesFor(this))}saidTexts;async loadLocaleMessages(){const t=vv(lc.preferencesFor(this),yv);if(t===this.messagesLanguage||t==="en"&&this.messagesLanguage===void 0)return;this.messagesLanguage=t;const e=await Ox(t);this.messagesLanguage===t&&this.applyMessages(e)}messagesLanguage;updateTimeLabelTitles(){const t=this.showClockTime?this.messages.switchToElapsed:this.messages.switchToClockTime,e=this.canSwitchTimeDisplay?` — ${t}`:"";this.timeStartLabel.title=this.messages.currentPosition+e,this.timeEndLabel.title=this.messages.duration+e,this.timePill.classList.toggle("switchable",this.canSwitchTimeDisplay),this.canSwitchTimeDisplay?(this.timePill.setAttribute("role","button"),this.timePill.setAttribute("tabindex","0")):(this.timePill.removeAttribute("role"),this.timePill.removeAttribute("tabindex"))}applyMessages(t){this.messages=t,this.updateTimeLabelTitles(),this.updatePlayPauseButton(),this.updateFullscreenButton(),this.updateMuteButton(),this.updateObserverMapButton(),this.updateReferencesButton(),this.updateTracesButton(),this.updateMilestonesButton(),this.renderIssues()}updateTimeLabels(){const t=this.currentSighting.event,e=px(t);this.realDurationMs=e!==void 0&&e>0?e:void 0,this.realStartMs=t.time?o0(t.time):void 0;const i=this.currentSighting.timeline.duration;this.player.playbackRate=this.realDurationMs!==void 0&&i>0?i/this.realDurationMs:1,this.player.durationOverrideMs=i>0?0:this.realDurationMs??0,this.timeEndLabel.textContent=this.formatEndOfTimeline(),this.timeStartLabel.textContent=this.formatPosition(this.player.time),this.paintMiniProgress(this.player.time),this.updateTimeLabelTitles()}formatPosition(t){if(this.realDurationMs===void 0)return Ya(t);const e=this.currentSighting.timeline.duration,i=e>0&&t<=e?t/e*this.realDurationMs:t;return this.canShowClockTime?fg(dg(this.realStartMs+i)):Ya(i)}formatElapsedAt(t){const e=this.currentSighting.timeline.duration;return this.realDurationMs===void 0?Ya(t):Ya(e>0&&t<=e?t/e*this.realDurationMs:t)}formatRemaining(t){const e=this.currentSighting.timeline.duration;if(this.realDurationMs===void 0)return Ya(Math.max(0,e-t));const i=e>0&&t<=e?t/e*this.realDurationMs:t;return Ya(Math.max(0,this.realDurationMs-i))}formatEndOfTimeline(){return this.realDurationMs===void 0?Ya(this.currentSighting.timeline.duration):this.canShowClockTime?fg(dg(this.realStartMs+this.realDurationMs)):Ya(this.realDurationMs)}}function dg(o){const t=new Date(o);return{hour:t.getUTCHours(),minute:t.getUTCMinutes(),second:t.getUTCSeconds()}}function fg(o){if(o.hour===void 0)return"0:00";const t=e=>String(e).padStart(2,"0");return o.second?`${t(o.hour)}:${t(o.minute??0)}:${t(o.second)}`:`${t(o.hour)}:${t(o.minute??0)}`}function Ya(o){const t=Math.round(o/1e3),e=Math.floor(t/60),i=t%60;return`${e}:${String(i).padStart(2,"0")}`}const h0="rr0-ufo";function Pv(){customElements.get(h0)||customElements.define(h0,Le)}const nw="recordingissues",Lv="minifiedreset";/**
1739
+ `);let e=$o.shared.get(t);return e||(e=this.fetchFirstAvailable(),$o.shared.set(t,e),e.then(i=>{i.length===0&&$o.shared.delete(t)})),this.index=e}async fetchFirstAvailable(){for(const t of this.indexUrls)try{const e=await this.fetchImpl(t);if(!e.ok)continue;const i=await e.json();if(Array.isArray(i?.entries))return i.entries.map(n=>({entry:n,indexUrl:t}))}catch{}return[]}static defaultIndexUrls(){const t=`?v=${encodeURIComponent("0.152.1")}`,e=typeof location>"u"?void 0:new URL("/roads/index.json",location.href).href;return(e&&e!==Dd?[e,Dd]:[Dd]).map(i=>i+t)}}class hr{attribution="Roads © IGN, BD TOPO (Licence Ouverte 2.0), as drawn today";contemporary=!0;static BY_NATURE={"Type autoroutier":{surface:"paved",widthM:11},"Route à 2 chaussées":{surface:"paved",widthM:7},"Route à 1 chaussée":{surface:"paved",widthM:5.5},"Rond-point":{surface:"paved",widthM:6},Bretelle:{surface:"paved",widthM:5},"Route empierrée":{surface:"gravel",widthM:3.5},Chemin:{surface:"dirt",widthM:3},"Piste cyclable":{surface:"paved",widthM:2.5}};static DEFAULT={surface:"paved",widthM:5};static KINDS={"Type autoroutier":"motorway","Route à 2 chaussées":"dual","Route à 1 chaussée":"road","Rond-point":"roundabout",Bretelle:"slip"};static DIRECTIONS={"Double sens":"both","Sens direct":"forward","Sens inverse":"backward"};platform;constructor(t={}){this.platform=new Re(t)}static covers(t){return Re.covers((t.south+t.north)/2,(t.west+t.east)/2)}async getRoads(t){return(await this.platform.roads(t)).flatMap((i,n)=>hr.wayOf(i,n))}static wayOf(t,e){if(t.geometry.type!=="LineString")return[];const i=t.geometry.coordinates.map(([d,f])=>({lat:f,lng:d}));if(i.length<2)return[];const n=String(t.properties.nature??""),s=hr.BY_NATURE[n]??hr.DEFAULT,a=Number(t.properties.largeur_de_chaussee),r=Number(t.properties.nombre_de_voies),c=Number(t.properties.vitesse_moyenne_vl),h=hr.DIRECTIONS[String(t.properties.sens_de_circulation??"")],l=hr.KINDS[n],u=[t.properties.cpx_toponyme_route_nommee,t.properties.nom_voie_ban_gauche,t.properties.nom_voie_ban_droite].find(d=>typeof d=="string"&&d.length>0);return[{id:String(t.properties.cleabs??`ign-${e}`),...u?{name:u}:{},surface:s.surface,widthM:Number.isFinite(a)&&a>0?a:s.widthM,...t.properties.urbain===!0?{urban:!0}:{},...l?{kind:l}:{},...Number.isInteger(r)&&r>0?{lanes:r}:{},...h?{direction:h}:{},...Number.isFinite(c)&&c>0?{speedKmh:c}:{},points:i}]}}class qx{constructor(t,e){this.regional=t,this.worldwide=e}attribution="Roads © IGN, BD TOPO, in France; © OpenStreetMap contributors elsewhere, as drawn today";contemporary=!0;async getRoads(t){if(hr.covers(t))try{const e=await this.regional.getRoads(t);if(e.length>0)return e}catch{}return this.worldwide.getRoads(t)}}class Fh{attribution="Water © IGN, BD TOPO (Licence Ouverte 2.0)";platform;constructor(t={}){this.platform=new Re(t)}static covers(t){return Re.covers((t.south+t.north)/2,(t.west+t.east)/2)}async getWater(t){return(await this.platform.waterSurfaces(t)).flatMap((i,n)=>Fh.surfacesOf(i,n))}static surfacesOf(t,e){const{type:i,coordinates:n}=t.geometry,s=i==="Polygon"?[n]:i==="MultiPolygon"?n:[],a=String(t.properties.cleabs??`ign-water-${e}`);return s.flatMap((r,c)=>{const h=r.map(l=>Fh.open(l.map(u=>({lat:u[1],lng:u[0]})))).filter(l=>l.length>=3);return h.length>0?[{id:s.length>1?`${a}-${c}`:a,rings:h}]:[]})}static open(t){const e=t[0],i=t[t.length-1];return t.length>1&&e.lat===i.lat&&e.lng===i.lng?t.slice(0,-1):t}}class Nr{attribution="Water © OpenStreetMap contributors";client;constructor(t={}){this.client=new Wn(t)}async getWater(t){const e=`${t.south},${t.west},${t.north},${t.east}`,i=`[out:json][timeout:30];(way["natural"="water"](${e});way["waterway"="riverbank"](${e});)->.w;(relation["natural"="water"](${e});relation["waterway"="riverbank"](${e});)->.r;.w out geom;.r out body;way(r.r)(${e});out geom;`;return Nr.surfacesFrom(await this.client.query(i))}static surfacesFrom(t){const e=t.elements??[],i=new Map;for(const a of e)a.type==="way"&&a.id!==void 0&&a.geometry&&i.set(a.id,a.geometry.map(r=>({lat:r.lat,lng:r.lon})));const n=[],s=new Set;for(const a of e){if(a.type!=="relation")continue;const r=h=>(a.members??[]).filter(l=>l.type==="way"&&l.role===h&&l.ref!==void 0&&i.has(l.ref)).map(l=>(s.add(l.ref),i.get(l.ref))),c=Nr.rings(r("inner"));for(const[h,l]of Nr.rings(r("outer")).entries()){const u=c.filter(d=>Nr.contains(l,d[0]));n.push({id:`osm-r${a.id}-${h}`,rings:[l,...u]})}}for(const a of e)if(!(a.type!=="way"||!a.tags||a.id===void 0||s.has(a.id))&&!(a.tags.natural!=="water"&&a.tags.waterway!=="riverbank"))for(const r of Nr.rings([i.get(a.id)??[]]))n.push({id:`osm-w${a.id}`,rings:[r]});return n}static rings(t){const e=(s,a)=>s.lat===a.lat&&s.lng===a.lng,i=t.filter(s=>s.length>=2).map(s=>[...s]),n=[];for(;i.length>0;){let s=i.pop(),a=!0;for(;!e(s[0],s[s.length-1])&&a;){a=!1;for(let r=0;r<i.length;r++){const c=i[r],h=s[s.length-1];if(e(h,c[0]))s=[...s,...c.slice(1)];else if(e(h,c[c.length-1]))s=[...s,...[...c].reverse().slice(1)];else continue;i.splice(r,1),a=!0;break}}s.length>=4&&e(s[0],s[s.length-1])&&n.push(s.slice(0,-1))}return n}static contains(t,e){let i=!1;for(let n=0,s=t.length-1;n<t.length;s=n++){const a=t[n],r=t[s];a.lat>e.lat!=r.lat>e.lat&&e.lng<(r.lng-a.lng)*(e.lat-a.lat)/(r.lat-a.lat)+a.lng&&(i=!i)}return i}}class Zx{constructor(t,e){this.regional=t,this.worldwide=e}attribution="Water © IGN, BD TOPO, in France; © OpenStreetMap contributors elsewhere";async getWater(t){if(Fh.covers(t))try{const e=await this.regional.getWater(t);if(e.length>0)return e}catch{}return this.worldwide.getWater(t)}}const Cd="https://ufoathome.org/water/index.json";class qo{attributionRead;fetchImpl;indexUrls;fallback;index;static shared=new Map;sharing;constructor(t={}){this.sharing=!t.fetchImpl,this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.indexUrls=t.indexUrls??qo.defaultIndexUrls(),this.fallback=t.fallback}get attribution(){return this.attributionRead??this.fallback?.attribution??"Water © OpenStreetMap contributors"}async getWater(t){const e=await this.held(t);if(e)return e;if(!this.fallback)return[];const i=await this.fallback.getWater(t);return this.attributionRead=this.fallback.attribution,i}async held(t){const i=(await this.load().catch(()=>[])).find(({entry:n})=>n.north>=t.north&&n.south<=t.south&&n.east>=t.east&&n.west<=t.west);if(i)try{const n=await this.fetchImpl(new URL(i.entry.file,i.indexUrl).href);if(!n.ok)return;const s=await n.json();return Array.isArray(s?.surfaces)?(this.attributionRead=s.attribution,s.surfaces):void 0}catch{return}}load(){if(this.index)return this.index;if(!this.sharing)return this.index=this.fetchFirstAvailable();const t=this.indexUrls.join(`
1740
+ `);let e=qo.shared.get(t);return e||(e=this.fetchFirstAvailable(),qo.shared.set(t,e),e.then(i=>{i.length===0&&qo.shared.delete(t)})),this.index=e}async fetchFirstAvailable(){for(const t of this.indexUrls)try{const e=await this.fetchImpl(t);if(!e.ok)continue;const i=await e.json();if(Array.isArray(i?.entries))return i.entries.map(n=>({entry:n,indexUrl:t}))}catch{}return[]}static defaultIndexUrls(){const t=`?v=${encodeURIComponent("0.152.1")}`,e=typeof location>"u"?void 0:new URL("/water/index.json",location.href).href;return(e&&e!==Cd?[e,Cd]:[Cd]).map(i=>i+t)}}class Bn{constructor(t){this.water=t}static CACHE_NAME="rr0-water";static MAX_AGE_MS=720*3600*1e3;static FORMAT=1;static MAX_STORED=400;static asked=new Map;get attribution(){return this.water.attribution}async getWater(t){const e=Bn.key(t);let i=Bn.asked.get(e);return i===void 0&&(i=this.recalled(e,t),Bn.asked.set(e,i),i.catch(()=>Bn.asked.delete(e))),structuredClone(await i)}static forget(){Bn.asked.clear()}static key(t){return`v${Bn.FORMAT}/${[t.north,t.south,t.east,t.west].map(e=>e.toFixed(5)).join("/")}`}async recalled(t,e){const i=await Bn.openCache(),n=Bn.request(t);if(i)try{const a=await i.match(n);if(a){const{savedAt:r,surfaces:c}=await a.json();if(Date.now()-r<Bn.MAX_AGE_MS&&Array.isArray(c))return c;await i.delete(n)}}catch{}const s=await this.water.getWater(e);return i&&Bn.store(i,n,s),s}static async store(t,e,i){try{const n={savedAt:Date.now(),surfaces:i};await t.put(e,new Response(JSON.stringify(n),{headers:{"Content-Type":"application/json"}}));const s=await t.keys();for(const a of s.slice(0,Math.max(0,s.length-Bn.MAX_STORED)))await t.delete(a)}catch{}}static async openCache(){try{return typeof caches>"u"?void 0:await caches.open(Bn.CACHE_NAME)}catch{return}}static request(t){const e=typeof location>"u"?"http://localhost":location.origin;return new Request(`${e}/__water__/${encodeURIComponent(t)}`)}}class lr{attribution="Railways © IGN, BD TOPO (Licence Ouverte 2.0), as drawn today";contemporary=!0;static BY_NATURE={"Voie ferrée principale":{kind:"rail"},LGV:{kind:"rail",highSpeed:!0},"Voie de service":{kind:"rail",service:!0},Métro:{kind:"subway"},Tramway:{kind:"tram"},"Transport urbain":{kind:"light_rail"},"Funiculaire ou crémaillère":{kind:"funicular"}};static GAUGE_MM={Normale:1435,Etroite:1e3,Étroite:1e3,Large:1668};static NO_ALTITUDE=-1e3;platform;constructor(t={}){this.platform=new Re(t)}static covers(t){return Re.covers((t.south+t.north)/2,(t.west+t.east)/2)}async getRailways(t){return(await this.platform.railways(t)).flatMap((i,n)=>lr.linesOf(i,n))}static linesOf(t,e){const{type:i,coordinates:n}=t.geometry,s=i==="LineString"?[n]:i==="MultiLineString"?n:[],a=lr.BY_NATURE[String(t.properties.nature??"")];if(!a)return[];const r=String(t.properties.cleabs??`ign-rail-${e}`),c=Number(t.properties.nombre_de_voies),h=Number(t.properties.position_par_rapport_au_sol),l=t.properties.cpx_toponyme,u=lr.GAUGE_MM[String(t.properties.largeur??"")]??1435,d=lr.electrificationOf(a.kind,u,t.properties.electrifie);return s.flatMap((f,p)=>{const g=f.map(m=>({lat:m[1],lng:m[0],...m.length>2&&Number.isFinite(m[2])&&m[2]>lr.NO_ALTITUDE?{altitudeM:m[2]}:{}}));return g.length<2?[]:[{id:s.length>1?`${r}-${p}`:r,...typeof l=="string"&&l.length>0?{name:l}:{},kind:a.kind,...a.service?{service:!0}:{},...a.highSpeed?{highSpeed:!0}:{},gaugeMm:u,tracks:Number.isInteger(c)&&c>0?c:1,...d?{electrification:d}:{},level:Number.isFinite(h)?h:0,points:g}]})}static electrificationOf(t,e,i){if(i===!1)return"none";if(i===!0){if(t==="subway")return"third_rail";if(!(t==="funicular"||e<1435))return"overhead"}}}class on{static NEAR_M=15;static ALIGNED_DEG=30;static SAMPLE_M=10;static ROUTES="train|subway|light_rail|tram|monorail";static KINDS="rail|light_rail|subway|tram|narrow_gauge|funicular|preserved";client;constructor(t={}){this.client=new Wn(t)}async named(t,e){if(t.length===0)return[...t];const i=`${e.south},${e.west},${e.north},${e.east}`,n=`[out:json][timeout:120];way["railway"~"^(${on.KINDS})$"](${i})->.w;.w out tags geom;rel(bw.w)["route"~"^(${on.ROUTES})$"];out body;`;return on.apply(t,await this.client.query(n),e)}static apply(t,e,i){const n={lat:(i.north+i.south)/2,lng:(i.east+i.west)/2},s=on.ways(e,n);return s.length===0?[...t]:t.map(a=>{const r=a.points.map(M=>ae(M.lat,M.lng,n.lat,n.lng)),c=new Map,h=new Map,l=new Map;let u=0;const d=s.filter(M=>M.service===!!a.service);for(const M of on.samples(r)){u++;const y=on.waysAt(d,M);if(y.length===0)continue;const[x]=y;x.name&&c.set(x.name,(c.get(x.name)??0)+1),x.voltageV&&h.set(x.voltageV,(h.get(x.voltageV)??0)+1);for(const v of new Set(y.flatMap(w=>w.services)))l.set(v,(l.get(v)??0)+1)}const f=M=>[...M.entries()].sort((y,x)=>x[1]-y[1])[0]?.[0],p=a.name??f(c),g=a.voltageV??(a.electrification==="none"?void 0:f(h)),m=[...l.entries()].filter(([,M])=>M*4>=u).sort((M,y)=>y[1]-M[1]||M[0].localeCompare(y[0])).map(([M])=>M);return{...a,...p?{name:p}:{},...g?{voltageV:g}:{},...m.length>0?{services:m}:{}}})}static serviceOf(t){const e=t.name?.split(" : ")[0].replace(/\s*\([^)]*\)\s*$/,"").trim();return e||[t.network,t.ref].filter(Boolean).join(" ")||void 0}static servicesByWay(t){const e=new Map;for(const i of t.elements??[]){if(i.type!=="relation"||!i.tags)continue;const n=on.serviceOf(i.tags);if(n)for(const s of i.members??[]){if(s.type!=="way"||s.ref===void 0)continue;const a=e.get(s.ref)??new Set;a.add(n),e.set(s.ref,a)}}return e}static voltageOf(t){const e=Number.parseInt((t.voltage??"").split(";")[0],10);return Number.isFinite(e)&&e>0?e:void 0}static ways(t,e){const i=on.servicesByWay(t),n=[];for(const s of t.elements??[]){if(s.type!=="way"||!s.geometry||s.geometry.length<2)continue;const a=s.tags??{},r=on.voltageOf(a);n.push({service:!!a.service||a.usage==="industrial",...a.name?{name:a.name}:{},...r?{voltageV:r}:{},services:[...i.get(s.id??-1)??[]],path:s.geometry.map(c=>ae(c.lat,c.lon,e.lat,e.lng))})}return n}static samples(t){const e=[];for(let i=0;i<t.length-1;i++){const n=Math.hypot(t[i+1].x-t[i].x,t[i+1].z-t[i].z);if(n<1e-6)continue;const s=(t[i+1].x-t[i].x)/n,a=(t[i+1].z-t[i].z)/n;for(let r=on.SAMPLE_M/2;r<n;r+=on.SAMPLE_M)e.push({x:t[i].x+s*r,z:t[i].z+a*r,dx:s,dz:a})}return e}static waysAt(t,e){const i=Math.cos(on.ALIGNED_DEG*Math.PI/180),n=[];for(const s of t){let a;for(let r=0;r<s.path.length-1;r++){const c=s.path[r],h=s.path[r+1],l=h.x-c.x,u=h.z-c.z,d=Math.hypot(l,u);if(d<1e-6||Math.abs((l*e.dx+u*e.dz)/d)<i)continue;const f=Math.max(0,Math.min(1,((e.x-c.x)*l+(e.z-c.z)*u)/(d*d))),p=Math.hypot(e.x-(c.x+l*f),e.z-(c.z+u*f));p<=on.NEAR_M&&(a===void 0||p<a)&&(a=p)}a!==void 0&&n.push({way:s,distance:a})}return n.sort((s,a)=>s.distance-a.distance).map(({way:s})=>s)}}class Zo{attribution="Railways © OpenStreetMap contributors, as surveyed today";contemporary=!0;static KINDS=["rail","light_rail","tram","subway","narrow_gauge","funicular","preserved"];client;constructor(t={}){this.client=new Wn(t)}async getRailways(t){const e=`${t.south},${t.west},${t.north},${t.east}`,i=`[out:json][timeout:25];way["railway"~"^(${Zo.KINDS.join("|")})$"](${e})->.w;.w out tags geom;rel(bw.w)["route"~"^(${on.ROUTES})$"];out body;`;return this.linesFrom(await this.client.query(i))}linesFrom(t){const e=[],i=on.servicesByWay(t);for(const n of t.elements??[]){const s=n.geometry,a=n.tags;if(n.type==="relation"||!a||!s||s.length<2)continue;const r=[...i.get(n.id??-1)??[]].sort(),c=on.voltageOf(a),h=Zo.kindOf(a),l=Number.parseInt((a.gauge??"").split(";")[0],10),u=Number.parseInt(a.tracks??"",10),d=Zo.electrificationOf(a.electrified),f=a.highspeed==="yes"||Number.parseInt(a.maxspeed??"",10)>=250;e.push({id:`osm-rail-${n.id??e.length}`,...a.name?{name:a.name}:{},...r.length>0?{services:r}:{},...c?{voltageV:c}:{},kind:h,...a.service||a.usage==="industrial"?{service:!0}:{},...f?{highSpeed:!0}:{},gaugeMm:Number.isFinite(l)&&l>300?l:a.railway==="narrow_gauge"?1e3:1435,tracks:Number.isFinite(u)&&u>0?u:1,...d?{electrification:d}:{},level:Zo.levelOf(a),points:s.map(p=>({lat:p.lat,lng:p.lon}))})}return e}static kindOf(t){switch(t.railway){case"tram":return"tram";case"subway":return"subway";case"light_rail":return"light_rail";case"funicular":return"funicular";default:return"rail"}}static electrificationOf(t){if(t!==void 0){if(t==="no")return"none";if(t==="contact_line"||t==="yes")return"overhead";if(t==="rail"||t==="4th_rail"||t==="ground-level_power_supply")return"third_rail"}}static levelOf(t){const e=Number.parseInt(t.layer??"",10);return t.tunnel&&t.tunnel!=="no"?Number.isFinite(e)&&e<0?e:-1:t.covered==="yes"&&t.location==="underground"?-1:t.bridge&&t.bridge!=="no"?Number.isFinite(e)&&e>0?e:1:0}}class Jx{constructor(t,e){this.regional=t,this.worldwide=e}attribution="Railways © IGN, BD TOPO, in France; © OpenStreetMap contributors elsewhere, as drawn today";contemporary=!0;async getRailways(t){if(!lr.covers(t))return this.worldwide.getRailways(t);let e;try{if(e=await this.regional.getRailways(t),e.length>0)return e}catch{}try{return await this.worldwide.getRailways(t)}catch(i){if(e)return e;throw i}}}class Wi{constructor(t,e=Date.now){this.railways=t,this.now=e}static CACHE_NAME="rr0-railways";static MAX_AGE_MS=720*3600*1e3;static FORMAT=1;static MAX_STORED=400;static RETRY_AFTER_MS=300*1e3;static asked=new Map;static failedAt=-1/0;get attribution(){return this.railways.attribution}get contemporary(){return this.railways.contemporary}async getRailways(t){const e=Wi.key(t);let i=Wi.asked.get(e)??Wi.containing(t);if(i===void 0){const n=this.recalled(e,t);i={bounds:t,answer:n},Wi.asked.set(e,i),n.catch(()=>Wi.asked.delete(e))}return structuredClone(await i.answer)}static forget(){Wi.asked.clear(),Wi.failedAt=-1/0}static key(t){return`v${Wi.FORMAT}/${[t.north,t.south,t.east,t.west].map(e=>e.toFixed(5)).join("/")}`}static containing(t){for(const e of Wi.asked.values()){const i=e.bounds;if(i.north>=t.north&&i.south<=t.south&&i.east>=t.east&&i.west<=t.west)return e}}async recalled(t,e){const i=await Wi.openCache(),n=Wi.request(t);let s;if(i)try{const r=await i.match(n);if(r){const{savedAt:c,lines:h}=await r.json();if(Array.isArray(h)){if(this.now()-c<Wi.MAX_AGE_MS)return h;s=h}}}catch{}if(this.now()-Wi.failedAt<Wi.RETRY_AFTER_MS){if(s)return s;throw new Error("The railway survey failed a moment ago: not asked again yet")}let a;try{a=await this.railways.getRailways(e)}catch(r){if(Wi.failedAt=this.now(),s)return s;throw r}return i&&Wi.store(i,n,{savedAt:this.now(),lines:a}),a}static async store(t,e,i){try{await t.delete(e),await t.put(e,new Response(JSON.stringify(i),{headers:{"Content-Type":"application/json"}}));const n=await t.keys();for(const s of n.slice(0,Math.max(0,n.length-Wi.MAX_STORED)))await t.delete(s)}catch{}}static async openCache(){try{return typeof caches>"u"?void 0:await caches.open(Wi.CACHE_NAME)}catch{return}}static request(t){const e=typeof location>"u"?"http://localhost":location.origin;return new Request(`${e}/__railways__/${encodeURIComponent(t)}`)}}const Od="https://ufoathome.org/railways/index.json";class Jo{contemporary=!0;attributionRead;fetchImpl;indexUrls;fallback;index;static shared=new Map;sharing;constructor(t={}){this.sharing=!t.fetchImpl,this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.indexUrls=t.indexUrls??Jo.defaultIndexUrls(),this.fallback=t.fallback}get attribution(){return this.attributionRead??this.fallback?.attribution??"Railways © OpenStreetMap contributors"}async getRailways(t){const e=await this.held(t);if(e)return e;if(!this.fallback)return[];const i=await this.fallback.getRailways(t);return this.attributionRead=this.fallback.attribution,i}async held(t){const i=(await this.load().catch(()=>[])).find(({entry:n})=>n.north>=t.north&&n.south<=t.south&&n.east>=t.east&&n.west<=t.west);if(i)try{const n=await this.fetchImpl(new URL(i.entry.file,i.indexUrl).href);if(!n.ok)return;const s=await n.json();return Array.isArray(s?.lines)?(this.attributionRead=s.attribution,s.lines):void 0}catch{return}}load(){if(this.index)return this.index;if(!this.sharing)return this.index=this.fetchFirstAvailable();const t=this.indexUrls.join(`
1741
+ `);let e=Jo.shared.get(t);return e||(e=this.fetchFirstAvailable(),Jo.shared.set(t,e),e.then(i=>{i.length===0&&Jo.shared.delete(t)})),this.index=e}async fetchFirstAvailable(){for(const t of this.indexUrls)try{const e=await this.fetchImpl(t);if(!e.ok)continue;const i=await e.json();if(Array.isArray(i?.entries))return i.entries.map(n=>({entry:n,indexUrl:t}))}catch{}return[]}static defaultIndexUrls(){const t=`?v=${encodeURIComponent("0.152.1")}`,e=typeof location>"u"?void 0:new URL("/railways/index.json",location.href).href;return(e&&e!==Od?[e,Od]:[Od]).map(i=>i+t)}}function Cv(){return{elevation:jx(),imagery:Ov(),roads:Qx(),water:tw(),railways:ew()}}function jx(){return new Yx(new Ae,new Wx)}function Ov(){return new Dv}function Qx(){return new $o({fallback:new qx(new hr,new ar)})}function tw(){return new qo({fallback:new Bn(new Zx(new Fh,new Nr))})}function ew(){return new Jo({fallback:new Wi(new Jx(new lr,new Zo))})}const iw=new Set,uc="show-observer-map",dc="hide-milestones",Hr="minified";class Le extends HTMLElement{static get observedAttributes(){return["src",uc,dc,Hr]}shadow;stageElement;canvas;canvasRenderer;chromeCanvas;chromeRenderer;chromeResizeObserver=typeof ResizeObserver>"u"?void 0:new ResizeObserver(()=>{this.chromeDirty&&this.refresh()});chromeDirty=!1;tooltip;toolbar;issuesBox;issuesButton;issuesPanel;playPauseButton;fullscreenButton;cornerButtons;observerMapButton;referencesButton;tracesButton;tracesShownState=!0;referenceOpacityInput;referencesShownState=!0;accountHidden=!1;referenceViews=new Map;referencesMenu;referenceOpacityTouched=!1;milestonesButton;observerMapPanel;observerMapCanvas;observerMapRenderer;mapZoomInButton;mapZoomOutButton;mapFitButton;observerMapView=new ei;observerMapDrag;suppressObserverMapClick=!1;observerMapImageryTimer;observerPlacing=!1;seekInput;playbackFlash;milestoneMarks;milestoneCaption;timeStartLabel;timeEndLabel;timePill;muteButton;volumeInput;controlsRow;momentsBox;momentsButton;momentsCurrent;momentsMenu;moreButton;controlsRight;seekSegments;seekDot;playerTitleBox;seekPreview;seekPreviewCanvas;seekPreviewTitle;seekPreviewTime;observerPath;observerMapBounds;observerMapImagery;observerMapImageryBounds;observerMapImageryViewWidth=0;observerMapImageryLoading=!1;observerMapImageryCredit;observerMapImageryFailed=!1;creditShownExternally=!1;lookYawDeg=0;lookPitchDeg=0;milestonesShown=!0;currentSighting=cd.create();issues=[];issueCheck=0;sightingAudio=new Ax;soundPreview;player;loopEnabled=!1;playbackBeforeClick;highlightedSourceIds=new Set;paintsShapes=!0;steadyObserver=!1;static LIVE_BODY_MAX_RATE=2;get steadyBody(){return this.steadyObserver||this.player.playbackState!=="playing"||this.player.playbackRate>Le.LIVE_BODY_MAX_RATE}selectionShown=!0;overlayPainter;enableClickToPlay=!0;fullscreenTarget;messages=xv;realDurationMs;realStartMs;showClockTime=!0;handleFullscreenChange=()=>{this.updateFullscreenButton(),this.updateMuteButton(),this.resizeObserverMap()};controlsFitObserver=typeof ResizeObserver>"u"?void 0:new ResizeObserver(()=>this.fitControls());controlsMutations;fitControls(){const t=this.controlsRow,e=t.classList.contains("more-open"),i=()=>t.scrollWidth>t.clientWidth+1,n=!this.momentsMenu.hidden;if(this.momentsMenu.hidden=!0,t.classList.remove("narrow","more-open","nomoments","compact","tiny"),t.clientWidth>0&&i()){t.classList.add("narrow");for(const s of["nomoments","compact","tiny"]){if(!i())break;t.classList.add(s)}e&&t.classList.add("more-open")}this.momentsMenu.hidden=!n,this.updateMoreButton()}setControlsFolded(t){this.controlsRow.classList.toggle("more-open",!t),this.updateMoreButton()}updateMoreButton(){const t=this.controlsRow.classList.contains("more-open");Le.setIcon(this.moreButton,t?Zt.UNFOLDED:Zt.FOLDED);const e=t?this.messages.fewerControls:this.messages.moreControls;this.moreButton.title=e,this.moreButton.setAttribute("aria-label",e),this.moreButton.setAttribute("aria-expanded",String(t))}addControl(t){this.controlsRight.insertBefore(t,this.fullscreenButton.parentElement===this.controlsRight?this.fullscreenButton:null),this.fitControls()}observerMapResizeObserver=typeof ResizeObserver>"u"?void 0:new ResizeObserver(()=>this.resizeObserverMap());resizeObserverMap(){this.observerMapPanel.hidden||(this.sizeObserverMapCanvas(),this.paintObserverMap(this.currentTime))}simulatedFullscreen=!1;styleBeforeSimulatedFullscreen;bodyOverflowBeforeSimulatedFullscreen;handleSimulatedFullscreenKey=t=>{t.key==="Escape"&&this.exitSimulatedFullscreen()};handlePointerMove=t=>{const e=this.canvasPointFromEvent(t),i=e&&this.shapeAt(e.x,e.y),n=this.said.read(i?.shape.title);if(!n){this.tooltip.hidden=!0;return}this.tooltip.textContent=n,this.tooltip.hidden=!1;const s=this.stageElement.getBoundingClientRect();this.tooltip.style.left=`${t.clientX-s.left+12}px`,this.tooltip.style.top=`${t.clientY-s.top+12}px`};handleObserverMapPointerMove=t=>{if(this.dragObserverMap(t))return;const e=this.observerMapTargetFrom(t);if(!e){if(!this.observerPlacing){this.tooltip.hidden=!0,this.observerMapCanvas.style.cursor="grab";return}this.observerMapCanvas.style.cursor="crosshair",this.showObserverMapTooltip(t,this.messages.placeObserverHere);return}this.observerMapCanvas.style.cursor="pointer",this.showObserverMapTooltip(t,e.label)};showObserverMapTooltip(t,e){this.tooltip.textContent=e,this.tooltip.hidden=!1;const i=this.stageElement.getBoundingClientRect();this.tooltip.style.left=`${t.clientX-i.left+12}px`,this.tooltip.style.top=`${t.clientY-i.top+12}px`}handleObserverMapClick=t=>{if(this.suppressObserverMapClick){this.suppressObserverMapClick=!1;return}const e=this.observerMapTargetFrom(t);if(!e){this.observerPlacing&&this.placeObserverFrom(t);return}if(e.kind==="milestone"&&e.t!==void 0){this.player.seek(e.t);return}this.dispatchEvent(new CustomEvent("lookat",{detail:{lat:e.lat,lng:e.lng,kind:e.kind},bubbles:!0,composed:!0}))};observerMapTargetFrom(t){const e=this.observerMapCanvas.getBoundingClientRect();if(!(e.width===0||e.height===0))return this.observerMapRenderer.hitTest((t.clientX-e.left)/e.width*this.observerMapCanvas.width,(t.clientY-e.top)/e.height*this.observerMapCanvas.height)}handlePointerLeave=()=>{this.tooltip.hidden=!0};handleObserverMapPointerDown=t=>{t.button===0&&(this.suppressObserverMapClick=!1,this.observerMapDrag={pointerId:t.pointerId,startX:t.clientX,startY:t.clientY,lastX:t.clientX,lastY:t.clientY,moved:!1})};handleObserverMapPointerUp=t=>{const e=this.observerMapDrag;!e||e.pointerId!==t.pointerId||(this.observerMapDrag=void 0,this.observerMapCanvas.classList.remove("dragging"),e.moved&&(this.suppressObserverMapClick=!0,this.paintObserverMap(this.currentTime),this.observerMapCanvas.hasPointerCapture?.(t.pointerId)&&this.observerMapCanvas.releasePointerCapture(t.pointerId)))};dragObserverMap(t){const e=this.observerMapDrag;if(!e||e.pointerId!==t.pointerId)return!1;if(!e.moved){if(Math.hypot(t.clientX-e.startX,t.clientY-e.startY)<Le.OBSERVER_MAP_DRAG_PX)return!1;e.moved=!0,this.tooltip.hidden=!0,this.observerMapCanvas.classList.add("dragging"),this.observerMapCanvas.setPointerCapture?.(t.pointerId)}const i=this.observerMapCanvas.getBoundingClientRect();return i.width>0&&i.height>0&&(this.observerMapView.panBy((t.clientX-e.lastX)/i.width,(t.clientY-e.lastY)/i.height),this.observerMapViewChanged()),e.lastX=t.clientX,e.lastY=t.clientY,!0}static OBSERVER_MAP_DRAG_PX=4;handleObserverMapWheel=t=>{t.preventDefault();const e=this.observerMapCanvas.getBoundingClientRect();if(e.width===0||e.height===0)return;const i=t.deltaMode===0?t.deltaY:t.deltaY*40;this.zoomObserverMap((t.clientX-e.left)/e.width,(t.clientY-e.top)/e.height,Math.exp(-i*.002))};zoomObserverMap(t,e,i){this.observerMapView.zoomAt(t,e,i),this.observerMapViewChanged()}observerMapViewChanged(){this.mapFitButton.hidden=!this.observerMapView.changed,this.mapZoomInButton.disabled=this.observerMapView.zoomFactor>=ei.MAX_ZOOM,this.mapZoomOutButton.disabled=this.observerMapView.zoomFactor<=ei.MIN_ZOOM,this.paintObserverMap(this.currentTime),this.scheduleObserverMapImagery()}scheduleObserverMapImagery(){this.observerMapImageryTimer===void 0&&(this.observerMapImageryTimer=setTimeout(()=>{this.observerMapImageryTimer=void 0,this.loadObserverMapImagery()},Le.OBSERVER_MAP_IMAGERY_DELAY_MS))}static OBSERVER_MAP_FOLLOW_MARGIN=.1;static OBSERVER_MAP_IMAGERY_DELAY_MS=300;get observerMapViewBounds(){return this.observerMapBounds&&this.observerMapView.boundsWithin(this.observerMapBounds)}placeObserverFrom(t){const e=this.observerMapViewBounds,i=this.observerMapCanvas.getBoundingClientRect();if(!e||i.width===0||i.height===0)return;const n=ei.pointAt(e,(t.clientX-i.left)/i.width,(t.clientY-i.top)/i.height);this.dispatchEvent(new CustomEvent("observerplace",{detail:n,bubbles:!0,composed:!0}))}constructor(){super(),this.shadow=this.attachShadow({mode:"open"});const t=document.createElement("template");t.innerHTML=`<style>${Jy}</style>${Zy}`,this.shadow.appendChild(t.content.cloneNode(!0)),this.stageElement=this.shadow.getElementById("stage"),this.canvas=this.shadow.getElementById("canvas"),this.canvasRenderer=new Sc(this.canvas.getContext("2d")),this.chromeCanvas=this.shadow.getElementById("chrome"),this.tooltip=this.shadow.getElementById("tooltip"),this.toolbar=this.shadow.getElementById("toolbar"),this.issuesBox=this.shadow.getElementById("issues"),this.issuesButton=this.shadow.getElementById("issues-button"),this.issuesPanel=this.shadow.getElementById("issues-panel"),this.issuesButton.addEventListener("click",r=>{r.stopPropagation(),this.issuesPanel.hidden=!this.issuesPanel.hidden,this.issuesButton.setAttribute("aria-expanded",String(!this.issuesPanel.hidden))}),this.playPauseButton=this.shadow.getElementById("play-pause"),this.fullscreenButton=this.shadow.getElementById("fullscreen"),this.cornerButtons=this.shadow.getElementById("corner-buttons"),this.observerMapButton=this.shadow.getElementById("observer-map"),this.referencesButton=this.shadow.getElementById("references"),this.tracesButton=this.shadow.getElementById("traces"),this.referenceOpacityInput=this.shadow.getElementById("reference-opacity"),this.referencesMenu=this.shadow.getElementById("references-menu"),this.milestonesButton=this.shadow.getElementById("milestones"),this.observerMapPanel=this.shadow.getElementById("observer-map-panel"),this.observerMapCanvas=this.shadow.getElementById("observer-map-canvas"),this.observerMapRenderer=new Lr(this.observerMapCanvas.getContext("2d")),this.mapZoomInButton=this.shadow.getElementById("map-zoom-in"),this.mapZoomOutButton=this.shadow.getElementById("map-zoom-out"),this.mapFitButton=this.shadow.getElementById("map-fit"),this.seekInput=this.shadow.getElementById("seek"),this.playbackFlash=this.shadow.getElementById("playback-flash"),this.milestoneMarks=this.shadow.getElementById("milestone-marks"),this.milestoneCaption=this.shadow.getElementById("milestone-caption"),this.timeStartLabel=this.shadow.getElementById("time-start"),this.timeEndLabel=this.shadow.getElementById("time-end"),this.timePill=this.shadow.getElementById("time"),this.muteButton=this.shadow.getElementById("mute"),this.controlsRight=this.shadow.getElementById("controls-right"),this.seekSegments=this.shadow.getElementById("seek-segments"),this.seekDot=this.shadow.getElementById("seek-dot"),this.playerTitleBox=this.shadow.getElementById("player-title"),this.seekPreview=this.shadow.getElementById("seek-preview"),this.seekPreviewCanvas=this.shadow.getElementById("seek-preview-canvas"),this.seekPreviewTitle=this.shadow.getElementById("seek-preview-title"),this.seekPreviewTime=this.shadow.getElementById("seek-preview-time"),this.timePill.addEventListener("click",()=>this.toggleTimeDisplay()),this.timePill.addEventListener("keydown",r=>{r.key!=="Enter"&&r.key!==" "||(r.preventDefault(),this.toggleTimeDisplay())}),this.volumeInput=this.shadow.getElementById("volume"),this.controlsRow=this.shadow.querySelector(".controls"),this.momentsBox=this.shadow.getElementById("moments"),this.momentsButton=this.shadow.getElementById("moments-button"),this.momentsCurrent=this.shadow.getElementById("moments-current"),this.momentsMenu=this.shadow.getElementById("moments-menu"),this.momentsButton.addEventListener("click",()=>this.toggleMomentsMenu()),this.moreButton=this.shadow.getElementById("controls-more"),this.moreButton.addEventListener("click",()=>this.setControlsFolded(this.controlsRow.classList.contains("more-open"))),this.muteButton.addEventListener("click",()=>this.toggleMuted()),this.miniPlayed=this.shadow.getElementById("mini-played"),this.miniRemaining=this.shadow.getElementById("mini-remaining"),this.miniMuteButton=this.shadow.getElementById("mini-mute"),this.miniDot=this.shadow.getElementById("mini-dot"),this.miniScrubTime=this.shadow.getElementById("mini-scrub-time");const e=this.shadow.getElementById("mini-bar"),i=e.querySelector(".mini-track"),n=r=>{const c=i.getBoundingClientRect(),h=this.player.seekableDuration;if(c.width<=0||h<=0)return;const l=Math.min(Math.max((r.clientX-c.left)/c.width,0),1)*h;this.player.seek(l),this.miniScrubTime.textContent=this.formatElapsedAt(l),this.miniScrubTime.style.left=this.miniDot.style.left};let s=!1;e.addEventListener("pointerdown",r=>{r.button===0&&(r.stopPropagation(),e.setPointerCapture(r.pointerId),e.classList.add("scrubbing"),s=this.playRequested,this.pause(),this.miniScrubTime.hidden=!1,n(r))}),e.addEventListener("pointermove",r=>{e.hasPointerCapture(r.pointerId)&&n(r)});const a=r=>{e.classList.contains("scrubbing")&&(e.classList.remove("scrubbing"),e.hasPointerCapture(r.pointerId)&&e.releasePointerCapture(r.pointerId),this.miniScrubTime.hidden=!0,s&&this.play())};e.addEventListener("pointerup",a),e.addEventListener("pointercancel",a),e.addEventListener("click",r=>r.stopPropagation()),this.miniMuteButton.addEventListener("click",r=>{r.stopPropagation(),this.toggleMuted()}),this.stageElement.addEventListener("pointerenter",this.handleMinifiedEnter),this.stageElement.addEventListener("pointerleave",this.handleMinifiedLeave),this.volumeInput.addEventListener("input",()=>{this.setVolume(Number(this.volumeInput.value))}),this.fullscreenTarget=this.stageElement,this.playPauseButton.addEventListener("click",()=>this.togglePlayPause()),this.fullscreenButton.addEventListener("click",()=>this.toggleFullscreen()),this.addEventListener("keydown",this.handleFullscreenKey),this.observerMapButton.addEventListener("click",()=>this.toggleObserverMap()),this.referencesButton.addEventListener("click",()=>this.toggleReferences()),this.tracesButton.addEventListener("click",()=>this.toggleTraces()),this.referenceOpacityInput.addEventListener("input",()=>{this.referenceOpacityTouched=!0,this.dispatchReferenceView()}),this.milestonesButton.addEventListener("click",()=>this.toggleMilestones()),this.observerMapCanvas.addEventListener("pointermove",this.handleObserverMapPointerMove),this.observerMapCanvas.addEventListener("pointerleave",this.handlePointerLeave),this.observerMapCanvas.addEventListener("click",this.handleObserverMapClick),this.observerMapCanvas.addEventListener("pointerdown",this.handleObserverMapPointerDown),this.observerMapCanvas.addEventListener("pointerup",this.handleObserverMapPointerUp),this.observerMapCanvas.addEventListener("pointercancel",this.handleObserverMapPointerUp),this.observerMapCanvas.addEventListener("wheel",this.handleObserverMapWheel,{passive:!1}),this.mapZoomInButton.addEventListener("click",()=>this.zoomObserverMap(.5,.5,2)),this.mapZoomOutButton.addEventListener("click",()=>this.zoomObserverMap(.5,.5,.5)),this.mapFitButton.addEventListener("click",()=>{this.observerMapView.reset(),this.observerMapViewChanged()}),this.seekInput.addEventListener("input",()=>{this.player.seek(this.snapSeekToMark(Number(this.seekInput.value))),this.announceReveal()}),this.seekInput.addEventListener("pointerdown",r=>{this.suspendForScrub(),this.seekSnapArmed=!0,this.nameMarkUnder(r),this.beginTouchScrub(r)}),this.seekInput.addEventListener("pointerup",r=>{this.seekSnapArmed=!1,this.endTouchScrub(r)}),this.seekInput.addEventListener("pointercancel",r=>this.endTouchScrub(r)),this.seekInput.addEventListener("pointermove",r=>{this.nameMarkUnder(r),this.hoverSeek(r),this.touchScrub(r)}),this.seekInput.addEventListener("pointerleave",()=>{this.seekInput.removeAttribute("title"),this.leaveSeek()}),this.seekInput.addEventListener("keydown",this.handleSeekKey),this.stageElement.addEventListener("pointerdown",()=>{this.handlePointerDown(),this.touchedStage()},!0);for(const r of["touchend","click"])this.stageElement.addEventListener(r,()=>this.sightingAudio.resume(),!0);this.stageElement.addEventListener("pointermove",()=>this.touchedStage()),this.canvas.addEventListener("click",r=>{if(!(!this.enableClickToPlay||this.minified)){if(this.tapRevealedOnly){this.tapRevealedOnly=!1;return}r.detail<=1&&(this.playbackBeforeClick={state:this.playbackState,time:this.currentTime}),this.togglePlayPause()}}),this.canvas.addEventListener("dblclick",r=>{!this.enableClickToPlay||this.minified||(r.preventDefault(),this.restorePlayback(),this.toggleFullscreen())}),this.canvas.addEventListener("pointermove",this.handlePointerMove),this.canvas.addEventListener("pointerleave",this.handlePointerLeave),document.addEventListener("fullscreenchange",this.handleFullscreenChange),document.addEventListener("pointerdown",this.handleMomentsDismiss,!0),document.addEventListener("keydown",this.handleMomentsDismiss,!0),document.addEventListener("visibilitychange",this.handleVisibility),window.addEventListener("pagehide",this.handleHidden),document.addEventListener("pointerup",this.handlePointerRelease,!0),document.addEventListener("pointercancel",this.handlePointerRelease,!0),this.observerMapResizeObserver?.observe(this.observerMapPanel),this.chromeResizeObserver?.observe(this.chromeCanvas),this.controlsFitObserver?.observe(this.controlsRow),this.controlsFitObserver?.observe(this.controlsRow.querySelector(".controls-left")),typeof MutationObserver<"u"&&(this.controlsMutations=new MutationObserver(()=>this.fitControls()),this.controlsMutations.observe(this.controlsRight,{attributes:!0,attributeFilter:["hidden"],childList:!0,subtree:!0})),this.hostControls(void 0),this.player=this.createPlayer(),this.updateTimeLabels(),this.updatePlayPauseButton(),this.updateFullscreenButton(),this.updateMuteButton(),this.updateObserverMapButton(),this.updateReferencesButton(),this.updateTracesButton(),this.updateMilestonesButton(),this.refresh()}connectedCallback(){this.saidTexts=void 0,this.loadLocaleMessages();const t=this.getAttribute("src");t&&this.loadFromSrc(t)}disconnectedCallback(){document.removeEventListener("fullscreenchange",this.handleFullscreenChange),document.removeEventListener("pointerdown",this.handleMomentsDismiss,!0),document.removeEventListener("keydown",this.handleMomentsDismiss,!0),document.removeEventListener("visibilitychange",this.handleVisibility),window.removeEventListener("pagehide",this.handleHidden),document.removeEventListener("pointerup",this.handlePointerRelease,!0),document.removeEventListener("pointercancel",this.handlePointerRelease,!0),window.clearTimeout(this.controlsIdleTimer),this.observerMapResizeObserver?.disconnect(),this.chromeResizeObserver?.disconnect(),this.controlsFitObserver?.disconnect(),this.controlsMutations?.disconnect(),this.exitSimulatedFullscreen(),this.sightingAudio.dispose()}attributeChangedCallback(t,e,i){if(t==="src"&&i&&i!==e&&this.isConnected&&this.loadFromSrc(i),t===uc&&this.applyObserverMapDefault(),t===dc&&this.setMilestonesShown(!this.hasAttribute(dc)),t===Hr){const n=this.minified;this.stageElement.classList.toggle("minified",n),n&&e===null&&(this.muted=!0),this.updateStartState()}}get minified(){return this.hasAttribute(Hr)}miniPlayed;miniRemaining;miniMuteButton;handleMinifiedEnter=t=>{!this.minified||t.pointerType==="touch"||(this.minifiedHovered=!0,this.play())};minifiedHovered=!1;handleMinifiedLeave=t=>{!this.minified||t.pointerType==="touch"||(this.minifiedHovered=!1,this.pause(),this.dispatchEvent(new CustomEvent(Lv)))};started=!1;updateStartState(){this.playRequested&&(this.started=!0);const t=!this.started&&this.enableClickToPlay;this.stageElement.classList.toggle("unstarted",t),t&&!this.minified?this.canvas.title=this.messages.clickToPlay:this.canvas.removeAttribute("title")}async loadFromSrc(t){this.sightingData=await Lh.recording(t)}get sightingData(){return Tx(this.currentSighting)}set sightingData(t){this.player.stop(),this.soundPreview=void 0,this.sightingAudio.silence(),this.currentSighting=Ix(t),this.observerMapFrozenSource&&(this.observerMapFrozen=this.observerMapFrozenSource(this.currentSighting.frozen)),this.issuesPanel.hidden=!0,this.issuesButton.setAttribute("aria-expanded","false"),this.reportIssues(t,this.currentSighting),this.observerMapView.reset(),this.mapFitButton.hidden=!0,this.observerMapAsked=!1,this.player=this.createPlayer(),this.started=!1,this.syncPlayerTitle(),this.updateTimeLabels(),this.updatePlayPauseButton(),this.refresh(),this.applyObserverMapDefault(),this.minified&&this.minifiedHovered&&this.play()}set playerTitle(t){this.titleOverride=t,this.syncPlayerTitle()}titleOverride;syncPlayerTitle(){const t=this.said.read(this.titleOverride)??this.said.read(this.currentSighting.observer?.title)??"";this.playerTitleBox.textContent=t,this.playerTitleBox.hidden=t===""}get recordingIssues(){return this.issues}async reportIssues(t,e){const i=++this.issueCheck;let n=[];try{const{default:s}=await Mi(async()=>{const{default:a}=await import("./sightingSchema-Bc1JhWrZ.js");return{default:a}},[],import.meta.url);n=new Rs(s).issues(t)}catch{}i===this.issueCheck&&(this.issues=[...n,...e.loadIssues],bc.warn(this.issues,e.id),this.renderIssues(),this.dispatchEvent(new CustomEvent(nw,{detail:{issues:this.issues},bubbles:!0,composed:!0})))}renderIssues(){const t=this.issues.length;this.issuesBox.hidden=t===0,this.shadow.getElementById("issues-count").textContent=String(t);const e=this.messages.recordingIssues.replace("{count}",String(t));this.issuesButton.title=e,this.issuesButton.setAttribute("aria-label",e),this.shadow.getElementById("issues-title").textContent=e,this.shadow.getElementById("issues-list").replaceChildren(...this.issues.map(i=>{const n=document.createElement("li");return n.textContent=bc.text(i,this.messages.issueTemplates),n}))}get sighting(){return this.currentSighting}previewSound(t){this.soundPreview=t,this.sightingAudio.resume(),this.sightingAudio.setSound(t)}stopSoundPreview(){this.soundPreview=void 0,this.sightingAudio.silence()}get canvasElement(){return this.canvas}get renderer(){return this.canvasRenderer}get currentTime(){return this.player.time}set currentTime(t){this.player.seek(t)}get seekableDuration(){return this.player.seekableDuration}get autoReplayEnabled(){return this.loopEnabled}set autoReplayEnabled(t){t!==this.loopEnabled&&this.toggleLoop()}play(){if(!(this.player.seekableDuration<=0||this.playbackState==="playing")){if(this.clockHeld){this.playAfterHold=!0,this.announcePlayRequest();return}this.togglePlayPause()}}get playRequested(){return this.playbackState==="playing"||this.playAfterHold}announcePlayRequest(){this.announceReveal(),this.dispatchEvent(new CustomEvent("playrequest"))}announceReveal(){this.started=!0,this.updateStartState(),this.dispatchEvent(new CustomEvent("revealrequest"))}clockHeld=!1;playAfterHold=!1;holdClock(t){if(t!==this.clockHeld){if(this.clockHeld=t,t){if(this.playbackState!=="playing")return;this.playAfterHold=!0,this.player.pause(),this.soundPreview=void 0,this.sightingAudio.silence(),this.refresh(),this.updatePlayPauseButton();return}this.playAfterHold&&(this.playAfterHold=!1,!(this.player.seekableDuration<=0||this.playbackState==="playing")&&(this.sightingAudio.resume(),this.player.play(),this.updatePlayPauseButton()))}}pause(){this.playAfterHold=!1,this.playbackState==="playing"&&this.togglePlayPause()}get positionLabel(){return this.timeStartLabel.textContent??""}get durationLabel(){return this.timeEndLabel.textContent??""}get showingClockTime(){return this.canShowClockTime}get canSwitchTimeDisplay(){return this.realStartMs!==void 0}toggleTimeDisplay(){this.canSwitchTimeDisplay&&(this.showClockTime=!this.showClockTime,this.updateTimeLabels(),this.updateTimeLabelTitles(),this.dispatchEvent(new CustomEvent("timedisplaychange",{bubbles:!0,composed:!0})))}get canShowClockTime(){return this.realStartMs!==void 0&&this.showClockTime}set showToolbar(t){this.toolbar.classList.toggle("hidden",!t),t?this.controlsRight.appendChild(this.fullscreenButton):this.cornerButtons.appendChild(this.fullscreenButton)}get playbackState(){return this.player.playbackState}get selectedSourceIds(){return this.highlightedSourceIds}get durationSeconds(){return this.currentSighting.event.durationSeconds}set durationSeconds(t){this.currentSighting.event.durationSeconds=t,this.updateTimeLabels(),this.refresh(),this.updatePlayPauseButton()}set selectedSourceIds(t){const e=new Set(t);e.size===this.highlightedSourceIds.size&&[...e].every(n=>this.highlightedSourceIds.has(n))||(this.highlightedSourceIds=e,this.refresh())}hasVisibleShapeAt(t,e){return this.shapeAt(t,e)!==void 0}refresh(){this.applyFrameFormat(),this.updateMuteButton(),this.updateTimeLabels(),this.seekInput.max=String(this.player.seekableDuration),this.refreshMilestoneMarks(),this.updateMilestonesButton(),this.updateObserverMap(),this.updateReferences(),this.updateTracesButton(),this.player.seek(this.player.time)}repaintOverlay(){this.quietFrame=!0;try{this.player.seek(this.player.time)}finally{this.quietFrame=!1}}quietFrame=!1;hostControls(t){const e=[this.milestonesButton,this.referencesButton,this.referenceOpacityInput,this.tracesButton,this.observerMapButton];if(t)for(const i of e)t.appendChild(i);else{const i=this.fullscreenButton.parentElement===this.controlsRight?this.fullscreenButton:null;for(const n of e)this.controlsRight.insertBefore(n,i)}}get referencesShown(){return this.referencesShownState}get referenceOpacity(){return Number(this.referenceOpacityInput.value)}get severalReferences(){return this.currentSighting.references.length>1}toggleReferences(){if(this.severalReferences){this.toggleReferencesMenu();return}this.referencesShownState=!this.referencesShownState,this.updateReferencesButton(),this.dispatchReferenceView()}updateReferences(){const t=this.currentSighting.references;!this.referenceOpacityTouched&&t.length>0&&(this.referenceOpacityInput.value=String(t[0].opacity));for(const e of[...this.referenceViews.keys()])t.some(i=>i.id===e)||this.referenceViews.delete(e);this.severalReferences?this.referencesMenu.hidden||this.renderReferencesMenu():this.closeReferencesMenu(),this.updateReferencesButton(),this.severalReferences&&this.dispatchReferenceView()}viewOfReference(t){let e=this.referenceViews.get(t.id);return e||(e={shown:!0,opacity:t.opacity},this.referenceViews.set(t.id,e)),e}toggleReferencesMenu(){this.referencesMenu.hidden?this.openReferencesMenu():this.closeReferencesMenu()}openReferencesMenu(){this.renderReferencesMenu(),this.referencesMenu.hidden=!1,this.placeReferencesMenu(),this.referencesButton.setAttribute("aria-expanded","true"),document.addEventListener("pointerdown",this.handleReferencesMenuOutside,!0),document.addEventListener("keydown",this.handleReferencesMenuKey,!0)}closeReferencesMenu(){this.referencesMenu.hidden||(this.referencesMenu.hidden=!0,this.referencesButton.setAttribute("aria-expanded","false"),document.removeEventListener("pointerdown",this.handleReferencesMenuOutside,!0),document.removeEventListener("keydown",this.handleReferencesMenuKey,!0))}handleReferencesMenuOutside=t=>{const e=t.composedPath();e.includes(this.referencesMenu)||e.includes(this.referencesButton)||this.closeReferencesMenu()};handleReferencesMenuKey=t=>{t.key==="Escape"&&(this.closeReferencesMenu(),this.referencesButton.focus())};placeReferencesMenu(){const t=this.referencesButton.getBoundingClientRect(),e=this.referencesMenu,i=4;e.style.bottom=`${Math.max(i,window.innerHeight-t.top+i)}px`,e.style.top="auto";const n=e.getBoundingClientRect().width;e.style.left=`${Math.max(i,Math.min(t.left,window.innerWidth-n-i))}px`}renderReferencesMenu(){const t=this.currentSighting.references.map(e=>{const i=this.viewOfReference(e),n=this.said.read(e.title)??e.id,s=document.createElement("div");s.className="reference-row";const a=document.createElement("label"),r=document.createElement("input");r.type="checkbox",r.checked=i.shown;const c=document.createElement("span");c.textContent=n,c.title=n,a.append(r,c);const h=document.createElement("input");return h.type="range",h.min="0",h.max="1",h.step="0.05",h.value=String(i.opacity),h.title=this.messages.referenceOpacity,h.setAttribute("aria-label",`${this.messages.referenceOpacity}: ${n}`),h.disabled=!i.shown,r.addEventListener("change",()=>{i.shown=r.checked,h.disabled=!i.shown,this.updateReferencesButton(),this.dispatchReferenceView()}),h.addEventListener("input",()=>{i.opacity=Number(h.value),this.dispatchReferenceView()}),s.append(a,h),s});this.referencesMenu.setAttribute("aria-label",this.messages.referencesMenu),this.referencesMenu.replaceChildren(...t)}updateReferencesButton(){const t=this.currentSighting.references.length>0,e=this.severalReferences,i=e?this.currentSighting.references.some(s=>this.viewOfReference(s).shown):this.referencesShownState;this.referencesButton.hidden=!t,this.referenceOpacityInput.hidden=!t||!this.referencesShownState||e,this.referencesButton.setAttribute("aria-pressed",String(i)),e?this.referencesButton.setAttribute("aria-haspopup","true"):this.referencesButton.removeAttribute("aria-haspopup"),Le.setIcon(this.referencesButton,i?Zt.PICTURES_ON:Zt.PICTURES_OFF);const n=e?this.messages.referencesMenu:this.referencesShownState?this.messages.hideReferences:this.messages.showReferences;this.referencesButton.title=n,this.referencesButton.setAttribute("aria-label",n),this.referenceOpacityInput.title=this.messages.referenceOpacity,this.referenceOpacityInput.setAttribute("aria-label",this.messages.referenceOpacity)}get tracesShown(){return this.tracesShownState}toggleTraces(){this.tracesShownState=!this.tracesShownState,this.updateTracesButton(),this.updateObserverMap(),this.dispatchEvent(new CustomEvent("traceview",{detail:{shown:this.tracesShown}}))}updateTracesButton(){this.tracesButton.hidden=this.currentSighting.traces.length===0,this.tracesButton.setAttribute("aria-pressed",String(this.tracesShownState)),Le.setIcon(this.tracesButton,this.tracesShownState?Zt.TRACES_ON:Zt.TRACES_OFF);const t=this.tracesShownState?this.messages.hideTraces:this.messages.showTraces;this.tracesButton.title=t,this.tracesButton.setAttribute("aria-label",t)}dispatchReferenceView(){const t=this.severalReferences?Object.fromEntries(this.currentSighting.references.map(e=>[e.id,{...this.viewOfReference(e)}])):void 0;this.dispatchEvent(new CustomEvent("referenceview",{detail:{shown:this.referencesShown,opacity:this.referenceOpacity,views:t}}))}refreshMilestoneMarks(){const t=this.player.seekableDuration,e=t>0?fh(this.sighting.milestones):[];this.milestoneMarks.replaceChildren(...e.map(i=>{const n=document.createElement("button");n.type="button",n.className="milestone-mark",n.style.left=`${Math.min(Math.max(i.t/t,0),1)*100}%`;const s=this.said.read(i.label)??"",a=this.said.read(i.note),r=a?`${s} — ${a}`:s;return n.title=r,n.setAttribute("aria-label",r),n.dataset.t=String(i.t),n.addEventListener("click",()=>this.player.seek(i.t)),n})),this.refreshSeekSegments(t,e.map(i=>i.t)),this.refreshMomentsPicker(e)}refreshMomentsPicker(t){const e=this.milestonesShown&&t.length>0;this.momentsBox.hidden=!e,this.closeMomentsMenu(),this.momentsMenu.replaceChildren(...t.map(i=>{const n=document.createElement("li"),s=document.createElement("button");s.type="button",s.dataset.t=String(i.t);const a=this.said.read(i.label)??"",r=this.said.read(i.note);return s.textContent=r?`${a} — ${r}`:a,s.addEventListener("click",()=>{this.player.seek(i.t),this.closeMomentsMenu()}),n.appendChild(s),n})),this.momentsButton.title=this.messages.moments,this.showCurrentMoment(void 0)}showCurrentMoment(t){const i=(t?this.said.read(t.label)??"":"")||this.messages.moments;this.momentsCurrent.textContent!==i&&(this.momentsCurrent.textContent=i);for(const n of this.momentsMenu.querySelectorAll("button")){const s=t!==void 0&&Number(n.dataset.t)===t.t;n.getAttribute("aria-current")==="true"!==s&&n.setAttribute("aria-current",String(s))}}toggleMomentsMenu(){this.momentsMenu.hidden?(this.momentsMenu.hidden=!1,this.momentsButton.setAttribute("aria-expanded","true")):this.closeMomentsMenu()}closeMomentsMenu(){this.momentsMenu.hidden=!0,this.momentsButton.setAttribute("aria-expanded","false")}handleMomentsDismiss=t=>{if(!this.momentsMenu.hidden){if(t instanceof KeyboardEvent){t.key==="Escape"&&this.closeMomentsMenu();return}t.composedPath().some(e=>e===this.momentsMenu||e===this.momentsButton)||this.closeMomentsMenu()}};seekSegmentList=[];refreshSeekSegments(t,e){const n=[0,...this.milestonesShown&&t>0?[...new Set(e.filter(a=>a>0&&a<t))].sort((a,r)=>a-r):[],Math.max(t,0)];this.seekSegmentList=[];const s=[];for(let a=0;a<n.length-1;a++){const r=document.createElement("div");r.className="seek-segment",r.style.flexGrow=String(Math.max(n[a+1]-n[a],1));const c=document.createElement("i");c.className="seek-hover";const h=document.createElement("i");h.className="seek-played",r.append(c,h),s.push(r),this.seekSegmentList.push({start:n[a],end:n[a+1],element:r,played:h,hover:c})}this.seekSegments.replaceChildren(...s),this.paintSeekProgress(this.player.time)}static fillOf(t,e){const i=t.end-t.start,n=i>0?(e-t.start)/i:e>=t.end?1:0;return`${Math.min(Math.max(n,0),1)*100}%`}paintMiniProgress(t){const e=this.player.seekableDuration,i=`${e>0?Math.min(Math.max(t/e,0),1)*100:0}%`;this.miniPlayed.style.width=i,this.miniDot.style.left=i,this.miniRemaining.textContent=this.formatRemaining(t)}miniDot;miniScrubTime;paintSeekProgress(t){for(const i of this.seekSegmentList)i.played.style.width=Le.fillOf(i,t);const e=this.player.seekableDuration;this.seekDot.style.left=`${e>0?Math.min(Math.max(t/e,0),1)*100:0}%`}hoverSeek(t){const e=this.seekInput.getBoundingClientRect(),i=this.player.seekableDuration;if(e.width<=0||i<=0)return;const n=Math.min(Math.max((t.clientX-e.left)/e.width,0),1),s=n*i,a=this.seekSegmentList.length-1;this.seekSegmentList.forEach((f,p)=>{f.hover.style.width=Le.fillOf(f,s),f.element.classList.toggle("hovered",s>=f.start&&(s<f.end||p===a))});const r=this.milestonesShown?this.sighting.milestones:[],c=r.length>0?Rd(r,s):void 0,h=c?this.said.read(c.label)??"":"",l=c?this.said.read(c.note):void 0,u=l?`${h} — ${l}`:h;this.seekPreviewTitle.textContent=u,this.seekPreviewTime.textContent=this.formatPosition(s),this.seekPreview.hidden=!1;const d=this.seekPreview.offsetWidth;this.seekPreview.style.left=`${Math.min(Math.max(n*e.width-d/2,0),Math.max(e.width-d,0))}px`,this.paintSeekPreview(s)}leaveSeek(){for(const t of this.seekSegmentList)t.hover.style.width="0",t.element.classList.remove("hovered");this.seekPreview.hidden=!0}seekPreviewPainter;paintSeekPreview(t){const e=this.seekPreviewPainter;this.seekPreviewCanvas.hidden=e===void 0,e?.(t,this.seekPreviewCanvas)}paintChrome(t){const e=this.chromeCanvas.getContext("2d"),i=this.overlayPainter!==void 0||this.selectionShown;if(!i&&!this.chromeDirty)return;const n=this.chromeCanvas.clientWidth,s=this.chromeCanvas.clientHeight;if(!e||typeof e.setTransform!="function"||n===0||s===0){t(this.canvasRenderer);return}const a=window.devicePixelRatio||1,r=Math.max(1,Math.round(n*a)),c=Math.max(1,Math.round(s*a));this.chromeCanvas.width!==r&&(this.chromeCanvas.width=r),this.chromeCanvas.height!==c&&(this.chromeCanvas.height=c),e.setTransform(1,0,0,1,0,0),e.clearRect(0,0,r,c),this.chromeDirty=!1,i&&(e.setTransform(r/this.canvas.width,0,0,c/this.canvas.height,0,0),this.chromeRenderer??=new Sc(e),this.chromeDirty=!0,t(this.chromeRenderer))}chromeDraw;repaintChrome(){this.chromeDraw&&this.overlayPainter&&this.paintChrome(this.chromeDraw)}scrubbingPointer;beginTouchScrub(t){if(t.pointerType!=="mouse"){this.scrubbingPointer=t.pointerId;try{this.seekInput.setPointerCapture(t.pointerId)}catch{}this.seekToPointer(t)}}touchScrub(t){t.pointerId===this.scrubbingPointer&&this.seekToPointer(t)}endTouchScrub(t){t.pointerId===this.scrubbingPointer&&(this.scrubbingPointer=void 0,this.seekToPointer(t))}seekToPointer(t){const e=this.seekInput.getBoundingClientRect(),i=this.player.seekableDuration;if(e.width<=0||i<=0)return;const n=Math.min(Math.max((t.clientX-e.left)/e.width,0),1);this.player.seek(this.snapSeekToMark(n*i))}seekSnapArmed=!1;static MARK_SNAP_PX=6;markNear(t){const e=this.player.seekableDuration,i=this.seekInput.getBoundingClientRect().width;if(e<=0||i<=0)return;const n=Le.MARK_SNAP_PX/i*e;let s;for(const a of this.milestoneMarks.children){const r=Number(a.dataset.t);Math.abs(r-t)>n||(!s||Math.abs(r-t)<Math.abs(s.t-t))&&(s={t:r,name:a.title})}return s}snapSeekToMark(t){return this.seekSnapArmed?(this.seekSnapArmed=!1,this.markNear(t)?.t??t):t}nameMarkUnder(t){const e=this.seekInput.getBoundingClientRect(),i=this.player.seekableDuration;if(e.width<=0||i<=0)return;const n=(t.clientX-e.left)/e.width*i,s=this.markNear(n);s?this.seekInput.title=s.name:this.seekInput.removeAttribute("title")}showMilestoneAt(t){const e=this.milestonesShown&&this.sighting.milestones.length>0?Rd(this.sighting.milestones,t):void 0;if(this.milestoneCaption.hidden=e===void 0,this.showCurrentMoment(e),!e)return;const i=document.createElement("b");i.textContent=this.said.read(e.label)??"";const n=this.said.read(e.note),s=n?` — ${n}`:"";this.milestoneCaption.replaceChildren(i,document.createTextNode(s))}exposureInstants(t){const e=this.exposureTimes(t),i=1/e.length;return e.map(n=>({shapes:this.shapesAt(n),share:i}))}exposureTimes(t=this.currentTime){const e=Ps.windowEndingAt(t,this.currentSighting.exposure??0);if(e.ms<Le.SHORTEST_VISIBLE_EXPOSURE_MS)return[t];const i=Math.min(Le.MAX_EXPOSURE_STEPS,Math.max(2,Math.round(e.ms/Le.SHORTEST_VISIBLE_EXPOSURE_MS))),n=Math.ceil(this.travelPxOver(e.fromMs,e.ms)/Le.EXPOSURE_STEP_PX),s=Math.min(Le.MAX_TRAVEL_STEPS,Math.max(i,n)),a=[];for(let r=0;r<s;r++)a.push(e.fromMs+e.ms*r/(s-1));return a}travelPxOver(t,e){const i=this.shapesAt(t),n=this.shapesAt(t+e);let s=0;for(const[a,r]of i){const c=n.get(a);if(!c)continue;const h=c.bounds.x+c.bounds.width/2-(r.bounds.x+r.bounds.width/2),l=c.bounds.y+c.bounds.height/2-(r.bounds.y+r.bounds.height/2);s=Math.max(s,Math.hypot(h,l))}return s}shapeAt(t,e,i){if(!this.accountHidden)for(const n of this.exposureTimes()){const s=this.currentSighting.timeline.hitTest(n,t,e,i);if(s)return s}}shapesAt(t){const e=new Map;for(const i of this.currentSighting.timeline.sourceIds){const n=this.currentSighting.timeline.getInterpolatedShapeAt(t,i);n&&e.set(i,n)}return e}static SHORTEST_VISIBLE_EXPOSURE_MS=20;static MAX_EXPOSURE_STEPS=48;static EXPOSURE_STEP_PX=2;static MAX_TRAVEL_STEPS=320;applyFrameFormat(){const t=Ii.frameWidthPx(this.currentSighting.instrument,this.canvas.height);if(this.canvas.width===t)return;this.canvas.width=t,this.canvas.parentElement?.style.setProperty("--frame-aspect",`${t} / ${this.canvas.height}`)}canvasPointFromEvent(t){const e=this.canvas.getBoundingClientRect();if(!(e.width===0||e.height===0))return{x:(t.clientX-e.left)/e.width*this.canvas.width,y:(t.clientY-e.top)/e.height*this.canvas.height}}onFrame(t,e){this.canvasRenderer.clear(this.canvas.width,this.canvas.height);const i=this.playbackState!=="playing"?this.highlightedSourceIds:iw;this.canvasRenderer.setStarPoints(Ii.starPointsOf(this.sighting.instrument,Fe(this.sighting,t)?.fNumber));const n=(Fe(this.sighting,t)?.rollDeg??0)+this.gaitAt(t).rollDeg;this.canvasRenderer.setRoll(n*Math.PI/180);const s=this.exposureInstants(t),a=this.frameShift;if(this.paintsShapes)for(const c of s)for(const[,h]of c.shapes){const l=c.share,u=l===1?h:{...h,transparency:1-(1-h.transparency)*l};this.canvasRenderer.paintShape(this.shifted(u,a))}for(const[c,h]of s[0].shapes)!this.selectionShown||!i.has(c)||(this.paintsShapes?i.size===1?this.canvasRenderer.paintShape({...h,selected:!0}):this.canvasRenderer.paintMemberOutline(h):this.canvasRenderer.paintSelectionOnly(this.shifted(h,a)));const r=this.selectionShown&&i.size>1?ss.groupBoundsFor([...e].filter(([c])=>i.has(c)).map(([,c])=>c.bounds)):void 0;this.chromeDraw=c=>{r&&c.paintGroupHandles(r),this.overlayPainter?.(c)},this.paintChrome(this.chromeDraw),this.mapShapeBounds=s.flatMap(c=>[...c.shapes.values()].filter(h=>h.transparency<1).map(h=>this.shifted(h,a).bounds)),this.keepObserverMapClear(),this.seekInput.value=String(t),this.paintSeekProgress(t),this.minified&&this.paintMiniProgress(t),this.timeStartLabel.textContent=this.formatPosition(t),this.showMilestoneAt(t),this.paintObserverMap(t),this.playbackState==="playing"?(this.soundPreview=void 0,this.sightingAudio.setSound(Mx(this.currentSighting,t))):this.soundPreview?this.sightingAudio.setSound(this.soundPreview):this.sightingAudio.silence(),this.updatePlayPauseButton(),!this.quietFrame&&this.dispatchEvent(new CustomEvent("timeupdate",{detail:{time:t}}))}shifted(t,e){return e.x===0&&e.y===0?t:{...t,bounds:{...t.bounds,x:t.bounds.x+e.x,y:t.bounds.y+e.y}}}createPlayer(){const t=new vx(this.currentSighting.timeline,(e,i)=>this.onFrame(e,i));return t.loop=this.loopEnabled,t.onEnded=()=>{this.updatePlayPauseButton(),this.dispatchEvent(new CustomEvent("ended",{bubbles:!0,composed:!0}))},t}static SEEK_KEY_STEP_MS=5e3;handleFullscreenKey=t=>{t.key.toLowerCase()!=="f"||t.altKey||t.ctrlKey||t.metaKey||!this.enableClickToPlay||t.composedPath().some(i=>i instanceof HTMLElement&&(i.isContentEditable||["INPUT","TEXTAREA","SELECT"].includes(i.tagName)&&i.type!=="range"))||(t.preventDefault(),this.toggleFullscreen())};handleSeekKey=t=>{if(t.altKey||t.ctrlKey||t.metaKey)return;const e=t.key==="ArrowLeft"?-1:t.key==="ArrowRight"?1:0;if(e){t.preventDefault();const i=this.player.seekableDuration;this.player.seek(Math.min(i,Math.max(0,this.player.time+e*Le.SEEK_KEY_STEP_MS)))}else t.key===" "&&(t.preventDefault(),this.togglePlayPause())};togglePlayPause(){if(!(this.player.seekableDuration<=0)){if(this.player.playbackState==="playing")this.player.pause(),this.soundPreview=void 0,this.sightingAudio.silence(),this.refresh();else if(this.clockHeld){this.playAfterHold=!this.playAfterHold,this.playAfterHold&&this.announcePlayRequest();return}else this.announcePlayRequest(),this.sightingAudio.resume(),this.player.play();this.updatePlayPauseButton(),this.flashPlayback()}}flashPlayback(){const t=this.playbackFlash;t.innerHTML=this.player.playbackState==="playing"?Zt.PLAY:Zt.PAUSE,t.classList.remove("flashing"),t.offsetWidth,t.classList.add("flashing")}static icons=new WeakMap;static setIcon(t,e){Le.icons.get(t)!==e&&(Le.icons.set(t,e),t.innerHTML=e)}set captionHeld(t){this.stageElement.classList.toggle("caption-held",t)}set controlsHeld(t){this.stageElement.classList.toggle("controls-held",t)}static CONTROLS_IDLE_MS=3e3;controlsIdleTimer;wasPlaying=!1;quietControlsValue=!1;get quietControls(){return this.quietControlsValue}set quietControls(t){this.quietControlsValue=t,this.stageElement.classList.toggle("quiet",t)}tapRevealedOnly=!1;get hoverless(){return typeof matchMedia=="function"&&matchMedia("(hover: none)").matches}touchedStage(){if(!this.hoverless)return;this.player.playbackState==="playing"&&!this.stageElement.classList.contains("touched")&&(this.tapRevealedOnly=!0),this.revealControls()}pointerHeld=!1;handlePointerDown=()=>{this.pointerHeld=!0};resumeAfterScrub=!1;suspendForScrub(){this.player.playbackState==="playing"&&(this.resumeAfterScrub=!0,this.stopPlaying())}stopPlaying(){this.player.pause(),this.soundPreview=void 0,this.sightingAudio.silence(),this.refresh(),this.updatePlayPauseButton()}resumeFromScrub(){this.resumeAfterScrub&&(this.resumeAfterScrub=!1,this.sightingAudio.resume(),this.player.play(),this.updatePlayPauseButton())}handleHidden=()=>{this.player.playbackState==="playing"&&this.stopPlaying(),this.resumeAfterScrub=!1};handleVisibility=()=>{document.visibilityState==="hidden"&&this.handleHidden()};handlePointerRelease=()=>{this.resumeAfterScrub&&window.setTimeout(()=>this.resumeFromScrub(),0),this.pointerHeld&&(this.pointerHeld=!1,this.hoverless&&this.stageElement.classList.contains("touched")&&this.revealControls())};revealControls(){this.stageElement.classList.add("touched"),window.clearTimeout(this.controlsIdleTimer),this.player.playbackState==="playing"&&(this.pointerHeld||!this.momentsMenu.hidden||(this.controlsIdleTimer=window.setTimeout(()=>{this.stageElement.classList.remove("touched"),this.tapRevealedOnly=!1},Le.CONTROLS_IDLE_MS)))}updatePlayPauseButton(){const t=this.player.playbackState==="playing";this.stageElement.classList.toggle("paused",!t),t!==this.wasPlaying&&t&&this.hoverless&&(!this.quietControlsValue||this.stageElement.classList.contains("touched"))&&this.revealControls(),this.wasPlaying=t,this.updateStartState(),Le.setIcon(this.playPauseButton,t?Zt.PAUSE:Zt.PLAY);const e=this.player.seekableDuration>0;this.playPauseButton.disabled=!e;const i=e?t?this.messages.pause:this.messages.play:this.messages.noDuration;this.playPauseButton.title=i,this.playPauseButton.setAttribute("aria-label",i)}toggleLoop(){this.loopEnabled=!this.loopEnabled,this.player.loop=this.loopEnabled}restorePlayback(){const t=this.playbackBeforeClick;t&&(this.currentTime=t.time,t.state==="playing"?this.play():this.pause())}get canUseNativeFullscreen(){return typeof this.fullscreenTarget.requestFullscreen=="function"&&document.fullscreenEnabled}toggleFullscreen(){if(!this.canUseNativeFullscreen){this.simulatedFullscreen?this.exitSimulatedFullscreen():this.enterSimulatedFullscreen();return}document.fullscreenElement?document.exitFullscreen():this.fullscreenTarget.requestFullscreen().catch(t=>{console.error("<rr0-ufo>: requestFullscreen() failed —",t)})}enterSimulatedFullscreen(){const t=this.fullscreenTarget;this.styleBeforeSimulatedFullscreen=t.getAttribute("style")??"",this.bodyOverflowBeforeSimulatedFullscreen=document.body.style.overflow;const e=t.style;e.setProperty("position","fixed"),e.setProperty("inset","0"),e.setProperty("margin","0"),e.setProperty("max-width","none"),e.setProperty("max-height","none"),e.setProperty("aspect-ratio","auto"),e.setProperty("z-index","2147483647"),e.setProperty("background","#000"),e.setProperty("width","100vw"),e.setProperty("width","100dvw"),e.setProperty("height","100vh"),e.setProperty("height","100dvh"),document.body.style.overflow="hidden",this.simulatedFullscreen=!0,document.addEventListener("keydown",this.handleSimulatedFullscreenKey),this.updateFullscreenButton(),this.updateMuteButton()}exitSimulatedFullscreen(){if(!this.simulatedFullscreen)return;const t=this.fullscreenTarget;this.styleBeforeSimulatedFullscreen?t.setAttribute("style",this.styleBeforeSimulatedFullscreen):t.removeAttribute("style"),document.body.style.overflow=this.bodyOverflowBeforeSimulatedFullscreen??"",this.simulatedFullscreen=!1,document.removeEventListener("keydown",this.handleSimulatedFullscreenKey),this.updateFullscreenButton(),this.updateMuteButton()}toggleObserverMap(){const t=this.observerMapPanel.hidden;this.observerMapAsked=t,this.setObserverMapOpen(t),this.keepObserverMapClear(),this.dispatchEvent(new CustomEvent("observermapchange",{bubbles:!0,composed:!0,detail:{open:t}}))}get observerMapOpen(){return!this.observerMapPanel.hidden}get milestonesVisible(){return this.milestonesShown}observerMapAsked=!1;applyObserverMapDefault(){const t=this.getAttribute(uc),e=t===null?this.sighting.observerMap??this.observerPath?.travels===!0:t!=="false";this.setObserverMapOpen(e&&this.observerPath!==void 0)}setObserverMapOpen(t){this.observerMapPanel.hidden=!t,this.observerMapPanel.removeAttribute("title"),this.observerMapButton.setAttribute("aria-pressed",String(t)),this.updateObserverMapButton(),t&&(this.sizeObserverMapCanvas(),this.loadObserverMapImagery(),this.paintObserverMap(this.currentTime))}updateObserverMapButton(){const t=!this.observerMapPanel.hidden;Le.setIcon(this.observerMapButton,t?Zt.MAP_ON:Zt.MAP_OFF);const e=t?this.messages.hideObserverMap:this.messages.showObserverMap;this.observerMapButton.title=e,this.observerMapButton.setAttribute("aria-label",e);const i=[[this.mapZoomInButton,this.messages.zoomMapIn],[this.mapZoomOutButton,this.messages.zoomMapOut],[this.mapFitButton,this.messages.fitMap]];for(const[n,s]of i)n.title=s,n.setAttribute("aria-label",s)}updateObserverMap(){const t=this.observerPath!==void 0;if(this.observerPath=hc.of(this.currentSighting),this.observerMapButton.hidden=this.observerPath===void 0,!t&&this.observerPath&&this.applyObserverMapDefault(),!this.observerPath){this.setObserverMapOpen(!1),this.observerMapBounds=void 0;return}const e=this.tracesShownState?this.currentSighting.traces.flatMap(n=>n.points):[],i=ei.fitted(this.observerPath,e);(!this.observerMapBounds||!this.sameGround(this.observerMapBounds,i))&&(this.observerMapBounds&&this.observerMapView.refit(this.observerMapBounds,i),this.observerMapBounds=i,this.observerMapImagery=void 0,this.observerMapImageryCredit=void 0,this.observerMapImageryFailed=!1,this.observerMapImageryBounds=void 0,this.observerMapImageryLoading=!1,this.observerMapPanel.hidden||this.loadObserverMapImagery())}sameGround(t,e){const i=Math.abs(t.east-t.west)/20;return Math.abs(t.north-e.north)<i&&Math.abs(t.south-e.south)<i&&Math.abs(t.west-e.west)<i&&Math.abs(t.east-e.east)<i}async loadObserverMapImagery(){const t=this.observerMapViewBounds;if(!t||this.observerMapPanel.hidden||this.observerMapImageryLoading||(this.observerMapFrozenImagery?this.observerMapImageryBounds!==void 0:!this.observerMapImageryNeededFor(t)))return;const e=this.observerMapView.changed,i=e?ei.expand(t,Le.OBSERVER_MAP_IMAGERY_AHEAD):t,n=ei.IMAGERY_PX*(e?1+2*Le.OBSERVER_MAP_IMAGERY_AHEAD:1);this.observerMapImageryBounds=i,this.observerMapImageryViewWidth=t.east-t.west,this.observerMapImageryLoading=!0;const s=this.observerMapFrozenImagery,a=s?void 0:Ov();try{const r=a?await a.getImageryTexture(i,{width:n,height:n}):await s.getImagery();if(this.observerMapImageryBounds!==i)return;this.observerMapImagery=r,this.observerMapImageryCredit=(a??s).attribution,this.observerMapImageryFailed=!1}catch{if(this.observerMapImageryBounds!==i)return;this.observerMapImageryFailed=this.observerMapImagery===void 0}finally{this.observerMapImageryBounds===i&&(this.observerMapImageryLoading=!1)}this.paintObserverMap(this.currentTime),this.scheduleObserverMapImagery()}static OBSERVER_MAP_IMAGERY_AHEAD=.5;static OBSERVER_MAP_IMAGERY_LOOKAHEAD=.25;observerMapImageryNeededFor(t){const e=this.observerMapImageryBounds;if(!e)return!0;const i=this.observerMapImagery?.bounds??e,n=this.observerMapView.changed?ei.expand(t,Le.OBSERVER_MAP_IMAGERY_LOOKAHEAD):t,s=n.west>=i.west&&n.east<=i.east&&n.south>=i.south&&n.north<=i.north,a=t.east-t.west>this.observerMapImageryViewWidth/2;return!s||!a}get observerMapCredit(){return this.observerMapImageryCredit}set observerMapFrozen(t){t!==this.observerMapFrozenImagery&&(this.observerMapFrozenImagery=t,this.observerMapImagery=void 0,this.observerMapImageryCredit=void 0,this.observerMapImageryFailed=!1,this.observerMapImageryBounds=void 0,this.observerMapImageryLoading=!1,this.observerMapPanel.hidden||(this.loadObserverMapImagery(),this.paintObserverMap(this.currentTime)))}get observerMapFrozen(){return this.observerMapFrozenImagery}observerMapFrozenImagery;observerMapFrozenSource;get observerMapFooterLine(){return this.observerMapImageryFailed?this.messages.mapImageryUnavailable:this.creditShownExternally?void 0:this.observerMapImageryCredit}mapShapeBounds=[];mapSceneBounds=[];setMapSubjectBounds(t){this.mapSceneBounds=t.map(e=>({x:e.x*this.canvas.width,y:e.y*this.canvas.height,width:e.width*this.canvas.width,height:e.height*this.canvas.height})),this.keepObserverMapClear()}keepObserverMapClear(){if(this.observerMapPanel.hidden)return;const t=this.observerMapBoxPx;if(!t)return;const e=[...this.mapShapeBounds,...this.mapSceneBounds],i=(h,l,u)=>{for(const d of e)if(!(d.x+d.width<h-u||d.x>l+u)&&!(d.y>t.bottom+u||d.y+d.height<t.top-u))return!0;return!1},n=[this.canvas.width-t.width,this.canvas.width],s=[0,t.width],a=Le.OBSERVER_MAP_CLEARANCE_PX,r=i(...n,0),c=i(...s,0);if(this.observerMapPanel.classList.toggle("subject-overlap",r&&c&&!this.observerMapAsked),this.observerMapPanel.classList.contains("on-the-left")){!r&&(c||!i(n[0],n[1],a))&&this.observerMapPanel.classList.remove("on-the-left");return}i(n[0],n[1],0)&&!i(s[0],s[1],0)&&this.observerMapPanel.classList.add("on-the-left")}observerMapBoxPx;static OBSERVER_MAP_CLEARANCE_PX=24;sizeObserverMapCanvas(){const t=this.observerMapPanel.clientWidth;if(t===0)return;const e=Math.round(t*(globalThis.devicePixelRatio??1));this.measureObserverMapBox(),this.observerMapCanvas.width!==e&&(this.observerMapCanvas.width=e,this.observerMapCanvas.height=e)}measureObserverMapBox(){const t=this.observerMapPanel.getBoundingClientRect(),e=this.canvas.getBoundingClientRect();if(e.width===0||e.height===0)return;const i=this.canvas.width/e.width,n=this.canvas.height/e.height;this.observerMapBoxPx={width:t.width*i,top:(t.top-e.top)*n,bottom:(t.bottom-e.top)*n}}paintObserverMap(t){if(this.observerMapPanel.hidden||!this.observerPath||!this.observerMapBounds)return;const e=Fe(this.currentSighting,t);e?.lat!==void 0&&e.lng!==void 0&&!this.observerMapDrag?.moved&&this.observerMapView.keepInView(this.observerMapBounds,{lat:e.lat,lng:e.lng},Le.OBSERVER_MAP_FOLLOW_MARGIN)&&this.scheduleObserverMapImagery();const i=this.currentSighting.instrument,n=[],s=this.currentSighting.milestones.length>0?Rd(this.currentSighting.milestones,t):void 0;for(const a of this.milestonesShown?fh(this.currentSighting.milestones):[]){const r=Fe(this.currentSighting,a.t);r?.lat===void 0||r.lng===void 0||n.push({label:this.said.read(a.label)??"",note:this.said.read(a.note),t:a.t,lat:r.lat,lng:r.lng,current:a===s})}this.observerMapRenderer.paint({bounds:this.observerMapViewBounds,imagery:this.observerMapImagery,path:this.observerPath,position:e?.lat!==void 0&&e.lng!==void 0?{lat:e.lat,lng:e.lng}:void 0,headingDeg:e?.headingDeg===void 0?void 0:e.headingDeg+this.lookYawDeg,coneHalfAngleDeg:e?ha.of(i,this.canvas.height,e.fovDeg).halfWidthAngleDeg(Ii.aspectOf(i)):void 0,markers:n,traces:(this.tracesShownState?this.currentSighting.traces:[]).map(a=>({kind:a.kind,points:a.points,color:a.color,label:this.said.read(a.title)})),decor:this.observerMapDecorAt(t),observerLabel:this.said.read(this.currentSighting.observer?.title)??this.messages.observerHere,nightFraction:this.observerMapNightFraction,attribution:this.observerMapFooterLine})}toggleMilestones(){this.setMilestonesShown(!this.milestonesShown)}setMilestonesShown(t){this.milestonesShown=t,this.milestoneMarks.hidden=!t,this.momentsBox.hidden=!t||this.sighting.milestones.length===0,this.refreshSeekSegments(this.player.seekableDuration,fh(this.sighting.milestones).map(e=>e.t)),this.milestonesButton.setAttribute("aria-pressed",String(t)),this.updateMilestonesButton(),this.showMilestoneAt(this.currentTime),this.paintObserverMap(this.currentTime)}updateMilestonesButton(){this.milestonesButton.hidden=this.currentSighting.milestones.length===0,this.momentsButton.title=this.messages.moments,Le.setIcon(this.milestonesButton,this.milestonesShown?Zt.MILESTONES_ON:Zt.MILESTONES_OFF);const t=this.milestonesShown?this.messages.hideMilestones:this.messages.showMilestones;this.milestonesButton.title=t,this.milestonesButton.setAttribute("aria-label",t)}observerMapDecorAt(t){const e=Fe(this.currentSighting,0);return e?.lat===void 0||e.lng===void 0?[]:this.currentSighting.decor.filter(i=>i.kind!=="crop").map(i=>{const n=fa(i,t),{lat:s,lng:a}=Kn(n.eastM,-n.northM,e.lat,e.lng);return{lat:s,lng:a,headingDeg:n.headingDeg,label:this.said.read(i.title)??this.messages.decorHere}})}observerMapNightFraction;setSunAltitude(t){const e=t===void 0?void 0:Math.max(0,Math.min(1,-t/12));e!==this.observerMapNightFraction&&(this.observerMapNightFraction=e,this.paintObserverMap(this.currentTime))}setLookOffset(t,e){t===this.lookYawDeg&&e===this.lookPitchDeg||(this.lookYawDeg=t,this.lookPitchDeg=e,this.refresh())}get frameShiftPx(){return this.frameShift}get frameShift(){const t=this.gaitAt(this.currentTime),e=this.lookYawDeg+t.yawDeg,i=this.lookPitchDeg+t.pitchDeg;if(e===0&&i===0)return{x:0,y:0};const n=Fe(this.currentSighting,this.currentTime),s=ha.of(this.currentSighting.instrument,this.canvas.height,n?.fovDeg??60);return{x:-s.angleDegToRadiusPx(e),y:s.angleDegToRadiusPx(i)}}gaitAt(t){return Ye.bodyAt(this.currentSighting,t,this.steadyBody)}mutedState=!1;get muted(){return this.mutedState}set muted(t){t!==this.mutedState&&(this.mutedState=t,!t&&this.volumeState===0&&(this.volumeState=Le.RESTORED_VOLUME),this.applyLevel())}volumeState=1;static RESTORED_VOLUME=.5;get volume(){return this.volumeState}set volume(t){this.setVolume(t)}setVolume(t){this.volumeState=Math.min(Math.max(t,0),1),this.mutedState=this.volumeState===0,this.applyLevel()}get level(){return this.mutedState?0:this.volumeState}applyLevel(){this.sightingAudio.setLevel(this.level),this.updateMuteButton(),this.dispatchEvent(new CustomEvent("mutedchange",{bubbles:!0,composed:!0,detail:{muted:this.mutedState,volume:this.volumeState}}))}toggleMuted(){this.hasSound&&(this.muted=!this.mutedState)}ambientSound;get hasSound(){return this.currentSighting.soundTrack.allKeyframes.length>0||this.ambientSound?.(this.currentSighting)===!0}updateMuteButton(){const t=!this.hasSound;this.miniMuteButton.hidden=t,this.miniMuteButton.setAttribute("aria-pressed",String(this.mutedState)),Le.setIcon(this.miniMuteButton,this.mutedState?Zt.MUTED:Zt.VOLUME);const e=this.mutedState?this.messages.unmute:this.messages.mute;if(this.miniMuteButton.title=e,this.miniMuteButton.setAttribute("aria-label",e),this.muteButton.disabled=t,this.volumeInput.hidden=t,t){Le.setIcon(this.muteButton,Zt.MUTED),this.muteButton.title=this.messages.noSound,this.muteButton.setAttribute("aria-label",this.messages.noSound),this.muteButton.setAttribute("aria-pressed","true");return}Le.setIcon(this.muteButton,this.mutedState?Zt.MUTED:Zt.VOLUME);const i=this.mutedState?this.messages.unmute:this.messages.mute;this.muteButton.title=i,this.muteButton.setAttribute("aria-label",i),this.muteButton.setAttribute("aria-pressed",String(this.mutedState)),this.volumeInput.value=String(this.level)}updateFullscreenButton(){const t=this.simulatedFullscreen||document.fullscreenElement===this.fullscreenTarget;Le.setIcon(this.fullscreenButton,t?Zt.EXIT_FULLSCREEN:Zt.ENTER_FULLSCREEN),this.fullscreenButton.title=t?this.messages.exitFullscreen:this.messages.fullscreen,this.fullscreenButton.setAttribute("aria-label",this.fullscreenButton.title)}get said(){return this.saidTexts??=new Pa(lc.preferencesFor(this))}saidTexts;async loadLocaleMessages(){const t=vv(lc.preferencesFor(this),yv);if(t===this.messagesLanguage||t==="en"&&this.messagesLanguage===void 0)return;this.messagesLanguage=t;const e=await Ox(t);this.messagesLanguage===t&&this.applyMessages(e)}messagesLanguage;updateTimeLabelTitles(){const t=this.showClockTime?this.messages.switchToElapsed:this.messages.switchToClockTime,e=this.canSwitchTimeDisplay?` — ${t}`:"";this.timeStartLabel.title=this.messages.currentPosition+e,this.timeEndLabel.title=this.messages.duration+e,this.timePill.classList.toggle("switchable",this.canSwitchTimeDisplay),this.canSwitchTimeDisplay?(this.timePill.setAttribute("role","button"),this.timePill.setAttribute("tabindex","0")):(this.timePill.removeAttribute("role"),this.timePill.removeAttribute("tabindex"))}applyMessages(t){this.messages=t,this.updateTimeLabelTitles(),this.updatePlayPauseButton(),this.updateFullscreenButton(),this.updateMuteButton(),this.updateObserverMapButton(),this.updateReferencesButton(),this.updateTracesButton(),this.updateMilestonesButton(),this.renderIssues()}updateTimeLabels(){const t=this.currentSighting.event,e=px(t);this.realDurationMs=e!==void 0&&e>0?e:void 0,this.realStartMs=t.time?o0(t.time):void 0;const i=this.currentSighting.timeline.duration;this.player.playbackRate=this.realDurationMs!==void 0&&i>0?i/this.realDurationMs:1,this.player.durationOverrideMs=i>0?0:this.realDurationMs??0,this.timeEndLabel.textContent=this.formatEndOfTimeline(),this.timeStartLabel.textContent=this.formatPosition(this.player.time),this.paintMiniProgress(this.player.time),this.updateTimeLabelTitles()}formatPosition(t){if(this.realDurationMs===void 0)return Ya(t);const e=this.currentSighting.timeline.duration,i=e>0&&t<=e?t/e*this.realDurationMs:t;return this.canShowClockTime?fg(dg(this.realStartMs+i)):Ya(i)}formatElapsedAt(t){const e=this.currentSighting.timeline.duration;return this.realDurationMs===void 0?Ya(t):Ya(e>0&&t<=e?t/e*this.realDurationMs:t)}formatRemaining(t){const e=this.currentSighting.timeline.duration;if(this.realDurationMs===void 0)return Ya(Math.max(0,e-t));const i=e>0&&t<=e?t/e*this.realDurationMs:t;return Ya(Math.max(0,this.realDurationMs-i))}formatEndOfTimeline(){return this.realDurationMs===void 0?Ya(this.currentSighting.timeline.duration):this.canShowClockTime?fg(dg(this.realStartMs+this.realDurationMs)):Ya(this.realDurationMs)}}function dg(o){const t=new Date(o);return{hour:t.getUTCHours(),minute:t.getUTCMinutes(),second:t.getUTCSeconds()}}function fg(o){if(o.hour===void 0)return"0:00";const t=e=>String(e).padStart(2,"0");return o.second?`${t(o.hour)}:${t(o.minute??0)}:${t(o.second)}`:`${t(o.hour)}:${t(o.minute??0)}`}function Ya(o){const t=Math.round(o/1e3),e=Math.floor(t/60),i=t%60;return`${e}:${String(i).padStart(2,"0")}`}const h0="rr0-ufo";function Pv(){customElements.get(h0)||customElements.define(h0,Le)}const nw="recordingissues",Lv="minifiedreset";/**
1742
1742
  * @license
1743
1743
  * Copyright 2010-2026 Three.js Authors
1744
1744
  * SPDX-License-Identifier: MIT
@@ -7826,7 +7826,7 @@ uniform float uWindowLuminance;
7826
7826
  varying float vLitRank;
7827
7827
  ${h.fragmentShader.replace("#include <emissivemap_fragment>",`#include <emissivemap_fragment>
7828
7828
  totalEmissiveRadiance *= step(vLitRank, uLitShare) * uWindowLuminance * ${lt.WINDOW_VARIETY_GLSL};`)}`},r.customProgramCacheKey=()=>"facade-lit-windows";const c=new vt(a,r);return c.castShadow=!0,c.receiveShadow=!0,e.add(c),e}static CLOSED_AT_NIGHT_SHARE=.2;static litWindowShare={value:0};static WINDOW_LUMINANCE_CD_M2=15;static ROOM_LIGHT_K=2900;static COLD_ROOM_LIGHT_K=4e3;static windowLuminance={value:0};static get WINDOW_VARIETY_GLSL(){const t=n=>`vec3(${n.map(s=>s.toFixed(4)).join(", ")})`,e=wc.ofTemperature(lt.ROOM_LIGHT_K),i=wc.ofTemperature(lt.COLD_ROOM_LIGHT_K);return`(mix(0.35, 2.0, fract(vLitRank * 97.13) * fract(vLitRank * 97.13)) * mix(${t(e)}, ${t(i)}, step(0.86, fract(vLitRank * 53.71))))`}static setWindowLuminance(t){lt.windowLuminance.value=lt.WINDOW_LUMINANCE_CD_M2*t}static setLitWindowShare(t){lt.litWindowShare.value=Math.max(0,Math.min(1,t))}static build(t,e){const i=lt.hasFacade(t)?lt.buildFacade(t):t.kind==="building"?pM(t.floors??Gm,t.windows,t.observerSide,t.occupiedFloor,t.observerFacing):t.kind==="tree"?gM():t.kind==="shrub"?mM():t.kind==="bridge"?S4(t):t.kind==="wire"?b4(t):t.kind==="wall"?Xi.build(t):t.kind==="crop"?vM():t.kind==="terrace"?C4():t.kind==="mound"?yM():t.kind==="streetlight"?xM(e,t.lamp?.mount,t.lamp):t.kind==="trafficlight"?ye.trafficLight(ue.isPedestrian(t.lights)):t.kind==="crossing"?ye.crossing(lt.sizeOf(t).widthM,lt.sizeOf(t).lengthM):t.kind==="roadsign"?ye.roadSign(t.sign):t.kind==="vehicle"?wM(e,t.windows,t.observerSide,t.observerFacing):t.kind==="aircraft"?TM():t.kind==="entity"?AM():Lp();t.color&&this.paint(i,t.color);const n=this.scaleFor(t),s=new Oe;return t.kind==="building"&&t.roof&&this.addRoof(s,t),i.name=lt.BODY_NAME,i.scale.copy(n),s.add(i),t.headingDeg!==void 0&&(s.rotation.y=-t.headingDeg*Tf),this.addLights(s,t.lights),lt.fitLights(s,t,t.sizeM??{}),s}static scaleFor(t){const e=t.sizeM;if(!e||lt.hasFacade(t)||t.kind==="bridge"||t.kind==="wire"||t.kind==="terrace"||t.kind==="wall"||t.kind==="crossing")return new T(1,1,1);const i=this.naturalSize(t.kind,t.floors);return new T(e.widthM===void 0?1:Cf(e.widthM,i.widthM),e.heightM===void 0?1:Cf(t.kind==="building"?this.wallHeightOf(t,e.heightM):e.heightM,i.heightM),e.lengthM===void 0?1:Cf(e.lengthM,i.lengthM))}static naturalSize(t,e){const i=t==="building"?Math.max(1,(e??Gm)+1):0;if(t==="bridge")return hi.NATURAL_SIZE;if(t==="wire")return Yr.NATURAL_SIZE;if(t==="terrace"||t==="wall")return{widthM:1,lengthM:1,heightM:1};if(t==="crossing")return{widthM:6,lengthM:2.5,heightM:ye.CROSSING_LIFT_M};const n=`${t}:${i}`,s=SM.get(n);if(s)return s;const a=t==="building"?pM(i-1,void 0,void 0,void 0):t==="tree"?gM():t==="shrub"?mM():t==="crop"?vM():t==="mound"?yM():t==="streetlight"?xM(!1):t==="trafficlight"?ye.trafficLight(!1):t==="roadsign"?ye.roadSign(void 0):t==="vehicle"?wM(!1,void 0,void 0):t==="aircraft"?TM():t==="entity"?AM():Lp(),r=new zi().setFromObject(a),c={widthM:r.max.x-r.min.x,heightM:r.max.y-r.min.y,lengthM:r.max.z-r.min.z};return this.dispose(a),SM.set(n,c),c}static usesModel(t){return a0(t)!==void 0&&!(t.observerSide!==void 0&&Au(t.kind))}static applyModel(t,e,i,n={}){const s=this.bodyOf(t),a=new Oe;a.name=lt.BODY_NAME,i.rotation.y=-(n.headingOffsetDeg??0)*Tf,i.updateMatrixWorld(!0);const r=new zi().setFromObject(i),c={lengthM:r.max.z-r.min.z,heightM:r.max.y-r.min.y,widthM:r.max.x-r.min.x},h=e.kind==="tree"&&e.sizeM?.heightM!==void 0?{heightM:e.sizeM.heightM}:e.sizeM,l=bM(h,c)??bM(n.depictedSizeM,c)??1;i.scale.multiplyScalar(l);const u=r.getCenter(new T).multiplyScalar(l);i.position.x-=u.x,i.position.z-=u.z,i.position.y-=e.kind==="aircraft"?u.y:r.min.y*l,i.traverse(d=>{d instanceof vt&&(d.castShadow=!0,d.receiveShadow=!0)}),a.add(i),e.kind==="tree"&&a.add(lt.trunkShadow(c.heightM*l)),s.parent?(s.parent.add(a),s.removeFromParent()):t.add(a),this.dispose(s),lt.fitLights(t,e,{widthM:c.widthM*l,heightM:c.heightM*l,lengthM:c.lengthM*l})}static fitLights(t,e,i){const n=Dp.byId(sc.rigOf(e)||void 0)?.referenceSizeM;if(!n||!e.lights)return;const s=(l,u)=>l===void 0||u===0?1:l/u,a=s(i.widthM,n.widthM),r=s(i.heightM,n.heightM),c=s(i.lengthM,n.lengthM),h=new Map(e.lights.map(l=>[l.id,l.offsetM]));t.traverse(l=>{const u=l.userData.lightId,d=u===void 0?void 0:h.get(u);d&&l.position.set(d.x*a,d.y*r,d.z*c)})}static trunkShadow(t){lt.trunkProxy??={geometry:new bn(1,1.15,1,8),material:new Zn({colorWrite:!1,depthWrite:!1})};const e=new vt(lt.trunkProxy.geometry,lt.trunkProxy.material),i=Math.min(.3,Math.max(.12,t*.035)),n=t*.45;return e.scale.set(i,n,i),e.position.y=n/2,e.castShadow=!0,e.receiveShadow=!1,e.userData.sharedModel=!0,e.name="trunk-shadow",e}static trunkProxy;static sizeOf(t){const e=this.naturalSize(t.kind,t.floors);return{widthM:t.sizeM?.widthM??e.widthM,lengthM:t.sizeM?.lengthM??e.lengthM,heightM:t.sizeM?.heightM??e.heightM}}static addLights(t,e){for(const i of e??[]){const n=f4(i.color),s=ue.figureOf(i),a=s?ye.pedestrianFigure(s,1.8*(i.radiusM??Rf)):new Bi(i.radiusM??Rf,8,6),r=ze(t,a,n,i.offsetM.y,!0);r.position.set(i.offsetM.x,i.offsetM.y,i.offsetM.z),r.userData={emissive:!0,lightId:i.id,lightColor:n},r.visible=!1;const c=r.material;z2.apply(c),c.transparent=!0,c.depthWrite=!1,c.fog=!1}}static setLights(t,e,i,n,s=0,a=1,r=o4,c=[1,1,1],h){if(!e||e.length===0)return;const l=new Map(e.map(d=>[d.id,d]));let u;h&&e.some(d=>d.beamDeg!==void 0)&&(t.updateWorldMatrix(!0,!1),u=t.worldToLocal(lt.eyeScratch.copy(h)));for(const d of t.children){if(!(d instanceof vt))continue;const f=d.userData.lightId;if(!f)continue;const p=l.get(f);if(!p)continue;const g=s>0?gv(p,i,i+s):Gy(p,i)?1:0,m=u&&p.beamDeg!==void 0?lt.beamShare(p.beamDeg,d.position,u):1;d.visible=g>0&&m>0;const M=p.radiusM??Rf,y=Math.max(1,n*r/M),x=M*y,v=a/(Math.PI*x*x),w=d.material,b=d.userData.lightColor;if(b){const _=g*m*c4*(p.intensity??1)*v,S=[b[0]*_*c[0],b[1]*_*c[1],b[2]*_*c[2]],A=Math.min(1,dM/Math.max(S[0],S[1],S[2],1e-30));w.color.setRGB(S[0]*A,S[1]*A,S[2]*A)}d.scale.setScalar(y)}}static eyeScratch=new T;static beamShare(t,e,i){const n=i.x-e.x,s=i.y-e.y,a=i.z-e.z,r=Math.hypot(n,s,a);if(r===0)return 1;const c=-a/r;if(c<=0)return 0;const h=Math.log(.5)/Math.log(Math.cos(t*Math.PI/180));return Math.pow(c,h)}static setLit(t,e,i,n=1,s){const[a,r,c]=e==="streetlight"?[h4*lt.lampShare(s),l4,lt.lampHue(s)]:[u4,d4,dy],h=i?a*n/(Math.PI*r*r):0,l=Math.min(1,dM/Math.max(c[0]*h,c[1]*h,c[2]*h,1e-30)),u=[c[0]*h*l,c[1]*h*l,c[2]*h*l];t.traverse(d=>{const f=d.userData;!(d instanceof vt)||!f.emissive||f.lightId||(d.material instanceof bs?d.material.emissive.setRGB(...u):d.material.color.setRGB(...u))})}static REFERENCE_LUMENS=1e4;static lampShare(t){return t?.lumens?t.lumens/lt.REFERENCE_LUMENS:1}static lampHue(t){return t?.colorTemperatureK?wc.ofTemperature(t.colorTemperatureK):m4}static dispose(t){t.traverse(e=>{if(!(e instanceof vt))return;if(e.userData.sharedModel){for(const n of e.userData.tintedMaterials??[])n.dispose();return}e.geometry.dispose();const i=e.material;for(const n of Array.isArray(i)?i:[i])n.dispose()})}}const Pf="https://ufoathome.org/models/index.json";class Th{attribution="3D models re-hosted by UFO@home, each under its own author's licence";fetchImpl;indexUrls;loading;static shared=new Map;sharing;constructor(t={}){this.sharing=!t.fetchImpl,this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.indexUrls=t.indexUrls??N4()}async entries(t){const e=await this.load();return t?e.filter(i=>[i.kind].flat().includes(t)):e}async entry(t){return(await this.load()).find(e=>e.id===t)}load(){if(this.loading)return this.loading;if(!this.sharing)return this.loading=this.fetchFirstAvailable();const t=this.indexUrls.join(`
7829
- `);let e=Th.shared.get(t);return e||(e=this.fetchFirstAvailable(),Th.shared.set(t,e),e.then(i=>{i.length===0&&Th.shared.delete(t)})),this.loading=e}async fetchFirstAvailable(){for(const t of this.indexUrls){const e=await this.fetchIndex(t);if(e)return e}return[]}async fetchIndex(t){try{const e=await this.fetchImpl(t);if(!e.ok)return;const i=await e.json();return Array.isArray(i?.models)?i.models.map(({file:n,...s})=>({...s,url:new URL(n,t).href})):void 0}catch{return}}}function N4(){const o=`?v=${encodeURIComponent("0.152.0")}`,t=typeof location>"u"?void 0:new URL("/models/index.json",location.href).href;return(t&&t!==Pf?[t,Pf]:[Pf]).map(e=>e+o)}const U4=[{id:"ufoathome",name:"UFO@home",credit:"3D models re-hosted by UFO@home, each under its own author's licence",creditUrl:"https://ufoathome.org/models/",create:()=>new Th}];async function Lf(o){const{GLTFLoader:t}=await Mi(async()=>{const{GLTFLoader:i}=await import("./GLTFLoader-wJ0bjCoG.js");return{GLTFLoader:i}},[],import.meta.url),e=new t;return new Promise((i,n)=>{e.load(o,s=>i(Object.assign(s.scene,{animations:s.animations})),void 0,s=>n(new Error(`Could not load 3D model ${o}: ${s instanceof Error?s.message:String(s)}`)))})}const yy=["ellipsoid","sphere","disc","cylinder","cone","box","torus","figure"];class as{static MIN_ANGLE_RAD=.002;static FILL=(1-Math.exp(-4))/4;static MAX_SHARE=.3;mesh;constructor(t,e){this.mesh=new vt(new En(2,2),new Se({uniforms:{uColor:{value:new st(0,0,0)},uRadius:{value:1}},vertexShader:as.VERTEX,fragmentShader:as.FRAGMENT,transparent:!0,depthWrite:!1,blending:Zi,toneMapped:!1})),this.mesh.name=t,this.mesh.frustumCulled=!1,this.mesh.renderOrder=e,this.mesh.visible=!1}shine(t,e,i){this.mesh.visible=!0,this.mesh.position.set(t.x,t.y,t.z),this.mesh.material.uniforms.uRadius.value=e,this.mesh.material.uniforms.uColor.value.setRGB(i[0],i[1],i[2])}hide(){this.mesh.visible=!1}dispose(){this.mesh.geometry.dispose(),this.mesh.material.dispose()}static spread(t,e,i,n){const s=Math.max(t,n*as.MIN_ANGLE_RAD),a=as.FILL*Math.PI*s*s;return{radiusM:s,luminanceCdM2:i*Math.min(as.MAX_SHARE,e/a)}}static conserving(t){return Math.sqrt(t/(as.MAX_SHARE*as.FILL*Math.PI))}static VERTEX=`
7829
+ `);let e=Th.shared.get(t);return e||(e=this.fetchFirstAvailable(),Th.shared.set(t,e),e.then(i=>{i.length===0&&Th.shared.delete(t)})),this.loading=e}async fetchFirstAvailable(){for(const t of this.indexUrls){const e=await this.fetchIndex(t);if(e)return e}return[]}async fetchIndex(t){try{const e=await this.fetchImpl(t);if(!e.ok)return;const i=await e.json();return Array.isArray(i?.models)?i.models.map(({file:n,...s})=>({...s,url:new URL(n,t).href})):void 0}catch{return}}}function N4(){const o=`?v=${encodeURIComponent("0.152.1")}`,t=typeof location>"u"?void 0:new URL("/models/index.json",location.href).href;return(t&&t!==Pf?[t,Pf]:[Pf]).map(e=>e+o)}const U4=[{id:"ufoathome",name:"UFO@home",credit:"3D models re-hosted by UFO@home, each under its own author's licence",creditUrl:"https://ufoathome.org/models/",create:()=>new Th}];async function Lf(o){const{GLTFLoader:t}=await Mi(async()=>{const{GLTFLoader:i}=await import("./GLTFLoader-wJ0bjCoG.js");return{GLTFLoader:i}},[],import.meta.url),e=new t;return new Promise((i,n)=>{e.load(o,s=>i(Object.assign(s.scene,{animations:s.animations})),void 0,s=>n(new Error(`Could not load 3D model ${o}: ${s instanceof Error?s.message:String(s)}`)))})}const yy=["ellipsoid","sphere","disc","cylinder","cone","box","torus","figure"];class as{static MIN_ANGLE_RAD=.002;static FILL=(1-Math.exp(-4))/4;static MAX_SHARE=.3;mesh;constructor(t,e){this.mesh=new vt(new En(2,2),new Se({uniforms:{uColor:{value:new st(0,0,0)},uRadius:{value:1}},vertexShader:as.VERTEX,fragmentShader:as.FRAGMENT,transparent:!0,depthWrite:!1,blending:Zi,toneMapped:!1})),this.mesh.name=t,this.mesh.frustumCulled=!1,this.mesh.renderOrder=e,this.mesh.visible=!1}shine(t,e,i){this.mesh.visible=!0,this.mesh.position.set(t.x,t.y,t.z),this.mesh.material.uniforms.uRadius.value=e,this.mesh.material.uniforms.uColor.value.setRGB(i[0],i[1],i[2])}hide(){this.mesh.visible=!1}dispose(){this.mesh.geometry.dispose(),this.mesh.material.dispose()}static spread(t,e,i,n){const s=Math.max(t,n*as.MIN_ANGLE_RAD),a=as.FILL*Math.PI*s*s;return{radiusM:s,luminanceCdM2:i*Math.min(as.MAX_SHARE,e/a)}}static conserving(t){return Math.sqrt(t/(as.MAX_SHARE*as.FILL*Math.PI))}static VERTEX=`
7830
7830
  uniform float uRadius;
7831
7831
  varying vec2 vOffset;
7832
7832
  void main() {