@rr0/ufoathome 0.10.0 → 0.10.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.
@@ -1 +1 @@
1
- const e={oval:"Ovale",saucer:"Soucoupe",triangle:"Triangle",color:"Couleur",transparency:"Transparence",halo:"Halo",shape:"Forme",shapeTitle:"Nom",addShape:"Ajouter une forme",deleteShape:"Supprimer la forme",play:"Lecture",pause:"Pause",noDuration:"Aucune durée d'observation",autoReplay:"Lecture automatique",group:"Grouper",ungroup:"Dégrouper",bringToFront:"Placer devant",sendToBack:"Placer derrière",contextMenuDelete:"Supprimer",confirmDeleteShape:"Supprimer {name} ? Cette action est irréversible.",confirmDeleteShapes:"Supprimer {count} formes ? Cette action est irréversible.",onlyOneShape:"Il n'y a qu'une seule forme",alreadyAtFront:"Cette forme est déjà la plus en avant",alreadyAtBack:"Cette forme est déjà la plus en arrière",needTwoShapesToGroup:"Sélectionnez au moins deux formes pour les grouper",notGrouped:"Cette forme ne fait pas partie d'un groupe",multipleShapesSelected:"Plusieurs formes sélectionnées — sélectionnez-en une seule pour modifier ceci",samplingRate:"Fréquence d'échantillonnage",duration:"Durée",durationPlaceholder:"durée de l'observation",durationImprecise:"Ces dates ne permettent pas de déterminer précisément une durée — saisissez-la manuellement.",export:"Exporter le JSON",importFile:"Charger un fichier JSON",importUrl:"Ou charger depuis une URL",importUrlPlaceholder:"https://…/sighting.json",importButton:"Charger",importError:"Impossible de charger cet enregistrement — vérifiez le fichier ou l'URL et réessayez.",record:"Enregistrer",stop:"Arrêter",latitude:"Latitude",longitude:"Longitude",heading:"Orientation",headingPlaceholder:"inconnu",pitch:"Inclinaison",observationTime:"Début de l'observation",observationEndTime:"Fin de l'observation",edtfInvalid:"Date/heure EDTF invalide (ex. 1965-07-01T05:00, 2025-06?, 2025~).",edtfPlaceholder:"AAAA-MM-JJThh:mm[?~%] ou hh:mm",observationTimeHint:"EDTF — ex. 1965-07-01T05:00, 2025-06? (incertain), 2025~ (approximatif), ou juste 05:00 si la date est inconnue",observationEndTimeHint:"EDTF — ex. 1965-07-01T05:10, 2025-06? (incertain), 2025~ (approximatif), ou juste 05:10 si la date est inconnue",presetsGroupLabel:"Forme de l'ovni",witnessId:"ID témoin",witnessDirName:"Répertoire du témoin",witnessTitle:"Titre du témoin",witnessLastName:"Nom de famille du témoin",witnessFirstNames:"Prénoms du témoin",caseId:"ID de l'affaire",description:"Description",tags:"Mots-clés",tagsPlaceholder:"séparés par des virgules",weather:"Météo",shapeGroup:"Forme",temporalGroup:"Temporel",locationGroup:"Lieu",observationGroup:"Observation",witnessGroup:"Témoin",circumstancesGroup:"Circonstances",cloudCover:"Couverture nuageuse",cloudDarkness:"Obscurité des nuages",precipitationType:"Précipitations",precipitationNone:"Aucune",precipitationRain:"Pluie",precipitationSnow:"Neige",precipitationHail:"Grêle",precipitationIntensity:"Intensité",windDirection:"Direction du vent",windSpeed:"Force du vent",storm:"Orage",lensFlareBrightness:"Intensité lumineuse",cameraDevice:"Appareil photo/vidéo",decorGroup:"Décor",decorKind:"Type",decor:"Décor",decorBuilding:"Bâtiment",decorTree:"Arbre",decorStreetlight:"Lampadaire",decorVehicle:"Véhicule",decorWitness:"Autre témoin",addDecor:"Ajouter un élément de décor",deleteDecor:"Supprimer l'élément de décor",decorEast:"Distance à l'est",decorNorth:"Distance au nord",decorHeading:"Orientation",decorLit:"Allumé",decorTitle:"Nom",decorSightingUrl:"URL de l'enregistrement du témoin",viewTestimony:"Voir le témoignage",noWitnessRecording:"Aucune URL d'enregistrement définie pour ce témoin",addWitness:"Ajouter un témoin",addBuilding:"Ajouter un bâtiment"};export{e as ufoRecorderMessages_fr};
1
+ const e={oval:"Ovale",saucer:"Soucoupe",triangle:"Triangle",color:"Couleur",transparency:"Transparence",halo:"Halo",shape:"Forme",shapeTitle:"Nom",addShape:"Ajouter une forme",deleteShape:"Supprimer la forme",play:"Lecture",pause:"Pause",noDuration:"Aucune durée d'observation",autoReplay:"Lecture automatique",group:"Grouper",ungroup:"Dégrouper",bringToFront:"Placer devant",sendToBack:"Placer derrière",contextMenuDelete:"Supprimer",confirmDeleteShape:"Supprimer {name} ? Cette action est irréversible.",confirmDeleteShapes:"Supprimer {count} formes ? Cette action est irréversible.",onlyOneShape:"Il n'y a qu'une seule forme",alreadyAtFront:"Cette forme est déjà la plus en avant",alreadyAtBack:"Cette forme est déjà la plus en arrière",needTwoShapesToGroup:"Sélectionnez au moins deux formes pour les grouper",notGrouped:"Cette forme ne fait pas partie d'un groupe",multipleShapesSelected:"Plusieurs formes sélectionnées — sélectionnez-en une seule pour modifier ceci",samplingRate:"Fréquence d'échantillonnage",duration:"Durée",durationPlaceholder:"durée de l'observation",durationImprecise:"Ces dates ne permettent pas de déterminer précisément une durée — saisissez-la manuellement.",export:"Exporter le JSON",importFile:"Charger un fichier JSON",importUrl:"Ou charger depuis une URL",importUrlPlaceholder:"https://…/sighting.json",importButton:"Charger",importError:"Impossible de charger cet enregistrement — vérifiez le fichier ou l'URL et réessayez.",record:"Enregistrer",stop:"Arrêter",latitude:"Latitude",longitude:"Longitude",heading:"Orientation",headingPlaceholder:"inconnu",pitch:"Inclinaison",observationTime:"Début de l'observation",observationEndTime:"Fin de l'observation",edtfInvalid:"Date/heure EDTF invalide (ex. 1965-07-01T05:00, 2025-06?, 2025~).",edtfPlaceholder:"AAAA-MM-JJThh:mm[?~%] ou hh:mm",observationTimeHint:"EDTF — ex. 1965-07-01T05:00, 2025-06? (incertain), 2025~ (approximatif), ou juste 05:00 si la date est inconnue",observationEndTimeHint:"EDTF — ex. 1965-07-01T05:10, 2025-06? (incertain), 2025~ (approximatif), ou juste 05:10 si la date est inconnue",presetsGroupLabel:"Forme de l'ovni",witnessId:"ID témoin",witnessDirName:"Répertoire du témoin",witnessTitle:"Titre du témoin",witnessLastName:"Nom de famille du témoin",witnessFirstNames:"Prénoms du témoin",caseId:"ID de l'affaire",description:"Description",tags:"Mots-clés",tagsPlaceholder:"séparés par des virgules",weather:"Météo",shapeGroup:"Forme",temporalGroup:"Temporel",locationGroup:"Lieu",observationGroup:"Observation",witnessGroup:"Témoin",circumstancesGroup:"Circonstances",cloudCover:"Couverture nuageuse",cloudDarkness:"Obscurité des nuages",precipitationType:"Précipitations",precipitationNone:"Aucune",precipitationRain:"Pluie",precipitationSnow:"Neige",precipitationHail:"Grêle",precipitationIntensity:"Intensité",windDirection:"Direction du vent",windSpeed:"Force du vent",storm:"Orage",lensFlareBrightness:"Intensité lumineuse",cameraDevice:"Appareil photo/vidéo",decorKind:"Type",decor:"Décor",decorBuilding:"Bâtiment",decorTree:"Arbre",decorStreetlight:"Lampadaire",decorVehicle:"Véhicule",decorWitness:"Autre témoin",addDecor:"Ajouter un élément de décor",deleteDecor:"Supprimer l'élément de décor",decorEast:"Distance à l'est",decorNorth:"Distance au nord",decorHeading:"Orientation",decorLit:"Allumé",decorTitle:"Nom",decorSightingUrl:"URL de l'enregistrement du témoin",viewTestimony:"Voir le témoignage",noWitnessRecording:"Aucune URL d'enregistrement définie pour ce témoin",addWitness:"Ajouter un témoin",addBuilding:"Ajouter un bâtiment"};export{e as ufoRecorderMessages_fr};
@@ -31,6 +31,27 @@ const Ud=`
31
31
  <label><span id="label-heading">Heading</span> <input id="heading" type="number" min="0" max="360" step="1" placeholder="unknown"/> &deg;</label>
32
32
  <label><span id="label-pitch">Tilt</span> <input id="pitch" type="number" min="-90" max="90" step="1" value="0"/> &deg;</label>
33
33
  <button id="add-decor-building" type="button">Add building</button>
34
+ <label><span id="label-decor-kind">Kind</span>
35
+ <select id="decorKind">
36
+ <!-- Building/witness are added from their own dedicated buttons instead (this group's own
37
+ "Add building" above, Witness's own "Add witness") — hidden (not removed) so
38
+ decorLabel() can still look up their translated kind name by id for the fallback
39
+ "{kind} {n}" label, see UfoRecorderElement.decorLabel. -->
40
+ <option id="option-decor-building" value="building" hidden>Building</option>
41
+ <option id="option-decor-tree" value="tree">Tree</option>
42
+ <option id="option-decor-streetlight" value="streetlight">Streetlight</option>
43
+ <option id="option-decor-vehicle" value="vehicle">Vehicle</option>
44
+ <option id="option-decor-witness" value="witness" hidden>Other witness</option>
45
+ </select>
46
+ </label>
47
+ <button id="add-decor" type="button" class="icon-btn" title="Add decor" aria-label="Add decor">+</button>
48
+ <button id="delete-decor" type="button" class="icon-btn" title="Delete decor" aria-label="Delete decor">🗑</button>
49
+ <label><span id="label-decor">Decor</span> <select id="decor"></select></label>
50
+ <label><span id="label-decor-title">Name</span> <input id="decorTitle" type="text"/></label>
51
+ <label><span id="label-decor-east">Distance east</span> <input id="decorEast" type="number" step="0.5" value="0"/> m</label>
52
+ <label><span id="label-decor-north">Distance north</span> <input id="decorNorth" type="number" step="0.5" value="0"/> m</label>
53
+ <label><span id="label-decor-heading">Heading</span> <input id="decorHeading" type="number" min="0" max="360" step="1" value="0"/> &deg;</label>
54
+ <label><span id="label-decor-lit">Lit</span> <input id="decorLit" type="checkbox"/></label>
34
55
  </div>
35
56
  </details>
36
57
  <details open>
@@ -64,31 +85,6 @@ const Ud=`
64
85
  <label><span id="label-lens-flare-brightness">Light intensity</span> <input id="lensFlareBrightness" type="range" min="0" max="3" step="0.1" value="1"/></label>
65
86
  </div>
66
87
  </details>
67
- <details open>
68
- <summary id="label-decor-group">Decor</summary>
69
- <div class="toolbar">
70
- <label><span id="label-decor-kind">Kind</span>
71
- <select id="decorKind">
72
- <!-- Building/witness are added from their own dedicated buttons instead (Location/Witness
73
- groups) — hidden (not removed) so decorLabel() can still look up their translated
74
- kind name by id for the fallback "{kind} {n}" label, see UfoRecorderElement.decorLabel. -->
75
- <option id="option-decor-building" value="building" hidden>Building</option>
76
- <option id="option-decor-tree" value="tree">Tree</option>
77
- <option id="option-decor-streetlight" value="streetlight">Streetlight</option>
78
- <option id="option-decor-vehicle" value="vehicle">Vehicle</option>
79
- <option id="option-decor-witness" value="witness" hidden>Other witness</option>
80
- </select>
81
- </label>
82
- <button id="add-decor" type="button" class="icon-btn" title="Add decor" aria-label="Add decor">+</button>
83
- <button id="delete-decor" type="button" class="icon-btn" title="Delete decor" aria-label="Delete decor">🗑</button>
84
- <label><span id="label-decor">Decor</span> <select id="decor"></select></label>
85
- <label><span id="label-decor-title">Name</span> <input id="decorTitle" type="text"/></label>
86
- <label><span id="label-decor-east">Distance east</span> <input id="decorEast" type="number" step="0.5" value="0"/> m</label>
87
- <label><span id="label-decor-north">Distance north</span> <input id="decorNorth" type="number" step="0.5" value="0"/> m</label>
88
- <label><span id="label-decor-heading">Heading</span> <input id="decorHeading" type="number" min="0" max="360" step="1" value="0"/> &deg;</label>
89
- <label><span id="label-decor-lit">Lit</span> <input id="decorLit" type="checkbox"/></label>
90
- </div>
91
- </details>
92
88
  <details open>
93
89
  <summary id="label-shape-group">Shape</summary>
94
90
  <div class="toolbar">
@@ -481,7 +477,7 @@ input[type=range] {
481
477
  pointer-events: none;
482
478
  white-space: nowrap;
483
479
  }
