@rr0/ufoathome 0.127.0 → 0.127.2

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.
@@ -359,7 +359,8 @@ const X2="modulepreload",Y2=function(r,t){return new URL(r,t).href},sm={},Fi=fun
359
359
  <div id="playback-flash" class="playback-flash" aria-hidden="true"></div>
360
360
  <!-- A thumbnail's only chrome (see MINIFIED_ATTRIBUTE): the played bar along the bottom edge, the time left above its right end,
361
361
  the sound button in the top-right corner. Hidden in every other player. -->
362
- <div class="mini-bar" aria-hidden="true"><div id="mini-played" class="mini-played"></div></div>
362
+ <!-- The bar is also where a click sets the position, as on the video sites: a band taller than the line, for a pointer to find. -->
363
+ <div id="mini-bar" class="mini-bar" aria-hidden="true"><div class="mini-track"><div id="mini-played" class="mini-played"></div></div></div>
363
364
  <span id="mini-remaining" class="mini-remaining"></span>
364
365
  <button id="mini-mute" type="button" class="mini-mute" title="Mute" aria-label="Mute" aria-pressed="false" hidden></button>
365
366
  <!-- What is being played, top left over the picture as on a video site, and there with the controls
@@ -972,13 +973,26 @@ canvas[data-cursor="rotate"] {
972
973
  left: 0;
973
974
  right: 0;
974
975
  bottom: 0;
975
- height: 3px;
976
- background: rgba(255, 255, 255, 0.3);
976
+ height: 14px;
977
+ cursor: pointer;
977
978
  pointer-events: none;
978
979
  opacity: 0;
979
980
  transition: opacity 0.15s;
980
981
  z-index: 3;
981
982
  }
