logseq-graph-living-atlas 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +29 -0
- package/CHANGELOG.md +38 -0
- package/CODE_OF_CONDUCT.md +33 -0
- package/CONTRIBUTING.md +116 -0
- package/GOVERNANCE.md +40 -0
- package/LICENSE +21 -0
- package/MAINTAINERS.md +34 -0
- package/README.md +370 -0
- package/ROADMAP.md +38 -0
- package/SECURITY.md +43 -0
- package/SUPPORT.md +31 -0
- package/dist/assets/AtlasCanvas-p-Pb_C3p.js +172 -0
- package/dist/assets/index-Cb0dgkF5.css +1 -0
- package/dist/assets/index-D-LUf-q7.js +12 -0
- package/dist/assets/three-DQCgX68K.js +3947 -0
- package/dist/index.html +13 -0
- package/docs/ADAPTERS.md +48 -0
- package/docs/API.md +145 -0
- package/docs/ARCHITECTURE.md +93 -0
- package/docs/CONCEPTS.md +62 -0
- package/docs/MCP.md +74 -0
- package/docs/RELEASE.md +65 -0
- package/docs/REPO_GUIDE.md +92 -0
- package/docs/TROUBLESHOOTING.md +138 -0
- package/docs/assets/living-atlas-demo.png +0 -0
- package/docs/assets/living-atlas-pathfinder.png +0 -0
- package/docs/assets/living-atlas-radar.png +0 -0
- package/docs/assets/living-atlas-source-detail.png +0 -0
- package/package.json +102 -0
- package/server/brain-service.mjs +201 -0
- package/server/contracts.mjs +346 -0
- package/server/fixture/create-fixture-graph.mjs +115 -0
- package/server/graph/pathfinding.mjs +155 -0
- package/server/graph/quality.mjs +11 -0
- package/server/graph/utils.mjs +25 -0
- package/server/graph-index.mjs +920 -0
- package/server/logseq/parser.mjs +121 -0
- package/server/logseq/source-adapter.mjs +147 -0
- package/server/redaction.mjs +89 -0
- package/server/service.mjs +777 -0
- package/server/source-adapter-contract.d.ts +46 -0
package/ROADMAP.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Roadmap
|
|
2
|
+
|
|
3
|
+
## 0.1.x Stabilization
|
|
4
|
+
|
|
5
|
+
- Keep the public demo fixture fast, safe, and visually representative.
|
|
6
|
+
- Harden the local service boundary before any remote or plugin integration.
|
|
7
|
+
- Improve parser coverage for common Logseq syntax with golden fixtures.
|
|
8
|
+
- Split large modules into smaller server, state, panel, and renderer units.
|
|
9
|
+
- Add regression coverage for timestamp-preserving same-size file rewrites so cache/watch invalidation cannot serve stale snapshots.
|
|
10
|
+
|
|
11
|
+
## 0.2 Parser And Inspection Coverage
|
|
12
|
+
|
|
13
|
+
- Add deeper graph-intelligence lenses for hubs, connectors, islands, stale pages, and proof gaps.
|
|
14
|
+
- Add true cluster-first storage and level-of-detail endpoints for very large graphs.
|
|
15
|
+
- Expand golden fixtures for Logseq block refs, namespaces, journals, aliases, and common property patterns.
|
|
16
|
+
- Add more UI states to fixture screenshots: connector path, source detail, fallback renderer, and redacted diagnostics.
|
|
17
|
+
|
|
18
|
+
## 0.3 Large-Graph Storage
|
|
19
|
+
|
|
20
|
+
- Persist historical snapshots for true time travel instead of timestamp-filtered replay.
|
|
21
|
+
- Explore a SQLite or DuckDB cache for very large graphs.
|
|
22
|
+
- Add persisted large-graph performance history for cold start, cache hit start, snapshot API, reindex, watch latency, and RSS.
|
|
23
|
+
- Add optional Logseq plugin launcher/deep-link support.
|
|
24
|
+
- Add optional MCP/writeback workflows for flagged fixes, kept outside the renderer.
|
|
25
|
+
|
|
26
|
+
## Good First Issues
|
|
27
|
+
|
|
28
|
+
- Add parser fixtures for one unsupported Logseq syntax feature.
|
|
29
|
+
- Improve README screenshots generated only from the public fixture.
|
|
30
|
+
- Add troubleshooting notes for browser/WebGL fallback cases.
|
|
31
|
+
- Tighten copy for one atlas term and update the matching test expectation.
|
|
32
|
+
|
|
33
|
+
## Non-Goals
|
|
34
|
+
|
|
35
|
+
- No cloud sync.
|
|
36
|
+
- No remote listener by default.
|
|
37
|
+
- No direct graph writes from the visualization service.
|
|
38
|
+
- No committed demo graph copied from a real user graph.
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Security
|
|
2
|
+
|
|
3
|
+
Living Atlas is designed as a local-only tool.
|
|
4
|
+
|
|
5
|
+
## Local Boundary
|
|
6
|
+
|
|
7
|
+
- The Local Index Service binds to `127.0.0.1`.
|
|
8
|
+
- Requests from non-loopback peers or with non-local `Host` or `Origin` headers are rejected.
|
|
9
|
+
- The service does not expose an internet-facing listener.
|
|
10
|
+
- The app reads a local Logseq graph from `LOGSEQ_ROOT` or `--root`.
|
|
11
|
+
- The app does not write to the Logseq graph. Writeback should go through a separate guarded MCP server.
|
|
12
|
+
- The cache path is rejected when it is inside `LOGSEQ_ROOT`.
|
|
13
|
+
- Cache records are minimized before writing: arbitrary Logseq properties and relation evidence are dropped unless they are needed for public source detail or parent inference.
|
|
14
|
+
- Normal API responses return graph-relative source paths. Absolute local paths require `LIVING_ATLAS_DEBUG_PATHS=1` or `--debug-paths`.
|
|
15
|
+
- API responses and bundled static files set defensive browser headers such as `X-Content-Type-Options: nosniff`; HTML is served with `Cache-Control: no-store` and a restrictive Content Security Policy.
|
|
16
|
+
- CLI runs against real graphs require a local read token by default. Demo mode remains unauthenticated.
|
|
17
|
+
- Programmatic `createBrainService()` use also requires read-token mode by default; unauthenticated local reads must be enabled explicitly for demos or tests.
|
|
18
|
+
- `POST /api/reindex` can be protected with `LIVING_ATLAS_TOKEN` or `--token`.
|
|
19
|
+
- `LIVING_ATLAS_REQUIRE_TOKEN=1` or `--require-token` requires that token for every `/api/*` route; `LIVING_ATLAS_ALLOW_UNAUTHENTICATED_READ=1` or `--allow-unauthenticated-read` is an explicit local development opt-out.
|
|
20
|
+
- The bundled UI accepts `#token=<token>` for local token entry. URL fragments are not sent to the server, and the app removes the fragment after storing it for the browser session.
|
|
21
|
+
- The SSE route uses a query token only because browser `EventSource` cannot send custom headers. Do not share service logs or browser diagnostics that include token-bearing URLs.
|
|
22
|
+
|
|
23
|
+
Do not reverse-proxy or expose the Local Index Service remotely unless you have added authentication, transport security, and a threat model for your deployment.
|
|
24
|
+
|
|
25
|
+
## Sensitive Data
|
|
26
|
+
|
|
27
|
+
Your Logseq graph may contain private notes, names, credentials, links, or business data. Treat screenshots, snapshot cache files, exported payloads, and QA artifacts as derived graph data.
|
|
28
|
+
|
|
29
|
+
New browser review flags are stored locally as graph-scoped hashed node references plus review handoff context, not page names or source paths. Legacy flags created by older versions are sanitized when migrated into the current graph key. Use the in-app `Clear local data` control, or clear browser site data after testing on sensitive graphs, if you do not want local flags retained.
|
|
30
|
+
|
|
31
|
+
Generated and private artifacts are ignored by default:
|
|
32
|
+
|
|
33
|
+
- `.cache/`
|
|
34
|
+
- `dist/`
|
|
35
|
+
- `docs/qa/`
|
|
36
|
+
- `.env`
|
|
37
|
+
- `.env.local`
|
|
38
|
+
|
|
39
|
+
## Reporting Issues
|
|
40
|
+
|
|
41
|
+
Use GitHub private vulnerability reporting on the canonical repository when available. If it is not enabled, open a minimal public issue that describes the affected version and impact without including private graph contents. See `SUPPORT.md` for non-security support boundaries.
|
|
42
|
+
|
|
43
|
+
Do not attach real graph files, private screenshots, `.cache/snapshot.json`, token URLs, or terminal output containing local paths. Reproduce with `npm run demo` whenever possible.
|
package/SUPPORT.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Support
|
|
2
|
+
|
|
3
|
+
Living Atlas is a local-first project. Support requests should avoid private graph content.
|
|
4
|
+
|
|
5
|
+
## Questions And Bugs
|
|
6
|
+
|
|
7
|
+
Open a GitHub issue using the bug or feature templates. Reproduce with `npm run demo` whenever possible.
|
|
8
|
+
|
|
9
|
+
Include:
|
|
10
|
+
|
|
11
|
+
- Living Atlas version or commit SHA.
|
|
12
|
+
- Node.js version.
|
|
13
|
+
- Operating system.
|
|
14
|
+
- Exact command used to start the service.
|
|
15
|
+
- Redacted API output when useful, for example `/api/health?redact=1` or `/api/snapshot?redact=1`.
|
|
16
|
+
|
|
17
|
+
Do not include:
|
|
18
|
+
|
|
19
|
+
- real Logseq graph files;
|
|
20
|
+
- private screenshots;
|
|
21
|
+
- `.cache/snapshot.json`;
|
|
22
|
+
- token URLs;
|
|
23
|
+
- terminal output containing local paths or graph contents.
|
|
24
|
+
|
|
25
|
+
## Security Reports
|
|
26
|
+
|
|
27
|
+
Use GitHub private vulnerability reporting when available. If private reporting is not available, open a minimal public issue describing the affected version and impact without private data.
|
|
28
|
+
|
|
29
|
+
## Scope
|
|
30
|
+
|
|
31
|
+
The first public release supports local Logseq markdown graphs and a local-only HTTP service. Remote hosting, direct graph writes, and MCP writeback workflows are outside this repository unless explicitly scoped in a future roadmap item.
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import{r as lt,j as os}from"./index-D-LUf-q7.js";import{j as as,l as rs,c as U,F as O,q as dt,U as ae,V as B,W as Kt,H as Qt,N as ls,C as cs,d as L,s as v,a as ut,k as hs,e as us,M as yt,T as xt,Q as Ee,r as De,R as ds,m as ps,h as R,i as Ke,O as fs,p as ms,f as gs,P as bs,t as _s,S as Ms,A as xs,b as ys,n as ws,G as vs,o as Vt,g as At,L as zt,B as ce}from"./three-DQCgX68K.js";const Zt={name:"CopyShader",uniforms:{tDiffuse:{value:null},opacity:{value:1}},vertexShader:`
|
|
2
|
+
|
|
3
|
+
varying vec2 vUv;
|
|
4
|
+
|
|
5
|
+
void main() {
|
|
6
|
+
|
|
7
|
+
vUv = uv;
|
|
8
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
|
|
9
|
+
|
|
10
|
+
}`,fragmentShader:`
|
|
11
|
+
|
|
12
|
+
uniform float opacity;
|
|
13
|
+
|
|
14
|
+
uniform sampler2D tDiffuse;
|
|
15
|
+
|
|
16
|
+
varying vec2 vUv;
|
|
17
|
+
|
|
18
|
+
void main() {
|
|
19
|
+
|
|
20
|
+
vec4 texel = texture2D( tDiffuse, vUv );
|
|
21
|
+
gl_FragColor = opacity * texel;
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
}`};class Ht{constructor(){this.isPass=!0,this.enabled=!0,this.needsSwap=!0,this.clear=!1,this.renderToScreen=!1}setSize(){}render(){console.error("THREE.Pass: .render() must be implemented in derived pass.")}dispose(){}}const Ts=new rs(-1,1,1,-1,0,1);class Ss extends U{constructor(){super(),this.setAttribute("position",new O([-1,3,0,-1,-1,0,3,-1,0],3)),this.setAttribute("uv",new O([0,2,0,0,2,0],2))}}const Ps=new Ss;class Qe{constructor(t){this._mesh=new as(Ps,t)}dispose(){this._mesh.geometry.dispose()}render(t){t.render(this._mesh,Ts)}get material(){return this._mesh.material}set material(t){this._mesh.material=t}}class Cs extends Ht{constructor(t,s="tDiffuse"){super(),this.textureID=s,this.uniforms=null,this.material=null,t instanceof dt?(this.uniforms=t.uniforms,this.material=t):t&&(this.uniforms=ae.clone(t.uniforms),this.material=new dt({name:t.name!==void 0?t.name:"unspecified",defines:Object.assign({},t.defines),uniforms:this.uniforms,vertexShader:t.vertexShader,fragmentShader:t.fragmentShader})),this._fsQuad=new Qe(this.material)}render(t,s,i){this.uniforms[this.textureID]&&(this.uniforms[this.textureID].value=i.texture),this._fsQuad.material=this.material,this.renderToScreen?(t.setRenderTarget(null),this._fsQuad.render(t)):(t.setRenderTarget(s),this.clear&&t.clear(t.autoClearColor,t.autoClearDepth,t.autoClearStencil),this._fsQuad.render(t))}dispose(){this.material.dispose(),this._fsQuad.dispose()}}class Re extends Ht{constructor(t,s){super(),this.scene=t,this.camera=s,this.clear=!0,this.needsSwap=!1,this.inverse=!1}render(t,s,i){const n=t.getContext(),o=t.state;o.buffers.color.setMask(!1),o.buffers.depth.setMask(!1),o.buffers.color.setLocked(!0),o.buffers.depth.setLocked(!0);let a,c;this.inverse?(a=0,c=1):(a=1,c=0),o.buffers.stencil.setTest(!0),o.buffers.stencil.setOp(n.REPLACE,n.REPLACE,n.REPLACE),o.buffers.stencil.setFunc(n.ALWAYS,a,4294967295),o.buffers.stencil.setClear(c),o.buffers.stencil.setLocked(!0),t.setRenderTarget(i),this.clear&&t.clear(),t.render(this.scene,this.camera),t.setRenderTarget(s),this.clear&&t.clear(),t.render(this.scene,this.camera),o.buffers.color.setLocked(!1),o.buffers.depth.setLocked(!1),o.buffers.color.setMask(!0),o.buffers.depth.setMask(!0),o.buffers.stencil.setLocked(!1),o.buffers.stencil.setFunc(n.EQUAL,1,4294967295),o.buffers.stencil.setOp(n.KEEP,n.KEEP,n.KEEP),o.buffers.stencil.setLocked(!0)}}class Es extends Ht{constructor(){super(),this.needsSwap=!1}render(t){t.state.buffers.stencil.setLocked(!1),t.state.buffers.stencil.setTest(!1)}}class Ds{constructor(t,s){if(this.renderer=t,this._pixelRatio=t.getPixelRatio(),s===void 0){const i=t.getSize(new B);this._width=i.width,this._height=i.height,s=new Kt(this._width*this._pixelRatio,this._height*this._pixelRatio,{type:Qt}),s.texture.name="EffectComposer.rt1"}else this._width=s.width,this._height=s.height;this.renderTarget1=s,this.renderTarget2=s.clone(),this.renderTarget2.texture.name="EffectComposer.rt2",this.writeBuffer=this.renderTarget1,this.readBuffer=this.renderTarget2,this.renderToScreen=!0,this.passes=[],this.copyPass=new Cs(Zt),this.copyPass.material.blending=ls,this.clock=new cs}swapBuffers(){const t=this.readBuffer;this.readBuffer=this.writeBuffer,this.writeBuffer=t}addPass(t){this.passes.push(t),t.setSize(this._width*this._pixelRatio,this._height*this._pixelRatio)}insertPass(t,s){this.passes.splice(s,0,t),t.setSize(this._width*this._pixelRatio,this._height*this._pixelRatio)}removePass(t){const s=this.passes.indexOf(t);s!==-1&&this.passes.splice(s,1)}isLastEnabledPass(t){for(let s=t+1;s<this.passes.length;s++)if(this.passes[s].enabled)return!1;return!0}render(t){t===void 0&&(t=this.clock.getDelta());const s=this.renderer.getRenderTarget();let i=!1;for(let n=0,o=this.passes.length;n<o;n++){const a=this.passes[n];if(a.enabled!==!1){if(a.renderToScreen=this.renderToScreen&&this.isLastEnabledPass(n),a.render(this.renderer,this.writeBuffer,this.readBuffer,t,i),a.needsSwap){if(i){const c=this.renderer.getContext(),l=this.renderer.state.buffers.stencil;l.setFunc(c.NOTEQUAL,1,4294967295),this.copyPass.render(this.renderer,this.writeBuffer,this.readBuffer,t),l.setFunc(c.EQUAL,1,4294967295)}this.swapBuffers()}Re!==void 0&&(a instanceof Re?i=!0:a instanceof Es&&(i=!1))}}this.renderer.setRenderTarget(s)}reset(t){if(t===void 0){const s=this.renderer.getSize(new B);this._pixelRatio=this.renderer.getPixelRatio(),this._width=s.width,this._height=s.height,t=this.renderTarget1.clone(),t.setSize(this._width*this._pixelRatio,this._height*this._pixelRatio)}this.renderTarget1.dispose(),this.renderTarget2.dispose(),this.renderTarget1=t,this.renderTarget2=t.clone(),this.writeBuffer=this.renderTarget1,this.readBuffer=this.renderTarget2}setSize(t,s){this._width=t,this._height=s;const i=this._width*this._pixelRatio,n=this._height*this._pixelRatio;this.renderTarget1.setSize(i,n),this.renderTarget2.setSize(i,n);for(let o=0;o<this.passes.length;o++)this.passes[o].setSize(i,n)}setPixelRatio(t){this._pixelRatio=t,this.setSize(this._width,this._height)}dispose(){this.renderTarget1.dispose(),this.renderTarget2.dispose(),this.copyPass.dispose()}}class Rs extends Ht{constructor(t,s,i=null,n=null,o=null){super(),this.scene=t,this.camera=s,this.overrideMaterial=i,this.clearColor=n,this.clearAlpha=o,this.clear=!0,this.clearDepth=!1,this.needsSwap=!1,this._oldClearColor=new L}render(t,s,i){const n=t.autoClear;t.autoClear=!1;let o,a;this.overrideMaterial!==null&&(a=this.scene.overrideMaterial,this.scene.overrideMaterial=this.overrideMaterial),this.clearColor!==null&&(t.getClearColor(this._oldClearColor),t.setClearColor(this.clearColor,t.getClearAlpha())),this.clearAlpha!==null&&(o=t.getClearAlpha(),t.setClearAlpha(this.clearAlpha)),this.clearDepth==!0&&t.clearDepth(),t.setRenderTarget(this.renderToScreen?null:i),this.clear===!0&&t.clear(t.autoClearColor,t.autoClearDepth,t.autoClearStencil),t.render(this.scene,this.camera),this.clearColor!==null&&t.setClearColor(this._oldClearColor),this.clearAlpha!==null&&t.setClearAlpha(o),this.overrideMaterial!==null&&(this.scene.overrideMaterial=a),t.autoClear=n}}const As={uniforms:{tDiffuse:{value:null},luminosityThreshold:{value:1},smoothWidth:{value:1},defaultColor:{value:new L(0)},defaultOpacity:{value:0}},vertexShader:`
|
|
25
|
+
|
|
26
|
+
varying vec2 vUv;
|
|
27
|
+
|
|
28
|
+
void main() {
|
|
29
|
+
|
|
30
|
+
vUv = uv;
|
|
31
|
+
|
|
32
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
|
|
33
|
+
|
|
34
|
+
}`,fragmentShader:`
|
|
35
|
+
|
|
36
|
+
uniform sampler2D tDiffuse;
|
|
37
|
+
uniform vec3 defaultColor;
|
|
38
|
+
uniform float defaultOpacity;
|
|
39
|
+
uniform float luminosityThreshold;
|
|
40
|
+
uniform float smoothWidth;
|
|
41
|
+
|
|
42
|
+
varying vec2 vUv;
|
|
43
|
+
|
|
44
|
+
void main() {
|
|
45
|
+
|
|
46
|
+
vec4 texel = texture2D( tDiffuse, vUv );
|
|
47
|
+
|
|
48
|
+
float v = luminance( texel.xyz );
|
|
49
|
+
|
|
50
|
+
vec4 outputColor = vec4( defaultColor.rgb, defaultOpacity );
|
|
51
|
+
|
|
52
|
+
float alpha = smoothstep( luminosityThreshold, luminosityThreshold + smoothWidth, v );
|
|
53
|
+
|
|
54
|
+
gl_FragColor = mix( outputColor, texel, alpha );
|
|
55
|
+
|
|
56
|
+
}`};class vt extends Ht{constructor(t,s=1,i,n){super(),this.strength=s,this.radius=i,this.threshold=n,this.resolution=t!==void 0?new B(t.x,t.y):new B(256,256),this.clearColor=new L(0,0,0),this.needsSwap=!1,this.renderTargetsHorizontal=[],this.renderTargetsVertical=[],this.nMips=5;let o=Math.round(this.resolution.x/2),a=Math.round(this.resolution.y/2);this.renderTargetBright=new Kt(o,a,{type:Qt}),this.renderTargetBright.texture.name="UnrealBloomPass.bright",this.renderTargetBright.texture.generateMipmaps=!1;for(let h=0;h<this.nMips;h++){const f=new Kt(o,a,{type:Qt});f.texture.name="UnrealBloomPass.h"+h,f.texture.generateMipmaps=!1,this.renderTargetsHorizontal.push(f);const m=new Kt(o,a,{type:Qt});m.texture.name="UnrealBloomPass.v"+h,m.texture.generateMipmaps=!1,this.renderTargetsVertical.push(m),o=Math.round(o/2),a=Math.round(a/2)}const c=As;this.highPassUniforms=ae.clone(c.uniforms),this.highPassUniforms.luminosityThreshold.value=n,this.highPassUniforms.smoothWidth.value=.01,this.materialHighPassFilter=new dt({uniforms:this.highPassUniforms,vertexShader:c.vertexShader,fragmentShader:c.fragmentShader}),this.separableBlurMaterials=[];const l=[6,10,14,18,22];o=Math.round(this.resolution.x/2),a=Math.round(this.resolution.y/2);for(let h=0;h<this.nMips;h++)this.separableBlurMaterials.push(this._getSeparableBlurMaterial(l[h])),this.separableBlurMaterials[h].uniforms.invSize.value=new B(1/o,1/a),o=Math.round(o/2),a=Math.round(a/2);this.compositeMaterial=this._getCompositeMaterial(this.nMips),this.compositeMaterial.uniforms.blurTexture1.value=this.renderTargetsVertical[0].texture,this.compositeMaterial.uniforms.blurTexture2.value=this.renderTargetsVertical[1].texture,this.compositeMaterial.uniforms.blurTexture3.value=this.renderTargetsVertical[2].texture,this.compositeMaterial.uniforms.blurTexture4.value=this.renderTargetsVertical[3].texture,this.compositeMaterial.uniforms.blurTexture5.value=this.renderTargetsVertical[4].texture,this.compositeMaterial.uniforms.bloomStrength.value=s,this.compositeMaterial.uniforms.bloomRadius.value=.1;const r=[1,.8,.6,.4,.2];this.compositeMaterial.uniforms.bloomFactors.value=r,this.bloomTintColors=[new v(1,1,1),new v(1,1,1),new v(1,1,1),new v(1,1,1),new v(1,1,1)],this.compositeMaterial.uniforms.bloomTintColors.value=this.bloomTintColors,this.copyUniforms=ae.clone(Zt.uniforms),this.blendMaterial=new dt({uniforms:this.copyUniforms,vertexShader:Zt.vertexShader,fragmentShader:Zt.fragmentShader,blending:ut,depthTest:!1,depthWrite:!1,transparent:!0}),this._oldClearColor=new L,this._oldClearAlpha=1,this._basic=new hs,this._fsQuad=new Qe(null)}dispose(){for(let t=0;t<this.renderTargetsHorizontal.length;t++)this.renderTargetsHorizontal[t].dispose();for(let t=0;t<this.renderTargetsVertical.length;t++)this.renderTargetsVertical[t].dispose();this.renderTargetBright.dispose();for(let t=0;t<this.separableBlurMaterials.length;t++)this.separableBlurMaterials[t].dispose();this.compositeMaterial.dispose(),this.blendMaterial.dispose(),this._basic.dispose(),this._fsQuad.dispose()}setSize(t,s){let i=Math.round(t/2),n=Math.round(s/2);this.renderTargetBright.setSize(i,n);for(let o=0;o<this.nMips;o++)this.renderTargetsHorizontal[o].setSize(i,n),this.renderTargetsVertical[o].setSize(i,n),this.separableBlurMaterials[o].uniforms.invSize.value=new B(1/i,1/n),i=Math.round(i/2),n=Math.round(n/2)}render(t,s,i,n,o){t.getClearColor(this._oldClearColor),this._oldClearAlpha=t.getClearAlpha();const a=t.autoClear;t.autoClear=!1,t.setClearColor(this.clearColor,0),o&&t.state.buffers.stencil.setTest(!1),this.renderToScreen&&(this._fsQuad.material=this._basic,this._basic.map=i.texture,t.setRenderTarget(null),t.clear(),this._fsQuad.render(t)),this.highPassUniforms.tDiffuse.value=i.texture,this.highPassUniforms.luminosityThreshold.value=this.threshold,this._fsQuad.material=this.materialHighPassFilter,t.setRenderTarget(this.renderTargetBright),t.clear(),this._fsQuad.render(t);let c=this.renderTargetBright;for(let l=0;l<this.nMips;l++)this._fsQuad.material=this.separableBlurMaterials[l],this.separableBlurMaterials[l].uniforms.colorTexture.value=c.texture,this.separableBlurMaterials[l].uniforms.direction.value=vt.BlurDirectionX,t.setRenderTarget(this.renderTargetsHorizontal[l]),t.clear(),this._fsQuad.render(t),this.separableBlurMaterials[l].uniforms.colorTexture.value=this.renderTargetsHorizontal[l].texture,this.separableBlurMaterials[l].uniforms.direction.value=vt.BlurDirectionY,t.setRenderTarget(this.renderTargetsVertical[l]),t.clear(),this._fsQuad.render(t),c=this.renderTargetsVertical[l];this._fsQuad.material=this.compositeMaterial,this.compositeMaterial.uniforms.bloomStrength.value=this.strength,this.compositeMaterial.uniforms.bloomRadius.value=this.radius,this.compositeMaterial.uniforms.bloomTintColors.value=this.bloomTintColors,t.setRenderTarget(this.renderTargetsHorizontal[0]),t.clear(),this._fsQuad.render(t),this._fsQuad.material=this.blendMaterial,this.copyUniforms.tDiffuse.value=this.renderTargetsHorizontal[0].texture,o&&t.state.buffers.stencil.setTest(!0),this.renderToScreen?(t.setRenderTarget(null),this._fsQuad.render(t)):(t.setRenderTarget(i),this._fsQuad.render(t)),t.setClearColor(this._oldClearColor,this._oldClearAlpha),t.autoClear=a}_getSeparableBlurMaterial(t){const s=[],i=t/3;for(let n=0;n<t;n++)s.push(.39894*Math.exp(-.5*n*n/(i*i))/i);return new dt({defines:{KERNEL_RADIUS:t},uniforms:{colorTexture:{value:null},invSize:{value:new B(.5,.5)},direction:{value:new B(.5,.5)},gaussianCoefficients:{value:s}},vertexShader:`varying vec2 vUv;
|
|
57
|
+
void main() {
|
|
58
|
+
vUv = uv;
|
|
59
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
|
|
60
|
+
}`,fragmentShader:`#include <common>
|
|
61
|
+
varying vec2 vUv;
|
|
62
|
+
uniform sampler2D colorTexture;
|
|
63
|
+
uniform vec2 invSize;
|
|
64
|
+
uniform vec2 direction;
|
|
65
|
+
uniform float gaussianCoefficients[KERNEL_RADIUS];
|
|
66
|
+
|
|
67
|
+
void main() {
|
|
68
|
+
float weightSum = gaussianCoefficients[0];
|
|
69
|
+
vec3 diffuseSum = texture2D( colorTexture, vUv ).rgb * weightSum;
|
|
70
|
+
for( int i = 1; i < KERNEL_RADIUS; i ++ ) {
|
|
71
|
+
float x = float(i);
|
|
72
|
+
float w = gaussianCoefficients[i];
|
|
73
|
+
vec2 uvOffset = direction * invSize * x;
|
|
74
|
+
vec3 sample1 = texture2D( colorTexture, vUv + uvOffset ).rgb;
|
|
75
|
+
vec3 sample2 = texture2D( colorTexture, vUv - uvOffset ).rgb;
|
|
76
|
+
diffuseSum += ( sample1 + sample2 ) * w;
|
|
77
|
+
}
|
|
78
|
+
gl_FragColor = vec4( diffuseSum, 1.0 );
|
|
79
|
+
}`})}_getCompositeMaterial(t){return new dt({defines:{NUM_MIPS:t},uniforms:{blurTexture1:{value:null},blurTexture2:{value:null},blurTexture3:{value:null},blurTexture4:{value:null},blurTexture5:{value:null},bloomStrength:{value:1},bloomFactors:{value:null},bloomTintColors:{value:null},bloomRadius:{value:0}},vertexShader:`varying vec2 vUv;
|
|
80
|
+
void main() {
|
|
81
|
+
vUv = uv;
|
|
82
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
|
|
83
|
+
}`,fragmentShader:`varying vec2 vUv;
|
|
84
|
+
uniform sampler2D blurTexture1;
|
|
85
|
+
uniform sampler2D blurTexture2;
|
|
86
|
+
uniform sampler2D blurTexture3;
|
|
87
|
+
uniform sampler2D blurTexture4;
|
|
88
|
+
uniform sampler2D blurTexture5;
|
|
89
|
+
uniform float bloomStrength;
|
|
90
|
+
uniform float bloomRadius;
|
|
91
|
+
uniform float bloomFactors[NUM_MIPS];
|
|
92
|
+
uniform vec3 bloomTintColors[NUM_MIPS];
|
|
93
|
+
|
|
94
|
+
float lerpBloomFactor(const in float factor) {
|
|
95
|
+
float mirrorFactor = 1.2 - factor;
|
|
96
|
+
return mix(factor, mirrorFactor, bloomRadius);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
void main() {
|
|
100
|
+
gl_FragColor = bloomStrength * ( lerpBloomFactor(bloomFactors[0]) * vec4(bloomTintColors[0], 1.0) * texture2D(blurTexture1, vUv) +
|
|
101
|
+
lerpBloomFactor(bloomFactors[1]) * vec4(bloomTintColors[1], 1.0) * texture2D(blurTexture2, vUv) +
|
|
102
|
+
lerpBloomFactor(bloomFactors[2]) * vec4(bloomTintColors[2], 1.0) * texture2D(blurTexture3, vUv) +
|
|
103
|
+
lerpBloomFactor(bloomFactors[3]) * vec4(bloomTintColors[3], 1.0) * texture2D(blurTexture4, vUv) +
|
|
104
|
+
lerpBloomFactor(bloomFactors[4]) * vec4(bloomTintColors[4], 1.0) * texture2D(blurTexture5, vUv) );
|
|
105
|
+
}`})}}vt.BlurDirectionX=new B(1,0);vt.BlurDirectionY=new B(0,1);const Ae={type:"change"},he={type:"start"},Ze={type:"end"},Yt=new ds,ze=new ps,zs=Math.cos(70*R.DEG2RAD),V=new v,Z=2*Math.PI,k={NONE:-1,ROTATE:0,DOLLY:1,PAN:2,TOUCH_ROTATE:3,TOUCH_PAN:4,TOUCH_DOLLY_PAN:5,TOUCH_DOLLY_ROTATE:6},ie=1e-6;class Ls extends us{constructor(t,s=null){super(t,s),this.state=k.NONE,this.target=new v,this.cursor=new v,this.minDistance=0,this.maxDistance=1/0,this.minZoom=0,this.maxZoom=1/0,this.minTargetRadius=0,this.maxTargetRadius=1/0,this.minPolarAngle=0,this.maxPolarAngle=Math.PI,this.minAzimuthAngle=-1/0,this.maxAzimuthAngle=1/0,this.enableDamping=!1,this.dampingFactor=.05,this.enableZoom=!0,this.zoomSpeed=1,this.enableRotate=!0,this.rotateSpeed=1,this.keyRotateSpeed=1,this.enablePan=!0,this.panSpeed=1,this.screenSpacePanning=!0,this.keyPanSpeed=7,this.zoomToCursor=!1,this.autoRotate=!1,this.autoRotateSpeed=2,this.keys={LEFT:"ArrowLeft",UP:"ArrowUp",RIGHT:"ArrowRight",BOTTOM:"ArrowDown"},this.mouseButtons={LEFT:yt.ROTATE,MIDDLE:yt.DOLLY,RIGHT:yt.PAN},this.touches={ONE:xt.ROTATE,TWO:xt.DOLLY_PAN},this.target0=this.target.clone(),this.position0=this.object.position.clone(),this.zoom0=this.object.zoom,this._domElementKeyEvents=null,this._lastPosition=new v,this._lastQuaternion=new Ee,this._lastTargetPosition=new v,this._quat=new Ee().setFromUnitVectors(t.up,new v(0,1,0)),this._quatInverse=this._quat.clone().invert(),this._spherical=new De,this._sphericalDelta=new De,this._scale=1,this._panOffset=new v,this._rotateStart=new B,this._rotateEnd=new B,this._rotateDelta=new B,this._panStart=new B,this._panEnd=new B,this._panDelta=new B,this._dollyStart=new B,this._dollyEnd=new B,this._dollyDelta=new B,this._dollyDirection=new v,this._mouse=new B,this._performCursorZoom=!1,this._pointers=[],this._pointerPositions={},this._controlActive=!1,this._onPointerMove=Os.bind(this),this._onPointerDown=ks.bind(this),this._onPointerUp=Ns.bind(this),this._onContextMenu=Ws.bind(this),this._onMouseWheel=Hs.bind(this),this._onKeyDown=Us.bind(this),this._onTouchStart=js.bind(this),this._onTouchMove=Is.bind(this),this._onMouseDown=Bs.bind(this),this._onMouseMove=Fs.bind(this),this._interceptControlDown=Vs.bind(this),this._interceptControlUp=Ys.bind(this),this.domElement!==null&&this.connect(this.domElement),this.update()}connect(t){super.connect(t),this.domElement.addEventListener("pointerdown",this._onPointerDown),this.domElement.addEventListener("pointercancel",this._onPointerUp),this.domElement.addEventListener("contextmenu",this._onContextMenu),this.domElement.addEventListener("wheel",this._onMouseWheel,{passive:!1}),this.domElement.getRootNode().addEventListener("keydown",this._interceptControlDown,{passive:!0,capture:!0}),this.domElement.style.touchAction="none"}disconnect(){this.domElement.removeEventListener("pointerdown",this._onPointerDown),this.domElement.removeEventListener("pointermove",this._onPointerMove),this.domElement.removeEventListener("pointerup",this._onPointerUp),this.domElement.removeEventListener("pointercancel",this._onPointerUp),this.domElement.removeEventListener("wheel",this._onMouseWheel),this.domElement.removeEventListener("contextmenu",this._onContextMenu),this.stopListenToKeyEvents(),this.domElement.getRootNode().removeEventListener("keydown",this._interceptControlDown,{capture:!0}),this.domElement.style.touchAction="auto"}dispose(){this.disconnect()}getPolarAngle(){return this._spherical.phi}getAzimuthalAngle(){return this._spherical.theta}getDistance(){return this.object.position.distanceTo(this.target)}listenToKeyEvents(t){t.addEventListener("keydown",this._onKeyDown),this._domElementKeyEvents=t}stopListenToKeyEvents(){this._domElementKeyEvents!==null&&(this._domElementKeyEvents.removeEventListener("keydown",this._onKeyDown),this._domElementKeyEvents=null)}saveState(){this.target0.copy(this.target),this.position0.copy(this.object.position),this.zoom0=this.object.zoom}reset(){this.target.copy(this.target0),this.object.position.copy(this.position0),this.object.zoom=this.zoom0,this.object.updateProjectionMatrix(),this.dispatchEvent(Ae),this.update(),this.state=k.NONE}update(t=null){const s=this.object.position;V.copy(s).sub(this.target),V.applyQuaternion(this._quat),this._spherical.setFromVector3(V),this.autoRotate&&this.state===k.NONE&&this._rotateLeft(this._getAutoRotationAngle(t)),this.enableDamping?(this._spherical.theta+=this._sphericalDelta.theta*this.dampingFactor,this._spherical.phi+=this._sphericalDelta.phi*this.dampingFactor):(this._spherical.theta+=this._sphericalDelta.theta,this._spherical.phi+=this._sphericalDelta.phi);let i=this.minAzimuthAngle,n=this.maxAzimuthAngle;isFinite(i)&&isFinite(n)&&(i<-Math.PI?i+=Z:i>Math.PI&&(i-=Z),n<-Math.PI?n+=Z:n>Math.PI&&(n-=Z),i<=n?this._spherical.theta=Math.max(i,Math.min(n,this._spherical.theta)):this._spherical.theta=this._spherical.theta>(i+n)/2?Math.max(i,this._spherical.theta):Math.min(n,this._spherical.theta)),this._spherical.phi=Math.max(this.minPolarAngle,Math.min(this.maxPolarAngle,this._spherical.phi)),this._spherical.makeSafe(),this.enableDamping===!0?this.target.addScaledVector(this._panOffset,this.dampingFactor):this.target.add(this._panOffset),this.target.sub(this.cursor),this.target.clampLength(this.minTargetRadius,this.maxTargetRadius),this.target.add(this.cursor);let o=!1;if(this.zoomToCursor&&this._performCursorZoom||this.object.isOrthographicCamera)this._spherical.radius=this._clampDistance(this._spherical.radius);else{const a=this._spherical.radius;this._spherical.radius=this._clampDistance(this._spherical.radius*this._scale),o=a!=this._spherical.radius}if(V.setFromSpherical(this._spherical),V.applyQuaternion(this._quatInverse),s.copy(this.target).add(V),this.object.lookAt(this.target),this.enableDamping===!0?(this._sphericalDelta.theta*=1-this.dampingFactor,this._sphericalDelta.phi*=1-this.dampingFactor,this._panOffset.multiplyScalar(1-this.dampingFactor)):(this._sphericalDelta.set(0,0,0),this._panOffset.set(0,0,0)),this.zoomToCursor&&this._performCursorZoom){let a=null;if(this.object.isPerspectiveCamera){const c=V.length();a=this._clampDistance(c*this._scale);const l=c-a;this.object.position.addScaledVector(this._dollyDirection,l),this.object.updateMatrixWorld(),o=!!l}else if(this.object.isOrthographicCamera){const c=new v(this._mouse.x,this._mouse.y,0);c.unproject(this.object);const l=this.object.zoom;this.object.zoom=Math.max(this.minZoom,Math.min(this.maxZoom,this.object.zoom/this._scale)),this.object.updateProjectionMatrix(),o=l!==this.object.zoom;const r=new v(this._mouse.x,this._mouse.y,0);r.unproject(this.object),this.object.position.sub(r).add(c),this.object.updateMatrixWorld(),a=V.length()}else console.warn("WARNING: OrbitControls.js encountered an unknown camera type - zoom to cursor disabled."),this.zoomToCursor=!1;a!==null&&(this.screenSpacePanning?this.target.set(0,0,-1).transformDirection(this.object.matrix).multiplyScalar(a).add(this.object.position):(Yt.origin.copy(this.object.position),Yt.direction.set(0,0,-1).transformDirection(this.object.matrix),Math.abs(this.object.up.dot(Yt.direction))<zs?this.object.lookAt(this.target):(ze.setFromNormalAndCoplanarPoint(this.object.up,this.target),Yt.intersectPlane(ze,this.target))))}else if(this.object.isOrthographicCamera){const a=this.object.zoom;this.object.zoom=Math.max(this.minZoom,Math.min(this.maxZoom,this.object.zoom/this._scale)),a!==this.object.zoom&&(this.object.updateProjectionMatrix(),o=!0)}return this._scale=1,this._performCursorZoom=!1,o||this._lastPosition.distanceToSquared(this.object.position)>ie||8*(1-this._lastQuaternion.dot(this.object.quaternion))>ie||this._lastTargetPosition.distanceToSquared(this.target)>ie?(this.dispatchEvent(Ae),this._lastPosition.copy(this.object.position),this._lastQuaternion.copy(this.object.quaternion),this._lastTargetPosition.copy(this.target),!0):!1}_getAutoRotationAngle(t){return t!==null?Z/60*this.autoRotateSpeed*t:Z/60/60*this.autoRotateSpeed}_getZoomScale(t){const s=Math.abs(t*.01);return Math.pow(.95,this.zoomSpeed*s)}_rotateLeft(t){this._sphericalDelta.theta-=t}_rotateUp(t){this._sphericalDelta.phi-=t}_panLeft(t,s){V.setFromMatrixColumn(s,0),V.multiplyScalar(-t),this._panOffset.add(V)}_panUp(t,s){this.screenSpacePanning===!0?V.setFromMatrixColumn(s,1):(V.setFromMatrixColumn(s,0),V.crossVectors(this.object.up,V)),V.multiplyScalar(t),this._panOffset.add(V)}_pan(t,s){const i=this.domElement;if(this.object.isPerspectiveCamera){const n=this.object.position;V.copy(n).sub(this.target);let o=V.length();o*=Math.tan(this.object.fov/2*Math.PI/180),this._panLeft(2*t*o/i.clientHeight,this.object.matrix),this._panUp(2*s*o/i.clientHeight,this.object.matrix)}else this.object.isOrthographicCamera?(this._panLeft(t*(this.object.right-this.object.left)/this.object.zoom/i.clientWidth,this.object.matrix),this._panUp(s*(this.object.top-this.object.bottom)/this.object.zoom/i.clientHeight,this.object.matrix)):(console.warn("WARNING: OrbitControls.js encountered an unknown camera type - pan disabled."),this.enablePan=!1)}_dollyOut(t){this.object.isPerspectiveCamera||this.object.isOrthographicCamera?this._scale/=t:(console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."),this.enableZoom=!1)}_dollyIn(t){this.object.isPerspectiveCamera||this.object.isOrthographicCamera?this._scale*=t:(console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."),this.enableZoom=!1)}_updateZoomParameters(t,s){if(!this.zoomToCursor)return;this._performCursorZoom=!0;const i=this.domElement.getBoundingClientRect(),n=t-i.left,o=s-i.top,a=i.width,c=i.height;this._mouse.x=n/a*2-1,this._mouse.y=-(o/c)*2+1,this._dollyDirection.set(this._mouse.x,this._mouse.y,1).unproject(this.object).sub(this.object.position).normalize()}_clampDistance(t){return Math.max(this.minDistance,Math.min(this.maxDistance,t))}_handleMouseDownRotate(t){this._rotateStart.set(t.clientX,t.clientY)}_handleMouseDownDolly(t){this._updateZoomParameters(t.clientX,t.clientX),this._dollyStart.set(t.clientX,t.clientY)}_handleMouseDownPan(t){this._panStart.set(t.clientX,t.clientY)}_handleMouseMoveRotate(t){this._rotateEnd.set(t.clientX,t.clientY),this._rotateDelta.subVectors(this._rotateEnd,this._rotateStart).multiplyScalar(this.rotateSpeed);const s=this.domElement;this._rotateLeft(Z*this._rotateDelta.x/s.clientHeight),this._rotateUp(Z*this._rotateDelta.y/s.clientHeight),this._rotateStart.copy(this._rotateEnd),this.update()}_handleMouseMoveDolly(t){this._dollyEnd.set(t.clientX,t.clientY),this._dollyDelta.subVectors(this._dollyEnd,this._dollyStart),this._dollyDelta.y>0?this._dollyOut(this._getZoomScale(this._dollyDelta.y)):this._dollyDelta.y<0&&this._dollyIn(this._getZoomScale(this._dollyDelta.y)),this._dollyStart.copy(this._dollyEnd),this.update()}_handleMouseMovePan(t){this._panEnd.set(t.clientX,t.clientY),this._panDelta.subVectors(this._panEnd,this._panStart).multiplyScalar(this.panSpeed),this._pan(this._panDelta.x,this._panDelta.y),this._panStart.copy(this._panEnd),this.update()}_handleMouseWheel(t){this._updateZoomParameters(t.clientX,t.clientY),t.deltaY<0?this._dollyIn(this._getZoomScale(t.deltaY)):t.deltaY>0&&this._dollyOut(this._getZoomScale(t.deltaY)),this.update()}_handleKeyDown(t){let s=!1;switch(t.code){case this.keys.UP:t.ctrlKey||t.metaKey||t.shiftKey?this.enableRotate&&this._rotateUp(Z*this.keyRotateSpeed/this.domElement.clientHeight):this.enablePan&&this._pan(0,this.keyPanSpeed),s=!0;break;case this.keys.BOTTOM:t.ctrlKey||t.metaKey||t.shiftKey?this.enableRotate&&this._rotateUp(-Z*this.keyRotateSpeed/this.domElement.clientHeight):this.enablePan&&this._pan(0,-this.keyPanSpeed),s=!0;break;case this.keys.LEFT:t.ctrlKey||t.metaKey||t.shiftKey?this.enableRotate&&this._rotateLeft(Z*this.keyRotateSpeed/this.domElement.clientHeight):this.enablePan&&this._pan(this.keyPanSpeed,0),s=!0;break;case this.keys.RIGHT:t.ctrlKey||t.metaKey||t.shiftKey?this.enableRotate&&this._rotateLeft(-Z*this.keyRotateSpeed/this.domElement.clientHeight):this.enablePan&&this._pan(-this.keyPanSpeed,0),s=!0;break}s&&(t.preventDefault(),this.update())}_handleTouchStartRotate(t){if(this._pointers.length===1)this._rotateStart.set(t.pageX,t.pageY);else{const s=this._getSecondPointerPosition(t),i=.5*(t.pageX+s.x),n=.5*(t.pageY+s.y);this._rotateStart.set(i,n)}}_handleTouchStartPan(t){if(this._pointers.length===1)this._panStart.set(t.pageX,t.pageY);else{const s=this._getSecondPointerPosition(t),i=.5*(t.pageX+s.x),n=.5*(t.pageY+s.y);this._panStart.set(i,n)}}_handleTouchStartDolly(t){const s=this._getSecondPointerPosition(t),i=t.pageX-s.x,n=t.pageY-s.y,o=Math.sqrt(i*i+n*n);this._dollyStart.set(0,o)}_handleTouchStartDollyPan(t){this.enableZoom&&this._handleTouchStartDolly(t),this.enablePan&&this._handleTouchStartPan(t)}_handleTouchStartDollyRotate(t){this.enableZoom&&this._handleTouchStartDolly(t),this.enableRotate&&this._handleTouchStartRotate(t)}_handleTouchMoveRotate(t){if(this._pointers.length==1)this._rotateEnd.set(t.pageX,t.pageY);else{const i=this._getSecondPointerPosition(t),n=.5*(t.pageX+i.x),o=.5*(t.pageY+i.y);this._rotateEnd.set(n,o)}this._rotateDelta.subVectors(this._rotateEnd,this._rotateStart).multiplyScalar(this.rotateSpeed);const s=this.domElement;this._rotateLeft(Z*this._rotateDelta.x/s.clientHeight),this._rotateUp(Z*this._rotateDelta.y/s.clientHeight),this._rotateStart.copy(this._rotateEnd)}_handleTouchMovePan(t){if(this._pointers.length===1)this._panEnd.set(t.pageX,t.pageY);else{const s=this._getSecondPointerPosition(t),i=.5*(t.pageX+s.x),n=.5*(t.pageY+s.y);this._panEnd.set(i,n)}this._panDelta.subVectors(this._panEnd,this._panStart).multiplyScalar(this.panSpeed),this._pan(this._panDelta.x,this._panDelta.y),this._panStart.copy(this._panEnd)}_handleTouchMoveDolly(t){const s=this._getSecondPointerPosition(t),i=t.pageX-s.x,n=t.pageY-s.y,o=Math.sqrt(i*i+n*n);this._dollyEnd.set(0,o),this._dollyDelta.set(0,Math.pow(this._dollyEnd.y/this._dollyStart.y,this.zoomSpeed)),this._dollyOut(this._dollyDelta.y),this._dollyStart.copy(this._dollyEnd);const a=(t.pageX+s.x)*.5,c=(t.pageY+s.y)*.5;this._updateZoomParameters(a,c)}_handleTouchMoveDollyPan(t){this.enableZoom&&this._handleTouchMoveDolly(t),this.enablePan&&this._handleTouchMovePan(t)}_handleTouchMoveDollyRotate(t){this.enableZoom&&this._handleTouchMoveDolly(t),this.enableRotate&&this._handleTouchMoveRotate(t)}_addPointer(t){this._pointers.push(t.pointerId)}_removePointer(t){delete this._pointerPositions[t.pointerId];for(let s=0;s<this._pointers.length;s++)if(this._pointers[s]==t.pointerId){this._pointers.splice(s,1);return}}_isTrackingPointer(t){for(let s=0;s<this._pointers.length;s++)if(this._pointers[s]==t.pointerId)return!0;return!1}_trackPointer(t){let s=this._pointerPositions[t.pointerId];s===void 0&&(s=new B,this._pointerPositions[t.pointerId]=s),s.set(t.pageX,t.pageY)}_getSecondPointerPosition(t){const s=t.pointerId===this._pointers[0]?this._pointers[1]:this._pointers[0];return this._pointerPositions[s]}_customWheelEvent(t){const s=t.deltaMode,i={clientX:t.clientX,clientY:t.clientY,deltaY:t.deltaY};switch(s){case 1:i.deltaY*=16;break;case 2:i.deltaY*=100;break}return t.ctrlKey&&!this._controlActive&&(i.deltaY*=10),i}}function ks(e){this.enabled!==!1&&(this._pointers.length===0&&(this.domElement.setPointerCapture(e.pointerId),this.domElement.addEventListener("pointermove",this._onPointerMove),this.domElement.addEventListener("pointerup",this._onPointerUp)),!this._isTrackingPointer(e)&&(this._addPointer(e),e.pointerType==="touch"?this._onTouchStart(e):this._onMouseDown(e)))}function Os(e){this.enabled!==!1&&(e.pointerType==="touch"?this._onTouchMove(e):this._onMouseMove(e))}function Ns(e){switch(this._removePointer(e),this._pointers.length){case 0:this.domElement.releasePointerCapture(e.pointerId),this.domElement.removeEventListener("pointermove",this._onPointerMove),this.domElement.removeEventListener("pointerup",this._onPointerUp),this.dispatchEvent(Ze),this.state=k.NONE;break;case 1:const t=this._pointers[0],s=this._pointerPositions[t];this._onTouchStart({pointerId:t,pageX:s.x,pageY:s.y});break}}function Bs(e){let t;switch(e.button){case 0:t=this.mouseButtons.LEFT;break;case 1:t=this.mouseButtons.MIDDLE;break;case 2:t=this.mouseButtons.RIGHT;break;default:t=-1}switch(t){case yt.DOLLY:if(this.enableZoom===!1)return;this._handleMouseDownDolly(e),this.state=k.DOLLY;break;case yt.ROTATE:if(e.ctrlKey||e.metaKey||e.shiftKey){if(this.enablePan===!1)return;this._handleMouseDownPan(e),this.state=k.PAN}else{if(this.enableRotate===!1)return;this._handleMouseDownRotate(e),this.state=k.ROTATE}break;case yt.PAN:if(e.ctrlKey||e.metaKey||e.shiftKey){if(this.enableRotate===!1)return;this._handleMouseDownRotate(e),this.state=k.ROTATE}else{if(this.enablePan===!1)return;this._handleMouseDownPan(e),this.state=k.PAN}break;default:this.state=k.NONE}this.state!==k.NONE&&this.dispatchEvent(he)}function Fs(e){switch(this.state){case k.ROTATE:if(this.enableRotate===!1)return;this._handleMouseMoveRotate(e);break;case k.DOLLY:if(this.enableZoom===!1)return;this._handleMouseMoveDolly(e);break;case k.PAN:if(this.enablePan===!1)return;this._handleMouseMovePan(e);break}}function Hs(e){this.enabled===!1||this.enableZoom===!1||this.state!==k.NONE||(e.preventDefault(),this.dispatchEvent(he),this._handleMouseWheel(this._customWheelEvent(e)),this.dispatchEvent(Ze))}function Us(e){this.enabled!==!1&&this._handleKeyDown(e)}function js(e){switch(this._trackPointer(e),this._pointers.length){case 1:switch(this.touches.ONE){case xt.ROTATE:if(this.enableRotate===!1)return;this._handleTouchStartRotate(e),this.state=k.TOUCH_ROTATE;break;case xt.PAN:if(this.enablePan===!1)return;this._handleTouchStartPan(e),this.state=k.TOUCH_PAN;break;default:this.state=k.NONE}break;case 2:switch(this.touches.TWO){case xt.DOLLY_PAN:if(this.enableZoom===!1&&this.enablePan===!1)return;this._handleTouchStartDollyPan(e),this.state=k.TOUCH_DOLLY_PAN;break;case xt.DOLLY_ROTATE:if(this.enableZoom===!1&&this.enableRotate===!1)return;this._handleTouchStartDollyRotate(e),this.state=k.TOUCH_DOLLY_ROTATE;break;default:this.state=k.NONE}break;default:this.state=k.NONE}this.state!==k.NONE&&this.dispatchEvent(he)}function Is(e){switch(this._trackPointer(e),this.state){case k.TOUCH_ROTATE:if(this.enableRotate===!1)return;this._handleTouchMoveRotate(e),this.update();break;case k.TOUCH_PAN:if(this.enablePan===!1)return;this._handleTouchMovePan(e),this.update();break;case k.TOUCH_DOLLY_PAN:if(this.enableZoom===!1&&this.enablePan===!1)return;this._handleTouchMoveDollyPan(e),this.update();break;case k.TOUCH_DOLLY_ROTATE:if(this.enableZoom===!1&&this.enableRotate===!1)return;this._handleTouchMoveDollyRotate(e),this.update();break;default:this.state=k.NONE}}function Ws(e){this.enabled!==!1&&e.preventDefault()}function Vs(e){e.key==="Control"&&(this._controlActive=!0,this.domElement.getRootNode().addEventListener("keyup",this._interceptControlUp,{passive:!0,capture:!0}))}function Ys(e){e.key==="Control"&&(this._controlActive=!1,this.domElement.getRootNode().removeEventListener("keyup",this._interceptControlUp,{passive:!0,capture:!0}))}class Xe extends fs{constructor(t=document.createElement("div")){super(),this.isCSS2DObject=!0,this.element=t,this.element.style.position="absolute",this.element.style.userSelect="none",this.element.setAttribute("draggable",!1),this.center=new B(.5,.5),this.addEventListener("removed",function(){this.traverse(function(s){s.element&&s.element instanceof s.element.ownerDocument.defaultView.Element&&s.element.parentNode!==null&&s.element.remove()})})}copy(t,s){return super.copy(t,s),this.element=t.element.cloneNode(!0),this.center=t.center,this}}const Mt=new v,Le=new Ke,ke=new Ke,Oe=new v,Ne=new v;class $s{constructor(t={}){const s=this;let i,n,o,a;const c={objects:new WeakMap},l=t.element!==void 0?t.element:document.createElement("div");l.style.overflow="hidden",this.domElement=l,this.sortObjects=!0,this.getSize=function(){return{width:i,height:n}},this.render=function(p,u){p.matrixWorldAutoUpdate===!0&&p.updateMatrixWorld(),u.parent===null&&u.matrixWorldAutoUpdate===!0&&u.updateMatrixWorld(),Le.copy(u.matrixWorldInverse),ke.multiplyMatrices(u.projectionMatrix,Le),h(p,p,u),this.sortObjects&&d(p)},this.setSize=function(p,u){i=p,n=u,o=i/2,a=n/2,l.style.width=p+"px",l.style.height=u+"px"};function r(p){p.isCSS2DObject&&(p.element.style.display="none");for(let u=0,g=p.children.length;u<g;u++)r(p.children[u])}function h(p,u,g){if(p.visible===!1){r(p);return}if(p.isCSS2DObject){Mt.setFromMatrixPosition(p.matrixWorld),Mt.applyMatrix4(ke);const M=Mt.z>=-1&&Mt.z<=1&&p.layers.test(g.layers)===!0,_=p.element;_.style.display=M===!0?"":"none",M===!0&&(p.onBeforeRender(s,u,g),_.style.transform="translate("+-100*p.center.x+"%,"+-100*p.center.y+"%)translate("+(Mt.x*o+o)+"px,"+(-Mt.y*a+a)+"px)",_.parentNode!==l&&l.appendChild(_),p.onAfterRender(s,u,g));const y={distanceToCameraSquared:f(g,p)};c.objects.set(p,y)}for(let M=0,_=p.children.length;M<_;M++)h(p.children[M],u,g)}function f(p,u){return Oe.setFromMatrixPosition(p.matrixWorld),Ne.setFromMatrixPosition(u.matrixWorld),Oe.distanceToSquared(Ne)}function m(p){const u=[];return p.traverseVisible(function(g){g.isCSS2DObject&&u.push(g)}),u}function d(p){const u=m(p).sort(function(M,_){if(M.renderOrder!==_.renderOrder)return _.renderOrder-M.renderOrder;const y=c.objects.get(M).distanceToCameraSquared,w=c.objects.get(_).distanceToCameraSquared;return y-w}),g=u.length;for(let M=0,_=u.length;M<_;M++)u[M].element.style.zIndex=g-M}}}function Be(e){return new dt({uniforms:{uOpacity:{value:e},uTime:{value:0}},vertexShader:`
|
|
106
|
+
uniform float uTime;
|
|
107
|
+
attribute float particleSize;
|
|
108
|
+
attribute float particleHeat;
|
|
109
|
+
varying vec3 vColor;
|
|
110
|
+
varying float vHeat;
|
|
111
|
+
void main() {
|
|
112
|
+
vColor = color;
|
|
113
|
+
vHeat = particleHeat;
|
|
114
|
+
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
|
|
115
|
+
float pulse = 1.0 + sin(uTime * 2.1 + position.x * 0.06 + position.y * 0.04) * 0.08 * (0.25 + particleHeat);
|
|
116
|
+
float perspective = clamp(145.0 / -mvPosition.z, 0.78, 1.62);
|
|
117
|
+
gl_PointSize = clamp(particleSize * pulse * perspective, 1.45, 38.0);
|
|
118
|
+
gl_Position = projectionMatrix * mvPosition;
|
|
119
|
+
}
|
|
120
|
+
`,fragmentShader:`
|
|
121
|
+
uniform float uOpacity;
|
|
122
|
+
varying vec3 vColor;
|
|
123
|
+
varying float vHeat;
|
|
124
|
+
void main() {
|
|
125
|
+
vec2 uv = gl_PointCoord - vec2(0.5);
|
|
126
|
+
float radius = length(uv);
|
|
127
|
+
if (radius > 0.5) discard;
|
|
128
|
+
float core = smoothstep(0.22, 0.0, radius);
|
|
129
|
+
float halo = smoothstep(0.5, 0.05, radius) * 0.54;
|
|
130
|
+
float alpha = min(0.98, (core + halo) * uOpacity * (0.62 + vHeat * 0.58));
|
|
131
|
+
vec3 color = vColor * (1.08 + core * 2.18 + vHeat * 0.78);
|
|
132
|
+
gl_FragColor = vec4(color, alpha);
|
|
133
|
+
}
|
|
134
|
+
`,vertexColors:!0,transparent:!0,depthWrite:!1,blending:ut})}function Fe(){return new dt({uniforms:{uTime:{value:0}},vertexShader:`
|
|
135
|
+
uniform float uTime;
|
|
136
|
+
attribute float particleSize;
|
|
137
|
+
attribute float particleHeat;
|
|
138
|
+
varying vec3 vColor;
|
|
139
|
+
varying float vHeat;
|
|
140
|
+
void main() {
|
|
141
|
+
vColor = color;
|
|
142
|
+
vHeat = particleHeat;
|
|
143
|
+
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
|
|
144
|
+
float flicker = 1.0 + sin(uTime * 2.4 + position.x * 0.11 + position.y * 0.08) * 0.05;
|
|
145
|
+
float perspective = clamp(150.0 / -mvPosition.z, 0.86, 1.95);
|
|
146
|
+
gl_PointSize = clamp(particleSize * flicker * perspective, 2.0, 70.0);
|
|
147
|
+
gl_Position = projectionMatrix * mvPosition;
|
|
148
|
+
}
|
|
149
|
+
`,fragmentShader:`
|
|
150
|
+
varying vec3 vColor;
|
|
151
|
+
varying float vHeat;
|
|
152
|
+
void main() {
|
|
153
|
+
vec2 uv = gl_PointCoord - vec2(0.5);
|
|
154
|
+
float radius = length(uv);
|
|
155
|
+
if (radius > 0.5) discard;
|
|
156
|
+
float core = smoothstep(0.18, 0.0, radius);
|
|
157
|
+
float corona = smoothstep(0.5, 0.04, radius);
|
|
158
|
+
float alpha = clamp(core + corona * 0.42, 0.0, 1.0) * clamp(0.24 + vHeat, 0.0, 0.78);
|
|
159
|
+
vec3 color = vColor * (1.16 + core * 2.25 + vHeat * 1.1);
|
|
160
|
+
gl_FragColor = vec4(color, alpha);
|
|
161
|
+
}
|
|
162
|
+
`,vertexColors:!0,transparent:!0,depthWrite:!1,depthTest:!1,blending:ut})}function Ks(e,t,s,i,n,o,a={edgeDensity:"sparse",linkDirection:"all",minLinkWeight:0}){const c=new Map(t.map(r=>[r.id,r])),l=new Map(t.map(r=>[r.id,r.total]));return e.filter(r=>{if(!s.has(r.source)||!s.has(r.target))return!1;if(o?.has(r.id))return!0;if((r.weight||0)<a.minLinkWeight)return!1;const h=c.get(r.source),f=c.get(r.target);if(!h||!f||a.linkDirection==="cross-cluster"&&h.cluster===f.cluster||i&&a.linkDirection==="outbound"&&r.source!==i||i&&a.linkDirection==="inbound"&&r.target!==i)return!1;if(i)return r.source===i||r.target===i;if(a.linkDirection==="outbound"||a.linkDirection==="inbound")return!1;if(a.edgeDensity==="dense")return!0;const m=a.edgeDensity==="balanced"?-18:0;if(n==="Radar")return(l.get(r.source)||0)<=2||(l.get(r.target)||0)<=2||a.edgeDensity==="balanced";if(n==="Today")return(l.get(r.source)||0)>Math.max(4,8+m)||(l.get(r.target)||0)>Math.max(4,8+m);const d=l.get(r.source)||0,p=l.get(r.target)||0;return a.edgeDensity==="balanced"?d>24&&p>10||d+p>42&&He(r.id,19)>.64:d>44&&p>18||d+p>72&&He(r.id,19)>.82})}function Qs(e,t,s){const i=new Map(t.map(c=>[c.id,c])),n=new Map;for(const c of e){if(!s.has(c.source)||!s.has(c.target))continue;const l=i.get(c.source),r=i.get(c.target);if(!l||!r||l.cluster===r.cluster)continue;const[h,f]=[l.cluster,r.cluster].sort(),m=`${h}:${f}`,d=n.get(m)||{fromId:h,toId:f,count:0,weight:0};d.count+=1,n.set(m,d)}const o=[...n.values()].sort((c,l)=>l.count-c.count).slice(0,12),a=Math.max(1,...o.map(c=>c.count));return o.map(c=>({...c,weight:Math.sqrt(c.count/a)}))}function He(e,t){let s=2166136261+t*1013;for(let i=0;i<e.length;i+=1)s^=e.charCodeAt(i),s=Math.imul(s,16777619);return(s>>>0)%1e4/1e4}function Ue(e){const t=Math.max(0,e.visibleNodes),s=Math.max(t,e.totalNodes),i=Math.max(0,e.visibleLinks),n=e.devicePixelRatio??1,o=e.hardwareConcurrency??8;return e.reducedMotion||s>=1e5||t>=6e3||i>=18e3||o<=4||n>=3&&t>=4e3?{tier:"safe",label:"100K safe",pixelRatioCap:1,antialias:!1,bloomStrength:.18,bloomRadius:.26,bloomThreshold:.28,particleScale:.45,tetherScale:.3,organicVeinScale:.44,maxNebulaTetherVertices:9e3,maxTransitionTetherVertices:7e3}:s>=1e4||t>=3e3||i>=9e3?{tier:"balanced",label:"10K balanced",pixelRatioCap:1.35,antialias:!0,bloomStrength:.28,bloomRadius:.32,bloomThreshold:.24,particleScale:.7,tetherScale:.55,organicVeinScale:.68,maxNebulaTetherVertices:18e3,maxTransitionTetherVertices:14e3}:{tier:"cinematic",label:"Cinematic",pixelRatioCap:2,antialias:!0,bloomStrength:.38,bloomRadius:.38,bloomThreshold:.22,particleScale:1,tetherScale:1,organicVeinScale:1,maxNebulaTetherVertices:42e3,maxTransitionTetherVertices:26e3}}function q(e,t,s=0){return e<=0||t<=0?s:Math.max(s,Math.round(e*Math.min(1,t)))}function kt(e,t){if(t>=1)return!0;if(t<=0)return!1;const s=Math.max(1,Math.round(1/t));return e%s===0}const ne=2600;function Bi({mode:e,snapshot:t,nodes:s,selectedNode:i,clusterLabels:n,emphasisLinkIds:o,highlightedNodeIds:a,liveEvents:c=[],edgeDensity:l="sparse",linkDirection:r="all",minLinkWeight:h=0,layoutMode:f="atlas",quietMotion:m=!1,pinnedNodeIds:d=[],onSelectNode:p,onSelectCluster:u}){const g=lt.useRef(null),M=lt.useRef(null),_=lt.useRef({onSelectNode:p,onSelectCluster:u}),y=i?.id||null;lt.useEffect(()=>{_.current={onSelectNode:p,onSelectCluster:u}},[u,p]);const w=lt.useMemo(()=>new Set(s.map(E=>E.id)),[s]),T=lt.useMemo(()=>Ks(t.links,t.nodes,w,y,e,o,{edgeDensity:l,linkDirection:r,minLinkWeight:h}),[l,o,r,h,e,w,y,t.links,t.nodes]),C=lt.useMemo(()=>Qs(t.links,t.nodes,w),[w,t.links,t.nodes]);return lt.useEffect(()=>{if(!g.current)return;const E=Zs(g.current,s.length,t.totals.nodes,T.length,P=>_.current.onSelectNode(P),P=>_.current.onSelectCluster(P));return M.current=E,()=>{E.dispose(),M.current=null}},[]),lt.useEffect(()=>{M.current?.update(s,T,t.totals.nodes,t.totals.links,y,e,n,C,o,a,c,f,d,m)},[C,n,o,a,f,c,e,s,d,m,y,t.totals.links,t.totals.nodes,T]),os.jsx("div",{ref:g,className:"atlas-canvas"})}function Zs(e,t,s,i,n,o){const a=new ms;a.background=new L("#080a10"),a.fog=new gs("#080a10",.014);const c=window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches??!1,l=navigator.hardwareConcurrency??8;let r=Ue({visibleNodes:t,totalNodes:s,visibleLinks:i,reducedMotion:c,devicePixelRatio:window.devicePixelRatio,hardwareConcurrency:l});const h=new bs(54,e.clientWidth/e.clientHeight,.1,900);h.position.set(0,0,104);const f=new _s({antialias:r.antialias,alpha:!0});f.setPixelRatio(Math.min(window.devicePixelRatio,r.pixelRatioCap)),f.setSize(e.clientWidth,e.clientHeight),f.outputColorSpace=Ms,f.toneMapping=xs,f.toneMappingExposure=1.34,e.appendChild(f.domElement);const m=new Ds(f);m.setPixelRatio(Math.min(window.devicePixelRatio,r.pixelRatioCap)),m.setSize(e.clientWidth,e.clientHeight),m.addPass(new Rs(a,h));const d=new vt(new B(e.clientWidth,e.clientHeight),r.bloomStrength,r.bloomRadius,r.bloomThreshold);m.addPass(d);const p=D=>{const H=Math.min(window.devicePixelRatio,D.pixelRatioCap);f.setPixelRatio(H),m.setPixelRatio(H),d.strength=D.bloomStrength,d.radius=D.bloomRadius,d.threshold=D.bloomThreshold,e.dataset.renderQuality=D.tier,e.dataset.renderQualityLabel=D.label,e.dataset.renderPixelRatioCap=String(D.pixelRatioCap),e.dataset.renderParticleScale=D.particleScale.toFixed(2),e.dataset.renderTetherScale=D.tetherScale.toFixed(2)};p(r);const u=new $s;u.setSize(e.clientWidth,e.clientHeight),u.domElement.className="atlas-label-layer",e.appendChild(u.domElement);const g=document.createElement("div");g.className="atlas-selection-pin",g.setAttribute("aria-hidden","true"),e.appendChild(g);const M=document.createElement("div");M.className="atlas-node-tooltip",M.setAttribute("role","status"),e.appendChild(M);const _=new Ls(h,f.domElement);_.enableDamping=!0,_.dampingFactor=.055,_.rotateSpeed=.28,_.zoomSpeed=.92,_.panSpeed=.42,_.enablePan=!0,_.screenSpacePanning=!0,_.minDistance=10,_.maxDistance=220,_.minPolarAngle=Math.PI*.18,_.maxPolarAngle=Math.PI*.82,_.minAzimuthAngle=-Math.PI*.44,_.maxAzimuthAngle=Math.PI*.44,"zoomToCursor"in _&&(_.zoomToCursor=!0),_.target.set(-6,0,0),_.update();const y=new ys("#8296ff",.28);a.add(y);const w=new ws("#ffcf85",3.2,260);w.position.set(-12,24,38),a.add(w);const T=new vs;T.scale.set(1.08,1.04,1),a.add(T);const C=new Map,E=new Map;let P=new U,x=Be(1),S=new Vt(P,x);T.add(S);let z=Be(.46),F=new Vt(new U,z);T.add(F);let A=new At(new U,new zt({vertexColors:!0,transparent:!0,opacity:.17,blending:ut,depthTest:!1,depthWrite:!1}));T.add(A);let j=new At(new U,new zt({vertexColors:!0,transparent:!0,opacity:.16,blending:ut,depthTest:!1,depthWrite:!1}));T.add(j);let W=new At(new U,new zt({vertexColors:!0,transparent:!0,opacity:.82,blending:ut,depthTest:!1,depthWrite:!1}));T.add(W);let K=new U,N=Fe(),I=new Vt(K,N);I.renderOrder=5,T.add(I);let X=new U,Y=new At(X,new zt({vertexColors:!0,transparent:!0,opacity:.92,blending:ut,depthTest:!1,depthWrite:!1}));Y.renderOrder=4,T.add(Y);let it=new At(new U,new zt({vertexColors:!0,transparent:!0,opacity:.84,blending:ut,depthTest:!1,depthWrite:!1}));it.renderOrder=6,T.add(it);let nt=new Vt(new U,Fe());nt.renderOrder=7,T.add(nt);const $=new Map,Tt=new Map,tt=new Map;let ct=[],Q=new Map,St=[],Pt="Whole Mind",ht=null,Gt,qt,Ut=[],ue=[],de={visuals:new Map},gt=!1;const Jt=new v(-6,0,0),te=new ce(new v(-82,-48,-35),new v(62,46,35));let Ct=[],ot=null,jt=!1,ee=0,It=!1,at=0,Et="Whole Mind",pe=null,Dt=!1,rt="far",fe=!1,me=null,ge=0,be=!1;e.dataset.zoomTier=rt,e.dataset.motionScale="1",e.dataset.motionMode="cinematic",e.dataset.morphModel="pressure-shove",e.dataset.nebulaAnchorMode="node-tethered";const _e=D=>{ot={x:D.clientX,y:D.clientY},jt=!1,f.domElement.classList.add("is-dragging-atlas")},Me=D=>{if(ot&&Math.hypot(D.clientX-ot.x,D.clientY-ot.y)>7){jt=!0,M.classList.remove("visible"),f.domElement.classList.remove("is-picking-node");return}cancelAnimationFrame(ee),ee=requestAnimationFrame(()=>{const H=We(D,h,f,S,Ct,24);if(!H){f.domElement.classList.remove("is-picking-node"),M.classList.remove("visible");return}f.domElement.classList.add("is-picking-node"),xi(M,H.node,D,e)})},xe=()=>{f.domElement.classList.remove("is-picking-node"),M.classList.remove("visible")},ye=D=>{const H=ot&&Math.hypot(D.clientX-ot.x,D.clientY-ot.y)>7;if(ot=null,f.domElement.classList.remove("is-dragging-atlas"),H||jt)return;const et=We(D,h,f,S,Ct,30);if(!et){n(null);return}n(et.node)},we=()=>{ot=null,jt=!1,f.domElement.classList.remove("is-dragging-atlas","is-picking-node"),M.classList.remove("visible")};f.domElement.addEventListener("pointerdown",_e),f.domElement.addEventListener("pointermove",Me),f.domElement.addEventListener("pointerleave",xe),f.domElement.addEventListener("pointerup",ye),f.domElement.addEventListener("pointercancel",we);const ve=new ResizeObserver(()=>{const D=e.clientWidth,H=e.clientHeight;h.aspect=D/H,h.updateProjectionMatrix(),f.setSize(D,H),m.setSize(D,H),u.setSize(D,H)});ve.observe(e);const Te=()=>{if(be)return;at+=1;const D=Et==="Today"?.006:Et==="Replay"?.011:.0035,H=_.getDistance(),et=gi(H,It,gt,c||Dt);if(e.dataset.motionScale=et.toFixed(2),e.dataset.motionMode=Dt?"quiet":"cinematic",T.rotation.y=R.lerp(T.rotation.y,Math.sin(at*D)*.018*et,.08),T.rotation.x=R.lerp(T.rotation.x,Math.sin(at*D*.72)*.014*et,.08),x.uniforms.uTime.value=at/60,x.uniforms.uOpacity.value=Et==="Radar"?.78:1,z.uniforms.uTime.value=at/60,z.uniforms.uOpacity.value=Et==="Radar"?.66:.94,N.uniforms.uTime.value=at/60,gt){if(gt=je(performance.now(),tt,$,St,Pt,ht,qt,Gt,S,F,A,j,W,Q,r),e.dataset.morphTransition=gt?"on":"off",!gt){const bt=$e([...$.values()],Q,Pt,ue,de,r);le(F,A,bt)}Ct=Ve([...$.values()],Q,ht,Gt),$t(T,E,Ut,$,Q,ht,rt,_.target,h,S,e)}hi(ct,Q,$,Tt,I,Y),ni(it,ht,Q,$,at,H,et,e),oi(nt,St,$,Q,ht,qt,at,H,et,e),e.dataset.nebulaTethers=String(Ft(A.geometry)),It&&_.target.lerp(Jt,.1),_.update(),Si(h,_,Jt,te);const Wt=mi(H,It);Wt!==rt?(rt=Wt,e.dataset.zoomTier=rt,$t(T,E,Ut,$,Q,ht,rt,_.target,h,S,e)):rt==="near"&&at%20===0&&$t(T,E,Ut,$,Q,ht,rt,_.target,h,S,e),yi(g,pe,Ct,h,S,e),m.render(),u.render(a,h),wi(e),ge=requestAnimationFrame(Te)};return Te(),{update(D,H,et,Wt,G,bt,es,Se,Pe,se,ss=[],is="atlas",Ce=[],ns=!1){Et=bt,pe=G,Dt=ns,e.dataset.motionMode=Dt?"quiet":"cinematic",ct=ss,r=Ue({visibleNodes:D.length,totalNodes:et,visibleLinks:Math.max(H.length,Wt),reducedMotion:c||Dt,devicePixelRatio:window.devicePixelRatio,hardwareConcurrency:l}),p(r);const Rt=Ei(D,is);fi(T,C,es,o,Rt),$.clear();for(const st of D)$.set(st.id,st);Tt.clear();for(const st of H)Tt.set(st.id,st);St=H,Pt=bt,ht=G,Gt=se,qt=Pe,Ut=Ce,ue=Se,de=Rt;const _t=new Map;for(const st of D)_t.set(st.id,Je(st,Rt));if(Xs(tt,D,_t,Q,Rt),gt=!0,e.dataset.morphTransition="on",je(performance.now(),tt,$,H,bt,G,Pe,se,S,F,A,j,W,Q,r),$t(T,E,Ce,$,Q,G,rt,_.target,h,S,e),Ct=Ve(D,Q,G,se),Ti(te,_t),(!fe||G!==me)&&vi(h,_,Jt,te,_t,G),fe=!0,me=G,It=!!(G&&_t.has(G)),!gt){const st=$e(D,_t,bt,Se,Rt,r);le(F,A,st),e.dataset.morphTransition="off"}},dispose(){be=!0,cancelAnimationFrame(ge),ve.disconnect(),f.domElement.removeEventListener("pointerdown",_e),f.domElement.removeEventListener("pointermove",Me),f.domElement.removeEventListener("pointerleave",xe),f.domElement.removeEventListener("pointerup",ye),f.domElement.removeEventListener("pointercancel",we),cancelAnimationFrame(ee),P.dispose(),x.dispose(),z.dispose(),A.geometry.dispose(),A.material.dispose(),j.geometry.dispose(),j.material.dispose(),W.geometry.dispose(),W.material.dispose(),I.geometry.dispose(),N.dispose(),Y.geometry.dispose(),Y.material.dispose(),it.geometry.dispose(),it.material.dispose(),nt.geometry.dispose(),nt.material.dispose(),m.dispose(),f.dispose(),e.replaceChildren()}}}function Xs(e,t,s,i,n){const o=performance.now(),a=640,c=new Set(t.map(l=>l.id));for(const l of t){const r=s.get(l.id);if(!r)continue;const h=e.get(l.id),f=!i.has(l.id)&&!h,m=i.get(l.id)?.clone()||h?.current.clone()||Gs(l,n,r),d=m.distanceTo(r);e.set(l.id,{node:l,from:m,to:r.clone(),current:m.clone(),entering:f,exiting:!1,startedAt:o,duration:f?620:R.clamp(280+d*4.2,340,a)})}for(const[l,r]of[...e]){if(c.has(l)||r.exiting)continue;const h=i.get(l)?.clone()||r.current.clone();e.set(l,{...r,from:h,to:qs(r.node,h,n),current:h.clone(),entering:!1,exiting:!0,startedAt:o,duration:560})}}function Gs(e,t,s){const i=ft(e.cluster,t),n=new v(...i.center),o=new v((b(e.id,41)-.5)*Math.min(5.8,i.spread[0]*.26),(b(e.id,42)-.5)*Math.min(4.2,i.spread[1]*.32),(b(e.id,43)-.5)*Math.min(5.2,i.spread[2]*.28));return n.clone().lerp(s,.18).add(o)}function qs(e,t,s){const i=ft(e.cluster,s);return new v(...i.center).lerp(t,.16).add(new v((b(e.id,91)-.5)*1.7,(b(e.id,92)-.5)*1.2,(b(e.id,93)-.5)*1.8))}function je(e,t,s,i,n,o,a,c,l,r,h,f,m,d,p){const u=[],g=[],M=[],_=[],y=[];d.clear();let w=!1;const T=ei(t,e);for(const[P,x]of[...t]){const S=R.clamp((e-x.startedAt)/x.duration,0,1),z=re(S),F=Lt(x.from,T),A=F.length(),j=Math.min(.2,A/80),W=T.length&&!x.entering&&!x.exiting?R.clamp((S-j)/Math.max(.2,1-j),0,1):S,K=x.entering?ci(S):x.exiting?re(W):Js(S,A,T.length);if(x.current.copy(x.from).lerp(x.to,K),!x.entering&&!x.exiting){const tt=Lt(x.current,T),ct=Math.min(1,Math.max(A,tt.length())/18),Q=Math.pow(Math.sin(S*Math.PI),.72),St=Math.sin(S*Math.PI*2)*.26*ct,Pt=F.multiplyScalar((1.35+ct*1.95)*Q);x.current.add(Pt),x.current.add(tt.multiplyScalar(.88+ct*1.1+St))}else if(x.entering){const tt=Math.sin(S*Math.PI),ct=x.to.clone().sub(x.from).normalize();x.current.addScaledVector(ct,-Math.sin(S*Math.PI)*2.25),x.current.add(Lt(x.current,T).multiplyScalar(1.42*tt))}else if(x.exiting){const tt=Math.sin(S*Math.PI);x.current.add(Lt(x.current,T).multiplyScalar(1.32*tt))}if(S<1&&(w=!0),x.exiting&&S>=1){t.delete(P);continue}const N=x.exiting?1-z:z,I=s.get(P)||x.node;d.set(P,x.current.clone()),y.push(P),u.push(x.current.x,x.current.y,x.current.z);const X=!!c?.has(P),Y=o===P?1.65:X?1.32:1,it=new L(J(I)),nt=Xt(I.cluster),$=(n==="Today"?.32+I.heat*.82:.68+I.heat*.42+(X?.32:0))*(.72+nt*.36)*(x.exiting?Math.max(.08,N):.28+N*.72);g.push(it.r*$,it.g*$,it.b*$);const Tt=x.entering?.5+Math.sin(S*Math.PI)*.8:1;M.push((3.2+I.size*.48+I.heat*6.6)*Y*nt*Tt*(x.exiting?Math.max(.08,N):.24+N*.76)),_.push(Math.min(1.35,(I.heat+(X?.35:0))*nt*(.25+N*.75)))}const C=new U;C.setAttribute("position",new O(u,3)),C.setAttribute("color",new O(g,3)),C.setAttribute("particleSize",new O(M,1)),C.setAttribute("particleHeat",new O(_,1)),C.userData.nodeIds=y,l.geometry.dispose(),l.geometry=C;const E=si(t,d,n,T,p);return le(r,h,E),ii(i,s,d,o,a,f,m),w}function Js(e,t,s){if(!s)return re(e);const i=R.clamp(t/26,0,1),n=R.lerp(.34,.1,i),o=R.clamp((e-n)/Math.max(.18,1-n),0,1),a=ti(o,1.08+i*.28);return R.clamp(a,0,1)}function ti(e,t=1.70158){const s=e-1;return 1+s*s*((t+1)*s+t)}function ei(e,t){const s=new Map;for(const i of e.values()){if(!i.entering&&!i.exiting)continue;const n=R.clamp((t-i.startedAt)/i.duration,0,1),o=Math.sin(n*Math.PI);if(o<=.001)continue;const a=`${i.exiting?"out":"in"}:${i.node.cluster}`,c=i.exiting?i.from:i.to,l=.7+Math.min(1.4,Math.sqrt(i.node.total+1)/5),r=s.get(a)||{id:a,center:new v,strength:0,radius:i.exiting?24:38,pull:i.exiting,count:0};r.center.add(c),r.strength+=o*l,r.count+=1,r.radius=Math.max(r.radius,(i.exiting?22:36)+Math.min(42,Math.sqrt(r.count)*3.8)),s.set(a,r)}return[...s.values()].map(i=>({id:i.id,center:i.center.multiplyScalar(1/Math.max(1,i.count)),strength:Math.min(i.pull?30:54,i.strength*(i.pull?.82:1.12)),radius:i.radius*(i.pull?1.12:1.04),pull:i.pull})).sort((i,n)=>n.strength-i.strength).slice(0,18)}function Lt(e,t){const s=new v;for(const i of t){const n=e.clone().sub(i.center),o=Math.max(.001,n.length());if(o>i.radius)continue;const a=Math.pow(1-o/i.radius,2),c=i.pull?n.normalize().multiplyScalar(-1):n.normalize();s.add(c.multiplyScalar(i.strength*a))}return s}function si(e,t,s,i,n){const o=q(s==="Focus"?5:7,n.particleScale,2),a=[],c=[],l=[],r=[],h=[],f=[],m=new Map;for(const[d,p]of e){const u=t.get(d);if(!u)continue;const g=m.get(p.node.cluster)||[];(g.length<120||b(d,111)>.74)&&g.push(u),m.set(p.node.cluster,g)}for(const[d,p]of e){const u=t.get(d);if(!u)continue;const g=p.node,M=new L(J(g)),_=Xt(g.cluster),y=R.clamp((performance.now()-p.startedAt)/p.duration,0,1),w=p.exiting?1-y:p.entering?Math.max(.18,y):1,T=Math.max(2,Math.round(o*Math.min(1.3,_)));for(let C=0;C<T;C+=1){const E=`${d}:motion-dust:${C}`,P=b(E,1)*Math.PI*2,x=1.4+b(E,2)*(5.2+g.heat*6),S=new v(u.x+Math.cos(P)*x,u.y+Math.sin(P)*x*.65,u.z+(b(E,3)-.5)*x*1.4);S.add(Lt(S,i).multiplyScalar(.42)),a.push(S.x,S.y,S.z);const z=(.44+b(E,4)*.54)*w;c.push(M.r*z,M.g*z,M.b*z),l.push((.72+b(E,5)*1.45+(p.entering?Math.sin(y*Math.PI)*1.7:0))*_*Math.max(.12,w)),r.push((.18+g.heat*.44+b(E,6)*.24)*Math.max(.16,w)),C%2===0&&(Ot(a,c,l,r,u,S,M,E,q(2,n.particleScale,1)),C%3===0&&kt(C,n.tetherScale)&&Bt(h,3,n.maxTransitionTetherVertices)&&Nt(h,f,u,S,M,E,.105,3))}}for(const d of i.slice(0,18)){const p=new L(d.pull?"#ff806d":"#ffe7a3"),u=d.id.split(":")[1]||"",g=m.get(u)||[],M=g.length?g[Math.floor(b(d.id,88)*g.length)%g.length]:d.center,_=q(18,n.particleScale,6);for(let y=0;y<_;y+=1){const w=`${d.id}:pressure:${y}`,T=b(w,1)*Math.PI*2,C=b(w,2)*d.radius*.72,E=new v(d.center.x+Math.cos(T)*C,d.center.y+Math.sin(T)*C*.55,d.center.z+(b(w,3)-.5)*C*.6);E.lerp(M,.12+b(w,12)*.26),a.push(E.x,E.y,E.z);const P=.18+b(w,4)*.3;c.push(p.r*P,p.g*P,p.b*P),l.push(.9+b(w,5)*2.2),r.push(.18+b(w,6)*.22),y%6===0&&(Ot(a,c,l,r,M,E,p,w,q(3,n.particleScale,1)),kt(y,n.tetherScale)&&Bt(h,3,n.maxTransitionTetherVertices)&&Nt(h,f,M,E,p,w,d.pull?.07:.12,3))}}return ts(a,c,l,r,h,f)}function ii(e,t,s,i,n,o,a){const c=[],l=[],r=[],h=[];for(const d of e){const p=t.get(d.source),u=t.get(d.target);if(!p||!u)continue;const g=s.get(p.id),M=s.get(u.id);if(!g||!M)continue;const _=!!n?.has(d.id),y=!!(i&&(d.source===i||d.target===i)),w=_||y;zi(w?r:c,w?h:l,p,u,g,M,d.id,w,d.weight||.35)}const f=new U;f.setAttribute("position",new O(c,3)),f.setAttribute("color",new O(l,3)),o.geometry.dispose(),o.geometry=f;const m=new U;m.setAttribute("position",new O(r,3)),m.setAttribute("color",new O(h,3)),a.geometry.dispose(),a.geometry=m}function ni(e,t,s,i,n,o,a,c){if(!t||!s.has(t)){if(c.dataset.selectedShockwave="off",c.dataset.selectionMotion="none",Ft(e.geometry)>0){const y=new U;e.geometry.dispose(),e.geometry=y}return}const l=i.get(t),r=s.get(t),h=new L(l?J(l):"#fff2c8").lerp(new L("#fff3cc"),.3),f=[],m=[],d=R.clamp((o-8)/48,.22,1),p=(Math.sin(n*.018+b(t,17)*Math.PI*2)+1)*.5*a,g=3.2+(l?Math.min(1.4,Math.sqrt(l.total+1)/8):.4)*3.8,M=o<34?[0]:[0,1];for(const y of M){const w=g+y*2.35+p*(y+1)*.28,T=(.2-y*.065)*d;ri(f,m,r,w,h,T,`${t}:ring:${y}`)}o>42&&li(f,m,r,g+6.4+p*.7,h,d);const _=new U;_.setAttribute("position",new O(f,3)),_.setAttribute("color",new O(m,3)),e.geometry.dispose(),e.geometry=_,c.dataset.selectedShockwave="on",c.dataset.selectionMotion="quiet-orbit"}function oi(e,t,s,i,n,o,a,c,l,r){const h=t.filter(g=>o?.has(g.id)?!0:!!(n&&(g.source===n||g.target===n))).slice(0,96);if(!h.length){if(r.dataset.linkCurrent="off",r.dataset.linkCurrentModel="none",Ft(e.geometry)>0){const g=new U;e.geometry.dispose(),e.geometry=g}return}const f=[],m=[],d=[],p=[];for(const g of h){const M=s.get(g.source),_=s.get(g.target),y=i.get(g.source),w=i.get(g.target);!M||!_||!y||!w||ai(f,m,d,p,M,_,y,w,g,a,c,l,!!o?.has(g.id))}const u=new U;u.setAttribute("position",new O(f,3)),u.setAttribute("color",new O(m,3)),u.setAttribute("particleSize",new O(d,1)),u.setAttribute("particleHeat",new O(p,1)),e.geometry.dispose(),e.geometry=u,r.dataset.linkCurrent=f.length?"on":"off",r.dataset.linkCurrentModel=f.length?"slow-packets":"none"}function ai(e,t,s,i,n,o,a,c,l,r,h,f,m){const d=new L(J(n)),p=new L(J(o)),u=a.distanceTo(c),g=a.clone().lerp(c,.5),M=new v((b(l.id,1)-.5)*Math.min(15,u*.18),(b(l.id,2)-.5)*Math.min(10,u*.14),(b(l.id,3)-.5)*18),_=g.add(M),y=R.clamp((h-8)/62,.24,1),w=R.clamp(l.weight||.28,.12,1),T=m||w>.68&&h>44?2:1,C=f<=0?0:(m?.0042:.0027)*(.85+w*.3)*Math.max(.35,f);for(let E=0;E<T;E+=1){const P=b(l.id,E+41),x=(r*C+P+E/Math.max(1,T))%1,S=Math.sin(x*Math.PI);if(!m&&S<.18)continue;const z=mt(a,_,c,x),F=d.clone().lerp(p,x).lerp(new L("#fff1c2"),m?.18:.08),A=(m?.82:.48)*y*(.62+S*.34);e.push(z.x,z.y,z.z),t.push(F.r*A,F.g*A,F.b*A),s.push(((m?4.8:3.2)+Math.min(3.8,w*4.2)+S*.9)*y),i.push((m?.58:.34)*y)}}function ri(e,t,s,i,n,o,a){for(let l=0;l<72;l+=1){const r=l/72*Math.PI*2,h=(l+1)/72*Math.PI*2,f=1+(b(a,l)-.5)*.065,m=1+(b(a,l+99)-.5)*.065,d=new v(s.x+Math.cos(r)*i*f,s.y+Math.sin(r)*i*.64*f,s.z+Math.sin(r*2.4+b(a,7))*.45),p=new v(s.x+Math.cos(h)*i*m,s.y+Math.sin(h)*i*.64*m,s.z+Math.sin(h*2.4+b(a,7))*.45);e.push(d.x,d.y,d.z,p.x,p.y,p.z),t.push(n.r*o,n.g*o,n.b*o,n.r*o,n.g*o,n.b*o)}}function li(e,t,s,i,n,o){for(let a=0;a<6;a+=1){const c=a/6*Math.PI*2,l=i*.82,r=i*(1.05+b(`tick:${a}`,1)*.12),h=new v(s.x+Math.cos(c)*l,s.y+Math.sin(c)*l*.64,s.z),f=new v(s.x+Math.cos(c)*r,s.y+Math.sin(c)*r*.64,s.z+(b(`tick:${a}`,2)-.5)*1.2),m=(.16+b(`tick:${a}`,3)*.11)*o;e.push(h.x,h.y,h.z,f.x,f.y,f.z),t.push(n.r*m,n.g*m,n.b*m,n.r*m*1.16,n.g*m*1.16,n.b*m*1.16)}}function re(e){return e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2}function ci(e){return 1-Math.pow(1-e,3)}function hi(e,t,s,i,n,o){const a=Date.now(),c=[],l=[],r=[],h=[],f=[],m=[];for(const u of e.slice(0,56)){const g=Date.parse(u.observedAt||""),M=Number.isFinite(g)?Math.max(0,(a-g)/1e3):0,_=u.kind.startsWith("link.")?10:7;if(M>_)continue;const y=1-M/_;if(u.kind.startsWith("node.")){const x=ui(u,t);if(!x)continue;di(c,l,r,h,u,x,y);continue}const w=u.sourceId?t.get(u.sourceId):void 0,T=u.targetId?t.get(u.targetId):void 0;if(!w||!T)continue;const C=u.sourceId?s.get(u.sourceId):void 0,E=u.targetId?s.get(u.targetId):void 0,P=u.linkId?i.get(u.linkId):void 0;pi(c,l,r,h,f,m,u,w,T,C,E,P,M/_,y)}if(c.length===0&&f.length===0&&Ft(n.geometry)===0&&Ft(o.geometry)===0)return;const d=new U;d.setAttribute("position",new O(c,3)),d.setAttribute("color",new O(l,3)),d.setAttribute("particleSize",new O(r,1)),d.setAttribute("particleHeat",new O(h,1)),n.geometry.dispose(),n.geometry=d;const p=new U;p.setAttribute("position",new O(f,3)),p.setAttribute("color",new O(m,3)),o.geometry.dispose(),o.geometry=p}function Ft(e){return e.getAttribute("position")?.count||0}function ui(e,t){if(e.nodeId&&t.has(e.nodeId))return t.get(e.nodeId);if(typeof e.x=="number"&&typeof e.y=="number"&&typeof e.z=="number"){const s=wt(e.cluster||e.id,1,0),i={id:e.nodeId||e.id,cluster:e.cluster||"",total:1};return e.kind==="node.removed"?new v(e.x,e.y,e.z):Je(i).lerp(new v(e.x,e.y,e.z),.22).lerp(new v(...s.center),.06)}return null}function di(e,t,s,i,n,o,a){const c=Ge(n),l=n.kind==="node.created"?1.35:n.kind==="node.removed"?.72:1;e.push(o.x,o.y,o.z),t.push(c.r*(1.1+a),c.g*(1.1+a),c.b*(1.1+a)),s.push((13+a*34)*l),i.push(.55+a*.42);const r=n.kind==="node.removed"?8:14;for(let h=0;h<r;h+=1){const f=`${n.id}:pulse:${h}`,m=b(f,1)*Math.PI*2,d=(1-a)*(5+b(f,2)*14)+b(f,3)*2;e.push(o.x+Math.cos(m)*d,o.y+Math.sin(m)*d*.72,o.z+(b(f,4)-.5)*d);const p=.72+a*.85;t.push(c.r*p,c.g*p,c.b*p),s.push(2.2+a*6+b(f,5)*3),i.push(.22+a*.68)}}function pi(e,t,s,i,n,o,a,c,l,r,h,f,m,d){const p=Ge(a,r,h),u=c.distanceTo(l),g=c.clone().lerp(l,.5).add(new v((b(a.id,11)-.5)*Math.min(18,u*.22),6+(b(a.id,12)-.5)*Math.min(14,u*.2),(b(a.id,13)-.5)*18)),M=mt(c,g,l,R.clamp(m,0,1)),_=mt(c,g,l,R.clamp(m-.18,0,1)),y=(a.kind==="link.removed"?.58:1.1)*d*(.8+(f?.weight||a.weight||.35)*.8);n.push(_.x,_.y,_.z,M.x,M.y,M.z),o.push(p.r*y,p.g*y,p.b*y,p.r*y*1.9,p.g*y*1.9,p.b*y*1.9),e.push(M.x,M.y,M.z),t.push(p.r*(1.4+d),p.g*(1.4+d),p.b*(1.4+d)),s.push(8+d*19),i.push(.72+d*.24)}function Ge(e,t,s){if(e.kind==="node.removed"||e.kind==="link.removed")return new L("#ff6c62");if(e.kind==="node.created")return new L(e.color||"#76ff9d");if(e.kind==="link.created"){const i=t?new L(J(t)):new L("#75eaff"),n=s?new L(J(s)):new L("#f4d57e");return i.lerp(n,.5).lerp(new L("#fff2c8"),.24)}return new L(e.color||"#75eaff")}function fi(e,t,s,i,n){const o=new Set(s.map(a=>a.id));for(const[a,c]of t)o.has(a)||(e.remove(c),t.delete(a));for(const a of s){const c=ft(a.id,n),l=Mi(a.id,c);let r=t.get(a.id);if(!r){const f=document.createElement("button");f.type="button",f.className="atlas-cluster-label",f.addEventListener("click",m=>{m.stopPropagation();const d=t.get(a.id)?.element;i(d?._clusterOverlay||a)}),r=new Xe(f),t.set(a.id,r),e.add(r)}const h=r.element;h._clusterOverlay=a,h.style.color=a.color,h.innerHTML=`
|
|
163
|
+
<strong>${pt(a.label)}</strong>
|
|
164
|
+
${a.parentHint?`<em>${pt(a.parentHint)}</em>`:""}
|
|
165
|
+
<span>${a.count}, ${a.degree}</span>
|
|
166
|
+
`,r.position.copy(l)}}function $t(e,t,s,i,n,o,a,c,l,r,h){const f=new Set(s.filter(d=>i.has(d)&&n.has(d)));o&&i.has(o)&&n.has(o)&&f.add(o);const m=bi(i,n,f,a,c,o,l,r,h);for(const d of m)f.add(d);for(const[d,p]of t)f.has(d)||(e.remove(p),t.delete(d));for(const d of f){const p=i.get(d),u=n.get(d);if(!p||!u)continue;let g=t.get(d);if(!g){const _=document.createElement("div");_.className="atlas-node-label",g=new Xe(_),t.set(d,g),e.add(g)}const M=g.element;M.className=`atlas-node-label ${m.includes(d)?"semantic":""}`,M.style.color=J(p),M.innerHTML=`
|
|
167
|
+
<strong>${pt(p.name)}</strong>
|
|
168
|
+
<span>${pt(p.type)} · ${p.total} links · ${pt(p.clusterLabel)}</span>
|
|
169
|
+
`,g.position.copy(u.clone().add(new v(1.2,3.8,3.4)))}}function mi(e,t){return t||e<42?"near":e<82?"mid":"far"}function gi(e,t,s,i){return i||t||e<42?0:e<82?s?.12:.32:s?.24:1}function bi(e,t,s,i,n,o,a,c,l){if(i!=="near"||o)return[];c.parent?.updateMatrixWorld(!0),c.updateMatrixWorld(!0),a.updateMatrixWorld(!0);const r=[...e.values()].filter(d=>!s.has(d.id)&&t.has(d.id)&&d.total>=1).map(d=>{const p=t.get(d.id),u=_i(p,a,c,l),g=p.distanceTo(n);return{id:d.id,screen:u,focusDistance:g,score:d.total*1.15+d.heat*42-g*1.15+Xt(d.cluster)*8}}).sort((d,p)=>p.score-d.score||d.id.localeCompare(p.id)),h=r.filter(d=>d.screen),f=Ie(h,l.clientWidth,l.clientHeight,90,270,120,220),m=f.length?f:Ie(h,l.clientWidth,l.clientHeight,42,190,84,176);return m.length?m.map(d=>d.id):r.sort((d,p)=>d.focusDistance-p.focusDistance||p.score-d.score||d.id.localeCompare(p.id)).slice(0,2).map(d=>d.id)}function Ie(e,t,s,i,n,o,a){const c=[];for(const l of e){const r=l.screen;if(r&&!(r.x<=i||r.x>=t-n||r.y<=o||r.y>=s-a)&&!c.some(h=>h.screen.distanceTo(r)<132)&&(c.push({id:l.id,screen:r,score:l.score}),c.length>=4))break}return c}function _i(e,t,s,i){const o=e.clone().applyMatrix4(s.matrixWorld).project(t);return o.z<-1||o.z>1?null:new B((o.x*.5+.5)*i.clientWidth,(-o.y*.5+.5)*i.clientHeight)}function Mi(e,t){const i={people:[-3,-1,3],organizations:[4,-1,3],projects:[0,4,4],infrastructure:[1,7,4],events:[2,5,3],locations:[-2,5,3],operations:[1,-7,4]}[e]||[0,t.spread[1]*.62,3];return new v(t.center[0]+i[0],t.center[1]+i[1],t.center[2]+i[2])}function pt(e){return e.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'")}function We(e,t,s,i,n,o){const a=s.domElement.getBoundingClientRect();i.updateMatrixWorld(!0),t.updateMatrixWorld(!0);let c=null;const l=new v,r=new v;for(const h of n){if(r.copy(h.position).applyMatrix4(i.matrixWorld),l.copy(r).project(t),l.z<-1||l.z>1)continue;const f=(l.x*.5+.5)*a.width+a.left,m=(-l.y*.5+.5)*a.height+a.top,d=Math.hypot(e.clientX-f,e.clientY-m),p=Math.max(8,t.position.distanceTo(r)),u=R.clamp(o*(.86+20/p),o*.86,o*1.42);d>u||c&&d>=c.distance||(c={id:h.id,node:h.node,distance:d})}return c?{id:c.id,node:c.node}:null}function Ve(e,t,s,i){const n=r=>{const h=t.get(r.id);return h?{id:r.id,node:r,position:h}:null};if(e.length<=ne)return e.map(n).filter(r=>!!r);const o=new Map,a=r=>r.total+r.heat*38+(i?.has(r.id)?1e3:0)+(r.id===s?2e3:0);for(const r of e)(r.id===s||i?.has(r.id))&&o.set(r.id,r);const c=new Map;for(const r of e)c.set(r.cluster,[...c.get(r.cluster)||[],r]);const l=Math.max(96,Math.floor((ne-o.size)*.58/Math.max(1,c.size)));for(const r of c.values())r.sort((h,f)=>a(f)-a(h)).slice(0,l).forEach(h=>o.set(h.id,h));return[...e].sort((r,h)=>a(h)-a(r)).some(r=>(o.set(r.id,r),o.size>=ne)),[...o.values()].map(n).filter(r=>!!r)}function xi(e,t,s,i){const n=i.getBoundingClientRect(),o=R.clamp(s.clientX-n.left+16,12,n.width-220),a=R.clamp(s.clientY-n.top+16,12,n.height-96);e.style.transform=`translate(${o}px, ${a}px)`,e.innerHTML=`
|
|
170
|
+
<strong>${pt(t.name)}</strong>
|
|
171
|
+
<span>source page · ${pt(t.type)} · ${t.total} links · ${pt(t.clusterLabel)}</span>
|
|
172
|
+
`,e.classList.add("visible")}function yi(e,t,s,i,n,o){if(!t){e.classList.remove("visible");return}const a=s.find(f=>f.id===t);if(!a){e.classList.remove("visible");return}n.updateMatrixWorld(!0);const l=a.position.clone().applyMatrix4(n.matrixWorld).project(i);if(l.z<-1||l.z>1){e.classList.remove("visible");return}const r=(l.x*.5+.5)*o.clientWidth,h=(-l.y*.5+.5)*o.clientHeight;e.style.transform=`translate(${r}px, ${h}px) translate(-50%, -50%)`,e.classList.add("visible")}function wi(e){const t=e.getBoundingClientRect(),s=t.width<520?8:14,i=t.width<520?8:72,n=t.width<520?60:112;for(const o of e.querySelectorAll(".atlas-cluster-label, .atlas-node-label")){o.style.marginLeft="0px",o.style.marginTop="0px";const a=o.getBoundingClientRect();let c=0,l=0;a.left<t.left+s&&(c=t.left+s-a.left),a.right>t.right-s&&(c=t.right-s-a.right),a.top<t.top+i&&(l=t.top+i-a.top),a.bottom>t.bottom-n&&(l=t.bottom-n-a.bottom),o.style.marginLeft=`${Math.round(c)}px`,o.style.marginTop=`${Math.round(l)}px`}}function vi(e,t,s,i,n,o){const a=[...n.values()];if(!a.length){s.set(-6,0,0);return}const c=new ce().setFromPoints(a);i.copy(qe(c));const l=c.getCenter(new v),r=c.getSize(new v),h=o?n.get(o):null;s.copy(h?h.clone().lerp(l,.42):new v(l.x,l.y,l.z*.28));const f=R.degToRad(e.fov),m=2*Math.atan(Math.tan(f/2)*e.aspect),d=r.y/2/Math.tan(f/2),p=r.x/2/Math.tan(m/2),u=Math.max(18,r.z*.62),g=Math.max(18,Math.max(d,p)*.74+u*.56),M=h?g:Math.max(d,p)+u,_=R.clamp(M,h?12:46,h?118:198),y=e.position.clone().sub(t.target),w=y.lengthSq()>1?y.normalize():new v(0,0,1);t.minDistance=h?3.5:Math.max(6,_*.07),t.maxDistance=Math.min(320,Math.max(_*1.9,_+82)),e.position.copy(s.clone().add(w.multiplyScalar(_))),t.target.copy(s),t.update()}function Ti(e,t){const s=[...t.values()];s.length&&e.copy(qe(new ce().setFromPoints(s)))}function qe(e){return e.clone().expandByScalar(24)}function Si(e,t,s,i){const n=t.target.clone();t.target.clamp(i.min,i.max),s.clamp(i.min,i.max);const o=t.target.clone().sub(n);o.lengthSq()>0&&e.position.add(o)}const Ye=[[-39,7,-3],[-6,23,2],[-7,-20,7],[34,7,-1],[31,-16,5],[-48,-10,4],[8,19,-8],[-21,-25,9]],oe=["#ffd66b","#ff8b72","#b276ff","#62e7ff","#6df0aa","#e96dae","#f4d57e","#7de3ff"],Pi={people:[4,1,-1],organizations:[4,-1,0],projects:[4,1,1],infrastructure:[-5,-1,1],events:[3,-1,0],locations:[4,-1,0],operations:[-5,3,-1]};function Ci(e){const t=Pi[e];if(t)return t;const s=b(e,83)*Math.PI*2,i=2+b(e,89)*4;return[Math.cos(s)*i,Math.sin(s)*i*.72,(b(e,97)-.5)*3]}function Ei(e,t){const s=new Map;for(const c of e)s.set(c.cluster,(s.get(c.cluster)||0)+1);const i=[...s.entries()].sort((c,l)=>{const r=wt(c[0],c[1],0),h=wt(l[0],l[1],0);return r.center[0]-h.center[0]||h.center[1]-r.center[1]}),n=new Map,o=i.map(([c,l],r)=>{const h=wt(c,l,r),f=Math.sqrt(l);return{clusterId:c,count:l,base:h,center:new v(h.center[0],h.center[1],h.center[2]),radius:R.clamp(7.5+f*1.1,9,22)}}),a=t==="compact"?7:3;for(let c=0;c<a;c+=1){for(let l=0;l<o.length;l+=1)for(let r=l+1;r<o.length;r+=1){const h=o[l],f=o[r],m=f.center.clone().sub(h.center),d=Math.max(.001,m.length()),p=h.radius+f.radius+3;if(d>=p)continue;const u=(p-d)*.48,g=m.normalize();h.center.addScaledVector(g,-u*(f.radius/(h.radius+f.radius))),f.center.addScaledVector(g,u*(h.radius/(h.radius+f.radius)))}for(const l of o){const r=new v(l.base.center[0],l.base.center[1],l.base.center[2]);l.center.lerp(r,.1),l.center.x=R.clamp(l.center.x,-58,45),l.center.y=R.clamp(l.center.y,-31,31),l.center.z=R.clamp(l.center.z,-14,14)}}for(const c of o){const l=Math.sqrt(c.count);n.set(c.clusterId,{center:[c.center.x,c.center.y,c.center.z+(b(c.clusterId,101)-.5)*2],spread:[R.clamp(7+l*1.6,9,20),R.clamp(5+l*.9,6,13),R.clamp(7+l*.8,8,16)],color:c.base.color})}return{mode:t,visuals:n,clusterCounts:s}}function ft(e,t){return t?.visuals.get(e)||wt(e,1,0)}function wt(e,t,s){const i=Ye[s%Ye.length],n=Math.sqrt(Math.max(1,t));return{center:[i[0]+(b(e,11)-.5)*8,i[1]+(b(e,17)-.5)*6,i[2]+(b(e,23)-.5)*5],spread:[R.clamp(9+n*1.15,10,24),R.clamp(6+n*.72,7,14),R.clamp(8+n*.66,8,16)],color:oe[Math.floor(b(e,29)*oe.length)%oe.length]}}function Je(e,t){if(t?.mode==="compact"){const d=ft(e.cluster,t),p=b(e.id,3),u=b(e.id,9),g=b(e.id,17),M=p*Math.PI*2,_=Math.sqrt(u),y=Math.min(1,e.total/42);return new v(d.center[0]+Math.cos(M)*d.spread[0]*_*(1.22-y*.38),d.center[1]+Math.sin(M)*d.spread[1]*_*(1.1-y*.28),d.center[2]+(g-.5)*d.spread[2]*(1.2-y*.42))}const s=ft(e.cluster,t),i=b(e.id,3),n=b(e.id,9),o=b(e.id,17),a=i*Math.PI*2,c=Math.sqrt(n),l=Math.min(1,e.total/42),r=.62+b(e.cluster,31)*.52,h=s.center[0]+Math.cos(a)*s.spread[0]*c*(1.22-l*.38),f=s.center[1]+Math.sin(a)*s.spread[1]*c*r*(1.1-l*.28),m=s.center[2]+(o-.5)*s.spread[2]*(1.2-l*.42);return new v(h,f,m)}function J(e){return e.color||wt(e.cluster,1,0).color}function Xt(e){return .78+b(e,43)*1.12}function Di(e,t,s){const i=s==="Focus"?.42:1,n=Math.sqrt(Math.max(1,t)),o=R.clamp(190+n*72+b(e,57)*760,220,2600);return Math.max(90,Math.round(o*i))}function Ri(e,t){const s=t==="Focus"?.45:1;return Math.round((7+b(e,71)*16)*s)}function $e(e,t,s,i,n,o){const a=q(s==="Focus"?20:32,o.particleScale,4),c=[],l=[],r=[],h=[],f=[],m=[],d=new Map;for(const u of e){const g=t.get(u.id);if(!g)continue;const M=d.get(u.cluster)||[];(M.length<180||b(u.id,71)>.7)&&M.push(g),d.set(u.cluster,M)}for(const u of e){const g=t.get(u.id);if(!g)continue;const M=Xt(u.cluster),_=Math.min(a,Math.max(4,Math.round(Math.sqrt(u.total+4)*2.35*M))),y=new L(J(u));for(let w=0;w<_;w+=1){const T=b(u.id,w)*Math.PI*2,C=1.2+b(u.id,w+12)*(7+u.heat*8+Math.sqrt(u.total+1)*.45),E=b(u.id,w+44),P=new v(g.x+Math.cos(T)*C*(E>.76?2.4:1),g.y+Math.sin(T)*C*(E>.76?.28:.72),g.z+(b(u.id,w+30)-.5)*10);c.push(P.x,P.y,P.z),l.push(y.r*.92,y.g*.92,y.b*.92),r.push((.62+u.heat*2.2+b(u.id,w+61)*1.3)*M),h.push(Math.min(1.2,(.18+u.heat*.54)*M)),w%5===0&&(Ot(c,l,r,h,g,P,y,`${u.id}:node-thread:${w}`,q(3,o.particleScale,1)),w%5===0&&kt(w,o.tetherScale)&&Bt(f,3,o.maxNebulaTetherVertices)&&Nt(f,m,g,P,y,`${u.id}:node-line:${w}`,.072,3))}}const p=[...new Set(e.map(u=>u.cluster))];for(const u of p){const g=ft(u,n),M=new L(g.color),_=new L("#ffe9c8"),y=e.filter(P=>P.cluster===u).length,T=q(Di(u,y,s),o.particleScale,80),C=Ci(u);for(let P=0;P<T;P+=1){const x=`${u}:${P}`,S=b(x,1)*Math.PI*2,z=Math.pow(b(x,2),.42),F=.72+Math.sin(S*3+b(x,8)*4)*.22,A=Math.pow(b(x,9),2.2),j=.86+b(x,10)*.34,W=new v(g.center[0]+Math.cos(S)*g.spread[0]*z*1.36*j+C[0]*A,g.center[1]+Math.sin(S)*g.spread[1]*z*F+C[1]*A+Math.sin(A*4.6+S)*1.8,g.center[2]+(b(x,4)-.5)*g.spread[2]*1.25+C[2]*A),K=d.get(u)||[],N=K.length?K[Math.floor(b(x,12)*K.length)%K.length]:null,I=N?W.clone().lerp(N,.58+b(x,13)*.26):W;c.push(I.x,I.y,I.z);const X=.48+b(x,5)*.68,Y=M.clone().lerp(_,b(x,11)*.18);l.push(Y.r*X,Y.g*X,Y.b*X),r.push(.78+b(x,6)*1.32),h.push(.28+b(x,7)*.42),N&&P%2===0&&(Ot(c,l,r,h,N,I,Y,x,q(6,o.particleScale,2)),P%4===0&&kt(P,o.tetherScale)&&Bt(f,4,o.maxNebulaTetherVertices)&&Nt(f,m,N,I,Y,x,.16,4))}const E=q(Ri(u,s),o.particleScale,4);for(let P=0;P<E;P+=1){const x=`${u}:hot:${P}`,S=b(x,1)*Math.PI*2,z=Math.pow(b(x,2),.72),F=new v(g.center[0]+Math.cos(S)*g.spread[0]*z*1.05,g.center[1]+Math.sin(S)*g.spread[1]*z*.78,g.center[2]+(b(x,4)-.5)*g.spread[2]*.9),A=d.get(u)||[],j=A.length?A[Math.floor(b(x,12)*A.length)%A.length]:null,W=j?F.clone().lerp(j,.5+b(x,13)*.24):F;c.push(W.x,W.y,W.z);const K=1+b(x,5)*.66,N=M.clone().lerp(_,.22+b(x,8)*.24);l.push(N.r*K,N.g*K,N.b*K),r.push(1.9+b(x,6)*4.1),h.push(.72+b(x,7)*.46),j&&(Ot(c,l,r,h,j,W,N,x,q(7,o.particleScale,2)),kt(P,o.tetherScale)&&Bt(f,4,o.maxNebulaTetherVertices)&&Nt(f,m,j,W,N,x,.13,4))}}return Ai(c,l,r,h,p,s,i,n,o),ts(c,l,r,h,f,m)}function Ot(e,t,s,i,n,o,a,c,l){const r=n.distanceTo(o);if(r<1.4)return;const h=new v((b(c,21)-.5)*Math.min(5,r*.16),(b(c,22)-.5)*Math.min(4,r*.12),(b(c,23)-.5)*Math.min(6,r*.18)),f=n.clone().lerp(o,.5).add(h);for(let m=1;m<=l;m+=1){const d=m/(l+1),p=mt(n,f,o,d),u=.22+b(c,m+31)*.34;e.push(p.x,p.y,p.z),t.push(a.r*u,a.g*u,a.b*u),s.push(.5+b(c,m+41)*.86),i.push(.16+b(c,m+51)*.22)}}function Nt(e,t,s,i,n,o,a,c){const l=s.distanceTo(i);if(l<2.2)return;const r=new v((b(o,121)-.5)*Math.min(6,l*.14),(b(o,122)-.5)*Math.min(5,l*.11),(b(o,123)-.5)*Math.min(7,l*.15)),h=s.clone().lerp(i,.5).add(r);let f=s;for(let m=1;m<=c;m+=1){const d=m/c,p=mt(s,h,i,d),u=a*(.62+Math.sin(d*Math.PI)*.38);e.push(f.x,f.y,f.z,p.x,p.y,p.z),t.push(n.r*u,n.g*u,n.b*u,n.r*u*1.35,n.g*u*1.35,n.b*u*1.35),f=p}}function Bt(e,t,s){return e.length/3+t*2<=s}function ts(e,t,s,i,n,o){const a=new U;a.setAttribute("position",new O(e,3)),a.setAttribute("color",new O(t,3)),a.setAttribute("particleSize",new O(s,1)),a.setAttribute("particleHeat",new O(i,1));const c=new U;return c.setAttribute("position",new O(n,3)),c.setAttribute("color",new O(o,3)),{particles:a,tethers:c,tetherCount:n.length/3}}function le(e,t,s){e.geometry.dispose(),e.geometry=s.particles,t.geometry.dispose(),t.geometry=s.tethers}function Ai(e,t,s,i,n,o,a,c,l){const r=new Set(n),h=o==="Focus"?.58:1;for(const{fromId:f,toId:m,count:d,weight:p}of a){if(!r.has(f)||!r.has(m))continue;const u=ft(f,c),g=ft(m,c),M=new L(u.color),_=new L(g.color),y=new L("#ffefd3"),w=q(Math.round(R.clamp(260+Math.sqrt(d)*130,220,1900)*h),l.organicVeinScale,80),T=new v(...u.center),C=new v(...g.center),E=T.clone().lerp(C,.5),P=new v((b(`${f}:${m}`,1)-.5)*22,7+(b(`${f}:${m}`,2)-.5)*18+p*7,(b(`${f}:${m}`,3)-.5)*16),x=E.add(P);for(let S=0;S<w;S+=1){const z=`${f}:${m}:matter:${S}`,F=b(z,1),A=mt(T,x,C,F),j=mt(T,x,C,Math.min(1,F+.01)).sub(A).normalize(),W=new v(-j.y,j.x,j.z*.2).normalize(),K=Math.sin(F*Math.PI),N=(b(z,2)-.5)*(5+K*(10+p*8)),I=(b(z,3)-.5)*(6+K*(8+p*6));e.push(A.x+W.x*N,A.y+W.y*N+Math.sin(F*Math.PI*3+b(z,8)*6)*2.4,A.z+I);const X=M.clone().lerp(_,F).lerp(y,.08+b(z,9)*.12),Y=(.34+b(z,4)*.62)*(.7+p*.52);t.push(X.r*Y,X.g*Y,X.b*Y),s.push((.72+b(z,5)*1.95)*(.78+p*.5)),i.push((.24+b(z,6)*.48)*(.72+p*.44))}}}function zi(e,t,s,i,n,o,a,c,l=.35){const r=new L(J(s)),h=new L(J(i)),f=n.clone().lerp(o,.5),m=n.distanceTo(o),d=new v((b(a,1)-.5)*Math.min(15,m*.18),(b(a,2)-.5)*Math.min(10,m*.14),(b(a,3)-.5)*18),p=f.add(d),u=c?8:5;let g=n;for(let M=1;M<=u;M+=1){const _=M/u,y=mt(n,p,o,_);e.push(g.x,g.y,g.z,y.x,y.y,y.z);const w=r.clone().lerp(h,Math.max(0,_-1/u)),T=r.clone().lerp(h,_),C=c?1.05:.028+l*.12;t.push(w.r*C,w.g*C,w.b*C,T.r*C,T.g*C,T.b*C),g=y}}function mt(e,t,s,i){const n=1-i;return new v(n*n*e.x+2*n*i*t.x+i*i*s.x,n*n*e.y+2*n*i*t.y+i*i*s.y,n*n*e.z+2*n*i*t.z+i*i*s.z)}function b(e,t){let s=2166136261+t*1013;for(let i=0;i<e.length;i+=1)s^=e.charCodeAt(i),s=Math.imul(s,16777619);return(s>>>0)%1e4/1e4}export{Bi as AtlasCanvas};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:root{font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;color:#eee7dc;background:#03060c;font-synthesis:none;text-rendering:optimizeLegibility}*{box-sizing:border-box}body{margin:0;min-width:320px;min-height:100vh;overflow:hidden}button,input{font:inherit}button{cursor:pointer}button:disabled,input:disabled{cursor:not-allowed}.atlas-shell{position:relative;width:100vw;height:100vh;overflow:hidden;background:radial-gradient(circle at 53% 42%,rgba(220,86,160,.09),transparent 31%),radial-gradient(circle at 68% 68%,rgba(75,182,204,.08),transparent 26%),radial-gradient(circle at 35% 70%,rgba(165,86,220,.08),transparent 25%),linear-gradient(180deg,#03060c,#080d17 48%,#03050a)}.atlas-shell:before{content:"";position:absolute;inset:0;background:linear-gradient(90deg,rgba(255,255,255,.035) 1px,transparent 1px),linear-gradient(180deg,rgba(255,255,255,.025) 1px,transparent 1px);background-size:80px 80px;opacity:.13;-webkit-mask-image:radial-gradient(circle at 48% 48%,black 0,black 58%,transparent 95%);mask-image:radial-gradient(circle at 48% 48%,black 0,black 58%,transparent 95%);pointer-events:none}.starfield{position:absolute;inset:0;opacity:.36;background-image:radial-gradient(circle,rgba(112,135,210,.58) 0 1px,transparent 1.4px),radial-gradient(circle,rgba(232,199,137,.24) 0 1px,transparent 1.5px),radial-gradient(circle,rgba(224,92,156,.16) 0 1px,transparent 1.7px);background-position:0 0,33px 28px,18px 61px;background-size:54px 54px,89px 89px,133px 133px;-webkit-mask-image:radial-gradient(circle at center,black 0,black 64%,transparent 100%);mask-image:radial-gradient(circle at center,black 0,black 64%,transparent 100%);pointer-events:none}.side-rail,.top-command,.stats-strip,.sonar-button,.cognition-stream,.timeline{pointer-events:auto}.side-rail{position:absolute;z-index:7;top:0;left:0;bottom:0;width:156px;padding:31px 16px;background:linear-gradient(90deg,rgba(3,6,12,.72),rgba(3,6,12,.25) 70%,transparent)}.brand-mark{display:flex;align-items:center;gap:14px;margin-bottom:34px;color:#eee7dcad;text-transform:uppercase}.brand-mark span{flex:0 0 19px;width:19px;height:19px;border:1px solid rgba(246,237,220,.58);border-radius:50%;box-shadow:inset 0 0 10px #79e8ff38,0 0 18px #ffd8752e}.brand-mark strong{font-size:13px;font-weight:500;letter-spacing:.36em;white-space:nowrap}.mode-switcher{display:grid;gap:12px}.mode-switcher button{height:39px;display:flex;align-items:center;gap:13px;padding:0 14px;border:1px solid transparent;color:#f6eddc85;background:transparent;text-transform:uppercase;font-size:11px;letter-spacing:.18em}.mode-switcher button i{width:18px;color:#f6eddca8;font-style:normal;font-size:17px;text-align:center}.mode-switcher button.active{color:#e8c676;border-color:#e8c67657;border-radius:20px;background:linear-gradient(90deg,#e8c67629,#e8c6760a);box-shadow:inset 0 0 0 1px #ffeecc0d,0 0 32px #e8c6760f}.mode-switcher button:disabled{color:#ffe2d847}.mode-switcher button:disabled i{color:#ffe2d852}.mode-switcher button.active:disabled{color:#ffe2d88a;border-color:#ff806d2e;background:#ff806d0d;box-shadow:none}.top-command{position:absolute;z-index:7;top:19px;left:50%;width:min(496px,calc(100vw - 560px));transform:translate(-50%)}.command-input{height:42px;display:flex;align-items:center;gap:12px;padding:0 12px 0 15px;color:#f6eddc8c;border:1px solid rgba(246,237,220,.12);border-radius:8px;background:#050910a3;box-shadow:inset 0 0 28px #79e8ff08,0 16px 50px #00000059;-webkit-backdrop-filter:blur(22px);backdrop-filter:blur(22px)}.command-input span{font-size:23px;line-height:1}.command-input input{width:100%;min-width:0;border:0;outline:0;color:#fff7e9;background:transparent;font-size:13px}.command-input input::placeholder{color:#f6eddc6e}.top-command.offline .command-input{border-color:#ff806d29;background:#07090e94;box-shadow:inset 0 0 24px #ff806d06,0 16px 50px #0000003d}.top-command.offline .command-input span,.top-command.offline .command-input input,.top-command.offline .command-input input::placeholder{color:#ffe2d85c}.command-input:focus-within{border-color:#79e8ff6b;box-shadow:inset 0 0 28px #79e8ff0f,0 0 0 2px #79e8ff1f,0 16px 50px #00000059}.command-input input:focus-visible{outline:0}.command-input kbd{min-width:42px;height:24px;display:grid;place-items:center;color:#f6eddc9e;border:1px solid rgba(246,237,220,.11);border-radius:5px;background:#ffffff09;font-size:11px}.command-clear{min-width:54px;height:26px;padding:0 10px;border:1px solid rgba(255,193,176,.18);border-radius:5px;color:#ffe2d6db;background:#ff6c6211;font-size:11px}.command-clear:hover{border-color:#ffc1b05c;color:#ffe9df;background:#ff6c621c}.command-input .command-offline-chip{flex:0 0 auto;min-width:58px;height:24px;display:grid;place-items:center;border:1px solid rgba(255,128,109,.18);border-radius:5px;color:#ffe2d894;background:#ff6c620b;font-size:10px;line-height:1;text-transform:uppercase;letter-spacing:.08em}.command-suggestions{position:absolute;top:calc(100% + 8px);left:0;right:0;display:grid;gap:5px;padding:8px;border:1px solid rgba(121,232,255,.16);border-radius:8px;background:#050910d1;box-shadow:0 22px 68px #00000075,inset 0 0 28px #79e8ff09;-webkit-backdrop-filter:blur(24px);backdrop-filter:blur(24px)}.command-suggestion-meta{margin:0 2px 3px;color:#f6eddc7a;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:10px;text-transform:uppercase;letter-spacing:.08em}.command-suggestions button{min-height:38px;display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:center;padding:7px 9px;border:1px solid rgba(246,237,220,.08);border-radius:6px;color:#fff7e9e6;background:#ffffff07;text-align:left}.command-suggestions button:hover,.command-suggestions button:focus-visible{border-color:#f4d57e52;background:#f4d57e12}.command-suggestions strong,.command-suggestions span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.command-suggestions strong{font-size:12px;font-weight:600}.command-suggestions span{color:#79e8ffa3;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:10px;text-transform:uppercase}.stats-strip{position:absolute;z-index:7;top:23px;right:142px;display:grid;grid-template-columns:auto auto;gap:0 12px;align-items:baseline;color:#e9bfae}.stats-strip strong{justify-self:end;font-size:32px;line-height:.96;font-weight:400;letter-spacing:.04em;text-shadow:0 0 24px rgba(255,139,114,.22)}.stats-strip span{color:#e8ccbedb;font-size:clamp(22px,1.75vw,30px);line-height:.96;font-weight:300;letter-spacing:.03em;white-space:nowrap}.stats-strip em{grid-column:1 / -1;justify-self:end;margin-top:3px;color:#79e8ff9e;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:10px;font-style:normal;text-transform:uppercase;letter-spacing:.16em}.sonar-button{position:absolute;z-index:7;top:22px;right:34px;width:48px;height:44px;display:grid;place-items:center;border:1px solid rgba(246,237,220,.12);border-radius:8px;color:#f6eddccc;background:#080c1494;-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px)}.sonar-button span{width:20px;height:20px;background:linear-gradient(90deg,transparent 0 2px,currentColor 2px 4px,transparent 4px 7px,currentColor 7px 9px,transparent 9px 12px,currentColor 12px 14px,transparent 14px 20px);opacity:.78}.sonar-button:disabled{color:#ffe2d852;border-color:#ff806d24;background:#080c145c}.canvas-stage{position:absolute;inset:0}.atlas-canvas{position:absolute;inset:0 334px 0 156px}.atlas-canvas canvas{filter:brightness(1.06) saturate(1.04) contrast(1.03);cursor:grab}.atlas-canvas canvas.is-dragging-atlas{cursor:grabbing}.atlas-canvas canvas.is-picking-node{cursor:pointer}.atlas-label-layer{position:absolute;inset:0;z-index:5;pointer-events:none}.atlas-node-tooltip{position:absolute;z-index:6;top:0;left:0;width:max-content;max-width:220px;display:grid;gap:3px;padding:8px 10px;border:1px solid rgba(121,232,255,.22);border-radius:6px;color:#fff6e7e6;background:#050910c2;box-shadow:0 18px 48px #00000059,inset 0 0 20px #79e8ff0a;opacity:0;pointer-events:none;transform:translate(-999px,-999px);transition:opacity .1s ease;-webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px)}.atlas-node-tooltip.visible{opacity:1}.atlas-selection-pin{position:absolute;z-index:6;top:0;left:0;width:62px;height:62px;border:2px solid rgba(255,247,233,.92);border-radius:50%;opacity:0;pointer-events:none;transform:translate(-999px,-999px) translate(-50%,-50%);transition:opacity .12s ease;filter:drop-shadow(0 0 12px rgba(255,216,117,.52))}.atlas-selection-pin:before{content:"";position:absolute;inset:-8px;border-radius:50%}.atlas-selection-pin:before{border:1px solid rgba(255,216,117,.62);animation:pinPulse 1.6s ease-out infinite}.atlas-selection-pin.visible{opacity:1}@keyframes pinPulse{0%{opacity:.72;transform:scale(.74)}to{opacity:0;transform:scale(1.32)}}.atlas-node-tooltip strong{overflow:hidden;color:#fff7e9;font-size:12px;line-height:1.1;text-overflow:ellipsis;white-space:nowrap}.atlas-node-tooltip span{color:#ffd8759e;font-size:10px;text-transform:uppercase;letter-spacing:.06em}.loading-state{position:absolute;inset:0;display:grid;place-items:center;color:#f6eddcc2}.atlas-cluster-label{display:grid;gap:3px;padding:0;border:0;color:#ffecd6e0;background:transparent;text-align:center;text-shadow:0 0 18px rgba(0,0,0,.82);pointer-events:auto}.atlas-cluster-label strong{font-size:clamp(20px,1.9vw,31px);font-weight:400;letter-spacing:.01em}.atlas-cluster-label em{justify-self:center;margin-top:-2px;color:#ffeecc94;font-size:10px;font-style:normal;font-weight:600;letter-spacing:.12em;text-transform:uppercase}.atlas-cluster-label span{justify-self:center;min-width:74px;padding:3px 8px 4px;color:#ffe2b7c7;border:1px solid rgba(255,226,183,.16);border-radius:5px;background:#07091075;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:13px}.atlas-node-label{pointer-events:none;display:grid;gap:3px;min-width:96px;padding:5px 7px;border:1px solid rgba(246,237,220,.14);border-radius:5px;background:#03060a9e;box-shadow:0 0 18px #0000008f,0 0 22px currentColor;text-shadow:0 0 12px rgba(0,0,0,.9)}.atlas-node-label.semantic{border-color:#79e8ff29;background:#04090f7a;box-shadow:0 0 12px #0000006b,0 0 16px currentColor;opacity:.82}.atlas-node-label strong{max-width:160px;overflow:hidden;color:currentColor;font-size:12px;line-height:1.05;text-overflow:ellipsis;white-space:nowrap}.atlas-node-label span{color:#f6eddc94;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:9px;letter-spacing:.08em;text-transform:uppercase}.stats-strip.offline{grid-template-columns:auto;gap:4px;justify-items:end;color:#ffe2d8}.stats-strip.offline strong{font-size:20px;font-weight:560;text-transform:uppercase}.stats-strip.offline span{color:#ffe2d8bd;font-size:18px;text-transform:uppercase}.empty-field{position:absolute;z-index:6;left:calc(50% - 121px);top:52%;width:min(320px,calc(100vw - 220px));display:grid;gap:8px;padding:16px;border:1px solid rgba(121,232,255,.18);border-radius:8px;color:#f6eddcc2;background:#050910ad;box-shadow:0 24px 70px #00000061,inset 0 0 26px #79e8ff0a;transform:translate(-50%,-50%);-webkit-backdrop-filter:blur(22px);backdrop-filter:blur(22px)}.empty-field strong{color:#fff7e9;font-size:17px;font-weight:500}.empty-field span{color:#f6eddc99;font-size:12px;line-height:1.42}.empty-field button{justify-self:start;height:28px;padding:0 10px;border:1px solid rgba(121,232,255,.22);border-radius:5px;color:#fff6e7d1;background:#79e8ff14}.service-offline{border-color:#ff806d3d;background:radial-gradient(circle at 12% 0%,rgba(255,128,109,.12),transparent 44%),#050910c7}.service-offline strong{color:#ffe2d8}.offline-commands{display:grid;gap:6px}.offline-commands code{display:block;overflow:hidden;padding:7px 9px;border:1px solid rgba(255,216,117,.16);border-radius:5px;color:#ffedb4db;background:#ffd8750f;font-family:SFMono-Regular,Consolas,monospace;font-size:11px;text-overflow:ellipsis;white-space:nowrap}.service-offline button{border-color:#ffc1b047;color:#ffe2d8;background:#ff6c6214}.renderer-fallback{position:absolute;z-index:6;left:clamp(28px,12vw,220px);top:50%;width:min(660px,calc(100vw - 64px));max-height:min(78vh,760px);transform:translateY(-50%);display:grid;gap:14px;overflow:auto;padding:22px;border:1px solid rgba(121,232,255,.22);border-radius:8px;background:radial-gradient(circle at 8% 0%,rgba(121,232,255,.16),transparent 42%),radial-gradient(circle at 100% 80%,rgba(255,216,117,.1),transparent 44%),#050910d6;box-shadow:0 0 42px #56d5ff1a}.renderer-fallback h2{margin:0;color:#fff7e9;font-size:24px;font-weight:500;letter-spacing:0}.renderer-fallback p{margin:8px 0 0;color:#f6eddca8;font-size:13px;line-height:1.45}.renderer-fallback-stats,.renderer-fallback-clusters,.renderer-fallback-browser>div{display:flex;flex-wrap:wrap;gap:8px}.renderer-fallback-stats span,.renderer-fallback-clusters span{display:inline-flex;align-items:center;gap:8px;min-height:30px;padding:0 10px;border:1px solid rgba(246,237,220,.14);border-radius:5px;background:#ffffff0a;color:#f6eddcbd;font-size:12px}.renderer-fallback-stats strong,.renderer-fallback-clusters strong{color:#fff2bf;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-weight:600}.renderer-fallback h3{margin:0 0 8px;color:#f6eddc9e;font-size:11px;font-weight:600;letter-spacing:.16em;text-transform:uppercase}.renderer-fallback-browser button{flex:1 1 190px;min-width:0;min-height:48px;display:grid;gap:4px;align-content:center;padding:9px 10px;border:1px solid rgba(121,232,255,.14);border-radius:6px;color:#fff7e9e6;background:#79e8ff0b;text-align:left}.renderer-fallback-browser button:hover,.renderer-fallback-browser button:focus-visible{border-color:#f4d57e57;background:#f4d57e14}.renderer-fallback-browser button strong,.renderer-fallback-browser button span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.renderer-fallback-browser button strong,.renderer-fallback-actions strong{font-size:12px;font-weight:600}.renderer-fallback-browser button span,.renderer-fallback-actions span{color:#79e8ffa8;font-size:11px;line-height:1.35}.renderer-fallback-actions{display:grid;gap:8px}.renderer-fallback-actions article{display:grid;gap:4px;padding:10px;border:1px solid rgba(255,216,117,.13);border-radius:6px;background:#ffd8750b}.renderer-fallback-retry{justify-self:start;height:32px;padding:0 12px;border:1px solid rgba(121,232,255,.3);border-radius:5px;color:#d8fbff;background:#79e8ff14}.field-truth{position:absolute;z-index:7;left:176px;bottom:82px;display:flex;flex-wrap:wrap;gap:8px;max-width:calc(100vw - 560px);color:#f6eddc94;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:10px;line-height:1;text-transform:uppercase;letter-spacing:.08em;pointer-events:none}.field-truth span{display:inline-flex;align-items:center;gap:6px;min-height:26px;padding:7px 9px;border:1px solid rgba(246,237,220,.1);border-radius:14px;background:#0509108f;box-shadow:inset 0 0 22px #79e8ff09;-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px)}.field-truth strong{color:#fff7e9d1;font-weight:600}.first-run-primer{position:absolute;z-index:8;left:176px;bottom:124px;display:grid;grid-template-columns:minmax(180px,1fr) auto auto;align-items:center;gap:12px;width:min(690px,calc(100vw - 560px));padding:12px 14px;border:1px solid rgba(255,216,117,.2);border-radius:8px;color:#f6eddcbd;background:radial-gradient(circle at 8% 20%,rgba(255,216,117,.13),transparent 38%),#050910b8;box-shadow:0 24px 70px #0000006b,inset 0 0 28px #ffd87509;-webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px)}.first-run-primer h2,.first-run-primer p{margin:0}.first-run-primer h2{margin-top:3px;color:#fff7e9e6;font-size:14px;font-weight:560;line-height:1.22}.first-run-actions{display:flex;flex-wrap:wrap;gap:6px}.first-run-actions button,.first-run-dismiss{min-height:30px;padding:0 10px;border:1px solid rgba(255,216,117,.18);border-radius:6px;color:#ffefbcdb;background:#ffd87514;font-size:11px;font-weight:650}.first-run-actions button:disabled{opacity:.42}.first-run-dismiss{color:#f6eddc8f;border-color:#f6eddc1f;background:#f6eddc0a}.truth-dot{width:7px;height:7px;border-radius:50%;box-shadow:0 0 12px currentColor}.truth-dot.real{color:#ffd875;background:currentColor}.truth-dot.link{color:#79e8ff;background:currentColor}.truth-dot.projection{color:#eb65ad;border:1px solid currentColor;background:radial-gradient(circle,currentColor 0 38%,transparent 40% 100%)}.radar-sweep{position:absolute;z-index:4;inset:0 334px 0 156px;display:grid;place-items:center;pointer-events:none;overflow:hidden}.radar-sweep span{width:64px;height:64px;border:1px solid rgba(121,232,255,.68);border-radius:50%;box-shadow:0 0 34px #79e8ff73,inset 0 0 18px #79e8ff38;animation:radarSweep 1.55s cubic-bezier(.19,1,.22,1) forwards}@keyframes radarSweep{0%{opacity:.95;transform:scale(.2)}82%{opacity:.28}to{opacity:0;transform:scale(18)}}.cognition-stream{position:absolute;z-index:8;top:86px;right:25px;bottom:63px;width:323px;padding:15px 12px 14px;border:1px solid rgba(246,237,220,.13);border-radius:18px 0 0 18px;background:linear-gradient(180deg,#050910b8,#0509108a);box-shadow:-18px 0 62px #00000052,inset 1px 0 #79e8ff0d;-webkit-backdrop-filter:blur(24px);backdrop-filter:blur(24px);overflow:auto;scrollbar-width:thin;scrollbar-color:rgba(246,237,220,.22) transparent}.cognition-stream.collapsed{bottom:auto;height:54px;overflow:hidden}.cognition-stream.collapsed .stream-header button{transform:rotate(180deg)}.stream-header{display:flex;align-items:center;justify-content:space-between;margin:0 3px 13px;color:#eee7dc99;font-size:11px;text-transform:uppercase;letter-spacing:.22em}.stream-header button{border:0;color:#f6eddc94;background:transparent}.selected-card{padding:16px 0 14px;border-bottom:1px solid rgba(246,237,220,.1)}.selected-card.compact-hidden{display:none}.stream-signal{margin:12px 0 0;color:#79e8ffad;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:11px;text-transform:uppercase}.rail-offline{display:grid;gap:10px;margin-top:14px;padding:16px;border:1px solid rgba(255,128,109,.26);border-radius:8px;background:radial-gradient(circle at 14% 0%,rgba(255,128,109,.12),transparent 48%),#090d14b8;box-shadow:inset 0 0 28px #ff806d09}.rail-offline h2,.rail-offline p{margin:0}.rail-offline h2{color:#ffe2d8;font-size:18px;font-weight:560}.rail-offline p,.rail-offline span{color:#f6eddc9e;font-size:12px;line-height:1.45}.rail-offline button{justify-self:start;height:30px;padding:0 12px;border:1px solid rgba(255,193,176,.3);border-radius:6px;color:#ffe2d8;background:#ff6c6214}.pathfinder,.source-panel,.radar-panel,.cluster-deck,.bridge-radar,.atlas-filters,.mutation-layer,.orbit-edges,.privacy-panel{padding-bottom:16px;border-bottom:1px solid rgba(246,237,220,.1)}.radar-panel,.cluster-deck,.bridge-radar,.atlas-filters,.mutation-layer,.orbit-edges,.privacy-panel{margin-top:14px}.privacy-panel{display:grid;gap:8px}.privacy-panel button{justify-self:start;min-height:29px;padding:0 10px;border:1px solid rgba(255,193,176,.24);border-radius:5px;color:#ffe2d8e0;background:#ff6c6212;font-size:10px;text-transform:uppercase;letter-spacing:.06em}.privacy-panel button:hover{border-color:#ffc1b06b;background:#ff6c621f}.privacy-note{color:#76ff9db8;font-size:11px;line-height:1.35}.radar-metrics{display:grid;grid-template-columns:repeat(3,1fr);gap:7px;margin-bottom:9px}.radar-metrics span{min-height:42px;padding:8px;border:1px solid rgba(121,232,255,.14);border-radius:6px;color:#f6eddc94;background:#79e8ff0b;font-size:10px;text-transform:uppercase}.mutation-metrics{display:grid;grid-template-columns:repeat(3,1fr);gap:7px;margin:8px 0 10px}.mutation-metrics span{min-height:41px;padding:8px;border:1px solid rgba(118,255,157,.16);border-radius:6px;color:#f6eddc94;background:radial-gradient(circle at 30% 25%,rgba(118,255,157,.08),transparent 68%)}.mutation-metrics strong{display:block;color:#f6eddce6;font-size:17px;line-height:1}.mutation-list{display:grid;gap:7px}.mutation-layer.quiet{padding-bottom:13px}.mutation-list button{display:grid;gap:3px;width:100%;padding:8px 9px;border:1px solid rgba(121,232,255,.11);border-radius:6px;color:#f6eddcc2;text-align:left;background:#03080e6b}.mutation-list button:disabled{opacity:.58}.mutation-empty{display:grid;gap:3px;padding:10px;border:1px solid rgba(118,255,157,.12);border-radius:6px;color:#f6eddcb8;background:radial-gradient(circle at 15% 30%,rgba(118,255,157,.08),transparent 42%),#03080e6b}.mutation-layer.quiet .mutation-empty{margin-top:8px}.mutation-list strong{font-size:11px;text-transform:uppercase;letter-spacing:.11em}.mutation-list span{color:#f6eddc85;font-size:11px}.radar-metrics strong{display:block;color:#79e8ff;font-size:17px;font-weight:500}.radar-panel button{height:30px;padding:0 10px;border:1px solid rgba(121,232,255,.24);border-radius:5px;color:#fff7e9;background:#79e8ff17}.view-preset-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:5px;margin:9px 0 10px}.view-preset-grid button{min-height:31px;padding:0 4px;border:1px solid rgba(246,237,220,.1);border-radius:5px;color:#f6eddc94;background:#f6eddc09;font-size:10px;text-transform:uppercase;letter-spacing:.08em;display:grid;place-items:center;gap:1px}.view-preset-grid button.active{border-color:#f4d57e5c;color:#f4d57e;background:#f4d57e17;box-shadow:0 0 18px #f4d57e1a}.view-preset-grid strong,.view-preset-grid em{display:block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.view-preset-grid strong{font-size:9px;font-weight:600;letter-spacing:.04em}.view-preset-grid em{color:#f6eddc7a;font-size:10px;font-style:normal;letter-spacing:.03em}.view-preset-grid button.active em{color:#f4d57ec2}.filter-summary-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:center}.filter-summary{margin:9px 0 8px;color:#f6eddc94;font-size:11px;line-height:1.35}.clear-view-button{min-height:28px;padding:0 9px;border:1px solid rgba(255,128,109,.2);border-radius:5px;color:#ffc1b0db;background:#ff6c620f;font-size:10px;white-space:nowrap}.clear-view-button:hover{border-color:#ffc1b05c;color:#ffe5dc;background:#ff6c621a}.active-lens-strip{display:flex;flex-wrap:wrap;gap:6px;margin:0 0 9px}.active-lens-strip button{min-height:25px;display:inline-flex;align-items:center;gap:6px;padding:0 7px;border:1px solid rgba(121,232,255,.18);border-radius:5px;color:#f6eddcc2;background:radial-gradient(circle at 12% 18%,rgba(121,232,255,.1),transparent 48%),#080e1775;font-size:10px}.active-lens-strip button:hover{border-color:#79e8ff61;color:#f6eddc;background:#79e8ff14}.active-lens-strip i{display:grid;width:14px;height:14px;place-items:center;border:1px solid rgba(121,232,255,.16);border-radius:50%;color:#79e8ffa8;font-style:normal;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1}.active-lens-strip i:before{content:"x";transform:translateY(-.5px)}.advanced-toggle{width:100%;min-height:31px;border:1px solid rgba(121,232,255,.16);border-radius:5px;color:#79e8ffd1;background:#79e8ff0e}.filter-row{display:flex;align-items:center;justify-content:space-between;gap:10px;min-height:34px;color:#f6eddca3;font-size:11px;text-transform:uppercase;letter-spacing:.12em}.filter-row button,.filter-actions button{min-height:28px;padding:0 10px;border:1px solid rgba(246,237,220,.13);border-radius:5px;color:#f6eddcbd;background:#f6eddc0b}.filter-row button.active,.filter-actions button:hover{border-color:#f4d57e57;color:#f4d57e;background:#f4d57e14}.filter-actions{display:flex;flex-wrap:wrap;gap:7px;margin-top:10px}.filter-select-grid{display:grid;grid-template-columns:1fr;gap:7px;margin-top:10px}.filter-select-grid label,.filter-slider{display:grid;gap:5px;color:#f6eddc85;font-size:10px;text-transform:uppercase;letter-spacing:.12em}.filter-select-grid select{width:100%;height:30px;border:1px solid rgba(121,232,255,.13);border-radius:5px;color:#f6eddcc7;background:#03080eb8}.filter-segment{display:grid;grid-template-columns:1fr repeat(4,auto);gap:5px;align-items:center;margin-top:9px;color:#f6eddc85;font-size:10px;text-transform:uppercase;letter-spacing:.1em}.filter-segment button{min-height:27px;padding:0 7px;border:1px solid rgba(246,237,220,.11);border-radius:5px;color:#f6eddc8a;background:#f6eddc09;font-size:10px;text-transform:uppercase}.filter-segment button.active{border-color:#79e8ff47;color:#79e8ff;background:#79e8ff13}.filter-slider{margin-top:10px}.filter-slider span{display:flex;justify-content:space-between}.filter-slider em{color:#f4d57e;font-style:normal}.filter-slider input{accent-color:#79e8ff}.promote-node-button{width:100%;min-height:31px;margin-top:10px;border:1px solid rgba(244,213,126,.22);border-radius:5px;color:#f4d57e;background:#f4d57e12}.pinned-node-list{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px}.pinned-node-list button{min-height:25px;padding:0 7px;border:1px solid rgba(244,213,126,.18);border-radius:5px;color:#f6eddcbd;background:#f4d57e0d;font-size:10px}.cluster-toggle-grid{display:grid;grid-template-columns:1fr 1fr;gap:6px}.cluster-toggle-grid button{display:grid;grid-template-columns:8px minmax(0,1fr) auto;align-items:center;gap:6px;min-height:30px;padding:0 7px;border:1px solid rgba(246,237,220,.1);border-radius:5px;color:#f6eddc7a;background:#03080e61;font-size:10px}.cluster-toggle-grid.compact button{grid-template-columns:8px minmax(0,1fr)}.cluster-toggle-grid button.active{border-color:#79e8ff3d;color:#f6eddcd1;background:#79e8ff0e}.cluster-toggle-grid i{width:7px;height:7px;border-radius:50%;box-shadow:0 0 10px currentColor}.cluster-toggle-grid span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.cluster-toggle-grid em{color:#f6eddc61;font-style:normal}.orbit-edge-stats{display:grid;grid-template-columns:repeat(3,1fr);gap:7px;margin-bottom:9px}.orbit-edge-stats span{min-height:42px;padding:8px;border:1px solid rgba(255,216,117,.16);border-radius:6px;color:#f6eddc94;background:#ffd8750b;font-size:10px;text-transform:uppercase}.orbit-edge-stats strong{display:block;color:#ffd875;font-size:17px;font-weight:500}.active-bridge{display:grid;gap:4px;margin:0 0 9px;padding:9px;border:1px solid rgba(255,216,117,.26);border-radius:6px;background:linear-gradient(90deg,#ffd8751a,#79e8ff0b),#05091070}.active-bridge small,.bridge-list span{color:#79e8ff9e;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:10px;text-transform:uppercase;letter-spacing:.08em}.active-bridge strong{color:#fff7e9;font-size:13px}.active-bridge span{color:#ffd875a8;font-size:11px}.bridge-list{display:grid;gap:8px}.bridge-list article{display:grid;gap:7px;padding:9px;border:1px solid rgba(121,232,255,.13);border-radius:7px;background:radial-gradient(circle at 16% 22%,rgba(121,232,255,.08),transparent 38%),#ffffff07}.bridge-list article.selected{border-color:#ffd87570;box-shadow:inset 0 0 24px #ffd8750a,0 0 28px #79e8ff0d}.bridge-list article>button:first-child{display:grid;gap:3px;padding:0;border:0;color:#fff7e9e6;background:transparent;text-align:left}.bridge-list strong{font-size:12px;line-height:1.15}.bridge-list div{display:flex;flex-wrap:wrap;gap:5px}.bridge-list div button,.trace-connector{min-height:25px;padding:0 7px;border:1px solid rgba(246,237,220,.11);border-radius:5px;color:#f6eddcb8;background:#04070c80;font-size:10px}.trace-connector{justify-self:start;border-color:#ffd87540;color:#fff7e9;background:#ffd87514}.deck-header{display:grid;gap:3px;margin-bottom:10px}.deck-header strong{color:#fff7e9;font-size:18px;font-weight:500}.deck-header span{color:#ffd8759e;font-size:11px}.deck-grid{display:grid;gap:9px}.deck-grid div{display:grid;gap:5px}.deck-grid small{color:#79e8ff9e;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:10px;text-transform:uppercase;letter-spacing:.1em}.deck-grid button,.deck-grid span{min-height:27px;display:flex;align-items:center;justify-content:space-between;gap:8px;padding:5px 7px;border:1px solid rgba(246,237,220,.09);border-radius:5px;color:#fff6e7d1;background:#04070c6b;font-size:11px;text-align:left}.deck-grid em{flex:0 0 auto;color:#ffd87594;font-size:9px;font-style:normal;text-transform:uppercase}.path-controls{display:grid;grid-template-columns:1fr auto 1fr;gap:8px;align-items:center}.path-controls input{min-width:0;height:34px;padding:0 10px;border:1px solid rgba(121,232,255,.15);border-radius:5px;color:#fff7e9;background:#080c1494;outline:0}.path-controls input::placeholder{color:#f6eddc52}.path-controls span{color:#f6eddc6b;font-size:12px}.path-actions{display:flex;gap:8px;margin-top:10px}.path-actions button{height:32px;padding:0 12px;border:1px solid rgba(255,216,117,.25);border-radius:5px;color:#fff7e9;background:#ffd8751a}.path-actions button:disabled{cursor:not-allowed;opacity:.58}.path-actions button+button{border-color:#f6eddc1f;color:#f6eddca3;background:transparent}.path-steps{display:grid;gap:8px;margin:12px 0 0;padding-left:18px;color:#f6eddca8;font-size:12px;line-height:1.4}.route-score{display:grid;grid-template-columns:auto 1fr;gap:1px 10px;align-items:center;margin-top:12px;padding:10px;border:1px solid rgba(255,216,117,.22);border-radius:6px;background:radial-gradient(circle at 12% 50%,rgba(255,216,117,.14),transparent 46%),#080c1480}.route-score strong{grid-row:span 2;min-width:42px;color:#ffd875;font-size:26px;font-weight:500;line-height:1}.route-score span{color:#fff7e9;font-size:12px;text-transform:uppercase;letter-spacing:.1em}.route-score em{color:#f6eddc94;font-size:10px;font-style:normal}.alternate-routes{display:grid;gap:7px;margin-top:12px}.alternate-routes div{display:grid;grid-template-columns:auto minmax(0,1fr);gap:1px 8px;align-items:center;padding:8px;border:1px solid rgba(121,232,255,.12);border-radius:5px;background:#79e8ff09}.alternate-routes strong{grid-row:span 2;min-width:30px;color:#79e8ffe6;font-size:18px;font-weight:500}.alternate-routes span{overflow:hidden;color:#fff7e9d1;font-size:11px;text-overflow:ellipsis;white-space:nowrap}.alternate-routes em{color:#f6eddc85;font-size:10px;font-style:normal;text-transform:uppercase;letter-spacing:.08em}.source-path-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:start;margin-bottom:8px}.source-path{margin:0;color:#79e8ff;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:11px;word-break:break-word}.source-path-row button{min-height:26px;padding:0 8px;border:1px solid rgba(121,232,255,.18);border-radius:5px;color:#fff7e9c2;background:#79e8ff12;font-size:10px;white-space:nowrap}.source-path-row button:hover,.source-path-row button:focus-visible{border-color:#79e8ff75;color:#fff7e9}.review-flag{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:center;margin:0 0 10px;padding:9px;border:1px solid rgba(244,213,126,.16);border-radius:6px;background:radial-gradient(circle at 8% 0%,rgba(244,213,126,.09),transparent 44%),#080c147a}.review-flag strong,.review-flag span{display:block}.review-flag strong{color:#fff7e9e0;font-size:11px}.review-flag span{margin-top:3px;color:#f6eddc85;font-size:10px;line-height:1.35}.review-flag button{min-height:28px;padding:0 9px;border:1px solid rgba(244,213,126,.24);border-radius:5px;color:#f4d57ee0;background:#f4d57e14;font-size:10px;white-space:nowrap}.review-flag.queued{border-color:#76ff9d2e;background:radial-gradient(circle at 8% 0%,rgba(118,255,157,.08),transparent 44%),#080c147a}.review-flag.queued button{color:#76ff9db8;border-color:#76ff9d29;background:#76ff9d0e}.review-queue{margin-top:16px;padding:12px;border:1px solid rgba(244,213,126,.18);border-radius:7px;background:radial-gradient(circle at 100% 0%,rgba(244,213,126,.105),transparent 42%),linear-gradient(180deg,#ffffff0a,#ffffff04);box-shadow:inset 0 1px #ffffff09}.review-queue-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px}.review-queue-head h2{margin:0 0 9px}.review-queue-head span{color:#f4d57eb8;font-size:10px;white-space:nowrap}.review-queue-list{display:grid;gap:8px;margin-top:10px}.review-queue-actions{display:grid;grid-template-columns:minmax(0,1fr) auto auto;gap:8px;margin-top:10px}.review-queue-actions button{min-height:31px;border:1px solid rgba(244,213,126,.18);border-radius:6px;color:#f4d57ed6;background:#f4d57e11;font-size:10px;text-transform:uppercase;letter-spacing:.12em}.review-queue-actions button:last-child{color:#f6eddc80;border-color:#f6eddc1a;background:#060a1185}.review-queue-item{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:stretch}.review-queue-item button{border:1px solid rgba(246,237,220,.11);border-radius:6px;background:#060a118f}.review-queue-item>button:first-child{min-width:0;padding:9px;text-align:left}.review-queue-item strong,.review-queue-item span,.review-queue-item em{display:block;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.review-queue-item strong{color:#fff7e9e6;font-size:11px}.review-queue-item span{margin-top:4px;color:#f6eddc7a;font-size:10px}.review-queue-item em{margin-top:5px;color:#76ff9da3;font-size:9px;font-style:normal;text-transform:uppercase;letter-spacing:.12em}.review-clear{width:52px;color:#f6eddc8a;font-size:10px}.review-queue-item button:hover,.review-queue-item button:focus-visible{border-color:#f4d57e59;color:#fff7e9}.source-meta{display:flex;flex-wrap:wrap;gap:5px;margin:0 0 9px}.source-meta span{min-height:20px;padding:4px 6px;border:1px solid rgba(121,232,255,.14);border-radius:5px;color:#ffd875ad;background:#080c147a;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:9px;line-height:1.05;text-transform:uppercase}.source-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin:12px 0}.source-grid div{padding:10px;border:1px solid rgba(246,237,220,.1);border-radius:5px;background:#ffffff09}.source-grid strong,.source-grid span{display:block}.source-grid strong{color:#ffd875;font-size:20px;font-weight:500}.source-grid span{color:#f6eddc7a;font-size:11px}.atlas-intelligence{display:grid;gap:8px;margin:12px 0;padding:10px;border:1px solid rgba(121,232,255,.16);border-radius:7px;background:radial-gradient(circle at 100% 0%,rgba(121,232,255,.1),transparent 38%),#080c148a}.atlas-intelligence h2{margin:0 0 2px}.atlas-intelligence div{display:grid;grid-template-columns:48px minmax(0,1fr);gap:8px;align-items:start}.atlas-intelligence span{color:#79e8ff9e;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:9px;line-height:1.35;text-transform:uppercase;letter-spacing:.12em}.atlas-intelligence strong{color:#fff7e9;font-size:13px;font-weight:600}.atlas-intelligence p{margin:0;color:#f6eddca3;font-size:11px;line-height:1.35}.link-cloud{display:flex;flex-wrap:wrap;gap:6px}.source-contract,.source-section-label{margin:0 0 8px;color:#f6eddc80;font-size:11px;line-height:1.35}.source-section-label{margin-top:12px;color:#79e8ff9e;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;text-transform:uppercase;letter-spacing:.08em}.entity-xray{margin:14px 0 0;padding-top:2px}.xray-summary{display:grid;gap:5px;margin-bottom:8px}.xray-summary span{min-height:24px;padding:5px 7px;border:1px solid rgba(121,232,255,.12);border-radius:5px;color:#f6eddca8;background:#79e8ff0a;font-size:11px}.xray-debt{display:flex;flex-wrap:wrap;gap:5px;margin-bottom:10px}.xray-debt span{padding:4px 6px;border:1px solid rgba(246,237,220,.1);border-radius:5px;color:#fff6e7c7;background:#ffffff09;font-size:10px;text-transform:uppercase}.xray-debt .debt-high{border-color:#ff7b6e57;color:#ff9a88;background:#ff7b6e14}.xray-debt .debt-medium{border-color:#ffd87547;color:#ffd875;background:#ffd87514}.xray-debt .debt-clear{border-color:#76ff9d3d;color:#9dffb6;background:#76ff9d12}.link-cloud button{min-height:28px;display:inline-flex;align-items:center;gap:6px;padding:0 9px;border:1px solid rgba(121,232,255,.18);border-radius:5px;color:#f6eddcb8;background:#080c1461}.link-cloud button em{color:#79e8ff94;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:9px;font-style:normal;text-transform:uppercase}.link-cloud.all-links{max-height:138px;overflow:auto;padding-right:2px;scrollbar-width:thin;scrollbar-color:rgba(121,232,255,.28) transparent}button:focus-visible,input:focus-visible{outline:2px solid rgba(121,232,255,.7);outline-offset:2px}.eyeline{margin:0 0 8px;color:#ffd875b3;font-size:11px;text-transform:uppercase;letter-spacing:.18em}h1,h2,p{margin-top:0}h1{margin-bottom:10px;color:#f2eadf;font-size:clamp(22px,2.6vw,34px);line-height:.98;font-weight:500}h2{margin:19px 0 12px;color:#f6eddcb8;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.16em}p{color:#f6eddc9e;line-height:1.48}.insight-list{display:grid;gap:10px}.insight{display:grid;grid-template-columns:1fr 78px;gap:11px;min-height:103px;padding:10px 10px 9px;border:1px solid rgba(246,237,220,.12);border-radius:7px;background:linear-gradient(180deg,#ffffff09,#ffffff05);box-shadow:inset 0 1px #ffffff06}.insight.live{border-color:#79e8ff47}.insight.attention{border-color:#ff7b6e57}.insight.selected{border-color:#ffd87580;background:linear-gradient(180deg,#ffd87514,#ffffff05);box-shadow:inset 0 1px #ffffff0a,0 0 28px #ffd87514}.insight small{display:block;margin-bottom:6px;color:#ffd875a8;font-size:10px;text-transform:uppercase;letter-spacing:.14em}.insight strong{display:block;margin-bottom:4px;color:#fff7e9;font-size:13px;line-height:1.15}.insight p,.source-note{margin:0;font-size:12px}.insight p{display:-webkit-box;overflow:hidden;color:#f6eddc94;line-height:1.34;-webkit-box-orient:vertical;-webkit-line-clamp:2}.insight-next{display:grid;grid-template-columns:auto minmax(0,1fr);gap:6px;align-items:center;margin-top:7px;padding:6px 7px;border:1px solid rgba(121,232,255,.12);border-radius:5px;background:#79e8ff09}.insight-next span{color:#79e8ffad;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:9px;text-transform:uppercase;letter-spacing:.1em}.insight-next strong{overflow:hidden;margin:0;color:#fff7e9c7;font-size:10px;font-weight:500;line-height:1.1;text-overflow:ellipsis;white-space:nowrap}.insight-provenance{display:flex;flex-wrap:wrap;gap:5px;margin-top:8px}.insight-provenance button{display:grid;max-width:100%;padding:4px 6px;border:1px solid rgba(246,237,220,.1);border-radius:5px;color:#fff6e7d1;background:#04070c7a;text-align:left}.insight-provenance button:hover,.insight-provenance button:focus-visible{border-color:#79e8ff52;color:#fff7e9;box-shadow:0 0 18px #79e8ff14}.insight-provenance span{overflow:hidden;font-size:10px;line-height:1.1;text-overflow:ellipsis;white-space:nowrap}.insight-provenance em{margin-top:2px;color:#ffd8758f;font-size:9px;font-style:normal;text-transform:uppercase;letter-spacing:.06em}.stream-action{height:17px;margin-top:7px;padding:0;border:0;color:#f6eddc94;background:transparent;font-size:11px;text-decoration:underline;text-underline-offset:2px}.insight-thumb{width:78px;height:78px;display:grid;place-items:center;align-self:center;color:#fff6e7eb;border:1px solid rgba(246,237,220,.11);border-radius:7px;background:radial-gradient(circle at 58% 48%,rgba(255,245,203,.92) 0 2px,transparent 4px),radial-gradient(circle at 41% 56%,rgba(224,92,156,.58),transparent 32%),radial-gradient(circle at 68% 34%,rgba(88,199,220,.48),transparent 30%),radial-gradient(circle at 48% 46%,rgba(232,198,118,.35),transparent 42%),#070b13;box-shadow:inset 0 0 28px #ffffff0a;overflow:hidden;white-space:pre-line;font-size:12px;font-weight:700;line-height:.92;text-align:left}.insight-thumb:before{content:"";grid-area:1 / 1;width:100%;height:100%;background:radial-gradient(circle at 30% 30%,rgba(255,241,196,.9) 0 2px,transparent 3px),radial-gradient(circle at 72% 38%,rgba(255,99,170,.72) 0 2px,transparent 3px),radial-gradient(circle at 48% 68%,rgba(103,223,241,.74) 0 2px,transparent 3px),linear-gradient(26deg,transparent 0 36%,rgba(232,198,118,.46) 36% 37%,transparent 37% 100%),linear-gradient(136deg,transparent 0 44%,rgba(235,101,173,.46) 44% 45%,transparent 45% 100%),radial-gradient(circle at 53% 55%,rgba(255,245,203,.28),transparent 44%),#070b13;opacity:.95}.insight-thumb b{grid-area:1 / 1;z-index:1;width:calc(100% - 14px);overflow:hidden;color:#fff6e7f0;text-shadow:0 0 14px rgba(0,0,0,.86)}.insight-thumb.has-label:before{opacity:.42}.insight-thumb-2:before{background:radial-gradient(circle at 29% 66%,rgba(187,114,238,.92) 0 3px,transparent 4px),radial-gradient(circle at 70% 34%,rgba(187,114,238,.78) 0 3px,transparent 4px),linear-gradient(36deg,transparent 0 49%,rgba(187,114,238,.55) 49% 50%,transparent 50% 100%),linear-gradient(114deg,transparent 0 43%,rgba(187,114,238,.48) 43% 44%,transparent 44% 100%),radial-gradient(circle at 50% 50%,rgba(187,114,238,.3),transparent 48%),#070b13}.insight-thumb-3{padding:9px;background:radial-gradient(circle at 65% 74%,rgba(239,123,99,.6),transparent 30%),linear-gradient(28deg,transparent 0 40%,rgba(102,223,241,.42) 40% 42%,transparent 42% 100%),#070b13}.insight-thumb-4:before{background:radial-gradient(circle at 30% 30%,rgba(239,123,99,.95) 0 2px,transparent 4px),radial-gradient(circle at 68% 65%,rgba(240,207,123,.82) 0 2px,transparent 4px),linear-gradient(22deg,transparent 0 46%,rgba(239,123,99,.52) 46% 47%,transparent 47% 100%),radial-gradient(circle at 54% 52%,rgba(239,123,99,.36),transparent 48%),#070b13}.insight-thumb-5:before{background:radial-gradient(circle at center,rgba(235,101,173,.95) 0 3px,transparent 4px),repeating-radial-gradient(circle at center,rgba(235,101,173,.48) 0 1px,transparent 1px 14px),linear-gradient(90deg,transparent 0 49%,rgba(235,101,173,.45) 49% 50%,transparent 50% 100%),linear-gradient(0deg,transparent 0 49%,rgba(235,101,173,.45) 49% 50%,transparent 50% 100%),#070b13}.related-sources{margin-top:13px}.related-sources h2{margin:0 0 9px}.source-strip{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}.source-chip,.source-more{height:44px;min-width:0;padding:7px 8px;border:1px solid rgba(246,237,220,.11);border-radius:6px;color:#fff6e7db;background:radial-gradient(circle at 38% 62%,rgba(102,223,241,.5),transparent 38%),radial-gradient(circle at 72% 40%,rgba(235,101,173,.42),transparent 32%),#070b13;font-size:9px;line-height:1.05;overflow:hidden}.source-chip span{display:block;text-align:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.source-chip em{display:block;margin-top:4px;color:#ffd875d1;font-size:10px;font-style:normal}.source-chip-2{background:radial-gradient(circle at 40% 62%,rgba(187,114,238,.58),transparent 38%),#070b13}.source-chip-3{background:radial-gradient(circle at 55% 52%,rgba(239,123,99,.62),transparent 40%),#070b13}.source-chip-4{background:radial-gradient(circle at 42% 58%,rgba(240,207,123,.54),transparent 38%),#070b13}.source-chip-5{background:radial-gradient(circle at 58% 48%,rgba(235,101,173,.54),transparent 38%),#070b13}.source-more{display:grid;place-items:center;color:#f6eddcb3;background:#ffffff0a;font-size:14px}.pathfinder,.source-panel{margin-top:16px}.source-truth{display:none}.timeline{position:absolute;z-index:7;left:22px;right:24px;bottom:22px;display:grid;grid-template-columns:auto auto minmax(0,calc(100vw - 742px)) auto minmax(138px,auto) auto auto;gap:13px;align-items:center;color:#f6eddc8a;font-size:11px;text-transform:uppercase;letter-spacing:.12em}.timeline.offline{color:#ffe2d880}.playback-button,.dimension-button,.timeline-next-button{height:38px;border:1px solid rgba(246,237,220,.13);border-radius:20px;color:#f6eddccc;background:#080c148c;-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px)}.playback-button{width:40px}.dimension-button,.timeline-next-button{width:40px;padding:0}.playback-button:disabled,.dimension-button:disabled,.timeline-next-button:disabled{opacity:.34}.replay-readout{min-width:138px;max-width:226px;padding:8px 12px;border:1px solid rgba(244,213,126,.18);border-radius:18px;color:#f6eddcbd;background:#080c1494;box-shadow:inset 0 0 26px #f4d57e0b;-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px);overflow:hidden;white-space:nowrap;text-overflow:ellipsis;font-size:10px}.timeline-track{position:relative;height:42px;margin:0 10px}.timeline.offline .timeline-track{opacity:.46}.timeline-track i{position:absolute;top:14px;left:0;height:2px;background:linear-gradient(90deg,#e7c676,#e9785f 24%,#ae66da 52%,#58c7dc);box-shadow:0 0 22px #e8c67652}.timeline-track:before{content:"";position:absolute;top:14px;left:0;right:0;height:2px;background:#f6eddc2e}.timeline.offline .timeline-track:before{background:#ffe2d821;box-shadow:none}.timeline-empty{position:absolute;top:26px;left:50%;color:#ffe2d875;font-size:10px;letter-spacing:.16em;transform:translate(-50%);white-space:nowrap;pointer-events:none}.timeline-track ol{position:absolute;inset:0;display:flex;align-items:flex-start;justify-content:space-between;margin:0;padding:0;list-style:none}.timeline-track li{position:relative;width:1px;height:42px}.timeline-track li:before{content:"";position:absolute;top:12px;left:-2px;width:5px;height:5px;border-radius:50%;background:#f6eddc57}.timeline-track li:nth-child(1):before,.timeline-track li:nth-child(3):before,.timeline-track li:nth-child(5):before,.timeline-track li:nth-child(8):before{width:14px;height:3px;border-radius:3px;background:#f6eddcd1}.timeline-track li.current:before{top:9px;left:-5px;width:10px;height:10px;background:#f4d57e;box-shadow:0 0 18px #f4d57ed9}.timeline-track li button{position:absolute;top:27px;left:50%;padding:0;border:0;background:transparent;transform:translate(-50%);white-space:nowrap;color:#f6eddc6e;font-size:10px;letter-spacing:.16em;text-transform:uppercase}.timeline-track li.current button{color:#f4d57e;font-weight:600}.live-dot{display:inline-flex;align-items:center;gap:7px}.live-dot:after{content:"";width:8px;height:8px;border-radius:50%;background:#76ff9d;box-shadow:0 0 14px #76ff9dbf}.live-dot.offline{color:#ffe2d8a8}.live-dot.offline:after{background:#ff806d;box-shadow:0 0 14px #ff806d8a}.fullscreen-button{width:28px;height:28px;display:grid;place-items:center;border:0;color:#f6eddc8f;background:transparent;font-size:17px}@media(max-width:980px){body{overflow:hidden auto}.atlas-shell{min-height:100vh;height:auto;padding-bottom:86px;overflow:hidden}.side-rail{position:relative;width:auto;min-height:auto;padding:18px;background:#05070cbf;overflow:hidden}.side-rail:after{display:none}.brand-mark{margin-bottom:16px}.mode-switcher{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));width:100%;gap:6px;overflow:visible;padding:0}.mode-switcher button{min-width:0;height:48px;flex-direction:column;justify-content:center;gap:3px;border-radius:20px;padding:5px 3px;font-size:8px;line-height:1.05;letter-spacing:.08em;text-align:center}.mode-switcher button i{width:15px;font-size:14px}.top-command,.stats-strip,.sonar-button,.timeline,.cognition-stream{position:relative;inset:auto;transform:none;width:auto;margin:14px 18px}.top-command{top:auto}.command-suggestions{position:relative;top:auto;margin-top:8px}.command-suggestions button{grid-template-columns:minmax(0,1fr)}.stats-strip{grid-template-columns:repeat(2,auto);justify-content:start}.stats-strip strong,.stats-strip span{font-size:24px}.sonar-button{display:none}.canvas-stage{position:relative;height:62vh;min-height:430px;border-top:1px solid rgba(246,237,220,.06);border-bottom:1px solid rgba(246,237,220,.06)}.atlas-canvas{inset:0}.field-truth{inset:12px 14px auto;max-width:none;gap:6px;font-size:9px}.field-truth span{min-height:24px;padding:6px 8px}.first-run-primer{inset:auto 14px 14px;grid-template-columns:minmax(0,1fr);width:auto}.first-run-actions{display:grid;grid-template-columns:minmax(0,1fr)}.atlas-cluster-label strong{font-size:16px;text-shadow:0 0 12px #000,0 0 18px #000}.atlas-cluster-label span{display:none}.cognition-stream{bottom:auto;max-height:none;margin-top:76px;border-radius:14px;overflow:visible}.bridge-radar,.cluster-deck,.insight-list,.related-sources,.pathfinder,.source-truth{display:block}.insight-list,.cluster-deck,.bridge-radar{max-height:420px;overflow:auto}.source-truth{margin-top:16px;padding-bottom:16px;border-bottom:1px solid rgba(246,237,220,.1)}.timeline{position:fixed;z-index:12;left:10px;right:10px;bottom:10px;grid-template-columns:auto auto minmax(0,1fr) auto auto;gap:8px;width:auto;margin:0;padding:8px;border:1px solid rgba(246,237,220,.12);border-radius:16px;background:#050910d1;box-shadow:0 -18px 48px #00000057,inset 0 0 28px #79e8ff09;-webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px)}.timeline>span,.replay-readout{display:none}.timeline-track{height:34px;margin:0 4px}.timeline-track li{height:34px}.timeline-track li button{top:24px;font-size:0;letter-spacing:0}.timeline-track li.current button{font-size:9px;letter-spacing:.08em}.playback-button,.dimension-button,.timeline-next-button{height:34px}.playback-button,.dimension-button,.timeline-next-button{width:36px}.fullscreen-button{width:24px}}
|