484
- `;function Bd(i,e="#39ff14"){return{kind:"oval",bounds:i,color:e,angle:0,transparency:0,haloScale:0,selected:!1}}function du(i,e,t="#39ff14"){return{kind:"polygon",bounds:i,points:e,color:t,angle:0,transparency:0,haloScale:0,selected:!1}}function zd(i,e="#39ff14"){const{width:t,height:n}=i,s=[{x:.5*t,y:0},{x:.8*t,y:.25*n},{x:t,y:.5*n},{x:.8*t,y:.75*n},{x:.5*t,y:n},{x:.2*t,y:.75*n},{x:0,y:.5*n},{x:.2*t,y:.25*n}];return du(i,s,e)}function kd(i,e="#39ff14"){const{width:t,height:n}=i,s=[{x:0,y:0},{x:t,y:n/2},{x:0,y:n}];return du(i,s,e)}const Gd={oval:Bd,saucer:zd,triangle:kd};function cc(i,e){return{...Gd[e.presetId](i,e.color),transparency:e.transparency,haloScale:e.haloScale}}function Hd(i,e,t){const{bounds:n}=i;return e>=n.x&&e<=n.x+n.width&&t>=n.y&&t<=n.y+n.height}function fu(i,e,t){const n=i.bounds.width,s=i.bounds.height;return{...i,bounds:{x:e-n/2,y:t-s/2,width:n,height:s}}}function Zt(i,e,t){return i+(e-i)*t}function hc(i){const e=/^#([0-9a-f]{6})$/i.exec(i);if(!e)return;const t=parseInt(e[1],16);return[t>>16&255,t>>8&255,t&255]}function Vd(i){return`#${i.map(e=>Math.round(e).toString(16).padStart(2,"0")).join("")}`}function Wd(i,e,t){const n=hc(i),s=hc(e);return!n||!s?t<1?i:e:Vd([Zt(n[0],s[0],t),Zt(n[1],s[1],t),Zt(n[2],s[2],t)])}function Xd(i,e,t){const n={x:Zt(i.bounds.x,e.bounds.x,t),y:Zt(i.bounds.y,e.bounds.y,t),width:Zt(i.bounds.width,e.bounds.width,t),height:Zt(i.bounds.height,e.bounds.height,t)},s=Zt(i.angle,e.angle,t),r=Zt(i.transparency,e.transparency,t),a=Zt(i.haloScale,e.haloScale,t),o=Wd(i.color,e.color,t);return i.kind==="polygon"&&e.kind==="polygon"&&i.points.length===e.points.length?{...i,bounds:n,angle:s,transparency:r,haloScale:a,color:o,points:i.points.map((l,c)=>({x:Zt(l.x,e.points[c].x,t),y:Zt(l.y,e.points[c].y,t)}))}:{...t<1?i:e,bounds:n,angle:s,transparency:r,haloScale:a,color:o}}class ta{keyframes=[];order=[];groups=[];addKeyframe(e,t){const n=this.findInsertIndex(e);if(this.keyframes[n]?.t===e){const s=new Set(t.map(r=>r.sourceId));this.keyframes[n]={t:e,shapes:[...this.keyframes[n].shapes.filter(r=>!s.has(r.sourceId)),...t]}}else this.keyframes.splice(n,0,{t:e,shapes:[...t]});for(const s of t)this.order.includes(s.sourceId)||this.order.push(s.sourceId)}findInsertIndex(e){let t=0,n=this.keyframes.length;for(;t<n;){const s=t+n>>>1;this.keyframes[s].t<e?t=s+1:n=s}return t}getKeyframeAt(e){const t=this.findInsertIndex(e),n=this.keyframes[t];return n?.t===e?n:void 0}getShapeAt(e,t){return this.getKeyframeAt(e)?.shapes.find(n=>n.sourceId===t)?.shape}getLatestShapeAt(e,t){let n=this.findInsertIndex(e);for(this.keyframes[n]?.t!==e&&(n-=1);n>=0;n--){const s=this.keyframes[n].shapes.find(r=>r.sourceId===t);if(s)return s.shape}}getInterpolatedShapeAt(e,t){const n=this.findShapeAtOrBefore(e,t);if(n?.t===e)return n.shape;const s=this.findShapeAtOrAfter(e,t);return n?s?Xd(n.shape,s.shape,(e-n.t)/(s.t-n.t)):n.shape:s?.shape}findShapeAtOrBefore(e,t){let n=this.findInsertIndex(e);for(this.keyframes[n]?.t!==e&&(n-=1);n>=0;n--){const s=this.keyframes[n].shapes.find(r=>r.sourceId===t);if(s)return{t:this.keyframes[n].t,shape:s.shape}}}findShapeAtOrAfter(e,t){for(let n=this.findInsertIndex(e);n<this.keyframes.length;n++){const s=this.keyframes[n].shapes.find(r=>r.sourceId===t);if(s)return{t:this.keyframes[n].t,shape:s.shape}}}hitTest(e,t,n){const s=this.sourceIds;for(let r=s.length-1;r>=0;r--){const a=this.getInterpolatedShapeAt(e,s[r]);if(a&&Hd(a,t,n))return{sourceId:s[r],shape:a}}}removeSource(e){for(let t=this.keyframes.length-1;t>=0;t--){const n=this.keyframes[t].shapes.filter(s=>s.sourceId!==e);n.length===0?this.keyframes.splice(t,1):n.length!==this.keyframes[t].shapes.length&&(this.keyframes[t]={t:this.keyframes[t].t,shapes:n})}this.order=this.order.filter(t=>t!==e),this.removeFromGroup(e)}group(e){if(!(e.length<2)){for(const t of e)this.removeFromGroup(t);this.groups.push([...e])}}ungroup(e){const t=this.groups.findIndex(n=>n.includes(e));t!==-1&&this.groups.splice(t,1)}groupMembers(e){return this.groups.find(t=>t.includes(e))}removeFromGroup(e){const t=this.groups.findIndex(s=>s.includes(e));if(t===-1)return;const n=this.groups[t].filter(s=>s!==e);n.length<2?this.groups.splice(t,1):this.groups[t]=n}bringToFront(e){const t=this.order.indexOf(e);t!==-1&&(this.order.splice(t,1),this.order.push(e))}sendToBack(e){const t=this.order.indexOf(e);t!==-1&&(this.order.splice(t,1),this.order.unshift(e))}get duration(){return this.keyframes.length===0?0:this.keyframes[this.keyframes.length-1].t}get sourceIds(){return[...this.order]}get allKeyframes(){return this.keyframes}toJSON(){return{keyframes:this.keyframes,order:this.order,groups:this.groups}}static fromJSON(e){const t=new ta;for(const n of e.keyframes)t.addKeyframe(n.t,n.shapes);if(e.order){const n=t.order.filter(s=>!e.order.includes(s));t.order=[...e.order,...n]}return e.groups&&(t.groups=e.groups.map(n=>n.filter(s=>t.order.includes(s))).filter(n=>n.length>=2)),t}}function Yd(i,e,t){return Math.max(e,Math.min(t,i))}function qd(i,e,t){const n=((e-i)%360+540)%360-180;return((i+n*t)%360+360)%360}function hs(i,e,t){return i+(e-i)*t}function Kd(i,e,t){return{lat:i.lat===void 0||e.lat===void 0?void 0:hs(i.lat,e.lat,t),lng:i.lng===void 0||e.lng===void 0?void 0:hs(i.lng,e.lng,t),elevationM:hs(i.elevationM,e.elevationM,t),headingDeg:i.headingDeg===void 0||e.headingDeg===void 0?void 0:qd(i.headingDeg,e.headingDeg,t),pitchDeg:hs(i.pitchDeg,e.pitchDeg,t),fovDeg:hs(i.fovDeg,e.fovDeg,t)}}class Is{keyframes=[];addKeyframe(e,t){const n=this.findInsertIndex(e);this.keyframes[n]?.t===e?this.keyframes[n]={t:e,pose:t}:this.keyframes.splice(n,0,{t:e,pose:t})}clear(){this.keyframes.length=0}removeKeyframeAt(e){const t=this.findInsertIndex(e);this.keyframes[t]?.t===e&&this.keyframes.splice(t,1)}findInsertIndex(e){let t=0,n=this.keyframes.length;for(;t<n;){const s=t+n>>>1;this.keyframes[s].t<e?t=s+1:n=s}return t}getLatestPoseAt(e){let t=this.findInsertIndex(e);return this.keyframes[t]?.t!==e&&(t-=1),t>=0?this.keyframes[t].pose:void 0}getInterpolatedPoseAt(e){const t=this.findInsertIndex(e),n=this.keyframes[t]?.t===e?this.keyframes[t]:this.keyframes[t-1];if(n?.t===e)return n.pose;const s=this.keyframes[t]?.t===e?void 0:this.keyframes[t];return n?s?Kd(n.pose,s.pose,Yd((e-n.t)/(s.t-n.t),0,1)):n.pose:s?.pose}get duration(){return this.keyframes.length===0?0:this.keyframes[this.keyframes.length-1].t}get allKeyframes(){return this.keyframes}toJSON(){return{keyframes:this.keyframes}}static fromJSON(e){const t=new Is;for(const n of e.keyframes)t.addKeyframe(n.t,n.pose);return t}}function Gs(i,e,t){return i+(e-i)*t}function $d(i,e,t){const n=((e-i)%360+540)%360-180;return((i+n*t)%360+360)%360}function Zd(i,e,t){return Math.max(e,Math.min(t,i))}function Jd(i,e,t){return{cloudCover:Gs(i.cloudCover,e.cloudCover,t),cloudDarkness:Gs(i.cloudDarkness,e.cloudDarkness,t),precipitationType:t<1?i.precipitationType:e.precipitationType,precipitationIntensity:Gs(i.precipitationIntensity,e.precipitationIntensity,t),windDirectionDeg:$d(i.windDirectionDeg,e.windDirectionDeg,t),windSpeed:Gs(i.windSpeed,e.windSpeed,t),storm:t<1?i.storm:e.storm}}class Ds{keyframes=[];addKeyframe(e,t){const n=this.findInsertIndex(e);this.keyframes[n]?.t===e?this.keyframes[n]={t:e,weather:t}:this.keyframes.splice(n,0,{t:e,weather:t})}clear(){this.keyframes.length=0}removeKeyframeAt(e){const t=this.findInsertIndex(e);this.keyframes[t]?.t===e&&this.keyframes.splice(t,1)}findInsertIndex(e){let t=0,n=this.keyframes.length;for(;t<n;){const s=t+n>>>1;this.keyframes[s].t<e?t=s+1:n=s}return t}getLatestWeatherAt(e){let t=this.findInsertIndex(e);return this.keyframes[t]?.t!==e&&(t-=1),t>=0?this.keyframes[t].weather:void 0}getInterpolatedWeatherAt(e){const t=this.findInsertIndex(e),n=this.keyframes[t]?.t===e?this.keyframes[t]:this.keyframes[t-1];if(n?.t===e)return n.weather;const s=this.keyframes[t]?.t===e?void 0:this.keyframes[t];return n?s?Jd(n.weather,s.weather,Zd((e-n.t)/(s.t-n.t),0,1)):n.weather:s?.weather}get duration(){return this.keyframes.length===0?0:this.keyframes[this.keyframes.length-1].t}get allKeyframes(){return this.keyframes}toJSON(){return{keyframes:this.keyframes}}static fromJSON(e){const t=new Ds;for(const n of e.keyframes)t.addKeyframe(n.t,n.weather);return t}}const pu={cloudCover:0,cloudDarkness:0,precipitationType:"none",precipitationIntensity:0,windDirectionDeg:0,windSpeed:0,storm:!1},Qd=/^(?:(?<year>\d{4}|\d{3}X|\d{2}XX)(-(?<month>0[1-9]|1[0-2]))?(-(?<day>0[1-9]|[12]\d|3[01]))?(?:[T ](?<hour>[01]?\d|2[0-3]):(?<minute>[0-5]\d)(?::(?<second>[0-5]\d))?)?|(?<timeOnlyHour>[01]?\d|2[0-3]):(?<timeOnlyMinute>[0-5]\d)(?::(?<timeOnlySecond>[0-5]\d))?)[?~%]?$/;function uc(i){const e=Qd.exec(i.trim());if(!e?.groups)return;const{year:t,month:n,day:s,hour:r,minute:a,second:o,timeOnlyHour:l,timeOnlyMinute:c,timeOnlySecond:h}=e.groups,d=r??l,u=a??c,p=o??h;return{year:t&&!t.includes("X")?Number(t):void 0,month:n?Number(n):void 0,day:s?Number(s):void 0,hour:d?Number(d):void 0,minute:u?Number(u):void 0,second:p?Number(p):void 0,raw:i.trim()}}function dc(i){if(i.raw!==void 0)return i.raw;if(i.year===void 0){if(i.hour===void 0)return"";let t=`${String(i.hour).padStart(2,"0")}:${String(i.minute??0).padStart(2,"0")}`;return i.second!==void 0&&(t+=`:${String(i.second).padStart(2,"0")}`),t}let e=String(i.year).padStart(4,"0");return i.month===void 0||(e+=`-${String(i.month).padStart(2,"0")}`,i.day===void 0)||(e+=`-${String(i.day).padStart(2,"0")}`,i.hour===void 0)||(e+=`T${String(i.hour).padStart(2,"0")}:${String(i.minute??0).padStart(2,"0")}`,i.second!==void 0&&(e+=`:${String(i.second).padStart(2,"0")}`)),e}function ho(i){if(i.year!==void 0)return Date.UTC(i.year,(i.month??1)-1,i.day??1,i.hour??0,i.minute??0,i.second??0)}function fc(i){return(((i.day??0)*24+(i.hour??0))*60+(i.minute??0))*6e4+(i.second??0)*1e3}const jd=["year","month","day","hour","minute"],e0=["day","hour","minute"];function pc(i,e){return e.filter(t=>i[t]!==void 0).join(",")}function Il(i){if(i.durationSeconds!==void 0)return i.durationSeconds*1e3;if(!i.time||!i.endTime)return;const e=i.time.year!==void 0&&i.endTime.year!==void 0,t=e?jd:e0,n=pc(i.time,t);if(!(n===""||n!==pc(i.endTime,t)))return e?ho(i.endTime)-ho(i.time):fc(i.endTime)-fc(i.time)}function t0(i){if(i.durationSeconds===void 0&&!(!i.time||!i.endTime))return Il(i)===void 0?"imprecise":void 0}class na{constructor(e,t,n,s,r,a,o,l=[]){this.event=e,this.timeline=t,this.witnessTrack=n,this.weatherTrack=s,this.witness=r,this.caseId=a,this.weather=o,this.decor=l}static create(e,t,n){return new na({eventType:"sighting",time:e,place:t},new ta,new Is,new Ds,n)}}const n0=0,i0=0,s0=60;function mc(i,e){const t=i.witnessTrack.getInterpolatedPoseAt(e);if(t)return t;const n=i.event.place?.[0];if(n)return{lat:n.lat,lng:n.lng,elevationM:n0,headingDeg:void 0,pitchDeg:i0,fovDeg:s0}}function uo(i,e){return i.weatherTrack.getInterpolatedWeatherAt(e)??i.weather??pu}class r0{constructor(e,t){this.timeline=e,this.onFrame=t}rafId=null;state="stopped";currentT=0;lastWallTime=0;playbackRate=1;loop=!1;durationOverrideMs=0;get seekableDuration(){return Math.max(this.timeline.duration,this.durationOverrideMs)}play(){if(this.state==="playing")return;this.currentT>=this.seekableDuration&&(this.currentT=0,this.resolveFrame(0)),this.state="playing",this.lastWallTime=performance.now();const e=()=>{if(this.state!=="playing")return;const t=performance.now();if(this.currentT+=(t-this.lastWallTime)*this.playbackRate,this.lastWallTime=t,this.currentT>=this.seekableDuration){if(this.loop&&this.seekableDuration>0){this.currentT%=this.seekableDuration,this.resolveFrame(this.currentT),this.rafId=requestAnimationFrame(e);return}this.currentT=this.seekableDuration,this.stop(),this.resolveFrame(this.currentT);return}this.resolveFrame(this.currentT),this.rafId=requestAnimationFrame(e)};this.rafId=requestAnimationFrame(e)}pause(){this.state==="playing"&&(this.state="paused",this.rafId!==null&&(cancelAnimationFrame(this.rafId),this.rafId=null))}stop(){this.state="stopped",this.rafId!==null&&(cancelAnimationFrame(this.rafId),this.rafId=null)}seek(e){this.currentT=Math.max(0,Math.min(e,this.seekableDuration)),this.resolveFrame(this.currentT)}get playbackState(){return this.state}get time(){return this.currentT}resolveFrame(e){const t=new Map;for(const n of this.timeline.sourceIds){const s=this.timeline.getInterpolatedShapeAt(e,n);s&&t.set(n,s)}this.onFrame(e,t)}}const mu=["nw","n","ne","e","se","s","sw","w"],a0=24,Kn=8;function fo(i,e,t){const n=i.x-e.x,s=i.y-e.y,r=Math.cos(t),a=Math.sin(t);return{x:e.x+n*r-s*a,y:e.y+n*a+s*r}}function Rs(i){return{x:i.x+i.width/2,y:i.y+i.height/2}}const o0={nw:{left:!0,top:!0},n:{top:!0},ne:{right:!0,top:!0},e:{right:!0},se:{right:!0,bottom:!0},s:{bottom:!0},sw:{left:!0,bottom:!0},w:{left:!0}};class Yt{static handlePointsFor(e){const{x:t,y:n,width:s,height:r}=e.bounds,a={nw:{x:t,y:n},n:{x:t+s/2,y:n},ne:{x:t+s,y:n},e:{x:t+s,y:n+r/2},se:{x:t+s,y:n+r},s:{x:t+s/2,y:n+r},sw:{x:t,y:n+r},w:{x:t,y:n+r/2},rotate:{x:t+s/2,y:n-a0}},o=Rs(e.bounds),l={};for(const c of Object.keys(a))l[c]=fo(a[c],o,e.angle);return l}static hitTestHandle(e,t,n=8,s=[...mu,"rotate"]){const r=Yt.handlePointsFor(e);for(const a of s)if(Math.hypot(t.x-r[a].x,t.y-r[a].y)<=n)return a}static resizeBounds(e,t,n,s){const r=Rs(e),a=fo(s,r,-t),{x:o,y:l,width:c,height:h}=e,d=o0[n];let u=o,p=l,v=o+c,y=l+h;return d.left&&(u=Math.min(a.x,v-Kn)),d.right&&(v=Math.max(a.x,u+Kn)),d.top&&(p=Math.min(a.y,y-Kn)),d.bottom&&(y=Math.max(a.y,p+Kn)),{x:u,y:p,width:v-u,height:y-p}}static resizeShape(e,t,n){if(t==="rotate")throw new Error("resizeShape does not accept the rotate handle");const{width:s,height:r}=e.bounds,a=Yt.resizeBounds(e.bounds,e.angle,t,n);if(e.kind==="oval")return{...e,bounds:a};const o=s===0?1:a.width/s,l=r===0?1:a.height/r;return{...e,bounds:a,points:e.points.map(c=>({x:c.x*o,y:c.y*l}))}}static rotateShape(e,t){const n=Rs(e.bounds),s=Math.atan2(t.y-n.y,t.x-n.x)+Math.PI/2;return{...e,angle:s}}static groupBoundsFor(e){const t=Math.min(...e.map(a=>a.x)),n=Math.min(...e.map(a=>a.y)),s=Math.max(...e.map(a=>a.x+a.width)),r=Math.max(...e.map(a=>a.y+a.height));return{x:t,y:n,width:s-t,height:r-n}}}class gc{constructor(e){this.members=e}bounds(){return Yt.groupBoundsFor(this.members.map(e=>e.shape.bounds))}scaleTo(e){const t=this.bounds(),n=t.width===0?1:e.width/t.width,s=t.height===0?1:e.height/t.height;return this.members.map(({sourceId:r,shape:a})=>{const o=Math.max(a.bounds.width*n,Kn),l=Math.max(a.bounds.height*s,Kn),c=e.x+(a.bounds.x-t.x)*n,h=e.y+(a.bounds.y-t.y)*s,d={x:c,y:h,width:o,height:l};return a.kind==="oval"?{sourceId:r,shape:{...a,bounds:d}}:{sourceId:r,shape:{...a,bounds:d,points:a.points.map(u=>({x:u.x*n,y:u.y*s}))}}})}resize(e,t){return this.scaleTo(Yt.resizeBounds(this.bounds(),0,e,t))}rotate(e,t){const n=Rs(this.bounds()),s=a=>Math.atan2(a.y-n.y,a.x-n.x),r=s(e)-s(t);return this.members.map(({sourceId:a,shape:o})=>{const l=Rs(o.bounds),c=fo(l,n,r),h={x:c.x-o.bounds.width/2,y:c.y-o.bounds.height/2,width:o.bounds.width,height:o.bounds.height};return{sourceId:a,shape:{...o,bounds:h,angle:o.angle+r}}})}}const po=6,Hs=po/2,l0=20;class c0{constructor(e){this.ctx=e}clear(e,t){this.ctx.clearRect(0,0,e,t)}paintShape(e){this.ctx.save(),this.ctx.globalAlpha=1-e.transparency,e.haloScale>0&&this.paintHalo(e),this.paintBase(e),this.ctx.restore(),e.selected&&this.paintSelectionHandles(e)}paintBase(e){if(this.ctx.fillStyle=e.color,this.ctx.beginPath(),e.kind==="oval"){const{x:t,y:n,width:s,height:r}=e.bounds,a=s/2,o=r/2;this.ctx.ellipse(t+a,n+o,a,o,e.angle,0,2*Math.PI)}else{const{x:t,y:n,width:s,height:r}=e.bounds;this.ctx.save(),this.ctx.translate(t+s/2,n+r/2),this.ctx.rotate(e.angle),this.ctx.translate(-s/2,-r/2),e.points.forEach((a,o)=>{o===0?this.ctx.moveTo(a.x,a.y):this.ctx.lineTo(a.x,a.y)}),this.ctx.closePath(),this.ctx.restore()}this.ctx.fill()}paintHalo(e){this.ctx.save(),this.ctx.shadowColor=e.color,this.ctx.shadowBlur=l0*e.haloScale,this.paintBase(e),this.ctx.restore()}paintSelectionHandles(e){this.paintHandleFrame(Yt.handlePointsFor(e),{includeRotate:!0})}paintMemberOutline(e){this.paintOutline(Yt.handlePointsFor(e))}paintGroupHandles(e){this.paintHandleFrame(Yt.handlePointsFor({bounds:e,angle:0}),{includeRotate:!0})}paintOutline(e){this.ctx.strokeStyle="lightgray",this.ctx.beginPath(),this.ctx.moveTo(e.nw.x,e.nw.y),this.ctx.lineTo(e.ne.x,e.ne.y),this.ctx.lineTo(e.se.x,e.se.y),this.ctx.lineTo(e.sw.x,e.sw.y),this.ctx.closePath(),this.ctx.stroke()}paintHandleFrame(e,{includeRotate:t}){this.paintOutline(e),this.ctx.fillStyle="lightgray";for(const n of mu){const s=e[n];this.ctx.fillRect(s.x-Hs,s.y-Hs,po,po)}t&&(this.ctx.beginPath(),this.ctx.moveTo(e.n.x,e.n.y),this.ctx.lineTo(e.rotate.x,e.rotate.y),this.ctx.stroke(),this.ctx.beginPath(),this.ctx.ellipse(e.rotate.x,e.rotate.y,Hs+1,Hs+1,0,0,2*Math.PI),this.ctx.fill())}}function h0(i){return{version:1,time:i.event.time,endTime:i.event.endTime,durationSeconds:i.event.durationSeconds,place:i.event.place,witness:i.witness,caseId:i.caseId,description:i.event.description,tags:i.event.tags,timeline:i.timeline.toJSON(),witnessTrack:i.witnessTrack.toJSON(),weatherTrack:i.weatherTrack.toJSON(),weather:i.weather,decor:i.decor}}function u0(i){return new na({eventType:"sighting",time:i.time,endTime:i.endTime,durationSeconds:i.durationSeconds,place:i.place,description:i.description,tags:i.tags},ta.fromJSON(i.timeline),i.witnessTrack?Is.fromJSON(i.witnessTrack):new Is,i.weatherTrack?Ds.fromJSON(i.weatherTrack):new Ds,i.witness,i.caseId,i.weather,i.decor??[])}function ia(i,e){for(const t of i){const n=t.toLowerCase().split("-")[0];if(e.includes(n))return n}return"en"}const d0="modulepreload",f0=function(i,e){return new URL(i,e).href},vc={},kr=function(e,t,n){let s=Promise.resolve();if(t&&t.length>0){let a=function(h){return Promise.all(h.map(d=>Promise.resolve(d).then(u=>({status:"fulfilled",value:u}),u=>({status:"rejected",reason:u}))))};const o=document.getElementsByTagName("link"),l=document.querySelector("meta[property=csp-nonce]"),c=l?.nonce||l?.getAttribute("nonce");s=a(t.map(h=>{if(h=f0(h,n),h in vc)return;vc[h]=!0;const d=h.endsWith(".css"),u=d?'[rel="stylesheet"]':"";if(!!n)for(let y=o.length-1;y>=0;y--){const m=o[y];if(m.href===h&&(!d||m.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${h}"]${u}`))return;const v=document.createElement("link");if(v.rel=d?"stylesheet":d0,d||(v.as="script"),v.crossOrigin="",v.href=h,c&&v.setAttribute("nonce",c),document.head.appendChild(v),d)return new Promise((y,m)=>{v.addEventListener("load",y),v.addEventListener("error",()=>m(new Error(`Unable to preload CSS for ${h}`)))})}))}function r(a){const o=new Event("vite:preloadError",{cancelable:!0});if(o.payload=a,window.dispatchEvent(o),!o.defaultPrevented)throw a}return s.then(a=>{for(const o of a||[])o.status==="rejected"&&r(o.reason);return e().catch(r)})},gu=["en","fr"],p0={en:()=>kr(()=>Promise.resolve().then(()=>_0),void 0,import.meta.url).then(i=>i.ufoMessages_en),fr:()=>kr(()=>import("./UfoMessages_fr-NZrwNFCQ.js"),[],import.meta.url).then(i=>i.ufoMessages_fr)};function m0(i){return p0[i]()}const g0={en:()=>kr(()=>Promise.resolve().then(()=>dS),void 0,import.meta.url).then(i=>i.ufoRecorderMessages_en),fr:()=>kr(()=>import("./UfoRecorderMessages_fr-tcCa8ZRb.js"),[],import.meta.url).then(i=>i.ufoRecorderMessages_fr)};function v0(i){return g0[i]()}const vu={play:"Play",pause:"Pause",noDuration:"No observation duration",autoReplay:"Auto-replay",currentPosition:"Current position",duration:"Duration",fullscreen:"Fullscreen",exitFullscreen:"Exit fullscreen"},_0=Object.freeze(Object.defineProperty({__proto__:null,ufoMessages_en:vu},Symbol.toStringTag,{value:"Module"})),x0=new Set;class S0 extends HTMLElement{static get observedAttributes(){return["src"]}shadow;stageElement;canvas;canvasRenderer;tooltip;toolbar;playPauseButton;loopButton;fullscreenButton;seekInput;timeStartLabel;timeEndLabel;currentSighting=na.create();player;loopEnabled=!0;highlightedSourceIds=new Set;enableClickToPlay=!0;fullscreenTarget;messages=vu;realDurationMs;realStartMs;handleFullscreenChange=()=>this.updateFullscreenButton();handlePointerMove=e=>{const t=this.canvasPointFromEvent(e),n=t&&this.currentSighting.timeline.hitTest(this.currentTime,t.x,t.y);if(!n?.shape.title){this.tooltip.hidden=!0;return}this.tooltip.textContent=n.shape.title,this.tooltip.hidden=!1;const s=this.stageElement.getBoundingClientRect();this.tooltip.style.left=`${e.clientX-s.left+12}px`,this.tooltip.style.top=`${e.clientY-s.top+12}px`};handlePointerLeave=()=>{this.tooltip.hidden=!0};constructor(){super(),this.shadow=this.attachShadow({mode:"open"});const e=document.createElement("template");e.innerHTML=`<style>${Od}</style>${Fd}`,this.shadow.appendChild(e.content.cloneNode(!0)),this.stageElement=this.shadow.getElementById("stage"),this.canvas=this.shadow.getElementById("canvas"),this.canvasRenderer=new c0(this.canvas.getContext("2d")),this.tooltip=this.shadow.getElementById("tooltip"),this.toolbar=this.shadow.getElementById("toolbar"),this.playPauseButton=this.shadow.getElementById("play-pause"),this.loopButton=this.shadow.getElementById("loop"),this.fullscreenButton=this.shadow.getElementById("fullscreen"),this.seekInput=this.shadow.getElementById("seek"),this.timeStartLabel=this.shadow.getElementById("time-start"),this.timeEndLabel=this.shadow.getElementById("time-end"),this.fullscreenTarget=this.stageElement,this.playPauseButton.addEventListener("click",()=>this.togglePlayPause()),this.loopButton.addEventListener("click",()=>this.toggleLoop()),this.fullscreenButton.addEventListener("click",()=>this.toggleFullscreen()),this.seekInput.addEventListener("input",()=>this.player.seek(Number(this.seekInput.value))),this.canvas.addEventListener("click",()=>{this.enableClickToPlay&&this.togglePlayPause()}),this.canvas.addEventListener("pointermove",this.handlePointerMove),this.canvas.addEventListener("pointerleave",this.handlePointerLeave),document.addEventListener("fullscreenchange",this.handleFullscreenChange),this.player=this.createPlayer(),this.updateTimeLabels(),this.updatePlayPauseButton(),this.updateFullscreenButton(),this.refresh(),this.loadLocaleMessages()}connectedCallback(){const e=this.getAttribute("src");e&&this.loadFromSrc(e)}disconnectedCallback(){document.removeEventListener("fullscreenchange",this.handleFullscreenChange)}attributeChangedCallback(e,t,n){e==="src"&&n&&n!==t&&this.isConnected&&this.loadFromSrc(n)}async loadFromSrc(e){const t=await fetch(e);this.sightingData=await t.json()}get sightingData(){return h0(this.currentSighting)}set sightingData(e){this.player.stop(),this.currentSighting=u0(e),this.player=this.createPlayer(),this.updateTimeLabels(),this.updatePlayPauseButton(),this.refresh()}get sighting(){return this.currentSighting}get canvasElement(){return this.canvas}get renderer(){return this.canvasRenderer}get currentTime(){return this.player.time}set currentTime(e){this.player.seek(e)}get seekableDuration(){return this.player.seekableDuration}get autoReplayEnabled(){return this.loopEnabled}get positionLabel(){return this.timeStartLabel.textContent??""}get durationLabel(){return this.timeEndLabel.textContent??""}set showToolbar(e){this.toolbar.classList.toggle("hidden",!e)}get playbackState(){return this.player.playbackState}get selectedSourceIds(){return this.highlightedSourceIds}get durationSeconds(){return this.currentSighting.event.durationSeconds}set durationSeconds(e){this.currentSighting.event.durationSeconds=e,this.updateTimeLabels(),this.refresh(),this.updatePlayPauseButton()}set selectedSourceIds(e){const t=new Set(e);t.size===this.highlightedSourceIds.size&&[...t].every(s=>this.highlightedSourceIds.has(s))||(this.highlightedSourceIds=t,this.refresh())}refresh(){this.seekInput.max=String(this.player.seekableDuration),this.player.seek(this.player.time)}canvasPointFromEvent(e){const t=this.canvas.getBoundingClientRect();if(!(t.width===0||t.height===0))return{x:(e.clientX-t.left)/t.width*this.canvas.width,y:(e.clientY-t.top)/t.height*this.canvas.height}}onFrame(e,t){this.canvasRenderer.clear(this.canvas.width,this.canvas.height);const n=this.playbackState!=="playing"?this.highlightedSourceIds:x0;for(const[s,r]of t){const a=n.has(s);a&&n.size===1?this.canvasRenderer.paintShape({...r,selected:!0}):(this.canvasRenderer.paintShape(r),a&&this.canvasRenderer.paintMemberOutline(r))}if(n.size>1){const s=Yt.groupBoundsFor([...t].filter(([r])=>n.has(r)).map(([,r])=>r.bounds));this.canvasRenderer.paintGroupHandles(s)}this.seekInput.value=String(e),this.timeStartLabel.textContent=this.formatPosition(e),this.updatePlayPauseButton(),this.dispatchEvent(new CustomEvent("timeupdate",{detail:{time:e}}))}createPlayer(){const e=new r0(this.currentSighting.timeline,(t,n)=>this.onFrame(t,n));return e.loop=this.loopEnabled,e}togglePlayPause(){this.player.seekableDuration<=0||(this.player.playbackState==="playing"?(this.player.pause(),this.refresh()):this.player.play(),this.updatePlayPauseButton())}updatePlayPauseButton(){const e=this.player.playbackState==="playing";this.playPauseButton.textContent=e?"⏸":"▶";const t=this.player.seekableDuration>0;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.toolbar.classList.toggle("auto-hide",e),this.fullscreenButton.classList.toggle("auto-hide",e)}toggleLoop(){this.loopEnabled=!this.loopEnabled,this.loopButton.setAttribute("aria-pressed",String(this.loopEnabled)),this.player.loop=this.loopEnabled}toggleFullscreen(){document.fullscreenElement?document.exitFullscreen():this.fullscreenTarget.requestFullscreen().catch(e=>{console.error("<rr0-ufo>: requestFullscreen() failed —",e)})}updateFullscreenButton(){const e=document.fullscreenElement===this.fullscreenTarget;this.fullscreenButton.title=e?this.messages.exitFullscreen:this.messages.fullscreen,this.fullscreenButton.setAttribute("aria-label",this.fullscreenButton.title)}async loadLocaleMessages(){const e=ia(navigator.languages,gu);e!=="en"&&this.applyMessages(await m0(e))}applyMessages(e){this.messages=e,this.timeStartLabel.title=e.currentPosition,this.timeEndLabel.title=e.duration,this.loopButton.title=e.autoReplay,this.loopButton.setAttribute("aria-label",e.autoReplay),this.updatePlayPauseButton(),this.updateFullscreenButton()}updateTimeLabels(){const e=this.currentSighting.event,t=Il(e);this.realDurationMs=t!==void 0&&t>0?t:void 0,this.realStartMs=e.time?ho(e.time):void 0;const n=this.currentSighting.timeline.duration;this.player.playbackRate=this.realDurationMs!==void 0&&n>0?n/this.realDurationMs:1,this.player.durationOverrideMs=this.realDurationMs??0,this.timeEndLabel.textContent=this.formatEndOfTimeline(),this.timeStartLabel.textContent=this.formatPosition(this.player.time)}formatPosition(e){if(this.realDurationMs===void 0)return Vs(e);const t=this.currentSighting.timeline.duration,n=t>0&&e<=t?e/t*this.realDurationMs:e;return this.realStartMs!==void 0?xc(_c(this.realStartMs+n)):Vs(n)}formatEndOfTimeline(){return this.realDurationMs===void 0?Vs(this.currentSighting.timeline.duration):this.realStartMs!==void 0?xc(_c(this.realStartMs+this.realDurationMs)):Vs(this.realDurationMs)}}function _c(i){const e=new Date(i);return{hour:e.getUTCHours(),minute:e.getUTCMinutes(),second:e.getUTCSeconds()}}function xc(i){if(i.hour===void 0)return"0:00";const e=t=>String(t).padStart(2,"0");return i.second?`${e(i.hour)}:${e(i.minute??0)}:${e(i.second)}`:`${e(i.hour)}:${e(i.minute??0)}`}function Vs(i){const e=Math.round(i/1e3),t=Math.floor(e/60),n=e%60;return`${t}:${String(n).padStart(2,"0")}`}const mo="rr0-ufo";function sa(){customElements.get(mo)||customElements.define(mo,S0)}const y0=`
480
+ `;function Bd(i,e="#39ff14"){return{kind:"oval",bounds:i,color:e,angle:0,transparency:0,haloScale:0,selected:!1}}function du(i,e,t="#39ff14"){return{kind:"polygon",bounds:i,points:e,color:t,angle:0,transparency:0,haloScale:0,selected:!1}}function zd(i,e="#39ff14"){const{width:t,height:n}=i,s=[{x:.5*t,y:0},{x:.8*t,y:.25*n},{x:t,y:.5*n},{x:.8*t,y:.75*n},{x:.5*t,y:n},{x:.2*t,y:.75*n},{x:0,y:.5*n},{x:.2*t,y:.25*n}];return du(i,s,e)}function kd(i,e="#39ff14"){const{width:t,height:n}=i,s=[{x:0,y:0},{x:t,y:n/2},{x:0,y:n}];return du(i,s,e)}const Gd={oval:Bd,saucer:zd,triangle:kd};function cc(i,e){return{...Gd[e.presetId](i,e.color),transparency:e.transparency,haloScale:e.haloScale}}function Hd(i,e,t){const{bounds:n}=i;return e>=n.x&&e<=n.x+n.width&&t>=n.y&&t<=n.y+n.height}function fu(i,e,t){const n=i.bounds.width,s=i.bounds.height;return{...i,bounds:{x:e-n/2,y:t-s/2,width:n,height:s}}}function Zt(i,e,t){return i+(e-i)*t}function hc(i){const e=/^#([0-9a-f]{6})$/i.exec(i);if(!e)return;const t=parseInt(e[1],16);return[t>>16&255,t>>8&255,t&255]}function Vd(i){return`#${i.map(e=>Math.round(e).toString(16).padStart(2,"0")).join("")}`}function Wd(i,e,t){const n=hc(i),s=hc(e);return!n||!s?t<1?i:e:Vd([Zt(n[0],s[0],t),Zt(n[1],s[1],t),Zt(n[2],s[2],t)])}function Xd(i,e,t){const n={x:Zt(i.bounds.x,e.bounds.x,t),y:Zt(i.bounds.y,e.bounds.y,t),width:Zt(i.bounds.width,e.bounds.width,t),height:Zt(i.bounds.height,e.bounds.height,t)},s=Zt(i.angle,e.angle,t),r=Zt(i.transparency,e.transparency,t),a=Zt(i.haloScale,e.haloScale,t),o=Wd(i.color,e.color,t);return i.kind==="polygon"&&e.kind==="polygon"&&i.points.length===e.points.length?{...i,bounds:n,angle:s,transparency:r,haloScale:a,color:o,points:i.points.map((l,c)=>({x:Zt(l.x,e.points[c].x,t),y:Zt(l.y,e.points[c].y,t)}))}:{...t<1?i:e,bounds:n,angle:s,transparency:r,haloScale:a,color:o}}class ta{keyframes=[];order=[];groups=[];addKeyframe(e,t){const n=this.findInsertIndex(e);if(this.keyframes[n]?.t===e){const s=new Set(t.map(r=>r.sourceId));this.keyframes[n]={t:e,shapes:[...this.keyframes[n].shapes.filter(r=>!s.has(r.sourceId)),...t]}}else this.keyframes.splice(n,0,{t:e,shapes:[...t]});for(const s of t)this.order.includes(s.sourceId)||this.order.push(s.sourceId)}findInsertIndex(e){let t=0,n=this.keyframes.length;for(;t<n;){const s=t+n>>>1;this.keyframes[s].t<e?t=s+1:n=s}return t}getKeyframeAt(e){const t=this.findInsertIndex(e),n=this.keyframes[t];return n?.t===e?n:void 0}getShapeAt(e,t){return this.getKeyframeAt(e)?.shapes.find(n=>n.sourceId===t)?.shape}getLatestShapeAt(e,t){let n=this.findInsertIndex(e);for(this.keyframes[n]?.t!==e&&(n-=1);n>=0;n--){const s=this.keyframes[n].shapes.find(r=>r.sourceId===t);if(s)return s.shape}}getInterpolatedShapeAt(e,t){const n=this.findShapeAtOrBefore(e,t);if(n?.t===e)return n.shape;const s=this.findShapeAtOrAfter(e,t);return n?s?Xd(n.shape,s.shape,(e-n.t)/(s.t-n.t)):n.shape:s?.shape}findShapeAtOrBefore(e,t){let n=this.findInsertIndex(e);for(this.keyframes[n]?.t!==e&&(n-=1);n>=0;n--){const s=this.keyframes[n].shapes.find(r=>r.sourceId===t);if(s)return{t:this.keyframes[n].t,shape:s.shape}}}findShapeAtOrAfter(e,t){for(let n=this.findInsertIndex(e);n<this.keyframes.length;n++){const s=this.keyframes[n].shapes.find(r=>r.sourceId===t);if(s)return{t:this.keyframes[n].t,shape:s.shape}}}hitTest(e,t,n){const s=this.sourceIds;for(let r=s.length-1;r>=0;r--){const a=this.getInterpolatedShapeAt(e,s[r]);if(a&&Hd(a,t,n))return{sourceId:s[r],shape:a}}}removeSource(e){for(let t=this.keyframes.length-1;t>=0;t--){const n=this.keyframes[t].shapes.filter(s=>s.sourceId!==e);n.length===0?this.keyframes.splice(t,1):n.length!==this.keyframes[t].shapes.length&&(this.keyframes[t]={t:this.keyframes[t].t,shapes:n})}this.order=this.order.filter(t=>t!==e),this.removeFromGroup(e)}group(e){if(!(e.length<2)){for(const t of e)this.removeFromGroup(t);this.groups.push([...e])}}ungroup(e){const t=this.groups.findIndex(n=>n.includes(e));t!==-1&&this.groups.splice(t,1)}groupMembers(e){return this.groups.find(t=>t.includes(e))}removeFromGroup(e){const t=this.groups.findIndex(s=>s.includes(e));if(t===-1)return;const n=this.groups[t].filter(s=>s!==e);n.length<2?this.groups.splice(t,1):this.groups[t]=n}bringToFront(e){const t=this.order.indexOf(e);t!==-1&&(this.order.splice(t,1),this.order.push(e))}sendToBack(e){const t=this.order.indexOf(e);t!==-1&&(this.order.splice(t,1),this.order.unshift(e))}get duration(){return this.keyframes.length===0?0:this.keyframes[this.keyframes.length-1].t}get sourceIds(){return[...this.order]}get allKeyframes(){return this.keyframes}toJSON(){return{keyframes:this.keyframes,order:this.order,groups:this.groups}}static fromJSON(e){const t=new ta;for(const n of e.keyframes)t.addKeyframe(n.t,n.shapes);if(e.order){const n=t.order.filter(s=>!e.order.includes(s));t.order=[...e.order,...n]}return e.groups&&(t.groups=e.groups.map(n=>n.filter(s=>t.order.includes(s))).filter(n=>n.length>=2)),t}}function Yd(i,e,t){return Math.max(e,Math.min(t,i))}function qd(i,e,t){const n=((e-i)%360+540)%360-180;return((i+n*t)%360+360)%360}function hs(i,e,t){return i+(e-i)*t}function Kd(i,e,t){return{lat:i.lat===void 0||e.lat===void 0?void 0:hs(i.lat,e.lat,t),lng:i.lng===void 0||e.lng===void 0?void 0:hs(i.lng,e.lng,t),elevationM:hs(i.elevationM,e.elevationM,t),headingDeg:i.headingDeg===void 0||e.headingDeg===void 0?void 0:qd(i.headingDeg,e.headingDeg,t),pitchDeg:hs(i.pitchDeg,e.pitchDeg,t),fovDeg:hs(i.fovDeg,e.fovDeg,t)}}class Is{keyframes=[];addKeyframe(e,t){const n=this.findInsertIndex(e);this.keyframes[n]?.t===e?this.keyframes[n]={t:e,pose:t}:this.keyframes.splice(n,0,{t:e,pose:t})}clear(){this.keyframes.length=0}removeKeyframeAt(e){const t=this.findInsertIndex(e);this.keyframes[t]?.t===e&&this.keyframes.splice(t,1)}findInsertIndex(e){let t=0,n=this.keyframes.length;for(;t<n;){const s=t+n>>>1;this.keyframes[s].t<e?t=s+1:n=s}return t}getLatestPoseAt(e){let t=this.findInsertIndex(e);return this.keyframes[t]?.t!==e&&(t-=1),t>=0?this.keyframes[t].pose:void 0}getInterpolatedPoseAt(e){const t=this.findInsertIndex(e),n=this.keyframes[t]?.t===e?this.keyframes[t]:this.keyframes[t-1];if(n?.t===e)return n.pose;const s=this.keyframes[t]?.t===e?void 0:this.keyframes[t];return n?s?Kd(n.pose,s.pose,Yd((e-n.t)/(s.t-n.t),0,1)):n.pose:s?.pose}get duration(){return this.keyframes.length===0?0:this.keyframes[this.keyframes.length-1].t}get allKeyframes(){return this.keyframes}toJSON(){return{keyframes:this.keyframes}}static fromJSON(e){const t=new Is;for(const n of e.keyframes)t.addKeyframe(n.t,n.pose);return t}}function Gs(i,e,t){return i+(e-i)*t}function $d(i,e,t){const n=((e-i)%360+540)%360-180;return((i+n*t)%360+360)%360}function Zd(i,e,t){return Math.max(e,Math.min(t,i))}function Jd(i,e,t){return{cloudCover:Gs(i.cloudCover,e.cloudCover,t),cloudDarkness:Gs(i.cloudDarkness,e.cloudDarkness,t),precipitationType:t<1?i.precipitationType:e.precipitationType,precipitationIntensity:Gs(i.precipitationIntensity,e.precipitationIntensity,t),windDirectionDeg:$d(i.windDirectionDeg,e.windDirectionDeg,t),windSpeed:Gs(i.windSpeed,e.windSpeed,t),storm:t<1?i.storm:e.storm}}class Ds{keyframes=[];addKeyframe(e,t){const n=this.findInsertIndex(e);this.keyframes[n]?.t===e?this.keyframes[n]={t:e,weather:t}:this.keyframes.splice(n,0,{t:e,weather:t})}clear(){this.keyframes.length=0}removeKeyframeAt(e){const t=this.findInsertIndex(e);this.keyframes[t]?.t===e&&this.keyframes.splice(t,1)}findInsertIndex(e){let t=0,n=this.keyframes.length;for(;t<n;){const s=t+n>>>1;this.keyframes[s].t<e?t=s+1:n=s}return t}getLatestWeatherAt(e){let t=this.findInsertIndex(e);return this.keyframes[t]?.t!==e&&(t-=1),t>=0?this.keyframes[t].weather:void 0}getInterpolatedWeatherAt(e){const t=this.findInsertIndex(e),n=this.keyframes[t]?.t===e?this.keyframes[t]:this.keyframes[t-1];if(n?.t===e)return n.weather;const s=this.keyframes[t]?.t===e?void 0:this.keyframes[t];return n?s?Jd(n.weather,s.weather,Zd((e-n.t)/(s.t-n.t),0,1)):n.weather:s?.weather}get duration(){return this.keyframes.length===0?0:this.keyframes[this.keyframes.length-1].t}get allKeyframes(){return this.keyframes}toJSON(){return{keyframes:this.keyframes}}static fromJSON(e){const t=new Ds;for(const n of e.keyframes)t.addKeyframe(n.t,n.weather);return t}}const pu={cloudCover:0,cloudDarkness:0,precipitationType:"none",precipitationIntensity:0,windDirectionDeg:0,windSpeed:0,storm:!1},Qd=/^(?:(?<year>\d{4}|\d{3}X|\d{2}XX)(-(?<month>0[1-9]|1[0-2]))?(-(?<day>0[1-9]|[12]\d|3[01]))?(?:[T ](?<hour>[01]?\d|2[0-3]):(?<minute>[0-5]\d)(?::(?<second>[0-5]\d))?)?|(?<timeOnlyHour>[01]?\d|2[0-3]):(?<timeOnlyMinute>[0-5]\d)(?::(?<timeOnlySecond>[0-5]\d))?)[?~%]?$/;function uc(i){const e=Qd.exec(i.trim());if(!e?.groups)return;const{year:t,month:n,day:s,hour:r,minute:a,second:o,timeOnlyHour:l,timeOnlyMinute:c,timeOnlySecond:h}=e.groups,d=r??l,u=a??c,p=o??h;return{year:t&&!t.includes("X")?Number(t):void 0,month:n?Number(n):void 0,day:s?Number(s):void 0,hour:d?Number(d):void 0,minute:u?Number(u):void 0,second:p?Number(p):void 0,raw:i.trim()}}function dc(i){if(i.raw!==void 0)return i.raw;if(i.year===void 0){if(i.hour===void 0)return"";let t=`${String(i.hour).padStart(2,"0")}:${String(i.minute??0).padStart(2,"0")}`;return i.second!==void 0&&(t+=`:${String(i.second).padStart(2,"0")}`),t}let e=String(i.year).padStart(4,"0");return i.month===void 0||(e+=`-${String(i.month).padStart(2,"0")}`,i.day===void 0)||(e+=`-${String(i.day).padStart(2,"0")}`,i.hour===void 0)||(e+=`T${String(i.hour).padStart(2,"0")}:${String(i.minute??0).padStart(2,"0")}`,i.second!==void 0&&(e+=`:${String(i.second).padStart(2,"0")}`)),e}function ho(i){if(i.year!==void 0)return Date.UTC(i.year,(i.month??1)-1,i.day??1,i.hour??0,i.minute??0,i.second??0)}function fc(i){return(((i.day??0)*24+(i.hour??0))*60+(i.minute??0))*6e4+(i.second??0)*1e3}const jd=["year","month","day","hour","minute"],e0=["day","hour","minute"];function pc(i,e){return e.filter(t=>i[t]!==void 0).join(",")}function Il(i){if(i.durationSeconds!==void 0)return i.durationSeconds*1e3;if(!i.time||!i.endTime)return;const e=i.time.year!==void 0&&i.endTime.year!==void 0,t=e?jd:e0,n=pc(i.time,t);if(!(n===""||n!==pc(i.endTime,t)))return e?ho(i.endTime)-ho(i.time):fc(i.endTime)-fc(i.time)}function t0(i){if(i.durationSeconds===void 0&&!(!i.time||!i.endTime))return Il(i)===void 0?"imprecise":void 0}class na{constructor(e,t,n,s,r,a,o,l=[]){this.event=e,this.timeline=t,this.witnessTrack=n,this.weatherTrack=s,this.witness=r,this.caseId=a,this.weather=o,this.decor=l}static create(e,t,n){return new na({eventType:"sighting",time:e,place:t},new ta,new Is,new Ds,n)}}const n0=0,i0=0,s0=60;function mc(i,e){const t=i.witnessTrack.getInterpolatedPoseAt(e);if(t)return t;const n=i.event.place?.[0];if(n)return{lat:n.lat,lng:n.lng,elevationM:n0,headingDeg:void 0,pitchDeg:i0,fovDeg:s0}}function uo(i,e){return i.weatherTrack.getInterpolatedWeatherAt(e)??i.weather??pu}class r0{constructor(e,t){this.timeline=e,this.onFrame=t}rafId=null;state="stopped";currentT=0;lastWallTime=0;playbackRate=1;loop=!1;durationOverrideMs=0;get seekableDuration(){return Math.max(this.timeline.duration,this.durationOverrideMs)}play(){if(this.state==="playing")return;this.currentT>=this.seekableDuration&&(this.currentT=0,this.resolveFrame(0)),this.state="playing",this.lastWallTime=performance.now();const e=()=>{if(this.state!=="playing")return;const t=performance.now();if(this.currentT+=(t-this.lastWallTime)*this.playbackRate,this.lastWallTime=t,this.currentT>=this.seekableDuration){if(this.loop&&this.seekableDuration>0){this.currentT%=this.seekableDuration,this.resolveFrame(this.currentT),this.rafId=requestAnimationFrame(e);return}this.currentT=this.seekableDuration,this.stop(),this.resolveFrame(this.currentT);return}this.resolveFrame(this.currentT),this.rafId=requestAnimationFrame(e)};this.rafId=requestAnimationFrame(e)}pause(){this.state==="playing"&&(this.state="paused",this.rafId!==null&&(cancelAnimationFrame(this.rafId),this.rafId=null))}stop(){this.state="stopped",this.rafId!==null&&(cancelAnimationFrame(this.rafId),this.rafId=null)}seek(e){this.currentT=Math.max(0,Math.min(e,this.seekableDuration)),this.resolveFrame(this.currentT)}get playbackState(){return this.state}get time(){return this.currentT}resolveFrame(e){const t=new Map;for(const n of this.timeline.sourceIds){const s=this.timeline.getInterpolatedShapeAt(e,n);s&&t.set(n,s)}this.onFrame(e,t)}}const mu=["nw","n","ne","e","se","s","sw","w"],a0=24,Kn=8;function fo(i,e,t){const n=i.x-e.x,s=i.y-e.y,r=Math.cos(t),a=Math.sin(t);return{x:e.x+n*r-s*a,y:e.y+n*a+s*r}}function Rs(i){return{x:i.x+i.width/2,y:i.y+i.height/2}}const o0={nw:{left:!0,top:!0},n:{top:!0},ne:{right:!0,top:!0},e:{right:!0},se:{right:!0,bottom:!0},s:{bottom:!0},sw:{left:!0,bottom:!0},w:{left:!0}};class Yt{static handlePointsFor(e){const{x:t,y:n,width:s,height:r}=e.bounds,a={nw:{x:t,y:n},n:{x:t+s/2,y:n},ne:{x:t+s,y:n},e:{x:t+s,y:n+r/2},se:{x:t+s,y:n+r},s:{x:t+s/2,y:n+r},sw:{x:t,y:n+r},w:{x:t,y:n+r/2},rotate:{x:t+s/2,y:n-a0}},o=Rs(e.bounds),l={};for(const c of Object.keys(a))l[c]=fo(a[c],o,e.angle);return l}static hitTestHandle(e,t,n=8,s=[...mu,"rotate"]){const r=Yt.handlePointsFor(e);for(const a of s)if(Math.hypot(t.x-r[a].x,t.y-r[a].y)<=n)return a}static resizeBounds(e,t,n,s){const r=Rs(e),a=fo(s,r,-t),{x:o,y:l,width:c,height:h}=e,d=o0[n];let u=o,p=l,v=o+c,y=l+h;return d.left&&(u=Math.min(a.x,v-Kn)),d.right&&(v=Math.max(a.x,u+Kn)),d.top&&(p=Math.min(a.y,y-Kn)),d.bottom&&(y=Math.max(a.y,p+Kn)),{x:u,y:p,width:v-u,height:y-p}}static resizeShape(e,t,n){if(t==="rotate")throw new Error("resizeShape does not accept the rotate handle");const{width:s,height:r}=e.bounds,a=Yt.resizeBounds(e.bounds,e.angle,t,n);if(e.kind==="oval")return{...e,bounds:a};const o=s===0?1:a.width/s,l=r===0?1:a.height/r;return{...e,bounds:a,points:e.points.map(c=>({x:c.x*o,y:c.y*l}))}}static rotateShape(e,t){const n=Rs(e.bounds),s=Math.atan2(t.y-n.y,t.x-n.x)+Math.PI/2;return{...e,angle:s}}static groupBoundsFor(e){const t=Math.min(...e.map(a=>a.x)),n=Math.min(...e.map(a=>a.y)),s=Math.max(...e.map(a=>a.x+a.width)),r=Math.max(...e.map(a=>a.y+a.height));return{x:t,y:n,width:s-t,height:r-n}}}class gc{constructor(e){this.members=e}bounds(){return Yt.groupBoundsFor(this.members.map(e=>e.shape.bounds))}scaleTo(e){const t=this.bounds(),n=t.width===0?1:e.width/t.width,s=t.height===0?1:e.height/t.height;return this.members.map(({sourceId:r,shape:a})=>{const o=Math.max(a.bounds.width*n,Kn),l=Math.max(a.bounds.height*s,Kn),c=e.x+(a.bounds.x-t.x)*n,h=e.y+(a.bounds.y-t.y)*s,d={x:c,y:h,width:o,height:l};return a.kind==="oval"?{sourceId:r,shape:{...a,bounds:d}}:{sourceId:r,shape:{...a,bounds:d,points:a.points.map(u=>({x:u.x*n,y:u.y*s}))}}})}resize(e,t){return this.scaleTo(Yt.resizeBounds(this.bounds(),0,e,t))}rotate(e,t){const n=Rs(this.bounds()),s=a=>Math.atan2(a.y-n.y,a.x-n.x),r=s(e)-s(t);return this.members.map(({sourceId:a,shape:o})=>{const l=Rs(o.bounds),c=fo(l,n,r),h={x:c.x-o.bounds.width/2,y:c.y-o.bounds.height/2,width:o.bounds.width,height:o.bounds.height};return{sourceId:a,shape:{...o,bounds:h,angle:o.angle+r}}})}}const po=6,Hs=po/2,l0=20;class c0{constructor(e){this.ctx=e}clear(e,t){this.ctx.clearRect(0,0,e,t)}paintShape(e){this.ctx.save(),this.ctx.globalAlpha=1-e.transparency,e.haloScale>0&&this.paintHalo(e),this.paintBase(e),this.ctx.restore(),e.selected&&this.paintSelectionHandles(e)}paintBase(e){if(this.ctx.fillStyle=e.color,this.ctx.beginPath(),e.kind==="oval"){const{x:t,y:n,width:s,height:r}=e.bounds,a=s/2,o=r/2;this.ctx.ellipse(t+a,n+o,a,o,e.angle,0,2*Math.PI)}else{const{x:t,y:n,width:s,height:r}=e.bounds;this.ctx.save(),this.ctx.translate(t+s/2,n+r/2),this.ctx.rotate(e.angle),this.ctx.translate(-s/2,-r/2),e.points.forEach((a,o)=>{o===0?this.ctx.moveTo(a.x,a.y):this.ctx.lineTo(a.x,a.y)}),this.ctx.closePath(),this.ctx.restore()}this.ctx.fill()}paintHalo(e){this.ctx.save(),this.ctx.shadowColor=e.color,this.ctx.shadowBlur=l0*e.haloScale,this.paintBase(e),this.ctx.restore()}paintSelectionHandles(e){this.paintHandleFrame(Yt.handlePointsFor(e),{includeRotate:!0})}paintMemberOutline(e){this.paintOutline(Yt.handlePointsFor(e))}paintGroupHandles(e){this.paintHandleFrame(Yt.handlePointsFor({bounds:e,angle:0}),{includeRotate:!0})}paintOutline(e){this.ctx.strokeStyle="lightgray",this.ctx.beginPath(),this.ctx.moveTo(e.nw.x,e.nw.y),this.ctx.lineTo(e.ne.x,e.ne.y),this.ctx.lineTo(e.se.x,e.se.y),this.ctx.lineTo(e.sw.x,e.sw.y),this.ctx.closePath(),this.ctx.stroke()}paintHandleFrame(e,{includeRotate:t}){this.paintOutline(e),this.ctx.fillStyle="lightgray";for(const n of mu){const s=e[n];this.ctx.fillRect(s.x-Hs,s.y-Hs,po,po)}t&&(this.ctx.beginPath(),this.ctx.moveTo(e.n.x,e.n.y),this.ctx.lineTo(e.rotate.x,e.rotate.y),this.ctx.stroke(),this.ctx.beginPath(),this.ctx.ellipse(e.rotate.x,e.rotate.y,Hs+1,Hs+1,0,0,2*Math.PI),this.ctx.fill())}}function h0(i){return{version:1,time:i.event.time,endTime:i.event.endTime,durationSeconds:i.event.durationSeconds,place:i.event.place,witness:i.witness,caseId:i.caseId,description:i.event.description,tags:i.event.tags,timeline:i.timeline.toJSON(),witnessTrack:i.witnessTrack.toJSON(),weatherTrack:i.weatherTrack.toJSON(),weather:i.weather,decor:i.decor}}function u0(i){return new na({eventType:"sighting",time:i.time,endTime:i.endTime,durationSeconds:i.durationSeconds,place:i.place,description:i.description,tags:i.tags},ta.fromJSON(i.timeline),i.witnessTrack?Is.fromJSON(i.witnessTrack):new Is,i.weatherTrack?Ds.fromJSON(i.weatherTrack):new Ds,i.witness,i.caseId,i.weather,i.decor??[])}function ia(i,e){for(const t of i){const n=t.toLowerCase().split("-")[0];if(e.includes(n))return n}return"en"}const d0="modulepreload",f0=function(i,e){return new URL(i,e).href},vc={},kr=function(e,t,n){let s=Promise.resolve();if(t&&t.length>0){let a=function(h){return Promise.all(h.map(d=>Promise.resolve(d).then(u=>({status:"fulfilled",value:u}),u=>({status:"rejected",reason:u}))))};const o=document.getElementsByTagName("link"),l=document.querySelector("meta[property=csp-nonce]"),c=l?.nonce||l?.getAttribute("nonce");s=a(t.map(h=>{if(h=f0(h,n),h in vc)return;vc[h]=!0;const d=h.endsWith(".css"),u=d?'[rel="stylesheet"]':"";if(!!n)for(let y=o.length-1;y>=0;y--){const m=o[y];if(m.href===h&&(!d||m.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${h}"]${u}`))return;const v=document.createElement("link");if(v.rel=d?"stylesheet":d0,d||(v.as="script"),v.crossOrigin="",v.href=h,c&&v.setAttribute("nonce",c),document.head.appendChild(v),d)return new Promise((y,m)=>{v.addEventListener("load",y),v.addEventListener("error",()=>m(new Error(`Unable to preload CSS for ${h}`)))})}))}function r(a){const o=new Event("vite:preloadError",{cancelable:!0});if(o.payload=a,window.dispatchEvent(o),!o.defaultPrevented)throw a}return s.then(a=>{for(const o of a||[])o.status==="rejected"&&r(o.reason);return e().catch(r)})},gu=["en","fr"],p0={en:()=>kr(()=>Promise.resolve().then(()=>_0),void 0,import.meta.url).then(i=>i.ufoMessages_en),fr:()=>kr(()=>import("./UfoMessages_fr-NZrwNFCQ.js"),[],import.meta.url).then(i=>i.ufoMessages_fr)};function m0(i){return p0[i]()}const g0={en:()=>kr(()=>Promise.resolve().then(()=>dS),void 0,import.meta.url).then(i=>i.ufoRecorderMessages_en),fr:()=>kr(()=>import("./UfoRecorderMessages_fr-C_v-Z91j.js"),[],import.meta.url).then(i=>i.ufoRecorderMessages_fr)};function v0(i){return g0[i]()}const vu={play:"Play",pause:"Pause",noDuration:"No observation duration",autoReplay:"Auto-replay",currentPosition:"Current position",duration:"Duration",fullscreen:"Fullscreen",exitFullscreen:"Exit fullscreen"},_0=Object.freeze(Object.defineProperty({__proto__:null,ufoMessages_en:vu},Symbol.toStringTag,{value:"Module"})),x0=new Set;class S0 extends HTMLElement{static get observedAttributes(){return["src"]}shadow;stageElement;canvas;canvasRenderer;tooltip;toolbar;playPauseButton;loopButton;fullscreenButton;seekInput;timeStartLabel;timeEndLabel;currentSighting=na.create();player;loopEnabled=!0;highlightedSourceIds=new Set;enableClickToPlay=!0;fullscreenTarget;messages=vu;realDurationMs;realStartMs;handleFullscreenChange=()=>this.updateFullscreenButton();handlePointerMove=e=>{const t=this.canvasPointFromEvent(e),n=t&&this.currentSighting.timeline.hitTest(this.currentTime,t.x,t.y);if(!n?.shape.title){this.tooltip.hidden=!0;return}this.tooltip.textContent=n.shape.title,this.tooltip.hidden=!1;const s=this.stageElement.getBoundingClientRect();this.tooltip.style.left=`${e.clientX-s.left+12}px`,this.tooltip.style.top=`${e.clientY-s.top+12}px`};handlePointerLeave=()=>{this.tooltip.hidden=!0};constructor(){super(),this.shadow=this.attachShadow({mode:"open"});const e=document.createElement("template");e.innerHTML=`<style>${Od}</style>${Fd}`,this.shadow.appendChild(e.content.cloneNode(!0)),this.stageElement=this.shadow.getElementById("stage"),this.canvas=this.shadow.getElementById("canvas"),this.canvasRenderer=new c0(this.canvas.getContext("2d")),this.tooltip=this.shadow.getElementById("tooltip"),this.toolbar=this.shadow.getElementById("toolbar"),this.playPauseButton=this.shadow.getElementById("play-pause"),this.loopButton=this.shadow.getElementById("loop"),this.fullscreenButton=this.shadow.getElementById("fullscreen"),this.seekInput=this.shadow.getElementById("seek"),this.timeStartLabel=this.shadow.getElementById("time-start"),this.timeEndLabel=this.shadow.getElementById("time-end"),this.fullscreenTarget=this.stageElement,this.playPauseButton.addEventListener("click",()=>this.togglePlayPause()),this.loopButton.addEventListener("click",()=>this.toggleLoop()),this.fullscreenButton.addEventListener("click",()=>this.toggleFullscreen()),this.seekInput.addEventListener("input",()=>this.player.seek(Number(this.seekInput.value))),this.canvas.addEventListener("click",()=>{this.enableClickToPlay&&this.togglePlayPause()}),this.canvas.addEventListener("pointermove",this.handlePointerMove),this.canvas.addEventListener("pointerleave",this.handlePointerLeave),document.addEventListener("fullscreenchange",this.handleFullscreenChange),this.player=this.createPlayer(),this.updateTimeLabels(),this.updatePlayPauseButton(),this.updateFullscreenButton(),this.refresh(),this.loadLocaleMessages()}connectedCallback(){const e=this.getAttribute("src");e&&this.loadFromSrc(e)}disconnectedCallback(){document.removeEventListener("fullscreenchange",this.handleFullscreenChange)}attributeChangedCallback(e,t,n){e==="src"&&n&&n!==t&&this.isConnected&&this.loadFromSrc(n)}async loadFromSrc(e){const t=await fetch(e);this.sightingData=await t.json()}get sightingData(){return h0(this.currentSighting)}set sightingData(e){this.player.stop(),this.currentSighting=u0(e),this.player=this.createPlayer(),this.updateTimeLabels(),this.updatePlayPauseButton(),this.refresh()}get sighting(){return this.currentSighting}get canvasElement(){return this.canvas}get renderer(){return this.canvasRenderer}get currentTime(){return this.player.time}set currentTime(e){this.player.seek(e)}get seekableDuration(){return this.player.seekableDuration}get autoReplayEnabled(){return this.loopEnabled}get positionLabel(){return this.timeStartLabel.textContent??""}get durationLabel(){return this.timeEndLabel.textContent??""}set showToolbar(e){this.toolbar.classList.toggle("hidden",!e)}get playbackState(){return this.player.playbackState}get selectedSourceIds(){return this.highlightedSourceIds}get durationSeconds(){return this.currentSighting.event.durationSeconds}set durationSeconds(e){this.currentSighting.event.durationSeconds=e,this.updateTimeLabels(),this.refresh(),this.updatePlayPauseButton()}set selectedSourceIds(e){const t=new Set(e);t.size===this.highlightedSourceIds.size&&[...t].every(s=>this.highlightedSourceIds.has(s))||(this.highlightedSourceIds=t,this.refresh())}refresh(){this.seekInput.max=String(this.player.seekableDuration),this.player.seek(this.player.time)}canvasPointFromEvent(e){const t=this.canvas.getBoundingClientRect();if(!(t.width===0||t.height===0))return{x:(e.clientX-t.left)/t.width*this.canvas.width,y:(e.clientY-t.top)/t.height*this.canvas.height}}onFrame(e,t){this.canvasRenderer.clear(this.canvas.width,this.canvas.height);const n=this.playbackState!=="playing"?this.highlightedSourceIds:x0;for(const[s,r]of t){const a=n.has(s);a&&n.size===1?this.canvasRenderer.paintShape({...r,selected:!0}):(this.canvasRenderer.paintShape(r),a&&this.canvasRenderer.paintMemberOutline(r))}if(n.size>1){const s=Yt.groupBoundsFor([...t].filter(([r])=>n.has(r)).map(([,r])=>r.bounds));this.canvasRenderer.paintGroupHandles(s)}this.seekInput.value=String(e),this.timeStartLabel.textContent=this.formatPosition(e),this.updatePlayPauseButton(),this.dispatchEvent(new CustomEvent("timeupdate",{detail:{time:e}}))}createPlayer(){const e=new r0(this.currentSighting.timeline,(t,n)=>this.onFrame(t,n));return e.loop=this.loopEnabled,e}togglePlayPause(){this.player.seekableDuration<=0||(this.player.playbackState==="playing"?(this.player.pause(),this.refresh()):this.player.play(),this.updatePlayPauseButton())}updatePlayPauseButton(){const e=this.player.playbackState==="playing";this.playPauseButton.textContent=e?"⏸":"▶";const t=this.player.seekableDuration>0;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.toolbar.classList.toggle("auto-hide",e),this.fullscreenButton.classList.toggle("auto-hide",e)}toggleLoop(){this.loopEnabled=!this.loopEnabled,this.loopButton.setAttribute("aria-pressed",String(this.loopEnabled)),this.player.loop=this.loopEnabled}toggleFullscreen(){document.fullscreenElement?document.exitFullscreen():this.fullscreenTarget.requestFullscreen().catch(e=>{console.error("<rr0-ufo>: requestFullscreen() failed —",e)})}updateFullscreenButton(){const e=document.fullscreenElement===this.fullscreenTarget;this.fullscreenButton.title=e?this.messages.exitFullscreen:this.messages.fullscreen,this.fullscreenButton.setAttribute("aria-label",this.fullscreenButton.title)}async loadLocaleMessages(){const e=ia(navigator.languages,gu);e!=="en"&&this.applyMessages(await m0(e))}applyMessages(e){this.messages=e,this.timeStartLabel.title=e.currentPosition,this.timeEndLabel.title=e.duration,this.loopButton.title=e.autoReplay,this.loopButton.setAttribute("aria-label",e.autoReplay),this.updatePlayPauseButton(),this.updateFullscreenButton()}updateTimeLabels(){const e=this.currentSighting.event,t=Il(e);this.realDurationMs=t!==void 0&&t>0?t:void 0,this.realStartMs=e.time?ho(e.time):void 0;const n=this.currentSighting.timeline.duration;this.player.playbackRate=this.realDurationMs!==void 0&&n>0?n/this.realDurationMs:1,this.player.durationOverrideMs=this.realDurationMs??0,this.timeEndLabel.textContent=this.formatEndOfTimeline(),this.timeStartLabel.textContent=this.formatPosition(this.player.time)}formatPosition(e){if(this.realDurationMs===void 0)return Vs(e);const t=this.currentSighting.timeline.duration,n=t>0&&e<=t?e/t*this.realDurationMs:e;return this.realStartMs!==void 0?xc(_c(this.realStartMs+n)):Vs(n)}formatEndOfTimeline(){return this.realDurationMs===void 0?Vs(this.currentSighting.timeline.duration):this.realStartMs!==void 0?xc(_c(this.realStartMs+this.realDurationMs)):Vs(this.realDurationMs)}}function _c(i){const e=new Date(i);return{hour:e.getUTCHours(),minute:e.getUTCMinutes(),second:e.getUTCSeconds()}}function xc(i){if(i.hour===void 0)return"0:00";const e=t=>String(t).padStart(2,"0");return i.second?`${e(i.hour)}:${e(i.minute??0)}:${e(i.second)}`:`${e(i.hour)}:${e(i.minute??0)}`}function Vs(i){const e=Math.round(i/1e3),t=Math.floor(e/60),n=e%60;return`${t}:${String(n).padStart(2,"0")}`}const mo="rr0-ufo";function sa(){customElements.get(mo)||customElements.define(mo,S0)}const y0=`
485
481
  <div class="stage" id="stage">
