@rr0/ufoathome 0.90.0 → 0.91.0

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.
@@ -1363,7 +1363,7 @@ canvas[data-cursor="rotate"] {
1363
1363
  }
1364
1364
  `,hc=[{id:"eye",name:"Naked eye",flare:0,projection:"equidistant",stabilization:.97},{id:"rectilinear-lens",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:"instamatic-126",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",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",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",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}},{id:"phone-portrait",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}}];class mi{static get default(){return hc[0]}static byId(t){return hc.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?2*Math.atan(e.heightMm/(2*e.focalLengthMm))*180/Math.PI:mi.UNAIDED_FIELD_DEG}static aspectOf(t){const e=t.frame;return e?e.widthMm/e.heightMm:mi.UNAIDED_ASPECT}static frameWidthPx(t,e){return Math.round(e*mi.aspectOf(t))}static availableAt(t){return t===void 0?hc:hc.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 2*Math.atan(i.heightMm/(2*e))*180/Math.PI}static focalLengthMmFor(t,e){const i=t.frame;if(!(!i||e<=0||e>=180))return i.heightMm/(2*Math.tan(e*Math.PI/360))}static bladesShowing(t,e){const i=e??t.fNumber;if(i===void 0||t.apertureBlades===void 0)return 0;const n=t.fNumberRange;return!n||n.max<=n.min?1:Math.max(0,Math.min(1,(i-n.min)/(n.max-n.min)))}static LENS_FLARE_ARTIFACTS=1;static flareArtifactsOf(t){return t.flare??mi.LENS_FLARE_ARTIFACTS}static starPointsOf(t){const e=t.apertureBlades;return e===void 0||e<3?0:e%2===0?e:e*2}}class Pr{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 Pr(e)}static TRAVEL_M=50;get travels(){return this.spanM>Pr.TRAVEL_M}get moved(){return this.spanM>Pr.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(Je(e,t.east,e,t.west).x),Math.abs(Je(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:xn(0,-s,i,n).lat,south:xn(0,s,i,n).lat,east:xn(s,0,i,n).lng,west:xn(-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 wn{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)>wn.HAND_HELD_S,i=t.sway??(e?0:1);if(i>0)return new wn(Math.max(1-(t.instrument.stabilization??0),wn.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,o,c,l,h]=wn.HZ;return{eastM:i*wn.SWAY_M*(.7*n(s,.3)+.3*n(c,1.9)),northM:i*wn.SWAY_M*(.6*n(o,2.2)+.4*n(l,.8)),upM:i*wn.BREATH_M*n(a,0),yawDeg:i*this.rotationPassed*wn.DRIFT_YAW_DEG*(.6*n(h,1.1)+.4*n(c,2.7)),pitchDeg:i*this.rotationPassed*wn.DRIFT_PITCH_DEG*(.5*n(a,1.6)+.5*n(o,.4)),rollDeg:i*this.rotationPassed*wn.DRIFT_ROLL_DEG*n(s,2.9)}}}class be{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=Pr.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],o=e.points[s],c=(o.t-a.t)/1e3;if(c<=0)continue;const l=Je(o.lat,o.lng,a.lat,a.lng),h=l.x,u=-l.z,d=Math.hypot(h,u),f=d/c,p=be.stepHzFor(f);i.push({startMs:a.t,endMs:o.t,speedMPerS:f,eastUnit:d>0?h/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],o=i[s+1];i[s].rampsIn=a===void 0||a.stepHz===0,i[s].rampsOut=o===void 0||o.stepHz===0}if(i.some(s=>s.stepHz>0))return new be(i,1-(t.instrument.stabilization??0))}static bodyAt(t,e,i=!1){const n=be.of(t)?.offsetAt(e)??be.STILL;return i?n:be.add(n,wn.of(t)?.offsetAt(e))}static stepHzFor(t){return t<be.SLOWEST_WALK_M_PER_S||t>be.FASTEST_WALK_M_PER_S?0:be.REFERENCE_STEP_HZ*Math.pow(t/be.REFERENCE_SPEED_M_PER_S,be.CADENCE_EXPONENT)}offsetAt(t){return be.add(this.cycleAt(t),this.joltAt(t))}joltAt(t){for(const e of this.stretches){if(e.stepHz===0)continue;const i=e.speedMPerS/be.REFERENCE_SPEED_M_PER_S,n=(o,c,l,h)=>{if(o<0||o>be.JOLT_LASTS_MS)return;const u=o/1e3,d=Math.exp(-u/be.JOLT_DECAY_S)*Math.sin(2*Math.PI*be.JOLT_HZ*u),f=h*c*i*d;return{eastM:f*e.eastUnit,northM:f*e.northUnit,upM:-Math.abs(f)*.3,rollDeg:0,pitchDeg:-h*l*i*d*this.rotationPassed,yawDeg:0}},s=e.rampsOut?n(t-e.endMs,be.STOP_LURCH_M,be.STOP_PITCH_DEG,1):void 0;if(s)return s;const a=e.rampsIn?n(t-e.startMs,be.START_LURCH_M,be.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 be.STILL;const i=e.stepsBefore+e.stepHz*(t-e.startMs)/1e3,n=2*Math.PI*i,s=this.amplitudeAt(e,t),a=be.SWAY_M*s*Math.cos(n/2),o=s*this.rotationPassed*e.speedMPerS/be.REFERENCE_SPEED_M_PER_S;return{eastM:a*e.northUnit,northM:-a*e.eastUnit,upM:be.RISE_M_PER_M_PER_S*e.speedMPerS*s*Math.cos(n),rollDeg:be.HEAD_ROLL_DEG*o*Math.cos(n/2),pitchDeg:-1.25*o*Math.cos(n),yawDeg:be.HEAD_YAW_DEG*o*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,o=Math.min(t.rampsIn?s/n:1,t.rampsOut?a/n:1,1);return(1-Math.cos(Math.PI*Math.max(o,0)))/2}}class De{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/De.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 Pv(r,t,e){if(!r||!t)return e<1?r:t;const i=((t.azimuthDeg-r.azimuthDeg)%360+540)%360-180;return{azimuthDeg:((r.azimuthDeg+i*e)%360+360)%360,altitudeDeg:r.altitudeDeg+(t.altitudeDeg-r.altitudeDeg)*e}}function Lv(r,t,e){const{bounds:i}=r;return t>=i.x&&t<=i.x+i.width&&e>=i.y&&e<=i.y+i.height}function en(r,t,e){return r+(t-r)*e}function wf(r){const t=/^#([0-9a-f]{6})$/i.exec(r);if(!t)return;const e=parseInt(t[1],16);return[e>>16&255,e>>8&255,e&255]}function Ov(r){return`#${r.map(t=>Math.round(t).toString(16).padStart(2,"0")).join("")}`}function Nv(r,t,e){const i=wf(r),n=wf(t);return!i||!n?e<1?r:t:Ov([en(i[0],n[0],e),en(i[1],n[1],e),en(i[2],n[2],e)])}function Fv(r,t,e){const i={x:en(r.bounds.x,t.bounds.x,e),y:en(r.bounds.y,t.bounds.y,e),width:en(r.bounds.width,t.bounds.width,e),height:en(r.bounds.height,t.bounds.height,e)},n=en(r.angle,t.angle,e),s=en(r.transparency,t.transparency,e),a=en(r.haloScale,t.haloScale,e),o=en(r.blur??0,t.blur??0,e),c=en(r.brightness??0,t.brightness??0,e),l=Nv(r.color,t.color,e),h=De.lerpAngular(r.angular,t.angular,e),u=Pv(r.aim,t.aim,e);return r.kind==="polygon"&&t.kind==="polygon"&&r.points.length===t.points.length?{...r,bounds:i,angle:n,transparency:s,haloScale:a,blur:o,brightness:c,color:l,angular:h,aim:u,points:r.points.map((d,f)=>({x:en(d.x,t.points[f].x,e),y:en(d.y,t.points[f].y,e)}))}:{...e<1?r:t,bounds:i,angle:n,transparency:s,haloScale:a,blur:o,brightness:c,color:l,angular:h,aim:u}}class Ea{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,o)=>{const c=`timeline.keyframes.${s}.shapes.${o}.shape`,l=Ea.completed(a,i.get(a.sourceId),c,e);return i.set(a.sourceId,l),{sourceId:a.sourceId,shape:l}})}))}static completed(t,e,i,n){const s=t.shape??{},a=e??Ea.firstAppearance(s,i,n),o={...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 o.aim,s.angular||delete o.angular);const c=s.kind??a.kind??"oval",l={...o,...s,kind:c};if(c==="polygon"&&!l.points){n.push({kind:"defaulted",path:`${i}.points`,expected:"rectangle"});const{width:h,height:u}=l.bounds;return{...l,points:[{x:0,y:0},{x:h,y:0},{x:h,y:u},{x:0,y:u}]}}return l}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:`"${Ea.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:{...Ea.NEUTRAL_BOUNDS},color:Ea.DEFAULT_COLOR,angle:0,transparency:0,haloScale:0,selected:!1}}static NEUTRAL_BOUNDS={x:De.CANVAS_WIDTH_PX/2,y:De.CANVAS_HEIGHT_PX/2,width:1,height:1}}class jl{keyframes=[];order=[];groups=[];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?Fv(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 o=this.getInterpolatedShapeAt(t,s[a]);if(o&&Lv(o,e,i))return{sourceId:s[a],shape:o}}}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)}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(){return this.keyframes.length===0?0:this.keyframes[this.keyframes.length-1].t}get sourceIds(){return[...this.order]}get allKeyframes(){return this.keyframes}toJSON(){return{keyframes:this.keyframes,order:this.order,groups:this.groups}}static fromJSON(t,e){const i=new jl;for(const n of Ea.complete(t.keyframes??[],e))i.addKeyframe(n.t,n.shapes);if(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 Uv(r,t,e){return Math.max(t,Math.min(e,r))}function kv(r,t,e){const i=((t-r)%360+540)%360-180;return((r+i*e)%360+360)%360}function Za(r,t,e){return r+(t-r)*e}function zv(r,t,e){return{lat:r.lat===void 0||t.lat===void 0?void 0:Za(r.lat,t.lat,e),lng:r.lng===void 0||t.lng===void 0?void 0:Za(r.lng,t.lng,e),elevationM:Za(r.elevationM,t.elevationM,e),headingDeg:r.headingDeg===void 0||t.headingDeg===void 0?void 0:kv(r.headingDeg,t.headingDeg,e),pitchDeg:Za(r.pitchDeg,t.pitchDeg,e),rollDeg:Za(r.rollDeg??0,t.rollDeg??0,e),fovDeg:Za(r.fovDeg,t.fovDeg,e),fNumber:r.fNumber,focusDistanceM:r.focusDistanceM}}class Ua{static at(t,e,i,n,s){const a=t[i],c=t[i+1]-a;if(c<=0)return e[i];const l=Ua.tangent(t,e,i,s),h=Ua.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*l+(-2*f+3*d)*e[i+1]+(f-d)*c*h}static BRAKE_S=.8;static paced(t,e,i,n){if(!i&&!n)return t;const s=e>0?Math.min(.5,Ua.BRAKE_S/e):.5;if(i&&n){const o=1/(1-s);return t<=s?o*t*t/(2*s):t>=1-s?1-o*(1-t)*(1-t)/(2*s):o*(t-s/2)}const a=o=>{const c=1/(1-s/2);if(o<=1-s)return c*o;const l=o-(1-s);return c*(1-s)+c*(l-l*l/(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 o=a(i-1),c=a(i);if(o*c<=0)return 0;const l=t[i]-t[i-1],h=t[i+1]-t[i],u=2*h+l,d=h+2*l;return(u+d)/(u/o+d/c)}}class Wo{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 i.pose;const s=zv(i.pose,n.pose,Uv((t-i.t)/(n.t-i.t),0,1));return this.humanly(e-1,t,s)}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),o=t-n,c=a.map(y=>y.t),l=(y,M)=>{const b=a.map(w=>y(w.pose));if(!b.some(w=>w===void 0))return Ua.at(c,b,o,e,M)},h=a.map(y=>y.pose.headingDeg);let u;if(h.every(y=>y!==void 0)){const y=[h[0]];for(let M=1;M<h.length;M++)y.push(y[M-1]+((h[M]-h[M-1])%360+540)%360-180);u=(Ua.at(c,y,o,e,!0)%360+360)%360}const d=this.keyframes[t],f=this.keyframes[t+1],p=(y,M)=>y.lat===M.lat&&y.lng===M.lng&&y.elevationM===M.elevationM,v=!p(d.pose,f.pose),m=v&&t>0&&p(this.keyframes[t-1].pose,d.pose),g=v&&t+2<this.keyframes.length&&p(f.pose,this.keyframes[t+2].pose);let _;if(m||g){const y=Ua.paced((e-d.t)/(f.t-d.t),(f.t-d.t)/1e3,m,g),M=(b,w)=>b===void 0||w===void 0?void 0:b+(w-b)*y;_={lat:M(d.pose.lat,f.pose.lat),lng:M(d.pose.lng,f.pose.lng),elevationM:M(d.pose.elevationM,f.pose.elevationM)}}return{...i,lat:_?_.lat:l(y=>y.lat,!1)??i.lat,lng:_?_.lng:l(y=>y.lng,!1)??i.lng,elevationM:_?_.elevationM:l(y=>y.elevationM,!1)??i.elevationM,headingDeg:u??i.headingDeg,pitchDeg:l(y=>y.pitchDeg,!0)??i.pitchDeg,rollDeg:l(y=>y.rollDeg??0,!0)??i.rollDeg,fovDeg:l(y=>y.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 Wo;for(const i of t.keyframes)e.addKeyframe(i.t,i.pose);return e}}class js{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(js.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?js.follow(this.followed[e],i.intensity,n.intensity,(n.t-i.t)/1e3,(t-i.t)/1e3):js.follow(this.followed[e],i.intensity,i.intensity,1,(t-i.t)/1e3);return{type:js.typeBetween(i,n,t,s),intensity:s,character:js.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=js.MAX_CHANGE_PER_S,o=n>0?(i-e)/n:0,c=u=>e+o*Math.min(Math.max(u,0),n);let l=t,h=0;for(let u=0;u<8&&h<s;u++){const d=c(h)-l;if(Math.abs(d)<1e-9){const y=h<n?o:0;if(Math.abs(y)<=a){const b=h<n?Math.min(s,n):s;l=c(b),h=b;continue}const M=Math.min(s,n);l+=Math.sign(y)*a*(M-h),h=M;continue}const f=Math.sign(d),p=h<n?o:0,v=a-f*p,m=v>0?h+Math.abs(d)/v:1/0,g=h<n?n:1/0,_=Math.min(s,m,g);l+=f*a*(_-h),h=_,_===m&&(l=c(h))}return Math.min(1,Math.max(0,l))}}function Be(r,t,e){return r+(t-r)*e}function m0(r,t,e){const i=((t-r)%360+540)%360-180;return((r+i*e)%360+360)%360}function Bv(r,t,e){return Math.max(t,Math.min(e,r))}function Hv(r=[],t=[],e){if(!(!r.length&&!t.length))return[...new Set([...r.map(i=>i.id),...t.map(i=>i.id)])].map(i=>{const n=r.find(c=>c.id===i),s=t.find(c=>c.id===i),a=n??{...s,density:0},o=s??{...n,density:0};return{...a,eastM:Be(a.eastM,o.eastM,e),northM:Be(a.northM,o.northM,e),baseM:Be(a.baseM,o.baseM,e),thicknessM:Be(a.thicknessM,o.thicknessM,e),widthM:Be(a.widthM,o.widthM,e),depthM:Be(a.depthM,o.depthM,e),rotationDeg:m0(a.rotationDeg,o.rotationDeg,e),density:Be(a.density,o.density,e),darkness:Be(a.darkness??0,o.darkness??0,e)}})}function Gv(r,t,e){if(r.cloudLayers===void 0&&t.cloudLayers===void 0)return;const i=Rl(r),n=Rl(t);return e>=1?n.map(a=>({...a})):[...new Set([...i.map(a=>a.id),...n.map(a=>a.id)])].map(a=>{const o=i.find(u=>u.id===a),c=n.find(u=>u.id===a),l=o??{...c,coverage:0},h=c??{...o,coverage:0};return{...l,instances:Hv(o?.instances,c?.instances,e),baseM:Be(l.baseM,h.baseM,e),thicknessM:Be(l.thicknessM,h.thicknessM,e),coverage:Be(l.coverage,h.coverage,e),sizeM:Be(l.sizeM,h.sizeM,e),density:Be(l.density,h.density,e),darkness:Be(l.darkness??r.cloudDarkness,h.darkness??t.cloudDarkness,e),iceCrystalAlignment:l.iceCrystalAlignment===void 0||h.iceCrystalAlignment===void 0?void 0:Be(l.iceCrystalAlignment,h.iceCrystalAlignment,e),windSpeed:l.windSpeed===void 0&&h.windSpeed===void 0?void 0:Be(l.windSpeed??r.windSpeed,h.windSpeed??t.windSpeed,e),windDirectionDeg:l.windDirectionDeg===void 0&&h.windDirectionDeg===void 0?void 0:m0(l.windDirectionDeg??r.windDirectionDeg,h.windDirectionDeg??t.windDirectionDeg,e)}})}function Vv(r,t,e){return{cloudLayers:Gv(r,t,e),cloudCover:Be(r.cloudCover,t.cloudCover,e),cloudDarkness:Be(r.cloudDarkness,t.cloudDarkness,e),highCloudCover:r.highCloudCover===void 0||t.highCloudCover===void 0?void 0:Be(r.highCloudCover,t.highCloudCover,e),iceCrystalAlignment:r.iceCrystalAlignment===void 0||t.iceCrystalAlignment===void 0?void 0:Be(r.iceCrystalAlignment,t.iceCrystalAlignment,e),lowerCloudCover:r.lowerCloudCover===void 0||t.lowerCloudCover===void 0?void 0:Be(r.lowerCloudCover,t.lowerCloudCover,e),cloudBaseM:r.cloudBaseM===void 0||t.cloudBaseM===void 0?void 0:Be(r.cloudBaseM,t.cloudBaseM,e),relativeHumidity:r.relativeHumidity===void 0||t.relativeHumidity===void 0?void 0:Be(r.relativeHumidity,t.relativeHumidity,e),precipitationType:e<1?r.precipitationType:t.precipitationType,precipitationIntensity:Be(r.precipitationIntensity,t.precipitationIntensity,e),windDirectionDeg:m0(r.windDirectionDeg,t.windDirectionDeg,e),windSpeed:Be(r.windSpeed,t.windSpeed,e),storm:e<1?r.storm:t.storm}}class Xo{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?Vv(i.weather,n.weather,Bv((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 js(this.keyframes)).at(t);if(!i)return e;const{type:n,intensity:s,character:a}=i,o=a>0?Math.min(1,s/a):n==="none"?0:1;return{...e,precipitationType:n,precipitationIntensity:a,precipitationAmount:o}}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 Xo;for(const i of t.keyframes)e.addKeyframe(i.t,i.weather);return e}}class Yo{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 Yo;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 Wv=100,Xv={kind:"none",volume:0,pitchHz:Wv};class Tn{constructor(t){this.entries=t}static empty(){return new Tn(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?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 Tn(new Map);return{recording:Tn.stripValue(t,[],e),provenance:e}}static restore(t,e){if(e.size===0)return t;const i=structuredClone(t);for(const n of e.paths()){const s=e.at(n),a=n.split("."),o=Tn.holderOf(i,a);if(!o)continue;const c=a[a.length-1],l=o[c];l!==void 0&&(s.of!==void 0&&JSON.stringify(s.of)!==JSON.stringify(l)||(o[c]={value:l,...s.basis==="stated"?{}:{basis:s.basis},...s.rationale===void 0?{}:{rationale:s.rationale}}))}return i}static isWrapper(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)&&"value"in t}static stripValue(t,e,i){return Tn.isWrapper(t)?(i.set(e.join("."),{basis:t.basis??"stated",...t.rationale===void 0?{}:{rationale:t.rationale},of:t.value}),Tn.stripValue(t.value,e,i)):Array.isArray(t)?t.map((n,s)=>Tn.stripValue(n,[...e,String(s)],i)):typeof t=="object"&&t!==null?Object.fromEntries(Object.entries(t).map(([n,s])=>[n,Tn.stripValue(s,[...e,n],i)])):t}static holderOf(t,e){let i=t;for(const n of e.slice(0,-1)){if(typeof i!="object"||i===null)return;i=i[n]}return typeof i=="object"&&i!==null?i:void 0}}function Hu(r){if(r.year!==void 0)return Date.UTC(r.year,(r.month??1)-1,r.day??1,r.hour??0,r.minute??0,r.second??0)}function Ef(r){return(((r.day??0)*24+(r.hour??0))*60+(r.minute??0))*6e4+(r.second??0)*1e3}const Yv=["year","month","day","hour","minute"],qv=["day","hour","minute"];function Af(r,t){return t.filter(e=>r[e]!==void 0).join(",")}function $v(r){if(r.durationSeconds!==void 0)return r.durationSeconds*1e3;if(!r.time||!r.endTime)return;const t=r.time.year!==void 0&&r.endTime.year!==void 0,e=t?Yv:qv,i=Af(r.time,e);if(!(i===""||i!==Af(r.endTime,e)))return t?Hu(r.endTime)-Hu(r.time):Ef(r.endTime)-Ef(r.time)}class Ql{constructor(t,e,i,n,s,a,o,c,l=[],h,u,d,f=[],p=[],v=[],m=[]){this.event=t,this.timeline=e,this.observerTrack=i,this.weatherTrack=n,this.soundTrack=s,this.observer=a,this.id=o,this.weather=c,this.decor=l,this.weatherSource=h,this.instrumentId=u,this.exposureSeconds=d,this.milestones=f,this.references=p,this.roads=v,this.traces=m}provenance=Tn.empty();loadIssues=[];account;sources;interpretation;sway;lightPollution;observerMap;iso;vehicle;get observerCount(){return 1+this.decor.filter(t=>t.kind==="observer").length}get exposure(){return this.exposureSeconds??this.instrument.exposureSeconds}get instrument(){return mi.byId(this.instrumentId)}static create(t,e,i){return new Ql({eventType:"sighting",time:t,place:e},new jl,new Wo,new Xo,new Yo,i)}}const Kv=0,Zv=0;function Ze(r,t){const e=r.observerTrack.getInterpolatedPoseAt(t);if(e)return e;const i=r.event.place?.[0];if(i)return{lat:i.lat,lng:i.lng,elevationM:Kv,headingDeg:void 0,pitchDeg:Zv,fovDeg:mi.fieldOfViewDeg(r.instrument)}}function io(r,t){return r.weatherTrack.getInterpolatedWeatherAt(t)??r.weather??p0}function uc(r,t){return r.weatherTrack.getActualWeatherAt(t)??r.weather??p0}function Jv(r,t){return r.soundTrack.getInterpolatedSoundAt(t)??Xv}class jv{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 Tg=["nw","n","ne","e","se","s","sw","w"],Qv=24,dc=8,t2=3,e2=8;function fc(r,t,e){const i=r.x-t.x,n=r.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 no(r){return{x:r.x+r.width/2,y:r.y+r.height/2}}const i2={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 pn{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-Qv}},o=no(t.bounds),c={};for(const l of Object.keys(a))c[l]=fc(a[l],o,t.angle);return c}static hitTestHandle(t,e,i=8,n=[...Tg,"rotate"]){const s=pn.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=((pn.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=no(t),a=fc(n,s,-e),{x:o,y:c,width:l,height:h}=t,u=i2[i];let d=o,f=c,p=o+l,v=c+h;return u.left&&(d=Math.min(a.x,p-dc)),u.right&&(p=Math.max(a.x,d+dc)),u.top&&(f=Math.min(a.y,v-dc)),u.bottom&&(v=Math.max(a.y,f+dc)),{x:d,y:f,width:p-d,height:v-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=pn.resizeBounds(t.bounds,t.angle,e,i);if(t.kind==="oval")return{...t,bounds:a};const o=n===0?1:a.width/n,c=s===0?1:a.height/s;return{...t,bounds:a,points:t.points.map(l=>({x:l.x*o,y:l.y*c}))}}static rotateShape(t,e){const i=no(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=no(t.bounds);return t.points.map(i=>fc({x:t.bounds.x+i.x,y:t.bounds.y+i.y},e,t.angle))}static hitTestVertex(t,e,i=e2){const n=pn.vertexPointsFor(t);let s,a=i;return n.forEach((o,c)=>{const l=Math.hypot(e.x-o.x,e.y-o.y);l<=a&&(a=l,s=c)}),s}static toLocalPoint(t,e){const i=no(t.bounds),n=fc(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?pn.toLocalPoint(t,i):u),s=Math.min(...n.map(u=>u.x)),a=Math.min(...n.map(u=>u.y)),o=Math.max(...n.map(u=>u.x)),c=Math.max(...n.map(u=>u.y)),l={x:t.bounds.x+s,y:t.bounds.y+a,width:o-s,height:c-a},h=n.map(u=>({x:u.x-s,y:u.y-a}));return{...t,bounds:l,points:h}}static insertVertexNear(t,e){const i=pn.toLocalPoint(t,e),{points:n}=t;let s=n.length-1,a=1/0;for(let c=0;c<n.length;c++){const l=n[c],h=n[(c+1)%n.length],u=pn.distanceToSegment(i,l,h);u<a&&(a=u,s=c)}const o=[...n.slice(0,s+1),i,...n.slice(s+1)];return{...t,points:o}}static distanceToSegment(t,e,i){const n=i.x-e.x,s=i.y-e.y,a=n*n+s*s,o=a===0?0:Math.max(0,Math.min(1,((t.x-e.x)*n+(t.y-e.y)*s)/a)),c=e.x+o*n,l=e.y+o*s;return Math.hypot(t.x-c,t.y-l)}static deleteVertex(t,e){return t.points.length<=t2?t:{...t,points:t.points.filter((i,n)=>n!==e)}}}const Gu=6,pc=Gu/2,Tf=20,Rf=24,Df=9,If=6,Cf=7,Pf=6,Jn=4;class qo{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,o=i+s/2,c=t.angle%(2*Math.PI)!==0,l=Math.hypot(n,s)/2,h=c?l:n/2,u=c?l:s/2,d=Math.max(n,s)/2,f=t.brightness??0,p=f>0?Math.max(d*(1+Df*f),Pf*f)-d:0,v=f>0?d*(1+Cf*f)-d:0,m=3*Rf*(t.blur??0)+1.5*Tf*t.haloScale,g=Math.max(p,v,0)+m+2;return{x:a-h-g,y:o-u-g,width:2*(h+g),height:2*(u+g)}}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(${(Rf*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,o=i+s/2,c=n+a/2,l=Math.max(s,a)/2,h=Math.max(l*(1+Df*e),Pf*e);if(h<=0)return;this.ctx.save(),this.ctx.globalCompositeOperation="lighter";const u=this.ctx.createRadialGradient(o,c,0,o,c,h);for(let d=0;d<=If;d++){const f=d/If,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(o,c,h,0,2*Math.PI),this.ctx.fill(),this.starPoints>0){const d=l*(1+Cf*e);this.ctx.lineWidth=Math.max(1,l*.12),this.ctx.lineCap="round";for(let f=0;f<this.starPoints;f++){const p=f/this.starPoints*Math.PI*2+this.roll,v=o+Math.cos(p)*d,m=c+Math.sin(p)*d,g=this.ctx.createLinearGradient(o,c,v,m);g.addColorStop(0,this.withAlpha(t.color,e*.55)),g.addColorStop(.35,this.withAlpha(t.color,e*.22)),g.addColorStop(1,this.withAlpha(t.color,0)),this.ctx.strokeStyle=g,this.ctx.beginPath(),this.ctx.moveTo(o,c),this.ctx.lineTo(v,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,o=s/2;this.ctx.ellipse(e+a,i+o,a,o,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,o)=>{o===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=Tf*t.haloScale,this.paintBase(t),this.ctx.restore()}paintSelectionHandles(t){this.paintHandleFrame(pn.handlePointsFor(t),{includeRotate:!0}),t.kind==="polygon"&&this.paintVertexHandles(t)}paintVertexHandles(t){this.ctx.fillStyle="#39f";for(const e of pn.vertexPointsFor(t))this.ctx.beginPath(),this.ctx.ellipse(e.x,e.y,Jn,Jn,0,0,2*Math.PI),this.ctx.fill()}paintMemberOutline(t){this.paintOutline(pn.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=qo.landmarkColour(s.residualDeg),o=s.selected?3:2;s.selected&&(n.strokeStyle="#fff",n.lineWidth=o+3,n.beginPath(),n.ellipse(s.picture.x,s.picture.y,Jn+2,Jn+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,Jn,Jn,0,0,2*Math.PI),n.fill()),n.strokeStyle=a,n.lineWidth=o,n.beginPath(),n.ellipse(s.picture.x,s.picture.y,Jn+2,Jn+2,0,0,2*Math.PI),n.stroke(),this.paintLabel(s.label,s.picture.x+Jn+5,s.picture.y-Jn-2,a)}i&&this.paintLabel(i,8,8,"#fff",13),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 o=a.measureText(t).width;a.fillStyle="rgba(0, 0, 0, 0.6)",a.fillRect(e-3,i-2,o+6,s+4),a.fillStyle=n,a.fillText(t,e,i),a.restore()}paintGroupHandles(t){this.paintHandleFrame(pn.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 Tg){const n=t[i];this.ctx.fillRect(n.x-pc,n.y-pc,Gu,Gu)}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,pc+1,pc+1,0,0,2*Math.PI),this.ctx.fill())}}const Lf=.05,Of=.08,Nf=2,Ff=3,n2=14,s2=.02;class a2{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}}Fa.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,Lf);for(const{param:s,ratio:a}of t.pitch)s.setTargetAtTime(Math.min(e.pitchHz*a,i.sampleRate/2-1),n,Lf)}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 o=t.createGain();return o.gain.value=0,a.connect(o).connect(s.gain),i.connect(n).connect(s).connect(this.output(t)),i.start(),a.start(),{key:e,nodes:[n,s,o],sources:[i,a],volumeParam:o.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 o=n.createGain();o.gain.value=0,a.connect(o).connect(this.output(n)),a.start(),this.voice={key:e,nodes:[o],sources:[a],volumeParam:o.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*Nf),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*Nf),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*Ff),t.sampleRate),i=e.getChannelData(0),n=Math.max(1,Math.floor(s2*t.sampleRate)),s=Math.round(Ff*n2);for(let a=0;a<s;a++){const o=Math.floor(Math.random()*i.length),c=.4+Math.random()*.6;for(let l=0;l<n&&o+l<i.length;l++)i[o+l]=Math.max(i[o+l],c*(1-l/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,Of/3);const n=i+Of;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 Gt{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=Gt.outline(Gt.BOOKMARK);static MILESTONES_ON=Gt.solid(Gt.BOOKMARK);static PICTURES_OFF=Gt.outline(`${Gt.PICTURE}${Gt.PICTURE_HILLS}`);static PICTURES_ON=Gt.solid(`${Gt.PICTURE}${Gt.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=Gt.outline(`${Gt.TRACE_LINE}${Gt.TRACE_MARK}`);static TRACES_ON=Gt.solid(`${Gt.TRACE_LINE}${Gt.TRACE_MARK}`);static MAP_OFF=Gt.outline(`${Gt.PIN}${Gt.PIN_HOLE}`);static MAP_ON=Gt.solid(`${Gt.PIN}${Gt.PIN_HOLE}`);static SHARE=Gt.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=Gt.svg("M15.4 7.4 14 6l-6 6 6 6 1.4-1.4L10.8 12z");static UNFOLDED=Gt.svg("M8.6 16.6 10 18l6-6-6-6-1.4 1.4 4.6 4.6z");static PLAY=Gt.svg("M7.4 5v14l11-7z");static PAUSE=Gt.svg("M6 5h4v14H6zM14 5h4v14h-4z");static VOLUME=Gt.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=Gt.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=Gt.svg("M5 5h5v2H7v3H5V5zm9 0h5v5h-2V7h-3V5zM5 14h2v3h3v2H5v-5zm12 0h2v5h-5v-2h3v-3z");static EXIT_FULLSCREEN=Gt.svg("M8 5h2v5H5V8h3V5zm6 0h2v3h3v2h-5V5zM5 14h5v5H8v-3H5v-2zm9 0h5v2h-3v3h-2v-5z")}function Oo(r){return[...r].sort((t,e)=>t.t-e.t)}function gh(r,t){let e;for(const i of Oo(r)){if(i.t>t)break;e=i}return e}const vh=Math.PI/180,mc=180/Math.PI;class Is{constructor(t,e,i){this.kind=t,this.canvasHeightPx=e,this.fovDeg=i;const n=i*vh/2;this.focalPx=t==="equidistant"?e/2/n:e/2/Math.tan(n)}focalPx;static of(t,e,i){return new Is(t.projection,e,i)}degToPx(t){const e=t*vh;return this.kind==="equidistant"?this.focalPx*e:2*this.focalPx*Math.tan(e/2)}pxToDeg(t){return this.kind==="equidistant"?t/this.focalPx*mc:2*Math.atan(t/(2*this.focalPx))*mc}angleDegToRadiusPx(t){const e=t*vh;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*mc:Math.atan(t/this.focalPx)*mc}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(De.angularWidthDeg(t))}}class an{static fovOf(t,e){return Ze(t,e)?.fovDeg??mi.fieldOfViewDeg(t.instrument)}static toAngular(t){this.eachKeyframe(t,(e,i)=>({...e,angular:i.ofBounds(e.bounds)}))}static toBounds(t){this.eachKeyframe(t,(e,i)=>{if(!e.angular)return e;const{width:n,height:s}=i.toBoundsSize(e.angular),a={x:e.bounds.x+(e.bounds.width-n)/2,y:e.bounds.y+(e.bounds.height-s)/2,width:n,height:s};if(e.kind!=="polygon")return{...e,bounds:a};const o=e.bounds.width===0?1:n/e.bounds.width,c=e.bounds.height===0?1:s/e.bounds.height;return{...e,bounds:a,points:e.points.map(l=>({x:l.x*o,y:l.y*c}))}})}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)<an.UNMOVED_PX&&Math.abs(s.y-e.bounds.y)<an.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=Is.of(t.instrument,De.CANVAS_HEIGHT_PX,this.fovOf(t,e));return this.aimFrom(t,n,Ze(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),o=e.radiusPxToAngleDeg(s.y-(n.y+n.height/2));return{azimuthDeg:((i.headingDeg+a)%360+360)%360,altitudeDeg:i.pitchDeg+o}}static toPosition(t){this.eachKeyframe(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 positionOf(t,e,i,n,s){if(s?.headingDeg===void 0)return;const a=this.frameCentre(t),o=this.shortestArc(e.azimuthDeg-s.headingDeg),c=e.altitudeDeg-s.pitchDeg;return{x:a.x+this.offAxisPx(n,o)-i.width/2,y:a.y-this.offAxisPx(n,c)-i.height/2}}static frameCentre(t){return{x:mi.frameWidthPx(t.instrument,De.CANVAS_HEIGHT_PX)/2,y:De.CANVAS_HEIGHT_PX/2}}static shortestArc(t){return(t%360+540)%360-180}static offAxisPx(t,e){return Math.abs(e)>=an.OFF_CANVAS_DEG?Math.sign(e)*an.OFF_CANVAS_PX:t.angleDegToRadiusPx(e)}static OFF_CANVAS_DEG=89;static OFF_CANVAS_PX=1e5;static reproject(t,e,i){const n=mi.frameWidthPx(e,De.CANVAS_HEIGHT_PX)/2,s=mi.frameWidthPx(t.instrument,De.CANVAS_HEIGHT_PX)/2,a=De.CANVAS_HEIGHT_PX/2;for(const o of[...t.timeline.allKeyframes]){const c=this.fovOf(t,o.t),l=i?.get(o.t)??c,h=Is.of(e,De.CANVAS_HEIGHT_PX,l),u=Is.of(t.instrument,De.CANVAS_HEIGHT_PX,c);t.timeline.addKeyframe(o.t,o.shapes.map(d=>{const{bounds:f}=d.shape,p=f.x+f.width/2-n,v=f.y+f.height/2-a,m=Math.hypot(p,v),g=m===0?1:u.angleDegToRadiusPx(h.radiusPxToAngleDeg(m))/m,_={...f,x:s+p*g-f.width/2,y:a+v*g-f.height/2};return{...d,shape:{...d.shape,bounds:_}}}))}this.toBounds(t)}static eachKeyframe(t,e){const{timeline:i}=t;for(const n of[...i.allKeyframes]){const s=Ze(t,n.t),a=this.fovOf(t,n.t),o=Is.of(t.instrument,De.CANVAS_HEIGHT_PX,a);i.addKeyframe(n.t,n.shapes.map(c=>({...c,shape:e(c.shape,o,s)})))}}}function r2(r){return Tn.restore(o2(r),r.provenance)}function o2(r){return an.toAngular(r),an.toAim(r),{version:1,id:r.id,time:r.event.time,endTime:r.event.endTime,durationSeconds:r.event.durationSeconds,utcOffsetHours:r.event.utcOffsetHours,timeZone:r.event.timeZone,place:r.event.place,observer:r.observer,account:r.account,sources:r.sources?.length?r.sources:void 0,sway:r.sway,vehicle:r.vehicle,description:r.event.description,tags:r.event.tags,timeline:r.timeline.toJSON(),observerTrack:r.observerTrack.toJSON(),weatherTrack:r.weatherTrack.toJSON(),soundTrack:r.soundTrack.toJSON(),weather:r.weather,decor:r.decor,milestones:r.milestones.length>0?r.milestones:void 0,references:r.references.length>0?r.references:void 0,roads:r.roads.length>0?r.roads:void 0,traces:r.traces.length>0?r.traces:void 0,weatherSource:r.weatherSource,instrument:r.instrumentId,exposureSeconds:r.exposureSeconds,iso:r.iso,lightPollution:r.lightPollution,observerMap:r.observerMap,interpretation:r.interpretation}}function c2(r){const{recording:t,provenance:e}=Tn.strip(r),i=l2(t);return i.provenance=e,i}function l2(r){const t=[],e=new Ql({eventType:"sighting",time:r.time,endTime:r.endTime,durationSeconds:r.durationSeconds,utcOffsetHours:r.utcOffsetHours,timeZone:r.timeZone,place:r.place,description:r.description,tags:r.tags},jl.fromJSON(r.timeline,t),r.observerTrack?Wo.fromJSON(r.observerTrack):new Wo,r.weatherTrack?Xo.fromJSON(r.weatherTrack):new Xo,r.soundTrack?Yo.fromJSON(r.soundTrack):new Yo,r.observer&&{id:r.observer.id,title:r.observer.title,lastName:r.observer.lastName,firstNames:r.observer.firstNames},r.id,r.weather,r.decor??[],r.weatherSource,r.instrument,r.exposureSeconds??r.observerTrack?.keyframes.map(i=>i.pose.exposureSeconds).find(i=>i!==void 0),Oo(r.milestones??[]),r.references??[],r.roads??[],r.traces??[]);return e.account=r.account,e.sources=r.sources,e.sway=r.sway,e.iso=r.iso,e.lightPollution=r.lightPollution,e.observerMap=r.observerMap,e.vehicle=r.vehicle,e.interpretation=r.interpretation,e.loadIssues=t,an.toBounds(e),an.toPosition(e),e}class Yr{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=Yr.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=>` ${Yr.text(n)}`);console.warn(`UFO@home: ${t.length} problem(s) in ${e??"this recording"}:
