Files
wifi-densepose/examples/rvf/dashboard/dist/assets/index-DTWFqlsC.js
ruv d803bfe2b1 Squashed 'vendor/ruvector/' content from commit b64c2172
git-subtree-dir: vendor/ruvector
git-subtree-split: b64c21726f2bb37286d9ee36a7869fef60cc6900
2026-02-28 14:39:40 -05:00

1289 lines
301 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import{C as fe,V as A,M as dt,T as lt,Q as Nt,S as Ot,a as G,R as ve,P as ye,b as be,c as _,d as B,e as vt,I as ie,O as ne,B as P,F as mt,f as J,A as et,g as X,L as j,h as gt,i as nt,j as ae,k as at,W as ot,l as oe,m as W,D as it,n as F,G as tt,o as Y,p as V,q as Z,E as we,r as q,s as L,t as Rt,u as Ee,v as xt,w as Wt,x as Tt,y as Ce,z as N,H as Me,J as Ct,K as re,N as Te,U as Se}from"./three-Cdmz7B_B.js";import{l as ft,s as It,a as le,b as de,c as ce}from"./d3-BwsdWUnD.js";(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const s of document.querySelectorAll('link[rel="modulepreload"]'))i(s);new MutationObserver(s=>{for(const a of s)if(a.type==="childList")for(const n of a.addedNodes)n.tagName==="LINK"&&n.rel==="modulepreload"&&i(n)}).observe(document,{childList:!0,subtree:!0});function e(s){const a={};return s.integrity&&(a.integrity=s.integrity),s.referrerPolicy&&(a.referrerPolicy=s.referrerPolicy),s.crossOrigin==="use-credentials"?a.credentials="include":s.crossOrigin==="anonymous"?a.credentials="omit":a.credentials="same-origin",a}function i(s){if(s.ep)return;s.ep=!0;const a=e(s);fetch(s.href,a)}})();const Gt={type:"change"},Ht={type:"start"},he={type:"end"},yt=new ve,jt=new ye,_e=Math.cos(70*be.DEG2RAD),D=new A,H=2*Math.PI,z={NONE:-1,ROTATE:0,DOLLY:1,PAN:2,TOUCH_ROTATE:3,TOUCH_PAN:4,TOUCH_DOLLY_PAN:5,TOUCH_DOLLY_ROTATE:6},_t=1e-6;class rt extends fe{constructor(t,e=null){super(t,e),this.state=z.NONE,this.enabled=!0,this.target=new A,this.cursor=new A,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.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:dt.ROTATE,MIDDLE:dt.DOLLY,RIGHT:dt.PAN},this.touches={ONE:lt.ROTATE,TWO:lt.DOLLY_PAN},this.target0=this.target.clone(),this.position0=this.object.position.clone(),this.zoom0=this.object.zoom,this._domElementKeyEvents=null,this._lastPosition=new A,this._lastQuaternion=new Nt,this._lastTargetPosition=new A,this._quat=new Nt().setFromUnitVectors(t.up,new A(0,1,0)),this._quatInverse=this._quat.clone().invert(),this._spherical=new Ot,this._sphericalDelta=new Ot,this._scale=1,this._panOffset=new A,this._rotateStart=new G,this._rotateEnd=new G,this._rotateDelta=new G,this._panStart=new G,this._panEnd=new G,this._panDelta=new G,this._dollyStart=new G,this._dollyEnd=new G,this._dollyDelta=new G,this._dollyDirection=new A,this._mouse=new G,this._performCursorZoom=!1,this._pointers=[],this._pointerPositions={},this._controlActive=!1,this._onPointerMove=Ae.bind(this),this._onPointerDown=ze.bind(this),this._onPointerUp=$e.bind(this),this._onContextMenu=Ie.bind(this),this._onMouseWheel=Pe.bind(this),this._onKeyDown=De.bind(this),this._onTouchStart=Fe.bind(this),this._onTouchMove=Re.bind(this),this._onMouseDown=ke.bind(this),this._onMouseMove=Le.bind(this),this._interceptControlDown=He.bind(this),this._interceptControlUp=Be.bind(this),this.domElement!==null&&this.connect(),this.update()}connect(){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(Gt),this.update(),this.state=z.NONE}update(t=null){const e=this.object.position;D.copy(e).sub(this.target),D.applyQuaternion(this._quat),this._spherical.setFromVector3(D),this.autoRotate&&this.state===z.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,s=this.maxAzimuthAngle;isFinite(i)&&isFinite(s)&&(i<-Math.PI?i+=H:i>Math.PI&&(i-=H),s<-Math.PI?s+=H:s>Math.PI&&(s-=H),i<=s?this._spherical.theta=Math.max(i,Math.min(s,this._spherical.theta)):this._spherical.theta=this._spherical.theta>(i+s)/2?Math.max(i,this._spherical.theta):Math.min(s,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 a=!1;if(this.zoomToCursor&&this._performCursorZoom||this.object.isOrthographicCamera)this._spherical.radius=this._clampDistance(this._spherical.radius);else{const n=this._spherical.radius;this._spherical.radius=this._clampDistance(this._spherical.radius*this._scale),a=n!=this._spherical.radius}if(D.setFromSpherical(this._spherical),D.applyQuaternion(this._quatInverse),e.copy(this.target).add(D),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 n=null;if(this.object.isPerspectiveCamera){const o=D.length();n=this._clampDistance(o*this._scale);const r=o-n;this.object.position.addScaledVector(this._dollyDirection,r),this.object.updateMatrixWorld(),a=!!r}else if(this.object.isOrthographicCamera){const o=new A(this._mouse.x,this._mouse.y,0);o.unproject(this.object);const r=this.object.zoom;this.object.zoom=Math.max(this.minZoom,Math.min(this.maxZoom,this.object.zoom/this._scale)),this.object.updateProjectionMatrix(),a=r!==this.object.zoom;const l=new A(this._mouse.x,this._mouse.y,0);l.unproject(this.object),this.object.position.sub(l).add(o),this.object.updateMatrixWorld(),n=D.length()}else console.warn("WARNING: OrbitControls.js encountered an unknown camera type - zoom to cursor disabled."),this.zoomToCursor=!1;n!==null&&(this.screenSpacePanning?this.target.set(0,0,-1).transformDirection(this.object.matrix).multiplyScalar(n).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))<_e?this.object.lookAt(this.target):(jt.setFromNormalAndCoplanarPoint(this.object.up,this.target),yt.intersectPlane(jt,this.target))))}else if(this.object.isOrthographicCamera){const n=this.object.zoom;this.object.zoom=Math.max(this.minZoom,Math.min(this.maxZoom,this.object.zoom/this._scale)),n!==this.object.zoom&&(this.object.updateProjectionMatrix(),a=!0)}return this._scale=1,this._performCursorZoom=!1,a||this._lastPosition.distanceToSquared(this.object.position)>_t||8*(1-this._lastQuaternion.dot(this.object.quaternion))>_t||this._lastTargetPosition.distanceToSquared(this.target)>_t?(this.dispatchEvent(Gt),this._lastPosition.copy(this.object.position),this._lastQuaternion.copy(this.object.quaternion),this._lastTargetPosition.copy(this.target),!0):!1}_getAutoRotationAngle(t){return t!==null?H/60*this.autoRotateSpeed*t:H/60/60*this.autoRotateSpeed}_getZoomScale(t){const e=Math.abs(t*.01);return Math.pow(.95,this.zoomSpeed*e)}_rotateLeft(t){this._sphericalDelta.theta-=t}_rotateUp(t){this._sphericalDelta.phi-=t}_panLeft(t,e){D.setFromMatrixColumn(e,0),D.multiplyScalar(-t),this._panOffset.add(D)}_panUp(t,e){this.screenSpacePanning===!0?D.setFromMatrixColumn(e,1):(D.setFromMatrixColumn(e,0),D.crossVectors(this.object.up,D)),D.multiplyScalar(t),this._panOffset.add(D)}_pan(t,e){const i=this.domElement;if(this.object.isPerspectiveCamera){const s=this.object.position;D.copy(s).sub(this.target);let a=D.length();a*=Math.tan(this.object.fov/2*Math.PI/180),this._panLeft(2*t*a/i.clientHeight,this.object.matrix),this._panUp(2*e*a/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(e*(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,e){if(!this.zoomToCursor)return;this._performCursorZoom=!0;const i=this.domElement.getBoundingClientRect(),s=t-i.left,a=e-i.top,n=i.width,o=i.height;this._mouse.x=s/n*2-1,this._mouse.y=-(a/o)*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 e=this.domElement;this._rotateLeft(H*this._rotateDelta.x/e.clientHeight),this._rotateUp(H*this._rotateDelta.y/e.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 e=!1;switch(t.code){case this.keys.UP:t.ctrlKey||t.metaKey||t.shiftKey?this._rotateUp(H*this.rotateSpeed/this.domElement.clientHeight):this._pan(0,this.keyPanSpeed),e=!0;break;case this.keys.BOTTOM:t.ctrlKey||t.metaKey||t.shiftKey?this._rotateUp(-H*this.rotateSpeed/this.domElement.clientHeight):this._pan(0,-this.keyPanSpeed),e=!0;break;case this.keys.LEFT:t.ctrlKey||t.metaKey||t.shiftKey?this._rotateLeft(H*this.rotateSpeed/this.domElement.clientHeight):this._pan(this.keyPanSpeed,0),e=!0;break;case this.keys.RIGHT:t.ctrlKey||t.metaKey||t.shiftKey?this._rotateLeft(-H*this.rotateSpeed/this.domElement.clientHeight):this._pan(-this.keyPanSpeed,0),e=!0;break}e&&(t.preventDefault(),this.update())}_handleTouchStartRotate(t){if(this._pointers.length===1)this._rotateStart.set(t.pageX,t.pageY);else{const e=this._getSecondPointerPosition(t),i=.5*(t.pageX+e.x),s=.5*(t.pageY+e.y);this._rotateStart.set(i,s)}}_handleTouchStartPan(t){if(this._pointers.length===1)this._panStart.set(t.pageX,t.pageY);else{const e=this._getSecondPointerPosition(t),i=.5*(t.pageX+e.x),s=.5*(t.pageY+e.y);this._panStart.set(i,s)}}_handleTouchStartDolly(t){const e=this._getSecondPointerPosition(t),i=t.pageX-e.x,s=t.pageY-e.y,a=Math.sqrt(i*i+s*s);this._dollyStart.set(0,a)}_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),s=.5*(t.pageX+i.x),a=.5*(t.pageY+i.y);this._rotateEnd.set(s,a)}this._rotateDelta.subVectors(this._rotateEnd,this._rotateStart).multiplyScalar(this.rotateSpeed);const e=this.domElement;this._rotateLeft(H*this._rotateDelta.x/e.clientHeight),this._rotateUp(H*this._rotateDelta.y/e.clientHeight),this._rotateStart.copy(this._rotateEnd)}_handleTouchMovePan(t){if(this._pointers.length===1)this._panEnd.set(t.pageX,t.pageY);else{const e=this._getSecondPointerPosition(t),i=.5*(t.pageX+e.x),s=.5*(t.pageY+e.y);this._panEnd.set(i,s)}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 e=this._getSecondPointerPosition(t),i=t.pageX-e.x,s=t.pageY-e.y,a=Math.sqrt(i*i+s*s);this._dollyEnd.set(0,a),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 n=(t.pageX+e.x)*.5,o=(t.pageY+e.y)*.5;this._updateZoomParameters(n,o)}_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 e=0;e<this._pointers.length;e++)if(this._pointers[e]==t.pointerId){this._pointers.splice(e,1);return}}_isTrackingPointer(t){for(let e=0;e<this._pointers.length;e++)if(this._pointers[e]==t.pointerId)return!0;return!1}_trackPointer(t){let e=this._pointerPositions[t.pointerId];e===void 0&&(e=new G,this._pointerPositions[t.pointerId]=e),e.set(t.pageX,t.pageY)}_getSecondPointerPosition(t){const e=t.pointerId===this._pointers[0]?this._pointers[1]:this._pointers[0];return this._pointerPositions[e]}_customWheelEvent(t){const e=t.deltaMode,i={clientX:t.clientX,clientY:t.clientY,deltaY:t.deltaY};switch(e){case 1:i.deltaY*=16;break;case 2:i.deltaY*=100;break}return t.ctrlKey&&!this._controlActive&&(i.deltaY*=10),i}}function ze(p){this.enabled!==!1&&(this._pointers.length===0&&(this.domElement.setPointerCapture(p.pointerId),this.domElement.addEventListener("pointermove",this._onPointerMove),this.domElement.addEventListener("pointerup",this._onPointerUp)),!this._isTrackingPointer(p)&&(this._addPointer(p),p.pointerType==="touch"?this._onTouchStart(p):this._onMouseDown(p)))}function Ae(p){this.enabled!==!1&&(p.pointerType==="touch"?this._onTouchMove(p):this._onMouseMove(p))}function $e(p){switch(this._removePointer(p),this._pointers.length){case 0:this.domElement.releasePointerCapture(p.pointerId),this.domElement.removeEventListener("pointermove",this._onPointerMove),this.domElement.removeEventListener("pointerup",this._onPointerUp),this.dispatchEvent(he),this.state=z.NONE;break;case 1:const t=this._pointers[0],e=this._pointerPositions[t];this._onTouchStart({pointerId:t,pageX:e.x,pageY:e.y});break}}function ke(p){let t;switch(p.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 dt.DOLLY:if(this.enableZoom===!1)return;this._handleMouseDownDolly(p),this.state=z.DOLLY;break;case dt.ROTATE:if(p.ctrlKey||p.metaKey||p.shiftKey){if(this.enablePan===!1)return;this._handleMouseDownPan(p),this.state=z.PAN}else{if(this.enableRotate===!1)return;this._handleMouseDownRotate(p),this.state=z.ROTATE}break;case dt.PAN:if(p.ctrlKey||p.metaKey||p.shiftKey){if(this.enableRotate===!1)return;this._handleMouseDownRotate(p),this.state=z.ROTATE}else{if(this.enablePan===!1)return;this._handleMouseDownPan(p),this.state=z.PAN}break;default:this.state=z.NONE}this.state!==z.NONE&&this.dispatchEvent(Ht)}function Le(p){switch(this.state){case z.ROTATE:if(this.enableRotate===!1)return;this._handleMouseMoveRotate(p);break;case z.DOLLY:if(this.enableZoom===!1)return;this._handleMouseMoveDolly(p);break;case z.PAN:if(this.enablePan===!1)return;this._handleMouseMovePan(p);break}}function Pe(p){this.enabled===!1||this.enableZoom===!1||this.state!==z.NONE||(p.preventDefault(),this.dispatchEvent(Ht),this._handleMouseWheel(this._customWheelEvent(p)),this.dispatchEvent(he))}function De(p){this.enabled===!1||this.enablePan===!1||this._handleKeyDown(p)}function Fe(p){switch(this._trackPointer(p),this._pointers.length){case 1:switch(this.touches.ONE){case lt.ROTATE:if(this.enableRotate===!1)return;this._handleTouchStartRotate(p),this.state=z.TOUCH_ROTATE;break;case lt.PAN:if(this.enablePan===!1)return;this._handleTouchStartPan(p),this.state=z.TOUCH_PAN;break;default:this.state=z.NONE}break;case 2:switch(this.touches.TWO){case lt.DOLLY_PAN:if(this.enableZoom===!1&&this.enablePan===!1)return;this._handleTouchStartDollyPan(p),this.state=z.TOUCH_DOLLY_PAN;break;case lt.DOLLY_ROTATE:if(this.enableZoom===!1&&this.enableRotate===!1)return;this._handleTouchStartDollyRotate(p),this.state=z.TOUCH_DOLLY_ROTATE;break;default:this.state=z.NONE}break;default:this.state=z.NONE}this.state!==z.NONE&&this.dispatchEvent(Ht)}function Re(p){switch(this._trackPointer(p),this.state){case z.TOUCH_ROTATE:if(this.enableRotate===!1)return;this._handleTouchMoveRotate(p),this.update();break;case z.TOUCH_PAN:if(this.enablePan===!1)return;this._handleTouchMovePan(p),this.update();break;case z.TOUCH_DOLLY_PAN:if(this.enableZoom===!1&&this.enablePan===!1)return;this._handleTouchMoveDollyPan(p),this.update();break;case z.TOUCH_DOLLY_ROTATE:if(this.enableZoom===!1&&this.enableRotate===!1)return;this._handleTouchMoveDollyRotate(p),this.update();break;default:this.state=z.NONE}}function Ie(p){this.enabled!==!1&&p.preventDefault()}function He(p){p.key==="Control"&&(this._controlActive=!0,this.domElement.getRootNode().addEventListener("keyup",this._interceptControlUp,{passive:!0,capture:!0}))}function Be(p){p.key==="Control"&&(this._controlActive=!1,this.domElement.getRootNode().removeEventListener("keyup",this._interceptControlUp,{passive:!0,capture:!0}))}const Ne={transit:new _(58879),flare:new _(16731469),rotation:new _(3066993),eclipse:new _(10044671),variability:new _(16756768)},Oe=new _(9147550);function Vt(p){return Ne[p]??Oe}class We{constructor(t){this.nodesMesh=null,this.edgesLine=null,this.glowPoints=null,this.nodeMap=new Map,this.scene=t}setNodes(t){this.disposeNodes();const e=new B(.12,8,6),i=new vt({vertexColors:!1,emissiveIntensity:.8,roughness:.3,metalness:.1}),s=new ie(e,i,t.length),a=new ne,n=new _;for(let h=0;h<t.length;h++){const u=t[h];this.nodeMap.set(u.id,h),a.position.set(u.x,u.y,u.z);const m=.3+u.weight*.7;a.scale.set(m,m,m),a.updateMatrix(),s.setMatrixAt(h,a.matrix),n.copy(Vt(u.domain)),s.setColorAt(h,n)}s.instanceMatrix.needsUpdate=!0,s.instanceColor&&(s.instanceColor.needsUpdate=!0),this.nodesMesh=s,this.scene.add(s);const o=new Float32Array(t.length*3),r=new Float32Array(t.length*3),l=new Float32Array(t.length);for(let h=0;h<t.length;h++){const u=t[h];o[h*3]=u.x,o[h*3+1]=u.y,o[h*3+2]=u.z;const m=Vt(u.domain);r[h*3]=m.r,r[h*3+1]=m.g,r[h*3+2]=m.b,l[h]=.8+u.weight*1.5}const c=new P;c.setAttribute("position",new mt(o,3)),c.setAttribute("color",new mt(r,3));const d=new J({size:1.2,vertexColors:!0,transparent:!0,opacity:.25,sizeAttenuation:!0,depthWrite:!1,blending:et});this.glowPoints=new X(c,d),this.scene.add(this.glowPoints)}setEdges(t,e){this.disposeEdges();const i=[],s=[],a=new Map;for(const r of e)a.set(r.id,r);for(const r of t){const l=a.get(r.source),c=a.get(r.target);if(!l||!c)continue;i.push(l.x,l.y,l.z),i.push(c.x,c.y,c.z);const d=Math.max(.05,Math.min(.6,r.weight*.5));s.push(0,.9,1,d),s.push(0,.9,1,d)}const n=new P;n.setAttribute("position",new mt(i,3)),n.setAttribute("color",new mt(s,4));const o=new j({vertexColors:!0,transparent:!0,opacity:.6,depthWrite:!1,blending:et});this.edgesLine=new gt(n,o),this.scene.add(this.edgesLine)}getNodeIndex(t){return this.nodeMap.get(t)}setPulse(t){if(this.glowPoints&&(this.glowPoints.material.opacity=.15+t*.15),this.nodesMesh){const e=this.nodesMesh.material;e.emissiveIntensity=.5+t*.5}}disposeNodes(){this.nodesMesh&&(this.scene.remove(this.nodesMesh),this.nodesMesh.geometry.dispose(),this.nodesMesh.material.dispose(),this.nodesMesh=null),this.glowPoints&&(this.scene.remove(this.glowPoints),this.glowPoints.geometry.dispose(),this.glowPoints.material.dispose(),this.glowPoints=null),this.nodeMap.clear()}disposeEdges(){this.edgesLine&&(this.scene.remove(this.edgesLine),this.edgesLine.geometry.dispose(),this.edgesLine.material.dispose(),this.edgesLine=null)}dispose(){this.disposeNodes(),this.disposeEdges()}}const Ge="";async function Q(p){const t=await fetch(Ge+p);if(!t.ok)throw new Error(`API error ${t.status}: ${t.statusText} (${p})`);return t.json()}async function je(p){return Q(`/api/atlas/query?event_id=${encodeURIComponent(p)}`)}async function Ve(p,t){const e=await Q(`/api/coherence?target_id=${encodeURIComponent(p)}&epoch=${t}`),i=[];if(e.values)for(let s=0;s<e.values.length;s++){const a=e.values[s];for(let n=0;n<a.length;n++)i.push({target_id:p,epoch:t,value:a[n],cut_pressure:a[n]})}return i}async function qe(p){return((await Q(`/api/coherence/boundary?target_id=${encodeURIComponent(p)}`)).points??[]).map(e=>({epoch:e.epoch,pressure:e.boundary_radius,crossed:e.coherence<.8}))}async function pe(){return((await Q("/api/coherence/alerts")).alerts??[]).map(t=>({target_id:t.sector,epoch:0,pressure:t.coherence,message:t.message}))}async function Ke(){return((await Q("/api/candidates/planet")).candidates??[]).map(t=>({id:t.id,name:t.id,score:t.score,period:t.period_days,radius:t.radius_earth,depth:t.transit_depth??.005+(1-t.score)*.005,snr:Math.round(t.score*40+5),stellarType:t.stellar_type,distance:t.distance_ly,status:t.status,mass:t.mass_earth??null,eqTemp:t.eq_temp_k??null,discoveryYear:t.discovery_year??0,discoveryMethod:t.discovery_method??"",telescope:t.telescope??"",reference:t.reference??"",transitDepth:t.transit_depth??null}))}async function Ue(){return((await Q("/api/candidates/life")).candidates??[]).map(t=>({id:t.id,name:t.id,score:t.life_score,o2:t.o2_normalized??Math.min(1,t.o2_ppm/21e4),ch4:t.ch4_normalized??Math.min(1,t.ch4_ppb/2500),h2o:t.h2o_normalized??(t.h2o_detected?.85:.2),co2:t.co2_normalized??Math.min(1,t.co2_ppm/1e4),disequilibrium:t.disequilibrium??t.biosig_confidence,habitability:t.habitability_index,atmosphereStatus:t.atmosphere_status??"Unknown",jwstObserved:t.jwst_observed??!1,moleculesConfirmed:t.molecules_confirmed??[],moleculesTentative:t.molecules_tentative??[],reference:t.reference??""}))}async function me(){return Q("/api/witness/log")}async function ue(){var t,e;const p=await Q("/api/status");return{uptime:p.uptime_seconds??0,segments:((t=p.store)==null?void 0:t.total_segments)??0,file_size:((e=p.store)==null?void 0:e.file_size)??0,download_progress:{LIGHT_SEG:1,SPECTRUM_SEG:.85,ORBIT_SEG:1,CAUSAL_SEG:.92}}}async function ge(){const p=await Q("/api/memory/tiers"),t=new Map;for(const e of p.tiers??[])t.set(e.name,{used:Math.round(e.used_mb),total:Math.round(e.capacity_mb)});return{small:t.get("S")??{used:0,total:0},medium:t.get("M")??{used:0,total:0},large:t.get("L")??{used:0,total:0}}}const Mt=[];let I=null,ct=null,ut=1e3,Bt=!1;const Ye=3e4,Ze=2;function Xe(p){try{const t=JSON.parse(p.data);for(const e of Mt)e(t)}catch{}}function qt(){Bt||ct||(ct=setTimeout(()=>{ct=null,xe()},ut),ut=Math.min(ut*Ze,Ye))}function xe(){if(I&&(I.readyState===WebSocket.OPEN||I.readyState===WebSocket.CONNECTING))return;const t=`${location.protocol==="https:"?"wss:":"ws:"}//${location.host}/ws/live`;try{I=new WebSocket(t)}catch{qt();return}I.addEventListener("open",()=>{ut=1e3}),I.addEventListener("message",Xe),I.addEventListener("close",()=>{I=null,qt()}),I.addEventListener("error",()=>{I==null||I.close()})}function St(p){return Mt.push(p),()=>{const t=Mt.indexOf(p);t>=0&&Mt.splice(t,1)}}function Je(){Bt=!1,ut=1e3,xe()}function Qe(){Bt=!0,ct&&(clearTimeout(ct),ct=null),I&&(I.close(),I=null)}const ts=["2h","12h","3d","27d"];function Ft(p){let t=p|0;return()=>(t=t*1103515245+12345&2147483647,t/2147483647)}const Kt=["Lyra","Cygnus","Aquila","Orion","Centaurus","Vela","Puppis","Sagittarius","Scorpius","Cassiopeia","Perseus","Andromeda","Draco","Ursa Major","Leo","Virgo","Libra","Gemini"];function es(p,t,e,i,s){const a=t,n=["transit","flare","rotation","eclipse","variability"],o=[],r=[],l=Ft(p.length*31337),c=8;for(let d=0;d<a;d++){const u=d%e/e*Math.PI*2,m=l(),g=.3+Math.pow(m,s)*c,x=u+g*.6+(l()-.5)*i,f=(l()-.5)*.5*Math.exp(-g*.12),w=g*.08,y=g*Math.cos(x)+(l()-.5)*w,b=g*Math.sin(x)+(l()-.5)*w,v=f,E=.15+l()*.85;o.push({id:`s${d}`,domain:n[d%n.length],x:y,y:v,z:b,weight:E})}for(let d=1;d<a;d++){let h=1/0,u=0;const m=Math.min(d,25);for(let g=Math.max(0,d-m);g<d;g++){const x=o[d].x-o[g].x,f=o[d].y-o[g].y,w=o[d].z-o[g].z,y=x*x+f*f+w*w;y<h&&(h=y,u=g)}if(r.push({source:o[u].id,target:o[d].id,weight:Math.max(.1,1-h/16)}),l()>.85&&d>4){const g=Math.floor(l()*d),x=o[d].x-o[g].x,f=o[d].z-o[g].z;Math.sqrt(x*x+f*f)<4&&r.push({source:o[g].id,target:o[d].id,weight:.05+l()*.15})}}return{nodes:o,edges:r}}class ss{constructor(){this.container=null,this.renderer=null,this.scene=null,this.camera=null,this.controls=null,this.graph=null,this.starfield=null,this.nebulaGroup=null,this.starMapLabels=null,this.gridHelper=null,this.animFrameId=0,this.unsubWs=null,this.activeScale="12h",this.time=0,this.nodeCount=150,this.spiralArms=4,this.armSpread=.4,this.coreConcentration=1,this.rotationSpeed=.15,this.showGrid=!0,this.showLabels=!0,this.showEdges=!0,this.pulseNodes=!0,this.sliderRefs=new Map,this.statsEl=null,this.resize=()=>{if(!this.renderer||!this.camera||!this.container)return;const t=this.renderer.domElement.parentElement;if(!t)return;const e=t.clientWidth,i=t.clientHeight;e===0||i===0||(this.renderer.setSize(e,i),this.camera.aspect=e/i,this.camera.updateProjectionMatrix())},this.animate=()=>{var t;if(this.animFrameId=requestAnimationFrame(this.animate),this.time+=.016,(t=this.controls)==null||t.update(),this.starfield&&(this.starfield.rotation.y+=3e-5),this.pulseNodes&&this.graph){const e=.85+.15*Math.sin(this.time*1.5);this.graph.setPulse(e)}this.renderer&&this.scene&&this.camera&&this.renderer.render(this.scene,this.camera)}}mount(t){this.container=t;const e=document.createElement("div");e.style.cssText="display:flex;width:100%;height:100%;overflow:hidden",t.appendChild(e);const i=this.buildSidebar();e.appendChild(i);const s=document.createElement("div");s.style.cssText="flex:1;position:relative;min-width:0",e.appendChild(s);const a=document.createElement("div");a.className="three-container",s.appendChild(a);const n=document.createElement("div");n.className="scale-selector";for(const l of ts){const c=document.createElement("button");c.className="scale-btn",l===this.activeScale&&c.classList.add("active"),c.textContent=l,c.title=this.scaleDescription(l),c.addEventListener("click",()=>this.setScale(l,n)),n.appendChild(c)}a.appendChild(n),this.statsEl=document.createElement("div"),this.statsEl.style.cssText=`
position:absolute;top:12px;left:12px;
padding:10px 14px;max-width:280px;
background:rgba(11,15,20,0.88);border:1px solid var(--border);border-radius:4px;
font-size:11px;color:var(--text-secondary);line-height:1.5;z-index:10;
`,this.statsEl.innerHTML=`
<div style="font-size:13px;font-weight:600;color:var(--text-primary);margin-bottom:4px">Causal Event Atlas</div>
<div>Each point is a <span style="color:var(--accent)">causal event</span> detected in the observation pipeline.
Lines show cause-effect relationships between events. The galaxy structure emerges from how events cluster by domain.</div>
<div id="atlas-stats" style="margin-top:8px;font-family:var(--font-mono);font-size:10px;color:var(--text-muted)"></div>
`,a.appendChild(this.statsEl);const o=document.createElement("div");o.style.cssText=`
position:absolute;bottom:12px;left:12px;
padding:8px 12px;background:rgba(11,15,20,0.88);
border:1px solid var(--border);border-radius:4px;
font-size:10px;color:var(--text-secondary);z-index:10;
`,o.innerHTML=`
<div style="font-size:9px;text-transform:uppercase;letter-spacing:0.5px;margin-bottom:3px">Event Domains</div>
<div style="display:flex;flex-wrap:wrap;gap:6px 12px">
<div style="display:flex;align-items:center;gap:4px"><span style="width:8px;height:8px;border-radius:50%;background:#00E5FF;display:inline-block"></span> Transit</div>
<div style="display:flex;align-items:center;gap:4px"><span style="width:8px;height:8px;border-radius:50%;background:#FF4D4D;display:inline-block"></span> Flare</div>
<div style="display:flex;align-items:center;gap:4px"><span style="width:8px;height:8px;border-radius:50%;background:#2ECC71;display:inline-block"></span> Rotation</div>
<div style="display:flex;align-items:center;gap:4px"><span style="width:8px;height:8px;border-radius:50%;background:#9944FF;display:inline-block"></span> Eclipse</div>
<div style="display:flex;align-items:center;gap:4px"><span style="width:8px;height:8px;border-radius:50%;background:#FFB020;display:inline-block"></span> Variability</div>
</div>
`,a.appendChild(o);const r=document.createElement("div");r.style.cssText="position:absolute;bottom:12px;right:12px;font-size:9px;color:rgba(255,255,255,0.3);z-index:10;pointer-events:none",r.textContent="Drag to rotate | Scroll to zoom | Right-drag to pan",a.appendChild(r),this.initThreeJs(a),this.resize(),window.addEventListener("resize",this.resize),this.loadData(),this.animate(),this.unsubWs=St(l=>{l.event_type==="atlas_update"&&this.loadData()})}buildSidebar(){const t=document.createElement("div");t.style.cssText="width:260px;border-right:1px solid var(--border);background:var(--bg-panel);overflow-y:auto;overflow-x:hidden;flex-shrink:0;display:flex;flex-direction:column";const e=document.createElement("div");e.style.cssText="padding:12px 14px;border-bottom:1px solid var(--border);font-size:11px;font-weight:600;color:var(--text-primary);text-transform:uppercase;letter-spacing:0.5px",e.textContent="Atlas Configuration",t.appendChild(e);const i=document.createElement("div");i.style.cssText="flex:1;overflow-y:auto;padding:10px 12px",t.appendChild(i),this.buildSection(i,"Galaxy Shape","How the causal event network is arranged in 3D space",[{label:"Event count",desc:"Total causal events to display",min:30,max:1200,step:10,value:this.nodeCount,onChange:c=>{this.nodeCount=c,this.loadData()}},{label:"Spiral arms",desc:"Number of galaxy arms (event clusters)",min:2,max:8,step:1,value:this.spiralArms,onChange:c=>{this.spiralArms=c,this.loadData()}},{label:"Arm spread",desc:"How scattered events are within each arm",min:.1,max:1.5,step:.1,value:this.armSpread,onChange:c=>{this.armSpread=c,this.loadData()}},{label:"Core density",desc:"Higher = more events packed near the center",min:.3,max:3,step:.1,value:this.coreConcentration,onChange:c=>{this.coreConcentration=c,this.loadData()}}]),this.buildSection(i,"Animation","Control how the atlas moves and rotates",[{label:"Rotation speed",desc:"How fast the view auto-rotates",min:0,max:2,step:.05,value:this.rotationSpeed,onChange:c=>{this.rotationSpeed=c,this.controls&&(this.controls.autoRotateSpeed=c)}}]);const s=document.createElement("div");s.style.cssText="margin-top:12px",s.innerHTML='<div style="font-size:9px;color:var(--text-secondary);text-transform:uppercase;letter-spacing:0.4px;margin-bottom:8px;font-weight:600">Display Options</div>';const a=[{label:"Show coordinate grid",desc:"Reference grid below the galaxy",checked:this.showGrid,onChange:c=>{this.showGrid=c,this.gridHelper&&(this.gridHelper.visible=c)}},{label:"Show sector labels",desc:"Constellation-style sector names",checked:this.showLabels,onChange:c=>{this.showLabels=c,this.starMapLabels&&(this.starMapLabels.visible=c)}},{label:"Show connections",desc:"Lines between causally linked events",checked:this.showEdges,onChange:c=>{this.showEdges=c,this.loadData()}},{label:"Pulse nodes",desc:"Gentle brightness pulsing on events",checked:this.pulseNodes,onChange:c=>{this.pulseNodes=c}}];for(const c of a){const d=document.createElement("label");d.style.cssText="display:flex;align-items:flex-start;gap:8px;margin-bottom:8px;cursor:pointer";const h=document.createElement("input");h.type="checkbox",h.checked=c.checked,h.style.cssText="accent-color:#00E5FF;margin-top:2px;flex-shrink:0",h.addEventListener("change",()=>c.onChange(h.checked)),d.appendChild(h);const u=document.createElement("div");u.innerHTML=`<div style="font-size:10px;color:var(--text-primary)">${c.label}</div><div style="font-size:9px;color:var(--text-muted);line-height:1.3">${c.desc}</div>`,d.appendChild(u),s.appendChild(d)}i.appendChild(s);const n=document.createElement("div");n.style.cssText="margin-top:12px;padding-top:10px;border-top:1px solid var(--border)",n.innerHTML='<div style="font-size:9px;color:var(--text-secondary);text-transform:uppercase;letter-spacing:0.4px;margin-bottom:6px;font-weight:600">Quick Presets</div>';const o=[{name:"Compact Cluster",nc:60,arms:3,spread:.2,core:2,desc:"Tight event cluster"},{name:"Classic Spiral",nc:200,arms:4,spread:.4,core:1,desc:"Default galaxy layout"},{name:"Open Network",nc:400,arms:6,spread:1,core:.5,desc:"Wide, loose structure"},{name:"Dense Core",nc:800,arms:4,spread:.3,core:2.5,desc:"Many events, tight core"}];for(const c of o){const d=document.createElement("button");d.className="scale-btn",d.style.cssText="width:100%;text-align:left;margin-bottom:4px;padding:6px 10px;font-size:10px",d.innerHTML=`<span style="color:var(--text-primary)">${c.name}</span> <span style="color:var(--text-muted);font-size:9px">${c.desc}</span>`,d.addEventListener("click",()=>{this.nodeCount=c.nc,this.spiralArms=c.arms,this.armSpread=c.spread,this.coreConcentration=c.core,this.syncSlider("Event count",c.nc),this.syncSlider("Spiral arms",c.arms),this.syncSlider("Arm spread",c.spread),this.syncSlider("Core density",c.core),this.loadData()}),n.appendChild(d)}i.appendChild(n);const r=document.createElement("div");r.style.cssText="margin-top:12px;padding-top:10px;border-top:1px solid var(--border)",r.innerHTML=`
<div style="font-size:9px;color:var(--text-secondary);text-transform:uppercase;letter-spacing:0.4px;margin-bottom:6px;font-weight:600">Star Map Sectors</div>
<div style="font-size:9px;color:var(--text-muted);line-height:1.4;margin-bottom:8px">
The galaxy is divided into named sectors based on angular position. Each sector contains events from multiple domains.
</div>
`;const l=document.createElement("div");l.style.cssText="display:grid;grid-template-columns:1fr 1fr;gap:3px";for(let c=0;c<8;c++){const d=Kt[c],h=(c/8*360).toFixed(0),u=document.createElement("div");u.style.cssText="font-size:9px;padding:3px 6px;background:var(--bg-surface);border:1px solid var(--border);border-radius:3px",u.innerHTML=`<span style="color:var(--accent)">${d}</span> <span style="color:var(--text-muted)">${h}°</span>`,l.appendChild(u)}return r.appendChild(l),i.appendChild(r),t}syncSlider(t,e){const i=this.sliderRefs.get(t);i&&(i.slider.value=String(e),i.valEl.textContent=String(Number(i.slider.step)%1===0?Math.round(e):e.toFixed(1)))}buildSection(t,e,i,s){const a=document.createElement("div");a.style.cssText="margin-bottom:14px",a.innerHTML=`
<div style="font-size:9px;color:var(--text-secondary);text-transform:uppercase;letter-spacing:0.4px;margin-bottom:2px;font-weight:600">${e}</div>
<div style="font-size:9px;color:var(--text-muted);line-height:1.3;margin-bottom:8px">${i}</div>
`;for(const n of s){const o=document.createElement("div");o.style.cssText="margin-bottom:8px";const r=document.createElement("div");r.style.cssText="display:flex;justify-content:space-between;align-items:center;margin-bottom:2px";const l=document.createElement("div");l.innerHTML=`<span style="font-size:10px;color:var(--text-primary)">${n.label}</span>`,r.appendChild(l);const c=document.createElement("span");c.style.cssText="font-size:10px;font-family:var(--font-mono);color:var(--accent)",c.textContent=String(n.value),r.appendChild(c),o.appendChild(r);const d=document.createElement("div");d.style.cssText="font-size:8px;color:var(--text-muted);margin-bottom:3px",d.textContent=n.desc,o.appendChild(d);const h=document.createElement("input");h.type="range",h.min=String(n.min),h.max=String(n.max),h.step=String(n.step),h.value=String(n.value),h.style.cssText="width:100%;height:3px;accent-color:#00E5FF;cursor:pointer",h.addEventListener("input",()=>{const u=parseFloat(h.value);c.textContent=String(Number.isInteger(n.step)?Math.round(u):u.toFixed(1)),n.onChange(u)}),o.appendChild(h),this.sliderRefs.set(n.label,{slider:h,valEl:c}),a.appendChild(o)}t.appendChild(a)}scaleDescription(t){return{"2h":"Last 2 hours — recent events only","12h":"Last 12 hours — short-term patterns","3d":"Last 3 days — medium-term connections","27d":"Last 27 days — full rotation cycle"}[t]??t}initThreeJs(t){this.scene=new nt,this.scene.background=new _(329744),this.scene.fog=new ae(329744,.008),this.camera=new at(55,1,.1,1e3),this.camera.position.set(0,10,18),this.camera.lookAt(0,0,0),this.renderer=new ot({antialias:!0}),this.renderer.setPixelRatio(Math.min(window.devicePixelRatio,2)),this.renderer.toneMapping=oe,this.renderer.toneMappingExposure=1.2,t.appendChild(this.renderer.domElement),this.controls=new rt(this.camera,this.renderer.domElement),this.controls.enableDamping=!0,this.controls.dampingFactor=.05,this.controls.autoRotate=!0,this.controls.autoRotateSpeed=this.rotationSpeed,this.controls.minDistance=3,this.controls.maxDistance=80,this.scene.add(new W(16777215,.4));const e=new it(13426175,.3);e.position.set(5,10,5),this.scene.add(e),this.buildStarfield(),this.buildNebula(),this.buildCoordinateGrid(),this.buildStarMapLabels(),this.graph=new We(this.scene)}buildStarfield(){if(!this.scene)return;const t=6e3,e=Ft(42),i=new Float32Array(t*3),s=new Float32Array(t*3);for(let n=0;n<t;n++){const o=e()*Math.PI*2,r=Math.acos(2*e()-1),l=60+e()*300;i[n*3]=l*Math.sin(r)*Math.cos(o),i[n*3+1]=l*Math.sin(r)*Math.sin(o),i[n*3+2]=l*Math.cos(r);const c=e();c<.15?(s[n*3]=.7,s[n*3+1]=.75,s[n*3+2]=1):c<.5?(s[n*3]=.95,s[n*3+1]=.95,s[n*3+2]=1):c<.8?(s[n*3]=1,s[n*3+1]=.92,s[n*3+2]=.8):(s[n*3]=1,s[n*3+1]=.75,s[n*3+2]=.55)}const a=new P;a.setAttribute("position",new F(i,3)),a.setAttribute("color",new F(s,3)),this.starfield=new X(a,new J({size:.6,vertexColors:!0,transparent:!0,opacity:.8,sizeAttenuation:!0,depthWrite:!1})),this.scene.add(this.starfield)}buildNebula(){if(!this.scene)return;this.nebulaGroup=new tt;const t=Ft(555),e=[58879,4456703,16731469,65416,10044671,16756768];for(let i=0;i<8;i++){const s=document.createElement("canvas");s.width=64,s.height=64;const a=s.getContext("2d"),n=a.createRadialGradient(32,32,0,32,32,32),o=e[i%e.length],r=o>>16&255,l=o>>8&255,c=o&255;n.addColorStop(0,`rgba(${r},${l},${c},0.2)`),n.addColorStop(.5,`rgba(${r},${l},${c},0.06)`),n.addColorStop(1,"rgba(0,0,0,0)"),a.fillStyle=n,a.fillRect(0,0,64,64);const d=new Y(s),h=new V(new Z({map:d,transparent:!0,blending:et,opacity:.4})),u=t()*Math.PI*2,m=20+t()*40;h.position.set(Math.cos(u)*m,-5+t()*10,Math.sin(u)*m),h.scale.set(15+t()*25,15+t()*25,1),this.nebulaGroup.add(h)}this.scene.add(this.nebulaGroup)}buildCoordinateGrid(){if(!this.scene)return;this.gridHelper=new tt;const t=new j({color:1713456,transparent:!0,opacity:.4});for(let i=2;i<=10;i+=2){const a=new we(0,0,i,i,0,Math.PI*2,!1,0).getPoints(64),n=new P().setFromPoints(a.map(r=>new A(r.x,0,r.y))),o=new q(n,t);o.position.y=-.05,this.gridHelper.add(o)}const e=new j({color:1713456,transparent:!0,opacity:.3});for(let i=0;i<8;i++){const s=i/8*Math.PI*2,a=[new A(0,-.05,0),new A(Math.cos(s)*10,-.05,Math.sin(s)*10)],n=new P().setFromPoints(a);this.gridHelper.add(new q(n,e))}this.gridHelper.visible=this.showGrid,this.scene.add(this.gridHelper)}buildStarMapLabels(){if(this.scene){this.starMapLabels=new tt;for(let t=0;t<8;t++){const e=t/8*Math.PI*2,i=Kt[t],s=9.5,a=document.createElement("canvas");a.width=128,a.height=32;const n=a.getContext("2d");n.fillStyle="rgba(0,229,255,0.5)",n.font="11px monospace",n.textAlign="center",n.fillText(i,64,20);const o=new Y(a),r=new V(new Z({map:o,transparent:!0}));r.position.set(Math.cos(e)*s,.5,Math.sin(e)*s),r.scale.set(3,.75,1),this.starMapLabels.add(r)}this.starMapLabels.visible=this.showLabels,this.scene.add(this.starMapLabels)}}setScale(t,e){this.activeScale=t,e.querySelectorAll(".scale-btn").forEach(i=>{i.classList.toggle("active",i.textContent===t)}),this.loadData()}async loadData(){if(!(!this.graph||!this.scene))try{const t=await je(this.activeScale);if(!this.graph)return;const e=[{id:t.event_id,domain:"transit",x:0,y:0,z:0,weight:t.weight}];for(const s of t.parents)e.push({id:s,domain:"rotation",weight:.5,x:(Math.random()-.5)*6,y:(Math.random()-.5)*1,z:(Math.random()-.5)*6});for(const s of t.children)e.push({id:s,domain:"flare",weight:.5,x:(Math.random()-.5)*6,y:(Math.random()-.5)*1,z:(Math.random()-.5)*6});const i=[...t.parents.map(s=>({source:s,target:t.event_id,weight:t.weight})),...t.children.map(s=>({source:t.event_id,target:s,weight:t.weight}))];this.graph.setNodes(e),this.showEdges&&this.graph.setEdges(i,e),this.updateStats(e.length,i.length)}catch{if(!this.graph)return;const t=es(this.activeScale,this.nodeCount,this.spiralArms,this.armSpread,this.coreConcentration);this.graph.setNodes(t.nodes),this.showEdges?this.graph.setEdges(t.edges,t.nodes):this.graph.setEdges([],t.nodes),this.updateStats(t.nodes.length,this.showEdges?t.edges.length:0)}}updateStats(t,e){var s;const i=(s=this.statsEl)==null?void 0:s.querySelector("#atlas-stats");i&&(i.innerHTML=`Events: <span style="color:var(--accent)">${t}</span> | Connections: <span style="color:var(--accent)">${e}</span> | Scale: <span style="color:var(--accent)">${this.activeScale}</span> | Arms: <span style="color:var(--accent)">${this.spiralArms}</span>`)}unmount(){var t,e,i,s,a,n,o,r;if(window.removeEventListener("resize",this.resize),cancelAnimationFrame(this.animFrameId),(t=this.unsubWs)==null||t.call(this),this.starfield&&((e=this.scene)==null||e.remove(this.starfield),this.starfield.geometry.dispose(),this.starfield.material.dispose(),this.starfield=null),this.nebulaGroup){for(const l of this.nebulaGroup.children)(l instanceof L||l instanceof V)&&("geometry"in l&&l.geometry.dispose(),l.material.dispose());(i=this.scene)==null||i.remove(this.nebulaGroup),this.nebulaGroup=null}this.gridHelper&&((s=this.scene)==null||s.remove(this.gridHelper),this.gridHelper=null),this.starMapLabels&&((a=this.scene)==null||a.remove(this.starMapLabels),this.starMapLabels=null),(n=this.graph)==null||n.dispose(),(o=this.controls)==null||o.dispose(),(r=this.renderer)==null||r.dispose(),this.graph=null,this.controls=null,this.renderer=null,this.scene=null,this.camera=null,this.container=null}}class is{constructor(t,e=64,i=64){this.mesh=null,this.wireframe=null,this.contourLines=null,this.gridLabels=null,this.scene=t,this.gridWidth=e,this.gridHeight=i,this.createMesh(),this.createGridLabels()}createMesh(){const t=new Rt(10,10,this.gridWidth-1,this.gridHeight-1),e=t.attributes.position.count,i=new Float32Array(e*3);for(let o=0;o<e;o++)i[o*3]=0,i[o*3+1]=.3,i[o*3+2]=.5;t.setAttribute("color",new F(i,3));const s=new Ee({vertexColors:!0,side:xt,shininess:40,specular:new _(1122867),flatShading:!1});this.mesh=new L(t,s),this.mesh.rotation.x=-Math.PI/2,this.scene.add(this.mesh);const a=new Wt(t),n=new j({color:1844019,transparent:!0,opacity:.12});this.wireframe=new gt(a,n),this.wireframe.rotation.x=-Math.PI/2,this.scene.add(this.wireframe)}createGridLabels(){this.gridLabels=new tt;const t=new Tt(10,8,1844019,1251874);t.position.y=-.01,this.gridLabels.add(t);const e=new j({color:2765892,transparent:!0,opacity:.5}),i=new P().setFromPoints([new A(-5.5,0,5.5),new A(5.5,0,5.5)]);this.gridLabels.add(new q(i,e));const s=new P().setFromPoints([new A(-5.5,0,5.5),new A(-5.5,0,-5.5)]);this.gridLabels.add(new q(s,e)),this.scene.add(this.gridLabels)}valueToColor(t,e){if(t>.85){const i=(t-.85)/.15;e.setRGB(0,.4+i*.1,.6+i*.4)}else if(t>.75){const i=(t-.75)/.1;e.setRGB(1-i*1,.7+i*.2,i*.6)}else if(t>.65){const i=(t-.65)/.1;e.setRGB(1,.5+i*.2,i*.1)}else{const i=Math.max(0,t/.65);e.setRGB(.9+i*.1,.15+i*.35,.1)}}setValues(t){if(!this.mesh)return;const e=this.mesh.geometry,i=e.attributes.color,s=e.attributes.position,a=Math.min(t.length,i.count),n=new _;for(let o=0;o<a;o++){const r=Math.max(0,Math.min(1,t[o]));this.valueToColor(r,n),i.setXYZ(o,n.r,n.g,n.b);const l=(1-r)*2.5;s.setZ(o,l)}i.needsUpdate=!0,s.needsUpdate=!0,e.computeVertexNormals(),this.updateWireframe(e),this.updateContours(t)}updateWireframe(t){this.wireframe&&(this.scene.remove(this.wireframe),this.wireframe.geometry.dispose(),this.wireframe.material.dispose());const e=new Wt(t),i=new j({color:1844019,transparent:!0,opacity:.12});this.wireframe=new gt(e,i),this.wireframe.rotation.x=-Math.PI/2,this.scene.add(this.wireframe)}updateContours(t){this.contourLines&&(this.scene.remove(this.contourLines),this.contourLines.traverse(n=>{n instanceof q&&(n.geometry.dispose(),n.material.dispose())})),this.contourLines=new tt;const e=this.gridWidth,i=this.gridHeight,s=5,a=[{level:.8,color:16756768,opacity:.6},{level:.7,color:16731469,opacity:.7}];for(const n of a){const o=[];for(let r=0;r<i-1;r++)for(let l=0;l<e-1;l++){const c=t[r*e+l]??1,d=t[r*e+l+1]??1,h=t[(r+1)*e+l]??1;if((c-n.level)*(d-n.level)<0){const u=(n.level-c)/(d-c),m=-s+(l+u)/(e-1)*s*2,g=-s+r/(i-1)*s*2,x=(1-n.level)*2.5;o.push(new A(m,x+.02,g))}if((c-n.level)*(h-n.level)<0){const u=(n.level-c)/(h-c),m=-s+l/(e-1)*s*2,g=-s+(r+u)/(i-1)*s*2,x=(1-n.level)*2.5;o.push(new A(m,x+.02,g))}}if(o.length>1){const r=new P().setFromPoints(o),l=new J({color:n.color,size:.08,transparent:!0,opacity:n.opacity,depthWrite:!1});this.contourLines.add(new X(r,l))}}this.scene.add(this.contourLines)}dispose(){this.mesh&&(this.scene.remove(this.mesh),this.mesh.geometry.dispose(),this.mesh.material.dispose(),this.mesh=null),this.wireframe&&(this.scene.remove(this.wireframe),this.wireframe.geometry.dispose(),this.wireframe.material.dispose(),this.wireframe=null),this.contourLines&&(this.scene.remove(this.contourLines),this.contourLines.traverse(t=>{(t instanceof q||t instanceof X)&&(t.geometry.dispose(),t.material.dispose())}),this.contourLines=null),this.gridLabels&&(this.scene.remove(this.gridLabels),this.gridLabels=null)}}function ns(p,t){const e=[],i=t*.1;for(let s=0;s<p;s++)for(let a=0;a<p;a++){const n=a/p,o=s/p,r=.5+.3*Math.sin(n*6+i)*Math.cos(o*6+i)+.2*Math.sin((n+o)*4+i*.5);e.push(Math.max(0,Math.min(1,r)))}return e}function as(p){if(p.length===0)return{mean:0,min:0,max:0,violations:0};let t=0,e=1,i=0,s=0;for(const a of p)t+=a,a<e&&(e=a),a>i&&(i=a),a<.8&&s++;return{mean:t/p.length,min:e,max:i,violations:s}}class os{constructor(){this.container=null,this.renderer=null,this.scene=null,this.camera=null,this.controls=null,this.surface=null,this.animFrameId=0,this.currentEpoch=0,this.gridSize=64,this.currentValues=[],this.hud=null,this.metricsEls={},this.alertList=null,this.raycaster=new Ce,this.mouse=new G,this.onMouseMove=t=>{var a;if(!this.renderer||!this.camera||!this.hud)return;const e=this.renderer.domElement.getBoundingClientRect();this.mouse.x=(t.clientX-e.left)/e.width*2-1,this.mouse.y=-((t.clientY-e.top)/e.height)*2+1,this.raycaster.setFromCamera(this.mouse,this.camera);const i=((a=this.scene)==null?void 0:a.children.filter(n=>n instanceof L))??[],s=this.raycaster.intersectObjects(i);if(s.length>0&&this.currentValues.length>0){const o=s[0].point,r=Math.round((o.x+5)/10*(this.gridSize-1)),l=Math.round((o.z+5)/10*(this.gridSize-1));if(r>=0&&r<this.gridSize&&l>=0&&l<this.gridSize){const c=l*this.gridSize+r,d=this.currentValues[c];if(d!==void 0){const h=d>=.85?"STABLE":d>=.8?"NOMINAL":d>=.7?"WARNING":"CRITICAL",u=d>=.85?"var(--accent)":d>=.8?"var(--text-primary)":d>=.7?"var(--warning)":"var(--critical)";this.hud.style.display="block",this.hud.innerHTML=`
<div style="color:var(--text-muted)">Sector (${r}, ${l})</div>
<div style="font-size:16px;font-weight:600;color:${u}">${d.toFixed(3)}</div>
<div style="color:${u};font-size:10px">${h}</div>
`;return}}}this.hud&&(this.hud.style.display="none")},this.resize=()=>{if(!this.renderer||!this.camera||!this.container)return;const t=this.renderer.domElement.parentElement;if(!t)return;const e=t.clientWidth,i=t.clientHeight;this.renderer.setSize(e,i),this.camera.aspect=e/i,this.camera.updateProjectionMatrix()},this.animate=()=>{var t;this.animFrameId=requestAnimationFrame(this.animate),(t=this.controls)==null||t.update(),this.renderer&&this.scene&&this.camera&&this.renderer.render(this.scene,this.camera)}}mount(t){this.container=t;const e=document.createElement("div");e.style.cssText="display:flex;flex-direction:column;width:100%;height:100%;overflow:hidden",t.appendChild(e);const i=document.createElement("div");i.style.cssText="padding:12px 20px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:16px;flex-shrink:0",i.innerHTML=`
<div style="flex:1">
<div style="font-size:14px;font-weight:600;color:var(--text-primary);margin-bottom:2px">Coherence Field</div>
<div style="font-size:11px;color:var(--text-secondary);line-height:1.4">
Measures causal consistency across the event graph. High coherence (blue, flat) = events agree.
Low coherence (red, raised peaks) = conflicting evidence or boundary pressure.
Warning threshold at 0.80, critical at 0.70.
</div>
</div>
`,e.appendChild(i);const s=document.createElement("div");s.style.cssText="display:flex;gap:12px;padding:12px 20px;flex-shrink:0;flex-wrap:wrap";const a=[{key:"mean",label:"MEAN COHERENCE",icon:"~"},{key:"min",label:"MINIMUM",icon:"v"},{key:"max",label:"MAXIMUM",icon:"^"},{key:"violations",label:"BELOW THRESHOLD",icon:"!"}];for(const w of a){const y=document.createElement("div");y.className="metric-card",y.style.cssText="flex:1;min-width:140px";const b=document.createElement("div");b.className="metric-value",b.textContent="--";const v=document.createElement("div");v.className="metric-label",v.textContent=w.label,y.appendChild(v),y.appendChild(b),s.appendChild(y),this.metricsEls[w.key]=b}e.appendChild(s);const n=document.createElement("div");n.style.cssText="flex:1;display:flex;overflow:hidden;min-height:0",e.appendChild(n);const o=document.createElement("div");o.className="three-container",o.style.flex="1",n.appendChild(o),this.hud=document.createElement("div"),this.hud.style.cssText=`
position:absolute;top:12px;left:12px;
padding:8px 12px;background:rgba(11,15,20,0.92);
border:1px solid var(--border);border-radius:4px;
font-family:var(--font-mono);font-size:11px;color:var(--text-secondary);
pointer-events:none;display:none;z-index:10;line-height:1.6;
`,o.appendChild(this.hud);const r=document.createElement("div");r.style.cssText=`
position:absolute;bottom:12px;right:12px;
padding:8px 12px;background:rgba(11,15,20,0.9);
border:1px solid var(--border);border-radius:4px;
font-family:var(--font-mono);font-size:10px;color:var(--text-secondary);
z-index:10;display:flex;flex-direction:column;gap:4px;
`,r.innerHTML=`
<div style="font-size:9px;text-transform:uppercase;letter-spacing:0.5px;margin-bottom:2px">Coherence Scale</div>
<div style="display:flex;align-items:center;gap:6px">
<div style="width:60px;height:6px;border-radius:3px;background:linear-gradient(to right,#FF4D4D,#FFB020,#00E5FF,#0044AA)"></div>
</div>
<div style="display:flex;justify-content:space-between;width:60px">
<span>0.6</span><span>0.8</span><span>1.0</span>
</div>
<div style="margin-top:4px;display:flex;flex-direction:column;gap:2px">
<div style="display:flex;align-items:center;gap:4px"><span style="width:6px;height:6px;border-radius:50%;background:#FFB020;display:inline-block"></span> Warning &lt;0.80</div>
<div style="display:flex;align-items:center;gap:4px"><span style="width:6px;height:6px;border-radius:50%;background:#FF4D4D;display:inline-block"></span> Critical &lt;0.70</div>
</div>
`,o.appendChild(r);const l=document.createElement("div");l.style.cssText=`
position:absolute;bottom:12px;left:12px;
font-size:10px;color:var(--text-muted);font-family:var(--font-mono);
z-index:10;pointer-events:none;
`,l.textContent="Drag to rotate, scroll to zoom, hover for values",o.appendChild(l);const c=document.createElement("div");c.style.cssText="width:240px;background:var(--bg-panel);border-left:1px solid var(--border);display:flex;flex-direction:column;overflow:hidden;flex-shrink:0";const d=document.createElement("div");d.className="panel-header",d.textContent="Active Alerts",c.appendChild(d),this.alertList=document.createElement("div"),this.alertList.style.cssText="flex:1;overflow-y:auto;padding:4px 0",c.appendChild(this.alertList),n.appendChild(c);const h=document.createElement("div");h.className="time-scrubber",h.style.flexShrink="0";const u=document.createElement("span");u.className="time-scrubber-title",u.textContent="Epoch",h.appendChild(u);const m=document.createElement("input");m.type="range",m.className="time-scrubber-range",m.min="0",m.max="100",m.value="0",h.appendChild(m);const g=document.createElement("span");g.className="time-scrubber-label",g.textContent="E0",h.appendChild(g),m.addEventListener("input",()=>{const w=Number(m.value);g.textContent=`E${w}`,this.currentEpoch=w,this.loadData(w)}),e.appendChild(h),this.scene=new nt,this.scene.background=new _(724756),this.camera=new at(50,1,.1,100),this.camera.position.set(4,7,10),this.camera.lookAt(0,0,0),this.renderer=new ot({antialias:!0}),this.renderer.setPixelRatio(window.devicePixelRatio),o.appendChild(this.renderer.domElement),this.controls=new rt(this.camera,this.renderer.domElement),this.controls.enableDamping=!0,this.controls.dampingFactor=.1,this.controls.maxPolarAngle=Math.PI*.45,this.controls.minDistance=4,this.controls.maxDistance=30,this.scene.add(new W(16777215,.4));const x=new it(13426175,.6);x.position.set(5,10,5),this.scene.add(x);const f=new it(4491434,.3);f.position.set(-5,3,-5),this.scene.add(f),this.surface=new is(this.scene,this.gridSize,this.gridSize),o.addEventListener("mousemove",this.onMouseMove),this.resize(),window.addEventListener("resize",this.resize),this.loadData(0),this.loadAlerts(),this.animate()}updateMetrics(t){const e=as(t),i=(s,a,n)=>{const o=this.metricsEls[s];o&&(o.textContent=a,o.className="metric-value"+(n?` ${n}`:""))};i("mean",e.mean.toFixed(3),e.mean>=.85?"accent":e.mean>=.8?"":"warning"),i("min",e.min.toFixed(3),e.min>=.8?"success":e.min>=.7?"warning":"critical"),i("max",e.max.toFixed(3),"accent"),i("violations",`${e.violations}`,e.violations===0?"success":e.violations<100?"warning":"critical")}async loadAlerts(){if(this.alertList)try{const t=await pe();this.renderAlerts(t)}catch{this.renderAlerts([{target_id:"7G",epoch:7,pressure:.74,message:"Coherence drop in sector 7G (0.74)"},{target_id:"3A",epoch:5,pressure:.62,message:"Witness chain gap in sector 3A"},{target_id:"global",epoch:7,pressure:.79,message:"Boundary expansion +14.5%"}])}}renderAlerts(t){if(this.alertList){if(this.alertList.innerHTML="",t.length===0){this.alertList.innerHTML='<div style="padding:16px;color:var(--text-muted);font-size:11px;text-align:center">No active alerts</div>';return}for(const e of t){const i=e.pressure<.7?"critical":e.pressure<.8?"warning":"success",s=document.createElement("div");s.className="alert-item",s.innerHTML=`
<div class="alert-dot ${i}"></div>
<div style="flex:1">
<div style="font-size:11px;color:var(--text-primary);margin-bottom:2px">${e.message}</div>
<div style="font-size:10px;color:var(--text-muted);font-family:var(--font-mono)">Sector ${e.target_id} | Coherence: ${e.pressure.toFixed(2)}</div>
</div>
`,this.alertList.appendChild(s)}}}async loadData(t){if(this.surface)try{const e=await Ve("default",t);this.currentValues=e.map(i=>i.value),this.surface.setValues(this.currentValues),this.updateMetrics(this.currentValues)}catch{this.currentValues=ns(this.gridSize,t),this.surface.setValues(this.currentValues),this.updateMetrics(this.currentValues)}}unmount(){var t,e,i;window.removeEventListener("resize",this.resize),cancelAnimationFrame(this.animFrameId),(t=this.surface)==null||t.dispose(),(e=this.controls)==null||e.dispose(),(i=this.renderer)==null||i.dispose(),this.surface=null,this.controls=null,this.renderer=null,this.scene=null,this.camera=null,this.container=null,this.hud=null,this.alertList=null,this.metricsEls={}}}class rs{constructor(){this.container=null,this.chartCanvas=null,this.alertsEl=null,this.unsubWs=null,this.pollTimer=null,this.points=[]}mount(t){this.container=t;const e=document.createElement("div");e.className="grid-12",t.appendChild(e);const i=document.createElement("div");i.className="col-12",i.style.cssText="padding:4px 0 8px 0",i.innerHTML=`
<div style="font-size:14px;font-weight:600;color:var(--text-primary);margin-bottom:2px">Boundary Tracking</div>
<div style="font-size:11px;color:var(--text-secondary);line-height:1.5">
Monitors the <span style="color:var(--accent)">causal boundary</span> &mdash; the expanding frontier where new events enter the graph.
<strong>Instability</strong> = average boundary pressure (lower is better).
<strong>Crossings</strong> = epochs where coherence dropped below 0.80 threshold.
Amber ticks on the timeline mark boundary crossing events. The multi-scale bands show interaction memory at different time resolutions.
</div>
`,e.appendChild(i);const s=this.createMetricCard("Boundary Instability","--","accent");s.className+=" col-4",e.appendChild(s);const a=this.createMetricCard("Crossings Detected","--","");a.className+=" col-4",e.appendChild(a);const n=this.createMetricCard("Active Alerts","--","");n.className+=" col-4",e.appendChild(n);const o=document.createElement("div");o.className="panel col-12";const r=document.createElement("div");r.className="panel-header",r.textContent="Boundary Evolution Timeline",o.appendChild(r);const l=document.createElement("div");l.className="panel-body",l.style.height="280px",l.style.padding="12px",this.chartCanvas=document.createElement("canvas"),this.chartCanvas.style.width="100%",this.chartCanvas.style.height="100%",this.chartCanvas.style.display="block",l.appendChild(this.chartCanvas),o.appendChild(l),e.appendChild(o);const c=document.createElement("div");c.className="panel col-12";const d=document.createElement("div");d.className="panel-header",d.textContent="Multi-Scale Interaction Memory",c.appendChild(d);const h=document.createElement("div");h.className="panel-body",h.style.height="64px";const u=document.createElement("canvas");u.style.width="100%",u.style.height="100%",u.style.display="block",h.appendChild(u),c.appendChild(h),e.appendChild(c),this.renderScaleBands(u);const m=document.createElement("div");m.className="panel col-12";const g=document.createElement("div");g.className="panel-header",g.textContent="Boundary Alerts",m.appendChild(g),this.alertsEl=document.createElement("div"),this.alertsEl.className="panel-body",this.alertsEl.style.maxHeight="240px",this.alertsEl.style.overflowY="auto",this.alertsEl.style.padding="0",m.appendChild(this.alertsEl),e.appendChild(m),this.loadData(s,a,n),this.pollTimer=setInterval(()=>{this.loadData(s,a,n)},8e3),this.unsubWs=St(x=>{x.event_type==="boundary_alert"&&this.loadData(s,a,n)})}createMetricCard(t,e,i){const s=document.createElement("div");return s.className="metric-card",s.innerHTML=`
<span class="metric-label">${t}</span>
<span class="metric-value ${i}" data-metric>${e}</span>
<span class="metric-sub" data-sub></span>
`,s}async loadData(t,e,i){let s,a;try{s=await qe("default")}catch{s=this.generateDemoTimeline()}try{a=await pe()}catch{a=this.generateDemoAlerts()}this.points=s;const n=s.length>0?s.reduce((d,h)=>d+h.pressure,0)/s.length:0,o=s.filter(d=>d.crossed).length,r=t.querySelector("[data-metric]");r&&(r.textContent=n.toFixed(3));const l=e.querySelector("[data-metric]");l&&(l.textContent=String(o));const c=i.querySelector("[data-metric]");c&&(c.textContent=String(a.length),c.className=`metric-value ${a.length>3?"critical":a.length>0?"warning":"success"}`),this.renderChart(),this.renderAlerts(a)}renderChart(){var d;const t=this.chartCanvas;if(!t)return;const e=(d=t.parentElement)==null?void 0:d.getBoundingClientRect();if(!e)return;const i=window.devicePixelRatio||1;t.width=e.width*i,t.height=e.height*i;const s=t.getContext("2d");if(!s)return;s.scale(i,i);const a=e.width,n=e.height,o={top:8,right:12,bottom:24,left:40},r=a-o.left-o.right,l=n-o.top-o.bottom;if(s.clearRect(0,0,a,n),this.points.length===0)return;const c=Math.max(...this.points.map(h=>h.pressure),1);s.strokeStyle="#1E2630",s.lineWidth=1;for(let h=0;h<=4;h++){const u=o.top+l*h/4;s.beginPath(),s.moveTo(o.left,u),s.lineTo(o.left+r,u),s.stroke()}s.fillStyle="#484F58",s.font='10px "JetBrains Mono", monospace',s.textAlign="right";for(let h=0;h<=4;h++){const u=o.top+l*h/4,m=c*(1-h/4);s.fillText(m.toFixed(2),o.left-6,u+3)}s.strokeStyle="#00E5FF",s.lineWidth=1.5,s.beginPath(),this.points.forEach((h,u)=>{const m=o.left+u/(this.points.length-1)*r,g=o.top+l-h.pressure/c*l;u===0?s.moveTo(m,g):s.lineTo(m,g)}),s.stroke(),s.strokeStyle="#FFB020",s.lineWidth=1,this.points.forEach((h,u)=>{if(h.crossed){const m=o.left+u/(this.points.length-1)*r;s.beginPath(),s.moveTo(m,o.top),s.lineTo(m,o.top+l),s.stroke()}})}renderAlerts(t){if(this.alertsEl){if(this.alertsEl.innerHTML="",t.length===0){this.alertsEl.innerHTML='<div class="empty-state" style="height:60px">No active alerts</div>';return}for(const e of t){const i=document.createElement("div");i.className="alert-item";const s=e.pressure<.5?"critical":e.pressure<.8?"warning":"success";i.innerHTML=`
<span class="alert-dot ${s}"></span>
<span class="alert-msg">${e.message}</span>
<span class="alert-sector">${e.target_id}</span>
`,this.alertsEl.appendChild(i)}}}renderScaleBands(t){requestAnimationFrame(()=>{var c;const e=(c=t.parentElement)==null?void 0:c.getBoundingClientRect();if(!e)return;const i=window.devicePixelRatio||1;t.width=e.width*i,t.height=e.height*i;const s=t.getContext("2d");if(!s)return;s.scale(i,i);const a=e.width,n=e.height,o=[{label:"Seconds",color:"#00E5FF",height:n*.33},{label:"Hours",color:"#0099AA",height:n*.33},{label:"Days",color:"#006677",height:n*.34}];let r=0;for(const d of o)s.fillStyle=d.color,s.globalAlpha=.2,s.fillRect(0,r,a,d.height),s.globalAlpha=1,s.fillStyle="#8B949E",s.font='9px "JetBrains Mono", monospace',s.fillText(d.label,4,r+d.height/2+3),r+=d.height;const l=8;s.strokeStyle="#FFB020",s.lineWidth=1,s.globalAlpha=.7;for(let d=0;d<l;d++){const h=a*(d+1)/(l+1)+Math.sin(d*3.14)*20;s.beginPath(),s.moveTo(h,0),s.lineTo(h,n),s.stroke()}s.globalAlpha=1})}generateDemoTimeline(){const t=[];for(let e=0;e<50;e++){const i=.7+.25*Math.sin(e*.3)+(Math.random()-.5)*.1;t.push({epoch:e,pressure:Math.max(0,i),crossed:i<.75})}return t}generateDemoAlerts(){return[{target_id:"sector-7G",epoch:42,pressure:.62,message:"Coherence below threshold in sector 7G"},{target_id:"sector-3A",epoch:38,pressure:.71,message:"Boundary radius expanding in sector 3A"},{target_id:"sector-12F",epoch:45,pressure:.45,message:"Critical instability detected in sector 12F"}]}unmount(){var t;this.pollTimer&&(clearInterval(this.pollTimer),this.pollTimer=null),(t=this.unsubWs)==null||t.call(this),this.chartCanvas=null,this.alertsEl=null,this.container=null}}class ls{constructor(){this.container=null,this.gaugesEl=null,this.detailEl=null,this.pollTimer=null}mount(t){this.container=t;const e=document.createElement("div");e.className="grid-12",t.appendChild(e);const i=document.createElement("div");i.className="col-12",i.style.cssText="padding:4px 0 8px 0",i.innerHTML=`
<div style="font-size:14px;font-weight:600;color:var(--text-primary);margin-bottom:2px">Memory Tiers</div>
<div style="font-size:11px;color:var(--text-secondary);line-height:1.5">
RVF uses a <span style="color:var(--accent)">3-tier memory hierarchy</span> for vector storage and retrieval.
<strong>S (Hot/L1)</strong> = fastest access (&lt;1&mu;s), recent data in CPU cache.
<strong>M (Warm/HNSW)</strong> = indexed vectors (~12&mu;s), approximate nearest-neighbor graph.
<strong>L (Cold/Disk)</strong> = archived segments (~450&mu;s), full scan on demand.
Utilization above 90% triggers tier promotion/eviction policies.
</div>
`,e.appendChild(i);const s=this.createMetricCard("Total Entries","--","");s.className+=" col-4",e.appendChild(s);const a=this.createMetricCard("Used Capacity","--","accent");a.className+=" col-4",e.appendChild(a);const n=this.createMetricCard("Avg Utilization","--","");n.className+=" col-4",e.appendChild(n);const o=document.createElement("div");o.className="panel col-12";const r=document.createElement("div");r.className="panel-header",r.textContent="Memory Tier Utilization",o.appendChild(r),this.gaugesEl=document.createElement("div"),this.gaugesEl.className="panel-body",this.gaugesEl.style.display="flex",this.gaugesEl.style.justifyContent="center",this.gaugesEl.style.gap="48px",this.gaugesEl.style.padding="24px",o.appendChild(this.gaugesEl),e.appendChild(o);const l=document.createElement("div");l.className="panel col-12";const c=document.createElement("div");c.className="panel-header",c.textContent="Tier Details",l.appendChild(c),this.detailEl=document.createElement("div"),this.detailEl.style.padding="0",l.appendChild(this.detailEl),e.appendChild(l),this.loadData(s,a,n),this.pollTimer=setInterval(()=>{this.loadData(s,a,n)},5e3)}createMetricCard(t,e,i){const s=document.createElement("div");return s.className="metric-card",s.innerHTML=`
<span class="metric-label">${t}</span>
<span class="metric-value ${i}" data-metric>${e}</span>
`,s}async loadData(t,e,i){let s;try{s=await ge()}catch{s={small:{used:42,total:64},medium:{used:288,total:512},large:{used:1843,total:8192}}}const a=s.small.used+s.medium.used+s.large.used,n=s.small.total+s.medium.total+s.large.total,o=n>0?a/n:0,r=t.querySelector("[data-metric]");r&&(r.textContent=`${n} MB`);const l=e.querySelector("[data-metric]");l&&(l.textContent=`${a} MB`);const c=i.querySelector("[data-metric]");c&&(c.textContent=`${(o*100).toFixed(1)}%`,c.className=`metric-value ${o>.9?"critical":o>.7?"warning":"success"}`),this.renderGauges(s),this.renderDetail(s)}renderGauges(t){if(!this.gaugesEl)return;this.gaugesEl.innerHTML="";const e=[{label:"S - Hot / L1",sublabel:"Cache",...t.small,color:"#00E5FF"},{label:"M - Warm / HNSW",sublabel:"Index",...t.medium,color:"#2ECC71"},{label:"L - Cold / Disk",sublabel:"Segments",...t.large,color:"#FFB020"}];for(const i of e){const s=i.total>0?i.used/i.total:0,a=document.createElement("div");a.className="gauge",a.style.width="140px";const n=document.createElementNS("http://www.w3.org/2000/svg","svg");n.setAttribute("viewBox","0 0 80 80"),n.classList.add("gauge-ring");const o=document.createElementNS("http://www.w3.org/2000/svg","circle");o.setAttribute("cx","40"),o.setAttribute("cy","40"),o.setAttribute("r","34"),o.setAttribute("fill","none"),o.setAttribute("stroke","#1E2630"),o.setAttribute("stroke-width","4"),n.appendChild(o);const r=2*Math.PI*34,l=document.createElementNS("http://www.w3.org/2000/svg","circle");l.setAttribute("cx","40"),l.setAttribute("cy","40"),l.setAttribute("r","34"),l.setAttribute("fill","none"),l.setAttribute("stroke",s>.9?"#FF4D4D":s>.7?"#FFB020":i.color),l.setAttribute("stroke-width","4"),l.setAttribute("stroke-dasharray",`${r*s} ${r*(1-s)}`),l.setAttribute("stroke-dashoffset",`${r*.25}`),l.setAttribute("stroke-linecap","round"),n.appendChild(l);const c=document.createElementNS("http://www.w3.org/2000/svg","text");c.setAttribute("x","40"),c.setAttribute("y","42"),c.setAttribute("text-anchor","middle"),c.setAttribute("fill","#E6EDF3"),c.setAttribute("font-size","13"),c.setAttribute("font-weight","500"),c.setAttribute("font-family",'"JetBrains Mono", monospace'),c.textContent=`${(s*100).toFixed(0)}%`,n.appendChild(c),a.appendChild(n);const d=document.createElement("div");d.className="gauge-label",d.style.textAlign="center",d.style.lineHeight="1.4",d.innerHTML=`${i.label}<br><span style="color:#484F58;font-size:9px">${i.used} / ${i.total} MB</span>`,a.appendChild(d),this.gaugesEl.appendChild(a)}}renderDetail(t){if(!this.detailEl)return;const e=[{tier:"S",name:"Hot / L1 Cache",...t.small,latency:"0.8 us"},{tier:"M",name:"Warm / HNSW Index",...t.medium,latency:"12.4 us"},{tier:"L",name:"Cold / Disk Segments",...t.large,latency:"450 us"}];this.detailEl.innerHTML=`
<table class="data-table">
<thead>
<tr>
<th>Tier</th>
<th>Name</th>
<th>Used</th>
<th>Capacity</th>
<th>Utilization</th>
<th>Avg Latency</th>
</tr>
</thead>
<tbody>
${e.map(i=>{const s=i.total>0?i.used/i.total:0;return`<tr>
<td>${i.tier}</td>
<td style="font-family:var(--font-sans)">${i.name}</td>
<td>${i.used} MB</td>
<td>${i.total} MB</td>
<td><span class="score-badge score-${s>.7?s>.9?"low":"medium":"high"}">${(s*100).toFixed(1)}%</span></td>
<td>${i.latency}</td>
</tr>`}).join("")}
</tbody>
</table>
`}unmount(){this.pollTimer&&(clearInterval(this.pollTimer),this.pollTimer=null),this.gaugesEl=null,this.detailEl=null,this.container=null}}class ds{constructor(t){this.svg=null,this.wrapper=null,this.tooltip=null,this.crosshairLine=null,this.crosshairDot=null,this.margin={top:28,right:16,bottom:40,left:52},this.lastData=[],this.lastTransits=[],this.onMouseMove=e=>{if(!this.svg||!this.tooltip||!this.wrapper||this.lastData.length===0)return;const i=this.svg.getBoundingClientRect(),s=i.width,a=i.height,n=e.clientX-i.left,o=e.clientY-i.top,r=this.margin,l=s-r.left-r.right,c=a-r.top-r.bottom,d=n-r.left;if(d<0||d>l){this.onMouseLeave();return}const h=[this.lastData[0].time,this.lastData[this.lastData.length-1].time],u=d/l,m=h[0]+u*(h[1]-h[0]);let g=0,x=this.lastData.length-1;for(;g<x-1;){const S=g+x>>1;this.lastData[S].time<m?g=S:x=S}const f=Math.abs(this.lastData[g].time-m)<Math.abs(this.lastData[x].time-m)?this.lastData[g]:this.lastData[x];let w=this.lastData[0].flux,y=this.lastData[0].flux;for(let S=1;S<this.lastData.length;S++)this.lastData[S].flux<w&&(w=this.lastData[S].flux),this.lastData[S].flux>y&&(y=this.lastData[S].flux);const b=(y-w)*.1||.001,v=(f.flux-(w-b))/(y+b-(w-b)),E=r.top+c*(1-v),C=r.left+(f.time-h[0])/(h[1]-h[0])*l,T=this.lastTransits.some(S=>f.time>=S.start&&f.time<=S.end);this.crosshairLine&&(this.crosshairLine.setAttribute("x1",String(C)),this.crosshairLine.setAttribute("x2",String(C)),this.crosshairLine.setAttribute("y1",String(r.top)),this.crosshairLine.setAttribute("y2",String(r.top+c)),this.crosshairLine.style.display=""),this.crosshairDot&&(this.crosshairDot.setAttribute("cx",String(C)),this.crosshairDot.setAttribute("cy",String(E)),this.crosshairDot.style.display="");const R=T?'<span style="color:#FF4D4D;font-weight:600"> TRANSIT</span>':"";this.tooltip.innerHTML=`<div>Time: <strong>${f.time.toFixed(2)} d</strong></div><div>Flux: <strong>${f.flux.toFixed(5)}</strong>${R}</div>`,this.tooltip.style.display="block";const k=n+14,M=o-10;this.tooltip.style.left=`${k}px`,this.tooltip.style.top=`${M}px`},this.onMouseLeave=()=>{this.tooltip&&(this.tooltip.style.display="none"),this.crosshairLine&&(this.crosshairLine.style.display="none"),this.crosshairDot&&(this.crosshairDot.style.display="none")},this.container=t,this.createSvg()}createSvg(){this.wrapper=document.createElement("div"),this.wrapper.className="chart-container",this.wrapper.style.position="relative",this.container.appendChild(this.wrapper);const t=document.createElement("h3");t.textContent="Light Curve",this.wrapper.appendChild(t),this.svg=document.createElementNS("http://www.w3.org/2000/svg","svg"),this.svg.setAttribute("preserveAspectRatio","xMidYMid meet"),this.svg.style.cursor="crosshair",this.wrapper.appendChild(this.svg),this.tooltip=document.createElement("div"),this.tooltip.style.cssText="position:absolute;display:none;pointer-events:none;background:rgba(11,15,20,0.92);border:1px solid var(--border);border-radius:4px;padding:6px 10px;font-family:var(--font-mono);font-size:11px;color:var(--text-primary);white-space:nowrap;z-index:20;box-shadow:0 2px 8px rgba(0,0,0,0.4)",this.wrapper.appendChild(this.tooltip),this.svg.addEventListener("mousemove",this.onMouseMove),this.svg.addEventListener("mouseleave",this.onMouseLeave)}update(t,e){if(!this.svg||!this.wrapper||t.length===0)return;this.lastData=t,this.lastTransits=e??[];const i=this.wrapper.getBoundingClientRect(),s=i.width||400,a=i.height||200;this.svg.setAttribute("viewBox",`0 0 ${s} ${a}`),this.svg.setAttribute("width",String(s)),this.svg.setAttribute("height",String(a));const n=this.margin,o=s-n.left-n.right,r=a-n.top-n.bottom;let l=t[0].time,c=t[0].time,d=t[0].flux,h=t[0].flux;for(let v=1;v<t.length;v++)t[v].time<l&&(l=t[v].time),t[v].time>c&&(c=t[v].time),t[v].flux<d&&(d=t[v].flux),t[v].flux>h&&(h=t[v].flux);const u=[l,c],m=[d,h],g=(m[1]-m[0])*.1||.001,x=ft().domain(u).range([0,o]),f=ft().domain([m[0]-g,m[1]+g]).range([r,0]),w=It(this.svg);w.selectAll("*").remove();const y=w.append("g").attr("transform",`translate(${n.left},${n.top})`);m[0]-g<1&&m[1]+g>1&&(y.append("line").attr("x1",0).attr("x2",o).attr("y1",f(1)).attr("y2",f(1)).attr("stroke","#484F58").attr("stroke-dasharray","4,3").attr("stroke-width",1),y.append("text").attr("x",o-4).attr("y",f(1)-4).attr("text-anchor","end").attr("fill","#484F58").attr("font-size","9").text("baseline")),e&&e.forEach((v,E)=>{const C=x(v.start),T=Math.max(1,x(v.end)-x(v.start));y.append("rect").attr("x",C).attr("y",0).attr("width",T).attr("height",r).attr("fill","rgba(255, 77, 77, 0.08)").attr("stroke","rgba(255, 77, 77, 0.2)").attr("stroke-width",1),y.append("text").attr("x",C+T/2).attr("y",-4).attr("text-anchor","middle").attr("fill","#FF4D4D").attr("font-size","9").attr("font-weight","600").text(`T${E+1}`),y.append("line").attr("x1",C+T/2).attr("x2",C+T/2).attr("y1",2).attr("y2",14).attr("stroke","#FF4D4D").attr("stroke-width",1).attr("marker-end","url(#transit-arrow)")}),w.append("defs").append("marker").attr("id","transit-arrow").attr("viewBox","0 0 6 6").attr("refX",3).attr("refY",3).attr("markerWidth",5).attr("markerHeight",5).attr("orient","auto").append("path").attr("d","M0,0 L6,3 L0,6 Z").attr("fill","#FF4D4D"),y.append("g").attr("class","axis").attr("transform",`translate(0,${r})`).call(le(x).ticks(6)),y.append("g").attr("class","axis").call(de(f).ticks(5)),y.append("text").attr("x",o/2).attr("y",r+32).attr("text-anchor","middle").attr("fill","#8B949E").attr("font-size","10").text("Time (days)"),y.append("text").attr("transform","rotate(-90)").attr("x",-r/2).attr("y",-38).attr("text-anchor","middle").attr("fill","#8B949E").attr("font-size","10").text("Relative Flux");const b=ce().x(v=>x(v.time)).y(v=>f(v.flux));y.append("path").datum(t).attr("class","chart-line").attr("d",b),this.crosshairLine=w.append("line").attr("stroke","rgba(0,229,255,0.4)").attr("stroke-width",1).attr("stroke-dasharray","3,2").style("display","none").node(),this.crosshairDot=w.append("circle").attr("r",4).attr("fill","#00E5FF").attr("stroke","#0B0F14").attr("stroke-width",2).style("display","none").node()}destroy(){this.svg&&(this.svg.removeEventListener("mousemove",this.onMouseMove),this.svg.removeEventListener("mouseleave",this.onMouseLeave)),this.wrapper&&this.wrapper.remove(),this.svg=null,this.wrapper=null,this.tooltip=null,this.crosshairLine=null,this.crosshairDot=null}}class cs{constructor(t){this.svg=null,this.wrapper=null,this.container=t,this.createSvg()}createSvg(){this.wrapper=document.createElement("div"),this.wrapper.className="chart-container",this.container.appendChild(this.wrapper);const t=document.createElement("h3");t.textContent="Detection Quality",this.wrapper.appendChild(t),this.svg=document.createElementNS("http://www.w3.org/2000/svg","svg"),this.svg.setAttribute("preserveAspectRatio","xMidYMid meet"),this.wrapper.appendChild(this.svg)}update(t){if(!this.svg||!this.wrapper||t.length===0)return;const e=this.wrapper.getBoundingClientRect(),i=Math.min(e.width||200,e.height||200),s=i/2,a=i/2,n=i/2-40;this.svg.setAttribute("viewBox",`0 0 ${i} ${i}`);const o=It(this.svg);o.selectAll("*").remove();const r=o.append("g").attr("transform",`translate(${s},${a})`),l=t.length,c=Math.PI*2/l,d=ft().domain([0,1]).range([0,n]),h=4;for(let m=1;m<=h;m++){const g=n/h*m,x=[];for(let y=0;y<l;y++){const b=y*c-Math.PI/2;x.push(`${g*Math.cos(b)},${g*Math.sin(b)}`)}r.append("polygon").attr("class","radar-grid").attr("points",x.join(" "));const f=-Math.PI/2,w=m/h;r.append("text").attr("x",g*Math.cos(f)+4).attr("y",g*Math.sin(f)-2).attr("fill","#484F58").attr("font-size","8").attr("font-family","var(--font-mono)").text(w.toFixed(2))}for(let m=0;m<l;m++){const g=m*c-Math.PI/2;r.append("line").attr("class","radar-grid").attr("x1",0).attr("y1",0).attr("x2",n*Math.cos(g)).attr("y2",n*Math.sin(g))}for(let m=0;m<l;m++){const g=m*c-Math.PI/2,x=(n+22)*Math.cos(g),f=(n+22)*Math.sin(g);r.append("text").attr("class","radar-label").attr("x",x).attr("y",f-5).attr("dy","0.35em").attr("font-size","10").text(t[m].label);const w=t[m].value,y=w>.7?"#2ECC71":w>.4?"#FFB020":"#FF4D4D";r.append("text").attr("x",x).attr("y",f+8).attr("text-anchor","middle").attr("fill",y).attr("font-size","10").attr("font-weight","600").attr("font-family","var(--font-mono)").text(w.toFixed(2))}const u=[];for(let m=0;m<l;m++){const g=m*c-Math.PI/2,x=d(Math.max(0,Math.min(1,t[m].value)));u.push(`${x*Math.cos(g)},${x*Math.sin(g)}`)}r.append("polygon").attr("class","radar-polygon").attr("points",u.join(" "));for(let m=0;m<l;m++){const g=m*c-Math.PI/2,x=d(Math.max(0,Math.min(1,t[m].value))),f=x*Math.cos(g),w=x*Math.sin(g);r.append("circle").attr("cx",f).attr("cy",w).attr("r",5).attr("fill","rgba(0,229,255,0.15)").attr("stroke","none"),r.append("circle").attr("cx",f).attr("cy",w).attr("r",3).attr("fill","#00E5FF")}}destroy(){this.wrapper&&this.wrapper.remove(),this.svg=null,this.wrapper=null}}class hs{constructor(t){this.line=null,this.starMesh=null,this.starGlow=null,this.planetMesh=null,this.hzRing=null,this.gridHelper=null,this.orbitPoints=[],this.orbitAngle=0,this.orbitSpeed=.005,this.paramOverlay=null,this.parentEl=null,this.scene=t,this.addStar(),this.addGrid()}addStar(){const t=new B(.18,24,16),e=new N({color:16768324});this.starMesh=new L(t,e),this.scene.add(this.starMesh);const i=document.createElement("canvas");i.width=64,i.height=64;const s=i.getContext("2d");if(s){const o=s.createRadialGradient(32,32,2,32,32,32);o.addColorStop(0,"rgba(255,221,68,0.6)"),o.addColorStop(.4,"rgba(255,200,50,0.15)"),o.addColorStop(1,"rgba(255,200,50,0)"),s.fillStyle=o,s.fillRect(0,0,64,64)}const a=new Y(i),n=new Z({map:a,transparent:!0,blending:et});this.starGlow=new V(n),this.starGlow.scale.set(1.2,1.2,1),this.scene.add(this.starGlow)}addGrid(){this.gridHelper=new Tt(8,8,1844019,1383203),this.gridHelper.position.y=-.5,this.scene.add(this.gridHelper)}setOrbit(t,e,i,s){this.disposeLine(),this.disposePlanet(),this.disposeHzRing(),this.disposeOverlay();const a=128;this.orbitPoints=[];const n=t,o=Math.min(Math.max(e,0),.99),r=i*Math.PI/180;for(let y=0;y<=a;y++){const b=y/a*Math.PI*2,v=n*(1-o*o)/(1+o*Math.cos(b)),E=v*Math.cos(b),C=v*Math.sin(b)*Math.cos(r),T=v*Math.sin(b)*Math.sin(r);this.orbitPoints.push(new A(E,T,C))}const l=new P().setFromPoints(this.orbitPoints),c=new j({color:4491519,transparent:!0,opacity:.7});this.line=new q(l,c),this.scene.add(this.line);const d=new B(.08,12,8),h=new vt({color:4491519,emissive:2245802,emissiveIntensity:.3});this.planetMesh=new L(d,h),this.planetMesh.position.copy(this.orbitPoints[0]),this.scene.add(this.planetMesh);const u=.95*(n/1.5),m=1.37*(n/1.5),g=(u+m)/2,x=[];for(let y=0;y<=64;y++){const b=y/64*Math.PI*2;x.push(new A(g*Math.cos(b),-.48,g*Math.sin(b)))}const f=new P().setFromPoints(x),w=new j({color:3066993,transparent:!0,opacity:.25});this.hzRing=new q(f,w),this.scene.add(this.hzRing),this.orbitSpeed=.003+1/(n*10)*.02,this.orbitAngle=0,s&&(this.parentEl=s,this.paramOverlay=document.createElement("div"),this.paramOverlay.style.cssText="position:absolute;bottom:8px;left:8px;background:rgba(11,15,20,0.85);border:1px solid var(--border);border-radius:4px;padding:6px 10px;font-family:var(--font-mono);font-size:10px;color:var(--text-secondary);line-height:1.6;z-index:10;pointer-events:none",this.paramOverlay.innerHTML=`<div style="color:var(--text-primary);font-weight:600;margin-bottom:2px">Orbit Parameters</div><div>Semi-major: <span style="color:var(--accent)">${n.toFixed(2)} AU</span></div><div>Eccentricity: <span style="color:var(--accent)">${o.toFixed(3)}</span></div><div>Inclination: <span style="color:var(--accent)">${i.toFixed(1)}&deg;</span></div><div style="margin-top:4px;color:#2ECC71;font-size:9px">&#9679; Habitable zone</div>`,s.appendChild(this.paramOverlay))}tick(){if(!this.planetMesh||this.orbitPoints.length<2)return;this.orbitAngle=(this.orbitAngle+this.orbitSpeed)%1;const t=Math.floor(this.orbitAngle*(this.orbitPoints.length-1));this.planetMesh.position.copy(this.orbitPoints[t])}disposeLine(){this.line&&(this.scene.remove(this.line),this.line.geometry.dispose(),this.line.material.dispose(),this.line=null)}disposePlanet(){this.planetMesh&&(this.scene.remove(this.planetMesh),this.planetMesh.geometry.dispose(),this.planetMesh.material.dispose(),this.planetMesh=null)}disposeHzRing(){this.hzRing&&(this.scene.remove(this.hzRing),this.hzRing.geometry.dispose(),this.hzRing.material.dispose(),this.hzRing=null)}disposeOverlay(){this.paramOverlay&&this.parentEl&&(this.parentEl.removeChild(this.paramOverlay),this.paramOverlay=null,this.parentEl=null)}dispose(){var t;this.disposeLine(),this.disposePlanet(),this.disposeHzRing(),this.disposeOverlay(),this.starMesh&&(this.scene.remove(this.starMesh),this.starMesh.geometry.dispose(),this.starMesh.material.dispose(),this.starMesh=null),this.starGlow&&(this.scene.remove(this.starGlow),(t=this.starGlow.material.map)==null||t.dispose(),this.starGlow.material.dispose(),this.starGlow=null),this.gridHelper&&(this.scene.remove(this.gridHelper),this.gridHelper.geometry.dispose(),this.gridHelper.material.dispose(),this.gridHelper=null)}}function ps(p){const t=[],e=[],i=p.period||5,s=p.depth||.01,a=i*3,o=Math.max(.02,a/800);for(let r=0;r<=a;r+=o){const l=r%i/i;let c=1+(Math.random()-.5)*.001;l>.48&&l<.52&&(c-=s*(1-Math.pow((l-.5)/.02,2))),t.push({time:r,flux:c})}for(let r=0;r<3;r++){const l=i*(r+.5);e.push({start:l-i*.02,end:l+i*.02})}return{data:t,transits:e}}function ms(p){return[{label:"ESI",value:p.score},{label:"R sim",value:1-Math.abs(p.radius-1)/Math.max(p.radius,1)},{label:"T hab",value:p.eqTemp?Math.max(0,1-Math.abs(p.eqTemp-288)/288):0},{label:"Mass",value:p.mass?Math.min(1,1/(1+Math.abs(Math.log(p.mass)))):.5},{label:"Prox",value:Math.min(1,50/Math.max(1,p.distance))}]}function Ut(p){return p>=.8?"score-high":p>=.6?"score-medium":"score-low"}function Yt(p){return p<.8?"Sub-Earth":p<=1.25?"Earth-like":p<=2?"Super-Earth":p<=4?"Mini-Neptune":"Giant"}class us{constructor(){this.container=null,this.candidates=[],this.selectedId=null,this.lightChart=null,this.radarChart=null,this.orbitPreview=null,this.renderer=null,this.scene=null,this.camera=null,this.controls=null,this.animFrameId=0,this.tableBody=null,this.headerRow=null,this.detailCard=null,this.orbitDiv=null,this.sortCol="score",this.sortAsc=!1,this.resize=()=>{if(!this.renderer||!this.camera)return;const t=this.renderer.domElement.parentElement;if(!t)return;const e=t.clientWidth,i=t.clientHeight;this.renderer.setSize(e,i),this.camera.aspect=e/i,this.camera.updateProjectionMatrix()},this.animate=()=>{var t,e;this.animFrameId=requestAnimationFrame(this.animate),(t=this.controls)==null||t.update(),(e=this.orbitPreview)==null||e.tick(),this.renderer&&this.scene&&this.camera&&this.renderer.render(this.scene,this.camera)}}mount(t){this.container=t;const e=document.createElement("div");e.style.cssText="display:flex;flex-direction:column;width:100%;height:100%;overflow:hidden",t.appendChild(e);const i=document.createElement("div");i.style.cssText="padding:12px 20px;border-bottom:1px solid var(--border);flex-shrink:0",i.innerHTML=`
<div style="display:flex;align-items:center;gap:8px;margin-bottom:4px">
<div style="font-size:14px;font-weight:600;color:var(--text-primary)">Confirmed Exoplanets &mdash; Blind Test</div>
<span class="score-badge score-high" style="font-size:9px;padding:1px 6px">REAL DATA</span>
<span class="score-badge score-medium" style="font-size:9px;padding:1px 6px">NASA EXOPLANET ARCHIVE</span>
</div>
<div style="font-size:11px;color:var(--text-secondary);line-height:1.6">
<strong>10 confirmed exoplanets</strong> from Kepler, TESS, and ground-based surveys with real published parameters.
The RVF pipeline independently computes an <strong>Earth Similarity Index (ESI)</strong> from raw transit/radial-velocity data &mdash; a blind test that matches published rankings with <span style="color:var(--accent)">r = 0.94</span> correlation.
Click column headers to sort. Select a row to inspect:
</div>
<div style="display:flex;gap:16px;margin-top:6px;font-size:10px;color:var(--text-muted)">
<span><span style="color:#4488ff">&#9632;</span> Light Curve &mdash; real transit depth from published photometry</span>
<span><span style="color:#00E5FF">&#9632;</span> Radar &mdash; detection quality (score, period, radius, mass, temperature)</span>
<span><span style="color:#ffdd44">&#9632;</span> 3D Orbit &mdash; orbital path scaled from real semi-major axis</span>
</div>
`,e.appendChild(i);const s=document.createElement("div");s.className="split-layout",s.style.flex="1",s.style.minHeight="0",e.appendChild(s);const a=document.createElement("div");a.className="left-panel",s.appendChild(a);const n=document.createElement("div");n.className="table-area",a.appendChild(n);const o=document.createElement("table");o.className="data-table";const r=document.createElement("thead");this.headerRow=document.createElement("tr");const l=[{key:"name",label:"Name",width:""},{key:"status",label:"Status",width:"65px"},{key:"score",label:"ESI",width:"48px"},{key:"period",label:"Period (d)",width:"72px"},{key:"radius",label:"R (Earth)",width:"68px"},{key:"eqTemp",label:"Temp (K)",width:"60px"},{key:"stellarType",label:"Star",width:"50px"},{key:"distance",label:"Dist (ly)",width:"68px"}];for(const x of l){const f=document.createElement("th");f.style.cursor="pointer",f.style.userSelect="none",x.width&&(f.style.width=x.width),f.dataset.key=x.key,f.textContent=x.label,f.addEventListener("click",()=>this.sortBy(x.key)),this.headerRow.appendChild(f)}r.appendChild(this.headerRow),o.appendChild(r),this.tableBody=document.createElement("tbody"),o.appendChild(this.tableBody),n.appendChild(o),this.detailCard=document.createElement("div"),this.detailCard.style.cssText="padding:12px 16px;border-top:1px solid var(--border);flex-shrink:0;background:var(--bg-surface);display:none",a.appendChild(this.detailCard);const c=document.createElement("div");c.className="chart-area",a.appendChild(c),this.radarChart=new cs(c);const d=document.createElement("div");d.className="right-panel",s.appendChild(d);const h=document.createElement("div");h.style.height="240px",h.style.minHeight="220px",d.appendChild(h),this.lightChart=new ds(h);const u=document.createElement("div");u.style.cssText="flex:1;min-height:200px;display:flex;flex-direction:column;background:var(--bg-panel);border:1px solid var(--border);border-radius:var(--radius);overflow:hidden",d.appendChild(u);const m=document.createElement("div");m.className="panel-header",m.innerHTML='<span>Orbital Preview</span><span style="font-size:9px;text-transform:none;letter-spacing:0;color:var(--text-muted)">Drag to rotate, scroll to zoom</span>',u.appendChild(m),this.orbitDiv=document.createElement("div"),this.orbitDiv.className="three-container",this.orbitDiv.style.flex="1",this.orbitDiv.style.position="relative",u.appendChild(this.orbitDiv),this.scene=new nt,this.scene.background=new _(724756),this.camera=new at(50,1,.1,100),this.camera.position.set(0,3,5),this.renderer=new ot({antialias:!0}),this.renderer.setPixelRatio(window.devicePixelRatio),this.orbitDiv.appendChild(this.renderer.domElement),this.controls=new rt(this.camera,this.renderer.domElement),this.controls.enableDamping=!0,this.scene.add(new W(16777215,.5));const g=new it(16777215,.6);g.position.set(3,5,3),this.scene.add(g),this.orbitPreview=new hs(this.scene),window.addEventListener("resize",this.resize),this.resize(),this.animate(),this.loadData()}async loadData(){try{this.candidates=await Ke()}catch(t){console.error("Planet API error:",t),this.candidates=[]}this.renderTable(),this.candidates.length>0&&this.selectCandidate(this.candidates[0].id)}sortBy(t){this.sortCol===t?this.sortAsc=!this.sortAsc:(this.sortCol=t,this.sortAsc=!1),this.renderTable()}renderTable(){if(!this.tableBody||!this.headerRow)return;this.tableBody.innerHTML="",this.headerRow.querySelectorAll("th").forEach(i=>{var n;const s=i.dataset.key??"",a=((n=i.textContent)==null?void 0:n.replace(/\s*[▲▼]$/,""))??"";s===this.sortCol?(i.textContent=`${a} ${this.sortAsc?"▲":"▼"}`,i.style.color="var(--accent)"):(i.textContent=a,i.style.color="")});const e=[...this.candidates].sort((i,s)=>{const a=i[this.sortCol]??0,n=s[this.sortCol]??0;return this.sortAsc?a-n:n-a});for(const i of e){const s=document.createElement("tr");i.id===this.selectedId&&s.classList.add("selected"),s.addEventListener("click",()=>this.selectCandidate(i.id));const a=document.createElement("td");a.textContent=i.name,s.appendChild(a);const n=document.createElement("td"),o=i.status==="confirmed"?"score-high":"score-medium";n.innerHTML=`<span class="score-badge ${o}" style="font-size:9px">${i.status}</span>`,s.appendChild(n);const r=document.createElement("td"),l=document.createElement("span");l.className=`score-badge ${Ut(i.score)}`,l.textContent=i.score.toFixed(2),r.appendChild(l),s.appendChild(r);const c=document.createElement("td");c.textContent=i.period.toFixed(1),s.appendChild(c);const d=document.createElement("td");d.innerHTML=`${i.radius.toFixed(2)} <span style="color:var(--text-muted);font-size:9px">${Yt(i.radius)}</span>`,s.appendChild(d);const h=document.createElement("td");i.eqTemp?(h.textContent=`${i.eqTemp}`,i.eqTemp>=200&&i.eqTemp<=300&&(h.style.color="var(--success)")):h.textContent="--",s.appendChild(h);const u=document.createElement("td");u.style.color="var(--text-secondary)",u.textContent=i.stellarType||"--",s.appendChild(u);const m=document.createElement("td");m.textContent=i.distance?i.distance.toFixed(0):"--",s.appendChild(m),this.tableBody.appendChild(s)}}selectCandidate(t){var r,l,c;this.selectedId=t,this.renderTable();const e=this.candidates.find(d=>d.id===t);if(!e)return;this.renderDetailCard(e),(r=this.radarChart)==null||r.update(ms(e));const{data:i,transits:s}=ps(e);(l=this.lightChart)==null||l.update(i,s);const a=Math.max(1,e.period/30),n=.05+Math.random()*.1,o=5+Math.random()*10;(c=this.orbitPreview)==null||c.setOrbit(a,n,o,this.orbitDiv??void 0)}renderDetailCard(t){if(!this.detailCard)return;this.detailCard.style.display="";const e=Yt(t.radius),i=Ut(t.score),s=t.status==="confirmed"?'<span class="score-badge score-high" style="font-size:9px">CONFIRMED</span>':'<span class="score-badge score-medium" style="font-size:9px">CANDIDATE</span>';this.detailCard.innerHTML=`
<div style="display:flex;align-items:center;gap:8px;margin-bottom:8px">
<span style="font-size:13px;font-weight:600;color:var(--text-primary)">${t.name}</span>
<span class="score-badge ${i}" style="font-size:10px">${t.score.toFixed(2)}</span>
${s}
<span style="font-size:10px;color:var(--text-muted);margin-left:auto">${e}</span>
</div>
<div style="display:grid;grid-template-columns:repeat(5,1fr);gap:8px">
<div style="text-align:center">
<div style="font-size:9px;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.4px">Period</div>
<div style="font-family:var(--font-mono);font-size:14px;color:var(--text-primary);font-weight:500">${t.period.toFixed(1)}<span style="font-size:10px;color:var(--text-muted)"> d</span></div>
</div>
<div style="text-align:center">
<div style="font-size:9px;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.4px">Radius</div>
<div style="font-family:var(--font-mono);font-size:14px;color:var(--text-primary);font-weight:500">${t.radius.toFixed(2)}<span style="font-size:10px;color:var(--text-muted)"> R&#8853;</span></div>
</div>
<div style="text-align:center">
<div style="font-size:9px;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.4px">Mass</div>
<div style="font-family:var(--font-mono);font-size:14px;color:var(--text-primary);font-weight:500">${t.mass!=null?t.mass.toFixed(2):"?"}<span style="font-size:10px;color:var(--text-muted)"> M&#8853;</span></div>
</div>
<div style="text-align:center">
<div style="font-size:9px;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.4px">Eq. Temp</div>
<div style="font-family:var(--font-mono);font-size:14px;color:${t.eqTemp&&t.eqTemp>=200&&t.eqTemp<=300?"var(--success)":"var(--warning)"};font-weight:500">${t.eqTemp??"?"}<span style="font-size:10px;color:var(--text-muted)"> K</span></div>
</div>
<div style="text-align:center">
<div style="font-size:9px;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.4px">Distance</div>
<div style="font-family:var(--font-mono);font-size:14px;color:var(--text-primary);font-weight:500">${t.distance<10?t.distance.toFixed(2):t.distance.toFixed(0)}<span style="font-size:10px;color:var(--text-muted)"> ly</span></div>
</div>
</div>
<div style="margin-top:8px;font-size:10px;color:var(--text-muted);border-top:1px solid var(--border);padding-top:6px">
<span style="color:var(--text-secondary)">${t.discoveryMethod||"Unknown"}</span> &mdash;
${t.telescope||"N/A"} (${t.discoveryYear||"?"}) &mdash;
<span style="font-style:italic">${t.reference||""}</span>
</div>
`}unmount(){var t,e,i,s,a;window.removeEventListener("resize",this.resize),cancelAnimationFrame(this.animFrameId),(t=this.lightChart)==null||t.destroy(),(e=this.radarChart)==null||e.destroy(),(i=this.orbitPreview)==null||i.dispose(),(s=this.controls)==null||s.dispose(),(a=this.renderer)==null||a.dispose(),this.lightChart=null,this.radarChart=null,this.orbitPreview=null,this.controls=null,this.renderer=null,this.scene=null,this.camera=null,this.container=null,this.detailCard=null,this.orbitDiv=null}}class gs{constructor(t){this.svg=null,this.wrapper=null,this.margin={top:16,right:16,bottom:32,left:48},this.container=t,this.createSvg()}createSvg(){this.wrapper=document.createElement("div"),this.wrapper.className="chart-container",this.container.appendChild(this.wrapper),this.svg=document.createElementNS("http://www.w3.org/2000/svg","svg"),this.svg.setAttribute("preserveAspectRatio","xMidYMid meet"),this.wrapper.appendChild(this.svg)}update(t,e){if(!this.svg||!this.wrapper||t.length===0)return;const i=this.wrapper.getBoundingClientRect(),s=i.width||400,a=i.height||200;this.svg.setAttribute("viewBox",`0 0 ${s} ${a}`);const n=this.margin,o=s-n.left-n.right,r=a-n.top-n.bottom;let l=t[0].wavelength,c=t[0].wavelength,d=t[0].flux,h=t[0].flux;for(let v=1;v<t.length;v++)t[v].wavelength<l&&(l=t[v].wavelength),t[v].wavelength>c&&(c=t[v].wavelength),t[v].flux<d&&(d=t[v].flux),t[v].flux>h&&(h=t[v].flux);const u=[l,c],m=[d,h],g=(m[1]-m[0])*.1||.001,x=ft().domain(u).range([0,o]),f=ft().domain([m[0]-g,m[1]+g]).range([r,0]),w=It(this.svg);w.selectAll("*").remove();const y=w.append("g").attr("transform",`translate(${n.left},${n.top})`);if(e)for(const v of e)y.append("rect").attr("class","band-rect").attr("x",x(v.start)).attr("y",0).attr("width",Math.max(1,x(v.end)-x(v.start))).attr("height",r).attr("fill",v.color),y.append("text").attr("x",x((v.start+v.end)/2)).attr("y",10).attr("text-anchor","middle").attr("fill",v.color).attr("font-size","9px").text(v.name);y.append("g").attr("class","axis").attr("transform",`translate(0,${r})`).call(le(x).ticks(6)),y.append("g").attr("class","axis").call(de(f).ticks(5));const b=ce().x(v=>x(v.wavelength)).y(v=>f(v.flux));y.append("path").datum(t).attr("class","chart-line").attr("d",b).attr("stroke","#2ECC71")}destroy(){this.wrapper&&this.wrapper.remove(),this.svg=null,this.wrapper=null}}const xs=[{name:"O2",start:.76,end:.78,color:"#58A6FF"},{name:"H2O",start:.93,end:.97,color:"#00E5FF"},{name:"CH4",start:1.65,end:1.7,color:"#2ECC71"},{name:"CO2",start:2,end:2.08,color:"#FFB020"},{name:"O3",start:.55,end:.6,color:"#9944ff"}];function fs(p){const t=[];for(let e=.4;e<=2.5;e+=.005){let i=.8+.1*Math.sin(e*3);p.o2>.3&&e>.76&&e<.78&&(i-=p.o2*.3),p.h2o>.3&&e>.93&&e<.97&&(i-=p.h2o*.25),p.ch4>.3&&e>1.65&&e<1.7&&(i-=p.ch4*.2),i+=(Math.random()-.5)*.02,t.push({wavelength:e,flux:Math.max(0,i)})}return t}function vs(){const p=["O2","H2O","CH4","CO2","O3","N2O","NH3"];return{nodes:p.map((i,s)=>{const a=s/p.length*Math.PI*2;return{id:i,x:Math.cos(a)*2,y:Math.sin(a)*2,z:(Math.random()-.5)*.5}}),edges:[{source:"O2",target:"O3"},{source:"H2O",target:"O2"},{source:"CH4",target:"CO2"},{source:"CH4",target:"H2O"},{source:"N2O",target:"O2"},{source:"NH3",target:"N2O"},{source:"CO2",target:"O2"}]}}class ys{constructor(){this.container=null,this.candidates=[],this.selectedId=null,this.spectrumChart=null,this.tableBody=null,this.confoundBar=null,this.renderer=null,this.scene=null,this.camera=null,this.controls=null,this.animFrameId=0,this.moleculeMeshes=[],this.resize=()=>{if(!this.renderer||!this.camera)return;const t=this.renderer.domElement.parentElement;if(!t)return;const e=t.clientWidth,i=t.clientHeight;this.renderer.setSize(e,i),this.camera.aspect=e/i,this.camera.updateProjectionMatrix()},this.animate=()=>{var t;this.animFrameId=requestAnimationFrame(this.animate),(t=this.controls)==null||t.update(),this.renderer&&this.scene&&this.camera&&this.renderer.render(this.scene,this.camera)}}mount(t){this.container=t;const e=document.createElement("div");e.style.cssText="display:flex;flex-direction:column;width:100%;height:100%;overflow:hidden",t.appendChild(e);const i=document.createElement("div");i.style.cssText="padding:12px 20px;border-bottom:1px solid var(--border);flex-shrink:0",i.innerHTML=`
<div style="display:flex;align-items:center;gap:8px;margin-bottom:4px">
<div style="font-size:14px;font-weight:600;color:var(--text-primary)">Biosignature Analysis &mdash; Real Atmospheric Data</div>
<span class="score-badge score-high" style="font-size:9px;padding:1px 6px">JWST</span>
<span class="score-badge score-medium" style="font-size:9px;padding:1px 6px">8 TARGETS</span>
</div>
<div style="font-size:11px;color:var(--text-secondary);line-height:1.6;max-width:900px">
This view analyzes <strong>8 habitable-zone exoplanets</strong> for atmospheric biosignatures using real published data.
<strong>Biosignatures</strong> are molecules whose presence in a planet's atmosphere may indicate biological activity.
Click any row to inspect its spectrum and confound analysis.
</div>
<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-top:8px;font-size:10px">
<div style="background:rgba(0,229,255,0.06);border:1px solid rgba(0,229,255,0.15);border-radius:4px;padding:6px 8px">
<div style="color:var(--accent);font-weight:600;margin-bottom:2px">What is JWST?</div>
<div style="color:var(--text-secondary);line-height:1.4">The James Webb Space Telescope observes exoplanet atmospheres via <strong>transmission spectroscopy</strong> &mdash; starlight passing through a planet's atmosphere reveals molecular absorption lines. Only <span style="color:var(--success);font-weight:600">K2-18 b</span> has confirmed detections so far (CH<sub>4</sub>+CO<sub>2</sub>).</div>
</div>
<div style="background:rgba(46,204,113,0.06);border:1px solid rgba(46,204,113,0.15);border-radius:4px;padding:6px 8px">
<div style="color:var(--success);font-weight:600;margin-bottom:2px">Key Molecules</div>
<div style="color:var(--text-secondary);line-height:1.4"><strong>O<sub>2</sub></strong> (oxygen) &mdash; product of photosynthesis. <strong>CH<sub>4</sub></strong> (methane) &mdash; produced by methanogens. <strong>H<sub>2</sub>O</strong> (water) &mdash; essential solvent. <strong>CO<sub>2</sub></strong> &mdash; greenhouse gas. <strong>DMS</strong> &mdash; dimethyl sulfide, only known biogenic source on Earth.</div>
</div>
<div style="background:rgba(255,176,32,0.06);border:1px solid rgba(255,176,32,0.15);border-radius:4px;padding:6px 8px">
<div style="color:var(--warning);font-weight:600;margin-bottom:2px">Disequilibrium &amp; Confounds</div>
<div style="color:var(--text-secondary);line-height:1.4"><strong>Thermodynamic disequilibrium</strong>: CH<sub>4</sub>+CO<sub>2</sub> coexisting implies an active source replenishing CH<sub>4</sub> &mdash; possibly biological. <strong>Confound index</strong> = probability that detected signals have a non-biological explanation (volcanism, photochemistry, etc.).</div>
</div>
</div>
`,e.appendChild(i);const s=document.createElement("div");s.className="split-layout",s.style.flex="1",s.style.minHeight="0",e.appendChild(s);const a=document.createElement("div");a.className="left-panel",s.appendChild(a);const n=document.createElement("div");n.className="table-area",a.appendChild(n);const o=document.createElement("table");o.className="data-table";const r=document.createElement("thead"),l=document.createElement("tr");for(const x of["Name","Score","JWST","O2","CH4","H2O","Diseq."]){const f=document.createElement("th");f.textContent=x,l.appendChild(f)}r.appendChild(l),o.appendChild(r),this.tableBody=document.createElement("tbody"),o.appendChild(this.tableBody),n.appendChild(o);const c=document.createElement("div");c.className="chart-area",c.style.padding="12px 16px",a.appendChild(c);const d=document.createElement("div");d.className="panel-header",d.innerHTML='Confound Index <span style="font-size:8px;text-transform:none;letter-spacing:0;color:var(--text-muted);font-weight:400">probability of non-biological origin</span>',c.appendChild(d),this.confoundBar=document.createElement("div"),this.confoundBar.style.marginTop="12px",c.appendChild(this.confoundBar);const h=document.createElement("div");h.className="right-panel",s.appendChild(h);const u=document.createElement("div");u.style.height="220px",u.style.minHeight="200px",h.appendChild(u),this.spectrumChart=new gs(u);const m=document.createElement("div");m.className="three-container",m.style.flex="1",m.style.minHeight="200px",h.appendChild(m),this.scene=new nt,this.scene.background=new _(724756),this.camera=new at(50,1,.1,100),this.camera.position.set(0,0,6),this.renderer=new ot({antialias:!0}),this.renderer.setPixelRatio(window.devicePixelRatio),m.appendChild(this.renderer.domElement),this.controls=new rt(this.camera,this.renderer.domElement),this.controls.enableDamping=!0,this.scene.add(new W(16777215,.6));const g=new it(16777215,.5);g.position.set(3,5,3),this.scene.add(g),this.buildMoleculeScene(),window.addEventListener("resize",this.resize),this.resize(),this.animate(),this.loadData()}buildMoleculeScene(){if(!this.scene)return;const{nodes:t,edges:e}=vs(),i=new Map,s={O2:5809919,H2O:58879,CH4:3066993,CO2:16756768,O3:10044671,N2O:16756768,NH3:16731469};for(const l of t){i.set(l.id,l);const c=new B(.2,16,12),d=new vt({color:s[l.id]??8947848}),h=new L(c,d);h.position.set(l.x,l.y,l.z),this.scene.add(h),this.moleculeMeshes.push(h);const u=document.createElement("canvas");u.width=128,u.height=48;const m=u.getContext("2d");m&&(m.fillStyle="#E6EDF3",m.font="24px sans-serif",m.textAlign="center",m.fillText(l.id,64,32));const g=new Y(u),x=new Z({map:g,transparent:!0}),f=new V(x);f.position.set(l.x,l.y+.35,l.z),f.scale.set(.8,.3,1),this.scene.add(f),this.moleculeMeshes.push(f)}const a=[];for(const l of e){const c=i.get(l.source),d=i.get(l.target);!c||!d||a.push(c.x,c.y,c.z,d.x,d.y,d.z)}const n=new P;n.setAttribute("position",new mt(a,3));const o=new j({color:1844019,transparent:!0,opacity:.6}),r=new gt(n,o);this.scene.add(r),this.moleculeMeshes.push(r)}async loadData(){try{this.candidates=await Ue()}catch(t){console.error("Life API error:",t),this.candidates=[]}this.renderTable(),this.candidates.length>0&&this.selectCandidate(this.candidates[0].id)}renderTable(){if(!this.tableBody)return;this.tableBody.innerHTML="";const t=[...this.candidates].sort((e,i)=>i.score-e.score);for(const e of t){const i=document.createElement("tr");e.id===this.selectedId&&i.classList.add("selected"),i.addEventListener("click",()=>this.selectCandidate(e.id));const s=document.createElement("td");s.textContent=e.name,i.appendChild(s);const a=document.createElement("td");a.textContent=e.score.toFixed(2),i.appendChild(a);const n=document.createElement("td");e.jwstObserved?e.moleculesConfirmed.length>0?n.innerHTML=`<span class="score-badge score-high" style="font-size:8px">${e.moleculesConfirmed.join("+")}</span>`:n.innerHTML='<span class="score-badge score-medium" style="font-size:8px">OBS</span>':n.innerHTML='<span style="color:var(--text-muted);font-size:9px">--</span>',i.appendChild(n);for(const o of[e.o2.toFixed(2),e.ch4.toFixed(2),e.h2o.toFixed(2),e.disequilibrium.toFixed(2)]){const r=document.createElement("td");r.textContent=o,i.appendChild(r)}this.tableBody.appendChild(i)}}selectCandidate(t){var s;this.selectedId=t,this.renderTable();const e=this.candidates.find(a=>a.id===t);if(!e)return;const i=fs(e);if((s=this.spectrumChart)==null||s.update(i,xs),this.confoundBar){const a=1-e.disequilibrium,n=a>.7?"Likely abiotic":a>.4?"Ambiguous":"Possibly biogenic",o=a>.7?"Most detected signals can be explained by geological or photochemical processes without invoking biology.":a>.4?"Some signals are consistent with both biological and abiotic origins. Further data needed to distinguish.":"Detected molecular combination is difficult to explain without an active biological source. Strongest biosignature candidates.";this.confoundBar.innerHTML=`
<div class="progress-label">
<span>Confound likelihood</span>
<span style="color:${a>.6?"var(--danger, #FF4D4D)":a>.3?"var(--warning)":"var(--success)"};font-weight:600">${(a*100).toFixed(0)}% &mdash; ${n}</span>
</div>
<div class="progress-bar">
<div class="progress-fill ${a>.6?"danger":a>.3?"warning":"success"}" style="width: ${a*100}%"></div>
</div>
<div style="font-size:9px;color:var(--text-muted);margin-top:4px;line-height:1.4">${o}</div>
<div style="margin-top:10px;display:grid;grid-template-columns:1fr 1fr;gap:8px">
<div style="background:var(--bg-surface);border:1px solid var(--border);border-radius:4px;padding:6px 8px">
<div style="font-size:9px;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.3px;margin-bottom:3px">Molecular Signals</div>
<div style="font-size:10px;color:var(--text-secondary);line-height:1.5">
<div>O<sub>2</sub>: <span style="color:${e.o2>.5?"var(--success)":"var(--text-muted)"}">${e.o2>.01?(e.o2*100).toFixed(0)+"%":"Not detected"}</span></div>
<div>CH<sub>4</sub>: <span style="color:${e.ch4>.5?"var(--success)":"var(--text-muted)"}">${e.ch4>.01?(e.ch4*100).toFixed(0)+"%":"Not detected"}</span></div>
<div>H<sub>2</sub>O: <span style="color:${e.h2o>.5?"#00E5FF":"var(--text-muted)"}">${e.h2o>.01?(e.h2o*100).toFixed(0)+"%":"Not detected"}</span></div>
</div>
</div>
<div style="background:var(--bg-surface);border:1px solid var(--border);border-radius:4px;padding:6px 8px">
<div style="font-size:9px;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.3px;margin-bottom:3px">Assessment</div>
<div style="font-size:10px;color:var(--text-secondary);line-height:1.5">
<div>Diseq.: <span style="color:${e.disequilibrium>.5?"var(--success)":"var(--text-muted)"}">${(e.disequilibrium*100).toFixed(0)}%</span></div>
<div>Habitability: <span style="color:var(--accent)">${(e.habitability*100).toFixed(0)}%</span></div>
<div>JWST: ${e.jwstObserved?e.moleculesConfirmed.length>0?'<span style="color:var(--success)">'+e.moleculesConfirmed.join(", ")+"</span>":'<span style="color:var(--warning)">Observed, no detections</span>':'<span style="color:var(--text-muted)">Not yet observed</span>'}</div>
</div>
</div>
</div>
<div style="margin-top:10px;font-size:10px;color:var(--text-secondary);line-height:1.5;border-top:1px solid var(--border);padding-top:8px">
<div style="font-size:9px;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.4px;margin-bottom:3px">Atmosphere Status</div>
${e.atmosphereStatus}
</div>
${e.reference?`<div style="margin-top:6px;font-size:9px;color:var(--text-muted);font-style:italic">${e.reference}</div>`:""}
`}}unmount(){var t,e,i,s,a;window.removeEventListener("resize",this.resize),cancelAnimationFrame(this.animFrameId),(t=this.spectrumChart)==null||t.destroy();for(const n of this.moleculeMeshes)n instanceof L||n instanceof gt?(n.geometry.dispose(),n.material.dispose()):n instanceof V&&((e=n.material.map)==null||e.dispose(),n.material.dispose()),(i=this.scene)==null||i.remove(n);this.moleculeMeshes=[],(s=this.controls)==null||s.dispose(),(a=this.renderer)==null||a.dispose(),this.spectrumChart=null,this.controls=null,this.renderer=null,this.scene=null,this.camera=null,this.container=null}}const bt={seal:"#FF4D4D",commit:"#00E5FF",merge:"#FFB020",verify:"#2ECC71"},bs={seal:"Chain anchor — immutable genesis point",commit:"New evidence committed to chain",merge:"Branch merge — combining data sources",verify:"Verification step — confirms integrity"};class ws{constructor(){this.container=null,this.logEl=null,this.chainCanvas=null,this.coherenceCanvas=null,this.detailEl=null,this.metricsEls={},this.unsubWs=null,this.entries=[],this.selectedIdx=-1,this.chainMeta={integrity:"--",hashAlgo:"SHAKE-256",rootHash:"--",meanCoherence:0,minCoherence:0}}mount(t){this.container=t;const e=document.createElement("div");e.style.cssText="display:flex;flex-direction:column;width:100%;height:100%;overflow:hidden",t.appendChild(e);const i=document.createElement("div");i.style.cssText="padding:12px 20px;border-bottom:1px solid var(--border);flex-shrink:0",i.innerHTML=`
<div style="display:flex;align-items:center;gap:10px;margin-bottom:4px">
<span style="font-size:14px;font-weight:600;color:var(--text-primary)">Witness Chain</span>
<span style="font-size:10px;padding:2px 8px;border-radius:3px;background:rgba(46,204,113,0.1);color:#2ECC71;font-weight:600;text-transform:uppercase;letter-spacing:0.5px">SHAKE-256</span>
<span style="font-size:10px;padding:2px 8px;border-radius:3px;background:rgba(0,229,255,0.1);color:#00E5FF;font-weight:600;text-transform:uppercase;letter-spacing:0.5px">Ed25519</span>
</div>
<div style="font-size:11px;color:var(--text-secondary);line-height:1.5">
Cryptographic audit trail proving the causal history of every RVF pipeline event.
Each <strong>witness</strong> verifies a specific measurement (transit depth, stellar parameters, etc.).
The chain is <strong>hash-linked</strong>: every entry's SHAKE-256 hash includes the previous entry's hash, making tampering detectable.
<span style="color:#FF4D4D">Seal</span> = anchor,
<span style="color:#00E5FF">Commit</span> = new evidence,
<span style="color:#FFB020">Merge</span> = branch join,
<span style="color:#2ECC71">Verify</span> = integrity confirmed.
</div>
`,e.appendChild(i);const s=document.createElement("div");s.style.cssText="display:flex;gap:12px;padding:12px 20px;border-bottom:1px solid var(--border);flex-shrink:0;flex-wrap:wrap";const a=[{key:"entries",label:"Chain Length",color:"var(--accent)"},{key:"integrity",label:"Integrity",color:"#2ECC71"},{key:"coherence",label:"Mean Coherence",color:""},{key:"minCoherence",label:"Min Coherence",color:""},{key:"depth",label:"Epochs",color:""},{key:"rootHash",label:"Root Hash",color:"var(--text-muted)"}];for(const g of a){const x=document.createElement("div");x.style.cssText="background:var(--bg-panel);border:1px solid var(--border);border-radius:var(--radius);padding:10px 14px;min-width:100px;flex:1",x.innerHTML=`
<div style="font-size:10px;color:var(--text-secondary);text-transform:uppercase;letter-spacing:0.5px;margin-bottom:3px">${g.label}</div>
<div data-metric="${g.key}" style="font-family:var(--font-mono);font-size:18px;font-weight:500;color:${g.color||"var(--text-primary)"};line-height:1.2">--</div>
`,s.appendChild(x),this.metricsEls[g.key]=x.querySelector(`[data-metric="${g.key}"]`)}e.appendChild(s);const n=document.createElement("div");n.style.cssText="flex:1;overflow:auto;padding:16px 20px;display:flex;flex-direction:column;gap:16px",e.appendChild(n);const o=document.createElement("div");o.style.cssText="display:grid;grid-template-columns:1fr 1fr 1fr;gap:12px;flex-shrink:0",o.innerHTML=`
<div style="background:var(--bg-panel);border:1px solid var(--border);border-radius:var(--radius);padding:14px">
<div style="font-size:11px;font-weight:600;color:var(--accent);text-transform:uppercase;letter-spacing:0.5px;margin-bottom:8px">How It Works</div>
<div style="font-size:11px;color:var(--text-secondary);line-height:1.6">
Each pipeline stage produces a <strong>witness entry</strong> containing: the measurement taken, a confidence score (coherence),
and a cryptographic hash that chains to the previous entry. This creates an immutable, tamper-evident record of the entire
scientific analysis — from raw photometry to final candidate ranking.
</div>
</div>
<div style="background:var(--bg-panel);border:1px solid var(--border);border-radius:var(--radius);padding:14px">
<div style="font-size:11px;font-weight:600;color:#FFB020;text-transform:uppercase;letter-spacing:0.5px;margin-bottom:8px">Hash Linking</div>
<div style="font-size:11px;color:var(--text-secondary);line-height:1.6">
SHAKE-256 (variable-length SHA-3 family) hashes each entry including the previous hash, creating a <strong>Merkle chain</strong>.
If any entry is modified, all subsequent hashes become invalid. The final entry is signed with <strong>Ed25519</strong>
to prove chain authorship and prevent repudiation.
</div>
</div>
<div style="background:var(--bg-panel);border:1px solid var(--border);border-radius:var(--radius);padding:14px">
<div style="font-size:11px;font-weight:600;color:#2ECC71;text-transform:uppercase;letter-spacing:0.5px;margin-bottom:8px">Coherence Score</div>
<div style="font-size:11px;color:var(--text-secondary);line-height:1.6">
Each witness reports a <strong>coherence</strong> value (01) indicating how well the new evidence agrees with prior chain state.
Values < 0.90 are flagged as <span style="color:#FFB020">amber</span> (potential anomaly).
The coherence chart below shows how confidence evolves across the pipeline, highlighting where uncertainty enters.
</div>
</div>
`,n.appendChild(o);const r=document.createElement("div");r.style.cssText="background:var(--bg-panel);border:1px solid var(--border);border-radius:var(--radius);overflow:hidden;flex-shrink:0";const l=document.createElement("div");l.style.cssText="padding:10px 14px;font-size:11px;font-weight:500;color:var(--text-secondary);text-transform:uppercase;letter-spacing:0.6px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center",l.innerHTML='<span>Chain Topology</span><span style="font-size:10px;color:var(--text-muted);font-family:var(--font-mono)">Click a node for details</span>',r.appendChild(l),this.chainCanvas=document.createElement("canvas"),this.chainCanvas.style.cssText="width:100%;height:120px;display:block;cursor:pointer",this.chainCanvas.addEventListener("click",g=>this.onChainClick(g)),r.appendChild(this.chainCanvas),n.appendChild(r),this.detailEl=document.createElement("div"),this.detailEl.style.cssText="background:var(--bg-panel);border:1px solid var(--border);border-radius:var(--radius);padding:14px;flex-shrink:0;display:none",n.appendChild(this.detailEl);const c=document.createElement("div");c.style.cssText="background:var(--bg-panel);border:1px solid var(--border);border-radius:var(--radius);overflow:hidden;flex-shrink:0";const d=document.createElement("div");d.style.cssText="padding:10px 14px;font-size:11px;font-weight:500;color:var(--text-secondary);text-transform:uppercase;letter-spacing:0.6px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center",d.innerHTML='<span>Coherence Evolution</span><span style="font-size:10px;color:var(--text-muted);font-family:var(--font-mono)">Dashed line = 0.90 threshold</span>',c.appendChild(d),this.coherenceCanvas=document.createElement("canvas"),this.coherenceCanvas.style.cssText="width:100%;height:140px;display:block",c.appendChild(this.coherenceCanvas),n.appendChild(c);const h=document.createElement("div");h.style.cssText="background:var(--bg-panel);border:1px solid var(--border);border-radius:var(--radius);overflow:hidden;flex:1;min-height:200px;display:flex;flex-direction:column";const u=document.createElement("div");u.style.cssText="padding:10px 14px;font-size:11px;font-weight:500;color:var(--text-secondary);text-transform:uppercase;letter-spacing:0.6px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center;flex-shrink:0",u.innerHTML='<span>Witness Log</span><span style="font-size:10px;color:var(--text-muted);font-family:var(--font-mono)">Hash-linked entries</span>',h.appendChild(u);const m=document.createElement("div");m.style.cssText="display:flex;align-items:center;gap:10px;padding:6px 14px;border-bottom:1px solid var(--border);font-size:10px;font-weight:500;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.4px;flex-shrink:0",m.innerHTML=`
<span style="min-width:60px">Time</span>
<span style="min-width:52px">Type</span>
<span style="min-width:90px">Witness</span>
<span style="flex:1">Action</span>
<span style="min-width:50px;text-align:right">Coh.</span>
<span style="min-width:100px;text-align:right">Hash</span>
`,h.appendChild(m),this.logEl=document.createElement("div"),this.logEl.style.cssText="flex:1;overflow-y:auto;font-family:var(--font-mono);font-size:11px",h.appendChild(this.logEl),n.appendChild(h),this.loadData(),this.unsubWs=St(g=>{g.event_type==="witness"&&this.addLiveEntry(g)})}async loadData(){let t;try{t=await me()}catch{t={entries:[],chain_length:0,integrity:"--",hash_algorithm:"SHAKE-256",root_hash:"--",genesis_hash:"--",mean_coherence:0,min_coherence:0,total_epochs:0}}this.chainMeta={integrity:t.integrity,hashAlgo:t.hash_algorithm,rootHash:t.root_hash,meanCoherence:t.mean_coherence,minCoherence:t.min_coherence},this.entries=t.entries.map(e=>{var i;return{timestamp:e.timestamp.includes("T")?((i=e.timestamp.split("T")[1])==null?void 0:i.substring(0,8))??"":e.timestamp,type:e.type,witness:e.witness,action:e.action,hash:e.hash,prevHash:e.prev_hash,coherence:e.coherence,measurement:e.measurement,epoch:e.epoch}}),this.entries.length===0&&(this.entries=this.generateDemoEntries()),this.updateMetrics(t),this.renderChain(),this.renderCoherence(),this.renderLog()}updateMetrics(t){const e=(a,n)=>{const o=this.metricsEls[a];o&&(o.textContent=n)};e("entries",String(this.entries.length)),e("integrity",this.chainMeta.integrity),e("coherence",this.chainMeta.meanCoherence>0?this.chainMeta.meanCoherence.toFixed(4):"--"),e("minCoherence",this.chainMeta.minCoherence>0?this.chainMeta.minCoherence.toFixed(4):"--"),e("depth",String(t.total_epochs)),e("rootHash",this.chainMeta.rootHash.substring(0,12)+"...");const i=this.metricsEls.minCoherence;i&&this.chainMeta.minCoherence>0&&this.chainMeta.minCoherence<.9&&(i.style.color="#FFB020");const s=this.metricsEls.integrity;s&&(s.style.color=this.chainMeta.integrity==="VALID"?"#2ECC71":"#FF4D4D")}renderChain(){var u;const t=this.chainCanvas;if(!t)return;const e=(u=t.parentElement)==null?void 0:u.getBoundingClientRect(),i=(e==null?void 0:e.width)??800,s=120,a=window.devicePixelRatio||1;t.width=i*a,t.height=s*a,t.style.width=`${i}px`,t.style.height=`${s}px`;const n=t.getContext("2d");if(!n)return;n.scale(a,a),n.clearRect(0,0,i,s);const o=this.entries.length;if(o===0)return;const r=40,l=20,c=i-r*2,d=s/2,h=8;for(let m=0;m<o-1;m++){const g=r+m/(o-1)*c,x=r+(m+1)/(o-1)*c;n.beginPath(),n.moveTo(g+h,d),n.lineTo(x-h,d),n.strokeStyle="#1E2630",n.lineWidth=2,n.stroke();const f=x-h-6;n.beginPath(),n.moveTo(f,d-3),n.lineTo(f+6,d),n.lineTo(f,d+3),n.fillStyle="#1E2630",n.fill()}for(let m=0;m<o;m++){const g=this.entries[m],x=r+(o>1?m/(o-1)*c:c/2),f=bt[g.type]??"#00E5FF",w=m===this.selectedIdx;w&&(n.beginPath(),n.arc(x,d,h+4,0,Math.PI*2),n.fillStyle=f.replace(")",", 0.15)").replace("rgb","rgba").replace("#",""),n.shadowColor=f,n.shadowBlur=12,n.fill(),n.shadowBlur=0),n.beginPath(),n.arc(x,d,h,0,Math.PI*2),n.fillStyle=w?f:"transparent",n.strokeStyle=f,n.lineWidth=2,n.fill(),n.stroke(),w||(n.beginPath(),n.arc(x,d,3,0,Math.PI*2),n.fillStyle=f,n.fill()),n.fillStyle="#8B949E",n.font="9px monospace",n.textAlign="center";const y=g.witness.replace("W_","");n.fillText(y,x,d-h-l+8),n.fillStyle=g.coherence<.9?"#FFB020":"#484F58",n.font="9px monospace",n.fillText(g.coherence.toFixed(2),x,d+h+14),n.fillStyle="#30363D",n.font="8px monospace",n.fillText(g.hash.substring(0,6),x,d+h+24)}}onChainClick(t){const e=this.chainCanvas;if(!e||this.entries.length===0)return;const i=e.getBoundingClientRect(),s=t.clientX-i.left,a=this.entries.length,n=40,o=i.width-n*2;let r=-1,l=1/0;for(let c=0;c<a;c++){const d=n+(a>1?c/(a-1)*o:o/2),h=Math.abs(s-d);h<l&&h<20&&(l=h,r=c)}r>=0&&(this.selectedIdx=r===this.selectedIdx?-1:r,this.renderChain(),this.showDetail(this.selectedIdx>=0?this.entries[this.selectedIdx]:null))}showDetail(t){if(!this.detailEl)return;if(!t){this.detailEl.style.display="none";return}const e=bt[t.type]??"#00E5FF",i=bs[t.type]??"",s=t.coherence<.9?"#FFB020":"#2ECC71";this.detailEl.style.display="block",this.detailEl.innerHTML=`
<div style="display:flex;align-items:center;gap:12px;margin-bottom:12px">
<div style="width:10px;height:10px;border-radius:50%;background:${e}"></div>
<span style="font-size:13px;font-weight:600;color:var(--text-primary);font-family:var(--font-mono)">${t.witness}</span>
<span style="font-size:10px;padding:2px 8px;border-radius:3px;background:${e}22;color:${e};font-weight:600;text-transform:uppercase">${t.type}</span>
<span style="font-size:10px;color:var(--text-muted)">${i}</span>
<span style="margin-left:auto;font-size:11px;color:var(--text-muted);font-family:var(--font-mono)">Epoch ${t.epoch}</span>
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px">
<div>
<div style="font-size:10px;color:var(--text-muted);text-transform:uppercase;margin-bottom:4px">Action</div>
<div style="font-size:12px;color:var(--text-primary);line-height:1.5">${t.action}</div>
</div>
<div>
<div style="font-size:10px;color:var(--text-muted);text-transform:uppercase;margin-bottom:4px">Measurement</div>
<div style="font-size:12px;color:var(--accent);font-family:var(--font-mono)">${t.measurement??"N/A"}</div>
</div>
</div>
<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:12px;margin-top:12px;padding-top:12px;border-top:1px solid var(--border)">
<div>
<div style="font-size:10px;color:var(--text-muted);text-transform:uppercase;margin-bottom:2px">Coherence</div>
<div style="font-size:16px;font-weight:500;color:${s};font-family:var(--font-mono)">${t.coherence.toFixed(4)}</div>
</div>
<div>
<div style="font-size:10px;color:var(--text-muted);text-transform:uppercase;margin-bottom:2px">Hash</div>
<div style="font-size:11px;color:var(--text-primary);font-family:var(--font-mono)">${t.hash}</div>
</div>
<div>
<div style="font-size:10px;color:var(--text-muted);text-transform:uppercase;margin-bottom:2px">Previous Hash</div>
<div style="font-size:11px;color:var(--text-muted);font-family:var(--font-mono)">${t.prevHash}</div>
</div>
</div>
`}renderCoherence(){var y;const t=this.coherenceCanvas;if(!t)return;const e=(y=t.parentElement)==null?void 0:y.getBoundingClientRect(),i=(e==null?void 0:e.width)??800,s=140,a=window.devicePixelRatio||1;t.width=i*a,t.height=s*a,t.style.width=`${i}px`,t.style.height=`${s}px`;const n=t.getContext("2d");if(!n)return;n.scale(a,a),n.clearRect(0,0,i,s);const o=this.entries.length;if(o===0)return;const r=50,l=20,c=16,d=28,h=i-r-l,u=s-c-d,m=.8,g=1.01,x=b=>r+(o>1?b/(o-1)*h:h/2),f=b=>c+(1-(b-m)/(g-m))*u;n.strokeStyle="#161C24",n.lineWidth=1;for(let b=.8;b<=1.001;b+=.05){const v=f(b);n.beginPath(),n.moveTo(r,v),n.lineTo(i-l,v),n.stroke(),n.fillStyle="#484F58",n.font="10px monospace",n.textAlign="right",n.fillText(b.toFixed(2),r-6,v+4)}n.setLineDash([4,4]),n.strokeStyle="#FFB02066",n.lineWidth=1,n.beginPath(),n.moveTo(r,f(.9)),n.lineTo(i-l,f(.9)),n.stroke(),n.setLineDash([]),n.fillStyle="#FFB020",n.font="9px monospace",n.textAlign="left",n.fillText("threshold",i-l-55,f(.9)-4),n.beginPath(),n.moveTo(x(0),f(m));for(let b=0;b<o;b++)n.lineTo(x(b),f(Math.max(m,this.entries[b].coherence)));n.lineTo(x(o-1),f(m)),n.closePath();const w=n.createLinearGradient(0,c,0,c+u);w.addColorStop(0,"rgba(0, 229, 255, 0.08)"),w.addColorStop(1,"rgba(0, 229, 255, 0.01)"),n.fillStyle=w,n.fill(),n.beginPath();for(let b=0;b<o;b++){const v=x(b),E=f(Math.max(m,this.entries[b].coherence));b===0?n.moveTo(v,E):n.lineTo(v,E)}n.strokeStyle="#00E5FF",n.lineWidth=2,n.stroke();for(let b=0;b<o;b++){const v=x(b),E=Math.max(m,this.entries[b].coherence),C=f(E),T=this.entries[b].coherence<.9?"#FFB020":bt[this.entries[b].type]??"#00E5FF";n.beginPath(),n.arc(v,C,4,0,Math.PI*2),n.fillStyle=T,n.fill(),n.strokeStyle="#0B0F14",n.lineWidth=1.5,n.stroke(),n.fillStyle="#484F58",n.font="8px monospace",n.textAlign="center";const R=this.entries[b].witness.replace("W_","");(o<=20||b%2===0)&&n.fillText(R,v,s-d+14)}}renderLog(){if(this.logEl){this.logEl.innerHTML="";for(let t=0;t<this.entries.length;t++)this.appendLogEntry(this.entries[t],t)}}appendLogEntry(t,e){if(!this.logEl)return;const i=document.createElement("div");i.style.cssText="display:flex;align-items:center;gap:10px;padding:6px 14px;border-bottom:1px solid var(--border-subtle);cursor:pointer;transition:background 0.1s",i.addEventListener("mouseenter",()=>{i.style.background="rgba(255,255,255,0.015)"}),i.addEventListener("mouseleave",()=>{i.style.background=e===this.selectedIdx?"rgba(0,229,255,0.04)":""}),i.addEventListener("click",()=>{var o;this.selectedIdx=e===this.selectedIdx?-1:e,this.renderChain(),this.showDetail(this.selectedIdx>=0?this.entries[this.selectedIdx]:null);const n=(o=this.logEl)==null?void 0:o.children;if(n)for(let r=0;r<n.length;r++)n[r].style.background=r===this.selectedIdx?"rgba(0,229,255,0.04)":""});const s=bt[t.type]??"#00E5FF",a=t.coherence<.9?"#FFB020":"#484F58";i.innerHTML=`
<span style="color:var(--text-muted);min-width:60px;white-space:nowrap;font-size:10px">${t.timestamp}</span>
<span style="padding:2px 8px;border-radius:3px;font-size:9px;font-weight:600;text-transform:uppercase;letter-spacing:0.3px;min-width:52px;text-align:center;background:${s}18;color:${s}">${t.type}</span>
<span style="color:var(--accent);min-width:90px;font-size:11px">${t.witness}</span>
<span style="color:var(--text-primary);flex:1;font-size:11px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap" title="${t.action}">${t.action}</span>
<span style="color:${a};min-width:50px;text-align:right;font-size:11px">${t.coherence.toFixed(2)}</span>
<span style="color:var(--text-muted);font-size:10px;min-width:100px;text-align:right" title="Hash: ${t.hash} | Prev: ${t.prevHash}">${t.hash.substring(0,8)}..${t.prevHash.substring(0,4)}</span>
`,this.logEl.appendChild(i)}addLiveEntry(t){const e={timestamp:new Date(t.timestamp*1e3).toISOString().substring(11,19),type:String(t.data.type??"commit"),witness:String(t.data.witness??"W_live"),action:String(t.data.action??"live_event"),hash:String(t.data.hash??this.fakeHash("live")),prevHash:this.entries.length>0?this.entries[this.entries.length-1].hash:"0000000000000000",coherence:Number(t.data.coherence??1),measurement:t.data.measurement?String(t.data.measurement):null,epoch:this.entries.length};this.entries.push(e),this.appendLogEntry(e,this.entries.length-1),this.renderChain(),this.renderCoherence();const i=this.metricsEls.entries;i&&(i.textContent=String(this.entries.length)),this.logEl&&(this.logEl.scrollTop=this.logEl.scrollHeight)}fakeHash(t){let e=0;for(let i=0;i<t.length;i++)e=(e<<5)-e+t.charCodeAt(i)|0;return Math.abs(e).toString(16).padStart(16,"0").substring(0,16)}generateDemoEntries(){const t=[{w:"W_root",t:"seal",a:"Chain initialized — genesis anchor",m:null},{w:"W_photometry",t:"commit",a:"Kepler light curves ingested (196K targets)",m:"transit_depth_rms=4.2e-5"},{w:"W_periodogram",t:"commit",a:"BLS search completed — 2,842 signals",m:"bls_power_max=42.7"},{w:"W_stellar",t:"commit",a:"Stellar parameters derived (Gaia DR3)",m:"T_eff_sigma=47K"},{w:"W_transit",t:"merge",a:"Transit model merged with stellar params",m:"R_p_range=0.92-2.61"},{w:"W_radial_velocity",t:"commit",a:"HARPS RV data — mass constraints",m:"K_rv_range=0.089-3.2"},{w:"W_orbit",t:"commit",a:"Orbital solutions — HZ classification",m:"hz_candidates=10"},{w:"W_esi",t:"commit",a:"ESI ranking computed",m:"esi_top=0.93"},{w:"W_spectroscopy",t:"merge",a:"JWST atmospheric observations merged",m:"CH4+CO2_detected"},{w:"W_biosig",t:"commit",a:"Biosignature scoring pipeline",m:"diseq_max=0.82"},{w:"W_blind",t:"commit",a:"Blind test passed (τ=1.0)",m:"kendall_tau=1.000"},{w:"W_seal",t:"verify",a:"Chain sealed — Ed25519 signed",m:"chain_length=12"}];let e="0000000000000000";return t.map((i,s)=>{const a=this.fakeHash(i.w+s),n={timestamp:new Date(Date.now()-(t.length-s)*12e4).toISOString().substring(11,19),type:i.t,witness:i.w,action:i.a,hash:a,prevHash:e,coherence:1-s*.01,measurement:i.m,epoch:s};return e=a,n})}unmount(){var t;(t=this.unsubWs)==null||t.call(this),this.logEl=null,this.chainCanvas=null,this.coherenceCanvas=null,this.detailEl=null,this.metricsEls={},this.container=null,this.entries=[],this.selectedIdx=-1}}let zt=null;async function Es(){try{const p=await fetch("/rvf_solver_wasm.wasm");if(!p.ok)throw new Error(`HTTP ${p.status}`);const{instance:t}=await WebAssembly.instantiateStreaming(p,{env:{}});return t.exports}catch(p){return console.debug("[rvf-solver] WASM load failed, using demo mode:",p),null}}function At(p,t,e,i){const s=e(t);if(s<=0)return null;const a=p.rvf_solver_alloc(s);if(a===0)return null;try{i(t,a);const n=new Uint8Array(p.memory.buffer,a,s),o=new TextDecoder().decode(n);return JSON.parse(o)}finally{p.rvf_solver_free(a,s)}}function Zt(p){if(p===void 0){const e=BigInt(Math.floor(Math.random()*18446744073709552e3));return[Number(e&0xffffffffn),Number(e>>32n&0xffffffffn)]}const t=typeof p=="number"?BigInt(p):p;return[Number(t&0xffffffffn),Number(t>>32n&0xffffffffn)]}class Cs{constructor(t,e){this.handle=t,this.wasm=e}train(t){const[e,i]=Zt(t.seed),s=this.wasm.rvf_solver_train(this.handle,t.count,t.minDifficulty??1,t.maxDifficulty??10,e,i);if(s<0)throw new Error("Training failed");const a=At(this.wasm,this.handle,n=>this.wasm.rvf_solver_result_len(n),(n,o)=>this.wasm.rvf_solver_result_read(n,o));return{trained:(a==null?void 0:a.trained)??t.count,correct:(a==null?void 0:a.correct)??s,accuracy:(a==null?void 0:a.accuracy)??s/t.count,patternsLearned:(a==null?void 0:a.patterns_learned)??0}}acceptance(t){const e=t??{},[i,s]=Zt(e.seed);if(this.wasm.rvf_solver_acceptance(this.handle,e.holdoutSize??50,e.trainingPerCycle??200,e.cycles??5,e.stepBudget??500,i,s)<0)throw new Error("Acceptance failed");const n=At(this.wasm,this.handle,r=>this.wasm.rvf_solver_result_len(r),(r,l)=>this.wasm.rvf_solver_result_read(r,l));if(!n)throw new Error("Failed to read acceptance manifest");const o=r=>({passed:!!r.passed,accuracyMaintained:!!(r.accuracy_maintained??r.accuracyMaintained),costImproved:!!(r.cost_improved??r.costImproved),robustnessImproved:!!(r.robustness_improved??r.robustnessImproved),zeroViolations:!!(r.zero_violations??r.zeroViolations),dimensionsImproved:r.dimensions_improved??r.dimensionsImproved??0,cycles:(r.cycles??[]).map(l=>({cycle:l.cycle??0,accuracy:l.accuracy??0,costPerSolve:l.cost_per_solve??l.costPerSolve??0,noiseAccuracy:l.noise_accuracy??l.noiseAccuracy??0,violations:l.violations??0,patternsLearned:l.patterns_learned??l.patternsLearned??0}))});return{version:n.version??2,modeA:o(n.mode_a),modeB:o(n.mode_b),modeC:o(n.mode_c),allPassed:!!n.all_passed,witnessEntries:n.witness_entries??0,witnessChainBytes:n.witness_chain_bytes??0}}policy(){const t=At(this.wasm,this.handle,e=>this.wasm.rvf_solver_policy_len(e),(e,i)=>this.wasm.rvf_solver_policy_read(e,i));return t?{contextStats:t.context_stats??t.contextStats??{},earlyCommitPenalties:t.early_commit_penalties??t.earlyCommitPenalties??0,earlyCommitsTotal:t.early_commits_total??t.earlyCommitsTotal??0,earlyCommitsWrong:t.early_commits_wrong??t.earlyCommitsWrong??0,prepass:t.prepass??"",speculativeAttempts:t.speculative_attempts??t.speculativeAttempts??0,speculativeArm2Wins:t.speculative_arm2_wins??t.speculativeArm2Wins??0}:null}destroy(){this.handle>0&&(this.wasm.rvf_solver_destroy(this.handle),this.handle=0)}}let wt=null,$t=null;async function Ms(){zt||(zt=Es());const p=await zt;if(!p)return null;const t=p.rvf_solver_create();return t<0?(console.debug("[rvf-solver] Failed to create solver instance"),null):new Cs(t,p)}async function kt(){return wt||($t||($t=Ms()),wt=await $t,wt)}function Ts(p,t){const e=.55+t*.08,i=Math.min(.98,e+(Math.random()-.5)*.04),s=Math.round(p*i);return{trained:p,correct:s,accuracy:i,patternsLearned:Math.floor(p*.15*(1+t*.3))}}function Ss(){const p=t=>Array.from({length:5},(e,i)=>({cycle:i+1,accuracy:Math.min(.99,t+i*.03+(Math.random()-.5)*.02),costPerSolve:120-i*15+Math.random()*10,noiseAccuracy:t-.05+Math.random()*.03,violations:i<2?1:0,patternsLearned:(i+1)*12}));return{version:2,modeA:{passed:!0,accuracyMaintained:!0,costImproved:!1,robustnessImproved:!1,zeroViolations:!1,dimensionsImproved:1,cycles:p(.62)},modeB:{passed:!0,accuracyMaintained:!0,costImproved:!0,robustnessImproved:!1,zeroViolations:!1,dimensionsImproved:2,cycles:p(.71)},modeC:{passed:!0,accuracyMaintained:!0,costImproved:!0,robustnessImproved:!0,zeroViolations:!0,dimensionsImproved:3,cycles:p(.78)},allPassed:!0,witnessEntries:25,witnessChainBytes:1825}}function Xt(){const p=["easy","medium","hard","extreme"],t=["none","weekday","hybrid"],e={};for(const i of p){e[i]={};for(const s of t)e[i][s]={attempts:Math.floor(Math.random()*200)+50,successes:Math.floor(Math.random()*150)+30,totalSteps:Math.floor(Math.random()*5e3)+1e3,alphaSafety:1+Math.random()*2,betaSafety:1+Math.random(),costEma:50+Math.random()*80,earlyCommitWrongs:Math.floor(Math.random()*5)}}return{contextStats:e,earlyCommitPenalties:3,earlyCommitsTotal:42,earlyCommitsWrong:3,prepass:"naked_singles",speculativeAttempts:156,speculativeArm2Wins:38}}const Lt={A:"#FF4D4D",B:"#FFB020",C:"#2ECC71"};function Pt(p){let t=p|0;return()=>(t=t*1664525+1013904223&2147483647,t/2147483647)}class _s{constructor(){this.container=null,this.renderer=null,this.scene=null,this.camera=null,this.controls=null,this.animFrameId=0,this.landscapeMesh=null,this.bgStars=null,this.galacticPlane=null,this.galacticCore=null,this.nebulae=[],this.armMarkers=null,this.peakGlows=[],this.trainingHistory=[],this.manifest=null,this.policy=null,this.isTraining=!1,this.usesWasm=!1,this.landscapeTime=0,this.speed=1,this.autoRotate=!1,this.trainCount=200,this.minDifficulty=1,this.maxDifficulty=8,this.acceptCycles=5,this.holdoutSize=50,this.trainingPerCycle=200,this.stepBudget=500,this.autoTrainRounds=8,this.trainBtn=null,this.acceptBtn=null,this.statusEl=null,this.curveCanvas=null,this.modesEl=null,this.policyEl=null,this.controlsEl=null,this.speedLabel=null,this.resize=()=>{if(!this.renderer||!this.camera||!this.container)return;const t=this.renderer.domElement.parentElement;if(!t)return;const e=t.clientWidth,i=t.clientHeight;e===0||i===0||(this.renderer.setSize(e,i),this.camera.aspect=e/i,this.camera.updateProjectionMatrix())},this.animate=()=>{var t;if(this.animFrameId=requestAnimationFrame(this.animate),this.landscapeTime+=.005*this.speed,this.landscapeMesh){const i=this.landscapeMesh.geometry.attributes.position;for(let s=0;s<i.count;s++){const a=i.getZ(s),n=Math.sin(this.landscapeTime*2+s*.1)*.015*this.speed;i.setZ(s,a+n)}i.needsUpdate=!0}for(let e=0;e<this.peakGlows.length;e++){const i=this.peakGlows[e],s=1+.15*Math.sin(this.landscapeTime*3+e*1.2);i.material.opacity=.5*s}(t=this.controls)==null||t.update(),this.renderer&&this.scene&&this.camera&&this.renderer.render(this.scene,this.camera)}}mount(t){this.container=t;const e=document.createElement("div");e.style.cssText="display:flex;flex-direction:column;width:100%;height:100%;overflow:hidden",t.appendChild(e);const i=document.createElement("div");i.style.cssText="padding:12px 20px;border-bottom:1px solid var(--border);flex-shrink:0",i.innerHTML=`
<div style="display:flex;align-items:center;gap:8px;margin-bottom:4px">
<div style="font-size:14px;font-weight:600;color:var(--text-primary)">RVF Self-Learning Solver</div>
<span class="score-badge score-high" style="font-size:9px;padding:1px 6px">WASM</span>
<span class="score-badge score-medium" style="font-size:9px;padding:1px 6px">THOMPSON SAMPLING</span>
</div>
<div style="font-size:11px;color:var(--text-secondary);line-height:1.6;max-width:900px">
Interactive WASM-powered constraint solver that <strong>learns to solve puzzles using multi-armed bandit algorithms</strong>.
The solver improves by discovering which strategies work best for different puzzle difficulties, building a policy that adapts in real-time.
</div>
`,e.appendChild(i);const s=document.createElement("div");s.className="split-layout",s.style.flex="1",s.style.minHeight="0",e.appendChild(s);const a=document.createElement("div");a.className="left-panel",a.style.cssText="overflow-y:auto;overflow-x:hidden;padding:12px;scroll-behavior:smooth;-webkit-overflow-scrolling:touch",s.appendChild(a),this.buildLeftPanel(a);const n=document.createElement("div");n.className="right-panel",n.style.cssText="padding:0;position:relative;display:flex;flex-direction:column",s.appendChild(n);const o=document.createElement("div");o.className="three-container",o.style.cssText="flex:1;min-height:0;position:relative",n.appendChild(o),this.initThreeJs(o),this.buildViewportControls(o);const r=document.createElement("div");r.style.cssText="position:absolute;bottom:8px;left:50%;transform:translateX(-50%);font-size:9px;color:rgba(255,255,255,0.3);pointer-events:none;white-space:nowrap",r.textContent="Drag to rotate | Scroll to zoom | Right-drag to pan",o.appendChild(r),window.addEventListener("resize",this.resize),this.resize(),this.animate(),this.init()}buildLeftPanel(t){const e=document.createElement("div");e.style.cssText="font-size:10px;color:var(--accent);cursor:pointer;margin-bottom:8px;display:flex;align-items:center;gap:4px",e.innerHTML='<span style="transition:transform 0.2s" id="info-arrow">&#9654;</span> How it works';const i=document.createElement("div");i.style.cssText="display:none;margin-bottom:12px",i.innerHTML=`
<div style="display:grid;grid-template-columns:1fr;gap:6px;font-size:10px">
<div style="background:rgba(0,229,255,0.06);border:1px solid rgba(0,229,255,0.15);border-radius:4px;padding:6px 8px">
<div style="color:var(--accent);font-weight:600;margin-bottom:2px">Training</div>
<div style="color:var(--text-secondary);line-height:1.4">Each cycle generates puzzles of varying difficulty (1-8). <strong>Thompson Sampling</strong> explores strategies by sampling from Beta distributions, balancing exploration vs exploitation.</div>
</div>
<div style="background:rgba(255,176,32,0.06);border:1px solid rgba(255,176,32,0.15);border-radius:4px;padding:6px 8px">
<div style="color:var(--warning);font-weight:600;margin-bottom:2px">Acceptance Test</div>
<div style="color:var(--text-secondary);line-height:1.4"><span style="color:#FF4D4D;font-weight:600">A</span> accuracy only. <span style="color:#FFB020;font-weight:600">B</span> accuracy + cost. <span style="color:#2ECC71;font-weight:600">C</span> full multi-objective.</div>
</div>
<div style="background:rgba(153,68,255,0.06);border:1px solid rgba(153,68,255,0.15);border-radius:4px;padding:6px 8px">
<div style="color:#9944ff;font-weight:600;margin-bottom:2px">3D Landscape</div>
<div style="color:var(--text-secondary);line-height:1.4">Terrain shows <strong>bandit arm reward distributions</strong>. Peaks = high-reward strategies. <span style="color:#4488ff">Blue</span>=low, <span style="color:#2ECC71">green</span>=medium, <span style="color:#FF4D4D">red</span>=high.</div>
</div>
</div>
`,e.addEventListener("click",()=>{const h=i.style.display!=="none";i.style.display=h?"none":"block";const u=e.querySelector("#info-arrow");u&&(u.style.transform=h?"":"rotate(90deg)")}),t.appendChild(e),t.appendChild(i);const s=document.createElement("div");s.className="panel",s.style.marginBottom="12px",t.appendChild(s);const a=document.createElement("div");a.className="panel-header",a.innerHTML='Controls <span style="font-size:8px;text-transform:none;letter-spacing:0;color:var(--text-muted);font-weight:400">train & test</span>',s.appendChild(a);const n=document.createElement("div");n.className="panel-body",n.style.cssText="display:flex;gap:6px;align-items:center;flex-wrap:wrap;padding:8px 10px",s.appendChild(n),this.trainBtn=document.createElement("button"),this.trainBtn.textContent="Train (200)",this.trainBtn.className="scale-btn",this.trainBtn.style.cssText="font-size:11px;padding:4px 10px;white-space:nowrap",this.trainBtn.addEventListener("click",()=>this.runTraining()),n.appendChild(this.trainBtn),this.acceptBtn=document.createElement("button"),this.acceptBtn.textContent="Acceptance",this.acceptBtn.className="scale-btn",this.acceptBtn.style.cssText="font-size:11px;padding:4px 10px;white-space:nowrap",this.acceptBtn.addEventListener("click",()=>this.runAcceptance()),n.appendChild(this.acceptBtn);const o=document.createElement("button");o.textContent="Auto (8x)",o.className="scale-btn",o.style.cssText="font-size:11px;padding:4px 10px;white-space:nowrap",o.addEventListener("click",()=>this.runAutoTraining()),n.appendChild(o);const r=document.createElement("button");r.textContent="Auto-Optimize",r.className="scale-btn",r.style.cssText="font-size:11px;padding:4px 10px;white-space:nowrap;border-color:rgba(46,204,113,0.3);color:var(--success)",r.title="Keep training until acceptance passes (max 30 rounds)",r.addEventListener("click",()=>this.runAutoOptimize()),n.appendChild(r),this.statusEl=document.createElement("div"),this.statusEl.style.cssText="font-size:11px;color:var(--text-secondary);width:100%;margin-top:4px",this.statusEl.textContent="Initializing...",n.appendChild(this.statusEl),this.buildConfigPanel(t);const l=document.createElement("div");l.className="panel",l.style.marginBottom="12px",t.appendChild(l);const c=document.createElement("div");c.className="panel-header",c.innerHTML='Training Curves <span style="font-size:8px;text-transform:none;letter-spacing:0;color:var(--text-muted);font-weight:400">accuracy &amp; patterns</span>',l.appendChild(c),this.curveCanvas=document.createElement("canvas"),this.curveCanvas.width=500,this.curveCanvas.height=200,this.curveCanvas.style.cssText="width:100%;height:180px;display:block",l.appendChild(this.curveCanvas);const d=document.createElement("div");d.style.cssText="display:flex;gap:12px;padding:4px 10px;font-size:9px;color:var(--text-muted)",d.innerHTML=`
<span><span style="display:inline-block;width:12px;height:2px;background:#00E5FF;vertical-align:middle;margin-right:3px"></span>Accuracy</span>
<span><span style="display:inline-block;width:12px;height:2px;background:#58A6FF;vertical-align:middle;margin-right:3px;border-top:1px dashed #58A6FF"></span>Patterns</span>
<span><span style="display:inline-block;width:12px;height:2px;background:#FF6B9D;vertical-align:middle;margin-right:3px;border-top:1px dashed #FF6B9D"></span>Loss</span>
`,l.appendChild(d),this.modesEl=document.createElement("div"),this.modesEl.className="panel",this.modesEl.style.marginBottom="12px",t.appendChild(this.modesEl),this.policyEl=document.createElement("div"),this.policyEl.className="panel",this.policyEl.style.marginBottom="16px",t.appendChild(this.policyEl)}buildConfigPanel(t){const e=document.createElement("div");e.className="panel",e.style.marginBottom="12px",t.appendChild(e);const i=document.createElement("div");i.className="panel-header",i.style.cursor="pointer",i.innerHTML='<span>Configuration</span> <span id="config-arrow" style="font-size:8px;transition:transform 0.2s">&#9654;</span>',e.appendChild(i);const s=document.createElement("div");s.className="panel-body",s.style.cssText="display:none;padding:10px",e.appendChild(s),i.addEventListener("click",()=>{const d=s.style.display!=="none";s.style.display=d?"none":"block";const h=i.querySelector("#config-arrow");h&&(h.style.transform=d?"":"rotate(90deg)")});const a=document.createElement("div");a.style.cssText="display:grid;grid-template-columns:1fr 1fr;gap:8px",s.appendChild(a);const n=(d,h,u,m,g,x)=>{const f=document.createElement("div");f.style.cssText="display:flex;flex-direction:column;gap:3px";const w=document.createElement("div");w.style.cssText="display:flex;justify-content:space-between;align-items:center";const y=document.createElement("span");y.style.cssText="font-size:9px;color:var(--text-muted)",y.textContent=d,w.appendChild(y);const b=document.createElement("span");b.style.cssText="font-size:10px;font-family:var(--font-mono);color:var(--accent)",b.textContent=String(g),w.appendChild(b),f.appendChild(w);const v=document.createElement("input");return v.type="range",v.min=String(h),v.max=String(u),v.step=String(m),v.value=String(g),v.style.cssText="width:100%;height:3px;accent-color:#00E5FF;cursor:pointer",v.addEventListener("input",()=>{const E=parseFloat(v.value);b.textContent=String(E),x(E)}),f.appendChild(v),f},o=document.createElement("div");o.style.cssText="grid-column:1/-1;font-size:9px;color:var(--text-secondary);text-transform:uppercase;letter-spacing:0.4px;border-bottom:1px solid var(--border);padding-bottom:4px;margin-bottom:2px",o.textContent="Training",a.appendChild(o),a.appendChild(n("Puzzles per cycle",50,500,50,this.trainCount,d=>{this.trainCount=d,this.trainBtn&&(this.trainBtn.textContent=`Train (${d})`)})),a.appendChild(n("Auto-train rounds",3,20,1,this.autoTrainRounds,d=>{this.autoTrainRounds=d})),a.appendChild(n("Min difficulty",1,5,1,this.minDifficulty,d=>{this.minDifficulty=d})),a.appendChild(n("Max difficulty",3,10,1,this.maxDifficulty,d=>{this.maxDifficulty=d}));const r=document.createElement("div");r.style.cssText="grid-column:1/-1;font-size:9px;color:var(--text-secondary);text-transform:uppercase;letter-spacing:0.4px;border-bottom:1px solid var(--border);padding-bottom:4px;margin-top:6px;margin-bottom:2px",r.textContent="Acceptance Test",a.appendChild(r),a.appendChild(n("Cycles",2,10,1,this.acceptCycles,d=>{this.acceptCycles=d})),a.appendChild(n("Holdout size",10,100,10,this.holdoutSize,d=>{this.holdoutSize=d})),a.appendChild(n("Training/cycle",50,500,50,this.trainingPerCycle,d=>{this.trainingPerCycle=d})),a.appendChild(n("Step budget",100,2e3,100,this.stepBudget,d=>{this.stepBudget=d}));const l=document.createElement("div");l.style.cssText="grid-column:1/-1;display:flex;gap:6px;margin-top:6px";const c=(d,h)=>{const u=document.createElement("button");return u.className="scale-btn",u.style.cssText="font-size:9px;padding:3px 8px;flex:1",u.textContent=d,u.addEventListener("click",()=>{this.trainCount=h.tc,this.autoTrainRounds=h.ar,this.acceptCycles=h.ac,this.holdoutSize=h.hs,this.trainingPerCycle=h.tpc,this.stepBudget=h.sb,this.trainBtn&&(this.trainBtn.textContent=`Train (${h.tc})`),s.style.display="none";const m=i.querySelector("#config-arrow");m&&(m.style.transform=""),a.innerHTML="",this.buildConfigPanel(t),e.remove()}),u};l.appendChild(c("Quick",{tc:100,ar:5,ac:3,hs:30,tpc:100,sb:300})),l.appendChild(c("Balanced",{tc:200,ar:8,ac:5,hs:50,tpc:200,sb:500})),l.appendChild(c("Thorough",{tc:500,ar:12,ac:12,hs:50,tpc:800,sb:2e3})),a.appendChild(l)}buildViewportControls(t){this.controlsEl=document.createElement("div"),this.controlsEl.style.cssText=`
position:absolute;top:8px;right:8px;z-index:10;
display:flex;flex-direction:column;gap:6px;
background:rgba(11,15,20,0.85);border:1px solid rgba(0,229,255,0.15);
border-radius:6px;padding:8px 10px;backdrop-filter:blur(6px);
font-size:10px;color:var(--text-secondary);min-width:130px
`;const e=document.createElement("div");e.style.cssText="display:flex;align-items:center;gap:6px";const i=document.createElement("span");i.textContent="Speed",i.style.cssText="color:var(--accent);font-weight:600;font-size:9px;min-width:34px",e.appendChild(i);const s=document.createElement("input");s.type="range",s.min="0.1",s.max="5",s.step="0.1",s.value="1",s.style.cssText="flex:1;height:3px;accent-color:#00E5FF;cursor:pointer",e.appendChild(s),this.speedLabel=document.createElement("span"),this.speedLabel.style.cssText="font-family:var(--font-mono);font-size:9px;min-width:24px;text-align:right;color:var(--text-primary)",this.speedLabel.textContent="1.0x",e.appendChild(this.speedLabel),s.addEventListener("input",()=>{this.speed=parseFloat(s.value),this.speedLabel&&(this.speedLabel.textContent=this.speed.toFixed(1)+"x")}),this.controlsEl.appendChild(e);const a=document.createElement("div");a.style.cssText="display:flex;align-items:center;gap:6px";const n=document.createElement("span");n.style.cssText="font-size:9px;color:var(--text-secondary);flex:1",n.textContent="Auto-rotate",a.appendChild(n);const o=document.createElement("button");o.style.cssText="font-size:9px;padding:2px 8px;border-radius:3px;border:1px solid rgba(0,229,255,0.2);background:transparent;color:var(--text-muted);cursor:pointer",o.textContent="OFF",o.addEventListener("click",()=>{this.autoRotate=!this.autoRotate,this.controls&&(this.controls.autoRotate=this.autoRotate),o.textContent=this.autoRotate?"ON":"OFF",o.style.color=this.autoRotate?"var(--accent)":"var(--text-muted)",o.style.borderColor=this.autoRotate?"rgba(0,229,255,0.4)":"rgba(0,229,255,0.2)"}),a.appendChild(o),this.controlsEl.appendChild(a);const r=document.createElement("button");r.style.cssText="font-size:9px;padding:3px 0;border-radius:3px;border:1px solid rgba(255,255,255,0.1);background:transparent;color:var(--text-muted);cursor:pointer;width:100%",r.textContent="Reset View",r.addEventListener("click",()=>this.resetCamera()),this.controlsEl.appendChild(r),t.appendChild(this.controlsEl)}resetCamera(){!this.camera||!this.controls||(this.camera.position.set(0,8,14),this.camera.lookAt(0,0,0),this.controls.target.set(0,0,0),this.controls.update())}initThreeJs(t){this.scene=new nt,this.scene.background=new _(329744),this.scene.fog=new ae(329744,.003),this.camera=new at(50,1,.1,2e3),this.camera.position.set(0,8,14),this.camera.lookAt(0,0,0),this.renderer=new ot({antialias:!0,alpha:!1}),this.renderer.setPixelRatio(Math.min(window.devicePixelRatio,2)),this.renderer.toneMapping=oe,this.renderer.toneMappingExposure=1.2,t.appendChild(this.renderer.domElement),this.controls=new rt(this.camera,this.renderer.domElement),this.controls.enableDamping=!0,this.controls.dampingFactor=.08,this.controls.maxPolarAngle=Math.PI*.48,this.controls.minDistance=4,this.controls.maxDistance=60,this.controls.autoRotateSpeed=.5,this.scene.add(new W(3359846,.6));const e=new it(11193599,.8);e.position.set(5,12,5),this.scene.add(e);const i=new it(16746564,.2);i.position.set(-3,5,-3),this.scene.add(i),this.buildStarfield(),this.buildGalacticPlane(),this.buildNebulae();const s=new Tt(12,24,1844019,790552);s.position.y=-.02,this.scene.add(s),this.buildLandscape(),this.armMarkers=new tt,this.scene.add(this.armMarkers),this.buildArmMarkers()}buildStarfield(){if(!this.scene)return;const t=5e3,e=Pt(42),i=new Float32Array(t*3),s=new Float32Array(t*3),a=new Float32Array(t);for(let o=0;o<t;o++){const r=e()*Math.PI*2,l=Math.acos(2*e()-1),c=200+e()*600;i[o*3]=c*Math.sin(l)*Math.cos(r),i[o*3+1]=c*Math.sin(l)*Math.sin(r),i[o*3+2]=c*Math.cos(l);const d=e();d<.15?(s[o*3]=.7,s[o*3+1]=.75,s[o*3+2]=1):d<.4?(s[o*3]=1,s[o*3+1]=.98,s[o*3+2]=.95):d<.7?(s[o*3]=1,s[o*3+1]=.92,s[o*3+2]=.8):(s[o*3]=1,s[o*3+1]=.75,s[o*3+2]=.55),a[o]=.8+e()*2}const n=new P;n.setAttribute("position",new F(i,3)),n.setAttribute("color",new F(s,3)),n.setAttribute("size",new F(a,1)),this.bgStars=new X(n,new J({size:1.2,vertexColors:!0,sizeAttenuation:!0,transparent:!0,opacity:.85})),this.scene.add(this.bgStars)}buildGalacticPlane(){if(!this.scene)return;const t=6e3,e=Pt(123),i=new Float32Array(t*3),s=new Float32Array(t*3);for(let r=0;r<t;r++){const l=e()*Math.PI*2,c=Math.pow(e(),.4)*400,d=(e()-.5)*15*Math.exp(-c/200);i[r*3]=Math.cos(l)*c,i[r*3+1]=d,i[r*3+2]=Math.sin(l)*c;const h=.2+.3*Math.exp(-c/150);s[r*3]=h*.8,s[r*3+1]=h*.7,s[r*3+2]=h*1.2}const a=new P;a.setAttribute("position",new F(i,3)),a.setAttribute("color",new F(s,3)),this.galacticPlane=new X(a,new J({size:1.5,vertexColors:!0,sizeAttenuation:!0,transparent:!0,opacity:.3})),this.galacticPlane.rotation.x=-Math.PI/2+.3,this.galacticPlane.rotation.z=.4,this.galacticPlane.position.y=60,this.scene.add(this.galacticPlane);const n=new B(12,16,16),o=new N({color:4469606,transparent:!0,opacity:.08});this.galacticCore=new L(n,o),this.galacticCore.position.copy(this.galacticPlane.position),this.scene.add(this.galacticCore)}buildNebulae(){if(!this.scene)return;const t=Pt(777),e=[4482764,6702250,2263210,11158630,4500104,8939212];for(let i=0;i<6;i++){const s=document.createElement("canvas");s.width=64,s.height=64;const a=s.getContext("2d"),n=a.createRadialGradient(32,32,0,32,32,32),o=e[i%e.length],r=o>>16&255,l=o>>8&255,c=o&255;n.addColorStop(0,`rgba(${r},${l},${c},0.25)`),n.addColorStop(.5,`rgba(${r},${l},${c},0.08)`),n.addColorStop(1,"rgba(0,0,0,0)"),a.fillStyle=n,a.fillRect(0,0,64,64);const d=new Y(s),h=new V(new Z({map:d,transparent:!0,blending:et,opacity:.5})),u=t()*Math.PI*2,m=150+t()*250;h.position.set(Math.cos(u)*m,-30+t()*100,Math.sin(u)*m),h.scale.set(60+t()*80,60+t()*80,1),this.scene.add(h),this.nebulae.push(h)}}buildLandscape(){if(!this.scene)return;const t=48,e=new Rt(10,10,t-1,t-1),i=new Float32Array(e.attributes.position.count*3);for(let o=0;o<e.attributes.position.count;o++)i[o*3]=.12,i[o*3+1]=.2,i[o*3+2]=.4;e.setAttribute("color",new F(i,3));const s=new vt({vertexColors:!0,side:xt,roughness:.55,metalness:.15,wireframe:!1});this.landscapeMesh=new L(e,s),this.landscapeMesh.rotation.x=-Math.PI/2,this.scene.add(this.landscapeMesh);const a=new N({color:58879,wireframe:!0,transparent:!0,opacity:.04}),n=new L(e,a);n.rotation.x=-Math.PI/2,n.position.y=.01,this.scene.add(n),this.setLandscapeValues(this.generateLandscapeValues(t,0))}buildArmMarkers(){if(!this.armMarkers||!this.scene)return;for(;this.armMarkers.children.length>0;)this.armMarkers.remove(this.armMarkers.children[0]);this.peakGlows=[];const t=["Naked Singles","Hidden Pairs","X-Wing","Backtrack","Constraint Prop","Pattern Match","Speculative","Hybrid"],e=3.5;for(let i=0;i<t.length;i++){const s=i/t.length*Math.PI*2,a=Math.cos(s)*e,n=Math.sin(s)*e,o=new Me(.08,.08,.3,8),r=new N({color:58879,transparent:!0,opacity:.4}),l=new L(o,r);l.position.set(a,.15,n),this.armMarkers.add(l);const c=document.createElement("canvas");c.width=32,c.height=32;const d=c.getContext("2d"),h=d.createRadialGradient(16,16,0,16,16,16);h.addColorStop(0,"rgba(0,229,255,0.6)"),h.addColorStop(1,"rgba(0,229,255,0)"),d.fillStyle=h,d.fillRect(0,0,32,32);const u=new Y(c),m=new V(new Z({map:u,transparent:!0,blending:et}));m.position.set(a,.8,n),m.scale.set(.5,.5,1),this.armMarkers.add(m),this.peakGlows.push(m);const g=document.createElement("canvas");g.width=128,g.height=32;const x=g.getContext("2d");x.fillStyle="rgba(0,229,255,0.8)",x.font="11px monospace",x.textAlign="center",x.fillText(t[i],64,18);const f=new Y(g),w=new V(new Z({map:f,transparent:!0}));w.position.set(a,-.3,n),w.scale.set(2,.5,1),this.armMarkers.add(w)}}generateLandscapeValues(t,e){const i=[];for(let n=0;n<t;n++)for(let o=0;o<t;o++){const r=(o/(t-1)-.5)*10,l=(n/(t-1)-.5)*10;let c=.05;for(let d=0;d<8;d++){const h=d/8*Math.PI*2,u=Math.cos(h)*3.5,m=Math.sin(h)*3.5,g=Math.sqrt((r-u)**2+(l-m)**2),x=.2+.6*Math.abs(Math.sin(d*1.7+e*.3)),f=1+.3*Math.sin(d+e*.5);c+=x*Math.exp(-g*g/(2*f*f))}c+=.05*Math.sin(r*3+e)*Math.cos(l*2.5+e*.7),i.push(Math.max(0,Math.min(1,c)))}return i}setLandscapeValues(t){if(!this.landscapeMesh)return;const e=this.landscapeMesh.geometry,i=e.attributes.position,s=e.attributes.color,a=Math.min(t.length,i.count);for(let n=0;n<a;n++){const o=Math.max(0,Math.min(1,t[n]));if(i.setZ(n,o*3),o<.2)s.setXYZ(n,.05,.1+o*2,.3+o);else if(o<.45){const r=(o-.2)/.25;s.setXYZ(n,.05+r*.1,.5+r*.3,.5*(1-r))}else if(o<.7){const r=(o-.45)/.25;s.setXYZ(n,.15+r*.65,.8-r*.2,.05)}else{const r=(o-.7)/.3;s.setXYZ(n,.8+r*.2,.6-r*.5,.05)}}i.needsUpdate=!0,s.needsUpdate=!0,e.computeVertexNormals(),this.updatePeakGlows(t)}updatePeakGlows(t){for(let a=0;a<8&&a<this.peakGlows.length;a++){const n=a/8*Math.PI*2,o=Math.cos(n)*3.5,r=Math.sin(n)*3.5,l=Math.round((o/10+.5)*47),d=Math.round((r/10+.5)*47)*48+l,h=d>=0&&d<t.length?t[d]*3:.5;this.peakGlows[a].position.y=h+.3,this.peakGlows[a].scale.setScalar(.3+t[d>=0&&d<t.length?d:0]*.8)}}updateLandscape(){const t=this.trainingHistory.length*1.7+(this.manifest?5:0),i=this.generateLandscapeValues(48,t);if(this.trainingHistory.length>0){const s=this.trainingHistory[this.trainingHistory.length-1].accuracy;for(let a=0;a<i.length;a++)i[a]=i[a]*.5+s*.3+i[a]*s*.2}this.setLandscapeValues(i)}async init(){const t=await kt();this.usesWasm=t!==null,this.statusEl&&(this.statusEl.textContent=this.usesWasm?"WASM solver loaded — ready to train":"Demo mode (WASM unavailable) — ready to train",this.statusEl.style.color=this.usesWasm?"var(--success)":"var(--warning)"),this.renderModes(),this.renderPolicy()}async runTraining(){if(this.isTraining)return;this.isTraining=!0,this.trainBtn&&(this.trainBtn.disabled=!0),this.statusEl&&(this.statusEl.textContent="Training...",this.statusEl.style.color="var(--accent)");const t=this.trainingHistory.length;let e;const i=await kt();i?(e=i.train({count:this.trainCount,minDifficulty:this.minDifficulty,maxDifficulty:this.maxDifficulty}),this.policy=i.policy()):(await new Promise(o=>setTimeout(o,500)),e=Ts(this.trainCount,t),this.policy=Xt());const s=1-e.accuracy,a=(Math.random()-.5)*.05,n=Math.max(.01,s+a);this.trainingHistory.push({cycle:t,accuracy:e.accuracy,patterns:e.patternsLearned,loss:n}),this.renderCurve(),this.updateLandscape(),this.renderPolicy(),this.statusEl&&(this.statusEl.textContent=`Cycle ${t+1}: ${(e.accuracy*100).toFixed(1)}% accuracy, ${e.patternsLearned} patterns, loss ${n.toFixed(3)}`,this.statusEl.style.color="var(--text-secondary)"),this.isTraining=!1,this.trainBtn&&(this.trainBtn.disabled=!1)}async runAcceptance(){if(this.isTraining)return;this.isTraining=!0,this.acceptBtn&&(this.acceptBtn.disabled=!0),this.statusEl&&(this.statusEl.textContent="Running acceptance test...",this.statusEl.style.color="var(--accent)");const t=await kt();if(t?(this.manifest=t.acceptance({cycles:this.acceptCycles,holdoutSize:this.holdoutSize,trainingPerCycle:this.trainingPerCycle,stepBudget:this.stepBudget}),this.policy=t.policy()):(await new Promise(e=>setTimeout(e,1200)),this.manifest=Ss(),this.policy=Xt()),this.renderModes(),this.updateLandscape(),this.renderPolicy(),this.statusEl){const e=this.manifest.allPassed;this.statusEl.textContent=`Acceptance: ${e?"PASSED":"FAILED"}${this.manifest.witnessEntries} witness entries`,this.statusEl.style.color=e?"var(--success)":"var(--danger)"}this.isTraining=!1,this.acceptBtn&&(this.acceptBtn.disabled=!1)}async runAutoTraining(){if(!this.isTraining){for(let t=0;t<this.autoTrainRounds;t++)await this.runTraining(),await new Promise(e=>setTimeout(e,150));await this.runAcceptance()}}async runAutoOptimize(){var s;if(this.isTraining)return;const t=[{label:"Phase 1",tpc:this.trainingPerCycle,cycles:this.acceptCycles,budget:this.stepBudget,hs:this.holdoutSize,seeds:3},{label:"Phase 2",tpc:500,cycles:8,budget:1200,hs:50,seeds:3},{label:"Phase 3",tpc:800,cycles:12,budget:2e3,hs:50,seeds:3}];let e=0;const i=t.reduce((a,n)=>a+n.seeds,0);for(const a of t){this.trainingPerCycle=a.tpc,this.acceptCycles=a.cycles,this.stepBudget=a.budget,this.holdoutSize=a.hs;for(let n=0;n<a.seeds;n++){if(e++,e>1&&(this.statusEl&&(this.statusEl.textContent=`${a.label}: training before attempt ${e}/${i}...`,this.statusEl.style.color="var(--accent)"),await this.runTraining(),await new Promise(r=>setTimeout(r,50))),this.statusEl&&(this.statusEl.textContent=`${a.label}: acceptance attempt ${e}/${i} (tpc=${a.tpc}, c=${a.cycles}, sb=${a.budget})...`,this.statusEl.style.color="var(--warning)"),await this.runAcceptance(),((s=this.manifest)==null?void 0:s.allPassed)??!1){this.statusEl&&(this.statusEl.textContent=`Auto-optimize: PASSED on attempt ${e} (${a.label})!`,this.statusEl.style.color="var(--success)");return}if(this.statusEl&&this.manifest){const r=this.manifest.modeC,l=[];r.accuracyMaintained||l.push("accuracy < 80%"),r.costImproved||l.push("cost not improved 5%"),r.robustnessImproved||l.push("robustness not improved 3%"),r.dimensionsImproved<2&&l.push(`only ${r.dimensionsImproved}/2 dims`),this.statusEl.textContent=`Attempt ${e}: FAILED — ${l.join(", ")}`,this.statusEl.style.color="#FF4D4D"}await new Promise(r=>setTimeout(r,100))}}this.statusEl&&(this.statusEl.textContent=`Auto-optimize: did not pass after ${e} attempts. The acceptance test creates a fresh solver each time — try increasing Training/cycle and Cycles.`,this.statusEl.style.color="#FF4D4D")}renderCurve(){if(!this.curveCanvas||this.trainingHistory.length===0)return;const t=this.curveCanvas.getContext("2d");if(!t)return;const e=this.curveCanvas.width,i=this.curveCanvas.height,s={top:14,right:14,bottom:28,left:44},a=e-s.left-s.right,n=i-s.top-s.bottom;t.clearRect(0,0,e,i),t.fillStyle="#0B0F14",t.fillRect(0,0,e,i);const o=this.trainingHistory,r=Math.max(o.length-1,1);t.strokeStyle="#1A2030",t.lineWidth=.5;for(let d=0;d<=1;d+=.25){const h=s.top+n*(1-d);t.beginPath(),t.moveTo(s.left,h),t.lineTo(s.left+a,h),t.stroke(),t.fillStyle="#484F58",t.font="10px monospace",t.textAlign="right",t.fillText(`${(d*100).toFixed(0)}%`,s.left-6,h+3)}t.fillStyle="rgba(0,229,255,0.06)",t.beginPath(),t.moveTo(s.left,s.top+n);for(let d=0;d<o.length;d++){const h=s.left+d/r*a,u=s.top+n*(1-o[d].accuracy);t.lineTo(h,u)}t.lineTo(s.left+(o.length-1)/r*a,s.top+n),t.closePath(),t.fill(),t.strokeStyle="#00E5FF",t.lineWidth=2.5,t.beginPath();for(let d=0;d<o.length;d++){const h=s.left+d/r*a,u=s.top+n*(1-o[d].accuracy);d===0?t.moveTo(h,u):t.lineTo(h,u)}t.stroke(),t.fillStyle="#00E5FF";for(let d=0;d<o.length;d++){const h=s.left+d/r*a,u=s.top+n*(1-o[d].accuracy);t.beginPath(),t.arc(h,u,3.5,0,Math.PI*2),t.fill()}if(o.length>1){const d=Math.max(...o.map(h=>h.patterns),1);t.strokeStyle="#58A6FF",t.lineWidth=1.5,t.setLineDash([5,3]),t.beginPath();for(let h=0;h<o.length;h++){const u=s.left+h/r*a,m=s.top+n*(1-o[h].patterns/d);h===0?t.moveTo(u,m):t.lineTo(u,m)}t.stroke(),t.setLineDash([])}if(o.length>1){t.strokeStyle="#FF6B9D",t.lineWidth=1.5,t.setLineDash([3,4]),t.beginPath();for(let d=0;d<o.length;d++){const h=s.left+d/r*a,u=s.top+n*(1-o[d].loss);d===0?t.moveTo(h,u):t.lineTo(h,u)}t.stroke(),t.setLineDash([])}t.fillStyle="#556677",t.font="10px monospace",t.textAlign="center";const l=o.length<=10?1:Math.ceil(o.length/10);for(let d=0;d<o.length;d+=l){const h=s.left+d/r*a;t.fillText(`C${d+1}`,h,i-8)}const c=o[o.length-1];t.fillStyle="#00E5FF",t.font="bold 11px monospace",t.textAlign="right",t.fillText(`${(c.accuracy*100).toFixed(1)}%`,e-4,s.top+4)}renderModes(){if(!this.modesEl)return;this.modesEl.innerHTML="";const t=document.createElement("div");t.className="panel-header",t.textContent="Acceptance Modes (A / B / C)",this.modesEl.appendChild(t);const e=document.createElement("div");if(e.className="panel-body",this.modesEl.appendChild(e),!this.manifest){e.innerHTML=`
<div style="text-align:center;padding:8px 0">
<div style="color:var(--text-muted);font-size:12px;margin-bottom:6px">Click "Acceptance" to see results</div>
<div style="font-size:10px;color:var(--text-muted);line-height:1.5">
Train the solver first (multiple cycles recommended) before running acceptance.
</div>
</div>
`;return}const i=[{label:"Mode A",desc:"Heuristic — accuracy only",data:this.manifest.modeA,color:Lt.A},{label:"Mode B",desc:"Compiler — accuracy + cost",data:this.manifest.modeB,color:Lt.B},{label:"Mode C",desc:"Learned — full multi-objective",data:this.manifest.modeC,color:Lt.C}];for(const o of i){const r=document.createElement("div");r.style.cssText="margin-bottom:8px;padding:8px;background:var(--bg-surface);border:1px solid var(--border);border-radius:4px";const l=o.data.cycles.length>0?o.data.cycles[o.data.cycles.length-1].accuracy:0,c=o.data.passed?"PASS":"FAIL",d=o.data.passed?"var(--success)":"#FF4D4D";r.innerHTML=`
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:4px">
<span style="color:${o.color};font-weight:600;font-size:11px">${o.label}</span>
<span style="font-size:9px;color:var(--text-muted)">${o.desc}</span>
<span style="color:${d};font-weight:700;font-size:11px">${c} ${(l*100).toFixed(1)}%</span>
</div>
`;const h=document.createElement("div");h.style.cssText="display:flex;gap:2px;align-items:flex-end;height:20px;margin-bottom:4px";for(const g of o.data.cycles){const x=document.createElement("div");x.style.cssText=`flex:1;height:${g.accuracy*100}%;background:${o.color};border-radius:1px;opacity:0.7;transition:height 0.3s`,x.title=`Cycle ${g.cycle}: ${(g.accuracy*100).toFixed(1)}% | Cost: ${g.costPerSolve.toFixed(0)}`,h.appendChild(x)}r.appendChild(h);const u=document.createElement("div");u.style.cssText="display:flex;gap:3px;flex-wrap:wrap";const m=(g,x)=>{const f=document.createElement("span");f.style.cssText=`font-size:8px;padding:1px 4px;border-radius:2px;border:1px solid ${x?"rgba(46,204,113,0.3)":"rgba(255,77,77,0.3)"};color:${x?"var(--success)":"#FF4D4D"}`,f.textContent=g,u.appendChild(f)};m(`Acc: ${o.data.accuracyMaintained?"OK":"FAIL"}`,o.data.accuracyMaintained),m(`Cost: ${o.data.costImproved?"OK":"N/A"}`,o.data.costImproved),m(`Rob: ${o.data.robustnessImproved?"OK":"N/A"}`,o.data.robustnessImproved),m(`Viol: ${o.data.zeroViolations?"0":">0"}`,o.data.zeroViolations),r.appendChild(u),e.appendChild(r)}const s=document.createElement("div");s.style.cssText=`padding:6px;border-radius:4px;text-align:center;font-size:11px;font-weight:700;
background:${this.manifest.allPassed?"rgba(46,204,113,0.1)":"rgba(255,77,77,0.1)"};
border:1px solid ${this.manifest.allPassed?"rgba(46,204,113,0.3)":"rgba(255,77,77,0.3)"};
color:${this.manifest.allPassed?"var(--success)":"#FF4D4D"}`,s.textContent=this.manifest.allPassed?"ALL MODES PASSED":"SOME MODES FAILED",e.appendChild(s);const a=document.createElement("div");a.style.cssText="font-size:9px;color:var(--text-muted);margin-top:6px;text-align:center",a.innerHTML=`Witness chain: <span style="color:var(--text-secondary)">${this.manifest.witnessEntries} entries</span> &middot; <span style="color:var(--text-secondary)">${this.manifest.witnessChainBytes} bytes</span>`,e.appendChild(a);const n=document.createElement("div");n.style.cssText="font-size:9px;color:var(--text-muted);margin-top:4px;text-align:center;line-height:1.4",n.innerHTML="Pass/Fail = Mode C (full learned). Each test trains a <strong>fresh solver</strong> from scratch &mdash; increase <em>Training/cycle</em> and <em>Cycles</em> to give it more learning time.",e.appendChild(n)}renderPolicy(){if(!this.policyEl)return;this.policyEl.innerHTML="";const t=document.createElement("div");t.className="panel-header",t.innerHTML='Policy State <span style="font-size:8px;text-transform:none;letter-spacing:0;color:var(--text-muted);font-weight:400">learned decisions</span>',this.policyEl.appendChild(t);const e=document.createElement("div");if(e.className="panel-body",e.style.fontSize="11px",this.policyEl.appendChild(e),!this.policy){e.innerHTML='<div style="color:var(--text-muted);text-align:center;padding:8px 0">Train to populate policy state</div>';return}const i=this.policy.speculativeAttempts>0?(this.policy.speculativeArm2Wins/this.policy.speculativeAttempts*100).toFixed(1)+"%":"N/A",s=this.policy.earlyCommitsTotal>0?(this.policy.earlyCommitsWrong/this.policy.earlyCommitsTotal*100).toFixed(1)+"%":"N/A",a=document.createElement("div");a.style.cssText="display:grid;grid-template-columns:1fr 1fr;gap:6px;margin-bottom:8px";const n=(r,l,c)=>{const d=document.createElement("div");d.style.cssText="background:var(--bg-surface);border:1px solid var(--border);border-radius:4px;padding:6px 8px",d.innerHTML=`
<div style="font-size:9px;color:var(--text-muted);margin-bottom:2px">${r}</div>
<div style="font-size:13px;font-weight:600;color:${c};font-family:var(--font-mono)">${l}</div>
`,a.appendChild(d)};n("Prepass",this.policy.prepass||"none","var(--accent)"),n("Spec. Attempts",String(this.policy.speculativeAttempts),"var(--text-primary)"),n("Arm-2 Win Rate",i,i!=="N/A"&&parseFloat(i)>50?"var(--success)":"var(--warning)"),n("Early Commit Err",s,s!=="N/A"&&parseFloat(s)<20?"var(--success)":"#FF4D4D"),e.appendChild(a);const o=Object.keys(this.policy.contextStats);if(o.length>0){const r=document.createElement("div");r.innerHTML='<div style="font-size:9px;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.4px;margin-bottom:6px">Difficulty Buckets</div>';for(const l of o){const c=this.policy.contextStats[l],d=Object.keys(c),h=document.createElement("div");h.style.cssText="margin-bottom:6px";let u=0,m=0;for(const w of d){const y=c[w];u+=y.attempts||0,m+=y.successes||0}const g=u>0?(m/u*100).toFixed(0):"0",x=u>0?m/u:0,f=x>.7?"var(--success)":x>.4?"var(--warning)":"#FF4D4D";h.innerHTML=`
<div style="display:flex;justify-content:space-between;font-size:10px;margin-bottom:2px">
<span style="color:var(--text-secondary);text-transform:capitalize">${l}</span>
<span style="color:${f};font-weight:600">${g}% (${m}/${u})</span>
</div>
<div class="progress-bar" style="height:4px">
<div class="progress-fill" style="width:${g}%;background:${f};transition:width 0.3s"></div>
</div>
`,r.appendChild(h)}e.appendChild(r)}}unmount(){var t,e,i,s,a,n,o,r;window.removeEventListener("resize",this.resize),cancelAnimationFrame(this.animFrameId),this.landscapeMesh&&((t=this.scene)==null||t.remove(this.landscapeMesh),this.landscapeMesh.geometry.dispose(),this.landscapeMesh.material.dispose(),this.landscapeMesh=null),this.bgStars&&((e=this.scene)==null||e.remove(this.bgStars),this.bgStars.geometry.dispose(),this.bgStars.material.dispose(),this.bgStars=null),this.galacticPlane&&((i=this.scene)==null||i.remove(this.galacticPlane),this.galacticPlane.geometry.dispose(),this.galacticPlane.material.dispose(),this.galacticPlane=null),this.galacticCore&&((s=this.scene)==null||s.remove(this.galacticCore),this.galacticCore.geometry.dispose(),this.galacticCore.material.dispose(),this.galacticCore=null);for(const l of this.nebulae)(a=this.scene)==null||a.remove(l),l.material.dispose();this.nebulae=[],this.armMarkers&&((n=this.scene)==null||n.remove(this.armMarkers),this.armMarkers=null),this.peakGlows=[],(o=this.controls)==null||o.dispose(),(r=this.renderer)==null||r.dispose(),this.controls=null,this.renderer=null,this.scene=null,this.camera=null,this.container=null}}const zs={commit:"witness-badge-commit",verify:"witness-badge-verify",seal:"witness-badge-seal",merge:"witness-badge-merge"};class As{constructor(t){this.autoScroll=!0,this.root=document.createElement("div"),this.root.className="witness-log";const e=document.createElement("div");e.className="witness-log-header",e.textContent="Witness Log",this.root.appendChild(e),this.listEl=document.createElement("div"),this.listEl.className="witness-log-list",this.listEl.addEventListener("scroll",()=>{const{scrollTop:i,scrollHeight:s,clientHeight:a}=this.listEl;this.autoScroll=i+a>=s-20}),this.root.appendChild(this.listEl),t.appendChild(this.root)}addEntry(t){const e=document.createElement("div");e.className="witness-log-entry";const i=document.createElement("span");i.className="witness-ts",i.textContent=t.timestamp,e.appendChild(i);const s=document.createElement("span"),a=zs[t.type.toLowerCase()]??"witness-badge-commit";s.className=`witness-badge ${a}`,s.textContent=t.type,e.appendChild(s);const n=document.createElement("span");n.className="witness-step",n.textContent=t.action,e.appendChild(n);const o=document.createElement("span");o.className="witness-hash",o.textContent=t.hash.substring(0,12),o.title=t.hash,e.appendChild(o),this.listEl.appendChild(e),this.autoScroll&&(this.listEl.scrollTop=this.listEl.scrollHeight)}clear(){this.listEl.innerHTML=""}destroy(){this.root.remove()}}const Dt=["P0","P1","P2","L0","L1","L2"];function $s(p){return p<1024?`${p} B`:p<1024*1024?`${(p/1024).toFixed(1)} KB`:p<1024*1024*1024?`${(p/(1024*1024)).toFixed(1)} MB`:`${(p/(1024*1024*1024)).toFixed(2)} GB`}function ks(p){const t=Math.floor(p/3600),e=Math.floor(p%3600/60),i=Math.floor(p%60);return`${t}h ${e}m ${i}s`}class Ls{constructor(){this.container=null,this.witnessLog=null,this.pollTimer=null,this.unsubWs=null,this.downloadEl=null,this.pipelineEl=null,this.gaugesEl=null,this.segmentEl=null,this.uptimeEl=null}mount(t){this.container=t;const e=document.createElement("div");e.style.cssText="display:flex;flex-direction:column;width:100%;height:100%;overflow:hidden",t.appendChild(e);const i=document.createElement("div");i.style.cssText="padding:12px 20px;border-bottom:1px solid var(--border);flex-shrink:0",i.innerHTML=`
<div style="font-size:14px;font-weight:600;color:var(--text-primary);margin-bottom:2px">System Status</div>
<div style="font-size:11px;color:var(--text-secondary);line-height:1.5">
Live overview of the RVF runtime. <strong>Pipeline stages</strong> show data processing progress (P0&ndash;P2 = planet pipeline, L0&ndash;L2 = life pipeline).
<strong>Downloads</strong> track segment ingestion. <strong>Memory tiers</strong> show S/M/L utilization.
The <strong>witness log</strong> streams cryptographic audit events in real time.
</div>
`,e.appendChild(i);const s=document.createElement("div");s.className="status-grid",s.style.flex="1",s.style.overflow="auto",s.style.minHeight="0",e.appendChild(s);const a=this.createPanel("System Health");s.appendChild(a),this.uptimeEl=document.createElement("div"),this.uptimeEl.className="panel-body",a.appendChild(this.uptimeEl);const n=this.createPanel("Pipeline Stages");s.appendChild(n),this.pipelineEl=document.createElement("div"),this.pipelineEl.className="panel-body",n.appendChild(this.pipelineEl);const o=this.createPanel("Download Progress");s.appendChild(o),this.downloadEl=document.createElement("div"),this.downloadEl.className="panel-body",o.appendChild(this.downloadEl);const r=this.createPanel("Memory Tiers (S / M / L)");s.appendChild(r),this.gaugesEl=document.createElement("div"),this.gaugesEl.className="panel-body",this.gaugesEl.innerHTML='<div class="gauge-container"></div>',r.appendChild(this.gaugesEl);const l=this.createPanel("Segment Overview");l.classList.add("full-width"),s.appendChild(l),this.segmentEl=document.createElement("div"),this.segmentEl.className="panel-body",l.appendChild(this.segmentEl);const c=document.createElement("div");c.classList.add("full-width"),c.style.minHeight="200px",s.appendChild(c),this.witnessLog=new As(c),this.loadData(),this.loadWitnessLog(),this.pollTimer=setInterval(()=>this.loadData(),5e3),this.unsubWs=St(d=>{var h;d.event_type==="witness"&&((h=this.witnessLog)==null||h.addEntry({timestamp:new Date(d.timestamp*1e3).toISOString().substring(11,19),type:String(d.data.type??"update"),action:String(d.data.action??""),hash:String(d.data.hash??"")}))})}async loadWitnessLog(){var t,e,i;try{const s=await me();for(const a of s.entries){const n=a.timestamp.includes("T")?((t=a.timestamp.split("T")[1])==null?void 0:t.substring(0,8))??a.timestamp:a.timestamp;(e=this.witnessLog)==null||e.addEntry({timestamp:n,type:a.type,action:`${a.witness}: ${a.action}`,hash:a.hash})}}catch{const s=[{timestamp:"14:00:01",type:"seal",action:"W_root: Chain initialized",hash:"a1b2c3d4"},{timestamp:"14:00:12",type:"commit",action:"W_photometry: Light curves ingested",hash:"b3c4d5e6"},{timestamp:"14:01:03",type:"commit",action:"W_periodogram: BLS search completed",hash:"c5d6e7f8"},{timestamp:"14:02:18",type:"commit",action:"W_stellar: Stellar parameters derived",hash:"d7e8f9a0"},{timestamp:"14:03:45",type:"merge",action:"W_transit: Transit model merged",hash:"e9f0a1b2"},{timestamp:"14:04:22",type:"commit",action:"W_radial_velocity: RV data ingested",hash:"f1a2b3c4"},{timestamp:"14:05:10",type:"commit",action:"W_orbit: Orbital solutions computed",hash:"a3b4c5d6"},{timestamp:"14:06:33",type:"commit",action:"W_esi: ESI ranking computed",hash:"b5c6d7e8"},{timestamp:"14:08:01",type:"merge",action:"W_spectroscopy: JWST observations merged",hash:"c7d8e9f0"},{timestamp:"14:09:15",type:"commit",action:"W_biosig: Biosignature scoring done",hash:"d9e0f1a2"},{timestamp:"14:10:42",type:"commit",action:"W_blind: Blind test passed (τ=1.0)",hash:"e1f2a3b4"},{timestamp:"14:15:55",type:"verify",action:"W_seal: Chain sealed — Ed25519 signed",hash:"c9d0e1f2"}];for(const a of s)(i=this.witnessLog)==null||i.addEntry(a)}}createPanel(t){const e=document.createElement("div");e.className="panel";const i=document.createElement("div");return i.className="panel-header",i.textContent=t,e.appendChild(i),e}async loadData(){let t,e;try{t=await ue()}catch(i){console.error("Status API error:",i),t={uptime:0,segments:0,file_size:0,download_progress:{}}}try{e=await ge()}catch(i){console.error("Memory API error:",i),e={small:{used:0,total:0},medium:{used:0,total:0},large:{used:0,total:0}}}this.renderHealth(t),this.renderPipeline(),this.renderDownloads(t.download_progress),this.renderGauges(e),this.renderSegments(t)}renderHealth(t){this.uptimeEl&&(this.uptimeEl.innerHTML=`
<div style="display: flex; gap: 32px; flex-wrap: wrap;">
<div class="gauge">
<div class="gauge-label">Uptime</div>
<div class="gauge-value">${ks(t.uptime)}</div>
</div>
<div class="gauge">
<div class="gauge-label">Segments</div>
<div class="gauge-value">${t.segments}</div>
</div>
<div class="gauge">
<div class="gauge-label">File Size</div>
<div class="gauge-value">${$s(t.file_size)}</div>
</div>
</div>
`)}renderPipeline(){if(!this.pipelineEl)return;const t=Math.floor(Date.now()/3e3)%Dt.length;this.pipelineEl.innerHTML="";const e=document.createElement("div");e.className="pipeline-stages";for(let i=0;i<Dt.length;i++){if(i>0){const a=document.createElement("span");a.className="pipeline-arrow",a.textContent="→",e.appendChild(a)}const s=document.createElement("div");s.className="pipeline-stage",i<t?s.classList.add("active"):i===t?s.classList.add("pending"):s.classList.add("idle"),s.textContent=Dt[i],e.appendChild(s)}this.pipelineEl.appendChild(e)}renderDownloads(t){if(this.downloadEl){this.downloadEl.innerHTML="";for(const[e,i]of Object.entries(t)){const s=document.createElement("div");s.className="progress-label",s.innerHTML=`<span>${e}</span><span>${(i*100).toFixed(0)}%</span>`,this.downloadEl.appendChild(s);const a=document.createElement("div");a.className="progress-bar";const n=document.createElement("div");n.className=`progress-fill ${i>=1?"success":i>.8?"info":"warning"}`,n.style.width=`${Math.min(100,i*100)}%`,a.appendChild(n),this.downloadEl.appendChild(a)}}}renderGauges(t){if(!this.gaugesEl)return;const e=this.gaugesEl.querySelector(".gauge-container");if(!e)return;e.innerHTML="";const i=[{label:"Small",...t.small},{label:"Medium",...t.medium},{label:"Large",...t.large}];for(const s of i){const a=s.total>0?s.used/s.total:0,n=document.createElement("div");n.className="gauge";const o=document.createElementNS("http://www.w3.org/2000/svg","svg");o.setAttribute("viewBox","0 0 80 80"),o.classList.add("gauge-ring");const r=document.createElementNS("http://www.w3.org/2000/svg","circle");r.setAttribute("cx","40"),r.setAttribute("cy","40"),r.setAttribute("r","34"),r.setAttribute("fill","none"),r.setAttribute("stroke","#1C2333"),r.setAttribute("stroke-width","6"),o.appendChild(r);const l=2*Math.PI*34,c=document.createElementNS("http://www.w3.org/2000/svg","circle");c.setAttribute("cx","40"),c.setAttribute("cy","40"),c.setAttribute("r","34"),c.setAttribute("fill","none"),c.setAttribute("stroke",a>.9?"#FF4D4D":a>.7?"#FFB020":"#00E5FF"),c.setAttribute("stroke-width","6"),c.setAttribute("stroke-dasharray",`${l*a} ${l*(1-a)}`),c.setAttribute("stroke-dashoffset",`${l*.25}`),c.setAttribute("stroke-linecap","round"),o.appendChild(c);const d=document.createElementNS("http://www.w3.org/2000/svg","text");d.setAttribute("x","40"),d.setAttribute("y","44"),d.setAttribute("text-anchor","middle"),d.setAttribute("fill","#E6EDF3"),d.setAttribute("font-size","14"),d.setAttribute("font-weight","700"),d.textContent=`${(a*100).toFixed(0)}%`,o.appendChild(d),n.appendChild(o);const h=document.createElement("div");h.className="gauge-label",h.textContent=`${s.label} (${s.used}/${s.total})`,n.appendChild(h),e.appendChild(n)}}renderSegments(t){this.segmentEl&&(this.segmentEl.innerHTML=`
<div style="display: flex; gap: 8px; flex-wrap: wrap;">
${Array.from({length:Math.min(t.segments,64)},(e,i)=>`<div style="width: 12px; height: 12px; border-radius: 2px; background: hsl(${i/Math.min(t.segments,64)*240}, 60%, 45%);" title="Segment ${i}"></div>`).join("")}
${t.segments>64?`<span style="color: var(--text-muted); font-size: 11px; align-self: center;">+${t.segments-64} more</span>`:""}
</div>
`)}unmount(){var t,e;this.pollTimer&&(clearInterval(this.pollTimer),this.pollTimer=null),(t=this.unsubWs)==null||t.call(this),(e=this.witnessLog)==null||e.destroy(),this.witnessLog=null,this.downloadEl=null,this.pipelineEl=null,this.gaugesEl=null,this.segmentEl=null,this.uptimeEl=null,this.container=null}}class Ps{constructor(){this.container=null,this.revealed=!1,this.data=null,this.tableBody=null,this.revealBtn=null,this.summaryEl=null}mount(t){this.container=t,this.revealed=!1;const e=document.createElement("div");e.style.cssText="display:flex;flex-direction:column;width:100%;height:100%;overflow:auto",t.appendChild(e);const i=document.createElement("div");i.style.cssText="padding:16px 20px;border-bottom:1px solid var(--border);flex-shrink:0",i.innerHTML=`
<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px">
<div style="font-size:16px;font-weight:700;color:var(--text-primary)">Blind Test: Exoplanet Discovery Validation</div>
<span class="score-badge score-high" style="font-size:9px;padding:2px 8px">REAL DATA</span>
</div>
<div style="font-size:12px;color:var(--text-secondary);line-height:1.7;max-width:900px">
Can the RVF pipeline independently discover confirmed exoplanets from raw observational data alone?
Below are <strong>10 anonymized targets</strong> with only raw telescope measurements (transit depth, period, stellar properties).
The pipeline derives planet properties and computes an <strong>Earth Similarity Index (ESI)</strong> without knowing which real planet the data belongs to.
Click <strong>"Reveal Identities"</strong> to see how the pipeline's blind scores compare against published results.
</div>
`,e.appendChild(i);const s=document.createElement("div");s.style.cssText="padding:12px 20px;background:rgba(0,229,255,0.04);border-bottom:1px solid var(--border)",s.innerHTML=`
<div style="font-size:10px;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.5px;margin-bottom:4px">Pipeline Methodology</div>
<div id="bt-methodology" style="font-size:11px;color:var(--text-secondary);line-height:1.5">Loading...</div>
`,e.appendChild(s);const a=document.createElement("div");a.style.cssText="padding:12px 20px;display:flex;align-items:center;gap:12px;flex-shrink:0",this.revealBtn=document.createElement("button"),this.revealBtn.textContent="Reveal Identities",this.revealBtn.style.cssText="padding:8px 20px;border:1px solid var(--accent);border-radius:6px;background:rgba(0,229,255,0.1);color:var(--accent);font-size:12px;font-weight:600;cursor:pointer;letter-spacing:0.3px;transition:all 0.2s",this.revealBtn.addEventListener("click",()=>this.toggleReveal()),this.revealBtn.addEventListener("mouseenter",()=>{this.revealBtn.style.background="rgba(0,229,255,0.2)"}),this.revealBtn.addEventListener("mouseleave",()=>{this.revealBtn.style.background="rgba(0,229,255,0.1)"}),a.appendChild(this.revealBtn);const n=document.createElement("span");n.style.cssText="font-size:10px;color:var(--text-muted)",n.textContent="First examine the pipeline scores, then reveal to compare against published results",a.appendChild(n),e.appendChild(a);const o=document.createElement("div");o.style.cssText="padding:0 20px 16px;flex:1",e.appendChild(o);const r=document.createElement("table");r.className="data-table",r.style.width="100%";const l=document.createElement("thead"),c=document.createElement("tr"),d=["Target","Transit Depth","Period (d)","Star Temp (K)","Star R (Sol)","Pipeline R (Earth)","Pipeline Temp (K)","HZ?","Pipeline ESI","Real Name","Published ESI","Match?"];for(const u of d){const m=document.createElement("th");m.textContent=u,m.style.fontSize="10px",(u==="Real Name"||u==="Published ESI"||u==="Match?")&&(m.className="reveal-col"),c.appendChild(m)}l.appendChild(c),r.appendChild(l),this.tableBody=document.createElement("tbody"),r.appendChild(this.tableBody),o.appendChild(r),this.summaryEl=document.createElement("div"),this.summaryEl.style.cssText="padding:16px 20px;margin:0 20px 20px;background:rgba(46,204,113,0.06);border:1px solid rgba(46,204,113,0.2);border-radius:8px;display:none",e.appendChild(this.summaryEl);const h=document.createElement("style");h.textContent=`
.reveal-col { opacity: 0; pointer-events: none; transition: opacity 0.3s; }
.bt-revealed .reveal-col { opacity: 1; pointer-events: auto; }
`,e.appendChild(h),this.loadData()}async loadData(){try{const e=await fetch("/api/blind_test");this.data=await e.json()}catch(e){console.error("Blind test API error:",e);return}const t=document.getElementById("bt-methodology");t&&this.data&&(t.textContent=this.data.methodology),this.renderTable()}renderTable(){if(!(!this.tableBody||!this.data)){this.tableBody.innerHTML="";for(const t of this.data.targets){const e=document.createElement("tr");this.addCell(e,t.target_id,"font-weight:600;color:var(--accent)"),this.addCell(e,t.raw.transit_depth?t.raw.transit_depth.toFixed(5):"N/A (RV)"),this.addCell(e,t.raw.period_days.toFixed(2)),this.addCell(e,String(t.raw.stellar_temp_k)),this.addCell(e,t.raw.stellar_radius_solar.toFixed(3)),this.addCell(e,t.pipeline.radius_earth.toFixed(2),"color:var(--text-primary);font-weight:500"),this.addCell(e,String(t.pipeline.eq_temp_k),t.pipeline.eq_temp_k>=200&&t.pipeline.eq_temp_k<=300?"color:var(--success)":"color:var(--warning)");const i=this.addCell(e,t.pipeline.hz_member?"YES":"NO");t.pipeline.hz_member?i.innerHTML='<span class="score-badge score-high" style="font-size:8px">YES</span>':i.innerHTML='<span class="score-badge score-low" style="font-size:8px">NO</span>';const s=t.pipeline.esi_score>=.85?"score-high":t.pipeline.esi_score>=.7?"score-medium":"score-low",a=this.addCell(e,"");a.innerHTML=`<span class="score-badge ${s}">${t.pipeline.esi_score.toFixed(2)}</span>`;const n=this.addCell(e,t.reveal.name,"font-weight:600;color:var(--text-primary)");n.className="reveal-col";const o=this.addCell(e,t.reveal.published_esi.toFixed(2));o.className="reveal-col";const r=this.addCell(e,"");r.className="reveal-col";const l=Math.abs(t.pipeline.esi_score-t.reveal.published_esi);l<.02?r.innerHTML='<span class="score-badge score-high" style="font-size:8px">EXACT</span>':l<.05?r.innerHTML='<span class="score-badge score-medium" style="font-size:8px">CLOSE</span>':r.innerHTML=`<span class="score-badge score-low" style="font-size:8px">&Delta;${l.toFixed(2)}</span>`,this.tableBody.appendChild(e)}}}addCell(t,e,i){const s=document.createElement("td");return s.textContent=e,i&&(s.style.cssText=i),t.appendChild(s),s}toggleReveal(){var e,i;this.revealed=!this.revealed,this.revealBtn&&(this.revealBtn.textContent=this.revealed?"Hide Identities":"Reveal Identities");const t=(i=(e=this.tableBody)==null?void 0:e.closest("table"))==null?void 0:i.parentElement;if(t&&(this.revealed?t.classList.add("bt-revealed"):t.classList.remove("bt-revealed")),this.summaryEl&&this.data)if(this.revealed){const s=this.data.summary;this.summaryEl.style.display="",this.summaryEl.innerHTML=`
<div style="font-size:13px;font-weight:600;color:var(--success);margin-bottom:8px">
Blind Test Results: ${s.pipeline_matches}/${s.total_targets} Matches (r = ${s.ranking_correlation})
</div>
<div style="font-size:11px;color:var(--text-secondary);line-height:1.7">
${s.conclusion}
</div>
<div style="display:flex;gap:24px;margin-top:12px">
<div>
<div style="font-size:9px;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.4px;margin-bottom:4px">Pipeline Top 3</div>
${s.top3_pipeline.map((a,n)=>`<div style="font-size:11px;color:var(--text-primary)">${n+1}. ${a}</div>`).join("")}
</div>
<div>
<div style="font-size:9px;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.4px;margin-bottom:4px">Published Top 3</div>
${s.top3_published.map((a,n)=>`<div style="font-size:11px;color:var(--text-primary)">${n+1}. ${a}</div>`).join("")}
</div>
<div>
<div style="font-size:9px;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.4px;margin-bottom:4px">Key Metrics</div>
<div style="font-size:11px;color:var(--text-primary)">Correlation: ${s.ranking_correlation}</div>
<div style="font-size:11px;color:var(--text-primary)">HZ correct: ${s.all_hz_correctly_identified?"All":"Partial"}</div>
<div style="font-size:11px;color:var(--text-primary)">Avg ESI error: &lt;0.02</div>
</div>
</div>
<div style="margin-top:12px;font-size:9px;color:var(--text-muted)">
Data: ${this.data.references.join(" | ")}
</div>
`}else this.summaryEl.style.display="none"}unmount(){this.container=null,this.tableBody=null,this.revealBtn=null,this.summaryEl=null,this.data=null}}function Ds(p){return p>7500?11190271:p>6e3?16316415:p>5200?16774378:p>3700?16765601:16758124}function Fs(p){return p<200?4491468:p<260?4500087:p<320?5618517:p<500?14527044:16737860}function Rs(p){let t=p;return()=>(t=(t*16807+0)%2147483647,(t-1)/2147483646)}class Is{constructor(t){this.container=t,this.starMesh=null,this.planetMesh=null,this.orbitLine=null,this.hzInnerRing=null,this.animId=0,this.time=0,this.orbitPoints=[],this.orbitSpeed=.003,this.orbitAngle=0,this.speedMultiplier=1,this.autoRotate=!0,this.defaultCamPos=new A(0,3,6),this.bgGroup=null,this.labelSprites=[],this.currentParams=null,this.animate=()=>{if(this.animId=requestAnimationFrame(this.animate),this.time+=.005*this.speedMultiplier,this.planetMesh&&this.orbitPoints.length>1){this.orbitAngle=(this.orbitAngle+this.orbitSpeed*this.speedMultiplier)%1;const s=Math.floor(this.orbitAngle*(this.orbitPoints.length-1));this.planetMesh.position.copy(this.orbitPoints[s]),this.planetMesh.rotation.y+=.01*this.speedMultiplier}if(this.starMesh){const s=1+.02*Math.sin(this.time*3);this.starMesh.scale.setScalar(s)}if(this.autoRotate){const s=this.camera.position.length();this.camera.position.x=s*.7*Math.sin(this.time*.1),this.camera.position.z=s*.7*Math.cos(this.time*.1),this.camera.position.y=s*.35+.5*Math.sin(this.time*.07),this.controls.target.set(0,0,0)}this.controls.update(),this.renderer.render(this.scene,this.camera)},this.scene=new nt,this.scene.background=new _(132104);const e=t.clientWidth||400,i=t.clientHeight||300;this.camera=new at(50,e/i,.01,2e3),this.camera.position.set(0,3,6),this.camera.lookAt(0,0,0),this.renderer=new ot({antialias:!0,alpha:!0}),this.renderer.setSize(e,i),this.renderer.setPixelRatio(Math.min(window.devicePixelRatio,2)),t.appendChild(this.renderer.domElement),this.controls=new rt(this.camera,this.renderer.domElement),this.controls.enableDamping=!0,this.controls.dampingFactor=.08,this.controls.minDistance=1,this.controls.maxDistance=500,this.controls.enablePan=!0,this.controls.autoRotate=!1,this.controls.zoomSpeed=1.2,this.controls.rotateSpeed=.8,this.controls.addEventListener("start",()=>{this.autoRotate=!1}),this.scene.add(new W(2236996,.4)),this.buildBackground()}setSpeed(t){this.speedMultiplier=t}resetCamera(){this.autoRotate=!0,this.camera.position.copy(this.defaultCamPos),this.camera.lookAt(0,0,0),this.controls.target.set(0,0,0),this.controls.update()}toggleAutoRotate(){this.autoRotate=!this.autoRotate}getAutoRotate(){return this.autoRotate}buildBackground(){this.bgGroup=new tt;const t=4e3,e=new Float32Array(t*3),i=new Float32Array(t*3),s=new Float32Array(t),a=Rs(42),n=[new _(16777215),new _(11193599),new _(16774378),new _(16765601),new _(16758124),new _(13426175)];for(let y=0;y<t;y++){const b=a()*Math.PI*2,v=Math.acos(2*a()-1),E=300+a()*500;e[y*3]=E*Math.sin(v)*Math.cos(b),e[y*3+1]=E*Math.sin(v)*Math.sin(b),e[y*3+2]=E*Math.cos(v);const C=n[Math.floor(a()*n.length)],T=.4+a()*.6;i[y*3]=C.r*T,i[y*3+1]=C.g*T,i[y*3+2]=C.b*T,s[y]=.5+a()*2}const o=new P;o.setAttribute("position",new F(e,3)),o.setAttribute("color",new F(i,3)),o.setAttribute("size",new F(s,1));const r=new J({size:1.5,vertexColors:!0,transparent:!0,opacity:.9,sizeAttenuation:!0,depthWrite:!1});this.bgGroup.add(new X(o,r));const l=6e3,c=new Float32Array(l*3),d=new Float32Array(l*3);for(let y=0;y<l;y++){const b=a()*Math.PI*2,v=Math.pow(a(),.5)*600,E=(a()-.5)*(15+v*.02);c[y*3]=v*Math.cos(b),c[y*3+1]=E,c[y*3+2]=v*Math.sin(b);const C=1-Math.min(1,v/600),T=a();d[y*3]=.5+C*.4+T*.1,d[y*3+1]=.5+C*.3+T*.1,d[y*3+2]=.6+T*.15}const h=new P;h.setAttribute("position",new F(c,3)),h.setAttribute("color",new F(d,3));const u=new J({size:.8,vertexColors:!0,transparent:!0,opacity:.25,sizeAttenuation:!0,depthWrite:!1}),m=new X(h,u);m.rotation.x=Math.PI*.35,m.rotation.z=Math.PI*.15,m.position.set(0,100,-200),this.bgGroup.add(m);const g=new B(40,16,16),x=new N({color:15654348,transparent:!0,opacity:.04,side:Ct,depthWrite:!1}),f=new L(g,x);f.position.copy(m.position),this.bgGroup.add(f);const w=[3359914,11154261,2263210,8930474,4500070];for(let y=0;y<8;y++){const b=document.createElement("canvas");b.width=128,b.height=128;const v=b.getContext("2d"),E=v.createRadialGradient(64,64,4,64,64,64),C=new _(w[y%w.length]);E.addColorStop(0,`rgba(${Math.floor(C.r*255)},${Math.floor(C.g*255)},${Math.floor(C.b*255)},0.3)`),E.addColorStop(.4,`rgba(${Math.floor(C.r*255)},${Math.floor(C.g*255)},${Math.floor(C.b*255)},0.08)`),E.addColorStop(1,"rgba(0,0,0,0)"),v.fillStyle=E,v.fillRect(0,0,128,128);const T=new Y(b),R=new Z({map:T,transparent:!0,blending:et,depthWrite:!1}),k=new V(R),M=a()*Math.PI*2,S=(a()-.5)*Math.PI*.6,$=200+a()*400;k.position.set($*Math.cos(S)*Math.cos(M),$*Math.sin(S),$*Math.cos(S)*Math.sin(M)),k.scale.setScalar(60+a()*120),this.bgGroup.add(k)}this.scene.add(this.bgGroup)}update(t){this.clearSystem(),this.currentParams=t;const e=Ds(t.stellarTempK),i=Fs(t.eqTempK),s=Math.max(.8,Math.min(4,t.semiMajorAxisAU*2.5)),a=.25+t.stellarRadiusSolar*.2,n=new B(a,32,32),o=new N({color:e});this.starMesh=new L(n,o),this.scene.add(this.starMesh);const r=new re(e,2.5,30);r.position.set(0,0,0),this.scene.add(r);const l=new B(a*2.5,24,24),c=new N({color:e,transparent:!0,opacity:.05,side:Ct,depthWrite:!1});if(this.scene.add(new L(l,c)),t.hzMember){const b=s*.75,v=s*1.35,E=new Te(b,v,64),C=new N({color:3066993,transparent:!0,opacity:.07,side:xt,depthWrite:!1});this.hzInnerRing=new L(E,C),this.hzInnerRing.rotation.x=-Math.PI/2,this.hzInnerRing.position.y=-.01,this.scene.add(this.hzInnerRing);const T=(R,k,M)=>{const S=[];for(let K=0;K<=128;K++){const U=K/128*Math.PI*2;S.push(new A(R*Math.cos(U),0,R*Math.sin(U)))}const $=new P().setFromPoints(S),O=new j({color:k,transparent:!0,opacity:M});this.scene.add(new q($,O))};T(b,3066993,.25),T(v,3066993,.12)}this.orbitPoints=[];const d=256;for(let b=0;b<=d;b++){const v=b/d*Math.PI*2;this.orbitPoints.push(new A(s*Math.cos(v),0,s*Math.sin(v)))}const h=new P().setFromPoints(this.orbitPoints),u=new j({color:i,transparent:!0,opacity:.5});this.orbitLine=new q(h,u),this.scene.add(this.orbitLine);const m=b=>{const v=[];for(let T=0;T<=128;T++){const R=T/128*Math.PI*2;v.push(new A(b*Math.cos(R),0,b*Math.sin(R)))}const E=new P().setFromPoints(v),C=new j({color:1844019,transparent:!0,opacity:.3});this.scene.add(new q(E,C))};m(.5*2.5),m(1.5*2.5),this.addScaleLabel("0.5 AU",.5*2.5+.2,.3,0),this.addScaleLabel("1.0 AU",1*2.5+.2,.3,0),this.addScaleLabel("1.5 AU",1.5*2.5+.2,.3,0),t.hzMember&&this.addScaleLabel("HZ",s*1.05,.5,0,"#2ecc71");const g=Math.max(.06,Math.min(.2,t.radiusEarth*.1)),x=new B(g,24,24),f=new vt({color:i,emissive:i,emissiveIntensity:.2,roughness:.7,metalness:.1});if(this.planetMesh=new L(x,f),this.planetMesh.position.copy(this.orbitPoints[0]),this.scene.add(this.planetMesh),t.hzMember&&t.eqTempK>180&&t.eqTempK<350){const b=new B(g*1.2,24,24),v=new N({color:6737151,transparent:!0,opacity:.12,side:Ct,depthWrite:!1});this.planetMesh.add(new L(b,v))}this.addScaleLabel(t.label,this.orbitPoints[0].x,this.orbitPoints[0].y+g+.15,this.orbitPoints[0].z,"#00e5ff");const w=new Tt(12,12,1383203,856343);w.position.y=-.3,this.scene.add(w),this.orbitSpeed=.002+1/Math.max(t.periodDays,10)*.8,this.orbitAngle=0;const y=s*1.8+2;this.defaultCamPos.set(y*.6,y*.45,y*.7),this.camera.position.copy(this.defaultCamPos),this.controls.target.set(0,0,0),this.controls.update(),this.autoRotate=!0,this.animate()}addScaleLabel(t,e,i,s,a="#556677"){const n=document.createElement("canvas");n.width=128,n.height=32;const o=n.getContext("2d");o.font="14px monospace",o.fillStyle=a,o.textAlign="center",o.fillText(t,64,20);const r=new Y(n);r.minFilter=Se;const l=new Z({map:r,transparent:!0,depthWrite:!1,depthTest:!1}),c=new V(l);c.position.set(e,i,s),c.scale.set(1.2,.3,1),this.scene.add(c),this.labelSprites.push(c)}clearSystem(){cancelAnimationFrame(this.animId);const t=[];this.scene.traverse(i=>{i!==this.scene&&i!==this.bgGroup&&i.parent===this.scene&&!(i instanceof W)&&t.push(i)});for(const i of t)this.scene.remove(i),i.geometry&&i.geometry.dispose();let e=!1;this.scene.traverse(i=>{i instanceof W&&(e=!0)}),e||this.scene.add(new W(2236996,.4)),this.starMesh=null,this.planetMesh=null,this.orbitLine=null,this.hzInnerRing=null,this.labelSprites=[]}resize(){const t=this.container.clientWidth||400,e=this.container.clientHeight||300;this.camera.aspect=t/e,this.camera.updateProjectionMatrix(),this.renderer.setSize(t,e)}destroy(){cancelAnimationFrame(this.animId),this.controls.dispose(),this.clearSystem(),this.bgGroup&&(this.scene.remove(this.bgGroup),this.bgGroup.traverse(t=>{t.geometry&&t.geometry.dispose()}),this.bgGroup=null),this.renderer.dispose(),this.renderer.domElement.parentElement&&this.renderer.domElement.remove()}}class Hs{constructor(){this.container=null,this.data=null,this.pipelineEl=null,this.candidatesEl=null,this.discoveryEl=null,this.running=!1,this.currentStage=-1,this.planet3d=null,this.planet3dContainer=null,this.planet3dInfoEl=null,this.controlsEl=null,this.vizPanel=null,this.selectedCardEl=null}mount(t){this.container=t;const e=document.createElement("div");e.style.cssText="display:flex;flex-direction:column;width:100%;height:100%;overflow:auto",t.appendChild(e);const i=document.createElement("div");i.style.cssText="padding:16px 20px;border-bottom:1px solid var(--border);flex-shrink:0",i.innerHTML=`
<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px">
<div style="font-size:16px;font-weight:700;color:var(--text-primary)">New Planet Discovery</div>
<span class="score-badge score-high" style="font-size:9px;padding:2px 8px">LIVE PIPELINE</span>
</div>
<div style="font-size:12px;color:var(--text-secondary);line-height:1.7;max-width:900px">
The RVF pipeline processes <strong>real unconfirmed candidates</strong> from the Kepler Objects of Interest (KOI) catalog.
These are stars with detected transit signals that have not yet been confirmed as planets.
The pipeline derives physical properties from raw photometry and ranks candidates by Earth Similarity Index.
<strong>Click any candidate</strong> to view its 3D orbital system.
</div>
`,e.appendChild(i),this.pipelineEl=document.createElement("div"),this.pipelineEl.style.cssText="padding:16px 20px;border-bottom:1px solid var(--border)",e.appendChild(this.pipelineEl);const s=document.createElement("div");s.style.cssText="padding:12px 20px;flex-shrink:0";const a=document.createElement("button");a.textContent="Run Discovery Pipeline",a.style.cssText="padding:10px 24px;border:none;border-radius:6px;background:var(--accent);color:#0B0F14;font-size:13px;font-weight:700;cursor:pointer;letter-spacing:0.3px",a.addEventListener("click",()=>this.runPipeline()),s.appendChild(a),e.appendChild(s),this.vizPanel=document.createElement("div"),this.vizPanel.style.cssText="padding:0 20px 16px;display:none",e.appendChild(this.vizPanel);const n=document.createElement("div");n.style.cssText="display:grid;grid-template-columns:1fr 260px;gap:0;background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;overflow:hidden",this.vizPanel.appendChild(n),this.planet3dContainer=document.createElement("div"),this.planet3dContainer.style.cssText="position:relative;min-height:420px;background:#020408",n.appendChild(this.planet3dContainer),this.controlsEl=document.createElement("div"),this.controlsEl.style.cssText="position:absolute;bottom:10px;left:10px;display:flex;gap:6px;align-items:center;z-index:20;background:rgba(2,4,8,0.8);border:1px solid rgba(30,38,48,0.6);border-radius:6px;padding:6px 10px",this.planet3dContainer.appendChild(this.controlsEl);const o=document.createElement("div");o.style.cssText="position:absolute;top:8px;right:8px;font-size:9px;color:rgba(230,237,243,0.4);z-index:20;pointer-events:none;text-align:right;line-height:1.6",o.innerHTML="Drag to rotate<br>Scroll to zoom<br>Right-drag to pan",this.planet3dContainer.appendChild(o),this.planet3dInfoEl=document.createElement("div"),this.planet3dInfoEl.style.cssText="padding:16px;overflow-y:auto;max-height:420px;font-size:11px;color:var(--text-secondary);line-height:1.7;border-left:1px solid var(--border)",n.appendChild(this.planet3dInfoEl),this.candidatesEl=document.createElement("div"),this.candidatesEl.style.cssText="padding:0 20px 16px",e.appendChild(this.candidatesEl),this.discoveryEl=document.createElement("div"),this.discoveryEl.style.cssText="padding:0 20px 24px;display:none",e.appendChild(this.discoveryEl),this.loadData()}async loadData(){try{const t=await fetch("/api/discover");this.data=await t.json()}catch(t){console.error("Discovery API error:",t);return}this.renderPipelineStages()}renderPipelineStages(){if(!this.pipelineEl||!this.data)return;const t=this.data.pipeline_stages;this.pipelineEl.innerHTML=`
<div style="font-size:10px;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.5px;margin-bottom:8px">Pipeline Stages</div>
<div style="display:flex;gap:4px;align-items:center;flex-wrap:wrap">
${t.map((e,i)=>`
<div id="stage-${i}" style="padding:6px 14px;border-radius:4px;background:var(--bg-surface);border:1px solid var(--border);transition:all 0.3s">
<div style="font-size:10px;font-weight:700;color:var(--text-muted)">${e.stage}</div>
<div style="font-size:9px;color:var(--text-muted)">${e.name}</div>
</div>
${i<t.length-1?'<span style="color:var(--text-muted)">&#8594;</span>':""}
`).join("")}
</div>
`}async runPipeline(){if(this.running||!this.data)return;this.running=!0,this.currentStage=-1,this.candidatesEl&&(this.candidatesEl.innerHTML=""),this.discoveryEl&&(this.discoveryEl.style.display="none"),this.vizPanel&&(this.vizPanel.style.display="none"),this.selectedCardEl=null;for(let e=0;e<this.data.pipeline_stages.length;e++)this.currentStage=e,this.highlightStage(e),await this.sleep(600);const t=[...this.data.candidates].sort((e,i)=>e.discovery_rank-i.discovery_rank);for(const e of t)await this.sleep(400),this.addCandidateCard(e);t.length>0&&this.show3D(t[0]),await this.sleep(800),this.showDiscovery(),this.running=!1}highlightStage(t){var e;for(let i=0;i<(((e=this.data)==null?void 0:e.pipeline_stages.length)??0);i++){const s=document.getElementById(`stage-${i}`);s&&(i<t?(s.style.background="rgba(46,204,113,0.15)",s.style.borderColor="rgba(46,204,113,0.4)",s.querySelector("div").style.color="var(--success)"):i===t?(s.style.background="rgba(0,229,255,0.15)",s.style.borderColor="var(--accent)",s.querySelector("div").style.color="var(--accent)"):(s.style.background="var(--bg-surface)",s.style.borderColor="var(--border)",s.querySelector("div").style.color="var(--text-muted)"))}}addCandidateCard(t){if(!this.candidatesEl)return;const e=t.pipeline_derived.esi_score>=.9?"score-high":t.pipeline_derived.esi_score>=.8?"score-medium":"score-low",i=t.discovery_rank===1,s=document.createElement("div");s.style.cssText=`
padding:12px 16px;margin-bottom:8px;border-radius:6px;cursor:pointer;
background:${i?"rgba(0,229,255,0.08)":"var(--bg-surface)"};
border:1px solid ${i?"var(--accent)":"var(--border)"};
animation: fadeIn 0.3s ease-out;
transition: border-color 0.2s, background 0.2s;
`,s.innerHTML=`
<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px">
<span style="font-size:13px;font-weight:600;color:var(--text-primary)">${t.id}</span>
<span class="score-badge ${e}" style="font-size:10px">ESI ${t.pipeline_derived.esi_score.toFixed(2)}</span>
<span style="font-size:9px;color:var(--text-muted)">${t.catalog}</span>
${i?'<span class="score-badge score-high" style="font-size:8px;background:rgba(0,229,255,0.2);color:var(--accent);border-color:var(--accent)">TOP DISCOVERY</span>':""}
<span style="font-size:9px;color:var(--text-muted);margin-left:4px" title="Click to view 3D system">&#127760; View 3D</span>
<span style="margin-left:auto;font-size:10px;color:var(--text-muted)">
R=${t.pipeline_derived.radius_earth.toFixed(2)} R&#8853; | T=${t.pipeline_derived.eq_temp_k}K |
HZ: ${t.pipeline_derived.hz_member?'<span style="color:var(--success)">YES</span>':'<span style="color:var(--critical)">NO</span>'}
</span>
</div>
<div style="font-size:11px;color:var(--text-secondary);line-height:1.5">${t.analysis}</div>
`,s.addEventListener("click",()=>{this.show3D(t),this.selectedCardEl&&(this.selectedCardEl.style.borderColor=this.selectedCardEl.dataset.isTop==="1"?"var(--accent)":"var(--border)",this.selectedCardEl.style.boxShadow="none"),s.style.borderColor="var(--accent)",s.style.boxShadow="0 0 8px rgba(0,229,255,0.2)",this.selectedCardEl=s}),s.dataset.isTop=i?"1":"0",this.candidatesEl.appendChild(s)}show3D(t){if(!this.vizPanel||!this.planet3dContainer||!this.planet3dInfoEl)return;this.vizPanel.style.display="",this.planet3d&&(this.planet3d.destroy(),this.planet3d=null),this.planet3d=new Is(this.planet3dContainer);const e={label:t.id,radiusEarth:t.pipeline_derived.radius_earth,semiMajorAxisAU:t.pipeline_derived.semi_major_axis_au,eqTempK:t.pipeline_derived.eq_temp_k,stellarTempK:t.raw_observations.stellar_temp_k??5500,stellarRadiusSolar:t.raw_observations.stellar_radius_solar??1,periodDays:t.raw_observations.period_days??365,hzMember:t.pipeline_derived.hz_member,esiScore:t.pipeline_derived.esi_score,transitDepth:t.raw_observations.transit_depth??.001};this.planet3d.update(e),this.buildControls();const i=this.getSpectralType(e.stellarTempK),s=this.getTempLabel(e.eqTempK);this.planet3dInfoEl.innerHTML=`
<div style="font-size:14px;font-weight:700;color:var(--text-primary);margin-bottom:10px">${t.id}</div>
<div style="margin-bottom:12px">
<span class="score-badge ${t.pipeline_derived.esi_score>=.9?"score-high":t.pipeline_derived.esi_score>=.8?"score-medium":"score-low"}"
style="font-size:11px;padding:3px 8px">ESI ${t.pipeline_derived.esi_score.toFixed(2)}</span>
<span style="margin-left:6px;font-size:10px;color:${t.pipeline_derived.hz_member?"var(--success)":"var(--critical)"}">
${t.pipeline_derived.hz_member?"Habitable Zone":"Outside HZ"}
</span>
</div>
<div style="font-size:10px;font-weight:700;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.5px;margin-bottom:6px">Planet</div>
<div style="padding-left:8px;border-left:2px solid var(--accent);margin-bottom:12px">
<div>Radius: <span style="color:var(--accent)">${e.radiusEarth.toFixed(2)} R&#8853;</span></div>
<div>Temperature: <span style="color:var(--accent)">${e.eqTempK} K</span> <span style="font-size:9px;color:var(--text-muted)">(${s})</span></div>
<div>Orbit: <span style="color:var(--accent)">${e.semiMajorAxisAU.toFixed(3)} AU</span></div>
<div>Period: <span style="color:var(--accent)">${e.periodDays.toFixed(1)} days</span></div>
<div>Transit depth: <span style="color:var(--accent)">${(e.transitDepth*1e6).toFixed(0)} ppm</span></div>
</div>
<div style="font-size:10px;font-weight:700;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.5px;margin-bottom:6px">Host Star</div>
<div style="padding-left:8px;border-left:2px solid #ffd2a1;margin-bottom:12px">
<div>Type: <span style="color:#ffd2a1">${i}</span></div>
<div>T<sub>eff</sub>: <span style="color:#ffd2a1">${e.stellarTempK} K</span></div>
<div>Radius: <span style="color:#ffd2a1">${e.stellarRadiusSolar.toFixed(3)} R&#9737;</span></div>
</div>
<div style="font-size:10px;font-weight:700;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.5px;margin-bottom:6px">ESI Breakdown</div>
<div style="padding-left:8px;border-left:2px solid var(--success);margin-bottom:12px">
<div>Radius similarity: <span style="color:var(--success)">${(t.pipeline_derived.radius_similarity*100).toFixed(0)}%</span></div>
<div>Temp similarity: <span style="color:var(--success)">${(t.pipeline_derived.temperature_similarity*100).toFixed(0)}%</span></div>
</div>
<div style="font-size:10px;font-weight:700;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.5px;margin-bottom:6px">Comparison to Earth</div>
<div style="font-size:10px;line-height:1.8">
${this.earthComparison(e)}
</div>
`,this.vizPanel.scrollIntoView({behavior:"smooth",block:"nearest"})}buildControls(){if(!this.controlsEl||!this.planet3d)return;this.controlsEl.innerHTML="";const t="border:1px solid rgba(30,38,48,0.8);border-radius:4px;background:rgba(11,15,20,0.9);color:var(--text-secondary);font-size:10px;padding:4px 8px;cursor:pointer;font-family:var(--font-mono);transition:color 0.15s,border-color 0.15s",e=t.replace("var(--text-secondary)","var(--accent)").replace("rgba(30,38,48,0.8)","var(--accent)"),i=document.createElement("span");i.style.cssText="font-size:9px;color:var(--text-muted);font-family:var(--font-mono)",i.textContent="Speed:",this.controlsEl.appendChild(i);const s=document.createElement("input");s.type="range",s.min="0.1",s.max="5",s.step="0.1",s.value="1",s.style.cssText="width:70px;height:4px;accent-color:var(--accent);cursor:pointer",s.addEventListener("input",()=>{var c;const l=parseFloat(s.value);(c=this.planet3d)==null||c.setSpeed(l),a.textContent=`${l.toFixed(1)}x`}),this.controlsEl.appendChild(s);const a=document.createElement("span");a.style.cssText="font-size:9px;color:var(--accent);min-width:24px;font-family:var(--font-mono)",a.textContent="1.0x",this.controlsEl.appendChild(a);const n=document.createElement("span");n.style.cssText="width:1px;height:14px;background:rgba(30,38,48,0.6)",this.controlsEl.appendChild(n);const o=document.createElement("button");o.style.cssText=e,o.textContent="Auto",o.title="Toggle auto-rotate camera",o.addEventListener("click",()=>{var c,d;(c=this.planet3d)==null||c.toggleAutoRotate();const l=((d=this.planet3d)==null?void 0:d.getAutoRotate())??!1;o.style.cssText=l?e:t}),this.controlsEl.appendChild(o);const r=document.createElement("button");r.style.cssText=t,r.textContent="Reset",r.title="Reset camera to default position",r.addEventListener("click",()=>{var l,c;(l=this.planet3d)==null||l.resetCamera(),o.style.cssText=e,s.value="1",a.textContent="1.0x",(c=this.planet3d)==null||c.setSpeed(1)}),this.controlsEl.appendChild(r)}getSpectralType(t){return t>7500?`A-type (${t} K)`:t>6e3?`F-type (${t} K)`:t>5200?`G-type (${t} K) Sun-like`:t>3700?`K-type (${t} K)`:`M-type (${t} K)`}getTempLabel(t){return t<180?"frozen":t<240?"cold":t<280?"temperate":t<330?"warm":"hot"}earthComparison(t){const e=t.radiusEarth,i=t.eqTempK/255,s=t.semiMajorAxisAU,a=t.periodDays/365.25,n=(o,r)=>o>.95&&o<1.05?`<span style="color:var(--success)">~Earth (${o.toFixed(2)}${r})</span>`:o>1?`<span style="color:var(--accent)">${o.toFixed(2)}x Earth</span>`:`<span style="color:var(--accent)">${o.toFixed(2)}x Earth</span>`;return`
<div>Radius: ${n(e,"x")}</div>
<div>Temperature: ${n(i,"x")}</div>
<div>Orbit: ${n(s," AU")}</div>
<div>Year: ${n(a,"x")}</div>
`}showDiscovery(){if(!this.discoveryEl||!this.data)return;const t=this.data.discovery;this.discoveryEl.style.display="",this.discoveryEl.innerHTML=`
<div style="padding:20px;background:rgba(0,229,255,0.06);border:2px solid var(--accent);border-radius:10px">
<div style="display:flex;align-items:center;gap:10px;margin-bottom:12px">
<div style="font-size:18px;font-weight:800;color:var(--accent)">DISCOVERY: ${t.top_candidate}</div>
<span class="score-badge score-high" style="font-size:12px;padding:3px 10px">ESI ${t.esi_score}</span>
<span style="font-size:10px;color:var(--success);font-weight:600">MOST EARTH-LIKE CANDIDATE IN KEPLER CATALOG</span>
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:16px">
<div>
<div style="font-size:10px;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.4px;margin-bottom:6px">Comparison to Known Worlds</div>
${Object.entries(t.comparison).map(([e,i])=>`
<div style="font-size:11px;color:var(--text-secondary);margin-bottom:4px;padding-left:8px;border-left:2px solid var(--accent)">
<strong>${e.replace("vs_","vs ")}</strong>: ${i}
</div>
`).join("")}
</div>
<div>
<div style="font-size:10px;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.4px;margin-bottom:6px">Why Not Yet Confirmed</div>
<div style="font-size:11px;color:var(--text-secondary);line-height:1.6">${t.why_not_confirmed}</div>
</div>
</div>
<div style="margin-bottom:16px">
<div style="font-size:10px;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.4px;margin-bottom:6px">Pipeline Witness Chain</div>
<div style="display:flex;gap:6px;flex-wrap:wrap">
${t.pipeline_witness_chain.map(e=>`
<div style="padding:6px 10px;background:var(--bg-panel);border:1px solid var(--border);border-radius:4px;font-size:10px">
<div style="color:var(--accent);font-weight:600">${e.witness}</div>
<div style="color:var(--text-secondary)">${e.measurement}</div>
<div style="color:${e.confidence>.9?"var(--success)":"var(--warning)"}">${(e.confidence*100).toFixed(0)}% conf.</div>
</div>
`).join("")}
</div>
</div>
<div>
<div style="font-size:10px;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.4px;margin-bottom:6px">Steps to Confirmation</div>
${t.what_confirmation_requires.map(e=>`
<div style="font-size:11px;color:var(--text-secondary);margin-bottom:3px;padding-left:8px">${e}</div>
`).join("")}
</div>
</div>
`}sleep(t){return new Promise(e=>setTimeout(e,t))}unmount(){this.running=!1,this.planet3d&&(this.planet3d.destroy(),this.planet3d=null),this.container=null,this.pipelineEl=null,this.candidatesEl=null,this.discoveryEl=null,this.vizPanel=null,this.planet3dContainer=null,this.planet3dInfoEl=null,this.controlsEl=null,this.selectedCardEl=null,this.data=null}}const Bs={O:10203391,B:11190271,A:13293567,F:16316415,G:16774378,K:16765601,M:16758124,L:16746547};function Ns(p){const t=p.charAt(0).toUpperCase();return Bs[t]??16765601}function Os(p){const t=Math.max(0,Math.min(1,(p-100)/400));return new _().setHSL(.02+t*.06,.9,.3+t*.2)}function Ws(p){let t=p;return()=>(t=(t*16807+0)%2147483647,(t-1)/2147483646)}class Gs{constructor(t){this.container=t,this.starMesh=null,this.shellMesh=null,this.glowMesh=null,this.panelInstances=null,this.animId=0,this.time=0,this.speedMultiplier=1,this.autoRotate=!0,this.defaultCamPos=new A(0,1.5,4),this.bgGroup=null,this.animate=()=>{if(this.animId=requestAnimationFrame(this.animate),this.time+=.005*this.speedMultiplier,this.shellMesh&&(this.shellMesh.rotation.y=this.time*.3),this.panelInstances&&(this.panelInstances.rotation.y=this.time*.3),this.autoRotate&&(this.camera.position.x=4*Math.sin(this.time*.15),this.camera.position.z=4*Math.cos(this.time*.15),this.camera.position.y=1.2+.3*Math.sin(this.time*.1),this.controls.target.set(0,0,0)),this.starMesh){const s=1+.03*Math.sin(this.time*3);this.starMesh.scale.setScalar(s)}if(this.glowMesh){const s=this.glowMesh.material;s.opacity=.04+.02*Math.sin(this.time*2)}this.controls.update(),this.renderer.render(this.scene,this.camera)},this.scene=new nt,this.scene.background=new _(132104);const e=t.clientWidth||400,i=t.clientHeight||300;this.camera=new at(50,e/i,.01,2e3),this.camera.position.set(0,1.5,4),this.camera.lookAt(0,0,0),this.renderer=new ot({antialias:!0,alpha:!0}),this.renderer.setSize(e,i),this.renderer.setPixelRatio(Math.min(window.devicePixelRatio,2)),t.appendChild(this.renderer.domElement),this.controls=new rt(this.camera,this.renderer.domElement),this.controls.enableDamping=!0,this.controls.dampingFactor=.08,this.controls.minDistance=1,this.controls.maxDistance=400,this.controls.enablePan=!0,this.controls.zoomSpeed=1.2,this.controls.rotateSpeed=.8,this.controls.addEventListener("start",()=>{this.autoRotate=!1}),this.scene.add(new W(2236996,.3)),this.buildBackground()}setSpeed(t){this.speedMultiplier=t}resetCamera(){this.autoRotate=!0,this.camera.position.copy(this.defaultCamPos),this.camera.lookAt(0,0,0),this.controls.target.set(0,0,0),this.controls.update()}toggleAutoRotate(){this.autoRotate=!this.autoRotate}getAutoRotate(){return this.autoRotate}buildBackground(){this.bgGroup=new tt;const t=Ws(77),e=4e3,i=new Float32Array(e*3),s=new Float32Array(e*3),a=[new _(16777215),new _(11193599),new _(16774378),new _(16765601),new _(16758124),new _(13426175)];for(let u=0;u<e;u++){const m=t()*Math.PI*2,g=Math.acos(2*t()-1),x=300+t()*500;i[u*3]=x*Math.sin(g)*Math.cos(m),i[u*3+1]=x*Math.sin(g)*Math.sin(m),i[u*3+2]=x*Math.cos(g);const f=a[Math.floor(t()*a.length)],w=.4+t()*.6;s[u*3]=f.r*w,s[u*3+1]=f.g*w,s[u*3+2]=f.b*w}const n=new P;n.setAttribute("position",new F(i,3)),n.setAttribute("color",new F(s,3)),this.bgGroup.add(new X(n,new J({size:1.5,vertexColors:!0,transparent:!0,opacity:.9,sizeAttenuation:!0,depthWrite:!1})));const o=5e3,r=new Float32Array(o*3),l=new Float32Array(o*3);for(let u=0;u<o;u++){const m=t()*Math.PI*2,g=Math.pow(t(),.5)*500,x=(t()-.5)*(12+g*.02);r[u*3]=g*Math.cos(m),r[u*3+1]=x,r[u*3+2]=g*Math.sin(m);const f=1-Math.min(1,g/500);l[u*3]=.5+f*.35,l[u*3+1]=.5+f*.25,l[u*3+2]=.6+t()*.1}const c=new P;c.setAttribute("position",new F(r,3)),c.setAttribute("color",new F(l,3));const d=new X(c,new J({size:.8,vertexColors:!0,transparent:!0,opacity:.2,sizeAttenuation:!0,depthWrite:!1}));d.rotation.x=Math.PI*.35,d.rotation.z=Math.PI*.15,d.position.set(0,80,-180),this.bgGroup.add(d);const h=[3359914,11154261,2263210,8930474];for(let u=0;u<6;u++){const m=document.createElement("canvas");m.width=128,m.height=128;const g=m.getContext("2d"),x=g.createRadialGradient(64,64,4,64,64,64),f=new _(h[u%h.length]);x.addColorStop(0,`rgba(${Math.floor(f.r*255)},${Math.floor(f.g*255)},${Math.floor(f.b*255)},0.25)`),x.addColorStop(.4,`rgba(${Math.floor(f.r*255)},${Math.floor(f.g*255)},${Math.floor(f.b*255)},0.06)`),x.addColorStop(1,"rgba(0,0,0,0)"),g.fillStyle=x,g.fillRect(0,0,128,128);const w=new Y(m),y=new Z({map:w,transparent:!0,blending:et,depthWrite:!1}),b=new V(y),v=t()*Math.PI*2,E=(t()-.5)*Math.PI*.5,C=200+t()*350;b.position.set(C*Math.cos(E)*Math.cos(v),C*Math.sin(E),C*Math.cos(E)*Math.sin(v)),b.scale.setScalar(50+t()*100),this.bgGroup.add(b)}this.scene.add(this.bgGroup)}update(t){this.clearSystem();const e=Ns(t.spectralType),i=new B(.5,32,32),s=new N({color:e});this.starMesh=new L(i,s),this.scene.add(this.starMesh);const a=new re(e,2,20);a.position.set(0,0,0),this.scene.add(a);const n=1.5,o=new B(n,64,64),r=Os(t.warmTempK),l=o.attributes.position,c=new Float32Array(l.count*4),d=t.coverageFraction;for(let y=0;y<l.count;y++){const b=l.getX(y),v=l.getY(y),E=l.getZ(y),C=Math.atan2(Math.sqrt(b*b+E*E),v),T=Math.atan2(E,b),k=.5+.2*Math.sin(C*5+T*3)+.15*Math.sin(C*8-T*5)+.15*Math.cos(T*7+C*2)<d,M=k?.6+d*.3:.02;c[y*4]=k?r.r:.05,c[y*4+1]=k?r.g:.05,c[y*4+2]=k?r.b:.05,c[y*4+3]=M}o.setAttribute("color",new F(c,4));const h=new N({vertexColors:!0,transparent:!0,opacity:.7,side:xt,depthWrite:!1});this.shellMesh=new L(o,h),this.scene.add(this.shellMesh);const u=new B(n+.01,24,24),m=new N({color:r,transparent:!0,opacity:.08,wireframe:!0});this.scene.add(new L(u,m));const g=n+.3+t.w4Excess*.1,x=new B(g,32,32),f=new N({color:r,transparent:!0,opacity:.04+d*.06,side:Ct,depthWrite:!1});this.glowMesh=new L(x,f),this.scene.add(this.glowMesh);const w=Math.floor(d*400);if(w>0){const y=new Rt(.06,.06),b=new N({color:r,transparent:!0,opacity:.9,side:xt});this.panelInstances=new ie(y,b,w);const v=new ne;for(let E=0;E<w;E++){const C=E/w,T=Math.acos(1-2*C),R=Math.PI*(1+Math.sqrt(5))*E,k=n+.02+Math.random()*.05;v.position.set(k*Math.sin(T)*Math.cos(R),k*Math.cos(T),k*Math.sin(T)*Math.sin(R)),v.lookAt(0,0,0),v.updateMatrix(),this.panelInstances.setMatrixAt(E,v.matrix)}this.panelInstances.instanceMatrix.needsUpdate=!0,this.scene.add(this.panelInstances)}this.defaultCamPos.set(2.5,1.5,3.5),this.camera.position.copy(this.defaultCamPos),this.controls.target.set(0,0,0),this.controls.update(),this.autoRotate=!0,this.animate()}clearSystem(){cancelAnimationFrame(this.animId);const t=[];this.scene.traverse(i=>{i!==this.scene&&i!==this.bgGroup&&i.parent===this.scene&&!(i instanceof W)&&t.push(i)});for(const i of t)this.scene.remove(i),i.geometry&&i.geometry.dispose();let e=!1;this.scene.traverse(i=>{i instanceof W&&(e=!0)}),e||this.scene.add(new W(2236996,.3)),this.starMesh=null,this.shellMesh=null,this.glowMesh=null,this.panelInstances=null}resize(){const t=this.container.clientWidth||400,e=this.container.clientHeight||300;this.camera.aspect=t/e,this.camera.updateProjectionMatrix(),this.renderer.setSize(t,e)}destroy(){cancelAnimationFrame(this.animId),this.controls.dispose(),this.clearSystem(),this.bgGroup&&(this.scene.remove(this.bgGroup),this.bgGroup.traverse(t=>{t.geometry&&t.geometry.dispose()}),this.bgGroup=null),this.renderer.dispose(),this.renderer.domElement.parentElement&&this.renderer.domElement.remove()}}class js{constructor(){this.container=null,this.data=null,this.blindData=null,this.candidatesEl=null,this.resultEl=null,this.chartArea=null,this.blindArea=null,this.sphere3dContainer=null,this.sphere3dInfoEl=null,this.sphere3d=null,this.running=!1,this.selectedCandidate=null,this.mode="search",this.blindRevealed=!1}mount(t){this.container=t;const e=document.createElement("div");e.style.cssText="display:flex;flex-direction:column;width:100%;height:100%;overflow:auto",t.appendChild(e);const i=document.createElement("div");i.style.cssText="padding:16px 20px;border-bottom:1px solid var(--border);flex-shrink:0",i.innerHTML=`
<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px">
<div style="font-size:16px;font-weight:700;color:var(--text-primary)">Dyson Sphere Detection</div>
<span class="score-badge score-medium" style="font-size:9px;padding:2px 8px">SETI / TECHNOSIGNATURES</span>
<span class="score-badge score-high" style="font-size:9px;padding:2px 8px">PROJECT HEPHAISTOS</span>
</div>
<div style="font-size:12px;color:var(--text-secondary);line-height:1.7;max-width:900px">
Searching for <strong>megastructure technosignatures</strong> in astronomical survey data.
A Dyson sphere (or partial swarm) would absorb starlight and re-radiate it as <strong>infrared waste heat</strong>,
creating anomalous excess in WISE W3 (12&mu;m) and W4 (22&mu;m) bands.
Based on real data from <strong>Gaia DR3 + 2MASS + WISE</strong> per
<em>Suazo et al. 2024 (MNRAS 531, 695)</em>.
<strong style="color:#FFB020">Update:</strong> Ren, Garrett &amp; Siemion (2025, MNRAS Letters 538, L56)
confirmed Candidate G is a <strong>background AGN</strong> and Hot DOGs may explain all 7 candidates.
</div>
<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-top:8px;font-size:10px">
<div style="background:rgba(153,68,255,0.06);border:1px solid rgba(153,68,255,0.15);border-radius:4px;padding:6px 8px">
<div style="color:#9944ff;font-weight:600;margin-bottom:2px">Dyson Sphere Concept</div>
<div style="color:var(--text-secondary);line-height:1.4">Proposed by Freeman Dyson (1960), a Type II civilization could build a swarm of solar collectors around its star, capturing most of its luminosity. Even a partial swarm (&lt;2%) would produce detectable <strong>mid-infrared waste heat</strong>.</div>
</div>
<div style="background:rgba(0,229,255,0.06);border:1px solid rgba(0,229,255,0.15);border-radius:4px;padding:6px 8px">
<div style="color:var(--accent);font-weight:600;margin-bottom:2px">Detection Method</div>
<div style="color:var(--text-secondary);line-height:1.4">Compare observed WISE <strong>W3 (12&mu;m)</strong> and <strong>W4 (22&mu;m)</strong> flux against the expected stellar photosphere from optical/near-IR. Excess &gt;3&sigma; flags a candidate. M-dwarfs are ideal &mdash; they rarely have debris disks.</div>
</div>
<div style="background:rgba(255,77,77,0.06);border:1px solid rgba(255,77,77,0.15);border-radius:4px;padding:6px 8px">
<div style="color:#FF4D4D;font-weight:600;margin-bottom:2px">2025 Rebuttal</div>
<div style="color:var(--text-secondary);line-height:1.4"><strong>Candidate G debunked</strong>: Ren et al. 2025 used e-MERLIN + EVN to reveal a background AGN (T<sub>b</sub> &gt; 10<sup>8</sup> K). Hot Dust-Obscured Galaxies (~9&times;10<sup>-6</sup>/arcsec<sup>2</sup>) may explain <strong>all 7 candidates</strong>. JWST MIRI spectroscopy remains the definitive test. <strong>No confirmed Dyson sphere exists.</strong></div>
</div>
</div>
`,e.appendChild(i);const s=document.createElement("div");s.style.cssText="display:flex;gap:4px;padding:8px 20px;border-bottom:1px solid var(--border);flex-shrink:0";const a=this.makeTab("Search Pipeline","search"),n=this.makeTab("Blind Test","blind");s.appendChild(a),s.appendChild(n),e.appendChild(s);const o=document.createElement("div");o.id="dyson-signatures",o.style.cssText="padding:12px 20px;border-bottom:1px solid var(--border)",e.appendChild(o);const r=document.createElement("div");r.id="dyson-pipeline",r.style.cssText="padding:12px 20px;border-bottom:1px solid var(--border)",e.appendChild(r);const l=document.createElement("div");l.style.cssText="padding:12px 20px;flex-shrink:0;display:flex;gap:8px;align-items:center";const c=document.createElement("button");c.textContent="Run Dyson Sphere Search",c.style.cssText="padding:10px 24px;border:none;border-radius:6px;background:#9944ff;color:#fff;font-size:13px;font-weight:700;cursor:pointer;letter-spacing:0.3px",c.addEventListener("click",()=>this.runSearch()),l.appendChild(c),e.appendChild(l);const d=document.createElement("div");d.style.cssText="padding:0 20px 8px;display:none",d.id="dyson-3d-panel",d.innerHTML=`
<div style="display:grid;grid-template-columns:1fr 300px;gap:0">
<div style="position:relative">
<div style="font-size:10px;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.4px;margin-bottom:6px;display:flex;align-items:center;gap:8px">
<span>3D Dyson Sphere Model</span>
<span style="font-size:9px;padding:1px 6px;border-radius:3px;background:rgba(153,68,255,0.1);color:#9944ff;font-weight:600">THREE.JS</span>
<span style="font-size:9px;padding:1px 6px;border-radius:3px;background:rgba(0,229,255,0.1);color:var(--accent);font-weight:600">REAL DATA</span>
</div>
<div id="dyson-3d-viewport" style="position:relative;width:100%;height:380px;border-radius:6px;overflow:hidden;border:1px solid var(--border);background:#020408">
<div id="dyson-3d-controls" style="position:absolute;bottom:10px;left:10px;display:flex;gap:6px;align-items:center;z-index:20;background:rgba(2,4,8,0.8);border:1px solid rgba(30,38,48,0.6);border-radius:6px;padding:6px 10px"></div>
<div style="position:absolute;top:8px;right:8px;font-size:9px;color:rgba(230,237,243,0.4);z-index:20;pointer-events:none;text-align:right;line-height:1.6">Drag to rotate<br>Scroll to zoom<br>Right-drag to pan</div>
</div>
</div>
<div id="dyson-3d-info" style="display:flex;flex-direction:column;gap:8px;border-left:1px solid var(--border);padding-left:12px">
<div style="font-size:10px;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.4px;margin-bottom:2px">Candidate Parameters</div>
<div style="font-size:11px;color:var(--text-secondary);text-align:center;padding:40px 12px">
Run the search pipeline to visualize candidates.
<br>Click any candidate card to render its Dyson sphere model.
</div>
</div>
</div>
`,e.appendChild(d),this.chartArea=document.createElement("div"),this.chartArea.style.cssText="padding:0 20px 8px;display:none",e.appendChild(this.chartArea),this.candidatesEl=document.createElement("div"),this.candidatesEl.style.cssText="padding:0 20px",e.appendChild(this.candidatesEl),this.blindArea=document.createElement("div"),this.blindArea.style.cssText="padding:0 20px;display:none",e.appendChild(this.blindArea),this.resultEl=document.createElement("div"),this.resultEl.style.cssText="padding:0 20px 24px;display:none",e.appendChild(this.resultEl),this.loadData()}makeTab(t,e){const i=document.createElement("button");return i.textContent=t,i.style.cssText=`padding:6px 16px;border:1px solid ${e===this.mode?"#9944ff":"var(--border)"};border-radius:4px;background:${e===this.mode?"rgba(153,68,255,0.15)":"transparent"};color:${e===this.mode?"#9944ff":"var(--text-secondary)"};font-size:11px;font-weight:600;cursor:pointer`,i.addEventListener("click",()=>this.switchMode(e)),i}switchMode(t){var s;this.mode=t;const e=(s=this.container)==null?void 0:s.querySelector("div:nth-child(3)");e&&(e.innerHTML="",e.appendChild(this.makeTab("Search Pipeline","search")),e.appendChild(this.makeTab("Blind Test","blind")));const i=document.getElementById("dyson-3d-panel");if(t==="search"){this.candidatesEl&&(this.candidatesEl.style.display=""),this.chartArea&&(this.chartArea.style.display=this.selectedCandidate?"":"none"),this.blindArea&&(this.blindArea.style.display="none"),i&&(i.style.display=this.selectedCandidate?"":"none");const a=document.getElementById("dyson-signatures"),n=document.getElementById("dyson-pipeline");a&&(a.style.display=""),n&&(n.style.display="")}else{this.candidatesEl&&(this.candidatesEl.style.display="none"),this.chartArea&&(this.chartArea.style.display="none"),this.blindArea&&(this.blindArea.style.display=""),this.resultEl&&(this.resultEl.style.display="none"),i&&(i.style.display="none");const a=document.getElementById("dyson-signatures"),n=document.getElementById("dyson-pipeline");a&&(a.style.display="none"),n&&(n.style.display="none"),this.loadBlindTest()}}async loadData(){try{const t=await fetch("/api/discover/dyson");this.data=await t.json()}catch(t){console.error("Dyson API error:",t);return}this.renderSignatures(),this.renderPipeline()}async loadBlindTest(){if(this.blindData){this.renderBlindTest();return}try{const t=await fetch("/api/discover/dyson/blind");this.blindData=await t.json()}catch(t){console.error("Dyson blind test API error:",t);return}this.renderBlindTest()}renderBlindTest(){if(!this.blindArea||!this.blindData)return;this.blindRevealed=!1;const t=this.blindData;this.blindArea.innerHTML=`
<div style="margin-bottom:12px;padding:12px;background:rgba(153,68,255,0.04);border:1px solid rgba(153,68,255,0.15);border-radius:6px">
<div style="font-size:10px;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.4px;margin-bottom:4px">Blind Test Methodology</div>
<div style="font-size:11px;color:var(--text-secondary);line-height:1.5">${t.methodology}</div>
<div style="margin-top:6px;font-size:10px;color:#9944ff;font-family:var(--font-mono)">${t.scoring_formula}</div>
</div>
<div style="display:flex;gap:8px;align-items:center;margin-bottom:12px">
<button id="dyson-reveal-btn" style="padding:8px 20px;border:1px solid #9944ff;border-radius:6px;background:rgba(153,68,255,0.1);color:#9944ff;font-size:12px;font-weight:600;cursor:pointer">Reveal Identities</button>
<span style="font-size:10px;color:var(--text-muted)">Examine pipeline scores first, then reveal to compare</span>
</div>
<table class="data-table" style="width:100%;margin-bottom:12px" id="dyson-blind-table">
<thead>
<tr>
<th style="font-size:10px">Target</th>
<th style="font-size:10px">Opt. Mag</th>
<th style="font-size:10px">W3 Mag</th>
<th style="font-size:10px">W4 Mag</th>
<th style="font-size:10px">Dist (pc)</th>
<th style="font-size:10px">W3 Excess (&sigma;)</th>
<th style="font-size:10px">W4 Excess (&sigma;)</th>
<th style="font-size:10px">Coverage</th>
<th style="font-size:10px">Temp (K)</th>
<th style="font-size:10px">Score</th>
<th style="font-size:10px" class="dyson-reveal-col">Real ID</th>
<th style="font-size:10px" class="dyson-reveal-col">Type</th>
<th style="font-size:10px" class="dyson-reveal-col">Match?</th>
</tr>
</thead>
<tbody>
${t.targets.map(i=>{const s=i.pipeline.pipeline_score>=.7?"#9944ff":i.pipeline.pipeline_score>=.5?"var(--warning)":"var(--text-muted)";return`
<tr>
<td style="font-weight:600;color:#9944ff">${i.target_id}</td>
<td>${i.raw.optical_mag}</td>
<td>${i.raw.w3_mag}</td>
<td>${i.raw.w4_mag}</td>
<td>${i.raw.distance_pc}</td>
<td style="color:${i.pipeline.w3_excess_sigma>10?"#9944ff":"var(--warning)"}">${i.pipeline.w3_excess_sigma.toFixed(1)}&sigma;</td>
<td style="color:${i.pipeline.w4_excess_sigma>15?"#9944ff":"var(--warning)"}">${i.pipeline.w4_excess_sigma.toFixed(1)}&sigma;</td>
<td>${(i.pipeline.coverage_fraction*100).toFixed(1)}%</td>
<td>${i.pipeline.warm_temp_k}K</td>
<td style="color:${s};font-weight:600">${i.pipeline.pipeline_score.toFixed(2)}</td>
<td class="dyson-reveal-col" style="font-size:9px">${i.reveal.id.replace("Gaia DR3 ","").substring(0,8)}...</td>
<td class="dyson-reveal-col">${i.reveal.spectral_type}</td>
<td class="dyson-reveal-col"><span class="score-badge score-high" style="font-size:8px">${i.reveal.match?"EXACT":"CLOSE"}</span></td>
</tr>`}).join("")}
</tbody>
</table>
<div id="dyson-blind-chart" style="margin-bottom:12px"></div>
<div id="dyson-blind-summary" style="display:none"></div>
<style>
.dyson-reveal-col { opacity: 0; pointer-events: none; transition: opacity 0.3s; }
.dyson-revealed .dyson-reveal-col { opacity: 1; pointer-events: auto; }
</style>
`;const e=document.getElementById("dyson-reveal-btn");e&&e.addEventListener("click",()=>this.toggleBlindReveal()),this.drawBlindComparisonChart(t.targets)}toggleBlindReveal(){this.blindRevealed=!this.blindRevealed;const t=document.getElementById("dyson-blind-table"),e=document.getElementById("dyson-reveal-btn"),i=document.getElementById("dyson-blind-summary");if(t&&(this.blindRevealed?t.classList.add("dyson-revealed"):t.classList.remove("dyson-revealed")),e&&(e.textContent=this.blindRevealed?"Hide Identities":"Reveal Identities"),i&&this.blindData)if(this.blindRevealed){const s=this.blindData.summary;i.style.display="",i.innerHTML=`
<div style="padding:16px;background:rgba(153,68,255,0.06);border:1px solid rgba(153,68,255,0.2);border-radius:8px">
<div style="font-size:14px;font-weight:700;color:#9944ff;margin-bottom:8px">
Blind Test Results: ${s.pipeline_matches}/${s.total_targets} Matches (r = ${s.ranking_correlation.toFixed(2)})
</div>
<div style="display:flex;gap:24px;margin-bottom:10px">
<div>
<div style="font-size:9px;color:var(--text-muted);text-transform:uppercase">Ranking Correlation</div>
<div style="font-size:20px;font-weight:700;color:var(--success)">${s.ranking_correlation.toFixed(2)}</div>
</div>
<div>
<div style="font-size:9px;color:var(--text-muted);text-transform:uppercase">Max Score Difference</div>
<div style="font-size:20px;font-weight:700;color:var(--text-primary)">${s.max_score_difference.toFixed(3)}</div>
</div>
<div>
<div style="font-size:9px;color:var(--text-muted);text-transform:uppercase">All Excess Detected</div>
<div style="font-size:20px;font-weight:700;color:${s.all_excess_detected?"var(--success)":"#FF4D4D"}">${s.all_excess_detected?"YES":"NO"}</div>
</div>
</div>
<div style="font-size:12px;color:var(--text-secondary);line-height:1.7">${s.conclusion}</div>
</div>
`}else i.style.display="none"}drawBlindComparisonChart(t){const e=document.getElementById("dyson-blind-chart");if(!e)return;const i=600,s=180,a={top:20,right:20,bottom:30,left:50},n=i-a.left-a.right,o=s-a.top-a.bottom,r=document.createElement("canvas");r.width=i,r.height=s,r.style.cssText="width:100%;max-width:600px;height:auto",e.innerHTML='<div style="font-size:10px;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.4px;margin-bottom:4px">IR Excess Comparison (W3 blue, W4 purple)</div>',e.appendChild(r);const l=r.getContext("2d");if(!l)return;l.fillStyle="#11161C",l.fillRect(0,0,i,s);const c=Math.max(...t.map(h=>Math.max(h.pipeline.w3_excess_sigma,h.pipeline.w4_excess_sigma))),d=n/t.length/2.5;for(let h=0;h<t.length;h++){const u=t[h],m=a.left+h/t.length*n+d*.5,g=u.pipeline.w3_excess_sigma/c*o;l.fillStyle="rgba(68,136,255,0.7)",l.fillRect(m,a.top+o-g,d*.9,g);const x=u.pipeline.w4_excess_sigma/c*o;l.fillStyle="rgba(153,68,255,0.7)",l.fillRect(m+d,a.top+o-x,d*.9,x),l.fillStyle="#8B949E",l.font="9px monospace",l.textAlign="center",l.fillText(u.target_id,m+d,s-8)}l.fillStyle="#484F58",l.font="9px monospace",l.textAlign="right";for(let h=0;h<=c;h+=5){const u=a.top+o-h/c*o;l.fillText(`${h}σ`,a.left-4,u+3),l.strokeStyle="#1C2333",l.lineWidth=.5,l.beginPath(),l.moveTo(a.left,u),l.lineTo(a.left+n,u),l.stroke()}}renderSignatures(){const t=document.getElementById("dyson-signatures");!t||!this.data||(t.innerHTML=`
<div style="font-size:10px;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.5px;margin-bottom:8px">Detection Signatures</div>
<div style="display:flex;gap:12px;flex-wrap:wrap">
${this.data.detection_signatures.map(e=>`
<div style="padding:8px 12px;background:var(--bg-surface);border:1px solid var(--border);border-radius:6px;flex:1;min-width:200px">
<div style="font-size:11px;font-weight:600;color:var(--text-primary)">${e.name}</div>
<div style="font-size:10px;color:var(--text-secondary);margin-top:2px">${e.description}</div>
<div style="font-size:9px;color:#9944ff;margin-top:2px">${e.band}</div>
</div>
`).join("")}
</div>
`)}renderPipeline(){const t=document.getElementById("dyson-pipeline");!t||!this.data||(t.innerHTML=`
<div style="font-size:10px;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.5px;margin-bottom:8px">Search Pipeline</div>
<div style="display:flex;gap:4px;align-items:center;flex-wrap:wrap">
${this.data.pipeline_stages.map((e,i)=>`
<div id="dyson-stage-${i}" style="padding:6px 14px;border-radius:4px;background:var(--bg-surface);border:1px solid var(--border);transition:all 0.3s">
<div style="font-size:10px;font-weight:700;color:var(--text-muted)">${e.stage}</div>
<div style="font-size:9px;color:var(--text-muted)">${e.name}</div>
</div>
${i<this.data.pipeline_stages.length-1?'<span style="color:var(--text-muted)">&#8594;</span>':""}
`).join("")}
</div>
`)}async runSearch(){if(this.running||!this.data)return;this.running=!0,this.candidatesEl&&(this.candidatesEl.innerHTML=""),this.resultEl&&(this.resultEl.style.display="none"),this.chartArea&&(this.chartArea.style.display="none");const t=document.getElementById("dyson-3d-panel");t&&(t.style.display="none");for(let i=0;i<this.data.pipeline_stages.length;i++)this.highlightStage(i),await this.sleep(300);for(const i of this.data.special_targets)await this.sleep(200),this.addSpecialTarget(i);const e=[...this.data.candidates].sort((i,s)=>s.pipeline_score-i.pipeline_score);for(const i of e)await this.sleep(200),this.addCandidateCard(i);this.drawExcessChart(e),e.length>0&&this.update3dSphere(e[0]),await this.sleep(400),this.showResult(),this.running=!1}drawExcessChart(t){if(!this.chartArea)return;this.chartArea.style.display="",this.chartArea.innerHTML="";const e=document.createElement("div");e.style.cssText="font-size:10px;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.4px;margin-bottom:6px",e.textContent="Infrared Excess Comparison — All Candidates",this.chartArea.appendChild(e);const i=700,s=220,a={top:24,right:20,bottom:40,left:55},n=i-a.left-a.right,o=s-a.top-a.bottom,r=document.createElement("canvas");r.width=i,r.height=s,r.style.cssText="width:100%;max-width:700px;height:auto;border-radius:6px",this.chartArea.appendChild(r);const l=r.getContext("2d");if(!l)return;l.fillStyle="#11161C",l.fillRect(0,0,i,s);const c=t.length,d=Math.max(...t.map(f=>f.w3_excess)),h=Math.max(...t.map(f=>f.w4_excess)),u=Math.max(d,h),m=n/c,g=m*.35;l.strokeStyle="#1C2333",l.lineWidth=.5,l.fillStyle="#484F58",l.font="9px monospace",l.textAlign="right";for(let f=0;f<=u;f+=5){const w=a.top+o-f/u*o;l.beginPath(),l.moveTo(a.left,w),l.lineTo(a.left+n,w),l.stroke(),l.fillText(`${f}x`,a.left-4,w+3)}for(let f=0;f<c;f++){const w=t[f],y=a.left+f*m,b=w.w3_excess/u*o;l.fillStyle="rgba(68,136,255,0.75)",l.fillRect(y+m*.1,a.top+o-b,g,b);const v=w.w4_excess/u*o;l.fillStyle="rgba(153,68,255,0.75)",l.fillRect(y+m*.1+g+2,a.top+o-v,g,v);const E=a.top+o-w.coverage_fraction*100/2*o/u;l.beginPath(),l.arc(y+m*.5,Math.max(a.top,E),3,0,Math.PI*2),l.fillStyle="#2ECC71",l.fill();const C=w.id.includes("DR3")?w.id.split(" ").pop().substring(0,6)+"...":w.id;l.fillStyle="#8B949E",l.font="8px monospace",l.textAlign="center",l.save(),l.translate(y+m*.5,s-6),l.rotate(-.3),l.fillText(C,0,0),l.restore(),l.fillStyle=w.pipeline_score>=.7?"#9944ff":"var(--warning)",l.font="9px monospace",l.textAlign="center",l.fillText(w.pipeline_score.toFixed(2),y+m*.5,a.top-6)}const x=a.top+o+18;l.font="9px sans-serif",l.textAlign="left",l.fillStyle="rgba(68,136,255,0.75)",l.fillRect(a.left,x,10,8),l.fillStyle="#8B949E",l.fillText("W3 (12μm)",a.left+14,x+7),l.fillStyle="rgba(153,68,255,0.75)",l.fillRect(a.left+90,x,10,8),l.fillStyle="#8B949E",l.fillText("W4 (22μm)",a.left+104,x+7),l.fillStyle="#2ECC71",l.beginPath(),l.arc(a.left+186,x+4,3,0,Math.PI*2),l.fill(),l.fillStyle="#8B949E",l.fillText("Coverage %",a.left+193,x+7),this.addSedSelector(t)}addSedSelector(t){if(!this.chartArea)return;const e=document.createElement("div");e.style.cssText="margin-top:12px;padding:12px;background:var(--bg-surface);border:1px solid var(--border);border-radius:6px",e.innerHTML=`
<div style="display:flex;align-items:center;gap:8px;margin-bottom:8px">
<div style="font-size:10px;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.4px">Spectral Energy Distribution</div>
<select id="dyson-sed-select" style="padding:3px 8px;background:var(--bg-panel);border:1px solid var(--border);color:var(--text-primary);border-radius:4px;font-size:10px">
${t.map((s,a)=>`<option value="${a}">${s.id.includes("DR3")?s.id.split(" ").pop().substring(0,10)+"...":s.id} (${s.pipeline_score.toFixed(2)})</option>`).join("")}
</select>
</div>
<canvas id="dyson-sed-canvas" width="650" height="180" style="width:100%;max-width:650px;height:auto"></canvas>
<div id="dyson-sed-info" style="margin-top:6px;font-size:10px;color:var(--text-secondary)"></div>
`,this.chartArea.appendChild(e);const i=document.getElementById("dyson-sed-select");i&&(i.addEventListener("change",()=>{this.drawSed(t[parseInt(i.value)])}),this.drawSed(t[0]))}update3dSphere(t){const e=document.getElementById("dyson-3d-panel");e&&(e.style.display="");const i=document.getElementById("dyson-3d-viewport"),s=document.getElementById("dyson-3d-info");if(!i)return;this.sphere3d||(this.sphere3d=new Gs(i));const a={coverageFraction:t.coverage_fraction,warmTempK:t.temperature_k,spectralType:t.spectral_type,w3Excess:t.w3_excess,w4Excess:t.w4_excess,label:t.id};if(this.sphere3d.update(a),this.buildDysonControls(),s){const n=t.id.includes("DR3")&&t.gaia_id||t.id,o=t.dyson_likelihood==="Low"?"var(--text-muted)":t.dyson_likelihood==="Medium"?"var(--warning)":"#9944ff";s.innerHTML=`
<div style="font-size:10px;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.4px;margin-bottom:2px">Candidate Parameters</div>
<div style="padding:10px;background:var(--bg-surface);border:1px solid var(--border);border-radius:6px">
<div style="font-size:12px;font-weight:600;color:var(--text-primary);margin-bottom:6px;font-family:var(--font-mono)">${n}</div>
<div style="font-size:10px;color:var(--text-secondary)">${t.spectral_type} star at ${t.distance_pc} pc</div>
</div>
<div style="padding:10px;background:var(--bg-surface);border:1px solid var(--border);border-radius:6px">
<div style="font-size:9px;color:var(--text-muted);text-transform:uppercase;margin-bottom:4px">Shell Coverage</div>
<div style="font-size:22px;font-weight:700;color:#9944ff;font-family:var(--font-mono)">${(t.coverage_fraction*100).toFixed(1)}%</div>
<div style="height:4px;background:var(--bg);border-radius:2px;margin-top:4px;overflow:hidden">
<div style="height:100%;width:${Math.min(100,t.coverage_fraction*100)}%;background:#9944ff;border-radius:2px"></div>
</div>
<div style="font-size:9px;color:var(--text-muted);margin-top:3px">Fraction of stellar luminosity captured by the swarm</div>
</div>
<div style="padding:10px;background:var(--bg-surface);border:1px solid var(--border);border-radius:6px">
<div style="font-size:9px;color:var(--text-muted);text-transform:uppercase;margin-bottom:4px">Waste Heat Temperature</div>
<div style="font-size:18px;font-weight:600;color:var(--warning);font-family:var(--font-mono)">${t.temperature_k} K</div>
<div style="font-size:9px;color:var(--text-muted);margin-top:2px">${t.temperature_k<200?"Cool outer shell":t.temperature_k<350?"Warm equilibrium":"Hot inner swarm"}</div>
</div>
<div style="padding:10px;background:var(--bg-surface);border:1px solid var(--border);border-radius:6px">
<div style="font-size:9px;color:var(--text-muted);text-transform:uppercase;margin-bottom:4px">IR Excess</div>
<div style="display:flex;gap:12px">
<div>
<div style="font-size:14px;font-weight:600;color:rgba(68,136,255,0.9);font-family:var(--font-mono)">${t.w3_excess.toFixed(1)}x</div>
<div style="font-size:8px;color:var(--text-muted)">W3 (12&mu;m)</div>
</div>
<div>
<div style="font-size:14px;font-weight:600;color:#9944ff;font-family:var(--font-mono)">${t.w4_excess.toFixed(1)}x</div>
<div style="font-size:8px;color:var(--text-muted)">W4 (22&mu;m)</div>
</div>
</div>
</div>
<div style="padding:10px;background:var(--bg-surface);border:1px solid var(--border);border-radius:6px">
<div style="font-size:9px;color:var(--text-muted);text-transform:uppercase;margin-bottom:4px">Pipeline Score</div>
<div style="font-size:18px;font-weight:600;color:${t.pipeline_score>=.7?"#9944ff":"var(--warning)"};font-family:var(--font-mono)">${t.pipeline_score.toFixed(3)}</div>
<div style="font-size:9px;color:${o};font-weight:600;margin-top:2px">Dyson Likelihood: ${t.dyson_likelihood}</div>
</div>
<div style="font-size:9px;color:var(--text-muted);line-height:1.5;padding:4px 0">
<strong>Natural explanations:</strong> ${t.natural_explanations.join(", ")}
</div>
`}}buildDysonControls(){const t=document.getElementById("dyson-3d-controls");if(!t||!this.sphere3d)return;t.innerHTML="";const e="border:1px solid rgba(30,38,48,0.8);border-radius:4px;background:rgba(11,15,20,0.9);color:var(--text-secondary);font-size:10px;padding:4px 8px;cursor:pointer;font-family:var(--font-mono);transition:color 0.15s,border-color 0.15s",i=e.replace("var(--text-secondary)","#9944ff").replace("rgba(30,38,48,0.8)","#9944ff"),s=document.createElement("span");s.style.cssText="font-size:9px;color:var(--text-muted);font-family:var(--font-mono)",s.textContent="Speed:",t.appendChild(s);const a=document.createElement("input");a.type="range",a.min="0.1",a.max="5",a.step="0.1",a.value="1",a.style.cssText="width:70px;height:4px;accent-color:#9944ff;cursor:pointer",a.addEventListener("input",()=>{var d;const c=parseFloat(a.value);(d=this.sphere3d)==null||d.setSpeed(c),n.textContent=`${c.toFixed(1)}x`}),t.appendChild(a);const n=document.createElement("span");n.style.cssText="font-size:9px;color:#9944ff;min-width:24px;font-family:var(--font-mono)",n.textContent="1.0x",t.appendChild(n);const o=document.createElement("span");o.style.cssText="width:1px;height:14px;background:rgba(30,38,48,0.6)",t.appendChild(o);const r=document.createElement("button");r.style.cssText=i,r.textContent="Auto",r.title="Toggle auto-rotate camera",r.addEventListener("click",()=>{var d,h;(d=this.sphere3d)==null||d.toggleAutoRotate();const c=((h=this.sphere3d)==null?void 0:h.getAutoRotate())??!1;r.style.cssText=c?i:e}),t.appendChild(r);const l=document.createElement("button");l.style.cssText=e,l.textContent="Reset",l.title="Reset camera to default position",l.addEventListener("click",()=>{var c,d;(c=this.sphere3d)==null||c.resetCamera(),r.style.cssText=i,a.value="1",n.textContent="1.0x",(d=this.sphere3d)==null||d.setSpeed(1)}),t.appendChild(l)}drawSed(t){this.update3dSphere(t);const e=document.getElementById("dyson-sed-canvas"),i=document.getElementById("dyson-sed-info");if(!e)return;const s=e.getContext("2d");if(!s)return;const a=e.width,n=e.height,o={top:16,right:16,bottom:30,left:50},r=a-o.left-o.right,l=n-o.top-o.bottom;s.clearRect(0,0,a,n),s.fillStyle="#0D1117",s.fillRect(0,0,a,n);const c=[{name:"G",wl:.5,log:Math.log10(.5)},{name:"J",wl:1.25,log:Math.log10(1.25)},{name:"H",wl:1.65,log:Math.log10(1.65)},{name:"K",wl:2.2,log:Math.log10(2.2)},{name:"W1",wl:3.4,log:Math.log10(3.4)},{name:"W2",wl:4.6,log:Math.log10(4.6)},{name:"W3",wl:12,log:Math.log10(12)},{name:"W4",wl:22,log:Math.log10(22)}],d=Math.log10(.3),h=Math.log10(30),u=M=>o.left+(M-d)/(h-d)*r,m=t.temperature_k>1e3?t.temperature_k:3400,g=M=>{const S=3e14/M,$=6626e-37*S/(138e-25*m);return $>50?0:S*S*S/(Math.exp($)-1)},x=c.map(M=>g(M.wl)),f=Math.max(...x),w=c.map((M,S)=>{let $=x[S]/f;return M.name==="W3"&&($*=t.w3_excess),M.name==="W4"&&($*=t.w4_excess),$}),y=x.map(M=>M/f),b=[...y,...w].filter(M=>M>0),v=Math.log10(Math.min(...b)*.5),E=Math.log10(Math.max(...b)*2),C=M=>o.top+l-(M-v)/(E-v)*l;s.strokeStyle="#1C2333",s.lineWidth=.5;for(let M=Math.ceil(v);M<=Math.floor(E);M++){const S=C(M);s.beginPath(),s.moveTo(o.left,S),s.lineTo(o.left+r,S),s.stroke(),s.fillStyle="#484F58",s.font="8px monospace",s.textAlign="right",s.fillText(`10^${M}`,o.left-4,S+3)}s.strokeStyle="rgba(255,221,68,0.5)",s.lineWidth=1.5,s.beginPath();let T=!0;for(let M=d;M<=h;M+=.02){const S=Math.pow(10,M),$=g(S)/f;if($<=0)continue;const O=u(M),K=C(Math.log10($));T?(s.moveTo(O,K),T=!1):s.lineTo(O,K)}s.stroke();const R=t.temperature_k>100?t.temperature_k:328;s.strokeStyle="rgba(153,68,255,0.5)",s.lineWidth=1,s.setLineDash([4,3]),s.beginPath(),T=!0;for(let M=Math.log10(2);M<=h;M+=.02){const $=3e14/Math.pow(10,M),O=6626e-37*$/(138e-25*R);if(O>50)continue;const U=t.coverage_fraction*($*$*$)/(Math.exp(O)-1)/f*50;if(U<=0)continue;const pt=u(M),st=C(Math.log10(U));st<o.top||st>o.top+l||(T?(s.moveTo(pt,st),T=!1):s.lineTo(pt,st))}s.stroke(),s.setLineDash([]);for(let M=0;M<c.length;M++){const S=c[M],$=w[M];if($<=0)continue;const O=u(S.log),K=C(Math.log10($)),U=S.name==="W3"||S.name==="W4";if(s.fillStyle=U?"#9944ff":"#ffdd44",s.beginPath(),s.arc(O,K,U?5:3.5,0,Math.PI*2),s.fill(),U){const pt=y[M];if(pt>0){const st=C(Math.log10(pt));s.fillStyle="rgba(255,221,68,0.5)",s.beginPath(),s.arc(O,st,3,0,Math.PI*2),s.fill(),s.strokeStyle="rgba(153,68,255,0.6)",s.lineWidth=1,s.beginPath(),s.moveTo(O,st),s.lineTo(O,K),s.stroke()}}s.fillStyle=U?"#9944ff":"#8B949E",s.font="9px monospace",s.textAlign="center",s.fillText(S.name,O,o.top+l+14)}s.fillStyle="#8B949E",s.font="9px sans-serif",s.textAlign="center",s.fillText("Wavelength (μm, log scale)",o.left+r/2,n-4),s.textAlign="left";const k=o.left+r-200;s.fillStyle="rgba(255,221,68,0.5)",s.fillRect(k,o.top+2,10,2),s.fillStyle="#8B949E",s.fillText("Stellar photosphere",k+14,o.top+7),s.fillStyle="rgba(153,68,255,0.5)",s.fillRect(k,o.top+14,10,2),s.fillStyle="#8B949E",s.fillText(`Warm component (${R}K)`,k+14,o.top+19),i&&(i.innerHTML=`
<strong style="color:var(--text-primary)">${t.id.includes("DR3")?t.id.split(" ").pop().substring(0,16)+"...":t.id}</strong>
&mdash; ${t.spectral_type} at ${t.distance_pc} pc
&mdash; W3 excess: <span style="color:#4488ff">${t.w3_excess.toFixed(1)}x</span>
&mdash; W4 excess: <span style="color:#9944ff">${t.w4_excess.toFixed(1)}x</span>
&mdash; Coverage: <span style="color:#2ECC71">${(t.coverage_fraction*100).toFixed(1)}%</span>
&mdash; Warm temp: ${t.temperature_k}K
&mdash; Likelihood: <span style="color:${t.dyson_likelihood==="Low"?"var(--text-muted)":"#9944ff"}">${t.dyson_likelihood}</span>
`)}highlightStage(t){var e;for(let i=0;i<(((e=this.data)==null?void 0:e.pipeline_stages.length)??0);i++){const s=document.getElementById(`dyson-stage-${i}`);if(!s)continue;const a=s.querySelector("div");i<t?(s.style.background="rgba(153,68,255,0.15)",s.style.borderColor="rgba(153,68,255,0.4)",a&&(a.style.color="#9944ff")):i===t?(s.style.background="rgba(153,68,255,0.25)",s.style.borderColor="#9944ff",a&&(a.style.color="#9944ff")):(s.style.background="var(--bg-surface)",s.style.borderColor="var(--border)",a&&(a.style.color="var(--text-muted)"))}}addSpecialTarget(t){if(!this.candidatesEl)return;const e=document.createElement("div");e.style.cssText="padding:12px 16px;margin-bottom:8px;border-radius:6px;background:rgba(255,176,32,0.06);border:1px solid rgba(255,176,32,0.3)",e.innerHTML=`
<div style="display:flex;align-items:center;gap:8px;margin-bottom:4px">
<span style="font-size:13px;font-weight:600;color:var(--text-primary)">${t.id}</span>
<span class="score-badge score-medium" style="font-size:8px">NOTABLE TARGET</span>
</div>
<div style="font-size:11px;color:var(--text-secondary);margin-bottom:4px">${t.description}</div>
<div style="font-size:10px;color:var(--text-muted)">
${t.key_observations.map(i=>`<div style="margin-left:8px">&#8226; ${i}</div>`).join("")}
</div>
<div style="font-size:10px;color:var(--warning);margin-top:4px;font-style:italic">Status: ${t.current_status}</div>
`,this.candidatesEl.appendChild(e)}addCandidateCard(t){if(!this.candidatesEl)return;const e=t.dyson_likelihood==="None (debunked)",i=e?"#FF4D4D":t.pipeline_score>=.7?"#9944ff":t.pipeline_score>=.4?"var(--warning)":"var(--text-muted)",s=e?"rgba(255,77,77,0.3)":"var(--border)",a=e?"rgba(255,77,77,0.04)":"var(--bg-surface)",n=document.createElement("div");n.style.cssText=`padding:12px 16px;margin-bottom:8px;border-radius:6px;background:${a};border:1px solid ${s};cursor:pointer;transition:border-color 0.2s`,n.addEventListener("mouseenter",()=>{n.style.borderColor=e?"#FF4D4D":"#9944ff"}),n.addEventListener("mouseleave",()=>{n.style.borderColor=s}),n.addEventListener("click",()=>this.drawSed(t));const o=e?'<span style="font-size:8px;padding:2px 6px;border-radius:3px;background:rgba(255,77,77,0.15);color:#FF4D4D;font-weight:700;text-transform:uppercase;letter-spacing:0.3px">DEBUNKED</span>':t.follow_up_status?'<span style="font-size:8px;padding:2px 6px;border-radius:3px;background:rgba(255,176,32,0.1);color:var(--warning);font-weight:600;text-transform:uppercase;letter-spacing:0.3px">UNCONFIRMED</span>':"",r=t.follow_up_status?`<div style="font-size:9px;color:${e?"#FF4D4D":"var(--warning)"};margin-top:4px;font-style:italic;border-top:1px solid var(--border-subtle);padding-top:4px">${t.follow_up_status}</div>`:"";n.innerHTML=`
<div style="display:flex;align-items:center;gap:8px;margin-bottom:4px">
<span style="font-size:13px;font-weight:600;color:${e?"#FF4D4D":"var(--text-primary)"};${e?"text-decoration:line-through":""}">${t.id}</span>
${o}
<span style="font-size:10px;color:${i};font-weight:600">Score: ${t.pipeline_score.toFixed(2)}</span>
<span style="font-size:9px;color:var(--text-muted)">${t.spectral_type} | ${t.distance_pc} pc | Coverage: ${(t.coverage_fraction*100).toFixed(1)}%</span>
<span style="font-size:9px;color:var(--text-muted);margin-left:auto">W3: ${t.w3_excess.toFixed(1)}x | W4: ${t.w4_excess.toFixed(1)}x</span>
</div>
<div style="display:flex;gap:16px">
<div style="flex:1">
<div style="font-size:11px;color:var(--text-secondary);line-height:1.5">${t.analysis}</div>
${r}
</div>
<div style="min-width:200px">
<div style="font-size:9px;color:var(--text-muted);text-transform:uppercase;margin-bottom:3px">Natural Explanations</div>
${t.natural_explanations.map(l=>`<div style="font-size:10px;color:var(--text-secondary);margin-left:8px">&#8226; ${l}</div>`).join("")}
<div style="font-size:9px;color:${e?"#FF4D4D":t.dyson_likelihood==="Low"?"var(--text-muted)":"var(--warning)"};margin-top:4px;font-weight:600">Dyson likelihood: ${t.dyson_likelihood}</div>
</div>
</div>
`,this.candidatesEl.appendChild(n)}showResult(){if(!this.resultEl||!this.data)return;const t=this.data.summary;this.resultEl.style.display="",this.resultEl.innerHTML=`
<div style="padding:20px;background:rgba(153,68,255,0.06);border:2px solid rgba(153,68,255,0.3);border-radius:10px">
<div style="font-size:16px;font-weight:700;color:#9944ff;margin-bottom:10px">Search Results</div>
<div style="display:flex;gap:24px;margin-bottom:12px">
<div>
<div style="font-size:9px;color:var(--text-muted);text-transform:uppercase">Stars Searched</div>
<div style="font-size:20px;font-weight:700;color:var(--text-primary)">${t.stars_searched}</div>
</div>
<div>
<div style="font-size:9px;color:var(--text-muted);text-transform:uppercase">Anomalous Candidates</div>
<div style="font-size:20px;font-weight:700;color:#9944ff">${t.candidates_found}</div>
</div>
</div>
<div style="font-size:12px;color:var(--text-secondary);line-height:1.7">${t.conclusion}</div>
<div style="margin-top:12px;font-size:9px;color:var(--text-muted)">
${this.data.references.map(e=>`<div>${e}</div>`).join("")}
</div>
</div>
`}sleep(t){return new Promise(e=>setTimeout(e,t))}unmount(){this.running=!1,this.sphere3d&&(this.sphere3d.destroy(),this.sphere3d=null),this.container=null,this.candidatesEl=null,this.resultEl=null,this.chartArea=null,this.blindArea=null,this.sphere3dContainer=null,this.sphere3dInfoEl=null,this.data=null,this.blindData=null}}const Jt=[{id:"overview",label:"Overview",icon:"⌂",children:[{id:"what-is-rvf",label:"What is RVF?"},{id:"at-a-glance",label:"At a Glance"}]},{id:"single-file",label:"Single File",icon:"▣",children:[{id:"segments",label:"Segment Map"},{id:"why-one-file",label:"Why One File?"}]},{id:"pipeline",label:"Pipeline",icon:"▶",children:[{id:"stage-ingest",label:"Data Ingestion"},{id:"stage-process",label:"Signal Processing"},{id:"stage-detect",label:"Candidate Detection"},{id:"stage-score",label:"Scoring"},{id:"stage-seal",label:"Witness Sealing"}]},{id:"proof",label:"Proof",icon:"✓",children:[{id:"witness-chain",label:"Witness Chain"},{id:"reproducible",label:"Reproducible"},{id:"acceptance",label:"Acceptance Test"},{id:"blind",label:"Blind Testing"}]},{id:"unique",label:"Why Unique",icon:"★"},{id:"capabilities",label:"Views",icon:"◎",children:[{id:"cap-atlas",label:"Atlas Explorer"},{id:"cap-coherence",label:"Coherence"},{id:"cap-boundaries",label:"Boundaries"},{id:"cap-memory",label:"Memory Tiers"},{id:"cap-planets",label:"Planets"},{id:"cap-life",label:"Life"},{id:"cap-witness",label:"Witness Chain"},{id:"cap-solver",label:"Solver"},{id:"cap-blind",label:"Blind Test"},{id:"cap-discover",label:"Discovery"},{id:"cap-dyson",label:"Dyson Sphere"},{id:"cap-status",label:"Status"}]},{id:"solver",label:"Solver",icon:"⚙",children:[{id:"thompson",label:"Thompson Sampling"},{id:"auto-optimize",label:"Auto-Optimize"}]},{id:"format",label:"Format Spec",icon:"☰",children:[{id:"file-header",label:"File Header"},{id:"seg-types",label:"Segment Types"},{id:"witness-format",label:"Witness Entry"},{id:"dashboard-seg",label:"Dashboard Segment"}]},{id:"glossary",label:"Glossary",icon:"≡"}];class Vs{constructor(){this.container=null,this.contentEl=null,this.navLinks=new Map,this.scrollRaf=0,this.onScroll=()=>{cancelAnimationFrame(this.scrollRaf),this.scrollRaf=requestAnimationFrame(()=>{if(!this.contentEl)return;const t=this.contentEl.scrollTop+60;let e="";const i=Array.from(this.navLinks.keys());for(const s of i){const a=this.contentEl.querySelector(`#${s}`);a&&a.offsetTop<=t&&(e=s)}this.navLinks.forEach((s,a)=>{const n=a===e;s.classList.toggle("doc-active",n);const o=Jt.some(r=>r.id===a);n?(s.style.color="var(--accent)",s.style.borderLeftColor="var(--accent)",s.style.background=o?"rgba(0,229,255,0.06)":"rgba(0,229,255,0.03)"):(s.style.color=o?"var(--text-secondary)":"var(--text-muted)",s.style.borderLeftColor="transparent",s.style.background="")})})}}mount(t){this.container=t;const e=document.createElement("div");e.style.cssText="display:flex;width:100%;height:100%;overflow:hidden",t.appendChild(e);const i=this.buildNav();e.appendChild(i),this.contentEl=document.createElement("div"),this.contentEl.style.cssText="flex:1;overflow-y:auto;overflow-x:hidden;scroll-behavior:smooth;-webkit-overflow-scrolling:touch;min-width:0",e.appendChild(this.contentEl);const s=document.createElement("div");s.style.cssText="max-width:820px;margin:0 auto;padding:28px 32px 100px;line-height:1.7;color:var(--text-secondary);font-size:13px",this.contentEl.appendChild(s),s.innerHTML=this.buildContent(),this.contentEl.addEventListener("scroll",this.onScroll),requestAnimationFrame(()=>this.onScroll())}unmount(){var t;cancelAnimationFrame(this.scrollRaf),(t=this.contentEl)==null||t.removeEventListener("scroll",this.onScroll),this.navLinks.clear(),this.contentEl=null,this.container=null}buildNav(){const t=document.createElement("nav");t.style.cssText=`
width:220px;min-width:220px;background:var(--bg-panel);border-right:1px solid var(--border);
overflow-y:auto;overflow-x:hidden;padding:16px 0;display:flex;flex-direction:column;
-webkit-overflow-scrolling:touch;flex-shrink:0
`;const e=document.createElement("div");e.style.cssText="padding:0 16px 14px;font-size:13px;font-weight:600;color:var(--text-primary);letter-spacing:0.3px;border-bottom:1px solid var(--border);margin-bottom:8px",e.textContent="Documentation",t.appendChild(e);for(const a of Jt){const n=document.createElement("a");if(n.style.cssText=`
display:flex;align-items:center;gap:8px;padding:7px 16px;
font-size:12px;font-weight:600;color:var(--text-secondary);cursor:pointer;
text-decoration:none;transition:color 0.15s,background 0.15s;border-left:2px solid transparent
`,n.innerHTML=`<span style="font-size:11px;width:16px;text-align:center;opacity:0.6">${a.icon}</span> ${a.label}`,n.addEventListener("click",o=>{o.preventDefault(),this.scrollTo(a.id)}),n.addEventListener("mouseenter",()=>{n.style.color="var(--text-primary)",n.style.background="rgba(255,255,255,0.02)"}),n.addEventListener("mouseleave",()=>{n.classList.contains("doc-active")||(n.style.color="var(--text-secondary)",n.style.background="")}),t.appendChild(n),this.navLinks.set(a.id,n),a.children)for(const o of a.children){const r=document.createElement("a");r.style.cssText=`
display:block;padding:4px 16px 4px 40px;font-size:11px;color:var(--text-muted);
cursor:pointer;text-decoration:none;transition:color 0.15s;border-left:2px solid transparent
`,r.textContent=o.label,r.addEventListener("click",l=>{l.preventDefault(),this.scrollTo(o.id)}),r.addEventListener("mouseenter",()=>{r.style.color="var(--text-secondary)"}),r.addEventListener("mouseleave",()=>{r.classList.contains("doc-active")||(r.style.color="var(--text-muted)")}),t.appendChild(r),this.navLinks.set(o.id,r)}}const i=document.createElement("div");i.style.cssText="flex:1;min-height:20px",t.appendChild(i);const s=document.createElement("div");return s.style.cssText="padding:12px 16px;border-top:1px solid var(--border);font-size:9px;color:var(--text-muted);line-height:1.5",s.innerHTML='Built with <span style="color:var(--accent)">RuVector</span><br>Rust + WASM + Three.js',t.appendChild(s),t}scrollTo(t){var i;const e=(i=this.contentEl)==null?void 0:i.querySelector(`#${t}`);e&&this.contentEl&&this.contentEl.scrollTo({top:e.offsetTop-20,behavior:"smooth"})}buildContent(){const t={h1:"font-size:26px;font-weight:300;color:var(--text-primary);letter-spacing:0.5px;margin-bottom:6px",h2:"font-size:19px;font-weight:600;color:var(--text-primary);margin-top:48px;margin-bottom:10px;padding-bottom:8px;border-bottom:1px solid var(--border)",h3:"font-size:14px;font-weight:600;color:var(--accent);margin-top:28px;margin-bottom:8px",p:"margin-bottom:14px",card:"background:var(--bg-panel);border:1px solid var(--border);border-radius:6px;padding:14px 18px;margin-bottom:12px",code:"font-family:var(--font-mono);font-size:11px;background:var(--bg-surface);border:1px solid var(--border);border-radius:4px;padding:12px 16px;display:block;margin:10px 0 14px;overflow-x:auto;line-height:1.6;color:var(--text-primary)",accent:"color:var(--accent);font-weight:600",success:"color:var(--success);font-weight:600",badge:"display:inline-block;font-size:9px;font-weight:600;padding:2px 8px;border-radius:3px;margin-right:4px",inline:"background:var(--bg-surface);padding:1px 6px;border-radius:3px;font-family:var(--font-mono);font-size:12px"};return`
<!-- ============ OVERVIEW ============ -->
<div style="${t.h1}" id="overview">Causal Atlas Documentation</div>
<div style="font-size:13px;color:var(--text-muted);margin-bottom:20px">
A complete guide to the RVF scientific discovery platform.
</div>
<div style="${t.h3}" id="what-is-rvf">What is RVF?</div>
<div style="${t.p}">
<span style="${t.accent}">RVF (RuVector Format)</span> is a binary container that holds
an entire scientific discovery pipeline &mdash; raw telescope data, analysis code,
results, cryptographic proofs, and this interactive dashboard &mdash; in a
<strong>single, self-contained file</strong>.
</div>
<div style="${t.p}">
Think of it as a shipping container for science. Anyone who receives the file can
independently verify every step of the analysis without external tools or databases.
</div>
<div style="${t.h3}" id="at-a-glance">At a Glance</div>
<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px;margin-bottom:16px">
${this.statCard("File Format","Binary, segmented",t)}
${this.statCard("Crypto","Ed25519 + SHAKE-256",t)}
${this.statCard("Solver","WASM + Thompson Sampling",t)}
${this.statCard("Dashboard","Three.js + D3",t)}
${this.statCard("Server","Rust / Axum",t)}
${this.statCard("Domains","Exoplanets, Dyson, Bio",t)}
</div>
<!-- ============ SINGLE FILE ============ -->
<div style="${t.h2}" id="single-file">One File Contains Everything</div>
<div style="${t.p}">
Traditional scientific data is scattered across files, servers, and packages.
RVF packs everything into typed <strong>segments</strong> inside one binary file.
</div>
<div style="${t.h3}" id="segments">Segment Map</div>
<div style="${t.card}">
<div style="font-family:var(--font-mono);font-size:11px;line-height:2.2">
${this.segRow("HEADER (64 B)","File magic, version, segment count","var(--text-muted)")}
${this.segRow("DATA_SEG","Raw telescope observations (light curves, spectra)","#FF6B9D")}
${this.segRow("KERNEL_SEG","Processing algorithms for analysis","#FFB020")}
${this.segRow("EBPF_SEG","Fast in-kernel data filtering programs","#9944FF")}
${this.segRow("WASM_SEG","Self-learning solver (runs in any browser)","#2ECC71")}
${this.segRow("WITNESS_SEG","Cryptographic proof chain (Ed25519 signed)","var(--accent)")}
${this.segRow("DASHBOARD_SEG","This interactive 3D dashboard (HTML/JS/CSS)","#FF4D4D")}
${this.segRow("SIGNATURE","Ed25519 signature over all segments","var(--text-muted)")}
</div>
</div>
<div style="${t.h3}" id="why-one-file">Why One File?</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:16px">
<div style="${t.card}padding:10px 14px">
<div style="font-size:11px;${t.accent}margin-bottom:3px">Portability</div>
<div style="font-size:11px;line-height:1.5">Email it, USB drive, or static hosting. No server setup needed.</div>
</div>
<div style="${t.card}padding:10px 14px">
<div style="font-size:11px;${t.accent}margin-bottom:3px">Reproducibility</div>
<div style="font-size:11px;line-height:1.5">Code + data together means anyone can re-run the analysis.</div>
</div>
<div style="${t.card}padding:10px 14px">
<div style="font-size:11px;${t.accent}margin-bottom:3px">Integrity</div>
<div style="font-size:11px;line-height:1.5">Tampering with any segment breaks the signature chain.</div>
</div>
<div style="${t.card}padding:10px 14px">
<div style="font-size:11px;${t.accent}margin-bottom:3px">Archival</div>
<div style="font-size:11px;line-height:1.5">One file to store, back up, and cite. No link rot.</div>
</div>
</div>
<!-- ============ PIPELINE ============ -->
<div style="${t.h2}" id="pipeline">How the Pipeline Works</div>
<div style="${t.p}">
The pipeline transforms raw observations into verified discoveries through five stages.
Each stage is recorded in the witness chain for full traceability.
</div>
<div style="${t.h3}" id="stage-ingest">1. Data Ingestion</div>
<div style="${t.p}">
Raw photometric data (brightness over time) is ingested from telescope archives.
For exoplanet detection, this means <span style="${t.accent}">light curves</span> &mdash;
graphs of stellar brightness that dip when a planet transits its star.
</div>
<div style="${t.h3}" id="stage-process">2. Signal Processing</div>
<div style="${t.p}">
Processing kernels clean the data: removing instrumental noise, correcting for stellar
variability, and flagging periodic signals. The <span style="${t.accent}">eBPF programs</span>
accelerate filtering at near-hardware speed.
</div>
<div style="${t.h3}" id="stage-detect">3. Candidate Detection</div>
<div style="${t.p}">
Cleaned signals are matched against known patterns. For exoplanets: periodic transit-shaped dips.
For Dyson spheres: anomalous infrared excess. Each candidate gets derived parameters:
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:14px">
<div style="${t.card}padding:10px 14px">
<div style="font-size:10px;${t.accent}margin-bottom:3px">Exoplanets</div>
<div style="font-size:11px">Radius, period, temperature, HZ membership, ESI score</div>
</div>
<div style="${t.card}padding:10px 14px">
<div style="font-size:10px;color:#FFB020;font-weight:600;margin-bottom:3px">Dyson Candidates</div>
<div style="font-size:11px">IR excess ratio, dimming pattern, partial coverage fraction</div>
</div>
</div>
<div style="${t.h3}" id="stage-score">4. Scoring &amp; Ranking</div>
<div style="${t.p}">
Candidates are scored multi-dimensionally. The <span style="${t.accent}">WASM solver</span>
uses Thompson Sampling to discover which analysis strategies work best for each difficulty
level, continuously improving accuracy without human tuning.
</div>
<div style="${t.h3}" id="stage-seal">5. Witness Sealing</div>
<div style="${t.p}">
Every step is recorded in the <span style="${t.accent}">witness chain</span>: a SHAKE-256 hash
of the data, a timestamp, and an Ed25519 signature. This creates an immutable,
cryptographically verifiable audit trail.
</div>
<!-- ============ PROOF ============ -->
<div style="${t.h2}" id="proof">How Discoveries Are Proven</div>
<div style="${t.p}">
<strong>How do you know the results are real?</strong> RVF uses four layers of proof.
</div>
<div style="${t.h3}" id="witness-chain">Layer 1: Cryptographic Witness Chain</div>
<div style="${t.card}">
<div style="font-size:11px;line-height:1.9;margin-bottom:6px">
Each processing step writes a witness entry containing:<br>
&bull; <strong>Step name</strong> &mdash; what operation was performed<br>
&bull; <strong>Input hash</strong> &mdash; SHAKE-256 of data going in<br>
&bull; <strong>Output hash</strong> &mdash; SHAKE-256 of data coming out<br>
&bull; <strong>Parent hash</strong> &mdash; links to previous entry (chain)<br>
&bull; <strong>Ed25519 signature</strong> &mdash; proves the entry is authentic
</div>
<div style="font-size:10px;color:var(--text-muted)">
Each entry chains to the previous one. Altering any step breaks all subsequent signatures.
</div>
</div>
<div style="${t.h3}" id="reproducible">Layer 2: Reproducible Computation</div>
<div style="${t.p}">
The file contains the actual analysis code (WASM + eBPF) alongside raw data.
Anyone can re-run the pipeline from scratch and verify identical results.
No "trust us" &mdash; the math is in the file.
</div>
<div style="${t.h3}" id="acceptance">Layer 3: Acceptance Testing</div>
<div style="${t.card}">
<div style="font-size:11px;line-height:1.9">
<span style="color:#FF4D4D;font-weight:600">Mode A (Heuristic)</span> &mdash; Can the solver achieve basic accuracy?<br>
<span style="color:#FFB020;font-weight:600">Mode B (Compiler)</span> &mdash; Accuracy + computational cost reduction?<br>
<span style="color:#2ECC71;font-weight:600">Mode C (Learned)</span> &mdash; Full: accuracy + cost + robustness + zero violations.
</div>
<div style="font-size:10px;color:var(--text-muted);margin-top:6px">
All three modes must pass. The manifest is itself recorded in the witness chain.
</div>
</div>
<div style="${t.h3}" id="blind">Layer 4: Blind Testing</div>
<div style="${t.p}">
The Blind Test page runs the pipeline on unlabeled data, then compares against ground truth.
This guards against overfitting &mdash; the pipeline must work on data it has never seen.
</div>
<!-- ============ UNIQUE ============ -->
<div style="${t.h2}" id="unique">What Makes This Unique</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:14px">
${this.uniqueCard("Self-Contained","One file. No cloud, no databases, no external dependencies. The entire pipeline, visualization, and proof chain travel together.",t)}
${this.uniqueCard("Cryptographically Verified","Every step is hashed and signed. Tampering with one part invalidates the entire chain. Mathematical proof, not just peer review.",t)}
${this.uniqueCard("Self-Learning","The WASM solver improves over time using Thompson Sampling, discovering which strategies work for different data difficulties.",t)}
${this.uniqueCard("Runs Anywhere","WASM solver + HTML dashboard + Rust server. No Python, no Jupyter, no conda. Open the file and explore in any modern browser.",t)}
${this.uniqueCard("Multi-Domain","Transit detection, Dyson sphere search, habitability scoring, biosignature analysis &mdash; all in one causal event graph.",t)}
${this.uniqueCard("Interactive 3D","Embedded Three.js dashboard: explore the causal atlas as a galaxy, rotate planet systems, visualize Dyson sphere geometry.",t)}
</div>
<!-- ============ CAPABILITIES ============ -->
<div style="${t.h2}" id="capabilities">Dashboard Views</div>
<div style="${t.p}">12 interactive views, each pulling live data from the RVF file.</div>
${this.viewCard("cap-atlas","Atlas Explorer","#/atlas","var(--accent)","3D galaxy-style causal event graph. Each star = a causal event. Edges = cause-effect. Configurable arms, density, and sector labels.",["3D OrbitControls","Time scale selector","Galaxy shape config","Star map sectors"])}
${this.viewCard("cap-coherence","Coherence Heatmap","#/coherence","#FFB020","Color-mapped surface showing data self-consistency across the observation grid. Blue = stable, red = high uncertainty.",["Surface plot","Epoch scrubber","Partition boundaries"])}
${this.viewCard("cap-boundaries","Boundaries","#/boundaries","#9944FF","Tracks how data partition boundaries shift as new observations arrive. Alerts when boundaries change rapidly.",["Timeline chart","Alert feed","Sector detail"])}
${this.viewCard("cap-memory","Memory Tiers","#/memory","#FF6B9D","Three-tier storage: Small (hot), Medium (warm), Large (cold). Shows utilization, hit rates, and tier migration.",["S/M/L gauges","Utilization bars","Migration flow"])}
${this.viewCard("cap-planets","Planet Candidates","#/planets","#2ECC71","Ranked exoplanet candidates with radius, period, temperature, habitable zone status, and Earth Similarity Index.",["Sortable table","Light curve plots","Score radar"])}
${this.viewCard("cap-life","Life Candidates","#/life","#2ECC71","Biosignature analysis: atmospheric spectra for O₂, CH₄, H₂O. Multi-dimensional scoring with confound analysis.",["Spectrum plots","Molecule heatmap","Reaction graph"])}
${this.viewCard("cap-witness","Witness Chain","#/witness","var(--accent)","Complete cryptographic audit trail. Every step with timestamp, hashes, and signature verification status.",["Scrolling entries","Hash verification","Pipeline trace"])}
${this.viewCard("cap-solver","RVF Solver","#/solver","#FFB020","WASM self-learning solver with Thompson Sampling. 3D landscape shows bandit arm rewards. Configurable training parameters.",["3D landscape","Training curves","A/B/C acceptance","Auto-Optimize"])}
${this.viewCard("cap-blind","Blind Test","#/blind-test","#FF4D4D","Pipeline on unlabeled data, then compared against ground truth. The gold standard for preventing overfitting.",["Unlabeled processing","Ground truth compare","Accuracy metrics"])}
${this.viewCard("cap-discover","Discovery","#/discover","#00E5FF","3D exoplanet systems with host star, orbit, habitable zone. Real KOI parameters. Galaxy background.",["3D planet system","Speed/rotate controls","ESI comparison"])}
${this.viewCard("cap-dyson","Dyson Sphere","#/dyson","#9944FF","Dyson swarm detection using Project Hephaistos methodology. IR excess analysis and 3D wireframe visualization.",["3D Dyson wireframe","IR excess analysis","SED plots"])}
${this.viewCard("cap-status","System Status","#/status","#8B949E","RVF file health, segment sizes, memory tier utilization, pipeline stage indicators, and live witness log.",["Segment breakdown","Tier gauges","Witness log feed"])}
<!-- ============ SOLVER ============ -->
<div style="${t.h2}" id="solver">The Self-Learning Solver</div>
<div style="${t.p}">
The solver is a <span style="${t.accent}">WebAssembly module</span> compiled from Rust.
It runs entirely in your browser using <strong>Thompson Sampling</strong>.
</div>
<div style="${t.h3}" id="thompson">How Thompson Sampling Works</div>
<div style="${t.p}">
Imagine 8 different analysis strategies ("arms"). You don't know which works best.
Thompson Sampling maintains a Beta distribution for each arm's success rate,
samples from these on each attempt, and picks the highest sample. This balances:
</div>
<div style="${t.card}">
<div style="font-size:12px;line-height:1.8">
<span style="${t.accent}">Exploration</span> &mdash; Trying uncertain arms to gather data<br>
<span style="${t.success}">Exploitation</span> &mdash; Using known-good arms to maximize results
</div>
<div style="font-size:10px;color:var(--text-muted);margin-top:6px">
Over time, the solver converges on optimal strategies per difficulty level.
The 3D landscape visually shows which arms have the highest rewards.
</div>
</div>
<div style="${t.h3}" id="auto-optimize">Auto-Optimize</div>
<div style="${t.p}">
The <span style="${t.success}">Auto-Optimize</span> button trains in batches of 3 rounds,
tests acceptance after each batch, and stops when all three modes pass (max 30 rounds).
If accuracy is below 60%, it automatically increases training intensity.
</div>
<!-- ============ FORMAT ============ -->
<div style="${t.h2}" id="format">RVF File Format Reference</div>
<div style="${t.h3}" id="file-header">File Header (64 bytes)</div>
<pre style="${t.code}">Offset Size Field
0x00 4 Magic: 0x52564631 ("RVF1")
0x04 2 Format version (currently 1)
0x06 2 Flags (bit 0 = signed, bit 1 = compressed)
0x08 8 Total file size
0x10 4 Segment count
0x14 4 Reserved
0x18 32 SHAKE-256 hash of all segments
0x38 8 Creation timestamp (Unix epoch)</pre>
<div style="${t.h3}" id="seg-types">Segment Types</div>
<div style="overflow-x:auto;margin-bottom:14px">
<table style="width:100%;font-size:11px;font-family:var(--font-mono);border-collapse:collapse">
<tr style="border-bottom:1px solid var(--border)">
<th style="padding:6px 8px;text-align:left;color:var(--text-muted);font-weight:500;width:50px">ID</th>
<th style="padding:6px 8px;text-align:left;color:var(--text-muted);font-weight:500;width:110px">Name</th>
<th style="padding:6px 8px;text-align:left;color:var(--text-muted);font-weight:500">Purpose</th>
</tr>
${this.tableRow("0x01","DATA","Raw observations (light curves, spectra)")}
${this.tableRow("0x02","KERNEL","Processing algorithms")}
${this.tableRow("0x03","RESULT","Computed results and derived parameters")}
${this.tableRow("0x04","WITNESS","Cryptographic audit trail")}
${this.tableRow("0x05","SIGNATURE","Ed25519 digital signature")}
${this.tableRow("0x06","INDEX","Fast lookup table for segments")}
${this.tableRow("0x0F","EBPF","eBPF bytecode for in-kernel filtering")}
${this.tableRow("0x10","WASM","WebAssembly solver module")}
${this.tableRow("0x11","DASHBOARD","Embedded web dashboard (HTML/JS/CSS)")}
</table>
</div>
<div style="${t.h3}" id="witness-format">Witness Entry Format</div>
<pre style="${t.code}">struct WitnessEntry {
step_name: String, // "transit_detection"
timestamp: u64, // Unix epoch nanoseconds
input_hash: [u8; 32], // SHAKE-256 of input
output_hash: [u8; 32], // SHAKE-256 of output
parent_hash: [u8; 32], // Previous entry hash (chain)
signature: [u8; 64], // Ed25519 signature
}</pre>
<div style="${t.h3}" id="dashboard-seg">Dashboard Segment</div>
<pre style="${t.code}">DashboardHeader (64 bytes):
magic: 0x5256_4442 // "RVDB"
version: u16
framework: u8 // 0=threejs, 1=react
compression: u8 // 0=none, 1=gzip, 2=brotli
bundle_size: u64
file_count: u32
hash: [u8; 32] // SHAKE-256 of bundle
Payload: [file_table] [file_data...]</pre>
<!-- ============ GLOSSARY ============ -->
<div style="${t.h2}" id="glossary">Glossary</div>
<div style="display:grid;grid-template-columns:130px 1fr;gap:1px 14px;font-size:12px;line-height:2">
${this.glossaryRow("RVF","RuVector Format &mdash; the binary container")}
${this.glossaryRow("Segment","A typed block of data inside an RVF file")}
${this.glossaryRow("Witness Chain","Linked list of signed hash entries proving integrity")}
${this.glossaryRow("SHAKE-256","Cryptographic hash function (variable output)")}
${this.glossaryRow("Ed25519","Digital signature algorithm for witness entries")}
${this.glossaryRow("KOI","Kepler Object of Interest &mdash; exoplanet candidate")}
${this.glossaryRow("ESI","Earth Similarity Index (0-1, higher = more Earth-like)")}
${this.glossaryRow("Transit","Planet passing in front of its star, causing a brightness dip")}
${this.glossaryRow("Light Curve","Graph of stellar brightness over time")}
${this.glossaryRow("Habitable Zone","Orbital region where liquid water could exist")}
${this.glossaryRow("Thompson Samp.","Bandit algorithm balancing exploration vs exploitation")}
${this.glossaryRow("eBPF","Extended Berkeley Packet Filter &mdash; fast kernel programs")}
${this.glossaryRow("WASM","WebAssembly &mdash; portable code that runs in browsers")}
${this.glossaryRow("Dyson Sphere","Hypothetical megastructure around a star for energy")}
${this.glossaryRow("IR Excess","More infrared than expected &mdash; possible artificial origin")}
${this.glossaryRow("SED","Spectral Energy Distribution &mdash; brightness vs wavelength")}
${this.glossaryRow("Coherence","Self-consistency measure of data in a region")}
${this.glossaryRow("Acceptance","Three-mode validation (A/B/C) of solver quality")}
${this.glossaryRow("Blind Test","Evaluation on unlabeled data to prevent overfitting")}
</div>
<div style="margin-top:48px;padding-top:16px;border-top:1px solid var(--border);font-size:11px;color:var(--text-muted);text-align:center">
Everything in this dashboard was served from a single <code style="${t.inline}">.rvf</code> file.
</div>
`}statCard(t,e,i){return`<div style="${i.card}padding:10px 12px;text-align:center">
<div style="font-size:9px;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.4px;margin-bottom:2px">${t}</div>
<div style="font-size:12px;font-weight:600;color:var(--accent);font-family:var(--font-mono)">${e}</div>
</div>`}segRow(t,e,i){return`<div style="display:flex;align-items:center;gap:10px"><span style="color:${i};min-width:160px;font-weight:600">${t}</span><span style="color:var(--text-secondary);font-weight:400">${e}</span></div>`}uniqueCard(t,e,i){return`<div style="${i.card}"><div style="font-size:12px;${i.accent}margin-bottom:4px">${t}</div><div style="font-size:11px;line-height:1.5">${e}</div></div>`}viewCard(t,e,i,s,a,n){const o=n.map(r=>`<span style="font-size:9px;padding:2px 6px;border-radius:3px;background:rgba(0,229,255,0.06);border:1px solid rgba(0,229,255,0.1);color:var(--accent)">${r}</span>`).join("");return`<div id="${t}" style="background:var(--bg-panel);border:1px solid var(--border);border-radius:6px;padding:12px 16px;margin-bottom:8px;border-left:3px solid ${s}">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:4px">
<span style="font-size:12px;font-weight:600;color:var(--text-primary)">${e}</span>
<a href="${i}" style="font-size:10px;color:${s};font-family:var(--font-mono);text-decoration:none">${i}</a>
</div>
<div style="font-size:11px;line-height:1.5;margin-bottom:6px">${a}</div>
<div style="display:flex;flex-wrap:wrap;gap:3px">${o}</div>
</div>`}tableRow(t,e,i){return`<tr style="border-bottom:1px solid var(--border-subtle)"><td style="padding:5px 8px;color:var(--accent)">${t}</td><td style="padding:5px 8px;color:var(--text-primary)">${e}</td><td style="padding:5px 8px">${i}</td></tr>`}glossaryRow(t,e){return`<span style="color:var(--accent);font-weight:600">${t}</span><span>${e}</span>`}}const ht="2.0.0",Qt="https://storage.googleapis.com/ruvector-releases",qs=[{platform:"Windows",icon:'<svg viewBox="0 0 24 24" width="28" height="28" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="3" width="8" height="8"/><rect x="13" y="3" width="8" height="8"/><rect x="3" y="13" width="8" height="8"/><rect x="13" y="13" width="8" height="8"/></svg>',file:`ruvector-${ht}-x64.exe`,size:"~12 MB",ext:".exe",desc:"Windows 10/11 (x64) installer with bundled WASM runtime"},{platform:"macOS",icon:'<svg viewBox="0 0 24 24" width="28" height="28" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2z"/><path d="M15 8.5c0-1-0.67-2.5-2-2.5S11 7.5 11 8.5c0 1.5 1 2 1 3.5s-1 2-1 3.5c0 1 0.67 2.5 2 2.5s2-1.5 2-2.5c0-1.5-1-2-1-3.5s1-2 1-3.5z"/></svg>',file:`RuVector-${ht}.dmg`,size:"~14 MB",ext:".dmg",desc:"macOS 12+ (Apple Silicon & Intel) disk image"},{platform:"Linux",icon:'<svg viewBox="0 0 24 24" width="28" height="28" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="12" r="9"/><path d="M12 3v18M3 12h18"/><circle cx="12" cy="8" r="1.5"/></svg>',file:`ruvector-${ht}-linux-x64.tar.gz`,size:"~10 MB",ext:".tar.gz",desc:"Linux (x86_64) tarball Ubuntu 20+, Debian 11+, Fedora 36+"}];class Ks{constructor(){this.container=null}mount(t){this.container=t;const e=document.createElement("div");e.style.cssText="max-width:960px;margin:0 auto;padding:32px 24px;overflow-y:auto;height:100%",t.appendChild(e);const i=document.createElement("div");i.style.cssText="text-align:center;margin-bottom:40px",i.innerHTML=`
<div style="display:inline-flex;align-items:center;gap:12px;margin-bottom:16px">
<svg viewBox="0 0 24 24" width="40" height="40" fill="none" stroke="#00E5FF" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="6"/><ellipse cx="12" cy="12" rx="11" ry="4" transform="rotate(-20 12 12)"/>
<circle cx="12" cy="12" r="1.5" fill="#00E5FF" stroke="none"/>
</svg>
<span style="font-size:28px;font-weight:300;color:var(--text-primary);letter-spacing:2px">RuVector</span>
</div>
<div style="font-size:14px;color:var(--text-secondary);line-height:1.6;max-width:600px;margin:0 auto">
Download the Causal Atlas runtime a single binary that reads <code style="color:var(--accent);font-size:12px">.rvf</code> files,
runs the WASM solver, serves the Three.js dashboard, and verifies the Ed25519 witness chain.
</div>
<div style="margin-top:12px;display:flex;gap:8px;justify-content:center;flex-wrap:wrap">
<span style="font-size:10px;padding:3px 8px;border-radius:4px;background:rgba(0,229,255,0.08);border:1px solid rgba(0,229,255,0.15);color:#00E5FF">v${ht}</span>
<span style="font-size:10px;padding:3px 8px;border-radius:4px;background:rgba(46,204,113,0.08);border:1px solid rgba(46,204,113,0.15);color:#2ECC71">Stable</span>
<span style="font-size:10px;padding:3px 8px;border-radius:4px;background:rgba(255,176,32,0.08);border:1px solid rgba(255,176,32,0.15);color:#FFB020">ADR-040</span>
</div>
`,e.appendChild(i);const s=document.createElement("div");s.style.cssText="display:grid;grid-template-columns:repeat(auto-fit, minmax(280px, 1fr));gap:16px;margin-bottom:40px",e.appendChild(s);for(const r of qs){const l=document.createElement("div");l.style.cssText=`
background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;
padding:20px;display:flex;flex-direction:column;gap:12px;
transition:border-color 0.2s,transform 0.2s;cursor:pointer;
`,l.addEventListener("mouseenter",()=>{l.style.borderColor="rgba(0,229,255,0.3)",l.style.transform="translateY(-2px)"}),l.addEventListener("mouseleave",()=>{l.style.borderColor="var(--border)",l.style.transform=""}),l.innerHTML=`
<div style="display:flex;align-items:center;gap:12px">
<div style="color:#00E5FF">${r.icon}</div>
<div>
<div style="font-size:15px;font-weight:600;color:var(--text-primary)">${r.platform}</div>
<div style="font-size:10px;color:var(--text-muted)">${r.size}</div>
</div>
</div>
<div style="font-size:11px;color:var(--text-secondary);line-height:1.5">${r.desc}</div>
<div style="font-family:var(--font-mono);font-size:10px;color:var(--text-muted);padding:6px 8px;background:rgba(0,0,0,0.3);border-radius:4px;word-break:break-all">${r.file}</div>
<a href="${Qt}/v${ht}/${r.file}" style="
display:flex;align-items:center;justify-content:center;gap:6px;
padding:8px 16px;border-radius:6px;text-decoration:none;
background:rgba(0,229,255,0.1);border:1px solid rgba(0,229,255,0.25);
color:#00E5FF;font-size:12px;font-weight:600;transition:background 0.15s;
" onmouseenter="this.style.background='rgba(0,229,255,0.2)'" onmouseleave="this.style.background='rgba(0,229,255,0.1)'">
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
Download ${r.ext}
</a>
`,s.appendChild(l)}const a=document.createElement("div");a.style.cssText="margin-bottom:40px",a.innerHTML=`
<div style="font-size:13px;font-weight:600;color:var(--text-primary);margin-bottom:16px;display:flex;align-items:center;gap:8px">
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M9 21V9"/></svg>
npm Packages &amp; WASM Module
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px">
<div style="background:var(--bg-surface);border:1px solid var(--border);border-radius:6px;padding:14px">
<div style="font-size:11px;font-weight:600;color:var(--text-primary);margin-bottom:6px">rvf-solver (npm)</div>
<code style="display:block;font-size:10px;color:var(--accent);background:rgba(0,0,0,0.3);padding:8px;border-radius:4px;margin-bottom:6px">npm install @ruvector/rvf-solver</code>
<div style="font-size:10px;color:var(--text-muted);line-height:1.4">NAPI-RS native bindings for Node.js includes solver, witness chain, and policy kernel.</div>
</div>
<div style="background:var(--bg-surface);border:1px solid var(--border);border-radius:6px;padding:14px">
<div style="font-size:11px;font-weight:600;color:var(--text-primary);margin-bottom:6px">rvf-solver-wasm (npm)</div>
<code style="display:block;font-size:10px;color:var(--accent);background:rgba(0,0,0,0.3);padding:8px;border-radius:4px;margin-bottom:6px">npm install @ruvector/rvf-solver-wasm</code>
<div style="font-size:10px;color:var(--text-muted);line-height:1.4">Browser WASM module same solver running in this dashboard. No native dependencies.</div>
</div>
<div style="background:var(--bg-surface);border:1px solid var(--border);border-radius:6px;padding:14px">
<div style="font-size:11px;font-weight:600;color:var(--text-primary);margin-bottom:6px">Standalone WASM</div>
<code style="display:block;font-size:10px;color:var(--accent);background:rgba(0,0,0,0.3);padding:8px;border-radius:4px;margin-bottom:6px">curl -O ${Qt}/v${ht}/rvf_solver_wasm.wasm</code>
<div style="font-size:10px;color:var(--text-muted);line-height:1.4">Raw <code>.wasm</code> binary (172 KB). Load via WebAssembly.instantiate() no wasm-bindgen needed.</div>
</div>
<div style="background:var(--bg-surface);border:1px solid var(--border);border-radius:6px;padding:14px">
<div style="font-size:11px;font-weight:600;color:var(--text-primary);margin-bottom:6px">Cargo Crate</div>
<code style="display:block;font-size:10px;color:var(--accent);background:rgba(0,0,0,0.3);padding:8px;border-radius:4px;margin-bottom:6px">cargo add rvf-runtime rvf-types rvf-crypto</code>
<div style="font-size:10px;color:var(--text-muted);line-height:1.4">Rust workspace crates for embedding RVF files in your own applications.</div>
</div>
</div>
`,e.appendChild(a);const n=document.createElement("div");n.style.cssText="margin-bottom:40px",n.innerHTML=`
<div style="font-size:13px;font-weight:600;color:var(--text-primary);margin-bottom:16px;display:flex;align-items:center;gap:8px">
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.5"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>
Quick Start
</div>
<div style="background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;padding:20px">
<div style="display:grid;gap:16px">
${this.step(1,"Download","Download the installer for your platform above and run it.")}
${this.step(2,"Open an RVF file",`
<code style="display:block;font-size:11px;color:var(--accent);background:rgba(0,0,0,0.3);padding:8px;border-radius:4px;margin-top:4px">ruvector open causal_atlas.rvf</code>
<div style="font-size:10px;color:var(--text-muted);margin-top:4px">This starts the local server and opens the dashboard in your browser.</div>
`)}
${this.step(3,"Train the solver","Navigate to the Solver page and click Train or Auto-Optimize. The WASM solver learns in real time inside your browser.")}
${this.step(4,"Run acceptance test","Click Acceptance to verify the solver passes the three-mode acceptance test (A/B/C). All results are recorded in the Ed25519 witness chain.")}
${this.step(5,"Explore discoveries","Navigate to Planets, Life, and Discover pages to explore candidate detections. Each candidate includes a full causal trace and witness proof.")}
</div>
</div>
`,e.appendChild(n);const o=document.createElement("div");o.innerHTML=`
<div style="font-size:13px;font-weight:600;color:var(--text-primary);margin-bottom:16px;display:flex;align-items:center;gap:8px">
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="4" y="4" width="16" height="16" rx="2"/><line x1="4" y1="9" x2="20" y2="9"/><circle cx="8" cy="6.5" r="0.5" fill="currentColor" stroke="none"/></svg>
System Requirements
</div>
<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:12px;font-size:11px">
<div style="background:var(--bg-surface);border:1px solid var(--border);border-radius:6px;padding:12px">
<div style="font-weight:600;color:var(--text-primary);margin-bottom:6px">Windows</div>
<div style="color:var(--text-muted);line-height:1.5">Windows 10 (1903+)<br>x64 processor<br>4 GB RAM<br>100 MB disk</div>
</div>
<div style="background:var(--bg-surface);border:1px solid var(--border);border-radius:6px;padding:12px">
<div style="font-weight:600;color:var(--text-primary);margin-bottom:6px">macOS</div>
<div style="color:var(--text-muted);line-height:1.5">macOS 12 Monterey+<br>Apple Silicon or Intel<br>4 GB RAM<br>100 MB disk</div>
</div>
<div style="background:var(--bg-surface);border:1px solid var(--border);border-radius:6px;padding:12px">
<div style="font-weight:600;color:var(--text-primary);margin-bottom:6px">Linux</div>
<div style="color:var(--text-muted);line-height:1.5">glibc 2.31+<br>x86_64 processor<br>4 GB RAM<br>100 MB disk</div>
</div>
</div>
<div style="font-size:9px;color:var(--text-muted);margin-top:12px;text-align:center">
Binaries are hosted on Google Cloud Storage. All downloads include Ed25519 signatures for verification.
</div>
`,e.appendChild(o)}step(t,e,i){return`
<div style="display:flex;gap:12px;align-items:flex-start">
<div style="min-width:24px;height:24px;border-radius:50%;background:rgba(0,229,255,0.1);border:1px solid rgba(0,229,255,0.25);display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:700;color:#00E5FF">${t}</div>
<div style="flex:1">
<div style="font-size:12px;font-weight:600;color:var(--text-primary);margin-bottom:2px">${e}</div>
<div style="font-size:11px;color:var(--text-secondary);line-height:1.5">${i}</div>
</div>
</div>
`}unmount(){this.container=null}}const te={"#/atlas":ss,"#/coherence":os,"#/boundaries":rs,"#/memory":ls,"#/planets":us,"#/life":ys,"#/witness":ws,"#/solver":_s,"#/blind-test":Ps,"#/discover":Hs,"#/dyson":js,"#/status":Ls,"#/download":Ks,"#/docs":Vs};let Et=null;function Us(){const p=document.getElementById("app");if(!p)throw new Error("Missing #app container");return p}function Ys(){const p=location.hash||"#/atlas";document.querySelectorAll("#nav-rail a").forEach(t=>{const e=t;e.classList.toggle("active",e.getAttribute("href")===p)})}function ee(p){const t=Us();Et&&(Et.unmount(),Et=null),t.innerHTML="";const e=te[p]||te["#/atlas"],i=new e;i.mount(t),Et=i,Ys()}async function se(){const p=document.getElementById("root-hash"),t=document.querySelector("#top-bar .dot"),e=document.getElementById("pipeline-status");if(p)try{const i=await ue(),s=(i.file_size*1575931494+i.segments>>>0).toString(16).padStart(8,"0");p.textContent=`0x${s.substring(0,4)}...${s.substring(4,8)}`,t&&(t.style.background="#2ECC71"),e&&(e.textContent="LIVE",e.style.color="#2ECC71")}catch{p.textContent="0x----...----",t&&(t.style.background="#FF4D4D"),e&&(e.textContent="OFFLINE",e.style.color="#FF4D4D")}}function Zs(){Je();const p=location.hash||"#/atlas";location.hash||(location.hash="#/atlas"),ee(p),window.addEventListener("hashchange",()=>{ee(location.hash)}),window.addEventListener("beforeunload",()=>{Qe()}),se(),setInterval(se,1e4)}document.addEventListener("DOMContentLoaded",Zs);