486
482
  <div class="frame" id="frame">
487
483
  <canvas id="scene-canvas"></canvas>
@@ -5368,4 +5364,4 @@ void main() {
5368
5364
  float blur = max(vNearBlur, vHaze);
5369
5365
  gl_FragColor = vec4(color, tex.a * uOpacity * (1.0 - blur * 0.5));
5370
5366
  }
5371
- `;let Dr;function q2(){if(Dr)return Dr;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),Dr=new Un(e),Dr}function K2(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=wd(i.illuminatedFraction,0,1),h=i.phaseFraction<.5,d=s*Math.abs(1-2*c),u=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,d,s,0,Math.PI/2,-Math.PI/2,u)):(n.arc(r,a,s,Math.PI/2,-Math.PI/2,!1),n.ellipse(r,a,d,s,0,-Math.PI/2,Math.PI/2,u)),n.fill(),n.restore(),new Un(t)}function $2(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 Un(e)}function oo(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 ou=new Map;function Z2(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 J2(i){let e=ou.get(i);return e||(e=fetch(i).then(t=>t.arrayBuffer()).then(Z2),ou.set(i,e)),e}const Q2=new URL(""+new URL("rain-BvWZrB9h.ogg",import.meta.url).href,import.meta.url).href,j2=new URL(""+new URL("wind-BjklexY7.ogg",import.meta.url).href,import.meta.url).href,eS=new URL(""+new URL("thunder-DA48qs_v.wav",import.meta.url).href,import.meta.url).href,tS=20,nS=1;class iS{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(Q2,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/tS,1);const r=n>nS;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(j2,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(eS,.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()}}sa();const sS={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"}},rS=["en","fr"],aS=new URL(""+new URL("stars-mag7.5-DDr9QasD.bin",import.meta.url).href,import.meta.url).href,oS={sun:{altitudeDeg:-3,azimuthDeg:180,magnitude:-26.7},moon:{altitudeDeg:-90,azimuthDeg:0,phase:{phaseFraction:0,illuminatedFraction:0},magnitude:-12.7},planets:[]},lo={lat:0,lng:0,elevationM:0,headingDeg:void 0,pitchDeg:0,fovDeg:60};class lS extends HTMLElement{static get observedAttributes(){return["src","star-catalog-src","show-compass","lens-flare-intensity","lens-flare-brightness"]}shadow;stageElement;frameElement;sceneCanvas;ufoElement;sceneRenderer;bodyTooltip;resizeObserver;lastTimeMs=0;starCatalog;weatherAudio=new iS;thunderTimeoutId;handleFullscreenChange=()=>this.resizeToStage();handlePointerMove=e=>{this.sceneRenderer.setCompassHovered(!0);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),a=this.sceneRenderer.pickBodyAt(s,r);if(!a){this.bodyTooltip.hidden=!0;return}const o=ia(navigator.languages,rS);this.bodyTooltip.textContent=sS[a]?.[o]??a,this.bodyTooltip.hidden=!1;const l=this.stageElement.getBoundingClientRect();this.bodyTooltip.style.left=`${e.clientX-l.left+12}px`,this.bodyTooltip.style.top=`${e.clientY-l.top+12}px`};handlePointerLeave=()=>{this.bodyTooltip.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(uo(this.ufoElement.sighting,this.lastTimeMs))};handleTimeUpdate=e=>{this.lastTimeMs=e.detail.time,this.updateAstronomy(this.lastTimeMs)};constructor(){super(),this.shadow=this.attachShadow({mode:"open"});const e=document.createElement("template");e.innerHTML=`<style>${M0}</style>${y0}`,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 B2(this.sceneCanvas,void 0,this.handleLightningFlash),this.bodyTooltip=this.shadow.getElementById("body-tooltip"),this.ufoElement=document.createElement(mo),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)}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")??aS;this.starCatalog=await J2(e),this.updateAstronomy(this.lastTimeMs)}updateAstronomy(e){const t=this.ufoElement.sighting;this.setWeather(uo(t,e)),this.sceneRenderer.setDecor(t.decor);const n=mc(t,e);this.sceneRenderer.setObserverPose(n??lo),this.sceneRenderer.updateDecorAnchoring(mc(t,0),n),this.sceneRenderer.setTerrainOrigin(n?.lat,n?.lng);const s=n?.lat??lo.lat,r=n?.lng??lo.lng,a=ox(t.event.time??{},r);if(!a){this.sceneRenderer.setAstronomy(oS);return}const o=new Date(a.getTime()+e),l={lat:s,lng:r,elevationM:n?.elevationM??0},c={...Ja("Sun",o,l),magnitude:Qa("Sun",o)},h={...Ja("Moon",o,l),phase:ix(o),magnitude:Qa("Moon",o)},d=tx.map(u=>({body:u,position:Ja(u,o,l),magnitude:Qa(u,o)}));this.sceneRenderer.setAstronomy({sun:c,moon:h,planets:d,stars:this.starCatalog?{catalog:this.starCatalog,date:o,observer:l}:void 0})}}const Cl="rr0-scene";function cS(){sa(),customElements.get(Cl)||customElements.define(Cl,lS)}class hS{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=fu(this.shapePrototype,this.currentPointer.x,this.currentPointer.y);this.timeline.addKeyframe(e,[{sourceId:this.sourceId,shape:t}])}}class uS{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 Td={oval:"Oval",saucer:"Saucer",triangle:"Triangle",color:"Color",transparency:"Transparency",halo:"Halo",shape:"Shape",shapeTitle:"Name",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",decorGroup:"Decor",decorKind:"Kind",decor:"Decor",decorBuilding:"Building",decorTree:"Tree",decorStreetlight:"Streetlight",decorVehicle:"Vehicle",decorWitness:"Other witness",addDecor:"Add decor",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",addWitness:"Add witness",addBuilding:"Add building"},dS=Object.freeze(Object.defineProperty({__proto__:null,ufoRecorderMessages_en:Td},Symbol.toStringTag,{value:"Module"}));sa();cS();const Ki={width:48,height:28},lu=.2,cu=new Set(["ArrowLeft","ArrowRight","ArrowUp","ArrowDown"]),Yn=4,co="ufo-1",hu=["oval","saucer","triangle"],fS={presetId:"oval",color:"#39ff14",transparency:0,haloScale:1.5};function pS(i){if(i.kind==="oval")return"oval";if(i.points.length===3)return"triangle";if(i.points.length===8)return"saucer"}class mS extends HTMLElement{shadow;sceneElement;ufoElement;recordButton;samplingRateInput;presetButtons;presetsGroup;colorInput;transparencyInput;haloScaleInput;sourceSelect;shapeTitleInput;addShapeButton;deleteShapeButton;contextMenu;contextGroupButton;contextUngroupButton;contextBringToFrontButton;contextSendToBackButton;contextDeleteButton;decorContextMenu;contextViewTestimonyButton;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;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;addDecorButton;addDecorWitnessButton;addDecorBuildingButton;deleteDecorButton;decorSelect;decorTitleInput;decorEastInput;decorNorthInput;decorHeadingInput;decorLitInput;decorSightingUrlInput;labelDecorGroup;labelDecorKind;labelDecor;labelDecorTitle;labelDecorEast;labelDecorNorth;labelDecorHeading;labelDecorLit;labelDecorSightingUrl;optionDecorBuilding;optionDecorTree;optionDecorStreetlight;optionDecorVehicle;optionDecorWitness;recorder;isRecording=!1;messages=Td;currentAppearance={...fS};currentSourceId=co;selectedSourceIds=new Set([co]);currentDecorId;contextMenuDecorId;dragState;cameraDragState;handleKeyDown=e=>{if(e.key==="Escape"&&(this.isRecording&&this.toggleRecording(),this.contextMenu.hidden||this.hideContextMenu(),this.decorContextMenu.hidden||this.hideDecorContextMenu()),cu.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;cu.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>${Nd}</style>${Ud}`,this.shadow.appendChild(e.content.cloneNode(!0)),this.sceneElement=document.createElement(Cl),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"),saucer:this.shadow.getElementById("preset-saucer"),triangle:this.shadow.getElementById("preset-triangle")},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.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.decorContextMenu=this.shadow.getElementById("decor-context-menu"),this.contextViewTestimonyButton=this.shadow.getElementById("context-view-testimony"),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.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.addDecorButton=this.shadow.getElementById("add-decor"),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.labelDecorGroup=this.shadow.getElementById("label-decor-group"),this.labelDecorKind=this.shadow.getElementById("label-decor-kind"),this.labelDecor=this.shadow.getElementById("label-decor"),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.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.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()),this.addDecorButton.addEventListener("click",()=>this.addDecor()),this.addDecorWitnessButton.addEventListener("click",()=>this.addDecor("witness")),this.addDecorBuildingButton.addEventListener("click",()=>this.addDecor("building")),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.decorLitInput,this.decorSightingUrlInput])t.addEventListener("input",()=>this.updateDecor());this.ufoElement.addEventListener("timeupdate",()=>{this.onSelectionOrTimeChanged(),this.syncPlaybackControls(),this.dispatchEvent(new CustomEvent("sightingchange"))}),document.addEventListener("keydown",this.handleKeyDown);for(const t of hu)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.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.refreshSourceList(),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]??co,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:60}),this.ufoElement.refresh()}applyEdtfTimeInput(e,t){const n=e.value.trim();if(n==="")t(void 0);else{const s=uc(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===""||uc(t)||(e.setCustomValidity(this.messages.edtfInvalid),e.classList.add("invalid"))}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=Il(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=t0(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?dc(e):"",this.obsTimeInput.setCustomValidity(""),this.obsTimeInput.classList.remove("invalid")}syncObservationEndTimeFields(){const e=this.ufoElement.sighting.event.endTime;this.obsEndTimeInput.value=e?dc(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=uo(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){this.currentAppearance={...this.currentAppearance,...e},this.updatePresetButtons(),!(this.isRecording||this.ufoElement.playbackState==="playing")&&this.applyAppearanceAtPlayhead()}applyAppearanceAtPlayhead(e){const t=this.ufoElement.sighting.timeline,n=this.ufoElement.currentTime,s=t.getInterpolatedShapeAt(n,this.currentSourceId),r=this.buildAppearanceShape(e??s?.bounds??this.defaultBounds(),s);t.addKeyframe(n,[{sourceId:this.currentSourceId,shape:r}]),this.ufoElement.refresh()}buildAppearanceShape(e,t){const n=cc(e,this.currentAppearance);return t?{...n,angle:t.angle,title:t.title,selected:t.selected}:n}onSelectionOrTimeChanged(){this.syncAppearanceFromTimeline(),this.syncObserverFromTimeline(),this.syncWeatherFromTimeline(),this.updateAppearanceFieldsDisabledState(),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.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:pS(e)??this.currentAppearance.presetId,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??""))}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())}shapeLabel(e){return this.ufoElement.sighting.timeline.getInterpolatedShapeAt(this.ufoElement.currentTime,e)?.title||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.refreshSourceList()}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,eastM:8*t.decor.length,northM:15,headingDeg:0,lit:!1};t.decor=[...t.decor,s],this.currentDecorId=s.id,this.refreshDecorList(),this.ufoElement.refresh()}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.syncDecorFields()}updateDecor(){if(this.currentDecorId===void 0)return;const e=this.ufoElement.sighting,t=this.wrapDegrees(Number(this.decorHeadingInput.value),this.decorHeadingInput)??0;e.decor=e.decor.map(n=>n.id===this.currentDecorId?{...n,title:this.stringOrUndefined(this.decorTitleInput.value),eastM:Number(this.decorEastInput.value),northM:Number(this.decorNorthInput.value),headingDeg:t,lit:this.decorLitInput.checked,sightingUrl:this.stringOrUndefined(this.decorSightingUrlInput.value)}:n),this.decorSelect.options[this.decorSelect.selectedIndex].textContent=this.decorLabel(e.decor.find(n=>n.id===this.currentDecorId)),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])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?.lit??!1,this.decorSightingUrlInput.value=e?.sightingUrl??""}updatePresetButtons(){for(const e of hu)this.presetButtons[e]?.setAttribute("aria-pressed",String(e===this.currentAppearance.presetId))}get samplingRate(){return Number(this.samplingRateInput.value)}buildPrototype(e=this.defaultBounds()){return cc(e,this.currentAppearance)}defaultBounds(){const e=this.ufoElement.canvasElement;return{x:e.width/2-Ki.width/2,y:e.height/2-Ki.height/2,width:Ki.width,height:Ki.height}}toggleRecording(){this.endDrag();const e=this.ufoElement.canvasElement;this.isRecording?(this.recorder?.stop(),this.isRecording=!1,this.setRecordButtonLabel(!1),e.style.cursor="",e.style.touchAction="",this.sourceSelect.disabled=!1,this.addShapeButton.disabled=!1,this.ufoElement.refresh(),this.refreshSourceList()):(this.recorder=new hS(this.ufoElement.sighting.timeline,new uS(this.samplingRate)),this.recorder.start(this.currentSourceId,this.buildPrototype()),this.isRecording=!0,this.setRecordButtonLabel(!0),e.style.cursor="crosshair",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=ia(navigator.languages,gu);e!=="en"&&this.applyMessages(await v0(e))}applyMessages(e){this.messages=e,this.presetButtons.oval.textContent=e.oval,this.presetButtons.saucer.textContent=e.saucer,this.presetButtons.triangle.textContent=e.triangle,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.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.labelDecorGroup.textContent=e.decorGroup,this.labelDecorKind.textContent=e.decorKind,this.labelDecor.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.addDecorButton.title=e.addDecor,this.addDecorButton.setAttribute("aria-label",e.addDecor),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.addDecorWitnessButton.textContent=e.addWitness,this.addDecorBuildingButton.textContent=e.addBuilding,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=[...this.selectedSourceIds].map(d=>({sourceId:d,shape:n.getInterpolatedShapeAt(s,d)})).filter(d=>!!d.shape),c=new gc(l),h=Yt.hitTestHandle({bounds:c.bounds(),angle:0},t);if(h==="rotate"){if(r)return;this.dragState={kind:"group-rotate",group:c,startPointer:t},this.startDragListening();return}if(h){if(r)return;this.dragState={kind:"group-resize",group:c,handle:h},this.startDragListening();return}}else{const l=n.getInterpolatedShapeAt(s,this.currentSourceId),c=l&&Yt.hitTestHandle(l,t);if(l&&c){if(r)return;this.beginDrag(c==="rotate"?"rotate":"resize",this.currentSourceId,l,t,c);return}}const a=n.hitTest(s,t.x,t.y);if(!a){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()}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 s=this.ufoElement.sighting.timeline.hitTest(this.ufoElement.currentTime,t.x,t.y);if(s){this.selectedSourceIds.has(s.sourceId)||this.selectUnit(s.sourceId),this.currentSourceId=s.sourceId,this.showContextMenu(e.clientX,e.clientY);return}const r=this.pickDecorAt(e),a=r?this.ufoElement.sighting.decor.find(o=>o.id===r):void 0;a?.kind==="witness"&&this.showDecorContextMenu(e.clientX,e.clientY,a)}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(c=>this.selectedSourceIds.has(c)),r=n.length<=s.length,a=s.length>0&&n.slice(n.length-s.length).every(c=>this.selectedSourceIds.has(c)),o=s.length>0&&n.slice(0,s.length).every(c=>this.selectedSourceIds.has(c));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:"",document.addEventListener("click",this.handleOutsideContextMenuClick)}hideContextMenu(){this.contextMenu.hidden=!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,document.addEventListener("click",this.handleOutsideContextMenuClick)}hideDecorContextMenu(){this.decorContextMenu.hidden=!0,this.contextMenuDecorId=void 0,document.removeEventListener("click",this.handleOutsideContextMenuClick)}viewWitnessTestimony(){const e=this.ufoElement.sighting.decor.find(t=>t.id===this.contextMenuDecorId);this.hideDecorContextMenu(),e?.sightingUrl&&this.importFromUrl(e.sightingUrl)}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){this.cameraDragState={startPointer:e,startHeadingDeg:this.numberOrUndefined(this.headingInput.value)??0,startPitchDeg:this.numberOrUndefined(this.pitchInput.value)??0},this.sceneElement.setCompassForced(!0),this.startDragListening()}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{const{kind:s,sourceId:r,original:a,handle:o}=this.dragState,l=s==="resize"?Yt.resizeShape(a,o,t):Yt.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}=this.cameraDragState,a=s+(t.x-n.x)*lu,o=Math.max(-90,Math.min(90,r-(t.y-n.y)*lu));this.headingInput.value=String(a),this.pitchInput.value=String(o),this.updateObserver()}endDrag(){!this.dragState&&!this.cameraDragState||(this.cameraDragState&&this.sceneElement.setCompassForced(!1),this.dragState=void 0,this.cameraDragState=void 0,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(Kn,n.width-Yn);break;case"ArrowRight":n.width+=Yn;break;case"ArrowUp":n.height=Math.max(Kn,n.height-Yn);break;case"ArrowDown":n.height+=Yn;break}n.x-=(n.width-e.width)/2,n.y-=(n.height-e.height)/2}else switch(t.key){case"ArrowLeft":n.x-=Yn;break;case"ArrowRight":n.x+=Yn;break;case"ArrowUp":n.y-=Yn;break;case"ArrowDown":n.y+=Yn;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.selectedSourceIds].map(r=>({sourceId:r,shape:t.getInterpolatedShapeAt(n,r)})).filter(r=>!!r.shape);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 gc(s),a=this.nudgeBounds(r.bounds(),e);t.addKeyframe(n,r.scaleTo(a))}this.ufoElement.refresh()}}onPointerMove(e){if(!this.isRecording)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(fu(this.buildPrototype({x:0,y:0,width:Ki.width,height:Ki.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 uu="rr0-ufo-recorder";function gS(){sa(),customElements.get(uu)||customElements.define(uu,mS)}gS();
5367
+ `;let Dr;function q2(){if(Dr)return Dr;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),Dr=new Un(e),Dr}function K2(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=wd(i.illuminatedFraction,0,1),h=i.phaseFraction<.5,d=s*Math.abs(1-2*c),u=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,d,s,0,Math.PI/2,-Math.PI/2,u)):(n.arc(r,a,s,Math.PI/2,-Math.PI/2,!1),n.ellipse(r,a,d,s,0,-Math.PI/2,Math.PI/2,u)),n.fill(),n.restore(),new Un(t)}function $2(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 Un(e)}function oo(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 ou=new Map;function Z2(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 J2(i){let e=ou.get(i);return e||(e=fetch(i).then(t=>t.arrayBuffer()).then(Z2),ou.set(i,e)),e}const Q2=new URL(""+new URL("rain-BvWZrB9h.ogg",import.meta.url).href,import.meta.url).href,j2=new URL(""+new URL("wind-BjklexY7.ogg",import.meta.url).href,import.meta.url).href,eS=new URL(""+new URL("thunder-DA48qs_v.wav",import.meta.url).href,import.meta.url).href,tS=20,nS=1;class iS{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(Q2,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/tS,1);const r=n>nS;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(j2,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(eS,.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()}}sa();const sS={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"}},rS=["en","fr"],aS=new URL(""+new URL("stars-mag7.5-DDr9QasD.bin",import.meta.url).href,import.meta.url).href,oS={sun:{altitudeDeg:-3,azimuthDeg:180,magnitude:-26.7},moon:{altitudeDeg:-90,azimuthDeg:0,phase:{phaseFraction:0,illuminatedFraction:0},magnitude:-12.7},planets:[]},lo={lat:0,lng:0,elevationM:0,headingDeg:void 0,pitchDeg:0,fovDeg:60};class lS extends HTMLElement{static get observedAttributes(){return["src","star-catalog-src","show-compass","lens-flare-intensity","lens-flare-brightness"]}shadow;stageElement;frameElement;sceneCanvas;ufoElement;sceneRenderer;bodyTooltip;resizeObserver;lastTimeMs=0;starCatalog;weatherAudio=new iS;thunderTimeoutId;handleFullscreenChange=()=>this.resizeToStage();handlePointerMove=e=>{this.sceneRenderer.setCompassHovered(!0);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),a=this.sceneRenderer.pickBodyAt(s,r);if(!a){this.bodyTooltip.hidden=!0;return}const o=ia(navigator.languages,rS);this.bodyTooltip.textContent=sS[a]?.[o]??a,this.bodyTooltip.hidden=!1;const l=this.stageElement.getBoundingClientRect();this.bodyTooltip.style.left=`${e.clientX-l.left+12}px`,this.bodyTooltip.style.top=`${e.clientY-l.top+12}px`};handlePointerLeave=()=>{this.bodyTooltip.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(uo(this.ufoElement.sighting,this.lastTimeMs))};handleTimeUpdate=e=>{this.lastTimeMs=e.detail.time,this.updateAstronomy(this.lastTimeMs)};constructor(){super(),this.shadow=this.attachShadow({mode:"open"});const e=document.createElement("template");e.innerHTML=`<style>${M0}</style>${y0}`,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 B2(this.sceneCanvas,void 0,this.handleLightningFlash),this.bodyTooltip=this.shadow.getElementById("body-tooltip"),this.ufoElement=document.createElement(mo),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)}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")??aS;this.starCatalog=await J2(e),this.updateAstronomy(this.lastTimeMs)}updateAstronomy(e){const t=this.ufoElement.sighting;this.setWeather(uo(t,e)),this.sceneRenderer.setDecor(t.decor);const n=mc(t,e);this.sceneRenderer.setObserverPose(n??lo),this.sceneRenderer.updateDecorAnchoring(mc(t,0),n),this.sceneRenderer.setTerrainOrigin(n?.lat,n?.lng);const s=n?.lat??lo.lat,r=n?.lng??lo.lng,a=ox(t.event.time??{},r);if(!a){this.sceneRenderer.setAstronomy(oS);return}const o=new Date(a.getTime()+e),l={lat:s,lng:r,elevationM:n?.elevationM??0},c={...Ja("Sun",o,l),magnitude:Qa("Sun",o)},h={...Ja("Moon",o,l),phase:ix(o),magnitude:Qa("Moon",o)},d=tx.map(u=>({body:u,position:Ja(u,o,l),magnitude:Qa(u,o)}));this.sceneRenderer.setAstronomy({sun:c,moon:h,planets:d,stars:this.starCatalog?{catalog:this.starCatalog,date:o,observer:l}:void 0})}}const Cl="rr0-scene";function cS(){sa(),customElements.get(Cl)||customElements.define(Cl,lS)}class hS{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=fu(this.shapePrototype,this.currentPointer.x,this.currentPointer.y);this.timeline.addKeyframe(e,[{sourceId:this.sourceId,shape:t}])}}class uS{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 Td={oval:"Oval",saucer:"Saucer",triangle:"Triangle",color:"Color",transparency:"Transparency",halo:"Halo",shape:"Shape",shapeTitle:"Name",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",decorKind:"Kind",decor:"Decor",decorBuilding:"Building",decorTree:"Tree",decorStreetlight:"Streetlight",decorVehicle:"Vehicle",decorWitness:"Other witness",addDecor:"Add decor",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",addWitness:"Add witness",addBuilding:"Add building"},dS=Object.freeze(Object.defineProperty({__proto__:null,ufoRecorderMessages_en:Td},Symbol.toStringTag,{value:"Module"}));sa();cS();const Ki={width:48,height:28},lu=.2,cu=new Set(["ArrowLeft","ArrowRight","ArrowUp","ArrowDown"]),Yn=4,co="ufo-1",hu=["oval","saucer","triangle"],fS={presetId:"oval",color:"#39ff14",transparency:0,haloScale:1.5};function pS(i){if(i.kind==="oval")return"oval";if(i.points.length===3)return"triangle";if(i.points.length===8)return"saucer"}class mS extends HTMLElement{shadow;sceneElement;ufoElement;recordButton;samplingRateInput;presetButtons;presetsGroup;colorInput;transparencyInput;haloScaleInput;sourceSelect;shapeTitleInput;addShapeButton;deleteShapeButton;contextMenu;contextGroupButton;contextUngroupButton;contextBringToFrontButton;contextSendToBackButton;contextDeleteButton;decorContextMenu;contextViewTestimonyButton;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;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;addDecorButton;addDecorWitnessButton;addDecorBuildingButton;deleteDecorButton;decorSelect;decorTitleInput;decorEastInput;decorNorthInput;decorHeadingInput;decorLitInput;decorSightingUrlInput;labelDecorKind;labelDecor;labelDecorTitle;labelDecorEast;labelDecorNorth;labelDecorHeading;labelDecorLit;labelDecorSightingUrl;optionDecorBuilding;optionDecorTree;optionDecorStreetlight;optionDecorVehicle;optionDecorWitness;recorder;isRecording=!1;messages=Td;currentAppearance={...fS};currentSourceId=co;selectedSourceIds=new Set([co]);currentDecorId;contextMenuDecorId;dragState;cameraDragState;handleKeyDown=e=>{if(e.key==="Escape"&&(this.isRecording&&this.toggleRecording(),this.contextMenu.hidden||this.hideContextMenu(),this.decorContextMenu.hidden||this.hideDecorContextMenu()),cu.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;cu.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>${Nd}</style>${Ud}`,this.shadow.appendChild(e.content.cloneNode(!0)),this.sceneElement=document.createElement(Cl),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"),saucer:this.shadow.getElementById("preset-saucer"),triangle:this.shadow.getElementById("preset-triangle")},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.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.decorContextMenu=this.shadow.getElementById("decor-context-menu"),this.contextViewTestimonyButton=this.shadow.getElementById("context-view-testimony"),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.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.addDecorButton=this.shadow.getElementById("add-decor"),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.labelDecorKind=this.shadow.getElementById("label-decor-kind"),this.labelDecor=this.shadow.getElementById("label-decor"),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.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.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()),this.addDecorButton.addEventListener("click",()=>this.addDecor()),this.addDecorWitnessButton.addEventListener("click",()=>this.addDecor("witness")),this.addDecorBuildingButton.addEventListener("click",()=>this.addDecor("building")),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.decorLitInput,this.decorSightingUrlInput])t.addEventListener("input",()=>this.updateDecor());this.ufoElement.addEventListener("timeupdate",()=>{this.onSelectionOrTimeChanged(),this.syncPlaybackControls(),this.dispatchEvent(new CustomEvent("sightingchange"))}),document.addEventListener("keydown",this.handleKeyDown);for(const t of hu)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.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.refreshSourceList(),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]??co,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:60}),this.ufoElement.refresh()}applyEdtfTimeInput(e,t){const n=e.value.trim();if(n==="")t(void 0);else{const s=uc(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===""||uc(t)||(e.setCustomValidity(this.messages.edtfInvalid),e.classList.add("invalid"))}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=Il(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=t0(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?dc(e):"",this.obsTimeInput.setCustomValidity(""),this.obsTimeInput.classList.remove("invalid")}syncObservationEndTimeFields(){const e=this.ufoElement.sighting.event.endTime;this.obsEndTimeInput.value=e?dc(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=uo(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){this.currentAppearance={...this.currentAppearance,...e},this.updatePresetButtons(),!(this.isRecording||this.ufoElement.playbackState==="playing")&&this.applyAppearanceAtPlayhead()}applyAppearanceAtPlayhead(e){const t=this.ufoElement.sighting.timeline,n=this.ufoElement.currentTime,s=t.getInterpolatedShapeAt(n,this.currentSourceId),r=this.buildAppearanceShape(e??s?.bounds??this.defaultBounds(),s);t.addKeyframe(n,[{sourceId:this.currentSourceId,shape:r}]),this.ufoElement.refresh()}buildAppearanceShape(e,t){const n=cc(e,this.currentAppearance);return t?{...n,angle:t.angle,title:t.title,selected:t.selected}:n}onSelectionOrTimeChanged(){this.syncAppearanceFromTimeline(),this.syncObserverFromTimeline(),this.syncWeatherFromTimeline(),this.updateAppearanceFieldsDisabledState(),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.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:pS(e)??this.currentAppearance.presetId,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??""))}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())}shapeLabel(e){return this.ufoElement.sighting.timeline.getInterpolatedShapeAt(this.ufoElement.currentTime,e)?.title||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.refreshSourceList()}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,eastM:8*t.decor.length,northM:15,headingDeg:0,lit:!1};t.decor=[...t.decor,s],this.currentDecorId=s.id,this.refreshDecorList(),this.ufoElement.refresh()}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.syncDecorFields()}updateDecor(){if(this.currentDecorId===void 0)return;const e=this.ufoElement.sighting,t=this.wrapDegrees(Number(this.decorHeadingInput.value),this.decorHeadingInput)??0;e.decor=e.decor.map(n=>n.id===this.currentDecorId?{...n,title:this.stringOrUndefined(this.decorTitleInput.value),eastM:Number(this.decorEastInput.value),northM:Number(this.decorNorthInput.value),headingDeg:t,lit:this.decorLitInput.checked,sightingUrl:this.stringOrUndefined(this.decorSightingUrlInput.value)}:n),this.decorSelect.options[this.decorSelect.selectedIndex].textContent=this.decorLabel(e.decor.find(n=>n.id===this.currentDecorId)),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])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?.lit??!1,this.decorSightingUrlInput.value=e?.sightingUrl??""}updatePresetButtons(){for(const e of hu)this.presetButtons[e]?.setAttribute("aria-pressed",String(e===this.currentAppearance.presetId))}get samplingRate(){return Number(this.samplingRateInput.value)}buildPrototype(e=this.defaultBounds()){return cc(e,this.currentAppearance)}defaultBounds(){const e=this.ufoElement.canvasElement;return{x:e.width/2-Ki.width/2,y:e.height/2-Ki.height/2,width:Ki.width,height:Ki.height}}toggleRecording(){this.endDrag();const e=this.ufoElement.canvasElement;this.isRecording?(this.recorder?.stop(),this.isRecording=!1,this.setRecordButtonLabel(!1),e.style.cursor="",e.style.touchAction="",this.sourceSelect.disabled=!1,this.addShapeButton.disabled=!1,this.ufoElement.refresh(),this.refreshSourceList()):(this.recorder=new hS(this.ufoElement.sighting.timeline,new uS(this.samplingRate)),this.recorder.start(this.currentSourceId,this.buildPrototype()),this.isRecording=!0,this.setRecordButtonLabel(!0),e.style.cursor="crosshair",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=ia(navigator.languages,gu);e!=="en"&&this.applyMessages(await v0(e))}applyMessages(e){this.messages=e,this.presetButtons.oval.textContent=e.oval,this.presetButtons.saucer.textContent=e.saucer,this.presetButtons.triangle.textContent=e.triangle,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.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.labelDecorKind.textContent=e.decorKind,this.labelDecor.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.addDecorButton.title=e.addDecor,this.addDecorButton.setAttribute("aria-label",e.addDecor),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.addDecorWitnessButton.textContent=e.addWitness,this.addDecorBuildingButton.textContent=e.addBuilding,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=[...this.selectedSourceIds].map(d=>({sourceId:d,shape:n.getInterpolatedShapeAt(s,d)})).filter(d=>!!d.shape),c=new gc(l),h=Yt.hitTestHandle({bounds:c.bounds(),angle:0},t);if(h==="rotate"){if(r)return;this.dragState={kind:"group-rotate",group:c,startPointer:t},this.startDragListening();return}if(h){if(r)return;this.dragState={kind:"group-resize",group:c,handle:h},this.startDragListening();return}}else{const l=n.getInterpolatedShapeAt(s,this.currentSourceId),c=l&&Yt.hitTestHandle(l,t);if(l&&c){if(r)return;this.beginDrag(c==="rotate"?"rotate":"resize",this.currentSourceId,l,t,c);return}}const a=n.hitTest(s,t.x,t.y);if(!a){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()}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 s=this.ufoElement.sighting.timeline.hitTest(this.ufoElement.currentTime,t.x,t.y);if(s){this.selectedSourceIds.has(s.sourceId)||this.selectUnit(s.sourceId),this.currentSourceId=s.sourceId,this.showContextMenu(e.clientX,e.clientY);return}const r=this.pickDecorAt(e),a=r?this.ufoElement.sighting.decor.find(o=>o.id===r):void 0;a?.kind==="witness"&&this.showDecorContextMenu(e.clientX,e.clientY,a)}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(c=>this.selectedSourceIds.has(c)),r=n.length<=s.length,a=s.length>0&&n.slice(n.length-s.length).every(c=>this.selectedSourceIds.has(c)),o=s.length>0&&n.slice(0,s.length).every(c=>this.selectedSourceIds.has(c));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:"",document.addEventListener("click",this.handleOutsideContextMenuClick)}hideContextMenu(){this.contextMenu.hidden=!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,document.addEventListener("click",this.handleOutsideContextMenuClick)}hideDecorContextMenu(){this.decorContextMenu.hidden=!0,this.contextMenuDecorId=void 0,document.removeEventListener("click",this.handleOutsideContextMenuClick)}viewWitnessTestimony(){const e=this.ufoElement.sighting.decor.find(t=>t.id===this.contextMenuDecorId);this.hideDecorContextMenu(),e?.sightingUrl&&this.importFromUrl(e.sightingUrl)}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){this.cameraDragState={startPointer:e,startHeadingDeg:this.numberOrUndefined(this.headingInput.value)??0,startPitchDeg:this.numberOrUndefined(this.pitchInput.value)??0},this.sceneElement.setCompassForced(!0),this.startDragListening()}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{const{kind:s,sourceId:r,original:a,handle:o}=this.dragState,l=s==="resize"?Yt.resizeShape(a,o,t):Yt.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}=this.cameraDragState,a=s+(t.x-n.x)*lu,o=Math.max(-90,Math.min(90,r-(t.y-n.y)*lu));this.headingInput.value=String(a),this.pitchInput.value=String(o),this.updateObserver()}endDrag(){!this.dragState&&!this.cameraDragState||(this.cameraDragState&&this.sceneElement.setCompassForced(!1),this.dragState=void 0,this.cameraDragState=void 0,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(Kn,n.width-Yn);break;case"ArrowRight":n.width+=Yn;break;case"ArrowUp":n.height=Math.max(Kn,n.height-Yn);break;case"ArrowDown":n.height+=Yn;break}n.x-=(n.width-e.width)/2,n.y-=(n.height-e.height)/2}else switch(t.key){case"ArrowLeft":n.x-=Yn;break;case"ArrowRight":n.x+=Yn;break;case"ArrowUp":n.y-=Yn;break;case"ArrowDown":n.y+=Yn;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.selectedSourceIds].map(r=>({sourceId:r,shape:t.getInterpolatedShapeAt(n,r)})).filter(r=>!!r.shape);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 gc(s),a=this.nudgeBounds(r.bounds(),e);t.addKeyframe(n,r.scaleTo(a))}this.ufoElement.refresh()}}onPointerMove(e){if(!this.isRecording)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(fu(this.buildPrototype({x:0,y:0,width:Ki.width,height:Ki.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 uu="rr0-ufo-recorder";function gS(){sa(),customElements.get(uu)||customElements.define(uu,mS)}gS();
@@ -5186,4 +5186,4 @@ void main() {
5186
5186
  float blur = max(vNearBlur, vHaze);
5187
5187
  gl_FragColor = vec4(color, tex.a * uOpacity * (1.0 - blur * 0.5));
5188
5188
  }