1365
1365
  ${i.join(`
1366
- `)}`)}}class Nn{constructor(t){this.format=t}issues(t){const e=[];return this.object(t,this.format,"",e),e}object(t,e,i,n){if(!Nn.isObject(t)){n.push({kind:"wrong-type",path:i||"(the file)",expected:"object",found:Nn.typeOf(t)});return}for(const[s,a]of Object.entries(t)){const o=i?`${i}.${s}`:s,c=e[s];c?this.field(a,c,o,n):n.push({kind:"unknown-key",path:o})}}field(t,e,i,n){if(Nn.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):Nn.isObject(t)||n.push({kind:"wrong-type",path:i,expected:"object",found:Nn.typeOf(t)});return;case"array":Array.isArray(t)?e.fields&&t.forEach((s,a)=>{const o=Nn.isStated(s)?s.value:s;this.object(o,e.fields,`${i}.${a}`,n)}):n.push({kind:"wrong-type",path:i,expected:"array",found:Nn.typeOf(t)});return;default:typeof t!==e.type&&n.push({kind:"wrong-type",path:i,expected:e.type,found:Nn.typeOf(t)})}}static isObject(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}static isStated(t){return Nn.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 Bn{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?Bn.travelDegOver(t,e,i,i+n*1e3)/s/Bn.PIXELS_PER_INSTANT:0,o=Bn.flashesOver(t,n)*Bn.INSTANTS_PER_FLASH,c=Math.ceil(Math.max(a,o));return c<2?1:Math.min(Bn.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 o=Bn.directionAt(a,e,i),c=Bn.directionAt(a,e,n),l=Math.min(1,Math.max(-1,o.x*c.x+o.y*c.y+o.z*c.z));s=Math.max(s,Math.acos(l)*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=Go(t,i),s=n.eastM,a=n.altitudeM-e,o=n.northM,c=Math.hypot(s,a,o);return c===0?{x:0,y:1,z:0}:{x:s/c,y:a/c,z:o/c}}}function Rg(r,t){for(const e of r){const i=e.toLowerCase().split("-")[0];if(t.includes(i))return i}return"en"}class Lr{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 Rs{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[Rs.base(i)];if(n)return n}const e=new Set(this.preferences.map(i=>Rs.base(i)));for(const[i,n]of Object.entries(t))if(n&&e.has(Rs.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(o=>o===i)??Object.keys(s).find(o=>Rs.base(o)===Rs.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 Dg=["en","fr","es","it"],h2={en:()=>rn(()=>Promise.resolve().then(()=>f2),void 0,import.meta.url).then(r=>r.ufoMessages_en),fr:()=>rn(()=>import("./UfoMessages_fr-BMafKxyw.js"),[],import.meta.url).then(r=>r.ufoMessages_fr),es:()=>rn(()=>import("./UfoMessages_es-8Us-3wIq.js"),[],import.meta.url).then(r=>r.ufoMessages_es),it:()=>rn(()=>import("./UfoMessages_it-C7cNoyQt.js"),[],import.meta.url).then(r=>r.ufoMessages_it)};function u2(r){return h2[r]()}function d2(r){switch(r){case"fr":return rn(()=>import("./SceneNames_fr-DYU3H8s1.js"),[],import.meta.url).then(t=>t.sceneNames_fr);case"es":return rn(()=>import("./SceneNames_es-DjVl7xge.js"),[],import.meta.url).then(t=>t.sceneNames_es);case"it":return rn(()=>import("./SceneNames_it-Box-aRN9.js"),[],import.meta.url).then(t=>t.sceneNames_it);default:return Promise.resolve(void 0)}}const Ig={play:"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",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",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:Yr.EN},f2=Object.freeze(Object.defineProperty({__proto__:null,ufoMessages_en:Ig},Symbol.toStringTag,{value:"Module"})),Cg=Math.PI/180,p2=180/Math.PI,m2=256,Pg=19,g2=1.25;function Lg(r,t){return 156543.03392*Math.cos(r*Cg)/2**t}function Og(r,t){return Lg(r,t)*m2}function v2(r,t){let e=0;for(;e<Pg&&Og(r,e+1)>=t;)e++;return e}function Ng(r,t){return Og(r,t)}function M2(r,t){const e=t*g2;let i=0;for(;i<Pg&&Lg(r,i)>e;)i++;return i}function ml(r){const t=r*Cg;return(1-Math.log(Math.tan(t)+1/Math.cos(t))/Math.PI)/2}function Fg(r,t,e){const i=2**e;return{x:(r+180)/360*i,y:ml(t)*i}}function Ug(r,t,e){const i=ml(r.north),n=ml(r.south);return{x:(t-r.west)/(r.east-r.west),y:(ml(e)-i)/(n-i)}}function x2(r,t,e){const{x:i,y:n}=Fg(r,t,e);return{x:Math.floor(i),y:Math.floor(n),z:e}}function y2(r){const t=2**r.z,e=r.x/t*360-180,i=(r.x+1)/t*360-180,n=Uf(r.y,t);return{south:Uf(r.y+1,t),north:n,west:e,east:i}}function Uf(r,t){const e=r/t;return Math.atan(Math.sinh(Math.PI*(1-2*e)))*p2}function kg(r,t,e,i){const n=x2(r,t,e),s=Math.floor(i/2),a=[];for(let l=-s;l<=s;l++)for(let h=-s;h<=s;h++)a.push({x:n.x+h,y:n.y+l,z:e});const o=a.map(y2),c={south:Math.min(...o.map(l=>l.south)),north:Math.max(...o.map(l=>l.north)),west:Math.min(...o.map(l=>l.west)),east:Math.max(...o.map(l=>l.east))};return{tiles:a,bounds:c}}const _2="#2ec4ff";class Aa{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=Ug(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??_2;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 o=this.toCanvas(t.bounds,t.position.lat,t.position.lng);a=n.reduce((c,l)=>Math.hypot(l.x-o.x,l.y-o.y)>Math.hypot(c.x-o.x,c.y-o.y)?l: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),o=Math.hypot(this.width,this.height),c=(i-90)*Math.PI/180,l=n*Math.PI/180;s.save(),s.beginPath(),s.moveTo(a.x,a.y),s.arc(a.x,a.y,o,c-l,c+l),s.closePath();const h=s.createRadialGradient(a.x,a.y,0,a.x,a.y,o);h.addColorStop(0,"rgba(255, 224, 130, 0.55)"),h.addColorStop(.35,"rgba(255, 224, 130, 0.22)"),h.addColorStop(1,"rgba(255, 224, 130, 0)"),s.fillStyle=h,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:Aa.MARKER_RADIUS_PX}),e.beginPath(),e.arc(n.x,n.y,Aa.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 o=Je(a.lat,a.lng,e.lat,e.lng);return Math.hypot(o.x,o.z)<=Aa.ON_MARKER_M});i.beginPath(),i.arc(n.x,n.y,s?Aa.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(Je(a,t.east,a,t.west).x)/this.width,l=Aa.SCALE_STEPS_M.find(f=>f/c<=this.width/3);if(l===void 0)return;const h=l/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+h,d),i.stroke(),i.lineWidth=1.5,i.strokeStyle="rgba(255, 255, 255, 0.95)",i.stroke(),i.textAlign="left",this.paintOutlinedText(l>=1e3?`${l/1e3} km`:`${l} 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 Xe{static MIN_ZOOM=.25;static MAX_ZOOM=64;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(Xe.MAX_ZOOM,Math.max(Xe.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=Xe.mercatorY01(e.north),s=Xe.mercatorY01(e.south),a=Xe.mercatorY01(i.north),o=Xe.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+o)/2-n)/(s-n)}keepInView(t,e,i){if(!this.changed)return!1;const n=this.boundsWithin(t),s=Xe.mercatorY01(n.north),a=Xe.mercatorY01(n.south),o=(e.lng-n.west)/(n.east-n.west),c=(Xe.mercatorY01(e.lat)-s)/(a-s);return o>=i&&o<=1-i&&c>=i&&c<=1-i?!1:(this.panBy(.5-o,.5-c),!0)}boundsWithin(t){if(!this.changed)return t;const e=.5/this.zoom,i=Xe.mercatorY01(t.north),n=Xe.mercatorY01(t.south),s=t.east-t.west;return{west:t.west+(this.centerX-e)*s,east:t.west+(this.centerX+e)*s,north:Xe.latitudeAt(i+(this.centerY-e)*(n-i)),south:Xe.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=Je(n,t.east,n,s).x;let o=a;for(const c of e){const{x:l,z:h}=Je(c.lat,c.lng,n,s),u=Math.max(Math.abs(l),Math.abs(h));u<=a*i&&(o=Math.max(o,u*1.15))}return o<=a?t:{north:xn(0,-o,n,s).lat,south:xn(0,o,n,s).lat,east:xn(o,0,n,s).lng,west:xn(-o,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=Xe.mercatorY01(t.north),s=Xe.mercatorY01(t.south);return{lat:Xe.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 Sn=256,kf=3,S2=32768;class b2{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(Je(i,t.east,i,t.west).x),a=Math.abs(Je(t.north,n,t.south,n).z),o=v2(i,Math.max(s,a)),{tiles:c}=kg(n,i,o,kf),l=kf*Sn,h=new Float32Array(l*l),u=c[0];await Promise.all(c.map(f=>this.decodeTileInto(f,u,h,l)));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 v=0;v<e.width;v++){const m=t.west+(t.east-t.west)*(v/(e.width-1));d[f*e.width+v]=this.sampleAt(p,m,o,u,h,l)}}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 o=await createImageBitmap(await a.blob()),c=document.createElement("canvas");c.width=Sn,c.height=Sn;const l=c.getContext("2d");if(!l)throw new Error("2D canvas context unavailable");l.drawImage(o,0,0);const{data:h}=l.getImageData(0,0,Sn,Sn),u=(t.x-e.x)*Sn,d=(t.y-e.y)*Sn;for(let f=0;f<Sn;f++)for(let p=0;p<Sn;p++){const v=(f*Sn+p)*4,m=h[v]*256+h[v+1]+h[v+2]/256-S2,g=u+p,_=d+f;i[_*n+g]=m}}sampleAt(t,e,i,n,s,a){const{x:o,y:c}=Fg(e,t,i),l=(o-n.x)*Sn,h=(c-n.y)*Sn,u=Math.max(0,Math.min(a-1,Math.floor(l))),d=Math.max(0,Math.min(a-1,Math.floor(h))),f=Math.min(a-1,u+1),p=Math.min(a-1,d+1),v=l-u,m=h-d,g=s[d*a+u],_=s[d*a+f],y=s[p*a+u],M=s[p*a+f],b=g+(_-g)*v,w=y+(M-y)*v;return b+(w-b)*m}}const gl=256,w2=5;async function E2(r,t,e,i){const n=(r.south+r.north)/2,s=(r.west+r.east)/2,a=Math.abs(Je(n,r.east,n,r.west).x),o=Math.abs(Je(r.north,s,r.south,s).z),c=Math.max(a,o),{zoom:l,gridSize:h}=A2(n,c,Math.max(t.width,t.height)),{tiles:u,bounds:d}=kg(s,n,l,h),f=h*gl,p=document.createElement("canvas");p.width=f,p.height=f;const v=p.getContext("2d");if(!v)throw new Error("2D canvas context unavailable");const m=u[0];await Promise.all(u.map(async M=>{const b=e(M),w=await i(b);if(!w.ok)throw new Error(`Imagery tile fetch failed (${w.status}): ${b}`);const T=await createImageBitmap(await w.blob());v.drawImage(T,(M.x-m.x)*gl,(M.y-m.y)*gl)}));const g=Math.min(Math.max(t.width,t.height),f);if(g===f)return{source:p,width:f,height:f,bounds:d};const _=document.createElement("canvas");_.width=g,_.height=g;const y=_.getContext("2d");if(!y)throw new Error("2D canvas context unavailable");return y.drawImage(p,0,0,f,f,0,0,g,g),{source:_,width:g,height:g,bounds:d}}function A2(r,t,e){let i=M2(r,t/Math.max(1,e)),n=zf(r,i,t);for(;n>w2&&i>0;)i--,n=zf(r,i,t);return{zoom:i,gridSize:n,mPerPixel:Ng(r,i)/gl}}function zf(r,t,e){const i=Math.ceil(e/2/Ng(r,t));return Math.max(3,2*i+1)}class T2{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 E2(t,e,i=>this.tileUrlTemplate.replace("{z}",String(i.z)).replace("{y}",String(i.y)).replace("{x}",String(i.x)),this.fetchImpl)}}class Fn{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;static ENDPOINTS=["https://overpass-api.de/api/interpreter","https://overpass.kumi.systems/api/interpreter","https://overpass.private.coffee/api/interpreter"];fetchImpl;endpoints;constructor(t={}){this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.endpoints=t.endpoints??Fn.ENDPOINTS}static queue=Promise.resolve();static RETRY_MS=4e3;async getRoads(t){const e=`${t.south},${t.west},${t.north},${t.east}`,i=`[out:json][timeout:30];way["highway"~"^(${Fn.DRIVABLE.join("|")})$"](${e});out geom;`;return this.waysFrom(await this.queued(()=>this.ask(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:Fn.surfaceOf(s),widthM:Fn.widthOf(s),points:n.map(a=>({lat:a.lat,lng:a.lon}))})}return e}queued(t){const e=Fn.queue.then(t,t);return Fn.queue=e.catch(()=>{}),e}async ask(t){let e;for(const i of this.endpoints)for(let n=0;n<2;n++){try{const s=await this.fetchImpl(`${i}?data=${encodeURIComponent(t)}`);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,Fn.RETRY_MS))}throw e??new Error("No Overpass instance answered")}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:Fn.WIDTH_M[t.highway]??Fn.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 Mh="https://ufoathome.org/roads/index.json";class g0{attributionRead;contemporaryRead;fetchImpl;indexUrls;fallback;index;constructor(t={}){this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.indexUrls=t.indexUrls??g0.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(){return this.index??=this.fetchFirstAvailable(),this.index}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.89.2")}`,e=typeof location>"u"?void 0:new URL("/roads/index.json",location.href).href;return(e&&e!==Mh?[e,Mh]:[Mh]).map(i=>i+t)}}function R2(){return{elevation:new b2,imagery:zg(),roads:D2()}}function zg(){return new T2}function D2(){return new g0({fallback:new Fn})}const I2=new Set,Or="show-observer-map",Nr="hide-milestones";class fe extends HTMLElement{static get observedAttributes(){return["src",Or,Nr]}shadow;stageElement;canvas;canvasRenderer;tooltip;toolbar;issuesBox;issuesButton;issuesPanel;playPauseButton;static OBSERVER_MAP_MIN_SPAN_M=400;static OBSERVER_MAP_MARGIN=.6;static OBSERVER_MAP_IMAGERY_PX=768;fullscreenButton;cornerButtons;observerMapButton;referencesButton;tracesButton;tracesShownState=!0;referenceOpacityInput;referencesShownState=!0;referenceOpacityTouched=!1;milestonesButton;observerMapPanel;observerMapCanvas;observerMapRenderer;mapZoomInButton;mapZoomOutButton;mapFitButton;observerMapView=new Xe;observerMapDrag;suppressObserverMapClick=!1;observerMapImageryTimer;observerPlacing=!1;seekInput;playbackFlash;milestoneMarks;milestoneCaption;timeStartLabel;timeEndLabel;timePill;muteButton;volumeInput;controlsRow;momentsBox;momentsButton;momentsCurrent;momentsMenu;moreButton;controlsRight;seekSegments;seekDot;seekPreview;seekPreviewCanvas;seekPreviewTitle;seekPreviewTime;observerPath;observerMapBounds;observerMapImagery;observerMapImageryBounds;observerMapImageryViewWidth=0;observerMapImageryLoading=!1;observerMapImageryCredit;observerMapImageryFailed=!1;creditShownExternally=!1;lookYawDeg=0;lookPitchDeg=0;milestonesShown=!0;currentSighting=Ql.create();issues=[];issueCheck=0;sightingAudio=new a2;soundPreview;player;loopEnabled=!1;playbackBeforeClick;highlightedSourceIds=new Set;paintsShapes=!0;steadyObserver=!1;selectionShown=!0;overlayPainter;enableClickToPlay=!0;fullscreenTarget;messages=Ig;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");fe.setIcon(this.moreButton,t?Gt.UNFOLDED:Gt.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)<fe.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>=Xe.MAX_ZOOM,this.mapZoomOutButton.disabled=this.observerMapView.zoomFactor<=Xe.MIN_ZOOM,this.paintObserverMap(this.currentTime),this.scheduleObserverMapImagery()}scheduleObserverMapImagery(){this.observerMapImageryTimer===void 0&&(this.observerMapImageryTimer=setTimeout(()=>{this.observerMapImageryTimer=void 0,this.loadObserverMapImagery()},fe.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=Xe.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>${Cv}</style>${Iv}`,this.shadow.appendChild(t.content.cloneNode(!0)),this.stageElement=this.shadow.getElementById("stage"),this.canvas=this.shadow.getElementById("canvas"),this.canvasRenderer=new qo(this.canvas.getContext("2d")),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",e=>{e.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.milestonesButton=this.shadow.getElementById("milestones"),this.observerMapPanel=this.shadow.getElementById("observer-map-panel"),this.observerMapCanvas=this.shadow.getElementById("observer-map-canvas"),this.observerMapRenderer=new Aa(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.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",e=>{e.key!=="Enter"&&e.key!==" "||(e.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.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.seekInput.addEventListener("pointerdown",e=>{this.suspendForScrub(),this.seekSnapArmed=!0,this.nameMarkUnder(e),this.beginTouchScrub(e)}),this.seekInput.addEventListener("pointerup",e=>{this.seekSnapArmed=!1,this.endTouchScrub(e)}),this.seekInput.addEventListener("pointercancel",e=>this.endTouchScrub(e)),this.seekInput.addEventListener("pointermove",e=>{this.nameMarkUnder(e),this.hoverSeek(e),this.touchScrub(e)}),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 e of["touchend","click"])this.stageElement.addEventListener(e,()=>this.sightingAudio.resume(),!0);this.stageElement.addEventListener("pointermove",()=>this.touchedStage()),this.canvas.addEventListener("click",e=>{if(this.enableClickToPlay){if(this.tapRevealedOnly){this.tapRevealedOnly=!1;return}e.detail<=1&&(this.playbackBeforeClick={state:this.playbackState,time:this.currentTime}),this.togglePlayPause()}}),this.canvas.addEventListener("dblclick",e=>{this.enableClickToPlay&&(e.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.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.controlsFitObserver?.disconnect(),this.controlsMutations?.disconnect(),this.exitSimulatedFullscreen(),this.sightingAudio.dispose()}attributeChangedCallback(t,e,i){t==="src"&&i&&i!==e&&this.isConnected&&this.loadFromSrc(i),t===Or&&this.applyObserverMapDefault(),t===Nr&&this.setMilestonesShown(!this.hasAttribute(Nr))}async loadFromSrc(t){this.sightingData=await Ag.json(t)}get sightingData(){return r2(this.currentSighting)}set sightingData(t){this.player.stop(),this.soundPreview=void 0,this.sightingAudio.silence(),this.currentSighting=c2(t),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.updateTimeLabels(),this.updatePlayPauseButton(),this.refresh(),this.applyObserverMapDefault()}get recordingIssues(){return this.issues}async reportIssues(t,e){const i=++this.issueCheck;let n=[];try{const{default:s}=await rn(async()=>{const{default:a}=await import("./sightingSchema-Bsub_0vA.js");return{default:a}},[],import.meta.url);n=new Nn(s).issues(t)}catch{}i===this.issueCheck&&(this.issues=[...n,...e.loadIssues],Yr.warn(this.issues,e.id),this.renderIssues(),this.dispatchEvent(new CustomEvent(C2,{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=Yr.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(){this.player.seekableDuration<=0||this.playbackState==="playing"||this.togglePlayPause()}pause(){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.updateTimeLabels(),this.seekInput.max=String(this.player.seekableDuration),this.refreshMilestoneMarks(),this.updateMilestonesButton(),this.updateObserverMap(),this.updateReferences(),this.updateTracesButton(),this.player.seek(this.player.time)}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)}toggleReferences(){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)),this.updateReferencesButton()}updateReferencesButton(){const t=this.currentSighting.references.length>0;this.referencesButton.hidden=!t,this.referenceOpacityInput.hidden=!t||!this.referencesShownState,this.referencesButton.setAttribute("aria-pressed",String(this.referencesShownState)),fe.setIcon(this.referencesButton,this.referencesShownState?Gt.PICTURES_ON:Gt.PICTURES_OFF);const e=this.referencesShownState?this.messages.hideReferences:this.messages.showReferences;this.referencesButton.title=e,this.referencesButton.setAttribute("aria-label",e),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)),fe.setIcon(this.tracesButton,this.tracesShownState?Gt.TRACES_ON:Gt.TRACES_OFF);const t=this.tracesShownState?this.messages.hideTraces:this.messages.showTraces;this.tracesButton.title=t,this.tracesButton.setAttribute("aria-label",t)}dispatchReferenceView(){this.dispatchEvent(new CustomEvent("referenceview",{detail:{shown:this.referencesShown,opacity:this.referenceOpacity}}))}refreshMilestoneMarks(){const t=this.player.seekableDuration,e=t>0?Oo(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),o=a?`${s} — ${a}`:s;return n.title=o,n.setAttribute("aria-label",o),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)??"",o=this.said.read(i.note);return s.textContent=o?`${a} — ${o}`: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,o)=>a-o):[],Math.max(t,0)];this.seekSegmentList=[];const s=[];for(let a=0;a<n.length-1;a++){const o=document.createElement("div");o.className="seek-segment",o.style.flexGrow=String(Math.max(n[a+1]-n[a],1));const c=document.createElement("i");c.className="seek-hover";const l=document.createElement("i");l.className="seek-played",o.append(c,l),s.push(o),this.seekSegmentList.push({start:n[a],end:n[a+1],element:o,played:l,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}%`}paintSeekProgress(t){for(const i of this.seekSegmentList)i.played.style.width=fe.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=fe.fillOf(f,s),f.element.classList.toggle("hovered",s>=f.start&&(s<f.end||p===a))});const o=this.milestonesShown?this.sighting.milestones:[],c=o.length>0?gh(o,s):void 0,l=c?this.said.read(c.label)??"":"",h=c?this.said.read(c.note):void 0,u=h?`${l} — ${h}`:l;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)}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=fe.MARK_SNAP_PX/i*e;let s;for(const a of this.milestoneMarks.children){const o=Number(a.dataset.t);Math.abs(o-t)>n||(!s||Math.abs(o-t)<Math.abs(s.t-t))&&(s={t:o,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?gh(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=Bn.windowEndingAt(t,this.currentSighting.exposure??0);if(e.ms<fe.SHORTEST_VISIBLE_EXPOSURE_MS)return[t];const i=Math.min(fe.MAX_EXPOSURE_STEPS,Math.max(2,Math.round(e.ms/fe.SHORTEST_VISIBLE_EXPOSURE_MS))),n=Math.ceil(this.travelPxOver(e.fromMs,e.ms)/fe.EXPOSURE_STEP_PX),s=Math.min(fe.MAX_TRAVEL_STEPS,Math.max(i,n)),a=[];for(let o=0;o<s;o++)a.push(e.fromMs+e.ms*o/(s-1));return a}travelPxOver(t,e){const i=this.shapesAt(t),n=this.shapesAt(t+e);let s=0;for(const[a,o]of i){const c=n.get(a);if(!c)continue;const l=c.bounds.x+c.bounds.width/2-(o.bounds.x+o.bounds.width/2),h=c.bounds.y+c.bounds.height/2-(o.bounds.y+o.bounds.height/2);s=Math.max(s,Math.hypot(l,h))}return s}shapeAt(t,e,i){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=mi.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:I2;this.canvasRenderer.setStarPoints(mi.starPointsOf(this.sighting.instrument));const n=(Ze(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 o of s)for(const[,c]of o.shapes){const l=o.share,h=l===1?c:{...c,transparency:1-(1-c.transparency)*l};this.canvasRenderer.paintShape(this.shifted(h,a))}for(const[o,c]of s[0].shapes)!this.selectionShown||!i.has(o)||(this.paintsShapes?i.size===1?this.canvasRenderer.paintShape({...c,selected:!0}):this.canvasRenderer.paintMemberOutline(c):this.canvasRenderer.paintSelectionOnly(this.shifted(c,a)));if(this.selectionShown&&i.size>1){const o=pn.groupBoundsFor([...e].filter(([c])=>i.has(c)).map(([,c])=>c.bounds));this.canvasRenderer.paintGroupHandles(o)}this.overlayPainter?.(this.canvasRenderer),this.mapShapeBounds=s.flatMap(o=>[...o.shapes.values()].filter(c=>c.transparency<1).map(c=>this.shifted(c,a).bounds)),this.keepObserverMapClear(),this.seekInput.value=String(t),this.paintSeekProgress(t),this.timeStartLabel.textContent=this.formatPosition(t),this.showMilestoneAt(t),this.paintObserverMap(t),this.playbackState==="playing"?(this.soundPreview=void 0,this.sightingAudio.setSound(Jv(this.currentSighting,t))):this.soundPreview?this.sightingAudio.setSound(this.soundPreview):this.sightingAudio.silence(),this.updatePlayPauseButton(),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 jv(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*fe.SEEK_KEY_STEP_MS)))}else t.key===" "&&(t.preventDefault(),this.togglePlayPause())};togglePlayPause(){this.player.seekableDuration<=0||(this.player.playbackState==="playing"?(this.player.pause(),this.soundPreview=void 0,this.sightingAudio.silence(),this.refresh()):(this.sightingAudio.resume(),this.player.play()),this.updatePlayPauseButton(),this.flashPlayback())}flashPlayback(){const t=this.playbackFlash;t.innerHTML=this.player.playbackState==="playing"?Gt.PLAY:Gt.PAUSE,t.classList.remove("flashing"),t.offsetWidth,t.classList.add("flashing")}static icons=new WeakMap;static setIcon(t,e){fe.icons.get(t)!==e&&(fe.icons.set(t,e),t.innerHTML=e)}set captionHeld(t){this.stageElement.classList.toggle("caption-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},fe.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,fe.setIcon(this.playPauseButton,t?Gt.PAUSE:Gt.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}}))}observerMapAsked=!1;applyObserverMapDefault(){const t=this.getAttribute(Or),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;fe.setIcon(this.observerMapButton,t?Gt.MAP_ON:Gt.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=Pr.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=Xe.including(this.observerPath.boundsAround(fe.OBSERVER_MAP_MIN_SPAN_M,fe.OBSERVER_MAP_MARGIN),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.observerMapImageryNeededFor(t))return;const e=this.observerMapView.changed,i=e?Xe.expand(t,fe.OBSERVER_MAP_IMAGERY_AHEAD):t,n=fe.OBSERVER_MAP_IMAGERY_PX*(e?1+2*fe.OBSERVER_MAP_IMAGERY_AHEAD:1);this.observerMapImageryBounds=i,this.observerMapImageryViewWidth=t.east-t.west,this.observerMapImageryLoading=!0;const s=zg();try{const a=await s.getImageryTexture(i,{width:n,height:n});if(this.observerMapImageryBounds!==i)return;this.observerMapImagery=a,this.observerMapImageryCredit=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?Xe.expand(t,fe.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}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=(l,h,u)=>{for(const d of e)if(!(d.x+d.width<l-u||d.x>h+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=fe.OBSERVER_MAP_CLEARANCE_PX,o=i(...n,0),c=i(...s,0);if(this.observerMapPanel.classList.toggle("subject-overlap",o&&c&&!this.observerMapAsked),this.observerMapPanel.classList.contains("on-the-left")){!o&&(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=Ze(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},fe.OBSERVER_MAP_FOLLOW_MARGIN)&&this.scheduleObserverMapImagery();const i=this.currentSighting.instrument,n=[],s=this.currentSighting.milestones.length>0?gh(this.currentSighting.milestones,t):void 0;for(const a of this.milestonesShown?Oo(this.currentSighting.milestones):[]){const o=Ze(this.currentSighting,a.t);o?.lat===void 0||o.lng===void 0||n.push({label:this.said.read(a.label)??"",note:this.said.read(a.note),t:a.t,lat:o.lat,lng:o.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?Is.of(i,this.canvas.height,e.fovDeg).halfWidthAngleDeg(mi.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,Oo(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,fe.setIcon(this.milestonesButton,this.milestonesShown?Gt.MILESTONES_ON:Gt.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=Ze(this.currentSighting,0);return e?.lat===void 0||e.lng===void 0?[]:this.currentSighting.decor.filter(i=>i.kind!=="crop").map(i=>{const n=Go(i,t),{lat:s,lng:a}=xn(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=Ze(this.currentSighting,this.currentTime),s=Is.of(this.currentSighting.instrument,this.canvas.height,n?.fovDeg??60);return{x:-s.angleDegToRadiusPx(e),y:s.angleDegToRadiusPx(i)}}gaitAt(t){return be.bodyAt(this.currentSighting,t,this.steadyObserver)}mutedState=!1;get muted(){return this.mutedState}set muted(t){t!==this.mutedState&&(this.mutedState=t,!t&&this.volumeState===0&&(this.volumeState=fe.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.muted=!this.mutedState}updateMuteButton(){fe.setIcon(this.muteButton,this.mutedState?Gt.MUTED:Gt.VOLUME);const t=this.mutedState?this.messages.unmute:this.messages.mute;this.muteButton.title=t,this.muteButton.setAttribute("aria-label",t),this.muteButton.setAttribute("aria-pressed",String(this.mutedState)),this.volumeInput.value=String(this.level)}updateFullscreenButton(){const t=this.simulatedFullscreen||document.fullscreenElement===this.fullscreenTarget;fe.setIcon(this.fullscreenButton,t?Gt.EXIT_FULLSCREEN:Gt.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 Rs(Lr.preferencesFor(this))}saidTexts;async loadLocaleMessages(){const t=Rg(Lr.preferencesFor(this),Dg);if(t===this.messagesLanguage||t==="en"&&this.messagesLanguage===void 0)return;this.messagesLanguage=t;const e=await u2(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=$v(t);this.realDurationMs=e!==void 0&&e>0?e:void 0,this.realStartMs=t.time?Hu(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.updateTimeLabelTitles()}formatPosition(t){if(this.realDurationMs===void 0)return gc(t);const e=this.currentSighting.timeline.duration,i=e>0&&t<=e?t/e*this.realDurationMs:t;return this.canShowClockTime?Hf(Bf(this.realStartMs+i)):gc(i)}formatEndOfTimeline(){return this.realDurationMs===void 0?gc(this.currentSighting.timeline.duration):this.canShowClockTime?Hf(Bf(this.realStartMs+this.realDurationMs)):gc(this.realDurationMs)}}function Bf(r){const t=new Date(r);return{hour:t.getUTCHours(),minute:t.getUTCMinutes(),second:t.getUTCSeconds()}}function Hf(r){if(r.hour===void 0)return"0:00";const t=e=>String(e).padStart(2,"0");return r.second?`${t(r.hour)}:${t(r.minute??0)}:${t(r.second)}`:`${t(r.hour)}:${t(r.minute??0)}`}function gc(r){const t=Math.round(r/1e3),e=Math.floor(t/60),i=t%60;return`${e}:${String(i).padStart(2,"0")}`}const Vu="rr0-ufo";function Bg(){customElements.get(Vu)||customElements.define(Vu,fe)}const C2="recordingissues";/**
1366
+ `)}`)}}class Nn{constructor(t){this.format=t}issues(t){const e=[];return this.object(t,this.format,"",e),e}object(t,e,i,n){if(!Nn.isObject(t)){n.push({kind:"wrong-type",path:i||"(the file)",expected:"object",found:Nn.typeOf(t)});return}for(const[s,a]of Object.entries(t)){const o=i?`${i}.${s}`:s,c=e[s];c?this.field(a,c,o,n):n.push({kind:"unknown-key",path:o})}}field(t,e,i,n){if(Nn.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):Nn.isObject(t)||n.push({kind:"wrong-type",path:i,expected:"object",found:Nn.typeOf(t)});return;case"array":Array.isArray(t)?e.fields&&t.forEach((s,a)=>{const o=Nn.isStated(s)?s.value:s;this.object(o,e.fields,`${i}.${a}`,n)}):n.push({kind:"wrong-type",path:i,expected:"array",found:Nn.typeOf(t)});return;default:typeof t!==e.type&&n.push({kind:"wrong-type",path:i,expected:e.type,found:Nn.typeOf(t)})}}static isObject(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}static isStated(t){return Nn.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 Bn{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?Bn.travelDegOver(t,e,i,i+n*1e3)/s/Bn.PIXELS_PER_INSTANT:0,o=Bn.flashesOver(t,n)*Bn.INSTANTS_PER_FLASH,c=Math.ceil(Math.max(a,o));return c<2?1:Math.min(Bn.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 o=Bn.directionAt(a,e,i),c=Bn.directionAt(a,e,n),l=Math.min(1,Math.max(-1,o.x*c.x+o.y*c.y+o.z*c.z));s=Math.max(s,Math.acos(l)*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=Go(t,i),s=n.eastM,a=n.altitudeM-e,o=n.northM,c=Math.hypot(s,a,o);return c===0?{x:0,y:1,z:0}:{x:s/c,y:a/c,z:o/c}}}function Rg(r,t){for(const e of r){const i=e.toLowerCase().split("-")[0];if(t.includes(i))return i}return"en"}class Lr{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 Rs{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[Rs.base(i)];if(n)return n}const e=new Set(this.preferences.map(i=>Rs.base(i)));for(const[i,n]of Object.entries(t))if(n&&e.has(Rs.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(o=>o===i)??Object.keys(s).find(o=>Rs.base(o)===Rs.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 Dg=["en","fr","es","it"],h2={en:()=>rn(()=>Promise.resolve().then(()=>f2),void 0,import.meta.url).then(r=>r.ufoMessages_en),fr:()=>rn(()=>import("./UfoMessages_fr-BMafKxyw.js"),[],import.meta.url).then(r=>r.ufoMessages_fr),es:()=>rn(()=>import("./UfoMessages_es-8Us-3wIq.js"),[],import.meta.url).then(r=>r.ufoMessages_es),it:()=>rn(()=>import("./UfoMessages_it-C7cNoyQt.js"),[],import.meta.url).then(r=>r.ufoMessages_it)};function u2(r){return h2[r]()}function d2(r){switch(r){case"fr":return rn(()=>import("./SceneNames_fr-DYU3H8s1.js"),[],import.meta.url).then(t=>t.sceneNames_fr);case"es":return rn(()=>import("./SceneNames_es-DjVl7xge.js"),[],import.meta.url).then(t=>t.sceneNames_es);case"it":return rn(()=>import("./SceneNames_it-Box-aRN9.js"),[],import.meta.url).then(t=>t.sceneNames_it);default:return Promise.resolve(void 0)}}const Ig={play:"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",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",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:Yr.EN},f2=Object.freeze(Object.defineProperty({__proto__:null,ufoMessages_en:Ig},Symbol.toStringTag,{value:"Module"})),Cg=Math.PI/180,p2=180/Math.PI,m2=256,Pg=19,g2=1.25;function Lg(r,t){return 156543.03392*Math.cos(r*Cg)/2**t}function Og(r,t){return Lg(r,t)*m2}function v2(r,t){let e=0;for(;e<Pg&&Og(r,e+1)>=t;)e++;return e}function Ng(r,t){return Og(r,t)}function M2(r,t){const e=t*g2;let i=0;for(;i<Pg&&Lg(r,i)>e;)i++;return i}function ml(r){const t=r*Cg;return(1-Math.log(Math.tan(t)+1/Math.cos(t))/Math.PI)/2}function Fg(r,t,e){const i=2**e;return{x:(r+180)/360*i,y:ml(t)*i}}function Ug(r,t,e){const i=ml(r.north),n=ml(r.south);return{x:(t-r.west)/(r.east-r.west),y:(ml(e)-i)/(n-i)}}function x2(r,t,e){const{x:i,y:n}=Fg(r,t,e);return{x:Math.floor(i),y:Math.floor(n),z:e}}function y2(r){const t=2**r.z,e=r.x/t*360-180,i=(r.x+1)/t*360-180,n=Uf(r.y,t);return{south:Uf(r.y+1,t),north:n,west:e,east:i}}function Uf(r,t){const e=r/t;return Math.atan(Math.sinh(Math.PI*(1-2*e)))*p2}function kg(r,t,e,i){const n=x2(r,t,e),s=Math.floor(i/2),a=[];for(let l=-s;l<=s;l++)for(let h=-s;h<=s;h++)a.push({x:n.x+h,y:n.y+l,z:e});const o=a.map(y2),c={south:Math.min(...o.map(l=>l.south)),north:Math.max(...o.map(l=>l.north)),west:Math.min(...o.map(l=>l.west)),east:Math.max(...o.map(l=>l.east))};return{tiles:a,bounds:c}}const _2="#2ec4ff";class Aa{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=Ug(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??_2;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 o=this.toCanvas(t.bounds,t.position.lat,t.position.lng);a=n.reduce((c,l)=>Math.hypot(l.x-o.x,l.y-o.y)>Math.hypot(c.x-o.x,c.y-o.y)?l: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),o=Math.hypot(this.width,this.height),c=(i-90)*Math.PI/180,l=n*Math.PI/180;s.save(),s.beginPath(),s.moveTo(a.x,a.y),s.arc(a.x,a.y,o,c-l,c+l),s.closePath();const h=s.createRadialGradient(a.x,a.y,0,a.x,a.y,o);h.addColorStop(0,"rgba(255, 224, 130, 0.55)"),h.addColorStop(.35,"rgba(255, 224, 130, 0.22)"),h.addColorStop(1,"rgba(255, 224, 130, 0)"),s.fillStyle=h,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:Aa.MARKER_RADIUS_PX}),e.beginPath(),e.arc(n.x,n.y,Aa.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 o=Je(a.lat,a.lng,e.lat,e.lng);return Math.hypot(o.x,o.z)<=Aa.ON_MARKER_M});i.beginPath(),i.arc(n.x,n.y,s?Aa.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(Je(a,t.east,a,t.west).x)/this.width,l=Aa.SCALE_STEPS_M.find(f=>f/c<=this.width/3);if(l===void 0)return;const h=l/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+h,d),i.stroke(),i.lineWidth=1.5,i.strokeStyle="rgba(255, 255, 255, 0.95)",i.stroke(),i.textAlign="left",this.paintOutlinedText(l>=1e3?`${l/1e3} km`:`${l} 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 Xe{static MIN_ZOOM=.25;static MAX_ZOOM=64;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(Xe.MAX_ZOOM,Math.max(Xe.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=Xe.mercatorY01(e.north),s=Xe.mercatorY01(e.south),a=Xe.mercatorY01(i.north),o=Xe.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+o)/2-n)/(s-n)}keepInView(t,e,i){if(!this.changed)return!1;const n=this.boundsWithin(t),s=Xe.mercatorY01(n.north),a=Xe.mercatorY01(n.south),o=(e.lng-n.west)/(n.east-n.west),c=(Xe.mercatorY01(e.lat)-s)/(a-s);return o>=i&&o<=1-i&&c>=i&&c<=1-i?!1:(this.panBy(.5-o,.5-c),!0)}boundsWithin(t){if(!this.changed)return t;const e=.5/this.zoom,i=Xe.mercatorY01(t.north),n=Xe.mercatorY01(t.south),s=t.east-t.west;return{west:t.west+(this.centerX-e)*s,east:t.west+(this.centerX+e)*s,north:Xe.latitudeAt(i+(this.centerY-e)*(n-i)),south:Xe.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=Je(n,t.east,n,s).x;let o=a;for(const c of e){const{x:l,z:h}=Je(c.lat,c.lng,n,s),u=Math.max(Math.abs(l),Math.abs(h));u<=a*i&&(o=Math.max(o,u*1.15))}return o<=a?t:{north:xn(0,-o,n,s).lat,south:xn(0,o,n,s).lat,east:xn(o,0,n,s).lng,west:xn(-o,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=Xe.mercatorY01(t.north),s=Xe.mercatorY01(t.south);return{lat:Xe.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 Sn=256,kf=3,S2=32768;class b2{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(Je(i,t.east,i,t.west).x),a=Math.abs(Je(t.north,n,t.south,n).z),o=v2(i,Math.max(s,a)),{tiles:c}=kg(n,i,o,kf),l=kf*Sn,h=new Float32Array(l*l),u=c[0];await Promise.all(c.map(f=>this.decodeTileInto(f,u,h,l)));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 v=0;v<e.width;v++){const m=t.west+(t.east-t.west)*(v/(e.width-1));d[f*e.width+v]=this.sampleAt(p,m,o,u,h,l)}}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 o=await createImageBitmap(await a.blob()),c=document.createElement("canvas");c.width=Sn,c.height=Sn;const l=c.getContext("2d");if(!l)throw new Error("2D canvas context unavailable");l.drawImage(o,0,0);const{data:h}=l.getImageData(0,0,Sn,Sn),u=(t.x-e.x)*Sn,d=(t.y-e.y)*Sn;for(let f=0;f<Sn;f++)for(let p=0;p<Sn;p++){const v=(f*Sn+p)*4,m=h[v]*256+h[v+1]+h[v+2]/256-S2,g=u+p,_=d+f;i[_*n+g]=m}}sampleAt(t,e,i,n,s,a){const{x:o,y:c}=Fg(e,t,i),l=(o-n.x)*Sn,h=(c-n.y)*Sn,u=Math.max(0,Math.min(a-1,Math.floor(l))),d=Math.max(0,Math.min(a-1,Math.floor(h))),f=Math.min(a-1,u+1),p=Math.min(a-1,d+1),v=l-u,m=h-d,g=s[d*a+u],_=s[d*a+f],y=s[p*a+u],M=s[p*a+f],b=g+(_-g)*v,w=y+(M-y)*v;return b+(w-b)*m}}const gl=256,w2=5;async function E2(r,t,e,i){const n=(r.south+r.north)/2,s=(r.west+r.east)/2,a=Math.abs(Je(n,r.east,n,r.west).x),o=Math.abs(Je(r.north,s,r.south,s).z),c=Math.max(a,o),{zoom:l,gridSize:h}=A2(n,c,Math.max(t.width,t.height)),{tiles:u,bounds:d}=kg(s,n,l,h),f=h*gl,p=document.createElement("canvas");p.width=f,p.height=f;const v=p.getContext("2d");if(!v)throw new Error("2D canvas context unavailable");const m=u[0];await Promise.all(u.map(async M=>{const b=e(M),w=await i(b);if(!w.ok)throw new Error(`Imagery tile fetch failed (${w.status}): ${b}`);const T=await createImageBitmap(await w.blob());v.drawImage(T,(M.x-m.x)*gl,(M.y-m.y)*gl)}));const g=Math.min(Math.max(t.width,t.height),f);if(g===f)return{source:p,width:f,height:f,bounds:d};const _=document.createElement("canvas");_.width=g,_.height=g;const y=_.getContext("2d");if(!y)throw new Error("2D canvas context unavailable");return y.drawImage(p,0,0,f,f,0,0,g,g),{source:_,width:g,height:g,bounds:d}}function A2(r,t,e){let i=M2(r,t/Math.max(1,e)),n=zf(r,i,t);for(;n>w2&&i>0;)i--,n=zf(r,i,t);return{zoom:i,gridSize:n,mPerPixel:Ng(r,i)/gl}}function zf(r,t,e){const i=Math.ceil(e/2/Ng(r,t));return Math.max(3,2*i+1)}class T2{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 E2(t,e,i=>this.tileUrlTemplate.replace("{z}",String(i.z)).replace("{y}",String(i.y)).replace("{x}",String(i.x)),this.fetchImpl)}}class Fn{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;static ENDPOINTS=["https://overpass-api.de/api/interpreter","https://overpass.kumi.systems/api/interpreter","https://overpass.private.coffee/api/interpreter"];fetchImpl;endpoints;constructor(t={}){this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.endpoints=t.endpoints??Fn.ENDPOINTS}static queue=Promise.resolve();static RETRY_MS=4e3;async getRoads(t){const e=`${t.south},${t.west},${t.north},${t.east}`,i=`[out:json][timeout:30];way["highway"~"^(${Fn.DRIVABLE.join("|")})$"](${e});out geom;`;return this.waysFrom(await this.queued(()=>this.ask(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:Fn.surfaceOf(s),widthM:Fn.widthOf(s),points:n.map(a=>({lat:a.lat,lng:a.lon}))})}return e}queued(t){const e=Fn.queue.then(t,t);return Fn.queue=e.catch(()=>{}),e}async ask(t){let e;for(const i of this.endpoints)for(let n=0;n<2;n++){try{const s=await this.fetchImpl(`${i}?data=${encodeURIComponent(t)}`);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,Fn.RETRY_MS))}throw e??new Error("No Overpass instance answered")}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:Fn.WIDTH_M[t.highway]??Fn.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 Mh="https://ufoathome.org/roads/index.json";class g0{attributionRead;contemporaryRead;fetchImpl;indexUrls;fallback;index;constructor(t={}){this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.indexUrls=t.indexUrls??g0.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(){return this.index??=this.fetchFirstAvailable(),this.index}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.90.0")}`,e=typeof location>"u"?void 0:new URL("/roads/index.json",location.href).href;return(e&&e!==Mh?[e,Mh]:[Mh]).map(i=>i+t)}}function R2(){return{elevation:new b2,imagery:zg(),roads:D2()}}function zg(){return new T2}function D2(){return new g0({fallback:new Fn})}const I2=new Set,Or="show-observer-map",Nr="hide-milestones";class fe extends HTMLElement{static get observedAttributes(){return["src",Or,Nr]}shadow;stageElement;canvas;canvasRenderer;tooltip;toolbar;issuesBox;issuesButton;issuesPanel;playPauseButton;static OBSERVER_MAP_MIN_SPAN_M=400;static OBSERVER_MAP_MARGIN=.6;static OBSERVER_MAP_IMAGERY_PX=768;fullscreenButton;cornerButtons;observerMapButton;referencesButton;tracesButton;tracesShownState=!0;referenceOpacityInput;referencesShownState=!0;referenceOpacityTouched=!1;milestonesButton;observerMapPanel;observerMapCanvas;observerMapRenderer;mapZoomInButton;mapZoomOutButton;mapFitButton;observerMapView=new Xe;observerMapDrag;suppressObserverMapClick=!1;observerMapImageryTimer;observerPlacing=!1;seekInput;playbackFlash;milestoneMarks;milestoneCaption;timeStartLabel;timeEndLabel;timePill;muteButton;volumeInput;controlsRow;momentsBox;momentsButton;momentsCurrent;momentsMenu;moreButton;controlsRight;seekSegments;seekDot;seekPreview;seekPreviewCanvas;seekPreviewTitle;seekPreviewTime;observerPath;observerMapBounds;observerMapImagery;observerMapImageryBounds;observerMapImageryViewWidth=0;observerMapImageryLoading=!1;observerMapImageryCredit;observerMapImageryFailed=!1;creditShownExternally=!1;lookYawDeg=0;lookPitchDeg=0;milestonesShown=!0;currentSighting=Ql.create();issues=[];issueCheck=0;sightingAudio=new a2;soundPreview;player;loopEnabled=!1;playbackBeforeClick;highlightedSourceIds=new Set;paintsShapes=!0;steadyObserver=!1;selectionShown=!0;overlayPainter;enableClickToPlay=!0;fullscreenTarget;messages=Ig;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");fe.setIcon(this.moreButton,t?Gt.UNFOLDED:Gt.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)<fe.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>=Xe.MAX_ZOOM,this.mapZoomOutButton.disabled=this.observerMapView.zoomFactor<=Xe.MIN_ZOOM,this.paintObserverMap(this.currentTime),this.scheduleObserverMapImagery()}scheduleObserverMapImagery(){this.observerMapImageryTimer===void 0&&(this.observerMapImageryTimer=setTimeout(()=>{this.observerMapImageryTimer=void 0,this.loadObserverMapImagery()},fe.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=Xe.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>${Cv}</style>${Iv}`,this.shadow.appendChild(t.content.cloneNode(!0)),this.stageElement=this.shadow.getElementById("stage"),this.canvas=this.shadow.getElementById("canvas"),this.canvasRenderer=new qo(this.canvas.getContext("2d")),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",e=>{e.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.milestonesButton=this.shadow.getElementById("milestones"),this.observerMapPanel=this.shadow.getElementById("observer-map-panel"),this.observerMapCanvas=this.shadow.getElementById("observer-map-canvas"),this.observerMapRenderer=new Aa(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.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",e=>{e.key!=="Enter"&&e.key!==" "||(e.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.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.seekInput.addEventListener("pointerdown",e=>{this.suspendForScrub(),this.seekSnapArmed=!0,this.nameMarkUnder(e),this.beginTouchScrub(e)}),this.seekInput.addEventListener("pointerup",e=>{this.seekSnapArmed=!1,this.endTouchScrub(e)}),this.seekInput.addEventListener("pointercancel",e=>this.endTouchScrub(e)),this.seekInput.addEventListener("pointermove",e=>{this.nameMarkUnder(e),this.hoverSeek(e),this.touchScrub(e)}),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 e of["touchend","click"])this.stageElement.addEventListener(e,()=>this.sightingAudio.resume(),!0);this.stageElement.addEventListener("pointermove",()=>this.touchedStage()),this.canvas.addEventListener("click",e=>{if(this.enableClickToPlay){if(this.tapRevealedOnly){this.tapRevealedOnly=!1;return}e.detail<=1&&(this.playbackBeforeClick={state:this.playbackState,time:this.currentTime}),this.togglePlayPause()}}),this.canvas.addEventListener("dblclick",e=>{this.enableClickToPlay&&(e.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.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.controlsFitObserver?.disconnect(),this.controlsMutations?.disconnect(),this.exitSimulatedFullscreen(),this.sightingAudio.dispose()}attributeChangedCallback(t,e,i){t==="src"&&i&&i!==e&&this.isConnected&&this.loadFromSrc(i),t===Or&&this.applyObserverMapDefault(),t===Nr&&this.setMilestonesShown(!this.hasAttribute(Nr))}async loadFromSrc(t){this.sightingData=await Ag.json(t)}get sightingData(){return r2(this.currentSighting)}set sightingData(t){this.player.stop(),this.soundPreview=void 0,this.sightingAudio.silence(),this.currentSighting=c2(t),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.updateTimeLabels(),this.updatePlayPauseButton(),this.refresh(),this.applyObserverMapDefault()}get recordingIssues(){return this.issues}async reportIssues(t,e){const i=++this.issueCheck;let n=[];try{const{default:s}=await rn(async()=>{const{default:a}=await import("./sightingSchema-Bsub_0vA.js");return{default:a}},[],import.meta.url);n=new Nn(s).issues(t)}catch{}i===this.issueCheck&&(this.issues=[...n,...e.loadIssues],Yr.warn(this.issues,e.id),this.renderIssues(),this.dispatchEvent(new CustomEvent(C2,{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=Yr.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(){this.player.seekableDuration<=0||this.playbackState==="playing"||this.togglePlayPause()}pause(){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.updateTimeLabels(),this.seekInput.max=String(this.player.seekableDuration),this.refreshMilestoneMarks(),this.updateMilestonesButton(),this.updateObserverMap(),this.updateReferences(),this.updateTracesButton(),this.player.seek(this.player.time)}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)}toggleReferences(){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)),this.updateReferencesButton()}updateReferencesButton(){const t=this.currentSighting.references.length>0;this.referencesButton.hidden=!t,this.referenceOpacityInput.hidden=!t||!this.referencesShownState,this.referencesButton.setAttribute("aria-pressed",String(this.referencesShownState)),fe.setIcon(this.referencesButton,this.referencesShownState?Gt.PICTURES_ON:Gt.PICTURES_OFF);const e=this.referencesShownState?this.messages.hideReferences:this.messages.showReferences;this.referencesButton.title=e,this.referencesButton.setAttribute("aria-label",e),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)),fe.setIcon(this.tracesButton,this.tracesShownState?Gt.TRACES_ON:Gt.TRACES_OFF);const t=this.tracesShownState?this.messages.hideTraces:this.messages.showTraces;this.tracesButton.title=t,this.tracesButton.setAttribute("aria-label",t)}dispatchReferenceView(){this.dispatchEvent(new CustomEvent("referenceview",{detail:{shown:this.referencesShown,opacity:this.referenceOpacity}}))}refreshMilestoneMarks(){const t=this.player.seekableDuration,e=t>0?Oo(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),o=a?`${s} — ${a}`:s;return n.title=o,n.setAttribute("aria-label",o),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)??"",o=this.said.read(i.note);return s.textContent=o?`${a} — ${o}`: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,o)=>a-o):[],Math.max(t,0)];this.seekSegmentList=[];const s=[];for(let a=0;a<n.length-1;a++){const o=document.createElement("div");o.className="seek-segment",o.style.flexGrow=String(Math.max(n[a+1]-n[a],1));const c=document.createElement("i");c.className="seek-hover";const l=document.createElement("i");l.className="seek-played",o.append(c,l),s.push(o),this.seekSegmentList.push({start:n[a],end:n[a+1],element:o,played:l,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}%`}paintSeekProgress(t){for(const i of this.seekSegmentList)i.played.style.width=fe.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=fe.fillOf(f,s),f.element.classList.toggle("hovered",s>=f.start&&(s<f.end||p===a))});const o=this.milestonesShown?this.sighting.milestones:[],c=o.length>0?gh(o,s):void 0,l=c?this.said.read(c.label)??"":"",h=c?this.said.read(c.note):void 0,u=h?`${l} — ${h}`:l;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)}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=fe.MARK_SNAP_PX/i*e;let s;for(const a of this.milestoneMarks.children){const o=Number(a.dataset.t);Math.abs(o-t)>n||(!s||Math.abs(o-t)<Math.abs(s.t-t))&&(s={t:o,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?gh(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=Bn.windowEndingAt(t,this.currentSighting.exposure??0);if(e.ms<fe.SHORTEST_VISIBLE_EXPOSURE_MS)return[t];const i=Math.min(fe.MAX_EXPOSURE_STEPS,Math.max(2,Math.round(e.ms/fe.SHORTEST_VISIBLE_EXPOSURE_MS))),n=Math.ceil(this.travelPxOver(e.fromMs,e.ms)/fe.EXPOSURE_STEP_PX),s=Math.min(fe.MAX_TRAVEL_STEPS,Math.max(i,n)),a=[];for(let o=0;o<s;o++)a.push(e.fromMs+e.ms*o/(s-1));return a}travelPxOver(t,e){const i=this.shapesAt(t),n=this.shapesAt(t+e);let s=0;for(const[a,o]of i){const c=n.get(a);if(!c)continue;const l=c.bounds.x+c.bounds.width/2-(o.bounds.x+o.bounds.width/2),h=c.bounds.y+c.bounds.height/2-(o.bounds.y+o.bounds.height/2);s=Math.max(s,Math.hypot(l,h))}return s}shapeAt(t,e,i){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=mi.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:I2;this.canvasRenderer.setStarPoints(mi.starPointsOf(this.sighting.instrument));const n=(Ze(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 o of s)for(const[,c]of o.shapes){const l=o.share,h=l===1?c:{...c,transparency:1-(1-c.transparency)*l};this.canvasRenderer.paintShape(this.shifted(h,a))}for(const[o,c]of s[0].shapes)!this.selectionShown||!i.has(o)||(this.paintsShapes?i.size===1?this.canvasRenderer.paintShape({...c,selected:!0}):this.canvasRenderer.paintMemberOutline(c):this.canvasRenderer.paintSelectionOnly(this.shifted(c,a)));if(this.selectionShown&&i.size>1){const o=pn.groupBoundsFor([...e].filter(([c])=>i.has(c)).map(([,c])=>c.bounds));this.canvasRenderer.paintGroupHandles(o)}this.overlayPainter?.(this.canvasRenderer),this.mapShapeBounds=s.flatMap(o=>[...o.shapes.values()].filter(c=>c.transparency<1).map(c=>this.shifted(c,a).bounds)),this.keepObserverMapClear(),this.seekInput.value=String(t),this.paintSeekProgress(t),this.timeStartLabel.textContent=this.formatPosition(t),this.showMilestoneAt(t),this.paintObserverMap(t),this.playbackState==="playing"?(this.soundPreview=void 0,this.sightingAudio.setSound(Jv(this.currentSighting,t))):this.soundPreview?this.sightingAudio.setSound(this.soundPreview):this.sightingAudio.silence(),this.updatePlayPauseButton(),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 jv(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*fe.SEEK_KEY_STEP_MS)))}else t.key===" "&&(t.preventDefault(),this.togglePlayPause())};togglePlayPause(){this.player.seekableDuration<=0||(this.player.playbackState==="playing"?(this.player.pause(),this.soundPreview=void 0,this.sightingAudio.silence(),this.refresh()):(this.sightingAudio.resume(),this.player.play()),this.updatePlayPauseButton(),this.flashPlayback())}flashPlayback(){const t=this.playbackFlash;t.innerHTML=this.player.playbackState==="playing"?Gt.PLAY:Gt.PAUSE,t.classList.remove("flashing"),t.offsetWidth,t.classList.add("flashing")}static icons=new WeakMap;static setIcon(t,e){fe.icons.get(t)!==e&&(fe.icons.set(t,e),t.innerHTML=e)}set captionHeld(t){this.stageElement.classList.toggle("caption-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},fe.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,fe.setIcon(this.playPauseButton,t?Gt.PAUSE:Gt.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}}))}observerMapAsked=!1;applyObserverMapDefault(){const t=this.getAttribute(Or),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;fe.setIcon(this.observerMapButton,t?Gt.MAP_ON:Gt.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=Pr.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=Xe.including(this.observerPath.boundsAround(fe.OBSERVER_MAP_MIN_SPAN_M,fe.OBSERVER_MAP_MARGIN),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.observerMapImageryNeededFor(t))return;const e=this.observerMapView.changed,i=e?Xe.expand(t,fe.OBSERVER_MAP_IMAGERY_AHEAD):t,n=fe.OBSERVER_MAP_IMAGERY_PX*(e?1+2*fe.OBSERVER_MAP_IMAGERY_AHEAD:1);this.observerMapImageryBounds=i,this.observerMapImageryViewWidth=t.east-t.west,this.observerMapImageryLoading=!0;const s=zg();try{const a=await s.getImageryTexture(i,{width:n,height:n});if(this.observerMapImageryBounds!==i)return;this.observerMapImagery=a,this.observerMapImageryCredit=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?Xe.expand(t,fe.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}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=(l,h,u)=>{for(const d of e)if(!(d.x+d.width<l-u||d.x>h+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=fe.OBSERVER_MAP_CLEARANCE_PX,o=i(...n,0),c=i(...s,0);if(this.observerMapPanel.classList.toggle("subject-overlap",o&&c&&!this.observerMapAsked),this.observerMapPanel.classList.contains("on-the-left")){!o&&(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=Ze(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},fe.OBSERVER_MAP_FOLLOW_MARGIN)&&this.scheduleObserverMapImagery();const i=this.currentSighting.instrument,n=[],s=this.currentSighting.milestones.length>0?gh(this.currentSighting.milestones,t):void 0;for(const a of this.milestonesShown?Oo(this.currentSighting.milestones):[]){const o=Ze(this.currentSighting,a.t);o?.lat===void 0||o.lng===void 0||n.push({label:this.said.read(a.label)??"",note:this.said.read(a.note),t:a.t,lat:o.lat,lng:o.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?Is.of(i,this.canvas.height,e.fovDeg).halfWidthAngleDeg(mi.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,Oo(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,fe.setIcon(this.milestonesButton,this.milestonesShown?Gt.MILESTONES_ON:Gt.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=Ze(this.currentSighting,0);return e?.lat===void 0||e.lng===void 0?[]:this.currentSighting.decor.filter(i=>i.kind!=="crop").map(i=>{const n=Go(i,t),{lat:s,lng:a}=xn(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=Ze(this.currentSighting,this.currentTime),s=Is.of(this.currentSighting.instrument,this.canvas.height,n?.fovDeg??60);return{x:-s.angleDegToRadiusPx(e),y:s.angleDegToRadiusPx(i)}}gaitAt(t){return be.bodyAt(this.currentSighting,t,this.steadyObserver)}mutedState=!1;get muted(){return this.mutedState}set muted(t){t!==this.mutedState&&(this.mutedState=t,!t&&this.volumeState===0&&(this.volumeState=fe.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.muted=!this.mutedState}updateMuteButton(){fe.setIcon(this.muteButton,this.mutedState?Gt.MUTED:Gt.VOLUME);const t=this.mutedState?this.messages.unmute:this.messages.mute;this.muteButton.title=t,this.muteButton.setAttribute("aria-label",t),this.muteButton.setAttribute("aria-pressed",String(this.mutedState)),this.volumeInput.value=String(this.level)}updateFullscreenButton(){const t=this.simulatedFullscreen||document.fullscreenElement===this.fullscreenTarget;fe.setIcon(this.fullscreenButton,t?Gt.EXIT_FULLSCREEN:Gt.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 Rs(Lr.preferencesFor(this))}saidTexts;async loadLocaleMessages(){const t=Rg(Lr.preferencesFor(this),Dg);if(t===this.messagesLanguage||t==="en"&&this.messagesLanguage===void 0)return;this.messagesLanguage=t;const e=await u2(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=$v(t);this.realDurationMs=e!==void 0&&e>0?e:void 0,this.realStartMs=t.time?Hu(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.updateTimeLabelTitles()}formatPosition(t){if(this.realDurationMs===void 0)return gc(t);const e=this.currentSighting.timeline.duration,i=e>0&&t<=e?t/e*this.realDurationMs:t;return this.canShowClockTime?Hf(Bf(this.realStartMs+i)):gc(i)}formatEndOfTimeline(){return this.realDurationMs===void 0?gc(this.currentSighting.timeline.duration):this.canShowClockTime?Hf(Bf(this.realStartMs+this.realDurationMs)):gc(this.realDurationMs)}}function Bf(r){const t=new Date(r);return{hour:t.getUTCHours(),minute:t.getUTCMinutes(),second:t.getUTCSeconds()}}function Hf(r){if(r.hour===void 0)return"0:00";const t=e=>String(e).padStart(2,"0");return r.second?`${t(r.hour)}:${t(r.minute??0)}:${t(r.second)}`:`${t(r.hour)}:${t(r.minute??0)}`}function gc(r){const t=Math.round(r/1e3),e=Math.floor(t/60),i=t%60;return`${e}:${String(i).padStart(2,"0")}`}const Vu="rr0-ufo";function Bg(){customElements.get(Vu)||customElements.define(Vu,fe)}const C2="recordingissues";/**
1367
1367
  * @license
1368
1368
  * Copyright 2010-2026 Three.js Authors
1369
1369
  * SPDX-License-Identifier: MIT
@@ -7213,7 +7213,7 @@ void main()
7213
7213
  if (ice <= 0.0) discard;
7214
7214
  gl_FragColor = vec4(iceHaloLight(dir, ice), 1.0);
7215
7215
  }
7216
- `,transparent:!0,blending:Ai,depthWrite:!1,side:Ye,fog:!1}),this.object=new At(new di(Oi.RADIUS,64,32),this.material),this.object.renderOrder=-1,this.object.frustumCulled=!1,this.object.visible=!1;const i=this.material.uniforms;this.deckUniforms={uSource:i.uSource,uUp:i.uUp,uStrength:i.uStrength,uTint:i.uTint,uMap:i.uMap,uGain:i.uGain,uHaloShown:{value:0}}}deckUniforms;shown=!1;hostedByDeck=!1;set hosted(t){this.hostedByDeck=t,this.show(this.shown)}show(t){this.shown=t,this.object.visible=t&&!this.hostedByDeck,this.deckUniforms.uHaloShown.value=t?1:0}get awaitingFirstDisplay(){return this.tracing&&!this.everDisplayed}setUrgent(t){this.urgent=t}set onReady(t){this.onRepaint=t}update(t,e,i,n,s,a){const o=this.material.uniforms;if(i<=0){o.uStrength.value=0,this.show(!1),this.stopWork();return}o.uSource.value.set(t.x,t.y,t.z).normalize(),o.uStrength.value=i,o.uTint.value.set(n[0],n[1],n[2]),o.uIceCover.value=s.cover,o.uIceHeight.value=s.layerHeight,this.show(this.everDisplayed),this.requestMap(e,a)}requestMap(t,e){if(!(!(Math.abs(t-this.mappedAltitudeDeg)<Oi.ALTITUDE_STEP_DEG)||!(Math.abs(e-this.mappedAlignment)<Oi.ALIGNMENT_STEP))){this.next=void 0;return}if(this.tracing){if(this.tracingFor(t,e)){this.next=void 0;return}if(!(!(Math.abs(t-this.pendingAltitudeDeg)<Oi.LEAP_ALTITUDE_DEG)||!(Math.abs(e-this.pendingAlignment)<Oi.LEAP_ALIGNMENT))){this.next={sourceAltitudeDeg:t,alignment:e};return}}this.next=void 0,this.pendingAltitudeDeg=t,this.pendingAlignment=e,this.sky.begin(t,e),this.tracing=!0,this.scheduleWork()}pendingAltitudeDeg=Number.NaN;pendingAlignment=Number.NaN;next;tracingFor(t,e){return this.tracing&&Math.abs(t-this.pendingAltitudeDeg)<Oi.ALTITUDE_STEP_DEG&&Math.abs(e-this.pendingAlignment)<Oi.ALIGNMENT_STEP}scheduleWork(){if(this.workHandle!==void 0)return;const t=()=>{if(this.workHandle=void 0,!this.tracing)return;const e=performance.now(),i=this.urgent?Oi.URGENT_BUDGET_MS:Oi.BUDGET_MS;do this.sky.trace(Oi.RAYS_PER_BATCH);while(this.sky.tracedRays<Oi.RAYS&&performance.now()-e<i);if(this.sky.tracedRays>=Oi.RAYS){this.publish(),this.tracing=!1,this.mappedAltitudeDeg=this.pendingAltitudeDeg,this.mappedAlignment=this.pendingAlignment;const s=this.next;s&&this.requestMap(s.sourceAltitudeDeg,s.alignment);return}this.workHandle=requestAnimationFrame(t)};this.workHandle=requestAnimationFrame(t)}stopWork(){this.workHandle!==void 0&&cancelAnimationFrame(this.workHandle),this.workHandle=void 0,this.tracing=!1,this.next=void 0}publish(){const e=this.sky.harvest().data;for(let i=0,n=0;n<e.length;i+=4,n+=3)this.texels[i]=Xn.toHalfFloat(e[n]),this.texels[i+1]=Xn.toHalfFloat(e[n+1]),this.texels[i+2]=Xn.toHalfFloat(e[n+2]),this.texels[i+3]=1;this.texture.needsUpdate=!0,this.everDisplayed=!0,this.show(this.material.uniforms.uStrength.value>0),this.onRepaint?.()}dispose(){this.stopWork(),this.texture.dispose(),this.object.geometry.dispose(),this.material.dispose()}}class Si{static MAX_CONCURRENT=24;static POINTS=8;static SEGMENTS=Si.POINTS-1;static ACROSS=3;static VERTICES_PER_SEGMENT=(Si.ACROSS-1)*6;static RADIUS=840;static MIN_HALF_WIDTH_DEG=.05;static BRIGHT_HALF_WIDTH_DEG=.22;object;positions;colors;meteors=[];radiantAltitudeDeg=0;radiantAzimuthDeg=0;constructor(){const t=Si.MAX_CONCURRENT*Si.SEGMENTS*Si.VERTICES_PER_SEGMENT;this.positions=new Float32Array(t*3),this.colors=new Float32Array(t*3);const e=new ne;e.setAttribute("position",new Zt(this.positions,3)),e.setAttribute("color",new Zt(this.colors,3)),e.setDrawRange(0,0),this.object=new At(e,new yn({vertexColors:!0,transparent:!0,blending:Ai,depthWrite:!1,fog:!1,side:Yi})),this.object.frustumCulled=!1}get schedule(){return this.meteors}setShower(t,e,i){this.meteors=t,this.radiantAltitudeDeg=e,this.radiantAzimuthDeg=i}update(t){const e=this.object.geometry;if(this.meteors.length===0){e.setDrawRange(0,0);return}const i=za.aliveAt(this.meteors,t).slice(0,Si.MAX_CONCURRENT);let n=0;for(const{meteor:s,progress:a}of i){const o=this.radiantOf(s);if(!o)continue;const c=Ke(o.altitudeDeg,o.azimuthDeg,1),[l,h]=this.basisAround(c),u=s.fromRadiantDeg+a*s.lengthDeg,d=Math.max(s.fromRadiantDeg,u-s.lengthDeg*.6),f=Math.min(1,(1-a)*2.5),p=this.turn(l,h,s.bearingDeg),v=(.15+.85*s.brightness)*f,m=y=>v*y**1.6,g=y=>this.onSphere(c,p,d+(u-d)*y),_=y=>Si.RADIUS*((Si.MIN_HALF_WIDTH_DEG+Si.BRIGHT_HALF_WIDTH_DEG*s.brightness*y)*Math.PI/180);for(let y=1;y<Si.POINTS;y++){const M=(y-1)/Si.SEGMENTS,b=y/Si.SEGMENTS;n=this.pushRibbon(n,g(M),g(b),_(M),_(b),m(M),m(b))}}e.setDrawRange(0,n),e.getAttribute("position").needsUpdate=!0,e.getAttribute("color").needsUpdate=!0}midpointOf(t){const e=this.radiantOf(t);if(!e)return;const i=Ke(e.altitudeDeg,e.azimuthDeg,1),[n,s]=this.basisAround(i),a=this.turn(n,s,t.bearingDeg),o=this.onSphere(i,a,t.fromRadiantDeg+t.lengthDeg/2),c=Math.hypot(o.x,o.y,o.z)||1;return{altitudeDeg:Math.asin(o.y/c)*180/Math.PI,azimuthDeg:(Math.atan2(o.x,-o.z)*180/Math.PI+360)%360}}radiantOf(t){return t.radiant?t.radiant:this.radiantAltitudeDeg>0?{altitudeDeg:this.radiantAltitudeDeg,azimuthDeg:this.radiantAzimuthDeg}:void 0}pushRibbon(t,e,i,n,s,a,o){const c=this.normalise(this.cross(this.normalise(e),this.normalise(this.subtract(i,e))));for(let l=0;l<Si.ACROSS-1;l++){const h=l-1,u=l,d=this.across(e,c,n,h),f=this.across(i,c,s,h),p=this.across(e,c,n,u),v=this.across(i,c,s,u),m=(g,_)=>g===0?_:0;t=this.push(t,d,m(h,a)),t=this.push(t,f,m(h,o)),t=this.push(t,p,m(u,a)),t=this.push(t,f,m(h,o)),t=this.push(t,v,m(u,o)),t=this.push(t,p,m(u,a))}return t}across(t,e,i,n){return{x:t.x+e.x*i*n,y:t.y+e.y*i*n,z:t.z+e.z*i*n}}push(t,e,i){const n=t*3;this.positions[n]=e.x,this.positions[n+1]=e.y,this.positions[n+2]=e.z;const s=wt.relativeOfResponse(Math.max(0,Math.min(1,i)));return this.colors[n]=s*.9,this.colors[n+1]=s*.95,this.colors[n+2]=s,t+1}turn(t,e,i){const n=i*Math.PI/180,s=Math.cos(n),a=Math.sin(n);return{x:t.x*s+e.x*a,y:t.y*s+e.y*a,z:t.z*s+e.z*a}}onSphere(t,e,i){const n=i*Math.PI/180,s=Math.cos(n),a=Math.sin(n);return{x:(t.x*s+e.x*a)*Si.RADIUS,y:(t.y*s+e.y*a)*Si.RADIUS,z:(t.z*s+e.z*a)*Si.RADIUS}}basisAround(t){const e=Math.abs(t.y)<.9?{x:0,y:1,z:0}:{x:1,y:0,z:0},i=this.normalise(this.cross(t,e));return[i,this.normalise(this.cross(t,i))]}subtract(t,e){return{x:t.x-e.x,y:t.y-e.y,z:t.z-e.z}}cross(t,e){return{x:t.y*e.z-t.z*e.y,y:t.z*e.x-t.x*e.z,z:t.x*e.y-t.y*e.x}}normalise(t){const e=Math.hypot(t.x,t.y,t.z)||1;return{x:t.x/e,y:t.y/e,z:t.z/e}}dispose(){this.object.geometry.dispose(),this.object.material.dispose()}}class Fe{constructor(t,e={}){this.size=t,this.span=Math.min(t.lengthM,Math.max(0,e.spanM??t.lengthM)),this.bank=(t.lengthM-this.span)/2,this.deck=Math.min(t.heightM,e.deckThicknessM??Fe.DEFAULT_DECK_THICKNESS_M),this.railHeight=e.railing?.heightM??Fe.DEFAULT_RAILING_HEIGHT_M,this.postSpacing=Math.max(.3,e.railing?.postSpacingM??Fe.DEFAULT_POST_SPACING_M),this.rails=Math.max(0,Math.round(e.railing?.rails??Fe.DEFAULT_RAILS))}static DEFAULT_DECK_THICKNESS_M=1.2;static DEFAULT_RAILING_HEIGHT_M=1.05;static DEFAULT_POST_SPACING_M=1.5;static DEFAULT_RAILS=2;static BANK_SLOPE=1.5;static ABUTMENT_THICKNESS_M=1;static POST_SIDE_M=.08;static RAIL_HEIGHT_M=.08;static RAIL_DEPTH_M=.06;static BANK_STATIONS=12;static NATURAL_SIZE=Object.freeze({widthM:9,lengthM:40,heightM:6.5});span;bank;deck;railHeight;postSpacing;rails;roadAt(t){const e=Math.abs(t)-this.span/2;return e<=0?this.size.heightM:this.bank<=0?0:Math.max(0,this.size.heightM*(1-e/this.bank))}build(){const{widthM:t,heightM:e}=this.size,i=this.span/2,n=[];if(this.span>0){n.push(Fe.box(t,this.deck,this.span,0,e-this.deck/2,0));for(const c of[-1,1]){const l=e-this.deck;l>0&&this.bank>0&&n.push(Fe.box(t+1,l,Fe.ABUTMENT_THICKNESS_M,0,l/2,c*(i-Fe.ABUTMENT_THICKNESS_M/2)))}}const s=[];this.span>0&&s.push(Fe.box(t,.04,this.span,0,e+.02,0));const a=[];for(const c of[-1,1])this.bank<=0||(a.push(this.embankment(c)),s.push(this.bankRoad(c)));const o=[];for(const c of[-1,1])o.push(...this.railing(c*(t/2-Fe.POST_SIDE_M)));return{concrete:Fe.merge(n),road:Fe.merge(s),earth:Fe.merge(a),railing:Fe.merge(o)}}embankment(t){const e=this.size.widthM/2,i=this.stations(t),n=[],s=(l,h,u,d)=>{n.push(l.x,l.y,l.z,h.x,h.y,h.z,u.x,u.y,u.z,l.x,l.y,l.z,u.x,u.y,u.z,d.x,d.y,d.z)},a=l=>{const h=this.roadAt(l),u=e+Fe.BANK_SLOPE*h;return{leftFoot:new R(-u,0,l),leftTop:new R(-e,h,l),rightTop:new R(e,h,l),rightFoot:new R(u,0,l)}};for(let l=1;l<i.length;l++){const h=a(i[l-1]),u=a(i[l]),d=t>0,f=(p,v,m,g)=>d?s(p,v,m,g):s(g,m,v,p);f(h.leftFoot,h.leftTop,u.leftTop,u.leftFoot),f(h.leftTop,h.rightTop,u.rightTop,u.leftTop),f(h.rightTop,h.rightFoot,u.rightFoot,u.rightTop)}const o=a(i[0]);t>0?s(o.leftFoot,o.rightFoot,o.rightTop,o.leftTop):s(o.leftTop,o.rightTop,o.rightFoot,o.leftFoot);const c=new ne;return c.setAttribute("position",new he(n,3)),c.computeVertexNormals(),c}bankRoad(t){const e=this.size.widthM/2,i=this.stations(t),n=[];for(let a=1;a<i.length;a++){const o=i[a-1],c=i[a],l=this.roadAt(o)+.02,h=this.roadAt(c)+.02,u=t>0?[[-e,l,o],[e,l,o],[e,h,c],[-e,h,c]]:[[-e,h,c],[e,h,c],[e,l,o],[-e,l,o]];for(const d of[0,2,1,0,3,2])n.push(...u[d])}const s=new ne;return s.setAttribute("position",new he(n,3)),s.computeVertexNormals(),s}stations(t){const e=[];for(let i=0;i<=Fe.BANK_STATIONS;i++)e.push(t*(this.span/2+this.bank*i/Fe.BANK_STATIONS));return e}railing(t){const e=this.size.lengthM/2,i=Math.max(1,Math.round(this.size.lengthM/this.postSpacing)),n=[];for(let o=0;o<=i;o++)n.push(-e+this.size.lengthM*o/i);const s=[],a=Fe.POST_SIDE_M;for(const o of n)s.push(Fe.box(a,this.railHeight,a,t,this.roadAt(o)+this.railHeight/2,o));for(let o=1;o<=this.rails;o++){const c=this.railHeight*o/this.rails-Fe.RAIL_HEIGHT_M/2;for(let l=1;l<n.length;l++){const h=new R(t,this.roadAt(n[l-1])+c,n[l-1]),u=new R(t,this.roadAt(n[l])+c,n[l]);s.push(Fe.beam(h,u))}}return s}static box(t,e,i,n,s,a){return new $i(t,e,i).translate(n,s,a)}static beam(t,e){const i=new R().subVectors(e,t),n=new $i(Fe.RAIL_DEPTH_M,Fe.RAIL_HEIGHT_M,i.length()),s=new on().setFromUnitVectors(new R(0,0,1),i.clone().normalize()),a=new R().addVectors(t,e).multiplyScalar(.5);return n.applyMatrix4(new Qt().compose(a,s,new R(1,1,1)))}static merge(t){const e=t.map(c=>c.getIndex()?c.toNonIndexed():c),i=e.reduce((c,l)=>c+l.getAttribute("position").count,0),n=new Float32Array(i*3),s=new Float32Array(i*3);let a=0;for(const c of e){const l=c.getAttribute("position"),h=c.getAttribute("normal");n.set(l.array,a*3),h&&s.set(h.array,a*3),a+=l.count}const o=new ne;o.setAttribute("position",new he(n,3)),o.setAttribute("normal",new he(s,3));for(const c of t)c.dispose();for(const c of e)c.dispose();return o}}const hu=Math.PI/180;function ze(r,t,e,i,n=!1){const s=n?new yn({color:new st(...e)}):new Wa({color:new st(...e)}),a=new At(t,s);return a.position.y=i,a.userData={emissive:n},a.castShadow=!n,a.receiveShadow=!n,r.add(a),a}const uu=.25,P5=.002,L5=100,O5=1500,N5=.25,F5=1e3,U5=.15;function k5(r){const t=/^#([0-9a-f]{6})$/i.exec(r);if(!t)return[1,1,1];const e=parseInt(t[1],16);return[(e>>16&255)/255,(e>>8&255)/255,(e&255)/255]}const z5=[.32,.32,.3],tv=[1,.85,.5],B5=[.25,.25,.25],ev=[1,.97,.85],H5=[.55,.68,.72],rs=.03,os=.05,iv={front:0,behind:Math.PI,left:Math.PI/2,right:-Math.PI/2,"front-left":Math.PI/2,"behind-left":Math.PI/2,"front-right":-Math.PI/2,"behind-right":-Math.PI/2};function Vi(r,t){return r?.[t]}function cs(r,t,e,i,n,s,a,o){if(o===void 0)return;const c=new Wa({color:new st(...H5),transparent:!0,opacity:o/100}),l=new At(new $i(t,e,i),c);l.position.set(n,s,a),r.add(l)}const An=.05,du=[.6,.58,.53],Tm=[.5,.5,.48];function Ir(r,t,e,i,n,s,a,o){const c=new Wa({color:new st(...o),side:Ye}),l=new At(new $i(t,e,i),c);l.position.set(n,s,a),r.add(l)}function G5(r,t,e,i,n,s,a,o,c){const l=(i-s)/2,h=(p,v,m,g)=>{p<=0||(t?Ir(r,p,v,An,m,o+g,a,c):Ir(r,An,v,p,a,o+g,m,c))};h(e,l,0,i/2-l/2),h(e,l,0,-(i/2-l/2));const u=[...n].sort((p,v)=>p.center-v.center);let d=-e/2;for(const p of u){const m=p.center-p.main/2-d;h(m,s,d+m/2,0),d=p.center+p.main/2}const f=e/2-d;h(f,s,d+f/2,0)}function nv(r,t,e,i,n,s,a,o,c,l){const h=(i+n)/2,u=n-i,d=(f,p,v,m)=>{f.length===0?p?Ir(r,v,u,An,0,h,m,du):Ir(r,An,u,v,m,h,0,du):G5(r,p,v,u,f,s,m,h,du)};d(a,!0,t*2,-e+An),d(o,!0,t*2,e-An),d(c,!1,e*2,-t+An),d(l,!1,e*2,t-An),Ir(r,t*2,An,e*2,0,i+An,0,Tm),Ir(r,t*2,An,e*2,0,n-An,0,Tm)}function o0(r,t,e,i){switch(r){case"front":return{x:0,z:-(e-i)};case"behind":return{x:0,z:e-i};case"left":return{x:-(t-i),z:0};case"right":return{x:t-i,z:0};case"front-left":return{x:-(t-i),z:-ls};case"front-right":return{x:t-i,z:-ls};case"behind-left":return{x:-(t-i),z:ls};case"behind-right":return{x:t-i,z:ls}}}function sv(r,t,e,i,n,s,a){const o=h0();o.scale.setScalar(i),o.rotation.y=iv[t];const{x:c,z:l}=o0(t,n,s,a);o.position.set(c,e,l),r.add(o)}const c0=6,l0=6,na=3,_o=1.4,So=na*.5,av=1.2,rv=.35,V5=.75,W5=1.6;function Rm(r,t,e,i){const n=new Ce,s=Math.max(1,r+1),a=s*na;ze(n,new $i(c0,a,l0),[.55,.54,.5],a/2);const o=c0/2,c=l0/2;for(let l=0;l<s;l++){const h=l*na+na/2;cs(n,_o,So,os,0,h,-c-rs,Vi(t,"front")),cs(n,_o,So,os,0,h,c+rs,Vi(t,"behind")),cs(n,os,So,_o,-o-rs,h,0,Vi(t,"left")),cs(n,os,So,_o,o+rs,h,0,Vi(t,"right"))}if(e){const l=Math.min(Math.max(i??0,0),s-1);sv(n,e,l*na,.72,o,c,av);const h=u=>Vi(t,u)!==void 0?[{main:_o,center:0}]:[];nv(n,o,c,l*na,(l+1)*na,So,h("front"),h("behind"),h("left"),h("right"))}return n}function Dm(){const r=new Ce,t=[[0,0,.55,.5],[.4,.1,.35,.4],[-.35,-.2,.4,.38],[.1,-.4,.35,.36],[-.15,.4,.3,.34]];for(const[e,i,n,s]of t){const a=new di(n,10,7);a.scale(1,.85,1),a.translate(e,0,i),ze(r,a,[.26,.28,.17],s)}return r}function X5(r){const t=new Ce,e=new Fe(hi.sizeOf(r),r.bridge).build();ze(t,e.concrete,[.6,.6,.58],0);const i=ze(t,e.road,[.2,.2,.21],0),n=ze(t,e.earth,[.3,.36,.22],0);for(const s of[i,n])s.material.side=Yi;return ze(t,e.railing,[.5,.52,.55],0),t}function Im(){const r=new Ce;return ze(r,new vs(.15,.22,2,8),[.32,.22,.14],1),ze(r,new jr(1.4,3,8),[.16,.32,.14],3.5),r}const Cm=.275,Y5=.35,q5=.9,$5=34,K5=8,Z5=1.4;function Pm(){const r=new Ce,t=new di(Cm,7,3,0,Math.PI*2,0,Math.PI/2);t.scale(1,Y5/Cm,1);const e=hi.repeatOnGrid(t,$5,q5,K5,Z5),i=ze(r,e,[.26,.28,.22],0);return i.castShadow=!0,i.userData.cropBasePositions=e.getAttribute("position").array.slice(),i.userData.cropVerticesPerClump=t.getAttribute("position").count,t.dispose(),r}function Lm(){const r=new Ce,t=new di(1,7,3,0,Math.PI*2,0,Math.PI/2);return ze(r,t,[.38,.36,.32],0),r}function Om(r){const t=new Ce;return ze(t,new vs(.05,.08,5,8),[.28,.28,.3],2.5),ze(t,new di(.25,12,8),r?tv:z5,5.1,!0),t}const J5=[.08,.08,.08],Js=.8,br=1,es=1.7,fu=.6,Sa=.4,nl=1.2,_r=.7,ls=.5,j5=es;function Nm(r,t,e){const i=new Ce;ze(i,new $i(1.8,1.4,4.2),[.45,.14,.14],.7),ze(i,new $i(Js*2,fu,br*2),[.4,.12,.12],es);for(const s of[-1.4,1.4])for(const a of[-.95,.95]){const o=ze(i,new vs(.4,.4,.3,12),J5,.4);o.rotation.z=Math.PI/2,o.position.x=a,o.position.z=s}const n=r?ev:B5;for(const s of[-.7,.7])ze(i,new di(.15,8,6),n,.7,!0).position.set(s,.7,-2.1);if(cs(i,nl,Sa,os,0,es,-br-rs,Vi(t,"front")),cs(i,nl,Sa,os,0,es,br+rs,Vi(t,"behind")),cs(i,os,Sa,_r,-Js-rs,es,-ls,Vi(t,"front-left")),cs(i,os,Sa,_r,-Js-rs,es,ls,Vi(t,"behind-left")),cs(i,os,Sa,_r,Js+rs,es,-ls,Vi(t,"front-right")),cs(i,os,Sa,_r,Js+rs,es,ls,Vi(t,"behind-right")),e){sv(i,e,V5,.5,Js,br,rv);const s=(c,l)=>{const h=[];return Vi(t,c)!==void 0&&h.push({main:_r,center:-ls}),Vi(t,l)!==void 0&&h.push({main:_r,center:ls}),h},a=Vi(t,"front")!==void 0?[{main:nl,center:0}]:[],o=Vi(t,"behind")!==void 0?[{main:nl,center:0}]:[];nv(i,Js,br,es-fu/2,es+fu/2,Sa,a,o,s("front-left","behind-left"),s("front-right","behind-right"))}return i}const Fm=new Map;function Um(r,t){if(!r)return;const e=[[r.lengthM,t.lengthM],[r.heightM,t.heightM],[r.widthM,t.widthM]];for(const[i,n]of e)if(i!==void 0&&n>1e-6)return i/n}function pu(r,t){return t>1e-6?r/t:1}const ov=[.95,.9,.82],km=[.72,.74,.78];function zm(){const r=new Ce;ze(r,new vs(.25,.3,1.5,10),km,.75),ze(r,new di(.26,10,8),km,1.74);const t=ze(r,new jr(.07,.16,8),ov,1.74);return t.rotation.x=-Math.PI/2,t.position.z=-.22,r}function h0(){const r=new Ce;ze(r,new vs(.25,.3,1.5,10),[.3,.3,.35],.75),ze(r,new di(.22,10,8),[.62,.52,.46],1.72);const t=ze(r,new jr(.07,.16,8),ov,1.72);return t.rotation.x=-Math.PI/2,t.position.z=-.2,r}const Q5=17,Bm=18.5,mu=[.16,.16,.18];function Hm(){const r=new Ce,t=ze(r,new vs(1.8,1.8,Bm*2,10),mu,0);t.rotation.x=Math.PI/2,ze(r,new $i(Q5*2,.5,4.5),mu,0);const e=ze(r,new $i(.4,5.5,4),mu,3);return e.position.z=-Bm+2,r}class hi{static GROWS_FROM_GROUND=new Set(["tree","shrub","crop","mound"]);static groundUnderFootprint(t,e,i,n,s,a=0){const o=hi.sizeOf(t);if(a>o.heightM)return s(e,i);const c=(n??0)*Math.PI/180,l=Math.min(21,Math.max(2,Math.ceil(o.lengthM/.75)+1)),h=Math.min(21,Math.max(2,Math.ceil(o.widthM/.75)+1)),u=hi.GROWS_FROM_GROUND.has(t.kind);let d=u?1/0:-1/0;for(let f=0;f<l;f++){const p=(f/(l-1)-.5)*o.lengthM;for(let v=0;v<h;v++){const m=(v/(h-1)-.5)*o.widthM,g=e+Math.sin(c)*p+Math.cos(c)*m,_=i-Math.cos(c)*p+Math.sin(c)*m;d=u?Math.min(d,s(g,_)):Math.max(d,s(g,_))}}return Number.isFinite(d)?d:s(e,i)}static occupantView(t){const e=t.observerSide;if(!e)throw new Error("occupantView requires object.observerSide to be set");const{x:i,z:n}=t.kind==="vehicle"?o0(e,Js,br,rv):o0(e,c0/2,l0/2,av),s=t.kind==="vehicle"?j5:(t.occupiedFloor??0)*na+W5,a=(t.headingDeg??0)-iv[e]/hu,o=this.scaleFor(t);return{x:i*o.x,z:n*o.z,eyeY:s*o.y,headingDeg:a}}static BODY_NAME="decor-body";static bodyOf(t){return t.getObjectByName(hi.BODY_NAME)??t}static repeatOnGrid(t,e,i,n,s){const a=t.getAttribute("position"),o=t.getAttribute("normal"),c=t.getIndex();if(!c)throw new Error("repeatOnGrid needs an indexed geometry");const l=a.count,h=e*n,u=new Float32Array(l*h*3),d=new Float32Array(l*h*3),f=new Uint32Array(c.count*h),p=-((e-1)*i)/2,v=-((n-1)*s)/2;let m=0;for(let _=0;_<n;_++)for(let y=0;y<e;y++,m++){const M=v+_*s,b=p+y*i;for(let w=0;w<l;w++){const T=(m*l+w)*3;u[T]=a.getX(w)+M,u[T+1]=a.getY(w),u[T+2]=a.getZ(w)+b,d[T]=o.getX(w),d[T+1]=o.getY(w),d[T+2]=o.getZ(w)}for(let w=0;w<c.count;w++)f[m*c.count+w]=c.getX(w)+m*l}const g=new ne;return g.setAttribute("position",new he(u,3)),g.setAttribute("normal",new he(d,3)),g.setIndex(new P0(f,1)),g}static fitCropToGround(t,e){t.updateMatrixWorld(!0);const i=new R;t.traverse(n=>{const s=n,a=s.userData.cropBasePositions,o=s.userData.cropVerticesPerClump;if(!s.isMesh||!a||!o)return;const c=s.geometry.getAttribute("position"),l=new Qt().copy(s.matrixWorld).invert();for(let h=0;h<c.count;h+=o){i.set(a[h*3],0,a[h*3+2]).applyMatrix4(s.matrixWorld),i.y=e(i.x,i.z),i.applyMatrix4(l);for(let u=h;u<h+o;u++)c.setY(u,a[u*3+1]+i.y)}c.needsUpdate=!0,s.geometry.computeBoundingBox(),s.geometry.computeBoundingSphere()})}static paint(t,e){t.traverse(i=>{const n=i,s=n.userData;if(!n.isMesh||s?.emissive)return;const a=n.material;a?.color&&a.color.set(e)})}static build(t,e){const i=t.kind==="building"?Rm(t.floors??Mf,t.windows,t.observerSide,t.occupiedFloor):t.kind==="tree"?Im():t.kind==="shrub"?Dm():t.kind==="bridge"?X5(t):t.kind==="crop"?Pm():t.kind==="mound"?Lm():t.kind==="streetlight"?Om(e):t.kind==="vehicle"?Nm(e,t.windows,t.observerSide):t.kind==="aircraft"?Hm():t.kind==="entity"?zm():h0();t.color&&this.paint(i,t.color);const n=this.scaleFor(t),s=new Ce;return i.name=hi.BODY_NAME,i.scale.copy(n),s.add(i),t.headingDeg!==void 0&&(s.rotation.y=-t.headingDeg*hu),this.addLights(s,t.lights),s}static scaleFor(t){const e=t.sizeM;if(!e||t.kind==="bridge")return new R(1,1,1);const i=this.naturalSize(t.kind,t.floors);return new R(e.widthM===void 0?1:pu(e.widthM,i.widthM),e.heightM===void 0?1:pu(e.heightM,i.heightM),e.lengthM===void 0?1:pu(e.lengthM,i.lengthM))}static naturalSize(t,e){const i=t==="building"?Math.max(1,(e??Mf)+1):0;if(t==="bridge")return Fe.NATURAL_SIZE;const n=`${t}:${i}`,s=Fm.get(n);if(s)return s;const a=t==="building"?Rm(i-1,void 0,void 0,void 0):t==="tree"?Im():t==="shrub"?Dm():t==="crop"?Pm():t==="mound"?Lm():t==="streetlight"?Om(!1):t==="vehicle"?Nm(!1,void 0,void 0):t==="aircraft"?Hm():t==="entity"?zm():h0(),o=new qi().setFromObject(a),c={widthM:o.max.x-o.min.x,heightM:o.max.y-o.min.y,lengthM:o.max.z-o.min.z};return this.dispose(a),Fm.set(n,c),c}static usesModel(t){return Bu(t)!==void 0&&!(t.observerSide!==void 0&&Sg(t.kind))}static applyModel(t,e,i,n={}){const s=this.bodyOf(t),a=new Ce;a.name=hi.BODY_NAME,i.rotation.y=-(n.headingOffsetDeg??0)*hu,i.updateMatrixWorld(!0);const o=new qi().setFromObject(i),c={lengthM:o.max.z-o.min.z,heightM:o.max.y-o.min.y,widthM:o.max.x-o.min.x},l=Um(e.sizeM,c)??Um(n.depictedSizeM,c)??1;i.scale.multiplyScalar(l);const h=o.getCenter(new R).multiplyScalar(l);i.position.x-=h.x,i.position.z-=h.z,i.position.y-=e.kind==="aircraft"?h.y:o.min.y*l,i.traverse(u=>{u instanceof At&&(u.castShadow=!0,u.receiveShadow=!0)}),a.add(i),s.parent?(s.parent.add(a),s.removeFromParent()):t.add(a),this.dispose(s)}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=k5(i.color),s=ze(t,new di(uu,8,6),n,i.offsetM.y,!0);s.position.set(i.offsetM.x,i.offsetM.y,i.offsetM.z),s.userData={emissive:!0,lightId:i.id,lightColor:n},s.visible=!1;const a=s.material;a.blending=Ai,a.transparent=!0,a.depthWrite=!1,a.fog=!1}}static setLights(t,e,i,n,s=0,a=1,o=P5,c=[1,1,1]){if(!e||e.length===0)return;const l=new Map(e.map(f=>[f.id,f])),h=Math.max(1,n*o/uu),u=uu*h,d=a/(Math.PI*u*u);for(const f of t.children){if(!(f instanceof At))continue;const p=f.userData.lightId;if(!p)continue;const v=l.get(p);if(!v)continue;const m=s>0?wg(v,i,i+s):Ev(v,i)?1:0;f.visible=m>0;const g=f.material,_=f.userData.lightColor;if(_){const y=m*L5*(v.intensity??1)*d;g.color.setRGB(_[0]*y*c[0],_[1]*y*c[1],_[2]*y*c[2])}f.scale.setScalar(h)}}static setLit(t,e,i,n=1){const[s,a,o]=e==="streetlight"?[O5,N5,tv]:[F5,U5,ev],c=i?s*n/(Math.PI*a*a):0,l=[o[0]*c,o[1]*c,o[2]*c];t.traverse(h=>{const u=h.userData;!(h instanceof At)||!u.emissive||u.lightId||h.material.color.setRGB(...l)})}static dispose(t){t.traverse(e=>{if(!(e instanceof At)||e.userData.sharedModel)return;e.geometry.dispose();const i=e.material;for(const n of Array.isArray(i)?i:[i])n.dispose()})}}const gu="https://ufoathome.org/models/index.json";class tE{attribution="3D models re-hosted by UFO@home, each under its own author's licence";fetchImpl;indexUrls;loading;constructor(t={}){this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.indexUrls=t.indexUrls??eE()}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(){return this.loading??=this.fetchFirstAvailable(),this.loading}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 eE(){const r=`?v=${encodeURIComponent("0.89.2")}`,t=typeof location>"u"?void 0:new URL("/models/index.json",location.href).href;return(t&&t!==gu?[t,gu]:[gu]).map(e=>e+r)}const iE=[{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 tE}];async function vu(r){const{GLTFLoader:t}=await rn(async()=>{const{GLTFLoader:i}=await import("./GLTFLoader-DYi1DaRQ.js");return{GLTFLoader:i}},[],import.meta.url),e=new t;return new Promise((i,n)=>{e.load(r,s=>i(Object.assign(s.scene,{animations:s.animations})),void 0,s=>n(new Error(`Could not load 3D model ${r}: ${s instanceof Error?s.message:String(s)}`)))})}const cv=["ellipsoid","sphere","disc","cylinder","cone","box","torus","figure"];class mn{static MIN_ANGLE_RAD=.002;static FILL=(1-Math.exp(-4))/4;static MAX_SHARE=.3;mesh;constructor(t,e){this.mesh=new At(new Ki(2,2),new ue({uniforms:{uColor:{value:new st(0,0,0)},uRadius:{value:1}},vertexShader:mn.VERTEX,fragmentShader:mn.FRAGMENT,transparent:!0,depthWrite:!1,blending:Ai,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*mn.MIN_ANGLE_RAD),a=mn.FILL*Math.PI*s*s;return{radiusM:s,luminanceCdM2:i*Math.min(mn.MAX_SHARE,e/a)}}static conserving(t){return Math.sqrt(t/(mn.MAX_SHARE*mn.FILL*Math.PI))}static VERTEX=`
7216
+ `,transparent:!0,blending:Ai,depthWrite:!1,side:Ye,fog:!1}),this.object=new At(new di(Oi.RADIUS,64,32),this.material),this.object.renderOrder=-1,this.object.frustumCulled=!1,this.object.visible=!1;const i=this.material.uniforms;this.deckUniforms={uSource:i.uSource,uUp:i.uUp,uStrength:i.uStrength,uTint:i.uTint,uMap:i.uMap,uGain:i.uGain,uHaloShown:{value:0}}}deckUniforms;shown=!1;hostedByDeck=!1;set hosted(t){this.hostedByDeck=t,this.show(this.shown)}show(t){this.shown=t,this.object.visible=t&&!this.hostedByDeck,this.deckUniforms.uHaloShown.value=t?1:0}get awaitingFirstDisplay(){return this.tracing&&!this.everDisplayed}setUrgent(t){this.urgent=t}set onReady(t){this.onRepaint=t}update(t,e,i,n,s,a){const o=this.material.uniforms;if(i<=0){o.uStrength.value=0,this.show(!1),this.stopWork();return}o.uSource.value.set(t.x,t.y,t.z).normalize(),o.uStrength.value=i,o.uTint.value.set(n[0],n[1],n[2]),o.uIceCover.value=s.cover,o.uIceHeight.value=s.layerHeight,this.show(this.everDisplayed),this.requestMap(e,a)}requestMap(t,e){if(!(!(Math.abs(t-this.mappedAltitudeDeg)<Oi.ALTITUDE_STEP_DEG)||!(Math.abs(e-this.mappedAlignment)<Oi.ALIGNMENT_STEP))){this.next=void 0;return}if(this.tracing){if(this.tracingFor(t,e)){this.next=void 0;return}if(!(!(Math.abs(t-this.pendingAltitudeDeg)<Oi.LEAP_ALTITUDE_DEG)||!(Math.abs(e-this.pendingAlignment)<Oi.LEAP_ALIGNMENT))){this.next={sourceAltitudeDeg:t,alignment:e};return}}this.next=void 0,this.pendingAltitudeDeg=t,this.pendingAlignment=e,this.sky.begin(t,e),this.tracing=!0,this.scheduleWork()}pendingAltitudeDeg=Number.NaN;pendingAlignment=Number.NaN;next;tracingFor(t,e){return this.tracing&&Math.abs(t-this.pendingAltitudeDeg)<Oi.ALTITUDE_STEP_DEG&&Math.abs(e-this.pendingAlignment)<Oi.ALIGNMENT_STEP}scheduleWork(){if(this.workHandle!==void 0)return;const t=()=>{if(this.workHandle=void 0,!this.tracing)return;const e=performance.now(),i=this.urgent?Oi.URGENT_BUDGET_MS:Oi.BUDGET_MS;do this.sky.trace(Oi.RAYS_PER_BATCH);while(this.sky.tracedRays<Oi.RAYS&&performance.now()-e<i);if(this.sky.tracedRays>=Oi.RAYS){this.publish(),this.tracing=!1,this.mappedAltitudeDeg=this.pendingAltitudeDeg,this.mappedAlignment=this.pendingAlignment;const s=this.next;s&&this.requestMap(s.sourceAltitudeDeg,s.alignment);return}this.workHandle=requestAnimationFrame(t)};this.workHandle=requestAnimationFrame(t)}stopWork(){this.workHandle!==void 0&&cancelAnimationFrame(this.workHandle),this.workHandle=void 0,this.tracing=!1,this.next=void 0}publish(){const e=this.sky.harvest().data;for(let i=0,n=0;n<e.length;i+=4,n+=3)this.texels[i]=Xn.toHalfFloat(e[n]),this.texels[i+1]=Xn.toHalfFloat(e[n+1]),this.texels[i+2]=Xn.toHalfFloat(e[n+2]),this.texels[i+3]=1;this.texture.needsUpdate=!0,this.everDisplayed=!0,this.show(this.material.uniforms.uStrength.value>0),this.onRepaint?.()}dispose(){this.stopWork(),this.texture.dispose(),this.object.geometry.dispose(),this.material.dispose()}}class Si{static MAX_CONCURRENT=24;static POINTS=8;static SEGMENTS=Si.POINTS-1;static ACROSS=3;static VERTICES_PER_SEGMENT=(Si.ACROSS-1)*6;static RADIUS=840;static MIN_HALF_WIDTH_DEG=.05;static BRIGHT_HALF_WIDTH_DEG=.22;object;positions;colors;meteors=[];radiantAltitudeDeg=0;radiantAzimuthDeg=0;constructor(){const t=Si.MAX_CONCURRENT*Si.SEGMENTS*Si.VERTICES_PER_SEGMENT;this.positions=new Float32Array(t*3),this.colors=new Float32Array(t*3);const e=new ne;e.setAttribute("position",new Zt(this.positions,3)),e.setAttribute("color",new Zt(this.colors,3)),e.setDrawRange(0,0),this.object=new At(e,new yn({vertexColors:!0,transparent:!0,blending:Ai,depthWrite:!1,fog:!1,side:Yi})),this.object.frustumCulled=!1}get schedule(){return this.meteors}setShower(t,e,i){this.meteors=t,this.radiantAltitudeDeg=e,this.radiantAzimuthDeg=i}update(t){const e=this.object.geometry;if(this.meteors.length===0){e.setDrawRange(0,0);return}const i=za.aliveAt(this.meteors,t).slice(0,Si.MAX_CONCURRENT);let n=0;for(const{meteor:s,progress:a}of i){const o=this.radiantOf(s);if(!o)continue;const c=Ke(o.altitudeDeg,o.azimuthDeg,1),[l,h]=this.basisAround(c),u=s.fromRadiantDeg+a*s.lengthDeg,d=Math.max(s.fromRadiantDeg,u-s.lengthDeg*.6),f=Math.min(1,(1-a)*2.5),p=this.turn(l,h,s.bearingDeg),v=(.15+.85*s.brightness)*f,m=y=>v*y**1.6,g=y=>this.onSphere(c,p,d+(u-d)*y),_=y=>Si.RADIUS*((Si.MIN_HALF_WIDTH_DEG+Si.BRIGHT_HALF_WIDTH_DEG*s.brightness*y)*Math.PI/180);for(let y=1;y<Si.POINTS;y++){const M=(y-1)/Si.SEGMENTS,b=y/Si.SEGMENTS;n=this.pushRibbon(n,g(M),g(b),_(M),_(b),m(M),m(b))}}e.setDrawRange(0,n),e.getAttribute("position").needsUpdate=!0,e.getAttribute("color").needsUpdate=!0}midpointOf(t){const e=this.radiantOf(t);if(!e)return;const i=Ke(e.altitudeDeg,e.azimuthDeg,1),[n,s]=this.basisAround(i),a=this.turn(n,s,t.bearingDeg),o=this.onSphere(i,a,t.fromRadiantDeg+t.lengthDeg/2),c=Math.hypot(o.x,o.y,o.z)||1;return{altitudeDeg:Math.asin(o.y/c)*180/Math.PI,azimuthDeg:(Math.atan2(o.x,-o.z)*180/Math.PI+360)%360}}radiantOf(t){return t.radiant?t.radiant:this.radiantAltitudeDeg>0?{altitudeDeg:this.radiantAltitudeDeg,azimuthDeg:this.radiantAzimuthDeg}:void 0}pushRibbon(t,e,i,n,s,a,o){const c=this.normalise(this.cross(this.normalise(e),this.normalise(this.subtract(i,e))));for(let l=0;l<Si.ACROSS-1;l++){const h=l-1,u=l,d=this.across(e,c,n,h),f=this.across(i,c,s,h),p=this.across(e,c,n,u),v=this.across(i,c,s,u),m=(g,_)=>g===0?_:0;t=this.push(t,d,m(h,a)),t=this.push(t,f,m(h,o)),t=this.push(t,p,m(u,a)),t=this.push(t,f,m(h,o)),t=this.push(t,v,m(u,o)),t=this.push(t,p,m(u,a))}return t}across(t,e,i,n){return{x:t.x+e.x*i*n,y:t.y+e.y*i*n,z:t.z+e.z*i*n}}push(t,e,i){const n=t*3;this.positions[n]=e.x,this.positions[n+1]=e.y,this.positions[n+2]=e.z;const s=wt.relativeOfResponse(Math.max(0,Math.min(1,i)));return this.colors[n]=s*.9,this.colors[n+1]=s*.95,this.colors[n+2]=s,t+1}turn(t,e,i){const n=i*Math.PI/180,s=Math.cos(n),a=Math.sin(n);return{x:t.x*s+e.x*a,y:t.y*s+e.y*a,z:t.z*s+e.z*a}}onSphere(t,e,i){const n=i*Math.PI/180,s=Math.cos(n),a=Math.sin(n);return{x:(t.x*s+e.x*a)*Si.RADIUS,y:(t.y*s+e.y*a)*Si.RADIUS,z:(t.z*s+e.z*a)*Si.RADIUS}}basisAround(t){const e=Math.abs(t.y)<.9?{x:0,y:1,z:0}:{x:1,y:0,z:0},i=this.normalise(this.cross(t,e));return[i,this.normalise(this.cross(t,i))]}subtract(t,e){return{x:t.x-e.x,y:t.y-e.y,z:t.z-e.z}}cross(t,e){return{x:t.y*e.z-t.z*e.y,y:t.z*e.x-t.x*e.z,z:t.x*e.y-t.y*e.x}}normalise(t){const e=Math.hypot(t.x,t.y,t.z)||1;return{x:t.x/e,y:t.y/e,z:t.z/e}}dispose(){this.object.geometry.dispose(),this.object.material.dispose()}}class Fe{constructor(t,e={}){this.size=t,this.span=Math.min(t.lengthM,Math.max(0,e.spanM??t.lengthM)),this.bank=(t.lengthM-this.span)/2,this.deck=Math.min(t.heightM,e.deckThicknessM??Fe.DEFAULT_DECK_THICKNESS_M),this.railHeight=e.railing?.heightM??Fe.DEFAULT_RAILING_HEIGHT_M,this.postSpacing=Math.max(.3,e.railing?.postSpacingM??Fe.DEFAULT_POST_SPACING_M),this.rails=Math.max(0,Math.round(e.railing?.rails??Fe.DEFAULT_RAILS))}static DEFAULT_DECK_THICKNESS_M=1.2;static DEFAULT_RAILING_HEIGHT_M=1.05;static DEFAULT_POST_SPACING_M=1.5;static DEFAULT_RAILS=2;static BANK_SLOPE=1.5;static ABUTMENT_THICKNESS_M=1;static POST_SIDE_M=.08;static RAIL_HEIGHT_M=.08;static RAIL_DEPTH_M=.06;static BANK_STATIONS=12;static NATURAL_SIZE=Object.freeze({widthM:9,lengthM:40,heightM:6.5});span;bank;deck;railHeight;postSpacing;rails;roadAt(t){const e=Math.abs(t)-this.span/2;return e<=0?this.size.heightM:this.bank<=0?0:Math.max(0,this.size.heightM*(1-e/this.bank))}build(){const{widthM:t,heightM:e}=this.size,i=this.span/2,n=[];if(this.span>0){n.push(Fe.box(t,this.deck,this.span,0,e-this.deck/2,0));for(const c of[-1,1]){const l=e-this.deck;l>0&&this.bank>0&&n.push(Fe.box(t+1,l,Fe.ABUTMENT_THICKNESS_M,0,l/2,c*(i-Fe.ABUTMENT_THICKNESS_M/2)))}}const s=[];this.span>0&&s.push(Fe.box(t,.04,this.span,0,e+.02,0));const a=[];for(const c of[-1,1])this.bank<=0||(a.push(this.embankment(c)),s.push(this.bankRoad(c)));const o=[];for(const c of[-1,1])o.push(...this.railing(c*(t/2-Fe.POST_SIDE_M)));return{concrete:Fe.merge(n),road:Fe.merge(s),earth:Fe.merge(a),railing:Fe.merge(o)}}embankment(t){const e=this.size.widthM/2,i=this.stations(t),n=[],s=(l,h,u,d)=>{n.push(l.x,l.y,l.z,h.x,h.y,h.z,u.x,u.y,u.z,l.x,l.y,l.z,u.x,u.y,u.z,d.x,d.y,d.z)},a=l=>{const h=this.roadAt(l),u=e+Fe.BANK_SLOPE*h;return{leftFoot:new R(-u,0,l),leftTop:new R(-e,h,l),rightTop:new R(e,h,l),rightFoot:new R(u,0,l)}};for(let l=1;l<i.length;l++){const h=a(i[l-1]),u=a(i[l]),d=t>0,f=(p,v,m,g)=>d?s(p,v,m,g):s(g,m,v,p);f(h.leftFoot,h.leftTop,u.leftTop,u.leftFoot),f(h.leftTop,h.rightTop,u.rightTop,u.leftTop),f(h.rightTop,h.rightFoot,u.rightFoot,u.rightTop)}const o=a(i[0]);t>0?s(o.leftFoot,o.rightFoot,o.rightTop,o.leftTop):s(o.leftTop,o.rightTop,o.rightFoot,o.leftFoot);const c=new ne;return c.setAttribute("position",new he(n,3)),c.computeVertexNormals(),c}bankRoad(t){const e=this.size.widthM/2,i=this.stations(t),n=[];for(let a=1;a<i.length;a++){const o=i[a-1],c=i[a],l=this.roadAt(o)+.02,h=this.roadAt(c)+.02,u=t>0?[[-e,l,o],[e,l,o],[e,h,c],[-e,h,c]]:[[-e,h,c],[e,h,c],[e,l,o],[-e,l,o]];for(const d of[0,2,1,0,3,2])n.push(...u[d])}const s=new ne;return s.setAttribute("position",new he(n,3)),s.computeVertexNormals(),s}stations(t){const e=[];for(let i=0;i<=Fe.BANK_STATIONS;i++)e.push(t*(this.span/2+this.bank*i/Fe.BANK_STATIONS));return e}railing(t){const e=this.size.lengthM/2,i=Math.max(1,Math.round(this.size.lengthM/this.postSpacing)),n=[];for(let o=0;o<=i;o++)n.push(-e+this.size.lengthM*o/i);const s=[],a=Fe.POST_SIDE_M;for(const o of n)s.push(Fe.box(a,this.railHeight,a,t,this.roadAt(o)+this.railHeight/2,o));for(let o=1;o<=this.rails;o++){const c=this.railHeight*o/this.rails-Fe.RAIL_HEIGHT_M/2;for(let l=1;l<n.length;l++){const h=new R(t,this.roadAt(n[l-1])+c,n[l-1]),u=new R(t,this.roadAt(n[l])+c,n[l]);s.push(Fe.beam(h,u))}}return s}static box(t,e,i,n,s,a){return new $i(t,e,i).translate(n,s,a)}static beam(t,e){const i=new R().subVectors(e,t),n=new $i(Fe.RAIL_DEPTH_M,Fe.RAIL_HEIGHT_M,i.length()),s=new on().setFromUnitVectors(new R(0,0,1),i.clone().normalize()),a=new R().addVectors(t,e).multiplyScalar(.5);return n.applyMatrix4(new Qt().compose(a,s,new R(1,1,1)))}static merge(t){const e=t.map(c=>c.getIndex()?c.toNonIndexed():c),i=e.reduce((c,l)=>c+l.getAttribute("position").count,0),n=new Float32Array(i*3),s=new Float32Array(i*3);let a=0;for(const c of e){const l=c.getAttribute("position"),h=c.getAttribute("normal");n.set(l.array,a*3),h&&s.set(h.array,a*3),a+=l.count}const o=new ne;o.setAttribute("position",new he(n,3)),o.setAttribute("normal",new he(s,3));for(const c of t)c.dispose();for(const c of e)c.dispose();return o}}const hu=Math.PI/180;function ze(r,t,e,i,n=!1){const s=n?new yn({color:new st(...e)}):new Wa({color:new st(...e)}),a=new At(t,s);return a.position.y=i,a.userData={emissive:n},a.castShadow=!n,a.receiveShadow=!n,r.add(a),a}const uu=.25,P5=.002,L5=100,O5=1500,N5=.25,F5=1e3,U5=.15;function k5(r){const t=/^#([0-9a-f]{6})$/i.exec(r);if(!t)return[1,1,1];const e=parseInt(t[1],16);return[(e>>16&255)/255,(e>>8&255)/255,(e&255)/255]}const z5=[.32,.32,.3],tv=[1,.85,.5],B5=[.25,.25,.25],ev=[1,.97,.85],H5=[.55,.68,.72],rs=.03,os=.05,iv={front:0,behind:Math.PI,left:Math.PI/2,right:-Math.PI/2,"front-left":Math.PI/2,"behind-left":Math.PI/2,"front-right":-Math.PI/2,"behind-right":-Math.PI/2};function Vi(r,t){return r?.[t]}function cs(r,t,e,i,n,s,a,o){if(o===void 0)return;const c=new Wa({color:new st(...H5),transparent:!0,opacity:o/100}),l=new At(new $i(t,e,i),c);l.position.set(n,s,a),r.add(l)}const An=.05,du=[.6,.58,.53],Tm=[.5,.5,.48];function Ir(r,t,e,i,n,s,a,o){const c=new Wa({color:new st(...o),side:Ye}),l=new At(new $i(t,e,i),c);l.position.set(n,s,a),r.add(l)}function G5(r,t,e,i,n,s,a,o,c){const l=(i-s)/2,h=(p,v,m,g)=>{p<=0||(t?Ir(r,p,v,An,m,o+g,a,c):Ir(r,An,v,p,a,o+g,m,c))};h(e,l,0,i/2-l/2),h(e,l,0,-(i/2-l/2));const u=[...n].sort((p,v)=>p.center-v.center);let d=-e/2;for(const p of u){const m=p.center-p.main/2-d;h(m,s,d+m/2,0),d=p.center+p.main/2}const f=e/2-d;h(f,s,d+f/2,0)}function nv(r,t,e,i,n,s,a,o,c,l){const h=(i+n)/2,u=n-i,d=(f,p,v,m)=>{f.length===0?p?Ir(r,v,u,An,0,h,m,du):Ir(r,An,u,v,m,h,0,du):G5(r,p,v,u,f,s,m,h,du)};d(a,!0,t*2,-e+An),d(o,!0,t*2,e-An),d(c,!1,e*2,-t+An),d(l,!1,e*2,t-An),Ir(r,t*2,An,e*2,0,i+An,0,Tm),Ir(r,t*2,An,e*2,0,n-An,0,Tm)}function o0(r,t,e,i){switch(r){case"front":return{x:0,z:-(e-i)};case"behind":return{x:0,z:e-i};case"left":return{x:-(t-i),z:0};case"right":return{x:t-i,z:0};case"front-left":return{x:-(t-i),z:-ls};case"front-right":return{x:t-i,z:-ls};case"behind-left":return{x:-(t-i),z:ls};case"behind-right":return{x:t-i,z:ls}}}function sv(r,t,e,i,n,s,a){const o=h0();o.scale.setScalar(i),o.rotation.y=iv[t];const{x:c,z:l}=o0(t,n,s,a);o.position.set(c,e,l),r.add(o)}const c0=6,l0=6,na=3,_o=1.4,So=na*.5,av=1.2,rv=.35,V5=.75,W5=1.6;function Rm(r,t,e,i){const n=new Ce,s=Math.max(1,r+1),a=s*na;ze(n,new $i(c0,a,l0),[.55,.54,.5],a/2);const o=c0/2,c=l0/2;for(let l=0;l<s;l++){const h=l*na+na/2;cs(n,_o,So,os,0,h,-c-rs,Vi(t,"front")),cs(n,_o,So,os,0,h,c+rs,Vi(t,"behind")),cs(n,os,So,_o,-o-rs,h,0,Vi(t,"left")),cs(n,os,So,_o,o+rs,h,0,Vi(t,"right"))}if(e){const l=Math.min(Math.max(i??0,0),s-1);sv(n,e,l*na,.72,o,c,av);const h=u=>Vi(t,u)!==void 0?[{main:_o,center:0}]:[];nv(n,o,c,l*na,(l+1)*na,So,h("front"),h("behind"),h("left"),h("right"))}return n}function Dm(){const r=new Ce,t=[[0,0,.55,.5],[.4,.1,.35,.4],[-.35,-.2,.4,.38],[.1,-.4,.35,.36],[-.15,.4,.3,.34]];for(const[e,i,n,s]of t){const a=new di(n,10,7);a.scale(1,.85,1),a.translate(e,0,i),ze(r,a,[.26,.28,.17],s)}return r}function X5(r){const t=new Ce,e=new Fe(hi.sizeOf(r),r.bridge).build();ze(t,e.concrete,[.6,.6,.58],0);const i=ze(t,e.road,[.2,.2,.21],0),n=ze(t,e.earth,[.3,.36,.22],0);for(const s of[i,n])s.material.side=Yi;return ze(t,e.railing,[.5,.52,.55],0),t}function Im(){const r=new Ce;return ze(r,new vs(.15,.22,2,8),[.32,.22,.14],1),ze(r,new jr(1.4,3,8),[.16,.32,.14],3.5),r}const Cm=.275,Y5=.35,q5=.9,$5=34,K5=8,Z5=1.4;function Pm(){const r=new Ce,t=new di(Cm,7,3,0,Math.PI*2,0,Math.PI/2);t.scale(1,Y5/Cm,1);const e=hi.repeatOnGrid(t,$5,q5,K5,Z5),i=ze(r,e,[.26,.28,.22],0);return i.castShadow=!0,i.userData.cropBasePositions=e.getAttribute("position").array.slice(),i.userData.cropVerticesPerClump=t.getAttribute("position").count,t.dispose(),r}function Lm(){const r=new Ce,t=new di(1,7,3,0,Math.PI*2,0,Math.PI/2);return ze(r,t,[.38,.36,.32],0),r}function Om(r){const t=new Ce;return ze(t,new vs(.05,.08,5,8),[.28,.28,.3],2.5),ze(t,new di(.25,12,8),r?tv:z5,5.1,!0),t}const J5=[.08,.08,.08],Js=.8,br=1,es=1.7,fu=.6,Sa=.4,nl=1.2,_r=.7,ls=.5,j5=es;function Nm(r,t,e){const i=new Ce;ze(i,new $i(1.8,1.4,4.2),[.45,.14,.14],.7),ze(i,new $i(Js*2,fu,br*2),[.4,.12,.12],es);for(const s of[-1.4,1.4])for(const a of[-.95,.95]){const o=ze(i,new vs(.4,.4,.3,12),J5,.4);o.rotation.z=Math.PI/2,o.position.x=a,o.position.z=s}const n=r?ev:B5;for(const s of[-.7,.7])ze(i,new di(.15,8,6),n,.7,!0).position.set(s,.7,-2.1);if(cs(i,nl,Sa,os,0,es,-br-rs,Vi(t,"front")),cs(i,nl,Sa,os,0,es,br+rs,Vi(t,"behind")),cs(i,os,Sa,_r,-Js-rs,es,-ls,Vi(t,"front-left")),cs(i,os,Sa,_r,-Js-rs,es,ls,Vi(t,"behind-left")),cs(i,os,Sa,_r,Js+rs,es,-ls,Vi(t,"front-right")),cs(i,os,Sa,_r,Js+rs,es,ls,Vi(t,"behind-right")),e){sv(i,e,V5,.5,Js,br,rv);const s=(c,l)=>{const h=[];return Vi(t,c)!==void 0&&h.push({main:_r,center:-ls}),Vi(t,l)!==void 0&&h.push({main:_r,center:ls}),h},a=Vi(t,"front")!==void 0?[{main:nl,center:0}]:[],o=Vi(t,"behind")!==void 0?[{main:nl,center:0}]:[];nv(i,Js,br,es-fu/2,es+fu/2,Sa,a,o,s("front-left","behind-left"),s("front-right","behind-right"))}return i}const Fm=new Map;function Um(r,t){if(!r)return;const e=[[r.lengthM,t.lengthM],[r.heightM,t.heightM],[r.widthM,t.widthM]];for(const[i,n]of e)if(i!==void 0&&n>1e-6)return i/n}function pu(r,t){return t>1e-6?r/t:1}const ov=[.95,.9,.82],km=[.72,.74,.78];function zm(){const r=new Ce;ze(r,new vs(.25,.3,1.5,10),km,.75),ze(r,new di(.26,10,8),km,1.74);const t=ze(r,new jr(.07,.16,8),ov,1.74);return t.rotation.x=-Math.PI/2,t.position.z=-.22,r}function h0(){const r=new Ce;ze(r,new vs(.25,.3,1.5,10),[.3,.3,.35],.75),ze(r,new di(.22,10,8),[.62,.52,.46],1.72);const t=ze(r,new jr(.07,.16,8),ov,1.72);return t.rotation.x=-Math.PI/2,t.position.z=-.2,r}const Q5=17,Bm=18.5,mu=[.16,.16,.18];function Hm(){const r=new Ce,t=ze(r,new vs(1.8,1.8,Bm*2,10),mu,0);t.rotation.x=Math.PI/2,ze(r,new $i(Q5*2,.5,4.5),mu,0);const e=ze(r,new $i(.4,5.5,4),mu,3);return e.position.z=-Bm+2,r}class hi{static GROWS_FROM_GROUND=new Set(["tree","shrub","crop","mound"]);static groundUnderFootprint(t,e,i,n,s,a=0){const o=hi.sizeOf(t);if(a>o.heightM)return s(e,i);const c=(n??0)*Math.PI/180,l=Math.min(21,Math.max(2,Math.ceil(o.lengthM/.75)+1)),h=Math.min(21,Math.max(2,Math.ceil(o.widthM/.75)+1)),u=hi.GROWS_FROM_GROUND.has(t.kind);let d=u?1/0:-1/0;for(let f=0;f<l;f++){const p=(f/(l-1)-.5)*o.lengthM;for(let v=0;v<h;v++){const m=(v/(h-1)-.5)*o.widthM,g=e+Math.sin(c)*p+Math.cos(c)*m,_=i-Math.cos(c)*p+Math.sin(c)*m;d=u?Math.min(d,s(g,_)):Math.max(d,s(g,_))}}return Number.isFinite(d)?d:s(e,i)}static occupantView(t){const e=t.observerSide;if(!e)throw new Error("occupantView requires object.observerSide to be set");const{x:i,z:n}=t.kind==="vehicle"?o0(e,Js,br,rv):o0(e,c0/2,l0/2,av),s=t.kind==="vehicle"?j5:(t.occupiedFloor??0)*na+W5,a=(t.headingDeg??0)-iv[e]/hu,o=this.scaleFor(t);return{x:i*o.x,z:n*o.z,eyeY:s*o.y,headingDeg:a}}static BODY_NAME="decor-body";static bodyOf(t){return t.getObjectByName(hi.BODY_NAME)??t}static repeatOnGrid(t,e,i,n,s){const a=t.getAttribute("position"),o=t.getAttribute("normal"),c=t.getIndex();if(!c)throw new Error("repeatOnGrid needs an indexed geometry");const l=a.count,h=e*n,u=new Float32Array(l*h*3),d=new Float32Array(l*h*3),f=new Uint32Array(c.count*h),p=-((e-1)*i)/2,v=-((n-1)*s)/2;let m=0;for(let _=0;_<n;_++)for(let y=0;y<e;y++,m++){const M=v+_*s,b=p+y*i;for(let w=0;w<l;w++){const T=(m*l+w)*3;u[T]=a.getX(w)+M,u[T+1]=a.getY(w),u[T+2]=a.getZ(w)+b,d[T]=o.getX(w),d[T+1]=o.getY(w),d[T+2]=o.getZ(w)}for(let w=0;w<c.count;w++)f[m*c.count+w]=c.getX(w)+m*l}const g=new ne;return g.setAttribute("position",new he(u,3)),g.setAttribute("normal",new he(d,3)),g.setIndex(new P0(f,1)),g}static fitCropToGround(t,e){t.updateMatrixWorld(!0);const i=new R;t.traverse(n=>{const s=n,a=s.userData.cropBasePositions,o=s.userData.cropVerticesPerClump;if(!s.isMesh||!a||!o)return;const c=s.geometry.getAttribute("position"),l=new Qt().copy(s.matrixWorld).invert();for(let h=0;h<c.count;h+=o){i.set(a[h*3],0,a[h*3+2]).applyMatrix4(s.matrixWorld),i.y=e(i.x,i.z),i.applyMatrix4(l);for(let u=h;u<h+o;u++)c.setY(u,a[u*3+1]+i.y)}c.needsUpdate=!0,s.geometry.computeBoundingBox(),s.geometry.computeBoundingSphere()})}static paint(t,e){t.traverse(i=>{const n=i,s=n.userData;if(!n.isMesh||s?.emissive)return;const a=n.material;a?.color&&a.color.set(e)})}static build(t,e){const i=t.kind==="building"?Rm(t.floors??Mf,t.windows,t.observerSide,t.occupiedFloor):t.kind==="tree"?Im():t.kind==="shrub"?Dm():t.kind==="bridge"?X5(t):t.kind==="crop"?Pm():t.kind==="mound"?Lm():t.kind==="streetlight"?Om(e):t.kind==="vehicle"?Nm(e,t.windows,t.observerSide):t.kind==="aircraft"?Hm():t.kind==="entity"?zm():h0();t.color&&this.paint(i,t.color);const n=this.scaleFor(t),s=new Ce;return i.name=hi.BODY_NAME,i.scale.copy(n),s.add(i),t.headingDeg!==void 0&&(s.rotation.y=-t.headingDeg*hu),this.addLights(s,t.lights),s}static scaleFor(t){const e=t.sizeM;if(!e||t.kind==="bridge")return new R(1,1,1);const i=this.naturalSize(t.kind,t.floors);return new R(e.widthM===void 0?1:pu(e.widthM,i.widthM),e.heightM===void 0?1:pu(e.heightM,i.heightM),e.lengthM===void 0?1:pu(e.lengthM,i.lengthM))}static naturalSize(t,e){const i=t==="building"?Math.max(1,(e??Mf)+1):0;if(t==="bridge")return Fe.NATURAL_SIZE;const n=`${t}:${i}`,s=Fm.get(n);if(s)return s;const a=t==="building"?Rm(i-1,void 0,void 0,void 0):t==="tree"?Im():t==="shrub"?Dm():t==="crop"?Pm():t==="mound"?Lm():t==="streetlight"?Om(!1):t==="vehicle"?Nm(!1,void 0,void 0):t==="aircraft"?Hm():t==="entity"?zm():h0(),o=new qi().setFromObject(a),c={widthM:o.max.x-o.min.x,heightM:o.max.y-o.min.y,lengthM:o.max.z-o.min.z};return this.dispose(a),Fm.set(n,c),c}static usesModel(t){return Bu(t)!==void 0&&!(t.observerSide!==void 0&&Sg(t.kind))}static applyModel(t,e,i,n={}){const s=this.bodyOf(t),a=new Ce;a.name=hi.BODY_NAME,i.rotation.y=-(n.headingOffsetDeg??0)*hu,i.updateMatrixWorld(!0);const o=new qi().setFromObject(i),c={lengthM:o.max.z-o.min.z,heightM:o.max.y-o.min.y,widthM:o.max.x-o.min.x},l=Um(e.sizeM,c)??Um(n.depictedSizeM,c)??1;i.scale.multiplyScalar(l);const h=o.getCenter(new R).multiplyScalar(l);i.position.x-=h.x,i.position.z-=h.z,i.position.y-=e.kind==="aircraft"?h.y:o.min.y*l,i.traverse(u=>{u instanceof At&&(u.castShadow=!0,u.receiveShadow=!0)}),a.add(i),s.parent?(s.parent.add(a),s.removeFromParent()):t.add(a),this.dispose(s)}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=k5(i.color),s=ze(t,new di(uu,8,6),n,i.offsetM.y,!0);s.position.set(i.offsetM.x,i.offsetM.y,i.offsetM.z),s.userData={emissive:!0,lightId:i.id,lightColor:n},s.visible=!1;const a=s.material;a.blending=Ai,a.transparent=!0,a.depthWrite=!1,a.fog=!1}}static setLights(t,e,i,n,s=0,a=1,o=P5,c=[1,1,1]){if(!e||e.length===0)return;const l=new Map(e.map(f=>[f.id,f])),h=Math.max(1,n*o/uu),u=uu*h,d=a/(Math.PI*u*u);for(const f of t.children){if(!(f instanceof At))continue;const p=f.userData.lightId;if(!p)continue;const v=l.get(p);if(!v)continue;const m=s>0?wg(v,i,i+s):Ev(v,i)?1:0;f.visible=m>0;const g=f.material,_=f.userData.lightColor;if(_){const y=m*L5*(v.intensity??1)*d;g.color.setRGB(_[0]*y*c[0],_[1]*y*c[1],_[2]*y*c[2])}f.scale.setScalar(h)}}static setLit(t,e,i,n=1){const[s,a,o]=e==="streetlight"?[O5,N5,tv]:[F5,U5,ev],c=i?s*n/(Math.PI*a*a):0,l=[o[0]*c,o[1]*c,o[2]*c];t.traverse(h=>{const u=h.userData;!(h instanceof At)||!u.emissive||u.lightId||h.material.color.setRGB(...l)})}static dispose(t){t.traverse(e=>{if(!(e instanceof At)||e.userData.sharedModel)return;e.geometry.dispose();const i=e.material;for(const n of Array.isArray(i)?i:[i])n.dispose()})}}const gu="https://ufoathome.org/models/index.json";class tE{attribution="3D models re-hosted by UFO@home, each under its own author's licence";fetchImpl;indexUrls;loading;constructor(t={}){this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.indexUrls=t.indexUrls??eE()}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(){return this.loading??=this.fetchFirstAvailable(),this.loading}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 eE(){const r=`?v=${encodeURIComponent("0.90.0")}`,t=typeof location>"u"?void 0:new URL("/models/index.json",location.href).href;return(t&&t!==gu?[t,gu]:[gu]).map(e=>e+r)}const iE=[{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 tE}];async function vu(r){const{GLTFLoader:t}=await rn(async()=>{const{GLTFLoader:i}=await import("./GLTFLoader-DYi1DaRQ.js");return{GLTFLoader:i}},[],import.meta.url),e=new t;return new Promise((i,n)=>{e.load(r,s=>i(Object.assign(s.scene,{animations:s.animations})),void 0,s=>n(new Error(`Could not load 3D model ${r}: ${s instanceof Error?s.message:String(s)}`)))})}const cv=["ellipsoid","sphere","disc","cylinder","cone","box","torus","figure"];class mn{static MIN_ANGLE_RAD=.002;static FILL=(1-Math.exp(-4))/4;static MAX_SHARE=.3;mesh;constructor(t,e){this.mesh=new At(new Ki(2,2),new ue({uniforms:{uColor:{value:new st(0,0,0)},uRadius:{value:1}},vertexShader:mn.VERTEX,fragmentShader:mn.FRAGMENT,transparent:!0,depthWrite:!1,blending:Ai,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*mn.MIN_ANGLE_RAD),a=mn.FILL*Math.PI*s*s;return{radiusM:s,luminanceCdM2:i*Math.min(mn.MAX_SHARE,e/a)}}static conserving(t){return Math.sqrt(t/(mn.MAX_SHARE*mn.FILL*Math.PI))}static VERTEX=`
7217
7217
  uniform float uRadius;
7218
7218
  varying vec2 vOffset;
7219
7219
  void main() {