diff --git a/nvsim/assets/index-C2Z9YIJa.js b/nvsim/assets/index-C2Z9YIJa.js
new file mode 100644
index 00000000..63c7db73
--- /dev/null
+++ b/nvsim/assets/index-C2Z9YIJa.js
@@ -0,0 +1,1402 @@
+import{f as Ge,u as Ye,i as m,a as b,b as c,w as U}from"./lit-BS7WqYd5.js";import{y as o,g as Xe,j as x}from"./signals-SG45zFCj.js";(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const a of document.querySelectorAll('link[rel="modulepreload"]'))r(a);new MutationObserver(a=>{for(const i of a)if(i.type==="childList")for(const n of i.addedNodes)n.tagName==="LINK"&&n.rel==="modulepreload"&&r(n)}).observe(document,{childList:!0,subtree:!0});function s(a){const i={};return a.integrity&&(i.integrity=a.integrity),a.referrerPolicy&&(i.referrerPolicy=a.referrerPolicy),a.crossOrigin==="use-credentials"?i.credentials="include":a.crossOrigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function r(a){if(a.ep)return;a.ep=!0;const i=s(a);fetch(a.href,i)}})();/**
+ * @license
+ * Copyright 2017 Google LLC
+ * SPDX-License-Identifier: BSD-3-Clause
+ */const h=e=>(t,s)=>{s!==void 0?s.addInitializer(()=>{customElements.define(e,t)}):customElements.define(e,t)};/**
+ * @license
+ * Copyright 2017 Google LLC
+ * SPDX-License-Identifier: BSD-3-Clause
+ */const Je={attribute:!0,type:String,converter:Ye,reflect:!1,hasChanged:Ge},Qe=(e=Je,t,s)=>{const{kind:r,metadata:a}=s;let i=globalThis.litPropertyMetadata.get(a);if(i===void 0&&globalThis.litPropertyMetadata.set(a,i=new Map),r==="setter"&&((e=Object.create(e)).wrapped=!0),i.set(s.name,e),r==="accessor"){const{name:n}=s;return{set(d){const p=t.get.call(this);t.set.call(this,d),this.requestUpdate(n,p,e,!0,d)},init(d){return d!==void 0&&this.C(n,void 0,e,d),d}}}if(r==="setter"){const{name:n}=s;return function(d){const p=this[n];t.call(this,d),this.requestUpdate(n,p,e,!0,d)}}throw Error("Unsupported decorator location: "+r)};function De(e){return(t,s)=>typeof s=="object"?Qe(e,t,s):((r,a,i)=>{const n=a.hasOwnProperty(i);return a.constructor.createProperty(i,r),n?Object.getOwnPropertyDescriptor(a,i):void 0})(e,t,s)}/**
+ * @license
+ * Copyright 2017 Google LLC
+ * SPDX-License-Identifier: BSD-3-Clause
+ */function u(e){return De({...e,state:!0,attribute:!1})}/**
+ * @license
+ * Copyright 2017 Google LLC
+ * SPDX-License-Identifier: BSD-3-Clause
+ */const Ze=(e,t,s)=>(s.configurable=!0,s.enumerable=!0,Reflect.decorate&&typeof t!="object"&&Object.defineProperty(e,t,s),s);/**
+ * @license
+ * Copyright 2017 Google LLC
+ * SPDX-License-Identifier: BSD-3-Clause
+ */function Ie(e,t){return(s,r,a)=>{const i=n=>n.renderRoot?.querySelector(e)??null;return Ze(s,r,{get(){return i(this)}})}}var et=Object.defineProperty,tt=Object.getOwnPropertyDescriptor,Le=(e,t,s,r)=>{for(var a=r>1?void 0:r?tt(t,s):t,i=e.length-1,n;i>=0;i--)(n=e[i])&&(a=(r?n(t,s,a):n(a))||a);return r&&a&&et(t,s,a),a};let ie=class extends b{constructor(){super(...arguments),this.view="scene"}navigate(e){this.dispatchEvent(new CustomEvent("navigate",{detail:e}))}render(){return c`
+
NV
+ this.navigate("scene")}>
+
+
+ this.navigate("apps")}>
+
+
+ this.navigate("scene")}>
+
+
+
+
+
+
+ this.dispatchEvent(new CustomEvent("open-settings",{bubbles:!0,composed:!0}))}>
+
+
+ `}};ie.styles=m`
+ :host {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 10px 0;
+ gap: 4px;
+ background: var(--bg-1);
+ border-right: 1px solid var(--line);
+ }
+ .logo {
+ width: 36px; height: 36px;
+ border-radius: 10px;
+ background: linear-gradient(135deg, oklch(0.78 0.14 70) 0%, oklch(0.55 0.16 30) 100%);
+ display: grid; place-items: center;
+ color: #1a0f00;
+ font-weight: 700;
+ font-family: var(--mono);
+ font-size: 11px;
+ margin-bottom: 14px;
+ box-shadow: 0 4px 12px -2px oklch(0.55 0.16 30 / 0.35);
+ }
+ .btn {
+ width: 36px; height: 36px;
+ border-radius: 8px;
+ background: transparent;
+ border: 1px solid transparent;
+ color: var(--ink-3);
+ display: grid; place-items: center;
+ transition: all 0.15s;
+ position: relative;
+ cursor: pointer;
+ }
+ .btn:hover { color: var(--ink); background: var(--bg-2); }
+ .btn.active {
+ color: var(--ink);
+ background: var(--bg-3);
+ border-color: var(--line-2);
+ }
+ .btn.active::before {
+ content: ''; position: absolute; left: -10px; top: 8px; bottom: 8px;
+ width: 2px; background: var(--accent); border-radius: 2px;
+ }
+ .spacer { flex: 1; }
+ svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.8; }
+ `;Le([De()],ie.prototype,"view",2);ie=Le([h("nv-rail")],ie);const _=o("wasm"),ye=o("");o(!1);o(null);const v=o(!1);o(!0);o(1);const at=o(0),$e=o(0n),q=o(0xCAFEBABEn),Q=o(1e4),Z=o(1e3),ee=o(1),te=o(!0),g=o("dark"),w=o("default"),$=o(!1),ae=o(!0),ne=o([0,0,0]),D=o(0),T=o(0),k=o(0),C=o(""),f=o("idle"),I=o(""),_e=o(null),oe=o([]),le=o([]),ce=o([]),de=o([]),ze=o("rebar-walkby-01"),st=o(""),N=o(!1),we=o("all"),Ae=Xe(()=>_.value==="wasm"?"wasm":"ws");let Fe=null;function rt(e){Fe=e}function P(){return Fe}const S=o([]),it=200;function l(e,t){if(N.value)return;const s=S.value.slice();for(s.push({ts:Date.now(),level:e,msg:t});s.length>it;)s.shift();S.value=s}function nt(e){const s=oe.value.slice();s.push(e[0]),s.length>200&&s.shift();const r=le.value.slice();r.push(e[1]),r.length>200&&r.shift();const a=ce.value.slice();a.push(e[2]),a.length>200&&a.shift(),oe.value=s,le.value=r,ce.value=a}function ot(e){const s=de.value.slice();for(s.push(Math.max(0,Math.min(1,e)));s.length>48;)s.shift();de.value=s}var lt=Object.getOwnPropertyDescriptor,ct=(e,t,s,r)=>{for(var a=r>1?void 0:r?lt(t,s):t,i=e.length-1,n;i>=0;i--)(n=e[i])&&(a=n(a)||a);return a};let Se=class extends b{connectedCallback(){super.connectedCallback(),x(()=>{k.value,Ae.value,q.value,g.value,ze.value,v.value,this.requestUpdate()})}async toggleRun(){const e=P();e&&(v.value?(await e.pause(),v.value=!1):(await e.run(),v.value=!0))}async reset(){const e=P();e&&await e.reset()}toggleTheme(){g.value=g.value==="dark"?"light":"dark"}render(){const e=q.value.toString(16).toUpperCase().padStart(8,"0");return c`
+
+ RuView /
+ nvsim /
+ ${ze.value}
+
+
+
+
+ ${k.value>0?(k.value/1e3).toFixed(2)+" kHz":"idle"}
+
+ ${Ae.value}
+ seed: 0x${e}
+
+ ${g.value==="dark"?"☼":"☾"}
+
+ ↺ Reset
+
+ ${v.value?"❚❚ Pause":"▶ Run"}
+
+ `}};Se.styles=m`
+ :host {
+ display: flex; align-items: center;
+ padding: 0 16px; gap: 12px;
+ background: var(--bg-1);
+ border-bottom: 1px solid var(--line);
+ z-index: 10;
+ }
+ .crumbs { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--ink-3); }
+ .crumbs .sep { color: var(--ink-4); }
+ .crumbs .cur { color: var(--ink); font-weight: 500; }
+ .spacer { flex: 1; }
+ .pill {
+ display: inline-flex; align-items: center; gap: 6px;
+ padding: 5px 10px;
+ background: var(--bg-2); border: 1px solid var(--line);
+ border-radius: 999px;
+ font-size: 12px; color: var(--ink-2);
+ font-family: var(--mono); font-weight: 500;
+ }
+ .pill .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--ok); box-shadow: 0 0 6px var(--ok); animation: pulse 2s infinite; }
+ .pill.wasm .dot { background: var(--accent-2); box-shadow: 0 0 6px var(--accent-2); }
+ .pill.seed { color: var(--ink-3); }
+ .pill.seed b { color: var(--accent); font-weight: 600; }
+ button {
+ display: inline-flex; align-items: center; gap: 6px;
+ padding: 6px 12px;
+ background: var(--bg-2); border: 1px solid var(--line);
+ border-radius: 8px;
+ font-size: 12.5px; font-weight: 500; color: var(--ink);
+ cursor: pointer;
+ transition: all 0.15s;
+ }
+ button:hover { border-color: var(--line-2); background: var(--bg-3); }
+ button.primary { background: var(--accent); border-color: var(--accent); color: #1a0f00; }
+ button.primary:hover { filter: brightness(1.08); }
+ button.ghost { background: transparent; }
+ `;Se=ct([h("nv-topbar")],Se);var dt=Object.getOwnPropertyDescriptor,pt=(e,t,s,r)=>{for(var a=r>1?void 0:r?dt(t,s):t,i=e.length-1,n;i>=0;i--)(n=e[i])&&(a=n(a)||a);return a};let Ce=class extends b{connectedCallback(){super.connectedCallback(),x(()=>{Q.value,Z.value,ee.value,te.value,v.value,this.requestUpdate()})}render(){return c`
+
+
Scene 4 sources
+
+
+ rebar.steel.coil
+ χ=5000
+
+
+
+ heart_proxy
+ 1e-6 A·m²
+
+
+
+ mains_60Hz
+ 2 A · 60 Hz
+
+
+
+ door.steel
+ eddy
+
+
+
+
+
NV sensor COTS
+
V 1 mm³
+
N 1e12 NV
+
C 0.030
+
T₂* 200 ns
+
δB 1.18 pT/√Hz
+
+
+
+
Tunables
+
+
Sample rate ${(Q.value/1e3).toFixed(1)} kHz
+
Q.value=+e.target.value} />
+
+
+
Lockin f_mod ${(Z.value/1e3).toFixed(3)} kHz
+
Z.value=+e.target.value} />
+
+
+
Integration t ${ee.value.toFixed(1)} ms
+
ee.value=+e.target.value} />
+
+
+
Shot noise ${te.value?"ON":"OFF"}
+
te.value=e.target.value==="1"} />
+
+
+
+
+
Pipeline
+
+ scene
+ →
+ B-S
+ →
+ prop
+ →
+ NV
+ →
+ ADC
+ →
+ frame
+
+
+ `}};Ce.styles=m`
+ :host {
+ display: flex; flex-direction: column; gap: 14px;
+ padding: 14px; overflow-y: auto;
+ background: var(--bg-1); border-right: 1px solid var(--line);
+ }
+ .panel {
+ background: var(--bg-2); border: 1px solid var(--line);
+ border-radius: var(--radius); padding: 12px;
+ }
+ .panel-h {
+ display: flex; align-items: center; justify-content: space-between;
+ font-size: 11px; font-weight: 600; color: var(--ink-3);
+ text-transform: uppercase; letter-spacing: 0.08em;
+ margin-bottom: 10px;
+ }
+ .count {
+ background: var(--bg-3); color: var(--ink-2);
+ padding: 1px 6px; border-radius: 999px;
+ font-family: var(--mono); font-size: 10px;
+ text-transform: none; letter-spacing: 0;
+ }
+ .scene-item {
+ display: flex; align-items: center; gap: 10px;
+ padding: 8px 10px;
+ border-radius: var(--radius-sm);
+ cursor: pointer;
+ transition: background 0.15s;
+ border: 1px solid transparent;
+ }
+ .scene-item:hover { background: var(--bg-3); }
+ .scene-item .swatch { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
+ .scene-item .name { font-size: 13px; flex: 1; }
+ .scene-item .meta { font-family: var(--mono); font-size: 10.5px; color: var(--ink-3); }
+ .field-row {
+ display: flex; align-items: center; justify-content: space-between;
+ padding: 6px 0; font-size: 12.5px;
+ border-bottom: 1px solid var(--line);
+ }
+ .field-row:last-child { border-bottom: 0; }
+ .field-row .lbl { color: var(--ink-3); }
+ .field-row .val { font-family: var(--mono); color: var(--ink); font-size: 12px; }
+ .slider-row { padding: 8px 0; border-bottom: 1px solid var(--line); }
+ .slider-row:last-child { border-bottom: 0; padding-bottom: 0; }
+ .slider-row .top { display: flex; justify-content: space-between; margin-bottom: 6px; font-size: 12px; }
+ .slider-row .top .lbl { color: var(--ink-3); }
+ .slider-row .top .val { font-family: var(--mono); color: var(--ink); }
+ input[type="range"] {
+ -webkit-appearance: none; appearance: none;
+ width: 100%; height: 4px;
+ background: var(--bg-3); border-radius: 2px; outline: none;
+ }
+ input[type="range"]::-webkit-slider-thumb {
+ -webkit-appearance: none; appearance: none;
+ width: 14px; height: 14px; border-radius: 50%;
+ background: var(--accent); cursor: pointer;
+ border: 2px solid var(--bg-2);
+ box-shadow: 0 0 0 1px var(--line-2);
+ }
+ .pipeline { display: flex; gap: 4px; align-items: center; flex-wrap: wrap; margin-top: 6px; }
+ .stage {
+ flex: 1; min-width: 50px;
+ padding: 4px 6px;
+ background: var(--bg-3); border: 1px solid var(--line);
+ border-radius: 6px; font-size: 9.5px; text-align: center;
+ color: var(--ink-2); font-family: var(--mono);
+ }
+ .stage.live { border-color: var(--accent-2); color: var(--accent-2); }
+ .stage-arrow { color: var(--ink-4); font-size: 10px; }
+ `;Ce=pt([h("nv-sidebar")],Ce);var ut=Object.defineProperty,vt=Object.getOwnPropertyDescriptor,be=(e,t,s,r)=>{for(var a=r>1?void 0:r?vt(t,s):t,i=e.length-1,n;i>=0;i--)(n=e[i])&&(a=(r?n(t,s,a):n(a))||a);return r&&a&&ut(t,s,a),a};let L=class extends b{constructor(){super(...arguments),this.items=[{id:"rebar",x:740,y:240,color:"oklch(0.72 0.18 330)",name:"rebar.steel"},{id:"heart",x:220,y:180,color:"oklch(0.78 0.14 195)",name:"heart_proxy"},{id:"mains",x:180,y:380,color:"oklch(0.72 0.18 330)",name:"mains_60Hz"},{id:"door",x:800,y:470,color:"oklch(0.78 0.14 145)",name:"door.steel"}],this.dragging=null,this.selected=null,this.dragOffset={dx:0,dy:0},this.onDown=(e,t)=>{t.preventDefault(),this.dragging=e,this.selected=e;const s=this.items.find(i=>i.id===e);if(!s)return;const r=this.renderRoot.querySelector("svg");if(!r)return;const a=this.toSvg(t,r);this.dragOffset={dx:a.x-s.x,dy:a.y-s.y}},this.onPointerMove=e=>{if(!this.dragging)return;const t=this.renderRoot.querySelector("svg");if(!t)return;const s=this.toSvg(e,t);this.items=this.items.map(r=>r.id===this.dragging?{...r,x:s.x-this.dragOffset.dx,y:s.y-this.dragOffset.dy}:r)},this.onPointerUp=()=>{this.dragging=null}}connectedCallback(){super.connectedCallback(),x(()=>{ne.value,D.value,k.value,T.value,$.value,this.requestUpdate()}),window.addEventListener("pointermove",this.onPointerMove),window.addEventListener("pointerup",this.onPointerUp)}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("pointermove",this.onPointerMove),window.removeEventListener("pointerup",this.onPointerUp)}toSvg(e,t){const s=t.getBoundingClientRect(),r=(e.clientX-s.left)/s.width*1e3,a=(e.clientY-s.top)/s.height*600;return{x:r,y:a}}render(){const e=ne.value,t=[e[0]*1e9,e[1]*1e9,e[2]*1e9],s=D.value*1e9,r=$.value?"":"anim";return c`
+
+
+
+
+
+
+
+
+
+
+
+ ${this.items.map(a=>U`
+
+ `)}
+
+
+ ${this.items.map(a=>U`
+ this.onDown(a.id,i)}>
+
+
+ ${a.name}
+
+ `)}
+
+
+
+
+
+
+
+
+
+ sensor · 〈111〉 NV
+
+
+ B_in: [${t[0].toFixed(2)}, ${t[1].toFixed(2)}, ${t[2].toFixed(2)}] nT
+
+
+
+
+
+
+
|B|
+
${s.toFixed(3)} nT
+
+
+
FPS
+
${k.value>0?Math.round(k.value):"—"}
+
+
+
SNR
+
${T.value>0?T.value.toFixed(1):"—"}
+
+
+ `}};L.styles=m`
+ :host {
+ display: block; height: 100%; width: 100%;
+ background: radial-gradient(ellipse at 50% 30%, var(--bg-2) 0%, var(--bg-0) 70%);
+ position: relative; overflow: hidden;
+ border-bottom: 1px solid var(--line);
+ }
+ .grid {
+ position: absolute; inset: 0;
+ background-image:
+ linear-gradient(var(--grid) 1px, transparent 1px),
+ linear-gradient(90deg, var(--grid) 1px, transparent 1px);
+ background-size: 32px 32px;
+ pointer-events: none;
+ mask-image: radial-gradient(ellipse at center, black 40%, transparent 100%);
+ }
+ svg { position: absolute; inset: 0; width: 100%; height: 100%; }
+ .stat-card {
+ background: rgba(13,17,23,0.7);
+ backdrop-filter: blur(8px);
+ border: 1px solid var(--line);
+ border-radius: var(--radius-sm);
+ padding: 8px 12px;
+ font-size: 11px;
+ min-width: 96px;
+ }
+ [data-theme="light"] .stat-card { background: rgba(255,255,255,0.85); }
+ .stat-card .lbl {
+ color: var(--ink-3);
+ text-transform: uppercase; font-weight: 600; letter-spacing: 0.06em; font-size: 9.5px;
+ }
+ .stat-card .val { font-family: var(--mono); font-size: 16px; font-weight: 600; margin-top: 2px; }
+ .stat-card .val.amber { color: var(--accent); }
+ .stat-card .val.cyan { color: var(--accent-2); }
+ .stat-card .val.mint { color: var(--accent-4); }
+ .scene-readout {
+ position: absolute; top: 14px; right: 14px;
+ display: flex; gap: 8px; z-index: 5;
+ }
+ .draggable { cursor: grab; transition: filter 0.15s; }
+ .draggable:hover { filter: brightness(1.15) drop-shadow(0 0 6px currentColor); }
+ .draggable.dragging { cursor: grabbing; filter: brightness(1.25) drop-shadow(0 0 10px currentColor); }
+ .field-line { stroke-dasharray: 4 6; }
+ @keyframes dash { to { stroke-dashoffset: -200; } }
+ .field-line.anim { animation: dash 4s linear infinite; }
+ @keyframes spin {
+ 0% { transform: rotateY(0) rotateX(8deg); }
+ 100% { transform: rotateY(360deg) rotateX(8deg); }
+ }
+ .crystal { transform-origin: center; transform-box: fill-box; }
+ .crystal.anim { animation: spin 12s linear infinite; }
+ .label {
+ font-family: var(--mono); font-size: 11px; fill: var(--ink-2);
+ pointer-events: none;
+ }
+ `;be([u()],L.prototype,"items",2);be([u()],L.prototype,"dragging",2);be([u()],L.prototype,"selected",2);L=be([h("nv-scene")],L);var gt=Object.defineProperty,mt=Object.getOwnPropertyDescriptor,Re=(e,t,s,r)=>{for(var a=r>1?void 0:r?mt(t,s):t,i=e.length-1,n;i>=0;i--)(n=e[i])&&(a=(r?n(t,s,a):n(a))||a);return r&&a&>(t,s,a),a};let pe=class extends b{constructor(){super(...arguments),this.tab="signal"}connectedCallback(){super.connectedCallback(),x(()=>{oe.value,le.value,ce.value,de.value,_e.value,C.value,f.value,ne.value,D.value,this.requestUpdate()})}async verify(){const e=P();if(e){f.value="pending",l("info","verifying witness over 256 frames…");try{const t=I.value,s=new Uint8Array(32);for(let a=0;a<32;a++)s[a]=parseInt(t.slice(a*2,a*2+2),16);const r=await e.verifyWitness(s);if(r.ok)f.value="ok",C.value=t,l("ok",`witness ${t.slice(0,16)}… matches · determinism gate ✓`);else{f.value="fail";const a=Array.from(r.actual).map(i=>i.toString(16).padStart(2,"0")).join("");C.value=a,l("err",`WITNESS MISMATCH actual=${a.slice(0,16)}…`)}}catch(t){f.value="fail",l("err",`verify failed: ${t.message}`)}}}renderSignalTab(){const i=n=>{let d="";return n.forEach((p,O)=>{const fe=O/Math.max(1,199)*320,xe=65-p*22;d+=(O===0?"M":"L")+` ${fe.toFixed(1)} ${xe.toFixed(1)} `}),d};return c`
+
+
+ B-vector trace
+ 3-axis · nT
+
+
+
+ ${U` `}
+ ${U` `}
+ ${U` `}
+
+
+
+
+
+ Frame stream
+ live
+
+
+ ${de.value.map(n=>c`
`)}
+
+
+ `}renderFrameTab(){const e=_e.value,t=e?.raw;let s="";return t&&(s=Array.from(t).map(a=>a.toString(16).padStart(2,"0")).slice(0,60).join(" ")),c`
+
+
+ MagFrame v1 fields
+ 60 B
+
+
+ magic ${e?"0x"+e.magic.toString(16).toUpperCase():"—"}
+ version ${e?.version??"—"}
+ flags 0x${(e?.flags??0).toString(16).padStart(4,"0")}
+ sensor_id ${e?.sensorId??"—"}
+ t_us ${e?e.tUs.toString():"—"}
+ b_pT[0] ${e?e.bPt[0].toFixed(1):"—"}
+ b_pT[1] ${e?e.bPt[1].toFixed(1):"—"}
+ b_pT[2] ${e?e.bPt[2].toFixed(1):"—"}
+ noise_floor ${e?e.noiseFloorPtSqrtHz.toFixed(2):"—"}
+ temp_K ${e?e.temperatureK.toFixed(1):"—"}
+
+
+
+
+ Hex dump
+ LE
+
+
${s||"—"}
+
+ `}renderWitnessTab(){const e=f.value,t=e==="ok"?"ok":e==="fail"?"fail":"",s=e==="pending"?"Verifying…":e==="ok"?"✓ Witness verified · determinism gate":e==="fail"?"✗ Witness mismatch · audit required":"Verify witness";return c`
+
+
+ Expected (Proof::EXPECTED_WITNESS_HEX)
+ SHA-256
+
+
${I.value||"(loading…)"}
+
+
+
+ Actual (last verify)
+ SHA-256
+
+
${C.value||"(not verified yet)"}
+
${s}
+
+ `}render(){return c`
+
+ this.tab="signal"}>Signal
+ this.tab="frame"}>Frame
+ this.tab="witness"}>Witness
+
+
+ ${this.tab==="signal"?this.renderSignalTab():this.tab==="frame"?this.renderFrameTab():this.renderWitnessTab()}
+
+ `}};pe.styles=m`
+ :host {
+ display: flex; flex-direction: column;
+ background: var(--bg-1);
+ border-left: 1px solid var(--line);
+ overflow: hidden;
+ height: 100%;
+ }
+ .tabs {
+ display: flex; border-bottom: 1px solid var(--line);
+ }
+ .tab {
+ flex: 1;
+ padding: 11px 8px;
+ background: transparent; border: none;
+ font-size: 11.5px; font-weight: 500;
+ color: var(--ink-3);
+ border-bottom: 2px solid transparent;
+ cursor: pointer; transition: color 0.15s, border-color 0.15s;
+ }
+ .tab.active { color: var(--ink); border-bottom-color: var(--accent); }
+ .tab:hover { color: var(--ink-2); }
+ .body { padding: 14px; flex: 1; overflow-y: auto; }
+
+ .card {
+ background: var(--bg-2); border: 1px solid var(--line);
+ border-radius: var(--radius); padding: 12px;
+ margin-bottom: 12px;
+ }
+ .card-h {
+ display: flex; justify-content: space-between; align-items: center;
+ margin-bottom: 8px;
+ }
+ .card-h .ttl { font-size: 12px; font-weight: 600; }
+ .badge {
+ font-family: var(--mono); font-size: 10px;
+ padding: 2px 6px;
+ background: oklch(0.78 0.14 195 / 0.12);
+ color: var(--accent-2);
+ border-radius: 4px;
+ border: 1px solid oklch(0.78 0.14 195 / 0.3);
+ }
+ svg { width: 100%; height: 130px; }
+ .frame-strip {
+ height: 28px;
+ display: flex; align-items: flex-end; gap: 1px;
+ padding: 4px 0;
+ }
+ .bar {
+ flex: 1;
+ background: linear-gradient(to top, var(--accent-2), var(--accent));
+ border-radius: 1px;
+ min-height: 2px;
+ }
+ table { width: 100%; border-collapse: collapse; font-family: var(--mono); font-size: 10.5px; }
+ td { padding: 4px 0; border-bottom: 1px solid var(--line); }
+ td:first-child { color: var(--ink-3); }
+ td:last-child { text-align: right; color: var(--ink); }
+ .hex {
+ background: var(--bg-3);
+ border: 1px solid var(--line);
+ border-radius: var(--radius-sm);
+ padding: 10px;
+ font-family: var(--mono);
+ font-size: 10.5px;
+ color: var(--ink-2);
+ line-height: 1.6;
+ overflow-x: auto;
+ white-space: nowrap;
+ }
+ .hex .magic { color: var(--accent); font-weight: 600; }
+ .witness-box {
+ font-family: var(--mono);
+ font-size: 11px;
+ color: var(--ink-2);
+ background: var(--bg-3);
+ border: 1px solid var(--line);
+ border-radius: 6px;
+ padding: 8px 10px;
+ word-break: break-all;
+ line-height: 1.5;
+ }
+ .verify-btn {
+ margin-top: 10px;
+ width: 100%;
+ padding: 8px;
+ border: 1px solid var(--line);
+ background: var(--bg-3);
+ color: var(--ink);
+ border-radius: 8px;
+ cursor: pointer;
+ font-family: var(--mono);
+ font-size: 12px;
+ }
+ .verify-btn:hover { border-color: var(--accent); }
+ .verify-btn.ok { border-color: var(--ok); color: var(--ok); }
+ .verify-btn.fail { border-color: var(--bad); color: var(--bad); }
+ `;Re([u()],pe.prototype,"tab",2);pe=Re([h("nv-inspector")],pe);var bt=Object.defineProperty,ht=Object.getOwnPropertyDescriptor,je=(e,t,s,r)=>{for(var a=r>1?void 0:r?ht(t,s):t,i=e.length-1,n;i>=0;i--)(n=e[i])&&(a=(r?n(t,s,a):n(a))||a);return r&&a&&bt(t,s,a),a};let ue=class extends b{constructor(){super(...arguments),this.history=[],this.hIdx=-1,this.onKey=e=>{e.key==="Enter"?(this.exec(this.inputEl.value),this.inputEl.value=""):e.key==="ArrowUp"?this.history.length&&(this.hIdx=Math.max(0,this.hIdx-1),this.inputEl.value=this.history[this.hIdx]??"",e.preventDefault()):e.key==="ArrowDown"&&this.history.length&&(this.hIdx=Math.min(this.history.length,this.hIdx+1),this.inputEl.value=this.history[this.hIdx]??"",e.preventDefault())}}connectedCallback(){super.connectedCallback(),x(()=>{S.value,we.value,N.value,this.requestUpdate()})}updated(){const e=this.renderRoot.querySelector(".body");e&&(e.scrollTop=e.scrollHeight)}counts(){const e={info:0,warn:0,err:0,dbg:0,ok:0};for(const t of S.value)e[t.level]=(e[t.level]??0)+1;return e.all=S.value.length,e}async exec(e){if(e=e.trim(),!e)return;l("info",`nvsim> ${e}`),this.history.push(e),this.hIdx=this.history.length;const[t,...s]=e.split(/\s+/),r=s.join(" "),a=P();switch(t){case"help":l("info","commands: help · scene.list · sensor.config · run · pause · seed · proof.verify · clear · theme · status");break;case"scene.list":l("info","scene rebar-walkby-01:"),l("info"," rebar.steel.coil @ [+2.7, 0.0, +0.3] m χ=5000"),l("info"," dipole.heart_proxy @ [-1.4, +0.2, +0.4] m m=1.0e-6 A·m²"),l("info"," loop.mains_60Hz @ [-1.6, -0.4, 0.0] m I=2 A"),l("info"," eddy.door_steel @ [+0.0, +1.8, +0.4] m σ=1e6 S/m");break;case"sensor.config":l("info","NvSensor::cots_defaults() {"),l("info"," pos=[0,0,0], V=1mm³, N=1e12, C=0.03, T2*=200ns"),l("info"," D=2.870 GHz, γe=28 GHz/T, Γ=1.0 MHz, axes=4×〈111〉"),l("info"," δB ≈ 1.18 pT/√Hz (Barry 2020 §III.A) }");break;case"run":a&&(await a.run(),v.value=!0,l("ok","pipeline RUN"));break;case"pause":a&&(await a.pause(),v.value=!1,l("warn","pipeline PAUSED"));break;case"reset":a&&(await a.reset(),l("info","pipeline reset · t=0"));break;case"seed":{if(!r){l("info",`current seed = 0x${q.value.toString(16).toUpperCase()}`);break}const i=BigInt(r.startsWith("0x")?r:"0x"+r);q.value=i,a&&await a.setSeed(i),l("ok",`seed → 0x${i.toString(16).toUpperCase()}`);break}case"proof.verify":{if(!a)break;l("dbg","computing SHA-256 over 256 frames…");try{const i=I.value,n=new Uint8Array(32);for(let p=0;p<32;p++)n[p]=parseInt(i.slice(p*2,p*2+2),16);(await a.verifyWitness(n)).ok?(f.value="ok",C.value=i,l("ok",`witness ${i.slice(0,16)}… matches · determinism gate ✓`)):(f.value="fail",l("err","WITNESS MISMATCH"))}catch(i){l("err",`verify failed: ${i.message}`)}break}case"clear":S.value=[];break;case"theme":{const i=(r||"").toLowerCase();i==="light"||i==="dark"?(g.value=i,l("ok",`theme → ${i}`)):l("info","theme [light|dark]");break}case"status":l("info",`running=${v.value} seed=0x${q.value.toString(16).toUpperCase()} verified=${f.value}`);break;default:l("err",`unknown command: ${t} · try help`)}}render(){const e=this.counts(),t=we.value,s=S.value.filter(r=>t==="all"||r.level===t);return c`
+
+ ${["all","info","warn","err","dbg"].map(r=>c`
+
we.value=r}>
+ ${r} ${e[r]??0}
+
+ `)}
+
+
+ S.value=[]}>×
+ N.value=!N.value}>
+ ${N.value?"▶":"❚❚"}
+
+
+
+
+ ${s.map(r=>{const a=new Date(r.ts),i=`${String(a.getSeconds()).padStart(2,"0")}.${String(a.getMilliseconds()).padStart(3,"0")}`;return c`
`})}
+
+
+ nvsim>
+
+
+ `}};ue.styles=m`
+ :host {
+ display: flex; flex-direction: column;
+ background: var(--bg-1);
+ overflow: hidden;
+ }
+ .tabs {
+ display: flex; align-items: center;
+ border-bottom: 1px solid var(--line);
+ padding: 0 10px;
+ gap: 2px;
+ }
+ .tab {
+ padding: 8px 12px;
+ background: transparent; border: none;
+ font-size: 11.5px; color: var(--ink-3);
+ font-family: var(--mono);
+ border-bottom: 2px solid transparent;
+ cursor: pointer;
+ margin-bottom: -1px;
+ }
+ .tab.active { color: var(--ink); border-bottom-color: var(--accent); }
+ .tab .cnt {
+ background: var(--bg-3); padding: 1px 5px; border-radius: 999px;
+ font-size: 9.5px; color: var(--ink-2); margin-left: 4px;
+ }
+ .spacer { flex: 1; }
+ .tools { display: flex; gap: 4px; padding: 4px 0; }
+ .tools button {
+ width: 24px; height: 24px;
+ background: transparent; border: 1px solid var(--line);
+ border-radius: 6px;
+ color: var(--ink-3);
+ font-size: 11px; cursor: pointer;
+ }
+ .tools button:hover { color: var(--ink); border-color: var(--line-2); }
+
+ .body {
+ flex: 1; overflow-y: auto;
+ font-family: var(--mono);
+ font-size: 11.5px;
+ padding: 6px 0;
+ background: var(--bg-0);
+ }
+ .line {
+ display: grid;
+ grid-template-columns: 70px 60px 1fr;
+ gap: 12px;
+ padding: 2px 12px;
+ color: var(--ink-2);
+ border-left: 2px solid transparent;
+ }
+ .line:hover { background: var(--bg-1); }
+ .ts { color: var(--ink-4); font-size: 10.5px; padding-top: 1px; }
+ .lvl {
+ font-size: 10px; font-weight: 600;
+ text-transform: uppercase; letter-spacing: 0.04em; padding-top: 1px;
+ }
+ .line.info .lvl { color: var(--accent-2); }
+ .line.warn .lvl { color: var(--warn); }
+ .line.warn { border-left-color: var(--warn); background: oklch(0.7 0.18 35 / 0.04); }
+ .line.err .lvl { color: var(--bad); }
+ .line.err { border-left-color: var(--bad); background: oklch(0.65 0.22 25 / 0.05); }
+ .line.dbg .lvl { color: var(--ink-3); }
+ .line.ok .lvl { color: var(--ok); }
+ .msg { color: var(--ink); white-space: pre-wrap; word-break: break-word; }
+
+ .input {
+ display: flex; align-items: center;
+ border-top: 1px solid var(--line);
+ background: var(--bg-0);
+ padding: 0 10px;
+ height: 32px; gap: 8px;
+ }
+ .prompt { color: var(--accent); font-family: var(--mono); font-size: 12px; }
+ input[type="text"] {
+ flex: 1; background: transparent; border: none; outline: none;
+ color: var(--ink); font-family: var(--mono); font-size: 12px;
+ height: 100%;
+ }
+ input::placeholder { color: var(--ink-4); }
+ `;je([Ie("#console-input")],ue.prototype,"inputEl",2);ue=je([h("nv-console")],ue);const B=[{id:"nvsim",name:"nvsim — NV-diamond magnetometer",category:"sim",crate:"nvsim",summary:"Deterministic forward simulator: scene → Biot–Savart → NV ensemble → ADC → MagFrame stream + SHA-256 witness.",budget:"L",active:!0,status:"available",tags:["quantum","magnetometer","simulator","witness","wasm"],adr:"ADR-089"},{id:"gesture",name:"Gesture (DTW)",category:"sig",crate:"wifi-densepose-wasm-edge",summary:"Dynamic-Time-Warping gesture classifier from CSI motion templates.",events:[1],budget:"M",status:"available",tags:["hci","csi","classifier","dtw"],adr:"ADR-014"},{id:"coherence",name:"Coherence gate",category:"sig",crate:"wifi-densepose-wasm-edge",summary:"Z-score coherence scoring + Accept/PredictOnly/Reject/Recalibrate gate.",events:[2],budget:"S",status:"available",tags:["gate","csi","coherence","drift"],adr:"ADR-029"},{id:"adversarial",name:"Adversarial-signal detector",category:"ais",crate:"wifi-densepose-wasm-edge",summary:"Physically-impossible-signal detector — multi-link consistency, used to flag spoofed CSI.",events:[3],budget:"M",status:"available",tags:["security","csi","spoofing","mesh"],adr:"ADR-032"},{id:"rvf",name:"RVF — Rust Verified Feature stream",category:"sig",crate:"wifi-densepose-wasm-edge",summary:"Verified-frame builder with SHA-256 hash + version metadata for the feature stream.",budget:"S",status:"available",tags:["witness","csi","hash"],adr:"ADR-040"},{id:"occupancy",name:"Occupancy estimator",category:"bld",crate:"wifi-densepose-wasm-edge",summary:"Through-wall presence + person-count via CSI amplitude perturbation.",events:[300,301,302],budget:"S",status:"available",tags:["csi","building","presence"]},{id:"vital_trend",name:"Vital-trend monitor",category:"med",crate:"wifi-densepose-wasm-edge",summary:"HR + BR trend tracking with bradycardia/tachycardia/apnea events.",events:[100,101,102,103,104,105],budget:"S",status:"available",tags:["medical","vitals","csi"],adr:"ADR-021"},{id:"intrusion",name:"Intrusion detector",category:"sec",crate:"wifi-densepose-wasm-edge",summary:"Zone-based intrusion alert from CSI motion patterns.",events:[200,201],budget:"S",status:"available",tags:["security","zone","csi"]},{id:"med_sleep_apnea",name:"Sleep-apnea detector",category:"med",crate:"wifi-densepose-wasm-edge",summary:"Episodic respiratory pause detection during sleep cycles.",events:[105],budget:"S",status:"available",tags:["medical","sleep","breathing"]},{id:"med_cardiac_arrhythmia",name:"Cardiac arrhythmia",category:"med",crate:"wifi-densepose-wasm-edge",summary:"Beat-to-beat irregularity classifier from cardiac micro-Doppler.",events:[103,104],budget:"M",status:"available",tags:["medical","cardiac","arrhythmia"]},{id:"med_respiratory_distress",name:"Respiratory distress",category:"med",crate:"wifi-densepose-wasm-edge",summary:"Distress signature: rapid shallow breathing + accessory-muscle motion.",events:[101,102],budget:"S",status:"available",tags:["medical","breathing","icu"]},{id:"med_gait_analysis",name:"Gait analysis",category:"med",crate:"wifi-densepose-wasm-edge",summary:"Stride length, cadence, asymmetry from through-wall CSI pose tracking.",budget:"M",status:"available",tags:["medical","gait","pose"]},{id:"med_seizure_detect",name:"Seizure detector",category:"med",crate:"wifi-densepose-wasm-edge",summary:"Tonic-clonic seizure motion signature.",budget:"M",status:"beta",tags:["medical","neuro"]},{id:"sec_perimeter_breach",name:"Perimeter breach",category:"sec",crate:"wifi-densepose-wasm-edge",summary:"Approach/departure detection at user-defined boundary segments.",events:[210,211,212,213],budget:"S",status:"available",tags:["security","perimeter"]},{id:"sec_weapon_detect",name:"Metal anomaly / weapon",category:"sec",crate:"wifi-densepose-wasm-edge",summary:"Metal-perturbation flag in CSI; potential weapon presence (research).",events:[220,221,222],budget:"M",status:"research",tags:["security","metal","csi"]},{id:"sec_tailgating",name:"Tailgating detector",category:"sec",crate:"wifi-densepose-wasm-edge",summary:"Detect 2+ persons crossing a single-passage threshold.",events:[230,231,232],budget:"S",status:"available",tags:["security","access-control"]},{id:"sec_loitering",name:"Loitering detector",category:"sec",crate:"wifi-densepose-wasm-edge",summary:"Stationary occupancy past a configurable dwell threshold.",events:[240,241,242],budget:"S",status:"available",tags:["security","dwell"]},{id:"sec_panic_motion",name:"Panic motion",category:"sec",crate:"wifi-densepose-wasm-edge",summary:"High-energy distress motion: struggle / fleeing pattern.",events:[250,251,252],budget:"S",status:"beta",tags:["security","distress"]},{id:"bld_hvac_presence",name:"HVAC presence",category:"bld",crate:"wifi-densepose-wasm-edge",summary:"Occupied/activity-level/departure-countdown for HVAC zones.",events:[310,311,312],budget:"S",status:"available",tags:["hvac","building","energy"]},{id:"bld_lighting_zones",name:"Lighting zones",category:"bld",crate:"wifi-densepose-wasm-edge",summary:"Per-zone light on/dim/off cues from occupancy.",events:[320,321,322],budget:"S",status:"available",tags:["lighting","building"]},{id:"bld_elevator_count",name:"Elevator count",category:"bld",crate:"wifi-densepose-wasm-edge",summary:"Person count inside elevator car from CSI.",events:[330],budget:"S",status:"available",tags:["elevator","building"]},{id:"bld_meeting_room",name:"Meeting-room utilization",category:"bld",crate:"wifi-densepose-wasm-edge",summary:"Meeting size + duration analytics for booking systems.",budget:"S",status:"available",tags:["meeting","analytics"]},{id:"bld_energy_audit",name:"Energy audit",category:"bld",crate:"wifi-densepose-wasm-edge",summary:"Continuous occupancy-vs-HVAC-state audit for energy savings.",budget:"M",status:"available",tags:["energy","audit"]},{id:"ret_queue_length",name:"Queue length",category:"ret",crate:"wifi-densepose-wasm-edge",summary:"Live queue-length tracking for checkout / kiosks.",budget:"S",status:"available",tags:["retail","queue"]},{id:"ret_dwell_heatmap",name:"Dwell heatmap",category:"ret",crate:"wifi-densepose-wasm-edge",summary:"Per-zone dwell time accumulation; analytics-only export.",budget:"M",status:"available",tags:["retail","heatmap"]},{id:"ret_customer_flow",name:"Customer flow",category:"ret",crate:"wifi-densepose-wasm-edge",summary:"Origin-destination flow graph through a store layout.",budget:"M",status:"available",tags:["retail","flow"]},{id:"ret_table_turnover",name:"Table turnover",category:"ret",crate:"wifi-densepose-wasm-edge",summary:"Restaurant table seat / vacate transitions.",budget:"S",status:"available",tags:["retail","restaurant"]},{id:"ret_shelf_engagement",name:"Shelf engagement",category:"ret",crate:"wifi-densepose-wasm-edge",summary:"Reach-to-shelf gestures and dwell at product zones.",budget:"M",status:"available",tags:["retail","shelf"]},{id:"ind_forklift_proximity",name:"Forklift proximity",category:"ind",crate:"wifi-densepose-wasm-edge",summary:"Worker-near-forklift safety alert.",budget:"S",status:"available",tags:["industrial","safety"]},{id:"ind_confined_space",name:"Confined-space monitor",category:"ind",crate:"wifi-densepose-wasm-edge",summary:"Last-person-out detection + presence audit for OSHA confined-space entries.",budget:"S",status:"available",tags:["industrial","osha"]},{id:"ind_clean_room",name:"Clean-room PPE / motion",category:"ind",crate:"wifi-densepose-wasm-edge",summary:"Motion patterns consistent with proper PPE-clad movement.",budget:"M",status:"beta",tags:["industrial","cleanroom"]},{id:"ind_livestock_monitor",name:"Livestock monitor",category:"ind",crate:"wifi-densepose-wasm-edge",summary:"Vital-sign + activity tracking for stall-bound livestock.",budget:"M",status:"beta",tags:["agriculture","livestock"]},{id:"ind_structural_vibration",name:"Structural vibration",category:"ind",crate:"wifi-densepose-wasm-edge",summary:"Building/equipment micro-vibration via CSI phase derivative.",budget:"M",status:"research",tags:["industrial","vibration"]},{id:"sig_coherence_gate",name:"Coherence gate (extended)",category:"sig",crate:"wifi-densepose-wasm-edge",summary:"Hysteresis + multi-state coherence gate driving downstream apps.",budget:"S",status:"available",tags:["gate","csi"]},{id:"sig_flash_attention",name:"Flash attention (CSI)",category:"sig",crate:"wifi-densepose-wasm-edge",summary:"Edge-friendly attention block for CSI subcarrier weighting.",budget:"M",status:"beta",tags:["attention","csi"]},{id:"sig_temporal_compress",name:"Temporal-tensor compress",category:"sig",crate:"wifi-densepose-wasm-edge",summary:"RuVector temporal-tensor compression on the CSI buffer.",budget:"M",status:"available",tags:["compress","tensor"]},{id:"sig_sparse_recovery",name:"Sparse recovery",category:"sig",crate:"wifi-densepose-wasm-edge",summary:"114→56 subcarrier sparse interpolation via L1 solver.",budget:"M",status:"available",tags:["sparse","csi"]},{id:"sig_mincut_person_match",name:"Mincut person-match",category:"sig",crate:"wifi-densepose-wasm-edge",summary:"Min-cut person assignment across multistatic frames.",budget:"M",status:"available",tags:["mincut","matching"]},{id:"sig_optimal_transport",name:"Optimal transport",category:"sig",crate:"wifi-densepose-wasm-edge",summary:"OT-based feature alignment between mesh nodes.",budget:"M",status:"beta",tags:["ot","alignment"]},{id:"lrn_dtw_gesture_learn",name:"DTW gesture learn",category:"lrn",crate:"wifi-densepose-wasm-edge",summary:"On-device template learning for personalized gesture libraries.",budget:"M",status:"beta",tags:["lifelong","gesture"]},{id:"lrn_anomaly_attractor",name:"Anomaly attractor",category:"lrn",crate:"wifi-densepose-wasm-edge",summary:"Novelty detector with dynamic-attractor recall.",budget:"M",status:"research",tags:["novelty","lifelong"]},{id:"lrn_meta_adapt",name:"Meta-adapt",category:"lrn",crate:"wifi-densepose-wasm-edge",summary:"Meta-learning adapter for fast site-to-site transfer.",budget:"L",status:"research",tags:["meta-learning"]},{id:"lrn_ewc_lifelong",name:"EWC++ lifelong",category:"lrn",crate:"wifi-densepose-wasm-edge",summary:"Elastic-weight-consolidation gate to avoid catastrophic forgetting.",budget:"M",status:"beta",tags:["lifelong","ewc"]},{id:"spt_pagerank_influence",name:"PageRank influence",category:"spt",crate:"wifi-densepose-wasm-edge",summary:"Graph-influence ranking on the multistatic mesh.",budget:"M",status:"beta",tags:["graph","pagerank"]},{id:"spt_micro_hnsw",name:"µHNSW vector index",category:"spt",crate:"wifi-densepose-wasm-edge",summary:"Tiny HNSW index for AETHER re-ID embeddings on-device.",budget:"M",status:"available",tags:["hnsw","reid"]},{id:"spt_spiking_tracker",name:"Spiking tracker",category:"spt",crate:"wifi-densepose-wasm-edge",summary:"Spiking-network multi-target tracker.",budget:"L",status:"research",tags:["snn","tracker"]},{id:"tmp_pattern_sequence",name:"Pattern sequence",category:"tmp",crate:"wifi-densepose-wasm-edge",summary:"Sequence-of-events pattern matcher (e.g. ingress→linger→egress).",budget:"M",status:"available",tags:["temporal","pattern"]},{id:"tmp_temporal_logic_guard",name:"Temporal logic guard",category:"tmp",crate:"wifi-densepose-wasm-edge",summary:"LTL/MTL safety-property guard over event streams.",budget:"M",status:"beta",tags:["ltl","safety"]},{id:"tmp_goap_autonomy",name:"GOAP autonomy",category:"tmp",crate:"wifi-densepose-wasm-edge",summary:"Goal-oriented action planning for adaptive routines.",budget:"L",status:"research",tags:["planning","autonomy"]},{id:"ais_prompt_shield",name:"Prompt shield",category:"ais",crate:"wifi-densepose-wasm-edge",summary:"Edge-side LLM prompt-injection guard for on-device assistants.",budget:"M",status:"beta",tags:["security","llm"]},{id:"ais_behavioral_profiler",name:"Behavioral profiler",category:"ais",crate:"wifi-densepose-wasm-edge",summary:"Anomalous-behaviour profiler (drift in motion habits).",budget:"M",status:"beta",tags:["anomaly","behaviour"]},{id:"qnt_quantum_coherence",name:"Quantum coherence",category:"qnt",crate:"wifi-densepose-wasm-edge",summary:"Coherence diagnostics adapted for quantum-sensor signals.",budget:"M",status:"research",tags:["quantum","coherence"]},{id:"qnt_interference_search",name:"Interference search",category:"qnt",crate:"wifi-densepose-wasm-edge",summary:"Interferometric anomaly search across mesh viewpoints.",budget:"L",status:"research",tags:["quantum","interference"]},{id:"aut_psycho_symbolic",name:"Psycho-symbolic agent",category:"aut",crate:"wifi-densepose-wasm-edge",summary:"Symbolic-rule + neural-feature hybrid for low-power autonomy loops.",budget:"L",status:"research",tags:["autonomy","symbolic"]},{id:"aut_self_healing_mesh",name:"Self-healing mesh",category:"aut",crate:"wifi-densepose-wasm-edge",summary:"Mesh-topology repair with per-node health gossip.",budget:"M",status:"beta",tags:["mesh","health"]},{id:"exo_ghost_hunter",name:"Ghost hunter (anomaly)",category:"exo",crate:"wifi-densepose-wasm-edge",summary:"Empty-room CSI anomaly detector — impulsive/periodic/drift/random + hidden-presence sub-detector.",events:[650,651,652,653],budget:"S",status:"available",tags:["anomaly","paranormal","csi"],adr:"ADR-041"},{id:"exo_breathing_sync",name:"Breathing sync",category:"exo",crate:"wifi-densepose-wasm-edge",summary:"Multi-person breathing synchrony analytics.",budget:"M",status:"beta",tags:["breathing","sync"]},{id:"exo_dream_stage",name:"Dream-stage classifier",category:"exo",crate:"wifi-densepose-wasm-edge",summary:"NREM/REM stage classification from breathing + micro-motion.",budget:"M",status:"research",tags:["sleep","rem"]},{id:"exo_emotion_detect",name:"Emotion detector",category:"exo",crate:"wifi-densepose-wasm-edge",summary:"Coarse arousal/valence from breathing + heart-rate variability.",budget:"M",status:"research",tags:["affect"]},{id:"exo_gesture_language",name:"Gesture language",category:"exo",crate:"wifi-densepose-wasm-edge",summary:"Sign-language pattern recognition.",budget:"L",status:"research",tags:["hci","sign"]},{id:"exo_happiness_score",name:"Happiness score",category:"exo",crate:"wifi-densepose-wasm-edge",summary:"Aggregate well-being score from co-occupancy + activity dynamics.",budget:"M",status:"research",tags:["affect","wellbeing"]},{id:"exo_hyperbolic_space",name:"Hyperbolic space embed",category:"exo",crate:"wifi-densepose-wasm-edge",summary:"Hyperbolic embeddings for hierarchical scene structure.",budget:"L",status:"research",tags:["embedding","hyperbolic"]},{id:"exo_music_conductor",name:"Music conductor",category:"exo",crate:"wifi-densepose-wasm-edge",summary:"Map gesture energy to MIDI tempo/dynamics.",budget:"M",status:"research",tags:["midi","art"]},{id:"exo_plant_growth",name:"Plant-growth tracker",category:"exo",crate:"wifi-densepose-wasm-edge",summary:"Slow CSI drift tracking for greenhouse foliage growth.",budget:"L",status:"research",tags:["agriculture"]},{id:"exo_rain_detect",name:"Rain detector",category:"exo",crate:"wifi-densepose-wasm-edge",summary:"Outdoor CSI signature of rainfall.",budget:"M",status:"research",tags:["weather"]},{id:"exo_time_crystal",name:"Time-crystal periodicity",category:"exo",crate:"wifi-densepose-wasm-edge",summary:"Periodicity diagnostics with anti-aliasing harmonics.",budget:"M",status:"research",tags:["periodicity"]}],j={sim:{label:"Simulators",color:"oklch(0.78 0.14 70)",range:"—"},med:{label:"Medical & Health",color:"oklch(0.65 0.22 25)",range:"100–199"},sec:{label:"Security & Safety",color:"oklch(0.7 0.18 35)",range:"200–299"},bld:{label:"Smart Building",color:"oklch(0.78 0.12 195)",range:"300–399"},ret:{label:"Retail & Hospitality",color:"oklch(0.78 0.14 145)",range:"400–499"},ind:{label:"Industrial",color:"oklch(0.72 0.18 330)",range:"500–599"},sig:{label:"Signal Processing",color:"oklch(0.78 0.14 70)",range:"600–619"},lrn:{label:"Online Learning",color:"oklch(0.78 0.12 260)",range:"620–639"},spt:{label:"Spatial / Graph",color:"oklch(0.7 0.18 100)",range:"640–659"},tmp:{label:"Temporal / Planning",color:"oklch(0.7 0.16 50)",range:"660–679"},ais:{label:"AI Safety",color:"oklch(0.65 0.22 25)",range:"700–719"},qnt:{label:"Quantum",color:"oklch(0.72 0.18 290)",range:"720–739"},aut:{label:"Autonomy",color:"oklch(0.78 0.14 145)",range:"740–759"},exo:{label:"Exotic / Research",color:"oklch(0.72 0.18 330)",range:"650–699"}};function ft(){return B.map(e=>({id:e.id,active:e.active===!0,eventCount:0}))}function xt(e,t){if(!e)return 1;const s=e.toLowerCase();let r=0;return t.id.toLowerCase().includes(s)&&(r+=3),t.name.toLowerCase().includes(s)&&(r+=3),t.summary.toLowerCase().includes(s)&&(r+=1),t.tags?.some(a=>a.toLowerCase().includes(s))&&(r+=2),t.category===s&&(r+=5),r}const yt="nvsim",wt=1,F="kv";let se=null;function He(){return se||(se=new Promise((e,t)=>{const s=indexedDB.open(yt,wt);s.onupgradeneeded=()=>{const r=s.result;r.objectStoreNames.contains(F)||r.createObjectStore(F)},s.onsuccess=()=>e(s.result),s.onerror=()=>t(s.error)}),se)}async function V(e){const t=await He();return await new Promise((s,r)=>{const i=t.transaction(F,"readonly").objectStore(F).get(e);i.onsuccess=()=>s(i.result),i.onerror=()=>r(i.error)})}async function K(e,t){const s=await He();return await new Promise((r,a)=>{const i=s.transaction(F,"readwrite");i.objectStore(F).put(t,e),i.oncomplete=()=>r(),i.onerror=()=>a(i.error)})}var kt=Object.defineProperty,$t=Object.getOwnPropertyDescriptor,We=(e,t,s,r)=>{for(var a=r>1?void 0:r?$t(t,s):t,i=e.length-1,n;i>=0;i--)(n=e[i])&&(a=(r?n(t,s,a):n(a))||a);return r&&a&&kt(t,s,a),a};const z=o(ft()),H=o(""),M=o("all"),y=o("all");(async()=>{const e=await V("app-activations");e&&(z.value=e)})();x(()=>{const e=z.value;e.length>0&&K("app-activations",e)});let ve=class extends b{constructor(){super(...arguments),this.renderTick=0}connectedCallback(){super.connectedCallback(),x(()=>{z.value,H.value,M.value,y.value,this.renderTick++})}isActive(e){return z.value.find(t=>t.id===e)?.active===!0}toggle(e){const t=z.value.map(s=>s.id===e.id?{...s,active:!s.active,lastActivatedAt:Date.now()}:s);z.value=t,l(this.isActive(e.id)?"ok":"info",`app ${e.id} deactivated`)}filtered(){let e=B;return M.value!=="all"&&(e=e.filter(t=>t.category===M.value)),y.value!=="all"&&(e=e.filter(t=>t.status===y.value)),H.value.trim()&&(e=e.map(t=>({a:t,s:xt(H.value,t)})).filter(t=>t.s>0).sort((t,s)=>s.s-t.s).map(t=>t.a)),e}categoryCounts(){const e={all:B.length};for(const t of Object.keys(j))e[t]=0;for(const t of B)e[t.category]=(e[t.category]??0)+1;return e}render(){const e=this.filtered(),t=this.categoryCounts(),s=z.value.filter(r=>r.active).length;return c`
+
+
+ App Store
+ ${B.length} edge apps · ${s} active
+
+
{H.value=r.target.value}} />
+
+
+
+ M.value="all"}>
+ All${t.all}
+
+ ${Object.keys(j).map(r=>c`
+ M.value=r}>
+
+ ${j[r].label}
+ ${t[r]??0}
+
+ `)}
+
+ y.value="all"}>any
+ y.value="available"}>available
+ y.value="beta"}>beta
+ y.value="research"}>research
+
+
+ ${e.length===0?c`No apps match the current filters.
`:c`${e.map(r=>this.card(r))}
`}
+ `}card(e){const t=this.isActive(e.id),s=j[e.category];return c`
+
+
+
+ ${e.name}
+
+
${e.summary}
+
+ ${s.label}
+ ${e.status}
+ ${e.budget?c`budget ${e.budget} `:""}
+ ${e.adr?c`${e.adr} `:""}
+ ${e.events?.length?c`events ${e.events.join("·")} `:""}
+
+
+
+ `}};ve.styles=m`
+ :host {
+ display: block;
+ height: 100%;
+ overflow-y: auto;
+ background: radial-gradient(ellipse at 50% 30%, var(--bg-2) 0%, var(--bg-0) 70%);
+ padding: 24px;
+ }
+ .head {
+ display: flex; align-items: center; gap: 16px;
+ margin-bottom: 18px;
+ flex-wrap: wrap;
+ }
+ .ttl {
+ font-size: 22px; font-weight: 700; letter-spacing: -0.02em;
+ color: var(--ink);
+ flex: 1; min-width: 200px;
+ }
+ .ttl small {
+ font-size: 12.5px; font-weight: 400;
+ color: var(--ink-3); margin-left: 8px;
+ }
+ .search {
+ width: 320px; max-width: 100%;
+ padding: 8px 12px;
+ background: var(--bg-2);
+ border: 1px solid var(--line);
+ border-radius: 8px;
+ font-family: var(--mono);
+ font-size: 12.5px;
+ color: var(--ink); outline: none;
+ }
+ .search:focus { border-color: var(--accent); }
+ .filters {
+ display: flex; flex-wrap: wrap; gap: 6px;
+ margin-bottom: 18px;
+ }
+ .chip {
+ padding: 4px 10px;
+ background: var(--bg-2);
+ border: 1px solid var(--line);
+ border-radius: 999px;
+ font-size: 11.5px; color: var(--ink-3);
+ cursor: pointer;
+ font-family: var(--mono);
+ display: inline-flex; align-items: center; gap: 4px;
+ }
+ .chip:hover { color: var(--ink); border-color: var(--line-2); }
+ .chip.on { background: var(--bg-3); border-color: var(--accent); color: var(--ink); }
+ .chip .swatch {
+ width: 7px; height: 7px; border-radius: 50%;
+ }
+ .chip .count { color: var(--ink-3); font-size: 10px; }
+ .grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
+ gap: 12px;
+ }
+ .card {
+ background: var(--bg-2);
+ border: 1px solid var(--line);
+ border-radius: var(--radius);
+ padding: 12px 14px;
+ display: flex; flex-direction: column; gap: 6px;
+ transition: border-color 0.15s, transform 0.15s;
+ position: relative;
+ }
+ .card:hover { border-color: var(--line-2); transform: translateY(-1px); }
+ .card.active {
+ border-color: oklch(0.78 0.14 145 / 0.7);
+ background: linear-gradient(180deg, var(--bg-2) 0%, oklch(0.78 0.14 145 / 0.04) 100%);
+ }
+ .card-h {
+ display: flex; align-items: flex-start; gap: 8px;
+ margin-bottom: 2px;
+ }
+ .card-h .name {
+ font-size: 13.5px; font-weight: 600; color: var(--ink);
+ flex: 1; line-height: 1.3;
+ }
+ .card-h .swatch {
+ width: 10px; height: 10px; border-radius: 50%;
+ flex-shrink: 0; margin-top: 4px;
+ }
+ .summary {
+ font-size: 12px; color: var(--ink-2); line-height: 1.45;
+ flex: 1;
+ }
+ .meta {
+ display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px;
+ font-family: var(--mono); font-size: 10px;
+ }
+ .badge {
+ padding: 1px 6px; border-radius: 4px;
+ background: var(--bg-3); color: var(--ink-3);
+ border: 1px solid var(--line);
+ }
+ .badge.cat { color: var(--accent); border-color: oklch(0.78 0.14 70 / 0.3); }
+ .badge.status-available { color: var(--ok); border-color: oklch(0.78 0.14 145 / 0.4); }
+ .badge.status-beta { color: var(--warn); border-color: oklch(0.7 0.18 35 / 0.4); }
+ .badge.status-research { color: var(--accent-3); border-color: oklch(0.72 0.18 330 / 0.4); }
+ .badge.budget { color: var(--accent-2); border-color: oklch(0.78 0.12 195 / 0.3); }
+ .card-foot {
+ display: flex; align-items: center; gap: 8px;
+ padding-top: 8px; margin-top: 4px;
+ border-top: 1px solid var(--line);
+ font-size: 11px; color: var(--ink-3);
+ }
+ .toggle {
+ position: relative;
+ width: 32px; height: 18px;
+ background: var(--bg-3); border: 1px solid var(--line-2);
+ border-radius: 999px; cursor: pointer;
+ transition: background 0.15s;
+ flex-shrink: 0;
+ }
+ .toggle::after {
+ content: ''; position: absolute;
+ top: 1px; left: 1px;
+ width: 12px; height: 12px;
+ background: var(--ink-3); border-radius: 50%;
+ transition: transform 0.15s, background 0.15s;
+ }
+ .toggle.on { background: var(--accent); border-color: var(--accent); }
+ .toggle.on::after { background: #1a0f00; transform: translateX(14px); }
+ .events {
+ font-family: var(--mono); font-size: 10px; color: var(--ink-3);
+ flex: 1;
+ }
+ .empty {
+ padding: 40px;
+ text-align: center; color: var(--ink-3);
+ font-size: 13px;
+ }
+ `;We([u()],ve.prototype,"renderTick",2);ve=We([h("nv-app-store")],ve);var _t=Object.defineProperty,St=Object.getOwnPropertyDescriptor,he=(e,t,s,r)=>{for(var a=r>1?void 0:r?St(t,s):t,i=e.length-1,n;i>=0;i--)(n=e[i])&&(a=(r?n(t,s,a):n(a))||a);return r&&a&&_t(t,s,a),a};let R=class extends b{constructor(){super(...arguments),this.visible=!1,this.msg="",this.icon="✓",this.timer=null,this.onToast=e=>{const t=e.detail;this.msg=t.msg??"Done",this.icon=t.icon??"✓",this.visible=!0,this.setAttribute("visible",""),this.timer!==null&&window.clearTimeout(this.timer),this.timer=window.setTimeout(()=>{this.visible=!1,this.removeAttribute("visible")},1800)}}connectedCallback(){super.connectedCallback(),window.addEventListener("nv-toast",this.onToast)}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("nv-toast",this.onToast)}render(){return c`${this.icon} ${this.msg} `}};R.styles=m`
+ :host {
+ position: fixed; bottom: 24px; left: 50%;
+ transform: translateX(-50%) translateY(80px);
+ background: var(--bg-2);
+ border: 1px solid var(--line-2);
+ border-radius: var(--radius);
+ padding: 10px 14px;
+ font-size: 12.5px;
+ box-shadow: var(--shadow);
+ z-index: 100;
+ opacity: 0; pointer-events: none;
+ transition: opacity 0.2s, transform 0.2s;
+ display: flex; align-items: center; gap: 8px;
+ }
+ :host([visible]) {
+ opacity: 1;
+ transform: translateX(-50%) translateY(0);
+ pointer-events: auto;
+ }
+ .icon { color: var(--accent); }
+ `;he([u()],R.prototype,"visible",2);he([u()],R.prototype,"msg",2);he([u()],R.prototype,"icon",2);R=he([h("nv-toast")],R);function W(e,t="✓"){window.dispatchEvent(new CustomEvent("nv-toast",{detail:{msg:e,icon:t}}))}var Ct=Object.defineProperty,Pt=Object.getOwnPropertyDescriptor,X=(e,t,s,r)=>{for(var a=r>1?void 0:r?Pt(t,s):t,i=e.length-1,n;i>=0;i--)(n=e[i])&&(a=(r?n(t,s,a):n(a))||a);return r&&a&&Ct(t,s,a),a};let A=class extends b{constructor(){super(...arguments),this.open=!1,this.mTitle="",this.mBody="",this.buttons=[],this.onModal=e=>{const t=e.detail;this.mTitle=t.title,this.mBody=t.body,this.buttons=t.buttons??[{label:"Close",variant:"primary"}],this.open=!0,this.setAttribute("open","")},this.onKey=e=>{e.key==="Escape"&&this.open&&this.close()}}connectedCallback(){super.connectedCallback(),window.addEventListener("nv-modal",this.onModal),window.addEventListener("keydown",this.onKey)}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("nv-modal",this.onModal),window.removeEventListener("keydown",this.onKey)}close(){this.open=!1,this.removeAttribute("open")}clickBtn(e){e.onClick?.(),this.close()}render(){return c`
+
+
+
${this.mTitle}
+
this.close()}>×
+
+
+
+ ${this.buttons.map(e=>c`
+ this.clickBtn(e)}>${e.label}
+ `)}
+
+
+ `}};A.styles=m`
+ :host {
+ position: fixed; inset: 0;
+ background: rgba(0,0,0,0.55);
+ backdrop-filter: blur(4px);
+ z-index: 200;
+ display: grid; place-items: center;
+ opacity: 0; pointer-events: none;
+ transition: opacity 0.18s;
+ }
+ :host([open]) { opacity: 1; pointer-events: auto; }
+ .modal {
+ background: var(--bg-1);
+ border: 1px solid var(--line-2);
+ border-radius: var(--radius);
+ box-shadow: 0 30px 80px -20px rgba(0,0,0,0.7);
+ width: min(520px, 92vw);
+ max-height: 86vh;
+ display: flex; flex-direction: column;
+ transform: translateY(12px) scale(0.98);
+ transition: transform 0.22s cubic-bezier(0.2,0.7,0.3,1);
+ }
+ :host([open]) .modal { transform: translateY(0) scale(1); }
+ .h {
+ padding: 14px 16px;
+ border-bottom: 1px solid var(--line);
+ display: flex; align-items: center; justify-content: space-between;
+ }
+ .h .ttl { font-size: 14px; font-weight: 600; }
+ .body { padding: 16px; overflow-y: auto; font-size: 13px; color: var(--ink-2); line-height: 1.55; }
+ .f {
+ padding: 12px 16px;
+ border-top: 1px solid var(--line);
+ display: flex; gap: 8px; justify-content: flex-end;
+ }
+ button {
+ padding: 6px 12px;
+ border-radius: 8px;
+ font-size: 12.5px;
+ cursor: pointer;
+ font-family: inherit;
+ border: 1px solid var(--line);
+ background: var(--bg-2); color: var(--ink);
+ }
+ button.ghost { background: transparent; }
+ button.primary { background: var(--accent); border-color: var(--accent); color: #1a0f00; }
+ button.danger { background: var(--bad); border-color: var(--bad); color: #fff; }
+ .close {
+ width: 28px; height: 28px;
+ background: transparent; border: 1px solid var(--line);
+ border-radius: 6px;
+ color: var(--ink-2);
+ }
+ `;X([u()],A.prototype,"open",2);X([u()],A.prototype,"mTitle",2);X([u()],A.prototype,"mBody",2);X([u()],A.prototype,"buttons",2);A=X([h("nv-modal")],A);function ke(e){window.dispatchEvent(new CustomEvent("nv-modal",{detail:e}))}var Mt=Object.defineProperty,zt=Object.getOwnPropertyDescriptor,J=(e,t,s,r)=>{for(var a=r>1?void 0:r?zt(t,s):t,i=e.length-1,n;i>=0;i--)(n=e[i])&&(a=(r?n(t,s,a):n(a))||a);return r&&a&&Mt(t,s,a),a};let E=class extends b{constructor(){super(...arguments),this.open=!1,this.filter="",this.idx=0,this.cmds=[{ico:"▶",label:"Run pipeline",kbd:"Space",run:async()=>{await P()?.run(),v.value=!0,W("Pipeline running","▶")}},{ico:"❚",label:"Pause pipeline",run:async()=>{await P()?.pause(),v.value=!1,W("Paused","❚❚")}},{ico:"⟳",label:"Reset pipeline",kbd:"⌘R",run:()=>ke({title:"Reset pipeline?",body:"Clears the frame stream and rewinds t to 0.
",buttons:[{label:"Cancel",variant:"ghost"},{label:"Reset",variant:"danger",onClick:async()=>{await P()?.reset(),l("warn","pipeline reset · t=0"),W("Pipeline reset","⟳")}}]})},{ico:"✓",label:"Verify witness",run:async()=>{const e=P();if(!e)return;f.value="pending";const t=I.value,s=new Uint8Array(32);for(let a=0;a<32;a++)s[a]=parseInt(t.slice(a*2,a*2+2),16);(await e.verifyWitness(s)).ok?(f.value="ok",C.value=t,W("Witness verified","✓")):(f.value="fail",W("Witness mismatch!","✗"))}},{ico:"☼",label:"Toggle theme",kbd:"⌘/",run:()=>{g.value=g.value==="dark"?"light":"dark"}},{ico:"⚙",label:"Open settings",kbd:"⌘,",run:()=>window.dispatchEvent(new CustomEvent("open-settings"))},{ico:"?",label:"Keyboard shortcuts…",run:()=>ke({title:"Keyboard shortcuts",body:`
+
⌘K / Ctrl K
Command palette
+
Space
Play / pause
+
⌘R
Reset
+
⌘,
Settings
+
⌘/
Toggle theme
+
\`
Debug HUD
+
1 · 2 · 3
Inspector tabs
+
Esc
Close modal/palette
+
/
Focus REPL
+
`,buttons:[{label:"Close",variant:"primary"}]})},{ico:"i",label:"About nvsim…",run:()=>ke({title:"About nvsim",body:`nvsim is a deterministic, byte-reproducible forward simulator for nitrogen-vacancy diamond magnetometry.
+ This dashboard runs nvsim as WASM in a Web Worker. Same (scene, config, seed) → byte-identical SHA-256 witness across runs and machines.
+ License: MIT OR Apache-2.0 · See ADR-089, ADR-092.
`,buttons:[{label:"Close",variant:"primary"}]})}],this.onKey=e=>{(e.metaKey||e.ctrlKey)&&e.key.toLowerCase()==="k"?(e.preventDefault(),this.openPal()):e.key==="Escape"&&this.open?this.closePal():this.open&&(e.key==="ArrowDown"?(this.idx=Math.min(this.cmds.length-1,this.idx+1),e.preventDefault()):e.key==="ArrowUp"?(this.idx=Math.max(0,this.idx-1),e.preventDefault()):e.key==="Enter"&&(this.runIdx(),e.preventDefault()))},this.onOpen=()=>this.openPal()}connectedCallback(){super.connectedCallback(),window.addEventListener("keydown",this.onKey),window.addEventListener("nv-palette",this.onOpen)}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("keydown",this.onKey),window.removeEventListener("nv-palette",this.onOpen)}openPal(){this.open=!0,this.setAttribute("open",""),this.filter="",this.idx=0,setTimeout(()=>this.inputEl?.focus(),0)}closePal(){this.open=!1,this.removeAttribute("open")}filtered(){if(!this.filter.trim())return this.cmds;const e=this.filter.toLowerCase();return this.cmds.filter(t=>t.label.toLowerCase().includes(e))}runIdx(){const t=this.filtered()[this.idx];t&&(t.run(),this.closePal())}render(){const e=this.filtered();return c`
+
+
+ {this.filter=t.target.value,this.idx=0}} />
+
+
+ ${e.map((t,s)=>c`
+
{this.idx=s,this.runIdx()}}>
+ ${t.ico}
+ ${t.label}
+ ${t.kbd?c`${t.kbd} `:""}
+
+ `)}
+
+
+ `}};E.styles=m`
+ :host {
+ position: fixed; inset: 0; z-index: 220;
+ background: rgba(0,0,0,0.5);
+ opacity: 0; pointer-events: none;
+ transition: opacity 0.15s;
+ display: flex; justify-content: center; padding-top: 12vh;
+ backdrop-filter: blur(4px);
+ }
+ :host([open]) { opacity: 1; pointer-events: auto; }
+ .palette {
+ width: min(560px, 92vw);
+ background: var(--bg-1);
+ border: 1px solid var(--line-2);
+ border-radius: var(--radius);
+ box-shadow: 0 30px 80px -20px rgba(0,0,0,0.7);
+ overflow: hidden;
+ display: flex; flex-direction: column;
+ max-height: 60vh;
+ }
+ .input {
+ padding: 14px 16px;
+ border-bottom: 1px solid var(--line);
+ }
+ input {
+ width: 100%;
+ background: transparent; border: none; outline: none;
+ color: var(--ink); font-size: 14px;
+ font-family: inherit;
+ }
+ .list { flex: 1; overflow-y: auto; padding: 4px; }
+ .item {
+ display: flex; align-items: center; gap: 10px;
+ padding: 8px 12px;
+ border-radius: 6px;
+ cursor: pointer;
+ font-size: 12.5px;
+ }
+ .item.active { background: var(--bg-3); }
+ .item .ico { width: 20px; text-align: center; color: var(--accent); }
+ .item .lbl { flex: 1; }
+ .item .kbd {
+ font-family: var(--mono); font-size: 10.5px;
+ color: var(--ink-3);
+ padding: 1px 5px; background: var(--bg-3); border-radius: 4px;
+ }
+ `;J([u()],E.prototype,"open",2);J([u()],E.prototype,"filter",2);J([u()],E.prototype,"idx",2);J([Ie("#palette-input")],E.prototype,"inputEl",2);E=J([h("nv-palette")],E);var At=Object.defineProperty,Et=Object.getOwnPropertyDescriptor,Pe=(e,t,s,r)=>{for(var a=r>1?void 0:r?Et(t,s):t,i=e.length-1,n;i>=0;i--)(n=e[i])&&(a=(r?n(t,s,a):n(a))||a);return r&&a&&At(t,s,a),a};let G=class extends b{constructor(){super(...arguments),this.open=!1,this.renderFps=0,this.lastTs=performance.now(),this.frameCount=0,this.rafId=0,this.onKey=e=>{e.key==="`"&&!e.target.matches("input, textarea")&&(this.open=!this.open,this.toggleAttribute("open",this.open))},this.tick=()=>{this.rafId=requestAnimationFrame(this.tick);const e=performance.now();this.frameCount++,e-this.lastTs>=500&&(this.renderFps=this.frameCount*1e3/(e-this.lastTs),this.frameCount=0,this.lastTs=e,this.requestUpdate())}}connectedCallback(){super.connectedCallback(),window.addEventListener("keydown",this.onKey),x(()=>{k.value,$e.value,D.value,T.value,at.value,this.requestUpdate()}),this.tick()}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("keydown",this.onKey),cancelAnimationFrame(this.rafId)}render(){return c`
+ nvsim · debug {this.open=!1,this.removeAttribute("open")}}>✕
+ render fps ${this.renderFps.toFixed(1)}
+ sim fps ${k.value>0?Math.round(k.value):"—"}
+ frames ${$e.value.toString()}
+ |B| ${(D.value*1e9).toFixed(3)} nT
+ SNR ${T.value>0?T.value.toFixed(1):"—"}
+ DOM ${document.querySelectorAll("*").length}
+ `}};G.styles=m`
+ :host {
+ position: fixed; bottom: 8px; right: 8px;
+ width: 220px;
+ background: rgba(13,17,23,0.85);
+ backdrop-filter: blur(8px);
+ border: 1px solid var(--line-2);
+ border-radius: 8px;
+ padding: 8px 10px;
+ font-family: var(--mono); font-size: 11px;
+ color: var(--ink-2);
+ z-index: 99;
+ display: none;
+ box-shadow: var(--shadow);
+ }
+ :host([open]) { display: block; }
+ .h {
+ display: flex; justify-content: space-between;
+ font-weight: 600; color: var(--ink);
+ margin-bottom: 6px; padding-bottom: 4px;
+ border-bottom: 1px solid var(--line);
+ }
+ .x { cursor: pointer; color: var(--ink-3); }
+ .row {
+ display: flex; justify-content: space-between;
+ padding: 1px 0;
+ }
+ .k { color: var(--ink-3); }
+ .v { color: var(--ink); }
+ `;Pe([u()],G.prototype,"open",2);Pe([u()],G.prototype,"renderFps",2);G=Pe([h("nv-debug-hud")],G);var Ot=Object.defineProperty,Tt=Object.getOwnPropertyDescriptor,Ne=(e,t,s,r)=>{for(var a=r>1?void 0:r?Tt(t,s):t,i=e.length-1,n;i>=0;i--)(n=e[i])&&(a=(r?n(t,s,a):n(a))||a);return r&&a&&Ot(t,s,a),a};let ge=class extends b{constructor(){super(...arguments),this.open=!1}connectedCallback(){super.connectedCallback(),x(()=>{g.value,w.value,$.value,ae.value,_.value,ye.value,this.requestUpdate()}),window.addEventListener("open-settings",()=>{this.open=!0,this.setAttribute("open","")})}close(){this.open=!1,this.removeAttribute("open")}render(){return c`
+ this.close()}>
+
+
Settings
+
this.close()}>×
+
+
+
+
Appearance
+
+
+
+ g.value="dark"}>dark
+ g.value="light"}>light
+
+
+
+
+
Density
+
Affects panel padding and font scale.
+
+
+ w.value="comfy"}>comfy
+ w.value="default"}>default
+ w.value="compact"}>compact
+
+
+
+
+
Reduce motion
+
Disable rotating crystal & field-line animation.
+
+
$.value=!$.value}>
+
+
+
+
+
Pipeline
+
+
Auto-rerun on edit
+
Restart pipeline when scene/config changes.
+
ae.value=!ae.value}>
+
+
+
+
+
Transport
+
+
+
+ _.value="wasm"}>WASM
+ _.value="ws"}>WS
+
+
+ ${_.value==="ws"?c`
+
+
+
ye.value=e.target.value} />
+
`:""}
+
+
+ `}};ge.styles=m`
+ :host {
+ position: fixed; top: 0; right: 0; bottom: 0;
+ width: 420px; max-width: 100vw;
+ background: var(--bg-1);
+ border-left: 1px solid var(--line);
+ z-index: 51;
+ transform: translateX(100%);
+ transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);
+ display: flex; flex-direction: column;
+ box-shadow: -20px 0 60px -20px rgba(0,0,0,0.5);
+ }
+ :host([open]) { transform: translateX(0); }
+ .scrim {
+ position: fixed; inset: 0;
+ background: rgba(0,0,0,0.5);
+ z-index: 50;
+ opacity: 0; pointer-events: none;
+ transition: opacity 0.2s;
+ }
+ :host([open]) .scrim { opacity: 1; pointer-events: auto; }
+ .h {
+ padding: 14px 16px;
+ border-bottom: 1px solid var(--line);
+ display: flex; align-items: center; justify-content: space-between;
+ }
+ .h .ttl { font-size: 14px; font-weight: 600; }
+ .body { flex: 1; overflow-y: auto; padding: 16px; }
+ .group { margin-bottom: 22px; }
+ .group h4 {
+ margin: 0 0 10px;
+ font-size: 11px; font-weight: 600;
+ text-transform: uppercase; letter-spacing: 0.08em;
+ color: var(--ink-3);
+ }
+ .row {
+ display: flex; justify-content: space-between; align-items: center;
+ padding: 10px 0;
+ border-bottom: 1px solid var(--line);
+ }
+ .row:last-child { border-bottom: 0; }
+ .row .lbl { font-size: 13px; }
+ .row .desc { font-size: 11.5px; color: var(--ink-3); margin-top: 2px; }
+ .row > div:first-child { flex: 1; padding-right: 12px; }
+ .seg {
+ display: inline-flex;
+ background: var(--bg-3);
+ border: 1px solid var(--line);
+ border-radius: var(--radius-sm);
+ padding: 2px;
+ }
+ .seg button {
+ padding: 4px 10px;
+ background: transparent; border: none;
+ border-radius: 6px;
+ font-size: 11.5px; color: var(--ink-3);
+ font-family: var(--mono);
+ cursor: pointer;
+ }
+ .seg button.on { background: var(--bg-1); color: var(--ink); }
+ .toggle {
+ position: relative;
+ width: 36px; height: 20px;
+ background: var(--bg-3);
+ border: 1px solid var(--line-2);
+ border-radius: 999px;
+ cursor: pointer;
+ flex-shrink: 0;
+ }
+ .toggle::after {
+ content: ''; position: absolute;
+ top: 2px; left: 2px;
+ width: 14px; height: 14px;
+ background: var(--ink-3);
+ border-radius: 50%;
+ transition: transform 0.15s, background 0.15s;
+ }
+ .toggle.on { background: var(--accent); border-color: var(--accent); }
+ .toggle.on::after { background: #1a0f00; transform: translateX(16px); }
+ .close {
+ width: 28px; height: 28px;
+ background: transparent; border: 1px solid var(--line);
+ border-radius: 6px;
+ color: var(--ink-2);
+ }
+ input[type="text"] {
+ background: var(--bg-3);
+ border: 1px solid var(--line);
+ border-radius: 6px;
+ padding: 6px 10px;
+ color: var(--ink); font-family: var(--mono); font-size: 12px;
+ outline: none;
+ }
+ `;Ne([u()],ge.prototype,"open",2);ge=Ne([h("nv-settings-drawer")],ge);var Dt=Object.defineProperty,It=Object.getOwnPropertyDescriptor,Me=(e,t,s,r)=>{for(var a=r>1?void 0:r?It(t,s):t,i=e.length-1,n;i>=0;i--)(n=e[i])&&(a=(r?n(t,s,a):n(a))||a);return r&&a&&Dt(t,s,a),a};const re=[{title:"Welcome to nvsim",body:`nvsim is an open-source, deterministic forward simulator for
+ nitrogen-vacancy diamond magnetometry — a real Rust crate compiled to
+ WASM and running in your browser, right now.
+ This 30-second tour highlights the four panels you'll use most.
`,cta:"Start tour"},{title:"1. Scene canvas",body:`The middle panel shows your magnetic scene — sources you can
+ drag (rebar, heart proxy, mains hum, ferrous door) and a single NV-diamond
+ sensor in the centre. Field lines from each source connect to the sensor
+ and animate while the pipeline runs.
+ Click 2 on your keyboard any time to jump to the Frame inspector.
`},{title:"2. Run the pipeline",body:`Click the ▶ Run button (top-right) to start streaming
+ MagFrame records at the digitiser's sample rate. The B-vector
+ trace and Frame stream sparkline update live, and the FPS pill in the
+ topbar shows the simulator's throughput in kHz.
+ Space toggles run/pause from anywhere.
`},{title:"3. Witness panel",body:`The Witness tab is the heart of nvsim's determinism contract.
+ Click Verify and the pipeline re-derives the SHA-256 over a 256-frame
+ reference run and asserts it matches the constant pinned in the Rust crate.
+ Same input → same hash → byte-for-byte across browsers, OSes, transports.
+ If the hash drifts, your build is non-canonical.
`},{title:"4. App Store",body:`The grid icon on the left rail opens the App Store — every
+ hot-loadable WASM edge module RuView ships, plus the simulators. 66 apps
+ across 13 categories: medical, security, building, retail, industrial,
+ signal, learning, autonomy, and more.
+ Toggle any card to mark it active in this session; the WS transport
+ will push the activation set to a connected ESP32 mesh.
`},{title:"You are ready",body:`Press ⌘K (or Ctrl K ) any time for the command
+ palette, ? for the full shortcuts list, or just start clicking.
+ Source on GitHub:
+ github.com/ruvnet/RuView · ADR-089, ADR-092 · MIT/Apache-2.0.
`,cta:"Get started"}];let Y=class extends b{constructor(){super(...arguments),this.open=!1,this.step=0,this.show=()=>{this.step=0,this.open=!0,this.setAttribute("open","")}}async connectedCallback(){super.connectedCallback(),window.addEventListener("nv-show-tour",this.show),await V("onboarding-seen")||(this.open=!0,this.setAttribute("open",""))}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("nv-show-tour",this.show)}async dismiss(){this.open=!1,this.removeAttribute("open"),await K("onboarding-seen",!0)}next(){this.step0&&this.step--}render(){const e=re[this.step];return c`
+
+
+
${e.title}
+ this.dismiss()} aria-label="Skip tour">×
+
+
+
+
+ `}};Y.styles=m`
+ :host {
+ position: fixed; inset: 0;
+ background: rgba(0, 0, 0, 0.55);
+ backdrop-filter: blur(4px);
+ z-index: 240;
+ display: grid; place-items: center;
+ opacity: 0; pointer-events: none;
+ transition: opacity 0.18s;
+ }
+ :host([open]) { opacity: 1; pointer-events: auto; }
+ .card {
+ background: var(--bg-1);
+ border: 1px solid var(--line-2);
+ border-radius: var(--radius);
+ box-shadow: 0 30px 80px -20px rgba(0,0,0,0.7);
+ width: min(560px, 92vw);
+ max-height: 86vh;
+ display: flex; flex-direction: column;
+ transform: translateY(12px) scale(0.98);
+ transition: transform 0.22s cubic-bezier(0.2,0.7,0.3,1);
+ }
+ :host([open]) .card { transform: translateY(0) scale(1); }
+ .h {
+ padding: 20px 22px 8px;
+ display: flex; justify-content: space-between; align-items: flex-start;
+ }
+ .h h2 { margin: 0; font-size: 18px; letter-spacing: -0.01em; }
+ .body {
+ padding: 8px 22px 16px;
+ font-size: 13px; color: var(--ink-2); line-height: 1.55;
+ overflow-y: auto;
+ }
+ .body p { margin: 0 0 12px; }
+ .body code, .body kbd {
+ font-family: var(--mono); font-size: 11.5px;
+ padding: 1px 5px; background: var(--bg-3);
+ border: 1px solid var(--line); border-radius: 4px;
+ color: var(--accent);
+ }
+ .footer {
+ display: flex; align-items: center; gap: 12px;
+ padding: 12px 22px;
+ border-top: 1px solid var(--line);
+ }
+ .dots { display: flex; gap: 6px; flex: 1; }
+ .dot {
+ width: 6px; height: 6px; border-radius: 50%;
+ background: var(--bg-3); border: 1px solid var(--line-2);
+ }
+ .dot.active { background: var(--accent); border-color: var(--accent); }
+ button {
+ padding: 8px 14px;
+ border-radius: 8px;
+ font-size: 12.5px; font-weight: 500;
+ border: 1px solid var(--line);
+ background: var(--bg-2); color: var(--ink);
+ cursor: pointer;
+ font-family: inherit;
+ }
+ button.primary {
+ background: var(--accent); border-color: var(--accent);
+ color: #1a0f00;
+ }
+ button.ghost { background: transparent; }
+ .skip {
+ width: 28px; height: 28px;
+ background: transparent; border: 1px solid var(--line);
+ border-radius: 6px; color: var(--ink-2);
+ }
+ `;Me([u()],Y.prototype,"open",2);Me([u()],Y.prototype,"step",2);Y=Me([h("nv-onboarding")],Y);var Lt=Object.defineProperty,Ft=Object.getOwnPropertyDescriptor,Be=(e,t,s,r)=>{for(var a=r>1?void 0:r?Ft(t,s):t,i=e.length-1,n;i>=0;i--)(n=e[i])&&(a=(r?n(t,s,a):n(a))||a);return r&&a&&Lt(t,s,a),a};let me=class extends b{constructor(){super(...arguments),this.view="scene"}render(){return c`
+
+
this.view=e.detail}>
+
+
+
+ ${this.view==="apps"?c` `:c` `}
+
+
+
+
+
+
+
+
+
+
+ `}};me.styles=m`
+ :host {
+ display: block;
+ height: 100vh;
+ width: 100vw;
+ background: var(--bg-0);
+ }
+ .app {
+ display: grid;
+ grid-template-columns: 56px 280px 1fr 340px;
+ grid-template-rows: 48px 1fr 220px;
+ grid-template-areas:
+ 'rail topbar topbar topbar'
+ 'rail sidebar main inspector'
+ 'rail sidebar console inspector';
+ height: 100vh;
+ width: 100vw;
+ }
+ nv-rail { grid-area: rail; }
+ nv-topbar { grid-area: topbar; }
+ nv-sidebar { grid-area: sidebar; }
+ .main { grid-area: main; min-width: 0; min-height: 0; position: relative; overflow: hidden; }
+ nv-inspector { grid-area: inspector; }
+ nv-console { grid-area: console; min-height: 0; }
+ @media (max-width: 1180px) {
+ .app {
+ grid-template-columns: 56px 1fr 320px;
+ grid-template-areas:
+ 'rail topbar topbar'
+ 'rail main inspector'
+ 'rail console console';
+ }
+ nv-sidebar { display: none; }
+ }
+ @media (max-width: 860px) {
+ .app {
+ grid-template-columns: 1fr;
+ grid-template-rows: 52px 1fr 200px;
+ grid-template-areas:
+ 'topbar'
+ 'main'
+ 'console';
+ }
+ nv-rail, nv-sidebar, nv-inspector { display: none; }
+ }
+ `;Be([u()],me.prototype,"view",2);me=Be([h("nv-app")],me);function Rt(e,t,s){const r=e.getUint32(t+0,!0),a=e.getUint16(t+4,!0),i=e.getUint16(t+6,!0),n=e.getUint16(t+8,!0),d=e.getBigUint64(t+12,!0),p=e.getFloat32(t+20,!0),O=e.getFloat32(t+24,!0),fe=e.getFloat32(t+28,!0),xe=e.getFloat32(t+32,!0),Ue=e.getFloat32(t+36,!0),qe=e.getFloat32(t+40,!0),Ve=e.getFloat32(t+44,!0),Ke=e.getFloat32(t+48,!0);return{magic:r,version:a,flags:i,sensorId:n,tUs:d,bPt:[p,O,fe],sigmaPt:[xe,Ue,qe],noiseFloorPtSqrtHz:Ve,temperatureK:Ke,raw:s.subarray(t,t+60)}}function jt(e){const s=new DataView(e.buffer,e.byteOffset,e.byteLength),r=[];for(let a=0;a+60<=e.byteLength;a+=60)r.push(Rt(s,a,e));return r}class Ht{constructor(){this.nextId=1,this.pending=new Map,this.frameSubs=new Set,this.eventSubs=new Set,this.bootInfo=null,this.worker=new Worker(new URL("/RuView/nvsim/assets/worker-BW0kLvYS.js",import.meta.url),{type:"module"}),this.worker.addEventListener("message",t=>this.onMessage(t)),this.worker.addEventListener("error",t=>this.eventSubs.forEach(s=>s({type:"log",level:"err",msg:String(t.message)})))}onMessage(t){const s=t.data;if(s.type==="frames"){const r=s.batch,a=new Uint8Array(r),n={frames:jt(a),bytes:a};this.frameSubs.forEach(p=>p(n));const d=s.fps;d>0&&this.eventSubs.forEach(p=>p({type:"fps",value:d}));return}if(s.type==="state"){this.eventSubs.forEach(r=>r({type:"state",running:!!s.running,t:0,framesEmitted:Number(s.framesEmitted??0)}));return}if(s.type!=="ready"){if(s.type==="err"&&s.id==null){this.eventSubs.forEach(r=>r({type:"log",level:"err",msg:String(s.msg)}));return}if(typeof s.id=="number"&&this.pending.has(s.id)){const r=this.pending.get(s.id);this.pending.delete(s.id),s.type==="err"?r.reject(new Error(String(s.msg))):r.resolve(s)}}}rpc(t,s=[]){const r=this.nextId++;return new Promise((a,i)=>{this.pending.set(r,{resolve:a,reject:i}),this.worker.postMessage({...t,id:r},s)})}async boot(){if(this.bootInfo)return this.bootInfo;const s=await this.rpc({type:"boot",base:"/RuView/nvsim/"});return this.bootInfo={buildVersion:s.buildVersion,frameMagic:s.frameMagic,frameBytes:s.frameBytes,expectedWitnessHex:s.expectedWitnessHex},this.bootInfo}async loadScene(t){await this.rpc({type:"setScene",json:JSON.stringify(t)})}async setConfig(t){await this.rpc({type:"setConfig",json:JSON.stringify(t)})}async setSeed(t){await this.rpc({type:"setSeed",seed:Number(t&0xFFFFFFFFn)})}async reset(){await this.rpc({type:"reset"})}async run(t){await this.rpc({type:"run"})}async pause(){await this.rpc({type:"pause"})}async step(t,s){await this.rpc({type:"step"})}onFrames(t){this.frameSubs.add(t)}onEvent(t){this.eventSubs.add(t)}async generateWitness(t){const s=await this.rpc({type:"witnessGenerate",samples:t});return new Uint8Array(s.witness)}async verifyWitness(t){const s=t.slice().buffer,r=await this.rpc({type:"witnessVerify",samples:256,expected:s},[s]);return r.ok?{ok:!0}:{ok:!1,actual:new Uint8Array(r.actual)}}async exportProofBundle(){const t=await this.generateWitness(256),s=Array.from(t).map(i=>i.toString(16).padStart(2,"0")).join(""),r=this.bootInfo??await this.boot(),a=JSON.stringify({kind:"nvsim-proof-bundle",version:r.buildVersion,seed:"0x0000002A",nSamples:256,witness:s,expected:r.expectedWitnessHex,ok:s===r.expectedWitnessHex,ts:new Date().toISOString()},null,2);return new Blob([a],{type:"application/json"})}async buildId(){return(await this.rpc({type:"buildId"})).buildId}async close(){this.worker.terminate()}}function Ee(e){document.documentElement.setAttribute("data-theme",e)}function Oe(e){document.body.classList.remove("density-comfy","density-default","density-compact"),document.body.classList.add(`density-${e}`)}function Te(e){document.body.classList.toggle("reduce-motion",e)}(async()=>{const e=await V("theme")??"dark",t=await V("density")??"default",s=await V("motionReduced")??!1;g.value=e,Ee(e),w.value=t,Oe(t),$.value=s,Te(s),x(()=>{Ee(g.value),K("theme",g.value)}),x(()=>{Oe(w.value),K("density",w.value)}),x(()=>{Te($.value),K("motionReduced",$.value)});const r=new Ht;rt(r),l("info","nvsim — booting WASM runtime"),r.onEvent(a=>{a.type==="log"&&l(a.level,a.msg),a.type==="fps"&&(k.value=a.value),a.type==="state"&&($e.value=BigInt(a.framesEmitted))}),r.onFrames(a=>{if(a.frames.length===0)return;const i=a.frames[a.frames.length-1];_e.value=i;const n=i.bPt[0]*1e-12,d=i.bPt[1]*1e-12,p=i.bPt[2]*1e-12;ne.value=[n,d,p],D.value=Math.sqrt(n*n+d*d+p*p),nt([n*1e9,d*1e9,p*1e9]);const O=Math.min(1,Math.abs(p*1e9)/5+.3);ot(O)});try{const a=await r.boot();I.value=a.expectedWitnessHex,l("ok",`WASM module ready · nvsim@${a.buildVersion} · magic=0x${a.frameMagic.toString(16).toUpperCase()}`),l("info",`expected witness · ${a.expectedWitnessHex.slice(0,16)}…`),st.value="(reference scene)",_.value="wasm"}catch(a){l("err",`boot failed: ${a.message}`)}try{const a=I.value;if(a){const i=new Uint8Array(32);for(let d=0;d<32;d++)i[d]=parseInt(a.slice(d*2,d*2+2),16);const n=await r.verifyWitness(i);if(n.ok)C.value=a,l("ok","witness verified · determinism gate ✓");else{const d=Array.from(n.actual).map(p=>p.toString(16).padStart(2,"0")).join("");C.value=d,l("err",`WITNESS MISMATCH · expected ${a.slice(0,16)}… got ${d.slice(0,16)}…`)}}}catch(a){l("warn",`witness verify skipped: ${a.message}`)}})();
+//# sourceMappingURL=index-C2Z9YIJa.js.map
diff --git a/nvsim/assets/index-C2Z9YIJa.js.map b/nvsim/assets/index-C2Z9YIJa.js.map
new file mode 100644
index 00000000..f47e537e
--- /dev/null
+++ b/nvsim/assets/index-C2Z9YIJa.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"index-C2Z9YIJa.js","sources":["../../node_modules/@lit/reactive-element/decorators/custom-element.js","../../node_modules/@lit/reactive-element/decorators/property.js","../../node_modules/@lit/reactive-element/decorators/state.js","../../node_modules/@lit/reactive-element/decorators/base.js","../../node_modules/@lit/reactive-element/decorators/query.js","../../src/components/nv-rail.ts","../../src/store/appStore.ts","../../src/components/nv-topbar.ts","../../src/components/nv-sidebar.ts","../../src/components/nv-scene.ts","../../src/components/nv-inspector.ts","../../src/components/nv-console.ts","../../src/store/apps.ts","../../src/store/persistence.ts","../../src/components/nv-app-store.ts","../../src/components/nv-toast.ts","../../src/components/nv-modal.ts","../../src/components/nv-palette.ts","../../src/components/nv-debug-hud.ts","../../src/components/nv-settings-drawer.ts","../../src/components/nv-onboarding.ts","../../src/components/nv-app.ts","../../src/transport/NvsimClient.ts","../../src/transport/WasmClient.ts","../../src/main.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\nconst t=t=>(e,o)=>{void 0!==o?o.addInitializer(()=>{customElements.define(t,e)}):customElements.define(t,e)};export{t as customElement};\n//# sourceMappingURL=custom-element.js.map\n","import{notEqual as t,defaultConverter as e}from\"../reactive-element.js\";\n/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */const o={attribute:!0,type:String,converter:e,reflect:!1,hasChanged:t},r=(t=o,e,r)=>{const{kind:n,metadata:i}=r;let s=globalThis.litPropertyMetadata.get(i);if(void 0===s&&globalThis.litPropertyMetadata.set(i,s=new Map),\"setter\"===n&&((t=Object.create(t)).wrapped=!0),s.set(r.name,t),\"accessor\"===n){const{name:o}=r;return{set(r){const n=e.get.call(this);e.set.call(this,r),this.requestUpdate(o,n,t,!0,r)},init(e){return void 0!==e&&this.C(o,void 0,t,e),e}}}if(\"setter\"===n){const{name:o}=r;return function(r){const n=this[o];e.call(this,r),this.requestUpdate(o,n,t,!0,r)}}throw Error(\"Unsupported decorator location: \"+n)};function n(t){return(e,o)=>\"object\"==typeof o?r(t,e,o):((t,e,o)=>{const r=e.hasOwnProperty(o);return e.constructor.createProperty(o,t),r?Object.getOwnPropertyDescriptor(e,o):void 0})(t,e,o)}export{n as property,r as standardProperty};\n//# sourceMappingURL=property.js.map\n","import{property as t}from\"./property.js\";\n/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */function r(r){return t({...r,state:!0,attribute:!1})}export{r as state};\n//# sourceMappingURL=state.js.map\n","/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\nconst e=(e,t,c)=>(c.configurable=!0,c.enumerable=!0,Reflect.decorate&&\"object\"!=typeof t&&Object.defineProperty(e,t,c),c);export{e as desc};\n//# sourceMappingURL=base.js.map\n","import{desc as t}from\"./base.js\";\n/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */function e(e,r){return(n,s,i)=>{const o=t=>t.renderRoot?.querySelector(e)??null;if(r){const{get:e,set:r}=\"object\"==typeof s?n:i??(()=>{const t=Symbol();return{get(){return this[t]},set(e){this[t]=e}}})();return t(n,s,{get(){let t=e.call(this);return void 0===t&&(t=o(this),(null!==t||this.hasUpdated)&&r.call(this,t)),t}})}return t(n,s,{get(){return o(this)}})}}export{e as query};\n//# sourceMappingURL=query.js.map\n","/* Left rail navigation. Emits `navigate` events for view switching. */\nimport { LitElement, html, css } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type { View } from './nv-app';\n\n@customElement('nv-rail')\nexport class NvRail extends LitElement {\n @property() view: View = 'scene';\n\n static styles = css`\n :host {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 10px 0;\n gap: 4px;\n background: var(--bg-1);\n border-right: 1px solid var(--line);\n }\n .logo {\n width: 36px; height: 36px;\n border-radius: 10px;\n background: linear-gradient(135deg, oklch(0.78 0.14 70) 0%, oklch(0.55 0.16 30) 100%);\n display: grid; place-items: center;\n color: #1a0f00;\n font-weight: 700;\n font-family: var(--mono);\n font-size: 11px;\n margin-bottom: 14px;\n box-shadow: 0 4px 12px -2px oklch(0.55 0.16 30 / 0.35);\n }\n .btn {\n width: 36px; height: 36px;\n border-radius: 8px;\n background: transparent;\n border: 1px solid transparent;\n color: var(--ink-3);\n display: grid; place-items: center;\n transition: all 0.15s;\n position: relative;\n cursor: pointer;\n }\n .btn:hover { color: var(--ink); background: var(--bg-2); }\n .btn.active {\n color: var(--ink);\n background: var(--bg-3);\n border-color: var(--line-2);\n }\n .btn.active::before {\n content: ''; position: absolute; left: -10px; top: 8px; bottom: 8px;\n width: 2px; background: var(--accent); border-radius: 2px;\n }\n .spacer { flex: 1; }\n svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.8; }\n `;\n\n private navigate(v: View): void {\n this.dispatchEvent(new CustomEvent('navigate', { detail: v }));\n }\n\n override render() {\n return html`\n NV
\n this.navigate('scene')}>\n \n \n this.navigate('apps')}>\n \n \n this.navigate('scene')}>\n \n \n \n \n \n
\n this.dispatchEvent(new CustomEvent('open-settings', { bubbles: true, composed: true }))}>\n \n \n `;\n }\n}\n","/* Application-wide reactive state.\n *\n * One signal per logical observable; components subscribe to only the\n * signals they read. Keeps re-renders surgical even at 1 kHz frame rates.\n * Persistence lives in `persistence.ts`; this module is pure state.\n */\nimport { signal, computed } from '@preact/signals-core';\nimport type { NvsimClient, MagFrameRecord, NvsimEvent } from '../transport/NvsimClient';\n\nexport type Theme = 'dark' | 'light';\nexport type Density = 'comfy' | 'default' | 'compact';\nexport type TransportMode = 'wasm' | 'ws';\n\nexport const transport = signal('wasm');\nexport const wsUrl = signal('');\nexport const connected = signal(false);\nexport const transportError = signal(null);\n\nexport const running = signal(false);\nexport const paused = signal(true);\nexport const speed = signal(1.0);\nexport const t = signal(0); // sim time (s)\nexport const framesEmitted = signal(0n);\n\nexport const seed = signal(0xCAFEBABEn);\n\nexport const fs = signal(10000); // sample rate Hz\nexport const fmod = signal(1000); // lockin Hz\nexport const dtMs = signal(1.0);\nexport const noiseEnabled = signal(true);\n\nexport const theme = signal('dark');\nexport const density = signal('default');\nexport const motionReduced = signal(false);\nexport const autoUpdate = signal(true);\n\nexport const lastB = signal<[number, number, number]>([0, 0, 0]); // T\nexport const bMag = signal(0);\nexport const snr = signal(0);\nexport const fps = signal(0);\n\nexport const witnessHex = signal('');\nexport const witnessVerified = signal<'pending' | 'ok' | 'fail' | 'idle'>('idle');\nexport const expectedWitness = signal('');\n\nexport const lastFrame = signal(null);\nexport const traceX = signal([]);\nexport const traceY = signal([]);\nexport const traceZ = signal([]);\nexport const stripBars = signal([]);\n\nexport const sceneName = signal('rebar-walkby-01');\nexport const sceneJson = signal('');\n\nexport const consolePaused = signal(false);\nexport const consoleFilter = signal<'all' | 'info' | 'warn' | 'err' | 'dbg' | 'ok'>('all');\n\nexport const transportLabel = computed(() =>\n transport.value === 'wasm' ? 'wasm' : 'ws',\n);\n\nlet _client: NvsimClient | null = null;\nexport function setClient(c: NvsimClient): void { _client = c; }\nexport function getClient(): NvsimClient | null { return _client; }\n\nexport interface ConsoleLine {\n ts: number;\n level: 'info' | 'warn' | 'err' | 'dbg' | 'ok';\n msg: string;\n}\nexport const consoleLines = signal([]);\nconst MAX_LINES = 200;\n\nexport function pushLog(level: ConsoleLine['level'], msg: string): void {\n if (consolePaused.value) return;\n const next = consoleLines.value.slice();\n next.push({ ts: Date.now(), level, msg });\n while (next.length > MAX_LINES) next.shift();\n consoleLines.value = next;\n}\n\nexport function pushTrace(b: [number, number, number]): void {\n const cap = 200;\n const x = traceX.value.slice(); x.push(b[0]); if (x.length > cap) x.shift();\n const y = traceY.value.slice(); y.push(b[1]); if (y.length > cap) y.shift();\n const z = traceZ.value.slice(); z.push(b[2]); if (z.length > cap) z.shift();\n traceX.value = x;\n traceY.value = y;\n traceZ.value = z;\n}\n\nexport function pushStripBar(amp: number): void {\n const cap = 48;\n const next = stripBars.value.slice();\n next.push(Math.max(0, Math.min(1, amp)));\n while (next.length > cap) next.shift();\n stripBars.value = next;\n}\n\nexport function recordEvent(_ev: NvsimEvent): void {\n // future: route NvsimEvent into store updates per type. For V1 the\n // worker pushes B-vector / frame data directly via the data plane.\n}\n","/* Topbar — breadcrumbs, transport pill, FPS pill, seed pill, controls. */\nimport { LitElement, html, css } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport { effect } from '@preact/signals-core';\nimport {\n fps, transportLabel, seed, theme, sceneName,\n running, getClient,\n} from '../store/appStore';\n\n@customElement('nv-topbar')\nexport class NvTopbar extends LitElement {\n static styles = css`\n :host {\n display: flex; align-items: center;\n padding: 0 16px; gap: 12px;\n background: var(--bg-1);\n border-bottom: 1px solid var(--line);\n z-index: 10;\n }\n .crumbs { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--ink-3); }\n .crumbs .sep { color: var(--ink-4); }\n .crumbs .cur { color: var(--ink); font-weight: 500; }\n .spacer { flex: 1; }\n .pill {\n display: inline-flex; align-items: center; gap: 6px;\n padding: 5px 10px;\n background: var(--bg-2); border: 1px solid var(--line);\n border-radius: 999px;\n font-size: 12px; color: var(--ink-2);\n font-family: var(--mono); font-weight: 500;\n }\n .pill .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--ok); box-shadow: 0 0 6px var(--ok); animation: pulse 2s infinite; }\n .pill.wasm .dot { background: var(--accent-2); box-shadow: 0 0 6px var(--accent-2); }\n .pill.seed { color: var(--ink-3); }\n .pill.seed b { color: var(--accent); font-weight: 600; }\n button {\n display: inline-flex; align-items: center; gap: 6px;\n padding: 6px 12px;\n background: var(--bg-2); border: 1px solid var(--line);\n border-radius: 8px;\n font-size: 12.5px; font-weight: 500; color: var(--ink);\n cursor: pointer;\n transition: all 0.15s;\n }\n button:hover { border-color: var(--line-2); background: var(--bg-3); }\n button.primary { background: var(--accent); border-color: var(--accent); color: #1a0f00; }\n button.primary:hover { filter: brightness(1.08); }\n button.ghost { background: transparent; }\n `;\n\n override connectedCallback(): void {\n super.connectedCallback();\n effect(() => { fps.value; transportLabel.value; seed.value; theme.value; sceneName.value; running.value; this.requestUpdate(); });\n }\n\n private async toggleRun(): Promise {\n const c = getClient(); if (!c) return;\n if (running.value) { await c.pause(); running.value = false; }\n else { await c.run(); running.value = true; }\n }\n private async reset(): Promise {\n const c = getClient(); if (!c) return;\n await c.reset();\n }\n private toggleTheme(): void {\n theme.value = theme.value === 'dark' ? 'light' : 'dark';\n }\n\n override render() {\n const seedHex = seed.value.toString(16).toUpperCase().padStart(8, '0');\n return html`\n \n RuView / \n nvsim / \n ${sceneName.value} \n
\n
\n \n \n ${fps.value > 0 ? (fps.value / 1000).toFixed(2) + ' kHz' : 'idle'} \n \n ${transportLabel.value} \n seed: 0x${seedHex} \n \n ${theme.value === 'dark' ? '☼' : '☾'}\n \n ↺ Reset \n \n ${running.value ? '❚❚ Pause' : '▶ Run'}\n \n `;\n }\n}\n","/* Sidebar — Scene panel, NV sensor panel, Tunables, Pipeline diagram. */\nimport { LitElement, html, css } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport { effect } from '@preact/signals-core';\nimport { fs, fmod, dtMs, noiseEnabled, running } from '../store/appStore';\n\n@customElement('nv-sidebar')\nexport class NvSidebar extends LitElement {\n static styles = css`\n :host {\n display: flex; flex-direction: column; gap: 14px;\n padding: 14px; overflow-y: auto;\n background: var(--bg-1); border-right: 1px solid var(--line);\n }\n .panel {\n background: var(--bg-2); border: 1px solid var(--line);\n border-radius: var(--radius); padding: 12px;\n }\n .panel-h {\n display: flex; align-items: center; justify-content: space-between;\n font-size: 11px; font-weight: 600; color: var(--ink-3);\n text-transform: uppercase; letter-spacing: 0.08em;\n margin-bottom: 10px;\n }\n .count {\n background: var(--bg-3); color: var(--ink-2);\n padding: 1px 6px; border-radius: 999px;\n font-family: var(--mono); font-size: 10px;\n text-transform: none; letter-spacing: 0;\n }\n .scene-item {\n display: flex; align-items: center; gap: 10px;\n padding: 8px 10px;\n border-radius: var(--radius-sm);\n cursor: pointer;\n transition: background 0.15s;\n border: 1px solid transparent;\n }\n .scene-item:hover { background: var(--bg-3); }\n .scene-item .swatch { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }\n .scene-item .name { font-size: 13px; flex: 1; }\n .scene-item .meta { font-family: var(--mono); font-size: 10.5px; color: var(--ink-3); }\n .field-row {\n display: flex; align-items: center; justify-content: space-between;\n padding: 6px 0; font-size: 12.5px;\n border-bottom: 1px solid var(--line);\n }\n .field-row:last-child { border-bottom: 0; }\n .field-row .lbl { color: var(--ink-3); }\n .field-row .val { font-family: var(--mono); color: var(--ink); font-size: 12px; }\n .slider-row { padding: 8px 0; border-bottom: 1px solid var(--line); }\n .slider-row:last-child { border-bottom: 0; padding-bottom: 0; }\n .slider-row .top { display: flex; justify-content: space-between; margin-bottom: 6px; font-size: 12px; }\n .slider-row .top .lbl { color: var(--ink-3); }\n .slider-row .top .val { font-family: var(--mono); color: var(--ink); }\n input[type=\"range\"] {\n -webkit-appearance: none; appearance: none;\n width: 100%; height: 4px;\n background: var(--bg-3); border-radius: 2px; outline: none;\n }\n input[type=\"range\"]::-webkit-slider-thumb {\n -webkit-appearance: none; appearance: none;\n width: 14px; height: 14px; border-radius: 50%;\n background: var(--accent); cursor: pointer;\n border: 2px solid var(--bg-2);\n box-shadow: 0 0 0 1px var(--line-2);\n }\n .pipeline { display: flex; gap: 4px; align-items: center; flex-wrap: wrap; margin-top: 6px; }\n .stage {\n flex: 1; min-width: 50px;\n padding: 4px 6px;\n background: var(--bg-3); border: 1px solid var(--line);\n border-radius: 6px; font-size: 9.5px; text-align: center;\n color: var(--ink-2); font-family: var(--mono);\n }\n .stage.live { border-color: var(--accent-2); color: var(--accent-2); }\n .stage-arrow { color: var(--ink-4); font-size: 10px; }\n `;\n\n override connectedCallback(): void {\n super.connectedCallback();\n effect(() => { fs.value; fmod.value; dtMs.value; noiseEnabled.value; running.value; this.requestUpdate(); });\n }\n\n override render() {\n return html`\n \n
Scene 4 sources
\n
\n \n rebar.steel.coil \n χ=5000 \n
\n
\n \n heart_proxy \n 1e-6 A·m² \n
\n
\n \n mains_60Hz \n 2 A · 60 Hz \n
\n
\n \n door.steel \n eddy \n
\n
\n\n \n
NV sensor COTS
\n
V 1 mm³
\n
N 1e12 NV
\n
C 0.030
\n
T₂* 200 ns
\n
δB 1.18 pT/√Hz
\n
\n\n \n
Tunables
\n
\n
Sample rate ${(fs.value / 1000).toFixed(1)} kHz
\n
fs.value = +(e.target as HTMLInputElement).value} />\n
\n
\n
Lockin f_mod ${(fmod.value / 1000).toFixed(3)} kHz
\n
fmod.value = +(e.target as HTMLInputElement).value} />\n
\n
\n
Integration t ${dtMs.value.toFixed(1)} ms
\n
dtMs.value = +(e.target as HTMLInputElement).value} />\n
\n
\n
Shot noise ${noiseEnabled.value ? 'ON' : 'OFF'}
\n
noiseEnabled.value = (e.target as HTMLInputElement).value === '1'} />\n
\n
\n\n \n
Pipeline
\n
\n scene \n → \n B-S \n → \n prop \n → \n NV \n → \n ADC \n → \n frame \n
\n
\n `;\n }\n}\n","/* Scene canvas — SVG with draggable sources, NV crystal sensor, field lines, mini ODMR. */\nimport { LitElement, html, css, svg } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\nimport { effect } from '@preact/signals-core';\nimport { lastB, bMag, fps, snr, motionReduced } from '../store/appStore';\n\ninterface SceneItem { id: string; x: number; y: number; color: string; name: string; }\n\n@customElement('nv-scene')\nexport class NvScene extends LitElement {\n @state() private items: SceneItem[] = [\n { id: 'rebar', x: 740, y: 240, color: 'oklch(0.72 0.18 330)', name: 'rebar.steel' },\n { id: 'heart', x: 220, y: 180, color: 'oklch(0.78 0.14 195)', name: 'heart_proxy' },\n { id: 'mains', x: 180, y: 380, color: 'oklch(0.72 0.18 330)', name: 'mains_60Hz' },\n { id: 'door', x: 800, y: 470, color: 'oklch(0.78 0.14 145)', name: 'door.steel' },\n ];\n @state() private dragging: string | null = null;\n @state() private selected: string | null = null;\n private dragOffset = { dx: 0, dy: 0 };\n\n static styles = css`\n :host {\n display: block; height: 100%; width: 100%;\n background: radial-gradient(ellipse at 50% 30%, var(--bg-2) 0%, var(--bg-0) 70%);\n position: relative; overflow: hidden;\n border-bottom: 1px solid var(--line);\n }\n .grid {\n position: absolute; inset: 0;\n background-image:\n linear-gradient(var(--grid) 1px, transparent 1px),\n linear-gradient(90deg, var(--grid) 1px, transparent 1px);\n background-size: 32px 32px;\n pointer-events: none;\n mask-image: radial-gradient(ellipse at center, black 40%, transparent 100%);\n }\n svg { position: absolute; inset: 0; width: 100%; height: 100%; }\n .stat-card {\n background: rgba(13,17,23,0.7);\n backdrop-filter: blur(8px);\n border: 1px solid var(--line);\n border-radius: var(--radius-sm);\n padding: 8px 12px;\n font-size: 11px;\n min-width: 96px;\n }\n [data-theme=\"light\"] .stat-card { background: rgba(255,255,255,0.85); }\n .stat-card .lbl {\n color: var(--ink-3);\n text-transform: uppercase; font-weight: 600; letter-spacing: 0.06em; font-size: 9.5px;\n }\n .stat-card .val { font-family: var(--mono); font-size: 16px; font-weight: 600; margin-top: 2px; }\n .stat-card .val.amber { color: var(--accent); }\n .stat-card .val.cyan { color: var(--accent-2); }\n .stat-card .val.mint { color: var(--accent-4); }\n .scene-readout {\n position: absolute; top: 14px; right: 14px;\n display: flex; gap: 8px; z-index: 5;\n }\n .draggable { cursor: grab; transition: filter 0.15s; }\n .draggable:hover { filter: brightness(1.15) drop-shadow(0 0 6px currentColor); }\n .draggable.dragging { cursor: grabbing; filter: brightness(1.25) drop-shadow(0 0 10px currentColor); }\n .field-line { stroke-dasharray: 4 6; }\n @keyframes dash { to { stroke-dashoffset: -200; } }\n .field-line.anim { animation: dash 4s linear infinite; }\n @keyframes spin {\n 0% { transform: rotateY(0) rotateX(8deg); }\n 100% { transform: rotateY(360deg) rotateX(8deg); }\n }\n .crystal { transform-origin: center; transform-box: fill-box; }\n .crystal.anim { animation: spin 12s linear infinite; }\n .label {\n font-family: var(--mono); font-size: 11px; fill: var(--ink-2);\n pointer-events: none;\n }\n `;\n\n override connectedCallback(): void {\n super.connectedCallback();\n effect(() => { lastB.value; bMag.value; fps.value; snr.value; motionReduced.value; this.requestUpdate(); });\n window.addEventListener('pointermove', this.onPointerMove);\n window.addEventListener('pointerup', this.onPointerUp);\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n window.removeEventListener('pointermove', this.onPointerMove);\n window.removeEventListener('pointerup', this.onPointerUp);\n }\n\n private onDown = (id: string, e: PointerEvent): void => {\n e.preventDefault();\n this.dragging = id;\n this.selected = id;\n const item = this.items.find((i) => i.id === id);\n if (!item) return;\n const svgEl = this.renderRoot.querySelector('svg') as SVGSVGElement | null;\n if (!svgEl) return;\n const pt = this.toSvg(e, svgEl);\n this.dragOffset = { dx: pt.x - item.x, dy: pt.y - item.y };\n };\n\n private onPointerMove = (e: PointerEvent): void => {\n if (!this.dragging) return;\n const svgEl = this.renderRoot.querySelector('svg') as SVGSVGElement | null;\n if (!svgEl) return;\n const pt = this.toSvg(e, svgEl);\n this.items = this.items.map((it) =>\n it.id === this.dragging\n ? { ...it, x: pt.x - this.dragOffset.dx, y: pt.y - this.dragOffset.dy }\n : it,\n );\n };\n\n private onPointerUp = (): void => { this.dragging = null; };\n\n private toSvg(e: PointerEvent, svgEl: SVGSVGElement): { x: number; y: number } {\n const r = svgEl.getBoundingClientRect();\n const vbX = ((e.clientX - r.left) / r.width) * 1000;\n const vbY = ((e.clientY - r.top) / r.height) * 600;\n return { x: vbX, y: vbY };\n }\n\n override render() {\n const b = lastB.value;\n const bnT = [b[0] * 1e9, b[1] * 1e9, b[2] * 1e9];\n const bMagNT = bMag.value * 1e9;\n const animClass = motionReduced.value ? '' : 'anim';\n\n return html`\n
\n \n \n \n \n \n \n \n \n\n \n ${this.items.map((it) => svg`\n \n `)}\n\n \n ${this.items.map((it) => svg`\n this.onDown(it.id, e)}>\n \n \n ${it.name} \n \n `)}\n\n \n \n \n \n \n \n \n \n sensor · 〈111〉 NV\n \n \n B_in: [${bnT[0].toFixed(2)}, ${bnT[1].toFixed(2)}, ${bnT[2].toFixed(2)}] nT \n \n \n \n\n \n
\n
|B|
\n
${bMagNT.toFixed(3)} nT
\n
\n
\n
FPS
\n
${fps.value > 0 ? Math.round(fps.value) : '—'}
\n
\n
\n
SNR
\n
${snr.value > 0 ? snr.value.toFixed(1) : '—'}
\n
\n
\n `;\n }\n}\n","/* Inspector — tabbed: Signal / Frame / Witness. */\nimport { LitElement, html, css, svg } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\nimport { effect } from '@preact/signals-core';\nimport {\n traceX, traceY, traceZ, stripBars, lastFrame,\n witnessHex, expectedWitness, witnessVerified, getClient,\n pushLog, lastB, bMag,\n} from '../store/appStore';\n\ntype Tab = 'signal' | 'frame' | 'witness';\n\n@customElement('nv-inspector')\nexport class NvInspector extends LitElement {\n @state() private tab: Tab = 'signal';\n\n static styles = css`\n :host {\n display: flex; flex-direction: column;\n background: var(--bg-1);\n border-left: 1px solid var(--line);\n overflow: hidden;\n height: 100%;\n }\n .tabs {\n display: flex; border-bottom: 1px solid var(--line);\n }\n .tab {\n flex: 1;\n padding: 11px 8px;\n background: transparent; border: none;\n font-size: 11.5px; font-weight: 500;\n color: var(--ink-3);\n border-bottom: 2px solid transparent;\n cursor: pointer; transition: color 0.15s, border-color 0.15s;\n }\n .tab.active { color: var(--ink); border-bottom-color: var(--accent); }\n .tab:hover { color: var(--ink-2); }\n .body { padding: 14px; flex: 1; overflow-y: auto; }\n\n .card {\n background: var(--bg-2); border: 1px solid var(--line);\n border-radius: var(--radius); padding: 12px;\n margin-bottom: 12px;\n }\n .card-h {\n display: flex; justify-content: space-between; align-items: center;\n margin-bottom: 8px;\n }\n .card-h .ttl { font-size: 12px; font-weight: 600; }\n .badge {\n font-family: var(--mono); font-size: 10px;\n padding: 2px 6px;\n background: oklch(0.78 0.14 195 / 0.12);\n color: var(--accent-2);\n border-radius: 4px;\n border: 1px solid oklch(0.78 0.14 195 / 0.3);\n }\n svg { width: 100%; height: 130px; }\n .frame-strip {\n height: 28px;\n display: flex; align-items: flex-end; gap: 1px;\n padding: 4px 0;\n }\n .bar {\n flex: 1;\n background: linear-gradient(to top, var(--accent-2), var(--accent));\n border-radius: 1px;\n min-height: 2px;\n }\n table { width: 100%; border-collapse: collapse; font-family: var(--mono); font-size: 10.5px; }\n td { padding: 4px 0; border-bottom: 1px solid var(--line); }\n td:first-child { color: var(--ink-3); }\n td:last-child { text-align: right; color: var(--ink); }\n .hex {\n background: var(--bg-3);\n border: 1px solid var(--line);\n border-radius: var(--radius-sm);\n padding: 10px;\n font-family: var(--mono);\n font-size: 10.5px;\n color: var(--ink-2);\n line-height: 1.6;\n overflow-x: auto;\n white-space: nowrap;\n }\n .hex .magic { color: var(--accent); font-weight: 600; }\n .witness-box {\n font-family: var(--mono);\n font-size: 11px;\n color: var(--ink-2);\n background: var(--bg-3);\n border: 1px solid var(--line);\n border-radius: 6px;\n padding: 8px 10px;\n word-break: break-all;\n line-height: 1.5;\n }\n .verify-btn {\n margin-top: 10px;\n width: 100%;\n padding: 8px;\n border: 1px solid var(--line);\n background: var(--bg-3);\n color: var(--ink);\n border-radius: 8px;\n cursor: pointer;\n font-family: var(--mono);\n font-size: 12px;\n }\n .verify-btn:hover { border-color: var(--accent); }\n .verify-btn.ok { border-color: var(--ok); color: var(--ok); }\n .verify-btn.fail { border-color: var(--bad); color: var(--bad); }\n `;\n\n override connectedCallback(): void {\n super.connectedCallback();\n effect(() => {\n traceX.value; traceY.value; traceZ.value; stripBars.value;\n lastFrame.value; witnessHex.value; witnessVerified.value;\n lastB.value; bMag.value;\n this.requestUpdate();\n });\n }\n\n private async verify(): Promise {\n const c = getClient(); if (!c) return;\n witnessVerified.value = 'pending';\n pushLog('info', 'verifying witness over 256 frames…');\n try {\n const exp = expectedWitness.value;\n const expBytes = new Uint8Array(32);\n for (let i = 0; i < 32; i++) expBytes[i] = parseInt(exp.slice(i * 2, i * 2 + 2), 16);\n const r = await c.verifyWitness(expBytes);\n if (r.ok) {\n witnessVerified.value = 'ok';\n witnessHex.value = exp;\n pushLog('ok', `witness ${exp.slice(0, 16)}… matches · determinism gate ✓`);\n } else {\n witnessVerified.value = 'fail';\n const actual = Array.from(r.actual).map((b) => b.toString(16).padStart(2, '0')).join('');\n witnessHex.value = actual;\n pushLog('err', `WITNESS MISMATCH actual=${actual.slice(0, 16)}…`);\n }\n } catch (e) {\n witnessVerified.value = 'fail';\n pushLog('err', `verify failed: ${(e as Error).message}`);\n }\n }\n\n private renderSignalTab() {\n const W = 320, H = 130, cy = 65, scale = 22;\n const cap = 200;\n const make = (arr: number[]) => {\n let p = '';\n arr.forEach((v, i) => {\n const x = (i / Math.max(1, cap - 1)) * W;\n const y = cy - v * scale;\n p += (i === 0 ? 'M' : 'L') + ` ${x.toFixed(1)} ${y.toFixed(1)} `;\n });\n return p;\n };\n\n return html`\n \n
\n B-vector trace \n 3-axis · nT \n
\n
\n \n ${svg``}\n ${svg``}\n ${svg``}\n \n
\n\n \n
\n Frame stream \n live \n
\n
\n ${stripBars.value.map((v) => html`
`)}\n
\n
\n `;\n }\n\n private renderFrameTab() {\n const f = lastFrame.value;\n const bytes = f?.raw;\n let hex = '';\n if (bytes) {\n const arr = Array.from(bytes).map((b) => b.toString(16).padStart(2, '0'));\n hex = arr.slice(0, 60).join(' ');\n }\n return html`\n \n
\n MagFrame v1 fields \n 60 B \n
\n
\n magic ${f ? '0x' + f.magic.toString(16).toUpperCase() : '—'} \n version ${f?.version ?? '—'} \n flags 0x${(f?.flags ?? 0).toString(16).padStart(4, '0')} \n sensor_id ${f?.sensorId ?? '—'} \n t_us ${f ? f.tUs.toString() : '—'} \n b_pT[0] ${f ? f.bPt[0].toFixed(1) : '—'} \n b_pT[1] ${f ? f.bPt[1].toFixed(1) : '—'} \n b_pT[2] ${f ? f.bPt[2].toFixed(1) : '—'} \n noise_floor ${f ? f.noiseFloorPtSqrtHz.toFixed(2) : '—'} \n temp_K ${f ? f.temperatureK.toFixed(1) : '—'} \n
\n
\n \n
\n Hex dump \n LE \n
\n
${hex || '—'}
\n
\n `;\n }\n\n private renderWitnessTab() {\n const status = witnessVerified.value;\n const cls = status === 'ok' ? 'ok' : status === 'fail' ? 'fail' : '';\n const label =\n status === 'pending' ? 'Verifying…' :\n status === 'ok' ? '✓ Witness verified · determinism gate' :\n status === 'fail' ? '✗ Witness mismatch · audit required' :\n 'Verify witness';\n return html`\n \n
\n Expected (Proof::EXPECTED_WITNESS_HEX) \n SHA-256 \n
\n
${expectedWitness.value || '(loading…)'}
\n
\n \n
\n Actual (last verify) \n SHA-256 \n
\n
${witnessHex.value || '(not verified yet)'}
\n
${label} \n
\n `;\n }\n\n override render() {\n return html`\n \n this.tab = 'signal'}>Signal \n this.tab = 'frame'}>Frame \n this.tab = 'witness'}>Witness \n
\n \n ${this.tab === 'signal' ? this.renderSignalTab()\n : this.tab === 'frame' ? this.renderFrameTab()\n : this.renderWitnessTab()}\n
\n `;\n }\n}\n","/* Console — log stream + REPL. */\nimport { LitElement, html, css } from 'lit';\nimport { customElement, query } from 'lit/decorators.js';\nimport { effect } from '@preact/signals-core';\nimport {\n consoleLines, consoleFilter, consolePaused, pushLog,\n getClient, seed, theme, expectedWitness, witnessHex, witnessVerified,\n running,\n} from '../store/appStore';\n\n@customElement('nv-console')\nexport class NvConsole extends LitElement {\n @query('#console-input') private inputEl!: HTMLInputElement;\n private history: string[] = [];\n private hIdx = -1;\n\n static styles = css`\n :host {\n display: flex; flex-direction: column;\n background: var(--bg-1);\n overflow: hidden;\n }\n .tabs {\n display: flex; align-items: center;\n border-bottom: 1px solid var(--line);\n padding: 0 10px;\n gap: 2px;\n }\n .tab {\n padding: 8px 12px;\n background: transparent; border: none;\n font-size: 11.5px; color: var(--ink-3);\n font-family: var(--mono);\n border-bottom: 2px solid transparent;\n cursor: pointer;\n margin-bottom: -1px;\n }\n .tab.active { color: var(--ink); border-bottom-color: var(--accent); }\n .tab .cnt {\n background: var(--bg-3); padding: 1px 5px; border-radius: 999px;\n font-size: 9.5px; color: var(--ink-2); margin-left: 4px;\n }\n .spacer { flex: 1; }\n .tools { display: flex; gap: 4px; padding: 4px 0; }\n .tools button {\n width: 24px; height: 24px;\n background: transparent; border: 1px solid var(--line);\n border-radius: 6px;\n color: var(--ink-3);\n font-size: 11px; cursor: pointer;\n }\n .tools button:hover { color: var(--ink); border-color: var(--line-2); }\n\n .body {\n flex: 1; overflow-y: auto;\n font-family: var(--mono);\n font-size: 11.5px;\n padding: 6px 0;\n background: var(--bg-0);\n }\n .line {\n display: grid;\n grid-template-columns: 70px 60px 1fr;\n gap: 12px;\n padding: 2px 12px;\n color: var(--ink-2);\n border-left: 2px solid transparent;\n }\n .line:hover { background: var(--bg-1); }\n .ts { color: var(--ink-4); font-size: 10.5px; padding-top: 1px; }\n .lvl {\n font-size: 10px; font-weight: 600;\n text-transform: uppercase; letter-spacing: 0.04em; padding-top: 1px;\n }\n .line.info .lvl { color: var(--accent-2); }\n .line.warn .lvl { color: var(--warn); }\n .line.warn { border-left-color: var(--warn); background: oklch(0.7 0.18 35 / 0.04); }\n .line.err .lvl { color: var(--bad); }\n .line.err { border-left-color: var(--bad); background: oklch(0.65 0.22 25 / 0.05); }\n .line.dbg .lvl { color: var(--ink-3); }\n .line.ok .lvl { color: var(--ok); }\n .msg { color: var(--ink); white-space: pre-wrap; word-break: break-word; }\n\n .input {\n display: flex; align-items: center;\n border-top: 1px solid var(--line);\n background: var(--bg-0);\n padding: 0 10px;\n height: 32px; gap: 8px;\n }\n .prompt { color: var(--accent); font-family: var(--mono); font-size: 12px; }\n input[type=\"text\"] {\n flex: 1; background: transparent; border: none; outline: none;\n color: var(--ink); font-family: var(--mono); font-size: 12px;\n height: 100%;\n }\n input::placeholder { color: var(--ink-4); }\n `;\n\n override connectedCallback(): void {\n super.connectedCallback();\n effect(() => {\n consoleLines.value; consoleFilter.value; consolePaused.value;\n this.requestUpdate();\n });\n }\n\n override updated(): void {\n const body = this.renderRoot.querySelector('.body') as HTMLElement | null;\n if (body) body.scrollTop = body.scrollHeight;\n }\n\n private counts(): Record {\n const c: Record = { info: 0, warn: 0, err: 0, dbg: 0, ok: 0 };\n for (const l of consoleLines.value) c[l.level] = (c[l.level] ?? 0) + 1;\n c.all = consoleLines.value.length;\n return c;\n }\n\n private async exec(line: string): Promise {\n line = line.trim();\n if (!line) return;\n pushLog('info', `nvsim> ${line}`);\n this.history.push(line); this.hIdx = this.history.length;\n const [cmd, ...args] = line.split(/\\s+/);\n const arg = args.join(' ');\n const c = getClient();\n switch (cmd) {\n case 'help':\n pushLog('info', 'commands: help · scene.list · sensor.config · run · pause · seed · proof.verify · clear · theme · status');\n break;\n case 'scene.list':\n pushLog('info', 'scene rebar-walkby-01:');\n pushLog('info', ' rebar.steel.coil @ [+2.7, 0.0, +0.3] m χ=5000');\n pushLog('info', ' dipole.heart_proxy @ [-1.4, +0.2, +0.4] m m=1.0e-6 A·m²');\n pushLog('info', ' loop.mains_60Hz @ [-1.6, -0.4, 0.0] m I=2 A');\n pushLog('info', ' eddy.door_steel @ [+0.0, +1.8, +0.4] m σ=1e6 S/m');\n break;\n case 'sensor.config':\n pushLog('info', 'NvSensor::cots_defaults() {');\n pushLog('info', ' pos=[0,0,0], V=1mm³, N=1e12, C=0.03, T2*=200ns');\n pushLog('info', ' D=2.870 GHz, γe=28 GHz/T, Γ=1.0 MHz, axes=4×〈111〉');\n pushLog('info', ' δB ≈ 1.18 pT/√Hz (Barry 2020 §III.A) }');\n break;\n case 'run':\n if (c) { await c.run(); running.value = true; pushLog('ok', 'pipeline RUN'); }\n break;\n case 'pause':\n if (c) { await c.pause(); running.value = false; pushLog('warn', 'pipeline PAUSED'); }\n break;\n case 'reset':\n if (c) { await c.reset(); pushLog('info', 'pipeline reset · t=0'); }\n break;\n case 'seed': {\n if (!arg) { pushLog('info', `current seed = 0x${seed.value.toString(16).toUpperCase()}`); break; }\n const v = BigInt(arg.startsWith('0x') ? arg : '0x' + arg);\n seed.value = v;\n if (c) await c.setSeed(v);\n pushLog('ok', `seed → 0x${v.toString(16).toUpperCase()}`);\n break;\n }\n case 'proof.verify': {\n if (!c) break;\n pushLog('dbg', 'computing SHA-256 over 256 frames…');\n try {\n const exp = expectedWitness.value;\n const expBytes = new Uint8Array(32);\n for (let i = 0; i < 32; i++) expBytes[i] = parseInt(exp.slice(i * 2, i * 2 + 2), 16);\n const r = await c.verifyWitness(expBytes);\n if (r.ok) { witnessVerified.value = 'ok'; witnessHex.value = exp; pushLog('ok', `witness ${exp.slice(0, 16)}… matches · determinism gate ✓`); }\n else { witnessVerified.value = 'fail'; pushLog('err', 'WITNESS MISMATCH'); }\n } catch (e) { pushLog('err', `verify failed: ${(e as Error).message}`); }\n break;\n }\n case 'clear':\n consoleLines.value = [];\n break;\n case 'theme': {\n const t = (arg || '').toLowerCase();\n if (t === 'light' || t === 'dark') { theme.value = t; pushLog('ok', `theme → ${t}`); }\n else pushLog('info', 'theme [light|dark]');\n break;\n }\n case 'status':\n pushLog('info', `running=${running.value} seed=0x${seed.value.toString(16).toUpperCase()} verified=${witnessVerified.value}`);\n break;\n default:\n pushLog('err', `unknown command: ${cmd} · try help`);\n }\n }\n\n private onKey = (e: KeyboardEvent): void => {\n if (e.key === 'Enter') { void this.exec(this.inputEl.value); this.inputEl.value = ''; }\n else if (e.key === 'ArrowUp') {\n if (this.history.length) {\n this.hIdx = Math.max(0, this.hIdx - 1);\n this.inputEl.value = this.history[this.hIdx] ?? '';\n e.preventDefault();\n }\n } else if (e.key === 'ArrowDown') {\n if (this.history.length) {\n this.hIdx = Math.min(this.history.length, this.hIdx + 1);\n this.inputEl.value = this.history[this.hIdx] ?? '';\n e.preventDefault();\n }\n }\n };\n\n override render() {\n const c = this.counts();\n const filter = consoleFilter.value;\n const visible = consoleLines.value.filter((l) => filter === 'all' || l.level === filter);\n return html`\n \n ${(['all', 'info', 'warn', 'err', 'dbg'] as const).map((k) => html`\n
consoleFilter.value = k}>\n ${k} ${c[k] ?? 0} \n \n `)}\n
\n
\n consoleLines.value = []}>× \n consolePaused.value = !consolePaused.value}>\n ${consolePaused.value ? '▶' : '❚❚'}\n \n
\n
\n \n ${visible.map((l) => {\n const ts = new Date(l.ts);\n const tsStr = `${String(ts.getSeconds()).padStart(2, '0')}.${String(ts.getMilliseconds()).padStart(3, '0')}`;\n // Use innerHTML pass-through via unsafe-html alt: inject raw html via property\n return html`
\n
${tsStr}
\n
${l.level}
\n
\n
`;\n })}\n
\n \n nvsim> \n \n
\n `;\n }\n}\n","/* RuView Edge App Store registry.\n *\n * Catalog of every WASM edge module shipping in the workspace plus the\n * `nvsim` simulator itself. Each entry maps to a hot-loadable algorithm\n * the dashboard can run in-browser (WASM transport) or push to a real\n * ESP32-S3 mesh (WS transport, deployed via WASM3 — ADR-040 Tier 3).\n *\n * Categories (ADR-041 event-ID ranges):\n * med 100–199 Medical & health\n * sec 200–299 Security & safety\n * bld 300–399 Smart building\n * ret 400–499 Retail & hospitality\n * ind 500–599 Industrial\n * sig 600–619 Signal-processing primitives\n * lrn 620–639 Online learning\n * spt 640–659 Spatial / graph\n * tmp 640–660 Temporal logic / planning\n * ais 700–719 AI safety\n * qnt 720–739 Quantum-flavoured signal\n * aut 740–759 Autonomy / mesh\n * exo 650–699 Exotic / research\n * sim — Pipeline simulators (nvsim)\n *\n * The `crate` field names the Cargo crate that owns the implementation.\n * `wasmEdge` apps are compiled out of `wifi-densepose-wasm-edge`;\n * `nvsim` apps come from `nvsim`. Future apps may target other crates.\n */\n\nexport type AppCategory =\n | 'sim'\n | 'med'\n | 'sec'\n | 'bld'\n | 'ret'\n | 'ind'\n | 'sig'\n | 'lrn'\n | 'spt'\n | 'tmp'\n | 'ais'\n | 'qnt'\n | 'aut'\n | 'exo';\n\nexport interface AppManifest {\n /** Stable kebab-case id; matches the wasm-edge module name (e.g. `med_sleep_apnea`). */\n id: string;\n /** Human-readable name. */\n name: string;\n /** Category short-code. */\n category: AppCategory;\n /** Cargo crate the implementation lives in. */\n crate: 'nvsim' | 'wifi-densepose-wasm-edge' | string;\n /** One-liner description. */\n summary: string;\n /** Optional longer markdown body. */\n body?: string;\n /** Numeric event IDs this app emits (i32 codes from `event_types` mod). */\n events?: number[];\n /** Compute budget tier the module advertises. S=<5ms, M=<15ms, L=<50ms. */\n budget?: 'S' | 'M' | 'L';\n /** Default activation state when listed. */\n active?: boolean;\n /** Tags for fuzzy search and filtering. */\n tags?: string[];\n /** \"Available\", \"Beta\", or \"Research\" maturity. */\n status: 'available' | 'beta' | 'research';\n /** ADR back-reference. */\n adr?: string;\n}\n\nexport const APPS: AppManifest[] = [\n // ── Pipeline simulators ──────────────────────────────────────────────────\n {\n id: 'nvsim',\n name: 'nvsim — NV-diamond magnetometer',\n category: 'sim',\n crate: 'nvsim',\n summary:\n 'Deterministic forward simulator: scene → Biot–Savart → NV ensemble → ADC → MagFrame stream + SHA-256 witness.',\n budget: 'L',\n active: true,\n status: 'available',\n tags: ['quantum', 'magnetometer', 'simulator', 'witness', 'wasm'],\n adr: 'ADR-089',\n },\n\n // ── Core sensing primitives (ADR-014/040 flagship modules) ───────────────\n {\n id: 'gesture',\n name: 'Gesture (DTW)',\n category: 'sig',\n crate: 'wifi-densepose-wasm-edge',\n summary: 'Dynamic-Time-Warping gesture classifier from CSI motion templates.',\n events: [1],\n budget: 'M',\n status: 'available',\n tags: ['hci', 'csi', 'classifier', 'dtw'],\n adr: 'ADR-014',\n },\n {\n id: 'coherence',\n name: 'Coherence gate',\n category: 'sig',\n crate: 'wifi-densepose-wasm-edge',\n summary: 'Z-score coherence scoring + Accept/PredictOnly/Reject/Recalibrate gate.',\n events: [2],\n budget: 'S',\n status: 'available',\n tags: ['gate', 'csi', 'coherence', 'drift'],\n adr: 'ADR-029',\n },\n {\n id: 'adversarial',\n name: 'Adversarial-signal detector',\n category: 'ais',\n crate: 'wifi-densepose-wasm-edge',\n summary:\n 'Physically-impossible-signal detector — multi-link consistency, used to flag spoofed CSI.',\n events: [3],\n budget: 'M',\n status: 'available',\n tags: ['security', 'csi', 'spoofing', 'mesh'],\n adr: 'ADR-032',\n },\n {\n id: 'rvf',\n name: 'RVF — Rust Verified Feature stream',\n category: 'sig',\n crate: 'wifi-densepose-wasm-edge',\n summary: 'Verified-frame builder with SHA-256 hash + version metadata for the feature stream.',\n budget: 'S',\n status: 'available',\n tags: ['witness', 'csi', 'hash'],\n adr: 'ADR-040',\n },\n {\n id: 'occupancy',\n name: 'Occupancy estimator',\n category: 'bld',\n crate: 'wifi-densepose-wasm-edge',\n summary: 'Through-wall presence + person-count via CSI amplitude perturbation.',\n events: [300, 301, 302],\n budget: 'S',\n status: 'available',\n tags: ['csi', 'building', 'presence'],\n },\n {\n id: 'vital_trend',\n name: 'Vital-trend monitor',\n category: 'med',\n crate: 'wifi-densepose-wasm-edge',\n summary: 'HR + BR trend tracking with bradycardia/tachycardia/apnea events.',\n events: [100, 101, 102, 103, 104, 105],\n budget: 'S',\n status: 'available',\n tags: ['medical', 'vitals', 'csi'],\n adr: 'ADR-021',\n },\n {\n id: 'intrusion',\n name: 'Intrusion detector',\n category: 'sec',\n crate: 'wifi-densepose-wasm-edge',\n summary: 'Zone-based intrusion alert from CSI motion patterns.',\n events: [200, 201],\n budget: 'S',\n status: 'available',\n tags: ['security', 'zone', 'csi'],\n },\n\n // ── Medical & Health (100-series) ────────────────────────────────────────\n { id: 'med_sleep_apnea', name: 'Sleep-apnea detector', category: 'med', crate: 'wifi-densepose-wasm-edge', summary: 'Episodic respiratory pause detection during sleep cycles.', events: [105], budget: 'S', status: 'available', tags: ['medical', 'sleep', 'breathing'] },\n { id: 'med_cardiac_arrhythmia', name: 'Cardiac arrhythmia', category: 'med', crate: 'wifi-densepose-wasm-edge', summary: 'Beat-to-beat irregularity classifier from cardiac micro-Doppler.', events: [103, 104], budget: 'M', status: 'available', tags: ['medical', 'cardiac', 'arrhythmia'] },\n { id: 'med_respiratory_distress', name: 'Respiratory distress', category: 'med', crate: 'wifi-densepose-wasm-edge', summary: 'Distress signature: rapid shallow breathing + accessory-muscle motion.', events: [101, 102], budget: 'S', status: 'available', tags: ['medical', 'breathing', 'icu'] },\n { id: 'med_gait_analysis', name: 'Gait analysis', category: 'med', crate: 'wifi-densepose-wasm-edge', summary: 'Stride length, cadence, asymmetry from through-wall CSI pose tracking.', budget: 'M', status: 'available', tags: ['medical', 'gait', 'pose'] },\n { id: 'med_seizure_detect', name: 'Seizure detector', category: 'med', crate: 'wifi-densepose-wasm-edge', summary: 'Tonic-clonic seizure motion signature.', budget: 'M', status: 'beta', tags: ['medical', 'neuro'] },\n\n // ── Security (200-series) ────────────────────────────────────────────────\n { id: 'sec_perimeter_breach', name: 'Perimeter breach', category: 'sec', crate: 'wifi-densepose-wasm-edge', summary: 'Approach/departure detection at user-defined boundary segments.', events: [210, 211, 212, 213], budget: 'S', status: 'available', tags: ['security', 'perimeter'] },\n { id: 'sec_weapon_detect', name: 'Metal anomaly / weapon', category: 'sec', crate: 'wifi-densepose-wasm-edge', summary: 'Metal-perturbation flag in CSI; potential weapon presence (research).', events: [220, 221, 222], budget: 'M', status: 'research', tags: ['security', 'metal', 'csi'] },\n { id: 'sec_tailgating', name: 'Tailgating detector', category: 'sec', crate: 'wifi-densepose-wasm-edge', summary: 'Detect 2+ persons crossing a single-passage threshold.', events: [230, 231, 232], budget: 'S', status: 'available', tags: ['security', 'access-control'] },\n { id: 'sec_loitering', name: 'Loitering detector', category: 'sec', crate: 'wifi-densepose-wasm-edge', summary: 'Stationary occupancy past a configurable dwell threshold.', events: [240, 241, 242], budget: 'S', status: 'available', tags: ['security', 'dwell'] },\n { id: 'sec_panic_motion', name: 'Panic motion', category: 'sec', crate: 'wifi-densepose-wasm-edge', summary: 'High-energy distress motion: struggle / fleeing pattern.', events: [250, 251, 252], budget: 'S', status: 'beta', tags: ['security', 'distress'] },\n\n // ── Smart Building (300-series) ──────────────────────────────────────────\n { id: 'bld_hvac_presence', name: 'HVAC presence', category: 'bld', crate: 'wifi-densepose-wasm-edge', summary: 'Occupied/activity-level/departure-countdown for HVAC zones.', events: [310, 311, 312], budget: 'S', status: 'available', tags: ['hvac', 'building', 'energy'] },\n { id: 'bld_lighting_zones', name: 'Lighting zones', category: 'bld', crate: 'wifi-densepose-wasm-edge', summary: 'Per-zone light on/dim/off cues from occupancy.', events: [320, 321, 322], budget: 'S', status: 'available', tags: ['lighting', 'building'] },\n { id: 'bld_elevator_count', name: 'Elevator count', category: 'bld', crate: 'wifi-densepose-wasm-edge', summary: 'Person count inside elevator car from CSI.', events: [330], budget: 'S', status: 'available', tags: ['elevator', 'building'] },\n { id: 'bld_meeting_room', name: 'Meeting-room utilization', category: 'bld', crate: 'wifi-densepose-wasm-edge', summary: 'Meeting size + duration analytics for booking systems.', budget: 'S', status: 'available', tags: ['meeting', 'analytics'] },\n { id: 'bld_energy_audit', name: 'Energy audit', category: 'bld', crate: 'wifi-densepose-wasm-edge', summary: 'Continuous occupancy-vs-HVAC-state audit for energy savings.', budget: 'M', status: 'available', tags: ['energy', 'audit'] },\n\n // ── Retail (400-series) ──────────────────────────────────────────────────\n { id: 'ret_queue_length', name: 'Queue length', category: 'ret', crate: 'wifi-densepose-wasm-edge', summary: 'Live queue-length tracking for checkout / kiosks.', budget: 'S', status: 'available', tags: ['retail', 'queue'] },\n { id: 'ret_dwell_heatmap', name: 'Dwell heatmap', category: 'ret', crate: 'wifi-densepose-wasm-edge', summary: 'Per-zone dwell time accumulation; analytics-only export.', budget: 'M', status: 'available', tags: ['retail', 'heatmap'] },\n { id: 'ret_customer_flow', name: 'Customer flow', category: 'ret', crate: 'wifi-densepose-wasm-edge', summary: 'Origin-destination flow graph through a store layout.', budget: 'M', status: 'available', tags: ['retail', 'flow'] },\n { id: 'ret_table_turnover', name: 'Table turnover', category: 'ret', crate: 'wifi-densepose-wasm-edge', summary: 'Restaurant table seat / vacate transitions.', budget: 'S', status: 'available', tags: ['retail', 'restaurant'] },\n { id: 'ret_shelf_engagement', name: 'Shelf engagement', category: 'ret', crate: 'wifi-densepose-wasm-edge', summary: 'Reach-to-shelf gestures and dwell at product zones.', budget: 'M', status: 'available', tags: ['retail', 'shelf'] },\n\n // ── Industrial (500-series) ──────────────────────────────────────────────\n { id: 'ind_forklift_proximity', name: 'Forklift proximity', category: 'ind', crate: 'wifi-densepose-wasm-edge', summary: 'Worker-near-forklift safety alert.', budget: 'S', status: 'available', tags: ['industrial', 'safety'] },\n { id: 'ind_confined_space', name: 'Confined-space monitor', category: 'ind', crate: 'wifi-densepose-wasm-edge', summary: 'Last-person-out detection + presence audit for OSHA confined-space entries.', budget: 'S', status: 'available', tags: ['industrial', 'osha'] },\n { id: 'ind_clean_room', name: 'Clean-room PPE / motion', category: 'ind', crate: 'wifi-densepose-wasm-edge', summary: 'Motion patterns consistent with proper PPE-clad movement.', budget: 'M', status: 'beta', tags: ['industrial', 'cleanroom'] },\n { id: 'ind_livestock_monitor', name: 'Livestock monitor', category: 'ind', crate: 'wifi-densepose-wasm-edge', summary: 'Vital-sign + activity tracking for stall-bound livestock.', budget: 'M', status: 'beta', tags: ['agriculture', 'livestock'] },\n { id: 'ind_structural_vibration', name: 'Structural vibration', category: 'ind', crate: 'wifi-densepose-wasm-edge', summary: 'Building/equipment micro-vibration via CSI phase derivative.', budget: 'M', status: 'research', tags: ['industrial', 'vibration'] },\n\n // ── Signal primitives (600-series) ───────────────────────────────────────\n { id: 'sig_coherence_gate', name: 'Coherence gate (extended)', category: 'sig', crate: 'wifi-densepose-wasm-edge', summary: 'Hysteresis + multi-state coherence gate driving downstream apps.', budget: 'S', status: 'available', tags: ['gate', 'csi'] },\n { id: 'sig_flash_attention', name: 'Flash attention (CSI)', category: 'sig', crate: 'wifi-densepose-wasm-edge', summary: 'Edge-friendly attention block for CSI subcarrier weighting.', budget: 'M', status: 'beta', tags: ['attention', 'csi'] },\n { id: 'sig_temporal_compress', name: 'Temporal-tensor compress', category: 'sig', crate: 'wifi-densepose-wasm-edge', summary: 'RuVector temporal-tensor compression on the CSI buffer.', budget: 'M', status: 'available', tags: ['compress', 'tensor'] },\n { id: 'sig_sparse_recovery', name: 'Sparse recovery', category: 'sig', crate: 'wifi-densepose-wasm-edge', summary: '114→56 subcarrier sparse interpolation via L1 solver.', budget: 'M', status: 'available', tags: ['sparse', 'csi'] },\n { id: 'sig_mincut_person_match', name: 'Mincut person-match', category: 'sig', crate: 'wifi-densepose-wasm-edge', summary: 'Min-cut person assignment across multistatic frames.', budget: 'M', status: 'available', tags: ['mincut', 'matching'] },\n { id: 'sig_optimal_transport', name: 'Optimal transport', category: 'sig', crate: 'wifi-densepose-wasm-edge', summary: 'OT-based feature alignment between mesh nodes.', budget: 'M', status: 'beta', tags: ['ot', 'alignment'] },\n\n // ── Online learning ──────────────────────────────────────────────────────\n { id: 'lrn_dtw_gesture_learn', name: 'DTW gesture learn', category: 'lrn', crate: 'wifi-densepose-wasm-edge', summary: 'On-device template learning for personalized gesture libraries.', budget: 'M', status: 'beta', tags: ['lifelong', 'gesture'] },\n { id: 'lrn_anomaly_attractor', name: 'Anomaly attractor', category: 'lrn', crate: 'wifi-densepose-wasm-edge', summary: 'Novelty detector with dynamic-attractor recall.', budget: 'M', status: 'research', tags: ['novelty', 'lifelong'] },\n { id: 'lrn_meta_adapt', name: 'Meta-adapt', category: 'lrn', crate: 'wifi-densepose-wasm-edge', summary: 'Meta-learning adapter for fast site-to-site transfer.', budget: 'L', status: 'research', tags: ['meta-learning'] },\n { id: 'lrn_ewc_lifelong', name: 'EWC++ lifelong', category: 'lrn', crate: 'wifi-densepose-wasm-edge', summary: 'Elastic-weight-consolidation gate to avoid catastrophic forgetting.', budget: 'M', status: 'beta', tags: ['lifelong', 'ewc'] },\n\n // ── Spatial / graph ──────────────────────────────────────────────────────\n { id: 'spt_pagerank_influence', name: 'PageRank influence', category: 'spt', crate: 'wifi-densepose-wasm-edge', summary: 'Graph-influence ranking on the multistatic mesh.', budget: 'M', status: 'beta', tags: ['graph', 'pagerank'] },\n { id: 'spt_micro_hnsw', name: 'µHNSW vector index', category: 'spt', crate: 'wifi-densepose-wasm-edge', summary: 'Tiny HNSW index for AETHER re-ID embeddings on-device.', budget: 'M', status: 'available', tags: ['hnsw', 'reid'] },\n { id: 'spt_spiking_tracker', name: 'Spiking tracker', category: 'spt', crate: 'wifi-densepose-wasm-edge', summary: 'Spiking-network multi-target tracker.', budget: 'L', status: 'research', tags: ['snn', 'tracker'] },\n\n // ── Temporal / planning ──────────────────────────────────────────────────\n { id: 'tmp_pattern_sequence', name: 'Pattern sequence', category: 'tmp', crate: 'wifi-densepose-wasm-edge', summary: 'Sequence-of-events pattern matcher (e.g. ingress→linger→egress).', budget: 'M', status: 'available', tags: ['temporal', 'pattern'] },\n { id: 'tmp_temporal_logic_guard', name: 'Temporal logic guard', category: 'tmp', crate: 'wifi-densepose-wasm-edge', summary: 'LTL/MTL safety-property guard over event streams.', budget: 'M', status: 'beta', tags: ['ltl', 'safety'] },\n { id: 'tmp_goap_autonomy', name: 'GOAP autonomy', category: 'tmp', crate: 'wifi-densepose-wasm-edge', summary: 'Goal-oriented action planning for adaptive routines.', budget: 'L', status: 'research', tags: ['planning', 'autonomy'] },\n\n // ── AI safety ────────────────────────────────────────────────────────────\n { id: 'ais_prompt_shield', name: 'Prompt shield', category: 'ais', crate: 'wifi-densepose-wasm-edge', summary: 'Edge-side LLM prompt-injection guard for on-device assistants.', budget: 'M', status: 'beta', tags: ['security', 'llm'] },\n { id: 'ais_behavioral_profiler', name: 'Behavioral profiler', category: 'ais', crate: 'wifi-densepose-wasm-edge', summary: 'Anomalous-behaviour profiler (drift in motion habits).', budget: 'M', status: 'beta', tags: ['anomaly', 'behaviour'] },\n\n // ── Quantum-flavoured ────────────────────────────────────────────────────\n { id: 'qnt_quantum_coherence', name: 'Quantum coherence', category: 'qnt', crate: 'wifi-densepose-wasm-edge', summary: 'Coherence diagnostics adapted for quantum-sensor signals.', budget: 'M', status: 'research', tags: ['quantum', 'coherence'] },\n { id: 'qnt_interference_search', name: 'Interference search', category: 'qnt', crate: 'wifi-densepose-wasm-edge', summary: 'Interferometric anomaly search across mesh viewpoints.', budget: 'L', status: 'research', tags: ['quantum', 'interference'] },\n\n // ── Autonomy / mesh ──────────────────────────────────────────────────────\n { id: 'aut_psycho_symbolic', name: 'Psycho-symbolic agent', category: 'aut', crate: 'wifi-densepose-wasm-edge', summary: 'Symbolic-rule + neural-feature hybrid for low-power autonomy loops.', budget: 'L', status: 'research', tags: ['autonomy', 'symbolic'] },\n { id: 'aut_self_healing_mesh', name: 'Self-healing mesh', category: 'aut', crate: 'wifi-densepose-wasm-edge', summary: 'Mesh-topology repair with per-node health gossip.', budget: 'M', status: 'beta', tags: ['mesh', 'health'] },\n\n // ── Exotic / Research (650-series) ───────────────────────────────────────\n { id: 'exo_ghost_hunter', name: 'Ghost hunter (anomaly)', category: 'exo', crate: 'wifi-densepose-wasm-edge', summary: 'Empty-room CSI anomaly detector — impulsive/periodic/drift/random + hidden-presence sub-detector.', events: [650, 651, 652, 653], budget: 'S', status: 'available', tags: ['anomaly', 'paranormal', 'csi'], adr: 'ADR-041' },\n { id: 'exo_breathing_sync', name: 'Breathing sync', category: 'exo', crate: 'wifi-densepose-wasm-edge', summary: 'Multi-person breathing synchrony analytics.', budget: 'M', status: 'beta', tags: ['breathing', 'sync'] },\n { id: 'exo_dream_stage', name: 'Dream-stage classifier', category: 'exo', crate: 'wifi-densepose-wasm-edge', summary: 'NREM/REM stage classification from breathing + micro-motion.', budget: 'M', status: 'research', tags: ['sleep', 'rem'] },\n { id: 'exo_emotion_detect', name: 'Emotion detector', category: 'exo', crate: 'wifi-densepose-wasm-edge', summary: 'Coarse arousal/valence from breathing + heart-rate variability.', budget: 'M', status: 'research', tags: ['affect'] },\n { id: 'exo_gesture_language', name: 'Gesture language', category: 'exo', crate: 'wifi-densepose-wasm-edge', summary: 'Sign-language pattern recognition.', budget: 'L', status: 'research', tags: ['hci', 'sign'] },\n { id: 'exo_happiness_score', name: 'Happiness score', category: 'exo', crate: 'wifi-densepose-wasm-edge', summary: 'Aggregate well-being score from co-occupancy + activity dynamics.', budget: 'M', status: 'research', tags: ['affect', 'wellbeing'] },\n { id: 'exo_hyperbolic_space', name: 'Hyperbolic space embed', category: 'exo', crate: 'wifi-densepose-wasm-edge', summary: 'Hyperbolic embeddings for hierarchical scene structure.', budget: 'L', status: 'research', tags: ['embedding', 'hyperbolic'] },\n { id: 'exo_music_conductor', name: 'Music conductor', category: 'exo', crate: 'wifi-densepose-wasm-edge', summary: 'Map gesture energy to MIDI tempo/dynamics.', budget: 'M', status: 'research', tags: ['midi', 'art'] },\n { id: 'exo_plant_growth', name: 'Plant-growth tracker', category: 'exo', crate: 'wifi-densepose-wasm-edge', summary: 'Slow CSI drift tracking for greenhouse foliage growth.', budget: 'L', status: 'research', tags: ['agriculture'] },\n { id: 'exo_rain_detect', name: 'Rain detector', category: 'exo', crate: 'wifi-densepose-wasm-edge', summary: 'Outdoor CSI signature of rainfall.', budget: 'M', status: 'research', tags: ['weather'] },\n { id: 'exo_time_crystal', name: 'Time-crystal periodicity', category: 'exo', crate: 'wifi-densepose-wasm-edge', summary: 'Periodicity diagnostics with anti-aliasing harmonics.', budget: 'M', status: 'research', tags: ['periodicity'] },\n];\n\nexport const CATEGORIES: Record = {\n sim: { label: 'Simulators', color: 'oklch(0.78 0.14 70)', range: '—' },\n med: { label: 'Medical & Health', color: 'oklch(0.65 0.22 25)', range: '100–199' },\n sec: { label: 'Security & Safety', color: 'oklch(0.7 0.18 35)', range: '200–299' },\n bld: { label: 'Smart Building', color: 'oklch(0.78 0.12 195)', range: '300–399' },\n ret: { label: 'Retail & Hospitality', color: 'oklch(0.78 0.14 145)', range: '400–499' },\n ind: { label: 'Industrial', color: 'oklch(0.72 0.18 330)', range: '500–599' },\n sig: { label: 'Signal Processing', color: 'oklch(0.78 0.14 70)', range: '600–619' },\n lrn: { label: 'Online Learning', color: 'oklch(0.78 0.12 260)', range: '620–639' },\n spt: { label: 'Spatial / Graph', color: 'oklch(0.7 0.18 100)', range: '640–659' },\n tmp: { label: 'Temporal / Planning', color: 'oklch(0.7 0.16 50)', range: '660–679' },\n ais: { label: 'AI Safety', color: 'oklch(0.65 0.22 25)', range: '700–719' },\n qnt: { label: 'Quantum', color: 'oklch(0.72 0.18 290)', range: '720–739' },\n aut: { label: 'Autonomy', color: 'oklch(0.78 0.14 145)', range: '740–759' },\n exo: { label: 'Exotic / Research', color: 'oklch(0.72 0.18 330)', range: '650–699' },\n};\n\nexport interface AppActivation {\n id: string;\n /** Active in the current session. */\n active: boolean;\n /** Last activation timestamp. */\n lastActivatedAt?: number;\n /** Last event count seen (for the cards' counter). */\n eventCount?: number;\n}\n\nexport function defaultActivations(): AppActivation[] {\n return APPS.map((a) => ({ id: a.id, active: a.active === true, eventCount: 0 }));\n}\n\nexport function appsByCategory(): Record {\n const map = {} as Record;\n for (const c of Object.keys(CATEGORIES) as AppCategory[]) map[c] = [];\n for (const a of APPS) map[a.category].push(a);\n return map;\n}\n\nexport function findApp(id: string): AppManifest | undefined {\n return APPS.find((a) => a.id === id);\n}\n\nexport function fuzzyMatch(query: string, app: AppManifest): number {\n if (!query) return 1;\n const q = query.toLowerCase();\n let score = 0;\n if (app.id.toLowerCase().includes(q)) score += 3;\n if (app.name.toLowerCase().includes(q)) score += 3;\n if (app.summary.toLowerCase().includes(q)) score += 1;\n if (app.tags?.some((t) => t.toLowerCase().includes(q))) score += 2;\n if (app.category === q) score += 5;\n return score;\n}\n","/* IndexedDB-backed persistence for settings and saved scenes.\n * Mirrors the mockup's `nvsim/kv` store. */\n\nconst DB_NAME = 'nvsim';\nconst DB_VER = 1;\nconst STORE = 'kv';\n\nlet dbPromise: Promise | null = null;\n\nfunction openDb(): Promise {\n if (dbPromise) return dbPromise;\n dbPromise = new Promise((resolve, reject) => {\n const req = indexedDB.open(DB_NAME, DB_VER);\n req.onupgradeneeded = () => {\n const db = req.result;\n if (!db.objectStoreNames.contains(STORE)) db.createObjectStore(STORE);\n };\n req.onsuccess = () => resolve(req.result);\n req.onerror = () => reject(req.error);\n });\n return dbPromise;\n}\n\nexport async function kvGet(key: string): Promise {\n const db = await openDb();\n return await new Promise((resolve, reject) => {\n const tx = db.transaction(STORE, 'readonly');\n const r = tx.objectStore(STORE).get(key);\n r.onsuccess = () => resolve(r.result as T | undefined);\n r.onerror = () => reject(r.error);\n });\n}\n\nexport async function kvSet(key: string, value: unknown): Promise {\n const db = await openDb();\n return await new Promise((resolve, reject) => {\n const tx = db.transaction(STORE, 'readwrite');\n tx.objectStore(STORE).put(value, key);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\nexport async function kvDelete(key: string): Promise {\n const db = await openDb();\n return await new Promise((resolve, reject) => {\n const tx = db.transaction(STORE, 'readwrite');\n tx.objectStore(STORE).delete(key);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n","/* App Store — catalog of every WASM edge module + simulator app.\n *\n * Mirrors `wifi-densepose-wasm-edge`'s 60+ hot-loadable algorithms and\n * the `nvsim` simulator. Each card is filterable by category, fuzzy\n * name search, and maturity (available / beta / research). A toggle on\n * each card flips activation in the live session — that drives the\n * dashboard's event log when running. WS transport (future) pushes the\n * activation set to the connected ESP32 mesh.\n *\n * ADR-092 §18.\n */\n\nimport { LitElement, html, css } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\nimport { signal, effect } from '@preact/signals-core';\nimport {\n APPS, CATEGORIES, defaultActivations, fuzzyMatch,\n type AppCategory, type AppManifest, type AppActivation,\n} from '../store/apps';\nimport { kvGet, kvSet } from '../store/persistence';\nimport { pushLog } from '../store/appStore';\n\nconst activations = signal(defaultActivations());\nconst query = signal('');\nconst activeCat = signal('all');\nconst statusFilter = signal<'all' | 'available' | 'beta' | 'research'>('all');\n\n(async () => {\n const saved = await kvGet('app-activations');\n if (saved) activations.value = saved;\n})();\n\neffect(() => {\n // Persist activations on change (post-load).\n const v = activations.value;\n if (v.length > 0) void kvSet('app-activations', v);\n});\n\n@customElement('nv-app-store')\nexport class NvAppStore extends LitElement {\n @state() private renderTick = 0;\n\n static styles = css`\n :host {\n display: block;\n height: 100%;\n overflow-y: auto;\n background: radial-gradient(ellipse at 50% 30%, var(--bg-2) 0%, var(--bg-0) 70%);\n padding: 24px;\n }\n .head {\n display: flex; align-items: center; gap: 16px;\n margin-bottom: 18px;\n flex-wrap: wrap;\n }\n .ttl {\n font-size: 22px; font-weight: 700; letter-spacing: -0.02em;\n color: var(--ink);\n flex: 1; min-width: 200px;\n }\n .ttl small {\n font-size: 12.5px; font-weight: 400;\n color: var(--ink-3); margin-left: 8px;\n }\n .search {\n width: 320px; max-width: 100%;\n padding: 8px 12px;\n background: var(--bg-2);\n border: 1px solid var(--line);\n border-radius: 8px;\n font-family: var(--mono);\n font-size: 12.5px;\n color: var(--ink); outline: none;\n }\n .search:focus { border-color: var(--accent); }\n .filters {\n display: flex; flex-wrap: wrap; gap: 6px;\n margin-bottom: 18px;\n }\n .chip {\n padding: 4px 10px;\n background: var(--bg-2);\n border: 1px solid var(--line);\n border-radius: 999px;\n font-size: 11.5px; color: var(--ink-3);\n cursor: pointer;\n font-family: var(--mono);\n display: inline-flex; align-items: center; gap: 4px;\n }\n .chip:hover { color: var(--ink); border-color: var(--line-2); }\n .chip.on { background: var(--bg-3); border-color: var(--accent); color: var(--ink); }\n .chip .swatch {\n width: 7px; height: 7px; border-radius: 50%;\n }\n .chip .count { color: var(--ink-3); font-size: 10px; }\n .grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));\n gap: 12px;\n }\n .card {\n background: var(--bg-2);\n border: 1px solid var(--line);\n border-radius: var(--radius);\n padding: 12px 14px;\n display: flex; flex-direction: column; gap: 6px;\n transition: border-color 0.15s, transform 0.15s;\n position: relative;\n }\n .card:hover { border-color: var(--line-2); transform: translateY(-1px); }\n .card.active {\n border-color: oklch(0.78 0.14 145 / 0.7);\n background: linear-gradient(180deg, var(--bg-2) 0%, oklch(0.78 0.14 145 / 0.04) 100%);\n }\n .card-h {\n display: flex; align-items: flex-start; gap: 8px;\n margin-bottom: 2px;\n }\n .card-h .name {\n font-size: 13.5px; font-weight: 600; color: var(--ink);\n flex: 1; line-height: 1.3;\n }\n .card-h .swatch {\n width: 10px; height: 10px; border-radius: 50%;\n flex-shrink: 0; margin-top: 4px;\n }\n .summary {\n font-size: 12px; color: var(--ink-2); line-height: 1.45;\n flex: 1;\n }\n .meta {\n display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px;\n font-family: var(--mono); font-size: 10px;\n }\n .badge {\n padding: 1px 6px; border-radius: 4px;\n background: var(--bg-3); color: var(--ink-3);\n border: 1px solid var(--line);\n }\n .badge.cat { color: var(--accent); border-color: oklch(0.78 0.14 70 / 0.3); }\n .badge.status-available { color: var(--ok); border-color: oklch(0.78 0.14 145 / 0.4); }\n .badge.status-beta { color: var(--warn); border-color: oklch(0.7 0.18 35 / 0.4); }\n .badge.status-research { color: var(--accent-3); border-color: oklch(0.72 0.18 330 / 0.4); }\n .badge.budget { color: var(--accent-2); border-color: oklch(0.78 0.12 195 / 0.3); }\n .card-foot {\n display: flex; align-items: center; gap: 8px;\n padding-top: 8px; margin-top: 4px;\n border-top: 1px solid var(--line);\n font-size: 11px; color: var(--ink-3);\n }\n .toggle {\n position: relative;\n width: 32px; height: 18px;\n background: var(--bg-3); border: 1px solid var(--line-2);\n border-radius: 999px; cursor: pointer;\n transition: background 0.15s;\n flex-shrink: 0;\n }\n .toggle::after {\n content: ''; position: absolute;\n top: 1px; left: 1px;\n width: 12px; height: 12px;\n background: var(--ink-3); border-radius: 50%;\n transition: transform 0.15s, background 0.15s;\n }\n .toggle.on { background: var(--accent); border-color: var(--accent); }\n .toggle.on::after { background: #1a0f00; transform: translateX(14px); }\n .events {\n font-family: var(--mono); font-size: 10px; color: var(--ink-3);\n flex: 1;\n }\n .empty {\n padding: 40px;\n text-align: center; color: var(--ink-3);\n font-size: 13px;\n }\n `;\n\n override connectedCallback(): void {\n super.connectedCallback();\n effect(() => { activations.value; query.value; activeCat.value; statusFilter.value; this.renderTick++; });\n }\n\n private isActive(id: string): boolean {\n return activations.value.find((a) => a.id === id)?.active === true;\n }\n\n private toggle(app: AppManifest): void {\n const next = activations.value.map((a) => a.id === app.id ? { ...a, active: !a.active, lastActivatedAt: Date.now() } : a);\n activations.value = next;\n pushLog(this.isActive(app.id) ? 'ok' : 'info', `app ${app.id} deactivated`);\n }\n\n private filtered(): AppManifest[] {\n let list = APPS;\n if (activeCat.value !== 'all') list = list.filter((a) => a.category === activeCat.value);\n if (statusFilter.value !== 'all') list = list.filter((a) => a.status === statusFilter.value);\n if (query.value.trim()) {\n list = list\n .map((a) => ({ a, s: fuzzyMatch(query.value, a) }))\n .filter((x) => x.s > 0)\n .sort((a, b) => b.s - a.s)\n .map((x) => x.a);\n }\n return list;\n }\n\n private categoryCounts(): Record {\n const counts: Record = { all: APPS.length };\n for (const k of Object.keys(CATEGORIES)) counts[k] = 0;\n for (const a of APPS) counts[a.category] = (counts[a.category] ?? 0) + 1;\n return counts;\n }\n\n override render() {\n const list = this.filtered();\n const counts = this.categoryCounts();\n const activeCount = activations.value.filter((a) => a.active).length;\n return html`\n \n
\n App Store\n ${APPS.length} edge apps · ${activeCount} active \n
\n
{ query.value = (e.target as HTMLInputElement).value; }} />\n
\n\n \n activeCat.value = 'all'}>\n All${counts.all} \n \n ${(Object.keys(CATEGORIES) as AppCategory[]).map((k) => html`\n activeCat.value = k}>\n \n ${CATEGORIES[k].label}\n ${counts[k] ?? 0} \n \n `)}\n \n statusFilter.value = 'all'}>any \n statusFilter.value = 'available'}>available \n statusFilter.value = 'beta'}>beta \n statusFilter.value = 'research'}>research \n
\n\n ${list.length === 0\n ? html`No apps match the current filters.
`\n : html`${list.map((app) => this.card(app))}
`}\n `;\n }\n\n private card(app: AppManifest) {\n const active = this.isActive(app.id);\n const cat = CATEGORIES[app.category];\n return html`\n \n
\n \n ${app.name} \n
\n
${app.summary}
\n
\n ${cat.label} \n ${app.status} \n ${app.budget ? html`budget ${app.budget} ` : ''}\n ${app.adr ? html`${app.adr} ` : ''}\n ${app.events?.length ? html`events ${app.events.join('·')} ` : ''}\n
\n \n
\n `;\n }\n}\n","/* Toast notification — shown briefly via window.dispatchEvent('nv-toast', detail). */\nimport { LitElement, html, css } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\n\n@customElement('nv-toast')\nexport class NvToast extends LitElement {\n @state() private visible = false;\n @state() private msg = '';\n @state() private icon = '✓';\n private timer: number | null = null;\n\n static styles = css`\n :host {\n position: fixed; bottom: 24px; left: 50%;\n transform: translateX(-50%) translateY(80px);\n background: var(--bg-2);\n border: 1px solid var(--line-2);\n border-radius: var(--radius);\n padding: 10px 14px;\n font-size: 12.5px;\n box-shadow: var(--shadow);\n z-index: 100;\n opacity: 0; pointer-events: none;\n transition: opacity 0.2s, transform 0.2s;\n display: flex; align-items: center; gap: 8px;\n }\n :host([visible]) {\n opacity: 1;\n transform: translateX(-50%) translateY(0);\n pointer-events: auto;\n }\n .icon { color: var(--accent); }\n `;\n\n override connectedCallback(): void {\n super.connectedCallback();\n window.addEventListener('nv-toast', this.onToast as EventListener);\n }\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n window.removeEventListener('nv-toast', this.onToast as EventListener);\n }\n\n private onToast = (e: Event): void => {\n const detail = (e as CustomEvent).detail as { msg?: string; icon?: string };\n this.msg = detail.msg ?? 'Done';\n this.icon = detail.icon ?? '✓';\n this.visible = true;\n this.setAttribute('visible', '');\n if (this.timer !== null) window.clearTimeout(this.timer);\n this.timer = window.setTimeout(() => {\n this.visible = false;\n this.removeAttribute('visible');\n }, 1800);\n };\n\n override render() {\n return html`${this.icon} ${this.msg} `;\n }\n}\n\nexport function toast(msg: string, icon = '✓'): void {\n window.dispatchEvent(new CustomEvent('nv-toast', { detail: { msg, icon } }));\n}\n","/* Modal dialog — opened via window.dispatchEvent('nv-modal', { title, body, buttons }). */\nimport { LitElement, html, css } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\n\ninterface ModalButton {\n label: string;\n variant?: 'ghost' | 'primary' | 'danger';\n onClick?: () => void;\n}\ninterface ModalReq {\n title: string;\n body: string;\n buttons?: ModalButton[];\n}\n\n@customElement('nv-modal')\nexport class NvModal extends LitElement {\n @state() private open = false;\n @state() private mTitle = '';\n @state() private mBody = '';\n @state() private buttons: ModalButton[] = [];\n\n static styles = css`\n :host {\n position: fixed; inset: 0;\n background: rgba(0,0,0,0.55);\n backdrop-filter: blur(4px);\n z-index: 200;\n display: grid; place-items: center;\n opacity: 0; pointer-events: none;\n transition: opacity 0.18s;\n }\n :host([open]) { opacity: 1; pointer-events: auto; }\n .modal {\n background: var(--bg-1);\n border: 1px solid var(--line-2);\n border-radius: var(--radius);\n box-shadow: 0 30px 80px -20px rgba(0,0,0,0.7);\n width: min(520px, 92vw);\n max-height: 86vh;\n display: flex; flex-direction: column;\n transform: translateY(12px) scale(0.98);\n transition: transform 0.22s cubic-bezier(0.2,0.7,0.3,1);\n }\n :host([open]) .modal { transform: translateY(0) scale(1); }\n .h {\n padding: 14px 16px;\n border-bottom: 1px solid var(--line);\n display: flex; align-items: center; justify-content: space-between;\n }\n .h .ttl { font-size: 14px; font-weight: 600; }\n .body { padding: 16px; overflow-y: auto; font-size: 13px; color: var(--ink-2); line-height: 1.55; }\n .f {\n padding: 12px 16px;\n border-top: 1px solid var(--line);\n display: flex; gap: 8px; justify-content: flex-end;\n }\n button {\n padding: 6px 12px;\n border-radius: 8px;\n font-size: 12.5px;\n cursor: pointer;\n font-family: inherit;\n border: 1px solid var(--line);\n background: var(--bg-2); color: var(--ink);\n }\n button.ghost { background: transparent; }\n button.primary { background: var(--accent); border-color: var(--accent); color: #1a0f00; }\n button.danger { background: var(--bad); border-color: var(--bad); color: #fff; }\n .close {\n width: 28px; height: 28px;\n background: transparent; border: 1px solid var(--line);\n border-radius: 6px;\n color: var(--ink-2);\n }\n `;\n\n override connectedCallback(): void {\n super.connectedCallback();\n window.addEventListener('nv-modal', this.onModal as EventListener);\n window.addEventListener('keydown', this.onKey);\n }\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n window.removeEventListener('nv-modal', this.onModal as EventListener);\n window.removeEventListener('keydown', this.onKey);\n }\n\n private onModal = (e: Event): void => {\n const r = (e as CustomEvent).detail as ModalReq;\n this.mTitle = r.title; this.mBody = r.body;\n this.buttons = r.buttons ?? [{ label: 'Close', variant: 'primary' }];\n this.open = true; this.setAttribute('open', '');\n };\n\n private onKey = (e: KeyboardEvent): void => {\n if (e.key === 'Escape' && this.open) this.close();\n };\n\n private close(): void { this.open = false; this.removeAttribute('open'); }\n private clickBtn(b: ModalButton): void { b.onClick?.(); this.close(); }\n\n override render() {\n return html`\n \n
\n
${this.mTitle}
\n
this.close()}>× \n
\n
\n
\n ${this.buttons.map((b) => html`\n this.clickBtn(b)}>${b.label} \n `)}\n
\n
\n `;\n }\n}\n\nexport function openModal(req: ModalReq): void {\n window.dispatchEvent(new CustomEvent('nv-modal', { detail: req }));\n}\n","/* Command palette ⌘K. */\nimport { LitElement, html, css } from 'lit';\nimport { customElement, state, query } from 'lit/decorators.js';\nimport { toast } from './nv-toast';\nimport { openModal } from './nv-modal';\nimport {\n getClient, theme, expectedWitness, witnessHex, witnessVerified, pushLog, running,\n} from '../store/appStore';\n\ninterface Cmd { ico: string; label: string; kbd?: string; run: () => void; }\n\n@customElement('nv-palette')\nexport class NvPalette extends LitElement {\n @state() private open = false;\n @state() private filter = '';\n @state() private idx = 0;\n @query('#palette-input') private inputEl!: HTMLInputElement;\n\n static styles = css`\n :host {\n position: fixed; inset: 0; z-index: 220;\n background: rgba(0,0,0,0.5);\n opacity: 0; pointer-events: none;\n transition: opacity 0.15s;\n display: flex; justify-content: center; padding-top: 12vh;\n backdrop-filter: blur(4px);\n }\n :host([open]) { opacity: 1; pointer-events: auto; }\n .palette {\n width: min(560px, 92vw);\n background: var(--bg-1);\n border: 1px solid var(--line-2);\n border-radius: var(--radius);\n box-shadow: 0 30px 80px -20px rgba(0,0,0,0.7);\n overflow: hidden;\n display: flex; flex-direction: column;\n max-height: 60vh;\n }\n .input {\n padding: 14px 16px;\n border-bottom: 1px solid var(--line);\n }\n input {\n width: 100%;\n background: transparent; border: none; outline: none;\n color: var(--ink); font-size: 14px;\n font-family: inherit;\n }\n .list { flex: 1; overflow-y: auto; padding: 4px; }\n .item {\n display: flex; align-items: center; gap: 10px;\n padding: 8px 12px;\n border-radius: 6px;\n cursor: pointer;\n font-size: 12.5px;\n }\n .item.active { background: var(--bg-3); }\n .item .ico { width: 20px; text-align: center; color: var(--accent); }\n .item .lbl { flex: 1; }\n .item .kbd {\n font-family: var(--mono); font-size: 10.5px;\n color: var(--ink-3);\n padding: 1px 5px; background: var(--bg-3); border-radius: 4px;\n }\n `;\n\n private cmds: Cmd[] = [\n { ico: '▶', label: 'Run pipeline', kbd: 'Space', run: async () => { await getClient()?.run(); running.value = true; toast('Pipeline running', '▶'); } },\n { ico: '❚', label: 'Pause pipeline', run: async () => { await getClient()?.pause(); running.value = false; toast('Paused', '❚❚'); } },\n { ico: '⟳', label: 'Reset pipeline', kbd: '⌘R', run: () => openModal({\n title: 'Reset pipeline?',\n body: 'Clears the frame stream and rewinds t to 0.
',\n buttons: [\n { label: 'Cancel', variant: 'ghost' },\n { label: 'Reset', variant: 'danger', onClick: async () => { await getClient()?.reset(); pushLog('warn', 'pipeline reset · t=0'); toast('Pipeline reset', '⟳'); } },\n ],\n }) },\n { ico: '✓', label: 'Verify witness', run: async () => {\n const c = getClient(); if (!c) return;\n witnessVerified.value = 'pending';\n const exp = expectedWitness.value;\n const eb = new Uint8Array(32);\n for (let i = 0; i < 32; i++) eb[i] = parseInt(exp.slice(i * 2, i * 2 + 2), 16);\n const r = await c.verifyWitness(eb);\n if (r.ok) { witnessVerified.value = 'ok'; witnessHex.value = exp; toast('Witness verified', '✓'); }\n else { witnessVerified.value = 'fail'; toast('Witness mismatch!', '✗'); }\n } },\n { ico: '☼', label: 'Toggle theme', kbd: '⌘/', run: () => { theme.value = theme.value === 'dark' ? 'light' : 'dark'; } },\n { ico: '⚙', label: 'Open settings', kbd: '⌘,', run: () => window.dispatchEvent(new CustomEvent('open-settings')) },\n { ico: '?', label: 'Keyboard shortcuts…', run: () => openModal({\n title: 'Keyboard shortcuts',\n body: `\n
⌘K / Ctrl K
Command palette
\n
Space
Play / pause
\n
⌘R
Reset
\n
⌘,
Settings
\n
⌘/
Toggle theme
\n
\\`
Debug HUD
\n
1 · 2 · 3
Inspector tabs
\n
Esc
Close modal/palette
\n
/
Focus REPL
\n
`,\n buttons: [{ label: 'Close', variant: 'primary' }],\n }) },\n { ico: 'i', label: 'About nvsim…', run: () => openModal({\n title: 'About nvsim',\n body: `nvsim is a deterministic, byte-reproducible forward simulator for nitrogen-vacancy diamond magnetometry.
\n This dashboard runs nvsim as WASM in a Web Worker. Same (scene, config, seed) → byte-identical SHA-256 witness across runs and machines.
\n License: MIT OR Apache-2.0 · See ADR-089, ADR-092.
`,\n buttons: [{ label: 'Close', variant: 'primary' }],\n }) },\n ];\n\n override connectedCallback(): void {\n super.connectedCallback();\n window.addEventListener('keydown', this.onKey);\n window.addEventListener('nv-palette', this.onOpen as EventListener);\n }\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n window.removeEventListener('keydown', this.onKey);\n window.removeEventListener('nv-palette', this.onOpen as EventListener);\n }\n\n private onKey = (e: KeyboardEvent): void => {\n if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') {\n e.preventDefault();\n this.openPal();\n } else if (e.key === 'Escape' && this.open) {\n this.closePal();\n } else if (this.open) {\n if (e.key === 'ArrowDown') { this.idx = Math.min(this.cmds.length - 1, this.idx + 1); e.preventDefault(); }\n else if (e.key === 'ArrowUp') { this.idx = Math.max(0, this.idx - 1); e.preventDefault(); }\n else if (e.key === 'Enter') { this.runIdx(); e.preventDefault(); }\n }\n };\n\n private onOpen = (): void => this.openPal();\n\n private openPal(): void {\n this.open = true; this.setAttribute('open', '');\n this.filter = ''; this.idx = 0;\n setTimeout(() => this.inputEl?.focus(), 0);\n }\n private closePal(): void { this.open = false; this.removeAttribute('open'); }\n\n private filtered(): Cmd[] {\n if (!this.filter.trim()) return this.cmds;\n const q = this.filter.toLowerCase();\n return this.cmds.filter((c) => c.label.toLowerCase().includes(q));\n }\n\n private runIdx(): void {\n const f = this.filtered();\n const c = f[this.idx];\n if (c) { c.run(); this.closePal(); }\n }\n\n override render() {\n const items = this.filtered();\n return html`\n \n
\n { this.filter = (e.target as HTMLInputElement).value; this.idx = 0; }} />\n
\n
\n ${items.map((c, i) => html`\n
{ this.idx = i; this.runIdx(); }}>\n ${c.ico} \n ${c.label} \n ${c.kbd ? html`${c.kbd} ` : ''}\n
\n `)}\n
\n
\n `;\n }\n}\n","/* Debug HUD toggled with `. Shows render fps, sim t, frames, |B|, SNR. */\nimport { LitElement, html, css } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\nimport { effect } from '@preact/signals-core';\nimport { fps, framesEmitted, bMag, snr, t as simT } from '../store/appStore';\n\n@customElement('nv-debug-hud')\nexport class NvDebugHud extends LitElement {\n @state() private open = false;\n @state() private renderFps = 0;\n private lastTs = performance.now();\n private frameCount = 0;\n private rafId = 0;\n\n static styles = css`\n :host {\n position: fixed; bottom: 8px; right: 8px;\n width: 220px;\n background: rgba(13,17,23,0.85);\n backdrop-filter: blur(8px);\n border: 1px solid var(--line-2);\n border-radius: 8px;\n padding: 8px 10px;\n font-family: var(--mono); font-size: 11px;\n color: var(--ink-2);\n z-index: 99;\n display: none;\n box-shadow: var(--shadow);\n }\n :host([open]) { display: block; }\n .h {\n display: flex; justify-content: space-between;\n font-weight: 600; color: var(--ink);\n margin-bottom: 6px; padding-bottom: 4px;\n border-bottom: 1px solid var(--line);\n }\n .x { cursor: pointer; color: var(--ink-3); }\n .row {\n display: flex; justify-content: space-between;\n padding: 1px 0;\n }\n .k { color: var(--ink-3); }\n .v { color: var(--ink); }\n `;\n\n override connectedCallback(): void {\n super.connectedCallback();\n window.addEventListener('keydown', this.onKey);\n effect(() => { fps.value; framesEmitted.value; bMag.value; snr.value; simT.value; this.requestUpdate(); });\n this.tick();\n }\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n window.removeEventListener('keydown', this.onKey);\n cancelAnimationFrame(this.rafId);\n }\n\n private onKey = (e: KeyboardEvent): void => {\n if (e.key === '`' && !(e.target as HTMLElement).matches('input, textarea')) {\n this.open = !this.open;\n this.toggleAttribute('open', this.open);\n }\n };\n\n private tick = (): void => {\n this.rafId = requestAnimationFrame(this.tick);\n const now = performance.now();\n this.frameCount++;\n if (now - this.lastTs >= 500) {\n this.renderFps = (this.frameCount * 1000) / (now - this.lastTs);\n this.frameCount = 0;\n this.lastTs = now;\n this.requestUpdate();\n }\n };\n\n override render() {\n return html`\n nvsim · debug { this.open = false; this.removeAttribute('open'); }}>✕
\n render fps ${this.renderFps.toFixed(1)}
\n sim fps ${fps.value > 0 ? Math.round(fps.value) : '—'}
\n frames ${framesEmitted.value.toString()}
\n |B| ${(bMag.value * 1e9).toFixed(3)} nT
\n SNR ${snr.value > 0 ? snr.value.toFixed(1) : '—'}
\n DOM ${document.querySelectorAll('*').length}
\n `;\n }\n}\n","/* Settings drawer — theme / density / motion / auto-update. */\nimport { LitElement, html, css } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\nimport { effect } from '@preact/signals-core';\nimport { theme, density, motionReduced, autoUpdate, transport, wsUrl } from '../store/appStore';\n\n@customElement('nv-settings-drawer')\nexport class NvSettingsDrawer extends LitElement {\n @state() private open = false;\n\n static styles = css`\n :host {\n position: fixed; top: 0; right: 0; bottom: 0;\n width: 420px; max-width: 100vw;\n background: var(--bg-1);\n border-left: 1px solid var(--line);\n z-index: 51;\n transform: translateX(100%);\n transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex; flex-direction: column;\n box-shadow: -20px 0 60px -20px rgba(0,0,0,0.5);\n }\n :host([open]) { transform: translateX(0); }\n .scrim {\n position: fixed; inset: 0;\n background: rgba(0,0,0,0.5);\n z-index: 50;\n opacity: 0; pointer-events: none;\n transition: opacity 0.2s;\n }\n :host([open]) .scrim { opacity: 1; pointer-events: auto; }\n .h {\n padding: 14px 16px;\n border-bottom: 1px solid var(--line);\n display: flex; align-items: center; justify-content: space-between;\n }\n .h .ttl { font-size: 14px; font-weight: 600; }\n .body { flex: 1; overflow-y: auto; padding: 16px; }\n .group { margin-bottom: 22px; }\n .group h4 {\n margin: 0 0 10px;\n font-size: 11px; font-weight: 600;\n text-transform: uppercase; letter-spacing: 0.08em;\n color: var(--ink-3);\n }\n .row {\n display: flex; justify-content: space-between; align-items: center;\n padding: 10px 0;\n border-bottom: 1px solid var(--line);\n }\n .row:last-child { border-bottom: 0; }\n .row .lbl { font-size: 13px; }\n .row .desc { font-size: 11.5px; color: var(--ink-3); margin-top: 2px; }\n .row > div:first-child { flex: 1; padding-right: 12px; }\n .seg {\n display: inline-flex;\n background: var(--bg-3);\n border: 1px solid var(--line);\n border-radius: var(--radius-sm);\n padding: 2px;\n }\n .seg button {\n padding: 4px 10px;\n background: transparent; border: none;\n border-radius: 6px;\n font-size: 11.5px; color: var(--ink-3);\n font-family: var(--mono);\n cursor: pointer;\n }\n .seg button.on { background: var(--bg-1); color: var(--ink); }\n .toggle {\n position: relative;\n width: 36px; height: 20px;\n background: var(--bg-3);\n border: 1px solid var(--line-2);\n border-radius: 999px;\n cursor: pointer;\n flex-shrink: 0;\n }\n .toggle::after {\n content: ''; position: absolute;\n top: 2px; left: 2px;\n width: 14px; height: 14px;\n background: var(--ink-3);\n border-radius: 50%;\n transition: transform 0.15s, background 0.15s;\n }\n .toggle.on { background: var(--accent); border-color: var(--accent); }\n .toggle.on::after { background: #1a0f00; transform: translateX(16px); }\n .close {\n width: 28px; height: 28px;\n background: transparent; border: 1px solid var(--line);\n border-radius: 6px;\n color: var(--ink-2);\n }\n input[type=\"text\"] {\n background: var(--bg-3);\n border: 1px solid var(--line);\n border-radius: 6px;\n padding: 6px 10px;\n color: var(--ink); font-family: var(--mono); font-size: 12px;\n outline: none;\n }\n `;\n\n override connectedCallback(): void {\n super.connectedCallback();\n effect(() => { theme.value; density.value; motionReduced.value; autoUpdate.value; transport.value; wsUrl.value; this.requestUpdate(); });\n window.addEventListener('open-settings', () => { this.open = true; this.setAttribute('open', ''); });\n }\n\n private close(): void { this.open = false; this.removeAttribute('open'); }\n\n override render() {\n return html`\n this.close()}>
\n \n
Settings
\n
this.close()}>× \n
\n \n
\n
Appearance \n
\n
\n
\n theme.value = 'dark'}>dark \n theme.value = 'light'}>light \n
\n
\n
\n
\n
Density
\n
Affects panel padding and font scale.
\n
\n
\n density.value = 'comfy'}>comfy \n density.value = 'default'}>default \n density.value = 'compact'}>compact \n
\n
\n
\n
\n
Reduce motion
\n
Disable rotating crystal & field-line animation.
\n
\n
motionReduced.value = !motionReduced.value}> \n
\n
\n\n
\n
Pipeline \n
\n
Auto-rerun on edit
\n
Restart pipeline when scene/config changes.
\n
autoUpdate.value = !autoUpdate.value}> \n
\n
\n\n
\n
Transport \n
\n
\n
\n transport.value = 'wasm'}>WASM \n transport.value = 'ws'}>WS \n
\n
\n ${transport.value === 'ws' ? html`\n
\n
\n
wsUrl.value = (e.target as HTMLInputElement).value} />\n
` : ''}\n
\n
\n `;\n }\n}\n","/* First-run welcome tour. 5 steps walking the user through the\n * dashboard's main concepts. Persists `seen` flag in IndexedDB so it\n * only shows the first time. ADR-092 §10 Pass 6.\n */\n\nimport { LitElement, html, css } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\nimport { kvGet, kvSet } from '../store/persistence';\n\ninterface TourStep {\n title: string;\n body: string;\n cta?: string;\n}\n\nconst STEPS: TourStep[] = [\n {\n title: 'Welcome to nvsim',\n body: `nvsim is an open-source, deterministic forward simulator for\n nitrogen-vacancy diamond magnetometry — a real Rust crate compiled to\n WASM and running in your browser, right now.
\n This 30-second tour highlights the four panels you'll use most.
`,\n cta: 'Start tour',\n },\n {\n title: '1. Scene canvas',\n body: `The middle panel shows your magnetic scene — sources you can\n drag (rebar, heart proxy, mains hum, ferrous door) and a single NV-diamond\n sensor in the centre. Field lines from each source connect to the sensor\n and animate while the pipeline runs.
\n Click 2 on your keyboard any time to jump to the Frame inspector.
`,\n },\n {\n title: '2. Run the pipeline',\n body: `Click the ▶ Run button (top-right) to start streaming\n MagFrame records at the digitiser's sample rate. The B-vector\n trace and Frame stream sparkline update live, and the FPS pill in the\n topbar shows the simulator's throughput in kHz.
\n Space toggles run/pause from anywhere.
`,\n },\n {\n title: '3. Witness panel',\n body: `The Witness tab is the heart of nvsim's determinism contract.\n Click Verify and the pipeline re-derives the SHA-256 over a 256-frame\n reference run and asserts it matches the constant pinned in the Rust crate.
\n Same input → same hash → byte-for-byte across browsers, OSes, transports.\n If the hash drifts, your build is non-canonical.
`,\n },\n {\n title: '4. App Store',\n body: `The grid icon on the left rail opens the App Store — every\n hot-loadable WASM edge module RuView ships, plus the simulators. 66 apps\n across 13 categories: medical, security, building, retail, industrial,\n signal, learning, autonomy, and more.
\n Toggle any card to mark it active in this session; the WS transport\n will push the activation set to a connected ESP32 mesh.
`,\n },\n {\n title: 'You are ready',\n body: `Press ⌘K (or Ctrl K ) any time for the command\n palette, ? for the full shortcuts list, or just start clicking.
\n Source on GitHub:\n github.com/ruvnet/RuView · ADR-089, ADR-092 · MIT/Apache-2.0.
`,\n cta: 'Get started',\n },\n];\n\n@customElement('nv-onboarding')\nexport class NvOnboarding extends LitElement {\n @state() private open = false;\n @state() private step = 0;\n\n static styles = css`\n :host {\n position: fixed; inset: 0;\n background: rgba(0, 0, 0, 0.55);\n backdrop-filter: blur(4px);\n z-index: 240;\n display: grid; place-items: center;\n opacity: 0; pointer-events: none;\n transition: opacity 0.18s;\n }\n :host([open]) { opacity: 1; pointer-events: auto; }\n .card {\n background: var(--bg-1);\n border: 1px solid var(--line-2);\n border-radius: var(--radius);\n box-shadow: 0 30px 80px -20px rgba(0,0,0,0.7);\n width: min(560px, 92vw);\n max-height: 86vh;\n display: flex; flex-direction: column;\n transform: translateY(12px) scale(0.98);\n transition: transform 0.22s cubic-bezier(0.2,0.7,0.3,1);\n }\n :host([open]) .card { transform: translateY(0) scale(1); }\n .h {\n padding: 20px 22px 8px;\n display: flex; justify-content: space-between; align-items: flex-start;\n }\n .h h2 { margin: 0; font-size: 18px; letter-spacing: -0.01em; }\n .body {\n padding: 8px 22px 16px;\n font-size: 13px; color: var(--ink-2); line-height: 1.55;\n overflow-y: auto;\n }\n .body p { margin: 0 0 12px; }\n .body code, .body kbd {\n font-family: var(--mono); font-size: 11.5px;\n padding: 1px 5px; background: var(--bg-3);\n border: 1px solid var(--line); border-radius: 4px;\n color: var(--accent);\n }\n .footer {\n display: flex; align-items: center; gap: 12px;\n padding: 12px 22px;\n border-top: 1px solid var(--line);\n }\n .dots { display: flex; gap: 6px; flex: 1; }\n .dot {\n width: 6px; height: 6px; border-radius: 50%;\n background: var(--bg-3); border: 1px solid var(--line-2);\n }\n .dot.active { background: var(--accent); border-color: var(--accent); }\n button {\n padding: 8px 14px;\n border-radius: 8px;\n font-size: 12.5px; font-weight: 500;\n border: 1px solid var(--line);\n background: var(--bg-2); color: var(--ink);\n cursor: pointer;\n font-family: inherit;\n }\n button.primary {\n background: var(--accent); border-color: var(--accent);\n color: #1a0f00;\n }\n button.ghost { background: transparent; }\n .skip {\n width: 28px; height: 28px;\n background: transparent; border: 1px solid var(--line);\n border-radius: 6px; color: var(--ink-2);\n }\n `;\n\n override async connectedCallback(): Promise {\n super.connectedCallback();\n window.addEventListener('nv-show-tour', this.show as EventListener);\n const seen = await kvGet('onboarding-seen');\n if (!seen) {\n this.open = true;\n this.setAttribute('open', '');\n }\n }\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n window.removeEventListener('nv-show-tour', this.show as EventListener);\n }\n\n private show = (): void => {\n this.step = 0;\n this.open = true;\n this.setAttribute('open', '');\n };\n\n private async dismiss(): Promise {\n this.open = false;\n this.removeAttribute('open');\n await kvSet('onboarding-seen', true);\n }\n\n private next(): void {\n if (this.step < STEPS.length - 1) this.step++;\n else void this.dismiss();\n }\n\n private prev(): void {\n if (this.step > 0) this.step--;\n }\n\n override render() {\n const s = STEPS[this.step];\n return html`\n \n
\n
${s.title} \n this.dismiss()} aria-label=\"Skip tour\">× \n \n
\n \n
\n `;\n }\n}\n","/* Top-level shell: 4-zone grid with rail / topbar / sidebar / scene / inspector / console.\n * View routing is per-rail-button: the central area swaps between\n * ``, ``, etc. */\n\nimport { LitElement, html, css } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\nimport './nv-rail';\nimport './nv-topbar';\nimport './nv-sidebar';\nimport './nv-scene';\nimport './nv-inspector';\nimport './nv-console';\nimport './nv-app-store';\nimport './nv-toast';\nimport './nv-modal';\nimport './nv-palette';\nimport './nv-debug-hud';\nimport './nv-settings-drawer';\nimport './nv-onboarding';\n\nexport type View = 'scene' | 'apps' | 'settings';\n\n@customElement('nv-app')\nexport class NvApp extends LitElement {\n @state() private view: View = 'scene';\n\n static styles = css`\n :host {\n display: block;\n height: 100vh;\n width: 100vw;\n background: var(--bg-0);\n }\n .app {\n display: grid;\n grid-template-columns: 56px 280px 1fr 340px;\n grid-template-rows: 48px 1fr 220px;\n grid-template-areas:\n 'rail topbar topbar topbar'\n 'rail sidebar main inspector'\n 'rail sidebar console inspector';\n height: 100vh;\n width: 100vw;\n }\n nv-rail { grid-area: rail; }\n nv-topbar { grid-area: topbar; }\n nv-sidebar { grid-area: sidebar; }\n .main { grid-area: main; min-width: 0; min-height: 0; position: relative; overflow: hidden; }\n nv-inspector { grid-area: inspector; }\n nv-console { grid-area: console; min-height: 0; }\n @media (max-width: 1180px) {\n .app {\n grid-template-columns: 56px 1fr 320px;\n grid-template-areas:\n 'rail topbar topbar'\n 'rail main inspector'\n 'rail console console';\n }\n nv-sidebar { display: none; }\n }\n @media (max-width: 860px) {\n .app {\n grid-template-columns: 1fr;\n grid-template-rows: 52px 1fr 200px;\n grid-template-areas:\n 'topbar'\n 'main'\n 'console';\n }\n nv-rail, nv-sidebar, nv-inspector { display: none; }\n }\n `;\n\n override render() {\n return html`\n \n
) => (this.view = e.detail)}> \n
\n
\n
\n ${this.view === 'apps' ? html` ` : html` `}\n
\n
\n
\n
\n \n \n \n \n \n \n `;\n }\n}\n","/* Common NvsimClient interface — both WasmClient and WsClient implement it.\n * Dashboard binds to this interface and never to a concrete client.\n * Aligns with ADR-092 §5.2.\n */\n\nexport interface PipelineConfigJson {\n digitiser?: {\n f_s_hz: number;\n f_mod_hz: number;\n lp_cutoff_hz: number;\n };\n sensor?: {\n n_centers: number;\n contrast: number;\n t2_star_s: number;\n shot_noise_disabled?: boolean;\n };\n dt_s?: number | null;\n}\n\nexport interface SceneJson {\n dipoles: { position: [number, number, number]; moment: [number, number, number] }[];\n loops: {\n centre: [number, number, number];\n normal: [number, number, number];\n radius: number;\n current: number;\n n_segments: number;\n }[];\n ferrous: {\n position: [number, number, number];\n volume: number;\n susceptibility: number;\n }[];\n eddy: unknown[];\n sensors: [number, number, number][];\n ambient_field: [number, number, number];\n}\n\nexport interface MagFrameRecord {\n magic: number;\n version: number;\n flags: number;\n sensorId: number;\n tUs: bigint;\n bPt: [number, number, number];\n sigmaPt: [number, number, number];\n noiseFloorPtSqrtHz: number;\n temperatureK: number;\n raw: Uint8Array;\n}\n\nexport interface MagFrameBatch {\n frames: MagFrameRecord[];\n bytes: Uint8Array;\n}\n\nexport type NvsimEvent =\n | { type: 'log'; level: 'info' | 'warn' | 'err' | 'dbg' | 'ok'; msg: string }\n | { type: 'witness'; hex: string }\n | { type: 'fps'; value: number }\n | { type: 'state'; running: boolean; t: number; framesEmitted: number };\n\nexport interface RunOpts { frames?: number }\n\nexport interface NvsimClient {\n loadScene(scene: SceneJson): Promise;\n setConfig(cfg: PipelineConfigJson): Promise;\n setSeed(seed: bigint): Promise;\n reset(): Promise;\n run(opts?: RunOpts): Promise;\n pause(): Promise;\n step(direction: 'fwd' | 'back', dtMs: number): Promise;\n\n onFrames(cb: (batch: MagFrameBatch) => void): void;\n onEvent(cb: (ev: NvsimEvent) => void): void;\n\n generateWitness(samples: number): Promise;\n verifyWitness(expected: Uint8Array): Promise<{ ok: true } | { ok: false; actual: Uint8Array }>;\n exportProofBundle(): Promise;\n\n buildId(): Promise;\n close(): Promise;\n}\n\n/** Parse one MagFrame from a 60-byte slice. Layout matches `nvsim::frame`. */\nexport function parseMagFrame(view: DataView, offset: number, raw: Uint8Array): MagFrameRecord {\n // v1 layout: magic(u32) | version(u16) | flags(u16) | sensor_id(u16) | _reserved(u16) |\n // t_us(u64) | b_pt[3](f32) | sigma_pt[3](f32) | noise_floor_pt_sqrt_hz(f32) |\n // temperature_k(f32) — 60 bytes total. All little-endian.\n const magic = view.getUint32(offset + 0, true);\n const version = view.getUint16(offset + 4, true);\n const flags = view.getUint16(offset + 6, true);\n const sensorId = view.getUint16(offset + 8, true);\n // skip 2 bytes reserved at offset+10\n const tUs = view.getBigUint64(offset + 12, true);\n const bx = view.getFloat32(offset + 20, true);\n const by = view.getFloat32(offset + 24, true);\n const bz = view.getFloat32(offset + 28, true);\n const sx = view.getFloat32(offset + 32, true);\n const sy = view.getFloat32(offset + 36, true);\n const sz = view.getFloat32(offset + 40, true);\n const noiseFloorPtSqrtHz = view.getFloat32(offset + 44, true);\n const temperatureK = view.getFloat32(offset + 48, true);\n return {\n magic,\n version,\n flags,\n sensorId,\n tUs,\n bPt: [bx, by, bz],\n sigmaPt: [sx, sy, sz],\n noiseFloorPtSqrtHz,\n temperatureK,\n raw: raw.subarray(offset, offset + 60),\n };\n}\n\nexport function parseFrameBatch(bytes: Uint8Array): MagFrameRecord[] {\n const frameSize = 60;\n const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n const out: MagFrameRecord[] = [];\n for (let off = 0; off + frameSize <= bytes.byteLength; off += frameSize) {\n out.push(parseMagFrame(view, off, bytes));\n }\n return out;\n}\n","/* Default `NvsimClient` implementation. Talks to the Web Worker that\n * hosts the nvsim WASM module. ADR-092 §5.4 + §6.3. */\n\nimport {\n type NvsimClient,\n type SceneJson,\n type PipelineConfigJson,\n type RunOpts,\n type MagFrameBatch,\n type NvsimEvent,\n parseFrameBatch,\n} from './NvsimClient';\n\ninterface PendingRequest {\n resolve: (v: T) => void;\n reject: (err: Error) => void;\n}\n\nexport interface WasmBootInfo {\n buildVersion: string;\n frameMagic: number;\n frameBytes: number;\n expectedWitnessHex: string;\n}\n\nexport class WasmClient implements NvsimClient {\n private worker: Worker;\n private nextId = 1;\n private pending = new Map>();\n private frameSubs = new Set<(b: MagFrameBatch) => void>();\n private eventSubs = new Set<(e: NvsimEvent) => void>();\n private bootInfo: WasmBootInfo | null = null;\n\n constructor() {\n this.worker = new Worker(new URL('./worker.ts', import.meta.url), { type: 'module' });\n this.worker.addEventListener('message', (ev) => this.onMessage(ev));\n this.worker.addEventListener('error', (e) =>\n this.eventSubs.forEach((s) => s({ type: 'log', level: 'err', msg: String(e.message) })),\n );\n }\n\n private onMessage(ev: MessageEvent): void {\n const m = ev.data as { type: string; id?: number; [k: string]: unknown };\n if (m.type === 'frames') {\n const buf = m.batch as ArrayBuffer;\n const bytes = new Uint8Array(buf);\n const frames = parseFrameBatch(bytes);\n const batch: MagFrameBatch = { frames, bytes };\n this.frameSubs.forEach((s) => s(batch));\n const fps = m.fps as number;\n if (fps > 0) {\n this.eventSubs.forEach((s) => s({ type: 'fps', value: fps }));\n }\n return;\n }\n if (m.type === 'state') {\n this.eventSubs.forEach((s) =>\n s({\n type: 'state',\n running: Boolean(m.running),\n t: 0,\n framesEmitted: Number(m.framesEmitted ?? 0),\n }),\n );\n return;\n }\n if (m.type === 'ready') {\n return;\n }\n if (m.type === 'err' && m.id == null) {\n this.eventSubs.forEach((s) =>\n s({ type: 'log', level: 'err', msg: String(m.msg) }),\n );\n return;\n }\n if (typeof m.id === 'number' && this.pending.has(m.id)) {\n const p = this.pending.get(m.id)!;\n this.pending.delete(m.id);\n if (m.type === 'err') p.reject(new Error(String(m.msg)));\n else p.resolve(m);\n }\n }\n\n private rpc(msg: Record, transfer: Transferable[] = []): Promise {\n const id = this.nextId++;\n return new Promise((resolve, reject) => {\n this.pending.set(id, { resolve: resolve as (v: unknown) => void, reject });\n this.worker.postMessage({ ...msg, id }, transfer);\n });\n }\n\n async boot(): Promise {\n if (this.bootInfo) return this.bootInfo;\n // Pass Vite's resolved BASE_URL so the worker can locate /nvsim-pkg/\n // under the same prefix the dashboard is served from (e.g. /RuView/nvsim/\n // on GitHub Pages, \"/\" in dev).\n const base = import.meta.env.BASE_URL ?? '/';\n const r = await this.rpc<{ buildVersion: string; frameMagic: number; frameBytes: number; expectedWitnessHex: string }>(\n { type: 'boot', base },\n );\n this.bootInfo = {\n buildVersion: r.buildVersion,\n frameMagic: r.frameMagic,\n frameBytes: r.frameBytes,\n expectedWitnessHex: r.expectedWitnessHex,\n };\n return this.bootInfo;\n }\n\n async loadScene(scene: SceneJson): Promise {\n await this.rpc({ type: 'setScene', json: JSON.stringify(scene) });\n }\n\n async setConfig(cfg: PipelineConfigJson): Promise {\n await this.rpc({ type: 'setConfig', json: JSON.stringify(cfg) });\n }\n\n async setSeed(seed: bigint): Promise {\n await this.rpc({ type: 'setSeed', seed: Number(seed & 0xFFFFFFFFn) });\n }\n\n async reset(): Promise {\n await this.rpc({ type: 'reset' });\n }\n\n async run(_opts?: RunOpts): Promise {\n await this.rpc({ type: 'run' });\n }\n\n async pause(): Promise {\n await this.rpc({ type: 'pause' });\n }\n\n async step(_direction: 'fwd' | 'back', _dtMs: number): Promise {\n await this.rpc({ type: 'step' });\n }\n\n onFrames(cb: (batch: MagFrameBatch) => void): void { this.frameSubs.add(cb); }\n onEvent(cb: (ev: NvsimEvent) => void): void { this.eventSubs.add(cb); }\n\n async generateWitness(samples: number): Promise {\n const r = await this.rpc<{ witness: ArrayBuffer; hex: string }>({ type: 'witnessGenerate', samples });\n return new Uint8Array(r.witness);\n }\n\n async verifyWitness(expected: Uint8Array): Promise<{ ok: true } | { ok: false; actual: Uint8Array }> {\n const buf = expected.slice().buffer;\n const r = await this.rpc<{ ok: boolean; actual: ArrayBuffer; actualHex: string }>(\n { type: 'witnessVerify', samples: 256, expected: buf },\n [buf],\n );\n if (r.ok) return { ok: true };\n return { ok: false, actual: new Uint8Array(r.actual) };\n }\n\n async exportProofBundle(): Promise {\n // Bundle = REFERENCE_SCENE_JSON + computed witness hex + version. Wraps\n // the same artifacts `Proof::generate` produces natively. ADR-092 §6.1.\n const w = await this.generateWitness(256);\n const hex = Array.from(w).map((b) => b.toString(16).padStart(2, '0')).join('');\n const info = this.bootInfo ?? (await this.boot());\n const manifest = JSON.stringify(\n {\n kind: 'nvsim-proof-bundle',\n version: info.buildVersion,\n seed: '0x0000002A',\n nSamples: 256,\n witness: hex,\n expected: info.expectedWitnessHex,\n ok: hex === info.expectedWitnessHex,\n ts: new Date().toISOString(),\n },\n null,\n 2,\n );\n return new Blob([manifest], { type: 'application/json' });\n }\n\n async buildId(): Promise {\n const r = await this.rpc<{ buildId: string }>({ type: 'buildId' });\n return r.buildId;\n }\n\n async close(): Promise {\n this.worker.terminate();\n }\n}\n","/* nvsim dashboard entry — boots the WasmClient, mounts . */\nimport './app.css';\nimport './components/nv-app';\nimport { effect } from '@preact/signals-core';\n\nimport { WasmClient } from './transport/WasmClient';\nimport {\n setClient, transport, theme, density, motionReduced,\n pushLog, expectedWitness, framesEmitted, fps, lastB, bMag,\n pushTrace, pushStripBar, lastFrame, sceneJson, witnessHex,\n} from './store/appStore';\nimport { kvGet, kvSet } from './store/persistence';\n\nfunction applyTheme(t: string): void {\n document.documentElement.setAttribute('data-theme', t);\n}\nfunction applyDensity(d: string): void {\n document.body.classList.remove('density-comfy', 'density-default', 'density-compact');\n document.body.classList.add(`density-${d}`);\n}\nfunction applyMotion(reduced: boolean): void {\n document.body.classList.toggle('reduce-motion', reduced);\n}\n\n(async () => {\n // Restore persisted prefs\n const t = (await kvGet<'dark' | 'light'>('theme')) ?? 'dark';\n const d = (await kvGet<'comfy' | 'default' | 'compact'>('density')) ?? 'default';\n const m = (await kvGet('motionReduced')) ?? false;\n theme.value = t; applyTheme(t);\n density.value = d; applyDensity(d);\n motionReduced.value = m; applyMotion(m);\n\n // React to changes → persist\n effect(() => { applyTheme(theme.value); kvSet('theme', theme.value); });\n effect(() => { applyDensity(density.value); kvSet('density', density.value); });\n effect(() => { applyMotion(motionReduced.value); kvSet('motionReduced', motionReduced.value); });\n\n // Boot WASM client\n const client = new WasmClient();\n setClient(client);\n\n pushLog('info', 'nvsim — booting WASM runtime');\n client.onEvent((ev) => {\n if (ev.type === 'log') pushLog(ev.level, ev.msg);\n if (ev.type === 'fps') fps.value = ev.value;\n if (ev.type === 'state') {\n framesEmitted.value = BigInt(ev.framesEmitted);\n }\n });\n\n client.onFrames((batch) => {\n if (batch.frames.length === 0) return;\n const last = batch.frames[batch.frames.length - 1];\n lastFrame.value = last;\n const bx = last.bPt[0] * 1e-12; // pT → T\n const by = last.bPt[1] * 1e-12;\n const bz = last.bPt[2] * 1e-12;\n lastB.value = [bx, by, bz];\n bMag.value = Math.sqrt(bx * bx + by * by + bz * bz);\n // For trace display we use nT scale.\n pushTrace([bx * 1e9, by * 1e9, bz * 1e9]);\n const amp = Math.min(1, Math.abs(bz * 1e9) / 5 + 0.3);\n pushStripBar(amp);\n });\n\n try {\n const info = await client.boot();\n expectedWitness.value = info.expectedWitnessHex;\n pushLog('ok', `WASM module ready · nvsim@${info.buildVersion} · magic=0x${info.frameMagic.toString(16).toUpperCase()}`);\n pushLog('info', `expected witness · ${info.expectedWitnessHex.slice(0, 16)}…`);\n\n // Load reference scene by default.\n sceneJson.value = '(reference scene)';\n transport.value = 'wasm';\n } catch (e) {\n pushLog('err', `boot failed: ${(e as Error).message}`);\n }\n\n // Auto-verify witness once at boot — proves WASM determinism contract.\n try {\n const exp = expectedWitness.value;\n if (exp) {\n const expBytes = new Uint8Array(32);\n for (let i = 0; i < 32; i++) expBytes[i] = parseInt(exp.slice(i * 2, i * 2 + 2), 16);\n const r = await client.verifyWitness(expBytes);\n if (r.ok) {\n witnessHex.value = exp;\n pushLog('ok', `witness verified · determinism gate ✓`);\n } else {\n const actual = Array.from(r.actual)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n witnessHex.value = actual;\n pushLog('err', `WITNESS MISMATCH · expected ${exp.slice(0, 16)}… got ${actual.slice(0, 16)}…`);\n }\n }\n } catch (e) {\n pushLog('warn', `witness verify skipped: ${(e as Error).message}`);\n }\n})();\n"],"names":["t","e","o","r","n","i","s","c","NvRail","LitElement","v","html","css","__decorateClass","property","customElement","transport","signal","wsUrl","running","framesEmitted","seed","fs","fmod","dtMs","noiseEnabled","theme","density","motionReduced","autoUpdate","lastB","bMag","snr","fps","witnessHex","witnessVerified","expectedWitness","lastFrame","traceX","traceY","traceZ","stripBars","sceneName","sceneJson","consolePaused","consoleFilter","transportLabel","computed","_client","setClient","getClient","consoleLines","MAX_LINES","pushLog","level","msg","next","pushTrace","b","x","y","z","pushStripBar","amp","NvTopbar","effect","seedHex","NvSidebar","NvScene","id","item","svgEl","pt","it","vbX","vbY","bnT","bMagNT","animClass","svg","state","NvInspector","exp","expBytes","actual","make","arr","p","f","bytes","hex","status","cls","label","NvConsole","body","l","line","cmd","args","arg","filter","visible","k","ts","tsStr","query","APPS","CATEGORIES","defaultActivations","a","fuzzyMatch","app","q","score","DB_NAME","DB_VER","STORE","dbPromise","openDb","resolve","reject","req","db","kvGet","key","kvSet","value","tx","activations","activeCat","statusFilter","saved","NvAppStore","list","counts","activeCount","active","cat","NvToast","detail","toast","icon","NvModal","openModal","NvPalette","eb","items","NvDebugHud","now","simT","NvSettingsDrawer","STEPS","NvOnboarding","_","NvApp","parseMagFrame","view","offset","raw","magic","version","flags","sensorId","tUs","bx","by","bz","sx","sy","sz","noiseFloorPtSqrtHz","temperatureK","parseFrameBatch","out","off","WasmClient","ev","m","buf","batch","transfer","scene","cfg","_opts","_direction","_dtMs","cb","samples","expected","w","info","manifest","applyTheme","applyDensity","d","applyMotion","reduced","client","last"],"mappings":"00BAAA;AAAA;AAAA;AAAA;AAAA,GAKA,MAAMA,EAAEA,GAAG,CAACC,EAAEC,IAAI,CAAUA,WAAEA,EAAE,eAAe,IAAI,CAAC,eAAe,OAAOF,EAAEC,CAAC,CAAC,CAAC,EAAE,eAAe,OAAOD,EAAEC,CAAC,CAAC,ECJ3G;AAAA;AAAA;AAAA;AAAA,GAIG,MAAMC,GAAE,CAAC,UAAU,GAAG,KAAK,OAAO,UAAUD,GAAE,QAAQ,GAAG,WAAWD,EAAC,EAAEG,GAAE,CAACH,EAAEE,GAAED,EAAEE,IAAI,CAAC,KAAK,CAAC,KAAKC,EAAE,SAASC,CAAC,EAAEF,EAAE,IAAIG,EAAE,WAAW,oBAAoB,IAAID,CAAC,EAAE,GAAYC,IAAT,QAAY,WAAW,oBAAoB,IAAID,EAAEC,EAAE,IAAI,GAAG,EAAaF,IAAX,YAAgBJ,EAAE,OAAO,OAAOA,CAAC,GAAG,QAAQ,IAAIM,EAAE,IAAIH,EAAE,KAAKH,CAAC,EAAeI,IAAb,WAAe,CAAC,KAAK,CAAC,KAAKF,CAAC,EAAEC,EAAE,MAAM,CAAC,IAAIA,EAAE,CAAC,MAAMC,EAAEH,EAAE,IAAI,KAAK,IAAI,EAAEA,EAAE,IAAI,KAAK,KAAKE,CAAC,EAAE,KAAK,cAAcD,EAAEE,EAAEJ,EAAE,GAAGG,CAAC,CAAC,EAAE,KAAKF,EAAE,CAAC,OAAgBA,IAAT,QAAY,KAAK,EAAEC,EAAE,OAAOF,EAAEC,CAAC,EAAEA,CAAC,CAAC,CAAC,CAAC,GAAcG,IAAX,SAAa,CAAC,KAAK,CAAC,KAAKF,CAAC,EAAEC,EAAE,OAAO,SAASA,EAAE,CAAC,MAAMC,EAAE,KAAKF,CAAC,EAAED,EAAE,KAAK,KAAKE,CAAC,EAAE,KAAK,cAAcD,EAAEE,EAAEJ,EAAE,GAAGG,CAAC,CAAC,CAAC,CAAC,MAAM,MAAM,mCAAmCC,CAAC,CAAC,EAAE,SAASA,GAAEJ,EAAE,CAAC,MAAM,CAACC,EAAEC,IAAc,OAAOA,GAAjB,SAAmBC,GAAEH,EAAEC,EAAEC,CAAC,GAAG,CAACF,EAAEC,EAAEC,IAAI,CAAC,MAAMC,EAAEF,EAAE,eAAeC,CAAC,EAAE,OAAOD,EAAE,YAAY,eAAeC,EAAEF,CAAC,EAAEG,EAAE,OAAO,yBAAyBF,EAAEC,CAAC,EAAE,MAAM,GAAGF,EAAEC,EAAEC,CAAC,CAAC,CCJ/yB;AAAA;AAAA;AAAA;AAAA,GAIG,SAASC,EAAEA,EAAE,CAAC,OAAOH,GAAE,CAAC,GAAGG,EAAE,MAAM,GAAG,UAAU,EAAE,CAAC,CAAC,CCLvD;AAAA;AAAA;AAAA;AAAA,GAKA,MAAMF,GAAE,CAAC,EAAE,EAAEM,KAAKA,EAAE,aAAa,GAAGA,EAAE,WAAW,GAAG,QAAQ,UAAoB,OAAO,GAAjB,UAAoB,OAAO,eAAe,EAAE,EAAEA,CAAC,EAAEA,GCJvH;AAAA;AAAA;AAAA;AAAA,GAIG,SAASN,GAAE,EAAEE,EAAE,CAAC,MAAM,CAACC,EAAEE,EAAED,IAAI,CAAC,MAAMH,EAAEF,GAAGA,EAAE,YAAY,cAAc,CAAC,GAAG,KAAwP,OAAOA,GAAEI,EAAEE,EAAE,CAAC,KAAK,CAAC,OAAOJ,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,sMCCrW,IAAMM,GAAN,cAAqBC,CAAW,CAAhC,aAAA,CAAA,MAAA,GAAA,SAAA,EACO,KAAA,KAAa,OAAA,CAiDjB,SAASC,EAAe,CAC9B,KAAK,cAAc,IAAI,YAAY,WAAY,CAAE,OAAQA,CAAA,CAAG,CAAC,CAC/D,CAES,QAAS,CAChB,OAAOC;AAAAA;AAAAA,2BAEgB,KAAK,OAAS,QAAU,SAAW,EAAE;AAAA,iBAC/C,IAAM,KAAK,SAAS,OAAO,CAAC;AAAA;AAAA;AAAA,2BAGlB,KAAK,OAAS,OAAS,SAAW,EAAE;AAAA,iBAC9C,IAAM,KAAK,SAAS,MAAM,CAAC;AAAA;AAAA;AAAA,qDAGS,IAAM,KAAK,SAAS,OAAO,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAQhE,IAAM,KAAK,cAAc,IAAI,YAAY,gBAAiB,CAAE,QAAS,GAAM,SAAU,EAAA,CAAM,CAAC,CAAC;AAAA;AAAA;AAAA,KAI5G,CACF,EA9EaH,GAGJ,OAASI;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA,IAFJC,GAAA,CAAXC,GAAA,CAAS,EADCN,GACC,UAAA,OAAA,CAAA,EADDA,GAANK,GAAA,CADNE,EAAc,SAAS,CAAA,EACXP,EAAA,ECON,MAAMQ,EAAYC,EAAsB,MAAM,EACxCC,GAAQD,EAAe,EAAE,EACbA,EAAgB,EAAK,EAChBA,EAAsB,IAAI,EAEjD,MAAME,EAAUF,EAAgB,EAAK,EACtBA,EAAgB,EAAI,EACrBA,EAAe,CAAG,EAChC,MAAMjB,GAAIiB,EAAe,CAAC,EACpBG,GAAgBH,EAAe,EAAE,EAEjCI,EAAOJ,EAAe,WAAW,EAEjCK,EAAKL,EAAe,GAAK,EACzBM,EAAON,EAAe,GAAI,EAC1BO,GAAOP,EAAe,CAAG,EACzBQ,GAAeR,EAAgB,EAAI,EAEnCS,EAAQT,EAAc,MAAM,EAC5BU,EAAUV,EAAgB,SAAS,EACnCW,EAAgBX,EAAgB,EAAK,EACrCY,GAAaZ,EAAgB,EAAI,EAEjCa,GAAQb,EAAiC,CAAC,EAAG,EAAG,CAAC,CAAC,EAClDc,EAAOd,EAAe,CAAC,EACvBe,EAAMf,EAAe,CAAC,EACtBgB,EAAMhB,EAAe,CAAC,EAEtBiB,EAAajB,EAAe,EAAE,EAC9BkB,EAAkBlB,EAA2C,MAAM,EACnEmB,EAAkBnB,EAAe,EAAE,EAEnCoB,GAAYpB,EAA8B,IAAI,EAC9CqB,GAASrB,EAAiB,EAAE,EAC5BsB,GAAStB,EAAiB,EAAE,EAC5BuB,GAASvB,EAAiB,EAAE,EAC5BwB,GAAYxB,EAAiB,EAAE,EAE/ByB,GAAYzB,EAAe,iBAAiB,EAC5C0B,GAAY1B,EAAe,EAAE,EAE7B2B,EAAgB3B,EAAgB,EAAK,EACrC4B,GAAgB5B,EAAuD,KAAK,EAE5E6B,GAAiBC,GAAiB,IAC7C/B,EAAU,QAAU,OAAS,OAAS,IACxC,EAEA,IAAIgC,GAA8B,KAC3B,SAASC,GAAU1C,EAAsB,CAAEyC,GAAUzC,CAAG,CACxD,SAAS2C,GAAgC,CAAE,OAAOF,EAAS,CAO3D,MAAMG,EAAelC,EAAsB,EAAE,EAC9CmC,GAAY,IAEX,SAASC,EAAQC,EAA6BC,EAAmB,CACtE,GAAIX,EAAc,MAAO,OACzB,MAAMY,EAAOL,EAAa,MAAM,MAAA,EAEhC,IADAK,EAAK,KAAK,CAAE,GAAI,KAAK,MAAO,MAAAF,EAAO,IAAAC,EAAK,EACjCC,EAAK,OAASJ,IAAWI,EAAK,MAAA,EACrCL,EAAa,MAAQK,CACvB,CAEO,SAASC,GAAUC,EAAmC,CAE3D,MAAMC,EAAIrB,GAAO,MAAM,MAAA,EAASqB,EAAE,KAAKD,EAAE,CAAC,CAAC,EAAOC,EAAE,OAAS,KAAKA,EAAE,MAAA,EACpE,MAAMC,EAAIrB,GAAO,MAAM,MAAA,EAASqB,EAAE,KAAKF,EAAE,CAAC,CAAC,EAAOE,EAAE,OAAS,KAAKA,EAAE,MAAA,EACpE,MAAMC,EAAIrB,GAAO,MAAM,MAAA,EAASqB,EAAE,KAAKH,EAAE,CAAC,CAAC,EAAOG,EAAE,OAAS,KAAKA,EAAE,MAAA,EACpEvB,GAAO,MAAQqB,EACfpB,GAAO,MAAQqB,EACfpB,GAAO,MAAQqB,CACjB,CAEO,SAASC,GAAaC,EAAmB,CAE9C,MAAMP,EAAOf,GAAU,MAAM,MAAA,EAE7B,IADAe,EAAK,KAAK,KAAK,IAAI,EAAG,KAAK,IAAI,EAAGO,CAAG,CAAC,CAAC,EAChCP,EAAK,OAAS,IAAKA,EAAK,MAAA,EAC/Bf,GAAU,MAAQe,CACpB,gJCvFO,IAAMQ,GAAN,cAAuBvD,CAAW,CAwC9B,mBAA0B,CACjC,MAAM,kBAAA,EACNwD,EAAO,IAAM,CAAEhC,EAAI,MAAOa,GAAe,MAAOzB,EAAK,MAAOK,EAAM,MAAOgB,GAAU,MAAOvB,EAAQ,MAAO,KAAK,cAAA,CAAiB,CAAC,CAClI,CAEA,MAAc,WAA2B,CACvC,MAAMZ,EAAI2C,EAAA,EAAkB3C,IACxBY,EAAQ,OAAS,MAAMZ,EAAE,MAAA,EAASY,EAAQ,MAAQ,KAC/C,MAAMZ,EAAE,IAAA,EAAOY,EAAQ,MAAQ,IACxC,CACA,MAAc,OAAuB,CACnC,MAAMZ,EAAI2C,EAAA,EAAkB3C,GAC5B,MAAMA,EAAE,MAAA,CACV,CACQ,aAAoB,CAC1BmB,EAAM,MAAQA,EAAM,QAAU,OAAS,QAAU,MACnD,CAES,QAAS,CAChB,MAAMwC,EAAU7C,EAAK,MAAM,SAAS,EAAE,EAAE,cAAc,SAAS,EAAG,GAAG,EACrE,OAAOV;AAAAA;AAAAA;AAAAA;AAAAA,4CAIiC+B,GAAU,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA,6BAK9BT,EAAI,MAAQ,GAAKA,EAAI,MAAQ,KAAM,QAAQ,CAAC,EAAI,OAAS,MAAM;AAAA;AAAA,6EAEfa,GAAe,KAAK;AAAA,0DACvCoB,CAAO;AAAA,yEACQ,KAAK,WAAW;AAAA,UAC/ExC,EAAM,QAAU,OAAS,IAAM,GAAG;AAAA;AAAA,sCAEN,KAAK,KAAK;AAAA,oDACI,KAAK,SAAS;AAAA,UACxDP,EAAQ,MAAQ,WAAa,OAAO;AAAA;AAAA,KAG5C,CACF,EAlFa6C,GACJ,OAASpD;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA,IADLoD,GAANnD,GAAA,CADNE,EAAc,WAAW,CAAA,EACbiD,EAAA,iJCHN,IAAMG,GAAN,cAAwB1D,CAAW,CAwE/B,mBAA0B,CACjC,MAAM,kBAAA,EACNwD,EAAO,IAAM,CAAE3C,EAAG,MAAOC,EAAK,MAAOC,GAAK,MAAOC,GAAa,MAAON,EAAQ,MAAO,KAAK,cAAA,CAAiB,CAAC,CAC7G,CAES,QAAS,CAChB,OAAOR;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA,oFAqCyEW,EAAG,MAAQ,KAAM,QAAQ,CAAC,CAAC;AAAA,+DAChD,OAAOA,EAAG,KAAK,CAAC;AAAA,qBACzD,GAAaA,EAAG,MAAQ,CAAE,EAAE,OAA4B,KAAK;AAAA;AAAA;AAAA,qFAGEC,EAAK,MAAQ,KAAM,QAAQ,CAAC,CAAC;AAAA,4DACtD,OAAOA,EAAK,KAAK,CAAC;AAAA,qBACxD,GAAaA,EAAK,MAAQ,CAAE,EAAE,OAA4B,KAAK;AAAA;AAAA;AAAA,qFAGAC,GAAK,MAAM,QAAQ,CAAC,CAAC;AAAA,qEACrC,OAAOA,GAAK,KAAK,CAAC;AAAA,qBACjE,GAAaA,GAAK,MAAQ,CAAE,EAAE,OAA4B,KAAK;AAAA;AAAA;AAAA,kFAGHC,GAAa,MAAQ,KAAO,KAAK;AAAA,uDAC5DA,GAAa,MAAQ,IAAM,GAAG;AAAA,qBAC/D,GAAaA,GAAa,MAAS,EAAE,OAA4B,QAAU,GAAG;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,+BAOrEN,EAAQ,MAAQ,OAAS,EAAE;AAAA;AAAA,+BAE3BA,EAAQ,MAAQ,OAAS,EAAE;AAAA;AAAA,+BAE3BA,EAAQ,MAAQ,OAAS,EAAE;AAAA;AAAA,+BAE3BA,EAAQ,MAAQ,OAAS,EAAE;AAAA;AAAA,+BAE3BA,EAAQ,MAAQ,OAAS,EAAE;AAAA;AAAA,+BAE3BA,EAAQ,MAAQ,OAAS,EAAE;AAAA;AAAA;AAAA,KAIxD,CACF,EA1JagD,GACJ,OAASvD;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA,IADLuD,GAANtD,GAAA,CADNE,EAAc,YAAY,CAAA,EACdoD,EAAA,uMCEN,IAAMC,EAAN,cAAsB3D,CAAW,CAAjC,aAAA,CAAA,MAAA,GAAA,SAAA,EACI,KAAQ,MAAqB,CACpC,CAAE,GAAI,QAAS,EAAG,IAAK,EAAG,IAAK,MAAO,uBAAwB,KAAM,aAAA,EACpE,CAAE,GAAI,QAAS,EAAG,IAAK,EAAG,IAAK,MAAO,uBAAwB,KAAM,aAAA,EACpE,CAAE,GAAI,QAAS,EAAG,IAAK,EAAG,IAAK,MAAO,uBAAwB,KAAM,YAAA,EACpE,CAAE,GAAI,OAAQ,EAAG,IAAK,EAAG,IAAK,MAAO,uBAAwB,KAAM,YAAA,CAAa,EAEzE,KAAQ,SAA0B,KAClC,KAAQ,SAA0B,KAC3C,KAAQ,WAAa,CAAE,GAAI,EAAG,GAAI,CAAA,EAwElC,KAAQ,OAAS,CAAC4D,EAAYpE,IAA0B,CACtDA,EAAE,eAAA,EACF,KAAK,SAAWoE,EAChB,KAAK,SAAWA,EAChB,MAAMC,EAAO,KAAK,MAAM,KAAM,GAAM,EAAE,KAAOD,CAAE,EAC/C,GAAI,CAACC,EAAM,OACX,MAAMC,EAAQ,KAAK,WAAW,cAAc,KAAK,EACjD,GAAI,CAACA,EAAO,OACZ,MAAMC,EAAK,KAAK,MAAMvE,EAAGsE,CAAK,EAC9B,KAAK,WAAa,CAAE,GAAIC,EAAG,EAAIF,EAAK,EAAG,GAAIE,EAAG,EAAIF,EAAK,CAAA,CACzD,EAEA,KAAQ,cAAiB,GAA0B,CACjD,GAAI,CAAC,KAAK,SAAU,OACpB,MAAMC,EAAQ,KAAK,WAAW,cAAc,KAAK,EACjD,GAAI,CAACA,EAAO,OACZ,MAAMC,EAAK,KAAK,MAAM,EAAGD,CAAK,EAC9B,KAAK,MAAQ,KAAK,MAAM,IAAKE,GAC3BA,EAAG,KAAO,KAAK,SACX,CAAE,GAAGA,EAAI,EAAGD,EAAG,EAAI,KAAK,WAAW,GAAI,EAAGA,EAAG,EAAI,KAAK,WAAW,IACjEC,CAAA,CAER,EAEA,KAAQ,YAAc,IAAY,CAAE,KAAK,SAAW,IAAM,CAAA,CArCjD,mBAA0B,CACjC,MAAM,kBAAA,EACNR,EAAO,IAAM,CAAEnC,GAAM,MAAOC,EAAK,MAAOE,EAAI,MAAOD,EAAI,MAAOJ,EAAc,MAAO,KAAK,cAAA,CAAiB,CAAC,EAC1G,OAAO,iBAAiB,cAAe,KAAK,aAAa,EACzD,OAAO,iBAAiB,YAAa,KAAK,WAAW,CACvD,CAES,sBAA6B,CACpC,MAAM,qBAAA,EACN,OAAO,oBAAoB,cAAe,KAAK,aAAa,EAC5D,OAAO,oBAAoB,YAAa,KAAK,WAAW,CAC1D,CA4BQ,MAAM,EAAiB2C,EAAgD,CAC7E,MAAMpE,EAAIoE,EAAM,sBAAA,EACVG,GAAQ,EAAE,QAAUvE,EAAE,MAAQA,EAAE,MAAS,IACzCwE,GAAQ,EAAE,QAAUxE,EAAE,KAAOA,EAAE,OAAU,IAC/C,MAAO,CAAE,EAAGuE,EAAK,EAAGC,CAAA,CACtB,CAES,QAAS,CAChB,MAAMjB,EAAI5B,GAAM,MACV8C,EAAM,CAAClB,EAAE,CAAC,EAAI,IAAKA,EAAE,CAAC,EAAI,IAAKA,EAAE,CAAC,EAAI,GAAG,EACzCmB,EAAS9C,EAAK,MAAQ,IACtB+C,EAAYlD,EAAc,MAAQ,GAAK,OAE7C,OAAOjB;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA,UAYD,KAAK,MAAM,IAAK8D,GAAOM;AAAAA,oCACGD,CAAS,QAAQL,EAAG,CAAC,OAAOA,EAAG,CAAC;AAAA;AAAA,qBAE/CA,EAAG,KAAK;AAAA,SACpB,CAAC;AAAA;AAAA;AAAA,UAGA,KAAK,MAAM,IAAKA,GAAOM;AAAAA,qBACZ,aAAa,KAAK,WAAaN,EAAG,GAAK,WAAa,EAAE,IAAI,KAAK,WAAaA,EAAG,GAAK,WAAa,EAAE,EAAE;AAAA,uBACnGA,EAAG,EAAE,mBAAmBA,EAAG,EAAE;AAAA,yBAC3B,aAAaA,EAAG,EAAE,QAAQ,CAAC,CAAC,IAAIA,EAAG,EAAE,QAAQ,CAAC,CAAC,GAAG;AAAA,4BAC9CxE,GAAoB,KAAK,OAAOwE,EAAG,GAAIxE,CAAC,CAAC;AAAA,0DACZwE,EAAG,KAAK;AAAA,uBAC3CA,EAAG,KAAK;AAAA,+CACgBA,EAAG,KAAK;AAAA,oEACaA,EAAG,IAAI;AAAA;AAAA,SAElE,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,qBAKW,WAAWK,CAAS,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,+DASoBF,EAAI,CAAC,EAAE,QAAQ,CAAC,CAAC,KAAKA,EAAI,CAAC,EAAE,QAAQ,CAAC,CAAC,KAAKA,EAAI,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qDAQvEC,EAAO,QAAQ,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA,mDAInB5C,EAAI,MAAQ,EAAI,KAAK,MAAMA,EAAI,KAAK,EAAI,GAAG;AAAA;AAAA;AAAA;AAAA,mDAI3CD,EAAI,MAAQ,EAAIA,EAAI,MAAM,QAAQ,CAAC,EAAI,GAAG;AAAA;AAAA;AAAA,KAI3F,CACF,EAxLaoC,EAWJ,OAASxD;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA,IAVCC,GAAA,CAAhBmE,EAAA,CAAM,EADIZ,EACM,UAAA,QAAA,CAAA,EAMAvD,GAAA,CAAhBmE,EAAA,CAAM,EAPIZ,EAOM,UAAA,WAAA,CAAA,EACAvD,GAAA,CAAhBmE,EAAA,CAAM,EARIZ,EAQM,UAAA,WAAA,CAAA,EARNA,EAANvD,GAAA,CADNE,EAAc,UAAU,CAAA,EACZqD,CAAA,uMCIN,IAAMa,GAAN,cAA0BxE,CAAW,CAArC,aAAA,CAAA,MAAA,GAAA,SAAA,EACI,KAAQ,IAAW,QAAA,CAqGnB,mBAA0B,CACjC,MAAM,kBAAA,EACNwD,EAAO,IAAM,CACX3B,GAAO,MAAOC,GAAO,MAAOC,GAAO,MAAOC,GAAU,MACpDJ,GAAU,MAAOH,EAAW,MAAOC,EAAgB,MACnDL,GAAM,MAAOC,EAAK,MAClB,KAAK,cAAA,CACP,CAAC,CACH,CAEA,MAAc,QAAwB,CACpC,MAAMxB,EAAI2C,EAAA,EAAa,GAAK3C,EAC5B,CAAA4B,EAAgB,MAAQ,UACxBkB,EAAQ,OAAQ,oCAAoC,EACpD,GAAI,CACF,MAAM6B,EAAM9C,EAAgB,MACtB+C,EAAW,IAAI,WAAW,EAAE,EAClC,QAAS9E,EAAI,EAAGA,EAAI,GAAIA,MAAcA,CAAC,EAAI,SAAS6E,EAAI,MAAM7E,EAAI,EAAGA,EAAI,EAAI,CAAC,EAAG,EAAE,EACnF,MAAM,EAAI,MAAME,EAAE,cAAc4E,CAAQ,EACxC,GAAI,EAAE,GACJhD,EAAgB,MAAQ,KACxBD,EAAW,MAAQgD,EACnB7B,EAAQ,KAAM,WAAW6B,EAAI,MAAM,EAAG,EAAE,CAAC,gCAAgC,MACpE,CACL/C,EAAgB,MAAQ,OACxB,MAAMiD,EAAS,MAAM,KAAK,EAAE,MAAM,EAAE,IAAK1B,GAAMA,EAAE,SAAS,EAAE,EAAE,SAAS,EAAG,GAAG,CAAC,EAAE,KAAK,EAAE,EACvFxB,EAAW,MAAQkD,EACnB/B,EAAQ,MAAO,2BAA2B+B,EAAO,MAAM,EAAG,EAAE,CAAC,GAAG,CAClE,CACF,OAASnF,EAAG,CACVkC,EAAgB,MAAQ,OACxBkB,EAAQ,MAAO,kBAAmBpD,EAAY,OAAO,EAAE,CACzD,EACF,CAEQ,iBAAkB,CAGxB,MAAMoF,EAAQC,GAAkB,CAC9B,IAAIC,EAAI,GACR,OAAAD,EAAI,QAAQ,CAAC5E,EAAGL,IAAM,CACpB,MAAMsD,GAAKtD,EAAI,KAAK,IAAI,EAAG,GAAO,EAAK,IACjCuD,GAAI,GAAKlD,EAAI,GACnB6E,IAAMlF,IAAM,EAAI,IAAM,KAAO,IAAIsD,GAAE,QAAQ,CAAC,CAAC,IAAIC,GAAE,QAAQ,CAAC,CAAC,GAC/D,CAAC,EACM2B,CACT,EAEA,OAAO5E;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA,4BAMiB,GAAC,IAAI,GAAC;AAAA,4BACN,EAAE,OAAO,GAAC,OAAO,EAAE;AAAA,YACnCoE,yBAA2BM,EAAK/C,GAAO,KAAK,CAAC,gEAAgE;AAAA,YAC7GyC,yBAA2BM,EAAK9C,GAAO,KAAK,CAAC,+EAA+E;AAAA,YAC5HwC,yBAA2BM,EAAK7C,GAAO,KAAK,CAAC,+EAA+E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAU5HC,GAAU,MAAM,IAAK/B,GAAMC,2BAA8B,UAAU,KAAK,IAAI,EAAGD,EAAI,GAAG,CAAC,GAAG,SAAS,CAAC;AAAA;AAAA;AAAA,KAI9G,CAEQ,gBAAiB,CACvB,MAAM8E,EAAInD,GAAU,MACdoD,EAAQD,GAAG,IACjB,IAAIE,EAAM,GACV,OAAID,IAEFC,EADY,MAAM,KAAKD,CAAK,EAAE,IAAK/B,GAAMA,EAAE,SAAS,EAAE,EAAE,SAAS,EAAG,GAAG,CAAC,EAC9D,MAAM,EAAG,EAAE,EAAE,KAAK,GAAG,GAE1B/C;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA,mDAOwC6E,EAAI,KAAOA,EAAE,MAAM,SAAS,EAAE,EAAE,YAAA,EAAgB,GAAG;AAAA,oCAClEA,GAAG,SAAW,GAAG;AAAA,qCAChBA,GAAG,OAAS,GAAG,SAAS,EAAE,EAAE,SAAS,EAAG,GAAG,CAAC;AAAA,sCAC3CA,GAAG,UAAY,GAAG;AAAA,iCACvBA,EAAIA,EAAE,IAAI,SAAA,EAAa,GAAG;AAAA,kDACTA,EAAIA,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC,EAAI,GAAG;AAAA,kDAC7BA,EAAIA,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC,EAAI,GAAG;AAAA,kDAC7BA,EAAIA,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC,EAAI,GAAG;AAAA,wCACvCA,EAAIA,EAAE,mBAAmB,QAAQ,CAAC,EAAI,GAAG;AAAA,mCAC9CA,EAAIA,EAAE,aAAa,QAAQ,CAAC,EAAI,GAAG;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0CAQ5BE,GAAO,GAAG;AAAA;AAAA,KAGlD,CAEQ,kBAAmB,CACzB,MAAMC,EAASxD,EAAgB,MACzByD,EAAMD,IAAW,KAAO,KAAOA,IAAW,OAAS,OAAS,GAC5DE,EACJF,IAAW,UAAY,aACvBA,IAAW,KAAO,wCAClBA,IAAW,OAAS,sCACpB,iBACF,OAAOhF;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA,yDAM8CyB,EAAgB,OAAS,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uDAOvCF,EAAW,OAAS,oBAAoB;AAAA,oCAC3D0D,CAAG,4BAA4B,KAAK,MAAM,IAAIC,CAAK;AAAA;AAAA,KAGrF,CAES,QAAS,CAChB,OAAOlF;AAAAA;AAAAA,6BAEkB,KAAK,MAAQ,SAAW,SAAW,EAAE,+BAA+B,IAAM,KAAK,IAAM,QAAQ;AAAA,6BAC7F,KAAK,MAAQ,QAAU,SAAW,EAAE,8BAA8B,IAAM,KAAK,IAAM,OAAO;AAAA,6BAC1F,KAAK,MAAQ,UAAY,SAAW,EAAE,gCAAgC,IAAM,KAAK,IAAM,SAAS;AAAA;AAAA;AAAA,UAGnH,KAAK,MAAQ,SAAW,KAAK,kBAC3B,KAAK,MAAQ,QAAU,KAAK,eAAA,EAC5B,KAAK,kBAAkB;AAAA;AAAA,KAGjC,CACF,EA9PasE,GAGJ,OAASrE;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA,IAFCC,GAAA,CAAhBmE,EAAA,CAAM,EADIC,GACM,UAAA,MAAA,CAAA,EADNA,GAANpE,GAAA,CADNE,EAAc,cAAc,CAAA,EAChBkE,EAAA,uMCFN,IAAMa,GAAN,cAAwBrF,CAAW,CAAnC,aAAA,CAAA,MAAA,GAAA,SAAA,EAEL,KAAQ,QAAoB,CAAA,EAC5B,KAAQ,KAAO,GAiLf,KAAQ,MAAS,GAA2B,CACtC,EAAE,MAAQ,SAAgB,KAAK,KAAK,KAAK,QAAQ,KAAK,EAAG,KAAK,QAAQ,MAAQ,IACzE,EAAE,MAAQ,UACb,KAAK,QAAQ,SACf,KAAK,KAAO,KAAK,IAAI,EAAG,KAAK,KAAO,CAAC,EACrC,KAAK,QAAQ,MAAQ,KAAK,QAAQ,KAAK,IAAI,GAAK,GAChD,EAAE,eAAA,GAEK,EAAE,MAAQ,aACf,KAAK,QAAQ,SACf,KAAK,KAAO,KAAK,IAAI,KAAK,QAAQ,OAAQ,KAAK,KAAO,CAAC,EACvD,KAAK,QAAQ,MAAQ,KAAK,QAAQ,KAAK,IAAI,GAAK,GAChD,EAAE,eAAA,EAGR,CAAA,CA3GS,mBAA0B,CACjC,MAAM,kBAAA,EACNwD,EAAO,IAAM,CACXd,EAAa,MAAON,GAAc,MAAOD,EAAc,MACvD,KAAK,cAAA,CACP,CAAC,CACH,CAES,SAAgB,CACvB,MAAMmD,EAAO,KAAK,WAAW,cAAc,OAAO,EAC9CA,IAAMA,EAAK,UAAYA,EAAK,aAClC,CAEQ,QAAiC,CACvC,MAAMxF,EAA4B,CAAE,KAAM,EAAG,KAAM,EAAG,IAAK,EAAG,IAAK,EAAG,GAAI,CAAA,EAC1E,UAAWyF,KAAK7C,EAAa,MAAO5C,EAAEyF,EAAE,KAAK,GAAKzF,EAAEyF,EAAE,KAAK,GAAK,GAAK,EACrE,OAAAzF,EAAE,IAAM4C,EAAa,MAAM,OACpB5C,CACT,CAEA,MAAc,KAAK0F,EAA6B,CAE9C,GADAA,EAAOA,EAAK,KAAA,EACR,CAACA,EAAM,OACX5C,EAAQ,OAAQ,uDAAuD4C,CAAI,EAAE,EAC7E,KAAK,QAAQ,KAAKA,CAAI,EAAG,KAAK,KAAO,KAAK,QAAQ,OAClD,KAAM,CAACC,EAAK,GAAGC,CAAI,EAAIF,EAAK,MAAM,KAAK,EACjCG,EAAMD,EAAK,KAAK,GAAG,EACnB5F,EAAI2C,EAAA,EACV,OAAQgD,EAAA,CACN,IAAK,OACH7C,EAAQ,OAAQ,0GAA0G,EAC1H,MACF,IAAK,aACHA,EAAQ,OAAQ,wBAAwB,EACxCA,EAAQ,OAAQ,mDAAmD,EACnEA,EAAQ,OAAQ,2DAA2D,EAC3EA,EAAQ,OAAQ,kDAAkD,EAClEA,EAAQ,OAAQ,uDAAuD,EACvE,MACF,IAAK,gBACHA,EAAQ,OAAQ,6BAA6B,EAC7CA,EAAQ,OAAQ,kDAAkD,EAClEA,EAAQ,OAAQ,qDAAqD,EACrEA,EAAQ,OAAQ,0CAA0C,EAC1D,MACF,IAAK,MACC9C,IAAK,MAAMA,EAAE,IAAA,EAAOY,EAAQ,MAAQ,GAAMkC,EAAQ,KAAM,cAAc,GAC1E,MACF,IAAK,QACC9C,IAAK,MAAMA,EAAE,MAAA,EAASY,EAAQ,MAAQ,GAAOkC,EAAQ,OAAQ,iBAAiB,GAClF,MACF,IAAK,QACC9C,IAAK,MAAMA,EAAE,MAAA,EAAS8C,EAAQ,OAAQ,sBAAsB,GAChE,MACF,IAAK,OAAQ,CACX,GAAI,CAAC+C,EAAK,CAAE/C,EAAQ,OAAQ,oBAAoBhC,EAAK,MAAM,SAAS,EAAE,EAAE,YAAA,CAAa,EAAE,EAAG,KAAO,CACjG,MAAMX,EAAI,OAAO0F,EAAI,WAAW,IAAI,EAAIA,EAAM,KAAOA,CAAG,EACxD/E,EAAK,MAAQX,EACTH,GAAG,MAAMA,EAAE,QAAQG,CAAC,EACxB2C,EAAQ,KAAM,YAAY3C,EAAE,SAAS,EAAE,EAAE,YAAA,CAAa,EAAE,EACxD,KACF,CACA,IAAK,eAAgB,CACnB,GAAI,CAACH,EAAG,MACR8C,EAAQ,MAAO,oCAAoC,EACnD,GAAI,CACF,MAAM6B,EAAM9C,EAAgB,MACtB+C,EAAW,IAAI,WAAW,EAAE,EAClC,QAAS9E,EAAI,EAAGA,EAAI,GAAIA,MAAcA,CAAC,EAAI,SAAS6E,EAAI,MAAM7E,EAAI,EAAGA,EAAI,EAAI,CAAC,EAAG,EAAE,GACzE,MAAME,EAAE,cAAc4E,CAAQ,GAClC,IAAMhD,EAAgB,MAAQ,KAAMD,EAAW,MAAQgD,EAAK7B,EAAQ,KAAM,WAAW6B,EAAI,MAAM,EAAG,EAAE,CAAC,gCAAgC,IACpI/C,EAAgB,MAAQ,OAAQkB,EAAQ,MAAO,kBAAkB,EAC1E,OAASpD,EAAG,CAAEoD,EAAQ,MAAO,kBAAmBpD,EAAY,OAAO,EAAE,CAAG,CACxE,KACF,CACA,IAAK,QACHkD,EAAa,MAAQ,CAAA,EACrB,MACF,IAAK,QAAS,CACZ,MAAMnD,GAAKoG,GAAO,IAAI,YAAA,EAClBpG,IAAM,SAAWA,IAAM,QAAU0B,EAAM,MAAQ1B,EAAGqD,EAAQ,KAAM,WAAWrD,CAAC,EAAE,GAC7EqD,EAAQ,OAAQ,oBAAoB,EACzC,KACF,CACA,IAAK,SACHA,EAAQ,OAAQ,WAAWlC,EAAQ,KAAK,WAAWE,EAAK,MAAM,SAAS,EAAE,EAAE,YAAA,CAAa,aAAac,EAAgB,KAAK,EAAE,EAC5H,MACF,QACEkB,EAAQ,MAAO,oBAAoB6C,CAAG,aAAa,CAAA,CAEzD,CAmBS,QAAS,CAChB,MAAM3F,EAAI,KAAK,OAAA,EACT8F,EAASxD,GAAc,MACvByD,EAAUnD,EAAa,MAAM,OAAQ6C,GAAMK,IAAW,OAASL,EAAE,QAAUK,CAAM,EACvF,OAAO1F;AAAAA;AAAAA,UAEA,CAAC,MAAO,OAAQ,OAAQ,MAAO,KAAK,EAAY,IAAK4F,GAAM5F;AAAAA,+BACvC0F,IAAWE,EAAI,SAAW,EAAE,cAAcA,CAAC;AAAA,qBACrD,IAAM1D,GAAc,MAAQ0D,CAAC;AAAA,cACpCA,CAAC,sBAAsBhG,EAAEgG,CAAC,GAAK,CAAC;AAAA;AAAA,SAErC,CAAC;AAAA;AAAA;AAAA,wDAG8C,IAAMpD,EAAa,MAAQ,EAAE;AAAA,wDAC7B,IAAMP,EAAc,MAAQ,CAACA,EAAc,KAAK;AAAA,cAC1FA,EAAc,MAAQ,IAAM,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA,UAKpC0D,EAAQ,IAAKN,GAAM,CACnB,MAAMQ,EAAK,IAAI,KAAKR,EAAE,EAAE,EAClBS,EAAQ,GAAG,OAAOD,EAAG,YAAY,EAAE,SAAS,EAAG,GAAG,CAAC,IAAI,OAAOA,EAAG,gBAAA,CAAiB,EAAE,SAAS,EAAG,GAAG,CAAC,GAE1G,OAAO7F,qBAAwBqF,EAAE,KAAK;AAAA,8BAClBS,CAAK;AAAA,+BACJT,EAAE,KAAK;AAAA,0CACIA,EAAE,GAAG;AAAA,iBAEvC,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAMW,KAAK,KAAK;AAAA;AAAA,KAG7B,CACF,EA7OaF,GAKJ,OAASlF;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA,IAJiBC,GAAA,CAAhC6F,GAAM,gBAAgB,CAAA,EADZZ,GACsB,UAAA,UAAA,CAAA,EADtBA,GAANjF,GAAA,CADNE,EAAc,YAAY,CAAA,EACd+E,EAAA,EC4DN,MAAMa,EAAsB,CAEjC,CACE,GAAI,QACJ,KAAM,kCACN,SAAU,MACV,MAAO,QACP,QACE,gHACF,OAAQ,IACR,OAAQ,GACR,OAAQ,YACR,KAAM,CAAC,UAAW,eAAgB,YAAa,UAAW,MAAM,EAChE,IAAK,SAAA,EAIP,CACE,GAAI,UACJ,KAAM,gBACN,SAAU,MACV,MAAO,2BACP,QAAS,qEACT,OAAQ,CAAC,CAAC,EACV,OAAQ,IACR,OAAQ,YACR,KAAM,CAAC,MAAO,MAAO,aAAc,KAAK,EACxC,IAAK,SAAA,EAEP,CACE,GAAI,YACJ,KAAM,iBACN,SAAU,MACV,MAAO,2BACP,QAAS,0EACT,OAAQ,CAAC,CAAC,EACV,OAAQ,IACR,OAAQ,YACR,KAAM,CAAC,OAAQ,MAAO,YAAa,OAAO,EAC1C,IAAK,SAAA,EAEP,CACE,GAAI,cACJ,KAAM,8BACN,SAAU,MACV,MAAO,2BACP,QACE,4FACF,OAAQ,CAAC,CAAC,EACV,OAAQ,IACR,OAAQ,YACR,KAAM,CAAC,WAAY,MAAO,WAAY,MAAM,EAC5C,IAAK,SAAA,EAEP,CACE,GAAI,MACJ,KAAM,qCACN,SAAU,MACV,MAAO,2BACP,QAAS,sFACT,OAAQ,IACR,OAAQ,YACR,KAAM,CAAC,UAAW,MAAO,MAAM,EAC/B,IAAK,SAAA,EAEP,CACE,GAAI,YACJ,KAAM,sBACN,SAAU,MACV,MAAO,2BACP,QAAS,uEACT,OAAQ,CAAC,IAAK,IAAK,GAAG,EACtB,OAAQ,IACR,OAAQ,YACR,KAAM,CAAC,MAAO,WAAY,UAAU,CAAA,EAEtC,CACE,GAAI,cACJ,KAAM,sBACN,SAAU,MACV,MAAO,2BACP,QAAS,oEACT,OAAQ,CAAC,IAAK,IAAK,IAAK,IAAK,IAAK,GAAG,EACrC,OAAQ,IACR,OAAQ,YACR,KAAM,CAAC,UAAW,SAAU,KAAK,EACjC,IAAK,SAAA,EAEP,CACE,GAAI,YACJ,KAAM,qBACN,SAAU,MACV,MAAO,2BACP,QAAS,uDACT,OAAQ,CAAC,IAAK,GAAG,EACjB,OAAQ,IACR,OAAQ,YACR,KAAM,CAAC,WAAY,OAAQ,KAAK,CAAA,EAIlC,CAAE,GAAI,kBAAmB,KAAM,uBAAwB,SAAU,MAAO,MAAO,2BAA4B,QAAS,4DAA6D,OAAQ,CAAC,GAAG,EAAG,OAAQ,IAAK,OAAQ,YAAa,KAAM,CAAC,UAAW,QAAS,WAAW,CAAA,EACxQ,CAAE,GAAI,yBAA0B,KAAM,qBAAsB,SAAU,MAAO,MAAO,2BAA4B,QAAS,mEAAoE,OAAQ,CAAC,IAAK,GAAG,EAAG,OAAQ,IAAK,OAAQ,YAAa,KAAM,CAAC,UAAW,UAAW,YAAY,CAAA,EAC5R,CAAE,GAAI,2BAA4B,KAAM,uBAAwB,SAAU,MAAO,MAAO,2BAA4B,QAAS,yEAA0E,OAAQ,CAAC,IAAK,GAAG,EAAG,OAAQ,IAAK,OAAQ,YAAa,KAAM,CAAC,UAAW,YAAa,KAAK,CAAA,EACjS,CAAE,GAAI,oBAAqB,KAAM,gBAAiB,SAAU,MAAO,MAAO,2BAA4B,QAAS,yEAA0E,OAAQ,IAAK,OAAQ,YAAa,KAAM,CAAC,UAAW,OAAQ,MAAM,CAAA,EAC3P,CAAE,GAAI,qBAAsB,KAAM,mBAAoB,SAAU,MAAO,MAAO,2BAA4B,QAAS,yCAA0C,OAAQ,IAAK,OAAQ,OAAQ,KAAM,CAAC,UAAW,OAAO,CAAA,EAGnN,CAAE,GAAI,uBAAwB,KAAM,mBAAoB,SAAU,MAAO,MAAO,2BAA4B,QAAS,kEAAmE,OAAQ,CAAC,IAAK,IAAK,IAAK,GAAG,EAAG,OAAQ,IAAK,OAAQ,YAAa,KAAM,CAAC,WAAY,WAAW,CAAA,EACtR,CAAE,GAAI,oBAAqB,KAAM,yBAA0B,SAAU,MAAO,MAAO,2BAA4B,QAAS,wEAAyE,OAAQ,CAAC,IAAK,IAAK,GAAG,EAAG,OAAQ,IAAK,OAAQ,WAAY,KAAM,CAAC,WAAY,QAAS,KAAK,CAAA,EAC5R,CAAE,GAAI,iBAAkB,KAAM,sBAAuB,SAAU,MAAO,MAAO,2BAA4B,QAAS,yDAA0D,OAAQ,CAAC,IAAK,IAAK,GAAG,EAAG,OAAQ,IAAK,OAAQ,YAAa,KAAM,CAAC,WAAY,gBAAgB,CAAA,EAC1Q,CAAE,GAAI,gBAAiB,KAAM,qBAAsB,SAAU,MAAO,MAAO,2BAA4B,QAAS,4DAA6D,OAAQ,CAAC,IAAK,IAAK,GAAG,EAAG,OAAQ,IAAK,OAAQ,YAAa,KAAM,CAAC,WAAY,OAAO,CAAA,EAClQ,CAAE,GAAI,mBAAoB,KAAM,eAAgB,SAAU,MAAO,MAAO,2BAA4B,QAAS,2DAA4D,OAAQ,CAAC,IAAK,IAAK,GAAG,EAAG,OAAQ,IAAK,OAAQ,OAAQ,KAAM,CAAC,WAAY,UAAU,CAAA,EAG5P,CAAE,GAAI,oBAAqB,KAAM,gBAAiB,SAAU,MAAO,MAAO,2BAA4B,QAAS,8DAA+D,OAAQ,CAAC,IAAK,IAAK,GAAG,EAAG,OAAQ,IAAK,OAAQ,YAAa,KAAM,CAAC,OAAQ,WAAY,QAAQ,CAAA,EAC5Q,CAAE,GAAI,qBAAsB,KAAM,iBAAkB,SAAU,MAAO,MAAO,2BAA4B,QAAS,iDAAkD,OAAQ,CAAC,IAAK,IAAK,GAAG,EAAG,OAAQ,IAAK,OAAQ,YAAa,KAAM,CAAC,WAAY,UAAU,CAAA,EAC3P,CAAE,GAAI,qBAAsB,KAAM,iBAAkB,SAAU,MAAO,MAAO,2BAA4B,QAAS,6CAA8C,OAAQ,CAAC,GAAG,EAAG,OAAQ,IAAK,OAAQ,YAAa,KAAM,CAAC,WAAY,UAAU,CAAA,EAC7O,CAAE,GAAI,mBAAoB,KAAM,2BAA4B,SAAU,MAAO,MAAO,2BAA4B,QAAS,yDAA0D,OAAQ,IAAK,OAAQ,YAAa,KAAM,CAAC,UAAW,WAAW,CAAA,EAClP,CAAE,GAAI,mBAAoB,KAAM,eAAgB,SAAU,MAAO,MAAO,2BAA4B,QAAS,+DAAgE,OAAQ,IAAK,OAAQ,YAAa,KAAM,CAAC,SAAU,OAAO,CAAA,EAGvO,CAAE,GAAI,mBAAoB,KAAM,eAAgB,SAAU,MAAO,MAAO,2BAA4B,QAAS,oDAAqD,OAAQ,IAAK,OAAQ,YAAa,KAAM,CAAC,SAAU,OAAO,CAAA,EAC5N,CAAE,GAAI,oBAAqB,KAAM,gBAAiB,SAAU,MAAO,MAAO,2BAA4B,QAAS,2DAA4D,OAAQ,IAAK,OAAQ,YAAa,KAAM,CAAC,SAAU,SAAS,CAAA,EACvO,CAAE,GAAI,oBAAqB,KAAM,gBAAiB,SAAU,MAAO,MAAO,2BAA4B,QAAS,wDAAyD,OAAQ,IAAK,OAAQ,YAAa,KAAM,CAAC,SAAU,MAAM,CAAA,EACjO,CAAE,GAAI,qBAAsB,KAAM,iBAAkB,SAAU,MAAO,MAAO,2BAA4B,QAAS,8CAA+C,OAAQ,IAAK,OAAQ,YAAa,KAAM,CAAC,SAAU,YAAY,CAAA,EAC/N,CAAE,GAAI,uBAAwB,KAAM,mBAAoB,SAAU,MAAO,MAAO,2BAA4B,QAAS,sDAAuD,OAAQ,IAAK,OAAQ,YAAa,KAAM,CAAC,SAAU,OAAO,CAAA,EAGtO,CAAE,GAAI,yBAA0B,KAAM,qBAAsB,SAAU,MAAO,MAAO,2BAA4B,QAAS,qCAAsC,OAAQ,IAAK,OAAQ,YAAa,KAAM,CAAC,aAAc,QAAQ,CAAA,EAC9N,CAAE,GAAI,qBAAsB,KAAM,yBAA0B,SAAU,MAAO,MAAO,2BAA4B,QAAS,8EAA+E,OAAQ,IAAK,OAAQ,YAAa,KAAM,CAAC,aAAc,MAAM,CAAA,EACrQ,CAAE,GAAI,iBAAkB,KAAM,0BAA2B,SAAU,MAAO,MAAO,2BAA4B,QAAS,4DAA6D,OAAQ,IAAK,OAAQ,OAAQ,KAAM,CAAC,aAAc,WAAW,CAAA,EAChP,CAAE,GAAI,wBAAyB,KAAM,oBAAqB,SAAU,MAAO,MAAO,2BAA4B,QAAS,4DAA6D,OAAQ,IAAK,OAAQ,OAAQ,KAAM,CAAC,cAAe,WAAW,CAAA,EAClP,CAAE,GAAI,2BAA4B,KAAM,uBAAwB,SAAU,MAAO,MAAO,2BAA4B,QAAS,+DAAgE,OAAQ,IAAK,OAAQ,WAAY,KAAM,CAAC,aAAc,WAAW,CAAA,EAG9P,CAAE,GAAI,qBAAsB,KAAM,4BAA6B,SAAU,MAAO,MAAO,2BAA4B,QAAS,mEAAoE,OAAQ,IAAK,OAAQ,YAAa,KAAM,CAAC,OAAQ,KAAK,CAAA,EACtP,CAAE,GAAI,sBAAuB,KAAM,wBAAyB,SAAU,MAAO,MAAO,2BAA4B,QAAS,8DAA+D,OAAQ,IAAK,OAAQ,OAAQ,KAAM,CAAC,YAAa,KAAK,CAAA,EAC9O,CAAE,GAAI,wBAAyB,KAAM,2BAA4B,SAAU,MAAO,MAAO,2BAA4B,QAAS,0DAA2D,OAAQ,IAAK,OAAQ,YAAa,KAAM,CAAC,WAAY,QAAQ,CAAA,EACtP,CAAE,GAAI,sBAAuB,KAAM,kBAAmB,SAAU,MAAO,MAAO,2BAA4B,QAAS,wDAAyD,OAAQ,IAAK,OAAQ,YAAa,KAAM,CAAC,SAAU,KAAK,CAAA,EACpO,CAAE,GAAI,0BAA2B,KAAM,sBAAuB,SAAU,MAAO,MAAO,2BAA4B,QAAS,uDAAwD,OAAQ,IAAK,OAAQ,YAAa,KAAM,CAAC,SAAU,UAAU,CAAA,EAChP,CAAE,GAAI,wBAAyB,KAAM,oBAAqB,SAAU,MAAO,MAAO,2BAA4B,QAAS,iDAAkD,OAAQ,IAAK,OAAQ,OAAQ,KAAM,CAAC,KAAM,WAAW,CAAA,EAG9N,CAAE,GAAI,wBAAyB,KAAM,oBAAqB,SAAU,MAAO,MAAO,2BAA4B,QAAS,kEAAmE,OAAQ,IAAK,OAAQ,OAAQ,KAAM,CAAC,WAAY,SAAS,CAAA,EACnP,CAAE,GAAI,wBAAyB,KAAM,oBAAqB,SAAU,MAAO,MAAO,2BAA4B,QAAS,kDAAmD,OAAQ,IAAK,OAAQ,WAAY,KAAM,CAAC,UAAW,UAAU,CAAA,EACvO,CAAE,GAAI,iBAAkB,KAAM,aAAc,SAAU,MAAO,MAAO,2BAA4B,QAAS,wDAAyD,OAAQ,IAAK,OAAQ,WAAY,KAAM,CAAC,eAAe,CAAA,EACzN,CAAE,GAAI,mBAAoB,KAAM,iBAAkB,SAAU,MAAO,MAAO,2BAA4B,QAAS,sEAAuE,OAAQ,IAAK,OAAQ,OAAQ,KAAM,CAAC,WAAY,KAAK,CAAA,EAG3O,CAAE,GAAI,yBAA0B,KAAM,qBAAsB,SAAU,MAAO,MAAO,2BAA4B,QAAS,mDAAoD,OAAQ,IAAK,OAAQ,OAAQ,KAAM,CAAC,QAAS,UAAU,CAAA,EACpO,CAAE,GAAI,iBAAkB,KAAM,qBAAsB,SAAU,MAAO,MAAO,2BAA4B,QAAS,yDAA0D,OAAQ,IAAK,OAAQ,YAAa,KAAM,CAAC,OAAQ,MAAM,CAAA,EAClO,CAAE,GAAI,sBAAuB,KAAM,kBAAmB,SAAU,MAAO,MAAO,2BAA4B,QAAS,wCAAyC,OAAQ,IAAK,OAAQ,WAAY,KAAM,CAAC,MAAO,SAAS,CAAA,EAGpN,CAAE,GAAI,uBAAwB,KAAM,mBAAoB,SAAU,MAAO,MAAO,2BAA4B,QAAS,mEAAoE,OAAQ,IAAK,OAAQ,YAAa,KAAM,CAAC,WAAY,SAAS,CAAA,EACvP,CAAE,GAAI,2BAA4B,KAAM,uBAAwB,SAAU,MAAO,MAAO,2BAA4B,QAAS,oDAAqD,OAAQ,IAAK,OAAQ,OAAQ,KAAM,CAAC,MAAO,QAAQ,CAAA,EACrO,CAAE,GAAI,oBAAqB,KAAM,gBAAiB,SAAU,MAAO,MAAO,2BAA4B,QAAS,uDAAwD,OAAQ,IAAK,OAAQ,WAAY,KAAM,CAAC,WAAY,UAAU,CAAA,EAGrO,CAAE,GAAI,oBAAqB,KAAM,gBAAiB,SAAU,MAAO,MAAO,2BAA4B,QAAS,iEAAkE,OAAQ,IAAK,OAAQ,OAAQ,KAAM,CAAC,WAAY,KAAK,CAAA,EACtO,CAAE,GAAI,0BAA2B,KAAM,sBAAuB,SAAU,MAAO,MAAO,2BAA4B,QAAS,yDAA0D,OAAQ,IAAK,OAAQ,OAAQ,KAAM,CAAC,UAAW,WAAW,CAAA,EAG/O,CAAE,GAAI,wBAAyB,KAAM,oBAAqB,SAAU,MAAO,MAAO,2BAA4B,QAAS,4DAA6D,OAAQ,IAAK,OAAQ,WAAY,KAAM,CAAC,UAAW,WAAW,CAAA,EAClP,CAAE,GAAI,0BAA2B,KAAM,sBAAuB,SAAU,MAAO,MAAO,2BAA4B,QAAS,yDAA0D,OAAQ,IAAK,OAAQ,WAAY,KAAM,CAAC,UAAW,cAAc,CAAA,EAGtP,CAAE,GAAI,sBAAuB,KAAM,wBAAyB,SAAU,MAAO,MAAO,2BAA4B,QAAS,sEAAuE,OAAQ,IAAK,OAAQ,WAAY,KAAM,CAAC,WAAY,UAAU,CAAA,EAC9P,CAAE,GAAI,wBAAyB,KAAM,oBAAqB,SAAU,MAAO,MAAO,2BAA4B,QAAS,oDAAqD,OAAQ,IAAK,OAAQ,OAAQ,KAAM,CAAC,OAAQ,QAAQ,CAAA,EAGhO,CAAE,GAAI,mBAAoB,KAAM,yBAA0B,SAAU,MAAO,MAAO,2BAA4B,QAAS,oGAAqG,OAAQ,CAAC,IAAK,IAAK,IAAK,GAAG,EAAG,OAAQ,IAAK,OAAQ,YAAa,KAAM,CAAC,UAAW,aAAc,KAAK,EAAG,IAAK,SAAA,EACzU,CAAE,GAAI,qBAAsB,KAAM,iBAAkB,SAAU,MAAO,MAAO,2BAA4B,QAAS,8CAA+C,OAAQ,IAAK,OAAQ,OAAQ,KAAM,CAAC,YAAa,MAAM,CAAA,EACvN,CAAE,GAAI,kBAAmB,KAAM,yBAA0B,SAAU,MAAO,MAAO,2BAA4B,QAAS,+DAAgE,OAAQ,IAAK,OAAQ,WAAY,KAAM,CAAC,QAAS,KAAK,CAAA,EAC5O,CAAE,GAAI,qBAAsB,KAAM,mBAAoB,SAAU,MAAO,MAAO,2BAA4B,QAAS,kEAAmE,OAAQ,IAAK,OAAQ,WAAY,KAAM,CAAC,QAAQ,CAAA,EACtO,CAAE,GAAI,uBAAwB,KAAM,mBAAoB,SAAU,MAAO,MAAO,2BAA4B,QAAS,qCAAsC,OAAQ,IAAK,OAAQ,WAAY,KAAM,CAAC,MAAO,MAAM,CAAA,EAChN,CAAE,GAAI,sBAAuB,KAAM,kBAAmB,SAAU,MAAO,MAAO,2BAA4B,QAAS,oEAAqE,OAAQ,IAAK,OAAQ,WAAY,KAAM,CAAC,SAAU,WAAW,CAAA,EACrP,CAAE,GAAI,uBAAwB,KAAM,yBAA0B,SAAU,MAAO,MAAO,2BAA4B,QAAS,0DAA2D,OAAQ,IAAK,OAAQ,WAAY,KAAM,CAAC,YAAa,YAAY,CAAA,EACvP,CAAE,GAAI,sBAAuB,KAAM,kBAAmB,SAAU,MAAO,MAAO,2BAA4B,QAAS,6CAA8C,OAAQ,IAAK,OAAQ,WAAY,KAAM,CAAC,OAAQ,KAAK,CAAA,EACtN,CAAE,GAAI,mBAAoB,KAAM,uBAAwB,SAAU,MAAO,MAAO,2BAA4B,QAAS,yDAA0D,OAAQ,IAAK,OAAQ,WAAY,KAAM,CAAC,aAAa,CAAA,EACpO,CAAE,GAAI,kBAAmB,KAAM,gBAAiB,SAAU,MAAO,MAAO,2BAA4B,QAAS,qCAAsC,OAAQ,IAAK,OAAQ,WAAY,KAAM,CAAC,SAAS,CAAA,EACpM,CAAE,GAAI,mBAAoB,KAAM,2BAA4B,SAAU,MAAO,MAAO,2BAA4B,QAAS,wDAAyD,OAAQ,IAAK,OAAQ,WAAY,KAAM,CAAC,aAAa,CAAA,CACzO,EAEaC,EAAmF,CAC9F,IAAK,CAAE,MAAO,aAAc,MAAO,sBAAuB,MAAO,GAAA,EACjE,IAAK,CAAE,MAAO,mBAAoB,MAAO,sBAAuB,MAAO,SAAA,EACvE,IAAK,CAAE,MAAO,oBAAqB,MAAO,qBAAsB,MAAO,SAAA,EACvE,IAAK,CAAE,MAAO,iBAAkB,MAAO,uBAAwB,MAAO,SAAA,EACtE,IAAK,CAAE,MAAO,uBAAwB,MAAO,uBAAwB,MAAO,SAAA,EAC5E,IAAK,CAAE,MAAO,aAAc,MAAO,uBAAwB,MAAO,SAAA,EAClE,IAAK,CAAE,MAAO,oBAAqB,MAAO,sBAAuB,MAAO,SAAA,EACxE,IAAK,CAAE,MAAO,kBAAmB,MAAO,uBAAwB,MAAO,SAAA,EACvE,IAAK,CAAE,MAAO,kBAAmB,MAAO,sBAAuB,MAAO,SAAA,EACtE,IAAK,CAAE,MAAO,sBAAuB,MAAO,qBAAsB,MAAO,SAAA,EACzE,IAAK,CAAE,MAAO,YAAa,MAAO,sBAAuB,MAAO,SAAA,EAChE,IAAK,CAAE,MAAO,UAAW,MAAO,uBAAwB,MAAO,SAAA,EAC/D,IAAK,CAAE,MAAO,WAAY,MAAO,uBAAwB,MAAO,SAAA,EAChE,IAAK,CAAE,MAAO,oBAAqB,MAAO,uBAAwB,MAAO,SAAA,CAC3E,EAYO,SAASC,IAAsC,CACpD,OAAOF,EAAK,IAAKG,IAAO,CAAE,GAAIA,EAAE,GAAI,OAAQA,EAAE,SAAW,GAAM,WAAY,GAAI,CACjF,CAaO,SAASC,GAAWL,EAAeM,EAA0B,CAClE,GAAI,CAACN,EAAO,MAAO,GACnB,MAAMO,EAAIP,EAAM,YAAA,EAChB,IAAIQ,EAAQ,EACZ,OAAIF,EAAI,GAAG,YAAA,EAAc,SAASC,CAAC,IAAGC,GAAS,GAC3CF,EAAI,KAAK,YAAA,EAAc,SAASC,CAAC,IAAGC,GAAS,GAC7CF,EAAI,QAAQ,YAAA,EAAc,SAASC,CAAC,IAAGC,GAAS,GAChDF,EAAI,MAAM,KAAMhH,GAAMA,EAAE,YAAA,EAAc,SAASiH,CAAC,CAAC,IAAGC,GAAS,GAC7DF,EAAI,WAAaC,IAAGC,GAAS,GAC1BA,CACT,CCjTA,MAAMC,GAAU,QACVC,GAAS,EACTC,EAAQ,KAEd,IAAIC,GAAyC,KAE7C,SAASC,IAA+B,CACtC,OAAID,KACJA,GAAY,IAAI,QAAqB,CAACE,EAASC,IAAW,CACxD,MAAMC,EAAM,UAAU,KAAKP,GAASC,EAAM,EAC1CM,EAAI,gBAAkB,IAAM,CAC1B,MAAMC,EAAKD,EAAI,OACVC,EAAG,iBAAiB,SAASN,CAAK,GAAGM,EAAG,kBAAkBN,CAAK,CACtE,EACAK,EAAI,UAAY,IAAMF,EAAQE,EAAI,MAAM,EACxCA,EAAI,QAAU,IAAMD,EAAOC,EAAI,KAAK,CACtC,CAAC,EACMJ,GACT,CAEA,eAAsBM,EAAmBC,EAAqC,CAC5E,MAAMF,EAAK,MAAMJ,GAAA,EACjB,OAAO,MAAM,IAAI,QAAuB,CAACC,EAASC,IAAW,CAE3D,MAAMtH,EADKwH,EAAG,YAAYN,EAAO,UAAU,EAC9B,YAAYA,CAAK,EAAE,IAAIQ,CAAG,EACvC1H,EAAE,UAAY,IAAMqH,EAAQrH,EAAE,MAAuB,EACrDA,EAAE,QAAU,IAAMsH,EAAOtH,EAAE,KAAK,CAClC,CAAC,CACH,CAEA,eAAsB2H,EAAMD,EAAaE,EAA+B,CACtE,MAAMJ,EAAK,MAAMJ,GAAA,EACjB,OAAO,MAAM,IAAI,QAAc,CAACC,EAASC,IAAW,CAClD,MAAMO,EAAKL,EAAG,YAAYN,EAAO,WAAW,EAC5CW,EAAG,YAAYX,CAAK,EAAE,IAAIU,EAAOF,CAAG,EACpCG,EAAG,WAAa,IAAMR,EAAA,EACtBQ,EAAG,QAAU,IAAMP,EAAOO,EAAG,KAAK,CACpC,CAAC,CACH,sMCnBA,MAAMC,EAAchH,EAAwB4F,IAAoB,EAC1DH,EAAQzF,EAAe,EAAE,EACzBiH,EAAYjH,EAA4B,KAAK,EAC7CkH,EAAelH,EAAkD,KAAK,GAE3E,SAAY,CACX,MAAMmH,EAAQ,MAAMR,EAAuB,iBAAiB,EACxDQ,MAAmB,MAAQA,EACjC,GAAA,EAEAnE,EAAO,IAAM,CAEX,MAAMvD,EAAIuH,EAAY,MAClBvH,EAAE,OAAS,GAAQoH,EAAM,kBAAmBpH,CAAC,CACnD,CAAC,EAGM,IAAM2H,GAAN,cAAyB5H,CAAW,CAApC,aAAA,CAAA,MAAA,GAAA,SAAA,EACI,KAAQ,WAAa,CAAA,CA0IrB,mBAA0B,CACjC,MAAM,kBAAA,EACNwD,EAAO,IAAM,CAAEgE,EAAY,MAAOvB,EAAM,MAAOwB,EAAU,MAAOC,EAAa,MAAO,KAAK,YAAc,CAAC,CAC1G,CAEQ,SAAS9D,EAAqB,CACpC,OAAO4D,EAAY,MAAM,KAAMnB,GAAMA,EAAE,KAAOzC,CAAE,GAAG,SAAW,EAChE,CAEQ,OAAO2C,EAAwB,CACrC,MAAMxD,EAAOyE,EAAY,MAAM,IAAKnB,GAAMA,EAAE,KAAOE,EAAI,GAAK,CAAE,GAAGF,EAAG,OAAQ,CAACA,EAAE,OAAQ,gBAAiB,KAAK,KAAI,EAAMA,CAAC,EACxHmB,EAAY,MAAQzE,EACpBH,EAAQ,KAAK,SAAS2D,EAAI,EAAE,EAAI,KAAO,OAAQ,uBAAuBA,EAAI,EAAE,qBAAqB,CACnG,CAEQ,UAA0B,CAChC,IAAIsB,EAAO3B,EACX,OAAIuB,EAAU,QAAU,QAAOI,EAAOA,EAAK,OAAQxB,GAAMA,EAAE,WAAaoB,EAAU,KAAK,GACnFC,EAAa,QAAU,QAAOG,EAAOA,EAAK,OAAQxB,GAAMA,EAAE,SAAWqB,EAAa,KAAK,GACvFzB,EAAM,MAAM,SACd4B,EAAOA,EACJ,IAAKxB,IAAO,CAAE,EAAAA,EAAG,EAAGC,GAAWL,EAAM,MAAOI,CAAC,CAAA,EAAI,EACjD,OAAQnD,GAAMA,EAAE,EAAI,CAAC,EACrB,KAAK,CAACmD,EAAGpD,IAAMA,EAAE,EAAIoD,EAAE,CAAC,EACxB,IAAKnD,GAAMA,EAAE,CAAC,GAEZ2E,CACT,CAEQ,gBAAyC,CAC/C,MAAMC,EAAiC,CAAE,IAAK5B,EAAK,MAAA,EACnD,UAAWJ,KAAK,OAAO,KAAKK,CAAU,EAAG2B,EAAOhC,CAAC,EAAI,EACrD,UAAWO,KAAKH,EAAM4B,EAAOzB,EAAE,QAAQ,GAAKyB,EAAOzB,EAAE,QAAQ,GAAK,GAAK,EACvE,OAAOyB,CACT,CAES,QAAS,CAChB,MAAMD,EAAO,KAAK,SAAA,EACZC,EAAS,KAAK,eAAA,EACdC,EAAcP,EAAY,MAAM,OAAQnB,GAAMA,EAAE,MAAM,EAAE,OAC9D,OAAOnG;AAAAA;AAAAA;AAAAA;AAAAA,mBAIQgG,EAAK,MAAM,gBAAgB6B,CAAW;AAAA;AAAA;AAAA,mBAGtC9B,EAAM,KAAK;AAAA,mBACVzG,GAAa,CAAEyG,EAAM,MAASzG,EAAE,OAA4B,KAAO,CAAC;AAAA;AAAA;AAAA;AAAA,4BAI5DiI,EAAU,QAAU,MAAQ,KAAO,EAAE;AAAA,mBAC9C,IAAMA,EAAU,MAAQ,KAAK;AAAA,mCACbK,EAAO,GAAG;AAAA;AAAA,UAElC,OAAO,KAAK3B,CAAU,EAAoB,IAAKL,GAAM5F;AAAAA,8BAClCuH,EAAU,QAAU3B,EAAI,KAAO,EAAE;AAAA,qBAC1C,IAAM2B,EAAU,MAAQ3B,CAAC;AAAA,yCACL,cAAcK,EAAWL,CAAC,EAAE,KAAK,EAAE;AAAA,cAC9DK,EAAWL,CAAC,EAAE,KAAK;AAAA,kCACCgC,EAAOhC,CAAC,GAAK,CAAC;AAAA;AAAA,SAEvC,CAAC;AAAA;AAAA,4BAEkB4B,EAAa,QAAU,MAAQ,KAAO,EAAE,YAAY,IAAMA,EAAa,MAAQ,KAAK;AAAA,4BACpFA,EAAa,QAAU,YAAc,KAAO,EAAE,YAAY,IAAMA,EAAa,MAAQ,WAAW;AAAA,4BAChGA,EAAa,QAAU,OAAS,KAAO,EAAE,YAAY,IAAMA,EAAa,MAAQ,MAAM;AAAA,4BACtFA,EAAa,QAAU,WAAa,KAAO,EAAE,YAAY,IAAMA,EAAa,MAAQ,UAAU;AAAA;AAAA;AAAA,QAGlHG,EAAK,SAAW,EACd3H,+DACAA,sBAAyB2H,EAAK,IAAKtB,GAAQ,KAAK,KAAKA,CAAG,CAAC,CAAC,QAAQ;AAAA,KAE1E,CAEQ,KAAKA,EAAkB,CAC7B,MAAMyB,EAAS,KAAK,SAASzB,EAAI,EAAE,EAC7B0B,EAAM9B,EAAWI,EAAI,QAAQ,EACnC,OAAOrG;AAAAA,yBACc8H,EAAS,SAAW,EAAE,iBAAiBzB,EAAI,EAAE;AAAA;AAAA,uCAE/B,cAAc0B,EAAI,KAAK,EAAE;AAAA,+BACjC1B,EAAI,IAAI;AAAA;AAAA,+BAERA,EAAI,OAAO;AAAA;AAAA,oCAEN0B,EAAI,KAAK;AAAA,sCACP1B,EAAI,MAAM,KAAKA,EAAI,MAAM;AAAA,YACnDA,EAAI,OAASrG,sCAAyCqG,EAAI,MAAM,UAAY,EAAE;AAAA,YAC9EA,EAAI,IAAMrG,wBAA2BqG,EAAI,GAAG,UAAY,EAAE;AAAA,YAC1DA,EAAI,QAAQ,OAASrG,+BAAkCqG,EAAI,OAAO,KAAK,GAAG,CAAC,UAAY,EAAE;AAAA;AAAA;AAAA,iCAGpEA,EAAI,KAAK;AAAA,gCACVyB,EAAS,KAAO,EAAE;AAAA,2BACvBA,CAAM;AAAA,8BACHzB,EAAI,EAAE;AAAA,qBACf,IAAM,KAAK,OAAOA,CAAG,CAAC;AAAA;AAAA;AAAA,KAIzC,CACF,EAnPaqB,GAGJ,OAASzH;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA,IAFCC,GAAA,CAAhBmE,EAAA,CAAM,EADIqD,GACM,UAAA,aAAA,CAAA,EADNA,GAANxH,GAAA,CADNE,EAAc,cAAc,CAAA,EAChBsH,EAAA,uMClCN,IAAMM,EAAN,cAAsBlI,CAAW,CAAjC,aAAA,CAAA,MAAA,GAAA,SAAA,EACI,KAAQ,QAAU,GAClB,KAAQ,IAAM,GACd,KAAQ,KAAO,IACxB,KAAQ,MAAuB,KAkC/B,KAAQ,QAAW,GAAmB,CACpC,MAAMmI,EAAU,EAAkB,OAClC,KAAK,IAAMA,EAAO,KAAO,OACzB,KAAK,KAAOA,EAAO,MAAQ,IAC3B,KAAK,QAAU,GACf,KAAK,aAAa,UAAW,EAAE,EAC3B,KAAK,QAAU,MAAM,OAAO,aAAa,KAAK,KAAK,EACvD,KAAK,MAAQ,OAAO,WAAW,IAAM,CACnC,KAAK,QAAU,GACf,KAAK,gBAAgB,SAAS,CAChC,EAAG,IAAI,CACT,CAAA,CApBS,mBAA0B,CACjC,MAAM,kBAAA,EACN,OAAO,iBAAiB,WAAY,KAAK,OAAwB,CACnE,CACS,sBAA6B,CACpC,MAAM,qBAAA,EACN,OAAO,oBAAoB,WAAY,KAAK,OAAwB,CACtE,CAeS,QAAS,CAChB,OAAOjI,uBAA0B,KAAK,IAAI,gBAAgB,KAAK,GAAG,SACpE,CACF,EAtDagI,EAMJ,OAAS/H;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA,IALCC,GAAA,CAAhBmE,EAAA,CAAM,EADI2D,EACM,UAAA,UAAA,CAAA,EACA9H,GAAA,CAAhBmE,EAAA,CAAM,EAFI2D,EAEM,UAAA,MAAA,CAAA,EACA9H,GAAA,CAAhBmE,EAAA,CAAM,EAHI2D,EAGM,UAAA,OAAA,CAAA,EAHNA,EAAN9H,GAAA,CADNE,EAAc,UAAU,CAAA,EACZ4H,CAAA,EAwDN,SAASE,EAAMtF,EAAauF,EAAO,IAAW,CACnD,OAAO,cAAc,IAAI,YAAY,WAAY,CAAE,OAAQ,CAAE,IAAAvF,EAAK,KAAAuF,CAAA,CAAK,CAAG,CAAC,CAC7E,qMC/CO,IAAMC,EAAN,cAAsBtI,CAAW,CAAjC,aAAA,CAAA,MAAA,GAAA,SAAA,EACI,KAAQ,KAAO,GACf,KAAQ,OAAS,GACjB,KAAQ,MAAQ,GAChB,KAAQ,QAAyB,CAAA,EAoE1C,KAAQ,QAAW,GAAmB,CACpC,MAAMN,EAAK,EAAkB,OAC7B,KAAK,OAASA,EAAE,MAAO,KAAK,MAAQA,EAAE,KACtC,KAAK,QAAUA,EAAE,SAAW,CAAC,CAAE,MAAO,QAAS,QAAS,UAAW,EACnE,KAAK,KAAO,GAAM,KAAK,aAAa,OAAQ,EAAE,CAChD,EAEA,KAAQ,MAAS,GAA2B,CACtC,EAAE,MAAQ,UAAY,KAAK,WAAW,MAAA,CAC5C,CAAA,CApBS,mBAA0B,CACjC,MAAM,kBAAA,EACN,OAAO,iBAAiB,WAAY,KAAK,OAAwB,EACjE,OAAO,iBAAiB,UAAW,KAAK,KAAK,CAC/C,CACS,sBAA6B,CACpC,MAAM,qBAAA,EACN,OAAO,oBAAoB,WAAY,KAAK,OAAwB,EACpE,OAAO,oBAAoB,UAAW,KAAK,KAAK,CAClD,CAaQ,OAAc,CAAE,KAAK,KAAO,GAAO,KAAK,gBAAgB,MAAM,CAAG,CACjE,SAASuD,EAAsB,CAAEA,EAAE,UAAA,EAAa,KAAK,MAAA,CAAS,CAE7D,QAAS,CAChB,OAAO/C;AAAAA;AAAAA;AAAAA,6BAGkB,KAAK,MAAM;AAAA,yCACC,IAAM,KAAK,OAAO;AAAA;AAAA,uCAEpB,KAAK,KAAK;AAAA;AAAA,YAErC,KAAK,QAAQ,IAAK+C,GAAM/C;AAAAA,4BACR+C,EAAE,SAAW,EAAE,WAAW,IAAM,KAAK,SAASA,CAAC,CAAC,IAAIA,EAAE,KAAK;AAAA,WAC5E,CAAC;AAAA;AAAA;AAAA,KAIV,CACF,EAtGaqF,EAMJ,OAASnI;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA,IALCC,EAAA,CAAhBmE,EAAA,CAAM,EADI+D,EACM,UAAA,OAAA,CAAA,EACAlI,EAAA,CAAhBmE,EAAA,CAAM,EAFI+D,EAEM,UAAA,SAAA,CAAA,EACAlI,EAAA,CAAhBmE,EAAA,CAAM,EAHI+D,EAGM,UAAA,QAAA,CAAA,EACAlI,EAAA,CAAhBmE,EAAA,CAAM,EAJI+D,EAIM,UAAA,UAAA,CAAA,EAJNA,EAANlI,EAAA,CADNE,EAAc,UAAU,CAAA,EACZgI,CAAA,EAwGN,SAASC,GAAUtB,EAAqB,CAC7C,OAAO,cAAc,IAAI,YAAY,WAAY,CAAE,OAAQA,CAAA,CAAK,CAAC,CACnE,qMC9GO,IAAMuB,EAAN,cAAwBxI,CAAW,CAAnC,aAAA,CAAA,MAAA,GAAA,SAAA,EACI,KAAQ,KAAO,GACf,KAAQ,OAAS,GACjB,KAAQ,IAAM,EAmDvB,KAAQ,KAAc,CACpB,CAAE,IAAK,IAAK,MAAO,eAAgB,IAAK,QAAS,IAAK,SAAY,CAAE,MAAMyC,EAAA,GAAa,IAAA,EAAO/B,EAAQ,MAAQ,GAAM0H,EAAM,mBAAoB,GAAG,CAAG,CAAA,EACpJ,CAAE,IAAK,IAAK,MAAO,iBAAkB,IAAK,SAAY,CAAE,MAAM3F,EAAA,GAAa,MAAA,EAAS/B,EAAQ,MAAQ,GAAO0H,EAAM,SAAU,IAAI,CAAG,CAAA,EAClI,CAAE,IAAK,IAAK,MAAO,iBAAkB,IAAK,KAAM,IAAK,IAAMG,GAAU,CACnE,MAAO,kBACP,KAAM,kEACN,QAAS,CACP,CAAE,MAAO,SAAU,QAAS,OAAA,EAC5B,CAAE,MAAO,QAAS,QAAS,SAAU,QAAS,SAAY,CAAE,MAAM9F,EAAA,GAAa,MAAA,EAASG,EAAQ,OAAQ,sBAAsB,EAAGwF,EAAM,iBAAkB,GAAG,CAAG,CAAA,CAAE,CACnK,CACD,CAAA,EACD,CAAE,IAAK,IAAK,MAAO,iBAAkB,IAAK,SAAY,CACpD,MAAMtI,EAAI2C,EAAA,EAAa,GAAI,CAAC3C,EAAG,OAC/B4B,EAAgB,MAAQ,UACxB,MAAM+C,EAAM9C,EAAgB,MACtB8G,EAAK,IAAI,WAAW,EAAE,EAC5B,QAAS7I,EAAI,EAAGA,EAAI,GAAIA,MAAQA,CAAC,EAAI,SAAS6E,EAAI,MAAM7E,EAAI,EAAGA,EAAI,EAAI,CAAC,EAAG,EAAE,GACnE,MAAME,EAAE,cAAc2I,CAAE,GAC5B,IAAM/G,EAAgB,MAAQ,KAAMD,EAAW,MAAQgD,EAAK2D,EAAM,mBAAoB,GAAG,IACxF1G,EAAgB,MAAQ,OAAQ0G,EAAM,oBAAqB,GAAG,EACvE,CAAA,EACA,CAAE,IAAK,IAAK,MAAO,eAAgB,IAAK,KAAM,IAAK,IAAM,CAAEnH,EAAM,MAAQA,EAAM,QAAU,OAAS,QAAU,MAAQ,CAAA,EACpH,CAAE,IAAK,IAAK,MAAO,gBAAiB,IAAK,KAAM,IAAK,IAAM,OAAO,cAAc,IAAI,YAAY,eAAe,CAAC,CAAA,EAC/G,CAAE,IAAK,IAAK,MAAO,sBAAuB,IAAK,IAAMsH,GAAU,CAC7D,MAAO,qBACP,KAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,cAWN,QAAS,CAAC,CAAE,MAAO,QAAS,QAAS,UAAW,CAAA,CACjD,CAAA,EACD,CAAE,IAAK,IAAK,MAAO,eAAgB,IAAK,IAAMA,GAAU,CACtD,MAAO,cACP,KAAM;AAAA;AAAA,mEAGN,QAAS,CAAC,CAAE,MAAO,QAAS,QAAS,UAAW,CAAA,CACjD,CAAA,CAAE,EAcL,KAAQ,MAAS,GAA2B,EACrC,EAAE,SAAW,EAAE,UAAY,EAAE,IAAI,YAAA,IAAkB,KACtD,EAAE,eAAA,EACF,KAAK,QAAA,GACI,EAAE,MAAQ,UAAY,KAAK,KACpC,KAAK,SAAA,EACI,KAAK,OACV,EAAE,MAAQ,aAAe,KAAK,IAAM,KAAK,IAAI,KAAK,KAAK,OAAS,EAAG,KAAK,IAAM,CAAC,EAAG,EAAE,eAAA,GAC/E,EAAE,MAAQ,WAAa,KAAK,IAAM,KAAK,IAAI,EAAG,KAAK,IAAM,CAAC,EAAG,EAAE,eAAA,GAC/D,EAAE,MAAQ,UAAW,KAAK,OAAA,EAAU,EAAE,eAAA,GAEnD,EAEA,KAAQ,OAAS,IAAY,KAAK,QAAA,CAAQ,CAxBjC,mBAA0B,CACjC,MAAM,kBAAA,EACN,OAAO,iBAAiB,UAAW,KAAK,KAAK,EAC7C,OAAO,iBAAiB,aAAc,KAAK,MAAuB,CACpE,CACS,sBAA6B,CACpC,MAAM,qBAAA,EACN,OAAO,oBAAoB,UAAW,KAAK,KAAK,EAChD,OAAO,oBAAoB,aAAc,KAAK,MAAuB,CACvE,CAiBQ,SAAgB,CACtB,KAAK,KAAO,GAAM,KAAK,aAAa,OAAQ,EAAE,EAC9C,KAAK,OAAS,GAAI,KAAK,IAAM,EAC7B,WAAW,IAAM,KAAK,SAAS,MAAA,EAAS,CAAC,CAC3C,CACQ,UAAiB,CAAE,KAAK,KAAO,GAAO,KAAK,gBAAgB,MAAM,CAAG,CAEpE,UAAkB,CACxB,GAAI,CAAC,KAAK,OAAO,KAAA,SAAe,KAAK,KACrC,MAAM/B,EAAI,KAAK,OAAO,YAAA,EACtB,OAAO,KAAK,KAAK,OAAQ1G,GAAMA,EAAE,MAAM,YAAA,EAAc,SAAS0G,CAAC,CAAC,CAClE,CAEQ,QAAe,CAErB,MAAM1G,EADI,KAAK,SAAA,EACH,KAAK,GAAG,EAChBA,IAAKA,EAAE,IAAA,EAAO,KAAK,SAAA,EACzB,CAES,QAAS,CAChB,MAAM4I,EAAQ,KAAK,SAAA,EACnB,OAAOxI;AAAAA;AAAAA;AAAAA;AAAAA,qBAIU,KAAK,MAAM;AAAA,qBACVV,GAAa,CAAE,KAAK,OAAUA,EAAE,OAA4B,MAAO,KAAK,IAAM,CAAG,CAAC;AAAA;AAAA;AAAA,YAG5FkJ,EAAM,IAAI,CAAC5I,EAAGF,IAAMM;AAAAA,+BACDN,IAAM,KAAK,IAAM,SAAW,EAAE,YAAY,IAAM,CAAE,KAAK,IAAMA,EAAG,KAAK,OAAA,CAAU,CAAC;AAAA,kCAC7EE,EAAE,GAAG;AAAA,kCACLA,EAAE,KAAK;AAAA,gBACzBA,EAAE,IAAMI,sBAAyBJ,EAAE,GAAG,UAAY,EAAE;AAAA;AAAA,WAEzD,CAAC;AAAA;AAAA;AAAA,KAIV,CACF,EAvKa0I,EAMJ,OAASrI;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA,IALCC,EAAA,CAAhBmE,EAAA,CAAM,EADIiE,EACM,UAAA,OAAA,CAAA,EACApI,EAAA,CAAhBmE,EAAA,CAAM,EAFIiE,EAEM,UAAA,SAAA,CAAA,EACApI,EAAA,CAAhBmE,EAAA,CAAM,EAHIiE,EAGM,UAAA,MAAA,CAAA,EACgBpI,EAAA,CAAhC6F,GAAM,gBAAgB,CAAA,EAJZuC,EAIsB,UAAA,UAAA,CAAA,EAJtBA,EAANpI,EAAA,CADNE,EAAc,YAAY,CAAA,EACdkI,CAAA,uMCLN,IAAMG,EAAN,cAAyB3I,CAAW,CAApC,aAAA,CAAA,MAAA,GAAA,SAAA,EACI,KAAQ,KAAO,GACf,KAAQ,UAAY,EAC7B,KAAQ,OAAS,YAAY,IAAA,EAC7B,KAAQ,WAAa,EACrB,KAAQ,MAAQ,EA6ChB,KAAQ,MAAS,GAA2B,CACtC,EAAE,MAAQ,KAAO,CAAE,EAAE,OAAuB,QAAQ,iBAAiB,IACvE,KAAK,KAAO,CAAC,KAAK,KAClB,KAAK,gBAAgB,OAAQ,KAAK,IAAI,EAE1C,EAEA,KAAQ,KAAO,IAAY,CACzB,KAAK,MAAQ,sBAAsB,KAAK,IAAI,EAC5C,MAAM4I,EAAM,YAAY,IAAA,EACxB,KAAK,aACDA,EAAM,KAAK,QAAU,MACvB,KAAK,UAAa,KAAK,WAAa,KAASA,EAAM,KAAK,QACxD,KAAK,WAAa,EAClB,KAAK,OAASA,EACd,KAAK,cAAA,EAET,CAAA,CA7BS,mBAA0B,CACjC,MAAM,kBAAA,EACN,OAAO,iBAAiB,UAAW,KAAK,KAAK,EAC7CpF,EAAO,IAAM,CAAEhC,EAAI,MAAOb,GAAc,MAAOW,EAAK,MAAOC,EAAI,MAAOsH,GAAK,MAAO,KAAK,cAAA,CAAiB,CAAC,EACzG,KAAK,KAAA,CACP,CACS,sBAA6B,CACpC,MAAM,qBAAA,EACN,OAAO,oBAAoB,UAAW,KAAK,KAAK,EAChD,qBAAqB,KAAK,KAAK,CACjC,CAqBS,QAAS,CAChB,OAAO3I;AAAAA,wEAC6D,IAAM,CAAE,KAAK,KAAO,GAAO,KAAK,gBAAgB,MAAM,CAAG,CAAC;AAAA,0EACxD,KAAK,UAAU,QAAQ,CAAC,CAAC;AAAA,uEAC5BsB,EAAI,MAAQ,EAAI,KAAK,MAAMA,EAAI,KAAK,EAAI,GAAG;AAAA,sEAC5Cb,GAAc,MAAM,UAAU;AAAA,oEAChCW,EAAK,MAAQ,KAAK,QAAQ,CAAC,CAAC;AAAA,mEAC7BC,EAAI,MAAQ,EAAIA,EAAI,MAAM,QAAQ,CAAC,EAAI,GAAG;AAAA,mEAC1C,SAAS,iBAAiB,GAAG,EAAE,MAAM;AAAA,KAEtG,CACF,EAhFaoH,EAOJ,OAASxI;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA,IANCC,GAAA,CAAhBmE,EAAA,CAAM,EADIoE,EACM,UAAA,OAAA,CAAA,EACAvI,GAAA,CAAhBmE,EAAA,CAAM,EAFIoE,EAEM,UAAA,YAAA,CAAA,EAFNA,EAANvI,GAAA,CADNE,EAAc,cAAc,CAAA,EAChBqI,CAAA,uMCAN,IAAMG,GAAN,cAA+B9I,CAAW,CAA1C,aAAA,CAAA,MAAA,GAAA,SAAA,EACI,KAAQ,KAAO,EAAA,CAiGf,mBAA0B,CACjC,MAAM,kBAAA,EACNwD,EAAO,IAAM,CAAEvC,EAAM,MAAOC,EAAQ,MAAOC,EAAc,MAAOC,GAAW,MAAOb,EAAU,MAAOE,GAAM,MAAO,KAAK,cAAA,CAAiB,CAAC,EACvI,OAAO,iBAAiB,gBAAiB,IAAM,CAAE,KAAK,KAAO,GAAM,KAAK,aAAa,OAAQ,EAAE,CAAG,CAAC,CACrG,CAEQ,OAAc,CAAE,KAAK,KAAO,GAAO,KAAK,gBAAgB,MAAM,CAAG,CAEhE,QAAS,CAChB,OAAOP;AAAAA,kCACuB,IAAM,KAAK,OAAO;AAAA;AAAA;AAAA,uCAGb,IAAM,KAAK,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,8BAQ3Be,EAAM,QAAU,OAAS,KAAO,EAAE,WAAW,IAAMA,EAAM,MAAQ,MAAM;AAAA,8BACvEA,EAAM,QAAU,QAAU,KAAO,EAAE,WAAW,IAAMA,EAAM,MAAQ,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,8BASzEC,EAAQ,QAAU,QAAU,KAAO,EAAE,WAAW,IAAMA,EAAQ,MAAQ,OAAO;AAAA,8BAC7EA,EAAQ,QAAU,UAAY,KAAO,EAAE,WAAW,IAAMA,EAAQ,MAAQ,SAAS;AAAA,8BACjFA,EAAQ,QAAU,UAAY,KAAO,EAAE,WAAW,IAAMA,EAAQ,MAAQ,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kCAQ7EC,EAAc,MAAQ,KAAO,EAAE;AAAA,uBAC1C,IAAMA,EAAc,MAAQ,CAACA,EAAc,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kCASrCC,GAAW,MAAQ,KAAO,EAAE;AAAA,uBACvC,IAAMA,GAAW,MAAQ,CAACA,GAAW,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,8BASnCb,EAAU,QAAU,OAAS,KAAO,EAAE,WAAW,IAAMA,EAAU,MAAQ,MAAM;AAAA,8BAC/EA,EAAU,QAAU,KAAO,KAAO,EAAE,WAAW,IAAMA,EAAU,MAAQ,IAAI;AAAA;AAAA;AAAA,YAG7FA,EAAU,QAAU,KAAOL;AAAAA;AAAAA;AAAAA,4EAGqCO,GAAM,KAAK;AAAA,yBAC7D,GAAaA,GAAM,MAAS,EAAE,OAA4B,KAAK;AAAA,oBACnE,EAAE;AAAA;AAAA;AAAA,KAItB,CACF,EA7KaqI,GAGJ,OAAS3I;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA,IAFCC,GAAA,CAAhBmE,EAAA,CAAM,EADIuE,GACM,UAAA,OAAA,CAAA,EADNA,GAAN1I,GAAA,CADNE,EAAc,oBAAoB,CAAA,EACtBwI,EAAA,uMCQb,MAAMC,GAAoB,CACxB,CACE,MAAO,mBACP,KAAM;AAAA;AAAA;AAAA,8EAIN,IAAK,YAAA,EAEP,CACE,MAAO,kBACP,KAAM;AAAA;AAAA;AAAA;AAAA,4FAAA,EAMR,CACE,MAAO,sBACP,KAAM;AAAA;AAAA;AAAA;AAAA,+DAAA,EAMR,CACE,MAAO,mBACP,KAAM;AAAA;AAAA;AAAA;AAAA,2DAAA,EAMR,CACE,MAAO,eACP,KAAM;AAAA;AAAA;AAAA;AAAA;AAAA,kEAAA,EAOR,CACE,MAAO,gBACP,KAAM;AAAA;AAAA;AAAA,sFAIN,IAAK,aAAA,CAET,EAGO,IAAMC,EAAN,cAA2BhJ,CAAW,CAAtC,aAAA,CAAA,MAAA,GAAA,SAAA,EACI,KAAQ,KAAO,GACf,KAAQ,KAAO,EAwFxB,KAAQ,KAAO,IAAY,CACzB,KAAK,KAAO,EACZ,KAAK,KAAO,GACZ,KAAK,aAAa,OAAQ,EAAE,CAC9B,CAAA,CAlBA,MAAe,mBAAmC,CAChD,MAAM,kBAAA,EACN,OAAO,iBAAiB,eAAgB,KAAK,IAAqB,EACrD,MAAMmH,EAAe,iBAAiB,IAEjD,KAAK,KAAO,GACZ,KAAK,aAAa,OAAQ,EAAE,EAEhC,CACS,sBAA6B,CACpC,MAAM,qBAAA,EACN,OAAO,oBAAoB,eAAgB,KAAK,IAAqB,CACvE,CAQA,MAAc,SAAyB,CACrC,KAAK,KAAO,GACZ,KAAK,gBAAgB,MAAM,EAC3B,MAAME,EAAM,kBAAmB,EAAI,CACrC,CAEQ,MAAa,CACf,KAAK,KAAO0B,GAAM,OAAS,EAAG,KAAK,OAC7B,KAAK,QAAA,CACjB,CAEQ,MAAa,CACf,KAAK,KAAO,GAAG,KAAK,MAC1B,CAES,QAAS,CAChB,MAAMlJ,EAAIkJ,GAAM,KAAK,IAAI,EACzB,OAAO7I;AAAAA;AAAAA;AAAAA,gBAGKL,EAAE,KAAK;AAAA,wCACiB,IAAM,KAAK,SAAS;AAAA;AAAA,uCAErBA,EAAE,IAAI;AAAA;AAAA;AAAA,cAG/BkJ,GAAM,IAAI,CAACE,EAAGrJ,IAAMM,oBAAuBN,IAAM,KAAK,KAAO,SAAW,EAAE,UAAU,CAAC;AAAA;AAAA,YAEvF,KAAK,KAAO,EACVM,iCAAoC,IAAM,KAAK,KAAA,CAAM,iBACrD,EAAE;AAAA,2CAC2B,IAAM,KAAK,MAAM;AAAA,cAC9C,KAAK,OAAS6I,GAAM,OAAS,EAAKlJ,EAAE,KAAO,OAAWA,EAAE,KAAO,MAAO;AAAA;AAAA;AAAA;AAAA,KAKlF,CACF,EAtIamJ,EAIJ,OAAS7I;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA,IAHCC,GAAA,CAAhBmE,EAAA,CAAM,EADIyE,EACM,UAAA,OAAA,CAAA,EACA5I,GAAA,CAAhBmE,EAAA,CAAM,EAFIyE,EAEM,UAAA,OAAA,CAAA,EAFNA,EAAN5I,GAAA,CADNE,EAAc,eAAe,CAAA,EACjB0I,CAAA,uMC7CN,IAAME,GAAN,cAAoBlJ,CAAW,CAA/B,aAAA,CAAA,MAAA,GAAA,SAAA,EACI,KAAQ,KAAa,OAAA,CAiDrB,QAAS,CAChB,OAAOE;AAAAA;AAAAA,yBAEc,KAAK,IAAI,cAAe,GAA0B,KAAK,KAAO,EAAE,MAAO;AAAA;AAAA;AAAA;AAAA,YAIpF,KAAK,OAAS,OAASA,iCAAsCA,wBAA2B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAYlG,CACF,EAtEagJ,GAGJ,OAAS/I;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA,IAFCC,GAAA,CAAhBmE,EAAA,CAAM,EADI2E,GACM,UAAA,OAAA,CAAA,EADNA,GAAN9I,GAAA,CADNE,EAAc,QAAQ,CAAA,EACV4I,EAAA,EC+DN,SAASC,GAAcC,EAAgBC,EAAgBC,EAAiC,CAI7F,MAAMC,EAAQH,EAAK,UAAUC,EAAS,EAAG,EAAI,EACvCG,EAAUJ,EAAK,UAAUC,EAAS,EAAG,EAAI,EACzCI,EAAQL,EAAK,UAAUC,EAAS,EAAG,EAAI,EACvCK,EAAWN,EAAK,UAAUC,EAAS,EAAG,EAAI,EAE1CM,EAAMP,EAAK,aAAaC,EAAS,GAAI,EAAI,EACzCO,EAAKR,EAAK,WAAWC,EAAS,GAAI,EAAI,EACtCQ,EAAKT,EAAK,WAAWC,EAAS,GAAI,EAAI,EACtCS,GAAKV,EAAK,WAAWC,EAAS,GAAI,EAAI,EACtCU,GAAKX,EAAK,WAAWC,EAAS,GAAI,EAAI,EACtCW,GAAKZ,EAAK,WAAWC,EAAS,GAAI,EAAI,EACtCY,GAAKb,EAAK,WAAWC,EAAS,GAAI,EAAI,EACtCa,GAAqBd,EAAK,WAAWC,EAAS,GAAI,EAAI,EACtDc,GAAef,EAAK,WAAWC,EAAS,GAAI,EAAI,EACtD,MAAO,CACL,MAAAE,EACA,QAAAC,EACA,MAAAC,EACA,SAAAC,EACA,IAAAC,EACA,IAAK,CAACC,EAAIC,EAAIC,EAAE,EAChB,QAAS,CAACC,GAAIC,GAAIC,EAAE,EACpB,mBAAAC,GACA,aAAAC,GACA,IAAKb,EAAI,SAASD,EAAQA,EAAS,EAAE,CAAA,CAEzC,CAEO,SAASe,GAAgBpF,EAAqC,CAEnE,MAAMoE,EAAO,IAAI,SAASpE,EAAM,OAAQA,EAAM,WAAYA,EAAM,UAAU,EACpEqF,EAAwB,CAAA,EAC9B,QAASC,EAAM,EAAGA,EAAM,IAAatF,EAAM,WAAYsF,GAAO,GAC5DD,EAAI,KAAKlB,GAAcC,EAAMkB,EAAKtF,CAAK,CAAC,EAE1C,OAAOqF,CACT,CCrGO,MAAME,EAAkC,CAQ7C,aAAc,CANd,KAAQ,OAAS,EACjB,KAAQ,YAAc,IACtB,KAAQ,cAAgB,IACxB,KAAQ,cAAgB,IACxB,KAAQ,SAAgC,KAGtC,KAAK,OAAS,IAAI,OAAO,IAAA,IAAA,0CAAA,YAAA,GAAA,EAAyC,CAAE,KAAM,QAAA,CAAU,EACpF,KAAK,OAAO,iBAAiB,UAAYC,GAAO,KAAK,UAAUA,CAAE,CAAC,EAClE,KAAK,OAAO,iBAAiB,QAAUhL,GACrC,KAAK,UAAU,QAAS,GAAM,EAAE,CAAE,KAAM,MAAO,MAAO,MAAO,IAAK,OAAOA,EAAE,OAAO,EAAG,CAAC,CAAA,CAE1F,CAEQ,UAAUgL,EAAwB,CACxC,MAAMC,EAAID,EAAG,KACb,GAAIC,EAAE,OAAS,SAAU,CACvB,MAAMC,EAAMD,EAAE,MACRzF,EAAQ,IAAI,WAAW0F,CAAG,EAE1BC,EAAuB,CAAE,OADhBP,GAAgBpF,CAAK,EACG,MAAAA,CAAA,EACvC,KAAK,UAAU,QAASnF,GAAMA,EAAE8K,CAAK,CAAC,EACtC,MAAMnJ,EAAMiJ,EAAE,IACVjJ,EAAM,GACR,KAAK,UAAU,QAAS3B,GAAMA,EAAE,CAAE,KAAM,MAAO,MAAO2B,CAAA,CAAK,CAAC,EAE9D,MACF,CACA,GAAIiJ,EAAE,OAAS,QAAS,CACtB,KAAK,UAAU,QAAS5K,GACtBA,EAAE,CACA,KAAM,QACN,QAAS,EAAQ4K,EAAE,QACnB,EAAG,EACH,cAAe,OAAOA,EAAE,eAAiB,CAAC,CAAA,CAC3C,CAAA,EAEH,MACF,CACA,GAAIA,EAAE,OAAS,QAGf,IAAIA,EAAE,OAAS,OAASA,EAAE,IAAM,KAAM,CACpC,KAAK,UAAU,QAAS5K,GACtBA,EAAE,CAAE,KAAM,MAAO,MAAO,MAAO,IAAK,OAAO4K,EAAE,GAAG,EAAG,CAAA,EAErD,MACF,CACA,GAAI,OAAOA,EAAE,IAAO,UAAY,KAAK,QAAQ,IAAIA,EAAE,EAAE,EAAG,CACtD,MAAM3F,EAAI,KAAK,QAAQ,IAAI2F,EAAE,EAAE,EAC/B,KAAK,QAAQ,OAAOA,EAAE,EAAE,EACpBA,EAAE,OAAS,MAAO3F,EAAE,OAAO,IAAI,MAAM,OAAO2F,EAAE,GAAG,CAAC,CAAC,EAClD3F,EAAE,QAAQ2F,CAAC,CAClB,EACF,CAEQ,IAAiB3H,EAA8B8H,EAA2B,GAAgB,CAChG,MAAMhH,EAAK,KAAK,SAChB,OAAO,IAAI,QAAW,CAACmD,EAASC,IAAW,CACzC,KAAK,QAAQ,IAAIpD,EAAI,CAAE,QAAAmD,EAA0C,OAAAC,EAAQ,EACzE,KAAK,OAAO,YAAY,CAAE,GAAGlE,EAAK,GAAAc,CAAA,EAAMgH,CAAQ,CAClD,CAAC,CACH,CAEA,MAAM,MAA8B,CAClC,GAAI,KAAK,SAAU,OAAO,KAAK,SAK/B,MAAMlL,EAAI,MAAM,KAAK,IACnB,CAAE,KAAM,OAAQ,KAFL,gBAEK,CAAK,EAEvB,YAAK,SAAW,CACd,aAAcA,EAAE,aAChB,WAAYA,EAAE,WACd,WAAYA,EAAE,WACd,mBAAoBA,EAAE,kBAAA,EAEjB,KAAK,QACd,CAEA,MAAM,UAAUmL,EAAiC,CAC/C,MAAM,KAAK,IAAI,CAAE,KAAM,WAAY,KAAM,KAAK,UAAUA,CAAK,EAAG,CAClE,CAEA,MAAM,UAAUC,EAAwC,CACtD,MAAM,KAAK,IAAI,CAAE,KAAM,YAAa,KAAM,KAAK,UAAUA,CAAG,EAAG,CACjE,CAEA,MAAM,QAAQlK,EAA6B,CACzC,MAAM,KAAK,IAAI,CAAE,KAAM,UAAW,KAAM,OAAOA,EAAO,WAAW,EAAG,CACtE,CAEA,MAAM,OAAuB,CAC3B,MAAM,KAAK,IAAI,CAAE,KAAM,QAAS,CAClC,CAEA,MAAM,IAAImK,EAAgC,CACxC,MAAM,KAAK,IAAI,CAAE,KAAM,MAAO,CAChC,CAEA,MAAM,OAAuB,CAC3B,MAAM,KAAK,IAAI,CAAE,KAAM,QAAS,CAClC,CAEA,MAAM,KAAKC,EAA4BC,EAA8B,CACnE,MAAM,KAAK,IAAI,CAAE,KAAM,OAAQ,CACjC,CAEA,SAASC,EAA0C,CAAE,KAAK,UAAU,IAAIA,CAAE,CAAG,CAC7E,QAAQA,EAAoC,CAAE,KAAK,UAAU,IAAIA,CAAE,CAAG,CAEtE,MAAM,gBAAgBC,EAAsC,CAC1D,MAAMzL,EAAI,MAAM,KAAK,IAA2C,CAAE,KAAM,kBAAmB,QAAAyL,EAAS,EACpG,OAAO,IAAI,WAAWzL,EAAE,OAAO,CACjC,CAEA,MAAM,cAAc0L,EAAiF,CACnG,MAAMV,EAAMU,EAAS,MAAA,EAAQ,OACvB,EAAI,MAAM,KAAK,IACnB,CAAE,KAAM,gBAAiB,QAAS,IAAK,SAAUV,CAAA,EACjD,CAACA,CAAG,CAAA,EAEN,OAAI,EAAE,GAAW,CAAE,GAAI,EAAA,EAChB,CAAE,GAAI,GAAO,OAAQ,IAAI,WAAW,EAAE,MAAM,CAAA,CACrD,CAEA,MAAM,mBAAmC,CAGvC,MAAMW,EAAI,MAAM,KAAK,gBAAgB,GAAG,EAClCpG,EAAM,MAAM,KAAKoG,CAAC,EAAE,IAAKpI,GAAMA,EAAE,SAAS,EAAE,EAAE,SAAS,EAAG,GAAG,CAAC,EAAE,KAAK,EAAE,EACvEqI,EAAO,KAAK,UAAa,MAAM,KAAK,KAAA,EACpCC,EAAW,KAAK,UACpB,CACE,KAAM,qBACN,QAASD,EAAK,aACd,KAAM,aACN,SAAU,IACV,QAASrG,EACT,SAAUqG,EAAK,mBACf,GAAIrG,IAAQqG,EAAK,mBACjB,GAAI,IAAI,KAAA,EAAO,YAAA,CAAY,EAE7B,KACA,CAAA,EAEF,OAAO,IAAI,KAAK,CAACC,CAAQ,EAAG,CAAE,KAAM,mBAAoB,CAC1D,CAEA,MAAM,SAA2B,CAE/B,OADU,MAAM,KAAK,IAAyB,CAAE,KAAM,UAAW,GACxD,OACX,CAEA,MAAM,OAAuB,CAC3B,KAAK,OAAO,UAAA,CACd,CACF,CC7KA,SAASC,GAAWjM,EAAiB,CACnC,SAAS,gBAAgB,aAAa,aAAcA,CAAC,CACvD,CACA,SAASkM,GAAaC,EAAiB,CACrC,SAAS,KAAK,UAAU,OAAO,gBAAiB,kBAAmB,iBAAiB,EACpF,SAAS,KAAK,UAAU,IAAI,WAAWA,CAAC,EAAE,CAC5C,CACA,SAASC,GAAYC,EAAwB,CAC3C,SAAS,KAAK,UAAU,OAAO,gBAAiBA,CAAO,CACzD,EAEC,SAAY,CAEX,MAAMrM,EAAK,MAAM4H,EAAwB,OAAO,GAAM,OAChDuE,EAAK,MAAMvE,EAAuC,SAAS,GAAM,UACjEsD,EAAK,MAAMtD,EAAe,eAAe,GAAM,GACrDlG,EAAM,MAAQ1B,EAAGiM,GAAWjM,CAAC,EAC7B2B,EAAQ,MAAQwK,EAAGD,GAAaC,CAAC,EACjCvK,EAAc,MAAQsJ,EAAGkB,GAAYlB,CAAC,EAGtCjH,EAAO,IAAM,CAAEgI,GAAWvK,EAAM,KAAK,EAAGoG,EAAM,QAASpG,EAAM,KAAK,CAAG,CAAC,EACtEuC,EAAO,IAAM,CAAEiI,GAAavK,EAAQ,KAAK,EAAGmG,EAAM,UAAWnG,EAAQ,KAAK,CAAG,CAAC,EAC9EsC,EAAO,IAAM,CAAEmI,GAAYxK,EAAc,KAAK,EAAGkG,EAAM,gBAAiBlG,EAAc,KAAK,CAAG,CAAC,EAG/F,MAAM0K,EAAS,IAAItB,GACnB/H,GAAUqJ,CAAM,EAEhBjJ,EAAQ,OAAQ,8BAA8B,EAC9CiJ,EAAO,QAASrB,GAAO,CACjBA,EAAG,OAAS,SAAeA,EAAG,MAAOA,EAAG,GAAG,EAC3CA,EAAG,OAAS,QAAOhJ,EAAI,MAAQgJ,EAAG,OAClCA,EAAG,OAAS,UACd7J,GAAc,MAAQ,OAAO6J,EAAG,aAAa,EAEjD,CAAC,EAEDqB,EAAO,SAAUlB,GAAU,CACzB,GAAIA,EAAM,OAAO,SAAW,EAAG,OAC/B,MAAMmB,EAAOnB,EAAM,OAAOA,EAAM,OAAO,OAAS,CAAC,EACjD/I,GAAU,MAAQkK,EAClB,MAAMlC,EAAKkC,EAAK,IAAI,CAAC,EAAI,MACnBjC,EAAKiC,EAAK,IAAI,CAAC,EAAI,MACnBhC,EAAKgC,EAAK,IAAI,CAAC,EAAI,MACzBzK,GAAM,MAAQ,CAACuI,EAAIC,EAAIC,CAAE,EACzBxI,EAAK,MAAQ,KAAK,KAAKsI,EAAKA,EAAKC,EAAKA,EAAKC,EAAKA,CAAE,EAElD9G,GAAU,CAAC4G,EAAK,IAAKC,EAAK,IAAKC,EAAK,GAAG,CAAC,EACxC,MAAMxG,EAAM,KAAK,IAAI,EAAG,KAAK,IAAIwG,EAAK,GAAG,EAAI,EAAI,EAAG,EACpDzG,GAAaC,CAAG,CAClB,CAAC,EAED,GAAI,CACF,MAAMgI,EAAO,MAAMO,EAAO,KAAA,EAC1BlK,EAAgB,MAAQ2J,EAAK,mBAC7B1I,EAAQ,KAAM,6BAA6B0I,EAAK,YAAY,cAAcA,EAAK,WAAW,SAAS,EAAE,EAAE,YAAA,CAAa,EAAE,EACtH1I,EAAQ,OAAQ,sBAAsB0I,EAAK,mBAAmB,MAAM,EAAG,EAAE,CAAC,GAAG,EAG7EpJ,GAAU,MAAQ,oBAClB3B,EAAU,MAAQ,MACpB,OAASf,EAAG,CACVoD,EAAQ,MAAO,gBAAiBpD,EAAY,OAAO,EAAE,CACvD,CAGA,GAAI,CACF,MAAMiF,EAAM9C,EAAgB,MAC5B,GAAI8C,EAAK,CACP,MAAMC,EAAW,IAAI,WAAW,EAAE,EAClC,QAAS9E,EAAI,EAAGA,EAAI,GAAIA,MAAcA,CAAC,EAAI,SAAS6E,EAAI,MAAM7E,EAAI,EAAGA,EAAI,EAAI,CAAC,EAAG,EAAE,EACnF,MAAMF,EAAI,MAAMmM,EAAO,cAAcnH,CAAQ,EAC7C,GAAIhF,EAAE,GACJ+B,EAAW,MAAQgD,EACnB7B,EAAQ,KAAM,uCAAuC,MAChD,CACL,MAAM+B,EAAS,MAAM,KAAKjF,EAAE,MAAM,EAC/B,IAAKuD,GAAMA,EAAE,SAAS,EAAE,EAAE,SAAS,EAAG,GAAG,CAAC,EAC1C,KAAK,EAAE,EACVxB,EAAW,MAAQkD,EACnB/B,EAAQ,MAAO,+BAA+B6B,EAAI,MAAM,EAAG,EAAE,CAAC,SAASE,EAAO,MAAM,EAAG,EAAE,CAAC,GAAG,CAC/F,CACF,CACF,OAASnF,EAAG,CACVoD,EAAQ,OAAQ,2BAA4BpD,EAAY,OAAO,EAAE,CACnE,CACF,GAAA","x_google_ignoreList":[0,1,2,3,4]}
\ No newline at end of file
diff --git a/nvsim/assets/worker-BW0kLvYS.js b/nvsim/assets/worker-BW0kLvYS.js
new file mode 100644
index 00000000..6646df98
--- /dev/null
+++ b/nvsim/assets/worker-BW0kLvYS.js
@@ -0,0 +1,2 @@
+const d=self;let o,_,x,g,W;async function B(r){const e=new URL(r,d.location.origin).href,s=await import(new URL("nvsim-pkg/nvsim.js",e).href);await s.default(),o=s.WasmPipeline,_=s.referenceSceneJson,x=s.expectedReferenceWitnessHex,g=s.hexWitness,W=s.referenceWitness}let a=null,p="",b="",F=BigInt(3405691582),m=!1,l=null,i=0,w=0;function f(){b||(b=_()),p||(p=JSON.stringify({digitiser:{f_s_hz:1e4,f_mod_hz:1e3},sensor:{gamma_fwhm_hz:1e6,t1_s:.005,t2_s:1e-6,t2_star_s:2e-7,contrast:.03,n_spins:1e12,shot_noise_disabled:!1},dt_s:null})),a?.free?.(),a=new o(b,p,Number(F&0xFFFFFFFFn))}function t(r,e=[]){d.postMessage(r,e)}function S(){if(l!==null)return;w=performance.now(),i=0;const r=()=>{if(!m||!a)return;const e=32,n=a.run(e);i+=e;const s=(performance.now()-w)/1e3,c=s>0?i/s:0;t({type:"frames",batch:n.buffer,count:e,fps:c,framesEmitted:i},[n.buffer]),l=d.setTimeout(r,16)};l=d.setTimeout(r,0)}function h(){l!==null&&(d.clearTimeout(l),l=null)}d.addEventListener("message",async r=>{const e=r.data;try{switch(e.type){case"boot":{const n=e.base??"/";await B(n),f(),t({type:"booted",id:e.id,buildVersion:o.buildVersion(),frameMagic:o.frameMagic(),frameBytes:o.frameBytes(),expectedWitnessHex:x()});break}case"setScene":{b=e.json,f(),t({type:"ack",id:e.id});break}case"setConfig":{p=e.json,f(),t({type:"ack",id:e.id});break}case"setSeed":{F=BigInt(e.seed),f(),t({type:"ack",id:e.id});break}case"reset":{h(),m=!1,f(),i=0,t({type:"ack",id:e.id}),t({type:"state",running:!1,framesEmitted:i});break}case"run":{a||f(),m=!0,S(),t({type:"ack",id:e.id}),t({type:"state",running:!0,framesEmitted:i});break}case"pause":{m=!1,h(),t({type:"ack",id:e.id}),t({type:"state",running:!1,framesEmitted:i});break}case"step":{a||f();const n=a.run(1);i+=1,t({type:"frames",batch:n.buffer,count:1,fps:0,framesEmitted:i},[n.buffer]),t({type:"ack",id:e.id});break}case"witnessGenerate":{a||f();const n=e.samples??256,s=a.runWithWitness(n),c=g(s.witness);t({type:"witness",id:e.id,witness:s.witness.buffer,hex:c,frameCount:s.frameCount},[s.witness.buffer]);break}case"witnessVerify":{const n=e.expected,s=new Uint8Array(n),c=W();let y=c.length===s.length;if(y){for(let u=0;u \n\nconst ws = self as unknown as DedicatedWorkerGlobalScope;\n\ninterface WasmPipelineApi {\n run(n: number): Uint8Array;\n runWithWitness(n: number): { frames: Uint8Array; witness: Uint8Array; frameCount: number };\n free?: () => void;\n}\ntype WasmPipelineCtor = new (sceneJson: string, configJson: string, seed: number) => WasmPipelineApi;\ntype WasmPipelineStatic = WasmPipelineCtor & {\n buildVersion(): string;\n frameMagic(): number;\n frameBytes(): number;\n};\n\ninterface NvsimPkg {\n default: (input?: unknown) => Promise;\n WasmPipeline: WasmPipelineStatic;\n referenceSceneJson: () => string;\n expectedReferenceWitnessHex: () => string;\n hexWitness: (b: Uint8Array) => string;\n referenceWitness: () => Uint8Array;\n}\n\nlet _WasmPipeline!: WasmPipelineStatic;\nlet referenceSceneJson!: () => string;\nlet expectedReferenceWitnessHex!: () => string;\nlet hexWitness!: (b: Uint8Array) => string;\nlet referenceWitness!: () => Uint8Array;\n\nasync function loadPkg(base: string): Promise {\n // `base` is the dashboard's BASE_URL injected by Vite, prefixed with the\n // origin so we get an absolute URL the dynamic import can resolve. In dev\n // this is \"/\", in prod under GitHub Pages it's \"/RuView/nvsim/\".\n const absoluteBase = new URL(base, ws.location.origin).href;\n const pkgUrl = new URL('nvsim-pkg/nvsim.js', absoluteBase).href;\n const pkg = (await import(/* @vite-ignore */ pkgUrl)) as NvsimPkg;\n await pkg.default();\n _WasmPipeline = pkg.WasmPipeline;\n referenceSceneJson = pkg.referenceSceneJson;\n expectedReferenceWitnessHex = pkg.expectedReferenceWitnessHex;\n hexWitness = pkg.hexWitness;\n referenceWitness = pkg.referenceWitness;\n}\n\nlet pipeline: WasmPipelineApi | null = null;\nlet configJson = '';\nlet sceneJson = '';\nlet seed = BigInt(0xCAFEBABE);\n\nlet running = false;\nlet timer: number | null = null;\nlet framesEmitted = 0;\nlet tStart = 0;\n\nfunction ensureRebuild(): void {\n if (!sceneJson) sceneJson = referenceSceneJson();\n if (!configJson) {\n configJson = JSON.stringify({\n digitiser: { f_s_hz: 10000, f_mod_hz: 1000 },\n sensor: {\n gamma_fwhm_hz: 1.0e6,\n t1_s: 5.0e-3,\n t2_s: 1.0e-6,\n t2_star_s: 200e-9,\n contrast: 0.03,\n n_spins: 1.0e12,\n shot_noise_disabled: false,\n },\n dt_s: null,\n });\n }\n pipeline?.free?.();\n pipeline = new _WasmPipeline(sceneJson, configJson, Number(seed & 0xFFFFFFFFn));\n}\n\nfunction post(msg: unknown, transfer: Transferable[] = []): void {\n // postMessage Transferable overload: pass transfer list as 2nd arg\n (ws.postMessage as (msg: unknown, t: Transferable[]) => void)(msg, transfer);\n}\n\nfunction startTimer(): void {\n if (timer !== null) return;\n tStart = performance.now();\n framesEmitted = 0;\n const tick = (): void => {\n if (!running || !pipeline) return;\n // Per-tick: simulate 32 frames; push as one batch.\n const n = 32;\n const bytes = pipeline.run(n);\n framesEmitted += n;\n const elapsed = (performance.now() - tStart) / 1000;\n const fps = elapsed > 0 ? framesEmitted / elapsed : 0;\n post(\n { type: 'frames', batch: bytes.buffer, count: n, fps, framesEmitted },\n [bytes.buffer],\n );\n timer = ws.setTimeout(tick, 16);\n };\n timer = ws.setTimeout(tick, 0);\n}\n\nfunction stopTimer(): void {\n if (timer !== null) {\n ws.clearTimeout(timer);\n timer = null;\n }\n}\n\nws.addEventListener('message', async (ev: MessageEvent): Promise => {\n const m = ev.data as { type: string; id?: number; [k: string]: unknown };\n try {\n switch (m.type) {\n case 'boot': {\n const base = (m.base as string | undefined) ?? '/';\n await loadPkg(base);\n ensureRebuild();\n post({\n type: 'booted',\n id: m.id,\n buildVersion: _WasmPipeline.buildVersion(),\n frameMagic: _WasmPipeline.frameMagic(),\n frameBytes: _WasmPipeline.frameBytes(),\n expectedWitnessHex: expectedReferenceWitnessHex(),\n });\n break;\n }\n case 'setScene': {\n sceneJson = m.json as string;\n ensureRebuild();\n post({ type: 'ack', id: m.id });\n break;\n }\n case 'setConfig': {\n configJson = m.json as string;\n ensureRebuild();\n post({ type: 'ack', id: m.id });\n break;\n }\n case 'setSeed': {\n seed = BigInt(m.seed as string | number | bigint);\n ensureRebuild();\n post({ type: 'ack', id: m.id });\n break;\n }\n case 'reset': {\n stopTimer();\n running = false;\n ensureRebuild();\n framesEmitted = 0;\n post({ type: 'ack', id: m.id });\n post({ type: 'state', running: false, framesEmitted });\n break;\n }\n case 'run': {\n if (!pipeline) ensureRebuild();\n running = true;\n startTimer();\n post({ type: 'ack', id: m.id });\n post({ type: 'state', running: true, framesEmitted });\n break;\n }\n case 'pause': {\n running = false;\n stopTimer();\n post({ type: 'ack', id: m.id });\n post({ type: 'state', running: false, framesEmitted });\n break;\n }\n case 'step': {\n if (!pipeline) ensureRebuild();\n const bytes = pipeline!.run(1);\n framesEmitted += 1;\n post(\n { type: 'frames', batch: bytes.buffer, count: 1, fps: 0, framesEmitted },\n [bytes.buffer],\n );\n post({ type: 'ack', id: m.id });\n break;\n }\n case 'witnessGenerate': {\n if (!pipeline) ensureRebuild();\n const samples = (m.samples as number) ?? 256;\n const result = pipeline!.runWithWitness(samples) as {\n frames: Uint8Array;\n witness: Uint8Array;\n frameCount: number;\n };\n const hex = hexWitness(result.witness);\n post(\n {\n type: 'witness',\n id: m.id,\n witness: result.witness.buffer,\n hex,\n frameCount: result.frameCount,\n },\n [result.witness.buffer],\n );\n break;\n }\n case 'witnessVerify': {\n // Verify always runs the *canonical* reference scene at seed=42, N=256\n // so the witness matches Proof::EXPECTED_WITNESS_HEX byte-for-byte.\n // The user's working scene/config/seed don't affect the witness.\n const expectedBuf = m.expected as ArrayBuffer;\n const expected = new Uint8Array(expectedBuf);\n const actual = referenceWitness();\n let ok = actual.length === expected.length;\n if (ok) {\n for (let i = 0; i < expected.length; i++) {\n if (actual[i] !== expected[i]) { ok = false; break; }\n }\n }\n const actualBuf = actual.slice().buffer;\n post(\n {\n type: 'verify',\n id: m.id,\n ok,\n actual: actualBuf,\n actualHex: hexWitness(actual),\n },\n [actualBuf],\n );\n break;\n }\n case 'buildId': {\n post({\n type: 'buildId',\n id: m.id,\n buildId: `nvsim@${_WasmPipeline.buildVersion()}`,\n });\n break;\n }\n default:\n post({ type: 'err', id: m.id, msg: `unknown op ${m.type}` });\n }\n } catch (e) {\n post({ type: 'err', id: m.id, msg: (e as Error).message ?? String(e) });\n }\n});\n\npost({ type: 'ready' });\n"],"names":["ws","_WasmPipeline","referenceSceneJson","expectedReferenceWitnessHex","hexWitness","referenceWitness","loadPkg","base","absoluteBase","pkg","pipeline","configJson","sceneJson","seed","running","timer","framesEmitted","tStart","ensureRebuild","post","msg","transfer","startTimer","tick","n","bytes","elapsed","fps","stopTimer","ev","m","samples","result","hex","expectedBuf","expected","actual","ok","i","actualBuf","e"],"mappings":"AAWA,MAAMA,EAAK,KAuBX,IAAIC,EACAC,EACAC,EACAC,EACAC,EAEJ,eAAeC,EAAQC,EAA6B,CAIlD,MAAMC,EAAe,IAAI,IAAID,EAAMP,EAAG,SAAS,MAAM,EAAE,KAEjDS,EAAO,MAAM,OADJ,IAAI,IAAI,qBAAsBD,CAAY,EAAE,MAE3D,MAAMC,EAAI,QAAA,EACVR,EAAgBQ,EAAI,aACpBP,EAAqBO,EAAI,mBACzBN,EAA8BM,EAAI,4BAClCL,EAAaK,EAAI,WACjBJ,EAAmBI,EAAI,gBACzB,CAEA,IAAIC,EAAmC,KACnCC,EAAa,GACbC,EAAY,GACZC,EAAO,OAAO,UAAU,EAExBC,EAAU,GACVC,EAAuB,KACvBC,EAAgB,EAChBC,EAAS,EAEb,SAASC,GAAsB,CACxBN,IAAWA,EAAYV,EAAA,GACvBS,IACHA,EAAa,KAAK,UAAU,CAC1B,UAAW,CAAE,OAAQ,IAAO,SAAU,GAAA,EACtC,OAAQ,CACN,cAAe,IACf,KAAM,KACN,KAAM,KACN,UAAW,KACX,SAAU,IACV,QAAS,KACT,oBAAqB,EAAA,EAEvB,KAAM,IAAA,CACP,GAEHD,GAAU,OAAA,EACVA,EAAW,IAAIT,EAAcW,EAAWD,EAAY,OAAOE,EAAO,WAAW,CAAC,CAChF,CAEA,SAASM,EAAKC,EAAcC,EAA2B,GAAU,CAE9DrB,EAAG,YAA0DoB,EAAKC,CAAQ,CAC7E,CAEA,SAASC,GAAmB,CAC1B,GAAIP,IAAU,KAAM,OACpBE,EAAS,YAAY,IAAA,EACrBD,EAAgB,EAChB,MAAMO,EAAO,IAAY,CACvB,GAAI,CAACT,GAAW,CAACJ,EAAU,OAE3B,MAAMc,EAAI,GACJC,EAAQf,EAAS,IAAIc,CAAC,EAC5BR,GAAiBQ,EACjB,MAAME,GAAW,YAAY,IAAA,EAAQT,GAAU,IACzCU,EAAMD,EAAU,EAAIV,EAAgBU,EAAU,EACpDP,EACE,CAAE,KAAM,SAAU,MAAOM,EAAM,OAAQ,MAAOD,EAAG,IAAAG,EAAK,cAAAX,CAAA,EACtD,CAACS,EAAM,MAAM,CAAA,EAEfV,EAAQf,EAAG,WAAWuB,EAAM,EAAE,CAChC,EACAR,EAAQf,EAAG,WAAWuB,EAAM,CAAC,CAC/B,CAEA,SAASK,GAAkB,CACrBb,IAAU,OACZf,EAAG,aAAae,CAAK,EACrBA,EAAQ,KAEZ,CAEAf,EAAG,iBAAiB,UAAW,MAAO6B,GAAoC,CACxE,MAAMC,EAAID,EAAG,KACb,GAAI,CACF,OAAQC,EAAE,KAAA,CACR,IAAK,OAAQ,CACX,MAAMvB,EAAQuB,EAAE,MAA+B,IAC/C,MAAMxB,EAAQC,CAAI,EAClBW,EAAA,EACAC,EAAK,CACH,KAAM,SACN,GAAIW,EAAE,GACN,aAAc7B,EAAc,aAAA,EAC5B,WAAYA,EAAc,WAAA,EAC1B,WAAYA,EAAc,WAAA,EAC1B,mBAAoBE,EAAA,CAA4B,CACjD,EACD,KACF,CACA,IAAK,WAAY,CACfS,EAAYkB,EAAE,KACdZ,EAAA,EACAC,EAAK,CAAE,KAAM,MAAO,GAAIW,EAAE,GAAI,EAC9B,KACF,CACA,IAAK,YAAa,CAChBnB,EAAamB,EAAE,KACfZ,EAAA,EACAC,EAAK,CAAE,KAAM,MAAO,GAAIW,EAAE,GAAI,EAC9B,KACF,CACA,IAAK,UAAW,CACdjB,EAAO,OAAOiB,EAAE,IAAgC,EAChDZ,EAAA,EACAC,EAAK,CAAE,KAAM,MAAO,GAAIW,EAAE,GAAI,EAC9B,KACF,CACA,IAAK,QAAS,CACZF,EAAA,EACAd,EAAU,GACVI,EAAA,EACAF,EAAgB,EAChBG,EAAK,CAAE,KAAM,MAAO,GAAIW,EAAE,GAAI,EAC9BX,EAAK,CAAE,KAAM,QAAS,QAAS,GAAO,cAAAH,EAAe,EACrD,KACF,CACA,IAAK,MAAO,CACLN,GAAUQ,EAAA,EACfJ,EAAU,GACVQ,EAAA,EACAH,EAAK,CAAE,KAAM,MAAO,GAAIW,EAAE,GAAI,EAC9BX,EAAK,CAAE,KAAM,QAAS,QAAS,GAAM,cAAAH,EAAe,EACpD,KACF,CACA,IAAK,QAAS,CACZF,EAAU,GACVc,EAAA,EACAT,EAAK,CAAE,KAAM,MAAO,GAAIW,EAAE,GAAI,EAC9BX,EAAK,CAAE,KAAM,QAAS,QAAS,GAAO,cAAAH,EAAe,EACrD,KACF,CACA,IAAK,OAAQ,CACNN,GAAUQ,EAAA,EACf,MAAMO,EAAQf,EAAU,IAAI,CAAC,EAC7BM,GAAiB,EACjBG,EACE,CAAE,KAAM,SAAU,MAAOM,EAAM,OAAQ,MAAO,EAAG,IAAK,EAAG,cAAAT,CAAA,EACzD,CAACS,EAAM,MAAM,CAAA,EAEfN,EAAK,CAAE,KAAM,MAAO,GAAIW,EAAE,GAAI,EAC9B,KACF,CACA,IAAK,kBAAmB,CACjBpB,GAAUQ,EAAA,EACf,MAAMa,EAAWD,EAAE,SAAsB,IACnCE,EAAStB,EAAU,eAAeqB,CAAO,EAKzCE,EAAM7B,EAAW4B,EAAO,OAAO,EACrCb,EACE,CACE,KAAM,UACN,GAAIW,EAAE,GACN,QAASE,EAAO,QAAQ,OACxB,IAAAC,EACA,WAAYD,EAAO,UAAA,EAErB,CAACA,EAAO,QAAQ,MAAM,CAAA,EAExB,KACF,CACA,IAAK,gBAAiB,CAIpB,MAAME,EAAcJ,EAAE,SAChBK,EAAW,IAAI,WAAWD,CAAW,EACrCE,EAAS/B,EAAA,EACf,IAAIgC,EAAKD,EAAO,SAAWD,EAAS,OACpC,GAAIE,GACF,QAASC,EAAI,EAAGA,EAAIH,EAAS,OAAQG,IACnC,GAAIF,EAAOE,CAAC,IAAMH,EAASG,CAAC,EAAG,CAAED,EAAK,GAAO,KAAO,EAGxD,MAAME,EAAYH,EAAO,MAAA,EAAQ,OACjCjB,EACE,CACE,KAAM,SACN,GAAIW,EAAE,GACN,GAAAO,EACA,OAAQE,EACR,UAAWnC,EAAWgC,CAAM,CAAA,EAE9B,CAACG,CAAS,CAAA,EAEZ,KACF,CACA,IAAK,UAAW,CACdpB,EAAK,CACH,KAAM,UACN,GAAIW,EAAE,GACN,QAAS,SAAS7B,EAAc,aAAA,CAAc,EAAA,CAC/C,EACD,KACF,CACA,QACEkB,EAAK,CAAE,KAAM,MAAO,GAAIW,EAAE,GAAI,IAAK,cAAcA,EAAE,IAAI,EAAA,CAAI,CAAA,CAEjE,OAASU,EAAG,CACVrB,EAAK,CAAE,KAAM,MAAO,GAAIW,EAAE,GAAI,IAAMU,EAAY,SAAW,OAAOA,CAAC,CAAA,CAAG,CACxE,CACF,CAAC,EAEDrB,EAAK,CAAE,KAAM,QAAS"}
\ No newline at end of file
diff --git a/nvsim/index.html b/nvsim/index.html
index 823d953d..f33dfd4e 100644
--- a/nvsim/index.html
+++ b/nvsim/index.html
@@ -10,7 +10,7 @@
-
+
diff --git a/nvsim/sw.js b/nvsim/sw.js
index f55af0f6..30816a43 100644
--- a/nvsim/sw.js
+++ b/nvsim/sw.js
@@ -1,2 +1,2 @@
-if(!self.define){let s,e={};const i=(i,n)=>(i=new URL(i+".js",n).href,e[i]||new Promise(e=>{if("document"in self){const s=document.createElement("script");s.src=i,s.onload=e,document.head.appendChild(s)}else s=i,importScripts(i),e()}).then(()=>{let s=e[i];if(!s)throw new Error(`Module ${i} didn’t register its module`);return s}));self.define=(n,r)=>{const c=s||("document"in self?document.currentScript.src:"")||location.href;if(e[c])return;let o={};const d=s=>i(s,c),l={module:{uri:c},exports:o,require:d};e[c]=Promise.all(n.map(s=>l[s]||d(s))).then(s=>(r(...s),o))}}define(["./workbox-8c29f6e4"],function(s){"use strict";self.skipWaiting(),s.clientsClaim(),s.precacheAndRoute([{url:"registerSW.js",revision:"4bcaa063d693b37532f242f566232490"},{url:"index.html",revision:"ba18af5bc33b9d818c44811be202cfb2"},{url:"icon-512.svg",revision:"98fc1c8102c279bf1c0dd52559821ddc"},{url:"icon-192.svg",revision:"e73b6aa9016dca426a59e0f8ff4f1b04"},{url:"nvsim-pkg/nvsim_bg.wasm",revision:"b510b70684796cc95dd7fb5bb0d23df7"},{url:"nvsim-pkg/nvsim.js",revision:"ec3b99fbf8131dc1b3d86dc2ae0cf7b8"},{url:"assets/worker-DBavH9su.js",revision:null},{url:"assets/signals-SG45zFCj.js",revision:null},{url:"assets/lit-BS7WqYd5.js",revision:null},{url:"assets/index-DGciMM9K.js",revision:null},{url:"assets/index-CyUCBwRA.css",revision:null},{url:"icon-192.svg",revision:"e73b6aa9016dca426a59e0f8ff4f1b04"},{url:"icon-512.svg",revision:"98fc1c8102c279bf1c0dd52559821ddc"},{url:"nvsim-pkg/nvsim.js",revision:"ec3b99fbf8131dc1b3d86dc2ae0cf7b8"},{url:"nvsim-pkg/nvsim_bg.wasm",revision:"b510b70684796cc95dd7fb5bb0d23df7"},{url:"manifest.webmanifest",revision:"e8c97968cae19a0ed3b64c1303a27a90"}],{}),s.cleanupOutdatedCaches(),s.registerRoute(new s.NavigationRoute(s.createHandlerBoundToURL("index.html")))});
+if(!self.define){let e,s={};const i=(i,n)=>(i=new URL(i+".js",n).href,s[i]||new Promise(s=>{if("document"in self){const e=document.createElement("script");e.src=i,e.onload=s,document.head.appendChild(e)}else e=i,importScripts(i),s()}).then(()=>{let e=s[i];if(!e)throw new Error(`Module ${i} didn’t register its module`);return e}));self.define=(n,r)=>{const c=e||("document"in self?document.currentScript.src:"")||location.href;if(s[c])return;let d={};const o=e=>i(e,c),l={module:{uri:c},exports:d,require:o};s[c]=Promise.all(n.map(e=>l[e]||o(e))).then(e=>(r(...e),d))}}define(["./workbox-8c29f6e4"],function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"registerSW.js",revision:"4bcaa063d693b37532f242f566232490"},{url:"index.html",revision:"cb26da184b8d91f8e9bc1910e87fd519"},{url:"icon-512.svg",revision:"98fc1c8102c279bf1c0dd52559821ddc"},{url:"icon-192.svg",revision:"e73b6aa9016dca426a59e0f8ff4f1b04"},{url:"nvsim-pkg/nvsim_bg.wasm",revision:"b510b70684796cc95dd7fb5bb0d23df7"},{url:"nvsim-pkg/nvsim.js",revision:"ec3b99fbf8131dc1b3d86dc2ae0cf7b8"},{url:"assets/worker-BW0kLvYS.js",revision:null},{url:"assets/signals-SG45zFCj.js",revision:null},{url:"assets/lit-BS7WqYd5.js",revision:null},{url:"assets/index-CyUCBwRA.css",revision:null},{url:"assets/index-C2Z9YIJa.js",revision:null},{url:"icon-192.svg",revision:"e73b6aa9016dca426a59e0f8ff4f1b04"},{url:"icon-512.svg",revision:"98fc1c8102c279bf1c0dd52559821ddc"},{url:"nvsim-pkg/nvsim.js",revision:"ec3b99fbf8131dc1b3d86dc2ae0cf7b8"},{url:"nvsim-pkg/nvsim_bg.wasm",revision:"b510b70684796cc95dd7fb5bb0d23df7"},{url:"manifest.webmanifest",revision:"e8c97968cae19a0ed3b64c1303a27a90"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("index.html")))});
//# sourceMappingURL=sw.js.map
diff --git a/nvsim/sw.js.map b/nvsim/sw.js.map
index bdc37aa5..b9f5c434 100644
--- a/nvsim/sw.js.map
+++ b/nvsim/sw.js.map
@@ -1 +1 @@
-{"version":3,"file":"sw.js","sources":["../../../AppData/Local/Temp/5b6adf3e7ea80877384706b047a2786e/sw.js"],"sourcesContent":["import {clientsClaim as workbox_core_clientsClaim} from 'C:/Users/ruv/Projects/wifi-densepose/dashboard/node_modules/workbox-core/clientsClaim.mjs';\nimport {precacheAndRoute as workbox_precaching_precacheAndRoute} from 'C:/Users/ruv/Projects/wifi-densepose/dashboard/node_modules/workbox-precaching/precacheAndRoute.mjs';\nimport {cleanupOutdatedCaches as workbox_precaching_cleanupOutdatedCaches} from 'C:/Users/ruv/Projects/wifi-densepose/dashboard/node_modules/workbox-precaching/cleanupOutdatedCaches.mjs';\nimport {registerRoute as workbox_routing_registerRoute} from 'C:/Users/ruv/Projects/wifi-densepose/dashboard/node_modules/workbox-routing/registerRoute.mjs';\nimport {NavigationRoute as workbox_routing_NavigationRoute} from 'C:/Users/ruv/Projects/wifi-densepose/dashboard/node_modules/workbox-routing/NavigationRoute.mjs';\nimport {createHandlerBoundToURL as workbox_precaching_createHandlerBoundToURL} from 'C:/Users/ruv/Projects/wifi-densepose/dashboard/node_modules/workbox-precaching/createHandlerBoundToURL.mjs';/**\n * Welcome to your Workbox-powered service worker!\n *\n * You'll need to register this file in your web app.\n * See https://goo.gl/nhQhGp\n *\n * The rest of the code is auto-generated. Please don't update this file\n * directly; instead, make changes to your Workbox build configuration\n * and re-run your build process.\n * See https://goo.gl/2aRDsh\n */\n\n\n\n\n\n\n\n\nself.skipWaiting();\n\nworkbox_core_clientsClaim();\n\n\n/**\n * The precacheAndRoute() method efficiently caches and responds to\n * requests for URLs in the manifest.\n * See https://goo.gl/S9QRab\n */\nworkbox_precaching_precacheAndRoute([\n {\n \"url\": \"registerSW.js\",\n \"revision\": \"4bcaa063d693b37532f242f566232490\"\n },\n {\n \"url\": \"index.html\",\n \"revision\": \"ba18af5bc33b9d818c44811be202cfb2\"\n },\n {\n \"url\": \"icon-512.svg\",\n \"revision\": \"98fc1c8102c279bf1c0dd52559821ddc\"\n },\n {\n \"url\": \"icon-192.svg\",\n \"revision\": \"e73b6aa9016dca426a59e0f8ff4f1b04\"\n },\n {\n \"url\": \"nvsim-pkg/nvsim_bg.wasm\",\n \"revision\": \"b510b70684796cc95dd7fb5bb0d23df7\"\n },\n {\n \"url\": \"nvsim-pkg/nvsim.js\",\n \"revision\": \"ec3b99fbf8131dc1b3d86dc2ae0cf7b8\"\n },\n {\n \"url\": \"assets/worker-DBavH9su.js\",\n \"revision\": null\n },\n {\n \"url\": \"assets/signals-SG45zFCj.js\",\n \"revision\": null\n },\n {\n \"url\": \"assets/lit-BS7WqYd5.js\",\n \"revision\": null\n },\n {\n \"url\": \"assets/index-DGciMM9K.js\",\n \"revision\": null\n },\n {\n \"url\": \"assets/index-CyUCBwRA.css\",\n \"revision\": null\n },\n {\n \"url\": \"icon-192.svg\",\n \"revision\": \"e73b6aa9016dca426a59e0f8ff4f1b04\"\n },\n {\n \"url\": \"icon-512.svg\",\n \"revision\": \"98fc1c8102c279bf1c0dd52559821ddc\"\n },\n {\n \"url\": \"nvsim-pkg/nvsim.js\",\n \"revision\": \"ec3b99fbf8131dc1b3d86dc2ae0cf7b8\"\n },\n {\n \"url\": \"nvsim-pkg/nvsim_bg.wasm\",\n \"revision\": \"b510b70684796cc95dd7fb5bb0d23df7\"\n },\n {\n \"url\": \"manifest.webmanifest\",\n \"revision\": \"e8c97968cae19a0ed3b64c1303a27a90\"\n }\n], {});\nworkbox_precaching_cleanupOutdatedCaches();\nworkbox_routing_registerRoute(new workbox_routing_NavigationRoute(workbox_precaching_createHandlerBoundToURL(\"index.html\")));\n\n\n\n\n\n\n"],"names":["self","skipWaiting","workbox_core_clientsClaim","workbox_precaching_precacheAndRoute","url","revision","workbox_precaching_cleanupOutdatedCaches","workbox","registerRoute","workbox_routing_NavigationRoute","NavigationRoute","workbox_precaching_createHandlerBoundToURL"],"mappings":"inBAwBAA,KAAKC,cAELC,EAAAA,eAQAC,EAAAA,iBAAoC,CAClC,CACEC,IAAO,gBACPC,SAAY,oCAEd,CACED,IAAO,aACPC,SAAY,oCAEd,CACED,IAAO,eACPC,SAAY,oCAEd,CACED,IAAO,eACPC,SAAY,oCAEd,CACED,IAAO,0BACPC,SAAY,oCAEd,CACED,IAAO,qBACPC,SAAY,oCAEd,CACED,IAAO,4BACPC,SAAY,MAEd,CACED,IAAO,6BACPC,SAAY,MAEd,CACED,IAAO,yBACPC,SAAY,MAEd,CACED,IAAO,2BACPC,SAAY,MAEd,CACED,IAAO,4BACPC,SAAY,MAEd,CACED,IAAO,eACPC,SAAY,oCAEd,CACED,IAAO,eACPC,SAAY,oCAEd,CACED,IAAO,qBACPC,SAAY,oCAEd,CACED,IAAO,0BACPC,SAAY,oCAEd,CACED,IAAO,uBACPC,SAAY,qCAEb,CAAE,GACLC,EAAAA,wBAC6BC,EAAAC,cAAC,IAAIC,EAA+BC,gBAACC,0BAA2C"}
\ No newline at end of file
+{"version":3,"file":"sw.js","sources":["../../../AppData/Local/Temp/4f9d042f382c206d714057826365f38b/sw.js"],"sourcesContent":["import {clientsClaim as workbox_core_clientsClaim} from 'C:/Users/ruv/Projects/wifi-densepose/dashboard/node_modules/workbox-core/clientsClaim.mjs';\nimport {precacheAndRoute as workbox_precaching_precacheAndRoute} from 'C:/Users/ruv/Projects/wifi-densepose/dashboard/node_modules/workbox-precaching/precacheAndRoute.mjs';\nimport {cleanupOutdatedCaches as workbox_precaching_cleanupOutdatedCaches} from 'C:/Users/ruv/Projects/wifi-densepose/dashboard/node_modules/workbox-precaching/cleanupOutdatedCaches.mjs';\nimport {registerRoute as workbox_routing_registerRoute} from 'C:/Users/ruv/Projects/wifi-densepose/dashboard/node_modules/workbox-routing/registerRoute.mjs';\nimport {NavigationRoute as workbox_routing_NavigationRoute} from 'C:/Users/ruv/Projects/wifi-densepose/dashboard/node_modules/workbox-routing/NavigationRoute.mjs';\nimport {createHandlerBoundToURL as workbox_precaching_createHandlerBoundToURL} from 'C:/Users/ruv/Projects/wifi-densepose/dashboard/node_modules/workbox-precaching/createHandlerBoundToURL.mjs';/**\n * Welcome to your Workbox-powered service worker!\n *\n * You'll need to register this file in your web app.\n * See https://goo.gl/nhQhGp\n *\n * The rest of the code is auto-generated. Please don't update this file\n * directly; instead, make changes to your Workbox build configuration\n * and re-run your build process.\n * See https://goo.gl/2aRDsh\n */\n\n\n\n\n\n\n\n\nself.skipWaiting();\n\nworkbox_core_clientsClaim();\n\n\n/**\n * The precacheAndRoute() method efficiently caches and responds to\n * requests for URLs in the manifest.\n * See https://goo.gl/S9QRab\n */\nworkbox_precaching_precacheAndRoute([\n {\n \"url\": \"registerSW.js\",\n \"revision\": \"4bcaa063d693b37532f242f566232490\"\n },\n {\n \"url\": \"index.html\",\n \"revision\": \"cb26da184b8d91f8e9bc1910e87fd519\"\n },\n {\n \"url\": \"icon-512.svg\",\n \"revision\": \"98fc1c8102c279bf1c0dd52559821ddc\"\n },\n {\n \"url\": \"icon-192.svg\",\n \"revision\": \"e73b6aa9016dca426a59e0f8ff4f1b04\"\n },\n {\n \"url\": \"nvsim-pkg/nvsim_bg.wasm\",\n \"revision\": \"b510b70684796cc95dd7fb5bb0d23df7\"\n },\n {\n \"url\": \"nvsim-pkg/nvsim.js\",\n \"revision\": \"ec3b99fbf8131dc1b3d86dc2ae0cf7b8\"\n },\n {\n \"url\": \"assets/worker-BW0kLvYS.js\",\n \"revision\": null\n },\n {\n \"url\": \"assets/signals-SG45zFCj.js\",\n \"revision\": null\n },\n {\n \"url\": \"assets/lit-BS7WqYd5.js\",\n \"revision\": null\n },\n {\n \"url\": \"assets/index-CyUCBwRA.css\",\n \"revision\": null\n },\n {\n \"url\": \"assets/index-C2Z9YIJa.js\",\n \"revision\": null\n },\n {\n \"url\": \"icon-192.svg\",\n \"revision\": \"e73b6aa9016dca426a59e0f8ff4f1b04\"\n },\n {\n \"url\": \"icon-512.svg\",\n \"revision\": \"98fc1c8102c279bf1c0dd52559821ddc\"\n },\n {\n \"url\": \"nvsim-pkg/nvsim.js\",\n \"revision\": \"ec3b99fbf8131dc1b3d86dc2ae0cf7b8\"\n },\n {\n \"url\": \"nvsim-pkg/nvsim_bg.wasm\",\n \"revision\": \"b510b70684796cc95dd7fb5bb0d23df7\"\n },\n {\n \"url\": \"manifest.webmanifest\",\n \"revision\": \"e8c97968cae19a0ed3b64c1303a27a90\"\n }\n], {});\nworkbox_precaching_cleanupOutdatedCaches();\nworkbox_routing_registerRoute(new workbox_routing_NavigationRoute(workbox_precaching_createHandlerBoundToURL(\"index.html\")));\n\n\n\n\n\n\n"],"names":["self","skipWaiting","workbox_core_clientsClaim","workbox_precaching_precacheAndRoute","url","revision","workbox_precaching_cleanupOutdatedCaches","workbox","registerRoute","workbox_routing_NavigationRoute","NavigationRoute","workbox_precaching_createHandlerBoundToURL"],"mappings":"inBAwBAA,KAAKC,cAELC,EAAAA,eAQAC,EAAAA,iBAAoC,CAClC,CACEC,IAAO,gBACPC,SAAY,oCAEd,CACED,IAAO,aACPC,SAAY,oCAEd,CACED,IAAO,eACPC,SAAY,oCAEd,CACED,IAAO,eACPC,SAAY,oCAEd,CACED,IAAO,0BACPC,SAAY,oCAEd,CACED,IAAO,qBACPC,SAAY,oCAEd,CACED,IAAO,4BACPC,SAAY,MAEd,CACED,IAAO,6BACPC,SAAY,MAEd,CACED,IAAO,yBACPC,SAAY,MAEd,CACED,IAAO,4BACPC,SAAY,MAEd,CACED,IAAO,2BACPC,SAAY,MAEd,CACED,IAAO,eACPC,SAAY,oCAEd,CACED,IAAO,eACPC,SAAY,oCAEd,CACED,IAAO,qBACPC,SAAY,oCAEd,CACED,IAAO,0BACPC,SAAY,oCAEd,CACED,IAAO,uBACPC,SAAY,qCAEb,CAAE,GACLC,EAAAA,wBAC6BC,EAAAC,cAAC,IAAIC,EAA+BC,gBAACC,0BAA2C"}
\ No newline at end of file