5189
- `;let Rr;function P2(){if(Rr)return Rr;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),Rr=new Ln(e),Rr}function I2(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=f0(i.illuminatedFraction,0,1),h=i.phaseFraction<.5,d=s*Math.abs(1-2*c),u=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,d,s,0,Math.PI/2,-Math.PI/2,u)):(n.arc(r,a,s,Math.PI/2,-Math.PI/2,!1),n.ellipse(r,a,d,s,0,-Math.PI/2,Math.PI/2,u)),n.fill(),n.restore(),new Ln(t)}function D2(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 Ln(e)}function so(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 Qh=new Map;function L2(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 U2(i){let e=Qh.get(i);return e||(e=fetch(i).then(t=>t.arrayBuffer()).then(L2),Qh.set(i,e)),e}const N2=new URL(""+new URL("rain-BvWZrB9h.ogg",import.meta.url).href,import.meta.url).href,F2=new URL(""+new URL("wind-BjklexY7.ogg",import.meta.url).href,import.meta.url).href,O2=new URL(""+new URL("thunder-DA48qs_v.wav",import.meta.url).href,import.meta.url).href,B2=20,z2=1;class G2{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(N2,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/B2,1);const r=n>z2;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(F2,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(O2,.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()}}su();const k2={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"}},H2=["en","fr"],V2=new URL(""+new URL("stars-mag7.5-DDr9QasD.bin",import.meta.url).href,import.meta.url).href,W2={sun:{altitudeDeg:-3,azimuthDeg:180,magnitude:-26.7},moon:{altitudeDeg:-90,azimuthDeg:0,phase:{phaseFraction:0,illuminatedFraction:0},magnitude:-12.7},planets:[]},ro={lat:0,lng:0,elevationM:0,headingDeg:void 0,pitchDeg:0,fovDeg:60};class X2 extends HTMLElement{static get observedAttributes(){return["src","star-catalog-src","show-compass","lens-flare-intensity","lens-flare-brightness"]}shadow;stageElement;frameElement;sceneCanvas;ufoElement;sceneRenderer;bodyTooltip;resizeObserver;lastTimeMs=0;starCatalog;weatherAudio=new G2;thunderTimeoutId;handleFullscreenChange=()=>this.resizeToStage();handlePointerMove=e=>{this.sceneRenderer.setCompassHovered(!0);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),a=this.sceneRenderer.pickBodyAt(s,r);if(!a){this.bodyTooltip.hidden=!0;return}const o=ea(navigator.languages,H2);this.bodyTooltip.textContent=k2[a]?.[o]??a,this.bodyTooltip.hidden=!1;const l=this.stageElement.getBoundingClientRect();this.bodyTooltip.style.left=`${e.clientX-l.left+12}px`,this.bodyTooltip.style.top=`${e.clientY-l.top+12}px`};handlePointerLeave=()=>{this.bodyTooltip.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(ac(this.ufoElement.sighting,this.lastTimeMs))};handleTimeUpdate=e=>{this.lastTimeMs=e.detail.time,this.updateAstronomy(this.lastTimeMs)};constructor(){super(),this.shadow=this.attachShadow({mode:"open"});const e=document.createElement("template");e.innerHTML=`<style>${w0}</style>${T0}`,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 S2(this.sceneCanvas,void 0,this.handleLightningFlash),this.bodyTooltip=this.shadow.getElementById("body-tooltip"),this.ufoElement=document.createElement(lo),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)}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")??V2;this.starCatalog=await U2(e),this.updateAstronomy(this.lastTimeMs)}updateAstronomy(e){const t=this.ufoElement.sighting;this.setWeather(ac(t,e)),this.sceneRenderer.setDecor(t.decor);const n=rc(t,e);this.sceneRenderer.setObserverPose(n??ro),this.sceneRenderer.updateDecorAnchoring(rc(t,0),n),this.sceneRenderer.setTerrainOrigin(n?.lat,n?.lng);const s=n?.lat??ro.lat,r=n?.lng??ro.lng,a=o0(t.event.time??{},r);if(!a){this.sceneRenderer.setAstronomy(W2);return}const o=new Date(a.getTime()+e),l={lat:s,lng:r,elevationM:n?.elevationM??0},c={...$a("Sun",o,l),magnitude:Za("Sun",o)},h={...$a("Moon",o,l),phase:kv(o),magnitude:Za("Moon",o)},d=zv.map(u=>({body:u,position:$a(u,o,l),magnitude:Za(u,o)}));this.sceneRenderer.setAstronomy({sun:c,moon:h,planets:d,stars:this.starCatalog?{catalog:this.starCatalog,date:o,observer:l}:void 0})}}const El="rr0-scene";function p0(){su(),customElements.get(El)||customElements.define(El,X2)}const m0={testimonyBy:"Testimony by",about:"About",close:"Close",observation:"Observation",date:"Date",location:"Location",case:"Case",description:"Description",tags:"Tags",credits:"Credits"},q2=Object.freeze(Object.defineProperty({__proto__:null,eyewitnessMessages_en:m0},Symbol.toStringTag,{value:"Module"}));p0();const Y2="“Thunder” by Jerimee",$2="https://creativecommons.org/licenses/by/3.0/",Z2="CC BY 3.0",K2="https://ufoathome.org";class J2 extends HTMLElement{static get observedAttributes(){return["src"]}shadow;sceneElement;toolbarElement;testimonyPrefix;witnessText;witnessSelect;infoButton;infoPanel;infoAppLink;infoObservationHeading;infoObservationList;infoCreditsToggle;infoCreditsList;infoCloseButton;entries=[];currentSrc;infoOpen=!1;creditsOpen=!1;language="en";messages=m0;constructor(){super(),this.shadow=this.attachShadow({mode:"open"});const e=document.createElement("template");e.innerHTML=`<style>${b0}</style>${E0}`,this.shadow.appendChild(e.content.cloneNode(!0)),this.sceneElement=document.createElement(El),this.shadow.getElementById("ufo-slot").replaceWith(this.sceneElement),this.toolbarElement=this.shadow.getElementById("toolbar"),this.testimonyPrefix=this.shadow.getElementById("testimony-prefix"),this.witnessText=this.shadow.getElementById("witness-text"),this.witnessSelect=this.shadow.getElementById("witness"),this.infoButton=this.shadow.getElementById("info-button"),this.infoPanel=this.shadow.getElementById("info-panel"),this.infoAppLink=this.shadow.getElementById("info-app-link"),this.infoObservationHeading=this.shadow.getElementById("info-observation-heading"),this.infoObservationList=this.shadow.getElementById("info-observation-list"),this.infoCreditsToggle=this.shadow.getElementById("info-credits-toggle"),this.infoCreditsList=this.shadow.getElementById("info-credits-list"),this.infoCloseButton=this.shadow.getElementById("info-close"),this.witnessSelect.addEventListener("change",()=>this.selectWitness(this.witnessSelect.value)),this.infoButton.addEventListener("click",()=>this.toggleInfoPanel()),this.infoCloseButton.addEventListener("click",()=>this.toggleInfoPanel()),this.infoCreditsToggle.addEventListener("click",()=>this.toggleCredits()),this.loadLocaleMessages()}async loadLocaleMessages(){this.language=ea(navigator.languages,nu),this.language!=="en"&&(this.messages=await id(this.language),this.testimonyPrefix.textContent=this.messages.testimonyBy,this.infoButton.title=this.messages.about,this.infoButton.setAttribute("aria-label",this.messages.about),this.infoCloseButton.setAttribute("aria-label",this.messages.close),this.infoObservationHeading.textContent=this.messages.observation,this.infoCreditsToggle.textContent=this.messages.credits,this.infoOpen&&this.populateInfoPanel(),this.updateTestimonyLine())}connectedCallback(){const e=this.getAttribute("src");e&&this.loadFromSrc(e)}disconnectedCallback(){document.removeEventListener("click",this.handleOutsideClick)}attributeChangedCallback(e,t,n){e==="src"&&n&&n!==t&&this.isConnected&&this.loadFromSrc(n)}async loadFromSrc(e){const n=await(await fetch(e)).json();Array.isArray(n)?await this.loadWitnessUrls(n):this.setEntries([{src:e,sighting:n}])}get witnessUrls(){return this.entries.map(e=>e.src)}set witnessUrls(e){this.loadWitnessUrls(e)}async loadWitnessUrls(e){const t=await Promise.all(e.map(async n=>{const s=await fetch(n);return{src:n,sighting:await s.json()}}));this.setEntries(t)}setEntries(e){this.entries=e,this.warnOnMismatchedCaseIds(e),this.toolbarElement.hidden=e.length===0;const t=e.length>1;this.witnessSelect.hidden=!t,this.witnessText.hidden=t,this.witnessSelect.innerHTML="";for(const s of e){const r=document.createElement("option");r.value=s.src,r.textContent=this.witnessDisplayName(s.sighting.witness)??s.src,this.witnessSelect.appendChild(r)}const n=e.find(s=>s.src===this.currentSrc)??e[0];n?this.selectWitness(n.src):this.updateTestimonyLine()}warnOnMismatchedCaseIds(e){const t=new Set(e.map(n=>n.sighting.caseId).filter(n=>n!==void 0));t.size>1&&console.warn(`<rr0-eyewitness>: witnesses declare different case ids (${[...t].join(", ")}) — they may not belong to the same case.`)}selectWitness(e){const t=this.entries.find(n=>n.src===e);t&&(this.currentSrc=e,this.witnessSelect.value=e,this.sceneElement.sightingData=t.sighting,this.updateTestimonyLine(),this.infoOpen&&this.populateInfoPanel())}updateTestimonyLine(){const e=this.entries.find(t=>t.src===this.currentSrc);e&&(this.witnessText.textContent=this.witnessDisplayName(e.sighting.witness)??e.src)}witnessDisplayName(e){if(!e)return;const t=[...e.firstNames??[],e.lastName].filter(Boolean).join(" ");return e.title||t||e.id||e.dirName}formatDate(e){const t=e.place?.[0],n=o0(e.time??{},t?.lng??0);if(n)return new Intl.DateTimeFormat(this.language==="fr"?"fr-FR":"en-US",{dateStyle:"long",timeStyle:"short"}).format(n)}formatLocation(e){const t=e.place?.[0];if(t)return`${t.lat.toFixed(4)}, ${t.lng.toFixed(4)}`}toggleInfoPanel(){this.infoOpen=!this.infoOpen,this.infoPanel.hidden=!this.infoOpen,this.infoButton.setAttribute("aria-expanded",String(this.infoOpen)),this.infoOpen?(this.populateInfoPanel(),document.addEventListener("click",this.handleOutsideClick)):(this.creditsOpen=!1,this.infoCreditsList.hidden=!0,this.infoCreditsToggle.setAttribute("aria-expanded","false"),document.removeEventListener("click",this.handleOutsideClick))}handleOutsideClick=e=>{const t=e.composedPath();!t.includes(this.infoPanel)&&!t.includes(this.infoButton)&&this.toggleInfoPanel()};toggleCredits(){this.creditsOpen=!this.creditsOpen,this.infoCreditsList.hidden=!this.creditsOpen,this.infoCreditsToggle.setAttribute("aria-expanded",String(this.creditsOpen))}populateInfoPanel(){const e=this.entries.find(r=>r.src===this.currentSrc);if(this.infoObservationList.innerHTML="",e){const r=this.formatDate(e.sighting);r&&this.appendInfoRow(this.infoObservationList,this.messages.date,r);const a=this.formatLocation(e.sighting);a&&this.appendInfoRow(this.infoObservationList,this.messages.location,a),e.sighting.caseId&&this.appendInfoRow(this.infoObservationList,this.messages.case,e.sighting.caseId),e.sighting.description&&this.appendInfoRow(this.infoObservationList,this.messages.description,e.sighting.description),e.sighting.tags&&e.sighting.tags.length>0&&this.appendInfoRow(this.infoObservationList,this.messages.tags,e.sighting.tags.join(", "))}this.infoAppLink.href=K2,this.infoAppLink.textContent="UFO@home v0.10.0",this.infoCreditsList.innerHTML="";const t=this.sceneElement.currentTerrainAttribution;if(t){const r=document.createElement("li");r.textContent=t,this.infoCreditsList.appendChild(r)}const n=document.createElement("li");n.textContent=`${Y2} (`;const s=document.createElement("a");s.href=$2,s.target="_blank",s.rel="noopener",s.textContent=Z2,n.appendChild(s),n.appendChild(document.createTextNode(")")),this.infoCreditsList.appendChild(n)}appendInfoRow(e,t,n){const s=document.createElement("dt");s.textContent=t;const r=document.createElement("dd");r.textContent=n,e.appendChild(s),e.appendChild(r)}}const jh="rr0-eyewitness";function Q2(){p0(),customElements.get(jh)||customElements.define(jh,J2)}Q2();
5189
+ `;let Rr;function P2(){if(Rr)return Rr;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),Rr=new Ln(e),Rr}function I2(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=f0(i.illuminatedFraction,0,1),h=i.phaseFraction<.5,d=s*Math.abs(1-2*c),u=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,d,s,0,Math.PI/2,-Math.PI/2,u)):(n.arc(r,a,s,Math.PI/2,-Math.PI/2,!1),n.ellipse(r,a,d,s,0,-Math.PI/2,Math.PI/2,u)),n.fill(),n.restore(),new Ln(t)}function D2(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 Ln(e)}function so(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 Qh=new Map;function L2(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 U2(i){let e=Qh.get(i);return e||(e=fetch(i).then(t=>t.arrayBuffer()).then(L2),Qh.set(i,e)),e}const N2=new URL(""+new URL("rain-BvWZrB9h.ogg",import.meta.url).href,import.meta.url).href,F2=new URL(""+new URL("wind-BjklexY7.ogg",import.meta.url).href,import.meta.url).href,O2=new URL(""+new URL("thunder-DA48qs_v.wav",import.meta.url).href,import.meta.url).href,B2=20,z2=1;class G2{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(N2,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/B2,1);const r=n>z2;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(F2,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(O2,.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()}}su();const k2={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"}},H2=["en","fr"],V2=new URL(""+new URL("stars-mag7.5-DDr9QasD.bin",import.meta.url).href,import.meta.url).href,W2={sun:{altitudeDeg:-3,azimuthDeg:180,magnitude:-26.7},moon:{altitudeDeg:-90,azimuthDeg:0,phase:{phaseFraction:0,illuminatedFraction:0},magnitude:-12.7},planets:[]},ro={lat:0,lng:0,elevationM:0,headingDeg:void 0,pitchDeg:0,fovDeg:60};class X2 extends HTMLElement{static get observedAttributes(){return["src","star-catalog-src","show-compass","lens-flare-intensity","lens-flare-brightness"]}shadow;stageElement;frameElement;sceneCanvas;ufoElement;sceneRenderer;bodyTooltip;resizeObserver;lastTimeMs=0;starCatalog;weatherAudio=new G2;thunderTimeoutId;handleFullscreenChange=()=>this.resizeToStage();handlePointerMove=e=>{this.sceneRenderer.setCompassHovered(!0);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),a=this.sceneRenderer.pickBodyAt(s,r);if(!a){this.bodyTooltip.hidden=!0;return}const o=ea(navigator.languages,H2);this.bodyTooltip.textContent=k2[a]?.[o]??a,this.bodyTooltip.hidden=!1;const l=this.stageElement.getBoundingClientRect();this.bodyTooltip.style.left=`${e.clientX-l.left+12}px`,this.bodyTooltip.style.top=`${e.clientY-l.top+12}px`};handlePointerLeave=()=>{this.bodyTooltip.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(ac(this.ufoElement.sighting,this.lastTimeMs))};handleTimeUpdate=e=>{this.lastTimeMs=e.detail.time,this.updateAstronomy(this.lastTimeMs)};constructor(){super(),this.shadow=this.attachShadow({mode:"open"});const e=document.createElement("template");e.innerHTML=`<style>${w0}</style>${T0}`,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 S2(this.sceneCanvas,void 0,this.handleLightningFlash),this.bodyTooltip=this.shadow.getElementById("body-tooltip"),this.ufoElement=document.createElement(lo),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)}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")??V2;this.starCatalog=await U2(e),this.updateAstronomy(this.lastTimeMs)}updateAstronomy(e){const t=this.ufoElement.sighting;this.setWeather(ac(t,e)),this.sceneRenderer.setDecor(t.decor);const n=rc(t,e);this.sceneRenderer.setObserverPose(n??ro),this.sceneRenderer.updateDecorAnchoring(rc(t,0),n),this.sceneRenderer.setTerrainOrigin(n?.lat,n?.lng);const s=n?.lat??ro.lat,r=n?.lng??ro.lng,a=o0(t.event.time??{},r);if(!a){this.sceneRenderer.setAstronomy(W2);return}const o=new Date(a.getTime()+e),l={lat:s,lng:r,elevationM:n?.elevationM??0},c={...$a("Sun",o,l),magnitude:Za("Sun",o)},h={...$a("Moon",o,l),phase:kv(o),magnitude:Za("Moon",o)},d=zv.map(u=>({body:u,position:$a(u,o,l),magnitude:Za(u,o)}));this.sceneRenderer.setAstronomy({sun:c,moon:h,planets:d,stars:this.starCatalog?{catalog:this.starCatalog,date:o,observer:l}:void 0})}}const El="rr0-scene";function p0(){su(),customElements.get(El)||customElements.define(El,X2)}const m0={testimonyBy:"Testimony by",about:"About",close:"Close",observation:"Observation",date:"Date",location:"Location",case:"Case",description:"Description",tags:"Tags",credits:"Credits"},q2=Object.freeze(Object.defineProperty({__proto__:null,eyewitnessMessages_en:m0},Symbol.toStringTag,{value:"Module"}));p0();const Y2="“Thunder” by Jerimee",$2="https://creativecommons.org/licenses/by/3.0/",Z2="CC BY 3.0",K2="https://ufoathome.org";class J2 extends HTMLElement{static get observedAttributes(){return["src"]}shadow;sceneElement;toolbarElement;testimonyPrefix;witnessText;witnessSelect;infoButton;infoPanel;infoAppLink;infoObservationHeading;infoObservationList;infoCreditsToggle;infoCreditsList;infoCloseButton;entries=[];currentSrc;infoOpen=!1;creditsOpen=!1;language="en";messages=m0;constructor(){super(),this.shadow=this.attachShadow({mode:"open"});const e=document.createElement("template");e.innerHTML=`<style>${b0}</style>${E0}`,this.shadow.appendChild(e.content.cloneNode(!0)),this.sceneElement=document.createElement(El),this.shadow.getElementById("ufo-slot").replaceWith(this.sceneElement),this.toolbarElement=this.shadow.getElementById("toolbar"),this.testimonyPrefix=this.shadow.getElementById("testimony-prefix"),this.witnessText=this.shadow.getElementById("witness-text"),this.witnessSelect=this.shadow.getElementById("witness"),this.infoButton=this.shadow.getElementById("info-button"),this.infoPanel=this.shadow.getElementById("info-panel"),this.infoAppLink=this.shadow.getElementById("info-app-link"),this.infoObservationHeading=this.shadow.getElementById("info-observation-heading"),this.infoObservationList=this.shadow.getElementById("info-observation-list"),this.infoCreditsToggle=this.shadow.getElementById("info-credits-toggle"),this.infoCreditsList=this.shadow.getElementById("info-credits-list"),this.infoCloseButton=this.shadow.getElementById("info-close"),this.witnessSelect.addEventListener("change",()=>this.selectWitness(this.witnessSelect.value)),this.infoButton.addEventListener("click",()=>this.toggleInfoPanel()),this.infoCloseButton.addEventListener("click",()=>this.toggleInfoPanel()),this.infoCreditsToggle.addEventListener("click",()=>this.toggleCredits()),this.loadLocaleMessages()}async loadLocaleMessages(){this.language=ea(navigator.languages,nu),this.language!=="en"&&(this.messages=await id(this.language),this.testimonyPrefix.textContent=this.messages.testimonyBy,this.infoButton.title=this.messages.about,this.infoButton.setAttribute("aria-label",this.messages.about),this.infoCloseButton.setAttribute("aria-label",this.messages.close),this.infoObservationHeading.textContent=this.messages.observation,this.infoCreditsToggle.textContent=this.messages.credits,this.infoOpen&&this.populateInfoPanel(),this.updateTestimonyLine())}connectedCallback(){const e=this.getAttribute("src");e&&this.loadFromSrc(e)}disconnectedCallback(){document.removeEventListener("click",this.handleOutsideClick)}attributeChangedCallback(e,t,n){e==="src"&&n&&n!==t&&this.isConnected&&this.loadFromSrc(n)}async loadFromSrc(e){const n=await(await fetch(e)).json();Array.isArray(n)?await this.loadWitnessUrls(n):this.setEntries([{src:e,sighting:n}])}get witnessUrls(){return this.entries.map(e=>e.src)}set witnessUrls(e){this.loadWitnessUrls(e)}async loadWitnessUrls(e){const t=await Promise.all(e.map(async n=>{const s=await fetch(n);return{src:n,sighting:await s.json()}}));this.setEntries(t)}setEntries(e){this.entries=e,this.warnOnMismatchedCaseIds(e),this.toolbarElement.hidden=e.length===0;const t=e.length>1;this.witnessSelect.hidden=!t,this.witnessText.hidden=t,this.witnessSelect.innerHTML="";for(const s of e){const r=document.createElement("option");r.value=s.src,r.textContent=this.witnessDisplayName(s.sighting.witness)??s.src,this.witnessSelect.appendChild(r)}const n=e.find(s=>s.src===this.currentSrc)??e[0];n?this.selectWitness(n.src):this.updateTestimonyLine()}warnOnMismatchedCaseIds(e){const t=new Set(e.map(n=>n.sighting.caseId).filter(n=>n!==void 0));t.size>1&&console.warn(`<rr0-eyewitness>: witnesses declare different case ids (${[...t].join(", ")}) — they may not belong to the same case.`)}selectWitness(e){const t=this.entries.find(n=>n.src===e);t&&(this.currentSrc=e,this.witnessSelect.value=e,this.sceneElement.sightingData=t.sighting,this.updateTestimonyLine(),this.infoOpen&&this.populateInfoPanel())}updateTestimonyLine(){const e=this.entries.find(t=>t.src===this.currentSrc);e&&(this.witnessText.textContent=this.witnessDisplayName(e.sighting.witness)??e.src)}witnessDisplayName(e){if(!e)return;const t=[...e.firstNames??[],e.lastName].filter(Boolean).join(" ");return e.title||t||e.id||e.dirName}formatDate(e){const t=e.place?.[0],n=o0(e.time??{},t?.lng??0);if(n)return new Intl.DateTimeFormat(this.language==="fr"?"fr-FR":"en-US",{dateStyle:"long",timeStyle:"short"}).format(n)}formatLocation(e){const t=e.place?.[0];if(t)return`${t.lat.toFixed(4)}, ${t.lng.toFixed(4)}`}toggleInfoPanel(){this.infoOpen=!this.infoOpen,this.infoPanel.hidden=!this.infoOpen,this.infoButton.setAttribute("aria-expanded",String(this.infoOpen)),this.infoOpen?(this.populateInfoPanel(),document.addEventListener("click",this.handleOutsideClick)):(this.creditsOpen=!1,this.infoCreditsList.hidden=!0,this.infoCreditsToggle.setAttribute("aria-expanded","false"),document.removeEventListener("click",this.handleOutsideClick))}handleOutsideClick=e=>{const t=e.composedPath();!t.includes(this.infoPanel)&&!t.includes(this.infoButton)&&this.toggleInfoPanel()};toggleCredits(){this.creditsOpen=!this.creditsOpen,this.infoCreditsList.hidden=!this.creditsOpen,this.infoCreditsToggle.setAttribute("aria-expanded",String(this.creditsOpen))}populateInfoPanel(){const e=this.entries.find(r=>r.src===this.currentSrc);if(this.infoObservationList.innerHTML="",e){const r=this.formatDate(e.sighting);r&&this.appendInfoRow(this.infoObservationList,this.messages.date,r);const a=this.formatLocation(e.sighting);a&&this.appendInfoRow(this.infoObservationList,this.messages.location,a),e.sighting.caseId&&this.appendInfoRow(this.infoObservationList,this.messages.case,e.sighting.caseId),e.sighting.description&&this.appendInfoRow(this.infoObservationList,this.messages.description,e.sighting.description),e.sighting.tags&&e.sighting.tags.length>0&&this.appendInfoRow(this.infoObservationList,this.messages.tags,e.sighting.tags.join(", "))}this.infoAppLink.href=K2,this.infoAppLink.textContent="UFO@home v0.10.1",this.infoCreditsList.innerHTML="";const t=this.sceneElement.currentTerrainAttribution;if(t){const r=document.createElement("li");r.textContent=t,this.infoCreditsList.appendChild(r)}const n=document.createElement("li");n.textContent=`${Y2} (`;const s=document.createElement("a");s.href=$2,s.target="_blank",s.rel="noopener",s.textContent=Z2,n.appendChild(s),n.appendChild(document.createTextNode(")")),this.infoCreditsList.appendChild(n)}appendInfoRow(e,t,n){const s=document.createElement("dt");s.textContent=t;const r=document.createElement("dd");r.textContent=n,e.appendChild(s),e.appendChild(r)}}const jh="rr0-eyewitness";function Q2(){p0(),customElements.get(jh)||customElements.define(jh,J2)}Q2();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rr0/ufoathome",
3
3
  "type": "module",
4
- "version": "0.10.0",
4
+ "version": "0.10.1",
5
5
  "description": "UFO@home — record and replay a UFO sighting's shape, movement and appearance",
6
6
  "author": "Jérôme Beau <rr0@rr0.org> (https://rr0.org)",
7
7
  "license": "MIT",