983
+ .mini-track {
984
+ position: absolute;
985
+ left: 0;
986
+ right: 0;
987
+ bottom: 0;
988
+ height: 3px;
989
+ background: rgba(255, 255, 255, 0.3);
990
+ transition: height 0.1s;
991
+ }
992
+ /* Thicker under the pointer, as on the video sites: it says the bar can be clicked. */
993
+ .mini-bar:hover .mini-track {
994
+ height: 5px;
995
+ }
982
996
  .mini-played {
983
997
  height: 100%;
984
998
  width: 0;
@@ -1026,12 +1040,15 @@ canvas[data-cursor="rotate"] {
1026
1040
  }
1027
1041
  .stage.minified:hover .mini-bar,
1028
1042
  .stage.minified:not(.paused) .mini-bar,
1043
+ /* Once played, the bar stays under the cover, saying how far the reader got, as on the video sites. */
1044
+ .stage.minified:not(.unstarted) .mini-bar,
1029
1045
  .stage.minified:hover .mini-mute:not([hidden]) {
1030
1046
  opacity: 1;
1031
- pointer-events: auto;
1032
1047
  }
1033
- .stage.minified:hover .mini-bar {
1034
- pointer-events: none;
1048
+ /* Only while hovered: at rest a click anywhere on the thumbnail, its bar included, is the page's. */
1049
+ .stage.minified:hover .mini-bar,
1050
+ .stage.minified:hover .mini-mute:not([hidden]) {
1051
+ pointer-events: auto;
1035
1052
  }
1036
1053
  /* Only where there is a hover to speak of: a touch screen keeps ":hover" on whatever was touched last,
1037
1054
  and a focus ring on the button just tapped — either would keep the controls over the picture for
@@ -1629,9 +1646,9 @@ canvas[data-cursor="rotate"] {
1629
1646
  `;class _o{static DEFAULT_FOCAL_MM=50;static FOCAL_RANGE_MM={minMm:14,maxMm:135};static BODIES=[{id:"eos-450d",name:"Canon EOS 450D (APS-C)",widthMm:22.2,heightMm:14.8,pixelUm:5.2,year:2008},{id:"eos-60da",name:"Canon EOS 60Da (APS-C)",widthMm:22.3,heightMm:14.9,pixelUm:4.3,year:2012},{id:"eos-70d",name:"Canon EOS 70D (APS-C)",widthMm:22.5,heightMm:15,pixelUm:4.1,year:2013},{id:"eos-80d",name:"Canon EOS 80D (APS-C)",widthMm:22.3,heightMm:14.9,pixelUm:3.7,year:2016},{id:"eos-7d",name:"Canon EOS 7D (APS-C)",widthMm:22.3,heightMm:14.9,pixelUm:4.1,year:2009},{id:"eos-7d-ii",name:"Canon EOS 7D Mark II (APS-C)",widthMm:22.4,heightMm:15,pixelUm:4.1,year:2014},{id:"eos-5d",name:"Canon EOS 5D (full frame)",widthMm:35.8,heightMm:23.9,pixelUm:8.2,year:2005},{id:"eos-5d-ii",name:"Canon EOS 5D Mark II (full frame)",widthMm:36,heightMm:24,pixelUm:6.4,year:2008},{id:"eos-5d-iii",name:"Canon EOS 5D Mark III (full frame)",widthMm:36,heightMm:24,pixelUm:6.25,year:2012},{id:"eos-5d-iv",name:"Canon EOS 5D Mark IV (full frame)",widthMm:36,heightMm:24,pixelUm:5.36,year:2016},{id:"eos-6d",name:"Canon EOS 6D (full frame)",widthMm:35.8,heightMm:23.9,pixelUm:6.55,year:2012},{id:"eos-6d-ii",name:"Canon EOS 6D Mark II (full frame)",widthMm:36,heightMm:24,pixelUm:5.77,year:2017},{id:"nikon-d3",name:"Nikon D3 / D700 (full frame)",widthMm:36,heightMm:23.9,pixelUm:8.44,year:2007},{id:"nikon-d7000",name:"Nikon D7000 (DX)",widthMm:23.6,heightMm:15.6,pixelUm:4.78,year:2010},{id:"nikon-d7100",name:"Nikon D7100 / D7200 (DX)",widthMm:23.5,heightMm:15.6,pixelUm:3.9,year:2013},{id:"nikon-d500",name:"Nikon D500 / D7500 (DX)",widthMm:23.5,heightMm:15.7,pixelUm:4.2,year:2016}];static instruments(){return _o.BODIES.map(t=>({id:t.id,category:"dslr",name:t.name,projection:"rectilinear",frame:{widthMm:t.widthMm,heightMm:t.heightMm,focalLengthMm:_o.DEFAULT_FOCAL_MM,focalRangeMm:_o.FOCAL_RANGE_MM},fNumber:8,fNumberRange:{min:1.4,max:22},exposureSeconds:1/250,exposureRangeSeconds:{min:1/8e3,max:3600},years:{from:t.year},apertureBlades:7,detailUm:t.pixelUm,medium:{kind:"sensor",iso:100}}))}static names(){return Object.fromEntries(_o.BODIES.map(t=>[t.id,t.name]))}}class rs{static DEFAULT_EYEPIECE_MM=26;static DEFAULT_APPARENT_FIELD_DEG=52;static FIELD_STOP_MM=2*rs.DEFAULT_EYEPIECE_MM*Math.tan(rs.DEFAULT_APPARENT_FIELD_DEG*Math.PI/360);static RANGE={min:26/40*.63,max:26/6*3};static BINOCULARS=[{id:"binoculars-zeiss-6x30",name:"Carl Zeiss 6x30",magnification:6,apertureMm:30,trueFieldDeg:5,fromYear:1960},{id:"binoculars-zeiss-dialyt-10x40",name:"Carl Zeiss Dialyt 10x40 B T*",magnification:10,apertureMm:40,trueFieldDeg:6.3,fromYear:1975},{id:"binoculars-jenoptem-10x50",name:"Jenoptem 10x50 W",magnification:10,apertureMm:50,trueFieldDeg:7.3,fromYear:1960},{id:"binoculars-swarovski-7x50-habicht",name:"Swarovski 7x50 SL Habicht",magnification:7,apertureMm:50,trueFieldDeg:6.6,fromYear:1960},{id:"binoculars-swarovski-7x50-slc",name:"Swarovski 7x50 SLC",magnification:7,apertureMm:50,trueFieldDeg:7.1,fromYear:1990},{id:"binoculars-nikon-10x42-edg",name:"Nikon 10x42 EDG",magnification:10,apertureMm:42,trueFieldDeg:6.5,fromYear:2011},{id:"binoculars-canon-15x50-is",name:"Canon 15x50 IS All Weather",magnification:15,apertureMm:50,trueFieldDeg:4.5,fromYear:2008},{id:"binoculars-celestron-15x70",name:"Celestron 15x70 SkyMaster",magnification:15,apertureMm:70,trueFieldDeg:4.4,fromYear:1990},{id:"binoculars-miyauchi-25x141",name:"Miyauchi BR-141 Galaxy 45 25x141",magnification:25,apertureMm:141,trueFieldDeg:2.6,fromYear:2e3}];static TELESCOPES=[{id:"telescope-generic-60-700",name:"Telescope 60/700",apertureMm:60,focalLengthMm:700},{id:"telescope-generic-60-1000",name:"Telescope 60/1000",apertureMm:60,focalLengthMm:1e3},{id:"telescope-celestron-onyx-80edf",name:"Celestron Onyx 80EDF",apertureMm:80,focalLengthMm:500,fromYear:2010},{id:"telescope-celestron-c5",name:"Celestron C5 f/10",apertureMm:125,focalLengthMm:1250,fromYear:1970},{id:"telescope-celestron-c8",name:"Celestron C8 f/10",apertureMm:203,focalLengthMm:2032,fromYear:1970},{id:"telescope-celestron-c11",name:"Celestron C11 f/10",apertureMm:280,focalLengthMm:2800,fromYear:1970},{id:"telescope-celestron-c14",name:"Celestron C14 f/11",apertureMm:355.6,focalLengthMm:3910,fromYear:1970},{id:"telescope-meade-etx-80",name:"Meade ETX 80 f/5",apertureMm:80,focalLengthMm:400,fromYear:1996},{id:"telescope-meade-etx-90",name:"Meade ETX 90 f/13.8",apertureMm:90,focalLengthMm:1242,fromYear:1996},{id:"telescope-meade-etx-125",name:"Meade ETX 125 f/15",apertureMm:127,focalLengthMm:1900,fromYear:1996},{id:"telescope-meade-lx200-8",name:"Meade LX200 8 in f/10",apertureMm:200,focalLengthMm:2e3,fromYear:1992},{id:"telescope-meade-lx200-10",name:"Meade LX200 10 in f/10",apertureMm:250,focalLengthMm:2500,fromYear:1992},{id:"telescope-meade-lx200-12",name:"Meade LX200 12 in f/10",apertureMm:305,focalLengthMm:3048,fromYear:1992},{id:"telescope-meade-lx200-14",name:"Meade LX200 14 in f/10",apertureMm:355,focalLengthMm:3556,fromYear:1992},{id:"telescope-meade-lx200-16",name:"Meade LX200 16 in f/10",apertureMm:406,focalLengthMm:4064,fromYear:1992}];static instruments(){const t=rs.BINOCULARS.map(n=>({id:n.id,category:"binoculars",name:n.name,projection:"rectilinear",visualAid:{apertureMm:n.apertureMm,magnification:n.magnification,trueFieldDeg:n.trueFieldDeg},...n.fromYear!==void 0?{years:{from:n.fromYear}}:{}})),e=rs.FIELD_STOP_MM,i=rs.TELESCOPES.map(n=>({id:n.id,category:"telescope",name:n.name,projection:"rectilinear",frame:{widthMm:e*16/9,heightMm:e,focalLengthMm:n.focalLengthMm,focalRangeMm:{minMm:n.focalLengthMm*rs.RANGE.min,maxMm:n.focalLengthMm*rs.RANGE.max}},visualAid:{apertureMm:n.apertureMm,eyepieceFocalMm:rs.DEFAULT_EYEPIECE_MM},...n.fromYear!==void 0?{years:{from:n.fromYear}}:{}}));return[...t,...i]}static names(){return Object.fromEntries(rs.instruments().map(t=>[t.id,t.name]))}}const Il=[{id:"eye",category:"eye",name:"Naked eye",flare:0,projection:"equidistant",stabilization:.97},{id:"rectilinear-lens",category:"camera",name:"Camera, unknown device",projection:"rectilinear",fNumber:8,fNumberRange:{min:2,max:22},exposureSeconds:1/250,exposureRangeSeconds:{min:1/1e3,max:8},apertureBlades:6},{id:"roamer-1-120",category:"camera",name:"Roamer 1, 120 film",projection:"rectilinear",frame:{widthMm:74,heightMm:60,focalLengthMm:100},fNumber:11,exposureSeconds:1/50,years:{from:1930,to:1965},detailUm:40,medium:{kind:"negative",iso:125}},{id:"instamatic-126",category:"camera",name:"Instamatic, 126 film",projection:"rectilinear",frame:{widthMm:28,heightMm:28,focalLengthMm:43},fNumber:11,exposureSeconds:1/90,years:{from:1963,to:1988},apertureBlades:5,detailUm:20,medium:{kind:"negative",iso:64}},{id:"slr-35mm-50",category:"camera",name:"35 mm SLR, 50 mm lens",projection:"rectilinear",frame:{widthMm:36,heightMm:24,focalLengthMm:50},fNumber:8,fNumberRange:{min:2,max:16},exposureSeconds:1/250,exposureRangeSeconds:{min:1/1e3,max:3600},years:{from:1959},apertureBlades:6,detailUm:20,medium:{kind:"negative",iso:100}},{id:"slr-35mm-zoom",category:"camera",name:"35 mm SLR, 70-210 mm zoom",projection:"rectilinear",frame:{widthMm:36,heightMm:24,focalLengthMm:135,focalRangeMm:{minMm:70,maxMm:210}},fNumber:8,fNumberRange:{min:4,max:22},exposureSeconds:1/250,exposureRangeSeconds:{min:1/1e3,max:3600},apertureBlades:8,years:{from:1975},detailUm:20,medium:{kind:"negative",iso:100}},{id:"phone-landscape",category:"phone",name:"Phone, held sideways",projection:"rectilinear",frame:{widthMm:7.6,heightMm:5.7,focalLengthMm:5.7},fNumber:1.8,exposureSeconds:1/120,exposureRangeSeconds:{min:1/8e3,max:10},years:{from:2007},apertureBlades:void 0,detailUm:1.4,medium:{kind:"sensor",iso:100,autoExposure:!0}},{id:"phone-portrait",category:"phone",name:"Phone, held upright",projection:"rectilinear",frame:{widthMm:5.7,heightMm:7.6,focalLengthMm:5.7},fNumber:1.8,exposureSeconds:1/120,exposureRangeSeconds:{min:1/8e3,max:10},years:{from:2007},apertureBlades:void 0,detailUm:1.4,medium:{kind:"sensor",iso:100,autoExposure:!0}},..._o.instruments(),...rs.instruments()];class Pi{static get default(){return Il[0]}static byId(t){return Il.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:t.visualAid?.trueFieldDeg??Pi.UNAIDED_FIELD_DEG}static aspectOf(t){const e=t.frame;return e?e.widthMm/e.heightMm:Pi.UNAIDED_ASPECT}static frameWidthPx(t,e){return Math.round(e*Pi.aspectOf(t))}static CATEGORIES=["eye","camera","dslr","phone","binoculars","telescope"];static unavailability(t,e){const i=t.years;if(!(e===void 0||!i)){if(e<i.from)return{kind:"before",from:i.from};if(i.to!==void 0&&e>i.to)return{kind:"after",to:i.to}}}static availableAt(t){return t===void 0?Il:Il.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??Pi.LENS_FLARE_ARTIFACTS}static starPointsOf(t){const e=t.apertureBlades;return e===void 0||e<3?0:e%2===0?e:e*2}}class ko{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 ko(e)}static TRAVEL_M=50;get travels(){return this.spanM>ko.TRAVEL_M}get moved(){return this.spanM>ko.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(le(e,t.east,e,t.west).x),Math.abs(le(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:Bn(0,-s,i,n).lat,south:Bn(0,s,i,n).lat,east:Bn(s,0,i,n).lng,west:Bn(-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 qn{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)>qn.HAND_HELD_S,i=t.sway??(e?0:1);if(i>0)return new qn(Math.max(1-(t.instrument.stabilization??0),qn.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]=qn.HZ;return{eastM:i*qn.SWAY_M*(.7*n(s,.3)+.3*n(c,1.9)),northM:i*qn.SWAY_M*(.6*n(o,2.2)+.4*n(l,.8)),upM:i*qn.BREATH_M*n(a,0),yawDeg:i*this.rotationPassed*qn.DRIFT_YAW_DEG*(.6*n(h,1.1)+.4*n(c,2.7)),pitchDeg:i*this.rotationPassed*qn.DRIFT_PITCH_DEG*(.5*n(a,1.6)+.5*n(o,.4)),rollDeg:i*this.rotationPassed*qn.DRIFT_ROLL_DEG*n(s,2.9)}}}class ze{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=ko.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=le(o.lat,o.lng,a.lat,a.lng),h=l.x,u=-l.z,d=Math.hypot(h,u),f=d/c,p=ze.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 ze(i,1-(t.instrument.stabilization??0))}static bodyAt(t,e,i=!1){const n=ze.of(t)?.offsetAt(e)??ze.STILL;return i?n:ze.add(n,qn.of(t)?.offsetAt(e))}static stepHzFor(t){return t<ze.SLOWEST_WALK_M_PER_S||t>ze.FASTEST_WALK_M_PER_S?0:ze.REFERENCE_STEP_HZ*Math.pow(t/ze.REFERENCE_SPEED_M_PER_S,ze.CADENCE_EXPONENT)}offsetAt(t){return ze.add(this.cycleAt(t),this.joltAt(t))}joltAt(t){for(const e of this.stretches){if(e.stepHz===0)continue;const i=e.speedMPerS/ze.REFERENCE_SPEED_M_PER_S,n=(o,c,l,h)=>{if(o<0||o>ze.JOLT_LASTS_MS)return;const u=o/1e3,d=Math.exp(-u/ze.JOLT_DECAY_S)*Math.sin(2*Math.PI*ze.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,ze.STOP_LURCH_M,ze.STOP_PITCH_DEG,1):void 0;if(s)return s;const a=e.rampsIn?n(t-e.startMs,ze.START_LURCH_M,ze.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 ze.STILL;const i=e.stepsBefore+e.stepHz*(t-e.startMs)/1e3,n=2*Math.PI*i,s=this.amplitudeAt(e,t),a=ze.SWAY_M*s*Math.cos(n/2),o=s*this.rotationPassed*e.speedMPerS/ze.REFERENCE_SPEED_M_PER_S;return{eastM:a*e.northUnit,northM:-a*e.eastUnit,upM:ze.RISE_M_PER_M_PER_S*e.speedMPerS*s*Math.cos(n),rollDeg:ze.HEAD_ROLL_DEG*o*Math.cos(n/2),pitchDeg:-1.25*o*Math.cos(n),yawDeg:ze.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 Vc{static ISO=/^P(?:(\d+(?:[.,]\d+)?)W)?(?:(\d+(?:[.,]\d+)?)D)?(?:T(?:(\d+(?:[.,]\d+)?)H)?(?:(\d+(?:[.,]\d+)?)M)?(?:(\d+(?:[.,]\d+)?)S)?)?$/;static seconds(t){const e=t.trim().toUpperCase(),i=Vc.ISO.exec(e);if(!i||e==="P"||e.endsWith("T"))return;const[,n,s,a,o,c]=i,l=u=>u===void 0?0:Number(u.replace(",",".")),h=l(n)*604800+l(s)*86400+l(a)*3600+l(o)*60+l(c);return Number.isFinite(h)?h:void 0}static parse(t){let e=t.trim();if(e==="")return;const i=e.slice(-1),n="?~%".includes(i)?i:"";n!==""&&(e=e.slice(0,-1).trim());const s=e.split("/");if(s.length>2)return;const a=s.map(u=>Vc.seconds(u));if(a.some(u=>u===void 0))return;const[o,c]=a,l=Math.min(o,c??o),h=Math.max(o,c??o);return{doubt:n,minSeconds:l,maxSeconds:h,chosenSeconds:(l+h)/2}}static isExact(t){const e=Vc.parse(t);return e!==void 0&&e.doubt===""&&e.minSeconds===e.maxSeconds}static format(t){const e=Math.max(0,Math.round(t*10)/10),i=Math.floor(e/3600),n=Math.floor(e%3600/60),s=Math.round(e%60*10)/10;return`PT${`${i>0?`${i}H`:""}${n>0?`${n}M`:""}${s>0||i===0&&n===0?`${s}S`:""}`}`}static say(t){const e=Math.round(t*10)/10;if(e<60)return`${e} s`;const i=Math.floor(e/3600),n=Math.floor(e%3600/60),s=Math.round(e%60*10)/10,a=[];return i>0&&a.push(`${i} h`),n>0&&a.push(`${n} min`),s>0&&a.push(`${s} s`),a.join(" ")}}class Xe{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/Xe.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 hy(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 uy(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 _n(r,t,e){return r+(t-r)*e}function mm(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 dy(r){return`#${r.map(t=>Math.round(t).toString(16).padStart(2,"0")).join("")}`}function fy(r,t,e){const i=mm(r),n=mm(t);return!i||!n?e<1?r:t:dy([_n(i[0],n[0],e),_n(i[1],n[1],e),_n(i[2],n[2],e)])}function py(r,t,e){const i={x:_n(r.bounds.x,t.bounds.x,e),y:_n(r.bounds.y,t.bounds.y,e),width:_n(r.bounds.width,t.bounds.width,e),height:_n(r.bounds.height,t.bounds.height,e)},n=_n(r.angle,t.angle,e),s=_n(r.transparency,t.transparency,e),a=_n(r.haloScale,t.haloScale,e),o=_n(r.blur??0,t.blur??0,e),c=_n(r.brightness??0,t.brightness??0,e),l=fy(r.color,t.color,e),h=Xe.lerpAngular(r.angular,t.angular,e),u=hy(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:_n(d.x,t.points[f].x,e),y:_n(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 ur{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=ur.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??ur.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:`"${ur.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:{...ur.NEUTRAL_BOUNDS},color:ur.DEFAULT_COLOR,angle:0,transparency:0,haloScale:0,selected:!1}}static NEUTRAL_BOUNDS={x:Xe.CANVAS_WIDTH_PX/2,y:Xe.CANVAS_HEIGHT_PX/2,width:1,height:1}}class Du{keyframes=[];order=[];groups=[];span=0;addKeyframe(t,e){const i=this.findInsertIndex(t);if(this.keyframes[i]?.t===t){const n=new Set(e.map(s=>s.sourceId));this.keyframes[i]={t,shapes:[...this.keyframes[i].shapes.filter(s=>!n.has(s.sourceId)),...e]}}else this.keyframes.splice(i,0,{t,shapes:[...e]});for(const n of e)this.order.includes(n.sourceId)||this.order.push(n.sourceId)}findInsertIndex(t){let e=0,i=this.keyframes.length;for(;e<i;){const n=e+i>>>1;this.keyframes[n].t<t?e=n+1:i=n}return e}getKeyframeAt(t){const e=this.findInsertIndex(t),i=this.keyframes[e];return i?.t===t?i:void 0}getShapeAt(t,e){return this.getKeyframeAt(t)?.shapes.find(i=>i.sourceId===e)?.shape}getLatestShapeAt(t,e){let i=this.findInsertIndex(t);for(this.keyframes[i]?.t!==t&&(i-=1);i>=0;i--){const n=this.keyframes[i].shapes.find(s=>s.sourceId===e);if(n)return n.shape}}getInterpolatedShapeAt(t,e){const i=this.findShapeAtOrBefore(t,e);if(i?.t===t)return i.shape;const n=this.findShapeAtOrAfter(t,e);return i?n?py(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&&uy(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(){const t=this.keyframes.length===0?0:this.keyframes[this.keyframes.length-1].t;return Math.max(t,this.span)}get hasSpan(){return this.span>0}setSpan(t){this.span=Math.max(0,t)}get sourceIds(){return[...this.order]}get allKeyframes(){return this.keyframes}toJSON(){return this.span>0?{keyframes:this.keyframes,order:this.order,groups:this.groups,span:this.span}:{keyframes:this.keyframes,order:this.order,groups:this.groups}}static fromJSON(t,e){const i=new Du;for(const n of ur.complete(t.keyframes??[],e))i.addKeyframe(n.t,n.shapes);if(t.span!==void 0&&t.span>0&&(i.span=t.span),t.order){const n=i.order.filter(s=>!t.order.includes(s));i.order=[...t.order,...n]}return t.groups&&(i.groups=t.groups.map(n=>n.filter(s=>i.order.includes(s))).filter(n=>n.length>=2)),i}}function my(r,t,e){return Math.max(t,Math.min(e,r))}function gy(r,t,e){const i=((t-r)%360+540)%360-180;return((r+i*e)%360+360)%360}function Wr(r,t,e){return r+(t-r)*e}function vy(r,t,e){return{lat:r.lat===void 0||t.lat===void 0?void 0:Wr(r.lat,t.lat,e),lng:r.lng===void 0||t.lng===void 0?void 0:Wr(r.lng,t.lng,e),elevationM:Wr(r.elevationM,t.elevationM,e),headingDeg:r.headingDeg===void 0||t.headingDeg===void 0?void 0:gy(r.headingDeg,t.headingDeg,e),pitchDeg:Wr(r.pitchDeg,t.pitchDeg,e),rollDeg:Wr(r.rollDeg??0,t.rollDeg??0,e),fovDeg:Wr(r.fovDeg,t.fovDeg,e),fNumber:r.fNumber,focusDistanceM:r.focusDistanceM,filter:r.filter}}class Er{static at(t,e,i,n,s){const a=t[i],c=t[i+1]-a;if(c<=0)return e[i];const l=Er.tangent(t,e,i,s),h=Er.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,Er.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 ol{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=vy(i.pose,n.pose,my((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(x=>x.t),l=(x,M)=>{const w=a.map(b=>x(b.pose));if(!w.some(b=>b===void 0))return Er.at(c,w,o,e,M)},h=a.map(x=>x.pose.headingDeg);let u;if(h.every(x=>x!==void 0)){const x=[h[0]];for(let M=1;M<h.length;M++)x.push(x[M-1]+((h[M]-h[M-1])%360+540)%360-180);u=(Er.at(c,x,o,e,!0)%360+360)%360}const d=this.keyframes[t],f=this.keyframes[t+1],p=(x,M)=>x.lat===M.lat&&x.lng===M.lng&&x.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 y;if(m||g){const x=Er.paced((e-d.t)/(f.t-d.t),(f.t-d.t)/1e3,m,g),M=(w,b)=>w===void 0||b===void 0?void 0:w+(b-w)*x;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:y?y.lat:l(x=>x.lat,!1)??i.lat,lng:y?y.lng:l(x=>x.lng,!1)??i.lng,elevationM:y?y.elevationM:l(x=>x.elevationM,!1)??i.elevationM,headingDeg:u??i.headingDeg,pitchDeg:l(x=>x.pitchDeg,!0)??i.pitchDeg,rollDeg:l(x=>x.rollDeg??0,!0)??i.rollDeg,fovDeg:l(x=>x.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 ol;for(const i of t.keyframes)e.addKeyframe(i.t,i.pose);return e}}class Ua{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(Ua.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?Ua.follow(this.followed[e],i.intensity,n.intensity,(n.t-i.t)/1e3,(t-i.t)/1e3):Ua.follow(this.followed[e],i.intensity,i.intensity,1,(t-i.t)/1e3);return{type:Ua.typeBetween(i,n,t,s),intensity:s,character:Ua.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=Ua.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 x=h<n?o:0;if(Math.abs(x)<=a){const w=h<n?Math.min(s,n):s;l=c(w),h=w;continue}const M=Math.min(s,n);l+=Math.sign(x)*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,y=Math.min(s,m,g);l+=f*a*(y-h),h=y,y===m&&(l=c(h))}return Math.min(1,Math.max(0,l))}}function ti(r,t,e){return r+(t-r)*e}function ep(r,t,e){const i=((t-r)%360+540)%360-180;return((r+i*e)%360+360)%360}function My(r,t,e){return Math.max(t,Math.min(e,r))}function yy(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:ti(a.eastM,o.eastM,e),northM:ti(a.northM,o.northM,e),baseM:ti(a.baseM,o.baseM,e),thicknessM:ti(a.thicknessM,o.thicknessM,e),widthM:ti(a.widthM,o.widthM,e),depthM:ti(a.depthM,o.depthM,e),rotationDeg:ep(a.rotationDeg,o.rotationDeg,e),density:ti(a.density,o.density,e),darkness:ti(a.darkness??0,o.darkness??0,e)}})}function xy(r,t,e){if(r.cloudLayers===void 0&&t.cloudLayers===void 0)return;const i=tu(r),n=tu(t);return e>=1?n.map(a=>({...a})):[...new Set([...i.map(a=>a.id),...n.map(a=>a.id)])].map(a=>{const 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:yy(o?.instances,c?.instances,e),baseM:ti(l.baseM,h.baseM,e),thicknessM:ti(l.thicknessM,h.thicknessM,e),coverage:ti(l.coverage,h.coverage,e),sizeM:ti(l.sizeM,h.sizeM,e),density:ti(l.density,h.density,e),darkness:ti(l.darkness??r.cloudDarkness,h.darkness??t.cloudDarkness,e),iceCrystalAlignment:l.iceCrystalAlignment===void 0||h.iceCrystalAlignment===void 0?void 0:ti(l.iceCrystalAlignment,h.iceCrystalAlignment,e),windSpeed:l.windSpeed===void 0&&h.windSpeed===void 0?void 0:ti(l.windSpeed??r.windSpeed,h.windSpeed??t.windSpeed,e),windDirectionDeg:l.windDirectionDeg===void 0&&h.windDirectionDeg===void 0?void 0:ep(l.windDirectionDeg??r.windDirectionDeg,h.windDirectionDeg??t.windDirectionDeg,e)}})}function Sy(r,t,e){return{cloudLayers:xy(r,t,e),cloudCover:ti(r.cloudCover,t.cloudCover,e),cloudDarkness:ti(r.cloudDarkness,t.cloudDarkness,e),highCloudCover:r.highCloudCover===void 0||t.highCloudCover===void 0?void 0:ti(r.highCloudCover,t.highCloudCover,e),iceCrystalAlignment:r.iceCrystalAlignment===void 0||t.iceCrystalAlignment===void 0?void 0:ti(r.iceCrystalAlignment,t.iceCrystalAlignment,e),rareIceCrystals:r.rareIceCrystals===void 0||t.rareIceCrystals===void 0?void 0:ti(r.rareIceCrystals,t.rareIceCrystals,e),lowerCloudCover:r.lowerCloudCover===void 0||t.lowerCloudCover===void 0?void 0:ti(r.lowerCloudCover,t.lowerCloudCover,e),cloudBaseM:r.cloudBaseM===void 0||t.cloudBaseM===void 0?void 0:ti(r.cloudBaseM,t.cloudBaseM,e),relativeHumidity:r.relativeHumidity===void 0||t.relativeHumidity===void 0?void 0:ti(r.relativeHumidity,t.relativeHumidity,e),precipitationType:e<1?r.precipitationType:t.precipitationType,precipitationIntensity:ti(r.precipitationIntensity,t.precipitationIntensity,e),windDirectionDeg:ep(r.windDirectionDeg,t.windDirectionDeg,e),windSpeed:ti(r.windSpeed,t.windSpeed,e),storm:e<1?r.storm:t.storm}}class cl{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?Sy(i.weather,n.weather,My((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 Ua(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 cl;for(const i of t.keyframes)e.addKeyframe(i.t,{...Ru,...i.weather});return e}}class ll{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 ll;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 wy=100,by={kind:"none",volume:0,pitchHz:wy};class Zn{constructor(t){this.entries=t}static empty(){return new Zn(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 Zn(new Map);return{recording:Zn.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=Zn.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 Zn.isWrapper(t)?(i.set(e.join("."),{basis:t.basis??"stated",...t.rationale===void 0?{}:{rationale:t.rationale},of:t.value}),Zn.stripValue(t.value,e,i)):Array.isArray(t)?t.map((n,s)=>Zn.stripValue(n,[...e,String(s)],i)):typeof t=="object"&&t!==null?Object.fromEntries(Object.entries(t).map(([n,s])=>[n,Zn.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 b0(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 gm(r){return(((r.day??0)*24+(r.hour??0))*60+(r.minute??0))*6e4+(r.second??0)*1e3}const _y=["year","month","day","hour","minute"],Ey=["day","hour","minute"];function vm(r,t){return t.filter(e=>r[e]!==void 0).join(",")}function Ay(r){if(r.durationSeconds!==void 0)return r.durationSeconds*1e3;const t=r.durationText===void 0?void 0:Vc.parse(r.durationText);if(t)return t.chosenSeconds*1e3;if(!r.time||!r.endTime)return;const e=r.time.year!==void 0&&r.endTime.year!==void 0,i=e?_y:Ey,n=vm(r.time,i);if(!(n===""||n!==vm(r.endTime,i)))return e?b0(r.endTime)-b0(r.time):gm(r.endTime)-gm(r.time)}class Iu{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=Zn.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 Pi.byId(this.instrumentId)}static create(t,e,i){return new Iu({eventType:"sighting",time:t,place:e},new Du,new ol,new cl,new ll,i)}}const Ty=0,Ry=0;function si(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:Ty,headingDeg:void 0,pitchDeg:Ry,fovDeg:Pi.fieldOfViewDeg(r.instrument)}}function dc(r,t){return r.weatherTrack.getInterpolatedWeatherAt(t)??r.weather??Ru}function Cl(r,t){return r.weatherTrack.getActualWeatherAt(t)??r.weather??Ru}function Dy(r,t){return r.soundTrack.getInterpolatedSoundAt(t)??by}class Iy{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 kv=["nw","n","ne","e","se","s","sw","w"],Cy=24,Pl=8,Py=3,Oy=8;function Ol(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 fc(r){return{x:r.x+r.width/2,y:r.y+r.height/2}}const Ly={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 Fn{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-Cy}},o=fc(t.bounds),c={};for(const l of Object.keys(a))c[l]=Ol(a[l],o,t.angle);return c}static hitTestHandle(t,e,i=8,n=[...kv,"rotate"]){const s=Fn.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=((Fn.HANDLE_DIRECTION_DEG[t]+e*180/Math.PI)%180+180)%180/45,s=["ew","nwse","ns","nesw"];return s[Math.round(n)%s.length]}static resizeBounds(t,e,i,n){const s=fc(t),a=Ol(n,s,-e),{x:o,y:c,width:l,height:h}=t,u=Ly[i];let d=o,f=c,p=o+l,v=c+h;return u.left&&(d=Math.min(a.x,p-Pl)),u.right&&(p=Math.max(a.x,d+Pl)),u.top&&(f=Math.min(a.y,v-Pl)),u.bottom&&(v=Math.max(a.y,f+Pl)),{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=Fn.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=fc(t.bounds),n=Math.atan2(e.y-i.y,e.x-i.x)+Math.PI/2;return{...t,angle:n}}static groupBoundsFor(t){const e=Math.min(...t.map(a=>a.x)),i=Math.min(...t.map(a=>a.y)),n=Math.max(...t.map(a=>a.x+a.width)),s=Math.max(...t.map(a=>a.y+a.height));return{x:e,y:i,width:n-e,height:s-i}}static vertexPointsFor(t){const e=fc(t.bounds);return t.points.map(i=>Ol({x:t.bounds.x+i.x,y:t.bounds.y+i.y},e,t.angle))}static hitTestVertex(t,e,i=Oy){const n=Fn.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=fc(t.bounds),n=Ol(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?Fn.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=Fn.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=Fn.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<=Py?t:{...t,points:t.points.filter((i,n)=>n!==e)}}}const _0=6,Ll=_0/2,Mm=20,ym=24,xm=9,Sm=6,wm=7,bm=6,Ss=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+xm*f),bm*f)-d:0,v=f>0?d*(1+wm*f)-d:0,m=3*ym*(t.blur??0)+1.5*Mm*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(${(ym*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+xm*e),bm*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<=Sm;d++){const f=d/Sm,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+wm*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=Mm*t.haloScale,this.paintBase(t),this.ctx.restore()}paintSelectionHandles(t){this.paintHandleFrame(Fn.handlePointsFor(t),{includeRotate:!0}),t.kind==="polygon"&&this.paintVertexHandles(t)}paintVertexHandles(t){this.ctx.fillStyle="#39f";for(const e of Fn.vertexPointsFor(t))this.ctx.beginPath(),this.ctx.ellipse(e.x,e.y,Ss,Ss,0,0,2*Math.PI),this.ctx.fill()}paintMemberOutline(t){this.paintOutline(Fn.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,Ss+2,Ss+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,Ss,Ss,0,0,2*Math.PI),n.fill()),n.strokeStyle=a,n.lineWidth=o,n.beginPath(),n.ellipse(s.picture.x,s.picture.y,Ss+2,Ss+2,0,0,2*Math.PI),n.stroke(),this.paintLabel(s.label,s.picture.x+Ss+5,s.picture.y-Ss-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(Fn.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 kv){const n=t[i];this.ctx.fillRect(n.x-Ll,n.y-Ll,_0,_0)}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,Ll+1,Ll+1,0,0,2*Math.PI),this.ctx.fill())}}const _m=.05,Em=.08,Am=2,Tm=3,Ny=14,Uy=.02;class Fy{context;voice;voiceToken=0;buffers=new Map;noiseBuffer;crackleBuffer;requested;level=1;master;output(t){return this.master||(this.master=t.createGain(),this.master.gain.value=this.level,this.master.connect(t.destination)),this.master}setLevel(t){this.level=t,this.master&&(this.master.gain.value=t)}resume(){if(!this.context){if(typeof AudioContext>"u")return;try{this.context=new AudioContext}catch(t){console.warn("SightingAudio: Web Audio unavailable, the sighting stays silent:",t);return}}_r.unlock(this.context)}setSound(t){if(this.requested=t,!this.context)return;const e=this.keyFor(t);if(!e){this.silence();return}if(this.voice?.key!==e){this.stopVoice();const i=++this.voiceToken;e.startsWith("src:")?this.buildRecordedVoice(t.src,e,i):this.voice=this.buildSynthesizedVoice(t,e)}this.applyTo(this.voice,t)}silence(){this.voiceToken++,this.stopVoice()}dispose(){this.silence(),this.context?.close(),this.context=void 0,this.master=void 0,this.buffers.clear(),this.noiseBuffer=void 0,this.crackleBuffer=void 0}keyFor(t){if(!(t.volume<=0))return t.src?`src:${t.src}`:t.kind==="none"?void 0:t.kind}applyTo(t,e){const i=this.context;if(!t||!i)return;const n=i.currentTime;t.volumeParam.setTargetAtTime(Math.max(0,Math.min(1,e.volume))*t.gainScale,n,_m);for(const{param:s,ratio:a}of t.pitch)s.setTargetAtTime(Math.min(e.pitchHz*a,i.sampleRate/2-1),n,_m)}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*Am),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*Am),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*Tm),t.sampleRate),i=e.getChannelData(0),n=Math.max(1,Math.floor(Uy*t.sampleRate)),s=Math.round(Tm*Ny);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,Em/3);const n=i+Em;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 Xt{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=Xt.outline(Xt.BOOKMARK);static MILESTONES_ON=Xt.solid(Xt.BOOKMARK);static PICTURES_OFF=Xt.outline(`${Xt.PICTURE}${Xt.PICTURE_HILLS}`);static PICTURES_ON=Xt.solid(`${Xt.PICTURE}${Xt.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=Xt.outline(`${Xt.TRACE_LINE}${Xt.TRACE_MARK}`);static TRACES_ON=Xt.solid(`${Xt.TRACE_LINE}${Xt.TRACE_MARK}`);static MAP_OFF=Xt.outline(`${Xt.PIN}${Xt.PIN_HOLE}`);static MAP_ON=Xt.solid(`${Xt.PIN}${Xt.PIN_HOLE}`);static SHARE=Xt.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=Xt.svg("M15.4 7.4 14 6l-6 6 6 6 1.4-1.4L10.8 12z");static UNFOLDED=Xt.svg("M8.6 16.6 10 18l6-6-6-6-1.4 1.4 4.6 4.6z");static PLAY=Xt.svg("M7.4 5v14l11-7z");static PAUSE=Xt.svg("M6 5h4v14H6zM14 5h4v14h-4z");static VOLUME=Xt.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=Xt.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=Xt.svg("M5 5h5v2H7v3H5V5zm9 0h5v5h-2V7h-3V5zM5 14h2v3h3v2H5v-5zm12 0h2v5h-5v-2h3v-3z");static EXIT_FULLSCREEN=Xt.svg("M8 5h2v5H5V8h3V5zm6 0h2v3h3v2h-5V5zM5 14h5v5H8v-3H5v-2zm9 0h5v2h-3v3h-2v-5z")}function Wc(r){return[...r].sort((t,e)=>t.t-e.t)}function Ku(r,t){let e;for(const i of Wc(r)){if(i.t>t)break;e=i}return e}const $u=Math.PI/180,Nl=180/Math.PI;class da{constructor(t,e,i){this.kind=t,this.canvasHeightPx=e,this.fovDeg=i;const n=i*$u/2;this.focalPx=t==="equidistant"?e/2/n:e/2/Math.tan(n)}focalPx;static of(t,e,i){return new da(t.projection,e,i)}degToPx(t){const e=t*$u;return this.kind==="equidistant"?this.focalPx*e:2*this.focalPx*Math.tan(e/2)}pxToDeg(t){return this.kind==="equidistant"?t/this.focalPx*Nl:2*Math.atan(t/(2*this.focalPx))*Nl}angleDegToRadiusPx(t){const e=t*$u;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*Nl:Math.atan(t/this.focalPx)*Nl}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(Xe.angularWidthDeg(t))}}class Tn{static fovOf(t,e){return si(t,e)?.fovDeg??Pi.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)<Tn.UNMOVED_PX&&Math.abs(s.y-e.bounds.y)<Tn.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=da.of(t.instrument,Xe.CANVAS_HEIGHT_PX,this.fovOf(t,e));return this.aimFrom(t,n,si(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:Pi.frameWidthPx(t.instrument,Xe.CANVAS_HEIGHT_PX)/2,y:Xe.CANVAS_HEIGHT_PX/2}}static shortestArc(t){return(t%360+540)%360-180}static offAxisPx(t,e){return Math.abs(e)>=Tn.OFF_CANVAS_DEG?Math.sign(e)*Tn.OFF_CANVAS_PX:t.angleDegToRadiusPx(e)}static OFF_CANVAS_DEG=89;static OFF_CANVAS_PX=1e5;static reproject(t,e,i){const n=Pi.frameWidthPx(e,Xe.CANVAS_HEIGHT_PX)/2,s=Pi.frameWidthPx(t.instrument,Xe.CANVAS_HEIGHT_PX)/2,a=Xe.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=da.of(e,Xe.CANVAS_HEIGHT_PX,l),u=da.of(t.instrument,Xe.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,y={...f,x:s+p*g-f.width/2,y:a+v*g-f.height/2};return{...d,shape:{...d.shape,bounds:y}}}))}this.toBounds(t)}static eachKeyframe(t,e){const{timeline:i}=t;for(const n of[...i.allKeyframes]){const s=si(t,n.t),a=this.fovOf(t,n.t),o=da.of(t.instrument,Xe.CANVAS_HEIGHT_PX,a);i.addKeyframe(n.t,n.shapes.map(c=>({...c,shape:e(c.shape,o,s)})))}}}function ky(r){return Zn.restore(zy(r),r.provenance)}function zy(r){return Tn.toAngular(r),Tn.toAim(r),{version:1,id:r.id,time:r.event.time,endTime:r.event.endTime,durationSeconds:r.event.durationSeconds,durationText:r.event.durationText,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,image:r.event.image,summary:r.event.summary,summaryTime:r.event.summaryTime,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 Hy(r){const{recording:t,provenance:e}=Zn.strip(r),i=By(t);return i.provenance=e,i}function By(r){const t=[],e=new Iu({eventType:"sighting",time:r.time,endTime:r.endTime,durationSeconds:r.durationSeconds,durationText:r.durationText,utcOffsetHours:r.utcOffsetHours,timeZone:r.timeZone,place:r.place,description:r.description,image:r.image,summary:r.summary,summaryTime:r.summaryTime,tags:r.tags},Du.fromJSON(r.timeline,t),r.observerTrack?ol.fromJSON(r.observerTrack):new ol,r.weatherTrack?cl.fromJSON(r.weatherTrack):new cl,r.soundTrack?ll.fromJSON(r.soundTrack):new ll,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),Wc(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,Tn.toBounds(e),Tn.toPosition(e),e}class tc{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=tc.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=>` ${tc.text(n)}`);console.warn(`UFO@home: ${t.length} problem(s) in ${e??"this recording"}:
1630
1647
  ${i.join(`
1631
1648
  `)}`)}}class os{constructor(t){this.format=t}issues(t){const e=[];return this.object(t,this.format,"",e),e}object(t,e,i,n){if(!os.isObject(t)){n.push({kind:"wrong-type",path:i||"(the file)",expected:"object",found:os.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(os.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):os.isObject(t)||n.push({kind:"wrong-type",path:i,expected:"object",found:os.typeOf(t)});return;case"array":Array.isArray(t)?e.fields&&t.forEach((s,a)=>{const o=os.isStated(s)?s.value:s;this.object(o,e.fields,`${i}.${a}`,n)}):n.push({kind:"wrong-type",path:i,expected:"array",found:os.typeOf(t)});return;default:typeof t!==e.type&&n.push({kind:"wrong-type",path:i,expected:e.type,found:os.typeOf(t)})}}static isObject(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}static isStated(t){return os.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 us{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?us.travelDegOver(t,e,i,i+n*1e3)/s/us.PIXELS_PER_INSTANT:0,o=us.flashesOver(t,n)*us.INSTANTS_PER_FLASH,c=Math.ceil(Math.max(a,o));return c<2?1:Math.min(us.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=us.directionAt(a,e,i),c=us.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=ua(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 zv(r,t){for(const e of r){const i=e.toLowerCase().split("-")[0];if(t.includes(i))return i}return"en"}class zo{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 ca{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[ca.base(i)];if(n)return n}const e=new Set(this.preferences.map(i=>ca.base(i)));for(const[i,n]of Object.entries(t))if(n&&e.has(ca.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=>ca.base(o)===ca.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 Hv=["en","fr","es","it"],Gy={en:()=>Fi(()=>Promise.resolve().then(()=>Xy),void 0,import.meta.url).then(r=>r.ufoMessages_en),fr:()=>Fi(()=>import("./UfoMessages_fr-Cs2GCHEt.js"),[],import.meta.url).then(r=>r.ufoMessages_fr),es:()=>Fi(()=>import("./UfoMessages_es-BRCWkzr3.js"),[],import.meta.url).then(r=>r.ufoMessages_es),it:()=>Fi(()=>import("./UfoMessages_it-B2hvjhgb.js"),[],import.meta.url).then(r=>r.ufoMessages_it)};function Vy(r){return Gy[r]()}function Wy(r){switch(r){case"fr":return Fi(()=>import("./SceneNames_fr-DAd-g0yB.js"),[],import.meta.url).then(t=>t.sceneNames_fr);case"es":return Fi(()=>import("./SceneNames_es-B9tudMDH.js"),[],import.meta.url).then(t=>t.sceneNames_es);case"it":return Fi(()=>import("./SceneNames_it-BLLX--oG.js"),[],import.meta.url).then(t=>t.sceneNames_it);default:return Promise.resolve(void 0)}}const Bv={play:"Play",clickToPlay:"Click to play",pause:"Pause",noDuration:"No observation duration",currentPosition:"Current position",duration:"Duration",switchToElapsed:"click to show elapsed time",switchToClockTime:"click to show the time of day",fullscreen:"Fullscreen",exitFullscreen:"Exit fullscreen",mute:"Mute",unmute:"Unmute",noSound:"No sound recorded",moments:"Moments",moreControls:"More controls",fewerControls:"Fewer controls",showObserverMap:"Show where the observer was",hideObserverMap:"Hide where the observer was",mapImageryUnavailable:"Aerial imagery unavailable",zoomMapIn:"Zoom in",zoomMapOut:"Zoom out",fitMap:"Back to the whole path",placeObserverHere:"Put the observer here",showReferences:"Show the pictures of the place",hideReferences:"Hide the pictures of the place",showTraces:"Show the investigator's lines",hideTraces:"Hide the investigator's lines",referenceOpacity:"Picture opacity",referencesMenu:"Pictures of the place",showMilestones:"Show the account's moments",hideMilestones:"Hide the account's moments",observerHere:"The observer, here",decorHere:"Scenery",recordingIssues:"{count} problem(s) in this recording: it may not play as its author meant",issueTemplates:tc.EN},Xy=Object.freeze(Object.defineProperty({__proto__:null,ufoMessages_en:Bv},Symbol.toStringTag,{value:"Module"})),Gv=Math.PI/180,Yy=180/Math.PI,qy=256,Vv=19,Ky=1.25;function Wv(r,t){return 156543.03392*Math.cos(r*Gv)/2**t}function Xv(r,t){return Wv(r,t)*qy}function $y(r,t){let e=0;for(;e<Vv&&Xv(r,e+1)>=t;)e++;return e}function Yv(r,t){return Xv(r,t)}function Zy(r,t){const e=t*Ky;let i=0;for(;i<Vv&&Wv(r,i)>e;)i++;return i}function kh(r){const t=r*Gv;return(1-Math.log(Math.tan(t)+1/Math.cos(t))/Math.PI)/2}function qv(r,t,e){const i=2**e;return{x:(r+180)/360*i,y:kh(t)*i}}function Kv(r,t,e){const i=kh(r.north),n=kh(r.south);return{x:(t-r.west)/(r.east-r.west),y:(kh(e)-i)/(n-i)}}function Jy(r,t,e){const{x:i,y:n}=qv(r,t,e);return{x:Math.floor(i),y:Math.floor(n),z:e}}function jy(r){const t=2**r.z,e=r.x/t*360-180,i=(r.x+1)/t*360-180,n=Rm(r.y,t);return{south:Rm(r.y+1,t),north:n,west:e,east:i}}function Rm(r,t){const e=r/t;return Math.atan(Math.sinh(Math.PI*(1-2*e)))*Yy}function $v(r,t,e,i){const n=Jy(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(jy),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 Qy="#2ec4ff";class dr{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=Kv(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??Qy;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:dr.MARKER_RADIUS_PX}),e.beginPath(),e.arc(n.x,n.y,dr.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=le(a.lat,a.lng,e.lat,e.lng);return Math.hypot(o.x,o.z)<=dr.ON_MARKER_M});i.beginPath(),i.arc(n.x,n.y,s?dr.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(le(a,t.east,a,t.west).x)/this.width,l=dr.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 ci{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(ci.MAX_ZOOM,Math.max(ci.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=ci.mercatorY01(e.north),s=ci.mercatorY01(e.south),a=ci.mercatorY01(i.north),o=ci.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=ci.mercatorY01(n.north),a=ci.mercatorY01(n.south),o=(e.lng-n.west)/(n.east-n.west),c=(ci.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=ci.mercatorY01(t.north),n=ci.mercatorY01(t.south),s=t.east-t.west;return{west:t.west+(this.centerX-e)*s,east:t.west+(this.centerX+e)*s,north:ci.latitudeAt(i+(this.centerY-e)*(n-i)),south:ci.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=le(n,t.east,n,s).x;let o=a;for(const c of e){const{x:l,z:h}=le(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:Bn(0,-o,n,s).lat,south:Bn(0,o,n,s).lat,east:Bn(o,0,n,s).lng,west:Bn(-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=ci.mercatorY01(t.north),s=ci.mercatorY01(t.south);return{lat:ci.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 Xn=256,Dm=3,tx=32768;class ex{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(le(i,t.east,i,t.west).x),a=Math.abs(le(t.north,n,t.south,n).z),o=$y(i,Math.max(s,a)),{tiles:c}=$v(n,i,o,Dm),l=Dm*Xn,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=Xn,c.height=Xn;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,Xn,Xn),u=(t.x-e.x)*Xn,d=(t.y-e.y)*Xn;for(let f=0;f<Xn;f++)for(let p=0;p<Xn;p++){const v=(f*Xn+p)*4,m=h[v]*256+h[v+1]+h[v+2]/256-tx,g=u+p,y=d+f;i[y*n+g]=m}}sampleAt(t,e,i,n,s,a){const{x:o,y:c}=qv(e,t,i),l=(o-n.x)*Xn,h=(c-n.y)*Xn,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],y=s[d*a+f],x=s[p*a+u],M=s[p*a+f],w=g+(y-g)*v,b=x+(M-x)*v;return w+(b-w)*m}}class Cu{constructor(t,e,i,n){this.width=t,this.height=e,this.samples=i,this.values=n}at(t,e,i=0){return this.values[(e*this.width+t)*this.samples+i]}static parse(t){const e=new DataView(t);if(t.byteLength<8||e.getUint16(0)!==18761||e.getUint16(2,!0)!==42)throw new Error("Not a little-endian TIFF");const i=e.getUint32(4,!0),n=e.getUint16(i,!0),s=new Map;for(let g=0;g<n;g++){const y=i+2+g*12;s.set(e.getUint16(y,!0),{type:e.getUint16(y+2,!0),count:e.getUint32(y+4,!0),value:e.getUint32(y+8,!0)})}const a=(g,y)=>{const x=s.get(g);if(x===void 0){if(y===void 0)throw new Error(`TIFF without tag ${g}`);return y}return x.type===3?x.value&65535:x.value},o=g=>{const y=s.get(g);if(y===void 0)throw new Error(`TIFF without tag ${g}`);const x=y.type===3?2:4,M=[];if(y.count*x<=4){const w=new DataView(new ArrayBuffer(4));w.setUint32(0,y.value,!0);for(let b=0;b<y.count;b++)M.push(x===2?w.getUint16(b*2,!0):w.getUint32(0,!0))}else for(let w=0;w<y.count;w++)M.push(x===2?e.getUint16(y.value+w*2,!0):e.getUint32(y.value+w*4,!0));return M};if(a(259,1)!==1)throw new Error("Compressed TIFF");if(s.has(322))throw new Error("Tiled TIFF");const c=a(256),l=a(257),h=a(277,1),u=o(258)[0],d=a(339,1)===3;if(!(d&&u===32||!d&&u===8))throw new Error(`Unsupported TIFF samples: ${u} bits`);const f=o(273),p=o(279),v=new Uint8Array(c*l*h*(u/8));let m=0;for(let g=0;g<f.length&&m<v.length;g++){const y=Math.min(p[g],v.length-m);v.set(new Uint8Array(t,f[g],y),m),m+=y}if(m<v.length)throw new Error("Truncated TIFF");return new Cu(c,l,h,d?new Float32Array(v.buffer):v)}}class Ea extends Error{constructor(t,e){super(e),this.reason=t,this.name="SurroundingsUnavailableError"}}class ix{constructor(t,e,i,n,s){this.heights=t,this.plants=e,this.buildings=i,this.size=n,this.metresPerPixel=s}structureAt(t,e){const i=Math.floor(t/this.metresPerPixel+this.size/2),n=Math.floor(this.size/2-e/this.metresPerPixel);if(i<0||n<0||i>=this.size||n>=this.size)return;const s=n*this.size+i;if(!(this.plants[s]||this.buildings[s]))return this.heights[s]}tallestStructureNear(t,e,i){let n;const s=Math.ceil(i/this.metresPerPixel);for(let a=-s;a<=s;a++)for(let o=-s;o<=s;o++){if(Math.hypot(o,a)*this.metresPerPixel>i)continue;const c=this.structureAt(t+o*this.metresPerPixel,e+a*this.metresPerPixel);c!==void 0&&(n===void 0||c>n)&&(n=c)}return n}}class be{static covers(t,e){return t>=41.2&&t<=51.3&&e>=-5.4&&e<=9.8}static WMS="https://data.geopf.fr/wms-r/wms";static WFS="https://data.geopf.fr/wfs/ows";static HEIGHT_LAYER="IGNF_LIDAR-HD_MNH_ELEVATION.ELEVATIONGRIDCOVERAGE.LAMB93";static CLASS_LAYER="IGNF_LIDAR-HD_CLASS";static PHOTO_LAYER="ORTHOIMAGERY.ORTHOPHOTOS";static MAX_PHOTO_PIXELS=1e3;static METRES_PER_PIXEL=.5;static MAX_RADIUS_M=3e3;static MAX_LIDAR_RADIUS_M=150;static NO_DATA=-9999;static METRES_PER_DEGREE=111320;fetchImpl;wms;wfs;constructor(t={}){this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.wms=t.wmsEndpoint??be.WMS,this.wfs=t.wfsEndpoint??be.WFS}static radius(t){return Math.min(t,be.MAX_RADIUS_M)}static lidarRadius(t){return Math.min(t,be.MAX_LIDAR_RADIUS_M)}async lidar(t,e){const i=be.lidarRadius(e),n=Math.ceil(2*i/be.METRES_PER_PIXEL),[s,a]=await Promise.all([this.raster(t,i,n,be.HEIGHT_LAYER),this.raster(t,i,n,be.CLASS_LAYER)]);if(s.samples!==1||a.samples<3)throw new Ea("unreachable","The survey answered in a layout this does not read");const o=s.values;if(o.every(u=>u===be.NO_DATA))throw new Ea("no-coverage","No LiDAR HD survey here yet");const c=new Uint8Array(n*n),l=new Uint8Array(n*n);for(let u=0;u<n*n;u++){const d=a.values[u*a.samples],f=a.values[u*a.samples+1],p=a.values[u*a.samples+2];c[u]=f>d&&f>p?1:0,l[u]=d>120&&f<90&&p<90?1:0}const h=2*i/n;return{size:n,metresPerPixel:h,heights:o,vegetation:c,building:l,structures:new ix(o,c,l,n,h)}}async laserDate(t){return be.latest(await this.dated("IGNF_LIDAR-HD_METADONNEE:metadata","geom","date_fin_acquisition",t))}async photoDate(t){return be.latest(await this.dated("ORTHOIMAGERY.ORTHOPHOTOS.GRAPHE-MOSAIQUAGE:graphe_bdortho","geom","date_vol",t))}static latest(t){return t.map(i=>/^\d{4}-\d{2}-\d{2}/.exec(String(i??""))?.[0]).filter(i=>i!==void 0).sort().at(-1)}async dated(t,e,i,n){const a=[n.lng-1e-4,n.lat-1e-4,n.lng+1e-4,n.lat+1e-4].map(o=>o.toFixed(6)).join(",");try{return(await this.features(t,`BBOX(${e},${a},'EPSG:4326')`,i,20)).map(o=>o.properties[i])}catch{return[]}}async photo(t,e){const i=be.radius(e),n=Math.min(be.MAX_PHOTO_PIXELS,Math.ceil(2*i/be.METRES_PER_PIXEL)),s=await this.raster(t,i,n,be.PHOTO_LAYER);if(s.samples<3)throw new Ea("unreachable","The photograph came in a layout this does not read");return{size:n,metresPerPixel:2*i/n,samples:s.samples,values:s.values}}async vectors(t,e,i){const n=be.radius(e),s=n/be.METRES_PER_DEGREE,a=n/(be.METRES_PER_DEGREE*Math.cos(t.lat*Math.PI/180)),c=`BBOX(geometrie,${[t.lng-a,t.lat-s,t.lng+a,t.lat+s].map(g=>g.toFixed(6)).join(",")},'EPSG:4326')`,[l,h,u,d,f,p]=await Promise.all([this.features("construction_lineaire",`${c} AND nature='Pont'`,"nature,geometrie"),this.features("troncon_de_route",`${c} AND position_par_rapport_au_sol>'0'`,"nature,largeur_de_chaussee,position_par_rapport_au_sol,nom_voie_ban_gauche,nom_voie_ban_droite,cpx_toponyme_route_nommee,geometrie"),this.features("troncon_de_voie_ferree",`${c} AND position_par_rapport_au_sol>'0'`,"position_par_rapport_au_sol,geometrie").catch(()=>[]),this.features("ligne_electrique",c,"voltage,geometrie"),i?this.features("batiment",c,be.BUILDING_PROPERTIES,5e3):Promise.resolve([]),i?this.features("zone_d_activite_ou_d_interet",c,"toponyme,categorie,geometrie",100).catch(()=>[]):Promise.resolve([])]),v=i?await this.wholeWorship(p,f,[t.lng-a,t.lat-s,t.lng+a,t.lat+s]):[],m=[...f,...v];return{bridges:l,elevatedRoads:h,elevatedRailways:u,lines:d,buildings:m,zones:p,mapDate:be.latest(m.map(g=>g.properties.date_modification))}}static BUILDING_PROPERTIES="cleabs,nature,usage_1,hauteur,nombre_d_etages,materiaux_des_murs,materiaux_de_la_toiture,date_d_apparition,date_modification,geometrie";static MAX_WHOLE_M=300;async wholeWorship(t,e,i){const[n,s,a,o]=i,c=be.MAX_WHOLE_M/be.METRES_PER_DEGREE;let l;for(const u of t){if(u.properties.categorie!=="Religieux")continue;const[d,f,p,v]=be.extent(u);if(d>=n&&f>=s&&p<=a&&v<=o)continue;const m=[Math.max(d,n-c),Math.max(f,s-c),Math.min(p,a+c),Math.min(v,o+c)];l=l?[Math.min(l[0],m[0]),Math.min(l[1],m[1]),Math.max(l[2],m[2]),Math.max(l[3],m[3])]:m}if(!l)return[];const h=new Set(e.map(u=>u.properties.cleabs));try{return(await this.features("batiment",`BBOX(geometrie,${l.map(d=>d.toFixed(6)).join(",")},'EPSG:4326')`,be.BUILDING_PROPERTIES,1e3)).filter(d=>!h.has(d.properties.cleabs))}catch{return[]}}static extent(t){let e=1/0,i=1/0,n=-1/0,s=-1/0;const a=o=>{Array.isArray(o)&&typeof o[0]=="number"?(e=Math.min(e,o[0]),n=Math.max(n,o[0]),i=Math.min(i,o[1]),s=Math.max(s,o[1])):Array.isArray(o)&&o.forEach(a)};return a(t.geometry.coordinates),[e,i,n,s]}async elevatedRoadLines(t){const e=`BBOX(geometrie,${[t.west,t.south,t.east,t.north].map(s=>s.toFixed(6)).join(",")},'EPSG:4326')`,i=await this.features("troncon_de_route",`${e} AND position_par_rapport_au_sol>'0'`,"geometrie",300),n=[];for(const s of i){const{type:a,coordinates:o}=s.geometry,c=a==="LineString"?[o]:a==="MultiLineString"?o:[];for(const l of c)n.push(l.map(h=>({lat:h[1],lng:h[0]})))}return n}async waterSurfaces(t){const e=`BBOX(geometrie,${[t.west,t.south,t.east,t.north].map(i=>i.toFixed(6)).join(",")},'EPSG:4326')`;return this.features("surface_hydrographique",`${e} AND position_par_rapport_au_sol='0' AND persistance='Permanent'`,"cleabs,nature,geometrie",500)}async roads(t){const e=`BBOX(geometrie,${[t.west,t.south,t.east,t.north].map(i=>i.toFixed(6)).join(",")},'EPSG:4326')`;return this.features("troncon_de_route",`${e} AND nature<>'Sentier' AND nature<>'Escalier' AND position_par_rapport_au_sol>='0'`,"cleabs,nature,largeur_de_chaussee,nombre_de_voies,sens_de_circulation,vitesse_moyenne_vl,urbain,nom_voie_ban_gauche,nom_voie_ban_droite,cpx_toponyme_route_nommee,geometrie",3e3)}async railways(t){const e=`BBOX(geometrie,${[t.west,t.south,t.east,t.north].map(i=>i.toFixed(6)).join(",")},'EPSG:4326')`;return this.features("troncon_de_voie_ferree",`${e} AND etat_de_l_objet='En service'`,"cleabs,nature,electrifie,largeur,nombre_de_voies,position_par_rapport_au_sol,cpx_toponyme,geometrie",3e3)}async raster(t,e,i,n){const s=e/be.METRES_PER_DEGREE,a=e/(be.METRES_PER_DEGREE*Math.cos(t.lat*Math.PI/180)),o=new URLSearchParams({SERVICE:"WMS",VERSION:"1.3.0",REQUEST:"GetMap",LAYERS:n,STYLES:"",CRS:"EPSG:4326",BBOX:[t.lat-s,t.lng-a,t.lat+s,t.lng+a].map(l=>l.toFixed(6)).join(","),WIDTH:String(i),HEIGHT:String(i),FORMAT:"image/geotiff"});let c;try{c=await this.fetchImpl(`${this.wms}?${o}`)}catch(l){throw new Ea("unreachable",l instanceof Error?l.message:String(l))}if(!c.ok)throw new Ea("unreachable",`The survey answered ${c.status}`);try{return Cu.parse(await c.arrayBuffer())}catch(l){throw new Ea("unreachable",l instanceof Error?l.message:String(l))}}async features(t,e,i,n=200){const s=new URLSearchParams({SERVICE:"WFS",VERSION:"2.0.0",REQUEST:"GetFeature",TYPENAMES:t.includes(":")?t:`BDTOPO_V3:${t}`,SRSNAME:"EPSG:4326",OUTPUTFORMAT:"application/json",COUNT:String(n),CQL_FILTER:e,PROPERTYNAME:i});let a;try{a=await this.fetchImpl(`${this.wfs}?${s}`)}catch(c){throw new Ea("unreachable",c instanceof Error?c.message:String(c))}if(!a.ok)throw new Ea("unreachable",`The map answered ${a.status}`);return(await a.json()).features??[]}}class Fa{static NEAR_M=15;static ALIGNED_DEG=30;static LONG_ENOUGH_M=15;static SAMPLE_M=5;static follows(t,e){if(t.length<2||e.length<2)return!1;const i=e[0],n=e.map(o=>le(o.lat,o.lng,i.lat,i.lng)),s=t.map(o=>le(o.lat,o.lng,i.lat,i.lng));let a=0;for(let o=0;o<s.length-1;o++){const c=s[o],l=s[o+1],h=Math.hypot(l.x-c.x,l.z-c.z);if(h<1e-6)continue;const u=Math.max(1,Math.ceil(h/Fa.SAMPLE_M)),d=Math.atan2(l.x-c.x,-(l.z-c.z));for(let f=0;f<=u;f++){const p=f/u,v=Fa.nearest(n,c.x+(l.x-c.x)*p,c.z+(l.z-c.z)*p);v.distanceM>Fa.NEAR_M||Fa.angleBetween(d,v.heading)<=Fa.ALIGNED_DEG&&(a+=h/u)}}return a>=Fa.LONG_ENOUGH_M}static nearest(t,e,i){let n={distanceM:1/0,heading:0};for(let s=0;s<t.length-1;s++){const a=t[s],o=t[s+1],c=o.x-a.x,l=o.z-a.z,h=c*c+l*l,u=h<1e-9?0:Math.max(0,Math.min(1,((e-a.x)*c+(i-a.z)*l)/h)),d=Math.hypot(e-(a.x+c*u),i-(a.z+l*u));d<n.distanceM&&(n={distanceM:d,heading:Math.atan2(c,-l)})}return n}static angleBetween(t,e){const i=Math.abs((t-e)*180/Math.PI%180);return Math.min(i,180-i)}}class Me{static WMS="https://data.geopf.fr/wms-r/wms";static LAYERS=["IGNF_LIDAR-HD_MNT_ELEVATION.ELEVATIONGRIDCOVERAGE.LAMB93","ELEVATION.ELEVATIONGRIDCOVERAGE.HIGHRES"];static METRES_PER_PIXEL=4;static METRES_PER_DEGREE=111320;static CLASS_LAYER="IGNF_LIDAR-HD_CLASS";static SURFACE_LAYER="IGNF_LIDAR-HD_MNS_ELEVATION.ELEVATIONGRIDCOVERAGE.LAMB93";static DECK=[240,240,0];static NO_CLASS=[0,0,0];static DECK_END_PIXELS=3;static DECK_HALF_WIDTH_M=8;static DECK_APPROACH_M=10;static DECK_STRAIGHT_MAX_M=200;static MIN_PIXELS=8;static MAX_PIXELS=700;static NO_DATA_BELOW=-9e3;static MESH_FROM_VERTICES=33;static FINE_SPACING_M=7;static MAX_SEGMENTS=256;static MAX_HOLE_SHARE=.05;static DEFAULT_TIMEOUT_MS=12e3;static MAX_WINDOW_M=50;fetchImpl;wms;timeoutMs;maxWindowM;geoplatform;constructor(t={}){this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.wms=t.wmsEndpoint??Me.WMS,this.timeoutMs=t.timeoutMs??Me.DEFAULT_TIMEOUT_MS,this.maxWindowM=t.maxWindowM??Me.MAX_WINDOW_M,this.geoplatform=new be({fetchImpl:this.fetchImpl,wmsEndpoint:this.wms,wfsEndpoint:t.wfsEndpoint})}async getElevationGrid(t,e,i){const n={lat:(t.south+t.north)/2,lng:(t.west+t.east)/2};if(!be.covers(n.lat,n.lng))throw new Error("The IGN's relief covers France only");const s=Math.abs(le(n.lat,t.east,n.lat,t.west).x),a=Math.abs(le(t.north,n.lng,t.south,n.lng).z);e=this.finer(e,s,a);const o={x:s/Math.max(1,e.width-1),y:a/Math.max(1,e.height-1)},c={x:Math.min(o.x,this.maxWindowM),y:Math.min(o.y,this.maxWindowM)},l={south:t.south-c.y/Me.METRES_PER_DEGREE,north:t.north+c.y/Me.METRES_PER_DEGREE,west:t.west-c.x/(Me.METRES_PER_DEGREE*Math.cos(n.lat*Math.PI/180)),east:t.east+c.x/(Me.METRES_PER_DEGREE*Math.cos(n.lat*Math.PI/180))},h=p=>Math.min(Me.MAX_PIXELS,Math.max(Me.MIN_PIXELS,Math.ceil(p/Me.METRES_PER_PIXEL))),u={width:h(s+2*c.x),height:h(a+2*c.y)},d={x:(s+2*c.x)/u.width,y:(a+2*c.y)/u.height};let f=new Error("No layer of the IGN's relief answered");for(const p of Me.LAYERS)try{const v=await this.heights(l,u,p);p===Me.LAYERS[0]&&await this.layBridgeDecks(v,l,u,i?.route);const m=this.sample(v,e,t,l,d,o);if(m)return{heights:m,width:e.width,height:e.height,bounds:t};f=new Error(`${p} does not cover this place`)}catch(v){f=v}throw f}finer(t,e,i){if(t.width<Me.MESH_FROM_VERTICES||t.height<Me.MESH_FROM_VERTICES)return t;const n=(s,a)=>{const o=Math.ceil(s/Me.FINE_SPACING_M),c=Math.max(a-1,Math.min(Me.MAX_SEGMENTS,o));return c%2===0?c:c+1};return{width:n(e,t.width)+1,height:n(i,t.height)+1}}async raster(t,e,i){const n=new URLSearchParams({SERVICE:"WMS",VERSION:"1.3.0",REQUEST:"GetMap",LAYERS:i,STYLES:"",CRS:"EPSG:4326",BBOX:[t.south,t.west,t.north,t.east].map(a=>a.toFixed(6)).join(","),WIDTH:String(e.width),HEIGHT:String(e.height),FORMAT:"image/geotiff"}),s=await this.fetchImpl(`${this.wms}?${n}`,{signal:AbortSignal.timeout(this.timeoutMs)});if(!s.ok)throw new Error(`The IGN's relief answered ${s.status}`);return Cu.parse(await s.arrayBuffer())}async heights(t,e,i){const n=await this.raster(t,e,i);if(n.samples!==1||!(n.values instanceof Float32Array))throw new Error("The IGN's relief came in a layout this does not read");return n}async layBridgeDecks(t,e,i,n){if(!(!n||n.length<2)&&!(!(t.values instanceof Float32Array)||!t.values.some(s=>s>Me.NO_DATA_BELOW)))try{const s=(await this.geoplatform.elevatedRoadLines({west:e.west,south:e.south,east:e.east,north:e.north})).filter(o=>Fa.follows(n,o));if(s.length===0)return;const a=Float32Array.from(t.values);await this.layClassifiedDecks(t,e,i,s),this.layRouteDecks(t,a,e,s)}catch{}}async layClassifiedDecks(t,e,i,n){try{const s=await this.raster(e,i,Me.CLASS_LAYER);if(s.samples<3||s.width!==t.width||s.height!==t.height)return;const a=(m,[g,y,x])=>s.values[m*s.samples]===g&&s.values[m*s.samples+1]===y&&s.values[m*s.samples+2]===x,o=t.width,c=t.height,l=new Uint8Array(o*c);let h=!1;for(let m=0;m<l.length;m++)a(m,Me.DECK)&&(l[m]=1,h=!0);if(!h)return;const u=Me.DECK_END_PIXELS,d=[];for(let m=0;m<l.length;m++){if(l[m]!==1)continue;const g=m%o,y=(m-g)/o;for(let x=-u;x<=u;x++)for(let M=-u;M<=u;M++){const w=g+M,b=y+x;if(w<0||b<0||w>=o||b>=c)continue;const E=b*o+w;l[E]===0&&a(E,Me.NO_CLASS)&&d.push(E)}}for(const m of d)l[m]=1;const f=this.paint(n,e,o,c),p=this.touching(l,f,o,c);if(p.every(m=>m===0))return;const v=await this.heights(e,i,Me.SURFACE_LAYER);if(v.width!==o||v.height!==c)return;for(let m=0;m<p.length;m++){if(p[m]===0)continue;const g=v.values[m];Number.isFinite(g)&&g>Me.NO_DATA_BELOW&&g>t.values[m]&&(t.values[m]=g)}}catch{}}layRouteDecks(t,e,i,n){const{width:s,height:a}=t,o=(i.north+i.south)/2,c=(i.east-i.west)*Me.METRES_PER_DEGREE*Math.cos(o*Math.PI/180),l=(i.north-i.south)*Me.METRES_PER_DEGREE,h=c/s,u=l/a,d=g=>({x:(g.lng-i.west)/(i.east-i.west)*c,y:(i.north-g.lat)/(i.north-i.south)*l}),f=(g,y)=>{const x=Math.floor(g/h),M=Math.floor(y/u);if(x<0||M<0||x>=s||M>=a)return;const w=e[M*s+x];return Number.isFinite(w)&&w>Me.NO_DATA_BELOW?w:void 0},p=Me.DECK_HALF_WIDTH_M,v=Me.DECK_APPROACH_M,m=(g,y)=>{const x=Math.hypot(g.x-y.x,g.y-y.y)||1,M={x:(g.x-y.x)/x,y:(g.y-y.y)/x},w=[0,v/2,v].map(b=>f(g.x+M.x*b,g.y+M.y*b)).filter(b=>b!==void 0);return w.length>0?Math.max(...w):void 0};for(const g of Me.chains(n.map(y=>y.map(d)))){const y=[0];for(let D=1;D<g.length;D++)y.push(y[D-1]+Math.hypot(g[D].x-g[D-1].x,g[D].y-g[D-1].y));const x=y[y.length-1];if(x<1||x>Me.DECK_STRAIGHT_MAX_M)continue;const M=m(g[0],g[1]),w=m(g[g.length-1],g[g.length-2]);if(M===void 0||w===void 0)continue;const b=p+v,E=Math.max(0,Math.floor((Math.min(...g.map(D=>D.x))-b)/h)),S=Math.min(s-1,Math.ceil((Math.max(...g.map(D=>D.x))+b)/h)),A=Math.max(0,Math.floor((Math.min(...g.map(D=>D.y))-b)/u)),I=Math.min(a-1,Math.ceil((Math.max(...g.map(D=>D.y))+b)/u));for(let D=A;D<=I;D++)for(let P=E;P<=S;P++){const N=Me.nearestAlong(g,y,{x:(P+.5)*h,y:(D+.5)*u});if(N.distance>p||N.s<-v||N.s>x+v)continue;const k=M+(w-M)*Math.min(1,Math.max(0,N.s/x)),O=D*s+P;e[O]>=k||(t.values[O]=k)}}}static chains(t){const e=t.filter(s=>s.length>=2).map(s=>[...s]),i=[],n=(s,a)=>Math.hypot(s.x-a.x,s.y-a.y)<=1;for(;e.length>0;){let s=e.shift(),a=!0;for(;a;){a=!1;for(let o=0;o<e.length;o++){const c=e[o],l=s[0],h=s[s.length-1];if(n(h,c[0]))s=[...s,...c.slice(1)];else if(n(h,c[c.length-1]))s=[...s,...[...c].reverse().slice(1)];else if(n(l,c[c.length-1]))s=[...c.slice(0,-1),...s];else if(n(l,c[0]))s=[...[...c].reverse().slice(0,-1),...s];else continue;e.splice(o,1),a=!0;break}}i.push(s)}return i}static nearestAlong(t,e,i){let n={s:0,distance:1/0};for(let s=0;s<t.length-1;s++){const a=t[s],o=t[s+1],c=o.x-a.x,l=o.y-a.y,h=c*c+l*l;if(h<1e-9)continue;let u=((i.x-a.x)*c+(i.y-a.y)*l)/h;s>0&&(u=Math.max(0,u)),s<t.length-2&&(u=Math.min(1,u));const d=Math.hypot(i.x-(a.x+c*u),i.y-(a.y+l*u));d<n.distance&&(n={s:e[s]+u*Math.sqrt(h),distance:d})}return n}paint(t,e,i,n){const s=new Uint8Array(i*n),a=c=>(c-e.west)/(e.east-e.west)*i,o=c=>(e.north-c)/(e.north-e.south)*n;for(const c of t)for(let l=0;l<c.length-1;l++){const h=a(c[l].lng),u=o(c[l].lat),d=a(c[l+1].lng),f=o(c[l+1].lat),p=Math.max(1,Math.ceil(Math.hypot(d-h,f-u)*2));for(let v=0;v<=p;v++){const m=Math.floor(h+(d-h)*v/p),g=Math.floor(u+(f-u)*v/p);for(let y=-1;y<=1;y++)for(let x=-1;x<=1;x++){const M=m+x,w=g+y;M>=0&&w>=0&&M<i&&w<n&&(s[w*i+M]=1)}}}return s}touching(t,e,i,n){const s=new Uint8Array(t.length),a=new Uint8Array(t.length);for(let o=0;o<t.length;o++){if(t[o]===0||a[o]===1)continue;const c=[],l=[o];a[o]=1;let h=!1;for(;l.length>0;){const u=l.pop();c.push(u),e[u]===1&&(h=!0);const d=u%i,f=(u-d)/i;for(let p=-1;p<=1;p++)for(let v=-1;v<=1;v++){const m=d+v,g=f+p;if(m<0||g<0||m>=i||g>=n)continue;const y=g*i+m;t[y]===1&&a[y]===0&&(a[y]=1,l.push(y))}}if(h)for(const u of c)s[u]=1}return s}sample(t,e,i,n,s,a){const{width:o,height:c}=e,l=new Float32Array(o*c),h=new Uint8Array(o*c),u=Math.min(a.x,this.maxWindowM)/s.x,d=Math.min(a.y,this.maxWindowM)/s.y;let f=0;for(let p=0;p<c;p++){const v=i.north+(i.south-i.north)*(c===1?.5:p/(c-1)),m=(n.north-v)/(n.north-n.south)*t.height-.5;for(let g=0;g<o;g++){const x=(i.west+(i.east-i.west)*(o===1?.5:g/(o-1))-n.west)/(n.east-n.west)*t.width-.5,M=u>1||d>1?this.tent(t,x,m,Math.max(1,u),Math.max(1,d)):this.bilinear(t,x,m),w=p*o+g;M===void 0?f++:(l[w]=M,h[w]=1)}}if(!(f===o*c||f/(o*c)>Me.MAX_HOLE_SHARE))return this.fill(l,h,o,c),l}tent(t,e,i,n,s){let a=0,o=0,c=0;const l=Math.max(0,Math.ceil(i-s)),h=Math.min(t.height-1,Math.floor(i+s)),u=Math.max(0,Math.ceil(e-n)),d=Math.min(t.width-1,Math.floor(e+n));for(let f=l;f<=h;f++){const p=1-Math.abs(f-i)/s;if(!(p<=0))for(let v=u;v<=d;v++){const m=p*(1-Math.abs(v-e)/n);if(m<=0)continue;c+=m;const g=t.at(v,f);!Number.isFinite(g)||g<Me.NO_DATA_BELOW||(a+=m*g,o+=m)}}return c>0&&o>=c*.5?a/o:void 0}bilinear(t,e,i){const n=Math.max(0,Math.min(t.width-1,Math.floor(e))),s=Math.max(0,Math.min(t.height-1,Math.floor(i))),a=Math.min(t.width-1,n+1),o=Math.min(t.height-1,s+1),c=Math.max(0,Math.min(1,e-n)),l=Math.max(0,Math.min(1,i-s)),h=t.at(n,s),u=t.at(a,s),d=t.at(n,o),f=t.at(a,o);for(const m of[h,u,d,f])if(!Number.isFinite(m)||m<Me.NO_DATA_BELOW)return;const p=h+(u-h)*c,v=d+(f-d)*c;return p+(v-p)*l}fill(t,e,i,n){let s=e.reduce((a,o)=>a+(o?0:1),0);for(;s>0;){const a=[];for(let o=0;o<n;o++)for(let c=0;c<i;c++){const l=o*i+c;if(e[l])continue;let h=0,u=0;for(let d=-1;d<=1;d++)for(let f=-1;f<=1;f++){const p=o+d,v=c+f;p<0||v<0||p>=n||v>=i||!e[p*i+v]||(h+=t[p*i+v],u++)}u>0&&a.push([l,h/u])}if(a.length===0)return;for(const[o,c]of a)t[o]=c,e[o]=1;s-=a.length}}}class nx{providers;constructor(...t){this.providers=t}async getElevationGrid(t,e,i){let n=new Error("No source of relief to ask");for(const s of this.providers)try{return await s.getElevationGrid(t,e,i)}catch(a){n=a}throw n}}const zh=256,sx=5;async function ax(r,t,e,i){const n=(r.south+r.north)/2,s=(r.west+r.east)/2,a=Math.abs(le(n,r.east,n,r.west).x),o=Math.abs(le(r.north,s,r.south,s).z),c=Math.max(a,o),{zoom:l,gridSize:h}=rx(n,c,Math.max(t.width,t.height)),{tiles:u,bounds:d}=$v(s,n,l,h),f=h*zh,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 w=e(M),b=await i(w);if(!b.ok)throw new Error(`Imagery tile fetch failed (${b.status}): ${w}`);const E=await createImageBitmap(await b.blob());v.drawImage(E,(M.x-m.x)*zh,(M.y-m.y)*zh)}));const g=Math.min(Math.max(t.width,t.height),f);if(g===f)return{source:p,width:f,height:f,bounds:d};const y=document.createElement("canvas");y.width=g,y.height=g;const x=y.getContext("2d");if(!x)throw new Error("2D canvas context unavailable");return x.drawImage(p,0,0,f,f,0,0,g,g),{source:y,width:g,height:g,bounds:d}}function rx(r,t,e){let i=Zy(r,t/Math.max(1,e)),n=Im(r,i,t);for(;n>sx&&i>0;)i--,n=Im(r,i,t);return{zoom:i,gridSize:n,mPerPixel:Yv(r,i)/zh}}function Im(r,t,e){const i=Math.ceil(e/2/Yv(r,t));return Math.max(3,2*i+1)}class ox{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 ax(t,e,i=>this.tileUrlTemplate.replace("{z}",String(i.z)).replace("{y}",String(i.y)).replace("{x}",String(i.x)),this.fetchImpl)}}class Un{static ENDPOINTS=["https://overpass-api.de/api/interpreter","https://overpass.kumi.systems/api/interpreter","https://overpass.private.coffee/api/interpreter"];static FRANCE_ENDPOINT="https://overpass.openstreetmap.fr/api/interpreter";static FRANCE={south:41.3,west:-5.2,north:51.1,east:9.6};static endpointsFor(t,e=Un.ENDPOINTS){const i=/\((-?\d+(?:\.\d+)?),(-?\d+(?:\.\d+)?),(-?\d+(?:\.\d+)?),(-?\d+(?:\.\d+)?)\)/.exec(t);if(!i)return[...e];const[n,s,a,o]=i.slice(1).map(Number),c=(n+a)/2,l=(s+o)/2,h=Un.FRANCE;return c>=h.south&&c<=h.north&&l>=h.west&&l<=h.east?[Un.FRANCE_ENDPOINT,...e.filter(d=>d!==Un.FRANCE_ENDPOINT)]:[...e]}fetchImpl;endpoints;constructor(t={}){this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.endpoints=t.endpoints}static queue=Promise.resolve();static HANG_MS=4e4;static RETRY_MS=4e3;query(t){return this.queued(()=>this.ask(t))}queued(t){const e=Un.queue.then(t,t);return Un.queue=e.catch(()=>{}),e}async ask(t){let e;for(const i of this.endpoints??Un.endpointsFor(t))for(let n=0;n<2;n++){try{const s=await this.fetchImpl(`${i}?data=${encodeURIComponent(t)}`,{signal:AbortSignal.timeout(Un.HANG_MS)});if(s.ok)return await s.json();if(e=new Error(`${new URL(i).host} refused (${s.status})`),s.status!==429&&s.status!==504)break}catch(s){e=new Error(`${new URL(i).host} unreachable (${String(s)})`);break}await new Promise(s=>setTimeout(s,Un.RETRY_MS))}throw e??new Error("No Overpass instance answered")}}class ka{attribution="Roads © OpenStreetMap contributors, as surveyed today";contemporary=!0;static DRIVABLE=["motorway","trunk","primary","secondary","tertiary","unclassified","residential","service","track","motorway_link","trunk_link","primary_link","secondary_link","tertiary_link"];static WIDTH_M={motorway:11,trunk:9,primary:8,secondary:7,tertiary:6.5,unclassified:5.5,residential:5.5,service:4,track:3.5};static DEFAULT_WIDTH_M=5;client;constructor(t={}){this.client=new Un(t)}async getRoads(t){const e=`${t.south},${t.west},${t.north},${t.east}`,i=`[out:json][timeout:30];way["highway"~"^(${ka.DRIVABLE.join("|")})$"](${e});out geom;`;return this.waysFrom(await this.client.query(i))}waysFrom(t){const e=[];for(const i of t.elements??[]){const n=i.geometry,s=i.tags;!s||!n||n.length<2||e.push({id:`osm-${i.id??e.length}`,name:s.name,surface:ka.surfaceOf(s),widthM:ka.widthOf(s),...ka.paintOf(s),points:n.map(a=>({lat:a.lat,lng:a.lon}))})}return e}static paintOf(t){const e=t.highway??"",i=t.junction==="roundabout"||t.junction==="circular",n=t.oneway,s=n==="yes"||n==="1"||n==="true"||n===void 0&&(e==="motorway"||i),a=n==="-1"||n==="reverse",o=Number.parseInt(t.lanes??"",10),c=Number.parseInt(t.maxspeed??"",10),l=i?"roundabout":e==="motorway"?"motorway":e.endsWith("_link")?"slip":(e==="trunk"||e==="primary")&&(s||a)?"dual":e?"road":void 0;return{...l?{kind:l}:{},...Number.isFinite(o)&&o>0?{lanes:o}:{},...n!==void 0||e==="motorway"||i?{direction:a?"backward":s?"forward":"both"}:{},...Number.isFinite(c)&&c>0?{speedKmh:c}:{}}}static widthOf(t){const e=Number.parseFloat(t.width??t.est_width??"");if(Number.isFinite(e)&&e>0)return e;const i=Number.parseInt(t.lanes??"",10);return Number.isFinite(i)&&i>0?i*3.5:ka.WIDTH_M[t.highway]??ka.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 Zu="https://ufoathome.org/roads/index.json";class Eo{attributionRead;contemporaryRead;fetchImpl;indexUrls;fallback;index;static shared=new Map;sharing;constructor(t={}){this.sharing=!t.fetchImpl,this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.indexUrls=t.indexUrls??Eo.defaultIndexUrls(),this.fallback=t.fallback}get attribution(){return this.attributionRead??this.fallback?.attribution??"Roads © OpenStreetMap contributors"}get contemporary(){return this.contemporaryRead??this.fallback?.contemporary??!0}async getRoads(t){const e=await this.held(t);if(e)return e;if(!this.fallback)return[];const i=await this.fallback.getRoads(t);return this.attributionRead=this.fallback.attribution,this.contemporaryRead=this.fallback.contemporary,i}async held(t){let e;try{e=await this.load()}catch{return}const i=e.find(({entry:n})=>n.north>=t.north&&n.south<=t.south&&n.east>=t.east&&n.west<=t.west);if(i)try{const n=await this.fetchImpl(new URL(i.entry.file,i.indexUrl).href);if(!n.ok)return;const s=await n.json();return Array.isArray(s?.ways)?(this.attributionRead=s.attribution,this.contemporaryRead=s.contemporary,s.ways):void 0}catch{return}}load(){if(this.index)return this.index;if(!this.sharing)return this.index=this.fetchFirstAvailable();const t=this.indexUrls.join(`
1632
- `);let e=Eo.shared.get(t);return e||(e=this.fetchFirstAvailable(),Eo.shared.set(t,e),e.then(i=>{i.length===0&&Eo.shared.delete(t)})),this.index=e}async fetchFirstAvailable(){for(const t of this.indexUrls)try{const e=await this.fetchImpl(t);if(!e.ok)continue;const i=await e.json();if(Array.isArray(i?.entries))return i.entries.map(n=>({entry:n,indexUrl:t}))}catch{}return[]}static defaultIndexUrls(){const t=`?v=${encodeURIComponent("0.127.0")}`,e=typeof location>"u"?void 0:new URL("/roads/index.json",location.href).href;return(e&&e!==Zu?[e,Zu]:[Zu]).map(i=>i+t)}}class Ga{attribution="Roads © IGN, BD TOPO (Licence Ouverte 2.0), as drawn today";contemporary=!0;static BY_NATURE={"Type autoroutier":{surface:"paved",widthM:11},"Route à 2 chaussées":{surface:"paved",widthM:7},"Route à 1 chaussée":{surface:"paved",widthM:5.5},"Rond-point":{surface:"paved",widthM:6},Bretelle:{surface:"paved",widthM:5},"Route empierrée":{surface:"gravel",widthM:3.5},Chemin:{surface:"dirt",widthM:3},"Piste cyclable":{surface:"paved",widthM:2.5}};static DEFAULT={surface:"paved",widthM:5};static KINDS={"Type autoroutier":"motorway","Route à 2 chaussées":"dual","Route à 1 chaussée":"road","Rond-point":"roundabout",Bretelle:"slip"};static DIRECTIONS={"Double sens":"both","Sens direct":"forward","Sens inverse":"backward"};platform;constructor(t={}){this.platform=new be(t)}static covers(t){return be.covers((t.south+t.north)/2,(t.west+t.east)/2)}async getRoads(t){return(await this.platform.roads(t)).flatMap((i,n)=>Ga.wayOf(i,n))}static wayOf(t,e){if(t.geometry.type!=="LineString")return[];const i=t.geometry.coordinates.map(([d,f])=>({lat:f,lng:d}));if(i.length<2)return[];const n=String(t.properties.nature??""),s=Ga.BY_NATURE[n]??Ga.DEFAULT,a=Number(t.properties.largeur_de_chaussee),o=Number(t.properties.nombre_de_voies),c=Number(t.properties.vitesse_moyenne_vl),l=Ga.DIRECTIONS[String(t.properties.sens_de_circulation??"")],h=Ga.KINDS[n],u=[t.properties.cpx_toponyme_route_nommee,t.properties.nom_voie_ban_gauche,t.properties.nom_voie_ban_droite].find(d=>typeof d=="string"&&d.length>0);return[{id:String(t.properties.cleabs??`ign-${e}`),...u?{name:u}:{},surface:s.surface,widthM:Number.isFinite(a)&&a>0?a:s.widthM,...t.properties.urbain===!0?{urban:!0}:{},...h?{kind:h}:{},...Number.isInteger(o)&&o>0?{lanes:o}:{},...l?{direction:l}:{},...Number.isFinite(c)&&c>0?{speedKmh:c}:{},points:i}]}}class cx{constructor(t,e){this.regional=t,this.worldwide=e}attribution="Roads © IGN, BD TOPO, in France; © OpenStreetMap contributors elsewhere, as drawn today";contemporary=!0;async getRoads(t){if(Ga.covers(t))try{const e=await this.regional.getRoads(t);if(e.length>0)return e}catch{}return this.worldwide.getRoads(t)}}class hl{attribution="Water © IGN, BD TOPO (Licence Ouverte 2.0)";platform;constructor(t={}){this.platform=new be(t)}static covers(t){return be.covers((t.south+t.north)/2,(t.west+t.east)/2)}async getWater(t){return(await this.platform.waterSurfaces(t)).flatMap((i,n)=>hl.surfacesOf(i,n))}static surfacesOf(t,e){const{type:i,coordinates:n}=t.geometry,s=i==="Polygon"?[n]:i==="MultiPolygon"?n:[],a=String(t.properties.cleabs??`ign-water-${e}`);return s.flatMap((o,c)=>{const l=o.map(h=>hl.open(h.map(u=>({lat:u[1],lng:u[0]})))).filter(h=>h.length>=3);return l.length>0?[{id:s.length>1?`${a}-${c}`:a,rings:l}]:[]})}static open(t){const e=t[0],i=t[t.length-1];return t.length>1&&e.lat===i.lat&&e.lng===i.lng?t.slice(0,-1):t}}class fr{attribution="Water © OpenStreetMap contributors";client;constructor(t={}){this.client=new Un(t)}async getWater(t){const e=`${t.south},${t.west},${t.north},${t.east}`,i=`[out:json][timeout:30];(way["natural"="water"](${e});way["waterway"="riverbank"](${e});)->.w;(relation["natural"="water"](${e});relation["waterway"="riverbank"](${e});)->.r;.w out geom;.r out body;way(r.r)(${e});out geom;`;return fr.surfacesFrom(await this.client.query(i))}static surfacesFrom(t){const e=t.elements??[],i=new Map;for(const a of e)a.type==="way"&&a.id!==void 0&&a.geometry&&i.set(a.id,a.geometry.map(o=>({lat:o.lat,lng:o.lon})));const n=[],s=new Set;for(const a of e){if(a.type!=="relation")continue;const o=l=>(a.members??[]).filter(h=>h.type==="way"&&h.role===l&&h.ref!==void 0&&i.has(h.ref)).map(h=>(s.add(h.ref),i.get(h.ref))),c=fr.rings(o("inner"));for(const[l,h]of fr.rings(o("outer")).entries()){const u=c.filter(d=>fr.contains(h,d[0]));n.push({id:`osm-r${a.id}-${l}`,rings:[h,...u]})}}for(const a of e)if(!(a.type!=="way"||!a.tags||a.id===void 0||s.has(a.id))&&!(a.tags.natural!=="water"&&a.tags.waterway!=="riverbank"))for(const o of fr.rings([i.get(a.id)??[]]))n.push({id:`osm-w${a.id}`,rings:[o]});return n}static rings(t){const e=(s,a)=>s.lat===a.lat&&s.lng===a.lng,i=t.filter(s=>s.length>=2).map(s=>[...s]),n=[];for(;i.length>0;){let s=i.pop(),a=!0;for(;!e(s[0],s[s.length-1])&&a;){a=!1;for(let o=0;o<i.length;o++){const c=i[o],l=s[s.length-1];if(e(l,c[0]))s=[...s,...c.slice(1)];else if(e(l,c[c.length-1]))s=[...s,...[...c].reverse().slice(1)];else continue;i.splice(o,1),a=!0;break}}s.length>=4&&e(s[0],s[s.length-1])&&n.push(s.slice(0,-1))}return n}static contains(t,e){let i=!1;for(let n=0,s=t.length-1;n<t.length;s=n++){const a=t[n],o=t[s];a.lat>e.lat!=o.lat>e.lat&&e.lng<(o.lng-a.lng)*(e.lat-a.lat)/(o.lat-a.lat)+a.lng&&(i=!i)}return i}}class lx{constructor(t,e){this.regional=t,this.worldwide=e}attribution="Water © IGN, BD TOPO, in France; © OpenStreetMap contributors elsewhere";async getWater(t){if(hl.covers(t))try{const e=await this.regional.getWater(t);if(e.length>0)return e}catch{}return this.worldwide.getWater(t)}}const Ju="https://ufoathome.org/water/index.json";class Ao{attributionRead;fetchImpl;indexUrls;fallback;index;static shared=new Map;sharing;constructor(t={}){this.sharing=!t.fetchImpl,this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.indexUrls=t.indexUrls??Ao.defaultIndexUrls(),this.fallback=t.fallback}get attribution(){return this.attributionRead??this.fallback?.attribution??"Water © OpenStreetMap contributors"}async getWater(t){const e=await this.held(t);if(e)return e;if(!this.fallback)return[];const i=await this.fallback.getWater(t);return this.attributionRead=this.fallback.attribution,i}async held(t){const i=(await this.load().catch(()=>[])).find(({entry:n})=>n.north>=t.north&&n.south<=t.south&&n.east>=t.east&&n.west<=t.west);if(i)try{const n=await this.fetchImpl(new URL(i.entry.file,i.indexUrl).href);if(!n.ok)return;const s=await n.json();return Array.isArray(s?.surfaces)?(this.attributionRead=s.attribution,s.surfaces):void 0}catch{return}}load(){if(this.index)return this.index;if(!this.sharing)return this.index=this.fetchFirstAvailable();const t=this.indexUrls.join(`
1633
- `);let e=Ao.shared.get(t);return e||(e=this.fetchFirstAvailable(),Ao.shared.set(t,e),e.then(i=>{i.length===0&&Ao.shared.delete(t)})),this.index=e}async fetchFirstAvailable(){for(const t of this.indexUrls)try{const e=await this.fetchImpl(t);if(!e.ok)continue;const i=await e.json();if(Array.isArray(i?.entries))return i.entries.map(n=>({entry:n,indexUrl:t}))}catch{}return[]}static defaultIndexUrls(){const t=`?v=${encodeURIComponent("0.127.0")}`,e=typeof location>"u"?void 0:new URL("/water/index.json",location.href).href;return(e&&e!==Ju?[e,Ju]:[Ju]).map(i=>i+t)}}class Sn{constructor(t){this.water=t}static CACHE_NAME="rr0-water";static MAX_AGE_MS=720*3600*1e3;static FORMAT=1;static MAX_STORED=400;static asked=new Map;get attribution(){return this.water.attribution}async getWater(t){const e=Sn.key(t);let i=Sn.asked.get(e);return i===void 0&&(i=this.recalled(e,t),Sn.asked.set(e,i),i.catch(()=>Sn.asked.delete(e))),structuredClone(await i)}static forget(){Sn.asked.clear()}static key(t){return`v${Sn.FORMAT}/${[t.north,t.south,t.east,t.west].map(e=>e.toFixed(5)).join("/")}`}async recalled(t,e){const i=await Sn.openCache(),n=Sn.request(t);if(i)try{const a=await i.match(n);if(a){const{savedAt:o,surfaces:c}=await a.json();if(Date.now()-o<Sn.MAX_AGE_MS&&Array.isArray(c))return c;await i.delete(n)}}catch{}const s=await this.water.getWater(e);return i&&Sn.store(i,n,s),s}static async store(t,e,i){try{const n={savedAt:Date.now(),surfaces:i};await t.put(e,new Response(JSON.stringify(n),{headers:{"Content-Type":"application/json"}}));const s=await t.keys();for(const a of s.slice(0,Math.max(0,s.length-Sn.MAX_STORED)))await t.delete(a)}catch{}}static async openCache(){try{return typeof caches>"u"?void 0:await caches.open(Sn.CACHE_NAME)}catch{return}}static request(t){const e=typeof location>"u"?"http://localhost":location.origin;return new Request(`${e}/__water__/${encodeURIComponent(t)}`)}}class Va{attribution="Railways © IGN, BD TOPO (Licence Ouverte 2.0), as drawn today";contemporary=!0;static BY_NATURE={"Voie ferrée principale":{kind:"rail"},LGV:{kind:"rail",highSpeed:!0},"Voie de service":{kind:"rail",service:!0},Métro:{kind:"subway"},Tramway:{kind:"tram"},"Transport urbain":{kind:"light_rail"},"Funiculaire ou crémaillère":{kind:"funicular"}};static GAUGE_MM={Normale:1435,Etroite:1e3,Étroite:1e3,Large:1668};static NO_ALTITUDE=-1e3;platform;constructor(t={}){this.platform=new be(t)}static covers(t){return be.covers((t.south+t.north)/2,(t.west+t.east)/2)}async getRailways(t){return(await this.platform.railways(t)).flatMap((i,n)=>Va.linesOf(i,n))}static linesOf(t,e){const{type:i,coordinates:n}=t.geometry,s=i==="LineString"?[n]:i==="MultiLineString"?n:[],a=Va.BY_NATURE[String(t.properties.nature??"")];if(!a)return[];const o=String(t.properties.cleabs??`ign-rail-${e}`),c=Number(t.properties.nombre_de_voies),l=Number(t.properties.position_par_rapport_au_sol),h=t.properties.cpx_toponyme,u=Va.GAUGE_MM[String(t.properties.largeur??"")]??1435,d=Va.electrificationOf(a.kind,u,t.properties.electrifie);return s.flatMap((f,p)=>{const v=f.map(m=>({lat:m[1],lng:m[0],...m.length>2&&Number.isFinite(m[2])&&m[2]>Va.NO_ALTITUDE?{altitudeM:m[2]}:{}}));return v.length<2?[]:[{id:s.length>1?`${o}-${p}`:o,...typeof h=="string"&&h.length>0?{name:h}:{},kind:a.kind,...a.service?{service:!0}:{},...a.highSpeed?{highSpeed:!0}:{},gaugeMm:u,tracks:Number.isInteger(c)&&c>0?c:1,...d?{electrification:d}:{},level:Number.isFinite(l)?l:0,points:v}]})}static electrificationOf(t,e,i){if(i===!1)return"none";if(i===!0){if(t==="subway")return"third_rail";if(!(t==="funicular"||e<1435))return"overhead"}}}class To{attribution="Railways © OpenStreetMap contributors, as surveyed today";contemporary=!0;static KINDS=["rail","light_rail","tram","subway","narrow_gauge","funicular","preserved"];client;constructor(t={}){this.client=new Un(t)}async getRailways(t){const e=`${t.south},${t.west},${t.north},${t.east}`,i=`[out:json][timeout:25];way["railway"~"^(${To.KINDS.join("|")})$"](${e});out tags geom;`;return this.linesFrom(await this.client.query(i))}linesFrom(t){const e=[];for(const i of t.elements??[]){const n=i.geometry,s=i.tags;if(!s||!n||n.length<2)continue;const a=To.kindOf(s),o=Number.parseInt((s.gauge??"").split(";")[0],10),c=Number.parseInt(s.tracks??"",10),l=To.electrificationOf(s.electrified),h=s.highspeed==="yes"||Number.parseInt(s.maxspeed??"",10)>=250;e.push({id:`osm-rail-${i.id??e.length}`,...s.name?{name:s.name}:{},kind:a,...s.service||s.usage==="industrial"?{service:!0}:{},...h?{highSpeed:!0}:{},gaugeMm:Number.isFinite(o)&&o>300?o:s.railway==="narrow_gauge"?1e3:1435,tracks:Number.isFinite(c)&&c>0?c:1,...l?{electrification:l}:{},level:To.levelOf(s),points:n.map(u=>({lat:u.lat,lng:u.lon}))})}return e}static kindOf(t){switch(t.railway){case"tram":return"tram";case"subway":return"subway";case"light_rail":return"light_rail";case"funicular":return"funicular";default:return"rail"}}static electrificationOf(t){if(t!==void 0){if(t==="no")return"none";if(t==="contact_line"||t==="yes")return"overhead";if(t==="rail"||t==="4th_rail"||t==="ground-level_power_supply")return"third_rail"}}static levelOf(t){const e=Number.parseInt(t.layer??"",10);return t.tunnel&&t.tunnel!=="no"?Number.isFinite(e)&&e<0?e:-1:t.covered==="yes"&&t.location==="underground"?-1:t.bridge&&t.bridge!=="no"?Number.isFinite(e)&&e>0?e:1:0}}class hx{constructor(t,e){this.regional=t,this.worldwide=e}attribution="Railways © IGN, BD TOPO, in France; © OpenStreetMap contributors elsewhere, as drawn today";contemporary=!0;async getRailways(t){if(!Va.covers(t))return this.worldwide.getRailways(t);let e;try{if(e=await this.regional.getRailways(t),e.length>0)return e}catch{}try{return await this.worldwide.getRailways(t)}catch(i){if(e)return e;throw i}}}class Ii{constructor(t,e=Date.now){this.railways=t,this.now=e}static CACHE_NAME="rr0-railways";static MAX_AGE_MS=720*3600*1e3;static FORMAT=1;static MAX_STORED=400;static RETRY_AFTER_MS=300*1e3;static asked=new Map;static failedAt=-1/0;get attribution(){return this.railways.attribution}get contemporary(){return this.railways.contemporary}async getRailways(t){const e=Ii.key(t);let i=Ii.asked.get(e)??Ii.containing(t);if(i===void 0){const n=this.recalled(e,t);i={bounds:t,answer:n},Ii.asked.set(e,i),n.catch(()=>Ii.asked.delete(e))}return structuredClone(await i.answer)}static forget(){Ii.asked.clear(),Ii.failedAt=-1/0}static key(t){return`v${Ii.FORMAT}/${[t.north,t.south,t.east,t.west].map(e=>e.toFixed(5)).join("/")}`}static containing(t){for(const e of Ii.asked.values()){const i=e.bounds;if(i.north>=t.north&&i.south<=t.south&&i.east>=t.east&&i.west<=t.west)return e}}async recalled(t,e){const i=await Ii.openCache(),n=Ii.request(t);let s;if(i)try{const o=await i.match(n);if(o){const{savedAt:c,lines:l}=await o.json();if(Array.isArray(l)){if(this.now()-c<Ii.MAX_AGE_MS)return l;s=l}}}catch{}if(this.now()-Ii.failedAt<Ii.RETRY_AFTER_MS){if(s)return s;throw new Error("The railway survey failed a moment ago: not asked again yet")}let a;try{a=await this.railways.getRailways(e)}catch(o){if(Ii.failedAt=this.now(),s)return s;throw o}return i&&Ii.store(i,n,{savedAt:this.now(),lines:a}),a}static async store(t,e,i){try{await t.delete(e),await t.put(e,new Response(JSON.stringify(i),{headers:{"Content-Type":"application/json"}}));const n=await t.keys();for(const s of n.slice(0,Math.max(0,n.length-Ii.MAX_STORED)))await t.delete(s)}catch{}}static async openCache(){try{return typeof caches>"u"?void 0:await caches.open(Ii.CACHE_NAME)}catch{return}}static request(t){const e=typeof location>"u"?"http://localhost":location.origin;return new Request(`${e}/__railways__/${encodeURIComponent(t)}`)}}const ju="https://ufoathome.org/railways/index.json";class Ro{contemporary=!0;attributionRead;fetchImpl;indexUrls;fallback;index;static shared=new Map;sharing;constructor(t={}){this.sharing=!t.fetchImpl,this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.indexUrls=t.indexUrls??Ro.defaultIndexUrls(),this.fallback=t.fallback}get attribution(){return this.attributionRead??this.fallback?.attribution??"Railways © OpenStreetMap contributors"}async getRailways(t){const e=await this.held(t);if(e)return e;if(!this.fallback)return[];const i=await this.fallback.getRailways(t);return this.attributionRead=this.fallback.attribution,i}async held(t){const i=(await this.load().catch(()=>[])).find(({entry:n})=>n.north>=t.north&&n.south<=t.south&&n.east>=t.east&&n.west<=t.west);if(i)try{const n=await this.fetchImpl(new URL(i.entry.file,i.indexUrl).href);if(!n.ok)return;const s=await n.json();return Array.isArray(s?.lines)?(this.attributionRead=s.attribution,s.lines):void 0}catch{return}}load(){if(this.index)return this.index;if(!this.sharing)return this.index=this.fetchFirstAvailable();const t=this.indexUrls.join(`
1634
- `);let e=Ro.shared.get(t);return e||(e=this.fetchFirstAvailable(),Ro.shared.set(t,e),e.then(i=>{i.length===0&&Ro.shared.delete(t)})),this.index=e}async fetchFirstAvailable(){for(const t of this.indexUrls)try{const e=await this.fetchImpl(t);if(!e.ok)continue;const i=await e.json();if(Array.isArray(i?.entries))return i.entries.map(n=>({entry:n,indexUrl:t}))}catch{}return[]}static defaultIndexUrls(){const t=`?v=${encodeURIComponent("0.127.0")}`,e=typeof location>"u"?void 0:new URL("/railways/index.json",location.href).href;return(e&&e!==ju?[e,ju]:[ju]).map(i=>i+t)}}function ux(){return{elevation:dx(),imagery:Zv(),roads:fx(),water:px(),railways:mx()}}function dx(){return new nx(new Me,new ex)}function Zv(){return new ox}function fx(){return new Eo({fallback:new cx(new Ga,new ka)})}function px(){return new Ao({fallback:new Sn(new lx(new hl,new fr))})}function mx(){return new Ro({fallback:new Ii(new hx(new Va,new To))})}const gx=new Set,Ho="show-observer-map",Bo="hide-milestones",Mr="minified";class ye extends HTMLElement{static get observedAttributes(){return["src",Ho,Bo,Mr]}shadow;stageElement;canvas;canvasRenderer;chromeCanvas;chromeRenderer;chromeResizeObserver=typeof ResizeObserver>"u"?void 0:new ResizeObserver(()=>{this.chromeDirty&&this.refresh()});chromeDirty=!1;tooltip;toolbar;issuesBox;issuesButton;issuesPanel;playPauseButton;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;accountHidden=!1;referenceViews=new Map;referencesMenu;referenceOpacityTouched=!1;milestonesButton;observerMapPanel;observerMapCanvas;observerMapRenderer;mapZoomInButton;mapZoomOutButton;mapFitButton;observerMapView=new ci;observerMapDrag;suppressObserverMapClick=!1;observerMapImageryTimer;observerPlacing=!1;seekInput;playbackFlash;milestoneMarks;milestoneCaption;timeStartLabel;timeEndLabel;timePill;muteButton;volumeInput;controlsRow;momentsBox;momentsButton;momentsCurrent;momentsMenu;moreButton;controlsRight;seekSegments;seekDot;playerTitleBox;seekPreview;seekPreviewCanvas;seekPreviewTitle;seekPreviewTime;observerPath;observerMapBounds;observerMapImagery;observerMapImageryBounds;observerMapImageryViewWidth=0;observerMapImageryLoading=!1;observerMapImageryCredit;observerMapImageryFailed=!1;creditShownExternally=!1;lookYawDeg=0;lookPitchDeg=0;milestonesShown=!0;currentSighting=Iu.create();issues=[];issueCheck=0;sightingAudio=new Fy;soundPreview;player;loopEnabled=!1;playbackBeforeClick;highlightedSourceIds=new Set;paintsShapes=!0;steadyObserver=!1;static LIVE_BODY_MAX_RATE=2;get steadyBody(){return this.steadyObserver||this.player.playbackState!=="playing"||this.player.playbackRate>ye.LIVE_BODY_MAX_RATE}selectionShown=!0;overlayPainter;enableClickToPlay=!0;fullscreenTarget;messages=Bv;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");ye.setIcon(this.moreButton,t?Xt.UNFOLDED:Xt.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)<ye.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>=ci.MAX_ZOOM,this.mapZoomOutButton.disabled=this.observerMapView.zoomFactor<=ci.MIN_ZOOM,this.paintObserverMap(this.currentTime),this.scheduleObserverMapImagery()}scheduleObserverMapImagery(){this.observerMapImageryTimer===void 0&&(this.observerMapImageryTimer=setTimeout(()=>{this.observerMapImageryTimer=void 0,this.loadObserverMapImagery()},ye.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=ci.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>${ly}</style>${cy}`,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.chromeCanvas=this.shadow.getElementById("chrome"),this.tooltip=this.shadow.getElementById("tooltip"),this.toolbar=this.shadow.getElementById("toolbar"),this.issuesBox=this.shadow.getElementById("issues"),this.issuesButton=this.shadow.getElementById("issues-button"),this.issuesPanel=this.shadow.getElementById("issues-panel"),this.issuesButton.addEventListener("click",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.referencesMenu=this.shadow.getElementById("references-menu"),this.milestonesButton=this.shadow.getElementById("milestones"),this.observerMapPanel=this.shadow.getElementById("observer-map-panel"),this.observerMapCanvas=this.shadow.getElementById("observer-map-canvas"),this.observerMapRenderer=new dr(this.observerMapCanvas.getContext("2d")),this.mapZoomInButton=this.shadow.getElementById("map-zoom-in"),this.mapZoomOutButton=this.shadow.getElementById("map-zoom-out"),this.mapFitButton=this.shadow.getElementById("map-fit"),this.seekInput=this.shadow.getElementById("seek"),this.playbackFlash=this.shadow.getElementById("playback-flash"),this.milestoneMarks=this.shadow.getElementById("milestone-marks"),this.milestoneCaption=this.shadow.getElementById("milestone-caption"),this.timeStartLabel=this.shadow.getElementById("time-start"),this.timeEndLabel=this.shadow.getElementById("time-end"),this.timePill=this.shadow.getElementById("time"),this.muteButton=this.shadow.getElementById("mute"),this.controlsRight=this.shadow.getElementById("controls-right"),this.seekSegments=this.shadow.getElementById("seek-segments"),this.seekDot=this.shadow.getElementById("seek-dot"),this.playerTitleBox=this.shadow.getElementById("player-title"),this.seekPreview=this.shadow.getElementById("seek-preview"),this.seekPreviewCanvas=this.shadow.getElementById("seek-preview-canvas"),this.seekPreviewTitle=this.shadow.getElementById("seek-preview-title"),this.seekPreviewTime=this.shadow.getElementById("seek-preview-time"),this.timePill.addEventListener("click",()=>this.toggleTimeDisplay()),this.timePill.addEventListener("keydown",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.miniPlayed=this.shadow.getElementById("mini-played"),this.miniRemaining=this.shadow.getElementById("mini-remaining"),this.miniMuteButton=this.shadow.getElementById("mini-mute"),this.miniMuteButton.addEventListener("click",e=>{e.stopPropagation(),this.toggleMuted()}),this.stageElement.addEventListener("pointerenter",this.handleMinifiedEnter),this.stageElement.addEventListener("pointerleave",this.handleMinifiedLeave),this.volumeInput.addEventListener("input",()=>{this.setVolume(Number(this.volumeInput.value))}),this.fullscreenTarget=this.stageElement,this.playPauseButton.addEventListener("click",()=>this.togglePlayPause()),this.fullscreenButton.addEventListener("click",()=>this.toggleFullscreen()),this.addEventListener("keydown",this.handleFullscreenKey),this.observerMapButton.addEventListener("click",()=>this.toggleObserverMap()),this.referencesButton.addEventListener("click",()=>this.toggleReferences()),this.tracesButton.addEventListener("click",()=>this.toggleTraces()),this.referenceOpacityInput.addEventListener("input",()=>{this.referenceOpacityTouched=!0,this.dispatchReferenceView()}),this.milestonesButton.addEventListener("click",()=>this.toggleMilestones()),this.observerMapCanvas.addEventListener("pointermove",this.handleObserverMapPointerMove),this.observerMapCanvas.addEventListener("pointerleave",this.handlePointerLeave),this.observerMapCanvas.addEventListener("click",this.handleObserverMapClick),this.observerMapCanvas.addEventListener("pointerdown",this.handleObserverMapPointerDown),this.observerMapCanvas.addEventListener("pointerup",this.handleObserverMapPointerUp),this.observerMapCanvas.addEventListener("pointercancel",this.handleObserverMapPointerUp),this.observerMapCanvas.addEventListener("wheel",this.handleObserverMapWheel,{passive:!1}),this.mapZoomInButton.addEventListener("click",()=>this.zoomObserverMap(.5,.5,2)),this.mapZoomOutButton.addEventListener("click",()=>this.zoomObserverMap(.5,.5,.5)),this.mapFitButton.addEventListener("click",()=>{this.observerMapView.reset(),this.observerMapViewChanged()}),this.seekInput.addEventListener("input",()=>this.player.seek(this.snapSeekToMark(Number(this.seekInput.value)))),this.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||this.minified)){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||this.minified||(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.chromeResizeObserver?.observe(this.chromeCanvas),this.controlsFitObserver?.observe(this.controlsRow),this.controlsFitObserver?.observe(this.controlsRow.querySelector(".controls-left")),typeof MutationObserver<"u"&&(this.controlsMutations=new MutationObserver(()=>this.fitControls()),this.controlsMutations.observe(this.controlsRight,{attributes:!0,attributeFilter:["hidden"],childList:!0,subtree:!0})),this.hostControls(void 0),this.player=this.createPlayer(),this.updateTimeLabels(),this.updatePlayPauseButton(),this.updateFullscreenButton(),this.updateMuteButton(),this.updateObserverMapButton(),this.updateReferencesButton(),this.updateTracesButton(),this.updateMilestonesButton(),this.refresh()}connectedCallback(){this.saidTexts=void 0,this.loadLocaleMessages();const t=this.getAttribute("src");t&&this.loadFromSrc(t)}disconnectedCallback(){document.removeEventListener("fullscreenchange",this.handleFullscreenChange),document.removeEventListener("pointerdown",this.handleMomentsDismiss,!0),document.removeEventListener("keydown",this.handleMomentsDismiss,!0),document.removeEventListener("visibilitychange",this.handleVisibility),window.removeEventListener("pagehide",this.handleHidden),document.removeEventListener("pointerup",this.handlePointerRelease,!0),document.removeEventListener("pointercancel",this.handlePointerRelease,!0),window.clearTimeout(this.controlsIdleTimer),this.observerMapResizeObserver?.disconnect(),this.chromeResizeObserver?.disconnect(),this.controlsFitObserver?.disconnect(),this.controlsMutations?.disconnect(),this.exitSimulatedFullscreen(),this.sightingAudio.dispose()}attributeChangedCallback(t,e,i){if(t==="src"&&i&&i!==e&&this.isConnected&&this.loadFromSrc(i),t===Ho&&this.applyObserverMapDefault(),t===Bo&&this.setMilestonesShown(!this.hasAttribute(Bo)),t===Mr){const n=this.minified;this.stageElement.classList.toggle("minified",n),n&&e===null&&(this.muted=!0),this.updateStartState()}}get minified(){return this.hasAttribute(Mr)}miniPlayed;miniRemaining;miniMuteButton;handleMinifiedEnter=t=>{!this.minified||t.pointerType==="touch"||(this.minifiedHovered=!0,this.play())};minifiedHovered=!1;handleMinifiedLeave=t=>{!this.minified||t.pointerType==="touch"||(this.minifiedHovered=!1,this.pause(),this.player.seek(0),this.dispatchEvent(new CustomEvent(jv)))};started=!1;updateStartState(){this.playRequested&&(this.started=!0);const t=!this.started&&this.enableClickToPlay;this.stageElement.classList.toggle("unstarted",t),t&&!this.minified?this.canvas.title=this.messages.clickToPlay:this.canvas.removeAttribute("title")}async loadFromSrc(t){this.sightingData=await Fv.json(t)}get sightingData(){return ky(this.currentSighting)}set sightingData(t){this.player.stop(),this.soundPreview=void 0,this.sightingAudio.silence(),this.currentSighting=Hy(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.started=!1,this.syncPlayerTitle(),this.updateTimeLabels(),this.updatePlayPauseButton(),this.refresh(),this.applyObserverMapDefault(),this.minified&&this.minifiedHovered&&this.play()}set playerTitle(t){this.titleOverride=t,this.syncPlayerTitle()}titleOverride;syncPlayerTitle(){const t=this.said.read(this.titleOverride)??this.currentSighting.observer?.title??"";this.playerTitleBox.textContent=t,this.playerTitleBox.hidden=t===""}get recordingIssues(){return this.issues}async reportIssues(t,e){const i=++this.issueCheck;let n=[];try{const{default:s}=await Fi(async()=>{const{default:a}=await import("./sightingSchema-v2l1p6Ld.js");return{default:a}},[],import.meta.url);n=new os(s).issues(t)}catch{}i===this.issueCheck&&(this.issues=[...n,...e.loadIssues],tc.warn(this.issues,e.id),this.renderIssues(),this.dispatchEvent(new CustomEvent(vx,{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=tc.text(i,this.messages.issueTemplates),n}))}get sighting(){return this.currentSighting}previewSound(t){this.soundPreview=t,this.sightingAudio.resume(),this.sightingAudio.setSound(t)}stopSoundPreview(){this.soundPreview=void 0,this.sightingAudio.silence()}get canvasElement(){return this.canvas}get renderer(){return this.canvasRenderer}get currentTime(){return this.player.time}set currentTime(t){this.player.seek(t)}get seekableDuration(){return this.player.seekableDuration}get autoReplayEnabled(){return this.loopEnabled}set autoReplayEnabled(t){t!==this.loopEnabled&&this.toggleLoop()}play(){if(!(this.player.seekableDuration<=0||this.playbackState==="playing")){if(this.clockHeld){this.playAfterHold=!0,this.announcePlayRequest();return}this.togglePlayPause()}}get playRequested(){return this.playbackState==="playing"||this.playAfterHold}announcePlayRequest(){this.started=!0,this.updateStartState(),this.dispatchEvent(new CustomEvent("playrequest"))}clockHeld=!1;playAfterHold=!1;holdClock(t){if(t!==this.clockHeld){if(this.clockHeld=t,t){if(this.playbackState!=="playing")return;this.playAfterHold=!0,this.player.pause(),this.soundPreview=void 0,this.sightingAudio.silence(),this.refresh(),this.updatePlayPauseButton();return}this.playAfterHold&&(this.playAfterHold=!1,!(this.player.seekableDuration<=0||this.playbackState==="playing")&&(this.sightingAudio.resume(),this.player.play(),this.updatePlayPauseButton()))}}pause(){this.playAfterHold=!1,this.playbackState==="playing"&&this.togglePlayPause()}get positionLabel(){return this.timeStartLabel.textContent??""}get durationLabel(){return this.timeEndLabel.textContent??""}get showingClockTime(){return this.canShowClockTime}get canSwitchTimeDisplay(){return this.realStartMs!==void 0}toggleTimeDisplay(){this.canSwitchTimeDisplay&&(this.showClockTime=!this.showClockTime,this.updateTimeLabels(),this.updateTimeLabelTitles(),this.dispatchEvent(new CustomEvent("timedisplaychange",{bubbles:!0,composed:!0})))}get canShowClockTime(){return this.realStartMs!==void 0&&this.showClockTime}set showToolbar(t){this.toolbar.classList.toggle("hidden",!t),t?this.controlsRight.appendChild(this.fullscreenButton):this.cornerButtons.appendChild(this.fullscreenButton)}get playbackState(){return this.player.playbackState}get selectedSourceIds(){return this.highlightedSourceIds}get durationSeconds(){return this.currentSighting.event.durationSeconds}set durationSeconds(t){this.currentSighting.event.durationSeconds=t,this.updateTimeLabels(),this.refresh(),this.updatePlayPauseButton()}set selectedSourceIds(t){const e=new Set(t);e.size===this.highlightedSourceIds.size&&[...e].every(n=>this.highlightedSourceIds.has(n))||(this.highlightedSourceIds=e,this.refresh())}hasVisibleShapeAt(t,e){return this.shapeAt(t,e)!==void 0}refresh(){this.applyFrameFormat(),this.updateMuteButton(),this.updateTimeLabels(),this.seekInput.max=String(this.player.seekableDuration),this.refreshMilestoneMarks(),this.updateMilestonesButton(),this.updateObserverMap(),this.updateReferences(),this.updateTracesButton(),this.player.seek(this.player.time)}repaintOverlay(){this.quietFrame=!0;try{this.player.seek(this.player.time)}finally{this.quietFrame=!1}}quietFrame=!1;hostControls(t){const e=[this.milestonesButton,this.referencesButton,this.referenceOpacityInput,this.tracesButton,this.observerMapButton];if(t)for(const i of e)t.appendChild(i);else{const i=this.fullscreenButton.parentElement===this.controlsRight?this.fullscreenButton:null;for(const n of e)this.controlsRight.insertBefore(n,i)}}get referencesShown(){return this.referencesShownState}get referenceOpacity(){return Number(this.referenceOpacityInput.value)}get severalReferences(){return this.currentSighting.references.length>1}toggleReferences(){if(this.severalReferences){this.toggleReferencesMenu();return}this.referencesShownState=!this.referencesShownState,this.updateReferencesButton(),this.dispatchReferenceView()}updateReferences(){const t=this.currentSighting.references;!this.referenceOpacityTouched&&t.length>0&&(this.referenceOpacityInput.value=String(t[0].opacity));for(const e of[...this.referenceViews.keys()])t.some(i=>i.id===e)||this.referenceViews.delete(e);this.severalReferences?this.referencesMenu.hidden||this.renderReferencesMenu():this.closeReferencesMenu(),this.updateReferencesButton(),this.severalReferences&&this.dispatchReferenceView()}viewOfReference(t){let e=this.referenceViews.get(t.id);return e||(e={shown:!0,opacity:t.opacity},this.referenceViews.set(t.id,e)),e}toggleReferencesMenu(){this.referencesMenu.hidden?this.openReferencesMenu():this.closeReferencesMenu()}openReferencesMenu(){this.renderReferencesMenu(),this.referencesMenu.hidden=!1,this.placeReferencesMenu(),this.referencesButton.setAttribute("aria-expanded","true"),document.addEventListener("pointerdown",this.handleReferencesMenuOutside,!0),document.addEventListener("keydown",this.handleReferencesMenuKey,!0)}closeReferencesMenu(){this.referencesMenu.hidden||(this.referencesMenu.hidden=!0,this.referencesButton.setAttribute("aria-expanded","false"),document.removeEventListener("pointerdown",this.handleReferencesMenuOutside,!0),document.removeEventListener("keydown",this.handleReferencesMenuKey,!0))}handleReferencesMenuOutside=t=>{const e=t.composedPath();e.includes(this.referencesMenu)||e.includes(this.referencesButton)||this.closeReferencesMenu()};handleReferencesMenuKey=t=>{t.key==="Escape"&&(this.closeReferencesMenu(),this.referencesButton.focus())};placeReferencesMenu(){const t=this.referencesButton.getBoundingClientRect(),e=this.referencesMenu,i=4;e.style.bottom=`${Math.max(i,window.innerHeight-t.top+i)}px`,e.style.top="auto";const n=e.getBoundingClientRect().width;e.style.left=`${Math.max(i,Math.min(t.left,window.innerWidth-n-i))}px`}renderReferencesMenu(){const t=this.currentSighting.references.map(e=>{const i=this.viewOfReference(e),n=this.said.read(e.title)??e.id,s=document.createElement("div");s.className="reference-row";const a=document.createElement("label"),o=document.createElement("input");o.type="checkbox",o.checked=i.shown;const c=document.createElement("span");c.textContent=n,c.title=n,a.append(o,c);const l=document.createElement("input");return l.type="range",l.min="0",l.max="1",l.step="0.05",l.value=String(i.opacity),l.title=this.messages.referenceOpacity,l.setAttribute("aria-label",`${this.messages.referenceOpacity}: ${n}`),l.disabled=!i.shown,o.addEventListener("change",()=>{i.shown=o.checked,l.disabled=!i.shown,this.updateReferencesButton(),this.dispatchReferenceView()}),l.addEventListener("input",()=>{i.opacity=Number(l.value),this.dispatchReferenceView()}),s.append(a,l),s});this.referencesMenu.setAttribute("aria-label",this.messages.referencesMenu),this.referencesMenu.replaceChildren(...t)}updateReferencesButton(){const t=this.currentSighting.references.length>0,e=this.severalReferences,i=e?this.currentSighting.references.some(s=>this.viewOfReference(s).shown):this.referencesShownState;this.referencesButton.hidden=!t,this.referenceOpacityInput.hidden=!t||!this.referencesShownState||e,this.referencesButton.setAttribute("aria-pressed",String(i)),e?this.referencesButton.setAttribute("aria-haspopup","true"):this.referencesButton.removeAttribute("aria-haspopup"),ye.setIcon(this.referencesButton,i?Xt.PICTURES_ON:Xt.PICTURES_OFF);const n=e?this.messages.referencesMenu:this.referencesShownState?this.messages.hideReferences:this.messages.showReferences;this.referencesButton.title=n,this.referencesButton.setAttribute("aria-label",n),this.referenceOpacityInput.title=this.messages.referenceOpacity,this.referenceOpacityInput.setAttribute("aria-label",this.messages.referenceOpacity)}get tracesShown(){return this.tracesShownState}toggleTraces(){this.tracesShownState=!this.tracesShownState,this.updateTracesButton(),this.updateObserverMap(),this.dispatchEvent(new CustomEvent("traceview",{detail:{shown:this.tracesShown}}))}updateTracesButton(){this.tracesButton.hidden=this.currentSighting.traces.length===0,this.tracesButton.setAttribute("aria-pressed",String(this.tracesShownState)),ye.setIcon(this.tracesButton,this.tracesShownState?Xt.TRACES_ON:Xt.TRACES_OFF);const t=this.tracesShownState?this.messages.hideTraces:this.messages.showTraces;this.tracesButton.title=t,this.tracesButton.setAttribute("aria-label",t)}dispatchReferenceView(){const t=this.severalReferences?Object.fromEntries(this.currentSighting.references.map(e=>[e.id,{...this.viewOfReference(e)}])):void 0;this.dispatchEvent(new CustomEvent("referenceview",{detail:{shown:this.referencesShown,opacity:this.referenceOpacity,views:t}}))}refreshMilestoneMarks(){const t=this.player.seekableDuration,e=t>0?Wc(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}%`}paintMiniProgress(t){const e=this.player.seekableDuration;this.miniPlayed.style.width=`${e>0?Math.min(Math.max(t/e,0),1)*100:0}%`,this.miniRemaining.textContent=this.formatRemaining(t)}paintSeekProgress(t){for(const i of this.seekSegmentList)i.played.style.width=ye.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=ye.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?Ku(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)}paintChrome(t){const e=this.chromeCanvas.getContext("2d"),i=this.overlayPainter!==void 0||this.selectionShown;if(!i&&!this.chromeDirty)return;const n=this.chromeCanvas.clientWidth,s=this.chromeCanvas.clientHeight;if(!e||typeof e.setTransform!="function"||n===0||s===0){t(this.canvasRenderer);return}const a=window.devicePixelRatio||1,o=Math.max(1,Math.round(n*a)),c=Math.max(1,Math.round(s*a));this.chromeCanvas.width!==o&&(this.chromeCanvas.width=o),this.chromeCanvas.height!==c&&(this.chromeCanvas.height=c),e.setTransform(1,0,0,1,0,0),e.clearRect(0,0,o,c),this.chromeDirty=!1,i&&(e.setTransform(o/this.canvas.width,0,0,c/this.canvas.height,0,0),this.chromeRenderer??=new Qo(e),this.chromeDirty=!0,t(this.chromeRenderer))}chromeDraw;repaintChrome(){this.chromeDraw&&this.overlayPainter&&this.paintChrome(this.chromeDraw)}scrubbingPointer;beginTouchScrub(t){if(t.pointerType!=="mouse"){this.scrubbingPointer=t.pointerId;try{this.seekInput.setPointerCapture(t.pointerId)}catch{}this.seekToPointer(t)}}touchScrub(t){t.pointerId===this.scrubbingPointer&&this.seekToPointer(t)}endTouchScrub(t){t.pointerId===this.scrubbingPointer&&(this.scrubbingPointer=void 0,this.seekToPointer(t))}seekToPointer(t){const e=this.seekInput.getBoundingClientRect(),i=this.player.seekableDuration;if(e.width<=0||i<=0)return;const n=Math.min(Math.max((t.clientX-e.left)/e.width,0),1);this.player.seek(this.snapSeekToMark(n*i))}seekSnapArmed=!1;static MARK_SNAP_PX=6;markNear(t){const e=this.player.seekableDuration,i=this.seekInput.getBoundingClientRect().width;if(e<=0||i<=0)return;const n=ye.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?Ku(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=us.windowEndingAt(t,this.currentSighting.exposure??0);if(e.ms<ye.SHORTEST_VISIBLE_EXPOSURE_MS)return[t];const i=Math.min(ye.MAX_EXPOSURE_STEPS,Math.max(2,Math.round(e.ms/ye.SHORTEST_VISIBLE_EXPOSURE_MS))),n=Math.ceil(this.travelPxOver(e.fromMs,e.ms)/ye.EXPOSURE_STEP_PX),s=Math.min(ye.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){if(!this.accountHidden)for(const n of this.exposureTimes()){const s=this.currentSighting.timeline.hitTest(n,t,e,i);if(s)return s}}shapesAt(t){const e=new Map;for(const i of this.currentSighting.timeline.sourceIds){const n=this.currentSighting.timeline.getInterpolatedShapeAt(t,i);n&&e.set(i,n)}return e}static SHORTEST_VISIBLE_EXPOSURE_MS=20;static MAX_EXPOSURE_STEPS=48;static EXPOSURE_STEP_PX=2;static MAX_TRAVEL_STEPS=320;applyFrameFormat(){const t=Pi.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:gx;this.canvasRenderer.setStarPoints(Pi.starPointsOf(this.sighting.instrument));const n=(si(this.sighting,t)?.rollDeg??0)+this.gaitAt(t).rollDeg;this.canvasRenderer.setRoll(n*Math.PI/180);const s=this.exposureInstants(t),a=this.frameShift;if(this.paintsShapes)for(const c of s)for(const[,l]of c.shapes){const h=c.share,u=h===1?l:{...l,transparency:1-(1-l.transparency)*h};this.canvasRenderer.paintShape(this.shifted(u,a))}for(const[c,l]of s[0].shapes)!this.selectionShown||!i.has(c)||(this.paintsShapes?i.size===1?this.canvasRenderer.paintShape({...l,selected:!0}):this.canvasRenderer.paintMemberOutline(l):this.canvasRenderer.paintSelectionOnly(this.shifted(l,a)));const o=this.selectionShown&&i.size>1?Fn.groupBoundsFor([...e].filter(([c])=>i.has(c)).map(([,c])=>c.bounds)):void 0;this.chromeDraw=c=>{o&&c.paintGroupHandles(o),this.overlayPainter?.(c)},this.paintChrome(this.chromeDraw),this.mapShapeBounds=s.flatMap(c=>[...c.shapes.values()].filter(l=>l.transparency<1).map(l=>this.shifted(l,a).bounds)),this.keepObserverMapClear(),this.seekInput.value=String(t),this.paintSeekProgress(t),this.minified&&this.paintMiniProgress(t),this.timeStartLabel.textContent=this.formatPosition(t),this.showMilestoneAt(t),this.paintObserverMap(t),this.playbackState==="playing"?(this.soundPreview=void 0,this.sightingAudio.setSound(Dy(this.currentSighting,t))):this.soundPreview?this.sightingAudio.setSound(this.soundPreview):this.sightingAudio.silence(),this.updatePlayPauseButton(),!this.quietFrame&&this.dispatchEvent(new CustomEvent("timeupdate",{detail:{time:t}}))}shifted(t,e){return e.x===0&&e.y===0?t:{...t,bounds:{...t.bounds,x:t.bounds.x+e.x,y:t.bounds.y+e.y}}}createPlayer(){const t=new Iy(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*ye.SEEK_KEY_STEP_MS)))}else t.key===" "&&(t.preventDefault(),this.togglePlayPause())};togglePlayPause(){if(!(this.player.seekableDuration<=0)){if(this.player.playbackState==="playing")this.player.pause(),this.soundPreview=void 0,this.sightingAudio.silence(),this.refresh();else if(this.clockHeld){this.playAfterHold=!this.playAfterHold,this.playAfterHold&&this.announcePlayRequest();return}else this.announcePlayRequest(),this.sightingAudio.resume(),this.player.play();this.updatePlayPauseButton(),this.flashPlayback()}}flashPlayback(){const t=this.playbackFlash;t.innerHTML=this.player.playbackState==="playing"?Xt.PLAY:Xt.PAUSE,t.classList.remove("flashing"),t.offsetWidth,t.classList.add("flashing")}static icons=new WeakMap;static setIcon(t,e){ye.icons.get(t)!==e&&(ye.icons.set(t,e),t.innerHTML=e)}set captionHeld(t){this.stageElement.classList.toggle("caption-held",t)}set controlsHeld(t){this.stageElement.classList.toggle("controls-held",t)}static CONTROLS_IDLE_MS=3e3;controlsIdleTimer;wasPlaying=!1;quietControlsValue=!1;get quietControls(){return this.quietControlsValue}set quietControls(t){this.quietControlsValue=t,this.stageElement.classList.toggle("quiet",t)}tapRevealedOnly=!1;get hoverless(){return typeof matchMedia=="function"&&matchMedia("(hover: none)").matches}touchedStage(){if(!this.hoverless)return;this.player.playbackState==="playing"&&!this.stageElement.classList.contains("touched")&&(this.tapRevealedOnly=!0),this.revealControls()}pointerHeld=!1;handlePointerDown=()=>{this.pointerHeld=!0};resumeAfterScrub=!1;suspendForScrub(){this.player.playbackState==="playing"&&(this.resumeAfterScrub=!0,this.stopPlaying())}stopPlaying(){this.player.pause(),this.soundPreview=void 0,this.sightingAudio.silence(),this.refresh(),this.updatePlayPauseButton()}resumeFromScrub(){this.resumeAfterScrub&&(this.resumeAfterScrub=!1,this.sightingAudio.resume(),this.player.play(),this.updatePlayPauseButton())}handleHidden=()=>{this.player.playbackState==="playing"&&this.stopPlaying(),this.resumeAfterScrub=!1};handleVisibility=()=>{document.visibilityState==="hidden"&&this.handleHidden()};handlePointerRelease=()=>{this.resumeAfterScrub&&window.setTimeout(()=>this.resumeFromScrub(),0),this.pointerHeld&&(this.pointerHeld=!1,this.hoverless&&this.stageElement.classList.contains("touched")&&this.revealControls())};revealControls(){this.stageElement.classList.add("touched"),window.clearTimeout(this.controlsIdleTimer),this.player.playbackState==="playing"&&(this.pointerHeld||!this.momentsMenu.hidden||(this.controlsIdleTimer=window.setTimeout(()=>{this.stageElement.classList.remove("touched"),this.tapRevealedOnly=!1},ye.CONTROLS_IDLE_MS)))}updatePlayPauseButton(){const t=this.player.playbackState==="playing";this.stageElement.classList.toggle("paused",!t),t!==this.wasPlaying&&t&&this.hoverless&&(!this.quietControlsValue||this.stageElement.classList.contains("touched"))&&this.revealControls(),this.wasPlaying=t,this.updateStartState(),ye.setIcon(this.playPauseButton,t?Xt.PAUSE:Xt.PLAY);const e=this.player.seekableDuration>0;this.playPauseButton.disabled=!e;const i=e?t?this.messages.pause:this.messages.play:this.messages.noDuration;this.playPauseButton.title=i,this.playPauseButton.setAttribute("aria-label",i)}toggleLoop(){this.loopEnabled=!this.loopEnabled,this.player.loop=this.loopEnabled}restorePlayback(){const t=this.playbackBeforeClick;t&&(this.currentTime=t.time,t.state==="playing"?this.play():this.pause())}get canUseNativeFullscreen(){return typeof this.fullscreenTarget.requestFullscreen=="function"&&document.fullscreenEnabled}toggleFullscreen(){if(!this.canUseNativeFullscreen){this.simulatedFullscreen?this.exitSimulatedFullscreen():this.enterSimulatedFullscreen();return}document.fullscreenElement?document.exitFullscreen():this.fullscreenTarget.requestFullscreen().catch(t=>{console.error("<rr0-ufo>: requestFullscreen() failed —",t)})}enterSimulatedFullscreen(){const t=this.fullscreenTarget;this.styleBeforeSimulatedFullscreen=t.getAttribute("style")??"",this.bodyOverflowBeforeSimulatedFullscreen=document.body.style.overflow;const e=t.style;e.setProperty("position","fixed"),e.setProperty("inset","0"),e.setProperty("margin","0"),e.setProperty("max-width","none"),e.setProperty("max-height","none"),e.setProperty("aspect-ratio","auto"),e.setProperty("z-index","2147483647"),e.setProperty("background","#000"),e.setProperty("width","100vw"),e.setProperty("width","100dvw"),e.setProperty("height","100vh"),e.setProperty("height","100dvh"),document.body.style.overflow="hidden",this.simulatedFullscreen=!0,document.addEventListener("keydown",this.handleSimulatedFullscreenKey),this.updateFullscreenButton(),this.updateMuteButton()}exitSimulatedFullscreen(){if(!this.simulatedFullscreen)return;const t=this.fullscreenTarget;this.styleBeforeSimulatedFullscreen?t.setAttribute("style",this.styleBeforeSimulatedFullscreen):t.removeAttribute("style"),document.body.style.overflow=this.bodyOverflowBeforeSimulatedFullscreen??"",this.simulatedFullscreen=!1,document.removeEventListener("keydown",this.handleSimulatedFullscreenKey),this.updateFullscreenButton(),this.updateMuteButton()}toggleObserverMap(){const t=this.observerMapPanel.hidden;this.observerMapAsked=t,this.setObserverMapOpen(t),this.keepObserverMapClear(),this.dispatchEvent(new CustomEvent("observermapchange",{bubbles:!0,composed:!0,detail:{open:t}}))}get observerMapOpen(){return!this.observerMapPanel.hidden}get milestonesVisible(){return this.milestonesShown}observerMapAsked=!1;applyObserverMapDefault(){const t=this.getAttribute(Ho),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;ye.setIcon(this.observerMapButton,t?Xt.MAP_ON:Xt.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=ko.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=ci.including(this.observerPath.boundsAround(ye.OBSERVER_MAP_MIN_SPAN_M,ye.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?ci.expand(t,ye.OBSERVER_MAP_IMAGERY_AHEAD):t,n=ye.OBSERVER_MAP_IMAGERY_PX*(e?1+2*ye.OBSERVER_MAP_IMAGERY_AHEAD:1);this.observerMapImageryBounds=i,this.observerMapImageryViewWidth=t.east-t.west,this.observerMapImageryLoading=!0;const s=Zv();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?ci.expand(t,ye.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=ye.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=si(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},ye.OBSERVER_MAP_FOLLOW_MARGIN)&&this.scheduleObserverMapImagery();const i=this.currentSighting.instrument,n=[],s=this.currentSighting.milestones.length>0?Ku(this.currentSighting.milestones,t):void 0;for(const a of this.milestonesShown?Wc(this.currentSighting.milestones):[]){const o=si(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?da.of(i,this.canvas.height,e.fovDeg).halfWidthAngleDeg(Pi.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,Wc(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,ye.setIcon(this.milestonesButton,this.milestonesShown?Xt.MILESTONES_ON:Xt.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=si(this.currentSighting,0);return e?.lat===void 0||e.lng===void 0?[]:this.currentSighting.decor.filter(i=>i.kind!=="crop").map(i=>{const n=ua(i,t),{lat:s,lng:a}=Bn(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=si(this.currentSighting,this.currentTime),s=da.of(this.currentSighting.instrument,this.canvas.height,n?.fovDeg??60);return{x:-s.angleDegToRadiusPx(e),y:s.angleDegToRadiusPx(i)}}gaitAt(t){return ze.bodyAt(this.currentSighting,t,this.steadyBody)}mutedState=!1;get muted(){return this.mutedState}set muted(t){t!==this.mutedState&&(this.mutedState=t,!t&&this.volumeState===0&&(this.volumeState=ye.RESTORED_VOLUME),this.applyLevel())}volumeState=1;static RESTORED_VOLUME=.5;get volume(){return this.volumeState}set volume(t){this.setVolume(t)}setVolume(t){this.volumeState=Math.min(Math.max(t,0),1),this.mutedState=this.volumeState===0,this.applyLevel()}get level(){return this.mutedState?0:this.volumeState}applyLevel(){this.sightingAudio.setLevel(this.level),this.updateMuteButton(),this.dispatchEvent(new CustomEvent("mutedchange",{bubbles:!0,composed:!0,detail:{muted:this.mutedState,volume:this.volumeState}}))}toggleMuted(){this.hasSound&&(this.muted=!this.mutedState)}ambientSound;get hasSound(){return this.currentSighting.soundTrack.allKeyframes.length>0||this.ambientSound?.(this.currentSighting)===!0}updateMuteButton(){const t=!this.hasSound;this.miniMuteButton.hidden=t,this.miniMuteButton.setAttribute("aria-pressed",String(this.mutedState)),ye.setIcon(this.miniMuteButton,this.mutedState?Xt.MUTED:Xt.VOLUME);const e=this.mutedState?this.messages.unmute:this.messages.mute;if(this.miniMuteButton.title=e,this.miniMuteButton.setAttribute("aria-label",e),this.muteButton.disabled=t,this.volumeInput.hidden=t,t){ye.setIcon(this.muteButton,Xt.MUTED),this.muteButton.title=this.messages.noSound,this.muteButton.setAttribute("aria-label",this.messages.noSound),this.muteButton.setAttribute("aria-pressed","true");return}ye.setIcon(this.muteButton,this.mutedState?Xt.MUTED:Xt.VOLUME);const i=this.mutedState?this.messages.unmute:this.messages.mute;this.muteButton.title=i,this.muteButton.setAttribute("aria-label",i),this.muteButton.setAttribute("aria-pressed",String(this.mutedState)),this.volumeInput.value=String(this.level)}updateFullscreenButton(){const t=this.simulatedFullscreen||document.fullscreenElement===this.fullscreenTarget;ye.setIcon(this.fullscreenButton,t?Xt.EXIT_FULLSCREEN:Xt.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 ca(zo.preferencesFor(this))}saidTexts;async loadLocaleMessages(){const t=zv(zo.preferencesFor(this),Hv);if(t===this.messagesLanguage||t==="en"&&this.messagesLanguage===void 0)return;this.messagesLanguage=t;const e=await Vy(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=Ay(t);this.realDurationMs=e!==void 0&&e>0?e:void 0,this.realStartMs=t.time?b0(t.time):void 0;const i=this.currentSighting.timeline.duration;this.player.playbackRate=this.realDurationMs!==void 0&&i>0?i/this.realDurationMs:1,this.player.durationOverrideMs=i>0?0:this.realDurationMs??0,this.timeEndLabel.textContent=this.formatEndOfTimeline(),this.timeStartLabel.textContent=this.formatPosition(this.player.time),this.paintMiniProgress(this.player.time),this.updateTimeLabelTitles()}formatPosition(t){if(this.realDurationMs===void 0)return Xr(t);const e=this.currentSighting.timeline.duration,i=e>0&&t<=e?t/e*this.realDurationMs:t;return this.canShowClockTime?Pm(Cm(this.realStartMs+i)):Xr(i)}formatRemaining(t){const e=this.currentSighting.timeline.duration;if(this.realDurationMs===void 0)return Xr(Math.max(0,e-t));const i=e>0&&t<=e?t/e*this.realDurationMs:t;return Xr(Math.max(0,this.realDurationMs-i))}formatEndOfTimeline(){return this.realDurationMs===void 0?Xr(this.currentSighting.timeline.duration):this.canShowClockTime?Pm(Cm(this.realStartMs+this.realDurationMs)):Xr(this.realDurationMs)}}function Cm(r){const t=new Date(r);return{hour:t.getUTCHours(),minute:t.getUTCMinutes(),second:t.getUTCSeconds()}}function Pm(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 Xr(r){const t=Math.round(r/1e3),e=Math.floor(t/60),i=t%60;return`${e}:${String(i).padStart(2,"0")}`}const E0="rr0-ufo";function Jv(){customElements.get(E0)||customElements.define(E0,ye)}const vx="recordingissues",jv="minifiedreset";/**
1649
+ `);let e=Eo.shared.get(t);return e||(e=this.fetchFirstAvailable(),Eo.shared.set(t,e),e.then(i=>{i.length===0&&Eo.shared.delete(t)})),this.index=e}async fetchFirstAvailable(){for(const t of this.indexUrls)try{const e=await this.fetchImpl(t);if(!e.ok)continue;const i=await e.json();if(Array.isArray(i?.entries))return i.entries.map(n=>({entry:n,indexUrl:t}))}catch{}return[]}static defaultIndexUrls(){const t=`?v=${encodeURIComponent("0.127.2")}`,e=typeof location>"u"?void 0:new URL("/roads/index.json",location.href).href;return(e&&e!==Zu?[e,Zu]:[Zu]).map(i=>i+t)}}class Ga{attribution="Roads © IGN, BD TOPO (Licence Ouverte 2.0), as drawn today";contemporary=!0;static BY_NATURE={"Type autoroutier":{surface:"paved",widthM:11},"Route à 2 chaussées":{surface:"paved",widthM:7},"Route à 1 chaussée":{surface:"paved",widthM:5.5},"Rond-point":{surface:"paved",widthM:6},Bretelle:{surface:"paved",widthM:5},"Route empierrée":{surface:"gravel",widthM:3.5},Chemin:{surface:"dirt",widthM:3},"Piste cyclable":{surface:"paved",widthM:2.5}};static DEFAULT={surface:"paved",widthM:5};static KINDS={"Type autoroutier":"motorway","Route à 2 chaussées":"dual","Route à 1 chaussée":"road","Rond-point":"roundabout",Bretelle:"slip"};static DIRECTIONS={"Double sens":"both","Sens direct":"forward","Sens inverse":"backward"};platform;constructor(t={}){this.platform=new be(t)}static covers(t){return be.covers((t.south+t.north)/2,(t.west+t.east)/2)}async getRoads(t){return(await this.platform.roads(t)).flatMap((i,n)=>Ga.wayOf(i,n))}static wayOf(t,e){if(t.geometry.type!=="LineString")return[];const i=t.geometry.coordinates.map(([d,f])=>({lat:f,lng:d}));if(i.length<2)return[];const n=String(t.properties.nature??""),s=Ga.BY_NATURE[n]??Ga.DEFAULT,a=Number(t.properties.largeur_de_chaussee),o=Number(t.properties.nombre_de_voies),c=Number(t.properties.vitesse_moyenne_vl),l=Ga.DIRECTIONS[String(t.properties.sens_de_circulation??"")],h=Ga.KINDS[n],u=[t.properties.cpx_toponyme_route_nommee,t.properties.nom_voie_ban_gauche,t.properties.nom_voie_ban_droite].find(d=>typeof d=="string"&&d.length>0);return[{id:String(t.properties.cleabs??`ign-${e}`),...u?{name:u}:{},surface:s.surface,widthM:Number.isFinite(a)&&a>0?a:s.widthM,...t.properties.urbain===!0?{urban:!0}:{},...h?{kind:h}:{},...Number.isInteger(o)&&o>0?{lanes:o}:{},...l?{direction:l}:{},...Number.isFinite(c)&&c>0?{speedKmh:c}:{},points:i}]}}class cx{constructor(t,e){this.regional=t,this.worldwide=e}attribution="Roads © IGN, BD TOPO, in France; © OpenStreetMap contributors elsewhere, as drawn today";contemporary=!0;async getRoads(t){if(Ga.covers(t))try{const e=await this.regional.getRoads(t);if(e.length>0)return e}catch{}return this.worldwide.getRoads(t)}}class hl{attribution="Water © IGN, BD TOPO (Licence Ouverte 2.0)";platform;constructor(t={}){this.platform=new be(t)}static covers(t){return be.covers((t.south+t.north)/2,(t.west+t.east)/2)}async getWater(t){return(await this.platform.waterSurfaces(t)).flatMap((i,n)=>hl.surfacesOf(i,n))}static surfacesOf(t,e){const{type:i,coordinates:n}=t.geometry,s=i==="Polygon"?[n]:i==="MultiPolygon"?n:[],a=String(t.properties.cleabs??`ign-water-${e}`);return s.flatMap((o,c)=>{const l=o.map(h=>hl.open(h.map(u=>({lat:u[1],lng:u[0]})))).filter(h=>h.length>=3);return l.length>0?[{id:s.length>1?`${a}-${c}`:a,rings:l}]:[]})}static open(t){const e=t[0],i=t[t.length-1];return t.length>1&&e.lat===i.lat&&e.lng===i.lng?t.slice(0,-1):t}}class fr{attribution="Water © OpenStreetMap contributors";client;constructor(t={}){this.client=new Un(t)}async getWater(t){const e=`${t.south},${t.west},${t.north},${t.east}`,i=`[out:json][timeout:30];(way["natural"="water"](${e});way["waterway"="riverbank"](${e});)->.w;(relation["natural"="water"](${e});relation["waterway"="riverbank"](${e});)->.r;.w out geom;.r out body;way(r.r)(${e});out geom;`;return fr.surfacesFrom(await this.client.query(i))}static surfacesFrom(t){const e=t.elements??[],i=new Map;for(const a of e)a.type==="way"&&a.id!==void 0&&a.geometry&&i.set(a.id,a.geometry.map(o=>({lat:o.lat,lng:o.lon})));const n=[],s=new Set;for(const a of e){if(a.type!=="relation")continue;const o=l=>(a.members??[]).filter(h=>h.type==="way"&&h.role===l&&h.ref!==void 0&&i.has(h.ref)).map(h=>(s.add(h.ref),i.get(h.ref))),c=fr.rings(o("inner"));for(const[l,h]of fr.rings(o("outer")).entries()){const u=c.filter(d=>fr.contains(h,d[0]));n.push({id:`osm-r${a.id}-${l}`,rings:[h,...u]})}}for(const a of e)if(!(a.type!=="way"||!a.tags||a.id===void 0||s.has(a.id))&&!(a.tags.natural!=="water"&&a.tags.waterway!=="riverbank"))for(const o of fr.rings([i.get(a.id)??[]]))n.push({id:`osm-w${a.id}`,rings:[o]});return n}static rings(t){const e=(s,a)=>s.lat===a.lat&&s.lng===a.lng,i=t.filter(s=>s.length>=2).map(s=>[...s]),n=[];for(;i.length>0;){let s=i.pop(),a=!0;for(;!e(s[0],s[s.length-1])&&a;){a=!1;for(let o=0;o<i.length;o++){const c=i[o],l=s[s.length-1];if(e(l,c[0]))s=[...s,...c.slice(1)];else if(e(l,c[c.length-1]))s=[...s,...[...c].reverse().slice(1)];else continue;i.splice(o,1),a=!0;break}}s.length>=4&&e(s[0],s[s.length-1])&&n.push(s.slice(0,-1))}return n}static contains(t,e){let i=!1;for(let n=0,s=t.length-1;n<t.length;s=n++){const a=t[n],o=t[s];a.lat>e.lat!=o.lat>e.lat&&e.lng<(o.lng-a.lng)*(e.lat-a.lat)/(o.lat-a.lat)+a.lng&&(i=!i)}return i}}class lx{constructor(t,e){this.regional=t,this.worldwide=e}attribution="Water © IGN, BD TOPO, in France; © OpenStreetMap contributors elsewhere";async getWater(t){if(hl.covers(t))try{const e=await this.regional.getWater(t);if(e.length>0)return e}catch{}return this.worldwide.getWater(t)}}const Ju="https://ufoathome.org/water/index.json";class Ao{attributionRead;fetchImpl;indexUrls;fallback;index;static shared=new Map;sharing;constructor(t={}){this.sharing=!t.fetchImpl,this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.indexUrls=t.indexUrls??Ao.defaultIndexUrls(),this.fallback=t.fallback}get attribution(){return this.attributionRead??this.fallback?.attribution??"Water © OpenStreetMap contributors"}async getWater(t){const e=await this.held(t);if(e)return e;if(!this.fallback)return[];const i=await this.fallback.getWater(t);return this.attributionRead=this.fallback.attribution,i}async held(t){const i=(await this.load().catch(()=>[])).find(({entry:n})=>n.north>=t.north&&n.south<=t.south&&n.east>=t.east&&n.west<=t.west);if(i)try{const n=await this.fetchImpl(new URL(i.entry.file,i.indexUrl).href);if(!n.ok)return;const s=await n.json();return Array.isArray(s?.surfaces)?(this.attributionRead=s.attribution,s.surfaces):void 0}catch{return}}load(){if(this.index)return this.index;if(!this.sharing)return this.index=this.fetchFirstAvailable();const t=this.indexUrls.join(`
1650
+ `);let e=Ao.shared.get(t);return e||(e=this.fetchFirstAvailable(),Ao.shared.set(t,e),e.then(i=>{i.length===0&&Ao.shared.delete(t)})),this.index=e}async fetchFirstAvailable(){for(const t of this.indexUrls)try{const e=await this.fetchImpl(t);if(!e.ok)continue;const i=await e.json();if(Array.isArray(i?.entries))return i.entries.map(n=>({entry:n,indexUrl:t}))}catch{}return[]}static defaultIndexUrls(){const t=`?v=${encodeURIComponent("0.127.2")}`,e=typeof location>"u"?void 0:new URL("/water/index.json",location.href).href;return(e&&e!==Ju?[e,Ju]:[Ju]).map(i=>i+t)}}class Sn{constructor(t){this.water=t}static CACHE_NAME="rr0-water";static MAX_AGE_MS=720*3600*1e3;static FORMAT=1;static MAX_STORED=400;static asked=new Map;get attribution(){return this.water.attribution}async getWater(t){const e=Sn.key(t);let i=Sn.asked.get(e);return i===void 0&&(i=this.recalled(e,t),Sn.asked.set(e,i),i.catch(()=>Sn.asked.delete(e))),structuredClone(await i)}static forget(){Sn.asked.clear()}static key(t){return`v${Sn.FORMAT}/${[t.north,t.south,t.east,t.west].map(e=>e.toFixed(5)).join("/")}`}async recalled(t,e){const i=await Sn.openCache(),n=Sn.request(t);if(i)try{const a=await i.match(n);if(a){const{savedAt:o,surfaces:c}=await a.json();if(Date.now()-o<Sn.MAX_AGE_MS&&Array.isArray(c))return c;await i.delete(n)}}catch{}const s=await this.water.getWater(e);return i&&Sn.store(i,n,s),s}static async store(t,e,i){try{const n={savedAt:Date.now(),surfaces:i};await t.put(e,new Response(JSON.stringify(n),{headers:{"Content-Type":"application/json"}}));const s=await t.keys();for(const a of s.slice(0,Math.max(0,s.length-Sn.MAX_STORED)))await t.delete(a)}catch{}}static async openCache(){try{return typeof caches>"u"?void 0:await caches.open(Sn.CACHE_NAME)}catch{return}}static request(t){const e=typeof location>"u"?"http://localhost":location.origin;return new Request(`${e}/__water__/${encodeURIComponent(t)}`)}}class Va{attribution="Railways © IGN, BD TOPO (Licence Ouverte 2.0), as drawn today";contemporary=!0;static BY_NATURE={"Voie ferrée principale":{kind:"rail"},LGV:{kind:"rail",highSpeed:!0},"Voie de service":{kind:"rail",service:!0},Métro:{kind:"subway"},Tramway:{kind:"tram"},"Transport urbain":{kind:"light_rail"},"Funiculaire ou crémaillère":{kind:"funicular"}};static GAUGE_MM={Normale:1435,Etroite:1e3,Étroite:1e3,Large:1668};static NO_ALTITUDE=-1e3;platform;constructor(t={}){this.platform=new be(t)}static covers(t){return be.covers((t.south+t.north)/2,(t.west+t.east)/2)}async getRailways(t){return(await this.platform.railways(t)).flatMap((i,n)=>Va.linesOf(i,n))}static linesOf(t,e){const{type:i,coordinates:n}=t.geometry,s=i==="LineString"?[n]:i==="MultiLineString"?n:[],a=Va.BY_NATURE[String(t.properties.nature??"")];if(!a)return[];const o=String(t.properties.cleabs??`ign-rail-${e}`),c=Number(t.properties.nombre_de_voies),l=Number(t.properties.position_par_rapport_au_sol),h=t.properties.cpx_toponyme,u=Va.GAUGE_MM[String(t.properties.largeur??"")]??1435,d=Va.electrificationOf(a.kind,u,t.properties.electrifie);return s.flatMap((f,p)=>{const v=f.map(m=>({lat:m[1],lng:m[0],...m.length>2&&Number.isFinite(m[2])&&m[2]>Va.NO_ALTITUDE?{altitudeM:m[2]}:{}}));return v.length<2?[]:[{id:s.length>1?`${o}-${p}`:o,...typeof h=="string"&&h.length>0?{name:h}:{},kind:a.kind,...a.service?{service:!0}:{},...a.highSpeed?{highSpeed:!0}:{},gaugeMm:u,tracks:Number.isInteger(c)&&c>0?c:1,...d?{electrification:d}:{},level:Number.isFinite(l)?l:0,points:v}]})}static electrificationOf(t,e,i){if(i===!1)return"none";if(i===!0){if(t==="subway")return"third_rail";if(!(t==="funicular"||e<1435))return"overhead"}}}class To{attribution="Railways © OpenStreetMap contributors, as surveyed today";contemporary=!0;static KINDS=["rail","light_rail","tram","subway","narrow_gauge","funicular","preserved"];client;constructor(t={}){this.client=new Un(t)}async getRailways(t){const e=`${t.south},${t.west},${t.north},${t.east}`,i=`[out:json][timeout:25];way["railway"~"^(${To.KINDS.join("|")})$"](${e});out tags geom;`;return this.linesFrom(await this.client.query(i))}linesFrom(t){const e=[];for(const i of t.elements??[]){const n=i.geometry,s=i.tags;if(!s||!n||n.length<2)continue;const a=To.kindOf(s),o=Number.parseInt((s.gauge??"").split(";")[0],10),c=Number.parseInt(s.tracks??"",10),l=To.electrificationOf(s.electrified),h=s.highspeed==="yes"||Number.parseInt(s.maxspeed??"",10)>=250;e.push({id:`osm-rail-${i.id??e.length}`,...s.name?{name:s.name}:{},kind:a,...s.service||s.usage==="industrial"?{service:!0}:{},...h?{highSpeed:!0}:{},gaugeMm:Number.isFinite(o)&&o>300?o:s.railway==="narrow_gauge"?1e3:1435,tracks:Number.isFinite(c)&&c>0?c:1,...l?{electrification:l}:{},level:To.levelOf(s),points:n.map(u=>({lat:u.lat,lng:u.lon}))})}return e}static kindOf(t){switch(t.railway){case"tram":return"tram";case"subway":return"subway";case"light_rail":return"light_rail";case"funicular":return"funicular";default:return"rail"}}static electrificationOf(t){if(t!==void 0){if(t==="no")return"none";if(t==="contact_line"||t==="yes")return"overhead";if(t==="rail"||t==="4th_rail"||t==="ground-level_power_supply")return"third_rail"}}static levelOf(t){const e=Number.parseInt(t.layer??"",10);return t.tunnel&&t.tunnel!=="no"?Number.isFinite(e)&&e<0?e:-1:t.covered==="yes"&&t.location==="underground"?-1:t.bridge&&t.bridge!=="no"?Number.isFinite(e)&&e>0?e:1:0}}class hx{constructor(t,e){this.regional=t,this.worldwide=e}attribution="Railways © IGN, BD TOPO, in France; © OpenStreetMap contributors elsewhere, as drawn today";contemporary=!0;async getRailways(t){if(!Va.covers(t))return this.worldwide.getRailways(t);let e;try{if(e=await this.regional.getRailways(t),e.length>0)return e}catch{}try{return await this.worldwide.getRailways(t)}catch(i){if(e)return e;throw i}}}class Ii{constructor(t,e=Date.now){this.railways=t,this.now=e}static CACHE_NAME="rr0-railways";static MAX_AGE_MS=720*3600*1e3;static FORMAT=1;static MAX_STORED=400;static RETRY_AFTER_MS=300*1e3;static asked=new Map;static failedAt=-1/0;get attribution(){return this.railways.attribution}get contemporary(){return this.railways.contemporary}async getRailways(t){const e=Ii.key(t);let i=Ii.asked.get(e)??Ii.containing(t);if(i===void 0){const n=this.recalled(e,t);i={bounds:t,answer:n},Ii.asked.set(e,i),n.catch(()=>Ii.asked.delete(e))}return structuredClone(await i.answer)}static forget(){Ii.asked.clear(),Ii.failedAt=-1/0}static key(t){return`v${Ii.FORMAT}/${[t.north,t.south,t.east,t.west].map(e=>e.toFixed(5)).join("/")}`}static containing(t){for(const e of Ii.asked.values()){const i=e.bounds;if(i.north>=t.north&&i.south<=t.south&&i.east>=t.east&&i.west<=t.west)return e}}async recalled(t,e){const i=await Ii.openCache(),n=Ii.request(t);let s;if(i)try{const o=await i.match(n);if(o){const{savedAt:c,lines:l}=await o.json();if(Array.isArray(l)){if(this.now()-c<Ii.MAX_AGE_MS)return l;s=l}}}catch{}if(this.now()-Ii.failedAt<Ii.RETRY_AFTER_MS){if(s)return s;throw new Error("The railway survey failed a moment ago: not asked again yet")}let a;try{a=await this.railways.getRailways(e)}catch(o){if(Ii.failedAt=this.now(),s)return s;throw o}return i&&Ii.store(i,n,{savedAt:this.now(),lines:a}),a}static async store(t,e,i){try{await t.delete(e),await t.put(e,new Response(JSON.stringify(i),{headers:{"Content-Type":"application/json"}}));const n=await t.keys();for(const s of n.slice(0,Math.max(0,n.length-Ii.MAX_STORED)))await t.delete(s)}catch{}}static async openCache(){try{return typeof caches>"u"?void 0:await caches.open(Ii.CACHE_NAME)}catch{return}}static request(t){const e=typeof location>"u"?"http://localhost":location.origin;return new Request(`${e}/__railways__/${encodeURIComponent(t)}`)}}const ju="https://ufoathome.org/railways/index.json";class Ro{contemporary=!0;attributionRead;fetchImpl;indexUrls;fallback;index;static shared=new Map;sharing;constructor(t={}){this.sharing=!t.fetchImpl,this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.indexUrls=t.indexUrls??Ro.defaultIndexUrls(),this.fallback=t.fallback}get attribution(){return this.attributionRead??this.fallback?.attribution??"Railways © OpenStreetMap contributors"}async getRailways(t){const e=await this.held(t);if(e)return e;if(!this.fallback)return[];const i=await this.fallback.getRailways(t);return this.attributionRead=this.fallback.attribution,i}async held(t){const i=(await this.load().catch(()=>[])).find(({entry:n})=>n.north>=t.north&&n.south<=t.south&&n.east>=t.east&&n.west<=t.west);if(i)try{const n=await this.fetchImpl(new URL(i.entry.file,i.indexUrl).href);if(!n.ok)return;const s=await n.json();return Array.isArray(s?.lines)?(this.attributionRead=s.attribution,s.lines):void 0}catch{return}}load(){if(this.index)return this.index;if(!this.sharing)return this.index=this.fetchFirstAvailable();const t=this.indexUrls.join(`
1651
+ `);let e=Ro.shared.get(t);return e||(e=this.fetchFirstAvailable(),Ro.shared.set(t,e),e.then(i=>{i.length===0&&Ro.shared.delete(t)})),this.index=e}async fetchFirstAvailable(){for(const t of this.indexUrls)try{const e=await this.fetchImpl(t);if(!e.ok)continue;const i=await e.json();if(Array.isArray(i?.entries))return i.entries.map(n=>({entry:n,indexUrl:t}))}catch{}return[]}static defaultIndexUrls(){const t=`?v=${encodeURIComponent("0.127.2")}`,e=typeof location>"u"?void 0:new URL("/railways/index.json",location.href).href;return(e&&e!==ju?[e,ju]:[ju]).map(i=>i+t)}}function ux(){return{elevation:dx(),imagery:Zv(),roads:fx(),water:px(),railways:mx()}}function dx(){return new nx(new Me,new ex)}function Zv(){return new ox}function fx(){return new Eo({fallback:new cx(new Ga,new ka)})}function px(){return new Ao({fallback:new Sn(new lx(new hl,new fr))})}function mx(){return new Ro({fallback:new Ii(new hx(new Va,new To))})}const gx=new Set,Ho="show-observer-map",Bo="hide-milestones",Mr="minified";class ye extends HTMLElement{static get observedAttributes(){return["src",Ho,Bo,Mr]}shadow;stageElement;canvas;canvasRenderer;chromeCanvas;chromeRenderer;chromeResizeObserver=typeof ResizeObserver>"u"?void 0:new ResizeObserver(()=>{this.chromeDirty&&this.refresh()});chromeDirty=!1;tooltip;toolbar;issuesBox;issuesButton;issuesPanel;playPauseButton;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;accountHidden=!1;referenceViews=new Map;referencesMenu;referenceOpacityTouched=!1;milestonesButton;observerMapPanel;observerMapCanvas;observerMapRenderer;mapZoomInButton;mapZoomOutButton;mapFitButton;observerMapView=new ci;observerMapDrag;suppressObserverMapClick=!1;observerMapImageryTimer;observerPlacing=!1;seekInput;playbackFlash;milestoneMarks;milestoneCaption;timeStartLabel;timeEndLabel;timePill;muteButton;volumeInput;controlsRow;momentsBox;momentsButton;momentsCurrent;momentsMenu;moreButton;controlsRight;seekSegments;seekDot;playerTitleBox;seekPreview;seekPreviewCanvas;seekPreviewTitle;seekPreviewTime;observerPath;observerMapBounds;observerMapImagery;observerMapImageryBounds;observerMapImageryViewWidth=0;observerMapImageryLoading=!1;observerMapImageryCredit;observerMapImageryFailed=!1;creditShownExternally=!1;lookYawDeg=0;lookPitchDeg=0;milestonesShown=!0;currentSighting=Iu.create();issues=[];issueCheck=0;sightingAudio=new Fy;soundPreview;player;loopEnabled=!1;playbackBeforeClick;highlightedSourceIds=new Set;paintsShapes=!0;steadyObserver=!1;static LIVE_BODY_MAX_RATE=2;get steadyBody(){return this.steadyObserver||this.player.playbackState!=="playing"||this.player.playbackRate>ye.LIVE_BODY_MAX_RATE}selectionShown=!0;overlayPainter;enableClickToPlay=!0;fullscreenTarget;messages=Bv;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");ye.setIcon(this.moreButton,t?Xt.UNFOLDED:Xt.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)<ye.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>=ci.MAX_ZOOM,this.mapZoomOutButton.disabled=this.observerMapView.zoomFactor<=ci.MIN_ZOOM,this.paintObserverMap(this.currentTime),this.scheduleObserverMapImagery()}scheduleObserverMapImagery(){this.observerMapImageryTimer===void 0&&(this.observerMapImageryTimer=setTimeout(()=>{this.observerMapImageryTimer=void 0,this.loadObserverMapImagery()},ye.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=ci.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>${ly}</style>${cy}`,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.chromeCanvas=this.shadow.getElementById("chrome"),this.tooltip=this.shadow.getElementById("tooltip"),this.toolbar=this.shadow.getElementById("toolbar"),this.issuesBox=this.shadow.getElementById("issues"),this.issuesButton=this.shadow.getElementById("issues-button"),this.issuesPanel=this.shadow.getElementById("issues-panel"),this.issuesButton.addEventListener("click",i=>{i.stopPropagation(),this.issuesPanel.hidden=!this.issuesPanel.hidden,this.issuesButton.setAttribute("aria-expanded",String(!this.issuesPanel.hidden))}),this.playPauseButton=this.shadow.getElementById("play-pause"),this.fullscreenButton=this.shadow.getElementById("fullscreen"),this.cornerButtons=this.shadow.getElementById("corner-buttons"),this.observerMapButton=this.shadow.getElementById("observer-map"),this.referencesButton=this.shadow.getElementById("references"),this.tracesButton=this.shadow.getElementById("traces"),this.referenceOpacityInput=this.shadow.getElementById("reference-opacity"),this.referencesMenu=this.shadow.getElementById("references-menu"),this.milestonesButton=this.shadow.getElementById("milestones"),this.observerMapPanel=this.shadow.getElementById("observer-map-panel"),this.observerMapCanvas=this.shadow.getElementById("observer-map-canvas"),this.observerMapRenderer=new dr(this.observerMapCanvas.getContext("2d")),this.mapZoomInButton=this.shadow.getElementById("map-zoom-in"),this.mapZoomOutButton=this.shadow.getElementById("map-zoom-out"),this.mapFitButton=this.shadow.getElementById("map-fit"),this.seekInput=this.shadow.getElementById("seek"),this.playbackFlash=this.shadow.getElementById("playback-flash"),this.milestoneMarks=this.shadow.getElementById("milestone-marks"),this.milestoneCaption=this.shadow.getElementById("milestone-caption"),this.timeStartLabel=this.shadow.getElementById("time-start"),this.timeEndLabel=this.shadow.getElementById("time-end"),this.timePill=this.shadow.getElementById("time"),this.muteButton=this.shadow.getElementById("mute"),this.controlsRight=this.shadow.getElementById("controls-right"),this.seekSegments=this.shadow.getElementById("seek-segments"),this.seekDot=this.shadow.getElementById("seek-dot"),this.playerTitleBox=this.shadow.getElementById("player-title"),this.seekPreview=this.shadow.getElementById("seek-preview"),this.seekPreviewCanvas=this.shadow.getElementById("seek-preview-canvas"),this.seekPreviewTitle=this.shadow.getElementById("seek-preview-title"),this.seekPreviewTime=this.shadow.getElementById("seek-preview-time"),this.timePill.addEventListener("click",()=>this.toggleTimeDisplay()),this.timePill.addEventListener("keydown",i=>{i.key!=="Enter"&&i.key!==" "||(i.preventDefault(),this.toggleTimeDisplay())}),this.volumeInput=this.shadow.getElementById("volume"),this.controlsRow=this.shadow.querySelector(".controls"),this.momentsBox=this.shadow.getElementById("moments"),this.momentsButton=this.shadow.getElementById("moments-button"),this.momentsCurrent=this.shadow.getElementById("moments-current"),this.momentsMenu=this.shadow.getElementById("moments-menu"),this.momentsButton.addEventListener("click",()=>this.toggleMomentsMenu()),this.moreButton=this.shadow.getElementById("controls-more"),this.moreButton.addEventListener("click",()=>this.setControlsFolded(this.controlsRow.classList.contains("more-open"))),this.muteButton.addEventListener("click",()=>this.toggleMuted()),this.miniPlayed=this.shadow.getElementById("mini-played"),this.miniRemaining=this.shadow.getElementById("mini-remaining"),this.miniMuteButton=this.shadow.getElementById("mini-mute");const e=this.shadow.getElementById("mini-bar");e.addEventListener("click",i=>{i.stopPropagation();const n=e.getBoundingClientRect(),s=this.player.seekableDuration;n.width<=0||s<=0||this.player.seek(Math.min(Math.max((i.clientX-n.left)/n.width,0),1)*s)}),this.miniMuteButton.addEventListener("click",i=>{i.stopPropagation(),this.toggleMuted()}),this.stageElement.addEventListener("pointerenter",this.handleMinifiedEnter),this.stageElement.addEventListener("pointerleave",this.handleMinifiedLeave),this.volumeInput.addEventListener("input",()=>{this.setVolume(Number(this.volumeInput.value))}),this.fullscreenTarget=this.stageElement,this.playPauseButton.addEventListener("click",()=>this.togglePlayPause()),this.fullscreenButton.addEventListener("click",()=>this.toggleFullscreen()),this.addEventListener("keydown",this.handleFullscreenKey),this.observerMapButton.addEventListener("click",()=>this.toggleObserverMap()),this.referencesButton.addEventListener("click",()=>this.toggleReferences()),this.tracesButton.addEventListener("click",()=>this.toggleTraces()),this.referenceOpacityInput.addEventListener("input",()=>{this.referenceOpacityTouched=!0,this.dispatchReferenceView()}),this.milestonesButton.addEventListener("click",()=>this.toggleMilestones()),this.observerMapCanvas.addEventListener("pointermove",this.handleObserverMapPointerMove),this.observerMapCanvas.addEventListener("pointerleave",this.handlePointerLeave),this.observerMapCanvas.addEventListener("click",this.handleObserverMapClick),this.observerMapCanvas.addEventListener("pointerdown",this.handleObserverMapPointerDown),this.observerMapCanvas.addEventListener("pointerup",this.handleObserverMapPointerUp),this.observerMapCanvas.addEventListener("pointercancel",this.handleObserverMapPointerUp),this.observerMapCanvas.addEventListener("wheel",this.handleObserverMapWheel,{passive:!1}),this.mapZoomInButton.addEventListener("click",()=>this.zoomObserverMap(.5,.5,2)),this.mapZoomOutButton.addEventListener("click",()=>this.zoomObserverMap(.5,.5,.5)),this.mapFitButton.addEventListener("click",()=>{this.observerMapView.reset(),this.observerMapViewChanged()}),this.seekInput.addEventListener("input",()=>this.player.seek(this.snapSeekToMark(Number(this.seekInput.value)))),this.seekInput.addEventListener("pointerdown",i=>{this.suspendForScrub(),this.seekSnapArmed=!0,this.nameMarkUnder(i),this.beginTouchScrub(i)}),this.seekInput.addEventListener("pointerup",i=>{this.seekSnapArmed=!1,this.endTouchScrub(i)}),this.seekInput.addEventListener("pointercancel",i=>this.endTouchScrub(i)),this.seekInput.addEventListener("pointermove",i=>{this.nameMarkUnder(i),this.hoverSeek(i),this.touchScrub(i)}),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 i of["touchend","click"])this.stageElement.addEventListener(i,()=>this.sightingAudio.resume(),!0);this.stageElement.addEventListener("pointermove",()=>this.touchedStage()),this.canvas.addEventListener("click",i=>{if(!(!this.enableClickToPlay||this.minified)){if(this.tapRevealedOnly){this.tapRevealedOnly=!1;return}i.detail<=1&&(this.playbackBeforeClick={state:this.playbackState,time:this.currentTime}),this.togglePlayPause()}}),this.canvas.addEventListener("dblclick",i=>{!this.enableClickToPlay||this.minified||(i.preventDefault(),this.restorePlayback(),this.toggleFullscreen())}),this.canvas.addEventListener("pointermove",this.handlePointerMove),this.canvas.addEventListener("pointerleave",this.handlePointerLeave),document.addEventListener("fullscreenchange",this.handleFullscreenChange),document.addEventListener("pointerdown",this.handleMomentsDismiss,!0),document.addEventListener("keydown",this.handleMomentsDismiss,!0),document.addEventListener("visibilitychange",this.handleVisibility),window.addEventListener("pagehide",this.handleHidden),document.addEventListener("pointerup",this.handlePointerRelease,!0),document.addEventListener("pointercancel",this.handlePointerRelease,!0),this.observerMapResizeObserver?.observe(this.observerMapPanel),this.chromeResizeObserver?.observe(this.chromeCanvas),this.controlsFitObserver?.observe(this.controlsRow),this.controlsFitObserver?.observe(this.controlsRow.querySelector(".controls-left")),typeof MutationObserver<"u"&&(this.controlsMutations=new MutationObserver(()=>this.fitControls()),this.controlsMutations.observe(this.controlsRight,{attributes:!0,attributeFilter:["hidden"],childList:!0,subtree:!0})),this.hostControls(void 0),this.player=this.createPlayer(),this.updateTimeLabels(),this.updatePlayPauseButton(),this.updateFullscreenButton(),this.updateMuteButton(),this.updateObserverMapButton(),this.updateReferencesButton(),this.updateTracesButton(),this.updateMilestonesButton(),this.refresh()}connectedCallback(){this.saidTexts=void 0,this.loadLocaleMessages();const t=this.getAttribute("src");t&&this.loadFromSrc(t)}disconnectedCallback(){document.removeEventListener("fullscreenchange",this.handleFullscreenChange),document.removeEventListener("pointerdown",this.handleMomentsDismiss,!0),document.removeEventListener("keydown",this.handleMomentsDismiss,!0),document.removeEventListener("visibilitychange",this.handleVisibility),window.removeEventListener("pagehide",this.handleHidden),document.removeEventListener("pointerup",this.handlePointerRelease,!0),document.removeEventListener("pointercancel",this.handlePointerRelease,!0),window.clearTimeout(this.controlsIdleTimer),this.observerMapResizeObserver?.disconnect(),this.chromeResizeObserver?.disconnect(),this.controlsFitObserver?.disconnect(),this.controlsMutations?.disconnect(),this.exitSimulatedFullscreen(),this.sightingAudio.dispose()}attributeChangedCallback(t,e,i){if(t==="src"&&i&&i!==e&&this.isConnected&&this.loadFromSrc(i),t===Ho&&this.applyObserverMapDefault(),t===Bo&&this.setMilestonesShown(!this.hasAttribute(Bo)),t===Mr){const n=this.minified;this.stageElement.classList.toggle("minified",n),n&&e===null&&(this.muted=!0),this.updateStartState()}}get minified(){return this.hasAttribute(Mr)}miniPlayed;miniRemaining;miniMuteButton;handleMinifiedEnter=t=>{!this.minified||t.pointerType==="touch"||(this.minifiedHovered=!0,this.play())};minifiedHovered=!1;handleMinifiedLeave=t=>{!this.minified||t.pointerType==="touch"||(this.minifiedHovered=!1,this.pause(),this.dispatchEvent(new CustomEvent(jv)))};started=!1;updateStartState(){this.playRequested&&(this.started=!0);const t=!this.started&&this.enableClickToPlay;this.stageElement.classList.toggle("unstarted",t),t&&!this.minified?this.canvas.title=this.messages.clickToPlay:this.canvas.removeAttribute("title")}async loadFromSrc(t){this.sightingData=await Fv.json(t)}get sightingData(){return ky(this.currentSighting)}set sightingData(t){this.player.stop(),this.soundPreview=void 0,this.sightingAudio.silence(),this.currentSighting=Hy(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.started=!1,this.syncPlayerTitle(),this.updateTimeLabels(),this.updatePlayPauseButton(),this.refresh(),this.applyObserverMapDefault(),this.minified&&this.minifiedHovered&&this.play()}set playerTitle(t){this.titleOverride=t,this.syncPlayerTitle()}titleOverride;syncPlayerTitle(){const t=this.said.read(this.titleOverride)??this.currentSighting.observer?.title??"";this.playerTitleBox.textContent=t,this.playerTitleBox.hidden=t===""}get recordingIssues(){return this.issues}async reportIssues(t,e){const i=++this.issueCheck;let n=[];try{const{default:s}=await Fi(async()=>{const{default:a}=await import("./sightingSchema-v2l1p6Ld.js");return{default:a}},[],import.meta.url);n=new os(s).issues(t)}catch{}i===this.issueCheck&&(this.issues=[...n,...e.loadIssues],tc.warn(this.issues,e.id),this.renderIssues(),this.dispatchEvent(new CustomEvent(vx,{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=tc.text(i,this.messages.issueTemplates),n}))}get sighting(){return this.currentSighting}previewSound(t){this.soundPreview=t,this.sightingAudio.resume(),this.sightingAudio.setSound(t)}stopSoundPreview(){this.soundPreview=void 0,this.sightingAudio.silence()}get canvasElement(){return this.canvas}get renderer(){return this.canvasRenderer}get currentTime(){return this.player.time}set currentTime(t){this.player.seek(t)}get seekableDuration(){return this.player.seekableDuration}get autoReplayEnabled(){return this.loopEnabled}set autoReplayEnabled(t){t!==this.loopEnabled&&this.toggleLoop()}play(){if(!(this.player.seekableDuration<=0||this.playbackState==="playing")){if(this.clockHeld){this.playAfterHold=!0,this.announcePlayRequest();return}this.togglePlayPause()}}get playRequested(){return this.playbackState==="playing"||this.playAfterHold}announcePlayRequest(){this.started=!0,this.updateStartState(),this.dispatchEvent(new CustomEvent("playrequest"))}clockHeld=!1;playAfterHold=!1;holdClock(t){if(t!==this.clockHeld){if(this.clockHeld=t,t){if(this.playbackState!=="playing")return;this.playAfterHold=!0,this.player.pause(),this.soundPreview=void 0,this.sightingAudio.silence(),this.refresh(),this.updatePlayPauseButton();return}this.playAfterHold&&(this.playAfterHold=!1,!(this.player.seekableDuration<=0||this.playbackState==="playing")&&(this.sightingAudio.resume(),this.player.play(),this.updatePlayPauseButton()))}}pause(){this.playAfterHold=!1,this.playbackState==="playing"&&this.togglePlayPause()}get positionLabel(){return this.timeStartLabel.textContent??""}get durationLabel(){return this.timeEndLabel.textContent??""}get showingClockTime(){return this.canShowClockTime}get canSwitchTimeDisplay(){return this.realStartMs!==void 0}toggleTimeDisplay(){this.canSwitchTimeDisplay&&(this.showClockTime=!this.showClockTime,this.updateTimeLabels(),this.updateTimeLabelTitles(),this.dispatchEvent(new CustomEvent("timedisplaychange",{bubbles:!0,composed:!0})))}get canShowClockTime(){return this.realStartMs!==void 0&&this.showClockTime}set showToolbar(t){this.toolbar.classList.toggle("hidden",!t),t?this.controlsRight.appendChild(this.fullscreenButton):this.cornerButtons.appendChild(this.fullscreenButton)}get playbackState(){return this.player.playbackState}get selectedSourceIds(){return this.highlightedSourceIds}get durationSeconds(){return this.currentSighting.event.durationSeconds}set durationSeconds(t){this.currentSighting.event.durationSeconds=t,this.updateTimeLabels(),this.refresh(),this.updatePlayPauseButton()}set selectedSourceIds(t){const e=new Set(t);e.size===this.highlightedSourceIds.size&&[...e].every(n=>this.highlightedSourceIds.has(n))||(this.highlightedSourceIds=e,this.refresh())}hasVisibleShapeAt(t,e){return this.shapeAt(t,e)!==void 0}refresh(){this.applyFrameFormat(),this.updateMuteButton(),this.updateTimeLabels(),this.seekInput.max=String(this.player.seekableDuration),this.refreshMilestoneMarks(),this.updateMilestonesButton(),this.updateObserverMap(),this.updateReferences(),this.updateTracesButton(),this.player.seek(this.player.time)}repaintOverlay(){this.quietFrame=!0;try{this.player.seek(this.player.time)}finally{this.quietFrame=!1}}quietFrame=!1;hostControls(t){const e=[this.milestonesButton,this.referencesButton,this.referenceOpacityInput,this.tracesButton,this.observerMapButton];if(t)for(const i of e)t.appendChild(i);else{const i=this.fullscreenButton.parentElement===this.controlsRight?this.fullscreenButton:null;for(const n of e)this.controlsRight.insertBefore(n,i)}}get referencesShown(){return this.referencesShownState}get referenceOpacity(){return Number(this.referenceOpacityInput.value)}get severalReferences(){return this.currentSighting.references.length>1}toggleReferences(){if(this.severalReferences){this.toggleReferencesMenu();return}this.referencesShownState=!this.referencesShownState,this.updateReferencesButton(),this.dispatchReferenceView()}updateReferences(){const t=this.currentSighting.references;!this.referenceOpacityTouched&&t.length>0&&(this.referenceOpacityInput.value=String(t[0].opacity));for(const e of[...this.referenceViews.keys()])t.some(i=>i.id===e)||this.referenceViews.delete(e);this.severalReferences?this.referencesMenu.hidden||this.renderReferencesMenu():this.closeReferencesMenu(),this.updateReferencesButton(),this.severalReferences&&this.dispatchReferenceView()}viewOfReference(t){let e=this.referenceViews.get(t.id);return e||(e={shown:!0,opacity:t.opacity},this.referenceViews.set(t.id,e)),e}toggleReferencesMenu(){this.referencesMenu.hidden?this.openReferencesMenu():this.closeReferencesMenu()}openReferencesMenu(){this.renderReferencesMenu(),this.referencesMenu.hidden=!1,this.placeReferencesMenu(),this.referencesButton.setAttribute("aria-expanded","true"),document.addEventListener("pointerdown",this.handleReferencesMenuOutside,!0),document.addEventListener("keydown",this.handleReferencesMenuKey,!0)}closeReferencesMenu(){this.referencesMenu.hidden||(this.referencesMenu.hidden=!0,this.referencesButton.setAttribute("aria-expanded","false"),document.removeEventListener("pointerdown",this.handleReferencesMenuOutside,!0),document.removeEventListener("keydown",this.handleReferencesMenuKey,!0))}handleReferencesMenuOutside=t=>{const e=t.composedPath();e.includes(this.referencesMenu)||e.includes(this.referencesButton)||this.closeReferencesMenu()};handleReferencesMenuKey=t=>{t.key==="Escape"&&(this.closeReferencesMenu(),this.referencesButton.focus())};placeReferencesMenu(){const t=this.referencesButton.getBoundingClientRect(),e=this.referencesMenu,i=4;e.style.bottom=`${Math.max(i,window.innerHeight-t.top+i)}px`,e.style.top="auto";const n=e.getBoundingClientRect().width;e.style.left=`${Math.max(i,Math.min(t.left,window.innerWidth-n-i))}px`}renderReferencesMenu(){const t=this.currentSighting.references.map(e=>{const i=this.viewOfReference(e),n=this.said.read(e.title)??e.id,s=document.createElement("div");s.className="reference-row";const a=document.createElement("label"),o=document.createElement("input");o.type="checkbox",o.checked=i.shown;const c=document.createElement("span");c.textContent=n,c.title=n,a.append(o,c);const l=document.createElement("input");return l.type="range",l.min="0",l.max="1",l.step="0.05",l.value=String(i.opacity),l.title=this.messages.referenceOpacity,l.setAttribute("aria-label",`${this.messages.referenceOpacity}: ${n}`),l.disabled=!i.shown,o.addEventListener("change",()=>{i.shown=o.checked,l.disabled=!i.shown,this.updateReferencesButton(),this.dispatchReferenceView()}),l.addEventListener("input",()=>{i.opacity=Number(l.value),this.dispatchReferenceView()}),s.append(a,l),s});this.referencesMenu.setAttribute("aria-label",this.messages.referencesMenu),this.referencesMenu.replaceChildren(...t)}updateReferencesButton(){const t=this.currentSighting.references.length>0,e=this.severalReferences,i=e?this.currentSighting.references.some(s=>this.viewOfReference(s).shown):this.referencesShownState;this.referencesButton.hidden=!t,this.referenceOpacityInput.hidden=!t||!this.referencesShownState||e,this.referencesButton.setAttribute("aria-pressed",String(i)),e?this.referencesButton.setAttribute("aria-haspopup","true"):this.referencesButton.removeAttribute("aria-haspopup"),ye.setIcon(this.referencesButton,i?Xt.PICTURES_ON:Xt.PICTURES_OFF);const n=e?this.messages.referencesMenu:this.referencesShownState?this.messages.hideReferences:this.messages.showReferences;this.referencesButton.title=n,this.referencesButton.setAttribute("aria-label",n),this.referenceOpacityInput.title=this.messages.referenceOpacity,this.referenceOpacityInput.setAttribute("aria-label",this.messages.referenceOpacity)}get tracesShown(){return this.tracesShownState}toggleTraces(){this.tracesShownState=!this.tracesShownState,this.updateTracesButton(),this.updateObserverMap(),this.dispatchEvent(new CustomEvent("traceview",{detail:{shown:this.tracesShown}}))}updateTracesButton(){this.tracesButton.hidden=this.currentSighting.traces.length===0,this.tracesButton.setAttribute("aria-pressed",String(this.tracesShownState)),ye.setIcon(this.tracesButton,this.tracesShownState?Xt.TRACES_ON:Xt.TRACES_OFF);const t=this.tracesShownState?this.messages.hideTraces:this.messages.showTraces;this.tracesButton.title=t,this.tracesButton.setAttribute("aria-label",t)}dispatchReferenceView(){const t=this.severalReferences?Object.fromEntries(this.currentSighting.references.map(e=>[e.id,{...this.viewOfReference(e)}])):void 0;this.dispatchEvent(new CustomEvent("referenceview",{detail:{shown:this.referencesShown,opacity:this.referenceOpacity,views:t}}))}refreshMilestoneMarks(){const t=this.player.seekableDuration,e=t>0?Wc(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}%`}paintMiniProgress(t){const e=this.player.seekableDuration;this.miniPlayed.style.width=`${e>0?Math.min(Math.max(t/e,0),1)*100:0}%`,this.miniRemaining.textContent=this.formatRemaining(t)}paintSeekProgress(t){for(const i of this.seekSegmentList)i.played.style.width=ye.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=ye.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?Ku(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)}paintChrome(t){const e=this.chromeCanvas.getContext("2d"),i=this.overlayPainter!==void 0||this.selectionShown;if(!i&&!this.chromeDirty)return;const n=this.chromeCanvas.clientWidth,s=this.chromeCanvas.clientHeight;if(!e||typeof e.setTransform!="function"||n===0||s===0){t(this.canvasRenderer);return}const a=window.devicePixelRatio||1,o=Math.max(1,Math.round(n*a)),c=Math.max(1,Math.round(s*a));this.chromeCanvas.width!==o&&(this.chromeCanvas.width=o),this.chromeCanvas.height!==c&&(this.chromeCanvas.height=c),e.setTransform(1,0,0,1,0,0),e.clearRect(0,0,o,c),this.chromeDirty=!1,i&&(e.setTransform(o/this.canvas.width,0,0,c/this.canvas.height,0,0),this.chromeRenderer??=new Qo(e),this.chromeDirty=!0,t(this.chromeRenderer))}chromeDraw;repaintChrome(){this.chromeDraw&&this.overlayPainter&&this.paintChrome(this.chromeDraw)}scrubbingPointer;beginTouchScrub(t){if(t.pointerType!=="mouse"){this.scrubbingPointer=t.pointerId;try{this.seekInput.setPointerCapture(t.pointerId)}catch{}this.seekToPointer(t)}}touchScrub(t){t.pointerId===this.scrubbingPointer&&this.seekToPointer(t)}endTouchScrub(t){t.pointerId===this.scrubbingPointer&&(this.scrubbingPointer=void 0,this.seekToPointer(t))}seekToPointer(t){const e=this.seekInput.getBoundingClientRect(),i=this.player.seekableDuration;if(e.width<=0||i<=0)return;const n=Math.min(Math.max((t.clientX-e.left)/e.width,0),1);this.player.seek(this.snapSeekToMark(n*i))}seekSnapArmed=!1;static MARK_SNAP_PX=6;markNear(t){const e=this.player.seekableDuration,i=this.seekInput.getBoundingClientRect().width;if(e<=0||i<=0)return;const n=ye.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?Ku(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=us.windowEndingAt(t,this.currentSighting.exposure??0);if(e.ms<ye.SHORTEST_VISIBLE_EXPOSURE_MS)return[t];const i=Math.min(ye.MAX_EXPOSURE_STEPS,Math.max(2,Math.round(e.ms/ye.SHORTEST_VISIBLE_EXPOSURE_MS))),n=Math.ceil(this.travelPxOver(e.fromMs,e.ms)/ye.EXPOSURE_STEP_PX),s=Math.min(ye.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){if(!this.accountHidden)for(const n of this.exposureTimes()){const s=this.currentSighting.timeline.hitTest(n,t,e,i);if(s)return s}}shapesAt(t){const e=new Map;for(const i of this.currentSighting.timeline.sourceIds){const n=this.currentSighting.timeline.getInterpolatedShapeAt(t,i);n&&e.set(i,n)}return e}static SHORTEST_VISIBLE_EXPOSURE_MS=20;static MAX_EXPOSURE_STEPS=48;static EXPOSURE_STEP_PX=2;static MAX_TRAVEL_STEPS=320;applyFrameFormat(){const t=Pi.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:gx;this.canvasRenderer.setStarPoints(Pi.starPointsOf(this.sighting.instrument));const n=(si(this.sighting,t)?.rollDeg??0)+this.gaitAt(t).rollDeg;this.canvasRenderer.setRoll(n*Math.PI/180);const s=this.exposureInstants(t),a=this.frameShift;if(this.paintsShapes)for(const c of s)for(const[,l]of c.shapes){const h=c.share,u=h===1?l:{...l,transparency:1-(1-l.transparency)*h};this.canvasRenderer.paintShape(this.shifted(u,a))}for(const[c,l]of s[0].shapes)!this.selectionShown||!i.has(c)||(this.paintsShapes?i.size===1?this.canvasRenderer.paintShape({...l,selected:!0}):this.canvasRenderer.paintMemberOutline(l):this.canvasRenderer.paintSelectionOnly(this.shifted(l,a)));const o=this.selectionShown&&i.size>1?Fn.groupBoundsFor([...e].filter(([c])=>i.has(c)).map(([,c])=>c.bounds)):void 0;this.chromeDraw=c=>{o&&c.paintGroupHandles(o),this.overlayPainter?.(c)},this.paintChrome(this.chromeDraw),this.mapShapeBounds=s.flatMap(c=>[...c.shapes.values()].filter(l=>l.transparency<1).map(l=>this.shifted(l,a).bounds)),this.keepObserverMapClear(),this.seekInput.value=String(t),this.paintSeekProgress(t),this.minified&&this.paintMiniProgress(t),this.timeStartLabel.textContent=this.formatPosition(t),this.showMilestoneAt(t),this.paintObserverMap(t),this.playbackState==="playing"?(this.soundPreview=void 0,this.sightingAudio.setSound(Dy(this.currentSighting,t))):this.soundPreview?this.sightingAudio.setSound(this.soundPreview):this.sightingAudio.silence(),this.updatePlayPauseButton(),!this.quietFrame&&this.dispatchEvent(new CustomEvent("timeupdate",{detail:{time:t}}))}shifted(t,e){return e.x===0&&e.y===0?t:{...t,bounds:{...t.bounds,x:t.bounds.x+e.x,y:t.bounds.y+e.y}}}createPlayer(){const t=new Iy(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*ye.SEEK_KEY_STEP_MS)))}else t.key===" "&&(t.preventDefault(),this.togglePlayPause())};togglePlayPause(){if(!(this.player.seekableDuration<=0)){if(this.player.playbackState==="playing")this.player.pause(),this.soundPreview=void 0,this.sightingAudio.silence(),this.refresh();else if(this.clockHeld){this.playAfterHold=!this.playAfterHold,this.playAfterHold&&this.announcePlayRequest();return}else this.announcePlayRequest(),this.sightingAudio.resume(),this.player.play();this.updatePlayPauseButton(),this.flashPlayback()}}flashPlayback(){const t=this.playbackFlash;t.innerHTML=this.player.playbackState==="playing"?Xt.PLAY:Xt.PAUSE,t.classList.remove("flashing"),t.offsetWidth,t.classList.add("flashing")}static icons=new WeakMap;static setIcon(t,e){ye.icons.get(t)!==e&&(ye.icons.set(t,e),t.innerHTML=e)}set captionHeld(t){this.stageElement.classList.toggle("caption-held",t)}set controlsHeld(t){this.stageElement.classList.toggle("controls-held",t)}static CONTROLS_IDLE_MS=3e3;controlsIdleTimer;wasPlaying=!1;quietControlsValue=!1;get quietControls(){return this.quietControlsValue}set quietControls(t){this.quietControlsValue=t,this.stageElement.classList.toggle("quiet",t)}tapRevealedOnly=!1;get hoverless(){return typeof matchMedia=="function"&&matchMedia("(hover: none)").matches}touchedStage(){if(!this.hoverless)return;this.player.playbackState==="playing"&&!this.stageElement.classList.contains("touched")&&(this.tapRevealedOnly=!0),this.revealControls()}pointerHeld=!1;handlePointerDown=()=>{this.pointerHeld=!0};resumeAfterScrub=!1;suspendForScrub(){this.player.playbackState==="playing"&&(this.resumeAfterScrub=!0,this.stopPlaying())}stopPlaying(){this.player.pause(),this.soundPreview=void 0,this.sightingAudio.silence(),this.refresh(),this.updatePlayPauseButton()}resumeFromScrub(){this.resumeAfterScrub&&(this.resumeAfterScrub=!1,this.sightingAudio.resume(),this.player.play(),this.updatePlayPauseButton())}handleHidden=()=>{this.player.playbackState==="playing"&&this.stopPlaying(),this.resumeAfterScrub=!1};handleVisibility=()=>{document.visibilityState==="hidden"&&this.handleHidden()};handlePointerRelease=()=>{this.resumeAfterScrub&&window.setTimeout(()=>this.resumeFromScrub(),0),this.pointerHeld&&(this.pointerHeld=!1,this.hoverless&&this.stageElement.classList.contains("touched")&&this.revealControls())};revealControls(){this.stageElement.classList.add("touched"),window.clearTimeout(this.controlsIdleTimer),this.player.playbackState==="playing"&&(this.pointerHeld||!this.momentsMenu.hidden||(this.controlsIdleTimer=window.setTimeout(()=>{this.stageElement.classList.remove("touched"),this.tapRevealedOnly=!1},ye.CONTROLS_IDLE_MS)))}updatePlayPauseButton(){const t=this.player.playbackState==="playing";this.stageElement.classList.toggle("paused",!t),t!==this.wasPlaying&&t&&this.hoverless&&(!this.quietControlsValue||this.stageElement.classList.contains("touched"))&&this.revealControls(),this.wasPlaying=t,this.updateStartState(),ye.setIcon(this.playPauseButton,t?Xt.PAUSE:Xt.PLAY);const e=this.player.seekableDuration>0;this.playPauseButton.disabled=!e;const i=e?t?this.messages.pause:this.messages.play:this.messages.noDuration;this.playPauseButton.title=i,this.playPauseButton.setAttribute("aria-label",i)}toggleLoop(){this.loopEnabled=!this.loopEnabled,this.player.loop=this.loopEnabled}restorePlayback(){const t=this.playbackBeforeClick;t&&(this.currentTime=t.time,t.state==="playing"?this.play():this.pause())}get canUseNativeFullscreen(){return typeof this.fullscreenTarget.requestFullscreen=="function"&&document.fullscreenEnabled}toggleFullscreen(){if(!this.canUseNativeFullscreen){this.simulatedFullscreen?this.exitSimulatedFullscreen():this.enterSimulatedFullscreen();return}document.fullscreenElement?document.exitFullscreen():this.fullscreenTarget.requestFullscreen().catch(t=>{console.error("<rr0-ufo>: requestFullscreen() failed —",t)})}enterSimulatedFullscreen(){const t=this.fullscreenTarget;this.styleBeforeSimulatedFullscreen=t.getAttribute("style")??"",this.bodyOverflowBeforeSimulatedFullscreen=document.body.style.overflow;const e=t.style;e.setProperty("position","fixed"),e.setProperty("inset","0"),e.setProperty("margin","0"),e.setProperty("max-width","none"),e.setProperty("max-height","none"),e.setProperty("aspect-ratio","auto"),e.setProperty("z-index","2147483647"),e.setProperty("background","#000"),e.setProperty("width","100vw"),e.setProperty("width","100dvw"),e.setProperty("height","100vh"),e.setProperty("height","100dvh"),document.body.style.overflow="hidden",this.simulatedFullscreen=!0,document.addEventListener("keydown",this.handleSimulatedFullscreenKey),this.updateFullscreenButton(),this.updateMuteButton()}exitSimulatedFullscreen(){if(!this.simulatedFullscreen)return;const t=this.fullscreenTarget;this.styleBeforeSimulatedFullscreen?t.setAttribute("style",this.styleBeforeSimulatedFullscreen):t.removeAttribute("style"),document.body.style.overflow=this.bodyOverflowBeforeSimulatedFullscreen??"",this.simulatedFullscreen=!1,document.removeEventListener("keydown",this.handleSimulatedFullscreenKey),this.updateFullscreenButton(),this.updateMuteButton()}toggleObserverMap(){const t=this.observerMapPanel.hidden;this.observerMapAsked=t,this.setObserverMapOpen(t),this.keepObserverMapClear(),this.dispatchEvent(new CustomEvent("observermapchange",{bubbles:!0,composed:!0,detail:{open:t}}))}get observerMapOpen(){return!this.observerMapPanel.hidden}get milestonesVisible(){return this.milestonesShown}observerMapAsked=!1;applyObserverMapDefault(){const t=this.getAttribute(Ho),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;ye.setIcon(this.observerMapButton,t?Xt.MAP_ON:Xt.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=ko.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=ci.including(this.observerPath.boundsAround(ye.OBSERVER_MAP_MIN_SPAN_M,ye.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?ci.expand(t,ye.OBSERVER_MAP_IMAGERY_AHEAD):t,n=ye.OBSERVER_MAP_IMAGERY_PX*(e?1+2*ye.OBSERVER_MAP_IMAGERY_AHEAD:1);this.observerMapImageryBounds=i,this.observerMapImageryViewWidth=t.east-t.west,this.observerMapImageryLoading=!0;const s=Zv();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?ci.expand(t,ye.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=ye.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=si(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},ye.OBSERVER_MAP_FOLLOW_MARGIN)&&this.scheduleObserverMapImagery();const i=this.currentSighting.instrument,n=[],s=this.currentSighting.milestones.length>0?Ku(this.currentSighting.milestones,t):void 0;for(const a of this.milestonesShown?Wc(this.currentSighting.milestones):[]){const o=si(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?da.of(i,this.canvas.height,e.fovDeg).halfWidthAngleDeg(Pi.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,Wc(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,ye.setIcon(this.milestonesButton,this.milestonesShown?Xt.MILESTONES_ON:Xt.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=si(this.currentSighting,0);return e?.lat===void 0||e.lng===void 0?[]:this.currentSighting.decor.filter(i=>i.kind!=="crop").map(i=>{const n=ua(i,t),{lat:s,lng:a}=Bn(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=si(this.currentSighting,this.currentTime),s=da.of(this.currentSighting.instrument,this.canvas.height,n?.fovDeg??60);return{x:-s.angleDegToRadiusPx(e),y:s.angleDegToRadiusPx(i)}}gaitAt(t){return ze.bodyAt(this.currentSighting,t,this.steadyBody)}mutedState=!1;get muted(){return this.mutedState}set muted(t){t!==this.mutedState&&(this.mutedState=t,!t&&this.volumeState===0&&(this.volumeState=ye.RESTORED_VOLUME),this.applyLevel())}volumeState=1;static RESTORED_VOLUME=.5;get volume(){return this.volumeState}set volume(t){this.setVolume(t)}setVolume(t){this.volumeState=Math.min(Math.max(t,0),1),this.mutedState=this.volumeState===0,this.applyLevel()}get level(){return this.mutedState?0:this.volumeState}applyLevel(){this.sightingAudio.setLevel(this.level),this.updateMuteButton(),this.dispatchEvent(new CustomEvent("mutedchange",{bubbles:!0,composed:!0,detail:{muted:this.mutedState,volume:this.volumeState}}))}toggleMuted(){this.hasSound&&(this.muted=!this.mutedState)}ambientSound;get hasSound(){return this.currentSighting.soundTrack.allKeyframes.length>0||this.ambientSound?.(this.currentSighting)===!0}updateMuteButton(){const t=!this.hasSound;this.miniMuteButton.hidden=t,this.miniMuteButton.setAttribute("aria-pressed",String(this.mutedState)),ye.setIcon(this.miniMuteButton,this.mutedState?Xt.MUTED:Xt.VOLUME);const e=this.mutedState?this.messages.unmute:this.messages.mute;if(this.miniMuteButton.title=e,this.miniMuteButton.setAttribute("aria-label",e),this.muteButton.disabled=t,this.volumeInput.hidden=t,t){ye.setIcon(this.muteButton,Xt.MUTED),this.muteButton.title=this.messages.noSound,this.muteButton.setAttribute("aria-label",this.messages.noSound),this.muteButton.setAttribute("aria-pressed","true");return}ye.setIcon(this.muteButton,this.mutedState?Xt.MUTED:Xt.VOLUME);const i=this.mutedState?this.messages.unmute:this.messages.mute;this.muteButton.title=i,this.muteButton.setAttribute("aria-label",i),this.muteButton.setAttribute("aria-pressed",String(this.mutedState)),this.volumeInput.value=String(this.level)}updateFullscreenButton(){const t=this.simulatedFullscreen||document.fullscreenElement===this.fullscreenTarget;ye.setIcon(this.fullscreenButton,t?Xt.EXIT_FULLSCREEN:Xt.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 ca(zo.preferencesFor(this))}saidTexts;async loadLocaleMessages(){const t=zv(zo.preferencesFor(this),Hv);if(t===this.messagesLanguage||t==="en"&&this.messagesLanguage===void 0)return;this.messagesLanguage=t;const e=await Vy(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=Ay(t);this.realDurationMs=e!==void 0&&e>0?e:void 0,this.realStartMs=t.time?b0(t.time):void 0;const i=this.currentSighting.timeline.duration;this.player.playbackRate=this.realDurationMs!==void 0&&i>0?i/this.realDurationMs:1,this.player.durationOverrideMs=i>0?0:this.realDurationMs??0,this.timeEndLabel.textContent=this.formatEndOfTimeline(),this.timeStartLabel.textContent=this.formatPosition(this.player.time),this.paintMiniProgress(this.player.time),this.updateTimeLabelTitles()}formatPosition(t){if(this.realDurationMs===void 0)return Xr(t);const e=this.currentSighting.timeline.duration,i=e>0&&t<=e?t/e*this.realDurationMs:t;return this.canShowClockTime?Pm(Cm(this.realStartMs+i)):Xr(i)}formatRemaining(t){const e=this.currentSighting.timeline.duration;if(this.realDurationMs===void 0)return Xr(Math.max(0,e-t));const i=e>0&&t<=e?t/e*this.realDurationMs:t;return Xr(Math.max(0,this.realDurationMs-i))}formatEndOfTimeline(){return this.realDurationMs===void 0?Xr(this.currentSighting.timeline.duration):this.canShowClockTime?Pm(Cm(this.realStartMs+this.realDurationMs)):Xr(this.realDurationMs)}}function Cm(r){const t=new Date(r);return{hour:t.getUTCHours(),minute:t.getUTCMinutes(),second:t.getUTCSeconds()}}function Pm(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 Xr(r){const t=Math.round(r/1e3),e=Math.floor(t/60),i=t%60;return`${e}:${String(i).padStart(2,"0")}`}const E0="rr0-ufo";function Jv(){customElements.get(E0)||customElements.define(E0,ye)}const vx="recordingissues",jv="minifiedreset";/**
1635
1652
  * @license
1636
1653
  * Copyright 2010-2026 Three.js Authors
1637
1654
  * SPDX-License-Identifier: MIT
@@ -7617,7 +7634,7 @@ uniform float uWindowLuminance;
7617
7634
  varying float vLitRank;
7618
7635
  ${c.fragmentShader.replace("#include <emissivemap_fragment>",`#include <emissivemap_fragment>
7619
7636
  totalEmissiveRadiance *= step(vLitRank, uLitShare) * uWindowLuminance * ${St.WINDOW_VARIETY_GLSL};`)}`},a.customProgramCacheKey=()=>"facade-lit-windows";const o=new yt(s,a);return o.castShadow=!0,o.receiveShadow=!0,e.add(o),e}static litWindowShare={value:0};static WINDOW_LUMINANCE_CD_M2=50;static ROOM_LIGHT_K=2900;static COLD_ROOM_LIGHT_K=4e3;static windowLuminance={value:0};static get WINDOW_VARIETY_GLSL(){const t=n=>`vec3(${n.map(s=>s.toFixed(4)).join(", ")})`,e=jo.ofTemperature(St.ROOM_LIGHT_K),i=jo.ofTemperature(St.COLD_ROOM_LIGHT_K);return`(mix(0.35, 2.0, fract(vLitRank * 97.13) * fract(vLitRank * 97.13)) * mix(${t(e)}, ${t(i)}, step(0.86, fract(vLitRank * 53.71))))`}static setWindowLuminance(t){St.windowLuminance.value=St.WINDOW_LUMINANCE_CD_M2*t}static setLitWindowShare(t){St.litWindowShare.value=Math.max(0,Math.min(1,t))}static build(t,e){const i=St.hasFacade(t)?St.buildFacade(t):t.kind==="building"?L1(t.floors??om,t.windows,t.observerSide,t.occupiedFloor,t.observerFacing):t.kind==="tree"?U1():t.kind==="shrub"?N1():t.kind==="bridge"?F4(t):t.kind==="wire"?k4(t):t.kind==="wall"?Ci.build(t):t.kind==="crop"?k1():t.kind==="terrace"?Y4():t.kind==="mound"?z1():t.kind==="streetlight"?H1(e,t.lamp?.mount,t.lamp):t.kind==="trafficlight"?de.trafficLight(Qt.isPedestrian(t.lights)):t.kind==="crossing"?de.crossing(St.sizeOf(t).widthM,St.sizeOf(t).lengthM):t.kind==="roadsign"?de.roadSign(t.sign):t.kind==="vehicle"?B1(e,t.windows,t.observerSide,t.observerFacing):t.kind==="aircraft"?q1():t.kind==="entity"?X1():Jf();t.color&&this.paint(i,t.color);const n=this.scaleFor(t),s=new Te;return t.kind==="building"&&t.roof&&this.addRoof(s,t),i.name=St.BODY_NAME,i.scale.copy(n),s.add(i),t.headingDeg!==void 0&&(s.rotation.y=-t.headingDeg*Yd),this.addLights(s,t.lights),St.fitLights(s,t,t.sizeM??{}),s}static scaleFor(t){const e=t.sizeM;if(!e||St.hasFacade(t)||t.kind==="bridge"||t.kind==="wire"||t.kind==="terrace"||t.kind==="wall"||t.kind==="crossing")return new R(1,1,1);const i=this.naturalSize(t.kind,t.floors);return new R(e.widthM===void 0?1:Zd(e.widthM,i.widthM),e.heightM===void 0?1:Zd(t.kind==="building"?this.wallHeightOf(t,e.heightM):e.heightM,i.heightM),e.lengthM===void 0?1:Zd(e.lengthM,i.lengthM))}static naturalSize(t,e){const i=t==="building"?Math.max(1,(e??om)+1):0;if(t==="bridge")return Qe.NATURAL_SIZE;if(t==="wire")return wr.NATURAL_SIZE;if(t==="terrace"||t==="wall")return{widthM:1,lengthM:1,heightM:1};if(t==="crossing")return{widthM:6,lengthM:2.5,heightM:de.CROSSING_LIFT_M};const n=`${t}:${i}`,s=G1.get(n);if(s)return s;const a=t==="building"?L1(i-1,void 0,void 0,void 0):t==="tree"?U1():t==="shrub"?N1():t==="crop"?k1():t==="mound"?z1():t==="streetlight"?H1(!1):t==="trafficlight"?de.trafficLight(!1):t==="roadsign"?de.roadSign(void 0):t==="vehicle"?B1(!1,void 0,void 0):t==="aircraft"?q1():t==="entity"?X1():Jf(),o=new Yi().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),G1.set(n,c),c}static usesModel(t){return w0(t)!==void 0&&!(t.observerSide!==void 0&&jh(t.kind))}static applyModel(t,e,i,n={}){const s=this.bodyOf(t),a=new Te;a.name=St.BODY_NAME,i.rotation.y=-(n.headingOffsetDeg??0)*Yd,i.updateMatrixWorld(!0);const o=new Yi().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=e.kind==="tree"&&e.sizeM?.heightM!==void 0?{heightM:e.sizeM.heightM}:e.sizeM,h=V1(l,c)??V1(n.depictedSizeM,c)??1;i.scale.multiplyScalar(h);const u=o.getCenter(new R).multiplyScalar(h);i.position.x-=u.x,i.position.z-=u.z,i.position.y-=e.kind==="aircraft"?u.y:o.min.y*h,i.traverse(d=>{d instanceof yt&&(d.castShadow=!0,d.receiveShadow=!0)}),a.add(i),e.kind==="tree"&&a.add(St.trunkShadow(c.heightM*h)),s.parent?(s.parent.add(a),s.removeFromParent()):t.add(a),this.dispose(s),St.fitLights(t,e,{widthM:c.widthM*h,heightM:c.heightM*h,lengthM:c.lengthM*h})}static fitLights(t,e,i){const n=qf.byId(No.rigOf(e)||void 0)?.referenceSizeM;if(!n||!e.lights)return;const s=(h,u)=>h===void 0||u===0?1:h/u,a=s(i.widthM,n.widthM),o=s(i.heightM,n.heightM),c=s(i.lengthM,n.lengthM),l=new Map(e.lights.map(h=>[h.id,h.offsetM]));t.traverse(h=>{const u=h.userData.lightId,d=u===void 0?void 0:l.get(u);d&&h.position.set(d.x*a,d.y*o,d.z*c)})}static trunkShadow(t){St.trunkProxy??={geometry:new on(1,1.15,1,8),material:new vn({colorWrite:!1,depthWrite:!1})};const e=new yt(St.trunkProxy.geometry,St.trunkProxy.material),i=Math.min(.3,Math.max(.12,t*.035)),n=t*.45;return e.scale.set(i,n,i),e.position.y=n/2,e.castShadow=!0,e.receiveShadow=!1,e.userData.sharedModel=!0,e.name="trunk-shadow",e}static trunkProxy;static sizeOf(t){const e=this.naturalSize(t.kind,t.floors);return{widthM:t.sizeM?.widthM??e.widthM,lengthM:t.sizeM?.lengthM??e.lengthM,heightM:t.sizeM?.heightM??e.heightM}}static addLights(t,e){for(const i of e??[]){const n=R4(i.color),s=Qt.figureOf(i),a=s?de.pedestrianFigure(s,1.8*(i.radiusM??qd)):new Si(i.radiusM??qd,8,6),o=Pe(t,a,n,i.offsetM.y,!0);o.position.set(i.offsetM.x,i.offsetM.y,i.offsetM.z),o.userData={emissive:!0,lightId:i.id,lightColor:n},o.visible=!1;const c=o.material;QM.apply(c),c.transparent=!0,c.depthWrite=!1,c.fog=!1}}static setLights(t,e,i,n,s=0,a=1,o=w4,c=[1,1,1],l){if(!e||e.length===0)return;const h=new Map(e.map(d=>[d.id,d]));let u;l&&e.some(d=>d.beamDeg!==void 0)&&(t.updateWorldMatrix(!0,!1),u=t.worldToLocal(St.eyeScratch.copy(l)));for(const d of t.children){if(!(d instanceof yt))continue;const f=d.userData.lightId;if(!f)continue;const p=h.get(f);if(!p)continue;const v=s>0?Uv(p,i,i+s):ty(p,i)?1:0,m=u&&p.beamDeg!==void 0?St.beamShare(p.beamDeg,d.position,u):1;d.visible=v>0&&m>0;const g=p.radiusM??qd,y=Math.max(1,n*o/g),x=g*y,M=a/(Math.PI*x*x),w=d.material,b=d.userData.lightColor;if(b){const E=v*m*b4*(p.intensity??1)*M,S=[b[0]*E*c[0],b[1]*E*c[1],b[2]*E*c[2]],A=Math.min(1,P1/Math.max(S[0],S[1],S[2],1e-30));w.color.setRGB(S[0]*A,S[1]*A,S[2]*A)}d.scale.setScalar(y)}}static eyeScratch=new R;static beamShare(t,e,i){const n=i.x-e.x,s=i.y-e.y,a=i.z-e.z,o=Math.hypot(n,s,a);if(o===0)return 1;const c=-a/o;if(c<=0)return 0;const l=Math.log(.5)/Math.log(Math.cos(t*Math.PI/180));return Math.pow(c,l)}static setLit(t,e,i,n=1,s){const[a,o,c]=e==="streetlight"?[_4*St.lampShare(s),E4,St.lampHue(s)]:[A4,T4,E2],l=i?a*n/(Math.PI*o*o):0,h=Math.min(1,P1/Math.max(c[0]*l,c[1]*l,c[2]*l,1e-30)),u=[c[0]*l*h,c[1]*l*h,c[2]*l*h];t.traverse(d=>{const f=d.userData;!(d instanceof yt)||!f.emissive||f.lightId||(d.material instanceof is?d.material.emissive.setRGB(...u):d.material.color.setRGB(...u))})}static REFERENCE_LUMENS=1e4;static lampShare(t){return t?.lumens?t.lumens/St.REFERENCE_LUMENS:1}static lampHue(t){return t?.colorTemperatureK?jo.ofTemperature(t.colorTemperatureK):I4}static dispose(t){t.traverse(e=>{if(!(e instanceof yt))return;if(e.userData.sharedModel){for(const n of e.userData.tintedMaterials??[])n.dispose();return}e.geometry.dispose();const i=e.material;for(const n of Array.isArray(i)?i:[i])n.dispose()})}}const jd="https://ufoathome.org/models/index.json";class il{attribution="3D models re-hosted by UFO@home, each under its own author's licence";fetchImpl;indexUrls;loading;static shared=new Map;sharing;constructor(t={}){this.sharing=!t.fetchImpl,this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.indexUrls=t.indexUrls??Z4()}async entries(t){const e=await this.load();return t?e.filter(i=>[i.kind].flat().includes(t)):e}async entry(t){return(await this.load()).find(e=>e.id===t)}load(){if(this.loading)return this.loading;if(!this.sharing)return this.loading=this.fetchFirstAvailable();const t=this.indexUrls.join(`
7620
- `);let e=il.shared.get(t);return e||(e=this.fetchFirstAvailable(),il.shared.set(t,e),e.then(i=>{i.length===0&&il.shared.delete(t)})),this.loading=e}async fetchFirstAvailable(){for(const t of this.indexUrls){const e=await this.fetchIndex(t);if(e)return e}return[]}async fetchIndex(t){try{const e=await this.fetchImpl(t);if(!e.ok)return;const i=await e.json();return Array.isArray(i?.models)?i.models.map(({file:n,...s})=>({...s,url:new URL(n,t).href})):void 0}catch{return}}}function Z4(){const r=`?v=${encodeURIComponent("0.127.0")}`,t=typeof location>"u"?void 0:new URL("/models/index.json",location.href).href;return(t&&t!==jd?[t,jd]:[jd]).map(e=>e+r)}const J4=[{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 il}];async function Qd(r){const{GLTFLoader:t}=await Fi(async()=>{const{GLTFLoader:i}=await import("./GLTFLoader-CowOlg4J.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 P2=["ellipsoid","sphere","disc","cylinder","cone","box","torus","figure"];class zn{static MIN_ANGLE_RAD=.002;static FILL=(1-Math.exp(-4))/4;static MAX_SHARE=.3;mesh;constructor(t,e){this.mesh=new yt(new Mn(2,2),new Re({uniforms:{uColor:{value:new nt(0,0,0)},uRadius:{value:1}},vertexShader:zn.VERTEX,fragmentShader:zn.FRAGMENT,transparent:!0,depthWrite:!1,blending:ki,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*zn.MIN_ANGLE_RAD),a=zn.FILL*Math.PI*s*s;return{radiusM:s,luminanceCdM2:i*Math.min(zn.MAX_SHARE,e/a)}}static conserving(t){return Math.sqrt(t/(zn.MAX_SHARE*zn.FILL*Math.PI))}static VERTEX=`
7637
+ `);let e=il.shared.get(t);return e||(e=this.fetchFirstAvailable(),il.shared.set(t,e),e.then(i=>{i.length===0&&il.shared.delete(t)})),this.loading=e}async fetchFirstAvailable(){for(const t of this.indexUrls){const e=await this.fetchIndex(t);if(e)return e}return[]}async fetchIndex(t){try{const e=await this.fetchImpl(t);if(!e.ok)return;const i=await e.json();return Array.isArray(i?.models)?i.models.map(({file:n,...s})=>({...s,url:new URL(n,t).href})):void 0}catch{return}}}function Z4(){const r=`?v=${encodeURIComponent("0.127.2")}`,t=typeof location>"u"?void 0:new URL("/models/index.json",location.href).href;return(t&&t!==jd?[t,jd]:[jd]).map(e=>e+r)}const J4=[{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 il}];async function Qd(r){const{GLTFLoader:t}=await Fi(async()=>{const{GLTFLoader:i}=await import("./GLTFLoader-CowOlg4J.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 P2=["ellipsoid","sphere","disc","cylinder","cone","box","torus","figure"];class zn{static MIN_ANGLE_RAD=.002;static FILL=(1-Math.exp(-4))/4;static MAX_SHARE=.3;mesh;constructor(t,e){this.mesh=new yt(new Mn(2,2),new Re({uniforms:{uColor:{value:new nt(0,0,0)},uRadius:{value:1}},vertexShader:zn.VERTEX,fragmentShader:zn.FRAGMENT,transparent:!0,depthWrite:!1,blending:ki,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*zn.MIN_ANGLE_RAD),a=zn.FILL*Math.PI*s*s;return{radiusM:s,luminanceCdM2:i*Math.min(zn.MAX_SHARE,e/a)}}static conserving(t){return Math.sqrt(t/(zn.MAX_SHARE*zn.FILL*Math.PI))}static VERTEX=`
7621
7638
  uniform float uRadius;
7622
7639
  varying vec2 vOffset;
7623
7640
  void main() {