@rr0/ufoathome 0.11.0 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5579,4 +5579,4 @@ void main() {
5579
5579
  float blur = max(vNearBlur, vHaze);
5580
5580
  gl_FragColor = vec4(color, tex.a * uOpacity * (1.0 - blur * 0.5));
5581
5581
  }
5582
- `;let ea;function GS(){if(ea)return ea;const i=128,e=document.createElement("canvas");e.width=i,e.height=i;const t=e.getContext("2d"),n=t.createRadialGradient(i/2,i/2,0,i/2,i/2,i/2);return n.addColorStop(0,"rgba(255,255,255,1)"),n.addColorStop(.4,"rgba(255,255,255,0.35)"),n.addColorStop(1,"rgba(255,255,255,0)"),t.fillStyle=n,t.fillRect(0,0,i,i),ea=new Vn(e),ea}function HS(i){const t=document.createElement("canvas");t.width=128,t.height=128;const n=t.getContext("2d"),s=128/2-2,r=128/2,a=128/2,o="#2e2b26",l="#f4f1e2";n.fillStyle=o,n.beginPath(),n.arc(r,a,s,0,Math.PI*2),n.fill();const c=m0(i.illuminatedFraction,0,1),h=i.phaseFraction<.5,u=s*Math.abs(1-2*c),d=c<.5;return n.save(),n.beginPath(),n.arc(r,a,s,0,Math.PI*2),n.clip(),n.fillStyle=l,n.beginPath(),h?(n.arc(r,a,s,-Math.PI/2,Math.PI/2,!1),n.ellipse(r,a,u,s,0,Math.PI/2,-Math.PI/2,d)):(n.arc(r,a,s,Math.PI/2,-Math.PI/2,!1),n.ellipse(r,a,u,s,0,-Math.PI/2,Math.PI/2,d)),n.fill(),n.restore(),new Vn(t)}function VS(i){const e=document.createElement("canvas");e.width=128,e.height=128;const t=e.getContext("2d");return t.fillStyle="rgba(0, 0, 0, 0.55)",t.beginPath(),t.arc(64,64,60,0,Math.PI*2),t.fill(),t.fillStyle="#ffffff",t.font="bold 52px sans-serif",t.textAlign="center",t.textBaseline="middle",t.fillText(i,64,68),new Vn(e)}function Uo(i){let e=i;return function(){e|=0,e=e+1831565813|0;let n=Math.imul(e^e>>>15,1|e);return n=n+Math.imul(n^n>>>7,61|n)^n,((n^n>>>14)>>>0)/4294967296}}const kd=new Map;function WS(i){const e=i.byteLength/(4*Float32Array.BYTES_PER_ELEMENT),t=e,n=t*Float32Array.BYTES_PER_ELEMENT;return{count:e,ra:new Float32Array(i,0*n,t),dec:new Float32Array(i,1*n,t),mag:new Float32Array(i,2*n,t),ci:new Float32Array(i,3*n,t)}}function XS(i){let e=kd.get(i);return e||(e=fetch(i).then(t=>t.arrayBuffer()).then(WS),kd.set(i,e)),e}const YS=new URL(""+new URL("rain-BvWZrB9h.ogg",import.meta.url).href,import.meta.url).href,qS=new URL(""+new URL("wind-BjklexY7.ogg",import.meta.url).href,import.meta.url).href,$S=new URL(""+new URL("thunder-DA48qs_v.wav",import.meta.url).href,import.meta.url).href,KS=20,ZS=1;class JS{context;buffers=new Map;ambientSource;ambientGain;ambientKey="none";ambientToken=0;ambientVolume=0;windSource;windGain;windActive=!1;windToken=0;windVolume=0;resume(){if(!this.context){if(typeof AudioContext>"u")return;try{this.context=new AudioContext}catch(e){console.warn("WeatherAudio: Web Audio unavailable, weather sounds disabled:",e);return}}this.context.state==="suspended"&&this.context.resume()}setAmbient(e,t,n){if(!this.context)return;const s=e==="rain"||e==="hail"?e:"none";if(this.ambientVolume=s==="hail"?Math.min(1,t*1.3+.2):s==="rain"?t:0,s!==this.ambientKey){this.ambientKey=s;const a=++this.ambientToken;this.stopSource(this.ambientSource,this.ambientGain),this.ambientSource=void 0,this.ambientGain=void 0,s!=="none"&&this.startLoop(YS,this.ambientVolume).then(o=>this.applyIfCurrent(o,a,()=>this.ambientToken,l=>{this.ambientSource=l?.source,this.ambientGain=l?.gain,l&&(l.gain.gain.value=this.ambientVolume)}))}else this.ambientGain&&(this.ambientGain.gain.value=this.ambientVolume);this.windVolume=Math.min(n/KS,1);const r=n>ZS;if(r!==this.windActive){this.windActive=r;const a=++this.windToken;this.stopSource(this.windSource,this.windGain),this.windSource=void 0,this.windGain=void 0,r&&this.startLoop(qS,this.windVolume).then(o=>this.applyIfCurrent(o,a,()=>this.windToken,l=>{this.windSource=l?.source,this.windGain=l?.gain,l&&(l.gain.gain.value=this.windVolume)}))}else this.windGain&&(this.windGain.gain.value=this.windVolume)}playThunder(){this.context&&this.playOneShot($S,.9)}dispose(){this.ambientToken++,this.windToken++,this.stopSource(this.ambientSource,this.ambientGain),this.stopSource(this.windSource,this.windGain),this.ambientSource=void 0,this.ambientGain=void 0,this.windSource=void 0,this.windGain=void 0,this.context?.close(),this.context=void 0,this.buffers.clear()}applyIfCurrent(e,t,n,s){if(t!==n()){e?.source.stop();return}s(e)}async startLoop(e,t){const n=this.context;if(n)try{const s=await this.getBuffer(e),r=n.createBufferSource();r.buffer=s,r.loop=!0;const a=n.createGain();return a.gain.value=t,r.connect(a).connect(n.destination),r.start(),{source:r,gain:a}}catch(s){console.warn("Weather ambient sound failed to load, staying silent:",s);return}}async playOneShot(e,t){const n=this.context;if(n)try{const s=await this.getBuffer(e),r=n.createBufferSource();r.buffer=s;const a=n.createGain();a.gain.value=t,r.connect(a).connect(n.destination),r.start()}catch(s){console.warn("Thunder sound failed to load:",s)}}async getBuffer(e){const t=this.context;if(!t)throw new Error("WeatherAudio: AudioContext not ready — resume() must be called first");let n=this.buffers.get(e);return n||(n=fetch(e).then(s=>{if(!s.ok)throw new Error(`Audio fetch failed (${s.status}): ${e}`);return s.arrayBuffer()}).then(s=>t.decodeAudioData(s)),this.buffers.set(e,n)),n}stopSource(e,t){try{e?.stop()}catch{}e?.disconnect(),t?.disconnect()}}Ia();const QS={sun:{en:"Sun",fr:"Soleil"},moon:{en:"Moon",fr:"Lune"},Venus:{en:"Venus",fr:"Vénus"},Mars:{en:"Mars",fr:"Mars"},Jupiter:{en:"Jupiter",fr:"Jupiter"},Saturn:{en:"Saturn",fr:"Saturne"}},jS=["en","fr"],ey={building:{en:"Building",fr:"Bâtiment"},tree:{en:"Tree",fr:"Arbre"},streetlight:{en:"Streetlight",fr:"Lampadaire"},vehicle:{en:"Vehicle",fr:"Véhicule"},witness:{en:"Witness",fr:"Témoin"}},ty=new URL(""+new URL("stars-mag7.5-DDr9QasD.bin",import.meta.url).href,import.meta.url).href,ny={sun:{altitudeDeg:-3,azimuthDeg:180,magnitude:-26.7},moon:{altitudeDeg:-90,azimuthDeg:0,phase:{phaseFraction:0,illuminatedFraction:0},magnitude:-12.7},planets:[]},Fo={lat:0,lng:0,elevationM:0,headingDeg:void 0,pitchDeg:0,fovDeg:60};class iy extends HTMLElement{static get observedAttributes(){return["src","star-catalog-src","show-compass","lens-flare-intensity","lens-flare-brightness"]}shadow;stageElement;frameElement;sceneCanvas;ufoElement;sceneRenderer;hoverTooltip;resizeObserver;lastTimeMs=0;starCatalog;weatherAudio=new JS;thunderTimeoutId;handleFullscreenChange=()=>this.resizeToStage();handlePointerMove=e=>{this.sceneRenderer.setCompassHovered(!0);const t=this.ufoElement.canvasElement,n=t.getBoundingClientRect();if(n.width===0||n.height===0)return;const s=(e.clientX-n.left)/n.width*t.width,r=(e.clientY-n.top)/n.height*t.height;if(this.ufoElement.hasVisibleShapeAt(s,r)){this.hoverTooltip.hidden=!0;return}const a=(e.clientX-n.left)/n.width*2-1,o=-((e.clientY-n.top)/n.height*2-1),l=Aa(navigator.languages,jS),c=this.sceneRenderer.pickBodyAt(a,o);if(c){this.showHoverTooltip(e,QS[c]?.[l]??c);return}const h=this.sceneRenderer.pickDecorAt(a,o),u=h?this.ufoElement.sighting.decor.find(d=>d.id===h):void 0;if(u){this.showHoverTooltip(e,u.title||ey[u.kind][l]);return}this.hoverTooltip.hidden=!0};showHoverTooltip(e,t){this.hoverTooltip.textContent=t,this.hoverTooltip.hidden=!1;const n=this.stageElement.getBoundingClientRect();this.hoverTooltip.style.left=`${e.clientX-n.left+12}px`,this.hoverTooltip.style.top=`${e.clientY-n.top+12}px`}handlePointerLeave=()=>{this.hoverTooltip.hidden=!0,this.sceneRenderer.setCompassHovered(!1)};handleLightningFlash=()=>{clearTimeout(this.thunderTimeoutId);const e=(.5+Math.random()*3.5)*1e3;this.thunderTimeoutId=window.setTimeout(()=>this.weatherAudio.playThunder(),e)};handleFirstInteraction=()=>{this.weatherAudio.resume(),this.setWeather(zo(this.ufoElement.sighting,this.lastTimeMs))};handleTimeUpdate=e=>{this.lastTimeMs=e.detail.time,this.updateAstronomy(this.lastTimeMs),this.updateUfoOcclusion(this.lastTimeMs)};constructor(){super(),this.shadow=this.attachShadow({mode:"open"});const e=document.createElement("template");e.innerHTML=`<style>${ff}</style>${uf}`,this.shadow.appendChild(e.content.cloneNode(!0)),this.stageElement=this.shadow.getElementById("stage"),this.frameElement=this.shadow.getElementById("frame"),this.sceneCanvas=this.shadow.getElementById("scene-canvas"),this.sceneRenderer=new PS(this.sceneCanvas,void 0,this.handleLightningFlash),this.hoverTooltip=this.shadow.getElementById("hover-tooltip"),this.ufoElement=document.createElement(Go),this.ufoElement.classList.add("ufo-overlay"),this.ufoElement.style.setProperty("--ufo-canvas-background","transparent"),this.ufoElement.style.setProperty("--ufo-canvas-border","none"),this.ufoElement.fullscreenTarget=this.stageElement,this.shadow.getElementById("ufo-slot").replaceWith(this.ufoElement),this.ufoElement.addEventListener("timeupdate",this.handleTimeUpdate),this.ufoElement.canvasElement.addEventListener("pointermove",this.handlePointerMove),this.ufoElement.canvasElement.addEventListener("pointerleave",this.handlePointerLeave),this.ufoElement.canvasElement.addEventListener("pointerdown",this.handleFirstInteraction,{once:!0})}connectedCallback(){this.resizeToStage(),this.updateAstronomy(this.lastTimeMs),this.loadStars(),this.resizeObserver=new ResizeObserver(()=>this.resizeToStage()),this.resizeObserver.observe(this.frameElement),document.addEventListener("fullscreenchange",this.handleFullscreenChange);const e=this.getAttribute("src");e&&this.loadFromSrc(e)}disconnectedCallback(){this.resizeObserver?.disconnect(),document.removeEventListener("fullscreenchange",this.handleFullscreenChange),this.sceneRenderer.stopTwinkle(),clearTimeout(this.thunderTimeoutId),this.weatherAudio.dispose()}attributeChangedCallback(e,t,n){if(e==="src"&&n&&n!==t&&this.isConnected&&this.loadFromSrc(n),e==="star-catalog-src"&&n!==t&&this.isConnected&&this.loadStars(),e==="show-compass"&&n!==t&&this.sceneRenderer.setShowCompass(this.hasAttribute("show-compass")),e==="lens-flare-intensity"&&n!==t){const s=n===null?NaN:parseFloat(n);this.sceneRenderer.setLensFlareArtifactIntensity(Number.isFinite(s)?s:0)}if(e==="lens-flare-brightness"&&n!==t){const s=n===null?NaN:parseFloat(n);this.sceneRenderer.setDazzleIntensity(Number.isFinite(s)?s:1)}}setCompassForced(e){this.sceneRenderer.setCompassForced(e)}setIndoorLook(e,t){this.sceneRenderer.setIndoorLook(e,t)}setWeather(e){this.sceneRenderer.setWeather(e),this.weatherAudio.setAmbient(e.precipitationType,e.precipitationIntensity,e.windSpeed)}pickDecorAt(e,t){return this.sceneRenderer.pickDecorAt(e,t)}resumeWeatherAudio(){this.weatherAudio.resume()}async loadFromSrc(e){const t=await fetch(e);this.sightingData=await t.json()}get sightingData(){return this.ufoElement.sightingData}set sightingData(e){this.ufoElement.sightingData=e,this.lastTimeMs=0,this.updateAstronomy(0)}get currentTerrainAttribution(){return this.sceneRenderer.currentTerrainAttribution}resizeToStage(){const e=this.frameElement.getBoundingClientRect(),t=Math.max(1,Math.round(e.width)),n=Math.max(1,Math.round(e.height));this.sceneCanvas.width=t,this.sceneCanvas.height=n,this.sceneRenderer.resize(t,n)}async loadStars(){const e=this.getAttribute("star-catalog-src")??ty;this.starCatalog=await XS(e),this.updateAstronomy(this.lastTimeMs)}updateAstronomy(e){const t=this.ufoElement.sighting;this.setWeather(zo(t,e)),this.sceneRenderer.setDecor(t.decor);const n=Bo(t,e);this.sceneRenderer.setObserverPose(n??Fo),this.sceneRenderer.updateDecorAnchoring(Bo(t,0),n),this.sceneRenderer.updateDecorLitState(e),this.sceneRenderer.setTerrainOrigin(n?.lat,n?.lng);const s=n?.lat??Fo.lat,r=n?.lng??Fo.lng,a=Qx(t.event.time??{},r,t.event.utcOffsetHours);if(!a){this.sceneRenderer.setAstronomy(ny);return}const o=new Date(a.getTime()+e),l={lat:s,lng:r,elevationM:n?.elevationM??0},c={...Eo("Sun",o,l),magnitude:wo("Sun",o)},h={...Eo("Moon",o,l),phase:$x(o),magnitude:wo("Moon",o)},u=Yx.map(d=>({body:d,position:Eo(d,o,l),magnitude:wo(d,o)}));this.sceneRenderer.setAstronomy({sun:c,moon:h,planets:u,stars:this.starCatalog?{catalog:this.starCatalog,date:o,observer:l}:void 0})}updateUfoOcclusion(e){const t=this.ufoElement.sighting.timeline,n=this.ufoElement.canvasElement,s=new Set;for(const r of t.sourceIds){const a=t.getInterpolatedShapeAt(e,r);if(!a)continue;const o=(a.bounds.x+a.bounds.width/2)/n.width*2-1,l=-((a.bounds.y+a.bounds.height/2)/n.height*2-1);this.sceneRenderer.isScreenPointOccluded(o,l,r)&&s.add(r)}this.ufoElement.setOccludedSourceIds(s)}}const oc="rr0-scene";function sy(){Ia(),customElements.get(oc)||customElements.define(oc,iy)}class ry{constructor(e,t){this.timeline=e,this.clock=t}currentPointer=null;shapePrototype=null;sourceId="";start(e,t){this.sourceId=e,this.shapePrototype=t,this.currentPointer=null,this.clock.start(n=>this.recordSample(n))}onPointerMove(e,t){this.currentPointer={x:e,y:t}}stop(){this.clock.stop()}recordSample(e){if(!this.currentPointer||!this.shapePrototype)return;const t=Yd(this.shapePrototype,this.currentPointer.x,this.currentPointer.y);this.timeline.addKeyframe(e,[{sourceId:this.sourceId,shape:t}])}}class ay{constructor(e){this.intervalMs=e}rafId=null;startTime=0;lastTick=0;start(e){this.startTime=performance.now(),this.lastTick=0;const t=()=>{const n=performance.now()-this.startTime;n-this.lastTick>=this.intervalMs&&(this.lastTick=n,e(n)),this.rafId=requestAnimationFrame(t)};this.rafId=requestAnimationFrame(t)}stop(){this.rafId!==null&&(cancelAnimationFrame(this.rafId),this.rafId=null)}}const g0={oval:"Oval",polygon:"Polygon",addVertex:"Add vertex",deleteVertex:"Delete vertex",notAPolygon:"Select a single polygon shape",tooFewVertices:"A shape needs at least 3 points",color:"Color",transparency:"Transparency",halo:"Halo",shape:"Shape",shapeTitle:"Name",objectSize:"Real size",objectDistance:"Distance",apparentSize:"i.e. {deg}° — {moons}× the Moon",utcOffset:"Time zone",utcOffsetPlaceholder:"from longitude",objectSizePlaceholder:"reported width",objectDistancePlaceholder:"reported distance",addShape:"Add shape",deleteShape:"Delete shape",play:"Play",pause:"Pause",noDuration:"No observation duration",autoReplay:"Auto-replay",group:"Group",ungroup:"Ungroup",bringToFront:"Bring to front",sendToBack:"Send to back",contextMenuDelete:"Delete",confirmDeleteShape:"Delete {name}? This can't be undone.",confirmDeleteShapes:"Delete {count} shapes? This can't be undone.",onlyOneShape:"There is only one shape",alreadyAtFront:"This shape is already at the front",alreadyAtBack:"This shape is already at the back",needTwoShapesToGroup:"Select at least two shapes to group them",notGrouped:"This shape isn't part of a group",multipleShapesSelected:"Multiple shapes selected — select just one to edit this",samplingRate:"Sampling rate",duration:"Duration",durationPlaceholder:"observation length",durationImprecise:"These dates don't precisely enough determine a duration — enter it manually.",export:"Export JSON",importFile:"Load JSON file",importUrl:"Or load from URL",importUrlPlaceholder:"https://…/sighting.json",importButton:"Load",importError:"Couldn't load that recording — check the file or URL and try again.",record:"Record",stop:"Stop",latitude:"Latitude",longitude:"Longitude",heading:"Heading",headingPlaceholder:"unknown",pitch:"Tilt",observationTime:"Observation start",observationEndTime:"Observation end",edtfInvalid:"Not a valid EDTF date/time (e.g. 1965-07-01T05:00, 2025-06?, 2025~).",edtfPlaceholder:"YYYY-MM-DDThh:mm[?~%] or hh:mm",observationTimeHint:"EDTF — e.g. 1965-07-01T05:00, 2025-06? (uncertain), 2025~ (approximate), or just 05:00 if the date isn't known",observationEndTimeHint:"EDTF — e.g. 1965-07-01T05:10, 2025-06? (uncertain), 2025~ (approximate), or just 05:10 if the date isn't known",presetsGroupLabel:"UFO shape",witnessId:"Witness ID",witnessDirName:"Witness dir name",witnessTitle:"Witness title",witnessLastName:"Witness last name",witnessFirstNames:"Witness first names",caseId:"Case ID",description:"Description",tags:"Tags",tagsPlaceholder:"comma-separated",weather:"Weather",shapeGroup:"Shape",temporalGroup:"Temporal",locationGroup:"Location",observationGroup:"Observation",witnessGroup:"Witness",circumstancesGroup:"Circumstances",cloudCover:"Cloud cover",cloudDarkness:"Cloud darkness",precipitationType:"Precipitation",precipitationNone:"None",precipitationRain:"Rain",precipitationSnow:"Snow",precipitationHail:"Hail",precipitationIntensity:"Intensity",windDirection:"Wind direction",windSpeed:"Wind speed",storm:"Storm",lensFlareBrightness:"Light intensity",cameraDevice:"Camera/video device",decor:"Decor",decorBuilding:"Building",decorTree:"Tree",decorStreetlight:"Streetlight",decorVehicle:"Vehicle",decorWitness:"Other witness",addDecor:"Add",deleteDecor:"Delete decor",decorEast:"Distance east",decorNorth:"Distance north",decorHeading:"Heading",decorLit:"Lit",decorTitle:"Name",decorSightingUrl:"Witness's own recording URL",viewTestimony:"View testimony",noWitnessRecording:"No recording URL set for this witness",masks:"Masks",addWitness:"Add witness",decorFloors:"Floors",decorOccupiedFloor:"Occupied floor",decorWitnessSide:"Witness location",decorWitnessSideNone:"Not present",decorWindows:"Windows",decorSideFront:"Front",decorSideBehind:"Behind",decorSideLeft:"Left",decorSideRight:"Right",decorSideFrontLeft:"Front-left",decorSideFrontRight:"Front-right",decorSideBehindLeft:"Behind-left",decorSideBehindRight:"Behind-right"},oy=Object.freeze(Object.defineProperty({__proto__:null,ufoRecorderMessages_en:g0},Symbol.toStringTag,{value:"Module"}));Ia();sy();const os={width:48,height:28},Gd=.2,Hd=60,Vd=new Set(["ArrowLeft","ArrowRight","ArrowUp","ArrowDown"]),ti=4,ta="ufo-1",Wd=["oval","polygon"],ly={presetId:"oval",color:"#39ff14",transparency:0,haloScale:1.5};function cy(i){return i.kind==="oval"?"oval":"polygon"}class hy extends HTMLElement{shadow;sceneElement;ufoElement;recordButton;samplingRateInput;presetButtons;presetsGroup;colorInput;transparencyInput;haloScaleInput;sourceSelect;shapeTitleInput;utcOffsetInput;objectSizeInput;objectDistanceInput;apparentSizeOutput;addShapeButton;deleteShapeButton;contextMenu;contextGroupButton;contextUngroupButton;contextBringToFrontButton;contextSendToBackButton;contextDeleteButton;contextAddVertexButton;contextDeleteVertexButton;decorContextMenu;contextViewTestimonyButton;contextMasksSubmenu;labelContextMasks;playPauseButton;seekInput;timeStartLabel;timeEndLabel;loopButton;durationInput;exportButton;importFileInput;importUrlInput;importUrlButton;latInput;lngInput;headingInput;pitchInput;obsTimeInput;obsEndTimeInput;witnessIdInput;witnessDirNameInput;witnessTitleInput;witnessLastNameInput;witnessFirstNamesInput;caseIdInput;descriptionInput;tagsInput;cloudCoverInput;cloudDarknessInput;precipitationTypeSelect;precipitationIntensityInput;windDirectionInput;windSpeedInput;stormInput;lensFlareBrightnessInput;cameraDeviceInput;labelColor;labelTransparency;labelHalo;labelShape;labelShapeTitle;labelUtcOffset;labelObjectSize;labelObjectDistance;labelSamplingRate;labelDuration;labelLatitude;labelLongitude;labelHeading;labelPitch;labelObservationTime;labelObservationEndTime;labelWitnessId;labelWitnessDirName;labelWitnessTitle;labelWitnessLastName;labelWitnessFirstNames;labelCaseId;labelDescription;labelTags;labelWeather;labelImportFile;labelImportUrl;labelShapeGroup;labelTemporalGroup;labelLocationGroup;labelObservationGroup;labelWitnessGroup;labelCircumstancesGroup;labelCloudCover;labelCloudDarkness;labelPrecipitationType;labelPrecipitationIntensity;labelWindDirection;labelWindSpeed;labelStorm;labelLensFlareBrightness;labelCameraDevice;optionPrecipitationNone;optionPrecipitationRain;optionPrecipitationSnow;optionPrecipitationHail;decorKindSelect;addDecorWitnessButton;addDecorBuildingButton;deleteDecorButton;decorSelect;decorTitleInput;decorEastInput;decorNorthInput;decorHeadingInput;decorLitInput;decorSightingUrlInput;decorFloorsInput;decorOccupiedFloorInput;decorWitnessSideSelect;decorWindowInputs;labelDecorSide;optionWitnessSide;labelDecor;labelDecorFieldset;labelDecorTitle;labelDecorEast;labelDecorNorth;labelDecorHeading;labelDecorLit;labelDecorSightingUrl;labelDecorFloors;labelDecorOccupiedFloor;labelDecorWitnessSide;labelDecorWindows;optionWitnessSideNone;optionDecorBuilding;optionDecorTree;optionDecorStreetlight;optionDecorVehicle;optionDecorWitness;recorder;isRecording=!1;messages=g0;currentAppearance={...ly};currentSourceId=ta;selectedSourceIds=new Set([ta]);currentDecorId;contextMenuDecorId;contextMenuPoint;dragState;cameraDragState;hoverCursor;indoorLookYawDeg=0;indoorLookPitchDeg=0;lastInhabitedKey;handleKeyDown=e=>{if(e.key==="Escape"&&(this.isRecording&&this.toggleRecording(),this.contextMenu.hidden||this.hideContextMenu(),this.decorContextMenu.hidden||this.hideDecorContextMenu()),Vd.has(e.key)||e.key==="Delete"||e.key==="Backspace"){const t=e.composedPath()[0];if(t instanceof HTMLInputElement||t instanceof HTMLSelectElement||t instanceof HTMLTextAreaElement)return;Vd.has(e.key)?this.moveOrResizeSelectedShapes(e):this.deleteShape()}};handleDragPointerMove=e=>this.onDragPointerMove(e);handleDragPointerUp=()=>this.endDrag();constructor(){super(),this.shadow=this.attachShadow({mode:"open"});const e=document.createElement("template");e.innerHTML=`<style>${w0}</style>${E0}`,this.shadow.appendChild(e.content.cloneNode(!0)),this.sceneElement=document.createElement(oc),this.sceneElement.setAttribute("show-compass",""),this.ufoElement=this.sceneElement.ufoElement,this.ufoElement.enableClickToPlay=!1,this.ufoElement.showToolbar=!1,this.shadow.getElementById("ufo-slot").replaceWith(this.sceneElement),this.recordButton=this.shadow.getElementById("record"),this.samplingRateInput=this.shadow.getElementById("samplingRate"),this.presetsGroup=this.shadow.getElementById("presets-group"),this.presetButtons={oval:this.shadow.getElementById("preset-oval"),polygon:this.shadow.getElementById("preset-polygon")},this.colorInput=this.shadow.getElementById("color"),this.transparencyInput=this.shadow.getElementById("transparency"),this.haloScaleInput=this.shadow.getElementById("haloScale"),this.sourceSelect=this.shadow.getElementById("source"),this.shapeTitleInput=this.shadow.getElementById("shapeTitle"),this.utcOffsetInput=this.shadow.getElementById("utcOffsetHours"),this.objectSizeInput=this.shadow.getElementById("objectSize"),this.objectDistanceInput=this.shadow.getElementById("objectDistance"),this.apparentSizeOutput=this.shadow.getElementById("apparent-size"),this.addShapeButton=this.shadow.getElementById("add-shape"),this.deleteShapeButton=this.shadow.getElementById("delete-shape"),this.contextMenu=this.shadow.getElementById("context-menu"),this.contextGroupButton=this.shadow.getElementById("context-group"),this.contextUngroupButton=this.shadow.getElementById("context-ungroup"),this.contextBringToFrontButton=this.shadow.getElementById("context-bring-to-front"),this.contextSendToBackButton=this.shadow.getElementById("context-send-to-back"),this.contextDeleteButton=this.shadow.getElementById("context-delete"),this.contextAddVertexButton=this.shadow.getElementById("context-add-vertex"),this.contextDeleteVertexButton=this.shadow.getElementById("context-delete-vertex"),this.decorContextMenu=this.shadow.getElementById("decor-context-menu"),this.contextViewTestimonyButton=this.shadow.getElementById("context-view-testimony"),this.contextMasksSubmenu=this.shadow.getElementById("context-masks-submenu"),this.labelContextMasks=this.shadow.getElementById("label-context-masks"),this.playPauseButton=this.shadow.getElementById("play-pause"),this.seekInput=this.shadow.getElementById("seek"),this.timeStartLabel=this.shadow.getElementById("time-start"),this.timeEndLabel=this.shadow.getElementById("time-end"),this.loopButton=this.shadow.getElementById("loop"),this.durationInput=this.shadow.getElementById("durationSeconds"),this.exportButton=this.shadow.getElementById("export"),this.importFileInput=this.shadow.getElementById("import-file"),this.importUrlInput=this.shadow.getElementById("import-url"),this.importUrlButton=this.shadow.getElementById("import-url-button"),this.latInput=this.shadow.getElementById("lat"),this.lngInput=this.shadow.getElementById("lng"),this.headingInput=this.shadow.getElementById("heading"),this.pitchInput=this.shadow.getElementById("pitch"),this.obsTimeInput=this.shadow.getElementById("obs-time"),this.obsEndTimeInput=this.shadow.getElementById("obs-end-time"),this.witnessIdInput=this.shadow.getElementById("witnessId"),this.witnessDirNameInput=this.shadow.getElementById("witnessDirName"),this.witnessTitleInput=this.shadow.getElementById("witnessTitle"),this.witnessLastNameInput=this.shadow.getElementById("witnessLastName"),this.witnessFirstNamesInput=this.shadow.getElementById("witnessFirstNames"),this.caseIdInput=this.shadow.getElementById("caseId"),this.descriptionInput=this.shadow.getElementById("description"),this.tagsInput=this.shadow.getElementById("tags"),this.cloudCoverInput=this.shadow.getElementById("cloudCover"),this.cloudDarknessInput=this.shadow.getElementById("cloudDarkness"),this.precipitationTypeSelect=this.shadow.getElementById("precipitationType"),this.precipitationIntensityInput=this.shadow.getElementById("precipitationIntensity"),this.windDirectionInput=this.shadow.getElementById("windDirection"),this.windSpeedInput=this.shadow.getElementById("windSpeed"),this.stormInput=this.shadow.getElementById("storm"),this.lensFlareBrightnessInput=this.shadow.getElementById("lensFlareBrightness"),this.cameraDeviceInput=this.shadow.getElementById("cameraDevice"),this.labelColor=this.shadow.getElementById("label-color"),this.labelTransparency=this.shadow.getElementById("label-transparency"),this.labelHalo=this.shadow.getElementById("label-halo"),this.labelShape=this.shadow.getElementById("label-shape"),this.labelShapeTitle=this.shadow.getElementById("label-shape-title"),this.labelUtcOffset=this.shadow.getElementById("label-utc-offset"),this.labelObjectSize=this.shadow.getElementById("label-object-size"),this.labelObjectDistance=this.shadow.getElementById("label-object-distance"),this.labelSamplingRate=this.shadow.getElementById("label-sampling-rate"),this.labelDuration=this.shadow.getElementById("label-duration"),this.labelLatitude=this.shadow.getElementById("label-lat"),this.labelLongitude=this.shadow.getElementById("label-lng"),this.labelHeading=this.shadow.getElementById("label-heading"),this.labelPitch=this.shadow.getElementById("label-pitch"),this.labelObservationTime=this.shadow.getElementById("label-observation-time"),this.labelObservationEndTime=this.shadow.getElementById("label-observation-end-time"),this.labelWitnessId=this.shadow.getElementById("label-witness-id"),this.labelWitnessDirName=this.shadow.getElementById("label-witness-dir-name"),this.labelWitnessTitle=this.shadow.getElementById("label-witness-title"),this.labelWitnessLastName=this.shadow.getElementById("label-witness-last-name"),this.labelWitnessFirstNames=this.shadow.getElementById("label-witness-first-names"),this.labelCaseId=this.shadow.getElementById("label-case-id"),this.labelDescription=this.shadow.getElementById("label-description"),this.labelTags=this.shadow.getElementById("label-tags"),this.labelWeather=this.shadow.getElementById("label-weather"),this.labelImportFile=this.shadow.getElementById("label-import-file"),this.labelImportUrl=this.shadow.getElementById("label-import-url"),this.labelShapeGroup=this.shadow.getElementById("label-shape-group"),this.labelTemporalGroup=this.shadow.getElementById("label-temporal-group"),this.labelLocationGroup=this.shadow.getElementById("label-location-group"),this.labelObservationGroup=this.shadow.getElementById("label-observation-group"),this.labelWitnessGroup=this.shadow.getElementById("label-witness-group"),this.labelCircumstancesGroup=this.shadow.getElementById("label-circumstances-group"),this.labelCloudCover=this.shadow.getElementById("label-cloud-cover"),this.labelCloudDarkness=this.shadow.getElementById("label-cloud-darkness"),this.labelPrecipitationType=this.shadow.getElementById("label-precipitation-type"),this.labelPrecipitationIntensity=this.shadow.getElementById("label-precipitation-intensity"),this.labelWindDirection=this.shadow.getElementById("label-wind-direction"),this.labelWindSpeed=this.shadow.getElementById("label-wind-speed"),this.labelStorm=this.shadow.getElementById("label-storm"),this.labelLensFlareBrightness=this.shadow.getElementById("label-lens-flare-brightness"),this.labelCameraDevice=this.shadow.getElementById("label-camera-device"),this.optionPrecipitationNone=this.shadow.getElementById("option-precipitation-none"),this.optionPrecipitationRain=this.shadow.getElementById("option-precipitation-rain"),this.optionPrecipitationSnow=this.shadow.getElementById("option-precipitation-snow"),this.optionPrecipitationHail=this.shadow.getElementById("option-precipitation-hail"),this.decorKindSelect=this.shadow.getElementById("decorKind"),this.addDecorWitnessButton=this.shadow.getElementById("add-decor-witness"),this.addDecorBuildingButton=this.shadow.getElementById("add-decor-building"),this.deleteDecorButton=this.shadow.getElementById("delete-decor"),this.decorSelect=this.shadow.getElementById("decor"),this.decorTitleInput=this.shadow.getElementById("decorTitle"),this.decorEastInput=this.shadow.getElementById("decorEast"),this.decorNorthInput=this.shadow.getElementById("decorNorth"),this.decorHeadingInput=this.shadow.getElementById("decorHeading"),this.decorLitInput=this.shadow.getElementById("decorLit"),this.decorSightingUrlInput=this.shadow.getElementById("decorSightingUrl"),this.decorFloorsInput=this.shadow.getElementById("decorFloors"),this.decorOccupiedFloorInput=this.shadow.getElementById("decorOccupiedFloor"),this.decorWitnessSideSelect=this.shadow.getElementById("decorWitnessSide"),this.decorWindowInputs={front:this.shadow.getElementById("decorWindowFront"),behind:this.shadow.getElementById("decorWindowBehind"),left:this.shadow.getElementById("decorWindowLeft"),right:this.shadow.getElementById("decorWindowRight"),"front-left":this.shadow.getElementById("decorWindowFrontLeft"),"front-right":this.shadow.getElementById("decorWindowFrontRight"),"behind-left":this.shadow.getElementById("decorWindowBehindLeft"),"behind-right":this.shadow.getElementById("decorWindowBehindRight")},this.labelDecorSide={front:this.shadow.getElementById("label-decor-window-front"),behind:this.shadow.getElementById("label-decor-window-behind"),left:this.shadow.getElementById("label-decor-window-left"),right:this.shadow.getElementById("label-decor-window-right"),"front-left":this.shadow.getElementById("label-decor-window-front-left"),"front-right":this.shadow.getElementById("label-decor-window-front-right"),"behind-left":this.shadow.getElementById("label-decor-window-behind-left"),"behind-right":this.shadow.getElementById("label-decor-window-behind-right")},this.optionWitnessSide={front:this.shadow.getElementById("option-witness-side-front"),behind:this.shadow.getElementById("option-witness-side-behind"),left:this.shadow.getElementById("option-witness-side-left"),right:this.shadow.getElementById("option-witness-side-right"),"front-left":this.shadow.getElementById("option-witness-side-front-left"),"front-right":this.shadow.getElementById("option-witness-side-front-right"),"behind-left":this.shadow.getElementById("option-witness-side-behind-left"),"behind-right":this.shadow.getElementById("option-witness-side-behind-right")},this.optionWitnessSideNone=this.shadow.getElementById("option-witness-side-none"),this.labelDecor=this.shadow.getElementById("label-decor"),this.labelDecorFieldset=this.shadow.getElementById("label-decor-fieldset"),this.labelDecorTitle=this.shadow.getElementById("label-decor-title"),this.labelDecorEast=this.shadow.getElementById("label-decor-east"),this.labelDecorNorth=this.shadow.getElementById("label-decor-north"),this.labelDecorHeading=this.shadow.getElementById("label-decor-heading"),this.labelDecorLit=this.shadow.getElementById("label-decor-lit"),this.labelDecorSightingUrl=this.shadow.getElementById("label-decor-sighting-url"),this.labelDecorFloors=this.shadow.getElementById("label-decor-floors"),this.labelDecorOccupiedFloor=this.shadow.getElementById("label-decor-occupied-floor"),this.labelDecorWitnessSide=this.shadow.getElementById("label-decor-witness-side"),this.labelDecorWindows=this.shadow.getElementById("label-decor-windows"),this.optionDecorBuilding=this.shadow.getElementById("option-decor-building"),this.optionDecorTree=this.shadow.getElementById("option-decor-tree"),this.optionDecorStreetlight=this.shadow.getElementById("option-decor-streetlight"),this.optionDecorVehicle=this.shadow.getElementById("option-decor-vehicle"),this.optionDecorWitness=this.shadow.getElementById("option-decor-witness"),this.ufoElement.canvasElement.addEventListener("pointerdown",t=>this.onPointerDown(t)),this.ufoElement.canvasElement.addEventListener("pointermove",t=>this.onPointerMove(t)),this.ufoElement.canvasElement.addEventListener("contextmenu",t=>this.onContextMenu(t)),this.contextGroupButton.addEventListener("click",()=>this.groupSelected()),this.contextUngroupButton.addEventListener("click",()=>this.ungroupSelected()),this.contextBringToFrontButton.addEventListener("click",()=>this.bringSelectedToFront()),this.contextSendToBackButton.addEventListener("click",()=>this.sendSelectedToBack()),this.contextDeleteButton.addEventListener("click",()=>{this.hideContextMenu(),this.deleteShape()}),this.contextAddVertexButton.addEventListener("click",()=>this.addVertexAtContextMenu()),this.contextDeleteVertexButton.addEventListener("click",()=>this.deleteVertexAtContextMenu()),this.contextViewTestimonyButton.addEventListener("click",()=>this.viewWitnessTestimony()),this.playPauseButton.addEventListener("click",()=>{this.ufoElement.togglePlayPause(),this.syncPlaybackControls()}),this.loopButton.addEventListener("click",()=>{this.ufoElement.toggleLoop(),this.syncPlaybackControls()}),this.seekInput.addEventListener("input",()=>this.ufoElement.currentTime=Number(this.seekInput.value)),this.recordButton.addEventListener("click",()=>this.toggleRecording()),this.addShapeButton.addEventListener("click",()=>this.addShape()),this.deleteShapeButton.addEventListener("click",()=>this.deleteShape()),this.exportButton.addEventListener("click",()=>this.exportJson()),this.importFileInput.addEventListener("change",()=>this.importFromFile()),this.importUrlButton.addEventListener("click",()=>this.importFromUrl()),this.durationInput.addEventListener("input",()=>{this.ufoElement.durationSeconds=this.durationInput.value===""?void 0:Number(this.durationInput.value),this.ufoElement.refresh(),this.updateDurationValidity()}),this.sourceSelect.addEventListener("change",()=>this.selectUnit(this.sourceSelect.value)),this.shapeTitleInput.addEventListener("input",()=>this.updateShapeTitle());for(const t of[this.objectSizeInput,this.objectDistanceInput])t.addEventListener("input",()=>this.updatePhysicalExtent());this.addDecorWitnessButton.addEventListener("click",()=>this.addDecor("witness")),this.addDecorBuildingButton.addEventListener("click",()=>this.addDecor()),this.deleteDecorButton.addEventListener("click",()=>this.deleteDecor()),this.decorSelect.addEventListener("change",()=>this.selectDecor(this.decorSelect.value));for(const t of[this.decorTitleInput,this.decorEastInput,this.decorNorthInput,this.decorHeadingInput,this.decorSightingUrlInput,this.decorFloorsInput,this.decorOccupiedFloorInput])t.addEventListener("input",()=>this.updateDecor());this.decorWitnessSideSelect.addEventListener("change",()=>this.updateDecor());for(const t of is)this.decorWindowInputs[t].addEventListener("input",()=>this.updateDecorWindows());this.decorLitInput.addEventListener("input",()=>this.updateDecorLit()),this.ufoElement.addEventListener("timeupdate",()=>{this.onSelectionOrTimeChanged(),this.syncPlaybackControls(),this.dispatchEvent(new CustomEvent("sightingchange"))}),document.addEventListener("keydown",this.handleKeyDown);for(const t of Wd)this.presetButtons[t].addEventListener("click",()=>this.setAppearance({presetId:t}));this.colorInput.addEventListener("input",()=>this.setAppearance({color:this.colorInput.value})),this.transparencyInput.addEventListener("input",()=>this.setAppearance({transparency:Number(this.transparencyInput.value)})),this.haloScaleInput.addEventListener("input",()=>this.setAppearance({haloScale:Number(this.haloScaleInput.value)}));for(const t of[this.latInput,this.lngInput,this.headingInput,this.pitchInput])t.addEventListener("input",()=>this.updateObserver());this.headingInput.addEventListener("focus",()=>this.sceneElement.setCompassForced(!0)),this.headingInput.addEventListener("blur",()=>this.sceneElement.setCompassForced(!1)),this.lensFlareBrightnessInput.addEventListener("input",()=>this.sceneElement.setAttribute("lens-flare-brightness",this.lensFlareBrightnessInput.value)),this.cameraDeviceInput.addEventListener("input",()=>this.sceneElement.setAttribute("lens-flare-intensity",this.cameraDeviceInput.value)),this.utcOffsetInput.addEventListener("input",()=>this.updateUtcOffset()),this.obsTimeInput.addEventListener("input",()=>this.updateObservationTime()),this.obsEndTimeInput.addEventListener("input",()=>this.updateObservationEndTime()),this.obsTimeInput.addEventListener("blur",()=>this.validateEdtfTimeInput(this.obsTimeInput)),this.obsEndTimeInput.addEventListener("blur",()=>this.validateEdtfTimeInput(this.obsEndTimeInput));for(const t of[this.witnessIdInput,this.witnessDirNameInput,this.witnessTitleInput,this.witnessLastNameInput,this.witnessFirstNamesInput,this.caseIdInput])t.addEventListener("input",()=>this.updateWitnessMetadata());this.descriptionInput.addEventListener("input",()=>this.updateDescription()),this.tagsInput.addEventListener("input",()=>this.updateTags());for(const t of[this.cloudCoverInput,this.cloudDarknessInput,this.precipitationTypeSelect,this.precipitationIntensityInput,this.windDirectionInput,this.windSpeedInput,this.stormInput])t.addEventListener("input",()=>this.applyWeatherAtPlayhead());this.updatePresetButtons(),this.setRecordButtonLabel(!1),this.applyAppearanceAtPlayhead(),this.shapeTitleInput.value=this.shapeLabel(this.currentSourceId),this.updateShapeTitle(),this.currentDecorId=this.ufoElement.sighting.decor[0]?.id,this.refreshDecorList(),this.onSelectionOrTimeChanged(),this.syncDurationField(),this.syncPlaybackControls(),this.loadLocaleMessages()}disconnectedCallback(){document.removeEventListener("keydown",this.handleKeyDown),document.removeEventListener("click",this.handleOutsideContextMenuClick),this.endDrag()}get sightingData(){return this.ufoElement.sightingData}set sightingData(e){this.endDrag(),this.ufoElement.sightingData=e,this.currentSourceId=this.ufoElement.sighting.timeline.sourceIds[0]??ta,this.selectedSourceIds=new Set([this.currentSourceId]),this.refreshSourceList(),this.currentDecorId=this.ufoElement.sighting.decor[0]?.id,this.refreshDecorList(),this.onSelectionOrTimeChanged(),this.syncDurationField(),this.syncObservationTimeFields(),this.syncObservationEndTimeFields(),this.syncWitnessMetadataFields()}exportJson(){const e=this.sightingData,t=`${e.witness?.id??"sighting"}-sighting.json`,n=new Blob([JSON.stringify(e,null,2)],{type:"application/json"}),s=URL.createObjectURL(n),r=document.createElement("a");r.href=s,r.download=t,r.click(),URL.revokeObjectURL(s)}async importFromFile(){const e=this.importFileInput.files?.[0];if(e)try{const t=await new Promise((n,s)=>{const r=new FileReader;r.onload=()=>n(r.result),r.onerror=()=>s(r.error),r.readAsText(e)});this.sightingData=JSON.parse(t)}catch{window.alert(this.messages.importError)}finally{this.importFileInput.value=""}}async importFromUrl(e=this.importUrlInput.value.trim()){if(e)try{const t=await fetch(e);if(!t.ok)throw new Error(`HTTP ${t.status}`);this.sightingData=await t.json()}catch{window.alert(this.messages.importError)}}numberOrUndefined(e){return e===""?void 0:Number(e)}stringOrUndefined(e){return e===""?void 0:e}wrapDegrees(e,t){if(e===void 0)return;const n=(e%360+360)%360;return String(n)!==t.value&&(t.value=String(n)),n}updateObserver(){if(this.ufoElement.playbackState==="playing")return;const e=this.numberOrUndefined(this.latInput.value),t=this.numberOrUndefined(this.lngInput.value),n=this.wrapDegrees(this.numberOrUndefined(this.headingInput.value),this.headingInput),s=this.numberOrUndefined(this.pitchInput.value)??0,r=this.ufoElement.sighting.event,a=this.ufoElement.sighting.witnessTrack,o=this.ufoElement.currentTime;r.place=e!==void 0&&t!==void 0?[{lat:e,lng:t}]:void 0,e===void 0&&t===void 0&&n===void 0&&s===0?a.removeKeyframeAt(o):a.addKeyframe(o,{lat:e,lng:t,elevationM:0,headingDeg:n,pitchDeg:s,fovDeg:Hd}),this.ufoElement.refresh()}applyEdtfTimeInput(e,t){const n=e.value.trim();if(n==="")t(void 0);else{const s=Vc(n);if(!s)return;t(s)}e.setCustomValidity(""),e.classList.remove("invalid"),this.ufoElement.refresh(),this.syncDurationField()}validateEdtfTimeInput(e){const t=e.value.trim();t===""||Vc(t)||(e.setCustomValidity(this.messages.edtfInvalid),e.classList.add("invalid"))}updateUtcOffset(){this.ufoElement.sighting.event.utcOffsetHours=this.numberOrUndefined(this.utcOffsetInput.value),this.ufoElement.refresh()}updateObservationTime(){this.applyEdtfTimeInput(this.obsTimeInput,e=>{this.ufoElement.sighting.event.time=e})}updateObservationEndTime(){this.applyEdtfTimeInput(this.obsEndTimeInput,e=>{this.ufoElement.sighting.event.endTime=e})}updateWitnessMetadata(){const e=this.ufoElement.sighting,t=this.witnessFirstNamesInput.value.split(",").map(s=>s.trim()).filter(s=>s.length>0),n={id:this.stringOrUndefined(this.witnessIdInput.value),dirName:this.stringOrUndefined(this.witnessDirNameInput.value),title:this.stringOrUndefined(this.witnessTitleInput.value),lastName:this.stringOrUndefined(this.witnessLastNameInput.value),firstNames:t.length>0?t:void 0};e.witness=Object.values(n).some(s=>s!==void 0)?n:void 0,e.caseId=this.stringOrUndefined(this.caseIdInput.value),this.ufoElement.refresh()}updateDescription(){this.ufoElement.sighting.event.description=this.stringOrUndefined(this.descriptionInput.value),this.ufoElement.refresh()}updateTags(){const e=this.tagsInput.value.split(",").map(t=>t.trim()).filter(t=>t.length>0);this.ufoElement.sighting.event.tags=e.length>0?e:void 0,this.ufoElement.refresh()}applyWeatherAtPlayhead(){if(this.ufoElement.playbackState==="playing")return;this.sceneElement.resumeWeatherAudio();const e={cloudCover:Number(this.cloudCoverInput.value),cloudDarkness:Number(this.cloudDarknessInput.value),precipitationType:this.precipitationTypeSelect.value,precipitationIntensity:Number(this.precipitationIntensityInput.value),windDirectionDeg:this.wrapDegrees(this.numberOrUndefined(this.windDirectionInput.value),this.windDirectionInput)??0,windSpeed:Number(this.windSpeedInput.value),storm:this.stormInput.checked};this.ufoElement.sighting.weatherTrack.addKeyframe(this.ufoElement.currentTime,e),this.ufoElement.refresh()}syncDurationField(){if(this.shadow.activeElement!==this.durationInput){const e=lc(this.ufoElement.sighting.event);this.durationInput.value=e!==void 0?String(e/1e3):""}this.updateDurationValidity()}updateDurationValidity(){const e=this.durationInput.value==="";this.durationInput.classList.toggle("invalid",e),this.durationInput.setAttribute("aria-invalid",String(e));const t=X0(this.ufoElement.sighting.event);this.durationInput.title=t==="imprecise"?this.messages.durationImprecise:""}syncPlaybackControls(){const e=this.ufoElement.playbackState==="playing",t=this.ufoElement.seekableDuration>0;this.playPauseButton.textContent=e?"⏸":"▶",this.playPauseButton.disabled=!t;const n=t?e?this.messages.pause:this.messages.play:this.messages.noDuration;this.playPauseButton.title=n,this.playPauseButton.setAttribute("aria-label",n),this.loopButton.setAttribute("aria-pressed",String(this.ufoElement.autoReplayEnabled)),this.seekInput.max=String(this.ufoElement.seekableDuration),this.shadow.activeElement!==this.seekInput&&(this.seekInput.value=String(this.ufoElement.currentTime)),this.timeStartLabel.textContent=this.ufoElement.positionLabel,this.timeEndLabel.textContent=this.ufoElement.durationLabel}syncObservationTimeFields(){const e=this.ufoElement.sighting.event.time;this.obsTimeInput.value=e?Wc(e):"",this.obsTimeInput.setCustomValidity(""),this.obsTimeInput.classList.remove("invalid")}syncObservationEndTimeFields(){const e=this.ufoElement.sighting.event.endTime;this.obsEndTimeInput.value=e?Wc(e):"",this.obsEndTimeInput.setCustomValidity(""),this.obsEndTimeInput.classList.remove("invalid")}syncWitnessMetadataFields(){const e=this.ufoElement.sighting;this.witnessIdInput.value=e.witness?.id??"",this.witnessDirNameInput.value=e.witness?.dirName??"",this.witnessTitleInput.value=e.witness?.title??"",this.witnessLastNameInput.value=e.witness?.lastName??"",this.witnessFirstNamesInput.value=e.witness?.firstNames?.join(", ")??"",this.caseIdInput.value=e.caseId??"",this.descriptionInput.value=e.event.description??"",this.tagsInput.value=e.event.tags?.join(", ")??""}syncWeatherFromTimeline(){if(this.ufoElement.playbackState==="playing")return;const e=zo(this.ufoElement.sighting,this.ufoElement.currentTime),t=this.shadow.activeElement;t!==this.cloudCoverInput&&(this.cloudCoverInput.value=String(e.cloudCover)),t!==this.cloudDarknessInput&&(this.cloudDarknessInput.value=String(e.cloudDarkness)),t!==this.precipitationTypeSelect&&(this.precipitationTypeSelect.value=e.precipitationType),t!==this.precipitationIntensityInput&&(this.precipitationIntensityInput.value=String(e.precipitationIntensity)),t!==this.windDirectionInput&&(this.windDirectionInput.value=String(e.windDirectionDeg)),t!==this.windSpeedInput&&(this.windSpeedInput.value=String(e.windSpeed)),t!==this.stormInput&&(this.stormInput.checked=e.storm)}syncObserverFromTimeline(){if(this.ufoElement.playbackState==="playing")return;const e=this.ufoElement.sighting,t=e.witnessTrack.getInterpolatedPoseAt(this.ufoElement.currentTime),n=e.event.place?.[0],s=this.shadow.activeElement;s!==this.latInput&&(this.latInput.value=t?.lat!==void 0?String(t.lat):n?String(n.lat):""),s!==this.lngInput&&(this.lngInput.value=t?.lng!==void 0?String(t.lng):n?String(n.lng):""),s!==this.headingInput&&(this.headingInput.value=t?.headingDeg!==void 0?String(t.headingDeg):""),s!==this.pitchInput&&(this.pitchInput.value=String(t?.pitchDeg??0))}get appearance(){return{...this.currentAppearance}}set appearance(e){this.setAppearance(e)}setAppearance(e){const t="presetId"in e;this.currentAppearance={...this.currentAppearance,...e},this.updatePresetButtons(),!(this.isRecording||this.ufoElement.playbackState==="playing")&&this.applyAppearanceAtPlayhead(void 0,t)}applyAppearanceAtPlayhead(e,t=!0){const n=this.ufoElement.sighting.timeline,s=this.ufoElement.currentTime,r=n.getInterpolatedShapeAt(s,this.currentSourceId),a=this.buildAppearanceShape(e??r?.bounds??this.defaultBounds(),r,t);n.addKeyframe(s,[{sourceId:this.currentSourceId,shape:a}]),this.ufoElement.refresh()}buildAppearanceShape(e,t,n=!0){if(t&&!n)return{...t,color:this.currentAppearance.color,transparency:this.currentAppearance.transparency,haloScale:this.currentAppearance.haloScale};const s=Gc(e,this.currentAppearance);return t?{...s,angle:t.angle,title:t.title,selected:t.selected}:s}onSelectionOrTimeChanged(){this.syncAppearanceFromTimeline(),this.syncObserverFromTimeline(),this.syncWeatherFromTimeline(),this.syncDecorLitFromTimeline(),this.syncIndoorLookReset(),this.updateAppearanceFieldsDisabledState(),this.updateShapeTitleValidity(),this.ufoElement.selectedSourceIds=this.selectedSourceIds;const e=this.ufoElement.sighting.timeline.sourceIds,t=e.filter(n=>this.selectedSourceIds.has(n)).length;this.deleteShapeButton.disabled=this.isRecording||this.ufoElement.playbackState==="playing"||t===0||e.length-t<1}updateAppearanceFieldsDisabledState(){const e=this.selectedSourceIds.size>1,t=e?this.messages.multipleShapesSelected:"";for(const n of[this.shapeTitleInput,this.colorInput,this.transparencyInput,this.haloScaleInput,this.objectSizeInput,this.objectDistanceInput,this.sourceSelect,...Object.values(this.presetButtons)])n.disabled=e,n.title=t}syncAppearanceFromTimeline(){if(this.ufoElement.playbackState==="playing"||this.selectedSourceIds.size>1)return;const e=this.ufoElement.sighting.timeline.getInterpolatedShapeAt(this.ufoElement.currentTime,this.currentSourceId);e&&(this.currentAppearance={presetId:cy(e),color:e.color,transparency:e.transparency,haloScale:e.haloScale},this.updatePresetButtons(),this.colorInput.value=this.currentAppearance.color,this.transparencyInput.value=String(this.currentAppearance.transparency),this.haloScaleInput.value=String(this.currentAppearance.haloScale),this.shadow.activeElement!==this.shapeTitleInput&&(this.shapeTitleInput.value=e.title??""),this.shadow.activeElement!==this.objectSizeInput&&(this.objectSizeInput.value=e.physical?String(Number(e.physical.sizeM.toFixed(2))):""),this.shadow.activeElement!==this.objectDistanceInput&&(this.objectDistanceInput.value=e.physical?String(Number(e.physical.distanceM.toFixed(2))):""),this.refreshApparentSize())}updateShapeTitle(){const e=this.ufoElement.sighting.timeline,t=this.ufoElement.currentTime,n=e.getInterpolatedShapeAt(t,this.currentSourceId);n&&(e.addKeyframe(t,[{sourceId:this.currentSourceId,shape:{...n,title:this.stringOrUndefined(this.shapeTitleInput.value)}}]),this.ufoElement.refresh(),this.refreshSourceList(),this.updateShapeTitleValidity())}updatePhysicalExtent(){const e=this.ufoElement.sighting.timeline,t=this.ufoElement.currentTime,n=e.getInterpolatedShapeAt(t,this.currentSourceId);if(!n)return;const s=this.numberOrUndefined(this.objectSizeInput.value),r=this.numberOrUndefined(this.objectDistanceInput.value);if(s===void 0&&r===void 0){e.addKeyframe(t,[{sourceId:this.currentSourceId,shape:{...n,physical:void 0}}]),this.ufoElement.refresh(),this.refreshApparentSize();return}if(s===void 0||r===void 0||s<=0||r<=0){this.refreshApparentSize();return}const a={sizeM:s,distanceM:r},o=this.ufoElement.canvasElement,l=fs.widthPx(a,o.height,this.currentFovDeg()),c=n.bounds.height*(n.bounds.width===0?1:l/n.bounds.width),h={x:n.bounds.x+(n.bounds.width-l)/2,y:n.bounds.y+(n.bounds.height-c)/2,width:l,height:c},u=n.kind==="oval"?{...n,bounds:h,physical:a}:{...n,bounds:h,physical:a,points:this.scalePoints(n,h)};e.addKeyframe(t,[{sourceId:this.currentSourceId,shape:u}]),this.ufoElement.refresh(),this.refreshApparentSize()}scalePoints(e,t){const n=e.bounds.width===0?1:t.width/e.bounds.width,s=e.bounds.height===0?1:t.height/e.bounds.height;return e.points.map(r=>({x:r.x*n,y:r.y*s}))}currentFovDeg(){return Bo(this.ufoElement.sighting,this.ufoElement.currentTime)?.fovDeg??Hd}refreshApparentSize(){const e=this.selectedSourceIds.size===1?this.ufoElement.sighting.timeline.getInterpolatedShapeAt(this.ufoElement.currentTime,this.currentSourceId):void 0;if(!e){this.apparentSizeOutput.textContent="";return}const t=this.ufoElement.canvasElement,n=fs.pxToDeg(e.bounds.width,t.height,this.currentFovDeg()),s=fs.inMoons(n);this.apparentSizeOutput.textContent=this.messages.apparentSize.replace("{deg}",n.toLocaleString(void 0,{maximumFractionDigits:n<1?2:1})).replace("{moons}",s.toLocaleString(void 0,{maximumFractionDigits:s<10?1:0}))}updateShapeTitleValidity(){const e=this.selectedSourceIds.size===1&&this.shapeTitleInput.value==="";this.shapeTitleInput.classList.toggle("invalid",e),this.shapeTitleInput.setAttribute("aria-invalid",String(e))}shapeLabel(e){const t=this.ufoElement.sighting.timeline.getInterpolatedShapeAt(this.ufoElement.currentTime,e);if(t?.title)return t.title;const n=/^ufo-(\d+)$/.exec(e);return n?`${this.messages.shape} ${n[1]}`:e}addShape(){if(this.isRecording)return;const e=this.ufoElement.sighting.timeline,t=new Set([...e.sourceIds,this.currentSourceId]);let n=t.size+1;for(;t.has(`ufo-${n}`);)n++;this.currentSourceId=`ufo-${n}`,this.selectedSourceIds=new Set([this.currentSourceId]),this.applyAppearanceAtPlayhead(this.offsetDefaultBounds(e.sourceIds.length)),this.shapeTitleInput.value=this.shapeLabel(this.currentSourceId),this.updateShapeTitle()}deleteShape(){if(this.isRecording||this.ufoElement.playbackState==="playing")return;const e=this.ufoElement.sighting.timeline,t=e.sourceIds.filter(s=>this.selectedSourceIds.has(s));if(!(t.length===0||e.sourceIds.length-t.length<1||!(t.length===1?window.confirm(this.messages.confirmDeleteShape.replace("{name}",this.shapeLabel(t[0]))):window.confirm(this.messages.confirmDeleteShapes.replace("{count}",String(t.length)))))){for(const s of t)e.removeSource(s);this.currentSourceId=e.sourceIds[0],this.selectedSourceIds=new Set([this.currentSourceId]),this.refreshSourceList(),this.ufoElement.refresh()}}offsetDefaultBounds(e){const t=this.defaultBounds(),n=24;return{...t,x:t.x+e*n,y:t.y+e*n}}refreshSourceList(){const e=this.ufoElement.sighting.timeline,t=[...new Set([...e.sourceIds,this.currentSourceId])];this.sourceSelect.innerHTML="";for(const n of t){const s=document.createElement("option");s.value=n,s.textContent=this.shapeLabel(n),this.sourceSelect.appendChild(s)}this.sourceSelect.value=this.currentSourceId}decorLabel(e){if(e.title)return e.title;const n=this.ufoElement.sighting.decor.filter(r=>r.kind===e.kind).indexOf(e)+1;return`${this.decorKindSelect.querySelector(`option[value="${e.kind}"]`)?.textContent??e.kind} ${n}`}addDecor(e=this.decorKindSelect.value){const t=this.ufoElement.sighting,s={id:`decor-${t.decor.length+1}`,kind:e,title:this.nextDecorLabel(e),eastM:8*t.decor.length,northM:15,headingDeg:0,lit:!1,...e==="building"?{floors:ca}:{},windows:U2(e)};t.decor=[...t.decor,s],this.currentDecorId=s.id,this.refreshDecorList(),this.ufoElement.refresh()}nextDecorLabel(e){const t=this.ufoElement.sighting.decor.filter(s=>s.kind===e).length;return`${this.decorKindSelect.querySelector(`option[value="${e}"]`)?.textContent??e} ${t+1}`}deleteDecor(){if(this.currentDecorId===void 0)return;const e=this.ufoElement.sighting;e.decor=e.decor.filter(t=>t.id!==this.currentDecorId),this.currentDecorId=e.decor[0]?.id,this.refreshDecorList(),this.ufoElement.refresh()}selectDecor(e){this.currentDecorId=e,this.decorSelect.value=e,this.syncDecorFields()}updateDecor(){if(this.currentDecorId===void 0)return;const e=this.ufoElement.sighting,t=this.wrapDegrees(Number(this.decorHeadingInput.value),this.decorHeadingInput)??0,n=this.decorWitnessSideSelect.value;e.decor=e.decor.map(s=>{if(s.id!==this.currentDecorId)return s;const r=$s(s.kind)&&n!==""?n:void 0;return{...s,title:this.stringOrUndefined(this.decorTitleInput.value),eastM:Number(this.decorEastInput.value),northM:Number(this.decorNorthInput.value),headingDeg:t,sightingUrl:this.stringOrUndefined(this.decorSightingUrlInput.value),witnessSide:r,floors:s.kind==="building"?Number(this.decorFloorsInput.value):void 0,occupiedFloor:s.kind==="building"?Number(this.decorOccupiedFloorInput.value):void 0}}),this.decorSelect.options[this.decorSelect.selectedIndex].textContent=this.decorLabel(e.decor.find(s=>s.id===this.currentDecorId)),this.syncDecorVisibility(),this.updateDecorTitleValidity(),this.ufoElement.refresh()}updateDecorTitleValidity(){const e=this.currentDecorId!==void 0&&this.decorTitleInput.value==="";this.decorTitleInput.classList.toggle("invalid",e),this.decorTitleInput.setAttribute("aria-invalid",String(e))}updateDecorWindows(){if(this.currentDecorId===void 0)return;const e=this.ufoElement.sighting;e.decor=e.decor.map(t=>{if(t.id!==this.currentDecorId)return t;const n={};for(const s of is){const r=this.decorWindowInputs[s];if(r.value==="")continue;const a=tc(t.kind,s)?0:ec,o=Math.max(a,Math.min(100,Number(r.value)));n[s]=o,String(o)!==r.value&&(r.value=String(o))}return{...t,windows:n}}),this.ufoElement.refresh()}updateDecorLit(){if(this.currentDecorId===void 0||this.ufoElement.playbackState==="playing")return;const e=this.ufoElement.sighting,t=this.ufoElement.currentTime,n=this.decorLitInput.checked;e.decor=e.decor.map(s=>{if(s.id!==this.currentDecorId)return s;const r=[...(s.litKeyframes??[]).filter(a=>a.t!==t),{t,lit:n}].sort((a,o)=>a.t-o.t);return{...s,litKeyframes:r}}),this.ufoElement.refresh()}refreshDecorList(){const e=this.ufoElement.sighting.decor;this.decorSelect.innerHTML="";for(const t of e){const n=document.createElement("option");n.value=t.id,n.textContent=this.decorLabel(t),this.decorSelect.appendChild(n)}this.currentDecorId!==void 0&&(this.decorSelect.value=this.currentDecorId),this.syncDecorFields()}syncDecorFields(){const e=this.ufoElement.sighting.decor.find(n=>n.id===this.currentDecorId),t=e!==void 0;this.deleteDecorButton.disabled=!t;for(const n of[this.decorSelect,this.decorTitleInput,this.decorEastInput,this.decorNorthInput,this.decorHeadingInput,this.decorLitInput,this.decorSightingUrlInput,this.decorFloorsInput,this.decorOccupiedFloorInput,this.decorWitnessSideSelect])n.disabled=!t;this.decorTitleInput.value=e?.title??"",this.decorEastInput.value=String(e?.eastM??0),this.decorNorthInput.value=String(e?.northM??0),this.decorHeadingInput.value=String(e?.headingDeg??0),this.decorLitInput.checked=e?nc(e,this.ufoElement.currentTime):!1,this.decorSightingUrlInput.value=e?.sightingUrl??"",this.decorFloorsInput.value=String(e?.floors??ca),this.decorOccupiedFloorInput.value=String(e?.occupiedFloor??0),this.decorWitnessSideSelect.value=e?.witnessSide??"";for(const n of is){const s=e?.windows?.[n];this.decorWindowInputs[n].value=s===void 0?"":String(s)}this.syncDecorVisibility(),this.updateDecorTitleValidity()}setRowVisible(e,t){const n=e.closest("label")??e;n.hidden=!t}syncDecorVisibility(){const e=this.ufoElement.sighting.decor.find(c=>c.id===this.currentDecorId),t=e!==void 0,n=e?.kind;this.setRowVisible(this.decorSelect,t),this.setRowVisible(this.deleteDecorButton,t),this.setRowVisible(this.decorTitleInput,t),this.setRowVisible(this.decorEastInput,t),this.setRowVisible(this.decorNorthInput,t),this.setRowVisible(this.decorHeadingInput,t),this.setRowVisible(this.decorLitInput,t);const s=t&&n!==void 0&&s0(n);this.setRowVisible(this.labelDecorWindows,s);const r=n!==void 0?Dc(n):[];for(const c of is)this.decorWindowInputs[c].disabled=!t,this.decorWindowInputs[c].min=String(n!==void 0&&tc(n,c)?0:ec),this.setRowVisible(this.decorWindowInputs[c],s&&r.includes(c));const a=t&&n!==void 0&&$s(n);this.setRowVisible(this.decorWitnessSideSelect,a);const o=n!==void 0?L2(n):[];for(const c of is)this.optionWitnessSide[c].hidden=!o.includes(c);const l=t&&n==="building";this.setRowVisible(this.decorFloorsInput,l),this.setRowVisible(this.decorOccupiedFloorInput,l),this.decorOccupiedFloorInput.max=String(e?.floors??ca)}syncDecorLitFromTimeline(){if(this.ufoElement.playbackState==="playing"||this.shadow.activeElement===this.decorLitInput)return;const e=this.ufoElement.sighting.decor.find(t=>t.id===this.currentDecorId);e&&(this.decorLitInput.checked=nc(e,this.ufoElement.currentTime))}updatePresetButtons(){for(const e of Wd)this.presetButtons[e]?.setAttribute("aria-pressed",String(e===this.currentAppearance.presetId))}get samplingRate(){return Number(this.samplingRateInput.value)}buildPrototype(e=this.defaultBounds()){return Gc(e,this.currentAppearance)}defaultBounds(){const e=this.ufoElement.canvasElement;return{x:e.width/2-os.width/2,y:e.height/2-os.height/2,width:os.width,height:os.height}}toggleRecording(){this.endDrag();const e=this.ufoElement.canvasElement;this.isRecording?(this.recorder?.stop(),this.isRecording=!1,this.setRecordButtonLabel(!1),this.setCanvasCursor(void 0),e.style.touchAction="",this.sourceSelect.disabled=!1,this.addShapeButton.disabled=!1,this.ufoElement.refresh(),this.refreshSourceList()):(this.recorder=new ry(this.ufoElement.sighting.timeline,new ay(this.samplingRate)),this.recorder.start(this.currentSourceId,this.buildPrototype()),this.isRecording=!0,this.setRecordButtonLabel(!0),this.setCanvasCursor("record"),e.style.touchAction="none",this.sourceSelect.disabled=!0,this.addShapeButton.disabled=!0,this.deleteShapeButton.disabled=!0)}setRecordButtonLabel(e){this.recordButton.textContent=e?"⏹":"⏺";const t=e?this.messages.stop:this.messages.record;this.recordButton.title=t,this.recordButton.setAttribute("aria-label",t)}async loadLocaleMessages(){const e=Aa(navigator.languages,Zd);e!=="en"&&this.applyMessages(await cf(e))}applyMessages(e){this.currentSourceId===ta&&this.shapeTitleInput.value===`${this.messages.shape} 1`?(this.messages=e,this.shapeTitleInput.value=`${this.messages.shape} 1`,this.updateShapeTitle()):this.messages=e,this.presetButtons.oval.textContent=e.oval,this.presetButtons.polygon.textContent=e.polygon,this.contextAddVertexButton.textContent=e.addVertex,this.contextDeleteVertexButton.textContent=e.deleteVertex,this.labelColor.textContent=e.color,this.labelTransparency.textContent=e.transparency,this.labelHalo.textContent=e.halo,this.labelShape.textContent=e.shape,this.labelShapeTitle.textContent=e.shapeTitle,this.labelUtcOffset.textContent=e.utcOffset,this.utcOffsetInput.placeholder=e.utcOffsetPlaceholder,this.labelObjectSize.textContent=e.objectSize,this.labelObjectDistance.textContent=e.objectDistance,this.objectSizeInput.placeholder=e.objectSizePlaceholder,this.objectDistanceInput.placeholder=e.objectDistancePlaceholder,this.refreshApparentSize(),this.labelSamplingRate.textContent=e.samplingRate,this.labelDuration.textContent=e.duration,this.durationInput.placeholder=e.durationPlaceholder,this.addShapeButton.title=e.addShape,this.addShapeButton.setAttribute("aria-label",e.addShape),this.deleteShapeButton.title=e.deleteShape,this.deleteShapeButton.setAttribute("aria-label",e.deleteShape),this.contextGroupButton.textContent=e.group,this.contextUngroupButton.textContent=e.ungroup,this.contextBringToFrontButton.textContent=e.bringToFront,this.contextSendToBackButton.textContent=e.sendToBack,this.contextDeleteButton.textContent=e.contextMenuDelete,this.exportButton.textContent=e.export,this.labelImportFile.textContent=e.importFile,this.labelImportUrl.textContent=e.importUrl,this.importUrlInput.placeholder=e.importUrlPlaceholder,this.importUrlButton.textContent=e.importButton,this.labelLatitude.textContent=e.latitude,this.labelLongitude.textContent=e.longitude,this.labelHeading.textContent=e.heading,this.headingInput.placeholder=e.headingPlaceholder,this.labelPitch.textContent=e.pitch,this.labelObservationTime.textContent=e.observationTime,this.labelObservationEndTime.textContent=e.observationEndTime,this.obsTimeInput.placeholder=e.edtfPlaceholder,this.obsTimeInput.title=e.observationTimeHint,this.obsEndTimeInput.placeholder=e.edtfPlaceholder,this.obsEndTimeInput.title=e.observationEndTimeHint,this.presetsGroup.setAttribute("aria-label",e.presetsGroupLabel),this.labelDecor.textContent=e.decor,this.labelDecorFieldset.textContent=e.decor,this.optionDecorBuilding.textContent=e.decorBuilding,this.optionDecorTree.textContent=e.decorTree,this.optionDecorStreetlight.textContent=e.decorStreetlight,this.optionDecorVehicle.textContent=e.decorVehicle,this.optionDecorWitness.textContent=e.decorWitness,this.deleteDecorButton.title=e.deleteDecor,this.deleteDecorButton.setAttribute("aria-label",e.deleteDecor),this.labelDecorTitle.textContent=e.decorTitle,this.labelDecorEast.textContent=e.decorEast,this.labelDecorNorth.textContent=e.decorNorth,this.labelDecorHeading.textContent=e.decorHeading,this.labelDecorLit.textContent=e.decorLit,this.labelDecorSightingUrl.textContent=e.decorSightingUrl,this.contextViewTestimonyButton.textContent=e.viewTestimony,this.labelContextMasks.textContent=`${e.masks} ▸`,this.addDecorWitnessButton.textContent=e.addWitness,this.addDecorBuildingButton.title=e.addDecor,this.addDecorBuildingButton.setAttribute("aria-label",e.addDecor),this.labelDecorFloors.textContent=e.decorFloors,this.labelDecorOccupiedFloor.textContent=e.decorOccupiedFloor,this.labelDecorWitnessSide.textContent=e.decorWitnessSide,this.labelDecorWindows.textContent=e.decorWindows,this.optionWitnessSideNone.textContent=e.decorWitnessSideNone;const t={front:e.decorSideFront,behind:e.decorSideBehind,left:e.decorSideLeft,right:e.decorSideRight,"front-left":e.decorSideFrontLeft,"front-right":e.decorSideFrontRight,"behind-left":e.decorSideBehindLeft,"behind-right":e.decorSideBehindRight};for(const n of is)this.labelDecorSide[n].textContent=t[n],this.optionWitnessSide[n].textContent=t[n];this.refreshDecorList(),this.labelWitnessId.textContent=e.witnessId,this.labelWitnessDirName.textContent=e.witnessDirName,this.labelWitnessTitle.textContent=e.witnessTitle,this.labelWitnessLastName.textContent=e.witnessLastName,this.labelWitnessFirstNames.textContent=e.witnessFirstNames,this.witnessFirstNamesInput.placeholder=e.tagsPlaceholder,this.labelCaseId.textContent=e.caseId,this.labelDescription.textContent=e.description,this.labelTags.textContent=e.tags,this.tagsInput.placeholder=e.tagsPlaceholder,this.labelWeather.textContent=e.weather,this.labelShapeGroup.textContent=e.shapeGroup,this.labelTemporalGroup.textContent=e.temporalGroup,this.labelLocationGroup.textContent=e.locationGroup,this.labelObservationGroup.textContent=e.observationGroup,this.labelWitnessGroup.textContent=e.witnessGroup,this.labelCircumstancesGroup.textContent=e.circumstancesGroup,this.labelCloudCover.textContent=e.cloudCover,this.labelCloudDarkness.textContent=e.cloudDarkness,this.labelPrecipitationType.textContent=e.precipitationType,this.optionPrecipitationNone.textContent=e.precipitationNone,this.optionPrecipitationRain.textContent=e.precipitationRain,this.optionPrecipitationSnow.textContent=e.precipitationSnow,this.optionPrecipitationHail.textContent=e.precipitationHail,this.labelPrecipitationIntensity.textContent=e.precipitationIntensity,this.labelWindDirection.textContent=e.windDirection,this.labelWindSpeed.textContent=e.windSpeed,this.labelStorm.textContent=e.storm,this.labelLensFlareBrightness.textContent=e.lensFlareBrightness,this.labelCameraDevice.textContent=e.cameraDevice,this.loopButton.title=e.autoReplay,this.loopButton.setAttribute("aria-label",e.autoReplay),this.setRecordButtonLabel(this.isRecording),this.syncPlaybackControls()}onPointerDown(e){if(this.isRecording){this.onPointerMove(e);return}const t=this.canvasPointFromEvent(e);if(!t)return;const n=this.ufoElement.sighting.timeline,s=this.ufoElement.currentTime,r=this.ufoElement.playbackState==="playing";if(this.selectedSourceIds.size>1){const l=new Ba(this.selectedMembers()),c=Ke.hitTestHandle({bounds:l.bounds(),angle:0},t);if(c==="rotate"){if(r)return;this.dragState={kind:"group-rotate",group:l,startPointer:t},this.startDragListening();return}if(c){if(r)return;this.dragState={kind:"group-resize",group:l,handle:c},this.startDragListening();return}}else{const l=n.getInterpolatedShapeAt(s,this.currentSourceId),c=l?.kind==="polygon"?Ke.hitTestVertex(l,t):void 0;if(l?.kind==="polygon"&&c!==void 0){if(r)return;this.dragState={kind:"vertex",sourceId:this.currentSourceId,original:l,vertexIndex:c},this.startDragListening();return}const h=l&&Ke.hitTestHandle(l,t);if(l&&h){if(r)return;this.beginDrag(h==="rotate"?"rotate":"resize",this.currentSourceId,l,t,h);return}}const a=n.hitTest(s,t.x,t.y);if(!a){const l=this.pickDecorAt(e);if(l!==void 0){this.selectDecor(l);return}r||this.beginCameraDrag(t);return}if(e.shiftKey?this.toggleUnitSelection(a.sourceId):this.selectedSourceIds.has(a.sourceId)||this.selectUnit(a.sourceId),r)return;const o=[...this.selectedSourceIds].map(l=>({sourceId:l,original:l===a.sourceId?a.shape:n.getInterpolatedShapeAt(s,l)??a.shape}));this.dragState={kind:"move",sources:o,startPointer:t},this.startDragListening()}selectedMembers(){const e=this.ufoElement.sighting.timeline,t=this.ufoElement.currentTime;return[...this.selectedSourceIds].map(n=>({sourceId:n,shape:e.getInterpolatedShapeAt(t,n)})).filter(n=>!!n.shape)}selectUnit(e){const t=this.ufoElement.sighting.timeline.groupMembers(e)??[e];t.length===this.selectedSourceIds.size&&t.every(n=>this.selectedSourceIds.has(n))&&e===this.currentSourceId||(this.selectedSourceIds=new Set(t),this.currentSourceId=e,this.refreshSourceList(),this.onSelectionOrTimeChanged())}toggleUnitSelection(e){const t=this.ufoElement.sighting.timeline,n=t.groupMembers(e)??[e];if(n.every(r=>this.selectedSourceIds.has(r))){if(n.length>=this.selectedSourceIds.size)return;for(const r of n)this.selectedSourceIds.delete(r);if(!this.selectedSourceIds.has(this.currentSourceId)){const r=t.sourceIds;this.currentSourceId=[...this.selectedSourceIds].sort((a,o)=>r.indexOf(a)-r.indexOf(o)).pop()}}else{for(const r of n)this.selectedSourceIds.add(r);this.currentSourceId=e}this.refreshSourceList(),this.onSelectionOrTimeChanged()}onContextMenu(e){if(e.preventDefault(),this.isRecording||this.ufoElement.playbackState==="playing")return;this.hideContextMenu(),this.hideDecorContextMenu();const t=this.canvasPointFromEvent(e);if(!t)return;const n=this.ufoElement.sighting.timeline,s=this.ufoElement.currentTime,r=this.selectedSourceIds.size===1?n.getInterpolatedShapeAt(s,this.currentSourceId):void 0,o=r?.kind==="polygon"&&Ke.hitTestVertex(r,t)!==void 0?{sourceId:this.currentSourceId}:n.hitTest(s,t.x,t.y);if(o){this.selectedSourceIds.has(o.sourceId)||this.selectUnit(o.sourceId),this.currentSourceId=o.sourceId,this.contextMenuPoint=t,this.showContextMenu(e.clientX,e.clientY);return}const l=this.pickDecorAt(e),c=l?this.ufoElement.sighting.decor.find(h=>h.id===l):void 0;c&&this.showDecorContextMenu(e.clientX,e.clientY,c)}pickDecorAt(e){const n=this.ufoElement.canvasElement.getBoundingClientRect();if(n.width===0||n.height===0)return;const s=(e.clientX-n.left)/n.width*2-1,r=-((e.clientY-n.top)/n.height*2-1);return this.sceneElement.pickDecorAt(s,r)}showContextMenu(e,t){this.contextMenu.style.left=`${e}px`,this.contextMenu.style.top=`${t}px`,this.contextMenu.hidden=!1;const n=this.ufoElement.sighting.timeline.sourceIds,s=n.filter(p=>this.selectedSourceIds.has(p)),r=n.length<=s.length,a=s.length>0&&n.slice(n.length-s.length).every(p=>this.selectedSourceIds.has(p)),o=s.length>0&&n.slice(0,s.length).every(p=>this.selectedSourceIds.has(p));this.contextBringToFrontButton.disabled=r||a,this.contextSendToBackButton.disabled=r||o,this.contextBringToFrontButton.title=r?this.messages.onlyOneShape:a?this.messages.alreadyAtFront:"",this.contextSendToBackButton.title=r?this.messages.onlyOneShape:o?this.messages.alreadyAtBack:"",this.contextGroupButton.disabled=this.selectedSourceIds.size<2,this.contextGroupButton.title=this.contextGroupButton.disabled?this.messages.needTwoShapesToGroup:"";const l=this.ufoElement.sighting.timeline.groupMembers(this.currentSourceId)!==void 0;this.contextUngroupButton.disabled=!l,this.contextUngroupButton.title=l?"":this.messages.notGrouped,this.contextDeleteButton.disabled=this.deleteShapeButton.disabled,this.contextDeleteButton.title=this.contextDeleteButton.disabled?this.messages.onlyOneShape:"";const c=this.ufoElement.sighting.timeline.getInterpolatedShapeAt(this.ufoElement.currentTime,this.currentSourceId),h=this.selectedSourceIds.size===1&&c?.kind==="polygon";this.contextAddVertexButton.disabled=!h,this.contextAddVertexButton.title=h?"":this.messages.notAPolygon;const u=h&&this.contextMenuPoint?Ke.hitTestVertex(c,this.contextMenuPoint):void 0,d=h&&c.points.length<=Kd;this.contextDeleteVertexButton.disabled=!h||u===void 0||d,this.contextDeleteVertexButton.title=h?d?this.messages.tooFewVertices:"":this.messages.notAPolygon,document.addEventListener("click",this.handleOutsideContextMenuClick)}hideContextMenu(){this.contextMenu.hidden=!0,this.contextMenuPoint=void 0,document.removeEventListener("click",this.handleOutsideContextMenuClick)}handleOutsideContextMenuClick=e=>{e.composedPath().includes(this.contextMenu)||e.composedPath().includes(this.decorContextMenu)||(this.hideContextMenu(),this.hideDecorContextMenu())};showDecorContextMenu(e,t,n){this.contextMenuDecorId=n.id,this.decorContextMenu.style.left=`${e}px`,this.decorContextMenu.style.top=`${t}px`,this.decorContextMenu.hidden=!1,this.contextViewTestimonyButton.disabled=!n.sightingUrl,this.contextViewTestimonyButton.title=n.sightingUrl?"":this.messages.noWitnessRecording,this.refreshContextMasksSubmenu(n),document.addEventListener("click",this.handleOutsideContextMenuClick)}hideDecorContextMenu(){this.decorContextMenu.hidden=!0,this.contextMenuDecorId=void 0,document.removeEventListener("click",this.handleOutsideContextMenuClick)}refreshContextMasksSubmenu(e){this.contextMasksSubmenu.innerHTML="";for(const t of this.ufoElement.sighting.timeline.sourceIds){const n=document.createElement("label"),s=document.createElement("input");s.type="checkbox",s.checked=e.occludesSourceIds?.includes(t)??!1,s.addEventListener("change",()=>this.updateDecorOccludesShape(e.id,t,s.checked)),n.appendChild(s),n.appendChild(document.createTextNode(this.shapeLabel(t))),this.contextMasksSubmenu.appendChild(n)}}updateDecorOccludesShape(e,t,n){const s=this.ufoElement.sighting;s.decor=s.decor.map(r=>{if(r.id!==e)return r;const a=n?[...new Set([...r.occludesSourceIds??[],t])]:(r.occludesSourceIds??[]).filter(o=>o!==t);return{...r,occludesSourceIds:a.length>0?a:void 0}}),this.ufoElement.refresh()}viewWitnessTestimony(){const e=this.ufoElement.sighting.decor.find(t=>t.id===this.contextMenuDecorId);this.hideDecorContextMenu(),e?.sightingUrl&&this.importFromUrl(e.sightingUrl)}addVertexAtContextMenu(){const e=this.contextMenuPoint;if(this.hideContextMenu(),!e)return;const t=this.ufoElement.currentTime,n=this.ufoElement.sighting.timeline.getInterpolatedShapeAt(t,this.currentSourceId);if(n?.kind!=="polygon")return;const s=Ke.insertVertexNear(n,e);this.ufoElement.sighting.timeline.addKeyframe(t,[{sourceId:this.currentSourceId,shape:s}]),this.ufoElement.refresh()}deleteVertexAtContextMenu(){const e=this.contextMenuPoint;if(this.hideContextMenu(),!e)return;const t=this.ufoElement.currentTime,n=this.ufoElement.sighting.timeline.getInterpolatedShapeAt(t,this.currentSourceId);if(n?.kind!=="polygon")return;const s=Ke.hitTestVertex(n,e);if(s===void 0)return;const r=Ke.deleteVertex(n,s);this.ufoElement.sighting.timeline.addKeyframe(t,[{sourceId:this.currentSourceId,shape:r}]),this.ufoElement.refresh()}bringSelectedToFront(){const e=this.ufoElement.sighting.timeline;for(const t of e.sourceIds.filter(n=>this.selectedSourceIds.has(n)))e.bringToFront(t);this.hideContextMenu(),this.ufoElement.refresh()}sendSelectedToBack(){const e=this.ufoElement.sighting.timeline;for(const t of e.sourceIds.filter(n=>this.selectedSourceIds.has(n)).reverse())e.sendToBack(t);this.hideContextMenu(),this.ufoElement.refresh()}groupSelected(){this.selectedSourceIds.size<2||(this.ufoElement.sighting.timeline.group([...this.selectedSourceIds]),this.hideContextMenu(),this.ufoElement.refresh())}ungroupSelected(){this.ufoElement.sighting.timeline.ungroup(this.currentSourceId),this.selectedSourceIds=new Set([this.currentSourceId]),this.hideContextMenu(),this.ufoElement.refresh()}beginDrag(e,t,n,s,r){this.dragState={kind:e,sourceId:t,original:n,handle:r,startPointer:s},this.startDragListening()}beginCameraDrag(e){const t=this.isWitnessInsideDecor();this.cameraDragState={startPointer:e,startHeadingDeg:t?this.indoorLookYawDeg:this.numberOrUndefined(this.headingInput.value)??0,startPitchDeg:t?this.indoorLookPitchDeg:this.numberOrUndefined(this.pitchInput.value)??0,insideDecor:t},t||this.sceneElement.setCompassForced(!0),this.setCanvasCursor("panning"),this.startDragListening()}isWitnessInsideDecor(){return this.ufoElement.sighting.decor.some(e=>e.witnessSide!==void 0&&$s(e.kind))}syncIndoorLookReset(){const e=this.ufoElement.sighting.decor.find(n=>n.witnessSide!==void 0&&$s(n.kind)),t=e?`${e.id}:${e.witnessSide}`:void 0;t!==this.lastInhabitedKey&&(this.lastInhabitedKey=t,this.indoorLookYawDeg=0,this.indoorLookPitchDeg=0,this.sceneElement.setIndoorLook(0,0))}startDragListening(){document.addEventListener("pointermove",this.handleDragPointerMove),document.addEventListener("pointerup",this.handleDragPointerUp)}onDragPointerMove(e){if(this.cameraDragState){this.onCameraDragPointerMove(e);return}if(!this.dragState)return;const t=this.canvasPointFromEvent(e);if(!t)return;const n=this.ufoElement.currentTime;if(this.dragState.kind==="move"){const{sources:s,startPointer:r}=this.dragState,a=t.x-r.x,o=t.y-r.y,l=s.map(({sourceId:c,original:h})=>({sourceId:c,shape:{...h,bounds:{...h.bounds,x:h.bounds.x+a,y:h.bounds.y+o}}}));this.ufoElement.sighting.timeline.addKeyframe(n,l)}else if(this.dragState.kind==="group-resize"){const{group:s,handle:r}=this.dragState;this.ufoElement.sighting.timeline.addKeyframe(n,s.resize(r,t))}else if(this.dragState.kind==="group-rotate"){const{group:s,startPointer:r}=this.dragState;this.ufoElement.sighting.timeline.addKeyframe(n,s.rotate(t,r))}else if(this.dragState.kind==="vertex"){const{sourceId:s,original:r,vertexIndex:a}=this.dragState,o=Ke.moveVertex(r,a,t);this.ufoElement.sighting.timeline.addKeyframe(n,[{sourceId:s,shape:o}])}else{const{kind:s,sourceId:r,original:a,handle:o}=this.dragState,l=s==="resize"?Ke.resizeShape(a,o,t):Ke.rotateShape(a,t);this.ufoElement.sighting.timeline.addKeyframe(n,[{sourceId:r,shape:l}])}this.ufoElement.refresh()}onCameraDragPointerMove(e){if(!this.cameraDragState)return;const t=this.canvasPointFromEvent(e);if(!t)return;const{startPointer:n,startHeadingDeg:s,startPitchDeg:r,insideDecor:a}=this.cameraDragState,o=s+(t.x-n.x)*Gd,l=Math.max(-90,Math.min(90,r-(t.y-n.y)*Gd));if(a){this.indoorLookYawDeg=o,this.indoorLookPitchDeg=l,this.sceneElement.setIndoorLook(o,l),this.ufoElement.refresh();return}this.headingInput.value=String(o),this.pitchInput.value=String(l),this.updateObserver()}endDrag(){!this.dragState&&!this.cameraDragState||(this.cameraDragState&&!this.cameraDragState.insideDecor&&this.sceneElement.setCompassForced(!1),this.dragState=void 0,this.cameraDragState=void 0,this.setCanvasCursor(this.hoverCursor),document.removeEventListener("pointermove",this.handleDragPointerMove),document.removeEventListener("pointerup",this.handleDragPointerUp))}nudgeBounds(e,t){const n={...e};if(t.shiftKey){switch(t.key){case"ArrowLeft":n.width=Math.max(ri,n.width-ti);break;case"ArrowRight":n.width+=ti;break;case"ArrowUp":n.height=Math.max(ri,n.height-ti);break;case"ArrowDown":n.height+=ti;break}n.x-=(n.width-e.width)/2,n.y-=(n.height-e.height)/2}else switch(t.key){case"ArrowLeft":n.x-=ti;break;case"ArrowRight":n.x+=ti;break;case"ArrowUp":n.y-=ti;break;case"ArrowDown":n.y+=ti;break}return n}moveOrResizeSelectedShapes(e){if(this.isRecording||this.ufoElement.playbackState==="playing")return;const t=this.ufoElement.sighting.timeline,n=this.ufoElement.currentTime,s=this.selectedMembers();if(s.length!==0){if(e.preventDefault(),s.length===1){const{sourceId:r,shape:a}=s[0];t.addKeyframe(n,[{sourceId:r,shape:{...a,bounds:this.nudgeBounds(a.bounds,e)}}])}else{const r=new Ba(s),a=this.nudgeBounds(r.bounds(),e);t.addKeyframe(n,r.scaleTo(a))}this.ufoElement.refresh()}}updateHoverCursor(e){this.isRecording||this.dragState||this.cameraDragState||(this.hoverCursor=this.hoverCursorAt(e),this.setCanvasCursor(this.hoverCursor))}hoverCursorAt(e){const t=this.canvasPointFromEvent(e);if(!t)return;const n=this.ufoElement.sighting.timeline,s=this.ufoElement.currentTime,r=this.ufoElement.playbackState!=="playing";if(r)if(this.selectedSourceIds.size>1){const a=Ke.hitTestHandle({bounds:new Ba(this.selectedMembers()).bounds(),angle:0},t);if(a)return this.cursorForHandle(a,0)}else{const a=n.getInterpolatedShapeAt(s,this.currentSourceId);if(a?.kind==="polygon"&&Ke.hitTestVertex(a,t)!==void 0)return"vertex";const o=a&&Ke.hitTestHandle(a,t);if(a&&o)return this.cursorForHandle(o,a.angle)}return n.hitTest(s,t.x,t.y)?r?"move":"select":this.pickDecorAt(e)!==void 0?"select":r?"pan":void 0}cursorForHandle(e,t){return e==="rotate"?"rotate":`resize-${Ke.resizeAxisFor(e,t)}`}setCanvasCursor(e){const t=this.ufoElement.canvasElement;e?t.dataset.cursor=e:delete t.dataset.cursor}onPointerMove(e){if(!this.isRecording){this.updateHoverCursor(e);return}const t=this.ufoElement.canvasElement,n=t.getBoundingClientRect(),s=e.clientX-n.left,r=e.clientY-n.top;this.recorder?.onPointerMove(s,r),this.ufoElement.renderer.clear(t.width,t.height),this.ufoElement.renderer.paintShape(Yd(this.buildPrototype({x:0,y:0,width:os.width,height:os.height}),s,r))}canvasPointFromEvent(e){const t=this.ufoElement.canvasElement,n=t.getBoundingClientRect();if(!(n.width===0||n.height===0))return{x:(e.clientX-n.left)/n.width*t.width,y:(e.clientY-n.top)/n.height*t.height}}}const Xd="rr0-ufo-recorder";function dy(){Ia(),customElements.get(Xd)||customElements.define(Xd,hy)}dy();
5582
+ `;let ea;function GS(){if(ea)return ea;const i=128,e=document.createElement("canvas");e.width=i,e.height=i;const t=e.getContext("2d"),n=t.createRadialGradient(i/2,i/2,0,i/2,i/2,i/2);return n.addColorStop(0,"rgba(255,255,255,1)"),n.addColorStop(.4,"rgba(255,255,255,0.35)"),n.addColorStop(1,"rgba(255,255,255,0)"),t.fillStyle=n,t.fillRect(0,0,i,i),ea=new Vn(e),ea}function HS(i){const t=document.createElement("canvas");t.width=128,t.height=128;const n=t.getContext("2d"),s=128/2-2,r=128/2,a=128/2,o="#2e2b26",l="#f4f1e2";n.fillStyle=o,n.beginPath(),n.arc(r,a,s,0,Math.PI*2),n.fill();const c=m0(i.illuminatedFraction,0,1),h=i.phaseFraction<.5,u=s*Math.abs(1-2*c),d=c<.5;return n.save(),n.beginPath(),n.arc(r,a,s,0,Math.PI*2),n.clip(),n.fillStyle=l,n.beginPath(),h?(n.arc(r,a,s,-Math.PI/2,Math.PI/2,!1),n.ellipse(r,a,u,s,0,Math.PI/2,-Math.PI/2,d)):(n.arc(r,a,s,Math.PI/2,-Math.PI/2,!1),n.ellipse(r,a,u,s,0,-Math.PI/2,Math.PI/2,d)),n.fill(),n.restore(),new Vn(t)}function VS(i){const e=document.createElement("canvas");e.width=128,e.height=128;const t=e.getContext("2d");return t.fillStyle="rgba(0, 0, 0, 0.55)",t.beginPath(),t.arc(64,64,60,0,Math.PI*2),t.fill(),t.fillStyle="#ffffff",t.font="bold 52px sans-serif",t.textAlign="center",t.textBaseline="middle",t.fillText(i,64,68),new Vn(e)}function Uo(i){let e=i;return function(){e|=0,e=e+1831565813|0;let n=Math.imul(e^e>>>15,1|e);return n=n+Math.imul(n^n>>>7,61|n)^n,((n^n>>>14)>>>0)/4294967296}}const kd=new Map;function WS(i){const e=i.byteLength/(4*Float32Array.BYTES_PER_ELEMENT),t=e,n=t*Float32Array.BYTES_PER_ELEMENT;return{count:e,ra:new Float32Array(i,0*n,t),dec:new Float32Array(i,1*n,t),mag:new Float32Array(i,2*n,t),ci:new Float32Array(i,3*n,t)}}function XS(i){let e=kd.get(i);return e||(e=fetch(i).then(t=>t.arrayBuffer()).then(WS),kd.set(i,e)),e}const YS=new URL(""+new URL("rain-BvWZrB9h.ogg",import.meta.url).href,import.meta.url).href,qS=new URL(""+new URL("wind-BjklexY7.ogg",import.meta.url).href,import.meta.url).href,$S=new URL(""+new URL("thunder-DA48qs_v.wav",import.meta.url).href,import.meta.url).href,KS=20,ZS=1;class JS{context;buffers=new Map;ambientSource;ambientGain;ambientKey="none";ambientToken=0;ambientVolume=0;windSource;windGain;windActive=!1;windToken=0;windVolume=0;resume(){if(!this.context){if(typeof AudioContext>"u")return;try{this.context=new AudioContext}catch(e){console.warn("WeatherAudio: Web Audio unavailable, weather sounds disabled:",e);return}}this.context.state==="suspended"&&this.context.resume()}setAmbient(e,t,n){if(!this.context)return;const s=e==="rain"||e==="hail"?e:"none";if(this.ambientVolume=s==="hail"?Math.min(1,t*1.3+.2):s==="rain"?t:0,s!==this.ambientKey){this.ambientKey=s;const a=++this.ambientToken;this.stopSource(this.ambientSource,this.ambientGain),this.ambientSource=void 0,this.ambientGain=void 0,s!=="none"&&this.startLoop(YS,this.ambientVolume).then(o=>this.applyIfCurrent(o,a,()=>this.ambientToken,l=>{this.ambientSource=l?.source,this.ambientGain=l?.gain,l&&(l.gain.gain.value=this.ambientVolume)}))}else this.ambientGain&&(this.ambientGain.gain.value=this.ambientVolume);this.windVolume=Math.min(n/KS,1);const r=n>ZS;if(r!==this.windActive){this.windActive=r;const a=++this.windToken;this.stopSource(this.windSource,this.windGain),this.windSource=void 0,this.windGain=void 0,r&&this.startLoop(qS,this.windVolume).then(o=>this.applyIfCurrent(o,a,()=>this.windToken,l=>{this.windSource=l?.source,this.windGain=l?.gain,l&&(l.gain.gain.value=this.windVolume)}))}else this.windGain&&(this.windGain.gain.value=this.windVolume)}playThunder(){this.context&&this.playOneShot($S,.9)}dispose(){this.ambientToken++,this.windToken++,this.stopSource(this.ambientSource,this.ambientGain),this.stopSource(this.windSource,this.windGain),this.ambientSource=void 0,this.ambientGain=void 0,this.windSource=void 0,this.windGain=void 0,this.context?.close(),this.context=void 0,this.buffers.clear()}applyIfCurrent(e,t,n,s){if(t!==n()){e?.source.stop();return}s(e)}async startLoop(e,t){const n=this.context;if(n)try{const s=await this.getBuffer(e),r=n.createBufferSource();r.buffer=s,r.loop=!0;const a=n.createGain();return a.gain.value=t,r.connect(a).connect(n.destination),r.start(),{source:r,gain:a}}catch(s){console.warn("Weather ambient sound failed to load, staying silent:",s);return}}async playOneShot(e,t){const n=this.context;if(n)try{const s=await this.getBuffer(e),r=n.createBufferSource();r.buffer=s;const a=n.createGain();a.gain.value=t,r.connect(a).connect(n.destination),r.start()}catch(s){console.warn("Thunder sound failed to load:",s)}}async getBuffer(e){const t=this.context;if(!t)throw new Error("WeatherAudio: AudioContext not ready — resume() must be called first");let n=this.buffers.get(e);return n||(n=fetch(e).then(s=>{if(!s.ok)throw new Error(`Audio fetch failed (${s.status}): ${e}`);return s.arrayBuffer()}).then(s=>t.decodeAudioData(s)),this.buffers.set(e,n)),n}stopSource(e,t){try{e?.stop()}catch{}e?.disconnect(),t?.disconnect()}}Ia();const QS={sun:{en:"Sun",fr:"Soleil"},moon:{en:"Moon",fr:"Lune"},Venus:{en:"Venus",fr:"Vénus"},Mars:{en:"Mars",fr:"Mars"},Jupiter:{en:"Jupiter",fr:"Jupiter"},Saturn:{en:"Saturn",fr:"Saturne"}},jS=["en","fr"],ey={building:{en:"Building",fr:"Bâtiment"},tree:{en:"Tree",fr:"Arbre"},streetlight:{en:"Streetlight",fr:"Lampadaire"},vehicle:{en:"Vehicle",fr:"Véhicule"},witness:{en:"Witness",fr:"Témoin"}},ty=new URL(""+new URL("stars-mag7.5-DDr9QasD.bin",import.meta.url).href,import.meta.url).href,ny={sun:{altitudeDeg:-3,azimuthDeg:180,magnitude:-26.7},moon:{altitudeDeg:-90,azimuthDeg:0,phase:{phaseFraction:0,illuminatedFraction:0},magnitude:-12.7},planets:[]},Fo={lat:0,lng:0,elevationM:0,headingDeg:void 0,pitchDeg:0,fovDeg:60};class iy extends HTMLElement{static get observedAttributes(){return["src","star-catalog-src","show-compass","lens-flare-intensity","lens-flare-brightness"]}shadow;stageElement;frameElement;sceneCanvas;ufoElement;sceneRenderer;hoverTooltip;resizeObserver;lastTimeMs=0;starCatalog;weatherAudio=new JS;thunderTimeoutId;handleFullscreenChange=()=>this.resizeToStage();handlePointerMove=e=>{this.sceneRenderer.setCompassHovered(!0);const t=this.ufoElement.canvasElement,n=t.getBoundingClientRect();if(n.width===0||n.height===0)return;const s=(e.clientX-n.left)/n.width*t.width,r=(e.clientY-n.top)/n.height*t.height;if(this.ufoElement.hasVisibleShapeAt(s,r)){this.hoverTooltip.hidden=!0;return}const a=(e.clientX-n.left)/n.width*2-1,o=-((e.clientY-n.top)/n.height*2-1),l=Aa(navigator.languages,jS),c=this.sceneRenderer.pickBodyAt(a,o);if(c){this.showHoverTooltip(e,QS[c]?.[l]??c);return}const h=this.sceneRenderer.pickDecorAt(a,o),u=h?this.ufoElement.sighting.decor.find(d=>d.id===h):void 0;if(u){this.showHoverTooltip(e,u.title||ey[u.kind][l]);return}this.hoverTooltip.hidden=!0};showHoverTooltip(e,t){this.hoverTooltip.textContent=t,this.hoverTooltip.hidden=!1;const n=this.stageElement.getBoundingClientRect();this.hoverTooltip.style.left=`${e.clientX-n.left+12}px`,this.hoverTooltip.style.top=`${e.clientY-n.top+12}px`}handlePointerLeave=()=>{this.hoverTooltip.hidden=!0,this.sceneRenderer.setCompassHovered(!1)};handleLightningFlash=()=>{clearTimeout(this.thunderTimeoutId);const e=(.5+Math.random()*3.5)*1e3;this.thunderTimeoutId=window.setTimeout(()=>this.weatherAudio.playThunder(),e)};handleFirstInteraction=()=>{this.weatherAudio.resume(),this.setWeather(zo(this.ufoElement.sighting,this.lastTimeMs))};handleTimeUpdate=e=>{this.lastTimeMs=e.detail.time,this.updateAstronomy(this.lastTimeMs),this.updateUfoOcclusion(this.lastTimeMs)};constructor(){super(),this.shadow=this.attachShadow({mode:"open"});const e=document.createElement("template");e.innerHTML=`<style>${ff}</style>${uf}`,this.shadow.appendChild(e.content.cloneNode(!0)),this.stageElement=this.shadow.getElementById("stage"),this.frameElement=this.shadow.getElementById("frame"),this.sceneCanvas=this.shadow.getElementById("scene-canvas"),this.sceneRenderer=new PS(this.sceneCanvas,void 0,this.handleLightningFlash),this.hoverTooltip=this.shadow.getElementById("hover-tooltip"),this.ufoElement=document.createElement(Go),this.ufoElement.classList.add("ufo-overlay"),this.ufoElement.style.setProperty("--ufo-canvas-background","transparent"),this.ufoElement.style.setProperty("--ufo-canvas-border","none"),this.ufoElement.fullscreenTarget=this.stageElement,this.shadow.getElementById("ufo-slot").replaceWith(this.ufoElement),this.ufoElement.addEventListener("timeupdate",this.handleTimeUpdate),this.ufoElement.canvasElement.addEventListener("pointermove",this.handlePointerMove),this.ufoElement.canvasElement.addEventListener("pointerleave",this.handlePointerLeave),this.ufoElement.canvasElement.addEventListener("pointerdown",this.handleFirstInteraction,{once:!0})}connectedCallback(){this.resizeToStage(),this.updateAstronomy(this.lastTimeMs),this.loadStars(),this.resizeObserver=new ResizeObserver(()=>this.resizeToStage()),this.resizeObserver.observe(this.frameElement),document.addEventListener("fullscreenchange",this.handleFullscreenChange);const e=this.getAttribute("src");e&&this.loadFromSrc(e)}disconnectedCallback(){this.resizeObserver?.disconnect(),document.removeEventListener("fullscreenchange",this.handleFullscreenChange),this.sceneRenderer.stopTwinkle(),clearTimeout(this.thunderTimeoutId),this.weatherAudio.dispose()}attributeChangedCallback(e,t,n){if(e==="src"&&n&&n!==t&&this.isConnected&&this.loadFromSrc(n),e==="star-catalog-src"&&n!==t&&this.isConnected&&this.loadStars(),e==="show-compass"&&n!==t&&this.sceneRenderer.setShowCompass(this.hasAttribute("show-compass")),e==="lens-flare-intensity"&&n!==t){const s=n===null?NaN:parseFloat(n);this.sceneRenderer.setLensFlareArtifactIntensity(Number.isFinite(s)?s:0)}if(e==="lens-flare-brightness"&&n!==t){const s=n===null?NaN:parseFloat(n);this.sceneRenderer.setDazzleIntensity(Number.isFinite(s)?s:1)}}setCompassForced(e){this.sceneRenderer.setCompassForced(e)}setIndoorLook(e,t){this.sceneRenderer.setIndoorLook(e,t)}setWeather(e){this.sceneRenderer.setWeather(e),this.weatherAudio.setAmbient(e.precipitationType,e.precipitationIntensity,e.windSpeed)}pickDecorAt(e,t){return this.sceneRenderer.pickDecorAt(e,t)}resumeWeatherAudio(){this.weatherAudio.resume()}async loadFromSrc(e){const t=await fetch(e);this.sightingData=await t.json()}get sightingData(){return this.ufoElement.sightingData}set sightingData(e){this.ufoElement.sightingData=e,this.lastTimeMs=0,this.updateAstronomy(0)}get currentTerrainAttribution(){return this.sceneRenderer.currentTerrainAttribution}resizeToStage(){const e=this.frameElement.getBoundingClientRect(),t=Math.max(1,Math.round(e.width)),n=Math.max(1,Math.round(e.height));this.sceneCanvas.width=t,this.sceneCanvas.height=n,this.sceneRenderer.resize(t,n)}async loadStars(){const e=this.getAttribute("star-catalog-src")??ty;this.starCatalog=await XS(e),this.updateAstronomy(this.lastTimeMs)}updateAstronomy(e){const t=this.ufoElement.sighting;this.setWeather(zo(t,e)),this.sceneRenderer.setDecor(t.decor);const n=Bo(t,e);this.sceneRenderer.setObserverPose(n??Fo),this.sceneRenderer.updateDecorAnchoring(Bo(t,0),n),this.sceneRenderer.updateDecorLitState(e),this.sceneRenderer.setTerrainOrigin(n?.lat,n?.lng);const s=n?.lat??Fo.lat,r=n?.lng??Fo.lng,a=Qx(t.event.time??{},r,t.event.utcOffsetHours);if(!a){this.sceneRenderer.setAstronomy(ny);return}const o=new Date(a.getTime()+e),l={lat:s,lng:r,elevationM:n?.elevationM??0},c={...Eo("Sun",o,l),magnitude:wo("Sun",o)},h={...Eo("Moon",o,l),phase:$x(o),magnitude:wo("Moon",o)},u=Yx.map(d=>({body:d,position:Eo(d,o,l),magnitude:wo(d,o)}));this.sceneRenderer.setAstronomy({sun:c,moon:h,planets:u,stars:this.starCatalog?{catalog:this.starCatalog,date:o,observer:l}:void 0})}updateUfoOcclusion(e){const t=this.ufoElement.sighting.timeline,n=this.ufoElement.canvasElement,s=new Set;for(const r of t.sourceIds){const a=t.getInterpolatedShapeAt(e,r);if(!a)continue;const o=(a.bounds.x+a.bounds.width/2)/n.width*2-1,l=-((a.bounds.y+a.bounds.height/2)/n.height*2-1);this.sceneRenderer.isScreenPointOccluded(o,l,r)&&s.add(r)}this.ufoElement.setOccludedSourceIds(s)}}const oc="rr0-scene";function sy(){Ia(),customElements.get(oc)||customElements.define(oc,iy)}class ry{constructor(e,t){this.timeline=e,this.clock=t}currentPointer=null;shapePrototype=null;sourceId="";start(e,t){this.sourceId=e,this.shapePrototype=t,this.currentPointer=null,this.clock.start(n=>this.recordSample(n))}onPointerMove(e,t){this.currentPointer={x:e,y:t}}stop(){this.clock.stop()}recordSample(e){if(!this.currentPointer||!this.shapePrototype)return;const t=Yd(this.shapePrototype,this.currentPointer.x,this.currentPointer.y);this.timeline.addKeyframe(e,[{sourceId:this.sourceId,shape:t}])}}class ay{constructor(e){this.intervalMs=e}rafId=null;startTime=0;lastTick=0;start(e){this.startTime=performance.now(),this.lastTick=0;const t=()=>{const n=performance.now()-this.startTime;n-this.lastTick>=this.intervalMs&&(this.lastTick=n,e(n)),this.rafId=requestAnimationFrame(t)};this.rafId=requestAnimationFrame(t)}stop(){this.rafId!==null&&(cancelAnimationFrame(this.rafId),this.rafId=null)}}const g0={oval:"Oval",polygon:"Polygon",addVertex:"Add vertex",deleteVertex:"Delete vertex",notAPolygon:"Select a single polygon shape",tooFewVertices:"A shape needs at least 3 points",color:"Color",transparency:"Transparency",halo:"Halo",shape:"Shape",shapeTitle:"Name",objectSize:"Real size",objectDistance:"Distance",apparentSize:"i.e. {deg}° — {moons}× the Moon",utcOffset:"Time zone",utcOffsetPlaceholder:"from longitude",objectSizePlaceholder:"reported width",objectDistancePlaceholder:"reported distance",addShape:"Add shape",deleteShape:"Delete shape",play:"Play",pause:"Pause",noDuration:"No observation duration",autoReplay:"Auto-replay",group:"Group",ungroup:"Ungroup",bringToFront:"Bring to front",sendToBack:"Send to back",contextMenuDelete:"Delete",confirmDeleteShape:"Delete {name}? This can't be undone.",confirmDeleteShapes:"Delete {count} shapes? This can't be undone.",onlyOneShape:"There is only one shape",alreadyAtFront:"This shape is already at the front",alreadyAtBack:"This shape is already at the back",needTwoShapesToGroup:"Select at least two shapes to group them",notGrouped:"This shape isn't part of a group",multipleShapesSelected:"Multiple shapes selected — select just one to edit this",samplingRate:"Sampling rate",duration:"Duration",durationPlaceholder:"observation length",durationImprecise:"These dates don't precisely enough determine a duration — enter it manually.",export:"Export JSON",importFile:"Load JSON file",importUrl:"Or load from URL",importUrlPlaceholder:"https://…/sighting.json",importButton:"Load",importError:"Couldn't load that recording — check the file or URL and try again.",record:"Record",stop:"Stop",latitude:"Latitude",longitude:"Longitude",heading:"Heading",headingPlaceholder:"unknown",pitch:"Tilt",observationTime:"Observation start",observationEndTime:"Observation end",edtfInvalid:"Not a valid EDTF date/time (e.g. 1965-07-01T05:00, 2025-06?, 2025~).",edtfPlaceholder:"YYYY-MM-DDThh:mm[?~%] or hh:mm",observationTimeHint:"EDTF — e.g. 1965-07-01T05:00, 2025-06? (uncertain), 2025~ (approximate), or just 05:00 if the date isn't known",observationEndTimeHint:"EDTF — e.g. 1965-07-01T05:10, 2025-06? (uncertain), 2025~ (approximate), or just 05:10 if the date isn't known",presetsGroupLabel:"UFO shape",witnessId:"Witness ID",witnessDirName:"Witness dir name",witnessTitle:"Witness title",witnessLastName:"Witness last name",witnessFirstNames:"Witness first names",caseId:"Case ID",description:"Description",tags:"Tags",tagsPlaceholder:"comma-separated",weather:"Weather",shapeGroup:"Shape",temporalGroup:"Temporal",locationGroup:"Location",observationGroup:"Observation",witnessGroup:"Witness",circumstancesGroup:"Circumstances",cloudCover:"Cloud cover",cloudDarkness:"Cloud darkness",precipitationType:"Precipitation",precipitationNone:"None",precipitationRain:"Rain",precipitationSnow:"Snow",precipitationHail:"Hail",precipitationIntensity:"Intensity",windDirection:"Wind direction",windSpeed:"Wind speed",storm:"Storm",lensFlareBrightness:"Light intensity",cameraDevice:"Camera/video device",decor:"Decor",decorBuilding:"Building",decorTree:"Tree",decorStreetlight:"Streetlight",decorVehicle:"Vehicle",decorWitness:"Other witness",addDecor:"Add",deleteDecor:"Delete decor",decorEast:"Distance east",decorNorth:"Distance north",decorHeading:"Heading",decorLit:"Lit",decorTitle:"Name",decorSightingUrl:"Witness's own recording URL",viewTestimony:"View testimony",noWitnessRecording:"No recording URL set for this witness",masks:"Masks",addWitness:"Add witness",decorFloors:"Floors",decorOccupiedFloor:"Occupied floor",decorWitnessSide:"Witness location",decorWitnessSideNone:"Not present",decorWindows:"Windows",decorSideFront:"Front",decorSideBehind:"Behind",decorSideLeft:"Left",decorSideRight:"Right",decorSideFrontLeft:"Front-left",decorSideFrontRight:"Front-right",decorSideBehindLeft:"Behind-left",decorSideBehindRight:"Behind-right"},oy=Object.freeze(Object.defineProperty({__proto__:null,ufoRecorderMessages_en:g0},Symbol.toStringTag,{value:"Module"}));Ia();sy();const os={width:48,height:28},Gd=.2,Hd=60,Vd=new Set(["ArrowLeft","ArrowRight","ArrowUp","ArrowDown"]),ti=4,ta="ufo-1",Wd=["oval","polygon"],ly={presetId:"oval",color:"#39ff14",transparency:0,haloScale:1.5};function cy(i){return i.kind==="oval"?"oval":"polygon"}class hy extends HTMLElement{shadow;sceneElement;ufoElement;recordButton;samplingRateInput;presetButtons;presetsGroup;colorInput;transparencyInput;haloScaleInput;sourceSelect;shapeTitleInput;utcOffsetInput;objectSizeInput;objectDistanceInput;apparentSizeOutput;addShapeButton;deleteShapeButton;contextMenu;contextGroupButton;contextUngroupButton;contextBringToFrontButton;contextSendToBackButton;contextDeleteButton;contextAddVertexButton;contextDeleteVertexButton;decorContextMenu;contextViewTestimonyButton;contextMasksSubmenu;labelContextMasks;playPauseButton;seekInput;timeStartLabel;timeEndLabel;loopButton;durationInput;exportButton;importFileInput;importUrlInput;importUrlButton;latInput;lngInput;headingInput;pitchInput;obsTimeInput;obsEndTimeInput;witnessIdInput;witnessDirNameInput;witnessTitleInput;witnessLastNameInput;witnessFirstNamesInput;caseIdInput;descriptionInput;tagsInput;cloudCoverInput;cloudDarknessInput;precipitationTypeSelect;precipitationIntensityInput;windDirectionInput;windSpeedInput;stormInput;lensFlareBrightnessInput;cameraDeviceInput;labelColor;labelTransparency;labelHalo;labelShape;labelShapeTitle;labelUtcOffset;labelObjectSize;labelObjectDistance;labelSamplingRate;labelDuration;labelLatitude;labelLongitude;labelHeading;labelPitch;labelObservationTime;labelObservationEndTime;labelWitnessId;labelWitnessDirName;labelWitnessTitle;labelWitnessLastName;labelWitnessFirstNames;labelCaseId;labelDescription;labelTags;labelWeather;labelImportFile;labelImportUrl;labelShapeGroup;labelTemporalGroup;labelLocationGroup;labelObservationGroup;labelWitnessGroup;labelCircumstancesGroup;labelCloudCover;labelCloudDarkness;labelPrecipitationType;labelPrecipitationIntensity;labelWindDirection;labelWindSpeed;labelStorm;labelLensFlareBrightness;labelCameraDevice;optionPrecipitationNone;optionPrecipitationRain;optionPrecipitationSnow;optionPrecipitationHail;decorKindSelect;addDecorWitnessButton;addDecorBuildingButton;deleteDecorButton;decorSelect;decorTitleInput;decorEastInput;decorNorthInput;decorHeadingInput;decorLitInput;decorSightingUrlInput;decorFloorsInput;decorOccupiedFloorInput;decorWitnessSideSelect;decorWindowInputs;labelDecorSide;optionWitnessSide;labelDecor;labelDecorFieldset;labelDecorTitle;labelDecorEast;labelDecorNorth;labelDecorHeading;labelDecorLit;labelDecorSightingUrl;labelDecorFloors;labelDecorOccupiedFloor;labelDecorWitnessSide;labelDecorWindows;optionWitnessSideNone;optionDecorBuilding;optionDecorTree;optionDecorStreetlight;optionDecorVehicle;optionDecorWitness;recorder;isRecording=!1;messages=g0;currentAppearance={...ly};currentSourceId=ta;selectedSourceIds=new Set([ta]);currentDecorId;contextMenuDecorId;contextMenuPoint;dragState;cameraDragState;hoverCursor;indoorLookYawDeg=0;indoorLookPitchDeg=0;lastInhabitedKey;handleKeyDown=e=>{if(e.key==="Escape"&&(this.isRecording&&this.toggleRecording(),this.contextMenu.hidden||this.hideContextMenu(),this.decorContextMenu.hidden||this.hideDecorContextMenu()),Vd.has(e.key)||e.key==="Delete"||e.key==="Backspace"){const t=e.composedPath()[0];if(t instanceof HTMLInputElement||t instanceof HTMLSelectElement||t instanceof HTMLTextAreaElement)return;Vd.has(e.key)?this.moveOrResizeSelectedShapes(e):this.deleteShape()}};handleDragPointerMove=e=>this.onDragPointerMove(e);handleDragPointerUp=()=>this.endDrag();constructor(){super(),this.shadow=this.attachShadow({mode:"open"});const e=document.createElement("template");e.innerHTML=`<style>${w0}</style>${E0}`,this.shadow.appendChild(e.content.cloneNode(!0)),this.sceneElement=document.createElement(oc),this.sceneElement.setAttribute("show-compass",""),this.ufoElement=this.sceneElement.ufoElement,this.ufoElement.enableClickToPlay=!1,this.ufoElement.showToolbar=!1,this.shadow.getElementById("ufo-slot").replaceWith(this.sceneElement),this.recordButton=this.shadow.getElementById("record"),this.samplingRateInput=this.shadow.getElementById("samplingRate"),this.presetsGroup=this.shadow.getElementById("presets-group"),this.presetButtons={oval:this.shadow.getElementById("preset-oval"),polygon:this.shadow.getElementById("preset-polygon")},this.colorInput=this.shadow.getElementById("color"),this.transparencyInput=this.shadow.getElementById("transparency"),this.haloScaleInput=this.shadow.getElementById("haloScale"),this.sourceSelect=this.shadow.getElementById("source"),this.shapeTitleInput=this.shadow.getElementById("shapeTitle"),this.utcOffsetInput=this.shadow.getElementById("utcOffsetHours"),this.objectSizeInput=this.shadow.getElementById("objectSize"),this.objectDistanceInput=this.shadow.getElementById("objectDistance"),this.apparentSizeOutput=this.shadow.getElementById("apparent-size"),this.addShapeButton=this.shadow.getElementById("add-shape"),this.deleteShapeButton=this.shadow.getElementById("delete-shape"),this.contextMenu=this.shadow.getElementById("context-menu"),this.contextGroupButton=this.shadow.getElementById("context-group"),this.contextUngroupButton=this.shadow.getElementById("context-ungroup"),this.contextBringToFrontButton=this.shadow.getElementById("context-bring-to-front"),this.contextSendToBackButton=this.shadow.getElementById("context-send-to-back"),this.contextDeleteButton=this.shadow.getElementById("context-delete"),this.contextAddVertexButton=this.shadow.getElementById("context-add-vertex"),this.contextDeleteVertexButton=this.shadow.getElementById("context-delete-vertex"),this.decorContextMenu=this.shadow.getElementById("decor-context-menu"),this.contextViewTestimonyButton=this.shadow.getElementById("context-view-testimony"),this.contextMasksSubmenu=this.shadow.getElementById("context-masks-submenu"),this.labelContextMasks=this.shadow.getElementById("label-context-masks"),this.playPauseButton=this.shadow.getElementById("play-pause"),this.seekInput=this.shadow.getElementById("seek"),this.timeStartLabel=this.shadow.getElementById("time-start"),this.timeEndLabel=this.shadow.getElementById("time-end"),this.loopButton=this.shadow.getElementById("loop"),this.durationInput=this.shadow.getElementById("durationSeconds"),this.exportButton=this.shadow.getElementById("export"),this.importFileInput=this.shadow.getElementById("import-file"),this.importUrlInput=this.shadow.getElementById("import-url"),this.importUrlButton=this.shadow.getElementById("import-url-button"),this.latInput=this.shadow.getElementById("lat"),this.lngInput=this.shadow.getElementById("lng"),this.headingInput=this.shadow.getElementById("heading"),this.pitchInput=this.shadow.getElementById("pitch"),this.obsTimeInput=this.shadow.getElementById("obs-time"),this.obsEndTimeInput=this.shadow.getElementById("obs-end-time"),this.witnessIdInput=this.shadow.getElementById("witnessId"),this.witnessDirNameInput=this.shadow.getElementById("witnessDirName"),this.witnessTitleInput=this.shadow.getElementById("witnessTitle"),this.witnessLastNameInput=this.shadow.getElementById("witnessLastName"),this.witnessFirstNamesInput=this.shadow.getElementById("witnessFirstNames"),this.caseIdInput=this.shadow.getElementById("caseId"),this.descriptionInput=this.shadow.getElementById("description"),this.tagsInput=this.shadow.getElementById("tags"),this.cloudCoverInput=this.shadow.getElementById("cloudCover"),this.cloudDarknessInput=this.shadow.getElementById("cloudDarkness"),this.precipitationTypeSelect=this.shadow.getElementById("precipitationType"),this.precipitationIntensityInput=this.shadow.getElementById("precipitationIntensity"),this.windDirectionInput=this.shadow.getElementById("windDirection"),this.windSpeedInput=this.shadow.getElementById("windSpeed"),this.stormInput=this.shadow.getElementById("storm"),this.lensFlareBrightnessInput=this.shadow.getElementById("lensFlareBrightness"),this.cameraDeviceInput=this.shadow.getElementById("cameraDevice"),this.labelColor=this.shadow.getElementById("label-color"),this.labelTransparency=this.shadow.getElementById("label-transparency"),this.labelHalo=this.shadow.getElementById("label-halo"),this.labelShape=this.shadow.getElementById("label-shape"),this.labelShapeTitle=this.shadow.getElementById("label-shape-title"),this.labelUtcOffset=this.shadow.getElementById("label-utc-offset"),this.labelObjectSize=this.shadow.getElementById("label-object-size"),this.labelObjectDistance=this.shadow.getElementById("label-object-distance"),this.labelSamplingRate=this.shadow.getElementById("label-sampling-rate"),this.labelDuration=this.shadow.getElementById("label-duration"),this.labelLatitude=this.shadow.getElementById("label-lat"),this.labelLongitude=this.shadow.getElementById("label-lng"),this.labelHeading=this.shadow.getElementById("label-heading"),this.labelPitch=this.shadow.getElementById("label-pitch"),this.labelObservationTime=this.shadow.getElementById("label-observation-time"),this.labelObservationEndTime=this.shadow.getElementById("label-observation-end-time"),this.labelWitnessId=this.shadow.getElementById("label-witness-id"),this.labelWitnessDirName=this.shadow.getElementById("label-witness-dir-name"),this.labelWitnessTitle=this.shadow.getElementById("label-witness-title"),this.labelWitnessLastName=this.shadow.getElementById("label-witness-last-name"),this.labelWitnessFirstNames=this.shadow.getElementById("label-witness-first-names"),this.labelCaseId=this.shadow.getElementById("label-case-id"),this.labelDescription=this.shadow.getElementById("label-description"),this.labelTags=this.shadow.getElementById("label-tags"),this.labelWeather=this.shadow.getElementById("label-weather"),this.labelImportFile=this.shadow.getElementById("label-import-file"),this.labelImportUrl=this.shadow.getElementById("label-import-url"),this.labelShapeGroup=this.shadow.getElementById("label-shape-group"),this.labelTemporalGroup=this.shadow.getElementById("label-temporal-group"),this.labelLocationGroup=this.shadow.getElementById("label-location-group"),this.labelObservationGroup=this.shadow.getElementById("label-observation-group"),this.labelWitnessGroup=this.shadow.getElementById("label-witness-group"),this.labelCircumstancesGroup=this.shadow.getElementById("label-circumstances-group"),this.labelCloudCover=this.shadow.getElementById("label-cloud-cover"),this.labelCloudDarkness=this.shadow.getElementById("label-cloud-darkness"),this.labelPrecipitationType=this.shadow.getElementById("label-precipitation-type"),this.labelPrecipitationIntensity=this.shadow.getElementById("label-precipitation-intensity"),this.labelWindDirection=this.shadow.getElementById("label-wind-direction"),this.labelWindSpeed=this.shadow.getElementById("label-wind-speed"),this.labelStorm=this.shadow.getElementById("label-storm"),this.labelLensFlareBrightness=this.shadow.getElementById("label-lens-flare-brightness"),this.labelCameraDevice=this.shadow.getElementById("label-camera-device"),this.optionPrecipitationNone=this.shadow.getElementById("option-precipitation-none"),this.optionPrecipitationRain=this.shadow.getElementById("option-precipitation-rain"),this.optionPrecipitationSnow=this.shadow.getElementById("option-precipitation-snow"),this.optionPrecipitationHail=this.shadow.getElementById("option-precipitation-hail"),this.decorKindSelect=this.shadow.getElementById("decorKind"),this.addDecorWitnessButton=this.shadow.getElementById("add-decor-witness"),this.addDecorBuildingButton=this.shadow.getElementById("add-decor-building"),this.deleteDecorButton=this.shadow.getElementById("delete-decor"),this.decorSelect=this.shadow.getElementById("decor"),this.decorTitleInput=this.shadow.getElementById("decorTitle"),this.decorEastInput=this.shadow.getElementById("decorEast"),this.decorNorthInput=this.shadow.getElementById("decorNorth"),this.decorHeadingInput=this.shadow.getElementById("decorHeading"),this.decorLitInput=this.shadow.getElementById("decorLit"),this.decorSightingUrlInput=this.shadow.getElementById("decorSightingUrl"),this.decorFloorsInput=this.shadow.getElementById("decorFloors"),this.decorOccupiedFloorInput=this.shadow.getElementById("decorOccupiedFloor"),this.decorWitnessSideSelect=this.shadow.getElementById("decorWitnessSide"),this.decorWindowInputs={front:this.shadow.getElementById("decorWindowFront"),behind:this.shadow.getElementById("decorWindowBehind"),left:this.shadow.getElementById("decorWindowLeft"),right:this.shadow.getElementById("decorWindowRight"),"front-left":this.shadow.getElementById("decorWindowFrontLeft"),"front-right":this.shadow.getElementById("decorWindowFrontRight"),"behind-left":this.shadow.getElementById("decorWindowBehindLeft"),"behind-right":this.shadow.getElementById("decorWindowBehindRight")},this.labelDecorSide={front:this.shadow.getElementById("label-decor-window-front"),behind:this.shadow.getElementById("label-decor-window-behind"),left:this.shadow.getElementById("label-decor-window-left"),right:this.shadow.getElementById("label-decor-window-right"),"front-left":this.shadow.getElementById("label-decor-window-front-left"),"front-right":this.shadow.getElementById("label-decor-window-front-right"),"behind-left":this.shadow.getElementById("label-decor-window-behind-left"),"behind-right":this.shadow.getElementById("label-decor-window-behind-right")},this.optionWitnessSide={front:this.shadow.getElementById("option-witness-side-front"),behind:this.shadow.getElementById("option-witness-side-behind"),left:this.shadow.getElementById("option-witness-side-left"),right:this.shadow.getElementById("option-witness-side-right"),"front-left":this.shadow.getElementById("option-witness-side-front-left"),"front-right":this.shadow.getElementById("option-witness-side-front-right"),"behind-left":this.shadow.getElementById("option-witness-side-behind-left"),"behind-right":this.shadow.getElementById("option-witness-side-behind-right")},this.optionWitnessSideNone=this.shadow.getElementById("option-witness-side-none"),this.labelDecor=this.shadow.getElementById("label-decor"),this.labelDecorFieldset=this.shadow.getElementById("label-decor-fieldset"),this.labelDecorTitle=this.shadow.getElementById("label-decor-title"),this.labelDecorEast=this.shadow.getElementById("label-decor-east"),this.labelDecorNorth=this.shadow.getElementById("label-decor-north"),this.labelDecorHeading=this.shadow.getElementById("label-decor-heading"),this.labelDecorLit=this.shadow.getElementById("label-decor-lit"),this.labelDecorSightingUrl=this.shadow.getElementById("label-decor-sighting-url"),this.labelDecorFloors=this.shadow.getElementById("label-decor-floors"),this.labelDecorOccupiedFloor=this.shadow.getElementById("label-decor-occupied-floor"),this.labelDecorWitnessSide=this.shadow.getElementById("label-decor-witness-side"),this.labelDecorWindows=this.shadow.getElementById("label-decor-windows"),this.optionDecorBuilding=this.shadow.getElementById("option-decor-building"),this.optionDecorTree=this.shadow.getElementById("option-decor-tree"),this.optionDecorStreetlight=this.shadow.getElementById("option-decor-streetlight"),this.optionDecorVehicle=this.shadow.getElementById("option-decor-vehicle"),this.optionDecorWitness=this.shadow.getElementById("option-decor-witness"),this.ufoElement.canvasElement.addEventListener("pointerdown",t=>this.onPointerDown(t)),this.ufoElement.canvasElement.addEventListener("pointermove",t=>this.onPointerMove(t)),this.ufoElement.canvasElement.addEventListener("contextmenu",t=>this.onContextMenu(t)),this.contextGroupButton.addEventListener("click",()=>this.groupSelected()),this.contextUngroupButton.addEventListener("click",()=>this.ungroupSelected()),this.contextBringToFrontButton.addEventListener("click",()=>this.bringSelectedToFront()),this.contextSendToBackButton.addEventListener("click",()=>this.sendSelectedToBack()),this.contextDeleteButton.addEventListener("click",()=>{this.hideContextMenu(),this.deleteShape()}),this.contextAddVertexButton.addEventListener("click",()=>this.addVertexAtContextMenu()),this.contextDeleteVertexButton.addEventListener("click",()=>this.deleteVertexAtContextMenu()),this.contextViewTestimonyButton.addEventListener("click",()=>this.viewWitnessTestimony()),this.playPauseButton.addEventListener("click",()=>{this.ufoElement.togglePlayPause(),this.syncPlaybackControls()}),this.loopButton.addEventListener("click",()=>{this.ufoElement.toggleLoop(),this.syncPlaybackControls()}),this.seekInput.addEventListener("input",()=>this.ufoElement.currentTime=Number(this.seekInput.value)),this.recordButton.addEventListener("click",()=>this.toggleRecording()),this.addShapeButton.addEventListener("click",()=>this.addShape()),this.deleteShapeButton.addEventListener("click",()=>this.deleteShape()),this.exportButton.addEventListener("click",()=>this.exportJson()),this.importFileInput.addEventListener("change",()=>this.importFromFile()),this.importUrlButton.addEventListener("click",()=>this.importFromUrl()),this.durationInput.addEventListener("input",()=>{this.ufoElement.durationSeconds=this.durationInput.value===""?void 0:Number(this.durationInput.value),this.ufoElement.refresh(),this.updateDurationValidity()}),this.sourceSelect.addEventListener("change",()=>this.selectUnit(this.sourceSelect.value)),this.shapeTitleInput.addEventListener("input",()=>this.updateShapeTitle());for(const t of[this.objectSizeInput,this.objectDistanceInput])t.addEventListener("input",()=>this.updatePhysicalExtent());this.addDecorWitnessButton.addEventListener("click",()=>this.addDecor("witness")),this.addDecorBuildingButton.addEventListener("click",()=>this.addDecor()),this.deleteDecorButton.addEventListener("click",()=>this.deleteDecor()),this.decorSelect.addEventListener("change",()=>this.selectDecor(this.decorSelect.value));for(const t of[this.decorTitleInput,this.decorEastInput,this.decorNorthInput,this.decorHeadingInput,this.decorSightingUrlInput,this.decorFloorsInput,this.decorOccupiedFloorInput])t.addEventListener("input",()=>this.updateDecor());this.decorWitnessSideSelect.addEventListener("change",()=>this.updateDecor());for(const t of is)this.decorWindowInputs[t].addEventListener("input",()=>this.updateDecorWindows());this.decorLitInput.addEventListener("input",()=>this.updateDecorLit()),this.ufoElement.addEventListener("timeupdate",()=>{this.onSelectionOrTimeChanged(),this.syncPlaybackControls(),this.dispatchEvent(new CustomEvent("sightingchange"))}),document.addEventListener("keydown",this.handleKeyDown);for(const t of Wd)this.presetButtons[t].addEventListener("click",()=>this.setAppearance({presetId:t}));this.colorInput.addEventListener("input",()=>this.setAppearance({color:this.colorInput.value})),this.transparencyInput.addEventListener("input",()=>this.setAppearance({transparency:Number(this.transparencyInput.value)})),this.haloScaleInput.addEventListener("input",()=>this.setAppearance({haloScale:Number(this.haloScaleInput.value)}));for(const t of[this.latInput,this.lngInput,this.headingInput,this.pitchInput])t.addEventListener("input",()=>this.updateObserver());this.headingInput.addEventListener("focus",()=>this.sceneElement.setCompassForced(!0)),this.headingInput.addEventListener("blur",()=>this.sceneElement.setCompassForced(!1)),this.lensFlareBrightnessInput.addEventListener("input",()=>this.sceneElement.setAttribute("lens-flare-brightness",this.lensFlareBrightnessInput.value)),this.cameraDeviceInput.addEventListener("input",()=>this.sceneElement.setAttribute("lens-flare-intensity",this.cameraDeviceInput.value)),this.utcOffsetInput.addEventListener("input",()=>this.updateUtcOffset()),this.obsTimeInput.addEventListener("input",()=>this.updateObservationTime()),this.obsEndTimeInput.addEventListener("input",()=>this.updateObservationEndTime()),this.obsTimeInput.addEventListener("blur",()=>this.validateEdtfTimeInput(this.obsTimeInput)),this.obsEndTimeInput.addEventListener("blur",()=>this.validateEdtfTimeInput(this.obsEndTimeInput));for(const t of[this.witnessIdInput,this.witnessDirNameInput,this.witnessTitleInput,this.witnessLastNameInput,this.witnessFirstNamesInput,this.caseIdInput])t.addEventListener("input",()=>this.updateWitnessMetadata());this.descriptionInput.addEventListener("input",()=>this.updateDescription()),this.tagsInput.addEventListener("input",()=>this.updateTags());for(const t of[this.cloudCoverInput,this.cloudDarknessInput,this.precipitationTypeSelect,this.precipitationIntensityInput,this.windDirectionInput,this.windSpeedInput,this.stormInput])t.addEventListener("input",()=>this.applyWeatherAtPlayhead());this.updatePresetButtons(),this.setRecordButtonLabel(!1),this.applyAppearanceAtPlayhead(),this.shapeTitleInput.value=this.shapeLabel(this.currentSourceId),this.updateShapeTitle(),this.currentDecorId=this.ufoElement.sighting.decor[0]?.id,this.refreshDecorList(),this.onSelectionOrTimeChanged(),this.syncDurationField(),this.syncPlaybackControls(),this.loadLocaleMessages()}static get observedAttributes(){return["src"]}connectedCallback(){const e=this.getAttribute("src");e&&this.importFromUrl(e)}attributeChangedCallback(e,t,n){e==="src"&&n&&n!==t&&this.isConnected&&this.importFromUrl(n)}disconnectedCallback(){document.removeEventListener("keydown",this.handleKeyDown),document.removeEventListener("click",this.handleOutsideContextMenuClick),this.endDrag()}get sightingData(){return this.ufoElement.sightingData}set sightingData(e){this.endDrag(),this.ufoElement.sightingData=e,this.currentSourceId=this.ufoElement.sighting.timeline.sourceIds[0]??ta,this.selectedSourceIds=new Set([this.currentSourceId]),this.refreshSourceList(),this.currentDecorId=this.ufoElement.sighting.decor[0]?.id,this.refreshDecorList(),this.onSelectionOrTimeChanged(),this.syncDurationField(),this.syncObservationTimeFields(),this.syncObservationEndTimeFields(),this.syncWitnessMetadataFields()}exportJson(){const e=this.sightingData,t=`${e.witness?.id??"sighting"}-sighting.json`,n=new Blob([JSON.stringify(e,null,2)],{type:"application/json"}),s=URL.createObjectURL(n),r=document.createElement("a");r.href=s,r.download=t,r.click(),URL.revokeObjectURL(s)}async importFromFile(){const e=this.importFileInput.files?.[0];if(e)try{const t=await new Promise((n,s)=>{const r=new FileReader;r.onload=()=>n(r.result),r.onerror=()=>s(r.error),r.readAsText(e)});this.sightingData=JSON.parse(t)}catch{window.alert(this.messages.importError)}finally{this.importFileInput.value=""}}async importFromUrl(e=this.importUrlInput.value.trim()){if(e)try{const t=await fetch(e);if(!t.ok)throw new Error(`HTTP ${t.status}`);this.sightingData=await t.json()}catch{window.alert(this.messages.importError)}}numberOrUndefined(e){return e===""?void 0:Number(e)}stringOrUndefined(e){return e===""?void 0:e}wrapDegrees(e,t){if(e===void 0)return;const n=(e%360+360)%360;return String(n)!==t.value&&(t.value=String(n)),n}updateObserver(){if(this.ufoElement.playbackState==="playing")return;const e=this.numberOrUndefined(this.latInput.value),t=this.numberOrUndefined(this.lngInput.value),n=this.wrapDegrees(this.numberOrUndefined(this.headingInput.value),this.headingInput),s=this.numberOrUndefined(this.pitchInput.value)??0,r=this.ufoElement.sighting.event,a=this.ufoElement.sighting.witnessTrack,o=this.ufoElement.currentTime;r.place=e!==void 0&&t!==void 0?[{lat:e,lng:t}]:void 0,e===void 0&&t===void 0&&n===void 0&&s===0?a.removeKeyframeAt(o):a.addKeyframe(o,{lat:e,lng:t,elevationM:0,headingDeg:n,pitchDeg:s,fovDeg:Hd}),this.ufoElement.refresh()}applyEdtfTimeInput(e,t){const n=e.value.trim();if(n==="")t(void 0);else{const s=Vc(n);if(!s)return;t(s)}e.setCustomValidity(""),e.classList.remove("invalid"),this.ufoElement.refresh(),this.syncDurationField()}validateEdtfTimeInput(e){const t=e.value.trim();t===""||Vc(t)||(e.setCustomValidity(this.messages.edtfInvalid),e.classList.add("invalid"))}updateUtcOffset(){this.ufoElement.sighting.event.utcOffsetHours=this.numberOrUndefined(this.utcOffsetInput.value),this.ufoElement.refresh()}updateObservationTime(){this.applyEdtfTimeInput(this.obsTimeInput,e=>{this.ufoElement.sighting.event.time=e})}updateObservationEndTime(){this.applyEdtfTimeInput(this.obsEndTimeInput,e=>{this.ufoElement.sighting.event.endTime=e})}updateWitnessMetadata(){const e=this.ufoElement.sighting,t=this.witnessFirstNamesInput.value.split(",").map(s=>s.trim()).filter(s=>s.length>0),n={id:this.stringOrUndefined(this.witnessIdInput.value),dirName:this.stringOrUndefined(this.witnessDirNameInput.value),title:this.stringOrUndefined(this.witnessTitleInput.value),lastName:this.stringOrUndefined(this.witnessLastNameInput.value),firstNames:t.length>0?t:void 0};e.witness=Object.values(n).some(s=>s!==void 0)?n:void 0,e.caseId=this.stringOrUndefined(this.caseIdInput.value),this.ufoElement.refresh()}updateDescription(){this.ufoElement.sighting.event.description=this.stringOrUndefined(this.descriptionInput.value),this.ufoElement.refresh()}updateTags(){const e=this.tagsInput.value.split(",").map(t=>t.trim()).filter(t=>t.length>0);this.ufoElement.sighting.event.tags=e.length>0?e:void 0,this.ufoElement.refresh()}applyWeatherAtPlayhead(){if(this.ufoElement.playbackState==="playing")return;this.sceneElement.resumeWeatherAudio();const e={cloudCover:Number(this.cloudCoverInput.value),cloudDarkness:Number(this.cloudDarknessInput.value),precipitationType:this.precipitationTypeSelect.value,precipitationIntensity:Number(this.precipitationIntensityInput.value),windDirectionDeg:this.wrapDegrees(this.numberOrUndefined(this.windDirectionInput.value),this.windDirectionInput)??0,windSpeed:Number(this.windSpeedInput.value),storm:this.stormInput.checked};this.ufoElement.sighting.weatherTrack.addKeyframe(this.ufoElement.currentTime,e),this.ufoElement.refresh()}syncDurationField(){if(this.shadow.activeElement!==this.durationInput){const e=lc(this.ufoElement.sighting.event);this.durationInput.value=e!==void 0?String(e/1e3):""}this.updateDurationValidity()}updateDurationValidity(){const e=this.durationInput.value==="";this.durationInput.classList.toggle("invalid",e),this.durationInput.setAttribute("aria-invalid",String(e));const t=X0(this.ufoElement.sighting.event);this.durationInput.title=t==="imprecise"?this.messages.durationImprecise:""}syncPlaybackControls(){const e=this.ufoElement.playbackState==="playing",t=this.ufoElement.seekableDuration>0;this.playPauseButton.textContent=e?"⏸":"▶",this.playPauseButton.disabled=!t;const n=t?e?this.messages.pause:this.messages.play:this.messages.noDuration;this.playPauseButton.title=n,this.playPauseButton.setAttribute("aria-label",n),this.loopButton.setAttribute("aria-pressed",String(this.ufoElement.autoReplayEnabled)),this.seekInput.max=String(this.ufoElement.seekableDuration),this.shadow.activeElement!==this.seekInput&&(this.seekInput.value=String(this.ufoElement.currentTime)),this.timeStartLabel.textContent=this.ufoElement.positionLabel,this.timeEndLabel.textContent=this.ufoElement.durationLabel}syncObservationTimeFields(){const e=this.ufoElement.sighting.event.time;this.obsTimeInput.value=e?Wc(e):"",this.obsTimeInput.setCustomValidity(""),this.obsTimeInput.classList.remove("invalid")}syncObservationEndTimeFields(){const e=this.ufoElement.sighting.event.endTime;this.obsEndTimeInput.value=e?Wc(e):"",this.obsEndTimeInput.setCustomValidity(""),this.obsEndTimeInput.classList.remove("invalid")}syncWitnessMetadataFields(){const e=this.ufoElement.sighting;this.witnessIdInput.value=e.witness?.id??"",this.witnessDirNameInput.value=e.witness?.dirName??"",this.witnessTitleInput.value=e.witness?.title??"",this.witnessLastNameInput.value=e.witness?.lastName??"",this.witnessFirstNamesInput.value=e.witness?.firstNames?.join(", ")??"",this.caseIdInput.value=e.caseId??"",this.descriptionInput.value=e.event.description??"",this.tagsInput.value=e.event.tags?.join(", ")??""}syncWeatherFromTimeline(){if(this.ufoElement.playbackState==="playing")return;const e=zo(this.ufoElement.sighting,this.ufoElement.currentTime),t=this.shadow.activeElement;t!==this.cloudCoverInput&&(this.cloudCoverInput.value=String(e.cloudCover)),t!==this.cloudDarknessInput&&(this.cloudDarknessInput.value=String(e.cloudDarkness)),t!==this.precipitationTypeSelect&&(this.precipitationTypeSelect.value=e.precipitationType),t!==this.precipitationIntensityInput&&(this.precipitationIntensityInput.value=String(e.precipitationIntensity)),t!==this.windDirectionInput&&(this.windDirectionInput.value=String(e.windDirectionDeg)),t!==this.windSpeedInput&&(this.windSpeedInput.value=String(e.windSpeed)),t!==this.stormInput&&(this.stormInput.checked=e.storm)}syncObserverFromTimeline(){if(this.ufoElement.playbackState==="playing")return;const e=this.ufoElement.sighting,t=e.witnessTrack.getInterpolatedPoseAt(this.ufoElement.currentTime),n=e.event.place?.[0],s=this.shadow.activeElement;s!==this.latInput&&(this.latInput.value=t?.lat!==void 0?String(t.lat):n?String(n.lat):""),s!==this.lngInput&&(this.lngInput.value=t?.lng!==void 0?String(t.lng):n?String(n.lng):""),s!==this.headingInput&&(this.headingInput.value=t?.headingDeg!==void 0?String(t.headingDeg):""),s!==this.pitchInput&&(this.pitchInput.value=String(t?.pitchDeg??0))}get appearance(){return{...this.currentAppearance}}set appearance(e){this.setAppearance(e)}setAppearance(e){const t="presetId"in e;this.currentAppearance={...this.currentAppearance,...e},this.updatePresetButtons(),!(this.isRecording||this.ufoElement.playbackState==="playing")&&this.applyAppearanceAtPlayhead(void 0,t)}applyAppearanceAtPlayhead(e,t=!0){const n=this.ufoElement.sighting.timeline,s=this.ufoElement.currentTime,r=n.getInterpolatedShapeAt(s,this.currentSourceId),a=this.buildAppearanceShape(e??r?.bounds??this.defaultBounds(),r,t);n.addKeyframe(s,[{sourceId:this.currentSourceId,shape:a}]),this.ufoElement.refresh()}buildAppearanceShape(e,t,n=!0){if(t&&!n)return{...t,color:this.currentAppearance.color,transparency:this.currentAppearance.transparency,haloScale:this.currentAppearance.haloScale};const s=Gc(e,this.currentAppearance);return t?{...s,angle:t.angle,title:t.title,selected:t.selected}:s}onSelectionOrTimeChanged(){this.syncAppearanceFromTimeline(),this.syncObserverFromTimeline(),this.syncWeatherFromTimeline(),this.syncDecorLitFromTimeline(),this.syncIndoorLookReset(),this.updateAppearanceFieldsDisabledState(),this.updateShapeTitleValidity(),this.ufoElement.selectedSourceIds=this.selectedSourceIds;const e=this.ufoElement.sighting.timeline.sourceIds,t=e.filter(n=>this.selectedSourceIds.has(n)).length;this.deleteShapeButton.disabled=this.isRecording||this.ufoElement.playbackState==="playing"||t===0||e.length-t<1}updateAppearanceFieldsDisabledState(){const e=this.selectedSourceIds.size>1,t=e?this.messages.multipleShapesSelected:"";for(const n of[this.shapeTitleInput,this.colorInput,this.transparencyInput,this.haloScaleInput,this.objectSizeInput,this.objectDistanceInput,this.sourceSelect,...Object.values(this.presetButtons)])n.disabled=e,n.title=t}syncAppearanceFromTimeline(){if(this.ufoElement.playbackState==="playing"||this.selectedSourceIds.size>1)return;const e=this.ufoElement.sighting.timeline.getInterpolatedShapeAt(this.ufoElement.currentTime,this.currentSourceId);e&&(this.currentAppearance={presetId:cy(e),color:e.color,transparency:e.transparency,haloScale:e.haloScale},this.updatePresetButtons(),this.colorInput.value=this.currentAppearance.color,this.transparencyInput.value=String(this.currentAppearance.transparency),this.haloScaleInput.value=String(this.currentAppearance.haloScale),this.shadow.activeElement!==this.shapeTitleInput&&(this.shapeTitleInput.value=e.title??""),this.shadow.activeElement!==this.objectSizeInput&&(this.objectSizeInput.value=e.physical?String(Number(e.physical.sizeM.toFixed(2))):""),this.shadow.activeElement!==this.objectDistanceInput&&(this.objectDistanceInput.value=e.physical?String(Number(e.physical.distanceM.toFixed(2))):""),this.refreshApparentSize())}updateShapeTitle(){const e=this.ufoElement.sighting.timeline,t=this.ufoElement.currentTime,n=e.getInterpolatedShapeAt(t,this.currentSourceId);n&&(e.addKeyframe(t,[{sourceId:this.currentSourceId,shape:{...n,title:this.stringOrUndefined(this.shapeTitleInput.value)}}]),this.ufoElement.refresh(),this.refreshSourceList(),this.updateShapeTitleValidity())}updatePhysicalExtent(){const e=this.ufoElement.sighting.timeline,t=this.ufoElement.currentTime,n=e.getInterpolatedShapeAt(t,this.currentSourceId);if(!n)return;const s=this.numberOrUndefined(this.objectSizeInput.value),r=this.numberOrUndefined(this.objectDistanceInput.value);if(s===void 0&&r===void 0){e.addKeyframe(t,[{sourceId:this.currentSourceId,shape:{...n,physical:void 0}}]),this.ufoElement.refresh(),this.refreshApparentSize();return}if(s===void 0||r===void 0||s<=0||r<=0){this.refreshApparentSize();return}const a={sizeM:s,distanceM:r},o=this.ufoElement.canvasElement,l=fs.widthPx(a,o.height,this.currentFovDeg()),c=n.bounds.height*(n.bounds.width===0?1:l/n.bounds.width),h={x:n.bounds.x+(n.bounds.width-l)/2,y:n.bounds.y+(n.bounds.height-c)/2,width:l,height:c},u=n.kind==="oval"?{...n,bounds:h,physical:a}:{...n,bounds:h,physical:a,points:this.scalePoints(n,h)};e.addKeyframe(t,[{sourceId:this.currentSourceId,shape:u}]),this.ufoElement.refresh(),this.refreshApparentSize()}scalePoints(e,t){const n=e.bounds.width===0?1:t.width/e.bounds.width,s=e.bounds.height===0?1:t.height/e.bounds.height;return e.points.map(r=>({x:r.x*n,y:r.y*s}))}currentFovDeg(){return Bo(this.ufoElement.sighting,this.ufoElement.currentTime)?.fovDeg??Hd}refreshApparentSize(){const e=this.selectedSourceIds.size===1?this.ufoElement.sighting.timeline.getInterpolatedShapeAt(this.ufoElement.currentTime,this.currentSourceId):void 0;if(!e){this.apparentSizeOutput.textContent="";return}const t=this.ufoElement.canvasElement,n=fs.pxToDeg(e.bounds.width,t.height,this.currentFovDeg()),s=fs.inMoons(n);this.apparentSizeOutput.textContent=this.messages.apparentSize.replace("{deg}",n.toLocaleString(void 0,{maximumFractionDigits:n<1?2:1})).replace("{moons}",s.toLocaleString(void 0,{maximumFractionDigits:s<10?1:0}))}updateShapeTitleValidity(){const e=this.selectedSourceIds.size===1&&this.shapeTitleInput.value==="";this.shapeTitleInput.classList.toggle("invalid",e),this.shapeTitleInput.setAttribute("aria-invalid",String(e))}shapeLabel(e){const t=this.ufoElement.sighting.timeline.getInterpolatedShapeAt(this.ufoElement.currentTime,e);if(t?.title)return t.title;const n=/^ufo-(\d+)$/.exec(e);return n?`${this.messages.shape} ${n[1]}`:e}addShape(){if(this.isRecording)return;const e=this.ufoElement.sighting.timeline,t=new Set([...e.sourceIds,this.currentSourceId]);let n=t.size+1;for(;t.has(`ufo-${n}`);)n++;this.currentSourceId=`ufo-${n}`,this.selectedSourceIds=new Set([this.currentSourceId]),this.applyAppearanceAtPlayhead(this.offsetDefaultBounds(e.sourceIds.length)),this.shapeTitleInput.value=this.shapeLabel(this.currentSourceId),this.updateShapeTitle()}deleteShape(){if(this.isRecording||this.ufoElement.playbackState==="playing")return;const e=this.ufoElement.sighting.timeline,t=e.sourceIds.filter(s=>this.selectedSourceIds.has(s));if(!(t.length===0||e.sourceIds.length-t.length<1||!(t.length===1?window.confirm(this.messages.confirmDeleteShape.replace("{name}",this.shapeLabel(t[0]))):window.confirm(this.messages.confirmDeleteShapes.replace("{count}",String(t.length)))))){for(const s of t)e.removeSource(s);this.currentSourceId=e.sourceIds[0],this.selectedSourceIds=new Set([this.currentSourceId]),this.refreshSourceList(),this.ufoElement.refresh()}}offsetDefaultBounds(e){const t=this.defaultBounds(),n=24;return{...t,x:t.x+e*n,y:t.y+e*n}}refreshSourceList(){const e=this.ufoElement.sighting.timeline,t=[...new Set([...e.sourceIds,this.currentSourceId])];this.sourceSelect.innerHTML="";for(const n of t){const s=document.createElement("option");s.value=n,s.textContent=this.shapeLabel(n),this.sourceSelect.appendChild(s)}this.sourceSelect.value=this.currentSourceId}decorLabel(e){if(e.title)return e.title;const n=this.ufoElement.sighting.decor.filter(r=>r.kind===e.kind).indexOf(e)+1;return`${this.decorKindSelect.querySelector(`option[value="${e.kind}"]`)?.textContent??e.kind} ${n}`}addDecor(e=this.decorKindSelect.value){const t=this.ufoElement.sighting,s={id:`decor-${t.decor.length+1}`,kind:e,title:this.nextDecorLabel(e),eastM:8*t.decor.length,northM:15,headingDeg:0,lit:!1,...e==="building"?{floors:ca}:{},windows:U2(e)};t.decor=[...t.decor,s],this.currentDecorId=s.id,this.refreshDecorList(),this.ufoElement.refresh()}nextDecorLabel(e){const t=this.ufoElement.sighting.decor.filter(s=>s.kind===e).length;return`${this.decorKindSelect.querySelector(`option[value="${e}"]`)?.textContent??e} ${t+1}`}deleteDecor(){if(this.currentDecorId===void 0)return;const e=this.ufoElement.sighting;e.decor=e.decor.filter(t=>t.id!==this.currentDecorId),this.currentDecorId=e.decor[0]?.id,this.refreshDecorList(),this.ufoElement.refresh()}selectDecor(e){this.currentDecorId=e,this.decorSelect.value=e,this.syncDecorFields()}updateDecor(){if(this.currentDecorId===void 0)return;const e=this.ufoElement.sighting,t=this.wrapDegrees(Number(this.decorHeadingInput.value),this.decorHeadingInput)??0,n=this.decorWitnessSideSelect.value;e.decor=e.decor.map(s=>{if(s.id!==this.currentDecorId)return s;const r=$s(s.kind)&&n!==""?n:void 0;return{...s,title:this.stringOrUndefined(this.decorTitleInput.value),eastM:Number(this.decorEastInput.value),northM:Number(this.decorNorthInput.value),headingDeg:t,sightingUrl:this.stringOrUndefined(this.decorSightingUrlInput.value),witnessSide:r,floors:s.kind==="building"?Number(this.decorFloorsInput.value):void 0,occupiedFloor:s.kind==="building"?Number(this.decorOccupiedFloorInput.value):void 0}}),this.decorSelect.options[this.decorSelect.selectedIndex].textContent=this.decorLabel(e.decor.find(s=>s.id===this.currentDecorId)),this.syncDecorVisibility(),this.updateDecorTitleValidity(),this.ufoElement.refresh()}updateDecorTitleValidity(){const e=this.currentDecorId!==void 0&&this.decorTitleInput.value==="";this.decorTitleInput.classList.toggle("invalid",e),this.decorTitleInput.setAttribute("aria-invalid",String(e))}updateDecorWindows(){if(this.currentDecorId===void 0)return;const e=this.ufoElement.sighting;e.decor=e.decor.map(t=>{if(t.id!==this.currentDecorId)return t;const n={};for(const s of is){const r=this.decorWindowInputs[s];if(r.value==="")continue;const a=tc(t.kind,s)?0:ec,o=Math.max(a,Math.min(100,Number(r.value)));n[s]=o,String(o)!==r.value&&(r.value=String(o))}return{...t,windows:n}}),this.ufoElement.refresh()}updateDecorLit(){if(this.currentDecorId===void 0||this.ufoElement.playbackState==="playing")return;const e=this.ufoElement.sighting,t=this.ufoElement.currentTime,n=this.decorLitInput.checked;e.decor=e.decor.map(s=>{if(s.id!==this.currentDecorId)return s;const r=[...(s.litKeyframes??[]).filter(a=>a.t!==t),{t,lit:n}].sort((a,o)=>a.t-o.t);return{...s,litKeyframes:r}}),this.ufoElement.refresh()}refreshDecorList(){const e=this.ufoElement.sighting.decor;this.decorSelect.innerHTML="";for(const t of e){const n=document.createElement("option");n.value=t.id,n.textContent=this.decorLabel(t),this.decorSelect.appendChild(n)}this.currentDecorId!==void 0&&(this.decorSelect.value=this.currentDecorId),this.syncDecorFields()}syncDecorFields(){const e=this.ufoElement.sighting.decor.find(n=>n.id===this.currentDecorId),t=e!==void 0;this.deleteDecorButton.disabled=!t;for(const n of[this.decorSelect,this.decorTitleInput,this.decorEastInput,this.decorNorthInput,this.decorHeadingInput,this.decorLitInput,this.decorSightingUrlInput,this.decorFloorsInput,this.decorOccupiedFloorInput,this.decorWitnessSideSelect])n.disabled=!t;this.decorTitleInput.value=e?.title??"",this.decorEastInput.value=String(e?.eastM??0),this.decorNorthInput.value=String(e?.northM??0),this.decorHeadingInput.value=String(e?.headingDeg??0),this.decorLitInput.checked=e?nc(e,this.ufoElement.currentTime):!1,this.decorSightingUrlInput.value=e?.sightingUrl??"",this.decorFloorsInput.value=String(e?.floors??ca),this.decorOccupiedFloorInput.value=String(e?.occupiedFloor??0),this.decorWitnessSideSelect.value=e?.witnessSide??"";for(const n of is){const s=e?.windows?.[n];this.decorWindowInputs[n].value=s===void 0?"":String(s)}this.syncDecorVisibility(),this.updateDecorTitleValidity()}setRowVisible(e,t){const n=e.closest("label")??e;n.hidden=!t}syncDecorVisibility(){const e=this.ufoElement.sighting.decor.find(c=>c.id===this.currentDecorId),t=e!==void 0,n=e?.kind;this.setRowVisible(this.decorSelect,t),this.setRowVisible(this.deleteDecorButton,t),this.setRowVisible(this.decorTitleInput,t),this.setRowVisible(this.decorEastInput,t),this.setRowVisible(this.decorNorthInput,t),this.setRowVisible(this.decorHeadingInput,t),this.setRowVisible(this.decorLitInput,t);const s=t&&n!==void 0&&s0(n);this.setRowVisible(this.labelDecorWindows,s);const r=n!==void 0?Dc(n):[];for(const c of is)this.decorWindowInputs[c].disabled=!t,this.decorWindowInputs[c].min=String(n!==void 0&&tc(n,c)?0:ec),this.setRowVisible(this.decorWindowInputs[c],s&&r.includes(c));const a=t&&n!==void 0&&$s(n);this.setRowVisible(this.decorWitnessSideSelect,a);const o=n!==void 0?L2(n):[];for(const c of is)this.optionWitnessSide[c].hidden=!o.includes(c);const l=t&&n==="building";this.setRowVisible(this.decorFloorsInput,l),this.setRowVisible(this.decorOccupiedFloorInput,l),this.decorOccupiedFloorInput.max=String(e?.floors??ca)}syncDecorLitFromTimeline(){if(this.ufoElement.playbackState==="playing"||this.shadow.activeElement===this.decorLitInput)return;const e=this.ufoElement.sighting.decor.find(t=>t.id===this.currentDecorId);e&&(this.decorLitInput.checked=nc(e,this.ufoElement.currentTime))}updatePresetButtons(){for(const e of Wd)this.presetButtons[e]?.setAttribute("aria-pressed",String(e===this.currentAppearance.presetId))}get samplingRate(){return Number(this.samplingRateInput.value)}buildPrototype(e=this.defaultBounds()){return Gc(e,this.currentAppearance)}defaultBounds(){const e=this.ufoElement.canvasElement;return{x:e.width/2-os.width/2,y:e.height/2-os.height/2,width:os.width,height:os.height}}toggleRecording(){this.endDrag();const e=this.ufoElement.canvasElement;this.isRecording?(this.recorder?.stop(),this.isRecording=!1,this.setRecordButtonLabel(!1),this.setCanvasCursor(void 0),e.style.touchAction="",this.sourceSelect.disabled=!1,this.addShapeButton.disabled=!1,this.ufoElement.refresh(),this.refreshSourceList()):(this.recorder=new ry(this.ufoElement.sighting.timeline,new ay(this.samplingRate)),this.recorder.start(this.currentSourceId,this.buildPrototype()),this.isRecording=!0,this.setRecordButtonLabel(!0),this.setCanvasCursor("record"),e.style.touchAction="none",this.sourceSelect.disabled=!0,this.addShapeButton.disabled=!0,this.deleteShapeButton.disabled=!0)}setRecordButtonLabel(e){this.recordButton.textContent=e?"⏹":"⏺";const t=e?this.messages.stop:this.messages.record;this.recordButton.title=t,this.recordButton.setAttribute("aria-label",t)}async loadLocaleMessages(){const e=Aa(navigator.languages,Zd);e!=="en"&&this.applyMessages(await cf(e))}applyMessages(e){this.currentSourceId===ta&&this.shapeTitleInput.value===`${this.messages.shape} 1`?(this.messages=e,this.shapeTitleInput.value=`${this.messages.shape} 1`,this.updateShapeTitle()):this.messages=e,this.presetButtons.oval.textContent=e.oval,this.presetButtons.polygon.textContent=e.polygon,this.contextAddVertexButton.textContent=e.addVertex,this.contextDeleteVertexButton.textContent=e.deleteVertex,this.labelColor.textContent=e.color,this.labelTransparency.textContent=e.transparency,this.labelHalo.textContent=e.halo,this.labelShape.textContent=e.shape,this.labelShapeTitle.textContent=e.shapeTitle,this.labelUtcOffset.textContent=e.utcOffset,this.utcOffsetInput.placeholder=e.utcOffsetPlaceholder,this.labelObjectSize.textContent=e.objectSize,this.labelObjectDistance.textContent=e.objectDistance,this.objectSizeInput.placeholder=e.objectSizePlaceholder,this.objectDistanceInput.placeholder=e.objectDistancePlaceholder,this.refreshApparentSize(),this.labelSamplingRate.textContent=e.samplingRate,this.labelDuration.textContent=e.duration,this.durationInput.placeholder=e.durationPlaceholder,this.addShapeButton.title=e.addShape,this.addShapeButton.setAttribute("aria-label",e.addShape),this.deleteShapeButton.title=e.deleteShape,this.deleteShapeButton.setAttribute("aria-label",e.deleteShape),this.contextGroupButton.textContent=e.group,this.contextUngroupButton.textContent=e.ungroup,this.contextBringToFrontButton.textContent=e.bringToFront,this.contextSendToBackButton.textContent=e.sendToBack,this.contextDeleteButton.textContent=e.contextMenuDelete,this.exportButton.textContent=e.export,this.labelImportFile.textContent=e.importFile,this.labelImportUrl.textContent=e.importUrl,this.importUrlInput.placeholder=e.importUrlPlaceholder,this.importUrlButton.textContent=e.importButton,this.labelLatitude.textContent=e.latitude,this.labelLongitude.textContent=e.longitude,this.labelHeading.textContent=e.heading,this.headingInput.placeholder=e.headingPlaceholder,this.labelPitch.textContent=e.pitch,this.labelObservationTime.textContent=e.observationTime,this.labelObservationEndTime.textContent=e.observationEndTime,this.obsTimeInput.placeholder=e.edtfPlaceholder,this.obsTimeInput.title=e.observationTimeHint,this.obsEndTimeInput.placeholder=e.edtfPlaceholder,this.obsEndTimeInput.title=e.observationEndTimeHint,this.presetsGroup.setAttribute("aria-label",e.presetsGroupLabel),this.labelDecor.textContent=e.decor,this.labelDecorFieldset.textContent=e.decor,this.optionDecorBuilding.textContent=e.decorBuilding,this.optionDecorTree.textContent=e.decorTree,this.optionDecorStreetlight.textContent=e.decorStreetlight,this.optionDecorVehicle.textContent=e.decorVehicle,this.optionDecorWitness.textContent=e.decorWitness,this.deleteDecorButton.title=e.deleteDecor,this.deleteDecorButton.setAttribute("aria-label",e.deleteDecor),this.labelDecorTitle.textContent=e.decorTitle,this.labelDecorEast.textContent=e.decorEast,this.labelDecorNorth.textContent=e.decorNorth,this.labelDecorHeading.textContent=e.decorHeading,this.labelDecorLit.textContent=e.decorLit,this.labelDecorSightingUrl.textContent=e.decorSightingUrl,this.contextViewTestimonyButton.textContent=e.viewTestimony,this.labelContextMasks.textContent=`${e.masks} ▸`,this.addDecorWitnessButton.textContent=e.addWitness,this.addDecorBuildingButton.title=e.addDecor,this.addDecorBuildingButton.setAttribute("aria-label",e.addDecor),this.labelDecorFloors.textContent=e.decorFloors,this.labelDecorOccupiedFloor.textContent=e.decorOccupiedFloor,this.labelDecorWitnessSide.textContent=e.decorWitnessSide,this.labelDecorWindows.textContent=e.decorWindows,this.optionWitnessSideNone.textContent=e.decorWitnessSideNone;const t={front:e.decorSideFront,behind:e.decorSideBehind,left:e.decorSideLeft,right:e.decorSideRight,"front-left":e.decorSideFrontLeft,"front-right":e.decorSideFrontRight,"behind-left":e.decorSideBehindLeft,"behind-right":e.decorSideBehindRight};for(const n of is)this.labelDecorSide[n].textContent=t[n],this.optionWitnessSide[n].textContent=t[n];this.refreshDecorList(),this.labelWitnessId.textContent=e.witnessId,this.labelWitnessDirName.textContent=e.witnessDirName,this.labelWitnessTitle.textContent=e.witnessTitle,this.labelWitnessLastName.textContent=e.witnessLastName,this.labelWitnessFirstNames.textContent=e.witnessFirstNames,this.witnessFirstNamesInput.placeholder=e.tagsPlaceholder,this.labelCaseId.textContent=e.caseId,this.labelDescription.textContent=e.description,this.labelTags.textContent=e.tags,this.tagsInput.placeholder=e.tagsPlaceholder,this.labelWeather.textContent=e.weather,this.labelShapeGroup.textContent=e.shapeGroup,this.labelTemporalGroup.textContent=e.temporalGroup,this.labelLocationGroup.textContent=e.locationGroup,this.labelObservationGroup.textContent=e.observationGroup,this.labelWitnessGroup.textContent=e.witnessGroup,this.labelCircumstancesGroup.textContent=e.circumstancesGroup,this.labelCloudCover.textContent=e.cloudCover,this.labelCloudDarkness.textContent=e.cloudDarkness,this.labelPrecipitationType.textContent=e.precipitationType,this.optionPrecipitationNone.textContent=e.precipitationNone,this.optionPrecipitationRain.textContent=e.precipitationRain,this.optionPrecipitationSnow.textContent=e.precipitationSnow,this.optionPrecipitationHail.textContent=e.precipitationHail,this.labelPrecipitationIntensity.textContent=e.precipitationIntensity,this.labelWindDirection.textContent=e.windDirection,this.labelWindSpeed.textContent=e.windSpeed,this.labelStorm.textContent=e.storm,this.labelLensFlareBrightness.textContent=e.lensFlareBrightness,this.labelCameraDevice.textContent=e.cameraDevice,this.loopButton.title=e.autoReplay,this.loopButton.setAttribute("aria-label",e.autoReplay),this.setRecordButtonLabel(this.isRecording),this.syncPlaybackControls()}onPointerDown(e){if(this.isRecording){this.onPointerMove(e);return}const t=this.canvasPointFromEvent(e);if(!t)return;const n=this.ufoElement.sighting.timeline,s=this.ufoElement.currentTime,r=this.ufoElement.playbackState==="playing";if(this.selectedSourceIds.size>1){const l=new Ba(this.selectedMembers()),c=Ke.hitTestHandle({bounds:l.bounds(),angle:0},t);if(c==="rotate"){if(r)return;this.dragState={kind:"group-rotate",group:l,startPointer:t},this.startDragListening();return}if(c){if(r)return;this.dragState={kind:"group-resize",group:l,handle:c},this.startDragListening();return}}else{const l=n.getInterpolatedShapeAt(s,this.currentSourceId),c=l?.kind==="polygon"?Ke.hitTestVertex(l,t):void 0;if(l?.kind==="polygon"&&c!==void 0){if(r)return;this.dragState={kind:"vertex",sourceId:this.currentSourceId,original:l,vertexIndex:c},this.startDragListening();return}const h=l&&Ke.hitTestHandle(l,t);if(l&&h){if(r)return;this.beginDrag(h==="rotate"?"rotate":"resize",this.currentSourceId,l,t,h);return}}const a=n.hitTest(s,t.x,t.y);if(!a){const l=this.pickDecorAt(e);if(l!==void 0){this.selectDecor(l);return}r||this.beginCameraDrag(t);return}if(e.shiftKey?this.toggleUnitSelection(a.sourceId):this.selectedSourceIds.has(a.sourceId)||this.selectUnit(a.sourceId),r)return;const o=[...this.selectedSourceIds].map(l=>({sourceId:l,original:l===a.sourceId?a.shape:n.getInterpolatedShapeAt(s,l)??a.shape}));this.dragState={kind:"move",sources:o,startPointer:t},this.startDragListening()}selectedMembers(){const e=this.ufoElement.sighting.timeline,t=this.ufoElement.currentTime;return[...this.selectedSourceIds].map(n=>({sourceId:n,shape:e.getInterpolatedShapeAt(t,n)})).filter(n=>!!n.shape)}selectUnit(e){const t=this.ufoElement.sighting.timeline.groupMembers(e)??[e];t.length===this.selectedSourceIds.size&&t.every(n=>this.selectedSourceIds.has(n))&&e===this.currentSourceId||(this.selectedSourceIds=new Set(t),this.currentSourceId=e,this.refreshSourceList(),this.onSelectionOrTimeChanged())}toggleUnitSelection(e){const t=this.ufoElement.sighting.timeline,n=t.groupMembers(e)??[e];if(n.every(r=>this.selectedSourceIds.has(r))){if(n.length>=this.selectedSourceIds.size)return;for(const r of n)this.selectedSourceIds.delete(r);if(!this.selectedSourceIds.has(this.currentSourceId)){const r=t.sourceIds;this.currentSourceId=[...this.selectedSourceIds].sort((a,o)=>r.indexOf(a)-r.indexOf(o)).pop()}}else{for(const r of n)this.selectedSourceIds.add(r);this.currentSourceId=e}this.refreshSourceList(),this.onSelectionOrTimeChanged()}onContextMenu(e){if(e.preventDefault(),this.isRecording||this.ufoElement.playbackState==="playing")return;this.hideContextMenu(),this.hideDecorContextMenu();const t=this.canvasPointFromEvent(e);if(!t)return;const n=this.ufoElement.sighting.timeline,s=this.ufoElement.currentTime,r=this.selectedSourceIds.size===1?n.getInterpolatedShapeAt(s,this.currentSourceId):void 0,o=r?.kind==="polygon"&&Ke.hitTestVertex(r,t)!==void 0?{sourceId:this.currentSourceId}:n.hitTest(s,t.x,t.y);if(o){this.selectedSourceIds.has(o.sourceId)||this.selectUnit(o.sourceId),this.currentSourceId=o.sourceId,this.contextMenuPoint=t,this.showContextMenu(e.clientX,e.clientY);return}const l=this.pickDecorAt(e),c=l?this.ufoElement.sighting.decor.find(h=>h.id===l):void 0;c&&this.showDecorContextMenu(e.clientX,e.clientY,c)}pickDecorAt(e){const n=this.ufoElement.canvasElement.getBoundingClientRect();if(n.width===0||n.height===0)return;const s=(e.clientX-n.left)/n.width*2-1,r=-((e.clientY-n.top)/n.height*2-1);return this.sceneElement.pickDecorAt(s,r)}showContextMenu(e,t){this.contextMenu.style.left=`${e}px`,this.contextMenu.style.top=`${t}px`,this.contextMenu.hidden=!1;const n=this.ufoElement.sighting.timeline.sourceIds,s=n.filter(p=>this.selectedSourceIds.has(p)),r=n.length<=s.length,a=s.length>0&&n.slice(n.length-s.length).every(p=>this.selectedSourceIds.has(p)),o=s.length>0&&n.slice(0,s.length).every(p=>this.selectedSourceIds.has(p));this.contextBringToFrontButton.disabled=r||a,this.contextSendToBackButton.disabled=r||o,this.contextBringToFrontButton.title=r?this.messages.onlyOneShape:a?this.messages.alreadyAtFront:"",this.contextSendToBackButton.title=r?this.messages.onlyOneShape:o?this.messages.alreadyAtBack:"",this.contextGroupButton.disabled=this.selectedSourceIds.size<2,this.contextGroupButton.title=this.contextGroupButton.disabled?this.messages.needTwoShapesToGroup:"";const l=this.ufoElement.sighting.timeline.groupMembers(this.currentSourceId)!==void 0;this.contextUngroupButton.disabled=!l,this.contextUngroupButton.title=l?"":this.messages.notGrouped,this.contextDeleteButton.disabled=this.deleteShapeButton.disabled,this.contextDeleteButton.title=this.contextDeleteButton.disabled?this.messages.onlyOneShape:"";const c=this.ufoElement.sighting.timeline.getInterpolatedShapeAt(this.ufoElement.currentTime,this.currentSourceId),h=this.selectedSourceIds.size===1&&c?.kind==="polygon";this.contextAddVertexButton.disabled=!h,this.contextAddVertexButton.title=h?"":this.messages.notAPolygon;const u=h&&this.contextMenuPoint?Ke.hitTestVertex(c,this.contextMenuPoint):void 0,d=h&&c.points.length<=Kd;this.contextDeleteVertexButton.disabled=!h||u===void 0||d,this.contextDeleteVertexButton.title=h?d?this.messages.tooFewVertices:"":this.messages.notAPolygon,document.addEventListener("click",this.handleOutsideContextMenuClick)}hideContextMenu(){this.contextMenu.hidden=!0,this.contextMenuPoint=void 0,document.removeEventListener("click",this.handleOutsideContextMenuClick)}handleOutsideContextMenuClick=e=>{e.composedPath().includes(this.contextMenu)||e.composedPath().includes(this.decorContextMenu)||(this.hideContextMenu(),this.hideDecorContextMenu())};showDecorContextMenu(e,t,n){this.contextMenuDecorId=n.id,this.decorContextMenu.style.left=`${e}px`,this.decorContextMenu.style.top=`${t}px`,this.decorContextMenu.hidden=!1,this.contextViewTestimonyButton.disabled=!n.sightingUrl,this.contextViewTestimonyButton.title=n.sightingUrl?"":this.messages.noWitnessRecording,this.refreshContextMasksSubmenu(n),document.addEventListener("click",this.handleOutsideContextMenuClick)}hideDecorContextMenu(){this.decorContextMenu.hidden=!0,this.contextMenuDecorId=void 0,document.removeEventListener("click",this.handleOutsideContextMenuClick)}refreshContextMasksSubmenu(e){this.contextMasksSubmenu.innerHTML="";for(const t of this.ufoElement.sighting.timeline.sourceIds){const n=document.createElement("label"),s=document.createElement("input");s.type="checkbox",s.checked=e.occludesSourceIds?.includes(t)??!1,s.addEventListener("change",()=>this.updateDecorOccludesShape(e.id,t,s.checked)),n.appendChild(s),n.appendChild(document.createTextNode(this.shapeLabel(t))),this.contextMasksSubmenu.appendChild(n)}}updateDecorOccludesShape(e,t,n){const s=this.ufoElement.sighting;s.decor=s.decor.map(r=>{if(r.id!==e)return r;const a=n?[...new Set([...r.occludesSourceIds??[],t])]:(r.occludesSourceIds??[]).filter(o=>o!==t);return{...r,occludesSourceIds:a.length>0?a:void 0}}),this.ufoElement.refresh()}viewWitnessTestimony(){const e=this.ufoElement.sighting.decor.find(t=>t.id===this.contextMenuDecorId);this.hideDecorContextMenu(),e?.sightingUrl&&this.importFromUrl(e.sightingUrl)}addVertexAtContextMenu(){const e=this.contextMenuPoint;if(this.hideContextMenu(),!e)return;const t=this.ufoElement.currentTime,n=this.ufoElement.sighting.timeline.getInterpolatedShapeAt(t,this.currentSourceId);if(n?.kind!=="polygon")return;const s=Ke.insertVertexNear(n,e);this.ufoElement.sighting.timeline.addKeyframe(t,[{sourceId:this.currentSourceId,shape:s}]),this.ufoElement.refresh()}deleteVertexAtContextMenu(){const e=this.contextMenuPoint;if(this.hideContextMenu(),!e)return;const t=this.ufoElement.currentTime,n=this.ufoElement.sighting.timeline.getInterpolatedShapeAt(t,this.currentSourceId);if(n?.kind!=="polygon")return;const s=Ke.hitTestVertex(n,e);if(s===void 0)return;const r=Ke.deleteVertex(n,s);this.ufoElement.sighting.timeline.addKeyframe(t,[{sourceId:this.currentSourceId,shape:r}]),this.ufoElement.refresh()}bringSelectedToFront(){const e=this.ufoElement.sighting.timeline;for(const t of e.sourceIds.filter(n=>this.selectedSourceIds.has(n)))e.bringToFront(t);this.hideContextMenu(),this.ufoElement.refresh()}sendSelectedToBack(){const e=this.ufoElement.sighting.timeline;for(const t of e.sourceIds.filter(n=>this.selectedSourceIds.has(n)).reverse())e.sendToBack(t);this.hideContextMenu(),this.ufoElement.refresh()}groupSelected(){this.selectedSourceIds.size<2||(this.ufoElement.sighting.timeline.group([...this.selectedSourceIds]),this.hideContextMenu(),this.ufoElement.refresh())}ungroupSelected(){this.ufoElement.sighting.timeline.ungroup(this.currentSourceId),this.selectedSourceIds=new Set([this.currentSourceId]),this.hideContextMenu(),this.ufoElement.refresh()}beginDrag(e,t,n,s,r){this.dragState={kind:e,sourceId:t,original:n,handle:r,startPointer:s},this.startDragListening()}beginCameraDrag(e){const t=this.isWitnessInsideDecor();this.cameraDragState={startPointer:e,startHeadingDeg:t?this.indoorLookYawDeg:this.numberOrUndefined(this.headingInput.value)??0,startPitchDeg:t?this.indoorLookPitchDeg:this.numberOrUndefined(this.pitchInput.value)??0,insideDecor:t},t||this.sceneElement.setCompassForced(!0),this.setCanvasCursor("panning"),this.startDragListening()}isWitnessInsideDecor(){return this.ufoElement.sighting.decor.some(e=>e.witnessSide!==void 0&&$s(e.kind))}syncIndoorLookReset(){const e=this.ufoElement.sighting.decor.find(n=>n.witnessSide!==void 0&&$s(n.kind)),t=e?`${e.id}:${e.witnessSide}`:void 0;t!==this.lastInhabitedKey&&(this.lastInhabitedKey=t,this.indoorLookYawDeg=0,this.indoorLookPitchDeg=0,this.sceneElement.setIndoorLook(0,0))}startDragListening(){document.addEventListener("pointermove",this.handleDragPointerMove),document.addEventListener("pointerup",this.handleDragPointerUp)}onDragPointerMove(e){if(this.cameraDragState){this.onCameraDragPointerMove(e);return}if(!this.dragState)return;const t=this.canvasPointFromEvent(e);if(!t)return;const n=this.ufoElement.currentTime;if(this.dragState.kind==="move"){const{sources:s,startPointer:r}=this.dragState,a=t.x-r.x,o=t.y-r.y,l=s.map(({sourceId:c,original:h})=>({sourceId:c,shape:{...h,bounds:{...h.bounds,x:h.bounds.x+a,y:h.bounds.y+o}}}));this.ufoElement.sighting.timeline.addKeyframe(n,l)}else if(this.dragState.kind==="group-resize"){const{group:s,handle:r}=this.dragState;this.ufoElement.sighting.timeline.addKeyframe(n,s.resize(r,t))}else if(this.dragState.kind==="group-rotate"){const{group:s,startPointer:r}=this.dragState;this.ufoElement.sighting.timeline.addKeyframe(n,s.rotate(t,r))}else if(this.dragState.kind==="vertex"){const{sourceId:s,original:r,vertexIndex:a}=this.dragState,o=Ke.moveVertex(r,a,t);this.ufoElement.sighting.timeline.addKeyframe(n,[{sourceId:s,shape:o}])}else{const{kind:s,sourceId:r,original:a,handle:o}=this.dragState,l=s==="resize"?Ke.resizeShape(a,o,t):Ke.rotateShape(a,t);this.ufoElement.sighting.timeline.addKeyframe(n,[{sourceId:r,shape:l}])}this.ufoElement.refresh()}onCameraDragPointerMove(e){if(!this.cameraDragState)return;const t=this.canvasPointFromEvent(e);if(!t)return;const{startPointer:n,startHeadingDeg:s,startPitchDeg:r,insideDecor:a}=this.cameraDragState,o=s+(t.x-n.x)*Gd,l=Math.max(-90,Math.min(90,r-(t.y-n.y)*Gd));if(a){this.indoorLookYawDeg=o,this.indoorLookPitchDeg=l,this.sceneElement.setIndoorLook(o,l),this.ufoElement.refresh();return}this.headingInput.value=String(o),this.pitchInput.value=String(l),this.updateObserver()}endDrag(){!this.dragState&&!this.cameraDragState||(this.cameraDragState&&!this.cameraDragState.insideDecor&&this.sceneElement.setCompassForced(!1),this.dragState=void 0,this.cameraDragState=void 0,this.setCanvasCursor(this.hoverCursor),document.removeEventListener("pointermove",this.handleDragPointerMove),document.removeEventListener("pointerup",this.handleDragPointerUp))}nudgeBounds(e,t){const n={...e};if(t.shiftKey){switch(t.key){case"ArrowLeft":n.width=Math.max(ri,n.width-ti);break;case"ArrowRight":n.width+=ti;break;case"ArrowUp":n.height=Math.max(ri,n.height-ti);break;case"ArrowDown":n.height+=ti;break}n.x-=(n.width-e.width)/2,n.y-=(n.height-e.height)/2}else switch(t.key){case"ArrowLeft":n.x-=ti;break;case"ArrowRight":n.x+=ti;break;case"ArrowUp":n.y-=ti;break;case"ArrowDown":n.y+=ti;break}return n}moveOrResizeSelectedShapes(e){if(this.isRecording||this.ufoElement.playbackState==="playing")return;const t=this.ufoElement.sighting.timeline,n=this.ufoElement.currentTime,s=this.selectedMembers();if(s.length!==0){if(e.preventDefault(),s.length===1){const{sourceId:r,shape:a}=s[0];t.addKeyframe(n,[{sourceId:r,shape:{...a,bounds:this.nudgeBounds(a.bounds,e)}}])}else{const r=new Ba(s),a=this.nudgeBounds(r.bounds(),e);t.addKeyframe(n,r.scaleTo(a))}this.ufoElement.refresh()}}updateHoverCursor(e){this.isRecording||this.dragState||this.cameraDragState||(this.hoverCursor=this.hoverCursorAt(e),this.setCanvasCursor(this.hoverCursor))}hoverCursorAt(e){const t=this.canvasPointFromEvent(e);if(!t)return;const n=this.ufoElement.sighting.timeline,s=this.ufoElement.currentTime,r=this.ufoElement.playbackState!=="playing";if(r)if(this.selectedSourceIds.size>1){const a=Ke.hitTestHandle({bounds:new Ba(this.selectedMembers()).bounds(),angle:0},t);if(a)return this.cursorForHandle(a,0)}else{const a=n.getInterpolatedShapeAt(s,this.currentSourceId);if(a?.kind==="polygon"&&Ke.hitTestVertex(a,t)!==void 0)return"vertex";const o=a&&Ke.hitTestHandle(a,t);if(a&&o)return this.cursorForHandle(o,a.angle)}return n.hitTest(s,t.x,t.y)?r?"move":"select":this.pickDecorAt(e)!==void 0?"select":r?"pan":void 0}cursorForHandle(e,t){return e==="rotate"?"rotate":`resize-${Ke.resizeAxisFor(e,t)}`}setCanvasCursor(e){const t=this.ufoElement.canvasElement;e?t.dataset.cursor=e:delete t.dataset.cursor}onPointerMove(e){if(!this.isRecording){this.updateHoverCursor(e);return}const t=this.ufoElement.canvasElement,n=t.getBoundingClientRect(),s=e.clientX-n.left,r=e.clientY-n.top;this.recorder?.onPointerMove(s,r),this.ufoElement.renderer.clear(t.width,t.height),this.ufoElement.renderer.paintShape(Yd(this.buildPrototype({x:0,y:0,width:os.width,height:os.height}),s,r))}canvasPointFromEvent(e){const t=this.ufoElement.canvasElement,n=t.getBoundingClientRect();if(!(n.width===0||n.height===0))return{x:(e.clientX-n.left)/n.width*t.width,y:(e.clientY-n.top)/n.height*t.height}}}const Xd="rr0-ufo-recorder";function dy(){Ia(),customElements.get(Xd)||customElements.define(Xd,hy)}dy();
@@ -0,0 +1 @@
1
+ const e={testimonyBy:"Témoignage de",about:"À propos",close:"Fermer",observation:"Observation",date:"Date",location:"Lieu",case:"Dossier",description:"Description",tags:"Mots-clés",credits:"Crédits",editThisObservation:"Éditer cette observation",embed:"Intégrer",embedReplay:"Relecture",embedEdit:"Édition",embedCopy:"Copier",embedCopied:"Copié"};export{e as eyewitnessMessages_fr};